diff options
Diffstat (limited to 'web/spiderweb/src/master/pathopen.web')
-rw-r--r-- | web/spiderweb/src/master/pathopen.web | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/web/spiderweb/src/master/pathopen.web b/web/spiderweb/src/master/pathopen.web new file mode 100644 index 0000000000..6e374eacc5 --- /dev/null +++ b/web/spiderweb/src/master/pathopen.web @@ -0,0 +1,192 @@ +% Copyright 1989 by Norman Ramsey, Odyssey Research Associates +% Not to be sold, but may be used freely for any purpose +% For more information, see file COPYRIGHT in the parent directory + +\def\title{Finding a file on a path} +@*Introduction. +This module is intended to make it easy for applications to open +a file that is not necessarily in the current directory, +but is somewhere on a search path. +The notion is to specify the path ahead of time, so that +calls to |fopen(n,"r")| can be replaced with calls to |pathopen(n)|. +{\em No ASCII conversions are done; everything is in the character set of the +local machine.} + +@ The functions we export are: +\medskip +\noindent{\tabskip=0ptplus1fil +\halign to \hsize{\vrule height 10pt depth3.5pt width0pt + \hfil#\tabskip=2em&\vtop{\hsize=4in + \noindent\ignorespaces#\par} + \tabskip=0ptplus1fil\cr +\omit\hfil\strut{\bf Function name and signature}& +\omit\bf What it does\hfil\cr +\noalign{\smallskip} +|pathreset()|& +Initializes the system to search the empty path. +This initialization is performed statically, so programs needn't call +|pathreset|, but then they may not be serially reusable. +\cr +|pathaddname(char *)|& +Adds the name to the search path (FIFO). +If the first argument is |NULL| or points to the empty string, +|pathaddname| is a no-op. +\cr +|pathaddpath(char *, char)|& +Adds the given path to the search path (FIFO). +The second argument is the character that is used to separate names on +the path, e.g. |pathaddpath(getenv("PATH"),':')|. +If the first argument is |NULL| or points to the empty string, +|pathaddpath| is a no-op. +\cr +|FILE *pathopen(char *)|& +Attempts to open (for read) +the given name, first in the current directory, then, +if the name is not absolute (i.e. on UNIX doesn't begin with |'/'|), +tries to open the name in each directory on the search path. +If some |fopen| succeeds, it returns a pointer to a stream, otherwise it +returns |NULL|. +\cr +}} + +@ We expect to be able to import: +\medskip +\noindent{\tabskip=0ptplus1fil +\halign to \hsize{\vrule height 10pt depth3.5pt width0pt + \hfil#\tabskip=2em&\vtop{\hsize=4in + \noindent\ignorespaces#\par} + \tabskip=0ptplus1fil\cr +\omit\hfil\strut{\bf Function name and signature}& +\omit\bf What it does\hfil\cr +\noalign{\smallskip} +|overflow(char *)|& +The |pathopen| routines will call |overflow| if they run out of space, +e.g.~|overflow("path texts")|. +\cr +}} + +@ Here we set up the search path. +It is a list of directories; if |pathopen| is handed a relative file name, +it will look for it first in the current directory, and then in each +directory on the search path. +We allow up to |maxpaths| directories to be on the path, +and we set aside |pathtextlength| bytes for the names of those directories. +We perform the initialization statically, so we don't {\em have} to call +|pathreset|. + +We use Knuth's technique for storing the names: all the bytes are stored +in |pathtexts|. +Pointers to the directories are stored in |searchpath|; the name of +the |i|th directory is found in $|*(searchpath[i])|\ldots|*(seachpath[i+1])|$, +where we start counting |i| from zero. +|nextpath| contains the number directories already stored, and +|searchpath[nextpath]| points to the first free byte in |pathtexts|. +This is all a little odd for those used to C's null-terminated strings, but +it becomes second nature after a while. +@d maxpaths = 64 +@d pathtextlength = 1024 +@u +@<Included files@>@; + +static int nextpath=0; +static char pathtexts[pathtextlength]; +static char *searchpath[maxpaths]={pathtexts}; +static char *maxpathtexts = pathtexts+pathtextlength; + +void pathreset() +{ + nextpath=0; + searchpath[nextpath]=pathtexts; +} + +@ Here's how we add a name to the path +@u +void pathaddname(name) + char *name; +{ char *t=searchpath[nextpath]; + if (name==NULL) return; + if (nextpath>=maxpaths) overflow ("paths"); + while (*name) { + if (t>=maxpathtexts) overflow("path texts"); + *t++=*name++; + } + @<If path is null, decrement |nextpath| to cancel addition, + and if path is root, make it null@>@; + searchpath[++nextpath]=t; +} + +@ @<If path is null...@>= +if (t==searchpath[nextpath]) nextpath--; +else if (t==searchpath[nextpath]+1 && + *searchpath[nextpath]==directory_separator) /* path is root */ + t--; + +@ Adding a path is slightly more complicated. +@u +void pathaddpath(path,path_separator) + char *path; + char path_separator; +{ + char *t=searchpath[nextpath]; + if (path!=NULL) { + while (*path) { + if (nextpath>=maxpaths) overflow ("paths"); + while(*path!=path_separator && *path!='\0') { + if (t>=maxpathtexts) overflow("path texts"); + *t++=*path++; + } + @<If path is null...@>@; + searchpath[++nextpath]=t; + if (*path) path++; /* skip separator */ + } + } +} + +@ Now we define the function that attempts to open a file, searching +on the path. +We need to know whether a file name is absolute: +@d directory_separator = '/' /* not converted to ASCII */ +@d absolute(n) = (*(n)==directory_separator) +@d maxpathnamelength = 1024 /* longest path name we can create */ +@u +FILE *pathopen(name) + char *name; +{ + FILE *fp; /* the stream we try to get */ + char pathname[maxpathnamelength]; /* used to create pathnames */ + char *s, *t; /* used to copy prefixes */ + int i; /* used to search pathnames */ + + if (absolute(name)) + return fopen(name,"r"); + else { + if ((fp=fopen(name,"r"))!=NULL) return fp; + for (i=0; i<nextpath; i++) { + @<Try to open on path |i|, returning if not |NULL|@>@; + } + } + return NULL; +} + +@ @<Included...@>=#include <stdio.h> + +@ @<Try to open on path |i|...@>= +for(s=pathname,t=searchpath[i]; t<searchpath[i+1];) { + *s++ = *t++; + if (s>pathname+maxpathnamelength) overflow("path name length"); +} +*s++=directory_separator; +if (s>pathname+maxpathnamelength) overflow("path name length"); +t=name; +while(*s++=*t++) + if (s>pathname+maxpathnamelength) overflow("path name length"); +if ((fp=fopen(pathname,"r"))!=NULL) return fp; + + +@ As a final service, we write declarations on file {\tt pathopen.h} +@(pathopen.h@>= +void pathaddname(); +void pathaddpath(); +void pathreset(); +FILE *pathopen(); +@* Index. |