Subversion Repositories SvarDOS

Rev

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

Rev 538 Rev 543
1
/* This file is part of the SvarCOM project and is published under the terms
1
/* This file is part of the SvarCOM project and is published under the terms
2
 * of the MIT license.
2
 * of the MIT license.
3
 *
3
 *
4
 * Copyright (C) 2021 Mateusz Viste
4
 * Copyright (C) 2021 Mateusz Viste
5
 *
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the "Software"),
7
 * copy of this software and associated documentation files (the "Software"),
8
 * to deal in the Software without restriction, including without limitation
8
 * to deal in the Software without restriction, including without limitation
9
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
 * and/or sell copies of the Software, and to permit persons to whom the
10
 * and/or sell copies of the Software, and to permit persons to whom the
11
 * Software is furnished to do so, subject to the following conditions:
11
 * Software is furnished to do so, subject to the following conditions:
12
 *
12
 *
13
 * The above copyright notice and this permission notice shall be included in
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
14
 * all copies or substantial portions of the Software.
15
 *
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
 * DEALINGS IN THE SOFTWARE.
22
 * DEALINGS IN THE SOFTWARE.
23
 */
23
 */
24
 
24
 
25
#include <string.h> /* memset() */
25
#include <string.h> /* memset() */
26
 
26
 
-
 
27
#include "env.h"
27
#include "helpers.h"
28
#include "helpers.h"
28
#include "rmodinit.h"
29
#include "rmodinit.h"
29
 
30
 
30
#include "redir.h"
31
#include "redir.h"
31
 
32
 
32
static unsigned short oldstdout = 0xffff;
33
static unsigned short oldstdout = 0xffff;
33
 
34
 
34
 
35
 
-
 
36
/* compute a filename to be used for pipes */
-
 
37
static unsigned short gentmpfile(char *s) {
-
 
38
  unsigned short err = 0;
-
 
39
  /* do I have a %temp% path? */
-
 
40
  /* TODO */
-
 
41
 
-
 
42
  /* if fails, then use truename(\) */
-
 
43
  if (file_truename(".\\", s) != 0) *s = 0;
-
 
44
 
-
 
45
  /* create file */
-
 
46
  _asm {
-
 
47
    mov ah, 0x5a
-
 
48
    mov dx, s
-
 
49
    xor cx, cx /* file attributes */
-
 
50
    int 0x21
-
 
51
    jnc CLOSEFILE
-
 
52
    mov err, ax
-
 
53
    jmp DONE
-
 
54
    /* close file handle */
-
 
55
    CLOSEFILE:
-
 
56
    mov ah, 0x3e
-
 
57
    mov bx, ax
-
 
58
    int 0x21
-
 
59
    DONE:
-
 
60
  }
-
 
61
  return(err);
-
 
62
}
-
 
63
 
-
 
64
#include <stdio.h>
35
/* parse commandline and performs necessary redirections. cmdline is
65
/* parse commandline and performs necessary redirections. cmdline is
36
 * modified so all redirections are cut out. */
66
 * modified so all redirections are cut out.
-
 
67
 * piped commands are move to awaitingcmd for later execution
-
 
68
 * returns 0 on success, DOS err on failure */
