Subversion Repositories SvarDOS

Rev

Rev 1943 | Rev 1946 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
28 mv_fox 1
/*
190 mateuszvis 2
 * SVARDOS INSTALL PROGRAM
206 mateuszvis 3
 *
190 mateuszvis 4
 * PUBLISHED UNDER THE TERMS OF THE MIT LICENSE
42 mv_fox 5
 *
1624 mateusz.vi 6
 * COPYRIGHT (C) 2016-2024 MATEUSZ VISTE, ALL RIGHTS RESERVED.
94 mv_fox 7
 *
190 mateuszvis 8
 * Permission is hereby granted, free of charge, to any person obtaining a
9
 * copy of this software and associated documentation files (the "Software"),
10
 * to deal in the Software without restriction, including without limitation
11
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12
 * and/or sell copies of the Software, and to permit persons to whom the
13
 * Software is furnished to do so, subject to the following conditions:
94 mv_fox 14
 *
190 mateuszvis 15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
94 mv_fox 17
 *
190 mateuszvis 18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24
 * DEALINGS IN THE SOFTWARE.
94 mv_fox 25
 *
868 mateusz.vi 26
 * http://svardos.org
28 mv_fox 27
 */
28
 
29
#include <dos.h>
30 mv_fox 30
#include <direct.h>  /* mkdir() */
28 mv_fox 31
#include <stdio.h>   /* printf() and friends */
32
#include <stdlib.h>  /* system() */
33
#include <string.h>  /* memcpy() */
34
#include <unistd.h>
42 mv_fox 35
 
1662 mateusz.vi 36
#include "mdr\cout.h"
1661 mateusz.vi 37
#include "mdr\dos.h"
624 mateuszvis 38
#include "svarlang.lib\svarlang.h"
42 mv_fox 39
 
67 mv_fox 40
/* keyboard layouts and locales */
41
#include "keylay.h"
42
#include "keyoff.h"
42 mv_fox 43
 
908 mateusz.vi 44
 
1664 mateusz.vi 45
/* color scheme (preset for color) */
46
static unsigned char COLOR_TITLEBAR  = 0x70;
1671 mateusz.vi 47
static unsigned char COLOR_TITLEVER  = 0x78;
1664 mateusz.vi 48
static unsigned char COLOR_BODY      = 0x17;
1673 mateusz.vi 49
static unsigned char COLOR_BODYWARN  = 0x1F;
1664 mateusz.vi 50
static unsigned char COLOR_SELECT    = 0x70;
51
static unsigned char COLOR_SELECTCUR = 0x1F;
28 mv_fox 52
 
1671 mateusz.vi 53
/* build release string, populated at startup by reading floppy's label */
54
static char BUILDSTRING[13];
28 mv_fox 55
 
190 mateuszvis 56
/* how much disk space does SvarDOS require (in MiB) */
1928 mateusz.vi 57
#define SVARDOS_DISK_REQ 4
28 mv_fox 58
 
73 mv_fox 59
/* menu screens can output only one of these: */
60
#define MENUNEXT 0
61
#define MENUPREV -1
62
#define MENUQUIT -2
63
 
67 mv_fox 64
/* a convenience 'function' used for debugging */
65
#define DBG(x) { video_putstringfix(24, 0, 0x4F00u, x, 80); }
47 mv_fox 66
 
67 mv_fox 67
struct slocales {
68
  char lang[4];
624 mateuszvis 69
  const char *keybcode;
1908 mateusz.vi 70
  unsigned short codepage;
71
  unsigned char egafile;
72
  unsigned char keybfile;
73
  short keyboff;
74
  short keyblen;
75
  unsigned short keybid;
76
  unsigned short countryid; /* 1=USA, 33=FR, 48=PL, etc */
67 mv_fox 77
};
78
 
79
 
1930 mateusz.vi 80
/* returns the DOS boot drive letter ('A', 'B', 'C', etc) */
81
static unsigned char GETDOSBOOTDRIVE(void);
82
#pragma aux GETDOSBOOTDRIVE = \
83
"mov ax, 0x3305" /* int 0x21,AX=3305 - get boot drive (MS-DOS 4.0+) */ \
84
"int 0x21" \
85
"jnc GOOD" \
86
"mov dl, 3"      /* fall back to "C" on error (DOS 3.x...) */ \
87
"GOOD:" \
88
"add dl, '@'"    /* convert the drive id (A=1, B=2...) into a drive letter */ \
89
modify [ax] \
90
value [dl]
91
 
92
 
1918 mateusz.vi 93
/* install a dummy int24h handler that always fails. this is to avoid the
94
 * annoying "abort, retry, fail... DOS messages. */
95
static void install_int24(void) {
96
  static unsigned char handler[] = { /* contains machine code instructions */
97
    0xB0, 0x03,  /* mov al, 3   ; tell DOS the action has to FAIL   */
98
    0xCF};       /* ret         ; return from the interrupt handler */
99
  /* install the handler */
100
  _asm {
101
    push dx
102
    mov ax, 0x2524          /* set INT vector 0x24 (to DS:DX)   */
103
    mov dx, offset handler  /* DS:DX points at my dummy handler */
104
    int 0x21
105
    pop dx
106
  }
107
}
108
 
109
 
110
static void exec(const char *s) {
111
  system(s);
112
  install_int24(); /* reinstall my int24 handler, apparently system() reverts
113
                      the original (DOS) one */
114
}
115
 
116
 
1908 mateusz.vi 117
/* put a string on screen and fill it until w chars with white space */
1662 mateusz.vi 118
static void video_putstringfix(unsigned char y, unsigned char x, unsigned char attr, const char *s, unsigned char w) {
119
  unsigned char i;
120
 
121
  /* print the string up to w characters */
122
  i = mdr_cout_str(y, x, s, attr, w);
123
 
124
  /* fill in left space (if any) with blanks */
125
  mdr_cout_char_rep(y, x + i, ' ', attr, w - i);
126
}
127
 
128
 
28 mv_fox 129
/* reboot the computer */
130
static void reboot(void) {
131
  void ((far *bootroutine)()) = (void (far *)()) 0xFFFF0000L;
132
  int far *rstaddr = (int far *)0x00400072L; /* BIOS boot flag is at 0040:0072 */
133
  *rstaddr = 0x1234; /* 0x1234 = warm boot, 0 = cold boot */
134
  (*bootroutine)(); /* jump to the BIOS reboot routine at FFFF:0000 */
135
}
136
 
42 mv_fox 137
 
1669 mateusz.vi 138
/* returns 1 if file exists, zero otherwise */
139
static int fileexists(const char *fname) {
140
  FILE *fd;
141
  fd = fopen(fname, "rb");
142
  if (fd == NULL) return(0);
143
  fclose(fd);
144
  return(1);
145
}
146
 
147
 
56 mv_fox 148
/* outputs a string to screen with taking care of word wrapping. returns amount of lines. */
1662 mateusz.vi 149
static unsigned char putstringwrap(unsigned char y, unsigned char x, unsigned char attr, const char *s) {
150
  unsigned char linew, lincount;
151
  linew = 80 - (x << 1);
56 mv_fox 152
 
153
  for (lincount = 1; y+lincount < 25; lincount++) {
154
    int i, len = linew;
155
    for (i = 0; i <= linew; i++) {
156
      if (s[i] == ' ') len = i;
157
      if (s[i] == '\n') {
158
        len = i;
159
        break;
160
      }
161
      if (s[i] == 0) {
162
        len = i;
163
        break;
164
      }
165
    }
1662 mateusz.vi 166
    mdr_cout_str(y++, x, s, attr, len);
56 mv_fox 167
    s += len;
168
    if (*s == 0) break;
169
    s += 1; /* skip the whitespace char */
170
  }
171
  return(lincount);
172
}
173
 
174
 
175
/* an NLS wrapper around video_putstring(), also performs line wrapping when
176
 * needed. returns the amount of lines that were output */
1662 mateusz.vi 177
static unsigned char putstringnls(unsigned char y, unsigned char x, unsigned char attr, unsigned char nlsmaj, unsigned char nlsmin) {
624 mateuszvis 178
  const char *s = svarlang_str(nlsmaj, nlsmin);
179
  if (s == NULL) s = "";
56 mv_fox 180
  return(putstringwrap(y, x, attr, s));
42 mv_fox 181
}
182
 
183
 
280 mateuszvis 184
/* copy file f1 to f2 using buff as a buffer of buffsz bytes. f2 will be overwritten if it
185
 * exists already! returns 0 on success. */
186
static int fcopy(const char *f2, const char *f1, void *buff, size_t buffsz) {
187
  FILE *fd1, *fd2;
188
  size_t sz;
189
  int res = -1; /* assume failure */
190
 
191
  /* open files */
192
  fd1 = fopen(f1, "rb");
193
  fd2 = fopen(f2, "wb");
194
  if ((fd1 == NULL) || (fd2 == NULL)) goto QUIT;
195
 
196
  /* copy data */
197
  for (;;) {
198
    sz = fread(buff, 1, buffsz, fd1);
199
    if (sz == 0) {
200
      if (feof(fd1) != 0) break;
201
      goto QUIT;
202
    }
203
    if (fwrite(buff, 1, sz, fd2) != sz) goto QUIT;
204
  }
205
 
206
  res = 0; /* success */
207
 
208
  QUIT:
209
  if (fd1 != NULL) fclose(fd1);
210
  if (fd2 != NULL) fclose(fd2);
211
  return(res);
212
}
213
 
