Subversion Repositories SvarDOS

Rev

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

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