From:	SMTP%"RELAY-INFO-VAX@CRVAX.SRI.COM" 28-JUN-1994 17:43:54.74
To:	EVERHART
CC:	
Subj:	Summary: Full path fro file

From: Court Demas <court+@CMU.EDU>
X-Newsgroups: comp.os.vms,comp.unix.programmer
Subject: Summary: Full path fro file
Date: Tue, 28 Jun 1994 01:52:51 -0400
Organization: Carnegie Mellon, Pittsburgh, PA
Lines: 736
Message-ID: <0i3ven200jcQ1UwGA0@andrew.cmu.edu>
NNTP-Posting-Host: po6.andrew.cmu.edu
To: Info-VAX@CRVAX.SRI.COM
X-Gateway-Source-Info: USENET


I sent out a request to the above two groups for information on how to
obtain the full pathname of a file specified on the command line in
either VMS or Unix (Borland comes through with an easy _fullpath()
function for DOS - yay).  I received a number of good responses for
both OS's - the unix ones were hacked a bit (lots 'o string
manipulation), and the VMS ones used weirdo system calls with $'s in
them (which I have been unable to get working properly,
unfortunately).  There's some other options I haven't checked out yet,
but there's the responses I got.

btw- I haven't edited these very much (kinda busy) - Also, because I
have not yet found a solution I like.  I was just trying to modify
a2ps (ascii text to postscript converter) to print out the full path
on all the platforms it support dos/unix/vms/etc?, and using these
methods will almost double the source code.  Doesn't seem really worth
it to me..

my original posting:

> > I am writing a command line utility which takes a filename as an
> > argument; I want to be able to get the full path name for the
> > specified file.  In Borland C++ (DOS) there is a _fullpath() command
> > which does exactly that, but the closest I've seen on either VMS or
> > Unix is getcwd().  This only gets me the current working directory - I
> > tried just tacking the filename onto the end of it, but if the user
> > specifies a directory along with that filename then it doesn't work.
> > Any ideas?


responses
---------

msteed@TFS.COM (Martin Steed) writes:
> Um, how about
> 
> If the first character is a / then it is a full pathname, so do nothing.
> Else tack the file name onto the end of getcwd()
> 
> ie
> 
> cd /tmp
> 
> file /tmp/MX                    -> MX
> file ../tmp/MX                  -> /tmp/../tmp/MX (ugly but OK)
> file MX                         -> /tmp/MX
> 
> Martin
> --
> Martin N. Steed                                                 <msteed@tfs.com>
> 
> It has been discovered that C++ provides a remarkable facility for concealing
> the trivial details of a program - such as where its bugs are.



msteed@TFS.COM (Martin Steed) writes:
> On Thu Jun 23 16:03:42 1994, Court Demas wrote to Martin Steed saying:
> 
> > 
> > msteed@TFS.COM (Martin Steed) writes:
> > > In article <0i2OdL200jcQ0F4lc0@andrew.cmu.edu> you wrote:
> > > 
> > > Um, how about
> > > 
> > > If the first character is a / then it is a full pathname, so do nothing.
> > > Else tack the file name onto the end of getcwd()
> > 
> > That works in a few more cases, but still isn't general enough.  How
> > bout this:
> > 
> > $ myprog -f ../../foo.bar
> > 
> > This will get tacked onto the end of the cwd, which isn't too bad, but
> > its still not the intended effect.  This also will not work on VMS,
> > unfortunately.  If I can't find anything better than I guess this is
> > what I'm going to have to do.  thanks..
> 
> Well, you could generate the path by
> 
> strcat(pathname, filename);
> 
> then parsing the pathname, and for every ../ remove the .*/ in front of it.
> 
> cd /tmp
> myprog -f ../usr/spool/news/../mail/msteed/../../../lp/file1
> 
> becomes
> 
> /tmp/../usr/spool/news/../mail/system/msteed/../../../lp/file1
>      ** remove ->
> /usr/spool/news/../mail/system/msteed/../../../lp/file1
>                 ** remove ->
> /usr/spool/mail/system/msteed/../../../lp/file1
>                               ** remove ->
> /usr/spool/mail/system/../../lp/file1
>                        ** remove ->
> /usr/spool/mail/../lp/file1
>                 ** remove ->
> /usr/spool/lp/file1
> 
> And do the same for any single '.''s (just drop the './')
> 
> Martin
> -- 
> Martin N. Steed                                                 <msteed@tfs.com>
> 
> The C Programming Language: combines the flexibility of assembly language
> with the power of assembly language.