214
 
1666 mateusz.vi 215
/* display a menu with items and return user's choice.
216
 * ypos: starting line where the menu is drawn
217
 * height: number of items to display inside the menu
218
 * list: NULL-terminated list of items
219
 * maxlistlen: limit list to this many items tops */
1665 mateusz.vi 220
static int menuselect(unsigned char ypos, unsigned char height, const char **list, int maxlistlen) {
221
  int i, offset = 0, res = 0, count;
222
  unsigned char y, xpos, width = 0;
1662 mateusz.vi 223
 
1666 mateusz.vi 224
  /* count how many positions there are, and check their width */
1665 mateusz.vi 225
  for (count = 0; (list[count] != NULL) && (count != maxlistlen); count++) {
28 mv_fox 226
    int len = strlen(list[count]);
227
    if (len > width) width = len;
228
  }
1666 mateusz.vi 229
  width++; /* it's nice to have a small margin to the right of the widest item */
28 mv_fox 230
 
231
  /* if xpos negative, means 'center out' */
1665 mateusz.vi 232
  xpos = 39 - (width >> 1);
28 mv_fox 233
 
1666 mateusz.vi 234
  mdr_cout_char_rep(ypos, xpos, 0xC4, COLOR_SELECT, width + 2);  /* top line */
1664 mateusz.vi 235
  mdr_cout_char(ypos, xpos+width+2, 0xBF, COLOR_SELECT);         /*       \ */
236
  mdr_cout_char(ypos, xpos-1, 0xDA, COLOR_SELECT);               /*  /      */
1666 mateusz.vi 237
  ypos++; /* from now on ypos relates to the position of the content */
238
  mdr_cout_char(ypos+height, xpos-1, 0xC0, COLOR_SELECT);      /*  \      */
239
  mdr_cout_char(ypos+height, xpos+width+2, 0xD9, COLOR_SELECT);/*      /  */
240
  mdr_cout_char_rep(ypos+height, xpos, 0xC4, COLOR_SELECT, width + 2);
28 mv_fox 241
 
242
  for (;;) {
243
    int key;
1666 mateusz.vi 244
 
245
    /* draw side borders of the menu + the cursor */
246
    if (count <= height) { /* no need for a cursor, all fits on one page */
247
      i = 255;
248
    } else {
249
      i = offset * (height - 1) / (count - height);
250
    }
251
 
252
    for (y = ypos; y < (ypos + height); y++) {
253
      mdr_cout_char(y, xpos-1, 0xB3, COLOR_SELECT); /* left side */
254
      if (y - ypos == i) {
1667 mateusz.vi 255
        mdr_cout_char(y, xpos+width+2, '=', COLOR_SELECT); /* cursor */
1666 mateusz.vi 256
      } else {
257
        mdr_cout_char(y, xpos+width+2, 0xB3, COLOR_SELECT); /* right side */
258
      }
259
    }
260
 
28 mv_fox 261
    /* list of selectable items */
1666 mateusz.vi 262
    for (i = 0; i < height; i++) {
28 mv_fox 263
      if (i + offset == res) {
1666 mateusz.vi 264
        mdr_cout_char(ypos + i, xpos, 16, COLOR_SELECTCUR);
265
        mdr_cout_char(ypos + i, xpos+width+1, 17, COLOR_SELECTCUR);
266
        mdr_cout_locate(ypos + i, xpos);
267
        video_putstringfix(ypos + i, xpos+1, COLOR_SELECTCUR, list[i + offset], width);
28 mv_fox 268
      } else if (i + offset < count) {
1666 mateusz.vi 269
        mdr_cout_char(ypos + i, xpos, ' ', COLOR_SELECT);
270
        mdr_cout_char(ypos + i, xpos+width+1, ' ', COLOR_SELECT);
271
        video_putstringfix(ypos + i, xpos+1, COLOR_SELECT, list[i + offset], width);
28 mv_fox 272
      } else {
1666 mateusz.vi 273
        mdr_cout_char_rep(ypos + i, xpos, ' ', COLOR_SELECT, width+2);
28 mv_fox 274
      }
275
    }
1661 mateusz.vi 276
    key = mdr_dos_getkey();
28 mv_fox 277
    if (key == 0x0D) { /* ENTER */
278
      return(res);
279
    } else if (key == 0x148) { /* up */
33 mv_fox 280
      if (res > 0) {
281
        res--;
282
        if (res < offset) offset = res;
283
      }
28 mv_fox 284
    } else if (key == 0x150) { /* down */
33 mv_fox 285
      if (res+1 < count) {
286
        res++;
1666 mateusz.vi 287
        if (res > offset + height - 1) offset = res - (height - 1);
33 mv_fox 288
      }
289
    } else if (key == 0x147) { /* home */
290
      res = 0;
291
      offset = 0;
292
    } else if (key == 0x14F) { /* end */
293
      res = count - 1;
1666 mateusz.vi 294
      if (res > offset + height - 1) offset = res - (height - 1);
28 mv_fox 295
    } else if (key == 0x1B) {  /* ESC */
296
      return(-1);
78 mv_fox 297
    }/* else {
33 mv_fox 298
      char buf[8];
55 mv_fox 299
      snprintf(buf, sizeof(buf), "0x%02X ", key);
1664 mateusz.vi 300
      video_putstring(1, 0, COLOR_BODY, buf, -1);
78 mv_fox 301
    }*/
28 mv_fox 302
  }
303
}
304
 
1662 mateusz.vi 305
static void newscreen(unsigned char statusbartype) {
624 mateuszvis 306
  const char *msg;
1664 mateusz.vi 307
  mdr_cout_cls(COLOR_BODY);
624 mateuszvis 308
  msg = svarlang_strid(0x00); /* "SVARDOS INSTALLATION" */
1664 mateusz.vi 309
  mdr_cout_char_rep(0, 0, ' ', COLOR_TITLEBAR, 80);
310
  mdr_cout_str(0, 40 - (strlen(msg) >> 1), msg, COLOR_TITLEBAR, 80);
1671 mateusz.vi 311
  mdr_cout_str(0, 80 - strlen(BUILDSTRING), BUILDSTRING, COLOR_TITLEVER, 12);
312
 
79 mv_fox 313
  switch (statusbartype) {
314
    case 1:
624 mateuszvis 315
      msg = svarlang_strid(0x000B); /* "Up/Down = Select entry | Enter = Validate your choice | ESC = Quit to DOS" */
79 mv_fox 316
      break;
317
    case 2:
624 mateuszvis 318
      msg = svarlang_strid(0x0005); /* "Press any key..." */
79 mv_fox 319
      break;
320
    case 3:
321
      msg = "";
322
      break;
323
    default:
624 mateuszvis 324
      msg = svarlang_strid(0x000A); /* "Up/Down = Select entry | Enter = Validate your choice | ESC = Previous screen" */
79 mv_fox 325
      break;
326
  }
1664 mateusz.vi 327
  mdr_cout_char(24, 0, ' ', COLOR_TITLEBAR);
328
  video_putstringfix(24, 1, COLOR_TITLEBAR, msg, 79);
1662 mateusz.vi 329
  mdr_cout_locate(25,0);
28 mv_fox 330
}
331
 
1908 mateusz.vi 332
 
96 mv_fox 333
/* fills a slocales struct accordingly to the value of its keyboff member */
334
static void kblay2slocal(struct slocales *locales) {
624 mateuszvis 335
  const char *m;
96 mv_fox 336
  for (m = kblayouts[locales->keyboff]; *m != 0; m++); /* skip layout name */
337
  m++;
338
  /* skip keyb code and copy it to locales.keybcode */
339
  locales->keybcode = m;
340
  for (; *m != 0; m++);
341
  /* */
342
  locales->codepage = ((unsigned short)m[1] << 8) | m[2];
343
  locales->egafile = m[3];
344
  locales->keybfile = m[4];
345
  locales->keybid = ((unsigned short)m[5] << 8) | m[6];
1908 mateusz.vi 346
  locales->countryid = ((unsigned short)m[7] << 8) | m[8];
96 mv_fox 347
}
348
 
1908 mateusz.vi 349
 
