- /*
 - * 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_cpy_header(const char **instr_ptr);
 - static void cpv_free_name_val_data(cpv_name_val *cnv);
 - static int cpv_parse_name_val(const char **instr_ptr, cpv_name_val *cpv_nv);
 - static
 - int cpv_read_cpy_header(const char **instr_ptr)
 - {
 - 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, cpv_name_val *cpv_nv)
 - {
 - char namebuff[MAX_NAME_VAL_SIZE];
 - char valbuff[MAX_NAME_VAL_SIZE];
 - 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') {
 - return 1;
 - }
 - /* cpv == "( foo=bar blabla=text )"*/
 - if (*s == ')') {
 - return 1;
 - }
 - parse_varname:
 - /*
 - * start parsing variable name
 - */
 - /* variable names MUST start with a letter! */
 - "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 != '=') {
 - *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) {
 - return 1;
 - }
 - if (in_doublequotes) {
 - return 1;
 - }
 - *v = '\0';
 - // (void)printf("name='%s', value='%s'\n", namebuff, valbuff);
 - 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);
 - return 2;
 - }
 - *instr_ptr = s;
 - return 0;
 - }
 - void cpv_free_name_val_data(cpv_name_val *cnv)
 - {
 - 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= "
 - "aftercomment=yep\n"
 - "typeset -i2 typedvar=1010\n"
 - "integer lastvar=666 \n"
 - "\n)";
 - const char *s = str;
 - int numcnv = 0;
 - int i = 0;
 - cpv_name_val cnv[256];
 - if (cpv_read_cpy_header(&s)) {
 - return EXIT_FAILURE;
 - }
 - for (numcnv=0 ; cpv_parse_name_val(&s, &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 11:56
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)
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.
 nrubsig.kpaste.net RSS