Subversion Repositories SvarDOS

Rev

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

Rev Author Line No. Line
349 mateuszvis 1
/*
2
 * SvarCOM is a command-line interpreter.
3
 *
4
 * a little memory area is allocated as high as possible. it contains:
5
 *  - a signature (like XMS drivers do)
6
 *  - a routine for exec'ing programs
7
 *  - a "last command" buffer for input history
8
 *
9
 * when svarcom starts, it tries locating the routine in memory.
10
 *
11
 * if found:
12
 *   waits for user input and processes it. if execing something is required, set the "next exec" field in routine's memory and quit.
13
 *
14
 * if not found:
15
 *   installs it by creating a new PSP, set int 22 vector to the routine, set my "parent PSP" to the routine
16
 *   and quit.
17
 *
18
 *
19
 *
20
 * good lecture about PSP and allocating memory
21
 * https://retrocomputing.stackexchange.com/questions/20001/how-much-of-the-program-segment-prefix-area-can-be-reused-by-programs-with-impun/20006#20006
22
 *
23
 * PSP structure
24
 * http://www.piclist.com/techref/dos/psps.htm
25
 *
26
 *
27
 *
28
 * === MCB ===
29
 *
30
 * each time that DOS allocates memory, it prefixes the allocated memory with
31
 * a 16-bytes structure called a "Memory Control Block" (MCB). This control
32
 * block has the following structure:
33
 *
34
 * Offset  Size     Description
35
 *   00h   byte     'M' =  non-last member of the MCB chain
36
 *                  'Z' = indicates last entry in MCB chain
37
 *                  other values cause "Memory Allocation Failure" on exit
38
 *   01h   word     PSP segment address of the owner (Process Id)
39
 *                  possible values:
40
 *                    0 = free
41
 *                    8 = Allocated by DOS before first user pgm loaded
42
 *                    other = Process Id/PSP segment address of owner
43
 *   03h  word      number of paragraphs related to this MCB (excluding MCB)
44
 *   05h  11 bytes  reserved
45
 *   10h  ...       start of actual allocated memory block
46
 */
47
 
48
#include <i86.h>
49
#include <dos.h>
50
#include <stdio.h>
350 mateuszvis 51
#include <stdlib.h>
349 mateuszvis 52
#include <string.h>
53
 
54
#include <process.h>
55
 
352 mateuszvis 56
#include "cmd.h"
57
#include "helpers.h"
351 mateuszvis 58
#include "rmodinit.h"
349 mateuszvis 59
 
60
struct config {
61
  int locate;
62
  int install;
350 mateuszvis 63
  int envsiz;
349 mateuszvis 64
} cfg;
65
 
66
 
67
static void parse_argv(struct config *cfg, int argc, char **argv) {
68
  int i;
69
  memset(cfg, 0, sizeof(*cfg));
350 mateuszvis 70
 
349 mateuszvis 71
  for (i = 1; i < argc; i++) {
72
    if (strcmp(argv[i], "/locate") == 0) {
73
      cfg->locate = 1;
74
    }
350 mateuszvis 75
    if (strstartswith(argv[i], "/e:") == 0) {
76
      cfg->envsiz = atoi(argv[i]+3);
77
      if (cfg->envsiz < 64) cfg->envsiz = 0;
78
    }
349 mateuszvis 79
  }
80
}
81
 
82
 
83
static int explode_progparams(char *s, char const **argvlist) {
84
  int si = 0, argc = 0;
85
  for (;;) {
86
    /* skip to next non-space character */
87
    while (s[si] == ' ') si++;
88
    /* end of string? */
89
    if (s[si] == '\r') break;
90
    /* set argv ptr */
91
    argvlist[argc++] = s + si;
92
    /* find next space */
93
    while (s[si] != ' ' && s[si] != '\r') si++;
94
    /* is this end of string? */
95
    if (s[si] == '\r') {
96
      s[si] = 0;
97
      break;
98
    }
99
    /* not end: terminate arg and look for next one */
100
    s[si++] = 0;
101
  }
102
  /* terminate argvlist with a NULL value */
103
  argvlist[argc] = NULL;
104
  return(argc);
105
}
106
 
107
 
108
 
109
 
