1 #ifdef RCSID
2 static char RCSid[] =
3 "$Header: d:/cvsroot/tads/TADS2/OS0.C,v 1.2 1999/05/17 02:52:12 MJRoberts Exp $";
4 #endif
5
6 /*
7 * Copyright (c) 1992, 2002 Michael J. Roberts. All Rights Reserved.
8 *
9 * Please see the accompanying license file, LICENSE.TXT, for information
10 * on using and copying this software.
11 */
12 /*
13 Name
14 os0.c - argument configuration utility
15 Function
16 This module allows a "main" routine to get additional arguments
17 from a configuration file. We look for the given configuration
18 file in the current directory, and if not found, in the executable's
19 directory. The arguments it contains are added before the command
20 line arguments, except that any argument flags (along with an extra
21 argument string, if any) listed in the "before" list are moved to
22 the beginning of the argument list. For example:
23
24 before list = "i"
25 config file contains "-m 128000 -1+ -tf- -i /tads/include"
26 command line contains "-1- -i ../include -o test.gam test.t"
27 translation: "-i ../include -m 128000 -1+ -f- -i /tads/include
28 -o test.gam test.t"
29
30 This allows arguments to be sorted according to precedence so that
31 an argument in the command line overrides an argument in the config
32 file. The "before" list contains options that need to come first
33 to override subsequent instances of the same option; other options
34 override by coming later in the string.
35 Notes
36
37 Modified
38 04/04/99 CNebel - Use new argize function; fix Metrowerks errors.
39 04/24/93 JEras - use new os_locate() to find config file
40 04/22/92 MJRoberts - creation
41 */
42
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <ctype.h>
47 #include <assert.h>
48 #include "os.h"
49 #include "appctx.h"
50 #include "argize.h"
51
52
os0main_internal(int oargc,char ** oargv,int (* mainfn1)(int,char **,char *),int (* mainfn2)(int,char **,struct appctxdef *,char *),const char * before,const char * config,struct appctxdef * appctx)53 static int os0main_internal(int oargc, char **oargv,
54 int (*mainfn1)(int, char **, char *),
55 int (*mainfn2)(int, char **, struct appctxdef *,
56 char *),
57 const char *before, const char *config,
58 struct appctxdef *appctx)
59 {
60 int argc = 0;
61 int fargc = 0;
62 char **argv;
63 char *configbuf = 0;
64 int i;
65 osfildef *fp;
66 long fsiz;
67 char buf[256];
68 char *save_ext = 0;
69 int ret;
70
71 /*
72 * Check for an embedded SAVX resource, which specifies the default
73 * saved game file suffix.
74 */
75 if (oargv != 0 && oargv[0] != 0
76 && (fp = os_exeseek(oargv[0], "SAVX")) != 0)
77 {
78 unsigned short len;
79
80 /* read the length and then read the name */
81 if (!osfrb(fp, &len, sizeof(len))
82 && len < sizeof(buf)
83 && !osfrb(fp, buf, len))
84 {
85 /* null-terminate the value */
86 buf[len] = '\0';
87
88 /* tell the OS layer about it */
89 os_set_save_ext(buf);
90
91 /* save a copy of the extension */
92 save_ext = (char *)osmalloc(len + 1);
93 strcpy(save_ext, buf);
94 }
95
96 /* done with it */
97 osfcls(fp);
98 fp = 0;
99 }
100
101 /*
102 * Try for an embedded configuration file. If we don't find one,
103 * try locating an external configuration file.
104 */
105 if (oargv != 0 && oargv[0] != 0
106 && (fp = os_exeseek(oargv[0], "RCFG")) != 0)
107 {
108 osfrb(fp, &fsiz, sizeof(fsiz));
109 }
110 else if (config != 0
111 && os_locate(config, (int)strlen(config), oargv[0], buf,
112 (size_t)sizeof(buf))
113 && (fp = osfoprb(buf, OSFTTEXT)) != 0)
114 {
115 osfseek(fp, 0L, OSFSK_END);
116 fsiz = osfpos(fp);
117 osfseek(fp, 0L, OSFSK_SET);
118 }
119 else
120 {
121 fsiz = 0;
122 fp = 0;
123 }
124
125 /* read the file if we found anything */
126 if (fsiz != 0)
127 {
128 configbuf = (char *)osmalloc((size_t)(fsiz + 1));
129 if (configbuf != 0)
130 {
131 /* read the configuration file into the buffer */
132 osfrb(fp, configbuf, (size_t)fsiz);
133
134 /* null-terminate it */
135 configbuf[fsiz] = '\0';
136
137 /* count arguments */
138 fargc = countargs(configbuf);
139 }
140 }
141
142 /* close the file if we opened one */
143 if (fp != 0)
144 osfcls(fp);
145
146 /* allocate space for the argument vector */
147 argv = (char **)osmalloc((size_t)((oargc + fargc + 1) * sizeof(*argv)));
148
149 /* first argument is always original argv[0] */
150 argv[argc++] = oargv[0];
151
152 /* put all user -i flags next */
153 for (i = 0 ; i < oargc ; ++i)
154 {
155 if (oargv[i][0] == '-' && strchr(before, oargv[i][1]))
156 {
157 argv[argc++] = oargv[i];
158 if (oargv[i][2] == '\0' && i+1 < oargc) argv[argc++] = oargv[++i];
159 }
160 }
161
162 /* put all config file flags next */
163 if (configbuf != 0)
164 {
165 int ret, foundargc;
166
167 /* parse the arguments */
168 ret = argize(configbuf, &foundargc, &argv[argc], fargc);
169
170 /* add them into our arguments */
171 argc += foundargc;
172
173 /* make sure we scanned the same number of args we anticipated */
174 assert(ret == 0);
175 assert(foundargc == fargc);
176 }
177
178 /* put all user parameters other than -i flags last */
179 for (i = 1 ; i < oargc ; ++i)
180 {
181 if (oargv[i][0] == '-' && strchr(before, oargv[i][1]))
182 {
183 if (oargv[i][2] == '\0' && i+1 < oargc) ++i;
184 }
185 else
186 {
187 argv[argc++] = oargv[i];
188 }
189 }
190
191 /* call appropriate real main with the modified argument list */
192 if (mainfn1)
193 ret = (*mainfn1)(argc, argv, save_ext);
194 else
195 ret = (*mainfn2)(argc, argv, appctx, save_ext);
196
197 /* forget our saved extension */
198 if (save_ext != 0)
199 osfree(save_ext);
200
201 /* return the result */
202 return ret;
203 }
204
205
206 /*
207 * Old-style os0main: call with main function that doesn't take a host
208 * container application context
209 */
os0main(int oargc,char ** oargv,int (* mainfn)(int,char **,char *),const char * before,const char * config)210 int os0main(int oargc, char **oargv,
211 int (*mainfn)(int, char **, char *),
212 const char *before, const char *config)
213 {
214 return os0main_internal(oargc, oargv, mainfn, 0, before, config, 0);
215 }
216
217 /*
218 * New-style os0main: call with main function that takes a host
219 * container application context
220 */
os0main2(int oargc,char ** oargv,int (* mainfn)(int,char **,struct appctxdef *,char *),const char * before,const char * config,struct appctxdef * appctx)221 int os0main2(int oargc, char **oargv,
222 int (*mainfn)(int, char **, struct appctxdef *, char *),
223 const char *before, const char *config,
224 struct appctxdef *appctx)
225 {
226 return os0main_internal(oargc, oargv, 0, mainfn, before, config, appctx);
227 }
228
229