diff options
Diffstat (limited to 'script.c')
-rw-r--r-- | script.c | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/script.c b/script.c new file mode 100644 index 0000000..e1a63f1 --- /dev/null +++ b/script.c @@ -0,0 +1,384 @@ +/* Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "script.c" argv tricks for `#!' scripts. + Author: Aubrey Jaffer */ + +#include <ctype.h> +#include "scm.h" + +#ifdef __IBMC__ +# include <io.h> +#endif /* def __IBMC__ */ + +#ifdef linux +# include <unistd.h> /* for X_OK define */ +#endif /* def linux */ +#ifdef __svr4__ +# include <unistd.h> /* for X_OK define */ +#else +# ifdef __sgi__ +# include <unistd.h> /* for X_OK define */ +# endif /* def __sgi__ */ +#endif /* def __svr4__ */ + +/* 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 unix +# include <stdio.h> + +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 /*WHITE_SPACES*/ ' ':case '\t':case '\r':case '\f': + case EOF: + tbuf[--i] = 0; + fclose(f); + return scm_cat_path(0L, tbuf, 0L); + } + } + fclose(f); + return scm_cat_path(0L, name, 0L); +} +#endif /* unix */ + +#ifdef MSDOS + +# define DEFAULT_PATH "C:\\DOS" +# define PATH_DELIMITER ';' +# define ABSOLUTE_FILENAME_P(fname) ((fname[0] == '\\') \ + || (fname[0] && (fname[1] == ':'))) + +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 */ + +/* 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 *scm_find_impl_file(exec_path, generic_name, initname, sep) + 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; + /* fprintf(stderr, "dld_find_e %s\n", exec_path); fflush(stderr); */ + 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, "lib", 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; + }}} + +#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) + 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; + 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) + char **argv; +{ + int argc = 0; + while (argv[argc]) argc++; + return argc; +} |