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