[comp.sources.unix] v24i090: Program identifier database tools, Part02/07

rsalz@bbn.com (Rich Salz) (06/06/91)

Submitted-by: Tom Horsley <tom@hcx2.ssd.csd.harris.com>
Posting-number: Volume 24, Issue 90
Archive-name: mkid2/part02

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 7)."
# Contents:  cannoname.c iid.1 iid.help mkid.1 paths.c scan-text.c
#   symfunc.el unsymlink.c
# Wrapped by tom@hcx2 on Tue Feb 26 10:03:02 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'cannoname.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cannoname.c'\"
else
echo shar: Extracting \"'cannoname.c'\" \(4112 characters\)
sed "s/^X//" >'cannoname.c' <<'END_OF_FILE'
X/* This file contains routines which put a file name into cannonical
X * form.
X */
X
X#define NULL 0
X
X/* define special name components */
X
Xstatic char slash[]  = "/" ;
Xstatic char dot[]    = "." ;
Xstatic char dotdot[] = ".." ;
X
X/* nextc points to the next character to look at in the string or is
X * null if the end of string was reached.
X *
X * namep points to buffer that holds the components.
X */
Xstatic char * nextc = NULL ;
Xstatic char * namep ;
X
X/* lexname - Return next name component. Uses global variables initialized
X * by cannoname to figure out what it is scanning.
X */
Xstatic char *
Xlexname()
X{
X   char   c ;
X   char * d ;
X
X   if (nextc) {
X      c = *nextc++ ;
X      if (c == '\0') {
X         nextc = NULL ;
X         return(NULL) ;
X      }
X      if (c == '/') {
X         return(&slash[0]) ;
X      }
X      if (c == '.') {
X         if ((*nextc == '/') || (*nextc == '\0')) return(&dot[0]) ;
X         if (*nextc == '.' && (*(nextc+1) == '/' || *(nextc+1) == '\0')) {
X            ++nextc ;
X            return(&dotdot[0]) ;
X         }
X      }
X      d = namep;
X      *namep++ = c;
X      while ((c = *nextc) != '/') {
X         *namep++ = c ;
X         if (c == '\0') {
X            nextc = NULL ;
X            return(d) ;
X         }
X         ++nextc;
X      }
X      *namep++ = '\0' ;
X      return(d) ;
X   } else {
X      return(NULL) ;
X   }
X}
X
X/* cannoname - Put a file name in cannonical form. Looks for all the
X * whacky wonderful things a demented *ni* programmer might put
X * in a file name and reduces the name to cannonical form.
X */
Xvoid
Xcannoname(n)
X   char * n;
X{
X   char *  components[1024] ;
X   char ** cap = &components[0] ;
X   char ** cad ;
X   char *  cp ;
X   char    namebuf[2048] ;
X   char *  s ;
X
X   /* initialize scanner */
X   nextc = n ;
X   namep = &namebuf[0] ;
X
X   /* break the file name into individual components */
X   while ((cp = lexname()) != NULL) {
X      *cap++ = cp ;
X   }
X
X   /* If name is empty, leave it that way */
X   if (cap == &components[0]) return ;
X
X   /* flag end of component list */
X   *cap = NULL ;
X
X   /* remove all trailing slashes and dots */
X   while ((--cap != &components[0]) &&
X          ((*cap == &slash[0]) || (*cap == &dot[0]))) *cap = NULL ;
X
X   /* squeeze out all . / component sequences */
X   cap = &components[0] ;
X   cad = cap ;
X   while (*cap != NULL) {
X      if ((*cap == &dot[0]) && (*(cap+1) == &slash[0])) {
X         cap += 2;
X      } else {
X         *cad++ = *cap++ ;
X      }
X   }
X   *cad++ = NULL ;
X
X   /* find multiple // and use last slash as root, except on apollo which
X    * apparently actually uses // in real file names (don't ask me why).
X    */
X#ifndef apollo
X   s = NULL ;
X   cap = &components[0] ;
X   cad = cap ;
X   while (*cap != NULL) {
X      if ((s == &slash[0]) && (*cap == &slash[0])) {
X         cad = &components[0];
X      }
X      s = *cap++;
X      *cad++ = s;
X   }
X   *cad = NULL ;
X#endif
X
X   /* if this is absolute name get rid of any /.. at beginning */
X   if ((components[0] == &slash[0]) && (components[1] == &dotdot[0])) {
X      cap = &components[1] ;
X      cad = cap ;
X      while (*cap == &dotdot[0]) {
X         ++cap;
X         if (*cap == NULL) break ;
X         if (*cap == &slash[0]) ++cap ;
X      }
X      while (*cap != NULL) {
X         *cad++ = *cap++ ;
X      }
X      *cad = NULL ;
X   }
X
X   /* squeeze out any name/.. sequences (but leave leading ../..) */
X   cap = &components[0] ;
X   cad = cap ;
X   while (*cap != NULL) {
X      if ((*cap == &dotdot[0]) &&
X          ((cad-2) >= &components[0]) &&
X          ((*(cad-2)) != &dotdot[0])) {
X         cad -= 2 ;
X         ++cap;
X         if (*cap != NULL) ++cap;
X      } else {
X         *cad++ = *cap++ ;
X      }
X   }
X   /* squeezing out a trailing /.. can leave unsightly trailing /s */
X   if ((cad >= &components[2]) && ((*(cad-1)) == &slash[0])) --cad ;
X   *cad = NULL ;
X   /* if it was just name/.. it now becomes . */
X   if (components[0] == NULL) {
X      components[0] = &dot[0] ;
X      components[1] = NULL ;
X   }
X
X   /* re-assemble components */
X   cap = &components[0] ;
X   while ((s = *cap++) != NULL) {
X      while (*s != NULL) *n++ = *s++;
X   }
X   *n++ = '\0' ;
X}
END_OF_FILE
if test 4112 -ne `wc -c <'cannoname.c'`; then
    echo shar: \"'cannoname.c'\" unpacked with wrong size!
