From: MERC::"uunet!CRVAX.SRI.COM!RELAY-INFO-VAX" 30-JUN-1992 02:10:02.31 To: info-vax@kl.sri.com CC: Subj: Re: CLI/CLD confusion -- How can I do this? Many thanks to all of the people who helped me to discover the solution to the problem I was having with CLI/CLD files, including: granoff@ranger.enet.dec.com, richon@stsci.edu, mjr059@mipl5.jpl.nasa.gov, d_north@ondec.lonestar.org, and nreadwin@micrognosis.co.uk. Most especially thanks to Ehud Gavron, who helped *enormously* in solving this problem. The problem involved several factors: - specify a qualifier/parameter only once, in the "parent" section; don't specify it again in the alternate syntax definition - use the NOPARAMETERS clause in the alternate syntax definition to "negate" the effect of the p1 definition in the parent (otherwise the alternate syntax will inherit the parent parameters) - use DISALLOWs to prevent mutually exclusive combinations; do not rely on alternate syntax definitions to do this for you. As you may have surmised, the example I included was vastly simplified from the *real* interface that I was trying to design. At the end of this message I am including a not-quite-so-simplified example of what I have finally been able to come up with -- it works the way I want it to, FINALLY! To play around with the example: $ $ define lnk$library sys$library:vaxcrtl.olb $ cc test $ set command testcld/object $ link test, testcld $ test :== "$ dev:[dir]test" Legal commands: $ test LOAD [/qualifiers] [tapename] $ test ENTER tapename [/qualifiers] where: a) legal qualifiers are: /JUKEBOX [ = jukename] /PERMANENT /SLOT [ = slotnumber] /PORT [ = portnumber] /DRIVE[ = drivenumber] b) /JUKEBOX and /PERMANENT can be specified at any time c) /SLOT, /PORT, and /DRIVE are mutually exclusive (you can have at most ONE of these qualifiers on the command line) d) LOAD does *NOT* take a parameter (tapename) if /SLOT, /PORT, or /DRIVE is present on the command line; otherwise you are *required* to enter a tape name e) ENTER *always* requires a tapename. The best part about the solution below (imho) is that CLI$DCL_PARSE still prompts for P1 *iff* it is *required*, and not when it is not required. Way cool. Thanks again to all who offered their advice. -- lauri ----------------------------------------------------------------------------- | Lauri Loebel "All that is gold does not glitter, | | lauri@elwing.fnal.gov Not all those who wander are lost..." - JRRT | |...they don't generally like what i say anyway, so i don't speak for them... | ----------------------------------------------------------------------------- ! ------------------------ start of TESTCLD.CLD ------------------------- module TESTCLD define verb LOAD routine LOAD parameter p1 label=tape_name,prompt="Tape name",value(required) qualifier slot syntax=LOAD_SLOT,nonnegatable,value qualifier port syntax=LOAD_PORT,nonnegatable,value qualifier drive syntax=LOAD_DRIVE,nonnegatable,value qualifier jukebox nonnegatable,value qualifier permanent nonnegatable disallow any2(slot, port, drive) define syntax LOAD_SLOT routine LOAD_SLOT noparameters define syntax LOAD_PORT routine LOAD_PORT noparameters define syntax LOAD_DRIVE routine LOAD_DRIVE noparameters define verb ENTER routine ENTER parameter p1 label=tape_name, prompt="Tape name",value(required) qualifier slot syntax=ENTER_SLOT,nonnegatable,value qualifier port syntax=ENTER_PORT,nonnegatable,value qualifier drive syntax=ENTER_DRIVE,nonnegatable,value qualifier jukebox nonnegatable,value qualifier permanent nonnegatable disallow any2(slot, port, drive) define syntax ENTER_SLOT routine ENTER_SLOT ! inherits parameters from parent define syntax ENTER_PORT routine ENTER_PORT ! inherits parameters from parent define syntax ENTER_DRIVE routine ENTER_DRIVE ! inherits parameters from parent ! ------------------------ end of TESTCLD.CLD ------------------------- ! ------------------------ start of TEST.C ------------------------- #include ssdef /* VMS status return symbols */ #include descrip /* VMS descriptor structures */ #include climsgdef /* Command Language Interpreter definitions */ #include stsdef /* VMS status values */ #include rmsdef /* RMS status return definitions */ #include rms /* RMS initialization routines */ extern long LIB$GET_FOREIGN(); /* obtain command line */ extern long CLI$DCL_PARSE(); /* make sure that it is legal */ extern long CLI$DISPATCH(); /* dispatch to the appropriate action routine */ extern long LIB$GET_INPUT(); /* prompt for missing values */ extern long TESTCLD(); /* command definition module */ extern long CLI$PRESENT(); /* check if value is present */ extern long CLI$GET_VALUE(); /* get specific value */ extern long VAXC$ESTABLISH(); /* establish an alternate condition handler */ extern long LIB$SIG_TO_RET(); /* the alternate handler: convert SIGNALLED conditions to STATUS values and return them */ $DESCRIPTOR(d_p1, "TAPE_NAME"); /* descriptor for entity P1 from TESTCLD */ $DESCRIPTOR(d_slot, "SLOT"); /* descriptor for entity SLOT from TESTCLD */ $DESCRIPTOR(d_port, "PORT"); /* descriptor for entity PORT from TESTCLD */ $DESCRIPTOR(d_drive, "DRIVE"); /* descriptor for entity DRIVE from TESTCLD */ $DESCRIPTOR(d_juke, "JUKEBOX"); /* descriptor for entity JUKE from TESTCLD */ $DESCRIPTOR(d_perm, "PERMANENT"); /* descriptor for entity PERMANENT from TESTCLD */ char p1_val[255]; /* storage for the value of P1 as entered */ $DESCRIPTOR(d_p1_val, p1_val); /* descriptor format for storage of P1 value */ char slot_val[255]; /* storage for the value of SLOT as entered */ $DESCRIPTOR(d_slot_val, slot_val); /* descriptor format for storage of SLOT value */ char port_val[255]; /* storage for the value of PORT as entered */ $DESCRIPTOR(d_port_val, port_val); /* descriptor format for storage of PORT value */ char drive_val[255]; /* storage for the value of DRIVE as entered */ $DESCRIPTOR(d_drive_val, drive_val); /* descriptor format for storage of DRIVE value */ char juke_val[255]; /* storage for the value of JUKEBOX as entered */ $DESCRIPTOR(d_juke_val, juke_val); /* descriptor format for storage of JUKEBOX value */ char cmdline[255]; /* storage for the command line text to be parsed */ $DESCRIPTOR(d_cmdline,cmdline); /* descriptor format for the command line text */ #define SIGNAL(c) if (!(c&1)) lib$signal(c) /* error signalling routine */ main() { long status; /* ***** VAXC$ESTABLISH(LIB$SIG_TO_RET); ***** <<--- this may or may not help later. */ p1_val[0] = '\0'; /* initialize strings to being empty */ slot_val[0] = '\0'; port_val[0] = '\0'; drive_val[0] = '\0'; juke_val[0] = '\0'; cmdline[0] = '\0'; status = parse(); /* pass to the main parsing routine */ SIGNAL(status); exit(SS$_NORMAL); /* bye bye */ } /************************ * main parsing routine * ************************/ long parse() { long status; /* status return values */ status = LIB$GET_FOREIGN(&d_cmdline, 0, &d_cmdline.dsc$w_length); /* get the foreign command line */ SIGNAL(status); /* signal any errors */ cmdline[d_cmdline.dsc$w_length] = '\0'; /* terminate the string for C */ status = CLI$DCL_PARSE(&d_cmdline, /* let CLI$DCL_PARSE do the hard work */ TESTCLD, &LIB$GET_INPUT, &LIB$GET_INPUT, 0); status = CLI$DISPATCH(); status = CLI$PRESENT(&d_juke); /* was /JUKEBOX specified? */ if ( status == CLI$_PRESENT ) { printf("\n/Jukebox"); status = CLI$GET_VALUE(&d_juke, &d_juke_val, &d_juke_val.dsc$w_length); /* get any value associated with jukebox */ juke_val[d_juke_val.dsc$w_length] = '\0'; /* null terminate the string */ if ( status != CLI$_ABSENT ) printf(" = %s",juke_val); } status = CLI$PRESENT(&d_perm); if ( status == CLI$_PRESENT ) printf("\n/Permanent"); return(SS$_NORMAL); } /******************************************************************************* * LOAD action routine if no qualifier is specified; parameter p1 is REQUIRED. * *******************************************************************************/ long load() { long status; /* status return values */ printf("\nLOAD: P1 = "); status = CLI$GET_VALUE(&d_p1, &d_p1_val, &d_p1_val.dsc$w_length); /* get p1 value */ p1_val[d_p1_val.dsc$w_length] = '\0'; /* null-terminate the string for C */ if ( status == CLI$_ABSENT ) /* show the results */ printf("-- whoops! no value"); else printf("%s",p1_val); return(SS$_NORMAL); } /******************************************************************************** * ENTER action routine if no qualifier is specified; parameter p1 is REQUIRED. * ********************************************************************************/ long enter() { long status; /* status return values */ printf("\nENTER: P1 = "); status = CLI$GET_VALUE(&d_p1, &d_p1_val, &d_p1_val.dsc$w_length); /* get p1 value */ p1_val[d_p1_val.dsc$w_length] = '\0'; /* null-terminate the string for C */ if ( status == CLI$_ABSENT ) /* show the results */ printf("-- whoops! no value"); else printf("%s",p1_val); return(SS$_NORMAL); } /************************************************************************ * LOAD action routine if /SLOT [ =value] is specified. No parameters. * ************************************************************************/ long load_slot() { long status; /* status return values */ printf("\nLOAD_SLOT: /SLOT"); status = CLI$GET_VALUE(&d_slot, &d_slot_val, &d_slot_val.dsc$w_length); /* get any value associated with slot */ slot_val[d_slot_val.dsc$w_length] = '\0'; /* null-terminate the string */ if ( status != CLI$_ABSENT ) /* show the results */ printf(" = %s", slot_val); return(SS$_NORMAL); } /*********************************************************************************** * ENTER action routine if /SLOT [ =value] is specified. A parameter is required. * ***********************************************************************************/ long enter_slot() { long status; /* status return values */ printf("\nENTER_SLOT: /SLOT"); status = CLI$GET_VALUE(&d_slot, &d_slot_val, &d_slot_val.dsc$w_length); /* get any value associated with slot */ slot_val[d_slot_val.dsc$w_length] = '\0'; /* null-terminate the string */ if ( status != CLI$_ABSENT ) /* show the results */ printf(" = %s", slot_val); status = CLI$GET_VALUE(&d_p1, &d_p1_val, &d_p1_val.dsc$w_length); /* get the parameter value */ p1_val[d_p1_val.dsc$w_length] = '\0'; /* null terminate the string */ if ( status != CLI$_ABSENT ) /* show the results */ printf("\nP1 = %s",p1_val); return(SS$_NORMAL); } /************************************************************************ * LOAD action routine if /PORT [ =value] is specified. No parameters. * ************************************************************************/ long load_port() { long status; /* status return values */ printf("\nLOAD_PORT: /PORT"); status = CLI$GET_VALUE(&d_port, &d_port_val, &d_port_val.dsc$w_length); /* get any value associated with port */ port_val[d_port_val.dsc$w_length] = '\0'; /* null-terminate the string */ if ( status != CLI$_ABSENT ) /* show the results */ printf(" = %s", port_val); return(SS$_NORMAL); } /*********************************************************************************** * ENTER action routine if /PORT [ =value] is specified. A parameter is required. * ***********************************************************************************/ long enter_port() { long status; /* status return values */ printf("\nENTER_PORT: /PORT"); status = CLI$GET_VALUE(&d_port, &d_port_val, &d_port_val.dsc$w_length); /* get any value associated with port */ port_val[d_port_val.dsc$w_length] = '\0'; /* null-terminate the string */ if ( status != CLI$_ABSENT ) /* show the results */ printf(" = %s", port_val); status = CLI$GET_VALUE(&d_p1, &d_p1_val, &d_p1_val.dsc$w_length); /* get the parameter value */ p1_val[d_p1_val.dsc$w_length] = '\0'; /* null terminate the string */ if ( status != CLI$_ABSENT ) /* show the results */ printf("\nP1 = %s",p1_val); return(SS$_NORMAL); } /************************************************************************ * LOAD action routine if /DRIVE [ =value] is specified. No parameters. * ************************************************************************/ long load_drive() { long status; /* status return values */ printf("\nLOAD_DRIVE: /DRIVE"); status = CLI$GET_VALUE(&d_drive, &d_drive_val, &d_drive_val.dsc$w_length); /* get any value associated with drive */ drive_val[d_drive_val.dsc$w_length] = '\0'; /* null-terminate the string */ if ( status != CLI$_ABSENT ) /* show the results */ printf(" = %s", drive_val); return(SS$_NORMAL); } /*********************************************************************************** * ENTER action routine if /DRIVE [ =value] is specified. A parameter is required. * ***********************************************************************************/ long enter_drive() { long status; /* status return values */ printf("\nENTER_DRIVE: /DRIVE"); status = CLI$GET_VALUE(&d_drive, &d_drive_val, &d_drive_val.dsc$w_length); /* get any value associated with drive */ drive_val[d_drive_val.dsc$w_length] = '\0'; /* null-terminate the string */ if ( status != CLI$_ABSENT ) /* show the results */ printf(" = %s", drive_val); status = CLI$GET_VALUE(&d_p1, &d_p1_val, &d_p1_val.dsc$w_length); /* get the parameter value */ p1_val[d_p1_val.dsc$w_length] = '\0'; /* null terminate the string */ if ( status != CLI$_ABSENT ) /* show the results */ printf("\nP1 = %s",p1_val); return(SS$_NORMAL); } ! ------------------------ end of TEST.C -------------------------