67 mv_fox 350
static int selectlang(struct slocales *locales) {
351
  int choice, x;
624 mateuszvis 352
  const char *msg;
353
  const char *langlist[] = {
67 mv_fox 354
    "English",
1177 mateusz.vi 355
    "Brazilian",
67 mv_fox 356
    "French",
133 mv_fox 357
    "German",
119 mv_fox 358
    "Italian",
67 mv_fox 359
    "Polish",
116 mv_fox 360
    "Russian",
123 mv_fox 361
    "Slovene",
128 mv_fox 362
    "Swedish",
67 mv_fox 363
    "Turkish",
28 mv_fox 364
    NULL
365
  };
366
 
79 mv_fox 367
  newscreen(1);
624 mateuszvis 368
  msg = svarlang_strid(0x0100); /* "Welcome to SvarDOS" */
42 mv_fox 369
  x = 40 - (strlen(msg) >> 1);
1664 mateusz.vi 370
  mdr_cout_str(4, x, msg, COLOR_BODY, 80);
371
  mdr_cout_char_rep(5, x, '=', COLOR_BODY, strlen(msg));
1662 mateusz.vi 372
 
373
  /* center out the string "Please select your language..." */
374
  msg = svarlang_str(1, 1); /* "Please select your language from the list below:" */
375
  if (strlen(msg) > 74) {
1664 mateusz.vi 376
    putstringwrap(8, 1, COLOR_BODY, msg);
1662 mateusz.vi 377
  } else {
1664 mateusz.vi 378
    mdr_cout_str(8, 40 - (strlen(msg) / 2), msg, COLOR_BODY, 80);
1662 mateusz.vi 379
  }
380
 
1666 mateusz.vi 381
  choice = menuselect(11, 9, langlist, -1);
73 mv_fox 382
  if (choice < 0) return(MENUPREV);
1669 mateusz.vi 383
 
67 mv_fox 384
  /* populate locales with default values */
385
  memset(locales, 0, sizeof(struct slocales));
386
  switch (choice) {
387
    case 1:
1179 mateusz.vi 388
      strcpy(locales->lang, "BR");
389
      locales->keyboff = OFFLOC_BR;
390
      locales->keyblen = OFFLEN_BR;
391
      break;
392
    case 2:
67 mv_fox 393
      strcpy(locales->lang, "FR");
394
      locales->keyboff = OFFLOC_FR;
395
      locales->keyblen = OFFLEN_FR;
396
      break;
1177 mateusz.vi 397
    case 3:
133 mv_fox 398
      strcpy(locales->lang, "DE");
399
      locales->keyboff = OFFLOC_DE;
400
      locales->keyblen = OFFLEN_DE;
401
      break;
1177 mateusz.vi 402
    case 4:
119 mv_fox 403
      strcpy(locales->lang, "IT");
404
      locales->keyboff = OFFLOC_IT;
405
      locales->keyblen = OFFLEN_IT;
406
      break;
1177 mateusz.vi 407
    case 5:
67 mv_fox 408
      strcpy(locales->lang, "PL");
409
      locales->keyboff = OFFLOC_PL;
410
      locales->keyblen = OFFLEN_PL;
411
      break;
1177 mateusz.vi 412
    case 6:
116 mv_fox 413
      strcpy(locales->lang, "RU");
414
      locales->keyboff = OFFLOC_RU;
415
      locales->keyblen = OFFLEN_RU;
416
      break;
1177 mateusz.vi 417
    case 7:
123 mv_fox 418
      strcpy(locales->lang, "SI");
419
      locales->keyboff = OFFLOC_SI;
420
      locales->keyblen = OFFLEN_SI;
421
      break;
1177 mateusz.vi 422
    case 8:
128 mv_fox 423
      strcpy(locales->lang, "SV");
424
      locales->keyboff = OFFLOC_SV;
425
      locales->keyblen = OFFLEN_SV;
426
      break;
1177 mateusz.vi 427
    case 9:
67 mv_fox 428
      strcpy(locales->lang, "TR");
429
      locales->keyboff = OFFLOC_TR;
430
      locales->keyblen = OFFLEN_TR;
431
      break;
432
    default:
433
      strcpy(locales->lang, "EN");
434
      locales->keyboff = 0;
435
      locales->keyblen = OFFCOUNT;
436
      break;
437
  }
96 mv_fox 438
  /* populate the slocales struct accordingly to the keyboff member */
439
  kblay2slocal(locales);
67 mv_fox 440
  /* */
73 mv_fox 441
  return(MENUNEXT);
28 mv_fox 442
}
443
 
444
 
67 mv_fox 445
static int selectkeyb(struct slocales *locales) {
96 mv_fox 446
  int menuheight, choice;
447
  if (locales->keyblen == 1) return(MENUNEXT); /* do not ask for keyboard layout if only one is available for given language */
79 mv_fox 448
  newscreen(0);
1664 mateusz.vi 449
  putstringnls(5, 1, COLOR_BODY, 1, 5); /* "SvarDOS supports different keyboard layouts */
1666 mateusz.vi 450
  menuheight = locales->keyblen;
451
  if (menuheight > 11) menuheight = 11;
1665 mateusz.vi 452
  choice = menuselect(10, menuheight, &(kblayouts[locales->keyboff]), locales->keyblen);
96 mv_fox 453
  if (choice < 0) return(MENUPREV);
454
  /* (re)load the keyboard layout & codepage setup */
455
  locales->keyboff += choice;
456
  kblay2slocal(locales);
73 mv_fox 457
  return(MENUNEXT);
67 mv_fox 458
}
459
 
460
 
28 mv_fox 461
/* returns 0 if installation must proceed, non-zero otherwise */
462
static int welcomescreen(void) {
73 mv_fox 463
  int c;
624 mateuszvis 464
  const char *choice[3];
465
  choice[0] = svarlang_strid(0x0001);
466
  choice[1] = svarlang_strid(0x0002);
467
  choice[2] = NULL;
79 mv_fox 468
  newscreen(0);
1664 mateusz.vi 469
  putstringnls(4, 1, COLOR_BODY, 2, 0); /* "You are about to install SvarDOS */
1666 mateusz.vi 470
  c = menuselect(13, 2, choice, -1);
73 mv_fox 471
  if (c < 0) return(MENUPREV);
472
  if (c == 0) return(MENUNEXT);
473
  return(MENUQUIT);
28 mv_fox 474
}
475
 
476
 
1908 mateusz.vi 477
/* returns 0 if drive is removable, 1 if fixed, -1 on error */
478
static int isdriveremovable(unsigned char drv);
479
#pragma aux isdriveremovable = \
480
"mov ax, 0x4408" \
481
"int 0x21" \
482
"jnc DONE" \
483
"xor ax,ax" \
484
"dec ax" \
485
"DONE:" \
486
parm [bl] \
487
value [ax]
28 mv_fox 488
 
489
 
1908 mateusz.vi 490
/* returns total disk space of drive drv (in MiB, max 2048, A=1 B=2 etc), or -1 if drive invalid */
1911 mateusz.vi 491
static int disksize(unsigned char drv) {
492
  unsigned short sec_per_cluster = 0;
493
  unsigned short tot_clusters = 0;
494
  unsigned short bytes_per_sec = 0;
495
  long res;
496
  _asm {
497
    push ax
498
    push bx
499
    push cx
500
    push dx
35 mv_fox 501
 
1911 mateusz.vi 502
    mov ah, 0x36
503
    mov dl, drv
504
    int 0x21
505
    /* AX=sec_per_cluster DX=tot_clusters BX=free_clusters CX=bytes_per_sec */
506
    mov sec_per_cluster, ax
507
    mov bytes_per_sec, cx
508
    mov tot_clusters, dx
35 mv_fox 509
 
1911 mateusz.vi 510
    pop dx
511
    pop cx
512
    pop bx
513
    pop ax
514
  }
515
 
516
  if (sec_per_cluster == 0xffff) return(-1);
517
  res = sec_per_cluster;
518
  res *= tot_clusters;
519
  res *= bytes_per_sec;
520
  res >>= 20;
521
  return((int)res);
522
}
523
 
524
 
35 mv_fox 525
/* returns 0 if disk is empty, non-zero otherwise */
1942 mateusz.vi 526
static int diskempty(char drv) {
35 mv_fox 527
  unsigned int rc;
528
  int res;
529
  char buff[8];
530
  struct find_t fileinfo;
1942 mateusz.vi 531
  snprintf(buff, sizeof(buff), "%c:\\*.*", drv);
35 mv_fox 532
  rc = _dos_findfirst(buff, _A_NORMAL | _A_SUBDIR | _A_HIDDEN | _A_SYSTEM, &fileinfo);
533
  if (rc == 0) {
534
    res = 1; /* call successfull means disk is not empty */
28 mv_fox 535
  } else {
35 mv_fox 536
    res = 0;
28 mv_fox 537
  }
35 mv_fox 538
  /* _dos_findclose(&fileinfo); */ /* apparently required only on OS/2 */
28 mv_fox 539
  return(res);
540
}
541
 
200 mateuszvis 542
 
1930 mateusz.vi 543
/* replace all occurences of char a by char b in s */
544
static void strtr(char *s, char a, char b) {
545
  for (;*s != 0; s++) {
546
    if (*s == a) *s = b;
547
  }
548
}
549
 
550
 
898 mateusz.vi 551
/* tries to write an empty file to drive.
552
 * asks DOS to inhibit the int 24h handler for this job, so erros are
553
 * gracefully reported - unfortunately this does not work under FreeDOS because
554
 * the DOS-C kernel does not implement the required flag.
555
 * returns 0 on success (ie. "disk exists and is writeable"). */
1908 mateusz.vi 556
static unsigned short test_drive_write(char drive) {
898 mateusz.vi 557
  unsigned short result = 0;
1908 mateusz.vi 558
  char *buff = "@:\\SVWRTEST.123";
559
  buff[0] = drive;
898 mateusz.vi 560
  _asm {
561
    push ax
562
    push bx
563
    push cx
564
    push dx
565
 
566
    mov ah, 0x6c   /* extended open/create file */
567
    mov bx, 0x2001 /* open for write + inhibit int 24h handler */
568
    xor cx, cx     /* file attributes on the created file */
569
    mov dx, 0x0010 /* create file if does not exist, fail if it exists */
570
    mov si, buff   /* filename to create */
571
    int 0x21
572
    jc FAILURE
573
    /* close the file (handle in AX) */
574
    mov bx, ax
575
    mov ah, 0x3e /* close file */
576
    int 0x21
577
    jc FAILURE
578
    /* delete the file */
579
    mov ah, 0x41 /* delete file pointed out by DS:DX */
580
    mov dx, buff
581
    int 0x21
582
    jnc DONE
583
 
584
    FAILURE:
585
    mov result, ax
586
    DONE:
587
 
588
    pop dx
589
    pop cx
590
    pop bx
591
    pop ax
592
  }
593
  return(result);
594
}
595
 
