int set_cstr(char **str,const char *src) { free_cstr(str); if (src != NULL) *str = strdup(src); return (*str != NULL); }
void shell_droplist_entry_free(struct shell_droplist_t *ent) { free_cstr(&ent->file); ent->next = NULL; }
void handle_macro(preprocessor_state* preproc, int macro) { FILE* input = preproc->input; FILE* output = preproc->output; lexer_state* lexer = &preproc->lexer; rsw_cstr expansion; init_cstr_str(&expansion, preproc->values.a[macro], strlen(preproc->values.a[macro])); macro_params* p = GET_PARAM(&preproc->params, macro); //do initial argument expansion if (p->num_params >= 0) parse_params(preproc, macro, &expansion); cvector_i valid_macros; cvec_i(&valid_macros, preproc->macros.size, preproc->macros.size); for (int i=0; i < preproc->macros.size; ++i) { valid_macros.a[i] = i; } rescan_expansion(preproc, &expansion, &valid_macros, macro); lexer_state save_lex; long fpos; token_lex t; save_lex = *lexer; if ((fpos = ftell(input)) == -1) { perror("ftell error in handle_macro"); exit(0); } t = read_token(input, lexer, NULL); *lexer = save_lex; if (fseek(input, fpos, SEEK_SET)) { perror("fseek failure in handle_macro"); exit(0); } if (t.tok.type == LPAREN) { char* search, *found; search = expansion.a; int len; for (int i=0; i < preproc->macros.size; ++i) { if (i == macro) continue; len = strlen(preproc->macros.a[i]); search = expansion.a; while (1) { found = strstr(search, preproc->macros.a[i]); if (!found) break; if (found[len]) { search = found + len; continue; } if (found != expansion.a) { if (isalpha(found[-1]) || found[-1] == '_') { search = found + len; continue; } } //don't need to check the end because we already did p = GET_PARAM(&preproc->params, i); if (p->num_params != -1) { *found = 0; //cut off matched macro fprintf(output, "%s", expansion.a); handle_macro(preproc, i); goto exit; } search = found + len; } } } else if (t.tok.type == ID || t.tok.type == STR_LITERAL) { free(t.tok.v.id); } fprintf(output, "%s", expansion.a); exit: free_cstr(&expansion); cvec_free_i(&valid_macros); }
unsigned int macro_expansion(preprocessor_state* preproc, rsw_cstr* expansion, unsigned long beginning, cvector_i* valid_macros, int macro_index) { //vaild_macros should never be NULL unless I uncomment that alternative method in prescan_argument //int macro = (valid_macros) ? valid_macros->a[macro_index] : macro_index; int macro = valid_macros->a[macro_index]; rsw_cstr local_expansion, scratch; init_cstr_str(&local_expansion, preproc->values.a[macro], strlen(preproc->values.a[macro])); init_cstr_str(&scratch, local_expansion.a, local_expansion.size); rsw_cstr arg_expansion; init_cstr_cap(&arg_expansion, 50); macro_params* p = GET_PARAM(&preproc->params, macro); int param_len, val_len, parens, loc; char* search, *found, *c; //beginning is start of macro name so jump forward len (the first c++ will jump over '(' ) c = &expansion->a[beginning + strlen(preproc->macros.a[macro])]; if (p->num_params != -1) while (isspace(*c)) ++c; parens = 0; for (int i=0; i < p->num_params; ++i) { val_len = 0; c++; while (isspace(*c)) ++c; //ignore spaces on edges ie after ( and , if (*c == '(') parens++; do { val_len += snprintf(macro_buf+val_len, MAX_MACRO_LEN-val_len, "%c", *c); c++; if (*c == '(') { parens++; } else if (*c == ')') { parens--; if (parens == -1) { if (i != p->num_params-1) preprocessor_error(NULL, &preproc->lexer, "more arguments expected for macro\n"); break; } } } while (*c != ',' || parens > 0); cstr_insert_str(&arg_expansion, 0, macro_buf, val_len); prescan_argument(preproc, &arg_expansion); param_len = strlen(p->names[i]); loc = cstr_find_str(&scratch, p->names[i]); while (loc != (size_t)-1) { cstr_replace_substr(&local_expansion, loc, param_len, arg_expansion.a, arg_expansion.size); //assuming size doesn't include \0 cstr_replace_substr(&scratch, loc, param_len, arg_expansion.a, arg_expansion.size); //assuming size doesn't include \0 for (int j=loc; j < loc+arg_expansion.size; ++j) scratch.a[j] = '*'; loc = cstr_find_str_start_at(&scratch, p->names[i], loc+arg_expansion.size); //-1 here? } arg_expansion.size = 0; } if (!p->num_params) // increment for ) because it didn't get it in loop ++c; //TODO test without this if (p->num_params == -1) --c; rescan_expansion(preproc, &local_expansion, valid_macros, macro_index); cstr_replace_substr(expansion, beginning, (c - expansion->a) - beginning + 1, local_expansion.a, local_expansion.size); unsigned int local_size = local_expansion.size; free_cstr(&local_expansion); free_cstr(&scratch); free_cstr(&arg_expansion); return beginning + local_size; }
void parse_params(preprocessor_state* preproc, int macro, rsw_cstr* expansion) { macro_params* p = GET_PARAM(&preproc->params, macro); token_lex t; rsw_cstr scratch; init_cstr_str(&scratch, expansion->a, expansion->size); //read ( read_token(preproc->input, &preproc->lexer, NULL); int param_len, val_len, parens, loc; char* search, *found; rsw_cstr arg_expansion; init_cstr_cap(&arg_expansion, 50); parens = 0; for (int i=0; i < p->num_params; ++i) { val_len = 0; t = read_token(preproc->input, &preproc->lexer, NULL); if (t.tok.type == LPAREN) parens++; do { val_len += print_token_to_str(&t.tok, macro_buf+val_len, MAX_MACRO_LEN-val_len); if (t.tok.type == ID || t.tok.type == STR_LITERAL) free(t.tok.v.id); t = read_token(preproc->input, &preproc->lexer, NULL); if (t.tok.type == LPAREN) { parens++; } else if (t.tok.type == RPAREN) { parens--; if (parens == -1) { if (i != p->num_params-1) preprocessor_error(&t, &preproc->lexer, "more arguments expected for macro,"); break; } } } while (t.tok.type != COMMA || parens > 0); //could put && parens != -1 and change above //perform prescan to handle nested calls //This contradicts C : A Reference Manual pg 50 but it's the only/easiest //way to get correct behavior (ie preventing infinite recursion but allowing nested calls to the same macro) //I know gcc does this (http://gcc.gnu.org/onlinedocs/gcc-3.0.2/cpp_3.html#SEC32) cstr_insert_str(&arg_expansion, 0, macro_buf, val_len); prescan_argument(preproc, &arg_expansion); param_len = strlen(p->names[i]); // val_len = strlen(macro_buf); loc = cstr_find_str(&scratch, p->names[i]); while (loc != (size_t)-1) { cstr_replace_substr(expansion, loc, param_len, arg_expansion.a, arg_expansion.size); //assuming size doesn't include \0 cstr_replace_substr(&scratch, loc, param_len, arg_expansion.a, arg_expansion.size); //assuming size doesn't include \0 //overwrite replacement in scratch with a character not allowed in identifiers //so that replacement of a subsequent parameter won't replace within an expansion //ie #define MYMACRO(a, b) a + b; //called as MYMACRO(b, a) would wrongly go to b + b -> a + a instead of b + a for (int j=loc; j < loc+arg_expansion.size; ++j) scratch.a[j] = '*'; loc = cstr_find_str_start_at(&scratch, p->names[i], loc+arg_expansion.size); //-1 here } //reset for next argument arg_expansion.size = 0; } //read ) for 0 params, others get read in loop if (!p->num_params) { token_lex t = read_token(preproc->input, &preproc->lexer, NULL); if (t.tok.type != RPAREN) preprocessor_error(&t, &preproc->lexer, "expected ) in function style macro with 0 arguments,"); } free_cstr(&arg_expansion); free_cstr(&scratch); }