From:	MERC::"uunet!WKUVX1.BITNET!FILESERV-Mgr" 12-JUN-1992 15:44:44.40
To:	galaxy::gleeve
CC:	
Subj:	GREP.10_OF_12

-+-+-+-+-+-+-+-+ START OF PART 10 -+-+-+-+-+-+-+-+
X`09`09     `7C`7C *p2 == (unsigned char) endline)
X`09      `7B
X`09`09register int c = *p2 == (unsigned char) endline ? '\n' : p2`5B2`5D;
X`09`09register unsigned char *p1 = p + mcnt;
X`09`09/* p1`5B0`5D ... p1`5B2`5D are an on_failure_jump.
X`09`09   Examine what follows that */
X`09`09if (p1`5B3`5D == (unsigned char) exactn && p1`5B5`5D != c)
X`09`09  p`5B-3`5D = (unsigned char) finalize_jump;
X`09`09else if (p1`5B3`5D == (unsigned char) charset
X`09`09`09 `7C`7C p1`5B3`5D == (unsigned char) charset_not)
X`09`09  `7B
X`09`09    int not = p1`5B3`5D == (unsigned char) charset_not;
X`09`09    if (c < p1`5B4`5D * BYTEWIDTH
X`09`09`09&& p1`5B5 + c / BYTEWIDTH`5D & (1 << (c % BYTEWIDTH)))
X`09`09      not = !not;
X`09`09    /* not is 1 if c would match */
X`09`09    /* That means it is not safe to finalize */
X`09`09    if (!not)
X`09`09      p`5B-3`5D = (unsigned char) finalize_jump;
X`09`09  `7D
X`09      `7D
X`09  `7D
X`09  p -= 2;
X`09  if (p`5B-1`5D != (unsigned char) finalize_jump)
X`09    `7B
X`09      p`5B-1`5D = (unsigned char) jump;
X`09      goto nofinalize;
X`09    `7D
X
X`09/* The end of a stupid repeat has a finalize-jump
X`09   back to the start, where another failure point will be made
X`09   which will point after all the repetitions found so far. */
X
X`09case finalize_jump:
X`09  stackp -= 2;
X
X`09case jump:
X`09nofinalize:
X`09  mcnt = *p++ & 0377;
X`09  mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
X`09  p += mcnt + 1;`09/* The 1 compensates for missing ++ above */
X`09  break;
X
X`09case dummy_failure_jump:
X`09  if (stackp == stacke)
X`09    `7B
X`09      unsigned char **stackx
X`09`09= (unsigned char **) alloca (2 * (stacke - stackb)
X`09`09`09`09`09     * sizeof (char *));
X`09      bcopy (stackb, stackx, (stacke - stackb) * sizeof (char *));
X`09      stackp = stackx + (stackp - stackb);
X`09      stacke = stackx + 2 * (stacke - stackb);
X`09      stackb = stackx;
X`09    `7D
X`09  *stackp++ = 0;
X`09  *stackp++ = 0;
X`09  goto nofinalize;
X
X`09case wordbound:
X`09  if (d == string1  /* Points to first char */
X`09      `7C`7C d == end2  /* Points to end */
X`09      `7C`7C (d == end1 && size2 == 0)) /* Points to end */
X`09    break;
X`09  if ((SYNTAX (d`5B-1`5D) == Sword)
X`09      != (SYNTAX (d == end1 ? *string2 : *d) == Sword))
X`09    break;
X`09  goto fail;
X
X`09case notwordbound:
X`09  if (d == string1  /* Points to first char */
X`09      `7C`7C d == end2  /* Points to end */
X`09      `7C`7C (d == end1 && size2 == 0)) /* Points to end */
X`09    goto fail;
X`09  if ((SYNTAX (d`5B-1`5D) == Sword)
X`09      != (SYNTAX (d == end1 ? *string2 : *d) == Sword))
X`09    goto fail;
X`09  break;
X
X`09case wordbeg:
X`09  if (d == end2  /* Points to end */
X`09      `7C`7C (d == end1 && size2 == 0) /* Points to end */
X`09      `7C`7C SYNTAX (* (d == end1 ? string2 : d)) != Sword) /* Next char
V not a letter */
X`09    goto fail;
X`09  if (d == string1  /* Points to first char */
X`09      `7C`7C SYNTAX (d`5B-1`5D) != Sword)  /* prev char not letter */
X`09    break;
X`09  goto fail;
X
X`09case wordend:
X`09  if (d == string1  /* Points to first char */
X`09      `7C`7C SYNTAX (d`5B-1`5D) != Sword)  /* prev char not letter */
X`09    goto fail;
X`09  if (d == end2  /* Points to end */
X`09      `7C`7C (d == end1 && size2 == 0) /* Points to end */
X`09      `7C`7C SYNTAX (d == end1 ? *string2 : *d) != Sword) /* Next char no
Vt a letter */
X`09    break;
X`09  goto fail;
X
X#ifdef emacs
X`09case before_dot:
X`09  if (((d - string2 <= (unsigned) size2)
X`09       ? d - bf_p2 : d - bf_p1)
X`09      <= point)
X`09    goto fail;
X`09  break;
X
X`09case at_dot:
X`09  if (((d - string2 <= (unsigned) size2)
X`09       ? d - bf_p2 : d - bf_p1)
X`09      == point)
X`09    goto fail;
X`09  break;
X
X`09case after_dot:
X`09  if (((d - string2 <= (unsigned) size2)
X`09       ? d - bf_p2 : d - bf_p1)
X`09      >= point)
X`09    goto fail;
X`09  break;
X
X`09case wordchar:
X`09  mcnt = (int) Sword;
X`09  goto matchsyntax;
X
X`09case syntaxspec:
X`09  mcnt = *p++;
X`09matchsyntax:
X`09  PREFETCH;
X`09  if (SYNTAX (*d++) != (enum syntaxcode) mcnt) goto fail;
X`09  break;
X`09 `20
X`09case notwordchar:
X`09  mcnt = (int) Sword;
X`09  goto matchnotsyntax;
X
X`09case notsyntaxspec:
X`09  mcnt = *p++;
X`09matchnotsyntax:
X`09  PREFETCH;
X`09  if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail;
X`09  break;
X#else
X`09case wordchar:
X`09  PREFETCH;
X`09  if (SYNTAX (*d++) == 0) goto fail;
X`09  break;
X`09 `20
X`09case notwordchar:
X`09  PREFETCH;
X`09  if (SYNTAX (*d++) != 0) goto fail;
X`09  break;
X#endif /* not emacs */
X
X`09case begbuf:
X`09  if (d == string1)`09/* Note, d cannot equal string2 */
X`09    break;`09`09/* unless string1 == string2.  */
X`09  goto fail;
X
X`09case endbuf:
X`09  if (d == end2 `7C`7C (d == end1 && size2 == 0))
X`09    break;
X`09  goto fail;
X
X`09case exactn:
X`09  /* Match the next few pattern characters exactly.
X`09     mcnt is how many characters to match. */
X`09  mcnt = *p++;
X`09  if (translate)
X`09    `7B
X`09      do
X`09`09`7B
X`09`09  PREFETCH;
X`09`09  if (translate`5B*d++`5D != *p++) goto fail;
X`09`09`7D
X`09      while (--mcnt);
X`09    `7D
X`09  else
X`09    `7B
X`09      do
X`09`09`7B
X`09`09  PREFETCH;
X`09`09  if (*d++ != *p++) goto fail;
X`09`09`7D
X`09      while (--mcnt);
X`09    `7D
X`09  break;
X
X`09default:
X`09  break;
X`09`7D
X      continue;    /* Successfully matched one pattern command; keep matchin
Vg */
X
X      /* Jump here if any matching operation fails. */
X    fail:
X      if (stackp != stackb)
X`09/* A restart point is known.  Restart there and pop it. */
X`09`7B
X`09  if (!stackp`5B-2`5D)
X`09    `7B   /* If innermost failure point is dormant, flush it and keep loo
Vking */
X`09      stackp -= 2;
X`09      goto fail;
X`09    `7D
X`09  d = *--stackp;
X`09  p = *--stackp;
X`09  if (d >= string1 && d <= end1)
X`09    dend = end_match_1;
X`09`7D
X      else break;   /* Matching at this starting point really fails! */
X    `7D
X  return -1;         /* Failure to match */
X`7D
X
Xstatic int
Xbcmp_translate (s1, s2, len, translate)
X     unsigned char *s1, *s2;
X     register int len;
X     unsigned char *translate;
X`7B
X  register unsigned char *p1 = s1, *p2 = s2;
X  while (len)
X    `7B
X      if (translate `5B*p1++`5D != translate `5B*p2++`5D) return 1;
X      len--;
X    `7D
X  return 0;
X`7D
X`0C
X/* Entry points compatible with bsd4.2 regex library */
X
X#ifndef emacs
X
Xstatic struct re_pattern_buffer re_comp_buf;
X
Xchar *
Xre_comp (s)
X     char *s;
X`7B
X  if (!s)
X    `7B
X      if (!re_comp_buf.buffer)
X`09return "No previous regular expression";
X      return 0;
X    `7D
X
X  if (!re_comp_buf.buffer)
X    `7B
X      if (!(re_comp_buf.buffer = (char *) malloc (200)))
X`09return "Memory exhausted";
X      re_comp_buf.allocated = 200;
X      if (!(re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH)))
X`09return "Memory exhausted";
X    `7D
X  return re_compile_pattern (s, strlen (s), &re_comp_buf);
X`7D
X
Xint
Xre_exec (s)
X     char *s;
X`7B
X  int len = strlen (s);
X  return 0 <= re_search (&re_comp_buf, s, len, 0, len, 0);
X`7D
X
X#endif /* emacs */
X`0C
X#ifdef test
X
X#include <stdio.h>
X
X/* Indexed by a character, gives the upper case equivalent of the character
V */
X
Xstatic char upcase`5B0400`5D =`20
X  `7B 000, 001, 002, 003, 004, 005, 006, 007,
X    010, 011, 012, 013, 014, 015, 016, 017,
X    020, 021, 022, 023, 024, 025, 026, 027,
X    030, 031, 032, 033, 034, 035, 036, 037,
X    040, 041, 042, 043, 044, 045, 046, 047,
X    050, 051, 052, 053, 054, 055, 056, 057,
X    060, 061, 062, 063, 064, 065, 066, 067,
X    070, 071, 072, 073, 074, 075, 076, 077,
X    0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
X    0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
X    0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
X    0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137,
X    0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
X    0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
X    0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
X    0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177,
X    0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
X    0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
X    0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
X    0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
X    0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
X    0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
X    0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
X    0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
X    0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
X    0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
X    0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
X    0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
X    0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
X    0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
X    0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
X    0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
X  `7D;
X
Xmain (argc, argv)
X     int argc;
X     char **argv;
X`7B
X  char pat`5B80`5D;
X  struct re_pattern_buffer buf;
X  int i;
X  char c;
X  char fastmap`5B(1 << BYTEWIDTH)`5D;
X
X  /* Allow a command argument to specify the style of syntax.  */
X  if (argc > 1)
X    obscure_syntax = atoi (argv`5B1`5D);
X
X  buf.allocated = 40;
X  buf.buffer = (char *) malloc (buf.allocated);
X  buf.fastmap = fastmap;
X  buf.translate = upcase;
X
X  while (1)
X    `7B
X      gets (pat);
X
X      if (*pat)
X`09`7B
X          re_compile_pattern (pat, strlen(pat), &buf);
X
X`09  for (i = 0; i < buf.used; i++)
X`09    printchar (buf.buffer`5Bi`5D);
X
X`09  putchar ('\n');
X
X`09  printf ("%d allocated, %d used.\n", buf.allocated, buf.used);
X
X`09  re_compile_fastmap (&buf);
X`09  printf ("Allowed by fastmap: ");
X`09  for (i = 0; i < (1 << BYTEWIDTH); i++)
X`09    if (fastmap`5Bi`5D) printchar (i);
X`09  putchar ('\n');
X`09`7D
X
X      gets (pat);`09/* Now read the string to match against */
X
X      i = re_match (&buf, pat, strlen (pat), 0, 0);
X      printf ("Match value %d.\n", i);
X    `7D
X`7D
X
X#ifdef NOTDEF
Xprint_buf (bufp)
X     struct re_pattern_buffer *bufp;
X`7B
X  int i;
X
X  printf ("buf is :\n----------------\n");
X  for (i = 0; i < bufp->used; i++)
X    printchar (bufp->buffer`5Bi`5D);
X `20
X  printf ("\n%d allocated, %d used.\n", bufp->allocated, bufp->used);
X `20
X  printf ("Allowed by fastmap: ");
X  for (i = 0; i < (1 << BYTEWIDTH); i++)
X    if (bufp->fastmap`5Bi`5D)
X      printchar (i);
X  printf ("\nAllowed by translate: ");
X  if (bufp->translate)
X    for (i = 0; i < (1 << BYTEWIDTH); i++)
X      if (bufp->translate`5Bi`5D)
X`09printchar (i);
X  printf ("\nfastmap is%s accurate\n", bufp->fastmap_accurate ? "" : "n't");
X  printf ("can %s be null\n----------", bufp->can_be_null ? "" : "not");
X`7D
X#endif
X
Xprintchar (c)
X     char c;
X`7B
X  if (c < 041 `7C`7C c >= 0177)
X    `7B
X      putchar ('\\');
X      putchar (((c >> 6) & 3) + '0');
X      putchar (((c >> 3) & 7) + '0');
X      putchar ((c & 7) + '0');
X    `7D
X  else
X    putchar (c);
X`7D
X
Xerror (string)
X     char *string;
X`7B
X  puts (string);
X  exit (1);
X`7D
X
X#endif /* test */
$ CALL UNPACK [.GREP016]REGEX.C;1 1748649007
$ create 'f'
X/* Definitions for data structures callers pass the regex library.
X   Copyright (C) 1985, 1989 Free Software Foundation, Inc.
X
X   This program is free software; you can redistribute it and/or modify
X   it under the terms of the GNU General Public License as published by
X   the Free Software Foundation; either version 2, or (at your option)
X   any later version.
X
X   This program is distributed in the hope that it will be useful,
X   but WITHOUT ANY WARRANTY; without even the implied warranty of
X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X   GNU General Public License for more details.
X
X   You should have received a copy of the GNU General Public License
X   along with this program; if not, write to the Free Software
X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
X
X   In other words, you are welcome to use, share and improve this program.
X   You are forbidden to forbid anyone else to use, share and improve
X   what you give them.   Help stamp out software-hoarding!  */
X
X
X/* Define number of parens for which we record the beginnings and ends.
X   This affects how much space the `60struct re_registers' type takes up.  *
V/
X#ifndef RE_NREGS
X#define RE_NREGS 10
X#endif
X
X/* These bits are used in the obscure_syntax variable to choose among
X   alternative regexp syntaxes.  */
X
X/* 1 means plain parentheses serve as grouping, and backslash
X     parentheses are needed for literal searching.
X   0 means backslash-parentheses are grouping, and plain parentheses
X     are for literal searching.  */
X#define RE_NO_BK_PARENS 1
X
X/* 1 means plain `7C serves as the "or"-operator, and \`7C is a literal.
X   0 means \`7C serves as the "or"-operator, and `7C is a literal.  */
X#define RE_NO_BK_VBAR 2
X
X/* 0 means plain + or ? serves as an operator, and \+, \? are literals.
X   1 means \+, \? are operators and plain +, ? are literals.  */
X#define RE_BK_PLUS_QM 4
X
X/* 1 means `7C binds tighter than `5E or $.
X   0 means the contrary.  */
X#define RE_TIGHT_VBAR 8
X
X/* 1 means treat \n as an _OR operator
X   0 means treat it as a normal character */
X#define RE_NEWLINE_OR 16
X
X/* 0 means that a special characters (such as *, `5E, and $) always have
X     their special meaning regardless of the surrounding context.
X   1 means that special characters may act as normal characters in some
X     contexts.  Specifically, this applies to:
X`09`5E - only special at the beginning, or after ( or `7C
X`09$ - only special at the end, or before ) or `7C
X`09*, +, ? - only special when not after the beginning, (, or `7C */
X#define RE_CONTEXT_INDEP_OPS 32
X
X/* Now define combinations of bits for the standard possibilities.  */
X#define RE_SYNTAX_AWK (RE_NO_BK_PARENS `7C RE_NO_BK_VBAR `7C RE_CONTEXT_INDE
VP_OPS)
X#define RE_SYNTAX_EGREP (RE_SYNTAX_AWK `7C RE_NEWLINE_OR)
X#define RE_SYNTAX_GREP (RE_BK_PLUS_QM `7C RE_NEWLINE_OR)
X#define RE_SYNTAX_EMACS 0
X
X/* This data structure is used to represent a compiled pattern. */
X
Xstruct re_pattern_buffer
X  `7B
X    char *buffer;`09/* Space holding the compiled pattern commands. */
X    int allocated;`09/* Size of space that  buffer  points to */
X    int used;`09`09/* Length of portion of buffer actually occupied */
X    char *fastmap;`09/* Pointer to fastmap, if any, or zero if none. */
X`09`09`09/* re_search uses the fastmap, if there is one,
X`09`09`09   to skip quickly over totally implausible characters */
X    char *translate;`09/* Translate table to apply to all characters before
V comparing.
X`09`09`09   Or zero for no translation.
X`09`09`09   The translation is applied to a pattern when it is compiled
X`09`09`09   and to data when it is matched. */
X    char fastmap_accurate;
X`09`09`09/* Set to zero when a new pattern is stored,
X`09`09`09   set to one when the fastmap is updated from it. */
X    char can_be_null;   /* Set to one by compiling fastmap
X`09`09`09   if this pattern might match the null string.
X`09`09`09   It does not necessarily match the null string
X`09`09`09   in that case, but if this is zero, it cannot.
X`09`09`09   2 as value means can match null string
X`09`09`09   but at end of range or before a character
X`09`09`09   listed in the fastmap.  */
X  `7D;
X
X/* Structure to store "register" contents data in.
X
X   Pass the address of such a structure as an argument to re_match, etc.,
X   if you want this information back.
X
X   start`5Bi`5D and end`5Bi`5D record the string matched by \( ... \) groupi
Vng i,
X   for i from 1 to RE_NREGS - 1.
X   start`5B0`5D and end`5B0`5D record the entire string matched. */
X
Xstruct re_registers
X  `7B
X    int start`5BRE_NREGS`5D;
X    int end`5BRE_NREGS`5D;
X  `7D;
X
X/* These are the command codes that appear in compiled regular expressions,
V one per byte.
X  Some command codes are followed by argument bytes.
X  A command code can specify any interpretation whatever for its arguments.
X  Zero-bytes may appear in the compiled regular expression. */
X
Xenum regexpcode
X  `7B
X    unused,
X    exactn,    /* followed by one byte giving n, and then by n literal bytes
V */
X    begline,   /* fails unless at beginning of line */
X    endline,   /* fails unless at end of line */
X    jump,`09 /* followed by two bytes giving relative address to jump to */
X    on_failure_jump,`09 /* followed by two bytes giving relative address of
V place
X`09`09            to resume at in case of failure. */
X    finalize_jump,`09 /* Throw away latest failure point and then jump to ad
Vdress. */
X    maybe_finalize_jump, /* Like jump but finalize if safe to do so.
X`09`09`09    This is used to jump back to the beginning
X`09`09`09    of a repeat.  If the command that follows
X`09`09`09    this jump is clearly incompatible with the
X`09`09`09    one at the beginning of the repeat, such that
X`09`09`09    we can be sure that there is no use backtracking
X`09`09`09    out of repetitions already completed,
X`09`09`09    then we finalize. */
X    dummy_failure_jump,  /* jump, and push a dummy failure point.
X`09`09`09    This failure point will be thrown away
X`09`09`09    if an attempt is made to use it for a failure.
X`09`09`09    A + construct makes this before the first repeat.  */
X    anychar,`09 /* matches any one character */
X    charset,     /* matches any one char belonging to specified set.
X`09`09    First following byte is # bitmap bytes.
X`09`09    Then come bytes for a bit-map saying which chars are in.
X`09`09    Bits in each byte are ordered low-bit-first.
X`09`09    A character is in the set if its bit is 1.
X`09`09    A character too large to have a bit in the map
X`09`09    is automatically not in the set */
X    charset_not, /* similar but match any character that is NOT one of those
V specified */
X    start_memory, /* starts remembering the text that is matched
X`09`09    and stores it in a memory register.
X`09`09    followed by one byte containing the register number.
X`09`09    Register numbers must be in the range 0 through NREGS. */
X    stop_memory, /* stops remembering the text that is matched
X`09`09    and stores it in a memory register.
X`09`09    followed by one byte containing the register number.
X`09`09    Register numbers must be in the range 0 through NREGS. */
X    duplicate,    /* match a duplicate of something remembered.
X`09`09    Followed by one byte containing the index of the memory register.
V */
X    before_dot,`09 /* Succeeds if before dot */
X    at_dot,`09 /* Succeeds if at dot */
X    after_dot,`09 /* Succeeds if after dot */
X    begbuf,      /* Succeeds if at beginning of buffer */
X    endbuf,      /* Succeeds if at end of buffer */
X    wordchar,    /* Matches any word-constituent character */
X    notwordchar, /* Matches any char that is not a word-constituent */
X    wordbeg,`09 /* Succeeds if at word beginning */
X    wordend,`09 /* Succeeds if at word end */
X    wordbound,   /* Succeeds if at a word boundary */
X    notwordbound, /* Succeeds if not at a word boundary */
X    syntaxspec,  /* Matches any character whose syntax is specified.
X`09`09    followed by a byte which contains a syntax code, Sword or such lik
Ve */
X    notsyntaxspec /* Matches any character whose syntax differs from the spe
Vcified. */
X  `7D;
X`0C
Xextern char *re_compile_pattern ();
X/* Is this really advertised? */
Xextern void re_compile_fastmap ();
Xextern int re_search (), re_search_2 ();
Xextern int re_match (), re_match_2 ();
X
X/* 4.2 bsd compatibility (yuck) */
Xextern char *re_comp ();
Xextern int re_exec ();
X
X#ifdef SYNTAX_TABLE
Xextern char *re_syntax_table;
X#endif
$ CALL UNPACK [.GREP016]REGEX.H;1 1778955074
$ create 'f'
X/******************************************************************/
X
X#ifdef VAXC`09`09`09/* v1.2-004 */
X#module SHELL_MUNG "Jym V1.2-005"       /* Only VAX C understands this. */
X#else`09`09`09`09/* v1.2-004 */
X#define`09TRUE`09`091`09/* GNU C stdio.h doesn't define TRUE and FALSE*/
X#define`09FALSE`09`090
X#endif
X
X/* SHELL_MUNG.C
X**==========================================================================
V===
X** Copyright (C) 1989 Jym Dyer (jym@wheaties.ai.mit.edu)
X**
X** This program is free software; you can redistribute it and/or modify
X** it under the terms of the GNU General Public License as published by
X** the Free Software Foundation; either version 1, or (at your option)
X** any later version.
X**
X** This program is distributed in the hope that it will be useful,
X** but WITHOUT ANY WARRANTY; without even the implied warranty of
X** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X** GNU General Public License for more details.
X**
X** You should have received a copy of the GNU General Public License
X** along with this program; if not, write to the Free Software
X** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X**--------------------------------------------------------------------------
V---
X** Version:     V1.2-005
X**--------------------------------------------------------------------------
V---
X** Facility:    GNU
X**--------------------------------------------------------------------------
V---
X** Prefix:      SHELL_
X**--------------------------------------------------------------------------
V---
X** Abstract
X** `7E`7E`7E`7E`7E`7E`7E`7E
X**  If you think "shell mung" is a step in the preparation of a good mung da
Vhl,
X** you're right, but in this context "mung" is the verb.  ("Mung" historical
Vly
X** means "mung until no good," but one could easily interpret it to mean "mu
Vng
X** until nearly gnu".  Or something to that effect.)
X**  This file provides the shell_glob() and shell_mung() functions for the
X** VMS/DCL/VAX C user.  The shell_glob() function "globs" (parses filespecs
X** with wildcards and matches them with existing files).  The shell_mung()
X** function provides GNU-shell-like IO redirection and globbing:  it changes
X** `60stderr', `60stdin', and/or `60stdout' to do the IO redirection; it mun
Vgs a
X** VAX C program's main() function's `60argc' and `60argv' variables (using
V shell_
X** glob()) to do the globbing; and it truncates `60argv`5B0`5D' down to a fi
Vlename
X** and filetype or, if the file is a .EXE file, to just the filename.
X**  This makes it easy to port many GNU utilities to VMS, as these utilities
X** often expect the shell to have done the work that shell_mung() does.  It
V can
X** also be used to port Un*x utilities as well, if anybody cares.
X**--------------------------------------------------------------------------
V---
X** Functions
X** `7E`7E`7E`7E`7E`7E`7E`7E`7E
X** shell_glob()
X** shell_mung()
X** (static) truncate_argv_0()
X**--------------------------------------------------------------------------
V---
X** Environment
X** `7E`7E`7E`7E`7E`7E`7E`7E`7E`7E`7E
X**  Must be linked with the VAX C RTL.  Intended for use with the DCL CLI on
X** VMS; it would be pointless to use shell_mung() with the SHELL CLI, though
X** shell_glob() might possibly come in handy.
X**  Must be linked with xmalloc() and xrealloc() functions, which are readil
Vy
X** available from GNU source code.  These are simply malloc() and realloc()
X** functions that exit if there is an error getting memory.
X**--------------------------------------------------------------------------
V---
X** Author:      Jym Dyer (jym@wheaties.ai.mit) 8-Apr-1988
X**--------------------------------------------------------------------------
V---
X** Modifications
X** `7E`7E`7E`7E`7E`7E`7E`7E`7E`7E`7E`7E`7E
X** 1.0-001 - Original version.  Inspired by the DECUS C getredirection()
X**           function written by Martin Minow, Jerry Leichter, and Jym Dyer.
X**           `7BJym 8-Apr-1988`7D
X** 1.1-002 - Added `60shell_default' and use of same by shell_glob(), which
X**           allows default filespecs to be used in globbing.
X**           `7BJym 9-Jan-1989`7D
X** 1.2-003 - Made shell_glob() accept unglobbable filespecs.
X**         - In addition to '-', '+' is now accepted as the start of an opti
Von.
X**           `7BJym 3-Jun-1989`7D
X** 1.2-004 - Made changes to allow compilation by GNU C.
X**`09     `7BHunter Goatley, goathunter@WKUVX1.BITNET, 12-SEP-1991`7D
X** 1.2-005 - Added Andrew Greer's patch to fix problem parsing non-filespec
X**`09     arguments to options
X**`09     `7BHunter Goatley, goathunter@WKUVX1.BITNET, 22-SEP-1991`7D
X**`09     `7BAndrew Greer, <Andrew.Greer@vuw.ac.nz>`7D
X**==========================================================================
V===
X*/
X
X/* -=- FILE INCLUSIONS -=- */
X
X#include <ctype.h>
X#include <errno.h>
X#include <stdio.h>
X#include <string.h>
X
X#include <fab.h>
X#include <nam.h>
X#include <rmsdef.h>
X#include <stsdef.h>
X
X#ifndef VAXC`09`09`09`09/* v1.2-004 */
X#define _tolower(c)     ((c) >= 'A' && (c) <= 'Z' ? (c) `7C 0x20:(c))
X#endif`09`09`09/* Also changed tolower() calls to _tolower() */
X
X/* -=- FORWARD DECLARATIONS -=- */
X
Xextern void *  xmalloc();
Xextern void *  xrealloc();
X
Xextern void  sys$exit();
Xextern int  sys$parse();
Xextern int  sys$search();
X
Xextern char **  shell_glob();
Xstatic char *  truncate_argv_0();
X
X/* -=- GLOBAL VARIABLE DEFINITION -=- */
X
X#ifdef VAXC`09`09`09`09/* v1.2-004 */
Xglobaldef char *  shell_default = NULL; /* Default filespec for shell_glob()
V.*/
X#else
Xchar *  shell_default = NULL;`09`09/* Default filespec for shell_glob().*/
X#endif
X                                        /* Initialized here to NULL, which
X                                        ** means that no default filespec is
X                                        ** used by shell_glob().
X                                        */
X
X/* -=- FUNCTIONS -=- */
X
X/* shell_glob()
X**--------------------------------------------------------------------------
V---
X** Functional Description
X** `7E`7E`7E`7E`7E`7E`7E`7E`7E`7E`7E`7E`7E`7E`7E`7E`7E`7E`7E`7E`7E`7E
X**  Given a filespec, this function parses that filespec out and searches fo
Vr
X** the file---or, if the filespec has wildcard characters in it, the files--
V-
X** associated with the filespec.  It returns a newly-allocated vector of fil
Ve-
X** specs that are also newly-allocated.  This function can be used to find o
Vnly
X** the first file that matches the filespec or all the files that match it.
V  In
X** the latter case, this function will also provide a count of the files tha
Vt
X** were found.
X**  Filespecs returned by this function are in lowercase, to approximate the
X** "look and feel" of GNU.
X**  This function is used by shell_mung(), and is also handy for general use
V.
X**--------------------------------------------------------------------------
V---
X** Usage
X** `7E`7E`7E`7E`7E
X**  This function returns a vector---that is, a pointer to pointers.  Thus y
Vou
X** will need to declare this function and a vector like this:
X**
X**      extern char **  shell_glob();
X**
X**      char **  filespec_v;
X**
X**  To find only the first match of a wildcarded filespec, or just to get th
Ve
X** fully-parsed filespec of a given filespec, call shell_glob() with NULL as
X** its second parameter.  For example, if you call it like this:
X**
X**      static int const  filespec = "*.c";
X**      char **  filespec_v;
X**              ...
X**      filespec_v = shell_glob(filespec,NULL);
X**
X** The value in `60filespec_v`5B0`5D' will be (for example) "dev:`5Bdir`5Dba
Vr.c;".  Note
X** that the character string pointer is the content of the vector, not the
X** vector itself.
X**  With this usage, `60filespec_v' points to a pointer (actually an array o
Vf one
X** pointer, which is the same thing).  When used to get a number of filespec
Vs,
X** it points to an array of pointers.
X**  To get all the filespecs that match a filespec, use an address of an
X** integer as shell_glob()'s second parameter, as in this example:
X**
X**      static int const  filespec = "*.c";
X**      int  filespec_count;
X**      char **  filespec_v;
X**              ...
X**      filespec_v = shell_glob(filespec,&filespec_count);
X**
X** The result of this would be (for example),
X**
X**      filespec_count = 3,
X**      filespec_v`5B0`5D = "dev:`5Bdir`5Dbar.c",
X**      filespec_v`5B1`5D = "dev:`5Bdir`5Dbaz.c", and
X**      filespec_v`5B2`5D = "dev:`5Bdir`5Dfoo.c".
X**
X**  In either type of usage, both the vector and the character strings are i
Vn
X** newly-allocated memory.
X**  VMS globbing entails a feature that allows one to fill in parts of a fil
Ve-
X** spec with default values.  This feature can be used by shell_glob() using
X** `60shell_default', a global character string.  Use of this character stri
Vng is
+-+-+-+-+-+-+-+-  END  OF PART 10 +-+-+-+-+-+-+-+-