596
 
1944 mateusz.vi 597
#define MBR_WRITE 3
598
#define MBR_READ 2
599
/* read (action=2) or write (action=3) MBR of driveid (0x80, 0x81..) into buff */
600
static int READ_OR_WRITE_MBR(unsigned char action, char *buff, unsigned char driveid);
601
#pragma aux READ_OR_WRITE_MBR = \
1939 mateusz.vi 602
"push es" \
1944 mateusz.vi 603
"mov al, 1"       /* read 1 sector into memory */ \
1940 mateusz.vi 604
"mov cx, 0x0001"  /* cylinder 0, sector 1 */ \
605
"xor dh, dh"      /* head 0 */ \
1939 mateusz.vi 606
"push ds" \
607
"pop es" \
608
"int 0x13" \
609
"mov ax, 0" /* do not do "xor ax, ax", CF needs to be preserved */ \
610
"jnc DONE" \
611
"inc ax" \
612
"DONE:" \
613
"pop es" \
1944 mateusz.vi 614
parm [ah] [bx] [dl] \
1940 mateusz.vi 615
modify [cx dx] \
1939 mateusz.vi 616
value [ax]
617
 
618
 
1944 mateusz.vi 619
 
1939 mateusz.vi 620
/*
621
 * MBR structure:
622
 *
623
 * Boot signature (word 0xAA55) is at 0x01FE
624
 *
625
 * partition entry 1 is at 0x01BE
626
 *                 2    at 0x01CE
627
 *                 3    at 0x01DE
628
 *                 4    at 0x01EE
629
 *
630
 * a partition entry is:
631
 * 0x00  status byte (active is bit 0x80 set)
632
 * 0x01  CHS addr of first sector (here: HEAD)
633
 * 0x02  CHS addr of first sector (CCSSSSSS) sector in 6 low bits, cylinder high bits in CC
634
 * 0x03  CHS addr of furst sector (here: low 8 bits of cylinder)
635
 * 0x04  Partition type:
636
        0x06/0x08 for CHS FAT16/32
637
        0x0E/0x0C for LBA FAT16/32
638
 * 0x05  CHS addr of last sector (same format as for 1st sector)
639
 * 0x06  CHS addr of last sector (same format as for 1st sector)
640
 * 0x07  CHS addr of last sector (same format as for 1st sector)
641
 * 0x08  LBA addr of first sector (4 bytes) - used sometimes instead of CHS
642
 * 0x0C  number of sectors in partition (4 bytes)
643
 */
644
 
645
struct drivelist {
1940 mateusz.vi 646
  unsigned long start_lba;
1943 mateusz.vi 647
  unsigned long tot_sect;  /* size (of partition), in sectors */
1940 mateusz.vi 648
  unsigned short tot_size; /* size in MiB */
1943 mateusz.vi 649
  unsigned char partid;    /* position of the partition in the MBR (0,1,2,3) */
1944 mateusz.vi 650
  unsigned char hd;        /* 0-3 */
651
  unsigned char dosid;     /* DOS drive id (A=0, B=1...)*/
1939 mateusz.vi 652
};
653
 
1940 mateusz.vi 654
 
655
/* a (very partial) struct mimicking what EDR-DOS uses in int 2Fh,AX=0803h */
656
#pragma pack (push)
657
#pragma pack (0) /* disable the automatic alignment of struct members */
658
struct dos_udsc {
1944 mateusz.vi 659
  unsigned short next_off; /* offset FFFFh if last */
1940 mateusz.vi 660
  unsigned short next_seg;
1944 mateusz.vi 661
  unsigned char hd;        /* physical unit (as in int 13h) */
662
  unsigned char letter;    /* DOS letter drive (A=0, B=1, C=2, ...) */
1940 mateusz.vi 663
  unsigned short sectsize; /* bytes per sector */
664
  unsigned char unknown[15];
665
  unsigned long start_lba; /* LBA address of the partition (only for primary partitions) */
666
};
667
#pragma pack (pop)
668
 
669
 
670
/* get the DOS drive data table list */
671
static struct dos_udsc far *get_dos_udsc(void)  {
672
  unsigned short udsc_seg = 0, udsc_off = 0;
673
  _asm {
674
    push ds
675
    push di
676
 
677
    mov ax, 0x0803
678
    int 0x2f
679
    /* drive data table list is in DS:DI now */
680
    mov udsc_seg, ds
681
    mov udsc_off, di
682
 
683
    pop di
684
    pop ds
685
  }
686
  if (udsc_off == 0xffff) return(NULL);
687
  return(MK_FP(udsc_seg, udsc_off));
688
}
689
 
690
 
691
/* reads the MBR and matches its entries to DOS drives
1943 mateusz.vi 692
 * fills the drives array with up to 16 drives (4 partitions * 4 disks)
1940 mateusz.vi 693
 * see https://github.com/SvarDOS/bugz/issues/89 */
1943 mateusz.vi 694
static int get_drives_list(char *buff, struct drivelist *drives) {
1939 mateusz.vi 695
  int i;
1943 mateusz.vi 696
  int listlen = 0;
697
  int drv;
1940 mateusz.vi 698
  struct dos_udsc far *udsc_root = get_dos_udsc();
699
  struct dos_udsc far *udsc_node;
1939 mateusz.vi 700
 
1943 mateusz.vi 701
  for (drv = 0x80; drv < 0x84; drv++) {
1940 mateusz.vi 702
 
1944 mateusz.vi 703
    if (READ_OR_WRITE_MBR(MBR_READ, buff, drv) != 0) continue;
1939 mateusz.vi 704
 
1943 mateusz.vi 705
    /* check boot signature at 0x01fe */
706
    if (*(unsigned short *)(buff + 0x01fe) != 0xAA55) continue;
1939 mateusz.vi 707
 
1943 mateusz.vi 708
    /* iterate over the 4 partitions in the MBR */
709
    for (i = 0; i < 4; i++) {
710
      unsigned char *entry;
1939 mateusz.vi 711
 
1943 mateusz.vi 712
      entry = buff + 0x01BE + (i * 16);
1939 mateusz.vi 713
 
1943 mateusz.vi 714
      /* ignore partition if fs is unknown (non-FAT) */
715
      if ((entry[4] != 0x0E) && (entry[4] != 0x0C)  /* LBA FAT */
716
       && (entry[4] != 0x01) && (entry[4] != 0x06) && (entry[4] != 0x08)) { /* CHS FAT */
717
        continue;
1939 mateusz.vi 718
      }
1943 mateusz.vi 719
      bzero(&(drives[listlen]), sizeof(struct drivelist));
1944 mateusz.vi 720
      drives[listlen].hd = drv & 3;
1943 mateusz.vi 721
      drives[listlen].partid = i;
722
      drives[listlen].start_lba = ((unsigned long *)entry)[2];
723
      drives[listlen].tot_sect = ((unsigned long *)entry)[3];
1939 mateusz.vi 724
 
1943 mateusz.vi 725
      /* now iterate over DOS drives and try to match ont to this MBR entry */
726
      udsc_node = udsc_root;
727
      while (udsc_node != NULL) {
728
        if (udsc_node->hd != drv) goto NEXT;
729
        if (udsc_node->start_lba != drives[listlen].start_lba) goto NEXT;
1939 mateusz.vi 730
 
1943 mateusz.vi 731
        /* FOUND! */
1944 mateusz.vi 732
        drives[listlen].dosid = udsc_node->letter;
1943 mateusz.vi 733
        {
734
          unsigned long sz = (drives[listlen].tot_sect * udsc_node->sectsize) >> 20;
735
          drives[listlen].tot_size = (unsigned short)sz;
736
        }
737
        listlen++;
738
        break;
739
 
740
        NEXT:
741
        if (udsc_node->next_off == 0xffff) break;
742
        udsc_node = MK_FP(udsc_node->next_seg, udsc_node->next_off);
743
      } /* iterate over UDSC nodes */
744
    } /* iterate over partition entries of the MBR */
745
  } /* iterate over BIOS disks (0x80, 0x81, ...) */
746
 
747
  return(listlen);
1939 mateusz.vi 748
}
749
 
750
 
1942 mateusz.vi 751
/* displays a list of drives and asks user to choose one for installation
1944 mateusz.vi 752
 * returns a word with bits HHPPLLLLLLLL where:
753
 * HH = hard drive id (0..3)
754
 * PP = position of the partition in MBR (0..3)
755
 * LL... = drive's DOS id (A=0, B=1, C=2, ...) */