peter@geochange.er.usgs.gov (Peter N. Schweitzer (703) 648-6533) writes:
> Here is the solution I used for a similar problem:
> 
> ...
>         /*------------------------------------------------------------------*\
>          | If string defines a partial pathname, append it to the cwd.          |
>         \*------------------------------------------------------------------*/
> 
>         if (*string != '/') {
>                 if (getcwd (file_select_path,FILENAME_MAX)) {
>                         s = file_select_path + strlen (file_select_path);
>                         if (*(s-1) != '/') {
>                                 *s++ = '/';
>                                 *s = 0;
>                                 }
>                         }
>                 strcat (file_select_path,string);
>                 }
>         else
>                 strcpy (file_select_path,string);
> ...
> 
> --
> Peter N. Schweitzer (MS 955, U.S. Geological Survey, Reston, VA 22092)
> Tel: (703) 648-6533  Email: peter@limulus.er.usgs.gov
> <A HREF="http://geochange.er.usgs.gov/peter/peter.html">Peter Schweitzer</A>
> Opinions are my own and not those of my employer etc. ...


Arne Vajhoej <ARNE@kopc.hhs.dk> writes:
> > I am writing a command line utility which takes a filename as an
> > argument; I want to be able to get the full path name for the
> > specified file.  In Borland C++ (DOS) there is a _fullpath() command
> > which does exactly that, but the closest I've seen on either VMS or
> > Unix is getcwd().  This only gets me the current working directory - I
> > tried just tacking the filename onto the end of it, but if the user
> > specifies a directory along with that filename then it doesn't work.
> > Any ideas?
> 
> LIB$FIND_FILE will return both full filename and perform wildcard
> expansion (not quite the same way as UNIX/DOS, but...).
> 
> To get an example try anonymous FTP to KOPC.HHS.DK and look
> in directory MISC where I have 2 small C examples of using
> LIB$FIND_FILE !
> 
>                                                           Arne
> 
> Arne Vajhxj                             local DECNET:  KO::ARNE
> Computer Department                     PSI:           PSI%238310013040::ARNE
> Business School of Southern Denmark     Internet:      ARNE@KO.HHS.DK