37
void redir_parsecmd(struct redir_data *d, char *cmdline) {
69
unsigned short redir_parsecmd(struct redir_data *d, char *cmdline, char far *awaitingcmd) {
38
  unsigned short i;
70
  unsigned short i;
39
  unsigned short pipescount = 0;
71
  unsigned short pipescount = 0;
40
 
72
 
41
  /* NOTE:
73
  /* NOTES:
42
   *
74
   *
43
   * 1. while it is possible to type a command with multiple
75
   * 1. while it is possible to type a command with multiple
44
   *    redirections, MSDOS executes only the last redirection.
76
   *    redirections, MSDOS executes only the last redirection.
45
   *
77
   *
46
   * 2. the order in which >, < and | are provided on the command line does
78
   * 2. the order in which >, < and | are provided on the command line does
47
   *    not seem to matter for MSDOS. piped commands are executed first (in
79
   *    not seem to matter for MSDOS. piped commands are executed first (in
48
   *    the order they appear) and the result of the last one is redirected to
80
   *    the order they appear) and the result of the last one is redirected to
49
   *    whenever the last > points at.
81
   *    whenever the last > points at.
-
 
82
   *    stdin redirection (<) is (obviously) applied to the first command only
50
   */
83
   */
51
 
84
 
52
  /* preset oldstdout to 0xffff in case no redirection is required */
85
  /* preset oldstdout to 0xffff in case no redirection is required */
53
  oldstdout = 0xffff;
86
  oldstdout = 0xffff;
54
 
87
 
55
  /* clear out the redir_data struct */
88
  /* clear out the redir_data struct */
56
  memset(d, 0, sizeof(*d));
89
  memset(d, 0, sizeof(*d));
57
 
90
 
-
 
91
  *awaitingcmd = 0;
-
 
92
 
58
  /* parse the command line and fill struct with pointers */
93
  /* parse the command line and fill struct with pointers */
59
  for (i = 0;; i++) {
94
  for (i = 0;; i++) {
60
    if (cmdline[i] == '>') {
95
    if (cmdline[i] == '>') {
61
      cmdline[i] = 0;
96
      cmdline[i] = 0;
62
      if (cmdline[i + 1] == '>') {
97
      if (cmdline[i + 1] == '>') {
63
        i++;
98
        i++;
64
        d->stdout_openflag = 0x11;  /* used during int 21h,AH=6C */
99
        d->stdout_openflag = 0x11;  /* used during int 21h,AH=6C */
65
      } else {
100
      } else {
66
        d->stdout_openflag = 0x12;
101
        d->stdout_openflag = 0x12;
67
      }
102
      }
68
      d->stdoutfile = cmdline + i + 1;
103
      d->stdoutfile = cmdline + i + 1;
69
      while (d->stdoutfile[0] == ' ') d->stdoutfile++;
104
      while (d->stdoutfile[0] == ' ') d->stdoutfile++;
70
    } else if (cmdline[i] == '<') {
105
    } else if (cmdline[i] == '<') {
71
      cmdline[i] = 0;
106
      cmdline[i] = 0;
72
      d->stdinfile = cmdline + i + 1;
107
      d->stdinfile = cmdline + i + 1;
73
      while (d->stdinfile[0] == ' ') d->stdinfile++;
108
      while (d->stdinfile[0] == ' ') d->stdinfile++;
74
    } else if (cmdline[i] == '|') {
109
    } else if (cmdline[i] == '|') {
75
      cmdline[i] = 0;
110
      cmdline[i] = 0;
76
      if (pipescount < REDIR_MAX_PIPES) {
111
      if (pipescount < REDIR_MAX_PIPES) {
77
        d->pipes[pipescount++] = cmdline + i + 1;
112
        d->pipes[pipescount++] = cmdline + i + 1;
78
        while (d->pipes[pipescount][0] == ' ') d->pipes[pipescount]++;
113
        while (d->pipes[pipescount][0] == ' ') d->pipes[pipescount]++;
79
      }
114
      }
80
    } else if (cmdline[i] == 0) {
115
    } else if (cmdline[i] == 0) {
81
      break;
116
      break;
82
    }
117
    }
83
  }
118
  }
-
 
119
 
-
 
120
  /* if pipes present, write them to awaitingcmd (and stdout redirection too) */
-
 
121
  if (pipescount != 0) {
-
 
122
    static char tmpfile[130];
-
 
123
    for (i = 0; i < pipescount; i++) {
-
 
124
      if (i != 0) _fstrcat(awaitingcmd, "|");
-
 
125
      _fstrcat(awaitingcmd, d->pipes[i]);
-
 
126
    }
-
 
127
    /* append stdout redirection so I don't forget about it for the last command of the pipe queue */
-
 
128
    if (d->stdoutfile != NULL) {
-
 
129
      if (d->stdout_openflag == 0x11) {
-
 
130
        _fstrcat(awaitingcmd, ">>");
-
 
131
      } else {
-
 
132
        _fstrcat(awaitingcmd, ">");
-
 
133
      }
-
 
134
      d->stdoutfile = NULL;
-
 
135
    }
-
 
136
    /* redirect stdin of next command from a temp file (that is used as my output) */
-
 
137
    _fstrcat(awaitingcmd, "<");
-
 
138
    i = gentmpfile(tmpfile);
-
 
139
    if (i != 0) return(i);
-
 
140
    _fstrcat(awaitingcmd, tmpfile);
-
 
141
    /* same file is used as my stdout */
-
 
142
    d->stdoutfile = tmpfile;
-
 
143
    d->stdout_openflag = 0x12;
-
 
144
    /* TODO I need to remember that the tmp file must be removed... */
-
 
145
/*    outputnl("awaitingcmd:");
-
 
146
    for (i = 0; awaitingcmd[i] != 0; i++) printf("%c", awaitingcmd[i]);
-
 
147
    printf("\r\n");*/
-
 
148
  }
-
 
149
  return(0);
84
}
150
}
85
 
