// Copies the string, prepending it with the startup working directory, and // expanding %p and %q entries. Returns a new, malloc'd string. Char* VG_(expand_file_name)(Char* option_name, Char* format) { static Char base_dir[VKI_PATH_MAX]; Int len, i = 0, j = 0; Char* out; Bool ok = VG_(get_startup_wd)(base_dir, VKI_PATH_MAX); tl_assert(ok); if (VG_STREQ(format, "")) { // Empty name, bad. VG_(umsg)("%s: filename is empty", option_name); goto bad; } // If 'format' starts with a '~', abort -- the user probably expected the // shell to expand but it didn't (see bug 195268 for details). This means // that we don't allow a legitimate filename beginning with '~' but that // seems very unlikely. if (format[0] == '~') { VG_(umsg)("%s: filename begins with '~'\n", option_name); VG_(umsg)("You probably expected the shell to expand the '~', but it\n"); VG_(umsg)("didn't. The rules for '~'-expansion " "vary from shell to shell.\n"); VG_(umsg)("You might have more luck using $HOME instead.\n"); goto bad; } // If 'format' starts with a '/', do not prefix with startup dir. if (format[0] != '/') { j += VG_(strlen)(base_dir); } // The 10 is slop, it should be enough in most cases. len = j + VG_(strlen)(format) + 10; out = VG_(malloc)( "options.efn.1", len ); if (format[0] != '/') { VG_(strcpy)(out, base_dir); out[j++] = '/'; } #define ENSURE_THIS_MUCH_SPACE(x) \ if (j + x >= len) { \ len += (10 + x); \ out = VG_(realloc)("options.efn.2(multiple)", out, len); \ } while (format[i]) { if (format[i] != '%') { ENSURE_THIS_MUCH_SPACE(1); out[j++] = format[i++]; } else { // We saw a '%'. What's next... i++; if ('%' == format[i]) { // Replace '%%' with '%'. ENSURE_THIS_MUCH_SPACE(1); out[j++] = format[i++]; } else if ('p' == format[i]) { // Print the PID. Assume that it's not longer than 10 chars -- // reasonable since 'pid' is an Int (ie. 32 bits). Int pid = VG_(getpid)(); ENSURE_THIS_MUCH_SPACE(10); j += VG_(sprintf)(&out[j], "%d", pid); i++; } else if ('q' == format[i]) { i++; if ('{' == format[i]) { // Get the env var name, print its contents. Char* qualname; Char* qual; i++; qualname = &format[i]; while (True) { if (0 == format[i]) { VG_(message)(Vg_UserMsg, "%s: malformed %%q specifier\n", option_name); goto bad; } else if ('}' == format[i]) { // Temporarily replace the '}' with NUL to extract var // name. format[i] = 0; qual = VG_(getenv)(qualname); if (NULL == qual) { VG_(message)(Vg_UserMsg, "%s: environment variable %s is not set\n", option_name, qualname); format[i] = '}'; // Put the '}' back. goto bad; } format[i] = '}'; // Put the '}' back. i++; break; } i++; } ENSURE_THIS_MUCH_SPACE(VG_(strlen)(qual)); j += VG_(sprintf)(&out[j], "%s", qual); } else { VG_(message)(Vg_UserMsg, "%s: expected '{' after '%%q'\n", option_name); goto bad; } } else { // Something else, abort. VG_(message)(Vg_UserMsg, "%s: expected 'p' or 'q' or '%%' after '%%'\n", option_name); goto bad; } } } ENSURE_THIS_MUCH_SPACE(1); out[j++] = 0; return out; bad: { Char* opt = // 2: 1 for the '=', 1 for the NUL. VG_(malloc)( "options.efn.3", VG_(strlen)(option_name) + VG_(strlen)(format) + 2 ); VG_(strcpy)(opt, option_name); VG_(strcat)(opt, "="); VG_(strcat)(opt, format); VG_(err_bad_option)(opt); } }
// Copies the string, prepending it with the startup working directory, and // expanding %p and %q entries. Returns a new, malloc'd string. HChar* VG_(expand_file_name)(const HChar* option_name, const HChar* format) { const HChar *base_dir; Int len, i = 0, j = 0; HChar* out; base_dir = VG_(get_startup_wd)(); if (VG_STREQ(format, "")) { // Empty name, bad. VG_(fmsg)("%s: filename is empty", option_name); goto bad; } // If 'format' starts with a '~', abort -- the user probably expected the // shell to expand but it didn't (see bug 195268 for details). This means // that we don't allow a legitimate filename beginning with '~' but that // seems very unlikely. if (format[0] == '~') { VG_(fmsg)( "%s: filename begins with '~'\n" "You probably expected the shell to expand the '~', but it\n" "didn't. The rules for '~'-expansion vary from shell to shell.\n" "You might have more luck using $HOME instead.\n", option_name ); goto bad; } len = VG_(strlen)(format) + 1; out = VG_(malloc)( "options.efn.1", len ); #define ENSURE_THIS_MUCH_SPACE(x) \ if (j + x >= len) { \ len += (10 + x); \ out = VG_(realloc)("options.efn.2(multiple)", out, len); \ } while (format[i]) { if (format[i] != '%') { ENSURE_THIS_MUCH_SPACE(1); out[j++] = format[i++]; } else { // We saw a '%'. What's next... i++; if ('%' == format[i]) { // Replace '%%' with '%'. ENSURE_THIS_MUCH_SPACE(1); out[j++] = format[i++]; } else if ('p' == format[i]) { // Print the PID. Assume that it's not longer than 10 chars -- // reasonable since 'pid' is an Int (ie. 32 bits). Int pid = VG_(getpid)(); ENSURE_THIS_MUCH_SPACE(10); j += VG_(sprintf)(&out[j], "%d", pid); i++; } else if ('q' == format[i]) { i++; if ('{' == format[i]) { // Get the env var name, print its contents. HChar *qual; Int begin_qualname = ++i; while (True) { if (0 == format[i]) { VG_(fmsg)("%s: malformed %%q specifier\n", option_name); goto bad; } else if ('}' == format[i]) { Int qualname_len = i - begin_qualname; HChar qualname[qualname_len + 1]; VG_(strncpy)(qualname, format + begin_qualname, qualname_len); qualname[qualname_len] = '\0'; qual = VG_(getenv)(qualname); if (NULL == qual) { VG_(fmsg)("%s: environment variable %s is not set\n", option_name, qualname); goto bad; } i++; break; } i++; } ENSURE_THIS_MUCH_SPACE(VG_(strlen)(qual)); j += VG_(sprintf)(&out[j], "%s", qual); } else { VG_(fmsg)("%s: expected '{' after '%%q'\n", option_name); goto bad; } } else { // Something else, abort. VG_(fmsg)("%s: expected 'p' or 'q' or '%%' after '%%'\n", option_name); goto bad; } } } ENSURE_THIS_MUCH_SPACE(1); out[j++] = 0; // If 'out' is not an absolute path name, prefix it with the startup dir. if (out[0] != '/') { len = VG_(strlen)(base_dir) + 1 + VG_(strlen)(out) + 1; HChar *absout = VG_(malloc)("options.efn.4", len); VG_(strcpy)(absout, base_dir); VG_(strcat)(absout, "/"); VG_(strcat)(absout, out); VG_(free)(out); out = absout; } return out; bad: { HChar* opt = // 2: 1 for the '=', 1 for the NUL. VG_(malloc)( "options.efn.3", VG_(strlen)(option_name) + VG_(strlen)(format) + 2 ); VG_(strcpy)(opt, option_name); VG_(strcat)(opt, "="); VG_(strcat)(opt, format); VG_(fmsg_bad_option)(opt, ""); } }
// Copies the string, prepending it with the startup working directory, and // expanding %p and %q entries. Returns a new, malloc'd string. HChar* VG_(expand_file_name)(const HChar* option_name, const HChar* format) { const HChar *base_dir; Int len, i = 0, j = 0; HChar* out; const HChar *message = NULL; base_dir = VG_(get_startup_wd)(); if (VG_STREQ(format, "")) { // Empty name, bad. message = "No filename given\n"; goto bad; } // If 'format' starts with a '~', abort -- the user probably expected the // shell to expand but it didn't (see bug 195268 for details). This means // that we don't allow a legitimate filename beginning with '~' but that // seems very unlikely. if (format[0] == '~') { message = "Filename begins with '~'\n" "You probably expected the shell to expand the '~', but it\n" "didn't. The rules for '~'-expansion vary from shell to shell.\n" "You might have more luck using $HOME instead.\n"; goto bad; } len = VG_(strlen)(format) + 1; out = VG_(malloc)( "options.efn.1", len ); #define ENSURE_THIS_MUCH_SPACE(x) \ if (j + x >= len) { \ len += (10 + x); \ out = VG_(realloc)("options.efn.2(multiple)", out, len); \ } while (format[i]) { if (format[i] != '%') { ENSURE_THIS_MUCH_SPACE(1); out[j++] = format[i++]; } else { // We saw a '%'. What's next... i++; if ('%' == format[i]) { // Replace '%%' with '%'. ENSURE_THIS_MUCH_SPACE(1); out[j++] = format[i++]; } else if ('p' == format[i]) { // Print the PID. Assume that it's not longer than 10 chars -- // reasonable since 'pid' is an Int (ie. 32 bits). Int pid = VG_(getpid)(); ENSURE_THIS_MUCH_SPACE(10); j += VG_(sprintf)(&out[j], "%d", pid); i++; } else if ('n' == format[i]) { // Print a seq nr. static Int last_pid; static Int seq_nr; Int pid = VG_(getpid)(); if (last_pid != pid) seq_nr = 0; last_pid = pid; seq_nr++; ENSURE_THIS_MUCH_SPACE(10); j += VG_(sprintf)(&out[j], "%d", seq_nr); i++; } else if ('q' == format[i]) { i++; if ('{' == format[i]) { // Get the env var name, print its contents. HChar *qual; Int begin_qualname = ++i; while (True) { if (0 == format[i]) { message = "Missing '}' in %q specifier\n"; goto bad; } else if ('}' == format[i]) { Int qualname_len = i - begin_qualname; HChar qualname[qualname_len + 1]; VG_(strncpy)(qualname, format + begin_qualname, qualname_len); qualname[qualname_len] = '\0'; qual = VG_(getenv)(qualname); if (NULL == qual) { // This memory will leak, But we don't care because // VG_(fmsg_bad_option) will terminate the process. HChar *str = VG_(malloc)("options.efn.3", 100 + qualname_len); VG_(sprintf)(str, "Environment variable '%s' is not set\n", qualname); message = str; goto bad; } i++; break; } i++; } ENSURE_THIS_MUCH_SPACE(VG_(strlen)(qual)); j += VG_(sprintf)(&out[j], "%s", qual); } else { message = "Expected '{' after '%q'\n"; goto bad; } } else { // Something else, abort. message = "Expected 'p' or 'q' or '%' after '%'\n"; goto bad; } } } ENSURE_THIS_MUCH_SPACE(1); out[j++] = 0; // If 'out' is not an absolute path name, prefix it with the startup dir. if (out[0] != '/') { if (base_dir == NULL) { message = "Current working dir doesn't exist, use absolute path\n"; goto bad; } len = VG_(strlen)(base_dir) + 1 + VG_(strlen)(out) + 1; HChar *absout = VG_(malloc)("options.efn.4", len); VG_(strcpy)(absout, base_dir); VG_(strcat)(absout, "/"); VG_(strcat)(absout, out); VG_(free)(out); out = absout; } return out; bad: { vg_assert(message != NULL); // 2: 1 for the '=', 1 for the NUL. HChar opt[VG_(strlen)(option_name) + VG_(strlen)(format) + 2]; VG_(sprintf)(opt, "%s=%s", option_name, format); VG_(fmsg_bad_option)(opt, "%s", message); } }