Subversion Repositories SvarDOS

Rev

Rev 962 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 962 Rev 964
Line 1... Line 1...
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,
Line 39... Line 39...
39
 * Labels can be written as:
39
 * Labels can be written as:
40
 * :LABEL
40
 * :LABEL
41
 *    :LABEL
41
 *    :LABEL
42
 *   :  LABEL
42
 *   :  LABEL
43
 *
43
 *
-
 
44
 * A label can also be followed by one or more space or tabs, followed by
-
 
45
 * anything. The label is parsed only to the first space, tab, end of line or
-
 
46
 * end of file. Hence this would be perfectly ok:
-
 
47
 *
-
 
48
 * :LABEL this is a comment
-
 
49
 *
44
 * Labels are searched in the batch file from top to bottom and first match
50
 * Labels are searched in the batch file from top to bottom and first match
45
 * is jumped to.
51
 * is jumped to. Matching labels is case-insensitive (ie. LABEL == LaBeL)
46
 */
52
 */
47
 
53
 
-
 
54
 
-
 
55
static void goto_close_dos_handle(unsigned short fhandle) {
-
 
56
  _asm {
-
 
57
    push bx
-
 
58
 
-
 
59
    mov ah, 0x3e
-
 
60
    mov bx, fhandle
-
 
61
    int 0x21
-
 
62
 
-
 
63
    pop bx
-
 
64
  }
-
 
65
}
-
 
66
 
-
 
67
 