fi
# end of 'cannoname.c'
fi
if test -f 'iid.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'iid.1'\"
else
echo shar: Extracting \"'iid.1'\" \(5306 characters\)
sed "s/^X//" >'iid.1' <<'END_OF_FILE'
X.TH IID 1
X.SH NAME
Xiid \- interactive query for ID database
X.SH SYNOPSIS
X.PP
X.B iid
X.RB [ \-a]
X.RB [ \-c \^command]
X.RB [ \-H]
X.SH DESCRIPTION
XThis command provides an interactive query interface to the
X.I ID
Xdatabase.
X.I Iid\^
Xallows you to query an
X.I ID
Xdatabase in a fashion similar to using \fIDIALOG\fP. Any individual
Xquery command results in a list of files that satisfy that query,
Xeach set of files is retained by
X.I iid
Xand assigned a set number. The sets may be combined with
X.IR AND ,
X.I OR
Xand
X.I NOT
Xoperators to produce additional sets. The primitive operators that
Xproduce sets are invocations of the
X.I lid
Xor
X.I aid
Xprograms.
X.SH OPTIONS
XNormally
X.I iid
Xruns interactively. Options may be used to run it in batch mode.
X.TP 8
X.B \-a
XUse the
X.I aid
Xprogram as the default query program, normally
X.I lid
Xis used.
X.TP 8
X.B \-c
XAccept a single command as an argument, run that command, and exit
X.IR Iid .
X.TP
X.B \-H
XPrint a brief help message and exit.
X.SH SUBCOMMANDS
XThe subcommands are used to carry on a dialog with
X.I iid
Xafter invoking the program.
X.PP
XTwo basic query commands are available:
X.B SS
Xand
X.BR FILES .
XThe
X.B SS
Xcommand shows the sets generated by a query, but does not display
Xthe actual file names that satisfy the query.
XThe
X.B FILES
Xcommand only displays the list of files, it does not show any
Xof the sets created during the query.
X.PP
XQueries consist of keywords and identifier strings. The keywords are:
X.B and or not lid aid match
Xand
X.B s<number>
Xwhere
X.B s<number>
Xis a set number consisting of the letter
X.B s
Xfollowed (with no space) by a decimal set number.
XA clause of the form
X.B lid <identifier list>
Xinvokes
X.I lid
Xwith the
X.B <identifier list>
Xas arguments and produces a set of files as a result.
XSubstituting
X.B aid
Xfor
X.B lid
Xruns the
X.I aid
Xprogram to generate the list of files.
XAs a shorthand notation for
X.B lid <identifier>
Xyou may simply use
X.B <identifier>.
XThe
X.B match
Xoperator runs the standard system
X.I ls
Xutility to produce a set of files. This allows sets to be
Xconstructed based on the names of files (using wild cards)
Xrather than contents.
XThe
X.B and or
Xand
X.B not
Xoperators can be used to combine sets in the obvious fashion.
XIf you need to pass any of the keywords as actual arguments to
Xprograms, or if the search strings contain any shell escape
Xcharacters place the argument in quotes.
X.PP
XThe
X.B NOT
Xoperator has highest precedence, followed by
X.B AND
Xand
X.B OR
Xin that order. Parenthesis may be used for grouping.
X.PP
XThe remaining commands are:
X.PP
X.B BEGIN <directory>
Xaccepts a directory name and switches to that directory. By changing
Xdirectories you control which
X.I ID
Xdatabase is searched. Changing directories automatically deletes
Xall the sets constructed so far. The
X.B BEGIN
Xcommand may be abbreviated as
X.BR B .
X.PP
X.B SETS
Xshows the description of all the sets created so far. Each set
Xdescription has the set number, the number of files in the set,
Xand a symbolic description of the query that created the set.
X.PP
X.B SHOW <set number>
Xruns a pager program, passing as arguments all the files in
Xthe specified set. The pager program comes from the
X.B $PAGER
Xenvironment variable. This command may be abbreviated
X.BR P .
X.PP
X.B HELP
Xruns the pager on the help file. The commands
X.B H
Xand
X.B ?
Xalso act as help commands.
X.PP
X.B OFF
Xexits the program.
X.B Q
Xis short for
X.BR OFF .
X.PP
XAll commands and keywords are case insensitive, so that
X.B SHOW ShOW
Xand
X.B show
Xall work equally well.
X.SH INTERFACE
XTwo forms of commands are provided for interface with arbitrary
Xprograms. Any command that is not recognized as one
Xof the above built in
X.I iid
Xcommands, is assumed to be a program which, when run, will print
Xa list of file names.
X.I Iid
Xruns the command as typed, and records the output as a new set
Xwhich may be combined with other sets in subsequent queries.
X.PP
XIf the command starts with a
X.BR !,
X.I iid
Xstrips off the leading
X.B !
Xand simply runs the command. Any output goes to stdout and
Xis not recorded as a set.
X.PP
XIn both types of shell commands, any set numbers specified as
Xarguments are expanded into a list of file names before running
Xthe command.
X.SH EXAMPLE
X.nf
X.ft L
X===> iid
Xiid> ss lid "^get" or lid "Arg$"
X   S0     14  lid -kmn "^get"
X   S1      3  lid -kmn "Arg$"
X   S2     15  (lid -kmn "^get") OR (lid -kmn "Arg$")
Xiid> f s1
Xlid.c
Xpaths.c
Xinit.c
Xiid> off
X.FT P
X.fi
X.EX off
X.PP
XIn this example the
X.B ss
Xcommand displays the sets it creates as it
Xdoes the parts of the query. In this case 3 sets are created, set S0
Xhas 14 files in it, set S1 has 3 files and the union of the two sets,
XS2, has 15 files. A description of the query that created any given
Xset is kept along with the set and displayed when sets are printed.
X.PP
XThe
X.B f s1
Xcommand lists the three files in set S1.
X.PP
XThe 
X.B off
Xcommand terminates the example session.
X.SH HINTS
XThe shell interface commands can be used to generate file sets by
Xrunning the
X.I find
Xor
X.I ls
Xutilities, or compiles of a selected group of files can be done
Xusing the
X.BR ! cc
Xcommand with a set number as the argument.
X.BR ! lp
Xcan be used to print a selected group of files.
X.PP
XThis program interfaces nicely with
X.I emacs
Xif you run the server program and specify the client program
Xas your $PAGER.
X.SH SEE ALSO
Xmkid(1),
Xlid(1),
Xaid(1).
END_OF_FILE
if test 5306 -ne `wc -c <'iid.1'`; then
    echo shar: \"'iid.1'\" unpacked with wrong size!
