Subversion Repositories SvarDOS

Rev

Rev 577 | Details | Compare with Previous | Last modification | View Log | RSS feed

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