48
static enum cmd_result cmd_goto(struct cmd_funcparam *p) {
68
static enum cmd_result cmd_goto(struct cmd_funcparam *p) {
-
 
69
  char *buff = NULL;
-
 
70
  const char *label;
-
 
71
  unsigned short bufflen = 0;
-
 
72
  unsigned short fhandle = 0;
-
 
73
  unsigned short doserr = 0;
-
 
74
  unsigned short batname_seg;
-
 
75
  unsigned short batname_off;
-
 
76
  unsigned char eof_reached = 0;
-
 
77
  unsigned short i;
49
 
78
 
50
  /* help? reacts only to /? being passed as FIRST argument */
79
  /* help? reacts only to /? being passed as FIRST argument */
51
  if ((p->argc > 0) && imatch(p->argv[0], "/?")) {
80
  if ((p->argc > 0) && imatch(p->argv[0], "/?")) {
52
    outputnl("Directs batch processing to a labelled line in the batch program.");
81
    nls_outputnl(17,0); /* "Directs batch processing to a labelled line in the batch program." */
53
    outputnl("");
82
    outputnl("");
54
    outputnl("GOTO LABEL");
83
    nls_outputnl(17,1); /* "GOTO LABEL" */
55
    outputnl("");
84
    outputnl("");
56
    outputnl("LABEL specifies a text string used in the batch program as a label.");
85
    nls_outputnl(17,2); /* "LABEL specifies a text string used in the batch program as a label." */
57
    outputnl("");
86
    outputnl("");
58
    outputnl("A label is on a line by itself and must be preceded by a colon.");
87
    nls_outputnl(17,3); /* "A label is on a line by itself and must be preceded by a colon." */
59
    return(CMD_OK);
88
    return(CMD_OK);
60
  }
89
  }
61
 
90
 
62
  /* not inside a batch file? then do nothing */
91
  /* not inside a batch file? not given any argument? then do nothing */
63
  if (p->rmod->bat == NULL) return(CMD_OK);
92
  if ((p->rmod->bat == NULL) || (p->argc == 0)) return(CMD_OK);
-
 
93
 
-
 
94
  /* label is in first arg */
-
 
95
  label = p->argv[0];
-
 
96
 
-
 
97
  /* open batch file (read-only) */
-
 
98
  batname_seg = FP_SEG(p->rmod->bat->fname);
-
 
99
  batname_off = FP_OFF(p->rmod->bat->fname);
-
 
100
  _asm {
-
 
101
    push bx
-
 
102
    push dx
-
 
103
 
-
 
104
    mov ax, batname_seg
-
 
105
    push ds /* save ds */
-
 
106
    mov ds, ax
-
 
107
    mov dx, batname_off
-
 
108
    mov ax, 0x3d00
-
 
109
    int 0x21    /* handle in ax on success */
-
 
110
    pop ds
-
 
111
    jnc OPEN_SUCCESS
-
 
112
    mov doserr, ax
-
 
113
 
-
 
114
    OPEN_SUCCESS:
-
 
115
    mov fhandle, ax /* save file handle */
-
 
116
 
-
 
117
    pop dx
-
 
118
    pop bx
-
 
119
  }
-
 
120
 
-
 
121
  /* file open failed? */
-
 
122
  if (doserr != 0) {
-
 
123
    nls_outputnl_doserr(doserr);
-
 
124
    return(CMD_FAIL);
-
 
125
  }
-
 
126
 
-
 
127
  /* reset the rmod bat counter since I will scan all lines from top to bottom */
-
 
128
  p->rmod->bat->nextline = 0; /* remember this is a byte offset, not a line number */
-
 
129
 
-
 
130
  /* read bat file line by line until label is found or EOF */
-
 
131
  for (;;) {
-
 
132
 
-
 
133
    /* move any existing data to the start of the buffer */
-
 
134
    if (bufflen > 0) memmove(p->BUFFER, buff, bufflen);
-
 
135
 
-
 
136
    buff = p->BUFFER; /* assumption: must be big enough to hold 2 sectors (2 * 512) */
-
 
137
 
-
 
138
    /* if buffer has less than 512b then load it with another sector (unless eof) */
-
 
139
    if ((eof_reached == 0) && (bufflen < 512)) {
-
 
140
      /* load 512b of data into buffer */
-
 
141
      _asm {
-
 
142
        push ax
-
 
143
        push bx
-
 
144
        push cx
-
 
145
        push dx
-
 
146
        pushf
-
 
147
 
-
 
148
        mov ah, 0x3f    /* read from file handle */
-
 
149
        mov bx, fhandle /* file handle where to read from */
-
 
150
        mov cx, 512     /* read 512 bytes (one sector) */
-
 
151
        mov dx, buff    /* target buffer */
-
 
152
        add dx, bufflen /* data must follow existing pending data */
-
 
153
        int 0x21        /* CF clear on success and AX=number of bytes read */
-
 
154
        /* error? */
-
 
155
        jnc READ_OK
-
 
156
        mov doserr, ax
-
 
157
        READ_OK:
-
 
158
        add bufflen, ax
-
 
159
        /* set eof if amount of bytes read is shorter than cx */
-
 
160
        cmp ax, cx
-
 
161
        je EOF_NOT_REACHED
-
 
162
        mov eof_reached, byte ptr 1
-
 
163
        EOF_NOT_REACHED:
-
 
164
 
-
 
165
        popf
-
 
166
        pop dx
-
 
167
        pop cx
-
 
168
        pop bx
-
 
169
        pop ax
-
 
170
      }
-
 
171
 
-
 
172
      /* on error close the file and quit */
-
 
173
      if (doserr != 0) {
-
 
174
        goto_close_dos_handle(fhandle);
-
 
175
        nls_outputnl_doserr(doserr);
-
 
176
        return(CMD_FAIL);
-
 
177
      }
-
 
178
    }
-
 
179
 
-
 
180
    /* advance buffer to first non-space/non-tab/non-CR/non-LF */
-
 
181
    while (bufflen > 0) {
-
 
182
      if ((*buff != ' ') && (*buff != '\t') && (*buff != '\r') && (*buff != '\n')) break;
-
 
183
      bufflen--;
-
 
184
      buff++;
-
 
185
      p->rmod->bat->nextline++;
-
 
186
    }
-
 
187
 
-
 
188
    /* if the line does not start with a colon, then jump to next line */
-
 
189
    if ((bufflen > 0) && (*buff != ':')) {
-
 
190
      while ((bufflen > 0) && (*buff != '\n')) {
-
 
191
        bufflen--;
-
 
192
        buff++;
-
 
193
        p->rmod->bat->nextline++;
-
 
194
      }
-
 
195
    }
-
 
196
 
-
 
197
    /* refill buffer if needed */
-
 
198
    if ((bufflen < 512) && (eof_reached == 0)) continue;
-
 
199
 
-
 
200
    /* eof? */
-
 
201
    if (bufflen == 0) break;
64
 
202
 
-
 
203
    /* skip the colon */
-
 
204
    if (*buff == ':') {
-
 
205
      bufflen--;
-
 
206
      buff++;
65
  /* TODO open batch file and read it line by line until label is found or EOF */
207
      p->rmod->bat->nextline++;
-
 
208
    }
66
 
209
 
67
  /* TODO if label not found, display error message and abort all batch scripts */
210
    /* skip any leading white spaces (space or tab) */
-
 
211
    while (bufflen > 0) {
-
 
212
      if ((*buff != ' ') && (*buff != '\t')) break;
-
 
213
      bufflen--;
-
 
214
      buff++;
-
 
215
      p->rmod->bat->nextline++;
-
 
216
    }
68
 
217
 
-
 
218
    /* read the in-file label and compare it with what's in the label buff */
-
 
219
    for (i = 0;; i++) {
-
 
220
      /* if end of label then check if it is also end of in-file label (ends with space, tab, \r or \n) */
-
 
221
      if ((i == bufflen) || (buff[i] == ' ') || (buff[i] == '\t') || (buff[i] == '\r') || (buff[i] == '\n')) {
-
 
222
        if (label[i] == 0) {
-
 
223
          /* match found -> close file, skip to end of line and quit */
-
 
224
          while (bufflen > 0) {
-
 
225
            bufflen--;
-
 
226
            buff++;
-
 
227
            p->rmod->bat->nextline++;
-
 
228
            if (*buff == '\n') break;
-
 
229
          }
-
 
230
          goto_close_dos_handle(fhandle);
69
  return(CMD_OK);
231
          return(CMD_OK);
70
}
232
        }
-
 
233
        break;
-
 
234
      }
-
 
235
      /* end of label = mismatch */
-
 
236
      if (label[i] == 0) break;
-
 
237
      /* case-insensitive comparison */
-
 
238
      if ((label[i] & 0xDF) != (buff[i] & 0xDF)) break;
-
 
239
    }
-
 
240
 
-
 
241
    /* no match, move forward to end of line and repeat */
-
 
242
    while ((bufflen > 0) && (*buff != '\n')) {
-
 
243
      bufflen--;
-
 
244
      buff++;
-
 
245
      p->rmod->bat->nextline++;
-
 
246
    }
-
 
247
  }
-
 
248
 
-
 
249
  /* close the batch file handle */
-
 
250
  goto_close_dos_handle(fhandle);
-
 
251
 
-
 
252
  /* label not found, display error message and abort all batch scripts */
-
 
253
  nls_outputnl(17, 10); /* "Label not found" */
-
 
254
  rmod_free_bat_llist(p->rmod);
-
 
255
 
-
 
256
  /* restore echo flag as it was before running the (first) bat file */
-
 
257
  p->rmod->flags &= ~FLAG_ECHOFLAG;
-
 
258
  if (p->rmod->flags & FLAG_ECHO_BEFORE_BAT) p->rmod->flags |= FLAG_ECHOFLAG;
-
 
259
 
-
 
260
  return(CMD_FAIL);
-
 
261
}