Advertisement
gocha

Expand environment variables in text (bash style)

Sep 19th, 2013
131
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2.  * Expand environment variables in text (bash style)
  3.  * @author gocha <http://twitter.com/gochaism> (I release it into public domain, though)
  4.  * FYI: Windows have ExpandEnvironmentStrings function for a similar purpose.
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <malloc.h>
  10. #include <ctype.h>
  11.  
  12. #ifdef HAVE_STDBOOL_H
  13. #  include <stdbool.h>
  14. #else
  15. #  ifndef HAVE__BOOL
  16. #    ifdef __cplusplus
  17.        typedef bool _Bool;
  18. #    else
  19. #      define _Bool signed char
  20. #    endif
  21. #  endif
  22. #  define bool _Bool
  23. #  define false 0
  24. #  define true 1
  25. #  define __bool_true_false_are_defined 1
  26. #endif
  27.  
  28. /**
  29.  * Expand environment variables in a string (bash style)
  30.  * @param str Input path string.
  31.  * @param outputStr Output path string buffer.
  32.  * @param bufferSize Size of the output buffer in chars. (includes null character)
  33.  * @return Number of characters written to the buffer (excludes null character). Returns -1 if a fatal error occurred.
  34.  */
  35. int ExpandEnvironmentVariables(const char *str, char *outputStr, int bufferSize)
  36. {
  37.     int inIndex = 0;
  38.     int outIndex = 0;
  39.     int varStartIndex = -1;
  40.     bool isInVariable = false;
  41.     bool hasParenthesis = false;
  42.     char *varName = NULL;
  43.     char *varValue = NULL;
  44.     int varNameLength = 0;
  45.     int varValueLength = 0;
  46.     unsigned char cIn, cNext;
  47.  
  48.     do
  49.     {
  50.         // check output buffer size
  51.         if (outIndex >= bufferSize)
  52.         {
  53.             outputStr[bufferSize - 1] = '\0';
  54.             outIndex = bufferSize + 1;
  55.             break;
  56.         }
  57.  
  58.         // read a character
  59.         cIn = (unsigned char) str[inIndex];
  60.         cNext = (cIn != '\0') ? (unsigned char) str[inIndex + 1] : '\0';
  61.  
  62.         if (isInVariable)
  63.         {
  64.             // check if we are still in a variable
  65.             if (hasParenthesis)
  66.             {
  67.                 isInVariable = (cIn != '}');
  68.  
  69.                 if (cIn == '\0')
  70.                 {
  71.                     fprintf(stderr, "error: missing closing parenthesis.\n");
  72.                     outputStr[outIndex] = '\0';
  73.                     return -1;
  74.                 }
  75.                 else if (cIn == '{')
  76.                 {
  77.                     fprintf(stderr, "error: bad substitution.\n");
  78.                     outputStr[outIndex] = '\0';
  79.                     return -1;
  80.                 }
  81.             }
  82.             else
  83.             {
  84.                 // check for the pattern [0-9]+|[A-Za-z_][0-9A-Za-z_]*
  85.                 if ((isdigit(str[varStartIndex]) != 0))
  86.                 {
  87.                     isInVariable = (isdigit(cIn) != 0);
  88.                 }
  89.                 else
  90.                 {
  91.                     isInVariable = ((isalnum(cIn) != 0) || cIn == '_');
  92.                 }
  93.             }
  94.  
  95.             // reached to end of variable
  96.             if (!isInVariable)
  97.             {
  98.                 // get variable name
  99.                 varNameLength = inIndex - varStartIndex;
  100.                 varName = (char*) malloc(varNameLength + 1);
  101.                 memcpy(varName, &str[varStartIndex], varNameLength);
  102.                 varName[varNameLength] = '\0';
  103.  
  104.                 if (varName[0] != '\0')
  105.                 {
  106.                     // expand a variable
  107.                     varValue = getenv(varName);
  108.                     if (varValue != NULL)
  109.                     {
  110.                         varValueLength = strlen(varValue);
  111.                         if (outIndex + varValueLength <= bufferSize)
  112.                         {
  113.                             memcpy(&outputStr[outIndex], varValue, varValueLength);
  114.                             outIndex += varValueLength;
  115.                         }
  116.                         else
  117.                         {
  118.                             memcpy(&outputStr[outIndex], varValue, bufferSize - outIndex);
  119.                             outIndex = bufferSize;
  120.                         }
  121.  
  122.                         if (outIndex == bufferSize)
  123.                         {
  124.                             outputStr[bufferSize - 1] = '\0';
  125.                             outIndex = bufferSize + 1;
  126.                             break;
  127.                         }
  128.                     }
  129.                     else
  130.                     {
  131.                         fprintf(stderr, "error: ${%s} is not defined.\n", varName);
  132.                         outputStr[outIndex] = '\0';
  133.                         return -1;
  134.                     }
  135.  
  136.                     if (!hasParenthesis)
  137.                     {
  138.                         // redo the same character
  139.                         inIndex--;
  140.                         continue;
  141.                     }
  142.                 }
  143.                 else
  144.                 {
  145.                     // not a variable
  146.                     if (hasParenthesis)
  147.                     {
  148.                         fprintf(stderr, "error: variable name must not be empty.\n");
  149.                         outputStr[outIndex] = '\0';
  150.                         return -1;
  151.                     }
  152.                     else
  153.                     {
  154.                         outputStr[outIndex] = '$';
  155.                         outIndex++;
  156.  
  157.                         if (outIndex < bufferSize)
  158.                         {
  159.                             outputStr[outIndex] = cIn;
  160.                             outIndex++;
  161.                         }
  162.                     }
  163.                 }
  164.             }
  165.         }
  166.         else
  167.         {
  168.             if (cIn == '$')
  169.             {
  170.                 // start of a variable
  171.                 isInVariable = true;
  172.  
  173.                 // check if it has a parenthesis
  174.                 if (cNext == '{')
  175.                 {
  176.                     hasParenthesis = true;
  177.                     inIndex++;
  178.                 }
  179.                 else
  180.                 {
  181.                     hasParenthesis = false;
  182.                 }
  183.                 varStartIndex = inIndex + 1;
  184.             }
  185.             else
  186.             {
  187.                 // plain string
  188.                 outputStr[outIndex] = cIn;
  189.                 outIndex++;
  190.             }
  191.         }
  192.  
  193. #ifdef MS932_SUPPORT
  194.         // check for the lead-byte of MS932 (Windows-31J)
  195.         if ((cIn >= 0x81 && cIn <= 0x9f) || (cIn >= 0xe0 && cIn <= 0xfc))
  196.         {
  197.             // check for the trailer-byte as well
  198.             if ((cNext >= 0x40 && cNext <= 0x7e) || (cNext >= 0x80 && cNext <= 0xfc))
  199.             {
  200.                 if (!isInVariable)
  201.                 {
  202.                     if (outIndex + 1 < bufferSize)
  203.                     {
  204.                         outputStr[outIndex] = cNext;
  205.                     }
  206.                     else
  207.                     {
  208.                         outputStr[outIndex - 1] = '\0';
  209.                     }
  210.                     outIndex++;
  211.                 }
  212.                 inIndex++;
  213.             }
  214.         }
  215. #endif
  216.     } while (str[inIndex++] != '\0');
  217.     return outIndex - 1;
  218. }
  219.  
  220. // test routine
  221. int main(int argc, char *argv[])
  222. {
  223.     char s[4096];
  224.     char *pat;
  225.     int ret;
  226.  
  227.     pat = "HOME";
  228.     ret = ExpandEnvironmentVariables(pat, s, sizeof(s));
  229.     printf("\"%s\" -> \"%s\" (%d)\n\n", pat, s, ret);
  230.  
  231.     pat = "$HOME";
  232.     ret = ExpandEnvironmentVariables(pat, s, sizeof(s));
  233.     printf("\"%s\" -> \"%s\" (%d)\n\n", pat, s, ret);
  234.  
  235.     pat = "${HOME}";
  236.     ret = ExpandEnvironmentVariables(pat, s, sizeof(s));
  237.     printf("\"%s\" -> \"%s\" (%d)\n\n", pat, s, ret);
  238.  
  239.     pat = "${HOME!}";
  240.     ret = ExpandEnvironmentVariables(pat, s, sizeof(s));
  241.     printf("\"%s\" -> \"%s\" (%d)\n\n", pat, s, ret);
  242.  
  243.     pat = "$HOME!";
  244.     ret = ExpandEnvironmentVariables(pat, s, sizeof(s));
  245.     printf("\"%s\" -> \"%s\" (%d)\n\n", pat, s, ret);
  246.  
  247.     pat = "$HOME$HOME";
  248.     ret = ExpandEnvironmentVariables(pat, s, sizeof(s));
  249.     printf("\"%s\" -> \"%s\" (%d)\n\n", pat, s, ret);
  250.  
  251.     pat = "$123ABC";
  252.     ret = ExpandEnvironmentVariables(pat, s, sizeof(s));
  253.     printf("\"%s\" -> \"%s\" (%d)\n\n", pat, s, ret);
  254.  
  255.     pat = "";
  256.     ret = ExpandEnvironmentVariables(pat, s, sizeof(s));
  257.     printf("\"%s\" -> \"%s\" (%d)\n\n", pat, s, ret);
  258.  
  259.     pat = "$";
  260.     ret = ExpandEnvironmentVariables(pat, s, sizeof(s));
  261.     printf("\"%s\" -> \"%s\" (%d)\n\n", pat, s, ret);
  262.  
  263.     pat = "${";
  264.     ret = ExpandEnvironmentVariables(pat, s, sizeof(s));
  265.     printf("\"%s\" -> \"%s\" (%d)\n\n", pat, s, ret);
  266.  
  267.     pat = "${{";
  268.     ret = ExpandEnvironmentVariables(pat, s, sizeof(s));
  269.     printf("\"%s\" -> \"%s\" (%d)\n\n", pat, s, ret);
  270.  
  271.     pat = "$}";
  272.     ret = ExpandEnvironmentVariables(pat, s, sizeof(s));
  273.     printf("\"%s\" -> \"%s\" (%d)\n\n", pat, s, ret);
  274.  
  275.     pat = "$NOT_DEFINED";
  276.     ret = ExpandEnvironmentVariables(pat, s, 8);
  277.     printf("\"%s\" -> \"%s\" (%d)\n\n", pat, s, ret);
  278.  
  279.     pat = "ABCDEFG$HOME";
  280.     ret = ExpandEnvironmentVariables(pat, s, 8);
  281.     printf("\"%s\" -> \"%s\" (%d)\n\n", pat, s, ret);
  282.  
  283.     return 0;
  284. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement