Subversion Repositories SvarDOS

Rev

Rev 351 | Rev 353 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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