Remove old GUM/GranSim code
[ghc-hetmet.git] / rts / RtsFlags.c
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The AQUA Project, Glasgow University, 1994-1997
4  * (c) The GHC Team, 1998-2006
5  *
6  * Functions for parsing the argument list.
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #include "PosixSource.h"
11 #include "Rts.h"
12 #include "RtsFlags.h"
13 #include "RtsUtils.h"
14 #include "Profiling.h"
15
16 #ifdef HAVE_CTYPE_H
17 #include <ctype.h>
18 #endif
19
20 #include <stdlib.h>
21 #include <string.h>
22
23 // Flag Structure
24 RTS_FLAGS RtsFlags;
25
26 /*
27  * Split argument lists
28  */
29 int     prog_argc = 0;    /* an "int" so as to match normal "argc" */
30 char  **prog_argv = NULL;
31 int     full_prog_argc = 0;    /* an "int" so as to match normal "argc" */
32 char  **full_prog_argv = NULL;
33 char   *prog_name = NULL; /* 'basename' of prog_argv[0] */
34 int     rts_argc = 0;  /* ditto */
35 char   *rts_argv[MAX_RTS_ARGS];
36
37 /*
38  * constants, used later 
39  */
40 #define RTS 1
41 #define PGM 0
42
43 /* -----------------------------------------------------------------------------
44    Static function decls
45    -------------------------------------------------------------------------- */
46
47 static int              /* return NULL on error */
48 open_stats_file (
49     I_ arg,
50     int argc, char *argv[],
51     int rts_argc, char *rts_argv[],
52     const char *FILENAME_FMT,
53     FILE **file_ret);
54
55 static I_ decode(const char *s);
56 static void bad_option(const char *s);
57
58 /* -----------------------------------------------------------------------------
59  * Command-line option parsing routines.
60  * ---------------------------------------------------------------------------*/
61
62 void initRtsFlagsDefaults(void)
63 {
64     RtsFlags.GcFlags.statsFile          = NULL;
65     RtsFlags.GcFlags.giveStats          = NO_GC_STATS;
66
67     RtsFlags.GcFlags.maxStkSize         = (8 * 1024 * 1024) / sizeof(W_);
68     RtsFlags.GcFlags.initialStkSize     = 1024 / sizeof(W_);
69
70     RtsFlags.GcFlags.minAllocAreaSize   = (512 * 1024)        / BLOCK_SIZE;
71     RtsFlags.GcFlags.minOldGenSize      = (1024 * 1024)       / BLOCK_SIZE;
72     RtsFlags.GcFlags.maxHeapSize        = 0;    /* off by default */
73     RtsFlags.GcFlags.heapSizeSuggestion = 0;    /* none */
74     RtsFlags.GcFlags.pcFreeHeap         = 3;    /* 3% */
75     RtsFlags.GcFlags.oldGenFactor       = 2;
76     RtsFlags.GcFlags.generations        = 2;
77     RtsFlags.GcFlags.steps              = 2;
78     RtsFlags.GcFlags.squeezeUpdFrames   = rtsTrue;
79     RtsFlags.GcFlags.compact            = rtsFalse;
80     RtsFlags.GcFlags.compactThreshold   = 30.0;
81     RtsFlags.GcFlags.sweep              = rtsFalse;
82 #ifdef RTS_GTK_FRONTPANEL
83     RtsFlags.GcFlags.frontpanel         = rtsFalse;
84 #endif
85     RtsFlags.GcFlags.idleGCDelayTime    = 300; /* millisecs */
86
87 #if osf3_HOST_OS
88 /* ToDo: Perhaps by adjusting this value we can make linking without
89  * -static work (i.e., not generate a core-dumping executable)? */
90 # if SIZEOF_VOID_P == 8
91     RtsFlags.GcFlags.heapBase           = 0x180000000L;
92 # else
93 #  error I have no idea where to begin the heap on a non-64-bit osf3 machine.
94 # endif
95 #else
96     RtsFlags.GcFlags.heapBase           = 0;   /* means don't care */
97 #endif
98
99 #ifdef DEBUG
100     RtsFlags.DebugFlags.scheduler       = rtsFalse;
101     RtsFlags.DebugFlags.interpreter     = rtsFalse;
102     RtsFlags.DebugFlags.weak            = rtsFalse;
103     RtsFlags.DebugFlags.gccafs          = rtsFalse;
104     RtsFlags.DebugFlags.gc              = rtsFalse;
105     RtsFlags.DebugFlags.block_alloc     = rtsFalse;
106     RtsFlags.DebugFlags.sanity          = rtsFalse;
107     RtsFlags.DebugFlags.stable          = rtsFalse;
108     RtsFlags.DebugFlags.stm             = rtsFalse;
109     RtsFlags.DebugFlags.prof            = rtsFalse;
110     RtsFlags.DebugFlags.eventlog        = rtsFalse;
111     RtsFlags.DebugFlags.apply           = rtsFalse;
112     RtsFlags.DebugFlags.linker          = rtsFalse;
113     RtsFlags.DebugFlags.squeeze         = rtsFalse;
114     RtsFlags.DebugFlags.hpc             = rtsFalse;
115     RtsFlags.DebugFlags.timestamp       = rtsFalse;
116 #endif
117
118 #if defined(PROFILING)
119     RtsFlags.CcFlags.doCostCentres      = 0;
120 #endif /* PROFILING */
121
122     RtsFlags.ProfFlags.doHeapProfile      = rtsFalse;
123     RtsFlags.ProfFlags.profileInterval    = 100;
124
125 #ifdef PROFILING
126     RtsFlags.ProfFlags.includeTSOs        = rtsFalse;
127     RtsFlags.ProfFlags.showCCSOnException = rtsFalse;
128     RtsFlags.ProfFlags.maxRetainerSetSize = 8;
129     RtsFlags.ProfFlags.ccsLength          = 25;
130     RtsFlags.ProfFlags.modSelector        = NULL;
131     RtsFlags.ProfFlags.descrSelector      = NULL;
132     RtsFlags.ProfFlags.typeSelector       = NULL;
133     RtsFlags.ProfFlags.ccSelector         = NULL;
134     RtsFlags.ProfFlags.ccsSelector        = NULL;
135     RtsFlags.ProfFlags.retainerSelector   = NULL;
136     RtsFlags.ProfFlags.bioSelector        = NULL;
137 #endif
138
139 #ifdef EVENTLOG
140     RtsFlags.EventLogFlags.doEventLogging = rtsFalse;
141 #endif
142
143     RtsFlags.MiscFlags.tickInterval     = 20;  /* In milliseconds */
144     RtsFlags.ConcFlags.ctxtSwitchTime   = 20;  /* In milliseconds */
145
146     RtsFlags.MiscFlags.install_signal_handlers = rtsTrue;
147     RtsFlags.MiscFlags.machineReadable = rtsFalse;
148     RtsFlags.MiscFlags.linkerMemBase    = 0;
149
150 #ifdef THREADED_RTS
151     RtsFlags.ParFlags.nNodes            = 1;
152     RtsFlags.ParFlags.migrate           = rtsTrue;
153     RtsFlags.ParFlags.wakeupMigrate     = rtsFalse;
154     RtsFlags.ParFlags.parGcEnabled      = 1;
155     RtsFlags.ParFlags.parGcGen          = 1;
156     RtsFlags.ParFlags.parGcLoadBalancing = 1;
157     RtsFlags.ParFlags.setAffinity       = 0;
158 #endif
159
160 #if defined(THREADED_RTS)
161     RtsFlags.ParFlags.maxLocalSparks    = 4096;
162 #endif /* THREADED_RTS */
163
164 #ifdef TICKY_TICKY
165     RtsFlags.TickyFlags.showTickyStats   = rtsFalse;
166     RtsFlags.TickyFlags.tickyFile        = NULL;
167 #endif
168
169 #ifdef USE_PAPI
170     /* By default no special measurements taken */
171     RtsFlags.PapiFlags.eventType        = 0;
172     RtsFlags.PapiFlags.numUserEvents    = 0;
173 #endif
174 }
175
176 static const char *
177 usage_text[] = {
178 "",
179 "Usage: <prog> <args> [+RTS <rtsopts> | -RTS <args>] ... --RTS <args>",
180 "",
181 "   +RTS    Indicates run time system options follow",
182 "   -RTS    Indicates program arguments follow",
183 "  --RTS    Indicates that ALL subsequent arguments will be given to the",
184 "           program (including any of these RTS flags)",
185 "",
186 "The following run time system options are available:",
187 "",
188 "  -?       Prints this message and exits; the program is not executed",
189 "  --info   Print information about the RTS used by this program",
190 "",
191 "  -K<size> Sets the maximum stack size (default 8M)  Egs: -K32k   -K512k",
192 "  -k<size> Sets the initial thread stack size (default 1k)  Egs: -k4k   -k2m",
193 "",
194 "  -A<size> Sets the minimum allocation area size (default 512k) Egs: -A1m -A10k",
195 "  -M<size> Sets the maximum heap size (default unlimited)  Egs: -M256k -M1G",
196 "  -H<size> Sets the minimum heap size (default 0M)   Egs: -H24m  -H1G",
197 "  -m<n>    Minimum % of heap which must be available (default 3%)",
198 "  -G<n>    Number of generations (default: 2)",
199 "  -T<n>    Number of steps in younger generations (default: 2)",
200 "  -c<n>    Auto-enable compaction of the oldest generation when live data is",
201 "           at least <n>% of the maximum heap size set with -M (default: 30%)",
202 "  -c       Enable compaction for all major collections",
203 "  -w       Use mark-region for the oldest generation (experimental)",
204 #if defined(THREADED_RTS)
205 "  -I<sec>  Perform full GC after <sec> idle time (default: 0.3, 0 == off)",
206 #endif
207 "",
208 "  -t[<file>] One-line GC statistics (if <file> omitted, uses stderr)",
209 "  -s[<file>] Summary  GC statistics (if <file> omitted, uses stderr)",
210 "  -S[<file>] Detailed GC statistics (if <file> omitted, uses stderr)",
211 #ifdef RTS_GTK_FRONTPANEL
212 "  -f       Display front panel (requires X11 & GTK+)",
213 #endif
214 "",
215 "",
216 "  -Z       Don't squeeze out update frames on stack overflow",
217 "  -B       Sound the bell at the start of each garbage collection",
218 #if defined(PROFILING)
219 "",
220 "  -px      Time/allocation profile (XML)  (output file <program>.prof)",
221 "  -p       Time/allocation profile        (output file <program>.prof)",
222 "  -P       More detailed Time/Allocation profile",
223 "  -Pa      Give information about *all* cost centres",
224
225 # if defined(PROFILING)
226 "",
227 "  -hx            Heap residency profile (XML)   (output file <program>.prof)",
228 "  -h<break-down> Heap residency profile (hp2ps) (output file <program>.hp)",
229 "     break-down: c = cost centre stack (default)",
230 "                 m = module",
231 "                 d = closure description",
232 "                 y = type description",
233 "                 r = retainer",
234 "                 b = biography (LAG,DRAG,VOID,USE)",
235 "  A subset of closures may be selected thusly:",
236 "    -hc<cc>,...  specific cost centre(s) (top of stack only)",
237 "    -hC<cc>,...  specific cost centre(s) (anywhere in stack)",
238 "    -hm<mod>...  all cost centres from the specified modules(s)",
239 "    -hd<des>,... closures with specified closure descriptions",
240 "    -hy<typ>...  closures with specified type descriptions",
241 "    -hr<cc>...   closures with specified retainers",
242 "    -hb<bio>...  closures with specified biographies (lag,drag,void,use)",
243 "",
244 "  -R<size>       Set the maximum retainer set size (default: 8)",
245 "", 
246 "  -L<chars>      Maximum length of a cost-centre stack in a heap profile",
247 "                 (default: 25)",
248 "",
249 "  -xt            Include threads (TSOs) in a heap profile",
250 "",
251 "  -xc      Show current cost centre stack on raising an exception",
252 "",
253 # endif
254 #endif /* PROFILING or PAR */
255
256 #ifdef EVENTLOG
257 "",
258 "  -l       Log runtime events (generates binary trace file <program>.eventlog)",
259 "",
260 #endif
261
262 #if !defined(PROFILING)
263 "",
264 "  -hT      Heap residency profile (output file <program>.hp)",
265 #endif
266 "  -i<sec>  Time between heap samples (seconds, default: 0.1)",
267 "",
268 #if defined(TICKY_TICKY)
269 "  -r<file>  Produce ticky-ticky statistics (with -rstderr for stderr)",
270 "",
271 #endif
272 "  -C<secs>  Context-switch interval in seconds.",
273 "            0 or no argument means switch as often as possible.",
274 "            Default: 0.02 sec; resolution is set by -V below.",
275 "  -V<secs>  Master tick interval in seconds (0 == disable timer).",
276 "            This sets the resolution for -C and the profile timer -i.",
277 "            Default: 0.02 sec.",
278 "",
279 "  -vt       Time-stamp debug messages",
280 "",
281 #if defined(DEBUG)
282 "  -Ds  DEBUG: scheduler",
283 "  -Di  DEBUG: interpreter",
284 "  -Dw  DEBUG: weak",
285 "  -DG  DEBUG: gccafs",
286 "  -Dg  DEBUG: gc",
287 "  -Db  DEBUG: block",
288 "  -DS  DEBUG: sanity",
289 "  -Dt  DEBUG: stable",
290 "  -Dp  DEBUG: prof",
291 "  -De  DEBUG: event logging",
292 "  -Da  DEBUG: apply",
293 "  -Dl  DEBUG: linker",
294 "  -Dm  DEBUG: stm",
295 "  -Dz  DEBUG: stack squezing",
296 "  -Dc  DEBUG: program coverage",
297 "",
298 #endif /* DEBUG */
299 #if defined(THREADED_RTS) && !defined(NOSMP)
300 "  -N<n>     Use <n> processors (default: 1)",
301 "  -N        Determine the number of processors to use automatically",
302 "  -q1       Use one OS thread for GC (turns off parallel GC)",
303 "  -qg<n>    Use parallel GC only for generations >= <n> (default: 1)",
304 "  -qb       Disable load-balancing in the parallel GC",
305 "  -qa       Use the OS to set thread affinity",
306 "  -qm       Don't automatically migrate threads between CPUs",
307 "  -qw       Migrate a thread to the current CPU when it is woken up",
308 #endif
309 "  --install-signal-handlers=<yes|no>",
310 "            Install signal handlers (default: yes)",
311 #if defined(THREADED_RTS)
312 "  -e<size>  Size of spark pools (default 100)",
313 #endif
314 #if defined(THREADED_RTS)
315 "  -e<n>     Maximum number of outstanding local sparks (default: 4096)",
316 #endif
317 #if defined(x86_64_HOST_ARCH)
318 "  -xm       Base address to mmap memory in the GHCi linker",
319 "            (hex; must be <80000000)",
320 #endif
321 #if defined(USE_PAPI)
322 "  -aX       CPU performance counter measurements using PAPI",
323 "            (use with the -s<file> option).  X is one of:",
324 "",
325 /* "            y - cycles", */
326 "            1 - level 1 cache misses",
327 "            2 - level 2 cache misses",
328 "            b - branch mispredictions",
329 "            s - stalled cycles",
330 "            e - cache miss and branch misprediction events",
331 #endif
332 "",
333 "RTS options may also be specified using the GHCRTS environment variable.",
334 "",
335 "Other RTS options may be available for programs compiled a different way.",
336 "The GHC User's Guide has full details.",
337 "",
338 0
339 };
340
341 STATIC_INLINE rtsBool
342 strequal(const char *a, const char * b)
343 {
344     return(strcmp(a, b) == 0);
345 }
346
347 static void
348 splitRtsFlags(char *s, int *rts_argc, char *rts_argv[])
349 {
350     char *c1, *c2;
351
352     c1 = s;
353     do {
354         while (isspace(*c1)) { c1++; };
355         c2 = c1;
356         while (!isspace(*c2) && *c2 != '\0') { c2++; };
357         
358         if (c1 == c2) { break; }
359         
360         if (*rts_argc < MAX_RTS_ARGS-1) {
361             s = stgMallocBytes(c2-c1+1, "RtsFlags.c:splitRtsFlags()");
362             strncpy(s, c1, c2-c1);
363             s[c2-c1] = '\0';
364             rts_argv[(*rts_argc)++] = s;
365         } else {
366             barf("too many RTS arguments (max %d)", MAX_RTS_ARGS-1);
367         }
368         
369         c1 = c2;
370     } while (*c1 != '\0');
371 }
372     
373 void
374 setupRtsFlags(int *argc, char *argv[], int *rts_argc, char *rts_argv[])
375 {
376     rtsBool error = rtsFalse;
377     I_ mode;
378     I_ arg, total_arg;
379
380     setProgName (argv);
381     total_arg = *argc;
382     arg = 1;
383
384     *argc = 1;
385     *rts_argc = 0;
386
387     // process arguments from the ghc_rts_opts global variable first.
388     // (arguments from the GHCRTS environment variable and the command
389     // line override these).
390     {
391         if (ghc_rts_opts != NULL) {
392             splitRtsFlags(ghc_rts_opts, rts_argc, rts_argv);
393         }
394     }
395
396     // process arguments from the GHCRTS environment variable next
397     // (arguments from the command line override these).
398     {
399         char *ghc_rts = getenv("GHCRTS");
400
401         if (ghc_rts != NULL) {
402             splitRtsFlags(ghc_rts, rts_argc, rts_argv);
403         }
404     }
405
406     // Split arguments (argv) into PGM (argv) and RTS (rts_argv) parts
407     //   argv[0] must be PGM argument -- leave in argv
408
409     for (mode = PGM; arg < total_arg; arg++) {
410         // The '--RTS' argument disables all future +RTS ... -RTS processing.
411         if (strequal("--RTS", argv[arg])) {
412             arg++;
413             break;
414         }
415         // The '--' argument is passed through to the program, but
416         // disables all further +RTS ... -RTS processing.
417         else if (strequal("--", argv[arg])) {
418             break;
419         }
420         else if (strequal("+RTS", argv[arg])) {
421             mode = RTS;
422         }
423         else if (strequal("-RTS", argv[arg])) {
424             mode = PGM;
425         }
426         else if (mode == RTS && *rts_argc < MAX_RTS_ARGS-1) {
427             rts_argv[(*rts_argc)++] = argv[arg];
428         }
429         else if (mode == PGM) {
430             argv[(*argc)++] = argv[arg];
431         }
432         else {
433           barf("too many RTS arguments (max %d)", MAX_RTS_ARGS-1);
434         }
435     }
436     // process remaining program arguments
437     for (; arg < total_arg; arg++) {
438         argv[(*argc)++] = argv[arg];
439     }
440     argv[*argc] = (char *) 0;
441     rts_argv[*rts_argc] = (char *) 0;
442
443     // Process RTS (rts_argv) part: mainly to determine statsfile
444     for (arg = 0; arg < *rts_argc; arg++) {
445         if (rts_argv[arg][0] != '-') {
446             fflush(stdout);
447             errorBelch("unexpected RTS argument: %s", rts_argv[arg]);
448             error = rtsTrue;
449
450         } else {
451             switch(rts_argv[arg][1]) {
452
453               /* process: general args, then PROFILING-only ones, then
454                  CONCURRENT-only, TICKY-only (same order as defined in
455                  RtsFlags.lh); within those groups, mostly in
456                  case-insensitive alphabetical order.  Final group is
457                  x*, which allows for more options.
458               */
459
460 #ifdef TICKY_TICKY
461 # define TICKY_BUILD_ONLY(x) x
462 #else
463 # define TICKY_BUILD_ONLY(x) \
464 errorBelch("not built for: ticky-ticky stats"); \
465 error = rtsTrue;
466 #endif
467
468 #ifdef PROFILING
469 # define PROFILING_BUILD_ONLY(x)   x
470 #else
471 # define PROFILING_BUILD_ONLY(x) \
472 errorBelch("not built for: -prof"); \
473 error = rtsTrue;
474 #endif
475
476 #ifdef EVENTLOG
477 # define EVENTLOG_BUILD_ONLY(x)   x
478 #else
479 # define EVENTLOG_BUILD_ONLY(x) \
480 errorBelch("not built for: -par-prof"); \
481 error = rtsTrue;
482 #endif
483
484 #ifdef THREADED_RTS
485 # define THREADED_BUILD_ONLY(x)      x
486 #else
487 # define THREADED_BUILD_ONLY(x) \
488 errorBelch("not built for: -smp"); \
489 error = rtsTrue;
490 #endif
491
492               /* =========== GENERAL ========================== */
493               case '?':
494                 error = rtsTrue;
495                 break;
496
497               /* This isn't going to allow us to keep related options
498                  together as we add more --* flags. We really need a
499                  proper options parser. */
500               case '-':
501                   if (strequal("install-signal-handlers=yes",
502                                &rts_argv[arg][2])) {
503                       RtsFlags.MiscFlags.install_signal_handlers = rtsTrue;
504                   }
505                   else if (strequal("install-signal-handlers=no",
506                                &rts_argv[arg][2])) {
507                       RtsFlags.MiscFlags.install_signal_handlers = rtsFalse;
508                   }
509                   else if (strequal("machine-readable",
510                                &rts_argv[arg][2])) {
511                       RtsFlags.MiscFlags.machineReadable = rtsTrue;
512                   }
513                   else if (strequal("info",
514                                &rts_argv[arg][2])) {
515                       printRtsInfo();
516                       exit(0);
517                   }
518                   else {
519                       errorBelch("unknown RTS option: %s",rts_argv[arg]);
520                       error = rtsTrue;
521                   }
522                   break;
523               case 'A':
524                 RtsFlags.GcFlags.minAllocAreaSize
525                   = decode(rts_argv[arg]+2) / BLOCK_SIZE;
526                 if (RtsFlags.GcFlags.minAllocAreaSize <= 0) {
527                   bad_option(rts_argv[arg]);
528                 }
529                 break;
530
531 #ifdef USE_PAPI
532               case 'a':
533                 switch(rts_argv[arg][2]) {
534                 case '1':
535                   RtsFlags.PapiFlags.eventType = PAPI_FLAG_CACHE_L1;
536                   break;
537                 case '2':
538                   RtsFlags.PapiFlags.eventType = PAPI_FLAG_CACHE_L2;
539                   break;
540                 case 'b':
541                   RtsFlags.PapiFlags.eventType = PAPI_FLAG_BRANCH;
542                   break;
543                 case 's':
544                   RtsFlags.PapiFlags.eventType = PAPI_FLAG_STALLS;
545                   break;
546                 case 'e':
547                   RtsFlags.PapiFlags.eventType = PAPI_FLAG_CB_EVENTS;
548                   break;
549                 case '+':
550                   if (RtsFlags.PapiFlags.numUserEvents >= MAX_PAPI_USER_EVENTS) {
551                       errorBelch("maximum number of PAPI events reached");
552                       stg_exit(EXIT_FAILURE);
553                   }
554                   RtsFlags.PapiFlags.eventType = PAPI_USER_EVENTS;
555                   RtsFlags.PapiFlags.userEvents[RtsFlags.PapiFlags.numUserEvents++] = rts_argv[arg] + 3;
556                   break;
557                 default:
558                   bad_option( rts_argv[arg] );
559                 }
560                 break;
561 #endif
562
563               case 'B':
564                 RtsFlags.GcFlags.ringBell = rtsTrue;
565                 break;
566
567               case 'c':
568                   if (rts_argv[arg][2] != '\0') {
569                       RtsFlags.GcFlags.compactThreshold =
570                           atof(rts_argv[arg]+2);
571                   } else {
572                       RtsFlags.GcFlags.compact = rtsTrue;
573                   }
574                   break;
575
576               case 'w':
577                 RtsFlags.GcFlags.sweep = rtsTrue;
578                 break;
579
580               case 'F':
581                 RtsFlags.GcFlags.oldGenFactor = atof(rts_argv[arg]+2);
582               
583                 if (RtsFlags.GcFlags.oldGenFactor < 0)
584                   bad_option( rts_argv[arg] );
585                 break;
586               
587 #ifdef DEBUG
588               case 'D':
589               { 
590                   char *c;
591
592                   for (c  = rts_argv[arg] + 2; *c != '\0'; c++) {
593                       switch (*c) {
594                       case 's':
595                           RtsFlags.DebugFlags.scheduler = rtsTrue;
596                           break;
597                       case 'i':
598                           RtsFlags.DebugFlags.interpreter = rtsTrue;
599                           break;
600                       case 'w':
601                           RtsFlags.DebugFlags.weak = rtsTrue;
602                           break;
603                       case 'G':
604                           RtsFlags.DebugFlags.gccafs = rtsTrue;
605                           break;
606                       case 'g':
607                           RtsFlags.DebugFlags.gc = rtsTrue;
608                           break;
609                       case 'b':
610                           RtsFlags.DebugFlags.block_alloc = rtsTrue;
611                           break;
612                       case 'S':
613                           RtsFlags.DebugFlags.sanity = rtsTrue;
614                           break;
615                       case 't':
616                           RtsFlags.DebugFlags.stable = rtsTrue;
617                           break;
618                       case 'p':
619                           RtsFlags.DebugFlags.prof = rtsTrue;
620                           break;
621                       case 'e':
622                           RtsFlags.DebugFlags.eventlog = rtsTrue;
623                           break;
624                       case 'l':
625                           RtsFlags.DebugFlags.linker = rtsTrue;
626                           break;
627                       case 'a':
628                           RtsFlags.DebugFlags.apply = rtsTrue;
629                           break;
630                       case 'm':
631                           RtsFlags.DebugFlags.stm = rtsTrue;
632                           break;
633                       case 'z':
634                           RtsFlags.DebugFlags.squeeze = rtsTrue;
635                           break;
636                       case 'c':
637                           RtsFlags.DebugFlags.hpc = rtsTrue;
638                           break;
639                       default:
640                           bad_option( rts_argv[arg] );
641                       }
642                   }
643                   break;
644               }
645 #endif
646
647               case 'K':
648                 RtsFlags.GcFlags.maxStkSize = 
649                   decode(rts_argv[arg]+2) / sizeof(W_);
650
651                 if (RtsFlags.GcFlags.maxStkSize == 0) 
652                   bad_option( rts_argv[arg] );
653                 break;
654
655               case 'k':
656                 RtsFlags.GcFlags.initialStkSize = 
657                   decode(rts_argv[arg]+2) / sizeof(W_);
658
659                 if (RtsFlags.GcFlags.initialStkSize == 0) 
660                   bad_option( rts_argv[arg] );
661                 break;
662
663               case 'M':
664                 RtsFlags.GcFlags.maxHeapSize = 
665                   decode(rts_argv[arg]+2) / BLOCK_SIZE;
666                 /* user give size in *bytes* but "maxHeapSize" is in *blocks* */
667
668                 if (RtsFlags.GcFlags.maxHeapSize <= 0) {
669                   bad_option(rts_argv[arg]);
670                 }
671                 break;
672
673               case 'm':
674                 RtsFlags.GcFlags.pcFreeHeap = atof(rts_argv[arg]+2);
675
676                 if (RtsFlags.GcFlags.pcFreeHeap < 0 || 
677                     RtsFlags.GcFlags.pcFreeHeap > 100)
678                   bad_option( rts_argv[arg] );
679                 break;
680
681               case 'G':
682                 RtsFlags.GcFlags.generations = decode(rts_argv[arg]+2);
683                 if (RtsFlags.GcFlags.generations < 1) {
684                   bad_option(rts_argv[arg]);
685                 }
686                 break;
687
688               case 'T':
689                 RtsFlags.GcFlags.steps = decode(rts_argv[arg]+2);
690                 if (RtsFlags.GcFlags.steps < 1) {
691                   bad_option(rts_argv[arg]);
692                 }
693                 break;
694
695               case 'H':
696                 RtsFlags.GcFlags.heapSizeSuggestion = 
697                   decode(rts_argv[arg]+2) / BLOCK_SIZE;
698                 break;
699
700 #ifdef RTS_GTK_FRONTPANEL
701               case 'f':
702                   RtsFlags.GcFlags.frontpanel = rtsTrue;
703                   break;
704 #endif
705
706               case 'I': /* idle GC delay */
707                 if (rts_argv[arg][2] == '\0') {
708                   /* use default */
709                 } else {
710                     I_ cst; /* tmp */
711
712                     /* Convert to millisecs */
713                     cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
714                     RtsFlags.GcFlags.idleGCDelayTime = cst;
715                 }
716                 break;
717
718               case 'S':
719                   RtsFlags.GcFlags.giveStats = VERBOSE_GC_STATS;
720                   goto stats;
721
722               case 's':
723                   RtsFlags.GcFlags.giveStats = SUMMARY_GC_STATS;
724                   goto stats;
725
726               case 't':
727                   RtsFlags.GcFlags.giveStats = ONELINE_GC_STATS;
728                   goto stats;
729
730             stats:
731                 { 
732                     int r;
733                     r = open_stats_file(arg, *argc, argv,
734                                         *rts_argc, rts_argv, NULL,
735                                         &RtsFlags.GcFlags.statsFile);
736                     if (r == -1) { error = rtsTrue; }
737                 }
738                 break;
739
740               case 'Z':
741                 RtsFlags.GcFlags.squeezeUpdFrames = rtsFalse;
742                 break;
743
744               /* =========== PROFILING ========================== */
745
746               case 'l':
747 #ifdef EVENTLOG
748                   RtsFlags.EventLogFlags.doEventLogging = rtsTrue;
749 #else
750                   errorBelch("not built for: -eventlog");
751 #endif
752                   break;
753
754               case 'P': /* detailed cost centre profiling (time/alloc) */
755               case 'p': /* cost centre profiling (time/alloc) */
756                 PROFILING_BUILD_ONLY(
757                 switch (rts_argv[arg][2]) {
758                   case 'x':
759                     RtsFlags.CcFlags.doCostCentres = COST_CENTRES_XML;
760                     break;
761                   case 'a':
762                     RtsFlags.CcFlags.doCostCentres = COST_CENTRES_ALL;
763                     break;
764                   default:
765                       if (rts_argv[arg][1] == 'P') {
766                           RtsFlags.CcFlags.doCostCentres =
767                               COST_CENTRES_VERBOSE;
768                       } else {
769                           RtsFlags.CcFlags.doCostCentres =
770                               COST_CENTRES_SUMMARY;
771                       }
772                       break;
773                 }
774                 ) break;
775
776               case 'R':
777                   PROFILING_BUILD_ONLY(
778                       RtsFlags.ProfFlags.maxRetainerSetSize = atof(rts_argv[arg]+2);
779                   ) break;
780               case 'L':
781                   PROFILING_BUILD_ONLY(
782                       RtsFlags.ProfFlags.ccsLength = atof(rts_argv[arg]+2);
783                       if(RtsFlags.ProfFlags.ccsLength <= 0) {
784                         bad_option(rts_argv[arg]);
785                       }
786                   ) break;
787               case 'h': /* serial heap profile */
788 #if !defined(PROFILING)
789                 switch (rts_argv[arg][2]) {
790                   case '\0':
791                   case 'T':
792                     RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CLOSURE_TYPE;
793                     break;
794                   default:
795                     errorBelch("invalid heap profile option: %s",rts_argv[arg]);
796                     error = rtsTrue;
797                 }
798 #else
799                 PROFILING_BUILD_ONLY(
800                 switch (rts_argv[arg][2]) {
801                 case '\0':
802                 case 'C':
803                 case 'c':
804                 case 'M':
805                 case 'm':
806                 case 'D':
807                 case 'd':
808                 case 'Y':
809                 case 'y':
810                 case 'R':
811                 case 'r':
812                 case 'B':
813                 case 'b':
814                     if (rts_argv[arg][2] != '\0' && rts_argv[arg][3] != '\0') {
815                         {
816                             char *left  = strchr(rts_argv[arg], '{');
817                             char *right = strrchr(rts_argv[arg], '}');
818
819                             // curly braces are optional, for
820                             // backwards compat.
821                             if (left)
822                                 left = left+1;
823                             else
824                                 left = rts_argv[arg] + 3;
825
826                             if (!right)
827                                 right = rts_argv[arg] + strlen(rts_argv[arg]);
828
829                             *right = '\0';
830
831                             switch (rts_argv[arg][2]) {
832                             case 'c': // cost centre label select
833                                 RtsFlags.ProfFlags.ccSelector = left;
834                                 break;
835                             case 'C':
836                                 RtsFlags.ProfFlags.ccsSelector = left;
837                                 break;
838                             case 'M':
839                             case 'm': // cost centre module select
840                                 RtsFlags.ProfFlags.modSelector = left;
841                                 break;
842                             case 'D':
843                             case 'd': // closure descr select 
844                                 RtsFlags.ProfFlags.descrSelector = left;
845                                 break;
846                             case 'Y':
847                             case 'y': // closure type select
848                                 RtsFlags.ProfFlags.typeSelector = left;
849                                 break;
850                             case 'R':
851                             case 'r': // retainer select
852                                 RtsFlags.ProfFlags.retainerSelector = left;
853                                 break;
854                             case 'B':
855                             case 'b': // biography select
856                                 RtsFlags.ProfFlags.bioSelector = left;
857                                 break;
858                             }
859                         }
860                         break;
861                     }
862
863                     if (RtsFlags.ProfFlags.doHeapProfile != 0) {
864                         errorBelch("multiple heap profile options");
865                         error = rtsTrue;
866                         break;
867                     }
868
869                     switch (rts_argv[arg][2]) {
870                     case '\0':
871                     case 'C':
872                     case 'c':
873                         RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CCS;
874                         break;
875                     case 'M':
876                     case 'm':
877                           RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_MOD;
878                           break;
879                     case 'D':
880                     case 'd':
881                           RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_DESCR;
882                           break;
883                     case 'Y':
884                     case 'y':
885                           RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_TYPE;
886                           break;
887                     case 'R':
888                     case 'r':
889                           RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_RETAINER;
890                           break;
891                     case 'B':
892                     case 'b':
893                           RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_LDV;
894                           break;
895                     }
896                     break;
897                       
898                 default:
899                     errorBelch("invalid heap profile option: %s",rts_argv[arg]);
900                     error = rtsTrue;
901                 }
902                 ) 
903 #endif /* PROFILING */
904                 break;
905
906               case 'i': /* heap sample interval */
907                 if (rts_argv[arg][2] == '\0') {
908                   /* use default */
909                 } else {
910                     I_ cst; /* tmp */
911
912                     /* Convert to milliseconds */
913                     cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
914                     RtsFlags.ProfFlags.profileInterval = cst;
915                 }
916                 break;
917
918               /* =========== CONCURRENT ========================= */
919               case 'C': /* context switch interval */
920                 if (rts_argv[arg][2] == '\0')
921                     RtsFlags.ConcFlags.ctxtSwitchTime = 0;
922                 else {
923                     I_ cst; /* tmp */
924
925                     /* Convert to milliseconds */
926                     cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
927                     RtsFlags.ConcFlags.ctxtSwitchTime = cst;
928                 }
929                 break;
930
931               case 'V': /* master tick interval */
932                 if (rts_argv[arg][2] == '\0') {
933                     // turns off ticks completely
934                     RtsFlags.MiscFlags.tickInterval = 0;
935                 } else {
936                     I_ cst; /* tmp */
937
938                     /* Convert to milliseconds */
939                     cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
940                     RtsFlags.MiscFlags.tickInterval = cst;
941                 }
942                 break;
943
944 #if defined(THREADED_RTS) && !defined(NOSMP)
945               case 'N':
946                 THREADED_BUILD_ONLY(
947                 if (rts_argv[arg][2] == '\0') {
948 #if defined(PROFILING)
949                     RtsFlags.ParFlags.nNodes = 1;
950 #else
951                     RtsFlags.ParFlags.nNodes = getNumberOfProcessors();
952 #endif
953                 } else {
954                     RtsFlags.ParFlags.nNodes
955                       = strtol(rts_argv[arg]+2, (char **) NULL, 10);
956                     if (RtsFlags.ParFlags.nNodes <= 0) {
957                       errorBelch("bad value for -N");
958                       error = rtsTrue;
959                     }
960 #if defined(PROFILING)
961                     if (RtsFlags.ParFlags.nNodes > 1) {
962                         errorBelch("bad option %s: only -N1 is supported with profiling", rts_argv[arg]);
963                       error = rtsTrue;
964                     }
965 #endif
966                 }
967                 ) break;
968
969               case 'g':
970                 THREADED_BUILD_ONLY(
971                     switch (rts_argv[arg][2]) {
972                     case '1':
973                         // backwards compat only
974                         RtsFlags.ParFlags.parGcEnabled = rtsFalse;
975                         break;
976                     default:
977                         errorBelch("unknown RTS option: %s",rts_argv[arg]);
978                         error = rtsTrue;
979                         break;
980                     }
981                     ) break;
982
983               case 'q':
984                     switch (rts_argv[arg][2]) {
985                     case '\0':
986                         errorBelch("incomplete RTS option: %s",rts_argv[arg]);
987                         error = rtsTrue;
988                         break;
989                     case '1':
990                         RtsFlags.ParFlags.parGcEnabled = rtsFalse;
991                         break;
992                     case 'g':
993                         if (rts_argv[arg][3] != '\0') {
994                             RtsFlags.ParFlags.parGcGen
995                                 = strtol(rts_argv[arg]+3, (char **) NULL, 10);
996                         } else {
997                             errorBelch("bad value for -qg");
998                             error = rtsTrue;
999                         }
1000                         break;
1001                     case 'b':
1002                         RtsFlags.ParFlags.parGcLoadBalancing = rtsFalse;
1003                         break;
1004                     case 'a':
1005                         RtsFlags.ParFlags.setAffinity = rtsTrue;
1006                         break;
1007                     case 'm':
1008                         RtsFlags.ParFlags.migrate = rtsFalse;
1009                         break;
1010                     case 'w':
1011                         RtsFlags.ParFlags.wakeupMigrate = rtsTrue;
1012                         break;
1013                     default:
1014                         errorBelch("unknown RTS option: %s",rts_argv[arg]);
1015                         error = rtsTrue;
1016                         break;
1017                     }
1018                     break;
1019 #endif
1020               /* =========== PARALLEL =========================== */
1021               case 'e':
1022                 THREADED_BUILD_ONLY(
1023                 if (rts_argv[arg][2] != '\0') {
1024                     RtsFlags.ParFlags.maxLocalSparks
1025                       = strtol(rts_argv[arg]+2, (char **) NULL, 10);
1026                     if (RtsFlags.ParFlags.maxLocalSparks <= 0) {
1027                       errorBelch("bad value for -e");
1028                       error = rtsTrue;
1029                     }
1030                 }
1031                 ) break;
1032
1033               /* =========== TICKY ============================== */
1034
1035               case 'r': /* Basic profiling stats */
1036                 TICKY_BUILD_ONLY(
1037
1038                 RtsFlags.TickyFlags.showTickyStats = rtsTrue;
1039
1040                 { 
1041                     int r;
1042                     r = open_stats_file(arg, *argc, argv,
1043                                         *rts_argc, rts_argv, TICKY_FILENAME_FMT,
1044                                         &RtsFlags.TickyFlags.tickyFile);
1045                     if (r == -1) { error = rtsTrue; }
1046                 }
1047                 ) break;
1048
1049               /* =========== TRACING ---------=================== */
1050
1051               case 'v':
1052                 switch(rts_argv[arg][2]) {
1053                 case '\0':
1054                     errorBelch("incomplete RTS option: %s",rts_argv[arg]);
1055                     error = rtsTrue;
1056                     break;
1057                 case 't':
1058                     RtsFlags.DebugFlags.timestamp = rtsTrue;
1059                     break;
1060                 case 's':
1061                 case 'g':
1062                     // ignored for backwards-compat
1063                     break;
1064                 default:
1065                     errorBelch("unknown RTS option: %s",rts_argv[arg]);
1066                     error = rtsTrue;
1067                     break;
1068                 }
1069                 break;
1070
1071               /* =========== EXTENDED OPTIONS =================== */
1072
1073               case 'x': /* Extend the argument space */
1074                 switch(rts_argv[arg][2]) {
1075                   case '\0':
1076                     errorBelch("incomplete RTS option: %s",rts_argv[arg]);
1077                     error = rtsTrue;
1078                     break;
1079
1080                 case 'b': /* heapBase in hex; undocumented */
1081                     if (rts_argv[arg][3] != '\0') {
1082                         RtsFlags.GcFlags.heapBase
1083                             = strtol(rts_argv[arg]+3, (char **) NULL, 16);
1084                     } else {
1085                         errorBelch("-xb: requires argument");
1086                         error = rtsTrue;
1087                     }
1088                     break;
1089
1090 #if defined(x86_64_HOST_ARCH)
1091                 case 'm': /* linkerMemBase */
1092                     if (rts_argv[arg][3] != '\0') {
1093                         RtsFlags.MiscFlags.linkerMemBase
1094                             = strtol(rts_argv[arg]+3, (char **) NULL, 16);
1095                         if (RtsFlags.MiscFlags.linkerMemBase > 0x80000000) {
1096                             errorBelch("-xm: value must be <80000000");
1097                             error = rtsTrue;
1098                         }
1099                     } else {
1100                         RtsFlags.MiscFlags.linkerMemBase = 0;
1101                     }
1102                     break;
1103 #endif
1104
1105                 case 'c': /* Debugging tool: show current cost centre on an exception */
1106                     PROFILING_BUILD_ONLY(
1107                         RtsFlags.ProfFlags.showCCSOnException = rtsTrue;
1108                         );
1109                     break;
1110
1111                 case 't':  /* Include memory used by TSOs in a heap profile */
1112                     PROFILING_BUILD_ONLY(
1113                         RtsFlags.ProfFlags.includeTSOs = rtsTrue;
1114                         );
1115                     break;
1116
1117                   /* The option prefix '-xx' is reserved for future extension.  KSW 1999-11. */
1118
1119                   default:
1120                     errorBelch("unknown RTS option: %s",rts_argv[arg]);
1121                     error = rtsTrue;
1122                     break;
1123                 }
1124                 break;  /* defensive programming */
1125
1126               /* =========== OH DEAR ============================ */
1127               default:
1128                 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1129                 error = rtsTrue;
1130                 break;
1131             }
1132         }
1133     }
1134
1135     if (RtsFlags.MiscFlags.tickInterval < 0) {
1136         RtsFlags.MiscFlags.tickInterval = 50;
1137     }
1138
1139     // If the master timer is disabled, turn off the other timers.
1140     if (RtsFlags.MiscFlags.tickInterval == 0) {
1141         RtsFlags.ConcFlags.ctxtSwitchTime  = 0;
1142         RtsFlags.GcFlags.idleGCDelayTime   = 0;
1143         RtsFlags.ProfFlags.profileInterval = 0;
1144     }
1145
1146     // Determine what tick interval we should use for the RTS timer
1147     // by taking the shortest of the various intervals that we need to
1148     // monitor.
1149     if (RtsFlags.ConcFlags.ctxtSwitchTime > 0) {
1150         RtsFlags.MiscFlags.tickInterval =
1151             stg_min(RtsFlags.ConcFlags.ctxtSwitchTime,
1152                     RtsFlags.MiscFlags.tickInterval);
1153     }
1154
1155     if (RtsFlags.GcFlags.idleGCDelayTime > 0) {
1156         RtsFlags.MiscFlags.tickInterval =
1157             stg_min(RtsFlags.GcFlags.idleGCDelayTime,
1158                     RtsFlags.MiscFlags.tickInterval);
1159     }
1160
1161     if (RtsFlags.ProfFlags.profileInterval > 0) {
1162         RtsFlags.MiscFlags.tickInterval =
1163             stg_min(RtsFlags.ProfFlags.profileInterval,
1164                     RtsFlags.MiscFlags.tickInterval);
1165     }
1166
1167     if (RtsFlags.ConcFlags.ctxtSwitchTime > 0) {
1168         RtsFlags.ConcFlags.ctxtSwitchTicks =
1169             RtsFlags.ConcFlags.ctxtSwitchTime /
1170             RtsFlags.MiscFlags.tickInterval;
1171     } else {
1172         RtsFlags.ConcFlags.ctxtSwitchTicks = 0;
1173     }
1174
1175     if (RtsFlags.ProfFlags.profileInterval > 0) {
1176         RtsFlags.ProfFlags.profileIntervalTicks =
1177             RtsFlags.ProfFlags.profileInterval / 
1178             RtsFlags.MiscFlags.tickInterval;
1179     } else {
1180         RtsFlags.ProfFlags.profileIntervalTicks = 0;
1181     }
1182
1183     if (error) {
1184         const char **p;
1185
1186         fflush(stdout);
1187         for (p = usage_text; *p; p++)
1188             errorBelch("%s", *p);
1189         stg_exit(EXIT_FAILURE);
1190     }
1191 }
1192
1193
1194 static void
1195 stats_fprintf(FILE *f, char *s, ...)
1196 {
1197     va_list ap;
1198     va_start(ap,s);
1199     if (f == NULL) {
1200         vdebugBelch(s, ap);
1201     } else {
1202         vfprintf(f, s, ap);
1203     }
1204     va_end(ap);
1205 }
1206
1207 static int              /* return -1 on error */
1208 open_stats_file (
1209     I_ arg,
1210     int argc, char *argv[],
1211     int rts_argc, char *rts_argv[],
1212     const char *FILENAME_FMT,
1213     FILE **file_ret)
1214 {
1215     FILE *f = NULL;
1216
1217     if (strequal(rts_argv[arg]+2, "stderr")
1218         || (FILENAME_FMT == NULL && rts_argv[arg][2] == '\0')) {
1219         f = NULL; /* NULL means use debugBelch */
1220     } else {
1221         if (rts_argv[arg][2] != '\0') {  /* stats file specified */
1222             f = fopen(rts_argv[arg]+2,"w");
1223         } else {
1224             char stats_filename[STATS_FILENAME_MAXLEN]; /* default <program>.<ext> */
1225             sprintf(stats_filename, FILENAME_FMT, argv[0]);
1226             f = fopen(stats_filename,"w");
1227         }
1228         if (f == NULL) {
1229             errorBelch("Can't open stats file %s\n", rts_argv[arg]+2);
1230             return -1;
1231         }
1232     }
1233     *file_ret = f;
1234
1235     {
1236         /* Write argv and rtsv into start of stats file */
1237         int count;
1238         for(count = 0; count < argc; count++) {
1239             stats_fprintf(f, "%s ", argv[count]);
1240         }
1241         stats_fprintf(f, "+RTS ");
1242         for(count = 0; count < rts_argc; count++)
1243             stats_fprintf(f, "%s ", rts_argv[count]);
1244         stats_fprintf(f, "\n");
1245     }
1246     return 0;
1247 }
1248
1249
1250
1251 static I_
1252 decode(const char *s)
1253 {
1254     I_ c;
1255     StgDouble m;
1256
1257     if (!*s)
1258         return 0;
1259
1260     m = atof(s);
1261     c = s[strlen(s)-1];
1262
1263     if (c == 'g' || c == 'G')
1264         m *= 1000*1000*1000;    /* UNchecked! */
1265     else if (c == 'm' || c == 'M')
1266         m *= 1000*1000;                 /* We do not use powers of 2 (1024) */
1267     else if (c == 'k' || c == 'K')      /* to avoid possible bad effects on */
1268         m *= 1000;                      /* a direct-mapped cache.           */ 
1269     else if (c == 'w' || c == 'W')
1270         m *= sizeof(W_);
1271
1272     return (I_)m;
1273 }
1274
1275 static void
1276 bad_option(const char *s)
1277 {
1278   errorBelch("bad RTS option: %s", s);
1279   stg_exit(EXIT_FAILURE);
1280 }
1281
1282 /* -----------------------------------------------------------------------------
1283    Getting/Setting the program's arguments.
1284
1285    These are used by System.Environment, and parts of the RTS.
1286    -------------------------------------------------------------------------- */
1287
1288 void
1289 setProgName(char *argv[])
1290 {
1291     /* Remove directory from argv[0] -- default files in current directory */
1292 #if !defined(mingw32_HOST_OS)
1293     char *last_slash;
1294     if ( (last_slash = (char *) strrchr(argv[0], '/')) != NULL ) {
1295         prog_name = last_slash+1;
1296    } else {
1297         prog_name = argv[0];
1298    }
1299 #else
1300     char* last_slash = argv[0] + (strlen(argv[0]) - 1);
1301     while ( last_slash > argv[0] ) {
1302         if ( *last_slash == '/' || *last_slash == '\\' ) {
1303             prog_name = last_slash+1;
1304             return;
1305         }
1306         last_slash--;
1307     }
1308     prog_name = argv[0];
1309 #endif
1310 }
1311
1312 void
1313 getProgArgv(int *argc, char **argv[])
1314 {
1315     if (argc) { *argc = prog_argc; }
1316     if (argv) { *argv = prog_argv; }
1317 }
1318
1319 void
1320 setProgArgv(int argc, char *argv[])
1321 {
1322    /* Usually this is done by startupHaskell, so we don't need to call this. 
1323       However, sometimes Hugs wants to change the arguments which Haskell
1324       getArgs >>= ... will be fed.  So you can do that by calling here
1325       _after_ calling startupHaskell.
1326    */
1327    prog_argc = argc;
1328    prog_argv = argv;
1329    setProgName(prog_argv);
1330 }
1331
1332 /* These functions record and recall the full arguments, including the
1333    +RTS ... -RTS options. The reason for adding them was so that the
1334    ghc-inplace program can pass /all/ the arguments on to the real ghc. */
1335 void
1336 getFullProgArgv(int *argc, char **argv[])
1337 {
1338     if (argc) { *argc = full_prog_argc; }
1339     if (argv) { *argv = full_prog_argv; }
1340 }
1341
1342 void
1343 setFullProgArgv(int argc, char *argv[])
1344 {
1345     int i;
1346     full_prog_argc = argc;
1347     full_prog_argv = stgCallocBytes(argc + 1, sizeof (char *),
1348                                     "setFullProgArgv 1");
1349     for (i = 0; i < argc; i++) {
1350         full_prog_argv[i] = stgMallocBytes(strlen(argv[i]) + 1,
1351                                            "setFullProgArgv 2");
1352         strcpy(full_prog_argv[i], argv[i]);
1353     }
1354     full_prog_argv[argc] = NULL;
1355 }
1356