/* Gales Scheme executable entry point and option parser * J. Welsh, 2017 */ #include "gscm.h" #ifndef GSCM_DEF_HEAP #define GSCM_DEF_HEAP 128 #endif #define STR_(token) #token #define STR(token_or_macro) STR_(token_or_macro) static const char usage[] = "Usage: gscm [-Hcgh] [-m SIZE] [--] [FILE [ARG ...]]" "\n" "\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." "\n" "\n-H: Use huge pages if supported" "\n-c: Load saved core instead of source (TODO)" "\n-g: Print memory stats to standard error on garbage collection" "\n-h: Print this help message" "\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)." "\n" "\nBuild configuration:" "\n Word size (bytes): " STR(__SIZEOF_POINTER__) "\n Default heap (-m): " STR(GSCM_DEF_HEAP) "\n Library path: " GSCMLIB "\n"; /* 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. */ static int parse_ulong_dec(unsigned long *dst, const char *src) { unsigned long acc = 0; if (!*src) return 0; do { unsigned char digit = ((unsigned char)(*src)) - '0'; if (digit > 9) return 0; if (acc > (-1UL)/10) return 0; acc *= 10; if (acc + digit < acc) return 0; acc += digit; } while (*++src); *dst = acc; return 1; } int main(int argc, char **argv) { sc_value heap_mb = GSCM_DEF_HEAP, heap_alloc; #define SHIFT (++argv, --argc) if (argc) SHIFT; while (argc) { char *arg = *argv; if (arg[0] != '-' || !arg[1] || (arg[1] == '-' && !arg[2])) break; while (*++arg) switch (*arg) { case 'H': sc_hugepages = 1; break; /* case 'c': break; */ case 'g': sc_gc_verbose = 1; break; case 'h': sc_write_error(usage); return 0; case 'm': if (!*++arg) { SHIFT; if (!argc) { sc_write_error("gscm: -m missing argument\n"); goto err; } arg = *argv; } if (!(parse_ulong_dec(&heap_mb, arg) && heap_mb)) { sc_write_error("gscm: bad -m argument\n"); goto err; } goto next_arg; default: { char tail[] = {*arg, '\n', 0}; sc_write_error("gscm: bad option: "); sc_write_error(tail); goto err; } } next_arg: SHIFT; } heap_alloc = heap_mb<<21; if (heap_alloc>>21 != heap_mb) { sc_write_error("gscm: heap size too big (integer overflow)\n"); return 1; } sc_init(heap_alloc); return sc_toplevel(argc, argv); err: sc_write_error(usage); return 1; }