static UWORD patchPSP(UWORD pspseg, UWORD envseg, exec_blk FAR *exb, BYTE FAR * fnam) { psp FAR *psp; mcb FAR *pspmcb; int i; BYTE FAR *np; pspmcb = MK_FP(pspseg, 0); ++pspseg; psp = MK_FP(pspseg, 0); /* complete the psp by adding the command line and FCBs */ fbcopy(exb->exec.cmd_line->ctBuffer, psp->ps_cmd, 127); fbcopy(exb->exec.fcb_1, &psp->ps_fcb1, 16); fbcopy(exb->exec.fcb_2, &psp->ps_fcb2, 16); psp->ps_cmd_count = exb->exec.cmd_line->ctCount; /* identify the mcb as this functions' */ pspmcb->m_psp = pspseg; /* Patch in environment segment, if present, also adjust its MCB */ if (envseg) { psp->ps_environ = envseg + 1; ((mcb FAR *) MK_FP(envseg, 0))->m_psp = pspseg; } else psp->ps_environ = 0; /* use the file name less extension - left adjusted and */ np = fnam; for (;;) { switch (*fnam++) { case '\0': goto set_name; case ':': case '/': case '\\': np = fnam; } } set_name: for (i = 0; i < 8 && np[i] != '.' && np[i] != '\0'; i++) { pspmcb->m_name[i] = toupper(np[i]); } if (i < 8) pspmcb->m_name[i] = '\0'; /* return value: AX value to be passed based on FCB values */ return ((psp->ps_fcb1.fcb_drive<lastdrive && CDSp->cds_table[psp->ps_fcb1.fcb_drive].cdsFlags & CDSVALID) ? 0 : 0xff) + ((psp->ps_fcb2.fcb_drive<lastdrive && CDSp->cds_table[psp->ps_fcb2.fcb_drive].cdsFlags & CDSVALID) ? 0 : 0xff) * 0x100; }
BOOL FcbFindNext(xfcb FAR * lpXfcb) { BYTE FAR *lpDir; COUNT FcbDrive; psp FAR *lpPsp = MK_FP(cu_psp, 0); /* First, move the dta to a local and change it around to match */ /* our functions. */ lpDir = (BYTE FAR *) dta; dta = (BYTE FAR *) & Dmatch; /* Next initialze local variables by moving them from the fcb */ lpFcb = CommonFcbInit(lpXfcb, SecPathName, &FcbDrive); /* Reconstrct the dirmatch structure from the fcb */ Dmatch.dm_drive = lpFcb->fcb_sftno; fbcopy(lpFcb->fcb_fname, (BYTE FAR *) Dmatch.dm_name_pat, FNAME_SIZE + FEXT_SIZE); DosUpFMem((BYTE FAR *) Dmatch.dm_name_pat, FNAME_SIZE + FEXT_SIZE); Dmatch.dm_attr_srch = wAttr; Dmatch.dm_entry = lpFcb->fcb_strtclst; Dmatch.dm_dircluster = lpFcb->fcb_dirclst; if ((xfcb FAR *) lpFcb != lpXfcb) { wAttr = lpXfcb->xfcb_attrib; fbcopy(lpXfcb, lpDir, 7); lpDir += 7; } else wAttr = D_ALL; if (DosFindNext() != SUCCESS) { dta = lpPsp->ps_dta; CritErrCode = 0x12; return FALSE; } *lpDir++ = FcbDrive; fmemcpy((struct dirent FAR *)lpDir, &SearchDir, sizeof(struct dirent)); lpFcb->fcb_dirclst = (UWORD)Dmatch.dm_dircluster; lpFcb->fcb_strtclst = Dmatch.dm_entry; lpFcb->fcb_sftno = Dmatch.dm_drive; #if 0 lpFcb->fcb_cublock = Dmatch.dm_entry; lpFcb->fcb_cublock *= 0x100; lpFcb->fcb_cublock += wAttr; #endif dta = lpPsp->ps_dta; return TRUE; }
static VOID DosGetFile(BYTE FAR * lpszPath, BYTE FAR * lpszDosFileName) { BYTE szLclName[FNAME_SIZE + 1]; BYTE szLclExt[FEXT_SIZE + 1]; ParseDosName(lpszPath, (COUNT *) 0, (BYTE *) 0, szLclName, szLclExt, FALSE); SpacePad(szLclName, FNAME_SIZE); SpacePad(szLclExt, FEXT_SIZE); fbcopy((BYTE FAR *) szLclName, lpszDosFileName, FNAME_SIZE); fbcopy((BYTE FAR *) szLclExt, &lpszDosFileName[FNAME_SIZE], FEXT_SIZE); }
BOOL FcbFindNext(xfcb FAR * lpXfcb) { BYTE FAR *lpOldDta; BYTE FAR *lpDir; COUNT nIdx, FcbDrive; psp FAR *lpPsp = MK_FP(cu_psp, 0); /* First, move the dta to a local and change it around to match */ /* our functions. */ lpDir = (BYTE FAR *) dta; dta = (BYTE FAR *) & Dmatch; /* Next initialze local variables by moving them from the fcb */ lpFcb = CommonFcbInit(lpXfcb, PriPathName, &FcbDrive); if ((xfcb FAR *) lpFcb != lpXfcb) { wAttr = lpXfcb->xfcb_attrib; fbcopy(lpXfcb, lpDir, 7); lpDir += 7; } else wAttr = D_ALL; /* Reconstrct the dirmatch structure from the fcb */ *lpDir++ = FcbDrive; Dmatch.dm_drive = FcbDrive ? FcbDrive - 1 : default_drive; fbcopy(lpFcb->fcb_fname, (BYTE FAR *) Dmatch.dm_name_pat, FNAME_SIZE + FEXT_SIZE); upMem((BYTE FAR *) Dmatch.dm_name_pat, FNAME_SIZE + FEXT_SIZE); Dmatch.dm_attr_srch = wAttr; Dmatch.dm_entry = lpFcb->fcb_diroff; Dmatch.dm_cluster = lpFcb->fcb_dirclst; if (dos_findnext() != SUCCESS) { dta = lpPsp->ps_dta; return FALSE; } MoveDirInfo((dmatch FAR *) & Dmatch, (struct dirent FAR *)lpDir); lpFcb->fcb_dirclst = Dmatch.dm_cluster; lpFcb->fcb_diroff = Dmatch.dm_entry; dta = lpPsp->ps_dta; return TRUE; }
BOOL FcbFindFirst(xfcb FAR * lpXfcb) { BYTE FAR *lpDir; COUNT FcbDrive; psp FAR *lpPsp = MK_FP(cu_psp, 0); /* First, move the dta to a local and change it around to match */ /* our functions. */ lpDir = (BYTE FAR *) dta; dta = (BYTE FAR *) & Dmatch; /* Next initialze local variables by moving them from the fcb */ lpFcb = CommonFcbInit(lpXfcb, SecPathName, &FcbDrive); if (lpXfcb->xfcb_flag == 0xff) { wAttr = lpXfcb->xfcb_attrib; fbcopy(lpXfcb, lpDir, 7); lpDir += 7; } else wAttr = D_ALL; if (DosFindFirst(wAttr, SecPathName) != SUCCESS) { dta = lpPsp->ps_dta; return FALSE; } *lpDir++ = FcbDrive; fmemcpy(lpDir, &SearchDir, sizeof(struct dirent)); lpFcb->fcb_dirclst = (UWORD)Dmatch.dm_dircluster; lpFcb->fcb_strtclst = Dmatch.dm_entry; /* This is undocumented and seen using Pcwatch and Ramview. The First byte is the current directory count and the second seems to be the attribute byte. */ lpFcb->fcb_sftno = Dmatch.dm_drive; /* MSD seems to save this @ fcb_date.*/ #if 0 lpFcb->fcb_cublock = Dmatch.dm_entry; lpFcb->fcb_cublock *= 0x100; lpFcb->fcb_cublock += wAttr; #endif dta = lpPsp->ps_dta; return TRUE; }
BOOL FcbFindFirst(xfcb FAR * lpXfcb) { BYTE FAR *lpOldDta; BYTE FAR *lpDir; COUNT nIdx, FcbDrive; psp FAR *lpPsp = MK_FP(cu_psp, 0); /* First, move the dta to a local and change it around to match */ /* our functions. */ lpDir = (BYTE FAR *) dta; dta = (BYTE FAR *) & Dmatch; /* Next initialze local variables by moving them from the fcb */ lpFcb = CommonFcbInit(lpXfcb, PriPathName, &FcbDrive); if (lpXfcb->xfcb_flag == 0xff) { wAttr = lpXfcb->xfcb_attrib; fbcopy(lpXfcb, lpDir, 7); lpDir += 7; } else wAttr = D_ALL; *lpDir++ = PriPathName[0] - 'A'; if (dos_findfirst(wAttr, PriPathName) != SUCCESS) { dta = lpPsp->ps_dta; return FALSE; } MoveDirInfo((dmatch FAR *) & Dmatch, (struct dirent FAR *)lpDir); lpFcb->fcb_dirclst = Dmatch.dm_cluster; lpFcb->fcb_diroff = Dmatch.dm_entry; dta = lpPsp->ps_dta; return TRUE; }
int main(int argc, char **argv) { DADSM dadsm; // DADSM workarea FILE *fout = NULL; // output file CIFBLK *cif; int dsn_recs_written = 0, bail, dsorg, rc; char pathname[MAX_PATH]; fprintf(stderr, "dasdseq %s (C) Copyright 1999-2010 Roger Bowler\n" "Portions (C) Copyright 2001-2010 James M. Morrison\n", VERSION); if (debug) fprintf(stderr, "DEBUG enabled\n"); // Parse command line memset(&dadsm, 0, sizeof(dadsm)); // init DADSM workarea rc = parsecmd(argc, argv, &dadsm); if (rc) exit(rc); // Open CKD image cif = open_ckd_image(din, sfn, O_RDONLY | O_BINARY, 0); if (!cif) { fprintf(stderr, "dasdseq unable to open image file %s\n", din); exit(20); } // Unless -abs specified (in which case trust the expert user): // Retrieve extent information for the dataset // Display dataset attributes // Verify dataset has acceptable attributes if (!absvalid) { rc = dadsm_setup(cif, &argdsn, &dadsm, local_verbose); if (rc) { close_ckd_image(cif); exit(rc); } if (local_verbose) { fprintf(stderr, "\n"); showf1(stderr, &dadsm.f1buf, dadsm.f1ext, copy_verbose); fprintf(stderr, "\n"); } bail = 1; dsorg = (dadsm.f1buf.ds1dsorg[0] << 8) | (dadsm.f1buf.ds1dsorg[1]); if (dsorg & (DSORG_PS * 256)) { if ((dadsm.f1buf.ds1recfm & RECFM_FORMAT) == RECFM_FORMAT_F) bail = 0; if ((dadsm.f1buf.ds1recfm & RECFM_FORMAT) == RECFM_FORMAT_V) { bail = 1; // not yet fprintf(stderr, "dasdseq only supports RECFM=F[B]\n"); } } else fprintf(stderr, "dasdseq only supports DSORG=PS datasets\n"); if (bail) { close_ckd_image(cif); exit(21); } } // Open output dataset (EBCDIC requires binary open) hostpath(pathname, argdsn, sizeof(pathname)); fout = fopen(pathname, (tran_ascii) ? "wb" : "w"); if (fout == NULL) { fprintf(stderr, "dasdseq unable to open output file %s, %s\n", argdsn, strerror(errno)); close_ckd_image(cif); exit(22); } if (local_verbose) fprintf(stderr, "dasdseq writing %s\n", argdsn); // Write dasd data to output dataset dsn_recs_written = fbcopy(fout, cif, &dadsm, tran_ascii, copy_verbose); if (dsn_recs_written == -1) fprintf(stderr, "dasdseq error processing %s\n", argdsn); else fprintf(stderr, "dasdseq wrote %d records to %s\n", dsn_recs_written, argdsn); // Close output dataset, dasd image and return to caller fclose(fout); if (local_verbose > 2) fprintf(stderr, "CLOSED %s\n", argdsn); if (local_verbose > 3) { fprintf(stderr, "CIFBLK\n"); data_dump((void *) cif, sizeof(CIFBLK)); } close_ckd_image(cif); if (local_verbose > 2) fprintf(stderr, "CLOSED image\n"); return rc; } /* main */
COUNT DosOpen(BYTE FAR * fname, COUNT mode) { psp FAR *p = MK_FP(cu_psp, 0); WORD hndl; WORD sft_idx; sft FAR *sftp; struct dhdr FAR *dhp; BYTE FAR *froot; WORD i; /* test if mode is in range */ if ((mode & ~SFT_OMASK) != 0) return DE_INVLDACC; mode &= 3; /* get a free handle */ if ((hndl = get_free_hndl()) == 0xff) return DE_TOOMANY; OpenMode = (BYTE) mode; /* now get a free system file table entry */ if ((sftp = get_free_sft((WORD FAR *) & sft_idx)) == (sft FAR *) - 1) return DE_TOOMANY; /* check for a device */ froot = get_root(fname); for (i = 0; i < FNAME_SIZE; i++) { if (*froot != '\0' && *froot != '.') PriPathName[i] = *froot++; else break; } for (; i < FNAME_SIZE; i++) PriPathName[i] = ' '; /* if we have an extension, can't be a device */ if (*froot != '.') { for (dhp = (struct dhdr FAR *)&nul_dev; dhp != (struct dhdr FAR *)-1; dhp = dhp->dh_next) { if (fnmatch((BYTE FAR *) PriPathName, (BYTE FAR *) dhp->dh_name, FNAME_SIZE, FALSE)) { sftp->sft_count += 1; sftp->sft_mode = mode; sftp->sft_attrib = 0; sftp->sft_flags = ((dhp->dh_attr & ~SFT_MASK) & ~SFT_FSHARED) | SFT_FDEVICE | SFT_FEOF; sftp->sft_psp = cu_psp; fbcopy((BYTE FAR *) PriPathName, sftp->sft_name, FNAME_SIZE + FEXT_SIZE); sftp->sft_dev = dhp; sftp->sft_date = dos_getdate(); sftp->sft_time = dos_gettime(); p->ps_filetab[hndl] = sft_idx; return hndl; } } } if (Remote_OCT(REM_OPEN, fname, mode, sftp) == 0) { if (sftp->sft_flags & SFT_FSHARED) { sftp->sft_count += 1; p->ps_filetab[hndl] = sft_idx; return hndl; } } sftp->sft_status = dos_open(fname, mode); if (sftp->sft_status >= 0) { struct f_node FAR *fnp = xlt_fd(sftp->sft_status); sftp->sft_attrib = fnp->f_dir.dir_attrib; /* Check permissions. -- JPP */ if ((sftp->sft_attrib & (D_DIR | D_VOLID)) || ((sftp->sft_attrib & D_RDONLY) && (mode != O_RDONLY))) { return DE_ACCESS; } p->ps_filetab[hndl] = sft_idx; sftp->sft_count += 1; sftp->sft_mode = mode; sftp->sft_attrib = 0; sftp->sft_flags = 0; sftp->sft_psp = cu_psp; DosGetFile(fname, sftp->sft_name); return hndl; } else return sftp->sft_status; }
COUNT DosCreat(BYTE FAR * fname, COUNT attrib) { psp FAR *p = MK_FP(cu_psp, 0); WORD hndl, sft_idx; sft FAR *sftp; struct dhdr FAR *dhp; BYTE FAR *froot; WORD i; /* get a free handle */ if ((hndl = get_free_hndl()) == 0xff) return DE_TOOMANY; /* now get a free system file table entry */ if ((sftp = get_free_sft((WORD FAR *) & sft_idx)) == (sft FAR *) - 1) return DE_TOOMANY; /* check for a device */ froot = get_root(fname); for (i = 0; i < FNAME_SIZE; i++) { if (*froot != '\0' && *froot != '.') PriPathName[i] = *froot++; else break; } for (; i < FNAME_SIZE; i++) PriPathName[i] = ' '; /* if we have an extension, can't be a device */ if (*froot != '.') { for (dhp = (struct dhdr FAR *)&nul_dev; dhp != (struct dhdr FAR *)-1; dhp = dhp->dh_next) { if (fnmatch((BYTE FAR *) PriPathName, (BYTE FAR *) dhp->dh_name, FNAME_SIZE, FALSE)) { sftp->sft_count += 1; sftp->sft_mode = SFT_MRDWR; sftp->sft_attrib = attrib; sftp->sft_flags = ((dhp->dh_attr & ~SFT_MASK) & ~SFT_FSHARED) | SFT_FDEVICE | SFT_FEOF; sftp->sft_psp = cu_psp; fbcopy((BYTE FAR *) PriPathName, sftp->sft_name, FNAME_SIZE + FEXT_SIZE); sftp->sft_dev = dhp; p->ps_filetab[hndl] = sft_idx; return hndl; } } } if (Remote_OCT(REM_CREATE, fname, attrib, sftp) == 0) { if (sftp->sft_flags & SFT_FSHARED) { sftp->sft_count += 1; p->ps_filetab[hndl] = sft_idx; return hndl; } } sftp->sft_status = dos_creat(fname, attrib); if (sftp->sft_status >= 0) { p->ps_filetab[hndl] = sft_idx; sftp->sft_count += 1; sftp->sft_mode = SFT_MRDWR; sftp->sft_attrib = attrib; sftp->sft_flags = 0; sftp->sft_psp = cu_psp; DosGetFile(fname, sftp->sft_name); return hndl; } else return sftp->sft_status; }
/* * The `force_binary' parameter is a hack to allow functions 0x01, 0x06, 0x07, * and function 0x40 to use the same code for performing reads, even though the * two classes of functions behave quite differently: 0x01 etc. always do * binary reads, while for 0x40 the type of read (binary/text) depends on what * the SFT says. -- ror4 */ UCOUNT GenericRead(COUNT hndl, UCOUNT n, BYTE FAR * bp, COUNT FAR * err, BOOL force_binary) { sft FAR *s; WORD sys_idx; sfttbl FAR *sp; UCOUNT ReadCount; /* Test that the handle is valid */ if (hndl < 0) { *err = DE_INVLDHNDL; return 0; } /* Get the SFT block that contains the SFT */ if ((s = get_sft(hndl)) == (sft FAR *) - 1) { *err = DE_INVLDHNDL; return 0; } /* If not open or write permission - exit */ if (s->sft_count == 0 || (s->sft_mode & SFT_MWRITE)) { *err = DE_INVLDACC; return 0; } /* * Do remote first or return error. * must have been opened from remote. */ if (s->sft_flags & SFT_FSHARED) { ReadCount = Remote_RW(REM_READ, n, bp, s, err); if (err) { *err = SUCCESS; return ReadCount; } else return 0; } /* Do a device read if device */ if (s->sft_flags & SFT_FDEVICE) { request rq; /* First test for eof and exit */ /* immediately if it is */ if (!(s->sft_flags & SFT_FEOF) || (s->sft_flags & SFT_FNUL)) { s->sft_flags &= ~SFT_FEOF; *err = SUCCESS; return 0; } /* Now handle raw and cooked modes */ if (force_binary || (s->sft_flags & SFT_FBINARY)) { rq.r_length = sizeof(request); rq.r_command = C_INPUT; rq.r_count = n; rq.r_trans = (BYTE FAR *) bp; rq.r_status = 0; execrh((request FAR *) & rq, s->sft_dev); if (rq.r_status & S_ERROR) { char_error(&rq, s->sft_dev); } else { *err = SUCCESS; return rq.r_count; } } else if (s->sft_flags & SFT_FCONIN) { kb_buf.kb_size = LINESIZE - 1; kb_buf.kb_count = 0; sti((keyboard FAR *) & kb_buf); fbcopy((BYTE FAR *) kb_buf.kb_buf, bp, kb_buf.kb_count); *err = SUCCESS; return kb_buf.kb_count; } else { *bp = _sti(); *err = SUCCESS; return 1; } } else /* a block read */ { COUNT rc; ReadCount = readblock(s->sft_status, bp, n, &rc); if (rc != SUCCESS) { *err = rc; return 0; } else { *err = SUCCESS; return ReadCount; } } *err = SUCCESS; return 0; }
COUNT ChildEnv(exec_blk FAR * exp, UWORD * pChildEnvSeg, char far * pathname) { BYTE FAR *pSrc; BYTE FAR *pDest; UWORD nEnvSize; COUNT RetCode; /* UWORD MaxEnvSize; not used -- 1999/04/21 ska */ psp FAR *ppsp = MK_FP(cu_psp, 0); /* create a new environment for the process */ /* copy parent's environment if exec.env_seg == 0 */ pSrc = exp->exec.env_seg ? MK_FP(exp->exec.env_seg, 0) : MK_FP(ppsp->ps_environ, 0); #if 0 /* Every process requires an environment because of argv[0] -- 1999/04/21 ska */ */ if (!pSrc) /* no environment to copy */ { *pChildEnvSeg = 0; return SUCCESS; } #endif nEnvSize = 1; /* This loop had not counted the very last '\0' -- 1999/04/21 ska */ if (pSrc) { /* if no environment is available, one byte is required */ for (nEnvSize = 0; ; nEnvSize++) { /* Test env size and abort if greater than max */ if (nEnvSize >= MAXENV - ENV_KEEPFREE) return DE_INVLDENV; if (*(UWORD FAR *)(pSrc+nEnvSize) == 0) break; } nEnvSize += 2; /* account for trailing \0\0 */ } /* allocate enough space for env + path */ if ((RetCode = DosMemAlloc(long2para(nEnvSize + ENV_KEEPFREE), mem_access_mode, (seg FAR *) pChildEnvSeg, NULL /*(UWORD FAR *) MaxEnvSize ska */ )) < 0) return RetCode; pDest = MK_FP(*pChildEnvSeg + 1, 0); /* fill the new env and inform the process of its */ /* location throught the psp */ /* copy the environment */ if (pSrc) { fbcopy(pSrc, pDest, nEnvSize); pDest += nEnvSize; } else *pDest++ = '\0'; /* create an empty environment */ /* initialize 'extra strings' count */ *((UWORD FAR *) pDest)++ = 1; /* copy complete pathname */ if ((RetCode = truename(pathname, pDest, TRUE)) != SUCCESS) { return RetCode; } /* Theoretically one could either: + resize the already allocated block to best-fit behind the pathname, or + generate the filename into a temporary buffer to allocate only the minimum required environment -- 1999/04/21 ska */ return SUCCESS; }
BOOL FcbOpen(xfcb FAR * lpXfcb) { WORD sft_idx; sft FAR *sftp; struct dhdr FAR *dhp; COUNT FcbDrive; /* get a free system file table entry */ if ((sftp = FcbGetFreeSft((WORD FAR *) & sft_idx)) == (sft FAR *) - 1) return DE_TOOMANY; /* Build a traditional DOS file name */ lpFcb = CommonFcbInit(lpXfcb, PriPathName, &FcbDrive); /* check for a device */ /* if we have an extension, can't be a device */ if (IsDevice(PriPathName)) { for (dhp = (struct dhdr FAR *)&nul_dev; dhp != (struct dhdr FAR *)-1; dhp = dhp->dh_next) { if (FcbFnameMatch((BYTE FAR *) PriPathName, (BYTE FAR *) dhp->dh_name, FNAME_SIZE, FALSE)) { sftp->sft_count += 1; sftp->sft_mode = O_RDWR; sftp->sft_attrib = 0; sftp->sft_flags = (dhp->dh_attr & ~SFT_MASK) | SFT_FDEVICE | SFT_FEOF; sftp->sft_psp = cu_psp; fbcopy(lpFcb->fcb_fname, sftp->sft_name, FNAME_SIZE + FEXT_SIZE); sftp->sft_dev = dhp; lpFcb->fcb_sftno = sft_idx; lpFcb->fcb_curec = 0; lpFcb->fcb_recsiz = 0; lpFcb->fcb_fsize = 0; lpFcb->fcb_date = dos_getdate(); lpFcb->fcb_time = dos_gettime(); lpFcb->fcb_rndm = 0; return TRUE; } } } sftp->sft_status = dos_open(PriPathName, O_RDWR); if (sftp->sft_status >= 0) { lpFcb->fcb_drive = FcbDrive; lpFcb->fcb_sftno = sft_idx; lpFcb->fcb_curec = 0; lpFcb->fcb_recsiz = 128; lpFcb->fcb_fsize = dos_getfsize(sftp->sft_status); dos_getftime(sftp->sft_status, (date FAR *) & lpFcb->fcb_date, (time FAR *) & lpFcb->fcb_time); lpFcb->fcb_rndm = 0; sftp->sft_count += 1; sftp->sft_mode = O_RDWR; sftp->sft_attrib = 0; sftp->sft_flags = 0; sftp->sft_psp = cu_psp; fbcopy((BYTE FAR *) & lpFcb->fcb_fname, (BYTE FAR *) & sftp->sft_name, FNAME_SIZE + FEXT_SIZE); return TRUE; } else return FALSE; }
VOID int21_service(iregs FAR * r) { COUNT rc = 0, rc1; psp FAR *p = MK_FP(cu_psp, 0); void FAR *FP_DS_DX = MK_FP(r->DS, r->DX); /* this is saved so often, that this saves ~100 bytes */ #define CLEAR_CARRY_FLAG() r->FLAGS &= ~FLG_CARRY #define SET_CARRY_FLAG() r->FLAGS |= FLG_CARRY p->ps_stack = (BYTE FAR *) r; #ifdef DEBUG if (bDumpRegs) { fbcopy((VOID FAR *) user_r, (VOID FAR *) & error_regs, sizeof(iregs)); printf("System call (21h): %02x\n", user_r->AX); dump_regs = TRUE; dump(); } #endif if(r->AH >=0x38 && r->AH <= 0x4F) CLEAR_CARRY_FLAG(); /* Clear carry by default for these functions */ dispatch: /* Check for Ctrl-Break */ switch (r->AH) { default: if (!break_ena) break; case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x08: case 0x09: case 0x0a: case 0x0b: if (control_break()) handle_break(); } /* The dispatch handler */ switch (r->AH) { /* int 21h common error handler */ case 0x64: error_invalid: r->AX = -DE_INVLDFUNC; goto error_out; error_exit: r->AX = -rc; error_out: CritErrCode = r->AX; /* Maybe set */ SET_CARRY_FLAG(); break; /* case 0x00: --> Simulate a DOS-4C-00 */ /* Read Keyboard with Echo */ case 0x01: r->AL = _sti(TRUE); sto(r->AL); break; /* Display Character */ case 0x02: sto(r->DL); break; /* Auxiliary Input */ case 0x03: { COUNT scratch; GenericRead(STDAUX, 1, (BYTE FAR *) & r->AL, (COUNT FAR *) & scratch, TRUE); break; } /* Auxiliary Output */ case 0x04: { COUNT scratch; DosWrite(STDAUX, 1, (BYTE FAR *) & r->DL, (COUNT FAR *) &scratch); break; } /* Print Character */ case 0x05: { COUNT scratch; DosWrite(STDPRN, 1, (BYTE FAR *) & r->DL, (COUNT FAR *) &scratch); break; } /* Direct Console I/O */ case 0x06: if (r->DL != 0xff) sto(r->DL); else if (StdinBusy()) { r->AL = 0x00; r->FLAGS |= FLG_ZERO; } else { r->FLAGS &= ~FLG_ZERO; r->AL = _sti(FALSE); } break; /* Direct Console Input */ case 0x07: r->AL = _sti(FALSE); break; /* Read Keyboard Without Echo */ case 0x08: r->AL = _sti(TRUE); break; /* Display String */ case 0x09: { BYTE FAR * q; q = FP_DS_DX; while (*q != '$') ++q; DosWrite(STDOUT, FP_OFF(q) - FP_OFF(FP_DS_DX), FP_DS_DX, (COUNT FAR *) & UnusedRetVal); } r->AL = '$'; break; /* Buffered Keyboard Input */ case 0x0a: sti_0a((keyboard FAR *) FP_DS_DX); break; /* Check Stdin Status */ case 0x0b: if (StdinBusy()) r->AL = 0x00; else r->AL = 0xFF; break; /* Flush Buffer, Read Keayboard */ case 0x0c: KbdFlush(); switch (r->AL) { case 0x01: case 0x06: case 0x07: case 0x08: case 0x0a: r->AH = r->AL; goto dispatch; default: r->AL = 0x00; break; } break; /* Reset Drive */ case 0x0d: flush(); break; /* Set Default Drive */ case 0x0e: r->AL = DosSelectDrv(r->DL); break; case 0x0f: if (FcbOpen(FP_DS_DX)) r->AL = 0; else r->AL = 0xff; break; case 0x10: if (FcbClose(FP_DS_DX)) r->AL = 0; else r->AL = 0xff; break; case 0x11: if (FcbFindFirst(FP_DS_DX)) r->AL = 0; else r->AL = 0xff; break; case 0x12: if (FcbFindNext(FP_DS_DX)) r->AL = 0; else r->AL = 0xff; break; case 0x13: if (FcbDelete(FP_DS_DX)) r->AL = 0; else r->AL = 0xff; break; case 0x14: { if (FcbRead(FP_DS_DX, &CritErrCode)) r->AL = 0; else r->AL = CritErrCode; break; } case 0x15: { if (FcbWrite(FP_DS_DX, &CritErrCode)) r->AL = 0; else r->AL = CritErrCode; break; } case 0x16: if (FcbCreate(FP_DS_DX)) r->AL = 0; else r->AL = 0xff; break; case 0x17: if (FcbRename(FP_DS_DX)) r->AL = 0; else r->AL = 0xff; break; default: #ifdef DEBUG printf("Unsupported INT21 AH = 0x%x, AL = 0x%x.\n", r->AH, r->AL); #endif /* Fall through. */ /* CP/M compatibility functions */ case 0x18: case 0x1d: case 0x1e: case 0x20: #ifndef TSC case 0x61: #endif case 0x6b: r->AL = 0; break; /* Get Default Drive */ case 0x19: r->AL = default_drive; break; /* Set DTA */ case 0x1a: { psp FAR *p = MK_FP(cu_psp, 0); p->ps_dta = FP_DS_DX; dos_setdta(p->ps_dta); } break; /* Get Default Drive Data */ case 0x1b: { BYTE FAR *p; FatGetDrvData(0, (COUNT FAR *) & r->AX, (COUNT FAR *) & r->CX, (COUNT FAR *) & r->DX, (BYTE FAR **) & p); r->DS = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Get Drive Data */ case 0x1c: { BYTE FAR *p; FatGetDrvData(r->DL, (COUNT FAR *) & r->AX, (COUNT FAR *) & r->CX, (COUNT FAR *) & r->DX, (BYTE FAR **) & p); r->DS = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Get default DPB */ /* case 0x1f: see case 0x32 */ /* Random read using FCB */ case 0x21: { if (FcbRandomIO(FP_DS_DX, &CritErrCode, FcbRead)) r->AL = 0; else r->AL = CritErrCode; break; } /* Random write using FCB */ case 0x22: { if (FcbRandomIO(FP_DS_DX, &CritErrCode, FcbWrite)) r->AL = 0; else r->AL = CritErrCode; break; } /* Get file size in records using FCB */ case 0x23: if (FcbGetFileSize(FP_DS_DX)) r->AL = 0; else r->AL = 0xff; break; /* Set random record field in FCB */ case 0x24: FcbSetRandom(FP_DS_DX); break; /* Set Interrupt Vector */ case 0x25: { VOID(INRPT FAR * p) () = FP_DS_DX; setvec(r->AL, p); } break; /* Dos Create New Psp */ case 0x26: { psp FAR *p = MK_FP(cu_psp, 0); new_psp((psp FAR *) MK_FP(r->DX, 0), p->ps_size); } break; /* Read random record(s) using FCB */ case 0x27: { if (FcbRandomBlockRead(FP_DS_DX, r->CX, &CritErrCode)) r->AL = 0; else r->AL = CritErrCode; break; } /* Write random record(s) using FCB */ case 0x28: { if (FcbRandomBlockWrite(FP_DS_DX, r->CX, &CritErrCode)) r->AL = 0; else r->AL = CritErrCode; break; } /* Parse File Name */ case 0x29: { BYTE FAR *lpFileName; lpFileName = MK_FP(r->DS, r->SI); r->AL = FcbParseFname(r->AL, &lpFileName, MK_FP(r->ES, r->DI)); r->DS = FP_SEG(lpFileName); r->SI = FP_OFF(lpFileName); } break; /* Get Date */ case 0x2a: DosGetDate( (BYTE FAR *) & (r->AL), /* WeekDay */ (BYTE FAR *) & (r->DH), /* Month */ (BYTE FAR *) & (r->DL), /* MonthDay */ (COUNT FAR *) & (r->CX)); /* Year */ break; /* Set Date */ case 0x2b: rc = DosSetDate( (BYTE FAR *) & (r->DH), /* Month */ (BYTE FAR *) & (r->DL), /* MonthDay */ (COUNT FAR *) & (r->CX)); /* Year */ if (rc != SUCCESS) r->AL = 0xff; else r->AL = 0; break; /* Get Time */ case 0x2c: DosGetTime( (BYTE FAR *) & (r->CH), /* Hour */ (BYTE FAR *) & (r->CL), /* Minutes */ (BYTE FAR *) & (r->DH), /* Seconds */ (BYTE FAR *) & (r->DL)); /* Hundredths */ break; /* Set Date */ case 0x2d: rc = DosSetTime( (BYTE FAR *) & (r->CH), /* Hour */ (BYTE FAR *) & (r->CL), /* Minutes */ (BYTE FAR *) & (r->DH), /* Seconds */ (BYTE FAR *) & (r->DL)); /* Hundredths */ if (rc != SUCCESS) r->AL = 0xff; else r->AL = 0; break; /* Set verify flag */ case 0x2e: verify_ena = (r->AL ? TRUE : FALSE); break; /* Get DTA */ case 0x2f: r->ES = FP_SEG(dta); r->BX = FP_OFF(dta); break; /* Get DOS Version */ case 0x30: r->AL = os_major; r->AH = os_minor; r->BH = OEM_ID; r->CH = REVISION_MAJOR; /* JPP */ r->CL = REVISION_MINOR; r->BL = REVISION_SEQ; if (ReturnAnyDosVersionExpected) { /* TE for testing purpose only and NOT to be documented: return programs, who ask for version == XX.YY exactly this XX.YY. this makes most MS programs more happy. */ UBYTE FAR *retp = MK_FP(r->cs, r->ip); if ( retp[0] == 0x3d && /* cmp ax, xxyy */ (retp[3] == 0x75 || retp[3] == 0x74)) /* je/jne error */ { r->AL = retp[1]; r->AH = retp[2]; } else if(retp[0] == 0x86 && /* xchg al,ah */ retp[1] == 0xc4 && retp[2] == 0x3d && /* cmp ax, xxyy */ (retp[5] == 0x75 || retp[5] == 0x74)) /* je/jne error */ { r->AL = retp[4]; r->AH = retp[3]; } } break; /* Keep Program (Terminate and stay resident) */ case 0x31: DosMemChange(cu_psp, r->DX < 6 ? 6 : r->DX, 0); return_mode = 3; return_code = r->AL; tsr = TRUE; return_user(); break; /* Get default BPB */ case 0x1f: /* Get DPB */ case 0x32: /* r->DL is NOT changed by MS 6.22 */ /* INT21/32 is documented to reread the DPB */ { struct dpb FAR *dpb; UCOUNT drv = r->DL; if (drv == 0 || r->AH == 0x1f) drv = default_drive; else drv--; if (drv >= lastdrive) { r->AL = 0xFF; CritErrCode = 0x0f; break; } dpb = CDSp->cds_table[drv].cdsDpb; if (dpb == 0 || CDSp->cds_table[drv].cdsFlags & CDSNETWDRV) { r->AL = 0xFF; CritErrCode = 0x0f; break; } dpb->dpb_flags = M_CHANGED; /* force reread of drive BPB/DPB */ if (media_check(dpb) < 0) { r->AL = 0xff; CritErrCode = 0x0f; break; } r->DS = FP_SEG(dpb); r->BX = FP_OFF(dpb); r->AL = 0; } break; /* case 0x33: see int21_syscall */ /* Get InDOS flag */ case 0x34: { BYTE FAR *p; p = (BYTE FAR *) ((BYTE *) & InDOS); r->ES = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Get Interrupt Vector */ case 0x35: { BYTE FAR *p; p = getvec((COUNT) r->AL); r->ES = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Dos Get Disk Free Space */ case 0x36: DosGetFree( r->DL, (COUNT FAR *) & r->AX, (COUNT FAR *) & r->BX, (COUNT FAR *) & r->CX, (COUNT FAR *) & r->DX); break; /* Undocumented Get/Set Switchar */ case 0x37: switch (r->AL) { /* Get switch character */ case 0x00: r->DL = switchar; r->AL = 0x00; break; /* Set switch character */ case 0x01: switchar = r->DL; r->AL = 0x00; break; default: goto error_invalid; } break; /* Get/Set Country Info */ case 0x38: { UWORD cntry = r->AL; if(cntry == 0) cntry = (UWORD)-1; else if(cntry == 0xff) cntry = r->BX; if (0xffff == r->DX) { /* Set Country Code */ if((rc = DosSetCountry(cntry)) < 0) goto error_invalid; } else { /* Get Country Information */ if((rc = DosGetCountryInformation(cntry, FP_DS_DX)) < 0) goto error_invalid; /* HACK FIXME */ if(cntry == (UWORD)-1) cntry = 1; /* END OF HACK */ r->AX = r->BX = cntry; } } break; /* Dos Create Directory */ case 0x39: rc = DosMkdir((BYTE FAR *) FP_DS_DX); if (rc != SUCCESS) goto error_exit; break; /* Dos Remove Directory */ case 0x3a: rc = DosRmdir((BYTE FAR *) FP_DS_DX); if (rc != SUCCESS) goto error_exit; break; /* Dos Change Directory */ case 0x3b: if ((rc = DosChangeDir((BYTE FAR *) FP_DS_DX)) < 0) goto error_exit; break; /* Dos Create File */ case 0x3c: if ((rc = DosCreat(FP_DS_DX, r->CX)) < 0) goto error_exit; else r->AX = rc; break; /* Dos Open */ case 0x3d: if ((rc = DosOpen(FP_DS_DX, r->AL)) < 0) goto error_exit; else r->AX = rc; break; /* Dos Close */ case 0x3e: if ((rc = DosClose(r->BX)) < 0) goto error_exit; break; /* Dos Read */ case 0x3f: rc1 = DosRead(r->BX, r->CX, FP_DS_DX, (COUNT FAR *) & rc); if (rc != SUCCESS) goto error_exit; else r->AX = rc1; break; /* Dos Write */ case 0x40: rc1 = DosWrite(r->BX, r->CX, FP_DS_DX, (COUNT FAR *) & rc); if (rc != SUCCESS) goto error_exit; else r->AX = rc1; break; /* Dos Delete File */ case 0x41: rc = DosDelete((BYTE FAR *) FP_DS_DX); if (rc < 0) goto error_exit; break; /* Dos Seek */ case 0x42: { ULONG lrc; if ((rc = DosSeek(r->BX, (LONG) ((((LONG) (r->CX)) << 16) + r->DX), r->AL, &lrc)) < 0) goto error_exit; else { r->DX = (lrc >> 16); r->AX = (UWORD)lrc; } } break; /* Get/Set File Attributes */ case 0x43: switch (r->AL) { case 0x00: rc = DosGetFattr((BYTE FAR *) FP_DS_DX); if (rc >= SUCCESS) r->CX = rc; break; case 0x01: rc = DosSetFattr((BYTE FAR *) FP_DS_DX, r->CX); break; default: goto error_invalid; } if (rc < SUCCESS) goto error_exit; break; /* Device I/O Control */ case 0x44: rc = DosDevIOctl(r); if (rc != SUCCESS) goto error_exit; break; /* Duplicate File Handle */ case 0x45: rc = DosDup(r->BX); if (rc < SUCCESS) goto error_exit; else r->AX = rc; break; /* Force Duplicate File Handle */ case 0x46: rc = DosForceDup(r->BX, r->CX); if (rc < SUCCESS) goto error_exit; break; /* Get Current Directory */ case 0x47: if ((rc = DosGetCuDir(r->DL, MK_FP(r->DS, r->SI))) < 0) goto error_exit; else r->AX = 0x0100; /*jpp: from interrupt list */ break; /* Allocate memory */ case 0x48: if ((rc = DosMemAlloc(r->BX, mem_access_mode, &(r->AX), &(r->BX))) < 0) { DosMemLargest(&(r->BX)); goto error_exit; } else ++(r->AX); /* DosMemAlloc() returns seg of MCB rather than data */ break; /* Free memory */ case 0x49: if ((rc = DosMemFree((r->ES) - 1)) < 0) goto error_exit; break; /* Set memory block size */ case 0x4a: { UWORD maxSize; if ((rc = DosMemChange(r->ES, r->BX, &maxSize)) < 0) { if (rc == DE_NOMEM) r->BX = maxSize; #if 0 if (cu_psp == r->ES) { psp FAR *p; p = MK_FP(cu_psp, 0); p->ps_size = r->BX + cu_psp; } #endif goto error_exit; } break; } /* Load and Execute Program */ case 0x4b: break_flg = FALSE; if ((rc = DosExec(r->AL, MK_FP(r->ES, r->BX), FP_DS_DX)) != SUCCESS) goto error_exit; break; /* Terminate Program */ case 0x00: r->AX = 0x4c00; /* End Program */ case 0x4c: if (cu_psp == RootPsp || ((psp FAR *) (MK_FP(cu_psp, 0)))->ps_parent == cu_psp) break; tsr = FALSE; if (ErrorMode) { ErrorMode = FALSE; return_mode = 2; } else if (break_flg) { break_flg = FALSE; return_mode = 1; } else { return_mode = 0; } return_code = r->AL; if (DosMemCheck() != SUCCESS) panic("MCB chain corrupted"); #ifdef TSC StartTrace(); #endif return_user(); break; /* Get Child-program Return Value */ case 0x4d: r->AL = return_code; r->AH = return_mode; break; /* Dos Find First */ case 0x4e: /* dta for this call is set on entry. This */ /* needs to be changed for new versions. */ if ((rc = DosFindFirst((UCOUNT) r->CX, (BYTE FAR *) FP_DS_DX)) < 0) goto error_exit; r->AX = 0; break; /* Dos Find Next */ case 0x4f: /* dta for this call is set on entry. This */ /* needs to be changed for new versions. */ if ((rc = DosFindNext()) < 0) { if (rc == DE_FILENOTFND) rc = DE_NFILES; goto error_exit; } else r->AX = -SUCCESS; break; /* case 0x50: case 0x51: see int21_syscall */ /* ************UNDOCUMENTED************************************* */ /* Get List of Lists */ case 0x52: { BYTE FAR *p; p = (BYTE FAR *) & DPBp; r->ES = FP_SEG(p); r->BX = FP_OFF(p); } break; case 0x53: /* DOS 2+ internal - TRANSLATE BIOS PARAMETER BLOCK TO DRIVE PARAM BLOCK */ bpb_to_dpb((bpb FAR *)MK_FP(r->DS, r->SI), (struct dpb FAR *)MK_FP(r->ES, r->BP)); break; /* Get verify state */ case 0x54: r->AL = (verify_ena ? TRUE : FALSE); break; /* ************UNDOCUMENTED************************************* */ /* Dos Create New Psp & set p_size */ case 0x55: new_psp((psp FAR *) MK_FP(r->DX, 0), r->SI); cu_psp = r->DX; break; /* Dos Rename */ case 0x56: rc = DosRename((BYTE FAR *) FP_DS_DX, (BYTE FAR *) MK_FP(r->ES, r->DI)); if (rc < SUCCESS) goto error_exit; else CLEAR_CARRY_FLAG(); break; /* Get/Set File Date and Time */ case 0x57: CLEAR_CARRY_FLAG(); switch (r->AL) { case 0x00: rc = DosGetFtime( (COUNT) r->BX, /* Handle */ (date FAR *) & r->DX, /* FileDate */ (time FAR *) & r->CX); /* FileTime */ if (rc < SUCCESS) goto error_exit; break; case 0x01: rc = DosSetFtime( (COUNT) r->BX, /* Handle */ (date) r->DX, /* FileDate */ (time) r->CX); /* FileTime */ if (rc < SUCCESS) goto error_exit; break; default: goto error_invalid; } break; /* Get/Set Allocation Strategy */ case 0x58: CLEAR_CARRY_FLAG(); switch (r->AL) { case 0x00: r->AL = mem_access_mode; r->AH = 0; break; case 0x01: { switch (r->BL) { case LAST_FIT: case LAST_FIT_U: case LAST_FIT_UO: case BEST_FIT: case BEST_FIT_U: case BEST_FIT_UO: case FIRST_FIT: case FIRST_FIT_U: case FIRST_FIT_UO: mem_access_mode = r->BL; break; default: goto error_invalid; } } break; case 0x02: r->AL = uppermem_link; break; case 0x03: if (uppermem_root) { DosUmbLink(r->BL); break; } /* else fall through */ default: goto error_invalid; #ifdef DEBUG case 0xff: show_chain(); break; #endif } break; /* Get Extended Error */ case 0x59: r->AX = CritErrCode; r->ES = FP_SEG(CritErrDev); r->DI = FP_OFF(CritErrDev); r->CH = CritErrLocus; r->BH = CritErrClass; r->BL = CritErrAction; CLEAR_CARRY_FLAG(); break; /* Create Temporary File */ case 0x5a: if ((rc = DosMkTmp(FP_DS_DX, r->CX)) < 0) goto error_exit; else { r->AX = rc; CLEAR_CARRY_FLAG(); } break; /* Create New File */ case 0x5b: if (!IsDevice(FP_DS_DX) && (rc = DosOpen(FP_DS_DX, 0)) >= 0) { DosClose(rc); r->AX = 80; goto error_out; } else { if ((rc = DosCreat(FP_DS_DX, r->CX)) < 0) goto error_exit; else { r->AX = rc; CLEAR_CARRY_FLAG(); } } break; /* /// Added for SHARE. - Ron Cemer */ /* Lock/unlock file access */ case 0x5c: if ((rc = DosLockUnlock (r->BX, (((unsigned long)r->CX)<<16)|(((unsigned long)r->DX)&0xffffL), (((unsigned long)r->SI)<<16)|(((unsigned long)r->DI)&0xffffL), ((r->AX & 0xff) != 0))) != 0) goto error_exit; CLEAR_CARRY_FLAG(); break; /* /// End of additions for SHARE. - Ron Cemer */ /* UNDOCUMENTED: server, share.exe and sda function */ case 0x5d: switch (r->AL) { /* Remote Server Call */ case 0x00: { UWORD FAR *x = FP_DS_DX; r->AX = x[0]; r->BX = x[1]; r->CX = x[2]; r->DX = x[3]; r->SI = x[4]; r->DI = x[5]; r->DS = x[6]; r->ES = x[7]; } goto dispatch; case 0x06: r->DS = FP_SEG(internal_data); r->SI = FP_OFF(internal_data); r->CX = swap_always - internal_data; r->DX = swap_indos - internal_data; CLEAR_CARRY_FLAG(); break; case 0x07: case 0x08: case 0x09: rc = -int2f_Remote_call(REM_PRINTREDIR, 0, 0, r->DX, 0, 0, (MK_FP(0, Int21AX))); if (rc != SUCCESS) goto error_exit; CLEAR_CARRY_FLAG(); break; default: goto error_invalid; } break; case 0x5e: CLEAR_CARRY_FLAG(); switch (r->AL) { case 0x00: r->CX = get_machine_name(FP_DS_DX); break; case 0x01: set_machine_name(FP_DS_DX, r->CX); break; default: rc = -int2f_Remote_call(REM_PRINTSET, r->BX, r->CX, r->DX, (MK_FP(r->ES, r->DI)), r->SI, (MK_FP(r->DS, Int21AX))); if (rc != SUCCESS) goto error_exit; r->AX=SUCCESS; break; } break; case 0x5f: CLEAR_CARRY_FLAG(); switch (r->AL) { case 0x07: if (r->DL < lastdrive) { CDSp->cds_table[r->DL].cdsFlags |= 0x100; } break; case 0x08: if (r->DL < lastdrive) { CDSp->cds_table[r->DL].cdsFlags &= ~0x100; } break; default: /* void int_2f_111e_call(iregs FAR *r); int_2f_111e_call(r); break;*/ rc = -int2f_Remote_call(REM_DOREDIRECT, r->BX, r->CX, r->DX, (MK_FP(r->ES, r->DI)), r->SI, (MK_FP(r->DS, Int21AX))); if (rc != SUCCESS) goto error_exit; r->AX=SUCCESS; break; } break; case 0x60: /* TRUENAME */ CLEAR_CARRY_FLAG(); if ((rc = truename(MK_FP(r->DS, r->SI), adjust_far(MK_FP(r->ES, r->DI)), FALSE)) != SUCCESS) goto error_exit; break; #ifdef TSC /* UNDOCUMENTED: no-op */ /* */ /* DOS-C: tsc support */ case 0x61: #ifdef DEBUG switch (r->AL) { case 0x01: bTraceNext = TRUE; break; case 0x02: bDumpRegs = FALSE; break; } #endif r->AL = 0x00; break; #endif /* UNDOCUMENTED: return current psp case 0x62: is in int21_syscall r->BX = cu_psp; break; */ /* UNDOCUMENTED: Double byte and korean tables */ case 0x63: { #define DBLBYTE #ifdef DBLBYTE static char dbcsTable[2] = { 0, 0 }; void FAR *dp = &dbcsTable; r->DS = FP_SEG(dp); r->SI = FP_OFF(dp); r->AL = 0; #else /* not really supported, but will pass. */ r->AL = 0x00; /*jpp: according to interrupt list */ /*Bart: fails for PQDI: use the above again */ #endif break; } /* case 0x64: see above (invalid) */ /* Extended country info */ case 0x65: switch(r->AL) { case 0x20: /* upcase single character */ r->DL = DosUpChar(r->DL); break; case 0x21: /* upcase memory area */ DosUpMem(FP_DS_DX, r->CX); break; case 0x22: /* upcase ASCIZ */ DosUpString(FP_DS_DX); break; case 0xA0: /* upcase single character of filenames */ r->DL = DosUpFChar(r->DL); break; case 0xA1: /* upcase memory area of filenames */ DosUpFMem(FP_DS_DX, r->CX); break; case 0xA2: /* upcase ASCIZ of filenames */ DosUpFString(FP_DS_DX); break; case 0x23: /* check Yes/No response */ r->AX = DosYesNo(r->DL); break; default: if ((rc = DosGetData( r->AL, r->BX, r->DX, r->CX, MK_FP(r->ES, r->DI))) < 0) { #ifdef NLS_DEBUG printf("DosGetData() := %d\n", rc); #endif goto error_exit; } #ifdef NLS_DEBUG printf("DosGetData() returned successfully\n", rc); #endif break; } CLEAR_CARRY_FLAG(); break; /* Code Page functions */ case 0x66: { int rc; switch (r->AL) { case 1: rc = DosGetCodepage(&r->BX, &r->DX); break; case 2: rc = DosSetCodepage(r->BX, r->DX); break; default: goto error_invalid; } if(rc != SUCCESS) goto error_exit; CLEAR_CARRY_FLAG(); break; } /* Set Max file handle count */ case 0x67: if ((rc = SetJFTSize(r->BX)) != SUCCESS) goto error_exit; else CLEAR_CARRY_FLAG(); break; /* Flush file buffer -- COMMIT FILE -- dummy function right now. */ case 0x68: case 0x6a: CLEAR_CARRY_FLAG(); break; /* Get/Set Serial Number */ case 0x69: rc = ( r->BL == 0 ? default_drive : r->BL - 1); if (rc < lastdrive) { UWORD saveCX = r->CX; if (CDSp->cds_table[rc].cdsFlags & CDSNETWDRV) { goto error_invalid; } switch(r->AL){ case 0x00: r->AL = 0x0d; r->CX = 0x0866; rc = DosDevIOctl(r); break; case 0x01: r->AL = 0x0d; r->CX = 0x0846; rc = DosDevIOctl(r); break; } r->CX = saveCX; if (rc != SUCCESS) goto error_exit; CLEAR_CARRY_FLAG(); break; } else r->AL = 0xFF; break; /* case 0x6a: see case 0x68 case 0x6b: dummy func: return AL=0 */ /* Extended Open-Creat, not fully functional. (bits 4,5,6 of BH) */ case 0x6c: { COUNT x = 0; if (r->AL != 0 || r->DH != 0 || (r->DL&0x0f) > 0x2 || (r->DL&0xf0) > 0x10) goto error_invalid; CLEAR_CARRY_FLAG(); if ((rc = DosOpen(MK_FP(r->DS, r->SI), (r->DL&0x0f) == 0x1 ? r->BL : 0)) < 0) { if (r->DL < 0x10) goto error_exit; /* else try to create below */ } else switch (r->DL & 0x0f) { case 0x0: /* fail if file exists */ DosClose(rc); rc = DE_FILEEXISTS; goto error_exit; case 0x1: /* file exists and opened: OK */ r->CX = 0x01; goto break_out; case 0x2: /* file exists: replace/open */ DosClose(rc); x = 1; break; } /* cases 0x00, 0x01 are finished now */ if ((rc = DosCreat(MK_FP(r->DS, r->SI), r->CX)) < 0) goto error_exit; r->CX = x+2; break_out: r->AX = rc; break; } /* case 0x6d and above not implemented : see default; return AL=0 */ } #ifdef DEBUG if (bDumpRegs) { fbcopy((VOID FAR *) user_r, (VOID FAR *) & error_regs, sizeof(iregs)); dump_regs = TRUE; dump(); } #endif }
COUNT dos_findfirst(UCOUNT attr, BYTE FAR * name) { REG struct f_node FAR *fnp; REG dmatch FAR *dmp = (dmatch FAR *) dta; REG COUNT i; COUNT nDrive; BYTE *p; struct cds FAR *cdsp; static BYTE local_name[FNAME_SIZE + 1], local_ext[FEXT_SIZE + 1]; /* The findfirst/findnext calls are probably the worst of the */ /* DOS calls. They must work somewhat on the fly (i.e. - open */ /* but never close). Since we don't want to lose fnodes every */ /* time a directory is searched, we will initialize the DOS */ /* dirmatch structure and then for every find, we will open the */ /* current directory, do a seek and read, then close the fnode. */ /* Start out by initializing the dirmatch structure. */ dmp->dm_drive = default_drive; dmp->dm_entry = 0; dmp->dm_cluster = 0; dmp->dm_attr_srch = attr | D_RDONLY | D_ARCHIVE; /* Parse out the drive, file name and file extension. */ i = ParseDosName(name, &nDrive, &LocalPath[2], local_name, local_ext, TRUE); if (i != SUCCESS) return i; if (nDrive >= 0) { dmp->dm_drive = nDrive; } else nDrive = default_drive; cdsp = &CDSp->cds_table[nDrive]; if (cdsp->cdsFlags & 0x8000) { if (Remote_find(REM_FINDFIRST, attr, name, dmp) != 0) return DE_FILENOTFND; return SUCCESS; } /* Now build a directory. */ if (!LocalPath[2]) strcpy(&LocalPath[2], "."); /* Build the match pattern out of the passed string */ /* copy the part of the pattern which belongs to the filename and is fixed */ for (p = local_name, i = 0; i < FNAME_SIZE && *p && *p != '*'; ++p, ++i) SearchDir.dir_name[i] = *p; if (*p == '*') { for (; i < FNAME_SIZE; ++i) SearchDir.dir_name[i] = '?'; while (*++p) ; } else for (; i < FNAME_SIZE; i++) SearchDir.dir_name[i] = ' '; /* and the extension (don't forget to add trailing spaces)... */ for (p = local_ext, i = 0; i < FEXT_SIZE && *p && *p != '*'; ++p, ++i) SearchDir.dir_ext[i] = *p; if (*p == '*') { for (; i < FEXT_SIZE; ++i) SearchDir.dir_ext[i] = '?'; while (*++p) ; } else for (; i < FEXT_SIZE; i++) SearchDir.dir_ext[i] = ' '; /* Convert everything to uppercase. */ upMem(SearchDir.dir_name, FNAME_SIZE + FEXT_SIZE); /* Copy the raw pattern from our data segment to the DTA. */ fbcopy((BYTE FAR *) SearchDir.dir_name, dmp->dm_name_pat, FNAME_SIZE + FEXT_SIZE); /* Now search through the directory to find the entry... */ /* Special handling - the volume id is only in the root */ /* directory and only searched for once. So we need to open */ /* the root and return only the first entry that contains the */ /* volume id bit set. */ if ((attr & ~(D_RDONLY | D_ARCHIVE)) == D_VOLID) { /* Now open this directory so that we can read the */ /* fnode entry and do a match on it. */ if ((fnp = dir_open((BYTE FAR *) "\\")) == NULL) return DE_PATHNOTFND; /* Now do the search */ while (dir_read(fnp) == DIRENT_SIZE) { /* Test the attribute and return first found */ if ((fnp->f_dir.dir_attrib & ~(D_RDONLY | D_ARCHIVE)) == D_VOLID) { pop_dmp(dmp, fnp); dir_close(fnp); return SUCCESS; } } /* Now that we've done our failed search, close it and */ /* return an error. */ dir_close(fnp); return DE_FILENOTFND; } /* Otherwise just do a normal find next */ else { /* Complete building the directory from the passed in */ /* name */ if (nDrive >= 0) LocalPath[0] = 'A' + nDrive; else LocalPath[0] = 'A' + default_drive; LocalPath[1] = ':'; /* Now open this directory so that we can read the */ /* fnode entry and do a match on it. */ if ((fnp = dir_open((BYTE FAR *) LocalPath)) == NULL) return DE_PATHNOTFND; pop_dmp(dmp, fnp); dmp->dm_entry = 0; if (!fnp->f_flags.f_droot) { dmp->dm_cluster = fnp->f_dirstart; dmp->dm_dirstart = fnp->f_dirstart; } else { dmp->dm_cluster = 0; dmp->dm_dirstart = 0; } dir_close(fnp); return dos_findnext(); } }
VOID int21_service(iregs FAR * r) { COUNT rc, rc1; ULONG lrc; psp FAR *p = MK_FP(cu_psp, 0); p->ps_stack = (BYTE FAR *) r; #ifdef DEBUG if (bDumpRegs) { fbcopy((VOID FAR *) user_r, (VOID FAR *) & error_regs, sizeof(iregs)); printf("System call (21h): %02x\n", user_r->AX); dump_regs = TRUE; dump(); } #endif dispatch: /* Check for Ctrl-Break */ switch (r->AH) { default: if (!break_ena) break; case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x08: case 0x09: case 0x0a: case 0x0b: if (control_break()) handle_break(); } /* The dispatch handler */ switch (r->AH) { /* int 21h common error handler */ case 0x64: case 0x6b: default: error_invalid: r->AX = -DE_INVLDFUNC; goto error_out; error_exit: r->AX = -rc; error_out: r->FLAGS |= FLG_CARRY; break; #if 0 /* Moved to simulate a 0x4c00 -- 1999/04/21 ska */ /* Terminate Program */ case 0x00: if (cu_psp == RootPsp) break; else if (((psp FAR *) (MK_FP(cu_psp, 0)))->ps_parent == cu_psp) break; tsr = FALSE; return_mode = break_flg ? 1 : 0; return_code = r->AL; if (DosMemCheck() != SUCCESS) panic("MCB chain corrupted"); #ifdef TSC StartTrace(); #endif return_user(); break; #endif /* Read Keyboard with Echo */ case 0x01: Do_DosIdle_loop(); r->AL = _sti(); sto(r->AL); break; /* Display Character */ case 0x02: sto(r->DL); break; /* Auxiliary Input */ case 0x03: r->AL = _sti(); break; /* Auxiliary Output */ case 0x04: sto(r->DL); break; /* Print Character */ case 0x05: sto(r->DL); break; /* Direct Cosole I/O */ case 0x06: if (r->DL != 0xff) sto(r->DL); else if (StdinBusy()) { r->AL = 0x00; r->FLAGS |= FLG_ZERO; } else { r->FLAGS &= ~FLG_ZERO; r->AL = _sti(); } break; /* Direct Console Input */ case 0x07: /* Read Keyboard Without Echo */ case 0x08: Do_DosIdle_loop(); r->AL = _sti(); break; /* Display String */ case 0x09: { static COUNT scratch; BYTE FAR *p = MK_FP(r->DS, r->DX), FAR * q; q = p; while (*q != '$') ++q; DosWrite(STDOUT, q - p, p, (COUNT FAR *) & scratch); } r->AL = '$'; break; /* Buffered Keyboard Input */ case 0x0a: ((keyboard FAR *) MK_FP(r->DS, r->DX))->kb_count = 0; sti((keyboard FAR *) MK_FP(r->DS, r->DX)); ((keyboard FAR *) MK_FP(r->DS, r->DX))->kb_count -= 2; break; /* Check Stdin Status */ case 0x0b: if (StdinBusy()) r->AL = 0xFF; else r->AL = 0x00; break; /* Flush Buffer, Read Keayboard */ case 0x0c: KbdFlush(); switch (r->AL) { case 0x01: case 0x06: case 0x07: case 0x08: case 0x0a: r->AH = r->AL; goto dispatch; default: r->AL = 0x00; break; } break; /* Reset Drive */ case 0x0d: flush(); break; /* Set Default Drive */ case 0x0e: r->AL = DosSelectDrv(r->DL); break; case 0x0f: if (FcbOpen(MK_FP(r->DS, r->DX))) r->AL = 0; else r->AL = 0xff; break; case 0x10: if (FcbClose(MK_FP(r->DS, r->DX))) r->AL = 0; else r->AL = 0xff; break; case 0x11: if (FcbFindFirst(MK_FP(r->DS, r->DX))) r->AL = 0; else r->AL = 0xff; break; case 0x12: if (FcbFindNext(MK_FP(r->DS, r->DX))) r->AL = 0; else r->AL = 0xff; break; case 0x13: if (FcbDelete(MK_FP(r->DS, r->DX))) r->AL = 0; else r->AL = 0xff; break; case 0x14: { COUNT nErrorCode; if (FcbRead(MK_FP(r->DS, r->DX), &nErrorCode)) r->AL = 0; else r->AL = nErrorCode; break; } case 0x15: { COUNT nErrorCode; if (FcbWrite(MK_FP(r->DS, r->DX), &nErrorCode)) r->AL = 0; else r->AL = nErrorCode; break; } case 0x16: if (FcbCreate(MK_FP(r->DS, r->DX))) r->AL = 0; else r->AL = 0xff; break; case 0x17: if (FcbRename(MK_FP(r->DS, r->DX))) r->AL = 0; else r->AL = 0xff; break; /* CP/M compatibility functions */ case 0x18: case 0x1d: case 0x1e: case 0x20: #ifndef TSC case 0x61: #endif r->AL = 0; break; /* Get Default Drive */ case 0x19: r->AL = default_drive; break; /* Set DTA */ case 0x1a: { psp FAR *p = MK_FP(cu_psp, 0); p->ps_dta = MK_FP(r->DS, r->DX); dos_setdta(p->ps_dta); } break; /* Get Default Drive Data */ case 0x1b: { BYTE FAR *p; FatGetDrvData(0, (COUNT FAR *) & r->AX, (COUNT FAR *) & r->CX, (COUNT FAR *) & r->DX, (BYTE FAR **) & p); r->DS = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Get Drive Data */ case 0x1c: { BYTE FAR *p; FatGetDrvData(r->DL, (COUNT FAR *) & r->AX, (COUNT FAR *) & r->CX, (COUNT FAR *) & r->DX, (BYTE FAR **) & p); r->DS = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Get default DPB */ case 0x1f: if (default_drive < lastdrive) { struct dpb FAR *dpb = (struct dpb FAR *)CDSp->cds_table[default_drive].cdsDpb; if (dpb == 0) { r->AL = 0xff; break; } r->DS = FP_SEG(dpb); r->BX = FP_OFF(dpb); r->AL = 0; } else r->AL = 0xff; break; /* Random read using FCB */ case 0x21: { COUNT nErrorCode; if (FcbRandomRead(MK_FP(r->DS, r->DX), &nErrorCode)) r->AL = 0; else r->AL = nErrorCode; break; } /* Random write using FCB */ case 0x22: { COUNT nErrorCode; if (FcbRandomWrite(MK_FP(r->DS, r->DX), &nErrorCode)) r->AL = 0; else r->AL = nErrorCode; break; } /* Get file size in records using FCB */ case 0x23: if (FcbGetFileSize(MK_FP(r->DS, r->DX))) r->AL = 0; else r->AL = 0xff; break; /* Set random record field in FCB */ case 0x24: FcbSetRandom(MK_FP(r->DS, r->DX)); break; /* Set Interrupt Vector */ case 0x25: { VOID(INRPT FAR * p) () = MK_FP(r->DS, r->DX); setvec(r->AL, p); } break; /* Dos Create New Psp */ case 0x26: { psp FAR *p = MK_FP(cu_psp, 0); new_psp((psp FAR *) MK_FP(r->DX, 0), p->ps_size); } break; /* Read random record(s) using FCB */ case 0x27: { COUNT nErrorCode; if (FcbRandomBlockRead(MK_FP(r->DS, r->DX), r->CX, &nErrorCode)) r->AL = 0; else r->AL = nErrorCode; break; } /* Write random record(s) using FCB */ case 0x28: { COUNT nErrorCode; if (FcbRandomBlockWrite(MK_FP(r->DS, r->DX), r->CX, &nErrorCode)) r->AL = 0; else r->AL = nErrorCode; break; } /* Parse File Name */ case 0x29: { BYTE FAR *lpFileName; lpFileName = MK_FP(r->DS, r->SI); r->AL = FcbParseFname(r->AL, &lpFileName, MK_FP(r->ES, r->DI)); r->DS = FP_SEG(lpFileName); r->SI = FP_OFF(lpFileName); } break; /* Get Date */ case 0x2a: DosGetDate( (BYTE FAR *) & (r->AL), /* WeekDay */ (BYTE FAR *) & (r->DH), /* Month */ (BYTE FAR *) & (r->DL), /* MonthDay */ (COUNT FAR *) & (r->CX)); /* Year */ break; /* Set Date */ case 0x2b: rc = DosSetDate( (BYTE FAR *) & (r->DH), /* Month */ (BYTE FAR *) & (r->DL), /* MonthDay */ (COUNT FAR *) & (r->CX)); /* Year */ if (rc != SUCCESS) r->AL = 0xff; else r->AL = 0; break; /* Get Time */ case 0x2c: DosGetTime( (BYTE FAR *) & (r->CH), /* Hour */ (BYTE FAR *) & (r->CL), /* Minutes */ (BYTE FAR *) & (r->DH), /* Seconds */ (BYTE FAR *) & (r->DL)); /* Hundredths */ break; /* Set Date */ case 0x2d: rc = DosSetTime( (BYTE FAR *) & (r->CH), /* Hour */ (BYTE FAR *) & (r->CL), /* Minutes */ (BYTE FAR *) & (r->DH), /* Seconds */ (BYTE FAR *) & (r->DL)); /* Hundredths */ if (rc != SUCCESS) r->AL = 0xff; else r->AL = 0; break; /* Set verify flag */ case 0x2e: verify_ena = (r->AL ? TRUE : FALSE); break; /* Get DTA */ case 0x2f: r->ES = FP_SEG(dta); r->BX = FP_OFF(dta); break; /* Get DOS Version */ case 0x30: r->AL = os_major; r->AH = os_minor; r->BH = OEM_ID; r->CH = REVISION_MAJOR; /* JPP */ r->CL = REVISION_MINOR; r->BL = REVISION_SEQ; break; /* Keep Program (Terminate and stay resident) */ case 0x31: DosMemChange(cu_psp, r->DX < 6 ? 6 : r->DX, 0); return_mode = 3; return_code = r->AL; tsr = TRUE; return_user(); break; /* Get DPB */ case 0x32: if (r->DL < lastdrive) { struct dpb FAR *dpb = CDSp->cds_table[r->DL].cdsDpb; if (dpb == 0) { r->AL = 0xff; break; } r->DS = FP_SEG(dpb); r->BX = FP_OFF(dpb); r->AL = 0; } else r->AL = 0xFF; break; /* Get InDOS flag */ case 0x34: { BYTE FAR *p; p = (BYTE FAR *) ((BYTE *) & InDOS); r->ES = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Get Interrupt Vector */ case 0x35: { BYTE FAR *p; p = getvec((COUNT) r->AL); r->ES = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Dos Get Disk Free Space */ case 0x36: DosGetFree( (COUNT) r->DL, (COUNT FAR *) & r->AX, (COUNT FAR *) & r->BX, (COUNT FAR *) & r->CX, (COUNT FAR *) & r->DX); break; /* Undocumented Get/Set Switchar */ case 0x37: switch (r->AL) { /* Get switch character */ case 0x00: r->DL = switchar; r->AL = 0x00; break; /* Set switch character */ case 0x01: switchar = r->DL; r->AL = 0x00; break; default: goto error_invalid; } break; /* Get/Set Country Info */ case 0x38: { BYTE FAR *lpTable = (BYTE FAR *) MK_FP(r->DS, r->DX); BYTE nRetCode; if (0xffff == r->DX) { r->BX = SetCtryInfo( (UBYTE FAR *) & (r->AL), (UWORD FAR *) & (r->BX), (BYTE FAR *) & lpTable, (UBYTE *) & nRetCode); if (nRetCode != 0) { r->AX = 0xff; r->FLAGS |= FLG_CARRY; } else { r->AX = nRetCode; r->FLAGS &= ~FLG_CARRY; } } else { r->BX = GetCtryInfo(&(r->AL), &(r->BX), lpTable); r->FLAGS &= ~FLG_CARRY; } } break; /* Dos Create Directory */ case 0x39: rc = dos_mkdir((BYTE FAR *) MK_FP(r->DS, r->DX)); if (rc != SUCCESS) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; } break; /* Dos Remove Directory */ case 0x3a: rc = dos_rmdir((BYTE FAR *) MK_FP(r->DS, r->DX)); if (rc != SUCCESS) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; } break; /* Dos Change Directory */ case 0x3b: if ((rc = DosChangeDir((BYTE FAR *) MK_FP(r->DS, r->DX))) < 0) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; } break; /* Dos Create File */ case 0x3c: if ((rc = DosCreat(MK_FP(r->DS, r->DX), r->CX)) < 0) goto error_exit; else { r->AX = rc; r->FLAGS &= ~FLG_CARRY; } break; /* Dos Open */ case 0x3d: if ((rc = DosOpen(MK_FP(r->DS, r->DX), r->AL)) < 0) goto error_exit; else { r->AX = rc; r->FLAGS &= ~FLG_CARRY; } break; /* Dos Close */ case 0x3e: if ((rc = DosClose(r->BX)) < 0) goto error_exit; else r->FLAGS &= ~FLG_CARRY; break; /* Dos Read */ case 0x3f: rc = DosRead(r->BX, r->CX, MK_FP(r->DS, r->DX), (COUNT FAR *) & rc1); if (rc1 != SUCCESS) { r->FLAGS |= FLG_CARRY; r->AX = -rc1; } else { r->FLAGS &= ~FLG_CARRY; r->AX = rc; } break; /* Dos Write */ case 0x40: rc = DosWrite(r->BX, r->CX, MK_FP(r->DS, r->DX), (COUNT FAR *) & rc1); if (rc1 != SUCCESS) { r->FLAGS |= FLG_CARRY; r->AX = -rc1; } else { r->FLAGS &= ~FLG_CARRY; r->AX = rc; } break; /* Dos Delete File */ case 0x41: rc = dos_delete((BYTE FAR *) MK_FP(r->DS, r->DX)); if (rc < 0) { r->FLAGS |= FLG_CARRY; r->AX = -rc1; } else r->FLAGS &= ~FLG_CARRY; break; /* Dos Seek */ case 0x42: if ((rc = DosSeek(r->BX, (LONG) ((((LONG) (r->CX)) << 16) + r->DX), r->AL, &lrc)) < 0) goto error_exit; else { r->DX = (lrc >> 16); r->AX = lrc & 0xffff; r->FLAGS &= ~FLG_CARRY; } break; /* Get/Set File Attributes */ case 0x43: switch (r->AL) { case 0x00: rc = DosGetFattr((BYTE FAR *) MK_FP(r->DS, r->DX), (UWORD FAR *) & r->CX); if (rc < SUCCESS) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; } break; case 0x01: rc = DosSetFattr((BYTE FAR *) MK_FP(r->DS, r->DX), (UWORD FAR *) & r->CX); if (rc != SUCCESS) goto error_exit; else r->FLAGS &= ~FLG_CARRY; break; default: goto error_invalid; } break; /* Device I/O Control */ case 0x44: { rc = DosDevIOctl(r, (COUNT FAR *) & rc1); if (rc1 != SUCCESS) { r->FLAGS |= FLG_CARRY; r->AX = -rc1; } else { r->FLAGS &= ~FLG_CARRY; } } break; /* Duplicate File Handle */ case 0x45: rc = DosDup(r->BX); if (rc < SUCCESS) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; r->AX = rc; } break; /* Force Duplicate File Handle */ case 0x46: rc = DosForceDup(r->BX, r->CX); if (rc < SUCCESS) goto error_exit; else r->FLAGS &= ~FLG_CARRY; break; /* Get Current Directory */ case 0x47: if ((rc = DosGetCuDir(r->DL, MK_FP(r->DS, r->SI))) < 0) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; r->AX = 0x0100; /*jpp: from interrupt list */ } break; /* Allocate memory */ case 0x48: if ((rc = DosMemAlloc(r->BX, mem_access_mode, &(r->AX), &(r->BX))) < 0) { DosMemLargest(&(r->BX)); goto error_exit; } else { ++(r->AX); /* DosMemAlloc() returns seg of MCB rather than data */ r->FLAGS &= ~FLG_CARRY; } break; /* Free memory */ case 0x49: if ((rc = DosMemFree((r->ES) - 1)) < 0) goto error_exit; else r->FLAGS &= ~FLG_CARRY; break; /* Set memory block size */ case 0x4a: { UWORD maxSize; if ((rc = DosMemChange(r->ES, r->BX, &maxSize)) < 0) { if (rc == DE_NOMEM) r->BX = maxSize; #if 0 if (cu_psp == r->ES) { psp FAR *p; p = MK_FP(cu_psp, 0); p->ps_size = r->BX + cu_psp; } #endif goto error_exit; } else r->FLAGS &= ~FLG_CARRY; break; } /* Load and Execute Program */ case 0x4b: break_flg = FALSE; if ((rc = DosExec(r->AL, MK_FP(r->ES, r->BX), MK_FP(r->DS, r->DX))) != SUCCESS) goto error_exit; else r->FLAGS &= ~FLG_CARRY; break; /* Terminate Program */ case 0x00: r->AX = 0x4c00; /* End Program */ case 0x4c: if (cu_psp == RootPsp || ((psp FAR *) (MK_FP(cu_psp, 0)))->ps_parent == cu_psp) break; tsr = FALSE; /* int2f_Remote_call(0x1122, 0, 0, 0, 0, 0, 0); int2f_Remote_call(REM_CLOSEALL, 0, 0, 0, 0, 0, 0); */ if (ErrorMode) { ErrorMode = FALSE; return_mode = 2; } else if (break_flg) { break_flg = FALSE; return_mode = 1; } else { return_mode = 0; } return_code = r->AL; if (DosMemCheck() != SUCCESS) panic("MCB chain corrupted"); #ifdef TSC StartTrace(); #endif return_user(); break; /* Get Child-program Return Value */ case 0x4d: r->AL = return_code; r->AH = return_mode; break; /* Dos Find First */ case 0x4e: { /* dta for this call is set on entry. This */ /* needs to be changed for new versions. */ if ((rc = DosFindFirst((UCOUNT) r->CX, (BYTE FAR *) MK_FP(r->DS, r->DX))) < 0) goto error_exit; else { r->AX = 0; r->FLAGS &= ~FLG_CARRY; } } break; /* Dos Find Next */ case 0x4f: { /* dta for this call is set on entry. This */ /* needs to be changed for new versions. */ if ((rc = DosFindNext()) < 0) { r->AX = -rc; if (r->AX == 2) r->AX = 18; r->FLAGS |= FLG_CARRY; } else { r->FLAGS &= ~FLG_CARRY; } } break; /* ************UNDOCUMENTED************************************* */ /* Get List of Lists */ case 0x52: { BYTE FAR *p; p = (BYTE FAR *) & DPBp; r->ES = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Get verify state */ case 0x54: r->AL = (verify_ena ? TRUE : FALSE); break; /* ************UNDOCUMENTED************************************* */ /* Dos Create New Psp & set p_size */ case 0x55: new_psp((psp FAR *) MK_FP(r->DX, 0), r->SI); break; /* Dos Rename */ case 0x56: rc = dos_rename( (BYTE FAR *) MK_FP(r->DS, r->DX), /* OldName */ (BYTE FAR *) MK_FP(r->ES, r->DI)); /* NewName */ if (rc < SUCCESS) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; } break; /* Get/Set File Date and Time */ case 0x57: switch (r->AL) { case 0x00: rc = DosGetFtime( (COUNT) r->BX, /* Handle */ (date FAR *) & r->DX, /* FileDate */ (time FAR *) & r->CX); /* FileTime */ if (rc < SUCCESS) goto error_exit; else r->FLAGS &= ~FLG_CARRY; break; case 0x01: rc = DosSetFtime( (COUNT) r->BX, /* Handle */ (date FAR *) & r->DX, /* FileDate */ (time FAR *) & r->CX); /* FileTime */ if (rc < SUCCESS) goto error_exit; else r->FLAGS &= ~FLG_CARRY; break; default: goto error_invalid; } break; /* Get/Set Allocation Strategy */ case 0x58: switch (r->AL) { case 0x00: r->AX = mem_access_mode; break; case 0x01: if (((COUNT) r->BX) < 0 || r->BX > 2) goto error_invalid; else { mem_access_mode = r->BX; r->FLAGS &= ~FLG_CARRY; } break; default: goto error_invalid; #ifdef DEBUG case 0xff: show_chain(); break; #endif } break; /* Create Temporary File */ case 0x5a: if ((rc = DosMkTmp(MK_FP(r->DS, r->DX), r->CX)) < 0) goto error_exit; else { r->AX = rc; r->FLAGS &= ~FLG_CARRY; } break; /* Create New File */ case 0x5b: if ((rc = DosOpen(MK_FP(r->DS, r->DX), 0)) >= 0) { DosClose(rc); r->AX = 80; r->FLAGS |= FLG_CARRY; } else { if ((rc = DosCreat(MK_FP(r->DS, r->DX), r->CX)) < 0) goto error_exit; else { r->AX = rc; r->FLAGS &= ~FLG_CARRY; } } break; /* UNDOCUMENTED: server, share.exe and sda function */ case 0x5d: switch (r->AL) { /* Remote Server Call */ case 0x00: { UWORD FAR *x = MK_FP(r->DS, r->DX); r->AX = x[0]; r->BX = x[1]; r->CX = x[2]; r->DX = x[3]; r->SI = x[4]; r->DI = x[5]; r->DS = x[6]; r->ES = x[7]; } goto dispatch; case 0x06: r->DS = FP_SEG(internal_data); r->SI = FP_OFF(internal_data); r->CX = swap_always - internal_data; r->DX = swap_indos - internal_data; r->FLAGS &= ~FLG_CARRY; break; case 0x07: case 0x08: case 0x09: int2f_Remote_call(REM_PRINTREDIR, 0, 0, r->DX, 0, 0, (MK_FP(0, Int21AX))); break; default: goto error_invalid; } break; case 0x5e: switch (r->AL) { case 0x00: r->CX = get_machine_name(MK_FP(r->DS, r->DX)); break; case 0x01: set_machine_name(MK_FP(r->DS, r->DX), r->CX); break; default: int2f_Remote_call(REM_PRINTSET, r->BX, r->CX, r->DX, (MK_FP(r->ES, r->DI)), r->SI, (MK_FP(r->DS, Int21AX))); break; } break; case 0x5f: switch (r->AL) { case 0x07: CDSp->cds_table[r->DL].cdsFlags |= 0x100; break; case 0x08: CDSp->cds_table[r->DL].cdsFlags &= ~0x100; break; default: int2f_Remote_call(REM_DOREDIRECT, r->BX, r->CX, r->DX, (MK_FP(r->ES, r->DI)), r->SI, (MK_FP(r->DS, Int21AX))); break; } break; case 0x60: /* TRUENAME */ if ((rc = truename(MK_FP(r->DS, r->SI), adjust_far(MK_FP(r->ES, r->DI)), TRUE)) != SUCCESS) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; } break; #ifdef TSC /* UNDOCUMENTED: no-op */ /* */ /* DOS-C: tsc support */ case 0x61: #ifdef DEBUG switch (r->AL) { case 0x01: bTraceNext = TRUE; break; case 0x02: bDumpRegs = FALSE; break; } #endif r->AL = 0x00; break; #endif /* UNDOCUMENTED: return current psp */ case 0x62: r->BX = cu_psp; break; /* UNDOCUMENTED: Double byte and korean tables */ case 0x63: { #ifdef DBLBYTE static char dbcsTable[2] = { 0, 0 }; void FAR *dp = &dbcsTable; r->DS = FP_SEG(dp); r->SI = FP_OFF(dp); r->AL = 0; #else /* not really supported, but will pass. */ r->AL = 0x00; /*jpp: according to interrupt list */ #endif break; } /* Extended country info */ case 0x65: if (r->AL <= 0x7) { if (ExtCtryInfo( r->AL, r->BX, r->CX, MK_FP(r->ES, r->DI))) r->FLAGS &= ~FLG_CARRY; else goto error_invalid; } else if ((r->AL >= 0x20) && (r->AL <= 0x22)) { switch (r->AL) { case 0x20: r->DL = upChar(r->DL); goto okay; case 0x21: upMem( MK_FP(r->DS, r->DX), r->CX); goto okay; case 0x22: upString(MK_FP(r->DS, r->DX)); okay: r->FLAGS &= ~FLG_CARRY; break; case 0x23: r->AX = yesNo(r->DL); goto okay; default: goto error_invalid; } } else r->FLAGS |= FLG_CARRY; break; /* Code Page functions */ case 0x66: switch (r->AL) { case 1: GetGlblCodePage( (UWORD FAR *) & (r->BX), (UWORD FAR *) & (r->DX)); goto okay_66; case 2: SetGlblCodePage( (UWORD FAR *) & (r->BX), (UWORD FAR *) & (r->DX)); okay_66: r->FLAGS &= ~FLG_CARRY; break; default: goto error_invalid; } break; /* Set Max file handle count */ case 0x67: if ((rc = SetJFTSize(r->BX)) != SUCCESS) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; } break; /* Flush file buffer -- dummy function right now. */ case 0x68: r->FLAGS &= ~FLG_CARRY; break; } #ifdef DEBUG if (bDumpRegs) { fbcopy((VOID FAR *) user_r, (VOID FAR *) & error_regs, sizeof(iregs)); dump_regs = TRUE; dump(); } #endif }