Subversion Repositories SvarDOS

Rev

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

Rev 377 Rev 397
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"
56
#include "cmd.h"
57
#include "env.h"
57
#include "env.h"
58
#include "helpers.h"
58
#include "helpers.h"
59
#include "rmodinit.h"
59
#include "rmodinit.h"
60
 
60
 
61
struct config {
61
struct config {
62
  int locate;
62
  int locate;
63
  int install;
63
  int install;
64
  int envsiz;
64
  int envsiz;
65
} cfg;
65
} cfg;
66
 
66
 
67
 
67
 
68
static void parse_argv(struct config *cfg, int argc, char **argv) {
68
static void parse_argv(struct config *cfg, int argc, char **argv) {
69
  int i;
69
  int i;
70
  memset(cfg, 0, sizeof(*cfg));
70
  memset(cfg, 0, sizeof(*cfg));
71
 
71
 
72
  for (i = 1; i < argc; i++) {
72
  for (i = 1; i < argc; i++) {
73
    if (strcmp(argv[i], "/locate") == 0) {
73
    if (strcmp(argv[i], "/locate") == 0) {
74
      cfg->locate = 1;
74
      cfg->locate = 1;
75
    }
75
    }
76
    if (strstartswith(argv[i], "/e:") == 0) {
76
    if (strstartswith(argv[i], "/e:") == 0) {
77
      cfg->envsiz = atoi(argv[i]+3);
77
      cfg->envsiz = atoi(argv[i]+3);
78
      if (cfg->envsiz < 64) cfg->envsiz = 0;
78
      if (cfg->envsiz < 64) cfg->envsiz = 0;
79
    }
79
    }
80
  }
80
  }
81
}
81
}
82
 
82
 
83
 
83
 
84
static void buildprompt(char *s, unsigned short envseg) {
84
static void buildprompt(char *s, unsigned short envseg) {
85
  /* locate the prompt variable or use the default pattern */
85
  /* locate the prompt variable or use the default pattern */
86
  const char far *fmt = env_lookup(envseg, "PROMPT");
86
  const char far *fmt = env_lookup(envseg, "PROMPT");
87
  while ((fmt != NULL) && (*fmt != 0)) {
87
  while ((fmt != NULL) && (*fmt != 0)) {
88
    fmt++;
88
    fmt++;
89
    if (fmt[-1] == '=') break;
89
    if (fmt[-1] == '=') break;
90
  }
90
  }
91
  if ((fmt == NULL) || (*fmt == 0)) fmt = "$p$g"; /* fallback to default if empty */
91
  if ((fmt == NULL) || (*fmt == 0)) fmt = "$p$g"; /* fallback to default if empty */
92
  /* build the prompt string based on pattern */
92
  /* build the prompt string based on pattern */
93
  for (; *fmt != 0; fmt++) {
93
  for (; *fmt != 0; fmt++) {
94
    if (*fmt != '$') {
94
    if (*fmt != '$') {
95
      *s = *fmt;
95
      *s = *fmt;
96
      s++;
96
      s++;
97
      continue;
97
      continue;
98
    }
98
    }
99
    /* escape code ($P, etc) */
99
    /* escape code ($P, etc) */
100
    fmt++;
100
    fmt++;
101
    switch (*fmt) {
101
    switch (*fmt) {
102
      case 'Q':  /* $Q = = (equal sign) */
102
      case 'Q':  /* $Q = = (equal sign) */
103
      case 'q':
103
      case 'q':
104
        *s = '=';
104
        *s = '=';
105
        s++;
105
        s++;
106
        break;
106
        break;
107
      case '$':  /* $$ = $ (dollar sign) */
107
      case '$':  /* $$ = $ (dollar sign) */
108
        *s = '$';
108
        *s = '$';
109
        s++;
109
        s++;
110
        break;
110
        break;
111
      case 'T':  /* $t = current time */
111
      case 'T':  /* $t = current time */
112
      case 't':
112
      case 't':
113
        s += sprintf(s, "00:00"); /* TODO */
113
        s += sprintf(s, "00:00"); /* TODO */
114
        break;
114
        break;
115
      case 'D':  /* $D = current date */
115
      case 'D':  /* $D = current date */
116
      case 'd':
116
      case 'd':
117
        s += sprintf(s, "1985-07-29"); /* TODO */
117
        s += sprintf(s, "1985-07-29"); /* TODO */
118
        break;
118
        break;
119
      case 'P':  /* $P = current drive and path */
119
      case 'P':  /* $P = current drive and path */
120
      case 'p':
120
      case 'p':
121
        _asm {
121
        _asm {
122
          mov ah, 0x19    /* DOS 1+ - GET CURRENT DRIVE */
122
          mov ah, 0x19    /* DOS 1+ - GET CURRENT DRIVE */
123
          int 0x21
123
          int 0x21
124
          mov bx, s
124
          mov bx, s
125
          mov [bx], al  /* AL = drive (00 = A:, 01 = B:, etc */
125
          mov [bx], al  /* AL = drive (00 = A:, 01 = B:, etc */
126
        }
126
        }
127
        *s += 'A';
127
        *s += 'A';
128
        s++;
128
        s++;
129
        *s = ':';
129
        *s = ':';
130
        s++;
130
        s++;
131
        *s = '\\';
131
        *s = '\\';
132
        s++;
132
        s++;
133
        _asm {
133
        _asm {
134
          mov ah, 0x47    /* DOS 2+ - CWD - GET CURRENT DIRECTORY */
134
          mov ah, 0x47    /* DOS 2+ - CWD - GET CURRENT DIRECTORY */
135
          xor dl,dl       /* DL = drive number (00h = default, 01h = A:, etc) */
135
          xor dl,dl       /* DL = drive number (00h = default, 01h = A:, etc) */
136
          mov si, s       /* DS:SI -> 64-byte buffer for ASCIZ pathname */
136
          mov si, s       /* DS:SI -> 64-byte buffer for ASCIZ pathname */
137
          int 0x21
137
          int 0x21
138
        }
138
        }
139
        while (*s != 0) s++; /* move ptr forward to end of pathname */
139
        while (*s != 0) s++; /* move ptr forward to end of pathname */
140
        break;
140
        break;
141
      case 'V':  /* $V = DOS version number */
141
      case 'V':  /* $V = DOS version number */
142
      case 'v':
142
      case 'v':
143
        s += sprintf(s, "VER"); /* TODO */
143
        s += sprintf(s, "VER"); /* TODO */
144
        break;
144
        break;
145
      case 'N':  /* $N = current drive */
145
      case 'N':  /* $N = current drive */
146
      case 'n':
146
      case 'n':
147
        _asm {
147
        _asm {
148
          mov ah, 0x19    /* DOS 1+ - GET CURRENT DRIVE */
148
          mov ah, 0x19    /* DOS 1+ - GET CURRENT DRIVE */
149
          int 0x21
149
          int 0x21
150
          mov bx, s
150
          mov bx, s
151
          mov [bx], al  /* AL = drive (00 = A:, 01 = B:, etc */
151
          mov [bx], al  /* AL = drive (00 = A:, 01 = B:, etc */
152
        }
152
        }
153
        *s += 'A';
153
        *s += 'A';
154
        s++;
154
        s++;
155
        break;
155
        break;
156
      case 'G':  /* $G = > (greater-than sign) */
156
      case 'G':  /* $G = > (greater-than sign) */
157
      case 'g':
157
      case 'g':
158
        *s = '>';
158
        *s = '>';
159
        s++;
159
        s++;
160
        break;
160
        break;
161
      case 'L':  /* $L = < (less-than sign) */
161
      case 'L':  /* $L = < (less-than sign) */
162
      case 'l':
162
      case 'l':
163
        *s = '<';
163
        *s = '<';
164
        s++;
164
        s++;
165
        break;
165
        break;
166
      case 'B':  /* $B = | (pipe) */
166
      case 'B':  /* $B = | (pipe) */
167
      case 'b':
167
      case 'b':
168
        *s = '|';
168
        *s = '|';
169
        s++;
169
        s++;
170
        break;
170
        break;
171
      case 'H':  /* $H = backspace (erases previous character) */
171
      case 'H':  /* $H = backspace (erases previous character) */
172
      case 'h':
172
      case 'h':
173
        *s = '\b';
173
        *s = '\b';
174
        s++;
174
        s++;
175
        break;
175
        break;
176
      case 'E':  /* $E = Escape code (ASCII 27) */
176
      case 'E':  /* $E = Escape code (ASCII 27) */
177
      case 'e':
177
      case 'e':
178
        *s = 27;
178
        *s = 27;
179
        s++;
179
        s++;
180
        break;
180
        break;
181
      case '_':  /* $_ = CR+LF */
181
      case '_':  /* $_ = CR+LF */
182
        *s = '\r';
182
        *s = '\r';
183
        s++;
183
        s++;
184
        *s = '\n';
184
        *s = '\n';
185
        s++;
185
        s++;
186
        break;
186
        break;
187
    }
187
    }
188
  }
188
  }
189
  *s = '$';
189
  *s = '$';
190
}
190
}
191
 
191
 
192
 
192
 
193
static void run_as_external(const char far *cmdline) {
193
static void run_as_external(const char far *cmdline) {
194
  char buff[256];
194
  char buff[256];
195
  char const *argvlist[256];
195
  char const *argvlist[256];
196
  int i, n;
196
  int i, n;
197
  /* copy buffer to a near var (incl. trailing CR), insert a space before
197
  /* copy buffer to a near var (incl. trailing CR), insert a space before
198
     every slash to make sure arguments are well separated */
198
     every slash to make sure arguments are well separated */
199
  n = 0;
199
  n = 0;
200
  i = 0;
200
  i = 0;
201
  for (;;) {
201
  for (;;) {
202
    if (cmdline[i] == '/') buff[n++] = ' ';
202
    if (cmdline[i] == '/') buff[n++] = ' ';
203
    buff[n++] = cmdline[i++];
203
    buff[n++] = cmdline[i++];
204
    if (buff[n] == 0) break;
204
    if (buff[n] == 0) break;
205
  }
205
  }
206
 
206
 
207
  cmd_explode(buff, cmdline, argvlist);
207
  cmd_explode(buff, cmdline, argvlist);
208
 
208
 
209
  /* for (i = 0; argvlist[i] != NULL; i++) printf("arg #%d = '%s'\r\n", i, argvlist[i]); */
209
  /* for (i = 0; argvlist[i] != NULL; i++) printf("arg #%d = '%s'\r\n", i, argvlist[i]); */
210
 
210
 
211
  /* must be an external command then. this call should never return, unless
211
  /* must be an external command then. this call should never return, unless
212
   * the other program failed to be executed. */
212
   * the other program failed to be executed. */
213
  execvp(argvlist[0], argvlist);
213
  execvp(argvlist[0], argvlist);
214
}
214
}
215
 
215
 
216
 
216
 
217
static void set_comspec_to_self(unsigned short envseg) {
217
static void set_comspec_to_self(unsigned short envseg) {
218
  unsigned short *psp_envseg = (void *)(0x2c); /* pointer to my env segment field in the PSP */
218
  unsigned short *psp_envseg = (void *)(0x2c); /* pointer to my env segment field in the PSP */
219
  char far *myenv = MK_FP(*psp_envseg, 0);
219
  char far *myenv = MK_FP(*psp_envseg, 0);
220
  unsigned short varcount;
220
  unsigned short varcount;
221
  char buff[256] = "COMSPEC=";
221
  char buff[256] = "COMSPEC=";
222
  char *buffptr = buff + 8;
222
  char *buffptr = buff + 8;
223
  /* who am i? look into my own environment, at the end of it should be my EXEPATH string */
223
  /* who am i? look into my own environment, at the end of it should be my EXEPATH string */
224
  while (*myenv != 0) {
224
  while (*myenv != 0) {
225
    /* consume a NULL-terminated string */
225
    /* consume a NULL-terminated string */
226
    while (*myenv != 0) myenv++;
226
    while (*myenv != 0) myenv++;
227
    /* move to next string */
227
    /* move to next string */
228
    myenv++;
228
    myenv++;
229
  }
229
  }
230
  /* get next word, if 1 then EXEPATH follows */
230
  /* get next word, if 1 then EXEPATH follows */
231
  myenv++;
231
  myenv++;
232
  varcount = *myenv;
232
  varcount = *myenv;
233
  myenv++;
233
  myenv++;
234
  varcount |= (*myenv << 8);
234
  varcount |= (*myenv << 8);
235
  myenv++;
235
  myenv++;
236
  if (varcount != 1) return; /* NO EXEPATH FOUND */
236
  if (varcount != 1) return; /* NO EXEPATH FOUND */
237
  while (*myenv != 0) {
237
  while (*myenv != 0) {
238
    *buffptr = *myenv;
238
    *buffptr = *myenv;
239
    buffptr++;
239
    buffptr++;
240
    myenv++;
240
    myenv++;
241
  }
241
  }
242
  *buffptr = 0;
242
  *buffptr = 0;
243
  /* printf("EXEPATH: '%s'\r\n", buff); */
243
  /* printf("EXEPATH: '%s'\r\n", buff); */
244
  env_setvar(envseg, buff);
244
  env_setvar(envseg, buff);
245
}
245
}
246
 