110
int main(int argc, char **argv) {
111
  struct config cfg;
350 mateuszvis 112
  unsigned short rmod_seg;
113
  unsigned short far *rmod_envseg;
352 mateuszvis 114
  int ecode = 0;
349 mateuszvis 115
 
116
  parse_argv(&cfg, argc, argv);
117
 
350 mateuszvis 118
  rmod_seg = rmod_find();
349 mateuszvis 119
  if (rmod_seg == 0xffff) {
350 mateuszvis 120
    rmod_seg = rmod_install(cfg.envsiz);
349 mateuszvis 121
    if (rmod_seg == 0xffff) {
350 mateuszvis 122
      puts("ERROR: rmod_install() failed");
349 mateuszvis 123
      return(1);
124
    } else {
125
      printf("rmod installed at seg 0x%04X\r\n", rmod_seg);
126
    }
127
  } else {
128
    printf("rmod found at seg 0x%04x\r\n", rmod_seg);
129
  }
130
 
350 mateuszvis 131
  rmod_envseg = MK_FP(rmod_seg, RMOD_OFFSET_ENVSEG);
132
 
133
  {
134
    unsigned short envsiz;
135
    unsigned short far *sizptr = MK_FP(*rmod_envseg - 1, 3);
136
    envsiz = *sizptr;
137
    envsiz *= 16;
138
    printf("rmod_inpbuff at %04X:%04X, env_seg at %04X:0000 (env_size = %u bytes)\r\n", rmod_seg, RMOD_OFFSET_INPBUFF, *rmod_envseg, envsiz);
349 mateuszvis 139
  }
140
 
141
  for (;;) {
142
    int i, argcount;
350 mateuszvis 143
    char far *cmdline = MK_FP(rmod_seg, RMOD_OFFSET_INPBUFF + 2);
349 mateuszvis 144
    char path[256] = "C:\\>$";
145
    char const *argvlist[256];
146
    union REGS r;
147
 
148
    /* print shell prompt */
149
    r.h.ah = 0x09;
150
    r.x.dx = FP_OFF(path);
151
    intdos(&r, &r);
152
 
153
    /* wait for user input */
154
    _asm {
155
      push ds
156
 
157
      /* is DOSKEY support present? (INT 2Fh, AX=4800h, returns non-zero in AL if present) */
158
      mov ax, 0x4800
159
      int 0x2f
160
      mov bl, al /* save doskey status in BL */
161
 
162
      /* set up buffered input */
163
      mov ax, rmod_seg
164
      push ax
165
      pop ds
350 mateuszvis 166
      mov dx, RMOD_OFFSET_INPBUFF
349 mateuszvis 167
 
168
      /* execute either DOS input or DOSKEY */
169
      test bl, bl /* zf set if no DOSKEY present */
170
      jnz DOSKEY
171
 
172
      mov ah, 0x0a
173
      int 0x21
174
      jmp short DONE
175
 
176
      DOSKEY:
177
      mov ax, 0x4810
178
      int 0x2f
179
 
180
      DONE:
181
      pop ds
182
    }
183
    printf("\r\n");
184
 
185
    /* if nothing entered, loop again */
186
    if (cmdline[-1] == 0) continue;
187
 
188
    /* copy buffer to a near var (incl. trailing CR) */
189
    _fmemcpy(path, cmdline, cmdline[-1] + 1);
190
 
191
    argcount = explode_progparams(path, argvlist);
192
 
193
    /* if nothing args found (eg. all-spaces), loop again */
194
    if (argcount == 0) continue;
195
 
196
    printf("got %u bytes of cmdline (%d args)\r\n", cmdline[-1], argcount);
197
    for (i = 0; i < argcount; i++) {
198
      printf("arg #%d = '%s'\r\n", i, argvlist[i]);
199
    }
200
 
352 mateuszvis 201
    /* is it about quitting? */
202
    if (imatch(argvlist[0], "exit")) break;
349 mateuszvis 203
 
352 mateuszvis 204
    /* try running it as an internal command */
205
    ecode = cmd_process(argcount, argvlist, *rmod_envseg);
206
    if (ecode >= 0) continue;
207
 
208
    /* must be an external command then */
349 mateuszvis 209
    execvp(argvlist[0], argvlist);
210
 
211
    /* execvp() replaces the current process by the new one
212
    if I am still alive then external command failed to execute */
213
    puts("Bad command or file name");
214
 
215
  }
216
 
217
  return(0);
218
}