Subversion Repositories SvarDOS

Rev

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