1942 mateusz.vi 756
static int selectdrive(void) {
1935 mateusz.vi 757
  char buff[512];
1943 mateusz.vi 758
  struct drivelist drives[16];
759
  char drvlist[16][32]; /* up to 16 drives (4 partitions on 4 disks) */
760
  int i, drvlistlen;
1942 mateusz.vi 761
  const char *menulist[16];
762
  unsigned char driveid = 1; /* fdisk runs on first drive (unless USB boot) */
1935 mateusz.vi 763
 
1940 mateusz.vi 764
  /* read MBR of first HDD */
1943 mateusz.vi 765
  drvlistlen = get_drives_list(buff, drives);
1939 mateusz.vi 766
 
1942 mateusz.vi 767
  /* if no drive found - disk not partitioned? */
768
  if (drvlistlen == 0) {
769
    const char *list[4];
770
    newscreen(0);
771
    list[0] = svarlang_str(0, 3); /* Create a partition automatically */
772
    list[1] = svarlang_str(0, 4); /* Run the FDISK tool */
773
    list[2] = svarlang_str(0, 2); /* Quit to DOS */
774
    list[3] = NULL;
775
    snprintf(buff, sizeof(buff), svarlang_strid(0x0300), SVARDOS_DISK_REQ); /* "ERROR: No drive could be found. Note, that SvarDOS requires at least %d MiB of available disk space */
776
    switch (menuselect(6 + putstringwrap(4, 1, COLOR_BODY, buff), 3, list, -1)) {
777
      case 0:
778
        sprintf(buff, "FDISK /PRI:MAX %u", driveid);
779
        exec(buff);
780
        break;
781
      case 1:
782
        mdr_cout_cls(0x07);
783
        mdr_cout_locate(0, 0);
784
        sprintf(buff, "FDISK %u", driveid);
785
        exec(buff);
786
        break;
787
      case 2:
788
        return(MENUQUIT);
789
      default:
790
        return(-1);
1908 mateusz.vi 791
    }
1942 mateusz.vi 792
    /* write a temporary MBR which only skips the drive (in case BIOS would
793
     * try to boot off the not-yet-ready C: disk) */
794
    sprintf(buff, "FDISK /LOADIPL %u", driveid);
795
    exec(buff); /* writes BOOT.MBR into actual MBR */
796
    newscreen(2);
797
    putstringnls(10, 10, COLOR_BODY, 3, 1); /* "Your computer will reboot now." */
798
    putstringnls(12, 10, COLOR_BODY, 0, 5); /* "Press any key..." */
799
    mdr_dos_getkey();
800
    reboot();
801
    return(MENUQUIT);
802
  }
1908 mateusz.vi 803
 
1943 mateusz.vi 804
  /* build a menu with all drives */
805
  for (i = 0; i < drvlistlen; i++) {
1944 mateusz.vi 806
    snprintf(drvlist[i], sizeof(drvlist[0]), "%c: [%u MiB, hd%c%u]", 'A' + drives[i].dosid, drives[i].tot_size, 'a' + drives[i].hd, drives[i].partid);
1943 mateusz.vi 807
    menulist[i] = drvlist[i];
808
  }
1942 mateusz.vi 809
  menulist[i++] = svarlang_str(0, 2); /* Quit to DOS */
810
  menulist[i] = NULL;
1943 mateusz.vi 811
 
1942 mateusz.vi 812
  newscreen(0);
813
  i = menuselect(6 /*ypos*/, i /*height*/, menulist, -1);
814
  if (i < 0) {
815
    return(MENUPREV);
816
  } else if (i < drvlistlen) {
1944 mateusz.vi 817
    /* return a bitfield HHPPLLLLLLLL
818
     * HH = hard drive id (0..3)
819
     * PP = position of the partition in MBR (0..3)
820
     * LL... = drive's DOS id (A=0, B=1, C=2, ...) */
821
    return((drives[i].partid << 8) | (drives[i].hd << 10) | drives[i].dosid);
1942 mateusz.vi 822
  }
1935 mateusz.vi 823
 
1942 mateusz.vi 824
  return(MENUQUIT);
825
}
1935 mateusz.vi 826
 
1944 mateusz.vi 827
/* hd_drv is a bitfield HHPPLLLLLLLL
828
 * HH = hard drive id (0..3)
829
 * PP = position of the partition in MBR (0..3)
830
 * LL... = drive's DOS id (A=0, B=1, C=2, ...) */
1942 mateusz.vi 831
static int preparedrive(int hd_drv) {
832
  unsigned char selecteddrive;
1944 mateusz.vi 833
  unsigned char driveid, partid;
1942 mateusz.vi 834
  char cselecteddrive;
835
  int choice;
836
  char buff[512];
556 mateuszvis 837
 
1942 mateusz.vi 838
  /* decode hd and drive id from hd_drv */
1944 mateusz.vi 839
  selecteddrive = hd_drv & 0xff; /* DOS drive letter (A=0. B=1, C=2 etc) */
840
  partid = (hd_drv >> 8) & 3;    /* position of partition in MBR (0..3) */
841
  driveid = (hd_drv >> 10);      /* HDD identifier (0..3) */
556 mateuszvis 842
 
1944 mateusz.vi 843
  cselecteddrive = 'A' + selecteddrive;
1935 mateusz.vi 844
 
1942 mateusz.vi 845
  TRY_AGAIN:
1935 mateusz.vi 846
 
1942 mateusz.vi 847
  /* if not formatted, propose to format it right away (try to create a directory) */
848
  if (test_drive_write(cselecteddrive) != 0) {
849
    const char *list[3];
79 mv_fox 850
    newscreen(0);
1942 mateusz.vi 851
    snprintf(buff, sizeof(buff), svarlang_str(3, 3), cselecteddrive); /* "ERROR: Drive %c: seems to be unformated. Do you wish to format it?") */
852
    mdr_cout_str(7, 1, buff, COLOR_BODY, 80);
556 mateuszvis 853
 
1942 mateusz.vi 854
    snprintf(buff, sizeof(buff), svarlang_strid(0x0007), cselecteddrive); /* "Format drive %c:" */
855
    list[0] = buff;
856
    list[1] = svarlang_strid(0x0002); /* "Quit to DOS" */
857
    list[2] = NULL;
556 mateuszvis 858
 
1942 mateusz.vi 859
    choice = menuselect(12, 2, list, -1);
860
    if (choice < 0) return(MENUPREV);
861
    if (choice == 1) return(MENUQUIT);
862
    mdr_cout_cls(0x07);
863
    mdr_cout_locate(0, 0);
864
    snprintf(buff, sizeof(buff), "FORMAT %c: /Q /U /Z:seriously /V:SVARDOS", cselecteddrive);
865
    exec(buff);
866
    goto TRY_AGAIN;
28 mv_fox 867
  }
1942 mateusz.vi 868
 
869
  /* check total disk space */
1944 mateusz.vi 870
  if (disksize(selecteddrive+1) < SVARDOS_DISK_REQ) {
1942 mateusz.vi 871
    int y = 9;
872
    newscreen(2);
873
    snprintf(buff, sizeof(buff), svarlang_strid(0x0304), cselecteddrive, SVARDOS_DISK_REQ); /* "ERROR: Drive %c: is not big enough! SvarDOS requires a disk of at least %d MiB." */
874
    y += putstringwrap(y, 1, COLOR_BODY, buff);
875
    putstringnls(++y, 1, COLOR_BODY, 0, 5); /* "Press any key..." */
876
    mdr_dos_getkey();
877
    return(MENUPREV);
878
  }
879
 
880
  /* is the disk empty? */
881
  newscreen(0);
882
  if (diskempty(cselecteddrive) != 0) {
883
    const char *list[3];
884
    int y = 6;
885
    snprintf(buff, sizeof(buff), svarlang_strid(0x0305), cselecteddrive); /* "ERROR: Drive %c: not empty" */
886
    y += putstringwrap(y, 1, COLOR_BODY, buff);
887
 
888
    snprintf(buff, sizeof(buff), svarlang_strid(0x0007), cselecteddrive); /* "Format drive %c:" */
889
    list[0] = buff;
890
    list[1] = svarlang_strid(0x0002); /* "Quit to DOS" */
891
    list[2] = NULL;
892
 
893
    choice = menuselect(++y, 2, list, -1);
894
    if (choice < 0) return(MENUPREV);
895
    if (choice == 1) return(MENUQUIT);
896
    mdr_cout_cls(0x07);
897
    mdr_cout_locate(0, 0);
898
    snprintf(buff, sizeof(buff), "FORMAT %c: /Q /U /Z:seriously /V:SVARDOS", cselecteddrive);
899
    exec(buff);
900
    goto TRY_AGAIN;
901
  } else {
902
    /* final confirmation */
903
    const char *list[3];
904
    list[0] = svarlang_strid(0x0001); /* Install SvarDOS */
905
    list[1] = svarlang_strid(0x0002); /* Quit to DOS */
906
    list[2] = NULL;
907
    snprintf(buff, sizeof(buff), svarlang_strid(0x0306), cselecteddrive); /* "The installation of SvarDOS to %c: is about to begin." */
908
    mdr_cout_str(7, 40 - (strlen(buff) / 2), buff, COLOR_BODY, 80);
909
    choice = menuselect(10, 2, list, -1);
910
    if (choice < 0) return(MENUPREV);
911
    if (choice == 1) return(MENUQUIT);
1944 mateusz.vi 912
 
913
    /* update the disk's MBR, transfer the boot system, make sure the partition
914
     * is ACTIVE and create a TEMP directory to copy SVP files over */
1942 mateusz.vi 915
    snprintf(buff, sizeof(buff), "SYS %c: > NUL", cselecteddrive);
916
    exec(buff);
1944 mateusz.vi 917
    sprintf(buff, "FDISK /MBR %u", driveid + 1);
1942 mateusz.vi 918
    exec(buff);
1944 mateusz.vi 919
 
920
    if (READ_OR_WRITE_MBR(MBR_READ, buff, driveid | 0x80) == 0) {
921
      /* active flags for part 0,1,2,3 are at offsets 0x01BE, 0x01CE, 0x01DE, 0x01EE */
922
      unsigned char i, flag_before, changed = 0;
923
      unsigned short memoffset = 0x01BE; /* first partition flag is here */
924
      for (i = 0; i < 4; i++) {
925
        flag_before = buff[memoffset];
926
        buff[memoffset] &= 127;
927
        if (i == partid) buff[memoffset] |= 0x80;
928
        if (flag_before != buff[memoffset]) changed++;
929
        memoffset += 16; /* jump to next partition entry */
930
      }
931
      /* do I need to update the MBR? */
932
      if (changed != 0) READ_OR_WRITE_MBR(MBR_WRITE, buff, driveid | 0x80);
933
    }
934
 
935
    snprintf(buff, sizeof(buff), "%c:\\TEMP", cselecteddrive);
1942 mateusz.vi 936
    mkdir(buff);
937
    return(0);
938
  }
28 mv_fox 939
}
940
 
