char *escape_string(const char *input) { expand_buf_t *escape_string = eb_init(strlen(input) + strlen(input) / 2); eb_append(escape_string, "\"", 1); unsigned int i; for (i = 0; i < strlen(input); i++) { switch (input[i]) { case '"': { eb_append(escape_string, "\\\"", -1); break; } case '\\': { eb_append(escape_string, "\\\\", -1); break; } default: { eb_append(escape_string, &input[i], 1); break; } } } eb_append(escape_string, "\"", 1); char *result = eb_extract(escape_string); eb_free(escape_string); return result; }
char *parse_emit_string (const char *ptr, ES_TYPE type, void *echo_target) { static int level = 0; char *word = NULL; int session; bool fWasParsed; char *name_end; level++; arg_context_t context = ARG_CONTEXT_INITIALIZER; while ((word = extract_arg_string(&ptr, &context)) != NULL) { // handle strings if (word[0] == '"') { char *next = next_expr (word, EXPR_DELIMS); if (*next != '\0') goto echo_error; reduce_string (word); if (type == ES_ECHO) { if (echo_target != NULL) { fprintf ((FILE *) echo_target, "%s", word); } } else if (type == ES_FCREATE) { eb_append((expand_buf_t *) echo_target, word, strlen(word)); } else { int i; for (i = 0; word[i]; i++) { if ((mode & MODE_NORMAL) || (mode & MODE_LIST)) write_out (word[i]); stats_datasize++; program_counter++; } } } else { int value; session = StartSPASMErrorSession(); fWasParsed = parse_num(word, &value); if (fWasParsed == true) { switch (type) { case ES_ECHO: { if (echo_target != NULL) { fprintf ((FILE *) echo_target, "%d", value); } break; } #ifdef USE_BUILTIN_FCREATE case ES_FCREATE: { char buffer[256]; sprintf_s(buffer, "%d", value); eb_append((expand_buf_t *) echo_target, buffer, -1); break; } #endif case ES_BYTE: { write_arg(value, ARG_NUM_8, 0, 0); stats_datasize++; program_counter++; break; } case ES_WORD: { write_arg(value, ARG_NUM_16, 0, 0); stats_datasize+=2; program_counter+=2; break; } case ES_LONG: { write_arg(value, ARG_NUM_24, 0, 0); stats_datasize+=3; program_counter+=3; break; } } ReplaySPASMErrorSession(session); } else if (IsSPASMErrorSessionFatal(session) == false && type != ES_FCREATE) { switch (type) { case ES_ECHO: break; case ES_BYTE: { add_pass_two_expr(word, ARG_NUM_8, 0, 0); stats_datasize++; program_counter++; break; } case ES_WORD: { add_pass_two_expr(word, ARG_NUM_16, 0, 0); stats_datasize+=2; program_counter+=2; break; } case ES_LONG: { add_pass_two_expr(word, ARG_NUM_24, 0, 0); stats_datasize += 3; program_counter += 3; break; } } ReplayFatalSPASMErrorSession(session); } else { char name[256]; char *next; define_t *define; name_end = word; //printf("error occured: %d, forward: %d, value: %d\n", error_occurred, parser_forward_ref_err, value); read_expr (&name_end, name, "("); //printf("Looking up %s\n", name); next = name_end; read_expr (&next, NULL, ")"); if (*next != '\0') goto echo_error; if ((define = search_defines (name))) { char *expr; list_t *args = NULL; //handle defines if (define->contents == NULL) { SetLastSPASMError(SPASM_ERR_ARG_USED_WITHOUT_VALUE, name); } if (*(name_end - 1) == '(') name_end--; name_end = parse_args (name_end, define, &args); if (!name_end) return (char *) ptr; expr = parse_define (define); if (expr != NULL) { arg_context_t nested_context = ARG_CONTEXT_INITIALIZER; // Is it some kind of argument list? const char *nested_expr = expr; extract_arg_string(&nested_expr, &nested_context); if (extract_arg_string(&nested_expr, &nested_context) != NULL) { // if it is, plug it in to the emit string parse_emit_string(expr, type, echo_target); } else { if (IsErrorInSPASMErrorSession(session, SPASM_ERR_EXCEEDED_RECURSION_LIMIT) == false) { int inner_session = StartSPASMErrorSession(); parse_emit_string(expr, type, echo_target); if (IsSPASMErrorSessionFatal(inner_session)) { EndSPASMErrorSession(inner_session); AddSPASMErrorSessionAnnotation(session, _T("Error during evaluation of macro '%s'"), define->name); ReplaySPASMErrorSession(session); } else { EndSPASMErrorSession(inner_session); } //ReplaySPASMErrorSession(session); } else { ReplaySPASMErrorSession(session); } } free (expr); } remove_arg_set (args); } else { echo_error: switch (type) { case ES_ECHO: { if (echo_target != NULL) { fprintf((FILE *) echo_target, "(error)"); } break; } case ES_FCREATE: { SetLastSPASMError(SPASM_ERR_LABEL_NOT_FOUND, word); eb_append((expand_buf_t *) echo_target, "(error)", -1); break; } } ReplaySPASMErrorSession(session); } } EndSPASMErrorSession(session); } } if (type == ES_ECHO && level == 1) { if (echo_target == stdout) putchar ('\n'); else { if (echo_target != NULL) { fclose ((FILE *) echo_target); } } } level--; return (char *) ptr; }
static void expand_expr_full (const char *expr, expand_buf *new_expr, int depth, bool search_local) { const char *block_start; char *name; static char separators[] = "=+-*<>|&/%^()\\, \t\r"; define_t *define; label_t *label; int name_len; if (depth > RECURSION_LIMIT) { SetLastSPASMError (SPASM_ERR_RECURSION_DEPTH, RECURSION_LIMIT); return; } while (*expr) { //handle strings if (*expr == '\"') { block_start = expr++; while (*expr && *expr != '\"') { if (!(*expr == '\\' && *(++expr) == '\0')) expr++; } if (*expr) expr++; eb_append (new_expr, block_start, expr - block_start); } //get the next name and look it up name = skip_to_name_end (expr); name_len = name - expr; //skip if there's no name, or if it's a macro with arguments if (name_len > 0) { name = strndup (expr, name_len); //if it's a define, recursively expand its contents if ((define = search_defines (name, search_local)) && define->contents != NULL) { list_t *args = NULL; if (define->num_args > 0) { expr = parse_args (expr + name_len, define, &args); if (!expr) { free (name); return; } } else { expr += name_len; } expand_expr_full (define->contents, new_expr, depth + 1, search_local); remove_arg_set (args); if (error_occurred) return; //if it's a label, write its value } else if ((label = search_labels (name))) { char buf[10]; snprintf (buf, sizeof(buf), "%d", label->value); eb_append (new_expr, buf, -1); expr += name_len; //otherwise, it might be a forward ref, so just write the name } else { eb_append (new_expr, name, name_len); expr += name_len; } free (name); } else if (*expr) { //if it can't be a name, just write the next char and move on eb_append (new_expr, expr, 1); expr++; } //skip past separators block_start = expr; while (*expr && strchr (separators, *expr)) expr++; //write those eb_append (new_expr, block_start, expr - block_start); } }