Subversion Repositories SvarDOS

Rev

Rev 577 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 577 Rev 1203
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-2022 Mateusz Viste
4
 * Copyright (C) 2021-2022 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 "env.h"
28
#include "helpers.h"
28
#include "helpers.h"
29
#include "rmodinit.h"
29
#include "rmodinit.h"
30
 
30
 
31
#include "redir.h"
31
#include "redir.h"
32
 
32
 
33
static unsigned short oldstdout = 0xffff;
33
static unsigned short oldstdout = 0xffff;
34
 
34
 
35
 
35
 
36
/* compute a filename to be used for pipes */
36
/* compute a filename to be used for pipes */
37
static unsigned short gentmpfile(char *s, unsigned short envseg) {
37
static unsigned short gentmpfile(char *s, unsigned short envseg) {
38
  unsigned short err = 0;
38
  unsigned short err = 0;
39
  unsigned short i;
39
  unsigned short i;
40
 
40
 
41
  /* do I have a %temp% path? */
41
  /* do I have a %temp% path? */
42
  i = env_lookup_valcopy(s, 116, envseg, "TEMP");
42
  i = env_lookup_valcopy(s, 116, envseg, "TEMP");
43
  if (i > 0) {
43
  if (i > 0) {
44
    /* make sure it is terminated by a backslash (required by int 0x21, ah=5a) */
44
    /* make sure it is terminated by a backslash (required by int 0x21, ah=5a) */
45
    if (s[i - 1] != '\\') {
45
    if (s[i - 1] != '\\') {
46
      s[i++] = '\\';
46
      s[i++] = '\\';
47
      s[i] = 0;
47
      s[i] = 0;
48
    }
48
    }
49
  } else {
49
  } else {
50
    /* if fails, then use truename(.\) */
50
    /* if fails, then use truename(.\) */
51
    if (file_truename(".\\", s) != 0) *s = 0;
51
    if (file_truename(".\\", s) != 0) *s = 0;
52
  }
52
  }
53
 
53
 
54
  /* create file */
54
  /* create file */
55
  _asm {
55
  _asm {
56
    mov ah, 0x5a
56
    mov ah, 0x5a
57
    mov dx, s
57
    mov dx, s
58
    xor cx, cx /* file attributes */
58
    xor cx, cx /* file attributes */
59
    int 0x21
59
    int 0x21
60
    jnc CLOSEFILE
60
    jnc CLOSEFILE
61
    mov err, ax
61
    mov err, ax
62
    jmp DONE
62
    jmp DONE
63
    /* close file handle (handle still in BX) */
63
    /* close file handle (handle still in BX) */
64
    CLOSEFILE:
64
    CLOSEFILE:
65
    mov bx, ax
65
    mov bx, ax
66
    mov ah, 0x3e
66
    mov ah, 0x3e
67
    int 0x21
67
    int 0x21
68
    DONE:
68
    DONE:
69
  }
69
  }
70
  return(err);
70
  return(err);
71
}
71
}
72
 
72
 
73
 
73
 
74
/* parse commandline and performs necessary redirections. cmdline is
74
/* parse commandline and performs necessary redirections. cmdline is
75
 * modified so all redirections are cut out.
75
 * modified so all redirections are cut out.
76
 * piped commands are moved to awaitingcmd for later execution
76
 * piped commands are moved to awaitingcmd for later execution
77
 * returns 0 on success, DOS err on failure */
77
 * returns 0 on success, DOS err on failure */