fi
# end of 'iid.1'
fi
if test -f 'iid.help' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'iid.help'\"
else
echo shar: Extracting \"'iid.help'\" \(3455 characters\)
sed "s/^X//" >'iid.help' <<'END_OF_FILE'
XThe iid program is an interactive shell on  top of the  mkid, lid, aid
Xdatabase programs. It allows interactive queries of  an ID database in
Xa fashion similar to a DIALOG session. Iid remembers the sets of files
Xthat were reported by any  lid or aid request.  These sets are refered
Xto by set numbers. The commands available are:
X
XBEGIN <directory>    cd to directory (presumably containing an ID file).
XB                    short for BEGIN
XSS <query>           run query displaying the sets generated
XFILES <query>        run query listing the files in the final set
XF                    short for FILES
XSHOW <set number>    run pager program on files in set
XP                    short for SHOW
XSETS                 show currently defined sets
XHELP                 run pager on this file
X? or H               short commands for HELP
XOFF                  exit iid
X<cmd>                run a shell command as a file name query
X!<cmd>               run a shell command
X
XA <set number> is the letter 's' (or 'S')  followed (with no space) by
Xa number. Set numbers may be used as terms in a query.
X
XA <query> is:
X   <set number>
X   <identifier>
X   lid <identifier list>
X   aid <identifier list>
X   match <wild card list>
X   <query> or <query>
X   <query> and <query>
X
XThe words  "lid", "aid", "match",  "or", and "and" are keywords, along
Xwith any word that looks like a set number. If you  have to use one of
Xthese (or in arguments to lid, aid  or match, shell escape characters)
Xthen quote the name.
X
XThe  "match" operator constructs a set  of  files by running the "pid"
Xprogram with the wild card  pattern as  an argument. This  is the only
Xoperator    which constructs sets   based  on file  names rather  than
Xcontents.
X
XAn identifier by itself is  simply shorthand for "lid identifier". (If
Xthe -a  option was used  to invoke iid,  then  a simple  identifier is
Xshorthand for "aid identifier").
X
XExample run:
X
X===> iid
X===> ss lid "^get" or lid "Arg$"
X   S0     14  lid -kmn "^get"
X   S1      3  lid -kmn "Arg$"
X   S2     15  (lid -kmn "^get") OR (lid -kmn "Arg$")
X===> f s1
Xlid.c
Xpaths.c
Xinit.c
X===> ls *.c
X   S3     28  ls *.c
X===> ls s*
X   S4      9  ls s*
X===> ss s3 and s4
X   S5      4  (ls *.c) AND (ls s*)
X===> !grep vhil s5
Xscan-c.c:				setCArgs("vhil",'+',"v");
Xscan-c.c:			setCArgs("vhil",'+',"v");
X===> off
X
XIn  this example  the 'ss' command  displays  the sets it creats as it
Xdoes the parts of the  query. In this case  3 sets are created, set S0
Xhas 14 files in it, set S1 has 3 files and the  union of the two sets,
XS2, has 15 files.  A description of the  query that created any  given
Xset is kept along with the set and displayed when sets are printed.
X
XThe 'f s1' command says list the files in set S1, and  the three files
Xin the set are displayed.
X
XThe 'ls'  commands are examples of using  arbitrary  shell commands to
Xgenerate lists  of files. In  this case the  'ls' command. (This could
Xhave been done as part of another query using the 'match' operator).
X
XThe '!grep vhil s5' command runs  the 'grep'  shell command passing as
Xarguments 'vhil' and the names of all the files in s5.
X
XThe 'off' command terminated the example session.
X
XKeywords, commands, and set numbers are recognized  regardless of case
X(and is And is aNd). Other parameters are case sensitive.
X
XThe iid program can  also be run in a  batch mode using the -c option.
XFor more information on command line options, run "iid -H", or use the
XUnix 'man' command.
END_OF_FILE
if test 3455 -ne `wc -c <'iid.help'`; then
    echo shar: \"'iid.help'\" unpacked with wrong size!
