home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 3 / Meeting_Pearls_III.iso / Pearls / texmf / source / driver / util / amiga / EVPaths.c < prev    next >
C/C++ Source or Header  |  1994-11-12  |  20KB  |  899 lines

  1. /*
  2.  * EVPaths.c - Environment Variables Path Routines for TeX related programs.
  3.  *
  4.  * Written by Giuseppe Ghibò
  5.  *
  6.  * © 1994 by Giuseppe Ghibò <ghibo@galileo.polito.it>
  7.  *
  8.  * Version 1.2 (09-Nov-94)
  9.  *
  10. */
  11.  
  12. #include "evpaths.h"
  13. #include <exec/memory.h>
  14. #include <dos/dosextens.h>
  15. #include <proto/exec.h>
  16. #include <proto/dos.h>
  17. #define USE_BUILTIN_MATH
  18. #include <string.h>
  19.  
  20. extern struct DosLibrary *DOSBase;
  21.  
  22. #define ENVPATH_OK        0L    /* Success */
  23. #define ENVPATH_NOT_ENOUGH_ROOM    1L    /* Array was truncated */
  24. #define ENVPATH_VAR_NOT_FOUND    2L    /* There is no env var */
  25. #define ENVPATH_NOT_ENOUGH_MEM    3L    /* Not enough mem to alloc */
  26.  
  27. #define ENVPATH_SCAN_NONE    0L    /* No dirs scan */
  28. #define ENVPATH_SCAN_ONE    1L    /* Scan one level subdirs */
  29. #define ENVPATH_SCAN_ALL    2L    /* Scan recursively all subdirs */
  30. #define ENVPATH_SCAN_VAR    3L    /* Scan recursively another var */
  31. #define ENVPATH_SCAN_DEFPATH    4L    /* Put default path */
  32.  
  33. #define ENVPATH_GETVAR        0L    /* Get var */
  34. #define ENVPATH_DONTGETVAR    1L    /* Don't get var */
  35.  
  36. /* Prototypes */
  37. STATIC LONG    __regargs GetVar13(STRPTR name, UBYTE *buf, LONG size);
  38. STATIC VOID     __regargs GetEnvPath(STRPTR envname, UBYTE *buffer, LONG size, LONG *Error, LONG mode);
  39. STATIC STRPTR     __regargs Super_Strtok(STRPTR s, STRPTR p1, STRPTR p2, UBYTE open_delim, UBYTE close_delim);
  40. STATIC LONG    __regargs Add_Path_String(STRPTR s, STRPTR *p, LONG size);
  41. STATIC STRPTR    __regargs Parse_Path_String(STRPTR s, LONG *scan_status);
  42. STATIC LONG    __regargs Scan_Path_String(BPTR dirlock, STRPTR name, BOOL recursion, STRPTR *buf, LONG size);
  43. STATIC VOID    __regargs Insert_Path(struct EnvVarPath *p, APTR path, LONG mode);
  44.  
  45. #define PATH_TMPLEN 256
  46. STATIC UBYTE Path_TmpStr[PATH_TMPLEN]; /* temporary storage */
  47.  
  48. /* Super_Strtok() is similar to strtok(). It breaks the string s if
  49.  * one or more char from the string p1 is matched. The string s is also
  50.  * breaked if one or more char from the string p2 is matched, but only
  51.  * if such char is found outside the string delimited by
  52.  * open_delim, close_delim. For instance if
  53.  *
  54.  * s = "one,two,three,four,<fi,ve>\nsix,seven" ;
  55.  * p1 = "\n" ;
  56.  * p2 = "," ;
  57.  * open_delim = '<' ;
  58.  * close_delim = '>' ;
  59.  *
  60.  * Then after each call to Super_Strtok, we obtain respectively the
  61.  * following strings:
  62.  *
  63.  *    one    two    three    four    <fi,ve>
  64.  *    six    seven
  65.  *
  66.  */
  67. STATIC STRPTR last;
  68. STATIC STRPTR __regargs Super_Strtok(STRPTR s, STRPTR p1, STRPTR p2, UBYTE open_delim, UBYTE close_delim)
  69. {
  70.     STRPTR p, s1, s2, token;
  71.     BOOL opened = FALSE;
  72.  
  73.     if (s == NULL && (s = last) == NULL)
  74.         return (NULL);
  75.  
  76.     s += strspn(s, p1);
  77.     s += strspn(s, p2);
  78.  
  79.     if (*s == '\0')
  80.     {
  81.         last = NULL;
  82.         return (NULL);
  83.     }
  84.  
  85.     token = s;
  86.     s1 = s + strcspn(s, p1);
  87.     s2 = s + strcspn(s, p2);
  88.  
  89.     for (p = s; *p && p < s2; p++)
  90.     {
  91.         if (*p == open_delim)
  92.         {
  93.             if (open_delim == close_delim && opened)
  94.                 opened = FALSE;
  95.             else
  96.                 opened = TRUE;
  97.         }
  98.         else
  99.         {
  100.             if (*p == close_delim)
  101.                 opened = FALSE;
  102.         }
  103.     }
  104.  
  105.     if (opened)
  106.     {
  107.         for (p = s2; *p && p < s1 && *p++ != close_delim; ) ;
  108.         s = p;
  109.     }
  110.     else
  111.         s = (s1 < s2 ? s1 : s2);
  112.  
  113.     if (*s == '\0') {
  114.         last = NULL;
  115.     }
  116.     else
  117.     {
  118.         *s = '\0';
  119.         last = s + 1;
  120.     }
  121.  
  122.     return(token);
  123. }
  124.  
  125. /*
  126.  * GetVarLength() returns the length of an environment variable. If the
  127.  * given env var is not found or it doesn't exists, then the returned
  128.  * value is 0L.
  129.  */
  130. LONG __regargs GetVarLength(STRPTR envname)
  131. {
  132.     REGISTER LONG len;
  133.  
  134.     if (DOSBase->dl_lib.lib_Version >= 37)
  135.     {
  136.         UBYTE buffer[1];
  137.  
  138.         if ((len = GetVar(envname, buffer, 1L, GVF_GLOBAL_ONLY | GVF_BINARY_VAR)) != -1L)
  139.             len = IoErr();
  140.         else
  141.             len = 0L;
  142.     }
  143.     else
  144.     {
  145.         struct FileInfoBlock *fib;
  146.         BPTR lock;
  147.  
  148.         SNPrintf(Path_TmpStr, PATH_TMPLEN, "ENV:%s", envname);
  149.  
  150.         if (lock = Lock(Path_TmpStr, ACCESS_READ))
  151.         {
  152.             if ((fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_ANY)))
  153.             {
  154.                 if (Examine(lock, fib))
  155.                 {
  156.                     if (fib->fib_DirEntryType < 0L)
  157.                         len = fib->fib_Size;
  158.                     else
  159.                         len = 0L;
  160.                 }
  161.                 else
  162.                     len = 0L;
  163.  
  164.                 FreeMem(fib, sizeof(struct FileInfoBlock));
  165.             }
  166.             else
  167.                 len = 0L;
  168.  
  169.             UnLock(lock);
  170.         }
  171.         else
  172.             len = 0L;
  173.     }
  174.  
  175.     return (len);
  176. }
  177.  
  178. /*
  179.  * Given an env var name, GetVar13() copies the contents of the env var into
  180.  * the buffer buf. If the size of the env var is greater than the size of
  181.  * the buffer, then the copied length will be size-1.
  182.  * The buffer is terminated with '\0'.
  183.  * The returned value is the number of the bytes copied into the buffer,
  184.  * without consider the trailing '\0'.
  185.  * If the environment variable doesn't exists, no action is performed and
  186.  * the returned value is 0L.
  187.  * Note that this function is similar to the GetVar() function of OS2.1,
  188.  * but has not the same behaviour. In fact GetVar() returns -1L if the var
  189.  * doesn't exists, while GetVar13() returns 0L in such case.
  190.  */
  191. STATIC LONG __regargs GetVar13(STRPTR name, UBYTE *buf, LONG size)
  192. {
  193.     LONG len;
  194.  
  195.     SNPrintf(Path_TmpStr, PATH_TMPLEN, "ENV:%s", name);
  196.  
  197.     len = min(GetVarLength(name), size);
  198.  
  199.     if (len > 0L)
  200.     {
  201.         BPTR fh;
  202.  
  203.         if ((fh = Open(Path_TmpStr, MODE_OLDFILE)) == DOSFALSE)
  204.             return(0L);
  205.  
  206.         if ((len = Read(fh, buf, len)) > 0L)
  207.         {
  208.             Close(fh);
  209.  
  210.             if (size <= len)
  211.                 len = size - 1L;
  212.  
  213.             buf[len] = '\0';
  214.             return(len);
  215.         }
  216.         else
  217.         {
  218.             Close(fh);
  219.             return(0L);
  220.         }
  221.     }
  222.     else
  223.         return(0L);
  224. }
  225.  
  226. #define ABSTOKEN "\012\014"     /* breaks only on line feed or form feed */
  227. #define RELTOKEN "\t\f\040,;"
  228. #define LQUOTE '\042'
  229. #define RQUOTE '\042'
  230. #define QUOTE  '\042'
  231.  
  232. /*
  233.  * GetEnvPath() processes the path of a given environment variable. The
  234.  * passed buffer is then fitted with path elements. Such buffer may be
  235.  * accessed as an array of string pointers.
  236.  * The 'mode' is either one of EVPATH_DONTGETVAR or EVPATH_GETVAR. If
  237.  * EVPATH_DONTGETVAR is specified then the 'envname' is considered a
  238.  * pointer to a path string, and paths element are treated as they were read
  239.  * from an environment variable.
  240.  *
  241.  * The *Error contains (on exit) one of these values:
  242.  * 
  243.  *  -  ENVPATH_OK: all was successful.
  244.  *
  245.  *  -  ENVPATH_NOT_ENOUGH_ROOM: the buffer is full. In this case the
  246.  *     buffer contains entries which fit into the buffer itself, i.e.
  247.  *     no truncated entries.
  248.  *
  249.  *  -  ENVPATH_VAR_NOT_FOUND: the given environment variable isn't
  250.  *     found or has zero length.
  251.  *
  252.  *  -  ENVPATH_NOT_ENOUGH_MEM: there was a not enough mem during processing.
  253.  *
  254.  */
  255.  
  256. #define MAX_RECURS_VAR 5
  257. STATIC VOID __regargs GetEnvPath(STRPTR envname, UBYTE *buffer, LONG size, LONG *Error, LONG mode)
  258. {
  259.     STRPTR    envbuf, *p = (STRPTR *)buffer, s;
  260.     LONG    envbuflen, scan_status = ENVPATH_SCAN_NONE, len;
  261.     STATIC LONG recurs_level = 0L;
  262.     STATIC STRPTR env_names[MAX_RECURS_VAR + 1];
  263.  
  264.     recurs_level++;
  265.  
  266.     if (recurs_level == 1L)
  267.     {
  268.         *Error = ENVPATH_OK;
  269.     }
  270.  
  271.     if (mode == ENVPATH_DONTGETVAR && recurs_level == 1)
  272.     {
  273.         if (envname)
  274.             envbuf = envname;
  275.         else
  276.         {
  277.             *Error = ENVPATH_VAR_NOT_FOUND;
  278.             --recurs_level;
  279.             return;
  280.         }
  281.     }
  282.     else
  283.     {
  284.         envbuflen = GetVarLength(envname) + 1L;
  285.  
  286.         if (envbuflen <= 1L)
  287.         {
  288.             *Error = ENVPATH_VAR_NOT_FOUND;
  289.             --recurs_level;
  290.             return;
  291.         }
  292.  
  293.         if (envbuf = AllocMem(envbuflen, MEMF_ANY | MEMF_CLEAR))
  294.         {
  295.             if (DOSBase->dl_lib.lib_Version >= 37)
  296.                 GetVar(envname, envbuf, envbuflen, GVF_GLOBAL_ONLY | GVF_BINARY_VAR);
  297.             else
  298.                 GetVar13(envname, envbuf, envbuflen);
  299.         }
  300.         else
  301.         {
  302.             *Error = ENVPATH_NOT_ENOUGH_MEM;
  303.             --recurs_level;
  304.             return;
  305.         }
  306.  
  307.         len = strlen(envname) + 1L;
  308.  
  309.         if (env_names[recurs_level - 1] = AllocMem(len, MEMF_ANY))
  310.         {
  311.             strcpy(env_names[recurs_level - 1], envname); /* store env name to avoid recursion loops */
  312.             env_names[recurs_level] = NULL;
  313.         }
  314.         else
  315.         {
  316.             *Error = ENVPATH_NOT_ENOUGH_MEM;
  317.             --recurs_level;
  318.             return;
  319.         }
  320.     }
  321.  
  322.     s = Super_Strtok(envbuf, ABSTOKEN, RELTOKEN, LQUOTE, RQUOTE); /* get first token */
  323.  
  324.     do
  325.     {
  326.         s = Parse_Path_String(s, &scan_status);
  327.  
  328.         if (scan_status == ENVPATH_SCAN_VAR)
  329.         {
  330.             if (recurs_level < MAX_RECURS_VAR)
  331.             {
  332.                 BOOL recursion = TRUE;
  333.                 LONG i = 0L;
  334.  
  335.                 while (env_names[i])
  336.                 {
  337.                     if (!strcmp(env_names[i++], s))
  338.                     {
  339.                         recursion = FALSE;
  340.                         break;
  341.                     }
  342.                 }
  343.  
  344.                 if (recursion)
  345.                 {
  346.                     GetEnvPath(s, buffer, size, Error, ENVPATH_GETVAR);
  347.  
  348.                     if (*Error == ENVPATH_VAR_NOT_FOUND)
  349.                         *Error = ENVPATH_OK; /* ignore recurs vars not found */
  350.                 }
  351.             }
  352.         }
  353.         else if (scan_status == ENVPATH_SCAN_ONE || scan_status == ENVPATH_SCAN_ALL)
  354.         {
  355.             BPTR dirlock;
  356.  
  357.             if (dirlock = Lock(s, ACCESS_READ))
  358.             {
  359.                 *Error = Add_Path_String(s, p, size);
  360.  
  361.                 if (*Error == ENVPATH_OK)
  362.                     *Error = Scan_Path_String(dirlock, s, (scan_status == ENVPATH_SCAN_ALL ? TRUE : FALSE), p, size);
  363.  
  364.                 UnLock(dirlock);
  365.             }
  366.         }
  367.         else
  368.             *Error = Add_Path_String(s, p, size);
  369.     }
  370.     while (*Error == ENVPATH_OK && (s = Super_Strtok(NULL, ABSTOKEN, RELTOKEN, LQUOTE, RQUOTE)));
  371.  
  372.     if (mode != ENVPATH_DONTGETVAR)
  373.         FreeMem(env_names[recurs_level - 1], len);
  374.  
  375.     if (envbuf && mode != ENVPATH_DONTGETVAR)
  376.         FreeMem(envbuf, envbuflen);
  377.  
  378.     --recurs_level;
  379. }
  380.  
  381. /*
  382.  * Add_Path_String(). Adds the string s to the array of strings p.
  383.  * The array must be initialized before to be passed to this function: the
  384.  * first element must be NULL! (p[0] = NULL).
  385.  *
  386.  * Returned values: ENVPATH_OK or ENVPATH_NOT_ENOUGH_ROOM.
  387.  *
  388.  */
  389. STATIC LONG __regargs Add_Path_String(STRPTR s, STRPTR *p, LONG size)
  390. {
  391.     LONG i = 0L, len;
  392.     STRPTR q;
  393.  
  394.     if (size < (2 * sizeof(STRPTR) + 1L))
  395.         return (ENVPATH_NOT_ENOUGH_ROOM);
  396.  
  397.     len = strlen(s);
  398.  
  399.     if (p[0] == NULL)
  400.     {
  401.         q = (STRPTR)p + size - (len + 1L);
  402.     }
  403.     else
  404.     {
  405.         for (i = 0L; p[i]; i++);
  406.         q = p[i-1] - (len + 1L);
  407.     }
  408.  
  409.     if (&p[i] > (STRPTR *)(q - 2*sizeof(STRPTR)))
  410.     {
  411.         p[i] = NULL;
  412.         return (ENVPATH_NOT_ENOUGH_ROOM);
  413.     }
  414.     else
  415.     {
  416.         LONG j;
  417.         BOOL is_valid_entry = TRUE;
  418.  
  419.         for (j = 0L; j < i; j++)
  420.         {
  421.             if (!stricmp(p[j], s))
  422.             {
  423.                 is_valid_entry = FALSE;
  424.             }
  425.         }
  426.  
  427.         if (is_valid_entry)
  428.         {
  429.             p[i] = q;
  430.             strcpy(p[i], s);
  431.             p[i+1] = NULL;
  432.         }
  433.     }
  434.  
  435.     return (ENVPATH_OK);
  436. }
  437.  
  438. #define MAX_RECURS_DIR 10L    /* maximum recursion dir level */
  439. STATIC LONG __regargs Scan_Path_String(BPTR dirlock, STRPTR name, BOOL recursion, STRPTR *buf, LONG size)
  440. {
  441.     struct FileInfoBlock *fib;
  442.     LONG result = ENVPATH_OK;
  443.     STATIC LONG recurs_level = 0L;
  444.  
  445.     recurs_level++;
  446.  
  447.     if ((fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_ANY)))
  448.     {
  449.         if (Examine(dirlock, fib))
  450.         {
  451.             if (fib->fib_DirEntryType > 0L)
  452.             {
  453.                 while (ExNext(dirlock, fib) && (result == ENVPATH_OK))
  454.                 {
  455.                     if (fib->fib_DirEntryType > 0L)
  456.                     {
  457.                         LONG len = strlen(name);
  458.  
  459.                         if (len > 0L)
  460.                             SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s%s%s", name,
  461.                                  ((name[len-1] != '/' && name[len-1] != ':') ? "/" : ""), fib->fib_FileName);
  462.                         else
  463.                             SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s", fib->fib_FileName);
  464.  
  465.                         result = Add_Path_String(Path_TmpStr, buf, size);
  466.  
  467.                         if (recursion && (result == ENVPATH_OK) && (recurs_level < MAX_RECURS_DIR))
  468.                         {
  469.                             BPTR OldDirLock, NewDirLock;
  470.  
  471.                             OldDirLock = CurrentDir(dirlock);
  472.  
  473.                             if (NewDirLock = Lock(Path_TmpStr, ACCESS_READ))
  474.                             {
  475.                                 STRPTR dirname;
  476.                                 LONG len = strlen(Path_TmpStr) + 1L;
  477.  
  478.                                 if (dirname = AllocMem(len, MEMF_ANY))
  479.                                 {
  480.                                     strcpy(dirname, Path_TmpStr);
  481.                                     result = Scan_Path_String(NewDirLock, dirname, recursion, buf, size);
  482.                                     FreeMem(dirname, len);
  483.                                 }
  484.                                 UnLock(NewDirLock);
  485.                             }
  486.                             CurrentDir(OldDirLock);
  487.                         }
  488.                     }
  489.                 }
  490.             }
  491.         }
  492.         FreeMem(fib, sizeof(struct FileInfoBlock));
  493.     }
  494.     else
  495.         result = ENVPATH_NOT_ENOUGH_MEM;
  496.  
  497.     --recurs_level;
  498.     return (result);
  499. }
  500.  
  501.  
  502. STATIC STRPTR __regargs Parse_Path_String(STRPTR s, LONG *scan_status)
  503. {
  504.     UBYTE *c;
  505.     LONG len;
  506.  
  507.     *scan_status = ENVPATH_SCAN_NONE;
  508.  
  509.     if (!s || !*s)
  510.         return("");
  511.  
  512.     if (s[0] == LQUOTE)
  513.         s++;        /* remove leading quote */
  514.  
  515.     for (c = s; *c; c++);    /* seek to the end of the string */
  516.  
  517.     if (*--c == RQUOTE)
  518.         *c = '\0';    /* remove trailing quote */
  519.  
  520.     if (s[0] == '.')    /* '.' or './' represents current dir */
  521.     {
  522.         switch (s[1])
  523.         {
  524.             case '\0':
  525.                 s[0] = '\0';    /* null string is current dir */
  526.                 break;
  527.  
  528.             case '/':
  529.                 if (s[2])
  530.                     s = &s[2];
  531.                 else
  532.                     s[0] = '\0';
  533.  
  534.                 break;
  535.  
  536.             case '.':    /* '../' is also parent dir */
  537.                 if (s[2] == '/')
  538.                     s = &s[2];
  539.                 
  540.                 break;
  541.         }
  542.     }
  543.  
  544.     len = strlen(s);
  545.  
  546.     if (len > 0)
  547.     {
  548.         if (s[0] == '$')
  549.         {
  550.             s++;
  551.             *scan_status = ENVPATH_SCAN_VAR;
  552.             if (s[0] == QUOTE)
  553.                 s++;
  554.         }
  555.         else if (s[0] == '?' && s[1] == '\0')
  556.         {
  557.             s++;
  558.             *scan_status = ENVPATH_SCAN_DEFPATH;
  559.         }
  560.         else
  561.         {
  562.             switch (s[len - 1])
  563.             {
  564.                 case '*':
  565.                     if (len > 1)
  566.                     {
  567.                         switch (s[len - 2])
  568.                         {
  569.                             case '*':
  570.                                 *scan_status = ENVPATH_SCAN_ALL;
  571.                                 s[len - 2] = '\0';
  572.                                 break;
  573.  
  574.                             default:
  575.                                 *scan_status = ENVPATH_SCAN_ONE;
  576.                                 s[len - 1] = '\0';
  577.                                 break;
  578.                         }
  579.                     }
  580.                     else /* len == 1 */
  581.                     {
  582.                         *scan_status = ENVPATH_SCAN_ONE;
  583.                         s[len - 1] = '\0';
  584.                     }
  585.  
  586.                     break;
  587.  
  588.                 case '?':
  589.                     if (len > 1)
  590.                     {
  591.                         switch (s[len - 2])
  592.                         {
  593.                             case '#':
  594.                                 *scan_status = ENVPATH_SCAN_ONE;
  595.                                 s[len - 2] = '\0';
  596.                                 break;
  597.  
  598.                             default:
  599.                                 *scan_status = ENVPATH_SCAN_NONE;
  600.                                 break;
  601.                         }
  602.                     }
  603.                     else
  604.                         *scan_status = ENVPATH_SCAN_NONE;
  605.  
  606.                     break;
  607.  
  608.                 case '>':
  609.                     if (len > 1)
  610.                     {
  611.                         switch (s[len - 2])
  612.                         {
  613.                             case '*':
  614.                                 *scan_status = ENVPATH_SCAN_ALL;
  615.                                 s[len - 2] = '\0';
  616.                                 break;
  617.  
  618.                             case '?':
  619.                                 if (len > 2)
  620.                                 {
  621.                                     switch (s[len - 3])
  622.                                     {
  623.                                         case '#':
  624.                                             *scan_status = ENVPATH_SCAN_ALL;
  625.                                             s[len -3] = '\0';
  626.                                             break;
  627.  
  628.                                         default:
  629.                                             *scan_status = ENVPATH_SCAN_NONE;
  630.                                             break;
  631.                                     }
  632.                                 }
  633.                                 else
  634.                                     *scan_status = ENVPATH_SCAN_NONE;
  635.  
  636.                                 break;
  637.  
  638.                             default:
  639.                                 *scan_status = ENVPATH_SCAN_NONE;
  640.                                 break;
  641.                         }
  642.                     }
  643.                     else
  644.                         *scan_status = ENVPATH_SCAN_NONE;
  645.  
  646.                     break;
  647.  
  648.                 default:
  649.                     *scan_status = ENVPATH_SCAN_NONE;
  650.                     break;
  651.             }
  652.         }
  653.     }
  654.  
  655.     return(s);
  656. }
  657.  
  658. /*
  659.  * Alloc_EnvVarPath(). Alloc an EnvVarPath structure.
  660.  *
  661.  */
  662. struct EnvVarPath __regargs *Alloc_EnvVarPath(STRPTR varname, LONG size)
  663. {
  664.     struct EnvVarPath *p;
  665.  
  666.     if (p = AllocMem(sizeof(struct EnvVarPath), MEMF_ANY))
  667.     {
  668.         if ((size >= 2*sizeof(STRPTR) + 1L) && (p->storage.buffer = AllocMem(size, MEMF_ANY)))
  669.         {
  670.             if (p->name = AllocMem(strlen(varname) + 1, MEMF_ANY))
  671.             {
  672.                 strcpy(p->name, varname);
  673.                 p->storage.strings[0] = NULL; /* init first entry */
  674.                 p->size = size;
  675.                 p->status = ENVPATH_BUFFER_EMPTY;
  676.                 p->defpath = NULL;
  677.                 p->pos = 0L;
  678.             }
  679.             else
  680.             {
  681.                 FreeMem(p->storage.buffer, size);
  682.                 FreeMem(p, sizeof(struct EnvVarPath));
  683.                 p = NULL;
  684.             }
  685.         }
  686.         else
  687.         {
  688.             FreeMem(p, sizeof(struct EnvVarPath));
  689.             p = NULL;
  690.         }
  691.     }
  692.  
  693.     return(p);
  694. }
  695.  
  696. /*
  697.  * Free_EnvVarPath. Frees an allocated EnvVarPath structure.
  698.  *
  699.  */
  700. VOID __regargs Free_EnvVarPath(struct EnvVarPath *p)
  701. {
  702.     if (p)
  703.     {
  704.         if (p->name) FreeMem(p->name, strlen(p->name) + 1);
  705.         if (p->storage.buffer) FreeMem(p->storage.buffer, p->size);
  706.         if (p->defpath)    FreeMem(p->defpath, strlen(p->defpath) + 1);
  707.         FreeMem(p, sizeof(struct EnvVarPath));
  708.         
  709.     }
  710. }
  711.  
  712. /*
  713.  * Init_EnvVarPath() inits an EnvVarPath structure provided by
  714.  * Alloc_EnvVarPath().
  715.  *
  716.  * deflt_path is an array of string pointers or a string pointer to be used
  717.  * if the specified environment variable doesn't exists or has zero length.
  718.  * 'mode' is one of ENVPATH_DEFSTR or ENPATH_DEFARR. If it is ENVPATH_DEFSTR
  719.  * then deflt_path is considered a string pointer, otherwise ENVPATH_DEFARR
  720.  * specifies that deflt_path is an array of string pointers.
  721.  *
  722.  */
  723. VOID __regargs Init_EnvVarPath(struct EnvVarPath *p, APTR deflt_path, LONG mode)
  724. {
  725.     if (p)
  726.     {
  727.         LONG Error;
  728.  
  729.         if ((mode & ENVPATH_PREPEND_PATH) == ENVPATH_PREPEND_PATH)
  730.             Insert_Path(p, deflt_path, mode);
  731.  
  732.         GetEnvPath(p->name, p->storage.buffer, p->size, &Error, ENVPATH_GETVAR);
  733.  
  734.         if ((mode & ENVPATH_APPEND_PATH) == ENVPATH_APPEND_PATH && (mode & ENVPATH_PREPEND_PATH) != ENVPATH_PREPEND_PATH && Error == ENVPATH_OK)
  735.             Insert_Path(p, deflt_path, mode);
  736.  
  737.         switch (Error)
  738.         {
  739.             case ENVPATH_OK:
  740.                 p->status = ENVPATH_BUFFER_COMPLETE;
  741.                 break;
  742.  
  743.             case ENVPATH_NOT_ENOUGH_ROOM:
  744.                 p->status = ENVPATH_BUFFER_FULL;
  745.                 break;
  746.  
  747.             case ENVPATH_NOT_ENOUGH_MEM:
  748.                 p->status = ENVPATH_BUFFER_TRUNC;
  749.                 break;
  750.  
  751.             case ENVPATH_VAR_NOT_FOUND:
  752.                 if (!(mode & (ENVPATH_PREPEND_PATH | ENVPATH_APPEND_PATH)))
  753.                     Insert_Path(p, deflt_path, mode);
  754.                 break;
  755.  
  756.             default:
  757.                 p->status = ENVPATH_BUFFER_EMPTY;
  758.                 break;
  759.         }
  760.     }
  761. }
  762.  
  763. /*
  764.    Insert_Path() adds a path to the p->buffer; mode is one of
  765.    ENVPATH_DEFARR or ENVPATH_DEFSTR, as in the function Init_EnvVarPath().
  766. */
  767. STATIC VOID __regargs Insert_Path(struct EnvVarPath *p, APTR path, LONG mode)
  768. {
  769.     LONG Error = ENVPATH_OK;
  770.  
  771.     if (path)
  772.     {
  773.         if ((mode & ENVPATH_DEFARR) == ENVPATH_DEFARR)
  774.         {
  775.             LONG i = 0L, l = 0L;
  776.             STRPTR *array = (STRPTR *) path, BufTmp, s;
  777.  
  778.             while (array[i])
  779.                 l += strlen(array[i++]) + 1L;
  780.  
  781.             if (BufTmp = AllocMem(++l, MEMF_ANY))
  782.             {
  783.                 s = BufTmp;
  784.                 *s = '\0';
  785.                 i = 0L;
  786.  
  787.                 while (array[i])
  788.                 {
  789.                     strcat(s, array[i++]);
  790.                     strcat(s, " ");
  791.                 }
  792.  
  793.                 GetEnvPath(BufTmp, p->storage.buffer, p->size, &Error, ENVPATH_DONTGETVAR);
  794.                 FreeMem(BufTmp, l);
  795.             }
  796.             else
  797.                 Error = ENVPATH_NOT_ENOUGH_MEM;
  798.         }
  799.         else
  800.             GetEnvPath(path, p->storage.buffer, p->size, &Error, ENVPATH_DONTGETVAR);
  801.  
  802.         switch(Error)
  803.         {
  804.             case ENVPATH_OK:
  805.                 p->status = ENVPATH_BUFFER_COMPLETE;
  806.                 break;
  807.  
  808.             case ENVPATH_NOT_ENOUGH_ROOM:
  809.                 p->status = ENVPATH_BUFFER_FULL;
  810.                 break;
  811.  
  812.             case ENVPATH_NOT_ENOUGH_MEM:
  813.                 p->status = ENVPATH_BUFFER_TRUNC;
  814.                 break;
  815.  
  816.             case ENVPATH_VAR_NOT_FOUND:
  817.                 p->status = ENVPATH_BUFFER_EMPTY;
  818.                 break;
  819.  
  820.             default:
  821.                 p->status = ENVPATH_BUFFER_EMPTY;
  822.                 break;
  823.         }
  824.     }
  825.     else
  826.         p->status = ENVPATH_BUFFER_EMPTY;
  827. }
  828.  
  829. /*
  830.  * Given a pointer to an initialized structure EnvVarPath, a filename
  831.  * and a buffer, EVP_FileSearch() returns the string pointer to the
  832.  * complete filename found. The returned string pointer is same of buffer.
  833.  * If the file isn't found then NULL is returned and buffer contains the
  834.  * empty string ("").
  835.  *
  836.  */
  837. STRPTR __regargs
  838. EVP_FileSearch(STRPTR filename, struct EnvVarPath *evp, UBYTE *buffer, LONG size)
  839. {
  840.     LONG i = 0L, len ;
  841.  
  842.     if (evp && buffer && size > 0L && filename && *filename)
  843.     {
  844.         *buffer = '\0';
  845.  
  846.         while (evp->storage.strings[i])
  847.         {
  848.             BPTR fh;
  849.  
  850.             if (DOSBase->dl_lib.lib_Version >= 37)
  851.             {
  852.                 SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s", evp->storage.strings[i]);
  853.                 AddPart(Path_TmpStr, filename, PATH_TMPLEN);
  854.                 len = strlen(Path_TmpStr);
  855.             }
  856.             else
  857.             {
  858.                 LONG l = strlen(evp->storage.strings[i]);
  859.  
  860.                 if (l > 0L && !strchr(filename, ':'))
  861.                 {
  862.                     UBYTE c = evp->storage.strings[i][l - 1];
  863.  
  864.                     len = SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s%s%s", evp->storage.strings[i],
  865.                         ((c != '/' && c != ':') ? "/" : ""), filename);
  866.                 }
  867.                 else
  868.                     len = SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s", filename);
  869.             }
  870.  
  871.             if (Path_TmpStr[0] && (fh = Open(Path_TmpStr, MODE_OLDFILE)) != DOSFALSE)
  872.             {
  873.                 /* note that the Lock() function would be faster than Open() to see if
  874.                                    a file exists or not, but in such case we should have to call
  875.                                    Examine() to discriminate files from directories. */
  876.  
  877.                 Close(fh);
  878.                 memcpy(buffer, Path_TmpStr, min(len, size));
  879.                 buffer[min(len, size - 1)] = '\0';
  880.             }
  881.  
  882.             if (*buffer)
  883.                 break;
  884.             else
  885.                 i++;
  886.         }
  887.     }
  888.     else
  889.     {
  890.         if (size > 0L)
  891.             buffer[0] = '\0';
  892.     }
  893.  
  894.     if (*buffer)
  895.         return(buffer);
  896.     else
  897.         return(NULL);
  898. }
  899.