PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/src/lid.c

#
C | 1611 lines | 1319 code | 232 blank | 60 comment | 301 complexity | 045283aecf9d1263774b093bcfcf432d MD5 | raw file
Possible License(s): GPL-3.0
  1. /* lid.c -- primary query interface for mkid database
  2. Copyright (C) 1986, 1995-1996, 1999-2000, 2007-2012 Free Software
  3. Foundation, Inc.
  4. Written by Greg McGary <gkm@gnu.ai.mit.edu>
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3, or (at your option)
  8. any later version.
  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. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <config.h>
  17. #include <stdio.h>
  18. #include <ctype.h>
  19. #include <stdlib.h>
  20. #include <signal.h>
  21. #include <errno.h>
  22. #include <sys/types.h>
  23. #include <sys/wait.h>
  24. #include <assert.h>
  25. #include <getopt.h>
  26. #include <limits.h>
  27. #include <string.h>
  28. #include <dirname.h>
  29. #include <unistd.h>
  30. #include <termios.h>
  31. #include <alloca.h>
  32. #include <regex.h>
  33. #include <xalloc.h>
  34. #include <pathmax.h>
  35. #include <error.h>
  36. #include "closeout.h"
  37. #include "xnls.h"
  38. #include "idfile.h"
  39. #include "iduglobal.h"
  40. #include "lid.h"
  41. #include "progname.h"
  42. #ifndef ATTRIBUTE_UNUSED
  43. # define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
  44. #endif
  45. typedef void (*report_func_t) (char const *name, struct file_link **flinkv);
  46. typedef int (*query_func_t) (char const *arg, report_func_t);
  47. enum delimiter_style
  48. {
  49. ds_bogus,
  50. ds_contextual,
  51. ds_word,
  52. ds_substring
  53. };
  54. enum pattern_style
  55. {
  56. ps_bogus,
  57. ps_contextual,
  58. ps_literal,
  59. ps_regexp
  60. };
  61. enum key_style
  62. {
  63. ks_bogus,
  64. ks_none,
  65. ks_token,
  66. ks_pattern
  67. };
  68. enum result_style
  69. {
  70. rs_bogus,
  71. rs_none,
  72. rs_filenames,
  73. rs_grep,
  74. rs_edit
  75. };
  76. enum radix
  77. {
  78. radix_oct = 1,
  79. radix_dec = 2,
  80. radix_hex = 4,
  81. radix_all = radix_dec | radix_oct | radix_hex
  82. };
  83. void usage (void) __attribute__((__noreturn__));
  84. static void lower_caseify (char *str);
  85. static enum key_style parse_key_style (char const *arg);
  86. static enum result_style parse_result_style (char const *arg);
  87. static query_func_t get_query_func (char *pattern);
  88. static report_func_t get_report_func (void);
  89. static void report_filenames (char const *name, struct file_link **flinkv);
  90. static void report_grep (char const *name, struct file_link **flinkv);
  91. static void report_edit (char const *name, struct file_link **flinkv);
  92. static void report_nothing (char const *name, struct file_link **flinkv);
  93. static int vector_cardinality (void *vector);
  94. static int search_flinkv (struct file_link **flinkv);
  95. static int query_literal_word (char const *pattern, report_func_t report_func);
  96. static int query_literal_prefix (char const *pattern, report_func_t report_func);
  97. static int query_regexp (char const *pattern_0, report_func_t report_func);
  98. static char const *add_regexp_word_delimiters (char const *pattern_0);
  99. static int query_number (char const *pattern, report_func_t report_func);
  100. static int query_ambiguous_prefix (unsigned int, report_func_t report_func);
  101. static int query_literal_substring (char const *pattern,
  102. report_func_t report_func);
  103. static void parse_frequency_arg (char const *arg);
  104. static int desired_frequency (char const *tok);
  105. static char const *file_regexp (char const *name_0, char const *left_delimit,
  106. char const *right_delimit);
  107. static off_t query_binary_search (char const *token);
  108. static int is_regexp (char *name);
  109. static int has_left_delimiter (char const *pattern);
  110. static int has_right_delimiter (char const *pattern);
  111. static int word_match (char const *name_0, char const *line);
  112. static int get_radix (char const *str);
  113. static int is_number (char const *str);
  114. static int stoi (char const *str);
  115. static int otoi (char const *str);
  116. static int dtoi (char const *str);
  117. static int xtoi (char const *str);
  118. static unsigned char *tree8_to_bits (unsigned char *bits_vec,
  119. unsigned char const *hits_tree8);
  120. static void tree8_to_bits_1 (unsigned char **bits_vec,
  121. unsigned char const **hits_tree8, int level);
  122. static struct file_link **tree8_to_flinkv (unsigned char const *hits_tree8);
  123. static struct file_link **bits_to_flinkv (unsigned char const *bits_vec);
  124. static void savetty (void);
  125. static void restoretty (void);
  126. static void chartty (void);
  127. #define TOLOWER(c) (isupper (c) ? tolower (c) : (c))
  128. #define IS_ALNUM(c) (isalnum (c) || (c) == '_')
  129. /* Sorry about all the globals, but it's really cleaner this way. */
  130. static int tree8_levels;
  131. static unsigned int bits_vec_size;
  132. struct idhead idh;
  133. static char *hits_buf_1;
  134. static char *hits_buf_2;
  135. static unsigned char *bits_vec;
  136. /* If nonzero, display usage information and exit. */
  137. static int show_help;
  138. /* If nonzero, print the version on standard output then exit. */
  139. static int show_version;
  140. /* Which radixes do we want? */
  141. static int radix_flag = 0;
  142. /* If nonzero, ignore differences in alphabetic case while matching. */
  143. static int ignore_case_flag = 0;
  144. /* How will patterns will be delimited? */
  145. static enum delimiter_style delimiter_style = ds_contextual;
  146. /* How will patterns be interpreted? */
  147. static enum pattern_style pattern_style = ps_contextual;
  148. /* How will keys be presented? */
  149. static enum key_style key_style = ks_token;
  150. /* How will query results be presented? */
  151. static enum result_style result_style = rs_filenames;
  152. /* How shall we separate file names when result_style == rs_filenames? */
  153. static enum separator_style separator_style = ss_contextual;
  154. /* If non-zero, list identifiers that are are non-unique within this
  155. number of leading characters. */
  156. static unsigned int ambiguous_prefix_length = 0;
  157. /* The style of report. */
  158. static report_func_t report_function;
  159. /* The style of query. */
  160. static query_func_t query_function;
  161. /* Lower and upper bounds on occurrence frequency. */
  162. static unsigned int frequency_low = 1;
  163. static unsigned int frequency_high = USHRT_MAX;
  164. static struct file_link *cw_dlink;
  165. static struct file_link **members_0;
  166. static struct option const long_options[] =
  167. {
  168. { "file", required_argument, 0, 'f' },
  169. { "frequency", required_argument, 0, 'F' },
  170. { "ambiguous", required_argument, 0, 'a' },
  171. { "key", required_argument, 0, 'k' },
  172. { "result", required_argument, 0, 'R' },
  173. { "separator", required_argument, 0, 'S' },
  174. { "ignore-case", no_argument, 0, 'i' },
  175. { "literal", no_argument, 0, 'l' },
  176. { "regexp", no_argument, 0, 'r' },
  177. { "word", no_argument, 0, 'w' },
  178. { "substring", no_argument, 0, 's' },
  179. { "hex", no_argument, 0, 'x' },
  180. { "decimal", no_argument, 0, 'd' },
  181. { "octal", no_argument, 0, 'o' },
  182. { "help", no_argument, &show_help, 1 },
  183. { "version", no_argument, &show_version, 1 },
  184. {NULL, 0, NULL, 0}
  185. };
  186. void
  187. usage (void)
  188. {
  189. fprintf (stderr, _("Try `%s --help' for more information.\n"),
  190. program_name);
  191. exit (EXIT_FAILURE);
  192. }
  193. static void __attribute__((__noreturn__))
  194. help_me (void)
  195. {
  196. printf (_("\
  197. Usage: %s [OPTION]... PATTERN...\n\
  198. "), program_name);
  199. printf (_("\
  200. Query ID database and report results.\n\
  201. By default, output consists of multiple lines, each line containing the\n\
  202. matched identifier followed by the list of file names in which it occurs.\n\
  203. \n\
  204. -f, --file=FILE file name of ID database\n\
  205. \n\
  206. -i, --ignore-case match PATTERN case insensitively\n\
  207. -l, --literal match PATTERN as a literal string\n\
  208. -r, --regexp match PATTERN as a regular expression\n\
  209. -w, --word match PATTERN as a delimited word\n\
  210. -s, --substring match PATTERN as a substring\n\
  211. Note: If PATTERN contains extended regular expression meta-\n\
  212. characters, it is interpreted as a regular expression substring.\n\
  213. Otherwise, PATTERN is interpreted as a literal word.\n\
  214. \n\
  215. -k, --key=STYLE STYLE is one of `token', `pattern' or `none'\n\
  216. -R, --result=STYLE STYLE is one of `filenames', `grep', `edit' or `none'\n\
  217. -S, --separator=STYLE STYLE is one of `braces', `space' or `newline' and\n\
  218. only applies to file names when `--result=filenames'\n\
  219. The above STYLE options control how query results are presented.\n\
  220. Defaults are --key=token --result=filenames --separator=%s\n\
  221. \n\
  222. -F, --frequency=FREQ find tokens that occur FREQ times, where FREQ\n\
  223. is a range expressed as `N..M'. If N is omitted, it\n\
  224. defaults to 1, if M is omitted it defaults to MAX_USHRT\n\
  225. -a, --ambiguous=LEN find tokens whose names are ambiguous for LEN chars\n\
  226. \n\
  227. -x, --hex only find numbers expressed as hexadecimal\n\
  228. -d, --decimal only find numbers expressed as decimal\n\
  229. -o, --octal only find numbers expressed as octal\n\
  230. By default, searches match numbers of any radix.\n\
  231. \n\
  232. --help display this help and exit\n\
  233. --version output version information and exit\n\
  234. "),
  235. (separator_style == ss_braces ? _("braces") : _("space")));
  236. printf (_("\nReport bugs to " PACKAGE_BUGREPORT "\n\n"));
  237. exit (EXIT_SUCCESS);
  238. }
  239. int
  240. main (int argc, char **argv)
  241. {
  242. set_program_name (argv[0]);
  243. idh.idh_file_name = 0;
  244. #if ENABLE_NLS
  245. /* Set locale according to user's wishes. */
  246. setlocale (LC_ALL, "");
  247. /* Tell program which translations to use and where to find. */
  248. bindtextdomain (PACKAGE, LOCALEDIR);
  249. textdomain (PACKAGE);
  250. #endif
  251. atexit (close_stdout);
  252. switch (lid_mode)
  253. {
  254. case LID_MODE_AID: /* -ils */
  255. ignore_case_flag = REG_ICASE;
  256. pattern_style = ps_literal;
  257. delimiter_style = ds_substring;
  258. break;
  259. case LID_MODE_EID: /* -R edit */
  260. result_style = rs_edit;
  261. break;
  262. case LID_MODE_GID: /* -R grep */
  263. result_style = rs_grep;
  264. break;
  265. case LID_MODE_LID:
  266. break;
  267. default:
  268. abort ();
  269. }
  270. for (;;)
  271. {
  272. int optc = getopt_long (argc, argv, "f:F:a:k:R:S:ilrwsxdo",
  273. long_options, (int *) 0);
  274. if (optc < 0)
  275. break;
  276. switch (optc)
  277. {
  278. case 0:
  279. break;
  280. case 'f':
  281. idh.idh_file_name = optarg;
  282. break;
  283. case 'F':
  284. parse_frequency_arg (optarg);
  285. break;
  286. case 'a':
  287. ambiguous_prefix_length = stoi (optarg);
  288. break;
  289. case 'k':
  290. key_style = parse_key_style (optarg);
  291. break;
  292. case 'R':
  293. result_style = parse_result_style (optarg);
  294. break;
  295. case 'S':
  296. separator_style = parse_separator_style (optarg);
  297. break;
  298. case 'i':
  299. ignore_case_flag = REG_ICASE;
  300. break;
  301. case 'l':
  302. pattern_style = ps_literal;
  303. break;
  304. case 'r':
  305. pattern_style = ps_regexp;
  306. break;
  307. case 'e':
  308. pattern_style = ps_regexp;
  309. error (0, 0, _("notice: use of `-e' is deprecated, use `-r' instead"));
  310. break;
  311. case 'w':
  312. delimiter_style = ds_word;
  313. break;
  314. case 's':
  315. delimiter_style = ds_substring;
  316. break;
  317. case 'x':
  318. radix_flag |= radix_hex;
  319. break;
  320. case 'd':
  321. radix_flag |= radix_dec;
  322. break;
  323. case 'o':
  324. radix_flag |= radix_oct;
  325. break;
  326. default:
  327. usage ();
  328. }
  329. }
  330. if (show_version)
  331. {
  332. printf ("%s - %s\n", program_name, PACKAGE_VERSION);
  333. exit (EXIT_SUCCESS);
  334. }
  335. if (show_help)
  336. help_me ();
  337. if (radix_flag == 0)
  338. radix_flag = radix_all;
  339. if (separator_style == ss_contextual)
  340. {
  341. if (isatty (STDOUT_FILENO))
  342. separator_style = DEFAULT_SEPARATOR_STYLE;
  343. else if (key_style == ks_none)
  344. separator_style = ss_newline;
  345. else
  346. separator_style = ss_space;
  347. }
  348. argc -= optind;
  349. argv += optind;
  350. if (argc == 0)
  351. {
  352. static char dot[] = ".";
  353. static char *dotp = dot;
  354. argc = 1;
  355. argv = &dotp;
  356. }
  357. /* Look for the ID database up the tree */
  358. idh.idh_file_name = locate_id_file_name (idh.idh_file_name);
  359. if (idh.idh_file_name == 0)
  360. error (EXIT_FAILURE, errno, _("can't locate `ID'"));
  361. init_idh_obstacks (&idh);
  362. init_idh_tables (&idh);
  363. cw_dlink = get_current_dir_link ();
  364. /* Determine absolute name of the directory name to which database
  365. constituent files are relative. */
  366. members_0 = read_id_file (idh.idh_file_name, &idh);
  367. bits_vec_size = (idh.idh_files + 7) / 4; /* more than enough */
  368. tree8_levels = tree8_count_levels (idh.idh_files);
  369. hits_buf_1 = xmalloc (idh.idh_buf_size);
  370. hits_buf_2 = xmalloc (idh.idh_buf_size);
  371. bits_vec = xmalloc (bits_vec_size);
  372. report_function = get_report_func ();
  373. if (ambiguous_prefix_length)
  374. {
  375. if (!query_ambiguous_prefix (ambiguous_prefix_length, report_function))
  376. fprintf (stderr, _("All identifiers are non-ambiguous within the first %d characters\n"),
  377. ambiguous_prefix_length);
  378. }
  379. else
  380. {
  381. while (argc)
  382. {
  383. char *pattern = (argc--, *argv++);
  384. if (ignore_case_flag)
  385. lower_caseify (pattern);
  386. query_function = get_query_func (pattern);
  387. (*query_function) (pattern, report_function);
  388. }
  389. }
  390. fclose (idh.idh_FILE);
  391. exit (EXIT_SUCCESS);
  392. }
  393. static void
  394. lower_caseify (char *str)
  395. {
  396. while (*str)
  397. {
  398. *str = TOLOWER (*str);
  399. str++;
  400. }
  401. }
  402. static enum key_style
  403. parse_key_style (char const *arg)
  404. {
  405. MAYBE_RETURN_PREFIX_MATCH (arg, "none", ks_none);
  406. MAYBE_RETURN_PREFIX_MATCH (arg, "token", ks_token);
  407. MAYBE_RETURN_PREFIX_MATCH (arg, "pattern", ks_pattern);
  408. error (0, 0, _("invalid `--key' style: `%s'"), arg);
  409. usage ();
  410. return ks_bogus;
  411. }
  412. static enum result_style
  413. parse_result_style (char const *arg)
  414. {
  415. MAYBE_RETURN_PREFIX_MATCH (arg, "none", rs_none);
  416. MAYBE_RETURN_PREFIX_MATCH (arg, "filenames", rs_filenames);
  417. MAYBE_RETURN_PREFIX_MATCH (arg, "grep", rs_grep);
  418. MAYBE_RETURN_PREFIX_MATCH (arg, "edit", rs_edit);
  419. error (0, 0, _("invalid `--result' style: `%s'"), arg);
  420. usage ();
  421. return rs_bogus;
  422. }
  423. static query_func_t
  424. get_query_func (char *pattern)
  425. {
  426. switch (pattern_style)
  427. {
  428. case ps_regexp:
  429. return query_regexp;
  430. case ps_literal:
  431. if (delimiter_style == ds_substring)
  432. return query_literal_substring;
  433. else
  434. return query_literal_word;
  435. default:
  436. if (is_regexp (pattern))
  437. return query_regexp;
  438. else if (has_left_delimiter (pattern))
  439. return query_literal_prefix;
  440. else if (delimiter_style == ds_substring)
  441. return query_literal_substring;
  442. else if (is_number (pattern))
  443. return query_number;
  444. else if (delimiter_style == ds_word)
  445. return query_literal_word;
  446. else
  447. return query_literal_word;
  448. }
  449. }
  450. static report_func_t
  451. get_report_func (void)
  452. {
  453. switch (result_style)
  454. {
  455. case rs_filenames: return report_filenames;
  456. case rs_grep: return report_grep;
  457. case rs_edit: return report_edit;
  458. default: return report_nothing;
  459. }
  460. }
  461. static void
  462. report_filenames (char const *name, struct file_link **flinkv)
  463. {
  464. if (name && key_style != ks_none)
  465. printf ("%-14s ", name);
  466. print_filenames (flinkv, separator_style);
  467. }
  468. static void
  469. report_grep (char const *name, struct file_link **flinkv)
  470. {
  471. char line[1<<020];
  472. char const *pattern = 0;
  473. regex_t compiled;
  474. char *file_name = alloca (PATH_MAX);
  475. if (key_style == ks_pattern)
  476. {
  477. pattern = file_regexp (name, "[^a-zA-Z0-9_\300-\377]_*", "[^a-zA-Z0-9_\300-\377]");
  478. if (pattern)
  479. {
  480. int regcomp_errno = regcomp (&compiled, pattern,
  481. ignore_case_flag | REG_EXTENDED);
  482. if (regcomp_errno)
  483. {
  484. char buf[BUFSIZ];
  485. regerror (regcomp_errno, &compiled, buf, sizeof (buf));
  486. error (EXIT_FAILURE, 0, "%s", buf);
  487. }
  488. }
  489. }
  490. line[0] = ' '; /* sentinel */
  491. while (*flinkv)
  492. {
  493. int line_number = 0;
  494. FILE *source_FILE;
  495. maybe_relative_file_name (file_name, *flinkv++, cw_dlink);
  496. source_FILE = fopen (file_name, "r");
  497. if (source_FILE == 0)
  498. {
  499. error (0, errno, _("can't open `%s'"), file_name);
  500. continue;
  501. }
  502. while (fgets (line + 1, sizeof (line) - 1, source_FILE))
  503. {
  504. line_number++;
  505. if (pattern)
  506. {
  507. int regexec_errno = regexec (&compiled, line, 0, 0, 0);
  508. if (regexec_errno == REG_ESPACE)
  509. error (EXIT_FAILURE, 0,
  510. _("can't match regular-expression: memory exhausted"));
  511. else if (regexec_errno)
  512. continue;
  513. }
  514. else if (word_match (name, line))
  515. printf ("%s:%d:%s", file_name, line_number, line + 1);
  516. }
  517. fclose (source_FILE);
  518. }
  519. }
  520. static char **
  521. get_editor_argv(char const *fullstring, int* argc)
  522. {
  523. int i;
  524. char const *mark;
  525. char **argv;
  526. char *p;
  527. static int already_called;
  528. assert(already_called == 0); /* call only once, otherwise leaks */
  529. *argc = 1;
  530. mark = fullstring;
  531. while ((mark = strchr(mark, ' '))) {
  532. (*argc)++;
  533. mark += strspn(mark, " ");
  534. }
  535. argv = xmalloc(sizeof(char *) * (*argc + 1));
  536. p = xstrdup(fullstring);
  537. argv[0] = strtok(p, " ");
  538. for (i = 1; i < (*argc + 1); i++) {
  539. argv[i] = strtok(NULL, " ");
  540. }
  541. already_called = 1;
  542. return argv;
  543. }
  544. static void
  545. report_edit (char const *name, struct file_link **flinkv)
  546. {
  547. static char const *editor; /* editor program name from env */
  548. static char **editor_argv; /* editor base arguments from env */
  549. static int editor_argc;
  550. static char const *eid_arg;
  551. static char const *eid_right_del;
  552. static char const *eid_left_del;
  553. char regexp_buf[BUFSIZ];
  554. char ed_arg_buffer[BUFSIZ];
  555. char const *pattern;
  556. int c;
  557. int skip;
  558. if (!editor)
  559. if (!(editor = getenv ("VISUAL")))
  560. if (!(editor = getenv ("EDITOR")))
  561. editor = "vi";
  562. if (!editor_argv)
  563. editor_argv = get_editor_argv(editor, &editor_argc);
  564. if (!eid_arg)
  565. {
  566. int using_vi;
  567. using_vi = strequ ("vi", base_name (editor)) || strequ ("vim", base_name (editor));
  568. eid_arg = getenv ("EIDARG");
  569. if (!eid_arg)
  570. eid_arg = (using_vi ? "+1;/%s/" : "");
  571. eid_left_del = getenv ("EIDLDEL");
  572. if (eid_left_del == 0)
  573. eid_left_del = (using_vi ? "\\<" : "");
  574. eid_right_del = getenv ("EIDRDEL");
  575. if (eid_right_del == 0)
  576. eid_right_del = (using_vi ? "\\>" : "");
  577. }
  578. report_filenames (name, flinkv);
  579. savetty ();
  580. for (;;)
  581. {
  582. /* FIXME: i18n of responses */
  583. printf (_("edit? [y1-9^S/nq] "));
  584. fflush (stdout);
  585. chartty ();
  586. c = (getchar () & 0177);
  587. restoretty ();
  588. switch (TOLOWER (c))
  589. {
  590. case '/': case ('s' & 037):
  591. putchar ('/');
  592. skip = search_flinkv (flinkv);
  593. if (skip < 0)
  594. continue;
  595. flinkv += skip;
  596. goto editit;
  597. case '0': case '1': case '2': case '3': case '4':
  598. case '5': case '6': case '7': case '8': case '9':
  599. putchar (c);
  600. skip = c - '0';
  601. break;
  602. case 'y':
  603. putchar (c);
  604. skip = 0;
  605. break;
  606. case '\n':
  607. case '\r':
  608. putchar ('y');
  609. skip = 0;
  610. break;
  611. case 'q':
  612. putchar (c);
  613. putchar ('\n');
  614. exit (EXIT_SUCCESS);
  615. case 'n':
  616. putchar (c);
  617. putchar ('\n');
  618. return;
  619. default:
  620. putchar (c);
  621. putchar ('\n');
  622. continue;
  623. }
  624. putchar ('\n');
  625. while (skip--)
  626. if (*++flinkv == 0)
  627. continue;
  628. break;
  629. }
  630. editit:
  631. if (key_style == ks_pattern)
  632. pattern = file_regexp (name, eid_left_del, eid_right_del);
  633. else
  634. pattern = 0;
  635. if (pattern == 0)
  636. {
  637. pattern = regexp_buf;
  638. sprintf (regexp_buf, "%s%s%s", eid_left_del, name, eid_right_del);
  639. }
  640. switch (fork ())
  641. {
  642. case -1:
  643. error (EXIT_FAILURE, errno, _("can't fork"));
  644. break;
  645. case 0:
  646. {
  647. int i;
  648. char **argv = xmalloc (sizeof(char *) *
  649. (editor_argc + 2 + vector_cardinality (flinkv)));
  650. for (i = 0; i < editor_argc; i++)
  651. argv[i] = editor_argv[i];
  652. if (*eid_arg) {
  653. sprintf (ed_arg_buffer, eid_arg, pattern);
  654. argv[i++] = ed_arg_buffer;
  655. }
  656. while (*flinkv)
  657. argv[i++] = maybe_relative_file_name (0, *flinkv++, cw_dlink);
  658. argv[i] = 0;
  659. execvp (editor_argv[0], argv);
  660. error (0, errno, _("can't exec `%s'"), editor_argv[0]);
  661. }
  662. default:
  663. {
  664. void (*oldint) (int) = signal (SIGINT, SIG_IGN);
  665. void (*oldquit) (int) = signal (SIGQUIT, SIG_IGN);
  666. while (wait (0) == -1 && errno == EINTR)
  667. ;
  668. signal (SIGINT, oldint);
  669. signal (SIGQUIT, oldquit);
  670. }
  671. break;
  672. }
  673. }
  674. static void
  675. report_nothing (char const *name, struct file_link **flinkv ATTRIBUTE_UNUSED)
  676. {
  677. if (key_style != ks_none)
  678. puts (name);
  679. }
  680. static int _GL_ATTRIBUTE_PURE
  681. vector_cardinality (void *vector)
  682. {
  683. void **v = (void **) vector;
  684. int count = 0;
  685. while (*v++)
  686. count++;
  687. return count;
  688. }
  689. static int
  690. search_flinkv (struct file_link **flinkv)
  691. {
  692. char pattern[BUFSIZ];
  693. unsigned int count;
  694. char *file_name = alloca (PATH_MAX);
  695. char *eol;
  696. if (fgets (pattern, sizeof (pattern), stdin) == 0)
  697. return -1;
  698. eol = strchr(pattern, '\n');
  699. if (eol)
  700. *eol = 0;
  701. for (count = 0; *flinkv; count++, flinkv++)
  702. {
  703. maybe_relative_file_name (file_name, *flinkv, cw_dlink);
  704. if (strcasestr (file_name, pattern))
  705. return count;
  706. }
  707. return -1;
  708. }
  709. static int
  710. query_literal_word (char const *arg, report_func_t report_func)
  711. {
  712. if (ignore_case_flag)
  713. return query_literal_substring (arg, report_func);
  714. if (query_binary_search (arg) == 0)
  715. return 0;
  716. gets_past_00 (hits_buf_1, idh.idh_FILE);
  717. assert (*hits_buf_1);
  718. if (!desired_frequency (hits_buf_1))
  719. return 0;
  720. (*report_func) (hits_buf_1, tree8_to_flinkv (token_hits_addr (hits_buf_1)));
  721. return 1;
  722. }
  723. static int
  724. query_literal_prefix (char const *arg, report_func_t report_func)
  725. {
  726. int count;
  727. unsigned int length;
  728. if (ignore_case_flag)
  729. return query_regexp (arg, report_func);
  730. if (query_binary_search (++arg) == 0)
  731. return 0;
  732. length = strlen (arg);
  733. count = 0;
  734. if (key_style != ks_token)
  735. memset (bits_vec, 0, bits_vec_size);
  736. while (gets_past_00 (hits_buf_1, idh.idh_FILE) > 0)
  737. {
  738. assert (*hits_buf_1);
  739. if (!desired_frequency (hits_buf_1))
  740. continue;
  741. if (!strnequ (arg, hits_buf_1, length))
  742. break;
  743. if (key_style == ks_token)
  744. (*report_func) (hits_buf_1, tree8_to_flinkv (token_hits_addr (hits_buf_1)));
  745. else
  746. tree8_to_bits (bits_vec, token_hits_addr (hits_buf_1));
  747. count++;
  748. }
  749. if (key_style != ks_token && count)
  750. (*report_func) (--arg, bits_to_flinkv (bits_vec));
  751. return count;
  752. }
  753. static int
  754. query_regexp (char const *pattern_0, report_func_t report_func)
  755. {
  756. int count;
  757. regex_t compiled;
  758. int regcomp_errno;
  759. char const *pattern = pattern_0;
  760. if (delimiter_style == ds_word)
  761. pattern = add_regexp_word_delimiters (pattern);
  762. regcomp_errno = regcomp (&compiled, pattern,
  763. ignore_case_flag | REG_EXTENDED);
  764. if (regcomp_errno)
  765. {
  766. char buf[BUFSIZ];
  767. regerror (regcomp_errno, &compiled, buf, sizeof (buf));
  768. error (EXIT_FAILURE, 0, "%s", buf);
  769. }
  770. fseek (idh.idh_FILE, idh.idh_tokens_offset, SEEK_SET);
  771. count = 0;
  772. if (key_style != ks_token)
  773. memset (bits_vec, 0, bits_vec_size);
  774. while (gets_past_00 (hits_buf_1, idh.idh_FILE) > 0)
  775. {
  776. int regexec_errno;
  777. assert (*hits_buf_1);
  778. if (!desired_frequency (hits_buf_1))
  779. continue;
  780. regexec_errno = regexec (&compiled, hits_buf_1, 0, 0, 0);
  781. if (regexec_errno == REG_ESPACE)
  782. error (0, 0, _("can't match regular-expression: memory exhausted"));
  783. else if (regexec_errno)
  784. continue;
  785. if (key_style == ks_token)
  786. (*report_func) (hits_buf_1, tree8_to_flinkv (token_hits_addr (hits_buf_1)));
  787. else
  788. tree8_to_bits (bits_vec, token_hits_addr (hits_buf_1));
  789. count++;
  790. }
  791. if (key_style != ks_token && count)
  792. (*report_func) (pattern, bits_to_flinkv (bits_vec));
  793. if (pattern != pattern_0)
  794. free ((char *) pattern);
  795. return count;
  796. }
  797. static char const *
  798. add_regexp_word_delimiters (char const *pattern_0)
  799. {
  800. int length = strlen (pattern_0);
  801. int has_left = has_left_delimiter (pattern_0);
  802. int has_right = has_right_delimiter (&pattern_0[length]);
  803. if (has_left && has_right)
  804. return pattern_0;
  805. else
  806. {
  807. char *pattern = xmalloc (length + 4);
  808. if (has_left)
  809. strcpy (pattern, pattern_0);
  810. else
  811. {
  812. length += 2;
  813. strcpy (pattern, "\\<");
  814. strcpy (pattern + 2, pattern_0);
  815. }
  816. if (!has_right)
  817. strcpy (pattern + length, "\\>");
  818. return pattern;
  819. }
  820. }
  821. static int
  822. query_number (char const *arg, report_func_t report_func)
  823. {
  824. int count;
  825. int radix;
  826. int val;
  827. int hit_digits = 0;
  828. radix = (val = stoi (arg)) ? radix_all : get_radix (arg);
  829. fseek (idh.idh_FILE, idh.idh_tokens_offset, SEEK_SET);
  830. count = 0;
  831. if (key_style != ks_token)
  832. memset (bits_vec, 0, bits_vec_size);
  833. while (gets_past_00 (hits_buf_1, idh.idh_FILE) > 0)
  834. {
  835. if (hit_digits)
  836. {
  837. if (!isdigit (*hits_buf_1))
  838. break;
  839. }
  840. else
  841. {
  842. if (isdigit (*hits_buf_1))
  843. hit_digits = 1;
  844. }
  845. if (!((radix_flag ? radix_flag : radix) & get_radix (hits_buf_1))
  846. || stoi (hits_buf_1) != val)
  847. continue;
  848. if (key_style == ks_token)
  849. (*report_func) (hits_buf_1, tree8_to_flinkv (token_hits_addr (hits_buf_1)));
  850. else
  851. tree8_to_bits (bits_vec, token_hits_addr (hits_buf_1));
  852. count++;
  853. }
  854. if (key_style != ks_token && count)
  855. (*report_func) (arg, bits_to_flinkv (bits_vec));
  856. return count;
  857. }
  858. /* Find identifiers that are non-unique within the first `count'
  859. characters. */
  860. static int
  861. query_ambiguous_prefix (unsigned int limit, report_func_t report_func)
  862. {
  863. char *old = hits_buf_1;
  864. char *new = hits_buf_2;
  865. int consecutive = 0;
  866. int count = 0;
  867. char name[1024];
  868. if (limit <= 1)
  869. usage ();
  870. assert (limit < sizeof(name));
  871. name[0] = '^';
  872. *new = '\0';
  873. fseek (idh.idh_FILE, idh.idh_tokens_offset, SEEK_SET);
  874. while (gets_past_00 (old, idh.idh_FILE) > 0)
  875. {
  876. char *tmp;
  877. if (!(token_flags (old) & TOK_NAME))
  878. continue;
  879. tmp = old;
  880. old = new;
  881. new = tmp;
  882. if (!strnequ (new, old, limit))
  883. {
  884. if (consecutive && key_style != ks_token)
  885. {
  886. strncpy (&name[1], old, limit);
  887. (*report_func) (name, bits_to_flinkv (bits_vec));
  888. }
  889. consecutive = 0;
  890. continue;
  891. }
  892. if (!consecutive++)
  893. {
  894. if (key_style != ks_token)
  895. tree8_to_bits (bits_vec, token_hits_addr (old));
  896. else
  897. (*report_func) (old, tree8_to_flinkv (token_hits_addr (old)));
  898. count++;
  899. }
  900. if (key_style == ks_token)
  901. (*report_func) (new, tree8_to_flinkv (token_hits_addr (new)));
  902. else
  903. tree8_to_bits (bits_vec, token_hits_addr (new));
  904. count++;
  905. }
  906. if (consecutive && key_style != ks_token)
  907. {
  908. strncpy (&name[1], new, limit);
  909. (*report_func) (name, bits_to_flinkv (bits_vec));
  910. }
  911. return count;
  912. }
  913. static int
  914. query_literal_substring (char const *arg, report_func_t report_func)
  915. {
  916. int count;
  917. int arg_length = 0;
  918. char *(*strstr_func) (char const *, char const *);
  919. fseek (idh.idh_FILE, idh.idh_tokens_offset, SEEK_SET);
  920. if (delimiter_style == ds_word)
  921. arg_length = strlen (arg);
  922. count = 0;
  923. if (key_style != ks_token)
  924. memset (bits_vec, 0, bits_vec_size);
  925. strstr_func = (ignore_case_flag ? strcasestr : strstr);
  926. while (gets_past_00 (hits_buf_1, idh.idh_FILE) > 0)
  927. {
  928. char *match;
  929. assert (*hits_buf_1);
  930. if (!desired_frequency (hits_buf_1))
  931. continue;
  932. match = (*strstr_func) (hits_buf_1, arg);
  933. if (match == 0)
  934. continue;
  935. if (delimiter_style == ds_word &&
  936. (match > hits_buf_1 || strlen (hits_buf_1) > arg_length))
  937. continue;
  938. if (key_style == ks_token)
  939. (*report_func) (hits_buf_1, tree8_to_flinkv (token_hits_addr (hits_buf_1)));
  940. else
  941. tree8_to_bits (bits_vec, token_hits_addr (hits_buf_1));
  942. count++;
  943. }
  944. if (key_style != ks_token && count)
  945. (*report_func) (arg, bits_to_flinkv (bits_vec));
  946. return count;
  947. }
  948. static void
  949. parse_frequency_arg (char const *arg)
  950. {
  951. int range = 0;
  952. if (strnequ (arg, "..", 2))
  953. frequency_low = 1;
  954. else
  955. {
  956. frequency_low = atoi (arg);
  957. while (isdigit (*arg))
  958. arg++;
  959. }
  960. if (strnequ (arg, "..", 2))
  961. {
  962. range = 1;
  963. arg += 2;
  964. }
  965. if (*arg)
  966. frequency_high = atoi (arg);
  967. else if (range)
  968. frequency_high = USHRT_MAX;
  969. else
  970. frequency_high = frequency_low;
  971. if (frequency_low > frequency_high)
  972. {
  973. unsigned int tmp = frequency_low;
  974. frequency_low = frequency_high;
  975. frequency_high = tmp;
  976. }
  977. }
  978. static int
  979. desired_frequency (char const *tok)
  980. {
  981. unsigned int count = token_count (tok);
  982. return (frequency_low <= count && count <= frequency_high);
  983. }
  984. /* Convert the regular expression that we used to locate identifiers
  985. in the id database into one suitable for locating the identifiers
  986. in files. */
  987. static char const *
  988. file_regexp (char const *name_0, char const *left_delimit, char const *right_delimit)
  989. {
  990. static char pat_buf[BUFSIZ];
  991. char *name = (char *) name_0;
  992. if (query_function == query_number && key_style == ks_pattern)
  993. {
  994. sprintf (pat_buf, "%s0*[Xx]*0*%d[Ll]*%s", left_delimit, stoi (name), right_delimit);
  995. return pat_buf;
  996. }
  997. if (!is_regexp (name) && name[0] != '^')
  998. return 0;
  999. if (name[0] == '^')
  1000. name_0++;
  1001. else
  1002. left_delimit = "";
  1003. while (*++name)
  1004. ;
  1005. if (*--name == '$')
  1006. *name = '\0';
  1007. else
  1008. right_delimit = "";
  1009. sprintf (pat_buf, "%s%s%s", left_delimit, name_0, right_delimit);
  1010. return pat_buf;
  1011. }
  1012. static off_t
  1013. query_binary_search (char const *token_0)
  1014. {
  1015. off_t offset = 0;
  1016. off_t start = idh.idh_tokens_offset - 2;
  1017. off_t end = idh.idh_end_offset;
  1018. off_t anchor_offset = 0;
  1019. int order = -1;
  1020. while (start < end)
  1021. {
  1022. int c;
  1023. int incr = 1;
  1024. char const *token;
  1025. offset = start + (end - start) / 2;
  1026. fseek (idh.idh_FILE, offset, SEEK_SET);
  1027. offset += skip_past_00 (idh.idh_FILE);
  1028. if (offset >= end)
  1029. {
  1030. offset = start + 2;
  1031. fseek (idh.idh_FILE, offset, SEEK_SET);
  1032. }
  1033. /* compare the token names */
  1034. token = token_0;
  1035. while (*token == (c = getc (idh.idh_FILE)) && *token && c)
  1036. {
  1037. token++;
  1038. incr++;
  1039. }
  1040. if (c && !*token && query_function == query_literal_prefix)
  1041. anchor_offset = offset;
  1042. order = *token - c;
  1043. if (order < 0)
  1044. end = offset - 2;
  1045. else if (order > 0)
  1046. start = offset + incr + skip_past_00 (idh.idh_FILE) - 2;
  1047. else
  1048. break;
  1049. }
  1050. if (order)
  1051. {
  1052. if (anchor_offset)
  1053. offset = anchor_offset;
  1054. else
  1055. return 0;
  1056. }
  1057. fseek (idh.idh_FILE, offset, SEEK_SET);
  1058. return offset;
  1059. }
  1060. /* Are there any regexp meta-characters in name?? */
  1061. static int _GL_ATTRIBUTE_PURE
  1062. is_regexp (char *name)
  1063. {
  1064. int backslash = 0;
  1065. if (*name == '^')
  1066. name++;
  1067. else if (strnequ (name, "\\<", 2))
  1068. name += 2;
  1069. while (*name)
  1070. {
  1071. if (*name == '\\')
  1072. {
  1073. if (strchr ("<>", name[1]))
  1074. return 1;
  1075. name++, backslash++;
  1076. }
  1077. else if (strchr ("[]().*+^$", *name))
  1078. return 1;
  1079. name++;
  1080. }
  1081. if (backslash)
  1082. while (*name)
  1083. {
  1084. if (*name == '\\')
  1085. strcpy (name, name + 1);
  1086. name++;
  1087. }
  1088. return 0;
  1089. }
  1090. static int
  1091. has_left_delimiter (char const *pattern)
  1092. {
  1093. return (*pattern == '^' || strnequ (pattern, "\\<", 2));
  1094. }
  1095. static int
  1096. has_right_delimiter (char const *pattern)
  1097. {
  1098. return (pattern[-1] == '$' || strequ (pattern - 2, "\\>"));
  1099. }
  1100. /* Does `name' occur in `line' delimited by non-alphanumerics?? */
  1101. static int _GL_ATTRIBUTE_PURE
  1102. word_match (char const *name_0, char const *line)
  1103. {
  1104. char const *name = name_0;
  1105. for (;;)
  1106. {
  1107. /* find an initial-character match */
  1108. while (*line != *name)
  1109. {
  1110. if (*line == '\0' || *line == '\n')
  1111. return 0;
  1112. line++;
  1113. }
  1114. /* do we have a word delimiter on the left ?? */
  1115. if (IS_ALNUM (line[-1]))
  1116. {
  1117. line++;
  1118. continue;
  1119. }
  1120. /* march down both strings as long as we match */
  1121. while (*++name == *++line)
  1122. ;
  1123. /* is this the end of `name', is there a word delimiter ?? */
  1124. if (*name == '\0' && !IS_ALNUM (*line))
  1125. return 1;
  1126. name = name_0;
  1127. }
  1128. }
  1129. /* Use the C lexical rules to determine an ascii number's radix. The
  1130. radix is returned as a bit map, so that more than one radix may
  1131. apply. In particular, it is impossible to determine the radix of
  1132. 0, so return all possibilities. */
  1133. static int _GL_ATTRIBUTE_PURE
  1134. get_radix (char const *str)
  1135. {
  1136. if (!isdigit (*str))
  1137. return 0;
  1138. if (*str != '0')
  1139. return radix_dec;
  1140. str++;
  1141. if (*str == 'x' || *str == 'X')
  1142. return radix_hex;
  1143. while (*str && *str == '0')
  1144. str++;
  1145. return (*str ? radix_oct : (radix_oct | radix_dec));
  1146. }
  1147. static int
  1148. is_number (char const *str)
  1149. {
  1150. if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
  1151. {
  1152. str += 2;
  1153. str += strspn (str, "0123456789aAbBcCdDeEfF");
  1154. }
  1155. else {
  1156. size_t offn;
  1157. str += (offn = strspn (str, "0123456789"));
  1158. if (offn)
  1159. str += strspn (str, "uUlL");
  1160. }
  1161. return (*str == '\0');
  1162. }
  1163. /* Convert an ascii string number to an integer. Determine the radix
  1164. before converting. */
  1165. static int
  1166. stoi (char const *str)
  1167. {
  1168. switch (get_radix (str))
  1169. {
  1170. case radix_dec:
  1171. return (dtoi (str));
  1172. case radix_oct:
  1173. return (otoi (&str[1]));
  1174. case radix_hex:
  1175. return (xtoi (&str[2]));
  1176. case radix_dec | radix_oct:
  1177. return 0;
  1178. default:
  1179. return -1;
  1180. }
  1181. }
  1182. /* Convert an ascii octal number to an integer. */
  1183. static int _GL_ATTRIBUTE_PURE
  1184. otoi (char const *str)
  1185. {
  1186. int n = 0;
  1187. while (*str >= '0' && *str <= '7')
  1188. {
  1189. n *= 010;
  1190. n += *str++ - '0';
  1191. }
  1192. while (*str && strchr ("uUlL", *str))
  1193. str++;
  1194. return (*str ? -1 : n);
  1195. }
  1196. /* Convert an ascii decimal number to an integer. */
  1197. static int _GL_ATTRIBUTE_PURE
  1198. dtoi (char const *str)
  1199. {
  1200. int n = 0;
  1201. while (isdigit (*str))
  1202. {
  1203. n *= 10;
  1204. n += *str++ - '0';
  1205. }
  1206. while (*str && strchr ("uUlL", *str))
  1207. str++;
  1208. return (*str ? -1 : n);
  1209. }
  1210. /* Convert an ascii hex number to an integer. */
  1211. static int _GL_ATTRIBUTE_PURE
  1212. xtoi (char const *str)
  1213. {
  1214. int n = 0;
  1215. while (isxdigit (*str))
  1216. {
  1217. n *= 0x10;
  1218. if (isdigit (*str))
  1219. n += *str++ - '0';
  1220. else if (islower (*str))
  1221. n += 0xa + *str++ - 'a';
  1222. else
  1223. n += 0xA + *str++ - 'A';
  1224. }
  1225. while (*str && strchr ("uUlL", *str))
  1226. str++;
  1227. return (*str ? -1 : n);
  1228. }
  1229. static unsigned char *
  1230. tree8_to_bits (unsigned char *bv_0, unsigned char const *hits_tree8)
  1231. {
  1232. unsigned char* bv = bv_0;
  1233. tree8_to_bits_1 (&bv, &hits_tree8, tree8_levels);
  1234. return bv_0;
  1235. }
  1236. static void
  1237. tree8_to_bits_1 (unsigned char **bv, unsigned char const **hits_tree8, int level)
  1238. {
  1239. int hits = *(*hits_tree8)++;
  1240. if (--level)
  1241. {
  1242. int incr = 1 << ((level - 1) * 3);
  1243. int bit;
  1244. for (bit = 1; bit & 0xff; bit <<= 1)
  1245. {
  1246. if (bit & hits)
  1247. tree8_to_bits_1 (bv, hits_tree8, level);
  1248. else
  1249. *bv += incr;
  1250. }
  1251. }
  1252. else
  1253. *(*bv)++ |= hits;
  1254. }
  1255. static struct file_link **
  1256. bits_to_flinkv (unsigned char const *bv)
  1257. {
  1258. int const reserved_flinkv_slots = 3;
  1259. static struct file_link **flinkv_0;
  1260. struct file_link **flinkv;
  1261. struct file_link **members = members_0;
  1262. struct file_link **end = &members_0[idh.idh_files];
  1263. if (flinkv_0 == 0)
  1264. flinkv_0 = xmalloc (sizeof(struct file_link *) * (idh.idh_files + reserved_flinkv_slots + 2));
  1265. flinkv = &flinkv_0[reserved_flinkv_slots];
  1266. for (;;)
  1267. {
  1268. int hits;
  1269. int bit;
  1270. while (*bv == 0)
  1271. {
  1272. bv++;
  1273. members += 8;
  1274. if (members >= end)
  1275. goto out;
  1276. }
  1277. hits = *bv++;
  1278. for (bit = 1; bit & 0xff; bit <<= 1)
  1279. {
  1280. if (bit & hits)
  1281. *flinkv++ = *members;
  1282. if (++members >= end)
  1283. goto out;
  1284. }
  1285. }
  1286. out:
  1287. *flinkv = 0;
  1288. return &flinkv_0[reserved_flinkv_slots];
  1289. }
  1290. static struct file_link **
  1291. tree8_to_flinkv (unsigned char const *hits_tree8)
  1292. {
  1293. memset (bits_vec, 0, bits_vec_size);
  1294. return bits_to_flinkv (tree8_to_bits (bits_vec, hits_tree8));
  1295. }
  1296. #if HAVE_TERMIOS_H
  1297. static struct termios linemode;
  1298. static struct termios charmode;
  1299. static struct termios savemode;
  1300. #define GET_TTY_MODES(modes) tcgetattr (0, (modes))
  1301. #define SET_TTY_MODES(modes) tcsetattr(0, TCSANOW, (modes))
  1302. #else /* not HAVE_TERMIOS_H */
  1303. #include <sys/ioctl.h>
  1304. # if HAVE_TERMIO_H
  1305. # include <termio.h>
  1306. static struct termio linemode;
  1307. static struct termio charmode;
  1308. static struct termio savemode;
  1309. #define GET_TTY_MODES(modes) ioctl (0, TCGETA, (modes))
  1310. #define SET_TTY_MODES(modes) ioctl (0, TCSETA, (modes))
  1311. # else /* not HAVE_TERMIO_H */
  1312. # if HAVE_SGTTY_H
  1313. # include <sgtty.h>
  1314. static struct sgttyb linemode;
  1315. static struct sgttyb charmode;
  1316. static struct sgttyb savemode;
  1317. # ifdef TIOCGETP
  1318. #define GET_TTY_MODES(modes) ioctl (0, TIOCGETP, (modes))
  1319. #define SET_TTY_MODES(modes) ioctl (0, TIOCSETP, (modes))
  1320. # else
  1321. #define GET_TTY_MODES(modes) gtty (0, (modes))
  1322. #define SET_TTY_MODES(modes) stty (0, (modes))
  1323. # endif
  1324. # else /* not HAVE_SGTTY_H */
  1325. #define GET_TTY_MODES(modes)
  1326. #define SET_TTY_MODES(modes)
  1327. # endif /* not HAVE_SGTTY_H */
  1328. # endif /* not HAVE_TERMIO_H */
  1329. #endif /* not HAVE_TERMIOS_H */
  1330. #if HAVE_TERMIOS_H || HAVE_TERMIO_H
  1331. static void
  1332. savetty (void)
  1333. {
  1334. GET_TTY_MODES (&savemode);
  1335. charmode = linemode = savemode;
  1336. charmode.c_lflag &= ~(ECHO | ICANON | ISIG);
  1337. charmode.c_cc[VMIN] = 1;
  1338. charmode.c_cc[VTIME] = 0;
  1339. linemode.c_lflag |= (ECHO | ICANON | ISIG);
  1340. linemode.c_cc[VEOF] = 'd' & 037;
  1341. linemode.c_cc[VEOL] = 0377;
  1342. }
  1343. #else /* not (HAVE_TERMIOS_H || HAVE_TERMIO_H) */
  1344. # if HAVE_SGTTY_H
  1345. static void
  1346. savetty (void)
  1347. {
  1348. # ifdef TIOCGETP
  1349. ioctl(0, TIOCGETP, &savemode);
  1350. # else
  1351. gtty(0, &savemode);
  1352. # endif
  1353. charmode = linemode = savemode;
  1354. charmode.sg_flags &= ~ECHO;
  1355. charmode.sg_flags |= RAW;
  1356. linemode.sg_flags |= ECHO;
  1357. linemode.sg_flags &= ~RAW;
  1358. }
  1359. # else /* not HAVE_SGTTY_H */
  1360. static void
  1361. savetty (void)
  1362. {
  1363. }
  1364. # endif /* not HAVE_SGTTY_H */
  1365. #endif /* not (HAVE_TERMIOS_H || HAVE_TERMIO_H) */
  1366. static void
  1367. restoretty (void)
  1368. {
  1369. SET_TTY_MODES (&savemode);
  1370. }
  1371. static void
  1372. chartty (void)
  1373. {
  1374. SET_TTY_MODES (&charmode);
  1375. }