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