/* "script.c" argv tricks for `#!' scripts. * Copyright (C) 1994-1999 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ /* Author: Aubrey Jaffer */ #include #include "scm.h" #ifdef __IBMC__ # include #endif /* def __IBMC__ */ #ifdef linux # include /* for X_OK define */ #endif /* def linux */ #ifdef __SVR4 # include /* for X_OK define */ #else # ifdef __sgi__ # include /* for X_OK define */ # endif /* def __sgi__ */ #endif /* def __SVR4 */ #ifdef _WIN32 # define WIN32_LEAN_AND_MEAN # include /* GetModuleFileName */ #endif /* Concatentate str2 onto str1 at position n and return concatenated string if file exists; 0 otherwise. */ char *scm_cat_path(str1, str2, n) char *str1; const char *str2; long n; { if (!n) n = strlen(str2); if (str1) { long len = strlen(str1); str1 = (char *)realloc(str1, (sizet)(len + n + 1)); if (!str1) return 0L; strncat(str1 + len, str2, n); return str1; } str1 = (char *)malloc((sizet)(n + 1)); if (!str1) return 0L; str1[0] = 0; strncat(str1, str2, n); return str1; } char *scm_try_path(path) char *path; { FILE *f; /* fprintf(stderr, "Trying %s\n", path);fflush(stderr); */ if (!path) return 0L; SYSCALL(f = fopen(path, "r");); if (f) { fclose(f); return path; } free(path); return 0L; } char *scm_sep_init_try(path, sep, initname) char *path; const char *sep, *initname; { if (path) path = scm_cat_path(path, sep, 0L); if (path) path = scm_cat_path(path, initname, 0L); return scm_try_path(path); } #ifndef LINE_INCREMENTORS # define LINE_INCREMENTORS '\n' # ifdef MSDOS # define WHITE_SPACES ' ':case '\t':case '\r':case '\f':case 26 # else # define WHITE_SPACES ' ':case '\t':case '\r':case '\f' # endif /* def MSDOS */ #endif /* ndef LINE_INCREMENTORS */ #ifndef MAXPATHLEN # define MAXPATHLEN 80 #endif /* ndef MAXPATHLEN */ #ifndef X_OK # define X_OK 1 #endif /* ndef X_OK */ #ifdef HAVE_UNIX # include char *script_find_executable(name) const char *name; { char tbuf[MAXPATHLEN]; int i = 0; FILE *f; /* fprintf(stderr, "s_f_e checking access %s ->%d\n", name, access(name, X_OK)); fflush(stderr); */ if (access(name, X_OK)) return 0L; f = fopen(name, "r"); if (!f) return 0L; if ((fgetc(f)=='#') && (fgetc(f)=='!')) { while (1) switch (tbuf[i++] = fgetc(f)) { case ' ': if (1==i) {i--; break;} case '\t':case '\r':case '\f': case EOF: tbuf[--i] = 0; fclose(f); if (0==i) return 0L; return scm_cat_path(0L, tbuf, 0L); } } fclose(f); return scm_cat_path(0L, name, 0L); } #endif /* unix */ /* Given dld_find_executable()'s best guess for the pathname of this executable, find (and verify the existence of) initname in the implementation-vicinity of this program. Returns a newly allocated string if successful, 0 if not */ char *find_impl_file(exec_path, generic_name, initname, sep) const char *exec_path; const char *generic_name, *initname, *sep; { char *sepptr = strrchr(exec_path, sep[0]); char *extptr = exec_path + strlen(exec_path); char *path = 0; #ifdef _WIN32 char exec_buf[MAX_PATH]; HMODULE mod = GetModuleHandle(0); /* Returns module handle to current executable. */ if (mod) { GetModuleFileName(mod, exec_buf, sizeof(exec_buf)); exec_path = exec_buf; } #endif /*fprintf(stderr, "dld_find_e %s\n", exec_path); fflush(stderr);*/ sepptr = strrchr(exec_path, sep[0]); extptr = exec_path + strlen(exec_path); if (sepptr) { long sepind = sepptr - exec_path + 1L; /* In case exec_path is in the source directory, look first in exec_path's directory. */ path = scm_cat_path(0L, exec_path, sepind - 1L); path = scm_sep_init_try(path, sep, initname); if (path) return path; #ifdef MSDOS if (!strcmp(extptr - 4, ".exe") || !strcmp(extptr - 4, ".com") || !strcmp(extptr - 4, ".EXE") || !strcmp(extptr - 4, ".COM")) extptr = extptr - 4; #endif /* def MSDOS */ if (generic_name && !strncmp(exec_path + sepind, generic_name, extptr - exec_path)) generic_name = 0; /* If exec_path is in directory "exe" or "bin": */ path = scm_cat_path(0L, exec_path, sepind - 1L); sepptr = path + sepind - 4; if (!strcmp(sepptr, "exe") || !strcmp(sepptr, "bin") || !strcmp(sepptr, "EXE") || !strcmp(sepptr, "BIN")) { char *peer; /* Look for initname in peer directory "lib". */ if (path) { strncpy(sepptr, "lib", 3); path = scm_sep_init_try(path, sep, initname); if (path) return path; } /* Look for initname in peer directories "lib" and "src" in subdirectory with the name of the executable (sans any type extension like .EXE). */ for (peer="lib";!0;peer="src") { path = scm_cat_path(0L, exec_path, extptr - exec_path + 0L); if (path) { strncpy(path + sepind - 4, peer, 3); path[extptr - exec_path] = 0; path = scm_sep_init_try(path, sep, initname); if (path) return path; } if (!strcmp(peer, "src")) break; } if (generic_name) { /* Look for initname in peer directories "lib" and "src" in subdirectory with the generic name. */ for (peer="lib";!0;peer="src") { path = scm_cat_path(0L, exec_path, sepind); if (path) { strncpy(path + sepind - 4, peer, 3); path = scm_cat_path(path, generic_name, 0L); path = scm_sep_init_try(path, sep, initname); if (path) return path; } if (!strcmp(peer, "src")) break; }} /* Look for initname in executable-name peer directory. */ path = scm_cat_path(0L, exec_path, sepind); if (path) { path[sepind - 4] = 0; path = scm_cat_path(path, &exec_path[sepind], 0L); path = scm_sep_init_try(path, sep, initname); if (path) return path; } if (generic_name) { /* Look for initname in generic peer directory. */ path = scm_cat_path(0L, exec_path, sepind); if (path) { path[sepind - 4] = 0; path = scm_cat_path(path, generic_name, 0L); path = scm_sep_init_try(path, sep, initname); if (path) return path; } } } #ifdef MSDOS if (strlen(extptr)) { /* If exec_path has type extension, look in a subdirectory with the name of the executable sans the executable file's type extension. */ path = scm_cat_path(0L, exec_path, extptr - exec_path + 0L); path = scm_sep_init_try(path, sep, initname); if (path) return path; if (generic_name) { /* Also look in generic_name subdirectory. */ path = scm_cat_path(0L, exec_path, sepind); if (path) path = scm_cat_path(path, generic_name, 0L); path = scm_sep_init_try(path, sep, initname); if (path) return path; }} #endif /* def MSDOS */ } else { /* We don't have a parse-able exec_path. The only path to try is just initname. */ path = scm_cat_path(0L, initname, 0L); if (path) path = scm_try_path(path); if (path) return path; } return 0L; } char *script_read_arg(f) FILE *f; { sizet tlen = 1; int tind = 0, qted = 0, chr; char *tbuf = (char *)malloc((1 + tlen) * sizeof(char)); if (!tbuf) return 0L; while (1) switch (chr = getc(f)) { case WHITE_SPACES: continue; case LINE_INCREMENTORS: case EOF: free(tbuf); return 0L; default: goto morearg; } morearg: while (1) { switch (tbuf[tind++] = chr) { case WHITE_SPACES: case LINE_INCREMENTORS: if (qted) break; case EOF: goto endarg; case '!': if (qted) break; switch (chr = getc(f)) { case '#': if (1==tind) return 0L; goto endarg; default: tbuf[tind++] = chr; break; } break; case '"': qted = !qted; tind--; break; case '\\': switch (tbuf[tind - 1] = getc(f)) { case '\n': --tind; break; case 'n': tbuf[tind - 1] = '\n'; break; case 'r': tbuf[tind - 1] = '\r'; break; case 't': tbuf[tind - 1] = '\t'; break; case 'b': tbuf[tind - 1] = '\b'; break; /* case '0': tbuf[tind - 1] = '\0'; break; */ default:; } default:; } if (tind >= tlen) { tbuf = (char *)realloc(tbuf, (1 + (2 * tlen)) * sizeof(char)); if (!tbuf) return 0L; tlen = 2 * tlen; } chr = getc(f); } endarg: tbuf[--tind] = 0; return tbuf; } int script_meta_arg_P(arg) const char *arg; { if ('\\' != arg[0]) return 0L; #ifdef MSDOS return !arg[1]; #else switch (arg[1]) { case 0: case '%': case WHITE_SPACES: return !0; default: return 0L;} #endif } char **script_process_argv(argc, argv) int argc; const char **argv; { int nargc = argc, argi = 1, nargi = 1; char *narg, **nargv; if (!(argc > 2 && script_meta_arg_P(argv[1]))) return 0L; if (!(nargv = (char **)malloc((1 + nargc) * sizeof(char *)))) return 0L; nargv[0] = argv[0]; while (((argi+1) < argc) && (script_meta_arg_P(argv[argi]))) { FILE *f = fopen(argv[++argi], "r"); if (f) { nargc--; /* to compensate for replacement of '\\' */ while (1) switch (getc(f)) { case EOF: return 0L; default: continue; case '\n': goto found_args; } found_args: while ((narg = script_read_arg(f))) if (!(nargv = (char **)realloc(nargv, (1 + ++nargc) * sizeof(char *)))) return 0L; else nargv[nargi++] = narg; fclose(f); nargv[nargi++] = argv[argi++]; } } while (argi <= argc) nargv[nargi++] = argv[argi++]; return nargv; } int script_count_argv(argv) const char **argv; { int argc = 0; while (argv[argc]) argc++; return argc; } #ifdef __IBMC__ # define MSDOS #endif #ifdef MSDOS char *dld_find_executable(file) const char *file; { /* fprintf(stderr, "dld_find_executable %s -> %s\n", file, scm_cat_path(0L, file, 0L)); fflush(stderr); */ return scm_cat_path(0L, file, 0L); } #endif /* def MSDOS */