1 /*
2 * Copyright (c) 2020, Masatake YAMATO
3 * Copyright (c) 2020, Red Hat, Inc.
4 *
5 * This source code is released for free distribution under the terms of the
6 * GNU General Public License version 2 or (at your option) any later version.
7 */
8
9 #include "general.h"
10
11 #include "optscript.h"
12 #include "mio.h"
13 #include "routines.h"
14
15 #include <string.h>
16 #include <stdlib.h>
17
18 static void
help(const char * progname,int exit_status)19 help (const char* progname, int exit_status)
20 {
21 FILE *out = stderr;
22 if (exit_status == 0)
23 out = stdout;
24
25 fprintf (out, "Usage: %s [options] [file|-]\n\n", progname);
26 fputs ( " -h|--help Print this option summary\n", out);
27 fputs ( " -l|--list-operators List built-in operators\n", out);
28 fputs ( " -e|--eval CODE Evaluate the CODE\n", out);
29 fputc ('\n', out);
30 exit (exit_status);
31 }
32
33 static EsObject*
op_renew(OptVM * vm,EsObject * name)34 op_renew (OptVM *vm, EsObject *name)
35 {
36 bool *app_data = opt_vm_get_app_data (vm);
37 *app_data = true;
38 return OPT_ERR_QUIT;
39 }
40
41 int
optscript_run(OptVM * vm,char * prompt,void * app_data)42 optscript_run (OptVM *vm, char *prompt, void *app_data)
43 {
44 int r = 0;
45 void *old_app_data = opt_vm_set_app_data (vm, app_data);
46 char *old_prompt = opt_vm_set_prompt (vm, prompt);
47
48 opt_vm_print_prompt (vm);
49
50 while (true)
51 {
52 EsObject *o = opt_vm_read (vm, NULL);
53 if (es_object_equal (o, ES_READER_EOF))
54 {
55 es_object_unref (o);
56 break;
57 }
58 EsObject *e = opt_vm_eval (vm, o);
59 es_object_unref (o);
60
61 if (es_error_p (e))
62 {
63 if (!es_object_equal (e, OPT_ERR_QUIT))
64 {
65 opt_vm_report_error (vm, e, NULL);
66 r = 1;
67 }
68 break;
69 }
70 }
71
72 opt_vm_set_prompt (vm, old_prompt);
73 opt_vm_set_app_data (vm, old_app_data);
74 return r;
75 }
76
77 int
main(int argc,char ** argv)78 main(int argc, char **argv)
79 {
80 MIO *in = NULL;
81 const char *file = NULL;
82 bool help_ops = false;
83
84 for (int i = 1; i < argc; i++)
85 {
86 if (strcmp (argv[i], "-h") == 0
87 || strcmp (argv[i], "--help") == 0)
88 help (argv[0], 0);
89 else if (strcmp (argv[i], "-l") == 0
90 || strcmp (argv[i], "--list-operators") == 0)
91 help_ops = true;
92 else if (strcmp (argv[i], "-e") == 0
93 || strcmp (argv[i], "--eval") == 0)
94 {
95 if (file)
96 {
97 fprintf (stderr, "Don't specify multiple input: %s, %s\n",
98 file, argv[i]);
99 exit (2);
100 }
101
102 if (i == argc -1)
103 {
104 fprintf (stderr, "no code for %s\n", argv[i]);
105 exit (2);
106 }
107 file = "<cmdline>";
108 i++;
109 in = mio_new_memory ((unsigned char *)eStrdup(argv[i]), strlen (argv[i]), eRealloc, eFree);
110 if (!in)
111 {
112 fprintf (stderr, "failed to create mio from memory\n");
113 exit (1);
114 }
115 }
116 else if (argv[i][0] == '-' && argv[i][1] == '\0')
117 {
118 if (file)
119 {
120 fprintf (stderr, "Don't specify multiple input: %s, %s\n",
121 file, argv[i]);
122 exit (2);
123 }
124
125 file = "<stdin>";
126 in = mio_new_fp (stdin, NULL);
127 if (!in)
128 {
129 fprintf (stderr, "failed to use <stdin>\n");
130 exit (1);
131 }
132 }
133 else if (argv[i][0] == '-')
134 {
135 fprintf (stderr, "unknown option: %s\n", argv[i]);
136 exit (2);
137 }
138 else if (in)
139 {
140 fprintf (stderr, "too many arugments\n");
141 mio_unref (in);
142 exit (2);
143 }
144 else
145 {
146 if (file)
147 {
148 fprintf (stderr, "Don't specify multiple input: %s, %s\n",
149 file, argv[i]);
150 exit (2);
151 }
152
153 file = argv[i];
154 in = mio_new_file (file, "r");
155 if (!in)
156 {
157 fprintf (stderr, "failed to open: %s\n", file);
158 exit (1);
159 }
160 }
161 }
162
163 opt_init ();
164
165 if (!in)
166 in = mio_new_fp (stdin, NULL);
167 if (in == NULL)
168 {
169 fprintf (stderr, "failed to open input stream\n");
170 exit (1);
171 }
172
173 MIO *out = mio_new_fp (stdout, NULL);
174 if (!out)
175 {
176 mio_unref (in);
177 fprintf (stderr, "failed to open output stream\n");
178 exit (1);
179 }
180 MIO *err = mio_new_fp (stderr, NULL);
181 if (!err)
182 {
183 mio_unref (out);
184 mio_unref (in);
185 fprintf (stderr, "failed to open error stream\n");
186 exit (1);
187 }
188
189 OptVM *vm = opt_vm_new (in, out, err);
190
191 int r;
192
193 EsObject *dict = opt_dict_new (47);
194 {
195 EsObject *op;
196 EsObject *sym;
197
198 op = opt_operator_new (op_renew, "_renew", 0, ":clear the state of vm%- _RENEW -");
199 sym = es_symbol_intern ("_renew");
200 opt_dict_def (dict, sym, op);
201 es_object_unref (op);
202 }
203
204 opt_vm_dstack_push (vm, dict);
205 if (help_ops)
206 r = opt_vm_help (vm, NULL, NULL, NULL);
207 else
208 {
209 bool renew = false;
210 renew:
211 r = optscript_run (vm, file? NULL: "OPT", &renew);
212 if (renew)
213 {
214 opt_vm_clear (vm);
215 opt_vm_dstack_push (vm, dict);
216 renew = false;
217 goto renew;
218 }
219 }
220 es_object_unref (dict);
221
222 opt_vm_delete (vm);
223
224 mio_unref (err);
225 mio_unref (out);
226 mio_unref (in);
227
228 return r;
229 }
230