mathezer@cpsc.ucalgary.ca (Stephen Mathezer) writes:
>    From: Court Demas <court+@CMU.EDU>
> 
> I have no idea where I got this from, but....
> 
> there is a program called realpath, here is the source and man page.
> 
> -Steve
> -------------------------realpath.c-------------------------
> #include <stdio.h>
> #include <sys/types.h>
> #include <sys/stat.h>
> #include <sys/param.h>
> #include <strings.h>
> 
> char *
> realpath(pathname, result)
> char    *pathname, *result;
> 
> {
> struct  stat    sbuf;
> char    curpath[MAXPATHLEN],
>         workpath[MAXPATHLEN],
>         linkpath[MAXPATHLEN],
>         namebuf[MAXPATHLEN],
>         *where,
>         *ptr,
>         *last;
> int     len;
> 
>    strcpy(curpath, pathname);
> 
>    if (*pathname != '/') {
>       if (!getwd(workpath)) {
>          strcpy(result, ".");
>          return(NULL);
>       }
>    } else *workpath = NULL;
> 
>    /* curpath is the path we're still resolving      */
>    /* linkpath is the path a symbolic link points to */
>    /* workpath is the path we've resolved            */
> 
> loop:
>    where = curpath;
>    while (*where != NULL) {
>       if (!strcmp(where, ".")) {
>          where++;
>          continue;
>       }
> 
>       /* deal with "./" */
>       if (!strncmp(where, "./", 2)) {
>          where += 2;
>          continue;
>       }
> 
>       /* deal with "../" */
>       if (!strncmp(where, "../", 3)) {
>          where += 3;
>          ptr = last = workpath;
>          while (*ptr) {
>             if (*ptr == '/') last = ptr;
>             ptr++;
>          }
>          *last = NULL;
>          continue;
>       }
> 
>       ptr = strchr(where, '/');
>       if (!ptr)
>          ptr = where + strlen(where) - 1;
>       else
>          *ptr = NULL;
> 
>       strcpy(namebuf, workpath);
>       for (last = namebuf; *last; last++) continue;
>       if (*--last != '/') strcat(namebuf, "/");
>       strcat(namebuf, where);
> 
>       where = ++ptr;
>       if (lstat(namebuf, &sbuf) == -1) {
>          strcpy(result, namebuf);
>          return(NULL);
>       }
> 
>       if ((sbuf.st_mode & S_IFLNK) == S_IFLNK) {
>          len = readlink(namebuf, linkpath, MAXPATHLEN);
>          if (len == 0) {
>             strcpy(result, namebuf);
>             return(NULL);
>          }
>          *(linkpath + len) = NULL; /* readlink doesn't null-terminate result */
>          if (*linkpath == '/') *workpath = NULL;
>          if (*where) {
>             strcat(linkpath, "/");
>             strcat(linkpath, where);
>          }
>          strcpy(curpath, linkpath);
>          goto loop;
>       }
> 
>       if ((sbuf.st_mode & S_IFDIR) == S_IFDIR) {
>          strcpy(workpath, namebuf);
>          continue;
>       }
> 
>       if (*where) {
>          strcpy(result, namebuf);
>          return(NULL);  /* path/notadir/morepath */
>       } else
>          strcpy(workpath, namebuf);
>    }
>    strcpy(result, workpath);
>    return(result);
> 
> }
> ------------------------------------------------------------------------
> 
> ------------------------------------realpath.3--------------------------
> 
> 
> 
> REALPATH(3)            C LIBRARY FUNCTIONS            REALPATH(3)
> 
> 
> 
> NAME
>      realpath - returns the canonicalized absolute pathname.
> 
> SYNOPSIS
>      #include <sys/param.h>
> 
>      char *realpath(file_name, resolved_name)
>      char *file_name;
>      char resolved_name[MAXPATHLEN];
> 
> DESCRIPTION
>      realpath() expands all symbolic links  and  resolves  refer-
>      ences  to '/./', '/../' and extra '/' characters in the null
>      terminated string named by file_name and stores the  canoni-
>      calized   absolute   pathname   in   the   buffer  named  by
>      resolved_name.  The resulting path  will  have  no  symbolic
>      links components, nor any '/./' or '/../' components.
> 
> RETURN VALUE
>      If  there  is  no  error,  it  returns  a  pointer  to   the
>      resolved_name.
> 
>      Otherwise  it  returns  a  NULL  pointer   and   places   in
>      resolved_name  the  absolute  pathname of the file_name com-
>      ponent which could not  be  resolved.  The  global  variable
>      errno is set to indicate the error. If any of the parameters
>      are NULL, errno will be set to EINVAL. realpath() indirectly
>      invokes  the  readlink(2)  system  call and getwd(3) library
>      call (for relative path names), and errno  will  be  set  by
>      them.
> 
> SEE ALSO
>      readlink(2), getwd(3)
> 
> WARNINGS
>      It  indirectly  invokes  the  readlink(2)  system  call  and
>      getwd(3)  library  call (for relative path names), and hence
>      inherits the possibility of hanging due to inaccessible file
>      system resources.
> ------------------------------------------------------------------------


ratner@FICUS.CS.UCLA.EDU (Dave Ratner) writes:
> In comp.unix.programmer you write:
> 
> 
> >I am writing a command line utility which takes a filename as an
> >argument; I want to be able to get the full path name for the
> >specified file.  In Borland C++ (DOS) there is a _fullpath() command
> >which does exactly that, but the closest I've seen on either VMS or
> >Unix is getcwd().  This only gets me the current working directory - I
> >tried just tacking the filename onto the end of it, but if the user
> >specifies a directory along with that filename then it doesn't work.
> >Any ideas?
> 
> >Please send email replies and I will post a summary if there's enough
> >interest.
> 
> Use the library routine realpath().  See the man page.
> 
> Dave
> -- 
>                         * *  ***  *     *            Dave Ratner
>   please send   |       * *  *    *    * *   |    ratner@cs.ucla.edu
>  money or beer  |       * *  *    *    ***   |
>                         ***  ***  ***  * *     "Wham Bam, thank you Van Damme"  

note:  I couldn't find the realpath() function in manpages under HPUX
9.0, Linux 1.1, Ultrix, or BSD/Mach.

"Jae W. Chang" <jae+@CMU.EDU> writes:
> I don't understand why that doesn't work. As long as you getcwd and
> tack on whatever the user gives you including the directory, you
> should have the full path to the file.
> 
> First check to see if the first char the user gives is a '/'. If so,
> then you're done - unless you also want to provide support for groking
> shell variables embedded in path names.
> 
> Getcwd, tack on a '/', then strcat what the user gives, and you're
> done.
> 
> Jae
> 
> --------------------------
> jae+@cmu.edu 


