home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / octa21fs.zip / octave / kpathsea / variable.c < prev    next >
C/C++ Source or Header  |  2000-01-15  |  7KB  |  249 lines

  1. /* variable.c: variable expansion.
  2.  
  3. Copyright (C) 1993, 94, 95, 96 Karl Berry.
  4.  
  5. This library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Library General Public
  7. License as published by the Free Software Foundation; either
  8. version 2 of the License, or (at your option) any later version.
  9.  
  10. This library is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13. Library General Public License for more details.
  14.  
  15. You should have received a copy of the GNU Library General Public
  16. License along with this library; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  18.  
  19. #include <kpathsea/config.h>
  20.  
  21. #include <kpathsea/c-ctype.h>
  22. #include <kpathsea/cnf.h>
  23. #include <kpathsea/fn.h>
  24. #include <kpathsea/variable.h>
  25.  
  26.  
  27. /* Here's the simple one, when a program just wants a value.  */
  28.  
  29. string
  30. kpse_var_value P1C(const_string, var)
  31. {
  32.   string ret = getenv (var);
  33.  
  34.   if (!ret)
  35.     ret = kpse_cnf_get (var);
  36.   
  37.   if (ret)
  38.     ret = kpse_var_expand (ret);
  39.  
  40. #ifdef KPSE_DEBUG
  41.   if (KPSE_DEBUG_P (KPSE_DEBUG_VARS))
  42.     DEBUGF2("variable: %s = %s\n", var, ret ? ret : "(nil)");
  43. #endif
  44.  
  45.   return ret;
  46. }
  47.  
  48. /* We have to keep track of variables being expanded, otherwise
  49.    constructs like TEXINPUTS = $TEXINPUTS result in an infinite loop.
  50.    (Or indirectly recursive variables, etc.)  Our simple solution is to
  51.    add to a list each time an expansion is started, and check the list
  52.    before expanding.  */
  53.  
  54. typedef struct {
  55.   const_string var;
  56.   boolean expanding;
  57. } expansion_type;
  58. static expansion_type *expansions; /* The sole variable of this type.  */
  59. static unsigned expansion_len = 0;
  60.  
  61. static void
  62. expanding P2C(const_string, var,  boolean, xp)
  63. {
  64.   unsigned e;
  65.   for (e = 0; e < expansion_len; e++) {
  66.     if (STREQ (expansions[e].var, var)) {
  67.       expansions[e].expanding = xp;
  68.       return;
  69.     }
  70.   }
  71.  
  72.   /* New variable, add it to the list.  */
  73.   expansion_len++;
  74.   XRETALLOC (expansions, expansion_len, expansion_type);
  75.   expansions[expansion_len - 1].var = xstrdup (var);
  76.   expansions[expansion_len - 1].expanding = xp;
  77. }
  78.  
  79.  
  80. /* Return whether VAR is currently being expanding.  */
  81.  
  82. static boolean
  83. expanding_p P1C(const_string, var)
  84. {
  85.   unsigned e;
  86.   for (e = 0; e < expansion_len; e++) {
  87.     if (STREQ (expansions[e].var, var))
  88.       return expansions[e].expanding;
  89.   }
  90.   
  91.   return false;
  92. }
  93.  
  94. /* Append the result of value of `var' to EXPANSION, where `var' begins
  95.    at START and ends at END.  If `var' is not set, do not complain.
  96.    This is a subroutine for the more complicated expansion function.  */
  97.  
  98. static void
  99. expand P3C(fn_type *, expansion,  const_string, start,  const_string, end)
  100. {
  101.   string value;
  102.   unsigned len = end - start + 1;
  103.   string var = xmalloc (len + 1);
  104.   strncpy (var, start, len);
  105.   var[len] = 0;
  106.   
  107.   if (expanding_p (var)) {
  108.     WARNING1 ("kpathsea: variable `%s' references itself (eventually)", var);
  109.   } else {
  110.     /* Check for an environment variable.  */
  111.     value = getenv (var);
  112.  
  113.     /* If no envvar, check the config files.  */
  114.     if (!value)
  115.       value = kpse_cnf_get (var);
  116.  
  117.     if (value) {
  118.       expanding (var, true);
  119.       value = kpse_var_expand (value);
  120.       expanding (var, false);
  121.       fn_grow (expansion, value, strlen (value));
  122.       free (value);
  123.     }
  124.  
  125.     free (var);
  126.   }
  127. }
  128.  
  129. /* Can't think of when it would be useful to change these (and the
  130.    diagnostic messages assume them), but ... */
  131. #ifndef IS_VAR_START /* starts all variable references */
  132. #define IS_VAR_START(c) ((c) == '$')
  133. #endif
  134. #ifndef IS_VAR_CHAR  /* variable name constituent */
  135. #define IS_VAR_CHAR(c) (ISALNUM (c) || (c) == '_')
  136. #endif
  137. #ifndef IS_VAR_BEGIN_DELIMITER /* start delimited variable name (after $) */
  138. #define IS_VAR_BEGIN_DELIMITER(c) ((c) == '{')
  139. #endif
  140. #ifndef IS_VAR_END_DELIMITER
  141. #define IS_VAR_END_DELIMITER(c) ((c) == '}')
  142. #endif
  143.  
  144.  
  145. /* Maybe we should support some or all of the various shell ${...}
  146.    constructs, especially ${var-value}.  */
  147.  
  148. string
  149. kpse_var_expand P1C(const_string, src)
  150. {
  151.   const_string s;
  152.   string ret;
  153.   fn_type expansion;
  154.   expansion = fn_init ();
  155.   
  156.   /* Copy everything but variable constructs.  */
  157.   for (s = src; *s; s++) {
  158.     if (IS_VAR_START (*s)) {
  159.       s++;
  160.  
  161.       /* Three cases: `$VAR', `${VAR}', `$<anything-else>'.  */
  162.       if (IS_VAR_CHAR (*s)) {
  163.         /* $V: collect name constituents, then expand.  */
  164.         const_string var_end = s;
  165.  
  166.         do {
  167.           var_end++;
  168.         } while (IS_VAR_CHAR (*var_end));
  169.  
  170.         var_end--; /* had to go one past */
  171.         expand (&expansion, s, var_end);
  172.         s = var_end;
  173.  
  174.       } else if (IS_VAR_BEGIN_DELIMITER (*s)) {
  175.         /* ${: scan ahead for matching delimiter, then expand.  */
  176.         const_string var_end = ++s;
  177.  
  178.         while (*var_end && !IS_VAR_END_DELIMITER (*var_end))
  179.           var_end++;
  180.  
  181.         if (! *var_end) {
  182.           WARNING1 ("%s: No matching } for ${", src);
  183.           s = var_end - 1; /* will incr to null at top of loop */
  184.         } else {
  185.           expand (&expansion, s, var_end - 1);
  186.           s = var_end; /* will incr past } at top of loop*/
  187.         }
  188.  
  189.       } else {
  190.         /* $<something-else>: error.  */
  191.         WARNING2 ("%s: Unrecognized variable construct `$%c'", src, *s);
  192.         /* Just ignore those chars and keep going.  */
  193.       }
  194.     } else
  195.      fn_1grow (&expansion, *s);
  196.   }
  197.   fn_1grow (&expansion, 0);
  198.           
  199.   ret = FN_STRING (expansion);
  200.   return ret;
  201. }
  202.  
  203. #ifdef TEST
  204.  
  205. static void
  206. test_var (string test, string right_answer)
  207. {
  208.   string result = kpse_var_expand (test);
  209.   
  210.   printf ("expansion of `%s'\t=> %s", test, result);
  211.   if (!STREQ (result, right_answer))
  212.     printf (" [should be `%s']", right_answer);
  213.   putchar ('\n');
  214. }
  215.  
  216.  
  217. int
  218. main ()
  219. {
  220.   test_var ("a", "a");
  221.   test_var ("$foo", "");
  222.   test_var ("a$foo", "a");
  223.   test_var ("$foo a", " a");
  224.   test_var ("a$foo b", "a b");
  225.  
  226.   xputenv ("FOO", "foo value");
  227.   test_var ("a$FOO", "afoo value");
  228.  
  229.   xputenv ("Dollar", "$");
  230.   test_var ("$Dollar a", "$ a");
  231.  
  232.   test_var ("a${FOO}b", "afoo valueb");
  233.   test_var ("a${}b", "ab");
  234.  
  235.   test_var ("$$", ""); /* and error */
  236.   test_var ("a${oops", "a"); /* and error */
  237.  
  238.   return 0;
  239. }
  240.  
  241. #endif /* TEST */
  242.  
  243.  
  244. /*
  245. Local variables:
  246. standalone-compile-command: "gcc -g -I. -I.. -DTEST variable.c kpathsea.a"
  247. End:
  248. */
  249.