1 /* Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001 Free Software Foundation, Inc.
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2, or (at your option)
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this software; see the file COPYING. If not, write to
14 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
15 * Boston, MA 02111-1307 USA
17 * As a special exception, the Free Software Foundation gives permission
18 * for additional uses of the text contained in its release of GUILE.
20 * The exception is that, if you link the GUILE library with other files
21 * to produce an executable, this does not by itself cause the
22 * resulting executable to be covered by the GNU General Public License.
23 * Your use of that executable is in no way restricted on account of
24 * linking the GUILE library code into it.
26 * This exception does not however invalidate any other reasons why
27 * the executable file might be covered by the GNU General Public License.
29 * This exception applies only to the code released by the
30 * Free Software Foundation under the name GUILE. If you copy
31 * code from other Free Software Foundation releases into a copy of
32 * GUILE, as the General Public License permits, the exception does
33 * not apply to the code that you add in this way. To avoid misleading
34 * anyone as to the status of such modified files, you must delete
35 * this exception notice from them.
37 * If you write modifications of your own for GUILE, it is your choice
38 * whether to permit this exception to apply to your modifications.
39 * If you do not wish that, delete this exception notice. */
41 /* "script.c" argv tricks for `#!' scripts.
42 Authors: Aubrey Jaffer and Jim Blandy */
44 /* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
45 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
51 #include "libguile/_scm.h"
52 #include "libguile/gh.h"
53 #include "libguile/load.h"
54 #include "libguile/version.h"
56 #include "libguile/validate.h"
57 #include "libguile/script.h"
64 #include <unistd.h> /* for X_OK define */
71 /* Concatentate str2 onto str1 at position n and return concatenated
72 string if file exists; 0 otherwise. */
75 scm_cat_path (char *str1
, const char *str2
, long n
)
81 size_t len
= strlen (str1
);
82 str1
= (char *) realloc (str1
, (size_t) (len
+ n
+ 1));
85 strncat (str1
+ len
, str2
, n
);
88 str1
= (char *) malloc ((size_t) (n
+ 1));
92 strncat (str1
, str2
, n
);
98 scm_try_path (char *path
)
101 /* fprintf(stderr, "Trying %s\n", path);fflush(stderr); */
104 SCM_SYSCALL (f
= fopen (path
, "r");
116 scm_sep_init_try (char *path
, const char *sep
, const char *initname
)
119 path
= scm_cat_path (path
, sep
, 0L);
121 path
= scm_cat_path (path
, initname
, 0L);
122 return scm_try_path (path
);
126 #ifndef LINE_INCREMENTORS
127 #define LINE_INCREMENTORS '\n'
129 #define WHITE_SPACES ' ':case '\t':case '\r':case '\f':case 26
131 #define WHITE_SPACES ' ':case '\t':case '\r':case '\f'
132 #endif /* def MSDOS */
133 #endif /* ndef LINE_INCREMENTORS */
136 #define MAXPATHLEN 80
137 #endif /* ndef MAXPATHLEN */
140 #endif /* ndef X_OK */
143 scm_find_executable (const char *name
)
145 char tbuf
[MAXPATHLEN
];
149 /* fprintf(stderr, "s_f_e checking access %s ->%d\n", name, access(name, X_OK)); fflush(stderr); */
150 if (access (name
, X_OK
))
152 f
= fopen (name
, "r");
155 if ((fgetc (f
) == '#') && (fgetc (f
) == '!'))
158 switch (tbuf
[i
++] = fgetc (f
))
160 case /*WHITE_SPACES */ ' ':
167 return scm_cat_path (0L, tbuf
, 0L);
171 return scm_cat_path (0L, name
, 0L);
175 /* Read a \nnn-style escape. We've just read the backslash. */
177 script_get_octal (FILE *f
)
178 #define FUNC_NAME "script_get_octal"
183 for (i
= 0; i
< 3; i
++)
186 if ('0' <= c
&& c
<= '7')
187 value
= (value
* 8) + (c
- '0');
189 SCM_MISC_ERROR ("malformed script: bad octal backslash escape",
198 script_get_backslash (FILE *f
)
199 #define FUNC_NAME "script_get_backslash"
205 case 'a': return '\a';
206 case 'b': return '\b';
207 case 'f': return '\f';
208 case 'n': return '\n';
209 case 'r': return '\r';
210 case 't': return '\t';
211 case 'v': return '\v';
219 case '0': case '1': case '2': case '3':
220 case '4': case '5': case '6': case '7':
222 return script_get_octal (f
);
225 SCM_MISC_ERROR ("malformed script: backslash followed by EOF", SCM_EOL
);
226 return 0; /* not reached? */
229 SCM_MISC_ERROR ("malformed script: bad backslash sequence", SCM_EOL
);
230 return 0; /* not reached? */
237 script_read_arg (FILE *f
)
238 #define FUNC_NAME "script_read_arg"
241 char *buf
= malloc (size
+ 1);
253 c
= script_get_backslash (f
);
254 /* The above produces a new character to add to the argument.
259 size
= (size
+ 1) * 2;
260 buf
= realloc (buf
, size
);
268 /* This may terminate an arg now, but it will terminate the
269 entire list next time through. */
277 /* Otherwise, those characters terminate the argument; fall
285 SCM_MISC_ERROR ("malformed script: TAB in meta-arguments", SCM_EOL
);
286 return 0; /* not reached? */
294 script_meta_arg_P (char *arg
)
314 scm_get_meta_args (int argc
, char **argv
)
316 int nargc
= argc
, argi
= 1, nargi
= 1;
318 if (!(argc
> 2 && script_meta_arg_P (argv
[1])))
320 if (!(nargv
= (char **) malloc ((1 + nargc
) * sizeof (char *))))
323 while (((argi
+ 1) < argc
) && (script_meta_arg_P (argv
[argi
])))
325 FILE *f
= fopen (argv
[++argi
], "r");
328 nargc
--; /* to compensate for replacement of '\\' */
340 while ((narg
= script_read_arg (f
)))
341 if (!(nargv
= (char **) realloc (nargv
,
342 (1 + ++nargc
) * sizeof (char *))))
345 nargv
[nargi
++] = narg
;
347 nargv
[nargi
++] = argv
[argi
++];
351 nargv
[nargi
++] = argv
[argi
++];
356 scm_count_argv (char **argv
)
365 /* For use in error messages. */
366 char *scm_usage_name
= 0;
369 scm_shell_usage (int fatal
, char *message
)
372 fprintf (stderr
, "%s\n", message
);
375 "Usage: %s OPTION ...\n"
376 "Evaluate Scheme code, interactively or from a script.\n"
378 " -s SCRIPT load Scheme source code from FILE, and exit\n"
379 " -c EXPR evalute Scheme expression EXPR, and exit\n"
380 " -- stop scanning arguments; run interactively\n"
381 "The above switches stop argument processing, and pass all\n"
382 "remaining arguments as the value of (command-line).\n"
384 " -l FILE load Scheme source code from FILE\n"
385 " -e FUNCTION after reading script, apply FUNCTION to\n"
386 " command line arguments\n"
387 " -ds do -s script at this point\n"
388 " --debug start with debugging evaluator and backtraces\n"
389 " -q inhibit loading of user init file\n"
390 " --emacs enable Emacs protocol (experimental)\n"
391 " --use-srfi=LS load SRFI modules for the SRFIs in LS,\n"
392 " which is a list of numbers like \"2,13,14\"\n"
393 " -h, --help display this help and exit\n"
394 " -v, --version display version information and exit\n"
395 " \\ read arguments from following script lines\n",
403 /* Some symbols used by the command-line compiler. */
404 SCM_SYMBOL (sym_load
, "load");
405 SCM_SYMBOL (sym_eval_string
, "eval-string");
406 SCM_SYMBOL (sym_command_line
, "command-line");
407 SCM_SYMBOL (sym_begin
, "begin");
408 SCM_SYMBOL (sym_load_user_init
, "load-user-init");
409 SCM_SYMBOL (sym_top_repl
, "top-repl");
410 SCM_SYMBOL (sym_quit
, "quit");
411 SCM_SYMBOL (sym_use_srfis
, "use-srfis");
414 /* Given an array of command-line switches, return a Scheme expression
415 to carry out the actions specified by the switches.
417 If you told me this should have been written in Scheme, I'd
418 probably agree. I'd say I didn't feel comfortable doing that in
419 the present system. You'd say, well, fix the system so you are
420 comfortable doing that. I'd agree again. *shrug*
423 static char guile
[] = "guile";
426 scm_compile_shell_switches (int argc
, char **argv
)
428 SCM tail
= SCM_EOL
; /* We accumulate the list backwards,
429 and then reverse! it before we
431 SCM do_script
= SCM_EOL
; /* The element of the list containing
432 the "load" command, in case we get
434 SCM entry_point
= SCM_EOL
; /* for -e switch */
435 int interactive
= 1; /* Should we go interactive when done? */
436 int inhibit_user_init
= 0; /* Don't load user init file */
437 int use_emacs_interface
= 0;
444 scm_usage_name
= strrchr (argv
[0], '/');
445 if (! scm_usage_name
)
446 scm_usage_name
= argv
[0];
450 if (! scm_usage_name
)
451 scm_usage_name
= guile
;
453 for (i
= 1; i
< argc
; i
++)
455 if (! strcmp (argv
[i
], "-s")) /* load script */
458 scm_shell_usage (1, "missing argument to `-s' switch");
460 /* If we specified the -ds option, do_script points to the
461 cdr of an expression like (load #f); we replace the car
462 (i.e., the #f) with the script name. */
463 if (!SCM_NULLP (do_script
))
465 SCM_SETCAR (do_script
, scm_makfrom0str (argv
[i
]));
469 /* Construct an application of LOAD to the script name. */
470 tail
= scm_cons (scm_cons2 (sym_load
,
471 scm_makfrom0str (argv
[i
]),
480 else if (! strcmp (argv
[i
], "-c")) /* evaluate expr */
483 scm_shell_usage (1, "missing argument to `-c' switch");
484 tail
= scm_cons (scm_cons2 (sym_eval_string
,
485 scm_makfrom0str (argv
[i
]),
493 else if (! strcmp (argv
[i
], "--")) /* end args; go interactive */
499 else if (! strcmp (argv
[i
], "-l")) /* load a file */
502 tail
= scm_cons (scm_cons2 (sym_load
,
503 scm_makfrom0str (argv
[i
]),
507 scm_shell_usage (1, "missing argument to `-l' switch");
510 else if (! strcmp (argv
[i
], "-e")) /* entry point */
513 entry_point
= gh_symbol2scm (argv
[i
]);
515 scm_shell_usage (1, "missing argument to `-e' switch");
518 else if (! strcmp (argv
[i
], "-ds")) /* do script here */
520 /* We put a dummy "load" expression, and let the -s put the
522 if (!SCM_NULLP (do_script
))
523 scm_shell_usage (1, "the -ds switch may only be specified once");
524 do_script
= scm_cons (SCM_BOOL_F
, SCM_EOL
);
525 tail
= scm_cons (scm_cons (sym_load
, do_script
),
529 else if (! strcmp (argv
[i
], "--debug")) /* debug eval + backtraces */
533 SCM_RECORD_POSITIONS_P
= 1;
534 SCM_RESET_DEBUG_MODE
;
537 else if (! strcmp (argv
[i
], "--emacs")) /* use emacs protocol */
538 use_emacs_interface
= 1;
540 else if (! strcmp (argv
[i
], "-q")) /* don't load user init */
541 inhibit_user_init
= 1;
543 else if (! strncmp (argv
[i
], "--use-srfi=", 11)) /* load SRFIs */
545 SCM srfis
= SCM_EOL
; /* List of requested SRFIs. */
546 char * p
= argv
[i
] + 11;
552 num
= strtol (p
, &end
, 10);
555 srfis
= scm_cons (scm_long2num (num
), srfis
);
561 scm_shell_usage (1, "invalid SRFI specification");
567 scm_shell_usage (1, "invalid SRFI specification");
569 if (scm_ilength (srfis
) <= 0)
570 scm_shell_usage (1, "invalid SRFI specification");
571 srfis
= scm_reverse_x (srfis
, SCM_UNDEFINED
);
572 tail
= scm_cons (scm_list_2 (sym_use_srfis
,
573 scm_list_2 (scm_sym_quote
, srfis
)),
577 else if (! strcmp (argv
[i
], "-h")
578 || ! strcmp (argv
[i
], "--help"))
580 scm_shell_usage (0, 0);
584 else if (! strcmp (argv
[i
], "-v")
585 || ! strcmp (argv
[i
], "--version"))
587 /* Print version number. */
589 "Copyright (c) 1995, 1996, 1997, 2000 Free Software Foundation\n"
590 "Guile may be distributed under the terms of the GNU General Public Licence;\n"
591 "certain other uses are permitted as well. For details, see the file\n"
592 "`COPYING', which is included in the Guile distribution.\n"
593 "There is no warranty, to the extent permitted by law.\n",
594 SCM_STRING_CHARS (scm_version ()));
600 fprintf (stderr
, "%s: Unrecognized switch `%s'\n",
601 scm_usage_name
, argv
[i
]);
602 scm_shell_usage (1, 0);
606 /* Check to make sure the -ds got a -s. */
607 if (!SCM_NULLP (do_script
))
608 scm_shell_usage (1, "the `-ds' switch requires the use of `-s' as well");
610 /* Make any remaining arguments available to the
611 script/command/whatever. */
612 scm_set_program_arguments (argc
? argc
- i
: 0, argv
+ i
, argv0
);
614 /* If the --emacs switch was set, now is when we process it. */
615 scm_c_define ("use-emacs-interface", SCM_BOOL (use_emacs_interface
));
617 /* Handle the `-e' switch, if it was specified. */
618 if (!SCM_NULLP (entry_point
))
619 tail
= scm_cons (scm_cons2 (entry_point
,
620 scm_cons (sym_command_line
, SCM_EOL
),
624 /* If we didn't end with a -c or a -s, start the repl. */
627 tail
= scm_cons (scm_cons (sym_top_repl
, SCM_EOL
), tail
);
631 /* After doing all the other actions prescribed by the command line,
633 tail
= scm_cons (scm_cons (sym_quit
, SCM_EOL
),
635 /* Allow asyncs (signal handlers etc.) to be run. */
639 /* After the following line, actions will be added to the front. */
640 tail
= scm_reverse_x (tail
, SCM_UNDEFINED
);
642 /* If we didn't end with a -c or a -s and didn't supply a -q, load
643 the user's customization file. */
644 if (interactive
&& !inhibit_user_init
)
646 tail
= scm_cons (scm_cons (sym_load_user_init
, SCM_EOL
), tail
);
650 SCM val
= scm_cons (sym_begin
, tail
);
653 scm_write (val
, SCM_UNDEFINED
);
654 scm_newline (SCM_UNDEFINED
);
663 scm_shell (int argc
, char **argv
)
665 /* If present, add SCSH-style meta-arguments from the top of the
666 script file to the argument vector. See the SCSH manual: "The
667 meta argument" for more details. */
669 char **new_argv
= scm_get_meta_args (argc
, argv
);
674 argc
= scm_count_argv (new_argv
);
678 exit (scm_exit_status (scm_eval_x (scm_compile_shell_switches (argc
, argv
),
679 scm_current_module ())));
686 #ifndef SCM_MAGIC_SNARFER
687 #include "libguile/script.x"