├── .gitignore ├── rdkit ├── .gitignore ├── conda_build_config.yaml ├── utils.py ├── rdpaths.patch ├── rdconfig.patch ├── meta.yaml ├── build.sh ├── bld.bat └── avalon_reaccsio.c ├── cheto ├── bld.bat ├── build.sh └── meta.yaml ├── cairo_nox ├── conda_build_config.yaml ├── build.sh └── meta.yaml ├── nox └── meta.yaml ├── rdkit-postgresql ├── conda_build_config.yaml ├── meta.yaml ├── build.sh └── bld.bat ├── docker-build ├── README.md └── Dockerfile ├── .azure-pipelines ├── rdkit_ubuntu1804_build.yml ├── rdkit_mac_build.yml └── rdkit_vs17_build.yml ├── azure-pipelines.yml ├── .travis.yml ├── Dockerfile └── README.rst /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | -------------------------------------------------------------------------------- /rdkit/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | __pycache__ 3 | -------------------------------------------------------------------------------- /cheto/bld.bat: -------------------------------------------------------------------------------- 1 | "%PYTHON%" setup.py install 2 | if errorlevel 1 exit 1 3 | -------------------------------------------------------------------------------- /cairo_nox/conda_build_config.yaml: -------------------------------------------------------------------------------- 1 | CONDA_BUILD_SYSROOT: 2 | - /opt/MacOSX10.9.sdk [osx] 3 | -------------------------------------------------------------------------------- /cheto/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | $PYTHON setup.py install # Python command to install the script. 4 | -------------------------------------------------------------------------------- /nox/meta.yaml: -------------------------------------------------------------------------------- 1 | package: 2 | name: nox 3 | version: 1.0 4 | 5 | build: 6 | track_features: 7 | - nox 8 | -------------------------------------------------------------------------------- /rdkit/conda_build_config.yaml: -------------------------------------------------------------------------------- 1 | CONDA_BUILD_SYSROOT: 2 | - /opt/MacOSX10.9.sdk [osx] 3 | 4 | libboost: 1.73 5 | pin_run_as_build: 6 | libboost: 7 | max_pin: x.x 8 | -------------------------------------------------------------------------------- /rdkit-postgresql/conda_build_config.yaml: -------------------------------------------------------------------------------- 1 | postgresql: 2 | - 9.6 3 | - 10 4 | - 11 5 | 6 | libboost: 1.67 7 | 8 | pin_run_as_build: 9 | postgresql: x.x 10 | libboost: 11 | max_pin: x.x 12 | -------------------------------------------------------------------------------- /docker-build/README.md: -------------------------------------------------------------------------------- 1 | Dockerfile for doing RDKit linux builds and uploading the results to conda. 2 | 3 | Note that you need to provide a conda user and conda token for this to work. Example invocation: 4 | ``` 5 | docker build -t conda-docker-build --build-arg anaconda_user=rdkit --build-arg anaconda_token="REPLACE_ME" . 6 | ``` 7 | -------------------------------------------------------------------------------- /cairo_nox/build.sh: -------------------------------------------------------------------------------- 1 | export CFLAGS="-I$PREFIX/include -L$PREFIX/lib $CFLAGS" 2 | if [ $(uname) == Linux ]; then 3 | XWIN_ARGS="--enable-xcb-shm" 4 | fi 5 | if [ $(uname -m) == x86_64 ]; then 6 | export ax_cv_c_float_words_bigendian="no" 7 | fi 8 | find $PREFIX -name '*.la' -delete 9 | ./configure \ 10 | --enable-xlib=no \ 11 | --enable-xlib-xrender=no \ 12 | --enable-xcb=no \ 13 | --disable-static \ 14 | --disable-gtk-doc \ 15 | --prefix=$PREFIX 16 | 17 | make && make install && rm -rf $PREFIX/share 18 | -------------------------------------------------------------------------------- /rdkit/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import requests 4 | 5 | 6 | # http://stackoverflow.com/questions/16694907/how-to-download-large-file-in-python-with-requests-py 7 | def download_file(url): 8 | r = requests.get(url, stream=True) 9 | filename = url.split('/')[-1] 10 | with open(filename, 'wb') as f: 11 | print("Downloading: ", filename) 12 | for chunk in r.iter_content(chunk_size=8192): 13 | if chunk: # filter out keep-alive new chunks 14 | f.write(chunk) 15 | f.flush() 16 | return filename 17 | 18 | 19 | -------------------------------------------------------------------------------- /cheto/meta.yaml: -------------------------------------------------------------------------------- 1 | package: 2 | name: cheto 3 | version: "0.1" 4 | 5 | source: 6 | git_url: https://github.com/rdkit/CheTo.git 7 | git_rev: master 8 | 9 | build: 10 | number: 1 11 | noarch_python: True 12 | 13 | requirements: 14 | build: 15 | - python 16 | - setuptools 17 | - scikit-learn 18 | - rdkit >=2017.03 19 | run: 20 | - python 21 | - scikit-learn 22 | - rdkit >=2017.03 23 | 24 | test: 25 | imports: 26 | - rdkit 27 | 28 | about: 29 | home: http://rdkit.org 30 | license: BSD 31 | summary: chemical topic modeling implementation from the paper http://pubs.acs.org/doi/10.1021/acs.jcim.7b00249 32 | -------------------------------------------------------------------------------- /rdkit/rdpaths.patch: -------------------------------------------------------------------------------- 1 | diff --git rdkit/CMakeLists.txt rdkit/CMakeLists.txt 2 | index 4ccb94f..a68ee75 100644 3 | --- rdkit/CMakeLists.txt 4 | +++ rdkit/CMakeLists.txt 5 | @@ -1,8 +1,8 @@ 6 | file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/RDPaths.py 7 | "import os 8 | -# unset so to trigger exceptions and track use: RDBaseDir=os.environ['RDBASE'] 9 | -RDCodeDir=os.path.join(r'${PYTHON_INSTDIR}','rdkit') 10 | -# not really hard-coded alternative RDCodeDir=os.path.dirname(__file__) 11 | +# do not set RDBaseDir, so to trigger exceptions and track use: 12 | +# RDBaseDir=os.environ['RDBASE'] 13 | +RDCodeDir=os.path.dirname(__file__) 14 | _share = os.path.join(r'${CMAKE_INSTALL_PREFIX}', r'${RDKit_ShareDir}') 15 | RDDataDir=os.path.join(_share,'Data') 16 | RDDocsDir=os.path.join(_share,'Docs') 17 | -------------------------------------------------------------------------------- /rdkit/rdconfig.patch: -------------------------------------------------------------------------------- 1 | diff --git rdkit/RDConfig.py rdkit/RDConfig.py 2 | index 9b685e2..7d022d5 100755 3 | --- rdkit/RDConfig.py 4 | +++ rdkit/RDConfig.py 5 | @@ -25,11 +25,11 @@ elif 'CONDA_DEFAULT_ENV' in os.environ: 6 | # we are running in a conda environ. 7 | RDCodeDir = os.path.dirname(__file__) 8 | splitdir = RDCodeDir.split(os.path.sep) 9 | - condaDir = splitdir[:-4] 10 | + condaDir = splitdir[:-3] 11 | if condaDir[0] == '': 12 | condaDir[0] = os.path.sep 13 | - condaDir += ['share', 'RDKit'] 14 | - _share = os.path.join(*condaDir) 15 | + condaDir += ['Library','share','RDKit'] 16 | + _share = os.path.sep.join(condaDir) 17 | RDDataDir = os.path.join(_share, 'Data') 18 | RDDocsDir = os.path.join(_share, 'Docs') 19 | RDProjDir = os.path.join(_share, 'Projects') 20 | -------------------------------------------------------------------------------- /rdkit-postgresql/meta.yaml: -------------------------------------------------------------------------------- 1 | package: 2 | name: rdkit-postgresql 3 | version: {{ environ.get('GIT_DESCRIBE_TAG', 'LOCAL').replace("_", ".").replace("Release.","") }}.{{ environ.get('GIT_DESCRIBE_NUMBER', 0) }} 4 | 5 | source: 6 | git_url: https://github.com/rdkit/rdkit.git 7 | git_rev: Release_2020_09 8 | 9 | build: 10 | number: 0 11 | 12 | requirements: 13 | build: 14 | - {{ compiler('c') }} 15 | - {{ compiler('cxx') }} 16 | - cmake 17 | - python 18 | host: 19 | - libboost {{ libboost }} 20 | - boost-cpp 21 | - eigen 22 | - msys2-conda-epoch >=20160418 [win] 23 | - m2-msys2-runtime [win] 24 | - m2-libiconv [win] 25 | - m2-libintl [win] 26 | - m2-diffutils [win] 27 | - m2-patch [win] 28 | - postgresql {{ postgresql }} 29 | run: 30 | - postgresql {{ postgresql }} 31 | - libboost {{ libboost }} 32 | 33 | about: 34 | home: http://rdkit.org 35 | license: BSD 36 | -------------------------------------------------------------------------------- /.azure-pipelines/rdkit_ubuntu1804_build.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - bash: | 3 | source ${CONDA}/etc/profile.d/conda.sh 4 | sudo chown -R ${USER} ${CONDA} 5 | conda config --set always_yes yes --set changeps1 no 6 | conda update -q conda 7 | conda install conda-build 8 | displayName: Setup build environment 9 | - bash: | 10 | source ${CONDA}/etc/profile.d/conda.sh 11 | export CONDA_PY=${PYTHON_VERSION} 12 | sed -i 's/git_rev: Release_2020_03/git_rev: master/; s/^ version:/# version;/; s/# nightly version:/version:/' rdkit/meta.yaml 13 | sed -i 's/^ctest/# ctest/' rdkit/build.sh 14 | conda build rdkit 15 | displayName: Do conda build and test 16 | - bash: | 17 | mkdir -p $(Build.ArtifactStagingDirectory)/linux-64 18 | echo "-----------------" 19 | ls -l /usr/share/miniconda/conda-bld/linux-64/rdkit* 20 | cp /usr/share/miniconda/conda-bld/linux-64/rdkit* $(Build.ArtifactStagingDirectory)/linux-64 21 | displayName: Create build artifacts 22 | - publish: $(Build.ArtifactStagingDirectory) 23 | artifact: conda_build_rdkit_linux_$(python.version) 24 | 25 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Starter pipeline 2 | # Start with a minimal pipeline that you can customize to build and deploy your code. 3 | # Add steps that build, run tests, deploy, and more: 4 | # https://aka.ms/yaml 5 | 6 | trigger: 7 | - master 8 | - development 9 | 10 | jobs: 11 | - job: RDKit_Ubuntu_18_04 12 | pool: 13 | vmImage: ubuntu-18.04 14 | strategy: 15 | matrix: 16 | Python37: 17 | python.version: '37' 18 | Python36: 19 | python.version: '36' 20 | steps: 21 | - template: .azure-pipelines/rdkit_ubuntu1804_build.yml 22 | 23 | - job: RDKit_macOS_10_14 24 | pool: 25 | vmImage: macos-10.14 26 | variables: 27 | target_platform: 10.9 28 | strategy: 29 | matrix: 30 | Python37: 31 | python.version: '37' 32 | Python36: 33 | python.version: '36' 34 | steps: 35 | - template: .azure-pipelines/rdkit_mac_build.yml 36 | 37 | - job: Windows_VS2017_x64 38 | timeoutInMinutes: 90 39 | pool: 40 | vmImage: vs2017-win2016 41 | strategy: 42 | matrix: 43 | Python37: 44 | python.version: '37' 45 | Python36: 46 | python.version: '36' 47 | steps: 48 | - template: .azure-pipelines/rdkit_vs17_build.yml -------------------------------------------------------------------------------- /cairo_nox/meta.yaml: -------------------------------------------------------------------------------- 1 | # adapted from: https://github.com/conda/conda-recipes/blob/master/cairo/meta.yaml 2 | package: 3 | name: cairo 4 | version: "1.14.6" 5 | 6 | build: 7 | number: 0 8 | features: 9 | - nox 10 | 11 | requirements: 12 | build: 13 | - {{ compiler('cxx') }} 14 | - {{ compiler('c') }} 15 | # HACK: The python dep is here to get vc features to work 16 | - python [win] 17 | host: 18 | - pkg-config [unix] 19 | - xz [unix] 20 | - freetype 2.9.* [unix] 21 | - fontconfig 2.13.* [linux] 22 | - pixman 0.38.* 23 | - libpng 1.6.* 24 | - zlib 1.2.* 25 | - libxml2 2.9.* 26 | run: 27 | - freetype 2.9.* [unix] 28 | - fontconfig 2.13.* [linux] 29 | - libpng 1.6.* 30 | - pixman 0.38.* 31 | - zlib 1.2.* 32 | - libxml2 2.9.* 33 | 34 | 35 | 36 | source: 37 | fn: cairo-1.14.6.tar.xz 38 | url: http://cairographics.org/releases/cairo-1.14.6.tar.xz 39 | 40 | about: 41 | home: http://cairographics.org/ 42 | license: LGPL 2.1, MPL 1.1 43 | summary: Cairo is a 2D graphics library with support for multiple output devices. 44 | -------------------------------------------------------------------------------- /rdkit/meta.yaml: -------------------------------------------------------------------------------- 1 | package: 2 | name: rdkit 3 | # This is the real version, used in releases: 4 | # version is the last TAG + the number of commits since 5 | version: {{ environ.get('GIT_DESCRIBE_TAG', 'LOCAL').replace("_", ".").replace("Release.","") }}.{{ environ.get('GIT_DESCRIBE_NUMBER', 0) }} 6 | # This is the version used for the nightlies: 7 | # nightly version: 2020.09.1b.{{ environ.get('GIT_DESCRIBE_NUMBER', 1) }} 8 | 9 | 10 | source: 11 | git_url: https://github.com/rdkit/rdkit.git 12 | git_rev: Release_2020_09 13 | patches: 14 | - rdpaths.patch 15 | 16 | build: 17 | number: 1 18 | 19 | requirements: 20 | build: 21 | - requests 22 | - {{ compiler('cxx') }} 23 | - python 24 | - m2-patch [win] 25 | - cmake 26 | host: 27 | - libboost {{ libboost }} 28 | - boost-cpp 29 | - py-boost {{ libboost }} 30 | - python 31 | - numpy 32 | - pillow 33 | - freetype 34 | - nox [linux] 35 | - cairo 36 | - pkg-config [unix] 37 | - eigen 38 | - pandas <=0.24.0 39 | run: 40 | - libboost 41 | - py-boost 42 | - cairo 43 | - python 44 | - pillow 45 | - pandas 46 | - numpy >=1.12 47 | test: 48 | imports: 49 | - rdkit 50 | 51 | about: 52 | home: http://rdkit.org 53 | license: BSD 54 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | # We don't actually use the Travis Python, but this keeps it organized. 4 | - "3.6" 5 | #- "2.7" 6 | install: 7 | - sudo apt-get update 8 | # We do this conditionally because it saves us some downloading if the 9 | # version is the same. 10 | - if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then 11 | wget https://repo.continuum.io/miniconda/Miniconda2-latest-Linux-x86_64.sh -O miniconda.sh; 12 | else 13 | wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh; 14 | fi 15 | - bash miniconda.sh -b -p $HOME/miniconda 16 | - export PATH="$HOME/miniconda/bin:$PATH" 17 | - hash -r 18 | - conda config --set always_yes yes --set changeps1 no 19 | - conda update -q conda 20 | # Useful for debugging any issues with conda 21 | - conda info -a 22 | 23 | # Replace dep1 dep2 ... with your dependencies 24 | - conda install cmake git patch conda-build anaconda-client boost boost-cpp numpy=1.12 gxx_linux-64 gcc_linux-64 25 | 26 | script: 27 | # do the build: 28 | - source activate base && conda build nox 29 | - source activate base && conda build cairo_nox 30 | - source activate base && conda build rdkit 31 | 32 | after_success: 33 | - anaconda -t $CONDA_UPLOAD_TOKEN upload --no-progress -u rdkit -l nightly $HOME/miniconda/conda-bld/$TRAVIS_OS_NAME-64/rdkit*.tar.bz2 34 | -------------------------------------------------------------------------------- /rdkit/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | PY_INC=`$PYTHON -c "from distutils import sysconfig; print (sysconfig.get_python_inc(0, '$PREFIX'))"` 5 | cmake \ 6 | -D RDK_INSTALL_INTREE=OFF \ 7 | -D RDK_INSTALL_STATIC_LIBS=OFF \ 8 | -D RDK_BUILD_INCHI_SUPPORT=ON \ 9 | -D RDK_BUILD_AVALON_SUPPORT=ON \ 10 | -D RDK_BUILD_FREESASA_SUPPORT=ON \ 11 | -D RDK_BUILD_YAEHMOP_SUPPORT=ON \ 12 | -D RDK_USE_FLEXBISON=OFF \ 13 | -D RDK_BUILD_CAIRO_SUPPORT=ON \ 14 | -D RDK_BUILD_THREADSAFE_SSS=ON \ 15 | -D RDK_TEST_MULTITHREADED=ON \ 16 | -D RDK_BUILD_CPP_TESTS=OFF \ 17 | -D CMAKE_SYSTEM_PREFIX_PATH=$PREFIX \ 18 | -D CMAKE_INSTALL_PREFIX=$PREFIX \ 19 | -D Python_ADDITIONAL_VERSIONS=${PY_VER} \ 20 | -D PYTHON_EXECUTABLE=$PYTHON \ 21 | -D PYTHON_INCLUDE_DIR=${PY_INC} \ 22 | -D PYTHON_NUMPY_INCLUDE_PATH=$SP_DIR/numpy/core/include \ 23 | -D BOOST_ROOT=$PREFIX -D Boost_NO_SYSTEM_PATHS=ON \ 24 | -D Boost_NO_BOOST_CMAKE=TRUE \ 25 | -D CMAKE_BUILD_TYPE=Release \ 26 | . 27 | 28 | 29 | if [[ `uname` == 'Linux' ]]; then 30 | make -j$CPU_COUNT 31 | RDBASE=$SRC_DIR LD_LIBRARY_PATH="$PREFIX/lib:$SRC_DIR/lib" PYTHONPATH=$SRC_DIR ctest -j$CPU_COUNT --output-on-failure 32 | else 33 | make -j$CPU_COUNT install 34 | RDBASE=$SRC_DIR DYLD_FALLBACK_LIBRARY_PATH="$PREFIX/lib:$SRC_DIR/lib:/usr/lib" PYTHONPATH=$SRC_DIR ctest -j$CPU_COUNT --output-on-failure 35 | fi 36 | 37 | make install 38 | -------------------------------------------------------------------------------- /.azure-pipelines/rdkit_mac_build.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - bash: | 3 | cd /opt 4 | wget https://github.com/phracker/MacOSX-SDKs/releases/download/10.15/MacOSX$(target_platform).sdk.tar.xz 5 | tar Jxvf MacOSX$(target_platform).sdk.tar.xz 6 | displayName: Install MacOSX $(target_platform) SDK 7 | - script: | 8 | echo "Removing homebrew from Azure to avoid conflicts." 9 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall.sh)" 10 | displayName: Remove homebrew 11 | - bash: | 12 | source ${CONDA}/etc/profile.d/conda.sh 13 | sudo chown -R ${USER} ${CONDA} 14 | conda config --set always_yes yes --set changeps1 no 15 | conda update -q conda 16 | conda install conda-build 17 | displayName: Setup build environment 18 | - bash: | 19 | source ${CONDA}/etc/profile.d/conda.sh 20 | export CONDA_PY=${PYTHON_VERSION} 21 | sed -i '.bak' 's/git_rev: Release_2020_03/git_rev: master/; s/^ version:/# version;/; s/# nightly version:/version:/' rdkit/meta.yaml 22 | sed -i '.bak' 's/^ctest/# ctest/' rdkit/build.sh 23 | conda build rdkit 24 | displayName: Do conda build and test 25 | - bash: | 26 | mkdir -p $(Build.ArtifactStagingDirectory)/osx-64 27 | echo "-----------------" 28 | cp /usr/local/miniconda/conda-bld/osx-64/rdkit* $(Build.ArtifactStagingDirectory)/osx-64 29 | displayName: Create build artifacts 30 | - publish: $(Build.ArtifactStagingDirectory) 31 | artifact: conda_build_rdkit_osx_$(python.version) 32 | 33 | -------------------------------------------------------------------------------- /.azure-pipelines/rdkit_vs17_build.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - powershell: Write-Host "##vso[task.prependpath]$env:CONDA\Scripts" 3 | displayName: Setup windows path 4 | - script: | 5 | conda config --set always_yes yes --set changeps1 no 6 | conda update -q conda 7 | conda install conda-build jom 8 | displayName: Setup build environment 9 | - bash: | 10 | sed -i 's/git_rev: Release_2020_03/git_rev: master/; s/^ version:/# version;/; s/# nightly version:/version:/' rdkit/meta.yaml 11 | sed -i 's/CPU_COUNT/NUMBER_OF_PROCESSORS/; s/^ctest/rem ctest/' rdkit/bld.bat 12 | displayName: Update conda-build configuration 13 | - script: | 14 | # this bit is from here: https://github.com/microsoft/azure-pipelines-tasks/issues/9737 15 | pushd "C:\Program Files (x86)\Microsoft Visual Studio\Installer\" 16 | for /f "delims=" %%x in ('.\vswhere.exe -latest -property InstallationPath') do set VSPATH=%%x 17 | popd 18 | call "%VSPATH%\VC\Auxiliary\Build\vcvarsall.bat" x64 19 | 20 | set CONDA_PY=%PYTHON_VERSION% 21 | conda build rdkit 22 | displayName: run conda build (hopefully) 23 | - bash: | 24 | mkdir -p $(Build.ArtifactStagingDirectory)/win-64 25 | echo "-----------------" 26 | pwd 27 | cp /c/Miniconda/conda-bld/win-64/rdkit* $(Build.ArtifactStagingDirectory)/win-64 28 | ls -l $(Build.ArtifactStagingDirectory)/*/* 29 | displayName: Create build artifacts 30 | - publish: $(Build.ArtifactStagingDirectory) 31 | artifact: conda_build_rdkit_win64_$(python.version) 32 | -------------------------------------------------------------------------------- /docker-build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:centos6 2 | MAINTAINER Greg Landrum 3 | 4 | ARG anaconda_token 5 | ARG anaconda_user 6 | 7 | RUN yum update -y && yum install -y \ 8 | wget \ 9 | gcc-c++ \ 10 | git \ 11 | cairo \ 12 | libXext \ 13 | patch \ 14 | cmake 15 | 16 | # conda 17 | RUN echo 'export PATH=/opt/conda/bin:$PATH' > /etc/profile.d/conda.sh && \ 18 | wget --quiet https://repo.continuum.io/miniconda/Miniconda3-4.3.11-Linux-x86_64.sh && \ 19 | /bin/bash /Miniconda3-4.3.11-Linux-x86_64.sh -b -p /opt/conda && \ 20 | rm Miniconda3-4.3.11-Linux-x86_64.sh 21 | 22 | ENV PATH /opt/conda/bin:$PATH 23 | ENV LANG C 24 | 25 | # actually do the conda install 26 | RUN conda config --prepend channels https://conda.anaconda.org/rdkit 27 | RUN conda config --append channels https://conda.anaconda.org/conda-forge 28 | RUN conda install -y nomkl numpy=1.13 boost=1.56 eigen conda-build=2.1.17 anaconda-client 29 | 30 | 31 | RUN mkdir /src 32 | WORKDIR /src 33 | RUN git clone https://github.com/rdkit/conda-rdkit 34 | WORKDIR /src/conda-rdkit 35 | RUN git checkout development 36 | 37 | RUN \ 38 | conda build nox --quiet --no-anaconda-upload && \ 39 | conda build cairo_nox --quiet --no-anaconda-upload && \ 40 | CONDA_PY=35 conda build rdkit --quiet --user=$anaconda_user --token=$anaconda_token && \ 41 | CONDA_PY=36 conda build rdkit --quiet --user=$anaconda_user --token=$anaconda_token && \ 42 | CONDA_PY=27 conda build rdkit --quiet --user=$anaconda_user --token=$anaconda_token 43 | -------------------------------------------------------------------------------- /rdkit-postgresql/build.sh: -------------------------------------------------------------------------------- 1 | mkdir -p build 2 | cd build 3 | # in case there are any old psql builds: remove them 4 | rm -rf Code/PgSQL 5 | 6 | cmake \ 7 | -D RDK_BUILD_PGSQL=ON \ 8 | -D RDK_PGSQL_STATIC=ON \ 9 | -D RDK_INSTALL_STATIC_LIBS=ON \ 10 | -D RDK_INSTALL_INTREE=OFF \ 11 | -D RDK_INSTALL_STATIC_LIBS=OFF \ 12 | -D RDK_INSTALL_DEV_COMPONENT=OFF \ 13 | -D RDK_BUILD_INCHI_SUPPORT=ON \ 14 | -D RDK_BUILD_AVALON_SUPPORT=ON \ 15 | -D RDK_BUILD_FREESASA_SUPPORT=OFF \ 16 | -D RDK_USE_FLEXBISON=OFF \ 17 | -D RDK_BUILD_THREADSAFE_SSS=ON \ 18 | -D RDK_TEST_MULTITHREADED=ON \ 19 | -D RDK_BUILD_CPP_TESTS=OFF \ 20 | -D RDK_BUILD_PYTHON_WRAPPERS=OFF \ 21 | -D RDK_USE_BOOST_SERIALIZATION=OFF \ 22 | -D CMAKE_SYSTEM_PREFIX_PATH=$PREFIX \ 23 | -D CMAKE_INSTALL_PREFIX=$PREFIX \ 24 | -D BOOST_ROOT=$PREFIX -D Boost_NO_SYSTEM_PATHS=ON \ 25 | -D CMAKE_BUILD_TYPE=Release \ 26 | .. 27 | 28 | make -j$CPU_COUNT 29 | 30 | cd ./Code/PgSQL/rdkit 31 | 32 | /bin/bash -e ./pgsql_install.sh 33 | 34 | export PGPORT=54321 35 | export PGDATA=$SRC_DIR/pgdata 36 | 37 | rm -rf $PGDATA # cleanup required when building variants 38 | pg_ctl initdb 39 | 40 | # ensure that the rdkit extension is loaded at process startup 41 | echo "shared_preload_libraries = 'rdkit'" >> $PGDATA/postgresql.conf 42 | 43 | pg_ctl start -l $PGDATA/log.txt 44 | 45 | # wait a few seconds just to make sure that the server has started 46 | sleep 2 47 | 48 | set +e 49 | ctest 50 | check_result=$? 51 | set -e 52 | 53 | pg_ctl stop 54 | 55 | exit $check_result 56 | -------------------------------------------------------------------------------- /rdkit/bld.bat: -------------------------------------------------------------------------------- 1 | rem surely there's a better way than this 2 | if "%PY_VER%"=="2.7" ( 3 | set PYTHON_LIBRARY=python27.lib 4 | ) else if "%PY_VER%"=="3.4" ( 5 | set PYTHON_LIBRARY=python34.lib 6 | ) else if "%PY_VER%"=="3.5" ( 7 | set PYTHON_LIBRARY=python35.lib 8 | ) else if "%PY_VER%"=="3.6" ( 9 | set PYTHON_LIBRARY=python36.lib 10 | ) else if "%PY_VER%"=="3.7" ( 11 | set PYTHON_LIBRARY=python37.lib 12 | ) else ( 13 | echo "Unexpected version of python" 14 | exit 1 15 | ) 16 | 17 | where jom 2> NUL 18 | if %ERRORLEVEL% equ 0 ( 19 | set MAKE_CMD=jom -j%CPU_COUNT% 20 | ) else ( 21 | set MAKE_CMD=nmake 22 | ) 23 | 24 | cmake ^ 25 | -G "NMake Makefiles" ^ 26 | -D RDK_INSTALL_INTREE=OFF ^ 27 | -D RDK_BUILD_INCHI_SUPPORT=ON ^ 28 | -D RDK_BUILD_AVALON_SUPPORT=ON ^ 29 | -D RDK_BUILD_CAIRO_SUPPORT=ON ^ 30 | -D RDK_INSTALL_DEV_COMPONENT=OFF ^ 31 | -D RDK_INSTALL_STATIC_LIBS=OFF ^ 32 | -D RDK_BUILD_THREADSAFE_SSS=ON ^ 33 | -D RDK_TEST_MULTITHREADED=ON ^ 34 | -D RDK_BUILD_CPP_TESTS=OFF ^ 35 | -D RDK_USE_FLEXBISON=OFF ^ 36 | -D RDK_BUILD_YAEHMOP_SUPPORT=ON ^ 37 | -D Python_ADDITIONAL_VERSIONS=${PY_VER} ^ 38 | -D PYTHON_EXECUTABLE="%PYTHON%" ^ 39 | -D PYTHON_INCLUDE_DIR="%PREFIX%\include" ^ 40 | -D PYTHON_LIBRARY="%PREFIX%\libs\%PYTHON_LIBRARY%" ^ 41 | -D PYTHON_INSTDIR="%SP_DIR%" ^ 42 | -D BOOST_ROOT="%LIBRARY_PREFIX%" -D Boost_NO_SYSTEM_PATHS=ON ^ 43 | -D CMAKE_INSTALL_PREFIX="%LIBRARY_PREFIX%" ^ 44 | -D CMAKE_BUILD_TYPE=Release ^ 45 | . 46 | 47 | %MAKE_CMD% 48 | 49 | rem extend the environment settings in preparation to tests 50 | set RDBASE=%SRC_DIR% 51 | set PYTHONPATH=%RDBASE% 52 | 53 | ctest --output-on-failure -j%CPU_COUNT% 54 | %PYTHON% "%RECIPE_DIR%\pkg_version.py" 55 | 56 | %MAKE_CMD% install 57 | -------------------------------------------------------------------------------- /rdkit-postgresql/bld.bat: -------------------------------------------------------------------------------- 1 | %PYTHON% "%RECIPE_DIR%\pkg_version.py" 2 | 3 | cd "%SRC_DIR%" 4 | 5 | rmdir /s /q build 2> NUL 6 | mkdir build 7 | cd build 8 | :: in case there are any old psql builds: remove them 9 | rmdir /s /q Code\PgSQL 2> NUL 10 | 11 | cmake ^ 12 | -G "NMake Makefiles" ^ 13 | -D RDK_BUILD_PGSQL=ON ^ 14 | -D RDK_PGSQL_STATIC=ON ^ 15 | -D RDK_INSTALL_INTREE=OFF ^ 16 | -D RDK_INSTALL_STATIC_LIBS=OFF ^ 17 | -D RDK_INSTALL_DEV_COMPONENT=OFF ^ 18 | -D RDK_BUILD_INCHI_SUPPORT=ON ^ 19 | -D RDK_BUILD_AVALON_SUPPORT=ON ^ 20 | -D RDK_BUILD_FREESASA_SUPPORT=OFF ^ 21 | -D RDK_USE_FLEXBISON=OFF ^ 22 | -D RDK_BUILD_THREADSAFE_SSS=ON ^ 23 | -D RDK_TEST_MULTITHREADED=ON ^ 24 | -D RDK_OPTIMIZE_POPCNT=ON ^ 25 | -D RDK_BUILD_CPP_TESTS=OFF ^ 26 | -D RDK_BUILD_PYTHON_WRAPPERS=OFF ^ 27 | -D RDK_USE_BOOST_SERIALIZATION=OFF ^ 28 | -D CMAKE_SYSTEM_PREFIX_PATH=%LIBRARY_PREFIX% ^ 29 | -D CMAKE_INSTALL_PREFIX=%LIBRARY_PREFIX% ^ 30 | -D BOOST_ROOT=%PREFIX% -D Boost_NO_SYSTEM_PATHS=ON ^ 31 | -D CMAKE_BUILD_TYPE=Release ^ 32 | .. 33 | 34 | where jom 2> NUL 35 | if %ERRORLEVEL% equ 0 ( 36 | set MAKE_CMD=jom -j%CPU_COUNT% 37 | ) else ( 38 | set MAKE_CMD=nmake 39 | ) 40 | 41 | %MAKE_CMD% 42 | 43 | cd Code\PgSQL\rdkit 44 | call pgsql_install.bat 45 | 46 | set PGPORT=54321 47 | set PGDATA=%SRC_DIR%\pgdata 48 | 49 | pg_ctl initdb 50 | 51 | rem ensure that the rdkit extension is loaded at process startup 52 | echo shared_preload_libraries = 'rdkit' >> %PGDATA%\postgresql.conf 53 | 54 | pg_ctl -D %PGDATA% -l %PGDATA%/log.txt start 55 | 56 | rem wait a few seconds just to make sure that the server has started 57 | ping -n 5 127.0.0.1 > NUL 58 | 59 | set "RDBASE=%SRC_DIR%" 60 | ctest -V 61 | set check_result=%ERRORLEVEL% 62 | 63 | pg_ctl stop 64 | 65 | exit /b %check_result% 66 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:centos6 2 | 3 | RUN \ 4 | yum update -y && \ 5 | yum install wget -y && \ 6 | yum install tar -y && \ 7 | yum groupinstall "Development tools" -y 8 | 9 | RUN useradd rdkit 10 | 11 | RUN mkdir /home/rdkit/recipes 12 | WORKDIR /home/rdkit/recipes 13 | 14 | COPY boost ./boost 15 | COPY nox ./nox 16 | COPY cairo_nox ./cairo_nox 17 | COPY cairocffi ./cairocffi 18 | COPY eigen ./eigen 19 | COPY rdkit ./rdkit 20 | COPY ncurses ./ncurses 21 | COPY postgresql ./postgresql 22 | COPY rdkit-postgresql ./rdkit-postgresql 23 | COPY postgresql95 ./postgresql95 24 | COPY rdkit-postgresql95 ./rdkit-postgresql95 25 | 26 | RUN chown -R rdkit:rdkit . 27 | 28 | WORKDIR /home/rdkit 29 | USER rdkit 30 | 31 | RUN wget http://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh 32 | RUN /bin/bash ./Miniconda-latest-Linux-x86_64.sh -b -p /home/rdkit/miniconda 33 | 34 | ENV PATH /home/rdkit/miniconda/bin:$PATH 35 | 36 | RUN \ 37 | conda update conda --yes --quiet && \ 38 | conda install jinja2 conda-build anaconda-client --yes --quiet 39 | 40 | # on centos6 the max path length for a unix socket is 107 characters. this 41 | # limit is exceeded when the postgresql build is located under the default 42 | # filesystem path. 43 | # 44 | # with the current conda implementation (conda 4.2.13 - conda-build 2.0.10) 45 | # the following $CONDA_BLD_PATH settings are sufficient to work around the 46 | # problem. 47 | # 48 | # (as a side effect, packages will be found in /home/rdkit/bld/linux-64) 49 | RUN mkdir /home/rdkit/bld 50 | ENV CONDA_BLD_PATH /home/rdkit/bld 51 | 52 | WORKDIR /home/rdkit/recipes 53 | 54 | RUN \ 55 | conda build boost --quiet --no-anaconda-upload && \ 56 | conda build nox --quiet --no-anaconda-upload && \ 57 | conda build cairo_nox --quiet --no-anaconda-upload && \ 58 | conda build cairocffi --quiet --no-anaconda-upload && \ 59 | conda build eigen --quiet --no-anaconda-upload && \ 60 | conda build rdkit --quiet --no-anaconda-upload && \ 61 | conda build ncurses --quiet --no-anaconda-upload && \ 62 | conda build postgresql --quiet --no-anaconda-upload && \ 63 | conda build rdkit-postgresql --quiet --no-anaconda-upload && \ 64 | conda build postgresql95 --quiet --no-anaconda-upload && \ 65 | conda build rdkit-postgresql95 --quiet --no-anaconda-upload && \ 66 | CONDA_PY=35 conda build boost --quiet --no-anaconda-upload && \ 67 | CONDA_PY=35 conda build nox --quiet --no-anaconda-upload && \ 68 | CONDA_PY=35 conda build cairo_nox --quiet --no-anaconda-upload && \ 69 | CONDA_PY=35 conda build cairocffi --quiet --no-anaconda-upload && \ 70 | CONDA_PY=35 conda build eigen --quiet --no-anaconda-upload && \ 71 | CONDA_PY=35 conda build rdkit --quiet --no-anaconda-upload && \ 72 | CONDA_PY=35 conda build postgresql --quiet --no-anaconda-upload && \ 73 | CONDA_PY=35 conda build rdkit-postgresql --quiet --no-anaconda-upload && \ 74 | CONDA_PY=35 conda build postgresql95 --quiet --no-anaconda-upload && \ 75 | CONDA_PY=35 conda build rdkit-postgresql95 --quiet --no-anaconda-upload && \ 76 | CONDA_NPY=110 conda build rdkit --quiet --no-anaconda-upload && \ 77 | CONDA_PY=35 CONDA_NPY=110 conda build rdkit --quiet --no-anaconda-upload 78 | 79 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Conda recipes for the RDKit 2 | ########################### 3 | 4 | NOTE 5 | ==== 6 | 7 | This repo is now only used to provide the occasional nightly or beta build of the RDKit. Production RDKit conda builds are provided by [conda-forge](https://anaconda.org/conda-forge/rdkit) 8 | 9 | 10 | Conda 11 | ===== 12 | 13 | Conda is an open-source, cross-platform, software package manager. It supports the packaging and distribution of software components, and manages their installation inside isolated execution environments. It has several analogies with pip and virtualenv, but it is designed to be more "python-agnostic" and more suitable for the distribution of binary packages and their dependencies. 14 | 15 | How to get conda 16 | ---------------- 17 | 18 | The easiest way to get Conda is having it installed as part of the `Anaconda Python distribution `_. A possible (but a bit more complex to use) alternative is provided with the smaller and more self-contained `Miniconda `_. The conda source code repository is available on `github `_ and additional documentation is provided by the project `website `_. 19 | 20 | How to build the packages 21 | ========================= 22 | 23 | Software and system requirements 24 | -------------------------------- 25 | 26 | A recent version of conda must be installed and included in the user's PATH. If not already included by the available anaconda/miniconda installation, the 'conda build' subcommand must also be installed:: 27 | 28 | $ conda install conda-build 29 | 30 | The recipes provided with this repository perform the automated download and management of the Avalon and InChI source code distributions as part of the RDKit build process, and most of the other 3rd party dependencies are readily available from the Anaconda Python distribution. Compared to the usual RDKit build procedure, the setup and configuration part is therefore strongly simplified, but depending on the operating system a few additional components may be required: 31 | 32 | Linux 33 | ..... 34 | 35 | If not already installed as a dependency of the conda-build package, the patchelf utility mush be also present. It can be available with the operating system or it may be installed inside the conda root environment with the following command:: 36 | 37 | $ conda install patchelf 38 | 39 | Windows 40 | ....... 41 | 42 | The recipes assume the availability of the Microsoft Visual C++ 2010 commmand-line toolchain. The freely available Express edition should provide all the necessary. 43 | 44 | The cmake build utility should be also installed. 45 | 46 | A git client is optionally required for building the version of the recipes which is available from the development branch. 47 | 48 | Building the packages 49 | --------------------- 50 | 51 | The latest stable version of these recipes (building the most recent RDKit release) may be downloaded from the following `link `_. Alternatively, users may directly clone this repository from github:: 52 | 53 | $ git clone https://github.com/rdkit/conda-rdkit.git 54 | 55 | Recipes for building the current development version of the RDKit are available from the development branch of the same repository. 56 | 57 | All commands in the described build procedure are assumed to run in a shell or windows command prompt already configured to make available conda and the compiler toolchain that may be needed for the specific platform. Moreover, the working directory for the build commands described in this section is assumed to correspond with the top level directory of the recipes distribution (where this README file is located). 58 | 59 | The build process doesn't require activating and configuring a dedicated python environment. The build commands may run within the root environment and conda will take care of automating all of the process, starting from downloading the source code and proceeding to unpacking it into a suitable working directory, creating the necessary build and test environments with the required dependencies, compiling, testing and finally storing the resulting binary packages into a local directory. 60 | 61 | If all of the necessary conditions are satisfied, building the RDKit may then reduce to running the following two commands:: 62 | 63 | $ conda build boost 64 | $ conda build rdkit 65 | 66 | For the linux platform an additional recipe is available, supporting the build of the postgresql cartridge:: 67 | 68 | $ conda build rdkit-postgresql 69 | 70 | Conda will store the produced packages into a local repository/channel, by default placed inside the anaconda installation (e.g. on a linux 64 bits system the packages would be found by default under ~/anaconda/conda-bld/linux-64). 71 | 72 | Installing and using the packages 73 | --------------------------------- 74 | 75 | Creating a new conda environment with the RDKit installed using these packages requires one single command similar to the following:: 76 | 77 | $ conda create -c -n my-rdkit-env rdkit 78 | 79 | where '' is to be replaced with the URL of the package repository where the packages have been placed for distribution. 80 | 81 | If the packages have been built locally and are still available inside the user's conda build directories, then specifying the '--use-local' option should be sufficient and configuring a distribution channel is not necessary:: 82 | 83 | $ conda create --use-local -n my-rdkit-env rdkit 84 | 85 | A new environment will be created including the required dependencies:: 86 | 87 | Fetching package metadata: ... 88 | Solving package specifications: . 89 | Package plan for installation in environment /home/ric/anaconda/envs/my-rdkit-env: 90 | 91 | The following packages will be linked: 92 | 93 | package | build 94 | ---------------------------|----------------- 95 | boost-1.55.0 | py27_1 hard-link 96 | bzip2-1.0.6 | 0 hard-link 97 | numpy-1.8.1 | py27_0 hard-link 98 | openssl-1.0.1g | 0 hard-link 99 | python-2.7.6 | 1 hard-link 100 | rdkit-2014.03.1pre | np18py27_1 hard-link 101 | readline-6.2 | 2 hard-link 102 | sqlite-3.7.13 | 0 hard-link 103 | system-5.8 | 1 hard-link 104 | tk-8.5.15 | 0 hard-link 105 | zlib-1.2.7 | 0 hard-link 106 | 107 | Proceed ([y]/n)? y 108 | 109 | Finally, the new environment must be activated, so that the corresponding python interpreter becomes available in the same shell:: 110 | 111 | $ source activate my-rdkit-env 112 | 113 | Windows users will use a slightly different command:: 114 | 115 | C:\> activate my-rdkit-env 116 | 117 | -------------------------------------------------------------------------------- /rdkit/avalon_reaccsio.c: -------------------------------------------------------------------------------- 1 | /* 2 | This is the AvalonToolkit 1.2.0 file SourceDistribution/common/reaccsio.c 3 | modified at line 1446 to comment-out a call to MyFree and fix a crash 4 | occurring on windows. 5 | */ 6 | 7 | // 8 | // Copyright (c) 2010, Novartis Institutes for BioMedical Research Inc. 9 | // All rights reserved. 10 | // 11 | // Redistribution and use in source and binary forms, with or without 12 | // modification, are permitted provided that the following conditions are 13 | // met: 14 | // 15 | // * Redistributions of source code must retain the above copyright 16 | // notice, this list of conditions and the following disclaimer. 17 | // * Redistributions in binary form must reproduce the above 18 | // copyright notice, this list of conditions and the following 19 | // disclaimer in the documentation and/or other materials provided 20 | // with the distribution. 21 | // * Neither the name of Novartis Institutes for BioMedical Research Inc. 22 | // nor the names of its contributors may be used to endorse or promote 23 | // products derived from this software without specific prior written permission. 24 | // 25 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | // 37 | /************************************************************************/ 38 | /* */ 39 | /* File: reaccsio.c */ 40 | /* */ 41 | /* Purpose: This file implements the routines to read RD-, */ 42 | /* SD-, and RXN-files. */ 43 | /* */ 44 | /************************************************************************/ 45 | 46 | #include 47 | #include 48 | 49 | #include "local.h" 50 | #include "reaccs.h" 51 | #include "forio.h" 52 | #include "reaccsio.h" 53 | #include "utilities.h" 54 | #include "symbol_lists.h" 55 | 56 | /** 57 | * Reads an ATOM description frm a version 3 MOL file. 58 | * mp is needed to save atom properties not stored with the atom. 59 | */ 60 | int ReadV30Atom(Fortran_FILE *fp, 61 | struct reaccs_atom_t *ap, 62 | struct reaccs_molecule_t *mp) 63 | { 64 | int nitems; 65 | char buffer[MAX_BUFFER+1]; 66 | int charge_radical; 67 | char prop[10][20]; 68 | int seq; 69 | int idummy; 70 | float mass; 71 | int i; 72 | char symbol[100]; 73 | struct symbol_list_t *list; 74 | 75 | if (fp->status != FORTRAN_NORMAL) return(fp->status); 76 | 77 | strncpy(buffer,fp->buffer,MAX_BUFFER); 78 | 79 | nitems = sscanf(buffer+strlen("M V30"), 80 | "%d %s %f %f %f %d %s %s %s %s %s %s %s %s %s %s", 81 | &seq, symbol, 82 | &ap->x, &ap->y, &ap->z, 83 | &ap->mapping, 84 | prop[0], prop[1], prop[2], prop[3], prop[4], 85 | prop[5], prop[6], prop[7], prop[8], prop[9]); 86 | 87 | if (nitems < 6) 88 | { 89 | ShowMessageI("incorrect # (%d) of arguments on atom line", 90 | "ReadV30Atom:", 91 | nitems); 92 | ShowMessageS("buffer ==\n%s\n","ReadV30Atom",fp->buffer); 93 | GetBuffer(fp); 94 | return(FORTRAN_ERROR); 95 | } 96 | 97 | if (strlen(symbol) <= 3) 98 | strcpy(ap->atom_symbol, symbol); 99 | else // need to parse symbol 100 | { 101 | mp->symbol_lists = 102 | ParseV30SymbolList(symbol, ap-mp->atom_array, mp, mp->symbol_lists); 103 | mp->n_atom_lists = 0; 104 | for (list=mp->symbol_lists; !IsNULL(list); list = list->next) mp->n_atom_lists++; 105 | } 106 | 107 | if (nitems >= 16) 108 | ShowMessageI("Warning %d properties for atom.\n", 109 | "ReadV30Atom:", (nitems-6)); 110 | 111 | /* Processing properties */ 112 | for (i=0; icharge)) continue; 115 | if (1 == sscanf(prop[i], "RAD=%d", &ap->radical)) continue; 116 | if (1 == sscanf(prop[i], "HCOUNT=%d", &ap->query_H_count)) continue; 117 | if (1 == sscanf(prop[i], "CFG=%d", &ap->stereo_parity)) continue; 118 | if (1 == sscanf(prop[i], "VAL=%d", &ap->dummy1)) continue; 119 | if (1 == sscanf(prop[i], "SUBST=%d", &ap->sub_desc)) continue; 120 | if (1 == sscanf(prop[i], "MASS=%f", &mass)) 121 | { 122 | ap->mass_difference = LookupMassDifference(mass, ap->atom_symbol); 123 | continue; 124 | } 125 | if (1 == sscanf(prop[i], "RBCNT=%d", &idummy)) continue; 126 | if (1 == sscanf(prop[i], "UNSAT=%d", &idummy)) continue; 127 | fprintf(stderr, "ignoring '%s' for atom %d\n", prop[i], seq); 128 | } 129 | GetBuffer(fp); 130 | return(FORTRAN_NORMAL); 131 | } 132 | 133 | /** 134 | * Read a V3.0 MOL file bond record. 135 | */ 136 | int ReadV30Bond(Fortran_FILE *fp, struct reaccs_bond_t *bp) 137 | { 138 | int nitems; 139 | char buffer[MAX_BUFFER+1]; 140 | char prop[10][20]; 141 | int seq; 142 | int i; 143 | char symbol[10]; 144 | 145 | if (fp->status != FORTRAN_NORMAL) return(fp->status); 146 | 147 | strncpy(buffer,fp->buffer,MAX_BUFFER); 148 | 149 | nitems = sscanf(buffer+strlen("M V30"), 150 | "%d %d %d %d %s %s %s %s %s %s %s %s %s %s", 151 | &seq, &bp->bond_type, 152 | &bp->atoms[0], &bp->atoms[1], 153 | prop[0], prop[1], prop[2], prop[3], prop[4], 154 | prop[5], prop[6], prop[7], prop[8], prop[9]); 155 | 156 | if (nitems < 4) 157 | { 158 | ShowMessageI("incorrect # (%d) of arguments on bond line", 159 | "ReadV30Atom:", 160 | nitems); 161 | ShowMessageS("buffer ==\n%s\n","ReadV30Atom",fp->buffer); 162 | GetBuffer(fp); 163 | return(FORTRAN_ERROR); 164 | } 165 | 166 | if (nitems >= 14) 167 | ShowMessageI("Warning %d properties for bond.\n", 168 | "ReadV30Bond:", (nitems-6)); 169 | 170 | /* Processing properties */ 171 | for (i=0; istatus != FORTRAN_NORMAL) return(fp->status); 186 | 187 | strncpy(buffer,fp->buffer,MAX_BUFFER); 188 | 189 | if (buffer[31] == ' ') buffer[32] = '?'; /* to cope with empty atom types */ 190 | nitems = sscanf(buffer, 191 | "%10f%10f%10f %s", 192 | &ap->x, &ap->y, &ap->z, 193 | ap->atom_symbol); 194 | BlankToZero(buffer+34); 195 | ap->mass_difference = 0; charge_radical = 0; 196 | ap->stereo_parity = NONE; 197 | ap->query_H_count = 0; 198 | ap->query_stereo_box = 0; 199 | ap->dummy1 = 0; ap->dummy2 = 0; ap->dummy3 = 0; ap->dummy4 = 0; 200 | ap->sub_desc = NONE; 201 | ap->mapping = NONE; 202 | ap->second_stereo_parity = NONE; 203 | ap->dummy5 = 0; 204 | ap->atext[0]='\0'; 205 | sscanf(buffer+34, 206 | "%2d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d", 207 | &ap->mass_difference, 208 | &charge_radical, &ap->stereo_parity, 209 | &ap->query_H_count, &ap->query_stereo_box, 210 | &ap->dummy1, &ap->dummy2, &ap->dummy3, &ap->dummy4, 211 | &ap->mapping, &ap->second_stereo_parity, 212 | &ap->dummy5); 213 | 214 | if (nitems >= 4) 215 | { 216 | SplitChargeRadical(charge_radical, &ap->charge, &ap->radical); 217 | GetBuffer(fp); 218 | return(FORTRAN_NORMAL); 219 | } 220 | else 221 | { 222 | ShowMessageI("incorrect # (%d) of arguments on atom line", 223 | "ReadREACCSAtom:", 224 | nitems); 225 | ShowMessageS("buffer ==\n%s\n","ReadREACCSAtom",fp->buffer); 226 | GetBuffer(fp); 227 | return(FORTRAN_ERROR); 228 | } 229 | } 230 | 231 | /* 232 | * This section manages the flag that tells the printing functions to 233 | * strip any trailing zeros on MOL file output to save space. 234 | */ 235 | static int strip_zeroes = FALSE; 236 | 237 | int SetStripZeroes(int do_strip) 238 | { 239 | int result; 240 | result = strip_zeroes; 241 | strip_zeroes = do_strip; 242 | return (result); 243 | } 244 | 245 | void PrintMACCSAtom(FILE *fp, struct reaccs_atom_t *ap) 246 | { 247 | fprintf(fp,"%10.4f%10.4f%10.4f",ap->x,ap->y,ap->z); 248 | fprintf(fp," %-3s%2d%3d", 249 | ap->atom_symbol, ap->mass_difference, 250 | (ANY_CHARGE == CombineChargeRadical(ap->charge,ap->radical)) ? 251 | 0 : CombineChargeRadical(ap->charge,ap->radical)); 252 | if (!strip_zeroes || 253 | ap->stereo_parity != 0 || 254 | ap->query_H_count != 0) 255 | fprintf(fp,"%3d%3d\n", ap->stereo_parity, ap->query_H_count); 256 | else 257 | fprintf(fp,"\n"); 258 | } 259 | 260 | static char *color_strings[] = 261 | { 262 | "NO_COLOR", 263 | "STRATEGIC_COLOR", 264 | "MODIFIED_COLOR", 265 | "ALPHA_COLOR", 266 | "ALLYL_COLOR", 267 | "CLOSURE_COLOR", 268 | "RING_COLOR", 269 | "SINGLE_COLOR", 270 | "MULTIPLE_COLOR", 271 | "PROTECTION_COLOR", 272 | "INTER_COLOR", 273 | "INTRA_COLOR", 274 | "REAGENT_COLOR", 275 | "ADD_REMOVE_COLOR", 276 | "DOUBLE_COLOR", 277 | }; 278 | 279 | void PrintREACCSAtom(FILE *fp, 280 | struct reaccs_atom_t *ap) 281 | { 282 | int i; 283 | fprintf(fp,"%10.4f%10.4f%10.4f",ap->x,ap->y,ap->z); 284 | fprintf(fp," %-3s%2d%3d", 285 | ap->atom_symbol, ap->mass_difference, 286 | (ANY_CHARGE == CombineChargeRadical(ap->charge,ap->radical)) ? 287 | 0 : CombineChargeRadical(ap->charge,ap->radical)); 288 | if (!strip_zeroes || 289 | ap->stereo_parity != 0 || 290 | ap->query_H_count != 0 || 291 | ap->query_stereo_box != 0 || 292 | ap->dummy1 != 0 || 293 | ap->dummy2 != 0 || 294 | ap->dummy3 != 0 || 295 | ap->dummy4 != 0 || 296 | ap->dummy5 != 0 || 297 | ap->mapping != 0 || 298 | ap->second_stereo_parity != 0) 299 | { 300 | fprintf(fp,"%3d%3d%3d", 301 | ap->stereo_parity, 302 | ap->query_H_count, ap->query_stereo_box); 303 | fprintf(fp,"%3d%3d%3d%3d", 304 | ap->dummy1, ap->dummy2, ap->dummy3, ap->dummy4); 305 | fprintf(fp,"%3d%3d%3d", 306 | ap->mapping, ap->second_stereo_parity, ap->dummy5); 307 | if (ap->color != NONE && 0) 308 | { 309 | for (i=1; i<14; i++) 310 | if (ap->color & (1<<(i-1))) fprintf(fp," %s", color_strings[i]); 311 | } 312 | fprintf(fp,"\n"); 313 | } 314 | else 315 | fprintf(fp,"\n"); 316 | } 317 | 318 | int ReadREACCSBond(Fortran_FILE *fp, struct reaccs_bond_t *bp) 319 | { 320 | int nitems, i; 321 | char buffer[MAX_BUFFER+1]; 322 | 323 | if (fp->status != FORTRAN_NORMAL) return(fp->status); 324 | 325 | strncpy(buffer,fp->buffer,MAX_BUFFER); 326 | /* zero pad only atom numbers! */ 327 | for (i=0; i<6; i++) if (buffer[i] == ' ') buffer[i] = '0'; 328 | 329 | bp->stereo_symbol = 0; 330 | bp->dummy = 0; 331 | bp->topography = 0; 332 | bp->reaction_mark = NONE; 333 | // make sure spaces are interpreted the Fortran-way 334 | for (i=9; iatoms[0], &bp->atoms[1], 342 | &bp->bond_type, &bp->stereo_symbol, 343 | &bp->dummy, 344 | &bp->topography, &bp->reaction_mark); 345 | 346 | if (nitems >= 3) 347 | { 348 | GetBuffer(fp); 349 | return(FORTRAN_NORMAL); 350 | } 351 | else 352 | { 353 | ShowMessageI("incorrect # (%d) of arguments on bond line", 354 | "ReadREACCSBond", 355 | nitems); 356 | ShowMessageS("buffer ==\n%s\n","ReadREACCSBond",buffer); 357 | return(FORTRAN_ERROR); 358 | } 359 | } 360 | 361 | void PrintMACCSBond(FILE *fp, struct reaccs_bond_t *bp) 362 | { 363 | int stereo_symbol = bp->stereo_symbol; 364 | /* CIS_TRANS_SWAPPED is not leagal in a MOL file */ 365 | if (stereo_symbol == CIS_TRANS_SWAPPED) stereo_symbol = CIS_TRANS_EITHER; 366 | 367 | fprintf(fp,"%3d%3d%3d%3d\n", 368 | bp->atoms[0], bp->atoms[1], 369 | bp->bond_type, stereo_symbol); 370 | } 371 | 372 | void PrintREACCSBond(FILE *fp, 373 | struct reaccs_bond_t *bp) 374 | { 375 | int stereo_symbol = bp->stereo_symbol; 376 | /* CIS_TRANS_SWAPPED is not leagal in a MOL file */ 377 | if (stereo_symbol == CIS_TRANS_SWAPPED) stereo_symbol = CIS_TRANS_EITHER; 378 | 379 | fprintf(fp,"%3d%3d%3d%3d", 380 | bp->atoms[0], bp->atoms[1], 381 | bp->bond_type, stereo_symbol); 382 | if (!strip_zeroes || 383 | bp->topography != 0 || 384 | bp->reaction_mark != 0) 385 | fprintf(fp,"%3d%3d%3d\n", 386 | bp->dummy, 387 | bp->topography, bp->reaction_mark); 388 | else 389 | fprintf(fp,"\n"); 390 | } 391 | 392 | struct prop_line_t * ReadProperties(Fortran_FILE *fp, 393 | struct reaccs_molecule_t *mp, 394 | int nprops) 395 | /* 396 | * Reads the nprops property lines off the file *fp. Interpretable lines 397 | * are stored in *mp while a pointer to the other lines is returned. 398 | */ 399 | { 400 | int nentries, n; 401 | int tmp_ats[8]; 402 | int tmp_vals[8]; 403 | struct prop_line_t *hp, *hhp, *result; 404 | int atom; 405 | float value; 406 | 407 | int old_nprops; 408 | 409 | old_nprops = nprops; 410 | result = (struct prop_line_t *)NULL; 411 | while (nprops-- > 0) 412 | { 413 | if (STRING_BEGINS(fp->buffer,"M CHG")) /* charge property */ 414 | { 415 | sscanf(fp->buffer+strlen("M CHG"), "%3d", &nentries); 416 | n = sscanf(fp->buffer+strlen("M CHG")+3, 417 | " %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", 418 | &tmp_ats[0], &tmp_vals[0], &tmp_ats[1], &tmp_vals[1], 419 | &tmp_ats[2], &tmp_vals[2], &tmp_ats[3], &tmp_vals[3], 420 | &tmp_ats[4], &tmp_vals[4], &tmp_ats[5], &tmp_vals[5], 421 | &tmp_ats[6], &tmp_vals[6], &tmp_ats[7], &tmp_vals[7]); 422 | if (n != nentries*2) 423 | { 424 | ShowMessageI("n = %d","ReadProperties", n); 425 | ShowMessageI("nentries = %d","ReadProperties", nentries); 426 | ShowMessageS("buffer = '%s'","ReadProperties",fp->buffer); 427 | } 428 | for (n=0; natom_array[tmp_ats[n]-1].charge = tmp_vals[n]; 430 | } 431 | else if (STRING_BEGINS(fp->buffer,"M RAD")) /* radical property */ 432 | { 433 | sscanf(fp->buffer+strlen("M RAD"), "%3d", &nentries); 434 | n = sscanf(fp->buffer+strlen("M RAD")+3, 435 | " %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", 436 | &tmp_ats[0], &tmp_vals[0], &tmp_ats[1], &tmp_vals[1], 437 | &tmp_ats[2], &tmp_vals[2], &tmp_ats[3], &tmp_vals[3], 438 | &tmp_ats[4], &tmp_vals[4], &tmp_ats[5], &tmp_vals[5], 439 | &tmp_ats[6], &tmp_vals[6], &tmp_ats[7], &tmp_vals[7]); 440 | if (n != nentries*2) 441 | { 442 | ShowMessageI("n = %d","ReadProperties", n); 443 | ShowMessageI("nentries = %d","ReadProperties", nentries); 444 | ShowMessageS("buffer = '%s'","ReadProperties",fp->buffer); 445 | } 446 | for (n=0; natom_array[tmp_ats[n]-1].radical = tmp_vals[n]; 448 | } 449 | else if (STRING_BEGINS(fp->buffer,"M SUB")) /* subst. degree property */ 450 | { 451 | sscanf(fp->buffer+strlen("M SUB"), "%3d", &nentries); 452 | n = sscanf(fp->buffer+strlen("M SUB")+3, 453 | " %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", 454 | &tmp_ats[0], &tmp_vals[0], &tmp_ats[1], &tmp_vals[1], 455 | &tmp_ats[2], &tmp_vals[2], &tmp_ats[3], &tmp_vals[3], 456 | &tmp_ats[4], &tmp_vals[4], &tmp_ats[5], &tmp_vals[5], 457 | &tmp_ats[6], &tmp_vals[6], &tmp_ats[7], &tmp_vals[7]); 458 | if (n != nentries*2) 459 | { 460 | ShowMessageI("n = %d","ReadProperties", n); 461 | ShowMessageI("nentries = %d","ReadProperties", nentries); 462 | ShowMessageS("buffer = '%s'","ReadProperties",fp->buffer); 463 | } 464 | for (n=0; natom_array[tmp_ats[n]-1].sub_desc = tmp_vals[n]; 466 | } 467 | else if (STRING_BEGINS(fp->buffer,"V ")) /* value for PC files */ 468 | { 469 | n = sscanf(fp->buffer+strlen("V "), " %d %f", &atom, &value); 470 | if (n == 2) 471 | mp->atom_array[atom-1].value = value; 472 | else 473 | { 474 | ShowMessage("value line ignored","ReadProperties"); 475 | ShowMessageS("buffer = '%s'","ReadProperties",fp->buffer); 476 | } 477 | } 478 | else if (STRING_BEGINS(fp->buffer,"M END")) 479 | { 480 | if (nprops != 0) 481 | { 482 | if (old_nprops != 999) 483 | ShowMessage("M END line was not last property line", 484 | "ReadProperties"); 485 | nprops = 0; 486 | } 487 | // GetBuffer(fp); 488 | break; 489 | } 490 | else if (STRING_BEGINS(fp->buffer,"M RGP")) /* R-Group Lines */ 491 | { 492 | hp = TypeAlloc(1,struct prop_line_t); 493 | strncpy(hp->text, fp->buffer, MDL_MAXLINE); 494 | hp->text[MDL_MAXLINE] = '\0'; 495 | hp->next = result; result = hp; 496 | } 497 | else if (STRING_BEGINS(fp->buffer,"G ")) /* Group Lines */ 498 | { 499 | hp = TypeAlloc(1,struct prop_line_t); 500 | strncpy(hp->text, fp->buffer, MDL_MAXLINE); 501 | hp->text[MDL_MAXLINE] = '\0'; 502 | hp->next = result; result = hp; 503 | GetBuffer(fp); nprops--; 504 | hp = TypeAlloc(1,struct prop_line_t); 505 | strncpy(hp->text, fp->buffer, MDL_MAXLINE); 506 | hp->text[MDL_MAXLINE] = '\0'; 507 | hp->next = result; result = hp; 508 | } 509 | else if (STRING_BEGINS(fp->buffer,"A ")) /* atom text Lines */ 510 | { 511 | n = sscanf(fp->buffer+strlen("A "), " %d", &atom); 512 | if (n==1 && atom <= mp->n_atoms && 0 == strcmp(mp->atom_array[atom-1].atom_symbol, "R")) 513 | { // interpret atom text as atom label 514 | GetBuffer(fp); nprops--; 515 | strncpy(mp->atom_array[atom-1].atext, fp->buffer, MDL_MAXLINE); 516 | mp->atom_array[atom-1].atext[MDL_MAXLINE] = '\0'; 517 | } 518 | else // just store as standard property 519 | { 520 | hp = TypeAlloc(1,struct prop_line_t); 521 | strncpy(hp->text, fp->buffer, MDL_MAXLINE); 522 | hp->text[MDL_MAXLINE] = '\0'; 523 | hp->next = result; result = hp; 524 | GetBuffer(fp); nprops--; 525 | hp = TypeAlloc(1,struct prop_line_t); 526 | strncpy(hp->text, fp->buffer, MDL_MAXLINE); 527 | hp->text[MDL_MAXLINE] = '\0'; 528 | hp->next = result; result = hp; 529 | } 530 | } 531 | else if (STRING_BEGINS(fp->buffer,"M ISO")) /* isotopic labelling */ 532 | { 533 | /* Just ignore these, because they are taken care of by */ 534 | /* the mass difference field. It would require a major */ 535 | /* change to modify the semantics now. Room for improvement! */ 536 | sscanf(fp->buffer+strlen("M ISO"), "%3d", &nentries); 537 | n = sscanf(fp->buffer+strlen("M ISO")+3, 538 | " %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", 539 | &tmp_ats[0], &tmp_vals[0], &tmp_ats[1], &tmp_vals[1], 540 | &tmp_ats[2], &tmp_vals[2], &tmp_ats[3], &tmp_vals[3], 541 | &tmp_ats[4], &tmp_vals[4], &tmp_ats[5], &tmp_vals[5], 542 | &tmp_ats[6], &tmp_vals[6], &tmp_ats[7], &tmp_vals[7]); 543 | if (n != nentries*2) 544 | { 545 | ShowMessageI("n = %d","ReadProperties", n); 546 | ShowMessageI("nentries = %d","ReadProperties", nentries); 547 | ShowMessageS("buffer = '%s'","ReadProperties",fp->buffer); 548 | } 549 | /* Just handle mass difference for substitution point labels and some well-known other atoms */ 550 | for (n=0; natom_array[tmp_ats[n]-1].atom_symbol, "R")) 552 | mp->atom_array[tmp_ats[n]-1].mass_difference = tmp_vals[n]; 553 | else if (0 == strcmp(mp->atom_array[tmp_ats[n]-1].atom_symbol, "H") && 1 <= tmp_vals[n] && tmp_vals[n] <= 3) 554 | mp->atom_array[tmp_ats[n]-1].mass_difference = tmp_vals[n]-1; 555 | else if (0 == strcmp(mp->atom_array[tmp_ats[n]-1].atom_symbol,"Li") && 6 <= tmp_vals[n] && tmp_vals[n] <= 7) 556 | mp->atom_array[tmp_ats[n]-1].mass_difference = tmp_vals[n]-7; 557 | else if (0 == strcmp(mp->atom_array[tmp_ats[n]-1].atom_symbol, "B") && 10 <= tmp_vals[n] && tmp_vals[n] <= 11) 558 | mp->atom_array[tmp_ats[n]-1].mass_difference = tmp_vals[n]-11; 559 | else if (0 == strcmp(mp->atom_array[tmp_ats[n]-1].atom_symbol, "C") && 12 <= tmp_vals[n] && tmp_vals[n] <= 14) 560 | mp->atom_array[tmp_ats[n]-1].mass_difference = tmp_vals[n]-12; 561 | else if (0 == strcmp(mp->atom_array[tmp_ats[n]-1].atom_symbol, "N") && 13 <= tmp_vals[n] && tmp_vals[n] <= 15) 562 | mp->atom_array[tmp_ats[n]-1].mass_difference = tmp_vals[n]-14; 563 | else if (0 == strcmp(mp->atom_array[tmp_ats[n]-1].atom_symbol, "O") && 16 <= tmp_vals[n] && tmp_vals[n] <= 18) 564 | mp->atom_array[tmp_ats[n]-1].mass_difference = tmp_vals[n]-16; 565 | else if (0 == strcmp(mp->atom_array[tmp_ats[n]-1].atom_symbol, "F") && 18 <= tmp_vals[n] && tmp_vals[n] <= 19) 566 | mp->atom_array[tmp_ats[n]-1].mass_difference = tmp_vals[n]-19; 567 | else if (0 == strcmp(mp->atom_array[tmp_ats[n]-1].atom_symbol, "P") && 31 <= tmp_vals[n] && tmp_vals[n] <= 33) 568 | mp->atom_array[tmp_ats[n]-1].mass_difference = tmp_vals[n]-31; 569 | else if (0 == strcmp(mp->atom_array[tmp_ats[n]-1].atom_symbol, "S") && 32 <= tmp_vals[n] && tmp_vals[n] <= 36) 570 | mp->atom_array[tmp_ats[n]-1].mass_difference = tmp_vals[n]-32; 571 | else if (0 == strcmp(mp->atom_array[tmp_ats[n]-1].atom_symbol,"Cl") && 35 <= tmp_vals[n] && tmp_vals[n] <= 37) 572 | mp->atom_array[tmp_ats[n]-1].mass_difference = tmp_vals[n]-35; 573 | else if (0 == strcmp(mp->atom_array[tmp_ats[n]-1].atom_symbol,"Co") && 56 <= tmp_vals[n] && tmp_vals[n] <= 61) 574 | mp->atom_array[tmp_ats[n]-1].mass_difference = tmp_vals[n]-59; 575 | else if (0 == strcmp(mp->atom_array[tmp_ats[n]-1].atom_symbol,"Br") && 79 <= tmp_vals[n] && tmp_vals[n] <= 81) 576 | mp->atom_array[tmp_ats[n]-1].mass_difference = tmp_vals[n]-80; 577 | else if (0 == strcmp(mp->atom_array[tmp_ats[n]-1].atom_symbol, "Y") && 88 <= tmp_vals[n] && tmp_vals[n] <= 90) 578 | mp->atom_array[tmp_ats[n]-1].mass_difference = tmp_vals[n]-89; 579 | else if (0 == strcmp(mp->atom_array[tmp_ats[n]-1].atom_symbol, "I") && 123 <= tmp_vals[n] && tmp_vals[n] <= 131) 580 | mp->atom_array[tmp_ats[n]-1].mass_difference = tmp_vals[n]-127; 581 | } 582 | else if (STRING_BEGINS(fp->buffer,"M ALS")) /* atom type lists */ 583 | { 584 | /* Just ignore these, because they are taken care of by */ 585 | /* the atom list lines read before. */ 586 | } 587 | /* ignore short cut lines */ 588 | else if (STRING_BEGINS(fp->buffer,"M SLB") || // Sgroup Labels 589 | STRING_BEGINS(fp->buffer,"M STY") || // Sgroup Type 590 | STRING_BEGINS(fp->buffer,"M SAL") || // Sgroup Atom List 591 | STRING_BEGINS(fp->buffer,"M SBL") || // Sgroup Bond List 592 | STRING_BEGINS(fp->buffer,"M SDI") || // Sgroup Display Information, e.g. bracket positions 593 | STRING_BEGINS(fp->buffer,"M SMT") || // Sgroup Subscript text 594 | STRING_BEGINS(fp->buffer,"M SBV") || // Abbreviation SGroup bond and vector information 595 | STRING_BEGINS(fp->buffer,"M SCL") || // Abbreviation Sgroup class 596 | STRING_BEGINS(fp->buffer,"M SAP") || // Abbreviation Sgroup Attachment Point 597 | STRING_BEGINS(fp->buffer,"M SDT") || // Data Sgroup Field Description 598 | STRING_BEGINS(fp->buffer,"M SDD") || // Data Sgroup Display Information 599 | STRING_BEGINS(fp->buffer,"M SED") || // Data Sgroup Data 600 | STRING_BEGINS(fp->buffer,"M SDS")) // Sgroup Expansion 601 | { 602 | /* Just ignore those line because they are display-only. */ 603 | } 604 | else 605 | { 606 | ShowMessage("found unknown property","ReadProperties"); 607 | ShowMessageS("buffer = '%s'","ReadProperties",fp->buffer); 608 | hp = TypeAlloc(1,struct prop_line_t); 609 | strncpy(hp->text, fp->buffer, MDL_MAXLINE); 610 | hp->text[MDL_MAXLINE] = '\0'; 611 | hp->next = result; result = hp; 612 | } 613 | GetBuffer(fp); 614 | } 615 | 616 | /* restore order of list */ 617 | hhp = result; result = (struct prop_line_t *)NULL; 618 | while (hhp) 619 | { 620 | hp = hhp; hhp = hp->next; 621 | hp->next = result; result = hp; 622 | } 623 | 624 | if (fp->buffer[0] != 'M' && fp->status == FORTRAN_NORMAL) 625 | { 626 | ShowMessage("possible format error","ReadProperties"); 627 | ShowMessageS("current line: '%s'","ReadProperties",fp->buffer); 628 | } 629 | else 630 | GetBuffer(fp); 631 | return (result); 632 | } 633 | 634 | void PrintPropLines(FILE *fp, 635 | struct reaccs_molecule_t *mp, 636 | struct prop_line_t *prop_lines) 637 | /* 638 | * Prints the property lines pointed to by prop_lines to the file *fp. 639 | * Lines derived from the details of the molecule are also added. 640 | */ 641 | { 642 | int i; 643 | struct reaccs_atom_t *ap; 644 | int use_charge_radical; 645 | 646 | while (prop_lines) 647 | { 648 | fprintf(fp,"%s\n",prop_lines->text); 649 | prop_lines = prop_lines->next; 650 | } 651 | 652 | use_charge_radical = FALSE; 653 | for (i=0, ap=mp->atom_array; in_atoms; i++, ap++) 654 | { 655 | if (ap->charge > 3 || ap->charge < -3) 656 | use_charge_radical = TRUE; 657 | if (ap->radical != NONE) 658 | use_charge_radical = TRUE; 659 | } 660 | 661 | for (i=0, ap=mp->atom_array; in_atoms; i++, ap++) 662 | { 663 | if (use_charge_radical && ap->charge != 0) 664 | fprintf(fp, "M CHG 1 %3d %3d\n", i+1, ap->charge); 665 | if (ap->radical != NONE) 666 | fprintf(fp, "M RAD 1 %3d %3d\n", i+1, ap->radical); 667 | if (ap->sub_desc != NONE) 668 | fprintf(fp, "M SUB 1 %3d %3d\n", i+1, ap->sub_desc); 669 | if (ap->value != 0) 670 | fprintf(fp, "V %3d %g\n", i+1, ap->value); 671 | if (ap->atext[0] != '\0' && 0 == strcmp(ap->atom_symbol, "R")) 672 | { 673 | fprintf(fp, "A %3d\n", i+1); 674 | fprintf(fp, "%s\n", ap->atext); 675 | } 676 | } 677 | 678 | fprintf(fp,"M END\n"); 679 | } 680 | 681 | int ReadREACCSMolecule(Fortran_FILE *fp, 682 | struct reaccs_molecule_t *mp, 683 | const char *label) 684 | /* 685 | * Reads the next molecule description in Fortran_FILE *fp starting 686 | * with a line that begins with label[]. The molecule is put into *mp 687 | * which must be preallocated by the caller. 688 | * The molecule must start at the current line if label == "". 689 | */ 690 | { 691 | int nitems; 692 | int n_stexts; 693 | struct stext_line_t *stp, *stph; 694 | int i; 695 | char buffer[MAX_BUFFER+1]; 696 | int status; 697 | long regno=0; 698 | /* additional temps for V3000 format */ 699 | int n_sgroups, n_3d; 700 | char regtext[20]; 701 | 702 | if (IsNULL(mp)) 703 | { 704 | fprintf(stderr, "ReadREACCSMolecule: null molecule pointer\n"); 705 | return(FORTRAN_ERROR); 706 | } 707 | 708 | // set some safe defaults 709 | mp->name[0] = '\0'; 710 | mp->scale1 = 0; mp->scale2 = 0; mp->energy = 0; mp->registry_number = 0; 711 | mp->user_initials[0] = '\0'; 712 | strcpy(mp->program_name,"DUMMY"); 713 | mp->date[0] = '\0'; 714 | mp->time[0] = '\0'; 715 | mp->dimensionality[0]= '\0'; 716 | mp->comment[0] = '\0'; 717 | mp->n_atom_lists = 0; 718 | mp->dummy1 = 0; 719 | mp->chiral_flag = 0; 720 | n_stexts = 0; 721 | mp->stext_lines = (struct stext_line_t *)NULL; 722 | mp->n_props = 0; 723 | mp->version[0] = '\0'; 724 | mp->atom_array = (struct reaccs_atom_t *)NULL; 725 | mp->bond_array = (struct reaccs_bond_t *)NULL; 726 | 727 | if (IsNULL(fp)) 728 | { 729 | fprintf(stderr, "ReadREACCSMolecule: null file pointer\n"); 730 | return(FORTRAN_ERROR); 731 | } 732 | 733 | if (IsNULL(label)) 734 | { 735 | fprintf(stderr, "ReadREACCSMolecule: null label pointer\n"); 736 | return(FORTRAN_ERROR); 737 | } 738 | 739 | if (fp->status != FORTRAN_NORMAL) 740 | { 741 | return(fp->status); 742 | } 743 | 744 | if (0 != strcmp(label,"")) 745 | { 746 | if (!SearchString(fp,label,"$MFMT")) return (fp->status); 747 | if (STRING_BEGINS(fp->buffer,"$MFMT $MIREG")) 748 | sscanf(fp->buffer+strlen("$MFMT $MIREG"),"%ld",®no); 749 | else 750 | regno = 0; 751 | GetBuffer(fp); /* skip header line */ 752 | if (fp->status != FORTRAN_NORMAL) 753 | { 754 | fprintf(stderr, "ReadREACCSMolecule: fp->status(2) = %d\n", fp->status); 755 | return(fp->status); 756 | } 757 | } 758 | 759 | /* patch for SD-files w/o molecule records */ 760 | if (fp->buffer[0] == '>' && strchr(fp->buffer,'<')) 761 | { 762 | mp->atom_array = TypeAlloc(0, struct reaccs_atom_t); 763 | mp->bond_array = TypeAlloc(0, struct reaccs_bond_t); 764 | return(fp->status); 765 | } 766 | 767 | strncpy(mp->name,fp->buffer,MAXNAME); 768 | mp->name[MAXNAME] = '\0'; 769 | GetBuffer(fp); 770 | if (fp->status != FORTRAN_NORMAL) return(fp->status); 771 | 772 | strncpy(buffer,fp->buffer,MAX_BUFFER); 773 | BlankToZero(buffer+22); 774 | strcpy(mp->dimensionality,"2D"); 775 | mp->user_initials[0] = '\0'; mp->program_name[0] = '\0'; 776 | mp->date[0] = '\0'; mp->time[0] = '\0'; 777 | mp->scale1 = 0; mp->scale2 = 0; mp->energy = 0; mp->registry_number = 0; 778 | 779 | nitems = sscanf(buffer, 780 | "%2c%8c%6c%4c%2c%2d%10f%12f%6ld", 781 | mp->user_initials, 782 | mp->program_name, 783 | mp->date, mp->time, 784 | mp->dimensionality, 785 | &mp->scale1, &mp->scale2, 786 | &mp->energy, 787 | &mp->registry_number); 788 | if (regno != 0) mp->registry_number = regno; 789 | 790 | mp->user_initials[2] = '\0'; RemoveTrailingBlanks(mp->user_initials); 791 | mp->program_name[8] = '\0'; RemoveTrailingBlanks(mp->program_name); 792 | mp->date[6] = '\0'; RemoveTrailingBlanks(mp->date); 793 | mp->time[4] = '\0'; RemoveTrailingBlanks(mp->time); 794 | mp->dimensionality[2] = '\0'; RemoveTrailingBlanks(mp->dimensionality); 795 | 796 | GetBuffer(fp); 797 | if (fp->status != FORTRAN_NORMAL) return(fp->status); 798 | 799 | strncpy(mp->comment,fp->buffer,MDL_MAXLINE); 800 | GetBuffer(fp); 801 | if (fp->status != FORTRAN_NORMAL) return(fp->status); 802 | RemoveTrailingBlanks(mp->comment); 803 | 804 | strncpy(buffer,fp->buffer,MAX_BUFFER); 805 | mp->version[0] = '\0'; 806 | if (strlen(buffer) > 34) 807 | { 808 | strncpy(mp->version, buffer+34, 6); 809 | mp->version[5] = '\0'; 810 | // fix a common glitch 811 | if (NULL != strstr(mp->version, "V200")) strcpy(mp->version, "V2000"); 812 | } 813 | 814 | if (0 == strcmp(mp->version, "V3000")) // new MOL format 815 | { 816 | GetBuffer(fp); 817 | mp->n_atom_lists = 0; 818 | mp->dummy1 = 0; 819 | mp->chiral_flag = 0; 820 | n_stexts = 0; 821 | mp->n_props = 0; 822 | mp->n_atoms = 0; 823 | mp->n_atoms = 0; 824 | while (fp->status == FORTRAN_NORMAL && 825 | 0 != strcmp("M END", fp->buffer)) 826 | { 827 | if (0 == strncmp("M V30 BEGIN CTAB", fp->buffer, 828 | strlen("M V30 BEGIN CTAB"))) 829 | GetBuffer(fp); 830 | else if (0 == strncmp("M V30 COUNTS ", fp->buffer, 831 | strlen("M V30 COUNTS "))) 832 | { 833 | regtext[0] = '\0'; 834 | nitems = sscanf(fp->buffer + strlen("M V30 COUNTS "), 835 | "%d %d %d %d %d %s", 836 | &mp->n_atoms, &mp->n_bonds, 837 | &n_sgroups, 838 | &n_3d, 839 | &mp->chiral_flag, 840 | ®text); 841 | mp->atom_array = TypeAlloc(mp->n_atoms,struct reaccs_atom_t); 842 | mp->bond_array = TypeAlloc(mp->n_bonds,struct reaccs_bond_t); 843 | GetBuffer(fp); 844 | } 845 | else if (0 == strncmp("M V30 BEGIN ATOM", fp->buffer, 846 | strlen("M V30 BEGIN ATOM"))) 847 | { 848 | GetBuffer(fp); 849 | i=0; 850 | while (fp->status == FORTRAN_NORMAL && 851 | 0 != strcmp("M V30 END ATOM", fp->buffer)) 852 | { 853 | status = ReadV30Atom(fp,&mp->atom_array[i++], mp); 854 | if (status != FORTRAN_NORMAL) return(status); 855 | } 856 | if (fp->status == FORTRAN_NORMAL) 857 | GetBuffer(fp); // skip 'M V30 END ATOM' 858 | } 859 | else if (0 == strncmp("M V30 BEGIN BOND", fp->buffer, 860 | strlen("M V30 BEGIN BOND"))) 861 | { 862 | GetBuffer(fp); 863 | i=0; 864 | while (fp->status == FORTRAN_NORMAL && 865 | 0 != strcmp("M V30 END BOND", fp->buffer)) 866 | { 867 | status = ReadV30Bond(fp,&mp->bond_array[i++]); 868 | if (status != FORTRAN_NORMAL) return(status); 869 | } 870 | if (fp->status == FORTRAN_NORMAL) 871 | GetBuffer(fp); // skip 'M V30 END BOND' 872 | } 873 | else if (0 == strncmp("M V30 BEGIN COLLECTION", fp->buffer, 874 | strlen("M V30 BEGIN COLLECTION"))) 875 | { 876 | while (fp->status == FORTRAN_NORMAL && 877 | 0 != strcmp("M V30 END COLLECTION", fp->buffer)) 878 | { 879 | GetBuffer(fp); 880 | } 881 | if (fp->status == FORTRAN_NORMAL) 882 | GetBuffer(fp); // skip 'M V30 END COLLECTION' 883 | } 884 | else if (0 == strncmp("M V30 END CTAB", fp->buffer, 885 | strlen("M V30 END CTAB"))) 886 | GetBuffer(fp); 887 | else 888 | { 889 | GetBuffer(fp); 890 | } 891 | } 892 | if (fp->status != FORTRAN_NORMAL) return(fp->status); 893 | // parsing was in V3000 but still using old representation 894 | strcpy(mp->version, "V2000"); 895 | } 896 | else // old MOL format 897 | { 898 | BlankToZero(buffer); 899 | mp->n_atom_lists = 0; 900 | mp->dummy1 = 0; 901 | mp->chiral_flag = 0; 902 | n_stexts = 0; 903 | mp->n_props = 0; 904 | mp->n_atoms = 0; 905 | mp->n_atoms = 0; 906 | nitems = sscanf(buffer,"%3d%3d%3d%3d%3d%3d%*12c%3d", 907 | &mp->n_atoms, &mp->n_bonds, 908 | &mp->n_atom_lists, 909 | &mp->dummy1, 910 | &mp->chiral_flag, 911 | &n_stexts, 912 | &mp->n_props); 913 | if (mp->version[0] == '\0') mp->version[0] = ' '; 914 | 915 | if (nitems >= 2 && 916 | mp->n_atoms >=0 && mp->n_atoms <= MAXATOMS && 917 | mp->n_bonds >=0 && mp->n_bonds <= MAXBONDS) 918 | { 919 | GetBuffer(fp); 920 | if (fp->status != FORTRAN_NORMAL) return(fp->status); 921 | } 922 | else 923 | { 924 | ShowMessage("incorrect syntax of arguments on atom/bond number line\n", "ReadREACCSMolecule"); 925 | fprintf(stderr,"buffer = '%s'\n", fp->buffer); 926 | return(FORTRAN_ERROR); 927 | } 928 | 929 | mp->atom_array = TypeAlloc(mp->n_atoms,struct reaccs_atom_t); 930 | for (i=0; in_atoms; i++) 931 | { 932 | status = ReadREACCSAtom(fp,&mp->atom_array[i]); 933 | if (status != FORTRAN_NORMAL) return(status); 934 | } 935 | 936 | mp->bond_array = TypeAlloc(mp->n_bonds,struct reaccs_bond_t); 937 | for (i=0; in_bonds; i++) 938 | { 939 | status = ReadREACCSBond(fp,&mp->bond_array[i]); 940 | if (status != FORTRAN_NORMAL) return(status); 941 | } 942 | 943 | mp->symbol_lists = ReadSymbolLists(fp,mp->n_atom_lists); 944 | 945 | mp->stext_lines = (struct stext_line_t *)NULL; 946 | for (i=0; ibuffer,"%f %f",&stp->x, &stp->y); 950 | GetBuffer(fp); 951 | strncpy(stp->text,fp->buffer,MDL_MAXLINE); 952 | GetBuffer(fp); 953 | stp->next = mp->stext_lines; 954 | mp->stext_lines = stp; 955 | } 956 | stp = mp->stext_lines; 957 | mp->stext_lines = (struct stext_line_t *)NULL; 958 | while (stp) 959 | { 960 | stph = stp->next; 961 | stp->next = mp->stext_lines; 962 | mp->stext_lines = stp; 963 | stp = stph; 964 | } 965 | 966 | mp->prop_lines = ReadProperties(fp,mp,mp->n_props); 967 | mp->n_props = CountPropLines(mp->prop_lines); 968 | } 969 | 970 | return(FORTRAN_NORMAL); 971 | } 972 | 973 | struct data_line_t *ReadMACCSDataLines(Fortran_FILE *fp) 974 | /* 975 | * Reads data lines from FORTRAN file *fp, constructs a data list, 976 | * and returns this list. 977 | */ 978 | { 979 | struct data_line_t head; 980 | struct data_line_t *tailp; 981 | struct data_line_t *hp; 982 | 983 | head.next = (struct data_line_t *)NULL; 984 | tailp = &head; 985 | while(fp->status == FORTRAN_NORMAL && 986 | !STRING_BEGINS(fp->buffer,"$$$$")) 987 | { 988 | hp = TypeAlloc(1,struct data_line_t); 989 | strncpy(hp->data,fp->buffer,MAXDATA); 990 | hp->next = (struct data_line_t *)NULL; 991 | tailp->next = hp; 992 | tailp = hp; 993 | GetBuffer(fp); 994 | } 995 | return (head.next); 996 | } 997 | 998 | struct data_line_t *ReadREACCSDataLines(Fortran_FILE *fp) 999 | /* 1000 | * Reads data lines from FORTRAN file *fp, constructs a data list, 1001 | * and returns this list. 1002 | */ 1003 | { 1004 | struct data_line_t head; 1005 | struct data_line_t *tailp; 1006 | struct data_line_t *hp; 1007 | 1008 | head.next = (struct data_line_t *)NULL; 1009 | tailp = &head; 1010 | while(fp->status == FORTRAN_NORMAL && 1011 | (STRING_BEGINS(fp->buffer,"$DTYPE") || 1012 | STRING_BEGINS(fp->buffer,"$DATUM"))) 1013 | { 1014 | hp = TypeAlloc(1,struct data_line_t); 1015 | strncpy(hp->data,fp->buffer,MAXDATA); 1016 | hp->next = (struct data_line_t *)NULL; 1017 | tailp->next = hp; 1018 | tailp = hp; 1019 | GetBuffer(fp); 1020 | } 1021 | return (head.next); 1022 | } 1023 | 1024 | int NeededPropLines(struct reaccs_molecule_t *mp) 1025 | /* 1026 | * Computes how many property lines are needed to represent: 1027 | * the float values associated with the atoms, 1028 | * the uncommon charges, 1029 | * the radical descriptions, and 1030 | * the general property lines. 1031 | */ 1032 | { 1033 | int i, result; 1034 | struct reaccs_atom_t *ap; 1035 | int use_charge_radical; 1036 | 1037 | use_charge_radical = FALSE; 1038 | for (i=0, ap=mp->atom_array; in_atoms; i++, ap++) 1039 | { 1040 | if (ap->charge > 3 || ap->charge < -3) 1041 | use_charge_radical = TRUE; 1042 | if (ap->radical != NONE) 1043 | use_charge_radical = TRUE; 1044 | } 1045 | 1046 | for (i=result=0, ap=mp->atom_array; in_atoms; i++, ap++) 1047 | { 1048 | if (use_charge_radical && ap->charge != 0) result++; 1049 | if (ap->radical != NONE) result++; 1050 | if (ap->sub_desc != NONE) result++; 1051 | if (ap->value != 0) result++; 1052 | // atom text properties 1053 | if (ap->atom_symbol[0] == 'R' && ap->atom_symbol[1] == '\0' && ap->atext[0] != '\0') result+=2; 1054 | } 1055 | 1056 | return (result+mp->n_props); 1057 | } 1058 | 1059 | void PrintMACCSMolecule(FILE *fp, 1060 | struct reaccs_molecule_t *mp, 1061 | char *header) 1062 | { 1063 | int i; 1064 | struct stext_line_t *stp; 1065 | 1066 | if (header[0] != '\0') fprintf(fp,"%s\n",header); 1067 | 1068 | fprintf(fp,"%s\n",mp->name); 1069 | 1070 | fprintf(fp,"%-2s%-8s%-6s%-4s%-2s%2d%10.5f%12.5f%6ld\n", 1071 | mp->user_initials, 1072 | mp->program_name, 1073 | mp->date, mp->time, 1074 | mp->dimensionality, 1075 | mp->scale1, mp->scale2, 1076 | mp->energy, 1077 | mp->registry_number); 1078 | 1079 | fprintf(fp,"%s\n",mp->comment); 1080 | 1081 | fprintf(fp,"%3d%3d%3d%3d%3d%3d %3d %-6s\n", 1082 | mp->n_atoms, mp->n_bonds, 1083 | mp->n_atom_lists, 1084 | mp->dummy1, 1085 | mp->chiral_flag, 1086 | CountSTextLines(mp->stext_lines), 1087 | NeededPropLines(mp)+ 1088 | 1, /* 'M END' line */ 1089 | mp->version); 1090 | 1091 | for (i=0; in_atoms; i++) 1092 | PrintMACCSAtom(fp,&mp->atom_array[i]); 1093 | 1094 | for (i=0; in_bonds; i++) 1095 | PrintMACCSBond(fp,&mp->bond_array[i]); 1096 | 1097 | PrintSymbolLists(fp, mp->symbol_lists); 1098 | 1099 | for (stp=mp->stext_lines; stp; stp=stp->next) 1100 | { 1101 | fprintf(fp,"%10.4f%10.4f\n",stp->x,stp->y); 1102 | fprintf(fp,"%s\n",stp->text); 1103 | } 1104 | 1105 | PrintPropLines(fp, mp, mp->prop_lines); 1106 | } 1107 | 1108 | void PrintREACCSMolecule(FILE *fp, 1109 | struct reaccs_molecule_t *mp, 1110 | const char *header) 1111 | { 1112 | int i; 1113 | struct stext_line_t *stp; 1114 | 1115 | if (header[0] != '\0') fprintf(fp,"%s\n",header); 1116 | fprintf(fp,"%s\n",mp->name); 1117 | 1118 | fprintf(fp,"%-2s%-8s%-6s%-4s%-2s%2d%10.5f%12.5f%6ld\n", 1119 | mp->user_initials, 1120 | mp->program_name, 1121 | mp->date, mp->time, 1122 | mp->dimensionality, 1123 | mp->scale1, mp->scale2, 1124 | mp->energy, 1125 | mp->registry_number); 1126 | 1127 | fprintf(fp,"%s\n",mp->comment); 1128 | 1129 | fprintf(fp,"%3d%3d%3d%3d%3d%3d %3d %-6s\n", 1130 | mp->n_atoms, mp->n_bonds, 1131 | mp->n_atom_lists, 1132 | mp->dummy1, 1133 | mp->chiral_flag, 1134 | CountSTextLines(mp->stext_lines), 1135 | NeededPropLines(mp)+ 1136 | 1, /* 'M END' line */ 1137 | mp->version); 1138 | 1139 | for (i=0; in_atoms; i++) 1140 | { 1141 | PrintREACCSAtom(fp,&mp->atom_array[i]); 1142 | } 1143 | 1144 | for (i=0; in_bonds; i++) 1145 | PrintREACCSBond(fp,&mp->bond_array[i]); 1146 | 1147 | PrintSymbolLists(fp, mp->symbol_lists); 1148 | 1149 | for (stp=mp->stext_lines; stp; stp=stp->next) 1150 | { 1151 | fprintf(fp,"%10.4f%10.4f\n",stp->x,stp->y); 1152 | fprintf(fp,"%s\n",stp->text); 1153 | } 1154 | 1155 | PrintPropLines(fp, mp, mp->prop_lines); 1156 | } 1157 | 1158 | struct reaccs_reaction_t *ReadREACCSReaction(Fortran_FILE *fp) 1159 | { 1160 | int nitems; 1161 | int i; 1162 | long regno; 1163 | struct reaccs_reaction_t *rp; 1164 | struct reaccs_molecule_t *mp, *mph; 1165 | 1166 | regno = 0; 1167 | 1168 | while ((fp->status != FORTRAN_EOF) && /* search for header line */ 1169 | !STRING_BEGINS(fp->buffer,"$RXN")) 1170 | { 1171 | if (STRING_BEGINS(fp->buffer,"$RFMT $RIREG")) 1172 | sscanf(fp->buffer+strlen("$RFMT $RIREG"),"%ld",®no); 1173 | GetBuffer(fp); 1174 | } 1175 | if (fp->status != FORTRAN_NORMAL) 1176 | return((struct reaccs_reaction_t *)NULL); 1177 | 1178 | GetBuffer(fp); /* skip header line */ 1179 | if (fp->status != FORTRAN_NORMAL) 1180 | return((struct reaccs_reaction_t *)NULL); 1181 | 1182 | rp = TypeAlloc(1,struct reaccs_reaction_t); 1183 | rp->n_reactants = rp->n_products = 0; 1184 | rp->reactants = rp->products = (struct reaccs_molecule_t *)NULL; 1185 | rp->next = (struct reaccs_reaction_t *)NULL; 1186 | 1187 | strncpy(rp->name,fp->buffer,MAXNAME); 1188 | rp->name[MAXNAME] = '\0'; 1189 | GetBuffer(fp); 1190 | if (fp->status != FORTRAN_NORMAL) 1191 | { 1192 | FreeReaction(rp); 1193 | return((struct reaccs_reaction_t *)NULL); 1194 | } 1195 | 1196 | nitems = sscanf(fp->buffer, 1197 | "%4c%*2c%8c%*2c%6c%4c%*2c%6ld", 1198 | rp->user_initials, 1199 | rp->program_name, 1200 | rp->date, rp->time, 1201 | &rp->registry_number); 1202 | 1203 | /* There is a bug in the definitions of registry numbers. */ 1204 | /* Therefore we always take the one from the $RFMT line!! */ 1205 | rp->registry_number = regno; 1206 | 1207 | rp->user_initials[4] = '\0'; RemoveTrailingBlanks(rp->user_initials); 1208 | rp->program_name[8] = '\0'; RemoveTrailingBlanks(rp->program_name); 1209 | rp->date[6] = '\0'; RemoveTrailingBlanks(rp->date); 1210 | rp->time[4] = '\0'; RemoveTrailingBlanks(rp->time); 1211 | 1212 | if (nitems >= 4) 1213 | { 1214 | GetBuffer(fp); 1215 | if (fp->status != FORTRAN_NORMAL) 1216 | { 1217 | FreeReaction(rp); 1218 | return((struct reaccs_reaction_t *)NULL); 1219 | } 1220 | } 1221 | else 1222 | { 1223 | ShowMessageI("incorrect # (%d) of arguments on reaction-id line\n", 1224 | "ReadREACCSReaction(1)", 1225 | nitems); 1226 | ShowMessageS("buffer = '%s'","ReadREACCSReaction",fp->buffer); 1227 | return((struct reaccs_reaction_t *)NULL); 1228 | } 1229 | 1230 | strncpy(rp->comment,fp->buffer,MDL_MAXLINE); GetBuffer(fp); 1231 | if (fp->status != FORTRAN_NORMAL) 1232 | { 1233 | FreeReaction(rp); 1234 | return((struct reaccs_reaction_t *)NULL); 1235 | } 1236 | RemoveTrailingBlanks(rp->comment); 1237 | 1238 | nitems = sscanf(fp->buffer, 1239 | "%3d%3d", 1240 | &rp->n_reactants, &rp->n_products); 1241 | 1242 | if (nitems == 2) 1243 | { 1244 | GetBuffer(fp); 1245 | if (fp->status != FORTRAN_NORMAL) 1246 | { 1247 | FreeReaction(rp); 1248 | return((struct reaccs_reaction_t *)NULL); 1249 | } 1250 | } 1251 | else 1252 | { 1253 | ShowMessageI("incorrect # (%d) of arguments on reactant/product line\n", 1254 | "ReadREACCSReaction(2)", 1255 | nitems); 1256 | ShowMessageS("buffer = '%s'","ReadREACCSReaction",fp->buffer); 1257 | if (fp->status != FORTRAN_NORMAL) 1258 | { 1259 | FreeReaction(rp); 1260 | return((struct reaccs_reaction_t *)NULL); 1261 | } 1262 | } 1263 | 1264 | for (i=0; in_reactants; i++) 1265 | { 1266 | mp = TypeAlloc(1,struct reaccs_molecule_t); 1267 | if (IsNULL(mp)) 1268 | { 1269 | ShowMessage("not enough storage!", "ReadREACCSReaction"); 1270 | exit(1); 1271 | } 1272 | mp->next = rp->reactants; rp->reactants = mp; 1273 | if (ReadREACCSMolecule(fp,mp,"$MOL") != FORTRAN_NORMAL) 1274 | { 1275 | FreeReaction(rp); 1276 | return((struct reaccs_reaction_t *)NULL); 1277 | } 1278 | } 1279 | mp = (struct reaccs_molecule_t *)NULL; /* fix order of reactants */ 1280 | while (!IsNULL(rp->reactants)) 1281 | { 1282 | mph = rp->reactants; rp->reactants = mph->next; 1283 | mph->next = mp; mp = mph; 1284 | } 1285 | rp->reactants = mp; 1286 | 1287 | for (i=0; in_products; i++) 1288 | { 1289 | mp = TypeAlloc(1,struct reaccs_molecule_t); 1290 | if (IsNULL(mp)) 1291 | { 1292 | ShowMessage("not enough storage!", "ReadREACCSReaction"); 1293 | exit(1); 1294 | } 1295 | mp->next = rp->products; rp->products = mp; 1296 | if (ReadREACCSMolecule(fp,mp,"$MOL") != FORTRAN_NORMAL) 1297 | { 1298 | FreeReaction(rp); 1299 | return((struct reaccs_reaction_t *)NULL); 1300 | } 1301 | } 1302 | mp = (struct reaccs_molecule_t *)NULL; /* fix order of products */ 1303 | while (!IsNULL(rp->products)) 1304 | { 1305 | mph = rp->products; rp->products = mph->next; 1306 | mph->next = mp; mp = mph; 1307 | } 1308 | rp->products = mp; 1309 | 1310 | return(rp); 1311 | } 1312 | 1313 | void PrintREACCSReaction(FILE *fp, struct reaccs_reaction_t *rp) 1314 | { 1315 | struct reaccs_molecule_t *mp; 1316 | 1317 | fprintf(fp,"$RXN\n"); 1318 | fprintf(fp,"%s\n",rp->name); 1319 | 1320 | fprintf(fp,"%-4s %-8s %-6s%-4s %6ld\n", 1321 | rp->user_initials, 1322 | rp->program_name, 1323 | rp->date, rp->time, 1324 | rp->registry_number); 1325 | 1326 | fprintf(fp,"%s\n",rp->comment); 1327 | fprintf(fp,"%3d%3d\n",rp->n_reactants,rp->n_products); 1328 | 1329 | for (mp=rp->reactants; !IsNULL(mp); mp=mp->next) 1330 | PrintREACCSMolecule(fp,mp,"$MOL"); 1331 | 1332 | for (mp=rp->products; !IsNULL(mp); mp=mp->next) 1333 | PrintREACCSMolecule(fp,mp,"$MOL"); 1334 | } 1335 | 1336 | struct reaccs_molecule_t *ReadReactionAgents(Fortran_FILE *fp) 1337 | /* 1338 | * Reads the reagtion agents (solvents and catalysts) for a 1339 | * reaction entry. It returns a list of those molecules. 1340 | */ 1341 | { 1342 | struct reaccs_molecule_t *result, *mhp; 1343 | 1344 | result = (struct reaccs_molecule_t *)NULL; 1345 | 1346 | while (SearchString(fp,"$DATUM $MFMT","$RFMT")) 1347 | { 1348 | mhp = TypeAlloc(1,struct reaccs_molecule_t); 1349 | ReadREACCSMolecule(fp,mhp,"$DATUM $MFMT"); 1350 | mhp->next = result; result = mhp; 1351 | } 1352 | return (result); 1353 | } 1354 | 1355 | #define MAXLINE 300 1356 | 1357 | static char * ReadFile(FILE *fp) 1358 | /* 1359 | * Read the file into a string 1360 | * the returned string should be free()ed if not NULL 1361 | */ 1362 | { 1363 | char * Buf; 1364 | char Line[MAXLINE+1]; 1365 | int Size; 1366 | 1367 | Buf = (char *)malloc(1); 1368 | Size = 1; 1369 | if (Buf == NULL) 1370 | { 1371 | fprintf(stderr,"Error allocating memory (%d)\n", Size); 1372 | abort(); 1373 | } 1374 | 1375 | *Buf = '\0'; 1376 | 1377 | while (fgets(Line,MAXLINE,fp) != NULL) 1378 | { 1379 | Size += strlen(Line); 1380 | Buf = (char *)realloc(Buf,Size); 1381 | if (Buf == NULL) 1382 | { 1383 | fprintf(stderr,"Error allocating memory (%d)\n", Size); 1384 | abort(); 1385 | } 1386 | strcat(Buf,Line); 1387 | } 1388 | 1389 | return Buf; 1390 | } 1391 | 1392 | 1393 | 1394 | struct reaccs_molecule_t * MolStr2Mol(char * MolStr) 1395 | /* 1396 | * Convert the MolFile in MolStr to a molecule struct 1397 | * this should be deallocated with: FreeMolecule() 1398 | * returns NULL on ERROR 1399 | */ 1400 | { 1401 | Fortran_FILE *fp; 1402 | struct reaccs_molecule_t *mp; 1403 | 1404 | fp = FortranStringOpen(MolStr); 1405 | mp = TypeAlloc(1, struct reaccs_molecule_t); 1406 | if (ReadREACCSMolecule(fp, mp, "") != FORTRAN_NORMAL) 1407 | { 1408 | FreeMolecule(mp); 1409 | mp = NULL; 1410 | } 1411 | FortranClose(fp); 1412 | 1413 | return mp; 1414 | } 1415 | 1416 | #define NTMPVARS 4 1417 | static char *tmpvars[] = 1418 | { 1419 | "TMP", 1420 | "TMPDIR", 1421 | "TEMP", 1422 | "TEMPDIR" 1423 | }; 1424 | 1425 | char * MolToMolStr(struct reaccs_molecule_t * mp) 1426 | /* 1427 | * Convert a molecule struct to a char * MolFile 1428 | * the returned string should be free()ed 1429 | * In case of problems NULL will be returned and an ErrorMessage appended 1430 | * to the message list. 1431 | */ 1432 | { 1433 | FILE *fp; 1434 | const char *tempdir; 1435 | char *tempfile; 1436 | int idir; 1437 | char * MolStr; 1438 | 1439 | tempfile = NULL; 1440 | if ((fp = tmpfile()) == NULL) 1441 | { 1442 | /* Try directory found in TMPDIR environment variable */ 1443 | for (idir=0; idir log an error and return NULL */ 1463 | if (IsNULL(fp)) 1464 | { 1465 | sprintf(msg_buffer,"Error opening tmpfile() for writing"); 1466 | AddMsgToList(msg_buffer); 1467 | return NULL; 1468 | } 1469 | 1470 | PrintREACCSMolecule(fp, mp,""); 1471 | 1472 | rewind(fp); 1473 | 1474 | MolStr = ReadFile(fp); 1475 | fclose(fp); 1476 | if (!IsNULL(tempfile)) // tmpfile() did not work => remove the file after use 1477 | { 1478 | remove(tempfile); 1479 | MyFree((char *)tempfile); 1480 | } 1481 | 1482 | if (MolStr == NULL) 1483 | AddMsgToList("PrintREACCSMolecule did return NULL"); 1484 | 1485 | return MolStr; 1486 | } 1487 | 1488 | struct symbol_list_t *ParseV30SymbolList(char *symbol, 1489 | int iatom, 1490 | struct reaccs_molecule_t *mp, 1491 | struct symbol_list_t *old_list) 1492 | /* 1493 | * Parses the contents of symbol into a new symbol_list_t structure and 1494 | * prepends it to old_list. atom_symbol is set to 'L' if parsing was OK 1495 | * and to 'Unk' otherwise. 1496 | */ 1497 | { 1498 | struct symbol_list_t *list; 1499 | char* bra_from; 1500 | char* bra_to; 1501 | int len; 1502 | bra_from = strchr(symbol, '['); 1503 | bra_to = strchr(symbol, ']'); 1504 | if (bra_from == NULL || bra_to == NULL || bra_to < bra_from) 1505 | { 1506 | list = old_list; 1507 | strcpy(mp->atom_array[iatom].atom_symbol, "Unk"); 1508 | fprintf(stderr, "ParseV30SymbolList: Could not parse symbol '%s'\n", 1509 | symbol); 1510 | } 1511 | else 1512 | { 1513 | len = (bra_to-bra_from)-1; 1514 | list = TypeAlloc(1,struct symbol_list_t); 1515 | list->next = old_list; 1516 | list->atom = iatom+1; 1517 | strncpy(list->string, bra_from+1, len); 1518 | list->string[len] = '\0'; 1519 | if (0 == strncmp(symbol,"NOT",3)) list->logic = EXCLUSIVE; 1520 | else list->logic = INCLUSIVE; 1521 | strcpy(mp->atom_array[iatom].atom_symbol, "L"); 1522 | } 1523 | return list; 1524 | } 1525 | --------------------------------------------------------------------------------