pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS


cpvparser1.c - test code for ksh93 compound variable parsing
Posted by Anonymous on Sat 18th Nov 2023 11:11
raw | new post
view followups (newest first): cpvparser1.c - test code for ksh93 compound variable parsing by Anonymous

  1. /*
  2.  * cpvparser1.c - test code for ksh93 compound variable parsing
  3.  *
  4.  *
  5.  * It basically reads the output of $ print -v ... # like this:
  6.  * ---- snip ----
  7.  * $ ksh93 -c 'compound c=( va=1 vb=hello ) ; print -v c'
  8.  * (
  9.  *        va=1
  10.  *        vb=hello
  11.  * )
  12.  * ---- snip ----
  13.  *
  14.  * ToDo:
  15.  * - typed member variables (compound c=(typeset -i num=4))
  16.  * - arrays (indexed, sparse indexed and associative)
  17.  * - multibyte characters
  18.  *
  19.  * Written by Roland Mainz <roland.mainz@nrubsig.org>
  20.  */
  21.  
  22. #include <stdlib.h>
  23. #include <stdbool.h>
  24. #include <string.h>
  25. #include <stdio.h>
  26. #include <ctype.h>
  27.  
  28. #define MAX_NAME_VAL_SIZE 1024
  29.  
  30. typedef struct cpv_name_val
  31. {
  32.         const char *cpv_name;
  33.         const char *cpv_value;
  34. } cpv_name_val;
  35.  
  36. /* prototypes */
  37. static void free_cpv_name_val_data(cpv_name_val *cnv);
  38. static int cpv_parse_name_val(const char **instr_ptr, cpv_name_val *cpv_nv);
  39.  
  40. static
  41. int cpv_parse_name_val(const char **instr_ptr, cpv_name_val *cpv_nv)
  42. {
  43.         char namebuff[MAX_NAME_VAL_SIZE];
  44.         char valbuff[MAX_NAME_VAL_SIZE];
  45.  
  46.         const char *instr = *instr_ptr;
  47.  
  48.         const char *s;
  49.         char *n;
  50.         char *v;
  51.  
  52.         s = instr;
  53.  
  54. skipspaces:
  55.         while((*s != '\0') && isspace(*s))
  56.                 s++;
  57.  
  58.         /*
  59.          * skip POSIX-style '#' comments
  60.          * (allowed since this is based on POSIX sh(1) syntax)
  61.          */
  62.         if (*s == '#') {
  63.                 s++;
  64.                 while((*s != '\0') && (*s != '\n'))
  65.                         s++;
  66.                 goto skipspaces;
  67.         }
  68.  
  69.         if (*s == '\0') {
  70.                 (void)fprintf(stderr, "end-of-string, should not happen\n");
  71.                 return 1;
  72.         }
  73.  
  74.         /* cpv == "( foo=bar blabla=text )"*/
  75.         if (*s == ')') {
  76.                 (void)fprintf(stderr, "end-of-cpv\n");
  77.                 return 1;
  78.         }
  79.  
  80.         /*
  81.          * start parsing variable name
  82.          */
  83.  
  84.         /*variable names MUST start with a letter! */
  85.         if (!isalpha(*s)) {
  86.                 (void)fprintf(stderr,
  87.                         "parser error, first char in variable not "
  88.                         "isalpha(c=%c)\n",
  89.                         *s);
  90.                 return 1;
  91.         }
  92.  
  93.         n = namebuff;
  94.         while((*s != '\0') && isalnum(*s))
  95.                 *n++ = *s++;
  96.         *n = '\0';
  97.         if (*s != '=') {
  98.                 (void)fprintf(stderr, "parser error, expected '=', got '%c'.\n",
  99.                         *s);
  100.                 return 1;
  101.         }
  102.  
  103.         s++; /* skip '=' */
  104.  
  105.         /*
  106.          * start parsing variable value
  107.          */
  108.         bool in_doublequotes=false;
  109.         bool in_singlequotes=false;
  110.         v = valbuff;
  111. val_quotes:
  112.         if (in_singlequotes) {
  113.                 while(*s != '\0') {
  114.                         if (*s == '\'') {
  115.                                 in_singlequotes = false;
  116.                                 s++;
  117.                                 goto val_quotes;
  118.                         }
  119.  
  120.                         if ((*s == '\\') && (*(s+1) != '\0')) {
  121.                                 /*
  122.                                  * fixme: should support \ooo octals,
  123.                                  * \u[hex] unicode and \w[hex] wchar
  124.                                  */
  125.                                 s++;
  126.                         }
  127.                         *v++ = *s++;
  128.                 }
  129.         }
  130.         else if (in_doublequotes) {
  131.                 while(*s != '\0') {
  132.                         if (*s == '"') {
  133.                                 in_doublequotes = false;
  134.                                 s++;
  135.                                 goto val_quotes;
  136.                         }
  137.  
  138.                         if ((*s == '\\') && (*(s+1) != '\0')) {
  139.                                 /*
  140.                                  * fixme: should support \ooo octals,
  141.                                  * \u[hex] unicode and \w[hex] wchar
  142.                                  */
  143.                                 s++;
  144.                         }
  145.  
  146.                         *v++ = *s++;
  147.                 }
  148.         }
  149.         else
  150.         {
  151.                 while((*s != '\0') && (!isspace(*s))) {
  152.                         if (*s == '"') {
  153.                                 in_doublequotes = true;
  154.                                 s++;
  155.                                 goto val_quotes;
  156.                         }
  157.  
  158.                         if (*s == '\'') {
  159.                                 in_singlequotes = true;
  160.                                 s++;
  161.                                 goto val_quotes;
  162.                         }
  163.  
  164.                         if ((*s == '\\') && (*(s+1) != '\0')) {
  165.                                 /*
  166.                                  * fixme: should support \ooo octals,
  167.                                  * \u[hex] unicode and \w[hex] wchar
  168.                                  */
  169.                                 s++;
  170.                         }
  171.                         *v++ = *s++;
  172.                 }
  173.         }
  174.  
  175.         if (in_singlequotes) {
  176.                 (void)fprintf(stderr, "parser error, still in single quotes at the end\n");
  177.                 return 1;
  178.         }
  179.         if (in_doublequotes) {
  180.                 (void)fprintf(stderr, "parser error, still in double quotes at the end\n");
  181.                 return 1;
  182.         }
  183.  
  184.         *v = '\0';
  185.  
  186. //      (void)printf("name='%s', value='%s'\n", namebuff, valbuff);
  187.  
  188.         cpv_nv->cpv_name   = strdup(namebuff);
  189.         cpv_nv->cpv_value  = strdup(valbuff);
  190.  
  191.         if ((cpv_nv->cpv_name == NULL) || (cpv_nv->cpv_value == NULL)) {
  192.                 free_cpv_name_val_data(cpv_nv);
  193.                 (void)fprintf(stderr, "parser error, out of memory\n");
  194.                 return 2;
  195.         }
  196.  
  197.         *instr_ptr = s;
  198.  
  199.         return 0;
  200. }
  201.  
  202. void free_cpv_name_val_data(cpv_name_val *cnv)
  203. {
  204.         free((void *)cnv->cpv_name);
  205.         free((void *)cnv->cpv_value);
  206.         cnv->cpv_name = NULL;
  207.         cnv->cpv_value = NULL;
  208. }
  209.  
  210. int main(int ac, char *av[])
  211. {
  212.         const char *str =
  213.                 "x=y1 chicken=wing xchicken=w\\\"ing qcount=\"one two\" sq1='foo \" x \" bar'"
  214.                 "\n  # a comment x=y\n"
  215.                 "\n"
  216.                 " \n"
  217.                 "\t\n"
  218.                 "emptyval= "
  219.                 "aftercomment=yep";
  220.         const char *s = str;
  221.         int i = 0;
  222.         cpv_name_val cnv[256];
  223.  
  224.         for (i=0 ; cpv_parse_name_val(&s, &cnv[i]) == 0 ; i++) {
  225.                 (void)printf("name='%s', value='%s'\n", cnv[i].cpv_name, cnv[i].cpv_value);
  226.         }
  227.  
  228.         return EXIT_SUCCESS;
  229. }

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at