home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 036 / less232.zip / FILENAME.C < prev    next >
C/C++ Source or Header  |  1994-09-24  |  12KB  |  614 lines

  1. /*
  2.  * Copyright (c) 1984,1985,1989,1994  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 MSOFTC
  35. #include <dos.h>
  36. #endif
  37.  
  38. extern int force_open;
  39. extern IFILE curr_ifile;
  40. extern IFILE old_ifile;
  41.  
  42. /*
  43.  * Return the full pathname of the given file in the "home directory".
  44.  */
  45.     public char *
  46. homefile(filename)
  47.     char *filename;
  48. {
  49.     register char *pathname;
  50.     register char *homedir;
  51.  
  52.     homedir = getenv("HOME");
  53. #if MSOFTC
  54.     /*
  55.      * If $HOME is not defined, look for the file anywhere on search path.
  56.      */
  57.     pathname = NULL;
  58.     if (homedir != NULL)
  59.     {
  60.         /*
  61.          * Found $HOME.
  62.          */
  63.         pathname = (char *) calloc(strlen(homedir)+strlen(filename)+2, 
  64.                     sizeof(char));
  65.         if (pathname == NULL)
  66.             return (NULL);
  67.         sprintf(pathname, "%s\\%s", homedir, filename);
  68.         if (access(pathname, 0) < 0)
  69.         {
  70.             free(pathname);
  71.             pathname = NULL;
  72.         }
  73.     }
  74.     if (pathname == NULL)
  75.     {
  76.             
  77.         pathname = (char *) calloc(_MAX_PATH, sizeof(char));
  78.         _searchenv(filename, "PATH", pathname);
  79.         if (*pathname == '\0')
  80.             
  81.         {
  82.             free(pathname);
  83.             pathname = NULL;
  84.         }
  85.     }
  86.     
  87. #else
  88. #if OS2
  89.         pathname = (char *) calloc(256, sizeof(char));
  90.     if (pathname == NULL)
  91.         return NULL;
  92.         _searchenv(filename, "INIT", pathname);
  93.         if ( pathname[0] == 0 )
  94.           _searchenv(filename, "PATH", pathname);
  95.         if ( pathname[0] == 0 )
  96.         {
  97.           free(pathname);
  98.           return NULL;
  99.         }
  100. #else
  101.     if (homedir == NULL)
  102.         return (NULL);
  103.     pathname = (char *) calloc(strlen(homedir)+strlen(filename)+2,
  104.                 sizeof(char));
  105.     if (pathname == NULL)
  106.         return (NULL);
  107.     sprintf(pathname, "%s/%s", homedir, filename);
  108. #endif
  109. #endif
  110.     return (pathname);
  111. }
  112.  
  113. /*
  114.  * Find out where the help file is.
  115.  */
  116.     public char *
  117. find_helpfile()
  118. {
  119.     register char *helpfile;
  120.     
  121.     if ((helpfile = getenv("LESSHELP")) != NULL)
  122.         return (save(helpfile));
  123. #if MSOFTC || OS2
  124.     return (homefile(HELPFILE));
  125. #else
  126.     return (save(HELPFILE));
  127. #endif
  128. }
  129.  
  130. /*
  131.  * Expand a string, substituting any "%" with the current filename,
  132.  * and any "#" with the previous filename.
  133.  * {{ This is a lot of work just to support % and #. }}
  134.  */
  135.     public char *
  136. fexpand(s)
  137.     char *s;
  138. {
  139.     register char *fr, *to;
  140.     register int n;
  141.     register char *e;
  142.  
  143.     /*
  144.      * Make one pass to see how big a buffer we 
  145.      * need to allocate for the expanded string.
  146.      */
  147.     n = 0;
  148.     for (fr = s;  *fr != '\0';  fr++)
  149.     {
  150.         switch (*fr)
  151.         {
  152.         case '%':
  153.             n += strlen(get_filename(curr_ifile));
  154.             break;
  155.         case '#':
  156.             if (old_ifile == NULL_IFILE)
  157.             {
  158.                 error("No previous file", NULL_PARG);
  159.                 return (NULL);
  160.             }
  161.             n += strlen(get_filename(old_ifile));
  162.             break;
  163.         default:
  164.             n++;
  165.             break;
  166.         }
  167.     }
  168.  
  169.     e = (char *) ecalloc(n+1, sizeof(char));
  170.  
  171.     /*
  172.      * Now copy the string, expanding any "%" or "#".
  173.      */
  174.     to = e;
  175.     for (fr = s;  *fr != '\0';  fr++)
  176.     {
  177.         switch (*fr)
  178.         {
  179.         case '%':
  180.             strcpy(to, get_filename(curr_ifile));
  181.             to += strlen(to);
  182.             break;
  183.         case '#':
  184.             strcpy(to, get_filename(old_ifile));
  185.             to += strlen(to);
  186.             break;
  187.         default:
  188.             *to++ = *fr;
  189.             break;
  190.         }
  191.     }
  192.     *to = '\0';
  193.     return (e);
  194. }
  195.  
  196. #if TAB_COMPLETE_FILENAME
  197.  
  198. /*
  199.  * Return a blank-separated list of filenames which "complete"
  200.  * the given string.
  201.  */
  202.     public char *
  203. fcomplete(s)
  204.     char *s;
  205. {
  206.     char *fpat;
  207.     /*
  208.      * Complete the filename "s" by globbing "s*".
  209.      */
  210. #if MSOFTC
  211.     /*
  212.      * But in DOS, we have to glob "s*.*".
  213.      * But if the final component of the filename already has
  214.      * a dot in it, just do "s*".  
  215.      * (Thus, "FILE" is globbed as "FILE*.*", 
  216.      *  but "FILE.A" is globbed as "FILE.A*").
  217.      */
  218.     char *slash;
  219.     for (slash = s+strlen(s)-1;  slash > s;  slash--)
  220.         if (*slash == '/' || *slash == '\\')
  221.             break;
  222.     fpat = (char *) ecalloc(strlen(s)+4, sizeof(char));
  223.     if (strchr(slash, '.') == NULL)
  224.         sprintf(fpat, "%s*.*", s);
  225.     else
  226.         sprintf(fpat, "%s*", s);
  227. #else
  228.     fpat = (char *) ecalloc(strlen(s)+2, sizeof(char));
  229.     sprintf(fpat, "%s*", s);
  230. #endif
  231.     s = glob(fpat);
  232.     if (s != NULL && strcmp(s,fpat) == 0)
  233.     {
  234.         free(s);
  235.         s = NULL;
  236.     }
  237.     free(fpat);
  238.     return (s);
  239. }
  240. #endif
  241.  
  242. /*
  243.  * Try to determine if a file is "binary".
  244.  * This is just a guess, and we need not try too hard to make it accurate.
  245.  */
  246.     public int
  247. bin_file(f)
  248.     int f;
  249. {
  250.     int i;
  251.     int n;
  252.     unsigned char data[64];
  253.  
  254.     n = read(f, data, sizeof(data));
  255.     for (i = 0;  i < n;  i++)
  256.         if (binary_char(data[i]))
  257.             return (1);
  258.     return (0);
  259. }
  260.  
  261. /*
  262.  * Try to determine the size of a file by seeking to the end.
  263.  */
  264.     static POSITION
  265. seek_filesize(f)
  266.     int f;
  267. {
  268.     off_t spos;
  269.  
  270.     spos = lseek(f, (off_t)0, 2);
  271.     if (spos == BAD_LSEEK)
  272.         return (NULL_POSITION);
  273.     return ((POSITION) spos);
  274. }
  275.  
  276. /*
  277.  * Expand a filename, substituting any environment variables, etc.
  278.  */
  279. #if GLOB
  280.  
  281. FILE *popen();
  282.  
  283.     static char *
  284. readfd(fd)
  285.     FILE *fd;
  286. {
  287.     int len;
  288.     int ch;
  289.     char *buf;
  290.     char *p;
  291.     
  292.     len = 100;
  293.     buf = (char *) ecalloc(len, sizeof(char));
  294.     for (p = buf;  ;  p++)
  295.     {
  296.         if ((ch = getc(fd)) == '\n' || ch == EOF)
  297.             break;
  298.         if (p - buf >= len-1)
  299.         {
  300.             len *= 2;
  301.             *p = '\0';
  302.             p = (char *) ecalloc(len, sizeof(char));
  303.             strcpy(p, buf);
  304.             free(buf);
  305.             buf = p;
  306.             p = buf + strlen(buf);
  307.         }
  308.         *p = ch;
  309.     }
  310.     *p = '\0';
  311.     return (buf);
  312. }
  313.  
  314.     static FILE *
  315. shellcmd(cmd, s1, s2)
  316.     char *cmd;
  317.     char *s1;
  318.     char *s2;
  319. {
  320.     char *scmd;
  321.     char *scmd2;
  322.     char *shell;
  323.     FILE *fd;
  324.     int len;
  325.     
  326.     len = strlen(cmd) + 
  327.         (s1 == NULL ? 0 : strlen(s1)) + 
  328.         (s2 == NULL ? 0 : strlen(s2)) + 1;
  329.     scmd = (char *) ecalloc(len, sizeof(char));
  330.     sprintf(scmd, cmd, s1, s2);
  331. #if !OS2
  332.     shell = getenv("SHELL");
  333.     if (shell != NULL && *shell != '\0')
  334.     {
  335.         /*
  336.          * Read the output of <$SHELL -c "cmd">.
  337.          */
  338.         scmd2 = (char *) ecalloc(strlen(shell) + strlen(scmd) + 7,
  339.                     sizeof(char));
  340.         sprintf(scmd2, "%s -c \"%s\"", shell, scmd);
  341.         free(scmd);
  342.         scmd = scmd2;
  343.     }
  344. #endif
  345.     fd = popen(scmd, "r");
  346.     free(scmd);
  347.     return (fd);
  348. }
  349.  
  350.     public char *
  351. glob(filename)
  352.     char *filename;
  353. {
  354. #if OS2
  355.     char **list = _fnexplode(filename);
  356.     char *names;
  357.     int cnt, length = 0;
  358.     for (cnt = 0; list[cnt]; cnt++)
  359.           length += strlen(list[cnt]) + 1;
  360.     names = (char *) ecalloc(length, sizeof(char));
  361.     for (cnt = 0; list[cnt]; cnt++)
  362.           strcat(strcat(names, list[cnt]), " ");
  363.     _fnexplodefree(list);
  364.     return names;
  365. #else
  366.     FILE *fd;
  367.     char *gfilename;
  368.  
  369.     filename = fexpand(filename);
  370.     if (filename == NULL)
  371.         return (NULL);
  372.  
  373.     /*
  374.      * We get the shell to expand the filename for us by passing
  375.      * an "echo" command to the shell and reading its output.
  376.      */
  377.     fd = shellcmd("echo %s", filename, (char*)NULL);
  378.     if (fd == NULL)
  379.     {
  380.         /*
  381.          * Cannot create the pipe.
  382.          * Just return the original (fexpanded) filename.
  383.          */
  384.         return (filename);
  385.     }
  386.     free(filename);
  387.     gfilename = readfd(fd);
  388.     pclose(fd);
  389.     if (*gfilename == '\0')
  390.         return (NULL);
  391.     return (gfilename);
  392. #endif
  393. }
  394.  
  395.     public char *
  396. open_altfile(filename)
  397.     char *filename;
  398. {
  399.     char *lessopen;
  400.     char *gfilename;
  401.     FILE *fd;
  402.     
  403.     if ((lessopen = getenv("LESSOPEN")) == NULL)
  404.         return (NULL);
  405.     filename = fexpand(filename);
  406.     if (filename == NULL)
  407.         return (NULL);
  408.     fd = shellcmd(lessopen, filename, (char*)NULL);
  409.     if (fd == NULL)
  410.     {
  411.         /*
  412.          * Cannot create the pipe.
  413.          */
  414.         return (NULL);
  415.     }
  416.     free(filename);
  417.     gfilename = readfd(fd);
  418.     pclose(fd);
  419.     if (*gfilename == '\0')
  420.         return (NULL);
  421.     return (gfilename);
  422. }
  423.  
  424.     public void
  425. close_altfile(altfilename, filename)
  426.     char *altfilename;
  427.     char *filename;
  428. {
  429.     char *lessclose;
  430.     FILE *fd;
  431.     
  432.     if ((lessclose = getenv("LESSCLOSE")) == NULL)
  433.              return;
  434.     fd = shellcmd(lessclose, filename, altfilename);
  435.     pclose(fd);
  436. }
  437.         
  438. #else
  439. #if MSOFTC
  440.  
  441.     public char *
  442. glob(filename)
  443.     char *filename;
  444. {
  445.     register char *gfilename;
  446.     register char *p;
  447.     register int len;
  448.     register int n;
  449.     struct find_t fnd;
  450.     char drive[_MAX_DRIVE];
  451.     char dir[_MAX_DIR];
  452.     char fname[_MAX_FNAME];
  453.     char ext[_MAX_EXT];
  454.     
  455.     filename = fexpand(filename);
  456.     if (filename == NULL)
  457.         return (NULL);
  458.     if (_dos_findfirst(filename, ~0, &fnd) != 0)
  459.         return (filename);
  460.         
  461.     _splitpath(filename, drive, dir, fname, ext);
  462.     len = 100;
  463.     gfilename = (char *) ecalloc(len, sizeof(char));
  464.     p = gfilename;
  465.     do {
  466.         n = strlen(drive) + strlen(dir) + strlen(fnd.name);
  467.         while (p - gfilename + n+2 >= len)
  468.         {
  469.             len *= 2;
  470.             *p = '\0';
  471.             p = (char *) ecalloc(len, sizeof(char));
  472.             strcpy(p, gfilename);
  473.             free(gfilename);
  474.             gfilename = p;
  475.             p = gfilename + strlen(gfilename);
  476.         }
  477.         sprintf(p, "%s%s%s", drive, dir, fnd.name);
  478.         p += n;
  479.         *p++ = ' ';
  480.     } while (_dos_findnext(&fnd) == 0);
  481.     
  482.     *--p = '\0';
  483.     return (gfilename);
  484. }
  485.     
  486.     public char *
  487. open_altfile(filename)
  488.     char *filename;
  489. {
  490.     return (NULL);
  491. }
  492.  
  493.     public void
  494. close_altfile(altfilename, filename)
  495.     char *altfilename;
  496.     char *filename;
  497. {
  498. }
  499.         
  500. #else
  501.  
  502.     public char *
  503. glob(filename)
  504.     char *filename;
  505. {
  506.     return (fexpand(filename));
  507. }
  508.  
  509.     
  510.     public char *
  511. open_altfile(filename)
  512.     char *filename;
  513. {
  514.          return (NULL);
  515. }
  516.  
  517.     public void
  518. close_altfile(altfilename, filename)
  519.     char *altfilename;
  520.     char *filename;
  521. {
  522. }
  523.         
  524. #endif
  525. #endif
  526.  
  527.  
  528. #if HAVE_STAT
  529.  
  530. #include <sys/stat.h>
  531.  
  532. /*
  533.  * Returns NULL if the file can be opened and
  534.  * is an ordinary file, otherwise an error message
  535.  * (if it cannot be opened or is a directory, etc.)
  536.  */
  537.     public char *
  538. bad_file(filename)
  539.     char *filename;
  540. {
  541.     register char *m;
  542.     struct stat statbuf;
  543.  
  544.     if (stat(filename, &statbuf) < 0)
  545.         return (errno_message(filename));
  546.  
  547.     if (force_open)
  548.         return (NULL);
  549.  
  550.     if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
  551.     {
  552.         static char is_dir[] = " is a directory";
  553.         m = (char *) ecalloc(strlen(filename) + sizeof(is_dir), 
  554.             sizeof(char));
  555.         strcpy(m, filename);
  556.         strcat(m, is_dir);
  557.         return (m);
  558.     }
  559.     if ((statbuf.st_mode & S_IFMT) != S_IFREG)
  560.     {
  561.         static char not_reg[] = " is not a regular file";
  562.         m = (char *) ecalloc(strlen(filename) + sizeof(not_reg), 
  563.             sizeof(char));
  564.         strcpy(m, filename);
  565.         strcat(m, not_reg);
  566.         return (m);
  567.     }
  568.  
  569.     return (NULL);
  570. }
  571.  
  572. /*
  573.  * Return the size of a file, as cheaply as possible.
  574.  * In Unix, we can stat the file.
  575.  */
  576.     public POSITION
  577. filesize(f)
  578.     int f;
  579. {
  580.     struct stat statbuf;
  581.  
  582.     if (fstat(f, &statbuf) < 0)
  583.         /*
  584.          * Can't stat; try seeking to the end.
  585.          */
  586.         return (seek_filesize(f));
  587.  
  588.     return ((POSITION) statbuf.st_size);
  589. }
  590.  
  591. #else
  592.  
  593. /*
  594.  * If we have no way to find out, just say the file is good.
  595.  */
  596.     public char *
  597. bad_file(filename)
  598.     char *filename;
  599. {
  600.     return (NULL);
  601. }
  602.  
  603. /*
  604.  * We can find the file size by seeking.
  605.  */
  606.     public POSITION
  607. filesize(f)
  608.     int f;
  609. {
  610.     return (seek_filesize(f));
  611. }
  612.  
  613. #endif
  614.