Carl J Lydick <carl@SOL1.GPS.CALTECH.EDU> writes:
> Probably the easiest way to do it is to call the RMS routine SYS$PARSE:
> 
> main(int nargs, char **args)
> {       char *myfullpath();
>         if(nargs != 2)
>         {       puts("Usage:  test filename");
>                 SYS$EXIT(1);
>         }
>         else puts(myfullpath(*++args));
> }
> 
> #include rms
> 
> char *myfullpath(char *str)
> {       struct NAM my_nam;
>         struct FAB my_fab;
>         static char esbuf[256];
>         
>         my_nam = cc$rms_nam;
>         my_nam.nam$l_esa = esbuf;
>         my_nam.nam$b_ess = 255;
>         my_fab = cc$rms_fab;
>         my_fab.fab$l_fna = str;
>         my_fab.fab$b_fns = strlen(str);
>         my_fab.fab$l_nam = &my_nam;
>         if((SYS$PARSE(&my_fab) & 7) == 1)
>                 esbuf[my_nam.nam$b_esl] = '\0';
>         else
>                 esbuf[0] = '\0';
>         return esbuf;
> }
> --------------------------------------------------------------------------------
> Carl J Lydick | INTERnet: CARL@SOL1.GPS.CALTECH.EDU | NSI/HEPnet: SOL1::CARL
> 

aldo@honeybun.Corp.Sun.COM (Aldo Castillo) writes:
> In Solaris use basename(1) and its cousin dirname.
> 
> 
>                         |
>  Aldo D. Castillo       |
>                         |  .signature under construction
>                         |       thank you for your cooperation
>                         |

"Jae W. Chang" <jae+@CMU.EDU> writes:
> Court Demas <court+@CMU.EDU> writes:
> > what if the user does:
> > 
> > $ myprog -f../../foo.txt
> > 
> > doesn't give the correct result
> 
> /blah/blah/../../foo.txt is still a full path name.
> 
> Sure there are other special cases to be handled. Shell vars, .., .,
> links, etc. They can all be handled w/ a little effort - one of the
> worst being handling something like /blah/blah/link/../../file where
> link is a *link*. I mean as a last resort you could do a system or
> popen call, whatever, and let the shell of your choice handle all the
> file name expansions for you.
> 
> Jae
> 
> --------------------------
> jae+@cmu.edu 


boubaker@cenatls.cena.dgac.fr (Heddy BOUBAKER) writes:
> 
>    I've written an utilities library for Unix which contain a function which
>    can do what you need. I can send you the whole library (which is a very
>    nice and usefull one - ad - ) or just the function you need, just send me
>    mail ...


msteed@TFS.COM (Martin Steed) writes:
> On Thu Jun 23 16:56:12 1994, Court Demas wrote to Martin Steed saying:
> 
> > Yah, cool idea..  Think I'll try it out.  I'm just hoping it doesn't
> > get confused with links and stuff - like when you go into a directory
> > and then .. out, and you're someplace different?  That probrably a
> > shellism I guess..
> 
> Links may or may not be a problem. On my system
> 
> cd
> mkdir /tmp/martin
> ln -s /tmp/martin .
> 
> cd /tmp/martin
> pwd
> /tmp/martin
> cd ..
> pwd
> /tmp
> 
> cd
> cd martin
> pwd
> /users/msteed/martin
> cd ..
> pwd
> /users/msteed
> 
> Anyway, good luck to you!!
> 
> Martin
> 
> -- 
> Martin N. Steed                                                 <msteed@tfs.com>
> 
> Todays translation is:
> 
> Outer Mongolian: Bi tsokh khairulj bain
> English:         I am herding beetles


