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