/*
* comcom64 - 64bit command.com
* ae0x.c: interface to int2f ax=0xae00,0xae01
* Copyright (C) 2018 @andrewbird
* Copyright (C) 2023-2024 @stsp
*
* 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 3 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 .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "env.h"
#include "ae0x.h"
#define CF 1
struct ae0x {
struct {
uint8_t cmax;
uint8_t clen;
char cbuf[256];
} __attribute__((packed)) cmdl;
struct {
uint8_t nlen;
char nbuf[11];
char _z;
} __attribute__((packed)) cmdn;
};
static int exec_ae01(struct ae0x *s)
{
__dpmi_regs r = {};
r.d.eax = 0xae01;
r.d.edx = 0xffff;
r.d.ecx = s->cmdn.nlen;
/* dosmemput() was already done before ae00 */
r.x.ds = __tb_segment;
r.d.ebx = __tb_offset;
r.d.esi = __tb_offset + sizeof(s->cmdl);
r.d.edi = 0;
set_env_seg();
__dpmi_int(0x2f, &r);
set_env_sel();
if (r.x.flags & CF)
return -1;
dosmemget(__tb, sizeof(*s), s);
return s->cmdn.nlen > 0;
}
int installable_command_check(char *cmd, const char *tail)
{
/* from RBIL
AX = AE00h
DX = magic value FFFFh
CH = FFh
CL = length of command line tail (4DOS v4.0)
DS:BX -> command line buffer (see #02977)
DS:SI -> command name buffer (see #02978)
DI = 0000h (4DOS v4.0)
Return:
AL = FFh if this command is a TSR extension to COMMAND.COM
AL = 00h if the command should be executed as usual
Format of COMMAND.COM command line buffer:
Offset Size Description (Table 02977)
00h BYTE max length of command line, as in INT 21/AH=0Ah
01h BYTE count of bytes to follow, excluding terminating 0Dh
N BYTEs command line text, terminated by 0Dh
Format of command name buffer:
Offset Size Description (Table 02978)
00h BYTE length of command name
01h N BYTEs uppercased command name (blank-padded to 11 chars by 4DOS v4)
*/
char *p;
char *q;
int i;
char *name;
int tlen;
int nlen;
__dpmi_regs r = {};
struct ae0x s = {};
int rc;
p = strrchr(cmd, '\\');
if (p)
name = p + 1;
else
name = cmd;
nlen = 0;
for (p = name, q = &s.cmdn.nbuf[0], i = 0; *p; p++) {
if (*p == '.') {
nlen = i;
if (i < 8) {
memset(q + i, ' ', 8 - i);
i = 8;
}
continue;
}
if (i >= sizeof(s.cmdn.nbuf))
return -1;
q[i++] = toupper(*p);
}
if (i < 11)
memset(q + i, ' ', 11 - i);
if (!nlen) // no dot found
nlen = i;
s.cmdn.nlen = nlen; // does not cover extension
if (strlen(cmd) + strlen(tail) + 2 >= sizeof(s.cmdl.cbuf))
return -1;
s.cmdl.cmax = sizeof(s.cmdl.cbuf) - 1;
if (tail[0]) {
s.cmdl.clen = snprintf(s.cmdl.cbuf, sizeof(s.cmdl.cbuf),
"%s %s\r", cmd, tail) - 1;
tlen = strlen(tail) + 1; // account for 'space'
} else {
s.cmdl.clen = snprintf(s.cmdl.cbuf, sizeof(s.cmdl.cbuf), "%s\r", cmd) - 1;
tlen = 0;
}
r.d.eax = 0xae00;
r.d.ecx = 0xff00 + tlen;
r.d.edx = 0xffff;
r.x.ds = __tb_segment;
r.d.ebx = __tb_offset;
r.d.esi = __tb_offset + sizeof(s.cmdl);
r.d.edi = 0;
dosmemput(&s, sizeof(s), __tb);
set_env("PATH", getenv("PATH"));
set_env_seg();
__dpmi_int(0x2f, &r);
set_env_sel();
if (r.x.flags & CF)
return -1;
dosmemget(__tb, sizeof(s), &s);
if (r.h.al != 0xff)
return 1;
rc = exec_ae01(&s);
if (rc != -1)
get_env();
if (rc <= 0)
return rc;
/* dont trust nlen here as it contains the old value */
memcpy(name, s.cmdn.nbuf, sizeof(s.cmdn.nbuf));
name[sizeof(s.cmdn.nbuf)] = '\0';
q = strchr(name, ' ');
if (!q)
{
/* insert dot */
memmove(name + 9, name + 8, 4); // 4 includes \0
name[8] = '.';
}
else
{
int spn;
*q = '.';
q++;
spn = strspn(q, " ");
if (spn)
memmove(q, q + spn, strlen(q + spn) + 1);
}
return 1;
}