third_party/inchi/INCHI_BASE/src/strutil.c
int fix_non_uniform_drawn_oxoanions( int num_atoms,
                                     inp_ATOM *at,
                                     int *num_changes )
{
    /* For central halogen, apply the following
    correction rules:

    O                             O(-)
    ||                            |
    O=Hal(-)=O         ===>        O=Hal=O
    ||                            ||
    O                             O

    (perchlorate, etc.)


    O                             O(-)
    ||                            |
    Hal(-)=O         ===>         Hal=O
    ||                            ||
    O                             O

    (chlorate, etc.)

    O                             O(-)
    ||                            |
    Hal(-)=O         ===>         Hal=O


    (chlorite, etc.)

    Hal(-)=O         ===>         Hal-O(-)


    (hypochlorite, etc.)



    For halcogenes (S, Se, Te)
    Y                               Y(-)
    ||                              |
    RnX(-)            ===>          RnX

    if:
    1) (X = S, Y = O) || (X = Se, Y = S, O) || (X = Te, Y = O, S, Se)
    2) valence of X exceeds 6, in initially drawn form


    So the following is corrected:

    O                               O(-)
    ||                              |
    O=S(-)-R            ===>        O=S-R
    ||                              ||
    O                               O

    Or

    O                              O-
    ||                             |
    F5Te(-)            ===>        F5Te

    but the following remains unchanged:


    O
    ||
    O=S(-)-R


    The central atom (of IUPAC Group 16-17) is shown as negative but it contains double bond(s)
    to terminal atom of greater electronegativity (of Group 16).
    The central atom is halcogen (S,Se,Te) in highest oxidation state or halogen.

    Fix:
    move negative charge to terminal atom and change double bond to a single one.

    Eligible central atom    Eligible terminal atom at double bond's end
    Cl              O
    Br              O
    I               O
    [At              S,Se,Te]
    S               O
    Se              O,S
    Te              O, S, Se

    Comments:
    1. Central atoms of Groups 13-15 are not considered.
    2. Pauling electronegativities are:
    F(3.98) > O(3.44) > Cl (3.16) > N (3.04) > Br(2.96) > I(2.66) > S(2.58) > Se(2.55) > At (2.2) > Te(2.1)


    */


    /* constants for element numbers */
    enum elems
    {
        dNone, dCl = 17, dBr = 35, dI = 53, dAt = 85, dO = 8,
        dS = 16, dSe = 34, dTe = 52, dP = 15, dC = 6, dN = 7
    };

    static U_CHAR  allowed_elnums_center_halogen[] = { dCl, dBr, dI, dAt };
    static U_CHAR  allowed_elnums_center_halcogen[] = { dS, dSe, dTe };

    int en_center;
    int i, j, k;

    for (i = 0; i < num_atoms; i++)
    {
        /* Find appropriate central atom. This center should be: ...*/

        /* charged exactly (-1) ... */
        if (at[i].charge != -1)
        {
            continue;
        }
        en_center = at[i].el_number;
        /*  from eligible element list ... */
        if (!memchr( allowed_elnums_center_halogen, en_center, sizeof( allowed_elnums_center_halogen ) ))
        {
            /* central atom is not not halogen; check if it is halcogen */
            if (memchr( allowed_elnums_center_halcogen, en_center, sizeof( allowed_elnums_center_halcogen ) ))
            {
                if (at[i].chem_bonds_valence < 7)
                {
                    /* central atom is anionic halcogen, but not in the highest oxidation state */
                    continue;
                }
            }
            else
            {
                continue;
            }
        }

        /* OK, found central halogen or eligible central halcogen. */

        /* non-radical... */
        if (at[i].radical && ( at[i].radical != RADICAL_SINGLET ))
        {
            continue;
        }

        /* Center found, now examine the adjacent terminals... */
        {
            int en_term, kk = 0, jj = 0, min_en = 999, iso = 0, min_iso = 999;
            jj = -1;
            for (k = 0; k < at[i].valence; k++)
            {
                j = at[i].neighbor[k];

                /* Terminal should be: ... */

                /* terminal... */
                if (at[j].valence != 1)
                {
                    continue;
                }
                /* double-bonded ... */
                if (at[i].bond_type[k] != BOND_TYPE_DOUBLE)
                {
                    continue;
                }
                /* zero-charged ... */
                if (at[j].charge != 0)
                {
                    continue;
                }
                /* non-radical */
                if (at[j].radical && ( at[j].radical != RADICAL_SINGLET ))
                {
                    continue;
                }
                /*  of eligible elements list ... */
                en_term = at[j].el_number;
                switch (en_term)
                {
                    case dO:    break;
                    case dS:    if (( en_center == dSe ) || ( en_center == dAt ) || ( en_center == dTe )) break;  continue;
                    case dSe:   if (( en_center == dAt ) || ( en_center == dTe )) break;  continue;
                    case dTe:   if (en_center == dAt) break; continue;
                    default:    continue;
                }

                /* From several candidates, select one with less el. number (==more electronegative). */
                if (en_term < min_en)
                {
                    min_en = en_term; kk = k; jj = j;
                    min_iso = at[j].iso_atw_diff > 0 ? at[i].iso_atw_diff - 1 : at[i].iso_atw_diff;
                    continue;
                }
                /* From same-element candidates, select one with less isotopic mass (arbitrary choice). */
                else if (en_term == min_en)
                {
                    iso = at[j].iso_atw_diff > 0 ? at[i].iso_atw_diff - 1 : at[i].iso_atw_diff;
                    if (iso < min_iso)
                    {
                        min_iso = iso; kk = k; jj = j; continue;
                    }
                }
            } /* end of checking nbrs. */

              /* If OK, apply changes. */
            if (jj >= 0)
            {
                at[i].charge = 0;
                at[jj].charge = -1;
                at[i].bond_type[kk] = BOND_TYPE_SINGLE;
                at[jj].bond_type[0] = BOND_TYPE_SINGLE;
                at[i].bond_stereo[kk] = at[jj].bond_stereo[0] = 0;
                at[i].chem_bonds_valence--;
                at[jj].chem_bonds_valence--;
                ( *num_changes )++;
            }
        }
    }  /* end of search for candidate centers. */

    return 0;
}
/****************************************************************************
Correct non-uniformly drawn oxoanions
****************************************************************************/
Correct non-uniformly drawn oxoanions
Correct non - uniformly drawn oxoanions
int fix_non_uniform_drawn_oxoanions( int num_atoms,
                                     inp_ATOM *at,
                                     int *num_changes )
{
    enum elems
    {
        dNone, dCl = 17, dBr = 35, dI = 53, dAt = 85, dO = 8,
        dS = 16, dSe = 34, dTe = 52, dP = 15, dC = 6, dN = 7
    };
    static U_CHAR  allowed_elnums_center_halogen[] = { dCl, dBr, dI, dAt };
    static U_CHAR  allowed_elnums_center_halcogen[] = { dS, dSe, dTe };
    int en_center;
    int i, j, k;
    for (i = 0; i < num_atoms; i++)
    {
        if (at[i].charge != -1)
        {
            continue;
        }
        en_center = at[i].el_number;
        if (!memchr( allowed_elnums_center_halogen, en_center, sizeof( allowed_elnums_center_halogen ) ))
        {
            if (memchr( allowed_elnums_center_halcogen, en_center, sizeof( allowed_elnums_center_halcogen ) ))
            {
                if (at[i].chem_bonds_valence < 7)
                {
                    continue;
                }
            }
            else
            {
                continue;
            }
        }
        if (at[i].radical && ( at[i].radical != RADICAL_SINGLET ))
        {
            continue;
        }
        {
            int en_term, kk = 0, jj = 0, min_en = 999, iso = 0, min_iso = 999;
            jj = -1;
            for (k = 0; k < at[i].valence; k++)
            {
                j = at[i].neighbor[k];
                if (at[j].valence != 1)
                {
                    continue;
                }
                if (at[i].bond_type[k] != BOND_TYPE_DOUBLE)
                {
                    continue;
                }
                if (at[j].charge != 0)
                {
                    continue;
                }
                if (at[j].radical && ( at[j].radical != RADICAL_SINGLET ))
                {
                    continue;
                }
                en_term = at[j].el_number;
                switch (en_term)
                {
                    case dO:    break;
                    case dS:    if (( en_center == dSe ) || ( en_center == dAt ) || ( en_center == dTe )) break;  continue;
                    case dSe:   if (( en_center == dAt ) || ( en_center == dTe )) break;  continue;
                    case dTe:   if (en_center == dAt) break; continue;
                    default:    continue;
                }
                if (en_term < min_en)
                {
                    min_en = en_term; kk = k; jj = j;
                    min_iso = at[j].iso_atw_diff > 0 ? at[i].iso_atw_diff - 1 : at[i].iso_atw_diff;
                    continue;
                }
                else if (en_term == min_en)
                {
                    iso = at[j].iso_atw_diff > 0 ? at[i].iso_atw_diff - 1 : at[i].iso_atw_diff;
                    if (iso < min_iso)
                    {
                        min_iso = iso; kk = k; jj = j; continue;
                    }
                }
            } 
            if (jj >= 0)
            {
                at[i].charge = 0;
                at[jj].charge = -1;
                at[i].bond_type[kk] = BOND_TYPE_SINGLE;
                at[jj].bond_type[0] = BOND_TYPE_SINGLE;
                at[i].bond_stereo[kk] = at[jj].bond_stereo[0] = 0;
                at[i].chem_bonds_valence--;
                at[jj].chem_bonds_valence--;
                ( *num_changes )++;
            }
        }
    }  
    return 0;
}
int fix_non_uniform_drawn_oxoanions ( int num_atoms , inp_ATOM * at , int * num_changes ) { enum elems { dNone , dCl = 17 , dBr = 35 , dI = 53 , dAt = 85 , dO = 8 , dS = 16 , dSe = 34 , dTe = 52 , dP = 15 , dC = 6 , dN = 7 } ; static U_CHAR allowed_elnums_center_halogen [ ] = { dCl , dBr , dI , dAt } ; static U_CHAR allowed_elnums_center_halcogen [ ] = { dS , dSe , dTe } ; int en_center ; int i , j , k ; for ( i = 0 ; i < num_atoms ; i ++ ) { if ( at [ i ] . charge != -1 ) { continue ; } en_center = at [ i ] . el_number ; if ( ! memchr ( allowed_elnums_center_halogen , en_center , sizeof ( allowed_elnums_center_halogen ) ) ) { if ( memchr ( allowed_elnums_center_halcogen , en_center , sizeof ( allowed_elnums_center_halcogen ) ) ) { if ( at [ i ] . chem_bonds_valence < 7 ) { continue ; } } else { continue ; } } if ( at [ i ] . radical && ( at [ i ] . radical != RADICAL_SINGLET ) ) { continue ; } { int en_term , kk = 0 , jj = 0 , min_en = 999 , iso = 0 , min_iso = 999 ; jj = -1 ; for ( k = 0 ; k < at [ i ] . valence ; k ++ ) { j = at [ i ] . neighbor [ k ] ; if ( at [ j ] . valence != 1 ) { continue ; } if ( at [ i ] . bond_type [ k ] != BOND_TYPE_DOUBLE ) { continue ; } if ( at [ j ] . charge != 0 ) { continue ; } if ( at [ j ] . radical && ( at [ j ] . radical != RADICAL_SINGLET ) ) { continue ; } en_term = at [ j ] . el_number ; switch ( en_term ) { case dO : break ; case dS : if ( ( en_center == dSe ) || ( en_center == dAt ) || ( en_center == dTe ) ) break ; continue ; case dSe : if ( ( en_center == dAt ) || ( en_center == dTe ) ) break ; continue ; case dTe : if ( en_center == dAt ) break ; continue ; default : continue ; } if ( en_term < min_en ) { min_en = en_term ; kk = k ; jj = j ; min_iso = at [ j ] . iso_atw_diff > 0 ? at [ i ] . iso_atw_diff - 1 : at [ i ] . iso_atw_diff ; continue ; } else if ( en_term == min_en ) { iso = at [ j ] . iso_atw_diff > 0 ? at [ i ] . iso_atw_diff - 1 : at [ i ] . iso_atw_diff ; if ( iso < min_iso ) { min_iso = iso ; kk = k ; jj = j ; continue ; } } } if ( jj >= 0 ) { at [ i ] . charge = 0 ; at [ jj ] . charge = -1 ; at [ i ] . bond_type [ kk ] = BOND_TYPE_SINGLE ; at [ jj ] . bond_type [ 0 ] = BOND_TYPE_SINGLE ; at [ i ] . bond_stereo [ kk ] = at [ jj ] . bond_stereo [ 0 ] = 0 ; at [ i ] . chem_bonds_valence -- ; at [ jj ] . chem_bonds_valence -- ; ( * num_changes ) ++ ; } } } return 0 ; }
Correct non-uniformly drawn oxoanions
Correct non - uniformly drawn oxoanions
/* For central halogen, apply the following
    correction rules:

    O                             O(-)
    ||                            |
    O=Hal(-)=O         ===>        O=Hal=O
    ||                            ||
    O                             O

    (perchlorate, etc.)


    O                             O(-)
    ||                            |
    Hal(-)=O         ===>         Hal=O
    ||                            ||
    O                             O

    (chlorate, etc.)

    O                             O(-)
    ||                            |
    Hal(-)=O         ===>         Hal=O


    (chlorite, etc.)

    Hal(-)=O         ===>         Hal-O(-)


    (hypochlorite, etc.)



    For halcogenes (S, Se, Te)
    Y                               Y(-)
    ||                              |
    RnX(-)            ===>          RnX

    if:
    1) (X = S, Y = O) || (X = Se, Y = S, O) || (X = Te, Y = O, S, Se)
    2) valence of X exceeds 6, in initially drawn form


    So the following is corrected:

    O                               O(-)
    ||                              |
    O=S(-)-R            ===>        O=S-R
    ||                              ||
    O                               O

    Or

    O                              O-
    ||                             |
    F5Te(-)            ===>        F5Te

    but the following remains unchanged:


    O
    ||
    O=S(-)-R


    The central atom (of IUPAC Group 16-17) is shown as negative but it contains double bond(s)
    to terminal atom of greater electronegativity (of Group 16).
    The central atom is halcogen (S,Se,Te) in highest oxidation state or halogen.

    Fix:
    move negative charge to terminal atom and change double bond to a single one.

    Eligible central atom    Eligible terminal atom at double bond's end
    Cl              O
    Br              O
    I               O
    [At              S,Se,Te]
    S               O
    Se              O,S
    Te              O, S, Se

    Comments:
    1. Central atoms of Groups 13-15 are not considered.
    2. Pauling electronegativities are:
    F(3.98) > O(3.44) > Cl (3.16) > N (3.04) > Br(2.96) > I(2.66) > S(2.58) > Se(2.55) > At (2.2) > Te(2.1)


    */ /* constants for element numbers */ /* Find appropriate central atom. This center should be: ...*/ /* charged exactly (-1) ... */ /*  from eligible element list ... */ /* central atom is not not halogen; check if it is halcogen */ /* central atom is anionic halcogen, but not in the highest oxidation state */ /* OK, found central halogen or eligible central halcogen. */ /* non-radical... */ /* Center found, now examine the adjacent terminals... */ /* Terminal should be: ... */ /* terminal... */ /* double-bonded ... */ /* zero-charged ... */ /* non-radical */ /*  of eligible elements list ... */ /* From several candidates, select one with less el. number (==more electronegative). */ /* From same-element candidates, select one with less isotopic mass (arbitrary choice). */ /* end of checking nbrs. */ /* If OK, apply changes. */ /* end of search for candidate centers. */