Projects : gscm : gscm_usrbin
1 | /* Gales Scheme executable entry point and option parser |
2 | * J. Welsh, 2017 |
3 | */ |
4 | |
5 | #include "gscm.h" |
6 | |
7 | #ifndef GSCM_DEF_HEAP |
8 | #define GSCM_DEF_HEAP 128 |
9 | #endif |
10 | |
11 | #define STR_(token) #token |
12 | #define STR(token_or_macro) STR_(token_or_macro) |
13 | |
14 | static const char usage[] = |
15 | "Usage: gscm [-Hcgh] [-m SIZE] [--] [FILE [ARG ...]]" |
16 | "\n" |
17 | "\nExecute Scheme source FILE (- for standard input, unless -- is used), with FILE and any ARGs stored in the global list *ARGS*. If no FILE is given, start a read-eval-print loop." |
18 | "\n" |
19 | "\n-H: Use huge pages if supported" |
20 | "\n-c: Load saved core instead of source (TODO)" |
21 | "\n-g: Print memory stats to standard error on garbage collection" |
22 | "\n-h: Print this help message" |
23 | "\n-m: Heap size in MiB. Twice this is fully allocated at startup from the OS kernel's point of view (half reserved for garbage collection). A larger heap reduces GC frequency but may increase virtual memory overhead (TLB thrashing)." |
24 | "\n" |
25 | "\nBuild configuration:" |
26 | "\n Word size (bytes): " STR(__SIZEOF_POINTER__) |
27 | "\n Default heap (-m): " STR(GSCM_DEF_HEAP) |
28 | "\n Library path: " GSCMLIB |
29 | "\n"; |
30 | |
31 | /* Strictly parse non-negative decimal integer in null-terminated string src. On success, return true and store the result in dst. On failure (empty string, non-digit or overflow), return false. */ |
32 | static int parse_ulong_dec(unsigned long *dst, const char *src) { |
33 | unsigned long acc = 0; |
34 | if (!*src) return 0; |
35 | do { |
36 | unsigned char digit = ((unsigned char)(*src)) - '0'; |
37 | if (digit > 9) return 0; |
38 | if (acc > (-1UL)/10) return 0; |
39 | acc *= 10; |
40 | if (acc + digit < acc) return 0; |
41 | acc += digit; |
42 | } while (*++src); |
43 | *dst = acc; |
44 | return 1; |
45 | } |
46 | |
47 | int main(int argc, char **argv) { |
48 | sc_value heap_mb = GSCM_DEF_HEAP, heap_alloc; |
49 | #define SHIFT (++argv, --argc) |
50 | if (argc) SHIFT; |
51 | while (argc) { |
52 | char *arg = *argv; |
53 | if (arg[0] != '-' || !arg[1] || (arg[1] == '-' && !arg[2])) break; |
54 | while (*++arg) switch (*arg) { |
55 | case 'H': |
56 | sc_hugepages = 1; break; |
57 | /* case 'c': break; */ |
58 | case 'g': |
59 | sc_gc_verbose = 1; break; |
60 | case 'h': |
61 | sc_write_error(usage); return 0; |
62 | case 'm': |
63 | if (!*++arg) { |
64 | SHIFT; |
65 | if (!argc) { |
66 | sc_write_error("gscm: -m missing argument\n"); |
67 | goto err; |
68 | } |
69 | arg = *argv; |
70 | } |
71 | if (!(parse_ulong_dec(&heap_mb, arg) && heap_mb)) { |
72 | sc_write_error("gscm: bad -m argument\n"); |
73 | goto err; |
74 | } |
75 | goto next_arg; |
76 | default: |
77 | { |
78 | char tail[] = {*arg, '\n', 0}; |
79 | sc_write_error("gscm: bad option: "); |
80 | sc_write_error(tail); |
81 | goto err; |
82 | } |
83 | } |
84 | next_arg: |
85 | SHIFT; |
86 | } |
87 | heap_alloc = heap_mb<<21; |
88 | if (heap_alloc>>21 != heap_mb) { |
89 | sc_write_error("gscm: heap size too big (integer overflow)\n"); |
90 | return 1; |
91 | } |
92 | sc_init(heap_alloc); |
93 | return sc_toplevel(argc, argv); |
94 | err: |
95 | sc_write_error(usage); |
96 | return 1; |
97 | } |