Subversion Repositories SvarDOS

Rev

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