fi
# end of 'iid.help'
fi
if test -f 'mkid.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mkid.1'\"
else
echo shar: Extracting \"'mkid.1'\" \(5564 characters\)
sed "s/^X//" >'mkid.1' <<'END_OF_FILE'
X.TH MKID 1
X.SH NAME
Xmkid \- make an id database
X.SH SYNOPSIS
X.B mkid
X.RB [ \-v ]
X.RB [ \-f \^out-file]
X.RB [ \-s \^directory]
X.RB [ \-r \^directory]
X.RB [ \-S \^scanarg]
X.RB [ \-a \^arg-file]
X.RB [ \- ]
X.RB [ \-u ]
X.RB [ files... ]
X.SH DESCRIPTION
X.I Mkid\^
Xbuilds a database that stores numbers and identifier names, as well
Xas the names of the files in which they occur.
X.I Mkid\^
Xis particularly useful with large programs spread out across multiple
Xsource files.  It serves as an aid for program maintenance and as a
X.I guide\^
Xfor perusing a program.
X.PP
XThe following options are recognized:
X.TP 10
X.B \-v
XVerbose.
XReport
X.IR mkid 's
Xprogress in building the database.  The output comes on standard error.
X.TP 10
X.BI \-f out-file\^
XWrite the finished database into
X.IR out-file .
X.B ID\^
Xis the default.
XNormally the names of the files scanned are written to the database
Xas specified in the argument list. If the database sepcified with
X.B \-f
Xis not located in the current directory, then the file names are
Xadjusted so that they are relative to the directory that the
Xdatabase is located in.
X.TP 10
X.BI \-s directory\^
X.TP 10
X.BI \-r directory\^
XIf
X.IR mkid 's
Xattempt to open a source-file fails, it will try to checkout the
Xcorresponding SCCS or RCS file if present.  The
X.B \-s
Xoption tells
X.I mkid\^
Xwhich directory holds the SCCS file.
XSimilarly, the
X.B \-r
Xoption tells
X.I mkid\^
Xwhich directory holds the RCS file.
XIf neither the RCS or SCCS directories are specified,
X.I mkid\^
Xwill first look for an SCCS file in the current directory, then in
X.BI sccs ,
Xand finally in
X.BI SCCS .
XIt will then look for an RCS file in the current directory, and finally in
X.BI RCS .
X.TP 10
X.BI \-a arg-file\^
XOpen and read
X.I arg-file\^
Xin order to obtain a list of source file arguments.  Source file names
Xmust appear one to a line.
X.BI \-S ,
X.BI \-r ,
Xand
X.BI \-s
Xarguments may also be placed one per line in
X.IR file .
XThey are distinguished from source file names by their leading `-'.  If a file name begins
Xwith `-', it can be distinguished from an argument by explicitly prepending the current
Xdirectory string: `./'.
X.TP 10
X.B \-
XThis operates in the same manner as the
X.B \-a
Xoption described above, but reads from the standard input instead of a file.
X.TP 10
X.B \-u
XUpdate an existing database.  Only those files that have been modified
Xsince the database was built will be rescanned.  This is a significant
Xtime-saver for updating large databases where few sources have changed.
X.TP 10
X.B files...
XIf neither the
X.BI \-a ,
X.BI \- ,
Xnor
X.BI \-u ,
Xarguments have been specified, take file names from the command line.
X.TP 10
X.BI \-S scanarg\^
X.I Mkid\^
Xscans source files in order to obtain numbers and identifier names.
XSince the lexical rules of languages differ,
X.I mkid\^
Xapplies a different scanning function to each language in order
Xto conform to that language's lexical rules.
X.I Mkid\^
Xdetermines the source file's language by examining its filename
Xsuffix which commonly occurs after a dot (`.').
XThe
X.B \-S
Xargument is a way of passing language specific arguments to the
Xscanner for that language.  This argument takes a number of forms:
X.br
X-S<suffix>=<language>
X.br
X-S<language>-<arg>
X.br
X+S-<arg>
X.br
X-S<lang>/<lang>/<filter>
X.br
XThe first form associates a suffix with a language.
XFor example -S.c=vhil would cause all .c files to be scanned
Xas though they were language vhil rather than c.
XYou may find
Xout which suffixes are defined for which languages with the following
Xoptions: `-S<suffix>=?' tells which language is bound to
X.IR <suffix> ,
X`-S?=<language>' tells which suffixes are bound to 
X.IR <language> ,
Xand `-S?=?' reports all bindings between suffixes and languages.
X.PP
XThe second form passes an argument for processing by the scanner
Xfor a specific language.  The third form passes an argument to
Xall scanners.
X.PP
XFinally, the <lang>/<lang>/<filter> form defines a shell command
Xto filter the file with. This can be used to run an arbitrary
Xprogram to filter the contents of a file before it is passed
Xto one of the existing language scanners. It is typically
Xused in conjunction with the plain text scanner.
XThe first <lang> defines a new language, the second <lang>
Xspecifies an existing language whose scanner will be used,
Xand the remaining <filter> is an arbitrary shell command.
X.PP
XYou may get a brief summary of the scanner-specific options for a
Xlanguage by supplying the following option: `-S<language>?'.
X.PP
XHere is a brief summary of the options for the
X.I `asm'\^
X(assembler) language.
X.PP
XThe
X.B \-u\^
Xoption controls whether or not the assembler scanner should strip
Xoff a leading
X.I underscore\^
X(`_') character.  If your assembler prepends an
X.I underscore\^
Xto external symbols, then you should tell the scanner to strip it
Xoff, so that references to the same symbol from assembly and from
Xa high-level language will look the same.
X.PP
XThe
X.B \-c<cc>\^
Xoption supplies the character(s) used to begin a comment that extends
Xto the end of the line.
X.PP
XThe
X.B \-a<cc>\^
Xoption indicates character(s) that are legal in names, in addition to
Xthe alpha-numeric characters.  If the option appears as `-a', names
Xthat contain these characters are ignored.  If it appears as `+a', these
Xnames are added to the database.
X.SH BUGS
XThis manual page needs to be more complete about the scanner-specific
Xarguments.
X.PP
XAt the moment, the only scanners implemented are for C, assembly
Xlanguage, and plain text.  There ought to be scanners for Ada, Pascal,
XFortran, and Lisp.
X.SH SEE ALSO
Xlid(1), deroff(1), detex(1).
END_OF_FILE
if test 5564 -ne `wc -c <'mkid.1'`; then
    echo shar: \"'mkid.1'\" unpacked with wrong size!
