C C C \ | / /##| @@@@ @ @@@@@ | | @@@@@@ C \|/ STAR /###| @ @ @ __|__ | @ C ----*---- /####| @ @ @@@@ | |___ __ __ @@ C /|\ /#####| @ @ @ | | \ \/ @ @ C / | \ |#####| @@@@ @ @ \___/ \___/ __/\__ @@@@ C |#####|________________________________________________ C ||#####| ___________________ | C __/|_____||#####|________________|&&&&&&&&&&&&&&&&&&&|| | C<\\\\\\\\_ |_____________________________|&&& 1 Sep 2006 &&|| | C \| ||#####|________________|&&&&&&&&&&&&&&&&&&&||__________| C |#####| C |#####| Version 3.0.4 Release C |#####| C /#######\ C |#########| C ==== C || C An extended tool box of fortran routines for manipulating CIF data. C || C || CIFtbx Version 3 C || by C || C || Sydney R. Hall (syd at crystal dot uwa dot edu dot au) C || and C || Herbert J. Bernstein (yaya at bernstein-plus-sons dot com) C || C || C_____________________||_____________________________________________________ C (C) Copyright 2006 Herbert J. Bernstein C C YOU MAY REDISTRIBUTE THE CIFtbx PACKAGE UNDER THE TERMS OF THE GPL. C C ALTERNATIVELY YOU MAY REDISTRIBUTE THE CIFtbx API (but not the programs C and documentation) UNDER THE TERMS OF THE LGPL. C C Work on CIFtbx has been supported in part by grants from the U. S. C National Science Foundation, the U.S. Department of Energy and the C International Union of Crystallography. C C CIFtbx3 is free software; you can redistribute this software and/or C modify this software under the terms of the GNU General Public C License as published by the Free Software Foundation; either version C 2 of the License, or (at your option) any later version. C C This software is distributed in the hope that it will be useful, C but WITHOUT ANY WARRANTY; without even the implied warranty of C MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the C GNU General Public License for more details. C C You should have received copies of the GNU General Public License C and of the GNU Lesser General Public License along with this software; C if not, write to the Free Software Foundation, Inc., 59 Temple Place, C Suite 330, Boston, MA 02111-1307 USA C C Before using this software, please read the NOTICE and please read C the IUCr Policy on the Use of the Crystallographic Information File (CIF) C C This is a version of CIFtbx which has been extended to work with DDL 2 C and mmCIF as well as with DDL 1.4 and core CIF dictionaries. CIFtbx C version 1 was written by Sydney R. Hall (see Hall, S. R., "CIF Applications C IV. CIFtbx: a Tool Box for Manipulating CIFs," J. Appl. Cryst (1993). 26, C 482-494. The revisions for version 2 were done by Herbert J. Bernstein C and Sydney R. Hall (see Hall, S. R. and Bernstein, H. J., "CIFtbx 2: C Extended Tool Box for Manipulating CIFs," J. Appl. Cryst.(1996). 29, C 598-603) C C The revisions for release 3 were done by Herbert J. Bernstein, work C funded in part by the International Union of Crystallography C C___________________________________________________________________________ C C C GENERAL TOOLS C C C init_ Sets the device numbers of files. (optional) C [logical function always returned .true.] C C Set input CIF device (def=1) C C Set output CIF device (def=2) C C Set direct access formatted C scratch device number (def=3) C C Set error message device (def=6) C C C C dict_ Requests a CIF dictionary be used for various data checks. C [logical function returned as .true. if the name dictionary C was opened and if the check codes are recognisable. The C data item names used in the first dictionary loaded are C considered to be preferred by the user to aliases found C in dictionaries loaded in later calls. On exit from dict_ C the variable dicname_ is either equal to the filename, or, C if the dictionary had a value for the tag dictionary_name C of dictionary.title, dicname_ is set to that value. C The variable dicver_ is blank or set to the value of C _dictionary_version or of _dictionary.version The check codes C 'catck' and 'catno' turn on and off checking of dictionary C catgeory conventions. The default is 'catck'. The check C codes 'parck' and 'parno' turn on and off checking of C parent-child relationships. The default is 'parck'. Three check C codes control the handling of tags from the current dictionary C which duplicate tags from a dictionary loaded earlier. These C codes ('first', 'final' and 'nodup') have effect only for the C current call to dict_ The default is 'first'.] C C A CIF dictionary in DDL format C or blank if just setting flags C or resetting the dictionary C C The codes specifying the types of C checks to be applied to the CIF. C C 'valid' data name validation check. C 'dtype' data item data type check. C 'catck' check datanames against C categories C 'catno' don't check datanames against C categories C 'first' accept first dictionary's C definitions of duplicate tags C 'final' accept final dictionary's C definitions of duplicate tags C 'nodup' do not accept duplicate tag C definitions C 'parck' check datanames against parent- C child relationahips C 'parno' don't check datanames against C parent-child relationships C 'reset' switch off checking flags C 'close' close existing dictionaries C C___________________________________________________________________________ C C C CIF ACCESS TOOLS ("the get_ing commands") C C C C ocif_ Opens the CIF containing the required data. C [logical function returned .true. if CIF opened] C C A blank name signals that the C currently open input CIF file C will be read. C C C C data_ Identifies the data block containing the data to be requested. C [logical function returned .true. if block found] C C A blank name signals that the next C encountered block is used (the block C name is stored in the variable bloc_). C C C bkmrk_ Saves or restores the current position so that data from C elsewhere in the cif can be examined. C [logical function returned as .true. on save if there was C room in internal storage to hold the current position, .true. C on restore if the bookmark number used was valid. If the C argument is zero, the call is to save the position and return C the bookmark number in the argument. If the argument is C non-zero, the call is to restore the position saved for the C bookmark number given. The bookmark and the argument are C cleared. The position set on return allow reprocessing of C the data item or loop row last processed when the bookmark C was placed. C C NOTE: All bookmarks are cleared by a call to data_] C C Bookmark number C C C find_ Find the location of the requested item in the CIF. C [The argument "name" may be a data item name, blank C for the next such item. The argument "type" may be C blank for unrestricted acceptance of any non-comment C string (use cmnt_ to see comments), including loop headers, C "name" to accept only the name itself and "valu" C to accept only the value, or "head" to position to the C head of the CIF. Except when the "head" is requested, C the position is left after the data item provided. If the C item found is of type "name", posnam_ is set, otherwise, C posval_] C C A blank name signals that the next C item of the type specified is needed C C blank, 'head', 'name' or 'valu' C C Returned string is of length long_. C C C C test_ Identify the data attributes of the named data item. C [logical function returned as .true. if the item is present or C .false. if it is not. The data attributes are stored in the C common variables list_, type_, dictype_, diccat_ and dicname_. C The values in dictype_, diccat_ and dicname_ are valid C whether or not the data item is found in the input CIF, as C long as the named data item is found in the dictionaries C declared by calls to dict_. The data item name found C in the input CIF is stored in tagname_. The appropriate C column numbers are stored in posnam_, posval_, posend_ and (for C numbers) in posdec_. The quotation mark, if any, used is C stored in quote_. C C list_ is an integer variable containing the sequential number C of the loop block in the data block. If the item is not within C a loop structure this value will be zero. C C type_ is a character*4 variable with the possible values: C 'numb' for number data C 'char' for character data C 'text' for text data C 'null' if data missing or '?' or '.' C also used for blank quoted fields if C nblank_ is true C C dictype_ is a character*(NUMCHAR) variable with the type code C given in the dictionary entry for the named data item. If C no dictionary was used, or no type code was specified, this C field will simply agree with type_. If a dictionary was used, C this type may be more specific than the one given by type_. C C diccat_ is a character*(NUMCHAR) variable with the category C of the named data item, or '(none)' C C dicname_ is a character*(NUMCHAR) variable with the name of C the data item which is found in the dictionary for the C named data item. If alias_ is .true., this name may C differ from the name given in the call to test_. If alias_ C is .false. or no preferred alias is found, dicname_ agrees with C the data item name. C C dicpname_ is a character*(NUMCHAR) variable with the name of C the parent of the data item which is found in the dictionary for the C named data item. The default when no parent is specified in a C dictionary is to give the value on dicname_. C C tagname_ is a character*(NUMCHAR) variable with the name C of the data item as found in the input CIF. It will be C blank if the data item name requested is not found in the C input CIF and may differ from the data item name provided C by the user if the name used in the input CIF is an C alias of the data item name and alias_ is .true. C C posnam_, posval_, posend_ and posdec_ are integer variables C which may be examined if information about the horizontal C position of the name and data read are needed. posnam_ is the C starting column of the data name found (most often 1). C posval_ is the starting column of the data value. If the C field is numeric, then posdec_ will contain the effective C column number of the decimal point. For whole numbers, the C effective position of the decimal point is one column to the C right of the field. posend_ contains the ending column of the C data value. C C valid_ is a logical variable that may be examined to C determine if the value conforms to dictionary-specified C type, range and enumeration restrictions. C C quote_ is a character*1 varibale which may be examined to C determine if a quotation character was used on character data.] C C Name of the data item to be tested. C C C dtype_ Return the dictionary type of a data name, if any. C [logical function returned as .true. if the item has a type C in the dctionary, .false. if not. The type returned is C one of the base type used by type_ (see above), if possible] C C Name of the item for which a type is needed C Returned type from the dictionary C C C name_ Get the NEXT data name in the current data block. C [logical function returned as .true. if a new data name exists C in the current data block, and .false. when the end of the data C block is reached.] C C Returned name of next data item in block. C C C C numb_ Extracts the number and its standard deviation (if appended). C [logical function returned as .true. if number present. If C .false. arguments 2 and 3 are unaltered. If the esd is not C attached to the number argument 3 is unaltered.] C C Name of the number sought. C C Returned number. C C Returned standard deviation. C C C C numd_ Extracts the number and its standard deviation (if appended) C as double precision variables. C [logical function returned as .true. if number present. If C .false. arguments 2 and 3 are unaltered. If the esd is not C attached to the number argument 3 is unaltered.] C C Name of the number sought. C C C Returned number. C C C Returned standard deviation. C C C C char_ Extracts character and text strings. C [logical function returned as .true. if the string is present. C Note that if the character string is text this function is C called repeatedly until the logical variable text_ is .false. C Non-text blank (quoted blanks) or empty ('' or "") fields C are converted by char to a null field, if nblank_ is true.] C C Name of the string sought. C C Returned string is of length long_. C C charnp_ Extracts character and text strings. C [logical function returned as .true. if the string is present. C Note that if the character string is text this function is C called repeatedly until the logical variable text_ is .false. C Non-text blank (quoted blanks) or empty ('' or "") fields C are converted by char to a null field, if nblank_ is true.] C Only the number of characters returned in the third argument C are set. This value is never less than 1, but may be less C than the allocated length of the returned string. C C Name of the string sought. C C Returned string is of length long_. C C Returned length of valid characters. C C C cmnt_ Extracts the next comment from the data block. C [logical function returned as .true. if a comment is present. C The initial comment character "#" is _not_ included in the C returned string. A completely blank line is treated as C a comment.] C C Returned string is of length long_. C C C C purge_ Closes existing data files and clears tables and pointers. C [subroutine call] C C____________________________________________________________________________ C C C C CIF CREATION TOOLS ("the put_ing commands") C C C C pfile_ Create a file with the specified file name. C [logical function returned as .true. if the file is opened. C The value will be .false. if the file already exists.] C C Blank for use of currently open file C C C C pdata_ Put a data block command into the created CIF. C [logical function returned as .true. if the block is created. C The value will be .false. if the block name already exists. C Produces a save frame instead of a data block if the C variable saveo_ is true during the call. No block duplicate C check is made for a save frame.] C C C C C C ploop_ Put a loop_ data name into the created CIF. C [logical function returned as .true. if the invocation C conforms with the CIF logical structure. If pposval_ C is non-zero, the "loop_" header is positioned to C that column. If pposnam_ is non-zero, the data name is C positioned to that column.] C C If the name is blank on the first call C of a loop, only the "loop_" is placed. C C C C pchar_ Put a character string into the created CIF. C [logical function returned as .true. if the name is unique, C AND, if dict_ is invoked, is a name defined in the dictionary, C AND, if the invocation conforms to the CIF logical structure. C The action of pchar_ is modified by the variables pquote_ and C nblanko_. If pquote_ is non-blank, it is used as a quotation C character for the string written by pchar_. The valid values C are '''', '"', and ';'. In the last case a text field is C written. If the string contains a matching character to the C value of quote_, or if quote_ is not one of the valid C quotation characters, a valid, non-conflicting quotation C character is used. Except when writing a text field, if C nblanko_ is true, pchar_ converts a blank string to C an unquoted period.] C C If the name is blank, do not output name. C C A character string of MAXBUF chars or less. C C C C pcmnt_ Puts a comment into the created CIF. C [logical function returned as .true. The comment character C "#" should not be included in the string. A blank comment C is presented as a blank line without the leading "#"]. C C A character string of MAXBUF chars or less. C C C pnumb_ Put a single precision number and its esd into the created CIF. C [logical function returned as .true. if the name is unique, C AND, if dict_ is invoked, is a name defined in the dictionary, C AND, if the invocation conforms to the CIF logical structure. C The number of esd digits is controlled by the variable C esdlim_] C C If the name is blank, do not output name. C C Number to be inserted. C C Esd number to be appended in parentheses. C C C pnumd_ Put a double precision number and its esd into the created CIF. C [logical function returned as .true. if the name is unique, C AND, if dict_ is invoked, is a name defined in the dictionary, C AND, if the invocation conforms to the CIF logical structure. C The number of esd digits is controlled by the variable C esdlim_] C C If the name is blank, do not output name. C C C Number to be inserted. C C C Esd number to be appended in parentheses. C C C C ptext_ Put a character string into the created CIF. C [logical function returned as .true. if the name is unique, C AND, if dict_ is invoked, is a name defined in the dictionary, C AND, if the invocation conforms to the CIF logical structure.] C ptext_ is invoked repeatedly until the text is finished. Only C the first invocation will insert a data name. C C If used when pfold_ is non-zero, the text field will be marked C as folded even if the first line is small enough to fit. C In order to produce a non-folded text field in the midst C of generally folded items, pfold_ should be set to 0 before C calling ptext_ and then restored to the previous value. C C If the name is blank, do not output name. C C A character string of MAXBUF chars or less. C C C prefx_ Puts a prefix onto subsequent lines of the created CIF. C [logical function returned as .true. The second argument C may be zero to suppress a previously used prefix, or C greater than the non-blank length of the string to force C a left margin. Any change in the length of the prefix C string flushes pending partial output lines, but does _not_ C force completion of pending text blocks or loops. C This function allows the CIF output functions to be used C within what appear to be text fields to support annotation C of a CIF. ] C C A character string of MAXBUF chars or less. C C The length of the prefix string to use. C C C C C close_ Close the creation CIF. MUST be used if pfile_ is used. C [subroutine call] C C C____________________________________________________________________________ C C C C....The CIF tool box also provides variables for data access control: C C C alias_ Logical variable: if left .true. then all calls to C CIFtbx functions may use aliases of data item names. C The preferred synonym from the dictionary will be C subsituted internally, provided aliased data names were C supplied by an input dictionary (via dict_). The C default is .true., but alias_ may be set to .false. C in an application. C C aliaso_ Logical variable: if set .true. then cif output C routines will convert aliases to the names to preferred C synonyms from the dictionary. The default is .false., but C aliaso_ may be set to .true. in an application. The C setting of aliaso_ is independent of the setting of C alias_. C C align_ Logical variable signals alignment of loop_ lists during C the creation of a CIF. The default is .true. C C append_ Logical variable: if set .true. each call to ocif_ will C append the information found to the current cif. The default C is .false. C C bloc_ Character*(NUMCHAR) variable: the current block name. C C decp_ Logical variable: set when processing numeric input, .true. C if there is a decimal point in the numeric value, .false. C otherwise C C dictype_ Character*(NUMCHAR) variable: the precise data type code C (see test_) C C diccat_ Character*(NUMCHAR) variable: the category (see test_) C C dicname_ Character*(NUMCHAR) variable: the root alias (see test_) or C the name of the dictionary just loaded (see dict_) C C dicpname_ Character*(NUMCHAR) variable: the parent (see test_) C C dicver_ Character*(NUMCHAR) variable: the version of the dictionary C just loaded (see dict_) C C esdlim_ Integer variable: Specifies the upper limit of esd's C produced by pnumb_, and, implicitly, the lower limit. C The default value is 19, which limits esd's to the range C 2-19. Typical values of esdlim_ might be 9 (limiting C esd's to the range 1-9), 19, or 29 (limiting esd's C to the range 3-29). If esdlim_ is given as a negative C value, the upper limit of esd's is the absolute value C of esdlim_ and the lower limit is 1. C C esddig_ Integer variable: The number of esd digits in the last C number read from a CIF. Will be zero if no esd C was given. C C file_ Character*(MAXBUF) variable: the filename of the current file. C Warning: only file_(1:longf_) is valid C C fold_ Logical variable signals that the current text block C began with the ';\' fold indicator. Only meaningful C when text_ is .true. and type_ is 'text'. C (fold_ is .true. if the indicator is present) C C glob_ Logical variable signals that the current data block C is actually a global block (.true. for a global block). C C globo_ Logical variable signals that the output data block from C pdata_ is actually a global block (.true. for a global block). C C line_ Integer variable: Specifies the input/output line limit C for processing a CIF. The default value is 80 characters. C This may be set by the program. The max value is MAXBUF C which has a default value of 2048. In order to use C the CIF 1.1 line folding protocol for lines that C cannot be fit into line_ characters, the variable C pfold_ must be set to a non-zero value less than C or equal to line_ C C list_ Integer variable: the loop block number (see test_). C C long_ Integer variable: the length of the data string in strg_. C C longf_ Integer variable: the length of the filename in file_. C C loop_ Logical variable signals if another loop packet is present. C C lzero_ Logical variable: set when processing numeric input, .true. C if the numeric value is of the form [sign]0.nnnn rather than C [sign].nnnn, .false. otherwise C C nblank_ Logical variable: if set .true. then all calls to C to char_ or test_ which encounter a non-text quoted blank C will return the type as 'null' rather than 'char'. C C nblanko_ Logical variable: if set .true. then cif output C routines will convert quoted blank strings to an C unquoted period (i.e. to a data item of type null). C C pdecp_ Logical variable: if set .true. then cif numeric output C routines will insert a decimal point in all numbers written by C pnumb_ or pnumbd_. If set .false. then a decimal point will be C written only when needed. The default is .false. C C pesddig_ Integer variable: if set non-zero, and esdlim_ is negative, C controls the number of digits for esd's produced by C pnumb_ and pnumd_ C C pfold_ Integer variable: If set non-zero, specifies a column C on which output lines are to be folded. The default is 0. C If pfold_ is set to a value greater than line_ the C value of line_ will be used instead. Non-zero values of C pfold_ less than 4 are not valid and will be reset to 4. C Non-zero values of pfold_ less than 80 can cause conflict C with the syntactic requirements of creating a valid CIF. C C plzero_ Logical variable: if set .true. then cif numeric output C routines will insert a zero before a leading decimal point, C The default is .false. C C pposdec_ Integer variable giving the position of the decimal point C for the next number to be written. This acts very much like C a decimal centered tab in a word processor, to help align C columns of number on a decimal point, if a decimal point C is present. C C pposend_ Integer variable giving the ending column of the next C number or quoted character value to be written. Used to C pad with zeros or blanks. C C pposnam_ Integer variable giving the starting column of the next C name or comment or data block to be written. C C pposval_ Integer variable giving the starting column of the next C data value to be written by pchar_, pnumb_ or pnumd_. C Also used to set the position of the initial "loop_" C in a ploop_ call or to set the position of a terminal "save_" C for a save frame in a pdata_ call for which saveo_ is .true. C C posdec_ Integer variable giving the position of the decimal point C for the last number read, if a decimal point was present. C C posend_ Integer variable giving the ending column of the last C data value read, not including a terminal quote. C C posnam_ Integer variable giving the starting column of the last C name or comment or data block read. C C posval_ Integer variable giving the starting column of the last C data value read. Also reports the column of the C terminal "save_" of a save frame. C C pquote_ Character variable giving the quotation symbol to be C used for the next string written, or the comment C flag for the next comment written. C C precn_ Integer variable: Reports the record number of the last C line written to the output cif. Set to zero by init_. Also C set to zero by pfile_ and close_ if the output cif file name C was not blank. C C ptabx_ Logical variable signals tab character expansion to blanks C during the creation of a CIF. The default is .true. C C quote_ Character variable giving the quotation symbol found C delimiting the last string read or the comment flag C for the last comment read. C C recbeg_ Integer variable: Gives the record number of the first C record to be used. May be changed by the user to restrict C access to a CIF. C C recend_ Integer variable: Gives the record number of the last C record to be used. May be changed by the user to restrict C access to a CIF. C C recn_ Integer variable: Reports the record number of the last C line read from the direct access copy of the input cif. C C save_ Logical variable signals that the current data block C is actually a save-frame (.true. for a save-frame). C C saveo_ Logical variable signals that the output data block from C pdata_ is actually a save-frame (.true. for a save-frame). C C strg_ Character*(MAXBUF) variable: the current data item. C C tabl_ Logical variable signals tab-stop alignment of output C during the creation of a CIF. The default is .true. C C tabx_ Logical variable signals tab character expansion to blanks C during the reading of a CIF. The default is .true. C C tbxver_ Character*32 variable: the CIFtbx version and date C in the form 'CIFtbx version N.N.N, DD MMM YY ' C C text_ Logical variable signals if another text line is present. C C type_ Character*4 variable: the data type code (see test_). C C unfold_ Logical variable signals that input lines are to be C unfolded before presentation of data. The default C is .false. C C valid_ Logical variable: set when processing input data for which C dictionary type checking has been requested , .true. C if the value conforms to type, range and enumeration C specifications for the given tag in the dictionary. C C xmlout_ Logical variable: Set by the user to change the output C style to XML conventions. Note that this is not a C cml output, but a literal translation from the input CIF. C The default is .false. C C xmlong_ Logical variable: Set by the user to change the style of C xml output if xmlout_ is .true. When .true. (the default) C xml tag names are the full CIF tag names with the leading C '_' removed. When .false. an attempt is made to strip C the leading category name as well. C C C_____________________________________________________________________________ C C C >>>>>> Set the device numbers. C function init_(devcif,devout,devdir,deverr) C logical init_ include 'ciftbx.sys' integer devcif,devout,devdir,deverr integer ii,kdig real ytest double precision ztest C init_=.true. cifdev=devcif outdev=devout dirdev=devdir errdev=deverr recn_=0 precn_=0 plcat = ' ' plxcat = ' ' plhead(1) = ' ' plxhead(1) = ' ' pdblok = ' ' ploopn = 0 nstable = 0 nivt = 0 C C recompute decimal single precision precision C This is found by computing the smallest power of C 10 which, when added to 1, produces a change C and then backing off by 1 C decprc = .1 do ii = 1,8 ytest = 1.+decprc/10. if (ytest.eq.1.) go to 100 decprc = decprc/10. enddo 100 continue decprc=decprc*10. C C recompute decimal double precision precision C kdig = 1 dpprc = .1D0 do ii = 1,17 ztest = 1.D0+dpprc/10. if (ztest.eq.1.D0) go to 200 dpprc = dpprc/10.D0 kdig = kdig+1 enddo 200 continue dpprc=dpprc*10.D0 write(ndpfmt,'(5h(d30.,i2,1h))') kdig-1 C C recompute decimal single precision minimum power of ten C decmin = .1 do ii = 1,39 ytest = decmin/10. if (ytest.eq.0.) go to 300 decmin = decmin/10. enddo 300 continue C C recompute decimal double precision minimum power of 10 C and its log base 10 (minexp) C dpmin = .1D0 minexp = -1 do ii = 1,309 ztest = dpmin/10. if (ztest.eq.0.D0) go to 400 dpmin = dpmin/10.D0 minexp = minexp-1 enddo 400 continue call clearfp return end C C C C C C >>>>>> Read a CIF dictionary and prepare for checks C function dict_(fname,checks) C logical dict_ logical ocif_ logical data_ logical charnp_ logical test_ integer lastnb include 'ciftbx.sys' logical tbxxnid, tbxxoid logical nresult character fname*(*),checks*(*) character temp*(MAXBUF) character codes(11)*5,name*(MAXBUF),bxname*(NUMCHAR) character bpname*(NUMCHAR) character bcname*(NUMCHAR),biname*(NUMCHAR),bname*(NUMCHAR) character baname*(NUMCHAR),ganame*(NUMCHAR),btname*(NUMCHAR) character batag*(NUMCHAR) character mcstrg*(NUMCHAR) character riname*(NUMCHAR),rfname*(NUMCHAR) character xdicnam*(NUMCHAR) character xdicver*(NUMCHAR) character xmtoken*(NUMCHAR),xmtarg*(XMLCHAR),xmtyp*(NUMCHAR) character xxxtemp*(NUMCHAR) character*3 ovchk, otchk integer nrecds,recends,recbegs integer lchecks,lbpname,lbcname,lbaname,lbtname,lbname integer lriname,lrfname integer kdict,kadict,ifind,jfind,iafind,jck,ick integer i,j,nmatch,mycat,ksmatch,ii,jj,idstrt,icstrt,kdup integer nmycat,ixmtyp,nxmc,kxmc integer lstrg,lxmtoken,lxmtarg,lxmtyp,kvrtp,kstrg,sindex C C Control flags for matching categories, names and types C C icloop is the loop number of the block for the C current category C ictype is the type of the current category C 0 - none found yet C 1 - _item.category.id C 2 - _category C 3 - _category.id C inloop is the loop number of the block for the C current name C intype is the type of the current name C 0 - none found yet C 1 - _item.name C 2 - _name C ialoop is the loop number of the block for the C current alias C iatype is the type for the current alias C 0 - none found yet C 1 - _item_aliases.alias_name C imloop is the loop number of the block for the C current parent C imtype is the type for the current parent C 0 - none found yet C 1 - _item.mandatory_code C iploop is the loop number of the block for the C current parent C iptype is the type for the current parent C 0 - none found yet C 1 - _item_linked.parent_name C 2 - _item_link_parent C itloop is the loop number of the block for the C current type C ittype is the type of the current type C 0 - none found yet C 1 - _item_type.code C 2 - _type C iritype is the type of the current related item C 0 - none found yet C 1 - _item_related.related_name C 2 - _related_item C irftype is the type of the current related item function C 0 - none found yet C 1 - _item_related.function_code C 2 - _related_function C integer icloop,ictype,inloop,intype,ialoop,iatype, * imloop,imtype,iploop,iptype,itloop,ittype, * iriloop,iritype,irfloop,irftype,icktype C character*4 map_type(16),map_to(16),mapped character*(NUMCHAR) dt(2),dv(2),ct(3),nt(2),at(1),tt(2) character*(NUMCHAR) ri(2),rf(2),ck(2),pt(2),pc(2),mc(2) character*(NUMCHAR) ve(2),vr(3) data map_type * /'floa','int ','yyyy','symo','ucha','ucod','name','idna', * 'any ','code','line','ulin','atco','fax ','phon','emai'/ data map_to * /'numb','numb','char','char','char','char','char','char', * 'char','char','char','char','char','char','char','char'/ data ri * /'_item_related.related_name ', * '_related_item '/ data rf * /'_item_related.function_code ', * '_related_function '/ data dt * /'_dictionary.title ', * '_dictionary_name '/ data dv * /'_dictionary.version ', * '_dictionary_version '/ data ct * /'_item.category_id ', * '_category ', * '_category.id '/ data nt * /'_item.name ', * '_name '/ data at * /'_item_aliases.alias_name '/ data tt * /'_item_type.code ', * '_type '/ data ck * /'_category_key.name ', * '_list_reference '/ data pt * /'_item_linked.parent_name ', * '_item_link_parent '/ data pc * /'_item_linked.child_name ', * '_item_link_child '/ data mc * /'_item.mandatory_code ', * '_mandatory '/ data ve * /'_item_enumeration.value ', * '_enumeration '/ data vr * /'_item_range.minimum ', * '_enumeration_range ', * '_item_range.maximum '/ C data codes /'valid','dtype','reset','close', * 'catck','catno','nodup','final','first', * 'parck','parno'/ C nrecds=nrecd recbegs=recbeg_ recends=recend_ if(append_) then recbeg_=nrecd endif C C Initialize kdup to 0 ('final') C kdup = 0 C C initialize both xdicnam and xdicver to blank C xdicnam = ' ' xdicver = ' ' C C preserve entry values of tcheck and vcheck in case dict fails C otchk = tcheck ovchk = vcheck C C....... Are the codes OK C lchecks=min(len(temp),len(checks)) call tbxxnlc(temp(1:lchecks),checks) i=0 120 i=i+1 if(i.ge.lchecks) goto 190 if(temp(i:i).eq.' ') goto 120 do 150 j=1,11 if(temp(i:i+4).eq.codes(j)) goto 170 150 continue dict_=.false. goto 500 170 i=i+4 if(j.eq.1) then vcheck='yes' goto 120 endif if(j.eq.2) then tcheck='yes' goto 120 endif if(j.eq.3) then vcheck = 'no ' tcheck = 'no ' goto 120 endif if(j.eq.4) then vcheck = 'no ' tcheck = 'no ' catchk = 'yes' ndcname = 0 ndict = 0 if(nname.gt.0) then do 180 i = 1,nname dtype(i)=' ' dxtyp(i)=' ' cindex(i)=0 ddict(i)=0 180 continue endif dict_=.true. goto 500 endif if (j.eq.5) then catchk = 'yes' goto 120 endif if (j.eq.6) then catchk = 'no ' goto 120 endif if (j.eq.10) then parchk = 'yes' goto 120 endif if (j.eq.11) then parchk = 'no ' goto 120 endif kdup=j-8 goto 120 C C if no category names have been loaded, clean up C the hash table for dictionary category names C 190 if(ndcname.eq.0) then call hash_init(dcname,dcchain,NUMDICT,ndcname,dchash, * NUMHASH) endif icstrt=ndcname C C if no dictionary names have been loaded, clean up C the hash table for dictionary names C if(ndict.eq.0) then call hash_init(dicnam,dicchain,NUMDICT,ndict,dichash, * NUMHASH) endif idstrt=ndict C C....... Open and store the dictionary C dict_=.true. if(fname.eq.' ') goto 500 if(nname.gt.0) call err(' Dict_ must precede ocif_') dict_=ocif_(fname) if(.not.dict_) goto 500 dictfl='yes' C C At this point is is proper to update xdicnam to fname C xdicnam = fname C C....... Loop over data blocks; extract _name's, _type etc. C 200 if(.not.data_(' ')) goto 400 lbloc = lastnb(bloc_) if(bloc_(1:1).eq.'_'.or.glob_.or.bloc_.eq.' ') then call tbxxclc(bname,lbname,bloc_(1:lbloc),lbloc) else call tbxxclc(bname,lbname,'_'//bloc_(1:lbloc),lbloc+1) endif C C see if this is a dictionary defining block C do i = 1,2 if(charnp_(dt(i),name,lstrg)) then xdicnam = name(1:lstrg) do j = 1,2 if(test_(dv(j))) then xdicver = strg_(1:max(1,long_)) goto 200 endif enddo goto 200 endif enddo C Cdbg WRITE(6,*) ndict,bloc_ C C Analyze loop structure for categories, names, types and parents C C C initalize loop info C icloop = -1 inloop = -1 ialoop = -1 imloop = -1 iploop = -1 itloop = -1 iriloop = -1 irfloop = -1 ictype = 0 intype = 0 iatype = 0 imtype = 0 iptype = 0 ittype = 0 iritype = 0 irftype = 0 icktype = 0 ixmtyp = 0 bcname = ' ' bpname = ' ' lbcname = 1 lbpname = 1 baname = ' ' batag = ' ' lbaname = 1 btname = ' ' lbtname = 1 biname=bloc_ mycat=0 loop_=.false. loopnl=0 nmatch=0 ksmatch=0 riname = ' ' lriname = 0 rfname = ' ' lrfname = 0 C C Pick up category_keys and list_references C do i = 1,2 210 if(charnp_(ck(i),name,lstrg)) then if (icktype.ne.0 .and. icktype.ne.i) * call warn * (' Multiple DDL 1 and 2 related key definitions ') icktype = i if (tbxxnid(name(1:lstrg),ick)) then catkey(ick) = .true. else if(.not.catkey(ick)) then ifind = aroot(ick) 215 catkey(ifind) = .true. ifind = alias(ifind) if (ifind.ne.0) go to 215 endif endif if (loop_) go to 210 endif enddo C C Process related items C do i = 1,2 if(charnp_(ri(i),name,lstrg)) then if (iritype.ne.0) * call warn * (' Multiple DDL 1 and 2 related item definitions ') iritype = i if(loop_) iriloop = loopnl call tbxxnlc(riname,name(1:lstrg)) lriname=long_ C C Seek the matching function, may be in the same loop or not C if(charnp_(rf(i),name,lstrg)) then if (irftype.ne.0) * call warn * (' Multiple DDL 1 and 2 related item functions ') irftype = i if (loop_) irfloop = loopnl call tbxxnlc(rfname,name(1:lstrg)) lrfname=long_ endif endif enddo loop_ = .false. loopnl = 0 C C Process categories C do i = 1,3 if(charnp_(ct(i),name,lstrg)) then if(ictype.ne.0) * call warn(' Multiple DDL 1 and 2 category definitions ') ictype = i if(loop_) icloop = loopnl call tbxxnlc(bcname,name(1:lstrg)) lbcname=long_ nmycat = ndcname+1 call hash_store(bcname(1:long_), * dcname,dcchain,NUMDICT,ndcname,dchash,NUMHASH,mycat) if(mycat.eq.0) then call err(' Dictionary category names > NUMDICT ') endif if (mycat.eq.nmycat) then ccatkey(mycat) = 0 xmcind(mycat)=0 endif C C if this is not a loop of categories, we expect a match C against the block name, unless we are doing replacements C if(.not.loop_) then if(ictype.eq.1) then if(bname(1:min(lbname,lbcname+2)).ne. * '_'//bcname(1:lbcname)//'.' * .and. catchk.eq.'yes' * .and. (rfname(1:7).ne.'replace')) then call warn(' Category id does not match block name') endif else if(ictype.eq.2) then if(bcname.ne.'dictionary_definition' .and. * bcname.ne.'category_overview') then if(bname(1:min(lbname,lbcname+2)).ne. * '_'//bcname(1:lbcname)//'_') then if(bname(1:min(lbname,lbcname+1)).ne. * '_'//bcname(1:lbcname) * .and. catchk.eq.'yes' * .and. (rfname(1:7).ne.'replace')) then call warn(' Category id does not match block name') endif endif endif endif endif endif endif loop_ = .false. loopnl = 0 enddo C C Process XML translations C loop_ = .false. loopnl = 0 if(charnp_('_xml_mapping.token',xmtoken,lxmtoken)) then 230 if(charnp_('_xml_mapping.token_type',xmtyp,lxmtyp)) then if(charnp_('_xml_mapping.target',xmtarg,lxmtarg)) then if (xmnxlat.ge.XMLDEFS) then call err(' XML translations > XMLDEFS') else xmnxlat=xmnxlat+1 xmlate(xmnxlat)=xmtarg(1:lxmtarg) endif if (xmtyp.eq.'data') then ixmtyp = 1 if (xmdata.eq.0) then xmdata = xmnxlat else call warn(' XML duplicate DATA_ translation') endif endif if (xmtyp(1:lxmtyp).eq.'category') then ixmtyp = 2 nxmc = ndcname+1 call tbxxnlc(xxxtemp,xmtoken(1:lxmtoken)) call hash_store(xxxtemp, * dcname,dcchain,NUMDICT,ndcname,dchash,NUMHASH,kxmc) if( kxmc.eq.nxmc) then ccatkey(kxmc) = 0 xmcind(kxmc) = xmnxlat else if (xmcind(kxmc).ne.0) then call warn(' XML duplicate category translation') else xmcind(kxmc) = xmnxlat endif endif endif if (xmtyp.eq.'item') then ixmtyp = 3 if (tbxxnid(xmtoken(1:lxmtoken),ifind)) then xmindex(ifind) = xmnxlat else if (xmindex(ifind).ne.0) then call warn(' XML duplicate item translation') else ifind = aroot(ifind) 235 xmindex(ifind) = xmnxlat ifind = alias(ifind) if (ifind.ne.0) go to 235 endif endif endif if(loop_) then if(charnp_('_xml_mapping.token',xmtoken,lxmtoken)) then go to 230 else call err(' XML dictionary logic error') endif endif else call err(' XML target missing') endif else call err(' XML token_type missing') endif else xmtoken = bname(1:lbname) lxmtoken=lbname if(charnp_('_xml_mapping.token_type',xmtyp,lxmtyp)) then if(charnp_('_xml_mapping.target',xmtarg,lxmtarg)) then if (xmnxlat.ge.XMLDEFS) then call err(' XML translations > XMLDEFS') else xmnxlat=xmnxlat+1 xmlate(xmnxlat)=xmtarg(1:lxmtarg) endif if (xmtyp(1:lxmtyp).eq.'data') then ixmtyp = 1 if (xmdata.eq.0) then xmdata = xmnxlat else call warn(' XML duplicate DATA_ translation') endif endif if (xmtyp.eq.'category') then ixmtyp = 2 nxmc = ndcname+1 call tbxxnlc(xxxtemp,xmtoken(1:lxmtoken)) call hash_store(xxxtemp, * dcname,dcchain,NUMDICT,ndcname,dchash,NUMHASH,kxmc) if( kxmc.eq.nxmc) then ccatkey(kxmc) = 0 xmcind(kxmc) = xmnxlat else if (xmcind(kxmc).ne.0) then call warn(' XML duplicate category translation') else xmcind(kxmc) = xmnxlat endif endif endif if (xmtyp.eq.'item') then ixmtyp = 3 if (tbxxnid(xmtoken(1:lxmtoken),ifind)) then xmindex(ifind) = xmnxlat else if (xmindex(ifind).ne.0) then call warn(' XML duplicate item translation') else ifind = aroot(ifind) 240 xmindex(ifind) = xmnxlat ifind = alias(ifind) if (ifind.ne.0) go to 240 xmindex(ifind) = xmnxlat endif endif endif if(loop_) then call err(' XML dictionary logic error') endif else call err(' XML target missing') endif endif endif C C Process names C bxname = ' ' do i = 1,2 if(charnp_(nt(i),name,lstrg)) then if(intype.ne.0) * call warn(' Multiple DDL 1 and 2 name definitions ') intype = i bxname = name(1:lstrg) if(loop_) inloop = loopnl endif loop_ = .false. loopnl=0 enddo if(intype.eq.0.and.ictype.ne.3.and.(.not.glob_) * .and.bname(1:lbname).ne.' '.and.ixmtyp.eq.0) * call warn (' No name defined in block') loop_ = .false. if(charnp_(at(1),name,lstrg)) then iatype=1 call tbxxnlc(baname,name(1:lstrg)) batag = name(1:lstrg) lbaname = lstrg if(loop_) ialoop = loopnl endif loop_ = .false. loopnl=0 mcstrg = "no" if(ictype.ne.3) then do i=1,2 if(charnp_(tt(i),name,lstrg)) then if(ittype.ne.0) * call warn(' Multiple DDL 1 and 2 type definitions ') ittype = i call tbxxnlc(btname,name(1:lstrg)) if(loop_) itloop = loopnl endif loop_ = .false. loopnl=0 enddo do i = 1,2 if(charnp_(mc(i),name,lstrg)) then if (imtype.ne.0) * call warn(' Multiple DDL 1 and 2 mandatory codes ') imtype = i call tbxxnlc(mcstrg,name(1:lstrg)) if (loop_) imloop = loopnl endif loop_ = .false. loopnl=0 enddo endif C C Now test for consistent combinations C if(inloop.ne.-1) then if(icloop.ne.-1.and.icloop.ne.inloop * .and. catchk.eq.'yes') * call warn( * ' Categories and names in different loops') if(iatype.ne.0.and.ialoop.ne.inloop) then if(ialoop.eq.-1) then if(bxname.ne.bname(1:lbname)) * call warn( * ' One alias, looped names, linking to first') else call warn( * ' Aliases and names in different loops ' * //' only using first alias ') endif endif if(itloop.ne.-1.and.itloop.ne.inloop) * call warn( * ' Types and names in different loops') if(imloop.ne.-1.and.imloop.ne.inloop) * call warn( * ' Mandatory codes and names in different loops') else if(icloop.ne.-1) * call warn( * ' Multiple categories for one name') if(itloop.ne.-1) * call warn( * ' Multiple types for one name') if(imloop.ne.-1) * call warn( * ' Multiple madatory codes for one name') endif C C Pick up parents C do i = 1,2 220 if(charnp_(pt(i),bpname,lbpname)) then if (iptype.ne.0 .and. iptype.ne.i) * call warn * (' Multiple DDL 1 and 2 parent definitions ') iptype = i if(loop_) iploop = loopnl C C Seek the matching child, may be in the same loop or not C if (charnp_(pc(i),name,lstrg)) then nresult = tbxxnid(name(1:lstrg),ifind) nresult = tbxxnid(bpname(1:lbpname),dpindex(ifind)) bpname = ' ' lbpname = 1 endif if (loop_) go to 220 endif enddo C C Now we need to process value enumerations and ranges C and load them into item value table C if (tcheck .eq. 'yes' .and. bxname.ne.' ') then loop_ = .false. nresult = tbxxnid(bxname,ifind) do i = 1,2 5400 if(charnp_(ve(i),name,lstrg) .and. nivt.lt.NUMIVALS) then call tbxxsstb(name(1:lstrg),sindex) if (sindex.gt.0) then if (deindex(ifind).eq.0) then deindex(ifind)=nivt+1 else kivt = deindex(ifind) 5410 if (ivtnxt(kivt).ne.0) then kivt = ivtnxt(kivt) go to 5410 endif ivtnxt(kivt)=nivt+1 endif nivt = nivt+1 ivtnxt(nivt)=0 ivtvet(nivt)=0 ivtsbp(nivt)=sindex endif endif if (loop_) go to 5400 enddo do i = 1,2 loop_ = .false. 5420 strg_=' ' long_=1 nresult = test_(vr(i)) if (strg_(1:long_).ne.' '.and.type_.eq.'null') nresult = .true. if (nresult .and. nivt.lt.NUMIVALS) then nresult = charnp_(vr(i),name,lstrg) if (type_.ne.'char'.and.type_.ne.'numb') then name = '.' lstrg = 1 endif kvrtp = -1 if(i.eq.1 .and. lstrg NUMDICT ') endif if(mycat.eq.nmycat) ccatkey(mycat)=0 endif endif C C If it is the same loop as for types, we need to extract C the matching type C if(inloop.eq.itloop) then btname=' ' if(charnp_(ct(ittype),name,lstrg)) then call tbxxnlc(btname,name(1:lstrg)) lbtname=lstrg endif endif C C If it is the same loop as for mandatory codes, we need to extract C the matching mandatory C if(inloop.eq.imloop) then mcstrg='no' if(charnp_(mc(imtype),name,lstrg)) then call tbxxnlc(mcstrg,name(1:lstrg)) endif endif C C If it is the same loop as for aliases, we need to extract C the matching alias C if(inloop.eq.ialoop) then baname=' ' batag=' ' if(charnp_(at(1),name,lstrrg)) then call tbxxnlc(baname,name(1:lstrg)) batag = name(1:lstrg) lbaname = lstrg endif endif endif C C now we have a name stored in dicnam at location ifind C the index of the category in mycat, the type in btname, C the alias in baname, and the mandatory code in mcstrg C C First verify match between the name and category, if C we have one, or extract from the block name C if (mycat.eq.0) then if (dcindex(ifind).eq.0) then if (dicnam(ifind).eq.bloc_) then call tbxxcat(dicnam(ifind),bcname,lbcname) Cdbg call warn(' Extracting category name from block name ' Cdbg * //bloc_(1:max(1,lastnb(bloc_)))) if(bcname(1:1).ne.' ') then ictype = 1 nmycat = ndcname+1 call hash_store(bcname, * dcname,dcchain,NUMDICT,ndcname,dchash,NUMHASH,mycat) if(mycat.eq.0) then call err(' Dictionary category names > NUMDICT ') endif if (mycat.eq.nmycat) then ccatkey(mycat) = 0 xmcind(mycat) = 0 endif else if(catchk.eq.'yes') * call warn(' No category defined in block ' * //bloc_(1:max(1,lastnb(bloc_)))//' and name ' * //dictag(ifind)(1:max(1,lastnb(dicnam(ifind)))) * //' does not match') endif endif endif else if (bcname(1:lbcname).ne.'dictionary_definition' .and. * bcname(1:lbcname).ne.'category_overview') then if (dicnam(ifind)(1:lbcname+1).ne.'_'//bcname(1:lbcname) * .or.( dicnam(ifind)(lbcname+2:lbcname+2).ne.'_' .and. * dicnam(ifind)(lbcname+2:lbcname+2).ne.'.' .and. * dicnam(ifind)(lbcname+2:lbcname+2).ne.' ' )) then if (catchk.eq.'yes'.and.rfname(1:7).ne.'replace') * call warn(' Item name '// * dictag(ifind)(1:max(1,lastnb(dictag(ifind))))//' '// * ' does not match category name '//bcname(1:lbcname)) endif endif endif C C We will need the type in what follows. cif_mm.dic defines C some higher level types. We map them to primitive types C mapped = btname(1:4) do i = 1,16 if (btname(1:4).eq.map_type(i)) mapped = map_to(i) enddo if (mapped.ne.'char' .and. * mapped.ne.'text' .and. * mapped.ne.' ' .and. * mapped.ne.'null' .and. * mapped.ne.'numb' ) then if (tcheck .eq. 'yes') then call warn (' Item type '// * btname(1:max(1,lastnb(btname)))//' not recognized') mapped = 'char' endif endif C C There are two cases to consider, one if the name is new to C the dictionary, the other, if it is not C if(ifind.eq.kdict) then aroot(ifind)=ifind alias(ifind)=0 dcindex(ifind)=mycat dictyp(ifind)=mapped dicxtyp(ifind)=btname dmcode(ifind) = 0 if (mcstrg .eq. 'yes') dmcode(ifind) = 1 if (mcstrg .eq. 'implicit') dmcode(ifind) = -1 else if(dcindex(ifind).ne.mycat) then if(dcindex(ifind).eq.0) then jfind=ifind if (aroot(ifind).ne.0) jfind=aroot(ifind) 255 continue dcindex(jfind)=mycat jfind=alias(jfind) if(jfind.ne.0) goto 255 else if(mycat.ne.0.and. * (vcheck.eq.'yes'.or.tcheck.eq.'yes') * .and.catchk.eq.'yes') then if(rfname(1:7).ne.'replace') * call warn(' Attempt to redefine category for item') endif endif endif if(dictyp(ifind).ne.mapped .or. * dicxtyp(ifind).ne.btname) then if(dictyp(ifind).eq.' ') then jfind=ifind if (aroot(ifind).ne.0) jfind=aroot(ifind) 256 continue dictyp(jfind)=mapped dicxtyp(jfind)=btname jfind=alias(jfind) if(jfind.ne.0) go to 256 else if(mapped.ne.' '.and.tcheck.eq.'yes') * call warn(' Attempt to redefine type for item') endif endif if(dmcode(ifind).eq.0) then jfind = ifind if (aroot(ifind).ne.0) jfind = aroot(ifind) 257 continue dmcode(jfind) = 0 if (mcstrg.eq.'yes') dmcode(jfind) = 1 if (mcstrg.eq.'implicit') dmcode(jfind) = -1 jfind=alias(jfind) if(jfind.ne.0) go to 257 else if((mcstrg.eq.'yes' .and. dmcode(ifind).lt.0) .or. * (mcstrg.eq.'implicit' .and. dmcode(ifind).gt.0)) * call warn( * ' Attempt to redefine mandatory code for item') endif endif C C now deal with alias, if any. C if(baname.ne.' ') then if (tbxxnid(baname(1:lbaname),iafind)) then dictag(iafind) =batag aroot(iafind) =aroot(ifind) if(aroot(iafind).eq.0) aroot(iafind)=ifind catkey(iafind) =catkey(ifind) alias(ifind) =iafind dcindex(iafind) =dcindex(ifind) dictyp(iafind) =dictyp(ifind) dicxtyp(iafind) =dicxtyp(ifind) xmindex(iafind) =xmindex(ifind) dmcode(iafind) =dmcode(ifind) dpindex(iafind) =dpindex(ifind) deindex(iafind) =deindex(ifind) else if(aroot(iafind).ne.0 .and. * aroot(iafind).ne.iafind) then if(aroot(iafind).eq.ifind .or. * aroot(iafind).eq.aroot(ifind)) then call warn(' Duplicate definition of same alias') else call warn(' Conflicting definition of alias') endif else if((dcindex(iafind).eq.0.or. * dcindex(iafind).eq.dcindex(ifind)).and. * (dictyp(iafind).eq.' '.or. * (dictyp(iafind).eq.dictyp(ifind) .and. * dicxtyp(iafind).eq.dicxtyp(ifind)))) then dcindex(iafind) =dcindex(ifind) dictyp(iafind) =dictyp(ifind) dicxtyp(iafind) =dicxtyp(ifind) endif if(xmindex(iafind).eq.0) * xmindex(iafind)=xmindex(ifind) if(xmindex(ifind).eq.0) * xmindex(ifind)=xmindex(iafind) if (dmcode(iafind).eq.0) * dmcode(iafind)=dmcode(ifind) if (dmcode(ifind).eq.0) * dmcode(ifind)=dmcode(iafind) if (dpindex(iafind).eq.iafind * .and. dpindex(ifind).ne.ifind) * dpindex(iafind) = dpindex(ifind) if (dpindex(ifind).eq.ifind * .and. dpindex(iafind).ne.iafind) * dpindex(ifind) = dpindex(iafind) if (deindex(ifind).eq.0) * deindex(ifind)=deindex(iafind) if (deindex(iafind).eq.0) * deindex(iafind)=deindex(ifind) aroot(iafind) =aroot(ifind) if(aroot(iafind).eq.0) aroot(iafind)=ifind alias(ifind) =iafind if (catkey(iafind)) catkey(ifind) = .true. if (catkey(ifind)) catkey(iafind) = .true. endif endif endif if(inloop.ge.0) then baname = ' ' batag = ' ' endif C if(inloop.ge.0.and.loop_) go to 250 if(nmatch.eq.0) then if ((ksmatch.eq.0.or.inloop.lt.0) * .and.(rfname(1:7).ne.'replace')) then call warn(' No name in the block matches the block name') endif endif C C check for aliases C we execute this loop only in the case of unlooped name C with looped alias C if(inloop.lt.0.and.ialoop.ge.0) then loop_=.false. loopnl=0 ganame=baname 260 if(.not.charnp_(at(iatype),name,lstrg)) goto 200 call tbxxnlc(baname,name(1:lstrg)) batag=name(1:lstrg) lbaname=lstrg if(baname.eq.ganame) then if(loop_) go to 260 go to 200 endif if(baname.ne.' ') then if (tbxxnid(baname(1:lbaname),iafind)) then if(iafind.eq.0) call err(' CIFdic names > NUMDICT') dictag(iafind) =batag aroot(iafind) =aroot(ifind) if(aroot(iafind).eq.0) aroot(iafind)=ifind catkey(iafind) =catkey(ifind) alias(ifind) =iafind dcindex(iafind) =dcindex(ifind) dictyp(iafind) =dictyp(ifind) dicxtyp(iafind) =dicxtyp(ifind) xmindex(iafind) =xmindex(ifind) dmcode(iafind) =dmcode(ifind) dpindex(iafind) =dpindex(ifind) deindex(iafind) =deindex(ifind) ifind=iafind else if(aroot(iafind).ne.0 .and. * aroot(iafind).ne.iafind) then if(aroot(iafind).eq.ifind .or. * aroot(iafind).eq.aroot(ifind)) then call warn(' Duplicate definition of same alias') else call warn(' Conflicting definition of alias') endif else if((dcindex(iafind).eq.0.or. * dcindex(iafind).eq.dcindex(ifind)).and. * (dictyp(iafind).eq.' '.or. * (dictyp(iafind).eq.dictyp(ifind) .and. * dicxtyp(iafind).eq.dicxtyp(ifind)))) then dcindex(iafind) =dcindex(ifind) dictyp(iafind) =dictyp(ifind) dicxtyp(iafind) =dicxtyp(ifind) ifind=iafind endif if(xmindex(iafind).eq.0) * xmindex(iafind)=xmindex(ifind) if(xmindex(ifind).eq.0) * xmindex(ifind)=xmindex(iafind) if (dmcode(iafind).eq.0) * dmcode(iafind)=dmcode(ifind) if (dmcode(ifind).eq.0) * dmcode(ifind)=dmcode(iafind) if (dpindex(iafind).eq.iafind * .and. dpindex(ifind).ne.ifind) * dpindex(iafind) = dpindex(ifind) if (dpindex(ifind).eq.ifind * .and. dpindex(iafind).ne.iafind) * dpindex(ifind) = dpindex(iafind) if (deindex(ifind).eq.0) * deindex(ifind) = deindex(iafind) if (deindex(iafind).eq.0) * deindex(iafind) = deindex(ifind) aroot(iafind) =aroot(ifind) if(aroot(iafind).eq.0) aroot(iafind)=ifind alias(ifind) =iafind if (catkey(iafind)) catkey(ifind) = .true. if (catkey(ifind)) catkey(iafind) = .true. endif endif endif if(loop_) go to 260 endif go to 200 C 400 bloc_=' ' if (ndcname.ne.0) then do ii = idstrt+1,ndict keychain(ii) = 0 if (aroot(ii).eq.0.and.dcindex(ii).eq.0 * .and.catchk.eq.'yes') * call warn(' No category specified for name '// * dictag(ii)(1:max(1,lastnb(dicnam(ii))))) enddo endif do ii = idstrt+1,ndict if (dicxtyp(ii).eq.' ') then if (dpindex(ii).ne.ii * .and. dicxtyp(dpindex(ii)).ne.' ') then dicxtyp(ii) = dicxtyp(dpindex(ii)) dictyp(ii) = dicxtyp(dpindex(ii)) else dicxtyp(ii) = 'null' dictyp(ii) = 'null' if (tcheck.eq.'yes') then jj = lastnb(dicnam(ii)) if (jj.gt.0) then if (dicnam(ii)(jj:jj).ne.'_') * call warn(' No type specified for name '// * dictag(ii)(1:max(1,lastnb(dicnam(ii))))) endif endif endif endif if (catkey(ii) .or. dmcode(ii).gt.0) then ifind = aroot(ii) mycat = dcindex(ifind) if (mycat.ne.0) then jj = ccatkey(mycat) if (jj.eq.0) then ccatkey(mycat) = ifind else 410 if (keychain(jj).eq.0) then keychain(jj) = ifind keychain(ifind) = 0 else if(keychain(jj).ne.ifind) then jj = keychain(jj) goto 410 endif endif endif endif endif enddo if (.not.append_) then close(dirdev) nrecd=0 endif dictfl='no ' 500 continue if (append_) then nrecd=nrecds recend_=recends recbeg_=recbegs endif if(dict_) then dicname_=xdicnam dicver_ =xdicver else tcheck = otchk vcheck = ovchk endif if(tcheck.eq.'yes') vcheck='yes' Cdbg WRITE(6,'(i5,3x,a,2x,a)') (i,dicnam(i),dictyp(i),i=1,ndict) return end C C C C C C >>>>>> Create a new dictionary entry, or find a matching existing one C function tbxxnid(xname,ick) logical tbxxnid include 'ciftbx.sys' character xname*(*) character xxxtemp*(NUMCHAR) integer jck, ick, ilen tbxxnid = .true. ilen = lastnb(xname) jck = ndict call tbxxnlc(xxxtemp,xname(1:ilen)) call hash_store(xxxtemp, * dicnam,dicchain, * NUMDICT,ndict,dichash,NUMHASH,ick) if(ick.eq.0) call err(' CIFdic names > NUMDICT') if(ick .eq. jck+1) then dictag(ick) = xname(1:ilen) dictyp(ick) = ' ' dicxtyp(ick) = ' ' catkey(ick) = .false. dpindex(ick) = ick deindex(ick) = 0 alias(ick) = 0 aroot(ick) = ick keychain(ick) = 0 dcindex(ick) = 0 xmindex(ick) = 0 dmcode(ick) = 0 else tbxxnid = .false. endif return end C C C C C C >>>>>> Find matching existing dictionary entry if any C function tbxxoid(xname,ick) logical tbxxoid include 'ciftbx.sys' character xname*(*) character xxxtemp*(NUMCHAR) integer jck, ick, ilen tbxxoid = .true. ilen = lastnb(xname) jck = ndict call tbxxnlc(xxxtemp,xname(1:ilen)) call hash_find(xxxtemp, * dicnam,dicchain, * NUMDICT,ndict,dichash,NUMHASH,ick) if(ick.eq.0) tbxxoid = .false. return end C C C C C C >>>>>> Find position of last non_blank in a string C but never less than 1 C function lastnb(str) C integer lastnb include 'ciftbx.sys' character*(*) str integer lenn,ihi,itestl lenn = len(str) c ihi = lenn if(ihi.eq.0) then ihi = 1 go to 200 endif itestl = ihi/4 if (itestl.lt.4) go to 200 c 100 if (ihi.gt.itestl) then if (str(ihi-itestl+1:ihi-itestl+1).eq.' ') then if (str(ihi-itestl+1:ihi).eq.' ') then ihi = ihi-itestl go to 100 endif endif endif itestl = itestl/2 if (itestl.gt.3) go to 100 c 200 if (ihi.gt.1 .and. str(ihi:ihi).eq.' ') then ihi = ihi-1 go to 200 endif lastnb = ihi return end C C C C C C >>>>>> Convert a character to a radix XXRADIX digit C C given a character c, return a decimal value C function tbxxc2dig(c) integer tbxxc2dig character*(*) c include 'ciftbx.sys' C tbxxc2dig = ichar(c)-ichar(' ') C C The code above may not be portable, especially to non-ascii C computer systems. In that case, comment out the line above C and uncomment the following lines. Be sure to make the C matching change in tbxxd2chr. Be certain to have at least C XXRADIX characters in the search string. C C tbxxc2dig = index( C * '+-01234567890'// C * 'abcdefghijlmnopqrstuvwxyz'// C * 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',c)-1 return end C C C C C C >>>>>> Convert a radix XXRADIX digit to a character C C given an integer value, return a character C function tbxxd2chr(d) character*1 tbxxd2chr integer d include 'ciftbx.sys' C tbxxd2chr = char(d+ichar(' ')) C C The code above may not be portable, especially to non-ascii C computer systems. In that case, comment out the line above C and uncomment the following lines. Be sure to make the C matching change in tbxxc2dig. Be certain to have at least C XXRADIX characters in the search string. C C character*(XXRADIX) digits C digits = C * '+-01234567890'// C * 'abcdefghijlmnopqrstuvwxyz'// C * 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' C tbxxd2chr = digits(d+1:d+1) return end C C C C C C >>>>>> Convert a string to Run Length Encoded version C subroutine tbxxrle(astr,bstr,mlen) C C astr is the raw input string C bstr is the run-length-encoded string C beginning with the compressed length in C in base-XXRADIX in the first four characters C followed by either individual characters or run C flagged by XXFLAG C XXFLAG//tbxxd2chr(n)//c represents n copies of c C character*(*) astr, bstr include 'ciftbx.sys' character*1 c character*1 tbxxd2chr integer tbxxc2dig integer klen, krep, ialen, iblen, mode C ialen = len(astr) iblen = len(bstr) mode = 0 klen = 4 bstr(1:4) = tbxxd2chr(0)//tbxxd2chr(0) * //tbxxd2chr(0)//tbxxd2chr(0) do ii = 1,ialen c = astr(ii:ii) if (mode .eq. -2) then krep = tbxxc2dig(bstr(klen-1:klen-1)) if (c.eq.bstr(klen:klen).and.krep.lt.XXRADIX-1) then bstr(klen-1:klen-1) = tbxxd2chr(krep+1) else mode = 0 if (c.eq.bstr(klen:klen)) mode=-1 endif endif if (klen.ge.iblen) go to 100 if (mode .ge.-1 .and. mode .le.2) then klen = klen+1 bstr(klen:klen) = c if (klen .gt. 5) then if (c.eq.bstr(klen-1:klen-1)) mode=mode+1 if (c.ne.bstr(klen-1:klen-1)) mode=0 endif if (c.eq.XXFLAG .and. klen.lt.iblen-1) then bstr(klen+1:klen+2) = tbxxd2chr(1)//c mode = -2 klen = klen+2 endif endif if (mode.eq.2) then bstr(klen-2:klen-1) = XXFLAG//tbxxd2chr(3) mode = -2 endif enddo 100 mlen = klen do ii = 4,1,-1 bstr(ii:ii) = tbxxd2chr(mod(klen,XXRADIX)) klen = klen/XXRADIX enddo return end C C C C C C >>>>>> Decode a string from Run Length Encoded version C function tbxxrld(astr,bstr,fill) C C astr is the raw output string C bstr is the run-length-encoded string C beginning with the compressed length in C in base-XXRADIX in the first four characters C followed by either individual characters or run C flagged by char(0) C char(0)//char(n)//c represents n copies of c C fill is a logical variable, .true. to fill astr with blanks C the return value is the number of valid characters in astr C never less than 1 C C character*(*) astr, bstr logical fill integer tbxxrld include 'ciftbx.sys' character*1 c character*1 tbxxd2chr integer tbxxc2dig integer klen, krep, ialen, iblen, mode C ialen = len(astr) iblen = len(bstr) if (fill) then astr = ' ' else astr(1:1) = ' ' endif mode = 0 klen = 0 do ii = 1,4 klen = klen*XXRADIX+tbxxc2dig(bstr(ii:ii)) enddo mode = 0 ipos = 0 do ii = 5,klen c = bstr(ii:ii) if(mode.eq.0) then if(c.ne.XXFLAG) then if (ipos.ge.ialen) then tbxxrld = ialen return endif ipos = ipos+1 astr(ipos:ipos) = c else mode = 1 endif else if (mode.eq.1) then krep = tbxxc2dig(c) mode = -1 else do jj = 1,krep if (ipos.ge.ialen) return ipos=ipos+1 astr(ipos:ipos) = c enddo mode = 0 endif endif enddo if(ipos .lt. ialen) astr(ipos+1:ipos+1) = ' ' tbxxrld = max(ipos,1) return end C C C C C C >>>>>> Extract the item.category_id from a save frame name C subroutine tbxxcat(sfname,bcname,lbcname) C character*(*) sfname,bcname integer lbcname,ii,ic,lastnb,lenn C C Note that this logic works only for item.category_id C not for category.id C lenn = lastnb(sfname) bcname = ' ' lbcname = 1 if (lenn.eq.0.or.sfname(1:1).ne.'_') return do ii = 1,lenn-2 ic = 1+lenn-ii if (sfname(ic:ic).eq.'.') then bcname = sfname(2:ic-1) lbcname = ic-2 return endif enddo return end C C C C C C >>>>>> Fetch line from direct access file C subroutine tbxxflin(linno,lip,lipag,lipof,kip,ip,mip,mis) C include 'ciftbx.sys' C integer linno,lip,kip,ip,mip,mis C C linno -- the line number to locate C lip -- the location of the line C (page*(NUMCPP/NUMCIP)+offset) C lipag -- the page number (1...) C lipof -- the offset (1...) C kip -- subindex number C ip -- subindex offset C mip -- master index number C mis -- master index offset kip = (linno-1)/NUMSIP + 1 ip = mod(linno-1,NUMSIP) + 1 mip = (kip-1)/NUMMIP + 1 mis = mod(kip-1,NUMMIP) + 1 C C test subindex page number against number in memory C if (kip.ne.iabs(ipim)) then C C save the current subindex page if it has been written C if (ipim.lt.0) then do i = 1,NUMSIP write(scrbuf(NUMCIP*(i-1)+1:NUMCIP*i),'(i8)') * ippoint(i) enddo write(dirdev,'(a)',rec=iabs(iprim)) scrbuf ipim = -ipim endif C C find the appropriate master index page and slot C if (mip.ne.iabs(mipim)) then C C save the current master index page if it has been written C if (mipim.lt.0) then write(scrbuf(1:NUMCIP),'(i)')mipcp do i = 1,NUMMIP write(scrbuf(NUMCIP*i+1:NUMCIP*(i+1)),'(i8)') * mippoint(i) enddo write(dirdev,'(a)',rec=iabs(miprim))scrbuf mipim = -mipim endif C C search the master index pages for a match C mipno = 0 miprno = 1 kzero = 0 kmode = 1 10 read(dirdev,'(a)',rec=miprno) scrbuf mipno = mipno+1 read(scrbuf(1:NUMCIP),'(i8)') mipcp if (mipno.ne.mip) then if (mipcp.eq.0) then if (nfword.gt.1) then nfblock = nfblock+1 nfword = 1 endif mipcp = nfblock nfblock = nfblock+1 write(scrbuf(1:NUMCIP),'(i8)') mipcp write(dirdev,'(a)',rec=miprno) scrbuf scrbuf = ' ' write(scrbuf(1:NUMCIP),'(i8)') kzero write(dirdev,'(a)',rec=mipcp) scrbuf kmode = -1 endif miprno = mipcp go to 10 endif C C Have the master index in scrbuf, copy to mippoint C do i = 1,NUMMIP if (scrbuf(NUMCIP*i+1:NUMCIP*(i+1)).eq.' ') then mippoint(i) = 0 else read(scrbuf(NUMCIP*i+1:NUMCIP*(i+1)),'(i8)') * mippoint(i) endif enddo mipim =kmode* mip miprim = miprno endif C C See if the subindex page exists C if (mippoint(mis).eq.0) then do i = 1,NUMSIP ippoint(i) = 0 enddo if (nfword.gt.1) then nfblock=nfblock+1 nfword = 1 endif mippoint(mis) = nfblock mipim = -iabs(mipim) ipim = -kip iprim = -nfblock scrbuf = ' ' write(dirdev,'(a)', rec=nfblock) scrbuf nfblock = nfblock+1 else read(dirdev,'(a)', rec=mippoint(mis)) scrbuf do i = 1,NUMSIP if (scrbuf(NUMCIP*(i-1)+1:NUMCIP*i).eq.' ') then ippoint(i) = 0 else read(scrbuf(NUMCIP*(i-1)+1:NUMCIP*i),'(i8)') * ippoint(i) endif enddo ipim = kip iprim = mippoint(mis) endif endif lip = ippoint(ip) lipag = (lip-1)/(NUMCPP/NUMCIP) + 1 lipof = mod(lip-1,NUMCPP/NUMCIP) + 1 lipof = (lipof-1)*NUMCIP + 1 return end C C C C C C >>>>>> Store a string in the string table C subroutine tbxxsstb(astrg,sindex) C C store string astrg in the string table, returning the C index in sindex C character *(*) astrg integer sindex include 'ciftbx.sys' character *(MAXBUF) temp character *(MAXBUF) temp1 integer mlen, ii, ibstb, icstb, ikstb, rlen integer tbxxfstb call tbxxrle(astrg,temp,mlen) icstb = mod(nstable,NUMCSTB)+1 ibstb = (nstable+NUMCSTB)/NUMCSTB iestb = min(NUMCSTB,icstb+mlen-1) ikstb = iestb-icstb+1 if (mlen+nstable .le. NUMCSTB*NUMSTB) then stable(ibstb)(icstb:iestb)=temp(1:ikstb) sindex = nstable+1 nstable = nstable+mlen rlen = mlen - ikstb if (rlen .gt. 0) then do ii = ikstb+1,mlen,NUMCSTB ibstb = ibstb+1 iestb = min(NUMCSTB,rlen) stable(ibstb)(1:iestb) = temp(ii:ii+iestb-1) rlen = rlen - iestb enddo endif else sindex = 0 call warn( * ' More than NUMCSTB*NUMSTB stable characters needed') endif return end C C C C C C >>>>>> Fetch a string from the string table C function tbxxfstb(astrg,sindex,fill) C C fetch string astrg from the string table, starting at the C index in sindex, and returning the valid length. C C fill is a logical variable, .true. to fill astr with blanks C the return value is the number of valid characters in astr C never less than 1, unless there is no valid string integer tbxxfstb character *(*)astrg integer sindex logical fill integer tbxxc2dig, tbxxrld include 'ciftbx.sys' character *(MAXBUF) temp tbxxfstb = 0 if (sindex.le.0.or.nstable+3.gt.NUMCSTB*NUMSTB) return icstb = mod(sindex-1,NUMCSTB)+1 ibstb = (sindex-1+NUMCSTB)/NUMCSTB iestb = min(NUMCSTB,icstb+3) ikstb = iestb-icstb+1 temp(1:ikstb)=stable(ibstb)(icstb:iestb) rlen = 4-ikstb if (rlen .gt. 0) then temp(ikstb+1:4)=stable(ibstb+1)(1:rlen) endif klen = 0 do ii = 1,4 klen = klen*XXRADIX+tbxxc2dig(temp(ii:ii)) enddo if (klen.gt.MAXBUF.or.klen.le.0) return if (sindex+klen-1.gt.NUMCSTB*NUMSTB) return if (klen.gt.4) then icstb = mod(sindex+3,NUMCSTB)+1 ibstb = (sindex+3+NUMCSTB)/NUMCSTB iestb = min(NUMCSTB,icstb+klen-5) ikstb = iestb-icstb+1 temp(5:ikstb+4) = stable(ibstb)(icstb:iestb) rlen = klen - ikstb - 4 if (rlen .gt. 0) then do ii = ikstb+1,ikstb+rlen,NUMCSTB ibstb = ibstb+1 iestb = min(NUMCSTB,rlen) temp(ii:ii+iestb-1) = stable(ibstb)(1:iestb) rlen = rlen - iestb enddo endif endif tbxxfstb = tbxxrld(astrg,temp(1:klen),fill) return end C C C C C C >>>>>> Open a CIF and copy its contents into a direct access file. C function ocif_(fname) C logical ocif_ integer lastnb include 'ciftbx.sys' logical test character fname*(*) integer lfname integer case,i,kp,lp,mp,krpp,mpp C save_=.false. glob_=.false. jchar=MAXBUF lastch=0 if(line_.gt.MAXBUF) call err(' Input line_ value > MAXBUF') if(nrecd.ne.0 .and. (.not.append_)) then close(dirdev) nrecd=0 lrecd=0 endif C C clear the memory resident page buffer C do i = 1,NUMPAGE mppoint(i)=0 enddo C case=ichar('a')-ichar('A') tab=char(05) if(case.lt.0) goto 100 tab=char(09) bloc_=' ' C C....... Make sure the CIF is available to open C 100 file_(1:longf_)=' ' lfname = len(fname) file_(1:lfname) = fname do 120 i=1,lfname if(file_(i:i).eq.' ' .or. file_(i:i).eq.char(0) ) goto 140 120 continue 140 longf_=i-1 if (longf_.gt.0) then inquire(file=file_(1:longf_),exist=test) ocif_=test if(.not.ocif_) goto 200 else file_(1:1) = ' ' longf_ = 1 ocif_ = .true. endif C C....... Open up the CIF and a direct access formatted file as scratch C if (file_(1:1).ne.' ') * open(unit=cifdev,file=file_(1:longf_),status='OLD', * access='SEQUENTIAL', * form='FORMATTED') if(nrecd.eq.0) then open(unit=dirdev,status='SCRATCH',access='DIRECT', * form='FORMATTED',recl=NUMCPP) mipim = -1 miprim = 1 mipcp = 0 ipim = -1 iprim = 2 do i = 1,NUMPAGE mppoint(i) = 0 enddo do i = 1,NUMMIP mippoint(i) = 0 enddo mippoint(1)=2 do i = 1,NUMSIP ippoint(i) = 0 enddo nfblock = 3 nfword = 1 endif if (mppoint(1).lt.0) then write(dirdev,'(a)',rec=-mppoint(1)) pagebuf(1) mppoint(1) = 0 endif if(append_ .and. nrecd.ne.0) then kp = 1 lp = nfblock nfblock = nfblock+1 mppoint(kp) = lp mp = 1 else do kp = 1,NUMPAGE mppoint(kp)=0 enddo kp = 1 lp = 3 nfblock = 4 mp = 1 endif C C....... Copy the CIF to the direct access file C 160 read(cifdev,'(a)',end=180) buffer nrecd=nrecd+1 irecd=nrecd klen = lastnb(buffer(1:MAXBUF)) if (klen.gt.line_) * call warn(' Input line length exceeds line_') call tbxxrle(buffer(1:klen),scrbuf,mlen) if (mp+mlen-1 .gt. NUMCPP) then if (mp.lt.NUMCPP) pagebuf(kp)(mp:NUMCPP) = ' ' C write(dirdev,'(a)',rec=lp) pagebuf(kp) mppoint(kp)=-lp if (nfword.gt.1) then nfblock = nfblock+1 nfword = 1 endif lp = nfblock nfblock=nfblock+1 kp = kp+1 if(kp.gt.NUMPAGE) kp=1 if (mppoint(kp).lt.0) then write(dirdev,'(a)',rec=-mppoint(kp)) pagebuf(kp) endif mppoint(kp)=0 mp=1 endif pagebuf(kp)(mp:mp+mlen-1)=scrbuf(1:mlen) mppoint(kp) = -lp mlen = ((mlen+NUMCIP-1)/NUMCIP) mlen = mlen*NUMCIP call tbxxflin(nrecd,lip,lppag,lipof,kip,ip,mip,mis) ippoint(ip) = (mp-1)/NUMCIP+(lp-1)*(NUMCPP/NUMCIP)+1 ipim = -iabs(ipim) mp = mp+mlen goto 160 C 180 if (mp.lt.NUMCPP) pagebuf(kp)(mp:NUMCPP) = ' ' if (mp.gt.1) then C write(dirdev,'(a)',rec=lp) pagebuf(kp) mppoint(kp)=-lp endif lrecd=max(0,recbeg_-1) jrecd=max(0,recbeg_-1) jrect=-1 irecd=max(0,recbeg_-1) recn_=irecd recend_=nrecd if (file_(1:1).ne.' ') close(cifdev) 200 return end C C C C C C >>>>>> Close off direct access file of the current CIF C and reset all data name tables and pointers C subroutine purge_ C include 'ciftbx.sys' C integer i if(nrecd.ne.0) close(dirdev) do i = 1,NUMPAGE mppoint(i)=0 enddo do i = 1,MAXBOOK ibkmrk(1,i)=-1 ibkmrk(2,i)=-1 ibkmrk(3,i)=-1 ibkmrk(4,i)=-1 enddo recn_=0 save_=.false. glob_=.false. jchar=MAXBUF lastch=0 nrecd=0 lrecd=0 irecd=0 nname=0 nhash=0 iname=0 loopct=0 loopnl=0 loop_=.false. text_=.false. textfl='no ' append_=.false. recbeg_=0 recend_=0 nivt = 0 nstable = 0 return end C C C C C C >>>>>> Store the data names and pointers for the requested data block C function data_(name) C logical data_ logical wasave logical tbxxoid, nresult integer lastnb include 'ciftbx.sys' character name*(*),flag*4,temp*(NUMCHAR),ltype*4 character ctemp*(NUMCHAR) character xdname*(NUMCHAR) character ydname*(NUMCHAR) character isbuf*(MAXBUF),lsbuf*(MAXBUF) logical ixcat(NUMDICT) integer ndata,idata,nitem,npakt,i,ii,j,k,kchar,krecd integer jj,icc,idd integer fcatnum,lctemp,isrecd,isjchr,islast integer lsrecd,lsjchr,lslast integer pnname,itpos,ipp,ipj integer ltemp C jchar=MAXBUF nname=0 ndata=0 nhash=0 nitem=0 idata=0 iname=0 loopct=0 loopnl=0 ltype=' ' posnam_=0 posval_=0 posdec_=0 posend_=0 data_=.false. wasave=.false. loop_=.false. text_=.false. textfl='no ' glob_=.false. do ii = 1,MAXBOOK ibkmrk(1,ii)=-1 enddo irecd=lrecd lrecd=min(nrecd,recend_) if(name(1:1).ne.' ') irecd=max(0,recbeg_-1) call hash_init(dname,dchain,NUMBLOCK,nname,dhash, * NUMHASH) call hash_init(cname,cchain,NUMBLOCK,ncname,chash, * NUMHASH) isrecd=irecd isjchr=jchar islast=lastch lsrecd=isrecd lsjchr=isjchr lslast=islast isbuf=' ' if(lastch.gt.0)isbuf(1:lastch)=buffer(1:lastch) lsbuf=' ' if(lastch.gt.0)lsbuf(1:lastch)=isbuf(1:lastch) call tbxxnlc(xdname,name) C C....... Find the requested data block in the file C 100 lsjchr=isjchr call getstr isjchr=jchar if(irecd.ne.isrecd) then lsrecd=isrecd lslast=islast lsbuf=' ' if(islast.gt.0)lsbuf(1:islast)=isbuf(1:islast) isrecd=irecd islast=lastch isbuf=' ' if(lastch.gt.0)isbuf(1:lastch)=buffer(1:lastch) endif if(type_.eq.'fini') goto 500 if(type_.ne.'text') goto 120 110 call getlin(flag) if(buffer(1:1).ne.';') goto 110 jchar=2 goto 100 120 continue if(type_.eq.'save') then if(long_.lt.6) then if(.not.save_) * call err(' Save frame terminator found out of context ') wasave=.true. save_=.false. goto 100 else if(save_) * call err(' Prior save frame not terminated ') save_=.true. if(name.eq.' ') goto 150 call tbxxnlc(ydname,strg_(6:long_)) if(ydname.ne.xdname) goto 100 goto 150 endif endif if(type_.eq.'glob') then if(name.ne.' ') goto 100 glob_=.true. goto 150 endif if(type_.eq.'name'.or.type_.eq.'loop') then if(name.ne.' ') goto 100 if(.not.wasave) * call warn(' Data block header missing ') isrecd=lsrecd islast=lslast isjchr=lsjchr isbuf=' ' if(islast.gt.0)isbuf(1:islast)=lsbuf(1:islast) data_=.true. bloc_=' ' itpos=jchar-long_ if(tabx_) then itpos=0 do ipp=1,jchar-long_ itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo endif posnam_=itpos goto 204 endif if(type_.ne.'data') goto 100 if(name.eq.' ') goto 150 call tbxxnlc(ydname,strg_(6:long_)) if(ydname.ne.xdname) goto 100 150 data_=.true. bloc_=strg_(6:long_) itpos=jchar-long_ if(tabx_) then itpos=0 do ipp=1,jchar-long_ itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo endif posnam_=itpos C C....... Get the next token and identify C 200 call getstr Cdbg if(dictfl.eq.'no ') Cdbg * WRITE(6,*) ltype,type_,loop_,nitem,ndata,idata,iname,nname C if(ltype.ne.'name') goto 201 if(type_.eq.'numb') goto 203 if(type_.eq.'char') goto 203 if(type_.eq.'text') goto 203 if(type_.eq.'null') goto 203 if(type_.eq.'name'.and.loop_) goto 204 call err(' Illegal tag/value construction') 201 if(ltype.ne.'valu') goto 204 if(type_.eq.'numb') goto 202 if(type_.eq.'char') goto 202 if(type_.eq.'text') goto 202 if(type_.eq.'null') goto 202 goto 204 202 if(nitem.gt.0) goto 205 call err(' Illegal tag/value construction') 203 ltype='valu' goto 205 204 ltype=type_ C 205 if(type_.eq.'name') goto 206 if(type_.eq.'loop') goto 210 if(type_.eq.'data') goto 210 if(type_.eq.'save') goto 210 if(type_.eq.'glob') goto 210 if(type_.ne.'fini') goto 220 206 if(loop_) goto 270 210 if(nitem.eq.0) goto 215 C C....... End of loop detected; save pointers C npakt=idata/nitem if(npakt*nitem.ne.idata) call err(' Item miscount in loop') loopni(loopct)=nitem loopnp(loopct)=npakt nitem=0 idata=0 215 if(type_.eq.'name') goto 270 if(type_.eq.'data') goto 300 if(type_.eq.'save') goto 300 if(type_.eq.'glob') goto 300 if(type_.eq.'fini') goto 300 C C....... Loop_ line detected; incr loop block counter C loop_=.true. loopct=loopct+1 if(loopct.gt.NUMLOOP) call err(' Number of loop_s > NUMLOOP') loorec(loopct)=irecd loopos(loopct)=jchar-long_ if(quote_.ne.' ') loopos(loopct)=jchar-long_-1 itpos=0 do ipp=1,loopos(loopct) itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo loopox(loopct)=itpos goto 200 C C....... This is the data item; store char position and length C 220 if(loop_ .and. nitem.eq.0) * call err(' Illegal tag/value construction') loop_=.false. C i=nname if(nitem.gt.0) i=i-nitem+mod(idata,nitem)+1 if(i.lt.1) call err(' Illegal tag/value construction') if(dtype(i).ne.'test') goto 223 if(dictfl.eq.'yes') goto 223 if(tcheck.eq.'no ') goto 223 C>>>> if(long_.eq.1.and.strg_(1:1).eq.'?') goto 223 C>>>> if(long_.eq.1.and.strg_(1:1).eq.'.') goto 223 if(type_.eq.'null') goto 223 if(type_.eq.'numb') goto 223 call warn( ' Numb type violated '//dname(i)) 223 if(nitem.le.0) goto 224 idata=idata+1 if(dtype(i).eq.'null') dtype(i)=type_ if(dtype(i).eq.'numb' .and. * (type_.eq.'char'.or.type_.eq.'text')) dtype(i)='char' 224 if(nname.eq.ndata) goto 230 ndata=ndata+1 if(iloop(ndata).gt.1) goto 225 krecd=irecd kchar=jchar-long_-1 if(quote_.ne.' ')kchar=kchar-1 225 continue if(dtype(ndata).eq.' ') dtype(ndata)=type_ drecd(ndata)=krecd dchar(ndata)=kchar if(nloop(ndata).gt.0) goto 230 nloop(ndata)=0 iloop(ndata)=long_ C C....... Skip text lines if present C 230 if(type_.ne.'text') goto 200 if(nloop(ndata).eq.0) dchar(ndata)=0 if(nloop(ndata).eq.0) iloop(ndata)=long_ 250 call getlin(flag) if(buffer(1:1).eq.';') then jchar=2 goto 200 endif if(flag.eq.'fini') call err(' Unexpected end of data') goto 250 C C....... This is a data name; store name and loop parameters C 270 call tbxxclc(temp,ltemp,strg_(1:long_),long_) k=0 if(dictfl.ne.'yes' .and. ndict.gt.0) then nresult = tbxxoid(temp(1:ltemp),k) if(k.ne.0) then if(alias_ .and. aroot(k).ne.0) then temp=dicnam(aroot(k)) ltemp = lastnb(temp) endif endif endif pnname=nname call hash_store(temp(1:ltemp), * dname,dchain,NUMBLOCK,nname,dhash, * NUMHASH,j) if(j.eq.pnname+1) then dtag(j)=strg_(1:long_) if(k.ne.0) dtag(j)=dictag(k) trecd(j)=irecd tchar(j)=jchar-long_ if(quote_.ne.' ') tchar(j)=jchar-long_-1 itpos=0 do ipp=1,tchar(j) itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo xchar(j)=itpos endif if(j.eq.0) * call err(' Number of data names > NUMBLOCK') if(k.ne.0) then ltemp = lastnb(dicnam(k)) temp(1:ltemp) = dicnam(k)(1:ltemp) endif if(j.ne.pnname+1) then call warn(' Duplicate data item '// * temp(1:ltemp)) goto 200 endif dtype(nname)=' ' dxtyp(nname)=' ' cindex(nname)=0 ddict(nname)=0 ctemp(1:6)='(none)' lctemp=6 C if(dictfl.eq.'yes' .or. vcheck.eq.'no ') goto 290 j=k if(j.ne.0) then ddict(nname)=j cindex(nname)=dcindex(j) dxtyp(nname)=dicxtyp(j) dtype(nname)=dictyp(j) if(vcheck.eq.'no ') goto 280 if(dictyp(j).eq.'numb') then dtype(nname)='test' endif if(cindex(nname).ne.0) then lctemp=lastnb(dcname(cindex(nname))) ctemp(1:lctemp)=dcname(cindex(nname))(1:lctemp) goto 290 endif goto 280 endif call warn(' Data name '// * temp(1:ltemp) * //' not in dictionary!') 280 call tbxxcat(temp(1:ltemp),ctemp,lctemp) if (ctemp(1:lctemp).eq.' '.or. * ('_'//ctemp(1:lctemp).eq.temp(1:ltemp))) then ctemp = '(none)' lctemp= 6 if (ndcname.ne.0.and.vcheck.eq.'yes') * call warn(' No category defined for ' * //temp(1:ltemp)) else call hash_find(ctemp(1:lctemp), * dcname,dcchain,NUMDICT,ndcname,dchash,NUMHASH,j) if(j.ne.0) then cindex(nname) = j else ipj=ncname call hash_store(ctemp(1:lctemp), * cname,cchain,NUMBLOCK,ncname,chash,NUMHASH,j) if (j.eq.0) * call err(' Number of categories > NUMBLOCK ') cindex(nname) = -j if (ndcname.gt.0.and.j.eq.ipj+1.and.vcheck.eq.'yes' * .and.catchk.eq.'yes') * call warn(' Category '// * ctemp(1:lctemp)//' first implicitly defined in cif ') endif endif C 290 lloop(nname)=0 nloop(nname)=0 iloop(nname)=0 if (nitem.eq.0) fcatnum=cindex(nname) if(.not.loop_) goto 200 nitem=nitem+1 if(nitem.gt.NUMITEM) * call err(' Items per loop packet > NUMITEM') nloop(nname)=loopct iloop(nname)=nitem if (fcatnum.ne.cindex(nname)) then temp = '(none)' if (fcatnum.gt.0) temp=dcname(fcatnum) if (fcatnum.lt.0) temp=cname(-fcatnum) ltemp = lastnb(temp) if (ctemp(1:lctemp).ne.temp(1:ltemp) * .and.catchk.eq.'yes') * call warn (' Heterogeneous categories in loop '// * ctemp(1:lctemp)//' vs '// * temp(1:ltemp)) fcatnum=cindex(nname) endif goto 200 300 continue C C....... Are names checked against dictionary? C if(dictfl.eq.'yes') goto 500 if(vcheck.eq.'no '.or.ndict.eq.0) goto 500 do i=1,nname if(dtype(i).eq.'test') dtype(i)='numb' enddo C C prepare for category and parent checks C if ((catchk.eq.'yes'.or.parchk.eq.'yes') * .and. ndict.gt.0) then do i = 1,ndict ixcat(i) = .false. enddo C C make a pass marking all used tags and their aliases C do i = 1,nname icc=cindex(i) idd=ddict(i) if(icc.ne.0.and.idd.ne.0) then icc = aroot(idd) 310 ixcat(icc) = .true. icc = alias(icc) if (icc.ne.0) goto 310 endif enddo endif C C check for category keys C C C C now make a pass making certain the keys are C used C if(catchk.eq.'yes' .and. ndict.gt.0) then do i = 1,nname idd=cindex(i) if (idd.gt.0) then icc=ccatkey(idd) if(icc.ne.0) then if(aroot(icc).ne.0) icc=aroot(icc) 320 if(icc.ne.0) then if(.not.ixcat(icc)) then jj = irecd irecd = drecd(i) if (catkey(icc)) then call warn(' Category key '// * dictag(icc)(1:lastnb(dictag(icc)))// * ' not given for '// * dcname(idd)(1:lastnb(dcname(idd)))) else call warn(' Mandatory item '// * dictag(icc)(1:lastnb(dictag(icc)))// * ' not given for '// * dcname(idd)(1:lastnb(dcname(idd)))) endif ixcat(icc) = .true. irecd = jj endif icc = keychain(icc) if(icc.ne.0) go to 320 endif endif endif enddo endif C C check for parents of tags that are used C if(parchk.eq.'yes' .and. ndict.gt.0) then do i = 1,nname if (ddict(i).ne.0) then if (dpindex(ddict(i)).ne.ddict(i)) then if (.not.ixcat(dpindex(ddict(i)))) then call warn(' Parent '// * dicnam(dpindex(ddict(i))) * (1:lastnb(dicnam(dpindex(ddict(i)))))// * ' of '// * dname(i)(1:lastnb(dname(i))) // * ' not given') endif endif endif enddo endif C C....... End of data block; tidy up loop storage C 500 lrecd=irecd-1 if(type_.eq.'save'.and.long_.lt.6) then itpos=jchar-long_ if(tabx_) then itpos=0 do ipp=1,jchar-long_ itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo endif posval_=itpos endif irecd=isrecd jchar=isjchr lastch=islast recn_=irecd buffer(1:1)=' ' if(lastch.gt.0)buffer(1:min(MAXBUF,lastch))=isbuf(1:lastch) jrecd=irecd loop_=.false. loopct=0 if(ndata.ne.nname) call err(' Syntax construction error') C Cdbg WRITE(6,'(a)') Cdbg * ' data name type recd char loop leng' Cdbg WRITE(6,'(a,1x,a,4i5)') (dname(i),dtype(i),drecd(i),dchar(i), Cdbg * nloop(i),iloop(i),i=1,nname) Cdbg WRITE(6,'(3i5)') (i,loopni(i),loopnp(i),i=1,loopct) C return end C C C C C C >>>>>> Check dictionary for data name validation C function dtype_(name,type) C logical dtype_, tbxxoid, nresult include 'ciftbx.sys' integer nln, ii character name*(*),temp*(NUMCHAR), * type*4 C character*4 map_type(16),map_to(16),mapped data map_type * /'floa','int ','yyyy','symo','ucha','ucod','name','idna', * 'any ','code','line','ulin','atco','fax ','phon','emai'/ data map_to * /'numb','numb','char','char','char','char','char','char', * 'char','char','char','char','char','char','char','char'/ C type = ' ' dtype_ = .false. nln = min(len(name),len(temp)) call tbxxnlc(temp(1:nln),name) if (ndict.eq.0) go to 200 nresult = tbxxoid(temp(1:nln),xdchk) if(xdchk.eq.0) go to 200 mapped = dictyp(xdchk)(1:4) do ii = 1,16 if (dictyp(xdchk)(1:4).eq.map_type(ii)) mapped = map_to(ii) enddo type = mapped dtype_ = .true. 200 continue return end C C C C C C C >>>>>> Get the attributes of data item associated with data name C function test_(temp) C logical test_ include 'ciftbx.sys' character temp*(*),name*(NUMCHAR) integer lname character otestf*3 C otestf=testfl testfl='yes' call tbxxclc(name,lname,temp,len(temp)) test_=.true. if(otestf.eq.'no ' .or. type_.eq.' ') goto 100 if(name(1:lname).eq.nametb(1:lnametb)) goto 200 100 call tbxxgitm(name(1:lname)) 200 list_ =loopnl if(type_.eq.'null') test_=.false. return end C C C C C C >>>>>> Set or Reference a bookmark C function bkmrk_(mark) C logical bkmrk_ include 'ciftbx.sys' C integer mark,ii,nitem character*4 flag bkmrk_=.true. if(mark.eq.0) then do ii=1,MAXBOOK if(ibkmrk(1,ii).lt.0) goto 100 enddo bkmrk_=.false. call warn(' More than MAXBOOK bookmarks requested') return 100 mark=ii ibkmrk(1,ii)=iname ibkmrk(2,ii)=irecd ibkmrk(3,ii)=jchar if(iname.gt.0) then ibkmrk(2,ii) = trecd(iname) ibkmrk(3,ii) = tchar(iname) endif ibkmrk(4,ii)=0 if(iname.gt.0) then if(nloop(iname).ne.0.and. * loopnl.eq.nloop(iname).and.loopct.ne.0) then nitem=loopni(nloop(iname)) ibkmrk(2,ii)=looprd(1) ibkmrk(3,ii)=max(0,loopch(1)-1) ibkmrk(4,ii)=loopct endif endif else if(ibkmrk(1,mark).lt.0) then bkmrk_=.false. return endif iname=ibkmrk(1,mark) irecd=ibkmrk(2,mark) loopct=ibkmrk(4,mark) loop_=.false. text_=.false. textfl = 'no ' loopnl=-1 testfl='no ' if(iname.gt.0) then if(nloop(iname).ne.0.and.loopct.ne.0) then nitem=loopni(nloop(iname)) looprd(nitem+1)=ibkmrk(2,mark) loopch(nitem+1)=ibkmrk(3,mark) do ii = 1,nitem lloop(ii+iname-iloop(iname))=loopct-1 enddo loopct=loopct-1 if(lloop(iname).gt.0) then loop_=.true. loopnl=nloop(iname) endif endif endif jchar=MAXBUF if(irecd.gt.0) then irecd=irecd-1 call getlin(flag) jchar=ibkmrk(3,mark) endif ibkmrk(1,mark)=-1 mark=0 endif return end C C C C C C C >>>>>> Find the location of the requested item in the CIF C The argument "name" may be a data item name, blank C for the next such item. The argument "type" may be C blank for unrestricted acceptance of any non-comment C string (use cmnt_ to see comments), including loop headers, C "name" to accept only the name itself and "valu" C to accept only the value, or "head" to position to the C head of the CIF. Except when the "head" is requested, C the position is left after the data item provided. C function find_(name,type,strg) C logical find_ include 'ciftbx.sys' character name*(*),type*(*),strg*(*),flag*4 character jjbuf*(MAXBUF) integer jjchar,jjrecd,jjlast,jjlrec,jjjrec C find_ = .false. strg = ' ' long_ = 0 jjchar = jchar jjrecd = lrecd jjlast = lastch jjlrec = lrecd jjjrec = jrecd jjbuf = ' ' if(lastch.gt.0) jjbuf(1:lastch)=buffer(1:lastch) if(type.eq.'head') then lrecd = min(nrecd,recend_) irecd = max(0,recbeg_-1) jchar=MAXBUF+1 call getlin(flag) if(flag.eq.'fini') goto 300 find_=.true. lrecd=max(0,recbeg_-1) return endif if(name.ne.' ') then testfl='no ' call tbxxgitm(name) if(iname.eq.0) goto 300 if(type.eq.'valu') then list_=loopnl strg=strg_(1:long_) find_=.true. return endif if(type.eq.'name'.or.loopnl.eq.0) then irecd=trecd(iname)-1 call getlin(flag) jchar=tchar(iname) posnam_=jchar+1 call getstr strg=strg_(1:long_) recn_=irecd find_=.true. return endif if(type.eq.' ') then irecd=loorec(loopnl)-1 call getlin(flag) jchar=loopos(loopnl) call getstr posval_=loopos(loopnl) if(tabx_) posval_=loopox(loopnl) strg=strg_(1:long_) recn_=irecd find_=.true. return endif call err(' Call to find_ with invalid arguments') endif if(name.eq.' ') then 200 call getstr if(type_.eq.'fini') goto 300 if(type.ne.' '.and. * (type_.eq.'data'.or.type_.eq.'save'.or. * type_.eq.'glob')) goto 300 if(type.eq.'name'.and.type_.ne.'name') goto 200 if(type.eq.'valu'.and. * type_.ne.'numb'.and.type_.ne.'text' * .and.type_.ne.'char'.and.type_.ne.'null') goto 200 find_=.true. strg=strg_(1:long_) if(type_.eq.'name') then posnam_=jchar-long_ else posval_=jchar-long_ if(quote_.ne.' ') posval_=posval_-1 endif recn_=irecd return endif C C Search failed, restore pointers C 300 irecd = jjrecd lastch = jjlast lrecd = jjlrec jchar = jjchar buffer(1:1) = ' ' if(lastch.gt.0)buffer(1:min(MAXBUF,lastch))=jjbuf(1:lastch) jrecd = jjjrec if(jrecd.ne.irecd) jrecd=-1 recn_ = irecd C return end C C C C C C C >>>>>> Get the next data name in the data block C function name_(temp) C logical name_ include 'ciftbx.sys' character temp*(*) C name_=.false. temp=' ' iname=iname+1 if(iname.gt.nname) goto 100 name_=.true. temp=dtag(iname) if(ddict(iname).ne.0) temp=dictag(ddict(iname)) 100 return end C C C C C C C >>>>>> Extract a number data item and its standard deviation C This version return single precision numbers C function numb_(temp,numb,sdev) C logical numb_ include 'ciftbx.sys' character temp*(*),name*(NUMCHAR) integer lname real numb,sdev C call tbxxclc(name,lname,temp,len(temp)) if(testfl.eq.'no ') goto 100 if(name(1:lname).eq.nametb(1:lnametb)) goto 150 C 100 call tbxxgitm(name(1:lname)) C 150 numb_=.false. if(type_.ne.'numb') goto 200 numb_=.true. numb =numbtb if(sdevtb.ge.0.0) sdev=sdevtb C 200 testfl='no ' return end C C C C C C C >>>>>> Extract a number data item and its standard deviation C This version returns double precision numbers C function numd_(temp,numb,sdev) C logical numd_ include 'ciftbx.sys' character temp*(*),name*(NUMCHAR) integer lname double precision numb,sdev C call tbxxclc(name,lname,temp,len(temp)) if(testfl.eq.'no ') goto 100 if(name(1:lname).eq.nametb(1:lnametb)) goto 150 C 100 call tbxxgitm(name(1:lname)) C 150 numd_=.false. if(type_.ne.'numb') goto 200 numd_=.true. numb =numbtb if(sdevtb.ge.0.0) sdev=sdevtb C 200 testfl='no ' return end C C C C C C C >>>>>> Extract a character data item. C function char_(temp,strg) C logical char_, charnp_ include 'ciftbx.sys' character temp*(*), strg*(*) integer lstrg,nstrg nstrg = len(strg) char_ = charnp_(temp,strg,lstrg) if (lstrg.lt.len(strg)) strg(lstrg+1:nstrg) = ' ' return end C >>>>>> Extract a character data item. C function ochar_(temp,strg) C logical ochar_ include 'ciftbx.sys' character temp*(*),name*(NUMCHAR) character strg*(*),flag*4 character*1 slash integer icpos,itpos,ixpos,ixtpos,ipp,iepos,ispos integer ltemp, lname C slash = '\\' ltemp = lastnb(temp) call tbxxclc(name,lname,temp,ltemp) if(testfl.eq.'yes') goto 100 if(.not.text_) goto 120 if(name(1:lname).ne.nametb(1:lnametb)) goto 120 ochar_=.false. text_=.false. strg=' ' long_=0 call getlin(flag) if(flag.eq.'fini') goto 200 if(buffer(1:1).eq.';') then jchar=2 textfl = 'no ' goto 200 endif quote_=' ' jchar=lastch+1 long_=max(1,lastch) strg_(1:long_)=buffer(1:long_) goto 150 C 100 if(name(1:lname).eq.nametb(1:lnametb)) goto 150 C 120 call tbxxgitm(name(1:lname)) if(type_.eq.'null') then ochar_=.false. text_=.false. textfl = 'no ' strg_=' ' long_=0 goto 200 endif C 150 ochar_=.true. text_=.false. if(tabx_) then call detab icpos=jchar-long_ if(quote_.ne.' ') icpos=icpos-1 iepos=icpos+long_-1 itpos=0 do ipp=1,icpos itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo ispos=itpos 160 ixpos=index(buffer(icpos:iepos),tab) ixtpos=itpos+ixpos-1 if(ixpos.gt.0.and.ixtpos.le.MAXBUF) then ixtpos=((ixtpos+7)/8)*8 icpos=icpos+ixpos itpos=ixtpos+1 if(icpos.le.iepos) goto 160 else strg = * bufntb(ispos:min(MAXBUF,itpos+iepos-icpos)) long_=min(MAXBUF,itpos+iepos-icpos)-ispos+1 if(ispos.eq.1.and.strg(1:1).eq.';') then strg(1:1) = ' ' if(strg(1:long_).eq.(' '//slash)) then fold_=.true. if(unfold_) then strg_(1:long_)=slash long_=1 endif endif endif endif else strg=' ' if(long_.gt.0) then strg=strg_(1:long_) endif endif if(type_.eq.'char') goto 200 ochar_=.false. if(type_.ne.'text') goto 200 ochar_=.true. call getlin(flag) jchar=MAXBUF+1 if(flag.eq.'fini') goto 200 if(buffer(1:1).eq.';')then jchar=2 textfl = 'no ' goto 200 endif irecd=irecd-1 text_=.true. if (long_.gt.0) then if (unfold_ .and. strg(long_:long_).eq.slash) then 170 klow = long_ long_ = long_-1 call getlin(flag) if(flag.eq.'fini') goto 210 if(buffer(1:1).eq.';') then jchar=2 textfl = 'no ' goto 210 endif quote_=' ' jchar=lastch+1 long_=min(len(strg_),klow+max(1,lastch)-1) strg_(klow:long_)=buffer(1:max(1,lastch)) if(tabx_) then call detab icpos=jchar-long_ if(quote_.ne.' ') icpos=icpos-1 iepos=icpos+long_-1 itpos=0 do ipp=1,icpos itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo ispos=itpos 180 ixpos=index(buffer(icpos:iepos),tab) ixtpos=itpos+ixpos-1 if(ixpos.gt.0.and.ixtpos.le.MAXBUF) then ixtpos=((ixtpos+7)/8)*8 icpos=icpos+ixpos itpos=ixtpos+1 if(icpos.le.iepos) goto 180 else if (ispos.eq.1 .and. bufntb(1:1).eq.';') go to 210 long_=min(len(strg_),klow+itpos+iepos-icpos-ispos) strg(klow:long_) = * bufntb(ispos:min(MAXBUF,itpos+iepos-icpos)) endif else strg(long_:long_)=' ' if(lastch.gt.0) then long_=min(len(strg),klow+lastch-1) if(long_.ge.klow) strg(klow:long_)=buffer(1:lastch) endif endif if( strg(long_:long_).eq.slash ) go to 170 endif endif C 200 testfl='no ' return C 210 text_ = .false. go to 200 C end C C C C C C >>>>>> Extract a character data item, no padding. C function charnp_(temp,strg,lstrg) C logical charnp_ include 'ciftbx.sys' character temp*(*),name*(NUMCHAR) character strg*(*),flag*4 integer lstrg character*1 slash integer icpos,itpos,ixpos,ixtpos,ipp,iepos,ispos integer ltemp, lname C slash = '\\' ltemp = lastnb(temp) call tbxxclc(name,lname,temp,ltemp) if(testfl.eq.'yes') goto 100 if(.not.text_) goto 120 if(name(1:lname).ne.nametb(1:lnametb)) goto 120 charnp_=.false. text_=.false. strg(1:1)=' ' long_=0 lstrg = 1 call getlin(flag) if(flag.eq.'fini') goto 200 if(buffer(1:1).eq.';') then jchar=2 textfl = 'no ' goto 200 endif quote_=' ' jchar=lastch+1 long_=max(1,lastch) strg_(1:long_)=buffer(1:long_) goto 150 C 100 if(name(1:lname).eq.nametb(1:lnametb)) goto 150 C 120 call tbxxgitm(name(1:lname)) if(type_.eq.'null') then charnp_=.false. text_=.false. textfl = 'no ' strg_=' ' long_=0 goto 200 endif C 150 charnp_=.true. text_=.false. if(tabx_) then call detab icpos=jchar-long_ if(quote_.ne.' ') icpos=icpos-1 iepos=icpos+long_-1 itpos=0 do ipp=1,icpos itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo ispos=itpos 160 ixpos=index(buffer(icpos:iepos),tab) ixtpos=itpos+ixpos-1 if(ixpos.gt.0.and.ixtpos.le.MAXBUF) then ixtpos=((ixtpos+7)/8)*8 icpos=icpos+ixpos itpos=ixtpos+1 if(icpos.le.iepos) goto 160 else strg = * bufntb(ispos:min(MAXBUF,itpos+iepos-icpos)) long_=min(MAXBUF,itpos+iepos-icpos)-ispos+1 if(ispos.eq.1.and.strg(1:1).eq.';') then strg(1:1) = ' ' if(strg(1:long_).eq.(' '//slash)) then fold_=.true. if(unfold_) then strg_(1:long_)=slash long_=1 endif endif endif endif else strg(1:1)=' ' lstrg = 1 if(long_.gt.0) then strg=strg_(1:long_) lstrg = long_ endif endif if(type_.eq.'char') goto 200 charnp_=.false. if(type_.ne.'text') goto 200 charnp_=.true. call getlin(flag) jchar=MAXBUF+1 if(flag.eq.'fini') goto 200 if(buffer(1:1).eq.';')then jchar=2 textfl = 'no ' goto 200 endif irecd=irecd-1 text_=.true. if (long_.gt.0) then if (unfold_ .and. strg(long_:long_).eq.slash) then 170 klow = long_ long_ = long_-1 call getlin(flag) if(flag.eq.'fini') goto 210 if(buffer(1:1).eq.';') then jchar=2 textfl = 'no ' goto 210 endif quote_=' ' jchar=lastch+1 long_=min(len(strg_),klow+max(1,lastch)-1) strg_(klow:long_)=buffer(1:max(1,lastch)) if(tabx_) then call detab icpos=jchar-long_ if(quote_.ne.' ') icpos=icpos-1 iepos=icpos+long_-1 itpos=0 do ipp=1,icpos itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo ispos=itpos 180 ixpos=index(buffer(icpos:iepos),tab) ixtpos=itpos+ixpos-1 if(ixpos.gt.0.and.ixtpos.le.MAXBUF) then ixtpos=((ixtpos+7)/8)*8 icpos=icpos+ixpos itpos=ixtpos+1 if(icpos.le.iepos) goto 180 else if (ispos.eq.1 .and. bufntb(1:1).eq.';') go to 210 long_=min(len(strg_),klow+itpos+iepos-icpos-ispos) strg(klow:long_) = * bufntb(ispos:min(MAXBUF,itpos+iepos-icpos)) endif else strg(long_:long_)=' ' if(lastch.gt.0) then long_=min(len(strg),klow+lastch-1) if(long_.ge.klow) strg(klow:long_)=buffer(1:lastch) endif endif if( strg(long_:long_).eq.slash ) go to 170 endif endif C 200 testfl='no ' if(long_.eq.0) strg(1:1)=' ' lstrg = max(1,long_) return C 210 text_ = .false. go to 200 C end C C C C C C C >>>>>> Extract a comment field. C function cmnt_(strg) C logical cmnt_ integer lastnb include 'ciftbx.sys' character strg*(*),flag*4,c*1, * jjbuf*(MAXBUF) integer jjchar,jjrecd,jjlast,jjlrec,jjjrec integer ipp,itpos,ixpos integer klow character*1 slash C jjchar = jchar jjrecd = irecd jjlast = lastch jjlrec = lrecd jjjrec = jrecd jjbuf=' ' slash = '\\' if(lastch.gt.0)jjbuf(1:lastch)=buffer(1:lastch) lrecd = nrecd if(bloc_.eq.' ') then if(irecd.eq.0) jchar=MAXBUF endif strg=' ' long_=0 cmnt_=.false. goto 105 100 jchar=jchar+1 105 if(jchar.le.lastch) goto 140 C C....... Read a new line C 110 call getlin(flag) if(flag.eq.'fini') then strg='fini' jchar=MAXBUF+1 long_=4 cmnt_=.false. return endif jchar=1 strg=char(0) long_=1 posnam_=0 quote_=' ' goto 220 140 if(lastch.eq.1.and.buffer(1:1).eq.' ') go to 200 C C....... Process this character in the line C 150 c=buffer(jchar:jchar) if(c.eq.' ') goto 100 if(c.eq.tab.and.(.not.tabx_)) goto 190 if(c.eq.tab) goto 100 if(c.eq.'#') goto 200 goto 300 C C For a tab, when not expanding to blanks, accept C that single character as a comment C 190 long_=1 strg=tab posnam_=jchar jchar=jchar+1 goto 220 C C....... Accept the remainder of the line as a comment C 200 long_=lastch-jchar quote_=buffer(jchar:jchar) itpos=jchar if(tabx_) then itpos=0 do ipp=1,jchar itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo endif 210 posnam_=itpos if(long_.gt.0) then if(tabx_) then call detab ixpos= lastnb(bufntb) strg = bufntb(itpos+1:ixpos) else strg = buffer(jchar+1:lastch) endif endif if(long_.le.0) then strg=' ' long_=1 endif if (strg.eq.slash .and. unfold_) go to 390 jchar=MAXBUF+1 220 lrecd=jjlrec cmnt_=.true. return C C....... Found a non-comment field, restore pointers C 300 irecd = jjrecd lastch = jjlast lrecd = jjlrec jchar = jjchar buffer(1:1)=' ' if(lastch.gt.0)buffer(1:min(MAXBUF,lastch))=jjbuf(1:lastch) jrecd=jjjrec if(jrecd.ne.irecd) jrecd=-1 recn_=irecd return C C....... Got a comment with a folding flag C 390 klow = 1 lrecd=jjlrec cmnt_=.true. strg(1:1)=' ' 400 jjchar = MAXBUF+1 lrecd = nrecd if(bloc_.eq.' ') then if(irecd.eq.0) jchar=MAXBUF endif long_=0 go to 420 410 jchar=jchar+1 if(jchar.le.lastch) go to 450 420 call getlin(flag) jchar = 1 jjchar = 1 if(flag.eq.'fini') then strg='fini' jchar=MAXBUF+1 long_=lastnb(strg) return endif jchar=1 450 if(lastch.eq.1.and.buffer(1:1).eq.' ') go to 400 C C....... Process this character in the line C 460 c=buffer(jchar:jchar) if(c.eq.' '.or.c.eq.tab) goto 410 if(c.eq.'#') goto 470 goto 500 C C....... Accept the remainder of the line as part of the comment C 470 long_=lastch-jchar itpos=jchar if(tabx_) then itpos=0 do ipp=1,jchar itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo endif if(long_.gt.0) then if(tabx_) then call detab ixpos= lastnb(bufntb) if(ixpos.gt.itpos) * strg(klow:min(len(strg),klow+ixpos-2)) = * bufntb(itpos+1:ixpos) else if(lastch.gt.jchar) * strg(klow:min(len(strg),klow+lastch-2)) = * buffer(jchar+1:lastch) endif endif klow=lastnb(strg) if (strg(klow:klow).eq.slash) then strg(klow:klow)=' ' go to 400 endif jchar=MAXBUF+1 long_ = klow lrecd=jjlrec return C C....... Found a non-comment field, restore pointers, but return the C comment found so far C 500 jchar = jjchar return end C C C C C C >>>>> Convert name string to lower case C function locase(name) C include 'ciftbx.sys' character locase*(MAXBUF) character temp*(MAXBUF),name*(*) character low*26,cap*26,c*1 integer i,j,kln data cap /'ABCDEFGHIJKLMNOPQRSTUVWXYZ'/ data low /'abcdefghijklmnopqrstuvwxyz'/ C temp=name kln = lastnb(name) do 100 i=1,kln c=temp(i:i) j=index(cap,c) if(j.ne.0) temp(i:i)=low(j:j) 100 continue 200 locase=temp return end C C C C C C >>>>> Convert name string to lower case as subroutine C subroutine tbxxnlc(loname, name) C include 'ciftbx.sys' character temp*(MAXBUF),loname*(*),name*(*) character low*26,cap*26,c*1 integer i,j,kln integer lolen,olen data cap /'ABCDEFGHIJKLMNOPQRSTUVWXYZ'/ data low /'abcdefghijklmnopqrstuvwxyz'/ C lolen = len(loname) olen = len(name) kln = min(MAXBUF,lolen,olen) kln = lastnb(name(1:kln)) temp(1:kln)=name(1:kln) do 100 i=1,kln c=temp(i:i) j=index(cap,c) if(j.ne.0) temp(i:i)=low(j:j) 100 continue 200 loname=temp(1:kln) return end C C C C C C >>>>> Convert counted name string to lower case as subroutine C with counts C subroutine tbxxclc(loname, lloname, name, lname) C include 'ciftbx.sys' character temp*(MAXBUF),loname*(*),name*(*) integer lloname, lname character low*26,cap*26,c*1 integer i,j,kln integer lolen,olen data cap /'ABCDEFGHIJKLMNOPQRSTUVWXYZ'/ data low /'abcdefghijklmnopqrstuvwxyz'/ C lolen = len(loname) olen = min(len(name),lname) kln = min(MAXBUF,lolen,olen) kln = lastnb(name(1:kln)) temp(1:kln)=name(1:kln) do 100 i=1,kln c=temp(i:i) j=index(cap,c) if(j.ne.0) temp(i:i)=low(j:j) 100 continue 200 loname(1:kln)=temp(1:kln) lloname = kln return end C C C C C C >>>>> Convert name string to upper case C function upcase(name) C include 'ciftbx.sys' character upcase*(MAXBUF) character temp*(MAXBUF),name*(*) character low*26,cap*26,c*1 integer i,j,kln data cap /'ABCDEFGHIJKLMNOPQRSTUVWXYZ'/ data low /'abcdefghijklmnopqrstuvwxyz'/ C temp=name kln = lastnb(name) do 100 i=1,kln c=temp(i:i) j=index(low,c) if(j.ne.0) temp(i:i)=cap(j:j) 100 continue 200 upcase=temp return end C C C C C C >>>>> Convert name string to upper case as subroutine C subroutine nupcase(upname, name) C include 'ciftbx.sys' character temp*(MAXBUF),upname*(*),name*(*) character low*26,cap*26,c*1 integer i,j,kln integer lolen,olen data cap /'ABCDEFGHIJKLMNOPQRSTUVWXYZ'/ data low /'abcdefghijklmnopqrstuvwxyz'/ C uplen = len(upname) olen = len(name) kln = min(MAXBUF,uplen,olen) kln = lastnb(name(1:kln)) temp(1:kln)=name(1:kln) do 100 i=1,kln c=temp(i:i) j=index(low,c) if(j.ne.0) temp(i:i)=cap(j:j) 100 continue 200 upname=temp(1:kln) return end C C C C C C >>>>>> Get the data item associated with the tag. C subroutine tbxxgitm(name) C include 'ciftbx.sys' SAVE character name*(*) character flag*4 character*1 slash integer iitem,nitem,npakt integer kchar,loopi,i,jdict,itpos,ipp logical tbxxoid C slash = '\\' C C....... Find requested dataname in hash list C lnametb=lastnb(name) nametb(1:lnametb)=name(1:lnametb) posnam_=0 posval_=0 posdec_=0 posend_=0 valid_ = .false. quote_=' ' jdict = 0 if(name(1:1).eq.'_') goto 100 type_='null' dictype_='null' diccat_='(none)' dicname_=name dicpname_=name tagname_=' ' strg_=' ' long_=1 goto 1000 100 call hash_find(nametb(1:lnametb), * dname,dchain,NUMBLOCK,nname,dhash,NUMHASH, * iname) if(iname.gt.0) go to 180 if(dictfl.ne.'yes') then if (tbxxoid(nametb(1:lnametb),jdict)) then dictype_=dicxtyp(jdict) if(dcindex(jdict).ne.0) diccat_=dcname(dcindex(jdict)) dicname_=dictag(jdict) dicpname_=dictag(dpindex(jdict)) if(aroot(jdict).ne.0) then dicname_=dictag(aroot(jdict)) dicpname_=dictag(dpindex(aroot(jdict))) call hash_find(dicnam(aroot(jdict)), * dname,dchain,NUMBLOCK,nname,dhash,NUMHASH, * iname) if(iname.gt.0) goto 180 endif type_='null' tagname_=' ' strg_=' ' long_=1 go to 1000 endif endif 160 continue type_='null' dictype_='null' diccat_='(none)' dicname_=name long_=1 goto 1000 C C 180 tagname_=dtag(iname) if(ddict(iname).ne.0) tagname_=dictag(ddict(iname)) posnam_=tchar(iname) if(tabx_)posnam_=xchar(iname) if(nloop(iname).le.0) goto 500 C C....... Process loop packet if first item request C if(nloop(iname).ne.loopnl) goto 200 if(lloop(iname).lt.loopct) goto 300 if(loop_) goto 230 200 loop_=.true. loopct=0 loopnl=nloop(iname) nitem=loopni(loopnl) npakt=loopnp(loopnl) irecd=drecd(iname)-1 call getlin(flag) jchar=max(0,dchar(iname)-1) Cdbg if(jchar.lt.0) write(6,'(7H dchar ,i5)') jchar do 220 i=1,nitem 220 lloop(i+iname-iloop(iname))=0 goto 240 C C....... Read a packet of loop items C 230 nitem=loopni(loopnl) npakt=loopnp(loopnl) irecd=looprd(nitem+1)-1 call getlin(flag) jchar=loopch(nitem+1) Cdbg if(jchar.lt.0) write(6,'(7H loopch,i5)') jchar 240 iitem=0 250 iitem=iitem+1 if(iitem.le.nitem) goto 255 loopch(iitem)=jchar looprd(iitem)=irecd goto 270 255 call getstr loopch(iitem)=jchar-long_ if(quote_.ne.' ')loopch(iitem)=jchar-long_-1 loopln(iitem)=long_ looprd(iitem)=irecd if(buffer(1:1).ne.';'.or.loopch(iitem).ne.1) * goto 250 260 call getlin(flag) if(flag.eq.'fini') call err(' Unexpected end of data') if(buffer(1:1).ne.';') goto 260 jchar=2 goto 250 270 loopct=loopct+1 if(loopct.lt.npakt) goto 300 loop_=.false. C C....... Point to the loop data item C 300 lloop(iname)=lloop(iname)+1 loopi=iloop(iname) irecd=looprd(loopi)-1 call getlin(flag) long_=loopln(loopi) kchar=loopch(loopi) goto 550 C C....... Point to the non-loop data item C 500 irecd=drecd(iname)-1 call getlin(flag) kchar=dchar(iname)+1 long_=iloop(iname) loop_=.false. loopct=0 loopnl=0 C C....... Place data item into variable string and make number C 550 type_=dtype(iname) dictype_=dxtyp(iname) diccat_='(none)' if(cindex(iname).gt.0) diccat_=dcname(cindex(iname)) if(cindex(iname).lt.0) diccat_=cname(-cindex(iname)) if(diccat_.eq.' ') diccat_='(none)' dicname_=dtag(iname) if(ddict(iname).ne.0) then if (aroot(ddict(iname)).ne.0) then dicname_=dictag(aroot(ddict(iname))) endif endif strg_=' ' if(long_.gt.0) then strg_(1:long_)=buffer(kchar:kchar+long_-1) endif itpos=kchar if(tabx_) then itpos=0 do ipp=1,kchar itpos=itpos+1 if(buffer(ipp:ipp).eq.tab) itpos=((itpos+7)/8)*8 enddo endif posval_=itpos posend_=itpos+long_-1 jchar=kchar+long_ if(jchar.le.MAXBUF) then if(buffer(jchar:jchar).ne.' ' .and. * buffer(jchar:jchar).ne.tab) jchar=jchar+1 endif quote_=' ' if(kchar.gt.1) then if(buffer(kchar-1:kchar-1).ne.' ' .and. * buffer(kchar-1:kchar-1).ne.tab) then quote_=buffer(kchar-1:kchar-1) endif endif if(type_.eq.'char' .and. kchar.eq.1 .and. * buffer(1:1).eq.';') then type_='text' fold_=.false. endif if(type_.eq.'text') then if(buffer(1:1).eq.';') then strg_(1:1)=' ' if (strg_(1:long_).eq.(' '//slash) ) then fold_=.true. if(unfold_) then strg_(1:long_)=slash long_=1 endif endif else type_='char' endif endif if(type_.eq.'numb') then call ctonum if(posdec_.gt.0) posdec_=posval_+posdec_-1 endif if(type_.eq.'char' .and. strg_.eq.' '.and.nblank_) * type_='null' if (quote_.ne.' ') goto 1000 if (long_.eq.1.and.strg_(1:1).eq.'?') type_='null' if (long_.eq.1.and.strg_(1:1).eq.'.') type_='null' if (tcheck.eq.'yes') then if (tbxxoid(nametb(1:lnametb),jdict)) * call tbxxckv(jdict) endif C 1000 return end C C C C C C C C >>>>>> Convert string to integer, marking non-digit C C function tbxxsti(xstr,nondig) integer tbxxsti character *(*) xstr integer nondig, i integer sign, digits, kdv tbxxsti = 0 digits = 0 nondig = 0 sign = 1 do i = 1,len(xstr) kdv = ichar(xstr(i:i))-ichar('0') if (digits.eq.0) then if (xstr(i:i).eq.'-') then sign = -1 digits = 1 else if (xstr(i:i).eq.'+') then sign = 1 digits = 1 else if (kdv.ge.0 .and. kdv.le.9) then digits = 1 tbxxsti = kdv else if (xstr(i:i).ne.' ') then nondig = i return endif endif endif endif else if (kdv.ge.0 .and.kdv.le.9) then tbxxsti = tbxxsti*10+kdv else tbxxsti = sign*tbxxsti nondig = i return endif endif enddo return end C C C C C C C C >>>>>> Convert string to double, marking non-digit C C function tbxxstd(xstr,nondig) double precision tbxxstd integer tbxxsti character *(*) xstr integer nondig, i integer sign, digits, kdv integer idp, eval tbxxstd = 0.0 digits = 0 nondig = 0 sign = 1 idp = 0 do i = 1,len(xstr) kdv = ichar(xstr(i:i))-ichar('0') if (i.lt.len(xstr) * .and. (xstr(i:i).eq.'e' * .or. xstr(i:i).eq.'E' * .or. xstr(i:i).eq.'d' * .or. xstr(i:i).eq.'D' * .or. xstr(i:i).eq.'q' * .or. xstr(i:i).eq.'Q')) then eval = tbxxsti(xstr(i+1:len(xstr)),nondig) tbxxstd = sign*tbxxstd*10.**eval if (nondig.ne.0) nondig=nondig+i+1 return endif if (i.lt.len(xstr) .and. digits .ne.0 * .and. (xstr(i:i).eq.'+' * .or. xstr(i:i).eq.'-')) then eval = tbxxsti(xstr(i:len(xstr)),nondig) tbxxstd = sign*tbxxstd*10.**eval if (nondig.ne.0) nondig=nondig+i return endif if (xstr(i:i).eq.'.'.and.idp.eq.0) then idp = i digits = 1 endif if (digits.eq.0) then if (xstr(i:i).eq.'-') then sign = -1 digits = 1 else if (xstr(i:i).eq.'+') then sign = 1 digits = 1 else if (kdv.ge.0 .and. kdv.le.9) then digits = 1 tbxxstd = kdv else if (xstr(i:i).ne.' ') then nondig = i return endif endif endif endif else if (kdv.ge.0 .and.kdv.le.9) then if (idp.eq.0) then tbxxstd = tbxxstd*10.+kdv else tbxxstd = tbxxstd+kdv*(10.**(idp-i)) endif else if (i.ne.idp) then tbxxstd = sign*tbxxstd nondig = i return endif endif endif enddo tbxxstd = sign*tbxxstd return end C C C C C C C C >>>>>> Validate the string in strg_(1:long_) of type type_ C against the dictionary item at jdict C C subroutine tbxxckv(jdict) integer jdict C include 'ciftbx.sys' character*(MAXBUF) temp, target, lcvalue integer tbxxfstb integer tbxxsti double precision tbxxstd integer tlen logical igood, isword, nolo, nohi integer fblank,ftab, symop, xlate, itest integer yyyy, mm, dd, hr, mi, se, sf, tz integer nondig, prevdig, ldt, ldn double precision tardvalue valid_ = .false. igood = .false. if (long_ .lt. 1) return fblank = index(strg_(1:long_),' ') ftab = index(strg_(1:long_),tab) ldt = max(1,lastnb(dictype_)) ldn = max(1,lastnb(dicnam(jdict))) isword = .true. if (fblank.ne.0 .or. ftab.ne.0) isword =.false. if (type_.eq.'null') igood = .true. if ((type_.eq.'char' .or. type_.eq. 'numb').and. isword) then if (dictype_.eq.'uchar3') then if (long_.eq.3.or. * (long_.eq.4.and.strg_(1:1).eq.'+') * ) igood = .true. go to 90 endif if (dictype_.eq.'uchar1') then if (long_.eq.1.or. * (long_.eq.2.and.strg_(1:1).eq.'+') * ) igood = .true. go to 90 endif if (dictype_(1:4).eq.'symo') then symop = tbxxsti(strg_(1:long_),nondig) xlate = 0 if (nondig.ne.0.and.nondig.lt.long_) then if (strg_(nondig:nondig).eq.'_') then xlate = tbxxsti(strg_(nondig+1:long_),nondig) endif endif if (nondig.eq.0 .and. * symop .ge. 1 .and. * symop .le. 192 .and. * xlate .ge. 0 .and. * xlate .le. 1000) igood =.true. go to 90 endif if (dictype_(1:5).eq.'yyyy-') then mm=-1 dd=-1 hr=0 mi =0 se=0 sf=0 tz = 0 yyyy = tbxxsti(strg_(1:long_),nondig) if (nondig.ne.0.and.nondig.lt.long_) then if (strg_(nondig:nondig).eq.'-') then prevdig = nondig mm = tbxxsti(strg_(nondig+1:long_),nondig) if (nondig.ne.0) nondig=prevdig+nondig if (nondig.ne.0.and.nondig.lt.long_) then if (strg_(nondig:nondig).eq.'-') then prevdig = nondig dd = tbxxsti(strg_(nondig+1:long_),nondig) if (nondig.ne.0) nondig=prevdig+nondig if (nondig.ne.0.and.nondig.lt.long_) then if (strg_(nondig:nondig).eq.'T' * .or. strg_(nondig:nondig).eq.'t' * .or. strg_(nondig:nondig).eq.':') then prevdig = nondig hr = tbxxsti(strg_(nondig+1:long_),nondig) if (nondig.ne.0) nondig=prevdig+nondig if (nondig.ne.0.and.nondig.lt.long_) then if (strg_(nondig:nondig).eq.':') then prevdig = nondig mi = tbxxsti(strg_(nondig+1:long_),nondig) if (nondig.ne.0) nondig=prevdig+nondig if (nondig.ne.0.and.nondig.lt.long_) then if (strg_(nondig:nondig).eq.':') then prevdig = nondig se = tbxxsti(strg_(nondig+1:long_),nondig) if (nondig.ne.0) nondig=prevdig+nondig if (nondig.ne.0.and.nondig.lt.long_) then if (strg_(nondig:nondig).eq.'.') then prevdig = nondig sf = tbxxsti(strg_(nondig+1:long_),nondig) if (nondig.ne.0) nondig=prevdig+nondig endif endif endif endif endif endif endif endif endif endif endif endif if (nondig.ne.0) then if (strg_(nondig:nondig).eq.'-' * .or. strg_(nondig:nondig).eq.'+') then tz = tbxxsti(strg_(nondig+1:long_),nondig) endif endif if (nondig.eq.0 * .and. yyyy .ge. 0 .and. yyyy .lt. 10000 * .and. mm .gt. 0 .and. mm .lt. 13 * .and. dd .gt. 0 .and. dd .lt. 32 * .and. hr .ge. 0 .and. hr .lt. 25 * .and. mi .ge. 0 .and. mi .lt. 61 * .and. se .ge. 0 .and. se .lt. 61 * .and. sf .ge. 0 * .and. tz .ge. 0 .and. tz .lt. 25 ) igood =.true. go to 90 endif if (dictype_(1:4).eq.'char' * .or. dictype_(1:4).eq.'ucha' * .or. dictype_(1:4).eq.'code' * .or. dictype_(1:4).eq.'ucod' * .or. dictype_(1:4).eq.'line' * .or. dictype_(1:4).eq.'ulin' * .or. dictype_(1:3).eq.'any' * .or. dictype_(1:4).eq.'atco' * .or. dictype_(1:4).eq.'phon' * .or. dictype_(1:4).eq.'emai' * .or. dictype_(1:4).eq.'fax' * .or. dictype_(1:4).eq.'text') then igood = .true. go to 90 endif if (dictype_(1:4).eq.'numb' * .or. dictype_(1:3).eq.'int' * .or. dictype_(1:4).eq.'floa') then itest = tbxxsti(strg_(1:long_),nondig) if (nondig.eq.0) then igood = .true. go to 90 endif if (strg_(nondig:nondig).eq.'(' * .and. nondig .lt. long_) then itest = tbxxsti(strg_(nondig+1:long_),nondig) if (nondig.gt.0) then if (strg_(nondig:nondig).eq.')') then igood = .true. go to 90 endif endif endif if (dictype_(1:4).eq.'numb' * .or. dictype_(1:4).eq.'floa') then if (type_.eq.'numb') igood = .true. endif go to 90 endif go to 90 endif if (type_.eq.'char') then if (dictype_(1:4).eq.'text' * .or. dictype_(1:3).eq.'any' * .or. dictype_(1:4).eq.'line' * .or. dictype_(1:4).eq.'ulin' * .or. dictype_(1:4).eq.'phon' * .or. dictype_(1:4).eq.'atco' * .or. dictype_(1:4).eq.'phon' * .or. dictype_(1:4).eq.'char' * .or. dictype_(1:4).eq.'ucha' ) igood = .true. go to 90 endif if (type_.eq.'text') then if (dictype_(1:4).eq.'text' * .or. dictype_(1:3).eq.'any' * .or. dictype_(1:4).eq.'char' * .or. dictype_(1:4).eq.'ucha' ) igood = .true. go to 90 endif 90 continue if (.not.igood) then call warn(' Dictionary type '//dictype_(1:ldt)// * ' for '//dicnam(jdict)(1:ldn)// * ' not matched by '//strg_(1:long_)) return endif kptr = deindex(jdict) if (kptr.eq.0 .or. type_.eq.'null') then valid_ = .true. return endif call tbxxclc(lcvalue,llcvalue,strg_,long_) 100 if (kptr.ne.0) then tlen = tbxxfstb(temp,ivtsbp(kptr),.false.) if (tlen.gt.0) then call tbxxclc(target,ltarget,temp,tlen) if (ivtvet(kptr) .eq. 0) then if (target(1:ltarget).eq.lcvalue(1:llcvalue)) then valid_ = .true. return endif if(type_.eq.'numb' * .and. (dictype_(1:4).eq.'numb' * .or. dictype_(1:3).eq.'int' * .or. dictype_(1:4).eq.'floa')) then if (tbxxstd(target(1:ltarget),nondig) * .eq.numbtb) then valid_= .true. return endif endif else icptr = index(target(1:ltarget),':') ilolo = 1 ilohi = icptr-1 ihilo = icptr+1 ihihi = ltarget nolo = .true. if (ilohi.ge.ilolo) then nolo = .false. if (target(ilolo:ilohi).eq.'.') * nolo = .true. endif nohi = .true. if (ihihi.ge.ihilo) then nohi = .false. if (target(ihilo:ihihi).eq.'.') * nohi = .true. endif if (dictype_(1:4).eq.'numb' * .or. dictype_(1:3).eq.'int' * .or. dictype_(1:4).eq.'floa') then if (nolo.and.(.not.nohi)) then if ((ivtvet(kptr).gt.0 * .and. numbtb .lt. * tbxxstd(target(ihilo:ihihi),nondig)) .or. * (ivtvet(kptr).lt.0 * .and. numbtb .le. * tbxxstd(target(ihilo:ihihi),nondig))) then valid_= .true. return endif endif if (nohi.and.(.not.nolo)) then if ((ivtvet(kptr).gt.0 * .and. numbtb .gt. * tbxxstd(target(ilolo:ilohi),nondig)) .or. * (ivtvet(kptr).lt.0 * .and. numbtb .ge. * tbxxstd(target(ilolo:ilohi),nondig))) then valid_= .true. return endif endif if ((.not.nohi).and.(.not.nolo)) then if ((ivtvet(kptr).gt.0 * .and. numbtb .lt. * tbxxstd(target(ihilo:ihihi),nondig) * .and. numbtb .gt. * tbxxstd(target(ilolo:ilohi),nondig)) .or. * (ivtvet(kptr).lt.0 * .and. numbtb .le. * tbxxstd(target(ihilo:ihihi),nondig) * .and. numbtb .ge. * tbxxstd(target(ilolo:ilohi),nondig))) then valid_= .true. return endif endif else if (nolo.and.(.not.nohi)) then if ((ivtvet(kptr).gt.0 * .and. lcvalue(1:llcvalue) .lt. * target(ihilo:ihihi)) .or. * (ivtvet(kptr).lt.0 * .and. lcvalue(1:llcvalue) .le. * target(ihilo:ihihi))) then valid_= .true. return endif endif if (nohi.and.(.not.nolo)) then if ((ivtvet(kptr).gt.0 * .and. lcvalue(1:llcvalue) .gt. * target(ilolo:ilohi)) .or. * (ivtvet(kptr).lt.0 * .and. lcvalue(1:llcvalue) .ge. * target(ilolo:ilohi))) then valid_= .true. return endif endif if ((.not.nohi).and.(.not.nolo)) then if ((ivtvet(kptr).gt.0 * .and. lcvalue(1:llcvalue) .lt. * target(ihilo:ihihi) * .and. lcvalue(1:llcvalue) .gt. * target(ilolo:ilohi)) .or. * (ivtvet(kptr).lt.0 * .and. lcvalue(1:llcvalue) .le. * target(ihilo:ihihi) * .and. lcvalue(1:llcvalue) .ge. * target(ilolo:ilohi))) then valid_= .true. return endif endif endif endif endif kptr = ivtnxt(kptr) go to 100 endif 200 continue call warn(' Dictionary type '//dictype_(1:ldt)// * ' for '//dicnam(jdict)(1:ldn)// * ' range not matched by '//strg_(1:long_)) return end C C C C C C C C >>>>>> Read the next string from the file C C subroutine getstr C C On entry, jchar is set to one less than the next character C to be read, on the line given by irecd, which is assumed C to have been loaded into buffer, with lastch set to the C position of the last character C include 'ciftbx.sys' integer i,j,jj(11),im logical quoted character c*1,num*21,flag*4 data num/'0123456789+-.()EDQedq'/ C quoted=.false. quote_=' ' if(irecd.gt.0.and. * jchar.le.1.and.lastch.gt.0) then jchar=1 goto 140 end if 100 jchar=jchar+1 if(jchar.le.lastch) goto 150 C C....... Read a new line C 110 call getlin(flag) type_='fini' dictype_=type_ diccat_='(none)' dicname_=' ' Cdbg write(6,'(/5i5,a)') Cdbg * irecd,jrecd,lrecd,nrecd,lastch, buffer(1:lastch) if(flag.eq.'fini') goto 500 C C....... Test if the new line is the start of a text sequence C 140 if(buffer(1:1).ne.';') goto 150 type_='text' jchar=lastch+1 long_=lastch strg_(1:long_)=buffer(1:long_) strg_(1:1)=' ' goto 500 C C....... Process this character in the line C 150 c=buffer(jchar:jchar) if(c.eq.' ') goto 100 if(c.eq.tab) goto 100 if(c.eq.'#') goto 110 if(c.eq.'''') goto 300 if(c.eq.'"') goto 300 if(c.ne.'_') goto 200 type_='name' goto 210 C C....... Span blank delimited token; test if a number or a character C 200 type_='numb' im=0 do 205 i=1,11 205 jj(i)=0 210 do 250 i=jchar,lastch if(buffer(i:i).eq.' ') goto 400 if(buffer(i:i).eq.tab) goto 400 if(type_.ne.'numb') goto 250 j=index(num,buffer(i:i)) if(j.eq.0) type_='char' if(j.le.10) then im=im+1 goto 250 endif if(j.gt.13.and.im.eq.0) type_='char' jj(j-10)=jj(j-10)+1 250 continue i=lastch+1 if(type_.ne.'numb') goto 400 do 270 j=1,5 if((jj(j).gt.1.and.j.gt.2) .or. * jj(j).gt.2) type_='char' 270 continue goto 400 C C....... Span quote delimited token; assume character C 300 type_='char' quoted=.true. jchar=jchar+1 do 320 i=jchar,lastch if(buffer(i:i).ne.c) goto 320 if(i+1.ge.lastch) goto 400 if(buffer(i+1:i+1).eq.' ') goto 400 if(buffer(i+1:i+1).eq.tab) goto 400 320 continue Cdbg write(6,'(a,4i5,a)') Cdbg * '**** ',irecd,lastch,i,jchar,buffer(jchar:i) call warn(' Quoted string not closed') C C....... Store the string for the getter C 400 long_=0 strg_=' ' if(i.gt.jchar) then long_=i-jchar strg_(1:long_)=buffer(jchar:i-1) endif jchar=i quote_=' ' if(quoted) then quote_=buffer(jchar:jchar) jchar =jchar+1 endif Cdbg write(6,'(5x,8i5,5x,a)') Cdbg * irecd,jrecd,lrecd,nrecd,lastch,i,jchar,long_,strg_(1:long_) if(type_.ne.'char'.or.quoted) goto 500 if(strg_(1:5).eq.'data_') type_='data' if(strg_(1:5).eq.'loop_') type_='loop' if(long_.eq.1.and.strg_(1:1).eq.'?') type_='null' if(long_.eq.1.and.strg_(1:1).eq.'.') type_='null' if(strg_(1:5).eq.'save_') type_='save' if(long_.eq.7.and. strg_(1:7).eq.'global_') type_='glob' C 500 return end C C C C C C C >>>>>> Convert a character string into a number and its esd C C Q C D+ C E- C + + C number string -xxxx.xxxx-xxx(x) C component count CCNT 11111222223333444 C (with at least 1 digit in the mantissa) C subroutine ctonum C integer lastnb include 'ciftbx.sys' character test*22,c*1 integer*4 m,nchar integer*4 ccnt,expn,msin,esin,ndec,ids,nmd integer*4 nms,ned,nef,nes double precision numb,sdev,ntemp,mant data test /'0123456789+.-()EDQedq '/ C numbtb=0.D0 sdevtb=-1.D0 numb=1.D0 sdev=0.D0 ccnt=0 mant=0.D0 expn=0. msin=+1 esin=+1 ndec=0 ids=0 nmd=0 nms=0 ned=0 nef=0 nes=0 type_='char' posdec_=0 esddig_=0 if(long_.eq.1.and. * index('0123456789',strg_(1:1)).eq.0) goto 500 lzero_=.false. decp_=.false. C C....... Loop over the string and identify components C C The scan works in phases C ccnt = 0 processing looking for first digit C ccnt = 1 processing before decimal point C ccnt = 2 processing after decimal point C ccnt = 3 processing exponent C ccnt = 4 processing standard deviation C do 400 nchar=1,long_ C c=strg_(nchar:nchar) m=index(test,c) if(m.eq.0) goto 500 if(m.gt.10) goto 300 C C....... Process the digits C if(ccnt.eq.0) ccnt=1 if(ccnt.eq.2) ndec=ndec+1 if(ccnt.gt.2) goto 220 ntemp=m-1 if (ndec.eq.0) then mant=mant*10.D0+ntemp else mant=mant+ntemp/10.D0**(ndec) endif nmd=nmd+1 if(ccnt.eq.1.and.mant.ne.0.D0) ids=ids+1 goto 400 220 if(ccnt.gt.3) goto 240 expn=expn*10+m-1 goto 400 240 esddig_=esddig_+1 ntemp=m-1 sdev=sdev*10.D0+ntemp sdevtb=1.D0 goto 400 C C....... Process the characters . + - ( ) E D Q C 300 if(c.ne.'.') goto 320 decp_=.true. if(nchar.gt.1.and.mant.eq.0.d0) then if(strg_(nchar-1:nchar-1).eq.'0') lzero_=.true. endif if(ccnt.gt.1) goto 500 posdec_=nchar ccnt=2 goto 400 C 320 if(nmd.eq.0.and.m.gt.13) goto 500 if(c.ne.'(') goto 340 if(posdec_.eq.0) posdec_=nchar ccnt=4 goto 400 C 340 if(posdec_.eq.0.and.ccnt.gt.0) posdec_=nchar if(c.eq.')' .or. c.eq.' ') goto 400 if(ccnt.eq.3 .and. ned.gt.0) goto 500 if(m.gt.13) then if (nef.gt.0) goto 500 nef = nef+1 ccnt = 3 esin = 1 else if(ccnt.gt.0) then if (nes.gt.0) goto 500 nes = nes+1 ccnt = 3 esin = 12-m else if (nms.gt.0) goto 500 nms = nms+1 ccnt=1 msin=12-m endif endif C 400 continue C if(posdec_.eq.0) posdec_=lastnb(strg_(1:long_))+1 C C....... String parsed; construct the numbers C expn=expn*esin if(expn+ids.gt.-minexp) then call warn(' Exponent overflow in numeric input') expn=-minexp-ids endif if(expn.lt.minexp) then call warn(' Exponent underflow in numeric input') expn=minexp endif if(expn-ndec.lt.0) numb=1./10.D0**abs(expn-ndec) if(expn-ndec.gt.0) numb=10.D0**(expn-ndec) if(sdevtb.gt.0.0) sdevtb=numb*sdev numb=1.D0 if(expn.lt.0) numb=1./10.D0**abs(expn) if(expn.gt.0) numb=10.D0**(expn) ntemp=msin numbtb=numb*mant*ntemp type_='numb' C 500 return end C C C C C C C >>>>>> Read a new line from the direct access file C subroutine getlin(flag) C include 'ciftbx.sys' character flag*4 integer krpp,kpp,lpp,mpp,npp,ir integer tbxxrld C irecd=irecd+1 jchar=1 if(irecd.eq.jrecd.and. * irecd.gt.recbeg_.and. * irecd.le.recend_) goto 200 if(irecd.le.min(lrecd,recend_)) goto 100 irecd=min(lrecd,recend_)+1 buffer(1:1)=' ' lastch=0 jchar=MAXBUF+1 jrecd=-1 flag='fini' goto 200 100 continue lpp=-1 mpp=-1 npp=kpp call tbxxflin(irecd,lip,kpp,mp,kip,ip,mip,mis) if (lip.eq.0) then buffer(1:1) = ' ' lastch = 1 go to 130 endif do ir = 1,NUMPAGE if(iabs(mppoint(ir)).eq.kpp) then lpp = ir goto 120 endif if(mppoint(ir).eq.0) then lpp=ir else if(iabs(iabs(mppoint(ir))-kpp) * .gt.iabs(npp-kpp)) then mpp=ir npp=iabs(mppoint(ir)) endif endif enddo C C failed to find page as resident C remove a target page C if(lpp.eq.-1)lpp=mpp if(lpp.eq.-1)lpp=1 if (mppoint(lpp).lt.0) then write(dirdev,'(a)',rec=-mppoint(lpp)) pagebuf(lpp) endif mppoint(lpp)=kpp read(dirdev,'(a)',rec=kpp) pagebuf(lpp) 120 lastch = tbxxrld(buffer,pagebuf(lpp)(mp:NUMCPP), .false.) 130 recn_=irecd jrecd=irecd flag=' ' 200 return end C C C C C C C >>>>>> Detab buffer into bufntb C subroutine detab C include 'ciftbx.sys' integer icpos,itpos,ixpos,ixtpos if(jrecd.eq.jrect) return icpos=1 itpos=1 bufntb=' ' if(lastch.gt.0) then 100 ixpos=index(buffer(icpos:lastch),tab) ixtpos=ixpos+itpos-1 if(ixpos.gt.0.and.ixtpos.le.MAXBUF) then ixtpos=((ixtpos+7)/8)*8 if(ixpos.gt.1) then bufntb(itpos:ixtpos)= * buffer(icpos:ixpos+icpos-2) else bufntb(itpos:ixtpos)=' ' endif itpos=ixtpos+1 icpos=ixpos+icpos goto 100 else bufntb(itpos:max(MAXBUF,itpos+lastch-icpos))= * buffer(icpos:lastch) endif endif jrect=jrecd return end C C C C C C C >>>>>> Write error message and exit. C subroutine err(mess) character*(*) mess call cifmsg('error',mess) stop end C C C C C C C >>>>>> Write warning message and continue. C subroutine warn(mess) character*(*) mess call cifmsg('warning',mess) return end C C C C C C C >>>>>> Write a message to the error device C subroutine cifmsg(flag,mess) C integer lastnb include 'ciftbx.sys' character*(*) flag character*(*) mess character*(MAXBUF) tline character*5 btype integer ll,ls,ltry,ii,i C btype = 'data_' if(save_) btype = 'save_' if(.not.glob_) then tline= ' ciftbx '//flag//': ' * //file_(1:longf_)//' '//btype * //bloc_(1:max(1,lastnb(bloc_)))//' line:' else tline= ' ciftbx '//flag//': ' * //file_(1:longf_)//' global_'//' line:' endif ll = max(1,lastnb(tline)) write(errdev,'(a,i7)')tline(1:ll),irecd ll=len(mess) ls=1 100 if(ll-ls.le.79) then write(errdev,'(1X,a)') mess(ls:ll) return else ltry = min(ll,ls+79) do ii = ls+1,ltry i = ltry-ii+ls+1 if(mess(i:i).eq.' ') then write(errdev,'(1X,a)') mess(ls:i-1) ls=i+1 if(ls.le.ll) go to 100 return endif enddo write(errdev,'(1X,a)') mess(ls:ltry) ls=ltry+1 if(ls.le.ll) go to 100 return endif end C C C C C >>>>>> Create a named file. C function pfile_(fname) C logical pfile_ include 'ciftbx.sys' logical test integer lfname integer i character fname*(*) C C....... Test if a file by this name is already open. C if(pfilef.eq.'yes') call close_ pfilef='no ' file_(1:longf_) = ' ' lfname = len(fname) file_(1:lfname)=fname do 120 i=1,lfname if(file_(i:i).eq.' ') goto 140 120 continue i = lfname+1 140 if (i.gt.1) then inquire(file=file_(1:i-1),exist=test) pfile_=.false. longf_ = i-1 if(test) goto 200 else file_ = ' ' pfile_ = .true. longf_ = 1 endif C C....... Open up a new CIF C if (file_(1:1) .ne. ' ') then open(unit=outdev,file=file_(1:longf_),status='NEW', * access='SEQUENTIAL', * form='FORMATTED') precn_=0 endif pfile_=.true. pfilef='yes' nbloc=0 pchar=1+lprefx pcharl=0 obuf=prefx obuf(pchar:MAXBUF)=' ' 200 ploopn = 0 ploofc = 0 ploopf = 'no ' ptextf = 'no ' plcat = ' ' pdblok = ' ' plhead(1) = ' ' if (xmlout_) then call putstr('') endif return end C C C C C C <<<<<< Substitute item in data block XML translation C function dsbst(oblok,xstring) include 'ciftbx.sys' character oblok*(*) character xstring*(*) character dsbst*(MAXBUF) jj = 1 dsbst = ' ' do ii = 1,lastnb(xstring) if(xstring(ii:ii).ne.'%') then dsbst(jj:jj) = xstring(ii:ii) jj = jj+1 else do kk = 1,lastnb(oblok) dsbst(jj:jj) = oblok(kk:kk) jj = jj+1 enddo endif enddo return end C C C C C C >>>>>> Store a data block command in the CIF C Call with blank name to close current block only C function pdata_(name) C logical pdata_ SAVE include 'ciftbx.sys' character name*(*),temp*(MAXBUF) character dbloc(100)*(NUMCHAR) character dsbst*(MAXBUF) integer i C pdata_=.true. if(ploopn.ne.0) call eoloop if(ptextf.eq.'yes') call eotext if(psaveo) then pchar=-1 if(pposval_.ne.0) then pchar=lprefx+1 call putstr(' ') pchar=lprefx+pposval_ pposval_=0 endif if (xmlout_) then call putxc('save_',' ') else call putstr('save_') endif psaveo=.false. endif if (pdblok(1:1).ne.' ') then if (xmlout_) then if (xmdata.eq.0) then call putxc(pdblok,' ') else call putxc(dsbst(pdblok,xmlate(xmdata)),' ') endif endif pdblok=' ' endif if(globo_) then pchar=-1 temp='global_' pdblok='global_' psaveo=.false. goto 135 endif C C....... Check for duplicate data name C temp=name if(temp.eq.' ') goto 200 if(saveo_) goto 130 pdata_=.false. do 110 i=1,nbloc if(temp.eq.dbloc(i)) goto 130 110 continue pdata_ = .true. goto 125 C C....... Save block name and put data_ statement C 125 nbloc=nbloc+1 if(nbloc.le.100) dbloc(nbloc)=temp pdblok = temp 130 pchar=-1 temp='data_'//name if(saveo_) temp='save_'//name if(globo_) temp='global_' psaveo=saveo_ 135 if(pposnam_.gt.0) then pchar=lprefx+1 call putstr(' ') pchar=lprefx+pposnam_ pposnam_=0 endif if (xmlout_) then if (globo_) then call putxo('global_',' ') else if (xmdata.eq.0) then call putxo(pdblok,' ') else call putxo(dsbst(pdblok,xmlate(xmdata)),' ') endif if (saveo_) then call putxo('save_',' ') endif endif else call putstr(temp(1:lastnb(temp))) endif pchar=lprefx plcat = ' ' ploopn = 0 C 200 return end C C C C C C C >>>>>> Process a name to extract the category and item C subroutine tbxxpcat(name,type,flag,tflag,mycat,myxcat, * item,xitem,nroot) C character name*(*),mycat*(*),item*(*),nroot*(*),type*4 character myxcat*(*),xitem*(*) include 'ciftbx.sys' character xxxtemp*(NUMCHAR) logical flag,tflag integer lastnb,kpl,npl character str1*(NUMCHAR), str2*(NUMCHAR) item = name xitem = ' ' nroot = name mycat = ' ' myxcat = ' ' flag = .true. tflag = .true. if(vcheck.eq.'yes') then kdc = 0 call dcheck(name,type,flag,tflag) if (xdchk.ne.0) then kdc = dcindex(xdchk) if (xmindex(xdchk).ne.0) xitem = xmlate(xmindex(xdchk)) endif if (aliaso_.and.xdchk.ne.0) then if (aroot(xdchk).ne.0) then nroot = dictag(aroot(xdchk)) kdc = dcindex(aroot(xdchk)) endif endif if (kdc.ne.0) then mycat = dcname(kdc) myxcat = ' ' if (xmcind(kdc).ne.0) myxcat = xmlate(xmcind(kdc)) endif else call tbxxcat(name,mycat,lmycat) endif kpl = lastnb(mycat) npl = lastnb(name) call tbxxnlc(str1, mycat) call tbxxnlc(str2, name) if (mycat(1:1).ne.' ' .and. name(1:1).eq.'_') then if(str1(1:kpl).eq.str2(2:kpl+1) .and. npl .gt. kpl+2 .and. * (name(kpl+2:kpl+2).eq.'.' .or. * name(kpl+2:kpl+2).eq.'_') ) then item = name(kpl+3:npl) else item = name(2:npl) endif else if (mycat(1:1).eq.' ' .and. plcat(1:1).ne.' ' * .and. name(1:1).eq.'_') then call tbxxnlc(str1, plcat) kpl = lastnb(plcat) if(str1(1:kpl).eq.str2(2:kpl+1) .and. npl .gt. kpl+2 .and. * (name(kpl+2:kpl+2).eq.'.' .or. * name(kpl+2:kpl+2).eq.'_') ) then mycat = plcat item = name(kpl+3:npl) else item = name(2:npl) endif else item = name if (item(1:1).eq.'_') item = name(2:npl) endif endif if (xmlong_) then item = name if (item(1:1).eq.'_') item = name(2:npl) endif call nupcase(xxxtemp,mycat) mycat = xxxtemp return end C C C C C C C >>>>>> Put a number into the CIF, perhaps with an esd appended C function pnumb_(name,numb,sdev) C logical pnumb_ include 'ciftbx.sys' logical flag,tflag character name*(*),temp*(NUMCHAR) character mycat*(NUMCHAR),item*(NUMCHAR) character myxcat*(XMLCHAR),xitem*(XMLCHAR) real numb,sdev double precision dnumb,dsdev,dprec integer kmn C pnumb_=.true. flag =.true. tflag =.true. temp=name if(ptextf.eq.'yes') call eotext C if(name(1:1).eq.' ') goto 110 call tbxxpcat(name,'numb',flag,tflag,mycat,myxcat, * item,xitem,temp) pnumb_=flag 100 if(ploopn.ne.0) call eoloop if (xmlout_) then if (plcat(1:1).ne.' ' .and. plcat.ne.mycat) then call putxc(plhead(1),plxhead(1)) plhead(1) = ' ' plxhead(1) = ' ' call putxc(plcat,plxcat) plcat = ' ' plxcat = ' ' endif endif pchar=-1 if(pposnam_.ne.0)pchar=pposnam_+lprefx if (xmlout_) then if ((plhead(1)(1:1).ne.' '.and.plhead(1).ne.item) * .or. plcat.ne.mycat) then call putxc (plhead(1),plxhead(1)) plhead(1) = ' ' plxhead(1) = ' ' if (plcat.ne.mycat) then call putxc(plcat,plxcat) plcat = mycat plxcat = myxcat call putxo(plcat,plxcat) endif call putxo (item,xitem) else if(plhead(1)(1:1).eq.' ') call putxo (item,xitem) endif plhead(1) = item plxhead(1) = xitem else call putstr(temp(1:lastnb(temp))) endif go to 120 C 110 if (xmlout_) then if (ploopn.gt.0) then kmn = mod(ploopc,ploopn)+2 if (ploopn.gt.1.or.ploopf.eq.'yes') then call putxo(plhead(kmn),plxhead(kmn)) endif endif endif C 120 if(ploopf.eq.'yes') ploopc=0 ploopf='no ' dprec=decprc dnumb=numb dsdev=sdev call putnum(dnumb,dsdev,dprec) if(.not.flag) then if(.not.tabl_) pchar=lprefx+57 if (xmlout_) then call putstr('') else call putstr('#< not in dictionary') endif endif if(.not.tflag) then if(.not.tabl_) pchar=lprefx+57 if (xmlout_) then call putstr('') else call putstr('#< not correct type') endif endif if (xmlout_) then if (ploopn.gt.1 .and.ploopc.gt.0) then call putxc(plhead(ploopc+1),plxhead(ploopc+1)) endif endif C 150 pposnam_=0 pposval_=0 pposdec_=0 pposend_=0 pesddig_=0 return end C C C C C C C >>>>>> Put a double precision number into the CIF, perhaps C with an esd appended C function pnumd_(name,numb,sdev) C logical pnumd_ include 'ciftbx.sys' logical flag,tflag character name*(*),temp*(NUMCHAR) character mycat*(NUMCHAR),item*(NUMCHAR) character myxcat*(XMLCHAR),xitem*(XMLCHAR) double precision numb,sdev integer kmn C pnumd_=.true. flag =.true. tflag =.true. temp=name if(ptextf.eq.'yes') call eotext C if(name(1:1).eq.' ') goto 110 call tbxxpcat(name,'numb',flag,tflag,mycat,myxcat, * item,xitem,temp) pnumd_=flag 100 if(ploopn.ne.0) call eoloop if (xmlout_) then if (plcat(1:1).ne.' ' .and. plcat.ne.mycat) then call putxc(plhead(1),plxhead(1)) plhead(1) = ' ' call putxc(plcat,plxcat) plcat = ' ' plxcat = ' ' endif endif pchar=-1 if(pposnam_.ne.0)pchar=pposnam_+lprefx if (xmlout_) then if ((plhead(1)(1:1).ne.' '.and.plhead(1).ne.item) * .or. plcat.ne.mycat) then call putxc (plhead(1),plxhead(1)) plhead(1) = ' ' plxhead(1) = ' ' if (plcat.ne.mycat) then call putxc(plcat,plxcat) plcat = mycat plxcat = myxcat call putxo(plcat,myxcat) endif call putxo (item,xitem) else if(plhead(1)(1:1).eq.' ') call putxo (item,xitem) endif plhead(1) = item plxhead(1) = xitem else call putstr(temp(1:lastnb(temp))) endif go to 120 C 110 if (xmlout_) then if (ploopn.gt.0) then kmn = mod(ploopc,ploopn)+2 if (ploopn.gt.1.or.ploopf.eq.'yes') then call putxo(plhead(kmn),plxhead(kmn)) endif endif endif C 120 if(ploopf.eq.'yes') ploopc=0 ploopf='no ' call putnum(numb,sdev,dpprc) if(.not.flag) then if(.not.tabl_) pchar=lprefx+57 if (xmlout_) then call putstr('') else call putstr('#< not in dictionary') endif endif if(.not.tflag) then if(.not.tabl_) pchar=lprefx+57 if (xmlout_) then call putstr('') else call putstr('#< not correct type') endif endif if (xmlout_) then if (ploopn.gt.1 .and.ploopc.gt.0) then call putxc(plhead(ploopc+1),plxhead(ploopc+1)) endif endif C 150 pposnam_=0 pposval_=0 pposdec_=0 pposend_=0 pesddig_=0 return end C C C C C C C >>>>>> Put a character string into the CIF. C function pchar_(name,string) C logical pchar_ include 'ciftbx.sys' logical flag,tflag character name*(*),temp*(NUMCHAR),string*(*) character mycat*(NUMCHAR),item*(NUMCHAR) character myxcat*(XMLCHAR),xitem*(XMLCHAR) character line*(MAXBUF),strg*(MAXBUF) integer i, j, kfold integer lstring,lqstring C pchar_=.true. flag =.true. tflag =.true. temp =name lstring = lastnb(string) if (lstring .gt. MAXBUF) then call warn('Output CIF line longer than MAXBUF, truncated') lstring = MAXBUF endif if(ptextf.eq.'yes') call eotext C if(name(1:1).eq.' ') goto 110 call tbxxpcat(name,'char',flag,tflag,mycat,myxcat, * item,xitem,temp) pchar_=flag 100 if(ploopn.ne.0) call eoloop if (xmlout_) then if (plcat(1:1).ne.' ' .and. plcat.ne.mycat) then call putxc(plhead(1),plxhead(1)) plhead(1) = ' ' plxhead(1) = ' ' call putxc(plcat,plxcat) plcat = ' ' plxcat = ' ' endif endif pchar=-1 if(pposnam_.gt.0) pchar=posnam_+lprefx if (xmlout_) then if ((plhead(1)(1:1).ne.' '.and.plhead(1).ne.item) * .or. plcat.ne.mycat) then call putxc (plhead(1),plxhead(1)) plhead(1) = ' ' plxhead(1) = ' ' if (plcat.ne.mycat) then call putxc(plcat,plxcat) plcat = mycat plxcat = myxcat call putxo(plcat,plxcat) endif call putxo (item,xitem) else if(plhead(1)(1:1).eq.' ') call putxo (item,xitem) endif plhead(1) = item plxhead(1) = xitem else call putstr(temp(1:lastnb(temp))) endif go to 120 C 110 if (xmlout_) then if (ploopn.gt.0) then kmn = mod(ploopc,ploopn)+2 if (ploopn.gt.1.or.ploopf.eq.'yes') then call putxo(plhead(kmn),plxhead(kmn)) endif endif endif C 120 if(ploopf.eq.'yes') ploopc=0 ploopf='no ' if (xmlout_) then i = 1 do ic = 1,lstring if ( string(ic:ic).eq.'&' * .or. string(ic:ic).eq.'<' * .or. string(ic:ic).eq.'>' ) then if(i.lt.MAXBUF) then line(i:i) = '&' endif if (i.lt.MAXBUF) then if( string(ic:ic).eq.'&' ) then line(i:MAXBUF)='amp;' i = i+4 endif if( string(ic:ic).eq.'<' ) then line(i:MAXBUF)='lt;' i = i+3 endif if( string(ic:ic).eq.'>' ) then line(i:MAXBUF)='gt;' i = i+3 endif endif if (i.gt.MAXBUF+1) then i = MAXBUF+1 endif else if(i.lt.MAXBUF) then line(i:i) = string(ic:ic) i = i+1 endif endif enddo if (i.gt.1) i = i-1 if (i.lt.MAXBUF) line(i+1:MAXBUF) = ' ' else line=string i = lstring endif 130 if(pposval_.ne.0.and.pposend_.ge.pposval_) * i=max(i,pposend_-pposval_+1) if(pfold_ .ne. 0 .and. lstring .gt. min(pfold_,line_) ) * go to 290 if(pquote_.ne.' ') go to 150 do 140 j=i,1,-1 if(line(j:j).eq.' ') go to 150 140 continue if((line(1:1).eq.'_' * .or. line(i:i).eq.'_' * .or. line(1:1).eq.'''' * .or. line(1:1).eq.'"' * .or. line(1:1).eq.';') * .and.line(1:i).ne.'''.''' * .and.line(1:i).ne.'''?''' * .and.line(1:i).ne.'"."' * .and.line(1:i).ne.'"?"') go to 150 strg=line(1:i) goto 200 150 if(pquote_.eq.';') go to 190 if(line(1:i).eq.' '.and.nblanko_) then strg = '.' i = 1 if(pposval_.ne.0) then pchar=pposval_+lprefx endif call putstr(strg(1:i)) go to 210 endif if(pquote_.eq.'"') go to 170 do 160 j=1,i-1 if(line(j:j).eq.''''.and. * (line(j+1:j+1).eq.' '.or.line(j+1:j+1).eq.tab)) * goto 170 160 continue 165 strg=''''//line(1:i)//'''' i=i+2 pquote_='''' goto 200 170 do 180 j=1,i-1 if(line(j:j).eq.'"'.and. * (line(j+1:j+1).eq.' '.or.line(j+1:j+1).eq.tab)) * goto 190 180 continue 185 strg='"'//line(1:i)//'"' i=i+2 pquote_='"' if(pfold_ .gt. 1 .and. i .gt. min(pfold_,line_) ) go to 290 goto 200 190 pchar=-1 if (xmlout_) then strg = '') else call putstr(';') endif pchar=lprefx call putstr(' ') strg = * ' Converted pchar_ output to text for: '//string(1:lstring) call warn(strg) goto 210 C 200 if(pposval_.ne.0) then pchar=pposval_+lprefx if(pquote_.ne.' ') pchar=pchar-1 endif call putstr(strg(1:i)) 210 if(.not.flag) then if(.not.tabl_) pchar=lprefx+57 if (xmlout_) then call putstr('') else call putstr('#< not in dictionary') endif endif if((.not.tflag).and.line(1:i).ne.'.'.and. * line(1:i).ne.'?'.and.pquote_.eq.' ') then if(.not.tabl_) pchar=lprefx+57 if (xmlout_) then call putstr('') else call putstr('#< not correct type') endif endif if (xmlout_) then if (ploopn.gt.1 .and. ploopc.gt.0) then call putxc(plhead(ploopc+1),plxhead(ploopc+1)) endif endif 250 pposval_=0 pposdec_=0 pposnam_=0 pposend_=0 pquote_=' ' return C C fold a string to min(pfold_,line_) C 290 pchar=-1 pquote_ = ';' if (xmlout_) then call putstr('') else call putstr(';') endif pchar=lprefx call putstr(' ') goto 210 end C C C C C C >>>>>> Put a comment in the output CIF C function pcmnt_(string) C logical pcmnt_ include 'ciftbx.sys' character string*(*), temp*(MAXBUF) character*1 slash integer lstring, kfold C slash = '\\' lstring = lastnb(string) kfold = min(pfold_,line_) if(ptextf.eq.'yes') call eotext if(pposnam_.ne.0) pchar=pposnam_+lprefx if(string.eq.' '.or. * (string.eq.char(0)) .or. * (string.eq.tab.and.(.not.ptabx_))) then if(string.eq.' ') pchar=-1 if (pquote_.eq.'#') then temp(1:1+lstring) = pquote_//string(1:lstring) call putstr(temp(1:1+lstring)) else call putstr(string) endif if(string.eq.' ') call putstr(char(0)) else if ((kfold .ne. 0) .and. * ((xmlout_ .and. (max(pchar,1)+8+lstring.gt.kfold)) * .or.((.not.xmlout_) .and. * ((max(pchar,1)+lstring).gt.kfold)))) then if (xmlout_) then call putstr('' ik = ik+4 if (ik.lt.MAXBUF) temp(ik:MAXBUF) = ' ' else temp='#'//string endif call putstr(temp(1:lastnb(temp))) call putstr(char(0)) endif endif pcmnt_=.true. pposnam_=0 if(string.ne.tab)pchar=lprefx+1 return end C C C C C C C C >>>>>> Put a text sequence into the CIF. C function ptext_(name,string) C logical ptext_ integer lastnb include 'ciftbx.sys' logical flag,tflag integer ll,nsl character name*(*),temp*(NUMCHAR),string*(*),store*(NUMCHAR) character mycat*(NUMCHAR),item*(NUMCHAR) character myxcat*(XMLCHAR),xitem*(XMLCHAR) character temp2*(MAXBUF) character slash*1 integer kmn integer kfold data store/' '/ C ptext_=.true. flag =.true. tflag =.true. slash = '\\' ll=lastnb(string) temp=name if(ptextf.eq.'no ') goto 100 if(temp.eq.store) goto 150 call eotext C 100 if(name(1:1).ne.' ') goto 110 if(ptextf.eq.'yes') goto 150 goto 120 C 110 if(ploopn.ne.0) call eoloop call tbxxpcat(name,'char',flag,tflag,mycat,myxcat, * item,xitem,temp) ptext_=flag if (xmlout_) then if (plcat(1:1).ne.' ' .and. plcat.ne.mycat) then call putxc(plhead(1),plxhead(1)) plhead(1) = ' ' plxhead(1) = ' ' call putxc(plcat,plxcat) plcat = ' ' plxcat = ' ' endif endif pchar=-1 if(pposnam_.ne.0) pchar=pposnam_+lprefx if (xmlout_) then if ((plhead(1)(1:1).ne.' '.and.plhead(1).ne.item) * .or. plcat.ne.mycat) then call putxc (plhead(1),plxhead(1)) plhead(1) = ' ' if (plcat.ne.mycat) then call putxc(plcat,plxcat) plcat = mycat plxcat = myxcat call putxo(plcat,plxcat) endif call putxo (item,xitem) else if(plhead(1)(1:1).eq.' ') call putxo (item,xitem) endif plhead(1) = item plxhead(1) = xitem else call putstr(temp) endif if(.not.flag) then if(.not.tabl_) pchar=lprefx+57 if (xmlout_) then call putstr('') else call putstr('#< not in dictionary') endif endif if(.not.tflag) then if(.not.tabl_) pchar=lprefx+57 if (xmlout_) then call putstr('') else call putstr('#< not correct type') endif endif go to 130 C 120 if (xmlout_) then if (ploopn.gt.0) then kmn = mod(ploopc,ploopn)+2 if (ploopn.gt.1.or.ploopf.eq.'yes') then call putxo(plhead(kmn),plxhead(kmn)) endif endif endif C 130 if(ploopf.eq.'yes') ploopc=0 ploopf='no ' ptextf='yes' store=temp if(string(1:1).eq.' '.and.ll.gt.1.and.pfold_.eq.0) then pchar=-1 if (xmlout_) then temp2 = '>>>>> Put a folded string to the output CIF C subroutine tbxxpfs(string,prefix,kfold) C include 'ciftbx.sys' character *(*) string,prefix character *(MAXBUF) temp character *1 slash logical stabl integer kfold integer sploopn integer i, klow, khi, kpref, klen slash = '\\' sploopn = ploopn ploopn = -1 stabl = tabl_ tabl_ = .false. if (kfold .lt. 4) then call * warn('Invalid attempt to fold output line, limit reset to 4') pfold_ = 4 kfold = 4 endif klen = lastnb(string) kpref = len(prefix) if (prefix.eq.' ') kpref=0 klow = 1 100 khi = klen if (khi.gt.klow+kfold-1-kpref) then khi = klow+kfold-1-kpref-1 do i = khi,klow+1,-1 if(string(i:i).eq.' ') then khi = i go to 120 endif enddo 120 if (kpref.gt.0) then temp(1:kpref+khi-klow+2) = prefix//string(klow:khi)//slash else temp(1:kpref+khi-klow+2) = string(klow:khi)//slash endif pchar = -1 call putstr(temp(1:kpref+khi-klow+2)) call putstr(char(0)) klow = khi+1 go to 100 else if (string(khi:khi).eq.slash) then if (khi.lt.klow+kfold-1-kpref) then if (kpref.gt.0) then temp(1:kpref+khi-klow+2) = * prefix//string(klow:khi)//slash pchar = -1 call putstr(temp(1:kpref+khi-klow+2)) call putstr(char(0)) pchar = -1 call putstr(prefix) else temp(1:khi-klow+2) = string(klow:khi)//slash pchar = -1 call putstr(temp(1:khi-klow+2)) pchar = -1 call putstr(' ') endif call putstr(char(0)) else if (kpref.gt.0) then temp(1:kpref+khi-klow+1) = prefix//string(klow:khi) pchar = -1 call putstr(temp(1:kpref+khi-klow+1)) call putstr(char(0)) temp(1:kpref+2) = prefix//slash//slash pchar = -1 call putstr(temp(1:kpref+2)) call putstr(char(0)) call putstr(prefix) else pchar = -1 call putstr(string(klow:khi)) call putstr(char(0)) pchar = -1 call putstr(slash//slash) call putstr(char(0)) call putstr(' ') endif call putstr(char(0)) pchar = -1 endif else pchar = -1 if (kpref.gt.0) then temp(1:kpref+khi-klow+1)=prefix//string(klow:khi) call putstr(temp(1:kpref+khi-klow+1)) else call putstr(string(klow:khi)) endif call putstr(char(0)) endif endif pchar = -1 ploopn = sploopn tabl_ = stabl return end C C C C C C C >>>>>> Put a loop_ data name into the CIF. C function ploop_(name) C logical ploop_ integer kdc,kpc,kpl,npl include 'ciftbx.sys' logical flag,tflag character name*(*), temp*(NUMCHAR), mycat*(NUMCHAR) character myxcat*(XMLCHAR),xitem*(XMLCHAR) character item*(NUMCHAR), str*(NUMCHAR) character shead*(NUMCHAR),xshead*(XMLCHAR) C ploop_=.true. flag =.true. if(ptextf.eq.'yes') call eotext if(ploopn.ne.0. and. ploopf.ne.'yes' * .and. name(1:1).eq.' ') then call eoloop endif temp = ' ' mycat = ' ' item = ' ' shead = plhead(1) xshead = plxhead(1) str = ' ' if(name(1:1).eq.' ') goto 100 C call tbxxpcat(name,' ',flag,tflag,mycat,myxcat, * item,xitem,str) ploop_ = flag if (ploopn.ne.0. and. ploopf.ne.'yes') then if (plcat.eq.mycat) then plcat = ' ' call eoloop plcat = mycat plxcat = myxcat else call eoloop endif endif if (xmlout_) then if (plcat(1:1).ne.' '.and.ploopn.eq.0) then call putxc(plhead(1),plxhead(1)) plhead(1) = ' ' plxhead(1) = ' ' shead = ' ' xshead = ' ' if (plcat.ne.mycat) then call putxc(plcat,plxcat) plcat = ' ' plxcat = ' ' endif endif endif if(tabl_.and.pposnam_.eq.0) then temp=' '//str else temp=str endif plhead(max(ploopn,0)+2) = item plxhead(max(ploopn,0)+2) = xitem 100 if(ploopn.ne.0) goto 120 ploopf='yes' pchar=-1 if(pposval_.ne.0) then pchar=lprefx+1 call putstr(' ') pchar=pposval_+lprefx else if(pposnam_.ne.0) then pchar=lprefx+1 call putstr(' ') pchar=pposnam_+lprefx+1 endif endif if (xmlout_) then if (shead(1:1).ne.' ') then call putxc (shead,xshead) endif else call putstr('loop_') endif pchar=-1 if(name(1:1).eq.' ') then ploopn=-1 plhead(1) = ' ' plxhead(1) = ' ' return endif 120 if(ploopn.le.0) then if (xmlout_.and.plcat.ne.mycat) then call putxc(plcat,plxcat) plcat = mycat plxcat = myxcat call putxo(mycat,myxcat) endif else if(xmlout_ .and. plcat.ne.mycat) then kpl = lastnb(plcat) if(mycat(1:1).eq.' ') then mycat = '(none)' myxcat = '_NONE_ ' endif npl = lastnb(mycat) kpc = pchar call putstr('') pchar = kpc endif endif if(pposnam_.ne.0) pchar=pposnam_+lprefx if (.not. xmlout_) then call putstr(temp(1:lastnb(temp))) endif if(flag) goto 130 if(.not.tabl_) pchar=lprefx+57 if (xmlout_) then call putstr('') else call putstr('#< not in dictionary') endif 130 pchar=lprefx+1 ploopn=max(ploopn,0)+1 ploopc = 0 C 150 return end C C C C C C >>>>>> Create or clear a prefix string C Any change in the length of the prefix string flushes C pending text, if any, loops and partial output lines C function prefx_(strg,lstrg) C logical prefx_ include 'ciftbx.sys' character strg*(*) integer lstrg,mxline C mxline=MAXBUF if(line_.gt.0) mxline=min(line_,MAXBUF) if(lstrg.ne.lprefx.and.pcharl.gt.0) then pchar=-1 call putstr(' ') endif if (lstrg.le.0) then prefx=' ' if(pchar.ge.lprefx+1)pchar=pchar-lprefx lprefx=0 else if(lstrg.gt.mxline) then call warn(' Prefix string truncated') endif prefx=strg if(pchar.ge.lprefx+1)pchar=pchar-lprefx+lstrg obuf(1:min(mxline,lstrg))=prefx lprefx=lstrg if(mxline-lprefx.lt.NUMCHAR) then call warn(' Output prefix may force line overflow') endif endif prefx_=.true. return end C C C C C C C >>>>>> Close the CIF C subroutine close_ C include 'ciftbx.sys' character dsbst*(MAXBUF) C if(ptextf.eq.'yes') call eotext if(ploopn.ne.0) call eoloop if (xmlout_) then if (plhead(1)(1:1).ne.' ') * call putxc(plhead(1),plxhead(1)) if (plcat(1:1).ne.' ') call putxc(plcat,plxcat) if (pdblok(1:1).ne.' ') then if (xmdata.eq.0) then call putxc(pdblok,' ') else call putxc(dsbst(pdblok,xmlate(xmdata)),' ') endif endif endif pdblok = ' ' plcat = ' ' plxcat = ' ' plhead(1) = ' ' plxhead(1) = ' ' if(pcharl.ge.lprefx+1) then pchar=-1 call putstr(' ') endif if (file_(1:1) .ne. ' ') then file_(1:longf_) = ' ' longf_ = 1 close(outdev) precn_=0 endif return end C C C >>>>> Clean out characters not valid for an XML name C C An XML name may begin with a letter, '_' or ':' C and may contain letters, digits, '_', ':', '.' or '-' C C Note that the full Unicode character set would also permit C combining characters and extender characters, but these C have no representation in a 128 character ASCII set C C function xmncln(xstring,lstr) logical xmncln character*(*) xstring integer lstr, ii, ix character*10 chkstr1 character*28 chkstr2 character*28 chkstr3 character*1 c data chkstr1/'0123456789'/ data chkstr2/'_:ABCDEFGHIJKLMNOPQRSTUVWXYZ'/ data chkstr3/'abcdefghijklmnopqrstuvwxyz.-'/ xmncln = .true. do ii = 1,lstr c = xstring(ii:ii) if (c.eq.' ') return ix = index(chkstr2,c) if (ix.eq.0) then ix = index(chkstr3,c) if (ix.eq.0.and.ii.gt.1) then ix = index(chkstr1,c) endif if(ix.eq.0.or.(ix.gt.26.and.ii.eq.1)) then xstring(ii:ii) = '_' xmncln = .false. endif endif enddo return end C C C >>>>>> Put out the given string as an xml open tag C C Note that the string may have embedded blanks and C parameters. The second argument is an optional C translation to be used if non-blank. C subroutine putxo(string,xstring) C integer lastnb include 'ciftbx.sys' character sbuf*(MAXBUF) character*(*) string, xstring integer ik logical xmncln if (string(1:1).eq.' ') return sbuf(1:1) = '<' if (xstring(1:1).eq.' ') then ik = lastnb(string) sbuf(2:ik+1)=string(1:ik) else ik = lastnb(xstring) sbuf(2:ik+1)=xstring(1:ik) endif sbuf(ik+2:ik+2) = '>' pchar = -1 if (.not.xmncln(sbuf(2:ik+1),ik)) then call warn(' XML required remapping for '//sbuf(2:ik+1)) endif call putstr(sbuf(1:ik+2)) return end C C C >>>>>> Put out the given string as an xml close tag C C Note that the string may have embedded blanks and C parameters. Only the first token will be used for close. C The second argument is an optional translation to be C used if non-blank C subroutine putxc(string, xstring) C integer lastnb include 'ciftbx.sys' character sbuf*(MAXBUF) character*(*) string, xstring integer ik logical xmncln if (string(1:1).eq.' ') return sbuf(1:2) = '' if (.not.xmncln(sbuf(3:ik+2),ik)) then call warn(' XML required remapping for '//sbuf(3:ik+2)) endif pchar = -1 call putstr(sbuf(1:ik+3)) return end C C C C C C >>>>>> Put the string into the output CIF buffer C subroutine putstr(string) C integer lastnb include 'ciftbx.sys' SAVE character string*(*),temp*(MAXBUF),bfill*(MAXBUF) character temp2*(MAXBUF) integer i,ii,mxline,ioffst,ifree,icpos,itpos integer ixpos,ixtpos,it,im,kbin,kpass integer lstring logical pflush,waslop data waslop /.false./ C bfill = ' ' lstring = min(MAXBUF,lastnb(string)) mxline=MAXBUF if(line_.gt.0) mxline=min(line_,MAXBUF) if(pfold_.gt.0) then if (pfold_ .lt. lprefx+lstring) then call warn('Invalid value of pfold_, reset') pfold = min(line_,lprefx+lstring) endif mxline=min(mxline,pfold_) endif temp(1:lstring)=string temp2=temp pflush=.false. if(pchar.lt.0) pflush=.true. C do 100 i=lstring,1,-1 if(temp(i:i).eq.' ') goto 100 if(ptabx_.and.temp(i:i).eq.tab) goto 100 goto 110 100 continue i=0 it=i C C....... Organise the output of loop_ items C 110 if(i.eq.0) goto 130 if(i.eq.1.and.string.eq.tab) goto 130 if(i.eq.1.and.string.eq.char(0)) then pcharl=MAXBUF goto 200 endif if((.not.xmlout_).and.temp(1:1).eq.'#') goto 130 if(xmlout_.and.temp(1:1).eq.'<') go to 130 if(ploopf.eq.'yes') goto 130 if(ptextf.eq.'yes') goto 130 if(ploopn.le.0) goto 130 ploopc=ploopc+1 if(align_.or.tabl_) then if(ploopc.gt.ploopn) then if(pcharl.gt.lprefx) pflush=.true. ploopc=1 if(pchar.gt.0) pchar=lprefx+1 endif if(pchar.lt.0) goto 130 if(tabl_) then kbin=(mxline-lprefx)/8 if(ploopn.lt.kbin) then if(kbin/(ploopn+1).gt.1) then pchar=9+lprefx+ * (ploopc-1)*8*(kbin/(ploopn+1)) else pchar=1+lprefx+ * (ploopc-1)*8*(kbin/ploopn) endif else if(ploopc.le.kbin) then pchar=1+lprefx+(ploopc-1)*8 else kpass=(ploopc-kbin-1)/(kbin-1)+1 pchar=2*kpass+1+lprefx+ * mod(ploopc-kbin-1,kbin-1)*8 endif endif else if(ptabx_) then icpos=1 itpos=1 120 ixpos = 0 if (icpos.le.i) ixpos=index(temp(icpos:i),tab) ixtpos=(pchar+itpos-1+ixpos) ixtpos=((ixtpos+7)/8)*8 if(ixpos.gt.0) then if(ixpos.gt.1) then temp2(itpos:ixtpos-pchar+1)=temp(icpos:ixpos-1) else temp2(itpos:ixtpos-pchar+1)=' ' endif icpos=ixpos+1 itpos=ixtpos+2-pchar if(icpos.le.i) goto 120 it=itpos-1 else if(icpos.le.i) then temp2(itpos:itpos+i-icpos)=temp(icpos:i) it=itpos+i-icpos endif endif endif if((pchar+i).gt.mxline+1.or. * (ptabx_.and.pchar+it.gt.mxline+1)) then if(pcharl.gt.lprefx)pflush=.true. pchar=lprefx+1 endif endif else if(ploopc.le.ploopn) goto 130 ploopc=1 endif C C....... Is the buffer full and needs flushing? C 130 if(i.eq.1.and.string.eq.tab) then if(pcharl.gt.lprefx) then if(obuf(pcharl:pcharl).eq.' ') pcharl=pcharl-1 endif endif if(pchar.le.pcharl.and.pcharl.gt.lprefx) pflush=.true. pchar=max(lprefx+1,pchar) if((ploopf.eq.'yes'.or.ploopn.le.0).and.tabl_) * pchar=((pchar-lprefx+6)/8)*8+1+lprefx if(ptabx_) then icpos=1 itpos=1 135 ixpos=0 if(icpos.le.i) ixpos=index(temp(icpos:i),tab) ixtpos=(pchar+itpos-1+ixpos) ixtpos=((ixtpos+7)/8)*8 if(ixpos.gt.0) then if(ixpos.gt.1) then temp2(itpos:ixtpos-pchar+1)=temp(icpos:ixpos-1) else temp2(itpos:ixtpos-pchar+1)=' ' endif icpos=ixpos+1 itpos=ixtpos+2-pchar if(icpos.le.i) goto 135 it=itpos-1 else if(icpos.le.i) then temp2(itpos:itpos+i-icpos)=temp(icpos:i) it=itpos+i-icpos endif endif endif if((pchar+i).gt.mxline+1.or. * (ptabx_.and.pchar+it.gt.mxline+1)) then pflush=.true. pchar=mxline+1-i if (xmlout_) pchar = 1 pchar=max(lprefx+1,pchar) endif if(.not.pflush) goto 150 140 if(pcharl.gt.lprefx) then if(waslop.or.(.not.tabl_)) goto 145 ioffst=0 pcharl=max(lastnb(obuf(1:pcharl)),lprefx+1) ifree=mxline-pcharl if(ifree.gt.0) then im=numtab+2 if(numtab.gt.0.and.numtab.le.MAXTAB) then if(obuf(itabp(numtab):itabp(numtab)).eq.'#') * im=im-1 endif if(ifree.ge.16.and.im.lt.4.and. * (obuf(1+lprefx:1+lprefx).ne.'#' * .and.((.not.xmlout_).or.( * obuf(1+lprefx:1+lprefx).ne.'<' * .and.obuf(1+lprefx:1+lprefx).ne.']')) * .and.obuf(1+lprefx:1+lprefx).ne.';' * .and.obuf(1+lprefx:1+lprefx).ne.'_' * .and.obuf(1+lprefx:1+lprefx).ne.' ' * .and.obuf(1+lprefx:5+lprefx).ne.'data_' * .and.obuf(1+lprefx:5+lprefx).ne.'save_' * .and.obuf(1+lprefx:5).ne.'loop_')) then temp(1+lprefx:pcharl)=obuf(1+lprefx:pcharl) obuf(1+lprefx:pcharl+8)= * bfill(1:8)//temp(1+lprefx:pcharl) ioffst = 8 ifree=ifree-8 pcharl=pcharl+8 endif do ii=1,min(MAXTAB,numtab) icpos=itabp(ii)+ioffst if(icpos.gt.pcharl) goto 145 if(im.lt.4) then itpos=(max(icpos-lprefx, * ii*(mxline-lprefx)/im)+6)/8 itpos=itpos*8+1+lprefx else itpos=(max(icpos-lprefx, * ii*(mxline-lprefx)/im)+4)/6 itpos=itpos*6+1+lprefx endif if((obuf(icpos:icpos).eq.''''.or. * obuf(icpos:icpos).eq.'"').and. * itpos.gt.icpos) itpos=itpos-1 if(itpos-icpos.gt.ifree) itpos=icpos+ifree if(itpos.gt.icpos) then temp(1:pcharl-icpos+1)= * obuf(icpos:pcharl) if(i.lt.numtab) then ixpos=itabp(ii+1)+ioffst if(ixpos.gt.icpos+itpos-icpos+1) then if(obuf(ixpos-(itpos-icpos+1):ixpos-1).eq. * bfill(1:itpos-icpos+1)) then temp(ixpos-itpos+1:pcharl-itpos+1)= * obuf(ixpos:pcharl) pcharl=pcharl-(itpos-icpos) endif endif endif obuf(icpos:pcharl+itpos-icpos)= * bfill(1:itpos-icpos)//temp(1:pcharl-icpos+1) ifree=ifree-(itpos-icpos) ioffst=ioffst+itpos-icpos pcharl=pcharl+itpos-icpos endif if(ifree.le.0) goto 145 enddo endif 145 pcharl=max(1,lastnb(obuf)) write(outdev,'(a)') obuf(1:pcharl) else if(precn_.gt.0) then if(lprefx.gt.0) then write(outdev,'(a)') obuf(1:lprefx) else write(outdev,'(a)') endif else precn_=precn_-1 endif endif waslop=.false. precn_=precn_+1 do ii = 1,MAXTAB itabp(ii)=0 enddo numtab=0 if(lprefx.gt.0) then obuf=prefx(1:lprefx) else obuf=' ' endif C C....... Load the next item into the buffer C 150 pcharl=pchar+i if(ptabx_) pcharl=pchar+it waslop= ploopf.eq.'no '.and.ploopn.gt.0.and.align_ if(i.eq.0) then if(pcharl.eq.lprefx+1.and. * obuf(lprefx+1:lprefx+1).eq.' ') pcharl=pcharl-1 pchar=pcharl+1 goto 200 endif if(ptabx_) then obuf(pchar:pcharl)=temp2(1:it) else if(string.eq.tab) pcharl=pcharl-1 obuf(pchar:pcharl)=string(1:i) endif if(pchar.gt.1+lprefx) then numtab=numtab+1 if(numtab.le.MAXTAB) itabp(numtab)=pchar endif pchar=pcharl+1 if(pchar.gt.mxline+2) then if (pfold_.eq.0) then call warn(' Output CIF line longer than line_') else call warn(' Output CIF line longer than line_ or pfold_') endif endif C 200 return end C C C C C C >>>>>> Convert the number and esd to string nnnn(m), limited C by relative precision prec C subroutine putnum(numb,sdev,prec) C include 'ciftbx.sys' character string*30,temp*30,c*1,sfmt*8 double precision numb,sdev,prec,xxnumb,xsdev,slog integer i,iexp,ifp,ii,jj,j,jlnz,jn,kexp,m,ixsdev,islog integer kdecp,ibexp,lexp C kdecp=0 if (sdev.gt.abs(numb)*prec) then if (iabs(esdlim_).ne.esdcac) then C C determine the number of digits set by esdlim_ C if (iabs(esdlim_).lt.9 .or.iabs(esdlim_).gt.99999) then call warn(' Invalid value of esdlim_ reset to 19') esdlim_ = 19 endif C C determine the number of esd digits C esddigx = 1.+alog10(float(iabs(esdlim_))) esdcac = iabs(esdlim_) endif C C if esdlim_ < 0, validate pesddig_ C if (esdlim_.lt. 0 )then if (pesddig_.lt.0 .or. pesddig_.gt.5) then call warn(' Invalid value of pesddig_ reset to 0') pesddig_ = 0 endif endif C C determine kexp, the power of 10 necessary C to present sdev as an integer in the range C (esdlim_/10,esdlim_] or [1,-esdlim_] if esdlim_ < 0 C slog = dlog10(sdev) islog = slog+1000. islog = islog-1000 kexp = -islog+esddigx C C Adjust exponent kexp, so that sdev*10**kexp C is in the interval (esdlim_/10,esdlim_] or [1,-esdlim_] C 20 if (kexp.lt.minexp) then call warn(' Underflow of esd') ixsdev = 0 go to 30 endif if (kexp.gt.-minexp) then call warn(' Overflow of esd') ixsdev = 99999 go to 30 endif xsdev = sdev*10.D0**kexp ixsdev = xsdev+.5 if (ixsdev.gt.iabs(esdlim_)) then kexp = kexp -1 go to 20 endif if (ixsdev.lt.(iabs(esdlim_)+5)/10) then kexp = kexp+1 go to 20 endif C C lexp holds the number of trailing zeros which may be C sacrificed in the esd if the number itself has C trailing zeros in the fraction which is permitted if C esdlim_ is negative C C If esdlim_ is negative and pesddig_ is .gt.0, C pesddig_ will be used to force the number of digits C in which case lexp has the number of digits that C must be sacrificed (lexp > 0) or zeros to add (lexp < 0) C lexp=0 if(esdlim_.lt.0) then if(pesddig_.gt.0) then 25 continue if(ixsdev*10**(-lexp).ge.10**(pesddig_))then if(lexp.gt.0) * ixsdev=ixsdev-5*10**(lexp-1) ixsdev=ixsdev+5*10**lexp lexp=lexp+1 goto 25 endif if(ixsdev.lt.10**(pesddig_-1+lexp) * .and.lexp.gt.0) then if(ixsdev*10**(-lexp).le.iabs(esdlim_))then lexp =lexp-1 if(lexp.ge.0) then ixsdev=ixsdev-5*10**lexp endif if(lexp.gt.0) then ixsdev=ixsdev+5*10**(lexp-1) endif goto 25 endif endif kexp=kexp-lexp ixsdev = ixsdev/(10**lexp) lexp=0 else do ii = 1,4 if(mod(ixsdev,10**ii).ne.0) go to 30 lexp = ii enddo endif endif C C We need to present the number to the same scaling C at first, but will adjust to avoid Ennn notation C if possible C 30 xxnumb = dabs(numb)*10.d0**kexp+.5 if(xxnumb*prec .gt.1.D0) then call warn(' ESD less than precision of machine') ixsdev=0 endif if(numb.lt.0.d0) xxnumb = -xxnumb write(string,ndpfmt)xxnumb if(xxnumb.lt.1.d0 .and. xxnumb.ge.0.d0) * string=' 0.0E0' if(xxnumb.gt.-1.d0 .and. xxnumb.lt.0.d0) * string=' -0.0E0' C C Extract the power of 10 C iexp = 0 ibexp = 0 do ii = 0,4 i = 30-ii c = string(i:i) m = index('0123456789',c) if (m.gt.0) then iexp = iexp+(m-1)*10**(ii-ibexp) else if (c.eq.' ') then ibexp = ibexp+1 else if (c.eq.'-') iexp=-iexp goto 40 endif endif enddo call err(' Internal error in putnum') C C Scan the rest of the string shifting the C decimal point to get an integer C 40 ifp = 0 j=1 do ii = 1,i-1 c = string(ii:ii) if (c.ne.' ')then m=index('0123456789+-',c) if(m.ne.0) then temp(j:j)=c if(j.gt.1.or.c.ne.'0')j=j+1 if(j.eq.3.and.temp(1:2).eq.'-0')j=j-1 if(ifp.ne.0)then iexp=iexp-1 if(iexp.le.0) goto 50 endif else if(c.eq.'.') then ifp=1 if(iexp.le.0) goto 50 endif endif endif enddo C C The string from 1 to j-1 has an integer C If iexp < 0, we present a 0. If iexp > 0 C we pad with zeros C 50 if(j.eq.2 .and. temp(1:1).eq.'-') then temp(1:2)='-0' j=3 iexp=0 endif if(j.eq.1 .or .iexp.lt.0) then temp(1:1)='0' j=2 iexp = 0 if(xxnumb.lt.0.d0) then temp(1:2)='-0' j=3 endif endif if (iexp.gt.0) then do ii = 1,iexp temp(j:j)='0' j=j+1 enddo iexp=0 endif string=temp(1:j-1) C C We have the number for which the presentation C would be nnnnnE-kexp. If kexp is gt 0, we can C decrease it and introduce a decimal point C jj=0 if(index('0123456789',temp(1:1)).eq.0) jj=1 if(kexp.gt.0.and.kexp.lt.j-jj+8) then if(kexp.lt.j-1) then if(plzero_ .and. * j-1-kexp.eq.1.and.temp(1:1).eq.'-') then string=temp(1:j-1-kexp)//'0.'// * temp(j-kexp:j-1) j=j+2 else string=temp(1:j-1-kexp)//'.'// * temp(j-kexp:j-1) j=j+1 endif kexp = 0 else if(jj.ne.0)string(1:1)=temp(1:1) if(plzero_) then string(1+jj:2+jj)='0.' do ii=1,kexp-(j-1-jj) string(2+jj+ii:2+jj+ii)='0' enddo string(3+jj+(kexp-(j-1-jj)):30)= * temp(1+jj:j-1) j=j+2+kexp-(j-1-jj) else string(1+jj:1+jj)='.' do ii=1,kexp-(j-1-jj) string(1+jj+ii:1+jj+ii)='0' enddo string(2+jj+(kexp-(j-1-jj)):30)= * temp(1+jj:j-1) j=j+1+kexp-(j-1-jj) endif kexp=0 endif endif kdecp=index(string(1:j-1),'.') if(kdecp.gt.0.and.kdecp.lt.j-1.and.lexp.gt.0) then jj=0 do ii = 1,min(lexp,j-1-kdecp) c = string(j-ii:j-ii) if(c.ne.'0') goto 60 jj=jj+1 enddo 60 j=j-jj ixsdev=ixsdev/10**jj if(.not.pdecp_.and.string(j-1:j-1).eq.'.') then j=j-1 kdecp=0 endif endif if(kdecp.eq.0) then kdecp=j if(pdecp_) then if(plzero_.and. * (j.eq.1 .or. (j.eq.2.and.string(1:1).eq.'-'))) then string(j:j)='0' j=j+1 endif string(j:j)='.' j=j+1 endif endif if(kexp.ne.0) then write(temp(1:5),'(i5)') -kexp string(j:j)='E' j=j+1 do ii=1,5 c=temp(ii:ii) if(c.ne.' ') then string(j:j)=c j=j+1 endif enddo endif C C if there is a standard deviation C append it in parentheses C if(ixsdev.ne.0) then write(temp(1:5),'(i5)') ixsdev string(j:j)='(' j=j+1 do ii=1,5 c=temp(ii:ii) if(c.ne.' ') then string(j:j)=c j=j+1 endif enddo string(j:j)=')' j=j+1 endif else C C There is no standard deviation, just write numb C But limit to the digits implied by prec C slog = dlog10(min(.1D0,max(prec,dpprc))) islog = slog+1000.5 islog = islog-1000 kexp = -islog write(sfmt,'(5h(D30.,i2,1h))') kexp write(temp,sfmt)numb C C Now have the number in the form C [sign][0].nnnnnnnnDeee C which, while sufficient, is not neat C we reformat for the case 0<=eee<=kexp C C C Extract the power of 10 C iexp = 0 ibexp = 0 do ii = 0,4 i = 30-ii c = temp(i:i) m = index('0123456789',c) if (m.gt.0) then iexp = iexp+(m-1)*10**(ii-ibexp) else if (c.eq.' ') then ibexp = ibexp+1 else if (c.eq.'-') iexp=-iexp goto 140 endif endif enddo call err(' Internal error in putnum') C C Scan the rest of the string shifting the C decimal point to get a number with exponent 0, C if possible C 140 ifp = 0 j=1 do ii = 1,i-1 jn=ii c = temp(ii:ii) if (c.ne.' ')then m=index('0123456789+-',c) if(m.ne.0) then string(j:j)=c if(j.gt.1.or.c.ne.'0')j=j+1 if(j.eq.3.and.string(1:2).eq.'-0')j=j-1 if(ifp.ne.0)then iexp=iexp-1 if(iexp.le.0) goto 150 endif else if(c.eq.'.') then ifp = -1 if(iexp.le.0) goto 150 endif endif endif enddo 150 if(plzero_ .and. * (j.eq.1 .or.(j.eq.2.and.string(1:1).eq.'-'))) then string(j:j)='0' j=j+1 endif string(j:j)='.' ifp = j j = j+1 jlnz = j-1 155 do ii = jn+1,i-1 c = temp(ii:ii) if (c.ne.' ')then m=index('0123456789',c) if(m.ne.0) then string(j:j)=c j=j+1 if(m.ne.1)jlnz=j if(m.eq.1.and.ifp.ge.1.and. * pposdec_.ne.0.and.pposend_.ne.0) then if(j-1-ifp-min(iexp,0).le.pposend_-pposdec_) * jlnz=j endif else goto 160 endif endif enddo 160 j=jlnz if(j.eq.1) then string(1:1)='0' j=2 endif if(iexp.lt.0.and.iexp.gt.-7.and.ifp.lt.j-1.and. * ifp.ne.0.and.j-ifp-iexp.le.kexp) then temp(1:ifp)=string(1:ifp) do ii = 1,-iexp temp(ifp+ii:ifp+ii) = '0' enddo temp(ifp-iexp+1:j-iexp-1) = string(ifp+1:j-1) j = j-iexp iexp=0 string(1:j-1) = temp(1:j-1) endif kdecp=index(string(1:j-1),'.') if(kdecp.eq.0) then kdecp=j if(pdecp_) then string(kdecp:kdecp)='.' j=j+1 endif endif if(iexp.ne.0) then write(temp(1:5),'(i5)')iexp string(j:j)='E' j=j+1 do ii=1,5 c=temp(ii:ii) if(c.ne.' ') then string(j:j)=c j=j+1 endif enddo endif endif C if(j.lt.1) then string(1:1)='0' j=2 endif if(kdecp.lt.1)kdecp=j if(pposdec_.ne.0) then pchar=lprefx+pposdec_-kdecp+1 else if(pposval_.ne.0)pchar=lprefx+pposval_ endif call putstr(string(1:j-1)) return end C C C C C C >>>>>> Check dictionary for data name validation C subroutine dcheck(name,type,flag,tflag) C include 'ciftbx.sys' logical flag,tflag integer nln character name*(*),temp*(NUMCHAR), * type*4 C flag=.true. tflag=.true. nln = min(len(name),len(temp)) call tbxxnlc(temp(1:nln),name) call hash_find(temp(1:nln), * dicnam,dicchain,NUMDICT,ndict,dichash,NUMHASH,xdchk) if(xdchk.eq.0) goto 150 if(tcheck.eq.'no ') goto 200 if(type.eq.dictyp(xdchk)) goto 200 if(type.eq.' ') goto 200 if(dictyp(xdchk).eq.'text' .and. type.eq.'char') goto 200 if(dictyp(xdchk).eq.'char' .and. type.eq.'numb') goto 200 tflag=.false. goto 200 150 flag=.false. 200 continue return end C C C C C C >>>>>> End of text string C subroutine eotext C include 'ciftbx.sys' C if(ptextf.ne.'yes') then call warn(' Out-of-sequence call to end text block') return endif ptextf='no ' pchar=-1 if (xmlout_) then call putstr(']]>') if (ploopn.gt.1) then call putxc(plhead(ploopc+1),plxhead(ploopc+1)) endif if (ploopn.le.0) then call putxc(plhead(1),plxhead(1)) plhead(1) = ' ' plxhead(1) = ' ' endif else call putstr(';') endif call putstr(char(0)) return end C C C C C C >>>>>> End of loop detected; check integrity and tidy up pointers C subroutine eoloop C include 'ciftbx.sys' integer i C if(ploopn.eq.0) goto 200 if(ploopn.eq.-1) then if (xmlout_) then plcat = ' ' plxcat = ' ' plhead(1) = 'DUMMY' plxhead(1) = ' ' else call putstr('_DUMMY') endif ploopn=1 ploopc=0 call warn( * ' Missing: missing loop_ name set as _DUMMY') endif if (xmlout_ .and. ploopn.eq.1 .and. * ploopf.ne.'yes') then call putxc(plhead(2),plxhead(2)) endif if(ploopn.eq.ploopc) goto 200 do i=ploopc+1,ploopn if (xmlout_) then call putxo(plhead(i+1),plxhead(1+1)) call putstr('DUMMY') call putxc(plhead(i+1),plxhead(i+1)) else call putstr('DUMMY') endif enddo call warn( * ' Missing: missing loop_ items set as DUMMY') plhead(1) = ' ' plxhead(1) = ' ' C 200 ploopc=0 ploopn=0 if (xmlout_) then call putxc(plhead(1),plxhead(1)) plhead(1) = ' ' call putxc(plcat,plxcat) plcat = ' ' endif return end C C C C C C C >>>>>> Set common default values C block data C include 'ciftbx.sys' data cifdev /1/ data outdev /2/ data dirdev /3/ data errdev /6/ data recbeg_ /1/ data recend_ /0/ data loopct /0/ data nhash /0/ data ndict /0/ data nname /0/ data nbloc /0/ data ploopn /0/ data ploopc /0/ data xmnxlat /0/ data xmdata /0/ data ploopf /'no '/ data ptextf /'no '/ data pfilef /'no '/ data testfl /'no '/ data textfl /'no '/ data vcheck /'no '/ data tcheck /'no '/ data catchk /'yes'/ data parchk /'yes'/ data align_ /.true./ data append_ /.false./ data tabl_ /.true./ data tabx_ /.true./ data ptabx_ /.true./ data text_ /.false./ data loop_ /.false./ data ndcname /0/ data ncname /0/ data save_ /.false./ data saveo_ /.false./ data psaveo /.false./ data glob_ /.false./ data globo_ /.false./ data alias_ /.true./ data aliaso_ /.false./ data nblank_ /.false./ data nblanko_ /.false./ data decp_ /.false./ data pdecp_ /.false./ data lzero_ /.false./ data plzero_ /.false./ data xmlout_ /.false./ data catkey /NUMDICT*.false./ data xmlong_ /.true./ data dchash /NUMHASH*0/ data dichash /NUMHASH*0/ data dhash /NUMHASH*0/ data dcchain /NUMDICT*0/ data aroot /NUMDICT*0/ data keychain /NUMDICT*0/ data ccatkey /NUMDICT*0/ data cindex /NUMBLOCK*0/ data line_ /80/ data lastch /0/ data dictype_ /' '/ data dicname_ /' '/ data dicver_ /' '/ data diccat_ /' '/ data tagname_ /' '/ data plcat /' '/ data plhead /NUMLP1*' '/ data prefx /' '/ data file_ /' '/ data longf_ /1/ data tbxver_ /'CIFtbx version 3.0.4 1 Sep 2006'/ data lprefx /0/ data esdlim_ /19/ data esddig_ /0/ data pesddig_ /0/ data esdcac /19/ data esddigx /2/ data esdfmt /'(e12.2)'/ data edpfmt /'(d12.2)'/ data ndpfmt /'(d30.14)'/ data decprc /1.e-6/ data dpprc /1.d-14/ data decmin /1.e-37/ data dpmin /1.d-307/ data minexp /-307/ data itabp /MAXTAB*0/ data jrect /-1/ data numtab /0/ data recn_ /0/ data precn_ /0/ data posnam_ /0/ data posval_ /0/ data posdec_ /0/ data posend_ /0/ data pposnam_ /0/ data pposval_ /0/ data pposdec_ /0/ data pposend_ /0/ data quote_ /' '/ data pquote_ /' '/ data unfold_ /.false./ data fold_ /.false./ data pfold_ /0/ data ibkmrk /MAXBOOK*-1,MAXBOOK*-1, * MAXBOOK*-1,MAXBOOK*-1/ data lnametb /1/ data nametb /' '/ end C C C change the following include to include 'clearfp_sun.f' C for use on a SUN C include 'clearfp.f'