Subversion Repositories SvarDOS

Rev

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

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