home *** CD-ROM | disk | FTP | other *** search
- /* MULTI.C */
-
- #include <stddef.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <dos.h>
- #include <io.h>
- #include "tsr.h"
-
- #define SEARCH_DIR "C:\\SPOOL\\"
- #define STACK_SIZE 4096 /* must be 16 byte boundaray */
- #define SET_DTA 0x1a /* SET Disk Transfer Address */
- #define GET_DTA 0x2f /* GET Disk Transfer Address */
-
- #define BACKGROUND_TICS 2
- #define FOREGROUND_TICS 16
- #define BACKGROUND_YIELD 0
- #define FOREGROUND_YIELD 0
-
- struct prReq
- {
- char level;
- char far *fname;
- };
-
- char far *stack_ptr; /* stack for our background TSR */
- char far *ptr;
- unsigned ss_save; /* slot for stack segment register */
- unsigned sp_save; /* slot for stack pointer register */
- unsigned unsafe_flag = 0; /* set true by variouse interrupts */
- int first_time = 1; /* flag for first time in running background */
-
- int my_psp; /* our TSR's psp */
- int foreground_psp; /* PSP of interrupted foreground process */
- int foreground_dta_seg; /* DTA of interrupted foreground process */
- int foreground_dta_off;
- int ctr=0;
- int tic_count = 0; /* counts timer tices */
- int in_progress = 0; /* true if we're in background process */
-
- char search_work[65];
- struct ExtErr my_ErrInfo;
- struct ExtErr foreground_ErrInfo;
-
- int foreground_limit = FOREGROUND_TICS; /* foreground cycle limit */
- int background_limit = BACKGROUND_TICS; /* background cycle limit */
-
- char search_dir[65] = {SEARCH_DIR}; /* dir to search for spool files */
- volatile int int_28_active = 0; /* true if activated by INT 28 */
- volatile int interval_timer; /* for sleeping a number of tics */
-
- /* old interrupt pointers are stored here */
- INTVECT old_int8, old_int9, old_int10, old_int13;
- INTVECT old_int1B, old_int23, old_int24, old_int25;
- INTVECT old_int26, old_int28;
-
- /* prototypes for this module */
- void main_loop();
- void interrupt far new_int8(INTERRUPT_REGS);
- void interrupt far new_int9(INTERRUPT_REGS);
- void interrupt far new_int10(void);
- void interrupt far new_int13(void);
- void interrupt far new_int1B(INTERRUPT_REGS);
- void interrupt far new_int23(INTERRUPT_REGS);
- void interrupt far new_int24(INTERRUPT_REGS);
- void interrupt far new_int25(void);
- void interrupt far new_int26(void);
- void interrupt far new_int28(INTERRUPT_REGS);
- int spooler_active(void);
- int search_spl_que(char * fname);
- void suspend_foreground(void);
- void suspend_background(void);
-
- /* returns nonzero if PRINT installed */
- int spooler_active()
- {
- union REGS regs;
-
- regs.x.ax = 0x0100; /* PRINT install check */
- int86(0x2f,®s,®s); /* call multiplex interrupt */
- return(regs.h.al == 0xff); /* FF if installed */
- }
-
- /* returns nonzero if file is in the spooler queue */
- int search_spl_que(char * fname)
- {
- union REGS regs;
- struct SREGS sregs;
- char far * que_ptr;
- char que_name[65];
- int i;
- int found = 0;
-
- if (spooler_active())
- {
- regs.x.ax = 0x0104; /* get spooler status */
- int86x(0x2f,®s,®s,&sregs);
- /* on return from call DS:SI points to print queue */
- FP_SEG(que_ptr) = sregs.ds;
- FP_OFF(que_ptr) = regs.x.si;
- /* release hold on spooler, side effect of status*/
- regs.x.ax = 0x0105;
- int86x(0x2f,®s,®s,&sregs);
- while (*que_ptr && !found) /* while items in queue */
- {
- for (i = 0; i < 65; i++)
- que_name[i] = *(que_ptr + i);
- if (found = !strcmpi(que_name,fname))
- break;
- que_ptr += 65;
- }
- }
-
- return(found);
- }
-
- void main_loop()
- {
- struct find_t c_file;
- union REGS regs;
- struct SREGS sregs;
- struct prReq prRequest;
- struct prReq far * ptr;
-
- while (1)
- {
- strcpy(search_work,search_dir);
- strcat(search_work,"*.SPL"); /* create dir search string */
-
- interval_timer = 18 * 30; /* search every 30 seconds */
- while (interval_timer) /* wait between each dir search */
- background_limit = BACKGROUND_YIELD; /* yield for fgrnd */
-
- if (!_dos_findfirst(search_work,_A_NORMAL,&c_file))
- {
- /* if spooler installed, dos 3.xx+ and file size > 0 */
- if (spooler_active() && _osmajor >= 3 && c_file.size)
- {
- strcpy(search_work,search_dir);
- strcat(search_work,c_file.name); /* full pathname */
- prRequest.level = 0;
- prRequest.fname = search_work;
- regs.x.ax = 0x0101;
- ptr = &prRequest;
- sregs.ds = FP_SEG(ptr);
- regs.x.dx= FP_OFF(ptr);
- int86x(0x2f,®s,®s,&sregs);
-
- while (search_spl_que(search_work)) /* wait till done */
- {
- interval_timer = 18 * 30; /* sleep for 30 seconds */
- while (interval_timer)
- background_limit = BACKGROUND_YIELD;
- }
-
- unlink(search_work); /* delete file */
- background_limit = BACKGROUND_YIELD;
- }
- }
- }
- }
-
- union REGS regs;
- struct SREGS sregs;
-
- void suspend_foreground()
- {
- /* SWAP TO BACKGROUND */
- tic_count = 0;
- /* save old handlers */
- old_int1B= _dos_getvect(0x1B);
- old_int23= _dos_getvect(0x23);
- old_int24= _dos_getvect(0x24);
-
- /* set our interrupt handlers */
- _dos_setvect(0x1b,new_int1B);
- _dos_setvect(0x23,new_int23);
- _dos_setvect(0x24,new_int24);
-
- /* save current PSP and set to ours */
- foreground_psp = GetPSP();
- SetPSP(my_psp);
-
- /* get foreground DTA */
- regs.h.ah = GET_DTA;
- intdosx(®s, ®s, &sregs);
- foreground_dta_seg = sregs.es;
- foreground_dta_off = regs.x.bx;
-
- /* set up our DTA */
- regs.h.ah = SET_DTA;
- regs.x.dx = 0x80; /* use default in PSP area */
- sregs.ds = my_psp;
- intdosx(®s, ®s, &sregs);
-
- /* save error info */
- GetExtErr(&foreground_ErrInfo);
-
- if (! first_time)
- SetExtErr(&my_ErrInfo);
-
- in_progress = 1;
- background_limit = BACKGROUND_TICS; /* set default limit */
- }
-
- void suspend_background()
- {
- /* SWAP TO FOREGROUND */
-
- /* put back original DTA */
- regs.h.ah = SET_DTA;
- regs.x.dx = foreground_dta_off;
- sregs.ds = foreground_dta_seg;
- intdosx(®s, ®s, &sregs);
-
- /* put back original PSP */
- SetPSP(foreground_psp);
-
- /* put back original INTS */
- _dos_setvect(0x1b,old_int1B);
- _dos_setvect(0x23,old_int23);
- _dos_setvect(0x24,old_int24);
-
- /* get error info */
- GetExtErr(&my_ErrInfo);
- SetExtErr(&foreground_ErrInfo);
-
- tic_count = 0;
- in_progress = 0;
- int_28_active = 0;
- foreground_limit = FOREGROUND_TICS; /* set default limit */
- }
-
- /**********
- * TIMER TICK INTERRUPT HANDLER
- **********/
- void interrupt far new_int8(INTERRUPT_REGS r)
- {
- tic_count++;
-
- if (interval_timer)
- interval_timer--;
-
- if ((in_progress && (tic_count >= background_limit) &&
- !DosBusy() && !unsafe_flag) ||
- (in_progress && int_28_active && !Int28DosBusy() &&
- (tic_count >=background_limit)))
- {
- suspend_background();
- restore_stack();
- }
- else if ((!in_progress && (tic_count >= foreground_limit) &&
- !DosBusy() && !unsafe_flag) ||
- (!in_progress && int_28_active && !Int28DosBusy() &&
- (tic_count >=foreground_limit)))
- {
- set_stack();
- suspend_foreground();
- if (first_time)
- {
- first_time = 0;
- timer_int_chain();
- }
- }
- old_int8(); /* call old handler */
- }
-
- /**********
- * KEYBOARD INTERRUPT HANDLER
- **********/
- void interrupt far new_int9(INTERRUPT_REGS r)
- {
- unsafe_flag++;
- old_int9();
- if (in_progress)
- background_limit = BACKGROUND_YIELD; /* set to swap to fgrnd */
- foreground_limit = 18; /* since user hit keyboard */
- unsafe_flag--;
- }
-
- /*********
- * CTRL-BREAK INTERRUPT HANDLER
- *********/
- void interrupt far new_int1B(INTERRUPT_REGS r)
- {
- /* do nothing */
- }
-
- /**********
- * CTRL-C INTERRUPT HANDLER
- **********/
- void interrupt far new_int23(INTERRUPT_REGS r)
- {
- /* do nothing */
- }
-
- /**********
- * CRTITICAL ERROR INTERRUPT HANDLER
- **********/
- void interrupt far new_int24(INTERRUPT_REGS r)
- {
- if (_osmajor >= 3)
- r.ax = 3; /* fail dos function */
- else
- r.ax = 0;
- }
-
- /**********
- * DOS IDLE INTERRUPT HANDLER
- **********/
- void interrupt far new_int28(INTERRUPT_REGS r)
- {
- if (!in_progress && !Int28DosBusy() && !unsafe_flag &&
- tic_count > foreground_limit)
- {
- foreground_limit = FOREGROUND_YIELD; /* stop foreground */
- int_28_active = 1;
- _enable(); /* STI */
- while (int_28_active)
- ; /*spin waiting for task swap to bckgrnd*/
- }
- (*old_int28)(); /* call old handler */
- }
-
- main()
- {
- unsigned memtop;
- unsigned dummy;
- void far* far* tmpptr;
-
- puts("Multi-Tasking PRINT spooler installing");
-
- if (_osmajor < 3)
- {
- puts("Error: MS-DOS version 3.00 or greater required");
- exit(1);
- }
-
- if (! spooler_active())
- puts("Warning: Print Spooler not active");
-
- InitInDos();
- my_psp = GetPSP();
-
- /* MALLOC a stack for our TSR section */
- stack_ptr = malloc(STACK_SIZE);
- stack_ptr += STACK_SIZE;
-
- ptr = stack_ptr;
- *(--stack_ptr) = 0xF2; /* set up stack as if an an IRET was done*/
- *(--stack_ptr) = 0x02;
- stack_ptr -= 4;
- tmpptr = stack_ptr;
- *(tmpptr) = main_loop;
-
- /* get interrupt vectors */
- old_int8 = _dos_getvect(0x08); /* timer int */
- old_int9 = _dos_getvect(0x09); /* keyboard int */
- old_int10 = _dos_getvect(0x10); /* video int */
- old_int13 = _dos_getvect(0x13); /* disk int */
- old_int25 = _dos_getvect(0x25); /* sector read int */
- old_int26 = _dos_getvect(0x26); /* sector write int */
- old_int28 = _dos_getvect(0x28); /* dos idle int */
-
- init_intr(); /* init asm variables */
-
- _dos_setvect(0x08,new_int8);
- _dos_setvect(0x09,new_int9);
- _dos_setvect(0x10,new_int10);
- _dos_setvect(0x13,new_int13);
- _dos_setvect(0x25,new_int25);
- _dos_setvect(0x26,new_int26);
- _dos_setvect(0x28,new_int28);
-
- #define PARAGRAPHS(x) ((FP_OFF(x) + 15) >> 4)
-
- /* release unused heap to MS-DOS */
- /* All MALLOCS for TSR section must be done in TSR_INIT() */
- /* calculate top of memory, shrink block, and go TSR */
- segread(&sregs);
- memtop = sregs.ds + PARAGRAPHS(ptr) - _psp;
-
- _dos_setblock(memtop, _psp, &dummy);
- _dos_keep(0, memtop);
- }
-
-