PageRenderTime 24ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/urlview-0.9/urlview.c.build

#
Bazel | 581 lines | 508 code | 37 blank | 36 comment | 113 complexity | 0f269ed39f473cd26941088f5b4af3c6 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * Copyright (C) 1997 Michael R. Elkins <me@cs.hmc.edu>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. *
  18. *
  19. * Created: Thu Dec 4 02:13:11 PST 1997
  20. * Last Modified: Tue Jul 4 11:23:49 CEST 2000
  21. */
  22. #ifdef USE_SLANG
  23. #include <slcurses.h>
  24. #include <sys/file.h>
  25. #else
  26. #ifdef HAVE_NCURSES_H
  27. #include <ncurses.h>
  28. #else
  29. #include <curses.h>
  30. #endif
  31. #endif /* USE_SLANG */
  32. #include <pwd.h>
  33. #include <string.h>
  34. #include <unistd.h>
  35. #include <ctype.h>
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <fcntl.h>
  39. #include <sys/stat.h>
  40. #ifdef HAVE_REGEX_H
  41. #include <regex.h>
  42. #else
  43. #include <rx/rxposix.h>
  44. #endif
  45. #define DEFAULT_REGEXP "(((https?|ftp|gopher)://|(mailto|file|news):)[^' \t<>\"]+|(www|web|w3)\\.[-a-z0-9.]+)[^' \t.,;<>\"\\):]"
  46. #define DEFAULT_COMMAND "url_handler.sh %s"
  47. #define SYSTEM_INITFILE "/etc/urlview.conf"
  48. #define OFFSET 2
  49. #define PAGELEN (LINES - 1 - OFFSET)
  50. #define URLSIZE 128
  51. enum
  52. {
  53. FULL = 1,
  54. INDEX,
  55. MOTION
  56. };
  57. extern int mutt_enter_string (unsigned char *buf, size_t buflen, int y, int x,
  58. int flags);
  59. void search_forward (char *search, int urlcount, char **url, int *redraw, int *current, int *top)
  60. {
  61. regex_t rx;
  62. int i, j;
  63. if (strlen(search) == 0 || *search == '\n')
  64. {
  65. move (LINES - 1, 0);
  66. clrtoeol ();
  67. *redraw = MOTION;
  68. }
  69. else
  70. {
  71. if ( (j = regcomp (&rx, search, REG_EXTENDED | REG_ICASE | REG_NEWLINE)) )
  72. {
  73. regerror (j, &rx, search, sizeof (search));
  74. regfree (&rx);
  75. puts (search);
  76. }
  77. for (i = *current + 1; i < urlcount; i++)
  78. {
  79. if (regexec (&rx, url[i], 0, NULL, 0) == 0)
  80. {
  81. *current = i;
  82. if (*current < *top || *current > *top + PAGELEN -1)
  83. {
  84. *top = *current - *current % PAGELEN - 1;
  85. }
  86. i = urlcount;
  87. }
  88. }
  89. move (LINES - 1, 0);
  90. clrtoeol ();
  91. *redraw = INDEX;
  92. regfree (&rx);
  93. }
  94. }
  95. void search_backward (char *search, int urlcount, char **url, int *redraw, int *current, int *top)
  96. {
  97. regex_t rx;
  98. int i, j;
  99. if (strlen(search) == 0 || *search == '\n')
  100. {
  101. move (LINES - 1, 0);
  102. clrtoeol ();
  103. *redraw = MOTION;
  104. }
  105. else
  106. {
  107. if ((j = regcomp (&rx, search, REG_EXTENDED | REG_ICASE | REG_NEWLINE)))
  108. {
  109. regerror (j, &rx, search, sizeof (search));
  110. regfree (&rx);
  111. puts (search);
  112. }
  113. for (i = *current - 1; i >= 0; i--)
  114. {
  115. if (regexec (&rx, url[i], 0, NULL, 0) == 0)
  116. {
  117. *current = i;
  118. if (*current < *top || *current > *top + PAGELEN -1)
  119. {
  120. *top = *current - *current % PAGELEN - 1;
  121. if (*top < 0)
  122. *top = 0;
  123. }
  124. i = 0;
  125. }
  126. }
  127. move (LINES - 1, 0);
  128. clrtoeol ();
  129. *redraw = INDEX;
  130. regfree (&rx);
  131. }
  132. }
  133. int main (int argc, char **argv)
  134. {
  135. struct passwd *pw;
  136. struct stat stat_buf;
  137. #ifndef USE_SLANG
  138. SCREEN *scr;
  139. #endif
  140. FILE *fp;
  141. regex_t rx;
  142. regmatch_t match;
  143. char buf[1024];
  144. char command[1024];
  145. char regexp[1024];
  146. char search[1024];
  147. char scratch[1024];
  148. char **url;
  149. int urlsize = URLSIZE;
  150. char *pc;
  151. char *wc;
  152. size_t len;
  153. size_t offset;
  154. int i;
  155. int top = 0;
  156. int oldcurrent = 0;
  157. int current = 0;
  158. int done = 0;
  159. int redraw = FULL;
  160. int urlcount = 0;
  161. int urlcheck = 0;
  162. int optind = 1;
  163. int reopen_tty = 0;
  164. int is_filter = 0;
  165. int expert = 0;
  166. if (!argv[optind])
  167. is_filter = 1;
  168. strncpy (regexp, DEFAULT_REGEXP, sizeof (regexp) - 1);
  169. strncpy (command, DEFAULT_COMMAND, sizeof (command) - 1);
  170. /*** read the initialization file ***/
  171. pw = getpwuid (getuid ());
  172. snprintf (buf, sizeof (buf), "%s/.urlview", pw->pw_dir);
  173. /*** Check for users rc-file ***/
  174. if (stat (buf,&stat_buf) == -1)
  175. snprintf (buf, sizeof(buf), "%s", SYSTEM_INITFILE);
  176. if ((fp = fopen (buf, "r")))
  177. {
  178. while (fgets (buf, sizeof (buf), fp) != NULL)
  179. {
  180. if (buf[0] == '#' || buf[0] == '\n')
  181. continue;
  182. if (strncmp ("REGEXP", buf, 6) == 0 && isspace (buf[6]))
  183. {
  184. pc = buf + 6;
  185. while (isspace (*pc))
  186. pc++;
  187. wc = regexp;
  188. while (*pc && *pc != '\n')
  189. {
  190. if (*pc == '\\')
  191. {
  192. pc++;
  193. switch (*pc)
  194. {
  195. case 'n':
  196. *wc++ = '\n';
  197. break;
  198. case 'r':
  199. *wc++ = '\r';
  200. break;
  201. case 't':
  202. *wc++ = '\t';
  203. break;
  204. case 'f':
  205. *wc++ = '\f';
  206. break;
  207. default:
  208. *wc++ = '\\';
  209. *wc++ = *pc;
  210. break;
  211. }
  212. }
  213. else
  214. *wc++ = *pc;
  215. pc++;
  216. }
  217. *wc = 0;
  218. }
  219. else if (strncmp ("COMMAND", buf, 7) == 0 && isspace (buf[7]))
  220. {
  221. pc = buf + 7;
  222. while (isspace (*pc))
  223. pc++;
  224. pc[ strlen (pc) - 1 ] = 0; /* kill the trailing newline */
  225. strncpy (command, pc, sizeof (command) - 1);
  226. command[sizeof (command) - 1] = 0;
  227. }
  228. else if (strcmp ("EXPERT\n", buf) == 0)
  229. {
  230. expert = 1;
  231. }
  232. else
  233. {
  234. printf ("Unknown command: %s", buf);
  235. exit (1);
  236. }
  237. }
  238. fclose (fp);
  239. }
  240. if (!expert && strchr (command, '\''))
  241. {
  242. puts ("\n\
  243. ERROR: Your COMMAND contains a single\n\
  244. quote (') character. This is most likely\n\
  245. in error; please read the manual page\n\
  246. for details. If you really want to use\n\
  247. this command, please put the word EXPERT\n\
  248. into a line of its own in your \n\
  249. ~/.urlview file.\n\
  250. ");
  251. exit (1);
  252. }
  253. /*** compile the regexp ***/
  254. if ((i = regcomp (&rx, regexp, REG_EXTENDED | REG_ICASE | REG_NEWLINE)))
  255. {
  256. regerror (i, &rx, buf, sizeof (buf));
  257. regfree (&rx);
  258. puts (buf);
  259. exit (1);
  260. }
  261. /*** find matching patterns ***/
  262. if ((url = (char **) malloc (urlsize * sizeof (char *))) == NULL)
  263. {
  264. printf ("Couldn't allocate memory for url list\n");
  265. exit (1);
  266. }
  267. for (; is_filter || argv[optind]; optind++)
  268. {
  269. if (is_filter || strcmp ("-", argv[optind]) == 0)
  270. {
  271. fp = stdin;
  272. reopen_tty = 1;
  273. }
  274. else if (!(fp = fopen (argv[optind], "r")))
  275. {
  276. perror (argv[optind]);
  277. continue;
  278. }
  279. while (fgets (buf, sizeof (buf) - 1, fp) != NULL)
  280. {
  281. offset = 0;
  282. while (regexec (&rx, buf + offset, 1, &match, offset ? REG_NOTBOL : 0) == 0)
  283. {
  284. len = match.rm_eo - match.rm_so;
  285. if (urlcount >= urlsize)
  286. {
  287. void *urltmp;
  288. urltmp = realloc ((void *) url, (urlsize + URLSIZE) * sizeof (char *));
  289. if (urltmp == NULL)
  290. {
  291. printf ("Couldn't allocate memory for additional urls, "
  292. "only first %d displayed\n", urlsize);
  293. goto got_urls;
  294. }
  295. else
  296. {
  297. urlsize += URLSIZE;
  298. url = (char **) urltmp;
  299. }
  300. }
  301. url[urlcount] = malloc (len + 1);
  302. memcpy (url[urlcount], buf + match.rm_so + offset, len);
  303. url[urlcount][len] = 0;
  304. for (urlcheck=0; urlcheck < urlcount; urlcheck++)
  305. {
  306. if(strcasecmp(url[urlcount],url[urlcheck])==0)
  307. {
  308. urlcount--;
  309. break;
  310. }
  311. }
  312. urlcount++;
  313. offset += match.rm_eo;
  314. }
  315. }
  316. got_urls:
  317. fclose (fp);
  318. if (is_filter)
  319. break;
  320. }
  321. regfree (&rx);
  322. if (!urlcount)
  323. {
  324. puts ("No URLs found.");
  325. exit (1);
  326. }
  327. /*** present the URLs to the user ***/
  328. #ifdef USE_SLANG
  329. if (reopen_tty)
  330. SLang_TT_Read_FD = open ("/dev/tty", O_RDONLY);
  331. initscr ();
  332. #else
  333. /* if we piped a file we can't use initscr() because it assumes `stdin' */
  334. fp = reopen_tty ? fopen ("/dev/tty", "r") : stdin;
  335. scr = newterm (NULL, stdout, fp);
  336. set_term (scr);
  337. #endif
  338. cbreak ();
  339. noecho ();
  340. #ifdef HAVE_CURS_SET
  341. curs_set (1);
  342. #endif
  343. keypad (stdscr, TRUE);
  344. while (!done)
  345. {
  346. if (redraw == FULL)
  347. {
  348. move (0, 0);
  349. clrtobot ();
  350. standout ();
  351. printw ("UrlView %s: (%d matches) Press Q or Ctrl-C to Quit!", VERSION, urlcount);
  352. standend ();
  353. redraw = INDEX;
  354. }
  355. if (redraw == INDEX)
  356. {
  357. for (i = top; i < urlcount && i < top + PAGELEN; i++)
  358. {
  359. mvaddstr (i - top + OFFSET, 0, " ");
  360. snprintf (buf, sizeof (buf), "%4d ", i + 1);
  361. addstr (buf);
  362. addstr (url[i]);
  363. clrtoeol ();
  364. }
  365. clrtobot ();
  366. }
  367. else if (redraw == MOTION)
  368. mvaddstr (oldcurrent - top + OFFSET, 0, " ");
  369. standout ();
  370. mvaddstr (current - top + OFFSET, 0, "->");
  371. standend ();
  372. oldcurrent = current;
  373. switch (i = getch ())
  374. {
  375. case 'q':
  376. case 'x':
  377. case 'h':
  378. done = 1;
  379. break;
  380. case KEY_DOWN:
  381. case 'j':
  382. if (current < urlcount - 1)
  383. {
  384. current++;
  385. if (current >= top + PAGELEN)
  386. {
  387. top++;
  388. redraw = INDEX;
  389. }
  390. else
  391. redraw = MOTION;
  392. }
  393. else
  394. beep ();
  395. break;
  396. case KEY_UP:
  397. case 'k':
  398. if (current)
  399. {
  400. current--;
  401. if (current < top)
  402. {
  403. top--;
  404. redraw = INDEX;
  405. }
  406. else
  407. redraw = MOTION;
  408. }
  409. else
  410. beep ();
  411. break;
  412. case KEY_HOME:
  413. case '=':
  414. if (top != 0)
  415. {
  416. top = 0;
  417. redraw = INDEX;
  418. }
  419. else
  420. redraw = MOTION;
  421. current = 0;
  422. break;
  423. case KEY_END:
  424. case '*':
  425. case 'G':
  426. current = urlcount - 1;
  427. if (current >= top + PAGELEN)
  428. {
  429. top = current - PAGELEN + 1;
  430. redraw = INDEX;
  431. }
  432. else
  433. redraw = MOTION;
  434. break;
  435. case KEY_NPAGE:
  436. case '\006':
  437. if (top + PAGELEN < urlcount)
  438. {
  439. current = top = top + PAGELEN;
  440. redraw = INDEX;
  441. }
  442. else
  443. beep ();
  444. break;
  445. case KEY_PPAGE:
  446. case '\002':
  447. if (top)
  448. {
  449. top -= PAGELEN;
  450. if (top < 0)
  451. top = 0;
  452. if (current >= top + PAGELEN)
  453. {
  454. current = top + PAGELEN - 1;
  455. if (current < 0)
  456. current = 0;
  457. }
  458. redraw = INDEX;
  459. }
  460. break;
  461. case '\n':
  462. case '\r':
  463. case KEY_ENTER:
  464. case ' ':
  465. strncpy (buf, url[current], sizeof (buf));
  466. buf[sizeof (buf) - 1] = 0;
  467. mvaddstr (LINES - 1, 0, "URL: ");
  468. if (mutt_enter_string (buf, sizeof (buf), LINES - 1, 5, 0) == 0 && buf[0])
  469. {
  470. free (url[current]);
  471. url[current] = strdup (buf);
  472. endwin ();
  473. if (strstr (command, "%s"))
  474. snprintf (buf, sizeof (buf), command, quote (scratch, sizeof (scratch), url[current]));
  475. else
  476. snprintf (buf, sizeof (buf), "%s %s", command, quote (scratch, sizeof (scratch), url[current]));
  477. printf ("Executing: %s...\n", buf);
  478. fflush (stdout);
  479. system (buf);
  480. }
  481. move (LINES - 1, 0);
  482. clrtoeol ();
  483. break;
  484. case '0':
  485. case '1':
  486. case '2':
  487. case '3':
  488. case '4':
  489. case '5':
  490. case '6':
  491. case '7':
  492. case '8':
  493. case '9':
  494. buf[0] = i; buf[1] = 0;
  495. mvaddstr (LINES - 1, 0, "Jump to url: ");
  496. if (mutt_enter_string (buf, sizeof (buf), LINES - 1, 13, 0) == 0 && buf[0])
  497. {
  498. i = atoi (buf);
  499. if (i < 1 || i > urlcount)
  500. {
  501. mvaddstr (LINES - 1, 0, "No such url number!");
  502. clrtoeol ();
  503. }
  504. else
  505. {
  506. move (LINES - 1, 0);
  507. clrtoeol ();
  508. current = i - 1;
  509. redraw = MOTION;
  510. if (current < top || current > top + PAGELEN - 1)
  511. {
  512. top = current - current % PAGELEN;
  513. redraw = INDEX;
  514. }
  515. }
  516. }
  517. break;
  518. case '\f':
  519. clearok (stdscr, TRUE);
  520. redraw = FULL;
  521. break;
  522. case '/':
  523. mvaddstr (LINES - 1, 0, "Search forwards for string: ");
  524. if (mutt_enter_string (search, sizeof (search), LINES - 1, 28, 0) == 0)
  525. search_forward (search, urlcount, url, &redraw, &current, &top);
  526. break;
  527. case '?':
  528. mvaddstr (LINES - 1, 0, "Search backwards for string: ");
  529. if (mutt_enter_string (search, sizeof (search), LINES - 1, 29, 0) == 0)
  530. search_backward (search, urlcount, url, &redraw, &current, &top);
  531. break;
  532. case 'n':
  533. search_forward (search, urlcount, url, &redraw, &current, &top);
  534. break;
  535. case 'N':
  536. search_backward (search, urlcount, url, &redraw, &current, &top);
  537. break;
  538. default:
  539. break;
  540. }
  541. }
  542. endwin ();
  543. exit (0);
  544. }