fi
# end of 'mkid.1'
fi
if test -f 'paths.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'paths.c'\"
else
echo shar: Extracting \"'paths.c'\" \(5284 characters\)
sed "s/^X//" >'paths.c' <<'END_OF_FILE'
X/* Copyright (c) 1986, Greg McGary */
Xstatic char sccsid[] = "@(#)paths.c	1.1 86/10/09";
X
X#include	<bool.h>
X#include	<stdio.h>
X#include	<string.h>
X
Xbool canCrunch();
Xchar *rootName();
Xchar *spanPath();
Xchar *suffName();
Xvoid cannoname();
X
X/* relPath takes two arguments:
X * 1) an absolute path name for a directory.
X *    (This name MUST have a trailing /).
X * 2) an absolute path name for a file.
X *
X * It looks for common components at the front of the file and
X * directory names and generates a relative path name for the file
X * (relative to the specified directory).
X *
X * This may result in a huge number of ../s if the names
X * have no components in common.
X *
X * The output from this concatenated with the input directory name
X * and run through spanPath should result in the original input
X * absolute path name of the file.
X *
X * Examples:
X *  dir      arg                  return value
X *  /x/y/z/  /x/y/q/file      ->  ../q/file
X *  /x/y/z/  /q/t/p/file      ->  ../../../q/t/p/file
X *  /x/y/z/  /x/y/z/file      ->  file
X */
Xchar *
XrelPath(dir, arg)
X	char		*dir;
X	char		*arg;
X{
X	char *		a;
X	char *		d;
X	char *		lasta;
X	char *		lastd;
X	static char	pathBuf[BUFSIZ];
X
X	lasta = a = arg;
X	lastd = d = dir;
X	while (*a == *d) {
X	   if (*a == '/') {
X	      lasta = a;
X	      lastd = d;
X	   }
X	   ++a;
X	   ++d;
X	}
X	/* lasta and lastd now point to the last / in each
X	 * file name where the leading file components were
X	 * identical.
X	 */
X	++lasta;
X	++lastd;
X	/* copy a ../ into the buffer for each component of
X	 * the directory that remains.
X	 */
X	d = pathBuf;
X	while (*lastd != '\0') {
X		if (*lastd == '/') {
X			strcpy(d, "../");
X			d += 3;
X		}
X		++lastd;
X	}
X	/* now tack on remainder of arg */
X	strcpy(d, lasta);
X	return(pathBuf);
X}
X
X/* spanPath accepts a directory name and a file name and returns
X * a cannonical form of the full file name within that directory.
X * It gets rid of ./ and things like that.
X *
X * If the file is an absolute name then the directory is ignored.
X */
Xchar *
XspanPath(dir, arg)
X	char		*dir;
X	char		*arg;
X{
X	char *          argptr;
X	static char	pathBuf[BUFSIZ];
X
X	/* reduce directory to cannonical form */
X	strcpy(pathBuf, dir);
X	cannoname(pathBuf);
X	/* tack the obilgatory / on the end */
X	strcat(pathBuf, "/");
X	/* stick file name in buffer after directory */
X	argptr = pathBuf + strlen(pathBuf);
X	strcpy(argptr, arg);
X	/* and reduce it to cannonical form also */
X	cannoname(argptr);
X	/* If it is an absolute name, just return it */
X	if (*argptr == '/') return(argptr);
X	/* otherwise, combine the names to cannonical form */
X	cannoname(pathBuf);
X	return(pathBuf);
X}
X
X/* rootName returns the base name of the file with any leading
X * directory information or trailing suffix stripped off. Examples:
X *
X *   /usr/include/stdio.h   ->   stdio
X *   fred                   ->   fred
X *   barney.c               ->   barney
X *   bill/bob               ->   bob
X *   /                      ->   < null string >
X */
Xchar *
XrootName(path)
X	char		*path;
X{
X	static char	pathBuf[BUFSIZ];
X	char		*root;
X	char		*dot;
X
X	if ((root = strrchr(path, '/')) == NULL)
X		root = path;
X	else
X		root++;
X	
X	if ((dot = strrchr(root, '.')) == NULL)
X		strcpy(pathBuf, root);
X	else {
X		strncpy(pathBuf, root, dot - root);
X		pathBuf[dot - root] = '\0';
X	}
X	return pathBuf;
X}
X
X/* suffName returns the suffix (including the dot) or a null string
X * if there is no suffix. Examples:
X *
X *   /usr/include/stdio.h   ->   .h
X *   fred                   ->   < null string >
X *   barney.c               ->   .c
X *   bill/bob               ->   < null string >
X *   /                      ->   < null string >
X */
Xchar *
XsuffName(path)
X	char		*path;
X{
X	char		*dot;
X
X	if ((dot = strrchr(path, '.')) == NULL)
X		return "";
X	return dot;
X}
X
Xbool
XcanCrunch(path1, path2)
X	char		*path1;
X	char		*path2;
X{
X	char		*slash1;
X	char		*slash2;
X
X	slash1 = strrchr(path1, '/');
X	slash2 = strrchr(path2, '/');
X
X	if (slash1 == NULL && slash2 == NULL)
X		return strequ(suffName(path1), suffName(path2));
X	if ((slash1 - path1) != (slash2 - path2))
X		return FALSE;
X	if (!strnequ(path1, path2, slash1 - path1))
X		return FALSE;
X	return strequ(suffName(slash1), suffName(slash2));
X}
X#include	<sys/types.h>
X#include	<sys/stat.h>
X
X/* LookUp adds ../s to the beginning of a file name until it finds
X * the one that really exists. Returns NULL if it gets all the way
X * to / and never finds it.
X *
X * If the file name starts with /, just return it as is.
X *
X * This routine is used to locate the ID database file.
X */
Xchar *
XLookUp(arg)
X	char *		arg;
X{
X	char *		p;
X	static char	pathBuf[BUFSIZ];
X	struct stat	rootb;
X	struct stat	statb;
X
X	/* if we got absolute name, just use it. */
X	if (arg[0] == '/') return(arg);
X	/* if the name we were give exists, don't bother searching */
X	if (stat(arg, &statb) == 0) return(arg);
X	/* search up the tree until we find a directory where this
X	 * relative file name is visible.
X	 * (or we run out of tree to search by hitting root).
X	 */
X	p = pathBuf;
X	if (stat("/", &rootb) != 0) return(NULL);
X	do {
X		strcpy(p, "../");
X		p += 3;
X		strcpy(p, arg);
X		if (stat(pathBuf, &statb) == 0) return(pathBuf);
X		*p = '\0';
X		if (stat(pathBuf, &statb) != 0) return(NULL);
X	} while (! ((statb.st_ino == rootb.st_ino) ||
X                    (statb.st_dev == rootb.st_dev)));
X	return(NULL);
X}
END_OF_FILE
if test 5284 -ne `wc -c <'paths.c'`; then
    echo shar: \"'paths.c'\" unpacked with wrong size!
