💾 Archived View for gemini.spam.works › mirrors › textfiles › programming › berens.lst captured on 2023-01-29 at 11:23:43.
View Raw
More Information
⬅️ Previous capture (2020-10-31)
-=-=-=-=-=-=-
C PROCEDURE TABLES
by Tim Berens
[LISTING ONE]
/****************************************************************************
Name : prompter.c
Description : A routine for prompting a user for a series of answers.
- ***************************************************************************/
#include<stdio.h>
#include"prompter.h"
struct group_stack group_stack[GROUP_STACK_SIZE];
prompter(pc)
struct prcontrol * pc;
{
int errstat;
pc->current_question = 0;
pc->group_stack_ptr = 0;
for(;;){
pc->errstat = 0;
display_current_question(pc);
gets(pc->response);
if(*pc->response == 0){
continue;
}
if(!(pc->errstat =
(*pc->current_group[pc->current_question].validate)(pc))){
if(pc->errstat =
(*pc->current_group[pc->current_question].doit)(pc)){
if(pc->errstat == EXIT_NOW){
return(0);
}
}
}
if(pc->current_group[pc->current_question].response != NULL){
strcpy(pc->current_group[pc->current_question].response,
pc->response);
}
(*pc->current_group[pc->current_question].set)(pc);
if(pc->current_group[pc->current_question].text == NULL){
return(0);
}
if(pc->errstat){
handle_error(pc->errstat,pc->errormess);
}
}
}
display_current_question(pc)
struct prcontrol * pc;
{
printf("\n%s\n",pc->current_group[pc->current_question].text);
printf("--->");
}
handle_error(errstat,errormess)
int errstat;
struct errormess * errormess;
{
int i;
int emess_offset = -1;
char * message,messagebuff[100];
for(i = 0 ; errormess[i].errstat != -1 ; ++i){
if(errormess[i].errstat == errstat){
emess_offset = i;
break;
}
}
message = messagebuff;
if(emess_offset != -1){
strcpy(message,errormess[emess_offset].message);
if(errormess[emess_offset].build){
(*errormess[emess_offset].build)(message);
}
}
else{
sprintf(message,"Error %d.",errstat);
}
puts("\n");
puts(message);
return(0);
}
/***************************************
Flow control routines
- **************************************/
no_op()
{
return(0);
}
next_question(pc)
struct prcontrol * pc;
{
++pc->current_question;
return(0);
}
pop_group(pc)
struct prcontrol * pc;
{
--pc->group_stack_ptr;
pc->current_group = group_stack[pc->group_stack_ptr].group;
pc->current_question = group_stack[pc->group_stack_ptr].current_question;
return(0);
}
push_current_group(pc)
struct prcontrol * pc;
{
group_stack[pc->group_stack_ptr].group = pc->current_group;
group_stack[pc->group_stack_ptr].current_question = pc->current_question;
++pc->group_stack_ptr;
return(0);
}
start_group(newgroup,pc)
struct question * newgroup;
struct prcontrol * pc;
{
push_current_group(pc);
pc->current_group = newgroup;
pc->current_question = 0;
return(0);
}
restart_group(pc)
struct prcontrol * pc;
{
pc->current_question = 0;
return(0);
}
end_group(pc)
struct prcontrol * pc;
{
pop_group(pc);
++pc->current_question;
return(0);
}
checkerror_end_group(pc)
struct prcontrol * pc;
{
if(pc->errstat){
return(0);
}
end_group(pc);
return(0);
}
checkerror_next_question(pc)
struct prcontrol * pc;
{
if(pc->errstat){
return(0);
}
next_question(pc);
return(0);
}
[LISTING TWO]
/****************************************************************************
Name : prompter.h
Description : Declarations for prompter
- ***************************************************************************/
struct prcontrol {
int current_question;
struct question * current_group;
int group_stack_ptr;
char response[121];
int errstat;
struct errormess * errormess;
};
struct question {
char * text;
char * response;
int (*validate)();
int (*doit)();
int (*set)();
};
struct group_stack {
struct question * group;
int current_question;
};
/************************
errormess data structure
struct errormess {
int errstat;
char * message;
int (*build)();
};
#define GROUP_STACK_SIZE 50
#define NO_ERROR 0
#define EXIT_NOW 2001
int pop_group(),end_group(),no_op(),next_question();
int checkerror_end_group(),checkerror_next_question();
[LISTING THREE]
/****************************************************************************
Name : prsample.c
Description : A sample that uses the prompter() routine
- ***************************************************************************/
#include<stdio.h>
#include"prompter.h"
#include<ctype.h>
/**************************
The report parameter variables
- **************************/
char report_destination[2];
char dest_filename[30];
char single_or_range[2];
char start_account[20],end_account[20];
int account_number;
char display_parmname[50];
char include_overshort[2];
/*********************
Error Values
#define ENTER_S_OR_R 1
#define ENTER_Y_OR_N 2
#define START_ACCOUNT_LARGER 3
#define BAD_PARM_NAME 4
#define BAD_ACCOUNT_NUMBER 5
#define ENTER_P_S_OR_D 6
#define FILE_EXISTS 7
/************************
Report to printer, screen or disk routines
int filename_val();
struct question report_filename[] = {
{ "What is the name of the disk file?",
dest_filename,filename_val,no_op,checkerror_end_group},
{ NULL,NULL,NULL,NULL,NULL }
};
filename_val(pc)
struct prcontrol * pc;
{
FILE * fp,*fopen();
/* you should put a routine to validate that the response
entered is a legal file name here */
if(fp = fopen(pc->response,"r")){
fclose(fp);
return(FILE_EXISTS);
}
return(0);
}
reportdest_val(pc)
struct prcontrol * pc;
{
char * strchr();
if((!strchr("PpSsDd",pc->response[0])) || (strlen(pc->response) != 1)){
return(ENTER_P_S_OR_D);
}
return(0);
}
reportdest_set(pc)
struct prcontrol * pc;
{
char destination;
destination = islower(*pc->response) ? *pc->response-32 : *pc->response;
switch(destination){
case 'P' :
case 'S' : next_question(pc);
break;
case 'D' : start_group(report_filename,pc);
break;
}
return(0);
}
/***************************
Account routines
- **************************/
int account_val(),end_account_set(),end_account_val();
struct question account_range[] = {
{"Enter the starting account.",
start_account,account_val,no_op,checkerror_next_question},
{"Enter the ending account.",
end_account,end_account_val,no_op,end_account_set},
{ NULL,NULL,NULL,NULL,NULL }
};
int save_account_doit(),account_set();
struct question account[] = {
{"Enter the account.",
start_account,account_val,save_account_doit,checkerror_end_group},
{NULL,NULL,NULL,NULL,NULL}};
account_or_range_val(pc)
struct prcontrol * pc;
{
char * strchr();
if((!strchr("SsRr",pc->response[0])) || (strlen(pc->response) > 1)){
return(ENTER_S_OR_R);
}
return(0);
}
account_or_range_set(pc)
struct prcontrol * pc;
{
char account_or_range;
account_or_range = islower(*pc->response) ? *pc->response-32 :
*pc->response;
if(pc->errstat){
return(0);
}
if(account_or_range == 'S'){
start_group(account,pc);
}
if(account_or_range == 'R'){
start_group(account_range,pc);
}
return(0);
}
save_account_doit(pc)
struct prcontrol * pc;
{
account_number = atoi(pc->response);
return(0);
}
account_val(pc)
struct prcontrol * pc;
{
if((atoi(pc->response) < 100) || (atoi(pc->response) > 1000)){
return(BAD_ACCOUNT_NUMBER);
}
return(0);
}
end_account_val(pc)
struct prcontrol * pc;
{
int errstat;
if(errstat = account_val(pc)){
return(errstat);
}
if(atoi(start_account) >= atoi(pc->response)){
return(START_ACCOUNT_LARGER);
}
return(0);
}
end_account_set(pc)
struct prcontrol * pc;
{
switch(pc->errstat){
case NO_ERROR : end_group(pc);
break;
case START_ACCOUNT_LARGER : restart_group(pc);
break;
case BAD_ACCOUNT_NUMBER : break;
}
return(0);
}
/***************************
Get display parameters routines
- ***************************/
char * legal_parmnames[] = { /* In a "real" system, this table */
"default", /* would probably be stored in a file */
"daily", /* and parmname_val would check to see */
"weekly", /* if the name entered is in this file. */
"yearly",
NULL
};
parmname_val(pc)
struct prcontrol * pc;
{
int i;
for(i = 0 ; legal_parmnames[i] != NULL ; ++i){
if(strcmp(pc->response,legal_parmnames[i]) == 0){
return(0);
}
}
return(BAD_PARM_NAME);
}
bld_bad_parmname(message)
char * message;
{
sprintf(message + strlen(message)," %s, %s, %s, or %s.",
legal_parmnames[0],legal_parmnames[1],legal_parmnames[2],
legal_parmnames[3]);
return(0);
}
/**************************
yesno validation
- **************************/
yesno_val(pc)
struct prcontrol * pc;
{
char * strchr();
if((!strchr("YyNn",pc->response[0])) || (strlen(pc->response) != 1)){
return(ENTER_Y_OR_N);
}
return(0);
}
/**************************************
Main question array procedure table
- **************************************/
struct question account_parms[] = {
{"Do you want this report for a single account or a range of accounts? (S or R)",
single_or_range,account_or_range_val,no_op,account_or_range_set },
{"Enter the name of the display parameter record.",
display_parmname,parmname_val,no_op,checkerror_next_question},
{"Do you want to include the Over/Short Report? (Y/N)",
NULL,yesno_val,no_op,checkerror_next_question},
{"Do you want this report on the printer, screen, or saved to disk?(P,S or D)",
report_destination,reportdest_val,no_op,reportdest_set},
{ NULL,NULL,NULL,NULL,NULL }
};
struct errormess account_errormess[] = {
{ ENTER_S_OR_R,"Please enter S or R.",NULL },
{ ENTER_Y_OR_N,"Please enter Y or N.",NULL },
{ START_ACCOUNT_LARGER,"The starting account must be smaller than the ending account.",NULL },
{ BAD_ACCOUNT_NUMBER,"The account number must be between 100 and 1000",NULL },
{ BAD_PARM_NAME,"Choose one of the following :",bld_bad_parmname },
{ ENTER_P_S_OR_D,"Please enter P, S or D",NULL },
{ FILE_EXISTS,"That file already exists.",NULL },
{ -1,NULL,NULL }
};
main(argc,argv)
int argc;
char * argv[];
{
int errstat;
struct prcontrol prcontrol;
prcontrol.current_group = account_parms;
prcontrol.errormess = account_errormess;
if(errstat = prompter(&prcontrol)){
handle_error(errstat,account_errormess);
}
/* Print the report with the gathered parameters */
}
[EXAMPLE 1]
loop{
display current_question->text
get response from user
execute current_question->validate
if(no error on validate){
execute current_question->doit
}
copy response to current_question->response
execute current_question->set
if(error from validate){
call error handler
}
}