home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c496 / 1.img / SOURCE.WPK / MEMOS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-20  |  17.1 KB  |  757 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include <time.h>
  6.  
  7. #include "structs.h"
  8.  
  9. /* This program implements a simple memo facility.
  10.  * Memos may be added to a memo file, displayed
  11.  * on the screen, and deleted.
  12.  *
  13.  * Modified    by        reason
  14.  * ========    ==        ======
  15.  * 87/10/02    Steve McDowell    Initial implementation.
  16.  * 88/09/20    Steve McDowell    Fixed up some style issues,
  17.  *                introduced use of TRUE and FALSE.
  18.  * 91/02/14    Jack Schueler    For QNX, support different memo file name.
  19.  */
  20.  
  21. /* Define TRUE and FALSE to make the code more readable.
  22.  */
  23. #define TRUE    1
  24. #define FALSE    0
  25. #if defined(__QNX__)
  26. #define SUFFIX ".db"
  27. #else
  28. #define SUFFIX
  29. #endif
  30.  
  31. static const char FileName[] = { "memos" SUFFIX };
  32. static const char TempName[] = { "tempmemo" SUFFIX };
  33.  
  34. static MEMO_EL *  MemoHead    = NULL;
  35. static int      MemosModified = FALSE;
  36. static int      QuitFlag    = TRUE;
  37.  
  38. typedef enum { INVALID,
  39.            HELP,
  40.            ADD,
  41.            DELETE,
  42.            REPLACE,
  43.            SHOW,
  44.            UP,
  45.            DOWN,
  46.            TOP,
  47.            TODAY,
  48.            SAVE,
  49.            QUIT
  50. } ACTION;
  51.  
  52. /* This table maps action keywords onto the "actions" defined above.
  53.  * The table also defines short forms for the keywords.
  54.  */
  55.  
  56. typedef struct {
  57.     ACTION act;
  58.     char * keyword;
  59. } ACTION_MAP;
  60.  
  61. static ACTION_MAP KeywordMap[] = {
  62.     HELP,     "help",
  63.     HELP,     "h",
  64.     ADD,     "add",
  65.     ADD,     "a",
  66.     DELETE,  "delete",
  67.     DELETE,  "del",
  68.     REPLACE, "replace",
  69.     REPLACE, "rep",
  70.     SHOW,     "show",
  71.     SHOW,     "sh",
  72.     UP,     "up",
  73.     UP,     "u",
  74.     DOWN,     "down",
  75.     DOWN,     "d",
  76.     DOWN,     "",
  77.     TOP,     "top",
  78.     TODAY,     "today",
  79.     TODAY,     "tod",
  80.     SAVE,     "save",
  81.     SAVE,     "sa",
  82.     QUIT,     "quit",
  83.     QUIT,     "q",
  84.  
  85.     INVALID, "" };
  86.  
  87. /* Maximum buffer length (maximum length of line of memo).
  88.  */
  89. #define MAXLEN 80
  90.  
  91. /* Function prototypes generated by changing all static functions to extern
  92.    and then recompiling with -v option which generates "memos.def".
  93.  */
  94. #include "memos.def"
  95.  
  96. static MEMO_EL *    ReadAMemo( FILE * __fid );
  97. static TEXT_LINE *  AddLine( char __buf[], MEMO_EL * __el, TEXT_LINE * __pl );
  98. static ACTION        PromptAction( void );
  99. static ACTION        ReadAction( void );
  100. static ACTION        GetAction( char __buf[] );
  101. static MEMO_EL *    DoActions( MEMO_EL * __el, ACTION __act );
  102. static MEMO_EL *    AddMemo( MEMO_EL * __el );
  103. static MEMO_EL *    EnterAMemo( void );
  104. static MEMO_EL *    DeleteMemo( MEMO_EL * __el );
  105. static MEMO_EL *    DoUpAction( MEMO_EL * __el );
  106. static MEMO_EL *    DoDownAction( MEMO_EL * __el );
  107. static MEMO_EL *    ShowTodaysMemos( void );
  108. static void *        MemoMAlloc( int __size );
  109.  
  110. extern int main( int argc, char * argv[] )
  111. /****************************************/
  112. {
  113.     int       index;
  114.     MEMO_EL * el;
  115.  
  116.     printf( "Memo facility\n" );
  117.  
  118. /* Check for a single argument that is a question mark,
  119.  * If found, then display the usage notes.
  120.  */
  121.     if( argc == 2  &&  strcmp( argv[1], "?" ) == 0 ) {
  122.     Usage();
  123.     exit( 0 );
  124.     }
  125.     ReadMemos();
  126.     MemosModified = FALSE;
  127.     QuitFlag = FALSE;
  128.  
  129. /* Use the command line parameters, if any, as the first actions to
  130.  * be performed on the memos.
  131.  */
  132.     el = NULL;
  133.     for( index = 1; index < argc; ++index ) {
  134.     el = DoActions( el, GetAction( argv[ index ] ) );
  135.     if( QuitFlag ) {
  136.         return( FALSE );
  137.     }
  138.     }
  139.     HandleMemoActions( el );
  140.     return( FALSE );
  141. }
  142.  
  143. static void ReadMemos( void )
  144. /***************************/
  145.  
  146. /* Read the memos file, building the structure to contain it.
  147.  */
  148. {
  149.     FILE *    fid;
  150.     MEMO_EL * new_el;
  151.     MEMO_EL * prev_el;
  152.     int       mcount;
  153.  
  154.     fid = fopen( FileName, "r" );
  155.     if( fid == NULL ) {
  156.     printf( "Memos file not found. Starting with no memos.\n" );
  157.     return;
  158.     }
  159.  
  160. /* Loop reading entire memos.
  161.  */
  162.     prev_el = NULL;
  163.     for( mcount = 0;; mcount++ ) {
  164.     new_el = ReadAMemo( fid );
  165.     if( new_el == NULL ) {
  166.         printf( "%d memo(s) found.\n", mcount );
  167.         fclose( fid );
  168.         return;
  169.     }
  170.     if( prev_el == NULL ) {
  171.         MemoHead = new_el;
  172.         new_el->prev = NULL;
  173.     } else {
  174.         prev_el->next = new_el;
  175.         new_el->prev = prev_el;
  176.     }
  177.     new_el->next = NULL;
  178.     prev_el = new_el;
  179.     }
  180. }
  181.  
  182. static int ReadLine( char buffer[], int len, FILE * fid )
  183. /*******************************************************/
  184.  
  185. /* Read a line from the memos file. Handle any I/O errors and EOF.
  186.  * Return the length read, not counting the newline on the end.
  187.  */
  188. {
  189.     if( fgets( buffer, len, fid ) == NULL ) {
  190.     if( feof( fid ) ) {
  191.         return( EOF );
  192.     }
  193.     perror( "Error reading memos file" );
  194.     abort();
  195.     }
  196.     return( strlen( buffer ) - 1 );
  197. }
  198.  
  199. static MEMO_EL * ReadAMemo( FILE * fid )
  200. /**************************************/
  201.  
  202. /* Read one memo, creating the memo structure and filling it in.
  203.  * Return a pointer to the memo (NULL if none read).
  204.  */
  205. {
  206.     MEMO_EL *    el;
  207.     int     len;
  208.     TEXT_LINE * line;
  209.     char    buffer[ MAXLEN ];
  210.  
  211.     len = ReadLine( buffer, MAXLEN, fid );
  212.     if( len == EOF ) {
  213.     return( NULL );
  214.     }
  215.  
  216. /* First line must be of the form "Date:" or "Date:YY/MM/DD":
  217.  */
  218.     if( (len != 5  &&  len != 13)  ||  strncmp( buffer, "Date:", 5 ) != 0 ) {
  219.     BadFormat();
  220.     }
  221.     buffer[ len ] = '\0';
  222.     el = MemoMAlloc( sizeof( MEMO_EL ) );
  223.     el->text = NULL;
  224.     strcpy( el->date, buffer + 5 );
  225.     line = NULL;
  226.     for( ;; ) {
  227.     len = ReadLine( buffer, MAXLEN, fid );
  228.     if( len == EOF ) {
  229.         BadFormat();
  230.     }
  231.     buffer[ len ] = '\0';
  232.     if( strcmp( buffer, "====" ) == 0 ) {
  233.         return( el );
  234.     }
  235.     line = AddLine( buffer, el, line );
  236.     }
  237. }
  238.  
  239. static TEXT_LINE * AddLine( char buffer[], MEMO_EL * el, TEXT_LINE * prevline )
  240. /*****************************************************************************/
  241.  
  242. /* Add a line of text to the memo, taking care of all the details
  243.  * of modifying the structure.
  244.  */
  245. {
  246.     TEXT_LINE * line;
  247.  
  248.     line = MemoMAlloc( sizeof( TEXT_LINE ) + strlen( buffer ) );
  249.     strcpy( line->text, buffer );
  250.     line->next = NULL;
  251.     if( prevline == NULL ) {
  252.     el->text = line;
  253.     } else {
  254.     prevline->next = line;
  255.     }
  256.     return( line );
  257. }
  258.  
  259. static ACTION PromptAction( void )
  260. /********************************/
  261.  
  262. /* The user didn't specify an action on the command line,
  263.  * so prompt for it.
  264.  */
  265. {
  266.     ACTION act;
  267.  
  268.     for( ;; ) {
  269.     printf( "\nEnter an action:\n" );
  270.     act = ReadAction();
  271.     if( act != INVALID ) {
  272.         return( act );
  273.     }
  274.     printf( "\nThat selection was not valid.\n" );
  275.     Help();
  276.     }
  277. }
  278.  
  279. static ACTION ReadAction( void )
  280. /******************************/
  281.  
  282. /* Read an action from the terminal.
  283.  * Return the action code.
  284.  */
  285. {
  286.     char buffer[80];
  287.  
  288.     if( gets( buffer ) == NULL ) {
  289.     perror( "Error reading action" );
  290.     abort();
  291.     }
  292.     return( GetAction( buffer ) );
  293. }
  294.  
  295. static ACTION GetAction( char buffer[] )
  296. /**************************************/
  297.  
  298. /* Given the string in the buffer, return the action that
  299.  * corresponds to it.
  300.  * The string in the buffer is first zapped into lower case
  301.  * so that mixed-case entries are recognized.
  302.  */
  303. {
  304.     ACTION_MAP * actmap;
  305.     char *     bufptr;
  306.  
  307.     for( bufptr = buffer; *bufptr != '\0'; ++bufptr ) {
  308.     *bufptr = tolower( *bufptr );
  309.     }
  310.     for( actmap = KeywordMap; actmap->act != INVALID; ++actmap ) {
  311.     if( strcmp( buffer, actmap->keyword ) == 0 ) break;
  312.     }
  313.     return( actmap->act );
  314. }
  315.  
  316. static void HandleMemoActions( MEMO_EL * el )
  317. /*******************************************/
  318.  
  319. /* Handle all the actions entered from the keyboard.
  320.  */
  321. {
  322.     for( ;; ) {
  323.     el = DoActions( el, PromptAction() );
  324.     if( QuitFlag ) break;
  325.     }
  326. }
  327.  
  328. static MEMO_EL * DoActions( MEMO_EL * el, ACTION act )
  329. /****************************************************/
  330.  
  331. /* Perform one action on the memos.
  332.  */
  333. {
  334.     MEMO_EL * new_el;
  335.     MEMO_EL * prev_el;
  336.  
  337.     switch( act ) {
  338.       case HELP:
  339.     Help();
  340.     break;
  341.       case ADD:
  342.     new_el = AddMemo( el );
  343.     if( new_el != NULL ) {
  344.         el = new_el;
  345.         MemosModified = TRUE;
  346.     }
  347.     break;
  348.       case DELETE:
  349.     el = DeleteMemo( el );
  350.     MemosModified = TRUE;
  351.     break;
  352.       case REPLACE:
  353.     prev_el = el;
  354.     new_el = AddMemo( el );
  355.     if( new_el != NULL ) {
  356.         DeleteMemo( prev_el );
  357.         MemosModified = TRUE;
  358.     }
  359.     break;
  360.       case SHOW:
  361.     DisplayMemo( el );
  362.     break;
  363.       case UP:
  364.     el = DoUpAction( el );
  365.     break;
  366.       case DOWN:
  367.     el = DoDownAction( el );
  368.     break;
  369.       case TOP:
  370.     el = NULL;
  371.     break;
  372.       case TODAY:
  373.     el = ShowTodaysMemos();
  374.     break;
  375.       case SAVE:
  376.     if( SaveMemos() ) {
  377.         MemosModified = FALSE;
  378.     }
  379.     break;
  380.       case QUIT:
  381.     if( WantToQuit() ) {
  382.         QuitFlag = TRUE;
  383.         return( NULL );
  384.     }
  385.     }
  386.     return( el );
  387. }
  388.  
  389. static MEMO_EL * AddMemo( MEMO_EL * el )
  390. /**************************************/
  391.  
  392. /* Add a memo following the current one.
  393.  */
  394. {
  395.     MEMO_EL * new_el;
  396.     MEMO_EL * next;
  397.  
  398.     new_el = EnterAMemo();
  399.     if( new_el == NULL ) {
  400.     return( NULL );
  401.     }
  402.     if( el == NULL ) {
  403.     next = MemoHead;
  404.     MemoHead = new_el;
  405.     } else {
  406.     next = el->next;
  407.     el->next = new_el;
  408.     }
  409.     new_el->prev = el;
  410.     new_el->next = next;
  411.     if( next != NULL ) {
  412.     next->prev = new_el;
  413.     }
  414.     return( new_el );
  415. }
  416.  
  417. static MEMO_EL * EnterAMemo( void )
  418. /*********************************/
  419.  
  420. /* Read a memo from the keyboard, creating the memo structure and filling it in.
  421.  * Return a pointer to the memo (NULL if none read).
  422.  */
  423. {
  424.     MEMO_EL *    el;
  425.     int     len;
  426.     TEXT_LINE * line;
  427.     char    buffer[ MAXLEN ];
  428.  
  429.     printf( "What date do you want the memo displayed (YY/MM/DD)?\n" );
  430.     if( gets( buffer ) == NULL ) {
  431.     printf( "Error reading from terminal.\n" );
  432.     return( NULL );
  433.     }
  434.     len = strlen( buffer );
  435.     if( len != 0
  436.         &&    (len != 8  ||  buffer[2] != '/'  || buffer[5] != '/') ) {
  437.     printf( "Date is not valid.\n" );
  438.     return( NULL );
  439.     }
  440.     el = MemoMAlloc( sizeof( MEMO_EL ) );
  441.     el->text = NULL;
  442.     strcpy( el->date, buffer );
  443.     line = NULL;
  444.     printf( "\nEnter the text of the memo.\n" );
  445.     printf( "To terminate the memo, enter a line starting with =\n" );
  446.     for( ;; ) {
  447.     if( gets( buffer ) == NULL ) {
  448.         printf( "Error reading from terminal.\n" );
  449.         return( NULL );
  450.     }
  451.     if( buffer[0] == '=' ) {
  452.         return( el );
  453.     }
  454.     line = AddLine( buffer, el, line );
  455.     }
  456. }
  457.  
  458. static MEMO_EL * DeleteMemo( MEMO_EL * el )
  459. /*****************************************/
  460.  
  461. /* Delete the current memo.
  462.  * Return a pointer to another memo, usually the following one.
  463.  */
  464. {
  465.     MEMO_EL * prev;
  466.     MEMO_EL * next;
  467.     MEMO_EL * ret_el;
  468.  
  469.     if( el == NULL ) {
  470.     return( MemoHead );
  471.     }
  472.     prev = el->prev;
  473.     next = el->next;
  474.     ret_el = next;
  475.     if( ret_el == NULL ) {
  476.     ret_el = prev;
  477.     }
  478.  
  479. /* If it's the first memo, set a new MemoHead value.
  480.  */
  481.     if( prev == NULL ) {
  482.     MemoHead = next;
  483.     if( next != NULL ) {
  484.         next->prev = NULL;
  485.     }
  486.     } else {
  487.     prev->next = next;
  488.     if( next != NULL ) {
  489.         next->prev = prev;
  490.     }
  491.     }
  492.     DisposeMemo( el );
  493.     return( ret_el );
  494. }
  495.  
  496. static MEMO_EL * DoUpAction( MEMO_EL * el )
  497. /*****************************************/
  498.  
  499. /* Perform the UP action, including displaying the memo.
  500.  */
  501. {
  502.     if( el == NULL ) {
  503.     DisplayTop();
  504.     } else {
  505.     el = el->prev;
  506.     DisplayMemo( el );
  507.     }
  508.     return( el );
  509. }
  510.  
  511. static MEMO_EL * DoDownAction( MEMO_EL * el )
  512. /*******************************************/
  513.  
  514. /* Perform the DOWN action, including displaying the memo.
  515.  */
  516. {
  517.     MEMO_EL * next_el;
  518.  
  519.     next_el = ( el == NULL ) ? MemoHead : el->next;
  520.     if( next_el == NULL ) {
  521.     printf( "No more memos.\n" );
  522.     } else {
  523.     el = next_el;
  524.     DisplayMemo( el );
  525.     }
  526.     return( el );
  527. }
  528.  
  529. static MEMO_EL * ShowTodaysMemos( void )
  530. /**************************************/
  531.  
  532. /* Show all memos that either:
  533.  * (1) match today's date
  534.  * (2) don't have a date stored.
  535.  * Return a pointer to the last displayed memo.
  536.  */
  537. {
  538.     MEMO_EL * el;
  539.     MEMO_EL * last_el;
  540.     time_t    timer;
  541.     struct tm ltime;
  542.     char      date[9];
  543.  
  544. /* Get today's time in YY/MM/DD format.
  545.  */
  546.     time( &timer );
  547.     ltime = *localtime( &timer );
  548.     strftime( date, 9, "%y/%m/%d", <ime );
  549.     last_el = NULL;
  550.     for( el = MemoHead; el != NULL; el = el->next ) {
  551.     if( el->date[0] == '\0'  ||  strcmp( date, el->date ) == 0 ) {
  552.         DisplayMemo( el );
  553.         last_el = el;
  554.     }
  555.     }
  556.     return( last_el );
  557. }
  558.  
  559. static void DisplayMemo( MEMO_EL * el )
  560. /*************************************/
  561.  
  562. /* Display a memo on the screen.
  563.  */
  564. {
  565.     TEXT_LINE * tline;
  566.  
  567.     if( el == NULL ) {
  568.     DisplayTop();
  569.     return;
  570.     }
  571.     if( el->date[0] == '\0' ){
  572.     printf( "\nUndated memo\n" );
  573.     } else {
  574.     printf( "\nDated: %s\n", el->date );
  575.     }
  576.     for( tline = el->text; tline != NULL; tline = tline->next ){
  577.     printf( "    %s\n", tline->text );
  578.     }
  579. }
  580.  
  581. static int SaveMemos( void )
  582. /**************************/
  583.  
  584. /* Save the memos to the memos file.
  585.  */
  586. {
  587.     FILE *    fid;
  588.     MEMO_EL *    el;
  589.     TEXT_LINE * tline;
  590.     char    buffer[20];
  591.  
  592.     if( MemoHead == NULL ) {
  593.     printf( "No memos to save.\n" );
  594.     return( FALSE );
  595.     }
  596.  
  597. /* Open a temporary filename in case something goes wrong during the save.
  598.  */
  599.     fid = fopen( TempName, "w" );
  600.     if( fid == NULL ) {
  601.     printf( "Unable to open \"%s\" for writing.\n", TempName );
  602.     printf( "Save not performed.\n" );
  603.     return( FALSE );
  604.     }
  605.     for( el = MemoHead; el != NULL; el = el->next ) {
  606.     sprintf( buffer, "Date:%s", el->date );
  607.     if( !WriteLine( buffer, fid ) ) {
  608.         return( FALSE );
  609.     }
  610.     for( tline = el->text; tline != NULL; tline = tline->next ){
  611.         if( !WriteLine( tline->text, fid ) ) {
  612.         return( FALSE );
  613.         }
  614.     }
  615.     if( !WriteLine( "====", fid ) ) {
  616.         return( FALSE );
  617.     }
  618.     }
  619.  
  620. /* Now get rid of the old file, if it's there, then rename the new one.
  621.  */
  622.     fclose( fid );
  623.     fid = fopen( FileName, "r" );
  624.     if( fid != NULL ) {
  625.     fclose( fid );
  626.     if( remove( FileName ) != 0 ) {
  627.         perror( "Can't remove old memos file" );
  628.         return( FALSE );
  629.     }
  630.     }
  631.     if( rename( TempName, FileName ) != 0 ) {
  632.     perror( "Can't rename new memos file" );
  633.     return( FALSE );
  634.     }
  635.     return( TRUE );
  636. }
  637.  
  638. static int WriteLine( char * text, FILE * fid )
  639. /*********************************************/
  640. {
  641.     if( fprintf( fid, "%s\n", text ) < 0 ) {
  642.     perror( "Error writing memos file" );
  643.     return( FALSE );
  644.     }
  645.     return( TRUE );
  646. }
  647.  
  648. /* Routines for displaying HELP and other simple text.
  649.  */
  650.  
  651. static void Usage( void )
  652. /***********************/
  653. {
  654.     printf( "Usage:\n" );
  655.     printf( "    memos ?\n" );
  656.     printf( "         displays this text\n" );
  657.     printf( "  or\n" );
  658.     printf( "    memos\n" );
  659.     printf( "         prompts for all actions.\n" );
  660.     printf( "  or\n" );
  661.     printf( "    memos action\n" );
  662.     printf( "         performs the action.\n" );
  663.     printf( "         More than one action may be specified.\n" );
  664.     printf( "         action is one of:\n" );
  665.     ShowActions();
  666. }
  667.  
  668. static void ShowActions( void )
  669. /*****************************/
  670. {
  671.     printf( "            Help    (display this text)\n" );
  672.     printf( "            Add     (add new memo here)\n" );
  673.     printf( "            DELete  (delete current memo)\n" );
  674.     printf( "            REPlace (replace current memo)\n" );
  675.     printf( "            SHow    (show the current memo again)\n" );
  676.     printf( "            Up      (move up one memo)\n" );
  677.     printf( "            Down    (move down one memo)\n" );
  678.     printf( "            TOP     (move to the top of the list\n" );
  679.     printf( "            TODay   (display today's memos)\n" );
  680.     printf( "            SAve    (write the memos to disk)\n" );
  681. }
  682.  
  683. static void Help( void )
  684. /**********************/
  685. {
  686.     printf( "Choose one of:\n" );
  687.     ShowActions();
  688.     printf( "            Quit\n" );
  689. }
  690.  
  691. static void DisplayTop( void )
  692. /****************************/
  693. {
  694.     printf( "Top of memos.\n" );
  695. }
  696.  
  697. static int WantToQuit( void )
  698. /***************************/
  699.  
  700. /* Check to see if the memos have been modified, but not saved.
  701.  * If so, query the user to make sure that he/she wants to quit
  702.  * without saving the memos.
  703.  */
  704. {
  705.     char buffer[MAXLEN];
  706.  
  707.     if( !MemosModified    ||  MemoHead == NULL ) {
  708.     return( TRUE );
  709.     }
  710.     printf( "\nThe memos have been modified but not saved.\n" );
  711.     printf( "Do you want to leave without saving them?\n" );
  712.     gets( buffer );
  713.     return( tolower( buffer[0] ) == 'y' );
  714. }
  715.  
  716. static void BadFormat( void )
  717. /***************************/
  718. {
  719.     printf( "Invalid format for memos file\n" );
  720.     abort();
  721. }
  722.  
  723. static void * MemoMAlloc( int size )
  724. /**********************************/
  725.  
  726. /* Allocate the specified size of memory, dealing with the
  727.  * case of a failure by displaying a message and quitting.
  728.  */
  729. {
  730.     register char * mem;
  731.  
  732.     mem = malloc( size );
  733.     if( mem == NULL ) {
  734.     printf( "Unable to allocate %d characters of memory\n", size );
  735.     abort();
  736.     }
  737.     return( mem );
  738. }
  739.  
  740. static void DisposeMemo( MEMO_EL * el )
  741. /*************************************/
  742.  
  743. /* Dispose of a memo, including its lines.
  744.  */
  745. {
  746.     TEXT_LINE * tline;
  747.     TEXT_LINE * next;
  748.  
  749.     tline = el->text;
  750.     while( tline != NULL ) {
  751.     next = tline->next;
  752.     free( tline );
  753.     tline = next;
  754.     }
  755.     free( el );
  756. }
  757.