78
unsigned short redir_parsecmd(struct redir_data *d, char *cmdline, char far *awaitingcmd, unsigned short envseg) {
78
unsigned short redir_parsecmd(struct redir_data *d, char *cmdline, char far *awaitingcmd, unsigned short envseg) {
79
  unsigned short i;
79
  unsigned short i;
80
  unsigned short pipescount = 0;
80
  unsigned short pipescount = 0;
81
 
81
 
82
  /* NOTES:
82
  /* NOTES:
83
   *
83
   *
84
   * 1. while it is possible to type a command with multiple
84
   * 1. while it is possible to type a command with multiple
85
   *    redirections, MSDOS executes only the last redirection.
85
   *    redirections, MSDOS executes only the last redirection.
86
   *
86
   *
87
   * 2. the order in which >, < and | are provided on the command line does
87
   * 2. the order in which >, < and | are provided on the command line does
88
   *    not seem to matter for MSDOS. piped commands are executed first (in
88
   *    not seem to matter for MSDOS. piped commands are executed first (in
89
   *    the order they appear) and the result of the last one is redirected to
89
   *    the order they appear) and the result of the last one is redirected to
90
   *    whenever the last > points at.
90
   *    whenever the last > points at.
91
   *    stdin redirection (<) is (obviously) applied to the first command only
91
   *    stdin redirection (<) is (obviously) applied to the first command only
92
   */
92
   */
93
 
93
 
94
  /* preset oldstdout to 0xffff in case no redirection is required */
94
  /* preset oldstdout to 0xffff in case no redirection is required */
95
  oldstdout = 0xffff;
95
  oldstdout = 0xffff;
96
 
96
 
97
  /* clear out the redir_data struct */
97
  /* clear out the redir_data struct */
98
  memset(d, 0, sizeof(*d));
98
  memset(d, 0, sizeof(*d));
99
 
99
 
100
  *awaitingcmd = 0;
100
  *awaitingcmd = 0;
101
 
101
 
102
  /* parse the command line and fill struct with pointers */
102
  /* parse the command line and fill struct with pointers */
103
  for (i = 0;; i++) {
103
  for (i = 0;; i++) {
104
    if (cmdline[i] == '>') {
104
    if (cmdline[i] == '>') {
105
      cmdline[i] = 0;
105
      cmdline[i] = 0;
106
      if (cmdline[i + 1] == '>') {
106
      if (cmdline[i + 1] == '>') {
107
        i++;
107
        i++;
108
        d->stdout_openflag = 0x11;  /* used during int 21h,AH=6C */
108
        d->stdout_openflag = 0x11;  /* used during int 21h,AH=6C */
109
      } else {
109
      } else {
110
        d->stdout_openflag = 0x12;
110
        d->stdout_openflag = 0x12;
111
      }
111
      }
112
      d->stdoutfile = cmdline + i + 1;
112
      d->stdoutfile = cmdline + i + 1;
113
      while (d->stdoutfile[0] == ' ') d->stdoutfile++;
113
      while (d->stdoutfile[0] == ' ') d->stdoutfile++;
114
    } else if (cmdline[i] == '<') {
114
    } else if (cmdline[i] == '<') {
115
      cmdline[i] = 0;
115
      cmdline[i] = 0;
116
      d->stdinfile = cmdline + i + 1;
116
      d->stdinfile = cmdline + i + 1;
117
      while (d->stdinfile[0] == ' ') d->stdinfile++;
117
      while (d->stdinfile[0] == ' ') d->stdinfile++;
118
    } else if (cmdline[i] == '|') {
118
    } else if (cmdline[i] == '|') {
119
      cmdline[i] = 0;
119
      cmdline[i] = 0;
120
      if (pipescount < REDIR_MAX_PIPES) {
120
      if (pipescount < REDIR_MAX_PIPES) {
121
        d->pipes[pipescount++] = cmdline + i + 1;
121
        d->pipes[pipescount++] = cmdline + i + 1;
122
        while (d->pipes[pipescount][0] == ' ') d->pipes[pipescount]++;
122
        while (d->pipes[pipescount][0] == ' ') d->pipes[pipescount]++;
123
      }
123
      }
124
    } else if (cmdline[i] == 0) {
124
    } else if (cmdline[i] == 0) {
125
      break;
125
      break;
126
    }
126
    }
127
  }
127
  }
128
 
128
 
129
  /* if pipes present, write them to awaitingcmd (and stdout redirection too) */
129
  /* if pipes present, write them to awaitingcmd (and stdout redirection too) */
130
  if (pipescount != 0) {
130
  if (pipescount != 0) {
131
    static char tmpfile[130];
131
    static char tmpfile[130];
132
    for (i = 0; i < pipescount; i++) {
132
    for (i = 0; i < pipescount; i++) {
133
      if (i != 0) _fstrcat(awaitingcmd, "|");
133
      if (i != 0) _fstrcat(awaitingcmd, "|");
134
      _fstrcat(awaitingcmd, d->pipes[i]);
134
      _fstrcat(awaitingcmd, d->pipes[i]);
135
    }
135
    }
136
    /* append stdout redirection so I don't forget about it for the last command of the pipe queue */
136
    /* append stdout redirection so I don't forget about it for the last command of the pipe queue */
137
    if (d->stdoutfile != NULL) {
137
    if (d->stdoutfile != NULL) {
138
      if (d->stdout_openflag == 0x11) {
138
      if (d->stdout_openflag == 0x11) {
139
        _fstrcat(awaitingcmd, ">>");
139
        _fstrcat(awaitingcmd, ">>");
140
      } else {
140
      } else {
141
        _fstrcat(awaitingcmd, ">");
141
        _fstrcat(awaitingcmd, ">");
142
      }
142
      }
143
      d->stdoutfile = NULL;
143
      d->stdoutfile = NULL;
144
    }
144
    }
145
    /* redirect stdin of next command from a temp file (that is used as my output) */
145
    /* redirect stdin of next command from a temp file (that is used as my output) */
146
    _fstrcat(awaitingcmd, "<");
146
    _fstrcat(awaitingcmd, "<");
147
    i = gentmpfile(tmpfile, envseg);
147
    i = gentmpfile(tmpfile, envseg);
148
    if (i != 0) return(i);
148
    if (i != 0) return(i);
149
    _fstrcat(awaitingcmd, tmpfile);
149
    _fstrcat(awaitingcmd, tmpfile);
150
    /* same file is used as my stdout */
150
    /* same file is used as my stdout */
151
    d->stdoutfile = tmpfile;
151
    d->stdoutfile = tmpfile;
152
    d->stdout_openflag = 0x12;
152
    d->stdout_openflag = 0x12;
153
  }
153
  }
154
  return(0);
154
  return(0);
155
}
155
}
156
 
