/* @(#)prepf.c 17.1.1.2 (ESO-DMD) 02/25/02 17:53:05 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. Correspondence concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /*++++++++++++++++++++ MIDAS monitor routines PREPF +++++++++++++++++++++++++++ .LANGUAGE C .IDENTIFICATION Module PREPF .AUTHOR K. Banse ESO - Garching .KEYWORDS MIDAS command data structures .COMMENTS holds INITCOM, EXTRACOM, FINDCOM, ADDCOM, MINMATCH, DELCOM, cut_links, SETDFF, CLEANCOM, PACKCOM, MODOFF, DEFCOM, SHOWCOM, spitout .VERSION [1.00] 871030: debugging ... 020212 last modif ----------------------------------------------------------------------------*/ #include #include #include #include #include #include static struct COMND_STRUCT *compntr, *cnext; static struct QUALIF_STRUCT *qualpntr, *qnext, *qlast; /* */ /* *** *** */ /* here the section for command completion in Midas */ /* *** *** */ #ifndef NO_READLINE struct COMMAND { char name[12]; /* User printable name of the function */ struct COMMAND *prev; }; struct CMD_LIST { struct COMMAND *curr; struct COMMAND *last; }; struct CMD_LIST cmds = { (struct COMMAND *)NULL, (struct COMMAND *)NULL }; void free_cmd_list() /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Free the memory allocated for the Command/Qualifier list. Also executed with the BYE command. .RETURNS nothing -----------------------------------------------------------------*/ { struct COMMAND *mycmd; while ((mycmd = cmds.last)) { cmds.last = mycmd->prev; free((char *)mycmd); } } void update_cmd_list() /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Update the Command/Qualifier list used for completeness with GNU readline .RETURNS nothing -----------------------------------------------------------------*/ { int list_cmd; register int m, n; struct COMND_STRUCT *compntr; struct QUALIF_STRUCT *qualpntr; struct COMMAND *mycmd; MONIT.CMD_LIST_UPDA = 0; /* reset the flag */ free_cmd_list(); /* Free previous list */ /* Initialize static list of commands */ compntr = COMN.CP; qualpntr = COMN.QP + compntr->INDX; list_cmd = 0; while (list_cmd <= COMN.INUSEC) { if (compntr->STR[0] != '\\') { while (1) { mycmd = (struct COMMAND *)malloc(sizeof(struct COMMAND)); mycmd->prev = cmds.last; cmds.last = mycmd; (void) memcpy(mycmd->name,compntr->STR,(size_t)6); if (qualpntr->STR[0] != ' ') { m = 6; /* get rid of trailing blanks */ for (n=5; n>0; n--) { if (mycmd->name[n] != ' ') { m = n+1; goto done; } } done: mycmd->name[m++] = '/'; (void) memcpy(&mycmd->name[m],qualpntr->STR,(size_t)4); mycmd->name[11] = '\0'; } else mycmd->name[6] = '\0'; if (qualpntr->NEXT == -1) break; qualpntr = COMN.QP + qualpntr->NEXT; } } list_cmd++; compntr++; qualpntr = COMN.QP + compntr->INDX; } cmds.curr = cmds.last; } #endif /* */ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE read in the binary file newcom.bin which contains all fixed MIDAS commands and qualifiers .ALGORITHM use FSY_OPNFIL to read the file .RETURNS status (0 = o.k., 1 = bad) ------------------------------------------------------------------*/ int INITCOM() { int mm, nn, stat; int totsize, comsize, qualsize; int cmax, qmax, lmax; unsigned int linesize; char *cpntr, *tmpntr; char *osmsg(); int fp; static int initflag = -1; static char file[] = "MID_MONIT:newcom.bin"; static char record[200]; /* if initflag != -1, we clean up virtual memory from last call */ if (++initflag > 0) { free((char *)COMN.CP); free((char *)COMN.QP); free(COMN.LINE); } /* open + read the command/qualif stuff from binary file newcom.bin */ CGN_LOGNAM(file,record,200); /* translate name */ fp = osdopen(record,READ); if (fp == -1) { (void) printf("Problems with initial command file %s - %s\n", record,osmsg()); return(1); } /* and read it to get the sizes of the following structures */ cpntr = (char *) &COMN; totsize = sizeof(struct COMND_ALL); stat = osdread(fp,cpntr,(unsigned int)totsize); if (stat < totsize) goto osd_error; /* save the original sizes from file (needed for reading correct amounts) */ cmax = COMN.CMAX; qmax = COMN.QMAX; lmax = COMN.ENDLIN; /* if comcnt > original command count, we update the sizes of the command/qualifier structures */ mm = KIWORDS[OFF_MONPAR]; nn = KIWORDS[OFF_MONPAR+1]; if ( (mm > cmax) || (nn > qmax) ) { COMN.CMAX = mm; COMN.QMAX = nn; COMN.ENDLIN = 10 * COMN.QMAX; /* must be synchronized with newcom.exe */ } /* now we can allocate the rest */ /* comsize, qualsize + linesize must be computed just like in newcom.c !! */ comsize = (sizeof(struct COMND_STRUCT)) * (COMN.CMAX+1); /* for security */ tmpntr = malloc((unsigned int)comsize); if (tmpntr == NULL) { printf("could not allocate %d bytes for COMND_STRUCT\n",comsize); ospexit(0); } COMN.CP = (struct COMND_STRUCT *) tmpntr; qualsize = (sizeof(struct QUALIF_STRUCT)) * (COMN.QMAX+1); tmpntr = malloc((unsigned int)qualsize); if (tmpntr == NULL) { (void) printf("could not allocate %d bytes for QUALIF_STRUCT\n",qualsize); ospexit(1); } COMN.QP = (struct QUALIF_STRUCT *) tmpntr; linesize = (unsigned int) (COMN.ENDLIN + 4); COMN.LINE = malloc(linesize); if (COMN.LINE == NULL) { (void) printf("could not allocate %d bytes for COMLINE\n", (int)linesize); ospexit(1); } /* O.K. now we read the stuff (in original size) */ comsize = (sizeof(struct COMND_STRUCT)) * (cmax+1); cpntr = (char *) COMN.CP; stat = osdread(fp,cpntr,(unsigned int)comsize); if (stat != comsize) goto osd_error; qualsize = (sizeof(struct QUALIF_STRUCT)) * (qmax+1); cpntr = (char *) COMN.QP; stat = osdread(fp,cpntr,(unsigned int)qualsize); if (stat != qualsize) goto osd_error; linesize = (unsigned int) (lmax + 4); stat = osdread(fp,COMN.LINE,linesize); if (stat != (int)linesize) goto osd_error; /* close file again + set offset as needed for context level = 0 */ osdclose(fp); #ifndef NO_READLINE if (MONIT.CMD_LIST_UPDA == 1) update_cmd_list(); #endif return(0); osd_error: (void) printf("Problems in reading from binary command file - %s\n",osmsg()); ospexit(1); return 0; /* just for the compiler... */ } /* */ void EXTRACOM(input,comnd,qualif) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE split input string of form command/qualifier into command + qualifier .ALGORITHM split up command + qualifier and convert to upper case .RETURNS nothing ------------------------------------------------------------------*/ char *input /* IN: input string */; char *comnd /* OUT: isolated command (6 char) */; char *qualif /* OUT: isolated qualifier (4 char) */; { int qoff; register int nr, mr; static int cdif = 'A' - 'a'; register char cc; cc = input[0]; if ((cc == '/') || (cc == '\0')) { comnd[0] = '\0'; /* bad command ... */ return; } if ((cc >= 'a') && (cc <= 'z')) cc += cdif; comnd[0] = cc; qualif[0] = qualif[1] = qualif[2] = qualif[3] = ' '; for (nr=1; nr<6; nr++) /* pull out command */ { cc = input[nr]; if (cc == '\0') { /* command without qualifier */ for (mr=nr; mr<6; mr++) comnd[mr] = ' '; return; } if (cc == '/') { /* we have a qualifier */ for (mr=nr; mr<6; mr++) comnd[mr] = ' '; qoff = nr + 1; goto qualif_stuff; } if ((cc >= 'a') && (cc <= 'z')) cc += cdif; /* move to upper case */ comnd[nr] = cc; } for (nr=6; ;nr++) /* skip over rest of command */ { cc = input[nr]; if (cc == '\0') return; if (cc == '/') { qoff = nr + 1; goto qualif_stuff; } } qualif_stuff: mr = 0; for (nr=qoff; nr= 'a') && (cc <= 'z')) cc += cdif; /* move to upper case */ qualif[mr++] = cc; } } /* */ int FINDCOM(comnd,qualif,defqual,defset,ctxno,line,linelen) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE search for a given command / qualifier .ALGORITHM compare only the no. of characters actually input - check also for ambiguities if found, store full command + qualifier into input pars also return pointer to connected command_line .RETURNS int stat : return status, = 0 if exact command/qualifier found = 1 if wild card command/qualifier found = 2, if command not found = 3, if qualifier not found = 8, if command ambiguous = 9, if qualifier ambiguous -----------------------------------------------------------------------*/ char *comnd /* IO: input/full command */; char *qualif /* IO: input/full qualifier */; char *defqual /* OUT: default qualifier of command found */; int *defset /* OUT: Defaults_defined_flag, 0 or 1 */; int *ctxno /* OUT: context no if >= 0, \ if < 0 it's the index for primitive commands */; char **line /* OUT: pointer to command_line */; int *linelen /* OUT: length of command_line in bytes */; { int nroff, wild_indx, clen, qlen, retval; int foundc, foundq; register int nr, mr; register char *cptr; clen = 6; qlen = 4; /* get `length' of command + qualifier */ for (nr=0; nr<6; nr++) { if (comnd[nr] == ' ') { clen = nr; break; } } for (nr=0; nr<4; nr++) { if (qualif[nr] == ' ') { if (nr != 0) qlen = nr; break; } } /* search commands first */ foundc = -1; nroff = 0; retval = -1; /* flag is set, when qualifier found */ compntr = COMN.CP; cloop: for (nr=nroff; nr <= COMN.INUSEC; nr++) { cptr = compntr->STR; for (mr=0; mrINDX; while (nr != -1) { qualpntr = COMN.QP + nr; if (qualpntr->STR[0] == ' ') { foundq = nr; goto after_qloop; } nr = qualpntr->NEXT; /* follow to next qualifier */ } (void)memcpy(qualif,compntr->QDEF,(size_t)4); /* use default qualifier */ } /* main loop over qualifiers */ foundq = -1; /* reset found indicator */ wild_indx = -1; nr = compntr->INDX; while (nr != -1) { qualpntr = COMN.QP + nr; if ( (qualpntr->STR[0] == '.') && (qualpntr->STR[1] == '.') && (qualpntr->STR[2] == '.') ) /* test, if "wild card" qualifier */ wild_indx = nr; else { cptr = qualpntr->STR; for (mr=0; mrNEXT; /* follow to next qualifier */ } after_qloop: if (foundq != -1) { if (retval != -1) return (8); /* we had a match before */ retval = 0; qnext = COMN.QP + foundq; } else /* no match with any qualifier */ { if (wild_indx == -1) /* also no wild_card match */ { if (clen < 6) { compntr ++; /* follow with pointer */ goto cloop; /* check the other commands */ } else return (3); } if (retval != -1) return (8); /* we had a match before */ retval = 1; qnext = COMN.QP + wild_indx; /* wild card qualifier... */ if (clen >= 6) /* if "full" command, we're done */ { cnext = compntr; /* use input qualif + save comnd pointer */ goto com_found; } } cnext = compntr; /* qualifier o.k., so save comnd pointer */ if (clen < 6) { compntr ++; /* follow with pointer */ goto cloop; /* check the other commands */ } /* return command/qualifier type and actual command line */ qual_found: (void)memcpy(qualif,qnext->STR,(size_t)4); /* store full qualif. string */ com_found: (void)memcpy(comnd,cnext->STR,(size_t)6); /* store full command string */ (void)memcpy(defqual,cnext->QDEF,(size_t)4); /* store default qualifier */ *defset = qnext->DEFSET; nr = qnext->CTXNO; if (nr == -2) *ctxno = qnext->OFF; /* primitive command */ else { *line = COMN.LINE+qnext->OFF; *linelen = (int)strlen(*line); if (nr == -1) *ctxno = 99; /* fixed added commands */ else *ctxno = qnext->CTXNO; /* 0, 1, ..., MAX_CONTXT */ } return (retval); } /* */ int ADDCOM(comnd,qualif,type,lenoff,line) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE add a command / qualifier (and default qualifier) .ALGORITHM add new command or increment qualifier pointers, if command already exists, add new qualifier and default qualifier and actual command line (only, if same command line does not exist yet) .RETURNS int stat : return status = 0, if command/qualifier successfully added = 10, if command / qualifier already exists or would lead to ambiguity = 10, if new command / qualifier would be ambiguous = 42, if overflow in command table = 42, if overflow in qualifier table = 42, if overflow in actual command table = 5, if no command line at all = 42, if comnd def. line + lenoff > COMN.ENDLIN -----------------------------------------------------------------------*/ char *comnd /* IN: command string */; char *qualif /* IN: qualifier string */; int type /* IN: type of new command: \ = -2 for primitive commands \ = -1 for fixed added commands \ >= 0 for dynamic commands */; int lenoff /* IN: no. of spaces to add to end of command string */; char *line /* IN: actual command line, terminated by \0 */; { int mm, k, next, linelen, nsav; int foundc, foundq; char mycomnd[8], myqualif[8]; char *cpntra, *cpntr; register int nr; if ((COMN.INUSEQ == COMN.QMAX) || /* at the top end, try to pack first */ (COMN.INUSEC == COMN.CMAX)) { k = PACKCOM(); if (k != 0) return (42); } if (type > -2) /* get length of command definition */ { linelen = (int)strlen(line); for (nr=linelen-1; nr>0; nr--) if (line[nr] != ' ') break; /* get rid of trailing blanks */ linelen = nr + 1; mm = lenoff + linelen + 1; /* get length of comnd_str (incl. '\0') */ if ( (COMN.FIRST + mm) > COMN.ENDLIN) { k = PACKCOM(); if (k != 0) return (42); } cpntr = COMN.LINE + COMN.FIRST; /* there is enough space, so we use */ (void) memcpy(cpntr,line,(size_t)linelen); /* COMN.LINE now as working buffer */ cpntra = cpntr + linelen; if (lenoff == 1) *cpntra++ = ' '; *cpntra = '\0'; /* terminate it */ next = mm + COMN.FIRST; /* point already to next free index */ COMN.STRL = mm; /* save that length */ } /* check, if command already exists (is permitted) */ compntr = COMN.CP; /* initialize pointers */ qualpntr = COMN.QP; for (foundc=0; foundc <= COMN.INUSEC; foundc++) { k = MINMATCH(comnd,compntr->STR,6); if (k == 2) return (10); /* new command would be ambiguous... */ else if (k == 1) goto cmnd_exist; /* new command exists already */ compntr ++; } /* add new command + qualifier */ if ((COMN.INUSEQ == COMN.QMAX) || (COMN.INUSEC == COMN.CMAX)) return (42); foundc = ++ COMN.INUSEC; /* increment COMN.INUSEC first */ foundq = ++ COMN.INUSEQ; compntr = COMN.CP + foundc; qualpntr = COMN.QP + foundq; (void)memcpy(compntr->STR,comnd,(size_t)6); (void)memcpy(compntr->QDEF,qualif,(size_t)4); compntr->INDX = (short int) foundq; (void)memcpy(qualpntr->STR,qualif,(size_t)4); qualpntr->LAST = (short int) (-(foundc + 1)); /* will be the 1. qualifer */ qualpntr->NEXT = -1; /* indicate that here is the end */ goto sect_2500; /* continue like the others... */ /* command already exists - now check qualifier */ cmnd_exist: foundq = compntr->INDX; while (foundq != -1) { qualpntr = COMN.QP + foundq; k = MINMATCH(qualif,qualpntr->STR,4); if (k == 2) return (10); /* new command would be ambiguous */ else if (k == 1) { if (KEYALL.ORIGIN != -1) { if (KIWORDS[OFF_ERROR+1] < 2) /* for non-experts */ return (10); /* that's an error... */ } nr = qualpntr->OFF; k = COMUSED(nr); /* see, if other comnd is accessing this string */ if (k == -1) { *(COMN.LINE+nr) = '\\'; /* undo corresp. comnd line */ if (nr < COMN.FDEL) COMN.FDEL = nr; /* update first_deleted_indx */ } (void)printf("existing command overwritten...\n"); goto sect_2500; /* just modify command line */ } foundq = qualpntr->NEXT; /* chain to next entry */ } if (COMN.INUSEQ == COMN.QMAX) return (42); foundq = ++ COMN.INUSEQ; qualpntr = COMN.QP + foundq; (void)memcpy(qualpntr->STR,qualif,(size_t)4); /* now link qualifier in */ nr = compntr->INDX; while (nr != -1) { nsav = nr; qualpntr = COMN.QP + nr; nr = qualpntr->NEXT; } qualpntr = COMN.QP + nsav; qualpntr->NEXT = (short int) foundq; /* link forward + backward */ qualpntr = COMN.QP + foundq; qualpntr->LAST = (short int) nsav; qualpntr->NEXT = -1; /* indicate that here is the end */ /* add command line and update QP.OFF */ sect_2500: qualpntr->CTXNO = (short int) type; /* save context no. */ if (type == -2) /* primitive command */ { nsav = -( COMN.INUSEQ + 1); /* put into [-1,-...] */ goto final_step; } /* check, if command line already in command buffer */ for (nr=0; nrOFF = (short int) nsav; qualpntr->DEFSET = 0; /* initially set to 0 */ #ifndef NO_READLINE MONIT.CMD_LIST_UPDA = 1; /* mark for action ... */ #endif return (0); } /* */ int MINMATCH(stra,strb,maxlen) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE compare two strings and consider minimum_match problems .ALGORITHM usual comparison but blanks are considered like wild cards .RETURNS 0, if strings are different 1, if strings are completely equal 2, if strings are ambiguous, i.e. are equal until the first blank -----------------------------------------------------------------*/ char *stra /* IN: 1. input string (not terminated by \0) */; char *strb /* IN: 2. input string (not terminated by \0) */; int maxlen /* IN: max. length of strings */; { register int nr; register char ca, cb; for (nr=0; nrSTR,6) == 0) goto qualif_sect; compntr ++; } return (-1); /* command does not exist */ /* find qualifier */ qualif_sect: foundq = compntr->INDX; while (foundq != -1) { qualpntr = COMN.QP + foundq; if (strncmp(qualif,qualpntr->STR,4) == 0) goto remove_sect; foundq = qualpntr->NEXT; } return (-2); /* qualifier not found */ /* command/qualifier found: remove (command and) qualifier + actual command line */ remove_sect: if (qualpntr->CTXNO == -2) return (1); /* not a dynamically added command... */ /* everything o.k. (more or less...) */ cut_links(); /* remove qualifier (and command) */ /* if last qualifier and/or command decrement qual/com limits */ if (foundq == COMN.INUSEQ) COMN.INUSEQ -- ; if ((compntr->STR[0] == '\\') && (foundc == COMN.INUSEC)) COMN.INUSEC -- ; return (0); } /* */ int SETDFF(comnd,qualif,flag) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE toggle the Defaults_defined_flag for a command / qualifier .ALGORITHM find the entry + change COMN.Q[].DEFSET .RETURNS return status, = 0 if command/qualifier successfully updated = -1, if command does not exist = -2, if qualifier does not exist --------------------------------------------------------------*/ char *comnd /*IN: command string (not terminated by \0) */; char *qualif /*IN: qualifier string (not terminated by \0) */; int flag /*IN: 0 or 1 */; { int foundc, foundq; /* check, if command exists */ compntr = COMN.CP; for (foundc=0; foundc<=COMN.INUSEC; foundc++) { if (strncmp(comnd,compntr->STR,6) == 0) goto qualif_sect; compntr ++; } return (-1); /* command does not exist */ /* find qualifier */ qualif_sect: foundq = compntr->INDX; while (foundq != -1) { qualpntr = COMN.QP + foundq; if (strncmp(qualif,qualpntr->STR,4) == 0) { qualpntr->DEFSET = (short int) flag; /* toggle Defaults_defd_flag */ return (0); } foundq = qualpntr->NEXT; } return (-2); /* qualifier not found */ } /* */ int COMUSED(koff) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE search through all qualifiers to see if command string at COMN.LINE+nr is referenced .ALGORITHM loop through qualifs and check qualif->OFF .RETURNS index of qualifer, if string is referenced, -1 if not -----------------------------------------------------------------*/ int koff; { int mm; register int nr; qnext = COMN.QP; for (nr=0; nrOFF == koff) && (qnext->STR[0] != '\\')) { mm = nr; return(mm); /* com/qualif found */ } qnext ++; } /* nothing found */ return (-1); } /* */ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE remove a command/qualif combination from the data structure .ALGORITHM work on qualifs, command line + maybe command itself .RETURNS nothing -----------------------------------------------------------------*/ void cut_links() { int k, last, next, mm; qualpntr->STR[0] = '\\'; /* this pulls it out of the action */ next = qualpntr->NEXT; /* get qualifier after */ qnext = COMN.QP + next; last = qualpntr->LAST; /* get qualifier in front */ qlast = COMN.QP + last; if (last >= 0) { /* still a qualifier before us */ qlast->NEXT = (short int) next; if (next >= 0) qnext->LAST = (short int) last; } else { /* we are the first qualifier of this command */ if (next == -1) compntr->STR[0] = '\\'; else qnext->LAST = (short int) last; } mm = qualpntr->OFF; /* OFF is > 0 !! */ k = COMUSED(mm); if (k == -1) { if (mm < COMN.FDEL) COMN.FDEL = mm; /* update first_deleted_index */ k = COMN.FIRST - COMN.STRL; if ((COMN.FIRST-COMN.STRL) == mm) /* was that the last string? */ { int nr, ns; COMN.FIRST = k; nr = k; while(*(COMN.LINE+nr) != '\0') /* get 1. char. of command line */ nr -- ; ns = nr + 1; COMN.STRL = (int) strlen(COMN.LINE+ns) + 1; } else *(COMN.LINE+mm) = '\\'; } #ifndef NO_READLINE MONIT.CMD_LIST_UPDA = 1; /* mark for action ... */ #endif } /* */ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE delete all commands/qualifiers of a given context no. that is, delete all c/q's with COMN.Q[n].CTXNO = ctxno .ALGORITHM loop through COMN.Q.OFF to find a matching ctxno when found, work backwards to get corresponding command/qualifier combination and use function cut_links to remove that pair .RETURNS nothing ------------------------------------------------------------------*/ void CLEANCOM(ctxno) int ctxno /* IN: > 0, delete all com/qual with matching CTXNO \ = 0, delete all com/qual with CTXNO > 0 */; { register int nr, rq; qualpntr = COMN.QP + COMN.LPRIMQ + 1; for (nr=COMN.LPRIMQ+1; nr<=COMN.INUSEQ; nr++) { /* loop through array Q.OFF */ if (qualpntr->CTXNO > 0) /* from a context ? */ { if ((ctxno == 0) || (qualpntr->CTXNO == ctxno)) { rq = qualpntr->LAST; /* unravel backwards */ while (rq >= 0) { qlast = COMN.QP + rq; rq = qlast->LAST; } compntr = COMN.CP - (rq + 1); cut_links(); } } qualpntr ++; } (void) PACKCOM(); /* sqeeze everything together again */ } /* */ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE compress the command data base .ALGORITHM remove any deleted commands, qualifiers .RETURNS completion status = 0, o.k.we could clean up = 1, nothing we could do... -----------------------------------------------------------------*/ int PACKCOM() { int mm, k, np, nt, ns; register int nr; /* look for deleted command entries */ compntr = COMN.CP + COMN.LPRIMC; for (nr=COMN.LPRIMC; nr <= COMN.INUSEC; nr++) { if (compntr->STR[0] == '\\') goto its_ok; compntr ++; } qualpntr = COMN.QP + COMN.LPRIMQ; for (nr=COMN.LPRIMQ; nr <= COMN.INUSEQ; nr++) { if (qualpntr->STR[0] == '\\') goto its_ok; qualpntr ++; } return (1); /* nothing to do */ /* remove deleted command entries from the top */ its_ok: compntr = COMN.CP + COMN.INUSEC; while (compntr->STR[0] == '\\') { COMN.INUSEC --; compntr --; } /* now move from COMN.LPRIMC upward + copy last entry into any free entry */ mm = COMN.LPRIMC; comnd_loop: for (nr=mm+1; nr<=COMN.INUSEC; nr++) { compntr = COMN.CP + nr; if (compntr->STR[0] == '\\') /* look for free entry */ { nt = COMN.INUSEC; cnext = COMN.CP + nt; if (cnext->STR[0] != '\\') /* only copy "full" entries */ { (void)memcpy(compntr->STR,cnext->STR,(size_t)6); (void)memcpy(compntr->QDEF,cnext->QDEF,(size_t)4); np = cnext->INDX; /* we also have to modify the link */ qualpntr = COMN.QP + np; qualpntr->LAST = (short int) (-(nr+1)); /* to the qualifier */ compntr->INDX = (short int) np; } else nr -- ; mm = nr; /* this will be the new start */ COMN.INUSEC -- ; goto comnd_loop; } } /* remove deleted qualifier entries from the top */ qualpntr = COMN.QP + COMN.INUSEQ; while (qualpntr->STR[0] == '\\') { COMN.INUSEQ --; qualpntr --; } /* now move from COMN.LPRIMQ upward + copy last entry into any free entry */ mm = COMN.LPRIMQ; qualif_loop: for (nr=mm+1; nr<=COMN.INUSEQ; nr++) { qualpntr = COMN.QP + nr; if (qualpntr->STR[0] == '\\') /* look for free entry */ { nt = COMN.INUSEQ; qnext = COMN.QP + nt; if (qnext->STR[0] != '\\') /* only copy "full" entries... */ { (void)memcpy(qualpntr->STR,qnext->STR,(size_t)4); np = qnext->LAST; /* we also have to modify the links to the other commands */ qualpntr->LAST = (short int) np; qualpntr->NEXT = qnext->NEXT; qualpntr->DEFSET = qnext->DEFSET; qualpntr->CTXNO = qnext->CTXNO; qualpntr->OFF = qnext->OFF; if (np >= 0) /* either link with other qualifs */ { qlast = COMN.QP + np; qlast->NEXT = (short int) nr; } else /* or link back to commands */ { ns = -1 - np; /* index in commands structure */ cnext = COMN.CP + ns; cnext->INDX = (short int) nr; } np = qnext->NEXT; /* look for next qualifier */ if (np >= 0) /* and update link */ { qlast = COMN.QP + np; qlast->LAST = nr; } } else nr -- ; mm = nr; /* this will be the new start */ COMN.INUSEQ -- ; goto qualif_loop; } } /* first, try to remove deleted command lines from the top */ k = COMN.FIRST - 2; /* point to last char. before NULL */ line_loop_1: nr = k; while(*(COMN.LINE+nr) != '\0') /* get first char. of this command line */ nr -- ; ns = nr + 1; if (*(COMN.LINE+ns) == '\\') { k = ns - 2; /* point to last char of previous command line */ goto line_loop_1; } /* now move from COMN.FDEL upward and shift remainder into any free command line */ COMN.FIRST = k + 2; mm = COMN.FDEL; line_loop_2: for (nr=mm; nrOFF == off) qualpntr->OFF -= m; qualpntr ++; } } /* */ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE update default qualifier for all commands with given qualif or wild card (...) (comnd = *) or specific commnds (comnd = command name) .ALGORITHM if found, store default qualifier into COMN.C.QDEF .RETURNS nothing -----------------------------------------------------------------------*/ void DEFCOM(comnd,qualif) char *comnd /* IN: command string (not terminated by \0) or '*' */; char *qualif /* IN: qualifier string (not terminated by \0) */; { int found, kstrn; register int nr; if (qualif[0] == ' ') return; /* blank qualifier not allowed */ kstrn = 4; for (nr=0; nr<4; nr++) { if ((qualif[nr] == ' ') || (qualif[nr] == '\0')) { kstrn = nr; break; } } compntr = COMN.CP; if (*comnd == '*') { for (nr=0; nr<=COMN.INUSEC; nr++) { found = compntr->INDX; while (found != -1) /* loop through all connected qualifiers */ { qualpntr = COMN.QP + found; if ( (strncmp(qualif,qualpntr->STR,kstrn) == 0) || ( (qualpntr->STR[0] == '.') && (qualpntr->STR[1] == '.') && (qualpntr->STR[2] == '.') ) ) { (void)memcpy(compntr->QDEF,qualif,(size_t)4); break; } else found = qualpntr->NEXT; } compntr ++; } } else { for (nr=0; nr<=COMN.INUSEC; nr++) { found = MINMATCH(comnd,compntr->STR,6); if (found != 0) (void)memcpy(compntr->QDEF,qualif,(size_t)4); compntr ++; } } } /* */ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE show the data structures holding the commands + qualifiers .ALGORITHM straight forward - once you know the data structures... .RETURNS = 0, o.k. = -1, if `com/qualif' not found, i.e. only applicable to that case! ------------------------------------------------------------------*/ int SHOWCOM(fp,option,qualif) int fp /* IN: file identifier obtained from osaopen if = -1, output to terminal instead */; char *option /* IN: display option: = D for diagnostic (complete) display = ' ' for display of only the dynamically added commands = Q show all commands with given qualifer = A show all commands beginning with given string = 'com/qualif' for display of single command */; char *qualif /*IN: qualifier for option Q above */; { char com1[8], qual1[8], defqual[8], buf[20], *cpntr; char record[84]; int found, foundc, ffp, kstrn, mm, qlen, i, ii, nn; register int nr; /* diagnostic display of all tables */ if (option[0] == '-') { if ((option[1] == 'X') || (option[1] == 'x')) goto comn_only; (void)strcpy(record,"---------------------------"); spitout(fp,record); (void) sprintf(record,"C: STR QDEF INDX"); spitout(fp,record); (void)strcpy(record,"---------------------------"); spitout(fp,record); for (nr=0; nr <= COMN.INUSEC; nr++) { compntr = COMN.CP + nr; (void) sprintf(record,"%3.3d: %6.6s %4.4s %4d", nr,compntr->STR,compntr->QDEF,compntr->INDX); spitout(fp,record); } (void)strcpy(record,"---------------------------------------------"); spitout(fp,record); (void) sprintf(record,"Q: STR LAST NEXT OFF DEFSET CTXNO"); spitout(fp,record); (void)strcpy(record,"---------------------------------------------"); spitout(fp,record); for (nr=0; nr <= COMN.INUSEQ; nr++) { qualpntr = COMN.QP + nr; (void) sprintf(record,"%3.3d: %4.4s %4d %4d %4d %d %d", nr,qualpntr->STR,qualpntr->LAST,qualpntr->NEXT,qualpntr->OFF, qualpntr->DEFSET,qualpntr->CTXNO); spitout(fp,record); } (void)strcpy(record,"-----------------"); spitout(fp,record); (void) sprintf(record,"buffer COMN.LINE:"); spitout(fp,record); (void)strcpy(record,"-----------------"); spitout(fp,record); nr = 0; while(nr < COMN.FIRST) { (void) sprintf(record,"%4.4d: %s",nr,COMN.LINE+nr); spitout(fp,record); nr += (int)strlen(COMN.LINE+nr) + 1; } comn_only: (void) sprintf(record,"INUSEC: %d INUSEQ: %d ",COMN.INUSEC,COMN.INUSEQ); spitout(fp,record); (void) sprintf(record,"CMAX: %d QMAX: %d ENDLIN: %d", COMN.CMAX,COMN.QMAX,COMN.ENDLIN); spitout(fp,record); (void) sprintf(record,"FIRST: %d ",COMN.FIRST); spitout(fp,record); (void) sprintf(record,"LPRIMC: %d LPRIMQ: %d FDEL: %d", COMN.LPRIMC,COMN.LPRIMQ,COMN.FDEL); spitout(fp,record); return 0; } /* check, if single command option */ if (option[1] != ' ') { int retstat = 0; EXTRACOM(option,com1,qual1); i = FINDCOM(com1,qual1,defqual,&nn,&ii,&cpntr,&mm); if (i > 1) { retstat = -1; (void)strcpy(record,"given command/qualif not defined ..."); } else { if (i == 1) /* wild card match */ { (void)strcpy(buf,"... "); (void) memcpy(qual1,buf,(size_t)4); } com1[6] = '\0'; qual1[4] = '\0'; defqual[4] = '\0'; (void) sprintf(record, "%6.6s/%4.4s (def_qualif %4.4s ) defaults_flag: %d", com1,qual1,defqual,nn); if (ii < 0) { record[34] = '\0'; spitout(fp,record); (void)strcpy(record,"primitive command "); } else { spitout(fp,record); (void)strcpy(record,cpntr); } } spitout(fp,record); return retstat; } /* display of dynamically added commands */ if (option[0] == ' ') { qualpntr = COMN.QP + COMN.LPRIMQ + 1; for (nr=COMN.LPRIMQ+1; nr <= COMN.INUSEQ; nr++) { if ((qualpntr->CTXNO >= 0) && (qualpntr->STR[0] != '\\')) { nn = qualpntr->LAST; while (nn >= 0) { qnext = COMN.QP + nn; nn = qnext->LAST; } foundc = -1 - nn; mm = qualpntr->OFF; compntr = COMN.CP + foundc; (void) sprintf(record,"%6.6s/%4.4s (%d): %s", compntr->STR,qualpntr->STR,qualpntr->CTXNO,COMN.LINE+mm); spitout(fp,record); } qualpntr ++; } } /* display of all commands with given qualifier */ if ((option[0] == 'Q') || (option[0] == 'q')) { ffp = CGN_OPEN("MID_MONIT:wildcom.in",0); /* file wildcom.in needed for wildcard qualifiers */ found = 0; /* use as counter */ qlen = (int)strlen(qualif); if (qlen <= 4) { kstrn = qlen; if ((kstrn == 1) && (qualif[0] == '?')) { qualif[0] = '.'; /* default to wildcard qualifier */ qualif[1] = '.'; qualif[2] = '.'; qualif[3] = '\0'; kstrn = 3; } } else kstrn = 4; for (nr=0; nr <= COMN.INUSEQ; nr++) { qualpntr = COMN.QP + nr; if (strncmp(qualpntr->STR,qualif,kstrn) == 0) { /* if we found something get to the command */ nn = qualpntr->LAST; while (nn >= 0) { qnext = COMN.QP + nn; nn = qnext->LAST; } foundc = -1 - nn; compntr = COMN.CP + foundc; (void) sprintf(record,"%6.6s/%4.4s",compntr->STR,qualpntr->STR); spitout(fp,record); found ++; } else if ((qualpntr->STR[0] == '.') && (qualpntr->STR[1] == '.')) { /* if we found a wildcard qualifier */ nn = qualpntr->LAST; while (nn >= 0) { qnext = COMN.QP + nn; nn = qnext->LAST; } foundc = -1 - nn; compntr = COMN.CP + foundc; if (ffp != -1) /* see if it hides a match */ { read_wild: mm = osaread(ffp,buf,18); if (mm == -1) goto end_wild; if (strncmp(buf,compntr->STR,6) != 0) goto read_wild; i = 0; while (buf[i] != '/' ) i ++; /* move to '/' */ if (strncmp(&buf[i+1],qualif,kstrn) != 0) goto read_wild; (void) sprintf(record,"%6.6s/%4.4s",compntr->STR,&buf[i+1]); spitout(fp,record); found ++; end_wild: mm = osaseek(ffp,0L,FILE_START); /* rewind file */ } } } if (found == 0) { (void)strncpy(buf,qualif,kstrn); buf[kstrn] = '\0'; (void) sprintf(record,"no command found for given qualifier: %s",buf); spitout(fp,record); (void)strcpy(record, "but check also the commands with qualifier '...' (the `wildcard' qualifier)"); spitout(fp,record); (void)strcpy(record,"via the command HELP/QUAL ..."); spitout(fp,record); } if (ffp != -1) osaclose(ffp); } /* display of all commands begining with given char.string */ else if ((option[0] == 'A') || (option[0] == 'a')) { qlen = (int)strlen(qualif); if (qlen <= 6) kstrn = qlen; else kstrn = 6; i = 0; for (nr=0; nr <= COMN.INUSEC; nr++) { compntr = COMN.CP + nr; if (strncmp(compntr->STR,qualif,kstrn) == 0) { i = 1; (void) sprintf(record,"%6.6s",compntr->STR); spitout(fp,record); } } if (i == 0) { (void)strcpy(record,"no command found ..."); spitout(fp,record); } } return 0; } /* */ void spitout(tp,rbuf) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE write out record to file or terminal .ALGORITHM clear .RETURNS nothing -----------------------------------------------------------------*/ int tp /* IN: file pointer */; char *rbuf /* IN: data buffer */; { int mm, unit; register int nr; mm = (int)strlen(rbuf); if (tp >= 0) osawrite(tp,rbuf,mm); else { SCTPUT(rbuf); for (nr=mm; nr<80; nr++) rbuf[nr] = ' '; /* fill with blanks */ rbuf[80] = '\0'; SCKWRC("OUTPUTC",1,rbuf,1,80,&unit); /* save also in key OUTPUTC */ } }