home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / ddjmag / ddj8908.zip / BERENS.LST < prev    next >
File List  |  1989-07-06  |  13KB  |  519 lines

  1. C PROCEDURE TABLES
  2. by Tim Berens
  3.  
  4. [LISTING ONE]
  5.  
  6.  
  7. /****************************************************************************
  8.     Name : prompter.c
  9.  
  10.     Description : A routine for prompting a user for a series of answers.
  11. ****************************************************************************/
  12. #include<stdio.h>
  13. #include"prompter.h"
  14.  
  15. struct group_stack group_stack[GROUP_STACK_SIZE];
  16.  
  17. prompter(pc)
  18.     struct prcontrol * pc;
  19. {
  20.     int errstat;
  21.  
  22.     pc->current_question = 0;
  23.     pc->group_stack_ptr = 0;
  24.  
  25.     for(;;){
  26.         pc->errstat = 0;
  27.  
  28.         display_current_question(pc);
  29.  
  30.         gets(pc->response);
  31.  
  32.         if(*pc->response == 0){
  33.             continue;
  34.         }
  35.  
  36.         if(!(pc->errstat = 
  37.           (*pc->current_group[pc->current_question].validate)(pc))){
  38.  
  39.             if(pc->errstat = 
  40.               (*pc->current_group[pc->current_question].doit)(pc)){
  41.                  if(pc->errstat == EXIT_NOW){
  42.                     return(0);
  43.                  }
  44.             }
  45.         }
  46.  
  47.         if(pc->current_group[pc->current_question].response != NULL){
  48.             strcpy(pc->current_group[pc->current_question].response,
  49.                    pc->response);
  50.         }
  51.  
  52.         (*pc->current_group[pc->current_question].set)(pc);
  53.  
  54.         if(pc->current_group[pc->current_question].text == NULL){
  55.             return(0);
  56.         }
  57.  
  58.         if(pc->errstat){
  59.             handle_error(pc->errstat,pc->errormess);
  60.         }
  61.  
  62.     }
  63.  
  64. }
  65.  
  66. display_current_question(pc)    
  67.     struct prcontrol * pc;
  68. {
  69.     printf("\n%s\n",pc->current_group[pc->current_question].text);
  70.     printf("--->");
  71.  
  72. }
  73.  
  74. handle_error(errstat,errormess)
  75.     int errstat;
  76.     struct errormess * errormess;
  77. {
  78.     int i;
  79.     int emess_offset = -1;
  80.     char * message,messagebuff[100];
  81.     
  82.     for(i = 0 ; errormess[i].errstat != -1 ; ++i){
  83.         if(errormess[i].errstat == errstat){
  84.            emess_offset = i;
  85.             break;
  86.         }
  87.     }
  88.     message = messagebuff;
  89.     if(emess_offset != -1){
  90.         strcpy(message,errormess[emess_offset].message);
  91.         if(errormess[emess_offset].build){
  92.             (*errormess[emess_offset].build)(message);
  93.         }
  94.     }
  95.     else{
  96.         sprintf(message,"Error %d.",errstat);
  97.     }
  98.  
  99.     puts("\n");
  100.     puts(message);
  101.     return(0);
  102. }
  103.  
  104.  
  105. /***************************************    
  106.     Flow control routines
  107. ***************************************/
  108. no_op()
  109. {
  110.     return(0);
  111. }
  112.  
  113. next_question(pc)
  114.     struct prcontrol * pc;
  115. {
  116.     ++pc->current_question;
  117.     return(0);
  118. }
  119.  
  120.  
  121. pop_group(pc)
  122.     struct prcontrol * pc;
  123. {
  124.     --pc->group_stack_ptr;
  125.     pc->current_group = group_stack[pc->group_stack_ptr].group; 
  126.     pc->current_question = group_stack[pc->group_stack_ptr].current_question;
  127.     return(0);
  128. }
  129.  
  130. push_current_group(pc)
  131.     struct prcontrol * pc;
  132. {
  133.     group_stack[pc->group_stack_ptr].group = pc->current_group;
  134.     group_stack[pc->group_stack_ptr].current_question = pc->current_question;
  135.     ++pc->group_stack_ptr;
  136.     return(0);
  137. }
  138.  
  139. start_group(newgroup,pc)
  140.     struct question * newgroup;
  141.     struct prcontrol * pc;
  142. {
  143.     push_current_group(pc);
  144.     pc->current_group = newgroup;
  145.     pc->current_question = 0;
  146.     return(0);
  147. }
  148.  
  149. restart_group(pc)
  150.     struct prcontrol * pc;
  151. {
  152.     pc->current_question = 0;
  153.     return(0);
  154. }
  155.  
  156.  
  157. end_group(pc)   
  158.     struct prcontrol * pc;
  159. {
  160.     pop_group(pc);
  161.     ++pc->current_question;
  162.     return(0);
  163. }
  164.  
  165. checkerror_end_group(pc)
  166.     struct prcontrol * pc;
  167. {   
  168.     if(pc->errstat){    
  169.         return(0);
  170.     }
  171.     end_group(pc);
  172.     return(0);
  173. }
  174.  
  175. checkerror_next_question(pc)
  176.     struct prcontrol * pc;
  177. {   
  178.     if(pc->errstat){    
  179.         return(0);
  180.     }
  181.     next_question(pc);
  182.     return(0);
  183. }
  184.  
  185.  
  186. [LISTING TWO]
  187.  
  188. /****************************************************************************
  189.     Name : prompter.h 
  190.  
  191.     Description : Declarations for prompter
  192. ****************************************************************************/
  193.  
  194. struct prcontrol {
  195.     int current_question;
  196.     struct question * current_group;
  197.     int group_stack_ptr;
  198.     char response[121];
  199.     int errstat;
  200.     struct errormess * errormess;
  201.     };
  202.  
  203. struct question {
  204.     char * text;
  205.     char * response;
  206.     int (*validate)();
  207.     int (*doit)();
  208.     int (*set)();
  209.     };
  210.  
  211. struct group_stack {
  212.     struct question * group;
  213.     int current_question;
  214.     };
  215.  
  216. /************************
  217.    errormess data structure
  218. ************************/
  219.     
  220. struct errormess {
  221.     int errstat;
  222.     char * message;
  223.     int (*build)();
  224.     };
  225.  
  226. #define GROUP_STACK_SIZE            50
  227. #define NO_ERROR                    0
  228. #define EXIT_NOW                    2001
  229.  
  230. int pop_group(),end_group(),no_op(),next_question();
  231. int checkerror_end_group(),checkerror_next_question();
  232.  
  233.  
  234. [LISTING THREE]
  235.  
  236. /****************************************************************************
  237.     Name : prsample.c
  238.  
  239.     Description : A sample that uses the prompter() routine
  240. ****************************************************************************/
  241. #include<stdio.h>
  242. #include"prompter.h"
  243. #include<ctype.h>
  244.  
  245. /**************************
  246.     The report parameter variables 
  247. ***************************/
  248. char report_destination[2];
  249. char dest_filename[30];
  250. char single_or_range[2];
  251. char start_account[20],end_account[20];
  252. int account_number;
  253. char display_parmname[50];
  254. char include_overshort[2];
  255.  
  256. /*********************
  257.     Error Values
  258. *********************/
  259. #define ENTER_S_OR_R            1
  260. #define ENTER_Y_OR_N            2
  261. #define START_ACCOUNT_LARGER    3
  262. #define BAD_PARM_NAME           4
  263. #define BAD_ACCOUNT_NUMBER      5
  264. #define ENTER_P_S_OR_D          6
  265. #define FILE_EXISTS             7
  266.  
  267. /************************
  268.   Report to printer, screen or disk routines
  269. ************************/
  270. int filename_val();
  271. struct question report_filename[] = {   
  272.     { "What is the name of the disk file?",
  273.         dest_filename,filename_val,no_op,checkerror_end_group},
  274.     {   NULL,NULL,NULL,NULL,NULL }
  275.     };
  276.  
  277. filename_val(pc)    
  278.     struct prcontrol * pc;
  279. {
  280.     FILE * fp,*fopen();
  281.     /* you should put a routine to validate that the response
  282.        entered is a legal file name here */
  283.     if(fp = fopen(pc->response,"r")){
  284.         fclose(fp);
  285.         return(FILE_EXISTS);
  286.     }
  287.     return(0);
  288. }
  289.  
  290. reportdest_val(pc)
  291.     struct prcontrol * pc;
  292. {
  293.     char * strchr();
  294.     if((!strchr("PpSsDd",pc->response[0])) || (strlen(pc->response) != 1)){
  295.         return(ENTER_P_S_OR_D);
  296.     }
  297.     return(0);
  298. }
  299.  
  300. reportdest_set(pc)
  301.     struct prcontrol * pc;
  302. {
  303.     char destination;
  304.     destination = islower(*pc->response) ? *pc->response-32 : *pc->response;
  305.     switch(destination){    
  306.         case 'P' :
  307.         case 'S' : next_question(pc);
  308.                    break;
  309.         case 'D' : start_group(report_filename,pc);
  310.                    break;
  311.    }
  312.    return(0);
  313. }
  314.  
  315. /***************************
  316.     Account routines
  317. ***************************/
  318. int account_val(),end_account_set(),end_account_val();
  319.  
  320. struct question account_range[] = {
  321.     {"Enter the starting account.",
  322.         start_account,account_val,no_op,checkerror_next_question},
  323.     {"Enter the ending account.",
  324.         end_account,end_account_val,no_op,end_account_set},
  325.     { NULL,NULL,NULL,NULL,NULL }
  326.     };
  327.  
  328. int save_account_doit(),account_set();
  329. struct question account[] = {
  330.     {"Enter the account.",
  331.         start_account,account_val,save_account_doit,checkerror_end_group},
  332.     {NULL,NULL,NULL,NULL,NULL}};
  333.  
  334. account_or_range_val(pc)
  335.     struct prcontrol * pc;
  336. {
  337.     char * strchr();
  338.     if((!strchr("SsRr",pc->response[0])) || (strlen(pc->response) > 1)){
  339.         return(ENTER_S_OR_R);
  340.     }
  341.     return(0);
  342. }
  343.  
  344. account_or_range_set(pc)
  345.     struct prcontrol * pc;
  346. {
  347.     char account_or_range;
  348.     account_or_range = islower(*pc->response) ? *pc->response-32 : 
  349.                         *pc->response;
  350.     if(pc->errstat){
  351.         return(0);
  352.     }    
  353.     if(account_or_range == 'S'){
  354.         start_group(account,pc);
  355.     }
  356.     if(account_or_range == 'R'){
  357.         start_group(account_range,pc);
  358.     }
  359.     return(0);
  360. }
  361.  
  362. save_account_doit(pc)
  363.     struct prcontrol * pc;
  364. {
  365.     account_number = atoi(pc->response);
  366.     return(0);
  367. }
  368.  
  369. account_val(pc)
  370.     struct prcontrol * pc;
  371. {
  372.     if((atoi(pc->response) < 100) || (atoi(pc->response) > 1000)){   
  373.         return(BAD_ACCOUNT_NUMBER);
  374.     }
  375.     return(0);
  376. }
  377.  
  378. end_account_val(pc)
  379.     struct prcontrol * pc;
  380. {
  381.     int errstat;
  382.     if(errstat = account_val(pc)){
  383.         return(errstat);
  384.     }
  385.     if(atoi(start_account) >= atoi(pc->response)){
  386.         return(START_ACCOUNT_LARGER);
  387.     }
  388.     return(0);
  389. }
  390.  
  391. end_account_set(pc)
  392.     struct prcontrol * pc;
  393. {
  394.     switch(pc->errstat){
  395.         case NO_ERROR             : end_group(pc);
  396.                                     break;
  397.         case START_ACCOUNT_LARGER : restart_group(pc);
  398.                                     break;
  399.         case BAD_ACCOUNT_NUMBER   : break;
  400.     }
  401.     return(0);
  402. }
  403.  
  404. /***************************
  405.     Get display parameters routines
  406. ****************************/
  407. char * legal_parmnames[] = {      /* In a "real" system, this table       */
  408.     "default",                    /* would probably be stored in a file   */
  409.     "daily",                      /* and parmname_val would check to see  */
  410.     "weekly",                     /* if the name entered is in this file. */
  411.     "yearly",
  412.     NULL
  413.     };
  414.  
  415. parmname_val(pc)
  416.     struct prcontrol * pc;
  417. {
  418.     int i;
  419.     for(i = 0 ; legal_parmnames[i] != NULL ; ++i){
  420.         if(strcmp(pc->response,legal_parmnames[i]) == 0){
  421.             return(0);
  422.         }
  423.     }    
  424.     return(BAD_PARM_NAME);
  425. }
  426.  
  427. bld_bad_parmname(message)
  428.     char * message;
  429. {
  430.     sprintf(message + strlen(message)," %s, %s, %s, or %s.",
  431.             legal_parmnames[0],legal_parmnames[1],legal_parmnames[2],
  432.             legal_parmnames[3]);
  433.     return(0);
  434. }
  435.  
  436. /**************************
  437.     yesno validation
  438. ***************************/
  439. yesno_val(pc)
  440.     struct prcontrol * pc;
  441. {
  442.     char * strchr();
  443.     if((!strchr("YyNn",pc->response[0])) || (strlen(pc->response) != 1)){
  444.         return(ENTER_Y_OR_N);
  445.     }
  446.     return(0);
  447. }
  448.  
  449. /**************************************
  450.     Main question array procedure table
  451. ***************************************/
  452. struct question account_parms[] = {
  453.     {"Do you want this report for a single account or a range of accounts? (S or R)",
  454.         single_or_range,account_or_range_val,no_op,account_or_range_set },
  455.     {"Enter the name of the display parameter record.",
  456.         display_parmname,parmname_val,no_op,checkerror_next_question},
  457.     {"Do you want to include the Over/Short Report? (Y/N)",
  458.         NULL,yesno_val,no_op,checkerror_next_question},
  459.     {"Do you want this report on the printer, screen, or saved to disk?(P,S or D)",
  460.         report_destination,reportdest_val,no_op,reportdest_set},
  461.     { NULL,NULL,NULL,NULL,NULL }
  462.     };
  463.  
  464. struct errormess account_errormess[] = { 
  465.     { ENTER_S_OR_R,"Please enter S or R.",NULL },
  466.     { ENTER_Y_OR_N,"Please enter Y or N.",NULL },
  467.     { START_ACCOUNT_LARGER,"The starting account must be smaller than the ending account.",NULL },
  468.     { BAD_ACCOUNT_NUMBER,"The account number must be between 100 and 1000",NULL },
  469.     { BAD_PARM_NAME,"Choose one of the following :",bld_bad_parmname },
  470.     { ENTER_P_S_OR_D,"Please enter P, S or D",NULL },
  471.     { FILE_EXISTS,"That file already exists.",NULL },
  472.     { -1,NULL,NULL }
  473.     };
  474.  
  475. main(argc,argv)
  476.     int argc;
  477.     char * argv[];
  478. {
  479.     int errstat;
  480.     struct prcontrol prcontrol;
  481.  
  482.     prcontrol.current_group = account_parms;
  483.     prcontrol.errormess = account_errormess;
  484.  
  485.     if(errstat = prompter(&prcontrol)){
  486.         handle_error(errstat,account_errormess);
  487.     }
  488.     /*  Print the report with the gathered parameters */
  489. }
  490.  
  491.  
  492.  
  493.  
  494. [EXAMPLE 1]
  495.  
  496.  
  497.         loop{
  498.             display current_question->text
  499.             
  500.             get response from user
  501.  
  502.             execute current_question->validate
  503.  
  504.             if(no error on validate){
  505.                 execute current_question->doit
  506.             }
  507.  
  508.             copy response to current_question->response
  509.  
  510.             execute current_question->set
  511.  
  512.             if(error from validate){
  513.                 call error handler
  514.             }
  515.         }
  516.  
  517.  
  518.  
  519.