Phil <phil@savvy.com> writes:
> Court,
> 
> If you are still looking for a solution, I would suggest the following 
> approach (I have used it in variations before):
> 
>         Use argv[0] to determine the method your program was 
> called.  ie. "/usr/local/bin/your_prog"  or "bin/your_prog". 
> 
>         If argv[0][0] == '/' then you know the program was called 
> relative to the root directory (and hence, this is your programs full 
> directory name).  ie. if argv[0][0] == '/' then the user invoked the 
> program as "/usr/local/bin/your_prog".
> 
>         else the program was called relative to the current directory, so, use
> getcwd() to determine what that directory is.  Then concatenate argv[0] to
> cwd_string which will yield you the full path.  ie. 
> 
>         strcpy(buffer, cwd_string);
>         strcat(buffer, "/\0");  /* cheezy way of adding one char! */
>         strcat(buffer, argv[0]);
> 
> and now you have buffer containing a full directory path.  This will work 
> whether argv[0] is a file or a directory (which I believe was your problem).
> 
>         Not too elegant, but I believe this approach will work w/o much 
> fuss on your part.  
>         
> Phil
> phil@savvy.com
> 
> In article <0i2OdL200jcQ0F4lc0@andrew.cmu.edu> you wrote:
> 
> : I am writing a command line utility which takes a filename as an
> : argument; I want to be able to get the full path name for the
> : specified file.  In Borland C++ (DOS) there is a _fullpath() command
> : which does exactly that, but the closest I've seen on either VMS or
> : Unix is getcwd().  This only gets me the current working directory - I
> : tried just tacking the filename onto the end of it, but if the user
> : specifies a directory along with that filename then it doesn't work.
> : Any ideas?
> 
> : Please send email replies and I will post a summary if there's enough
> : interest.
> 
> : thanks,
> : court


