📄 memos.gml
字号:
.code begin
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include "memos.h"
/* This program implements a simple memo facility.
* Memos may be added to a memo file, displayed
* on the screen, and deleted.
*
* Modified by reason
* ======== == ======
* 87/10/02 Steve McDowell Initial implementation.
* 88/09/20 Steve McDowell Fixed up some style issues,
* introduced use of TRUE and
* FALSE.
*/
/* Define some constants to make the code more readable.
*/
#define TRUE 1
#define FALSE 0
#define NULLCHAR '\0'
.code break
static const char FileName[] = { "memos.db" };
static const char TempName[] = { "tempmemo.db" };
static MEMO_EL * MemoHead = NULL;
static int MemosModified = FALSE;
static int QuitFlag = TRUE;
.code break
typedef enum {
INVALID,
HELP,
ADD,
DELETE,
REPLACE,
SHOW,
UP,
DOWN,
TOP,
TODAY,
SAVE,
QUIT
} ACTION;
.code break
/* This table maps action keywords onto the "actions" defined
* above. The table also defines short forms for the keywords.
*/
typedef struct {
ACTION act;
char * keyword;
} ACTION_MAP;
.code break
static ACTION_MAP KeywordMap[] = {
HELP, "help",
HELP, "h",
ADD, "add",
ADD, "a",
DELETE, "delete",
DELETE, "del",
REPLACE, "replace",
REPLACE, "rep",
SHOW, "show",
SHOW, "sh",
UP, "up",
UP, "u",
DOWN, "down",
DOWN, "d",
DOWN, "",
TOP, "top",
TODAY, "today",
TODAY, "tod",
SAVE, "save",
SAVE, "sa",
QUIT, "quit",
QUIT, "q",
INVALID, "" };
.code break
/* Maximum buffer length (maximum length of line of memo).
*/
#define MAXLEN 80
/* Function prototypes.
*/
static TEXT_LINE * AddLine();
static MEMO_EL * AddMemo();
static MEMO_EL * DeleteMemo();
static MEMO_EL * DoActions();
static MEMO_EL * DoDownAction();
static MEMO_EL * DoUpAction();
static MEMO_EL * EnterAMemo();
static ACTION GetAction();
static void * MemoMAlloc();
static ACTION PromptAction();
static ACTION ReadAction();
static MEMO_EL * ReadAMemo();
static MEMO_EL * ShowTodaysMemos();
.code break
extern int main( int argc, char * argv[] )
/****************************************/
{
int index;
MEMO_EL * el;
printf( "Memo facility\n" );
.code break
/* Check for a single argument that is a question mark,
* If found, then display the usage notes.
*/
if( argc == 2 && strcmp( argv[1], "?" ) == 0 ) {
Usage();
exit( 0 );
}
ReadMemos();
MemosModified = FALSE;
QuitFlag = FALSE;
.code break
/* Use the command line parameters, if any, as the first
* actions to be performed on the memos.
*/
el = NULL;
for( index = 1; index < argc; ++index ) {
el = DoActions( el, GetAction( argv[index] ) );
if( QuitFlag ) {
return( FALSE );
}
}
HandleMemoActions( el );
return( FALSE );
}
.code break
static void ReadMemos( void )
/***************************/
/* Read the memos file, building the structure to contain it.
*/
{
FILE * fid;
MEMO_EL * new_el;
MEMO_EL * prev_el;
int mcount;
fid = fopen( FileName, "r" );
.code break
if( fid == NULL ) {
printf( "Memos file not found."
" Starting with no memos.\n" );
return;
}
.code break
/* Loop reading entire memos.
*/
prev_el = NULL;
for( mcount = 0;; mcount++ ) {
new_el = ReadAMemo( fid );
if( new_el == NULL ) {
printf( "%d memo(s) found.\n", mcount );
fclose( fid );
return;
}
.code break
if( prev_el == NULL ) {
MemoHead = new_el;
new_el->prev = NULL;
} else {
prev_el->next = new_el;
new_el->prev = prev_el;
}
.code break
new_el->next = NULL;
prev_el = new_el;
}
}
.code break
static int ReadLine( char buffer[], int len, FILE * fid )
/*******************************************************/
/* Read a line from the memos file. Handle any I/O errors and
* EOF. Return the length read, not counting the newline on
* the end.
*/
{
if( fgets( buffer, len, fid ) == NULL ) {
if( feof( fid ) ) {
return( EOF );
}
perror( "Error reading memos file" );
abort();
}
.code break
return( strlen( buffer ) - 1 );
}
.code break
static MEMO_EL * ReadAMemo( FILE * fid )
/**************************************/
/* Read one memo, creating the memo structure and filling it
* in. Return a pointer to the memo (NULL if none read).
*/
{
MEMO_EL * el;
int len;
TEXT_LINE * line;
char buffer[MAXLEN];
len = ReadLine( buffer, MAXLEN, fid );
if( len == EOF ) {
return( NULL );
}
.code break
/* First line must be of the form "Date:" or "Date:YY/MM/DD":
*/
if( (len != 5 && len != 13)
|| strncmp( buffer, "Date:", 5 ) != 0 ) {
BadFormat();
}
.code break
buffer[len] = NULLCHAR;
el = MemoMAlloc( sizeof( MEMO_EL ) );
el->text = NULL;
strcpy( el->date, buffer + 5 );
line = NULL;
.code break
for( ;; ) {
len = ReadLine( buffer, MAXLEN, fid );
if( len == EOF ) {
BadFormat();
}
.code break
buffer[len] = NULLCHAR;
if( strcmp( buffer, "====" ) == 0 ) {
return( el );
}
line = AddLine( buffer, el, line );
}
}
.code break
static TEXT_LINE * AddLine( char buffer[],
MEMO_EL * el,
TEXT_LINE * prevline )
/************************************************/
/* Add a line of text to the memo, taking care of all the
* details of modifying the structure.
*/
{
TEXT_LINE * line;
line = MemoMAlloc( sizeof( TEXT_LINE ) + strlen( buffer ) );
strcpy( line->text, buffer );
line->next = NULL;
.code break
if( prevline == NULL ) {
el->text = line;
} else {
prevline->next = line;
}
return( line );
}
.code break
static ACTION PromptAction( void )
/********************************/
/* The user didn't specify an action on the command line,
* so prompt for it.
*/
{
ACTION act;
for( ;; ) {
printf( "\nEnter an action:\n" );
act = ReadAction();
.code break
if( act != INVALID ) {
return( act );
}
printf( "\nThat selection was not valid.\n" );
Help();
}
}
.code break
static ACTION ReadAction( void )
/******************************/
/* Read an action from the terminal.
* Return the action code.
*/
{
char buffer[80];
if( gets( buffer ) == NULL ) {
perror( "Error reading action" );
abort();
}
.code break
return( GetAction( buffer ) );
}
.code break
static ACTION GetAction( char buffer[] )
/**************************************/
/* Given the string in the buffer, return the action that
* corresponds to it.
* The string in the buffer is first zapped into lower case
* so that mixed-case entries are recognized.
*/
{
ACTION_MAP * actmap;
char * bufptr;
for( bufptr = buffer; *bufptr != NULLCHAR; ++bufptr ) {
*bufptr = tolower( *bufptr );
}
.code break
for( actmap = KeywordMap; actmap->act != INVALID; ++actmap ) {
if( strcmp( buffer, actmap->keyword ) == 0 ) break;
}
return( actmap->act );
}
.code break
static void HandleMemoActions( MEMO_EL * el )
/*******************************************/
/* Handle all the actions entered from the keyboard.
*/
{
for( ;; ) {
el = DoActions( el, PromptAction() );
if( QuitFlag ) break;
}
}
.code break
static MEMO_EL * DoActions( MEMO_EL * el, ACTION act )
/****************************************************/
/* Perform one action on the memos.
*/
{
MEMO_EL * new_el;
MEMO_EL * prev_el;
switch( act ) {
case HELP:
Help();
break;
.code break
case ADD:
new_el = AddMemo( el );
if( new_el != NULL ) {
el = new_el;
MemosModified = TRUE;
}
break;
.code break
case DELETE:
el = DeleteMemo( el );
MemosModified = TRUE;
break;
.code break
case REPLACE:
prev_el = el;
new_el = AddMemo( el );
if( new_el != NULL ) {
DeleteMemo( prev_el );
MemosModified = TRUE;
}
break;
.code break
case SHOW:
DisplayMemo( el );
break;
.code break
case UP:
el = DoUpAction( el );
break;
.code break
case DOWN:
el = DoDownAction( el );
break;
.code break
case TOP:
el = NULL;
break;
.code break
case TODAY:
el = ShowTodaysMemos();
break;
.code break
case SAVE:
if( SaveMemos() ) {
MemosModified = FALSE;
}
break;
.code break
case QUIT:
if( WantToQuit() ) {
QuitFlag = TRUE;
el = NULL;
}
}
.code break
return( el );
}
.code break
static MEMO_EL * AddMemo( MEMO_EL * el )
/**************************************/
/* Add a memo following the current one.
*/
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -