Subversion Repositories SvarDOS

Rev

Rev 397 | Rev 405 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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