/* ** COPYRIGHT (c) 1993 BY ** DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS. ** ALL RIGHTS RESERVED. ** ** THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED ** ONLY IN ACCORDANCE OF THE TERMS OF SUCH LICENSE AND WITH THE ** INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER ** COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY ** OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY ** TRANSFERRED. ** ** THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE ** AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT ** CORPORATION. ** ** DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS ** SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL. */ #ifdef VAX #module READ_VERIFY "V06-000" #else #pragma module READ_VERIFY "V06-000" #endif /* **++ ** FACILITY: SYS$EXAMPLES ** ** MODULE DESCRIPTION: ** ** READ_VERIFY -- Programming example to demonstrate use of the ** OpenVMS terminal driver to read data from a terminal (as defined ** by the logical name SYS$INPUT) using itemlist read-verify ** input. The module first does a right-justified read of a ** "commercially" formatted (comma to the left of the thousands ** place) six digit number, and then does a left-justified read of ** a date in dd-mmm-yy format. ** ** AUTHORS: ** ** Digital Equipment Corporation ** ** CREATION DATE: 11 March 1993 ** ** ** PRECONDITIONS: ** ** SYS$INPUT must translate to an ANSI-terminal-capable device to ** allow cursor positioning to work correctly. ** ** MODIFICATION HISTORY: ** ** 11-Mar-1993 Conversion from READ_VERIFY.MAR **-- */ /* ** ** INCLUDE FILES ** */ #include /* Descriptor Structure and Constant Definitions */ #include /* I/O function code Definitions */ #include /* Library (LIB$) routine definitions */ #include /* System Service Return Status Value Definitions */ #include /* System routine definitions */ #include /* Symbol definitions for the item list QIO format */ /* ** ** MACRO DEFINITIONS ** */ /* ** The inititmlst_* macros below initialize item lists for itemlist ** terminal reads. Both macros initialize "must be zero" ** parameters (buffer length for the inititmlst_v, return address ** for both). inititmlst_a initializes lists which reference a ** buffer exernal to the item list. inititmlst_v initializes lists ** which use an immediate value instead. ** ** The macros take the following parameters: ** ** Param # Name Usage ** 1 name name of structure to be initialized ** 2 trmcode item list type code ** 3 (_v only) trmvalue immediate value ** 3 (_a only) trmbadr address of referenced buffer ** 4 (_a only) trmblen length of referenced buffer */ #define inititmlst_v(name, trmcode, trmvalue) \ name.buflen = 0; \ name.code = trmcode; \ name.value = trmvalue; \ name.retadr = (void *) (0); #define inititmlst_a(name, trmcode, trmbadr, trmblen) \ name.buflen = trmblen; \ name.code = trmcode; \ name.bufadr = trmbadr; \ name.retadr = (void *) (0); /* ** Hard-coded constants */ #define esc 0x1B /* escape character */ #define in_buflen 20 /* Input buffer length */ /* ** Validation mask for right justified input: ** Allow 0-9, plus, minus, decimal point as valid characters. */ #define R_MASK TRM$M_CV_NUMERIC|TRM$M_CV_NUMPUNC /* ** Validation mask for left justified input: ** Mask 1 allows numeric input only. ** Mask 2 allows alphabetic input (upper or lower case) only. */ #define L_MASK1 TRM$M_CV_NUMERIC #define L_MASK2 TRM$M_CV_UPPER|TRM$M_CV_LOWER /* ** Lengths of various strings (cursor positioning, prompt, initial ** string and picture string for right and left justified input as ** needed). */ #define R_PROMPT_LEN sizeof (R_PROMPT) #define R_INISTR_LEN sizeof (R_INISTR) #define R_PICSTR_LEN sizeof (R_PICSTR) #define L_PR_POS_LEN sizeof (L_PR_POS) #define L_PROMPT_LEN sizeof (L_PROMPT) #define L_INISTR_LEN sizeof (L_INISTR) #define L_PICSTR_LEN sizeof (L_PICSTR) /* ** The following macro defines a status check which ** occurs numerous times throughout the program. */ #define check_s(status) \ if ( ! (status & SS$_NORMAL) ) \ {\ lib$signal (status);\ } /* ** Declare item list structure. Our definition includes a ** non-ANSI-standard variant union construct, to allow reasonable ** length names, so we let the compiler know to allow the ** definition this way. */ #pragma nostandard struct itmlst { unsigned short int buflen; /* Buffer Length */ unsigned short int code; /* Item code */ variant_union { unsigned long int value; /* Immediate value or */ void * bufadr; /* Buffer address */ } valadr; void * retadr; /* Return address (must be zero) */ } ; #pragma standard /* ** Forward routine declarations */ unsigned long int do_read ( unsigned long int, struct itmlst * ); unsigned long int do_curs ( char *, unsigned long int ); /* ** Allocate two arrays of item lists, one for left-justified read ** verify operations, and one for right-justified read verify ** operations. */ struct itmlst l_item_list [6], /* Left-justified item list array */ r_item_list [7]; /* Right-justified item list array */ /* ** Right-Justified Prompt: ** Positions cursor at row 12, column 12, and puts up dollar sign. ** The cursor positioning must be included for right justification, ** since the whole prompt and input field are echoed after each ** character is read in. */ char R_PROMPT[] = {esc,'[','1','2',';','1','2','H','$'} ; char * R_PROMPT_ADDR = &R_PROMPT[0]; /* ** Right-Justified initial String. */ char R_INISTR[] = {' ', ' ', ' ', ',', ' ', ' ', ' ' }; char * R_INISTR_ADDR = &R_INISTR[0]; /* ** Right-Justified Picture String: three digits, marker, three more ** digits (here, digits can be punctuation.). */ char R_PICSTR [] = { R_MASK, R_MASK, R_MASK, 0, R_MASK, R_MASK, R_MASK }; char * R_PICSTR_ADDR = &R_PICSTR[0]; /* ** Positioning for Left-Justified Prompt: ** Positions cursor (at row 13, column 12) prior to left-justified ** prompt. While this can be made part of the prompt itself in this ** example, it is generally safer for left-justified input to do the ** positioning separately to avoid adverse interactions with command ** recall and line wrapping. */ char L_PR_POS[] = { esc,'[','1','3',';','1','2','H'}; char * L_PR_POS_ADDR = &L_PR_POS[0]; /* ** Left-Justified Prompt: ** Puts up " Enter Date: " */ char L_PROMPT[] = { 'E','n','t','e','r',' ','D','a','t','e',':',' '}; char * L_PROMPT_ADDR = &L_PROMPT[0]; /* ** Left-Justified initial String. */ char L_INISTR[] = {' ', ' ', '-', ' ', ' ', ' ', '-', ' ', ' '}; char * L_INISTR_ADDR = &L_INISTR[0]; /* ** Left-justified Picture String: two numbers, marker, three letters, ** marker, two numbers (could represent date in dd-mmm-yy format). */ char L_PICSTR [ ] = { L_MASK1, L_MASK1, 0, L_MASK2, L_MASK2, L_MASK2, 0, L_MASK1, L_MASK1 }; char * L_PICSTR_ADDR = &L_PICSTR[0]; /* ** ANSI Clear Screen sequence (home cursor + clear from cursor). */ char clr_scrn [ ] = { esc, '[', 'H', esc, '[', 'J' }; /* ** I/O status block definition for terminal operations. As with the ** item list, our definition includes a non-ANSI-standard variant ** union construct to allow reasonable length names, so we let the ** compiler know to allow the definition this way. Not all the ** members defined here are actually referenced in this example. */ #pragma nostandard struct iosb { unsigned short int status; /* Common to all forms of IOSB */ variant_union { /* Usage-dependent section of IOSB */ struct { /* Item List Read IOSB */ unsigned short int term_off; /* offset to terminator */ unsigned char term_char; /* terminating character */ unsigned char rdvf_st; /* read-verify status */ unsigned char term_lgth; /* length of terminator */ unsigned char curs_posn; } itlrd; struct { /* Terminal Read IOSB */ unsigned short int term_off; char term_esc; /* escape if present in terminator */ char term_fill; /* fill */ unsigned short int term_size; /* length of terminator */ } trmrd; unsigned short int byte_count; /* Write IOSB -- bytes written */ struct { /* Set/Sense Mode/Characteristics IOSB */ unsigned char xmit_speed; /* transmit speed */ unsigned char rcv_speed; /* receive speed if != transmit */ unsigned char cr_fill_count; /* # fill bytes for CR */ unsigned char lf_fill_count; /* # fill bytes for LF */ unsigned char par_flags; /* parity flags */ unsigned char resvd1; /* not used */ } mode_char; } io_spec; } in_iosb, /* terminal read IOSB */ out_iosb; /* terminal write IOSB */ #pragma standard /* ** Other QIO-related storage. */ unsigned long int sync_efn; /* Event flag number for */ /* synchronous terminal processing */ unsigned long int tt_chan; /* TT channel number storage */ char in_buf [in_buflen]; /* Input buffer */ /* ** Define and initialize constants for program */ $DESCRIPTOR (tt_desc, "SYS$INPUT"); /* Terminal Descriptor */ unsigned long int status = SS$_NORMAL; /* sys svc status return */ /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Main routine: Sets up item lists, assigns terminal channel, ** does right- and left-justified verified reads. ** ** FORMAL PARAMETERS: ** ** None. ** ** RETURN VALUE: ** ** None ** ** SIDE EFFECTS: ** ** No residual effects after exit ** ** ** **-- */ main () { /* ** Declare and initialize clear and fill mask itemlists. ** (clear = space, fill = *) */ unsigned long int fill_mask = '*' | ( ' ' << 8 ); /* ** Initialize Right Justification item lists ** for six-digit number formatted xxx,xxx. */ inititmlst_v (r_item_list[0], TRM$_MODIFIERS, /* Modifier: */ TRM$M_TM_R_JUST) /* create right-justified field */ inititmlst_v (r_item_list[1], TRM$_EDITMODE, /* Specify extended edit mode: */ TRM$K_EM_RDVERIFY) /* enable read verify */ inititmlst_a (r_item_list[2], TRM$_PROMPT, /* set up prompt */ R_PROMPT_ADDR, R_PROMPT_LEN) inititmlst_a (r_item_list[3], TRM$_INISTRNG, /* Set up initial string */ R_INISTR_ADDR, R_INISTR_LEN) inititmlst_v (r_item_list[4], TRM$_INIOFFSET, /* specify start of echo as the */ R_INISTR_LEN) /* beginning (right justification) */ inititmlst_a (r_item_list[5], TRM$_PICSTRNG, /* Set up picture string for */ R_PICSTR_ADDR, /* character validation */ R_PICSTR_LEN) inititmlst_v (r_item_list[6], TRM$_FILLCHR, /* Specify clear and fill characters: */ fill_mask ) /* clear = space, fill = * */ /* ** Initialize Left Justification item lists for eight-character ** data formatted dd-mmm-yy. */ inititmlst_v (l_item_list[0], TRM$_MODIFIERS, /* Modifier: */ TRM$M_TM_CVTLOW| /* Uppercase the input */ TRM$M_TM_AUTO_TAB) /* and complete on field full */ inititmlst_v (l_item_list[1], TRM$_EDITMODE, /* Specify extended edit mode: */ TRM$K_EM_RDVERIFY) /* Enable read verify */ inititmlst_a (l_item_list[2], TRM$_PROMPT, /* Set up prompt */ L_PROMPT_ADDR, L_PROMPT_LEN) inititmlst_a (l_item_list[3], TRM$_INISTRNG, /* Set up initial string */ L_INISTR_ADDR, L_INISTR_LEN) inititmlst_v (l_item_list[4], TRM$_INIOFFSET, /* specify start of echo as the */ 0) /* beginning (left justification) */ inititmlst_a (l_item_list[5], TRM$_PICSTRNG, /* Set up picture string */ L_PICSTR_ADDR, L_PICSTR_LEN) /* ** Begin by getting an event flag number for synchronous I/O */ status = lib$get_ef (&sync_efn); /* EFN for sync terminal operations */ check_s(status) /* ensure flag obtained ok */ /* ** Assign a channel for the terminal. */ status = sys$assign ( /* Assign channel using logical name */ &tt_desc, /* device descriptor for SYS$INPUT */ &tt_chan, /* channel number */ 0, /* default access mode */ 0); /* No mailbox */ check_s(status) /* Ensure assign went OK */ /* ** Clear the screen before beginning. */ status = do_curs ( &clr_scrn[0], sizeof(clr_scrn) ); check_s(status) /* Ensure clear went OK */ /* ** Do the right-justified read operation. As noted above, cursor ** positioning will be repeated for every character read in. */ status = do_read (sizeof (r_item_list), &r_item_list[0]); check_s(status) /* Ensure read went OK */ /* ** Position cursor once and do the left-justified read operation. */ status = do_curs ( L_PR_POS_ADDR, L_PR_POS_LEN ); check_s(status) /* Ensure positioning went OK */ status = do_read (sizeof (l_item_list), &l_item_list[0]); check_s(status) /* Ensure read went OK */ /* ** All done. */ } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** do_read: Does itemlist reads for main program. ** ** FORMAL PARAMETERS: ** ** itmlen: ** Length of item list in bytes. ** ** itmadr: ** Address of item list. ** ** RETURN VALUE: ** ** The most severe status return code from the actual read: ** either the return QIO status code if not normal, or the IOSB ** status if the QIO call returned normal status, ** ** SIDE EFFECTS: ** ** Causes itemlist read to be done to the SYS$INPUT device ** ** PRECONDITIONS: ** ** Channel and event flag are assigned. ** ** ** IMPLICIT INPUT PARAMETERS: ** ** (NOTE: these all have file scope, i.e. they are available to ** all functions and routines in the module.) ** ** sync_efn: ** Event flag number for synchronous I/O ** ** tt_chan: ** Assigned channel number for I/O. ** ** in_buflen: ** Input buffer length. ** ** IMPLICIT OUTPUT PARAMETERS: ** ** in_buf: ** File-scope input buffer ** ** in_iosb: ** I/O Status Block. ** ** **-- */ unsigned long int do_read ( unsigned long int itmlen, struct itmlst * itmadr ) { unsigned long int io_stat; /* ** Do QIO. Use the event flag number sync_efn, channel number ** tt_chan, IO status block in_iosb and input buffer in_buf, all ** of which are available to all routines in this module. */ io_stat = sys$qiow ( sync_efn, /* event flag number */ tt_chan, /* channel number */ IO$_READVBLK| /* Function code is */ IO$M_EXTEND, /* itemlist read virtual block */ &in_iosb, /* Use own I/O status block */ 0, /* No AST routine */ 0, /* or parameter */ &in_buf[0], /* P1 = Input buff addr */ in_buflen, /* P2 = Input buff length */ 3, /* P3 = 3 for user mode itemlist probe */ 0, /* no P4 */ itmadr, /* P5 = Itemlist read address */ itmlen); /* P6 = Itemlist read size */ /* ** Any processing of input could be done here, or could be done in ** the calling routine. */ /* ** Return to caller the worst status returned from QIO: QIO ** status if not normal, status from IOSB if QIO status normal. */ return (!(io_stat & SS$_NORMAL) ? io_stat : in_iosb.status); } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** do_curs: Does writes to position cursor (and clear screen if ** input string specifies) prior to itemlist reads for main program. ** ** FORMAL PARAMETERS: ** ** cursadr: ** Address of cursor control string. ** ** curslen: ** Length of cursor control string in bytes. ** ** RETURN VALUE: ** ** The most severe status return code from the actual write: ** either the return QIO status code if not normal, or the IOSB ** status if the QIO call returned normal status, ** ** SIDE EFFECTS: ** ** Causes cursor position to change on the SYS$INPUT device, and ** clears screen from cursor position to end if provided cursor ** control string so specifies. ** ** PRECONDITIONS: ** ** Channel and event flag are assigned. ** ** ** IMPLICIT INPUT PARAMETERS: ** ** (NOTE: these all have file scope, i.e. they are available to ** all functions and routines in the module.) ** ** sync_efn: ** Event flag number for synchronous I/O ** ** tt_chan: ** Assigned channel number for I/O. ** ** IMPLICIT OUTPUT PARAMETERS: ** ** out_iosb: ** I/O Status Block. ** ** **-- */ unsigned long int do_curs ( char * cursadr, unsigned long int curslen ) { unsigned long int io_stat; /* ** Do QIO. Use the event flag number sync_efn, channel number ** tt_chan and IO status block out_iosb, all of which are ** available to all routines in this module. */ io_stat = sys$qiow ( sync_efn, /* event flag number */ tt_chan, /* channel number */ IO$_WRITEVBLK, /* Function is write virt blk */ &out_iosb, /* use write I/O stat blk */ 0, /* No AST routine */ 0, /* or parameter */ cursadr, /* P1 = addr of string */ curslen, /* P2 = length of string */ 0, /* No P3-P6 */ 0, 0, 0); /* ** Return to caller the worst status returned from QIO: QIO ** status if not normal, status from IOSB if QIO status normal. */ return (!(io_stat & SS$_NORMAL) ? io_stat : out_iosb.status); }