9a1f439b7246b8db142773a7906fab96a1092205
1 /* Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
7 * This library 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 GNU
10 * Lesser General Public License for more details.
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 /* "script.c" argv tricks for `#!' scripts.
18 Authors: Aubrey Jaffer and Jim Blandy */
28 #include "libguile/_scm.h"
29 #include "libguile/gh.h"
30 #include "libguile/load.h"
31 #include "libguile/version.h"
33 #include "libguile/validate.h"
34 #include "libguile/script.h"
41 #include <unistd.h> /* for X_OK define */
48 /* Concatentate str2 onto str1 at position n and return concatenated
49 string if file exists; 0 otherwise. */
52 scm_cat_path (char *str1
, const char *str2
, long n
)
58 size_t len
= strlen (str1
);
59 str1
= (char *) realloc (str1
, (size_t) (len
+ n
+ 1));
62 strncat (str1
+ len
, str2
, n
);
65 str1
= (char *) scm_malloc ((size_t) (n
+ 1));
69 strncat (str1
, str2
, n
);
75 scm_try_path (char *path
)
78 /* fprintf(stderr, "Trying %s\n", path);fflush(stderr); */
81 SCM_SYSCALL (f
= fopen (path
, "r");
93 scm_sep_init_try (char *path
, const char *sep
, const char *initname
)
96 path
= scm_cat_path (path
, sep
, 0L);
98 path
= scm_cat_path (path
, initname
, 0L);
99 return scm_try_path (path
);
103 #ifndef LINE_INCREMENTORS
104 #define LINE_INCREMENTORS '\n'
106 #define WHITE_SPACES ' ':case '\t':case '\r':case '\f':case 26
108 #define WHITE_SPACES ' ':case '\t':case '\r':case '\f'
109 #endif /* def MSDOS */
110 #endif /* ndef LINE_INCREMENTORS */
113 #define MAXPATHLEN 80
114 #endif /* ndef MAXPATHLEN */
117 #endif /* ndef X_OK */
120 scm_find_executable (const char *name
)
122 char tbuf
[MAXPATHLEN
];
126 /* fprintf(stderr, "s_f_e checking access %s ->%d\n", name, access(name, X_OK)); fflush(stderr); */
127 if (access (name
, X_OK
))
129 f
= fopen (name
, "r");
132 if ((fgetc (f
) == '#') && (fgetc (f
) == '!'))
135 switch (tbuf
[i
++] = fgetc (f
))
137 case /*WHITE_SPACES */ ' ':
144 return scm_cat_path (0L, tbuf
, 0L);
148 return scm_cat_path (0L, name
, 0L);
152 /* Read a \nnn-style escape. We've just read the backslash. */
154 script_get_octal (FILE *f
)
155 #define FUNC_NAME "script_get_octal"
160 for (i
= 0; i
< 3; i
++)
163 if ('0' <= c
&& c
<= '7')
164 value
= (value
* 8) + (c
- '0');
166 SCM_MISC_ERROR ("malformed script: bad octal backslash escape",
175 script_get_backslash (FILE *f
)
176 #define FUNC_NAME "script_get_backslash"
182 case 'a': return '\a';
183 case 'b': return '\b';
184 case 'f': return '\f';
185 case 'n': return '\n';
186 case 'r': return '\r';
187 case 't': return '\t';
188 case 'v': return '\v';
196 case '0': case '1': case '2': case '3':
197 case '4': case '5': case '6': case '7':
199 return script_get_octal (f
);
202 SCM_MISC_ERROR ("malformed script: backslash followed by EOF", SCM_EOL
);
203 return 0; /* not reached? */
206 SCM_MISC_ERROR ("malformed script: bad backslash sequence", SCM_EOL
);
207 return 0; /* not reached? */
214 script_read_arg (FILE *f
)
215 #define FUNC_NAME "script_read_arg"
218 char *buf
= scm_malloc (size
+ 1);
230 c
= script_get_backslash (f
);
231 /* The above produces a new character to add to the argument.
236 size
= (size
+ 1) * 2;
237 buf
= realloc (buf
, size
);
245 /* This may terminate an arg now, but it will terminate the
246 entire list next time through. */
254 /* Otherwise, those characters terminate the argument; fall
262 SCM_MISC_ERROR ("malformed script: TAB in meta-arguments", SCM_EOL
);
263 return 0; /* not reached? */
271 script_meta_arg_P (char *arg
)
291 scm_get_meta_args (int argc
, char **argv
)
293 int nargc
= argc
, argi
= 1, nargi
= 1;
295 if (!(argc
> 2 && script_meta_arg_P (argv
[1])))
297 if (!(nargv
= (char **) scm_malloc ((1 + nargc
) * sizeof (char *))))
300 while (((argi
+ 1) < argc
) && (script_meta_arg_P (argv
[argi
])))
302 FILE *f
= fopen (argv
[++argi
], "r");
305 nargc
--; /* to compensate for replacement of '\\' */
317 while ((narg
= script_read_arg (f
)))
318 if (!(nargv
= (char **) realloc (nargv
,
319 (1 + ++nargc
) * sizeof (char *))))
322 nargv
[nargi
++] = narg
;
324 nargv
[nargi
++] = argv
[argi
++];
328 nargv
[nargi
++] = argv
[argi
++];
333 scm_count_argv (char **argv
)
342 /* For use in error messages. */
343 char *scm_usage_name
= 0;
346 scm_shell_usage (int fatal
, char *message
)
348 FILE *fp
= (fatal
? stderr
: stdout
);
351 fprintf (fp
, "%s\n", message
);
354 "Usage: %s OPTION ...\n"
355 "Evaluate Scheme code, interactively or from a script.\n"
357 " [-s] FILE load Scheme source code from FILE, and exit\n"
358 " -c EXPR evalute Scheme expression EXPR, and exit\n"
359 " -- stop scanning arguments; run interactively\n"
360 "The above switches stop argument processing, and pass all\n"
361 "remaining arguments as the value of (command-line).\n"
362 "If FILE begins with `-' the -s switch is mandatory.\n"
364 " -L DIRECTORY add DIRECTORY to the front of the module load path\n"
365 " -l FILE load Scheme source code from FILE\n"
366 " -e FUNCTION after reading script, apply FUNCTION to\n"
367 " command line arguments\n"
368 " -ds do -s script at this point\n"
369 " --debug start with debugging evaluator and backtraces\n"
370 " --no-debug start with normal evaluator\n"
371 " Default is to enable debugging for interactive\n"
372 " use, but not for `-s' and `-c'.\n"
373 " -q inhibit loading of user init file\n"
374 " --emacs enable Emacs protocol (experimental)\n"
375 " --use-srfi=LS load SRFI modules for the SRFIs in LS,\n"
376 " which is a list of numbers like \"2,13,14\"\n"
377 " -h, --help display this help and exit\n"
378 " -v, --version display version information and exit\n"
379 " \\ read arguments from following script lines\n"
381 "Please report bugs to bug-guile@gnu.org\n",
389 /* Some symbols used by the command-line compiler. */
390 SCM_SYMBOL (sym_load
, "load");
391 SCM_SYMBOL (sym_eval_string
, "eval-string");
392 SCM_SYMBOL (sym_command_line
, "command-line");
393 SCM_SYMBOL (sym_begin
, "begin");
394 SCM_SYMBOL (sym_turn_on_debugging
, "turn-on-debugging");
395 SCM_SYMBOL (sym_load_user_init
, "load-user-init");
396 SCM_SYMBOL (sym_top_repl
, "top-repl");
397 SCM_SYMBOL (sym_quit
, "quit");
398 SCM_SYMBOL (sym_use_srfis
, "use-srfis");
399 SCM_SYMBOL (sym_load_path
, "%load-path");
400 SCM_SYMBOL (sym_set_x
, "set!");
401 SCM_SYMBOL (sym_cons
, "cons");
403 /* Given an array of command-line switches, return a Scheme expression
404 to carry out the actions specified by the switches.
406 If you told me this should have been written in Scheme, I'd
407 probably agree. I'd say I didn't feel comfortable doing that in
408 the present system. You'd say, well, fix the system so you are
409 comfortable doing that. I'd agree again. *shrug*
412 static char guile
[] = "guile";
415 scm_compile_shell_switches (int argc
, char **argv
)
417 SCM tail
= SCM_EOL
; /* We accumulate the list backwards,
418 and then reverse! it before we
420 SCM do_script
= SCM_EOL
; /* The element of the list containing
421 the "load" command, in case we get
423 SCM entry_point
= SCM_EOL
; /* for -e switch */
424 SCM user_load_path
= SCM_EOL
; /* for -L switch */
425 int interactive
= 1; /* Should we go interactive when done? */
426 int inhibit_user_init
= 0; /* Don't load user init file */
427 int use_emacs_interface
= 0;
428 int turn_on_debugging
= 0;
429 int dont_turn_on_debugging
= 0;
437 scm_usage_name
= strrchr (argv
[0], '/');
438 if (! scm_usage_name
)
439 scm_usage_name
= argv
[0];
443 if (! scm_usage_name
)
444 scm_usage_name
= guile
;
446 for (i
= 1; i
< argc
; i
++)
448 if ((! strcmp (argv
[i
], "-s")) || (argv
[i
][0] != '-')) /* load script */
450 if ((argv
[i
][0] == '-') && (++i
>= argc
))
451 scm_shell_usage (1, "missing argument to `-s' switch");
453 /* If we specified the -ds option, do_script points to the
454 cdr of an expression like (load #f); we replace the car
455 (i.e., the #f) with the script name. */
456 if (!SCM_NULLP (do_script
))
458 SCM_SETCAR (do_script
, scm_from_locale_string (argv
[i
]));
462 /* Construct an application of LOAD to the script name. */
463 tail
= scm_cons (scm_cons2 (sym_load
,
464 scm_from_locale_string (argv
[i
]),
473 else if (! strcmp (argv
[i
], "-c")) /* evaluate expr */
476 scm_shell_usage (1, "missing argument to `-c' switch");
477 tail
= scm_cons (scm_cons2 (sym_eval_string
,
478 scm_from_locale_string (argv
[i
]),
486 else if (! strcmp (argv
[i
], "--")) /* end args; go interactive */
492 else if (! strcmp (argv
[i
], "-l")) /* load a file */
495 tail
= scm_cons (scm_cons2 (sym_load
,
496 scm_from_locale_string (argv
[i
]),
500 scm_shell_usage (1, "missing argument to `-l' switch");
503 else if (! strcmp (argv
[i
], "-L")) /* add to %load-path */
507 scm_cons (scm_list_3 (sym_set_x
,
509 scm_list_3 (sym_cons
,
510 scm_from_locale_string (argv
[i
]),
514 scm_shell_usage (1, "missing argument to `-L' switch");
517 else if (! strcmp (argv
[i
], "-e")) /* entry point */
520 entry_point
= scm_c_read_string (argv
[i
]);
522 scm_shell_usage (1, "missing argument to `-e' switch");
525 else if (! strcmp (argv
[i
], "-ds")) /* do script here */
527 /* We put a dummy "load" expression, and let the -s put the
529 if (!SCM_NULLP (do_script
))
530 scm_shell_usage (1, "the -ds switch may only be specified once");
531 do_script
= scm_cons (SCM_BOOL_F
, SCM_EOL
);
532 tail
= scm_cons (scm_cons (sym_load
, do_script
),
536 else if (! strcmp (argv
[i
], "--debug"))
538 turn_on_debugging
= 1;
539 dont_turn_on_debugging
= 0;
542 else if (! strcmp (argv
[i
], "--no-debug"))
544 dont_turn_on_debugging
= 1;
545 turn_on_debugging
= 0;
548 else if (! strcmp (argv
[i
], "--emacs")) /* use emacs protocol */
549 use_emacs_interface
= 1;
551 else if (! strcmp (argv
[i
], "-q")) /* don't load user init */
552 inhibit_user_init
= 1;
554 else if (! strncmp (argv
[i
], "--use-srfi=", 11)) /* load SRFIs */
556 SCM srfis
= SCM_EOL
; /* List of requested SRFIs. */
557 char * p
= argv
[i
] + 11;
563 num
= strtol (p
, &end
, 10);
566 srfis
= scm_cons (scm_from_long (num
), srfis
);
572 scm_shell_usage (1, "invalid SRFI specification");
578 scm_shell_usage (1, "invalid SRFI specification");
580 if (scm_ilength (srfis
) <= 0)
581 scm_shell_usage (1, "invalid SRFI specification");
582 srfis
= scm_reverse_x (srfis
, SCM_UNDEFINED
);
583 tail
= scm_cons (scm_list_2 (sym_use_srfis
,
584 scm_list_2 (scm_sym_quote
, srfis
)),
588 else if (! strcmp (argv
[i
], "-h")
589 || ! strcmp (argv
[i
], "--help"))
591 scm_shell_usage (0, 0);
595 else if (! strcmp (argv
[i
], "-v")
596 || ! strcmp (argv
[i
], "--version"))
598 /* Print version number. */
600 "Copyright (c) 1995, 1996, 1997, 2000, 2001, 2002, 2003, 2004 Free Software Foundation\n"
601 "Guile may be distributed under the terms of the GNU General Public Licence;\n"
602 "certain other uses are permitted as well. For details, see the file\n"
603 "`COPYING', which is included in the Guile distribution.\n"
604 "There is no warranty, to the extent permitted by law.\n",
605 scm_to_locale_string (scm_version ()));
611 fprintf (stderr
, "%s: Unrecognized switch `%s'\n",
612 scm_usage_name
, argv
[i
]);
613 scm_shell_usage (1, 0);
617 /* Check to make sure the -ds got a -s. */
618 if (!SCM_NULLP (do_script
))
619 scm_shell_usage (1, "the `-ds' switch requires the use of `-s' as well");
621 /* Make any remaining arguments available to the
622 script/command/whatever. */
623 scm_set_program_arguments (argc
? argc
- i
: 0, argv
+ i
, argv0
);
625 /* If the --emacs switch was set, now is when we process it. */
626 scm_c_define ("use-emacs-interface", scm_from_bool (use_emacs_interface
));
628 /* Handle the `-e' switch, if it was specified. */
629 if (!SCM_NULLP (entry_point
))
630 tail
= scm_cons (scm_cons2 (entry_point
,
631 scm_cons (sym_command_line
, SCM_EOL
),
635 /* If we didn't end with a -c or a -s, start the repl. */
638 tail
= scm_cons (scm_cons (sym_top_repl
, SCM_EOL
), tail
);
642 /* After doing all the other actions prescribed by the command line,
644 tail
= scm_cons (scm_cons (sym_quit
, SCM_EOL
),
648 /* After the following line, actions will be added to the front. */
649 tail
= scm_reverse_x (tail
, SCM_UNDEFINED
);
651 /* add the user-specified load path here, so it won't be in effect
652 during the loading of the user's customization file. */
653 if(!SCM_NULLP(user_load_path
))
655 tail
= scm_append_x( scm_cons2(user_load_path
, tail
, SCM_EOL
) );
658 /* If we didn't end with a -c or a -s and didn't supply a -q, load
659 the user's customization file. */
660 if (interactive
&& !inhibit_user_init
)
662 tail
= scm_cons (scm_cons (sym_load_user_init
, SCM_EOL
), tail
);
665 /* If debugging was requested, or we are interactive and debugging
666 was not explicitly turned off, turn on debugging. */
667 if (turn_on_debugging
|| (interactive
&& !dont_turn_on_debugging
))
669 tail
= scm_cons (scm_cons (sym_turn_on_debugging
, SCM_EOL
), tail
);
673 SCM val
= scm_cons (sym_begin
, tail
);
676 scm_write (val
, SCM_UNDEFINED
);
677 scm_newline (SCM_UNDEFINED
);
686 scm_shell (int argc
, char **argv
)
688 /* If present, add SCSH-style meta-arguments from the top of the
689 script file to the argument vector. See the SCSH manual: "The
690 meta argument" for more details. */
692 char **new_argv
= scm_get_meta_args (argc
, argv
);
697 argc
= scm_count_argv (new_argv
);
701 exit (scm_exit_status (scm_eval_x (scm_compile_shell_switches (argc
, argv
),
702 scm_current_module ())));
709 #include "libguile/script.x"