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