My build of nnn with minor changes
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

noice.c 6.0 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. #include <sys/types.h>
  2. #include <errno.h>
  3. #include <fcntl.h>
  4. #include <dirent.h>
  5. #include <curses.h>
  6. #include <libgen.h>
  7. #include <locale.h>
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <signal.h>
  11. #include <string.h>
  12. #include <unistd.h>
  13. #ifdef DEBUG
  14. #define DPRINTF_D(x) printw(#x "=%d\n", x)
  15. #define DPRINTF_S(x) printw(#x "=%s\n", x)
  16. #define DPRINTF_P(x) printw(#x "=0x%p\n", x)
  17. #else
  18. #define DPRINTF_D(x)
  19. #define DPRINTF_S(x)
  20. #define DPRINTF_P(x)
  21. #endif /* DEBUG */
  22. #define LEN(x) (sizeof(x) / sizeof(*(x)))
  23. #define MIN(x, y) ((x) < (y) ? (x) : (y))
  24. /*
  25. * Layout:
  26. * .---------
  27. * | cwd: /mnt/path
  28. * |
  29. * | > file0
  30. * | file1
  31. * ...
  32. * | filen
  33. * |
  34. * | msg: invalid extension
  35. * '------
  36. */
  37. int die = 0;
  38. struct assoc {
  39. char *ext;
  40. char *bin;
  41. } assocs[] = {
  42. { "avi", "mplayer" },
  43. { "mp4", "mplayer" },
  44. { "mkv", "mplayer" },
  45. { "mp3", "mplayer" },
  46. { "ogg", "mplayer" },
  47. { "srt", "less" },
  48. { "txt", "less" },
  49. };
  50. char *
  51. extension(char *file)
  52. {
  53. char *dot;
  54. dot = strrchr(file, '.');
  55. if (dot == NULL || dot == file)
  56. return NULL;
  57. else
  58. return dot + 1;
  59. }
  60. char *
  61. openwith(char *ext)
  62. {
  63. int i;
  64. for (i = 0; i < LEN(assocs); i++)
  65. if (strncmp(assocs[i].ext, ext, strlen(ext)) == 0)
  66. return assocs[i].bin;
  67. return NULL;
  68. }
  69. int
  70. dentcmp(const void *va, const void *vb)
  71. {
  72. const struct dirent *a, *b;
  73. a = *(struct dirent **)va;
  74. b = *(struct dirent **)vb;
  75. return strcmp(a->d_name, b->d_name);
  76. }
  77. /* Warning shows up at the bottom */
  78. void
  79. printwarn(char *prefix)
  80. {
  81. move(LINES - 1, 0);
  82. printw("%s: %s\n", prefix, strerror(errno));
  83. }
  84. /* Kill curses and display error before exiting */
  85. void
  86. printerr(int ret, char *prefix)
  87. {
  88. endwin();
  89. printf("%s: %s\n", prefix, strerror(errno));
  90. exit(ret);
  91. }
  92. /*
  93. * Returns 0 normally
  94. * On movement it updates *cur
  95. * Returns 1 on quit
  96. * Returns 2 on go in
  97. * Returns 3 on go up
  98. */
  99. int
  100. nextsel(int *cur, int max)
  101. {
  102. int c;
  103. c = getch();
  104. switch (c) {
  105. case 'q':
  106. return 1;
  107. /* go up */
  108. case KEY_BACKSPACE:
  109. case KEY_LEFT:
  110. case 'h':
  111. return 2;
  112. /* go in */
  113. case KEY_ENTER:
  114. case '\r':
  115. case KEY_RIGHT:
  116. case 'l':
  117. return 3;
  118. /* next */
  119. case 'j':
  120. case KEY_DOWN:
  121. if (*cur < max - 1)
  122. (*cur)++;
  123. break;
  124. /* prev */
  125. case 'k':
  126. case KEY_UP:
  127. if (*cur > 0)
  128. (*cur)--;
  129. break;
  130. }
  131. return 0;
  132. }
  133. int
  134. testopen(char *path)
  135. {
  136. int fd;
  137. fd = open(path, O_RDONLY);
  138. if (fd == -1) {
  139. return 0;
  140. } else {
  141. close(fd);
  142. return 1;
  143. }
  144. }
  145. int
  146. testopendir(char *path)
  147. {
  148. DIR *dirp;
  149. dirp = opendir(path);
  150. if (dirp == NULL) {
  151. return 0;
  152. } else {
  153. closedir(dirp);
  154. return 1;
  155. }
  156. }
  157. void
  158. browse(const char *ipath)
  159. {
  160. DIR *dirp;
  161. struct dirent *dp;
  162. struct dirent **dents;
  163. int i, n, cur;
  164. int r, ret;
  165. char *path = strdup(ipath);
  166. begin:
  167. /* Path should be a malloc(3)-ed string at all times */
  168. n = 0;
  169. cur = 0;
  170. dents = NULL;
  171. dirp = opendir(path);
  172. if (dirp == NULL) {
  173. printwarn("opendir");
  174. goto nochange;
  175. }
  176. while ((dp = readdir(dirp)) != NULL) {
  177. /* Skip self and parent */
  178. if (strncmp(dp->d_name, ".", 2) == 0
  179. || strncmp(dp->d_name, "..", 3) == 0)
  180. continue;
  181. dents = realloc(dents, (n + 1) * sizeof(*dents));
  182. if (dents == NULL)
  183. printerr(1, "realloc");
  184. dents[n] = dp;
  185. n++;
  186. }
  187. qsort(dents, n, sizeof(*dents), dentcmp);
  188. for (;;) {
  189. int nlines;
  190. redraw:
  191. nlines = MIN(LINES - 4, n);
  192. /* Clean screen */
  193. erase();
  194. /* Strip slashes */
  195. for (i = strlen(path) - 1; i > -1; i--)
  196. if (path[i] == '/')
  197. path[i] = '\0';
  198. else
  199. break;
  200. DPRINTF_D(cur);
  201. DPRINTF_S(path);
  202. /* Print cwd */
  203. printw("cwd: %s%s\n\n",
  204. strncmp(path, "", 1) == 0 ? "/" : "",
  205. path);
  206. /* Print listing */
  207. if (cur < nlines / 2) {
  208. for (i = 0; i < nlines; i++)
  209. printw(" %s %s\n",
  210. i == cur ? ">" : " ",
  211. dents[i]->d_name);
  212. } else if (cur >= n - nlines / 2) {
  213. for (i = n - nlines; i < n; i++)
  214. printw(" %s %s\n",
  215. i == cur ? ">" : " ",
  216. dents[i]->d_name);
  217. } else {
  218. for (i = cur - nlines / 2; i <= cur + nlines / 2; i++)
  219. printw(" %s %s\n",
  220. i == cur ? ">" : " ",
  221. dents[i]->d_name);
  222. }
  223. nochange:
  224. ret = nextsel(&cur, n);
  225. if (ret == 1) {
  226. free(path);
  227. return;
  228. }
  229. if (ret == 2) {
  230. /* Handle root case */
  231. if (strncmp(path, "", 1) == 0) {
  232. goto nochange;
  233. } else {
  234. char *dir, *tmp;
  235. dir = dirname(path);
  236. tmp = malloc(strlen(dir) + 1);
  237. strncpy(tmp, dir, strlen(dir) + 1);
  238. free(path);
  239. path = tmp;
  240. goto out;
  241. }
  242. }
  243. if (ret == 3) {
  244. char *name, *file = NULL;
  245. char *newpath;
  246. char *ext, *bin;
  247. pid_t pid;
  248. name = dents[cur]->d_name;
  249. switch (dents[cur]->d_type) {
  250. case DT_DIR:
  251. newpath = malloc(strlen(path) + 1
  252. + strlen(name) + 1);
  253. sprintf(newpath, "%s/%s", path, name);
  254. if (testopen(newpath)) {
  255. free(path);
  256. path = newpath;
  257. goto out;
  258. } else {
  259. printwarn(newpath);
  260. free(newpath);
  261. goto nochange;
  262. }
  263. case DT_REG:
  264. file = malloc(strlen(path) + 1
  265. + strlen(name) + 1);
  266. sprintf(file, "%s/%s", path, name);
  267. DPRINTF_S(file);
  268. /* Open with */
  269. ext = extension(name);
  270. if (ext == NULL) {
  271. printwarn("invalid extension\n");
  272. goto nochange;
  273. }
  274. bin = openwith(ext);
  275. if (bin == NULL) {
  276. printwarn("no association\n");
  277. goto nochange;
  278. }
  279. DPRINTF_S(ext);
  280. DPRINTF_S(bin);
  281. /* Run program */
  282. pid = fork();
  283. if (pid == 0)
  284. execlp(bin, bin, file, NULL);
  285. else
  286. waitpid(pid, NULL, 0);
  287. free(file);
  288. /* Screen may be messed up */
  289. clear();
  290. /* Some programs reset this */
  291. keypad(stdscr, TRUE);
  292. goto redraw;
  293. default:
  294. DPRINTF_D(dents[cur]->d_type);
  295. }
  296. }
  297. }
  298. out:
  299. free(dents);
  300. r = closedir(dirp);
  301. if (r == -1)
  302. printerr(1, "closedir");
  303. goto begin;
  304. }
  305. int
  306. main(int argc, char *argv[])
  307. {
  308. char *ipath = argv[1] != NULL ? argv[1] : "/";
  309. /* Test initial path */
  310. if (!testopendir(ipath))
  311. printerr(1, ipath);
  312. /* Set locale before curses setup */
  313. setlocale(LC_ALL, "");
  314. /* Init curses */
  315. initscr();
  316. cbreak();
  317. noecho();
  318. nonl();
  319. intrflush(stdscr, FALSE);
  320. keypad(stdscr, TRUE);
  321. curs_set(FALSE); /* Hide cursor */
  322. browse(ipath);
  323. endwin(); /* Restore terminal */
  324. return 0;
  325. }