156
 
157
 
157
 
158
/* apply stdout redirections defined in redir_data, returns 0 on success */
158
/* apply stdout redirections defined in redir_data, returns 0 on success */
159
int redir_apply(const struct redir_data *d) {
159
int redir_apply(const struct redir_data *d) {
160
 
160
 
161
  if (d->stdoutfile != NULL) {
161
  if (d->stdoutfile != NULL) {
162
    unsigned short openflag = d->stdout_openflag;
162
    unsigned short openflag = d->stdout_openflag;
163
    unsigned short errcode = 0;
163
    unsigned short errcode = 0;
164
    unsigned short handle = 0;
164
    unsigned short handle = 0;
165
    const char *myptr = d->stdoutfile;
165
    const char *myptr = d->stdoutfile;
166
 
166
 
167
    /* */
167
    /* */
168
    _asm {
168
    _asm {
169
      push ax
169
      push ax
170
      push bx
170
      push bx
171
      push cx
171
      push cx
172
      push dx
172
      push dx
173
      push si
173
      push si
174
      mov ax, 0x6c00     /* Extended Open/Create */
174
      mov ax, 0x6c00     /* Extended Open/Create */
175
      mov bx, 1          /* access mode (0=read, 1=write, 2=r+w */
175
      mov bx, 1          /* access mode (0=read, 1=write, 2=r+w */
176
      xor cx, cx         /* attributes when(if) creating the file (0=normal) */
176
      xor cx, cx         /* attributes when(if) creating the file (0=normal) */
177
      mov dx, [openflag] /* action if file exists (0x11=open, 0x12=truncate)*/
177
      mov dx, [openflag] /* action if file exists (0x11=open, 0x12=truncate)*/
178
      mov si, myptr      /* ASCIIZ filename */
178
      mov si, myptr      /* ASCIIZ filename */
179
      int 0x21           /* AX=handle on success (CF clear), otherwise dos err */
179
      int 0x21           /* AX=handle on success (CF clear), otherwise dos err */
180
      mov handle, ax     /* save the file handler */
180
      mov handle, ax     /* save the file handler */
181
      jnc JMPEOF
181
      jnc JMPEOF
182
      mov errcode, ax
182
      mov errcode, ax
183
      jmp DONE
183
      jmp DONE
184
 
184
 
185
      JMPEOF:
185
      JMPEOF:
186
      cmp openflag, word ptr 0x11
186
      cmp openflag, word ptr 0x11
187
      jne DUPSTDOUT
187
      jne DUPSTDOUT
188
      /* jump to the end of the file (required for >> redirections) */
188
      /* jump to the end of the file (required for >> redirections) */
189
      mov ax, 0x4202     /* jump to position EOF - CX:DX in handle BX */
189
      mov ax, 0x4202     /* jump to position EOF - CX:DX in handle BX */
190
      mov bx, handle
190
      mov bx, handle
191
      xor cx, cx
191
      xor cx, cx
192
      xor dx, dx
192
      xor dx, dx
193
      int 0x21
193
      int 0x21
194
 
194
 
195
      /* save (duplicate) current stdout so I can revert it later */
195
      /* save (duplicate) current stdout so I can revert it later */
196
      DUPSTDOUT:
196
      DUPSTDOUT:
197
      mov ah, 0x45       /* duplicate file handle */
197
      mov ah, 0x45       /* duplicate file handle */
198
      mov bx, 1          /* handle to dup (1=stdout) */
198
      mov bx, 1          /* handle to dup (1=stdout) */
199
      int 0x21           /* ax = new file handle */
199
      int 0x21           /* ax = new file handle */
200
      mov oldstdout, ax
200
      mov oldstdout, ax
201
      /* redirect the stdout handle */
201
      /* redirect the stdout handle */
202
      mov bx, handle     /* dst handle */
202
      mov bx, handle     /* dst handle */
203
      mov cx, 1          /* src handle (1=stdout) */
203
      mov cx, 1          /* src handle (1=stdout) */
204
      mov ah, 0x46       /* redirect a handle */
204
      mov ah, 0x46       /* redirect a handle */
205
      int 0x21
205
      int 0x21
206
      /* close the original file handle (no longer needed) */
206
      /* close the original file handle (no longer needed) */
207
      mov ah, 0x3e       /* close a file handle (handle in BX) */
207
      mov ah, 0x3e       /* close a file handle (handle in BX) */
208
      int 0x21
208
      int 0x21
209
      DONE:
209
      DONE:
210
      pop si
210
      pop si
211
      pop dx
211
      pop dx
212
      pop cx
212
      pop cx
213
      pop bx
213
      pop bx
214
      pop ax
214
      pop ax
215
    }
215
    }
216
    if (errcode != 0) {
216
    if (errcode != 0) {
217
      nls_outputnl_doserr(errcode);
217
      nls_outputnl_doserr(errcode);
218
      return(-1);
218
      return(-1);
219
    }
219
    }
220
  }
220
  }
221
 
221
 
222
  return(0);
222
  return(0);
223
}
223
}
224
 
