home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / less-321-src.tgz / tar.out / fsf / less / filename.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  16KB  |  834 lines

  1. /*
  2.  * Copyright (c) 1984,1985,1989,1994,1995,1996  Mark Nudelman
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice in the documentation and/or other materials provided with 
  12.  *    the distribution.
  13.  *
  14.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
  15.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  17.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
  18.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  19.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
  20.  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
  21.  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
  22.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
  23.  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 
  24.  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25.  */
  26.  
  27.  
  28. /*
  29.  * Routines to mess around with filenames (and files).
  30.  * Much of this is very OS dependent.
  31.  */
  32.  
  33. #include "less.h"
  34. #if MSDOS_COMPILER
  35. #include <dos.h>
  36. #if MSDOS_COMPILER==WIN32C
  37. #include <dir.h>
  38. #endif
  39. #endif
  40. #ifdef _OSK
  41. #include <rbf.h>
  42. #ifndef _OSK_MWC32
  43. #include <modes.h>
  44. #endif
  45. #endif
  46.  
  47. extern int force_open;
  48. extern int secure;
  49. extern IFILE curr_ifile;
  50. extern IFILE old_ifile;
  51.  
  52. /*
  53.  * Return a pathname that points to a specified file in a specified directory.
  54.  * Return NULL if the file does not exist in the directory.
  55.  */
  56.     static char *
  57. dirfile(dirname, filename)
  58.     char *dirname;
  59.     char *filename;
  60. {
  61.     char *pathname;
  62.     int f;
  63.  
  64.     if (dirname == NULL || *dirname == '\0')
  65.         return (NULL);
  66.     /*
  67.      * Construct the full pathname.
  68.      */
  69.     pathname = (char *) calloc(strlen(dirname) + strlen(filename) + 2, 
  70.                     sizeof(char));
  71.     if (pathname == NULL)
  72.         return (NULL);
  73.     sprintf(pathname, "%s%s%s", dirname, PATHNAME_SEP, filename);
  74.     /*
  75.      * Make sure the file exists.
  76.      */
  77.     f = open(pathname, OPEN_READ);
  78.     if (f < 0)
  79.     {
  80.         free(pathname);
  81.         pathname = NULL;
  82.     } else
  83.     {
  84.         close(f);
  85.     }
  86.     return (pathname);
  87. }
  88.  
  89. /*
  90.  * Return the full pathname of the given file in the "home directory".
  91.  */
  92.     public char *
  93. homefile(filename)
  94.     char *filename;
  95. {
  96.     register char *pathname;
  97.  
  98.     /*
  99.      * Try $HOME/filename.
  100.      */
  101.     pathname = dirfile(lgetenv("HOME"), filename);
  102.     if (pathname != NULL)
  103.         return (pathname);
  104. #if OS2
  105.     /*
  106.      * Try $INIT/filename.
  107.      */
  108.     pathname = dirfile(lgetenv("INIT"), filename);
  109.     if (pathname != NULL)
  110.         return (pathname);
  111. #endif
  112. #if MSDOS_COMPILER || OS2
  113.     /*
  114.      * Look for the file anywhere on search path.
  115.      */
  116.     pathname = (char *) calloc(_MAX_PATH, sizeof(char));
  117.     _searchenv(filename, "PATH", pathname);
  118.     if (*pathname != '\0')
  119.         return (pathname);
  120.     free(pathname);
  121. #endif
  122.     return (NULL);
  123. }
  124.  
  125. /*
  126.  * Expand a string, substituting any "%" with the current filename,
  127.  * and any "#" with the previous filename.
  128.  * But a string of N "%"s is just replaced with N-1 "%"s.
  129.  * Likewise for a string of N "#"s.
  130.  * {{ This is a lot of work just to support % and #. }}
  131.  */
  132.     public char *
  133. fexpand(s)
  134.     char *s;
  135. {
  136.     register char *fr, *to;
  137.     register int n;
  138.     register char *e;
  139.     IFILE ifile;
  140.  
  141. #define    fchar_ifile(c) \
  142.     ((c) == '%' ? curr_ifile : \
  143.      (c) == '#' ? old_ifile : NULL_IFILE)
  144.  
  145.     /*
  146.      * Make one pass to see how big a buffer we 
  147.      * need to allocate for the expanded string.
  148.      */
  149.     n = 0;
  150.     for (fr = s;  *fr != '\0';  fr++)
  151.     {
  152.         switch (*fr)
  153.         {
  154.         case '%':
  155.         case '#':
  156.             if (fr > s && fr[-1] == *fr)
  157.             {
  158.                 /*
  159.                  * Second (or later) char in a string
  160.                  * of identical chars.  Treat as normal.
  161.                  */
  162.                 n++;
  163.             } else if (fr[1] != *fr)
  164.             {
  165.                 /*
  166.                  * Single char (not repeated).  Treat specially.
  167.                  */
  168.                 ifile = fchar_ifile(*fr);
  169.                 if (ifile == NULL_IFILE)
  170.                     return (save(s));
  171.                 n += strlen(get_filename(ifile));
  172.             }
  173.             /*
  174.              * Else it is the first char in a string of
  175.              * identical chars.  Just discard it.
  176.              */
  177.             break;
  178.         default:
  179.             n++;
  180.             break;
  181.         }
  182.     }
  183.  
  184.     e = (char *) ecalloc(n+1, sizeof(char));
  185.  
  186.     /*
  187.      * Now copy the string, expanding any "%" or "#".
  188.      */
  189.     to = e;
  190.     for (fr = s;  *fr != '\0';  fr++)
  191.     {
  192.         switch (*fr)
  193.         {
  194.         case '%':
  195.         case '#':
  196.             if (fr > s && fr[-1] == *fr)
  197.             {
  198.                 *to++ = *fr;
  199.             } else if (fr[1] != *fr)
  200.             {
  201.                 ifile = fchar_ifile(*fr);
  202.                 strcpy(to, get_filename(ifile));
  203.                 to += strlen(to);
  204.             }
  205.             break;
  206.         default:
  207.             *to++ = *fr;
  208.             break;
  209.         }
  210.     }
  211.     *to = '\0';
  212.     return (e);
  213. }
  214.  
  215. #if TAB_COMPLETE_FILENAME
  216.  
  217. /*
  218.  * Return a blank-separated list of filenames which "complete"
  219.  * the given string.
  220.  */
  221.     public char *
  222. fcomplete(s)
  223.     char *s;
  224. {
  225.     char *fpat;
  226.  
  227.     if (secure)
  228.         return (NULL);
  229.     /*
  230.      * Complete the filename "s" by globbing "s*".
  231.      */
  232. #if MSDOS_COMPILER
  233.     /*
  234.      * But in DOS, we have to glob "s*.*".
  235.      * But if the final component of the filename already has
  236.      * a dot in it, just do "s*".  
  237.      * (Thus, "FILE" is globbed as "FILE*.*", 
  238.      *  but "FILE.A" is globbed as "FILE.A*").
  239.      */
  240.     {
  241.         char *slash;
  242.         for (slash = s+strlen(s)-1;  slash > s;  slash--)
  243.             if (*slash = *PATHNAME_SEP || *slash == '/')
  244.                 break;
  245.         fpat = (char *) ecalloc(strlen(s)+4, sizeof(char));
  246.         if (strchr(slash, '.') == NULL)
  247.             sprintf(fpat, "%s*.*", s);
  248.         else
  249.             sprintf(fpat, "%s*", s);
  250.     }
  251. #else
  252.     fpat = (char *) ecalloc(strlen(s)+2, sizeof(char));
  253.     sprintf(fpat, "%s*", s);
  254. #endif
  255.     s = lglob(fpat);
  256.     if (strcmp(s,fpat) == 0)
  257.     {
  258.         /*
  259.          * The filename didn't expand.
  260.          */
  261.         free(s);
  262.         s = NULL;
  263.     }
  264.     free(fpat);
  265.     return (s);
  266. }
  267. #endif
  268.  
  269. /*
  270.  * Try to determine if a file is "binary".
  271.  * This is just a guess, and we need not try too hard to make it accurate.
  272.  */
  273.     public int
  274. bin_file(f)
  275.     int f;
  276. {
  277.     int i;
  278.     int n;
  279.     unsigned char data[64];
  280.  
  281.     if (!seekable(f))
  282.         return (0);
  283.     if (lseek(f, (off_t)0, 0) == BAD_LSEEK)
  284.         return (0);
  285.     n = read(f, data, sizeof(data));
  286.     for (i = 0;  i < n;  i++)
  287.         if (binary_char(data[i]))
  288.             return (1);
  289.     return (0);
  290. }
  291.  
  292. /*
  293.  * Try to determine the size of a file by seeking to the end.
  294.  */
  295.     static POSITION
  296. seek_filesize(f)
  297.     int f;
  298. {
  299.     off_t spos;
  300.  
  301.     spos = lseek(f, (off_t)0, 2);
  302.     if (spos == BAD_LSEEK)
  303.         return (NULL_POSITION);
  304.     return ((POSITION) spos);
  305. }
  306.  
  307. #if GLOB
  308.  
  309. FILE *popen();
  310.  
  311. /*
  312.  * Read a string from a file.
  313.  * Return a pointer to the string in memory.
  314.  */
  315.     static char *
  316. readfd(fd)
  317.     FILE *fd;
  318. {
  319.     int len;
  320.     int ch;
  321.     char *buf;
  322.     char *p;
  323.     
  324.     /* 
  325.      * Make a guess about how many chars in the string
  326.      * and allocate a buffer to hold it.
  327.      */
  328.     len = 100;
  329.     buf = (char *) ecalloc(len, sizeof(char));
  330.     for (p = buf;  ;  p++)
  331.     {
  332.         if ((ch = getc(fd)) == '\n' || ch == EOF)
  333.             break;
  334.         if (p - buf >= len-1)
  335.         {
  336.             /*
  337.              * The string is too big to fit in the buffer we have.
  338.              * Allocate a new buffer, twice as big.
  339.              */
  340.             len *= 2;
  341.             *p = '\0';
  342.             p = (char *) ecalloc(len, sizeof(char));
  343.             strcpy(p, buf);
  344.             free(buf);
  345.             buf = p;
  346.             p = buf + strlen(buf);
  347.         }
  348.         *p = ch;
  349.     }
  350.     *p = '\0';
  351.     return (buf);
  352. }
  353.  
  354. /*
  355.  * Execute a shell command.
  356.  * Return a pointer to a pipe connected to the shell command's standard output.
  357.  */
  358.     static FILE *
  359. shellcmd(cmd, s1, s2)
  360.     char *cmd;
  361.     char *s1;
  362.     char *s2;
  363. {
  364.     char *scmd;
  365.     char *shell;
  366.     FILE *fd;
  367.     int len;
  368.     
  369.     len = strlen(cmd) + 
  370.         (s1 == NULL ? 0 : strlen(s1)) + 
  371.         (s2 == NULL ? 0 : strlen(s2)) + 1;
  372.     scmd = (char *) ecalloc(len, sizeof(char));
  373.     sprintf(scmd, cmd, s1, s2);
  374. #if HAVE_SHELL
  375.     shell = lgetenv("SHELL");
  376.     if (shell != NULL && *shell != '\0')
  377.     {
  378.         /*
  379.          * Read the output of <$SHELL -c "cmd">.
  380.          */
  381.         char *scmd2;
  382.         scmd2 = (char *) ecalloc(strlen(shell) + strlen(scmd) + 7,
  383.                     sizeof(char));
  384.         sprintf(scmd2, "%s -c \"%s\"", shell, scmd);
  385.         free(scmd);
  386.         scmd = scmd2;
  387.     }
  388. #endif
  389.     fd = popen(scmd, "r");
  390.     free(scmd);
  391.     return (fd);
  392. }
  393.  
  394. /*
  395.  * Expand a filename, doing any shell-level substitutions.
  396.  */
  397.     public char *
  398. lglob(filename)
  399.     char *filename;
  400. {
  401.     char *gfilename;
  402.  
  403.     filename = fexpand(filename);
  404.  
  405.     if (secure)
  406.         return (filename);
  407. #if OS2
  408. {
  409.     char **list;
  410.     int cnt;
  411.     int length;
  412.  
  413.     list = _fnexplode(filename);
  414.     if (list == NULL)
  415.         return (filename);
  416.     length = 1; /* Room for trailing null byte */
  417.     for (cnt = 0;  list[cnt] != NULL;  cnt++)
  418.           length += strlen(list[cnt]) + 1;
  419.     gfilename = (char *) ecalloc(length, sizeof(char));
  420.     for (cnt = 0;  list[cnt] != NULL;  cnt++)
  421.     {
  422.         strcat(gfilename, list[cnt]);
  423.           strcat(gfilename, " ");
  424.     }
  425.     _fnexplodefree(list);
  426. }
  427. #else
  428. {
  429.     FILE *fd;
  430.     char *s;
  431.  
  432.     /*
  433.      * We get the shell to expand the filename for us by passing
  434.      * an "echo" command to the shell and reading its output.
  435.      */
  436.  
  437.     /*
  438.      * Certain characters will cause problems if passed to the shell,
  439.      * so we disallow them.
  440.      * {{ This presumes too much knowlege about the shell, but not
  441.      *    doing this can cause serious problems.  For example, do 
  442.      *    "!;TAB" when the first file in the dir is named "rm". }}
  443.      */
  444.     for (s = filename;  *s != '\0';  s++)
  445.     {
  446.         if (*s == ';' || *s == '\'' || *s == '\"' || *s == '\\')
  447.             return (filename);
  448.     }
  449.  
  450.     fd = shellcmd("echo %s", filename, (char*)NULL);
  451.     if (fd == NULL)
  452.     {
  453.         /*
  454.          * Cannot create the pipe.
  455.          * Just return the original (fexpanded) filename.
  456.          */
  457.         return (filename);
  458.     }
  459.     gfilename = readfd(fd);
  460.     pclose(fd);
  461.     if (*gfilename == '\0')
  462.     {
  463.         free(gfilename);
  464.         return (filename);
  465.     }
  466.     free(filename);
  467. }
  468. #endif
  469.     return (gfilename);
  470. }
  471.  
  472. /*
  473.  * See if we should open a "replacement file" 
  474.  * instead of the file we're about to open.
  475.  */
  476.     public char *
  477. open_altfile(filename, pf, pfd)
  478.     char *filename;
  479.     int *pf;
  480.     void **pfd;
  481. {
  482.     char *lessopen;
  483.     char *gfilename;
  484.     FILE *fd;
  485. #if HAVE_FILENO
  486.     int returnfd = 0;
  487. #endif
  488.     
  489.     if (secure)
  490.         return (NULL);
  491.     ch_ungetchar(-1);
  492.     if ((lessopen = lgetenv("LESSOPEN")) == NULL)
  493.         return (NULL);
  494.     if (strcmp(filename, "-") == 0)
  495.         return (NULL);
  496.     if (*lessopen == '|')
  497.     {
  498.         /*
  499.          * If LESSOPEN starts with a |, it indicates 
  500.          * a "pipe preprocessor".
  501.          */
  502. #if HAVE_FILENO
  503.         lessopen++;
  504.         returnfd = 1;
  505. #else
  506.         error("LESSOPEN pipe is not supported", NULL_PARG);
  507.         return (NULL);
  508. #endif
  509.     }
  510.     fd = shellcmd(lessopen, filename, (char*)NULL);
  511.     if (fd == NULL)
  512.     {
  513.         /*
  514.          * Cannot create the pipe.
  515.          */
  516.         return (NULL);
  517.     }
  518. #if HAVE_FILENO
  519.     if (returnfd)
  520.     {
  521.         int f;
  522.         char c;
  523.  
  524.         /*
  525.          * Read one char to see if the pipe will produce any data.
  526.          * If it does, push the char back on the pipe.
  527.          */
  528.         f = fileno(fd);
  529.         if (read(f, &c, 1) != 1)
  530.         {
  531.             /*
  532.              * Pipe is empty.  This means there is no alt file.
  533.              */
  534.             pclose(fd);
  535.             return (NULL);
  536.         }
  537.         ch_ungetchar(c);
  538.         *pfd = (void *) fd;
  539.         *pf = f;
  540.         return (save("-"));
  541.     }
  542. #endif
  543.     gfilename = readfd(fd);
  544.     pclose(fd);
  545.     if (*gfilename == '\0')
  546.         /*
  547.          * Pipe is empty.  This means there is no alt file.
  548.          */
  549.         return (NULL);
  550.     return (gfilename);
  551. }
  552.  
  553. /*
  554.  * Close a replacement file.
  555.  */
  556.     public void
  557. close_altfile(altfilename, filename, pipefd)
  558.     char *altfilename;
  559.     char *filename;
  560.     void *pipefd;
  561. {
  562.     char *lessclose;
  563.     FILE *fd;
  564.     
  565.     if (secure)
  566.         return;
  567.     if (pipefd != NULL)
  568.         pclose((FILE*) pipefd);
  569.     if ((lessclose = lgetenv("LESSCLOSE")) == NULL)
  570.              return;
  571.     fd = shellcmd(lessclose, filename, altfilename);
  572.     pclose(fd);
  573. }
  574.         
  575. #else
  576. #if MSDOS_COMPILER
  577.  
  578. /*
  579.  * Define macros for the MS-DOS "find file" interfaces.
  580.  */
  581. #if MSDOS_COMPILER==WIN32C
  582.  
  583. #define    FIND_FIRST(filename,fndp)    findfirst(filename, fndp, ~0)
  584. #define    FIND_NEXT(fndp)            findnext(fndp)
  585. #define    FND_NAME            ff_name
  586. #define    DECLARE_FIND(fnd,drive,dir,fname,ext) \
  587.                     struct ffblk fnd;    \
  588.                     char drive[MAXDRIVE];    \
  589.                     char dir[MAXDIR];    \
  590.                     char fname[MAXFILE];    \
  591.                     char ext[MAXEXT];    
  592.  
  593. #else
  594.  
  595. #define    FIND_FIRST(filename,fndp)    _dos_findfirst(filename, ~0, fndp)
  596. #define    FIND_NEXT(fndp)            _dos_findnext(fndp)
  597. #define    FND_NAME            name
  598. #define    DECLARE_FIND(fnd,drive,dir,fname,ext) \
  599.                     struct find_t fnd;    \
  600.                     char drive[_MAX_DRIVE];    \
  601.                     char dir[_MAX_DIR];    \
  602.                     char fname[_MAX_FNAME];    \
  603.                     char ext[_MAX_EXT];    
  604.  
  605. #endif
  606.     
  607.     public char *
  608. lglob(filename)
  609.     char *filename;
  610. {
  611.     register char *gfilename;
  612.     register char *p;
  613.     register int len;
  614.     register int n;
  615.     DECLARE_FIND(fnd,drive,dir,fname,ext)
  616.     
  617.     filename = fexpand(filename);
  618.  
  619.     if (secure)
  620.         return (filename);
  621.  
  622.     if (FIND_FIRST(filename, &fnd) != 0)
  623.         return (filename);
  624.  
  625.     _splitpath(filename, drive, dir, fname, ext);
  626.     len = 100;
  627.     gfilename = (char *) ecalloc(len, sizeof(char));
  628.     p = gfilename;
  629.     do {
  630.         n = strlen(drive) + strlen(dir) + strlen(fnd.FND_NAME);
  631.         while (p - gfilename + n+2 >= len)
  632.         {
  633.             /*
  634.              * No room in current buffer.  Allocate a bigger one.
  635.              */
  636.             len *= 2;
  637.             *p = '\0';
  638.             p = (char *) ecalloc(len, sizeof(char));
  639.             strcpy(p, gfilename);
  640.             free(gfilename);
  641.             gfilename = p;
  642.             p = gfilename + strlen(gfilename);
  643.         }
  644.         sprintf(p, "%s%s%s", drive, dir, fnd.FND_NAME);
  645.         p += n;
  646.         *p++ = ' ';
  647.     } while (FIND_NEXT(&fnd) == 0);
  648.  
  649.     /*
  650.      * Overwrite the final trailing space with a null terminator.
  651.      */
  652.     *--p = '\0';
  653.     return (gfilename);
  654. }
  655.  
  656.     public char *
  657. open_altfile(filename)
  658.     char *filename;
  659. {
  660.     return (NULL);
  661. }
  662.  
  663.     public void
  664. close_altfile(altfilename, filename)
  665.     char *altfilename;
  666.     char *filename;
  667. {
  668. }
  669.         
  670. #else
  671.  
  672.     public char *
  673. lglob(filename)
  674.     char *filename;
  675. {
  676.     return (fexpand(filename));
  677. }
  678.  
  679.     
  680.     public char *
  681. open_altfile(filename)
  682.     char *filename;
  683. {
  684.          return (NULL);
  685. }
  686.  
  687.     public void
  688. close_altfile(altfilename, filename)
  689.     char *altfilename;
  690.     char *filename;
  691. {
  692. }
  693.         
  694. #endif
  695. #endif
  696.  
  697.  
  698. #if HAVE_STAT
  699.  
  700. #include <sys/stat.h>
  701. #ifndef S_ISDIR
  702. #define    S_ISDIR(m)    (((m) & S_IFMT) == S_IFDIR)
  703. #endif
  704. #ifndef S_ISREG
  705. #define    S_ISREG(m)    (((m) & S_IFMT) == S_IFREG)
  706. #endif
  707.  
  708. /*
  709.  * Returns NULL if the file can be opened and
  710.  * is an ordinary file, otherwise an error message
  711.  * (if it cannot be opened or is a directory, etc.)
  712.  */
  713.     public char *
  714. bad_file(filename)
  715.     char *filename;
  716. {
  717.     register char *m;
  718.     struct stat statbuf;
  719.  
  720.     if (stat(filename, &statbuf) < 0)
  721.         return (errno_message(filename));
  722.  
  723.     if (force_open)
  724.         return (NULL);
  725.  
  726.     if (S_ISDIR(statbuf.st_mode))
  727.     {
  728.         static char is_dir[] = " is a directory";
  729.         m = (char *) ecalloc(strlen(filename) + sizeof(is_dir), 
  730.             sizeof(char));
  731.         strcpy(m, filename);
  732.         strcat(m, is_dir);
  733.         return (m);
  734.     }
  735.     if (!S_ISREG(statbuf.st_mode))
  736.     {
  737.         static char not_reg[] = " is not a regular file";
  738.         m = (char *) ecalloc(strlen(filename) + sizeof(not_reg), 
  739.             sizeof(char));
  740.         strcpy(m, filename);
  741.         strcat(m, not_reg);
  742.         return (m);
  743.     }
  744.  
  745.     return (NULL);
  746. }
  747.  
  748. /*
  749.  * Return the size of a file, as cheaply as possible.
  750.  * In Unix, we can stat the file.
  751.  */
  752.     public POSITION
  753. filesize(f)
  754.     int f;
  755. {
  756.     struct stat statbuf;
  757.  
  758.     if (fstat(f, &statbuf) < 0)
  759.         /*
  760.          * Can't stat; try seeking to the end.
  761.          */
  762.         return (seek_filesize(f));
  763.  
  764.     return ((POSITION) statbuf.st_size);
  765. }
  766.  
  767. #else
  768. #ifdef _OSK
  769.  
  770.     public char *
  771. bad_file(filename)
  772.     char *filename;
  773. {
  774.     register int f;
  775.     register char *m;
  776.  
  777.     if ((f = open(filename, S_IREAD | S_IFDIR)) >= 0)
  778.     {
  779.         static char is_dir[] = " is a directory";
  780.         close(f);
  781.         if (force_open)
  782.             return (NULL);
  783.         m = (char *) ecalloc(strlen(filename) + sizeof(is_dir),
  784.             sizeof(char));
  785.         strcpy(m, filename);
  786.         strcat(m, is_dir);
  787.         return (m);
  788.     }
  789.     if ((f = open(filename, S_IREAD)) < 0)
  790.         return (errno_message(filename));
  791.     close(f);
  792.     return (NULL);
  793. }
  794.  
  795.     public POSITION
  796. filesize(f)
  797.     int f;
  798. {
  799.     long size;
  800.  
  801.     if ((size = (long)_gs_size(f)) < 0)
  802.         /*
  803.          * Can't stat; try seeking to the end.
  804.          */
  805.         return (seek_filesize(f));
  806.  
  807.     return ((POSITION) size);
  808. }
  809.  
  810. #else
  811.  
  812. /*
  813.  * If we have no way to find out, just say the file is good.
  814.  */
  815.     public char *
  816. bad_file(filename)
  817.     char *filename;
  818. {
  819.     return (NULL);
  820. }
  821.  
  822. /*
  823.  * We can find the file size by seeking.
  824.  */
  825.     public POSITION
  826. filesize(f)
  827.     int f;
  828. {
  829.     return (seek_filesize(f));
  830. }
  831.  
  832. #endif
  833. #endif
  834.