fi
# end of 'paths.c'
fi
if test -f 'scan-text.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'scan-text.c'\"
else
echo shar: Extracting \"'scan-text.c'\" \(4062 characters\)
sed "s/^X//" >'scan-text.c' <<'END_OF_FILE'
X/* Copyright (c) 1986, Greg McGary */
X/* Assembler scanner hacked into a Text scanner by Tom Horsley 1988 */
X
X#include	<bool.h>
X#include	<stdio.h>
X#include	<string.h>
X#include	<ctype.h>
X#include	<id.h>
X
Xchar *getTextId();
Xvoid setTextArgs();
X
Xstatic void clrCtype();
Xstatic void setCtype();
X
X#define	I1	0x01	/* 1st char of an identifier [a-zA-Z_] */
X#define	NM	0x02	/* digit [0-9a-fA-FxX] */
X#define SQ	0x04	/* squeeze these out (.,',-) */
X#define	EF	0x80	/* EOF */
X
X/* Text character classes */
X#define	ISID1ST(c)	((rct)[c]&(I1))
X#define	ISIDREST(c)	((rct)[c]&(I1|NM|SQ))
X#define	ISNUMBER(c)	((rct)[c]&(NM))
X#define	ISEOF(c)	((rct)[c]&(EF))
X#define	ISBORING(c)	(!((rct)[c]&(I1|NM|EF)))
X#define ISIDSQUEEZE(c)	((rct)[c]&(SQ))
X
Xstatic char idctype[] = {
X
X	EF,
X
X	/*      0       1       2       3       4       5       6       7   */
X	/*    -----   -----   -----   -----   -----   -----   -----   ----- */
X
X	/*000*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*010*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*020*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*030*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*040*/	0,	0,	0,	0,	0,	0,	0,	SQ,
X	/*050*/	0,	0,	0,	0,	0,	SQ,	SQ,	0,
X	/*060*/	NM,	NM,	NM,	NM,	NM,	NM,	NM,	NM,	
X	/*070*/	NM,	NM,	0,	0,	0,	0,	0,	0,
X	/*100*/	0,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1,
X	/*110*/	I1,	I1,	I1,	I1,	I1|NM,	I1,	I1,	I1,
X	/*120*/	I1,	I1,	I1,	I1,	I1,	I1,	I1,	I1,
X	/*130*/	I1|NM,	I1,	I1,	0,	0,	0,	0,	I1,
X	/*140*/	0,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1,
X	/*150*/	I1,	I1,	I1,	I1,	I1|NM,	I1,	I1,	I1,
X	/*160*/	I1,	I1,	I1,	I1,	I1,	I1,	I1,	I1,
X	/*170*/	I1|NM,	I1,	I1,	0,	0,	0,	0,	0,
X
X	/*200*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*210*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*220*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*230*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*240*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*250*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*260*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*270*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*300*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*310*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*320*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*330*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*340*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*350*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*360*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*370*/	0,	0,	0,	0,	0,	0,	0,	0,
X
X};
X
X/* 
X        Grab the next identifier the text source file opened with the
X	handle `inFILE'.  This state machine is built for speed, not
X	elegance.
X*/
Xchar *
XgetTextId(inFILE, flagP)
X	FILE		*inFILE;
X	int		*flagP;
X{
X	static char	idBuf[BUFSIZ];
X	register char	*rct = &idctype[1];
X	register int	c;
X	register char	*id = idBuf;
X
Xtop:
X	c = getc(inFILE);
X	while (ISBORING(c))
X		c = getc(inFILE);
X	if (ISEOF(c)) {
X		return NULL;
X	}
X	id = idBuf;
X	*id++ = c;
X	if (ISID1ST(c)) {
X		*flagP = IDN_NAME;
X		while (ISIDREST(c = getc(inFILE)))
X			if (! ISIDSQUEEZE(c)) *id++ = c;
X	} else if (ISNUMBER(c)) {
X		*flagP = IDN_NUMBER;
X		while (ISNUMBER(c = getc(inFILE)))
X			*id++ = c;
X	} else {
X		if (isprint(c))
X			fprintf(stderr, "junk: `%c'", c);
X		else
X			fprintf(stderr, "junk: `\\%03o'", c);
X		goto top;
X	}
X
X	*id = '\0';
X	ungetc(c, inFILE);
X	*flagP |= IDN_LITERAL;
X	return idBuf;
X}
X
Xstatic void
XsetCtype(chars, type)
X	char		*chars;
X	int		type;
X{
X	char		*rct = &idctype[1];
X
X	while (*chars)
X		rct[*chars++] |= type;
X}
Xstatic void
XclrCtype(chars, type)
X	char		*chars;
X	int		type;
X{
X	char		*rct = &idctype[1];
X
X	while (*chars)
X		rct[*chars++] &= ~type;
X}
X
Xextern char	*MyName;
Xstatic void
Xusage(lang)
X	char		*lang;
X{
X	fprintf(stderr, "Usage: %s -S%s([(+|-)a<cc>] [(+|-)s<cc>]\n", MyName, lang);
X	exit(1);
X}
Xstatic char *textDocument[] =
X{
X"The Text scanner arguments take the form -Stext<arg>, where",
X"<arg> is one of the following: (<cc> denotes one or more characters)",
X"  (+|-)a<cc> . . Include (or exculde) <cc> in ids.",
X"  (+|-)s<cc> . . Squeeze (or don't squeeze) <cc> out of ids.",
XNULL
X};
Xvoid
XsetTextArgs(lang, op, arg)
X	char		*lang;
X	int		op;
X	char		*arg;
X{
X	if (op == '?') {
X		document(textDocument);
X		return;
X	}
X	switch (*arg++)
X	{
X	case 'a':
X		if (op == '+') {
X			setCtype(arg, I1) ;
X		} else {
X			clrCtype(arg, I1) ;
X		}
X		break;
X	case 's':
X		if (op == '+') {
X			setCtype(arg, SQ) ;
X		} else {
X			clrCtype(arg, SQ) ;
X		}
X		break;
X	default:
X		if (lang)
X			usage(lang);
X		break;
X	}
X}
END_OF_FILE
if test 4062 -ne `wc -c <'scan-text.c'`; then
    echo shar: \"'scan-text.c'\" unpacked with wrong size!
