script.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /* Copyright 1994-1998,2000-2011,2013-2014,2018
  2. Free Software Foundation, Inc.
  3. This file is part of Guile.
  4. Guile is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Lesser General Public License as published
  6. by the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. Guile is distributed in the hope that it will be useful, but WITHOUT
  9. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  11. License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with Guile. If not, see
  14. <https://www.gnu.org/licenses/>. */
  15. /* "script.c" argv tricks for `#!' scripts.
  16. Authors: Aubrey Jaffer and Jim Blandy */
  17. #ifdef HAVE_CONFIG_H
  18. # include <config.h>
  19. #endif
  20. #include <ctype.h>
  21. #include <errno.h>
  22. #include <localcharset.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <uniconv.h>
  27. #include <unistd.h> /* for X_OK define */
  28. #ifdef HAVE_IO_H
  29. #include <io.h>
  30. #endif
  31. #include "eval.h"
  32. #include "feature.h"
  33. #include "fluids.h"
  34. #include "load.h"
  35. #include "modules.h"
  36. #include "pairs.h"
  37. #include "read.h"
  38. #include "strings.h"
  39. #include "strports.h"
  40. #include "throw.h"
  41. #include "version.h"
  42. #include "vm.h"
  43. #include "script.h"
  44. #ifndef WHITE_SPACES
  45. #ifdef MSDOS
  46. #define WHITE_SPACES ' ':case '\t':case '\r':case '\f':case 26
  47. #else
  48. #define WHITE_SPACES ' ':case '\t':case '\r':case '\f'
  49. #endif /* def MSDOS */
  50. #endif /* ndef LINE_INCREMENTORS */
  51. /* Read a \nnn-style escape. We've just read the backslash. */
  52. static int
  53. script_get_octal (FILE *f)
  54. #define FUNC_NAME "script_get_octal"
  55. {
  56. int i;
  57. int value = 0;
  58. for (i = 0; i < 3; i++)
  59. {
  60. int c = getc (f);
  61. if ('0' <= c && c <= '7')
  62. value = (value * 8) + (c - '0');
  63. else
  64. SCM_MISC_ERROR ("malformed script: bad octal backslash escape",
  65. SCM_EOL);
  66. }
  67. return value;
  68. }
  69. #undef FUNC_NAME
  70. static int
  71. script_get_backslash (FILE *f)
  72. #define FUNC_NAME "script_get_backslash"
  73. {
  74. int c = getc (f);
  75. switch (c)
  76. {
  77. case 'a': return '\a';
  78. case 'b': return '\b';
  79. case 'f': return '\f';
  80. case 'n': return '\n';
  81. case 'r': return '\r';
  82. case 't': return '\t';
  83. case 'v': return '\v';
  84. case '\\':
  85. case ' ':
  86. case '\t':
  87. case '\n':
  88. return c;
  89. case '0': case '1': case '2': case '3':
  90. case '4': case '5': case '6': case '7':
  91. ungetc (c, f);
  92. return script_get_octal (f);
  93. case EOF:
  94. SCM_MISC_ERROR ("malformed script: backslash followed by EOF", SCM_EOL);
  95. return 0; /* not reached? */
  96. default:
  97. SCM_MISC_ERROR ("malformed script: bad backslash sequence", SCM_EOL);
  98. return 0; /* not reached? */
  99. }
  100. }
  101. #undef FUNC_NAME
  102. /*
  103. * Like `realloc', but free memory on failure;
  104. * unlike `scm_realloc', return NULL, not aborts.
  105. */
  106. static void*
  107. realloc0 (void *ptr, size_t size)
  108. {
  109. void *new_ptr = realloc (ptr, size);
  110. if (!new_ptr)
  111. {
  112. free (ptr);
  113. }
  114. return new_ptr;
  115. }
  116. static char *
  117. script_read_arg (FILE *f)
  118. #define FUNC_NAME "script_read_arg"
  119. {
  120. size_t size = 7;
  121. char *buf = scm_malloc (size + 1);
  122. size_t len = 0;
  123. if (! buf)
  124. return 0;
  125. for (;;)
  126. {
  127. int c = getc (f);
  128. switch (c)
  129. {
  130. case '\\':
  131. c = script_get_backslash (f);
  132. /* The above produces a new character to add to the argument.
  133. Fall through. */
  134. default:
  135. if (len >= size)
  136. {
  137. size = (size + 1) * 2;
  138. buf = realloc0 (buf, size);
  139. if (! buf)
  140. return 0;
  141. }
  142. buf[len++] = c;
  143. break;
  144. case '\n':
  145. /* This may terminate an arg now, but it will terminate the
  146. entire list next time through. */
  147. ungetc ('\n', f);
  148. case EOF:
  149. if (len == 0)
  150. {
  151. free (buf);
  152. return 0;
  153. }
  154. /* Otherwise, those characters terminate the argument; fall
  155. through. */
  156. case ' ':
  157. buf[len] = '\0';
  158. return buf;
  159. case '\t':
  160. free (buf);
  161. SCM_MISC_ERROR ("malformed script: TAB in meta-arguments", SCM_EOL);
  162. return 0; /* not reached? */
  163. }
  164. }
  165. }
  166. #undef FUNC_NAME
  167. static int
  168. script_meta_arg_P (char *arg)
  169. {
  170. if ('\\' != arg[0])
  171. return 0L;
  172. #ifdef MSDOS
  173. return !arg[1];
  174. #else
  175. switch (arg[1])
  176. {
  177. case 0:
  178. case '%':
  179. case WHITE_SPACES:
  180. return !0;
  181. default:
  182. return 0L;
  183. }
  184. #endif
  185. }
  186. char **
  187. scm_get_meta_args (int argc, char **argv)
  188. {
  189. int nargc = argc, argi = 1, nargi = 1;
  190. char *narg, **nargv;
  191. if (!(argc > 2 && script_meta_arg_P (argv[1])))
  192. return 0L;
  193. if (!(nargv = (char **) scm_malloc ((1 + nargc) * sizeof (char *))))
  194. return 0L;
  195. nargv[0] = argv[0];
  196. while (((argi + 1) < argc) && (script_meta_arg_P (argv[argi])))
  197. {
  198. FILE *f = fopen (argv[++argi], "r");
  199. if (f)
  200. {
  201. nargc--; /* to compensate for replacement of '\\' */
  202. while (1)
  203. switch (getc (f))
  204. {
  205. case EOF:
  206. free (nargv);
  207. return 0L;
  208. default:
  209. continue;
  210. case '\n':
  211. goto found_args;
  212. }
  213. found_args:
  214. /* FIXME: we leak the result of calling script_read_arg. */
  215. while ((narg = script_read_arg (f)))
  216. if (!(nargv = (char **) realloc0 (nargv,
  217. (1 + ++nargc) * sizeof (char *))))
  218. return 0L;
  219. else
  220. nargv[nargi++] = narg;
  221. fclose (f);
  222. nargv[nargi++] = argv[argi++];
  223. }
  224. }
  225. while (argi <= argc)
  226. nargv[nargi++] = argv[argi++];
  227. return nargv;
  228. }
  229. int
  230. scm_count_argv (char **argv)
  231. {
  232. int argc = 0;
  233. while (argv[argc])
  234. argc++;
  235. return argc;
  236. }
  237. /* For use in error messages. */
  238. char *scm_usage_name = 0;
  239. void
  240. scm_shell_usage (int fatal, char *message)
  241. {
  242. scm_call_3 (scm_c_private_ref ("ice-9 command-line",
  243. "shell-usage"),
  244. (scm_usage_name
  245. ? scm_from_locale_string (scm_usage_name)
  246. : scm_from_latin1_string ("guile")),
  247. scm_from_bool (fatal),
  248. (message
  249. ? scm_from_locale_string (message)
  250. : SCM_BOOL_F));
  251. }
  252. /* Return a list of strings from ARGV, which contains ARGC strings
  253. assumed to be encoded in the current locale. Use
  254. `environ_locale_charset' instead of relying on
  255. `scm_from_locale_string' because the user hasn't had a change to call
  256. (setlocale LC_ALL "") yet.
  257. XXX: This hack is for 2.0 and will be removed in the next stable
  258. series where the `setlocale' call will be implicit. See
  259. <http://lists.gnu.org/archive/html/guile-devel/2011-11/msg00040.html>
  260. for details. */
  261. static SCM
  262. locale_arguments_to_string_list (int argc, char **const argv)
  263. {
  264. int i;
  265. SCM lst;
  266. const char *encoding;
  267. encoding = environ_locale_charset ();
  268. for (i = argc - 1, lst = SCM_EOL;
  269. i >= 0;
  270. i--)
  271. lst = scm_cons (scm_from_stringn (argv[i], (size_t) -1, encoding,
  272. SCM_FAILED_CONVERSION_ESCAPE_SEQUENCE),
  273. lst);
  274. return lst;
  275. }
  276. /* Set the value returned by `program-arguments', given ARGC and ARGV. */
  277. void
  278. scm_i_set_boot_program_arguments (int argc, char *argv[])
  279. {
  280. scm_fluid_set_x (scm_program_arguments_fluid,
  281. locale_arguments_to_string_list (argc, argv));
  282. }
  283. /* Given an array of command-line switches, return a Scheme expression
  284. to carry out the actions specified by the switches.
  285. */
  286. SCM
  287. scm_compile_shell_switches (int argc, char **argv)
  288. {
  289. return scm_call_2 (scm_c_public_ref ("ice-9 command-line",
  290. "compile-shell-switches"),
  291. locale_arguments_to_string_list (argc, argv),
  292. (scm_usage_name
  293. ? scm_from_locale_string (scm_usage_name)
  294. : scm_from_latin1_string ("guile")));
  295. }
  296. void
  297. scm_shell (int argc, char **argv)
  298. {
  299. /* If present, add SCSH-style meta-arguments from the top of the
  300. script file to the argument vector. See the SCSH manual: "The
  301. meta argument" for more details. */
  302. {
  303. char **new_argv = scm_get_meta_args (argc, argv);
  304. if (new_argv)
  305. {
  306. argv = new_argv;
  307. argc = scm_count_argv (new_argv);
  308. }
  309. }
  310. exit (scm_exit_status (scm_eval_x (scm_compile_shell_switches (argc, argv),
  311. scm_current_module ())));
  312. }
  313. void
  314. scm_init_script ()
  315. {
  316. #include "script.x"
  317. }