diff --git a/easybuild/easyconfigs/i/IMOD/IMOD-4.12.17-foss-2022a-CUDA-11.7.0.eb b/easybuild/easyconfigs/i/IMOD/IMOD-4.12.17-foss-2022a-CUDA-11.7.0.eb index eefed7ef7b9..9c4a1782893 100644 --- a/easybuild/easyconfigs/i/IMOD/IMOD-4.12.17-foss-2022a-CUDA-11.7.0.eb +++ b/easybuild/easyconfigs/i/IMOD/IMOD-4.12.17-foss-2022a-CUDA-11.7.0.eb @@ -15,6 +15,7 @@ Kremer, Quanren Xiong, and John Heumann at the University of Colorado.""" toolchain = {'name': 'foss', 'version': '2022a'} toolchainopts = {'pic': True} # openmp leads to segfault with xftoxg tool +#cuda_compute_capabilities = ['5.0', '6.0', '7.0', '7.5', '8.0', '8.6'] # download manually from mercurial repository and create source tarball: # hg clone --debug http://bio3d.colorado.edu/imod/nightlyBuilds/IMOD @@ -27,13 +28,16 @@ sources = [SOURCE_TAR_GZ] patches = [ 'IMOD-4.11.12_hdf1.12.patch', 'IMOD-4.12.17_tiltalign_include.patch', + 'IMOD-4.12.17_rename_pip.patch', + # replace hardcoded CUDA compute capabilitites in machines/rhlinux. set as CUDACC + 'IMOD-4.12.17_cudacc.patch', ] checksums = [ - None, # can't include a valid checksum for source tarball, since it has to be created manually - # IMOD-4.11.12_hdf1.12.patch - '19e5bff97b997c600f157dd56eddae96a7f34fef528e7f40e76ea8e19144810e', - # IMOD-4.12.17_tiltalign_include.patch - '998c01a4f78b0d48dbffc530fcb12faaa892b1d322bce4f1643df20799845ab7', + {'IMOD-4.12.17.tar.gz': '63978ef981d04ab0b9d5de406dcb8ebeebd1832b75423cd00be3d190352bd820'}, + {'IMOD-4.11.12_hdf1.12.patch': '19e5bff97b997c600f157dd56eddae96a7f34fef528e7f40e76ea8e19144810e'}, + {'IMOD-4.12.17_tiltalign_include.patch': '998c01a4f78b0d48dbffc530fcb12faaa892b1d322bce4f1643df20799845ab7'}, + {'IMOD-4.12.17_rename_pip.patch': '1075b8b4023cd0738e418690fec9dea95991c6bc5b5eefa707ebfc6a56a60893'}, + {'IMOD-4.12.17_cudacc.patch': '8e84ab5137b7a51575d53d86c4177936f975a2e579ed41a6f7cc86da701c5bd9'}, ] # can't include a valid checksum, since tarball has to be created manually @@ -52,19 +56,12 @@ dependencies = [ # parallel build sometimes fails parallel = 1 -# replace hardcoded CUDA compute capabilitites in machines/rhlinux. -_cuda_replace = 'echo %(cuda_cc_space_sep)s|sed "s/\\.//g"|' -_cuda_replace += ' awk \'{' -_cuda_replace += ' printf "-arch sm_"$1; ' -_cuda_replace += ' for (i=1;i<=NF; i++){printf(" -gencode=arch=compute_%s,code=sm_%s",$i,$i) } ' -_cuda_replace += ' }\'' -_cudaarch_sed = 'sed -i "s/-arch sm_35/`' + _cuda_replace + '`/g" machines/rhlinux && ' - # modify all qmake pro files in order to pass CFLAGS _qmake_pass_cflags = "find -name *.pro -exec sed -i -e '$aQMAKE_CXXFLAGS += $$(CFLAGS)' {} \\; && " # exports required for configure and build _exports = 'export QTDIR=$EBROOTQT5 && ' +_exports += "export CUDACC='%(cuda_cc_cmake)s' && " _exports += 'export HDF5_DIR=$EBROOTHDF5 && ' _exports += 'export QMAKESPEC=$EBROOTQT5/mkspecs/`qmake -query QMAKE_SPEC` && ' _exports += 'export CUDA_DIR=$CUDA_HOME && ' @@ -74,7 +71,6 @@ _exports += 'export CUDA_DIR=$CUDA_HOME && ' _exports += 'export CFLAGS="$CFLAGS -fallow-argument-mismatch" && ' # required for gfortran10 preconfigopts = _exports -preconfigopts += _cudaarch_sed preconfigopts += _qmake_pass_cflags preconfigopts += 'sed -i "s|#!/bin/csh -f|#!/usr/bin/env tcsh|g;s|#! /bin/csh -f|#!/usr/bin/env tcsh|g" ' preconfigopts += ' %(builddir)s/IMOD/{manpages/convert,setup,setup2,machines/rhlinux,packMacApps} &&' @@ -98,15 +94,14 @@ preinstallopts += "export PYTHONPATH=%(builddir)s/IMOD/pysrc:$PYTHONPATH && " preinstallopts += "ls manpages/{csvtohtml,adocdefaults} | xargs sed -i 's@^#!.*/python -u@#!/usr/bin/env python@g' && " preinstallopts += "xargs sed -i 's@^#!.*/python -u@#!/usr/bin/env python@g' html/makeqhp && " +modextrapaths = {'PYTHONPATH': 'pylib'} + modextravars = { 'IMOD_DIR': "%(installdir)s", 'IMOD_PLUGIN_DIR': '%(installdir)s/lib/imodplug', 'IMOD_JAVADIR': '$JAVA_HOME', 'FOR_DISABLE_STACK_TRACE': '1', } - -modextrapaths = {'PYTHONPATH': 'pylib'} - modloadmsg = 'Please set the environment variable $IMOD_CALIB_DIR if appropriate.' sanity_check_paths = { 'files': ['VERSION', 'bin/subm'], diff --git a/easybuild/easyconfigs/i/IMOD/IMOD-4.12.17_cudacc.patch b/easybuild/easyconfigs/i/IMOD/IMOD-4.12.17_cudacc.patch new file mode 100644 index 00000000000..6bbc61c3d49 --- /dev/null +++ b/easybuild/easyconfigs/i/IMOD/IMOD-4.12.17_cudacc.patch @@ -0,0 +1,20 @@ +# Thomas Hoffmann, EMBL Heidelberg, structures-it@embl.de, 2023/11 +# replace hardcoded CUDA compute capabilitites in machines/rhlinux. +# Allow to be set by env $CUDACC +diff -ru IMOD/machines/rhlinux IMOD_cuda_cc/machines/rhlinux +--- IMOD/machines/rhlinux 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_cuda_cc/machines/rhlinux 2023-11-06 16:24:33.990693005 +0100 +@@ -541,9 +541,10 @@ + if ($?CUDA_DIR) then + set cudavers = `nvcc --version | sed -n -e '/[,.]/s// /g' -e '/^.*release/s///p'` + @ cudamajor = $cudavers[1] +- if ($cudamajor >= 4) set cuda_arch_opts = '-arch sm_20' +- if ($cudamajor >= 9) set cuda_arch_opts = '-arch sm_30' +- if ($cudamajor >= 11) set cuda_arch_opts = '-arch sm_35' ++ #if ($cudamajor >= 4) set cuda_arch_opts = '-arch sm_20' ++ #if ($cudamajor >= 9) set cuda_arch_opts = '-arch sm_30' ++ #if ($cudamajor >= 11) set cuda_arch_opts = '-arch sm_35' ++ set cuda_arch_opts = `echo "$CUDACC;8" | awk -F ';' '{for f "-gencode=arch=compute_%s,code=sm_%s " , $i, $i}'` + set cudalibdir = "$CUDA_DIR/lib" + if ($cudamajor > 2 && $m64bit == true) set cudalibdir = "$CUDA_DIR/lib64" + set nvcc_flags = "$cuda_arch_opts $nvcc_flags -DUNIX -Xcompiler -fno-strict-aliasing -O3" diff --git a/easybuild/easyconfigs/i/IMOD/IMOD-4.12.17_rename_pip.patch b/easybuild/easyconfigs/i/IMOD/IMOD-4.12.17_rename_pip.patch new file mode 100644 index 00000000000..166b83cf4d5 --- /dev/null +++ b/easybuild/easyconfigs/i/IMOD/IMOD-4.12.17_rename_pip.patch @@ -0,0 +1,3963 @@ +diff -ruN IMOD/pysrc/alignlog IMOD_rename_pip/pysrc/alignlog +--- IMOD/pysrc/alignlog 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/alignlog 2023-11-06 16:49:35.205638650 +0100 +@@ -68,7 +68,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + clipsize = '' + +diff -ruN IMOD/pysrc/alttomosetup IMOD_rename_pip/pysrc/alttomosetup +--- IMOD/pysrc/alttomosetup 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/alttomosetup 2023-11-06 16:49:35.205638650 +0100 +@@ -111,7 +111,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + from tomocoords import * + +diff -ruN IMOD/pysrc/archiveorig IMOD_rename_pip/pysrc/archiveorig +--- IMOD/pysrc/archiveorig 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/archiveorig 2023-11-06 16:49:35.205638650 +0100 +@@ -89,7 +89,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + options = ['r::B:Restore setname_orig.ext from setname.st and setname_xray.ext.gz', + 'd::B:Delete setname_orig.ext after computing difference', +diff -ruN IMOD/pysrc/autofidseed IMOD_rename_pip/pysrc/autofidseed +--- IMOD/pysrc/autofidseed 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/autofidseed 2023-11-06 16:49:35.206638675 +0100 +@@ -319,7 +319,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + + # Fallbacks from ../manpages/autodoc2man 3 1 autofidseed +diff -ruN IMOD/pysrc/autopatchfit IMOD_rename_pip/pysrc/autopatchfit +--- IMOD/pysrc/autopatchfit 2022-02-24 19:04:11.000000000 +0100 ++++ IMOD_rename_pip/pysrc/autopatchfit 2023-11-06 16:49:35.206638675 +0100 +@@ -33,7 +33,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + + # Fallbacks from ../manpages/autodoc2man 3 1 autopatchfit +diff -ruN IMOD/pysrc/b3dcatfiles IMOD_rename_pip/pysrc/b3dcatfiles +--- IMOD/pysrc/b3dcatfiles 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/b3dcatfiles 2023-11-06 16:49:35.206638675 +0100 +@@ -22,7 +22,7 @@ + # + # load IMOD Libraries + from imodpy import * +-from pip import exitError, setExitPrefix ++from PIP import exitError, setExitPrefix + setExitPrefix(prefix) + + numfiles = len(sys.argv) - 1 +diff -ruN IMOD/pysrc/b3dwinps IMOD_rename_pip/pysrc/b3dwinps +--- IMOD/pysrc/b3dwinps 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/b3dwinps 2023-11-06 16:49:35.207638699 +0100 +@@ -25,7 +25,7 @@ + # + # load IMOD Libraries + from imodpy import * +-from pip import exitError, setExitPrefix ++from PIP import exitError, setExitPrefix + setExitPrefix(prefix) + + cygwin = 'cygwin' in sys.platform +diff -ruN IMOD/pysrc/batchruntomo IMOD_rename_pip/pysrc/batchruntomo +--- IMOD/pysrc/batchruntomo 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/batchruntomo 2023-11-06 16:49:35.209638749 +0100 +@@ -4598,7 +4598,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + from comchanger import * + from prochunks import * +diff -ruN IMOD/pysrc/chunksetup IMOD_rename_pip/pysrc/chunksetup +--- IMOD/pysrc/chunksetup 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/chunksetup 2023-11-06 16:49:35.209638749 +0100 +@@ -23,7 +23,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + + # Initializations - defaults for filename identifiers and tomopieces call +diff -ruN IMOD/pysrc/collectmmm IMOD_rename_pip/pysrc/collectmmm +--- IMOD/pysrc/collectmmm 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/collectmmm 2023-11-06 16:49:35.209638749 +0100 +@@ -26,7 +26,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + if len(sys.argv) < 5: + prnstr(""" +diff -ruN IMOD/pysrc/colornewst IMOD_rename_pip/pysrc/colornewst +--- IMOD/pysrc/colornewst 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/colornewst 2023-11-06 16:49:35.210638773 +0100 +@@ -89,7 +89,7 @@ + + # + # load IMOD Libraries +-from pip import exitError, setExitPrefix ++from PIP import exitError, setExitPrefix + + setExitPrefix(prefix) + passOnKeyInterrupt(True) +diff -ruN IMOD/pysrc/comchanger.py IMOD_rename_pip/pysrc/comchanger.py +--- IMOD/pysrc/comchanger.py 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/comchanger.py 2023-11-06 16:49:35.210638773 +0100 +@@ -9,7 +9,7 @@ + import re + from imodpy import * + from pysed import * +-from pip import * ++from PIP import * + + # Modify a set of command lines for relevant changes in a potentially large changeList + # comlines are the lines, comRoot is the root of the com file name exclusive of axis +diff -ruN IMOD/pysrc/copyheader IMOD_rename_pip/pysrc/copyheader +--- IMOD/pysrc/copyheader 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/copyheader 2023-11-06 16:49:35.210638773 +0100 +@@ -25,7 +25,7 @@ + sys.stdout.write(prefix + " IMOD_DIR is not defined!\n") + sys.exit(1) + +-from pip import exitError, setExitPrefix ++from PIP import exitError, setExitPrefix + setExitPrefix(prefix) + + # Get file names, check existence +diff -ruN IMOD/pysrc/copytomocoms IMOD_rename_pip/pysrc/copytomocoms +--- IMOD/pysrc/copytomocoms 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/copytomocoms 2023-11-06 16:49:35.210638773 +0100 +@@ -148,7 +148,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + from comchanger import * + +diff -ruN IMOD/pysrc/cryoposition IMOD_rename_pip/pysrc/cryoposition +--- IMOD/pysrc/cryoposition 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/cryoposition 2023-11-06 16:49:35.211638798 +0100 +@@ -45,7 +45,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + + # Fallbacks from ../manpages/autodoc2man 3 1 cryoposition +diff -ruN IMOD/pysrc/ctf3dsetup IMOD_rename_pip/pysrc/ctf3dsetup +--- IMOD/pysrc/ctf3dsetup 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/ctf3dsetup 2023-11-06 16:49:35.211638798 +0100 +@@ -35,7 +35,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + from tomocoords import * + +diff -ruN IMOD/pysrc/dm2mrc IMOD_rename_pip/pysrc/dm2mrc +--- IMOD/pysrc/dm2mrc 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/dm2mrc 2023-11-06 16:49:35.211638798 +0100 +@@ -39,7 +39,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + options = ['s::B:Treat unsigned data as signed (use if < 32768)', + 'r::B:Reduce (divide by 2) unsigned 16-bit data or 32-bit integer data', +diff -ruN IMOD/pysrc/dualvolmatch IMOD_rename_pip/pysrc/dualvolmatch +--- IMOD/pysrc/dualvolmatch 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/dualvolmatch 2023-11-06 16:49:35.211638798 +0100 +@@ -36,7 +36,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + + # Fallbacks from ../manpages/autodoc2man 3 1 dualvolmatch +diff -ruN IMOD/pysrc/edgepatches IMOD_rename_pip/pysrc/edgepatches +--- IMOD/pysrc/edgepatches 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/edgepatches 2023-11-06 16:49:35.212638823 +0100 +@@ -349,7 +349,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from supermont import * + + setSMErrorPrefix(prefix) +diff -ruN IMOD/pysrc/etomo IMOD_rename_pip/pysrc/etomo +--- IMOD/pysrc/etomo 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/etomo 2023-11-06 16:49:35.212638823 +0100 +@@ -52,7 +52,7 @@ + + # + # load IMOD Libraries +-from pip import setExitPrefix ++from PIP import setExitPrefix + setExitPrefix(prefix) + setLibPath() + goodMacJavas = [('/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/', +diff -ruN IMOD/pysrc/etomoPluginDemo IMOD_rename_pip/pysrc/etomoPluginDemo +--- IMOD/pysrc/etomoPluginDemo 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/etomoPluginDemo 2023-11-06 16:49:35.212638823 +0100 +@@ -24,7 +24,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + # Fallbacks from ../manpages/autodoc2man 3 1 etomoPluginDemo + options = ["sleep:SleepTime:F:", "message:Message:CH:"] +diff -ruN IMOD/pysrc/excludeviews IMOD_rename_pip/pysrc/excludeviews +--- IMOD/pysrc/excludeviews 2022-02-24 19:04:20.000000000 +0100 ++++ IMOD_rename_pip/pysrc/excludeviews 2023-11-06 16:49:35.212638823 +0100 +@@ -184,7 +184,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + # Fallbacks from ../manpages/autodoc2man 3 1 excludeviews + options = ["stack:StackName:FN:", "views:ViewsToExclude:LI:", +diff -ruN IMOD/pysrc/expandargs IMOD_rename_pip/pysrc/expandargs +--- IMOD/pysrc/expandargs 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/expandargs 2023-11-06 16:49:35.212638823 +0100 +@@ -23,7 +23,7 @@ + + # + # load IMOD Libraries +-from pip import exitError, setExitPrefix ++from PIP import exitError, setExitPrefix + setExitPrefix(prefix) + + lenarg = len(sys.argv) +diff -ruN IMOD/pysrc/findsirtdiffs IMOD_rename_pip/pysrc/findsirtdiffs +--- IMOD/pysrc/findsirtdiffs 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/findsirtdiffs 2023-11-06 16:49:35.212638823 +0100 +@@ -26,7 +26,7 @@ + + # + # load IMOD Libraries +-from pip import exitError, setExitPrefix ++from PIP import exitError, setExitPrefix + + setExitPrefix(prefix) + if len(sys.argv) < 2: +diff -ruN IMOD/pysrc/finishjoin IMOD_rename_pip/pysrc/finishjoin +--- IMOD/pysrc/finishjoin 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/finishjoin 2023-11-06 16:49:35.213638848 +0100 +@@ -35,7 +35,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + # Initializations + newmode = '' +diff -ruN IMOD/pysrc/fitpatches IMOD_rename_pip/pysrc/fitpatches +--- IMOD/pysrc/fitpatches 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/fitpatches 2023-11-06 16:49:35.213638848 +0100 +@@ -28,7 +28,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from supermont import * + + setSMErrorPrefix(prefix) +diff -ruN IMOD/pysrc/fixgradtable IMOD_rename_pip/pysrc/fixgradtable +--- IMOD/pysrc/fixgradtable 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/fixgradtable 2023-11-06 16:49:35.213638848 +0100 +@@ -22,7 +22,7 @@ + # + # load IMOD Libraries + from imodpy import * +-from pip import exitError, setExitPrefix ++from PIP import exitError, setExitPrefix + setExitPrefix(prefix) + + if len(sys.argv) < 4: +diff -ruN IMOD/pysrc/framewatcher IMOD_rename_pip/pysrc/framewatcher +--- IMOD/pysrc/framewatcher 2022-02-24 19:04:38.000000000 +0100 ++++ IMOD_rename_pip/pysrc/framewatcher 2023-11-06 16:49:35.213638848 +0100 +@@ -423,7 +423,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + + keyVals = ['outputDir', 'processedDir', 'reducedDir', 'gainReference', +diff -ruN IMOD/pysrc/gpuallocator IMOD_rename_pip/pysrc/gpuallocator +--- IMOD/pysrc/gpuallocator 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/gpuallocator 2023-11-06 16:49:35.213638848 +0100 +@@ -33,7 +33,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + isWindows = 'win32' in sys.platform + if isWindows: +diff -ruN IMOD/pysrc/gpumonitor IMOD_rename_pip/pysrc/gpumonitor +--- IMOD/pysrc/gpumonitor 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/gpumonitor 2023-11-06 16:49:35.213638848 +0100 +@@ -125,7 +125,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + # Initializations + +diff -ruN IMOD/pysrc/gputilttest IMOD_rename_pip/pysrc/gputilttest +--- IMOD/pysrc/gputilttest 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/gputilttest 2023-11-06 16:49:35.214638872 +0100 +@@ -223,7 +223,7 @@ + + # + # load IMOD Libraries +-from pip import exitError, setExitPrefix ++from PIP import exitError, setExitPrefix + + gpunum = 0 + minutes = 1. +diff -ruN IMOD/pysrc/imodhelp IMOD_rename_pip/pysrc/imodhelp +--- IMOD/pysrc/imodhelp 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/imodhelp 2023-11-06 16:49:35.215638897 +0100 +@@ -54,7 +54,7 @@ + + # + # load IMOD Libraries +-from pip import exitError, setExitPrefix ++from PIP import exitError, setExitPrefix + + setExitPrefix(prefix) + +diff -ruN IMOD/pysrc/imodkillgroup IMOD_rename_pip/pysrc/imodkillgroup +--- IMOD/pysrc/imodkillgroup 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/imodkillgroup 2023-11-06 16:49:35.215638897 +0100 +@@ -97,7 +97,7 @@ + + # + # load IMOD Libraries +-from pip import exitError, setExitPrefix ++from PIP import exitError, setExitPrefix + setExitPrefix(prefix) + #setRetryLimit(10, 3.) + +diff -ruN IMOD/pysrc/imodpy.py IMOD_rename_pip/pysrc/imodpy.py +--- IMOD/pysrc/imodpy.py 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/imodpy.py 2023-11-06 16:49:35.216638922 +0100 +@@ -110,7 +110,7 @@ + + # other modules needed by imodpy + import sys, os, re, time, glob, signal, stat, shlex, copy, shutil +-from pip import exitError, PipGetInteger ++from PIP import exitError, PipGetInteger + + pyVersion = 100 * sys.version_info[0] + 10 * sys.version_info[1] + +diff -ruN IMOD/pysrc/justblend IMOD_rename_pip/pysrc/justblend +--- IMOD/pysrc/justblend 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/justblend 2023-11-06 16:49:35.216638922 +0100 +@@ -102,7 +102,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + from comchanger import * + from prochunks import * +diff -ruN IMOD/pysrc/makecomfile IMOD_rename_pip/pysrc/makecomfile +--- IMOD/pysrc/makecomfile 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/makecomfile 2023-11-06 16:49:35.216638922 +0100 +@@ -28,7 +28,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + from comchanger import * + +diff -ruN IMOD/pysrc/Makefile IMOD_rename_pip/pysrc/Makefile +--- IMOD/pysrc/Makefile 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/Makefile 2023-11-06 17:35:23.080376774 +0100 +@@ -19,7 +19,7 @@ + b3dtomosetexts \ + $(BACKGROUND_SCRIPTS) + +-MODULES = imodpy.py pysed.py supermont.py pip.py comchanger.py tomocoords.py \ ++MODULES = imodpy.py pysed.py supermont.py PIP.py comchanger.py tomocoords.py \ + tiltmatch.py prochunks.py + + all: +diff -ruN IMOD/pysrc/makejoincom IMOD_rename_pip/pysrc/makejoincom +--- IMOD/pysrc/makejoincom 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/makejoincom 2023-11-06 16:49:35.216638922 +0100 +@@ -64,7 +64,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + # Fallbacks from ../manpages/autodoc2man 3 1 makejoincom + options = ["root:RootName:CH:", "input:InputTomogram:FNM:", "top:TopSlices:IPL:", +diff -ruN IMOD/pysrc/makepyramid IMOD_rename_pip/pysrc/makepyramid +--- IMOD/pysrc/makepyramid 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/makepyramid 2023-11-06 16:49:35.217638947 +0100 +@@ -27,7 +27,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + # Fallbacks from ../manpages/autodoc2man 3 1 makepyramid + options = ["input:InputFile:FN:", "rootname:RootOutputName:CH:", +diff -ruN IMOD/pysrc/matchorwarp IMOD_rename_pip/pysrc/matchorwarp +--- IMOD/pysrc/matchorwarp 2022-02-24 19:04:11.000000000 +0100 ++++ IMOD_rename_pip/pysrc/matchorwarp 2023-11-06 16:49:35.217638947 +0100 +@@ -28,7 +28,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + clipsize = '' + +diff -ruN IMOD/pysrc/matchrotpairs IMOD_rename_pip/pysrc/matchrotpairs +--- IMOD/pysrc/matchrotpairs 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/matchrotpairs 2023-11-06 16:49:35.217638947 +0100 +@@ -35,7 +35,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + from tiltmatch import * + +diff -ruN IMOD/pysrc/multifiltsetup IMOD_rename_pip/pysrc/multifiltsetup +--- IMOD/pysrc/multifiltsetup 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/multifiltsetup 2023-11-06 16:49:35.217638947 +0100 +@@ -26,7 +26,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + + # Fallbacks from ../manpages/autodoc2man 3 1 multifiltsetup +diff -ruN IMOD/pysrc/onegenplot IMOD_rename_pip/pysrc/onegenplot +--- IMOD/pysrc/onegenplot 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/onegenplot 2023-11-06 16:49:35.217638947 +0100 +@@ -34,7 +34,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + defSymbols = [9, 7, 5, 8, 13, 14, 1, 11, 3, 10, 6, 2, 12, 4] + stockColors = {'aqua' : (0, 255, 255), +diff -ruN IMOD/pysrc/pip.py IMOD_rename_pip/pysrc/pip.py +--- IMOD/pysrc/pip.py 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/pip.py 1970-01-01 01:00:00.000000000 +0100 +@@ -1,1545 +0,0 @@ +-#!/usr/bin/python +-# +-# Parse Input Params module, translated from C +-# +-# Author: David Mastronarde +-# +-# $Id$ +-# +-# The approach in translating was to retain most of the flags and capabilities +-# in the C code, even when the calls for setting the flags were not included: +-# i.e., the special flags, help output level and type. However, manpage output +-# is not provided for as that was not needed. Default value entries for +-# general arrays was also not included as this would have involved changing the +-# calls for getting arrays defined in the previous extension module. The code +-# order is the same as in parse_params.c. Obvious simplifications were made +-# but much of the string processing logic was retained as the safest and +-# easiest approach - so some of this will seem rather un-Python like. +-# All global variables are declared in the functions that use them, although +-# only the ones being assigned to need to be declared. +- +-import re, sys, os, glob +- +-# The global defines, tables and variables +-NON_OPTION_STRING = "NonOptionArgument" +-STANDARD_INPUT_STRING = "StandardInput" +-STANDARD_INPUT_END = "EndInput" +-LOOKUP_NOT_FOUND = -1 +-LOOKUP_AMBIGUOUS = -2 +-OPTFILE_DIR = "autodoc" +-OPTFILE_EXT = "adoc" +-OPTDIR_VARIABLE = "AUTODOC_DIR" +-DEFAULTS_FILE = "progDefaults.adoc" +-DEFAULTS_DIR = "com" +-DEFAULT_SUB_STR = "%{default}" +-PRINTENTRY_VARIABLE = "PIP_PRINT_ENTRIES" +-OPEN_DELIM = "[" +-CLOSE_DELIM = "]" +-VALUE_DELIM = "=" +-PATH_SEPARATOR = os.sep +-PIP_INTEGER = 1 +-PIP_FLOAT = 2 +- +-sTypes = ("B","PF","LI","I", "F", "IP", "FP", "IT", "FT", "IA", "FA", "CH","FN") +-sTypeForUsage = ("Boolean", "File", "List", "Int", "Float", "2 ints", \ +- "2 floats", "3 ints", "3 floats", "Ints", "Floats", "String", "File", \ +- "Unknown argument type") +-sNumTypes = 13 +-tokenSep = re.compile("[= \t]") +-nonWhite = re.compile('[^ \t]') +-valueSep = re.compile('[ ,\t/]') +-pipErrno = 0 +-sQuoteTypes = """'"`""" +- +- +-# The options "structure"; initialize all the values +-class pipOption: +- def __init__(self): +- self.shortName = '' +- self.longName = '' +- self.type = '' +- self.helpString = '' +- self.format = '' +- self.defaultVal = '' +- self.values = [] +- self.multiple = 0 +- self.count = 0 +- self.lenShort = 0 +- self.nextLinked = [] +- self.linked = False +-sOptTable = None +-sTableSize = 0 +-sNumOptions = 0 +-sNonOptInd = 0 +-sErrorString = None +-sExitPrefix = None +-sProgramName = "" +-sErrorDest = 0 +-sNextOption = 0 +-sNextArgBelongsTo = -1 +-sNumOptionArguments = 0 +-sAllowDefaults = 0 +-sOutputManpage = 0 +-sPrintEntries = -1 +-sDefaultDelim = VALUE_DELIM +-sValueDelim = sDefaultDelim +-sNoCase = 0 +-sDoneEnds = 0 +-sTakeStdIn = 0 +-sNonOptLines = 0 +-sNoAbbrevs = 0 +-sNotFoundOK = False +-sLinkedOption = None +-sTestAbbrevForUsage = False +-sForbidCommentLong = '' +-sForbidCommentShort = '' +-sWarnOnComment = False +- +-# Initialize for given number of options +-# +-def PipInitialize(numOpts): +- global sNumOptions, sTableSize, sNonOptInd, sOptTable +- sNumOptions = numOpts +- sTableSize = numOpts + 2 +- sNonOptInd = sNumOptions +- sOptTable = [] +- +- # Initialize the table +- for i in range(sTableSize): +- inst = pipOption() +- sOptTable.append(inst) +- +- # In the last slots, put non-option arguments, and also put the +- # name for the standard input option for easy checking on duplication +- sOptTable[sNonOptInd].longName = NON_OPTION_STRING +- sOptTable[sNonOptInd + 1].shortName = STANDARD_INPUT_STRING +- sOptTable[sNonOptInd + 1].longName = STANDARD_INPUT_END +- sOptTable[sNonOptInd].multiple = 1 +- return 0 +- +- +-# Free all allocated memory and set state back to initial state (sort of) +-# +-def PipDone(): +- global sNumOptions, sTableSize, sNonOptInd, sOptTable, sErrorString, sNextOption +- global sNextArgBelongsTo, sNumOptionArguments, sAllowDefaults +- del sOptTable +- sOptTable = None +- sTableSize = 0 +- sNumOptions = 0 +- sErrorString = None +- sNextOption = 0 +- sNextArgBelongsTo = -1 +- sNumOptionArguments = 0 +- sAllowDefaults = 0 +- sLinkedOption = None +- +- +-# Set up for Pip to handle exiting on error, with a prefix string +-# +-def PipExitOnError(useStdErr, prefix): +- global sErrorDest, sExitPrefix +- sErrorDest = useStdErr +- sExitPrefix = prefix +- return 0 +- +- +-# Just set the exit prefix +-# +-def setExitPrefix(prefix): +- global sExitPrefix +- sExitPrefix = prefix +- +-# Enable the entry ouput +-# +-def PipEnableEntryOutput(val): +- global sPrintEntries +- sPrintEntries = val +- +-# Set a linked option +-# +-def PipSetLinkedOption(option): +- global sLinkedOption +- sLinkedOption = option +- +-# Set up one option for which in-line comments are not allowed +-# +-def PipForbidComments(longName, shortName, warn): +- global sForbidCommentShort, sForbidCommentLong, sWarnOnComment +- sForbidCommentShort = shortName +- sForbidCommentLong = longName +- sWarnOnComment = warn +- +-# Return the error number +-# +-def PipGetErrNo(): +- global pipErrno +- return pipErrno +- +- +-# Expand a set of arguments in the input list on Windows; pass through any argument +-# without a wild card, try to match the rest, and pass one through if there is no match +-# but return index of first non-matched item +-def expandArgList(args): +- if not ('win32' in sys.platform or 'cygwin' in sys.platform): +- return (args, -1) +- newList = [] +- noMatchInd = -1 +- for ind, arg in enumerate(args): +- if '*' not in arg and '?' not in arg: +- newList.append(arg) +- else: +- expanded = glob.glob(arg) +- if expanded: +- expanded.sort() +- newList += expanded +- else: +- newList.append(arg) +- if noMatchInd < 0: +- noMatchInd = ind +- +- return (newList, noMatchInd) +- +- +-# Add an option, with short and long name, type, and help string +-# +-def PipAddOption(optionString): +- global sNextOption, sNumOptions, sOptTable, sTableSize, sNonOptInd +- +- if (sNextOption >= sNumOptions): +- PipSetError("Attempting to add more options than were originally" +- " specified") +- return -1 +- +- parts = optionString.split(':', 3) +- if len(parts) < 4: +- PipSetError("Option does not have three colons in it: " + optionString) +- return -1 +- +- sOptTable[sNextOption].shortName = parts[0] +- newSlen = len(parts[0]) +- sOptTable[sNextOption].lenShort = newSlen +- sOptTable[sNextOption].longName = parts[1] +- +- # If type ends in M or L, set multiple flag and strip M or L +- if parts[2].endswith('M') or parts[2].endswith('L'): +- sOptTable[sNextOption].multiple = 1 +- sOptTable[sNextOption].linked = parts[2].endswith('L') +- if len(parts[2]) > 1: +- parts[2] = parts[2][0:len(parts[2]) - 1] +- else: +- parts[2] = '' +- +- sOptTable[sNextOption].type = parts[2] +- sOptTable[sNextOption].helpString = parts[3] +- +- for ind in range(sTableSize): +- # after checking existing ones, skip to NonOptionArg and +- # StandardInput entries +- if (ind >= sNextOption and ind < sNonOptInd): +- continue +- +- oldShort = sOptTable[ind].shortName +- oldLong = sOptTable[ind].longName +- oldSlen = sOptTable[ind].lenShort +- if (((PipStartsWith(parts[0], oldShort) or PipStartsWith(oldShort, parts[0])) and +- ((newSlen > 1 and oldSlen > 1) or (newSlen == 1 and oldSlen == 1))) or \ +- PipStartsWith(oldLong, parts[0]) or PipStartsWith(parts[0], oldLong) or \ +- PipStartsWith(oldShort, parts[1]) or PipStartsWith(parts[1], oldShort) or \ +- PipStartsWith(oldLong, parts[1]) or PipStartsWith(parts[1], oldLong)): +- sTempStr = "Option " + parts[0] + " " + parts[1] + \ +- " is ambiguous with option " + oldShort + " " + oldLong +- PipSetError(sTempStr) +- sys.stdout.write(sTempStr + "\n") +- return -1 +- +- sNextOption += 1 +- return 0 +- +- +-# Call this to process the next argument +-def PipNextArg(argString): +- global sNextArgBelongsTo, sOptTable, STANDARD_INPUT_STRING +- global sNumOptionArguments, sNonOptInd, sNextOption, sNotFoundOK +- +- # If we are expecting a value for an option, add string to the option +- if (sNextArgBelongsTo >= 0): +- err = AddValueString(sNextArgBelongsTo, argString) +- +- # Check whether this option was for reading from parameter file +- if (not err and sOptTable[sNextArgBelongsTo].type == 'PF'): +- try: +- paramFile = open(argString, "r") +- except: +- sTempStr = "Error opening parameter file " + argString +- PipSetError(sTempStr) +- return -1 +- +- err = ReadParamFile(paramFile) +- try: +- close(paramFile) +- except: +- pass +- sNextArgBelongsTo = -1 +- return err +- +- # Is it a legal option starting with - or -- ? +- if (argString.strip()[0] == '-'): +- argString = argString.strip() +- indStart = 1 +- if (len(argString) > 1 and argString[1] == '-'): +- indStart = 2 +- if (len(argString) == indStart): +- PipSetError("Illegal argument: - or --") +- return -1 +- +- # First check for StandardInput +- if (STANDARD_INPUT_STRING.startswith(argString[indStart:])): +- err = ReadParamFile(sys.stdin) +- return err +- +- # Next check if it is a potential numeric non-option arg +- sNotFoundOK = 1 +- for ch in argString[indStart:]: +- if ch != '-' and ch != ',' and ch != '.' and ch != ' ' and not ch.isdigit(): +- sNotFoundOK = 0 +- break +- +- # Lookup the option among true defined options +- err = LookupOption(argString[indStart:], sNextOption) +- +- # Process as an option unless it could be numeric and was not found +- if not (sNotFoundOK and err == LOOKUP_NOT_FOUND): +- sNotFoundOK = 0 +- if err < 0: +- return err +- +- sNumOptionArguments += 1 +- +- # For an option with value, setup to get argument next time and +- # return an indicator that there had better be another +- if (sOptTable[err].type != 'B'): +- sNextArgBelongsTo = err +- return 1 +- else: +- +- # for a boolean option, set the argument with a 1 +- return AddValueString(err, '1') +- +- # A non-option argument +- sNotFoundOK = 0 +- (expanded, noMatchInd) = expandArgList([argString]) +- for arg in expanded: +- err = AddValueString(sNonOptInd, arg) +- if err == None: +- return None +- return 0 +- +- +-# return number of option arguments (approximate) and number of non-option +-# arguments +-# +-def PipNumberOfArgs(): +- global sOptTable, sNumOptionArguments, pipErrno +- pipErrno = 0 +- return (sNumOptionArguments, sOptTable[sNonOptInd].count) +- +-# Get a non-option argument, index numbered from 0 here +-# +-def PipGetNonOptionArg(argNo): +- global sOptTable, pipErrno +- pipErrno = 0 +- if (argNo >= sOptTable[sNonOptInd].count): +- PipSetError("Requested a non-option argument beyond the number" + \ +- " available") +- pipErrno = -1 +- return None +- return sOptTable[sNonOptInd].values[argNo] +- +- +-# Get a string option +-# +-def PipGetString(option, string): +- global pipErrno +- pipErrno = 0 +- retval = GetNextValueString(option) +- if pipErrno < 0: +- return None +- if pipErrno == 1: +- return string +- return retval +- +- +-# Get a boolean (binary) option; make sure it has a legal specification +-# +-def PipGetBoolean(option, val): +- global pipErrno +- pipErrno = 0 +- strPtr = GetNextValueString(option) +- if pipErrno < 0: +- return None +- if pipErrno > 0: +- return val +- if (strPtr == "1" or strPtr == "T" or strPtr == "TRUE" or strPtr == "ON" \ +- or strPtr == "t" or strPtr == "true" or strPtr == "on"): +- return 1 +- elif (strPtr == "0" or strPtr == "F" or strPtr == "FALSE" or \ +- strPtr == "OFF" or strPtr == "f" or strPtr == "false" or \ +- strPtr == "off"): +- return 0 +- else: +- sTempStr = "Illegal entry for boolean option " + option + ": " + strPtr +- PipSetError(sTempStr) +- pipErrno = -1 +- return None +- +- +-# Get single integer and float just call to get an array with one element +-# +-def PipGetInteger(option, val): +- global pipErrno +- num = 1 +- retval = PipGetIntegerArray(option, num) +- if (pipErrno < 0): +- return None +- if (pipErrno == 1): +- return val +- return retval[0] +- +-def PipGetFloat(option, val): +- global pipErrno +- num = 1 +- retval = PipGetFloatArray(option, num) +- if (pipErrno < 0): +- return None +- if (pipErrno == 1): +- return val +- return retval[0] +- +- +-# Get two integers or floats - move into array, get array with two elements +-# +-def PipGetTwoIntegers(option, val1, val2): +- global pipErrno +- num = 2 +- retval = PipGetIntegerArray(option, num) +- if (pipErrno < 0): +- return None +- if (pipErrno == 1): +- return (val1, val2) +- return (retval[0], retval[1]) +- +-def PipGetTwoFloats(option, val1, val2): +- global pipErrno +- num = 2 +- retval = PipGetFloatArray(option, num) +- if (pipErrno < 0): +- return None +- if (pipErrno == 1): +- return (val1, val2) +- return (retval[0], retval[1]) +- +- +-# Get three integers or floats - move into array, get array with two elements +-# +-def PipGetThreeIntegers(option, val1, val2, val3): +- global pipErrno +- num = 3 +- retval = PipGetIntegerArray(option, num) +- if (pipErrno < 0): +- return None +- if (pipErrno == 1): +- return (val1, val2, val3) +- return (retval[0], retval[1], retval[2]) +- +-def PipGetThreeFloats(option, val1, val2, val3): +- global pipErrno +- num = 3 +- retval = PipGetFloatArray(option, num) +- if (pipErrno < 0): +- return None +- if (pipErrno == 1): +- return (val1, val2, val3) +- return (retval[0], retval[1], retval[2]) +- +- +-# Getting an array of integers or floats calls the general routine for +-# getting a line of values +-# +-def PipGetIntegerArray(option, numToGet): +- global PIP_INTEGER +- return OptionLineOfValues(option, PIP_INTEGER, numToGet) +- +-def PipGetFloatArray(option, numToGet): +- global PIP_FLOAT +- return OptionLineOfValues(option, PIP_FLOAT, numToGet) +- +- +-# Print a complete usage statement only +-# +-def PipPrintHelp(progName, useStdErr, inputFiles, outputFiles): +- global sNumOptions, sOptTable, sOutputManpage, sTypeForUsage, sTypes, sNumTypes +- global sTestAbbrevForUsage +- numOut = 0 +- numReal = 0 +- helplim = 74 +- out = sys.stdout +- if useStdErr: +- out = sys.stderr +- indent4 = " " +- linePos = 11 +-# descriptions = sTypeDescriptions +- +- for i in range(sNumOptions): +- if (len(sOptTable[i].shortName) or len(sOptTable[i].longName)): +- numReal += 1 +- +- if (not sOutputManpage): +- out.write("Usage: " + progName + " ") +- if (sNumOptions): +- out.write("[Options]") +- if (inputFiles): +- out.write(" input_file") +- if (inputFiles > 1): +- out.write("s...") +- if (outputFiles): +- out.write(" output_file") +- if (outputFiles > 1): +- out.write("s...") +- out.write("\n") +- +- if (not numReal): +- return 0 +- out.write("Options can be abbreviated, current short name abbreviations are in " +\ +- "parentheses\n") +- out.write("Options:\n") +- descriptions = sTypeForUsage +- +- sTestAbbrevForUsage = True +- for i in range(sNumOptions): +- +- sname = sOptTable[i].shortName +- lname = sOptTable[i].longName +- indentStr = "" +- +- # Try to look up an abbreviation of the short name +- abbrev = None +- if len(sname): +- for j in range(1, len(sname)): +- if LookupOption(sname[:j], sNumOptions) == i: +- abbrev = sname[:j] +- break +- +- if (len(lname) or len(sname)): +- if (sOutputManpage <= 0): +- indentStr = indent4 +- +- out.write(" ") +- if len(sname): +- out.write("-" + sname) +- if abbrev: +- out.write(" (-" + abbrev + ")") +- if len(sname) and len(lname): +- out.write(" OR ") +- if len(lname): +- out.write("-" + lname) +- for j in range(sNumTypes): +- jj = j +- if (sOptTable[i].type == sTypes[j]): +- break +- +- if (sOptTable[i].type != "B"): +- format = descriptions[jj] +- if sOptTable[i].format: +- format = sOptTable[i].format.replace("\\fR", '').replace("\\fI", '').\ +- replace("\\fB", '') +- out.write(" " + format) +- +- out.write("\n") +- +- # Print help string, breaking up line as needed +- if len(sOptTable[i].helpString): +- sname = sOptTable[i].helpString +- if sOptTable[i].defaultVal: +- sname = sname.replace(DEFAULT_SUB_STR, sOptTable[i].defaultVal); +- optLen = len(sname) +- newLinePt = sname.find('\n') +- while (optLen > helplim or newLinePt >= 0): +- +- # Break string at newline +- # Or break string at last space before limit +- if (newLinePt >= 0 and newLinePt <= helplim): +- j = newLinePt +- else: +- j = sname.rfind(' ', 1, helplim) +- if (j < 0): +- j = 0 +- +- out.write(indentStr + sname[0:j] + "\n") +- sname = sname[j+1:] +- newLinePt = sname.find('\n') +- optLen -= j + 1 +- +- out.write(indentStr + sname + "\n") +- +- if (sOptTable[i].multiple): +- out.write(indentStr + "(Successive entries accumulate)\n") +- +- sTestAbbrevForUsage = False +- return 0 +- +- +-# Print the entries +-def PipPrintEntries(): +- global sNumOptions, sOptTable, sPrintEntries +- if sPrintEntries < 0: +- sPrintEntries = 0 +- val = os.getenv(PRINTENTRY_VARIABLE) +- if val != None: +- try: +- sPrintEntries = int(val) +- except: +- sPrintEntries = 0 +- if not sPrintEntries: +- return +- sys.stdout.write("\n*** Entries to program " + sProgramName + " ***" + "\n") +- for i in range(sNumOptions): +- sname = sOptTable[i].shortName +- lname = sOptTable[i].longName +- if (len(lname) or len(sname)) and sOptTable[i].count: +- name = lname +- if not len(lname): +- name = sname +- for j in range(sOptTable[i].count): +- sys.stdout.write(" " + name + " = " + sOptTable[i].values[j] + \ +- "\n") +- if sOptTable[sNonOptInd].count: +- sys.stdout.write(" Non-option arguments:") +- for j in range(sOptTable[sNonOptInd].count): +- if ' ' in sOptTable[sNonOptInd].values[j]: +- sys.stdout.write(' "' + sOptTable[sNonOptInd].values[j] + '"') +- else: +- sys.stdout.write(" " + sOptTable[sNonOptInd].values[j]) +- sys.stdout.write('\n') +- sys.stdout.write("*** End of entries ***\n\n") +- +- +-# Return the error string, or an empty string and an error if there is none +-# +-def PipGetError(): +- global sErrorString, pipErrno +- pipErrno = 0 +- if (not sErrorString): +- pipErrno = -1 +- return '' +- return sErrorString +- +- +-# Set the error string. +-# If sExitPrefix is set, then output an error message to stderr or stdout +-# and exit. +-def PipSetError(errString): +- global sErrorString, sExitPrefix +- outFile = sys.stdout +- if sErrorDest: +- outFile = stderr +- sErrorString = errString +- if not sErrorString and not sExitPrefix: +- pipErrno = -1 +- return None +- +- if sExitPrefix: +- if not sErrorString: +- sErrorString = "Unspecified error" +- outFile.write(sExitPrefix + sErrorString + "\n") +- sys.exit(1) +- +- return 0 +- +- +-# Simple function to call with error string to append to prefix and exit +-# +-def exitError(errorMess): +- PipSetError(errorMess) +- sys.exit(1) +- +- +-# Return the number of entries for a particular option +-# +-def PipNumberOfEntries(option): +- global sNonOptInd, pipErrno +- pipErrno = 0 +- err = LookupOption(option, sNonOptInd + 1) +- if (err < 0): +- pipErrno = err +- return None +- +- return sOptTable[err].count +- +- +-# Return the index of the next non-option arg or linked option that was entered after +-# this option +-# +-def PipLinkedIndex(option): +- global sNumOptions, sLinkedOption, pipErrno, sNonOptInd +- pipErrno = 0 +- err = LookupOption(option, sNumOptions) +- if (err < 0): +- pipErrno = err +- return None +- +- ind = 0 +- if sOptTable[err].multiple: +- ind = sOptTable[err].multiple - 1 +- +- # Set up to use count from non-option args, but use the count from the linked option +- # instead if it was entered at all. This allows other non-option args to be used +- which = 0 +- if sLinkedOption != None: +- ilink = LookupOption(sLinkedOption, sNumOptions) +- if (ilink < 0): +- pipErrno = ilink +- return None +- if sOptTable[ilink].count: +- which = 1 +- return sOptTable[err].nextLinked[2 * ind + which] +- +- +-# Top level routine to be called to process options and arguments +-# +-def PipParseInput(argv, options): +- +- # Initialize +- numOpts = len(options) +- err = PipInitialize(numOpts) +- if err: +- pipErrno = err +- return None +- +- # add the options +- for i in range(numOpts): +- err = PipAddOption(options[i]) +- if err: +- pipErrno = err +- return None +- +- return (PipParseEntries(argv)) +- +- +-# Try to open an autodoc at AUTODOC_DIR or IMOD_DIR/autodoc +-# +-def PipOpenInstalledAdoc(progName): +- global OPTDIR_VARIABLE, PATH_SEPARATOR, OPTFILE_DIR, OPTFILE_EXT +- optFile = None +- pipDir = os.getenv(OPTDIR_VARIABLE) +- if (pipDir): +- bigStr = pipDir + PATH_SEPARATOR + progName + "." + OPTFILE_EXT +- try: +- # print "Looking for file " + bigStr +- optFile = open(bigStr, "r") +- except IOError: +- optFile = None +- +- if (not optFile): +- pipDir = os.getenv("IMOD_DIR") +- if (pipDir): +- bigStr = pipDir + PATH_SEPARATOR + OPTFILE_DIR +\ +- PATH_SEPARATOR + progName + "." + OPTFILE_EXT +- try: +- #print "Looking for file " + bigStr +- optFile = open(bigStr, "r") +- except IOError: +- optFile = None +- +- return optFile +- +- +-# Alternative routine to have options read from a file +-# +-def PipReadOptionFile(progName, helpLevel, localDir): +- global PATH_SEPARATOR, OPTFILE_DIR, OPTFILE_EXT +- global sOptTable, sValueDelim, sProgramName +- optFile = None +- sProgramName = progName +- +- # If local directory not set, look for environment variable pointing +- # directly to where the file should be +- if (not localDir): +- optFile = PipOpenInstalledAdoc(progName) +- +- # If local directory set, set up name with ../ as many times as specified +- # and look for file there +- elif (localDir > 0): +- bigStr = "" +- for i in range(localDir): +- bigStr += ".." + PATH_SEPARATOR +- +- bigStr += OPTFILE_DIR + PATH_SEPARATOR + progName + "." + OPTFILE_EXT +- try: +- # print "Looking for file " + bigStr +- optFile = open(bigStr, "r") +- except IOError: +- optFile = None +- +- +- # If there is still no file, look in current directory +- if (not optFile): +- bigStr = progName + "." + OPTFILE_EXT +- try: +- # print "Looking for file " + bigStr +- optFile = open(bigStr, "r") +- except IOError: +- optFile = None +- +- if (not optFile): +- bigStr = "Autodoc file " + progName + "." + OPTFILE_EXT + \ +- " was not found or not readable.\n" +\ +- "Check environment variable settings of " + \ +- OPTDIR_VARIABLE + " and " + \ +- "IMOD_DIR\nor place autodoc file in current directory" +- PipSetError(bigStr) +- return -1 +- +- numOpts = 0 +- optList = [] +- formatList = [] +- defaultList = [] +- longName = shortName = type = '' +- helpStr = ['','',''] +- formatStr = '' +- defaultStr = '' +- readingOpt = 0 +- inQuoteIndex = -1 +- +- while (1): +- (lineLen, bigStr, indst, badComment) = PipReadNextLine(optFile, '#', 0, 0) +- if (lineLen == -2): +- PipSetError("Error reading autodoc file") +- return -1 +- +- # Count up option entries +- textStr = bigStr[indst:] +- isOption = LineIsOptionToken(textStr) +- if (isOption): +- numOpts += 1 +- +- # Look for new keyword-value delimiter before any options +- if (not numOpts): +- (newDelim, lastInd, inQuoteIndex) = CheckKeyword(textStr, "KeyValueDelimiter", 0) +- if (newDelim): +- sValueDelim = newDelim +- +- if (readingOpt and (lineLen == -3 or isOption)): +- +- # If we were reading options, it is time to add them if we are at +- # end of file or if we have reached a new token of any kind +- +- # Pick the closest help string that was read in if the given one +- # does not match (there has got to be an easier way!) +- if (helpLevel <= 1): +- if (helpStr[0]): +- helpInd = 0 +- elif (helpStr[1]): +- helpInd = 1 +- else: +- helpInd = 2 +- +- elif (helpLevel == 2): +- if (helpStr[1]): +- helpInd = 1 +- elif (helpStr[0]): +- helpInd = 0 +- else: +- helpInd = 2 +- +- else: +- if (helpStr[2]): +- helpInd = 2 +- elif (helpStr[1]): +- helpInd = 1 +- else: +- helpInd = 0 +- +- # If it is a section header, get rid of the names +- if (isSection): +- longName = shortName = '' +- +- optStr = shortName + ":" + longName + ":" + type + ":" + \ +- helpStr[helpInd] +- optList.append(optStr) +- formatList.append(formatStr) +- defaultList.append(defaultStr) +- +- # Clean up +- longName = shortName = type = '' +- helpStr = ['','',''] +- formatStr = '' +- defaultStr = '' +- readingOpt = 0 +- +- if (lineLen == -3): +- break +- +- # If reading options, look for the various keywords +- if (readingOpt): +- +- # If the last string gotten was a help string and the line does not contain the +- # value delimiter or we are in a quote, then append it to the last string +- if lastInd and (inQuoteIndex >= 0 or textStr.find(sValueDelim) < 0): +- if helpStr[lastInd-1].endswith('.'): +- helpStr[lastInd-1] += ' ' +- else: +- helpStr[lastInd-1] += ' ' +- +- # Replace leading ^ with a newline +- if (textStr[0] == '^'): +- textStr = textStr.replace('^', '\n', 1) +- +- # If inside quotes, look for quote at end and say it is the end of accepting +- # continuation lines, and as a protection, also say a blank line ends it +- lentx = len(textStr) +- if inQuoteIndex >= 0 and \ +- (not lentx or textStr[lentx - 1] == sQuoteTypes[inQuoteIndex]): +- if lentx: +- helpStr[lastInd-1] += textStr[:lentx - 1] +- lastInd = 0 +- inQuoteIndex = -1 +- else: +- helpStr[lastInd-1] += textStr +- +- # Otherwise look for each keyword of interest, but zero last index +- else: +- lastInd = 0 +- retval = CheckKeyword(textStr, "short", 0) +- if retval[0]: +- (shortName, lastInd, inQuoteIndex) = retval +- retval = CheckKeyword(textStr, "long", 0) +- if retval[0]: +- (longName, lastInd, inQuoteIndex) = retval +- retval = CheckKeyword(textStr, "type", 0) +- if retval[0]: +- (type, lastInd, inQuoteIndex) = retval +- retval = CheckKeyword(textStr, "format", 0) +- if retval[0]: +- (formatStr, lastInd, inQuoteIndex) = retval +- retval = CheckKeyword(textStr, "default", 0) +- if retval[0]: +- (defaultStr, lastInd, inQuoteIndex) = retval +- +- # Check for usage if at help level 1 or if we haven't got +- # either of the other strings yet +- if (helpLevel <= 1 or not (helpStr[1] or helpStr[2])): +- retval = CheckKeyword(textStr, "usage", 1, 1) +- if retval[0]: +- (helpStr[0], lastInd, inQuoteIndex) = retval +- +- # Check for tooltip if at level 2 or if at level 1 and haven't +- # got usage, or at level 3 and haven't got manpage +- if (helpLevel == 2 or (helpLevel <= 1 and not helpStr[0]) or +- (helpLevel >= 3 and not helpStr[2])): +- retval = CheckKeyword(textStr, "tooltip", 2, 1) +- if retval[0]: +- (helpStr[1], lastInd, inQuoteIndex) = retval +- +- # Check for manpage if at level 3 or if at level 2 and haven't +- # got tip, or at level 1 and haven't got tip or usage +- if (helpLevel >= 3 or (helpLevel == 2 and not helpStr[1]) or +- (helpLevel <= 1 and not (helpStr[1] or helpStr[0]))): +- retval = CheckKeyword(textStr, "manpage", 3, 1) +- if retval[0]: +- (helpStr[2], lastInd, inQuoteIndex) = retval +- +- # If that was a line with quoted string, check for quote at end of line and +- # close out the help string if so */ +- if inQuoteIndex >= 0 and lastInd: +- lentx = len(helpStr[lastInd - 1]) +- if lentx and helpStr[lastInd - 1][lentx - 1] == sQuoteTypes[inQuoteIndex]: +- helpStr[lastInd - 1] = helpStr[lastInd - 1][:lentx - 1] +- inQuoteIndex = -1 +- lastInd = 0 +- +- # But if not reading options, check for a new option token and start +- # reading if one is found. But first take a Field value as default +- # long option name +- elif (isOption > 0): +- lastInd = 0 +- inQuoteIndex = -1 +- readingOpt = 1 +- isSection = isOption - 1 +- if (not isSection): +- retval = CheckKeyword(textStr[len(OPEN_DELIM):], "Field", 0) +- if retval[0]: +- longName = retval[0] +- longName = longName[:len(longName)-1].rstrip() +- +- +- # Initialize and process option strings +- PipInitialize(numOpts) +- # print "Initialized for %d options" % numOpts +- +- # add the options +- for i in range(numOpts): +- err = PipAddOption(optList[i]) +- if err: +- return err +- sOptTable[sNextOption - 1].format = formatList[i] +- sOptTable[sNextOption - 1].defaultVal = defaultList[i] +- +- return 0 +- +- +-# Routine to parse the entries in command line after options have been +-# defined one way or another +-# +-def PipParseEntries(argv): +- global sTakeStdIn, pipErrno +- pipErrno = 0 +- argc = len(argv) +- +- # Special case: no arguments and flag set to take stdin automatically +- if (not argc and sTakeStdIn): +- err = ReadParamFile(sys.stdin) +- if err: +- pipErrno = err +- return None +- else: +- +- # parse the arguments +- for i in range(1,argc): +- err = PipNextArg(argv[i]) +- if (err < 0): +- pipErrno = err +- return None +- if (err and i == argc - 1): +- PipSetError("A value was expected but not found for" + \ +- " the last option on the command line") +- pipErrno = -1 +- return None +- +- PipPrintEntries() +- return PipNumberOfArgs() +- +- +-# High-level routine to initialize from autodoc with optional fallback options +-# Set exit string and output to stdout, print usage if not enough arguments +-# +-def PipReadOrParseOptions(argv, options, progName, minArgs, numInFiles, +- numOutFiles): +- global sExitPrefix +- +- # Startup with fallback +- ierr = PipReadOptionFile(progName, 0, 0) +- PipExitOnError(0, "ERROR: " + progName + " - ") +- if (not ierr): +- (numOptArgs, numNonOptArgs) = PipParseEntries(argv) +- else: +- errString = PipGetError() +- if (not options or not len(options)): +- PipSetError(errString) +- if (errString): +- sys.stdout.write("PIP WARNING: " + errString + \ +- "\nUsing fallback options in main program\n\n") +- +- (numOptArgs, numNonOptArgs) = PipParseInput(argv, options) +- +- +- # Output usage and exit if not enough arguments +- exitSave = sExitPrefix +- sExitPrefix = None +- help = PipGetBoolean('help', 0) +- sExitPrefix = exitSave +- if (help or numOptArgs + numNonOptArgs < minArgs): +- PipPrintHelp(progName, 0, numInFiles, numOutFiles) +- sys.exit(0) +- +- if not ierr: +- return (numOptArgs, numNonOptArgs) +- +- # If no autodoc found, open the master list of program defaults +- try: +- pipDir = os.getenv('IMOD_DIR') +- if not pipDir: +- return (numOptArgs, numNonOptArgs) +- defFile = open(pipDir + PATH_SEPARATOR + DEFAULTS_DIR + PATH_SEPARATOR + +- DEFAULTS_FILE, 'r') +- +- # Read lines, determine when enter and leave the program section, add lines +- # to dictionary +- progMatch = re.compile('\[\s*Program\s*=\s*' + progName + '\s*\]') +- inProg = False +- defDict = {} +- while True: +- line = defFile.readline() +- if not line: +- break +- line = line.strip() +- if progMatch.search(line): +- if inProg: +- break +- inProg = True +- elif inProg: +- lsplit = line.split('=') +- if len(lsplit) == 2: +- defDict[lsplit[0].strip()] = lsplit[1].strip() +- +- defFile.close() +- +- # Look up each option in dictionary and assign default if found +- for ind in range(sNumOptions): +- if sOptTable[ind].longName in defDict: +- sOptTable[ind].defaultVal = defDict[sOptTable[ind].longName] +- +- except IOError: +- pass +- +- return (numOptArgs, numNonOptArgs) +- +- +-# Routine to get input/output file from parameter or non-option args +-# +-def PipGetInOutFile(option, nonOptArgNo): +- global sOptTable, pipErrno +- retval = PipGetString(option, '') +- if not pipErrno: +- return retval +- if (nonOptArgNo >= sOptTable[sNonOptInd].count): +- pipErrno = 1 +- return None +- return PipGetNonOptionArg(nonOptArgNo) +- +- +-# Read successive lines from a parameter file or standard input, and +-# store as options and values +-# +-def ReadParamFile(pFile): +- global sNotFoundOK, sNumOptionArguments, sOptTable, sNonOptLines, tokenSep +- global STANDARD_INPUT_STRING, STANDARD_INPUT_END, sNumOptions, sWarnOnComment +- while (1): +- +- # If non-option lines are allowed, set flag that it is OK for +- # LookupOption to not find the option, but only for the given number +- # of lines at the start of the input +- sNotFoundOK = not sNumOptionArguments and \ +- (sOptTable[sNonOptInd].count < sNonOptLines) +- (lineLen, lineStr, indst, badComment) = PipReadNextLine(pFile, '#', 0, 1) +- if (lineLen == -3): +- break +- if (lineLen == -2): +- PipSetError("Error reading parameter file or " + \ +- STANDARD_INPUT_STRING) +- return -1 +- if badComment: +- if sWarnOnComment: +- sys.stdout.write("PIP WARNING: " + badComment) +- else: +- PipSetError(badComment) +- return -1 +- +- # Find token +- matchObj = re.search(tokenSep, lineStr[indst:]) +- indnd = lineLen +- if (matchObj): +- indnd = matchObj.start() +- token = lineStr[indst:indnd] +- +- # Done if it matches end of input string +- if (token == STANDARD_INPUT_END) or (sDoneEnds and token == "DONE"): +- break +- +- # Look up option +- optNum = LookupOption(token, sNumOptions) +- if (optNum < 0): +- +- # If no option, process special case if in-line non-options allowed +- # or error out +- if (sNotFoundOK): +- err = AddValueString(sNonOptInd, lineStr[indst:]) +- if err: +- return err +- continue +- else: +- return optNum +- +- if (sOptTable[optNum].type == "PF"): +- PipSetError("Trying to open a parameter file while reading a " + +- "parameter file or " + STANDARD_INPUT_STRING) +- return -1 +- +- # Find first non-white space, passing over at most one equals sign +- indst = indnd + 1 +- gotEquals = 0 +- while (indst < lineLen): +- if (lineStr[indst] == '='): +- if (gotEquals): +- PipSetError("Two = signs in input line: " + lineStr) +- return -1 +- gotEquals = 1 +- +- elif (lineStr[indst] != ' ' and lineStr[indst] != '\t'): +- break +- indst += 1 +- +- # If there is a string, get one; if not, get a "1" for boolean, +- # otherwise it is an error +- if (indst < lineLen): +- token = lineStr[indst:] +- elif (sOptTable[optNum].type == 'B'): +- token = "1" +- else: +- PipSetError("Missing a value on the input line: " + lineStr) +- return -1 +- +- # Add the token as a value string and increment argument number +- err = AddValueString(optNum, token) +- if err: +- return err +- sNumOptionArguments += 1 +- +- sNotFoundOK = 0 +- return 0 +- +- +-# Reads a line from the file [pFile], stripping white space at the end of the +-# line and in-line comments starting with [comment] if [inLineComments] is +-# non-zero. Discards the line and reads another if it is blank or if the +-# first non-blank character is [comment], unless [keepComments] is nonzero. +-# Returns a tuple of: the length of the line, or -3 for end of +-# file, or -2 for error reading file; the line; and the index of the first +-# non-white space character +-# +-def PipReadNextLine(pFile, comment, keepComments, inLineComments): +- global nonWhite, sForbidCommentLong, sForbidCommentShort +- +- while (1): +- badComment = "" +- try: +- lineStr = pFile.readline() +- lineLen = len(lineStr) +- if not lineLen: +- return (-3, '', 0, '') +- except: +- return (-2, '', 0, '') +- +- # Get first non-white space +- matchObj = re.search(nonWhite, lineStr) +- if (not matchObj): +- continue +- indst = matchObj.start() +- +- # If it is a comment, skip or strip line ending and return +- if (lineStr[indst] == comment): +- if (keepComments): +- lineStr = lineStr.rstrip() +- lineLen = len(lineStr) +- break +- else: +- continue +- +- # adjust line length to remove comment, if we have in-line comments +- if inLineComments: +- strPtr = lineStr.find(comment) +- if strPtr >= 0: +- lineLen = strPtr +- +- # Look for forbidden in-line comments +- if sForbidCommentLong or sForbidCommentShort: +- lsplit = lineStr.split() +- option = lsplit[0].lstrip('-') +- if (sForbidCommentLong and sForbidCommentLong.startswith(option)) or \ +- (sForbidCommentShort and sForbidCommentShort.startswith(option)): +- badComment = 'The ' + comment + ' character should not be used for' + \ +- ' a comment or any other reason on the line: ' + lineStr +- +- # adjust line length back further to remove white space and newline +- lineStr = lineStr[0:lineLen].rstrip() +- lineLen = len(lineStr) +- +- # Return if something is on line or we are keeping comments +- if (indst < lineLen or keepComments): +- break +- +- return (lineLen, lineStr, indst, badComment) +- +- +- +-# Parse a line of values for an option and return them into an array +-# +-def OptionLineOfValues(option, valType, numToGet): +- global pipErrno +- +- # Get string and save pointer to it for error messages +- strPtr = GetNextValueString(option) +- if pipErrno and pipErrno != 2: +- return None +- saveErrno = pipErrno +- retval = PipGetLineOfValues(option, strPtr, valType, numToGet) +- if not pipErrno: +- pipErrno = saveErrno +- return retval +- +- +-# Parses a line of values from the string in [strPtr] and returns them as an +-# array. The type is indicated in +-# [valType] as PIP_INTEGER (1) for integer or PIP_FLOAT (2) for float. +-# The number of values to get is set in [numToGet], where a value of zero +-# indicates all values should be returned, in which case the number gotten is +-# returned in [numToGet]. The return value is -1 for errors in parsing or +-# too few values on the line. +-# NOTE THAT DEFAULTS CANNOT BE ALLOWED UNLESS AN ARRAY CAN BE SUPPLIED +-# +-def PipGetLineOfValues(option, strPtr, valType, numToGet): +- global valueSep, sAllowDefaults, PIP_INTEGER, PIP_FLOAT +- global pipErrno +- pipErrno = 0 +- fullStr = strPtr +- array = [] +- numGot = 0 +- gotComma = 0 +- +- while (len(strPtr)): +- matchObj = re.search(valueSep, strPtr) +- if (not matchObj): +- +- # no object means read a number to end of string +- endPtr = len(strPtr) +- elif (matchObj.start() == 0): +- +- # separator at start means advance by one byte and continue +- # if defaults allowed and a specific number are expected, +- # / means stop processing and mark all values as received +- if (strPtr[0] == '/'): +- if (sAllowDefaults and numToGet): +- numGot = numToGet +- break +- +- sTempStr = "Default entry with a / is not allowed in value entry" +\ +- ": "+ option + " " + fullStr +- PipSetError(sTempStr) +- pipErrno = -1 +- return None +- +- # special handling of commas to allow default values +- if (strPtr[0] == ','): +- +- # If already have a comma, skip an array value if defaults +- # allowed +- if (gotComma): +- if (sAllowDefaults and numToGet): +- numGot += 1 +- if (numGot >= numToGet): +- break +- else: +- sTempStr = "Default entries with commas are not allowed " +\ +- "in value entry: " + option + " " + fullStr +- PipSetError(sTempStr) +- pipErrno = -1 +- return None +- gotComma = 1 +- +- strPtr = strPtr[1:] +- continue +- +- else: +- # otherwise, this should be the end index for the conversion +- endPtr = matchObj.start() +- +- +- # convert number in a try block +- try: +- if (valType == PIP_INTEGER): +- array.append(int(strPtr[0:endPtr])) +- else: +- array.append(float(strPtr[0:endPtr])) +- numGot += 1 +- except: +- sTempStr = "Illegal character in value entry: " + \ +- option + " " + fullStr +- PipSetError(sTempStr) +- pipErrno = -1 +- return None +- +- # Mark that there is no comma after we have a number +- gotComma = 0 +- +- # Done if at end of line, or if count is fulfilled +- if (endPtr == len(strPtr) or (numToGet and numGot >= numToGet)): +- break +- +- # Otherwise advance to separator and continue +- strPtr = strPtr[endPtr:] +- +- +- # If not enough values found, return error +- if (numToGet > 0 and numGot < numToGet): +- sTempStr = str(numToGet) + " values expected but only " + str(numGot) + \ +- " values found in value entry: " + option + " " + fullStr +- PipSetError(sTempStr) +- pipErrno = -1 +- return None +- +- return array +- +- +-# Get a pointer to the value string for the given option. +-# Return < 0 if the option is invalid, 1 if the option was not entered, or 2 if it was +-# not entered and there is a default being returned +-# If the option allows multiple values, advance the multiple counter +-# +-def GetNextValueString(option): +- global sOptTable, sNonOptInd, pipErrno +- pipErrno = 0 +- err = LookupOption(option, sNonOptInd + 1) +- if (err < 0): +- pipErrno = err +- return None +- optp = sOptTable[err] +- if (not optp.count): +- if optp.defaultVal: +- pipErrno = 2 +- return optp.defaultVal +- pipErrno = 1 +- return None +- +- index = 0 +- if (optp.multiple): +- index = optp.multiple - 1 +- if (optp.multiple and optp.multiple < optp.count): +- optp.multiple += 1 +- return optp.values[index] +- +- +-# Add a string to the set of values for an option whose index is optInd +-# +-def AddValueString(optInd, strPtr): +- global sOptTable, pipErrno +- optp = sOptTable[optInd] +- +- # Add the index of the next non-option arg and the index of a linked option if +- # one is defined to the array for these +- if optp.linked: +- optp.nextLinked.append(sOptTable[sNonOptInd].count) +- ind = 0 +- if sLinkedOption: +- err = LookupOption(sLinkedOption, sNumOptions) +- if (err < 0): +- pipErrno = err +- return None +- ind = sOptTable[err].count +- optp.nextLinked.append(ind) +- +- # If we accept multiple values or have none yet, append; +- # otherwise set first element +- if optp.multiple or not optp.count: +- optp.values.append(strPtr) +- optp.count += 1 +- else: +- optp.values[0] = strPtr +- optp.count = 1 +- return 0 +- +- +-# Lookup an option in the table, up to the range in maxLookup +-# +-def LookupOption(option, maxLookup): +- global sOptTable, LOOKUP_NOT_FOUND, LOOKUP_AMBIGUOUS, sNotFoundOK, sNoAbbrevs +- lenopt = len(option) +- found = LOOKUP_NOT_FOUND +- +- # Look at all of the options specified by maxLookup +- for i in range(maxLookup): +- sname = sOptTable[i].shortName +- lname = sOptTable[i].longName +- lenShort = sOptTable[i].lenShort +- starts = PipStartsWith(sname, option) +- +- # First test for single letter short name match - if it passes, skip ambiguity test +- if lenopt == 1 and starts and lenShort == 1: +- found = i; +- break +- +- if (starts and (not sNoAbbrevs or lenopt == lenShort)) or \ +- (PipStartsWith(lname, option) and (not sNoAbbrevs or lenopt == len(lname))): +- +- # If it is found, it's an error if one has already been found +- if (found == LOOKUP_NOT_FOUND): +- found = i +- else: +- if not sTestAbbrevForUsage: +- sTempStr = "An option specified by \"" + option + \ +- "\" is ambiguous between option " + sname + " - " + \ +- lname + " and option " + sOptTable[found].shortName + \ +- " - " + sOptTable[found].longName +- PipSetError(sTempStr) +- return LOOKUP_AMBIGUOUS +- +- # Set error string unless flag set that non-options are OK +- if (found == LOOKUP_NOT_FOUND and not sNotFoundOK): +- sTempStr = "Illegal option: " + option +- PipSetError(sTempStr) +- return found +- +- +-# Test for whether str1 starts with str2, returns false if either is empty +-# +-def PipStartsWith(str1, str2): +- if (not str1 or str1 == "" or not str2 or str2 == ""): +- return False +- return str1.startswith(str2) +- +- +-# Determines whether the line contains the token for an option inside the +-# opening and closing delimiters and returns 1 if it does, or -1 if it is +-# another token +-# +-def LineIsOptionToken(line): +- +- # It is not a token unless it starts with open delim and contains close +- if (not PipStartsWith(line, OPEN_DELIM) or line.find(CLOSE_DELIM) < 0): +- return 0 +- +- # It must then contain "Field" right after delim to be an option +- openlen = len(OPEN_DELIM) +- if (PipStartsWith(line[openlen:], "Field")): +- return 1 +- if (PipStartsWith(line[openlen:], "SectionHeader")): +- return 2 +- +- return -1 +- +- +-# +-# Checks for whether a keyword occurs at the beginning of the line and +-# is followed by the keyword-value delimiter, and if so returns the +-# value string and the supplied index number, otherwise blank string and 0. +-# If quoteOK is non-zero, it sees if the string starts with a quote character in +-# sQuoteTypes, strips that, and returns the index in the third element +-# +-def CheckKeyword(line, keyword, index, quoteOK = 0): +- global sValueDelim +- lineLen = len(line) +- +- # First make sure line starts with it +- if (not PipStartsWith(line, keyword)): +- return ('', 0, -1) +- +- # Now look for delimiter +- valStart = line.find(sValueDelim) +- if (valStart < 0): +- return ('', 0, -1) +- +- # Eat spaces after the delimiter and return if nothing left +- # In other words, a key with no value is the same as having no key at all +- valStart += len(sValueDelim) +- while (valStart < lineLen and (line[valStart] == ' ' or +- line[valStart] == '\t')): +- valStart += 1 +- if (valStart >= lineLen): +- return ('', 0, -1) +- +- # Look for quote if directed to +- indQuote = -1 +- if quoteOK and line[valStart] in sQuoteTypes: +- indQuote = sQuoteTypes.find(line[valStart]) +- valStart += 1 +- +- return (line[valStart:], index, indQuote) +diff -ruN IMOD/pysrc/PIP.py IMOD_rename_pip/pysrc/PIP.py +--- IMOD/pysrc/PIP.py 1970-01-01 01:00:00.000000000 +0100 ++++ IMOD_rename_pip/pysrc/PIP.py 2023-11-06 16:49:35.218638971 +0100 +@@ -0,0 +1,1545 @@ ++#!/usr/bin/python ++# ++# Parse Input Params module, translated from C ++# ++# Author: David Mastronarde ++# ++# $Id$ ++# ++# The approach in translating was to retain most of the flags and capabilities ++# in the C code, even when the calls for setting the flags were not included: ++# i.e., the special flags, help output level and type. However, manpage output ++# is not provided for as that was not needed. Default value entries for ++# general arrays was also not included as this would have involved changing the ++# calls for getting arrays defined in the previous extension module. The code ++# order is the same as in parse_params.c. Obvious simplifications were made ++# but much of the string processing logic was retained as the safest and ++# easiest approach - so some of this will seem rather un-Python like. ++# All global variables are declared in the functions that use them, although ++# only the ones being assigned to need to be declared. ++ ++import re, sys, os, glob ++ ++# The global defines, tables and variables ++NON_OPTION_STRING = "NonOptionArgument" ++STANDARD_INPUT_STRING = "StandardInput" ++STANDARD_INPUT_END = "EndInput" ++LOOKUP_NOT_FOUND = -1 ++LOOKUP_AMBIGUOUS = -2 ++OPTFILE_DIR = "autodoc" ++OPTFILE_EXT = "adoc" ++OPTDIR_VARIABLE = "AUTODOC_DIR" ++DEFAULTS_FILE = "progDefaults.adoc" ++DEFAULTS_DIR = "com" ++DEFAULT_SUB_STR = "%{default}" ++PRINTENTRY_VARIABLE = "PIP_PRINT_ENTRIES" ++OPEN_DELIM = "[" ++CLOSE_DELIM = "]" ++VALUE_DELIM = "=" ++PATH_SEPARATOR = os.sep ++PIP_INTEGER = 1 ++PIP_FLOAT = 2 ++ ++sTypes = ("B","PF","LI","I", "F", "IP", "FP", "IT", "FT", "IA", "FA", "CH","FN") ++sTypeForUsage = ("Boolean", "File", "List", "Int", "Float", "2 ints", \ ++ "2 floats", "3 ints", "3 floats", "Ints", "Floats", "String", "File", \ ++ "Unknown argument type") ++sNumTypes = 13 ++tokenSep = re.compile("[= \t]") ++nonWhite = re.compile('[^ \t]') ++valueSep = re.compile('[ ,\t/]') ++pipErrno = 0 ++sQuoteTypes = """'"`""" ++ ++ ++# The options "structure"; initialize all the values ++class pipOption: ++ def __init__(self): ++ self.shortName = '' ++ self.longName = '' ++ self.type = '' ++ self.helpString = '' ++ self.format = '' ++ self.defaultVal = '' ++ self.values = [] ++ self.multiple = 0 ++ self.count = 0 ++ self.lenShort = 0 ++ self.nextLinked = [] ++ self.linked = False ++sOptTable = None ++sTableSize = 0 ++sNumOptions = 0 ++sNonOptInd = 0 ++sErrorString = None ++sExitPrefix = None ++sProgramName = "" ++sErrorDest = 0 ++sNextOption = 0 ++sNextArgBelongsTo = -1 ++sNumOptionArguments = 0 ++sAllowDefaults = 0 ++sOutputManpage = 0 ++sPrintEntries = -1 ++sDefaultDelim = VALUE_DELIM ++sValueDelim = sDefaultDelim ++sNoCase = 0 ++sDoneEnds = 0 ++sTakeStdIn = 0 ++sNonOptLines = 0 ++sNoAbbrevs = 0 ++sNotFoundOK = False ++sLinkedOption = None ++sTestAbbrevForUsage = False ++sForbidCommentLong = '' ++sForbidCommentShort = '' ++sWarnOnComment = False ++ ++# Initialize for given number of options ++# ++def PipInitialize(numOpts): ++ global sNumOptions, sTableSize, sNonOptInd, sOptTable ++ sNumOptions = numOpts ++ sTableSize = numOpts + 2 ++ sNonOptInd = sNumOptions ++ sOptTable = [] ++ ++ # Initialize the table ++ for i in range(sTableSize): ++ inst = pipOption() ++ sOptTable.append(inst) ++ ++ # In the last slots, put non-option arguments, and also put the ++ # name for the standard input option for easy checking on duplication ++ sOptTable[sNonOptInd].longName = NON_OPTION_STRING ++ sOptTable[sNonOptInd + 1].shortName = STANDARD_INPUT_STRING ++ sOptTable[sNonOptInd + 1].longName = STANDARD_INPUT_END ++ sOptTable[sNonOptInd].multiple = 1 ++ return 0 ++ ++ ++# Free all allocated memory and set state back to initial state (sort of) ++# ++def PipDone(): ++ global sNumOptions, sTableSize, sNonOptInd, sOptTable, sErrorString, sNextOption ++ global sNextArgBelongsTo, sNumOptionArguments, sAllowDefaults ++ del sOptTable ++ sOptTable = None ++ sTableSize = 0 ++ sNumOptions = 0 ++ sErrorString = None ++ sNextOption = 0 ++ sNextArgBelongsTo = -1 ++ sNumOptionArguments = 0 ++ sAllowDefaults = 0 ++ sLinkedOption = None ++ ++ ++# Set up for Pip to handle exiting on error, with a prefix string ++# ++def PipExitOnError(useStdErr, prefix): ++ global sErrorDest, sExitPrefix ++ sErrorDest = useStdErr ++ sExitPrefix = prefix ++ return 0 ++ ++ ++# Just set the exit prefix ++# ++def setExitPrefix(prefix): ++ global sExitPrefix ++ sExitPrefix = prefix ++ ++# Enable the entry ouput ++# ++def PipEnableEntryOutput(val): ++ global sPrintEntries ++ sPrintEntries = val ++ ++# Set a linked option ++# ++def PipSetLinkedOption(option): ++ global sLinkedOption ++ sLinkedOption = option ++ ++# Set up one option for which in-line comments are not allowed ++# ++def PipForbidComments(longName, shortName, warn): ++ global sForbidCommentShort, sForbidCommentLong, sWarnOnComment ++ sForbidCommentShort = shortName ++ sForbidCommentLong = longName ++ sWarnOnComment = warn ++ ++# Return the error number ++# ++def PipGetErrNo(): ++ global pipErrno ++ return pipErrno ++ ++ ++# Expand a set of arguments in the input list on Windows; pass through any argument ++# without a wild card, try to match the rest, and pass one through if there is no match ++# but return index of first non-matched item ++def expandArgList(args): ++ if not ('win32' in sys.platform or 'cygwin' in sys.platform): ++ return (args, -1) ++ newList = [] ++ noMatchInd = -1 ++ for ind, arg in enumerate(args): ++ if '*' not in arg and '?' not in arg: ++ newList.append(arg) ++ else: ++ expanded = glob.glob(arg) ++ if expanded: ++ expanded.sort() ++ newList += expanded ++ else: ++ newList.append(arg) ++ if noMatchInd < 0: ++ noMatchInd = ind ++ ++ return (newList, noMatchInd) ++ ++ ++# Add an option, with short and long name, type, and help string ++# ++def PipAddOption(optionString): ++ global sNextOption, sNumOptions, sOptTable, sTableSize, sNonOptInd ++ ++ if (sNextOption >= sNumOptions): ++ PipSetError("Attempting to add more options than were originally" ++ " specified") ++ return -1 ++ ++ parts = optionString.split(':', 3) ++ if len(parts) < 4: ++ PipSetError("Option does not have three colons in it: " + optionString) ++ return -1 ++ ++ sOptTable[sNextOption].shortName = parts[0] ++ newSlen = len(parts[0]) ++ sOptTable[sNextOption].lenShort = newSlen ++ sOptTable[sNextOption].longName = parts[1] ++ ++ # If type ends in M or L, set multiple flag and strip M or L ++ if parts[2].endswith('M') or parts[2].endswith('L'): ++ sOptTable[sNextOption].multiple = 1 ++ sOptTable[sNextOption].linked = parts[2].endswith('L') ++ if len(parts[2]) > 1: ++ parts[2] = parts[2][0:len(parts[2]) - 1] ++ else: ++ parts[2] = '' ++ ++ sOptTable[sNextOption].type = parts[2] ++ sOptTable[sNextOption].helpString = parts[3] ++ ++ for ind in range(sTableSize): ++ # after checking existing ones, skip to NonOptionArg and ++ # StandardInput entries ++ if (ind >= sNextOption and ind < sNonOptInd): ++ continue ++ ++ oldShort = sOptTable[ind].shortName ++ oldLong = sOptTable[ind].longName ++ oldSlen = sOptTable[ind].lenShort ++ if (((PipStartsWith(parts[0], oldShort) or PipStartsWith(oldShort, parts[0])) and ++ ((newSlen > 1 and oldSlen > 1) or (newSlen == 1 and oldSlen == 1))) or \ ++ PipStartsWith(oldLong, parts[0]) or PipStartsWith(parts[0], oldLong) or \ ++ PipStartsWith(oldShort, parts[1]) or PipStartsWith(parts[1], oldShort) or \ ++ PipStartsWith(oldLong, parts[1]) or PipStartsWith(parts[1], oldLong)): ++ sTempStr = "Option " + parts[0] + " " + parts[1] + \ ++ " is ambiguous with option " + oldShort + " " + oldLong ++ PipSetError(sTempStr) ++ sys.stdout.write(sTempStr + "\n") ++ return -1 ++ ++ sNextOption += 1 ++ return 0 ++ ++ ++# Call this to process the next argument ++def PipNextArg(argString): ++ global sNextArgBelongsTo, sOptTable, STANDARD_INPUT_STRING ++ global sNumOptionArguments, sNonOptInd, sNextOption, sNotFoundOK ++ ++ # If we are expecting a value for an option, add string to the option ++ if (sNextArgBelongsTo >= 0): ++ err = AddValueString(sNextArgBelongsTo, argString) ++ ++ # Check whether this option was for reading from parameter file ++ if (not err and sOptTable[sNextArgBelongsTo].type == 'PF'): ++ try: ++ paramFile = open(argString, "r") ++ except: ++ sTempStr = "Error opening parameter file " + argString ++ PipSetError(sTempStr) ++ return -1 ++ ++ err = ReadParamFile(paramFile) ++ try: ++ close(paramFile) ++ except: ++ pass ++ sNextArgBelongsTo = -1 ++ return err ++ ++ # Is it a legal option starting with - or -- ? ++ if (argString.strip()[0] == '-'): ++ argString = argString.strip() ++ indStart = 1 ++ if (len(argString) > 1 and argString[1] == '-'): ++ indStart = 2 ++ if (len(argString) == indStart): ++ PipSetError("Illegal argument: - or --") ++ return -1 ++ ++ # First check for StandardInput ++ if (STANDARD_INPUT_STRING.startswith(argString[indStart:])): ++ err = ReadParamFile(sys.stdin) ++ return err ++ ++ # Next check if it is a potential numeric non-option arg ++ sNotFoundOK = 1 ++ for ch in argString[indStart:]: ++ if ch != '-' and ch != ',' and ch != '.' and ch != ' ' and not ch.isdigit(): ++ sNotFoundOK = 0 ++ break ++ ++ # Lookup the option among true defined options ++ err = LookupOption(argString[indStart:], sNextOption) ++ ++ # Process as an option unless it could be numeric and was not found ++ if not (sNotFoundOK and err == LOOKUP_NOT_FOUND): ++ sNotFoundOK = 0 ++ if err < 0: ++ return err ++ ++ sNumOptionArguments += 1 ++ ++ # For an option with value, setup to get argument next time and ++ # return an indicator that there had better be another ++ if (sOptTable[err].type != 'B'): ++ sNextArgBelongsTo = err ++ return 1 ++ else: ++ ++ # for a boolean option, set the argument with a 1 ++ return AddValueString(err, '1') ++ ++ # A non-option argument ++ sNotFoundOK = 0 ++ (expanded, noMatchInd) = expandArgList([argString]) ++ for arg in expanded: ++ err = AddValueString(sNonOptInd, arg) ++ if err == None: ++ return None ++ return 0 ++ ++ ++# return number of option arguments (approximate) and number of non-option ++# arguments ++# ++def PipNumberOfArgs(): ++ global sOptTable, sNumOptionArguments, pipErrno ++ pipErrno = 0 ++ return (sNumOptionArguments, sOptTable[sNonOptInd].count) ++ ++# Get a non-option argument, index numbered from 0 here ++# ++def PipGetNonOptionArg(argNo): ++ global sOptTable, pipErrno ++ pipErrno = 0 ++ if (argNo >= sOptTable[sNonOptInd].count): ++ PipSetError("Requested a non-option argument beyond the number" + \ ++ " available") ++ pipErrno = -1 ++ return None ++ return sOptTable[sNonOptInd].values[argNo] ++ ++ ++# Get a string option ++# ++def PipGetString(option, string): ++ global pipErrno ++ pipErrno = 0 ++ retval = GetNextValueString(option) ++ if pipErrno < 0: ++ return None ++ if pipErrno == 1: ++ return string ++ return retval ++ ++ ++# Get a boolean (binary) option; make sure it has a legal specification ++# ++def PipGetBoolean(option, val): ++ global pipErrno ++ pipErrno = 0 ++ strPtr = GetNextValueString(option) ++ if pipErrno < 0: ++ return None ++ if pipErrno > 0: ++ return val ++ if (strPtr == "1" or strPtr == "T" or strPtr == "TRUE" or strPtr == "ON" \ ++ or strPtr == "t" or strPtr == "true" or strPtr == "on"): ++ return 1 ++ elif (strPtr == "0" or strPtr == "F" or strPtr == "FALSE" or \ ++ strPtr == "OFF" or strPtr == "f" or strPtr == "false" or \ ++ strPtr == "off"): ++ return 0 ++ else: ++ sTempStr = "Illegal entry for boolean option " + option + ": " + strPtr ++ PipSetError(sTempStr) ++ pipErrno = -1 ++ return None ++ ++ ++# Get single integer and float just call to get an array with one element ++# ++def PipGetInteger(option, val): ++ global pipErrno ++ num = 1 ++ retval = PipGetIntegerArray(option, num) ++ if (pipErrno < 0): ++ return None ++ if (pipErrno == 1): ++ return val ++ return retval[0] ++ ++def PipGetFloat(option, val): ++ global pipErrno ++ num = 1 ++ retval = PipGetFloatArray(option, num) ++ if (pipErrno < 0): ++ return None ++ if (pipErrno == 1): ++ return val ++ return retval[0] ++ ++ ++# Get two integers or floats - move into array, get array with two elements ++# ++def PipGetTwoIntegers(option, val1, val2): ++ global pipErrno ++ num = 2 ++ retval = PipGetIntegerArray(option, num) ++ if (pipErrno < 0): ++ return None ++ if (pipErrno == 1): ++ return (val1, val2) ++ return (retval[0], retval[1]) ++ ++def PipGetTwoFloats(option, val1, val2): ++ global pipErrno ++ num = 2 ++ retval = PipGetFloatArray(option, num) ++ if (pipErrno < 0): ++ return None ++ if (pipErrno == 1): ++ return (val1, val2) ++ return (retval[0], retval[1]) ++ ++ ++# Get three integers or floats - move into array, get array with two elements ++# ++def PipGetThreeIntegers(option, val1, val2, val3): ++ global pipErrno ++ num = 3 ++ retval = PipGetIntegerArray(option, num) ++ if (pipErrno < 0): ++ return None ++ if (pipErrno == 1): ++ return (val1, val2, val3) ++ return (retval[0], retval[1], retval[2]) ++ ++def PipGetThreeFloats(option, val1, val2, val3): ++ global pipErrno ++ num = 3 ++ retval = PipGetFloatArray(option, num) ++ if (pipErrno < 0): ++ return None ++ if (pipErrno == 1): ++ return (val1, val2, val3) ++ return (retval[0], retval[1], retval[2]) ++ ++ ++# Getting an array of integers or floats calls the general routine for ++# getting a line of values ++# ++def PipGetIntegerArray(option, numToGet): ++ global PIP_INTEGER ++ return OptionLineOfValues(option, PIP_INTEGER, numToGet) ++ ++def PipGetFloatArray(option, numToGet): ++ global PIP_FLOAT ++ return OptionLineOfValues(option, PIP_FLOAT, numToGet) ++ ++ ++# Print a complete usage statement only ++# ++def PipPrintHelp(progName, useStdErr, inputFiles, outputFiles): ++ global sNumOptions, sOptTable, sOutputManpage, sTypeForUsage, sTypes, sNumTypes ++ global sTestAbbrevForUsage ++ numOut = 0 ++ numReal = 0 ++ helplim = 74 ++ out = sys.stdout ++ if useStdErr: ++ out = sys.stderr ++ indent4 = " " ++ linePos = 11 ++# descriptions = sTypeDescriptions ++ ++ for i in range(sNumOptions): ++ if (len(sOptTable[i].shortName) or len(sOptTable[i].longName)): ++ numReal += 1 ++ ++ if (not sOutputManpage): ++ out.write("Usage: " + progName + " ") ++ if (sNumOptions): ++ out.write("[Options]") ++ if (inputFiles): ++ out.write(" input_file") ++ if (inputFiles > 1): ++ out.write("s...") ++ if (outputFiles): ++ out.write(" output_file") ++ if (outputFiles > 1): ++ out.write("s...") ++ out.write("\n") ++ ++ if (not numReal): ++ return 0 ++ out.write("Options can be abbreviated, current short name abbreviations are in " +\ ++ "parentheses\n") ++ out.write("Options:\n") ++ descriptions = sTypeForUsage ++ ++ sTestAbbrevForUsage = True ++ for i in range(sNumOptions): ++ ++ sname = sOptTable[i].shortName ++ lname = sOptTable[i].longName ++ indentStr = "" ++ ++ # Try to look up an abbreviation of the short name ++ abbrev = None ++ if len(sname): ++ for j in range(1, len(sname)): ++ if LookupOption(sname[:j], sNumOptions) == i: ++ abbrev = sname[:j] ++ break ++ ++ if (len(lname) or len(sname)): ++ if (sOutputManpage <= 0): ++ indentStr = indent4 ++ ++ out.write(" ") ++ if len(sname): ++ out.write("-" + sname) ++ if abbrev: ++ out.write(" (-" + abbrev + ")") ++ if len(sname) and len(lname): ++ out.write(" OR ") ++ if len(lname): ++ out.write("-" + lname) ++ for j in range(sNumTypes): ++ jj = j ++ if (sOptTable[i].type == sTypes[j]): ++ break ++ ++ if (sOptTable[i].type != "B"): ++ format = descriptions[jj] ++ if sOptTable[i].format: ++ format = sOptTable[i].format.replace("\\fR", '').replace("\\fI", '').\ ++ replace("\\fB", '') ++ out.write(" " + format) ++ ++ out.write("\n") ++ ++ # Print help string, breaking up line as needed ++ if len(sOptTable[i].helpString): ++ sname = sOptTable[i].helpString ++ if sOptTable[i].defaultVal: ++ sname = sname.replace(DEFAULT_SUB_STR, sOptTable[i].defaultVal); ++ optLen = len(sname) ++ newLinePt = sname.find('\n') ++ while (optLen > helplim or newLinePt >= 0): ++ ++ # Break string at newline ++ # Or break string at last space before limit ++ if (newLinePt >= 0 and newLinePt <= helplim): ++ j = newLinePt ++ else: ++ j = sname.rfind(' ', 1, helplim) ++ if (j < 0): ++ j = 0 ++ ++ out.write(indentStr + sname[0:j] + "\n") ++ sname = sname[j+1:] ++ newLinePt = sname.find('\n') ++ optLen -= j + 1 ++ ++ out.write(indentStr + sname + "\n") ++ ++ if (sOptTable[i].multiple): ++ out.write(indentStr + "(Successive entries accumulate)\n") ++ ++ sTestAbbrevForUsage = False ++ return 0 ++ ++ ++# Print the entries ++def PipPrintEntries(): ++ global sNumOptions, sOptTable, sPrintEntries ++ if sPrintEntries < 0: ++ sPrintEntries = 0 ++ val = os.getenv(PRINTENTRY_VARIABLE) ++ if val != None: ++ try: ++ sPrintEntries = int(val) ++ except: ++ sPrintEntries = 0 ++ if not sPrintEntries: ++ return ++ sys.stdout.write("\n*** Entries to program " + sProgramName + " ***" + "\n") ++ for i in range(sNumOptions): ++ sname = sOptTable[i].shortName ++ lname = sOptTable[i].longName ++ if (len(lname) or len(sname)) and sOptTable[i].count: ++ name = lname ++ if not len(lname): ++ name = sname ++ for j in range(sOptTable[i].count): ++ sys.stdout.write(" " + name + " = " + sOptTable[i].values[j] + \ ++ "\n") ++ if sOptTable[sNonOptInd].count: ++ sys.stdout.write(" Non-option arguments:") ++ for j in range(sOptTable[sNonOptInd].count): ++ if ' ' in sOptTable[sNonOptInd].values[j]: ++ sys.stdout.write(' "' + sOptTable[sNonOptInd].values[j] + '"') ++ else: ++ sys.stdout.write(" " + sOptTable[sNonOptInd].values[j]) ++ sys.stdout.write('\n') ++ sys.stdout.write("*** End of entries ***\n\n") ++ ++ ++# Return the error string, or an empty string and an error if there is none ++# ++def PipGetError(): ++ global sErrorString, pipErrno ++ pipErrno = 0 ++ if (not sErrorString): ++ pipErrno = -1 ++ return '' ++ return sErrorString ++ ++ ++# Set the error string. ++# If sExitPrefix is set, then output an error message to stderr or stdout ++# and exit. ++def PipSetError(errString): ++ global sErrorString, sExitPrefix ++ outFile = sys.stdout ++ if sErrorDest: ++ outFile = stderr ++ sErrorString = errString ++ if not sErrorString and not sExitPrefix: ++ pipErrno = -1 ++ return None ++ ++ if sExitPrefix: ++ if not sErrorString: ++ sErrorString = "Unspecified error" ++ outFile.write(sExitPrefix + sErrorString + "\n") ++ sys.exit(1) ++ ++ return 0 ++ ++ ++# Simple function to call with error string to append to prefix and exit ++# ++def exitError(errorMess): ++ PipSetError(errorMess) ++ sys.exit(1) ++ ++ ++# Return the number of entries for a particular option ++# ++def PipNumberOfEntries(option): ++ global sNonOptInd, pipErrno ++ pipErrno = 0 ++ err = LookupOption(option, sNonOptInd + 1) ++ if (err < 0): ++ pipErrno = err ++ return None ++ ++ return sOptTable[err].count ++ ++ ++# Return the index of the next non-option arg or linked option that was entered after ++# this option ++# ++def PipLinkedIndex(option): ++ global sNumOptions, sLinkedOption, pipErrno, sNonOptInd ++ pipErrno = 0 ++ err = LookupOption(option, sNumOptions) ++ if (err < 0): ++ pipErrno = err ++ return None ++ ++ ind = 0 ++ if sOptTable[err].multiple: ++ ind = sOptTable[err].multiple - 1 ++ ++ # Set up to use count from non-option args, but use the count from the linked option ++ # instead if it was entered at all. This allows other non-option args to be used ++ which = 0 ++ if sLinkedOption != None: ++ ilink = LookupOption(sLinkedOption, sNumOptions) ++ if (ilink < 0): ++ pipErrno = ilink ++ return None ++ if sOptTable[ilink].count: ++ which = 1 ++ return sOptTable[err].nextLinked[2 * ind + which] ++ ++ ++# Top level routine to be called to process options and arguments ++# ++def PipParseInput(argv, options): ++ ++ # Initialize ++ numOpts = len(options) ++ err = PipInitialize(numOpts) ++ if err: ++ pipErrno = err ++ return None ++ ++ # add the options ++ for i in range(numOpts): ++ err = PipAddOption(options[i]) ++ if err: ++ pipErrno = err ++ return None ++ ++ return (PipParseEntries(argv)) ++ ++ ++# Try to open an autodoc at AUTODOC_DIR or IMOD_DIR/autodoc ++# ++def PipOpenInstalledAdoc(progName): ++ global OPTDIR_VARIABLE, PATH_SEPARATOR, OPTFILE_DIR, OPTFILE_EXT ++ optFile = None ++ pipDir = os.getenv(OPTDIR_VARIABLE) ++ if (pipDir): ++ bigStr = pipDir + PATH_SEPARATOR + progName + "." + OPTFILE_EXT ++ try: ++ # print "Looking for file " + bigStr ++ optFile = open(bigStr, "r") ++ except IOError: ++ optFile = None ++ ++ if (not optFile): ++ pipDir = os.getenv("IMOD_DIR") ++ if (pipDir): ++ bigStr = pipDir + PATH_SEPARATOR + OPTFILE_DIR +\ ++ PATH_SEPARATOR + progName + "." + OPTFILE_EXT ++ try: ++ #print "Looking for file " + bigStr ++ optFile = open(bigStr, "r") ++ except IOError: ++ optFile = None ++ ++ return optFile ++ ++ ++# Alternative routine to have options read from a file ++# ++def PipReadOptionFile(progName, helpLevel, localDir): ++ global PATH_SEPARATOR, OPTFILE_DIR, OPTFILE_EXT ++ global sOptTable, sValueDelim, sProgramName ++ optFile = None ++ sProgramName = progName ++ ++ # If local directory not set, look for environment variable pointing ++ # directly to where the file should be ++ if (not localDir): ++ optFile = PipOpenInstalledAdoc(progName) ++ ++ # If local directory set, set up name with ../ as many times as specified ++ # and look for file there ++ elif (localDir > 0): ++ bigStr = "" ++ for i in range(localDir): ++ bigStr += ".." + PATH_SEPARATOR ++ ++ bigStr += OPTFILE_DIR + PATH_SEPARATOR + progName + "." + OPTFILE_EXT ++ try: ++ # print "Looking for file " + bigStr ++ optFile = open(bigStr, "r") ++ except IOError: ++ optFile = None ++ ++ ++ # If there is still no file, look in current directory ++ if (not optFile): ++ bigStr = progName + "." + OPTFILE_EXT ++ try: ++ # print "Looking for file " + bigStr ++ optFile = open(bigStr, "r") ++ except IOError: ++ optFile = None ++ ++ if (not optFile): ++ bigStr = "Autodoc file " + progName + "." + OPTFILE_EXT + \ ++ " was not found or not readable.\n" +\ ++ "Check environment variable settings of " + \ ++ OPTDIR_VARIABLE + " and " + \ ++ "IMOD_DIR\nor place autodoc file in current directory" ++ PipSetError(bigStr) ++ return -1 ++ ++ numOpts = 0 ++ optList = [] ++ formatList = [] ++ defaultList = [] ++ longName = shortName = type = '' ++ helpStr = ['','',''] ++ formatStr = '' ++ defaultStr = '' ++ readingOpt = 0 ++ inQuoteIndex = -1 ++ ++ while (1): ++ (lineLen, bigStr, indst, badComment) = PipReadNextLine(optFile, '#', 0, 0) ++ if (lineLen == -2): ++ PipSetError("Error reading autodoc file") ++ return -1 ++ ++ # Count up option entries ++ textStr = bigStr[indst:] ++ isOption = LineIsOptionToken(textStr) ++ if (isOption): ++ numOpts += 1 ++ ++ # Look for new keyword-value delimiter before any options ++ if (not numOpts): ++ (newDelim, lastInd, inQuoteIndex) = CheckKeyword(textStr, "KeyValueDelimiter", 0) ++ if (newDelim): ++ sValueDelim = newDelim ++ ++ if (readingOpt and (lineLen == -3 or isOption)): ++ ++ # If we were reading options, it is time to add them if we are at ++ # end of file or if we have reached a new token of any kind ++ ++ # Pick the closest help string that was read in if the given one ++ # does not match (there has got to be an easier way!) ++ if (helpLevel <= 1): ++ if (helpStr[0]): ++ helpInd = 0 ++ elif (helpStr[1]): ++ helpInd = 1 ++ else: ++ helpInd = 2 ++ ++ elif (helpLevel == 2): ++ if (helpStr[1]): ++ helpInd = 1 ++ elif (helpStr[0]): ++ helpInd = 0 ++ else: ++ helpInd = 2 ++ ++ else: ++ if (helpStr[2]): ++ helpInd = 2 ++ elif (helpStr[1]): ++ helpInd = 1 ++ else: ++ helpInd = 0 ++ ++ # If it is a section header, get rid of the names ++ if (isSection): ++ longName = shortName = '' ++ ++ optStr = shortName + ":" + longName + ":" + type + ":" + \ ++ helpStr[helpInd] ++ optList.append(optStr) ++ formatList.append(formatStr) ++ defaultList.append(defaultStr) ++ ++ # Clean up ++ longName = shortName = type = '' ++ helpStr = ['','',''] ++ formatStr = '' ++ defaultStr = '' ++ readingOpt = 0 ++ ++ if (lineLen == -3): ++ break ++ ++ # If reading options, look for the various keywords ++ if (readingOpt): ++ ++ # If the last string gotten was a help string and the line does not contain the ++ # value delimiter or we are in a quote, then append it to the last string ++ if lastInd and (inQuoteIndex >= 0 or textStr.find(sValueDelim) < 0): ++ if helpStr[lastInd-1].endswith('.'): ++ helpStr[lastInd-1] += ' ' ++ else: ++ helpStr[lastInd-1] += ' ' ++ ++ # Replace leading ^ with a newline ++ if (textStr[0] == '^'): ++ textStr = textStr.replace('^', '\n', 1) ++ ++ # If inside quotes, look for quote at end and say it is the end of accepting ++ # continuation lines, and as a protection, also say a blank line ends it ++ lentx = len(textStr) ++ if inQuoteIndex >= 0 and \ ++ (not lentx or textStr[lentx - 1] == sQuoteTypes[inQuoteIndex]): ++ if lentx: ++ helpStr[lastInd-1] += textStr[:lentx - 1] ++ lastInd = 0 ++ inQuoteIndex = -1 ++ else: ++ helpStr[lastInd-1] += textStr ++ ++ # Otherwise look for each keyword of interest, but zero last index ++ else: ++ lastInd = 0 ++ retval = CheckKeyword(textStr, "short", 0) ++ if retval[0]: ++ (shortName, lastInd, inQuoteIndex) = retval ++ retval = CheckKeyword(textStr, "long", 0) ++ if retval[0]: ++ (longName, lastInd, inQuoteIndex) = retval ++ retval = CheckKeyword(textStr, "type", 0) ++ if retval[0]: ++ (type, lastInd, inQuoteIndex) = retval ++ retval = CheckKeyword(textStr, "format", 0) ++ if retval[0]: ++ (formatStr, lastInd, inQuoteIndex) = retval ++ retval = CheckKeyword(textStr, "default", 0) ++ if retval[0]: ++ (defaultStr, lastInd, inQuoteIndex) = retval ++ ++ # Check for usage if at help level 1 or if we haven't got ++ # either of the other strings yet ++ if (helpLevel <= 1 or not (helpStr[1] or helpStr[2])): ++ retval = CheckKeyword(textStr, "usage", 1, 1) ++ if retval[0]: ++ (helpStr[0], lastInd, inQuoteIndex) = retval ++ ++ # Check for tooltip if at level 2 or if at level 1 and haven't ++ # got usage, or at level 3 and haven't got manpage ++ if (helpLevel == 2 or (helpLevel <= 1 and not helpStr[0]) or ++ (helpLevel >= 3 and not helpStr[2])): ++ retval = CheckKeyword(textStr, "tooltip", 2, 1) ++ if retval[0]: ++ (helpStr[1], lastInd, inQuoteIndex) = retval ++ ++ # Check for manpage if at level 3 or if at level 2 and haven't ++ # got tip, or at level 1 and haven't got tip or usage ++ if (helpLevel >= 3 or (helpLevel == 2 and not helpStr[1]) or ++ (helpLevel <= 1 and not (helpStr[1] or helpStr[0]))): ++ retval = CheckKeyword(textStr, "manpage", 3, 1) ++ if retval[0]: ++ (helpStr[2], lastInd, inQuoteIndex) = retval ++ ++ # If that was a line with quoted string, check for quote at end of line and ++ # close out the help string if so */ ++ if inQuoteIndex >= 0 and lastInd: ++ lentx = len(helpStr[lastInd - 1]) ++ if lentx and helpStr[lastInd - 1][lentx - 1] == sQuoteTypes[inQuoteIndex]: ++ helpStr[lastInd - 1] = helpStr[lastInd - 1][:lentx - 1] ++ inQuoteIndex = -1 ++ lastInd = 0 ++ ++ # But if not reading options, check for a new option token and start ++ # reading if one is found. But first take a Field value as default ++ # long option name ++ elif (isOption > 0): ++ lastInd = 0 ++ inQuoteIndex = -1 ++ readingOpt = 1 ++ isSection = isOption - 1 ++ if (not isSection): ++ retval = CheckKeyword(textStr[len(OPEN_DELIM):], "Field", 0) ++ if retval[0]: ++ longName = retval[0] ++ longName = longName[:len(longName)-1].rstrip() ++ ++ ++ # Initialize and process option strings ++ PipInitialize(numOpts) ++ # print "Initialized for %d options" % numOpts ++ ++ # add the options ++ for i in range(numOpts): ++ err = PipAddOption(optList[i]) ++ if err: ++ return err ++ sOptTable[sNextOption - 1].format = formatList[i] ++ sOptTable[sNextOption - 1].defaultVal = defaultList[i] ++ ++ return 0 ++ ++ ++# Routine to parse the entries in command line after options have been ++# defined one way or another ++# ++def PipParseEntries(argv): ++ global sTakeStdIn, pipErrno ++ pipErrno = 0 ++ argc = len(argv) ++ ++ # Special case: no arguments and flag set to take stdin automatically ++ if (not argc and sTakeStdIn): ++ err = ReadParamFile(sys.stdin) ++ if err: ++ pipErrno = err ++ return None ++ else: ++ ++ # parse the arguments ++ for i in range(1,argc): ++ err = PipNextArg(argv[i]) ++ if (err < 0): ++ pipErrno = err ++ return None ++ if (err and i == argc - 1): ++ PipSetError("A value was expected but not found for" + \ ++ " the last option on the command line") ++ pipErrno = -1 ++ return None ++ ++ PipPrintEntries() ++ return PipNumberOfArgs() ++ ++ ++# High-level routine to initialize from autodoc with optional fallback options ++# Set exit string and output to stdout, print usage if not enough arguments ++# ++def PipReadOrParseOptions(argv, options, progName, minArgs, numInFiles, ++ numOutFiles): ++ global sExitPrefix ++ ++ # Startup with fallback ++ ierr = PipReadOptionFile(progName, 0, 0) ++ PipExitOnError(0, "ERROR: " + progName + " - ") ++ if (not ierr): ++ (numOptArgs, numNonOptArgs) = PipParseEntries(argv) ++ else: ++ errString = PipGetError() ++ if (not options or not len(options)): ++ PipSetError(errString) ++ if (errString): ++ sys.stdout.write("PIP WARNING: " + errString + \ ++ "\nUsing fallback options in main program\n\n") ++ ++ (numOptArgs, numNonOptArgs) = PipParseInput(argv, options) ++ ++ ++ # Output usage and exit if not enough arguments ++ exitSave = sExitPrefix ++ sExitPrefix = None ++ help = PipGetBoolean('help', 0) ++ sExitPrefix = exitSave ++ if (help or numOptArgs + numNonOptArgs < minArgs): ++ PipPrintHelp(progName, 0, numInFiles, numOutFiles) ++ sys.exit(0) ++ ++ if not ierr: ++ return (numOptArgs, numNonOptArgs) ++ ++ # If no autodoc found, open the master list of program defaults ++ try: ++ pipDir = os.getenv('IMOD_DIR') ++ if not pipDir: ++ return (numOptArgs, numNonOptArgs) ++ defFile = open(pipDir + PATH_SEPARATOR + DEFAULTS_DIR + PATH_SEPARATOR + ++ DEFAULTS_FILE, 'r') ++ ++ # Read lines, determine when enter and leave the program section, add lines ++ # to dictionary ++ progMatch = re.compile('\[\s*Program\s*=\s*' + progName + '\s*\]') ++ inProg = False ++ defDict = {} ++ while True: ++ line = defFile.readline() ++ if not line: ++ break ++ line = line.strip() ++ if progMatch.search(line): ++ if inProg: ++ break ++ inProg = True ++ elif inProg: ++ lsplit = line.split('=') ++ if len(lsplit) == 2: ++ defDict[lsplit[0].strip()] = lsplit[1].strip() ++ ++ defFile.close() ++ ++ # Look up each option in dictionary and assign default if found ++ for ind in range(sNumOptions): ++ if sOptTable[ind].longName in defDict: ++ sOptTable[ind].defaultVal = defDict[sOptTable[ind].longName] ++ ++ except IOError: ++ pass ++ ++ return (numOptArgs, numNonOptArgs) ++ ++ ++# Routine to get input/output file from parameter or non-option args ++# ++def PipGetInOutFile(option, nonOptArgNo): ++ global sOptTable, pipErrno ++ retval = PipGetString(option, '') ++ if not pipErrno: ++ return retval ++ if (nonOptArgNo >= sOptTable[sNonOptInd].count): ++ pipErrno = 1 ++ return None ++ return PipGetNonOptionArg(nonOptArgNo) ++ ++ ++# Read successive lines from a parameter file or standard input, and ++# store as options and values ++# ++def ReadParamFile(pFile): ++ global sNotFoundOK, sNumOptionArguments, sOptTable, sNonOptLines, tokenSep ++ global STANDARD_INPUT_STRING, STANDARD_INPUT_END, sNumOptions, sWarnOnComment ++ while (1): ++ ++ # If non-option lines are allowed, set flag that it is OK for ++ # LookupOption to not find the option, but only for the given number ++ # of lines at the start of the input ++ sNotFoundOK = not sNumOptionArguments and \ ++ (sOptTable[sNonOptInd].count < sNonOptLines) ++ (lineLen, lineStr, indst, badComment) = PipReadNextLine(pFile, '#', 0, 1) ++ if (lineLen == -3): ++ break ++ if (lineLen == -2): ++ PipSetError("Error reading parameter file or " + \ ++ STANDARD_INPUT_STRING) ++ return -1 ++ if badComment: ++ if sWarnOnComment: ++ sys.stdout.write("PIP WARNING: " + badComment) ++ else: ++ PipSetError(badComment) ++ return -1 ++ ++ # Find token ++ matchObj = re.search(tokenSep, lineStr[indst:]) ++ indnd = lineLen ++ if (matchObj): ++ indnd = matchObj.start() ++ token = lineStr[indst:indnd] ++ ++ # Done if it matches end of input string ++ if (token == STANDARD_INPUT_END) or (sDoneEnds and token == "DONE"): ++ break ++ ++ # Look up option ++ optNum = LookupOption(token, sNumOptions) ++ if (optNum < 0): ++ ++ # If no option, process special case if in-line non-options allowed ++ # or error out ++ if (sNotFoundOK): ++ err = AddValueString(sNonOptInd, lineStr[indst:]) ++ if err: ++ return err ++ continue ++ else: ++ return optNum ++ ++ if (sOptTable[optNum].type == "PF"): ++ PipSetError("Trying to open a parameter file while reading a " + ++ "parameter file or " + STANDARD_INPUT_STRING) ++ return -1 ++ ++ # Find first non-white space, passing over at most one equals sign ++ indst = indnd + 1 ++ gotEquals = 0 ++ while (indst < lineLen): ++ if (lineStr[indst] == '='): ++ if (gotEquals): ++ PipSetError("Two = signs in input line: " + lineStr) ++ return -1 ++ gotEquals = 1 ++ ++ elif (lineStr[indst] != ' ' and lineStr[indst] != '\t'): ++ break ++ indst += 1 ++ ++ # If there is a string, get one; if not, get a "1" for boolean, ++ # otherwise it is an error ++ if (indst < lineLen): ++ token = lineStr[indst:] ++ elif (sOptTable[optNum].type == 'B'): ++ token = "1" ++ else: ++ PipSetError("Missing a value on the input line: " + lineStr) ++ return -1 ++ ++ # Add the token as a value string and increment argument number ++ err = AddValueString(optNum, token) ++ if err: ++ return err ++ sNumOptionArguments += 1 ++ ++ sNotFoundOK = 0 ++ return 0 ++ ++ ++# Reads a line from the file [pFile], stripping white space at the end of the ++# line and in-line comments starting with [comment] if [inLineComments] is ++# non-zero. Discards the line and reads another if it is blank or if the ++# first non-blank character is [comment], unless [keepComments] is nonzero. ++# Returns a tuple of: the length of the line, or -3 for end of ++# file, or -2 for error reading file; the line; and the index of the first ++# non-white space character ++# ++def PipReadNextLine(pFile, comment, keepComments, inLineComments): ++ global nonWhite, sForbidCommentLong, sForbidCommentShort ++ ++ while (1): ++ badComment = "" ++ try: ++ lineStr = pFile.readline() ++ lineLen = len(lineStr) ++ if not lineLen: ++ return (-3, '', 0, '') ++ except: ++ return (-2, '', 0, '') ++ ++ # Get first non-white space ++ matchObj = re.search(nonWhite, lineStr) ++ if (not matchObj): ++ continue ++ indst = matchObj.start() ++ ++ # If it is a comment, skip or strip line ending and return ++ if (lineStr[indst] == comment): ++ if (keepComments): ++ lineStr = lineStr.rstrip() ++ lineLen = len(lineStr) ++ break ++ else: ++ continue ++ ++ # adjust line length to remove comment, if we have in-line comments ++ if inLineComments: ++ strPtr = lineStr.find(comment) ++ if strPtr >= 0: ++ lineLen = strPtr ++ ++ # Look for forbidden in-line comments ++ if sForbidCommentLong or sForbidCommentShort: ++ lsplit = lineStr.split() ++ option = lsplit[0].lstrip('-') ++ if (sForbidCommentLong and sForbidCommentLong.startswith(option)) or \ ++ (sForbidCommentShort and sForbidCommentShort.startswith(option)): ++ badComment = 'The ' + comment + ' character should not be used for' + \ ++ ' a comment or any other reason on the line: ' + lineStr ++ ++ # adjust line length back further to remove white space and newline ++ lineStr = lineStr[0:lineLen].rstrip() ++ lineLen = len(lineStr) ++ ++ # Return if something is on line or we are keeping comments ++ if (indst < lineLen or keepComments): ++ break ++ ++ return (lineLen, lineStr, indst, badComment) ++ ++ ++ ++# Parse a line of values for an option and return them into an array ++# ++def OptionLineOfValues(option, valType, numToGet): ++ global pipErrno ++ ++ # Get string and save pointer to it for error messages ++ strPtr = GetNextValueString(option) ++ if pipErrno and pipErrno != 2: ++ return None ++ saveErrno = pipErrno ++ retval = PipGetLineOfValues(option, strPtr, valType, numToGet) ++ if not pipErrno: ++ pipErrno = saveErrno ++ return retval ++ ++ ++# Parses a line of values from the string in [strPtr] and returns them as an ++# array. The type is indicated in ++# [valType] as PIP_INTEGER (1) for integer or PIP_FLOAT (2) for float. ++# The number of values to get is set in [numToGet], where a value of zero ++# indicates all values should be returned, in which case the number gotten is ++# returned in [numToGet]. The return value is -1 for errors in parsing or ++# too few values on the line. ++# NOTE THAT DEFAULTS CANNOT BE ALLOWED UNLESS AN ARRAY CAN BE SUPPLIED ++# ++def PipGetLineOfValues(option, strPtr, valType, numToGet): ++ global valueSep, sAllowDefaults, PIP_INTEGER, PIP_FLOAT ++ global pipErrno ++ pipErrno = 0 ++ fullStr = strPtr ++ array = [] ++ numGot = 0 ++ gotComma = 0 ++ ++ while (len(strPtr)): ++ matchObj = re.search(valueSep, strPtr) ++ if (not matchObj): ++ ++ # no object means read a number to end of string ++ endPtr = len(strPtr) ++ elif (matchObj.start() == 0): ++ ++ # separator at start means advance by one byte and continue ++ # if defaults allowed and a specific number are expected, ++ # / means stop processing and mark all values as received ++ if (strPtr[0] == '/'): ++ if (sAllowDefaults and numToGet): ++ numGot = numToGet ++ break ++ ++ sTempStr = "Default entry with a / is not allowed in value entry" +\ ++ ": "+ option + " " + fullStr ++ PipSetError(sTempStr) ++ pipErrno = -1 ++ return None ++ ++ # special handling of commas to allow default values ++ if (strPtr[0] == ','): ++ ++ # If already have a comma, skip an array value if defaults ++ # allowed ++ if (gotComma): ++ if (sAllowDefaults and numToGet): ++ numGot += 1 ++ if (numGot >= numToGet): ++ break ++ else: ++ sTempStr = "Default entries with commas are not allowed " +\ ++ "in value entry: " + option + " " + fullStr ++ PipSetError(sTempStr) ++ pipErrno = -1 ++ return None ++ gotComma = 1 ++ ++ strPtr = strPtr[1:] ++ continue ++ ++ else: ++ # otherwise, this should be the end index for the conversion ++ endPtr = matchObj.start() ++ ++ ++ # convert number in a try block ++ try: ++ if (valType == PIP_INTEGER): ++ array.append(int(strPtr[0:endPtr])) ++ else: ++ array.append(float(strPtr[0:endPtr])) ++ numGot += 1 ++ except: ++ sTempStr = "Illegal character in value entry: " + \ ++ option + " " + fullStr ++ PipSetError(sTempStr) ++ pipErrno = -1 ++ return None ++ ++ # Mark that there is no comma after we have a number ++ gotComma = 0 ++ ++ # Done if at end of line, or if count is fulfilled ++ if (endPtr == len(strPtr) or (numToGet and numGot >= numToGet)): ++ break ++ ++ # Otherwise advance to separator and continue ++ strPtr = strPtr[endPtr:] ++ ++ ++ # If not enough values found, return error ++ if (numToGet > 0 and numGot < numToGet): ++ sTempStr = str(numToGet) + " values expected but only " + str(numGot) + \ ++ " values found in value entry: " + option + " " + fullStr ++ PipSetError(sTempStr) ++ pipErrno = -1 ++ return None ++ ++ return array ++ ++ ++# Get a pointer to the value string for the given option. ++# Return < 0 if the option is invalid, 1 if the option was not entered, or 2 if it was ++# not entered and there is a default being returned ++# If the option allows multiple values, advance the multiple counter ++# ++def GetNextValueString(option): ++ global sOptTable, sNonOptInd, pipErrno ++ pipErrno = 0 ++ err = LookupOption(option, sNonOptInd + 1) ++ if (err < 0): ++ pipErrno = err ++ return None ++ optp = sOptTable[err] ++ if (not optp.count): ++ if optp.defaultVal: ++ pipErrno = 2 ++ return optp.defaultVal ++ pipErrno = 1 ++ return None ++ ++ index = 0 ++ if (optp.multiple): ++ index = optp.multiple - 1 ++ if (optp.multiple and optp.multiple < optp.count): ++ optp.multiple += 1 ++ return optp.values[index] ++ ++ ++# Add a string to the set of values for an option whose index is optInd ++# ++def AddValueString(optInd, strPtr): ++ global sOptTable, pipErrno ++ optp = sOptTable[optInd] ++ ++ # Add the index of the next non-option arg and the index of a linked option if ++ # one is defined to the array for these ++ if optp.linked: ++ optp.nextLinked.append(sOptTable[sNonOptInd].count) ++ ind = 0 ++ if sLinkedOption: ++ err = LookupOption(sLinkedOption, sNumOptions) ++ if (err < 0): ++ pipErrno = err ++ return None ++ ind = sOptTable[err].count ++ optp.nextLinked.append(ind) ++ ++ # If we accept multiple values or have none yet, append; ++ # otherwise set first element ++ if optp.multiple or not optp.count: ++ optp.values.append(strPtr) ++ optp.count += 1 ++ else: ++ optp.values[0] = strPtr ++ optp.count = 1 ++ return 0 ++ ++ ++# Lookup an option in the table, up to the range in maxLookup ++# ++def LookupOption(option, maxLookup): ++ global sOptTable, LOOKUP_NOT_FOUND, LOOKUP_AMBIGUOUS, sNotFoundOK, sNoAbbrevs ++ lenopt = len(option) ++ found = LOOKUP_NOT_FOUND ++ ++ # Look at all of the options specified by maxLookup ++ for i in range(maxLookup): ++ sname = sOptTable[i].shortName ++ lname = sOptTable[i].longName ++ lenShort = sOptTable[i].lenShort ++ starts = PipStartsWith(sname, option) ++ ++ # First test for single letter short name match - if it passes, skip ambiguity test ++ if lenopt == 1 and starts and lenShort == 1: ++ found = i; ++ break ++ ++ if (starts and (not sNoAbbrevs or lenopt == lenShort)) or \ ++ (PipStartsWith(lname, option) and (not sNoAbbrevs or lenopt == len(lname))): ++ ++ # If it is found, it's an error if one has already been found ++ if (found == LOOKUP_NOT_FOUND): ++ found = i ++ else: ++ if not sTestAbbrevForUsage: ++ sTempStr = "An option specified by \"" + option + \ ++ "\" is ambiguous between option " + sname + " - " + \ ++ lname + " and option " + sOptTable[found].shortName + \ ++ " - " + sOptTable[found].longName ++ PipSetError(sTempStr) ++ return LOOKUP_AMBIGUOUS ++ ++ # Set error string unless flag set that non-options are OK ++ if (found == LOOKUP_NOT_FOUND and not sNotFoundOK): ++ sTempStr = "Illegal option: " + option ++ PipSetError(sTempStr) ++ return found ++ ++ ++# Test for whether str1 starts with str2, returns false if either is empty ++# ++def PipStartsWith(str1, str2): ++ if (not str1 or str1 == "" or not str2 or str2 == ""): ++ return False ++ return str1.startswith(str2) ++ ++ ++# Determines whether the line contains the token for an option inside the ++# opening and closing delimiters and returns 1 if it does, or -1 if it is ++# another token ++# ++def LineIsOptionToken(line): ++ ++ # It is not a token unless it starts with open delim and contains close ++ if (not PipStartsWith(line, OPEN_DELIM) or line.find(CLOSE_DELIM) < 0): ++ return 0 ++ ++ # It must then contain "Field" right after delim to be an option ++ openlen = len(OPEN_DELIM) ++ if (PipStartsWith(line[openlen:], "Field")): ++ return 1 ++ if (PipStartsWith(line[openlen:], "SectionHeader")): ++ return 2 ++ ++ return -1 ++ ++ ++# ++# Checks for whether a keyword occurs at the beginning of the line and ++# is followed by the keyword-value delimiter, and if so returns the ++# value string and the supplied index number, otherwise blank string and 0. ++# If quoteOK is non-zero, it sees if the string starts with a quote character in ++# sQuoteTypes, strips that, and returns the index in the third element ++# ++def CheckKeyword(line, keyword, index, quoteOK = 0): ++ global sValueDelim ++ lineLen = len(line) ++ ++ # First make sure line starts with it ++ if (not PipStartsWith(line, keyword)): ++ return ('', 0, -1) ++ ++ # Now look for delimiter ++ valStart = line.find(sValueDelim) ++ if (valStart < 0): ++ return ('', 0, -1) ++ ++ # Eat spaces after the delimiter and return if nothing left ++ # In other words, a key with no value is the same as having no key at all ++ valStart += len(sValueDelim) ++ while (valStart < lineLen and (line[valStart] == ' ' or ++ line[valStart] == '\t')): ++ valStart += 1 ++ if (valStart >= lineLen): ++ return ('', 0, -1) ++ ++ # Look for quote if directed to ++ indQuote = -1 ++ if quoteOK and line[valStart] in sQuoteTypes: ++ indQuote = sQuoteTypes.find(line[valStart]) ++ valStart += 1 ++ ++ return (line[valStart:], index, indQuote) +Binary files IMOD/pysrc/.pip.py.swp and IMOD_rename_pip/pysrc/.pip.py.swp differ +diff -ruN IMOD/pysrc/rawtiltcoords IMOD_rename_pip/pysrc/rawtiltcoords +--- IMOD/pysrc/rawtiltcoords 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/rawtiltcoords 2023-11-06 16:49:35.218638971 +0100 +@@ -27,7 +27,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + from tomocoords import * + +diff -ruN IMOD/pysrc/restrictalign IMOD_rename_pip/pysrc/restrictalign +--- IMOD/pysrc/restrictalign 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/restrictalign 2023-11-06 16:49:35.219638996 +0100 +@@ -356,7 +356,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + + # Fallbacks from ../manpages/autodoc2man 3 1 restrictalign +diff -ruN IMOD/pysrc/runraptor IMOD_rename_pip/pysrc/runraptor +--- IMOD/pysrc/runraptor 2022-02-24 19:04:20.000000000 +0100 ++++ IMOD_rename_pip/pysrc/runraptor 2023-11-06 16:49:35.219638996 +0100 +@@ -25,7 +25,7 @@ + # + # load IMOD Libraries + from pysed import * +-from pip import exitError, setExitPrefix ++from PIP import exitError, setExitPrefix + setExitPrefix(prefix) + + if os.getenv('RAPTOR_BIN'): +diff -ruN IMOD/pysrc/serieswatcher IMOD_rename_pip/pysrc/serieswatcher +--- IMOD/pysrc/serieswatcher 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/serieswatcher 2023-11-06 16:49:35.220639021 +0100 +@@ -678,7 +678,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + from comchanger import * + from prochunks import * +diff -ruN IMOD/pysrc/setupcombine IMOD_rename_pip/pysrc/setupcombine +--- IMOD/pysrc/setupcombine 2022-02-24 19:04:11.000000000 +0100 ++++ IMOD_rename_pip/pysrc/setupcombine 2023-11-06 16:49:35.220639021 +0100 +@@ -204,7 +204,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + from comchanger import * + +diff -ruN IMOD/pysrc/setupstitch IMOD_rename_pip/pysrc/setupstitch +--- IMOD/pysrc/setupstitch 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/setupstitch 2023-11-06 16:49:35.220639021 +0100 +@@ -45,7 +45,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from supermont import * + + setSMErrorPrefix(prefix) +diff -ruN IMOD/pysrc/sirtsetup IMOD_rename_pip/pysrc/sirtsetup +--- IMOD/pysrc/sirtsetup 2022-02-24 19:04:38.000000000 +0100 ++++ IMOD_rename_pip/pysrc/sirtsetup 2023-11-06 16:49:35.221639046 +0100 +@@ -84,7 +84,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + + +diff -ruN IMOD/pysrc/sorttiltframes IMOD_rename_pip/pysrc/sorttiltframes +--- IMOD/pysrc/sorttiltframes 2022-02-24 19:04:20.000000000 +0100 ++++ IMOD_rename_pip/pysrc/sorttiltframes 2023-11-06 16:49:35.221639046 +0100 +@@ -23,7 +23,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + # Fallbacks from ../manpages/autodoc2man 3 1 sorttiltframes + options = ["input:InputFile:FNM:", "listin:ListOfInputFiles:FN:", +diff -ruN IMOD/pysrc/splitbatch IMOD_rename_pip/pysrc/splitbatch +--- IMOD/pysrc/splitbatch 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/splitbatch 2023-11-06 16:49:35.221639046 +0100 +@@ -26,7 +26,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + options = ['comfile:CommandFile:FN:Command file for running Batchruntomo (required)', + 'maxgpu:MaxGPUsForOneJob:I:Maximum # of GPUs that one batch run would use ' + \ +diff -ruN IMOD/pysrc/splitblend IMOD_rename_pip/pysrc/splitblend +--- IMOD/pysrc/splitblend 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/splitblend 2023-11-06 16:49:35.221639046 +0100 +@@ -26,7 +26,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + + # Fallbacks from ../manpages/autodoc2man 3 1 splitblend +diff -ruN IMOD/pysrc/splitcombine IMOD_rename_pip/pysrc/splitcombine +--- IMOD/pysrc/splitcombine 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/splitcombine 2023-11-06 16:49:35.221639046 +0100 +@@ -29,7 +29,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + + # Fallbacks from ../manpages/autodoc2man 3 1 splitcombine +diff -ruN IMOD/pysrc/splitcorrection IMOD_rename_pip/pysrc/splitcorrection +--- IMOD/pysrc/splitcorrection 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/splitcorrection 2023-11-06 16:49:35.221639046 +0100 +@@ -26,7 +26,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + + boundExt = 'cbound' +diff -ruN IMOD/pysrc/splittilt IMOD_rename_pip/pysrc/splittilt +--- IMOD/pysrc/splittilt 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/splittilt 2023-11-06 16:49:35.221639046 +0100 +@@ -32,7 +32,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + + +diff -ruN IMOD/pysrc/squeezevol IMOD_rename_pip/pysrc/squeezevol +--- IMOD/pysrc/squeezevol 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/squeezevol 2023-11-06 16:49:35.222639070 +0100 +@@ -24,7 +24,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + # Initializations + factor = 1.6 +diff -ruN IMOD/pysrc/startprocess IMOD_rename_pip/pysrc/startprocess +--- IMOD/pysrc/startprocess 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/startprocess 2023-11-06 16:49:35.222639070 +0100 +@@ -23,7 +23,7 @@ + + # + # load IMOD Libraries +-from pip import exitError, setExitPrefix ++from PIP import exitError, setExitPrefix + + setExitPrefix(prefix) + +diff -ruN IMOD/pysrc/subm IMOD_rename_pip/pysrc/subm +--- IMOD/pysrc/subm 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/subm 2023-11-06 16:49:35.222639070 +0100 +@@ -23,7 +23,7 @@ + + # + # load IMOD Libraries +-from pip import exitError, setExitPrefix ++from PIP import exitError, setExitPrefix + setExitPrefix(prefix) + args = ['submfg'] + if 'win32' in sys.platform: +diff -ruN IMOD/pysrc/submfg IMOD_rename_pip/pysrc/submfg +--- IMOD/pysrc/submfg 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/submfg 2023-11-06 16:49:35.222639070 +0100 +@@ -23,7 +23,7 @@ + + # + # load IMOD Libraries +-from pip import exitError, setExitPrefix, expandArgList ++from PIP import exitError, setExitPrefix, expandArgList + setExitPrefix(prefix) + + comtmp = 'submtemp.' + str(os.getpid()) +diff -ruN IMOD/pysrc/subtomosetup IMOD_rename_pip/pysrc/subtomosetup +--- IMOD/pysrc/subtomosetup 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/subtomosetup 2023-11-06 16:49:35.222639070 +0100 +@@ -45,7 +45,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + from tomocoords import * + +diff -ruN IMOD/pysrc/subtractcurves IMOD_rename_pip/pysrc/subtractcurves +--- IMOD/pysrc/subtractcurves 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/subtractcurves 2023-11-06 16:49:35.222639070 +0100 +@@ -42,7 +42,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + # Fallbacks from ../manpages/autodoc2man 3 1 subtractcurves + options = ["pos:PositiveInputFile:FN:", "neg:NegativeInputFile:FN:", +diff -ruN IMOD/pysrc/swaptomostacks IMOD_rename_pip/pysrc/swaptomostacks +--- IMOD/pysrc/swaptomostacks 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/swaptomostacks 2023-11-06 16:49:35.222639070 +0100 +@@ -47,7 +47,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + # Fallbacks from ../manpages/autodoc2man 3 1 swaptomostacks + options = ["from:FromRootname:CH:", "to:ToRootname:CH:", "root:SetRootname:CH:", +diff -ruN IMOD/pysrc/tiltmatch.py IMOD_rename_pip/pysrc/tiltmatch.py +--- IMOD/pysrc/tiltmatch.py 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/tiltmatch.py 2023-11-06 16:49:35.223639095 +0100 +@@ -7,7 +7,7 @@ + # + + import os, math, glob +-from pip import * ++from PIP import * + from imodpy import * + + # Filter for tiltxcorr +diff -ruN IMOD/pysrc/tomocleanup IMOD_rename_pip/pysrc/tomocleanup +--- IMOD/pysrc/tomocleanup 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/tomocleanup 2023-11-06 16:49:35.223639095 +0100 +@@ -40,7 +40,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + # Fallbacks from ../manpages/autodoc2man 3 1 tomocleanup + options = ["dir:Directory:FNM:", "aligned:KeepAlignedStack:B:", +diff -ruN IMOD/pysrc/tomocoords.py IMOD_rename_pip/pysrc/tomocoords.py +--- IMOD/pysrc/tomocoords.py 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/tomocoords.py 2023-11-06 16:49:35.223639095 +0100 +@@ -9,7 +9,7 @@ + yzRatioCrit = 2. + + import os, sys, math +-from pip import * ++from PIP import * + from imodpy import * + + # Do initial option startup and get the options that are common between the programs +diff -ruN IMOD/pysrc/tomodataplots IMOD_rename_pip/pysrc/tomodataplots +--- IMOD/pysrc/tomodataplots 2023-08-25 12:38:55.000000000 +0200 ++++ IMOD_rename_pip/pysrc/tomodataplots 2023-11-06 16:49:35.223639095 +0100 +@@ -71,7 +71,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + tempFile = '' + defaultColors = ['1,navy', '2,maroon', '3,darkgreen'] +diff -ruN IMOD/pysrc/tomosnapshot IMOD_rename_pip/pysrc/tomosnapshot +--- IMOD/pysrc/tomosnapshot 2022-02-24 19:07:09.000000000 +0100 ++++ IMOD_rename_pip/pysrc/tomosnapshot 2023-11-06 16:49:35.224639120 +0100 +@@ -241,7 +241,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + # Startup + unameFile = 'uname.out' +diff -ruN IMOD/pysrc/tomostitch IMOD_rename_pip/pysrc/tomostitch +--- IMOD/pysrc/tomostitch 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/tomostitch 2023-11-06 16:49:35.224639120 +0100 +@@ -99,7 +99,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from supermont import * + + setSMErrorPrefix(prefix) +diff -ruN IMOD/pysrc/transferfid IMOD_rename_pip/pysrc/transferfid +--- IMOD/pysrc/transferfid 2022-02-24 19:04:11.000000000 +0100 ++++ IMOD_rename_pip/pysrc/transferfid 2023-11-06 16:49:35.224639120 +0100 +@@ -102,7 +102,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + from pysed import * + from tiltmatch import * + +diff -ruN IMOD/pysrc/trimvol IMOD_rename_pip/pysrc/trimvol +--- IMOD/pysrc/trimvol 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/trimvol 2023-11-06 16:49:35.225639144 +0100 +@@ -23,7 +23,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + # Initializations + adjust = '-ori' +diff -ruN IMOD/pysrc/xfalign IMOD_rename_pip/pysrc/xfalign +--- IMOD/pysrc/xfalign 2022-02-24 18:22:55.000000000 +0100 ++++ IMOD_rename_pip/pysrc/xfalign 2023-11-06 16:49:35.225639144 +0100 +@@ -113,7 +113,7 @@ + + # + # load IMOD Libraries +-from pip import * ++from PIP import * + + # Initializations + tmpdir = imodTempDir()