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:32
raw | new post
view followups (newest first): cpvparser1.c - test code for ksh93 compound variable parsing by Anonymous
modification of post by Anonymous (view diff)

  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 int cpv_read_cpy_header(const char **instr_ptr);
  38. static void cpv_free_name_val_data(cpv_name_val *cnv);
  39. static int cpv_parse_name_val(const char **instr_ptr, cpv_name_val *cpv_nv);
  40.  
  41. static
  42. int cpv_read_cpy_header(const char **instr_ptr)
  43. {
  44.         const char *s = *instr_ptr;
  45.  
  46. skipspaces:
  47.         while((*s != '\0') && isspace(*s))
  48.                 s++;
  49.  
  50.         /*
  51.          * skip POSIX-style '#' comments
  52.          * (allowed since this is based on POSIX sh(1) syntax)
  53.          */
  54.         if (*s == '#') {
  55.                 s++;
  56.                 /* ignore everything until the end-of-line */
  57.                 while((*s != '\0') && (*s != '\n'))
  58.                         s++;
  59.                 goto skipspaces;
  60.         }
  61.  
  62.         if (*s == '(') {
  63.                 *instr_ptr=++s;
  64.                 (void)fprintf(stderr, "begin-of-cpv\n");
  65.                 return 0;
  66.         }
  67.  
  68.         (void)fprintf(stderr, "cpv_read_cpy_header: end-of-string, should not happen\n");
  69.         return 1;
  70. }
  71.  
  72. static
  73. int cpv_parse_name_val(const char **instr_ptr, cpv_name_val *cpv_nv)
  74. {
  75.         char namebuff[MAX_NAME_VAL_SIZE];
  76.         char valbuff[MAX_NAME_VAL_SIZE];
  77.  
  78.         const char *s = *instr_ptr;
  79.  
  80.         char *n; /* pointer in |namebuff| */
  81.         char *v; /* pointer in |valbuff| */
  82.  
  83. skipspaces:
  84.         while((*s != '\0') && isspace(*s))
  85.                 s++;
  86.  
  87.         /*
  88.          * skip POSIX-style '#' comments
  89.          * (allowed since this is based on POSIX sh(1) syntax)
  90.          */
  91.         if (*s == '#') {
  92.                 s++;
  93.                 /* ignore everything until the end-of-line */
  94.                 while((*s != '\0') && (*s != '\n'))
  95.                         s++;
  96.                 goto skipspaces;
  97.         }
  98.  
  99.         if (*s == '\0') {
  100.                 (void)fprintf(stderr, "end-of-string, should not happen\n");
  101.                 return 1;
  102.         }
  103.  
  104.         /* cpv == "( foo=bar blabla=text )"*/
  105.         if (*s == ')') {
  106.                 (void)fprintf(stderr, "end-of-cpv\n");
  107.                 return 1;
  108.         }
  109.  
  110.         /*
  111.          * start parsing variable name
  112.          */
  113.  
  114.         /* variable names MUST start with a letter! */
  115.         if (!isalpha(*s)) {
  116.                 (void)fprintf(stderr,
  117.                         "parser error, first char in variable not "
  118.                         "isalpha(c=%c)\n",
  119.                         *s);
  120.                 return 1;
  121.         }
  122.  
  123.         n = namebuff;
  124.         while((*s != '\0') && isalnum(*s))
  125.                 *n++ = *s++;
  126.         *n = '\0';
  127.  
  128.         /* handle '=' */
  129.         if (*s != '=') {
  130.                 (void)fprintf(stderr, "parser error, expected '=', got '%c'.\n",
  131.                         *s);
  132.                 return 1;
  133.         }
  134.  
  135.         s++; /* skip '=' */
  136.  
  137.         /*
  138.          * start parsing variable value
  139.          */
  140.         bool in_doublequotes=false;
  141.         bool in_singlequotes=false;
  142.         v = valbuff;
  143. val_quotes:
  144.         if (in_singlequotes) {
  145.                 while(*s != '\0') {
  146.                         if (*s == '\'') {
  147.                                 in_singlequotes = false;
  148.                                 s++;
  149.                                 goto val_quotes;
  150.                         }
  151.  
  152.                         if ((*s == '\\') && (*(s+1) != '\0')) {
  153.                                 /*
  154.                                  * fixme: should support \ooo octals,
  155.                                  * \u[hex] unicode and \w[hex] wchar
  156.                                  */
  157.                                 s++;
  158.                         }
  159.                         *v++ = *s++;
  160.                 }
  161.         }
  162.         else if (in_doublequotes) {
  163.                 while(*s != '\0') {
  164.                         if (*s == '"') {
  165.                                 in_doublequotes = false;
  166.                                 s++;
  167.                                 goto val_quotes;
  168.                         }
  169.  
  170.                         if ((*s == '\\') && (*(s+1) != '\0')) {
  171.                                 /*
  172.                                  * fixme: should support \ooo octals,
  173.                                  * \u[hex] unicode and \w[hex] wchar
  174.                                  */
  175.                                 s++;
  176.                         }
  177.  
  178.                         *v++ = *s++;
  179.                 }
  180.         }
  181.         else
  182.         {
  183.                 while((*s != '\0') && (!isspace(*s))) {
  184.                         if (*s == '"') {
  185.                                 in_doublequotes = true;
  186.                                 s++;
  187.                                 goto val_quotes;
  188.                         }
  189.  
  190.                         if (*s == '\'') {
  191.                                 in_singlequotes = true;
  192.                                 s++;
  193.                                 goto val_quotes;
  194.                         }
  195.  
  196.                         if ((*s == '\\') && (*(s+1) != '\0')) {
  197.                                 /*
  198.                                  * fixme: should support \ooo octals,
  199.                                  * \u[hex] unicode and \w[hex] wchar
  200.                                  */
  201.                                 s++;
  202.                         }
  203.                         *v++ = *s++;
  204.                 }
  205.         }
  206.  
  207.         if (in_singlequotes) {
  208.                 (void)fprintf(stderr, "parser error, still in single quotes at the end\n");
  209.                 return 1;
  210.         }
  211.         if (in_doublequotes) {
  212.                 (void)fprintf(stderr, "parser error, still in double quotes at the end\n");
  213.                 return 1;
  214.         }
  215.  
  216.         *v = '\0';
  217.  
  218. //      (void)printf("name='%s', value='%s'\n", namebuff, valbuff);
  219.  
  220.         cpv_nv->cpv_name   = strdup(namebuff);
  221.         cpv_nv->cpv_value  = strdup(valbuff);
  222.  
  223.         if ((cpv_nv->cpv_name == NULL) || (cpv_nv->cpv_value == NULL)) {
  224.                 cpv_free_name_val_data(cpv_nv);
  225.                 (void)fprintf(stderr, "parser error, out of memory\n");
  226.                 return 2;
  227.         }
  228.  
  229.         *instr_ptr = s;
  230.  
  231.         return 0;
  232. }
  233.  
  234. void cpv_free_name_val_data(cpv_name_val *cnv)
  235. {
  236.         free((void *)cnv->cpv_name);
  237.         free((void *)cnv->cpv_value);
  238.         cnv->cpv_name = NULL;
  239.         cnv->cpv_value = NULL;
  240. }
  241.  
  242. int main(int ac, char *av[])
  243. {
  244.         const char *str =
  245.                 " ( \n"
  246.                 "x=y1 chicken=wing xchicken=w\\\"ing qcount=\"one two\" sq1='foo \" x \" bar'"
  247.                 "\n  # a comment x=y\n"
  248.                 "\n"
  249.                 " \n"
  250.                 "\t\n"
  251.                 "emptyval= "
  252.                 "aftercomment=yep"
  253.                 "\n)";
  254.         const char *s = str;
  255.         int numcnv = 0;
  256.         int i = 0;
  257.         cpv_name_val cnv[256];
  258.  
  259.         (void)fputs("# parsing...\n", stderr);
  260.         if (cpv_read_cpy_header(&s)) {
  261.                 (void)fprintf(stderr, "cpv_read_cpy_header failed\n");
  262.                 return EXIT_FAILURE;
  263.         }
  264.  
  265.         for (numcnv=0 ; cpv_parse_name_val(&s, &cnv[numcnv]) == 0 ; numcnv++) {
  266.         }
  267.  
  268.         (void)fputs("# data:\n", stderr);
  269.         for (i=0 ; i < numcnv ; i++) {
  270.                 (void)printf("name='%s', value='%s'\n", cnv[i].cpv_name, cnv[i].cpv_value);
  271.         }
  272.  
  273.         (void)fputs("# free memory ...\n", stderr);
  274.         for (i=0 ; i < numcnv ; i++) {
  275.                 cpv_free_name_val_data(&cnv[i]);
  276.         }
  277.  
  278.         (void)fputs("# done.\n", stderr);
  279.  
  280.         return EXIT_SUCCESS;
  281. }

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