Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 417 lines (339 sloc) 10.149 kB
97dc010 @marianoguerra license to fnc files
marianoguerra authored
1 // New BSD License, part of efene, see LICENSE for details
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
2 #include <ctype.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <getopt.h>
7 #include <string.h>
8 #include <assert.h>
188e2dd @marianoguerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0…
marianoguerra authored
9 #include <libgen.h>
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
10 #include <sys/types.h>
11 #include <sys/stat.h>
12
13 #include "fnc.h"
14
1405441 @marianoguerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
15 #define STR_BUFFER_SIZE 2048
16 #define PATHS_SIZE 512
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
17
18 // copy the path to efene from the environment variable FNPATH if available
19 // if not found return NULL
20 // you have to free the variable
21 char* get_efene_path_from_env() {
22 char *fnpath, *result;
23
24 result = NULL;
25 fnpath = getenv("FNPATH");
26
27 if (fnpath != NULL) {
188e2dd @marianoguerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0…
marianoguerra authored
28 result = strdup(fnpath);
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
29 assert(result != NULL);
30 }
31
32 return result;
33 }
34
35 void show_usage() {
36 printf("usage:\n");
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
37 printf("\tfnc -s: run the interactive shell\n");
4c4e3cc @marianoguerra some simplifications in fnc.c
marianoguerra authored
38 printf("\tfnc -h: shows this help\n");
77493d1 @marianoguerra added the -r option to run commands (replaces fn) and -T option to de…
marianoguerra authored
39 printf("\tfnc -r module function [argumens*]: runs function from module passing optional arguments\n");
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
40 printf("options:\n");
41 printf("\t-t: type, can be beam (the default), lex, tree, ast, mod, erl or erl2ast\n");
42 printf("\t-o: output path, the path where the compiled files will be written\n");
77493d1 @marianoguerra added the -r option to run commands (replaces fn) and -T option to de…
marianoguerra authored
43 printf("\t-T: test, instead of running the command print it to the screen\n");
6b5b8cb @marianoguerra add help for -a and -p
marianoguerra authored
44 printf("\t-a: append a path to look for modules\n");
45 printf("\t-p: prepend a path to look for modules\n");
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
46 printf("examples:\n");
47 printf("\tfnc foo.ifn: compile foo.ifn, write the result in the current directory\n");
48 printf("\tfnc foo.ifn bar.fn baz.ifn: same as before but multiple files compiled\n");
49 printf("\tfnc foo.ifn -o /tmp: compile foo.ifn, write the result in /tmp\n");
50 printf("\tfnc -t beam -o /tmp foo.ifn: same as before but with the type set\n");
51 printf("\tfnc -t erl foo.ifn: translate foo.ifn to erlang\n");
77493d1 @marianoguerra added the -r option to run commands (replaces fn) and -T option to de…
marianoguerra authored
52 printf("\tfnc -r foo run: runs the run function in the foo module\n");
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
53 }
54
55 int is_dir(const char *path) {
56 struct stat st;
57 return (stat(path, &st) == 0 && S_ISDIR(st.st_mode));
58 }
59
77493d1 @marianoguerra added the -r option to run commands (replaces fn) and -T option to de…
marianoguerra authored
60 int fn_run(const char *args, char *argv0, int is_test) {
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
61 int count, status;
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
62 char *fnpath, buffer[STR_BUFFER_SIZE], *basepath;
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
63 fnpath = get_efene_path_from_env();
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
64 basepath = dirname(dirname(argv0));
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
65
66 if (fnpath == NULL) {
67 if (!is_dir("../ebin")) {
68
188e2dd @marianoguerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0…
marianoguerra authored
69 count = snprintf(buffer, STR_BUFFER_SIZE, "%s/ebin", basepath);
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
70 assert(count <= STR_BUFFER_SIZE);
188e2dd @marianoguerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0…
marianoguerra authored
71
72 fnpath = strdup(buffer);
73 assert(fnpath != NULL);
74
75 if (!is_dir(fnpath)) {
76 fprintf(stderr, "$FNPATH is not defined, %s and ../ebin don't exist, options:\n", fnpath);
77 fprintf(stderr, " * set $FNPATH to the path where efene is installed\n");
78 fprintf(stderr, " * run fnc -s from the bin directory\n");
79 fprintf(stderr, " * stop doing maginc tricks with your path\n");
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
80 status = EXIT_FAILURE;
188e2dd @marianoguerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0…
marianoguerra authored
81 }
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
82 else {
83 count = snprintf(buffer, STR_BUFFER_SIZE,
4c4e3cc @marianoguerra some simplifications in fnc.c
marianoguerra authored
84 "erl -run %s -run init stop -noshell -pa \"%s\"",
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
85 args, fnpath);
188e2dd @marianoguerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0…
marianoguerra authored
86
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
87 assert(count <= STR_BUFFER_SIZE);
77493d1 @marianoguerra added the -r option to run commands (replaces fn) and -T option to de…
marianoguerra authored
88
89 if (is_test) {
90 printf("%s\n", buffer);
91 }
92 else {
93 status = system(buffer);
94 }
188e2dd @marianoguerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0…
marianoguerra authored
95 }
96 }
97 else {
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
98 count = snprintf(buffer, STR_BUFFER_SIZE,
4c4e3cc @marianoguerra some simplifications in fnc.c
marianoguerra authored
99 "erl -run %s -run init stop -noshell -pa \"../ebin\"",
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
100 args);
101
102 assert(count <= STR_BUFFER_SIZE);
77493d1 @marianoguerra added the -r option to run commands (replaces fn) and -T option to de…
marianoguerra authored
103
104 if (is_test) {
105 printf("%s\n", buffer);
106 }
107 else {
108 status = system(buffer);
109 }
188e2dd @marianoguerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0…
marianoguerra authored
110 }
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
111 }
112 else {
188e2dd @marianoguerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0…
marianoguerra authored
113 count = snprintf(buffer, STR_BUFFER_SIZE,
4c4e3cc @marianoguerra some simplifications in fnc.c
marianoguerra authored
114 "erl -run %s -run init stop -noshell -pa \"%s/ebin\"",
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
115 args, fnpath);
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
116
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
117 assert(count <= STR_BUFFER_SIZE);
77493d1 @marianoguerra added the -r option to run commands (replaces fn) and -T option to de…
marianoguerra authored
118
119 if (is_test) {
120 printf("%s\n", buffer);
121 }
122 else {
123 status = system(buffer);
124 }
125
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
126 free(fnpath);
127 }
128
129 exit(status);
130 }
131
132 struct FnOptions* fn_options_new() {
133 struct FnOptions* options = (struct FnOptions*) malloc(sizeof(struct FnOptions));
134
77493d1 @marianoguerra added the -r option to run commands (replaces fn) and -T option to de…
marianoguerra authored
135 assert(options != NULL);
136 options->output_path = NULL;
137 options->files = NULL;
138 options->files_num = 0;
139 options->output_type = NULL;
140 options->mode = '?';
141 options->is_test = 0;
1405441 @marianoguerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
142 options->appends = (char*) malloc(sizeof(char) * PATHS_SIZE);
143 options->prepends = (char*) malloc(sizeof(char) * PATHS_SIZE);
144 options->appends[0] = '\0';
145 options->prepends[0] = '\0';
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
146
147 return options;
148 }
149
150 void fn_options_free_files(struct FnOptions* options) {
151 int index;
152
153 if (options != NULL && options->files != NULL && options->files_num > 0) {
154 for (index = 0; index < options->files_num; index++) {
155 free(options->files[index]);
156 }
157
158 free(options->files);
159 }
160 }
161
162 void fn_options_delete(struct FnOptions* options) {
163 if (options != NULL) {
164
165 if (options->output_path != NULL) {
166 free(options->output_path);
167 }
168
169 fn_options_free_files(options);
170
171 if (options->output_type != NULL) {
172 free(options->output_type);
173 }
174
1405441 @marianoguerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
175 free(options->appends);
176 free(options->prepends);
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
177 free(options);
178 }
179 }
180
181 void fn_options_print(struct FnOptions* options) {
182 int index;
183
184 if (options != NULL) {
185 printf("options:\n");
186
187 if (options->output_path != NULL) {
188 printf("\toutput: %s\n", options->output_path);
189 }
190
191 if (options->files != NULL && options->files_num > 0) {
192 for (index = 0; index < options->files_num; index++) {
193 printf("\tfile: %s\n", options->files[index]);
194 }
195 }
196
197 if (options->output_type != NULL) {
198 printf("\toutput type: %s\n", options->output_type);
199 }
200 }
201 else {
202 printf("options: NULL\n");
203 }
204 }
205
206 int fn_options_copy_output_type(struct FnOptions* options, const char* arg) {
207 if (arg == NULL || options == NULL) {
208 return 0;
209 }
210
211 if (options->output_type != NULL) {
212 free(options->output_type);
213 }
214
188e2dd @marianoguerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0…
marianoguerra authored
215 options->output_type = strdup(optarg);
216 assert(options->output_type != NULL);
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
217
218 return 1;
219 }
220
221 int fn_options_copy_output_path(struct FnOptions* options, const char* arg) {
222 if (arg == NULL || options == NULL) {
223 return 0;
224 }
225
226 if (options->output_path != NULL) {
227 free(options->output_path);
228 }
229
188e2dd @marianoguerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0…
marianoguerra authored
230 options->output_path = strdup(optarg);
231 assert(options->output_path != NULL);
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
232
233 return 1;
234 }
235
236 void fn_options_copy_extra_args(struct FnOptions* options, int optind, int argc, char **argv) {
237 int index;
238
239 if (options == NULL) {
240 return;
241 }
242
243 if (optind == argc) {
244 return;
245 }
246
247 fn_options_free_files(options);
248
249 options->files_num = argc - optind;
250 options->files = (char**) malloc(sizeof(char*) * options->files_num);
251
252 for (index = optind; index < argc; index++) {
188e2dd @marianoguerra strdup used un fnc.c, added lookup for ebin in dirname(dirname(argv[0…
marianoguerra authored
253 options->files[index - optind] = strdup(argv[index]);
254 assert(options->files[index - optind] != NULL);
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
255 }
256 }
257
1405441 @marianoguerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
258 void set_mode(struct FnOptions *options, char new_mode) {
259 if (options->mode != '?') {
260 fprintf(stderr, "warning! overriding %c flag with %c flag\n", options->mode, new_mode);
261 }
262
263 options->mode = new_mode;
264 }
265
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
266 struct FnOptions* parse_options (int argc, char **argv) {
267 int c;
268 struct FnOptions* options = fn_options_new();
269
1405441 @marianoguerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
270 while ((c = getopt (argc, argv, "o:ht:sTra:p:")) != -1) {
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
271 switch (c) {
1405441 @marianoguerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
272 case 'a':
273 if (options->appends[0] == '\0') {
274 strcat(options->appends, " -pa");
275 }
276
277 strcat(options->appends, " ");
278 strncat(options->appends, optarg, PATHS_SIZE);
279 break;
280 case 'p':
281 if (options->prepends[0] == '\0') {
282 strcat(options->prepends, " -pz");
283 }
284
285 strcat(options->prepends, " ");
286 strncat(options->prepends, optarg, PATHS_SIZE);
287 break;
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
288 case 'o':
289 if (fn_options_copy_output_path(options, optarg) == 0) {
290 fprintf(stderr, "error copying output path\n");
291 }
292
293 break;
294 case 'h':
295 show_usage();
296 exit(EXIT_SUCCESS);
77493d1 @marianoguerra added the -r option to run commands (replaces fn) and -T option to de…
marianoguerra authored
297 case 'T':
298 options->is_test = 1;
299 break;
300 case 'r':
1405441 @marianoguerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
301 set_mode(options, 'r');
77493d1 @marianoguerra added the -r option to run commands (replaces fn) and -T option to de…
marianoguerra authored
302 break;
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
303 case 't':
304 if (fn_options_copy_output_type(options, optarg) == 0) {
305 fprintf(stderr, "error copying output type\n");
306 }
307
308 break;
309 case 's':
1405441 @marianoguerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
310 set_mode(options, 's');
311 break;
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
312 case '?':
313 if (optopt == 'o') {
314 fprintf(stderr, "output path option requires an argument\n");
315 }
316 else if (optopt == 't') {
317 fprintf(stderr, "output type option requires an argument\n");
318 }
319 else if (isprint(optopt)) {
320 fprintf(stderr, "Unknown option `-%c'.\n", optopt);
321 }
322 else {
323 fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
324 }
325
326 exit(EXIT_FAILURE);
327 }
328 }
329
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
330 if (options->output_type == NULL) {
331 options->output_type = strdup("beam");
332 }
333
334 if (options->output_path == NULL) {
335 options->output_path = strdup(".");
336 }
337
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
338 fn_options_copy_extra_args(options, optind, argc, argv);
339
340 return options;
341 }
342
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
343 char* str_join(int count, char **strs) {
344 int i, size = 0, len, offset = 0;
345 char *result;
346 assert(count > 0);
347 assert(strs != NULL);
348
349 for (i = 0; i < count; i++) {
350 // the + 1 is for the spaces in all and for \0 in the last one
351 size += strlen(strs[i]) + 1;
352 }
353
354 result = (char*) malloc(sizeof(char) * size);
355 assert(result != NULL);
356
357 for (i = 0; i < count; i++) {
358 len = strlen(strs[i]);
359 strncpy(result + offset, strs[i], len);
360 offset += len;
361 result[offset] = ' ';
362 offset++;
363 }
364
9cef3fd @marianoguerra off by one error and access after free memory, thanks valgrind
marianoguerra authored
365 result[offset - 1] = '\0';
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
366 return result;
367 }
368
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
369 int main (int argc, char **argv) {
9cef3fd @marianoguerra off by one error and access after free memory, thanks valgrind
marianoguerra authored
370 int count, is_test;
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
371 char buffer[STR_BUFFER_SIZE], *extra_args;
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
372 struct FnOptions* options = parse_options(argc, argv);
373
1405441 @marianoguerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
374 if (options->mode == 's') {
375 count = snprintf(buffer, STR_BUFFER_SIZE, "fn run shell%s%s",
376 options->appends, options->prepends);
4c4e3cc @marianoguerra some simplifications in fnc.c
marianoguerra authored
377 }
1405441 @marianoguerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
378 else {
379 if (options->files_num == 0) {
380 fn_options_delete(options);
381 fprintf(stderr, "at least one extra argument required\n");
382 return EXIT_FAILURE;
383 }
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
384
1405441 @marianoguerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
385 extra_args = str_join(options->files_num, options->files);
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
386
1405441 @marianoguerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
387 if (options->mode == 'r') {
388 if (options->files_num < 2) {
389 fprintf(stderr, "at least two arguments required, got %d\n",
390 options->files_num);
391 fprintf(stderr, " -r module function [arguments*]\n");
392 fprintf(stderr, " -r module function [arguments*]\n");
393 return EXIT_FAILURE;
394 }
395
396 count = snprintf(buffer, STR_BUFFER_SIZE, "%s%s%s", extra_args,
397 options->appends, options->prepends);
398 }
399 else if (strcmp(options->output_type, "beam") == 0) {
400 count = snprintf(buffer, STR_BUFFER_SIZE, "fn run %s \"%s\" %s",
401 options->output_type, options->output_path, extra_args);
402 }
403 else {
404 count = snprintf(buffer, STR_BUFFER_SIZE, "fn run %s %s",
405 options->output_type, extra_args);
77493d1 @marianoguerra added the -r option to run commands (replaces fn) and -T option to de…
marianoguerra authored
406 }
407
1405441 @marianoguerra initial implementation of -a and -p flags (-pa and -pz in erl command)
marianoguerra authored
408 free(extra_args);
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
409 }
410
411 assert(count <= STR_BUFFER_SIZE);
9cef3fd @marianoguerra off by one error and access after free memory, thanks valgrind
marianoguerra authored
412 is_test = options->is_test;
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
413 fn_options_delete(options);
cc5d656 @marianoguerra first working implementation of efene compiler frontend in C
marianoguerra authored
414
9cef3fd @marianoguerra off by one error and access after free memory, thanks valgrind
marianoguerra authored
415 return fn_run(buffer, argv[0], is_test);
2fd6e38 @marianoguerra initial import of the new compiler frontend
marianoguerra authored
416 }
Something went wrong with that request. Please try again.