- /*
- * cpvparser1.c - test code for ksh93 compound variable parsing
- *
- *
- * It basically reads the output of $ print -v ... # like this:
- * ---- snip ----
- * $ ksh93 -c 'compound c=( va=1 vb=hello ) ; print -v c'
- * (
- * va=1
- * vb=hello
- * )
- * ---- snip ----
- *
- * ToDo:
- * - arrays (indexed, sparse indexed and associative)
- * - multibyte characters
- *
- * Written by Roland Mainz <roland.mainz@nrubsig.org>
- */
- #include <stdlib.h>
- #include <stdbool.h>
- #include <string.h>
- #include <stdio.h>
- #include <ctype.h>
- #define MAX_NAME_VAL_SIZE 1024
- typedef struct cpv_name_val
- {
- const char *cpv_name;
- const char *cpv_value;
- } cpv_name_val;
- /* prototypes */
- static int cpv_read_cpv_header(const char **instr_ptr, size_t maxsize);
- static void cpv_free_name_val_data(cpv_name_val *cnv);
- static int cpv_parse_name_val(const char **instr_ptr, size_t maxsize, cpv_name_val *cpv_nv);
- static
- int cpv_read_cpv_header(const char **instr_ptr, size_t maxsize)
- {
- const char *s = *instr_ptr;
- skipspaces:
- s++;
- /*
- * skip POSIX-style '#' comments
- * (allowed since this is based on POSIX sh(1) syntax)
- */
- if (*s == '#') {
- s++;
- /* ignore everything until the end-of-line */
- while((*s != '\0') && (*s != '\n'))
- s++;
- goto skipspaces;
- }
- if (*s == '(') {
- *instr_ptr=++s;
- return 0;
- }
- return 1;
- }
- static
- int cpv_parse_name_val(const char **instr_ptr, size_t maxsize, cpv_name_val *cpv_nv)
- {
- char namebuff[maxsize+1];
- char valbuff[maxsize+1];
- const char *s = *instr_ptr;
- char *n; /* pointer in |namebuff| */
- char *v; /* pointer in |valbuff| */
- skipspaces:
- s++;
- /*
- * skip POSIX-style '#' comments
- * (allowed since this is based on POSIX sh(1) syntax)
- */
- if (*s == '#') {
- s++;
- /* ignore everything until the end-of-line */
- while((*s != '\0') && (*s != '\n'))
- s++;
- goto skipspaces;
- }
- if (*s == '\0') {
- "error: end-of-string, should not happen\n");
- return 1;
- }
- /* cpv == "( foo=bar blabla=text )"*/
- if (*s == ')') {
- return 1;
- }
- parse_varname:
- /*
- * start parsing variable name
- */
- /* variable names MUST start with a letter! */
- "cpv_parse_name_val: parser error, first char "
- "in variable name not isalpha(c=%c)\n",
- *s);
- return 1;
- }
- n = namebuff;
- *n++ = *s++;
- *n = '\0';
- /*
- * skip typed member varables
- * (e.g. "typeset ", "typeset -i ", "typeset -l -i2" etc.)
- */
- skip_typeset_options:
- s++;
- if (*s == '-') {
- s++;
- s++;
- goto skip_typeset_options;
- }
- goto parse_varname;
- }
- }
- /* handle '=' */
- if (*s != '=') {
- "parser error, expected '=', got '%c'.\n",
- *s);
- return 1;
- }
- s++; /* skip '=' */
- /*
- * start parsing variable value
- */
- bool in_doublequotes=false;
- bool in_singlequotes=false;
- v = valbuff;
- val_quotes:
- if (in_singlequotes) {
- while(*s != '\0') {
- if (*s == '\'') {
- in_singlequotes = false;
- s++;
- goto val_quotes;
- }
- if ((*s == '\\') && (*(s+1) != '\0')) {
- /*
- * fixme: should support \ooo octals,
- * \u[hex] unicode and \w[hex] wchar
- */
- s++;
- }
- *v++ = *s++;
- }
- }
- else if (in_doublequotes) {
- while(*s != '\0') {
- if (*s == '"') {
- in_doublequotes = false;
- s++;
- goto val_quotes;
- }
- if ((*s == '\\') && (*(s+1) != '\0')) {
- /*
- * fixme: should support \ooo octals,
- * \u[hex] unicode and \w[hex] wchar
- */
- s++;
- }
- *v++ = *s++;
- }
- }
- else
- {
- if (*s == '"') {
- in_doublequotes = true;
- s++;
- goto val_quotes;
- }
- if (*s == '\'') {
- in_singlequotes = true;
- s++;
- goto val_quotes;
- }
- if ((*s == '\\') && (*(s+1) != '\0')) {
- /*
- * fixme: should support \ooo octals,
- * \u[hex] unicode and \w[hex] wchar
- */
- s++;
- }
- *v++ = *s++;
- }
- }
- if (in_singlequotes) {
- "parsererror, still in single quotes "
- "at the end\n");
- return 1;
- }
- if (in_doublequotes) {
- "parser error, still in double quotes "
- "at the end\n");
- return 1;
- }
- *v = '\0';
- #if 0
- namebuff, valbuff);
- #endif
- cpv_nv->cpv_name = strdup(namebuff);
- cpv_nv->cpv_value = strdup(valbuff);
- if ((cpv_nv->cpv_name == NULL) || (cpv_nv->cpv_value == NULL)) {
- cpv_free_name_val_data(cpv_nv);
- "parser error, out of memory\n");
- return 2;
- }
- *instr_ptr = s;
- return 0;
- }
- void cpv_free_name_val_data(cpv_name_val *cnv)
- {
- if (!cnv)
- return;
- cnv->cpv_name = NULL;
- cnv->cpv_value = NULL;
- }
- int main(int ac, char *av[])
- {
- const char *str =
- " ( \n"
- "x=y1 chicken=wing xchicken=w\\\"ing qcount=\"one two\" sq1='foo \" x \" bar'"
- "\n # a comment x=y\n"
- "\n"
- " \n"
- "\t\n"
- "emptyval= \n"
- "emptyval2=\n"
- "emptyval3=''\n"
- " emptyval4="" \n"
- "aftercomment=yep\n"
- "typeset -i2 bintypedvar=1010\n"
- "typeset -u strtypedvar=UAUA\n"
- "integer lastvar=666 \n"
- "\n)";
- const char *s = str;
- int numcnv = 0;
- int i = 0;
- cpv_name_val cnv[256];
- if (cpv_read_cpv_header(&s, MAX_NAME_VAL_SIZE)) {
- return EXIT_FAILURE;
- }
- for (numcnv=0 ; cpv_parse_name_val(&s, MAX_NAME_VAL_SIZE, &cnv[numcnv]) == 0 ; numcnv++) {
- }
- for (i=0 ; i < numcnv ; i++) {
- }
- for (i=0 ; i < numcnv ; i++) {
- cpv_free_name_val_data(&cnv[i]);
- }
- return EXIT_SUCCESS;
- }
cpvparser1.c - test code for ksh93 compound variable parsing
Posted by Anonymous on Sat 18th Nov 2023 12:27
raw | new post
modification of post by Anonymous (view diff)
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.