t_dlist *tokenizer(char *line, t_lnv *envlist) { t_dlist *list; t_dlist *cur; int i; char *exp; i = 0; if (line == NULL || !line[(i)]) return (NULL); list = NULL; if ((exp = expand_variables(line, envlist)) == NULL) return (NULL); while ((exp[i])) { skipspace(exp, &i); if (exp[i]) { if (((list = add_dlist_elem(list)) == NULL) || ((cur = goto_last_dlist(list)) == NULL) || ((cur->data = get_next_token(exp, &i)) == NULL)) return (NULL); } } gbgc_free(NULL, exp); return (list); }
std::string filename_map::expand_variables(it & begin, it end, bool close) const { std::string result; result.reserve(size_t(end - begin)); while(begin != end) { // Flush everything before the next bracket it pos = begin; while(pos != end && *pos != '{' && *pos != '}') { pos++; } result.append(begin, pos); begin = pos; if(pos == end) { // No more variables or escape sequences break; } begin++; if(close && *pos == '}') { // Current context closed break; } if(!close && *pos == '}') { // literal '}' character result.push_back('}'); continue; } // '{{' escape sequence if(begin != end && *begin == '{') { result.push_back('{'); begin++; continue; } // Recursively expand variables until we reach the end of this context result.append(lookup(expand_variables(begin, end, true))); } return result; }
std::string filename_map::convert(std::string input) const { // Convert paths to lower-case if requested if(lowercase) { std::transform(input.begin(), input.end(), input.begin(), ::tolower); } // Don't expand variables if requested if(!expand) { return input; } it begin = input.begin(); std::string expanded = expand_variables(begin, input.end()); return shorten_path(expanded); }
/* * @brief minimal realization of wordexp according to IEEE standard * shall perform word expansion as described in the Shell * expansion of ´$NAME´ or ´${NAME}´ * expansion of ´*´ and ´?´ * @param words: pointer to a string containing one or more words to be expanded * but here only one word supported */ int wordexp(const char *words, wordexp_t *we, int flags) { int i; int error; char *words_expanded; #ifdef HAVE_API_WIN32_BASE glob_t pglob; #endif assert(we != NULL); assert(words != NULL); /* expansion of ´$NAME´ or ´${NAME}´ */ words_expanded=expand_variables(words); #ifdef HAVE_API_WIN32_BASE /* expansion of ´*´, ´?´ */ error=glob(words_expanded, 0, NULL, &pglob); if (!error) { /* copy the content of struct of glob into struct of wordexp */ we->we_wordc = pglob.gl_pathc; we->we_offs = pglob.gl_offs; we->we_wordv = malloc(we->we_wordc * sizeof(char*)); for (i=0; i<we->we_wordc; i++) { we->we_wordv[i] = strdup(pglob.gl_pathv[i]); } globfree(&pglob); free(words_expanded); } else { #endif we->we_wordc = 1; we->we_wordv = malloc(sizeof(char*)); we->we_wordv[0] = words_expanded; #ifdef HAVE_API_WIN32_BASE } #endif return error; }
static int configure_via_resource(LPWSTR basename, LPWSTR exepath, LPWSTR exep, LPWSTR *prefix_args, int *prefix_args_len, int *is_git_command, LPWSTR *working_directory, int *full_path, int *skip_arguments, int *allocate_console, int *show_console, int *append_quote_to_cmdline) { int i, id, minimal_search_path, needs_a_console, no_hide, wargc; int append_quote; LPWSTR *wargv; WCHAR *app_id; #define BUFSIZE 65536 static WCHAR buf[BUFSIZE]; LPWSTR buf2 = buf; int len; for (id = 0; ; id++) { minimal_search_path = 0; needs_a_console = 0; no_hide = 0; append_quote = 0; app_id = NULL; len = LoadString(NULL, id, buf, BUFSIZE); if (!len) { if (!id) return 0; /* no resources found */ fwprintf(stderr, L"Need a valid command-line; " L"Edit the string resources accordingly\n"); exit(1); } if (len >= BUFSIZE) { fwprintf(stderr, L"Could not read resource (too large)\n"); exit(1); } for (;;) { if (strip_prefix(buf, &len, L"MINIMAL_PATH=1 ")) minimal_search_path = 1; else if (strip_prefix(buf, &len, L"ALLOC_CONSOLE=1 ")) needs_a_console = 1; else if (strip_prefix(buf, &len, L"SHOW_CONSOLE=1 ")) no_hide = 1; else if (strip_prefix(buf, &len, L"APPEND_QUOTE=1 ")) append_quote = 1; else if (strip_prefix(buf, &len, L"APP_ID=")) { LPWSTR space = wcschr(buf, L' '); size_t app_id_len = space - buf; if (!space) { len -= 7; memmove(buf, buf + 7, len * sizeof(WCHAR)); break; } app_id = wcsdup(buf); app_id[app_id_len] = L'\0'; len -= app_id_len + 1; memmove(buf, buf + app_id_len + 1, len * sizeof(WCHAR)); } else break; } buf[len] = L'\0'; if (!id) SetEnvironmentVariable(L"EXEPATH", exepath); buf2 = expand_variables(buf, BUFSIZE); extract_first_arg(buf2, exepath, exep); if (_waccess(exep, 0) != -1) break; fwprintf(stderr, L"Skipping command-line '%s'\n('%s' not found)\n", buf2, exep); if (app_id) free(app_id); } *prefix_args = buf2; *prefix_args_len = wcslen(buf2); *is_git_command = 0; wargv = CommandLineToArgvW(GetCommandLine(), &wargc); for (i = 1; i < wargc; i++) { if (!wcscmp(L"--no-cd", wargv[i])) *working_directory = NULL; else if (!wcscmp(L"--cd-to-home", wargv[i])) *working_directory = (LPWSTR) 1; else if (!wcsncmp(L"--cd=", wargv[i], 5)) *working_directory = wcsdup(wargv[i] + 5); else if (!wcscmp(L"--minimal-search-path", wargv[i])) minimal_search_path = 1; else if (!wcscmp(L"--no-minimal-search-path", wargv[i])) minimal_search_path = 0; else if (!wcscmp(L"--needs-console", wargv[i])) needs_a_console = 1; else if (!wcscmp(L"--no-needs-console", wargv[i])) needs_a_console = 0; else if (!wcscmp(L"--hide", wargv[i])) no_hide = 0; else if (!wcscmp(L"--no-hide", wargv[i])) no_hide = 1; else if (!wcscmp(L"--append-quote", wargv[i])) append_quote = 1; else if (!wcscmp(L"--no-append-quote", wargv[i])) append_quote = -1; else if (!wcsncmp(L"--command=", wargv[i], 10)) { LPWSTR expanded; wargv[i] += 10; expanded = expand_variables(wargv[i], wcslen(wargv[i])); if (expanded == wargv[i]) expanded = wcsdup(expanded); extract_first_arg(expanded, exepath, exep); *prefix_args = expanded; *prefix_args_len = wcslen(*prefix_args); *skip_arguments = i; break; } else if (!wcsncmp(L"--app-id=", wargv[i], 9)) { free(app_id); app_id = wcsdup(wargv[i] + 9); } else break; *skip_arguments = i; } if (minimal_search_path) *full_path = 0; if (needs_a_console) *allocate_console = 1; if (no_hide) *show_console = 1; if (append_quote) *append_quote_to_cmdline = append_quote == 1; if (app_id) set_app_id(app_id); LocalFree(wargv); return 1; }
/// Expand all environment variables in the string *ptr. /// /// This function is slow, fragile and complicated. There are lots of little corner cases, like /// $$foo should do a double expansion, $foo$bar should not double expand bar, etc. Also, it's easy /// to accidentally leak memory on array out of bounds errors an various other situations. All in /// all, this function should be rewritten, split out into multiple logical units and carefully /// tested. After that, it can probably be optimized to do fewer memory allocations, fewer string /// scans and overall just less work. But until that happens, don't edit it unless you know exactly /// what you are doing, and do proper testing afterwards. /// /// This function operates on strings backwards, starting at last_idx. /// /// Note: last_idx is considered to be where it previously finished procesisng. This means it /// actually starts operating on last_idx-1. As such, to process a string fully, pass string.size() /// as last_idx instead of string.size()-1. static bool expand_variables(const wcstring &instr, std::vector<completion_t> *out, size_t last_idx, parse_error_list_t *errors) { const size_t insize = instr.size(); // last_idx may be 1 past the end of the string, but no further. assert(last_idx <= insize && "Invalid last_idx"); if (last_idx == 0) { append_completion(out, instr); return true; } // Locate the last VARIABLE_EXPAND or VARIABLE_EXPAND_SINGLE bool is_single = false; size_t varexp_char_idx = last_idx; while (varexp_char_idx--) { const wchar_t c = instr.at(varexp_char_idx); if (c == VARIABLE_EXPAND || c == VARIABLE_EXPAND_SINGLE) { is_single = (c == VARIABLE_EXPAND_SINGLE); break; } } if (varexp_char_idx >= instr.size()) { // No variable expand char, we're done. append_completion(out, instr); return true; } // Get the variable name. const size_t var_name_start = varexp_char_idx + 1; size_t var_name_stop = var_name_start; while (var_name_stop < insize) { const wchar_t nc = instr.at(var_name_stop); if (nc == VARIABLE_EXPAND_EMPTY) { var_name_stop++; break; } if (!valid_var_name_char(nc)) break; var_name_stop++; } assert(var_name_stop >= var_name_start && "Bogus variable name indexes"); const size_t var_name_len = var_name_stop - var_name_start; // It's an error if the name is empty. if (var_name_len == 0) { if (errors) { parse_util_expand_variable_error(instr, 0 /* global_token_pos */, varexp_char_idx, errors); } return false; } // Get the variable name as a string, then try to get the variable from env. const wcstring var_name(instr, var_name_start, var_name_len); // Do a dirty hack to make sliced history fast (#4650). We expand from either a variable, or a // history_t. Note that "history" is read only in env.cpp so it's safe to special-case it in // this way (it cannot be shadowed, etc). history_t *history = nullptr; maybe_t<env_var_t> var{}; if (var_name == L"history") { // We do this only on the main thread, matching env.cpp. if (is_main_thread()) { history = reader_get_history(); } } else if (var_name != wcstring{VARIABLE_EXPAND_EMPTY}) { var = env_get(var_name); } // Parse out any following slice. // Record the end of the variable name and any following slice. size_t var_name_and_slice_stop = var_name_stop; bool all_values = true; const size_t slice_start = var_name_stop; // List of indexes, and parallel array of source positions of each index in the variable list. std::vector<long> var_idx_list; std::vector<size_t> var_pos_list; if (slice_start < insize && instr.at(slice_start) == L'[') { all_values = false; const wchar_t *in = instr.c_str(); wchar_t *slice_end; // If a variable is missing, behave as though we have one value, so that $var[1] always // works. size_t effective_val_count = 1; if (var) { effective_val_count = var->as_list().size(); } else if (history) { effective_val_count = history->size(); } size_t bad_pos = parse_slice(in + slice_start, &slice_end, var_idx_list, var_pos_list, effective_val_count); if (bad_pos != 0) { append_syntax_error(errors, slice_start + bad_pos, L"Invalid index value"); return false; } var_name_and_slice_stop = (slice_end - in); } if (!var && !history) { // Expanding a non-existent variable. if (!is_single) { // Normal expansions of missing variables successfully expand to nothing. return true; } else { // Expansion to single argument. // Replace the variable name and slice with VARIABLE_EXPAND_EMPTY. wcstring res(instr, 0, varexp_char_idx); if (!res.empty() && res.back() == VARIABLE_EXPAND_SINGLE) { res.push_back(VARIABLE_EXPAND_EMPTY); } res.append(instr, var_name_and_slice_stop, wcstring::npos); return expand_variables(res, out, varexp_char_idx, errors); } } // Ok, we have a variable or a history. Let's expand it. // Start by respecting the sliced elements. assert((var || history) && "Should have variable or history here"); wcstring_list_t var_item_list; if (all_values) { if (history) { history->get_history(var_item_list); } else { var->to_list(var_item_list); } } else { // We have to respect the slice. if (history) { // Ask history to map indexes to item strings. // Note this may have missing entries for out-of-bounds. auto item_map = history->items_at_indexes(var_idx_list); for (long item_index : var_idx_list) { auto iter = item_map.find(item_index); if (iter != item_map.end()) { var_item_list.push_back(iter->second); } } } else { const wcstring_list_t &all_var_items = var->as_list(); for (long item_index : var_idx_list) { // Check that we are within array bounds. If not, skip the element. Note: // Negative indices (`echo $foo[-1]`) are already converted to positive ones // here, So tmp < 1 means it's definitely not in. // Note we are 1-based. if (item_index >= 1 && size_t(item_index) <= all_var_items.size()) { var_item_list.push_back(all_var_items.at(item_index - 1)); } } } } if (is_single) { wcstring res(instr, 0, varexp_char_idx); if (!res.empty()) { if (res.back() != VARIABLE_EXPAND_SINGLE) { res.push_back(INTERNAL_SEPARATOR); } else if (var_item_list.empty() || var_item_list.front().empty()) { // First expansion is empty, but we need to recursively expand. res.push_back(VARIABLE_EXPAND_EMPTY); } } // Append all entries in var_item_list, separated by spaces. // Remove the last space. if (!var_item_list.empty()) { for (const wcstring &item : var_item_list) { res.append(item); res.push_back(L' '); } res.pop_back(); } res.append(instr, var_name_and_slice_stop, wcstring::npos); return expand_variables(res, out, varexp_char_idx, errors); } else { // Normal cartesian-product expansion. for (const wcstring &item : var_item_list) { if (varexp_char_idx == 0 && var_name_and_slice_stop == insize) { append_completion(out, item); } else { wcstring new_in(instr, 0, varexp_char_idx); if (!new_in.empty()) { if (new_in.back() != VARIABLE_EXPAND) { new_in.push_back(INTERNAL_SEPARATOR); } else if (item.empty()) { new_in.push_back(VARIABLE_EXPAND_EMPTY); } } new_in.append(item); new_in.append(instr, var_name_and_slice_stop, wcstring::npos); if (!expand_variables(new_in, out, varexp_char_idx, errors)) { return false; } } } } return true; }
/* Make the insides of an about box. */ static void about_build( iDialog *idlg, GtkWidget *work ) { /* Translators: translate this to a credit for you, and it'll appear in * the About box. */ char *translator_credits = _( "translator_credits" ); GtkWidget *hb; GtkWidget *lab; char txt[MAX_DIALOG_TEXT]; char txt2[MAX_DIALOG_TEXT]; VipsBuf buf = VIPS_BUF_STATIC( txt ); GtkWidget *image; im_snprintf( txt2, MAX_DIALOG_TEXT, _( "About %s." ), PACKAGE ); vips_buf_appendf( &buf, "<b><big>%s</big></b>\n\n", txt2 ); im_snprintf( txt2, MAX_DIALOG_TEXT, _( "%s is an image processing package." ), PACKAGE ); vips_buf_appendf( &buf, "%s\n\n", txt2 ); im_snprintf( txt2, MAX_DIALOG_TEXT, _( "%s comes with ABSOLUTELY NO WARRANTY. This is " "free software and you are welcome to redistribute " "it under certain conditions, see http://www.gnu.org." ), PACKAGE ); vips_buf_appendf( &buf, "%s\n\n", txt2 ); im_snprintf( txt2, MAX_DIALOG_TEXT, _( NIP_COPYRIGHT ), PACKAGE ); vips_buf_appendf( &buf, "%s\n\n", txt2 ); { char buf1[FILENAME_MAX]; char buf2[FILENAME_MAX]; im_snprintf( buf1, FILENAME_MAX, "%s" G_DIR_SEPARATOR_S "start", get_savedir() ); expand_variables( buf1, buf2 ); nativeize_path( buf2 ); escape_markup( buf2, buf1, FILENAME_MAX ); vips_buf_appendf( &buf, "<b>%s:</b> %s\n", _( "Personal start folder" ), buf1 ); } vips_buf_appendf( &buf, "<b>%s:</b> %s\n", _( "Homepage" ), VIPS_HOMEPAGE ); escape_markup( im_version_string(), txt2, MAX_DIALOG_TEXT ); vips_buf_appendf( &buf, "<b>%s:</b> %s\n", _( "Linked to VIPS" ), txt2 ); escape_markup( IM_VERSION_STRING, txt2, MAX_DIALOG_TEXT ); vips_buf_appendf( &buf, "<b>%s:</b> %s\n", _( "Built against VIPS" ), txt2 ); escape_markup( PACKAGE, txt2, MAX_DIALOG_TEXT ); vips_buf_appendf( &buf, "<b>$PACKAGE:</b> %s\n", txt2 ); escape_markup( VERSION, txt2, MAX_DIALOG_TEXT ); vips_buf_appendf( &buf, "<b>$VERSION:</b> %s\n", txt2 ); escape_markup( NN( g_getenv( "VIPSHOME" ) ), txt2, MAX_DIALOG_TEXT ); vips_buf_appendf( &buf, "<b>$VIPSHOME:</b> %s\n", txt2 ); escape_markup( NN( g_getenv( "HOME" ) ), txt2, MAX_DIALOG_TEXT ); vips_buf_appendf( &buf, "<b>$HOME:</b> %s\n", txt2 ); escape_markup( NN( g_getenv( "SAVEDIR" ) ), txt2, MAX_DIALOG_TEXT ); vips_buf_appendf( &buf, "<b>$SAVEDIR:</b> %s\n", txt2 ); escape_markup( PATH_TMP, txt2, MAX_DIALOG_TEXT ); vips_buf_appendf( &buf, "<b>%s:</b> %s\n", _( "Temp files in" ), txt2 ); if( strcmp( translator_credits, "translator_credits" ) != 0 ) { vips_buf_appendf( &buf, "\n" ); vips_buf_appends( &buf, translator_credits ); } vips_buf_appendf( &buf, "\n" ); mainw_find_disc( &buf ); /* Expands to (eg.) "14GB free in /pics/tmp" */ vips_buf_appendf( &buf, _( " in \"%s\"" ), PATH_TMP ); vips_buf_appends( &buf, "\n" ); vips_buf_appendf( &buf, _( "%d cells in heap, %d cells free, %d cells maximum" ), reduce_context->heap->ncells, reduce_context->heap->nfree, reduce_context->heap->max_fn( reduce_context->heap ) ); vips_buf_appends( &buf, "\n" ); vips_buf_appendf( &buf, _( "%d vips calls cached by nip2" ), cache_history_size ); vips_buf_appends( &buf, "\n" ); vips_buf_appendf( &buf, _( "%d vips operations cached by libvips" ), vips_cache_get_size() ); vips_buf_appends( &buf, "\n" ); vips_buf_appendf( &buf, _( "using %d threads" ), im_concurrency_get() ); vips_buf_appends( &buf, "\n" ); vips_buf_appendf( &buf, _( "%d pixel buffers in vips" ), vips_tracked_get_allocs() ); vips_buf_appends( &buf, "\n" ); vips_buf_append_size( &buf, vips_tracked_get_mem() ); vips_buf_appendf( &buf, _( " of ram in pixel buffers" ) ); vips_buf_appends( &buf, "\n" ); vips_buf_append_size( &buf, vips_tracked_get_mem_highwater() ); vips_buf_appendf( &buf, _( " of ram highwater mark" ) ); vips_buf_appends( &buf, "\n" ); hb = gtk_hbox_new( FALSE, 0 ); gtk_container_border_width( GTK_CONTAINER( hb ), 10 ); gtk_container_add( GTK_CONTAINER( work ), hb ); gtk_widget_show( hb ); image = image_new_from_file( "$VIPSHOME/share/$PACKAGE/data/vips-128.png" ); gtk_box_pack_start( GTK_BOX( hb ), image, FALSE, FALSE, 2 ); gtk_widget_show( image ); lab = gtk_label_new( "" ); gtk_label_set_markup( GTK_LABEL( lab ), vips_buf_all( &buf ) ); gtk_label_set_justify( GTK_LABEL( lab ), GTK_JUSTIFY_LEFT ); gtk_label_set_selectable( GTK_LABEL( lab ), TRUE ); gtk_label_set_line_wrap( GTK_LABEL( lab ), TRUE ); gtk_box_pack_start( GTK_BOX( hb ), lab, FALSE, FALSE, 2 ); gtk_widget_show( lab ); }