"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/frontend/frontend_pipes_xorriso.c" (30 Jan 2021, 28855 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "frontend_pipes_xorriso.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.5.2_vs_1.5.4.

    1 
    2 /* Beefed-up example from man 2 pipe
    3    to illustrate how xorriso is to be used by frontend programs via two pipes.
    4    Additionally there is a standalone implementation of Xorriso_parse_line().
    5 
    6    Copyright 2012 Thomas Schmitt, <scdbackup@gmx.net> 
    7    Unaltered provided under BSD license.
    8    You may issue licenses of your choice for derived code, provided that they
    9    do not infringe anybody's right to do the same for this original code.
   10 
   11    Build:
   12      cc -g -o frontend_pipes_xorriso frontend_pipes_xorriso.c
   13 
   14    Usage:
   15      ./frontend_pipes_xorriso [path_to_xorriso_binary | -h]
   16 
   17 */
   18 
   19 #include <sys/wait.h>
   20 #include <assert.h>
   21 #include <stdio.h>
   22 #include <stdlib.h>
   23 #include <unistd.h>
   24 #include <string.h>
   25 #include <ctype.h>
   26 
   27 
   28 static int usage()
   29 {
   30     static char helptext[][80] = {
   31 "usage: frontend_pipes_xorriso [path_to_xorriso|-h]",
   32 "",
   33 "Forks a process that runs xorriso and communicates with it via two pipes.",
   34 "The command pipe sends payload commands and -mark commands. The reply pipe",
   35 "receives -pkt_output lines which it dispatches to stdout and stderr.",
   36 "The communication between both processes is made synchronous by the parent",
   37 "awaiting the -mark message of the child.",
   38 "Optionally the reply lines can be parsed into words. This is initiated by",
   39 "meta command",
   40 "  @parse [prefix [separators [max_words [flag]]]]",
   41 "which sets the four parameters for a function equivalent to",
   42 "Xorriso_parse_line() (see xorriso.h). All reply will then be parsed and",
   43 "non-empty word arrays are displayed. Meta command",
   44 "  @noparse",
   45 "ends this mode.",
   46 "Meta command",
   47 "  @drain_sieve",
   48 "reports all recorded results of all installed message sieve filter rules.",
   49 "For illustration perform this xorriso command sequence",
   50 "  -msg_op start_sieve - -outdev /dev/sr0 -msg_op clear_sieve - -toc",
   51 "and then @drain_sieve.", 
   52 "@END@"
   53     };
   54     int i;
   55 
   56     for (i = 0; strcmp(helptext[i], "@END@") != 0; i++)
   57         fprintf(stderr, "%s\n", helptext[i]);
   58     return(1);
   59 }
   60 
   61 
   62 /* Local helpers of parent process */
   63 
   64 struct boss_state {
   65     /* What the parent needs to know about its connection to xorriso */
   66 
   67     /* The ends of the dialog pipes */
   68     int command_fd;
   69     int reply_fd;
   70 
   71     /* For synchronization between boss and xorriso */
   72     int mark_count;
   73     char pending_mark[16];
   74 
   75     /* Parsing_parameters. See xorriso.h Xorriso_parse_line */
   76     int do_parse;
   77     char progname[1024];
   78     char prefix[1024];
   79     char separators[256];
   80     int max_words;
   81     int flag;
   82 
   83     /* A primitive catcher for result lines */
   84     int reply_lines_size; /* 0= catching disabled */
   85     char **reply_lines;
   86     int reply_lines_count;
   87 };
   88 
   89 #define Frontend_xorriso_max_resulT 1000
   90 
   91 
   92 /* Some basic gestures of this program: */
   93 
   94 static int prompt_for_command(struct boss_state *boss,
   95                               char *line, int line_size);
   96 
   97 static int transmit_command(struct boss_state *boss, char *line);
   98 
   99 static int await_all_replies(struct boss_state *boss);
  100 
  101 static int de_pkt_result(struct boss_state *boss);
  102 
  103 static int drain_sieve(struct boss_state *boss);
  104 
  105 int parse_line(char *progname, char *line,
  106                char *prefix, char *separators, int max_words,
  107                int *argc, char ***argv, int flag);
  108 
  109 int dispose_parsed_words(int *argc, char ***argv);
  110 
  111 
  112 
  113 /* Parent and child */
  114 int main(int argc, char *argv[])
  115 {
  116     int command_pipe[2], reply_pipe[2];
  117     pid_t cpid;
  118     char *xorriso_path = "/usr/bin/xorriso";
  119 
  120     if (argc > 1) {
  121         if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "-help") == 0 ||
  122             strcmp(argv[1], "--help") == 0) {
  123             usage();
  124             exit(0);
  125         }
  126         xorriso_path = argv[1];
  127     }
  128 
  129     if (pipe(command_pipe) == -1)
  130         { perror("pipe"); exit(1); }
  131     if (pipe(reply_pipe) == -1)
  132         { perror("pipe"); exit(1); }
  133 
  134     cpid = fork();
  135     if (cpid == -1)
  136         { perror("fork"); exit(2); }
  137 
  138     if (cpid == 0) {
  139         /* Child redirects stdin and stdout. Then it becomes xorriso. */
  140 
  141         char *xargv[8];
  142 
  143         close(command_pipe[1]);        /* Close unused write end */
  144         close(reply_pipe[0]);          /* Close unused read end */
  145 
  146         /* Attach pipe ends to stdin and stdout */
  147         close(0);
  148         if (dup2(command_pipe[0], 0) == -1)
  149             { perror("dup2(,0)"); exit(1); }
  150         close(1);
  151         if (dup2(reply_pipe[1], 1) == -1)
  152             { perror("dup2(,1)"); exit(1); }
  153 
  154         xargv[0] = xorriso_path;
  155         xargv[1] = "-dialog";
  156         xargv[2] = "on";
  157         xargv[3] = "-pkt_output";
  158         xargv[4] = "on";
  159         xargv[5] = "-mark";
  160         xargv[6] = "0";       /* corresponds to mark_count = 0 in parent */
  161         xargv[7] = NULL;
  162         execv(xorriso_path, xargv);
  163         perror("execv"); exit(1);
  164 
  165     } else {
  166         /* Parent prompts user for command lines and prints xorriso replies.
  167            It knows when all reply text of the pending command line has arrived
  168            by watching for -mark reply pending_mark. 
  169         */
  170 
  171         int ret;
  172         char line[4096];
  173         struct boss_state boss;
  174 
  175         close(command_pipe[0]);        /* Close unused read end */
  176         close(reply_pipe[1]);          /* Close unused write end */
  177 
  178         memset(&boss, 0, sizeof(boss));
  179         boss.command_fd = command_pipe[1];
  180         boss.reply_fd = reply_pipe[0];
  181         strcpy(boss.progname, argv[0]);
  182         boss.reply_lines = NULL;
  183 
  184         /* Dialog loop */
  185         sprintf(boss.pending_mark, "%d", boss.mark_count);
  186         while (1) {
  187 
  188             /* Wait for pending mark and print all replies */
  189             ret = await_all_replies(&boss);
  190             if (ret < 0)
  191         break;
  192 
  193             /* Prompt for command line */
  194             ret = prompt_for_command(&boss, line, sizeof(line));
  195             if (ret <= 0)
  196         break;
  197 
  198             /* Send line and -mark command */
  199             ret = transmit_command(&boss, line);
  200             if (ret <= 0)
  201         break;
  202         }
  203 
  204 
  205         /* >>> if child is still operational: send -rollback_end */;
  206 
  207         /* >>> wait a short while */;
  208 
  209         /* >>> if not yet ended: kill child  */;
  210 
  211         wait(NULL);             /* Wait for child */
  212         exit(0);
  213     }
  214 }
  215 
  216 
  217 /* ------------------- Local helpers of parent process -------------------- */
  218 
  219 static int show_parsed(struct boss_state *boss, char *line);
  220 static int record_reply_line(struct boss_state *boss, char *line);
  221 static int make_reply_lines(struct boss_state *boss);
  222 static int input_interpreter(char *line, struct boss_state *boss);
  223 
  224 
  225 /* Ask the user for command input and trigger processing of meta commands.
  226 */
  227 static int prompt_for_command(struct boss_state *boss,
  228                               char *line, int line_size)
  229 {
  230     int l, ret;
  231     char *line_res;
  232 
  233     while (1) {
  234         fprintf(stderr, "+++ Enter a command and its parameters :\n");
  235         line_res = fgets(line, line_size - 1, stdin);
  236         if (line_res == NULL)
  237             return(0);
  238         l = strlen(line);
  239         if (l == 0) {
  240             line[0] = '\n';
  241             line[1] = 0;
  242         } else if (line[l - 1] != '\n') {
  243             line[l] = '\n';
  244             line[l + 1] = 0;
  245         }
  246         /* Interpret meta commands which begin by @ */
  247         ret = input_interpreter(line, boss);
  248         if (ret == 0)
  249             return(1);
  250         if (ret < 0)
  251             return(-1);
  252     }
  253 }
  254 
  255 
  256 /* Transmit a command (which must end by white space, e.g. newline)
  257    and its unique synchronization mark.
  258 */
  259 static int transmit_command(struct boss_state *boss, char *line)
  260 {
  261     int ret;
  262     char mark_line[32];
  263 
  264     ret = write(boss->command_fd, line, strlen(line));
  265     if (ret == -1) {
  266         perror("write");
  267         return(0);
  268     }
  269     /* Produce new unique -mark text to watch for */
  270     (boss->mark_count)++;
  271     sprintf(boss->pending_mark, "%d", boss->mark_count);
  272     sprintf(mark_line, "-mark %s\n", boss->pending_mark);
  273     ret = write(boss->command_fd, mark_line, strlen(mark_line));
  274     if (ret == -1) {
  275         perror("write");
  276         return(0);
  277     }
  278     return(1);
  279 }
  280 
  281 
  282 /* Read reply messages from xorriso and wait for the expected synchronization
  283    mark. Messages can be printed or collected in boss->reply_lines.
  284 */
  285 static int await_all_replies(struct boss_state *boss)
  286 {
  287     int count, remainder = 0, ret;
  288     char buf[32769], *line, *npt;
  289 
  290     while (1) {
  291         count = read(boss->reply_fd, buf + remainder,
  292                      sizeof(buf) - 1 - remainder);
  293         if (count == -1) {
  294             perror("read");
  295             return(-1);
  296         }
  297         if (count == 0) {
  298             fprintf(stderr, "+++ EOF encountered by Master process\n");
  299             return(-2);
  300         }
  301         for (npt = buf + remainder; npt < buf + count; npt++) {
  302              if (*npt == 0) {
  303                     fprintf(stderr,
  304                             "+++ Protocol error : Reply contains 0-chars\n");
  305                     return(-1);
  306              }
  307         }
  308 
  309         /* Split buf into lines */
  310         buf[remainder + count] = 0; /* for convenience */
  311         line = buf;
  312         while (1) {
  313             npt = strchr(line, '\n');
  314             if (npt == NULL) {
  315                 /* Move line to start of buffer and set remainder */
  316                 if (line != buf) {
  317                     remainder = 0;
  318                     for (npt = line; *npt; npt++)
  319                          buf[remainder++] = *npt;
  320                 }
  321                 /* Now read more data in the hope to get a newline char */
  322         break;
  323             }
  324             /* Interpret line */
  325             *npt = 0;
  326             if (line[0] == 'M') {
  327                 /* M-replies will be outdated until the pending command line
  328                    is completely done and the appended -mark command gets
  329                    into effect.
  330                 */
  331                 if (strlen(line) < 6) {
  332                     fprintf(stderr,
  333                  "+++ Protocol error : M-channel line shorter than 6 chars\n");
  334                     return(-1);
  335                 }
  336                 if (strcmp(line + 5, boss->pending_mark) == 0) {
  337                     if ((line - buf) + strlen(line) + 1 < count) {
  338                         fprintf(stderr,
  339                     "+++ Protocol error : Surplus reply data after M-match\n");
  340                         fprintf(stderr, "%s\n", line + strlen(line) + 1);
  341                         return(-1);
  342                     }
  343                     return (1); /* Expected mark has arrived */
  344                 }
  345             } else if (line[0] == 'R') {
  346                 /* R-replies are result lines of inquiry commands, like -ls.
  347                    They should be handled by specialized code which knows
  348                    how to parse and interpret them.
  349                 */
  350                 if (boss->reply_lines_count < boss->reply_lines_size) {
  351                     ret = record_reply_line(boss, line);
  352                     if (ret <= 0)
  353                         return(ret);
  354                 } else
  355                     printf("%s\n", line);
  356             } else {
  357                 /* I-replies are pacifiers, notifications, warnings, or
  358                    error messages. They should be handled by a general
  359                    message interpreter which determines their severity
  360                    and decides whether to bother the user.
  361                 */
  362                 if (boss->reply_lines_count < boss->reply_lines_size) {
  363                     ret = record_reply_line(boss, line);
  364                     if (ret <= 0)
  365                         return(ret);
  366                 } else
  367                     fprintf(stderr, "%s\n", line);
  368             }
  369 
  370             /* Parse line and show words */
  371             if (strlen(line) >= 5)
  372                 show_parsed(boss, line + 5);
  373 
  374             line = npt + 1;
  375         }
  376     }
  377     return(1);
  378 }
  379 
  380 
  381 /* Throw away I channel.
  382    Unpack and reconstruct payload of R channel lines.
  383 */
  384 static int de_pkt_result(struct boss_state *boss)
  385 {
  386     int i, l, w;
  387     char *payload = NULL, *new_payload = NULL;
  388 
  389     w = 0;
  390     for (i = 0; i < boss->reply_lines_count; i++) {
  391         if (boss->reply_lines[i][0] != 'R' ||
  392             strlen(boss->reply_lines[i]) < 5)
  393     continue;
  394 
  395         if (payload == NULL) {
  396             payload = strdup(boss->reply_lines[i] + 5);
  397         } else {
  398             l = strlen(payload);
  399             new_payload = calloc(l + strlen(boss->reply_lines[i] + 5) + 1, 1);
  400             if (new_payload == NULL)
  401                 goto no_mem;
  402             strcpy(new_payload, payload);
  403             strcpy(new_payload + l, boss->reply_lines[i] + 5);
  404             free(payload);
  405             payload = new_payload;
  406         }
  407         if (payload == NULL)
  408             goto no_mem;
  409         l = strlen(payload);
  410         if (l > 0)
  411            if (payload[l - 1] == '\n')
  412                payload[l - 1] = 0;
  413 
  414         if (boss->reply_lines[i][2] != '0') {
  415            free(boss->reply_lines[w]);
  416            boss->reply_lines[w] = payload;
  417            w++;
  418            payload = NULL;
  419         }
  420     }
  421     for (i = w ; i < boss->reply_lines_count; i++) {
  422         free(boss->reply_lines[i]);
  423         boss->reply_lines[i] = NULL;
  424     }
  425     boss->reply_lines_count = w;
  426     return(1);
  427 no_mem:;
  428     fprintf(stderr, "FATAL: Out of memory !\n");
  429     return(-1);
  430 }
  431 
  432 
  433 /* Inquire and print all recorded message sieve results.
  434 */
  435 static int drain_sieve(struct boss_state *boss)
  436 {
  437     int ret, i, j, names_size = 0, names_count = 0, first_result;
  438     int number_of_strings, available, xorriso_ret, number_of_lines, k, r;
  439     char **names = NULL, line[1024];
  440 
  441     /* Install catcher for reply_lines */
  442     ret = make_reply_lines(boss);
  443     if (ret <= 0)
  444         goto ex;
  445     boss->reply_lines_size = Frontend_xorriso_max_resulT;
  446     boss->reply_lines_count = 0;
  447 
  448     /* Get list of filter rule names from -msg_op show_sieve */
  449     ret = transmit_command(boss, "-msg_op show_sieve -\n");
  450     if (ret <= 0)
  451         goto ex;
  452     ret = await_all_replies(boss);
  453     if (ret <= 0)
  454         goto ex;
  455     ret = de_pkt_result(boss);
  456     if (ret <= 0)
  457         goto ex;
  458 
  459     names = boss->reply_lines;
  460     boss->reply_lines = NULL;
  461     names_size = Frontend_xorriso_max_resulT;
  462     names_count= boss->reply_lines_count;
  463     ret = make_reply_lines(boss);
  464     if (ret <= 0)
  465         goto ex;
  466     boss->reply_lines_size = Frontend_xorriso_max_resulT;
  467 
  468     /* Inquire caught results of each name by -msg_op read_sieve
  469        until return value is <= 0
  470     */
  471     printf("--------------------------------------------------\n");
  472     for (i = 0; i < names_count; i++) {
  473         available = 1;
  474         first_result = 1;
  475         while (available > 0) {
  476             boss->reply_lines_count = 0;
  477             sprintf(line, "-msg_op read_sieve '%s'\n", names[i]);
  478             ret = transmit_command(boss, line);
  479             if (ret <= 0)
  480                 goto ex;
  481             ret = await_all_replies(boss);
  482             if (ret <= 0)
  483                 goto ex;
  484             ret = de_pkt_result(boss);
  485             if (ret <= 0)
  486                 goto ex;
  487 
  488             if (boss->reply_lines_count < 2) {
  489                 fprintf(stderr, "drain_sieve: illegible result reply\n");
  490                 {ret= 0; goto ex;}
  491             }
  492             xorriso_ret = -1;
  493             sscanf(boss->reply_lines[0], "%d", &xorriso_ret);
  494             if(xorriso_ret <= 0)
  495         break;
  496             number_of_strings = -1;
  497             sscanf(boss->reply_lines[1], "%d", &number_of_strings);
  498             if(xorriso_ret < 0)
  499         break;
  500             if (first_result)
  501                 printf(" '%s' |\n", names[i]);
  502             first_result = 0;
  503             for (j = 0; names[i][j] != 0; j++)
  504                 printf("-");
  505             printf("-----\n");
  506             r = 2;
  507             for (j = 0; j < number_of_strings && r < boss->reply_lines_count;
  508                  j++) {
  509                 number_of_lines = -1;
  510                 sscanf(boss->reply_lines[r], "%d", &number_of_lines);
  511                 r++;
  512                 printf("|");
  513                 for (k = 0; k < number_of_lines
  514                             && r < boss->reply_lines_count; k++) {
  515                    printf("%s%s", boss->reply_lines[r],
  516                                   k < number_of_lines - 1 ? "\n" : "");
  517                    r++;
  518                 }
  519                 printf("|\n");
  520             }
  521         }
  522         if (first_result == 0)
  523             printf("--------------------------------------------------\n");
  524     }
  525 
  526     /* Dispose all recorded results */
  527     ret = transmit_command(boss, "-msg_op clear_sieve -\n");
  528     if (ret <= 0)
  529         goto ex;
  530     ret = await_all_replies(boss);
  531     if (ret <= 0)
  532         goto ex;
  533 
  534     ret = 1;
  535 ex:;
  536     /* Disable result catcher */
  537     boss->reply_lines_size = 0;
  538     if (names != NULL)
  539         dispose_parsed_words(&names_size, &names);
  540     return(ret);
  541 }
  542 
  543 
  544 /* ------------------------- Helpers of local helpers ---------------------- */
  545 
  546 
  547 static int show_parsed(struct boss_state *boss, char *line)
  548 {
  549     int argc, ret = 0, i;
  550     char **argv = NULL;
  551 
  552     if (!boss->do_parse)
  553         return(2);
  554     ret = parse_line(boss->progname, line, boss->prefix, boss->separators,
  555                      boss->max_words, &argc, &argv, boss->flag);
  556     if (ret <= 0 || argc <= 0)
  557         return(0);
  558     fprintf(stderr, "-----------------------------------------------------\n");
  559     fprintf(stderr, "parse_line returns %d, argc = %d\n", ret, argc);
  560     for (i = 0; i < argc; i++)
  561          fprintf(stderr, "%2d : %s\n", i, argv[i]);
  562     fprintf(stderr, "-----------------------------------------------------\n");
  563     dispose_parsed_words(&argc, &argv); /* release memory */
  564     return(1);    
  565 }
  566 
  567 
  568 static int make_reply_lines(struct boss_state *boss)
  569 {
  570     int i;
  571 
  572     if (boss->reply_lines != NULL)
  573         return(1);
  574 
  575     boss->reply_lines = calloc(Frontend_xorriso_max_resulT,
  576                                  sizeof(char *));
  577     if (boss->reply_lines == 0) {
  578         fprintf(stderr, "FATAL: Out of memory !\n");
  579         return(-1);
  580     }
  581     boss->reply_lines_count = 0;
  582     boss->reply_lines_size = 0;
  583     for (i = 0; i < Frontend_xorriso_max_resulT; i++)
  584         boss->reply_lines[i] = NULL;
  585     return(1);
  586 }
  587 
  588 
  589 static int record_reply_line(struct boss_state *boss, char *line)
  590 {
  591     if (boss->reply_lines[boss->reply_lines_count] != NULL)
  592         free(boss->reply_lines[boss->reply_lines_count]);
  593     boss->reply_lines[boss->reply_lines_count] = strdup(line);
  594     if (boss->reply_lines[boss->reply_lines_count] == NULL) {
  595         fprintf(stderr, "FATAL: Out of memory !\n");
  596         return(-1);
  597     }
  598     boss->reply_lines_count++;
  599     return(1);
  600 }
  601 
  602 
  603 static int input_interpreter(char *line, struct boss_state *boss)
  604 {
  605     int argc, ret = 0;
  606     char **argv = NULL;
  607 
  608     ret = parse_line(boss->progname, line, "", "", 6, &argc, &argv, 0);
  609     if (ret <= 0 || argc <= 0)
  610         return(0);
  611     if (strcmp(argv[0], "@parse") == 0) {
  612         boss->do_parse = 1;
  613         boss->prefix[0] = 0;
  614         if (argc > 1)
  615             strcpy(boss->prefix, argv[1]);
  616         boss->separators[0] = 0;
  617         if (argc > 2)
  618             strcpy(boss->separators, argv[2]);
  619         boss->max_words = 0;
  620         if (argc > 3)
  621             sscanf(argv[3], "%d", &(boss->max_words));
  622         boss->max_words = 0;
  623         if (argc > 4)
  624             sscanf(argv[4], "%d", &(boss->flag));
  625         ret = 1;
  626     } else if(strcmp(argv[0], "@noparse") == 0) {
  627         boss->do_parse = 0;
  628         ret = 1;
  629     } else if(strcmp(argv[0], "@drain_sieve") == 0) {
  630         ret= drain_sieve(boss);
  631     } else {
  632         ret = 0;
  633     }
  634     dispose_parsed_words(&argc, &argv); /* release memory */
  635     return ret;
  636 }
  637 
  638 
  639 /* -------- Line-to-word parser equivalent to Xorriso_parse_line() -------- */
  640 
  641 
  642 static int Sfile_sep_make_argv(char *progname, char *line, char *separators,
  643                              int max_words, int *argc, char ***argv, int flag);
  644 
  645 
  646 int parse_line(char *progname, char *line,
  647                char *prefix, char *separators, int max_words,
  648                int *argc, char ***argv, int flag)
  649 {
  650     int ret, bsl_mode;
  651     char *to_parse;
  652  
  653     *argc = 0;
  654     *argv = NULL;
  655  
  656     to_parse = line;
  657     bsl_mode = (flag >> 1) & 15;
  658     if (prefix[0]) {
  659         if (strncmp(line, prefix, strlen(prefix)) == 0) {
  660             to_parse = line + strlen(prefix);
  661         } else {
  662             ret = 2; goto ex;
  663         }
  664     }
  665     ret = Sfile_sep_make_argv(progname, to_parse, separators,
  666                               max_words, argc, argv,
  667                               (!(flag & 32)) | 4 | (bsl_mode << 5));
  668     if (ret < 0) {
  669         fprintf(stderr,
  670                 "%s : Severe lack of resources during command line parsing\n",
  671                 progname);
  672         goto ex;
  673     }
  674     if (ret == 0) {
  675         fprintf(stderr,
  676                 "%s : Incomplete quotation in %s line: %s\n",
  677                 progname, (flag & 32) ? "command" : "parsed", to_parse);
  678         goto ex;
  679     }
  680 ex:;
  681     if (ret <= 0)
  682         Sfile_sep_make_argv("", "", "", 0, argc, argv, 2); /* release memory */
  683     return(ret);
  684 }
  685 
  686 
  687 int dispose_parsed_words(int *argc, char ***argv)
  688 {
  689     Sfile_sep_make_argv("", "", "", 0, argc, argv, 2);
  690     return(1);
  691 }
  692 
  693 
  694 /* -------------- Some helpers copied from xorriso/sfile.c ----------------- */
  695 
  696 
  697 static int Sfile_destroy_argv(int *argc, char ***argv, int flag)
  698 {
  699  int i;
  700 
  701  if(*argc>0 && *argv!=NULL){
  702    for(i=0;i<*argc;i++){
  703      if((*argv)[i]!=NULL)
  704        free((*argv)[i]);
  705    }
  706    free((char *) *argv);
  707  }
  708  *argc= 0;
  709  *argv= NULL;
  710  return(1);
  711 }
  712 
  713 
  714 /* Converts backslash codes into single characters:
  715     \a BEL 7 , \b BS 8 , \e ESC 27 , \f FF 12 , \n LF 10 , \r CR 13 ,
  716     \t  HT 9 , \v VT 11 , \\ \ 92 
  717     \[0-9][0-9][0-9] octal code , \x[0-9a-f][0-9a-f] hex code ,
  718     \cX control-x (ascii(X)-64)
  719    @param upto  maximum number of characters to examine for backslash.
  720                 The scope of a backslash (0 to 3 characters) is not affected.
  721    @param eaten returns the difference in length between input and output
  722    @param flag bit0= only determine *eaten, do not convert
  723                bit1= convert \000 to binary 0 
  724 */
  725 static int Sfile_bsl_interpreter(char *text, int upto, int *eaten, int flag)
  726 {
  727  char *rpt, *wpt, num_text[8], wdummy[8];
  728  unsigned int num= 0;
  729 
  730  *eaten= 0;
  731  wpt= text;
  732  for(rpt= text; *rpt != 0 && rpt - text < upto; rpt++) {
  733    if(flag & 1)
  734      wpt= wdummy;
  735    if(*rpt == '\\') {
  736      rpt++;
  737      (*eaten)++;
  738      if(*rpt == 'a') {
  739        *(wpt++)= 7;
  740      } else if(*rpt == 'b') {
  741        *(wpt++)= 8;
  742      } else if(*rpt == 'e') {
  743        *(wpt++)= 27;
  744      } else if(*rpt == 'f') {
  745        *(wpt++)= 12;
  746      } else if(*rpt == 'n') {
  747        *(wpt++)= 10;
  748      } else if(*rpt == 'r') {
  749        *(wpt++)= 13;
  750      } else if(*rpt == 't') {
  751        *(wpt++)= 9;
  752      } else if(*rpt == 'v') {
  753        *(wpt++)= 11;
  754      } else if(*rpt == '\\') {
  755        *(wpt++)= '\\';
  756      } else if(rpt[0] >= '0' && rpt[0] <= '7' &&
  757                rpt[1] >= '0' && rpt[1] <= '7' &&
  758                rpt[2] >= '0' && rpt[2] <= '7') {
  759        num_text[0]= '0';
  760        num_text[1]= *(rpt + 0);
  761        num_text[2]= *(rpt + 1);
  762        num_text[3]= *(rpt + 2);
  763        num_text[4]= 0;
  764        sscanf(num_text, "%o", &num);
  765        if((num > 0 || (flag & 2)) && num <= 255) {
  766          rpt+= 2;
  767          (*eaten)+= 2;
  768          *(wpt++)= num;
  769        } else
  770          goto not_a_code;
  771      } else if(rpt[0] == 'x' &&
  772                ((rpt[1] >= '0' && rpt[1] <= '9') ||
  773                 (rpt[1] >= 'A' && rpt[1] <= 'F') ||
  774                 (rpt[1] >= 'a' && rpt[1] <= 'f'))
  775                &&
  776                ((rpt[2] >= '0' && rpt[2] <= '9') ||
  777                 (rpt[2] >= 'A' && rpt[2] <= 'F') ||
  778                 (rpt[2] >= 'a' && rpt[2] <= 'f'))
  779                ) {
  780        num_text[0]= *(rpt + 1);
  781        num_text[1]= *(rpt + 2);
  782        num_text[2]= 0;
  783        sscanf(num_text, "%x", &num);
  784        if(num > 0 && num <= 255) {
  785          rpt+= 2;
  786          (*eaten)+= 2;
  787          *(wpt++)= num;
  788        } else
  789          goto not_a_code;
  790      } else if(*rpt == 'c') {
  791        if(rpt[1] > 64 && rpt[1] < 96) {
  792          *(wpt++)= rpt[1] - 64;
  793          rpt++;
  794          (*eaten)++;
  795        } else
  796          goto not_a_code;
  797      } else {
  798 not_a_code:;
  799        *(wpt++)= '\\';
  800        rpt--;
  801        (*eaten)--;
  802      }
  803    } else
  804      *(wpt++)= *rpt;
  805  }
  806  *wpt= *rpt;
  807  return(1);
  808 }
  809 
  810 
  811 #define SfileadrL 4096
  812 
  813 static int Sfile_sep_make_argv(char *progname, char *line, char *separators,
  814                               int max_words, int *argc, char ***argv, int flag)
  815 /*
  816  bit0= read progname as first argument from line
  817  bit1= just release argument list argv and return
  818  bit2= abort with return(0) if incomplete quotes are found
  819  bit3= eventually prepend missing '-' to first argument read from line
  820  bit4= like bit2 but only check quote completeness, do not allocate memory
  821  bit5+6= interpretation of backslashes:
  822        0= no interpretation, leave unchanged
  823        1= only inside double quotes
  824        2= outside single quotes
  825        3= everywhere
  826  bit7= append a NULL element to argv
  827 */
  828 {
  829  int i,pass,maxl=0,l,argzaehl=0,bufl,line_start_argc, bsl_mode, ret= 0, eaten;
  830  char *cpt,*start;
  831  char *buf= NULL;
  832 
  833  Sfile_destroy_argv(argc,argv,0);
  834  if(flag&2)
  835    {ret= 1; goto ex;}
  836 
  837  if(flag & 16)
  838    flag|= 4;
  839  bsl_mode= (flag >> 5) & 3;
  840 
  841  buf= calloc(strlen(line) + SfileadrL, 1);
  842  if(buf == NULL)
  843    {ret= -1; goto ex;}
  844  for(pass=0;pass<2;pass++) {
  845    cpt= line-1;
  846    if(!(flag&1)){
  847      argzaehl= line_start_argc= 1;
  848      if(pass==0)
  849        maxl= strlen(progname);
  850      else
  851        strcpy((*argv)[0],progname);
  852    } else {
  853      argzaehl= line_start_argc= 0;
  854      if(pass==0) maxl= 0;
  855    }
  856    while(*(++cpt)!=0){
  857      if(*separators) {
  858        if(strchr(separators, *cpt) != NULL)
  859    continue;
  860      } else if(isspace(*cpt))
  861    continue;
  862      start= cpt;
  863      buf[0]= 0;
  864      cpt--;
  865 
  866      if(max_words > 0 && argzaehl >= max_words && *cpt != 0) {
  867        /* take uninterpreted up to the end */
  868        cpt+= strlen(cpt) - 1;
  869      }
  870 
  871      while(*(++cpt)!=0) {
  872        if(*separators) {
  873          if(strchr(separators, *cpt) != NULL)
  874      break;
  875        } else if(isspace(*cpt))
  876      break;
  877        if(*cpt=='"'){
  878          l= cpt-start; bufl= strlen(buf);
  879          if(l>0) {
  880            strncpy(buf + bufl, start, l); buf[bufl + l]= 0;
  881            if(bsl_mode >= 3) {
  882              ret= Sfile_bsl_interpreter(buf, l, &eaten, 0);
  883              if(ret <= 0)
  884                goto ex;
  885            }
  886          }
  887          l= strlen(buf);
  888          start= cpt+1;
  889          while(*(++cpt)!=0) if(*cpt=='"') break;
  890          if((flag&4) && *cpt==0)
  891            {ret= 0; goto ex;}
  892          l= cpt-start; bufl= strlen(buf);
  893          if(l>0) {
  894            strncpy(buf + bufl, start, l);
  895            buf[bufl + l]= 0;
  896            if(bsl_mode >= 1) {
  897              ret= Sfile_bsl_interpreter(buf + bufl, l, &eaten, 0);
  898              if(ret <= 0)
  899                goto ex;
  900            }
  901          }
  902          start= cpt+1;
  903        }else if(*cpt=='\''){
  904          l= cpt-start; bufl= strlen(buf);
  905          if(l>0) {
  906            strncpy(buf + bufl, start, l); buf[bufl + l]= 0;
  907            if(bsl_mode >= 3) {
  908              ret= Sfile_bsl_interpreter(buf, l, &eaten, 0);
  909              if(ret <= 0)
  910                goto ex;
  911            }
  912          }
  913          l= strlen(buf);
  914          start= cpt+1;
  915          while(*(++cpt)!=0) if(*cpt=='\'') break;
  916          if((flag&4) && *cpt==0)
  917            {ret= 0; goto ex;}
  918          l= cpt-start; bufl= strlen(buf);
  919          if(l>0) {
  920            strncat(buf,start,l);buf[bufl+l]= 0;
  921            if(bsl_mode >= 2) {
  922              ret= Sfile_bsl_interpreter(buf + bufl, l, &eaten, 0);
  923              if(ret <= 0)
  924                goto ex;
  925            }
  926          }
  927          start= cpt+1;
  928        }
  929      if(*cpt==0) break;
  930      }
  931      l= cpt-start;
  932      bufl= strlen(buf);
  933      if(l>0) {
  934        strncpy(buf + bufl, start, l); buf[bufl + l]= 0;
  935        if(bsl_mode >= 3) {
  936          ret= Sfile_bsl_interpreter(buf, l, &eaten, 0);
  937          if(ret <= 0)
  938            goto ex;
  939        }
  940      }
  941      l= strlen(buf);
  942      if(pass==0){
  943        if(argzaehl==line_start_argc && (flag&8))
  944          if(buf[0]!='-' && buf[0]!=0 && buf[0]!='#')
  945            l++;
  946        if(l>maxl) maxl= l;
  947      }else{
  948        strcpy((*argv)[argzaehl],buf);
  949        if(argzaehl==line_start_argc && (flag&8))
  950          if(buf[0]!='-' && buf[0]!=0 && buf[0]!='#')
  951            sprintf((*argv)[argzaehl],"-%s", buf);
  952      }
  953      argzaehl++;
  954    if(*cpt==0) break;
  955    }
  956    if(pass==0){
  957      if(flag & 16)
  958        {ret= 1; goto ex;}
  959      *argc= argzaehl;
  960      if(argzaehl>0 || (flag & 128)) {
  961        *argv= (char **) calloc((argzaehl + !!(flag & 128)), sizeof(char *));
  962        if(*argv==NULL)
  963          {ret= -1; goto ex;}
  964      }
  965      for(i=0;i<*argc;i++) {
  966        (*argv)[i]= (char *) calloc(maxl + 1, 1);
  967        if((*argv)[i]==NULL)
  968          {ret= -1; goto ex;}
  969      }
  970      if(flag & 128)
  971        (*argv)[*argc]= NULL;
  972    }
  973  }
  974  ret= 1;
  975 ex:
  976  if(buf != NULL)
  977    free(buf);
  978  return(ret);
  979 }
  980