941
 
280 mateuszvis 942
/* generates locales-related configurations and writes them to file (this
943
 * is used to compute autoexec.bat content) */
944
static void genlocalesconf(FILE *fd, const struct slocales *locales) {
945
  if (locales == NULL) return;
946
 
947
  fprintf(fd, "SET LANG=%s\r\n", locales->lang);
948
 
949
  if (locales->egafile > 0) {
950
    fprintf(fd, "DISPLAY CON=(EGA,,1)\r\n");
951
    if (locales->egafile == 1) {
952
      fprintf(fd, "MODE CON CP PREPARE=((%u) %%DOSDIR%%\\CPI\\EGA.CPX)\r\n", locales->codepage);
953
    } else {
1908 mateusz.vi 954
      fprintf(fd, "MODE CON CP PREPARE=((%u) %%DOSDIR%%\\CPI\\EGA%u.CPX)\r\n", locales->codepage, locales->egafile);
280 mateuszvis 955
    }
956
    fprintf(fd, "MODE CON CP SELECT=%u\r\n", locales->codepage);
957
  }
958
 
959
  if (locales->keybfile > 0) {
1659 bttr 960
    fprintf(fd, "KEYB %s,%d,%%DOSDIR%%\\", locales->keybcode, locales->codepage);
280 mateuszvis 961
    if (locales->keybfile == 1) {
962
      fprintf(fd, "KEYBOARD.SYS");
963
    } else {
1908 mateusz.vi 964
      fprintf(fd, "KEYBRD%u.SYS", locales->keybfile);
280 mateuszvis 965
    }
966
    if (locales->keybid != 0) fprintf(fd, " /ID:%d", locales->keybid);
967
    fprintf(fd, "\r\n");
968
  }
969
}
970
 
971
 
1930 mateusz.vi 972
/* generates configuration files on the dest drive, this is run once system booted successfully */
973
static void bootfilesgen(const struct slocales *locales) {
28 mv_fox 974
  char buff[128];
975
  FILE *fd;
1930 mateusz.vi 976
  unsigned char bootdrv = GETDOSBOOTDRIVE();
977
 
978
  /****************
979
   * CONFIG.SYS ***
980
   ****************/
981
  snprintf(buff, sizeof(buff), "%c:\\TEMP\\CONFIG.SYS", bootdrv);
53 mv_fox 982
  fd = fopen(buff, "wb");
983
  if (fd == NULL) return;
1751 mateusz.vi 984
  fprintf(fd, "; SvarDOS kernel configuration\r\n"
985
              "\r\n"
986
              "; highest allowed drive letter\r\n"
987
              "LASTDRIVE=Z\r\n"
988
              "\r\n"
989
              "; max. number of files that programs are allowed to open simultaneously\r\n"
990
              "FILES=25\r\n");
991
  fprintf(fd, "\r\n"
992
              "; XMS memory driver\r\n"
1930 mateusz.vi 993
              "DEVICE=%c:\\SVARDOS\\HIMEMX.EXE\r\n", bootdrv);
1751 mateusz.vi 994
  fprintf(fd, "\r\n"
995
              "; try moving DOS to upper memory, then to high memory\r\n"
996
              "DOS=UMB,HIGH\r\n");
997
  fprintf(fd, "\r\n"
1930 mateusz.vi 998
              "; command interpreter (shell) location and environment size\r\n"
999
              "SHELL=%c:\\COMMAND.COM /E:512 /P\r\n", bootdrv);
1751 mateusz.vi 1000
  fprintf(fd, "\r\n"
1908 mateusz.vi 1001
              "; NLS configuration\r\n");
1002
  if (locales != NULL) {
1930 mateusz.vi 1003
    fprintf(fd, "COUNTRY=%03u,%u,%c:\\SVARDOS\\COUNTRY.SYS\r\n", locales->countryid, locales->codepage, bootdrv);
1908 mateusz.vi 1004
  } else {
1930 mateusz.vi 1005
    fprintf(fd, "COUNTRY=001,437,%c:\\SVARDOS\\COUNTRY.SYS\r\n", bootdrv);
1908 mateusz.vi 1006
  }
1751 mateusz.vi 1007
  fprintf(fd, "\r\n"
1008
              "; CD-ROM driver initialization\r\n"
1930 mateusz.vi 1009
              ";DEVICE=%c:\\DRIVERS\\VIDECDD\\VIDE-CDD.SYS /D:SVCD0001\r\n", bootdrv);
53 mv_fox 1010
  fclose(fd);
1930 mateusz.vi 1011
 
1012
  /****************
1013
   * AUTOEXEC.BAT *
1014
   ****************/
1015
  snprintf(buff, sizeof(buff), "%c:\\TEMP\\AUTOEXEC.BAT", bootdrv);
28 mv_fox 1016
  fd = fopen(buff, "wb");
1930 mateusz.vi 1017
  if (fd == NULL) {
1018
    return;
1019
  } else {
1020
    char *autoexec_bat1 =
1021
      "@ECHO OFF\r\n"
1935 mateusz.vi 1022
      "SET TEMP=#:\\TEMP\r\n"
1023
      "SET DOSDIR=#:\\SVARDOS\r\n"
1930 mateusz.vi 1024
      "SET NLSPATH=%DOSDIR%\\NLS\r\n"
1025
      "SET DIRCMD=/O/P\r\n"
1026
      "SET WATTCP.CFG=%DOSDIR%\\CFG\r\n"
1027
      "PATH %DOSDIR%\r\n"
1028
      "PROMPT $P$G\r\n"
1029
      "\r\n"
1030
      "REM enable CPU power saving\r\n"
1031
      "FDAPM ADV:REG\r\n"
1032
      "\r\n";
1033
    char *autoexec_bat2 =
1034
      "REM Uncomment the line below for CDROM support\r\n"
1035
      "REM SHSUCDX /d:SVCD0001\r\n"
1036
      "\r\n"
1037
      "ECHO.\r\n";
1038
 
1935 mateusz.vi 1039
    /* replace all '#' occurences by bootdrive */
1040
    strtr(autoexec_bat1, '#', bootdrv);
1930 mateusz.vi 1041
 
1042
    /* write all to file */
1043
    fputs(autoexec_bat1, fd);
1044
    if (locales != NULL) genlocalesconf(fd, locales);
1045
    fputs(autoexec_bat2, fd);
1046
 
1047
    fprintf(fd, "ECHO %s\r\n", svarlang_strid(0x0600)); /* "Welcome to SvarDOS!" */
1048
    fclose(fd);
1049
  }
1050
 
200 mateuszvis 1051
  /*** CREATE DIRECTORY FOR CONFIGURATION FILES ***/
1930 mateusz.vi 1052
  snprintf(buff, sizeof(buff), "%c:\\SVARDOS", bootdrv);
200 mateuszvis 1053
  mkdir(buff);
1930 mateusz.vi 1054
 
1055
  /****************
1056
   * PKG.CFG      *
1057
   ****************/
1935 mateusz.vi 1058
  snprintf(buff, sizeof(buff), "%c:\\SVARDOS\\PKG.CFG", bootdrv);
277 mateuszvis 1059
  fd = fopen(buff, "wb");
1930 mateusz.vi 1060
  if (fd == NULL) {
1061
    return;
1062
  } else {
1063
    char *pkg_cfg =
1064
      "# pkg config file - specifies locations where packages should be installed\r\n"
1065
      "\r\n"
1066
      "# System boot drive\r\n"
1935 mateusz.vi 1067
      "BOOTDRIVE @\r\n"
1930 mateusz.vi 1068
      "\r\n"
1069
      "# DOS core binaries\r\n"
1070
      "DIR BIN @:\\SVARDOS\r\n"
1071
      "\r\n"
1072
      "# Programs\r\n"
1073
      "DIR PROGS @:\\\r\n"
1074
      "\r\n"
1075
      "# Games \r\n"
1076
      "DIR GAMES @:\\\r\n"
1077
      "\r\n"
1078
      "# Drivers\r\n"
1079
      "DIR DRIVERS @:\\DRIVERS\r\n"
1080
      "\r\n"
1081
      "# Development tools\r\n"
1082
      "DIR DEVEL @:\\DEVEL\r\n";
1083
 
1084
    /* replace all @ by the actual boot drive */
1085
    strtr(pkg_cfg, '@', bootdrv);
1086
 
1087
    /* write to file */
1088
    fputs(pkg_cfg, fd);
1089
    fclose(fd);
1090
  }
1091
 
53 mv_fox 1092
  /*** PICOTCP ***/
1930 mateusz.vi 1093
  /* TODO (or not? maybe not that useful) */
1094
 
53 mv_fox 1095
  /*** WATTCP ***/
1930 mateusz.vi 1096
  snprintf(buff, sizeof(buff), "%c:\\SVARDOS\\CFG\\WATTCP.CFG", bootdrv);
303 mateuszvis 1097
  fd = fopen(buff, "wb");
1098
  if (fd == NULL) return;
1099
  fprintf(fd, "my_ip = dhcp\r\n"
1100
              "#my_ip = 192.168.0.7\r\n"
1101
              "#netmask = 255.255.255.0\r\n"
1102
              "#nameserver = 192.168.0.1\r\n"
1103
              "#nameserver = 192.168.0.2\r\n"
554 mateuszvis 1104
              "#gateway = 192.168.0.1\r\n");
303 mateuszvis 1105
  fclose(fd);
28 mv_fox 1106
}
1107
 
