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