fi
# end of 'scan-text.c'
fi
if test -f 'symfunc.el' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'symfunc.el'\"
else
echo shar: Extracting \"'symfunc.el'\" \(3162 characters\)
sed "s/^X//" >'symfunc.el' <<'END_OF_FILE'
X;; This file provides functions for symbols, that is, things consisting only
X;; of characters matching the regular expression \(\w\|\s_\).  The functions
X;; are similar to those provided for words (e.g., symbol-around-point is
X;; just like word-around-point).
X
X(provide 'symfunc)
X
X(defvar symbol-char-re "\\(\\w\\|\\s_\\)"
X"The regular expression that matches a character belonging to a symbol.")
X
X(defun symbol-around-point ()
X  "return the symbol around the point as a string"
X  (save-excursion
X    (let (beg)
X      (if (not (at-beginning-of-symbol))
X	  (forward-symbol -1))
X      (setq beg (point))
X      (forward-symbol 1)
X      (buffer-substring beg (point))
X    )
X  )
X)
X
X(defun at-beginning-of-symbol ()
X"Return t if point is currently positioned at the beginning of
Xa symbol."
X   (and
X      (looking-at symbol-char-re)
X      (not (looking-back symbol-char-re))
X   )
X)
X
X(defun forward-symbol (arg)
X"Move point forward ARG symbols (backward if ARG is negative).
XNormally returns t.
XIf an edge of the buffer is reached, point is left there
Xand nil is returned.
XIt is faster to call backward-symbol than to call forward-symbol
Xwith a negative argument."
X   (interactive "p")
X   (if (null arg)
X      (setq arg 1)
X   )
X   (if (< arg 0)
X      (backward-symbol (- arg))
X      (progn
X         (while (> arg 0)
X            (condition-case ()
X               (progn
X                  (while (not (looking-at symbol-char-re))
X                     (forward-char 1)
X                  )
X                  (while (looking-at symbol-char-re)
X                     (forward-char 1)
X                  )
X                  t
X               )
X               (error nil)          ;; Return nil if error
X            )
X            (setq arg (1- arg))
X         )
X      )
X   )
X)
X
X(defun backward-symbol (arg)
X"Move backward until encountering the end of a symbol.
XWith argument, do this that many times.
XIn programs, it is faster to call forward-symbol
Xthan to call backward-symbol with a negative arg."
X   (interactive "p")
X   (if (null arg)
X      (setq arg 1)
X   )
X   (if (< arg 0)
X      (forward-symbol (- arg))
X      (progn
X         (while (> arg 0)
X            (condition-case ()
X               (progn
X                  (while (not (looking-back symbol-char-re))
X                     (forward-char -1)
X                  )
X                  (while (looking-back symbol-char-re)
X                     (forward-char -1)
X                  )
X                  t
X               )
X               (error nil)          ;; Return nil if error
X            )
X            (setq arg (1- arg))
X         )
X      )
X   )
X)
X
X;; Additional word-oriented functions.
X
X(defun word-around-point ()
X  "return the word around the point as a string"
X  (save-excursion
X    (let (beg)
X      (if (not (looking-at "\\<"))
X	  (forward-word -1))
X      (setq beg (point))
X      (forward-word 1)
X      (buffer-substring beg (point)))))
X
X;; The looking-back function used to exist in Emacs distribution, but
X;; it disappeared in 18.52.
X
X(defun looking-back (str)
X  "returns t if looking back reg-exp STR before point."
X  (and
X     (save-excursion (re-search-backward str nil t))
X     (= (point) (match-end 0))
X  )
X)
END_OF_FILE
if test 3162 -ne `wc -c <'symfunc.el'`; then
    echo shar: \"'symfunc.el'\" unpacked with wrong size!
fi
# end of 'symfunc.el'
fi
if test -f 'unsymlink.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'unsymlink.c'\"
else
echo shar: Extracting \"'unsymlink.c'\" \(2622 characters\)
sed "s/^X//" >'unsymlink.c' <<'END_OF_FILE'
X#include <string.h>
X#include <sys/param.h>
X#include <sys/stat.h>
X
Xextern void cannoname();
X
X/* unsymlink is a routine that resolves all symbolic links in
X * a file name, transforming a name to the "actual" file name
X * instead of the name in terms of symbolic links.
X *
X * If it can resolve all links and discover an actual file
X * it returns a pointer to its argument string and transforms
X * the argument in place to the actual name.
X *
X * If no such actual file exists, or for some reason the links
X * cannot be resolved, it returns a NULL pointer and leaves the
X * name alone.
X */
Xchar *
Xunsymlink(n)
X   char *    n;
X{
X   char          newname[MAXPATHLEN];
X   char          partname[MAXPATHLEN];
X   char          linkname[MAXPATHLEN];
X   char *        s;
X   char *        d;
X   char *        lastcomp;
X   int           linksize;
X   struct stat   statb;
X
X   /* Just stat the file to automagically do all the symbolic
X    * link verification checks and make sure we have access to
X    * directories, etc.
X    */
X   if (stat(n, &statb) != 0) return(NULL) ;
X   strcpy(newname, n);
X   /* Now loop, lstating each component to see if it is a symbolic
X    * link. For symbolic link components, use readlink() to get
X    * the real name, put the read link name in place of the
X    * last component, and start again.
X    */
X   cannoname(newname) ;
X   s = &newname[0] ;
X   d = &partname[0] ;
X   if (*s == '/') {
X      *d++ = *s++ ;
X   }
X   lastcomp = d ;
X   for ( ; ; ) {
X      if ((*s == '/') || (*s == '\0')) {
X         /* we have a complete component name in partname, check it out */
X         *d = '\0' ;
X         if (lstat(partname, &statb) != 0) return(NULL) ;
X         if ((statb.st_mode & S_IFMT) == S_IFLNK) {
X            /* This much of name is a symbolic link, do a readlink
X             * and tack the bits and pieces together
X             */
X            linksize = readlink(partname, linkname, MAXPATHLEN) ;
X            if (linksize < 0) return(NULL) ;
X            linkname[linksize] = '\0' ;
X            strcpy(lastcomp, linkname) ;
X            lastcomp += linksize ;
X            strcpy(lastcomp, s) ;
X            strcpy(newname, partname) ;
X            cannoname(newname) ;
X            s = &newname[0] ;
X            d = &partname[0] ;
X            if (*s == '/') {
X               *d++ = *s++ ;
X            }
X            lastcomp = d ;
X         } else {
X            /* Not a symlink, just keep scanning to next component */
X            if (*s == '\0') break ;
X            *d++ = *s++ ;
X            lastcomp = d ;
X         }
X      } else {
X         *d++ = *s++ ;
X      }
X   }
X   strcpy(n, newname) ;
X   return(n) ;
X}
END_OF_FILE
if test 2622 -ne `wc -c <'unsymlink.c'`; then
    echo shar: \"'unsymlink.c'\" unpacked with wrong size!
fi
# end of 'unsymlink.c'
fi
echo shar: End of archive 2 \(of 7\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 6 7 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 7 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.