Documentation updates (mainly thru vs. through).
[wine] / msdos / dosconf.c
1 /*
2  * DOS CONFIG.SYS parser
3  *
4  * Copyright 1998 Andreas Mohr 
5  *
6  */
7
8 #include "config.h"
9
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <ctype.h>
15
16 #include "winbase.h"
17
18 #include "file.h"
19 #include "miscemu.h"
20 #include "msdos.h"
21 #include "options.h"
22
23 #include "debugtools.h"
24
25 DEFAULT_DEBUG_CHANNEL(profile);
26
27
28 static int DOSCONF_Device(char **confline);
29 static int DOSCONF_Dos(char **confline);
30 static int DOSCONF_Fcbs(char **confline);
31 static int DOSCONF_Break(char **confline);
32 static int DOSCONF_Files(char **confline);
33 static int DOSCONF_Install(char **confline);
34 static int DOSCONF_Lastdrive(char **confline);
35 static int DOSCONF_Menu(char **confline);
36 static int DOSCONF_Include(char **confline);
37 static int DOSCONF_Country(char **confline);
38 static int DOSCONF_Numlock(char **confline);
39 static int DOSCONF_Switches(char **confline);
40 static int DOSCONF_Shell(char **confline);
41 static int DOSCONF_Stacks(char **confline);
42 static int DOSCONF_Buffers(char **confline);
43 static void DOSCONF_Parse(char *menuname);
44
45 DOSCONF DOSCONF_config = 
46 {
47     'E',  /* lastdrive */
48     0,    /* brk_flag */
49     8,    /* files */
50     9,    /* stacks_nr */
51     256,  /* stacks_sz */
52     15,   /* buf */
53     1,    /* buf2 */
54     4,    /* fcbs */
55     0,    /* flags */
56     NULL, /* shell */
57     NULL  /* country */
58 };
59
60 typedef struct {
61     const char *tag_name;
62     int (*tag_handler)(char **p);
63 } TAG_ENTRY;
64
65
66 /*
67  * see
68  * http://egeria.cm.cf.ac.uk/User/P.L.Poulain/project/internal/allinter.htm
69  * or
70  * http://www.csulb.edu/~murdock/dosindex.html
71  */
72
73 static const TAG_ENTRY tag_entries[] =
74 {
75     { ";", NULL },
76     { "REM ", NULL },
77     { "DEVICE", DOSCONF_Device },
78     { "[", DOSCONF_Menu },
79     { "SUBMENU", NULL },
80     { "MENUDEFAULT", DOSCONF_Menu },
81     { "INCLUDE", DOSCONF_Include },
82
83     { "INSTALL", DOSCONF_Install },
84     { "DOS", DOSCONF_Dos },
85     { "FCBS", DOSCONF_Fcbs },
86     { "BREAK", DOSCONF_Break },
87     { "FILES", DOSCONF_Files },
88     { "SHELL", DOSCONF_Shell },    
89     { "STACKS", DOSCONF_Stacks },
90     { "BUFFERS", DOSCONF_Buffers },
91     { "COUNTRY", DOSCONF_Country },
92     { "NUMLOCK", DOSCONF_Numlock },
93     { "SWITCHES", DOSCONF_Switches },
94     { "LASTDRIVE", DOSCONF_Lastdrive }
95 };
96
97 static FILE *cfg_fd;
98
99 static char *menu_default = NULL;
100 static int menu_in_listing = 0;         /* we are in the [menu] section */
101 static int menu_skip = 0;                               /* the current menu gets skipped */
102
103
104 static void DOSCONF_skip(char **pconfline)
105 {
106     char *p;
107     
108     p = *pconfline;
109     while ( (*p == ' ') || (*p == '\t') ) p++;
110     *pconfline = p;
111 }
112                 
113 static int DOSCONF_JumpToEntry(char **pconfline, char separator)
114 {
115     char *p;
116     
117     p = *pconfline;
118     while ( (*p != separator) && (*p != '\0') ) p++;
119
120     if (*p != separator)
121         return 0;
122     else p++;
123
124     while ( (*p == ' ') || (*p == '\t') ) p++;
125     *pconfline = p;
126     return 1;
127 }
128
129 static int DOSCONF_Device(char **confline)
130 {
131     int loadhigh = 0;
132
133     *confline += 6; /* strlen("DEVICE") */
134     if (!(strncasecmp(*confline, "HIGH", 4)))
135     {
136         loadhigh = 1;
137         *confline += 4;
138         /* FIXME: get DEVICEHIGH parameters if avail ? */
139     }
140     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
141     TRACE("Loading device '%s'\n", *confline);
142 #if 0
143     DOSMOD_LoadDevice(*confline, loadhigh);
144 #endif
145     return 1;
146 }
147
148 static int DOSCONF_Dos(char **confline)
149 {
150     *confline += 3; /* strlen("DOS") */
151     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
152     while (**confline != '\0')
153     {
154         if (!(strncasecmp(*confline, "HIGH", 4)))
155         {
156             DOSCONF_config.flags |= DOSCONF_MEM_HIGH;
157             *confline += 4;
158         }
159         else
160         if (!(strncasecmp(*confline, "UMB", 3)))
161         {
162             DOSCONF_config.flags |= DOSCONF_MEM_UMB;
163             *confline += 3;
164         }
165         else (*confline)++;
166         DOSCONF_JumpToEntry(confline, ',');
167     }
168     TRACE("DOSCONF_Dos: HIGH is %d, UMB is %d\n",
169         (DOSCONF_config.flags & DOSCONF_MEM_HIGH) != 0, (DOSCONF_config.flags & DOSCONF_MEM_UMB) != 0);
170     return 1;
171 }
172
173 static int DOSCONF_Fcbs(char **confline)
174 {
175     *confline += 4; /* strlen("FCBS") */
176     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
177     DOSCONF_config.fcbs = atoi(*confline);
178     if (DOSCONF_config.fcbs > 255)
179     {
180                 MESSAGE("The FCBS value in the config.sys file is too high ! Setting to 255.\n");
181                 DOSCONF_config.fcbs = 255;
182     }
183     TRACE("DOSCONF_Fcbs returning %d\n", DOSCONF_config.fcbs);
184     return 1;
185 }
186
187 static int DOSCONF_Break(char **confline)
188 {
189     *confline += 5; /* strlen("BREAK") */
190     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
191     if (!(strcasecmp(*confline, "ON")))
192         DOSCONF_config.brk_flag = 1;
193     TRACE("BREAK is %d\n", DOSCONF_config.brk_flag);
194     return 1;
195 }
196
197 static int DOSCONF_Files(char **confline)
198 {
199     *confline += 5; /* strlen("FILES") */
200     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
201     DOSCONF_config.files = atoi(*confline);
202     if (DOSCONF_config.files > 255)
203     {
204         MESSAGE("The FILES value in the config.sys file is too high ! Setting to 255.\n");
205         DOSCONF_config.files = 255;
206     }
207     if (DOSCONF_config.files < 8)
208     {
209         MESSAGE("The FILES value in the config.sys file is too low ! Setting to 8.\n");
210         DOSCONF_config.files = 8;
211     }
212     TRACE("DOSCONF_Files returning %d\n", DOSCONF_config.files);
213     return 1;
214 }
215
216 static int DOSCONF_Install(char **confline)
217 {
218 #if 0
219     int loadhigh = 0;
220 #endif
221
222     *confline += 7; /* strlen("INSTALL") */
223     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
224     TRACE("Installing '%s'\n", *confline);
225 #if 0
226     DOSMOD_Install(*confline, loadhigh);
227 #endif
228     return 1;
229 }
230
231 static int DOSCONF_Lastdrive(char **confline)
232 {
233     *confline += 9; /* strlen("LASTDRIVE") */
234     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
235     DOSCONF_config.lastdrive = toupper(**confline);
236     TRACE("Lastdrive %c\n", DOSCONF_config.lastdrive);
237     return 1;
238 }
239
240 static int DOSCONF_Country(char **confline)
241 {
242     *confline += 7; /* strlen("COUNTRY") */
243     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
244     TRACE("Country '%s'\n", *confline);
245     if (DOSCONF_config.country == NULL)
246                 DOSCONF_config.country = malloc(strlen(*confline) + 1);
247     strcpy(DOSCONF_config.country, *confline);
248     return 1;
249 }
250
251 static int DOSCONF_Numlock(char **confline)
252 {
253     *confline += 7; /* strlen("NUMLOCK") */
254     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
255     if (!(strcasecmp(*confline, "ON")))
256         DOSCONF_config.flags |= DOSCONF_NUMLOCK;
257     TRACE("NUMLOCK is %d\n", (DOSCONF_config.flags & DOSCONF_NUMLOCK) != 0);
258     return 1;
259 }
260
261 static int DOSCONF_Switches(char **confline)
262 {
263     char *p;
264
265     *confline += 8; /* strlen("SWITCHES") */
266     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
267     p = strtok(*confline, "/");
268     do
269     {
270         if ( toupper(*p) == 'K')
271             DOSCONF_config.flags |= DOSCONF_KEYB_CONV;
272     }
273     while ((p = strtok(NULL, "/")));
274     TRACE("'Force conventional keyboard' is %d\n",
275                 (DOSCONF_config.flags & DOSCONF_KEYB_CONV) != 0);
276     return 1;
277 }
278
279 static int DOSCONF_Shell(char **confline)
280 {
281     *confline += 5; /* strlen("SHELL") */
282     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
283     TRACE("Shell '%s'\n", *confline);
284     if (DOSCONF_config.shell == NULL)
285                 DOSCONF_config.shell = malloc(strlen(*confline) + 1);
286     strcpy(DOSCONF_config.shell, *confline);
287     return 1;
288 }
289
290 static int DOSCONF_Stacks(char **confline)
291 {
292
293     *confline += 6; /* strlen("STACKS") */
294     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
295     DOSCONF_config.stacks_nr = atoi(strtok(*confline, ","));
296     DOSCONF_config.stacks_sz = atoi((strtok(NULL, ",")));
297     TRACE("%d stacks of size %d\n",
298           DOSCONF_config.stacks_nr, DOSCONF_config.stacks_sz);
299     return 1;
300 }
301
302 static int DOSCONF_Buffers(char **confline)
303 {
304     char *p;
305
306     *confline += 7; /* strlen("BUFFERS") */
307     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
308     p = strtok(*confline, ",");
309     DOSCONF_config.buf = atoi(p);
310     if ((p = strtok(NULL, ",")))
311         DOSCONF_config.buf2 = atoi(p);
312     TRACE("%d primary buffers, %d secondary buffers\n",
313           DOSCONF_config.buf, DOSCONF_config.buf2);
314     return 1;
315 }
316
317 static int DOSCONF_Menu(char **confline)
318 {
319     if (!(strncasecmp(*confline, "[MENU]", 6)))
320         menu_in_listing = 1;
321     else
322     if ((!(strncasecmp(*confline, "[COMMON]", 8)))
323     || (!(strncasecmp(*confline, "[WINE]", 6))))
324         menu_skip = 0;
325     else
326     if (**confline == '[')
327     {
328         (*confline)++;
329         if ((menu_default)
330         && (!(strncasecmp(*confline, menu_default, strlen(menu_default)))))
331     {
332                 free(menu_default);
333                 menu_default = NULL;
334             menu_skip = 0;
335     }
336         else
337             menu_skip = 1;
338         menu_in_listing = 0;
339     }
340     else
341     if (!(strncasecmp(*confline, "menudefault", 11)) && (menu_in_listing))
342     {
343         if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
344     *confline = strtok(*confline, ",");
345     menu_default = malloc(strlen(*confline) + 1);
346         strcpy(menu_default, *confline);
347     }
348     return 1;
349 }
350
351 static int DOSCONF_Include(char **confline)
352 {
353     fpos_t oldpos;
354     char *temp;
355     
356     *confline += 7; /* strlen("INCLUDE") */
357     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
358     fgetpos(cfg_fd, &oldpos);
359     fseek(cfg_fd, 0, SEEK_SET);
360     TRACE("Including menu '%s'\n", *confline);
361     temp = malloc(strlen(*confline) + 1);
362     strcpy(temp, *confline);
363     DOSCONF_Parse(temp);
364         free(temp);
365     fsetpos(cfg_fd, &oldpos);
366     return 1;
367 }
368
369 static void DOSCONF_Parse(char *menuname)
370 {
371    char confline[256];
372    char *p, *trail;
373    int i;
374     
375     if (menuname != NULL) /* we need to jump to a certain sub menu */
376     {
377         while (fgets(confline, 255, cfg_fd))
378         {
379              p = confline;
380              DOSCONF_skip(&p);
381              if (*p == '[')
382              {
383                 p++;
384                 if (!(trail = strrchr(p, ']')))
385                     return;
386                 if (!(strncasecmp(p, menuname, (int)trail - (int)p)))
387                     break;
388              }
389         }
390     }
391
392     while (fgets(confline, 255, cfg_fd))
393     {
394         p = confline;
395         DOSCONF_skip(&p);
396
397         if ((menuname) && (*p == '['))
398             /* we were handling a specific sub menu, but now next menu begins */
399             break;
400
401         if ((trail = strrchr(confline, '\n')))
402                 *trail = '\0';
403         if ((trail = strrchr(confline, '\r')))
404                 *trail = '\0';
405         if (!(menu_skip))
406         {
407             for (i = 0; i < sizeof(tag_entries) / sizeof(TAG_ENTRY); i++)
408                 if (!(strncasecmp(p, tag_entries[i].tag_name,
409                    strlen(tag_entries[i].tag_name))))
410                 {
411                     TRACE("tag '%s'\n", tag_entries[i].tag_name);
412                     if (tag_entries[i].tag_handler != NULL)
413                             tag_entries[i].tag_handler(&p);
414                         break;
415                 }
416         }
417         else /* the current menu gets skipped */
418         DOSCONF_Menu(&p);
419     }
420 }
421
422 int DOSCONF_ReadConfig(void)
423 {
424     char buffer[256];
425     DOS_FULL_NAME fullname;
426     char *filename, *menuname;
427     int ret = 1;
428
429     PROFILE_GetWineIniString( "wine", "config.sys", "", buffer, sizeof(buffer) );
430     if (!(filename = strtok(buffer, ","))) return ret;
431     menuname = strtok(NULL,   ",");
432
433     DOSFS_GetFullName(filename, FALSE, &fullname);
434     if (menuname) menu_default = strdup(menuname);
435     if ((cfg_fd = fopen(fullname.long_name, "r")))
436     {
437         DOSCONF_Parse(NULL);
438         fclose(cfg_fd);
439     }
440     else
441     {
442         MESSAGE("Couldn't open config.sys file given as \"%s\" in" \
443             " wine.conf or .winerc, section [wine] !\n", filename);
444         ret = 0;
445     }
446     if (menu_default) free(menu_default);
447     return ret;
448 }