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