1 /**
2 Configuration options for druntime.
3 
4 The default way to configure the runtime is by passing command line arguments
5 starting with `--DRT-` and followed by the option name, e.g. `--DRT-gcopt` to
6 configure the GC.
7 When command line parsing is enabled, command line options starting
8 with `--DRT-` are filtered out before calling main, so the program
9 will not see them. They are still available via `rt_args()`.
10 
11 Configuration via the command line can be disabled by declaring a variable for the
12 linker to pick up before using it's default from the runtime:
13 
14 ---
15 extern(C) __gshared bool rt_cmdline_enabled = false;
16 ---
17 
18 Likewise, declare a boolean rt_envvars_enabled to enable configuration via the
19 environment variable `DRT_` followed by the option name, e.g. `DRT_GCOPT`:
20 
21 ---
22 extern(C) __gshared bool rt_envvars_enabled = true;
23 ---
24 
25 Setting default configuration properties in the executable can be done by specifying an
26 array of options named `rt_options`:
27 
28 ---
29 extern(C) __gshared string[] rt_options = [ "gcopt=precise:1 profile:1"];
30 ---
31 
32 Evaluation order of options is `rt_options`, then environment variables, then command
33 line arguments, i.e. if command line arguments are not disabled, they can override
34 options specified through the environment or embedded in the executable.
35 
36 Copyright: Copyright Digital Mars 2014.
37 License: Distributed under the
38      $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
39    (See accompanying file LICENSE)
40 Authors:   Rainer Schuetze
41 Source: $(DRUNTIMESRC rt/_config.d)
42 */
43 
44 module rt.config;
45 
46 // put each variable in its own COMDAT by making them template instances
47 template rt_envvars_enabled()
48 {
49     extern(C) pragma(mangle, "rt_envvars_enabled") __gshared bool rt_envvars_enabled = false;
50 }
51 template rt_cmdline_enabled()
52 {
53     extern(C) pragma(mangle, "rt_cmdline_enabled") __gshared bool rt_cmdline_enabled = true;
54 }
55 template rt_options()
56 {
57     extern(C) pragma(mangle, "rt_options") __gshared string[] rt_options = [];
58 }
59 
60 import core.stdc.ctype : toupper;
61 import core.stdc.stdlib : getenv;
62 import core.stdc.string : strlen;
63 
64 extern extern(C) string[] rt_args() @nogc nothrow @system;
65 
66 alias rt_configCallBack = string delegate(string) @nogc nothrow;
67 
68 /**
69 * get a druntime config option using standard configuration options
70 *      opt             name of the option to retrieve
71 *      dg              if non-null, passes the option through this
72 *                      delegate and only returns its return value if non-null
73 *      reverse         reverse the default processing order cmdline/envvar/rt_options
74 *                      to allow overwriting settings in the delegate with values
75 *                      from higher priority
76 *
77 * returns the options' value if
78 *  - set on the command line as "--DRT-<opt>=value" (rt_cmdline_enabled enabled)
79 *  - the environment variable "DRT_<OPT>" is set (rt_envvars_enabled enabled)
80 *  - rt_options[] contains an entry "<opt>=value"
81 *  - null otherwise
82 */
83 string rt_configOption(string opt, scope rt_configCallBack dg = null, bool reverse = false) @nogc nothrow
84 {
85     if (!dg)
86         dg = (string s) => s;
87 
88     string s = (reverse ? rt_linkOption(opt, dg) : rt_cmdlineOption(opt, dg));
89     if (s != null)
90         return s;
91     s = rt_envvarsOption(opt, dg);
92     if (s != null)
93         return s;
94     s = (reverse ? rt_cmdlineOption(opt, dg) : rt_linkOption(opt, dg));
95     return s;
96 }
97 
98 string rt_cmdlineOption(string opt, scope rt_configCallBack dg) @nogc nothrow
99 {
100     if (rt_cmdline_enabled!())
101     {
102         foreach (a; rt_args)
103         {
104             if (a == "--")
105                 break;
106 
107             if (a.length >= opt.length + 7 && a[0..6] == "--DRT-" &&
108                 a[6 .. 6 + opt.length] == opt && a[6 + opt.length] == '=')
109             {
110                 string s = dg(a[7 + opt.length .. $]);
111                 if (s != null)
112                     return s;
113             }
114         }
115     }
116     return null;
117 }
118 
119 string rt_envvarsOption(string opt, scope rt_configCallBack dg) @nogc nothrow
120 {
121     if (rt_envvars_enabled!())
122     {
123         if (opt.length >= 32)
124             assert(0);
125 
126         char[40] var = void;
127         var[0 .. 4] = "DRT_";
128         foreach (i, c; opt)
129             var[4 + i] = cast(char) toupper(c);
130         var[4 + opt.length] = 0;
131 
132         auto p = getenv(var.ptr);
133         if (p)
134         {
135             string s = dg(cast(string) p[0 .. strlen(p)]);
136             if (s != null)
137                 return s;
138         }
139     }
140     return null;
141 }
142 
143 string rt_linkOption(string opt, scope rt_configCallBack dg) @nogc nothrow
144 {
145     foreach (a; rt_options!())
146     {
147         if (a.length > opt.length && a[0..opt.length] == opt && a[opt.length] == '=')
148         {
149             string s = dg(a[opt.length + 1 .. $]);
150             if (s != null)
151                 return s;
152         }
153     }
154     return null;
155 }