224
 
225
 
225
 
226
/* restores previous stdout handle if is has been redirected */
226
/* restores previous stdout handle if is has been redirected */
227
void redir_revert(void) {
227
void redir_revert(void) {
228
  _asm {
228
  _asm {
229
    /* if oldstdout is 0xffff then not redirected */
229
    /* if oldstdout is 0xffff then not redirected */
230
    mov bx, [oldstdout] /* dst handle */
230
    mov bx, [oldstdout] /* dst handle */
231
    cmp bx, 0xffff
231
    cmp bx, 0xffff
232
    je DONE
232
    je DONE
233
    /* redirect the stdout handle (handle already in BX) */
233
    /* redirect the stdout handle (handle already in BX) */
234
    mov cx, 1           /* src handle (1=stdout) */
234
    mov cx, 1           /* src handle (1=stdout) */
235
    mov ah, 0x46        /* redirect a handle */
235
    mov ah, 0x46        /* redirect a handle */
236
    int 0x21
236
    int 0x21
237
    /* close old handle (in bx already) */
237
    /* close old handle (in bx already) */
238
    mov ah, 0x3e
238
    mov ah, 0x3e
239
    int 0x21
239
    int 0x21
240
    mov [oldstdout], 0xffff
240
    mov [oldstdout], 0xffff
241
    DONE:
241
    DONE:
242
  }
242
  }
243
}
243
}
244
 
244