🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.os.msdos.programmer
Article #2488

Re: Calc. program size for Microsoft C _dos_keep function ?

#2488
From: Jim Dunn
Date: Tue, 02 Oct 1990 15:08
251 lines
9029 bytes
In article monty@blackhole.lerc.nasa.gov (Monty Andro) writes:
>
>I'm attempting to use Microsoft C's _dos_keep function but I 
>do not know how to calculate the 2'd paramter required by this
>function.  The 2'd paramter is the desired size in 16 byte paragraphs
>of the program that you want to remain resident.  Does anybody know how to
>calculate this, or is there some function call that I can use to get
>the desired size.  Any help with my problem would be greatly appreciated.
>
>Thanks
>monty

Well, why don't we let MICROSOFT lend an answer for a change, OK?  Here's
the Example program that popped up on my screen when I inquired about the
_dos_keep function in Microsoft Quick C / Quick Assembler v2.51.

---Cut Here---
/* ALARM.C illustrates in-line assembly and functions or keywords
 * related to terminate-and-stay-resident programs. Functions include:
 *      _dos_setvect    _dos_getvect    _dos_keep
 *      _enable         _disable        _chain_intr
 *
 * Keywords:
 *      _interrupt      _asm
 * Directive:
 *      #pragma
 * Pragma:
 *      check_stack     check_pointer   intrinsic
 * Global variables:
 *      _psp
 *
 * WARNING: You should run ALARM from the DOS command line. Running from
 * inside the QuickC environment will cause subsequent memory problems.
 *
 * See MOVEMEM.C for another pragma example.
 */

#include <dos.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/* Stack and pointer checking off */
#pragma check_stack( off )
#pragma check_pointer( off )
#pragma intrinsic( _enable, _disable )

/* In-line assembler macro to sound a bell. Note that comments in macros must
 * be in the C format, not the assembler format.
 */
#define BEEP() _asm { \
                        _asm     sub  bx, bx    /* Page 0          */ \
                        _asm     mov  ax, 0E07h /* TTY bell        */ \
                        _asm     int  10h       /* BIOS 10         */ \
                    }

#define TICKPERMIN  1092L
#define MINPERHOUR  60L
enum BOOLEAN { FALSE, TRUE };

/* Prototypes for interrupt functions */
void (_interrupt _far *oldtimer)( void );
void (_interrupt _far *oldvideo)( void );
void _interrupt _far newtimer( void );
void _interrupt _far newvideo( unsigned _es, unsigned _ds, unsigned _di,
                               unsigned _si, unsigned _bp, unsigned _sp,
                               unsigned _bx, unsigned _dx, unsigned _cx,
                               unsigned _ax, unsigned _ip, unsigned _cs,
                               unsigned _flags );

/* Variables that will be accessed inside TSR must be global. */
int  ftimesup = FALSE, finvideo = FALSE;
long goaltick;
long _far *pcurtick = (long _far *)0x0000046cL;

/* Huge pointers force compiler to do segment arithmetic for us. */
char _huge *tsrstack;
char _huge *appstack;
char _huge *tsrbottom;

void main( int argc, char **argv )
{
    long minute, hour;
    unsigned tsrsize;

    /* Initialize stack and bottom of program. */
    _asm mov  WORD PTR tsrstack[0], sp
    _asm mov  WORD PTR tsrstack[2], ss
    FP_SEG( tsrbottom ) = _psp;
    FP_OFF( tsrbottom ) = 0;

    /* Program size is:
     *     top of stack
     *   - bottom of program (converted to paragraphs)
     *   + one extra paragraph
     */
    tsrsize = ((tsrstack - tsrbottom) >> 4) + 1;

    /* If command line not given, show syntax and quit. */
    if( argc < 2 )
    {
        puts( "  Syntax: ALARM <hhmm> " );
        puts( "     where <hhmm> is time (military format) to ring alarm" );
        exit( 1 );
    }

    /* Convert time to ticks past midnight. Time must include 0 in first
     * position (0930, not 930). Time must be later than current time.
     */
    minute = atol( argv[1] + 2 );
    argv[1][2] = 0;
    hour = atol( argv[1] );
    goaltick = (hour * MINPERHOUR * TICKPERMIN) + (minute * TICKPERMIN);
    if( *pcurtick > goaltick )
    {
        puts( "It's past that time now" );
        exit( 1 );
    }

    /* Replace existing timer and video routines with ours. */
    oldtimer = _dos_getvect( 0x1c );
    _dos_setvect( 0x1c, newtimer );
    oldvideo = _dos_getvect( 0x10 );
    _dos_setvect( 0x10, newvideo );

    /* Free the PSP segment and terminate with program resident. */
    _dos_freemem( _psp );
    _dos_keep( 0, tsrsize );
}