151
 
86
 
152
 
87
/* apply stdin/stdout redirections defined in redir_data, returns 0 on success */
153
/* apply stdout redirections defined in redir_data, returns 0 on success */
88
int redir_apply(const struct redir_data *d) {
154
int redir_apply(const struct redir_data *d) {
89
  if (d->stdinfile != NULL) {
-
 
90
    outputnl("ERROR: stdin redirection is not supported yet");
-
 
91
    return(-1);
-
 
92
  }
-
 
93
 
155
 
94
  if (d->stdoutfile != NULL) {
156
  if (d->stdoutfile != NULL) {
95
    unsigned short openflag = d->stdout_openflag;
157
    unsigned short openflag = d->stdout_openflag;
96
    unsigned short errcode = 0;
158
    unsigned short errcode = 0;
97
    unsigned short handle = 0;
159
    unsigned short handle = 0;
98
    const char *myptr = d->stdoutfile;
160
    const char *myptr = d->stdoutfile;
99
 
161
 
100
    /* */
162
    /* */
101
    _asm {
163
    _asm {
102
      push ax
164
      push ax
103
      push bx
165
      push bx
104
      push cx
166
      push cx
105
      push dx
167
      push dx
106
      push si
168
      push si
107
      mov ax, 0x6c00     /* Extended Open/Create */
169
      mov ax, 0x6c00     /* Extended Open/Create */
108
      mov bx, 1          /* access mode (0=read, 1=write, 2=r+w */
170
      mov bx, 1          /* access mode (0=read, 1=write, 2=r+w */
109
      xor cx, cx         /* attributes when(if) creating the file (0=normal) */
171
      xor cx, cx         /* attributes when(if) creating the file (0=normal) */
110
      mov dx, [openflag] /* action if file exists (0x11=open, 0x12=truncate)*/
172
      mov dx, [openflag] /* action if file exists (0x11=open, 0x12=truncate)*/
111
      mov si, myptr      /* ASCIIZ filename */
173
      mov si, myptr      /* ASCIIZ filename */
112
      int 0x21           /* AX=handle on success (CF clear), otherwise dos err */
174
      int 0x21           /* AX=handle on success (CF clear), otherwise dos err */
113
      mov handle, ax     /* save the file handler */
175
      mov handle, ax     /* save the file handler */
114
      jnc JMPEOF
176
      jnc JMPEOF
115
      mov errcode, ax
177
      mov errcode, ax
116
      jmp DONE
178
      jmp DONE
117
 
179
 
118
      JMPEOF:
180
      JMPEOF:
119
      cmp openflag, word ptr 0x11
181
      cmp openflag, word ptr 0x11
120
      jne DUPSTDOUT
182
      jne DUPSTDOUT
121
      /* jump to the end of the file (required for >> redirections) */
183
      /* jump to the end of the file (required for >> redirections) */
122
      mov ax, 0x4202     /* jump to position EOF - CX:DX in handle BX */
184
      mov ax, 0x4202     /* jump to position EOF - CX:DX in handle BX */
123
      mov bx, handle
185
      mov bx, handle
124
      xor cx, cx
186
      xor cx, cx
125
      xor dx, dx
187
      xor dx, dx
126
      int 0x21
188
      int 0x21
127
 
189
 
128
      /* save (duplicate) current stdout so I can revert it later */
190
      /* save (duplicate) current stdout so I can revert it later */
129
      DUPSTDOUT:
191
      DUPSTDOUT:
130
      mov ah, 0x45       /* duplicate file handle */
192
      mov ah, 0x45       /* duplicate file handle */
131
      mov bx, 1          /* handle to dup (1=stdout) */
193
      mov bx, 1          /* handle to dup (1=stdout) */
132
      int 0x21           /* ax = new file handle */
194
      int 0x21           /* ax = new file handle */
133
      mov oldstdout, ax
195
      mov oldstdout, ax
134
      /* redirect the stdout handle */
196
      /* redirect the stdout handle */
135
      mov bx, handle     /* dst handle */
197
      mov bx, handle     /* dst handle */
136
      mov cx, 1          /* src handle (1=stdout) */
198
      mov cx, 1          /* src handle (1=stdout) */
137
      mov ah, 0x46       /* redirect a handle */
199
      mov ah, 0x46       /* redirect a handle */
138
      int 0x21
200
      int 0x21
139
      /* close the original file handle (no longer needed) */
201
      /* close the original file handle (no longer needed) */
140
      mov ah, 0x3e       /* close a file handle (handle in BX) */
202
      mov ah, 0x3e       /* close a file handle (handle in BX) */
141
      int 0x21
203
      int 0x21
142
      DONE:
204
      DONE:
143
      pop si
205
      pop si
144
      pop dx
206
      pop dx
145
      pop cx
207
      pop cx
146
      pop bx
208
      pop bx
147
      pop ax
209
      pop ax
148
    }
210
    }
149
    if (errcode != 0) {
211
    if (errcode != 0) {
150
      nls_outputnl_doserr(errcode);
212
      nls_outputnl_doserr(errcode);
151
      return(-1);
213
      return(-1);
152
    }
214
    }
153
  }
215
  }
154
 
216
 
155
  return(0);
217
  return(0);
156
}
218
}
157
 
