C C *%%%%%* C *%%%%%%%%%%%* C *%%%%%/\|/\%%%%%* C *%%%%%%|--2--|%%%%%%* C Y C L O P S 2 ...... STAR data name checker C *%%%%%\/|\/%%%%%* C *%%%%%%%%%%%* Version 2.1.4 C *%%%%%* 12 May 1997 C C C C CYCLOPS2 is a fortran program for checking STAR data names against data C -------- name dictionaries written in DDL-STAR format proposed by Tony Cook C of ORAC Ltd., Leeds. Data names may be checked in any text file. C C CYCLOPS Version 2 C by C C Sydney R. Hall (syd@crystal.uwa.edu.au) C Crystallography Centre C University of Western Australia C Nedlands 6009, AUSTRALIA C C and C C Herbert J. Bernstein (yaya@bernstein-plus-sons.com) C Bernstein + Sons C 5 Brewster Lane C Bellport, NY 11713, U.S.A. C C Version 2 handles DDL1 and DDL2 dictionaries, and uses CIFtbx2 C C The latest program source and information is available from: C C Em: syd@crystal.uwa.edu.au ,-_|\ Sydney R. Hall C sendcif@crystal.uwa.edu.au / \ Crystallography Centre C Fx: +61 9 380 1118 --> *_,-._/ University of Western Australia C Ph: +61 9 380 2725 v Nedlands 6009, AUSTRALIA C C C CYCLOPS reads the text containing data names from the standard input device C (normally device 5). One or more STAR data name dictionaries (in DDL format) C are opened (normally from unit 1). A report on the data names is output to C the standard output device (normally device 6). Messages are output to the C standard error device (normally device 0). If an error is encountered in C attempting to write to the standard error device, further messages output C is diverted to the standard output device. C C NOTE: An attempt is made to open a file named "STARDICT" to use C either as a dictionary or from which to obtain a list of names C of dictionaries. If any dictionaries are specified on the command C line or by $CYCLOPS_CHECK_DICTIONARY, STARDICT is not examined. C C STARDICT may directly contain a dictionary as in version 1 of CYCLOPS, or C contain a list of file names of dictionaries, one per line. In that case C the list must begin with the line for which the first 5 characters are C "#DICT". The list of unreferenced data names is suppressed unless C the line "#VERBOSE" appears in STARDICT, or the command line argument C "-v yes" is used. Both the list of names used and the list of unreferenced C data are suppressed if the line #SHORT appears in STARDICT, or the command C line argument "-s yes" is used. C C C In a unix-like environment, the program is run as: C C cyclops [-i input_text] [-o validation_output] \ C [-d dictionary] [-p priority] \ C [-f command_file] [-v verbose] [-s short]\ C [[[input_text][[validation_output] [dictionary]]] C C where: C input_text defaults to $CYCLOPS_INPUT_TEXT or stdin C validation_output defaults to $CYCLOPS_VALIDATION_OUT or stdout C dictionary defaults to $CYCLOPS_CHECK_DICTIONARY C (multiple dictionaries may be specified) C input_text of "-" is stdin, validation_output of "-" is stdout C -p has values of first, final or nodup C (default first for first dictionary has priority) ', C -v has values of t or 1 or y vs. f or 0 or n (default f) C -s has values of t or 1 or y vs. f or 0 or n (default f) C C C .............................Installation notes............................. C C C CYCLOPS2 is provided as a part of the CIFtbx2 release kit, as the C file 'cyclops.f', 'cyclops.cmn' and README.cyclops. CIFtbx2 is C needed for the files ciftbx.f, ciftbx.sys, ciftbx.cmn and C hash_funcs.f. See the CIFtbx2 documentation for further information. C For non-unix-like environments, you will have to provide replacements C for iargc, getarg and getenv. The following are reasonable C possibilities: C C integer function iargc(dummy) C iargc=1 C return C end C C subroutine getarg(narg,string) C integer narg C character*(*) string C string=char(0) C if (narg.eq.1) string='-vn' C return C end C C subroutine getenv(evar,string) C character*(*) evar,string C string=char(0) C if(evar.eq."CYCLOPS_INPUT_TEXT") C * string='STARTEXT'//char(0) C if(evar.eq."CYCLOPS_VALIDATION_OUT") C * string='STARCHEK'//char(0) C if(evar.eq."CYCLOPS_CHECK_DICTIONARY") C * string=char(0) C return C end C C This combination of substitute routines would "wire-in" CYCLOPS2 to C read its input text from a file named STARTEXT, write the C validations output to a file named STARCHEK, and check names C against the default dictionary or file listing dictionaries C STARDICT C C Note that the PARAMETER 'MAXBUF' should contain the maximum number C of characters contained on a single text line. The default value is 200. C C C ..................................Files Used................................ C C dictionary input input on device 1 C Optionally a list of dictionaries, 1 per line after a #DICT line C validation output output on device 6 ('stdout') C Input text input on device 1, if a file, 5 if 'stdin' C Message device output on device 0 ('stderr') C may be diverted to the validation output file C Direct access in/out on device 3 C C*************************************************************************** C C **** PROGRAM CYCLOPS C include 'ciftbx.sys' include 'cyclops.cmn' C iundac = 3 iunerr = 0 iunout = 6 iuninp = 1 verbose=.false. short =.false. CASE=ICHAR('a')-ICHAR('A') XTAB=CHAR(05) IF(CASE.LT.0) GOTO 100 XTAB=CHAR(09) C VERS='2.1.4 (12 May 97)' WRITE(IUNERR, * '(/35H STAR data name checker ,A,/1X,59(1H-))' * ,ERR=40) VERS GO TO 50 40 IUNERR=IUNOUT C 50 call getfiles if (valout(1:lvalout) .ne.' ' .and. * valout(1:lvalout) .ne. '-') then OPEN(IUNOUT, * FILE=valout(1:lvalout),STATUS='UNKNOWN',FORM='FORMATTED') endif if (iunerr.eq.iunout) * WRITE(IUNERR, * '(/35H STAR data name checker ,A,/1X,59(1H-))') * VERS iuninp=5 if (inptext(1:linptext) .ne.' ' .and. * inptext(1:linptext) .ne. '-') then iuninp=1 OPEN(IUNINP, * FILE=inptext(1:linptext),STATUS='OLD',FORM='FORMATTED') endif C C 100 CONTINUE CALL CHEKDN CALL REPORT C END C C*************************************************************************** C CHEKDN checks the input text file on the standard input file for data C names and checks them against the stored dictionary names in dicnam(). C If it is not present the data name is added to the end of dicnam(). The C line numbers are added to NPOS(). XGETSTR supplies strings as the C variable 'stri' of length 'nchr'. NTYP=1 for a data name. C*************************************************************************** C SUBROUTINE CHEKDN integer lastnb include 'ciftbx.sys' include 'cyclops.cmn' INTEGER I,J,N,IL,IR C CHARACTER HEAD*14,TAIL*19,C*1,CBS*1 CHARACTER*20 XDICNAM(30) INTEGER NAMLEN(30),NNCHR DATA HEAD/' ,.:([{!;:/-=|" '/ DATA XDICNAM / * '_category ','_definition ', * '_dictionary_history ','_dictionary_name ', * '_dictionary_update ','_dictionary_version ', * '_enumeration ','_enumeration_default', * '_enumeration_detail ','_enumeration_range ', * '_example ','_example_detail ', * '_list ','_list_level ', * '_list_link_child ','_list_link_parent ', * '_list_mandatory ','_list_reference ', * '_list_uniqueness ','_name ', * '_related_item ','_related_function ', * '_type ','_type_conditions ', * '_type_construct ','_units ', * '_units_detail ',' ', * ' ',' '/ C DO I = 1,30 NAMLEN(I)=nblen(XDICNAM(I)) ENDDO C CBS='\\' HEAD(1:1)='''' HEAD(2:2)=CBS(1:1) HEAD(14:14)=XTAB TAIL(1:1)='''' TAIL(2:2)=CBS(1:1) TAIL(19:19)=XTAB MCNT=NDICT+1 LLINE=0 IEOF=0 MAXC=MAXBUF ICHR=MAXC STRI=' ' C 10 CALL XGETSTR IF(IEOF.NE.0) GOTO 200 I=1 J=NCHR IF(NTYP.EQ.1) GOTO 20 IF(NTYP.NE.4) GOTO 10 C -------------------------------------- look for data name in string IL=3 DO 15 I=1,NCHR IF(STRI(I:I).EQ.'_') GOTO 20 15 CONTINUE GOTO 10 C 20 IF(I.EQ.1) GOTO 22 IL=INDEX(HEAD,STRI(I-1:I-1)) IF(IL.GE.6.AND.IL.LE.8) THEN ILEV=1 DO J = I,NCHR IF(STRI(J:J).EQ.STRI(I-1:I-1)) ILEV=ILEV+1 IR=INDEX(TAIL,STRI(J:J)) IF (IR.EQ.IL) THEN ILEV=ILEV-1 IF(ILEV.EQ.0) THEN ICHR=ICHR-(NCHR-J)+1 NCHR=J GOTO 21 ENDIF ENDIF ENDDO ENDIF 21 IF(IL.EQ.0 .AND. STRI(I-1:I-1).NE.'*') GOTO 10 NNCHR=INDEX(STRI(I:NCHR),' ') IF(NNCHR.GT.0 .AND. NNCHR.LT.NCHR-I+1) THEN NCHR=NNCHR+I-1 ENDIF 22 DO 25 J=NCHR,I,-1 IR=INDEX(TAIL,STRI(J:J)) IF(IR.EQ.0. .OR. * (IR.EQ.7.AND.IR.NE.IL)) GO TO 30 25 CONTINUE J=I 30 IF(J.GT.I+1.AND.STRI(J-1:J).eq.CBS(1:1)//'n') THEN NCHR=J-2 GOTO 22 ENDIF NCHR=J-I+1 C -------------------------------------- identify mode of search 35 IF(NCHR.LT.2) GOTO 10 IF(NCHR.GT.NUMCHAR) * CALL CERR(0,'Data name in text is > NUMCHAR chars', * STRI(I:J)) NCHR = MIN(NUMCHAR,NCHR) XNAME=STRI(I:J) UNAME=XNAME DO 37 N=1,NCHR C=XNAME(N:N) IF(C.GE.'A'.AND.C.LE.'Z') XNAME(N:N)=CHAR(ICHAR(C)+CASE) 37 CONTINUE IF(STRI(J:J).EQ.'_') GOTO 50 IF(I.EQ.1) GOTO 40 IF(STRI(I-1:I-1).EQ.'*') GOTO 60 C --------------------------------------- search for full data name 40 call hash_find(XNAME,dicnam,dicchain,NUMDICT,ndict, * dichash,NUMHASH,I) IF (I.NE.0) GOTO 170 GOTO 100 C ---------------------------------------- search for group data name 50 DO 55 I=1,NDICT IF(XNAME(1:NCHR).EQ.dicnam(I)(1:NCHR)) GOTO 170 55 CONTINUE GOTO 100 C ---------------------------------------- search for end-part data name 60 DO 65 I=1,NDICT N=lastnb(dicnam(I)) IF(NCHR.GT.N) GOTO 65 IF(XNAME(1:NCHR).EQ.dicnam(I)(N-NCHR+1:N)) GOTO 170 65 CONTINUE C ---------------------------------------- new data name add to list 100 DO 120 I=1,30 IF(NAMLEN(I).NE.NCHR) GOTO 120 IF(XDICNAM(I).EQ.XNAME(1:20)) GOTO 10 120 CONTINUE J = NDICT+1 call hash_store(XNAME,dicnam,dicchain,NUMDICT,ndict, * dichash,NUMHASH,I) IF (I.EQ.0) * CALL CERR(1,'Data name table exceeded (Current max is NUMDICT)' * ,' ') IF (J.NE.I) GOTO 170 dictag(I) = UNAME DO 160 J=1,20 160 NPOS(NDICT,J)=0 I=NDICT C --------------------------------------- add line numbers to npos() 170 IF(NPOS(I,1).EQ.19) THEN DO J = 12,19 NPOS(I,J)=NPOS(I,J+1) ENDDO NPOS(I,12)=-NPOS(I,12) NPOS(I,1)=NPOS(I,1)-1 ENDIF NPOS(I,1)=NPOS(I,1)+1 N=NPOS(I,1) 180 NPOS(I,N+1)=LLINE GO TO 10 C 200 RETURN END C C*************************************************************************** C REPORT prints a summary of the line occurrences for each data name C in the dictionary and the text file itself (if it does not appear C in the dictionary). This summary is output as the file STARCHEK. C*************************************************************************** C SUBROUTINE REPORT integer lastnb include 'ciftbx.sys' include 'cyclops.cmn' INTEGER I,II,J,JJ,KK,MAXPAS,N,NNT,NT,NPASS CHARACTER*2 BREAK CHARACTER*4 RFLAG CHARACTER*4 DNUM INTEGER NUMCP7 PARAMETER (NUMCP7 = NUMCHAR+7) CHARACTER*(NUMCP7) NAMT C WRITE(IUNOUT, * '(//,20X,18HCYCLOPS Check List,/,20x,18(1H-),//)') WRITE(IUNOUT, * '(15X,25H Dictionary data names =,I5)') MCNT-1 WRITE(IUNOUT, * '(15X,25H New data names in text =,I5)') NDICT-MCNT+1 WRITE(IUNERR, * '(25H New data names in text =,I5)') NDICT-MCNT+1 NT=0 DO I = 1,KDICT IF (I.LT.10) THEN WRITE(DNUM,'(''['',I1,''] '')') I ELSE WRITE(DNUM,'(''['',I2,'']'')') I ENDIF WRITE(IUNERR, * '(1x,A,I5)')DNUM//' Dictionary '// * DICTNM(I)(1:MAX(1,LASTNB(DICTNM(I))))// * ' '// * DICTVR(I)(1:MAX(1,LASTNB(DICTVR(I))))// * ' data names = ', * MDICT(I)-NT IF(KDICT.GT.1) THEN WRITE(IUNOUT,'(16X,A,I5)')DNUM//' Dictionary '// * DICTNM(I)(1:MAX(1,LASTNB(DICTNM(I))))// * ' '// * DICTVR(I)(1:MAX(1,LASTNB(DICTVR(I))))// * ' data names = ', * MDICT(I)-NT ELSE WRITE(IUNOUT,'(16X,A,I5)')'Dictionary '// * DICTNM(I)(1:MAX(1,LASTNB(DICTNM(I))))// * ' '// * DICTVR(I)(1:MAX(1,LASTNB(DICTVR(I))))// * ' data names = ', * MDICT(I)-NT ENDIF NT=MDICT(I) ENDDO IF (NDICT.GT.MDICT(KDICT)) THEN WRITE(IUNOUT,'(//1X,28HData names NOT in Dictionary,25X, * 12HLine Numbers,/)') call ssort(DICNAM(MDICT(KDICT)+1), * NDICT-MDICT(KDICT),NUMCHAR,NORDER) DO KK=1,-MDICT(KDICT)+NDICT I=MDICT(KDICT)+NORDER(KK) N=NPOS(I,1) BREAK=" " NAMT = DICTAG(I) NNT = LASTNB(NAMT) DO II = 1,NUMCP7,2 IF(II.GE.NNT+3) NAMT(II:II)='.' ENDDO IF(NPOS(I,12).LT.0) BREAK=".." IF(N.LE.10) THEN IF(N.LE.4) THEN WRITE(IUNOUT,'(1X,A,4I6)') * NAMT, * (IABS(NPOS(I,J+1)),J=1,N) ELSE WRITE(IUNOUT,'(1X,A,4I6,/,44X,6I6)') * NAMT, * (IABS(NPOS(I,J+1)),J=1,N) ENDIF ELSE IF(N.LE.16) THEN WRITE(IUNOUT,'(1X,A,4I6,/,44X,6I6,/41X,A2,1X,6I6)') * NAMT,(IABS(NPOS(I,J+1)),J=1,10),BREAK, * (IABS(NPOS(I,J+1)),J=11,N) ELSE WRITE(IUNOUT, * '(1X,A,4I6,/,44X,6I6,/41X,A2,1X,6I6,/,44X,6I6)') * NAMT,(IABS(NPOS(I,J+1)),J=1,10),BREAK, * (IABS(NPOS(I,J+1)),J=11,N) ENDIF ENDIF ENDDO ENDIF C if (short) go to 900 NT=1 DO I=1,MDICT(KDICT) IF(I.EQ.MDICT(NT)+1) NT=NT+1 NNDICT(I)=NT ENDDO call ssort(DICNAM,MDICT(KDICT),NUMCHAR,NORDER) MAXPAS = 1 IF (verbose) MAXPAS = 2 DO NPASS = 1,MAXPAS WRITE(IUNOUT,'(//)') DO II = 1,KDICT IF (II.LT.10) THEN WRITE(DNUM,'(''['',I1,''] '')') II ELSE WRITE(DNUM,'(''['',I2,'']'')') II ENDIF IF(KDICT.GT.1) THEN WRITE(IUNOUT,'(1x,A)')DNUM//' Dictionary '// * DICTNM(II)(1:MAX(1,LASTNB(DICTNM(II))))// * ' '// * DICTVR(II)(1:MAX(1,LASTNB(DICTVR(II)))) ELSE WRITE(IUNOUT,'(1x,A)')'Dictionary '// * DICTNM(II)(1:MAX(1,LASTNB(DICTNM(II))))// * ' '// * DICTVR(II)(1:MAX(1,LASTNB(DICTVR(II)))) ENDIF ENDDO IF (NPASS.EQ.1) THEN WRITE(IUNOUT,'(54X,12HLine Numbers,/)') ELSE WRITE(IUNOUT,'(54X,20HNames Not Referenced,/)') ENDIF C NT=1 DO 50 JJ=1,MDICT(KDICT) I=NORDER(JJ) IF(NBLEN(DICNAM(I)).NE.0) THEN 20 N=NPOS(I,1) BREAK=" " IF(NPOS(I,12).LT.0) BREAK=".." IF((NPASS.EQ.1.AND.N.GT.0).OR. * (NPASS.EQ.2.AND.N.EQ.0)) THEN C IF (NPASS.EQ.2.AND.AROOT(I).NE.0.AND.AROOT(I).NE.I) GO TO 50 IF (NPASS.EQ.2.AND.ALIAS(I).NE.0) THEN II = I 30 IF(NPOS(II,1).NE.0) GO TO 50 II = ALIAS(II) IF(II.NE.0) GO TO 30 ENDIF NAMT = DICTAG(I) IF (KDICT.GT.1) THEN IF (NNDICT(I).LT.10) THEN WRITE(RFLAG,'(''['',I1,''] '')') NNDICT(I) ELSE WRITE(RFLAG,'(''['',I2,'']'')') NNDICT(I) ENDIF NAMT = RFLAG//DICTAG(I)(1:MAX(1,LASTNB(DICTAG(I)))) ENDIF NNT = LASTNB(NAMT) IF (NPASS.EQ.1) THEN DO II = 1,NUMCP7,2 IF(II.GE.NNT+3) NAMT(II:II)='.' ENDDO ENDIF IF(N.LE.10) THEN IF(N.LE.4) THEN WRITE(IUNOUT,'(1X,A,4I6)') * NAMT, * (IABS(NPOS(I,J+1)),J=1,N) ELSE WRITE(IUNOUT,'(1X,A,4I6,/,44X,6I6)') * NAMT, * (IABS(NPOS(I,J+1)),J=1,N) ENDIF ELSE IF(N.LE.16) THEN WRITE(IUNOUT,'(1X,A,4I6,/,44X,6I6,/41X,A2,1X,6I6)') * NAMT,(IABS(NPOS(I,J+1)),J=1,10),BREAK, * (IABS(NPOS(I,J+1)),J=11,N) ELSE WRITE(IUNOUT, * '(1X,A,4I6,/,44X,6I6,/41X,A2,1X,6I6,/,44X,6I6)') * NAMT,(IABS(NPOS(I,J+1)),J=1,10),BREAK, * (IABS(NPOS(I,J+1)),J=11,N) ENDIF ENDIF IF (AROOT(I).NE.0.OR.ALIAS(I).NE.0) THEN II = AROOT(I) IF (II.EQ.0) II = I 40 IF (II.NE.I) THEN RFLAG=' ' IF(KDICT.GT.1.AND.NNDICT(II).NE.NNDICT(I)) THEN IF (NNDICT(II).LT.10) THEN WRITE(RFLAG,'(''['',I1,''] '')') NNDICT(II) ELSE WRITE(RFLAG,'(''['',I2,'']'')') NNDICT(II) ENDIF ENDIF NAMT = RFLAG//'= '// * DICTAG(II)(1:max(1,lastnb(DICTAG(II)))) IF(NPOS(II,1).eq.0) THEN WRITE(IUNOUT,'(1X,A)') NAMT ELSE BREAK=" " IF(NPOS(II,12).LT.0) BREAK=".." IF(NPOS(II,1).LE.10) THEN IF(NPOS(II,1).LE.4) THEN WRITE(IUNOUT,'(1X,A,4I6)') * NAMT, * (IABS(NPOS(II,J+1)),J=1,NPOS(II,1)) ELSE WRITE(IUNOUT,'(1X,A,4I6,/,44X,6I6)') * NAMT, * (IABS(NPOS(II,J+1)),J=1,NPOS(II,1)) ENDIF ELSE IF(NPOS(II,1).LE.16) THEN WRITE(IUNOUT, * '(1X,A,4I6,/,44X,6I6,/41X,A2,1X,6I6)') * NAMT,(IABS(NPOS(II,J+1)),J=1,10),BREAK, * (IABS(NPOS(II,J+1)),J=11,NPOS(II,1)) ELSE WRITE(IUNOUT, * '(1X,A,4I6,/,44X,6I6,/41X,A2,1X,6I6,/,44X,6I6)') * NAMT,(IABS(NPOS(II,J+1)),J=1,10),BREAK, * (IABS(NPOS(II,J+1)),J=11,NPOS(II,1)) ENDIF ENDIF ENDIF ENDIF II=ALIAS(II) IF (II.NE.0) GOTO 40 ENDIF ENDIF ENDIF 50 CONTINUE ENDDO C 900 CLOSE(7) RETURN END C C*************************************************************************** C XGETSTR extract a string of characters delimited by blanks, XTABs, quotes. C NTYP=1 data name; =3 number data; =4 character data; =5 text data. C*************************************************************************** SUBROUTINE XGETSTR include 'ciftbx.sys' include 'cyclops.cmn' C INTEGER I CHARACTER C*1,NUM*13,CBS*2 DATA NUM/'0123456789+-.'/ maxc=maxbuf CBS='\\' CBS(2:2)='n' C C---------------------------------- loop over data items in each line 10 ICHR=ICHR+1 IF(ICHR.LE.MAXC) GOTO 30 C---------------------------------- get a new line from device iuninp 20 READ(IUNINP,'(A)',END=95) IBUF(1:MAXC) LLINE=LLINE+1 ICHR=1 NTYP=0 C---------------------------------- test for text data IF(IBUF(1:1).NE.';') GOTO 30 ICHR=2 C---------------------------------- test for delimiter character 30 C=IBUF(ICHR:ICHR) IF(C.EQ.' ') GOTO 10 IF(C.EQ.XTAB) GOTO 10 IF(ICHR.LT.MAXC) THEN IF(IBUF(ICHR:ICHR+1).EQ.CBS) THEN IBUF(ICHR:ICHR+1) = ' ' GOTO 10 ENDIF ENDIF IF(C.EQ.'#') GOTO 20 IF(C.EQ.'''') GOTO 60 IF(C.EQ.'"') GOTO 60 C---------------------------------- test for data name IF(C.NE.'_') GOTO 40 NTYP=1 GOTO 45 C---------------------------------- test for number or character data 40 NTYP=3 IF(INDEX(NUM,C).EQ.0) NTYP=4 C---------------------------------- get blank-limited char string 45 DO 50 I=ICHR,MAXC IF(IBUF(I:I).EQ.' ') GOTO 90 IF(IBUF(I:I).EQ.XTAB) GOTO 90 IF(I.LT.MAXC) THEN IF(IBUF(I:I+1).EQ.CBS) THEN IBUF(I:I+1) = ' ' GOTO 90 ENDIF ENDIF 50 CONTINUE I=MAXC+1 GOTO 90 C---------------------------------- get quote-limited char string 60 NTYP=4 DO 70 I=ICHR+1,MAXC IF(IBUF(I:I).EQ.C) GOTO 80 70 CONTINUE I=MAXC IBUF(I:I)=C 80 I=I+1 C---------------------------------- count & store string 90 NCHR=I-ICHR ICHR=I-1 STRI(1:NCHR)=IBUF(I-NCHR:ICHR) GOTO 100 95 IEOF=1 100 RETURN END C C*************************************************************************** C Error message generator. Output to device 6 and stop. C*************************************************************************** SUBROUTINE CERR(I,MESS,STRG) include 'ciftbx.sys' include 'cyclops.cmn' INTEGER I C CHARACTER*(*) MESS,STRG C WRITE(iunerr,'(11H Error >>> ,A,2X,A)') MESS,STRG IF(I.EQ.0) RETURN C WRITE(iunerr,'(11X,30HFatal error -- Text file line ,I5/)') LLINE CLOSE(4) 50 STOP END subroutine ssort(strg,nstrg,nchr,norder) C C simple sort routine to establish order of array C strg of nstrg string of length nchr in array norder C no attempt is made to remove duplicates nor to C preserve the initial ordering of duplicates. C C Herbert J. Bernstein, Bernstein+Sons, 13 July 1996 C integer nstrg, nchr, ns, ii, jj, ilow, ihigh, imid integer norder(nstrg) character*(*) strg(nstrg) norder(1)=1 ns=1 do ii = 2,nstrg ilow = 1 ihigh = ns 100 imid = (ilow+ihigh+1)/2 if (ihigh-ilow.le.1) then if (strg(ii) .ge. strg(norder(ilow)).and. * strg(ii) .le. strg(norder(ihigh))) then do jj = ns,ihigh,-1 norder(jj+1) = norder(jj) enddo norder(ihigh) = ii ns=ns+1 go to 200 endif endif if (strg(ii) .ge. strg(norder(ihigh))) then do jj = ns,ihigh+1,-1 norder(jj+1) = norder(jj) enddo norder(ihigh+1) = ii ns=ns+1 else if (strg(ii) .le. strg(norder(ilow))) then do jj = ns,ilow,-1 norder(jj+1) = norder(jj) enddo norder(ilow) = ii ns=ns+1 else if (strg(ii) .le. strg(norder(imid))) then ihigh = imid else ilow = imid endif go to 100 endif endif 200 continue enddo return end C C subroutine getfiles C C This routine, derived from the similar routine in cif2pdb C by H. J. Bernstein and F. C. Bernstein, is used to control C initial processing of command line arguments and envrionment C variables C C On systems lacking a unix style iargc and getarg, provide C equivalent routines. At the very least, you will need C to have iargc() return 0 (for no command line arguments) C and have getarg(karg,strg) return a null-terminated C empty string in strg. C C On systems lacking a unix-style getenv, provide a dummy C routine returning a null-terminated empty string C C C integer lastnb logical init_ logical dict_ include 'ciftbx.sys' include 'cyclops.cmn' character*256 temp,temp2,cline character*256 cldict(99) integer ncld integer nblen,i,j,kk character*(MAXBUF) XTEST character*5 prior, cats integer iargc,ll,karg,kfarg,nfarg, * ifound,iwant,isi,iso,ii logical backarg,ffile ncld = 0 numarg = iargc() call getenv("CYCLOPS_INPUT_TEXT",inptext) call getenv("CYCLOPS_VALIDATION_OUT",valout) call getenv("CYCLOPS_CHECK_DICTIONARY",ckdict) lckdict = max(1,nblen(ckdict)) if(ckdict(1:lckdict).ne.' ') then ncld = ncld+1 if(ncld.gt.99) * call cerr(1,'Too many dictionaries',' ') cldict(ncld) = ckdict(1:lckdict) ckdict = " " lckdict = 1 endif IUNINP=1 IEOF=0 NDICT=0 FLAG=0 LLINE=0 KDICT=1 karg = 0 iwant = 0 ifound = 0 isi = 0 iso = 0 backarg = .false. ffile = .false. prior = ' ' cats = 'catno' 100 if(.not.ffile) then karg = karg+1 if (karg.le.numarg) then if (.not.backarg) then call getarg(karg,temp) temp2 = ' ' else temp = temp2 backarg = .false. endif else go to 500 endif else go to 300 200 close(unit=iuninp) ffile = .false. go to 100 300 kfarg = kfarg+1 if (kfarg.gt.nfarg) then read(iuninp,'(a)',end=200) cline call splitstr(nfarg,cline,cstr,128,' ') kfarg = 0 go to 300 else if (.not.backarg) then temp = cstr(kfarg) temp2 = ' ' else temp = temp2 backarg = .false. endif endif endif ll = nblen(temp) if (ll.eq.0) then temp = ' ' ll = 1 endif if (iwant.ne.0) then if (iwant.eq.1) inptext = temp(1:ll) if (iwant.eq.2) valout = temp(1:ll) if (iwant.eq.3) then ckdict = temp(1:ll) lckdict = max(1,nblen(ckdict)) ncld = ncld+1 if(ncld.gt.99) * call cerr(1,'Too many dictionaries',' ') cldict(ncld) = ckdict(1:lckdict) ckdict = " " lckdict = 1 endif if (iwant.eq.4) then if(temp(1:ll).eq.'F.' .or. temp(1:ll).eq.'f' .or. * temp(1:ll).eq.'0' .or. temp(1:ll).eq.'N' .or. * temp(1:ll).eq.'n') then verbose=.false. else if(temp(1:ll).eq.'T.' .or. temp(1:ll).eq.'t' .or. * temp(1:ll).eq.'1' .or. temp(1:ll).eq.'Y' .or. * temp(1:ll).eq.'y') then verbose=.true. else go to 900 endif endif endif if (iwant.eq.5) then if(temp(1:ll).eq.'F.' .or. temp(1:ll).eq.'f' .or. * temp(1:ll).eq.'0' .or. temp(1:ll).eq.'N' .or. * temp(1:ll).eq.'n') then short=.false. else if(temp(1:ll).eq.'T.' .or. temp(1:ll).eq.'t' .or. * temp(1:ll).eq.'1' .or. temp(1:ll).eq.'Y' .or. * temp(1:ll).eq.'y') then short=.true. else go to 900 endif endif endif if (iwant.eq.6) then if(prior.ne.' ') go to 900 if(temp(1:ll).eq.'NODUP' .or. * temp(1:ll).eq.'nodup') then prior='nodup' else if(temp(1:ll).eq.'FIRST' .or. * temp(1:ll).eq.'first') then prior='first' else if(temp(1:ll).eq.'FINAL' .or. * temp(1:ll).eq.'final') then prior='first' else go to 900 endif endif endif endif if (iwant.eq.7) then open(unit=iuninp,file=temp(1:ll),status='OLD',err=900) kfarg = 1 nfarg = 0 ffile = .true. endif if (iwant.eq.8) then if(temp(1:ll).eq.'F.' .or. temp(1:ll).eq.'f' .or. * temp(1:ll).eq.'0' .or. temp(1:ll).eq.'N' .or. * temp(1:ll).eq.'n') then cats='catno' else if(temp(1:ll).eq.'T.' .or. temp(1:ll).eq.'t' .or. * temp(1:ll).eq.'1' .or. temp(1:ll).eq.'Y' .or. * temp(1:ll).eq.'y') then cats='catck' else go to 900 endif endif endif iwant = 0 else if (temp(1:1).eq."-") then temp2=temp(3:256) if (ll.gt.2) then backarg = .true. karg = karg-1 endif if (temp(2:2).eq."i") then iwant = 1 if (isi.gt.0) go to 900 isi = 1 endif if (temp(2:2).eq."o") then iwant = 2 if (iso.gt.0) go to 900 iso = 1 endif if (temp(2:2).eq."d") iwant = 3 if (temp(2:2).eq."v") iwant = 4 if (temp(2:2).eq."s") iwant = 5 if (temp(2:2).eq."p") iwant = 6 if (temp(2:2).eq."f") iwant = 7 if (temp(2:2).eq."c") iwant = 8 if (iwant.eq.0) go to 900 else ifound = ifound+1 if (ifound.eq.1) then if (isi.gt.0) then ifound = ifound+1 else inptext = temp(1:ll) isi = 1 endif endif if (ifound.eq.2) then if (iso.gt.0) then ifound = ifound+1 else valout = temp(1:ll) iso = 1 endif endif if (ifound.eq.3) then ckdict = temp(1:ll) endif if (ifound.gt.3) go to 900 endif endif go to 100 500 linptext = max(1,nblen(inptext)) lvalout = max(1,nblen(valout)) lckdict = max(1,nblen(ckdict)) if(.not.init_(iuninp,iunout,iundac,iunerr)) * call cerr(1,' failed init',' ') XDICT(1)='STARDICT' kdict = 1 MDICT(1)=0 if(ncld.gt.0) goto 560 open(iuninp,FILE='STARDICT',STATUS='OLD',FORM='FORMATTED', * err=560) READ(iuninp,'(A)',END=560)XTEST if(XTEST.eq.'#DICT') then do kk = 1,100 READ(iuninp,'(A)',END=550) XDICT(kdict) if (XDICT(kdict).eq.'#VERBOSE') then verbose=.true. else if (XDICT(kdict).eq.'#SHORT') then short=.true. else do ii = 1,kdict-1 if (XDICT(ii).eq.XDICT(kdict)) then if(prior.eq.'nodup') * call cerr(1,' Duplicate dictionary ', * XDICT(ii)) go to 540 endif enddo kdict=kdict+1 540 continue endif endif enddo 550 kdict=kdict-1 endif go to 570 560 kdict=0 570 do ii = 1,ncld do kk = 1,kdict if (XDICT(kk).eq.cldict(ii)) then if(prior.eq.'nodup') * call cerr(1,' Duplicate dictionary ', * XDICT(kk)) go to 580 endif enddo kdict=kdict+1 if (kdict.gt.99) call cerr(1, 'Too many dictionaries', ' ') XDICT(kdict)=cldict(ii) 580 continue enddo if(kdict.lt.1) call cerr(1,' Dictionary list empty',' ') close(1) do i = 1,kdict if(.not.dict_(XDICT(i)(1:max(1,lastnb(XDICT(i)))), * prior//cats)) * call cerr(1,XDICT(i)(1:max(1,lastnb(XDICT(i))))// *' not found',' ') MDICT(i)=NDICT DICTNM(i)=dicname_ DICTVR(i)=dicver_ enddo close(unit=iundac) DO 610 I=1,NDICT DO 660 J=1,20 660 NPOS(I,J)=0 610 CONTINUE RETURN 900 write(iunerr,'(a)') * ' cyclops [-i input_text] [-o validation_output] '// * '[-d dictionary] [-p priority] [-c catck]', * ' [-f command_file] [-v verbose] [-s short] '// * '[[[input_text][[validation_output]'// * ' [dictionary]]]', * ' input_text defaults to $CYCLOPS_INPUT_TEXT or stdin', * ' validation_output defaults to $CYCLOPS_VALIDATION_OUT'// * ' or stdout', * ' dictionary defaults to $CYCLOPS_CHECK_DICTIONARY', * ' multiple dictionaries may be specified ', * ' input_text of "-" is stdin ', * ' validation_output of "-" is stdout ' write(iunerr,'(a)') * ' -p has values of first, final or nodup ', * ' (default first for first dictionary has priority) ', * ' -c has values of t or 1 or y vs. f or 0 or n,', * ' (default f, i.e. no category checking) ', * ' -v has values of t or 1 or y vs. f or 0 or n,', * ' (default f, i.e. non-verbose),', * ' -s has values of t or 1 or y vs. f or 0 or n,', * ' (default f, i.e. not short),', * ' short restricts output to items not in dictionaries' stop end C C function nblen(str) C C variant of lastnb which also detects a null character to C terminate a string C character*(*) str integer nblen,ll,jj,ii ll = len(str) jj = index(str,char(0)) if (jj.ne.0) ll = jj-1 if (ll.eq.0) then nblen = 0 return endif do ii = 1,ll nblen = 1+ll-ii if(str(nblen:nblen).ne.' ' .and. * str(nblen:nblen).ne. char(9) ) return enddo nblen = 0 return end C C C C subroutine splitstr(numf,str,sarry,maxf,fs) C C split the string str into a maximum of maxf fields using the C field separator fs. The number of fields found is reported in C numf. The fields are split into the array sarry, with each C field terminated by a null character. C C C The field separator ' ' is treated as a special case, with C full blank and tab removal, and only the count of non-blank C fields returned. C integer numf, maxf integer jj,jjt,is,ll,lfs character*(*) str, sarry(maxf), fs ll = len(str) lfs = len(fs) if (fs.eq.' ') lfs = 1 is = 1 numf = 0 100 jj = index(str(is:ll),fs) if (fs.eq.' ') then jjt = index(str(is:ll),char(9)) if (jj.ne.0) then if (jjt.ne.0) jj = min(jjt,jj) else jj = jjt endif endif if (jj.eq.0) then numf = numf+1 if (numf.le.maxf) then sarry(numf) = str(is:ll)//char(0) endif return else if (fs.ne.' ' .or. jj.gt.1) then numf = numf+1 if (numf.le.maxf) then if (jj.gt.1) then sarry(numf) = str(is:is-1+jj-1)//char(0) else sarry(numf) = char(0) endif endif endif is = is+jj+lfs-1 if (is.le.ll) go to 100 if (fs.ne.' ') then numf = numf+1 if (numf.le.maxf) sarry(numf) = char(0) endif return endif end