/* Our timer interrupt compares current time to goal. If earlier,
 * it just continues. If later, it beeps and sets a flag to quit checking.
 */
void _interrupt _far newtimer()
{
    if( ftimesup )
        _chain_intr( oldtimer );
    else
    {
        /* First, execute the original timer interrupt. */
        (*oldtimer)();

        /* Activate if two conditions are met: First, it's past time for
         * the alarm. Second, we are not in a video interrupt. Checking
         * the video interrupt prevents the rare but potentially
         * dangerous case of calling INT 10 to beep while INT 10 is
         * already running.
         */
        if( (*pcurtick > goaltick) && !finvideo )
        {
            /* Set flag so we'll never return. */
            ftimesup = TRUE;

            /* Save current stack of application, and set old stack of TSR.
             * This is for safety since we don't know the state of the
             * application stack, but we do know the state of our own stack.
             * Turn off interrupts during the stack switch.
             */
            _disable();
            _asm
            {
                mov  WORD PTR appstack[0], sp   ; Save current stack
                mov  WORD PTR appstack[2], ss
                mov  sp, WORD PTR tsrstack[0]   ; Load new stack
                mov  ss, WORD PTR tsrstack[2]
            }
            _enable();

            BEEP();
            BEEP();
            BEEP();

            /* Restore application stack. */
            _disable();
            _asm
            {
                mov  sp, WORD PTR appstack[0]
                mov  ss, WORD PTR appstack[2]
            }
            _enable();
        }
    }
}

/* Protects against reentering INT 10 while it is already executing.
 * Although rare, this could be disastrous if the interrupt routine was
 * interrupted while it was accessing a hardware register.
 */
void _interrupt _far newvideo( unsigned _es, unsigned _ds, unsigned _di,
                               unsigned _si, unsigned _bp, unsigned _sp,
                               unsigned _bx, unsigned _dx, unsigned _cx,
                               unsigned _ax, unsigned _ip, unsigned _cs,
                               unsigned _flags )
{
    static unsigned save_bp;

    /* If not already inside interrupt, chain to original. */
    if( !finvideo )
        _chain_intr( oldvideo );
    else
    {

        /* Set the inside flag, then make sure all the real registers
         * that might be passed to an interrupt 10h match the parameter
         * registers. Some of the real registers may be modified by the
         * preceding code. Note that BP must be saved in a static (nonstack)
         * variable so that it can be retrieved without modifying the stack.
         */
        ++finvideo;
        _asm
        {
            mov ax, _ax
            mov bx, _bx
            mov cx, _cx
            mov dx, _dx
            mov es, _es
            mov di, _di
            mov save_bp, bp
            mov bp, _bp
        }

        /* Call the original interrupt. */
        (*oldvideo)();

        /* Make sure that any values returned in real registers by the
         * interrupt are updated in the parameter registers. Reset the flag.
         */
        _asm
        {
            mov bp, save_bp
            mov _bp, bp
            mov _di, di
            mov _es, es
            mov _dx, dx
            mov _cx, cx
            mov _bx, bx
            mov _ax, ax
        }
        --finvideo;
    }
}
---Cut Here---

You're welcome, and best of skill!
:)

 Jim Dunn; jdunn@dsac.dla.mil; AV 850-9713; AT&T 614-238-9713; FAX 614-238-9936
 Department of Defense-Defense Logistics Agency-Systems Automation Center, DSAC
 *******  Compuserve Users Send Mail To:  >INTERNET:jdunn@dsac.dla.mil  *******
 "I thought I needed to be free-but when I was free-I just needed to be needed"
Technical Details
Message-ID: <2584@dsacg4.dsac.dla.mil>
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!rutgers!cs.utexas.edu!uunet!tut.cis.ohio-state.edu!dsac.dla.mil!dsacg3.dsac.dla.mil!dsacg4.dsac.dla.mil!nol2321
References: <1990Sep29.125312.20416@eagle.lerc.nasa.gov>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!rutgers!cs.utexas.edu!uunet!tut.cis.ohio-state.edu!dsac.dla.mil!dsacg3.dsac.dla.mil!dsacg4.dsac.dla.mil!nol2321
From: nol2321@dsacg4.dsac.dla.mil (Jim Dunn)
Newsgroups: comp.os.msdos.programmer
Subject: Re: Calc. program size for Microsoft C _dos_keep function ?
Keywords: TSR
Message-ID: <2584@dsacg4.dsac.dla.mil>
Date: 2 Oct 90 15:08:10 GMT
References: <1990Sep29.125312.20416@eagle.lerc.nasa.gov>
Distribution: usa
Organization: Defense Logistics Agency Systems Automation Center, Columbus
Lines: 251