home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of Shareware - Software Farm 2
/
wosw_2.zip
/
wosw_2
/
CPROG
/
VISIONS.ZIP
/
DEMOLIST.C
< prev
next >
Wrap
Text File
|
1990-05-18
|
29KB
|
738 lines
/*------------------------- DEMOLIST.C -------------------------*/
/* */
/* This file contains the VISIONS LIBRARY LIST DEMO software. */
/* */
/* Copyright 1990 Dan Vogel & David Bernazzani */
/* */
/* Date Initials Comments */
/* */
/* 03/07/90 DCV Initial Release 0.00 */
/*--------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <ctype.h>
#include "USERLIST.H"
#include "USERWIND.H"
#include "USERFORM.H"
#include "DEMOPROT.H"
static char *cnotice="VISIONS Copyright 1990 Dan Vogel & David Bernazzani";
/*--------------------------------------------------------------*/
/* Window Commands */
#define WIND_INIT 0 /* Create a window. */
#define WIND_UPDATE 1 /* Update the window displayed data. */
#define WIND_DEL 2 /* Close the window. */
/*-----------------------------------------------------------------*/
/* Run_List */
/* This is the list library demonstration code. */
/* */
/* The VISIONS list library demonstration code below is set up */
/* to allow the user to interactively create a displayed list */
/* of up to 10 string items. These items may be added, appended, */
/* deleted, searched, and sorted. Cursor highlights of the list */
/* items are controlled by the arrow keys, Ins, and Del. This */
/* allows the list functions to be invoked by the user with visual */
/* feedback. Implementing this mechanism on the screen requires */
/* the following visual 'areas': a command window, a list display */
/* window, a string entry form, a list length counter window, a */
/* response window and an introductory explanation window. */
/* Separate windows are set up for each of these functions, and */
/* then a keystroke driven execution loop is entered to allow the */
/* user interaction. */
/* More complex list examples are given in the comments of this */
/* code. */
/* WARNING - Most error checking has been removed to make the */
/* code easier to read. Users of VISIONS should check for error */
/* returns! */
/*-----------------------------------------------------------------*/
int Run_List()
{
WINDOW_HEAD *clear_window; /* Window to clear screen. */
WINDOW_HEAD *command_window; /* Commands available window. */
WINDOW_HEAD *list_window; /* List display. */
WINDOW_HEAD *length_window; /* List length display. */
WINDOW_HEAD *response_window; /* Error response screen. */
LIST_HEAD *demo_list; /* Demonstration list pointer. */
LIST_LINK *list_cursor; /* Screen list cursor pointer. */
LIST_LINK *tmp_cursor; /* Temporary cursor holder. */
unsigned char *item_pointer; /* List item pointer. */
int list_num; /* Number of items in the list. */
int key; /* User input holder. */
int status=0;
/*-------------------------------------------*/
/* Create a window just to clear the screen. */
/*-------------------------------------------*/
DefineWindow(&clear_window, 1, 1, 24, 80,
TEXT_BLACK, TEXT_WHITE, "", NOBORDER, FALSE, FALSE, TRUE);
DisplayWindow(clear_window);
/*-------------------------------------------*/
/* Tell the user what this routine is about. */
/*-------------------------------------------*/
List_Intro();
/*-------------------------------*/
/* Display the list of commands. */
/*-------------------------------*/
Command_Wind(&command_window, WIND_INIT);
/*---------------------------------------------*/
/* Initialize the list and the display window. */
/*---------------------------------------------*/
DefineList(&demo_list,*CompareString,*ReleaseString,*CopyString);
list_cursor = NULL;
Display_Wind(&list_window, WIND_INIT, demo_list, list_cursor);
/*------------------------------------*/
/* Initialize the list length window. */
/*------------------------------------*/
Length_Wind(&length_window, WIND_INIT, demo_list);
/*-----------------------------------------*/
/* Initialize the command response window. */
/*-----------------------------------------*/
Response_Wind(&response_window, WIND_INIT, "");
/*-------------------------------------------------------*/
/* This is the user command interpreter loop. The */
/* basic structure is similar to most interpreters, */
/* a token input followed by a switch or dispatch */
/* command that actually handles the different commands. */
/*-------------------------------------------------------*/
while (((char)(key = GetKey())) != ESC) /* Until user strikes ESC */
{
/*---------------------------------*/
/* Clear the last response window. */
/*---------------------------------*/
Response_Wind(&response_window, WIND_UPDATE, "");
/*--------------------------*/
/* Interpret the keystroke. */
/*--------------------------*/
switch (key)
{
case HOME: /* Move cursor to top of displayed list. */
ListTop(demo_list, &list_cursor);
break;
case END: /* Move cursor to bottom of displayed list. */
ListBottom(demo_list,&list_cursor);
break;
case UP: /* Move cursor up one position on list. */
ListLast(list_cursor,&tmp_cursor);
if (tmp_cursor != NULL)
list_cursor = tmp_cursor;
break;
case DOWN: /* Move cursor down one position on displayed list. */
ListNext(list_cursor,&tmp_cursor);
if (tmp_cursor != NULL)
list_cursor = tmp_cursor;
break;
case INS: /* Add a list item before the current cursor. */
if (CountList(demo_list) >= 10) /* Maximum list length is 10. */
Response_Wind(&response_window, WIND_UPDATE,
"List is already full.");
else
{
if (EnterListItem(&item_pointer) != -1)
{ /* If user enters an item */
status = AddToList(demo_list, list_cursor, item_pointer);
if (status != 0) /* Handle error here by deleting item! */
{
free(item_pointer); /* Release storage and tell user. */
Response_Wind(&response_window, WIND_UPDATE,
"Unable to insert new list item.");
status = 0;
}
else /* If all went well, set cursor to new item. */
FindInList(demo_list, item_pointer, &list_cursor);
}
}
break;
case DEL: /* Delete the current list item. */
if (GetListItem(list_cursor, &item_pointer) == 0)
{ /* If the cursor was good, set up new cursor, then delete. */
ListNext(list_cursor,&tmp_cursor);
if (tmp_cursor != NULL)
list_cursor = tmp_cursor;
else
ListLast(list_cursor,&list_cursor);
if (DeleteFromList(demo_list, item_pointer) != 0)
Response_Wind(&response_window, WIND_UPDATE,
"Unable to delete list item.");
}
else
Response_Wind(&response_window, WIND_UPDATE,
"Cursor does not point to valid list link.");
break;
case 'A': /* Append an item to the list. */
case 'a':
if (CountList(demo_list) >= 10) /* Check Max list length. */
Response_Wind(&response_window, WIND_UPDATE,
"List is already full.");
else
{
if (EnterListItem(&item_pointer) != -1)
{ /* If user enters an item */
status = AppendToList(demo_list, item_pointer);
if (status != 0) /* Handle error here by deleting item! */
{
free(item_pointer); /* Release storage and tell user. */
Response_Wind(&response_window, WIND_UPDATE,
"Unable to append new list item.");
status = 0;
}
}
ListBottom(demo_list,&list_cursor); /* Set cursor to new item. */
}
break;
case 'S': /* Sort the list and redisplay it. */
case 's':
SortList(demo_list,*CompareString);
ListTop(demo_list, &list_cursor); /* Set cursor to list top. */
break;
case 'J': /* Jump to the nth item in the list. */
case 'j':
if (GetListItemNumber(&list_num) >= 0) /* Get # to jump to. */
{
if (list_num >= 0)
{
if (ListNth(demo_list, list_num, &tmp_cursor) != 0)
Response_Wind(&response_window, WIND_UPDATE,
"Invalid list item number.");
else
list_cursor = tmp_cursor;
}
}
break;
}
/*-----------------------------*/
/* Update the display windows. */
/*-----------------------------*/
Display_Wind(&list_window,WIND_UPDATE,demo_list,list_cursor);
Length_Wind(&length_window, WIND_UPDATE, demo_list);
}
/*----------------------------------*/
/* Delete the list and the windows. */
/*----------------------------------*/
Command_Wind(&command_window, WIND_DEL);
Display_Wind(&list_window,WIND_DEL,demo_list,list_cursor);
Length_Wind(&length_window, WIND_DEL, demo_list);
Response_Wind(&response_window, WIND_DEL, "");
DeleteList(demo_list);
exit:
RemoveWindow(clear_window);
DeleteWindow(clear_window);
return(status);
}
/*--------------------------------------------------------*/
/* CopyString */
/* This is the simple list example version of the display */
/* item routine. Since the simple example keeps lists */
/* of character strings, this routine just copies the */
/* list character string over into an output buffer for */
/* display. No other formatting takes place. */
/* If the list were a structure, for example: */
/* struct employee_info */
/* { */
/* char first_name[10]; */
/* char last_name[10]; */
/* char ss_number[12]; */
/* } */
/* then this routine might look more like: */
/* int Format_Employee(instr,outstr) */
/* unsigned char *instr, *outstr; */
/* { */
/* struct employee_info *employee; */
/* */
/* employee = (struct employee_info *) instr; */
/* strcpy(outstr,employee->first_name); */
/* strcat(outstr," "); */
/* strcat(outstr,employee->last_name); */
/* strcat(outstr," "); */
/* strcat(outstr,employee->ss_number); */
/* return(0); */
/* } */
/* */
/* Note that you are not tied to a single display format,*/
/* this is just the routine used by DisplayList. You may */
/* create different display routines for uses at different*/
/* times, and call them directly instead of through the */
/* library. */
/*--------------------------------------------------------*/
int CopyString(instr, outstr)
unsigned char *instr, *outstr;
{
strcpy(outstr,instr);
return(0);
}
/*------------------------------------------------------------*/
/* CompareString */
/* This is the simple list example version of the item */
/* compare routine. Again, as the items here are simple */
/* character strings, we can use strcmp to do the comparison. */
/* A more complex case such as the example given in */
/* CopyString would require comparisons of all the items */
/* within the structure. */
/*------------------------------------------------------------*/
int CompareString(instr, outstr)
unsigned char *instr, *outstr;
{
return(strcmp(instr,outstr));
}
/*-------------------------------------------------------*/
/* ReleaseString */
/* This is the simple list example version of the item */
/* delete routine. Since we are using character strings */
/* allocated from the heap, we just 'free' them. If we */
/* were using predefined variables, like X="123", we */
/* would not need this routine at all! */
/* The CopyString example of the use of a structure */
/* would not change this routine. */
/*-------------------------------------------------------*/
int ReleaseString(delstr)
unsigned char *delstr;
{
return(free(delstr));
}
/*---------------------------------------------------*/
/* */
/* The remainder of the file consists primarily of */
/* screen handling routines. While these may be of */
/* interest as examples of forms and windows library */
/* use, they are not directly related to the list */
/* library demonstration. */
/* */
/*---------------------------------------------------*/
/*-----------------------------------------------*/
/* List_Intro */
/* Introduce the user to this demonstration, */
/* explaining the purpose and what is happening. */
/*-----------------------------------------------*/
int List_Intro()
{
WINDOW_HEAD *intro_window;
DefineWindow(&intro_window, 1, 1, 24, 80,
TEXT_BLUE, TEXT_WHITE, "VISIONS List Demonstration Introduction",
SINGLEBORDER, FALSE, FALSE, TRUE);
DisplayWindow(intro_window);
WindMesg(9,7,
" The VISIONS list library demonstration is intended to introduce ");
WindMesg(10,7,
" the user to the list library concepts and functions through the ");
WindMesg(11,7,
" use of a simple interactive example. This example takes the form ");
WindMesg(12,7,
" of an interactive manipulation of a list of up to ten string ");
WindMesg(13,7,
" elements. Each action taken by the user causes a list manipulation ");
WindMesg(14,7,
" to be performed by one or more VISIONS list library routines. This ");
WindMesg(15,7,
" is displayed in the list display window. The source code used to ");
WindMesg(16,7,
" create this demonstration is supplied with the executable. More ");
WindMesg(17,7,
" complex examples of list management are given in comments in the ");
WindMesg(18,7," source code.");
WindMesg(24,28,"Hit any key to continue.");
GetKey(); /* Force a key strike by the user. */
RemoveWindow(intro_window); /* And destroy the window. */
DeleteWindow(intro_window);
return(0);
}
/*-------------------------------------------*/
/* Command_Wind */
/* Display the command set that the user has */
/* available for the interactive list demo. */
/* Use the passed window pointer for display.*/
/*-------------------------------------------*/
/* Command Window Parameters */
#define COMMAND_ROW 3
#define COMMAND_COL 36
#define COMMAND_WIDTH 43
#define COMMAND_HEIGHT 13
#define COMMAND_BKCOL TEXT_RED
#define COMMAND_TXTCOL TEXT_BWHITE
#define COMMAND_TITLE "List Editing Commands"
#define COMMAND_BORDER SINGLEBORDER
int Command_Wind(command_window, cmd)
WINDOW_HEAD **command_window; /* The window pointer to use. */
int cmd; /* The window command (INIT, DELete. */
{
switch(cmd)
{
case WIND_INIT:
DefineWindow(command_window, COMMAND_ROW, COMMAND_COL,
COMMAND_HEIGHT, COMMAND_WIDTH,
COMMAND_BKCOL, COMMAND_TXTCOL, COMMAND_TITLE,
COMMAND_BORDER, TRUE, TRUE, TRUE);
DisplayWindow(*command_window);
WindMesg(4,3,"HOME - Move cursor to list top");
WindMesg(5,3,"END - Move cursor to list bottom");
WindMesg(6,3,"UP - Move cursor up one item");
WindMesg(7,3,"DOWN - Move Cursor down one item");
WindMesg(8,3,"INS - Insert new item into list");
WindMesg(9,3,"DEL - Delete current item from list");
WindMesg(10,3,"A - Append new item to list");
WindMesg(11,3,"S - Sort list and redisplay");
WindMesg(12,3,"J - Move cursor to numbered list item");
break;
case WIND_DEL:
RemoveWindow(*command_window);
DeleteWindow(*command_window);
break;
}
return(0);
}
/*--------------------------------------------------------------*/
/* Display_Wind */
/* The following window is used to display the list contents. */
/* This could normally be done much more simply by calling the */
/* DisplayList routine. This would only display the list */
/* until a key was struck however. Therefore the routine */
/* below was written to leave the list display up on the screen */
/* during the entire demonstration of the list library. */
/*--------------------------------------------------------------*/
/* List Display Window Parameters */
#define DISPLAY_ROW 5
#define DISPLAY_COL 3
#define DISPLAY_WIDTH 25
#define DISPLAY_HEIGHT 14
#define DISPLAY_BKCOL TEXT_BLUE
#define DISPLAY_TXTCOL TEXT_WHITE
#define DISPLAY_HIBKCOL TEXT_BLUE
#define DISPLAY_HITXTCOL TEXT_BWHITE
#define DISPLAY_TITLE "List Display"
#define DISPLAY_BORDER DOUBLEBORDER
int Display_Wind(list_window, cmd, demo_list, list_cursor)
WINDOW_HEAD **list_window; /* The window pointer to use. */
LIST_HEAD *demo_list; /* The list to display. */
LIST_LINK *list_cursor; /* The list item to highlight. */
int cmd; /* The window display command. */
{
LIST_LINK *list_travel;
char buffer[81];
int disp_row=0;
switch(cmd)
{
case WIND_INIT: /* Initially define and display the window. */
DefineWindow(list_window, DISPLAY_ROW, DISPLAY_COL,
DISPLAY_HEIGHT, DISPLAY_WIDTH,
DISPLAY_BKCOL, DISPLAY_TXTCOL, DISPLAY_TITLE,
DISPLAY_BORDER, TRUE, TRUE, TRUE);
DisplayWindow(*list_window);
case WIND_UPDATE: /* Redisplay the window, with cursor color inverted.*/
SetWindowPtr(*list_window);
ListTop(demo_list, &list_travel);
while (disp_row++ < 10) /* Display the list of up to 10 items. */
{
if (list_travel == NULL)
strcpy(buffer," ");
else
DisplayListItem(demo_list, list_travel, buffer);
if (list_travel == list_cursor) /* Highlighted item? */
{
SetBkColor(DISPLAY_HIBKCOL);
SetTextColor(DISPLAY_HITXTCOL);
}
while (strlen(buffer) < DISPLAY_WIDTH - 4)
strcat(buffer," ");
WindMesg(disp_row + 3, 3, buffer);
if (list_travel == list_cursor) /* Reset colors after highlight. */
{
SetBkColor(DISPLAY_BKCOL);
SetTextColor(DISPLAY_TXTCOL);
}
ListNext(list_travel,&list_travel);
}
break;
case WIND_DEL: /* Finally shut down the window. */
RemoveWindow(*list_window);
DeleteWindow(*list_window);
break;
}
return(0);
}
/*---------------------------------------------*/
/* Length_Wind */
/* This creates a small window used to display */
/* the number of items in the current list. */
/*---------------------------------------------*/
/* List Length Window Parameters */
#define LENGTH_ROW 3
#define LENGTH_COL 3
#define LENGTH_WIDTH 25
#define LENGTH_HEIGHT 2
#define LENGTH_BKCOL TEXT_GREEN
#define LENGTH_TXTCOL TEXT_BWHITE
#define LENGTH_TITLE "Number of Items in List"
#define LENGTH_BORDER NOBORDER
int Length_Wind(length_window, cmd, demo_list)
WINDOW_HEAD **length_window; /* The window pointer to use. */
LIST_HEAD *demo_list; /* The list to count. */
int cmd; /* The window command. */
{
int length;
char buffer[20];
switch(cmd)
{
case WIND_INIT: /* Define and display the window. */
DefineWindow(length_window, LENGTH_ROW, LENGTH_COL,
LENGTH_HEIGHT, LENGTH_WIDTH,
LENGTH_BKCOL, LENGTH_TXTCOL, LENGTH_TITLE,
LENGTH_BORDER, TRUE, TRUE, TRUE);
DisplayWindow(*length_window);
case WIND_UPDATE: /* Display the list length in the window. */
if ((length = CountList(demo_list)) <= 10)
{
sprintf(buffer,"%2.2d",length);
WindMesgPtr(*length_window,2,12,buffer);
}
break;
case WIND_DEL: /* Destroy the window. */
RemoveWindow(*length_window);
DeleteWindow(*length_window);
break;
}
return(0);
}
/*------------------------------------------------------*/
/* Response_Wind */
/* The window created and maintained by this routine is */
/* used for interaction with the user. It's primary */
/* function is to display single line error messages */
/* related to an illegal command made by the user. */
/*------------------------------------------------------*/
/* Command Response Window Parameters */
#define RESPONSE_ROW 25
#define RESPONSE_COL 1
#define RESPONSE_WIDTH 80
#define RESPONSE_HEIGHT 1
#define RESPONSE_BKCOL TEXT_WHITE
#define RESPONSE_TXTCOL TEXT_RED
#define RESPONSE_TITLE ""
#define RESPONSE_BORDER NOBORDER
int Response_Wind(response_window, cmd, msg)
WINDOW_HEAD **response_window; /* The window pointer to use. */
int cmd; /* The window command, INIT, DEL, UPDATE. */
char *msg; /* Message to display in the window. */
{
char buffer[81];
switch(cmd)
{
case WIND_INIT: /* Define and display the window. */
DefineWindow(response_window, RESPONSE_ROW, RESPONSE_COL,
RESPONSE_HEIGHT, RESPONSE_WIDTH,
RESPONSE_BKCOL, RESPONSE_TXTCOL, RESPONSE_TITLE,
RESPONSE_BORDER, TRUE, TRUE, TRUE);
DisplayWindow(*response_window);
break;
case WIND_UPDATE: /* Display the message, or clear the message line. */
if ((msg == NULL) || (strlen(msg) == 0))
strcpy(buffer," ");
else
{
strncpy(buffer,msg,RESPONSE_WIDTH-1);
buffer[RESPONSE_WIDTH-2] = (char)NULL;
}
while (strlen(buffer) < RESPONSE_WIDTH-2)
strcat(buffer," ");
WindMesgPtr(*response_window,1,2,buffer);
break;
case WIND_DEL: /* Destroy the window. */
RemoveWindow(*response_window);
DeleteWindow(*response_window);
break;
}
return(0);
}
/*--------------------------------------------------*/
/* EnterListItem */
/* This routine generates a form used to allow the */
/* operator to enter a text string that will become */
/* a list item. This is a good short example of */
/* a form being used. */
/*--------------------------------------------------*/
int EnterListItem(item_pointer)
unsigned char **item_pointer; /* Returned pointer to string entered. */
{
FORM_HEAD *new_form;
FORM_FIELD *field_ptr;
int status=0;
/*---------------------------------------*/
/* Allocate memory for the string entry. */
/*---------------------------------------*/
*item_pointer = (unsigned char *)malloc(26*sizeof(char));
strcpy(*item_pointer,"");
/*-------------------------------*/
/* Create the string entry form. */
/*-------------------------------*/
DefineForm(&new_form,12,15,6,25,SINGLEBORDER,
TEXT_BROWN,TEXT_BWHITE,"LIST ITEM ENTRY");
AddToForm(new_form, NULL, &field_ptr);
AddToPrompt(field_ptr, 4, 2, 6, TEXT_BROWN,TEXT_BWHITE,
TEXT_BWHITE,TEXT_BROWN,"Item: ");
AddToText(field_ptr, 5, 2, 21, TEXT_BLACK,TEXT_WHITE,
TEXT_WHITE,TEXT_BLACK,*item_pointer);
/*-------------------------------------*/
/* Execute the form to get user input. */
/*-------------------------------------*/
status = FormEntry(new_form);
/*------------------------------------------------------*/
/* Release the memory if the user aborted string entry. */
/*------------------------------------------------------*/
if (status != 0)
free(*item_pointer);
/*------------------*/
/* Delete the form. */
/*------------------*/
DeleteForm(new_form);
/*---------------------------*/
/* Tell the caller if form */
/* was aborted or completed. */
/*---------------------------*/
return(status);
}
/*--------------------------------------------------*/
/* GetListItemNumber */
/* This routine generates a form used to allow the */
/* operator to enter a number of the list item to */
/* be selected. This is a good short example of */
/* a form being used. */
/*--------------------------------------------------*/
int GetListItemNumber(list_num)
int *list_num; /* Pointer to integer to return number in. */
{
FORM_HEAD *new_form;
FORM_FIELD *field_ptr;
char string_ret[3]; /* Temporary string for number entry. */
int status=0;
strcpy(string_ret,"");
*list_num = 0;
/*------------------------*/
/* Create the entry form. */
/*------------------------*/
DefineForm(&new_form,12,15,5,25,SINGLEBORDER,
TEXT_BROWN,TEXT_BWHITE,"LIST ITEM NUMBER");
AddToForm(new_form, *IntOnly, &field_ptr);
AddToPrompt(field_ptr, 4, 2, 8, TEXT_BROWN,TEXT_BWHITE,
TEXT_BWHITE,TEXT_BROWN,"Number: ");
AddToText(field_ptr, 4, 11, 2, TEXT_BLACK,TEXT_WHITE,
TEXT_WHITE,TEXT_BLACK,string_ret);
/*-----------------------*/
/* Now execute the form. */
/*-----------------------*/
status = FormEntry(new_form);
/*-+--------------------------*/
/* Release the form's memory. */
/*----------------------------*/
DeleteForm(new_form);
/*--------------------------------------*/
/* Convert the received string into */
/* an integer, if form was not aborted. */
/*--------------------------------------*/
if (status != -1)
{
if (isdigit(string_ret[0]) != 0)
*list_num = (int)(string_ret[0] - '0');
if (isdigit(string_ret[1]) != 0)
*list_num = (*list_num * 10) + (int)(string_ret[1] - '0');
*list_num = *list_num - 1;
if (*list_num < 0)
*list_num = 0;
if (*list_num > 9)
*list_num = 9;
}
/*---------------------------*/
/* Tell the caller if form */
/* was aborted or completed. */
/*---------------------------*/
return(status);
}