static const char * macro_expand (int idx, sb *in, macro_entry *m, sb *out) { sb t; formal_entry *ptr; formal_entry *f; int is_keyword = 0; int narg = 0; const char *err = NULL; sb_new (&t); /* Reset any old value the actuals may have. */ for (f = m->formals; f; f = f->next) sb_reset (&f->actual); f = m->formals; while (f != NULL && f->index < 0) f = f->next; if (macro_mri) { /* The macro may be called with an optional qualifier, which may be referred to in the macro body as \0. */ if (idx < in->len && in->ptr[idx] == '.') { /* The Microtec assembler ignores this if followed by a white space. (Macro invocation with empty extension) */ idx++; if ( idx < in->len && in->ptr[idx] != ' ' && in->ptr[idx] != '\t') { formal_entry *n = new_formal (); n->index = QUAL_INDEX; n->next = m->formals; m->formals = n; idx = get_any_string (idx, in, &n->actual); } } } /* Peel off the actuals and store them away in the hash tables' actuals. */ idx = sb_skip_white (idx, in); while (idx < in->len) { int scan; /* Look and see if it's a positional or keyword arg. */ scan = idx; while (scan < in->len && !ISSEP (in->ptr[scan]) && !(macro_mri && in->ptr[scan] == '\'') && (!macro_alternate && in->ptr[scan] != '=')) scan++; if (scan < in->len && !macro_alternate && in->ptr[scan] == '=') { is_keyword = 1; /* It's OK to go from positional to keyword. */ /* This is a keyword arg, fetch the formal name and then the actual stuff. */ sb_reset (&t); idx = get_token (idx, in, &t); if (in->ptr[idx] != '=') { err = _("confusion in formal parameters"); break; } /* Lookup the formal in the macro's list. */ ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t)); if (!ptr) as_bad (_("Parameter named `%s' does not exist for macro `%s'"), t.ptr, m->name); else { /* Insert this value into the right place. */ if (ptr->actual.len) { as_warn (_("Value for parameter `%s' of macro `%s' was already specified"), ptr->name.ptr, m->name); sb_reset (&ptr->actual); } idx = get_any_string (idx + 1, in, &ptr->actual); if (ptr->actual.len > 0) ++narg; } } else { if (is_keyword) { err = _("can't mix positional and keyword arguments"); break; } if (!f) { formal_entry **pf; int c; if (!macro_mri) { err = _("too many positional arguments"); break; } f = new_formal (); c = -1; for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next) if ((*pf)->index >= c) c = (*pf)->index + 1; if (c == -1) c = 0; *pf = f; f->index = c; } if (f->type != FORMAL_VARARG) idx = get_any_string (idx, in, &f->actual); else { sb_add_buffer (&f->actual, in->ptr + idx, in->len - idx); idx = in->len; } if (f->actual.len > 0) ++narg; do { f = f->next; } while (f != NULL && f->index < 0); } if (! macro_mri) idx = sb_skip_comma (idx, in); else { if (in->ptr[idx] == ',') ++idx; if (ISWHITE (in->ptr[idx])) break; } } if (! err) { for (ptr = m->formals; ptr; ptr = ptr->next) { if (ptr->type == FORMAL_REQUIRED && ptr->actual.len == 0) as_bad (_("Missing value for required parameter `%s' of macro `%s'"), ptr->name.ptr, m->name); } if (macro_mri) { char buffer[20]; sb_reset (&t); sb_add_string (&t, macro_strip_at ? "$NARG" : "NARG"); ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t)); sprintf (buffer, "%d", narg); sb_add_string (&ptr->actual, buffer); } err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, m); } /* Discard any unnamed formal arguments. */ if (macro_mri) { formal_entry **pf; pf = &m->formals; while (*pf != NULL) { if ((*pf)->name.len != 0) pf = &(*pf)->next; else { f = (*pf)->next; del_formal (*pf); *pf = f; } } } sb_kill (&t); if (!err) macro_number++; return err; }
static int get_any_string (int idx, sb *in, sb *out) { sb_reset (out); idx = sb_skip_white (idx, in); if (idx < in->len) { if (in->len > idx + 2 && in->ptr[idx + 1] == '\'' && ISBASE (in->ptr[idx])) { while (!ISSEP (in->ptr[idx])) sb_add_char (out, in->ptr[idx++]); } else if (in->ptr[idx] == '%' && macro_alternate) { int val; char buf[20]; /* Turns the next expression into a string. */ /* xgettext: no-c-format */ idx = (*macro_expr) (_("% operator needs absolute expression"), idx + 1, in, &val); sprintf (buf, "%d", val); sb_add_string (out, buf); } else if (in->ptr[idx] == '"' || (in->ptr[idx] == '<' && (macro_alternate || macro_mri)) || (macro_alternate && in->ptr[idx] == '\'')) { if (macro_alternate && ! macro_strip_at && in->ptr[idx] != '<') { /* Keep the quotes. */ sb_add_char (out, '"'); idx = getstring (idx, in, out); sb_add_char (out, '"'); } else { idx = getstring (idx, in, out); } } else { char *br_buf = xmalloc(1); char *in_br = br_buf; *in_br = '\0'; while (idx < in->len && (*in_br || (in->ptr[idx] != ' ' && in->ptr[idx] != '\t')) && in->ptr[idx] != ',' && (in->ptr[idx] != '<' || (! macro_alternate && ! macro_mri))) { char tchar = in->ptr[idx]; switch (tchar) { case '"': case '\'': sb_add_char (out, in->ptr[idx++]); while (idx < in->len && in->ptr[idx] != tchar) sb_add_char (out, in->ptr[idx++]); if (idx == in->len) return idx; break; case '(': case '[': if (in_br > br_buf) --in_br; else { br_buf = xmalloc(strlen(in_br) + 2); strcpy(br_buf + 1, in_br); free(in_br); in_br = br_buf; } *in_br = tchar; break; case ')': if (*in_br == '(') ++in_br; break; case ']': if (*in_br == '[') ++in_br; break; } sb_add_char (out, tchar); ++idx; } free(br_buf); } } return idx; }
static int get_any_string (int idx, sb *in, sb *out, int expand, int pretend_quoted) { sb_reset (out); idx = sb_skip_white (idx, in); if (idx < in->len) { if (in->len > idx + 2 && in->ptr[idx + 1] == '\'' && ISBASE (in->ptr[idx])) { while (!ISSEP (in->ptr[idx])) sb_add_char (out, in->ptr[idx++]); } else if (in->ptr[idx] == '%' && macro_alternate && expand) { int val; char buf[20]; /* Turns the next expression into a string. */ /* xgettext: no-c-format */ idx = (*macro_expr) (_("% operator needs absolute expression"), idx + 1, in, &val); sprintf (buf, "%d", val); sb_add_string (out, buf); } else if (in->ptr[idx] == '"' || (in->ptr[idx] == '<' && (macro_alternate || macro_mri)) || (macro_alternate && in->ptr[idx] == '\'')) { if (macro_alternate && ! macro_strip_at && expand) { /* Keep the quotes. */ sb_add_char (out, '\"'); idx = getstring (idx, in, out); sb_add_char (out, '\"'); } else { idx = getstring (idx, in, out); } } else { while (idx < in->len && (in->ptr[idx] == '"' || in->ptr[idx] == '\'' || pretend_quoted || (in->ptr[idx] != ' ' && in->ptr[idx] != '\t' && in->ptr[idx] != ',' && (in->ptr[idx] != '<' || (! macro_alternate && ! macro_mri))))) { if (in->ptr[idx] == '"' || in->ptr[idx] == '\'') { char tchar = in->ptr[idx]; sb_add_char (out, in->ptr[idx++]); while (idx < in->len && in->ptr[idx] != tchar) sb_add_char (out, in->ptr[idx++]); if (idx == in->len) return idx; } sb_add_char (out, in->ptr[idx++]); } } } return idx; }
/* return 0 on everything-is-fine, and non-zero otherwise */ int parseconfig(const char *filename, struct GlobalConfig *global) { FILE *file; char filebuffer[512]; bool usedarg = FALSE; int rc = 0; struct OperationConfig *operation = global->first; if(!filename || !*filename) { /* NULL or no file name attempts to load .curlrc from the homedir! */ #ifndef __AMIGA__ char *home = homedir(); /* portable homedir finder */ filename = CURLRC; /* sensible default */ if(home) { if(strlen(home) < (sizeof(filebuffer) - strlen(CURLRC))) { msnprintf(filebuffer, sizeof(filebuffer), "%s%s%s", home, DIR_CHAR, CURLRC); #ifdef WIN32 /* Check if the file exists - if not, try CURLRC in the same * directory as our executable */ file = fopen(filebuffer, FOPEN_READTEXT); if(file != NULL) { fclose(file); filename = filebuffer; } else { /* Get the filename of our executable. GetModuleFileName is * already declared via inclusions done in setup header file. * We assume that we are using the ASCII version here. */ int n = GetModuleFileNameA(0, filebuffer, sizeof(filebuffer)); if(n > 0 && n < (int)sizeof(filebuffer)) { /* We got a valid filename - get the directory part */ char *lastdirchar = strrchr(filebuffer, '\\'); if(lastdirchar) { size_t remaining; *lastdirchar = 0; /* If we have enough space, build the RC filename */ remaining = sizeof(filebuffer) - strlen(filebuffer); if(strlen(CURLRC) < remaining - 1) { msnprintf(lastdirchar, remaining, "%s%s", DIR_CHAR, CURLRC); /* Don't bother checking if it exists - we do that later */ filename = filebuffer; } } } } #else /* WIN32 */ filename = filebuffer; #endif /* WIN32 */ } Curl_safefree(home); /* we've used it, now free it */ } # else /* __AMIGA__ */ /* On AmigaOS all the config files are into env: */ filename = "ENV:" CURLRC; #endif } if(strcmp(filename, "-")) file = fopen(filename, FOPEN_READTEXT); else file = stdin; if(file) { char *line; char *aline; char *option; char *param; int lineno = 0; bool dashed_option; while(NULL != (aline = my_get_line(file))) { int res; bool alloced_param = FALSE; lineno++; line = aline; /* line with # in the first non-blank column is a comment! */ while(*line && ISSPACE(*line)) line++; switch(*line) { case '#': case '/': case '\r': case '\n': case '*': case '\0': Curl_safefree(aline); continue; } /* the option keywords starts here */ option = line; /* the option starts with a dash? */ dashed_option = option[0]=='-'?TRUE:FALSE; while(*line && !ISSPACE(*line) && !ISSEP(*line, dashed_option)) line++; /* ... and has ended here */ if(*line) *line++ = '\0'; /* zero terminate, we have a local copy of the data */ #ifdef DEBUG_CONFIG fprintf(stderr, "GOT: %s\n", option); #endif /* pass spaces and separator(s) */ while(*line && (ISSPACE(*line) || ISSEP(*line, dashed_option))) line++; /* the parameter starts here (unless quoted) */ if(*line == '\"') { /* quoted parameter, do the quote dance */ line++; param = malloc(strlen(line) + 1); /* parameter */ if(!param) { /* out of memory */ Curl_safefree(aline); rc = 1; break; } alloced_param = TRUE; (void)unslashquote(line, param); } else { param = line; /* parameter starts here */ while(*line && !ISSPACE(*line)) line++; if(*line) { *line = '\0'; /* zero terminate */ /* to detect mistakes better, see if there's data following */ line++; /* pass all spaces */ while(*line && ISSPACE(*line)) line++; switch(*line) { case '\0': case '\r': case '\n': case '#': /* comment */ break; default: warnf(operation->global, "%s:%d: warning: '%s' uses unquoted " "white space in the line that may cause side-effects!\n", filename, lineno, option); } } if(!*param) /* do this so getparameter can check for required parameters. Otherwise it always thinks there's a parameter. */ param = NULL; } #ifdef DEBUG_CONFIG fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)")); #endif res = getparameter(option, param, &usedarg, global, operation); if(!res && param && *param && !usedarg) /* we passed in a parameter that wasn't used! */ res = PARAM_GOT_EXTRA_PARAMETER; if(res == PARAM_NEXT_OPERATION) { if(operation->url_list && operation->url_list->url) { /* Allocate the next config */ operation->next = malloc(sizeof(struct OperationConfig)); if(operation->next) { /* Initialise the newly created config */ config_init(operation->next); /* Copy the easy handle */ operation->next->easy = global->easy; /* Set the global config pointer */ operation->next->global = global; /* Update the last operation pointer */ global->last = operation->next; /* Move onto the new config */ operation->next->prev = operation; operation = operation->next; } else res = PARAM_NO_MEM; } } if(res != PARAM_OK && res != PARAM_NEXT_OPERATION) { /* the help request isn't really an error */ if(!strcmp(filename, "-")) { filename = "<stdin>"; } if(res != PARAM_HELP_REQUESTED && res != PARAM_MANUAL_REQUESTED && res != PARAM_VERSION_INFO_REQUESTED && res != PARAM_ENGINES_REQUESTED) { const char *reason = param2text(res); warnf(operation->global, "%s:%d: warning: '%s' %s\n", filename, lineno, option, reason); } } if(alloced_param) Curl_safefree(param); Curl_safefree(aline); } if(file != stdin) fclose(file); } else rc = 1; /* couldn't open the file */ return rc; }
/* return 0 on everything-is-fine, and non-zero otherwise */ int parseconfig(const char *filename, struct Configurable *config) { int res; FILE *file; char filebuffer[512]; bool usedarg; char *home; int rc = 0; if(!filename || !*filename) { /* NULL or no file name attempts to load .curlrc from the homedir! */ #ifndef __AMIGA__ filename = CURLRC; /* sensible default */ home = homedir(); /* portable homedir finder */ if(home) { if(strlen(home) < (sizeof(filebuffer) - strlen(CURLRC))) { snprintf(filebuffer, sizeof(filebuffer), "%s%s%s", home, DIR_CHAR, CURLRC); #ifdef WIN32 /* Check if the file exists - if not, try CURLRC in the same * directory as our executable */ file = fopen(filebuffer, "r"); if(file != NULL) { fclose(file); filename = filebuffer; } else { /* Get the filename of our executable. GetModuleFileName is * already declared via inclusions done in setup header file. * We assume that we are using the ASCII version here. */ int n = GetModuleFileName(0, filebuffer, sizeof(filebuffer)); if(n > 0 && n < (int)sizeof(filebuffer)) { /* We got a valid filename - get the directory part */ char *lastdirchar = strrchr(filebuffer, '\\'); if(lastdirchar) { size_t remaining; *lastdirchar = 0; /* If we have enough space, build the RC filename */ remaining = sizeof(filebuffer) - strlen(filebuffer); if(strlen(CURLRC) < remaining - 1) { snprintf(lastdirchar, remaining, "%s%s", DIR_CHAR, CURLRC); /* Don't bother checking if it exists - we do * that later */ filename = filebuffer; } } } } #else /* WIN32 */ filename = filebuffer; #endif /* WIN32 */ } Curl_safefree(home); /* we've used it, now free it */ } # else /* __AMIGA__ */ /* On AmigaOS all the config files are into env: */ filename = "ENV:" CURLRC; #endif } if(strcmp(filename,"-")) file = fopen(filename, "r"); else file = stdin; if(file) { char *line; char *aline; char *option; char *param; int lineno = 0; bool alloced_param; while(NULL != (aline = my_get_line(file))) { lineno++; line = aline; alloced_param=FALSE; /* line with # in the first non-blank column is a comment! */ while(*line && ISSPACE(*line)) line++; switch(*line) { case '#': case '/': case '\r': case '\n': case '*': case '\0': Curl_safefree(aline); continue; } /* the option keywords starts here */ option = line; while(*line && !ISSPACE(*line) && !ISSEP(*line)) line++; /* ... and has ended here */ if(*line) *line++ = '\0'; /* zero terminate, we have a local copy of the data */ #ifdef DEBUG_CONFIG fprintf(stderr, "GOT: %s\n", option); #endif /* pass spaces and separator(s) */ while(*line && (ISSPACE(*line) || ISSEP(*line))) line++; /* the parameter starts here (unless quoted) */ if(*line == '\"') { /* quoted parameter, do the quote dance */ line++; param = malloc(strlen(line) + 1); /* parameter */ if(!param) { /* out of memory */ Curl_safefree(aline); rc = 1; break; } alloced_param = TRUE; (void)unslashquote(line, param); } else { param = line; /* parameter starts here */ while(*line && !ISSPACE(*line)) line++; *line = '\0'; /* zero terminate */ } if(param && !*param) { /* do this so getparameter can check for required parameters. Otherwise it always thinks there's a parameter. */ if(alloced_param) Curl_safefree(param); param = NULL; } #ifdef DEBUG_CONFIG fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)")); #endif res = getparameter(option, param, &usedarg, config); if(param && *param && !usedarg) /* we passed in a parameter that wasn't used! */ res = PARAM_GOT_EXTRA_PARAMETER; if(res != PARAM_OK) { /* the help request isn't really an error */ if(!strcmp(filename, "-")) { filename = (char *)"<stdin>"; } if(PARAM_HELP_REQUESTED != res) { const char *reason = param2text(res); warnf(config, "%s:%d: warning: '%s' %s\n", filename, lineno, option, reason); } } if(alloced_param) Curl_safefree(param); Curl_safefree(aline); } if(file != stdin) fclose(file); } else rc = 1; /* couldn't open the file */ return rc; }
CMD* make_stage(token_list** list_ref) { token_list* list = *list_ref; if (!list) return make_error_cmd("could not form stage (no tokens)"); CMD* stage_tree = mallocCMD(); // Current type is NONE int next_type = NONE; // Hold the type of the head token of list bool redir_in = false; // Has there been a previous input redirection? bool redir_out = false; // Loop until hit a pipe or a separator; raise an error if multiple redirect // or both a command and subcommand while ((next_type = type(list)) != -1 && !ISSEP(next_type) && !ISPIPE(next_type) && next_type != PAR_RIGHT) { bool error = false; // Signals whether the current action results in an // error if (next_type == SIMPLE && stage_tree->type != SUBCMD) { int argc = stage_tree->argc + 1; char** argv = stage_tree->argv; argv = realloc(argv, (argc + 1) * sizeof(char*)); // +1 for trailing // NULL required // by freeCMD argv[argc - 1] = strdup(text(list)); argv[argc] = NULL; stage_tree->argc = argc; stage_tree->argv = argv; stage_tree->type = SIMPLE; } else if ((next_type == RED_IN || next_type == RED_HERE) && !redir_in) { error = make_redirect(stage_tree, &redir_in, next_type, &list); } else if (ISREDOUT(next_type) && !redir_out) { error = make_redirect(stage_tree, &redir_out, next_type, &list); } else if (next_type == PAR_LEFT && stage_tree->type == NONE) { // Can't have two subcommands in a stage advance(&list); // Advance past left parentheses CMD* subcmd_tree = make_cmd(&list); error = subcmd_tree->type == ERROR || type(list) != PAR_RIGHT; stage_tree->type = SUBCMD; stage_tree->left = subcmd_tree; } else { error = true; } if (error) { freeCMD(stage_tree); return make_error_cmd("Invalid stage"); } advance(&list); } // Make sure we didn't double-redirect if (ISPIPE(next_type) && redir_out) { freeCMD(stage_tree); return make_error_cmd("Double redirect - pipe and >"); } // Make sure there was actually an argument if (stage_tree->type == NONE) { freeCMD(stage_tree); return make_error_cmd("No arguments for simple command"); } assert(stage_tree->type != NONE); *list_ref = list; return stage_tree; }