1108
 
1942 mateusz.vi 1109
static int copypackages(char drvletter, const struct slocales *locales) {
192 mateuszvis 1110
  char pkglist[512];
30 mv_fox 1111
  int i, pkglistlen;
192 mateuszvis 1112
  size_t pkglistflen;
280 mateuszvis 1113
  char buff[1024]; /* must be *at least* 1 sector big for efficient file copying */
1114
  FILE *fd = NULL;
192 mateuszvis 1115
  char *pkgptr;
1942 mateusz.vi 1116
 
79 mv_fox 1117
  newscreen(3);
1942 mateusz.vi 1118
 
192 mateuszvis 1119
  /* load pkg list */
1120
  fd = fopen("install.lst", "rb");
1121
  if (fd == NULL) {
1664 mateusz.vi 1122
    mdr_cout_str(10, 30, "ERROR: INSTALL.LST NOT FOUND", COLOR_BODY, 80);
1661 mateusz.vi 1123
    mdr_dos_getkey();
192 mateuszvis 1124
    return(-1);
1125
  }
1125 mateusz.vi 1126
  pkglistflen = fread(pkglist, 1, sizeof(pkglist) - 2, fd);
192 mateuszvis 1127
  fclose(fd);
1125 mateusz.vi 1128
  if (pkglistflen == sizeof(pkglist) - 2) {
1664 mateusz.vi 1129
    mdr_cout_str(10, 30, "ERROR: INSTALL.LST TOO LARGE", COLOR_BODY, 80);
1661 mateusz.vi 1130
    mdr_dos_getkey();
192 mateuszvis 1131
    return(-1);
1132
  }
1125 mateusz.vi 1133
  /* mark the end of list */
1134
  pkglist[pkglistflen] = 0;
1135
  pkglist[pkglistflen + 1] = 0xff;
192 mateuszvis 1136
  /* replace all \r and \n chars by 0 bytes, and count the number of packages */
1137
  pkglistlen = 0;
1138
  for (i = 0; i < pkglistflen; i++) {
1139
    switch (pkglist[i]) {
1140
      case '\n':
1141
        pkglistlen++;
1142
        /* FALLTHRU */
1143
      case '\r':
1144
        pkglist[i] = 0;
1145
        break;
1146
    }
1147
  }
280 mateuszvis 1148
 
1930 mateusz.vi 1149
  /* copy pkg.exe, install.com and install.lng to the new drive, along with all packages */
1942 mateusz.vi 1150
  snprintf(buff, sizeof(buff), "%c:\\TEMP\\PKG.EXE", drvletter);
1930 mateusz.vi 1151
  fcopy(buff, buff + 8, buff, sizeof(buff));
1942 mateusz.vi 1152
  snprintf(buff, sizeof(buff), "%c:\\TEMP\\INSTALL.COM", drvletter);
1930 mateusz.vi 1153
  fcopy(buff, buff + 8, buff, sizeof(buff));
1942 mateusz.vi 1154
  snprintf(buff, sizeof(buff), "%c:\\TEMP\\INSTALL.LNG", drvletter);
1930 mateusz.vi 1155
  fcopy(buff, buff + 8, buff, sizeof(buff));
1156
 
280 mateuszvis 1157
  /* copy packages */
192 mateuszvis 1158
  for (i = 0;; i++) {
1125 mateusz.vi 1159
    RETRY_ENTIRE_LIST:
1160
 
192 mateuszvis 1161
    /* move forward to nearest entry or end of list */
1125 mateusz.vi 1162
    for (pkgptr = pkglist; *pkgptr == 0; pkgptr++);
1163
    if (*pkgptr == 0xff) break; /* end of list: means all packages have been processed */
1164
 
1165
    /* is this package present on the floppy disk? */
1166
    TRY_NEXTPKG:
1167
    sprintf(buff, "%s.svp", pkgptr);
1669 mateusz.vi 1168
    if (!fileexists(buff)) {
1125 mateusz.vi 1169
      while (*pkgptr != 0) pkgptr++;
1170
      while (*pkgptr == 0) pkgptr++;
1171
      /* end of list? ask for next floppy, there's nothing interesting left on this one */
1172
      if (*pkgptr == 0xff) {
1664 mateusz.vi 1173
        putstringnls(12, 1, COLOR_BODY, 4, 1); /* "INSERT THE DISK THAT CONTAINS THE REQUIRED FILE AND PRESS ANY KEY" */
1661 mateusz.vi 1174
        mdr_dos_getkey();
1664 mateusz.vi 1175
        video_putstringfix(12, 1, COLOR_BODY, "", 80); /* erase the 'insert disk' message */
1125 mateusz.vi 1176
        goto RETRY_ENTIRE_LIST;
1177
      }
1178
      goto TRY_NEXTPKG;
1179
    }
1180
 
192 mateuszvis 1181
    /* install the package */
624 mateuszvis 1182
    snprintf(buff, sizeof(buff), svarlang_strid(0x0400), i+1, pkglistlen, pkgptr); /* "Installing package %d/%d: %s" */
36 mv_fox 1183
    strcat(buff, "       ");
1664 mateusz.vi 1184
    mdr_cout_str(10, 1, buff, COLOR_BODY, 40);
1125 mateusz.vi 1185
 
1186
    /* proceed with package copy */
1942 mateusz.vi 1187
    sprintf(buff, "%c:\\TEMP\\%s.svp", drvletter, pkgptr);
1930 mateusz.vi 1188
    if (fcopy(buff, buff + 8, buff, sizeof(buff)) != 0) {
1664 mateusz.vi 1189
      mdr_cout_str(10, 30, "READ ERROR", COLOR_BODY, 80);
1661 mateusz.vi 1190
      mdr_dos_getkey();
192 mateuszvis 1191
      return(-1);
55 mv_fox 1192
    }
1125 mateusz.vi 1193
    /* jump to next entry or end of list and zero out the pkg name in the process */
1194
    while ((*pkgptr != 0) && (*pkgptr != 0xff)) {
1195
      *pkgptr = 0;
1196
      pkgptr++;
1197
    }
28 mv_fox 1198
  }
1934 mateusz.vi 1199
 
1200
  /* open the post-install autoexec.bat and prepare initial instructions */
1942 mateusz.vi 1201
  snprintf(buff, sizeof(buff), "%c:\\TEMP\\POSTINST.BAT", drvletter);
1934 mateusz.vi 1202
  fd = fopen(buff, "wb");
1203
  if (fd == NULL) return(-1);
1204
  fputs(
1205
    "@ECHO OFF\r\n"
1206
    "INSTALL\r\n"  /* installer will run in 2nd stage (generating pkg.cfg and stuff) */
1207
    "ECHO INSTALLING SVARDOS\r\n"
1208
    "COPY \\COMMAND.COM \\CMD.COM\r\n" /* move COMMAND.COM so it does not clashes with the installation of the SVARCOM package */
1209
    "SET COMSPEC=\\CMD.COM\r\n" /* no drive letter because I do not know it */
1210
    "DEL \\COMMAND.COM\r\n"
1211
    "DEL \\KERNEL.SYS\r\n" /* KERNEL.SYS will be installed from the package in a moment */
1212
    "FOR %%P IN (*.SVP) DO PKG INSTALL %%P\r\n" /* install packages */
1213
    "DEL *.SVP\r\n", fd);
1214
 
280 mateuszvis 1215
  /* replace autoexec.bat and config.sys now and write some nice message on screen */
1216
  fprintf(fd, "DEL pkg.exe\r\n"
1930 mateusz.vi 1217
              "DEL install.com\r\n"
1934 mateusz.vi 1218
              "DEL install.lng\r\n"
1930 mateusz.vi 1219
              "COPY CONFIG.SYS \\\r\n"
280 mateuszvis 1220
              "DEL CONFIG.SYS\r\n"
1930 mateusz.vi 1221
              "DEL \\AUTOEXEC.BAT\r\n"
1222
              "COPY AUTOEXEC.BAT \\\r\n"
1104 mateusz.vi 1223
              "DEL AUTOEXEC.BAT\r\n"
1930 mateusz.vi 1224
              "SET COMSPEC=\\COMMAND.COM\r\n"
1104 mateusz.vi 1225
              "DEL \\CMD.COM\r\n");
280 mateuszvis 1226
  /* print out the "installation over" message */
1227
  fprintf(fd, "ECHO.\r\n"
868 mateusz.vi 1228
              "ECHO ");
1673 mateusz.vi 1229
  fprintf(fd, svarlang_strid(0x0502), BUILDSTRING); /* "SvarDOS installation is over. Please restart your computer now" */
868 mateusz.vi 1230
  fprintf(fd, "\r\n"
1231
              "ECHO.\r\n");
280 mateuszvis 1232
  fclose(fd);
1233
 
1234
  /* prepare a dummy autoexec.bat that will call temp\postinst.bat */
1942 mateusz.vi 1235
  snprintf(buff, sizeof(buff), "%c:\\autoexec.bat", drvletter);
280 mateuszvis 1236
  fd = fopen(buff, "wb");
1237
  if (fd == NULL) return(-1);
1238
  fprintf(fd, "@ECHO OFF\r\n"
1930 mateusz.vi 1239
              "SET DOSDIR=\\SVARDOS\r\n"
1659 bttr 1240
              "PATH %%DOSDIR%%\r\n");
1930 mateusz.vi 1241
  genlocalesconf(fd, locales);
280 mateuszvis 1242
  fprintf(fd, "CD TEMP\r\n"
1243
              "postinst.bat\r\n");
1244
  fclose(fd);
1245
 
192 mateuszvis 1246
  return(0);
28 mv_fox 1247
}
1248
 
