home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spiele Shareware / os2games.iso / os2games / fun / quoter / quoter2 / quote.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-11-18  |  12.9 KB  |  388 lines

  1. /****************************************************************************
  2.  * QUOTE.C                                    *
  3.  *                                        *
  4.  *   -    Quote randomly chooses a quote from a quote file chosen at random.  *
  5.  *   The quote chosen is displayed in a window under Presentation Manger.   *
  6.  *   The quote window may be closed by pressing the right mouse button or   *
  7.  *   by pressing any key when Quote has the input focus.  Optionally, the   *
  8.  *   quote window may be set to expire after a specified number of minutes. *
  9.  *                                        *
  10.  * "Quote" is copyright (c) 1990 by Todd B. Crowe.  There is no warranty    *
  11.  * implied or otherwise.  You may copy the program freely but it must be    *
  12.  * accompanied by this notice.    The program may not be sold or distributed  *
  13.  * commercially or otherwise for profit.  I reserve all rights and        *
  14.  * privileges to this program.                            *
  15.  *                                        *
  16.  ****************************************************************************/
  17.  
  18. #define  INCL_DOS
  19. #define  INCL_GPI
  20. #define  INCL_WIN
  21.  
  22. #include <os2.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26.  
  27. // Constants
  28. #define ERR_OK          0     // No errors occured on run
  29. #define ERR_BADARGS  -1     // Bad/missing arguments
  30. #define ERR_REGCLASS -2     // WinRegisterClass failed
  31. #define ERR_WININIT  -3     // Failure to obtain HAB (is this possible?)
  32. #define ERR_MSGQUEUE -4     // Failure to obtain HMQ (usually DETACH'd)
  33. #define ID_TIMER      1     // Timer resource ID
  34. #define MAXQUOTE      16    // Maximum number of quote files/lines
  35. #define BUFFERSIZE    2048    // Buffer for quote file name and quote text
  36.  
  37. // Function prototyping
  38. MRESULT EXPENTRY ClientWndProc(HWND, USHORT, MPARAM, MPARAM);
  39. int    ProcessArguments(int, char **);
  40. int    ParseTime(CHAR *, SHORT *);
  41. SHORT    ReadQuote(CHAR **,SHORT *);
  42. VOID    SeedRandom(VOID);
  43.  
  44. // Profile record structure
  45. typedef struct _PROFILEREC {
  46.     USHORT usSEED;
  47. } PROFILEREC;
  48.  
  49. // Pause & display counters
  50. static SHORT sLength = 0L,sDisplay = 0L;
  51. static BOOL  bDisplay = FALSE;
  52.  
  53. // Private class name (also used to index profile record)
  54. static HAB   hab;
  55. static CHAR  szClientClass[] = "Quote";
  56. static CHAR  szUsage[] = { "Quote - (c)1990   by Todd Crowe\n"
  57.                "USAGE: QUOTE [-{?|Ln|Ttime|Dn}]\n" };
  58.  
  59. int main(int argc, char **argv)
  60. {
  61.     static ULONG flFrameFlags = FCF_DLGBORDER | FCF_TASKLIST;
  62.  
  63.     HMQ   hmq;
  64.     QMSG  qmsg;
  65.     HWND  hwndFrame,hwndClient;
  66.     int   err;
  67.  
  68.     // Process command line arguments
  69.     err = ProcessArguments(argc,argv);
  70.  
  71.     // Initialize PM interface
  72.     if ((hab = WinInitialize(0)) == NULL) return(ERR_WININIT);
  73.     if ((hmq = WinCreateMsgQueue(hab, 0)) == NULL) return(ERR_MSGQUEUE);
  74.  
  75.     // Check to see if the arguments were bad or '-?' was used
  76.     //     if so, put up a message box explaning the proper usage
  77.     if (err == ERR_BADARGS) {
  78.     WinMessageBox(HWND_DESKTOP,NULL,szUsage,szClientClass,0,
  79.         MB_ICONEXCLAMATION|MB_OK|MB_APPLMODAL);
  80.     return(ERR_BADARGS);
  81.     }
  82.  
  83.     // Create a private window class for client window, process messages,
  84.     //     and when complete destroy the client window
  85.     else {
  86.     WinRegisterClass(hab, szClientClass, ClientWndProc, CS_SYNCPAINT, 0);
  87.  
  88.     hwndFrame = WinCreateStdWindow(HWND_DESKTOP, 0L, &flFrameFlags,
  89.         szClientClass, NULL, 0L, 0, 0, &hwndClient);
  90.  
  91.     // Start timer ticking once every minute
  92.     WinStartTimer(hab,hwndClient,ID_TIMER,(USHORT)60000);
  93.  
  94.     while (WinGetMsg(hab, &qmsg, NULL, 0, 0))
  95.         WinDispatchMsg(hab, &qmsg);
  96.  
  97.     // Stop the timer
  98.     WinStopTimer(hab,hwndClient,ID_TIMER);
  99.  
  100.     WinDestroyWindow(hwndClient);
  101.     }
  102.  
  103.     // Cleanup
  104.     WinDestroyMsgQueue(hmq);
  105.     WinTerminate(hab);
  106.     return(ERR_OK);
  107. }
  108.  
  109. /****************************************************************************
  110.  * ClientWndProc                                *
  111.  *                                        *
  112.  *   Standard PM procedure to handle client window messages.  Sizes window  *
  113.  *   to fit text, draws text in the window, waits for input to terminate.   *
  114.  ****************************************************************************/
  115. MRESULT EXPENTRY ClientWndProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  116. {
  117.     SHORT  i;
  118.  
  119.     POINTL ptl;
  120.     HPS    hps;
  121.     SWP    swp;
  122.  
  123.     static SHORT cLines,            // Count of quote lines to print
  124.          cLen;                // Maximum quote line length
  125.     static CHAR  *szLines[MAXQUOTE];        // Pointers to quote lines
  126.     static FONTMETRICS fm;
  127.  
  128.     switch (msg) {
  129.     case WM_CREATE:
  130.         // Read one quote, terminate in case of an error
  131.         if ((cLines = ReadQuote(szLines,&cLen)) == 0) {
  132.         WinPostMsg(hwnd, WM_QUIT, (MPARAM) 0L, (MPARAM) 0L);
  133.         return 0;
  134.         }
  135.  
  136.         if (sLength != 0)
  137.         return 0;
  138.  
  139.     case WM_TIMER:
  140.         // If the window is visible and display time has expired, quit
  141.         if (bDisplay) {
  142.         if (--sDisplay <= 0)
  143.             WinPostMsg(hwnd, WM_QUIT, (MPARAM) 0L, (MPARAM) 0L);
  144.         return 0;
  145.         }
  146.         // Else, if the pause time has expired then display the quote
  147.         else if (--sLength > 0)
  148.         return 0;
  149.  
  150.         // Was display length was set
  151.         if (sDisplay > 0)
  152.         bDisplay = TRUE;
  153.  
  154.         hps = WinGetPS(hwnd);
  155.  
  156.         // Find the DESKTOP Dimensions
  157.         WinQueryWindowPos(HWND_DESKTOP, &swp);
  158.  
  159.         // Get the dimensions of the current font
  160.         GpiQueryFontMetrics(hps, (LONG) sizeof fm, &fm);
  161.  
  162.         // Calculate a window width based on the average width of the
  163.         //     current character set.
  164.         i = ((SHORT) fm.lAveCharWidth * cLen) +
  165.         ((SHORT) fm.lAveCharWidth * cLen) / 6;
  166.  
  167.         // Size & Center the window to fit the quote
  168.         WinSetWindowPos(
  169.            WinQueryWindow(hwnd, QW_PARENT, FALSE), HWND_TOP,
  170.            max((swp.cx-i)/2,4),
  171.            max((swp.cy-(cLines * (SHORT) fm.lMaxBaselineExt))/2,4),
  172.            min(i, swp.cx-8),
  173.            min(cLines * (SHORT) fm.lMaxBaselineExt +
  174.            2 * (SHORT) fm.lMaxDescender + 1, swp.cy-8),
  175.            SWP_ACTIVATE | SWP_SHOW | SWP_SIZE | SWP_MOVE);
  176.  
  177.         WinReleasePS(hps);
  178.  
  179.         return 0;
  180.  
  181.     case WM_PAINT:
  182.         hps = WinBeginPaint(hwnd, NULL, NULL);
  183.         GpiErase(hps);
  184.  
  185.         // Draw each line of the quote
  186.         ptl.x = 4L;
  187.         ptl.y = fm.lMaxDescender + 1;
  188.         for (i=cLines-1;i>=0;i--) {
  189.         GpiCharStringAt(hps, &ptl, strlen(szLines[i]), szLines[i]);
  190.         ptl.y += fm.lMaxBaselineExt;// + fm.lMaxDescender;
  191.         }
  192.  
  193.             WinEndPaint(hps);
  194.             return 0;
  195.  
  196.     case WM_BUTTON2DOWN: case WM_CHAR:
  197.         // Terminate on any button or key press
  198.         WinPostMsg(hwnd, WM_QUIT, (MPARAM) 0L, (MPARAM) 0L);
  199.  
  200.         // Make sure the timer is stopped
  201.         WinStopTimer(hab,hwnd,ID_TIMER);
  202.         return 0;
  203.         }
  204.     return WinDefWindowProc(hwnd, msg, mp1, mp2);
  205. }
  206.  
  207.  
  208. /****************************************************************************
  209.  * ProcessArguments                                *
  210.  *      argc: count of command line arguments                 *
  211.  *      argv: pointer to list of command line arguments            *
  212.  *    RETURN: ERR_OK, ERR_BADARGS                        *
  213.  *                                        *
  214.  *   Processes command line arguments.    Pauses program if requested by user *
  215.  *   and Quote was START'ed.                                                *
  216.  ****************************************************************************/
  217. int ProcessArguments(int argc, char **argv)
  218. {
  219.     int   i;
  220.  
  221.     // Ignore the argv[0] and process the rest
  222.     for (i=1;i<argc;i++) {
  223.     // Make sure each argument is preceded by a switch character
  224.     if (((argv[i][0] != '-') && (argv[i][0] != '/')) ||
  225.         (argv[i][1] == '?'))
  226.         return(ERR_BADARGS);
  227.  
  228.     switch (argv[i][1]) {
  229.       case 'd': case 'D':
  230.         sscanf(&argv[i][2],"%d",&sDisplay);
  231.         if (sDisplay < 0)
  232.         return(ERR_BADARGS);
  233.         break;
  234.       // Set pause length
  235.       case 'l': case 'L':
  236.         sscanf(&argv[i][2],"%d",&sLength);
  237.         if (sLength < 0)
  238.         return(ERR_BADARGS);
  239.         break;
  240.       // Calculate pause length based on current and requested times
  241.       case 't': case 'T':
  242.         if (ParseTime(&argv[i][2],&sLength) != ERR_OK)
  243.         return(ERR_BADARGS);
  244.         break;
  245.       }
  246.     }
  247.  
  248.     return(ERR_OK);
  249. }
  250.  
  251. /****************************************************************************
  252.  * ParseTime                                    *
  253.  *    cbTime: pointer to string containing request time (in HH:MM)        *
  254.  *   ulEndTime: pointer to variable which will contain pause time (in msec) *
  255.  *    RETURN: ERR_OK, ERR_BADARGS                        *
  256.  *                                        *
  257.  *   Processes command line arguments.    Pauses program if requested by user *
  258.  *   and Quote was START'ed.                                                *
  259.  ****************************************************************************/
  260. int ParseTime(CHAR *cbTime,SHORT *sEndTime)
  261. {
  262.     UCHAR    ucHours = 0,ucMinutes = 0;
  263.     DATETIME dtDate;
  264.  
  265.     // Make sure colons are in the proper position
  266.     if ((strlen(cbTime) != 5) || (cbTime[2] != ':'))
  267.     return (ERR_BADARGS);
  268.  
  269.     // Calculate request time
  270.     sscanf(cbTime,"%d:%d",&ucHours,&ucMinutes);
  271.     *sEndTime = (SHORT)ucHours*60 + (SHORT)ucMinutes;
  272.  
  273.     // Subtract current time
  274.     DosGetDateTime(&dtDate);
  275.     *sEndTime -= (SHORT)dtDate.hours*60 + (SHORT)dtDate.minutes;
  276.  
  277.     // Make sure pause time is valid (within 24 hours)
  278.     if (*sEndTime < 0)
  279.     *sEndTime += 1440;
  280.  
  281.     return(ERR_OK);
  282. }
  283.  
  284. /****************************************************************************
  285.  * ReadQuote                                    *
  286.  *  QuoteArray: array of pointers to character strings                *
  287.  *      cLen: contains length of longest line of quote on return        *
  288.  *    RETURN: number of lines in the quote read, or zero if error        *
  289.  *                                        *
  290.  *   Randomly selects a quote file to open, determines the last quote in    *
  291.  *   the file, and randomly chooses a quote.                    *
  292.  ****************************************************************************/
  293. SHORT ReadQuote(CHAR **QuoteArray,SHORT *cLen)
  294. {
  295.        USHORT      usLine,            // Current quote on read
  296.                usQuote = 0;        // # Quote files, quote #
  297.        SHORT       cFiles = 1,
  298.                cLines = 0,        // Count of lines in quote
  299.                cLineLen = 0,
  300.                idxData = 0;        // Index into buffer
  301.        FILE        *fInput;
  302.        HDIR        hdir = HDIR_CREATE;
  303.        FILEFINDBUF findbuf;
  304.  
  305.     static CHAR        szData[BUFFERSIZE];  // Quote file/text buffer
  306.  
  307.     // Seed the random number generator
  308.     SeedRandom();
  309.  
  310.     // Form a list of all the quote files available (up to MAXQUOTE)
  311.     //    - Uses QuoteArray as a list of pointers to quote file names
  312.     //    - Uses szData as a buffer to contain the quote file names
  313.     DosFindFirst("*.QUO", &hdir, FILE_NORMAL | FILE_READONLY,
  314.     &findbuf, sizeof(findbuf), &cFiles, 0L);
  315.     while ((cFiles > 0) && (usQuote < MAXQUOTE) &&
  316.        (idxData + CCHMAXPATHCOMP <= BUFFERSIZE)) {
  317.     strcpy(&szData[idxData],findbuf.achName);
  318.     QuoteArray[usQuote++] = &szData[idxData];
  319.     idxData += findbuf.cchName + 1;
  320.     DosFindNext(hdir, &findbuf, sizeof(findbuf), &cFiles);
  321.     }
  322.  
  323.     // If no quote files where found or there is a problem opening the file
  324.     //     selected (randomly), return that fact
  325.     if ((usQuote < 1) ||
  326.     ((fInput = fopen(QuoteArray[rand() % (int) usQuote],"r")) == NULL))
  327.     return 0;
  328.  
  329.     // Find the number of the last quote in the file
  330.     fseek(fInput,-128L,SEEK_END);
  331.     fgets(&szData[0],96,fInput);
  332.     do {
  333.     fscanf(fInput,"%5d%%",&usQuote);
  334.     fgets(&szData[0],96,fInput);
  335.     } while (!feof(fInput));
  336.     fseek(fInput,0L,SEEK_SET);
  337.  
  338.     // Initialize the quote buffer & max quote line length
  339.     idxData = 0;
  340.     *cLen = 0;
  341.  
  342.     // Choose a quote at random
  343.     usQuote = (usQuote > 0) ? (USHORT) rand() % usQuote+1 : 0;
  344.  
  345.     // Form a list of the lines of the selected quote (up to BUFFERSIZE)
  346.     //    - Uses QuoteArray as a list of pointers to quote lines
  347.     //    - Uses szData as a buffer to contain the quote lines
  348.     do {
  349.     fscanf(fInput,"%5d%%",&usLine);
  350.     fgets(&szData[idxData],96,fInput);
  351.     if ((usQuote == usLine) &&
  352.         ((cLineLen = strlen(&szData[idxData])) > 0)) {
  353.         *cLen = max(*cLen,cLineLen-1);
  354.         szData[idxData+cLineLen-1] = 0;
  355.         QuoteArray[cLines++] = &szData[idxData];
  356.         idxData += cLineLen;
  357.         }
  358.     } while ((usQuote >= usLine) && (idxData < BUFFERSIZE-97) &&
  359.          !feof(fInput));
  360.  
  361.     // Return a count of the lines read
  362.     return cLines;
  363. }
  364.  
  365. /****************************************************************************
  366.  * SeedRandom                                    *
  367.  *   Reads seed from profile record, seeds the random number generator, and *
  368.  *   puts a new seed in the profile record.                    *
  369.  ****************************************************************************/
  370. VOID SeedRandom(VOID)
  371. {
  372.     ULONG      cb;
  373.     PROFILEREC prfProfile;
  374.  
  375.     // Read in the profile data if it exists
  376.     PrfQueryProfileSize(HINI_USERPROFILE,szClientClass,"Data",&cb);
  377.     if (cb == sizeof(PROFILEREC))
  378.     PrfQueryProfileData(HINI_USERPROFILE,szClientClass,"Data",&prfProfile,&cb);
  379.  
  380.     // Seed the random number generator from seed in profile
  381.     srand((unsigned int) prfProfile.usSEED);
  382.     prfProfile.usSEED = (USHORT) rand();
  383.  
  384.     // Write profile information
  385.     PrfWriteProfileData(HINI_USERPROFILE,szClientClass,"Data",
  386.     &prfProfile,sizeof(PROFILEREC));
  387. }
  388.