Subversion Repositories SvarDOS

Rev

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

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