/* return codes: -1 is error; 0 is everything OK but did not find shebang; if shebang is found, does an exec */ static int attempt_shebang_launch(char *program_to_launch, char *origin, char *profile_bin_dir, int argc, char **argv) { /* Attempt to open the file to scan for a shebang, which we handle ourself. (If a script is executable but not readable then no interpreter can read it anyway; assume such a thing doesn't exist.) */ FILE *f; char shebang[SHEBANG_MAX], interpreter[SHEBANG_MAX], arg[SHEBANG_MAX]; char *r, *s, *interpreter_part, *arg_part = NULL; char **new_argv; char **p; /* read first line */ if ((f = fopen(program_to_launch, "r")) == NULL) return -1; r = fgets(shebang, SHEBANG_MAX, f); fclose(f); if (r == NULL) return -1; /* Reference: http://homepages.cwi.nl/~aeb/std/hashexclam.html */ /* TODO: There's a Mac OS X special case on interpreter handling.. */ /* shebang header */ if (r[0] != '#' || r[1] != '!') return 0; /* shebang not present return code */ r += 2; skip_whites(&r); if (r == '\0') return -1; interpreter_part = r; skip_nonwhites(&r); if (*r != '\0') { *r = '\0'; /* terminate 'interpreter' string */ ++r; skip_whites(&r); /* there may be an argument: */ arg_part = r; rstrip(arg_part); } if (expandvars(interpreter, interpreter_part, origin, profile_bin_dir, SHEBANG_MAX) != 0) return -1; if (arg_part != NULL) { if (expandvars(arg, arg_part, origin, profile_bin_dir, SHEBANG_MAX) != 0) return -1; } else { arg[0] = '\0'; } if (debug) { fprintf(stderr, "%sshebang_cmd=%s\n", debug_header, interpreter); fprintf(stderr, "%sshebang_arg=%s\n", debug_header, arg); } /* Done parsing, do launch */ new_argv = malloc(sizeof(char*) * (argc + 3)); p = new_argv; p++; /* we'll set interpreter below */ if (arg[0]) *p++ = arg; /* substitute argv[0] with program_to_launch */ argv++; *p++ = program_to_launch; while (*argv) *p++ = *argv++; *p = NULL; /* The interpreter string may contain : to separate many possible interpreters; try them in turn. */ s = interpreter; for (;;) { r = strstr(s, ":"); if (r != NULL) r[0] = '\0'; new_argv[0] = s; execv(s, new_argv); if (r == NULL) break; s = r + 1; } /* failed to execute */ free(new_argv); return -1; }
std::string path::expand(const std::string &path) { return normpath(expandvars(expanduser(path))); }