diff options
Diffstat (limited to 'lid.c')
-rw-r--r-- | lid.c | 1390 |
1 files changed, 1390 insertions, 0 deletions
@@ -0,0 +1,1390 @@ +/* lid.c -- primary query interface for mkid database + Copyright (C) 1986, 1995 Greg McGary + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "config.h" +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <signal.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <rx.h> +#include <assert.h> +#include <limits.h> +#include "alloc.h" +#include "idfile.h" +#include "idarg.h" +#include "token.h" +#include "bitops.h" +#include "strxtra.h" +#include "misc.h" +#include "filenames.h" + +typedef void (*doit_t) (char const *name, char **argv); + +unsigned char *tree8_to_bits (unsigned char *bits_vec, unsigned char const *hits_tree8); +void tree8_to_bits_1 (unsigned char **bits_vec, unsigned char const **hits_tree8, int level); +char **tree8_to_argv (unsigned char const *hits_tree8); +char **bits_to_argv (unsigned char const *bits_vec); + +static void usage (void); +void look_id (char const *name, char **argv); +void grep_id (char const *name, char **argv); +void edit_id (char const *name, char **argv); +int skip_to_argv (char **argv); +int find_plain (char const *arg, doit_t doit); +int find_anchor (char const *arg, doit_t doit); +int find_regexp (char const *arg, doit_t doit); +int find_number (char const *arg, doit_t doit); +int find_non_unique (int, doit_t doit); +int find_apropos (char const *arg, doit_t doit); +void parse_frequency_arg (char const *arg); +int frequency_wanted (char const *tok); +char const *strcpos (char const *s1, char const *s2); +char const *file_regexp (char const *name0, char const *left_delimit, char const *right_delimit); +off_t find_token (char const *token); +int is_regexp (char *name); +char **vec_to_argv (int const *vec); +int file_name_wildcard (char const *re, char const *fn); +int match_file_names (char const *re, doit_t doit); +int word_match (char const *name0, char const *line); +int radix (char const *name); +int stoi (char const *name); +int otoi (char const *name); +int dtoi (char const *name); +int xtoi (char const *name); +void savetty (void); +void restoretty (void); +void linetty (void); +void chartty (void); + +enum radix { + RADIX_OCT = 1, + RADIX_DEC = 2, + RADIX_HEX = 4, + RADIX_ALL = RADIX_DEC | RADIX_OCT | RADIX_HEX, +}; + +#define TOLOWER(c) (isupper (c) ? tolower (c) : (c)) +#define IS_ALNUM(c) (isalnum (c) || (c) == '_') + +#ifndef CRUNCH_DEFAULT +#define CRUNCH_DEFAULT 1 +#endif + +/* Sorry about all the globals, but it's really cleaner this way. */ +FILE *id_FILE; +int merging; +int radix_arg; +int echo_on = 1; +int crunch_on = CRUNCH_DEFAULT; +int file_name_regexp = 0; +int match_base = 0; +char id_dir[BUFSIZ]; +off_t anchor_offset; +int tree8_levels; +int bits_vec_size; +char PWD_name[BUFSIZ]; +struct idhead idh; +struct idarg *id_args; +int (*find_func) (char const *arg, doit_t doit); +unsigned short frequency_low = 1; +unsigned short frequency_high = USHRT_MAX; +char *buf; +char *buf2; +unsigned char *bits_vec; + +char const *program_name; + +static void +usage (void) +{ + fprintf (stderr, "Usage: %s [-f<file>] [-u<n>] [-r<dir>] [-mewdoxasknc] patterns...\n", program_name); + exit (1); +} + +int +main (int argc, char **argv) +{ + char const *id_file_name = IDFILE; + doit_t doit = look_id; + int force_merge = 0; + int unique_limit = 0; + int use_id_file_name = 1; + int use_pwd_file_name = 0; + int use_relative_file_name = 0; + char const *REL_file_name = NULL; + int (*forced_find_func) (char const *arg, doit_t doit) = NULL; + + program_name = basename (GETARG (argc, argv)); + + while (argc) + { + char const *arg = GETARG (argc, argv); + int op = *arg++; + switch (op) + { + case '-': + case '+': + break; + default: + UNGETARG (argc, argv); + goto argsdone; + } + while (*arg) + switch (*arg++) + { + case 'f': + id_file_name = arg; + goto nextarg; + case 'u': + unique_limit = stoi (arg); + goto nextarg; + case 'm': + force_merge = 1; + break; + case 'e': + forced_find_func = find_regexp; + file_name_regexp = 1; + break; + case 'w': + forced_find_func = find_plain; + break; + case 'd': + radix_arg |= RADIX_DEC; + break; + case 'o': + radix_arg |= RADIX_OCT; + break; + case 'x': + radix_arg |= RADIX_HEX; + break; + case 'a': + radix_arg |= RADIX_ALL; + break; + case 'F': + parse_frequency_arg (arg); + goto nextarg; + case 'k': + crunch_on = 0; + break; + case 'g': + crunch_on = 1; + break; + case 'n': + echo_on = 0; + break; + case 'c': + use_id_file_name = 0; + use_pwd_file_name = 1; + break; + case 'b': + match_base = 1; + break; + case 'r': + use_id_file_name = 0; + use_relative_file_name = 1; + REL_file_name = arg; + goto nextarg; + default: + usage (); + } + nextarg:; + } +argsdone: + + if (use_pwd_file_name && use_relative_file_name) + { + fprintf (stderr, "%s: please use only one of -c or -r\n", program_name); + usage (); + } + /* Look for the ID database up the tree */ + id_file_name = look_up (id_file_name); + if (id_file_name == NULL) + { + filerr ("open", id_file_name); + exit (1); + } + /* Find out current directory to relate names to */ + if (kshgetwd (PWD_name) == NULL) + { + fprintf (stderr, "%s: cannot determine current directory\n", program_name); + exit (1); + } + strcat (PWD_name, "/"); + /* Determine absolute path name that database files are relative to */ + if (use_id_file_name) + { + strcpy (id_dir, span_file_name (PWD_name, id_file_name)); + *(strrchr (id_dir, '/') + 1) = '\0'; + } + else if (use_pwd_file_name) + { + strcpy (id_dir, PWD_name); + } + else + { + strcpy (id_dir, span_file_name (PWD_name, REL_file_name)); + strcat (id_dir, "/"); + } + id_FILE = init_idfile (id_file_name, &idh, &id_args); + if (id_FILE == NULL) + { + filerr ("open", id_file_name); + exit (1); + } + bits_vec_size = (idh.idh_paths + 7) >> 3; + tree8_levels = tree8_count_levels (idh.idh_paths); + + switch (program_name[0]) + { + case 'a': + forced_find_func = find_apropos; + /*FALLTHROUGH*/ + case 'l': + doit = look_id; + break; + case 'g': + doit = grep_id; + break; + case 'e': + doit = edit_id; + break; + case 'p': + forced_find_func = match_file_names; + doit = look_id; + break; + default: + program_name = "[algep]id"; + usage (); + } + + if (argc == 0) + { + UNGETARG (argc, argv); + *(char const **)argv = "."; + } + + while (argc) + { + long val = -1; + char *arg = GETARG (argc, argv); + + if (forced_find_func) + find_func = forced_find_func; + else if (radix (arg) && (val = stoi (arg)) >= 0) + find_func = find_number; + else if (is_regexp (arg)) + find_func = find_regexp; + else if (arg[0] == '^') + find_func = find_anchor; + else + find_func = find_plain; + + if ((doit == look_id && !force_merge) + || (find_func == find_number + && val > 7 + && radix_arg != RADIX_DEC + && radix_arg != RADIX_OCT + && radix_arg != RADIX_HEX)) + merging = 0; + else + merging = 1; + + buf = malloc (idh.idh_buf_size); + buf2 = malloc (idh.idh_buf_size); + bits_vec = MALLOC (unsigned char, bits_vec_size); + + if (unique_limit) + { + if (!find_non_unique (unique_limit, doit)) + fprintf (stderr, "All identifiers are unique within the first %d characters\n", unique_limit); + exit (0); + } + else if (!(*find_func) (arg, doit)) + { + fprintf (stderr, "%s: not found\n", arg); + continue; + } + } + exit (0); +} + +void +look_id (char const *name, char **argv) +{ + char const *arg; + char const *dir; + int crunching = 0; + + if (echo_on) + printf ("%-14s ", name); + while (*argv) + { + arg = *argv++; + if (*argv && crunch_on && can_crunch (arg, *argv)) + { + if (crunching) + printf (",%s", root_name (arg)); + else + { + dir = dirname (arg); + if (dir && !strequ (dir, ".")) + printf ("%s/", dir); + printf ("{%s", root_name (arg)); + } + crunching = 1; + } + else + { + if (crunching) + printf (",%s}%s", root_name (arg), suff_name (arg)); + else + fputs (arg, stdout); + crunching = 0; + if (*argv) + putchar (' '); + } + } + putchar ('\n'); +} + +void +grep_id (char const *name, char **argv) +{ + FILE *gid_FILE; + char const *gid_name; + char line[BUFSIZ]; + char const *re = NULL; + int line_number; + + if (merging) + { + re = file_regexp (name, "[^a-zA-Z0-9_]_*", "[^a-zA-Z0-9_]"); + if (re) + { + char const *regexp_error = re_comp (re); + if (regexp_error) + { + fprintf (stderr, "%s: Syntax Error: %s (%s)\n", program_name, re, regexp_error); + return; + } + } + } + + line[0] = ' '; /* sentry */ + while (*argv) + { + gid_FILE = fopen (gid_name = *argv++, "r"); + if (gid_FILE == NULL) + { + filerr ("open", gid_name); + continue; + } + line_number = 0; + while (fgets (&line[1], sizeof (line), gid_FILE)) + { + line_number++; + if (re) + { + if (!re_exec (line)) + continue; + } + else if (!word_match (name, line)) + continue; + printf ("%s:%d: %s", gid_name, line_number, &line[1]); + } + fclose (gid_FILE); + } +} + +void +edit_id (char const *name, char **argv) +{ + char re_buffer[BUFSIZ]; + char ed_arg_buffer[BUFSIZ]; + char const *re; + int c; + int skip; + static char const *editor; + static char const *eid_arg; + static char const *eid_right_del; + static char const *eid_left_del; + + if (editor == NULL) + editor = getenv ("EDITOR"); + if (editor == NULL) + { + char const *ucb_vi = "/usr/ucb/vi"; + char const *bin_vi = "/usr/bin/vi"; + + if (access (ucb_vi, 01) == 0) + editor = ucb_vi; + else if (access (bin_vi, 01) == 0) + editor = bin_vi; + else + editor = "/bin/ed"; /* YUCK! */ + if (editor == ucb_vi || editor == bin_vi) + { + eid_arg = "+1;/%s/"; + eid_left_del = "\\<"; + eid_right_del = "\\>"; + } + } + if (eid_left_del == NULL) + { + eid_arg = getenv ("EIDARG"); + eid_left_del = getenv ("EIDLDEL"); + if (eid_left_del == NULL) + eid_left_del = ""; + eid_right_del = getenv ("EIDRDEL"); + if (eid_right_del == NULL) + eid_right_del = ""; + } + + look_id (name, argv); + savetty (); + for (;;) + { + printf ("Edit? [y1-9^S/nq] "); + fflush (stdout); + chartty (); + c = (getchar () & 0177); + restoretty (); + switch (TOLOWER (c)) + { + case '/': + case ('s' & 037): + putchar ('/'); + skip = skip_to_argv (argv); + if (skip < 0) + continue; + argv += skip; + goto editit; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + putchar (c); + skip = c - '0'; + break; + case 'y': + putchar (c); + /*FALLTHROUGH*/ + case '\n': + case '\r': + skip = 0; + break; + case 'q': + putchar (c); + putchar ('\n'); + exit (0); + case 'n': + putchar (c); + putchar ('\n'); + return; + default: + putchar (c); + putchar ('\n'); + continue; + } + + putchar ('\n'); + while (skip--) + if (*++argv == NULL) + continue; + break; + } +editit: + + if (merging) + re = file_regexp (name, eid_left_del, eid_right_del); + else + re = NULL; + if (re == NULL) + { + re = re_buffer; + sprintf (re_buffer, "%s%s%s", eid_left_del, name, eid_right_del); + } + + switch (fork ()) + { + case -1: + fprintf (stderr, "%s: Cannot fork (%s)\n", program_name, uerror ()); + exit (1); + case 0: + argv--; + if (eid_arg) + { + argv--; + sprintf (ed_arg_buffer, eid_arg, re); + argv[1] = ed_arg_buffer; + } + *(char const **) argv = editor; + execv (editor, argv); + filerr ("exec", editor); + default: + { + void (*oldint) (int) = signal (SIGINT, SIG_IGN); + void (*oldquit) (int) = signal (SIGQUIT, SIG_IGN); + + while (wait (0) == -1 && errno == EINTR) + ; + + signal (SIGINT, oldint); + signal (SIGQUIT, oldquit); + } + break; + } +} + +int +skip_to_argv (char **argv) +{ + char pattern[BUFSIZ]; + int count; + + if (gets (pattern) == NULL) + return -1; + + for (count = 0; *argv; count++, argv++) + if (strcpos (*argv, pattern)) + return count; + return -1; +} + +int +find_plain (char const *arg, doit_t doit) +{ + if (find_token (arg) == 0) + return 0; + gets_past_00 (buf, id_FILE); + assert (*buf); + if (!frequency_wanted (buf)) + return 0; + (*doit) (buf, tree8_to_argv (tok_hits_addr (buf))); + return 1; +} + +int +find_anchor (char const *arg, doit_t doit) +{ + int count; + int length; + + if (find_token (++arg) == 0) + return 0; + + length = strlen (arg); + count = 0; + if (merging) + memset (bits_vec, 0, bits_vec_size); + while (gets_past_00 (buf, id_FILE) > 0) + { + assert (*buf); + if (!frequency_wanted (buf)) + continue; + if (!strnequ (arg, buf, length)) + break; + if (merging) + tree8_to_bits (bits_vec, tok_hits_addr (buf)); + else + (*doit) (buf, tree8_to_argv (tok_hits_addr (buf))); + count++; + } + if (merging && count) + (*doit) (--arg, bits_to_argv (bits_vec)); + + return count; +} + +int +find_regexp (char const *re, doit_t doit) +{ + int count; + char const *regexp_error; + + regexp_error = re_comp (re); + if (regexp_error) + { + fprintf (stderr, "%s: Syntax Error: %s (%s)\n", program_name, re, regexp_error); + return 0; + } + fseek (id_FILE, idh.idh_tokens_offset, SEEK_SET); + + count = 0; + if (merging) + memset (bits_vec, 0, bits_vec_size); + while (gets_past_00 (buf, id_FILE) > 0) + { + assert (*buf); + if (!frequency_wanted (buf)) + continue; + if (!re_exec (buf)) + continue; + if (merging) + tree8_to_bits (bits_vec, tok_hits_addr (buf)); + else + (*doit) (buf, tree8_to_argv (tok_hits_addr (buf))); + count++; + } + if (merging && count) + (*doit) (re, bits_to_argv (bits_vec)); + + return count; +} + +int +find_number (char const *arg, doit_t doit) +{ + int count; + int rdx; + int val; + int hit_digits = 0; + + rdx = (val = stoi (arg)) ? RADIX_ALL : radix (arg); + fseek (id_FILE, idh.idh_tokens_offset, SEEK_SET); + + count = 0; + if (merging) + memset (bits_vec, 0, bits_vec_size); + while (gets_past_00 (buf, id_FILE) > 0) + { + if (hit_digits) + { + if (!isdigit (*buf)) + break; + } + else + { + if (isdigit (*buf)) + hit_digits = 1; + } + + if (!((radix_arg ? radix_arg : rdx) & radix (buf)) + || stoi (buf) != val) + continue; + if (merging) + tree8_to_bits (bits_vec, tok_hits_addr (buf)); + else + (*doit) (buf, tree8_to_argv (tok_hits_addr (buf))); + count++; + } + if (merging && count) + (*doit) (arg, bits_to_argv (bits_vec)); + + return count; +} + +/* Find identifiers that are non-unique within the first `count' + characters. */ +int +find_non_unique (int limit, doit_t doit) +{ + char *old = buf; + char *new = buf2; + int consecutive = 0; + int count = 0; + char name[1024]; + + if (limit <= 1) + usage (); + assert (limit < sizeof(name)); + + name[0] = '^'; + *new = '\0'; + fseek (id_FILE, idh.idh_tokens_offset, SEEK_SET); + while (gets_past_00 (old, id_FILE) > 0) + { + char *tmp; + if (!(tok_flags (old) & TOK_NAME)) + continue; + tmp = old; + old = new; + new = tmp; + if (!strnequ (new, old, limit)) + { + if (consecutive && merging) + { + strncpy (&name[1], old, limit); + (*doit) (name, bits_to_argv (bits_vec)); + } + consecutive = 0; + continue; + } + if (!consecutive++) + { + if (merging) + tree8_to_bits (bits_vec, tok_hits_addr (old)); + else + (*doit) (old, tree8_to_argv (tok_hits_addr (old))); + count++; + } + if (merging) + tree8_to_bits (bits_vec, tok_hits_addr (new)); + else + (*doit) (new, tree8_to_argv (tok_hits_addr (new))); + count++; + } + if (consecutive && merging) + { + strncpy (&name[1], new, limit); + (*doit) (name, bits_to_argv (bits_vec)); + } + return count; +} + +int +find_apropos (char const *arg, doit_t doit) +{ + int count; + + fseek (id_FILE, idh.idh_tokens_offset, SEEK_SET); + + count = 0; + if (merging) + memset (bits_vec, 0, bits_vec_size); + while (gets_past_00 (buf, id_FILE) > 0) + { + assert (*buf); + if (!frequency_wanted (buf)) + continue; + if (strcpos (buf, arg) == NULL) + continue; + if (merging) + tree8_to_bits (bits_vec, tok_hits_addr (buf)); + else + (*doit) (buf, tree8_to_argv (tok_hits_addr (buf))); + count++; + } + if (merging && count) + (*doit) (arg, bits_to_argv (bits_vec)); + + return count; +} + +void +parse_frequency_arg (char const *arg) +{ + if (*arg == '-') + frequency_low = 1; + else + { + frequency_low = atoi (arg); + while (isdigit (*arg)) + arg++; + if (*arg == '-') + arg++; + } + if (*arg) + frequency_high = atoi (arg); + else if (arg[-1] == '-') + frequency_high = USHRT_MAX; + else + frequency_high = frequency_low; + if (frequency_low > frequency_high) + fprintf (stderr, "Bogus frequencies: %u > %u\n", frequency_low, frequency_high); +} + +int +frequency_wanted (char const *tok) +{ + unsigned int count = tok_count (tok); + return (frequency_low <= count && count <= frequency_high); +} + +/* if string `s2' occurs in `s1', return a pointer to the first match. + Ignore differences in alphabetic case. */ +char const * +strcpos (char const *s1, char const *s2) +{ + char const *s1p; + char const *s2p; + char const *s1last; + + for (s1last = &s1[strlen (s1) - strlen (s2)]; s1 <= s1last; s1++) + for (s1p = s1, s2p = s2; TOLOWER (*s1p) == TOLOWER (*s2p); s1p++) + if (*++s2p == '\0') + return s1; + return NULL; +} + +/* Convert the regular expression that we used to locate identifiers + in the id database into one suitable for locating the identifiers + in files. */ +char const * +file_regexp (char const *name0, char const *left_delimit, char const *right_delimit) +{ + static char re_buffer[BUFSIZ]; + char *name = (char *) name0; + + if (find_func == find_number && merging) + { + sprintf (re_buffer, "%s0*[Xx]*0*%d[Ll]*%s", left_delimit, stoi (name), right_delimit); + return re_buffer; + } + + if (!is_regexp (name) && name[0] != '^') + return NULL; + + if (name[0] == '^') + name0++; + else + left_delimit = ""; + while (*++name) + ; + if (*--name == '$') + *name = '\0'; + else + right_delimit = ""; + + sprintf (re_buffer, "%s%s%s", left_delimit, name0, right_delimit); + return re_buffer; +} + +off_t +find_token (char const *token_0) +{ + off_t offset = 0; + off_t start = idh.idh_tokens_offset - 2; + off_t end = idh.idh_end_offset; + off_t anchor_offset = 0; + int order = -1; + + while (start < end) + { + int c; + int incr = 1; + char const *token; + + offset = start + (end - start) / 2; + fseek (id_FILE, offset, SEEK_SET); + offset += skip_past_00 (id_FILE); + if (offset >= end) + { + offset = start + 2; + fseek (id_FILE, offset, SEEK_SET); + } + + /* compare the token names */ + token = token_0; + while (*token == (c = getc (id_FILE)) && *token && c) + { + token++; + incr++; + } + if (c && !*token && find_func == find_anchor) + anchor_offset = offset; + order = *token - c; + + if (order < 0) + end = offset - 2; + else if (order > 0) + start = offset + incr + skip_past_00 (id_FILE) - 2; + else + break; + } + + if (order) + { + if (anchor_offset) + offset = anchor_offset; + else + return 0; + } + fseek (id_FILE, offset, SEEK_SET); + return offset; +} + +/* Are there any regexp meta-characters in name?? */ +int +is_regexp (char *name) +{ + int backslash = 0; + + if (*name == '^') + name++; + while (*name) + { + if (*name == '\\') + { + if (strchr ("<>", name[1])) + return 1; + name++, backslash++; + } + else if (strchr ("[]{}().*+^$", *name)) + return 1; + name++; + } + if (backslash) + while (*name) + { + if (*name == '\\') + strcpy (name, name + 1); + name++; + } + return 0; +} + +/* file_name_wildcard implements a simple pattern matcher that + emulates the shell wild card capability. + + * - any string of chars + ? - any char + [] - any char in set (if first char is !, any not in set) + \ - literal match next char */ +int +file_name_wildcard (char const *re, char const *fn) +{ + int c; + int i; + char set[256]; + int revset; + + while ((c = *re++) != '\0') + { + if (c == '*') + { + if (*re == '\0') + return 1; /* match anything at end */ + while (*fn != '\0') + { + if (file_name_wildcard (re, fn)) + return 1; + ++fn; + } + return 0; + } + else if (c == '?') + { + if (*fn++ == '\0') + return 0; + } + else if (c == '[') + { + c = *re++; + memset (set, 0, 256); + if (c == '!') + { + revset = 1; + c = *re++; + } + else + revset = 0; + while (c != ']') + { + if (c == '\\') + c = *re++; + set[c] = 1; + if ((*re == '-') && (*(re + 1) != ']')) + { + re += 1; + while (++c <= *re) + set[c] = 1; + ++re; + } + c = *re++; + } + if (revset) + for (i = 1; i < 256; ++i) + set[i] = !set[i]; + if (!set[(int)*fn++]) + return 0; + } + else + { + if (c == '\\') + c = *re++; + if (c != *fn++) + return 0; + } + } + return (*fn == '\0'); +} + +/* match_file_names implements the pid tool. This matches the *names* + of files in the database against the input pattern rather than the + *contents* of the files. */ + +int +match_file_names (char const *re, doit_t doit) +{ + char const *absname; + struct idarg *ida = id_args; + int i; + int count = 0; + int matched; + + if (file_name_regexp) + { + char const *regexp_error = re_comp (re); + if (regexp_error) + { + fprintf (stderr, "%s: Syntax Error: %s (%s)\n", program_name, re, regexp_error); + return 0; + } + } + + for (i = 0; i < idh.idh_paths; i++, ida++) + { + if (*ida->ida_arg == 0) + continue; + if (match_base) + { + absname = strrchr (ida->ida_arg, '/'); + if (absname == NULL) + absname = ida->ida_arg; + } + else + absname = span_file_name (id_dir, ida->ida_arg); + if (file_name_regexp) + matched = re_exec (absname); + else + matched = file_name_wildcard (re, absname); + if (matched) + { + BITSET (bits_vec, i); + ++count; + } + } + if (count) + (*doit) (re, bits_to_argv (bits_vec)); + return count; +} + +/* Does `name' occur in `line' delimited by non-alphanumerics?? */ +int +word_match (char const *name0, char const *line) +{ + char const *name = name0; + + for (;;) + { + /* find an initial-character match */ + while (*line != *name) + { + if (*line == '\n') + return 0; + line++; + } + /* do we have a word delimiter on the left ?? */ + if (isalnum (line[-1])) + { + line++; + continue; + } + /* march down both strings as long as we match */ + while (*++name == *++line) + ; + /* is this the end of `name', is there a word delimiter ?? */ + if (*name == '\0' && !IS_ALNUM (*line)) + return 1; + name = name0; + } +} + +/* Use the C lexical rules to determine an ascii number's radix. The + radix is returned as a bit map, so that more than one radix may + apply. In particular, it is impossible to determine the radix of + 0, so return all possibilities. */ +int +radix (char const *name) +{ + if (!isdigit (*name)) + return 0; + if (*name != '0') + return RADIX_DEC; + name++; + if (*name == 'x' || *name == 'X') + return RADIX_HEX; + while (*name && *name == '0') + name++; + return (RADIX_OCT | ((*name) ? 0 : RADIX_DEC)); +} + +/* Convert an ascii string number to an integer. Determine the radix + before converting. */ +int +stoi (char const *name) +{ + switch (radix (name)) + { + case RADIX_DEC: + return (dtoi (name)); + case RADIX_OCT: + return (otoi (&name[1])); + case RADIX_HEX: + return (xtoi (&name[2])); + case RADIX_DEC | RADIX_OCT: + return 0; + default: + return -1; + } +} + +/* Convert an ascii octal number to an integer. */ +int +otoi (char const *name) +{ + int n = 0; + + while (*name >= '0' && *name <= '7') + { + n *= 010; + n += *name++ - '0'; + } + if (*name == 'l' || *name == 'L') + name++; + return (*name ? -1 : n); +} + +/* Convert an ascii decimal number to an integer. */ +int +dtoi (char const *name) +{ + int n = 0; + + while (isdigit (*name)) + { + n *= 10; + n += *name++ - '0'; + } + if (*name == 'l' || *name == 'L') + name++; + return (*name ? -1 : n); +} + +/* Convert an ascii hex number to an integer. */ +int +xtoi (char const *name) +{ + int n = 0; + + while (isxdigit (*name)) + { + n *= 0x10; + if (isdigit (*name)) + n += *name++ - '0'; + else if (islower (*name)) + n += 0xa + *name++ - 'a'; + else + n += 0xA + *name++ - 'A'; + } + if (*name == 'l' || *name == 'L') + name++; + return (*name ? -1 : n); +} + +unsigned char * +tree8_to_bits (unsigned char *bits_vec, unsigned char const *hits_tree8) +{ + unsigned char* bv = bits_vec; + tree8_to_bits_1 (&bv, &hits_tree8, tree8_levels); + return bits_vec; +} + +void +tree8_to_bits_1 (unsigned char **bits_vec, unsigned char const **hits_tree8, int level) +{ + int hits = *(*hits_tree8)++; + + if (--level) + { + int incr = 1 << ((level - 1) * 3); + int bit; + for (bit = 1; bit & 0xff; bit <<= 1) + { + if (bit & hits) + tree8_to_bits_1 (bits_vec, hits_tree8, level); + else + *bits_vec += incr; + } + } + else + *(*bits_vec)++ |= hits; +} + +char ** +bits_to_argv (unsigned char const *bits_vec) +{ + int const reserved_argv_slots = 3; + static char **argv_0; + char **argv; + struct idarg *ida = id_args; + struct idarg *end = &id_args[idh.idh_paths]; + + if (argv_0 == NULL) + argv_0 = MALLOC (char *, idh.idh_paths + reserved_argv_slots + 2); + argv = &argv_0[reserved_argv_slots]; + + for (;;) + { + int hits; + int bit; + + while (*bits_vec == 0) + { + bits_vec++; + ida += 8; + if (ida >= end) + goto out; + } + hits = *bits_vec++; + for (bit = 1; bit & 0xff; bit <<= 1) + { + if (bit & hits) + { + if (!(ida->ida_flags & IDA_RELATIVE)) + { + char const *abs_name = span_file_name (id_dir, ida->ida_arg); + char const *rel_name = relative_file_name (PWD_name, abs_name); + char const *short_name = (strlen (rel_name) > strlen (abs_name) + ? abs_name : rel_name); + if (!strequ (short_name, ida->ida_arg)) + ida->ida_arg = strdup (short_name); + ida->ida_flags |= IDA_RELATIVE; + } + *argv++ = ida->ida_arg; + } + if (++ida >= end) + goto out; + } + } +out: + *argv = NULL; + return &argv_0[reserved_argv_slots]; +} + +char ** +tree8_to_argv (unsigned char const *hits_tree8) +{ + memset (bits_vec, 0, bits_vec_size); + return bits_to_argv (tree8_to_bits (bits_vec, hits_tree8)); +} + +#if HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#if HAVE_TERMIOS_H || HAVE_TERMIO_H +#if HAVE_TERMIOS_H +#include <termios.h> +#endif +#if HAVE_TERMIO_H +#include <termio.h> +#endif + +struct termio linemode; +struct termio charmode; +struct termio savemode; + +void +savetty (void) +{ + ioctl (0, TCGETA, &savemode); + charmode = linemode = savemode; + + charmode.c_lflag &= ~(ECHO | ICANON | ISIG); + charmode.c_cc[VMIN] = 1; + charmode.c_cc[VTIME] = 0; + + linemode.c_lflag |= (ECHO | ICANON | ISIG); + linemode.c_cc[VEOF] = 'd' & 037; + linemode.c_cc[VEOL] = 0377; +} + +void +restoretty (void) +{ + ioctl (0, TCSETA, &savemode); +} + +void +linetty (void) +{ + ioctl (0, TCSETA, &linemode); +} + +void +chartty (void) +{ + ioctl (0, TCSETA, &charmode); +} + +#else /* not HAVE_TERMIOS_H || HAVE_TERMIO_H */ + +#if HAVE_SGTTYB_H +#include <sgttyb.h> + +struct sgttyb linemode; +struct sgttyb charmode; +struct sgttyb savemode; + +savetty() +{ +#ifdef TIOCGETP + ioctl(0, TIOCGETP, &savemode); +#else + gtty(0, &savemode); +#endif + charmode = linemode = savemode; + + charmode.sg_flags &= ~ECHO; + charmode.sg_flags |= RAW; + + linemode.sg_flags |= ECHO; + linemode.sg_flags &= ~RAW; +} + +restoretty() +{ +#ifdef TIOCSETP + ioctl(0, TIOCSETP, &savemode); +#else + stty(0, &savemode); +#endif +} + +linetty() +{ +#ifdef TIOCSETP + ioctl(0, TIOCSETP, &linemode); +#else + stty(0, &linemode); +#endif +} + +chartty() +{ +#ifdef TIOCSETP + ioctl(0, TIOCSETP, &charmode); +#else + stty(0, &charmode); +#endif +} + +#endif /* HAVE_SGTTYB_H */ +#endif /* not HAVE_TERMIOS_H || HAVE_TERMIO_H */ |