home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / INTERNET / UPC2S1.ZIP / SSLEEP.C < prev    next >
C/C++ Source or Header  |  1993-09-26  |  18KB  |  515 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    s s l e e p . c                                                 */
  3. /*                                                                    */
  4. /*    Smart sleep routines for UUPC/extended                          */
  5. /*                                                                    */
  6. /*    Written by Dave Watt, modified by Drew Derbyshire               */
  7. /*                                                                    */
  8. /*    Generates DOS specific code with Windows support by default,    */
  9. /*    generates call to OS/2 family API if FAMILYAPI is defined       */
  10. /*    generates calls to Windows/NT if WIN32 is defined               */
  11. /*--------------------------------------------------------------------*/
  12.  
  13. /*--------------------------------------------------------------------*/
  14. /*                          RCS Information                           */
  15. /*--------------------------------------------------------------------*/
  16.  
  17. /*
  18.  *    $Id: ssleep.c 1.10 1993/09/27 02:42:11 ahd Exp $
  19.  *
  20.  *    Revision history:
  21.  *    $Log: ssleep.c $
  22.  *     Revision 1.10  1993/09/27  02:42:11  ahd
  23.  *     Use signed number for delay computations under DOS
  24.  *
  25.  *     Revision 1.9  1993/09/24  03:43:27  ahd
  26.  *     Use OS/2 error messages
  27.  *
  28.  *     Revision 1.8  1993/09/20  04:39:51  ahd
  29.  *     OS/2 2.x support
  30.  *
  31.  *     Revision 1.7  1993/08/02  03:24:59  ahd
  32.  *     Further changes in support of Robert Denny's Windows 3.x support
  33.  *
  34.  *     Revision 1.6  1993/07/31  16:22:16  ahd
  35.  *     Changes in support of Robert Denny's Windows 3.x support
  36.  *
  37.  *     Revision 1.5  1993/07/22  23:19:50  ahd
  38.  *     First pass for Robert Denny's Windows 3.x support changes
  39.  *
  40.  *     Revision 1.4  1993/04/11  00:32:29  ahd
  41.  *     Global edits for year, TEXT, etc.
  42.  *
  43.  * Revision 1.3  1992/12/12  16:12:13  ahd
  44.  * Correct test for DesqView
  45.  *
  46.  * Revision 1.2  1992/12/07  02:43:20  ahd
  47.  * Add DesqView support from David M. Watt
  48.  *
  49.  * Revision 1.1  1992/11/16  05:00:26  ahd
  50.  * Initial revision
  51.  *
  52.  */
  53.  
  54. /*--------------------------------------------------------------------*/
  55. /*                        System include files                        */
  56. /*--------------------------------------------------------------------*/
  57.  
  58. #include <limits.h>
  59. #include <stdio.h>
  60. #include <stdlib.h>
  61. #include <signal.h>
  62. #include <time.h>
  63.  
  64. /*--------------------------------------------------------------------*/
  65. /*               MS-DOS and OS/2 specific include files               */
  66. /*--------------------------------------------------------------------*/
  67.  
  68. #if defined(FAMILYAPI) || defined(__OS2__)
  69.  
  70. #define INCL_NOPM
  71. #define INCL_BASE
  72. #include <os2.h>
  73.  
  74. #else
  75.  
  76. #include <dos.h>
  77. #include <sys/timeb.h>
  78.  
  79. #endif
  80.  
  81. #if defined(WIN32) || defined(_Windows)
  82. #include <windows.h>
  83. #endif
  84.  
  85. /*--------------------------------------------------------------------*/
  86. /*                    UUPC/extended include files                     */
  87. /*--------------------------------------------------------------------*/
  88.  
  89. #include "lib.h"
  90. #include "ssleep.h"
  91. #include "safeio.h"
  92. #include "catcher.h"
  93.  
  94. #if defined(_Windows)
  95. #include "winutil.h"
  96. #endif
  97.  
  98.  
  99. #if defined(FAMILYAPI) || defined(__OS2__)
  100. #include "pos2err.h"
  101. #endif
  102.  
  103. /*--------------------------------------------------------------------*/
  104. /*                          Global variables                          */
  105. /*--------------------------------------------------------------------*/
  106.  
  107. #if defined(FAMILYAPI) || defined(__OS2__)
  108. currentfile();
  109. #endif
  110.  
  111.  
  112. /*--------------------------------------------------------------------*/
  113. /*                     MS-DOS specific functions                      */
  114. /*--------------------------------------------------------------------*/
  115.  
  116. #if !defined(FAMILYAPI) && !defined(__OS2__)
  117.  
  118. currentfile();
  119.  
  120. #define MULTIPLEX 0x2F
  121. #define DESQVIEW 0x15
  122.  
  123. #ifdef _Windows
  124.  
  125. static void WindowsDelay( const int milliseconds );
  126.  
  127. /*--------------------------------------------------------------------*/
  128. /*    W i n d o w s D e l a y                                         */
  129. /*                                                                    */
  130. /*    Delay processing under Windows                                  */
  131. /*                                                                    */
  132. /*    NOTE: Minimum resolution is 54.925 ms.                          */
  133. /*--------------------------------------------------------------------*/
  134.  
  135. static void WindowsDelay( const int milliseconds )
  136. {
  137.    MSG msg;
  138.    WORD TimerId = 1;
  139.    BOOL bTimerDone = FALSE;
  140.  
  141.    //
  142.    //    A 0-delay call means give up control to Windows
  143.    //
  144.  
  145.    if (milliseconds == 0)
  146.    {
  147.       while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  148.       {
  149.          TranslateMessage(&msg);
  150.          DispatchMessage(&msg);
  151.       }
  152.       return;
  153.    }
  154.  
  155.    SetTimer( hOurWindow,
  156.             TimerId,
  157.             (milliseconds > 55) ? (WORD)milliseconds : (WORD)55 ,
  158.             NULL );
  159.  
  160.    if ( TimerId == 0 )
  161.    {
  162.       printmsg(0, "WindowsDelay: Unable to set Windows Timer");
  163.       panic();
  164.       return;
  165.    } /* if */
  166.  
  167.    //
  168.    // LOCAL MESSAGE LOOP - Service Windows while waiting for
  169.    // the timer message.
  170.    //
  171.  
  172.    while(!bTimerDone && GetMessage(&msg, NULL, NULL, NULL))
  173.    {
  174.       TranslateMessage(&msg);
  175.       DispatchMessage(&msg);
  176.       if (msg.message == WM_TIMER)
  177.          bTimerDone = TRUE;
  178.    }
  179.  
  180.    if (KillTimer( hOurWindow, TimerId ) == 0)
  181.       printmsg(0, "WindowsDelay: Unable to kill Windows Timer %d",
  182.                   (int) TimerId );
  183.  
  184. } /* WindowsDelay */
  185.  
  186. #else
  187.  
  188. #ifndef WIN32
  189.  
  190. /*--------------------------------------------------------------------*/
  191. /*                      Local function declares                       */
  192. /*--------------------------------------------------------------------*/
  193.  
  194. static void WinGiveUpTimeSlice(void);
  195. static int RunningUnderWindows(void);
  196. static int RunningUnderDesqview(void);
  197. static void DVGiveUpTimeSlice(void);
  198.  
  199. /*--------------------------------------------------------------------*/
  200. /*              Use this first to see if the rest are OK              */
  201. /*                                                                    */
  202. /*                  MOV AX,1600h   ; Check for win386/win3.0          */
  203. /*                                   present                          */
  204. /*                  INT 2Fh                                           */
  205. /* Return AL = 0 -> No Windows, AL = 80 -> No WIn386 mode             */
  206. /*        AL = 1 or AL = FFh -> Win386 2.xx running                   */
  207. /*   else AL = Major version (3), AH = Minor version                  */
  208. /*--------------------------------------------------------------------*/
  209. /* --------------- Release time slice                                 */
  210. /*                  MOV AX,1680h   ; **** Release time slice          */
  211. /*                  INT 2Fh        ; Let someone else run             */
  212. /* Return code is AL = 80H -> service not installed, AL = 0 -> all    */
  213. /*                                                              OK    */
  214. /*--------------------------------------------------------------------*/
  215. /* --------------- Enter critical section (disable task switch)       */
  216. /*                  MOV AX,1681H   ; Don't tread on me!               */
  217. /*                  INT 2Fh                                           */
  218. /*--------------------------------------------------------------------*/
  219. /* --------------- End critical section (Permit task switching)       */
  220. /*                  MOV AX,1682h                                      */
  221. /*                  INT 2Fh                                           */
  222. /*--------------------------------------------------------------------*/
  223.  
  224. /*--------------------------------------------------------------------*/
  225. /*    R u n n i n g U n d e r W i n d o w s                           */
  226. /*                                                                    */
  227. /*    Determines if we are running under MS-Windows 386 or            */
  228. /*    MS-Windows 3.  We save the result, to avoid excessively         */
  229. /*    disabling interrupts when in a spin loop.                       */
  230. /*--------------------------------------------------------------------*/
  231.  
  232. static int RunningUnderWindows(void)
  233. {
  234.  
  235.    static int result = 2;
  236.    union REGS inregs, outregs;
  237.    static const int irq = MULTIPLEX;
  238.  
  239.    if (result != 2)           /* First call?                         */
  240.       return result;          /* No --> Return saved result          */
  241.  
  242.    inregs.x.ax = 0x1600;
  243.    int86(irq, &inregs, &outregs);
  244.    if ( (outregs.h.al & 0x7f) == 0)
  245.       result = 0;
  246.    else
  247.       result = 1;
  248.  
  249.    return result;
  250.  
  251. } /* RunningUnderWindows */
  252.  
  253. /*--------------------------------------------------------------------*/
  254. /*    W i n G i v e U p T i m e S l i c e                             */
  255. /*                                                                    */
  256. /*    Surrender our time slice when executing under Windows/386       */
  257. /*    or Windows release 3.                                           */
  258. /*--------------------------------------------------------------------*/
  259.  
  260. static void WinGiveUpTimeSlice(void)
  261. {
  262.    union REGS inregs, outregs;
  263.    static const int irq = MULTIPLEX;
  264.  
  265.    inregs.x.ax = 0x1680;
  266.    int86(irq, &inregs, &outregs);
  267.    if (outregs.h.al != 0) {
  268.       printmsg(0,"Problem giving up timeslice:  %u\n", outregs.h.al);
  269.       panic();
  270.    }
  271. } /* WinGiveUpTimeSlice */
  272.  
  273. /*--------------------------------------------------------------------*/
  274. /*    R u n n i n g U n d e r D e s q v i e w                         */
  275. /*                                                                    */
  276. /*    Returns TRUE if running under that OTHER DOS multi-tasker.      */
  277. /*--------------------------------------------------------------------*/
  278.  
  279. static int RunningUnderDesqview(void)
  280. {
  281.    static int result = 2;
  282.    union REGS inregs, outregs;
  283.  
  284.    if (result != 2)           /* First call?                         */
  285.       return result;          /* No --> Return saved result          */
  286.  
  287.    inregs.x.ax = 0x2B01;      /* Dos Set Date function */
  288.    inregs.x.cx = 0x4445;      /* CX DX = 'DESQ' */
  289.    inregs.x.dx = 0x5351;
  290.  
  291.    intdos(&inregs, &outregs);
  292.    if (outregs.h.al == 0xff) {
  293.       result = 0;
  294.    } else {
  295.       printmsg(4, "RunningUnderDesqview:  Running under DesqView (AX=0x%x)",
  296.                (int) outregs.x.ax);
  297.       result = 1;
  298.    }
  299.  
  300.    return result;
  301.  
  302. } /* RunningUnderDesqview */
  303.  
  304. /*--------------------------------------------------------------------*/
  305. /*    D V G i v e U p T i m e S l i c e                               */
  306. /*                                                                    */
  307. /*    Surrender the CPU under DesqView                                */
  308. /*--------------------------------------------------------------------*/
  309.  
  310. static void DVGiveUpTimeSlice(void)
  311. {
  312. #ifdef __TURBOC__
  313.    asm {
  314. #else
  315.    _asm \
  316.       {
  317. #endif
  318.       push ax
  319.       mov ax, 101AH
  320.                               /* Switch over to Desqview's stack  */
  321.       int     15H
  322.       mov ax, 1000H
  323.                               /* Give up the timeslice            */
  324.       int     15H
  325.       mov ax, 1025H
  326.                               /* Switch stack back to application */
  327.       int     15H
  328.       pop ax
  329.       }
  330.  
  331. } /* DVGiveUpTimeSlice */
  332.  
  333. #endif /* _Windows */
  334. #endif /* WIN32 */
  335. #endif
  336.  
  337.  
  338. /*--------------------------------------------------------------------*/
  339. /*    ssleep() - wait n seconds                                       */
  340. /*                                                                    */
  341. /*    Simply delay until n seconds have passed.                       */
  342. /*--------------------------------------------------------------------*/
  343.  
  344. void ssleep(time_t interval)
  345. {
  346.    time_t start = time((time_t *)NULL);
  347.    time_t left = interval;
  348.  
  349. /*--------------------------------------------------------------------*/
  350. /*            Break the spin into chunks ddelay can handle            */
  351. /*--------------------------------------------------------------------*/
  352.  
  353.    while ( (left*1000L) > (long) INT_MAX )
  354.    {
  355.       ddelay( 5000 );         /* Five seconds per pass               */
  356.       left = max(interval - (time( NULL ) - start),0);
  357.    } /* while */
  358.  
  359. /*--------------------------------------------------------------------*/
  360. /*                 Final delay for the time remaining                 */
  361. /*--------------------------------------------------------------------*/
  362.  
  363.    ddelay( (int) (left * 1000L) );
  364.  
  365. } /*ssleep*/
  366.  
  367. /*--------------------------------------------------------------------*/
  368. /*    d d e l a y                                                     */
  369. /*                                                                    */
  370. /*    Delay for an interval of milliseconds                           */
  371. /*--------------------------------------------------------------------*/
  372.  
  373. void   ddelay   (KEWSHORT interval )
  374. {
  375.  
  376. #if defined(FAMILYAPI) || defined(__OS2__)
  377.  
  378.    USHORT result;
  379.  
  380. #elif !defined(_Windows)
  381.  
  382.    struct timeb t;
  383.    time_t seconds;
  384.    unsigned last;
  385.    time_t milliseconds = interval;
  386.  
  387. #endif
  388.  
  389. #ifndef _Windows
  390.  
  391. /*--------------------------------------------------------------------*/
  392. /*           Check for user aborts via the ESC (escape) key           */
  393. /*--------------------------------------------------------------------*/
  394.  
  395.    if (bflag[F_ESCAPE])       /* Special Ctrl-C processing avail?    */
  396.    {
  397.       boolean beep = TRUE;
  398.  
  399.       while (safepeek())      /* Yes --> While character in buffer   */
  400.       {
  401.          if (safein() == '\033') /* Look for ESC                     */
  402.             raise( SIGINT );     /* Yes --> eject via std exit       */
  403.          else if ( beep )
  404.          {
  405.              putchar('\a');      /* No --> Complain to user          */
  406.              beep = FALSE;       /* But be nice about it ...
  407.                                     only once per pass through here  */
  408.          } /* else if ( beep ) */
  409.       } /* while */
  410.  
  411.    } /* if (bflag[F_ESCAPE]) */
  412.  
  413. #endif /* _Windows */
  414.  
  415. /*--------------------------------------------------------------------*/
  416. /*                          Now do the wait                           */
  417. /*--------------------------------------------------------------------*/
  418.  
  419. /*--------------------------------------------------------------------*/
  420. /*                          Windows/NT wait                           */
  421. /*--------------------------------------------------------------------*/
  422.  
  423. #ifdef WIN32
  424.    Sleep(interval);
  425.  
  426. /*--------------------------------------------------------------------*/
  427. /*                           Windows wait                             */
  428. /*--------------------------------------------------------------------*/
  429.  
  430. #elif defined(_Windows)
  431.    WindowsDelay(interval);
  432.  
  433. /*--------------------------------------------------------------------*/
  434. /*                             OS/2 wait                              */
  435. /*--------------------------------------------------------------------*/
  436.  
  437. #elif defined(FAMILYAPI) || defined(__OS2__)
  438.  
  439.    result = DosSleep(interval);
  440.    if (result)
  441.       printOS2error( "DosSleep", result );
  442. #else
  443.  
  444. /*--------------------------------------------------------------------*/
  445. /*                            MS-DOS wait                             */
  446. /*--------------------------------------------------------------------*/
  447.  
  448. #ifdef __TURBOC__
  449.    enable();
  450. #else
  451.    _enable();
  452. #endif
  453.  
  454. /*--------------------------------------------------------------------*/
  455. /*       Handle the special case of 0 delay, which is simply a        */
  456. /*                  request to give up our timeslice                  */
  457. /*--------------------------------------------------------------------*/
  458.  
  459.    if (milliseconds == 0)     /* Make it compatible with DosSleep    */
  460.    {
  461.  
  462.       if (RunningUnderWindows())
  463.          WinGiveUpTimeSlice( );
  464.       else if (RunningUnderDesqview())
  465.          DVGiveUpTimeSlice();
  466.  
  467.       return;
  468.    } /* if */
  469.  
  470.    ftime(&t);                 /* Get a starting time                 */
  471.    last = t.millitm;          /* Save milliseconds portion           */
  472.    seconds = t.time;          /* Save seconds as well                */
  473.  
  474.    while( milliseconds > 0)   /* Begin the spin loop                 */
  475.    {
  476.  
  477.       if (RunningUnderWindows())
  478.          WinGiveUpTimeSlice();
  479.       else if (RunningUnderDesqview())
  480.          DVGiveUpTimeSlice();
  481.       else {
  482.  
  483. #ifdef __TURBOC__
  484.  
  485.          delay( (short) milliseconds );
  486.  
  487. #else
  488.  
  489.          int volatile count;  /* Don't let compiler optimize this    */
  490.          for ( count = 0; count < 2400; count ++);
  491.                               /* We spin so that interrupts are
  492.                                  enabled for most of the loop        */
  493. #endif
  494.  
  495.       } /* else */
  496.  
  497.       ftime(&t);              /* Take a new time check               */
  498.  
  499.       if (t.time == seconds)  /* Same second as last pass?           */
  500.          milliseconds -= (t.millitm - last); /* Yes --> mSecond delta*/
  501.       else
  502.          milliseconds -= 1000 * (int) (t.time - seconds)
  503.                               - (last - t.millitm);
  504.                               /* No --> Handle wrap of mSeconds      */
  505.  
  506.       last = t.millitm;       /* Update last tick indicator          */
  507.       seconds = t.time;       /* Update this as well; only needed if
  508.                                  it changed (see above), but it
  509.                                  kills time (which is our job)       */
  510.    } /* while */
  511.  
  512. #endif /* FAMILYAPI */
  513.  
  514. } /* ddelay */
  515.