Back to index

wims  3.65+svn20090927
checkmolc.c
Go to the documentation of this file.
00001 /*
00002    Modified to run w/o p2c libraries
00003    2007 Ernst-Georg Schmid
00004    Modified to run as shared library
00005    2007 Ernst-Georg Schmid
00006    pgchem@tuschehund.de
00007    
00008    compile with gcc without optimizations (except -march= -mcpu=) or it gets SLOWER!
00009    
00010    THIS VERSION HAS extended_molstat SWITCHED ON BY DEFAULT!
00011    
00012    This file is part of the xchem::tigress project.
00013 
00014    --- DUAL LICENSING ---
00015    
00016    If checkmol.c aka. pgchem::barsoi is compiled as a library, it is released under the terms of the
00017    lesser GNU General Public License. For the executable, the original GPL
00018    licensing applies!
00019    
00020    This program is free software; you can redistribute it and/or modify
00021    it under the terms of the lesser GNU General Public License as published by
00022    the Free Software Foundation version 2.1 of the License.
00023   
00024    This program is distributed in the hope that it will be useful,
00025    but WITHOUT ANY WARRANTY; without even the implied warranty of
00026    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00027    lesser GNU General Public License for more details.
00028    
00029    --- DUAL LICENSING ---
00030 
00031    ORIGINAL HEADER:
00032    
00033 checkmol/matchmol
00034 Norbert Haider, University of Vienna, 2003-2007
00035 norbert.haider@univie.ac.at
00036 
00037 This software is published under the terms of the GNU General Public
00038 License (GPL, see below). For a detailed description of this license,
00039 see http://www.gnu.org/copyleft/gpl.html
00040 
00041 If invoked as "checkmol", this program reads 2D and 3D molecular structure
00042 files in various formats (Tripos Alchemy "mol", Tripos SYBYL "mol2", MDL "mol")
00043 and describes the molecule either by its functional groups or by a set of
00044 descriptors useful for database pre-screening (number of rings, sp2-hybridized
00045 carbons, aromatic bonds, etc.; see definition of molstat_rec).
00046 
00047 If invoked as "matchmol", the program reads two individual 2D or 3D molecular
00048 structure files in various formats (see above) and checks if the first molecule
00049 (the "needle") is a substructure of the second one (the "haystack").
00050 "Haystack" can also be a MDL SD-file (containing multiple MOL files);
00051 if invoked with "-" as file argument, both "needle" and "haystack" are
00052 read as an SD-file from standard input, assuming the first entry in
00053 the SDF to be the "needle"; output: entry number + ":F" (false) or ":T" (true)
00054 
00055 
00056 Compile with fpc (Free Pascal, see http://www.freepascal.org), using
00057 the -Sd or -S2 option (Delphi mode; IMPORTANT!)
00058 
00059 example for compilation (with optimization) and installation:
00060 
00061 fpc checkmol.pas -S2 -Xs -OG -Or -O2u -Op1
00062 
00063 as "root", do the following:
00064 
00065 cp checkmol /usr/local/bin
00066 cd /usr/local/bin
00067 ln checkmol matchmol
00068 
00069 
00070 Version history
00071 
00072 v0.1   extends "chkmol" utility (N. Haider, 2002), adds matching functionality;
00073 
00074 v0.1a  minor bugfixes:
00075        stop ring search when max_rings is reached (function is_ringpath);
00076        fixed upper/lowercase of element symbol in MDL molfile output;
00077        added debug output for checkmol (-D option)
00078 
00079 v0.2   added functionality to switch ring search from SAR (set of all rings) to
00080        SSR (set of small rings; see below) if number of rings exceeds max_rings
00081        (1024), e.g. with Buckminster-fullerenes (thanks to E.-G. Schmid for a hint);
00082        added -r command-line option to force ring search into SSR mode;
00083        as SSR, we regard the set of all rings with max. 10 ring members, and in
00084        which no ring is completely contained in another one
00085 
00086 v0.2a  fixed a bug in function is_ringpath which could cause SAR ring search to
00087        overlook a few rings (e.g., the six 8-membered rings in cubane)
00088 
00089 v0.2b  fixed unequal treatment of needle and haystack structures with respect
00090        to aromaticity check (trusting input file vs. full check)
00091 
00092 v0.2c  modified the changes of v0.2b so that they affect only "matchmol" mode;
00093        added quick_match function
00094 
00095 v0.2d  refined function bondtypes_OK so that it does not accept C=O fragments
00096        (and C=S, C=Se, C=Te) as equivalent to aromatic C-O (C-S, C-Se, C-Te);
00097        fixed function find_ndl_ref_atom to use only heavy atoms as "needle"
00098        reference atoms for atom-to-atom match; update function quick_match to
00099        handle queries with only one heavy atom (thanks to A. Barozza for a hint)
00100 
00101 v0.2e  modified procedure get_molstat: adds 1 formal double bond for each aromatic
00102        ring to the "fingerprint" in order to allow an isolated double bond in the
00103        needle to be matched as a fragment of an aromatic ring
00104        ATTENTION: "fingerprints" (molecular statistics) generated with a previous
00105        version of checkmol(-x and -X option) must be updated for structure/
00106        substructure database searching with matchmaol.
00107 
00108 v0.2f  modified procedures chk_ccx, chk_xccx, write_fg_text, write_fg_text_de,
00109        write_fg_code in order to report halogen derivatives other than alkyl halides,
00110        aryl halides and acyl halides (e.g., vinyl halides) and C=C compounds other
00111        than "true" alkenes, enols, enediols, enamines, etc. (e.g. vinyl halides);
00112        added "strict mode" (option -s) for matching: this uses a more thorough
00113        comparison of atom types and bond types (new functions atomtypes_OK_strict,
00114        bondtypes_OK_strict, several minor modifications in other subroutines).
00115 
00116 v0.2g  changed procedure readinputfile (+ minor changes in main routine) in
00117        order to read very large SD input files without "not enough memory" error
00118        (the previous version attempted to read the entire SD file into a buffer,
00119        the new version reads only one molecule at once);
00120        fixed a minor bug in read_mol2file which led to undefined bond types;
00121        added definition of "debug" option as a compiler flag.
00122 
00123 v0.2h  fixed a small bug which caused program hangs with (e.g.) some metal
00124        complexes: this was solved just by increasing the number of possible
00125        neighbor atoms from 8 to 16 (now defined in the constant max_neighbors).
00126 
00127 v0.2i  introduced some more plausibility checking (number of directly connected
00128        atoms), result stored in variable mol_OK (set in count_neighbors);
00129        completely rewrote function matrix_OK which now can handle up to
00130        max_neighbors substituents per atom (previous versions were limited to
00131        4 substituents; larger numbers are required e.g. for ferrocenes and
00132        similar compounds).
00133 
00134 v0.2j  new function raw_hetbond_count: ignores bond order (in contrast to function
00135        hetbond_count), this is better suitable for molecular statistics.
00136        ATTENTION: previously generated "fingerprints" in databases must be updated!
00137        improved recognition of non-conformant SD files (with missing "M  END" line)
00138 
00139 v0.2k  changed quick_match routine to compare atom types only by element in
00140        order to avoid (rare) cases of non-matching identical input files;
00141        slightly changed error message for non-existant input files
00142 
00143 v0.3   changed function update_Htotal in order to distinguish between 3-valent
00144        and 5-valent phosphorus (thanks to H. Feldman for this suggestion);
00145        added a table (array ringprop) to store ring sizes and aromaticity for
00146        faster lookup; changed aromaticity detection (chk_arom) to be fully
00147        independent of Kekulé structures in condensed ring systems; changed add_ring
00148        to store new rings in ascending order (with respect to ring size): this
00149        will cause the aromaticity detection to start with smaller rings;
00150        added additional calls to chk_arom when in SSR ring search mode (to ensure
00151        that all aromatic rings are found); speeded up function is_newring;
00152        added option "-M": this restores the behavior of previous versions,
00153        i.e. metal atoms will be accepted as ring members (which costs a lot
00154        of performance for coordinate compounds like ferrocenes but gives
00155        only little useful information); when used in databases: use the _same_
00156        mode ("-M" or not) _both_ for checkmol (creation of fingerprints) and matchmol;
00157        fixed ugly linebreaks in show_usage;
00158 
00159 v0.3a  fixed a bug in read_charges (which was introduced in the v0.3 code cleanup)
00160 
00161 v0.3b  fixed recognition of ketenes, CO2, CS2, CSO, phosphines, boronic esters
00162 
00163 v0.3c  fixed recognition of hydrazines, hydroxylamines, thiocarboxylic acids,
00164        orthocarboxylic acids; slightly changed textual output for a few functional
00165        groups
00166 
00167 v0.3d  added bond topology feature ("any", "ring", "chain", as defined by MDL specs,
00168        plus "always_any", "excess-ringcount", "exact-ringcount") to bond properties
00169        and implemented its use for substructure searches, either as specified in the
00170        query MDL molfile or by using "strict" mode; added ring_count property to
00171        "bonds" section of Checkmol-tweaked molfiles (using an unused field in the MDL
00172        molfile specs);
00173        added option for E/Z isomer search, either globally (-g option) or per
00174        double bond: bstereo_xyz property, encoded either by a leading "0" in the
00175        bond block of a checkmol-tweaked molfile or by using the "stereo care" flag
00176        as defined in the MDL file specs (both atoms of a double bond must carry
00177        this flag)
00178 
00179 v0.3e  fixed wrong position of "stereo care" flag expected in input molfile;
00180 
00181 v0.3f  added option for enantiospecific search (R/S isomer search); this can be
00182        turned on either globally (-G option or using the "chiral" flag in the
00183        "counts line" of the query MDL molfile) or per atom (using - or abusing -
00184        the "stereo care" flag); enantiomers are compared using the 3D coordinates
00185        of the substituents at a chiral center, so we do not have to rely on the
00186        presence of correct "up" and "down" bond types in the candidate structures;
00187        nevertheless, "pseudo-3D" structures (i.e. flat 2D structures with "up"
00188        and "down" bond notation) can be also used, even in mixed mode both as
00189        query structure and candidate structure; added support for "up" and "down"
00190        bond notation in MDL molfile output (if -m option is used and these bond
00191        types were present in the input file); refined function find_ndl_ref_atom;
00192        fixed Alchemy atom type misinterpretation (upper/lower case mismatch);
00193 
00194 v0.3g  minor fixes: recognition of sp2 nitrogen in N=N structures (function
00195        update_atypes); extended E/Z geometry check to C=N and N=N bonds; accelerated
00196        exact search by initial comparison of C,O,N counts; added meaningful error
00197        message for input structures with 0 (zero) atoms;
00198 
00199 v0.3h  added a match matrix clean-up step to function is_matching in order to
00200        remove "impossible" multiple matches prior to chirality check; added
00201        function ndl_maybe_chiral as a plausibility check; added support for other
00202        atoms than carbon as chiral centers; changed function is_cis from a
00203        distance-based cis/trans check into a torsion-based check;
00204 
00205 v0.3i  minor fixes in functions max_neighbors and chk_ammon;
00206        revert ringsearch_mode to its original value for each new molecule
00207        (main routine)
00208 
00209 v0.3j  various improvements in checkmol: added alkenyl (vinyl) and alkynyl
00210        residues as possible substituents for amides, esters, ethers, etc.;
00211        extended recognition of orthocarboxylic acid derivatives; refined
00212        recognition of oxohetarenes and iminohetareenes, ureas, nitroso
00213        compounds; fixed reading of "old-style" charges from MDL files;
00214        refined aromaticity check; fixed a bug in procedure chk_arom and
00215        renamed function is_exocyclic_methylene_C into
00216        find_exocyclic_methylene_C; added assignment of pointers to "nil"
00217        after calling "freemem" in procedure zap_molecule and zap_needle;
00218        matchmol: refined selection of needle reference atom; added "strict
00219        chirality check" mode (if -x -s and -G options are used): returns
00220        "false" if a chiral or pseudochiral atom is matched against its
00221        counterpart with undefined or "flat" geometry; added an alternative
00222        selection mechanism for the needle reference atom, based on the
00223        Morgan algorithm;
00224 
00225 v0.3k  improved matching of nitro compounds (ionic vs. non-ionic
00226        representation); some finetuning in recognition of N-oxides,
00227        hydroxylamines, etc.; modified get_molstat in order to ignore
00228        charges in nitro groups, N-oxides, sulfoxides, azides, etc. in
00229        ionic representation; added function normalize_ionic_bonds;
00230        fixed a bug in is_alkenyl; fixed a bug (introduced in v0.3j) in
00231        the treatment of "old-style" MDL charges;
00232 
00233 v0.3l  minor adjustments in quick_match (for unknown atom types,
00234        opposite charges); some performance improvements, e.g. in function
00235        path_pos, reduced extensive calls to is_heavyatom and is_metal
00236        by extending atom_rec with boolean fields 'heavy' and 'metal'
00237        (thanks to E.-G.Schmid); added molstat field n_rBz (number of
00238        benzene rings; deactivated by default); added -l command-line
00239        option to checkmol (lists all molstat codes with a short
00240        explanation); added graceful handling of NoStruct (i.e.,
00241        zero-atom) molecules
00242 
00243 v0.3m  minor bug fixes (chk_imine), let normalize_ionic_bonds return "true"
00244        if some bond-order change was made; fixed incorrect implementation
00245        of the Morgan algorithm (thanks to H.Feldman), fixed is_matching in
00246        order to prevent wrong matches of larger rings on smaller ones; count
00247        halogens also as type "X" in molstat (as before v0.3l); added some more
00248        molstat descriptors for most elements (deactivated by default; for
00249        activation, uncomment the definition of "extended_molstat", see below);
00250        added support for the generation of binary fingerprints with output
00251        either as boolean values (-f option) or as decimal values (-F option),
00252        fingerprint patterns are supplied by the user (in SDF format, max. 62
00253        structures per file); added a version check ("tweaklevel",
00254        ringsearch_mode, opt_metalrings) for "tweaked" MDL molfiles
00255 
00256 v0.3n  increased max_vringsize in SSR mode from 10 to 12 (now defined in
00257        ssr_vringsize); optionally changed ring statistics to ignore envelope
00258        rings (which completely contain another ring, "reduced SAR") in order to
00259        make molstat in SAR and SSR mode more compatible) - disabled by default;
00260        introduced a new molstat descriptor: n_br2p (number of bonds which
00261        belong to two or more rings); changed n_b1 counter to ignore bonds to
00262        explicit hydrogens; added procedure fix_ssr_ringcounts
00263        (see comment in the code); added bond property mdl_stereo for preservation
00264        of original value; slightly changed "get_molstat" and "update_atypes" in
00265        order to consolidate atom type for various N atoms; remember "chiral" flag
00266        status in molfile output (-m); modified chk_arom in order to accept rings
00267        as aromatic if all bonds are of type 'A'; several minor bug fixes
00268 
00269 v0.3o  minor changes in update_atypes (nitrogen); changed the matching
00270        algorithm in order to take care of disconnected molecular graphs
00271        (e.g., salts); refined matching of atoms with formal charges
00272 
00273 
00274 Credits:
00275 
00276 Rami Jbara (rami_jbara@hotmail.com) designed the 8-character functional
00277 group codes.
00278 
00279 I am also very grateful to Ernst-Georg Schmid (Bayer Business Services,
00280 Leverkusen/Germany) and to Howard Feldman (The Blueprint Initiative,
00281 Toronto/Canada) for numerous bug reports and suggestions for improvements.
00282 
00283 
00284 
00285 ===============================================================================
00286 DISCLAIMER
00287 This program is free software; you can redistribute it and/or
00288 modify it under the terms of the GNU General Public License
00289 as published by the Free Software Foundation; either version 2
00290 of the License, or (at your option) any later version.
00291 
00292 This program is distributed in the hope that it will be useful,
00293 but WITHOUT ANY WARRANTY; without even the implied warranty of
00294 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00295 GNU General Public License for more details.
00296 
00297 You should have received a copy of the GNU General Public License
00298 along with this program; if not, write to the Free Software Foundation,
00299 Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00300 ===============================================================================
00301 */
00302 
00303 /* $DEFINE debug                    uncomment if desired */
00304 /* $DEFINE extended_molstat         uncomment if desired */
00305 /* $DEFINE reduced_SAR              uncomment if desired */
00306 
00307 /* uses
00308   SYSUTILS, MATH; */
00309 
00310 #include <stdlib.h>
00311 #include <stdio.h>
00312 #include <math.h>
00313 #include <string.h>
00314 #include <ctype.h>
00315 #include <sys/types.h>
00316 #include <sys/stat.h>
00317 #include "safemem.h"
00318 #ifdef MAKE_SHARED_LIBRARY
00319 #include "barsoi.h"
00320 #endif
00321 
00322 #ifdef MAKE_SHARED_LIBRARY
00323 #define version         "0.3p C (pgchem::barsoi)"
00324 #else
00325 #define version         "0.3p C"
00326 #endif
00327 
00328 #undef REDUCED_SAR
00329 
00330 /* How many recursions before aborting is_ringpath and reverting to SSR */
00331 #define max_ringpath_recursion_depth   500000
00332 
00333 /* How many recursions before aborting is_match and reverting to non-exhaustive match */
00334 #define max_match_recursion_depth   500000
00335 
00336 #define tweaklevel      2
00337     /* v0.3m; accept tweaks in MDL molfiles only if same level */
00338 #define max_atoms       1024
00339 #define max_bonds       1024
00340 #define slack           8192
00341 #define max_ringsize    128
00342 #define max_rings       1024
00343 #define max_fg          256
00344 #define max_neighbors   16  /* new in v0.2h */
00345 
00346 #define TAB             '\t'
00347 
00348 #define max_matchpath_length  256
00349 #define pmCheckMol      1001
00350 #define pmMatchMol      1002
00351 
00352 #define rs_sar          2001       /* ring search mode: SAR = set of all rings */
00353 #define rs_ssr          2002
00354     /*                   SSR = set of small rings */
00355 
00356 #define btopo_any       0   /* bond topology, new in v0.3d */
00357 #define btopo_ring      1
00358 #define btopo_chain     2
00359 #define btopo_always_any  3 /* even in "strict mode" */
00360 #define btopo_excess_rc  4
00361 /* bond in candidate must be included in _more_ rings than
00362                         the matching bond in the query ==> specific search for
00363                         annulated systems */
00364 #define btopo_exact_rc  5
00365     /* bond in query and candidate must have same ring count */
00366 
00367 #define bstereo_any     0
00368     /* new in v0.3d, any E/Z isomer matches (for double bonds) */
00369 #define bstereo_xyz     1
00370     /* E/Z match is checked by using XYZ coordinates of the atoms */
00371 #define bstereo_up      11  /* new in v0.3f, flags for single bonds */
00372 #define bstereo_down    16
00373 #define bstereo_either    14       /* 0.3x */
00374 #define bstereo_double_either    13       /* 0.3x */
00375 
00376 #define fpf_boolean     3001
00377     /* v0.3m; format for fingerprint output (n:T, n:F) */
00378 #define fpf_decimal     3002
00379     /* v0.3m; format for fingerprint output as decimal value of bitstring */
00380 #define fp_blocksize    62
00381     /* v0.3m; 1 bit may be used for sign (e.g. by PHP), 1 bit for "exact hit" */
00382 #define ssr_vringsize   12  /* v0.3n; max. ring size in SSR mode */
00383 
00384 /* Definitions for functional groups: */
00385 #define fg_cation       1
00386 #define fg_anion        2
00387 #define fg_carbonyl     3
00388 #define fg_aldehyde     4
00389 #define fg_ketone       5
00390 #define fg_thiocarbonyl  6
00391 #define fg_thioaldehyde  7
00392 #define fg_thioketone   8
00393 #define fg_imine        9
00394 #define fg_hydrazone    10
00395 #define fg_semicarbazone  11
00396 #define fg_thiosemicarbazone  12
00397 #define fg_oxime        13
00398 #define fg_oxime_ether  14
00399 #define fg_ketene       15
00400 #define fg_ketene_acetal_deriv  16
00401 #define fg_carbonyl_hydrate  17
00402 #define fg_hemiacetal   18
00403 #define fg_acetal       19
00404 #define fg_hemiaminal   20
00405 #define fg_aminal       21
00406 #define fg_thiohemiaminal  22
00407 #define fg_thioacetal   23
00408 #define fg_enamine      24
00409 #define fg_enol         25
00410 #define fg_enolether    26
00411 #define fg_hydroxy      27
00412 #define fg_alcohol      28
00413 #define fg_prim_alcohol  29
00414 #define fg_sec_alcohol  30
00415 #define fg_tert_alcohol  31
00416 #define fg_1_2_diol     32
00417 #define fg_1_2_aminoalcohol  33
00418 #define fg_phenol       34
00419 #define fg_1_2_diphenol  35
00420 #define fg_enediol      36
00421 #define fg_ether        37
00422 #define fg_dialkylether  38
00423 #define fg_alkylarylether  39
00424 #define fg_diarylether  40
00425 #define fg_thioether    41
00426 #define fg_disulfide    42
00427 #define fg_peroxide     43
00428 #define fg_hydroperoxide  44
00429 #define fg_hydrazine    45
00430 #define fg_hydroxylamine  46
00431 #define fg_amine        47
00432 #define fg_prim_amine   48
00433 #define fg_prim_aliph_amine  49
00434 #define fg_prim_arom_amine  50
00435 #define fg_sec_amine    51
00436 #define fg_sec_aliph_amine  52
00437 #define fg_sec_mixed_amine  53
00438 #define fg_sec_arom_amine  54
00439 #define fg_tert_amine   55
00440 #define fg_tert_aliph_amine  56
00441 #define fg_tert_mixed_amine  57
00442 #define fg_tert_arom_amine  58
00443 #define fg_quart_ammonium  59
00444 #define fg_n_oxide      60
00445 #define fg_halogen_deriv  61
00446 #define fg_alkyl_halide  62
00447 #define fg_alkyl_fluoride  63
00448 #define fg_alkyl_chloride  64
00449 #define fg_alkyl_bromide  65
00450 #define fg_alkyl_iodide  66
00451 #define fg_aryl_halide  67
00452 #define fg_aryl_fluoride  68
00453 #define fg_aryl_chloride  69
00454 #define fg_aryl_bromide  70
00455 #define fg_aryl_iodide  71
00456 #define fg_organometallic  72
00457 #define fg_organolithium  73
00458 #define fg_organomagnesium  74
00459 #define fg_carboxylic_acid_deriv  75
00460 #define fg_carboxylic_acid  76
00461 #define fg_carboxylic_acid_salt  77
00462 #define fg_carboxylic_acid_ester  78
00463 #define fg_lactone      79
00464 #define fg_carboxylic_acid_amide  80
00465 #define fg_carboxylic_acid_prim_amide  81
00466 #define fg_carboxylic_acid_sec_amide  82
00467 #define fg_carboxylic_acid_tert_amide  83
00468 #define fg_lactam       84
00469 #define fg_carboxylic_acid_hydrazide  85
00470 #define fg_carboxylic_acid_azide  86
00471 #define fg_hydroxamic_acid  87
00472 #define fg_carboxylic_acid_amidine  88
00473 #define fg_carboxylic_acid_amidrazone  89
00474 #define fg_nitrile      90
00475 #define fg_acyl_halide  91
00476 #define fg_acyl_fluoride  92
00477 #define fg_acyl_chloride  93
00478 #define fg_acyl_bromide  94
00479 #define fg_acyl_iodide  95
00480 #define fg_acyl_cyanide  96
00481 #define fg_imido_ester  97
00482 #define fg_imidoyl_halide  98
00483 #define fg_thiocarboxylic_acid_deriv  99
00484 #define fg_thiocarboxylic_acid  100
00485 #define fg_thiocarboxylic_acid_ester  101
00486 #define fg_thiolactone  102
00487 #define fg_thiocarboxylic_acid_amide  103
00488 #define fg_thiolactam   104
00489 #define fg_imido_thioester  105
00490 #define fg_oxohetarene  106
00491 #define fg_thioxohetarene  107
00492 #define fg_iminohetarene  108
00493 #define fg_orthocarboxylic_acid_deriv  109
00494 #define fg_carboxylic_acid_orthoester  110
00495 #define fg_carboxylic_acid_amide_acetal  111
00496 #define fg_carboxylic_acid_anhydride  112
00497 #define fg_carboxylic_acid_imide  113
00498 #define fg_carboxylic_acid_unsubst_imide  114
00499 #define fg_carboxylic_acid_subst_imide  115
00500 #define fg_co2_deriv    116
00501 #define fg_carbonic_acid_deriv  117
00502 #define fg_carbonic_acid_monoester  118
00503 #define fg_carbonic_acid_diester  119
00504 #define fg_carbonic_acid_ester_halide  120
00505 #define fg_thiocarbonic_acid_deriv  121
00506 #define fg_thiocarbonic_acid_monoester  122
00507 #define fg_thiocarbonic_acid_diester  123
00508 #define fg_thiocarbonic_acid_ester_halide  124
00509 #define fg_carbamic_acid_deriv  125
00510 #define fg_carbamic_acid  126
00511 #define fg_carbamic_acid_ester  127
00512 #define fg_carbamic_acid_halide  128
00513 #define fg_thiocarbamic_acid_deriv  129
00514 #define fg_thiocarbamic_acid  130
00515 #define fg_thiocarbamic_acid_ester  131
00516 #define fg_thiocarbamic_acid_halide  132
00517 #define fg_urea         133
00518 #define fg_isourea      134
00519 #define fg_thiourea     135
00520 #define fg_isothiourea  136
00521 #define fg_guanidine    137
00522 #define fg_semicarbazide  138
00523 #define fg_thiosemicarbazide  139
00524 #define fg_azide        140
00525 #define fg_azo_compound  141
00526 #define fg_diazonium_salt  142
00527 #define fg_isonitrile   143
00528 #define fg_cyanate      144
00529 #define fg_isocyanate   145
00530 #define fg_thiocyanate  146
00531 #define fg_isothiocyanate  147
00532 #define fg_carbodiimide  148
00533 #define fg_nitroso_compound  149
00534 #define fg_nitro_compound  150
00535 #define fg_nitrite      151
00536 #define fg_nitrate      152
00537 #define fg_sulfuric_acid_deriv  153
00538 #define fg_sulfuric_acid  154
00539 #define fg_sulfuric_acid_monoester  155
00540 #define fg_sulfuric_acid_diester  156
00541 #define fg_sulfuric_acid_amide_ester  157
00542 #define fg_sulfuric_acid_amide  158
00543 #define fg_sulfuric_acid_diamide  159
00544 #define fg_sulfuryl_halide  160
00545 #define fg_sulfonic_acid_deriv  161
00546 #define fg_sulfonic_acid  162
00547 #define fg_sulfonic_acid_ester  163
00548 #define fg_sulfonamide  164
00549 #define fg_sulfonyl_halide  165
00550 #define fg_sulfone      166
00551 #define fg_sulfoxide    167
00552 #define fg_sulfinic_acid_deriv  168
00553 #define fg_sulfinic_acid  169
00554 #define fg_sulfinic_acid_ester  170
00555 #define fg_sulfinic_acid_halide  171
00556 #define fg_sulfinic_acid_amide  172
00557 #define fg_sulfenic_acid_deriv  173
00558 #define fg_sulfenic_acid  174
00559 #define fg_sulfenic_acid_ester  175
00560 #define fg_sulfenic_acid_halide  176
00561 #define fg_sulfenic_acid_amide  177
00562 #define fg_thiol        178
00563 #define fg_alkylthiol   179
00564 #define fg_arylthiol    180
00565 #define fg_phosphoric_acid_deriv  181
00566 #define fg_phosphoric_acid  182
00567 #define fg_phosphoric_acid_ester  183
00568 #define fg_phosphoric_acid_halide  184
00569 #define fg_phosphoric_acid_amide  185
00570 #define fg_thiophosphoric_acid_deriv  186
00571 #define fg_thiophosphoric_acid  187
00572 #define fg_thiophosphoric_acid_ester  188
00573 #define fg_thiophosphoric_acid_halide  189
00574 #define fg_thiophosphoric_acid_amide  190
00575 #define fg_phosphonic_acid_deriv  191
00576 #define fg_phosphonic_acid  192
00577 #define fg_phosphonic_acid_ester  193
00578 #define fg_phosphine    194
00579 #define fg_phosphinoxide  195
00580 #define fg_boronic_acid_deriv  196
00581 #define fg_boronic_acid  197
00582 #define fg_boronic_acid_ester  198
00583 #define fg_alkene       199
00584 #define fg_alkyne       200
00585 #define fg_aromatic     201
00586 #define fg_heterocycle  202
00587 #define fg_alpha_aminoacid  203
00588 #define fg_alpha_hydroxyacid  204
00589 
00590 typedef enum
00591 { false = 0, true } boolean;
00592 
00593 
00594 typedef char str2[3];
00595 
00596 typedef char str3[4];
00597 
00598 typedef char str4[5];
00599 
00600 typedef char str5[6];
00601 
00602 typedef char str8[9];
00603 
00604 typedef struct atom_rec
00605 {
00606   str2 element;
00607   str3 atype;
00608   float x, y, z;
00609   int formal_charge;
00610   float real_charge;
00611   int Hexp;                 /* explicit H count */
00612   int Htot;                 /* total H count */
00613   int neighbor_count, ring_count;
00614   boolean arom, stereo_care;       /* new in v0.3d */
00615   boolean q_arom;           // v0.3p potentially aromatic in a query structure
00616   boolean heavy;            /* new in v0.3l */
00617   boolean metal;            /* new in v0.3l */
00618   int nvalences;            /* new in v0.3m */
00619   boolean tag;                     /* new in v0.3o */
00620   int nucleon_number;              /* 0.3.x */
00621   int radical_type;         /* 0.3.x */
00622 } atom_rec;
00623 
00624 typedef struct bond_rec
00625 {
00626   int a1, a2;
00627   char btype;
00628   int ring_count;
00629   boolean arom;
00630   boolean q_arom;           // v0.3p potentially aromatic in a query structure
00631   int topo;                 /* new in v0.3d, see MDL file description */
00632   int stereo;               /* new in v0.3d */
00633   int mdl_stereo;           /* new in v0.3n */
00634 } bond_rec;
00635 
00636 typedef int ringpath_type[max_ringsize];
00637 typedef int matchpath_type[max_matchpath_length];
00638 
00639 typedef atom_rec atomlist[max_atoms];
00640 typedef bond_rec bondlist[max_bonds];
00641 typedef ringpath_type ringlist[max_rings];
00642 typedef int neighbor_rec[max_neighbors];  /* new in v0.2h */
00643 typedef boolean fglist[max_fg];
00644 
00645 typedef char molbuftype[max_atoms + max_bonds + slack][256];
00646 
00647 typedef boolean matchmatrix[max_neighbors][max_neighbors];
00648     /* new in v0.2i */
00649 
00650 typedef struct molstat_rec
00651 {
00652   int n_QA, n_QB, n_chg;    /* number of query atoms, query bonds, charges */
00653   int n_C1, n_C2, n_C;
00654   /* number of sp, sp2 hybridized, and total no. of carbons */
00655   int n_CHB1p, n_CHB2p, n_CHB3p, n_CHB4;
00656   /* number of C atoms with at least 1, 2, 3 hetero bonds */
00657   int n_O2, n_O3;           /* number of sp2 and sp3 oxygens */
00658   int n_N1, n_N2, n_N3;            /* number of sp, sp2, and sp3 nitrogens */
00659   int n_S, n_SeTe;
00660   /* number of sulfur atoms and selenium or tellurium atoms */
00661   int n_F, n_Cl, n_Br, n_I;
00662   /* number of fluorine, chlorine, bromine, iodine atoms */
00663   int n_P, n_B;                    /* number of phosphorus and boron atoms */
00664   int n_Met, n_X;
00665   /* number of metal and "other" atoms (not listed elsewhere); v0.3l */
00666   int n_b1, n_b2, n_b3, n_bar;
00667   /* number single, double, triple, and aromatic bonds */
00668   int n_C1O, n_C2O, n_CN, n_XY;
00669   /* number of C-O single bonds, C=O double bonds, CN bonds (any type), hetero/hetero bonds */
00670   int n_r3, n_r4, n_r5, n_r6, n_r7, n_r8;
00671   /* number of 3-, 4-, 5-, 6-, 7-, and 8-membered rings */
00672   int n_r9, n_r10, n_r11, n_r12, n_r13p;
00673   /* number of 9-, 10-, 11-, 12-, and 13plus-membered rings */
00674   int n_rN, n_rN1, n_rN2, n_rN3p;
00675   /* number of rings containing N (any number), 1 N, 2 N, and 3 N or more */
00676   int n_rO, n_rO1, n_rO2p;
00677   /* number of rings containing O (any number), 1 O, and 2 O or more */
00678   int n_rS, n_rX, n_rAr, n_rBz;
00679   /* number of rings containing S (any number), any heteroatom (any number),  */
00680   /* number of aromatic rings, number of benzene rings */
00681   int n_br2p;               /* number of bonds belonging to more than one ring (v0.3n) */
00682 /* p2c: checkmol.pas, line 590:
00683  * Note: Turbo Pascal conditional compilation directive was ignored [218] */
00684   /*$IFDEF extended_molstat */
00685   int n_psg01, n_psg02, n_psg13, n_psg14;
00686   /* number of atoms belonging to elements of group 1, 2, etc.  */
00687   int n_psg15, n_psg16, n_psg17, n_psg18;
00688   /* number of atoms belonging to elements of group 15, 16, etc.  */
00689   int n_pstm, n_psla;
00690   /* number of transition metals, lanthanides/actinides */
00691   int n_iso, n_rad;
00692   /* number of isotopes, radicals */
00693   /*$ENDIF */
00694 } molstat_rec;
00695 
00696 typedef struct ringprop_rec
00697 {
00698   /* new in v0.3 */
00699   int size;
00700   boolean arom, envelope;
00701 } ringprop_rec;
00702 
00703 typedef ringprop_rec ringprop_type[max_rings];
00704 
00705 typedef struct p_3d
00706 {
00707   /* new in v0.3d */
00708   double x, y, z;
00709 } p_3d;
00710 
00711 typedef int chirpath_type[4];      /* new in v0.3f */
00712 
00713 #ifdef MAKE_SHARED_LIBRARY
00714 static boolean yet_initialized = false;
00715 #endif
00716 
00717 typedef struct connval_rec
00718 {
00719   /* new in v0.3j */
00720   int def;                  /* better as longint for large molecules? */
00721   int tmp;
00722 } connval_rec;
00723 
00724 typedef connval_rec connval_type[max_atoms];     /* new in v0.3j  */
00725 
00726 
00727 static int progmode;
00728 static char progname[256];
00729 
00730 #ifndef MAKE_SHARED_LIBRARY
00731 static int i;               /* general purpose index */
00732 #endif
00733 
00734 static int li;
00735 static boolean opt_none, opt_verbose, opt_text, opt_text_de, opt_code,
00736   opt_bin, opt_bitstring, opt_stdin, opt_exact, opt_debug,
00737   opt_molout, opt_molstat, opt_molstat_X, opt_xmdlout, opt_strict;
00738     /* new in v0.2f */
00739 static boolean opt_metalrings;     /* new in v0.3 */
00740 static boolean opt_geom;    /* new in v0.3d */
00741 static boolean opt_chiral;  /* new in v0.3f */
00742 static boolean opt_iso;            /* new in v0.3x */
00743 static boolean opt_chg;            /* new in v0.3x */
00744 static boolean opt_rad;            /* new in v0.3x */
00745 static int opt_rs;          /* new in v0.3i */
00746 
00747 #ifdef MAKE_SHARED_LIBRARY
00748 static int opt_rs_dll = RPA_DEFAULT;
00749 #endif
00750 
00751 static boolean opt_fp;             /* new in v0.3m */
00752 static int fpformat;        /* new in v0.3m */
00753 static char filetype[256];
00754 /*molfile : text; */
00755 static char molfilename[256];
00756 static char ndl_molfilename[256];
00757 static char molname[256];
00758 static char ndl_molname[256];
00759 static char tmp_molname[256];      /* v0.3m */
00760 static char molcomment[256];
00761 static int n_atoms, n_bonds, n_rings;
00762     /* the number of rings we determined ourselves */
00763 static int n_countablerings;
00764     /* v0.3n; number of rings which are not envelope rings */
00765 static int n_cmrings;
00766     /* the number of rings we read from a (CheckMol-tweaked) MDL molfile */
00767 //static int n_charges;         /* number of charges */
00768 static int n_heavyatoms, n_heavybonds, ndl_n_atoms, ndl_n_bonds, ndl_n_rings,
00769   ndl_n_heavyatoms, ndl_n_heavybonds;
00770 /*cm_mdlmolfile  : boolean; */
00771 static boolean found_arominfo, found_querymol, ndl_querymol;
00772 static int tmp_n_atoms;            /* v0.3m */
00773 static int tmp_n_bonds;            /* v0.3m */
00774 static int tmp_n_rings;            /* v0.3m */
00775 static int tmp_n_heavyatoms;       /* v0.3m */
00776 static int tmp_n_heavybonds;       /* v0.3m */
00777 
00778 static atom_rec *atom;
00779 static bond_rec *bond;
00780 static ringpath_type *ring;
00781 static ringprop_rec *ringprop;     /* new in v0.3 */
00782 
00783 static atom_rec *ndl_atom;
00784 static bond_rec *ndl_bond;
00785 static ringpath_type *ndl_ring;
00786 static ringprop_rec *ndl_ringprop; /* new in v0.3 */
00787 static int ndl_ref_atom;    /* since v0.3j as a global variable */
00788 static atom_rec *tmp_atom;  /* v0.3m */
00789 static bond_rec *tmp_bond;  /* v0.3m */
00790 static ringpath_type *tmp_ring;    /* v0.3m */
00791 static ringprop_rec *tmp_ringprop; /* v0.3m */
00792 
00793 static boolean matchresult, matchsummary; /* v0.3o */
00794 static matchpath_type ndl_matchpath, hst_matchpath;
00795 
00796 static fglist fg;
00797 static str4 atomtype;
00798 static str3 newatomtype;
00799 
00800 static char (*molbuf)[256];
00801 static int molbufindex;
00802 
00803 static boolean mol_in_queue;
00804 static int mol_count;
00805 
00806 static molstat_rec molstat, ndl_molstat, tmp_molstat;   /* v0.3m */
00807 
00808 static int ringsearch_mode, max_vringsize;       /* for SSR ring search */
00809 
00810 static FILE *rfile;
00811 static boolean rfile_is_open, mol_OK;     /* new in v0.2i */
00812 
00813 static int n_ar;            /* new in v0.3 */
00814 static int prev_n_ar;              /* new in v0.3 */
00815 static boolean ez_search;   /* new in v0.3d */
00816 static boolean rs_search;   /* new in v0.3f */
00817 static boolean ez_flag;            /* new in v0.3f */
00818 static boolean chir_flag;   /* new in v0.3f */
00819 static boolean rs_strict;   /* new in v0.3j */
00820 
00821 static int n_Ctot, n_Otot, n_Ntot; /* new in v0.3g */
00822 static int ndl_n_Ctot, ndl_n_Otot, ndl_n_Ntot;   /* new in v0.3g */
00823 static int tmp_n_Ctot, tmp_n_Otot, tmp_n_Ntot;   /* new in v0.3m */
00824 static boolean ether_generic;      /* v0.3j */
00825 static boolean amine_generic;      /* v0.3j   */
00826 static boolean hydroxy_generic;    /* v0.3j */
00827 static connval_rec *cv;            /* new in v0.3j */
00828 static long long fpdecimal; /* v0.3m */
00829 static long long fpincrement;
00830 static int fpindex;
00831 static boolean fp_exacthit, fp_exactblock;
00832 static int tmfcode;
00833     /* v0.3m; version number for tweaked MDL molfiles (tweaklevel) */
00834 static boolean tmfmismatch;
00835     /* v0.3m; rely on tweaked MDL molfiles only if same level */
00836 static boolean auto_ssr;
00837     /* v0.3n; indicates that SAR -> SSR fallback has happened */
00838 static int recursion_depth;
00839     /* ====================emulated pascal functions============================ */
00840 
00841 static boolean
00842 file_exists (const char *fileName)
00843 {
00844   struct stat filestat;
00845 
00846   return stat (fileName, &filestat) == 0 ? true : false;
00847 }
00848 
00849 static void
00850 lblank (int cols, char *nstr)
00851 {
00852   /* inserts leading blanks up to a given number of total characters */
00853   char STR1[256];
00854 
00855   if (strlen (nstr) >= cols)
00856     return;
00857   while (strlen (nstr) < cols)
00858     sprintf (nstr, " %s", strcpy (STR1, nstr));
00859 }
00860 
00861 static inline double
00862 radtodeg (double rads)
00863 {
00864   return (180.0 / M_PI) * rads;
00865 }
00866 
00867 static void
00868 strdelete (char *s, int pos, int len)
00869 {
00870   int slen;
00871 
00872   if (--pos < 0)
00873     return;
00874   slen = strlen (s) - pos;
00875   if (slen <= 0)
00876     return;
00877   s += pos;
00878   if (slen <= len)
00879     {
00880       *s = 0;
00881       return;
00882     }
00883   while ((*s = s[len]))
00884     s++;
00885 }
00886 
00887 static int
00888 strpos2 (char *s, char *pat, int pos)
00889 {
00890   char *cp, ch;
00891   int slen;
00892 
00893   if (--pos < 0)
00894     return 0;
00895   slen = strlen (s) - pos;
00896   cp = s + pos;
00897   if (!(ch = *pat++))
00898     return 0;
00899   pos = strlen (pat);
00900   slen -= pos;
00901   while (--slen >= 0)
00902     {
00903       if (*cp++ == ch && !strncmp (cp, pat, pos))
00904        return cp - s;
00905     }
00906   return 0;
00907 }
00908 
00909 static char *
00910 strsub (char *ret, char *s, int pos, int len)
00911 {
00912   char *s2;
00913 
00914   if (--pos < 0 || len <= 0)
00915     {
00916       *ret = 0;
00917       return ret;
00918     }
00919   while (pos > 0)
00920     {
00921       if (!*s++)
00922        {
00923          *ret = 0;
00924          return ret;
00925        }
00926       pos--;
00927     }
00928   s2 = ret;
00929   while (--len >= 0)
00930     {
00931       if (!(*s2++ = *s++))
00932        return ret;
00933     }
00934   *s2 = 0;
00935   return ret;
00936 }
00937 
00938 
00939 /*============================= auxiliary functions & procedures */
00940 
00941 inline static void
00942 all_lowercase (char *astring)
00943 {
00944   int i;
00945   int l = strlen (astring);
00946 
00947   for (i = 0; i < l; i++)
00948     {
00949       astring[i] = tolower (astring[i]);
00950     }
00951 }
00952 
00953 static void
00954 init_globals ()
00955 {
00956   int i;
00957 
00958   opt_verbose = false;
00959   opt_debug = false;
00960   opt_exact = false;
00961   opt_stdin = false;
00962   opt_text = false;
00963   opt_code = false;
00964   opt_bin = false;
00965   opt_bitstring = false;
00966   opt_molout = false;
00967   opt_molstat = false;
00968   opt_molstat_X = false;
00969   opt_xmdlout = false;
00970   opt_strict = false;              /* new in v0.2f */
00971   opt_metalrings = false;   /* new in v0.3 */
00972   opt_geom = false;         /* new in v0.3d */
00973   opt_chiral = false;              /* new in v0.3f */
00974   opt_fp = false;           /* new in v0.3m */
00975   opt_iso = false;          /* new in v0.3x */
00976   opt_chg = false;          /* new in v0.3x */
00977   opt_rad = false;          /* new in v0.3x */
00978   /*cm_mdlmolfile   := false; */
00979   found_arominfo = false;
00980   found_querymol = false;
00981   ndl_querymol = false;
00982   opt_rs = rs_sar;          /* v0.3i */
00983   /*ringsearch_mode := rs_sar; */
00984   rfile_is_open = false;    /* new in v0.2g */
00985   ez_search = false;        /* new in v0.3d */
00986   rs_search = false;        /* new in v0.3f */
00987   ez_flag = false;          /* new in v0.3f */
00988   chir_flag = false;        /* new in v0.3f */
00989   rs_strict = false;        /* new in v0.3j */
00990   n_Ctot = 0;
00991   n_Otot = 0;
00992   n_Ntot = 0;               /* new in v0.3g */
00993   ndl_n_Ctot = 0;
00994   ndl_n_Otot = 0;
00995   ndl_n_Ntot = 0;           /* new in v0.3g */
00996   //for (i = 0; i < max_fg; i++)
00997   //  fg[i] = false;
00998   memset (fg, 0, sizeof (fglist));
00999   /*try */
01000   molbuf = safe_malloc (sizeof (molbuftype));
01001   /*except
01002      on e:Eoutofmemory do
01003      begin
01004      writeln('Not enough memory');
01005      halt(4);
01006      end;
01007      end; */
01008   ether_generic = false;    /* v0.3j */
01009   amine_generic = false;    /* v0.3j */
01010   hydroxy_generic = false;  /* v0.3j */
01011   fpformat = fpf_decimal;   /* v0.3m */
01012   fpindex = 0;                     /* v0.3m */
01013   fp_exacthit = false;             /* v0.3m */
01014   fp_exactblock = false;    /* v0.3m */
01015   tmfcode = 0;                     /* v0.3m */
01016   tmfmismatch = false;             /* v0.3m */
01017   auto_ssr = false;         /* v0.3n */
01018   recursion_depth = 0;
01019 }
01020 
01021 
01022 static inline void
01023 init_molstat (mstat)
01024      molstat_rec *mstat;
01025 {
01026   /*
01027      with mstat do
01028      begin
01029      n_QA := 0; n_QB := 0; n_chg := 0;
01030      n_C1 := 0; n_C2 := 0; n_C  := 0;
01031      n_CHB1p := 0; n_CHB2p := 0; n_CHB3p := 0; n_CHB4 := 0;
01032      n_O2 := 0; n_O3  := 0;
01033      n_N1 := 0; n_N2 := 0; n_N3 := 0;
01034      n_S := 0; n_SeTe := 0;
01035      n_F := 0; n_Cl := 0; n_Br := 0; n_I := 0;
01036      n_P := 0; n_B := 0;
01037      n_Met := 0; n_X := 0;
01038      n_b1 := 0; n_b2 := 0; n_b3 := 0; n_bar := 0;
01039      n_C1O := 0; n_C2O := 0; n_CN := 0; n_XY := 0;
01040      n_r3 := 0; n_r4 := 0; n_r5 := 0; n_r6 := 0; n_r7 := 0;
01041      n_r8 := 0; n_r9 := 0; n_r10 := 0; n_r11 := 0; n_r12 := 0; n_r13p := 0;
01042      n_rN := 0; n_rN1 := 0; n_rN2 := 0; n_rN3p := 0;
01043      n_rO := 0; n_rO1 := 0; n_rO2p := 0;
01044      n_rS := 0; n_rX := 0;
01045      n_rAr := 0; n_rBz := 0; n_br2p := 0;
01046      end;
01047    */
01048   memset (mstat, 0, sizeof (molstat_rec));       /* v0.3k */
01049 }
01050 
01051 
01052 static void
01053 debugoutput (dstr)
01054      char *dstr;
01055 {
01056   if (opt_debug)
01057     printf ("%s\n", dstr);
01058 }
01059 
01060 
01061 static void
01062 left_trim (trimstr)
01063      char *trimstr;
01064 {
01065   while (*trimstr != '\0' && (trimstr[0] == ' ' || trimstr[0] == TAB))
01066     strdelete (trimstr, 1, 1);
01067 }
01068 
01069 
01070 static int
01071 left_int (trimstr)
01072      char *trimstr;
01073 {
01074   char numstr[256];
01075   char auxstr[256];
01076   int auxint = 0;
01077   int code;
01078   char STR1[256];
01079 
01080   strcpy (numstr, "-+0123456789");
01081   *auxstr = '\0';
01082   while (*trimstr != '\0' && (trimstr[0] == ' ' || trimstr[0] == TAB))
01083     strdelete (trimstr, 1, 1);
01084   while ((*trimstr != '\0') &&
01085         (strpos2 (numstr, (sprintf (STR1, "%c", trimstr[0]), STR1), 1) > 0))
01086     {
01087       sprintf (auxstr + strlen (auxstr), "%c", trimstr[0]);
01088       strdelete (trimstr, 1, 1);
01089     }
01090   code = (sscanf (auxstr, "%ld", &auxint) == 0);
01091   return auxint;
01092 }
01093 
01094 static int
01095 path_pos (int id, int *a_path)
01096 {
01097   int i = 0;
01098 
01099   for (i = 0; i < max_ringsize; i++)
01100     {
01101       if (*(a_path++) == id)
01102        {
01103          return ++i;
01104        }
01105     }
01106   return 0;
01107 }
01108 
01109 static int
01110 path_length (int *a_path)
01111 {
01112   if ((a_path[max_ringsize - 1] != 0) && (path_pos (0, a_path) == 0))
01113     return max_ringsize;
01114   else
01115     return (path_pos (0, a_path) - 1);
01116 }
01117 
01118 static int
01119 get_bond (int ba1, int ba2)
01120 {
01121   int i;
01122   int b_id = 0;
01123   int FORLIM;
01124 
01125   if (n_bonds <= 0)
01126     return b_id;
01127   FORLIM = n_bonds;
01128   for (i = 1; i <= FORLIM; i++)
01129     {
01130       if (bond[i - 1].a1 == ba1 && bond[i - 1].a2 == ba2 ||
01131          bond[i - 1].a1 == ba2 && bond[i - 1].a2 == ba1)
01132        b_id = i;
01133     }
01134   return b_id;
01135 }
01136 
01137 static void
01138 clear_atom_tags ()
01139 {
01140   int i, FORLIM;
01141 
01142   if (n_atoms > 0)
01143     {
01144       FORLIM = n_atoms;
01145       for (i = 0; i < FORLIM; i++)
01146        atom[i].tag = false;
01147     }
01148 }
01149 
01150 static void
01151 set_atom_tags ()
01152 {
01153   int i, FORLIM;
01154 
01155   if (n_atoms > 0)
01156     {
01157       FORLIM = n_atoms;
01158       for (i = 0; i < FORLIM; i++)
01159        atom[i].tag = true;
01160     }
01161 }
01162 
01163 static void
01164 order_ringpath (int *r_path)
01165 {
01166   /* order should be: array starts with atom of lowest number, followed by neighbor atom with lower number */
01167   int i, pl, a_ref, a_left, a_right, a_tmp;
01168 
01169   pl = path_length (r_path);
01170   if (pl < 3)
01171     return;
01172   a_ref = n_atoms;
01173   /* start with highest possible value for an atom number */
01174   for (i = 0; i < pl; i++)
01175     {
01176       if (r_path[i] < a_ref)       /* find the minimum value ==> reference atom */
01177        a_ref = r_path[i];
01178     }
01179   if (a_ref < 1)            /* just to be sure */
01180     return;
01181   if (path_pos (a_ref, r_path) < pl)
01182     a_right = r_path[path_pos (a_ref, r_path)];
01183   else
01184     a_right = r_path[0];
01185   if (path_pos (a_ref, r_path) > 1)
01186     a_left = r_path[path_pos (a_ref, r_path) - 2];
01187   else
01188     a_left = r_path[pl - 1];
01189   if (a_right == a_left)    /* should never happen */
01190     return;
01191   if (a_right < a_left)
01192     {
01193       /* correct ring numbering direction, only shift of the reference atom to the left end required */
01194       while (path_pos (a_ref, r_path) > 1)
01195        {
01196          a_tmp = r_path[0];
01197          for (i = 1; i < pl; i++)
01198            r_path[i - 1] = r_path[i];
01199          r_path[pl - 1] = a_tmp;
01200        }
01201       return;
01202     }
01203   while (path_pos (a_ref, r_path) < pl)
01204     {
01205       /* step one: create "mirrored" ring path with reference atom at right end */
01206       a_tmp = r_path[pl - 1];
01207       for (i = pl; i >= 2; i--)
01208        r_path[i - 1] = r_path[i - 2];
01209       r_path[0] = a_tmp;
01210     }
01211   for (i = 1; i <= pl / 2; i++)
01212     {                       /* one more mirroring */
01213       a_tmp = r_path[i - 1];
01214       r_path[i - 1] = r_path[pl - i];
01215       r_path[pl - i] = a_tmp;
01216       /* wrong ring numbering direction, two steps required */
01217     }
01218 }
01219 
01220 static void
01221 clear_ndl_atom_tags ()
01222 {
01223   int i;
01224 
01225   if (ndl_n_atoms > 0)
01226     {
01227 
01228       for (i = 0; i < ndl_n_atoms; i++)
01229        ndl_atom[i].tag = false;
01230     }
01231 }
01232 
01233 
01234 static void
01235 set_ndl_atom_tags ()
01236 {
01237   int i;
01238 
01239   if (ndl_n_atoms > 0)
01240     {
01241 
01242       for (i = 0; i < ndl_n_atoms; i++)
01243        ndl_atom[i].tag = true;
01244     }
01245 }
01246 
01247 
01248 static int
01249 count_tagged_ndl_heavyatoms ()
01250 {
01251   int i;
01252   int n = 0;
01253 
01254   if (ndl_n_atoms < 1)
01255     return n;
01256 
01257   for (i = 0; i < ndl_n_atoms; i++)
01258     {
01259       if (ndl_atom[i].heavy && ndl_atom[i].tag)
01260        n++;
01261     }
01262   return n;
01263 }
01264 
01265 
01266 
01267 /*============================= geometry functions ========================== */
01268 
01269 static double
01270 dist3d (p1, p2)
01271      p_3d p1, p2;
01272 {
01273   double res, TEMP, TEMP1, TEMP2;
01274 
01275   TEMP = p1.x - p2.x;
01276   TEMP1 = p1.y - p2.y;
01277   TEMP2 = p1.z - p2.z;
01278   res = sqrt (TEMP * TEMP + TEMP1 * TEMP1 + TEMP2 * TEMP2);
01279   return res;
01280 }
01281 
01282 
01283 /*
01284 function is_cis(p1,p2,p3,p4:p_3d):boolean;  (* new in v0.3d
01285 var                         (* just a simple, distance-based estimation
01286   total_dist  : double;     (* instead of calculating the dihedral angle
01287   direct_dist : double;
01288   res         : boolean;
01289 begin
01290   res := false;
01291   total_dist  := dist3d(p1,p2) + dist3d(p2,p3) + dist3d(p3,p4);
01292   direct_dist := dist3d(p1,p4);
01293   if (direct_dist < 0.78 * total_dist) then res := true;  (* cutoff value of 0.78 was
01294   is_cis := res;                                          (* experimentally determined
01295 end;
01296 */
01297 /* function is_cis was replaced by a new one in v0.3h */
01298 
01299 
01300 static p_3d
01301 subtract_3d (p1, p2)
01302      p_3d p1, p2;
01303 {
01304   p_3d p;
01305 
01306   p.x = p1.x - p2.x;
01307   p.y = p1.y - p2.y;
01308   p.z = p1.z - p2.z;
01309   return p;
01310 }
01311 
01312 
01313 static p_3d
01314 add_3d (p1, p2)
01315      p_3d p1, p2;
01316 {
01317   p_3d p;
01318 
01319   p.x = p1.x + p2.x;
01320   p.y = p1.y + p2.y;
01321   p.z = p1.z + p2.z;
01322   return p;
01323 }
01324 
01325 
01326 static void
01327 vec2origin (p1, p2)
01328      p_3d *p1, *p2;
01329 {
01330   p_3d p;
01331 
01332   p = subtract_3d (*p2, *p1);
01333   *p2 = p;
01334   p1->x = 0.0;
01335   p1->y = 0.0;
01336   p1->z = 0.0;
01337 }
01338 
01339 
01340 static double
01341 scalar_prod (p1, p2, p3)
01342      p_3d p1, p2, p3;
01343 {
01344   p_3d p;
01345   double res;
01346 
01347   p = subtract_3d (p2, p1);
01348   p2 = p;
01349   p = subtract_3d (p3, p1);
01350   p3 = p;
01351   p1.x = 0.0;
01352   p1.y = 0.0;
01353   p1.z = 0.0;
01354   res = p2.x * p3.x + p2.y * p3.y + p2.z * p3.z;
01355   return res;
01356 }
01357 
01358 
01359 static p_3d
01360 cross_prod (p1, p2, p3)
01361      p_3d p1, p2, p3;
01362 {
01363   p_3d p, orig_p1;
01364 
01365   orig_p1 = p1;
01366   p = subtract_3d (p2, p1);
01367   p2 = p;
01368   p = subtract_3d (p3, p1);
01369   p3 = p;
01370   p.x = p2.y * p3.z - p2.z * p3.y;
01371   p.y = p2.z * p3.x - p2.x * p3.z;
01372   p.z = p2.x * p3.y - p2.y * p3.x;
01373   return (add_3d (orig_p1, p));
01374 }
01375 
01376 
01377 static double
01378 angle_3d (p1, p2, p3)
01379      p_3d p1, p2, p3;
01380 {
01381   p_3d lp1, lp2, lp3, p;
01382   double res = 0.0;
01383   double magn_1, magn_2, cos_phi;
01384 
01385   lp1 = p1;
01386   lp2 = p2;
01387   lp3 = p3;
01388   p = subtract_3d (lp2, lp1);
01389   lp2 = p;
01390   p = subtract_3d (lp3, lp1);
01391   lp3 = p;
01392   lp1.x = 0.0;
01393   lp1.y = 0.0;
01394   lp1.z = 0.0;
01395   magn_1 = dist3d (lp1, lp2);
01396   magn_2 = dist3d (lp1, lp3);
01397   if (magn_1 * magn_2 == 0) /* emergency exit */
01398     return M_PI;
01399   cos_phi = scalar_prod (lp1, lp2, lp3) / (magn_1 * magn_2);
01400   if (cos_phi < -1)
01401     cos_phi = -1.0;
01402   if (cos_phi > 1)
01403     cos_phi = 1.0;
01404   res = acos (cos_phi);
01405   return res;
01406 }
01407 
01408 
01409 static double
01410 torsion (p1, p2, p3, p4)
01411      p_3d p1, p2, p3, p4;
01412 {
01413   p_3d lp1, lp2, lp3, lp4, d1, c1, c2;
01414   double res;
01415   p_3d c1xc2, c2xc1;
01416   double dist1, dist2, sign;
01417 
01418   /* copy everything into local variables */
01419   lp1 = p1;
01420   lp2 = p2;
01421   lp3 = p3;
01422   lp4 = p4;
01423   /* get the vector between the two central atoms */
01424   d1 = subtract_3d (p3, p2);
01425   /* shift the first atom parallel to be attached to p3 instead of p2 */
01426   lp1 = add_3d (p1, d1);
01427   /* now get the cross product vectors */
01428   c1 = cross_prod (lp3, lp2, lp1);
01429   c2 = cross_prod (lp3, lp2, lp4);
01430   res = angle_3d (p3, c1, c2);
01431   /*now check if it is clockwise or anticlockwise: */
01432   /*first, make the cross products of the two cross products c1 and c2 (both ways) */
01433   c1xc2 = cross_prod (lp3, c1, c2);
01434   c2xc1 = cross_prod (lp3, c2, c1);
01435   /*next, get the distances from these points to our refernce point lp2 */
01436   dist1 = dist3d (lp2, c1xc2);
01437   dist2 = dist3d (lp2, c2xc1);
01438   if (dist1 <= dist2)
01439     sign = 1.0;
01440   else
01441     sign = -1.0;
01442   return (sign * res);
01443 }
01444 
01445 
01446 static double
01447 ctorsion (p1, p2, p3, p4)
01448      p_3d p1, p2, p3, p4;
01449 {
01450   /* calculates "pseudo-torsion" defined by atoms 3 and 4, being both */
01451   /* attached to atom 2, with respect to axis of atoms 1 and 2 */
01452   p_3d lp1, lp2, lp3, lp4;
01453   /*d1 : p_3d; */
01454   p_3d c1, c2;
01455   double res;
01456   p_3d c1xc2, c2xc1;
01457   double dist1, dist2, sign;
01458 
01459   /* copy everything into local variables */
01460   lp1 = p1;
01461   lp2 = p2;
01462   lp3 = p3;
01463   lp4 = p4;
01464   /* get the cross product vectors */
01465   c1 = cross_prod (lp2, lp1, lp3);
01466   c2 = cross_prod (lp2, lp1, lp4);
01467   res = angle_3d (p2, c1, c2);
01468   /*now check if it is clockwise or anticlockwise: */
01469   /*first, make the cross products of the two cross products c1 and c2 (both ways) */
01470   c1xc2 = cross_prod (lp2, c1, c2);
01471   c2xc1 = cross_prod (lp2, c2, c1);
01472   /*next, get the distances from these points to our refernce point lp1 */
01473   dist1 = dist3d (lp1, c1xc2);
01474   dist2 = dist3d (lp1, c2xc1);
01475   if (dist1 <= dist2)
01476     sign = 1.0;
01477   else
01478     sign = -1.0;
01479   return (sign * res);
01480 }
01481 
01482 
01483 static boolean
01484 is_cis (p1, p2, p3, p4)
01485      p_3d p1, p2, p3, p4;
01486 {
01487   /* new in v0.3h, uses the dihedral angle */
01488   double phi;
01489   boolean res = false;
01490 
01491   phi = torsion (p1, p2, p3, p4);
01492   if (fabs (phi) < M_PI / 2)
01493     res = true;
01494   return res;
01495 }
01496 
01497 
01498 /*====================== end of geometry functions ========================== */
01499 
01500 static void
01501 show_usage ()
01502 {
01503   if (progmode == pmMatchMol)
01504     {
01505       printf
01506        ("matchmol version %s  N. Haider, University of Vienna, 2003-2007\n",
01507         version);
01508       printf ("Usage: matchmol [options] <needle> <haystack>\n");
01509       printf
01510        (" where <needle> and <haystack> are the two molecules to compare\n");
01511       printf
01512        (" (supported formats: MDL *.mol or *.sdf, Alchemy *.mol, Sybyl *.mol2)\n");
01513       printf (" options can be:\n");
01514       printf ("    -v  verbose output\n");
01515       printf ("    -x  exact match\n");
01516       printf
01517        ("    -s  strict comparison of atom and bond types (including ring check)\n");
01518       /* new in v0.2f, v0.3d */
01519       printf ("    -r  force SSR (set of small rings) ring search mode\n");
01520       printf
01521        ("    -m  write matching molecule as MDL molfile to standard output\n");
01522       printf
01523        ("        (default output: record number + \":T\" for hit  or \":F\" for miss\n");
01524       printf ("    -M  accept metal atoms as ring members\n");
01525       printf ("    -g  check geometry of double bonds (E/Z)\n");
01526       printf ("    -G  check geometry of chiral centers (R/S)\n");
01527       printf ("    -a  check charges strict\n"); /* 0.3x */
01528       printf ("    -i  check isotopes strict\n");       /* 0.3x */
01529       printf ("    -d  check radicals strict\n");       /* 0.3x */
01530       printf
01531        ("    -f  fingerprint mode (1 haystack, multiple needles) with boolean output\n");
01532       printf
01533        ("    -F  fingerprint mode (1 haystack, multiple needles) with decimal output\n");
01534       return;
01535     }
01536   printf ("checkmol version %s  N. Haider, University of Vienna, 2003-2007\n",
01537          version);
01538   printf ("Usage: checkmol [options] <filename>\n");
01539   printf (" where options can be:\n");
01540   printf
01541     ("    -l  print a list of fingerprint codes + explanation and exit\n");
01542   printf ("    -v  verbose output\n");
01543   printf ("    -r  force SSR (set of small rings) ring search mode\n");
01544   printf ("    -M  accept metal atoms as ring members\n");
01545   printf ("  and one of the following:\n");
01546   printf
01547     ("    -e  english text (common name of functional group; default)\n");
01548   printf ("    -d  german text (common name of functional group)\n");
01549   printf ("    -c  code (acronym-like code for functional group)\n");
01550   printf
01551     ("    -b  binary (a bitstring representing absence or presence of each group)\n");
01552   printf
01553     ("    -s  the ASCII representation of the above bitstring, i.e. 0s and 1s)\n");
01554   printf
01555     ("    -x  print molecular statistics (number of various atom types, bond types,\n");
01556   printf ("        ring sizes, etc.\n");
01557   printf
01558     ("    -X  same as above, listing all records (even if 0) as comma-separated list\n");
01559   printf ("    -a  count charges in fingerprint\n");    /* 0.3x */
01560   printf
01561     ("    -m  write MDL molfile (with special encoding for aromatic atoms/bonds)\n");
01562   printf (" options can be combined like -vc\n");
01563   printf (" <filename> specifies any file in the formats supported\n");
01564   printf
01565     (" (MDL *.mol, Alchemy *.mol, Sybyl *.mol2), the filename \"-\" (without quotes)\n");
01566   printf (" specifies standard input\n");
01567   /* the "debug" option (-D) remains undocumented */
01568 }
01569 
01570 
01571 static void
01572 list_molstat_codes ()
01573 {
01574   printf ("n_atoms:     number of heavy atoms\n");
01575   printf ("n_bonds:     number of bonds between non-H atoms\n");
01576   printf ("n_rings:     number of rings\n");
01577   printf ("n_QA:        number of query atoms\n");
01578   printf ("n_QB:        number of query bonds\n");
01579   printf ("n_chg:       number of charges\n");
01580   printf ("n_C1:        number of sp-hybridized carbon atoms\n");
01581   printf ("n_C2:        number of sp2-hybridized carbon atoms\n");
01582   printf ("n_C:         total number of carbon atoms\n");
01583   printf
01584     ("n_CHB1p:     number of carbon atoms with at least 1 bond to a hetero atom\n");
01585   printf
01586     ("n_CHB2p:     number of carbon atoms with at least 2 bonds to a hetero atom\n");
01587   printf
01588     ("n_CHB3p:     number of carbon atoms with at least 3 bonds to a hetero atom\n");
01589   printf
01590     ("n_CHB4:      number of carbon atoms with 4 bonds to a hetero atom\n");
01591   printf ("n_O2:        number of sp2-hybridized oxygen atoms\n");
01592   printf ("n_O3:        number of sp3-hybridized oxygen atoms\n");
01593   printf ("n_N1:        number of sp-hybridized nitrogen atoms\n");
01594   printf ("n_N2:        number of sp2-hybridized nitrogen atoms\n");
01595   printf ("n_N3:        number of sp3-hybridized nitrogen atoms\n");
01596   printf ("n_S:         number of sulfur atoms\n");
01597   printf ("n_SeTe:      total number of selenium and tellurium atoms\n");
01598   printf ("n_F:         number of fluorine atoms\n");
01599   printf ("n_Cl:        number of chlorine atoms\n");
01600   printf ("n_Br:        number of bromine atoms\n");
01601   printf ("n_I:         number of iodine atoms\n");
01602   printf ("n_P:         number of phosphorus atoms\n");
01603   printf ("n_B:         number of boron atoms\n");
01604   printf ("n_Met:       total number of metal atoms\n");
01605   printf
01606     ("n_X:         total number of \"other\" atoms (not listed above) and halogens\n");
01607   printf ("n_b1:        number of single bonds\n");
01608   printf ("n_b2:        number of double bonds\n");
01609   printf ("n_b3:        number of triple bonds\n");
01610   printf ("n_bar:       number of aromatic bonds\n");
01611   printf ("n_C1O:       number of C-O single bonds\n");
01612   printf ("n_C2O:       number of C=O double bonds\n");
01613   printf ("n_CN:        number of C/N bonds (any type)\n");
01614   printf ("n_XY:        number of heteroatom/heteroatom bonds (any type)\n");
01615   printf ("n_r3:        number of 3-membered rings\n");
01616   printf ("n_r4:        number of 4-membered rings\n");
01617   printf ("n_r5:        number of 5-membered rings\n");
01618   printf ("n_r6:        number of 6-membered rings\n");
01619   printf ("n_r7:        number of 7-membered rings\n");
01620   printf ("n_r8:        number of 8-membered rings\n");
01621   printf ("n_r9:        number of 9-membered rings\n");
01622   printf ("n_r10:       number of 10-membered rings\n");
01623   printf ("n_r11:       number of 11-membered rings\n");
01624   printf ("n_r12:       number of 12-membered rings\n");
01625   printf ("n_r13p:      number of 13-membered or larger rings\n");
01626   printf ("n_rN:        number of rings containing nitrogen (any number)\n");
01627   printf ("n_rN1:       number of rings containing 1 nitrogen atom\n");
01628   printf ("n_rN2:       number of rings containing 2 nitrogen atoms\n");
01629   printf
01630     ("n_rN3p:      number of rings containing 3 or more nitrogen atoms\n");
01631   printf ("n_rO:        number of rings containing oxygen (any number)\n");
01632   printf ("n_rO1:       number of rings containing 1 oxygen atom\n");
01633   printf ("n_rO2p:      number of rings containing 2 or more oxygen atoms\n");
01634   printf ("n_rS:        number of rings containing sulfur (any number)\n");
01635   printf ("n_rX:        number of heterocycles (any type)\n");
01636   printf ("n_rar:       number of aromatic rings (any type)\n");
01637 /* p2c: checkmol.pas, line 1207:
01638  * Note: Turbo Pascal conditional compilation directive was ignored [218] */
01639   /*$IFDEF extended_molstat */
01640   printf ("n_rbz:       number of benzene rings\n");
01641   printf ("n_br2p:      number of bonds belonging to two or more rings\n");
01642   printf
01643     ("n_psg01:     number of atoms belonging to group 1 of the periodic system\n");
01644   printf
01645     ("n_psg02:     number of atoms belonging to group 2 of the periodic system\n");
01646   printf
01647     ("n_psg13:     number of atoms belonging to group 13 of the periodic system\n");
01648   printf
01649     ("n_psg14:     number of atoms belonging to group 14 of the periodic system\n");
01650   printf
01651     ("n_psg15:     number of atoms belonging to group 15 of the periodic system\n");
01652   printf
01653     ("n_psg16:     number of atoms belonging to group 16 of the periodic system\n");
01654   printf
01655     ("n_psg17:     number of atoms belonging to group 17 of the periodic system\n");
01656   printf
01657     ("n_psg18:     number of atoms belonging to group 18 of the periodic system\n");
01658   printf
01659     ("n_pstm:      number of atoms belonging to the transition metals\n");
01660   printf
01661     ("n_psla:      number of atoms belonging to the lanthanides or actinides\n");
01662   printf ("n_iso:      number of isotopes\n");
01663   printf ("n_rad:      number of radicals\n");
01664   /*$ENDIF */
01665 }
01666 
01667 
01668 /*static void parse_args()
01669 {
01670   int p;
01671   char parstr[256];
01672   char tmpstr[256];
01673   int l;
01674 
01675   *tmpstr = '\0';
01676   opt_none = true;
01677   if (progmode == pmCheckMol) {
01678     for (p = 1; p < P_argc; p++) {
01679       strcpy(parstr, P_argv[p]);
01680       if (!strcmp(parstr, "-l")) {   /* new in v0.3l 
01681        list_molstat_codes();
01682        _Escape(0);
01683       }
01684       if (p < P_argc - 1) {
01685        if (strpos2(parstr, "-", 1) == 1 && p < P_argc - 1) {
01686          strcpy(tmpstr, P_argv[p]);
01687          left_trim(tmpstr);
01688          l = 0;
01689          if (strpos2(tmpstr, "v", 1) > 0)
01690            l++;
01691          if (strpos2(tmpstr, "D", 1) > 0)
01692            l++;
01693          if (strpos2(tmpstr, "r", 1) > 0)
01694            l++;
01695          if (strpos2(tmpstr, "M", 1) > 0)   /* new in v0.3 
01696            l++;
01697          if (strlen(tmpstr) > l + 2) {
01698            show_usage();
01699            _Escape(1);
01700          }
01701          opt_none = false;
01702          if (strpos2(tmpstr, "M", 1) > 0)
01703            opt_metalrings = true;
01704          if (strpos2(tmpstr, "v", 1) > 0)
01705            opt_verbose = true;
01706 /* p2c: checkmol.pas, line 1261:
01707  * Note: Turbo Pascal conditional compilation directive was ignored [218] 
01708          /*$IFDEF debug
01709          if (strpos2(tmpstr, "D", 1) > 0)
01710            opt_debug = true;
01711          /*$ENDIF
01712          if (strpos2(tmpstr, "e", 1) > 0)
01713            opt_text = true;
01714          else {
01715            if (strpos2(tmpstr, "d", 1) > 0)
01716              opt_text_de = true;
01717            else {
01718              if (strpos2(tmpstr, "c", 1) > 0)
01719               opt_code = true;
01720              else {
01721               if (strpos2(tmpstr, "b", 1) > 0)
01722                 opt_bin = true;
01723               else {
01724                 if (strpos2(tmpstr, "s", 1) > 0)
01725                   opt_bitstring = true;
01726               }
01727              }
01728            }
01729            if (strpos2(tmpstr, "x", 1) > 0)
01730              opt_molstat = true;
01731            if (strpos2(tmpstr, "r", 1) > 0)
01732              opt_rs = rs_ssr;
01733            if (strpos2(tmpstr, "X", 1) > 0) {
01734              opt_molstat = true;
01735              opt_molstat_X = true;
01736            }
01737            if (strpos2(tmpstr, "m", 1) > 0) {
01738              opt_text = false;
01739              opt_text_de = false;
01740              opt_bin = false;
01741              opt_bitstring = false;
01742              opt_code = false;
01743              opt_molstat = false;
01744              opt_xmdlout = true;
01745            }
01746          }
01747          strcpy(molfilename, tmpstr);
01748        }
01749       } else {
01750        if (strpos2(parstr, "-", 1) == 1) {
01751          if (strlen(parstr) > 1) {
01752            show_usage();
01753            _Escape(1);
01754          }
01755          opt_stdin = true;
01756        } else {
01757          opt_stdin = false;
01758          strcpy(molfilename, parstr);
01759        }
01760       }
01761     }
01762     if (opt_text == false && opt_text_de == false && opt_code == false &&
01763        opt_bin == false && opt_bitstring == false && opt_molstat == false &&
01764        opt_molstat_X == false && opt_xmdlout == false)
01765       opt_none = true;
01766   }
01767   if (progmode == pmMatchMol) {
01768     *ndl_molfilename = '\0';
01769     *molfilename = '\0';
01770     for (p = 1; p < P_argc; p++) {
01771       strcpy(parstr, P_argv[p]);
01772       if (p == 1) {
01773        if (strpos2(parstr, "-", 1) == 1) {
01774          if (strpos2(parstr, "v", 1) > 1)
01775            opt_verbose = true;
01776 /* p2c: checkmol.pas, line 1329:
01777  * Note: Turbo Pascal conditional compilation directive was ignored [218] */
01778          /*$IFDEF debug
01779             if (strpos2(parstr, "D", 1) > 1)
01780             opt_debug = true;
01781             /*$ENDIF
01782             if (strpos2(parstr, "x", 1) > 1)
01783             opt_exact = true;
01784             if (strpos2(parstr, "s", 1) > 1)   /* new in v0.2f 
01785             opt_strict = true;
01786             if (strpos2(parstr, "m", 1) > 1)
01787             opt_molout = true;
01788             if (strpos2(parstr, "r", 1) > 1)
01789             opt_rs = rs_ssr;
01790             if (strpos2(parstr, "M", 1) > 0)   /* new in v0.3 
01791             opt_metalrings = true;
01792             if (strpos2(parstr, "g", 1) > 0)   /* new in v0.3d 
01793             opt_geom = true;
01794             if (strpos2(parstr, "G", 1) > 0)   /* new in v0.3f 
01795             opt_chiral = true;
01796             if (strpos2(parstr, "f", 1) > 0) {   /* new in v0.3m 
01797             opt_fp = true;
01798             fpformat = fpf_boolean;
01799             }
01800             if (strpos2(parstr, "F", 1) > 0) {   /* new in v0.3m 
01801             opt_fp = true;
01802             fpformat = fpf_decimal;
01803             }
01804             if (strpos2(parstr, "h", 1) > 1) {
01805             show_usage();
01806             _Escape(0);
01807             }
01808             } else
01809             strcpy(ndl_molfilename, parstr);
01810             }
01811             if (p == P_argc - 2) {
01812             if (strpos2(parstr, "-", 1) != 1)
01813             strcpy(ndl_molfilename, parstr);
01814             }
01815             if (p == P_argc - 1) {
01816             if (strcmp(parstr, "-"))
01817             strcpy(molfilename, parstr);
01818             else
01819             opt_stdin = true;
01820             }
01821             }
01822             if (opt_geom)   /* v0.3d 
01823             ez_search = true;
01824             if (opt_chiral)   /* v0.3f 
01825             rs_search = true;
01826             if (opt_chiral && opt_strict && (opt_exact || opt_fp))
01827             /* new in v0.3j, v0.3m 
01828             rs_strict = true;
01829             if (opt_fp) {   /* v0.3m 
01830             opt_molout = false;
01831             opt_exact = false;
01832             }
01833             }  /* progmode = pmMatchMol 
01834             ringsearch_mode = opt_rs;   /* v0.3i 
01835             }
01836           */
01837 
01838 static void
01839 parse_args (int argc, char *argv[])
01840 {
01841   short p;
01842   char parstr[256];
01843   char tmpstr[256];
01844   short l;
01845 
01846   *tmpstr = '\0';
01847   opt_none = true;
01848   *molfilename = '\0';
01849   *ndl_molfilename = '\0';
01850   if (progmode == pmCheckMol)
01851     {
01852       for (p = 1; p <= argc - 1; p++)
01853        {
01854          strcpy (parstr, argv[p]);
01855          if (!strcmp (parstr, "-l"))
01856            {                /* new in v0.3l */
01857              list_molstat_codes ();
01858              exit (0);
01859            }
01860          if (p < argc - 1)
01861            {
01862              if (strpos2 (parstr, "-", 1) == 1 && p < argc - 1)
01863               {
01864                 strcpy (tmpstr, argv[p]);
01865                 left_trim (tmpstr);
01866                 l = 0;
01867                 if (strpos2 (tmpstr, "v", 1) > 0)
01868                   l++;
01869                 if (strpos2 (tmpstr, "D", 1) > 0)
01870                   l++;
01871                 if (strpos2 (tmpstr, "r", 1) > 0)
01872                   l++;
01873                 /*if (strpos2 (tmpstr, "a", 1) > 0)   /* 0.3x 
01874                    l++; */
01875                 if (strpos2 (tmpstr, "M", 1) > 0)       /* new in v0.3 */
01876                   l++;
01877                 if (strlen (tmpstr) > l + 2)
01878                   {
01879                     show_usage ();
01880                     exit (1);
01881                   }
01882                 opt_none = false;
01883                 if (strpos2 (tmpstr, "M", 1) > 0)
01884                   opt_metalrings = true;
01885                 if (strpos2 (tmpstr, "v", 1) > 0)
01886                   opt_verbose = true;
01887                 /*{$IFDEF debug
01888                    if pos('D',tmpstr)>0 then opt_debug       := true;
01889                    {$ENDIF */
01890                 if (strpos2 (tmpstr, "e", 1) > 0)
01891                   opt_text = true;
01892                 else
01893                   {
01894                     if (strpos2 (tmpstr, "d", 1) > 0)
01895                      opt_text_de = true;
01896                     else
01897                      {
01898                        if (strpos2 (tmpstr, "c", 1) > 0)
01899                          opt_code = true;
01900                        else
01901                          {
01902                            if (strpos2 (tmpstr, "b", 1) > 0)
01903                             opt_bin = true;
01904                            else
01905                             {
01906                               if (strpos2 (tmpstr, "s", 1) > 0)
01907                                 opt_bitstring = true;
01908                             }
01909                          }
01910                      }
01911                     if (strpos2 (tmpstr, "x", 1) > 0)
01912                      opt_molstat = true;
01913                     if (strpos2 (tmpstr, "r", 1) > 0)
01914                      opt_rs = rs_ssr;
01915                     /* if (strpos2 (tmpstr, "a", 1) > 0)
01916                        opt_chg = true; /* 0.3x  */
01917                     if (strpos2 (tmpstr, "X", 1) > 0)
01918                      {
01919                        opt_molstat = true;
01920                        opt_molstat_X = true;
01921                      }
01922                     if (strpos2 (tmpstr, "m", 1) > 0)
01923                      {
01924                        opt_text = false;
01925                        opt_text_de = false;
01926                        opt_bin = false;
01927                        opt_bitstring = false;
01928                        opt_code = false;
01929                        opt_molstat = false;
01930                        opt_xmdlout = true;
01931                      }
01932                   }
01933                 strcpy (molfilename, tmpstr);
01934               }
01935            }
01936          else
01937            {
01938              if (strpos2 (parstr, "-", 1) == 1)
01939               {
01940                 if (strlen (parstr) > 1)
01941                   {
01942                     show_usage ();
01943                     exit (1);
01944                   }
01945                 opt_stdin = true;
01946               }
01947              else
01948               {
01949                 opt_stdin = false;
01950                 strcpy (molfilename, parstr);
01951               }
01952            }
01953        }
01954       if (opt_text == false && opt_text_de == false && opt_code == false &&
01955          opt_bin == false && opt_bitstring == false && opt_molstat == false
01956          && opt_molstat_X == false && opt_xmdlout == false
01957          && opt_chg == false)
01958        opt_none = true;     /* 0.3x */
01959     }
01960   if (progmode == pmMatchMol)
01961     {
01962 
01963       for (p = 1; p <= argc - 1; p++)
01964        {
01965          strcpy (parstr, argv[p]);
01966          if (p == 1)
01967            {
01968              if (strpos2 (parstr, "-", 1) == 1)
01969               {
01970                 if (strpos2 (parstr, "v", 1) > 1)
01971                   opt_verbose = true;
01972                 /*{$IFDEF debug
01973                    if pos('D',parstr)>1 then opt_debug       := true;
01974                    {$ENDIF */
01975                 if (strpos2 (parstr, "x", 1) > 1)
01976                   opt_exact = true;
01977                 if (strpos2 (parstr, "s", 1) > 1)       /* new in v0.2f */
01978                   opt_strict = true;
01979                 if (strpos2 (parstr, "m", 1) > 1)
01980                   opt_molout = true;
01981                 if (strpos2 (parstr, "r", 1) > 1)
01982                   opt_rs = rs_ssr;
01983                 if (strpos2 (parstr, "a", 1) > 0)
01984                   opt_chg = true;  /* 0.3x */
01985                 if (strpos2 (parstr, "i", 1) > 0)
01986                   opt_iso = true;  /* 0.3x */
01987                 if (strpos2 (parstr, "d", 1) > 0)
01988                   opt_rad = true;  /* 0.3x */
01989                 if (strpos2 (parstr, "M", 1) > 0)       /* new in v0.3 */
01990                   opt_metalrings = true;
01991                 if (strpos2 (parstr, "g", 1) > 0)       /* new in v0.3d */
01992                   opt_geom = true;
01993                 if (strpos2 (parstr, "G", 1) > 0)       /* new in v0.3f */
01994                   opt_chiral = true;
01995                 if (strpos2 (parstr, "f", 1) > 0)
01996                   {         /* new in v0.3m */
01997                     opt_fp = true;
01998                     fpformat = fpf_boolean;
01999                   }
02000                 if (strpos2 (parstr, "F", 1) > 0)
02001                   {         /* new in v0.3m */
02002                     opt_fp = true;
02003                     fpformat = fpf_decimal;
02004                   }
02005                 if (strpos2 (parstr, "h", 1) > 1)
02006                   {
02007                     show_usage ();
02008                     exit (0);
02009                   }
02010               }
02011              else
02012               strcpy (ndl_molfilename, parstr);
02013            }
02014          if (p == argc - 2)
02015            {
02016              if (strpos2 (parstr, "-", 1) != 1)
02017               strcpy (ndl_molfilename, parstr);
02018            }
02019          if (p == argc - 1)
02020            {
02021              if (strcmp (parstr, "-"))
02022               strcpy (molfilename, parstr);
02023              else
02024               opt_stdin = true;
02025            }
02026        }
02027       if (opt_geom)         /* v0.3d */
02028        ez_search = true;
02029       if (opt_chiral)              /* v0.3f */
02030        rs_search = true;
02031       if (opt_chiral && opt_strict && (opt_exact || opt_fp))
02032        /* new in v0.3j, v0.3m  */
02033        rs_strict = true;
02034       if (opt_fp)
02035        {                    /* v0.3m */
02036          opt_molout = false;
02037          opt_exact = false;
02038        }
02039     }                       /* progmode = pmMatchMol */
02040   ringsearch_mode = opt_rs; /* v0.3i */
02041 }
02042 
02043 /*============== input-related functions & procedures ===================== */
02044 
02045 static char *
02046 get_filetype (Result, f)
02047      char *Result;
02048      char *f;
02049 {
02050   char rline[256];
02051   char auxstr[256];
02052   int i;
02053   boolean mdl1 = false;
02054   int ri;
02055   int sepcount = 0;
02056   char STR1[256], STR6[256], STR7[256];
02057 
02058   strcpy (auxstr, "unknown");
02059   i = li;
02060   ri = li - 1;
02061   while (ri < molbufindex && sepcount < 1)
02062     {
02063       ri++;
02064       strcpy (rline, molbuf[ri - 1]);
02065       if (strpos2 (rline, "$$$$", 1) > 0)
02066        sepcount++;
02067       if ((i == li) && (strcmp (strsub (STR1, rline, 7, 5), "ATOMS") == 0) &&
02068          (strcmp (strsub (STR6, rline, 20, 5), "BONDS") == 0) &&
02069          (strcmp (strsub (STR7, rline, 33, 7), "CHARGES") == 0))
02070        strcpy (auxstr, "alchemy");
02071       if ((i == li + 3) && (strcmp (strsub (STR1, rline, 35, 5), "V2000") ==
02072                          0))
02073        /* and (copy(rline,31,3)='999') */
02074        mdl1 = true;
02075       if ((i == li + 1) && (strcmp (strsub (STR1, rline, 3, 6), "-ISIS-") ==
02076                          0))
02077        mdl1 = true;
02078       if ((i == li + 1) && (strcmp (strsub (STR1, rline, 3, 8), "WLViewer") ==
02079                          0))
02080        mdl1 = true;
02081       if ((i == li + 1) && (strcmp (strsub (STR1, rline, 3, 8), "CheckMol") ==
02082                          0))
02083        mdl1 = true;
02084       if ((i == li + 1) && (strcmp (strsub (STR1, rline, 3, 8), "CATALYST") ==
02085                          0))
02086        {
02087          mdl1 = true;
02088          strcpy (auxstr, "mdl");
02089        }
02090       if (strpos2 (rline, "M  END", 1) == 1 || mdl1)
02091        strcpy (auxstr, "mdl");
02092       if (strpos2 (rline, "@<TRIPOS>MOLECULE", 1) > 0)
02093        strcpy (auxstr, "sybyl");
02094       i++;
02095     }
02096   /* new in v0.2j: try to identify non-conformant SD-files */
02097   if (!strcmp (auxstr, "unknown") && sepcount > 0)
02098     strcpy (auxstr, "mdl");
02099   return strcpy (Result, auxstr);
02100 }
02101 
02102 
02103 static void
02104 zap_molecule ()
02105 {
02106   /* try */
02107   if (atom != NULL)
02108     {
02109       free (atom);
02110       atom = NULL;          /* added in v0.3j */
02111     }
02112   if (bond != NULL)
02113     {
02114       free (bond);
02115       bond = NULL;          /* added in v0.3j */
02116     }
02117   if (ring != NULL)
02118     {
02119       free (ring);
02120       ring = NULL;          /* added in v0.3j */
02121     }
02122   if (ringprop != NULL)
02123     {
02124       free (ringprop);
02125       ringprop = NULL;             /* added in v0.3j */
02126     }
02127   /* except
02128      on e:Einvalidpointer do begin end;
02129      end; */
02130   n_atoms = 0;
02131   n_bonds = 0;
02132   n_rings = 0;
02133 }
02134 
02135 
02136 static void
02137 zap_needle ()
02138 {
02139   /* try */
02140   if (ndl_atom != NULL)
02141     {
02142       free (ndl_atom);
02143       ndl_atom = NULL;             /* added in v0.3j */
02144     }
02145   if (ndl_bond != NULL)
02146     {
02147       free (ndl_bond);
02148       ndl_bond = NULL;             /* added in v0.3j */
02149     }
02150   if (ndl_ring != NULL)
02151     {
02152       free (ndl_ring);
02153       ndl_ring = NULL;             /* added in v0.3j */
02154     }
02155   if (ndl_ringprop != NULL)
02156     {
02157       free (ndl_ringprop);  /* fixed in v0.3g */
02158       ndl_ringprop = NULL;  /* added in v0.3j */
02159     }
02160   /* except
02161      on e:Einvalidpointer do begin end;
02162      end; */
02163   ndl_n_atoms = 0;
02164   ndl_n_bonds = 0;
02165   ndl_n_rings = 0;
02166 }
02167 
02168 
02169 static void
02170 zap_tmp ()
02171 {
02172   /* try */
02173   if (tmp_atom != NULL)
02174     {
02175       free (tmp_atom);
02176       tmp_atom = NULL;             /* added in v0.3j */
02177     }
02178   if (tmp_bond != NULL)
02179     {
02180       free (tmp_bond);
02181       tmp_bond = NULL;             /* added in v0.3j */
02182     }
02183   if (tmp_ring != NULL)
02184     {
02185       free (tmp_ring);
02186       tmp_ring = NULL;             /* added in v0.3j */
02187     }
02188   if (tmp_ringprop != NULL)
02189     {
02190       free (tmp_ringprop);  /* fixed in v0.3g */
02191       tmp_ringprop = NULL;  /* added in v0.3j */
02192     }
02193   /* except
02194      on e:Einvalidpointer do begin end;
02195      end; */
02196   tmp_n_atoms = 0;
02197   tmp_n_bonds = 0;
02198   tmp_n_rings = 0;
02199 }
02200 
02201 
02202 static boolean
02203 is_heavyatom (id)
02204      int id;
02205 {
02206   str2 el;
02207 
02208   strcpy (el, atom[id - 1].element);
02209   
02210   if (!strcmp (el, "DU") || !strcmp (el, "LP"))
02211     return false;
02212   /*if (progmode == pmCheckMol && !strcmp (el, "H ")
02213      && atom[id - 1].nucleon_number < 2)
02214      return false;              /* 0.3x  */
02215   if (!strcmp (el, "H "))   /* 0.3 p */
02216     {
02217       if (progmode == pmMatchMol && !opt_iso)
02218        {
02219          return false;
02220        }
02221       else
02222        {
02223          if (atom[id - 1].nucleon_number < 2)
02224            return false;
02225        }
02226     }
02227   return true;
02228 }
02229 
02230 
02231 static boolean
02232 ndl_alkene_C (ba)
02233      int ba;
02234 {
02235   /* new in v0.3f */
02236   boolean res = false;
02237   int i, ba2, FORLIM;
02238 
02239   if (ndl_n_atoms <= 0 || ndl_n_bonds <= 0)
02240     return false;
02241   FORLIM = ndl_n_bonds;
02242   for (i = 0; i < FORLIM; i++)
02243     {
02244       if (ndl_bond[i].a1 == ba || ndl_bond[i].a2 == ba)
02245        {
02246          if (ndl_bond[i].a1 == ba)
02247            ba2 = ndl_bond[i].a2;
02248          else
02249            ba2 = ndl_bond[i].a1;
02250          if (!strcmp (ndl_atom[ba - 1].atype, "C2 ") &&
02251              !strcmp (ndl_atom[ba2 - 1].atype, "C2 ")
02252              && ndl_bond[i].btype == 'D' && ndl_bond[i].arom == false)
02253            res = true;
02254        }
02255     }
02256   return res;
02257 }
02258 
02259 
02260 static boolean
02261 is_metal (id)
02262      int id;
02263 {
02264   boolean r = false;
02265   str2 el;
02266 
02267   strcpy (el, atom[id - 1].element);
02268   if (!strcmp (el, "LI") || !strcmp (el, "NA") || !strcmp (el, "K ") ||
02269       !strcmp (el, "RB") || !strcmp (el, "CS") || !strcmp (el, "BE") ||
02270       !strcmp (el, "MG") || !strcmp (el, "CA") || !strcmp (el, "SR") ||
02271       !strcmp (el, "BA") || !strcmp (el, "TI") || !strcmp (el, "ZR") ||
02272       !strcmp (el, "CR") || !strcmp (el, "MO") || !strcmp (el, "MN") ||
02273       !strcmp (el, "FE") || !strcmp (el, "CO") || !strcmp (el, "NI") ||
02274       !strcmp (el, "PD") || !strcmp (el, "PT") || !strcmp (el, "SN") ||
02275       !strcmp (el, "CU") || !strcmp (el, "AG") || !strcmp (el, "AU") ||
02276       !strcmp (el, "ZN") || !strcmp (el, "CD") || !strcmp (el, "HG") ||
02277       !strcmp (el, "AL") || !strcmp (el, "SN") || !strcmp (el, "PB") ||
02278       !strcmp (el, "SB") || !strcmp (el, "BI"))
02279 /* p2c: checkmol.pas, line 1577: 
02280  * Note: Line breaker spent 0.0 seconds, 5000 tries on line 1686 [251] */
02281     /* etc. etc. */
02282     r = true;
02283   return r;
02284 }
02285 
02286 
02287 static int
02288 get_nvalences (a_el)
02289      char *a_el;
02290 {
02291   /* changed name and position in v0.3m */
02292   /* preliminary version; should be extended to element/atomtype */
02293   int res = 1;
02294 
02295   if (!strcmp (a_el, "H "))
02296     res = 1;
02297   /*if (!strcmp (a_el, "D "))   /* v0.3n 
02298      res = 1; */
02299   if (!strcmp (a_el, "C "))
02300     res = 4;
02301   if (!strcmp (a_el, "N "))
02302     res = 3;
02303   if (!strcmp (a_el, "O "))
02304     res = 2;
02305   if (!strcmp (a_el, "S "))
02306     res = 2;
02307   if (!strcmp (a_el, "SE"))
02308     res = 2;
02309   if (!strcmp (a_el, "TE"))
02310     res = 2;
02311   if (!strcmp (a_el, "P "))
02312     res = 3;
02313   if (!strcmp (a_el, "F "))
02314     res = 1;
02315   if (!strcmp (a_el, "CL"))
02316     res = 1;
02317   if (!strcmp (a_el, "BR"))
02318     res = 1;
02319   if (!strcmp (a_el, "I "))
02320     res = 1;
02321   if (!strcmp (a_el, "AT"))
02322     res = 1;
02323   if (!strcmp (a_el, "B "))
02324     res = 3;
02325   if (!strcmp (a_el, "LI"))
02326     res = 1;
02327   if (!strcmp (a_el, "NA"))
02328     res = 1;
02329   if (!strcmp (a_el, "K "))
02330     res = 1;
02331   if (!strcmp (a_el, "CA"))
02332     res = 2;
02333   if (!strcmp (a_el, "SR"))
02334     res = 2;
02335   if (!strcmp (a_el, "MG"))
02336     res = 2;
02337   if (!strcmp (a_el, "FE"))
02338     res = 3;
02339   if (!strcmp (a_el, "MN"))
02340     res = 2;
02341   if (!strcmp (a_el, "HG"))
02342     res = 2;
02343   if (!strcmp (a_el, "SI"))
02344     res = 4;
02345   if (!strcmp (a_el, "SN"))
02346     res = 4;
02347   if (!strcmp (a_el, "ZN"))
02348     res = 2;
02349   if (!strcmp (a_el, "CU"))
02350     res = 2;
02351   if (!strcmp (a_el, "A "))
02352     res = 4;
02353   if (!strcmp (a_el, "Q "))
02354     res = 4;
02355   return res;
02356 }
02357 
02358 
02359 static char *
02360 convert_type (Result, oldtype)
02361      char *Result;
02362      char *oldtype;
02363 {
02364   int i;
02365   str3 newtype;
02366 
02367   sprintf (newtype, "%.3s", oldtype);
02368   for (i = 0; i <= 2; i++)
02369     newtype[i] = toupper (newtype[i]);
02370   if (newtype[0] == '~')
02371     strcpy (newtype, "VAL");
02372   if (newtype[0] == '*')
02373     strcpy (newtype, "STR");
02374   return strcpy (Result, newtype);
02375 }
02376 
02377 
02378 static char *
02379 convert_sybtype (Result, oldtype)
02380      char *Result;
02381      char *oldtype;
02382 {
02383   str3 newtype;
02384 
02385   /*  NewType := Copy(OldType,1,3); */
02386   /*  For i := 1 To 3 Do NewType[i] := UpCase(NewType[i]); */
02387   /*  If NewType[1] = '~' Then NewType := 'VAL'; */
02388   /*  If NewType[1] = '*' Then NewType := 'STR'; */
02389   strcpy (newtype, "DU ");
02390   if (!strcmp (oldtype, "H    "))
02391     strcpy (newtype, "H  ");
02392   if (!strcmp (oldtype, "C.ar "))
02393     strcpy (newtype, "CAR");
02394   if (!strcmp (oldtype, "C.2  "))
02395     strcpy (newtype, "C2 ");
02396   if (!strcmp (oldtype, "C.3  "))
02397     strcpy (newtype, "C3 ");
02398   if (!strcmp (oldtype, "C.1  "))
02399     strcpy (newtype, "C1 ");
02400   if (!strcmp (oldtype, "O.2  "))
02401     strcpy (newtype, "O2 ");
02402   if (!strcmp (oldtype, "O.3  "))
02403     strcpy (newtype, "O3 ");
02404   if (!strcmp (oldtype, "O.co2"))
02405     strcpy (newtype, "O2 ");
02406   if (!strcmp (oldtype, "O.spc"))
02407     strcpy (newtype, "O3 ");
02408   if (!strcmp (oldtype, "O.t3p"))
02409     strcpy (newtype, "O3 ");
02410   if (!strcmp (oldtype, "N.1  "))
02411     strcpy (newtype, "N1 ");
02412   if (!strcmp (oldtype, "N.2  "))
02413     strcpy (newtype, "N2 ");
02414   if (!strcmp (oldtype, "N.3  "))
02415     strcpy (newtype, "N3 ");
02416   if (!strcmp (oldtype, "N.pl3"))
02417     strcpy (newtype, "NPL");
02418   if (!strcmp (oldtype, "N.4  "))
02419     strcpy (newtype, "N3+");
02420   if (!strcmp (oldtype, "N.am "))
02421     strcpy (newtype, "NAM");
02422   if (!strcmp (oldtype, "N.ar "))
02423     strcpy (newtype, "NAR");
02424   if (!strcmp (oldtype, "F    "))
02425     strcpy (newtype, "F  ");
02426   if (!strcmp (oldtype, "Cl   "))
02427     strcpy (newtype, "CL ");
02428   if (!strcmp (oldtype, "Br   "))
02429     strcpy (newtype, "BR ");
02430   if (!strcmp (oldtype, "I    "))
02431     strcpy (newtype, "I  ");
02432   if (!strcmp (oldtype, "Al   "))
02433     strcpy (newtype, "AL ");
02434   if (!strcmp (oldtype, "ANY  "))
02435     strcpy (newtype, "A  ");
02436   if (!strcmp (oldtype, "Ca   "))
02437     strcpy (newtype, "CA ");
02438   if (!strcmp (oldtype, "Du   "))
02439     strcpy (newtype, "DU ");
02440   if (!strcmp (oldtype, "Du.C "))
02441     strcpy (newtype, "DU ");
02442   if (!strcmp (oldtype, "H.spc"))
02443     strcpy (newtype, "H  ");
02444   if (!strcmp (oldtype, "H.t3p"))
02445     strcpy (newtype, "H  ");
02446   if (!strcmp (oldtype, "HAL  "))
02447     strcpy (newtype, "Cl ");
02448   if (!strcmp (oldtype, "HET  "))
02449     strcpy (newtype, "Q  ");
02450   if (!strcmp (oldtype, "HEV  "))
02451     strcpy (newtype, "DU ");
02452   if (!strcmp (oldtype, "K    "))
02453     strcpy (newtype, "K  ");
02454   if (!strcmp (oldtype, "Li   "))
02455     strcpy (newtype, "LI ");
02456   if (!strcmp (oldtype, "LP   "))
02457     strcpy (newtype, "LP ");
02458   if (!strcmp (oldtype, "Na   "))
02459     strcpy (newtype, "NA ");
02460   if (!strcmp (oldtype, "P.3  "))
02461     strcpy (newtype, "P3 ");
02462   if (!strcmp (oldtype, "S.2  "))
02463     strcpy (newtype, "S2 ");
02464   if (!strcmp (oldtype, "S.3  "))
02465     strcpy (newtype, "S3 ");
02466   if (!strcmp (oldtype, "S.o  "))
02467     strcpy (newtype, "SO ");
02468   if (!strcmp (oldtype, "S.o2 "))
02469     strcpy (newtype, "SO2");
02470   if (!strcmp (oldtype, "Si   "))
02471     strcpy (newtype, "SI ");
02472   if (!strcmp (oldtype, "P.4  "))
02473     strcpy (newtype, "P4 ");
02474   return strcpy (Result, newtype);
02475 }
02476 
02477 
02478 static char *
02479 convert_MDLtype (Result, oldtype)
02480      char *Result, *oldtype;
02481 {
02482   str3 newtype;
02483 
02484   /*  NewType := Copy(OldType,1,3); */
02485   /*  For i := 1 To 3 Do NewType[i] := UpCase(NewType[i]); */
02486   /*  If NewType[1] = '~' Then NewType := 'VAL'; */
02487   /*  If NewType[1] = '*' Then NewType := 'STR'; */
02488   strcpy (newtype, "DU ");
02489   if (!strcmp (oldtype, "H  "))
02490     strcpy (newtype, "H  ");
02491   if (!strcmp (oldtype, "C  "))
02492     strcpy (newtype, "C3 ");
02493   if (!strcmp (oldtype, "O  "))
02494     strcpy (newtype, "O2 ");
02495   if (!strcmp (oldtype, "N  "))
02496     strcpy (newtype, "N3 ");
02497   if (!strcmp (oldtype, "F  "))
02498     strcpy (newtype, "F  ");
02499   if (!strcmp (oldtype, "Cl "))
02500     strcpy (newtype, "CL ");
02501   if (!strcmp (oldtype, "Br "))
02502     strcpy (newtype, "BR ");
02503   if (!strcmp (oldtype, "I  "))
02504     strcpy (newtype, "I  ");
02505   if (!strcmp (oldtype, "Al "))
02506     strcpy (newtype, "AL ");
02507   if (!strcmp (oldtype, "ANY"))
02508     strcpy (newtype, "A  ");
02509   if (!strcmp (oldtype, "Ca "))
02510     strcpy (newtype, "CA ");
02511   if (!strcmp (oldtype, "Du "))
02512     strcpy (newtype, "DU ");
02513   if (!strcmp (oldtype, "K  "))
02514     strcpy (newtype, "K  ");
02515   if (!strcmp (oldtype, "Li "))
02516     strcpy (newtype, "LI ");
02517   if (!strcmp (oldtype, "LP "))
02518     strcpy (newtype, "LP ");
02519   if (!strcmp (oldtype, "Na "))
02520     strcpy (newtype, "NA ");
02521   if (!strcmp (oldtype, "P  "))
02522     strcpy (newtype, "P3 ");
02523   if (!strcmp (oldtype, "S  "))
02524     strcpy (newtype, "S3 ");
02525   if (!strcmp (oldtype, "Si "))
02526     strcpy (newtype, "SI ");
02527   if (!strcmp (oldtype, "P  "))
02528     strcpy (newtype, "P4 ");
02529   if (!strcmp (oldtype, "A  "))
02530     strcpy (newtype, "A  ");
02531   if (!strcmp (oldtype, "Q  "))
02532     strcpy (newtype, "Q  ");
02533   return strcpy (Result, newtype);
02534 }
02535 
02536 
02537 static char *
02538 get_element (Result, oldtype)
02539      char *Result;
02540      char *oldtype;
02541 {
02542   char elemstr[256];
02543 
02544   if (!strcmp (oldtype, "H   "))
02545     strcpy (elemstr, "H ");
02546   /* if (!strcmp (oldtype, "D   "))      /* v0.3n 
02547      strcpy (elemstr, "D "); */
02548   if (!strcmp (oldtype, "CAR "))
02549     strcpy (elemstr, "C ");
02550   if (!strcmp (oldtype, "C2  "))
02551     strcpy (elemstr, "C ");
02552   if (!strcmp (oldtype, "C3  "))
02553     strcpy (elemstr, "C ");
02554   if (!strcmp (oldtype, "C1  "))
02555     strcpy (elemstr, "C ");
02556   if (!strcmp (oldtype, "O2  "))
02557     strcpy (elemstr, "O ");
02558   if (!strcmp (oldtype, "O3  "))
02559     strcpy (elemstr, "O ");
02560   if (!strcmp (oldtype, "O2  "))
02561     strcpy (elemstr, "O ");
02562   if (!strcmp (oldtype, "O3  "))
02563     strcpy (elemstr, "O ");
02564   if (!strcmp (oldtype, "O3  "))
02565     strcpy (elemstr, "O ");
02566   if (!strcmp (oldtype, "N1  "))
02567     strcpy (elemstr, "N ");
02568   if (!strcmp (oldtype, "N2  "))
02569     strcpy (elemstr, "N ");
02570   if (!strcmp (oldtype, "N3  "))
02571     strcpy (elemstr, "N ");
02572   if (!strcmp (oldtype, "NPL "))
02573     strcpy (elemstr, "N ");
02574   if (!strcmp (oldtype, "N3+ "))
02575     strcpy (elemstr, "N ");
02576   if (!strcmp (oldtype, "NAM "))
02577     strcpy (elemstr, "N ");
02578   if (!strcmp (oldtype, "NAR "))
02579     strcpy (elemstr, "N ");
02580   if (!strcmp (oldtype, "F   "))
02581     strcpy (elemstr, "F ");
02582   if (!strcmp (oldtype, "CL  "))
02583     strcpy (elemstr, "CL");
02584   if (!strcmp (oldtype, "BR  "))
02585     strcpy (elemstr, "BR");
02586   if (!strcmp (oldtype, "I   "))
02587     strcpy (elemstr, "I ");
02588   if (!strcmp (oldtype, "AT  "))
02589     strcpy (elemstr, "AT");
02590   if (!strcmp (oldtype, "AL  "))
02591     strcpy (elemstr, "AL");
02592   if (!strcmp (oldtype, "DU  "))
02593     strcpy (elemstr, "DU");
02594   if (!strcmp (oldtype, "CA  "))
02595     strcpy (elemstr, "CA");
02596   if (!strcmp (oldtype, "DU  "))
02597     strcpy (elemstr, "DU");
02598   if (!strcmp (oldtype, "Cl  "))
02599     strcpy (elemstr, "CL");
02600   if (!strcmp (oldtype, "K   "))
02601     strcpy (elemstr, "K ");
02602   if (!strcmp (oldtype, "LI  "))
02603     strcpy (elemstr, "LI");
02604   if (!strcmp (oldtype, "LP  "))
02605     strcpy (elemstr, "LP");
02606   if (!strcmp (oldtype, "NA  "))
02607     strcpy (elemstr, "NA");
02608   if (!strcmp (oldtype, "P3  "))
02609     strcpy (elemstr, "P ");
02610   if (!strcmp (oldtype, "S2  "))
02611     strcpy (elemstr, "S ");
02612   if (!strcmp (oldtype, "S3  "))
02613     strcpy (elemstr, "S ");
02614   if (!strcmp (oldtype, "SO  "))
02615     strcpy (elemstr, "S ");
02616   if (!strcmp (oldtype, "SO2 "))
02617     strcpy (elemstr, "S ");
02618   if (!strcmp (oldtype, "SI  "))
02619     strcpy (elemstr, "SI");
02620   if (!strcmp (oldtype, "P4  "))
02621     strcpy (elemstr, "P ");
02622   if (!strcmp (oldtype, "A   "))
02623     strcpy (elemstr, "A ");
02624   if (!strcmp (oldtype, "Q   "))
02625     strcpy (elemstr, "Q ");
02626   return strcpy (Result, elemstr);
02627 }
02628 
02629 
02630 static char *
02631 get_sybelement (Result, oldtype)
02632      char *Result;
02633      char *oldtype;
02634 {
02635   int i;
02636   str2 elemstr;
02637 
02638   if (strpos2 (oldtype, ".", 1) < 2)
02639     sprintf (elemstr, "%.2s", oldtype);
02640   else
02641     {
02642       sprintf (elemstr, "%.*s", strpos2 (oldtype, ".", 1) - 1, oldtype);
02643       if (strlen (elemstr) < 2)
02644        strcat (elemstr, " ");
02645     }
02646   for (i = 0; i <= 1; i++)
02647     elemstr[i] = toupper (elemstr[i]);
02648   return strcpy (Result, elemstr);
02649 }
02650 
02651 
02652 static char *
02653 get_MDLelement (Result, oldtype)
02654      char *Result;
02655      char *oldtype;
02656 {
02657   int i;
02658   str2 elemstr;
02659 
02660   sprintf (elemstr, "%.2s", oldtype);
02661   for (i = 0; i <= 1; i++)
02662     elemstr[i] = toupper (elemstr[i]);
02663   if (elemstr[0] == '~')
02664     strcpy (elemstr, "??");
02665   if (elemstr[0] == '*')
02666     strcpy (elemstr, "??");
02667   return strcpy (Result, elemstr);
02668 }
02669 
02670 
02671 static void
02672 read_molfile (mfilename)
02673      char *mfilename;
02674 {
02675   /* reads ALCHEMY mol files */
02676   int n, code;
02677   char rline[256], tmpstr[256];
02678   char xstr[256], ystr[256], zstr[256], chgstr[256];
02679   float xval, yval, zval, chgval;
02680   char a1str[256], a2str[256], elemstr[256];
02681   int a1val, a2val, ri;
02682   char STR1[256];
02683   int FORLIM;
02684   atom_rec *WITH;
02685   bond_rec *WITH1;
02686 
02687   if (n_atoms > 0)
02688     zap_molecule ();
02689   ri = li;
02690   strcpy (rline, molbuf[ri - 1]);
02691   sprintf (tmpstr, "%.5s", rline);
02692   code = (sscanf (tmpstr, "%ld", &n_atoms) == 0);
02693   strsub (tmpstr, rline, 14, 5);
02694   code = (sscanf (tmpstr, "%ld", &n_bonds) == 0);
02695   strsub (molname, rline, 42, (int) (strlen (rline) - 42L));
02696   /* try */
02697   atom = safe_calloc (n_atoms, sizeof (atom_rec));
02698   bond = safe_calloc (n_bonds, sizeof (bond_rec));
02699   ring = safe_calloc (1, sizeof (ringlist));
02700   ringprop = safe_calloc (1, sizeof (ringprop_type));
02701   /* except
02702      on e:Eoutofmemory do
02703      begin
02704      writeln('Not enough memory');
02705      halt(4);
02706      end;
02707      end; */
02708   n_heavyatoms = 0;
02709   n_heavybonds = 0;
02710   n_Ctot = 0;               /* v0.3g */
02711   n_Otot = 0;               /* v0.3g */
02712   n_Ntot = 0;               /* v0.3g */
02713   FORLIM = n_atoms;
02714   for (n = 1; n <= FORLIM; n++)
02715     {
02716       ri++;
02717       strcpy (rline, molbuf[ri - 1]);
02718       strsub (atomtype, rline, 7, 4);
02719       sprintf (STR1, "%c", toupper (*atomtype));
02720       strcpy (atomtype, STR1);     /* fixed in v0.3f */
02721       get_element (elemstr, atomtype);
02722       if (!strcmp (elemstr, "C "))
02723        n_Ctot++;
02724       if (!strcmp (elemstr, "O "))
02725        n_Otot++;
02726       if (!strcmp (elemstr, "N "))
02727        n_Ntot++;
02728       convert_type (newatomtype, atomtype);
02729       strsub (xstr, rline, 14, 7);
02730       strsub (ystr, rline, 23, 7);
02731       strsub (zstr, rline, 32, 7);
02732       strsub (chgstr, rline, 43, 7);
02733       code = (sscanf (xstr, "%lg", &xval) == 0);
02734       code = (sscanf (ystr, "%lg", &yval) == 0);
02735       code = (sscanf (zstr, "%lg", &zval) == 0);
02736       code = (sscanf (chgstr, "%lg", &chgval) == 0);
02737       WITH = &atom[n - 1];
02738       strcpy (WITH->element, elemstr);
02739       strcpy (WITH->atype, newatomtype);
02740       WITH->x = xval;
02741       WITH->y = yval;
02742       WITH->z = zval;
02743       WITH->real_charge = chgval;
02744       if (is_heavyatom (n))
02745        {
02746          n_heavyatoms++;
02747          WITH->heavy = true;
02748          if (is_metal (n))
02749            WITH->metal = true;
02750        }
02751       WITH->nvalences = get_nvalences (WITH->element);  /* v0.3m   */
02752     }
02753   /*
02754      with atom^[n] do
02755      begin
02756      x := 0; y := 0; z := 0;  (* v0.3g
02757      formal_charge  := 0;
02758      real_charge    := 0;
02759      Hexp           := 0;
02760      Htot           := 0;
02761      neighbor_count := 0;
02762      ring_count     := 0;
02763      arom           := false;
02764      stereo_care    := false;
02765      heavy          := false;
02766      metal          := false;
02767      tag            := false;
02768      end;
02769    */
02770   FORLIM = n_bonds;
02771   for (n = 0; n < FORLIM; n++)
02772     {
02773       ri++;
02774       strcpy (rline, molbuf[ri - 1]);
02775       strsub (a1str, rline, 9, 3);
02776       strsub (a2str, rline, 15, 3);
02777       code = (sscanf (a1str, "%ld", &a1val) == 0);
02778       /* if code <> 0 then beep; */
02779       code = (sscanf (a2str, "%ld", &a2val) == 0);
02780       /* if code <> 0 then beep; */
02781       WITH1 = &bond[n];
02782       WITH1->a1 = a1val;
02783       WITH1->a2 = a2val;
02784       WITH1->btype = rline[19];
02785       WITH1->ring_count = 0;
02786       WITH1->arom = false;
02787       WITH1->topo = btopo_any;
02788       WITH1->stereo = bstereo_any;
02789       WITH1->mdl_stereo = 0;       /* v0.3n */
02790       if (atom[a1val - 1].heavy && atom[a2val - 1].heavy)
02791        n_heavybonds++;
02792     }
02793   memset (ring, 0, sizeof (ringlist));
02794   for (n = 0; n < max_rings; n++)
02795     {                       /* new in v0.3 */
02796       ringprop[n].size = 0;
02797       ringprop[n].arom = false;
02798       ringprop[n].envelope = false;
02799     }
02800   li = ri + 1;
02801 }
02802 
02803 
02804 static void
02805 read_mol2file (mfilename)
02806      char *mfilename;
02807 {
02808   /* reads SYBYL mol2 files */
02809   int n, code;
02810   char sybatomtype[6];
02811   char tmpstr[256], rline[256];
02812   char xstr[256], ystr[256], zstr[256], chgstr[256];
02813   float xval, yval, zval, chgval;
02814   char a1str[256], a2str[256], elemstr[256];
02815   int a1val, a2val, ri, FORLIM;
02816   atom_rec *WITH;
02817   bond_rec *WITH1;
02818 
02819   if (n_atoms > 0)
02820     zap_molecule ();
02821   *rline = '\0';
02822   ri = li - 1;
02823   while ((ri < molbufindex) && (strpos2 (rline, "@<TRIPOS>MOLECULE", 1) == 0))
02824     {
02825       ri++;
02826       strcpy (rline, molbuf[ri - 1]);
02827     }
02828   if (ri < molbufindex)
02829     {
02830       ri++;
02831       strcpy (molname, molbuf[ri - 1]);
02832     }
02833   if (ri < molbufindex)
02834     {
02835       ri++;
02836       strcpy (rline, molbuf[ri - 1]);
02837     }
02838   sprintf (tmpstr, "%.5s", rline);
02839   sscanf (tmpstr, "%ld", &n_atoms);
02840 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
02841   strsub (tmpstr, rline, 7, 5);
02842   sscanf (tmpstr, "%ld", &n_bonds);
02843   /* try */
02844 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
02845   atom = safe_calloc (n_atoms, sizeof (atom_rec));
02846   bond = safe_calloc (n_bonds, sizeof (bond_rec));
02847   ring = safe_calloc (1, sizeof (ringlist));
02848   ringprop = safe_calloc (1, sizeof (ringprop_type));
02849   /* except
02850      on e:Eoutofmemory do
02851      begin
02852      writeln('Not enough memory');
02853      halt(4);
02854      end;
02855      end; */
02856   n_heavyatoms = 0;
02857   n_heavybonds = 0;
02858   n_Ctot = 0;               /* v0.3g */
02859   n_Otot = 0;               /* v0.3g */
02860   n_Ntot = 0;               /* v0.3g */
02861   while ((ri < molbufindex) && (strpos2 (rline, "@<TRIPOS>ATOM", 1) == 0))
02862     {
02863       ri++;
02864       strcpy (rline, molbuf[ri - 1]);
02865     }
02866   FORLIM = n_atoms;
02867   for (n = 1; n <= FORLIM; n++)
02868     {
02869       /*
02870          with atom^[n] do
02871          begin
02872          x := 0; y := 0; z := 0;  (* v0.3g
02873          formal_charge  := 0;
02874          real_charge    := 0;
02875          Hexp           := 0;
02876          Htot           := 0;
02877          neighbor_count := 0;
02878          ring_count     := 0;
02879          arom           := false;
02880          stereo_care    := false;
02881          heavy          := false;
02882          metal          := false;
02883          tag            := false;
02884          end;
02885        */
02886       if (ri < molbufindex)
02887        {
02888          ri++;
02889          strcpy (rline, molbuf[ri - 1]);
02890        }
02891       strsub (sybatomtype, rline, 48, 5);
02892       get_sybelement (elemstr, sybatomtype);
02893       if (!strcmp (elemstr, "C "))
02894        n_Ctot++;
02895       if (!strcmp (elemstr, "O "))
02896        n_Otot++;
02897       if (!strcmp (elemstr, "N "))
02898        n_Ntot++;
02899       convert_sybtype (newatomtype, sybatomtype);
02900       strsub (xstr, rline, 18, 9);
02901       strsub (ystr, rline, 28, 9);
02902       strsub (zstr, rline, 38, 9);
02903       strsub (chgstr, rline, 70, 9);
02904 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
02905 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
02906       sscanf (xstr, "%lg", &xval);
02907       sscanf (ystr, "%lg", &yval);
02908       sscanf (zstr, "%lg", &zval);
02909       sscanf (chgstr, "%lg", &chgval);
02910 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
02911 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
02912       WITH = &atom[n - 1];
02913       strcpy (WITH->element, elemstr);
02914       strcpy (WITH->atype, newatomtype);
02915       WITH->x = xval;
02916       WITH->y = yval;
02917       WITH->z = zval;
02918       WITH->real_charge = chgval;
02919       if (is_heavyatom (n))
02920        {
02921          n_heavyatoms++;
02922          WITH->heavy = true;
02923          if (is_metal (n))
02924            WITH->metal = true;
02925        }
02926       WITH->nvalences = get_nvalences (WITH->element);  /* v0.3m   */
02927     }
02928   while ((ri < molbufindex) && (strpos2 (rline, "@<TRIPOS>BOND", 1) == 0))
02929     {
02930       ri++;
02931       strcpy (rline, molbuf[ri - 1]);
02932     }
02933   FORLIM = n_bonds;
02934   for (n = 0; n < FORLIM; n++)
02935     {
02936       if (ri < molbufindex)
02937        {
02938          ri++;
02939          strcpy (rline, molbuf[ri - 1]);
02940        }
02941       strsub (a1str, rline, 9, 3);
02942       strsub (a2str, rline, 14, 3);
02943       code = (sscanf (a1str, "%ld", &a1val) == 0);
02944       if (code != 0)
02945        printf ("%s\007\n", rline);
02946       code = (sscanf (a2str, "%ld", &a2val) == 0);
02947       if (code != 0)
02948        printf ("%s\007\n", rline);
02949       WITH1 = &bond[n];
02950       WITH1->a1 = a1val;
02951       WITH1->a2 = a2val;
02952       if (rline[17] == '1')
02953        WITH1->btype = 'S';
02954       if (rline[17] == '2')
02955        WITH1->btype = 'D';
02956       if (rline[17] == '3')
02957        WITH1->btype = 'T';
02958       if (rline[17] == 'a')
02959        WITH1->btype = 'A';
02960       WITH1->ring_count = 0;
02961       WITH1->arom = false;
02962       WITH1->topo = btopo_any;
02963       WITH1->stereo = bstereo_any;
02964       WITH1->mdl_stereo = 0;       /* v0.3n */
02965       if (atom[a1val - 1].heavy && atom[a2val - 1].heavy)
02966        n_heavybonds++;
02967     }
02968   memset (ring, 0, sizeof (ringlist));
02969   for (n = 0; n < max_rings; n++)
02970     {                       /* new in v0.3 */
02971       ringprop[n].size = 0;
02972       ringprop[n].arom = false;
02973       ringprop[n].envelope = false;
02974     }
02975   li = ri + 1;
02976 }
02977 
02978 
02979 static void
02980 read_charges (chgstring_)
02981      char *chgstring_;
02982 {
02983   char chgstring[256];
02984   int a_id, a_chg, n_chrg;
02985 
02986   /* typical example: a molecule with 2 cations + 1 anion */
02987   /* M  CHG  3   8   1  10   1  11  -1 */
02988   strcpy (chgstring, chgstring_);
02989   if (strpos2 (chgstring, "M  CHG", 1) <= 0)
02990     return;
02991   strdelete (chgstring, 1, 6);
02992   left_trim (chgstring);
02993   n_chrg = left_int (chgstring);
02994   /* this assignment must be kept also in non-debug mode! */
02995 /* p2c: checkmol.pas, line 2077:
02996  * Note: Turbo Pascal conditional compilation directive was ignored [218] */
02997   /*$IFDEF debug */
02998   /*if (n_chrg == 0)
02999      debugoutput ("strange... M  CHG present, but no charges found"); */
03000   /*$ENDIF */
03001   while (*chgstring != '\0')
03002     {
03003       a_id = left_int (chgstring);
03004       a_chg = left_int (chgstring);
03005       if (a_id != 0 && a_chg != 0)
03006        atom[a_id - 1].formal_charge = a_chg;
03007       //printf ("CHG %i %i\n", a_id, a_chg);
03008     }
03009 }
03010 
03011 static void
03012 read_isotopes (char *isotopestring_)
03013 {
03014   char isotopestring[256];
03015   int a_id, a_nucleon_number, n_isotopes;
03016 
03017   /* typical example: a molecule with 2 cations + 1 anion */
03018   /* M  CHG  3   8   1  10   1  11  -1 */
03019   strcpy (isotopestring, isotopestring_);
03020   if (strpos2 (isotopestring, "M  ISO", 1) <= 0)
03021     return;
03022   strdelete (isotopestring, 1, 6);
03023   left_trim (isotopestring);
03024   n_isotopes = left_int (isotopestring);
03025   /* this assignment must be kept also in non-debug mode! */
03026 /* p2c: checkmol.pas, line 2077:
03027  * Note: Turbo Pascal conditional compilation directive was ignored [218] */
03028   /*$IFDEF debug */
03029   /*if (n_chrg == 0)
03030      debugoutput ("strange... M  CHG present, but no charges found"); */
03031   /*$ENDIF */
03032   while (*isotopestring != '\0')
03033     {
03034       a_id = left_int (isotopestring);
03035       a_nucleon_number = left_int (isotopestring);
03036       if (a_id != 0 && a_nucleon_number != 0)
03037        {
03038          atom[a_id - 1].nucleon_number = a_nucleon_number;
03039          if (!strcmp (atom[a_id - 1].element, "H "))
03040            {
03041              atom[a_id - 1].heavy = true;
03042              n_heavyatoms++;
03043              strcpy (atom[a_id - 1].atype, "DU ");
03044            }
03045        }
03046       //printf ("ISO %i %i\n", a_id, a_nucleon_number);
03047     }
03048 }
03049 
03050 static void
03051 read_radicals (radstring_)
03052      char *radstring_;
03053 {
03054   char radstring[256];
03055   int a_id, a_rad, n_rads;
03056 
03057   /* typical example: a molecule with 2 cations + 1 anion */
03058   /* M  CHG  3   8   1  10   1  11  -1 */
03059   strcpy (radstring, radstring_);
03060   if (strpos2 (radstring, "M  RAD", 1) <= 0)
03061     return;
03062   strdelete (radstring, 1, 6);
03063   left_trim (radstring);
03064   n_rads = left_int (radstring);
03065   /* this assignment must be kept also in non-debug mode! */
03066 /* p2c: checkmol.pas, line 2077:
03067  * Note: Turbo Pascal conditional compilation directive was ignored [218] */
03068   /*$IFDEF debug */
03069   /*if (n_chrg == 0)
03070      debugoutput ("strange... M  CHG present, but no charges found"); */
03071   /*$ENDIF */
03072   while (*radstring != '\0')
03073     {
03074       a_id = left_int (radstring);
03075       a_rad = left_int (radstring);
03076       if (a_id != 0 && a_rad != 0)
03077        atom[a_id - 1].radical_type = a_rad;
03078       //printf ("RAD %i %i\n", a_id, a_rad);
03079     }
03080 }
03081 
03082 
03083 static void
03084 read_MDLmolfile (char *mfilename)
03085 {
03086   /* reads MDL mol files */
03087   int n, v, tmp_n_atoms, tmp_n_bonds, code;      /* v0.3l */
03088   char rline[256], tmpstr[256];
03089   char xstr[256], ystr[256], zstr[256], chgstr[256];
03090   float xval, yval, zval, chgval;
03091   char a1str[256], a2str[256], elemstr[256];
03092   int a1val, a2val, ri, rc, bt, bs;
03093   int sepcount = 0;
03094   int i;                    /* v0.3j */
03095   boolean clearcharges = true;     /* v0.3j */
03096   char STR1[256];
03097   int FORLIM;
03098   atom_rec *WITH;
03099   bond_rec *WITH1;
03100 
03101   /* v0.3j */
03102   if (n_atoms > 0)
03103     zap_molecule ();
03104   /*cm_mdlmolfile := false; */
03105   *rline = '\0';
03106   ri = li;
03107   strcpy (molname, molbuf[ri - 1]);       /* line 1 */
03108   if (ri < molbufindex)            /* line 2 */
03109     ri++;
03110   strcpy (rline, molbuf[ri - 1]);
03111   if (strpos2 (rline, "CheckMol", 1) == 3)
03112     {
03113       /*cm_mdlmolfile := true; */
03114       found_arominfo = true;
03115       tmfcode = 1;          /* v0.3m (begin) */
03116       code = 0;
03117       if ((strlen (rline) >= 39) && (strpos2 (rline, "TMF", 1) == 35))
03118        {                    /* v0.3m; encoding of tweaklevel */
03119          strsub (tmpstr, rline, 38, 2);
03120          code = (sscanf (tmpstr, "%d", &tmfcode) == 0);
03121        }
03122       if (code != 0 || tmfcode != tweaklevel)
03123        tmfmismatch = true;
03124       else
03125        tmfmismatch = false;
03126       if ((strpos2 (rline, ":r0", 1) >= 40 && ringsearch_mode != rs_sar) |
03127          (strpos2 (rline, ":r1", 1) >= 40 && ringsearch_mode != rs_ssr))
03128        tmfmismatch = true;
03129       if ((strpos2 (rline, ":m0", 1) >= 40 && opt_metalrings == true) |
03130          (strpos2 (rline, ":m1", 1) >= 40 && opt_metalrings == false))
03131        tmfmismatch = true;
03132 /* p2c: checkmol.pas, line 2128:
03133  * Note: Turbo Pascal conditional compilation directive was ignored [218] */
03134       /*$IFDEF debug */
03135       //if (tmfmismatch)
03136       //printf ("\"tweaked\" molfile: version mismatch!\n");
03137       // else
03138       //printf ("\"tweaked\" molfile: version OK");
03139     }
03140   /*$ENDIF */
03141   /* v0.3m (end) */
03142   if (ri < molbufindex)            /* line 3 */
03143     ri++;
03144   strcpy (rline, molbuf[ri - 1]);
03145   strcpy (molcomment, rline);
03146   if (ri < molbufindex)            /* line 4 */
03147     ri++;
03148   strcpy (rline, molbuf[ri - 1]);
03149   sprintf (tmpstr, "%.3s", rline);
03150   sscanf (tmpstr, "%d", &n_atoms);
03151 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
03152   strsub (tmpstr, rline, 4, 3);
03153   sscanf (tmpstr, "%d", &n_bonds);
03154 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
03155   strsub (tmpstr, rline, 10, 3);
03156   /* if it is a CheckMol-tweaked molfile, this is the number of rings */
03157   n_cmrings = 0;
03158   code = (sscanf (tmpstr, "%d", &n_cmrings) == 0);
03159   if (code != 0)
03160     n_cmrings = 0;
03161   /* do some range checking for n_atoms, n_bonds; new in v0.3l */
03162   tmp_n_atoms = n_atoms;
03163   if (n_atoms > max_atoms)
03164     n_atoms = max_atoms;
03165   if (n_atoms < 0)
03166     n_atoms = 0;
03167   tmp_n_bonds = n_bonds;
03168   if (n_bonds > max_bonds)
03169     n_bonds = max_bonds;
03170   if (n_bonds < 0)
03171     n_bonds = 0;
03172   if (n_atoms == 0
03173 #ifndef MAKE_SHARED_LIBRARY
03174       && opt_verbose
03175 #endif
03176     )
03177     {                       /* v0.3l */
03178       printf ("WARNING: Possible NoStruct read!\n");
03179       printf ("NoStructs are proprietary, obsolete and dangerous.\n");
03180     }
03181   /* try */
03182   atom = safe_calloc (n_atoms, sizeof (atom_rec));
03183   bond = safe_calloc (n_bonds, sizeof (bond_rec));
03184   /* this would be only one safe_calloc() in C;  v0.3l */
03185   ring = safe_calloc (1, sizeof (ringlist));
03186   ringprop = safe_calloc (1, sizeof (ringprop_type));
03187   /* except
03188      on e:Eoutofmemory do
03189      begin
03190      writeln('Not enough memory');
03191      (* close(molfile);
03192      halt(4);
03193      exit;
03194      end;
03195      end; */
03196   /* check for the chirality flag */
03197   if (strlen (rline) > 14 && rline[14] == '1')   /* new in v0.3f */
03198     chir_flag = true;
03199   n_heavyatoms = 0;
03200   n_heavybonds = 0;
03201   n_Ctot = 0;               /* v0.3g */
03202   n_Otot = 0;               /* v0.3g */
03203   n_Ntot = 0;               /* v0.3g */
03204   if (n_atoms > 0)
03205     {                       /* v0.3l */
03206       for (n = 1; n <= tmp_n_atoms; n++)
03207        {
03208          if (n <= max_atoms)
03209            v = n;
03210          else
03211            v = max_atoms;
03212          /* just for safety; v0.3l */
03213          /*
03214             with atom^[v] do
03215             begin
03216             x := 0; y := 0; z := 0;  (* v0.3g
03217             formal_charge  := 0;
03218             real_charge    := 0;
03219             Hexp           := 0;
03220             Htot           := 0;
03221             neighbor_count := 0;
03222             ring_count     := 0;
03223             arom           := false;
03224             stereo_care    := false;
03225             metal          := false;
03226             heavy          := false;
03227             tag            := false;
03228             end;
03229           */
03230          /* replaced by fillchar() after getmem() (see above); v0.3l */
03231          ri++;
03232          strcpy (rline, molbuf[ri - 1]);
03233          strsub (atomtype, rline, 32, 3);
03234          get_MDLelement (elemstr, atomtype);
03235          if (!strcmp (elemstr, "C "))
03236            n_Ctot++;
03237          if (!strcmp (elemstr, "O "))
03238            n_Otot++;
03239          if (!strcmp (elemstr, "N "))
03240            n_Ntot++;
03241 
03242          convert_MDLtype (newatomtype, atomtype);
03243          strsub (xstr, rline, 1, 10);     /* fixed in v0.3k (was: 2,9 etc.) */
03244          strsub (ystr, rline, 11, 10);
03245          strsub (zstr, rline, 21, 10);
03246          /*chgstr := '0'; */
03247          strsub (chgstr, rline, 37, 3);   /* new in v0.3j */
03248          sscanf (chgstr, "%f", &chgval);
03249 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
03250          if (chgval != 0)
03251            {
03252              if (chgval >= 1 && chgval <= 7)
03253               chgval = 4.0 - chgval;
03254              else
03255               {
03256                 chgval = 0.0;
03257 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
03258               }
03259            }                /* end (v0.3j) */
03260          sscanf (xstr, "%f", &xval);
03261          sscanf (ystr, "%f", &yval);
03262          sscanf (zstr, "%f", &zval);
03263          /* v0.3k: removed superfluous val(chgstr,chgval,code) */
03264 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
03265 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
03266          WITH = &atom[v - 1];
03267          strcpy (WITH->element, elemstr);
03268          if (!strcmp (elemstr, "A ") || !strcmp (elemstr, "Q ") ||
03269              !strcmp (elemstr, "X "))
03270            /* 'X ' added in v0.3n */
03271            found_querymol = true;
03272 
03273          strcpy (WITH->atype, newatomtype);
03274 
03275 
03276          if (!strcmp (elemstr, "D "))
03277            {
03278              strcpy (WITH->element, "H ");
03279              WITH->nucleon_number = 2;
03280            }                /* 0.3x */
03281          if (!strcmp (elemstr, "T "))
03282            {
03283              strcpy (WITH->element, "H ");
03284              WITH->nucleon_number = 3;
03285            }                /* 0.3x */
03286 
03287 
03288 
03289          WITH->x = xval;
03290          WITH->y = yval;
03291          WITH->z = zval;
03292          WITH->formal_charge = (long) floor (chgval + 0.5);
03293          WITH->real_charge = 0.0;  /* v0.3j */
03294          /* read aromaticity flag from CheckMol-tweaked MDL molfile */
03295          if (strlen (rline) > 37 && rline[37] == '0')
03296            {
03297              WITH->arom = true;
03298              found_arominfo = true;
03299            }
03300          /* new in v0.3d: read stereo care flag */
03301          if (strlen (rline) > 47 && rline[47] == '1')
03302            WITH->stereo_care = true;
03303          if (is_heavyatom (n))
03304            {
03305              n_heavyatoms++;
03306              WITH->heavy = true;
03307              if (is_metal (n))
03308               WITH->metal = true;
03309            }
03310          WITH->nvalences = get_nvalences (WITH->element);
03311          /* v0.3m                 */
03312        }
03313     }                       /* if (n_atoms > 0)... */
03314   if (n_bonds > 0)
03315     {                       /* v0.3l */
03316       for (n = 1; n <= tmp_n_bonds; n++)
03317        {
03318          if (n <= max_bonds)
03319            v = n;
03320          else
03321            v = max_bonds;
03322          /* just for safety; v0.3l */
03323          ri++;
03324          strcpy (rline, molbuf[ri - 1]);
03325          sprintf (a1str, "%.3s", rline);
03326          strsub (a2str, rline, 4, 3);
03327          code = (sscanf (a1str, "%d", &a1val) == 0);
03328          if (code != 0)     /* v0.3l */
03329            a1val = 1;
03330          code = (sscanf (a2str, "%d", &a2val) == 0);
03331          if (code != 0)     /* v0.3l */
03332            a2val = 1;
03333          WITH1 = &bond[v - 1];
03334          WITH1->a1 = a1val;
03335          WITH1->a2 = a2val;
03336          if (rline[8] == '1')      /* single */
03337            WITH1->btype = 'S';
03338          if (rline[8] == '2')      /* double */
03339            WITH1->btype = 'D';
03340          if (rline[8] == '3')      /* triple */
03341            WITH1->btype = 'T';
03342          if (rline[8] == '4')      /* aromatic */
03343            WITH1->btype = 'A';
03344          if (rline[8] == '5')      /* single or double */
03345            WITH1->btype = 'l';
03346          if (rline[8] == '6')      /* single or aromatic */
03347            WITH1->btype = 's';
03348          if (rline[8] == '7')      /* double or aromatic */
03349            WITH1->btype = 'd';
03350          if (rline[8] == '8')      /* any */
03351            WITH1->btype = 'a';
03352          sprintf (STR1, "%c", WITH1->btype);
03353          if (strpos2 ("lsda", STR1, 1) > 0)
03354            found_querymol = true;
03355          WITH1->arom = false;
03356          WITH1->q_arom = false;    /* 0.3p */
03357          /* read aromaticity flag from CheckMol-tweaked MDL molfile */
03358          if (WITH1->btype == 'A' || rline[7] == '0')
03359            {
03360              WITH1->arom = true;
03361              if (rline[7] == '0')
03362               found_arominfo = true;
03363            }
03364          strsub (tmpstr, rline, 13, 3);
03365          /* new in v0.3d: read ring_count from tweaked molfile */
03366          code = (sscanf (tmpstr, "%d", &rc) == 0);
03367          if (code != 0 || rc < 0 || progmode == pmCheckMol || tmfmismatch)
03368            WITH1->ring_count = 0;
03369          else
03370            WITH1->ring_count = rc;
03371          /* v0.3n: added tmfmismatch check */
03372          strsub (tmpstr, rline, 16, 3);   /* new in v0.3d: read bond topology; */
03373          code = (sscanf (tmpstr, "%d", &bt) == 0);
03374          /* extended features are encoded by leading zero */
03375          if (code != 0 || (unsigned long) bt > 2)
03376            WITH1->topo = btopo_any;
03377          else
03378            {
03379              if (tmpstr[1] == '0')
03380               WITH1->topo = bt + 3;
03381              else
03382               WITH1->topo = bt;
03383            }
03384          /* v0.3n changed >5 into >2 */
03385          /* new in v0.3d: add stereo property from MDL "stereo care" flag in atom block */
03386          WITH1->stereo = bstereo_any;
03387          if (WITH1->btype == 'D')
03388            {
03389              if (atom[WITH1->a1 - 1].stereo_care
03390                 && atom[WITH1->a2 - 1].stereo_care)
03391               {             /* this is the MDL-conformant encoding, */
03392                 WITH1->stereo = bstereo_xyz;     /* for an alternative see below */
03393                 ez_flag = true;    /* v0.3f */
03394               }
03395              else
03396               {             /* this extended feature is encoded by a leading zero */
03397                 strsub (tmpstr, rline, 10, 3);
03398                 /* new in v0.3d: read bond stereo specification; */
03399                 code = (sscanf (tmpstr, "%d", &bs) == 0);
03400                 WITH1->mdl_stereo = bs;   /* v0.3n */
03401                 if (code != 0 || bs <= 0 || bs > 2)
03402                   WITH1->stereo = bstereo_any;
03403                 else
03404                   WITH1->stereo = bstereo_xyz;
03405                 if (tmpstr[1] == '0')
03406                   WITH1->stereo = bstereo_xyz;
03407               }
03408            }
03409          /*if stereo <> bstereo_any then ez_search := true; */
03410          if (WITH1->stereo != bstereo_any)       /* changed in v0.3f */
03411            ez_flag = true;
03412          if (WITH1->btype == 'S' && strlen (rline) > 11 && rline[11] == '1')
03413            WITH1->stereo = bstereo_up;
03414          if (WITH1->btype == 'S' && strlen (rline) > 11 && rline[11] == '6')
03415            WITH1->stereo = bstereo_down;
03416          if (WITH1->btype == 'S' && strlen (rline) > 11 && rline[11] == '4')
03417            WITH1->stereo = bstereo_either;       /* 0.3x */
03418          if (WITH1->btype == 'D' && strlen (rline) > 11 && rline[11] == '3')
03419            WITH1->stereo = bstereo_double_either;       /* 0.3x */
03420          strsub (tmpstr, rline, 10, 3);
03421          /* new in v0.3n: save original bond stereo specification; */
03422          sscanf (tmpstr, "%d", &bs);
03423          /* v0.3n */
03424 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
03425          WITH1->mdl_stereo = bs;   /* v0.3n */
03426          if (atom[a1val - 1].heavy && atom[a2val - 1].heavy)
03427            n_heavybonds++;
03428        }
03429     }                       /* if (n_bonds > 0)... */
03430   while (ri < molbufindex && sepcount < 1)
03431     {
03432       ri++;
03433       strcpy (rline, molbuf[ri - 1]);
03434       if (strpos2 (rline, "M  CHG", 1) > 0)
03435        {                    /* new in v0.3j */
03436          if (clearcharges)
03437            {                /* "M  CHG" supersedes all "old-style" charge values */
03438 
03439              for (i = 0; i < n_atoms; i++)
03440               atom[i].formal_charge = 0;
03441            }
03442          read_charges (rline);
03443          clearcharges = false;
03444          /* subsequent "M  CHG" lines must not clear previous values */
03445        }
03446 
03447       if (strpos2 (rline, "M  ISO", 1) > 0)
03448        read_isotopes (rline);      /* 0.3x */
03449 
03450       if (strpos2 (rline, "M  RAD", 1) > 0)
03451        read_radicals (rline);      /* 0.3x */
03452 
03453       if (strpos2 (rline, "$$$$", 1) > 0)
03454        {
03455          sepcount++;
03456          if (molbufindex > ri + 2) /* we assume this is an SDF file */
03457            mol_in_queue = true;
03458        }
03459     }
03460   memset (ring, 0, sizeof (ringlist));
03461   for (n = 0; n < max_rings; n++)
03462     {                       /* new in v0.3 */
03463       ringprop[n].size = 0;
03464       ringprop[n].arom = false;
03465       ringprop[n].envelope = false;
03466     }
03467   li = ri + 1;
03468 }
03469 
03470 
03471 
03472 static void
03473 write_MDLmolfile ()
03474 {
03475   int i;
03476   char tmpstr[256];
03477   char wline[256];
03478   int a_chg;
03479   int a_iso;
03480   int a_rad;
03481   char tmflabel[256];              /* v0.3m */
03482   char STR1[256], STR7[256];
03483   int FORLIM;
03484 
03485   sprintf (tmflabel, "%d", (int) tweaklevel);    /* v0.3m */
03486   while (strlen (tmflabel) < 2)    /* v0.3m */
03487     sprintf (tmflabel, "0%s", strcpy (STR1, tmflabel));
03488   sprintf (tmflabel, "TMF%s", strcpy (STR1, tmflabel)); /* v0.3m */
03489   if (strlen (molname) > 80)
03490     sprintf (molname, "%.80s", strcpy (STR1, molname));
03491   puts (molname);
03492   printf ("  CheckMol                        %s", tmflabel);   /* v0.3m */
03493   if (ringsearch_mode == rs_sar)   /* v0.3m */
03494     printf (":r0");
03495   if (ringsearch_mode == rs_ssr)   /* v0.3m */
03496     printf (":r1");
03497   if (opt_metalrings)
03498     printf (":m1");
03499   else
03500     printf (":m0");
03501   /* v0.3m */
03502   printf ("\n%s\n", molcomment);
03503   *wline = '\0';
03504   *tmpstr = '\0';
03505   sprintf (tmpstr, "%d", n_atoms);
03506   lblank (3L, tmpstr);
03507   strcat (wline, tmpstr);
03508   *tmpstr = '\0';           /* first 3 digits: number of atoms */
03509   sprintf (tmpstr, "%d", n_bonds);
03510   lblank (3L, tmpstr);
03511   strcat (wline, tmpstr);
03512   *tmpstr = '\0';           /* next 3 digits: number of bonds */
03513   strcpy (tmpstr, "  0");
03514   strcat (wline, tmpstr);
03515   *tmpstr = '\0';           /* next 3 digits: number of atom lists (not used by us) */
03516 /* p2c: checkmol.pas, line 2388:
03517  * Note: Turbo Pascal conditional compilation directive was ignored [218] */
03518 #ifdef REDUCED_SAR
03519   sprintf (tmpstr, "%d", n_countablerings);
03520   /* v0.3n; changed n_rings into n_countablerings */
03521 #else
03522   sprintf (tmpstr, "%d", n_rings);
03523 #endif
03524   lblank (3L, tmpstr);
03525   strcat (wline, tmpstr);
03526   *tmpstr = '\0';
03527   /* officially "obsolete", we use it for the number of rings */
03528   strcat (wline, "  ");            /* v0.3n: obey chiral flag */
03529   if (chir_flag)
03530     strcat (wline, "1");
03531   else
03532     strcat (wline, "0");
03533   /* v0.3n */
03534   strcat (wline, "               999 V2000");
03535   /* v0.3n (adjust string length) */
03536   puts (wline);
03537   FORLIM = n_atoms;
03538   for (i = 0; i < FORLIM; i++)
03539     {
03540       *wline = '\0';
03541       sprintf (tmpstr, "%1.4f", atom[i].x);
03542       lblank (10L, tmpstr);
03543       strcat (wline, tmpstr);
03544       sprintf (tmpstr, "%1.4f", atom[i].y);
03545       lblank (10L, tmpstr);
03546       strcat (wline, tmpstr);
03547       sprintf (tmpstr, "%1.4f", atom[i].z);
03548       lblank (10L, tmpstr);
03549       strcat (wline, tmpstr);
03550       strcpy (tmpstr, atom[i].element);
03551       /* tmpstr := lowercase(tmpstr); REPLACE!!! */
03552       //tmpstr[0] = toupper (tmpstr[0]);
03553       all_lowercase (tmpstr);
03554       tmpstr[0] = toupper (tmpstr[0]);
03555       /*wline := wline + ' '+atom^[i].element+' '; */
03556       sprintf (wline + strlen (wline), " %s ", tmpstr);
03557       strcat (wline, " 0"); /* mass difference (isotopes) */
03558       /* now we code aromaticity into the old-style charge column (charges are now in the M  CHG line) */
03559       if (atom[i].arom)
03560        strcpy (tmpstr, " 00");
03561       else
03562        strcpy (tmpstr, "  0");
03563       strcat (wline, tmpstr);
03564       strcat (wline, "  0  0  0  0  0  0  0  0  0  0");
03565       puts (wline);
03566     }
03567   FORLIM = n_bonds;
03568   for (i = 0; i < FORLIM; i++)
03569     {
03570       *wline = '\0';
03571       sprintf (tmpstr, "%d", bond[i].a1);
03572       lblank (3L, tmpstr);
03573       strcat (wline, tmpstr);
03574       sprintf (tmpstr, "%d", bond[i].a2);
03575       lblank (3L, tmpstr);
03576       strcat (wline, tmpstr);
03577       if (bond[i].btype == 'S')
03578        strcpy (tmpstr, "  1");
03579       if (bond[i].btype == 'D')
03580        strcpy (tmpstr, "  2");
03581       if (bond[i].btype == 'T')
03582        strcpy (tmpstr, "  3");
03583       if (bond[i].btype == 'A')
03584        strcpy (tmpstr, "  4");
03585       if (bond[i].btype == 'l')
03586        strcpy (tmpstr, "  5");
03587       if (bond[i].btype == 's')
03588        strcpy (tmpstr, "  6");
03589       if (bond[i].btype == 'd')
03590        strcpy (tmpstr, "  7");
03591       if (bond[i].btype == 'a')
03592        strcpy (tmpstr, "  8");
03593       /* now encode our own aromaticity information */
03594       if (bond[i].arom)
03595        tmpstr[1] = '0';
03596       strcat (wline, tmpstr);      /* next, encode bond stereo property (v0.3f) */
03597       /*if (bond^[i].stereo = bstereo_up) then wline := wline + '  1' else */
03598       /*  if (bond^[i].stereo = bstereo_down) then wline := wline + '  6' else */
03599       /*    wline := wline + '  0'; */
03600       /* restore original value from MDL molfile (v0.3n) */
03601       /* wline := wline + '  ' + inttostr(bond^[i].mdl_stereo);    REPLACE!!! */
03602       *tmpstr = '\0';
03603       sprintf (tmpstr, "%i", bond[i].mdl_stereo);
03604       strcat (wline, "  ");
03605       strcat (wline, tmpstr);
03606       *tmpstr = '\0';
03607       /* now encode the ring_count of this bond (using a field which officially is "not used") */
03608       /* tmpstr := inttostr(bond^[i].ring_count); REPLACE!!! */
03609       sprintf (tmpstr, "%i", bond[i].ring_count);
03610       while (strlen (tmpstr) < 3)
03611        sprintf (tmpstr, " %s", strcpy (STR1, tmpstr));
03612       sprintf (wline + strlen (wline), "%s  0  0", tmpstr);
03613       puts (wline);
03614     }
03615   FORLIM = n_atoms;
03616   for (i = 1; i <= FORLIM; i++)
03617     {
03618       a_chg = atom[i - 1].formal_charge;
03619       if (a_chg != 0)
03620        {
03621          strcpy (wline, "M  CHG  1 ");
03622          sprintf (tmpstr, "%d", i);
03623          lblank (3L, tmpstr);
03624          sprintf (wline + strlen (wline), "%s ", tmpstr);
03625          sprintf (tmpstr, "%d", a_chg);
03626          lblank (3L, tmpstr);
03627          strcat (wline, tmpstr);
03628          puts (wline);
03629        }
03630     }
03631   for (i = 1; i <= FORLIM; i++)    /* 0.3x */
03632     {
03633       a_iso = atom[i - 1].nucleon_number;
03634       if (a_iso != 0)
03635        {
03636          strcpy (wline, "M  ISO  1 ");
03637          sprintf (tmpstr, "%d", i);
03638          lblank (3L, tmpstr);
03639          sprintf (wline + strlen (wline), "%s ", tmpstr);
03640          sprintf (tmpstr, "%d", a_iso);
03641          lblank (3L, tmpstr);
03642          strcat (wline, tmpstr);
03643          puts (wline);
03644        }
03645     }
03646   for (i = 1; i <= FORLIM; i++)    /* 0.3x */
03647     {
03648       a_rad = atom[i - 1].radical_type;
03649       if (a_rad != 0)
03650        {
03651          strcpy (wline, "M  RAD  1 ");
03652          sprintf (tmpstr, "%d", i);
03653          lblank (3L, tmpstr);
03654          sprintf (wline + strlen (wline), "%s ", tmpstr);
03655          sprintf (tmpstr, "%d", a_rad);
03656          lblank (3L, tmpstr);
03657          strcat (wline, tmpstr);
03658          puts (wline);
03659        }
03660     }
03661   printf ("M  END\n");
03662 }
03663 
03664 
03665 /*============= chemical processing functions && procedures ============ */
03666 
03667 static boolean
03668 is_electroneg (a_el)
03669      char *a_el;
03670 {
03671   /* new in v0.3j */
03672   boolean res = false;
03673 
03674   if (!strcmp (a_el, "N "))
03675     res = true;
03676   if (!strcmp (a_el, "P "))
03677     res = true;
03678   if (!strcmp (a_el, "O "))
03679     res = true;
03680   if (!strcmp (a_el, "S "))
03681     res = true;
03682   if (!strcmp (a_el, "SE"))
03683     res = true;
03684   if (!strcmp (a_el, "TE"))
03685     res = true;
03686   if (!strcmp (a_el, "F "))
03687     res = true;
03688   if (!strcmp (a_el, "CL"))
03689     res = true;
03690   if (!strcmp (a_el, "BR"))
03691     res = true;
03692   if (!strcmp (a_el, "I "))
03693     res = true;
03694   if (!strcmp (a_el, "AT"))
03695     res = true;
03696   return res;
03697 }
03698 
03699 
03700 static void
03701 count_neighbors ()
03702 {
03703   /* counts heavy-atom neighbors and explicit hydrogens */
03704   int i, FORLIM;
03705 
03706   if (n_atoms < 1 || n_bonds < 1)
03707     return;
03708   FORLIM = n_bonds;
03709   for (i = 0; i < FORLIM; i++)
03710     {
03711       if (atom[bond[i].a1 - 1].heavy)
03712        atom[bond[i].a2 - 1].neighbor_count++;
03713       if (atom[bond[i].a2 - 1].heavy)
03714        atom[bond[i].a1 - 1].neighbor_count++;
03715       if (!strcmp (atom[bond[i].a1 - 1].element, "H "))
03716        atom[bond[i].a2 - 1].Hexp++;
03717       if (!strcmp (atom[bond[i].a2 - 1].element, "H "))
03718        atom[bond[i].a1 - 1].Hexp++;
03719       /* plausibility check (new in v02.i) */
03720       if (atom[bond[i].a1 - 1].neighbor_count > max_neighbors ||
03721          atom[bond[i].a2 - 1].neighbor_count > max_neighbors)
03722        {
03723          mol_OK = false;
03724          /*writeln('invalid molecule!'); */
03725        }
03726     }
03727 }
03728 
03729 
03730 static void
03731 get_neighbors (Result, id)
03732      int *Result;
03733      int id;
03734 {
03735   int i = 0;
03736   //neighbor_rec nb_tmp;
03737   int nb_count = 0;
03738   //int FORLIM = n_bonds;
03739 
03740   //memset (Result, 0, sizeof (neighbor_rec));
03741 
03742   for (i; i < n_bonds; i++)
03743     {
03744       if (bond[i].a1 == id && atom[bond[i].a2 - 1].heavy
03745          && nb_count < max_neighbors)
03746        {
03747          Result[nb_count++] = bond[i].a2;
03748        }
03749       if (bond[i].a2 == id && atom[bond[i].a1 - 1].heavy
03750          && nb_count < max_neighbors)
03751        {
03752          Result[nb_count++] = bond[i].a1;
03753        }
03754     }
03755   //return memcpy (Result, nb_tmp, sizeof (neighbor_rec));
03756 }
03757 
03758 
03759 static void
03760 get_ndl_neighbors (int *Result, int id)
03761 {
03762   int i;
03763   //neighbor_rec nb_tmp;
03764   int nb_count = 0;
03765   /* v0.3i: use max_neighbors instead of a fixed value of 8 */
03766   //int FORLIM = ndl_n_bonds;
03767 
03768   //memset (nb_tmp, 0, sizeof (neighbor_rec));
03769 
03770   for (i = 0; i < ndl_n_bonds; i++)
03771     {
03772       if (ndl_bond[i].a1 == id && nb_count < max_neighbors &&
03773          ndl_atom[ndl_bond[i].a2 - 1].heavy)
03774        {
03775          nb_count++;
03776          Result[nb_count - 1] = ndl_bond[i].a2;
03777        }
03778       if (ndl_bond[i].a2 == id && nb_count < max_neighbors &&
03779          ndl_atom[ndl_bond[i].a1 - 1].heavy)
03780        {
03781          nb_count++;
03782          Result[nb_count - 1] = ndl_bond[i].a1;
03783        }
03784     }
03785   //return memcpy (Result, nb_tmp, sizeof (neighbor_rec));
03786 }
03787 
03788 
03789 static int *
03790 get_nextneighbors (int *Result, int id, int prev_id)
03791 {
03792   int i;
03793   neighbor_rec nb_tmp;
03794   int nb_count = 0;
03795   int FORLIM;
03796 
03797   /* gets all neighbors except prev_id (usually the atom where we came from */
03798   memset (nb_tmp, 0, sizeof (neighbor_rec));
03799   FORLIM = n_bonds;
03800   for (i = 0; i < FORLIM; i++)
03801     {
03802       if (bond[i].a1 == id && bond[i].a2 != prev_id &&
03803          nb_count < max_neighbors && atom[bond[i].a2 - 1].heavy)
03804        {
03805          nb_count++;
03806          nb_tmp[nb_count - 1] = bond[i].a2;
03807        }
03808       if (bond[i].a2 == id && bond[i].a1 != prev_id &&
03809          nb_count < max_neighbors && atom[bond[i].a1 - 1].heavy)
03810        {
03811          nb_count++;
03812          nb_tmp[nb_count - 1] = bond[i].a1;
03813        }
03814     }
03815   return memcpy (Result, nb_tmp, sizeof (neighbor_rec));
03816 }
03817 
03818 
03819 static int *
03820 get_ndl_nextneighbors (int *Result, int id, int prev_id)
03821 {
03822   int i;
03823   neighbor_rec nb_tmp;
03824   int nb_count = 0;
03825   int FORLIM;
03826 
03827   /* gets all neighbors except prev_id (usually the atom where we came from */
03828   memset (nb_tmp, 0, sizeof (neighbor_rec));
03829   FORLIM = ndl_n_bonds;
03830   for (i = 0; i < FORLIM; i++)
03831     {
03832       if (ndl_bond[i].a1 == id && ndl_bond[i].a2 != prev_id &&
03833          nb_count < max_neighbors && ndl_atom[ndl_bond[i].a2 - 1].heavy)
03834        {
03835          nb_count++;
03836          nb_tmp[nb_count - 1] = ndl_bond[i].a2;
03837        }
03838       if (ndl_bond[i].a2 == id && ndl_bond[i].a1 != prev_id &&
03839          nb_count < max_neighbors && ndl_atom[ndl_bond[i].a1 - 1].heavy)
03840        {
03841          nb_count++;
03842          nb_tmp[nb_count - 1] = ndl_bond[i].a1;
03843        }
03844     }
03845   return memcpy (Result, nb_tmp, sizeof (neighbor_rec));
03846 }
03847 
03848 
03849   /*static int path_pos (id, a_path) int id;
03850      int *a_path;
03851      {
03852      /* new version in v0.3l 
03853      int i;
03854      int pp = 0;
03855 
03856      for (i = 1; i <= max_ringsize; i++)
03857      {
03858      if (a_path[i - 1] == id)
03859      {
03860      pp = i;
03861      /* p2c: checkmol.pas, line 2620:
03862      * Warning: Expected a '(', found a semicolon [227] 
03863      /* p2c: checkmol.pas, line 2620:
03864      * Warning: Expected an expression, found a semicolon [227] 
03865      fflush (0);
03866      P_ioresult = 0;
03867      }
03868      }
03869      return pp;
03870      } */
03871 
03872 static int
03873 matchpath_pos (int id, int *a_path)
03874 {
03875   int i;
03876   int pp = 0;
03877 
03878   for (i = max_matchpath_length; i >= 1; i--)
03879     {
03880       if (a_path[i - 1] == id)
03881        pp = i;
03882     }
03883   return pp;
03884 }
03885 
03886 
03887 static int
03888 matchpath_length (int *a_path)
03889 {
03890   if (a_path[max_matchpath_length - 1] != 0)
03891     return max_matchpath_length;
03892   else
03893     return (matchpath_pos (0L, a_path) - 1);
03894 }
03895 
03896 static int
03897 get_ndl_bond (int ba1, int ba2)
03898 {
03899   int i;
03900   int b_id = 0;
03901   int FORLIM;
03902 
03903   if (ndl_n_bonds <= 0)
03904     return b_id;
03905   FORLIM = ndl_n_bonds;
03906   for (i = 1; i <= FORLIM; i++)
03907     {
03908       if (ndl_bond[i - 1].a1 == ba1 && ndl_bond[i - 1].a2 == ba2 ||
03909          ndl_bond[i - 1].a1 == ba2 && ndl_bond[i - 1].a2 == ba1)
03910        b_id = i;
03911     }
03912   return b_id;
03913 }
03914 
03915 static int
03916 ringcompare (int *rp1, int *rp2)
03917 {
03918   int i, j;
03919   int rc = 0;
03920   int rs1, rs2;
03921   int n_common = 0;
03922   int max_cra;
03923 
03924   rs1 = path_length (rp1);
03925   rs2 = path_length (rp2);
03926   if (rs1 < rs2)
03927     max_cra = rs1;
03928   else
03929     max_cra = rs2;
03930   for (i = 0; i < rs1; i++)
03931     {
03932       for (j = 0; j < rs2; j++)
03933        {
03934          if (rp1[i] == rp2[j])
03935            n_common++;
03936        }
03937     }
03938   if (rs1 == rs2 && n_common == max_cra)
03939     {
03940       rc = 0;
03941       return rc;
03942     }
03943   if (n_common == 0)
03944     rc += 8;
03945   if (n_common < max_cra)
03946     {
03947       rc += 4;
03948       return rc;
03949     }
03950   if (rs1 < rs2)
03951     rc++;
03952   else
03953     rc += 2;
03954   return rc;
03955 }
03956 
03957 
03958 static boolean
03959 rc_identical (int rc_int)
03960 {
03961   if (rc_int == 0)
03962     return true;
03963   else
03964     return false;
03965 }
03966 
03967 
03968 static boolean
03969 rc_1in2 (int rc_int)
03970 {
03971   if (rc_int & 1)
03972     return true;
03973   else
03974     return false;
03975 }
03976 
03977 
03978 static boolean
03979 rc_2in1 (int rc_int)
03980 {
03981   rc_int /= 2;
03982   if (rc_int & 1)
03983     return true;
03984   else
03985     return false;
03986 }
03987 
03988 
03989 static boolean
03990 rc_different (int rc_int)
03991 {
03992   rc_int /= 4;
03993   if (rc_int & 1)
03994     return true;
03995   else
03996     return false;
03997 }
03998 
03999 
04000 static boolean
04001 rc_independent (int rc_int)
04002 {
04003   rc_int /= 8;
04004   if (rc_int & 1)
04005     return true;
04006   else
04007     return false;
04008 }
04009 
04010 
04011 static boolean
04012 is_newring (int *n_path)
04013 {
04014   int i, j;
04015   boolean nr = true;
04016   boolean same_ring;
04017   ringpath_type tmp_path;
04018   int rc_result;
04019   boolean found_ring;
04020   int pl;                   /* new in v0.3 */
04021   int FORLIM;
04022 
04023   pl = path_length (n_path);       /* new in v0.3 */
04024   if (n_rings <= 0)
04025     return true;
04026   switch (ringsearch_mode)
04027     {
04028 
04029     case rs_sar:
04030       found_ring = false;
04031       i = 0;
04032       while (i < n_rings && !found_ring)
04033        {
04034          i++;
04035          if (pl != ringprop[i - 1].size)  /* compare only rings of same size */
04036            continue;
04037          same_ring = true;
04038          for (j = 0; j < max_ringsize; j++)
04039            {
04040              if (ring[i - 1][j] != n_path[j])
04041               same_ring = false;
04042            }
04043          if (same_ring)
04044            {
04045              nr = false;
04046              found_ring = true;
04047            }
04048        }
04049       break;
04050 
04051     case rs_ssr:
04052       FORLIM = n_rings;
04053       for (i = 0; i < FORLIM; i++)
04054        {
04055          for (j = 0; j < max_ringsize; j++)
04056            tmp_path[j] = ring[i][j];
04057          rc_result = ringcompare (n_path, tmp_path);
04058          if (rc_identical (rc_result))
04059            nr = false;
04060          if (rc_1in2 (rc_result))
04061            {
04062              /* exchange existing ring by smaller one */
04063              for (j = 0; j < max_ringsize; j++)
04064               ring[i][j] = n_path[j];
04065              /* update ring property record (new in v0.3) */
04066              ringprop[i].size = pl;
04067              nr = false;
04068 /* p2c: checkmol.pas, line 2841:
04069  * Note: Turbo Pascal conditional compilation directive was ignored [218] */
04070              /*$IFDEF debug */
04071              /* debugoutput('replacing ring '+inttostr(i)+' by smaller one (ringsize: '+inttostr(path_length(n_path))+')'); */
04072              /*$ENDIF */
04073            }
04074          if (rc_2in1 (rc_result))
04075            {
04076              /* new ring contains existing one, but is larger ==> discard */
04077              nr = false;
04078            }
04079        }
04080       break;
04081     }
04082   return nr;
04083 }
04084 
04085 
04086 static void
04087 add_ring (int *n_path)
04088 {
04089   /* new in v0.3: store rings in an ordered way (with ascending ring size) */
04090   int i;
04091   int j = 0;
04092   int k, s, pl;
04093 /* p2c: checkmol.pas, line 2862:
04094  * Note: Turbo Pascal conditional compilation directive was ignored [218] */
04095   /*$IFDEF debug */
04096   char dstr[256];
04097   int FORLIM;
04098 
04099   /*$ENDIF */
04100   pl = path_length (n_path);
04101 
04102   if (pl < 1)
04103     return;
04104 
04105   if (n_rings >= max_rings)
04106     {
04107 
04108 /* p2c: checkmol.pas, line 2906:
04109  * Note: Turbo Pascal conditional compilation directive was ignored [218] */
04110       /*$IFDEF debug 
04111          debugoutput ("max_rings exceeded!");
04112          /*$ENDIF */
04113       return;
04114     }
04115   n_rings++;
04116 
04117 /* p2c: checkmol.pas, line 2871:
04118  * Note: Turbo Pascal conditional compilation directive was ignored [218] */
04119   /*$IFDEF debug */
04120   /* dstr := '';
04121      for j := 1 to pl do dstr := dstr + inttostr((n_path[j])) + ' ';
04122      debugoutput('adding ring '+inttostr(n_rings)+':  '+dstr); */
04123   /*$ENDIF */
04124   if (n_rings > 1)
04125     {
04126       FORLIM = n_rings;
04127       for (i = 1; i < FORLIM; i++)
04128        {
04129          s = ringprop[i - 1].size;
04130          if (pl >= s)
04131            j = i;
04132        }
04133     }
04134   j++;                      /* the next position is ours */
04135   if (j < n_rings)
04136     {                       /* push up the remaining rings by one position */
04137       for (k = n_rings; k > j; k--)
04138        {
04139          ringprop[k - 1].size = ringprop[k - 2].size;
04140          /*ringprop^[k].arom := ringprop^[(k-1)].arom; */
04141          for (i = 0; i < max_ringsize; i++)
04142            ring[k - 1][i] = ring[k - 2][i];
04143        }
04144     }
04145   ringprop[j - 1].size = pl;
04146   for (i = 0; i < max_ringsize; i++)
04147     {
04148       ring[j - 1][i] = n_path[i];
04149       /*inc(atom^[(n_path[i])].ring_count); */
04150     }
04151 }
04152 
04153 
04154   /* static boolean is_ringpath (s_path) int *s_path;
04155      {
04156      boolean Result;
04157      int i, j;
04158      neighbor_rec nb;
04159      boolean rp = false;
04160      boolean new_atom;
04161      int a_last, pl;
04162      ringpath_type l_path;
04163      int FORLIM;
04164 
04165      /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] 
04166      memset (nb, 0, sizeof (neighbor_rec));
04167      memset (l_path, 0, sizeof (ringpath_type));
04168      pl = path_length (s_path);
04169      if (pl < 1)
04170      {
04171      /* p2c: checkmol.pas, line 2928:
04172      * Note: Turbo Pascal conditional compilation directive was ignored [218] 
04173      /*$IFDEF debug 
04174      debugoutput ("Oops! Got zero-length s_path!");
04175      /*$ENDIF 
04176      return Result;
04177      }
04178      for (i = 0; i < pl; i++)
04179      l_path[i] = s_path[i];
04180      /* check if the last atom is a metal and stop if opt_metalrings is not set (v0.3) 
04181      if (opt_metalrings == false)
04182      {
04183      if (atom[l_path[pl - 1] - 1].metal)
04184      {
04185      /* p2c: checkmol.pas, line 2942:
04186      * Note: Turbo Pascal conditional compilation directive was ignored [218] 
04187      /*$IFDEF debug 
04188      debugoutput ("skipping metal in ring search");
04189      /*$ENDIF 
04190      return false;
04191      }
04192      }
04193      /* check if ring is already closed 
04194      if (pl > 2 && l_path[pl - 1] == l_path[0])
04195      {
04196      l_path[pl - 1] = 0;        /* remove last entry (redundant!) 
04197      order_ringpath (l_path);
04198      if (is_newring (l_path))
04199      {
04200      if (n_rings >= max_rings)
04201      {
04202      /* p2c: checkmol.pas, line 2958:
04203      * Note: Turbo Pascal conditional compilation directive was ignored [218] 
04204      /*$IFDEF debug 
04205      debugoutput ("maximum number of rings exceeded!");
04206      /*$ENDIF 
04207      return false;
04208      }
04209      add_ring (l_path);
04210      }
04211      /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] 
04212      return true;
04213      }
04214      /* any other case: ring is not (yet) closed 
04215      a_last = l_path[pl - 1];
04216      get_neighbors (nb, a_last);
04217      if (atom[a_last - 1].neighbor_count <= 1)
04218      return false;
04219      if (n_rings >= max_rings)
04220      /* added in v0.2: check if max_rings is reached *
04221      {                          /* if ring is not closed, continue searching 
04222      return false;
04223      }
04224      FORLIM = atom[a_last - 1].neighbor_count;
04225      for (i = 0; i < FORLIM; i++)
04226      {
04227      new_atom = true;
04228      for (j = 1; j < pl; j++)
04229      {
04230      if (nb[i] == l_path[j])
04231      {                    /* v0.3k 
04232      new_atom = false;
04233      /* p2c: checkmol.pas, line 2982:
04234      * Warning: Expected a '(', found a semicolon [227] *
04235      /* p2c: checkmol.pas, line 2982:
04236      * Warning: Expected an expression, found a semicolon [227] 
04237      fflush (0);
04238      P_ioresult = 0;      /* v0.3k *
04239      }
04240      }
04241 
04242      /* added in v0.1a: check if max_rings not yet reached 
04243      /* added in v0.2:  limit ring size to max_vringsize instead of max_ringsize 
04244      if (new_atom && pl < max_vringsize && n_rings < max_rings)
04245      {
04246      l_path[pl] = nb[i];
04247      if (pl < max_ringsize - 1)   /* just to be sure 
04248      l_path[pl + 1] = 0;
04249      if (is_ringpath (l_path))
04250      rp = true;
04251      }
04252      }
04253      return rp;
04254      } */
04255 
04256 static boolean
04257 is_ringpath (int *s_path)
04258 {
04259   int i, j;
04260   neighbor_rec nb;
04261   boolean rp = false;
04262   boolean new_atom;
04263   int a_last, pl;
04264   ringpath_type l_path;
04265   int FORLIM, pl_prev, pl_next, max_ringsize_dec;
04266 
04267 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
04268   memset ((void *) nb, 0, sizeof (neighbor_rec));
04269   memset ((void *) l_path, 0, sizeof (ringpath_type));
04270   pl = path_length (s_path);
04271   if (pl < 1)
04272     {
04273 /* p2c: checkmol.pas, line 2524:
04274  * Note: Turbo Pascal conditional compilation directive was ignored [218] */
04275 
04276       return false;
04277     }
04278 
04279   pl_prev = pl - 1;
04280   //memcpy (l_path, s_path, sizeof (ringpath_type));
04281   memcpy (l_path, s_path, pl * sizeof (int));
04282 
04283   /* check if the last atom is a metal and stop if opt_metalrings is not set (v0.3) */
04284   if (opt_metalrings == false)
04285     {
04286       if (atom[l_path[pl_prev] - 1].metal)
04287        {
04288 /* p2c: checkmol.pas, line 2538:
04289  * Note: Turbo Pascal conditional compilation directive was ignored [218] */
04290          return false;
04291        }
04292     }
04293   /* check if ring is already closed */
04294   if (pl > 2 && l_path[pl_prev] == l_path[0])
04295     {
04296       l_path[pl_prev] = 0;  /* remove last entry (redundant!) */
04297       order_ringpath (l_path);
04298       if (is_newring (l_path))
04299        {
04300          if (n_rings >= max_rings)
04301            {
04302 /* p2c: checkmol.pas, line 2554:
04303  * Note: Turbo Pascal conditional compilation directive was ignored [218] */
04304 
04305              return false;
04306            }
04307          add_ring (l_path);
04308        }
04309 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
04310       return true;
04311     }
04312   /* any other case: ring is not (yet) closed */
04313   a_last = l_path[pl_prev];
04314   get_neighbors (nb, a_last);
04315   if (atom[a_last - 1].neighbor_count <= 1)
04316     return false;
04317   if (n_rings >= max_rings)
04318     /* added in v0.2: check if max_rings is reached */
04319     {                       /* if ring is not closed, continue searching */
04320       return false;
04321     }
04322   FORLIM = atom[a_last - 1].neighbor_count;
04323   pl_next = pl + 1;
04324   max_ringsize_dec = max_ringsize - 1;
04325   for (i = 0; i < FORLIM; i++)
04326     {
04327       new_atom = true;
04328       for (j = 1; j < pl; j++)
04329        {
04330          if (nb[i] == l_path[j])
04331            {
04332              new_atom = false;
04333              break;
04334            }
04335        }
04336       /* added in v0.1a: check if max_rings not yet reached */
04337       /* added in v0.2:  limit ring size to max_vringsize instead of max_ringsize */
04338       if (new_atom && pl < max_vringsize && n_rings < max_rings)
04339        {
04340          l_path[pl] = nb[i];
04341          if (pl < max_ringsize_dec)       /* just to be sure */
04342            l_path[pl_next] = 0;
04343 
04344          if (max_ringpath_recursion_depth != 0
04345              && ++recursion_depth > max_ringpath_recursion_depth)
04346            {
04347 #ifndef MAKE_SHARED_LIBRARY
04348              if (opt_verbose)
04349 #endif
04350               printf
04351                 ("Warning: max. number of ringpath recursions (%i) reached\n",
04352                  max_ringpath_recursion_depth);
04353              n_rings = max_rings;
04354              return false;
04355            }
04356 
04357          //printf("%i\n",recursion_depth);
04358          //fflush(stdout);
04359 
04360          if (is_ringpath (l_path))
04361            rp = true;
04362          //return true;
04363        }
04364     }
04365   return rp;
04366 }
04367 
04368 static boolean
04369 is_ringbond (int b_id)
04370 {
04371   int i, ra1, ra2;
04372   neighbor_rec nb;
04373   ringpath_type search_path;
04374   boolean rb = false;
04375   int FORLIM;
04376 
04377   recursion_depth = 0;
04378 
04379   ra1 = bond[b_id - 1].a1;
04380   ra2 = bond[b_id - 1].a2;
04381   memset (nb, 0, sizeof (neighbor_rec));
04382   memset (search_path, 0, sizeof (ringpath_type));
04383   get_neighbors (nb, ra2);
04384   if (atom[ra2 - 1].neighbor_count <= 1 || atom[ra1 - 1].neighbor_count <= 1)
04385     return false;
04386   search_path[0] = ra1;
04387   search_path[1] = ra2;
04388   FORLIM = atom[ra2 - 1].neighbor_count;
04389   for (i = 0; i < FORLIM; i++)
04390     {
04391       if (nb[i] != ra1 && atom[nb[i] - 1].heavy)
04392        {
04393          search_path[2] = nb[i];
04394          if (is_ringpath (search_path))
04395            rb = true;
04396          //return true;
04397        }
04398     }
04399   return rb;
04400 }
04401 
04402 
04403 static void
04404 chk_ringbonds ()
04405 {
04406   int i, a1rc, a2rc;
04407 
04408   if (n_bonds < 1)
04409     return;
04410 
04411   for (i = 0; i < n_bonds; i++)
04412     {
04413       a1rc = atom[bond[i].a1 - 1].ring_count;
04414       a2rc = atom[bond[i].a2 - 1].ring_count;
04415       if (n_rings == 0 || a1rc < n_rings && a2rc < n_rings)
04416        {
04417          is_ringbond (i + 1);
04418          /*inc(bond^[i].ring_count); */
04419        }
04420     }
04421 }
04422 
04423 
04424 /* v0.3d: moved procedure update_ringcount a bit down */
04425 
04426 
04427 static int
04428 raw_hetbond_count (int a)
04429 {
04430   /* new in v0.2j, ignores bond order */
04431   int i;
04432   neighbor_rec nb;
04433   str2 nb_el;
04434   int hbc = 0;
04435   int FORLIM;
04436 
04437   if (a <= 0 || a > n_atoms)
04438     return hbc;
04439   memset (nb, 0, sizeof (neighbor_rec));
04440   get_neighbors (nb, a);
04441   if (atom[a - 1].neighbor_count <= 0)
04442     return hbc;
04443   FORLIM = atom[a - 1].neighbor_count;
04444   for (i = 0; i < FORLIM; i++)
04445     {
04446       strcpy (nb_el, atom[nb[i] - 1].element);
04447       if (strcmp (nb_el, "C ") && strcmp (nb_el, "A ") && strcmp (nb_el, "H ")      /* &&  strcmp (nb_el, "D ") */
04448          && strcmp (nb_el, "LP") && strcmp (nb_el, "DU"))
04449        /* added 'D ' in v0.3n */
04450        hbc++;
04451     }
04452   return hbc;
04453 }
04454 
04455 
04456 static int
04457 hetbond_count (int a)
04458 {
04459   int i;
04460   neighbor_rec nb;
04461   str2 nb_el;
04462   float hbc = 0.0;
04463   int FORLIM;
04464 
04465   if (a <= 0 || a > n_atoms)
04466     return ((int) floor (hbc + 0.5));
04467   memset (nb, 0, sizeof (neighbor_rec));
04468   get_neighbors (nb, a);
04469   if (atom[a - 1].neighbor_count <= 0)
04470     return ((int) floor (hbc + 0.5));
04471   FORLIM = atom[a - 1].neighbor_count;
04472   for (i = 0; i < FORLIM; i++)
04473     {
04474       strcpy (nb_el, atom[nb[i] - 1].element);
04475       if (strcmp (nb_el, "C ") && strcmp (nb_el, "A ") && strcmp (nb_el, "H ")      /*&& strcmp (nb_el, "D ") */
04476          && strcmp (nb_el, "LP") && strcmp (nb_el, "DU"))
04477        {                    /* added 'D ' in v0.3n */
04478          if (bond[get_bond (a, nb[i]) - 1].btype == 'S')
04479            hbc += 1.0;
04480          if (bond[get_bond (a, nb[i]) - 1].btype == 'A')
04481            hbc += 1.5;
04482          if (bond[get_bond (a, nb[i]) - 1].btype == 'D')
04483            hbc += 2.0;
04484          if (bond[get_bond (a, nb[i]) - 1].btype == 'T')
04485            hbc += 3.0;
04486        }
04487     }
04488   return ((int) floor (hbc + 0.5));
04489 }
04490 
04491 
04492 static int
04493 hetatom_count (int a)
04494 {
04495   int i;
04496   neighbor_rec nb;
04497   str2 nb_el;
04498   int hac = 0;
04499   int FORLIM;
04500 
04501   if (a <= 0 || a > n_atoms)
04502     return hac;
04503   memset (nb, 0, sizeof (neighbor_rec));
04504   get_neighbors (nb, a);
04505   if (atom[a - 1].neighbor_count <= 0)
04506     return hac;
04507   FORLIM = atom[a - 1].neighbor_count;
04508   for (i = 0; i < FORLIM; i++)
04509     {
04510       strcpy (nb_el, atom[nb[i] - 1].element);
04511       if (strcmp (nb_el, "C ") && strcmp (nb_el, "H ")
04512          /*&&  strcmp (nb_el, "D ") */  && strcmp (nb_el, "LP")
04513          && strcmp (nb_el, "DU"))
04514        /* added 'D ' in v0.3n */
04515        hac++;
04516     }
04517   return hac;
04518 }
04519 
04520 
04521 static int
04522 ndl_hetbond_count (int a)
04523 {
04524   int i;
04525   neighbor_rec nb;
04526   str2 nb_el;
04527   float hbc = 0.0;
04528   int FORLIM;
04529 
04530   if (a <= 0 || a > n_atoms)
04531     return ((int) floor (hbc + 0.5));
04532   memset (nb, 0, sizeof (neighbor_rec));
04533   get_ndl_neighbors (nb, a);
04534   if (ndl_atom[a - 1].neighbor_count <= 0)
04535     return ((int) floor (hbc + 0.5));
04536   FORLIM = ndl_atom[a - 1].neighbor_count;
04537   for (i = 0; i < FORLIM; i++)
04538     {
04539       strcpy (nb_el, ndl_atom[nb[i] - 1].element);
04540       if (strcmp (nb_el, "C ") && strcmp (nb_el, "H ")
04541          /*&&  strcmp (nb_el, "D ") */  && strcmp (nb_el, "LP")
04542          && strcmp (nb_el, "DU"))
04543        {                    /* added 'D ' in v0.3n */
04544          if (ndl_bond[get_ndl_bond (a, nb[i]) - 1].btype == 'S')
04545            hbc += 1.0;
04546          if (ndl_bond[get_ndl_bond (a, nb[i]) - 1].btype == 'A')
04547            hbc += 1.5;
04548          if (ndl_bond[get_ndl_bond (a, nb[i]) - 1].btype == 'D')
04549            hbc += 2.0;
04550          if (ndl_bond[get_ndl_bond (a, nb[i]) - 1].btype == 'T')
04551            hbc += 3.0;
04552        }
04553     }
04554   return ((int) floor (hbc + 0.5));
04555 }
04556 
04557 
04558 static int
04559 ndl_hetatom_count (int a)
04560 {
04561   int i;
04562   neighbor_rec nb;
04563   str2 nb_el;
04564   int hac = 0;
04565   int FORLIM;
04566 
04567   if (a <= 0 || a > ndl_n_atoms)
04568     return hac;
04569   memset (nb, 0, sizeof (neighbor_rec));
04570   get_ndl_neighbors (nb, a);
04571   if (ndl_atom[a - 1].neighbor_count <= 0)
04572     return hac;
04573   FORLIM = ndl_atom[a - 1].neighbor_count;
04574   for (i = 0; i < FORLIM; i++)
04575     {                       /* note: query atoms like 'A' should be present only in the needle */
04576       strcpy (nb_el, ndl_atom[nb[i] - 1].element);
04577       if (strcmp (nb_el, "C ") && strcmp (nb_el, "A ") && strcmp (nb_el, "H ")      /*&&  strcmp (nb_el, "D ") */
04578          && strcmp (nb_el, "LP") && strcmp (nb_el, "DU"))
04579        /* added 'D ' in v0.3n */
04580        hac++;
04581     }
04582   return hac;
04583 }
04584 
04585 
04586 static boolean
04587 is_oxo_C (int id)
04588 {
04589   boolean Result;
04590   int i;
04591   boolean r = false;
04592   neighbor_rec nb;
04593   int FORLIM;
04594 
04595   memset (nb, 0, sizeof (neighbor_rec));
04596   if (id < 1 || id > n_atoms)
04597     return Result;
04598   get_neighbors (nb, id);
04599   if (strcmp (atom[id - 1].element, "C ") || atom[id - 1].neighbor_count <= 0)
04600     return false;
04601   FORLIM = atom[id - 1].neighbor_count;
04602   for (i = 0; i < FORLIM; i++)
04603     {
04604       if (bond[get_bond (id, nb[i]) - 1].btype == 'D' &&
04605          !strcmp (atom[nb[i] - 1].element, "O "))
04606        /* no N, amidines are different... */
04607        r = true;
04608       /* or
04609          (atom^[(nb[i])].element = 'S ')  or
04610          (atom^[(nb[i])].element = 'SE') */
04611     }
04612   return r;
04613 }
04614 
04615 
04616 static boolean
04617 is_thioxo_C (int id)
04618 {
04619   boolean Result;
04620   int i;
04621   boolean r = false;
04622   neighbor_rec nb;
04623   int FORLIM;
04624 
04625   memset (nb, 0, sizeof (neighbor_rec));
04626   if (id < 1 || id > n_atoms)
04627     return Result;
04628   get_neighbors (nb, id);
04629   if (strcmp (atom[id - 1].element, "C ") || atom[id - 1].neighbor_count <= 0)
04630     return false;
04631   FORLIM = atom[id - 1].neighbor_count;
04632   for (i = 0; i < FORLIM; i++)
04633     {
04634       if (bond[get_bond (id, nb[i]) - 1].btype == 'D' &&
04635          (!strcmp (atom[nb[i] - 1].element, "S ") ||
04636           !strcmp (atom[nb[i] - 1].element, "SE")))
04637        /* no N, amidines are different... */
04638        r = true;
04639     }
04640   return r;
04641 }
04642 
04643 
04644 static boolean
04645 is_imino_C (int id)
04646 {
04647   boolean Result;
04648   int i;
04649   boolean r = false;
04650   neighbor_rec nb;
04651   int FORLIM;
04652 
04653   memset (nb, 0, sizeof (neighbor_rec));
04654   if (id < 1 || id > n_atoms)
04655     return Result;
04656   get_neighbors (nb, id);
04657   if (strcmp (atom[id - 1].element, "C ") || atom[id - 1].neighbor_count <= 0)
04658     return false;
04659   FORLIM = atom[id - 1].neighbor_count;
04660   for (i = 0; i < FORLIM; i++)
04661     {
04662       if (bond[get_bond (id, nb[i]) - 1].btype == 'D' &&
04663          !strcmp (atom[nb[i] - 1].element, "N "))
04664        r = true;
04665     }
04666   return r;
04667 }
04668 
04669 
04670 static boolean
04671 is_true_imino_C (int id)
04672 {
04673   boolean Result;
04674   int i;
04675   boolean r = true;
04676   neighbor_rec nb;
04677   str2 nb_el;
04678   int a_n = 0;
04679   int b;                    /* v0.3j */
04680   int FORLIM;
04681 
04682 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
04683   memset (nb, 0, sizeof (neighbor_rec));
04684   if (id < 1 || id > n_atoms)
04685     return Result;
04686   get_neighbors (nb, id);
04687   if (strcmp (atom[id - 1].element, "C ") || atom[id - 1].neighbor_count <= 0)
04688     return false;
04689   FORLIM = atom[id - 1].neighbor_count;
04690   for (i = 0; i < FORLIM; i++)
04691     {
04692       b = get_bond (id, nb[i]);    /* v0.3j */
04693       if (bond[b - 1].btype == 'D' && bond[b - 1].arom == false &&
04694          !strcmp (atom[nb[i] - 1].element, "N "))
04695        /* v0.3j */
04696        a_n = nb[i];
04697     }
04698   if (a_n <= 0)
04699     return false;
04700   memset (nb, 0, sizeof (neighbor_rec));
04701   get_neighbors (nb, a_n);
04702   FORLIM = atom[a_n - 1].neighbor_count;
04703   for (i = 0; i < FORLIM; i++)
04704     {
04705       strcpy (nb_el, atom[nb[i] - 1].element);
04706       if (strcmp (nb_el, "C ") && strcmp (nb_el, "H ")
04707          /*&&  strcmp (nb_el, "D ") */ )
04708        /* v0.3n: D */
04709        r = false;
04710     }
04711   return r;
04712 }
04713 
04714 
04715 static boolean
04716 is_true_exocyclic_imino_C (int id, int r_id)
04717 {
04718   /* v0.3j */
04719   boolean Result;
04720   int i, j;
04721   boolean r = false;
04722   neighbor_rec nb;
04723   ringpath_type testring;
04724   int ring_size, b, FORLIM;
04725 
04726   memset (nb, 0, sizeof (neighbor_rec));
04727   if (id < 1 || id > n_atoms)
04728     return Result;
04729   get_neighbors (nb, id);
04730   memset (testring, 0, sizeof (ringpath_type));
04731   ring_size = ringprop[r_id - 1].size;    /* v0.3j */
04732   for (j = 0; j < ring_size; j++)  /* v0.3j */
04733     testring[j] = ring[r_id - 1][j];
04734   if (strcmp (atom[id - 1].element, "C ") || atom[id - 1].neighbor_count <= 0)
04735     return false;
04736   FORLIM = atom[id - 1].neighbor_count;
04737   for (i = 0; i < FORLIM; i++)
04738     {
04739       b = get_bond (id, nb[i]);
04740       if (bond[b - 1].btype == 'D' && bond[b - 1].arom == false &&
04741          !strcmp (atom[nb[i] - 1].element, "N "))
04742        {
04743          r = true;
04744          for (j = 0; j < ring_size; j++)
04745            {
04746              if (nb[i] == ring[r_id - 1][j])
04747               r = false;
04748            }
04749        }
04750     }
04751   return r;
04752 }
04753 
04754 
04755 static boolean
04756 is_exocyclic_imino_C (int id, int r_id)
04757 {
04758   boolean Result;
04759   int i, j;
04760   boolean r = false;
04761   neighbor_rec nb;
04762   ringpath_type testring;
04763   int ring_size, FORLIM;
04764 
04765   memset (nb, 0, sizeof (neighbor_rec));
04766   if (id < 1 || id > n_atoms)
04767     return Result;
04768   get_neighbors (nb, id);
04769   memset (testring, 0, sizeof (ringpath_type));
04770   ring_size = ringprop[r_id - 1].size;    /* v0.3j */
04771   for (j = 0; j < ring_size; j++)  /* v0.3j */
04772     testring[j] = ring[r_id - 1][j];
04773   if (strcmp (atom[id - 1].element, "C ") || atom[id - 1].neighbor_count <= 0)
04774     return false;
04775   FORLIM = atom[id - 1].neighbor_count;
04776   for (i = 0; i < FORLIM; i++)
04777     {
04778       if (bond[get_bond (id, nb[i]) - 1].btype == 'D' &&
04779          !strcmp (atom[nb[i] - 1].element, "N "))
04780        {
04781          r = true;
04782          for (j = 0; j < ring_size; j++)
04783            {
04784              if (nb[i] == ring[r_id - 1][j])
04785               r = false;
04786            }
04787        }
04788     }
04789   return r;
04790 }
04791 
04792 
04793 static int
04794 find_exocyclic_methylene_C (int id, int r_id)
04795 {
04796   /* renamed and rewritten in v0.3j */
04797   int i, j;
04798   int r = 0;
04799   neighbor_rec nb;
04800   ringpath_type testring;
04801   int ring_size, FORLIM;
04802 
04803   memset (nb, 0, sizeof (neighbor_rec));
04804   if (id < 1 || id > n_atoms)
04805     return 0;
04806   get_neighbors (nb, id);
04807   memset (testring, 0, sizeof (ringpath_type));
04808   ring_size = ringprop[r_id - 1].size;    /* v0.3j */
04809   for (j = 0; j < ring_size; j++)  /* v0.3j */
04810     testring[j] = ring[r_id - 1][j];
04811   if (strcmp (atom[id - 1].element, "C ") || atom[id - 1].neighbor_count <= 0)
04812     return r;
04813   FORLIM = atom[id - 1].neighbor_count;
04814   for (i = 0; i < FORLIM; i++)
04815     {
04816       if (bond[get_bond (id, nb[i]) - 1].btype == 'D' &&
04817          !strcmp (atom[nb[i] - 1].element, "C "))
04818        {
04819          r = nb[i];
04820          for (j = 0; j < ring_size; j++)
04821            {
04822              if (nb[i] == ring[r_id - 1][j])
04823               r = 0;
04824            }
04825        }
04826     }
04827   return r;
04828 }
04829 
04830 
04831 static boolean
04832 is_hydroxy (int a_view, int a_ref)
04833 {
04834   boolean r = false;
04835 
04836   if (atom[a_view - 1].
04837       heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S'))
04838     {
04839       if (!strcmp (atom[a_ref - 1].atype, "O3 ") &&
04840          atom[a_ref - 1].neighbor_count == 1)
04841        r = true;
04842     }
04843   return r;
04844 }
04845 
04846 
04847 static boolean
04848 is_sulfanyl (int a_view, int a_ref)
04849 {
04850   boolean r = false;
04851 
04852   if (atom[a_view - 1].
04853       heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S'))
04854     {
04855       if (!strcmp (atom[a_ref - 1].atype, "S3 ") &&
04856          atom[a_ref - 1].neighbor_count == 1)
04857        r = true;
04858     }
04859   return r;
04860 }
04861 
04862 
04863 static boolean
04864 is_amino (int a_view, int a_ref)
04865 {
04866   boolean r = false;
04867 
04868   if (atom[a_view - 1].
04869       heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S'))
04870     {
04871       if ((!strcmp (atom[a_ref - 1].atype, "N3 ") ||
04872           !strcmp (atom[a_ref - 1].atype, "N3+")) &&
04873          atom[a_ref - 1].neighbor_count == 1)
04874        r = true;
04875     }
04876   return r;
04877 }
04878 
04879 
04880 static boolean
04881 is_alkyl (int a_view, int a_ref)
04882 {
04883   int i;
04884   boolean r = false;
04885   neighbor_rec nb;
04886   str2 nb_el;
04887   int het_count = 0;
04888   int FORLIM;
04889 
04890   memset (nb, 0, sizeof (neighbor_rec));
04891   if (!
04892       (atom[a_view - 1].
04893        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S'))
04894       || strcmp (atom[a_ref - 1].atype, "C3 ")
04895       || atom[a_ref - 1].arom != false)
04896     return false;
04897   get_nextneighbors (nb, a_ref, a_view);
04898   FORLIM = atom[a_ref - 1].neighbor_count - 2;
04899   for (i = 0; i <= FORLIM; i++)
04900     {
04901       strcpy (nb_el, atom[nb[i] - 1].element);
04902       if (strcmp (nb_el, "C ") && strcmp (nb_el, "H ")
04903          /*&&  strcmp (nb_el, "D ") */  && strcmp (nb_el, "DU")
04904          && strcmp (nb_el, "LP"))
04905        /* added 'D ' in v0.3n */
04906        het_count++;
04907     }
04908   if (het_count <= 1)              /* we consider (e.g.) alkoxyalkyl groups as alkyl */
04909     r = true;
04910   return r;
04911 }
04912 
04913 
04914 static boolean
04915 is_true_alkyl (int a_view, int a_ref)
04916 {
04917   int i;
04918   boolean r = false;
04919   neighbor_rec nb;
04920   str2 nb_el;
04921   int het_count = 0;
04922   int FORLIM;
04923 
04924   memset (nb, 0, sizeof (neighbor_rec));
04925   if (!
04926       (atom[a_view - 1].
04927        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S'))
04928       || strcmp (atom[a_ref - 1].atype, "C3 ")
04929       || atom[a_ref - 1].arom != false)
04930     return false;
04931   get_nextneighbors (nb, a_ref, a_view);
04932   FORLIM = atom[a_ref - 1].neighbor_count - 2;
04933   for (i = 0; i <= FORLIM; i++)
04934     {
04935       strcpy (nb_el, atom[nb[i] - 1].element);
04936       if (strcmp (nb_el, "C ") && strcmp (nb_el, "H ")
04937          /*&&  strcmp (nb_el, "D ") */  && strcmp (nb_el, "DU"))
04938        /* added 'D ' in v0.3n */
04939        het_count++;
04940     }
04941   if (het_count == 0)              /* */
04942     r = true;
04943   return r;
04944 }
04945 
04946 
04947 static boolean
04948 is_alkenyl (int a_view, int a_ref)
04949 {
04950   /* new in v0.3j */
04951   int i;
04952   boolean r = false;
04953   neighbor_rec nb;
04954   str2 nb_el;
04955   str3 nb_at;
04956   int c2_count = 0, het_count = 0;
04957   int FORLIM;
04958 
04959   memset (nb, 0, sizeof (neighbor_rec));
04960   if (!
04961       (atom[a_view - 1].
04962        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S'))
04963       || strcmp (atom[a_ref - 1].atype, "C2 ")
04964       || atom[a_ref - 1].arom != false)
04965     {
04966       return false;
04967     }                       /* v0.3k: changed c2_count = 1 into c2_count >= 1 */
04968   get_nextneighbors (nb, a_ref, a_view);
04969   FORLIM = atom[a_ref - 1].neighbor_count - 2;
04970   for (i = 0; i <= FORLIM; i++)
04971     {
04972       strcpy (nb_el, atom[nb[i] - 1].element);
04973       strcpy (nb_at, atom[nb[i] - 1].atype);
04974       if (strcmp (nb_el, "C ") && strcmp (nb_el, "H ")
04975          /*&&  strcmp (nb_el, "D ") */  && strcmp (nb_el, "DU")
04976          && strcmp (nb_el, "LP"))
04977        /* added 'D ' in v0.3n */
04978        het_count++;
04979       if (!strcmp (nb_at, "C2 "))
04980        c2_count++;
04981     }
04982   if (c2_count >= 1 && het_count <= 1)
04983     /* we consider (e.g.) alkoxyalkenyl groups as alkenyl */
04984     r = true;
04985   return r;
04986 }
04987 
04988 
04989 static boolean
04990 is_alkynyl (int a_view, int a_ref)
04991 {
04992   /* new in v0.3j */
04993   int i;
04994   boolean r = false;
04995   neighbor_rec nb;
04996   str3 nb_at;
04997   int c1_count = 0;
04998   int FORLIM;
04999 
05000   memset (nb, 0, sizeof (neighbor_rec));
05001   if (!
05002       (atom[a_view - 1].
05003        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S'))
05004       || strcmp (atom[a_ref - 1].atype, "C1 ")
05005       || atom[a_ref - 1].arom != false)
05006     return false;
05007   get_nextneighbors (nb, a_ref, a_view);
05008   FORLIM = atom[a_ref - 1].neighbor_count - 2;
05009   for (i = 0; i <= FORLIM; i++)
05010     {
05011       strcpy (nb_at, atom[nb[i] - 1].atype);
05012       if (!strcmp (nb_at, "C1 "))
05013        c1_count++;
05014     }
05015   if (c1_count == 1)
05016     r = true;
05017   return r;
05018 }
05019 
05020 
05021 static boolean
05022 is_aryl (int a_view, int a_ref)
05023 {
05024   boolean r = false;
05025 
05026   if ((atom[a_view - 1].
05027        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S'))
05028       && !strcmp (atom[a_ref - 1].element, "C ")
05029       && atom[a_ref - 1].arom == true)
05030     r = true;
05031   return r;
05032 }
05033 
05034 
05035 static boolean
05036 is_alkoxy (int a_view, int a_ref)
05037 {
05038   boolean r = false;
05039   neighbor_rec nb;
05040 
05041   memset (nb, 0, sizeof (neighbor_rec));
05042   if (!
05043       (atom[a_view - 1].
05044        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05045     return false;
05046   if (strcmp (atom[a_ref - 1].atype, "O3 ")
05047       || atom[a_ref - 1].neighbor_count != 2)
05048     return false;
05049   get_nextneighbors (nb, a_ref, a_view);
05050   if (is_alkyl (a_ref, nb[0]))
05051     r = true;
05052   return r;
05053 }
05054 
05055 
05056 static boolean
05057 is_siloxy (int a_view, int a_ref)
05058 {
05059   boolean r = false;
05060   neighbor_rec nb;
05061 
05062   memset (nb, 0, sizeof (neighbor_rec));
05063   if (!
05064       (atom[a_view - 1].
05065        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05066     return false;
05067   if (strcmp (atom[a_ref - 1].atype, "O3 ")
05068       || atom[a_ref - 1].neighbor_count != 2)
05069     return false;
05070   get_nextneighbors (nb, a_ref, a_view);
05071   if (!strcmp (atom[nb[0] - 1].element, "SI"))
05072     r = true;
05073   return r;
05074 }
05075 
05076 
05077 static boolean
05078 is_true_alkoxy (int a_view, int a_ref)
05079 {
05080   boolean r = false;
05081   neighbor_rec nb;
05082 
05083   memset (nb, 0, sizeof (neighbor_rec));
05084   if (!
05085       (atom[a_view - 1].
05086        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05087     return false;
05088   if (strcmp (atom[a_ref - 1].atype, "O3 ")
05089       || atom[a_ref - 1].neighbor_count != 2)
05090     return false;
05091   get_nextneighbors (nb, a_ref, a_view);
05092   if (is_true_alkyl (a_ref, nb[0]))
05093     r = true;
05094   return r;
05095 }
05096 
05097 
05098 static boolean
05099 is_aryloxy (int a_view, int a_ref)
05100 {
05101   boolean r = false;
05102   neighbor_rec nb;
05103 
05104   memset (nb, 0, sizeof (neighbor_rec));
05105   if (!
05106       (atom[a_view - 1].
05107        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05108     return false;
05109   if (strcmp (atom[a_ref - 1].atype, "O3 ")
05110       || atom[a_ref - 1].neighbor_count != 2)
05111     return false;
05112   get_nextneighbors (nb, a_ref, a_view);
05113   if (is_aryl (a_ref, nb[0]))
05114     r = true;
05115   return r;
05116 }
05117 
05118 
05119 static boolean
05120 is_alkenyloxy (int a_view, int a_ref)
05121 {
05122   /* v0.3j */
05123   boolean r = false;
05124   neighbor_rec nb;
05125 
05126   memset (nb, 0, sizeof (neighbor_rec));
05127   if (!
05128       (atom[a_view - 1].
05129        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05130     return false;
05131   if (strcmp (atom[a_ref - 1].atype, "O3 ")
05132       || atom[a_ref - 1].neighbor_count != 2)
05133     return false;
05134   get_nextneighbors (nb, a_ref, a_view);
05135   if (is_alkenyl (a_ref, nb[0]))
05136     r = true;
05137   return r;
05138 }
05139 
05140 
05141 static boolean
05142 is_alkynyloxy (int a_view, int a_ref)
05143 {
05144   /* v0.3j */
05145   boolean r = false;
05146   neighbor_rec nb;
05147 
05148   memset (nb, 0, sizeof (neighbor_rec));
05149   if (!
05150       (atom[a_view - 1].
05151        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05152     return false;
05153   if (strcmp (atom[a_ref - 1].atype, "O3 ")
05154       || atom[a_ref - 1].neighbor_count != 2)
05155     return false;
05156   get_nextneighbors (nb, a_ref, a_view);
05157   if (is_alkynyl (a_ref, nb[0]))
05158     r = true;
05159   return r;
05160 }
05161 
05162 
05163 static boolean
05164 is_alkylsulfanyl (int a_view, int a_ref)
05165 {
05166   boolean r = false;
05167   neighbor_rec nb;
05168 
05169   memset (nb, 0, sizeof (neighbor_rec));
05170   if (!
05171       (atom[a_view - 1].
05172        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05173     return false;
05174   if (strcmp (atom[a_ref - 1].atype, "S3 ")
05175       || atom[a_ref - 1].neighbor_count != 2)
05176     return false;
05177   get_nextneighbors (nb, a_ref, a_view);
05178   if (is_alkyl (a_ref, nb[0]))
05179     r = true;
05180   return r;
05181 }
05182 
05183 
05184 static boolean
05185 is_true_alkylsulfanyl (int a_view, int a_ref)
05186 {
05187   boolean r = false;
05188   neighbor_rec nb;
05189 
05190   memset (nb, 0, sizeof (neighbor_rec));
05191   if (!
05192       (atom[a_view - 1].
05193        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05194     return false;
05195   if (strcmp (atom[a_ref - 1].atype, "S3 ")
05196       || atom[a_ref - 1].neighbor_count != 2)
05197     return false;
05198   get_nextneighbors (nb, a_ref, a_view);
05199   if (is_true_alkyl (a_ref, nb[0]))
05200     r = true;
05201   return r;
05202 }
05203 
05204 
05205 static boolean
05206 is_arylsulfanyl (int a_view, int a_ref)
05207 {
05208   boolean r = false;
05209   neighbor_rec nb;
05210 
05211   memset (nb, 0, sizeof (neighbor_rec));
05212   if (!
05213       (atom[a_view - 1].
05214        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05215     return false;
05216   if (strcmp (atom[a_ref - 1].atype, "S3 ")
05217       || atom[a_ref - 1].neighbor_count != 2)
05218     return false;
05219   get_nextneighbors (nb, a_ref, a_view);
05220   if (is_aryl (a_ref, nb[0]))
05221     r = true;
05222   return r;
05223 }
05224 
05225 
05226 static boolean
05227 is_alkenylsulfanyl (a_view, a_ref)
05228      int a_view, a_ref;
05229 {
05230   /* v0.3j */
05231   boolean r = false;
05232   neighbor_rec nb;
05233 
05234   memset (nb, 0, sizeof (neighbor_rec));
05235   if (!
05236       (atom[a_view - 1].
05237        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05238     return false;
05239   if (strcmp (atom[a_ref - 1].atype, "S3 ")
05240       || atom[a_ref - 1].neighbor_count != 2)
05241     return false;
05242   get_nextneighbors (nb, a_ref, a_view);
05243   if (is_alkenyl (a_ref, nb[0]))
05244     r = true;
05245   return r;
05246 }
05247 
05248 
05249 static boolean
05250 is_alkynylsulfanyl (a_view, a_ref)
05251      int a_view, a_ref;
05252 {
05253   /* v0.3j */
05254   boolean r = false;
05255   neighbor_rec nb;
05256 
05257   memset (nb, 0, sizeof (neighbor_rec));
05258   if (!
05259       (atom[a_view - 1].
05260        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05261     return false;
05262   if (strcmp (atom[a_ref - 1].atype, "S3 ")
05263       || atom[a_ref - 1].neighbor_count != 2)
05264     return false;
05265   get_nextneighbors (nb, a_ref, a_view);
05266   if (is_alkynyl (a_ref, nb[0]))
05267     r = true;
05268   return r;
05269 }
05270 
05271 
05272 static boolean
05273 is_alkylamino (a_view, a_ref)
05274      int a_view, a_ref;
05275 {
05276   boolean r = false;
05277   neighbor_rec nb;
05278   int alkyl_count = 0;
05279 
05280   memset (nb, 0, sizeof (neighbor_rec));
05281   if (!
05282       (atom[a_view - 1].
05283        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05284     return false;
05285   if (strcmp (atom[a_ref - 1].element, "N ")
05286       || atom[a_ref - 1].neighbor_count != 2)
05287     return false;
05288   get_nextneighbors (nb, a_ref, a_view);
05289   if (is_alkyl (a_ref, nb[0]))
05290     alkyl_count++;
05291   if (alkyl_count == 1)
05292     r = true;
05293   return r;
05294 }
05295 
05296 
05297 static boolean
05298 is_dialkylamino (a_view, a_ref)
05299      int a_view, a_ref;
05300 {
05301   int i;
05302   boolean r = false;
05303   neighbor_rec nb;
05304   int alkyl_count = 0;
05305 
05306   memset (nb, 0, sizeof (neighbor_rec));
05307   if (!
05308       (atom[a_view - 1].
05309        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05310     return false;
05311   if (strcmp (atom[a_ref - 1].element, "N ")
05312       || atom[a_ref - 1].neighbor_count != 3)
05313     return false;
05314   get_nextneighbors (nb, a_ref, a_view);
05315   for (i = 0; i <= 1; i++)
05316     {
05317       if (is_alkyl (a_ref, nb[i]))
05318        alkyl_count++;
05319     }
05320   if (alkyl_count == 2)
05321     r = true;
05322   return r;
05323 }
05324 
05325 
05326 static boolean
05327 is_arylamino (a_view, a_ref)
05328      int a_view, a_ref;
05329 {
05330   boolean r = false;
05331   neighbor_rec nb;
05332   int aryl_count = 0;
05333 
05334   memset (nb, 0, sizeof (neighbor_rec));
05335   if (!
05336       (atom[a_view - 1].
05337        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05338     return false;
05339   if (strcmp (atom[a_ref - 1].element, "N ")
05340       || atom[a_ref - 1].neighbor_count != 2)
05341     return false;
05342   get_nextneighbors (nb, a_ref, a_view);
05343   if (is_aryl (a_ref, nb[0]))
05344     aryl_count++;
05345   if (aryl_count == 1)
05346     r = true;
05347   return r;
05348 }
05349 
05350 
05351 static boolean
05352 is_diarylamino (a_view, a_ref)
05353      int a_view, a_ref;
05354 {
05355   int i;
05356   boolean r = false;
05357   neighbor_rec nb;
05358   int aryl_count = 0;
05359 
05360   memset (nb, 0, sizeof (neighbor_rec));
05361   if (!
05362       (atom[a_view - 1].
05363        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05364     return false;
05365   if (strcmp (atom[a_ref - 1].element, "N ")
05366       || atom[a_ref - 1].neighbor_count != 3)
05367     return false;
05368   get_nextneighbors (nb, a_ref, a_view);
05369   for (i = 0; i <= 1; i++)
05370     {
05371       if (is_aryl (a_ref, nb[i]))
05372        aryl_count++;
05373     }
05374   if (aryl_count == 2)
05375     r = true;
05376   return r;
05377 }
05378 
05379 
05380 static boolean
05381 is_alkylarylamino (a_view, a_ref)
05382      int a_view, a_ref;
05383 {
05384   int i;
05385   boolean r = false;
05386   neighbor_rec nb;
05387   int alkyl_count = 0, aryl_count = 0;
05388 
05389   memset (nb, 0, sizeof (neighbor_rec));
05390   if (!
05391       (atom[a_view - 1].
05392        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05393     return false;
05394   if (strcmp (atom[a_ref - 1].element, "N ")
05395       || atom[a_ref - 1].neighbor_count != 3)
05396     return false;
05397   get_nextneighbors (nb, a_ref, a_view);
05398   for (i = 0; i <= 1; i++)
05399     {
05400       if (is_alkyl (a_ref, nb[i]))
05401        alkyl_count++;
05402       if (is_aryl (a_ref, nb[i]))
05403        aryl_count++;
05404     }
05405   if (alkyl_count == 1 && aryl_count == 1)
05406     r = true;
05407   return r;
05408 }
05409 
05410 
05411 static boolean
05412 is_C_monosubst_amino (a_view, a_ref)
05413      int a_view, a_ref;
05414 {
05415   /* new in v0.3j */
05416   boolean r = false;
05417   neighbor_rec nb;
05418   int c_count = 0;
05419 
05420   memset (nb, 0, sizeof (neighbor_rec));
05421   if (!
05422       (atom[a_view - 1].
05423        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05424     return false;
05425   if (strcmp (atom[a_ref - 1].atype, "N3 ")
05426       && strcmp (atom[a_ref - 1].atype, "NAM")
05427       || atom[a_ref - 1].neighbor_count != 2)
05428     return false;
05429   get_nextneighbors (nb, a_ref, a_view);
05430   if (!strcmp (atom[nb[0] - 1].element, "C "))
05431     c_count++;
05432   if (c_count == 1)
05433     r = true;
05434   return r;
05435 }
05436 
05437 
05438 static boolean
05439 is_C_disubst_amino (a_view, a_ref)
05440      int a_view, a_ref;
05441 {
05442   /* new in v0.3j */
05443   int i;
05444   boolean r = false;
05445   neighbor_rec nb;
05446   int b;
05447   int c_count = 0;
05448 
05449   b = get_bond (a_view, a_ref);
05450   memset (nb, 0, sizeof (neighbor_rec));
05451   if (!(atom[a_view - 1].heavy && bond[b - 1].btype == 'S' &&
05452        bond[b - 1].arom == false))
05453     return false;
05454   if (strcmp (atom[a_ref - 1].atype, "N3 ")
05455       && strcmp (atom[a_ref - 1].atype, "NAM")
05456       || atom[a_ref - 1].neighbor_count != 3)
05457     return false;
05458   get_nextneighbors (nb, a_ref, a_view);
05459   for (i = 0; i <= 1; i++)
05460     {
05461       if (!strcmp (atom[nb[i] - 1].element, "C "))
05462        c_count++;
05463     }
05464   if (c_count == 2)
05465     r = true;
05466   return r;
05467 }
05468 
05469 
05470 static boolean
05471 is_subst_amino (a_view, a_ref)
05472      int a_view, a_ref;
05473 {
05474   boolean r = false;
05475 
05476   if (is_amino (a_view, a_ref) || is_alkylamino (a_view, a_ref) |
05477       is_arylamino (a_view, a_ref) || is_dialkylamino (a_view, a_ref) |
05478       is_alkylarylamino (a_view, a_ref) || is_diarylamino (a_view, a_ref))
05479     r = true;
05480   return r;
05481 }
05482 
05483 
05484 static boolean
05485 is_true_alkylamino (a_view, a_ref)
05486      int a_view, a_ref;
05487 {
05488   boolean r = false;
05489   neighbor_rec nb;
05490   int alkyl_count = 0;
05491 
05492   memset (nb, 0, sizeof (neighbor_rec));
05493   if (!
05494       (atom[a_view - 1].
05495        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05496     return false;
05497   if (strcmp (atom[a_ref - 1].atype, "N3 ")
05498       && strcmp (atom[a_ref - 1].atype, "N3+")
05499       || atom[a_ref - 1].neighbor_count != 2)
05500     return false;
05501   get_nextneighbors (nb, a_ref, a_view);
05502   if (is_true_alkyl (a_ref, nb[0]))
05503     alkyl_count++;
05504   if (alkyl_count == 1)
05505     r = true;
05506   return r;
05507 }
05508 
05509 
05510 static boolean
05511 is_true_dialkylamino (a_view, a_ref)
05512      int a_view, a_ref;
05513 {
05514   int i;
05515   boolean r = false;
05516   neighbor_rec nb;
05517   int alkyl_count = 0;
05518 
05519   memset (nb, 0, sizeof (neighbor_rec));
05520   if (!
05521       (atom[a_view - 1].
05522        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05523     return false;
05524   if (strcmp (atom[a_ref - 1].atype, "N3 ")
05525       && strcmp (atom[a_ref - 1].atype, "N3+")
05526       || atom[a_ref - 1].neighbor_count != 3)
05527     return false;
05528   get_nextneighbors (nb, a_ref, a_view);
05529   for (i = 0; i <= 1; i++)
05530     {
05531       if (is_true_alkyl (a_ref, nb[i]))
05532        alkyl_count++;
05533     }
05534   if (alkyl_count == 2)
05535     r = true;
05536   return r;
05537 }
05538 
05539 
05540 static boolean
05541 is_true_alkylarylamino (a_view, a_ref)
05542      int a_view, a_ref;
05543 {
05544   int i;
05545   boolean r = false;
05546   neighbor_rec nb;
05547   int alkyl_count = 0, aryl_count = 0;
05548 
05549   memset (nb, 0, sizeof (neighbor_rec));
05550   if (!
05551       (atom[a_view - 1].
05552        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05553     return false;
05554   if (strcmp (atom[a_ref - 1].atype, "N3 ")
05555       && strcmp (atom[a_ref - 1].atype, "N3+")
05556       || atom[a_ref - 1].neighbor_count != 3)
05557     return false;
05558   get_nextneighbors (nb, a_ref, a_view);
05559   for (i = 0; i <= 1; i++)
05560     {
05561       if (is_true_alkyl (a_ref, nb[i]))
05562        alkyl_count++;
05563       if (is_aryl (a_ref, nb[i]))
05564        aryl_count++;
05565     }
05566   if (alkyl_count == 1 && aryl_count == 1)
05567     r = true;
05568   return r;
05569 }
05570 
05571 
05572 static boolean
05573 is_hydroxylamino (a_view, a_ref)
05574      int a_view, a_ref;
05575 {
05576   int i;
05577   boolean r = false;
05578   neighbor_rec nb;
05579   int oh_count = 0, het_count = 0; /* v0.3k */
05580   str2 nb_el;               /* v0.3k */
05581   int FORLIM;
05582 
05583   memset (nb, 0, sizeof (neighbor_rec));
05584   if (!
05585       (atom[a_view - 1].
05586        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05587     return false;
05588   if (strcmp (atom[a_ref - 1].element, "N ")
05589       || atom[a_ref - 1].neighbor_count < 2)
05590     /* v0.3c */
05591     return false;
05592   get_nextneighbors (nb, a_ref, a_view);
05593   FORLIM = atom[a_ref - 1].neighbor_count - 2;
05594   for (i = 0; i <= FORLIM; i++)
05595     {                       /* v0.3c */
05596       if (is_hydroxy (a_ref, nb[i]))
05597        oh_count++;
05598       strcpy (nb_el, atom[nb[i] - 1].element);   /* v0.3k */
05599       if (strcmp (nb_el, "C ") && strcmp (nb_el, "H ")
05600          /*&&  strcmp (nb_el, "D ") */  && strcmp (nb_el, "DU")
05601          && strcmp (nb_el, "LP"))
05602        /* v0.3k */
05603        het_count++;
05604       /* v0.3n: D */
05605     }
05606   if (oh_count == 1 && het_count == 1)
05607     r = true;
05608   return r;
05609 }
05610 
05611 
05612 static boolean
05613 is_nitro (a_view, a_ref)
05614      int a_view, a_ref;
05615 {
05616   int i;
05617   boolean r = false;
05618   neighbor_rec nb;
05619   int o_count = 0, bond_count = 0;
05620 
05621   memset (nb, 0, sizeof (neighbor_rec));
05622   if (!
05623       (atom[a_view - 1].
05624        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05625     return false;
05626   if (strcmp (atom[a_ref - 1].element, "N ")
05627       || atom[a_ref - 1].neighbor_count != 3)
05628     return false;
05629   get_nextneighbors (nb, a_ref, a_view);
05630   for (i = 0; i <= 1; i++)
05631     {
05632       if (!strcmp (atom[nb[i] - 1].element, "O "))
05633        o_count++;
05634       if (bond[get_bond (a_ref, nb[i]) - 1].btype == 'S')
05635        bond_count++;
05636       if (bond[get_bond (a_ref, nb[i]) - 1].btype == 'D')
05637        bond_count += 2;
05638     }
05639   if (o_count == 2 && bond_count >= 3)
05640     r = true;
05641   return r;
05642 }
05643 
05644 
05645 static boolean
05646 is_azido (a_view, a_ref)
05647      int a_view, a_ref;
05648 {
05649   boolean r = false;
05650   neighbor_rec nb;
05651   int bond_count = 0, n1 = 0, n2 = 0, n3 = 0;
05652 
05653   if (!
05654       (atom[a_view - 1].
05655        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05656     return false;
05657   if (strcmp (atom[a_ref - 1].element, "N ")
05658       || atom[a_ref - 1].neighbor_count != 2)
05659     return false;
05660   n1 = a_ref;
05661   memset (nb, 0, sizeof (neighbor_rec));
05662   get_nextneighbors (nb, n1, a_view);
05663   if (!strcmp (atom[nb[0] - 1].element, "N "))
05664     {
05665       n2 = nb[0];
05666       if (bond[get_bond (n1, n2) - 1].btype == 'S')
05667        bond_count++;
05668       if (bond[get_bond (n1, n2) - 1].btype == 'D')
05669        bond_count += 2;
05670       if (bond[get_bond (n1, n2) - 1].btype == 'T')
05671        bond_count += 3;
05672     }
05673   if (n2 > 0 && atom[n2 - 1].neighbor_count == 2)
05674     {
05675       memset (nb, 0, sizeof (neighbor_rec));
05676       get_nextneighbors (nb, n2, n1);
05677       if (!strcmp (atom[nb[0] - 1].element, "N "))
05678        {
05679          n3 = nb[0];
05680          if (bond[get_bond (n2, n3) - 1].btype == 'S')
05681            bond_count++;
05682          if (bond[get_bond (n2, n3) - 1].btype == 'D')
05683            bond_count += 2;
05684          if (bond[get_bond (n2, n3) - 1].btype == 'T')
05685            bond_count += 3;
05686        }
05687     }
05688   if (n1 > 0 && n2 > 0 && n3 > 0 && atom[n3 - 1].neighbor_count == 1 &&
05689       bond_count > 3)
05690     r = true;
05691   return r;
05692 }
05693 
05694 
05695 static boolean
05696 is_diazonium (a_view, a_ref)
05697      int a_view, a_ref;
05698 {
05699   boolean r = false;
05700   neighbor_rec nb;
05701   int bond_count = 0, chg_count = 0, n1 = 0, n2 = 0;
05702 
05703   if (!
05704       (atom[a_view - 1].
05705        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05706     return false;
05707   if (strcmp (atom[a_ref - 1].element, "N ")
05708       || atom[a_ref - 1].neighbor_count != 2)
05709     return false;
05710   n1 = a_ref;
05711   chg_count = atom[n1 - 1].formal_charge;
05712   memset (nb, 0, sizeof (neighbor_rec));
05713   get_nextneighbors (nb, n1, a_view);
05714   if (!strcmp (atom[nb[0] - 1].element, "N "))
05715     {
05716       n2 = nb[0];
05717       chg_count += atom[n2 - 1].formal_charge;
05718       if (bond[get_bond (n1, n2) - 1].btype == 'S')
05719        bond_count++;
05720       if (bond[get_bond (n1, n2) - 1].btype == 'D')
05721        bond_count += 2;
05722       if (bond[get_bond (n1, n2) - 1].btype == 'T')
05723        bond_count += 3;
05724     }
05725   if (n1 > 0 && n2 > 0 && atom[n2 - 1].neighbor_count == 1
05726       && bond_count >= 2 && chg_count > 0)
05727     r = true;
05728   return r;
05729 }
05730 
05731 
05732 static boolean
05733 is_hydroximino_C (id)
05734      int id;
05735 {
05736   boolean Result;
05737   int i;
05738   boolean r = false;
05739   neighbor_rec nb;
05740   int a_het = 0;
05741   int FORLIM;
05742 
05743   memset (nb, 0, sizeof (neighbor_rec));
05744   if (id < 1 || id > n_atoms)
05745     return Result;
05746   get_neighbors (nb, id);
05747   if (strcmp (atom[id - 1].element, "C ") || atom[id - 1].neighbor_count <= 0)
05748     return false;
05749   FORLIM = atom[id - 1].neighbor_count;
05750   for (i = 0; i < FORLIM; i++)
05751     {
05752       if ((bond[get_bond (id, nb[i]) - 1].btype == 'D' &&
05753           !strcmp (atom[nb[i] - 1].element,
05754                   "N ")) && (hetbond_count (nb[i]) == 3))
05755        a_het = nb[i];
05756     }
05757   if (a_het <= 0)
05758     return false;
05759   memset (nb, 0, sizeof (neighbor_rec));
05760   get_neighbors (nb, a_het);
05761   if (strcmp (atom[a_het - 1].element, "N ")
05762       || atom[a_het - 1].neighbor_count <= 0)
05763     return false;
05764   FORLIM = atom[a_het - 1].neighbor_count;
05765   for (i = 0; i < FORLIM; i++)
05766     {
05767       if (is_hydroxy (a_het, nb[i]))
05768        r = true;
05769     }
05770   return r;
05771 }
05772 
05773 
05774 static boolean
05775 is_hydrazono_C (id)
05776      int id;
05777 {
05778   boolean Result;
05779   int i;
05780   boolean r = false;
05781   neighbor_rec nb;
05782   int a_het = 0;
05783   int FORLIM;
05784 
05785   memset (nb, 0, sizeof (neighbor_rec));
05786   if (id < 1 || id > n_atoms)
05787     return Result;
05788   get_neighbors (nb, id);
05789   if (strcmp (atom[id - 1].element, "C ") || atom[id - 1].neighbor_count <= 0)
05790     return false;
05791   FORLIM = atom[id - 1].neighbor_count;
05792   for (i = 0; i < FORLIM; i++)
05793     {
05794       if (bond[get_bond (id, nb[i]) - 1].btype == 'D' &&
05795          !strcmp (atom[nb[i] - 1].element, "N "))
05796        {
05797          /* and
05798             (hetbond_count(nb[i]) = 3)  */
05799          a_het = nb[i];
05800        }
05801     }
05802   if (a_het <= 0)
05803     return false;
05804   memset (nb, 0, sizeof (neighbor_rec));
05805   get_neighbors (nb, a_het);
05806   if (strcmp (atom[a_het - 1].element, "N ")
05807       || atom[a_het - 1].neighbor_count <= 0)
05808     return false;
05809   FORLIM = atom[a_het - 1].neighbor_count;
05810   for (i = 0; i < FORLIM; i++)
05811     {
05812       if (is_amino (a_het, nb[i]) || is_alkylamino (a_het, nb[i]) |
05813          is_alkylarylamino (a_het, nb[i]) || is_arylamino (a_het, nb[i]) |
05814          is_dialkylamino (a_het, nb[i]) || is_diarylamino (a_het, nb[i]))
05815        r = true;
05816     }
05817   return r;
05818 }
05819 
05820 
05821 static boolean
05822 is_alkoxycarbonyl (a_view, a_ref)
05823      int a_view, a_ref;
05824 {
05825   int i;
05826   boolean r = false;
05827   neighbor_rec nb;
05828 
05829   memset (nb, 0, sizeof (neighbor_rec));
05830   if (!
05831       (atom[a_view - 1].
05832        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05833     return false;
05834   if (!(is_oxo_C (a_ref) && atom[a_ref - 1].neighbor_count == 3))
05835     return false;
05836   get_nextneighbors (nb, a_ref, a_view);
05837   for (i = 0; i <= 1; i++)
05838     {
05839       if (is_alkoxy (a_ref, nb[i]))
05840        r = true;
05841     }
05842   return r;
05843 }
05844 
05845 
05846 static boolean
05847 is_aryloxycarbonyl (a_view, a_ref)
05848      int a_view, a_ref;
05849 {
05850   int i;
05851   boolean r = false;
05852   neighbor_rec nb;
05853 
05854   memset (nb, 0, sizeof (neighbor_rec));
05855   if (!
05856       (atom[a_view - 1].
05857        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05858     return false;
05859   if (!(is_oxo_C (a_ref) && atom[a_ref - 1].neighbor_count == 3))
05860     return false;
05861   get_nextneighbors (nb, a_ref, a_view);
05862   for (i = 0; i <= 1; i++)
05863     {
05864       if (is_aryloxy (a_ref, nb[i]))
05865        r = true;
05866     }
05867   return r;
05868 }
05869 
05870 
05871 static boolean
05872 is_carbamoyl (a_view, a_ref)
05873      int a_view, a_ref;
05874 {
05875   int i;
05876   boolean r = false;
05877   neighbor_rec nb;
05878 
05879   memset (nb, 0, sizeof (neighbor_rec));
05880   if (!
05881       (atom[a_view - 1].
05882        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05883     return false;
05884   if (!(is_oxo_C (a_ref) && atom[a_ref - 1].neighbor_count == 3))
05885     return false;
05886   get_nextneighbors (nb, a_ref, a_view);
05887   for (i = 0; i <= 1; i++)
05888     {
05889       if (!strcmp (atom[nb[i] - 1].atype, "N3 ") ||
05890          !strcmp (atom[nb[i] - 1].atype, "NAM"))
05891        r = true;
05892     }
05893   return r;
05894 }
05895 
05896 
05897 static boolean
05898 is_alkoxythiocarbonyl (a_view, a_ref)
05899      int a_view, a_ref;
05900 {
05901   int i;
05902   boolean r = false;
05903   neighbor_rec nb;
05904 
05905   memset (nb, 0, sizeof (neighbor_rec));
05906   if (!
05907       (atom[a_view - 1].
05908        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05909     return false;
05910   if (!(is_thioxo_C (a_ref) && atom[a_ref - 1].neighbor_count == 3))
05911     return false;
05912   get_nextneighbors (nb, a_ref, a_view);
05913   for (i = 0; i <= 1; i++)
05914     {
05915       if (is_alkoxy (a_ref, nb[i]))
05916        r = true;
05917     }
05918   return r;
05919 }
05920 
05921 
05922 static boolean
05923 is_aryloxythiocarbonyl (a_view, a_ref)
05924      int a_view, a_ref;
05925 {
05926   int i;
05927   boolean r = false;
05928   neighbor_rec nb;
05929 
05930   memset (nb, 0, sizeof (neighbor_rec));
05931   if (!
05932       (atom[a_view - 1].
05933        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05934     return false;
05935   if (!(is_thioxo_C (a_ref) && atom[a_ref - 1].neighbor_count == 3))
05936     return false;
05937   get_nextneighbors (nb, a_ref, a_view);
05938   for (i = 0; i <= 1; i++)
05939     {
05940       if (is_aryloxy (a_ref, nb[i]))
05941        r = true;
05942     }
05943   return r;
05944 }
05945 
05946 
05947 static boolean
05948 is_thiocarbamoyl (a_view, a_ref)
05949      int a_view, a_ref;
05950 {
05951   int i;
05952   boolean r = false;
05953   neighbor_rec nb;
05954 
05955   memset (nb, 0, sizeof (neighbor_rec));
05956   if (!
05957       (atom[a_view - 1].
05958        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05959     return false;
05960   if (!(is_thioxo_C (a_ref) && atom[a_ref - 1].neighbor_count == 3))
05961     return false;
05962   get_nextneighbors (nb, a_ref, a_view);
05963   for (i = 0; i <= 1; i++)
05964     {
05965       if (!strcmp (atom[nb[i] - 1].atype, "N3 ") ||
05966          !strcmp (atom[nb[i] - 1].atype, "NAM"))
05967        r = true;
05968     }
05969   return r;
05970 }
05971 
05972 
05973 static boolean
05974 is_alkanoyl (a_view, a_ref)
05975      int a_view, a_ref;
05976 {
05977   int i;
05978   boolean r = false;
05979   neighbor_rec nb;
05980 
05981   memset (nb, 0, sizeof (neighbor_rec));
05982   if (!
05983       (atom[a_view - 1].
05984        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
05985     return false;
05986   if (!(is_oxo_C (a_ref) && atom[a_ref - 1].neighbor_count == 3))
05987     return false;
05988   get_nextneighbors (nb, a_ref, a_view);
05989   for (i = 0; i <= 1; i++)
05990     {
05991       if (is_alkyl (a_ref, nb[i]))
05992        r = true;
05993     }
05994   return r;
05995 }
05996 
05997 
05998 static boolean
05999 is_aroyl (a_view, a_ref)
06000      int a_view, a_ref;
06001 {
06002   int i;
06003   boolean r = false;
06004   neighbor_rec nb;
06005 
06006   memset (nb, 0, sizeof (neighbor_rec));
06007   if (!
06008       (atom[a_view - 1].
06009        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
06010     return false;
06011   if (!(is_oxo_C (a_ref) && atom[a_ref - 1].neighbor_count == 3))
06012     return false;
06013   get_nextneighbors (nb, a_ref, a_view);
06014   for (i = 0; i <= 1; i++)
06015     {
06016       if (is_aryl (a_ref, nb[i]))
06017        r = true;
06018     }
06019   return r;
06020 }
06021 
06022 
06023 static boolean
06024 is_acyl (a_view, a_ref)
06025      int a_view, a_ref;
06026 {
06027   boolean r = false;
06028 
06029   if (is_alkanoyl (a_view, a_ref) || is_aroyl (a_view, a_ref))
06030     r = true;
06031   return r;
06032 }
06033 
06034 
06035 static boolean
06036 is_acyl_gen (a_view, a_ref)
06037      int a_view, a_ref;
06038 {
06039   /* new in v0.3j */
06040   boolean r = false;
06041 
06042   if (is_oxo_C (a_ref))
06043     r = true;
06044   return r;
06045 }
06046 
06047 
06048 static boolean
06049 is_acylamino (a_view, a_ref)
06050      int a_view, a_ref;
06051 {
06052   boolean r = false;
06053   neighbor_rec nb;
06054   int acyl_count = 0;
06055 
06056   memset (nb, 0, sizeof (neighbor_rec));
06057   if (!
06058       (atom[a_view - 1].
06059        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
06060     return false;
06061   if (strcmp (atom[a_ref - 1].element, "N ")
06062       || atom[a_ref - 1].neighbor_count != 2)
06063     return false;
06064   get_nextneighbors (nb, a_ref, a_view);
06065   if (is_acyl (a_ref, nb[0]))
06066     acyl_count++;
06067   if (acyl_count == 1)
06068     r = true;
06069   return r;
06070 }
06071 
06072 
06073 static boolean
06074 is_subst_acylamino (a_view, a_ref)
06075      int a_view, a_ref;
06076 {
06077   /* may be substituted _or_ unsubstituted acylamino group! */
06078   int i;
06079   boolean r = false;
06080   neighbor_rec nb;
06081   int acyl_count = 0;
06082   int FORLIM;
06083 
06084   memset (nb, 0, sizeof (neighbor_rec));
06085   if (!
06086       (atom[a_view - 1].
06087        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
06088     return false;
06089   if (strcmp (atom[a_ref - 1].element, "N ")
06090       || atom[a_ref - 1].neighbor_count < 2)
06091     return false;
06092   get_nextneighbors (nb, a_ref, a_view);
06093   FORLIM = atom[a_ref - 1].neighbor_count - 2;
06094   for (i = 0; i <= FORLIM; i++)
06095     {
06096       if (is_acyl_gen (a_ref, nb[i]))     /* v0.3j */
06097        acyl_count++;
06098     }
06099   if (acyl_count > 0)
06100     r = true;
06101   return r;
06102 }
06103 
06104 
06105 static boolean
06106 is_hydrazino (a_view, a_ref)
06107      int a_view, a_ref;
06108 {
06109   int i;
06110   boolean r = false;
06111   neighbor_rec nb;
06112   int nr_count = 0;
06113   int FORLIM;
06114 
06115   memset (nb, 0, sizeof (neighbor_rec));
06116   if (!
06117       (atom[a_view - 1].
06118        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
06119     return false;
06120   if (strcmp (atom[a_ref - 1].element, "N ")
06121       || atom[a_ref - 1].neighbor_count < 2)
06122     return false;
06123   get_nextneighbors (nb, a_ref, a_view);
06124   FORLIM = atom[a_ref - 1].neighbor_count - 2;
06125   for (i = 0; i <= FORLIM; i++)
06126     {                       /* fixed in v0.3c */
06127       if (is_amino (a_ref, nb[i]) || is_subst_amino (a_ref, nb[i]))
06128        nr_count++;
06129     }
06130   if (nr_count == 1)
06131     r = true;
06132   return r;
06133 }
06134 
06135 
06136 static boolean
06137 is_nitroso (a_view, a_ref)
06138      int a_view, a_ref;
06139 {
06140   /* new in v0.3j */
06141   boolean r = false;
06142   neighbor_rec nb;
06143   int o_count = 0;
06144   int a2;
06145 
06146   memset (nb, 0, sizeof (neighbor_rec));
06147   if (!
06148       (atom[a_view - 1].
06149        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
06150     return false;
06151   if (strcmp (atom[a_ref - 1].element, "N ")
06152       || atom[a_ref - 1].neighbor_count != 2)
06153     return false;
06154   get_nextneighbors (nb, a_ref, a_view);
06155   a2 = nb[0];
06156   if ((strcmp (atom[a2 - 1].element, "O ") == 0) &
06157       (bond[get_bond (a_ref, a2) - 1].btype == 'D'))
06158     o_count++;
06159   if (o_count == 1)
06160     r = true;
06161   return r;
06162 }
06163 
06164 
06165 static boolean
06166 is_subst_hydrazino (a_view, a_ref)
06167      int a_view, a_ref;
06168 {
06169   int i;
06170   boolean r = false;
06171   neighbor_rec nb;
06172   int nr_count = 0;
06173   int a2, FORLIM;
06174 
06175   memset (nb, 0, sizeof (neighbor_rec));
06176   if (!
06177       (atom[a_view - 1].
06178        heavy && (bond[get_bond (a_view, a_ref) - 1].btype == 'S')))
06179     return false;
06180   if (strcmp (atom[a_ref - 1].element, "N ")
06181       || atom[a_ref - 1].neighbor_count < 2)
06182     return false;
06183   get_nextneighbors (nb, a_ref, a_view);
06184   FORLIM = atom[a_ref - 1].neighbor_count - 2;
06185   for (i = 0; i <= FORLIM; i++)
06186     {
06187       a2 = nb[i];
06188       if ((strcmp (atom[a2 - 1].element, "N ") ==
06189           0) && (!is_nitroso (a_ref, a2)))
06190        /* v0.3j */
06191        nr_count++;
06192     }
06193   if (nr_count == 1)
06194     r = true;
06195   return r;
06196 }
06197 
06198 
06199 static boolean
06200 is_cyano (a_view, a_ref)
06201      int a_view, a_ref;
06202 {
06203   boolean r = false;
06204 
06205   if (((strcmp (atom[a_view - 1].atype, "C1 ") == 0) &
06206        (bond[get_bond (a_view, a_ref) - 1].btype == 'T')) &&
06207       !strcmp (atom[a_ref - 1].atype, "N1 ") &&
06208       atom[a_ref - 1].neighbor_count == 1)
06209     r = true;
06210   return r;
06211 }
06212 
06213 
06214 static boolean
06215 is_cyano_c (a_ref)
06216      int a_ref;
06217 {
06218   int i;
06219   boolean r = false;
06220   neighbor_rec nb;
06221   int FORLIM;
06222 
06223   memset (nb, 0, sizeof (neighbor_rec));
06224   if (strcmp (atom[a_ref - 1].atype, "C1 ")
06225       || atom[a_ref - 1].neighbor_count <= 0)
06226     return false;
06227   get_neighbors (nb, a_ref);
06228   FORLIM = atom[a_ref - 1].neighbor_count;
06229   for (i = 0; i < FORLIM; i++)
06230     {
06231       if (is_cyano (a_ref, nb[i]))
06232        r = true;
06233     }
06234   return r;
06235 }
06236 
06237 
06238 static boolean
06239 is_nitrile (a_view, a_ref)
06240      int a_view, a_ref;
06241 {
06242   boolean r = false;
06243   neighbor_rec nb;
06244   str2 nb_el;
06245 
06246   if (!is_cyano (a_view, a_ref))
06247     return false;
06248   if (atom[a_view - 1].neighbor_count == 1
06249       && atom[a_view - 1].formal_charge == 0)
06250     return true;
06251 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
06252   get_nextneighbors (nb, a_view, a_ref);
06253   strcpy (nb_el, atom[nb[0] - 1].element);
06254   if (!strcmp (nb_el, "C ")
06255       || !strcmp (nb_el, "H ") /*|| !strcmp (nb_el, "D ") */ )
06256     /* v0.3n: D */
06257     r = true;
06258   /* HCN is also a nitrile! */
06259   return r;
06260 }
06261 
06262 
06263 static boolean
06264 is_isonitrile (a_view, a_ref)
06265      int a_view, a_ref;
06266 {
06267   /* only recognized with CN triple bond! */
06268   boolean r = false;
06269 
06270   if (((strcmp (atom[a_view - 1].atype, "C1 ") == 0) &
06271        (bond[get_bond (a_view, a_ref) - 1].btype == 'T')) &&
06272       !strcmp (atom[a_ref - 1].atype, "N1 ") &&
06273       atom[a_ref - 1].neighbor_count == 2
06274       && atom[a_view - 1].neighbor_count == 1)
06275     r = true;
06276   return r;
06277 }
06278 
06279 
06280 static boolean
06281 is_cyanate (a_view, a_ref)
06282      int a_view, a_ref;
06283 {
06284   boolean r = false;
06285   neighbor_rec nb;
06286 
06287   if (!is_cyano (a_view, a_ref))
06288     return false;
06289   if (atom[a_view - 1].neighbor_count != 2)
06290     return false;
06291   get_nextneighbors (nb, a_view, a_ref);
06292   if (is_alkoxy (a_view, nb[0]) || is_aryloxy (a_view, nb[0]))
06293     r = true;
06294   return r;
06295 }
06296 
06297 
06298 static boolean
06299 is_thiocyanate (a_view, a_ref)
06300      int a_view, a_ref;
06301 {
06302   boolean r = false;
06303   neighbor_rec nb;
06304 
06305   if (!is_cyano (a_view, a_ref))
06306     return false;
06307   if (atom[a_view - 1].neighbor_count != 2)
06308     return false;
06309   get_nextneighbors (nb, a_view, a_ref);
06310   if (is_alkylsulfanyl (a_view, nb[0]) || is_arylsulfanyl (a_view, nb[0]))
06311     r = true;
06312   return r;
06313 }
06314 
06315 
06316 static void
06317 update_Htotal ()
06318 {
06319   int i, j, b_id;
06320   neighbor_rec nb;
06321   int single_count, double_count, triple_count, arom_count, total_bonds,
06322     Htotal, nval;
06323   /* new in v0.3 */
06324   boolean diazon = false;   /* new in v0.3j */
06325   neighbor_rec nb2;         /* new in v0.3j */
06326   int a1, a2, a3;           /* new in v0.3j */
06327   int FORLIM, FORLIM1;
06328 
06329   if (n_atoms < 1)
06330     return;
06331   memset (nb, 0, sizeof (neighbor_rec));
06332   FORLIM = n_atoms;
06333   for (i = 1; i <= FORLIM; i++)
06334     {
06335       single_count = 0;
06336       double_count = 0;
06337       triple_count = 0;
06338       arom_count = 0;
06339       total_bonds = 0;
06340       Htotal = 0;
06341       get_neighbors (nb, i);
06342       if (atom[i - 1].neighbor_count > 0)
06343        {
06344          /* count single, double, triple, and aromatic bonds to all neighbor atoms */
06345          FORLIM1 = atom[i - 1].neighbor_count;
06346          for (j = 0; j < FORLIM1; j++)
06347            {
06348              b_id = get_bond (i, nb[j]);
06349              if (b_id > 0)
06350               {
06351                 if (bond[b_id - 1].btype == 'S')
06352                   single_count++;
06353                 if (bond[b_id - 1].btype == 'D')
06354                   double_count++;
06355                 if (bond[b_id - 1].btype == 'T')
06356                   triple_count++;
06357                 if (bond[b_id - 1].btype == 'A')
06358                   arom_count++;
06359               }
06360            }
06361          /*check for diazonium salts */
06362          a1 = i;
06363          a2 = nb[0];
06364          if (!strcmp (atom[a1 - 1].element, "N ") &&
06365              !strcmp (atom[a2 - 1].element, "N "))
06366            {
06367              if (atom[a2 - 1].neighbor_count == 2)
06368               {
06369                 get_nextneighbors (nb2, a2, a1);
06370                 a3 = nb2[0];
06371                 if ((strcmp (atom[a3 - 1].element, "C ") ==
06372                      0) && is_diazonium (a3, a2))
06373                   diazon = true;
06374               }
06375            }
06376        }
06377       total_bonds = single_count + double_count * 2 + triple_count * 3 +
06378        (int) (1.5 * arom_count);
06379       /* calculate number of total hydrogens per atom */
06380       /*nval := nvalences(atom^[i].element);    (* new in v0.3 */
06381       nval = atom[i - 1].nvalences;       /* new in v0.3m */
06382       if (!strcmp (atom[i - 1].element, "P "))
06383        {
06384          if (total_bonds - atom[i - 1].formal_charge > 3)      /* refined in v0.3n */
06385            nval = 5;
06386        }                    /*  */
06387       if (!strcmp (atom[i - 1].element, "S "))
06388        {                    /* v0.3h */
06389          if (total_bonds > 2 && atom[i - 1].formal_charge < 1)
06390            /* updated in v0.3j */
06391            nval = 4;
06392          if (total_bonds > 4)      /* this will need some refinement... */
06393            nval = 6;
06394        }                    /*  */
06395       Htotal = nval - total_bonds + atom[i - 1].formal_charge;
06396       if (diazon)           /* v0.3j */
06397        Htotal = 0;
06398       if (Htotal < 0)              /* e.g., N in nitro group */
06399        Htotal = 0;
06400       atom[i - 1].Htot = Htotal;
06401       if (atom[i - 1].Hexp > atom[i - 1].Htot)   /* v0.3n; just to be sure... */
06402        atom[i - 1].Htot = atom[i - 1].Hexp;
06403     }
06404 }
06405 
06406 
06407 static void
06408 update_atypes ()
06409 {
06410   int i, j, b_id;
06411   neighbor_rec nb;
06412   int single_count, double_count, triple_count, arom_count, acyl_count,
06413     C_count, O_count, total_bonds, NdO_count, NdC_count, Htotal, FORLIM,
06414     FORLIM1;
06415 
06416   if (n_atoms < 1)
06417     return;
06418   memset (nb, 0, sizeof (neighbor_rec));
06419   FORLIM = n_atoms;
06420   for (i = 0; i < FORLIM; i++)
06421     {
06422       single_count = 0;
06423       double_count = 0;
06424       triple_count = 0;
06425       arom_count = 0;
06426       total_bonds = 0;
06427       acyl_count = 0;
06428       C_count = 0;
06429       O_count = 0;
06430       NdO_count = 0;
06431       NdC_count = 0;
06432       Htotal = 0;
06433       get_neighbors (nb, i + 1);
06434       if (atom[i].neighbor_count > 0)
06435        {
06436          /* count single, double, triple, and aromatic bonds to all neighbor atoms */
06437          FORLIM1 = atom[i].neighbor_count;
06438          for (j = 0; j < FORLIM1; j++)
06439            {
06440              if (is_oxo_C (nb[j]) || is_thioxo_C (nb[j]))
06441               acyl_count++;
06442              if (!strcmp (atom[nb[j] - 1].element, "C "))
06443               C_count++;
06444              if (!strcmp (atom[nb[j] - 1].element, "O "))
06445               O_count++;
06446              b_id = get_bond (i + 1, nb[j]);
06447              if (b_id > 0)
06448               {
06449                 if (bond[b_id - 1].btype == 'S')
06450                   single_count++;
06451                 if (bond[b_id - 1].btype == 'D')
06452                   double_count++;
06453                 if (bond[b_id - 1].btype == 'T')
06454                   triple_count++;
06455                 if (bond[b_id - 1].btype == 'A')
06456                   /* v0.3n: special treatment for acyclic bonds */
06457                   {         /* flagged as "aromatic" (in query structures) */
06458                     if (bond[b_id - 1].ring_count > 0)
06459                      arom_count++;
06460                     else
06461                      double_count++;
06462                   }
06463                 if ((!strcmp (atom[i].element, "N ") &&
06464                      !strcmp (atom[nb[j] - 1].element, "O ")) ||
06465                     (!strcmp (atom[i].element, "O ") &&
06466                      !strcmp (atom[nb[j] - 1].element, "N ")))
06467                   {
06468                     /* check if it is an N-oxide drawn with a double bond ==> should be N3 */
06469                     if (bond[b_id - 1].btype == 'D')
06470                      NdO_count++;
06471                   }
06472                 if ((!strcmp (atom[i].element, "N ") &&
06473                      !strcmp (atom[nb[j] - 1].element, "C ")) ||
06474                     (!strcmp (atom[i].element, "C ") &&
06475                      !strcmp (atom[nb[j] - 1].element, "N ")))
06476                   {
06477                     if (bond[b_id - 1].btype == 'D')
06478                      NdC_count++;
06479                   }
06480               }
06481            }
06482          total_bonds = single_count + double_count * 2 + triple_count * 3 +
06483            (int) (1.5 * arom_count);
06484          /* calculate number of total hydrogens per atom */
06485          /*Htotal := nvalences(atom^[i].element) - total_bonds + atom^[i].formal_charge; */
06486          Htotal = atom[i].nvalences - total_bonds + atom[i].formal_charge;
06487          if (Htotal < 0)    /* e.g., N in nitro group */
06488            Htotal = 0;
06489          atom[i].Htot = Htotal;
06490          /* refine atom types, based on bond types */
06491          if (!strcmp (atom[i].element, "C "))
06492            {
06493              if (arom_count > 1)
06494               strcpy (atom[i].atype, "CAR");
06495              if (triple_count == 1 || double_count == 2)
06496               strcpy (atom[i].atype, "C1 ");
06497              if (double_count == 1)
06498               strcpy (atom[i].atype, "C2 ");
06499              if (triple_count == 0 && double_count == 0 && arom_count < 2)
06500               strcpy (atom[i].atype, "C3 ");
06501            }
06502          if (!strcmp (atom[i].element, "O "))
06503            {
06504              if (double_count == 1)
06505               strcpy (atom[i].atype, "O2 ");
06506              if (double_count == 0)
06507               strcpy (atom[i].atype, "O3 ");
06508            }
06509          if (!strcmp (atom[i].element, "N "))
06510            {
06511              if (total_bonds > 3)
06512               {
06513                 if (O_count == 0)
06514                   {
06515                     if (single_count > 3 ||
06516                        single_count == 2 && double_count == 1
06517                        && C_count >= 2)
06518                      atom[i].formal_charge = 1;
06519                   }
06520                 else
06521                   {
06522                     if (O_count == 1 && atom[i].formal_charge == 0)   /* v0.3m */
06523                      strcpy (atom[i].atype, "N3 ");
06524                     if (O_count == 2 && atom[i].formal_charge == 0)
06525                      {
06526                        if (atom[i].neighbor_count > 2)  /* nitro v0.3o */
06527                          strcpy (atom[i].atype, "N2 ");
06528                        if (atom[i].neighbor_count == 2) /* NO2   v0.3o */
06529                          strcpy (atom[i].atype, "N1 ");
06530                      }
06531                     /* the rest is left empty, so far.... */
06532                   }
06533               }
06534              /* could be an N-oxide -> should be found elsewhere  */
06535              if (triple_count == 1 ||
06536                 double_count == 2 && atom[i].neighbor_count == 2)
06537               /* v0.3n */
06538               strcpy (atom[i].atype, "N1 ");
06539              if (double_count == 1)
06540               {
06541                 /*if NdC_count > 0 then atom^[i].atype := 'N2 '; */
06542                 if (NdC_count == 0 && NdO_count > 0 && C_count >= 2)
06543                   strcpy (atom[i].atype, "N3 ");
06544                 /* N-oxide is N3 except in hetarene etc. */
06545                 else
06546                   strcpy (atom[i].atype, "N2 ");
06547               }
06548              /* fallback, added in v0.3g  */
06549              if (arom_count > 1 || atom[i].arom == true)       /* v0.3n */
06550               strcpy (atom[i].atype, "NAR");
06551              if (triple_count == 0 && double_count == 0)
06552               {
06553                 if (atom[i].formal_charge == 0)
06554                   {
06555                     if (acyl_count == 0)
06556                      strcpy (atom[i].atype, "N3 ");
06557                     if (acyl_count > 0)
06558                      strcpy (atom[i].atype, "NAM");
06559                   }
06560                 if (atom[i].formal_charge == 1)
06561                   strcpy (atom[i].atype, "N3+");
06562               }
06563            }
06564          if (!strcmp (atom[i].element, "P "))
06565            {
06566              if (single_count > 4)
06567               strcpy (atom[i].atype, "P4 ");
06568              if (single_count <= 4 && double_count == 0)
06569               strcpy (atom[i].atype, "P3 ");
06570              if (double_count == 2)
06571               strcpy (atom[i].atype, "P3D");
06572            }
06573          if (!strcmp (atom[i].element, "S "))
06574            {
06575              if (double_count == 1 && single_count == 0)
06576               strcpy (atom[i].atype, "S2 ");
06577              if (double_count == 0)
06578               strcpy (atom[i].atype, "S3 ");
06579              if (double_count == 1 && single_count > 0)
06580               strcpy (atom[i].atype, "SO ");
06581              if (double_count == 2 && single_count > 0)
06582               strcpy (atom[i].atype, "SO2");
06583            }
06584          /* further atom types should go here */
06585        }
06586     }
06587 }
06588 
06589 
06590 static void
06591 chk_arom ()
06592 {
06593   int i, j, pi_count, ring_size, b, a1, a2;      /* v0.3n */
06594   ringpath_type testring;
06595   int a_ref, a_prev, a_next, b_bk, b_fw, b_exo;
06596   char bt_bk, bt_fw;
06597   boolean ar_bk, ar_fw, ar_exo;    /* new in v0.3 */
06598   boolean conj_intr, ko, aromatic, aromatic_bt;  /* v0.3n */
06599   int n_db, n_sb, n_ar;
06600   boolean cumul;
06601   int exo_mC;               /* v0.3j */
06602   int arom_pi_diff;         /* v0.3j */
06603   int FORLIM;
06604 
06605   if (n_rings < 1)
06606     return;
06607   FORLIM = n_rings;
06608   /* first, do a very quick check for benzene, pyridine, etc. */
06609   for (i = 0; i < FORLIM; i++)
06610     {
06611       ring_size = ringprop[i].size;
06612       if (ring_size == 6)
06613        {
06614          memset (testring, 0, sizeof (ringpath_type));
06615          for (j = 0; j < ring_size; j++)
06616            testring[j] = ring[i][j];
06617          cumul = false;
06618          n_sb = 0;
06619          n_db = 0;
06620          n_ar = 0;
06621          a_prev = testring[ring_size - 1];
06622          for (j = 1; j <= ring_size; j++)
06623            {
06624              a_ref = testring[j - 1];
06625              if (j < ring_size)
06626               a_next = testring[j];
06627              else
06628               a_next = testring[0];
06629              b_bk = get_bond (a_prev, a_ref);
06630              b_fw = get_bond (a_ref, a_next);
06631              bt_bk = bond[b_bk - 1].btype;
06632              bt_fw = bond[b_fw - 1].btype;
06633              if (bt_fw == 'S')
06634               n_sb++;
06635              if (bt_fw == 'D')
06636               n_db++;
06637              if (bt_fw == 'A')
06638               n_ar++;
06639              if (bt_fw != 'A' && bt_bk == bt_fw)
06640               cumul = true;
06641              a_prev = a_ref;
06642            }
06643          if (n_ar == 6 || n_sb == 3 && n_db == 3 && cumul == false)
06644            {                /* this ring is aromatic */
06645              a_prev = testring[ring_size - 1];
06646              for (j = 0; j < ring_size; j++)
06647               {
06648                 a_ref = testring[j];
06649                 b_bk = get_bond (a_prev, a_ref);
06650                 bond[b_bk - 1].arom = true;
06651                 a_prev = a_ref;
06652               }
06653              ringprop[i].arom = true;
06654            }
06655        }
06656     }
06657   FORLIM = n_rings;
06658   for (i = 1; i <= FORLIM; i++)
06659     {
06660       if (ringprop[i - 1].arom == false)
06661        {
06662          /* do the hard work only for those rings which are not yet flagged aromatic */
06663          memset (testring, 0, sizeof (ringpath_type));
06664          ring_size = ringprop[i - 1].size;       /* v0.3j */
06665          for (j = 0; j < ring_size; j++)  /* v0.3j */
06666            testring[j] = ring[i - 1][j];
06667          pi_count = 0;
06668          arom_pi_diff = 0;  /* v0.3j */
06669 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
06670          ko = false;
06671          a_prev = testring[ring_size - 1];
06672          for (j = 1; j <= ring_size; j++)
06673            {
06674              a_ref = testring[j - 1];
06675              if (j < ring_size)
06676               a_next = testring[j];
06677              else
06678               a_next = testring[0];
06679              b_bk = get_bond (a_prev, a_ref);
06680              b_fw = get_bond (a_ref, a_next);
06681              bt_bk = bond[b_bk - 1].btype;
06682              bt_fw = bond[b_fw - 1].btype;
06683              ar_bk = bond[b_bk - 1].arom;
06684              ar_fw = bond[b_fw - 1].arom;
06685              if (bt_bk == 'S' && bt_fw == 'S' && ar_bk == false
06686                 && ar_fw == false)
06687               {
06688                 /* first, assume the worst case (interrupted conjugation) */
06689                 conj_intr = true;
06690                 /* conjugation can be restored by hetero atoms */
06691                 if (!strcmp (atom[a_ref - 1].atype, "O3 ") ||
06692                     !strcmp (atom[a_ref - 1].atype, "S3 ") ||
06693                     !strcmp (atom[a_ref - 1].element, "N ") ||
06694                     !strcmp (atom[a_ref - 1].element, "SE"))
06695                   {
06696                     conj_intr = false;
06697                     pi_count += 2; /* lone pair adds for 2 pi electrons */
06698                   }
06699                 /* conjugation can be restored by a formal charge at a methylene group */
06700                 if (!strcmp (atom[a_ref - 1].element, "C ") &&
06701                     atom[a_ref - 1].formal_charge != 0)
06702                   {
06703                     conj_intr = false;
06704                     pi_count -= atom[a_ref - 1].formal_charge;
06705                     /* neg. charge increases pi_count! */
06706                   }
06707                 /* conjugation can be restored by carbonyl groups etc. */
06708                 if (is_oxo_C (a_ref) || is_thioxo_C (a_ref) |
06709                     is_exocyclic_imino_C (a_ref, i))
06710                   conj_intr = false;
06711                 /* conjugation can be restored by exocyclic C=C double bond, */
06712                 /* adds 2 pi electrons to 5-membered rings, not to 7-membered rings (CAUTION!) */
06713                 /* apply only to non-aromatic exocyclic C=C bonds */
06714                 exo_mC = find_exocyclic_methylene_C (a_ref, i);       /* v0.3j */
06715                 if (exo_mC > 0 && (ring_size & 1))
06716                   {         /* v0.3j */
06717                     b_exo = get_bond (a_ref, exo_mC);   /* v0.3j  */
06718                     ar_exo = bond[b_exo - 1].arom;
06719                     if (((ring_size - 1) & 3) == 0)
06720                      {      /* 5-membered rings and related */
06721                        conj_intr = false;
06722                        pi_count += 2;
06723                      }
06724                     else
06725                      {
06726                        if (!ar_exo)
06727                          conj_intr = false;
06728                      }
06729                   }
06730                 /* 7-membered rings and related */
06731                 /* if conjugation is still interrupted ==> knock-out */
06732                 if (conj_intr)
06733                   ko = true;
06734               }
06735              else
06736               {
06737                 if (bt_bk == 'S' && bt_fw == 'S' && ar_bk == true
06738                     && ar_fw == true)
06739                   {
06740                     if (!strcmp (atom[a_ref - 1].atype, "O3 ") ||
06741                        !strcmp (atom[a_ref - 1].atype, "S3 ") ||
06742                        !strcmp (atom[a_ref - 1].element, "N ") ||
06743                        !strcmp (atom[a_ref - 1].element, "SE"))
06744                      pi_count += 2;       /* lone pair adds for 2 pi electrons */
06745                     if (!strcmp (atom[a_ref - 1].element, "C ") &&
06746                        atom[a_ref - 1].formal_charge != 0)
06747                      pi_count -= atom[a_ref - 1].formal_charge;
06748                     /* neg. charge increases pi_count! */
06749                     exo_mC = find_exocyclic_methylene_C (a_ref, i);   /* v0.3j */
06750                     if (exo_mC > 0 && (ring_size & 1))
06751                      {      /* v0.3j */
06752                        b_exo = get_bond (a_ref, exo_mC);       /* v0.3j */
06753 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
06754                        if (((ring_size - 1) & 3) == 0)
06755                          /* 5-membered rings and related */
06756                          pi_count += 2;
06757                      }
06758                   }
06759                 else
06760                   {
06761                     pi_count++;    /* v0.3j; adjustment for bridgehead N: see below */
06762                     if (bt_bk == 'S' && bt_fw == 'S' &&
06763                        (ar_bk == true && ar_fw == false ||
06764                         ar_bk == false && ar_fw == true))
06765                      {
06766                        /* v0.3j; if a bridgehead N were not aromatic, it could  */
06767                        /* contribute 2 pi electrons --> try also this variant */
06768                        /* (example: CAS 32278-54-9) */
06769                        if (!strcmp (atom[a_ref - 1].element, "N "))
06770                          {
06771                            arom_pi_diff++;
06772                            /* any other case: increase pi count by one electron */
06773                          }
06774                      }
06775                   }
06776               }
06777              /* last command: */
06778              a_prev = a_ref;
06779            }                /* for j := 1 to ring_size */
06780          /* now we can draw our conclusion */
06781          /*if not ((ko) or (odd(pi_count))) then */
06782          if (!ko)
06783            /* v0.3j; odd pi_count might be compensated by arom_pi_diff */
06784            {                /* apply Hueckel's rule */
06785              if (labs (ring_size - pi_count) < 2 &&
06786                 (((pi_count - 2) & 3) == 0 ||
06787                  ((pi_count + arom_pi_diff - 2) & 3) == 0))
06788               {
06789                 /* this ring is aromatic */
06790                 ringprop[i - 1].arom = true;
06791                 /* now mark _all_ bonds in the ring as aromatic */
06792                 a_prev = testring[ring_size - 1];
06793                 for (j = 0; j < ring_size; j++)
06794                   {
06795                     a_ref = testring[j];
06796                     bond[get_bond (a_prev, a_ref) - 1].arom = true;
06797                     a_prev = a_ref;
06798                   }
06799               }
06800            }
06801        }
06802     }                       /* (for i := 1 to n_rings) */
06803   FORLIM = n_bonds;
06804   /* finally, mark all involved atoms as aromatic */
06805   for (i = 0; i < FORLIM; i++)
06806     {
06807       if (bond[i].arom)
06808        {
06809          a1 = bond[i].a1;   /* v0.3n */
06810          a2 = bond[i].a2;   /* v0.3n */
06811          atom[a1 - 1].arom = true;
06812          atom[a2 - 1].arom = true;
06813          /* v0.3n: update atom types if applicable (C and N) */
06814          if (!strcmp (atom[a1 - 1].element, "C "))
06815            strcpy (atom[a1 - 1].atype, "CAR");
06816          if (!strcmp (atom[a2 - 1].element, "C "))
06817            strcpy (atom[a2 - 1].atype, "CAR");
06818          if (!strcmp (atom[a1 - 1].element, "N "))
06819            strcpy (atom[a1 - 1].atype, "NAR");
06820          if (!strcmp (atom[a2 - 1].element, "N "))
06821            strcpy (atom[a2 - 1].atype, "NAR");
06822        }
06823     }
06824   FORLIM = n_rings;
06825   /* update aromaticity information in ringprop */
06826   /* new in v0.3n: accept rings as aromatic if all bonds are of type 'A' */
06827   for (i = 0; i < FORLIM; i++)
06828     {
06829       memcpy (testring, ring[i], sizeof (ringpath_type));
06830       /*ring_size := path_length(testring); */
06831       ring_size = ringprop[i].size;       /* v0.3j */
06832       aromatic = true;
06833       aromatic_bt = true;   /* v0.3n */
06834       a_prev = testring[ring_size - 1];
06835       for (j = 0; j < ring_size; j++)
06836        {
06837          a_ref = testring[j];
06838          b = get_bond (a_prev, a_ref);    /* v0.3n */
06839          if (!bond[b - 1].arom)
06840            aromatic = false;
06841          if (bond[b - 1].btype != 'A')    /* v0.3n */
06842            aromatic_bt = false;
06843          a_prev = a_ref;
06844        }
06845       if (aromatic_bt && !aromatic)
06846        {                    /* v0.3n: update aromaticity flag */
06847          a_prev = testring[ring_size - 1];
06848          for (j = 0; j < ring_size; j++)
06849            {
06850              a_ref = testring[j];
06851              b = get_bond (a_prev, a_ref);
06852              bond[b - 1].arom = true;
06853              if (!strcmp (atom[a_ref - 1].element, "C "))
06854               strcpy (atom[a_ref - 1].atype, "CAR");
06855              if (!strcmp (atom[a_ref - 1].element, "N "))
06856               strcpy (atom[a_ref - 1].atype, "NAR");
06857              a_prev = a_ref;
06858            }
06859          aromatic = true;
06860        }                    /* end v0.3n block   */
06861       if (aromatic)
06862        ringprop[i].arom = true;
06863       else
06864        ringprop[i].arom = false;
06865     }
06866 }
06867 
06868 
06869 static void
06870 write_mol ()
06871 {
06872   int i, j;
06873   ringpath_type testring;
06874   int ring_size, FORLIM;
06875 
06876   /*aromatic : boolean; */
06877   /*a_prev, a_ref : integer; */
06878   if (progmode == pmCheckMol)
06879     printf ("Molecule name: %s\n", molname);
06880   else
06881     printf ("Molecule name (haystack): %s\n", molname);
06882   printf ("atoms: %ld  bonds: %ld  rings: %ld\n", n_atoms, n_bonds, n_rings);
06883   if (n_atoms < 1)
06884     return;
06885   if (n_bonds < 1)
06886     return;
06887   FORLIM = n_atoms;
06888   for (i = 1; i <= FORLIM; i++)
06889     {
06890       if (i < 10)
06891        putchar (' ');
06892       if (i < 100)
06893        putchar (' ');
06894       if (i < 1000)
06895        putchar (' ');
06896       printf ("%ld %s %s %f %f ",
06897              i, atom[i - 1].element, atom[i - 1].atype, atom[i - 1].x,
06898              atom[i - 1].y);
06899       printf ("%f", atom[i - 1].z);
06900       printf ("  (%ld heavy-atom neighbors, Hexp: %ld Htot: %ld)",
06901              atom[i - 1].neighbor_count, atom[i - 1].Hexp, atom[i - 1].Htot);
06902       if (atom[i - 1].formal_charge != 0)
06903        printf ("  charge: %ld", atom[i - 1].formal_charge);
06904       putchar ('\n');
06905     }
06906   FORLIM = n_bonds;
06907   for (i = 1; i <= FORLIM; i++)
06908     {
06909       if (i < 10)
06910        putchar (' ');
06911       if (i < 100)
06912        putchar (' ');
06913       if (i < 1000)
06914        putchar (' ');
06915       printf ("%ld %ld %ld %c",
06916              i, bond[i - 1].a1, bond[i - 1].a2, bond[i - 1].btype);
06917       if (bond[i - 1].ring_count > 0)
06918        printf (", contained in %ld ring(s)", bond[i - 1].ring_count);
06919       if (bond[i - 1].arom)
06920        printf (" (aromatic) ");
06921       putchar ('\n');
06922     }
06923   if (n_rings <= 0)
06924     return;
06925   FORLIM = n_rings;
06926   for (i = 0; i < FORLIM; i++)
06927     {
06928       printf ("ring %ld: ", i + 1);
06929       /*aromatic := true; */
06930       memset (testring, 0, sizeof (ringpath_type));
06931       ring_size = ringprop[i].size;       /* v0.3j */
06932       /*for j := 1 to max_ringsize do if ring^[i,j] > 0 then testring[j] := ring^[i,j]; */
06933       for (j = 0; j < ring_size; j++)     /* v0.3j */
06934        testring[j] = ring[i][j];
06935       /*ring_size := path_length(testring); */
06936       /*a_prev := testring[ring_size]; */
06937       for (j = 0; j < ring_size; j++)
06938        {
06939          printf ("%ld ", testring[j]);
06940          /*a_ref := testring[j]; */
06941          /*if (not bond^[get_bond(a_prev,a_ref)].arom) then aromatic := false; */
06942          /*a_prev := a_ref; */
06943        }
06944       /*if aromatic then write(' (aromatic)'); */
06945       if (ringprop[i].arom)
06946        printf (" (aromatic)");
06947       if (ringprop[i].envelope)
06948        printf (" (env)");
06949       putchar ('\n');
06950     }
06951 }
06952 
06953 
06954 static void
06955 write_needle_mol ()
06956 {
06957   int i, j;
06958   ringpath_type testring;
06959   int ring_size;
06960   boolean aromatic;
06961   int a_prev, a_ref, FORLIM;
06962 
06963   printf ("Molecule name (needle): %s\n", ndl_molname);
06964   printf ("atoms: %ld  bonds: %ld  rings: %ld\n",
06965          ndl_n_atoms, ndl_n_bonds, ndl_n_rings);
06966   if (ndl_n_atoms < 1)
06967     return;
06968   if (ndl_n_bonds < 1)
06969     return;
06970   FORLIM = ndl_n_atoms;
06971   for (i = 1; i <= FORLIM; i++)
06972     {
06973       if (i < 10)
06974        putchar (' ');
06975       if (i < 100)
06976        putchar (' ');
06977       if (i < 1000)
06978        putchar (' ');
06979       printf ("%ld %s %s %f %f ",
06980              i, ndl_atom[i - 1].element, ndl_atom[i - 1].atype,
06981              ndl_atom[i - 1].x, atom[i - 1].y);
06982       printf ("%f", ndl_atom[i - 1].z);
06983       printf ("  (%ld heavy-atom neighbors, Hexp: %ld Htot: %ld)",
06984              ndl_atom[i - 1].neighbor_count, ndl_atom[i - 1].Hexp,
06985              ndl_atom[i - 1].Htot);
06986       if (ndl_atom[i - 1].formal_charge != 0)
06987        printf ("  charge: %ld", ndl_atom[i - 1].formal_charge);
06988       putchar ('\n');
06989     }
06990   FORLIM = ndl_n_bonds;
06991   for (i = 1; i <= FORLIM; i++)
06992     {
06993       if (i < 10)
06994        putchar (' ');
06995       if (i < 100)
06996        putchar (' ');
06997       if (i < 1000)
06998        putchar (' ');
06999       printf ("%ld %ld %ld %c",
07000              i, ndl_bond[i - 1].a1, ndl_bond[i - 1].a2,
07001              ndl_bond[i - 1].btype);
07002       if (ndl_bond[i - 1].ring_count > 0)
07003        printf (", contained in %ld ring(s)", ndl_bond[i - 1].ring_count);
07004       if (ndl_bond[i - 1].arom)
07005        printf (" (aromatic) ");
07006       putchar ('\n');
07007     }
07008   if (ndl_n_rings <= 0)
07009     return;
07010   FORLIM = ndl_n_rings;
07011   for (i = 0; i < FORLIM; i++)
07012     {
07013       aromatic = true;
07014       memset (testring, 0, sizeof (ringpath_type));
07015       for (j = 0; j < max_ringsize; j++)
07016        {
07017          if (ndl_ring[i][j] > 0)
07018            testring[j] = ndl_ring[i][j];
07019        }
07020       ring_size = path_length (testring);
07021       printf ("ring %ld: ", i + 1);
07022       a_prev = testring[ring_size - 1];
07023       for (j = 0; j < ring_size; j++)
07024        {
07025          printf ("%ld ", testring[j]);
07026          a_ref = testring[j];
07027          if (!ndl_bond[get_ndl_bond (a_prev, a_ref) - 1].arom) /* v0.3k */
07028            aromatic = false;
07029          a_prev = a_ref;
07030        }
07031       if (aromatic)
07032        printf (" (aromatic)");
07033       putchar ('\n');
07034     }
07035 }
07036 
07037 
07038 static void
07039 chk_so2_deriv (a_ref)
07040      int a_ref;
07041 {
07042   int i;
07043   neighbor_rec nb;
07044   str2 nb_el;
07045   int het_count = 0, o_count = 0, or_count = 0, hal_count = 0, n_count = 0,
07046     c_count = 0;
07047   int FORLIM;
07048 
07049   memset (nb, 0, sizeof (neighbor_rec));
07050   if (strcmp (atom[a_ref - 1].atype, "SO2"))
07051     return;
07052   get_neighbors (nb, a_ref);
07053   FORLIM = atom[a_ref - 1].neighbor_count;
07054   for (i = 0; i < FORLIM; i++)
07055     {
07056       if (bond[get_bond (a_ref, nb[i]) - 1].btype == 'S')
07057        {
07058          strcpy (nb_el, atom[nb[i] - 1].element);
07059          if (strcmp (nb_el, "C ") && strcmp (nb_el, "H ")
07060              /*&&  strcmp (nb_el, "D ") */  && strcmp (nb_el, "DU")
07061              && strcmp (nb_el, "LP"))
07062            /* added 'D ' in v0.3n */
07063            het_count++;
07064          if (!strcmp (nb_el, "O "))
07065            {
07066              o_count++;
07067              if (is_alkoxy (a_ref, nb[i]) || is_aryloxy (a_ref, nb[i]))
07068               or_count++;
07069            }
07070          if (!strcmp (nb_el, "N "))
07071            n_count++;
07072          if (!strcmp (nb_el, "C "))
07073            c_count++;
07074          if (!strcmp (nb_el, "F ") || !strcmp (nb_el, "CL") ||
07075              !strcmp (nb_el, "BR") || !strcmp (nb_el, "I ")
07076              || !strcmp (nb_el, "AT"))
07077            hal_count++;
07078        }
07079     }
07080   if (het_count == 2)
07081     {                       /* sulfuric acid derivative */
07082       fg[fg_sulfuric_acid_deriv - 1] = true;
07083       if (o_count == 2)
07084        {
07085          if (or_count == 0)
07086            fg[fg_sulfuric_acid - 1] = true;
07087          if (or_count == 1)
07088            fg[fg_sulfuric_acid_monoester - 1] = true;
07089          if (or_count == 2)
07090            fg[fg_sulfuric_acid_diester - 1] = true;
07091        }
07092       if (o_count == 1)
07093        {
07094          if (or_count == 1 && n_count == 1)
07095            fg[fg_sulfuric_acid_amide_ester - 1] = true;
07096          if (or_count == 0 && n_count == 1)
07097            fg[fg_sulfuric_acid_amide - 1] = true;
07098        }
07099       if (n_count == 2)
07100        fg[fg_sulfuric_acid_diamide - 1] = true;
07101       if (hal_count > 0)
07102        fg[fg_sulfuryl_halide - 1] = true;
07103     }
07104   if (het_count == 1 && c_count == 1)
07105     {                       /* sulfonic acid derivative */
07106       fg[fg_sulfonic_acid_deriv - 1] = true;
07107       if (o_count == 1 && or_count == 0)
07108        fg[fg_sulfonic_acid - 1] = true;
07109       if (o_count == 1 && or_count == 1)
07110        fg[fg_sulfonic_acid_ester - 1] = true;
07111       if (n_count == 1)
07112        fg[fg_sulfonamide - 1] = true;
07113       if (hal_count == 1)
07114        fg[fg_sulfonyl_halide - 1] = true;
07115     }
07116   if (het_count == 0 && c_count == 2)     /* sulfone */
07117     fg[fg_sulfone - 1] = true;
07118 }
07119 
07120 
07121 static void
07122 chk_p_deriv (a_ref)
07123      int a_ref;
07124 {
07125   int i;
07126   neighbor_rec nb;
07127   str2 nb_el, dbl_het;
07128   int het_count;
07129   int oh_count = 0, or_count = 0, hal_count = 0, n_count = 0, c_count = 0;
07130   int FORLIM;
07131 
07132   if (strcmp (atom[a_ref - 1].element, "P "))
07133     return;
07134   memset (nb, 0, sizeof (neighbor_rec));
07135   get_neighbors (nb, a_ref);
07136   *dbl_het = '\0';
07137 /* p2c: checkmol.pas: Note: Eliminated unused assignment statement [338] */
07138   FORLIM = atom[a_ref - 1].neighbor_count;
07139   for (i = 0; i < FORLIM; i++)
07140     {
07141       if (bond[get_bond (a_ref, nb[i]) - 1].btype == 'D')
07142        strcpy (dbl_het, atom[nb[i] - 1].element);
07143       if (bond[get_bond (a_ref, nb[i]) - 1].btype == 'S')
07144        {
07145          strcpy (nb_el, atom[nb[i] - 1].element);
07146          if (!strcmp (nb_el, "C "))
07147            c_count++;
07148          if (is_hydroxy (a_ref, nb[i]))
07149            oh_count++;
07150          if (is_alkoxy (a_ref, nb[i]) || is_aryloxy (a_ref, nb[i]))
07151            or_count++;
07152          if (!strcmp (nb_el, "N "))
07153            n_count++;
07154          if (!strcmp (nb_el, "F ") || !strcmp (nb_el, "CL") ||
07155              !strcmp (nb_el, "BR") || !strcmp (nb_el, "I ")
07156              || !strcmp (nb_el, "AT"))
07157            hal_count++;
07158        }
07159     }
07160   het_count = oh_count + or_count + hal_count + n_count;
07161   if (!strcmp (atom[a_ref - 1].atype, "P3D") ||
07162       !strcmp (atom[a_ref - 1].atype, "P4 "))
07163     {
07164       if (!strcmp (dbl_het, "O "))
07165        {
07166          if (c_count == 0)
07167            {
07168              fg[fg_phosphoric_acid_deriv - 1] = true;
07169              if (oh_count == 3)
07170               fg[fg_phosphoric_acid - 1] = true;
07171              if (or_count > 0)
07172               fg[fg_phosphoric_acid_ester - 1] = true;
07173              if (hal_count > 0)
07174               fg[fg_phosphoric_acid_halide - 1] = true;
07175              if (n_count > 0)
07176               fg[fg_phosphoric_acid_amide - 1] = true;
07177            }
07178          if (c_count == 1)
07179            {
07180              fg[fg_phosphonic_acid_deriv - 1] = true;
07181              if (oh_count == 2)
07182               fg[fg_phosphonic_acid - 1] = true;
07183              if (or_count > 0)
07184               fg[fg_phosphonic_acid_ester - 1] = true;
07185              /*if (hal_count > 0)  then fg[fg_phosphonic_acid_halide] := true;             */
07186              /*if (n_count > 0)    then fg[fg_phosphonic_acid_amide]  := true; */
07187            }
07188          if (c_count == 3)
07189            fg[fg_phosphinoxide - 1] = true;
07190        }
07191       if (!strcmp (dbl_het, "S "))
07192        {
07193          if (c_count == 0)
07194            {
07195              fg[fg_thiophosphoric_acid_deriv - 1] = true;
07196              if (oh_count == 3)
07197               fg[fg_thiophosphoric_acid - 1] = true;
07198              if (or_count > 0)
07199               fg[fg_thiophosphoric_acid_ester - 1] = true;
07200              if (hal_count > 0)
07201               fg[fg_thiophosphoric_acid_halide - 1] = true;
07202              if (n_count > 0)
07203               fg[fg_thiophosphoric_acid_amide - 1] = true;
07204            }
07205        }
07206     }
07207   /*  if (atom^[a_ref].atype = 'P4 ') then fg[fg_phosphoric_acid_deriv] := true; */
07208   if (strcmp (atom[a_ref - 1].atype, "P3 "))     /* changed P3D into P3 in v0.3b */
07209     return;
07210   if (c_count == 3 && het_count == 0)
07211     fg[fg_phosphine - 1] = true;
07212   if (c_count == 3 && oh_count == 1)
07213     fg[fg_phosphinoxide - 1] = true;
07214 }
07215 
07216 
07217 static void
07218 chk_b_deriv (a_ref)
07219      int a_ref;
07220 {
07221   int i;
07222   neighbor_rec nb;
07223   str2 nb_el;
07224   int het_count = 0, oh_count = 0, or_count = 0, hal_count = 0, n_count = 0,
07225     c_count = 0;
07226   int FORLIM;
07227 
07228   if (strcmp (atom[a_ref - 1].element, "B "))
07229     return;
07230   memset (nb, 0, sizeof (neighbor_rec));
07231   get_neighbors (nb, a_ref);
07232   FORLIM = atom[a_ref - 1].neighbor_count;
07233   for (i = 0; i < FORLIM; i++)
07234     {
07235       if (bond[get_bond (a_ref, nb[i]) - 1].btype == 'S')
07236        {
07237          strcpy (nb_el, atom[nb[i] - 1].element);
07238          if (!strcmp (nb_el, "C "))
07239            c_count++;
07240          else if (strcmp (nb_el, "H ") /*&& strcmp (nb_el, "D ") */  &&
07241                  strcmp (nb_el, "LP"))
07242            /* v0.3n: D */
07243            het_count++;
07244          if (is_hydroxy (a_ref, nb[i]))
07245            oh_count++;
07246          if (is_alkoxy (a_ref, nb[i]) || is_aryloxy (a_ref, nb[i]))
07247            /* fixed in v0.3b */
07248            or_count++;
07249          if (!strcmp (nb_el, "N "))
07250            n_count++;
07251          if (!strcmp (nb_el, "F ") || !strcmp (nb_el, "CL") ||
07252              !strcmp (nb_el, "BR") || !strcmp (nb_el, "I ")
07253              || !strcmp (nb_el, "AT"))
07254            hal_count++;
07255        }
07256     }
07257   het_count = oh_count + or_count + hal_count + n_count;
07258   /* fixed in v0.3b */
07259   if (c_count != 1 || het_count != 2)
07260     return;
07261   fg[fg_boronic_acid_deriv - 1] = true;
07262   if (oh_count == 2)
07263     fg[fg_boronic_acid - 1] = true;
07264   if (or_count > 0)
07265     fg[fg_boronic_acid_ester - 1] = true;
07266 }
07267 
07268 
07269 static void
07270 chk_ammon (a_ref)
07271      int a_ref;
07272 {
07273   int i;
07274   neighbor_rec nb;
07275   str2 nb_el;
07276   int het_count = 0, o_count = 0, or_count = 0, r_count = 0;
07277   char bt;                  /* v0.3k */
07278   float bo_sum = 0.0;
07279   boolean ha;
07280   int FORLIM;
07281 
07282   memset (nb, 0, sizeof (neighbor_rec));
07283   if (strcmp (atom[a_ref - 1].atype, "N3+")
07284       && atom[a_ref - 1].formal_charge == 0)
07285     return;
07286   if (strcmp (atom[a_ref - 1].element, "N "))    /* just to be sure;  v0.3i */
07287     return;
07288   get_neighbors (nb, a_ref);
07289   FORLIM = atom[a_ref - 1].neighbor_count;
07290   for (i = 0; i < FORLIM; i++)
07291     {
07292       bt = bond[get_bond (a_ref, nb[i]) - 1].btype;     /* v0.3k */
07293       strcpy (nb_el, atom[nb[i] - 1].element);   /* v0.3k */
07294       ha = atom[nb[i] - 1].heavy;  /* v0.3k */
07295       if (bt == 'S')
07296        {
07297          if (ha)
07298            bo_sum += 1.0;
07299          if (strcmp (nb_el, "C ") && strcmp (nb_el, "H ")
07300              /*&&  strcmp (nb_el, "D ") */  && strcmp (nb_el, "DU"))
07301            {                /* added 'D ' in v0.3n */
07302              het_count++;
07303              if (!strcmp (nb_el, "O "))
07304               {
07305                 o_count++;
07306                 if (atom[nb[i] - 1].neighbor_count > 1)
07307                   or_count++;
07308               }
07309            }
07310          if (is_alkyl (a_ref, nb[i]) || is_aryl (a_ref, nb[i]) |
07311              is_alkenyl (a_ref, nb[i]) || is_alkynyl (a_ref, nb[i]))
07312            /* v0.3k */
07313            r_count++;
07314        }
07315       if (bt == 'D')
07316        {
07317          if (ha)
07318            bo_sum += 2.0;
07319          if (strcmp (nb_el, "C "))
07320            {
07321              het_count += 2;
07322              if (!strcmp (nb_el, "O "))
07323               o_count += 2;
07324            }
07325          if (!strcmp (nb_el, "C "))
07326            r_count++;
07327        }
07328       if (bt == 'A' && ha)
07329        bo_sum += 1.5;
07330     }                       /* v0.3k: corrected end of "for ..." loop */
07331   if (het_count == 0 && r_count == 4)
07332     fg[fg_quart_ammonium - 1] = true;
07333   if (het_count != 1 || atom[a_ref - 1].neighbor_count < 3)
07334     return;
07335   if (o_count == 1 && or_count == 0 && bo_sum > 3)
07336     fg[fg_n_oxide - 1] = true;     /* finds only aliphatic N-oxides! */
07337   if ((o_count == 1 && or_count == 1 || o_count == 0) &&
07338       atom[a_ref - 1].arom == true)
07339     fg[fg_quart_ammonium - 1] = true;
07340 }
07341 
07342 
07343 static void
07344 swap_atoms (a1, a2)
07345      int *a1, *a2;
07346 {
07347   int a_tmp;
07348 
07349   a_tmp = *a1;
07350   *a1 = *a2;
07351   *a2 = a_tmp;
07352 }
07353 
07354 
07355 static void
07356 orient_bond (a1, a2)
07357      int *a1, *a2;
07358 {
07359   str2 a1_el, a2_el;
07360 
07361   strcpy (a1_el, atom[*a1 - 1].element);
07362   strcpy (a2_el, atom[*a2 - 1].element);
07363   if (!strcmp (a1_el, "H ") || !strcmp (a2_el, "H ")
07364       || !strcmp (a1_el, "D ") || !strcmp (a2_el, "D "))
07365     /* v0.3n: D */
07366     return;
07367   if (!strcmp (a2_el, "C ") && strcmp (a1_el, "C "))
07368     swap_atoms (a1, a2);
07369   if (!strcmp (a2_el, a1_el))
07370     {
07371       if (hetbond_count (*a1) > hetbond_count (*a2))
07372        swap_atoms (a1, a2);
07373     }
07374   if (strcmp (a2_el, "C ") && strcmp (a1_el, "C ") && strcmp (a1_el, a2_el))
07375     {
07376       if (!strcmp (a1_el, "O ") || !strcmp (a2_el, "O "))
07377        {
07378          if (!strcmp (a1_el, "O "))
07379            swap_atoms (a1, a2);
07380        }
07381     }
07382   if (strcmp (a2_el, "C ") && strcmp (a1_el, "C ") && !strcmp (a1_el, a2_el))
07383     {
07384       if (atom[*a2 - 1].neighbor_count - hetbond_count (*a2) >
07385          atom[*a1 - 1].neighbor_count - hetbond_count (*a1))
07386        swap_atoms (a1, a2);
07387     }
07388 }
07389 
07390 
07391 static void
07392 chk_imine (a_ref, a_view)
07393      int a_ref, a_view;
07394 {
07395   /* a_ref = C, a_view = N */
07396   int i;
07397   neighbor_rec nb;
07398   str2 nb_el;
07399   int a_het, a_c;
07400   int het_count = 0, c_count = 0, o_count = 0;   /* v0.3k */
07401   int FORLIM;
07402 
07403   /* v0.3k */
07404   if (atom[a_view - 1].neighbor_count == 1)
07405     {
07406       if (atom[a_ref - 1].arom == false)
07407        fg[fg_imine - 1] = true;
07408       return;
07409     }
07410   memset (nb, 0, sizeof (neighbor_rec));
07411   get_neighbors (nb, a_view);
07412   if (atom[a_view - 1].neighbor_count <= 1)
07413     return;
07414   FORLIM = atom[a_view - 1].neighbor_count;
07415   for (i = 0; i < FORLIM; i++)
07416     {
07417       if ((nb[i] != a_ref) && (bond[get_bond (a_view, nb[i]) - 1].btype ==
07418                             'S'))
07419        {
07420          strcpy (nb_el, atom[nb[i] - 1].element);
07421          if (!strcmp (nb_el, "C "))
07422            {
07423              a_c = nb[i];
07424              c_count++;
07425            }
07426          if (!strcmp (nb_el, "O ") || !strcmp (nb_el, "N "))
07427            {
07428              a_het = nb[i];
07429              het_count++;
07430            }
07431          if ((!strcmp (nb_el, "O ")
07432               && atom[nb[i] - 1].neighbor_count ==
07433               1) && (bond[get_bond (a_view, nb[i]) - 1].arom == false))
07434            /* v0.3k */
07435            o_count++;
07436        }
07437       if ((nb[i] != a_ref) && (bond[get_bond (a_view, nb[i]) - 1].btype ==
07438                             'D'))
07439        {                    /* v0.3k; make sure we do not count nitro groups in "azi" form etc. */
07440          strcpy (nb_el, atom[nb[i] - 1].element);
07441          if (!strcmp (nb_el, "O ") || !strcmp (nb_el, "N ")
07442              || !strcmp (nb_el, "S "))
07443            {
07444              a_het = nb[i]; /* v0.3m */
07445              het_count++;
07446            }
07447          if ((!strcmp (nb_el, "O ")
07448               && atom[nb[i] - 1].neighbor_count ==
07449               1) && (bond[get_bond (a_view, nb[i]) - 1].arom == false))
07450            /* v0.3k */
07451            o_count++;
07452        }
07453     }
07454   if (c_count == 1)
07455     {
07456       if ((is_alkyl (a_view, a_c) || is_aryl (a_view, a_c) |
07457           is_alkenyl (a_view, a_c) || is_alkynyl (a_view, a_c))
07458          && atom[a_ref - 1].arom == false && het_count == 0)
07459        /* v0.3k */
07460        fg[fg_imine - 1] = true;
07461     }
07462   if (het_count == 1)
07463     {
07464       strcpy (nb_el, atom[a_het - 1].element);
07465       if (!strcmp (nb_el, "O "))
07466        {
07467          if (is_hydroxy (a_view, a_het))
07468            fg[fg_oxime - 1] = true;
07469          if (is_alkoxy (a_view, a_het) || is_aryloxy (a_view, a_het) |
07470              is_alkenyloxy (a_view, a_het) || is_alkynyloxy (a_view, a_het))
07471            fg[fg_oxime_ether - 1] = true;
07472        }
07473       if (!strcmp (nb_el, "N "))
07474        {
07475          if (is_amino (a_view, a_het) || is_alkylamino (a_view, a_het) |
07476              is_dialkylamino (a_view, a_het) || is_alkylarylamino (a_view,
07477                                                             a_het) |
07478              is_arylamino (a_view, a_het) || is_diarylamino (a_view, a_het))
07479            fg[fg_hydrazone - 1] = true;
07480          else
07481            {
07482              memset (nb, 0, sizeof (neighbor_rec));
07483              get_neighbors (nb, a_het);
07484              if (atom[a_het - 1].neighbor_count > 1)
07485               {
07486                 FORLIM = atom[a_het - 1].neighbor_count;
07487                 for (i = 0; i < FORLIM; i++)
07488                   {
07489                     if (nb[i] != a_view)
07490                      {
07491                        if (is_carbamoyl (a_het, nb[i]))
07492                          fg[fg_semicarbazone - 1] = true;
07493                        if (is_thiocarbamoyl (a_het, nb[i]))
07494                          fg[fg_thiosemicarbazone - 1] = true;
07495                      }
07496                   }
07497               }
07498            }
07499        }
07500     }                       /* v0.3k: nitro groups in "azi" form */
07501   /* check for semicarbazone or thiosemicarbazone */
07502   if (het_count == 2 && o_count == 2)
07503     fg[fg_nitro_compound - 1] = true;
07504 }
07505 
07506 
07507 static void
07508 chk_carbonyl_deriv (a_view, a_ref)
07509      int a_view, a_ref;
07510 {
07511   /* a_view = C */
07512   int i;
07513   neighbor_rec nb;
07514   str2 nb_el;
07515   int c_count = 0, cn_count = 0;
07516   char bt;                  /* new in v0.3b */
07517   int n_db = 0;                    /* new in v0.3b */
07518   int FORLIM;
07519 
07520   memset (nb, 0, sizeof (neighbor_rec));
07521   get_neighbors (nb, a_view);
07522   FORLIM = atom[a_view - 1].neighbor_count;
07523   /* new in v0.3b */
07524   for (i = 0; i < FORLIM; i++)
07525     {
07526       bt = bond[get_bond (a_view, nb[i]) - 1].btype;
07527       if (bt == 'S')
07528        {
07529          strcpy (nb_el, atom[nb[i] - 1].element);
07530          if (!strcmp (nb_el, "C "))
07531            {
07532              if (is_cyano_c (nb[i]))
07533               cn_count++;
07534              else
07535               c_count++;
07536            }
07537        }
07538       else
07539        {
07540          if (bt == 'D')
07541            n_db++;
07542        }
07543     }
07544   /* new in v0.3b */
07545   if (is_oxo_C (a_view))
07546     {
07547       fg[fg_carbonyl - 1] = true;
07548       if (c_count + cn_count < 2)
07549        {                    /* new in v0.3b (detection of ketenes) */
07550          if (n_db <= 1)
07551            fg[fg_aldehyde - 1] = true;
07552          else
07553            fg[fg_ketene - 1] = true;
07554        }
07555       if (c_count == 2)
07556        {
07557          if (atom[a_view - 1].arom)
07558            fg[fg_oxohetarene - 1] = true;
07559          else
07560            fg[fg_ketone - 1] = true;
07561        }
07562       if (cn_count > 0)
07563        fg[fg_acyl_cyanide - 1] = true;
07564     }
07565   if (is_thioxo_C (a_view))
07566     {
07567       fg[fg_thiocarbonyl - 1] = true;
07568       if (c_count < 2)
07569        fg[fg_thioaldehyde - 1] = true;
07570       if (c_count == 2)
07571        {
07572          if (atom[a_view - 1].arom)
07573            fg[fg_thioxohetarene - 1] = true;
07574          else
07575            fg[fg_thioketone - 1] = true;
07576        }
07577     }
07578   if (is_imino_C (a_view))
07579     chk_imine (a_view, a_ref);
07580 }
07581 
07582 
07583 static void
07584 chk_carboxyl_deriv (a_view, a_ref)
07585      int a_view, a_ref;
07586 {
07587   int i;
07588   neighbor_rec nb;
07589   str2 nb_el;
07590   int o_count = 0, n_count = 0, s_count = 0;
07591   int a_o, a_n, a_s, FORLIM;
07592 
07593   memset (nb, 0, sizeof (neighbor_rec));
07594   get_neighbors (nb, a_view);
07595   FORLIM = atom[a_view - 1].neighbor_count;
07596   for (i = 0; i < FORLIM; i++)
07597     {
07598       if (bond[get_bond (a_view, nb[i]) - 1].btype == 'S')
07599        {
07600          strcpy (nb_el, atom[nb[i] - 1].element);
07601          if (strcmp (nb_el, "C "))
07602            {
07603              if (!strcmp (nb_el, "O "))
07604               {
07605                 o_count++;
07606                 a_o = nb[i];
07607               }
07608              if (!strcmp (nb_el, "N "))
07609               {
07610                 n_count++;
07611                 a_n = nb[i];
07612               }
07613              if (!strcmp (nb_el, "S "))
07614               {
07615                 s_count++;
07616                 a_s = nb[i];
07617               }
07618            }
07619        }
07620     }
07621   if (is_oxo_C (a_view))
07622     {
07623       if (o_count == 1)
07624        {                    /* anhydride is checked somewhere else */
07625          if (bond[get_bond (a_view, a_o) - 1].arom == false)
07626            fg[fg_carboxylic_acid_deriv - 1] = true;
07627          if (is_hydroxy (a_view, a_o))
07628            {
07629              if (atom[a_o - 1].formal_charge == 0)
07630               fg[fg_carboxylic_acid - 1] = true;
07631              if (atom[a_o - 1].formal_charge == -1)
07632               fg[fg_carboxylic_acid_salt - 1] = true;
07633            }
07634          if (is_alkoxy (a_view, a_o) || is_aryloxy (a_view, a_o) |
07635              is_alkenyloxy (a_view, a_o) || is_alkynyloxy (a_view, a_o))
07636            {
07637              if (bond[get_bond (a_view, a_o) - 1].arom == false)
07638               fg[fg_carboxylic_acid_ester - 1] = true;
07639              if (bond[get_bond (a_view, a_o) - 1].ring_count > 0)
07640               {
07641                 if (bond[get_bond (a_view, a_o) - 1].arom == true)
07642                   {
07643                     /*fg[fg_lactone_heteroarom] := true else fg[fg_lactone] := true; */
07644                     fg[fg_oxohetarene - 1] = true;
07645                   }
07646                 else
07647                   fg[fg_lactone - 1] = true;
07648               }
07649            }
07650        }
07651       if (n_count == 1)
07652        {
07653          if (bond[get_bond (a_view, a_n) - 1].arom == false)
07654            fg[fg_carboxylic_acid_deriv - 1] = true;
07655          else
07656            {
07657              /*fg[fg_lactam_heteroarom] := true;  (* catches also pyridazines, 1,2,3-triazines, etc. */
07658              fg[fg_oxohetarene - 1] = true;
07659            }
07660          if (is_amino (a_view, a_n)
07661              || (!strcmp (atom[a_n - 1].atype, "NAM")
07662                 && atom[a_n - 1].neighbor_count == 1))
07663            {
07664              fg[fg_carboxylic_acid_amide - 1] = true;
07665              fg[fg_carboxylic_acid_prim_amide - 1] = true;
07666            }
07667          /*if (is_alkylamino(a_view,a_n)) or (is_arylamino(a_view,a_n)) then  */
07668          if (is_C_monosubst_amino (a_view, a_n) &
07669              (!is_subst_acylamino (a_view, a_n)))
07670            {                /* v0.3j */
07671              if (bond[get_bond (a_view, a_n) - 1].arom == false)
07672               fg[fg_carboxylic_acid_amide - 1] = true;
07673              if (bond[get_bond (a_view, a_n) - 1].arom == false)
07674               fg[fg_carboxylic_acid_sec_amide - 1] = true;
07675              if (bond[get_bond (a_view, a_n) - 1].ring_count > 0)
07676               {
07677                 if (bond[get_bond (a_view, a_n) - 1].arom == true)
07678                   {
07679                     /*fg[fg_lactam_heteroarom]    := true else  */
07680                     fg[fg_oxohetarene - 1] = true;
07681                   }
07682                 else
07683                   fg[fg_lactam - 1] = true;
07684               }
07685            }
07686          /*if (is_dialkylamino(a_view,a_n)) or (is_alkylarylamino(a_view,a_n)) or */
07687          /*   (is_diarylamino(a_view,a_n)) then  */
07688          if (is_C_disubst_amino (a_view, a_n) &
07689              (!is_subst_acylamino (a_view, a_n)))
07690            {                /* v0.3j */
07691              if (bond[get_bond (a_view, a_n) - 1].arom == false)
07692               fg[fg_carboxylic_acid_amide - 1] = true;
07693              if (bond[get_bond (a_view, a_n) - 1].arom == false)
07694               fg[fg_carboxylic_acid_tert_amide - 1] = true;
07695              if (bond[get_bond (a_view, a_n) - 1].ring_count > 0)
07696               {
07697                 if (bond[get_bond (a_view, a_n) - 1].arom == true)
07698                   {
07699                     /*fg[fg_lactam_heteroarom]    := true else  */
07700                     fg[fg_oxohetarene - 1] = true;
07701                   }
07702                 else
07703                   fg[fg_lactam - 1] = true;
07704               }
07705            }
07706          if (is_hydroxylamino (a_view, a_n))
07707            fg[fg_hydroxamic_acid - 1] = true;
07708          if (is_hydrazino (a_view, a_n))
07709            fg[fg_carboxylic_acid_hydrazide - 1] = true;
07710          if (is_azido (a_view, a_n))
07711            fg[fg_carboxylic_acid_azide - 1] = true;
07712        }
07713       if (s_count == 1)
07714        {                    /* anhydride is checked somewhere else */
07715          if (bond[get_bond (a_view, a_s) - 1].arom == false)
07716            fg[fg_thiocarboxylic_acid_deriv - 1] = true;
07717          if (is_sulfanyl (a_view, a_s))
07718            fg[fg_thiocarboxylic_acid - 1] = true;
07719          if (is_alkylsulfanyl (a_view, a_s) || is_arylsulfanyl (a_view, a_s))
07720            {
07721              if (bond[get_bond (a_view, a_s) - 1].arom == false)
07722               fg[fg_thiocarboxylic_acid_ester - 1] = true;
07723              if (bond[get_bond (a_view, a_s) - 1].ring_count > 0)
07724               {
07725                 if (bond[get_bond (a_view, a_s) - 1].arom == true)
07726                   {
07727                     /*fg[fg_thiolactone_heteroarom] := true else fg[fg_thiolactone] := true; */
07728                     fg[fg_oxohetarene - 1] = true;
07729                   }
07730                 else
07731                   fg[fg_thiolactone - 1] = true;
07732               }
07733            }
07734        }
07735     }                       /* end Oxo-C */
07736   if (is_thioxo_C (a_view))
07737     {
07738       /* fg[fg_thiocarboxylic_acid_deriv]  := true; */
07739       if (o_count == 1)
07740        {                    /* anhydride is checked somewhere else */
07741          if (bond[get_bond (a_view, a_o) - 1].arom == false)
07742            fg[fg_thiocarboxylic_acid_deriv - 1] = true;
07743          if (is_hydroxy (a_view, a_o))
07744            fg[fg_thiocarboxylic_acid - 1] = true;       /* fixed in v0.3c */
07745          if (is_alkoxy (a_view, a_o) || is_aryloxy (a_view, a_o))
07746            {
07747              if (bond[get_bond (a_view, a_s) - 1].arom == false)
07748               fg[fg_thiocarboxylic_acid_ester - 1] = true;
07749              if (bond[get_bond (a_view, a_o) - 1].ring_count > 0)
07750               {
07751                 if (bond[get_bond (a_view, a_o) - 1].arom == true)
07752                   {
07753                     /*fg[fg_thiolactone_heteroarom] := true else fg[fg_thiolactone] := true; */
07754                     fg[fg_thioxohetarene - 1] = true;
07755                   }
07756                 else
07757                   fg[fg_thiolactone - 1] = true;
07758               }
07759            }
07760        }
07761       if (n_count == 1)
07762        {
07763          if (bond[get_bond (a_view, a_n) - 1].arom == false)
07764            fg[fg_thiocarboxylic_acid_deriv - 1] = true;
07765          else
07766            {
07767              /*fg[fg_thiolactam_heteroarom] := true;  (* catches also pyridazines, 1,2,3-triazines, etc. */
07768              fg[fg_thioxohetarene - 1] = true;
07769            }
07770          /* catches also pyridazines, 1,2,3-triazines, etc. */
07771          if (is_amino (a_view, a_n))
07772            {
07773              fg[fg_thiocarboxylic_acid_amide - 1] = true;
07774              /* fg[fg_thiocarboxylic_acid_prim_amide] := true; */
07775            }
07776          /*if (is_alkylamino(a_view,a_n)) or (is_arylamino(a_view,a_n)) then  */
07777          if (is_C_monosubst_amino (a_view, a_n) &
07778              (!is_subst_acylamino (a_view, a_n)))
07779            {                /* v0.3j */
07780              if (bond[get_bond (a_view, a_n) - 1].arom == false)
07781               fg[fg_thiocarboxylic_acid_amide - 1] = true;
07782              /*fg[fg_thiocarboxylic_acid_sec_amide]  := true; */
07783              if (bond[get_bond (a_view, a_n) - 1].ring_count > 0)
07784               {
07785                 if (bond[get_bond (a_view, a_n) - 1].arom == true)
07786                   {
07787                     /*fg[fg_thiolactam_heteroarom] := true else fg[fg_thiolactam] := true; */
07788                     fg[fg_thioxohetarene - 1] = true;
07789                   }
07790                 else
07791                   fg[fg_thiolactam - 1] = true;
07792               }
07793            }
07794          /*if (is_dialkylamino(a_view,a_n)) or (is_alkylarylamino(a_view,a_n)) or */
07795          /*   (is_diarylamino(a_view,a_n)) then  */
07796          if (is_C_disubst_amino (a_view, a_n) &
07797              (!is_subst_acylamino (a_view, a_n)))
07798            {                /* v0.3j */
07799              if (bond[get_bond (a_view, a_n) - 1].arom == false)
07800               fg[fg_thiocarboxylic_acid_amide - 1] = true;
07801              /*fg[fg_thiocarboxylic_acid_tert_amide] := true; */
07802              if (bond[get_bond (a_view, a_n) - 1].ring_count > 0)
07803               {
07804                 if (bond[get_bond (a_view, a_n) - 1].arom == true)
07805                   {
07806                     /*fg[fg_thiolactam_heteroarom] := true else fg[fg_thiolactam] := true; */
07807                     fg[fg_thioxohetarene - 1] = true;
07808                   }
07809                 else
07810                   fg[fg_thiolactam - 1] = true;
07811               }
07812            }
07813        }
07814       if (s_count == 1)
07815        {                    /* anhydride is checked somewhere else */
07816          if (bond[get_bond (a_view, a_s) - 1].arom == false)
07817            fg[fg_thiocarboxylic_acid_deriv - 1] = true;
07818          if (is_sulfanyl (a_view, a_s))
07819            fg[fg_thiocarboxylic_acid - 1] = true;
07820          if (is_alkylsulfanyl (a_view, a_s) || is_arylsulfanyl (a_view, a_s))
07821            {
07822              if (bond[get_bond (a_view, a_s) - 1].arom == false)
07823               fg[fg_thiocarboxylic_acid_ester - 1] = true;
07824              if (bond[get_bond (a_view, a_s) - 1].ring_count > 0)
07825               {
07826                 if (bond[get_bond (a_view, a_s) - 1].arom == true)
07827                   {
07828                     /*fg[fg_thiolactone_heteroarom] := true else fg[fg_thiolactone] := true; */
07829                     fg[fg_thioxohetarene - 1] = true;
07830                   }
07831                 else
07832                   fg[fg_thiolactone - 1] = true;
07833               }
07834            }
07835        }
07836     }                       /* end Thioxo-C */
07837   if (is_true_imino_C (a_view))
07838     {
07839       if (o_count == 1)
07840        {
07841          if (bond[get_bond (a_view, a_o) - 1].arom == false)
07842            fg[fg_carboxylic_acid_deriv - 1] = true;
07843          if (is_alkoxy (a_view, a_o) || is_aryloxy (a_view, a_o))
07844            {
07845              if (bond[get_bond (a_view, a_o) - 1].arom == false)
07846               fg[fg_imido_ester - 1] = true;
07847            }
07848        }
07849       if ((n_count == 1) && (bond[get_bond (a_view, a_n) - 1].arom == false))
07850        {
07851          if (bond[get_bond (a_view, a_n) - 1].arom == false)
07852            fg[fg_carboxylic_acid_deriv - 1] = true;
07853          if (is_amino (a_view, a_n) || is_subst_amino (a_view, a_n))
07854            {
07855              if (bond[get_bond (a_view, a_n) - 1].arom == false)
07856               fg[fg_carboxylic_acid_deriv - 1] = true;
07857              fg[fg_carboxylic_acid_amidine - 1] = true;
07858            }
07859          if (is_hydrazino (a_view, a_n))
07860            {
07861              if (bond[get_bond (a_view, a_n) - 1].arom == false)
07862               fg[fg_carboxylic_acid_amidrazone - 1] = true;
07863            }
07864        }
07865       if ((n_count == 1) && (bond[get_bond (a_view, a_n) - 1].arom == true))
07866        /* catches also pyridazines, 1,2,3-triazines, etc. */
07867        fg[fg_iminohetarene - 1] = true;
07868       if (s_count == 1)
07869        {
07870          if (bond[get_bond (a_view, a_s) - 1].arom == false)
07871            fg[fg_carboxylic_acid_deriv - 1] = true;
07872          if (is_alkylsulfanyl (a_view, a_s) || is_arylsulfanyl (a_view, a_s))
07873            {
07874              if (bond[get_bond (a_view, a_s) - 1].arom == false)
07875               fg[fg_imido_thioester - 1] = true;
07876            }
07877        }
07878     }
07879   if (is_hydroximino_C (a_view))
07880     {
07881       if (bond[get_bond (a_view, a_n) - 1].arom == false)
07882        fg[fg_carboxylic_acid_deriv - 1] = true;
07883       if (o_count == 1)
07884        {
07885          if (is_hydroxy (a_view, a_o))
07886            fg[fg_hydroxamic_acid - 1] = true;
07887        }
07888     }
07889   if (!is_hydrazono_C (a_view))
07890     return;
07891   if (bond[get_bond (a_view, a_n) - 1].arom == false)
07892     fg[fg_carboxylic_acid_deriv - 1] = true;
07893   if (n_count == 1)
07894     {
07895       if (is_amino (a_view, a_n) || is_subst_amino (a_view, a_n))
07896        fg[fg_carboxylic_acid_amidrazone - 1] = true;
07897     }
07898 }
07899 
07900 
07901 static void
07902 chk_co2_sp2 (a_view, a_ref)
07903      int a_view, a_ref;
07904 {
07905   int i;
07906   neighbor_rec nb;
07907   str2 nb_el;
07908   int o_count = 0, or_count = 0, n_count = 0, nn_count = 0, nnx_count = 0,
07909     s_count = 0, sr_count = 0;
07910   int FORLIM;
07911 
07912   memset (nb, 0, sizeof (neighbor_rec));
07913   get_neighbors (nb, a_view);
07914   FORLIM = atom[a_view - 1].neighbor_count;
07915   for (i = 0; i < FORLIM; i++)
07916     {
07917       if (bond[get_bond (a_view, nb[i]) - 1].btype == 'S')
07918        {
07919          strcpy (nb_el, atom[nb[i] - 1].element);
07920          if (strcmp (nb_el, "C "))
07921            {
07922              if (!strcmp (nb_el, "O "))
07923               {
07924                 o_count++;
07925                 if (is_alkoxy (a_view, nb[i]) |
07926                     is_alkenyloxy (a_view, nb[i]) || is_aryloxy (a_view,
07927                                                            nb[i]))
07928                   /* v0.3j */
07929                   or_count++;
07930               }
07931              if (!strcmp (nb_el, "N "))
07932               {
07933                 n_count++;
07934                 if (is_hydrazino (a_view, nb[i]))
07935                   nn_count++;
07936                 if (is_subst_hydrazino (a_view, nb[i])) /* more general... */
07937                   nnx_count++;
07938               }
07939              if (!strcmp (nb_el, "S "))
07940               {
07941                 s_count++;
07942                 if (is_alkylsulfanyl (a_view, nb[i]) |
07943                     is_arylsulfanyl (a_view, nb[i]))
07944                   sr_count++;
07945               }
07946            }
07947        }
07948     }
07949   if (is_oxo_C (a_view))
07950     {
07951       if (o_count == 2)
07952        {
07953          fg[fg_carbonic_acid_deriv - 1] = true;
07954          if (or_count == 1)
07955            fg[fg_carbonic_acid_monoester - 1] = true;
07956          if (or_count == 2)
07957            fg[fg_carbonic_acid_diester - 1] = true;
07958        }
07959       if (o_count == 1 && s_count == 1)
07960        {
07961          fg[fg_thiocarbonic_acid_deriv - 1] = true;
07962          if (or_count + sr_count == 1)
07963            fg[fg_thiocarbonic_acid_monoester - 1] = true;
07964          if (or_count + sr_count == 2)
07965            fg[fg_thiocarbonic_acid_diester - 1] = true;
07966        }
07967       if (s_count == 2)
07968        {
07969          fg[fg_thiocarbonic_acid_deriv - 1] = true;
07970          if (sr_count == 1)
07971            fg[fg_thiocarbonic_acid_monoester - 1] = true;
07972          if (sr_count == 2)
07973            fg[fg_thiocarbonic_acid_diester - 1] = true;
07974        }
07975       if (o_count == 1 && n_count == 1)
07976        {
07977          fg[fg_carbamic_acid_deriv - 1] = true;
07978          if (or_count == 0)
07979            fg[fg_carbamic_acid - 1] = true;
07980          if (or_count == 1)
07981            fg[fg_carbamic_acid_ester - 1] = true;
07982        }
07983       if (s_count == 1 && n_count == 1)
07984        {
07985          fg[fg_thiocarbamic_acid_deriv - 1] = true;
07986          if (sr_count == 0)
07987            fg[fg_thiocarbamic_acid - 1] = true;
07988          if (sr_count == 1)
07989            fg[fg_thiocarbamic_acid_ester - 1] = true;
07990        }
07991       if (n_count == 2)
07992        {
07993          if (nn_count == 1)
07994            fg[fg_semicarbazide - 1] = true;
07995          else
07996            {
07997              if (nnx_count == 0)   /* excludes semicarbazones */
07998               fg[fg_urea - 1] = true;
07999            }
08000        }
08001     }                       /* end Oxo-C */
08002   if (is_thioxo_C (a_view))
08003     {
08004       if (o_count == 2)
08005        {
08006          fg[fg_thiocarbonic_acid_deriv - 1] = true;
08007          if (or_count == 1)
08008            fg[fg_thiocarbonic_acid_monoester - 1] = true;
08009          if (or_count == 2)
08010            fg[fg_thiocarbonic_acid_diester - 1] = true;
08011        }
08012       if (o_count == 1 && s_count == 1)
08013        {
08014          fg[fg_thiocarbonic_acid_deriv - 1] = true;
08015          if (or_count + sr_count == 1)
08016            fg[fg_thiocarbonic_acid_monoester - 1] = true;
08017          if (or_count + sr_count == 2)
08018            fg[fg_thiocarbonic_acid_diester - 1] = true;
08019        }
08020       if (s_count == 2)
08021        {
08022          fg[fg_thiocarbonic_acid_deriv - 1] = true;
08023          if (sr_count == 1)
08024            fg[fg_thiocarbonic_acid_monoester - 1] = true;
08025          if (sr_count == 2)
08026            fg[fg_thiocarbonic_acid_diester - 1] = true;
08027        }
08028       if (o_count == 1 && n_count == 1)
08029        {
08030          fg[fg_thiocarbamic_acid_deriv - 1] = true;
08031          if (or_count == 0)
08032            fg[fg_thiocarbamic_acid - 1] = true;
08033          if (or_count == 1)
08034            fg[fg_thiocarbamic_acid_ester - 1] = true;
08035        }
08036       if (s_count == 1 && n_count == 1)
08037        {
08038          fg[fg_thiocarbamic_acid_deriv - 1] = true;
08039          if (sr_count == 0)
08040            fg[fg_thiocarbamic_acid - 1] = true;
08041          if (sr_count == 1)
08042            fg[fg_thiocarbamic_acid_ester - 1] = true;
08043        }
08044       if (n_count == 2)
08045        {
08046          if (nn_count == 1)
08047            fg[fg_thiosemicarbazide - 1] = true;
08048          else
08049            {
08050              if (nnx_count == 0)   /* excludes thiosemicarbazones */
08051               fg[fg_thiourea - 1] = true;
08052            }
08053        }
08054     }                       /* end Thioxo-C */
08055   if (!
08056       (is_true_imino_C (a_view) &
08057        (bond[get_bond (a_view, a_ref) - 1].arom == false)))
08058     {
08059       return;
08060     }                       /* end Imino-C */
08061   if (o_count == 1 && n_count == 1)
08062     fg[fg_isourea - 1] = true;
08063   if (s_count == 1 && n_count == 1)
08064     fg[fg_isothiourea - 1] = true;
08065   if (n_count == 2)
08066     fg[fg_guanidine - 1] = true;
08067 }
08068 
08069 
08070 static void
08071 chk_co2_sp (a_view, a_ref)
08072      int a_view, a_ref;
08073 {
08074   int i;
08075   neighbor_rec nb;
08076   str2 nb_el;
08077   int o_count = 0, n_count = 0, s_count = 0;
08078   int FORLIM;
08079 
08080   memset (nb, 0, sizeof (neighbor_rec));
08081   get_neighbors (nb, a_view);
08082   FORLIM = atom[a_view - 1].neighbor_count;
08083   for (i = 0; i < FORLIM; i++)
08084     {
08085       if (bond[get_bond (a_view, nb[i]) - 1].btype == 'D')
08086        {
08087          strcpy (nb_el, atom[nb[i] - 1].element);
08088          if (strcmp (nb_el, "C "))
08089            {
08090              if (!strcmp (nb_el, "O "))
08091               o_count++;
08092              if (!strcmp (nb_el, "N "))
08093               n_count++;
08094              if (!strcmp (nb_el, "S "))
08095               s_count++;
08096            }
08097        }
08098     }
08099   if (o_count + s_count == 2)      /* new in v0.3b */
08100     fg[fg_co2_deriv - 1] = true;
08101   if (o_count == 1 && n_count == 1)
08102     fg[fg_isocyanate - 1] = true;
08103   if (s_count == 1 && n_count == 1)
08104     fg[fg_isothiocyanate - 1] = true;
08105   if (n_count == 2)
08106     fg[fg_carbodiimide - 1] = true;
08107 }
08108 
08109 
08110 static void
08111 chk_triple (a1, a2)
08112      int a1, a2;
08113 {
08114   str2 a1_el, a2_el;
08115 
08116   strcpy (a1_el, atom[a1 - 1].element);
08117   strcpy (a2_el, atom[a2 - 1].element);
08118   if ((!strcmp (a1_el, "C ") && !strcmp (a2_el, "C ")) &
08119       (bond[get_bond (a1, a2) - 1].arom == false))
08120     fg[fg_alkyne - 1] = true;
08121   if (is_nitrile (a1, a2))
08122     fg[fg_nitrile - 1] = true;
08123   if (is_isonitrile (a1, a2))
08124     fg[fg_isonitrile - 1] = true;
08125   if (is_cyanate (a1, a2))
08126     fg[fg_cyanate - 1] = true;
08127   if (is_thiocyanate (a1, a2))
08128     fg[fg_thiocyanate - 1] = true;
08129 }
08130 
08131 
08132 static void
08133 chk_ccx (a_view, a_ref)
08134      int a_view, a_ref;
08135 {
08136   int i;
08137   neighbor_rec nb;
08138   int oh_count = 0, or_count = 0, n_count = 0;
08139   int FORLIM;
08140 
08141   memset (nb, 0, sizeof (neighbor_rec));
08142   get_neighbors (nb, a_ref);
08143   FORLIM = atom[a_ref - 1].neighbor_count;
08144   for (i = 0; i < FORLIM; i++)
08145     {
08146       if (bond[get_bond (a_ref, nb[i]) - 1].btype == 'S')
08147        {
08148          if (is_hydroxy (a_ref, nb[i]))
08149            oh_count++;
08150          if (is_alkoxy (a_ref, nb[i]) || is_aryloxy (a_ref, nb[i]) |
08151              is_siloxy (a_ref, nb[i]))
08152            or_count++;
08153          if (!strcmp (atom[nb[i] - 1].atype, "N3 ") ||
08154              !strcmp (atom[nb[i] - 1].atype, "NAM"))
08155            n_count++;
08156        }
08157     }
08158   if (oh_count == 1)
08159     fg[fg_enol - 1] = true;
08160   if (or_count == 1)
08161     fg[fg_enolether - 1] = true;
08162   if (n_count == 1)
08163     fg[fg_enamine - 1] = true;
08164   /* new in v0.2f   (regard anything else as an alkene) */
08165   if (oh_count + or_count + n_count == 0)
08166     fg[fg_alkene - 1] = true;
08167 }
08168 
08169 
08170 static void
08171 chk_xccx (a_view, a_ref)
08172      int a_view, a_ref;
08173 {
08174   int i;
08175   neighbor_rec nb;
08176   int oh_count = 0, or_count = 0, n_count = 0;
08177   int FORLIM;
08178 
08179   memset (nb, 0, sizeof (neighbor_rec));
08180   get_neighbors (nb, a_view);
08181   FORLIM = atom[a_view - 1].neighbor_count;
08182   for (i = 0; i < FORLIM; i++)
08183     {
08184       if (bond[get_bond (a_view, nb[i]) - 1].btype == 'S')
08185        {
08186          if (is_hydroxy (a_view, nb[i]))
08187            oh_count++;
08188          if (is_alkoxy (a_view, nb[i]) || is_aryloxy (a_view, nb[i]) |
08189              is_siloxy (a_view, nb[i]))
08190            or_count++;
08191          if (!strcmp (atom[nb[i] - 1].atype, "N3 ") ||
08192              !strcmp (atom[nb[i] - 1].atype, "NAM"))
08193            n_count++;
08194        }
08195     }
08196   memset (nb, 0, sizeof (neighbor_rec));
08197   get_neighbors (nb, a_ref);
08198   FORLIM = atom[a_ref - 1].neighbor_count;
08199   for (i = 0; i < FORLIM; i++)
08200     {
08201       if (bond[get_bond (a_ref, nb[i]) - 1].btype == 'S')
08202        {
08203          if (is_hydroxy (a_ref, nb[i]))
08204            oh_count++;
08205          if (is_alkoxy (a_ref, nb[i]) || is_aryloxy (a_ref, nb[i]) |
08206              is_siloxy (a_ref, nb[i]))
08207            or_count++;
08208          if (!strcmp (atom[nb[i] - 1].atype, "N3 ") ||
08209              !strcmp (atom[nb[i] - 1].atype, "NAM"))
08210            n_count++;
08211        }
08212     }
08213   if (oh_count == 2)
08214     fg[fg_enediol - 1] = true;
08215   /* new in v0.2f   (regard anything else as an alkene) */
08216   if (oh_count + or_count + n_count == 0)
08217     fg[fg_alkene - 1] = true;
08218 }
08219 
08220 
08221 static void
08222 chk_n_o_dbl (a1, a2)
08223      int a1, a2;
08224 {
08225   int i;
08226   neighbor_rec nb;
08227   str2 nb_el;
08228   int or_count = 0, n_count = 0, c_count = 0;
08229   int b;                    /* v0.3j */
08230   int het_count = 0;        /* v0.3k */
08231   char bt;                  /* v0.3k */
08232   float bo_sum = 0.0;              /* v0.3k */
08233   int FORLIM;
08234 
08235   memset (nb, 0, sizeof (neighbor_rec));
08236   get_neighbors (nb, a1);
08237   FORLIM = atom[a1 - 1].neighbor_count;
08238   /* v0.3k */
08239   /* v0.3k */
08240   for (i = 0; i < FORLIM; i++)
08241     {
08242       if (nb[i] != a2)
08243        {
08244          b = get_bond (a1, nb[i]); /* v0.3j */
08245          strcpy (nb_el, atom[nb[i] - 1].element);
08246          bt = bond[b - 1].btype;   /* v0.3k */
08247          if (strcmp (nb_el, "C ") && strcmp (nb_el, "H ")
08248              /*&&  strcmp (nb_el, "D ") */  && strcmp (nb_el, "DU")
08249              && strcmp (nb_el, "LP") && bond[b - 1].arom == false)
08250            /* added 'D ' in v0.3n */
08251            het_count++;
08252          /* v0.3k: ignore hetero atoms */
08253          /* in aromatic rings like isoxazole  */
08254          if (bt == 'S')
08255            bo_sum += 1.0;
08256          if (bt == 'D')
08257            bo_sum += 2.0;
08258          if (bt == 'A')
08259            bo_sum += 1.5;
08260          if (!strcmp (nb_el, "O "))
08261            or_count++;
08262          if (!strcmp (nb_el, "N "))
08263            n_count++;
08264          if (!strcmp (nb_el, "C ") && bond[b - 1].btype == 'S')       /* v0.3k */
08265            c_count++;
08266          /* if (is_alkyl(a1,nb[i])) or (is_aryl(a1,nb[i])) then inc(c_count); */
08267        }
08268     }
08269   if (or_count + n_count + c_count == 1 && atom[a1 - 1].neighbor_count == 2)
08270     {                       /* excludes nitro etc. */
08271       if (or_count == 1)
08272        fg[fg_nitrite - 1] = true;
08273       if (c_count == 1)
08274        fg[fg_nitroso_compound - 1] = true;
08275       if (n_count == 1)            /* instead of nitrosamine  v0.3j */
08276        fg[fg_nitroso_compound - 1] = true;
08277       /*if (n_count = 1) then fg[fg_nitrosamine]   := true;  (* still missing */
08278     }
08279   /*if ((c_count > 1) and (or_count = 0) and (n_count = 0)) then */
08280   /*  begin */
08281   /*    fg[fg_n_oxide] := true; */
08282   /*  end; */
08283   /* new approach in v0.3k */
08284   if (het_count == 0 && bo_sum > 2)       /* =O does not count! */
08285     fg[fg_n_oxide - 1] = true;
08286 }
08287 
08288 
08289 static void
08290 chk_sulfoxide (a1, a2)
08291      int a1, a2;
08292 {
08293   int i;
08294   neighbor_rec nb;
08295   str2 nb_el;
08296   int o_count = 0, c_count = 0;
08297   int FORLIM;
08298 
08299   memset (nb, 0, sizeof (neighbor_rec));
08300   get_neighbors (nb, a1);
08301   FORLIM = atom[a1 - 1].neighbor_count;
08302   for (i = 0; i < FORLIM; i++)
08303     {
08304       strcpy (nb_el, atom[nb[i] - 1].element);
08305       if (!strcmp (nb_el, "O "))
08306        o_count++;
08307       if (is_alkyl (a1, nb[i]) || is_aryl (a1, nb[i]))
08308        c_count++;
08309     }
08310   if (o_count == 1 && c_count == 2)
08311     fg[fg_sulfoxide - 1] = true;
08312 }
08313 
08314 
08315 static void
08316 chk_double (a1, a2)
08317      int a1, a2;
08318 {
08319   str2 a1_el, a2_el;
08320 
08321   strcpy (a1_el, atom[a1 - 1].element);
08322   strcpy (a2_el, atom[a2 - 1].element);
08323   if ((!strcmp (a1_el, "C ") && strcmp (a2_el, "C ")) &
08324       (bond[get_bond (a1, a2) - 1].arom == false))
08325     {
08326       if (hetbond_count (a1) == 2)
08327        chk_carbonyl_deriv (a1, a2);
08328       if (hetbond_count (a1) == 3)
08329        chk_carboxyl_deriv (a1, a2);
08330       if (hetbond_count (a1) == 4)
08331        {
08332          if (!strcmp (atom[a1 - 1].atype, "C2 "))
08333            chk_co2_sp2 (a1, a2);
08334          if (!strcmp (atom[a1 - 1].atype, "C1 "))
08335            chk_co2_sp (a1, a2);
08336        }
08337     }                       /* end C=X */
08338   if ((!strcmp (atom[a1 - 1].atype, "C2 ")
08339        && !strcmp (atom[a2 - 1].atype,
08340                  "C2 ")) && (bond[get_bond (a1, a2) - 1].arom == false))
08341     {
08342       if ((hetbond_count (a1) == 0) && (hetbond_count (a2) == 2))
08343        fg[fg_ketene_acetal_deriv - 1] = true;
08344       if ((hetbond_count (a1) == 0) && (hetbond_count (a2) == 1))
08345        chk_ccx (a1, a2);
08346       if ((hetbond_count (a1) == 1) && (hetbond_count (a2) == 1))
08347        chk_xccx (a1, a2);
08348       if (((hetbond_count (a1) == 0) && (hetbond_count (a2) == 0)) &&
08349          atom[a1 - 1].arom == false && atom[a2 - 1].arom == false)
08350        fg[fg_alkene - 1] = true;
08351     }
08352   if (((!strcmp (a1_el, "N ")
08353        && !strcmp (a2_el,
08354                   "N ")) && (hetbond_count (a1) ==
08355                             2) && (hetbond_count (a2) ==
08356                                   2) && (bond[get_bond (a1, a2) -
08357                                             1].arom == false))
08358       && atom[a1 - 1].neighbor_count == 2 && atom[a2 - 1].neighbor_count == 2)
08359     fg[fg_azo_compound - 1] = true;
08360   if (!strcmp (a1_el, "N ") && !strcmp (a2_el, "O "))
08361     chk_n_o_dbl (a1, a2);
08362   if (!strcmp (a1_el, "S ") && !strcmp (a2_el, "O "))
08363     chk_sulfoxide (a1, a2);
08364 }
08365 
08366 
08367 static void
08368 chk_c_hal (a1, a2)
08369      int a1, a2;
08370 {
08371   str2 a2_el;
08372 
08373   strcpy (a2_el, atom[a2 - 1].element);
08374   fg[fg_halogen_deriv - 1] = true;
08375   if (atom[a1 - 1].arom)
08376     {
08377       fg[fg_aryl_halide - 1] = true;
08378       if (!strcmp (a2_el, "F "))
08379        fg[fg_aryl_fluoride - 1] = true;
08380       if (!strcmp (a2_el, "CL"))
08381        fg[fg_aryl_chloride - 1] = true;
08382       if (!strcmp (a2_el, "BR"))
08383        fg[fg_aryl_bromide - 1] = true;
08384       if (!strcmp (a2_el, "I "))
08385        fg[fg_aryl_iodide - 1] = true;
08386       return;
08387     }
08388   if ((strcmp (atom[a1 - 1].atype, "C3 ") == 0) && (hetbond_count (a1) <= 2))
08389     {                       /* alkyl halides */
08390       fg[fg_alkyl_halide - 1] = true;
08391       if (!strcmp (a2_el, "F "))
08392        fg[fg_alkyl_fluoride - 1] = true;
08393       if (!strcmp (a2_el, "CL"))
08394        fg[fg_alkyl_chloride - 1] = true;
08395       if (!strcmp (a2_el, "BR"))
08396        fg[fg_alkyl_bromide - 1] = true;
08397       if (!strcmp (a2_el, "I "))
08398        fg[fg_alkyl_iodide - 1] = true;
08399     }
08400   if ((strcmp (atom[a1 - 1].atype, "C2 ") == 0) && (hetbond_count (a1) == 3))
08401     {                       /* acyl halides and related compounds */
08402       if (is_oxo_C (a1))
08403        {
08404          fg[fg_acyl_halide - 1] = true;
08405          if (!strcmp (a2_el, "F "))
08406            fg[fg_acyl_fluoride - 1] = true;
08407          if (!strcmp (a2_el, "CL"))
08408            fg[fg_acyl_chloride - 1] = true;
08409          if (!strcmp (a2_el, "BR"))
08410            fg[fg_acyl_bromide - 1] = true;
08411          if (!strcmp (a2_el, "I "))
08412            fg[fg_acyl_iodide - 1] = true;
08413        }
08414       if (is_thioxo_C (a1))
08415        fg[fg_thiocarboxylic_acid_deriv - 1] = true;
08416       if (is_imino_C (a1))
08417        fg[fg_imidoyl_halide - 1] = true;
08418     }
08419   if (!
08420       ((strcmp (atom[a1 - 1].atype, "C2 ") == 0)
08421        && (hetbond_count (a1) == 4)))
08422     /* chloroformates etc. */
08423     return;
08424   /* still missing: polyhalogen compounds (-CX2H, -CX3) */
08425   fg[fg_co2_deriv - 1] = true;
08426   if (is_oxo_C (a1))
08427     {
08428       fg[fg_carbonic_acid_deriv - 1] = true;
08429       if (is_alkoxycarbonyl (a2, a1) || is_aryloxycarbonyl (a2, a1))
08430        fg[fg_carbonic_acid_ester_halide - 1] = true;
08431       if (is_carbamoyl (a2, a1))
08432        {
08433          fg[fg_carbamic_acid_deriv - 1] = true;
08434          fg[fg_carbamic_acid_halide - 1] = true;
08435        }
08436     }
08437   if (!is_thioxo_C (a1))
08438     return;
08439   fg[fg_thiocarbonic_acid_deriv - 1] = true;
08440   if (is_alkoxythiocarbonyl (a2, a1) || is_aryloxythiocarbonyl (a2, a1))
08441     fg[fg_thiocarbonic_acid_ester_halide - 1] = true;
08442   if (is_thiocarbamoyl (a2, a1))
08443     {
08444       fg[fg_thiocarbamic_acid_deriv - 1] = true;
08445       fg[fg_thiocarbamic_acid_halide - 1] = true;
08446       /* end of non-aromatic halogen compounds */
08447     }
08448 }
08449 
08450 
08451 static void
08452 chk_c_o (a1, a2)
08453      int a1, a2;
08454 {
08455   /* ignore heteroaromatic rings (like furan, thiophene, etc.) */
08456   if (bond[get_bond (a1, a2) - 1].arom == true)
08457     return;
08458   if (is_true_alkyl (a2, a1) && is_hydroxy (a1, a2))
08459     {
08460       fg[fg_hydroxy - 1] = true;
08461       fg[fg_alcohol - 1] = true;
08462       if (atom[a1 - 1].neighbor_count <= 2)
08463        fg[fg_prim_alcohol - 1] = true;
08464       if (atom[a1 - 1].neighbor_count == 3)
08465        fg[fg_sec_alcohol - 1] = true;
08466       if (atom[a1 - 1].neighbor_count == 4)
08467        fg[fg_tert_alcohol - 1] = true;
08468     }
08469   if (is_aryl (a2, a1) && is_hydroxy (a1, a2))
08470     {
08471       fg[fg_hydroxy - 1] = true;
08472       fg[fg_phenol - 1] = true;
08473     }
08474   if (is_true_alkyl (a2, a1) && is_true_alkoxy (a1, a2))
08475     {
08476       fg[fg_ether - 1] = true;
08477       fg[fg_dialkylether - 1] = true;
08478     }
08479   if ((is_true_alkyl (a2, a1) && is_aryloxy (a1, a2)) |
08480       (is_aryl (a2, a1) && is_true_alkoxy (a1, a2)))
08481     {
08482       fg[fg_ether - 1] = true;
08483       fg[fg_alkylarylether - 1] = true;
08484     }
08485   if (is_aryl (a2, a1) && is_aryloxy (a1, a2))
08486     {
08487       fg[fg_ether - 1] = true;
08488       fg[fg_diarylether - 1] = true;
08489     }
08490   if ((is_true_alkyl (a2, a1) || is_aryl (a2, a1)) && is_alkynyloxy (a1, a2))
08491     {
08492       fg[fg_ether - 1] = true;
08493       ether_generic = true;
08494     }
08495   if (is_alkynyl (a2, a1) && is_hydroxy (a1, a2))
08496     {
08497       fg[fg_hydroxy - 1] = true;
08498       hydroxy_generic = true;
08499     }
08500 
08501 }
08502 
08503 
08504 static void
08505 chk_c_s (a1, a2)
08506      int a1, a2;
08507 {
08508   int i;
08509   neighbor_rec nb;
08510   str2 nb_el;
08511   int o_count = 0, oh_count = 0, or_count = 0, n_count = 0, c_count = 0,
08512     hal_count = 0;
08513   int FORLIM;
08514 
08515   /* ignore heteroaromatic rings (like furan, thiophene, etc.) */
08516   if (bond[get_bond (a1, a2) - 1].arom == true)
08517     return;
08518   if (is_alkyl (a2, a1) && is_sulfanyl (a1, a2))
08519     {
08520       fg[fg_thiol - 1] = true;
08521       fg[fg_alkylthiol - 1] = true;
08522     }
08523   if (is_aryl (a2, a1) && is_sulfanyl (a1, a2))
08524     {
08525       fg[fg_thiol - 1] = true;
08526       fg[fg_arylthiol - 1] = true;
08527     }
08528   if (is_true_alkyl (a2, a1) && is_true_alkylsulfanyl (a1, a2))
08529     fg[fg_thioether - 1] = true;
08530   if ((is_true_alkyl (a2, a1) && is_arylsulfanyl (a1, a2)) |
08531       (is_aryl (a2, a1) && is_true_alkylsulfanyl (a1, a2)))
08532     fg[fg_thioether - 1] = true;
08533   if (is_aryl (a2, a1) && is_arylsulfanyl (a1, a2))
08534     fg[fg_thioether - 1] = true;
08535   /* check for sulfinic/sulfenic acid derivatives */
08536   memset (nb, 0, sizeof (neighbor_rec));
08537   get_neighbors (nb, a2);
08538   FORLIM = atom[a2 - 1].neighbor_count;
08539   for (i = 0; i < FORLIM; i++)
08540     {
08541       strcpy (nb_el, atom[nb[i] - 1].element);
08542       if (is_alkyl (a2, nb[i]) || is_aryl (a2, nb[i]))
08543        c_count++;
08544       if (is_hydroxy (a2, nb[i]))
08545        oh_count++;
08546       if (is_alkoxy (a2, nb[i]) || is_aryloxy (a2, nb[i]))
08547        or_count++;
08548       if (is_amino (a2, nb[i]) || is_subst_amino (a2, nb[i]))
08549        n_count++;
08550       if (!strcmp (nb_el, "F ") || !strcmp (nb_el, "CL") ||
08551          !strcmp (nb_el, "BR") || !strcmp (nb_el, "I "))
08552        hal_count++;
08553       if (!strcmp (nb_el, "O "))
08554        o_count++;
08555     }
08556   if (c_count != 1)
08557     return;
08558   if (atom[a2 - 1].neighbor_count == 3 && o_count - oh_count - or_count == 1)
08559     {                       /* sulfinic acid && derivs */
08560       fg[fg_sulfinic_acid_deriv - 1] = true;
08561       if (oh_count == 1)
08562        fg[fg_sulfinic_acid - 1] = true;
08563       if (or_count == 1)
08564        fg[fg_sulfinic_acid_ester - 1] = true;
08565       if (hal_count == 1)
08566        fg[fg_sulfinic_acid_halide - 1] = true;
08567       if (n_count == 1)
08568        fg[fg_sulfinic_acid_amide - 1] = true;
08569     }
08570   if (atom[a2 - 1].neighbor_count != 2 || o_count - oh_count - or_count != 0)
08571     /* sulfenic acid && derivs */
08572     return;
08573 
08574   fg[fg_sulfenic_acid_deriv - 1] = true;
08575   if (oh_count == 1)
08576     fg[fg_sulfenic_acid - 1] = true;
08577   if (or_count == 1)
08578     fg[fg_sulfenic_acid_ester - 1] = true;
08579   if (hal_count == 1)
08580     fg[fg_sulfenic_acid_halide - 1] = true;
08581   if (n_count == 1)
08582     fg[fg_sulfenic_acid_amide - 1] = true;
08583 }
08584 
08585 
08586 static void
08587 chk_c_n (a1, a2)
08588      int a1, a2;
08589 {
08590   /* ignore heteroaromatic rings (like furan, thiophene, pyrrol, etc.) */
08591   if (atom[a2 - 1].arom == true)
08592     return;
08593   if (is_true_alkyl (a2, a1) && is_amino (a1, a2))
08594     {
08595       fg[fg_amine - 1] = true;
08596       fg[fg_prim_amine - 1] = true;
08597       fg[fg_prim_aliph_amine - 1] = true;
08598     }
08599   if (is_aryl (a2, a1) && is_amino (a1, a2))
08600     {
08601       fg[fg_amine - 1] = true;
08602       fg[fg_prim_amine - 1] = true;
08603       fg[fg_prim_arom_amine - 1] = true;
08604     }
08605   if (is_true_alkyl (a2, a1) && is_true_alkylamino (a1, a2))
08606     {
08607       fg[fg_amine - 1] = true;
08608       fg[fg_sec_amine - 1] = true;
08609       fg[fg_sec_aliph_amine - 1] = true;
08610     }
08611   if (is_aryl (a2, a1) && is_true_alkylamino (a1, a2))
08612     {
08613       fg[fg_amine - 1] = true;
08614       fg[fg_sec_amine - 1] = true;
08615       fg[fg_sec_mixed_amine - 1] = true;
08616     }
08617   if (is_aryl (a2, a1) && is_arylamino (a1, a2))
08618     {
08619       fg[fg_amine - 1] = true;
08620       fg[fg_sec_amine - 1] = true;
08621       fg[fg_sec_arom_amine - 1] = true;
08622     }
08623   if (is_true_alkyl (a2, a1) && is_true_dialkylamino (a1, a2))
08624     {
08625       fg[fg_amine - 1] = true;
08626       fg[fg_tert_amine - 1] = true;
08627       fg[fg_tert_aliph_amine - 1] = true;
08628     }
08629   if ((is_true_alkyl (a2, a1) && is_diarylamino (a1, a2)) |
08630       (is_aryl (a2, a1) && is_true_dialkylamino (a1, a2)))
08631     {
08632       fg[fg_amine - 1] = true;
08633       fg[fg_tert_amine - 1] = true;
08634       fg[fg_tert_mixed_amine - 1] = true;
08635     }
08636   if (is_aryl (a2, a1) && is_diarylamino (a1, a2))
08637     {
08638       fg[fg_amine - 1] = true;
08639       fg[fg_tert_amine - 1] = true;
08640       fg[fg_tert_arom_amine - 1] = true;
08641     }
08642   if ((is_alkyl (a2, a1) || is_aryl (a2, a1) || is_alkenyl (a2, a1) |
08643        is_alkynyl (a2, a1)) && is_hydroxylamino (a1, a2) && (is_acyl_gen (a2,
08644                                                                  a1)
08645                                                       == false))
08646     /* v0.3k */
08647     fg[fg_hydroxylamine - 1] = true;
08648   /* v0.3k */
08649   /* v0.3k  */
08650   if ((is_alkyl (a2, a1) || is_aryl (a2, a1) || is_acyl (a2, a1) |
08651        is_alkenyl (a2, a1) || is_alkynyl (a2, a1)) && is_hydrazino (a1, a2))
08652     fg[fg_hydrazine - 1] = true;
08653   if ((is_alkyl (a2, a1) || is_aryl (a2, a1) || is_alkenyl (a2, a1) |
08654        is_alkynyl (a2, a1)) && is_azido (a1, a2))
08655     /* v0.3k */
08656     fg[fg_azide - 1] = true;
08657   if ((is_alkyl (a2, a1) || is_aryl (a2, a1) || is_alkenyl (a2, a1) |
08658        is_alkynyl (a2, a1)) && is_diazonium (a1, a2))
08659     /* v0.3k */
08660     fg[fg_diazonium_salt - 1] = true;
08661   if ((is_alkyl (a2, a1) || is_aryl (a2, a1) || is_alkenyl (a2, a1) |
08662        is_alkynyl (a2, a1)) && is_nitro (a1, a2))
08663     /* v0.3k */
08664     fg[fg_nitro_compound - 1] = true;
08665   if (is_alkynyl (a2, a1) &
08666       (is_amino (a1, a2) || is_C_monosubst_amino (a1, a2) |
08667        (is_C_disubst_amino (a1, a2) && (!is_acylamino (a1, a2)))))
08668     {
08669       fg[fg_amine - 1] = true;
08670       amine_generic = true;
08671     }
08672 }
08673 
08674 
08675 static void
08676 chk_c_c (a1, a2)
08677      int a1, a2;
08678 {
08679   int i;
08680   neighbor_rec nb;
08681   int oh_count, nhr_count, FORLIM;
08682 
08683   /* ignore aromatic rings */
08684   if (atom[a2 - 1].arom == true)
08685     return;
08686   /*check for 1,2-diols and 1,2-aminoalcoholes */
08687   if (!strcmp (atom[a1 - 1].atype, "C3 ")
08688       && !strcmp (atom[a2 - 1].atype, "C3 "))
08689     {
08690       if ((hetbond_count (a1) == 1) && (hetbond_count (a2) == 1))
08691        {
08692          oh_count = 0;
08693          nhr_count = 0;
08694          memset (nb, 0, sizeof (neighbor_rec));
08695          get_neighbors (nb, a1);
08696          FORLIM = atom[a1 - 1].neighbor_count;
08697          for (i = 0; i < FORLIM; i++)
08698            {
08699              if (nb[i] != a2)
08700               {
08701                 if (is_hydroxy (a1, nb[i]))
08702                   oh_count++;
08703                 if (is_amino (a1, nb[i]) || is_alkylamino (a1, nb[i]) |
08704                     is_arylamino (a1, nb[i]))
08705                   nhr_count++;
08706               }
08707            }
08708          memset (nb, 0, sizeof (neighbor_rec));
08709          get_neighbors (nb, a2);
08710          FORLIM = atom[a2 - 1].neighbor_count;
08711          for (i = 0; i < FORLIM; i++)
08712            {
08713              if (nb[i] != a1)
08714               {
08715                 if (is_hydroxy (a2, nb[i]))
08716                   oh_count++;
08717                 if (is_amino (a2, nb[i]) || is_alkylamino (a2, nb[i]) |
08718                     is_arylamino (a2, nb[i]))
08719                   nhr_count++;
08720               }
08721            }
08722          if (oh_count == 2)
08723            fg[fg_1_2_diol - 1] = true;
08724          if (oh_count == 1 && nhr_count == 1)
08725            fg[fg_1_2_aminoalcohol - 1] = true;
08726        }
08727     }
08728   /* check for alpha-aminoacids and alpha-hydroxyacids */
08729   if (strcmp (atom[a1 - 1].atype, "C3 ")
08730       || strcmp (atom[a2 - 1].atype, "C2 "))
08731     return;
08732   if (!((hetbond_count (a1) == 1) && (hetbond_count (a2) == 3)))
08733     return;
08734   oh_count = 0;
08735   nhr_count = 0;
08736   memset (nb, 0, sizeof (neighbor_rec));
08737   get_neighbors (nb, a1);
08738   FORLIM = atom[a1 - 1].neighbor_count;
08739   for (i = 0; i < FORLIM; i++)
08740     {
08741       if (nb[i] != a2)
08742        {
08743          if (is_hydroxy (a1, nb[i]))
08744            oh_count++;
08745          if (is_amino (a1, nb[i]) || is_alkylamino (a1, nb[i]) |
08746              is_arylamino (a1, nb[i]))
08747            nhr_count++;
08748        }
08749     }
08750   memset (nb, 0, sizeof (neighbor_rec));
08751   get_neighbors (nb, a2);
08752   FORLIM = atom[a2 - 1].neighbor_count;
08753   for (i = 0; i < FORLIM; i++)
08754     {
08755       if (nb[i] != a1)
08756        {
08757          if (is_hydroxy (a2, nb[i]))
08758            oh_count++;
08759        }
08760     }
08761   if ((oh_count == 2) && is_oxo_C (a2))
08762     fg[fg_alpha_hydroxyacid - 1] = true;
08763   if ((oh_count == 1 && nhr_count == 1) && is_oxo_C (a2))
08764     fg[fg_alpha_aminoacid - 1] = true;
08765 }
08766 
08767 
08768 static void
08769 chk_x_y_single (a_view, a_ref)
08770      int a_view, a_ref;
08771 {
08772   if (!strcmp (atom[a_view - 1].atype, "O3 ") &&
08773       !strcmp (atom[a_ref - 1].atype, "O3 "))
08774     {
08775       if (is_hydroxy (a_ref, a_view) || is_hydroxy (a_view, a_ref))
08776        fg[fg_hydroperoxide - 1] = true;
08777       if ((is_alkoxy (a_ref, a_view) || is_aryloxy (a_ref, a_view) |
08778           is_siloxy (a_ref, a_view)) && (is_alkoxy (a_view,
08779                                                a_ref) |
08780                                      is_aryloxy (a_view,
08781                                                 a_ref) |
08782                                      is_siloxy (a_view, a_ref)))
08783        fg[fg_peroxide - 1] = true;
08784     }                       /* still missing: peracid */
08785   if (!strcmp (atom[a_view - 1].atype, "S3 ") &&
08786       !strcmp (atom[a_ref - 1].atype, "S3 "))
08787     {
08788       if (atom[a_view - 1].neighbor_count == 2 &&
08789          atom[a_ref - 1].neighbor_count == 2)
08790        fg[fg_disulfide - 1] = true;
08791     }
08792   if ((!strcmp (atom[a_view - 1].element, "N ") &&
08793        !strcmp (atom[a_ref - 1].element,
08794               "N ")) && (hetbond_count (a_view) ==
08795                         1) && (hetbond_count (a_ref) == 1))
08796     {
08797       /*if ((is_amino(a_ref,a_view)) or  */
08798       /*    (is_subst_amino(a_ref,a_view)) or */
08799       /*    (is_acylamino(a_ref,a_view))) and */
08800       /*   ((is_amino(a_view,a_ref)) or  */
08801       /*    (is_subst_amino(a_view,a_ref)) or */
08802       /*    (is_acylamino(a_ref,a_view))) then  */
08803       if (bond[get_bond (a_view, a_ref) - 1].arom == false)
08804        fg[fg_hydrazine - 1] = true;
08805     }
08806   if (!strcmp (atom[a_view - 1].element, "N ") &&
08807       !strcmp (atom[a_ref - 1].atype, "O3 "))
08808     {                       /* bond is in "opposite" direction */
08809       if ((is_alkoxy (a_view, a_ref) || is_aryloxy (a_view, a_ref)) &
08810          is_nitro (a_ref, a_view))
08811        fg[fg_nitrate - 1] = true;
08812       if ((is_nitro (a_ref, a_view) == false
08813           && atom[a_view - 1].arom == false) && (is_amino (a_ref,
08814                                                      a_view) |
08815                                             is_subst_amino (a_ref,
08816                                                           a_view)) &
08817          (is_acylamino (a_ref, a_view) == false))
08818        fg[fg_hydroxylamine - 1] = true;   /* new in v0.3c */
08819     }
08820   if (!strcmp (atom[a_view - 1].element, "S ") &&
08821       !strcmp (atom[a_ref - 1].element, "O "))
08822     chk_sulfoxide (a_view, a_ref);
08823 }
08824 
08825 
08826 static void
08827 chk_single (a1, a2)
08828      int a1, a2;
08829 {
08830   str2 a1_el, a2_el;
08831 
08832   strcpy (a1_el, atom[a1 - 1].element);
08833   strcpy (a2_el, atom[a2 - 1].element);
08834   if (!strcmp (a1_el, "C ") &&
08835       (!strcmp (a2_el, "F ") || !strcmp (a2_el, "CL")
08836        || !strcmp (a2_el, "BR") || !strcmp (a2_el, "I ")))
08837     chk_c_hal (a1, a2);
08838   if (!strcmp (a1_el, "C ") && !strcmp (a2_el, "O "))
08839     chk_c_o (a1, a2);
08840   if (!strcmp (a1_el, "C ") && !strcmp (a2_el, "S "))
08841     chk_c_s (a1, a2);
08842   if (!strcmp (a1_el, "C ") && !strcmp (a2_el, "N "))
08843     chk_c_n (a1, a2);
08844   if ((strcmp (a1_el, "C ") == 0) && atom[a2 - 1].metal && (is_cyano_c (a1) ==
08845                                                      false))
08846     {
08847       fg[fg_organometallic - 1] = true;
08848       if (!strcmp (a2_el, "LI"))
08849        fg[fg_organolithium - 1] = true;
08850       if (!strcmp (a2_el, "MG"))
08851        fg[fg_organomagnesium - 1] = true;
08852     }
08853   if (!strcmp (a1_el, "C ") && !strcmp (a2_el, "C "))
08854     chk_c_c (a1, a2);
08855   if (strcmp (a1_el, "C ") && strcmp (a2_el, "C "))
08856     chk_x_y_single (a1, a2);
08857 }
08858 
08859 
08860 static void
08861 chk_carbonyl_deriv_sp3 (a_ref)
08862      int a_ref;
08863 {
08864   int i;
08865   neighbor_rec nb;
08866   int oh_count = 0, or_count = 0, n_count = 0, sh_count = 0, sr_count = 0;
08867   int FORLIM;
08868 
08869   memset (nb, 0, sizeof (neighbor_rec));
08870   get_neighbors (nb, a_ref);
08871   FORLIM = atom[a_ref - 1].neighbor_count;
08872   for (i = 0; i < FORLIM; i++)
08873     {
08874       if (is_hydroxy (a_ref, nb[i]))
08875        oh_count++;
08876       if (is_alkoxy (a_ref, nb[i]) || is_aryloxy (a_ref, nb[i]) |
08877          is_alkenyloxy (a_ref, nb[i]) || is_alkynyloxy (a_ref, nb[i]))
08878        or_count++;
08879       if (is_sulfanyl (a_ref, nb[i]))
08880        sh_count++;
08881       if (is_alkylsulfanyl (a_ref, nb[i]) || is_arylsulfanyl (a_ref, nb[i]) |
08882          is_alkenylsulfanyl (a_ref, nb[i]) || is_alkynylsulfanyl (a_ref,
08883                                                            nb[i]))
08884        sr_count++;
08885       if (!strcmp (atom[nb[i] - 1].atype, "N3 ") ||
08886          !strcmp (atom[nb[i] - 1].atype, "NAM"))
08887        n_count++;
08888     }
08889   if (oh_count == 2)
08890     fg[fg_carbonyl_hydrate - 1] = true;
08891   if (oh_count == 1 && or_count == 1)
08892     fg[fg_hemiacetal - 1] = true;
08893   if (or_count == 2)
08894     fg[fg_acetal - 1] = true;
08895   if ((oh_count == 1 || or_count == 1) && n_count == 1)
08896     fg[fg_hemiaminal - 1] = true;
08897   if (n_count == 2)
08898     fg[fg_aminal - 1] = true;
08899   if ((sh_count == 1 || sr_count == 1) && n_count == 1)
08900     fg[fg_thiohemiaminal - 1] = true;
08901   if (sr_count == 2 || or_count == 1 && sr_count == 1)
08902     fg[fg_thioacetal - 1] = true;
08903 }
08904 
08905 
08906 static void
08907 chk_carboxyl_deriv_sp3 (a_ref)
08908      int a_ref;
08909 {
08910   int i;
08911   neighbor_rec nb;
08912   int or_count = 0, oh_count = 0, n_count = 0;   /* oh_count new in v0.3c */
08913   int electroneg_count = 0; /* new in v0.3j */
08914   int hal_count = 0;
08915   str2 nb_el;
08916   int FORLIM;
08917 
08918   memset (nb, 0, sizeof (neighbor_rec));
08919   get_neighbors (nb, a_ref);
08920   FORLIM = atom[a_ref - 1].neighbor_count;
08921   for (i = 0; i < FORLIM; i++)
08922     {
08923       strcpy (nb_el, atom[nb[i] - 1].element);   /* v0.3j */
08924       if (is_electroneg (nb_el))
08925        electroneg_count++;
08926       if (!strcmp (nb_el, "F ") || !strcmp (nb_el, "CL") ||
08927          !strcmp (nb_el, "BR") || !strcmp (nb_el, "I ")
08928          || !strcmp (nb_el, "AT"))
08929        hal_count++;
08930       if (is_alkoxy (a_ref, nb[i]) || is_aryloxy (a_ref, nb[i]) |
08931          is_siloxy (a_ref, nb[i]))
08932        or_count++;
08933       if (is_hydroxy (a_ref, nb[i]))      /* new in v0.3c    */
08934        oh_count++;
08935       if (!strcmp (atom[nb[i] - 1].atype, "N3 ") ||
08936          !strcmp (atom[nb[i] - 1].atype, "NAM"))
08937        n_count++;
08938     }
08939   /*if (or_count + n_count > 1) then fg[fg_orthocarboxylic_acid_deriv] := true;  (* until v0.3i */
08940   if (electroneg_count == 3 && hal_count < 3)    /* v0.3j */
08941     fg[fg_orthocarboxylic_acid_deriv - 1] = true;
08942   if (or_count == 3)
08943     fg[fg_carboxy