/* * Process the commands arguments */ static char *parse_cmd_args(sed_cmd_t *sed_cmd, char *cmdstr) { /* handle (s)ubstitution command */ if (sed_cmd->cmd == 's') cmdstr += parse_subst_cmd(sed_cmd, cmdstr); /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ else if (strchr("aic", sed_cmd->cmd)) { if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c') bb_error_msg_and_die ("only a beginning address can be specified for edit commands"); while(isspace(*cmdstr)) cmdstr++; sed_cmd->string = bb_xstrdup(cmdstr); parse_escapes(sed_cmd->string,sed_cmd->string,strlen(cmdstr),0,0); cmdstr += strlen(cmdstr); /* handle file cmds: (r)ead */ } else if(strchr("rw", sed_cmd->cmd)) { if (sed_cmd->end_line || sed_cmd->end_match) bb_error_msg_and_die("Command only uses one address"); cmdstr += parse_file_cmd(sed_cmd, cmdstr, &sed_cmd->string); if(sed_cmd->cmd=='w') sed_cmd->file=bb_xfopen(sed_cmd->string,"w"); /* handle branch commands */ } else if (strchr(":bt", sed_cmd->cmd)) { int length; while(isspace(*cmdstr)) cmdstr++; length = strcspn(cmdstr, semicolon_whitespace); if (length) { sed_cmd->string = strndup(cmdstr, length); cmdstr += length; } } /* translation command */ else if (sed_cmd->cmd == 'y') { char *match, *replace; int i=cmdstr[0]; cmdstr+=parse_regex_delim(cmdstr, &match, &replace)+1; /* \n already parsed, but \delimiter needs unescaping. */ parse_escapes(match,match,strlen(match),i,i); parse_escapes(replace,replace,strlen(replace),i,i); sed_cmd->string = xcalloc(1, (strlen(match) + 1) * 2); for (i = 0; match[i] && replace[i]; i++) { sed_cmd->string[i * 2] = match[i]; sed_cmd->string[(i * 2) + 1] = replace[i]; } free(match); free(replace); } /* if it wasnt a single-letter command that takes no arguments * then it must be an invalid command. */ else if (strchr("dDgGhHlnNpPqx={}", sed_cmd->cmd) == 0) { bb_error_msg_and_die("Unsupported command %c", sed_cmd->cmd); } /* give back whatever's left over */ return (cmdstr); }
static char *parse_cmd_str(struct sed_cmd * const sed_cmd, const char *const cmdstr) { int idx = 0; /* parse the command * format is: [addr][,addr]cmd * |----||-----||-| * part1 part2 part3 */ /* first part (if present) is an address: either a number or a /regex/ */ if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/') idx = get_address(sed_cmd, cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); /* second part (if present) will begin with a comma */ if (cmdstr[idx] == ',') { idx++; idx += get_address(sed_cmd, &cmdstr[idx], &sed_cmd->end_line, &sed_cmd->end_match); } /* last part (mandatory) will be a command */ if (cmdstr[idx] == '\0') error_msg_and_die("missing command"); sed_cmd->cmd = cmdstr[idx]; /* if it was a single-letter command that takes no arguments (such as 'p' * or 'd') all we need to do is increment the index past that command */ if (strchr("pd", cmdstr[idx])) { idx++; } /* handle (s)ubstitution command */ else if (sed_cmd->cmd == 's') { idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]); } /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ else if (strchr("aic", sed_cmd->cmd)) { if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c') error_msg_and_die("only a beginning address can be specified for edit commands"); idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]); } /* handle file cmds: (r)ead */ else if (sed_cmd->cmd == 'r') { if (sed_cmd->end_line || sed_cmd->end_match) error_msg_and_die("Command only uses one address"); idx += parse_file_cmd(sed_cmd, &cmdstr[idx]); } else { error_msg_and_die("invalid command"); } /* give back whatever's left over */ return (char *)&cmdstr[idx]; }
/* * Process the commands arguments */ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr) { static const char cmd_letters[] ALIGN1 = "saicrw:btTydDgGhHlnNpPqx={}"; enum { IDX_s = 0, IDX_a, IDX_i, IDX_c, IDX_r, IDX_w, IDX_colon, IDX_b, IDX_t, IDX_T, IDX_y, IDX_d, IDX_D, IDX_g, IDX_G, IDX_h, IDX_H, IDX_l, IDX_n, IDX_N, IDX_p, IDX_P, IDX_q, IDX_x, IDX_equal, IDX_lbrace, IDX_rbrace, IDX_nul }; unsigned idx; BUILD_BUG_ON(sizeof(cmd_letters)-1 != IDX_nul); idx = strchrnul(cmd_letters, sed_cmd->cmd) - cmd_letters; /* handle (s)ubstitution command */ if (idx == IDX_s) { cmdstr += parse_subst_cmd(sed_cmd, cmdstr); } /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ else if (idx <= IDX_c) { /* a,i,c */ unsigned len; if (idx < IDX_c) { /* a,i */ if (sed_cmd->end_line || sed_cmd->end_match) bb_error_msg_and_die("command '%c' uses only one address", sed_cmd->cmd); } for (;;) { if (*cmdstr == '\n' || *cmdstr == '\\') { cmdstr++; break; } if (!isspace(*cmdstr)) break; cmdstr++; } len = strlen(cmdstr); sed_cmd->string = copy_parsing_escapes(cmdstr, len); cmdstr += len; /* "\anychar" -> "anychar" */ parse_escapes(sed_cmd->string, sed_cmd->string, -1, '\0', '\0'); } /* handle file cmds: (r)ead */ else if (idx <= IDX_w) { /* r,w */ if (idx < IDX_w) { /* r */ if (sed_cmd->end_line || sed_cmd->end_match) bb_error_msg_and_die("command '%c' uses only one address", sed_cmd->cmd); } cmdstr += parse_file_cmd(/*sed_cmd,*/ cmdstr, &sed_cmd->string); if (sed_cmd->cmd == 'w') { sed_cmd->sw_file = xfopen_for_write(sed_cmd->string); sed_cmd->sw_last_char = '\n'; } } /* handle branch commands */ else if (idx <= IDX_T) { /* :,b,t,T */ int length; cmdstr = skip_whitespace(cmdstr); length = strcspn(cmdstr, semicolon_whitespace); if (length) { sed_cmd->string = xstrndup(cmdstr, length); cmdstr += length; } } /* translation command */ else if (idx == IDX_y) { char *match, *replace; int i = cmdstr[0]; cmdstr += parse_regex_delim(cmdstr, &match, &replace)+1; /* \n already parsed, but \delimiter needs unescaping. */ parse_escapes(match, match, -1, i, i); parse_escapes(replace, replace, -1, i, i); sed_cmd->string = xzalloc((strlen(match) + 1) * 2); for (i = 0; match[i] && replace[i]; i++) { sed_cmd->string[i*2] = match[i]; sed_cmd->string[i*2+1] = replace[i]; } free(match); free(replace); } /* if it wasn't a single-letter command that takes no arguments * then it must be an invalid command. */ else if (idx >= IDX_nul) { /* not d,D,g,G,h,H,l,n,N,p,P,q,x,=,{,} */ bb_error_msg_and_die("unsupported command %c", sed_cmd->cmd); } /* give back whatever's left over */ return cmdstr; }