Add GPL-2-or-later license headers to the DOS utility source files and document the purpose and local dependencies of each C, header and assembler file. Preserve the original Martin Stover copyright attribution for the historic MARS-NWE utility sources, including files that did not previously carry an explicit header but are part of the original tool set. Add Mario Fetka as the 2026 copyright holder for the current maintenance work, and use Mario-only headers for files without original Martin Stover ownership. Also add a root-level COPYING file containing the GPL-2 license text.
197 lines
4.8 KiB
C
197 lines
4.8 KiB
C
/*
|
|
* mars-nwe-dosutils - NetWare/DOS utility tools.
|
|
*
|
|
* Copyright (C) 2026 Mario Fetka
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
* Purpose: Small DOS delayed-start helper used by the utility set.
|
|
* Depends on: DOS/Open Watcom runtime headers only; it is independent from the NetWare helper modules.
|
|
*/
|
|
/* dlystrt.c - maintainer-only delayed DOS command starter.
|
|
*
|
|
* This is a tiny TSR helper for login/logout tests. It waits a short
|
|
* time, then stuffs a command line into the BIOS keyboard buffer. The
|
|
* command is therefore executed by the command processor after the batch
|
|
* file that installed DLYSTRT has already returned to the DOS prompt.
|
|
*
|
|
* Example:
|
|
* DLYSTRT /T:2 C:\\LGNTC.BAT
|
|
*
|
|
* The tool is intended for MAINTAINER_BUILD only and is not installed in
|
|
* normal builds.
|
|
*/
|
|
|
|
#include <dos.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <i86.h>
|
|
|
|
#ifndef MAINTAINER_BUILD
|
|
int main(void)
|
|
{
|
|
puts("DLYSTRT is only available in maintainer builds.");
|
|
return 1;
|
|
}
|
|
#else
|
|
|
|
#define MAX_CMD 126
|
|
#define BIOS_SEG 0x0040
|
|
#define KB_HEAD 0x001a
|
|
#define KB_TAIL 0x001c
|
|
#define KB_BUF 0x001e
|
|
#define KB_END 0x003e
|
|
|
|
typedef void (__interrupt __far *intr_fn)(void);
|
|
|
|
static intr_fn old_int1c;
|
|
static volatile unsigned wait_ticks;
|
|
static volatile unsigned pos;
|
|
static volatile unsigned done;
|
|
static char command[MAX_CMD + 3];
|
|
|
|
static int strnicmp_local(const char *a, const char *b, int n)
|
|
{
|
|
int ca, cb;
|
|
while (n-- > 0) {
|
|
ca = toupper((unsigned char)*a++);
|
|
cb = toupper((unsigned char)*b++);
|
|
if (ca != cb || ca == 0 || cb == 0) return ca - cb;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int kb_put_char(char ch)
|
|
{
|
|
unsigned far *headp = (unsigned far *)MK_FP(BIOS_SEG, KB_HEAD);
|
|
unsigned far *tailp = (unsigned far *)MK_FP(BIOS_SEG, KB_TAIL);
|
|
unsigned far *bufp;
|
|
unsigned head = *headp;
|
|
unsigned tail = *tailp;
|
|
unsigned next = tail + 2;
|
|
|
|
if (next >= KB_END) next = KB_BUF;
|
|
if (next == head) return 0; /* keyboard buffer full */
|
|
|
|
bufp = (unsigned far *)MK_FP(BIOS_SEG, tail);
|
|
*bufp = (unsigned)((unsigned char)ch); /* scan code 0, ASCII ch */
|
|
*tailp = next;
|
|
return 1;
|
|
}
|
|
|
|
static void raw_restore_vector(void)
|
|
{
|
|
intr_fn __far *vecp;
|
|
|
|
if (!old_int1c) return;
|
|
|
|
/* Do not call DOS from the timer interrupt. Restore the IVT entry
|
|
* directly, then leave the TSR out of the interrupt path before the
|
|
* delayed command is executed.
|
|
*/
|
|
_disable();
|
|
vecp = (intr_fn __far *)MK_FP(0x0000, 0x1c * 4);
|
|
*vecp = old_int1c;
|
|
_enable();
|
|
}
|
|
|
|
static void __interrupt __far dly_int1c(void)
|
|
{
|
|
intr_fn prev = old_int1c;
|
|
|
|
if (!done) {
|
|
if (wait_ticks) {
|
|
wait_ticks--;
|
|
} else {
|
|
if (command[pos]) {
|
|
if (kb_put_char(command[pos])) pos++;
|
|
} else {
|
|
/* One-shot: unhook before pressing Enter so the command that gets
|
|
* started by COMMAND.COM runs without DLYSTRT still sitting on INT 1Ch.
|
|
*/
|
|
done = 1;
|
|
raw_restore_vector();
|
|
kb_put_char('\r');
|
|
}
|
|
}
|
|
}
|
|
|
|
if (prev) prev();
|
|
}
|
|
|
|
static void usage(void)
|
|
{
|
|
puts("Usage: DLYSTRT [/T:seconds] command [args]");
|
|
puts("Maintainer helper: delay-start a command after returning to DOS.");
|
|
}
|
|
|
|
static void build_command(int argc, char **argv, int first)
|
|
{
|
|
int i;
|
|
|
|
command[0] = '\0';
|
|
for (i = first; i < argc; i++) {
|
|
if (command[0]) strncat(command, " ", MAX_CMD - strlen(command));
|
|
strncat(command, argv[i], MAX_CMD - strlen(command));
|
|
}
|
|
command[MAX_CMD] = '\0';
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
unsigned seconds = 2;
|
|
int first = 1;
|
|
unsigned paras;
|
|
|
|
if (argc < 2) {
|
|
usage();
|
|
return 1;
|
|
}
|
|
|
|
if (!strnicmp_local(argv[first], "/T:", 3)) {
|
|
seconds = (unsigned)atoi(argv[first] + 3);
|
|
if (seconds == 0) seconds = 1;
|
|
first++;
|
|
}
|
|
|
|
if (first >= argc) {
|
|
usage();
|
|
return 1;
|
|
}
|
|
|
|
build_command(argc, argv, first);
|
|
wait_ticks = seconds * 18;
|
|
pos = 0;
|
|
done = 0;
|
|
|
|
old_int1c = _dos_getvect(0x1c);
|
|
_dos_setvect(0x1c, dly_int1c);
|
|
|
|
printf("DLYSTRT installed: %s\n", command);
|
|
|
|
/* Keep a small fixed amount resident. This maintainer helper is tiny;
|
|
* 256 paragraphs = 4 KiB is enough for code, data and the command buffer
|
|
* in the small DOS model used here.
|
|
*/
|
|
paras = 256;
|
|
_dos_keep(0, paras);
|
|
return 0;
|
|
}
|
|
|
|
#endif /* MAINTAINER_BUILD */
|