/*############################################################################## FUNNNELWEB COPYRIGHT ==================== FunnelWeb is a literate-programming macro preprocessor. The FunnelWeb web is at http://www.ross.net/funnelweb/ Copyright (c) Ross N. Williams 1992. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of Version 2 of the GNU General Public License as published by the Free Software Foundation (http://www.gnu.org/). This program is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 of the GNU General Public License for more details. You should have received a copy of Version 2 of the GNU General Public License along with this program. If not, you can obtain a copy as follows: ftp://prep.ai.mit.edu/pub/gnu/COPYING-2.0 or write to: Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA Section 2a of the license requires that all changes to this file be recorded prominently in this file. Please record all changes here. Programmers: RNW Ross N. Williams (ross@ross.net) Changes: 07-May-1992 RNW Program prepared for release under GNU GPL V2. 08-May-1999 RNW Added +u option for HTML documentation. ##############################################################################*/ /******************************************************************************/ /* OPTION.C */ /******************************************************************************/ #include #include "style.h" #include "as.h" #include "data.h" #include "machin.h" #include "misc.h" #include "option.h" /******************************************************************************/ LOCAL void wl_caret P_((ulong,void (*)(char *))); LOCAL void wl_caret(n,p_outf) /* Writes a caret at position n of an otherwise blank line. */ ulong n; void (*p_outf) P_((char *)); { as_cold(n<1000,"wl_caret: Argument is out of range."); while (--n > 0) (*p_outf)(" "); (*p_outf)("^\n"); } /******************************************************************************/ EXPORT void op_ini(p_op) p_op_t p_op; { p_op->op_f_b=FALSE; strcpy(&p_op->op_f_s[0],""); p_op->op_j_b=FALSE; strcpy(&p_op->op_j_s[0],""); strcpy(&p_op->op_i_s[0],""); p_op->op_o_b=TRUE; strcpy(&p_op->op_o_s[0],""); p_op->op_t_b=FALSE; strcpy(&p_op->op_t_s[0],""); p_op->op_u_b=FALSE; strcpy(&p_op->op_u_s[0],""); p_op->op_l_b=TRUE; strcpy(&p_op->op_l_s[0],""); p_op->op_d_b=FALSE; p_op->op_c_i=2; p_op->op_q_b=FALSE; p_op->op_s_b=FALSE; p_op->op_s_i=1; p_op->op_w_b=FALSE; p_op->op_w_i=80; p_op->op_x_b=FALSE; strcpy(&p_op->op_x_s[0],""); p_op->op_k_b=FALSE; p_op->op_b1_b=FALSE; p_op->op_b2_b=FALSE; p_op->op_b3_b=FALSE; p_op->op_b4_b=FALSE; p_op->op_b5_b=FALSE; p_op->op_b6_b=FALSE; p_op->op_b7_b=FALSE; p_op->op_h_b=FALSE; strcpy(&p_op->op_h_s[0],"menu"); } /******************************************************************************/ EXPORT bool op_add(p_op,p_cl,p_outf) p_op_t p_op; p_cl_t p_cl; void (*p_outf) P_((char *)); { op_t op_save; /* Saves *p_op so it can be restored later. */ char *comline = (char *) p_cl; /* Pointer to the command line to be parsed. */ char *p; /* Handy parsing pointer. */ bool seen_error = FALSE; /* TRUE iff one or more errors seen. */ #define ECHO_CL {if (!seen_error)\ {(*p_outf)(comline);(*p_outf)("\n"); seen_error=TRUE;}} /* Save the parameter option structure so that we can restore it */ /* if an error occurs later on. */ ASSIGN(op_save,*p_op); /* Check to make sure that the command line is not too long. */ /* This error should really never occur. */ p=comline; while (*p++ != EOS) if ((p-comline) > COMLINE_MAX) { (*p_outf)("FunnelWeb command line syntax error.\n"); (*p_outf)("The entire command line is too long.\n"); sprintf(linet1,"The maximum command line length is %u characters.\n", (unsigned) COMLINE_MAX); (*p_outf)(linet1); goto failure; } /* Check that the command line contains only printables. */ p=comline; while (*p != EOS) { if (!isascprn(*p)) { (*p_outf)("FunnelWeb command line syntax error.\n"); (*p_outf)("Command line contains one or more non-printables.\n"); sprintf(linet1,"The first is at column %u.\n",(unsigned) (1+p-comline)); (*p_outf)(linet1); goto failure; } p++; } /* Now parse each option. */ p=comline; while (TRUE) {/* This loop processes one command line parameter (option) per iteration. */ char *p_startopt; /* Points to the start of the parameter. */ bool opsign; /* The sign of the current option (+=TRUE). */ bool opsign_active; /* TRUE => (+ or -). FALSE => (=). */ char letter; /* Letter of current option. */ cl_t cl_temp; /* Parameter string of the current option. */ fn_t fn_temp; /* Parameter string of the current option. */ int i; /* Handy int used to feed sscanf. */ /* Skip first parameter or rest of previous parameter after syntax error. */ while ((*p!=' ') && (*p!=EOS)) p++; /* Skip blanks between parameters. */ while (*p==' ') p++; /* At this point we are either at the start of a parameter or at EOS. */ /* Finish if we are at the EOS. */ if (*p==EOS) break; /* p now points to the next parameter (option). Make a note of its start. */ p_startopt=p; /* This switch statement parses the sign and letter characters. */ switch (*p) { case '-': opsign=FALSE; opsign_active=TRUE; p++; goto parse_letter; case '+': opsign=TRUE; opsign_active=TRUE; p++; goto parse_letter; case '=': opsign_active=FALSE; p++; goto parse_letter; parse_letter: /* We have seen a sign. There should be a following letter. */ letter = *p; if (!isalpha(letter)) { ECHO_CL; wl_caret(p-comline,p_outf); (*p_outf)("FunnelWeb command line syntax error.\n"); (*p_outf)("Option letter expected here.\n"); continue; /* Skip to the next parameter. */ } p++; break; default: /* If no sign the option is a NAME option and defaults to +F. */ opsign=TRUE; opsign_active=TRUE; letter='F'; break; } /* End switch */ /* Assert: p points to the parameter string of the option. */ /* Copy the parameter string into the holding variable cl_temp. */ {char *q; q = &cl_temp[0]; while ((*p!=EOS) && (*p!=' ')) *q++ = *p++; *q=EOS; } /* As COMLINE_MAX can be greater than PATHNAME_MAX, we have to be careful */ /* that the user is not about to blow our filename buffer. */ if (strlen(cl_temp) > PATHNAME_MAX) { ECHO_CL; wl_caret(p_startopt-comline,p_outf); (*p_outf)("FunnelWeb command line syntax error.\n"); (*p_outf)("Option parameter string is too long.\n"); sprintf(linet1,"The maximum option parameter length is %u characters.\n", (unsigned) PATHNAME_MAX); (*p_outf)(linet1); continue; /* Skip to next parameter. */ } /* Now that we know that the parameter is not too big, we can copy it */ /* into a temporary variable of filename type. */ strcpy(&fn_temp[0],&cl_temp[0]); /* At this point p points to the character following the option that */ /* we have just scanned. This is either a blank or an EOS. */ /* The current option is held in (opsign,opsign_active,letter,fn_temp). */ /* Now we apply the option to the option record. */ switch (toupper(letter)) { case 'F': if (opsign_active) p_op->op_f_b=opsign; strcpy(&p_op->op_f_s[0],&fn_temp[0]); break; case 'J': if (opsign_active) p_op->op_j_b=opsign; strcpy(&p_op->op_j_s[0],&fn_temp[0]); break; case 'I': strcpy(&p_op->op_i_s[0],&fn_temp[0]); break; case 'O': if (opsign_active) p_op->op_o_b=opsign; strcpy(&p_op->op_o_s[0],&fn_temp[0]); break; case 'T': if (opsign_active) p_op->op_t_b=opsign; strcpy(&p_op->op_t_s[0],&fn_temp[0]); break; case 'U': if (opsign_active) p_op->op_u_b=opsign; strcpy(&p_op->op_u_s[0],&fn_temp[0]); break; case 'L': if (opsign_active) p_op->op_l_b=opsign; strcpy(&p_op->op_l_s[0],&fn_temp[0]); break; case 'D': if (opsign_active) p_op->op_d_b=opsign; if (strlen(fn_temp)>0) { ECHO_CL; wl_caret(3+p_startopt-comline,p_outf); (*p_outf)("FunnelWeb command line syntax error.\n"); (*p_outf)("The D option does not take an argument.\n"); } break; case 'C': if ((sscanf(&fn_temp[0],"%d",&i) != 1) || (i<0) || (100op_c_i=i; break; case 'Q': if (opsign_active) p_op->op_q_b=opsign; if (strlen(fn_temp)>0) { ECHO_CL; wl_caret(3+p_startopt-comline,p_outf); (*p_outf)("FunnelWeb command line syntax error.\n"); (*p_outf)("The Q option does not take an argument.\n"); } break; case 'S': if (opsign_active) p_op->op_s_b=opsign; if (strlen(fn_temp)==0) break; if ((sscanf(&fn_temp[0],"%d",&i) != 1) || (i<0) || (100op_s_i=i; break; case 'W': if (opsign_active) p_op->op_w_b=opsign; if (strlen(fn_temp)==0) break; if ((sscanf(&fn_temp[0],"%d",&i) != 1) || (i<0) || (1000op_w_i=i; break; case 'X': if (opsign_active) p_op->op_x_b=opsign; strcpy(&p_op->op_x_s[0],&fn_temp[0]); break; case 'K': if (opsign_active) p_op->op_k_b=opsign; if (strlen(fn_temp)>0) { ECHO_CL; wl_caret(3+p_startopt-comline,p_outf); (*p_outf)("FunnelWeb command line syntax error.\n"); (*p_outf)("The K option does not take an argument.\n"); } break; case 'H': if (opsign_active) p_op->op_h_b=opsign; if (strlen(&fn_temp[0])>0) if (strlen(&fn_temp[0]) > HL_NMLEN) { ECHO_CL; wl_caret(3+p_startopt-comline,p_outf); (*p_outf)("FunnelWeb command line syntax error.\n"); (*p_outf)("The H option string argument is too long.\n"); (*p_outf)("Try +Hmenu for a list of help message names.\n"); } else if (hel_num(&fn_temp[0]) == HL_ERR) { ECHO_CL; wl_caret(3+p_startopt-comline,p_outf); (*p_outf)("FunnelWeb command line syntax error.\n"); (*p_outf)("Unrecognised message name in argument to H option.\n"); (*p_outf)("Try +Hmenu for a list of help message names.\n"); } else strcpy(&p_op->op_h_s[0],&fn_temp[0]); break; case 'B': { uword i; if (strlen(fn_temp)==0) { ECHO_CL; wl_caret(3+p_startopt-comline,p_outf); (*p_outf)("FunnelWeb command line syntax error.\n"); (*p_outf)("The B option must be followed by one or more digits.\n"); (*p_outf)("The digits must be in the range 1..7.\n"); break; } for (i=0;i'7') { ECHO_CL; wl_caret(2+p_startopt-comline+(1+i),p_outf); (*p_outf)("FunnelWeb command line syntax error.\n"); (*p_outf)("Error: Characters in B argument must be '1'..'7'.\n"); goto endbop; } if (opsign_active) for (i=0;iop_b1_b=opsign; break; case '2': p_op->op_b2_b=opsign; break; case '3': p_op->op_b3_b=opsign; break; case '4': p_op->op_b4_b=opsign; break; case '5': p_op->op_b5_b=opsign; break; case '6': p_op->op_b6_b=opsign; break; case '7': p_op->op_b7_b=opsign; break; default: as_bomb("op_add: b option case defaulted."); } endbop: break; } default: ECHO_CL; wl_caret(2+p_startopt-comline,p_outf); (*p_outf)("FunnelWeb command line syntax error.\n"); (*p_outf)("Error: Unknown option letter.\n"); (*p_outf)("Legal option letters are FIOTLCSWPXZ.\n"); (*p_outf)("(Note: But P is not yet implemented!)\n"); break; } } /* End while. */ if (seen_error) goto failure; return TRUE; failure: ASSIGN(*p_op,op_save); return FALSE; } /******************************************************************************/ EXPORT void op_wri(p_op,p_outf) p_op_t p_op; void (*p_outf) P_((char *)); { #define STC(BOOLV) ((BOOLV)?'+':'-') sprintf(linet1," %cB1 %cB2 %cB3 %cB4 %cB5 %cB6 %cB7\n", STC(p_op->op_b1_b), STC(p_op->op_b2_b), STC(p_op->op_b3_b), STC(p_op->op_b4_b), STC(p_op->op_b5_b), STC(p_op->op_b6_b), STC(p_op->op_b7_b));(*p_outf)(linet1); sprintf(linet1," +C%u\n" , (unsigned) p_op->op_c_i );(*p_outf)(linet1); sprintf(linet1," %cD\n" , STC(p_op->op_d_b) );(*p_outf)(linet1); sprintf(linet1," %cF%s\n", STC(p_op->op_f_b), p_op->op_f_s );(*p_outf)(linet1); sprintf(linet1," %cH%s\n", STC(p_op->op_h_b), p_op->op_h_s );(*p_outf)(linet1); sprintf(linet1," +I%s\n" , p_op->op_i_s );(*p_outf)(linet1); sprintf(linet1," %cJ%s\n", STC(p_op->op_j_b), p_op->op_j_s );(*p_outf)(linet1); sprintf(linet1," %cK\n" , STC(p_op->op_k_b) );(*p_outf)(linet1); sprintf(linet1," %cL%s\n", STC(p_op->op_l_b), p_op->op_l_s );(*p_outf)(linet1); sprintf(linet1," %cO%s\n", STC(p_op->op_o_b), p_op->op_o_s );(*p_outf)(linet1); sprintf(linet1," %cQ\n" , STC(p_op->op_q_b) );(*p_outf)(linet1); sprintf(linet1," %cS%u\n", STC(p_op->op_s_b), (unsigned) p_op->op_s_i );(*p_outf)(linet1); sprintf(linet1," %cT%s\n", STC(p_op->op_t_b), p_op->op_t_s );(*p_outf)(linet1); sprintf(linet1," %cU%s\n", STC(p_op->op_u_b), p_op->op_u_s );(*p_outf)(linet1); sprintf(linet1," %cW%u\n", STC(p_op->op_w_b), (unsigned) p_op->op_w_i );(*p_outf)(linet1); sprintf(linet1," %cX%s\n", STC(p_op->op_x_b), p_op->op_x_s );(*p_outf)(linet1); } /******************************************************************************/ /* End of OPTION.C */ /******************************************************************************/