219
 
158
 
220
 
159
/* restores previous stdout/stdin handlers if they have been redirected */
221
/* restores previous stdout handle if is has been redirected */
160
void redir_revert(void) {
222
void redir_revert(void) {
161
  _asm {
223
  _asm {
162
    /* if oldstdout is 0xffff then not redirected */
224
    /* if oldstdout is 0xffff then not redirected */
163
    cmp word ptr [oldstdout], 0xffff
225
    cmp word ptr [oldstdout], 0xffff
164
    je DONE
226
    je DONE
165
    /* redirect the stdout handle */
227
    /* redirect the stdout handle */
166
    mov bx, [oldstdout] /* dst handle */
228
    mov bx, [oldstdout] /* dst handle */
167
    mov cx, 1           /* src handle (1=stdout) */
229
    mov cx, 1           /* src handle (1=stdout) */
168
    mov ah, 0x46        /* redirect a handle */
230
    mov ah, 0x46        /* redirect a handle */
169
    int 0x21
231
    int 0x21
170
    /* close old handle (in bx already) */
232
    /* close old handle (in bx already) */
171
    mov ah, 0x3e
233
    mov ah, 0x3e
172
    int 0x21
234
    int 0x21
173
    mov [oldstdout], 0xffff
235
    mov [oldstdout], 0xffff
174
    DONE:
236
    DONE:
175
  }
237
  }
176
}
238
}
177
 
239