alexm@vlsi19.gsfc.nasa.gov (Alex Measday) writes:
> Hi!  I have a package you might be interested in.  The package contains
> two functions, FPARSE() and FSEARCH().  FPARSE() is used to take apart
> and reassemble UNIX path names.  FSEARCH() is used to scan the list of
> files in a directory.  Documentation for the two is appended to this
> message.
> 
> The source code for this package is available via anonymous ftp from:
> 
>        tpocc.gsfc.nasa.gov  (192.225.69.29)  in /pub/alex/libfsearch.tar
> 
> The code works under SunOS and VxWorks.  It also used to work under HP/UX;
> I've ANSI-fied the code since then and haven't had access to an HP machine
> on which to try building it.
> 
> I noticed that you also posted your request to COMP.OS.VMS.  I have VMS
> versions of FPARSE() and FSEARCH() available if you're interested  They
> use the same calling interface, but they handle VMS file specifications
> instead of UNIX pathnames.
> 
> If you have any questions, let me know - good luck!
> 
>                                 Alex Measday
>                                 Integral Systems, Inc.
>                                 Code 521 - Microelectronic Systems Branch
>                                 NASA Goddard Space Flight Center
>                                 alexm@vlsi19.gsfc.nasa.gov
> 
> ********************************************************************************
> 
>     The following functions are available for manipulating file names and
>     for scanning directories:
> 
>         FPARSE() - parses and constructs file names.
>         FSEARCH() - performs a wildcard scan of a directory of files.
> 
>     FPARSE() and FSEARCH(), by the way, get their names from and are patterned
>     after the VAX/VMS DCL lexical functions, F$PARSE and F$SEARCH.
> 
> ********************************************************************************
> 
>     File Name Parsing (FPARSE)
>     --------------------------
> 
>     FPARSE() parses UNIX pathnames.  Given a file specification, FPARSE()
>     will expand the file specification, translating environment variable
>     references and filling in defaults for missing fields.  The fully-
>     expanded file specification, or parts of it if requested, is returned
>     to the calling routine.
> 
>     File specifications have the following structure:
> 
>             node:/directory(s)/file.extension.version
> 
>     Any field is optional.  NODE is a host name; DIRECTORY is one or more
>     names separated by "/"s; FILE follows the last "/" in the pathname.
>     VERSION is a 3-digit number (e.g., "002") and EXTENSION follows the
>     last dot before the VERSION dot.
> 
>     Parsing utilizes one or more file specifications, processed from left to
>     right in the calling sequence.  First, the leftmost file specification
>     is examined and any references to environment variables are translated.
>     The next file specification is then examined.  Environment variables are
>     translated and fields missing in the first file specification are supplied
>     from the new file specification.  Subsequent file specifications are
>     examined, in turn, and "applied" to the results of the processing of the
>     previous file specifications.  Finally, system defaults (e.g., the user's
>     home directory) are supplied for missing fields that remain.
> 
>     Is that clear?  I used to have a diagram that showed the file names
>     stacked up, one on top of another:
> 
>                           ... System Defaults ...
>                                File_Spec_#N    |
>                                     ...        |
>                                File_Spec_#2    |
>                                File_Spec_#1    V
>                               --------------
>                                   Result
> 
>     File name components would drop down through holes in lower-level
>     specifications to fill in missing fields in the result.
> 
>     Still not clear?  Here's a practical, but hypothetical, example.  Suppose
>     the MEDS software boots from a configuration file, "test.cfg", which is
>     found in a directory whose pathname is stored in environment variable,
>     "$BOOT_DIRECTORY".  Furthermore, the MEDS software needs to derive the
>     segment directory configuration file's name from the boot file's name
>     by replacing the ".cfg" extension with a ".sdr" extension.  The following
>     sequence of FPARSE() calls does the needed file name manipulation:
> 
>         #include  "fparse.h"            -- Filename parsing definitions.
>         char  *boot_file, *segment_file ;
>         ...
>         boot_file = fparse ("test.cfg", "$BOOT_DIRECTORY", NULL, NULL) ;
>         ... load the boot file ...
>         segment_file = fparse (".sdr", boot_file, NULL, NULL) ;
>         ... load the segment directory file ...
> 
>     If "BOOT_DIRECTORY" is defined as "/fast/meds/boot/" (note the trailing
>     "/"), then the result of the first call to FPARSE() will be
> 
>                          /fast/meds/boot/test.cfg
> 
>     The second call to FPARSE() will return
> 
>                         /fast/meds/boot/test.sdr
> 
>     Note that you must use or duplicate the file name returned by FPARSE()
>     before calling FPARSE() again.
> 
>     The examples below (from the source code prolog) show some of the other
>     capabilities of FPARSE().
> 
>         CONSTRUCTING FILE SPECIFICATIONS:
> 
>             fparse (NULL, NULL)
>                 =>  "/usr/me"  (my current working directory)
>             fparse (".lis", "prog.c", NULL, NULL)
>                 =>  "/usr/me/prog.lis"
>             fparse (".o", "tools/dump.c", "/usr/you/", NULL, NULL)
>                 =>  "/usr/you/tools/dump.o"
> 
>         DISSECTING FILE SPECIFICATIONS:
> 
>             fparse ("host:/usr/who/myprog.c.001", NULL, "ALL")
>                 =>  "host:/usr/who/myprog.c.001"
>             fparse ("host:/usr/who/myprog.c.001", NULL, "DIRECTORY")
>                 =>  "/usr/who"
>             fparse ("host:/usr/who/myprog.c.001", NULL, "FILENAME")
>                 =>  "myprog"
>             fparse ("host:/usr/who/myprog.c.001", NULL, "EXTENSION")
>                 =>  ".c"
>             fparse ("host:/usr/who/myprog.c.001", NULL, "VERSION")
>                 =>  ".001"
>             fparse ("host:/usr/who/myprog.c.001", NULL, "FILEXTVER")
>                 =>  "myprog.c.001"
>             fparse ("host:/usr/who/myprog.c.001", NULL, "NODE")
>                 =>  "host:"
> 
> ********************************************************************************
> 
>     Searching Wildcard File Specifications (FSEARCH)
>     ------------------------------------------------
> 
>     FSEARCH() processes UNIX wildcard file specifications; repeated calls
>     to FSEARCH() return each file name that matches the specified wildcard
>     file name.  FSEARCH() supports most, if not all, of the standard shell
>     wildcards.  Matched files are returned fully-expanded (see FPARSE()
>     above) and in alphabetic order.
> 
>     To illustrate, if your current directory contains the following files:
> 
>         input.c  input.dat  main.c  output.c  output.dat
> 
>     the following code could be used to process each C file in turn:
> 
>         #include  "fsearch.h"           -- Wildcard file search definitions.
>         char  *file_name ;
>         ...
>         while ((file_name = fsearch ("*.c", NULL, NULL)) != NULL) {
>             ... process FILE_NAME ...
>         }
> 
>     The last argument to FSEARCH() is the search context.  In the example
>     above, NULL specified the default search context.  If your program
>     must perform simultaneous searches on different wildcard pathnames,
>     you can specify a different search context for each search path.  The
>     following example steps through the ".c" and ".o" files in the current
>     directory (for no particularly good reason):
> 
>         #include  "fsearch.h"           -- Directory scanning definitions.
>         char  *object_name, *source_name ;
>         void  *object_context, *source_context ;
>         ...
>         source_context = NULL ;
>         object_context = NULL ;
>         for ( ; ; ) {
>             source_name = fsearch ("*.c", NULL, &source_context) ;
>             if (source_name == NULL)  break ;
>             object_name = fsearch ("*.o", NULL, &object_context) ;
>             if (object_name == NULL)  break ;
>             ... do something with SOURCE_NAME and OBJECT_NAME ...
>         }
> 
>     FSEARCH() works under UNIX and, for NFS-mounted file systems only,
>     under VxWorks.  A VMS version is also available if you find the need.
> 
> ********************************************************************************

