kernel32: Forward interrupts in 32-bit code to winedos too.
[wine] / dlls / winedos / dosconf.c
1 /*
2  * DOS CONFIG.SYS parser
3  *
4  * Copyright 1998 Andreas Mohr
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdarg.h>
25 #include <stdio.h>
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29 #include <string.h>
30 #include <stdlib.h>
31 #include <ctype.h>
32
33 #include "windef.h"
34 #include "winbase.h"
35
36 #include "dosexe.h"
37
38 #include "wine/debug.h"
39 #include "wine/unicode.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(profile);
42
43
44 static int DOSCONF_Device(char **confline);
45 static int DOSCONF_Dos(char **confline);
46 static int DOSCONF_Fcbs(char **confline);
47 static int DOSCONF_Break(char **confline);
48 static int DOSCONF_Files(char **confline);
49 static int DOSCONF_Install(char **confline);
50 static int DOSCONF_Lastdrive(char **confline);
51 static int DOSCONF_Menu(char **confline);
52 static int DOSCONF_Include(char **confline);
53 static int DOSCONF_Country(char **confline);
54 static int DOSCONF_Numlock(char **confline);
55 static int DOSCONF_Switches(char **confline);
56 static int DOSCONF_Shell(char **confline);
57 static int DOSCONF_Stacks(char **confline);
58 static int DOSCONF_Buffers(char **confline);
59 static void DOSCONF_Parse(char *menuname);
60
61 static DOSCONF DOSCONF_config =
62 {
63     'E',  /* lastdrive */
64     0,    /* brk_flag */
65     8,    /* files */
66     9,    /* stacks_nr */
67     256,  /* stacks_sz */
68     15,   /* buf */
69     1,    /* buf2 */
70     4,    /* fcbs */
71     0,    /* flags */
72     NULL, /* shell */
73     NULL  /* country */
74 };
75
76 static BOOL DOSCONF_loaded = FALSE;
77
78 typedef struct {
79     const char *tag_name;
80     int (*tag_handler)(char **p);
81 } TAG_ENTRY;
82
83
84 /*
85  * see
86  * http://egeria.cm.cf.ac.uk/User/P.L.Poulain/project/internal/allinter.htm
87  * or
88  * http://www.csulb.edu/~murdock/dosindex.html
89  */
90
91 static const TAG_ENTRY DOSCONF_tag_entries[] =
92 {
93     { ";", NULL },
94     { "REM ", NULL },
95     { "DEVICE", DOSCONF_Device },
96     { "[", DOSCONF_Menu },
97     { "SUBMENU", NULL },
98     { "MENUDEFAULT", DOSCONF_Menu },
99     { "INCLUDE", DOSCONF_Include },
100     { "INSTALL", DOSCONF_Install },
101     { "DOS", DOSCONF_Dos },
102     { "FCBS", DOSCONF_Fcbs },
103     { "BREAK", DOSCONF_Break },
104     { "FILES", DOSCONF_Files },
105     { "SHELL", DOSCONF_Shell },
106     { "STACKS", DOSCONF_Stacks },
107     { "BUFFERS", DOSCONF_Buffers },
108     { "COUNTRY", DOSCONF_Country },
109     { "NUMLOCK", DOSCONF_Numlock },
110     { "SWITCHES", DOSCONF_Switches },
111     { "LASTDRIVE", DOSCONF_Lastdrive }
112 };
113
114 static FILE *DOSCONF_fd = NULL;
115
116 static char *DOSCONF_menu_default = NULL;
117 static int   DOSCONF_menu_in_listing = 0; /* we are in the [menu] section */
118 static int   DOSCONF_menu_skip = 0;       /* the current menu gets skipped */
119
120 static void DOSCONF_skip(char **pconfline)
121 {
122     char *p;
123
124     p = *pconfline;
125     while ( (*p == ' ') || (*p == '\t') ) p++;
126     *pconfline = p;
127 }
128
129 static int DOSCONF_JumpToEntry(char **pconfline, char separator)
130 {
131     char *p;
132
133     p = *pconfline;
134     while ( (*p != separator) && (*p != '\0') ) p++;
135
136     if (*p != separator)
137         return 0;
138     else 
139         p++;
140
141     while ( (*p == ' ') || (*p == '\t') ) p++;
142     *pconfline = p;
143     return 1;
144 }
145
146 static int DOSCONF_Device(char **confline)
147 {
148     int loadhigh = 0;
149
150     *confline += 6; /* strlen("DEVICE") */
151     if (!(strncasecmp(*confline, "HIGH", 4)))
152     {
153         loadhigh = 1;
154         *confline += 4;
155         /* FIXME: get DEVICEHIGH parameters if avail ? */
156     }
157     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
158     TRACE("Loading device '%s'\n", *confline);
159 #if 0
160     DOSMOD_LoadDevice(*confline, loadhigh);
161 #endif
162     return 1;
163 }
164
165 static int DOSCONF_Dos(char **confline)
166 {
167     *confline += 3; /* strlen("DOS") */
168     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
169     while (**confline != '\0')
170     {
171         if (!(strncasecmp(*confline, "HIGH", 4)))
172         {
173             DOSCONF_config.flags |= DOSCONF_MEM_HIGH;
174             *confline += 4;
175         }
176         else if (!(strncasecmp(*confline, "UMB", 3)))
177         {
178             DOSCONF_config.flags |= DOSCONF_MEM_UMB;
179             *confline += 3;
180         }
181         else 
182         {
183             (*confline)++;
184         }
185
186         DOSCONF_JumpToEntry(confline, ',');
187     }
188     TRACE( "DOSCONF_Dos: HIGH is %d, UMB is %d\n",
189            (DOSCONF_config.flags & DOSCONF_MEM_HIGH) != 0, 
190            (DOSCONF_config.flags & DOSCONF_MEM_UMB) != 0 );
191     return 1;
192 }
193
194 static int DOSCONF_Fcbs(char **confline)
195 {
196     *confline += 4; /* strlen("FCBS") */
197     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
198     DOSCONF_config.fcbs = atoi(*confline);
199     if (DOSCONF_config.fcbs > 255)
200     {
201         WARN( "The FCBS value in the config.sys file is too high! Setting to 255.\n" );
202         DOSCONF_config.fcbs = 255;
203     }
204     TRACE( "DOSCONF_Fcbs returning %d\n", DOSCONF_config.fcbs );
205     return 1;
206 }
207
208 static int DOSCONF_Break(char **confline)
209 {
210     *confline += 5; /* strlen("BREAK") */
211     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
212     if (!(strcasecmp(*confline, "ON")))
213         DOSCONF_config.brk_flag = 1;
214     TRACE( "BREAK is %d\n", DOSCONF_config.brk_flag );
215     return 1;
216 }
217
218 static int DOSCONF_Files(char **confline)
219 {
220     *confline += 5; /* strlen("FILES") */
221     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
222     DOSCONF_config.files = atoi(*confline);
223     if (DOSCONF_config.files > 255)
224     {
225         WARN( "The FILES value in the config.sys file is too high! Setting to 255.\n" );
226         DOSCONF_config.files = 255;
227     }
228     if (DOSCONF_config.files < 8)
229     {
230         WARN( "The FILES value in the config.sys file is too low! Setting to 8.\n" );
231         DOSCONF_config.files = 8;
232     }
233     TRACE( "DOSCONF_Files returning %d\n", DOSCONF_config.files );
234     return 1;
235 }
236
237 static int DOSCONF_Install(char **confline)
238 {
239 #if 0
240     int loadhigh = 0;
241 #endif
242
243     *confline += 7; /* strlen("INSTALL") */
244     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
245     TRACE( "Installing '%s'\n", *confline );
246 #if 0
247     DOSMOD_Install(*confline, loadhigh);
248 #endif
249     return 1;
250 }
251
252 static int DOSCONF_Lastdrive(char **confline)
253 {
254     *confline += 9; /* strlen("LASTDRIVE") */
255     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
256     DOSCONF_config.lastdrive = toupper(**confline);
257     TRACE( "Lastdrive %c\n", DOSCONF_config.lastdrive );
258     return 1;
259 }
260
261 static int DOSCONF_Country(char **confline)
262 {
263     *confline += 7; /* strlen("COUNTRY") */
264     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
265     TRACE( "Country '%s'\n", *confline );
266     if (DOSCONF_config.country == NULL)
267         DOSCONF_config.country = malloc(strlen(*confline) + 1);
268     strcpy(DOSCONF_config.country, *confline);
269     return 1;
270 }
271
272 static int DOSCONF_Numlock(char **confline)
273 {
274     *confline += 7; /* strlen("NUMLOCK") */
275     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
276     if (!(strcasecmp(*confline, "ON")))
277         DOSCONF_config.flags |= DOSCONF_NUMLOCK;
278     TRACE( "NUMLOCK is %d\n", 
279            (DOSCONF_config.flags & DOSCONF_NUMLOCK) != 0 );
280     return 1;
281 }
282
283 static int DOSCONF_Switches(char **confline)
284 {
285     char *p;
286
287     *confline += 8; /* strlen("SWITCHES") */
288     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
289     p = strtok(*confline, "/");
290     do
291     {
292         if ( toupper(*p) == 'K')
293             DOSCONF_config.flags |= DOSCONF_KEYB_CONV;
294     }
295     while ((p = strtok(NULL, "/")));
296     TRACE( "'Force conventional keyboard' is %d\n",
297            (DOSCONF_config.flags & DOSCONF_KEYB_CONV) != 0 );
298     return 1;
299 }
300
301 static int DOSCONF_Shell(char **confline)
302 {
303     *confline += 5; /* strlen("SHELL") */
304     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
305     TRACE( "Shell '%s'\n", *confline );
306     if (DOSCONF_config.shell == NULL)
307         DOSCONF_config.shell = malloc(strlen(*confline) + 1);
308     strcpy(DOSCONF_config.shell, *confline);
309     return 1;
310 }
311
312 static int DOSCONF_Stacks(char **confline)
313 {
314
315     *confline += 6; /* strlen("STACKS") */
316     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
317     DOSCONF_config.stacks_nr = atoi(strtok(*confline, ","));
318     DOSCONF_config.stacks_sz = atoi((strtok(NULL, ",")));
319     TRACE( "%d stacks of size %d\n",
320            DOSCONF_config.stacks_nr, DOSCONF_config.stacks_sz );
321     return 1;
322 }
323
324 static int DOSCONF_Buffers(char **confline)
325 {
326     char *p;
327
328     *confline += 7; /* strlen("BUFFERS") */
329     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
330     p = strtok(*confline, ",");
331     DOSCONF_config.buf = atoi(p);
332     if ((p = strtok(NULL, ",")))
333         DOSCONF_config.buf2 = atoi(p);
334     TRACE( "%d primary buffers, %d secondary buffers\n",
335            DOSCONF_config.buf, DOSCONF_config.buf2 );
336     return 1;
337 }
338
339 static int DOSCONF_Menu(char **confline)
340 {
341     if (!(strncasecmp(*confline, "[MENU]", 6)))
342     {
343         DOSCONF_menu_in_listing = 1;
344     }
345     else if ((!(strncasecmp(*confline, "[COMMON]", 8)))
346              || (!(strncasecmp(*confline, "[WINE]", 6))))
347     {
348         DOSCONF_menu_skip = 0;
349     }
350     else if (**confline == '[')
351     {
352         (*confline)++;
353         if ((DOSCONF_menu_default)
354             && (!(strncasecmp(*confline, DOSCONF_menu_default, 
355                               strlen(DOSCONF_menu_default)))))
356         {
357             free(DOSCONF_menu_default);
358             DOSCONF_menu_default = NULL;
359             DOSCONF_menu_skip = 0;
360         }
361         else
362             DOSCONF_menu_skip = 1;
363         DOSCONF_menu_in_listing = 0;
364     }
365     else if (!(strncasecmp(*confline, "menudefault", 11)) 
366              && (DOSCONF_menu_in_listing))
367     {
368         if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
369         *confline = strtok(*confline, ",");
370         DOSCONF_menu_default = malloc(strlen(*confline) + 1);
371         strcpy(DOSCONF_menu_default, *confline);
372     }
373
374     return 1;
375 }
376
377 static int DOSCONF_Include(char **confline)
378 {
379     fpos_t oldpos;
380     char *temp;
381
382     *confline += 7; /* strlen("INCLUDE") */
383     if (!(DOSCONF_JumpToEntry(confline, '='))) return 0;
384     fgetpos(DOSCONF_fd, &oldpos);
385     fseek(DOSCONF_fd, 0, SEEK_SET);
386     TRACE( "Including menu '%s'\n", *confline );
387     temp = malloc(strlen(*confline) + 1);
388     strcpy(temp, *confline);
389     DOSCONF_Parse(temp);
390     free(temp);
391     fsetpos(DOSCONF_fd, &oldpos);
392     return 1;
393 }
394
395 static void DOSCONF_Parse(char *menuname)
396 {
397     char confline[256];
398     char *p, *trail;
399     unsigned int i;
400
401     if (menuname != NULL) /* we need to jump to a certain sub menu */
402     {
403         while (fgets(confline, 255, DOSCONF_fd))
404         {
405              p = confline;
406              DOSCONF_skip(&p);
407              if (*p == '[')
408              {
409                 p++;
410                 if (!(trail = strrchr(p, ']')))
411                     return;
412                 if (!(strncasecmp(p, menuname, (int)trail - (int)p)))
413                     break;
414              }
415         }
416     }
417
418     while (fgets(confline, 255, DOSCONF_fd))
419     {
420         p = confline;
421         DOSCONF_skip(&p);
422
423         if ((menuname) && (*p == '['))
424             /*
425              * we were handling a specific sub menu, 
426              * but now next menu begins 
427              */
428             break;
429
430         if ((trail = strrchr(confline, '\n')))
431             *trail = '\0';
432         if ((trail = strrchr(confline, '\r')))
433             *trail = '\0';
434         if (!(DOSCONF_menu_skip))
435         {
436             for (i = 0; i < sizeof(DOSCONF_tag_entries) / sizeof(TAG_ENTRY); 
437                  i++)
438                 if (!(strncasecmp(p, DOSCONF_tag_entries[i].tag_name,
439                                   strlen(DOSCONF_tag_entries[i].tag_name))))
440                 {
441                     TRACE( "tag '%s'\n", DOSCONF_tag_entries[i].tag_name );
442                     if (DOSCONF_tag_entries[i].tag_handler != NULL)
443                         DOSCONF_tag_entries[i].tag_handler(&p);
444                     break;
445                 }
446         }
447         else
448         { 
449             /* the current menu gets skipped */
450             DOSCONF_Menu(&p);
451         }
452     }
453 }
454
455 DOSCONF *DOSCONF_GetConfig(void)
456 {
457     char *fullname;
458     WCHAR filename[MAX_PATH];
459     static const WCHAR configW[] = {'c','o','n','f','i','g','.','s','y','s',0};
460
461     if (DOSCONF_loaded)
462         return &DOSCONF_config;
463
464     /* look for config.sys at the root of the drive containing the windows dir */
465     GetWindowsDirectoryW( filename, MAX_PATH );
466     strcpyW( filename + 3, configW );
467
468     if ((fullname = wine_get_unix_file_name(filename)))
469     {
470         DOSCONF_fd = fopen(fullname, "r");
471         HeapFree( GetProcessHeap(), 0, fullname );
472     }
473
474     if (DOSCONF_fd)
475     {
476         DOSCONF_Parse(NULL);
477         fclose(DOSCONF_fd);
478         DOSCONF_fd = NULL;
479     }
480     else WARN( "Couldn't open %s\n", debugstr_w(filename) );
481
482     DOSCONF_loaded = TRUE;
483     return &DOSCONF_config;
484 }