/*------------------------------------------------------------------*/ /* SYSPA: This program massages the data returned from the Aid */ /* Spelling API in order to make it possible to process for our */ /* purposes. A complication from the API is that it doesn't tell */ /* you directly which dictionaries contributed to the list of */ /* candidate alternative-spelling words. You must run through */ /* the word list to see if any word entry refers to a given */ /* dictionary on the output dictionary list. */ /* */ /* We also create a reformatted list that gets returned to our */ /* caller in place of the list from the API. */ /* */ /* Each dictionary that has words returned will cause a "segment" */ /* to be created. The dictionary number begins the segment and */ /* points to a dictionary name in the dictionary list. This is */ /* followed by a count of the words in this segment. Then, each */ /* word is placed, one immediately after the other, with each */ /* preceded by its length. The WrdCnt tells how many lengths and */ /* words are in the segment before the next dictionary number. */ /* */ /* Format (pseudo-COBOL): */ /* */ /* 01 DCT_RTN_CT PIC 9(8) COMP-4 */ /* */ /* 01 CW_LST. */ /* 05 DictionarySegment OCCURS DCT_RTN_CT TIMES. */ /* 10 DCT_CTR PIC 9(8) COMP-4. */ /* 10 CD_WRD_CNT PIC 9(8) COMP-4. */ /* 10 SegmentWords OCCURS CD_WRD_CNT TIMES. */ /* 15 CW_LEN PIC 9(8) COMP-4. */ /* 15 Word PIC X(CW_LEN). */ /* */ /* By referring to the DCT_RTN_CT, we know how many segments to */ /* process when we return to the caller. By extracting each */ /* DCT_CTR, we know which dictionary name to display. */ /*------------------------------------------------------------------*/ SYSPA: PGM PARM(&P_WORD &FORMAT &SPLCHK &DCT_RTN_CT + &O_DCT_LST &NBR_RTN &CW_LST) DCL VAR(&P_WORD) TYPE(*CHAR) LEN(35) DCL VAR(&FORMAT) TYPE(*CHAR) LEN(10) DCL VAR(&SPLCHK) TYPE(*CHAR) LEN(1) DCL VAR(&DCT_RTN_CT) TYPE(*DEC) LEN(1) DCL VAR(&O_DCT_LST) TYPE(*CHAR) LEN(160) DCL VAR(&NBR_RTN) TYPE(*DEC) LEN(5 0) DCL VAR(&CW_LST) TYPE(*CHAR) LEN(3000) /*------------------------------------------------------------------*/ DCL VAR(&USER) TYPE(*CHAR) LEN(10) DCL VAR(&@NO) TYPE(*LGL) LEN(1) VALUE('0') DCL VAR(&SPADCT) TYPE(*LGL) LEN(1) VALUE('1') DCL VAR(&P_WORD_LEN) TYPE(*DEC) LEN(3) /*------ ------*/ /* */ /* Spelling Aid API command parameters... */ /* */ DCL VAR(&RTN_RESULT) TYPE(*CHAR) LEN(4000) DCL VAR(&RTN_LEN) TYPE(*CHAR) LEN(4) + VALUE(X'00000FA0') /* Length is 4000 + (X'270F' w/b 9999)... */ DCL VAR(&WORD) TYPE(*CHAR) LEN(32) DCL VAR(&WORD_LEN) TYPE(*CHAR) LEN(4) + VALUE(X'00000000') /* Begins w/zero; SST + fills in actual LEN... */ DCL VAR(&I_DCT) TYPE(*CHAR) LEN(172) DCL VAR(&I_DCT_LEN) TYPE(*CHAR) LEN(4) + VALUE(X'000000AC') /* Length is 172... */ DCL VAR(&O_DCT) TYPE(*CHAR) LEN(168) DCL VAR(&O_DCT_LEN) TYPE(*CHAR) LEN(4) + VALUE(X'000000A8') /* Length is 168... */ DCL VAR(&ERRCODE) TYPE(*CHAR) LEN(4) + VALUE(X'00000000') /*------ ------*/ /* Used to build the input dictionaries list... */ DCL VAR(&ID_OS) TYPE(*CHAR) LEN(4) + VALUE(X'0000000C') /* Length is 12... */ DCL VAR(&IDENTRIES) TYPE(*CHAR) LEN(4) + VALUE(X'00000004') /* Count is 4... */ DCL VAR(&IDRESERVED) TYPE(*CHAR) LEN(4) + VALUE(X'00000000') DCL VAR(&IDLIST) TYPE(*CHAR) LEN(160) + VALUE('US QDCT UK + QDCT LEGAL QDCT MEDICAL + QDCT') /*------ ------*/ /* Used for 1-byte to 2-byte binary conversions... */ DCL VAR(&MSP_C) TYPE(*CHAR) LEN(2) VALUE(X'0000') /* Will be non-zero where missplellings were found... */ DCL VAR(&MISSPELLED) TYPE(*DEC) LEN(3) VALUE(0) /* Count of dictionaries that alternate spellings were found in... */ DCL VAR(&DCT_CT) TYPE(*DEC) LEN(1) /* Counter for how many dictionaries sent words back... */ DCL VAR(&DCT_CTR) TYPE(*DEC) LEN(1) /* A single Word Information Entry and some WIE attributes... */ DCL VAR(&WIE) TYPE(*CHAR) LEN(16) DCL VAR(&WIE_LEN) TYPE(*DEC) LEN(5) DCL VAR(&WIE_ADDR) TYPE(*DEC) LEN(5) /* Current Word ctr, address and length... */ DCL VAR(&CW_CTR) TYPE(*DEC) LEN(5) DCL VAR(&CW_ADDR) TYPE(*DEC) LEN(5) DCL VAR(&CW_LEN) TYPE(*DEC) LEN(3) DCL VAR(&CW_LST_LEN) TYPE(*DEC) LEN(5) DCL VAR(&CW_LST_ADR) TYPE(*DEC) LEN(5) DCL VAR(&CD_WRD_CNT) TYPE(*DEC) LEN(5) DCL VAR(&CW_WC_ADDR) TYPE(*DEC) LEN(5) DCL VAR(&RESULT) TYPE(*CHAR) LEN(9) + VALUE('incorrect') /*------------------------------------------------------------------*/ /* */ /* Check this user for a personal *spadct... */ /* */ RTVUSRPRF RTNUSRPRF(&USER) CHKOBJ OBJ(*LIBL/&USER) OBJTYPE(*SPADCT) MONMSG MSGID(CPF9801) EXEC(CHGVAR VAR(&SPADCT) + VALUE(&@NO)) /* Add the personal *spadct to the list if one exists... */ IF COND(&SPADCT) THEN(DO) CHGVAR VAR(&IDENTRIES) VALUE(X'00000005') /* New + count is 5... */ CHGVAR VAR(%SST(&IDLIST 81 20)) VALUE(&USER *CAT + '*LIBL') ENDDO /*------------------------------------------------------------------*/ /* Build the list of input dictionaries... */ CHGVAR VAR(&I_DCT) VALUE(&ID_OS *CAT &IDENTRIES + *CAT &IDRESERVED *CAT &IDLIST) /*------------------------------------------------------------------*/ /* */ /* We need to tell the API how long the word is. We take length */ /* from the command parameter length attribute in bytes 2 & 3. */ /* But note that the API requires bin(4), so we append our two */ /* bytes onto two bytes of X'00'. */ /* */ /* Get the length... */ CHGVAR VAR(&P_WORD_LEN) VALUE(%BIN(&P_WORD 2 2)) /* Get the word... */ CHGVAR VAR(&WORD) VALUE(%SST(&P_WORD 4 &P_WORD_LEN)) /* Append the two bytes... */ CHGVAR VAR(%SST(&WORD_LEN 3 2)) VALUE(%SST(&P_WORD + 2 2)) /*------------------------------------------------------------------*/ /* */ /* The Aid Spelling API... */ /* */ CALL PGM(QTWAIDSP) PARM(&RTN_RESULT &RTN_LEN + &FORMAT &WORD &WORD_LEN &I_DCT &I_DCT_LEN + &O_DCT &O_DCT_LEN &ERRCODE) MONMSG MSGID(CPF8757) EXEC(SNDPGMMSG MSGID(CPF9898) + MSGF(QCPFMSG) MSGDTA('Word (''' *CAT + &WORD *TCAT ''') is not valid for this + function') MSGTYPE(*ESCAPE)) /*------------------------------------------------------------------*/ CHGVAR VAR(&NBR_RTN) VALUE(%BIN(&RTN_RESULT 9 4)) CHGVAR VAR(&O_DCT_LST) VALUE(%SST(&O_DCT 9 160)) CHGVAR VAR(&DCT_RTN_CT) VALUE(%BIN(&O_DCT 1 4)) /* Get misspelling indicator in *char and *dec forms... */ CHGVAR VAR(%SST(&MSP_C 2 1)) VALUE(%SST(&RTN_RESULT + 25 1)) CHGVAR VAR(&MISSPELLED) VALUE(%BIN(&MSP_C)) CHGVAR VAR(&SPLCHK) VALUE(&MISSPELLED) IF COND(&MISSPELLED = 0) THEN(CHGVAR + VAR(&RESULT) VALUE('correct')) /*------------------------------------------------------------------*/ /* Initialize work fields... */ CHGVAR VAR(&CW_LST) VALUE(' ') CHGVAR VAR(&CW_LST_ADR) VALUE(1) CHGVAR VAR(&DCT_CT) VALUE(0) CHGVAR VAR(&DCT_CTR) VALUE(1) CHGVAR VAR(&WIE_LEN) VALUE(%BIN(&RTN_RESULT 33 4)) /*------ DICT_LOOP ------*/ /* The API does not tell us how many of the returned dictionaries */ /* had alternate spellings; it only tells how many dictionaries */ /* were actually searched. (This may differ from the count of */ /* input dictionaries because one of those input might not exist */ /* or might not be accessible for this user.) We have to run */ /* through the returned word list, checking each WIE for a match */ /* against each dictionary number to see if a given dictionary */ /* contributed any words at all and how many it contributed. */ /* Process the returned word list for each dictionary... */ DICT_LOOP: CHGVAR VAR(&WIE_ADDR) VALUE(%BIN(&RTN_RESULT 29 4) + + 1) CHGVAR VAR(&CW_CTR) VALUE(1) CHGVAR VAR(&CD_WRD_CNT) VALUE(0) /* Put the current DCT_CTR at the beginning of this segment of the */ /* list we'll return to our caller... */ CHGVAR VAR(%BIN(&CW_LST &CW_LST_ADR 4)) + VALUE(&DCT_CTR) /* Leave an extra 4 bytes for CD_WRD_CNT... */ /* ...but remember where our word-count should go... */ CHGVAR VAR(&CW_WC_ADDR) VALUE(&CW_LST_ADR + 4) CHGVAR VAR(&CW_LST_ADR) VALUE(&CW_LST_ADR + 8) /*------ WORD_LOOP ------*/ /* Extract each WIE... */ WORD_LOOP: CHGVAR VAR(&WIE) VALUE(%SST(&RTN_RESULT &WIE_ADDR + &WIE_LEN)) /* See if this WIE is related to the dictionary we're on now... */ IF COND(%BIN(&WIE 9 4) *EQ &DCT_CTR) THEN(DO) /* Get this WIE's word address and length... */ CHGVAR VAR(&CW_ADDR) VALUE(%BIN(&WIE 1 4) + 1) CHGVAR VAR(&CW_LEN) VALUE(%BIN(&WIE 5 4)) /* We'll store the 4-byte length plus the word. We add 4 plus the */ /* word length to know how many total characters to store... */ CHGVAR VAR(&CW_LST_LEN) VALUE(4 + &CW_LEN) /* We store the length of the alternate word plus the alternate */ /* word itself in the list we're building to send to the caller...*/ CHGVAR VAR(%SST(&CW_LST &CW_LST_ADR &CW_LST_LEN)) + VALUE(%SST(&WIE 5 4) *CAT + %SST(&RTN_RESULT &CW_ADDR &CW_LEN)) /* Move our pointer as far as the length of what we stored... */ CHGVAR VAR(&CW_LST_ADR) VALUE(&CW_LST_ADR + + &CW_LST_LEN) /* Count this candidate word from this dictionary... */ CHGVAR VAR(&CD_WRD_CNT) VALUE(&CD_WRD_CNT + 1) ENDDO /* Count this word so we know how far we've gone down the list... */ CHGVAR VAR(&CW_CTR) VALUE(&CW_CTR + 1) /* See if we're still within the returned word list... */ /* If we are, then we need to go back to try the next WIE... */ IF COND(&CW_CTR *LE &NBR_RTN) THEN(DO) /* Point to the next WIE... */ CHGVAR VAR(&WIE_ADDR) VALUE(&WIE_ADDR + &WIE_LEN) GOTO CMDLBL(WORD_LOOP) ENDDO /*------ WORD_LOOP ------*/ /* When we pass the end of the returned word list, we need to see */ /* if this run-through found any matches against the current */ /* dictionary. If it did, then we'll count this dictionary and */ /* stash its word count in the list we're returning to our caller.*/ /* Count a "successful" dictionary, i.e., one that had words... */ IF COND(&CD_WRD_CNT *NE 0) THEN(CHGVAR + VAR(&DCT_CT) VALUE(&DCT_CT + 1)) /* Stash our word_count from this just-finished dictionary... */ CHGVAR VAR(%BIN(&CW_LST &CW_WC_ADDR 4)) + VALUE(&CD_WRD_CNT) /* Bump our dictionary counter... */ CHGVAR VAR(&DCT_CTR) VALUE(&DCT_CTR + 1) /* See if we're still within the list of output dictionaries. If */ /* we are, then we'll go back to run through the returned word */ /* list again for the next dictionary... */ IF COND(&DCT_CTR *LE &DCT_RTN_CT) THEN(GOTO + CMDLBL(DICT_LOOP)) /*------ DICT_LOOP ------*/ /* Otherwise we're simply going to fall through and get out... */ /*------------------------------------------------------------------*/ /* Main exit for this application... */ /*------------------------------------------------------------------*/ /* */ /* Stash the number of dictionaries words were returned from and */ /* return with a message about correct/incorrect spelling... */ MAIN_EXIT: CHGVAR VAR(&DCT_RTN_CT) VALUE(&DCT_CT) SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) + MSGDTA('Spelling is:' *BCAT &RESULT) + MSGTYPE(*COMP) RETURN ENDPGM