/* * returns the index in the string just past where the address ends. */ static int get_address(const char *my_str, int *linenum, regex_t ** regex) { const char *pos = my_str; if (isdigit(*my_str)) { *linenum = strtol(my_str, (char**)&pos, 10); /* endstr shouldn't ever equal NULL */ } else if (*my_str == '$') { *linenum = -1; pos++; } else if (*my_str == '/' || *my_str == '\\') { int next; char delimiter; char *temp; delimiter = '/'; if (*my_str == '\\') delimiter = *++pos; next = index_of_next_unescaped_regexp_delim(delimiter, ++pos); if (next != 0) { temp = copy_parsing_escapes(pos, next); G.previous_regex_ptr = *regex = xzalloc(sizeof(regex_t)); xregcomp(*regex, temp, G.regex_type); free(temp); } else { *regex = G.previous_regex_ptr; if (!G.previous_regex_ptr) bb_error_msg_and_die("no previous regexp"); } /* Move position to next character after last delimiter */ pos += (next+1); } return pos - my_str; }
/* * returns the index in the string just past where the address ends. */ static int get_address(const char *my_str, int *linenum, regex_t ** regex) { const char *pos = my_str; if (isdigit(*my_str)) { *linenum = strtol(my_str, (char**)&pos, 10); /* endstr shouldnt ever equal NULL */ } else if (*my_str == '$') { *linenum = -1; pos++; } else if (*my_str == '/' || *my_str == '\\') { int next; char delimiter; char *temp; delimiter = '/'; if (*my_str == '\\') delimiter = *++pos; next = index_of_next_unescaped_regexp_delim(delimiter, ++pos); temp = copy_parsing_escapes(pos, next); *regex = xmalloc(sizeof(regex_t)); xregcomp(*regex, temp, G.regex_type|REG_NEWLINE); free(temp); /* Move position to next character after last delimiter */ pos += (next+1); } return pos - my_str; }
/* * Returns the index of the third delimiter */ static int parse_regex_delim(const char *cmdstr, char **match, char **replace) { const char *cmdstr_ptr = cmdstr; unsigned char delimiter; int idx = 0; /* verify that the 's' or 'y' is followed by something. That something * (typically a 'slash') is now our regexp delimiter... */ if (*cmdstr == '\0') bb_error_msg_and_die("bad format in substitution expression"); delimiter = *cmdstr_ptr++; /* save the match string */ idx = index_of_next_unescaped_regexp_delim(delimiter, cmdstr_ptr); *match = copy_parsing_escapes(cmdstr_ptr, idx); /* save the replacement string */ cmdstr_ptr += idx + 1; idx = index_of_next_unescaped_regexp_delim(- (int)delimiter, cmdstr_ptr); *replace = copy_parsing_escapes(cmdstr_ptr, idx); return ((cmdstr_ptr - 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; }