From 9367e4392342164ceb100e6cce73aa807bf34f26 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Sun, 30 Sep 2012 20:34:52 +0000 Subject: [PATCH] Equipped frontend_pipes_xorriso.c with word parser code --- test/frontend_pipes_xorriso.c | 516 ++++++++++++++++++++++++++++++++-- 1 file changed, 495 insertions(+), 21 deletions(-) diff --git a/test/frontend_pipes_xorriso.c b/test/frontend_pipes_xorriso.c index 779ba98e..55e3ad75 100644 --- a/test/frontend_pipes_xorriso.c +++ b/test/frontend_pipes_xorriso.c @@ -1,6 +1,7 @@ /* Beefed-up example from man 2 pipe to illustrate how xorriso is to be used by frontend programs via two pipes. + Additionally there is a standalone implementation of Xorriso_parse_line(). Copyright 2012 Thomas Schmitt, Unaltered provided under BSD license. @@ -11,7 +12,7 @@ cc -g -o frontend_pipes_xorriso frontend_pipes_xorriso.c Usage: - ./frontend_pipes_xorriso [path_to_xorriso_binary] + ./frontend_pipes_xorriso [path_to_xorriso_binary | -h] */ @@ -21,11 +22,34 @@ #include #include #include +#include /* Local helpers of parent process */ -int await_all_replies(int fd, char *pending_mark); -int prompt_for_command(char *line, int line_size); + +struct parse_rules { /* Parsing_parameters. See xorriso.h Xorriso_parse_line */ + int do_parse; + char progname[1024]; + + char prefix[1024]; + char separators[256]; + int max_words; + int flag; +}; + +int parse_line(char *progname, char *line, + char *prefix, char *separators, int max_words, + int *argc, char ***argv, int flag); + +int dispose_parsed_words(int *argc, char ***argv); + +static int await_all_replies(int fd, char *pending_mark, + struct parse_rules *parse); + +static int prompt_for_command(char *line, int line_size, + struct parse_rules *parse); + +static int usage(); /* Parent and child */ @@ -35,8 +59,14 @@ int main(int argc, char *argv[]) pid_t cpid; char *xorriso_path = "/usr/bin/xorriso"; - if (argc > 1) + if (argc > 1) { + if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "-help") == 0 || + strcmp(argv[1], "--help") == 0) { + usage(); + exit(0); + } xorriso_path = argv[1]; + } if (pipe(command_pipe) == -1) { perror("pipe"); exit(1); } @@ -82,21 +112,25 @@ int main(int argc, char *argv[]) int mark_count = 0, ret; char pending_mark[16], line[4096]; + struct parse_rules parse; close(command_pipe[0]); /* Close unused read end */ close(reply_pipe[1]); /* Close unused write end */ + memset(&parse, 0, sizeof(parse)); /* Disable parsing as default */ + strcpy(parse.progname, argv[0]); + /* Dialog loop */ sprintf(pending_mark, "%d", mark_count); while (1) { /* Wait for pending mark and print all replies */ - ret = await_all_replies(reply_pipe[0], pending_mark); + ret = await_all_replies(reply_pipe[0], pending_mark, &parse); if (ret < 0) break; /* Prompt for command line */ - ret = prompt_for_command(line, sizeof(line)); + ret = prompt_for_command(line, sizeof(line), &parse); if (ret <= 0) break; @@ -130,10 +164,60 @@ int main(int argc, char *argv[]) } -/* Local helpers of parent process */ +/* ------------------- Local helpers of parent process -------------------- */ -int await_all_replies(int fd, char *pending_mark) +static int usage() +{ + static char helptext[][80] = { +"usage: frontend_pipes_xorriso [path_to_xorriso|-h]", +"", +"Forks a process that runs xorriso and communicates with it via two pipes.", +"The command pipe sends payload commands and -mark commands. The reply pipe", +"receives -pkt_output lines which it dispatches to stdout and stderr.", +"The communication between both processes is made synchronous by the parent", +"awaiting the -mark message of the child.", +"Optionally the reply lines can be parsed into words. This is initiated by", +"meta command", +" @parse [prefix [separators [max_words [flag]]]]", +"which sets the four parameters for a function equivalent to", +"Xorriso_parse_line() (see xorriso.h). All reply will then be parsed and", +"non-empty word arrays are displayed. Meta command", +" @noparse", +"ends this mode.", +"@END@" + }; + int i; + + for (i = 0; strcmp(helptext[i], "@END@") != 0; i++) + fprintf(stderr, "%s\n", helptext[i]); + return(1); +} + + +static int show_parsed(struct parse_rules *parse, char *line) +{ + int argc, ret = 0, i; + char **argv = NULL; + + if (!parse->do_parse) + return(2); + ret = parse_line(parse->progname, line, parse->prefix, parse->separators, + parse->max_words, &argc, &argv, parse->flag); + if (ret <= 0 || argc <= 0) + return(0); + fprintf(stderr, "-----------------------------------------------------\n"); + fprintf(stderr, "parse_line returns %d, argc = %d\n", ret, argc); + for (i = 0; i < argc; i++) + fprintf(stderr, "%2d : %s\n", i, argv[i]); + fprintf(stderr, "-----------------------------------------------------\n"); + dispose_parsed_words(&argc, &argv); /* release memory */ + return(1); +} + + +static int await_all_replies(int fd, char *pending_mark, + struct parse_rules *parse) { int count, remainder = 0; char buf[32769], *line, *npt; @@ -206,6 +290,11 @@ int await_all_replies(int fd, char *pending_mark) */ fprintf(stderr, "%s\n", line); } + + /* Parse line and show words */ + if (strlen(line) >= 5) + show_parsed(parse, line + 5); + line = npt + 1; } } @@ -213,23 +302,408 @@ int await_all_replies(int fd, char *pending_mark) } -int prompt_for_command(char *line, int line_size) +static int input_interpreter(char *line, struct parse_rules *parse) { - int l; + int argc, ret = 0; + char **argv = NULL; + + ret = parse_line(parse->progname, line, "", "", 6, &argc, &argv, 0); + if (ret <= 0 || argc <= 0) + return(0); + if (strcmp(argv[0], "@parse") == 0) { + parse->do_parse = 1; + parse->prefix[0] = 0; + if (argc > 1) + strcpy(parse->prefix, argv[1]); + parse->separators[0] = 0; + if (argc > 2) + strcpy(parse->separators, argv[2]); + parse->max_words = 0; + if (argc > 3) + sscanf(argv[3], "%d", &(parse->max_words)); + parse->max_words = 0; + if (argc > 4) + sscanf(argv[4], "%d", &(parse->flag)); + ret = 1; + } else if(strcmp(argv[0], "@noparse") == 0) { + parse->do_parse = 0; + ret = 1; + } else { + ret = 0; + } + dispose_parsed_words(&argc, &argv); /* release memory */ + return ret; +} + + +static int prompt_for_command(char *line, int line_size, + struct parse_rules *parse) +{ + int l, ret; char *line_res; - fprintf(stderr, "+++ Enter a command and its parameters :\n"); - line_res = fgets(line, line_size - 1, stdin); - if (line_res == NULL) - return(0); - l = strlen(line); - if (l == 0) { - line[0] = '\n'; - line[1] = 0; - } else if (line[l - 1] != '\n') { - line[l] = '\n'; - line[l + 1] = 0; + while (1) { + fprintf(stderr, "+++ Enter a command and its parameters :\n"); + line_res = fgets(line, line_size - 1, stdin); + if (line_res == NULL) + return(0); + l = strlen(line); + if (l == 0) { + line[0] = '\n'; + line[1] = 0; + } else if (line[l - 1] != '\n') { + line[l] = '\n'; + line[l + 1] = 0; + } + /* Interpret meta commands which begin by @ */ + ret = input_interpreter(line, parse); + if (ret == 0) + return(1); + if (ret < 0) + return(-1); } +} + + +/* -------- Line-to-word parser equivalent to Xorriso_parse_line() -------- */ + + +static int Sfile_sep_make_argv(char *progname, char *line, char *separators, + int max_words, int *argc, char ***argv, int flag); + + +int parse_line(char *progname, char *line, + char *prefix, char *separators, int max_words, + int *argc, char ***argv, int flag) +{ + int ret, bsl_mode; + char *to_parse; + + *argc = 0; + *argv = NULL; + + to_parse = line; + bsl_mode = (flag >> 1) & 15; + if (prefix[0]) { + if (strncmp(line, prefix, strlen(prefix)) == 0) { + to_parse = line + strlen(prefix); + } else { + ret = 2; goto ex; + } + } + ret = Sfile_sep_make_argv(progname, to_parse, separators, + max_words, argc, argv, + (!(flag & 32)) | 4 | (bsl_mode << 5)); + if (ret < 0) { + fprintf(stderr, + "%s : Severe lack of resources during command line parsing\n", + progname); + goto ex; + } + if (ret == 0) { + fprintf(stderr, + "%s : Incomplete quotation in %s line: %s\n", + progname, (flag & 32) ? "command" : "parsed", to_parse); + goto ex; + } +ex:; + if (ret <= 0) + Sfile_sep_make_argv("", "", "", 0, argc, argv, 2); /* release memory */ + return(ret); +} + + +int dispose_parsed_words(int *argc, char ***argv) +{ + Sfile_sep_make_argv("", "", "", 0, argc, argv, 2); return(1); } + +/* -------------- Some helpers copied from xorriso/sfile.c ----------------- */ + + +static int Sfile_destroy_argv(int *argc, char ***argv, int flag) +{ + int i; + + if(*argc>0 && *argv!=NULL){ + for(i=0;i<*argc;i++){ + if((*argv)[i]!=NULL) + free((*argv)[i]); + } + free((char *) *argv); + } + *argc= 0; + *argv= NULL; + return(1); +} + + +/* Converts backslash codes into single characters: + \a BEL 7 , \b BS 8 , \e ESC 27 , \f FF 12 , \n LF 10 , \r CR 13 , + \t HT 9 , \v VT 11 , \\ \ 92 + \[0-9][0-9][0-9] octal code , \x[0-9a-f][0-9a-f] hex code , + \cX control-x (ascii(X)-64) + @param upto maximum number of characters to examine for backslash. + The scope of a backslash (0 to 3 characters) is not affected. + @param eaten returns the difference in length between input and output + @param flag bit0= only determine *eaten, do not convert + bit1= allow to convert \000 to binary 0 +*/ +static int Sfile_bsl_interpreter(char *text, int upto, int *eaten, int flag) +{ + char *rpt, *wpt, num_text[8], wdummy[8]; + unsigned int num= 0; + + *eaten= 0; + wpt= text; + for(rpt= text; *rpt != 0 && rpt - text < upto; rpt++) { + if(flag & 1) + wpt= wdummy; + if(*rpt == '\\') { + rpt++; + (*eaten)++; + if(*rpt == 'a') { + *(wpt++)= 7; + } else if(*rpt == 'b') { + *(wpt++)= 8; + } else if(*rpt == 'e') { + *(wpt++)= 27; + } else if(*rpt == 'f') { + *(wpt++)= 12; + } else if(*rpt == 'n') { + *(wpt++)= 10; + } else if(*rpt == 'r') { + *(wpt++)= 13; + } else if(*rpt == 't') { + *(wpt++)= 9; + } else if(*rpt == 'v') { + *(wpt++)= 11; + } else if(*rpt == '\\') { + *(wpt++)= '\\'; + } else if(rpt[0] >= '0' && rpt[0] <= '7' && + rpt[1] >= '0' && rpt[1] <= '7' && + rpt[2] >= '0' && rpt[2] <= '7') { + num_text[0]= '0'; + num_text[1]= *(rpt + 0); + num_text[2]= *(rpt + 1); + num_text[3]= *(rpt + 2); + num_text[4]= 0; + sscanf(num_text, "%o", &num); + if((num > 0 || (flag & 2)) && num <= 255) { + rpt+= 2; + (*eaten)+= 2; + *(wpt++)= num; + } else + goto not_a_code; + } else if(rpt[0] == 'x' && + ((rpt[1] >= '0' && rpt[1] <= '9') || + (rpt[1] >= 'A' && rpt[1] <= 'F') || + (rpt[1] >= 'a' && rpt[1] <= 'f')) + && + ((rpt[2] >= '0' && rpt[2] <= '9') || + (rpt[2] >= 'A' && rpt[2] <= 'F') || + (rpt[2] >= 'a' && rpt[2] <= 'f')) + ) { + num_text[0]= *(rpt + 1); + num_text[1]= *(rpt + 2); + num_text[2]= 0; + sscanf(num_text, "%x", &num); + if(num > 0 && num <= 255) { + rpt+= 2; + (*eaten)+= 2; + *(wpt++)= num; + } else + goto not_a_code; + } else if(*rpt == 'c') { + if(rpt[1] > 64 && rpt[1] < 96) { + *(wpt++)= rpt[1] - 64; + rpt++; + (*eaten)++; + } else + goto not_a_code; + } else { +not_a_code:; + *(wpt++)= '\\'; + rpt--; + (*eaten)--; + } + } else + *(wpt++)= *rpt; + } + *wpt= *rpt; + return(1); +} + + +#define SfileadrL 4096 + +static int Sfile_sep_make_argv(char *progname, char *line, char *separators, + int max_words, int *argc, char ***argv, int flag) +/* + bit0= read progname as first argument from line + bit1= just release argument list argv and return + bit2= abort with return(0) if incomplete quotes are found + bit3= eventually prepend missing '-' to first argument read from line + bit4= like bit2 but only check quote completeness, do not allocate memory + bit5+6= interpretation of backslashes: + 0= no interpretation, leave unchanged + 1= only inside double quotes + 2= outside single quotes + 3= everywhere + bit7= append a NULL element to argv +*/ +{ + int i,pass,maxl=0,l,argzaehl=0,bufl,line_start_argc, bsl_mode, ret= 0, eaten; + char *cpt,*start; + char *buf= NULL; + + Sfile_destroy_argv(argc,argv,0); + if(flag&2) + {ret= 1; goto ex;} + + if(flag & 16) + flag|= 4; + bsl_mode= (flag >> 5) & 3; + + buf= calloc(strlen(line) + SfileadrL, 1); + if(buf == NULL) + {ret= -1; goto ex;} + for(pass=0;pass<2;pass++) { + cpt= line-1; + if(!(flag&1)){ + argzaehl= line_start_argc= 1; + if(pass==0) + maxl= strlen(progname); + else + strcpy((*argv)[0],progname); + } else { + argzaehl= line_start_argc= 0; + if(pass==0) maxl= 0; + } + while(*(++cpt)!=0){ + if(*separators) { + if(strchr(separators, *cpt) != NULL) + continue; + } else if(isspace(*cpt)) + continue; + start= cpt; + buf[0]= 0; + cpt--; + + if(max_words > 0 && argzaehl >= max_words && *cpt != 0) { + /* take uninterpreted up to the end */ + cpt+= strlen(cpt) - 1; + } + + while(*(++cpt)!=0) { + if(*separators) { + if(strchr(separators, *cpt) != NULL) + break; + } else if(isspace(*cpt)) + break; + if(*cpt=='"'){ + l= cpt-start; bufl= strlen(buf); + if(l>0) { + strncpy(buf + bufl, start, l); buf[bufl + l]= 0; + if(bsl_mode >= 3) { + ret= Sfile_bsl_interpreter(buf, l, &eaten, 0); + if(ret <= 0) + goto ex; + } + } + l= strlen(buf); + start= cpt+1; + while(*(++cpt)!=0) if(*cpt=='"') break; + if((flag&4) && *cpt==0) + {ret= 0; goto ex;} + l= cpt-start; bufl= strlen(buf); + if(l>0) { + strncpy(buf + bufl, start, l); + buf[bufl + l]= 0; + if(bsl_mode >= 1) { + ret= Sfile_bsl_interpreter(buf + bufl, l, &eaten, 0); + if(ret <= 0) + goto ex; + } + } + start= cpt+1; + }else if(*cpt=='\''){ + l= cpt-start; bufl= strlen(buf); + if(l>0) { + strncpy(buf + bufl, start, l); buf[bufl + l]= 0; + if(bsl_mode >= 3) { + ret= Sfile_bsl_interpreter(buf, l, &eaten, 0); + if(ret <= 0) + goto ex; + } + } + l= strlen(buf); + start= cpt+1; + while(*(++cpt)!=0) if(*cpt=='\'') break; + if((flag&4) && *cpt==0) + {ret= 0; goto ex;} + l= cpt-start; bufl= strlen(buf); + if(l>0) { + strncat(buf,start,l);buf[bufl+l]= 0; + if(bsl_mode >= 2) { + ret= Sfile_bsl_interpreter(buf + bufl, l, &eaten, 0); + if(ret <= 0) + goto ex; + } + } + start= cpt+1; + } + if(*cpt==0) break; + } + l= cpt-start; + bufl= strlen(buf); + if(l>0) { + strncpy(buf + bufl, start, l); buf[bufl + l]= 0; + if(bsl_mode >= 3) { + ret= Sfile_bsl_interpreter(buf, l, &eaten, 0); + if(ret <= 0) + goto ex; + } + } + l= strlen(buf); + if(pass==0){ + if(argzaehl==line_start_argc && (flag&8)) + if(buf[0]!='-' && buf[0]!=0 && buf[0]!='#') + l++; + if(l>maxl) maxl= l; + }else{ + strcpy((*argv)[argzaehl],buf); + if(argzaehl==line_start_argc && (flag&8)) + if(buf[0]!='-' && buf[0]!=0 && buf[0]!='#') + sprintf((*argv)[argzaehl],"-%s", buf); + } + argzaehl++; + if(*cpt==0) break; + } + if(pass==0){ + if(flag & 16) + {ret= 1; goto ex;} + *argc= argzaehl; + if(argzaehl>0 || (flag & 128)) { + *argv= (char **) calloc((argzaehl + !!(flag & 128)), sizeof(char *)); + if(*argv==NULL) + {ret= -1; goto ex;} + } + for(i=0;i<*argc;i++) { + (*argv)[i]= (char *) calloc(maxl + 1, 1); + if((*argv)[i]==NULL) + {ret= -1; goto ex;} + } + if(flag & 128) + (*argv)[*argc]= NULL; + } + } + ret= 1; +ex: + if(buf != NULL) + free(buf); + return(ret); +} +