246
 
247
 
247
 
248
int main(int argc, char **argv) {
248
int main(int argc, char **argv) {
249
  static struct config cfg;
249
  static struct config cfg;
250
  static unsigned short rmod_seg;
250
  static unsigned short rmod_seg;
251
  static unsigned short far *rmod_envseg;
251
  static unsigned short far *rmod_envseg;
252
  static unsigned short far *lastexitcode;
252
  static unsigned short far *lastexitcode;
253
  static unsigned char BUFFER[4096];
253
  static unsigned char BUFFER[4096];
254
 
254
 
255
  parse_argv(&cfg, argc, argv);
255
  parse_argv(&cfg, argc, argv);
256
 
256
 
257
  rmod_seg = rmod_find();
257
  rmod_seg = rmod_find();
258
  if (rmod_seg == 0xffff) {
258
  if (rmod_seg == 0xffff) {
259
    rmod_seg = rmod_install(cfg.envsiz);
259
    rmod_seg = rmod_install(cfg.envsiz);
260
    if (rmod_seg == 0xffff) {
260
    if (rmod_seg == 0xffff) {
261
      outputnl("ERROR: rmod_install() failed");
261
      outputnl("ERROR: rmod_install() failed");
262
      return(1);
262
      return(1);
263
    }
263
    }
264
/*    printf("rmod installed at seg 0x%04X\r\n", rmod_seg); */
264
/*    printf("rmod installed at seg 0x%04X\r\n", rmod_seg); */
265
  } else {
265
  } else {
266
/*    printf("rmod found at seg 0x%04x\r\n", rmod_seg); */
266
/*    printf("rmod found at seg 0x%04x\r\n", rmod_seg); */
267
  }
267
  }
268
 
268
 
269
  rmod_envseg = MK_FP(rmod_seg, RMOD_OFFSET_ENVSEG);
269
  rmod_envseg = MK_FP(rmod_seg, RMOD_OFFSET_ENVSEG);
270
  lastexitcode = MK_FP(rmod_seg, RMOD_OFFSET_LEXITCODE);
270
  lastexitcode = MK_FP(rmod_seg, RMOD_OFFSET_LEXITCODE);
271
 
271
 
272
  /* make COMPSEC point to myself */
272
  /* make COMPSEC point to myself */
273
  set_comspec_to_self(*rmod_envseg);
273
  set_comspec_to_self(*rmod_envseg);
274
 
274
 
275
/*  {
275
/*  {
276
    unsigned short envsiz;
276
    unsigned short envsiz;
277
    unsigned short far *sizptr = MK_FP(*rmod_envseg - 1, 3);
277
    unsigned short far *sizptr = MK_FP(*rmod_envseg - 1, 3);
278
    envsiz = *sizptr;
278
    envsiz = *sizptr;
279
    envsiz *= 16;
279
    envsiz *= 16;
280
    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);
280
    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);
281
  }*/
281
  }*/
282
 
282
 
283
  for (;;) {
283
  for (;;) {
284
    char far *cmdline = MK_FP(rmod_seg, RMOD_OFFSET_INPBUFF + 2);
284
    char far *cmdline = MK_FP(rmod_seg, RMOD_OFFSET_INPBUFF + 2);
285
 
285
 
286
    /* revert input history terminator to \r */
286
    /* revert input history terminator to \r */
287
    if (cmdline[-1] != 0) {
287
    if (cmdline[-1] != 0) {
288
      cmdline[(unsigned short)(cmdline[-1])] = '\r';
288
      cmdline[(unsigned short)(cmdline[-1])] = '\r';
289
    }
289
    }
290
 
290
 
291
    {
291
    {
292
      /* print shell prompt */
292
      /* print shell prompt */
293
      char *promptptr = BUFFER;
293
      char *promptptr = BUFFER;
294
      buildprompt(promptptr, *rmod_envseg);
294
      buildprompt(promptptr, *rmod_envseg);
295
      _asm {
295
      _asm {
296
        push ax
296
        push ax
297
        push dx
297
        push dx
298
        mov ah, 0x09
298
        mov ah, 0x09
299
        mov dx, promptptr
299
        mov dx, promptptr
300
        int 0x21
300
        int 0x21
301
        pop dx
301
        pop dx
302
        pop ax
302
        pop ax
303
      }
303
      }
304
    }
304
    }
305
 
305
 
306
    /* wait for user input */
306
    /* wait for user input */
307
    _asm {
307
    _asm {
308
      push ax
308
      push ax
309
      push bx
309
      push bx
310
      push cx
310
      push cx
311
      push dx
311
      push dx
312
      push ds
312
      push ds
313
 
313
 
314
      /* is DOSKEY support present? (INT 2Fh, AX=4800h, returns non-zero in AL if present) */
314
      /* is DOSKEY support present? (INT 2Fh, AX=4800h, returns non-zero in AL if present) */
315
      mov ax, 0x4800
315
      mov ax, 0x4800
316
      int 0x2f
316
      int 0x2f
317
      mov bl, al /* save doskey status in BL */
317
      mov bl, al /* save doskey status in BL */
318
 
318
 
319
      /* set up buffered input */
319
      /* set up buffered input */
320
      mov ax, rmod_seg
320
      mov ax, rmod_seg
321
      push ax
321
      push ax
322
      pop ds
322
      pop ds
323
      mov dx, RMOD_OFFSET_INPBUFF
323
      mov dx, RMOD_OFFSET_INPBUFF
324
 
324
 
325
      /* execute either DOS input or DOSKEY */
325
      /* execute either DOS input or DOSKEY */
326
      test bl, bl /* zf set if no DOSKEY present */
326
      test bl, bl /* zf set if no DOSKEY present */
327
      jnz DOSKEY
327
      jnz DOSKEY
328
 
328
 
329
      mov ah, 0x0a
329
      mov ah, 0x0a
330
      int 0x21
330
      int 0x21
331
      jmp short DONE
331
      jmp short DONE
332
 
332
 
333
      DOSKEY:
333
      DOSKEY:
334
      mov ax, 0x4810
334
      mov ax, 0x4810
335
      int 0x2f
335
      int 0x2f
336
 
336
 
337
      DONE:
337
      DONE:
338
      pop ds
338
      pop ds
339
      pop dx
339
      pop dx
340
      pop cx
340
      pop cx
341
      pop bx
341
      pop bx
342
      pop ax
342
      pop ax
343
    }
343
    }
344
    outputnl("");
344
    outputnl("");
345
 
345
 
346
    /* if nothing entered, loop again */
346
    /* if nothing entered, loop again */
347
    if (cmdline[-1] == 0) continue;
347
    if (cmdline[-1] == 0) continue;
348
 
348
 
349
    /* replace \r by a zero terminator */
349
    /* replace \r by a zero terminator */
350
    cmdline[(unsigned char)(cmdline[-1])] = 0;
350
    cmdline[(unsigned char)(cmdline[-1])] = 0;
351
 
351
 
352
    /* move pointer forward to skip over any leading spaces */
352
    /* move pointer forward to skip over any leading spaces */
353
    while (*cmdline == ' ') cmdline++;
353
    while (*cmdline == ' ') cmdline++;
354
 
354
 
355
    /* update rmod's ptr to COMPSPEC so it is always up to date */
355
    /* update rmod's ptr to COMPSPEC so it is always up to date */
356
    rmod_updatecomspecptr(rmod_seg, *rmod_envseg);
356
    rmod_updatecomspecptr(rmod_seg, *rmod_envseg);
357
 
357
 
358
    /* try matching (and executing) an internal command */
358
    /* try matching (and executing) an internal command */
359
    {
359
    {
360
      int ecode = cmd_process(*rmod_envseg, cmdline, BUFFER);
360
      int ecode = cmd_process(*rmod_envseg, cmdline, BUFFER);
361
      if (ecode >= 0) *lastexitcode = ecode;
361
      if (ecode >= 0) *lastexitcode = ecode;
362
      if (ecode >= -1) { /* internal command executed */
362
      if (ecode >= -1) { /* internal command executed */
363
        outputnl("");
363
        outputnl("");
364
        continue;
364
        continue;
365
      }
365
      }
366
    }
366
    }
367
 
367
 
368
    /* if here, then this was not an internal command */
368
    /* if here, then this was not an internal command */
369
    run_as_external(cmdline);
369
    run_as_external(cmdline);
370
 
370
 
371
    /* execvp() replaces the current process by the new one
371
    /* execvp() replaces the current process by the new one
372
    if I am still alive then external command failed to execute */
372
    if I am still alive then external command failed to execute */
373
    outputnl("Bad command or file name");
373
    outputnl("Bad command or file name");
374
 
374
 
375
  }
375
  }
376
 
376
 
377
  return(0);
377
  return(0);
378
}
378
}
379
 
379