1249
 
42 mv_fox 1250
static void finalreboot(void) {
56 mv_fox 1251
  int y = 9;
79 mv_fox 1252
  newscreen(2);
1673 mateusz.vi 1253
  y += putstringnls(y, 1, COLOR_BODY, 5, 0); /* "Your computer will reboot now." */
1254
  y += putstringnls(y, 1, COLOR_BODYWARN, 5, 1); /* Please remove the installation disk from your drive" */
1664 mateusz.vi 1255
  putstringnls(++y, 1, COLOR_BODY, 0, 5); /* "Press any key..." */
1661 mateusz.vi 1256
  mdr_dos_getkey();
42 mv_fox 1257
  reboot();
1258
}
1259
 
1260
 
192 mateuszvis 1261
static void loadcp(const struct slocales *locales) {
42 mv_fox 1262
  char buff[64];
67 mv_fox 1263
  if (locales->codepage == 437) return;
1662 mateusz.vi 1264
  mdr_cout_locate(1, 0);
67 mv_fox 1265
  if (locales->egafile == 1) {
310 mateuszvis 1266
    snprintf(buff, sizeof(buff), "MODE CON CP PREP=((%u) EGA.CPX) > NUL", locales->codepage);
42 mv_fox 1267
  } else {
310 mateuszvis 1268
    snprintf(buff, sizeof(buff), "MODE CON CP PREP=((%u) EGA%d.CPX) > NUL", locales->codepage, locales->egafile);
42 mv_fox 1269
  }
1918 mateusz.vi 1270
  exec(buff);
67 mv_fox 1271
  snprintf(buff, sizeof(buff), "MODE CON CP SEL=%u > NUL", locales->codepage);
1918 mateusz.vi 1272
  exec(buff);
42 mv_fox 1273
  /* below I re-init the video controller - apparently this is required if
65 mv_fox 1274
   * I want the new glyph symbols to be actually applied, at least some
1275
   * (broken?) BIOSes, like VBox, apply glyphs only at next video mode change */
1908 mateusz.vi 1276
  _asm {
1277
    push bx
1278
    mov ah, 0x0F  /* get current video mode */
1279
    int 0x10      /* al contains the current video mode now */
1280
    or al, 128    /* set high bit of AL to instruct BIOS not to flush VRAM's content (EGA+) */
1281
    xor ah, ah    /* re-set video mode (to whatever is set in AL) */
1282
    int 0x10
1283
    pop bx
42 mv_fox 1284
  }
1285
}
1286
 
200 mateuszvis 1287
 
1671 mateusz.vi 1288
int main(void) {
1908 mateusz.vi 1289
  struct slocales locales_data;
1290
  struct slocales *locales = &locales_data;
28 mv_fox 1291
  int targetdrv;
73 mv_fox 1292
  int action;
28 mv_fox 1293
 
1911 mateusz.vi 1294
  /* setup an internal int 24h handler ("always fail") so DOS does not output
1295
   * the ugly "abort, retry, fail" messages */
1918 mateusz.vi 1296
  install_int24();
908 mateusz.vi 1297
 
1930 mateusz.vi 1298
  /* init screen and detect mono adapters */
1299
  if (mdr_cout_init(NULL, NULL) == 0) {
1300
    /* overload color scheme with mono settings */
1301
    COLOR_TITLEBAR = 0x70;
1302
    COLOR_TITLEVER = 0x70;
1303
    COLOR_BODY = 0x07;
1304
    COLOR_BODYWARN = 0x07;
1305
    COLOR_SELECT = 0x70;
1306
    COLOR_SELECTCUR = 0x07;
1307
  }
1308
 
1309
  /* is it stage 2 of the installation? */
1310
  if (fileexists("postinst.bat")) goto GENCONF;
1311
 
1671 mateusz.vi 1312
  /* read the svardos build revision (from floppy label) */
1313
  {
1314
    const char *fspec = "*.*";
1315
    const char *res = (void*)0x9E; /* default DTA is at PSP:80h, field 1Eh of DTA is the ASCIZ file name */
868 mateusz.vi 1316
 
1671 mateusz.vi 1317
    _asm {
1318
      push cx
1319
      push dx
1320
 
1321
      mov ax, 0x4e00  /* findfirst */
1322
      mov cx, 0x08    /* file attr mask, 0x08 = volume label */
1323
      mov dx, fspec
1324
      int 0x21
1325
      jnc good
1672 mateusz.vi 1326
      mov bx, res
1327
      mov [bx], byte ptr 0
1671 mateusz.vi 1328
      good:
1329
 
1330
      pop dx
1331
      pop cx
1332
    }
1333
 
1334
    memcpy(BUILDSTRING, res, 12);
1335
  }
1336
 
1908 mateusz.vi 1337
  /* am I EN-only? */
1338
  if (!fileexists("INSTALL.LNG")) locales = NULL;
1339
 
73 mv_fox 1340
 SelectLang:
1908 mateusz.vi 1341
  if (locales == NULL) goto WelcomeScreen;
1342
  action = selectlang(locales); /* welcome to svardos, select your language */
1930 mateusz.vi 1343
  if (action != MENUNEXT) goto QUIT;
1908 mateusz.vi 1344
  loadcp(locales);
1345
  svarlang_load("INSTALL.LNG", locales->lang); /* NLS support */
865 mateusz.vi 1346
 
1908 mateusz.vi 1347
  action = selectkeyb(locales);  /* what keyb layout should we use? */
1930 mateusz.vi 1348
  if (action == MENUQUIT) goto QUIT;
1908 mateusz.vi 1349
  if (action == MENUPREV) goto SelectLang;
73 mv_fox 1350
 
1351
 WelcomeScreen:
190 mateuszvis 1352
  action = welcomescreen(); /* what svardos is, ask whether to run live dos or install */
1930 mateusz.vi 1353
  if (action == MENUQUIT) goto QUIT;
1908 mateusz.vi 1354
  if (action == MENUPREV) {
1930 mateusz.vi 1355
    if (locales == NULL) goto QUIT;
1908 mateusz.vi 1356
    goto SelectLang;
1357
  }
1669 mateusz.vi 1358
 
1942 mateusz.vi 1359
 SelDriveScreen:
1360
  targetdrv = selectdrive();
1930 mateusz.vi 1361
  if (targetdrv == MENUQUIT) goto QUIT;
73 mv_fox 1362
  if (targetdrv == MENUPREV) goto WelcomeScreen;
1942 mateusz.vi 1363
 
1364
  action = preparedrive(targetdrv); /* what drive should we install to? check avail. space */
1365
  if (action == MENUQUIT) goto QUIT;
1366
  if (action == MENUPREV) goto SelDriveScreen;
1944 mateusz.vi 1367
  targetdrv = (targetdrv & 0xff) + 'A'; /* convert the part+hd+drv value to a DOS letter */
1942 mateusz.vi 1368
 
1369
  /* copy packages to dst drive */
1370
  if (copypackages(targetdrv, locales) != 0) goto QUIT;
1930 mateusz.vi 1371
  finalreboot(); /* remove the install medium and reboot */
73 mv_fox 1372
 
1930 mateusz.vi 1373
  goto QUIT;
1374
 
1375
 GENCONF: /* second stage of the installation (run from the destination disk) */
1376
  bootfilesgen(locales); /* generate boot files and other configurations */
1377
 
1378
 QUIT:
1662 mateusz.vi 1379
  mdr_cout_locate(0, 0);
1380
  mdr_cout_close();
28 mv_fox 1381
  return(0);
1382
}