diff --git a/Makefile.am b/Makefile.am index 786112a0..17a98902 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,7 +13,9 @@ noinst_HEADERS = \ mmveri.h \ mmvstr.h \ mmword.h \ - mmwtex.h + mmwtex.h \ + mmhtbl.h \ + mmwsts.h metamath_SOURCES = \ metamath.c \ @@ -30,6 +32,8 @@ metamath_SOURCES = \ mmvstr.c \ mmword.c \ mmwtex.c \ + mmhtbl.c \ + mmwsts.c \ $(noinst_HEADERS) diff --git a/metamath.c b/metamath.c index 87c5e758..4113b36f 100644 --- a/metamath.c +++ b/metamath.c @@ -1,6430 +1,6483 @@ -/*****************************************************************************/ -/* Program name: metamath */ -/* Copyright (C) 2021 NORMAN MEGILL nm at alum.mit.edu http://metamath.org */ -/* License terms: GNU General Public License Version 2 or any later version */ -/*****************************************************************************/ -/*34567890123456 (79-character line to adjust editor window) 2345678901234567*/ - -/* Copyright notice: All code in this program that was written by Norman - Megill is public domain. However, the project includes code contributions - from other people which may be GPL licensed. For more details see: - https://github.com/metamath/metamath-exe/issues/7#issuecomment-675555069 */ - -/* The overall functionality of the modules is as follows: - metamath.c - Contains main(); executes or calls commands - mmcmdl.c - Command line interpreter - mmcmds.c - Extends metamath.c command() to execute SHOW and other - commands; added after command() became too bloated (still is:) - mmdata.c - Defines global data structures and manipulates arrays - with functions similar to BASIC string functions; - memory management; converts between proof formats - mmhlpa.c - The help file, part 1. - mmhlpb.c - The help file, part 2. - mminou.c - Basic input and output interface - mmpars.c - Parses the source file - mmpfas.c - Proof Assistant - mmunif.c - Unification algorithm for Proof Assistant - mmveri.c - Proof verifier for source file - mmvstr.c - BASIC-like string functions - mmwtex.c - LaTeX/HTML source generation - mmword.c - File revision utility (for TOOLS> UPDATE) (not generally useful) -*/ - -/* Compilation instructions (gcc on Unix/Linus/Cygwin, lcc on Windows): - 1. Make sure each .c file above is present in the compilation directory and - that each .c file (except metamath.c) has its corresponding .h file - present. - 2. In the directory where these files are present, type: - gcc m*.c -o metamath - 3. For full error checking, use: - gcc m*.c -o metamath -O2 -Wall -Wextra -Wmissing-prototypes \ - -Wmissing-declarations -Wshadow -Wpointer-arith -Wcast-align \ - -Wredundant-decls -Wnested-externs -Winline -Wno-long-long \ - -Wconversion -Wstrict-prototypes -std=c99 -pedantic -Wunused-result - Note: gcc 4.9.2 (on Debian) fails with "unknown type name `ssize_t'" if - -std=c99 is used, so omit -std=c99 to work around this problem. - 4. For faster runtime, use these gcc options: - gcc m*.c -o metamath -O3 -funroll-loops -finline-functions \ - -fomit-frame-pointer -Wall -std=c99 -pedantic -fno-strict-overflow - 5. The Windows version in the download was compiled with lcc-win32 version 3.8: - lc -O m*.c -o metamath.exe - 6. On Linux, if you have autoconf, automake, and a C compiler, you - can compile with the command "autoreconf -i && ./configure && make". - See the README.TXT file for more information. -*/ - - - -#define MVERSION "0.199.pre 7-Aug-2021" -/* 0.199.pre - 30-Dec-2021 mc metamath.c mmdata.c mminou.c mmmaci.c - - Remove mmmaci and everything related to THINK_C compiler - 4-Jan-2022 mc - change VERIFY MARKUP /TOP_DATE_SKIP and /FILE_SKIP to - /TOP_DATE_CHECK and /FILE_CHECK (with opposite meaning), and make the - skip behavior the default. */ -/* 0.198 nm 7-Aug-2021 mmpars.c - Fix cosmetic bug in WRITE SOURCE ... /REWRAP - that prevented end of sentence (e.g. period) from appearing in column 79, - thus causing some lines to be shorter than necessary. */ -/* 0.197 nm 2-Aug-2021 mmpars.c - put two spaces between $c,v on same line - in /rewrap; mmwtex.c mmhlpa.c mminou.c - minor edits */ -/* 0.196 nm 31-Dec-2020 metamath.c mmpars.c - fix bug that deleted comments - that were followed by ${, $}, $c, $v, $d on the same line */ -/* 0.195 nm 30-Dec-2020 metamath.c - temporarily disable /REWRAP until bug fixed - 27-Sep-2020 nm mmwtex.c - prevent "htmlexturl" links from wrapping */ -/* 0.194 26-Dec-2020 nm mmwtex.c - add keyword "htmlexturl" to $t - statement in .mm file */ -/* 0.193 12-Sep-2020 nm mmcmds.c mmdata.c,h mmwtex.c,h mmhlpa.c - make the - output of /EXTRACT stable in the sense that, with the same - parameter, extract(extract(file)) = extract(file) except that the date - stamp at the top will be updated. (The first extraction even if "*" will - usually be different because it discards non-relevant content. Note that - the include file directives "$( $[ Begin..." etc. and comments with "$j" are - currently discarded.) */ -/* 0.192 4-Sep-2020 nm metamath.c - fix bug */ -/* 0.191 4-Sep-2020 nm metamath.c - add comment close */ -/* 0.190 4-Sep-2020 nm mmcmds.c - fix bug in writeExtractedSource() */ -/* 0.189 4-Sep-2020 nm mmhlpa.c - add help for WRITE SOURCE .. /EXTRACT ... - 24-Aug-2020 nm metamath.c mmcmdl.c mmcmds.c,h mmdata.c,h mmhlpa.c - mmpars.c mmpfas.c mmunif.c mmwtex.c,h - Added - WRITE SOURCE ... /EXTRACT ... */ -/* 0.188 23-Aug-2020 nm mmwtex.c, mmhlpa.c Added CONCLUSION FACT INTRODUCTION - PARAGRAPH SCOLIA SCOLION SUBSECTION TABLE to [bib] keywords */ -/* 0.187 15-Aug-2020 nm All m*.c, m*.h - put "g_" in front of all global - variable names e.g. "statements" becomes "g_statements"; also capitalized - 1st letter of original name in case of global structs e.g. "statement" - becomes "g_Statement". - 9-Aug-2020 nm mmcmdl.c, mmhlpa.c - add HELP BIBLIOGRAPHY */ -/* 0.186 8-Aug-2020 nm mmwtex.c, mmhlpa.c - add CONJECTURE, RESULT to [bib] - keywords - 8-Aug-2020 nm mmpfas.c, metamath.c - print message when IMPROVE or - MINIMIZE_WITH uses another mathbox */ -/* 0.185 5-Aug-2020 nm metamath.c mmcmdl.c mmhlpb.c mmpfas.c,h mmcmds.c - mmwtex.c,h - add /INCLUDE_MATHBOXES to to IMPROVE; notify user upon ASSIGN - from another mathbox. - 18-Jul-2020 nm mmcmds.c, mmdata.c, mmhlpb.c, metamath.c - "PROVE =" will now - resume the previous MM-PA session if there was one; allow "~" to start/end - with blank (meaning first/last statement); add "@1234" */ -/* 0.184 17-Jul-2020 nm metamath.c mmcmdl.c mmcmds.c,h mmhlpb.c mmwtex.c,h - - add checking for mathbox independence to VERIFY MARKUP; add /MATHBOX_SKIP - 4-Jul-2020 nm mmwtex.c - correct error msg for missing althtmldef - 3-Jul-2020 nm metamath.c, mmhlpa.c - allow space in TOOLS> BREAK */ -/* 0.183 30-Jun-2020 30-Jun-2020 nm mmpars.c - refine prevention of - WRITE SOURCE.../REWRAP from modifying comments containing "" - (specifically, remove indentation alignment). - 25-Jun-2020 nm metamath.c, mmcmds.c,h mmcmdl.c mmhlpb.c - add underscore - checking in VERIFY MARKUP and add /UNDERSCORE_SKIP qualifier; also check - for trailing space on lines. - 20-Jun-2020 nm mmcmds.c - check for discouragement tags in *ALT, *OLD - labels in VERIFY MARKUP. - 19-Jun-2020 nm mminou.c,h, metamath.c, mmwtex.c - dynamically allocate - buffer in print2() using vsnprintf() to calculate size needed - 18-Jun-2020 nm mmpars.c - remove error check for $e <- $f assignments. See - https://groups.google.com/d/msg/metamath/Cx_d84uorf8/0FrNYTM9BAAJ */ -/* 0.182 12-Apr-2020 nm mmwtex.c, mmphlpa.c - add "Claim" to bib ref types */ -/* 0.181 12-Feb-2020 nm (reported by David Starner) metamath.c - fix bug causing - new axioms to be used by MINIMIZE_WITH */ -/* 0.180 10-Dec-2019 nm (bj 13-Sep-2019) mmpars.c - fix "line 0" in error msg - when label clashes with math symbol - 8-Dec-2019 nm (bj 13-Oct-2019) mmhlpa.c - improve TOOLS> HELP INSERT, DELETE - 8-Dec-2019 nm (bj 19-Sep-2019) mminou.c - change bug 1511 to error message - 30-Nov-2019 nm (bj 12-Oct-2019) mmwtex.c - trigger Most Recent link on - mmtheorems.html when there is a mathbox statement (currently set.mm and - iset.mm). - 30-Nov-2019 nm (bj 13-Sep-2019) mmhlpa.c - improve help for TOOLS> DELETE and - SUBSTITUTE. - 30-Nov-2019 nm (bj 13-Sep-2019) mmwtex.c - change "g_htmlHome" in warnings to - "htmlhome". */ -/* 0.179 29-Nov-2019 nm (bj 22-Sep-2019) metamath.c - MINIMIZE_WITH axiom trace - now starts from current NEW_PROOF instead of SAVEd proof. - 23-Nov-2019 nm (bj 4-Oct-2019) metamath.c - make sure traceback flags are - cleared after MINIMIZE_WITH - 20-Nov-2019 nm mmhlpa.c - add url pointer to HELP WRITE SOURCE /SPLIT - 18-Nov-2019 nm mmhlpa.c - clarify HELP WRITE SOURCE /REWRAP - 15-Oct-2019 nm mmdata.c - add bug check info for user - 14-Oct-2019 nm mmcmds.c - use '|->' (not 'e.') as syntax hint for maps-to - 14-Oct-2019 nm mmwtex.c - remove extraneous */ -/* 0.178 10-Aug-2019 nm mminou.c - eliminate redundant fopen in fSafeOpen - 6-Aug-2019 nm mmwtex.c,h, mmcmds.c - Add error check for >1 line - section name or missing closing decoration line in getSectionHeadings() - 4-Aug-2019 nm mmhlpb.c, mmcmdl.c, metamath.c - Add /ALLOW_NEW_AXIOMS, - renamed /ALLOW_GROWTH to /MAY_GROW - 17-Jul-2019 nm mmcmdl.c, mmhlpa.c, metamath.c - Add /NO_VERSIONING to - WRITE THEOREM_LIST - 17-Jul-2019 nm metamath.c - Change line of dashes between SHOW STATEMENT - output from hardcoded 79 to current g_screenWidth */ -/* 0.177 27-Apr-2019 nm mmcmds.c -"set" -> "setvar" in htmlAllowedSubst. - mmhlpb.c - fix typos in HELP IMPROVE. */ -/* 0.176 25-Mar-2019 nm metamath.c mmcmds.h mmcmds.c mmcmdl.c mmhlpb.c - - add /TOP_DATE_SKIP to VERIFY MARKUP */ -/* 0.175 8-Mar-2019 nm mmvstr.c - eliminate warning in gcc 8.3 (patch - provided by David Starner) */ -/* 0.174 22-Feb-2019 nm mmwtex.c - fix erroneous warning when using "[[" - bracket escape in comment */ -/* 0.173 3-Feb-2019 nm mmwtex.c - fix infinite loop when "[" was the first - character in a comment */ -/* 0.172 25-Jan-2019 nm mmwtex.c - comment out bug 2343 trap (not a bug) */ -/* 0.171 13-Dec-2018 nm metamath.c, mmcmdl.c, mmhlpa.c, mmcmds.c,h, mmwtex.c,h - - add fine-grained qualfiers to MARKUP command */ -/* 0.170 12-Dec-2018 nm mmwtex.c - restore line accidentally deleted in 0.169 */ -/* 0.169 10-Dec-2018 nm metamath.c, mmcmds.c,h, mmcmdl.c, mmpars.c, mmhlpa.c, - mmwtex.c - Add MARKUP command. - 9-Dec-2018 nm mmwtex.c - escape literal "[" with "[[" in comments. */ -/* 0.168 8-Dec-2018 nm metamath.c - validate that /NO_REPEATED_STEPS is used - only with /LEMMON. - 8-Dec-2018 nm mmcmds.c - fix bug #256 reported by Jim Kingdon - (https://github.com/metamath/set.mm/issues/497). */ -/* 0.167 13-Nov-2018 nm mmcmds.c - SHOW TRACE_BACK .../COUNT now uses proof - the way it's stored (previously, it always uncompressed the proof). The - new step count (for compressed proofs) corresponds to the step count the - user would see on the web pages. - 12-Nov-2018 nm mmcmds.c - added unlimited precision arithmetic - for SHOW TRACE_BACK .../COUNT/ESSENTIAL */ -/* 0.166 31-Oct-2018 nm mmwtex.c - workaround Chrome anchor bug - 30-Oct-2018 nm mmcmds.c - put "This theorem is referenced by" after - axioms and definitions used in HTML; use "(None)" instead of suppressing - line if nothing is referenced */ -/* 0.165 20-Oct-2018 nm mmwtex.c - added ~ mmtheorems#abc type anchor - in TOC details. mmwtex.c - fix bug (reported by Benoit Jubin) that - changes "_" in labels to subscript. mmcmdl.c - remove unused COMPLETE - qualifier from SHOW PROOF. mmwtex.c - enhance special cases of web page - spacing identified by Benoit Jubin */ -/* 0.164 5-Sep-2018 nm mmwtex.c, mmhlpb.c - added NOTE to bib keywords - 14-Aug-2018 nm metamath.c - added defaultScrollMode to prevent - SET SCROLL CONTINUOUS from reverting to PROMPTED after a SUBMIT command */ -/* 0.163 4-Aug-2018 nm mmwtex.c - removed 2nd "sandbox:bighdr" anchor - in mmtheorems.html; removed Firefox and IE references; changed breadcrumb - font to be consistent with other pages; put asterisk next to TOC entries - that have associated comments */ -/* FOR FUTURE REFERENCE: search for "Thierry" in mmwtex.c to modify the link - to tirix.org structured proof site */ -/* 0.162-thierry 3-Jun-2018 nm mmwtex.c - add link to tirix.org structured - proofs */ -/* 0.162 3-Jun-2018 nm mmpars.c - re-enabled error check for $c not in - outermost scope. mmhlpa.c mmhlpb.c- improve some help messages. - mmwtex.c - added "OBSERVATION", "PROOF", AND "STATEMENT" keywords for - WRITE BIBLIOGRAPHY */ -/* 0.161 2-Feb-2018 nm mmpars.c,h mmcmds.c mmwtex.c - fix wrong file name - and line number in error messages */ -/* 0.160 24-Jan-2018 nm mmpars.c - fix bug introduced in version 0.158 */ -/* 0.159 23-Jan-2018 nm mmpars.c - fix crash due to missing include file */ -/* 0.158 22-Jan-2018 nm mminou.c - strip CRs from Windows SUBMIT files - run on Linux */ -/* 0.157 15-Jan-2018 nm Major rewrite of READ-related functions. - Added HELP MARKUP. - 9-Jan-2018 nm Track line numbers for error messages in included files - 1-Jan-2018 nm Changed HOME_DIRECTORY to ROOT_DIRECTORY - 31-Dec-2017 nm metamath.c mmcmdl.c,h mmpars.c,h mmcmds.c,h mminou.c,h - mmwtex.c mmhlpb.c mmdata.h - add virtual includes "$( Begin $[...$] $)", - $( End $[...$] $)", "$( Skip $[...$] $)" */ -/* 0.156 8-Dec-2017 nm mmwtex.c - fix bug that incorrectly gave "verify markup" - errors when there was a mathbox statement without an "extended" section */ -/* 0.155 8-Oct-2017 nm mmcmdl.c - restore accidentally removed HELP HTML; - mmhlpb.c mmwtex.c mmwtex.h,c mmcmds.c metamath.c - improve HELP and make - other cosmetic changes per Benoit Jubin's suggestions */ -/* 0.154 2-Oct-2017 nm mmunif.h,c mmcmds.c - add 2 more variables to ERASE; - metamath.c mmcmdl.c - remove obsolete OPEN/CLOSE HTML; mmhlpa.c mmhlpb.c - - fix typos reported by Benoit Jubin */ -/* 0.153 1-Oct-2017 nm mmunif.c,h mmcmds.c - Re-initialize internal nmbrStrings - in unify() after 'erase' command reported by Benoit Jubin */ -/* 0.152 26-Sep-2017 nm mmcmds.c - change default links from mpegif to mpeuni; - metamath.c - enforce minimum screen width = 3 to prevent crash reported - by Benoit Jubin */ -/* 0.151 20-Sep-2017 nm mmwtex.c - better matching to insert space between - A and y in "E. x e. ran A y R x" to prevent spurious spaces in thms rncoeq, - dfiun3g as reported by Benoit Jubin */ -/* 0.150 26-Aug-2017 nm mmcmds.c,mmwtex.h - fix hyperlink for Distinct variable - etc. lists so that it will point to mmset.html on other Explorers like NF. - Move the "Dummy variables..." to print after the "Proof of Theorem..." - line. */ -/* 0.149 21-Aug-2017 nm mmwtex.c,h mmcmds.c mmhlpb.c - add a subsubsection - "tiny" header with separator "-.-." to table of contents and theorem list; - see HELP WRITE THEOREM_LIST - 21-Aug-2017 nm mmcmds.c - remove bug check 255 - 19-Aug-2017 nm mmcmds.c - change mmset.html links to - ../mpeuni/mmset.html so they will work in NF Explorer etc. */ -/* 0.148 14-Aug-2017 nm mmcmds.c - hyperlink "Dummy variable(s)" */ -/* 0.147 13-Aug-2017 nm mmcmds.c,h - add "Dummy variable x is distinct from all - other variables." to proof web page */ -/* 0.146 26-Jun-2017 nm mmwtex.c - fix handling of local labels in - 'show proof.../tex' (bug 2341 reported by Eric Parfitt) */ -/* 0.145 16-Jun-2017 nm metamath.c mmpars.c - fix bug 1741 during - MINIMIZE_WITH; mmpfas.c - make duplicate bug numbers unique; mmhlpa.c - mmhlpb.c - adjust to prevent lcc compiler "Function too big for the - optimizer" - 29-May-2017 nm mmwtex.c mmhlpa.c - take out extraneous ... - markup tags in HTML output so w3c validator will pass */ -/* 0.144 15-May-2017 nm metamath.c mmcmds.c - add "(Revised by..." tag for - conversion of legacy .mm's if there is a 2nd date under the proof */ -/* 0.143 14-May-2017 nm metamath.c mmdata.c,h mmcmdl.c mmcmds.c mmhlpb.c - - added SET CONTRIBUTOR; for missing "(Contributed by..." use date - below proof if it exists, otherwise use today's date, in order to update - old .mm files. - 14-May-2017 Ari Ferrera - mmcmds.c - fix memory leaks in ERASE */ -/* 0.142 12-May-2017 nm metamath.c mmdata.c,h mmcmds.c - added - "#define DATE_BELOW_PROOF" in mmdata.h that if uncommented, will enable - use of the (soon-to-be obsolete) date below the proof - 4-May-2017 Ari Ferrera - mmcmds.c metamath.c mmdata.c mmcmdl.c - mminou.c mminou.h mmcmdl.h mmdata.h - fixed memory leaks and warnings - found by valgrind. - 3-May-2017 nm - metamath.c mmdata.c,h mmcmds.c,h mmpars.c,h mmhlpb.c - mmcmdl.c mmwtex.c - added xxChanged flags to statement structure so - that any part of the source can be changed; removed /CLEAN qualifier - of WRITE SOURCE; automatically put "(Contributed by ?who?..." during - SAVE NEW_PROOF or SAVE PROOF when it is missing; more VERIFY MARKUP - checking. */ -/* 0.141 2-May-2017 nm mmdata.c, metamath.c, mmcmds.c, mmhlpb.c - use - getContrib() date for WRITE RECENT instead of date below proof. This lets - us list recent $a's as well as $p's. Also, add caching to getContrib() for - speedup. */ -/* 0.140 1-May-2017 nm mmwtex.c, mmcmds.c, metamath.c - fix some LaTeX issues - reported by Ari Ferrera */ -/* 0.139 2-Jan-2017 nm metamath.c - print only one line for - 'save proof * /compressed/fast' */ -/* 0.138 26-Dec-2016 nm mmwtex.c - remove extraneous causing w3c - validation failure; put space after 1st x in "F/ x x = x"; - mmcmds.c - added checking for lines > 79 chars in VERIFY MARKUP; - mmcmds.c, mmcmdl.c, metamath.c, mmhlpb.c, mmcmds.h - added /VERBOSE to - VERIFY MARKUP */ -/* 0.137 20-Dec-2016 nm mmcmds.c - check ax-XXX $a vs axXXX $p label convention - in 'verify markup' - 18-Dec-2016 nm mmwtex.c, mmpars.c, mmdata.h - use true "header area" - between successive $a/$p for getSectionHeadings() mmcmds.c - add - header comment checking - 13-Dec-2016 nm mmdata.c,h - enhanced compareDates() to treat empty string as - older date. - 13-Dec-2016 nm metamath.c, mmcmds.c - moved mm* and Microsoft illegal file - name label check to verifyMarkup() (the VERIFY MARKUP command) instead of - checking on READ; added check of set.mm Version date to verifyMarkup(). - 13-Dec-2016 nm mmwtex.c,h - don't treat bracketed description text with - space as a bib label; add labelMatch parameter to writeBibliography() */ -/* 0.136 10-Oct-2016 mminou.c - fix resource leak bug reported by David - Binderman */ -/* 0.135 11-Sep-2016, 14-Sep-2016 metamath.c, mmpfas.c,h, mmdata.c,h, - mmpars.c,h mmcmds.c, mmcmdl.c, mmhlpb.c - added EXPAND command */ -/* 0.134 16-Aug-2016 mmwtex.c - added breadcrumbs to theorem pages; - metamath.c, mmcmdl.c, mmhlpb.c, mminou.c,.h - added /TIME to SAVE PROOF, - SHOW STATEMENT.../[ALT}HTML, MINIMIZE_WITH */ -/* 0.133 13-Aug-2016 mmwtex.c - improve mobile display with tag - mmpars.c - use updated Macintosh information */ -/* 0.132 10-Jul-2016 metamath.c, mmcmdl.c, mmcmds.c,.h, mmdata.c,.h, mmhlpb.c, - mmpfas.c - change "restricted" to "discouraged" to match set.mm markup - tags; add SET DISCOURAGEMENT OFF|ON (default ON) to turn off blocking for - convenience of advanced users - 6-Jul-2016 metamath.c - add "(void)" in front of "system(...)" to - suppress -Wunused-result warning */ -/* 0.131 10-Jun-2016 mminou.c - reverted change of 22-May-2016 because - 'minimize_with' depends on error message in string to prevent DV violations. - Todo: write a DV-checking routine for 'minimize_with', then revert - the 22-May-2016 fix for bug 126 (which only occurs when writing web - pages for .mm file with errors). - 9-Jun-2016 mmcmdl.c, metamath.c - added _EXIT_PA for use with - scripts that will give an error message outside of MM-PA> rather - than exiting metamath */ -/* 0.130 25-May-2016 mmpars.c - workaround clang warning about j = j; - mmvstr.c - workaround gcc -Wstrict-overflow warning */ -/* 0.129 24-May-2016 mmdata.c - fix bug 1393 */ -/* 0.128 22-May-2016 mminou.c - fixed error message going to html page - instead of to screen, triggering bug 126. */ -/* 0.127 10-May-2016 metamath.c, mmcmdl.c, mmhlpb.c - added /OVERRIDE to - PROVE */ -/* 0.126 3-May-2016 metamath.c, mmdata.h, mmdata.c, mmcmds.h, mmcmds.c, - mmcmdl.c, mmhlpb.c, mmpars.c - added getMarkupFlag() in mmdata.c; - Added /OVERRIDE added to ASSIGN, REPLACE, IMPROVE, MINIMIZE_WITH, - SAVE NEW_PROOF; PROVE gives warning about SAVE NEW_PROOF for locked - proof. Added SHOW RESTRICTED command. - 3-May-2016 m*.c - fix numerous conversion warnings provided by gcc 5.3.0 */ -/* 0.125 10-Mar-2016 mmpars.c - fixed bug parsing /EXPLICIT/PACKED format - 8-Mar-2016 nm mmdata.c - added "#nnn" to SHOW STATEMENT etc. to reference - statement number e.g. SHOW STATEMENT #58 shows a1i in set.mm. - 7-Mar-2016 nm mmwtex.c - added space between } and { in HTML output - 6-Mar-2016 nm mmpars.c - disabled wrapping of formula lines in - WRITE SOURCE.../REWRAP - 2-Mar-2016 nm metamat.c, mmcmdl.c, mmhlpb.c - added /FAST to - SAVE PROOF, SHOW PROOF */ -/* 0.123 25-Jan-2016 nm mmpars.c, mmdata.h, mmdata.c, mmpfas.c, mmcmds., - metamath.c, mmcmdl.c, mmwtex.c - unlocked SHOW PROOF.../PACKED, - added SHOW PROOF.../EXPLICIT */ -/* 0.122 14-Jan-2016 nm metamath.c, mmcmds.c, mmwtex.c, mmwtex.h - surrounded - math HTML output with "...; added htmlcss and - htmlfont $t commands - 10-Jan-2016 nm mmwtex.c - delete duplicate -4px style; metamath.c - - add   after char on mmascii.html - 3-Jan-2016 nm mmwtex.c - fix bug when doing SHOW STATEMENT * /ALT_HTML after - VERIFY MARKUP */ -/* 0.121 17-Nov-2015 nm metamath.c, mmcmdl.h, mmcmdl.c, mmcmds.h, mmcmds.c, - mmwtex.h, mmwtex.c, mmdata.h, mmdata.c - - 1. Moved WRITE BIBLIOGRAPHY code from metamath.c to its own function in - mmwtex.c; moved qsortStringCmp() from metamath.c to mmdata.c - 2. Added $t, comment markup, and bibliography checking to VERIFY MARKUP - 3. Added options to bug() bug-check interception to select aborting, - stepping to next bug, or ignoring subsequent bugs - 4. SHOW STATEMENT can now use both /HTML and /ALT_HTML in same session - 5. Added /HTML, /ALT_HTML to WRITE THEOREM_LIST and - WRITE RECENT_ADDITIONS */ -/* 0.120 7-Nov-2015 nm metamath.c, mmcmdl.c, mmpars.c - add VERIFY MARKUP - 4-Nov-2015 nm metamath.c, mmcmds.c/h, mmdata.c/h - move getDescription, - getSourceIndentation from mmcmds.c to mmdata.c. - metamath.c, mmdata.c - add and call parseDate() instead of in-line - code; add getContrib(), getProofDate(), buildDate(), compareDates(). */ -/* 0.119 18-Oct-2015 nm mmwtex.c - add summary TOC to Theorem List; improve - math symbol GIF image alignment - 2-Oct-2015 nm metamath.c, mmpfas.c, mmwtex.c - fix miscellaneous small - bugs or quirks */ -/* 0.118 18-Jul-2015 nm metamath.c, mmcmds.h, mmcmds.c, mmcmdl.c, mmhlpb.h, - mmhlpb.c - added /TO qualifier to SHOW TRACE_BACK. See - HELP SHOW TRACE_BACK. */ -/* 0.117 30-May-2015 - 1. nm mmwtex.c - move of Theorem List pages */ -/* 0.115 8-May-2015 nm mmwtex.c - added section header comments to - WRITE THEOREM_LIST and broke out Table of Contents page - 24-Apr-2015 nm metamath.c - add # bytes to end of "---Clip out the proof"; - reverted to no blank lines there (see 0.113 item 3) */ -/* 0.114 22-Apr-2015 nm mmcmds.c - put [-1], [-2],... offsets on 'show - new_proof/unknown' */ -/* 0.113 19-Apr-2015 so, nm metamath.c, mmdata.c - 1. SHOW LABEL % will show statements with changed proofs - 2. SHOW LABEL = will show the statement being proved in MM-PA - 3. Added blank lines before, after "---------Clip out the proof" proof - 4. Generate date only if the proof is complete */ -/* 0.112 15-Apr-2015 nm metamath.c - fix bug 1121 (reported by S. O'Rear); - mwtex.c - add "img { margin-bottom: -4px }" to CSS to align symbol GIFs; - mwtex.c - remove some hard coding for set.mm, for use with new nf.mm; - metamath.c - fix comment parsing in WRITE BIBLIOGRAPHY to ignore - math symbols */ -/* 0.111 22-Nov-2014 nm metamath.c, mmcmds.c, mmcmdl.c, mmhlpb.c - added - /NO_NEW_AXIOMS_FROM qualifier to MINIMIZE_WITH; see HELP MINIMIZE_WITH. - 21-Nov-2014 Stepan O'Rear mmdata.c, mmhlpb.c - added ~ label range specifier - to wildcards; see HELP SEARCH */ -/* 0.110 2-Nov-2014 nm mmcmds.c - fixed bug 1114 (reported by Stefan O'Rear); - metamath.c, mmhlpb.c - added "SHOW STATEMENT =" to show the statement - being proved in MM-PA (based on patch submitted by Stefan O'Rear) */ -/* 0.109 20-Aug-2014 nm mmwtex.c - fix corrupted HTML caused by misinterpreting - math symbols as comment markup (math symbols with _ [ ] or ~). Also, - allow https:// as well as http:// in ~ label markup. - 11-Jul-2014 wl mmdata.c - fix obscure crash in debugging mode db9 */ -/* 0.108 25-Jun-2014 nm - (1) metamath.c, mmcmdl.c, mmhlpb.c - MINIMIZE_WITH now checks the size - of the compressed proof, prevents $d violations, and tries forward and - reverse statment scanning order; /NO_DISTINCT, /BRIEF, /REVERSE - qualifiers were removed. - (2) mminou.c - prevent hard breaks (in the middle of a word) in too-long - lines (e.g. long URLs) in WRITE SOURCE .../REWRAP; just overflow the - screen width instead. - (3) mmpfas.c - fixed memory leak in replaceStatement() - (4) mmpfas.c - suppress inf. growth with MINIMIZE_WITH idi/ALLOW_GROWTH */ -/* 0.107 21-Jun-2014 nm metamath.c, mmcmdl.c, mmhlpb.c - added /SIZE qualifier - to SHOW PROOF; added SHOW ELAPSED_TIME; mmwtex.c - reformatted WRITE - THEOREM_LIST output; now "$(", newline, "######" starts a "part" */ -/* 0.106 30-Mar-2014 nm mmwtex.c - fix bug introduced by 0.105 that disabled - hyperlinks on literature refs in HTML comment. metamath.c - improve - messages */ -/* 0.105 15-Feb-2014 nm mmwtex.c - prevented illegal LaTeX output for certain - special characters in comments. */ -/* 0.104 14-Feb-2014 nm mmwtex.c - fixed bug 2312, mmcmds.c - enhanced ASSIGN - error message. */ -/* 0.103 4-Jan-2014 nm mmcmds.c,h - added "Allowed substitution hints" below - the "Distinct variable groups" list on generated web pages - mmwtex.c - added "*" to indicate DV's occur in Statement List entries. */ -/* 0.102 2-Jan-2014 nm mminou.c - made compressed proof line wrapping more - uniform at start of compressed part of proof */ -/* 0.101 27-Dec-2013 nm mmdata.h,c, mminou.c, mmcmdl.c, mmhlpb.c, mmvstr.c - - Improved storage efficiency of /COMPRESSED proofs (but with 20% slower run - time); added /OLD_COMPRESSION to specify old algorithm; removed end-of-line - space after label list in old algorithm; fixed linput() bug */ -/* 0.100 30-Nov-2013 nm mmpfas.c - reversed statement scan order in - proveFloating(), to speed up SHOW STATEMENT df-* /HTML; metamath.c - remove - the unknown date place holder in SAVE NEW_PROOF; Wolf Lammen mmvstr.c - - some cleanup */ -/* 0.07.99 1-Nov-2013 nm metamath.c, mmpfas.h,c, mmcmdl.h,c, mmhlpa.c, - mmhlpb.c - added UNDO, REDO, SET UNDO commands (see HELP UNDO) */ -/* 0.07.98 30-Oct-2013 Wolf Lammen mmvstr.c,h, mmiou.c, mmpars.c, - mmdata.c - improve code style and program structure */ -/* 0.07.97 20-Oct-2013 Wolf Lammen mmvstr.c,h, metamath.c - improved linput(); - nm mmcmds.c, mmdata.c - tolerate bad proofs in SHOW TRACE_BACK etc. */ -/* 0.07.96 20-Sep-2013 Wolf Lammen mmvstr.c - revised cat(); - nm mmwtex.c, mminou.c - change a print2 to printLongLine to fix bug 1150 */ -/* 0.07.95 18-Sep-2013 Wolf Lammen mmvstr.c - optimized cat(); - nm metamath.c, mmcmds.c, mmdata.c, mmpars.c, mmpfas.c, mmvstr.c, - mmwtex.c - suppress some clang warnings */ -/* 0.07.94 28-Aug-2013 Alexey Merkulov mmcmds.c, mmpars.c - fixed several - memory leaks found by valgrind --leak-check=full --show-possibly-lost=no */ -/* 0.07.93 8-Jul-2013 Wolf Lammen mmvstr.c - simplified let() function; - also many minor changes in m*.c and m*.h to assist future refactoring */ -/* 0.07.92 28-Jun-2013 nm metamath.c mmcmds.c,h mmcmdl.c mmhlpb.c- added - /NO_REPEATED_STEPS for /LEMMON mode of SHOW PROOF, SHOW NEW_PROOF. - This reverts the /LEMMON mode default display change of 31-Jan-2010 - and invokes it when desired via /NO_REPEATED_STEPS. */ -/* 0.07.91 20-May-2013 nm metamath.c mmpfas.c,h mmcmds.c,h mmcmdl.c - mmhlpb.c- added /FORBID qualifier to MINIMIZE_WITH */ -/* 0.07.90 19-May-2013 nm metamath.c mmcmds.c mmcmdl.c mmhlpb.c - added /MATCH - qualifier to SHOW TRACE_BACK */ -/* 0.07.88 18-Nov-2012 nm mmcmds.c - fixed bug 243 */ -/* 0.07.87 17-Nov-2012 nm mmwtex.c - fixed formatting problem when label - markup ends a comment in SHOW PROOF ... /HTML */ -/* 0.07.86 27-Oct-2012 nm mmcmds.c, mmwtex.c, mmwtex.h - fixed ERASE bug - caused by imperfect re-initialization; reported by Wolf Lammen */ -/* 0.07.85 10-Oct-2012 nm metamath.c, mmcmdl.c, mmwtex.c, mmwtex.h, mmhlpb.c - - added /SHOW_LEMMAS to WRITE THEOREM_LIST to bypass lemma math suppression */ -/* 0.07.84 9-Oct-2012 nm mmcmds.c - fixed bug in getStatementNum() */ -/* 0.07.83 19-Sep-2012 nm mmwtex.c - fixed bug reported by Wolf Lammen */ -/* 0.07.82 16-Sep-2012 nm metamath.c, mmpfas.c - fixed REPLACE infinite loop; - improved REPLACE message for shared dummy variables */ -/* 0.07.81 14-Sep-2012 nm metamath.c, mmcmds.c, mmcmds.h, mmcmdl.c, mmhlpb.c - - added FIRST, LAST, +nn, -nn where missing from ASSIGN, REPLACE, - IMPROVE, LET STEP. Wildcards are allowed for PROVE, ASSIGN, REPLACE - labels provided there is a unique match. */ -/* 0.07.80 4-Sep-2012 nm metamath.c, mmpfas.c, mmpfas.h, mmcmdl.c, mmhlpb.c - - added / 1, / 2, / 3, / SUBPROOFS to IMPROVE to specify search level */ -/* 0.07.79 31-Aug-2012 nm m*.c - clean up some gcc warnings */ -/* 0.07.78 28-Aug-2012 nm mmpfas.c - fix bug in 0.07.77. */ -/* 0.07.77 25-Aug-2012 nm metamath.c, mmpfas.c - Enhanced IMPROVE algorithm to - allow non-shared dummy variables in unknown steps */ -/* 0.07.76 22-Aug-2012 nm metamath.c, mmpfas.c, mmcmdl.c, mmhlpb.c - - Enhanced IMPROVE algorithm to also try REPLACE algorithm */ -/* 0.07.75 14-Aug-2012 nm metamath.c - MINIMIZE_WITH now checks current - mathbox (but not other mathboxes) even if /INCLUDE_MATHBOXES is omitted */ -/* 0.07.74 18-Mar-2012 nm mmwtex.c, mmcmds.c, metamath.c - improved texToken() - error message */ -/* 0.07.73 26-Dec-2011 nm mmwtex.c, mmpars.c - added ... in - comments for passing through raw HTML code into HTML files generated with - SHOw STATEMENT xxx / HTML */ -/* 0.07.72 25-Dec-2011 nm (obsolete) */ -/* 0.07.71 10-Nov-2011 nm metamath.c, mmcmdl.c - added /REV to MINIMIZE_WITH */ -/* 0.07.70 6-Aug-2011 nm mmwtex.c - fix handling of double quotes inside - of htmldef strings to match spec in Metamath book Appendix A p. 156 */ -/* 0.07.69 9-Jul-2011 nm mmpars.c, mmvstr.c - Untab file in WRITE SOURCE - ... /REWRAP */ -/* 0.07.68 3-Jul-2011 nm metamath.c, mminou.h, mminou.c - Nested SUBMIT calls - (SUBMIT calls inside of a SUBMIT command file) are now allowed. - Also, mmdata.c - fix memory leak. */ -/* 0.07.67 2-Jul-2011 nm metamath.c, mmcmdl.c, mmhlpa.c - Added TAG command - to TOOLS. See HELP TAG under TOOLS. (The old special-purpose TAG command - was renamed to UPDATE.) */ -/* 0.07.66 1-Jul-2011 nm metamath.c, mmcmds.c, mmpars.c, mmpars.h - Added code - to strip spurious "$( [?] $)" in WRITE SOURCE ... /CLEAN output */ -/* 0.07.65 30-Jun-2011 nm mmwtex.c - Prevent processing [...] bibliography - brackets inside of `...` math strings in comments. */ -/* 0.07.64 28-Jun-2011 nm metamath.c, mmcmdl.c - Added /INCLUDE_MATHBOXES - qualifier to MINIMIZE_WITH; without it, MINIMIZE_WITH * will skip - checking user mathboxes. */ -/* 0.07.63 26-Jun-2011 nm mmwtex.c - check that .gifs exist for htmldefs */ -/* 0.07.62 18-Jun-2011 nm mmpars.c - fixed bug where redeclaration of active - $v was not detected */ -/* 0.07.61 12-Jun-2011 nm mmpfas.c, mmcmds.c, metamath.c, mmhlpb.c - added - /FORMAT and /REWRAP qualifiers to WRITE SOURCE to format according to set.mm - conventions - set HELP WRITE SOURCE */ -/* 0.07.60 7-Jun-2011 nm mmpfas.c - fixed bug 1805 which occurred when doing - MINIMIZE_WITH weq/ALLOW_GROWTH after DELETE DELETE FLOATING_HYPOTHESES */ -/* 0.07.59 11-Dec-2010 nm mmpfas.c - increased default SET SEARCH_LIMIT from - 10000 to 25000 to accomodate df-plig web page in set.mm */ -/* 0.07.58 9-Dec-2010 nm mmpars.c - detect if same symbol is used with both - $c and $v, in order to conform with Metamath spec */ -/* 0.07.57 19-Oct-2010 nm mmpars.c - fix bug causing incorrect line count - for error messages when non-ASCII character was found; mminou.h - - increase SET WIDTH maximum from 999 to 9999 */ -/* 0.07.56 27-Sep-2010 nm mmpars.c, mmpfas.c - check for $a's with - one token e.g. "$a wff $."; if found, turn SET EMPTY_SUBSTITUTION ON - automatically. (Suggested by Mel O'Cat; patent pending.) */ -/* 0.07.55 26-Sep-2010 nm mmunif.c, mmcmds.c, mmunif.h - check for mismatched - brackets in all $a's, so that if there are any, the bracket matching - algorithm (for fewer ambiguous unifications) in mmunif.c will be turned - off. */ -/* 0.07.54 25-Sep-2010 nm mmpars.c - added $f checking to conform to the - current Metamath spec, so footnote 2 on p. 92 of Metamath book is - no longer applicable. */ -/* 0.07.53 24-Sep-2010 nm mmveri.c - fixed bug(2106), reported by Michal - Burger */ -/* 0.07.52 14-Sep-2010 nm metamath.c, mmwtex.h, mmwtex.c, mmcmds.c, - mmcmdl.c, mmhlpb.c - rewrote the LaTeX output for easier hand-editing - and embedding in LaTeX documents. The old LaTeX output is still - available with /OLD_TEX on OPEN TEX, SHOW STATEMENT, and SHOW PROOF, - but it is obsolete and will be deleted eventually if no one objects. The - new /TEX output also replaces the old /SIMPLE_TEX, which was removed. */ -/* 0.07.51 9-Sep-2010 Stefan Allen mmwtex.c - put hyperlinks on hypothesis - label references in SHOW STATEMENT * /HTML, ALT_HTML output */ -/* 0.07.50 21-Feb-2010 nm mminou.c - "./metamath < empty", where "empty" is a - 0-byte file, now exits metamath instead of producing an infinite loop. - Also, ^D now exits metamath. Reported by Cai Yufei */ -/* 0.07.49 31-Jan-2010 nm mmcmds.c - Lemmon-style proofs (SHOW PROOF xxx - /LEMON/RENUMBER) no longer have steps with dummy labels; instead, steps - are now the same as in HTML page proofs. (There is a line to comment - out if you want to revert to old behavior.) */ -/* 0.07.48 11-Sep-2009 nm mmpars.c, mm, mmvstr.c, mmdata.c - Added detection of - non-whitespace around keywords (mmpars.c); small changes to eliminate - warnings in gcc 3.4.4 (mmvstr.c, mmdata.c) */ -/* 0.07.47 2-Aug-2009 nm mmwtex.c, mmwtex.h - added user name to mathbox - pages */ -/* 0.07.46 24-Jul-2009 nm metamath.c, mmwtex.c - changed name of sandbox - to "mathbox" */ -/* 0.07.45 15-Jun-2009 nm metamath.c, mmhlpb.c - put "!" before each line of - SET ECHO ON output to make them easy to identity for creating scripts */ -/* 0.07.44 12-May-2009 Stefan Allan, nm metamath.c, mmcmdl.c, mmwtex.c - - added SHOW STATEMENT / MNEMONICS - see HELP SHOW STATEMENT */ -/* 0.07.43 29-Aug-2008 nm mmwtex.c - workaround for Unicode huge font bug in - FireFox 3 */ -/* 0.07.42 8-Aug-2008 nm metamath.c - added sandbox, Hilbert Space colors to - Definition List */ -/* 0.07.41 29-Jul-2008 nm metamath.c, mmwtex.h, mmwtex.c - Added handling of - sandbox section of Metamath Proof Explorer web pages */ -/* 0.07.40 6-Jul-2008 nm metamath.c, mmcmdl.c, mmhlpa.c, mmhlpb.c - Added - / NO_VERSIONING qualifier for SHOW STATEMENT, so website can be regenerated - in place with less temporary space required. Also, the wildcard trigger - for mmdefinitions.html, etc. is more flexible (see HELP HTML). */ -/* 0.07.39 21-May-2008 nm metamath.c, mmhlpb.c - Added wildcard handling to - statement label in SHOW TRACE_BACK. All wildcards now allow - comma-separated lists [i.e. matchesList() instead of matches()] */ -/* 0.07.38 26-Apr-2008 nm metamath.c, mmdata.h, mmdata.c, mmvstr.c, mmhlpb.c - - Enhanced / EXCEPT qualifier for MINIMIZE_WITH to handle comma-separated - wildcard list. */ -/* 0.07.37 14-Apr-2008 nm metamath.c, mmcmdl.c, mmhlpb.c - Added / JOIN - qualifier to SEARCH. */ -/* 0.07.36 7-Jan-2008 nm metamath.c, mmcmdl.c, mmhlpb.c - Added wildcard - handling for labels in SHOW USAGE. */ -/* 0.07.35 2-Jan-2008 nm mmcmdl.c, metamath.c, mmhlpb.c - Changed keywords - COMPACT to PACKED and COLUMN to START_COLUMN so that SAVE/SHOW proof can use - C to abbreviate COMPRESSED. (PACKED format is supported but "unofficial," - used mainly for debugging purposes, and is not listed in HELP SAVE - PROOF.) */ -/* 0.07.34 19-Nov-2007 nm mmwtex.c, mminou.c - Added tooltips to proof step - hyperlinks in SHOW STATEMENT.../HTML,ALT_HTML output (suggested by Reinder - Verlinde) */ -/* 0.07.33 19-Jul-2007 nm mminou.c, mmvstr.c, mmdata.c, mmword.c - added fflush - after each printf() call for proper behavior inside emacs (suggested by - Frederic Line) */ -/* 0.07.32 29-Apr-2007 nm mminou.c - fSafeOpen now stops at gap; e.g. if ~2 - doesn't exist, ~1 will be renamed to ~2, but any ~3, etc. are not touched */ -/* 0.07.31 5-Apr-2007 nm mmwtex.c - Don't make "_" in hyperlink a subscript */ -/* 0.07.30 8-Feb-2007 nm mmcmds.c, mmwtex.c Added HTML statement number info to - SHOW STATEMENT.../FULL; friendlier "Contents+1" link in mmtheorems*.html */ -/* 0.07.29 6-Feb-2007 Jason Orendorff mmpfas.c - Patch to eliminate the - duplicate "Exceeded trial limit at step n" messages */ -/* 0.07.28 22-Dec-2006 nm mmhlpb.c - Added info on quotes to HELP LET */ -/* 0.07.27 23-Oct-2006 nm metamath.c, mminou.c, mmhlpa.c, mmhlpb.c - Added - / SILENT qualifier to SUBMIT command */ -/* 0.07.26 12-Oct-2006 nm mminou.c - Fixed bug when SUBMIT file was missing - a new-line at end of file (reported by Marnix Klooster) */ -/* 0.07.25 10-Oct-2006 nm metamath.c - Fixed bug invoking TOOLS as a ./metamath - command-line argument */ -/* 0.07.24 25-Sep-2006 nm mmcmdl.c Fixed bug in - SHOW NEW_PROOF/START_COLUMN nn/LEM */ -/* 0.07.23 31-Aug-2006 nm mmwtex.c - Added Home and Contents links to bottom of - WRITE THEOREM_LIST pages */ -/* 0.07.22 26-Aug-2006 nm metamath.c, mmcmdl.c, mmhlpb.c - Changed 'IMPROVE - STEP ' to 'IMPROVE ' for user convenience and to be consistent - with ASSIGN */ -/* 0.07.21 20-Aug-2006 nm mmwtex.c - Revised small colored numbers so that all - colors have the same grayscale brightness.. */ -/* 0.07.20 19-Aug-2006 nm mmpars.c - Made the error "Required hypotheses may - not be explicitly declared" in a compressed proof non-severe, so that we - can still SAVE the proof to reformat and recover it. */ -/* 0.07.19 11-Aug-06 nm mmcmds.c - "Distinct variable group(s)" is now - "group" or "groups" as appropriate. */ -/* 0.07.18 31-Jul-06 nm mmwtex.c - added table to contents to p.1 of output of - WRITE THEOREM_LIST command. */ -/* 0.07.17 4-Jun-06 nm mmpars.c - do not allow labels to match math symbols - (new spec proposed by O'Cat). mmwtex.c - made theorem name 1st in title, - for readability in Firefox tabs. */ -/* 0.07.16 16-Apr-06 nm metamath.c, mmcmdl.c, mmpfas.c, mmhlpb.c - allow step - to be negative (relative to end of proof) for ASSIGN, UNIFY, and LET STEP - (see their HELPs). Added INITIALIZE USER to delete LET STEP assignments - (see HELP INITIALIZE). Fixed bug in LET STEP (mmpfas.c). */ -/* 0.07.15 10-Apr-06 nm metamath.c, mmvstr.c - change dates from 2-digit to - 4-digit year; make compatible with older 2-digit year. */ -/* 0.07.14 21-Mar-06 nm mmpars.c - fix bug 1722 when compressed proof has - "Z" at beginning of proof instead of after a proof step. */ -/* 0.07.13 3-Feb-06 nm mmpfas.c - minor improvement to MINIMIZE_WITH */ -/* 0.07.12 30-Jan-06 nm metamath.c, mmcmds.c, mmdata.c, mmdata.h, mmhlpa.c, - mmhlpb.c - added "?" wildcard to match single character. See HELP SEARCH. */ -/* 0.07.11 7-Jan-06 nm metamath.c, mmcmdl.c, mmhlpb.c - added EXCEPT qualifier - to MINIMIZE_WITH */ -/* 0.07.10 28-Dec-05 nm metamath.c, mmcmds.c - cosmetic tweaks */ -/* 0.07.10 11-Dec-05 nm metamath.c, mmcmdl.c, mmhlpb.c - added ASSIGN FIRST - and IMPROVE FIRST commands. Also enhanced READ error message */ -/* 0.07.9 1-Dec-05 nm mmvstr.c - added comment on how to make portable */ -/* 0.07.9 18-Nov-05 nm metamath.c, mminou.c, mminou.h, mmcmdl.c, mmhlpb.c - - added SET HEIGHT command; changed SET SCREEN_WIDTH to SET WIDTH; changed - SET HENTY_FILTER to SET JEREMY_HENTY_FILTER (to make H for HEIGHT - unambiguous); added HELP for SET JEREMY_HENTY_FILTER */ -/* 0.07.8 15-Nov-05 nm mmunif.c - now detects wrong order in bracket matching - heuristic to further reduce ambiguous unifications in Proof Assistant */ -/* 0.07.7 12-Nov-05 nm mmunif.c - add "[","]" and "[_","]_" bracket matching - heuristic to reduce ambiguous unifications in Proof Assistant. - mmwtex.c - added heuristic for HTML spacing after "sum_" token. */ -/* 0.07.6 15-Oct-05 nm mmcmds.c,mmpars.c - fixed compressed proof algorithm - to match spec in book (with new algorithm due to Marnix Klooster). - Users are warned to convert proofs when the old compression is found. */ -/* 0.07.5 6-Oct-05 nm mmpars.c - fixed bug that reset "severe error in - proof" flag when a proof with severe error also had unknown steps */ -/* 0.07.4 1-Oct-05 nm mmcmds.c - ignored bug 235, which could happen for - non-standard logics */ -/* 0.07.3 17-Sep-05 nm mmpars.c - reinstated duplicate local label checking to - conform to strict spec */ -/* 0.07.2 19-Aug-05 nm mmwtex.c - suppressed math content for lemmas in - WRITE THEOREMS output */ -/* 0.07.1 28-Jul-05 nm Added SIMPLE_TEX qualifier to SHOW STATEMENT */ -/* 0.07: Official 0.07 22-Jun-05 corresponding to Metamath book */ -/* 0.07x: Fixed to work with AMD64 with 64-bit longs by - Waldek Hebisch; deleted unused stuff in mmdata.c */ -/* 0.07w: .mm date format like "$( [7-Sep-04] $)" is now - generated and permitted (old one is tolerated too for compatibility) */ -/* Metamath Proof Verifier - main program */ -/* See the book "Metamath" for description of Metamath and run instructions */ - -/*****************************************************************************/ - - -/*----------------------------------------------------------------------*/ - - -#include -#include -#include -#include -#include -#include -#include "mmvstr.h" -#include "mmdata.h" -#include "mmcmdl.h" -#include "mmcmds.h" -#include "mmhlpa.h" -#include "mmhlpb.h" -#include "mminou.h" -#include "mmpars.h" -#include "mmveri.h" -#include "mmpfas.h" -#include "mmunif.h" -#include "mmword.h" -#include "mmwtex.h" - -void command(int argc, char *argv[]); - -int main(int argc, char *argv[]) { - -/* argc is the number of arguments; argv points to an array containing them */ - - /****** If g_listMode is set to 1 here, the startup will be Text Tools - utilities, and Metamath will be disabled ***************************/ - /* (Historically, this mode was used for the creation of a stand-alone - "TOOLS>" utility for people not interested in Metamath. This utility - was named "LIST.EXE", "tools.exe", and "tools" on VMS, DOS, and Unix - platforms respectively. The UPDATE command of TOOLS (mmword.c) was - custom-written in accordance with the version control requirements of a - company that used it; it documents the differences between two versions - of a program as C-style comments embedded in the newer version.) */ - g_listMode = 0; /* Force Metamath mode as startup */ - - - g_toolsMode = g_listMode; - - if (!g_listMode) { - /*print2("Metamath - Version %s\n", MVERSION);*/ - print2("Metamath - Version %s%s", MVERSION, space(27 - (long)strlen(MVERSION))); - } - print2("Type HELP for help, EXIT to exit.\n"); - - /* Allocate big arrays */ - initBigArrays(); - - /* Set the default contributor */ - let(&g_contributorName, DEFAULT_CONTRIBUTOR); - - /* Process a command line until EXIT */ - command(argc, argv); - - /* Close logging command file */ - if (g_listMode && g_listFile_fp != NULL) { - fclose(g_listFile_fp); - } - - return 0; - -} - - - - -void command(int argc, char *argv[]) { - /* Command line user interface -- this is an infinite loop; it fetches and - processes a command; returns only if the command is 'EXIT' or 'QUIT' and - never returns otherwise. */ - long argsProcessed = 0; /* Number of argv initial command-line - arguments processed so far */ - - long /*c,*/ i, j, k, m, l, n, p, q, r, s /*,tokenNum*/; - long stmt, step; - int subType = 0; -#define SYNTAX 4 - vstring str1 = "", str2 = "", str3 = "", str4 = "", str5= ""; - nmbrString *nmbrTmpPtr; /* Pointer only; not allocated directly */ - nmbrString *nmbrTmp = NULL_NMBRSTRING; - nmbrString *nmbrSaveProof = NULL_NMBRSTRING; - /*pntrString *pntrTmpPtr;*/ /* Pointer only; not allocated directly */ - pntrString *pntrTmp = NULL_PNTRSTRING; - pntrString *expandedProof = NULL_PNTRSTRING; - flag tmpFlag; - - /* proofSavedFlag tells us there was at least one - SAVE NEW_PROOF during the MM-PA session while the UNDO stack wasn't - empty, meaning that "UNDO stack empty" is no longer a reliable indication - that the proof wasn't changed. It is cleared upon entering MM-PA, and - set by SAVE NEW_PROOF. */ - flag proofSavedFlag = 0; - - /* Variables for SHOW PROOF */ - flag pipFlag; /* Proof-in-progress flag */ - long outStatement; /* Statement for SHOW PROOF or SHOW NEW_PROOF */ - flag explicitTargets; /* For SAVE PROOF /EXPLICIT */ - long startStep; long endStep; - /* long startIndent; */ - long endIndent; /* Also for SHOW TRACE_BACK */ - flag essentialFlag; /* Also for SHOW TRACE_BACK */ - flag renumberFlag; /* Flag to use essential step numbering */ - flag unknownFlag; - flag notUnifiedFlag; - flag reverseFlag; - long detailStep; - flag noIndentFlag; /* Flag to use non-indented display */ - long splitColumn; /* Column at which formula starts in nonindented display */ - flag skipRepeatedSteps; /* NO_REPEATED_STEPS qualifier */ - flag texFlag; /* Flag for TeX */ - flag saveFlag; /* Flag to save in source */ - flag fastFlag; /* Flag for SAVE PROOF.../FAST */ - long indentation; /* Number of spaces to indent proof */ - vstring labelMatch = ""; /* SHOW PROOF ", - g_Statement[stmt].labelName, "", - str4, "", NULL), /* Description */ - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - - g_showStatement = stmt; /* For printTexComment */ - g_outputToString = 0; /* For printTexComment */ - g_texFilePtr = list2_fp; - printTexComment(str3, /* Sends result to g_texFilePtr */ - 0, /* 1 = htmlCenterFlag */ - PROCESS_EVERYTHING, /* actionBits */ - 1 /* 1 = fileCheck */ ); - g_texFilePtr = NULL; - g_outputToString = 1; /* Restore after printTexComment */ - - /* Get HTML hypotheses => assertion */ - let(&str4, ""); - str4 = getTexOrHtmlHypAndAssertion(stmt); - printLongLine(cat("" : - cat(" BGCOLOR=", PURPLISH_BIBLIO_COLOR, ">", NULL), - */ - - (stmt < g_extHtmlStmt) - ? ">" - : (stmt < g_mathboxStmt) - ? cat(" BGCOLOR=", PURPLISH_BIBLIO_COLOR, ">", - NULL) - : cat(" BGCOLOR=", SANDBOX_COLOR, ">", NULL), - - "", - str4, "", NULL), - - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - - g_outputToString = 0; - fprintf(list2_fp, "%s", g_printString); - let(&g_printString, ""); - - if (n >= i /*RECENT_COUNT*/) break; /* We're done */ - - /* Put separator row if not last theorem */ - g_outputToString = 1; - printLongLine(cat("", - " ", NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - - /* Put the previous, current, and next statement - labels in HTML comments so a script can use them to update - web site incrementally. This would be done by searching - for "For script" and gather label between = and --> then - regenerate just those statements. Previous and next labels - are included to prevent dead links if they don't exist yet. */ - /* This section can be deleted without side effects */ - /* Find the previous statement with a web page */ - j = 0; - for (q = stmt - 1; q >= 1; q--) { - if (g_Statement[q].type == (char)p_ || - g_Statement[q].type == (char)a_ ) { - j = q; - break; - } - } - /* 13-Dec-2018 nm This isn't used anywhere yet. But fix error - in current label and also identify previous, current, next */ - if (j) print2("\n", - g_Statement[j].labelName); - /* Current statement */ - print2("\n", - g_Statement[stmt].labelName); - /* Find the next statement with a web page */ - j = 0; - for (q = stmt + 1; q <= g_statements; q++) { - if (g_Statement[q].type == (char)p_ || - g_Statement[q].type == (char)a_ ) { - j = q; - break; - } - } - if (j) print2("\n", - g_Statement[j].labelName); - - g_outputToString = 0; - fprintf(list2_fp, "%s", g_printString); - let(&g_printString, ""); - - } - } /* Next stmt - statement number */ - /* Decrement date */ - if (k > 1) { - k--; /* Decrement day */ - } else { - k = 31; /* Non-existent day 31's will never match, which is OK */ - if (l > 1) { - l--; /* Decrement month */ - } else { - l = 12; /* Dec */ - m --; /* Decrement year */ - } - } - } /* next while - Scan next date */ - - - /* Discard the input file up to the special "" comment */ - while (1) { - if (!linput(list1_fp, NULL, &str1)) { - print2( -"?Error: Could not find \"\" line in input file \"%s\".\n", - g_fullArg[2]); - tmpFlag = 1; /* Error flag to recover input file */ - break; - } - if (!strcmp(str1, "")) { - fprintf(list2_fp, "%s\n", str1); - break; - } - } - if (tmpFlag) goto wrrecent_error; - - /* Transfer the rest of the input file */ - while (1) { - if (!linput(list1_fp, NULL, &str1)) { - break; - } - - /* Update the date stamp at the bottom of the HTML page. */ - /* This is just a nicety; no error check is done. */ - if (!strcmp("This page was last updated on ", left(str1, 30))) { - let(&str1, cat(left(str1, 30), date(), ".", NULL)); - } - - fprintf(list2_fp, "%s\n", str1); - } - - print2("The %ld most recent theorem(s) were written.\n", n); - - wrrecent_error: - fclose(list1_fp); - fclose(list2_fp); - if (tmpFlag) { - /* Recover input files in case of error */ - remove(g_fullArg[2]); /* Delete output file */ - rename(cat(g_fullArg[2], "~1", NULL), g_fullArg[2]); - /* Restore input file name */ - print2("?The file \"%s\" was not modified.\n", g_fullArg[2]); - } - continue; - } /* End of "WRITE RECENT_ADDITIONS" */ - - - if (cmdMatches("SHOW LABELS")) { - linearFlag = 0; - if (switchPos("/ LINEAR")) linearFlag = 1; - if (switchPos("/ ALL")) { - m = 1; /* Include $e, $f statements */ - print2( -"The labels that match are shown with statement number, label, and type.\n"); - } else { - m = 0; /* Show $a, $p only */ - print2( -"The assertions that match are shown with statement number, label, and type.\n"); - } - j = 0; - k = 0; - let(&str2, ""); /* Line so far */ -#define COL 20 /* Column width */ -#define MIN_SPACE 2 /* At least this many spaces between columns */ - for (i = 1; i <= g_statements; i++) { - if (!g_Statement[i].labelName[0]) continue; /* No label */ - if (!m && g_Statement[i].type != (char)p_ && - g_Statement[i].type != (char)a_) continue; /* No /ALL switch */ - if (!matchesList(g_Statement[i].labelName, g_fullArg[2], '*', '?')) { - continue; - } - - let(&str1, cat(str((double)i), " ", - g_Statement[i].labelName, " $", chr(g_Statement[i].type), - NULL)); - if (!str2[0]) { - j = 0; /* # of fields on line so far */ - } - k = ((long)strlen(str2) + MIN_SPACE > j * COL) - ? (long)strlen(str2) + MIN_SPACE : j * COL; - /* Position before new str1 starts */ - if (k + (long)strlen(str1) > g_screenWidth || linearFlag) { - if (j == 0) { - /* In case of huge label, force it out anyway */ - printLongLine(str1, "", " "); - } else { - /* Line width exceeded, postpone adding str1 */ - print2("%s\n", str2); - let(&str2, str1); - j = 1; - } - } else { - /* Add new field to line */ - if (j == 0) { - let(&str2, str1); /* Don't put space before 1st label on line */ - } else { - let(&str2, cat(str2, space(k - (long)strlen(str2)), str1, NULL)); - } - j++; - } - } /* next i */ - if (str2[0]) { - print2("%s\n", str2); - let(&str2, ""); - } - let(&str1, ""); - continue; - } - - if (cmdMatches("SHOW DISCOURAGED")) { - showDiscouraged(); - continue; - } - - if (cmdMatches("SHOW SOURCE")) { - /* Currently, SHOW SOURCE only handles one statement at a time, - so use getStatementNum(). Eventually, SHOW SOURCE may become - obsolete; I don't think anyone uses it. */ - s = getStatementNum(g_fullArg[2], - 1/*startStmt*/, - g_statements + 1 /*maxStmt*/, - 1/*aAllowed*/, - 1/*pAllowed*/, - 1/*eAllowed*/, - 1/*fAllowed*/, - 0/*efOnlyForMaxStmt*/, - 1/*uniqueFlag*/); - if (s == -1) { - continue; /* Error msg was provided */ - } - g_showStatement = s; /* Update for future defaults */ - - let(&str1, ""); - str1 = outputStatement(g_showStatement, /* cleanFlag */ - 0 /* reformatFlag */); - let(&str1,edit(str1,128)); /* Trim trailing spaces */ - if (str1[strlen(str1)-1] == '\n') let(&str1, left(str1, - (long)strlen(str1) - 1)); - printLongLine(str1, "", ""); - let(&str1,""); /* Deallocate vstring */ - continue; - } /* if (cmdMatches("SHOW SOURCE")) */ - - - if (cmdMatches("SHOW STATEMENT") && ( - switchPos("/ HTML") - || switchPos("/ BRIEF_HTML") - || switchPos("/ ALT_HTML") - || switchPos("/ BRIEF_ALT_HTML"))) { - /* Special processing for the / HTML qualifiers - for each matching - statement, a .html file is opened, the statement is output, - and depending on statement type a proof or other information - is output. */ - - noVersioning = (switchPos("/ NO_VERSIONING") != 0); - i = 5; /* # arguments with only / HTML or / ALT_HTML */ - if (noVersioning) i = i + 2; - if (switchPos("/ TIME")) i = i + 2; - if (g_rawArgs != i) { - printLongLine(cat("?The HTML qualifiers may not be combined with", - " others except / NO_VERSIONING and / TIME.\n", NULL), " ", " "); - continue; - } - - printTime = 0; - if (switchPos("/ TIME") != 0) { - printTime = 1; - } - - g_htmlFlag = 1; - - if (switchPos("/ BRIEF_HTML") || switchPos("/ BRIEF_ALT_HTML")) { - if (strcmp(g_fullArg[2], "*")) { - print2( - "?For BRIEF_HTML or BRIEF_ALT_HTML, the label must be \"*\"\n"); - goto htmlDone; - } - g_briefHtmlFlag = 1; - } else { - g_briefHtmlFlag = 0; - } - - if (switchPos("/ ALT_HTML") || switchPos("/ BRIEF_ALT_HTML")) { - g_altHtmlFlag = 1; - } else { - g_altHtmlFlag = 0; - } - - q = 0; - - /* Special feature: if the match statement starts with "*", we - will also output mmascii.html, mmtheoremsall.html, and - mmdefinitions.html. So, with - SHOW STATEMENT * / HTML - these will be output plus all statements; with - SHOW STATEMENT *! / HTML - these will be output with no statements (since ! is illegal in a - statement label); with - SHOW STATEMENT ?* / HTML - all statements will be output, but without mmascii.html etc. */ - if (((char *)(g_fullArg[2]))[0] == '*' || g_briefHtmlFlag) { - s = -2; /* -2 is for ASCII table; -1 is for theorems; - 0 is for definitions */ - } else { - s = 1; - } - - for (s = s + 0; s <= g_statements; s++) { - - if (s > 0 && g_briefHtmlFlag) break; /* Only do summaries */ - - /* - s = -2: mmascii.html - s = -1: mmtheoremsall.html (used to be mmtheorems.html) - s = 0: mmdefinitions.html - s > 0: normal statement - */ - - if (s > 0) { - if (!g_Statement[s].labelName[0]) continue; /* No label */ - if (!matchesList(g_Statement[s].labelName, g_fullArg[2], '*', '?')) - continue; - if (g_Statement[s].type != (char)a_ - && g_Statement[s].type != (char)p_) continue; - } - - q = 1; /* Flag that at least one matching statement was found */ - - if (s > 0) { - g_showStatement = s; - } else { - /* We set it to 1 here so we will output the Metamath Proof - Explorer and not the Hilbert Space Explorer header for - definitions and theorems lists, when g_showStatement is - compared to g_extHtmlStmt in printTexHeader in mmwtex.c */ - g_showStatement = 1; - } - - - /*** Open the html file ***/ - g_htmlFlag = 1; - /* Open the html output file */ - switch (s) { - case -2: - let(&g_texFileName, "mmascii.html"); - break; - case -1: - let(&g_texFileName, "mmtheoremsall.html"); - break; - case 0: - let(&g_texFileName, "mmdefinitions.html"); - break; - default: - let(&g_texFileName, cat(g_Statement[g_showStatement].labelName, ".html", - NULL)); - } - print2("Creating HTML file \"%s\"...\n", g_texFileName); - g_texFilePtr = fSafeOpen(g_texFileName, "w", noVersioning); - if (!g_texFilePtr) goto htmlDone; /* Couldn't open it (err msg was - provided) */ - g_texFileOpenFlag = 1; - printTexHeader((s > 0) ? 1 : 0 /*texHeaderFlag*/); - if (!g_texDefsRead) { - /* If there was an error reading the $t xx.mm statement, - g_texDefsRead won't be set, and we should close out file and skip - further processing. Otherwise we will be attempting to process - uninitialized htmldef arrays and such. */ - print2("?HTML generation was aborted due to the error above.\n"); - s = g_statements + 1; /* To force loop to exit */ - goto ABORT_S; /* Go to end of loop where file is closed out */ - } - - if (s <= 0) { - g_outputToString = 1; - if (s == -2) { - printLongLine(cat("
", - "Symbol to ASCII Correspondence for Text-Only Browsers", - " (in order of appearance in $c and $v statements", - " in the database)", - "

", NULL), "", "\""); - } - /* 13-Oct-2006 nm todo - still appears - where is it? */ - if (!g_briefHtmlFlag) print2("

\n"); - print2("\n"); - break; - case -1: - print2("SUMMARY=\"List of theorems\">\n"); - break; - case 0: - print2("SUMMARY=\"List of syntax, axioms and definitions\">\n"); - break; - } - switch (s) { - case -2: - print2("\n"); - m = 0; /* Statement number map */ - let(&str3, ""); /* For storing ASCII token list in s=-2 mode */ - let(&bgcolor, MINT_BACKGROUND_COLOR); - for (i = 1; i <= g_statements; i++) { - if (s != -2 && (i == g_extHtmlStmt || i == g_mathboxStmt)) { - /* Print a row that identifies the start of the extended - database (e.g. Hilbert Space Explorer) or the user - sandboxes */ - if (i == g_extHtmlStmt) { - let(&bgcolor, PURPLISH_BIBLIO_COLOR); - } else { - let(&bgcolor, SANDBOX_COLOR); - } - printLongLine(cat("", NULL), "", "\""); - } - - if (g_Statement[i].type == (char)p_ || - g_Statement[i].type == (char)a_ ) m++; - if ((s == -1 && g_Statement[i].type != (char)p_) - || (s == 0 && g_Statement[i].type != (char)a_) - || (s == -2 && g_Statement[i].type != (char)c_ - && g_Statement[i].type != (char)v_) - ) continue; - switch (s) { - case -2: - /* Print symbol to ASCII table entry */ - /* It's a $c or $v statement, so each token generates a - table row */ - for (j = 0; j < g_Statement[i].mathStringLen; j++) { - let(&str1, g_MathToken[(g_Statement[i].mathString)[j]].tokenName); - /* Output each token only once in case of multiple decl. */ - if (!instr(1, str3, cat(" ", str1, " ", NULL))) { - let(&str3, cat(str3, " ", str1, " ", NULL)); - let(&str2, ""); - str2 = tokenToTex(g_MathToken[(g_Statement[i].mathString)[j] - ].tokenName, i/*stmt# for error msgs*/); - /* Skip any tokens (such as |- in QL Explorer) that may be suppressed */ - if (!str2[0]) continue; - /* Convert special characters to HTML entities */ - for (k = 0; k < (signed)(strlen(str1)); k++) { - if (str1[k] == '&') { - let(&str1, cat(left(str1, k), "&", - right(str1, k + 2), NULL)); - k = k + 4; - } - if (str1[k] == '<') { - let(&str1, cat(left(str1, k), "<", - right(str1, k + 2), NULL)); - k = k + 3; - } - if (str1[k] == '>') { - let(&str1, cat(left(str1, k), ">", - right(str1, k + 2), NULL)); - k = k + 3; - } - } /* next k */ - printLongLine(cat("", NULL), "", "\""); - } - } /* next j */ - /* Close out the string now to prevent memory overflow */ - fprintf(g_texFilePtr, "%s", g_printString); - let(&g_printString, ""); - break; - case -1: /* Falls through to next case */ - case 0: - let(&str1, ""); - if (s == 0 || g_briefHtmlFlag) { - let(&str1, ""); - /* Get HTML hypotheses => assertion */ - str1 = getTexOrHtmlHypAndAssertion(i); - let(&str1, cat(str1, "", NULL)); - } - - if (g_briefHtmlFlag) { - /* Get page number in mmtheorems*.html of WRITE THEOREMS */ - k = ((g_Statement[i].pinkNumber - 1) / - THEOREMS_PER_PAGE) + 1; /* Page # */ - let(&str2, cat("", NULL)); - printLongLine(str1, "", "\""); - } - /* Close out the string now to prevent overflow */ - fprintf(g_texFilePtr, "%s", g_printString); - let(&g_printString, ""); - break; - } /* end switch */ - } /* next i (statement number) */ - g_outputToString = 0; /* closing will write out the string */ - let(&bgcolor, ""); /* Deallocate (to improve fragmentation) */ - - } else { /* s > 0 */ - - if (printTime == 1) { - getRunTime(&timeIncr); /* This call just resets the time */ - } - - /*** Output the html statement body ***/ - typeStatement(g_showStatement, - 0 /*briefFlag*/, - 0 /*commentOnlyFlag*/, - 1 /*texFlag*/, /* means latex or html */ - 1 /*g_htmlFlag*/); - - if (printTime == 1) { - getRunTime(&timeIncr); - print2("SHOW STATEMENT run time = %6.2f sec for \"%s\"\n", - timeIncr, - g_texFileName); - } - - } /* if s <= 0 */ - - ABORT_S: - /*** Close the html file ***/ - printTexTrailer(1 /*texHeaderFlag*/); - fclose(g_texFilePtr); - g_texFileOpenFlag = 0; - let(&g_texFileName,""); - - } /* next s */ - - if (!q) { - /* No matching statement was found */ - printLongLine(cat("?There is no statement whose label matches \"", - g_fullArg[2], "\". ", - "Use SHOW LABELS for a list of valid labels.", NULL), "", " "); - continue; - } - - /* Complete the command processing to bypass normal SHOW STATEMENT - (non-html) below. */ - htmlDone: - continue; - } /* if (cmdMatches("SHOW STATEMENT") && switchPos("/ HTML")...) */ - - - /* Write mnemosyne.txt */ - if (cmdMatches("SHOW STATEMENT") && switchPos("/ MNEMONICS")) { - g_htmlFlag = 1; /* Use HTML, not TeX section */ - g_altHtmlFlag = 1; /* Use Unicode, not GIF */ - /* readTexDefs() rereads based on changes to g_htmlFlag, g_altHtmlFlag */ - if (2/*error*/ == readTexDefs(0 /* 1 = check errors only */, - 1 /* 1 = GIF file existence check */ )) { - continue; /* An error occurred */ - } - - let(&g_texFileName, "mnemosyne.txt"); - g_texFilePtr = fSafeOpen(g_texFileName, "w", 0/*noVersioningFlag*/); - if (!g_texFilePtr) { - /* Couldn't open file; error message was provided by fSafeOpen */ - continue; - } - print2("Creating Mnemosyne file \"%s\"...\n", g_texFileName); - - for (s = 1; s <= g_statements; s++) { - g_showStatement = s; - - if (!g_Statement[s].labelName[0]) continue; /* No label */ - if (!matchesList(g_Statement[s].labelName, g_fullArg[2], '*', '?')) - continue; - if (g_Statement[s].type != (char)a_ - && g_Statement[s].type != (char)p_) - continue; - - let(&str1, cat("
", - " ", g_Statement[g_showStatement].labelName, - "", "
", NULL)); - fprintf(g_texFilePtr, "%s", str1); - - let(&str1, cat("
\n"); - break; - case -1: - print2( - "
List of Theorems
\n"); - break; - case 0: - printLongLine(cat( - /* (in case |- suppressed) */ - "
List of Syntax, ", - "Axioms (ax-) and", - " Definitions (df-)", "
", - NULL), "", "\""); - break; - } - switch (s) { - case -2: - print2("SymbolASCII\n"); - break; - case -1: - print2( - "RefDescription\n"); - break; - case 0: - printLongLine(cat( - "Ref", - "Expression (see link for any distinct variable requirements)", - NULL), "", "\""); - break; - } - print2("
", - "The list of syntax, axioms (ax-) and definitions (df-) for", - " the ", - (i == g_extHtmlStmt) ? - g_extHtmlTitle : - "User Mathboxes", - " starts here
", - (g_altHtmlFlag ? cat("", NULL) : ""), - str2, - (g_altHtmlFlag ? "" : ""), - " ", /* This will prevent a - -4px shifted image from overlapping the - lower border of the table cell */ - "", - str1, - "
", - /*"",*/ - "", - str((double)(g_Statement[i].pinkNumber)), " ", - "", g_Statement[i].labelName, - "", NULL)); - let(&str1, cat(str2, " ", str1, NULL)); - } else { - /* Get little pink (or rainbow-colored) number */ - let(&str4, ""); - str4 = pinkHTML(i); - let(&str2, cat("
", g_Statement[i].labelName, - "", str4, NULL)); - let(&str1, cat(str2, "", str1, NULL)); - } - - print2("\n"); /* New line for HTML source readability */ - printLongLine(str1, "", "\""); - - if (s == 0 || g_briefHtmlFlag) { - /* Set s == 0 here for Web site version, - s == s for symbol version of theorem list */ - /* The below has been replaced by - getTexOrHtmlHypAndAssertion(i) above. */ - /*printTexLongMath(g_Statement[i].mathString, "", "", 0, 0);*/ - /*g_outputToString = 1;*/ /* Is reset by printTexLongMath */ - } else { - /* Theorems are listed w/ description; otherwise file is too - big for convenience */ - let(&str1, ""); - str1 = getDescription(i); - if (strlen(str1) > 29) - let(&str1, cat(left(str1, 26), "...", NULL)); - let(&str1, cat(str1, "
",NULL)); - fprintf(g_texFilePtr, "%s", str1); - - j = nmbrLen(g_Statement[g_showStatement].reqHypList); - for (i = 0; i < j; i++) { - k = g_Statement[g_showStatement].reqHypList[i]; - if (g_Statement[k].type != (char)e_ - && !(subType == SYNTAX - && g_Statement[k].type == (char)f_)) - continue; - - let(&str1, cat("", str1); - } - - - let(&str1, "
", - g_Statement[k].labelName, "", - NULL)); - fprintf(g_texFilePtr, "%s", str1); - - /* Print hypothesis */ - let(&str1, ""); /* Free any previous allocation to str1 */ - /* getTexLongMath does not return a temporary allocation; must - assign str1 directly, not with let(). It will be deallocated - with the next let(&str1,...). */ - str1 = getTexLongMath(g_Statement[k].mathString, - k/*stmt# for err msgs*/); - fprintf(g_texFilePtr, "%s
"); - fprintf(g_texFilePtr, "%s", str1); - - let(&str1, "
What is the conclusion?"); - fprintf(g_texFilePtr, "%s\n", str1); - - let(&str1, ""); - fprintf(g_texFilePtr, "%s", str1); - - let(&str1, ""); /* Free any previous allocation to str1 */ - /* getTexLongMath does not return a temporary allocation */ - str1 = getTexLongMath(g_Statement[s].mathString, s); - fprintf(g_texFilePtr, "%s", str1); - - let(&str1, ""); - fprintf(g_texFilePtr, "%s\n",str1); - } /* for(s=1;s j-3) { - print2("At least %ld bytes of memory are free.\n",j); - } else { - print2("%ld bytes of memory are free.\n",i); - } - continue; - } - - if (cmdMatches("SHOW ELAPSED_TIME")) { - timeTotal = getRunTime(&timeIncr); - print2( - "Time since last SHOW ELAPSED_TIME command = %6.2f s; total = %6.2f s\n", - timeIncr, timeTotal); - continue; - } /* if (cmdMatches("SHOW ELAPSED_TIME")) */ - - - if (cmdMatches("SHOW TRACE_BACK")) { - essentialFlag = 0; - axiomFlag = 0; - endIndent = 0; - i = switchPos("/ ESSENTIAL"); - if (i) essentialFlag = 1; /* Limit trace to essential steps only */ - i = switchPos("/ ALL"); - if (i) essentialFlag = 0; - i = switchPos("/ AXIOMS"); - if (i) axiomFlag = 1; /* Limit trace printout to axioms */ - i = switchPos("/ DEPTH"); /* Limit depth of printout */ - if (i) endIndent = (long)val(g_fullArg[i + 1]); - - i = switchPos("/ COUNT_STEPS"); - countStepsFlag = (i != 0 ? 1 : 0); - i = switchPos("/ TREE"); - treeFlag = (i != 0 ? 1 : 0); - i = switchPos("/ MATCH"); - matchFlag = (i != 0 ? 1 : 0); - if (matchFlag) { - let(&matchList, g_fullArg[i + 1]); - } else { - let(&matchList, ""); - } - i = switchPos("/ TO"); - if (i != 0) { - let(&traceToList, g_fullArg[i + 1]); - } else { - let(&traceToList, ""); - } - if (treeFlag) { - if (axiomFlag) { - print2( - "(Note: The AXIOMS switch is ignored in TREE mode.)\n"); - } - if (countStepsFlag) { - print2( - "(Note: The COUNT_STEPS switch is ignored in TREE mode.)\n"); - } - if (matchFlag) { - print2( - "(Note: The MATCH list is ignored in TREE mode.)\n"); - } - } else { - if (endIndent != 0) { - print2( - "(Note: The DEPTH is ignored if the TREE switch is not used.)\n"); - } - if (countStepsFlag) { - if (matchFlag) { - print2( - "(Note: The MATCH list is ignored in COUNT_STEPS mode.)\n"); - } - } - } - - g_showStatement = 0; - for (i = 1; i <= g_statements; i++) { - if (g_Statement[i].type != (char)p_) - continue; /* Not a $p statement; skip it */ - /* Wildcard matching */ - if (!matchesList(g_Statement[i].labelName, g_fullArg[2], '*', '?')) - continue; - - g_showStatement = i; - - if (treeFlag) { - traceProofTree(g_showStatement, essentialFlag, endIndent); - } else { - if (countStepsFlag) { - countSteps(g_showStatement, essentialFlag); - } else { - traceProof(g_showStatement, - essentialFlag, - axiomFlag, - matchList, - traceToList, - 0 /* testOnlyFlag */); - } - } - - } /* next i */ - if (g_showStatement == 0) { - printLongLine(cat("?There are no $p labels matching \"", - g_fullArg[2], "\". ", - "See HELP SHOW TRACE_BACK for matching rules.", NULL), "", " "); - } - - let(&matchList, ""); /* Deallocate memory */ - let(&traceToList, ""); /* Deallocate memory */ - continue; - } /* if (cmdMatches("SHOW TRACE_BACK")) */ - - - if (cmdMatches("SHOW USAGE")) { - - if (switchPos("/ ALL")) { - m = 1; /* Always include $e, $f statements */ - } else { - m = 0; /* If wildcards are used, show $a, $p only */ - } - - g_showStatement = 0; - for (i = 1; i <= g_statements; i++) { - if (!g_Statement[i].labelName[0]) continue; /* No label */ - if (!m && g_Statement[i].type != (char)p_ && - g_Statement[i].type != (char)a_ - /* A wildcard-free user-specified statement is always matched even - if it's a $e, i.e. it overrides omission of / ALL */ - && (instr(1, g_fullArg[2], "*") - || instr(1, g_fullArg[2], "?"))) - continue; /* No /ALL switch and wildcard and not $p, $a */ - /* Wildcard matching */ - if (!matchesList(g_Statement[i].labelName, g_fullArg[2], '*', '?')) - continue; - - g_showStatement = i; - recursiveFlag = 0; - j = switchPos("/ RECURSIVE"); - if (j) recursiveFlag = 1; /* Recursive (indirect) usage */ - j = switchPos("/ DIRECT"); - if (j) recursiveFlag = 0; /* Direct references only */ - - let(&str1, ""); - str1 = traceUsage(g_showStatement, - recursiveFlag, - 0 /* cutoffStmt */); - - /* str1[0] will be 'Y' or 'N' depending on whether there are any - statements. str1[i] will be 'Y' or 'N' depending on whether - g_Statement[i] uses g_showStatement. */ - /* Count the number of statements k = # of 'Y' */ - k = 0; - if (str1[0] == 'Y') { - /* There is at least one statement using g_showStatement */ - for (j = g_showStatement + 1; j <= g_statements; j++) { - if (str1[j] == 'Y') { - k++; - } else { - if (str1[j] != 'N') bug(1124); /* Must be 'Y' or 'N' */ - } - } - } else { - if (str1[0] != 'N') bug(1125); /* Must be 'Y' or 'N' */ - } - - if (k == 0) { - printLongLine(cat("Statement \"", - g_Statement[g_showStatement].labelName, - "\" is not referenced in the proof of any statement.", NULL), - "", " "); - } else { - if (recursiveFlag) { - let(&str2, "\" directly or indirectly affects"); - } else { - let(&str2, "\" is directly referenced in"); - } - if (k == 1) { - printLongLine(cat("Statement \"", - g_Statement[g_showStatement].labelName, - str2, " the proof of ", - str((double)k), " statement:", NULL), "", " "); - } else { - printLongLine(cat("Statement \"", - g_Statement[g_showStatement].labelName, - str2, " the proofs of ", - str((double)k), " statements:", NULL), "", " "); - } - } - - if (k != 0) { - let(&str3, " "); /* Line buffer */ - for (j = g_showStatement + 1; j <= g_statements; j++) { - if (str1[j] == 'Y') { - /* Since the output list could be huge, don't build giant - string (very slow) but output it line by line */ - if ((long)strlen(str3) + 1 + - (long)strlen(g_Statement[j].labelName) > g_screenWidth) { - /* Output and reset the line buffer */ - print2("%s\n", str3); - let(&str3, " "); - } - let(&str3, cat(str3, " ", g_Statement[j].labelName, NULL)); - } - } - if (strlen(str3) > 1) print2("%s\n", str3); - let(&str3, ""); - } else { - print2(" (None)\n"); - } /* if (k != 0) */ - } /* next i (statement matching wildcard list) */ - - if (g_showStatement == 0) { - printLongLine(cat("?There are no labels matching \"", - g_fullArg[2], "\". ", - "See HELP SHOW USAGE for matching rules.", NULL), "", " "); - } - continue; - } /* if cmdMatches("SHOW USAGE") */ - - - if (cmdMatches("SHOW PROOF") - || cmdMatches("SHOW NEW_PROOF") - || cmdMatches("SAVE PROOF") - || cmdMatches("SAVE NEW_PROOF") - || cmdMatches("MIDI")) { - if (switchPos("/ HTML")) { - print2("?HTML qualifier is obsolete - use SHOW STATEMENT * / HTML\n"); - continue; - } - - if (cmdMatches("SAVE NEW_PROOF") - && getMarkupFlag(g_proveStatement, PROOF_DISCOURAGED)) { - if (switchPos("/ OVERRIDE") == 0 && g_globalDiscouragement == 1) { - /* print2("\n"); */ /* Enable for more emphasis */ - print2( -">>> ?Error: Attempt to overwrite a proof whose modification is discouraged.\n"); - print2( - ">>> Use SAVE NEW_PROOF ... / OVERRIDE if you really want to do this.\n"); - /* print2("\n"); */ /* Enable for more emphasis */ - continue; - } else { - /* print2("\n"); */ /* Enable for more emphasis */ - print2( -">>> ?Warning: You are overwriting a proof whose modification is discouraged.\n"); - /* print2("\n"); */ /* Enable for more emphasis */ - } - } - - if (cmdMatches("SHOW PROOF") || cmdMatches("SAVE PROOF")) { - pipFlag = 0; - } else { - pipFlag = 1; /* Proof-in-progress (NEW_PROOF) flag */ - } - if (cmdMatches("SHOW")) { - saveFlag = 0; - } else { - saveFlag = 1; /* The command is SAVE PROOF */ - } - - printTime = 0; - if (switchPos("/ TIME") != 0) { /* / TIME legal in SAVE mode only */ - printTime = 1; - } - - i = switchPos("/ OLD_COMPRESSION"); - if (i) { - if (!switchPos("/ COMPRESSED")) { - print2("?/ OLD_COMPRESSION must be accompanied by / COMPRESSED.\n"); - continue; - } - } - - i = switchPos("/ FAST"); - if (i) { - if (!switchPos("/ COMPRESSED") && !switchPos("/ PACKED")) { - print2("?/ FAST must be accompanied by / COMPRESSED or / PACKED.\n"); - continue; - } - fastFlag = 1; - } else { - fastFlag = 0; - } - - if (switchPos("/ EXPLICIT")) { - if (switchPos("/ COMPRESSED")) { - print2("?/ COMPRESSED and / EXPLICIT may not be used together.\n"); - continue; - } else if (switchPos("/ NORMAL")) { - print2("?/ NORMAL and / EXPLICIT may not be used together.\n"); - continue; - } - } - if (switchPos("/ NORMAL")) { - if (switchPos("/ COMPRESSED")) { - print2("?/ NORMAL and / COMPRESSED may not be used together.\n"); - continue; - } - } - - - /* Establish defaults for omitted qualifiers */ - startStep = 0; - endStep = 0; - endIndent = 0; - essentialFlag = 1; - renumberFlag = 0; - unknownFlag = 0; - notUnifiedFlag = 0; - reverseFlag = 0; - detailStep = 0; - noIndentFlag = 0; - splitColumn = DEFAULT_COLUMN; - skipRepeatedSteps = 0; - texFlag = 0; - - i = switchPos("/ FROM_STEP"); - if (i) startStep = (long)val(g_fullArg[i + 1]); - i = switchPos("/ TO_STEP"); - if (i) endStep = (long)val(g_fullArg[i + 1]); - i = switchPos("/ DEPTH"); - if (i) endIndent = (long)val(g_fullArg[i + 1]); - /* ESSENTIAL is retained for downwards compatibility, but is - now the default, so we ignore it. */ - /* - i = switchPos("/ ESSENTIAL"); - if (i) essentialFlag = 1; - */ - i = switchPos("/ ALL"); - if (i) essentialFlag = 0; - if (i && switchPos("/ ESSENTIAL")) { - print2("?You may not specify both / ESSENTIAL and / ALL.\n"); - continue; - } - i = switchPos("/ RENUMBER"); - if (i) renumberFlag = 1; - i = switchPos("/ UNKNOWN"); - if (i) unknownFlag = 1; - i = switchPos("/ NOT_UNIFIED"); /* pip mode only */ - if (i) notUnifiedFlag = 1; - i = switchPos("/ REVERSE"); - if (i) reverseFlag = 1; - i = switchPos("/ LEMMON"); - if (i) noIndentFlag = 1; - i = switchPos("/ START_COLUMN"); - if (i) splitColumn = (long)val(g_fullArg[i + 1]); - i = switchPos("/ NO_REPEATED_STEPS"); - if (i) skipRepeatedSteps = 1; - - /* If NO_REPEATED_STEPS is specified, indentation (tree) mode will be - misleading because a hypothesis assignment will be suppressed if the - same assignment occurred earlier, i.e. it is no longer a "tree". */ - if (skipRepeatedSteps == 1 && noIndentFlag == 0) { - print2("?You must specify / LEMMON with / NO_REPEATED_STEPS\n"); - continue; - } - - i = switchPos("/ TEX") || switchPos("/ HTML") - || switchPos("/ OLD_TEX"); - if (i) texFlag = 1; - - g_oldTexFlag = 0; - if (switchPos("/ OLD_TEX")) g_oldTexFlag = 1; - - if (cmdMatches("MIDI")) { - g_midiFlag = 1; - pipFlag = 0; - saveFlag = 0; - let(&labelMatch, g_fullArg[1]); - i = switchPos("/ PARAMETER"); /* MIDI only */ - if (i) { - let(&g_midiParam, g_fullArg[i + 1]); - } else { - let(&g_midiParam, ""); - } - } else { - g_midiFlag = 0; - if (!pipFlag) let(&labelMatch, g_fullArg[2]); - } - - - if (texFlag) { - if (!g_texFileOpenFlag) { - print2( - "?You have not opened a %s file. Use the OPEN %s command first.\n", - g_htmlFlag ? "HTML" : "LaTeX", - g_htmlFlag ? "HTML" : "TEX"); - continue; - } - } - - i = switchPos("/ DETAILED_STEP"); /* non-pip mode only */ - if (i) { - detailStep = (long)val(g_fullArg[i + 1]); - if (!detailStep) detailStep = -1; /* To use as flag; error message - will occur in showDetailStep() */ - } - -/*??? Need better warnings for switch combinations that don't make sense */ - - /* Print a single message for "/compressed/fast" */ - if (switchPos("/ COMPRESSED") && fastFlag - && !strcmp("*", labelMatch)) { - print2( - "Reformatting and saving (but not recompressing) all proofs...\n"); - } - - - q = 0; /* Flag that at least one matching statement was found */ - for (stmt = 1; stmt <= g_statements; stmt++) { - /* If pipFlag (NEW_PROOF), we will iterate exactly once. This - loop of course will be entered because there is a least one - statement, and at the end of the s loop we break out of it. */ - /* If !pipFlag, get the next statement: */ - if (!pipFlag) { - if (g_Statement[stmt].type != (char)p_) continue; /* Not $p */ - if (!matchesList(g_Statement[stmt].labelName, labelMatch, '*', '?')) - continue; - g_showStatement = stmt; - } - - q = 1; /* Flag that at least one matching statement was found */ - - if (detailStep) { - /* Show the details of just one step */ - showDetailStep(g_showStatement, detailStep); - continue; - } - - if (switchPos("/ STATEMENT_SUMMARY")) { /* non-pip mode only */ - /* Just summarize the statements used in the proof */ - proofStmtSumm(g_showStatement, essentialFlag, texFlag); - continue; - } - - if (switchPos("/ SIZE")) { /* non-pip mode only */ - /* Just print the size of the stored proof and continue */ - let(&str1, space(g_Statement[g_showStatement].proofSectionLen)); - memcpy(str1, g_Statement[g_showStatement].proofSectionPtr, - (size_t)(g_Statement[g_showStatement].proofSectionLen)); - n = instr(1, str1, "$."); - if (n == 0) { - /* The original source truncates the proof before $. */ - n = g_Statement[g_showStatement].proofSectionLen; - } else { - /* If a proof is saved, it includes the $. (Should we - revisit or document better how/why this is done?) */ - n = n - 1; - } - print2("The proof source for \"%s\" has %ld characters.\n", - g_Statement[g_showStatement].labelName, n); - continue; - } - - if (switchPos("/ PACKED") || switchPos("/ NORMAL") || - switchPos("/ COMPRESSED") || switchPos("/ EXPLICIT") || saveFlag) { - /*??? Add error msg if other switches were specified. (Ignore them.)*/ - - if (saveFlag) { - if (printTime == 1) { - getRunTime(&timeIncr); /* This call just resets the time */ - } - } - - if (!pipFlag) { - outStatement = g_showStatement; - } else { - outStatement = g_proveStatement; - } - - explicitTargets = (switchPos("/ EXPLICIT") != 0) ? 1 : 0; - - /* Get the amount to indent the proof by */ - indentation = 2 + getSourceIndentation(outStatement); - - if (!pipFlag) { - parseProof(g_showStatement); /* Prints message if severe error */ - if (g_WrkProof.errorSeverity > 1) { - /* Prevent bugtrap in nmbrSquishProof -> nmbrGetSubProofLen - if proof corrupted */ - print2( - "?The proof has a severe error and cannot be displayed or saved.\n"); - continue; - } - if (fastFlag) { - /* Use the proof as is */ - nmbrLet(&nmbrSaveProof, g_WrkProof.proofString); - } else { - /* Make sure the proof is uncompressed */ - nmbrLet(&nmbrSaveProof, nmbrUnsquishProof(g_WrkProof.proofString)); - } - } else { - nmbrLet(&nmbrSaveProof, g_ProofInProgress.proof); - } - if (switchPos("/ PACKED") || switchPos("/ COMPRESSED")) { - if (!fastFlag) { - nmbrLet(&nmbrSaveProof, nmbrSquishProof(nmbrSaveProof)); - } - } - - if (switchPos("/ COMPRESSED")) { - let(&str1, compressProof(nmbrSaveProof, - outStatement, /* g_showStatement or g_proveStatement based on pipFlag */ - (switchPos("/ OLD_COMPRESSION")) ? 1 : 0)); - } else { - let(&str1, nmbrCvtRToVString(nmbrSaveProof, - explicitTargets, - outStatement /*statemNum, used only if explicitTargets*/)); - } - - - if (saveFlag) { - /* ??? This is a problem when mixing html and save proof */ - if (g_printString[0]) bug(1114); - let(&g_printString, ""); - - /* Set flag for print2() to put output in g_printString instead - of displaying it on the screen */ - g_outputToString = 1; - - } else { - if (!print2("Proof of \"%s\":\n", g_Statement[outStatement].labelName)) - break; /* Break for speedup if user quit */ - print2( -"---------Clip out the proof below this line to put it in the source file:\n"); - } - if (switchPos("/ COMPRESSED")) { - printLongLine(cat(space(indentation), str1, " $.", NULL), - space(indentation), "& "); /* "&" is special flag to break - compressed part of proof anywhere */ - } else { - printLongLine(cat(space(indentation), str1," $.", NULL), - space(indentation), " "); - } - - l = (long)(strlen(str1)); /* Save length for printout below */ - - /* SOREAR Only generate date if the proof looks complete. - This is not intended as a grading mechanism, just trying - to avoid premature output */ - if (!nmbrElementIn(1, nmbrSaveProof, -(long)'?')) { - /* Add a "(Contributed by...)" date if it isn't there */ - let(&str2, ""); - str2 = getContrib(outStatement, CONTRIBUTOR); - if (str2[0] == 0) { /* The is no contributor, so add one */ - - /* See if there is a date below the proof (for converting old - .mm files). Someday this will be obsolete, with str3 and - str4 always returned as "". */ - getProofDate(outStatement, &str3, &str4); - /* If there are two dates below the proof, the first on is - the revision date and the second the "Contributed by" date. */ - if (str4[0] != 0) { /* There are 2 dates below the proof */ - let(&str5, str3); /* 1st date is Revised by... */ - let(&str3, str4); /* 2nd date is Contributed by... */ - } else { - let(&str5, ""); - } - /* If there is no date below proof, use today's date */ - if (str3[0] == 0) let(&str3, date()); - let(&str4, cat("\n", space(indentation + 1), - "(Contributed by ", g_contributorName, - ", ", str3, ".) ", NULL)); - /* If there is a 2nd date below proof, add a "(Revised by..." - tag */ - if (str5[0] != 0) { - /* Use the DEFAULT_CONTRIBUTOR ?who? because we don't - know the reviser name (using the contributor name may - be incorrect). Also, this will trigger a warning in - VERIFY MARKUP since it may be a proof shortener rather than - a reviser. */ - let(&str4, cat(str4, "\n", space(indentation + 1), - "(Revised by ", DEFAULT_CONTRIBUTOR, - ", ", str5, ".) ", NULL)); - } - - let(&str3, space(g_Statement[outStatement].labelSectionLen)); - /* str3 will have the statement's label section w/ comment */ - memcpy(str3, g_Statement[outStatement].labelSectionPtr, - (size_t)(g_Statement[outStatement].labelSectionLen)); - i = rinstr(str3, "$)"); /* The last "$)" occurrence */ - if (i != 0 /* A description comment exists */ - && saveFlag) { /* and we are saving the proof */ - /* This isn't a perfect wrapping but we assume - 'write source .../rewrap' will be done eventually. */ - /* str3 will have the updated comment */ - let(&str3, cat(left(str3, i - 1), str4, right(str3, i), NULL)); - if (g_Statement[outStatement].labelSectionChanged == 1) { - /* Deallocate old comment if not original source */ - let(&str4, ""); /* Deallocate any previous str4 content */ - str4 = g_Statement[outStatement].labelSectionPtr; - let(&str4, ""); /* Deallocate the old content */ - } - /* Set flag that this is not the original source */ - g_Statement[outStatement].labelSectionChanged = 1; - g_Statement[outStatement].labelSectionLen = (long)strlen(str3); - /* We do a direct assignment instead of let(&...) because - labelSectionPtr may point to the middle of the giant input - file buffer, which we don't want to deallocate */ - g_Statement[outStatement].labelSectionPtr = str3; - /* Reset str3 without deallocating with let(), since it - was assigned to labelSectionPtr */ - str3 = ""; - /* Reset the cache for this statement in getContrib() */ - str3 = getContrib(outStatement, GC_RESET_STMT); - } /* if i != 0 */ - } /* if str2[0] == 0 */ - } /* if (!nmbrElementIn(1, nmbrSaveProof, -(long)'?')) */ - - if (saveFlag) { - g_sourceChanged = 1; - g_proofChanged = 0; - if (processUndoStack(NULL, PUS_GET_STATUS, "", 0)) { - /* The UNDO stack may not be empty */ - proofSavedFlag = 1; /* UNDO stack empty no longer reliably - indicates that proof hasn't changed */ - } - - /* Add an initial \n which will go after the "$=" and the - beginning of the proof */ - let(&g_printString, cat("\n", g_printString, NULL)); - if (g_Statement[outStatement].proofSectionChanged == 1) { - /* Deallocate old proof if not original source */ - let(&str1, ""); /* Deallocate any previous str1 content */ - str1 = g_Statement[outStatement].proofSectionPtr; - let(&str1, ""); /* Deallocate the proof section */ - } - /* Set flag that this is not the original source */ - g_Statement[outStatement].proofSectionChanged = 1; - if (strcmp(" $.\n", - right(g_printString, (long)strlen(g_printString) - 3))) { - bug(1128); - } - /* Note that g_printString ends with "$.\n", but those 3 characters - should not be in the proofSection. (The "$." keyword is - added between proofSection and next labelSection when the - output is written by writeOutput.) Thus we subtract 3 - from the length. But there is no need to truncate the - string; later deallocation will take care of the whole - string. */ - g_Statement[outStatement].proofSectionLen - = (long)strlen(g_printString) - 3; - /* We do a direct assignment instead of let(&...) because - proofSectionPtr may point to the middle of the giant input - file string, which we don't want to deallocate */ - g_Statement[outStatement].proofSectionPtr = g_printString; - /* Reset g_printString without deallocating with let(), since it - was assigned to proofSectionPtr */ - g_printString = ""; - g_outputToString = 0; - - - if (!pipFlag) { - if (!(fastFlag && !strcmp("*", labelMatch))) { - printLongLine( - cat("The proof of \"", g_Statement[outStatement].labelName, - "\" has been reformatted and saved internally.", - NULL), "", " "); - } - } else { - printLongLine(cat("The new proof of \"", g_Statement[outStatement].labelName, - "\" has been saved internally.", - NULL), "", " "); - } - - if (printTime == 1) { - getRunTime(&timeIncr); - print2("SAVE PROOF run time = %6.2f sec for \"%s\"\n", timeIncr, - g_Statement[outStatement].labelName); - } - - } else { - /*print2("\n");*/ /* Add a blank line to make clipping easier */ - print2(cat( - "---------The proof of \"", g_Statement[outStatement].labelName, - /* "\" to clip out ends above this line.\n",NULL)); */ - "\" (", str((double)l), " bytes) ends above this line.\n", NULL)); - } /* End if saveFlag */ - nmbrLet(&nmbrSaveProof, NULL_NMBRSTRING); - if (pipFlag) break; /* Only one iteration for NEW_PROOF stuff */ - continue; /* to next s iteration */ - } /* end if (switchPos("/ PACKED") || switchPos("/ NORMAL") || - switchPos("/ COMPRESSED") || switchPos("/ EXPLICIT") || saveFlag) */ - - if (saveFlag) bug(1112); /* Shouldn't get here */ - - if (!pipFlag) { - outStatement = g_showStatement; - } else { - outStatement = g_proveStatement; - } - if (texFlag) { - g_outputToString = 1; /* Flag for print2 to add to g_printString */ - if (!g_htmlFlag) { - if (!g_oldTexFlag) { - print2("\\begin{proof}\n"); - print2("\\begin{align}\n"); - } else { - print2("\n"); - print2("\\vspace{1ex} %%1\n"); - printLongLine(cat("Proof of ", - "{\\tt ", - asciiToTt(g_Statement[outStatement].labelName), - "}:", NULL), "", " "); - print2("\n"); - print2("\n"); - } - } else { /* g_htmlFlag */ - bug(1118); - } - g_outputToString = 0; - /* printTeXLongMath clears g_printString in LaTeX - mode before starting its output, so we must put out the - g_printString ourselves here */ - fprintf(g_texFilePtr, "%s", g_printString); - let(&g_printString, ""); /* We'll clr it anyway */ - } else { /* !texFlag */ - /* Terminal output - display the statement if wildcard is used */ - if (!pipFlag) { - if (instr(1, labelMatch, "*") || instr(1, labelMatch, "?")) { - if (!print2("Proof of \"%s\":\n", g_Statement[outStatement].labelName)) - break; /* Break for speedup if user quit */ - } - } - } - - - if (texFlag) print2("Outputting proof of \"%s\"...\n", - g_Statement[outStatement].labelName); - - typeProof(outStatement, - pipFlag, - startStep, - endStep, - endIndent, - essentialFlag, - - /* In SHOW PROOF xxx /TEX, we use renumber steps mode so that - the first step is step 1. The step number is checked for - step 1 in mmwtex.c to prevent a spurious \\ (newline) at the - start of the proof. Note that - SHOW PROOF is not available in HTML mode, so texFlag will - always mean LaTeX mode here. */ - (texFlag ? 1 : renumberFlag), - - unknownFlag, - notUnifiedFlag, - reverseFlag, - - /* In SHOW PROOF xxx /TEX, we use Lemmon mode so that the - hypothesis reference list will be available. Note that - SHOW PROOF is not available in HTML mode, so texFlag will - always mean LaTeX mode here. */ - (texFlag ? 1 : noIndentFlag), - - splitColumn, - skipRepeatedSteps, - texFlag, - g_htmlFlag); - if (texFlag) { - if (!g_htmlFlag) { - if (!g_oldTexFlag) { - g_outputToString = 1; - print2("\\end{align}\n"); - print2("\\end{proof}\n"); - print2("\n"); - g_outputToString = 0; - fprintf(g_texFilePtr, "%s", g_printString); - let(&g_printString, ""); - } else { - } - } else { /* g_htmlFlag */ - g_outputToString = 1; - print2("\n"); - print2("
\n"); - /* print trailer will close out string later */ - g_outputToString = 0; - } - } - - /*E*/ if (0) { /* for debugging: */ - printLongLine(nmbrCvtRToVString(g_WrkProof.proofString, - 0, /*explicitTargets*/ - 0 /*statemNum, used only if explicitTargets*/)," "," "); - print2("\n"); - - nmbrLet(&nmbrSaveProof, nmbrSquishProof(g_WrkProof.proofString)); - printLongLine(nmbrCvtRToVString(nmbrSaveProof, - 0, /*explicitTargets*/ - 0 /*statemNum, used only if explicitTargets*/)," "," "); - print2("\n"); - - nmbrLet(&nmbrTmp, nmbrUnsquishProof(nmbrSaveProof)); - printLongLine(nmbrCvtRToVString(nmbrTmp, - 0, /*explicitTargets*/ - 0 /*statemNum, used only if explicitTargets*/)," "," "); - - nmbrLet(&nmbrTmp, nmbrGetTargetHyp(nmbrSaveProof,g_showStatement)); - printLongLine(nmbrCvtAnyToVString(nmbrTmp)," "," "); print2("\n"); - - nmbrLet(&nmbrTmp, nmbrGetEssential(nmbrSaveProof)); - printLongLine(nmbrCvtAnyToVString(nmbrTmp)," "," "); print2("\n"); - - cleanWrkProof(); /* Deallocate verifyProof storage */ - } /* end debugging */ - - if (pipFlag) break; /* Only one iteration for NEW_PROOF stuff */ - } /* Next stmt */ - if (!q) { - /* No matching statement was found */ - printLongLine(cat("?There is no $p statement whose label matches \"", - (cmdMatches("MIDI")) ? g_fullArg[1] : g_fullArg[2], - "\". ", - "Use SHOW LABELS to see list of valid labels.", NULL), "", " "); - } else { - if (saveFlag) { - print2("Remember to use WRITE SOURCE to save changes permanently.\n"); - } - if (texFlag) { - print2("The LaTeX source was written to \"%s\".\n", g_texFileName); - g_oldTexFlag = 0; - } - } - - continue; - } /* if (cmdMatches("SHOW/SAVE [NEW_]PROOF" or" MIDI") */ - - -/*E*/ /*???????? DEBUG command for debugging only */ - if (cmdMatches("DBG")) { - print2("DEBUGGING MODE IS FOR DEVELOPER'S USE ONLY!\n"); - print2("Argument: %s\n", g_fullArg[1]); - nmbrLet(&nmbrTmp, parseMathTokens(g_fullArg[1], g_proveStatement)); - for (j = 0; j < 3; j++) { - print2("Trying depth %ld\n", j); - nmbrTmpPtr = proveFloating(nmbrTmp, g_proveStatement, j, 0, 0, - 1/*overrideFlag*/, 1/*mathboxFlag*/); - if (nmbrLen(nmbrTmpPtr)) break; - } - - print2("Result: %s\n", nmbrCvtRToVString(nmbrTmpPtr, - 0, /*explicitTargets*/ - 0 /*statemNum, used only if explicitTargets*/)); - nmbrLet(&nmbrTmpPtr, NULL_NMBRSTRING); - - continue; - } -/*E*/ /*???????? DEBUG command for debugging only */ - - if (cmdMatches("PROVE")) { - - /* Get the unique statement matching the g_fullArg[1] pattern */ - i = getStatementNum(g_fullArg[1], - 1/*startStmt*/, - g_statements + 1 /*maxStmt*/, - 0/*aAllowed*/, - 1/*pAllowed*/, - 0/*eAllowed*/, - 0/*fAllowed*/, - 0/*efOnlyForMaxStmt*/, - 1/*uniqueFlag*/); - if (i == -1) { - continue; /* Error msg was provided if not unique */ - } - g_proveStatement = i; - - - /* 1 means to override usage locks */ - overrideFlag = ( (switchPos("/ OVERRIDE")) ? 1 : 0) - || g_globalDiscouragement == 0; - if (getMarkupFlag(g_proveStatement, PROOF_DISCOURAGED)) { - if (overrideFlag == 0) { - /* print2("\n"); */ /* Enable for more emphasis */ - print2(">>> ?Error: " - "Modification of this statement's proof is discouraged.\n"); - print2(">>> You must use PROVE ... / OVERRIDE to work on it.\n"); - /* print2("\n"); */ /* Enable for more emphasis */ - continue; - } - } - - print2("Entering the Proof Assistant. " - "HELP PROOF_ASSISTANT for help, EXIT to exit.\n"); - - g_PFASmode = 1; /* Set mode for commands here and in mmcmdl.c */ - /* Note: Proof Assistant mode can equivalently be determined by: - nmbrLen(g_ProofInProgress.proof) != 0 */ - - parseProof(g_proveStatement); - verifyProof(g_proveStatement); /* Necessary to set RPN stack ptrs - before calling cleanWrkProof() */ - if (g_WrkProof.errorSeverity > 1) { - print2( - "The starting proof has a severe error. It will not be used.\n"); - nmbrLet(&nmbrSaveProof, nmbrAddElement(NULL_NMBRSTRING, -(long)'?')); - } else { - nmbrLet(&nmbrSaveProof, g_WrkProof.proofString); - } - cleanWrkProof(); /* Deallocate verifyProof storage */ - - /* Initialize the structure needed for the Proof Assistant */ - initProofStruct(&g_ProofInProgress, nmbrSaveProof, g_proveStatement); - - /* Show the user the statement to be proved */ - print2("You will be working on statement (from \"SHOW STATEMENT %s\"):\n", - g_Statement[g_proveStatement].labelName); - typeStatement(g_proveStatement /*g_showStatement*/, - 1 /*briefFlag*/, - 0 /*commentOnlyFlag*/, - 0 /*texFlag*/, - 0 /*g_htmlFlag*/); - - if (!nmbrElementIn(1, g_ProofInProgress.proof, -(long)'?')) { - print2( - "Note: The proof you are starting with is already complete.\n"); - } else { - - print2( - "Unknown step summary (from \"SHOW NEW_PROOF / UNKNOWN\"):\n"); - /* Automatically display new unknown steps - ???Future - add switch to enable/defeat this */ - typeProof(g_proveStatement, - 1 /*pipFlag*/, - 0 /*startStep*/, - 0 /*endStep*/, - 0 /*endIndent*/, - 1 /*essentialFlag*/, - 0 /*renumberFlag*/, - 1 /*unknownFlag*/, - 0 /*notUnifiedFlag*/, - 0 /*reverseFlag*/, - 0 /*noIndentFlag*/, - 0 /*splitColumn*/, - 0 /*skipRepeatedSteps*/, - 0 /*texFlag*/, - 0 /*g_htmlFlag*/); - } - - if (getMarkupFlag(g_proveStatement, PROOF_DISCOURAGED)) { - /* print2("\n"); */ /* Enable for more emphasis */ - print2( -">>> ?Warning: Modification of this statement's proof is discouraged.\n" - ); - /* print2("\n"); */ /* Enable for more emphasis */ - } - - processUndoStack(NULL, PUS_INIT, "", 0); /* Optional? */ - /* Put the initial proof into the UNDO stack; we don't need - the info string since it won't be undone */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, "", 0); - continue; - } - - - if (cmdMatches("UNDO")) { - processUndoStack(&g_ProofInProgress, PUS_UNDO, "", 0); - g_proofChanged = 1; /* Maybe make this more intelligent some day */ - /* Automatically display new unknown steps - ???Future - add switch to enable/defeat this */ - typeProof(g_proveStatement, - 1 /*pipFlag*/, - 0 /*startStep*/, - 0 /*endStep*/, - 0 /*endIndent*/, - 1 /*essentialFlag*/, - 0 /*renumberFlag*/, - 1 /*unknownFlag*/, - 0 /*notUnifiedFlag*/, - 0 /*reverseFlag*/, - 0 /*noIndentFlag*/, - 0 /*splitColumn*/, - 0 /*skipRepeatedSteps*/, - 0 /*texFlag*/, - 0 /*g_htmlFlag*/); - continue; - } - - if (cmdMatches("REDO")) { - processUndoStack(&g_ProofInProgress, PUS_REDO, "", 0); - g_proofChanged = 1; /* Maybe make this more intelligent some day */ - /* Automatically display new unknown steps - ???Future - add switch to enable/defeat this */ - typeProof(g_proveStatement, - 1 /*pipFlag*/, - 0 /*startStep*/, - 0 /*endStep*/, - 0 /*endIndent*/, - 1 /*essentialFlag*/, - 0 /*renumberFlag*/, - 1 /*unknownFlag*/, - 0 /*notUnifiedFlag*/, - 0 /*reverseFlag*/, - 0 /*noIndentFlag*/, - 0 /*splitColumn*/, - 0 /*skipRepeatedSteps*/, - 0 /*texFlag*/, - 0 /*g_htmlFlag*/); - continue; - } - - if (cmdMatches("UNIFY")) { - m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ - g_proofChangedFlag = 0; - if (cmdMatches("UNIFY STEP")) { - - s = (long)val(g_fullArg[2]); /* Step number */ - if (s > m || s < 1) { - print2("?The step must be in the range from 1 to %ld.\n", m); - continue; - } - - interactiveUnifyStep(s - 1, 1); /* 2nd arg. means print msg if - already unified */ - - /* (The interactiveUnifyStep handles all messages.) */ - /* print2("... */ - - autoUnify(1); - if (g_proofChangedFlag) { - g_proofChanged = 1; /* Cumulative flag */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - } - continue; - } - - /* "UNIFY ALL" */ - if (!switchPos("/ INTERACTIVE")) { - autoUnify(1); - if (!g_proofChangedFlag) { - print2("No new unifications were made.\n"); - } else { - print2( - "Steps were unified. SHOW NEW_PROOF / NOT_UNIFIED to see any remaining.\n"); - g_proofChanged = 1; /* Cumulative flag */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - } - } else { - q = 0; - while (1) { - /* Repeat the unifications over and over until done, since - a later unification may improve the ability of an aborted earlier - one to be done without timeout */ - g_proofChangedFlag = 0; /* This flag is set by autoUnify() and - interactiveUnifyStep() */ - autoUnify(0); - for (s = m - 1; s >= 0; s--) { - interactiveUnifyStep(s, 0); /* 2nd arg. means no msg if already - unified */ - } - autoUnify(1); /* 1 means print congratulations if complete */ - if (!g_proofChangedFlag) { - if (!q) { - print2("No new unifications were made.\n"); - } else { - /* If q=1, then we are in the 2nd or later pass, which means - there was a change in the 1st pass. */ - print2( - "Steps were unified. SHOW NEW_PROOF / NOT_UNIFIED to see any remaining.\n"); - g_proofChanged = 1; /* Cumulative flag */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - } - break; /* while (1) */ - } else { - q = 1; /* Flag that we're starting a 2nd or later pass */ - } - } /* End while (1) */ - } - /* Automatically display new unknown steps - ???Future - add switch to enable/defeat this */ - typeProof(g_proveStatement, - 1 /*pipFlag*/, - 0 /*startStep*/, - 0 /*endStep*/, - 0 /*endIndent*/, - 1 /*essentialFlag*/, - 0 /*renumberFlag*/, - 1 /*unknownFlag*/, - 0 /*notUnifiedFlag*/, - 0 /*reverseFlag*/, - 0 /*noIndentFlag*/, - 0 /*splitColumn*/, - 0 /*skipRepeatedSteps*/, - 0 /*texFlag*/, - 0 /*g_htmlFlag*/); - continue; - } - - if (cmdMatches("MATCH")) { - - maxEssential = -1; /* Default: no maximum */ - i = switchPos("/ MAX_ESSENTIAL_HYP"); - if (i) maxEssential = (long)val(g_fullArg[i + 1]); - - if (cmdMatches("MATCH STEP")) { - - s = (long)val(g_fullArg[2]); /* Step number */ - m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ - if (s > m || s < 1) { - print2("?The step must be in the range from 1 to %ld.\n", m); - continue; - } - if ((g_ProofInProgress.proof)[s - 1] != -(long)'?') { - print2( - "?Step %ld is already assigned. Only unknown steps can be matched.\n", s); - continue; - } - - interactiveMatch(s - 1, maxEssential); - n = nmbrLen(g_ProofInProgress.proof); /* New proof length */ - if (n != m) { - if (s != m) { - printLongLine(cat("Steps ", str((double)s), ":", - str((double)m), " are now ", str((double)(s - m + n)), ":", - str((double)n), ".", - NULL), - "", " "); - } else { - printLongLine(cat("Step ", str((double)m), " is now step ", str((double)n), ".", - NULL), - "", " "); - } - } - - autoUnify(1); - g_proofChanged = 1; /* Cumulative flag */ - /* 1-Nov-2013 nm Why is g_proofChanged set unconditionally above? - Do we need the processUndoStack() call? */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - - continue; - } /* End if MATCH STEP */ - - if (cmdMatches("MATCH ALL")) { - - m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ - - k = 0; - g_proofChangedFlag = 0; - - if (switchPos("/ ESSENTIAL")) { - nmbrLet(&nmbrTmp, nmbrGetEssential(g_ProofInProgress.proof)); - } - - for (s = m; s > 0; s--) { - /* Match only unknown steps */ - if ((g_ProofInProgress.proof)[s - 1] != -(long)'?') continue; - /* Match only essential steps if specified */ - if (switchPos("/ ESSENTIAL")) { - if (!nmbrTmp[s - 1]) continue; - } - - interactiveMatch(s - 1, maxEssential); - if (g_proofChangedFlag) { - k = s; /* Save earliest step changed */ - g_proofChangedFlag = 0; - } - print2("\n"); - } - if (k) { - g_proofChangedFlag = 1; /* Restore it */ - g_proofChanged = 1; /* Cumulative flag */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - print2("Steps %ld and above have been renumbered.\n", k); - } - autoUnify(1); - - continue; - } /* End if MATCH ALL */ - } - - if (cmdMatches("LET")) { - - g_errorCount = 0; - nmbrLet(&nmbrTmp, parseMathTokens(g_fullArg[4], g_proveStatement)); - if (g_errorCount) { - /* Parsing issued error message(s) */ - g_errorCount = 0; - continue; - } - - if (cmdMatches("LET VARIABLE")) { - if (((vstring)(g_fullArg[2]))[0] != '$') { - print2( - "?The target variable must be of the form \"$\", e.g. \"$23\".\n"); - continue; - } - n = (long)val(right(g_fullArg[2], 2)); - if (n < 1 || n > g_pipDummyVars) { - print2("?The target variable must be between $1 and $%ld.\n", - g_pipDummyVars); - continue; - } - - replaceDummyVar(n, nmbrTmp); - - autoUnify(1); - - - g_proofChangedFlag = 1; /* Flag to push 'undo' stack */ - g_proofChanged = 1; /* Cumulative flag */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - - } - - if (cmdMatches("LET STEP")) { - - s = getStepNum(g_fullArg[2], g_ProofInProgress.proof, - 0 /* ALL not allowed */); - if (s == -1) continue; /* Error; message was provided already */ - - /* Check to see if the statement selected is allowed */ - if (!checkMStringMatch(nmbrTmp, s - 1)) { - printLongLine(cat("?Step ", str((double)s), " cannot be unified with \"", - nmbrCvtMToVString(nmbrTmp),"\".", NULL), " ", " "); - continue; - } - - /* Assign the user string */ - nmbrLet((nmbrString **)(&((g_ProofInProgress.user)[s - 1])), nmbrTmp); - - autoUnify(1); - g_proofChangedFlag = 1; /* Flag to push 'undo' stack */ - g_proofChanged = 1; /* Cumulative flag */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - } - /* Automatically display new unknown steps - ???Future - add switch to enable/defeat this */ - typeProof(g_proveStatement, - 1 /*pipFlag*/, - 0 /*startStep*/, - 0 /*endStep*/, - 0 /*endIndent*/, - 1 /*essentialFlag*/, - 0 /*renumberFlag*/, - 1 /*unknownFlag*/, - 0 /*notUnifiedFlag*/, - 0 /*reverseFlag*/, - 0 /*noIndentFlag*/, - 0 /*splitColumn*/, - 0 /*skipRepeatedSteps*/, - 0 /*texFlag*/, - 0 /*g_htmlFlag*/); - continue; - } - - - if (cmdMatches("ASSIGN")) { - s = getStepNum(g_fullArg[1], g_ProofInProgress.proof, - 0 /* ALL not allowed */); - if (s == -1) continue; /* Error; message was provided already */ - - /* 1 means to override usage locks */ - overrideFlag = ( (switchPos("/ OVERRIDE")) ? 1 : 0) - || g_globalDiscouragement == 0; - - /* Get the unique statement matching the g_fullArg[2] pattern */ - k = getStatementNum(g_fullArg[2], - 1/*startStmt*/, - g_proveStatement /*maxStmt*/, - 1/*aAllowed*/, - 1/*pAllowed*/, - 1/*eAllowed*/, - 1/*fAllowed*/, - 1/*efOnlyForMaxStmt*/, - 1/*uniqueFlag*/); - if (k == -1) { - continue; /* Error msg was provided if not unique */ - } - - if (getMarkupFlag(k, USAGE_DISCOURAGED)) { - if (overrideFlag == 0) { - /* print2("\n"); */ /* Enable for more emphasis */ - print2( -">>> ?Error: Attempt to assign a statement whose usage is discouraged.\n"); - print2( - ">>> Use ASSIGN ... / OVERRIDE if you really want to do this.\n"); - /* print2("\n"); */ /* Enable for more emphasis */ - continue; - } else { - /* print2("\n"); */ /* Enable for more emphasis */ - print2( -">>> ?Warning: You are assigning a statement whose usage is discouraged.\n"); - /* print2("\n"); */ /* Enable for more emphasis */ - } - } - - m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ - - /* Check to see that the step is an unknown step */ - if ((g_ProofInProgress.proof)[s - 1] != -(long)'?') { - print2( - "?Step %ld is already assigned. You can only assign unknown steps.\n" - , s); - continue; - } - - /* Check to see if the statement selected is allowed */ - if (!checkStmtMatch(k, s - 1)) { - print2("?Statement \"%s\" cannot be unified with step %ld.\n", - g_Statement[k].labelName, s); - continue; - } - - assignStatement(k /*statement#*/, s - 1 /*step*/); - - n = nmbrLen(g_ProofInProgress.proof); /* New proof length */ - autoUnify(1); - - /* Automatically interact with user if step not unified */ - /* ???We might want to add a setting to defeat this if user doesn't - like it */ - /* Since ASSIGN LAST is often run from a commmand file, don't - interact if / NO_UNIFY is specified, so response is predictable */ - if (switchPos("/ NO_UNIFY") == 0) { - interactiveUnifyStep(s - m + n - 1, 2); /* 2nd arg. means print msg if - already unified */ - } /* if NO_UNIFY flag not set */ - - /* See if it's in another mathbox; if so, let user know */ - assignMathboxInfo(); - if (k > g_mathboxStmt && g_proveStatement > g_mathboxStmt) { - if (k < g_mathboxStart[getMathboxNum(g_proveStatement) - 1]) { - printLongLine(cat("\"", g_Statement[k].labelName, - "\" is in the mathbox for ", - g_mathboxUser[getMathboxNum(k) - 1], ".", - NULL), - "", " "); - } - } - - /* Automatically display new unknown steps - ???Future - add switch to enable/defeat this */ - typeProof(g_proveStatement, - 1 /*pipFlag*/, - 0 /*startStep*/, - 0 /*endStep*/, - 0 /*endIndent*/, - 1 /*essentialFlag*/, - 0 /*renumberFlag*/, - 1 /*unknownFlag*/, - 0 /*notUnifiedFlag*/, - 0 /*reverseFlag*/, - 0 /*noIndentFlag*/, - 0 /*splitColumn*/, - 0 /*skipRepeatedSteps*/, - 0 /*texFlag*/, - 0 /*g_htmlFlag*/); - - g_proofChangedFlag = 1; /* Flag to push 'undo' stack (future) */ - g_proofChanged = 1; /* Cumulative flag */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - continue; - - } /* cmdMatches("ASSIGN") */ - - - if (cmdMatches("REPLACE")) { - /* 1 means to override usage locks */ - overrideFlag = ( (switchPos("/ OVERRIDE")) ? 1 : 0) - || g_globalDiscouragement == 0; - - step = getStepNum(g_fullArg[1], g_ProofInProgress.proof, - 0 /* ALL not allowed */); - if (step == -1) continue; /* Error; message was provided already */ - - /* Get the unique statement matching the g_fullArg[2] pattern */ - stmt = getStatementNum(g_fullArg[2], - 1/*startStmt*/, - g_proveStatement /*maxStmt*/, - 1/*aAllowed*/, - 1/*pAllowed*/, - 0/*eAllowed*/, /* Not implemented (yet?) */ - 0/*fAllowed*/, /* Not implemented (yet?) */ - 1/*efOnlyForMaxStmt*/, - 1/*uniqueFlag*/); - if (stmt == -1) { - continue; /* Error msg was provided if not unique */ - } - - if (getMarkupFlag(stmt, USAGE_DISCOURAGED)) { - if (overrideFlag == 0) { - /* print2("\n"); */ /* Enable for more emphasis */ - print2( -">>> ?Error: Attempt to assign a statement whose usage is discouraged.\n"); - print2( - ">>> Use REPLACE ... / OVERRIDE if you really want to do this.\n"); - /* print2("\n"); */ /* Enable for more emphasis */ - continue; - } else { - /* print2("\n"); */ /* Enable for more emphasis */ - print2( -">>> ?Warning: You are assigning a statement whose usage is discouraged.\n"); - /* print2("\n"); */ /* Enable for more emphasis */ - } - } - - m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ - - /* Set a flag that proof has unknown steps (for autoUnify() call below) */ - if (nmbrElementIn(1, g_ProofInProgress.proof, -(long)'?')) { - p = 1; - } else { - p = 0; - } - - /* Check to see if the statement selected is allowed */ - if (!checkStmtMatch(stmt, step - 1)) { - print2("?Statement \"%s\" cannot be unified with step %ld.\n", - g_Statement[stmt].labelName, step); - continue; - } - - /* Check dummy variable status of step */ - /* For use in message later */ - dummyVarIsoFlag = checkDummyVarIsolation(step - 1); - /* 0=no dummy vars, 1=isolated dummy vars, 2=not isolated*/ - - /* Do the replacement */ - nmbrTmpPtr = replaceStatement(stmt /*statement#*/, - step - 1 /*step*/, - g_proveStatement, - 0,/*scan whole proof to maximize chance of a match*/ - 0/*noDistinct*/, - 1/* try to prove $e's */, - 1/*improveDepth*/, - overrideFlag, - /* Currently REPLACE (not often used) allows other mathboxes - silently; TODO: we may want to notify user like for ASSIGN */ - 1/*mathboxFlag*/); - if (!nmbrLen(nmbrTmpPtr)) { - print2( - "?Hypotheses of statement \"%s\" do not match known proof steps.\n", - g_Statement[stmt].labelName); - continue; - } - - /* Get the subproof at step s */ - q = subproofLen(g_ProofInProgress.proof, step - 1); - deleteSubProof(step - 1); - addSubProof(nmbrTmpPtr, step - q); - - /* Assign known subproofs */ - assignKnownSubProofs(); - /* Initialize remaining steps */ - i = nmbrLen(g_ProofInProgress.proof); - for (j = 0; j < i; j++) { - if (!nmbrLen((g_ProofInProgress.source)[j])) { - initStep(j); - } - } - /* Unify whatever can be unified */ - /* If proof wasn't complete before (p = 1), but is now, print congrats - for user */ - autoUnify((char)p); /* 0 means no "congrats" message */ - - nmbrLet(&nmbrTmpPtr, NULL_NMBRSTRING); /* Deallocate memory */ - - n = nmbrLen(g_ProofInProgress.proof); /* New proof length */ - if (nmbrElementIn(1, g_ProofInProgress.proof, -(long)'?')) { - /* The proof is not complete, so print step numbers that changed */ - if (m == n) { - print2("Step %ld was replaced with statement %s.\n", - step, g_Statement[stmt].labelName); - } else { - if (step != m) { - printLongLine(cat("Step ", str((double)step), - " was replaced with statement ", g_Statement[stmt].labelName, - ". Steps ", str((double)step), ":", - str((double)m), " are now ", str((double)(step - m + n)), ":", - str((double)n), ".", - NULL), - "", " "); - } else { - printLongLine(cat("Step ", str((double)step), - " was replaced with statement ", g_Statement[stmt].labelName, - ". Step ", str((double)m), " is now step ", str((double)n), ".", - NULL), - "", " "); - } - } - } - - g_proofChangedFlag = 1; /* Flag to push 'undo' stack */ - g_proofChanged = 1; /* Cumulative flag */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - - if (dummyVarIsoFlag == 2 && g_proofChangedFlag) { - printLongLine(cat( - "Assignments to shared working variables ($nn) are guesses. If " - "incorrect, UNDO then assign them manually with LET ", - "and try REPLACE again.", - NULL), - "", " "); - } - - - /* Automatically display new unknown steps - ???Future - add switch to enable/defeat this */ - if (g_proofChangedFlag) - typeProof(g_proveStatement, - 1 /*pipFlag*/, - 0 /*startStep*/, - 0 /*endStep*/, - 0 /*endIndent*/, - 1 /*essentialFlag*/, - 0 /*renumberFlag*/, - 1 /*unknownFlag*/, - 0 /*notUnifiedFlag*/, - 0 /*reverseFlag*/, - 0 /*noIndentFlag*/, - 0 /*splitColumn*/, - 0 /*skipRepeatedSteps*/, - 0 /*texFlag*/, - 0 /*g_htmlFlag*/); - - continue; - - } /* REPLACE */ - - - if (cmdMatches("IMPROVE")) { - - improveDepth = 0; /* Depth */ - i = switchPos("/ DEPTH"); - if (i) improveDepth = (long)val(g_fullArg[i + 1]); - if (switchPos("/ NO_DISTINCT")) p = 1; else p = 0; - /* p = 1 means don't try to use statements with $d's */ - searchAlg = 1; /* Default */ - if (switchPos("/ 1")) searchAlg = 1; - if (switchPos("/ 2")) searchAlg = 2; - if (switchPos("/ 3")) searchAlg = 3; - searchUnkSubproofs = 0; - if (switchPos("/ SUBPROOFS")) searchUnkSubproofs = 1; - - mathboxFlag = (switchPos("/ INCLUDE_MATHBOXES") != 0); - assignMathboxInfo(); /* In case it hasn't been assigned yet */ - if (g_proveStatement > g_mathboxStmt) { - /* We're in a mathbox */ - i = getMathboxNum(g_proveStatement); - if (i <= 0) bug(1130); - thisMathboxStartStmt = g_mathboxStart[i - 1]; - } else { - thisMathboxStartStmt = g_mathboxStmt; - } - - /* 1 means to override usage locks */ - overrideFlag = ( (switchPos("/ OVERRIDE")) ? 1 : 0) - || g_globalDiscouragement == 0; - - s = getStepNum(g_fullArg[1], g_ProofInProgress.proof, - 1 /* 1 = "ALL" is permissible; returns 0 */); - if (s == -1) continue; /* Error; message was provided already */ - - if (s != 0) { /* s=0 means ALL */ - m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ - - /* Get the subproof at step s */ - q = subproofLen(g_ProofInProgress.proof, s - 1); - nmbrLet(&nmbrTmp, nmbrSeg(g_ProofInProgress.proof, s - q + 1, s)); - - /*???Shouldn't this be just known?*/ - /* Check to see that the subproof has an unknown step. */ - if (!nmbrElementIn(1, nmbrTmp, -(long)'?')) { - print2( - "?Step %ld already has a proof and cannot be improved.\n", - s); - continue; - } - - /* Check dummy variable status of step */ - dummyVarIsoFlag = checkDummyVarIsolation(s - 1); - /* 0=no dummy vars, 1=isolated dummy vars, 2=not isolated*/ - if (dummyVarIsoFlag == 2) { - print2( - "?Step %ld target has shared dummy variables and cannot be improved.\n", s); - continue; /* Don't try to improve - dummy variables that aren't isolated */ - } - - if (dummyVarIsoFlag == 0) { /* No dummy vars */ - /* Only use proveFloating if no dummy vars */ - nmbrTmpPtr = proveFloating((g_ProofInProgress.target)[s - 1], - g_proveStatement, improveDepth, s - 1, (char)p/*NO_DISTINCT*/, - overrideFlag, - mathboxFlag); - } else { - nmbrTmpPtr = NULL_NMBRSTRING; /* Initialize */ - } - if (!nmbrLen(nmbrTmpPtr)) { - /* A proof for the step was not found with proveFloating(). */ - - /* Next, try REPLACE algorithm */ - if (searchAlg == 2 || searchAlg == 3) { - nmbrTmpPtr = proveByReplacement(g_proveStatement, - s - 1/*prfStep*/, /* 0 means step 1 */ - (char)p/*NO_DISTINCT*/, /* 1 means don't try stmts with $d's */ - dummyVarIsoFlag, - (char)(searchAlg - 2), /*0=proveFloat for $fs, 1=$e's also */ - improveDepth, - overrideFlag, - mathboxFlag); - } - if (!nmbrLen(nmbrTmpPtr)) { - print2("A proof for step %ld was not found.\n", s); - /* REPLACE algorithm also failed */ - continue; - } - } - - /* If q=1, subproof must be an unknown step, so don't bother to - delete it */ - /*???Won't q always be 1 here?*/ - if (q > 1) deleteSubProof(s - 1); - addSubProof(nmbrTmpPtr, s - q); - assignKnownSteps(s - q, nmbrLen(nmbrTmpPtr)); - nmbrLet(&nmbrTmpPtr, NULL_NMBRSTRING); - - n = nmbrLen(g_ProofInProgress.proof); /* New proof length */ - if (m == n) { - print2("A 1-step proof was found for step %ld.\n", s); - } else { - if (s != m || q != 1) { - printLongLine(cat("A ", str((double)(n - m + 1)), - "-step proof was found for step ", str((double)s), - ". Steps ", str((double)s), ":", - str((double)m), " are now ", str((double)(s - q + 1 - m + n)), - ":", str((double)n), ".", - NULL), - "", " "); - } else { - printLongLine(cat("A ", str((double)(n - m + 1)), - "-step proof was found for step ", str((double)s), - ". Step ", str((double)m), " is now step ", str((double)n), ".", - NULL), - "", " "); - } - } - - autoUnify(1); /* To get 'congrats' message if proof complete */ - g_proofChanged = 1; /* Cumulative flag */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - - /* End if s != 0 i.e. not IMPROVE ALL */ - } else { - /* Here, getStepNum() returned 0, meaning ALL */ - - if (!nmbrElementIn(1, g_ProofInProgress.proof, -(long)'?')) { - print2("The proof is already complete.\n"); - continue; - } - - n = 0; /* Earliest step that changed */ - - g_proofChangedFlag = 0; - - for (improveAllIter = 1; improveAllIter <= 4; improveAllIter++) { - if (improveAllIter == 1 && (searchAlg == 2 || searchAlg == 3)) - print2("Pass 1: Trying to match cut-free statements...\n"); - if (improveAllIter == 2) { - if (searchAlg == 2) { - print2("Pass 2: Trying to match all statements...\n"); - } else { - print2( -"Pass 2: Trying to match all statements, with cut-free hypothesis matches...\n" - ); - } - } - if (improveAllIter == 3 && searchUnkSubproofs) - print2("Pass 3: Trying to replace incomplete subproofs...\n"); - if (improveAllIter == 4) { - if (searchUnkSubproofs) { - print2("Pass 4: Repeating pass 1...\n"); - } else { - print2("Pass 3: Repeating pass 1...\n"); - } - } - /* improveAllIter = 1: run proveFloating only */ - /* improveAllIter = 2: run proveByReplacement on unknown steps */ - /* improveAllIter = 3: run proveByReplacement on steps with - incomplete subproofs */ - /* improveAllIter = 4: if something changed, run everything again */ - - if (improveAllIter == 3 && !searchUnkSubproofs) continue; - - m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ - - for (s = m; s > 0; s--) { - - proofStepUnk = ((g_ProofInProgress.proof)[s - 1] == -(long)'?') - ? 1 : 0; - - /* I think this is really too conservative, even - with the old algorithm, but keep it to imitate the old one */ - if (improveAllIter == 1 || searchAlg == 1) { - /* If the step is known and unified, don't do it, since nothing - would be accomplished. */ - if (!proofStepUnk) { - if (nmbrEq((g_ProofInProgress.target)[s - 1], - (g_ProofInProgress.source)[s - 1])) continue; - } - } - - /* Get the subproof at step s */ - q = subproofLen(g_ProofInProgress.proof, s - 1); - if (proofStepUnk && q != 1) bug(1120); /* Consistency check */ - nmbrLet(&nmbrTmp, nmbrSeg(g_ProofInProgress.proof, s - q + 1, s)); - - /* Improve only subproofs with unknown steps */ - if (!nmbrElementIn(1, nmbrTmp, -(long)'?')) continue; - - nmbrLet(&nmbrTmp, NULL_NMBRSTRING); /* No longer needed - dealloc */ - - /* Check dummy variable status of step */ - dummyVarIsoFlag = checkDummyVarIsolation(s - 1); - /* 0=no dummy vars, 1=isolated dummy vars, 2=not isolated*/ - if (dummyVarIsoFlag == 2) continue; /* Don't try to improve - dummy variables that aren't isolated */ - - if (dummyVarIsoFlag == 0 - && (improveAllIter == 1 - || improveAllIter == 4)) { - /* No dummy vars */ - /* Only use proveFloating if no dummy vars */ - nmbrTmpPtr = proveFloating((g_ProofInProgress.target)[s - 1], - g_proveStatement, improveDepth, s - 1, - (char)p/*NO_DISTINCT*/, - overrideFlag, - mathboxFlag); - } else { - nmbrTmpPtr = NULL_NMBRSTRING; /* Init */ - } - if (!nmbrLen(nmbrTmpPtr)) { - /* A proof for the step was not found with proveFloating(). */ - - /* Next, try REPLACE algorithm */ - if ((searchAlg == 2 || searchAlg == 3) - && ((improveAllIter == 2 && proofStepUnk) - || (improveAllIter == 3 && !proofStepUnk) - /*|| improveAllIter == 4*/)) { - nmbrTmpPtr = proveByReplacement(g_proveStatement, - s - 1/*prfStep*/, /* 0 means step 1 */ - (char)p/*NO_DISTINCT*/, /* 1 means don't try stmts w/ $d's */ - dummyVarIsoFlag, - (char)(searchAlg - 2),/*searchMethod: 0 or 1*/ - improveDepth, - overrideFlag, - mathboxFlag); - - } - if (!nmbrLen(nmbrTmpPtr)) { - /* REPLACE algorithm also failed */ - continue; - } - } - - /* If q=1, subproof must be an unknown step, so don't bother to - delete it */ - if (q > 1) deleteSubProof(s - 1); - addSubProof(nmbrTmpPtr, s - q); - assignKnownSteps(s - q, nmbrLen(nmbrTmpPtr)); - print2("A proof of length %ld was found for step %ld.\n", - nmbrLen(nmbrTmpPtr), s); - if (nmbrLen(nmbrTmpPtr) || q != 1) n = s - q + 1; - /* Save earliest step changed */ - nmbrLet(&nmbrTmpPtr, NULL_NMBRSTRING); - g_proofChangedFlag = 1; - s = s - q + 1; /* Adjust step position to account for deleted subpr */ - } /* Next step s */ - - if (g_proofChangedFlag) { - autoUnify(0); /* 0 = No 'Congrats' if done */ - } - - if (!g_proofChangedFlag - && ( (improveAllIter == 2 && !searchUnkSubproofs) - || improveAllIter == 3 - || searchAlg == 1)) { - print2("No new subproofs were found.\n"); - break; /* out of improveAllIter loop */ - } - if (g_proofChangedFlag) { - g_proofChanged = 1; /* Cumulative flag */ - } - - if (!nmbrElementIn(1, g_ProofInProgress.proof, -(long)'?')) { - break; /* Proof is complete */ - } - - if (searchAlg == 1) break; /* Old algorithm does just 1st pass */ - - } /* Next improveAllIter */ - - if (g_proofChangedFlag) { - if (n > 0) { - /* n is the first step number changed. It will be 0 if - the numbering didn't change e.g. a $e was assigned to - an unknown step. */ - print2("Steps %ld and above have been renumbered.\n", n); - } - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - } - if (!nmbrElementIn(1, g_ProofInProgress.proof, -(long)'?')) { - /* This is a redundant call; its purpose is just to give - the message if the proof is complete */ - autoUnify(1); /* 1 = 'Congrats' if done */ - } - - } /* End if IMPROVE ALL */ - - /* Automatically display new unknown steps - ???Future - add switch to enable/defeat this */ - if (g_proofChangedFlag) - typeProof(g_proveStatement, - 1 /*pipFlag*/, - 0 /*startStep*/, - 0 /*endStep*/, - 0 /*endIndent*/, - 1 /*essentialFlag*/, - 0 /*renumberFlag*/, - 1 /*unknownFlag*/, - 0 /*notUnifiedFlag*/, - 0 /*reverseFlag*/, - 0 /*noIndentFlag*/, - 0 /*splitColumn*/, - 0 /*skipRepeatedSteps*/, - 0 /*texFlag*/, - 0 /*g_htmlFlag*/); - - continue; - - } /* cmdMatches("IMPROVE") */ - - - if (cmdMatches("MINIMIZE_WITH")) { - - printTime = 0; - if (switchPos("/ TIME") != 0) { - printTime = 1; - } - if (printTime == 1) { - getRunTime(&timeIncr); /* This call just resets the time */ - } - - prntStatus = 0; /* Status flag to help determine messages - 0 = no statement was matched during scan (mainly for - error message if user typo in label field) - 1 = a statement was matched but no shorter proof - 2 = shorter proof found */ - verboseMode = (switchPos("/ VERBOSE") != 0); /* Verbose mode */ - - /* If no wildcard was used, switch to non-verbose mode - since there is no point to it and an annoying extra blank line - results */ - if (!(instr(1, g_fullArg[1], "*") || instr(1, g_fullArg[1], "?"))) i = 1; - - mayGrowFlag = (switchPos("/ MAY_GROW") != 0); - /* Mode to replace even if it doesn't reduce proof length */ - exceptPos = switchPos("/ EXCEPT"); /* Statement match to skip */ - - allowNewAxiomsMatchPos = switchPos("/ ALLOW_NEW_AXIOMS"); - if (allowNewAxiomsMatchPos != 0) { - let(&allowNewAxiomsMatchList, g_fullArg[allowNewAxiomsMatchPos + 1]); - } else { - let(&allowNewAxiomsMatchList, ""); - } - - noNewAxiomsMatchPos = switchPos("/ NO_NEW_AXIOMS_FROM"); - if (noNewAxiomsMatchPos != 0) { - let(&noNewAxiomsMatchList, g_fullArg[noNewAxiomsMatchPos + 1]); - } else { - let(&noNewAxiomsMatchList, ""); - } - - forbidMatchPos = switchPos("/ FORBID"); - if (forbidMatchPos != 0) { - let(&forbidMatchList, g_fullArg[forbidMatchPos + 1]); - } else { - let(&forbidMatchList, ""); - } - - mathboxFlag = (switchPos("/ INCLUDE_MATHBOXES") != 0); - - /* Flag to override any "usage locks" placed in the comment markup */ - overrideFlag = (switchPos("/ OVERRIDE") != 0) - || g_globalDiscouragement == 0; - - /* If a single statement is specified, don't bother to do certain - actions or print some of the messages */ - hasWildCard = 0; - /* Set hasWildCard only when there are potentially > 1 matches */ - if (strpbrk(g_fullArg[1], "*?~%,") != NULL) { - /* (See matches() function for processing of these) - "*" 0 or more char match - "?" 1 char match - "=" Most recent PROVE command statement = one statement match - "~" Statement range - "%" List of modified statements - "#" Internal statement number = one statement match - "@" Web page statement number = one statement match - "," Comma-separated fields */ - hasWildCard = 1; - } - - g_proofChangedFlag = 0; - - /* Always scan statements in current mathbox, even if - "/ INCLUDE_MATHBOXES" is omitted */ - - assignMathboxInfo(); /* In case it hasn't been assigned yet */ - if (g_proveStatement > g_mathboxStmt) { - /* We're in a mathbox */ - i = getMathboxNum(g_proveStatement); - if (i <= 0) bug(1130); - thisMathboxStartStmt = g_mathboxStart[i - 1]; - } else { - thisMathboxStartStmt = g_mathboxStmt; - } - - copyProofStruct(&saveOrigProof, g_ProofInProgress); - - /* 12-Sep-2016 nm TODO replace this w/ compressedProofSize */ - /* Get the current (original) compressed proof length - to compare it when a shorter non-compressed proof is found, to see - if the compressed proof also decreased in size */ - nmbrLet(&nmbrSaveProof, g_ProofInProgress.proof); /* Redundant? */ - nmbrLet(&nmbrSaveProof, nmbrSquishProof(g_ProofInProgress.proof)); - /* We only care about length; str1 will be discarded */ - let(&str1, compressProof(nmbrSaveProof, - g_proveStatement, /* statement being proved */ - 0 /* Normal (not "fast") compression */ - )); - origCompressedLength = (long)strlen(str1); - print2("Bytes refer to compressed proof size, " - "steps to uncompressed length.\n"); - - /* Scan forward, then reverse, then pick best result */ - for (forwRevPass = 1; forwRevPass <= 2; forwRevPass++) { - - if (forwRevPass == 1) { - if (hasWildCard) print2("Scanning forward through statements...\n"); - forwFlag = 1; - } else { - /* If growth allowed, don't bother with reverse pass */ - if (mayGrowFlag) break; - /* If nothing was found on forward pass, don't bother with rev pass */ - if (!g_proofChangedFlag) break; - /* If only one statement was specified, don't bother with rev pass */ - if (!hasWildCard) break; - print2("Scanning backward through statements...\n"); - forwFlag = 0; - /* Save proof and length from 1st pass; re-initialize */ - copyProofStruct(&save1stPassProof, g_ProofInProgress); - forwardLength = nmbrLen(g_ProofInProgress.proof); - forwardCompressedLength = oldCompressedLength; - /* Start over from original proof */ - copyProofStruct(&g_ProofInProgress, saveOrigProof); - } - - copyProofStruct(&saveProofForReverting, g_ProofInProgress); - - oldCompressedLength = origCompressedLength; - - /* If forwFlag is 0, scan from g_proveStatement-1 to 1 - If forwFlag is 1, scan from 1 to g_proveStatement-1 */ - for (k = forwFlag ? 1 : (g_proveStatement - 1); - k * (forwFlag ? 1 : -1) < (forwFlag ? g_proveStatement : 0); - k = k + (forwFlag ? 1 : -1)) { - if (!mathboxFlag && k >= g_mathboxStmt && k < thisMathboxStartStmt) { - continue; - } - - if (g_Statement[k].type != (char)p_ && g_Statement[k].type != (char)a_) - continue; - if (!matchesList(g_Statement[k].labelName, g_fullArg[1], '*', '?')) - continue; - - if (exceptPos != 0) { - /* Skip any match to the EXCEPT argument */ - if (matchesList(g_Statement[k].labelName, g_fullArg[exceptPos + 1], - '*', '?')) - continue; - } - - if (forbidMatchList[0]) { /* User provided a /FORBID list */ - /* First, we check to make sure we're not trying a statement - in the forbidMatchList directly (traceProof() won't find - this) */ - if (matchesList(g_Statement[k].labelName, forbidMatchList, '*', '?')) - continue; - } - - /* Check to see if statement comment specified a usage - restriction */ - if (!overrideFlag) { - if (getMarkupFlag(k, USAGE_DISCOURAGED)) { - continue; - } - } - - /* Print individual labels */ - if (prntStatus == 0) prntStatus = 1; /* Matched at least one */ - - m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ - nmbrLet(&nmbrTmp, g_ProofInProgress.proof); - minimizeProof(k /* trial statement */, - g_proveStatement /* statement being proved in MM-PA */, - (char)mayGrowFlag /* mayGrowFlag */); - - n = nmbrLen(g_ProofInProgress.proof); /* New proof length */ - if (!nmbrEq(nmbrTmp, g_ProofInProgress.proof)) { - /* The proof got shorter (or it changed if MAY_GROW) */ - - /* Because of the slow speed of traceBack(), - we only want to check the /FORBID list in the relatively - rare case where a minimization occurred. If the FORBID - list is matched, we then need to revert back to the - original proof. */ - if (forbidMatchList[0]) { /* User provided a /FORBID list */ - if (g_Statement[k].type == (char)p_) { - /* We only care about tracing $p statements */ - /* See if the TRACE_BACK list includes a match to the - /FORBID argument */ - if (traceProof(k, - 0, /*essentialFlag*/ - 0, /*axiomFlag*/ - forbidMatchList, - "", /*traceToList*/ - 1 /* testOnlyFlag */)) { - /* Yes, a forbidden statement occurred in traceProof() */ - /* Revert the proof to before minimization */ - copyProofStruct(&g_ProofInProgress, saveProofForReverting); - /* Skip further printout and flag setting */ - continue; /* Continue at 'Next k' loop end below */ - } - } - } - - - /* Because of the slow speed of traceBack(), - we only want to check the /NO_NEW_AXIOMS_FROM list in the - relatively rare case where a minimization occurred. If the - NO_NEW_AXIOMS_FROM condition applies, we then need to revert - back to the original proof. */ - if (n == n + 0) { /* By default, no new axioms are permitted */ - /*if (noNewAxiomsMatchList[0]) {*/ /* User provided /NO_NEW_AXIOMS_FROM */ - /* If we haven't called trace yet for the theorem being proved, - do it now. */ - if (traceProofFlags[0] == 0) { - - /* traceProofWork() was written to use the SAVEd proof and - not the proof in progress. In order to use the proof in - progress, we temporarily put the proof in progress into the - (SAVEd) statement structure to trick traceProofWork() into using - the proof in progress instead of the SAVEd proof */ - /* Use the version of the proof in progress that existed *before* the - MINIMIZE_WITH command was invoked */ - nmbrLet(&nmbrSaveProof, nmbrSquishProof(saveProofForReverting.proof)); - let(&str1, compressProof(nmbrSaveProof, - g_proveStatement, /* statement being proved in MM-PA */ - 0 /* Normal (not "fast") compression */ - )); - saveZappedProofSectionPtr - = g_Statement[g_proveStatement].proofSectionPtr; - saveZappedProofSectionLen - = g_Statement[g_proveStatement].proofSectionLen; - saveZappedProofSectionChanged - = g_Statement[g_proveStatement].proofSectionChanged; - /* Set flag that this is not the original source */ - g_Statement[g_proveStatement].proofSectionChanged = 1; - /* str1 has the new compressed trial proof after minimization */ - /* Put space before and after to satisfy "space around token" - requirement, to prevent possible error messages, and also - add "$." since parseCompressedProof() expects it */ - let(&str1, cat(" ", str1, " $.", NULL)); - /* Don't include the "$." in the length */ - g_Statement[g_proveStatement].proofSectionLen - = (long)strlen(str1) - 2; - /* We don't deallocate previous proofSectionPtr content because - we will recover it after the verifyProof() */ - g_Statement[g_proveStatement].proofSectionPtr = str1; - - traceProofWork(g_proveStatement, - 1 /*essentialFlag*/, - "", /*traceToList*/ - &traceProofFlags, /* y/n list of flags */ - &nmbrTmp /* unproved list - ignored */); - nmbrLet(&nmbrTmp, NULL_NMBRSTRING); /* Discard */ - - /* Restore the SAVEd proof */ - g_Statement[g_proveStatement].proofSectionPtr - = saveZappedProofSectionPtr; - g_Statement[g_proveStatement].proofSectionLen - = saveZappedProofSectionLen; - g_Statement[g_proveStatement].proofSectionChanged - = saveZappedProofSectionChanged; - } - let(&traceTrialFlags, ""); - traceProofWork(k, /* The trial statement */ - 1 /*essentialFlag*/, - "", /*traceToList*/ - &traceTrialFlags, /* Y/N list of flags */ - &nmbrTmp /* unproved list - ignored */); - nmbrLet(&nmbrTmp, NULL_NMBRSTRING); /* Discard */ - j = 1; /* 1 = ok to use trial statement */ - for (i = 1; i < g_proveStatement; i++) { - if (g_Statement[i].type != (char)a_) continue; /* Not $a */ - if (traceProofFlags[i] == 'Y') continue; - /* If the axiom is already used by the proof, we - don't care if the trial statement depends on it */ - if (matchesList(g_Statement[i].labelName, allowNewAxiomsMatchList, - '*', '?') == 1 - && - matchesList(g_Statement[i].labelName, noNewAxiomsMatchList, - '*', '?') != 1) { - /* If the axiom is in the list to allow and not in the list - to disallow, we don't care if the trial statement depends - on it */ - continue; - } - if (traceTrialFlags[i] == 'Y') { - /* The trial statement uses an axiom that the current - proof should avoid, so we abort it */ - j = 0; /* 0 = don't use trial statement */ - break; - } - } /* next i */ - if (j == 0) { - /* A forbidden axiom is used by the trial proof */ - /* Revert the proof to before minimization */ - copyProofStruct(&g_ProofInProgress, saveProofForReverting); - /* Skip further printout and flag setting */ - continue; /* Continue at 'Next k' loop end below */ - } - } /* end if (true) */ - - - /* Make sure the compressed proof length - decreased, otherwise revert. Also, we will use the - compressed proof for the $d check next */ - if (nmbrLen(g_Statement[k].reqDisjVarsA) || !mayGrowFlag) { - nmbrLet(&nmbrSaveProof, g_ProofInProgress.proof); - nmbrLet(&nmbrSaveProof, nmbrSquishProof(g_ProofInProgress.proof)); - let(&str1, compressProof(nmbrSaveProof, - g_proveStatement, /* statement being proved in MM-PA */ - 0 /* Normal (not "fast") compression */ - )); - newCompressedLength = (long)strlen(str1); - if (!mayGrowFlag && newCompressedLength > oldCompressedLength) { - /* The compressed proof length increased, so don't use it. - (If it stayed the same, we will use it because the uncompressed - length did decrease.) */ - /* Revert the proof to before minimization */ - if (verboseMode) { - print2( - "Reverting \"%s\": Uncompressed steps: old = %ld, new = %ld\n", - g_Statement[k].labelName, - m, n ); - print2( - " but compressed size: old = %ld bytes, new = %ld bytes\n", - oldCompressedLength, newCompressedLength); - } - copyProofStruct(&g_ProofInProgress, saveProofForReverting); - /* Skip further printout and flag setting */ - continue; /* Continue at 'Next k' loop end below */ - } - } /* if (nmbrLen(g_Statement[k].reqDisjVarsA) || !mayGrowFlag) */ - - /* Make sure there are no $d violations, otherwise revert */ - /* This requires the str1 from above */ - if (nmbrLen(g_Statement[k].reqDisjVarsA)) { - /* There is currently no way to verify a proof that doesn't - read and parse the source directly. This should be - changed in the future to make the program more modular. But - for now, we temporarily zap the source with new compressed - proof and see if there are any $d violations by looking at - the error message output */ - saveZappedProofSectionPtr - = g_Statement[g_proveStatement].proofSectionPtr; - saveZappedProofSectionLen - = g_Statement[g_proveStatement].proofSectionLen; - - saveZappedProofSectionChanged - = g_Statement[g_proveStatement].proofSectionChanged; - /* Set flag that this is not the original source */ - g_Statement[g_proveStatement].proofSectionChanged = 1; - /* str1 has the new compressed trial proof after minimization */ - /* Put space before and after to satisfy "space around token" - requirement, to prevent possible error messages, and also - add "$." since parseCompressedProof() expects it */ - let(&str1, cat(" ", str1, " $.", NULL)); - /* Don't include the "$." in the length */ - g_Statement[g_proveStatement].proofSectionLen = (long)strlen(str1) - 2; - /* We don't deallocate previous proofSectionPtr content because - we will recover it after the verifyProof() */ - g_Statement[g_proveStatement].proofSectionPtr = str1; - - g_outputToString = 1; /* Suppress error messages */ - /* parseProof, verifyProof, cleanWkrProof must be - called in sequence to assign the g_WrkProof structure, verify - the proof, and deallocate the g_WrkProof structure. Either none - of them or all of them must be called. */ - parseProof(g_proveStatement); - verifyProof(g_proveStatement); /* Must be called even if error - occurred in parseProof, to init RPN stack - for cleanWrkProof() */ - /* don't change proof if there is an error - (which could be pre-existing). */ - i = (g_WrkProof.errorSeverity > 1); - /**** Here we look at the screen output sent to a string. - This is rather crude, and someday the ability to - check proofs and $d violations should be modularized *****/ - j = instr(1, g_printString, - "There is a disjoint variable ($d) violation"); - g_outputToString = 0; /* Restore to normal output */ - let(&g_printString, ""); /* Clear out the stored error messages */ - cleanWrkProof(); /* Deallocate verifyProof storage */ - g_Statement[g_proveStatement].proofSectionPtr - = saveZappedProofSectionPtr; - g_Statement[g_proveStatement].proofSectionLen - = saveZappedProofSectionLen; - g_Statement[g_proveStatement].proofSectionChanged - = saveZappedProofSectionChanged; - if (i != 0 || j != 0) { - /* There was a verify proof error (j!=0) or $d violation (i!=0) - so don't used minimized proof */ - /* Revert the proof to before minimization */ - copyProofStruct(&g_ProofInProgress, saveProofForReverting); - /* Skip further printout and flag setting */ - continue; /* Continue at 'Next k' loop end below */ - } - } /* if (nmbrLen(g_Statement[k].reqDisjVarsA)) */ - - /* Warn user if a discouraged statement is overridden */ - if (getMarkupFlag(k, USAGE_DISCOURAGED)) { - if (!overrideFlag) bug(1126); - /* print2("\n"); */ /* Enable for more emphasis */ - print2( - ">>> ?Warning: Overriding discouraged usage of \"%s\".\n", - g_Statement[k].labelName); - /* print2("\n"); */ /* Enable for more emphasis */ - } - - if (!mayGrowFlag) { - /* Note: this is the length BEFORE indentation and wrapping, - so it is less than SHOW PROOF ... /SIZE */ - if (newCompressedLength < oldCompressedLength) { - print2( - "Proof of \"%s\" decreased from %ld to %ld bytes using \"%s\".\n", - g_Statement[g_proveStatement].labelName, - oldCompressedLength, newCompressedLength, - g_Statement[k].labelName); - } else { - if (newCompressedLength > oldCompressedLength) bug(1123); - print2( - "Proof of \"%s\" stayed at %ld bytes using \"%s\".\n", - g_Statement[g_proveStatement].labelName, - oldCompressedLength, - g_Statement[k].labelName); - print2( - " (Uncompressed steps decreased from %ld to %ld).\n", - m, n ); - } - /* (We don't care about compressed length if MAY_GROW) */ - oldCompressedLength = newCompressedLength; - } - - if (n < m && (mayGrowFlag || verboseMode)) { - print2( - "%sProof of \"%s\" decreased from %ld to %ld steps using \"%s\".\n", - (mayGrowFlag ? "" : " "), - g_Statement[g_proveStatement].labelName, - m, n, g_Statement[k].labelName); - } - /* MAY_GROW possibility */ - if (m < n) print2( - "Proof of \"%s\" increased from %ld to %ld steps using \"%s\".\n", - g_Statement[g_proveStatement].labelName, - m, n, g_Statement[k].labelName); - /* MAY_GROW possibility */ - if (m == n) print2( - "Proof of \"%s\" remained at %ld steps using \"%s\".\n", - g_Statement[g_proveStatement].labelName, - m, g_Statement[k].labelName); - - /* See if it's in another mathbox; if so, let user know */ - assignMathboxInfo(); - if (k > g_mathboxStmt && g_proveStatement > g_mathboxStmt) { - if (k < g_mathboxStart[getMathboxNum(g_proveStatement) - 1]) { - printLongLine(cat("\"", g_Statement[k].labelName, - "\" is in the mathbox for ", - g_mathboxUser[getMathboxNum(k) - 1], ".", - NULL), - " ", " "); - } - } - - prntStatus = 2; /* Found one */ - g_proofChangedFlag = 1; - - /* Save the changed proof in case we have to restore - it later */ - copyProofStruct(&saveProofForReverting, g_ProofInProgress); - - } - - } /* Next k (statement) */ - - if (g_proofChangedFlag && forwRevPass == 2) { - /* Check whether the reverse pass found a better proof than the - forward pass */ - if (verboseMode) { - print2( -"Forward vs. backward: %ld vs. %ld bytes; %ld vs. %ld steps\n", - forwardCompressedLength, - oldCompressedLength, - forwardLength, - nmbrLen(g_ProofInProgress.proof)); - } - if (oldCompressedLength < forwardCompressedLength - || (oldCompressedLength == forwardCompressedLength && - nmbrLen(g_ProofInProgress.proof) < forwardLength)) { - /* The reverse pass was better */ - print2("The backward scan results were used.\n"); - } else { - copyProofStruct(&g_ProofInProgress, save1stPassProof); - print2("The forward scan results were used.\n"); - } - } - - } /* next forwRevPass */ - - if (prntStatus == 1 && !mayGrowFlag) - print2("No shorter proof was found.\n"); - if (prntStatus == 1 && mayGrowFlag) - print2("The proof was not changed.\n"); - if (!prntStatus /* && !noDistinctFlag */) - print2("?No earlier %s$p or $a label matches \"%s\".\n", - (overrideFlag ? "" : "(allowed) "), - g_fullArg[1]); - if (!mathboxFlag && g_proveStatement >= g_mathboxStmt) { - print2( - "(Other mathboxes were not checked. Use / INCLUDE_MATHBOXES to include them.)\n"); - } - - if (printTime == 1) { - getRunTime(&timeIncr); - print2("MINIMIZE_WITH run time = %7.2f sec for \"%s\"\n", timeIncr, - g_Statement[g_proveStatement].labelName); - } - - let(&str1, ""); /* Deallocate memory */ - nmbrLet(&nmbrSaveProof, NULL_NMBRSTRING); /* Deallocate memory */ - - /* Clear these Y/N trace strings unconditionally since new axioms are no - longer allowed by default, so they may become set regardless of - qualifiers */ - let(&traceProofFlags, ""); /* Deallocate memory */ - let(&traceTrialFlags, ""); /* Deallocate memory */ - - if (allowNewAxiomsMatchList[0]) { /* User provided /NO_NEW_AXIOMS_FROM list */ - let(&allowNewAxiomsMatchList, ""); /* Deallocate memory */ - } - - if (noNewAxiomsMatchList[0]) { /* User provided /ALLOW_NEW_AXIOMS list */ - let(&noNewAxiomsMatchList, ""); /* Deallocate memory */ - } - - if (forbidMatchList[0]) { /* User provided a /FORBID list */ - let(&forbidMatchList, ""); /* Deallocate memory */ - } - - deallocProofStruct(&saveProofForReverting); /* Deallocate memory */ - deallocProofStruct(&saveOrigProof); /* Deallocate memory */ - deallocProofStruct(&save1stPassProof); /* Deallocate memory */ - - if (g_proofChangedFlag) { - g_proofChanged = 1; /* Cumulative flag */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - } - continue; - - } /* End if MINIMIZE_WITH */ - - - if (cmdMatches("EXPAND")) { - - g_proofChangedFlag = 0; - nmbrLet(&nmbrSaveProof, g_ProofInProgress.proof); - s = compressedProofSize(nmbrSaveProof, g_proveStatement); - - for (i = g_proveStatement - 1; i >= 1; i--) { - if (g_Statement[i].type != (char)p_) continue; /* Not a $p */ - if (!matchesList(g_Statement[i].labelName, g_fullArg[1], '*', '?')) { - continue; - } - sourceStatement = i; - - nmbrTmp = expandProof(nmbrSaveProof, sourceStatement); - - if (!nmbrEq(nmbrTmp, nmbrSaveProof)) { - g_proofChangedFlag = 1; - n = compressedProofSize(nmbrTmp, g_proveStatement); - printLongLine(cat("Proof of \"", - g_Statement[g_proveStatement].labelName, "\" ", - (s == n ? cat("stayed at ", str((double)s), NULL) - : cat((s < n ? "increased from " : " decreased from "), - str((double)s), " to ", str((double)n), NULL)), - " bytes after expanding \"", - g_Statement[sourceStatement].labelName, "\".", NULL), " ", " "); - s = n; - nmbrLet(&nmbrSaveProof, nmbrTmp); - } - } - - if (g_proofChangedFlag) { - g_proofChanged = 1; /* Cumulative flag */ - /* Clear the existing proof structure */ - deallocProofStruct(&g_ProofInProgress); - /* Then rebuild proof structure from new proof nmbrTmp */ - initProofStruct(&g_ProofInProgress, nmbrTmp, g_proveStatement); - /* Save the new proof structure on the undo stack */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - } else { - print2("No expansion occurred. The proof was not changed.\n"); - } - nmbrLet(&nmbrSaveProof, NULL_NMBRSTRING); - nmbrLet(&nmbrTmp, NULL_NMBRSTRING); - continue; - } /* EXPAND */ - - - if (cmdMatches("DELETE STEP") || (cmdMatches("DELETE ALL"))) { - - if (cmdMatches("DELETE STEP")) { - s = (long)val(g_fullArg[2]); /* Step number */ - } else { - s = nmbrLen(g_ProofInProgress.proof); - } - if ((g_ProofInProgress.proof)[s - 1] == -(long)'?') { - print2("?Step %ld is unknown and cannot be deleted.\n", s); - continue; - } - m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ - if (s > m || s < 1) { - print2("?The step must be in the range from 1 to %ld.\n", m); - continue; - } - - deleteSubProof(s - 1); - n = nmbrLen(g_ProofInProgress.proof); /* New proof length */ - if (m == n) { - print2("Step %ld was deleted.\n", s); - } else { - if (n > 1) { - printLongLine(cat("A ", str((double)(m - n + 1)), - "-step subproof at step ", str((double)s), - " was deleted. Steps ", str((double)s), ":", - str((double)m), " are now ", str((double)(s - m + n)), ":", - str((double)n), ".", - NULL), - "", " "); - } else { - print2("The entire proof was deleted.\n"); - } - } - - /* Automatically display new unknown steps - ???Future - add switch to enable/defeat this */ - typeProof(g_proveStatement, - 1 /*pipFlag*/, - 0 /*startStep*/, - 0 /*endStep*/, - 0 /*endIndent*/, - 1 /*essentialFlag*/, - 0 /*renumberFlag*/, - 1 /*unknownFlag*/, - 0 /*notUnifiedFlag*/, - 0 /*reverseFlag*/, - 0 /*noIndentFlag*/, - 0 /*splitColumn*/, - 0 /*skipRepeatedSteps*/, - 0 /*texFlag*/, - 0 /*g_htmlFlag*/); - - g_proofChanged = 1; /* Cumulative flag */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - - continue; - - } - - if (cmdMatches("DELETE FLOATING_HYPOTHESES")) { - - /* Get the essential step flags */ - nmbrLet(&nmbrTmp, nmbrGetEssential(g_ProofInProgress.proof)); - - m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ - - n = 0; /* Earliest step that changed */ - g_proofChangedFlag = 0; - - for (s = m; s > 0; s--) { - - /* Skip essential steps and unknown steps */ - if (nmbrTmp[s - 1] == 1) continue; /* Not floating */ - if ((g_ProofInProgress.proof)[s - 1] == -(long)'?') continue; /* Unknown */ - - /* Get the subproof length at step s */ - q = subproofLen(g_ProofInProgress.proof, s - 1); - - deleteSubProof(s - 1); - - n = s - q + 1; /* Save earliest step changed */ - g_proofChangedFlag = 1; - s = s - q + 1; /* Adjust step position to account for deleted subpr */ - } /* Next step s */ - - if (g_proofChangedFlag) { - print2("All floating-hypothesis steps were deleted.\n"); - - if (n) { - print2("Steps %ld and above have been renumbered.\n", n); - } - - /* Automatically display new unknown steps - ???Future - add switch to enable/defeat this */ - typeProof(g_proveStatement, - 1 /*pipFlag*/, - 0 /*startStep*/, - 0 /*endStep*/, - 0 /*endIndent*/, - 1 /*essentialFlag*/, - 0 /*renumberFlag*/, - 1 /*unknownFlag*/, - 0 /*notUnifiedFlag*/, - 0 /*reverseFlag*/, - 0 /*noIndentFlag*/, - 0 /*splitColumn*/, - 0 /*skipRepeatedSteps*/, - 0 /*texFlag*/, - 0 /*g_htmlFlag*/); - - g_proofChanged = 1; /* Cumulative flag */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - } else { - print2("?There are no floating-hypothesis steps to delete.\n"); - } - - continue; - - } /* End if DELETE FLOATING_HYPOTHESES */ - - if (cmdMatches("INITIALIZE")) { - - if (cmdMatches("INITIALIZE ALL")) { - i = nmbrLen(g_ProofInProgress.proof); - - /* Reset the dummy variable counter (all will be refreshed) */ - g_pipDummyVars = 0; - - /* Initialize all steps */ - for (j = 0; j < i; j++) { - initStep(j); - } - - /* Assign known subproofs */ - assignKnownSubProofs(); - - print2("All steps have been initialized.\n"); - g_proofChanged = 1; /* Cumulative flag */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - continue; - } - - if (cmdMatches("INITIALIZE USER")) { - i = nmbrLen(g_ProofInProgress.proof); - /* Delete all LET STEP assignments */ - for (j = 0; j < i; j++) { - nmbrLet((nmbrString **)(&((g_ProofInProgress.user)[j])), - NULL_NMBRSTRING); - } - print2( - "All LET STEP user assignments have been initialized (i.e. deleted).\n"); - g_proofChanged = 1; /* Cumulative flag */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - continue; - } - - s = (long)val(g_fullArg[2]); /* Step number */ - if (s > nmbrLen(g_ProofInProgress.proof) || s < 1) { - print2("?The step must be in the range from 1 to %ld.\n", - nmbrLen(g_ProofInProgress.proof)); - continue; - } - - initStep(s - 1); - - /* Also delete LET STEPs, per HELP INITIALIZE */ - nmbrLet((nmbrString **)(&((g_ProofInProgress.user)[s - 1])), - NULL_NMBRSTRING); - - print2("Step %ld and its hypotheses have been initialized.\n", s); - - g_proofChanged = 1; /* Cumulative flag */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); - continue; - - } - - - if (cmdMatches("SEARCH")) { - if (switchPos("/ ALL")) { - m = 1; /* Include $e, $f statements */ - } else { - m = 0; /* Show $a, $p only */ - } - - if (switchPos("/ JOIN")) { - joinFlag = 1; /* Join $e's to $a,$p for matching */ - } else { - joinFlag = 0; /* Search $a,$p by themselves */ - } - - if (switchPos("/ COMMENTS")) { - n = 1; /* Search comments */ - } else { - n = 0; /* Search statement math symbols */ - } - - let(&str1, g_fullArg[2]); /* String to match */ - - if (n) { /* COMMENTS switch */ - /* Trim leading, trailing spaces; reduce white space to space; - convert to upper case */ - let(&str1, edit(str1, 8 + 16 + 128 + 32)); - } else { /* No COMMENTS switch */ - /* Trim leading, trailing spaces; reduce white space to space */ - let(&str1, edit(str1, 8 + 16 + 128)); - - /* Change all spaces to double spaces */ - q = (long)strlen(str1); - let(&str3, space(q + q)); - s = 0; - for (p = 0; p < q; p++) { - str3[p + s] = str1[p]; - if (str1[p] == ' ') { - s++; - str3[p + s] = str1[p]; - } - } - let(&str1, left(str3, q + s)); - - /* Find single-character-match wildcard argument "$?" - (or "?" for convenience). Use ASCII 3 for the exactly-1-char - wildcard character. This is a single-character - match, not a single-token match: we need "??" to match "ph". */ - while (1) { - p = instr(1, str1, "$?"); - if (!p) break; - let(&str1, cat(left(str1, p - 1), chr(3), right(str1, p + 2), NULL)); - } - /* Allow just "?" for convenience. */ - while (1) { - p = instr(1, str1, "?"); - if (!p) break; - let(&str1, cat(left(str1, p - 1), chr(3), right(str1, p + 1), NULL)); - } - - /* Change wildcard to ASCII 2 (to be different from printable chars) */ - /* 1-Mar-02 nm - (Why are we matching with and without space? I'm not sure.) */ - /* 30-Jan-06 nm Answer: We need the double-spacing, and the removal - of space in the "with spaces" case, so that "ph $ ph" will match - "ph ph" (0-token case) - "ph $ ph" won't match this in the - (character-based, not token-based) matches(). The "with spaces" - case is for matching whole tokens, whereas the "without spaces" - case is for matching part of a token. */ - while (1) { - p = instr(1, str1, " $* "); - if (!p) break; - /* This removes the space before and after the $* */ - let(&str1, cat(left(str1, p - 1), chr(2), right(str1, p + 4), NULL)); - } - while (1) { - p = instr(1, str1, "$*"); - if (!p) break; - /* This simply replaces $* with chr(2) */ - let(&str1, cat(left(str1, p - 1), chr(2), right(str1, p + 2), NULL)); - } - /* Also allow a plain $ as a wildcard, for convenience. */ - while (1) { - p = instr(1, str1, " $ "); - if (!p) break; - let(&str1, cat(left(str1, p - 1), chr(2), right(str1, p + 3), NULL)); - } - while (1) { - /* Note: the "$" shortcut must be done last to avoid picking up - "$*" and "$?". */ - p = instr(1, str1, "$"); - if (!p) break; - let(&str1, cat(left(str1, p - 1), chr(2), right(str1, p + 1), NULL)); - } - - /* Add wildcards to beginning and end to match middle of any string */ - let(&str1, cat(chr(2), " ", str1, " ", chr(2), NULL)); - } /* End no COMMENTS switch */ - - for (i = 1; i <= g_statements; i++) { - if (!g_Statement[i].labelName[0]) continue; /* No label */ - if (!m && g_Statement[i].type != (char)p_ && - g_Statement[i].type != (char)a_) { - continue; /* No /ALL switch */ - } - if (!matchesList(g_Statement[i].labelName, g_fullArg[1], '*', '?')) - continue; - if (n) { /* COMMENTS switch */ - let(&str2, ""); - str2 = getDescription(i); /* str2 must be deallocated here */ - /* Strip linefeeds and reduce spaces; cvt to uppercase */ - j = instr(1, edit(str2, 4 + 8 + 16 + 128 + 32), str1); - if (!j) { /* No match */ - let(&str2, ""); - continue; - } - /* Strip linefeeds and reduce spaces */ - let(&str2, edit(str2, 4 + 8 + 16 + 128)); - j = j + ((long)strlen(str1) / 2); /* Center of match location */ - p = g_screenWidth - 7 - (long)strlen(str((double)i)) - - (long)strlen(g_Statement[i].labelName); - /* Longest comment portion that will fit in one line */ - q = (long)strlen(str2); /* Length of comment */ - if (q <= p) { /* Use entire comment */ - let(&str3, str2); - } else { - if (q - j <= p / 2) { /* Use right part of comment */ - let(&str3, cat("...", right(str2, q - p + 4), NULL)); - } else { - if (j <= p / 2) { /* Use left part of comment */ - let(&str3, cat(left(str2, p - 3), "...", NULL)); - } else { /* Use middle part of comment */ - let(&str3, cat("...", mid(str2, j - p / 2, p - 6), "...", - NULL)); - } - } - } - print2("%s\n", cat(str((double)i), " ", g_Statement[i].labelName, " $", - chr(g_Statement[i].type), " \"", str3, "\"", NULL)); - let(&str2, ""); - } else { /* No COMMENTS switch */ - let(&str2,nmbrCvtMToVString(g_Statement[i].mathString)); - - tmpFlag = 0; /* Flag that $p or $a is already in string */ - if (joinFlag && (g_Statement[i].type == (char)p_ || - g_Statement[i].type == (char)a_)) { - /* If $a or $p, prepend $e's to string to match */ - k = nmbrLen(g_Statement[i].reqHypList); - for (j = k - 1; j >= 0; j--) { - p = g_Statement[i].reqHypList[j]; - if (g_Statement[p].type == (char)e_) { - let(&str2, cat("$e ", - nmbrCvtMToVString(g_Statement[p].mathString), - tmpFlag ? "" : cat(" $", chr(g_Statement[i].type), NULL), - " ", str2, NULL)); - tmpFlag = 1; /* Flag that a $p or $a was added */ - } - } - } - - /* Change all spaces to double spaces */ - q = (long)strlen(str2); - let(&str3, space(q + q)); - s = 0; - for (p = 0; p < q; p++) { - str3[p + s] = str2[p]; - if (str2[p] == ' ') { - s++; - str3[p + s] = str2[p]; - } - } - let(&str2, left(str3, q + s)); - - let(&str2, cat(" ", str2, " ", NULL)); - /* We should use matches() and not matchesList() here, because - commas can be legal token characters in math symbols */ - if (!matches(str2, str1, 2/* ascii 2 0-or-more-token match char*/, - 3/* ascii 3 single-token-match char*/)) - continue; - let(&str2, edit(str2, 8 + 16 + 128)); /* Trim leading, trailing - spaces; reduce white space to space */ - printLongLine(cat(str((double)i)," ", - g_Statement[i].labelName, - tmpFlag ? "" : cat(" $", chr(g_Statement[i].type), NULL), - " ", str2, - NULL), " ", " "); - } /* End no COMMENTS switch */ - } /* Next i */ - continue; - } - - - if (cmdMatches("SET ECHO")) { - if (cmdMatches("SET ECHO ON")) { - g_commandEcho = 1; - print2("!SET ECHO ON\n"); - print2("Command line echoing is now turned on.\n"); - } else { - g_commandEcho = 0; - print2("Command line echoing is now turned off.\n"); - } - continue; - } - - if (cmdMatches("SET MEMORY_STATUS")) { - if (cmdMatches("SET MEMORY_STATUS ON")) { - print2("Memory status display has been turned on.\n"); - print2("This command is intended for debugging purposes only.\n"); - g_memoryStatus = 1; - } else { - g_memoryStatus = 0; - print2("Memory status display has been turned off.\n"); - } - continue; - } - - - if (cmdMatches("SET JEREMY_HENTY_FILTER")) { - if (cmdMatches("SET JEREMY_HENTY_FILTER ON")) { - print2("The unification equivalence filter has been turned on.\n"); - print2("This command is intended for debugging purposes only.\n"); - g_hentyFilter = 1; - } else { - print2("This command is intended for debugging purposes only.\n"); - print2("The unification equivalence filter has been turned off.\n"); - g_hentyFilter = 0; - } - continue; - } - - - if (cmdMatches("SET EMPTY_SUBSTITUTION")) { - if (cmdMatches("SET EMPTY_SUBSTITUTION ON")) { - g_minSubstLen = 0; - print2("Substitutions with empty symbol sequences is now allowed.\n"); - continue; - } - if (cmdMatches("SET EMPTY_SUBSTITUTION OFF")) { - g_minSubstLen = 1; - printLongLine(cat("The ability to substitute empty expressions", - " for variables has been turned off. Note that this may", - " make the Proof Assistant too restrictive in some cases.", - NULL), - "", " "); - continue; - } - } - - - if (cmdMatches("SET SEARCH_LIMIT")) { - s = (long)val(g_fullArg[2]); /* Timeout value */ - print2("IMPROVE search limit has been changed from %ld to %ld\n", - g_userMaxProveFloat, s); - g_userMaxProveFloat = s; - continue; - } - - if (cmdMatches("SET WIDTH")) { - s = (long)val(g_fullArg[2]); /* Screen width value */ - - /* TODO: figure out why s=2 crashes program! */ - if (s < 3) s = 3; /* Less than 3 may cause a segmentation fault */ - i = g_screenWidth; - g_screenWidth = s; - print2("Screen width has been changed from %ld to %ld.\n", - i, s); - continue; - } - - - if (cmdMatches("SET HEIGHT")) { - s = (long)val(g_fullArg[2]); /* Screen height value */ - if (s < 2) s = 2; /* Less than 2 makes no sense */ - i = g_screenHeight; - g_screenHeight = s - 1; - print2("Screen height has been changed from %ld to %ld.\n", - i + 1, s); - /* g_screenHeight is one less than the physical screen to account for the - prompt line after pausing. */ - continue; - } - - - if (cmdMatches("SET DISCOURAGEMENT")) { - if (!strcmp(g_fullArg[2], "ON")) { - g_globalDiscouragement = 1; - print2("\"(...is discouraged.)\" markup tags are now honored.\n"); - } else if (!strcmp(g_fullArg[2], "OFF")) { - print2( - "\"(...is discouraged.)\" markup tags are no longer honored.\n"); - /* print2("\n"); */ /* Enable for more emphasis */ - print2( -">>> ?Warning: This setting is intended for advanced users only. Please turn\n"); - print2( -">>> it back ON if you are not intimately familiar with this database.\n"); - /* print2("\n"); */ /* Enable for more emphasis */ - g_globalDiscouragement = 0; - } else { - bug(1129); - } - continue; - } - - - if (cmdMatches("SET CONTRIBUTOR")) { - print2("\"Contributed by...\" name was changed from \"%s\" to \"%s\"\n", - g_contributorName, g_fullArg[2]); - let(&g_contributorName, g_fullArg[2]); - continue; - } - - - if (cmdMatches("SET ROOT_DIRECTORY")) { - let(&str1, g_rootDirectory); /* Save previous one */ - let(&g_rootDirectory, edit(g_fullArg[2], 2/*discard spaces,tabs*/)); - if (g_rootDirectory[0] != 0) { /* Not an empty directory path */ - /* Add trailing "/" to g_rootDirectory if missing */ - if (instr(1, g_rootDirectory, "\\") != 0 - || instr(1, g_input_fn, "\\") != 0 - || instr(1, g_output_fn, "\\") != 0 ) { - /* Using Windows-style path (not really supported, but at least - make full path consistent) */ - if (g_rootDirectory[strlen(g_rootDirectory) - 1] != '\\') { - let(&g_rootDirectory, cat(g_rootDirectory, "\\", NULL)); - } - } else { - if (g_rootDirectory[strlen(g_rootDirectory) - 1] != '/') { - let(&g_rootDirectory, cat(g_rootDirectory, "/", NULL)); - } - } - } - if (strcmp(str1, g_rootDirectory)) { - print2("Root directory was changed from \"%s\" to \"%s\"\n", - str1, g_rootDirectory); - } - let(&str1, ""); - continue; - } - - - if (cmdMatches("SET UNDO")) { - s = (long)val(g_fullArg[2]); /* Maximum UNDOs */ - if (s < 0) s = 0; /* Less than 0 UNDOs makes no sense */ - /* Reset the stack size if it changed */ - if (processUndoStack(NULL, PUS_GET_SIZE, "", 0) != s) { - print2( - "The maximum number of UNDOs was changed from %ld to %ld\n", - processUndoStack(NULL, PUS_GET_SIZE, "", 0), s); - processUndoStack(NULL, PUS_NEW_SIZE, "", s); - if (g_PFASmode == 1) { - /* If we're in the Proof Assistant, assign the first stack - entry with the current proof (the stack was erased) */ - processUndoStack(&g_ProofInProgress, PUS_PUSH, "", 0); - } - } else { - print2("The maximum number of UNDOs was not changed.\n"); - } - continue; - } - - - if (cmdMatches("SET UNIFICATION_TIMEOUT")) { - s = (long)val(g_fullArg[2]); /* Timeout value */ - print2("Unification timeout has been changed from %ld to %ld\n", - g_userMaxUnifTrials,s); - g_userMaxUnifTrials = s; - continue; - } - - - if (cmdMatches("OPEN LOG")) { - /* Open a log file */ - let(&g_logFileName, g_fullArg[2]); - g_logFilePtr = fSafeOpen(g_logFileName, "w", 0/*noVersioningFlag*/); - if (!g_logFilePtr) continue; /* Couldn't open it (err msg was provided) */ - g_logFileOpenFlag = 1; - print2("The log file \"%s\" was opened %s %s.\n",g_logFileName, - date(),time_()); - continue; - } - - if (cmdMatches("CLOSE LOG")) { - /* Close the log file */ - if (!g_logFileOpenFlag) { - print2("?Sorry, there is no log file currently open.\n"); - } else { - print2("The log file \"%s\" was closed %s %s.\n",g_logFileName, - date(),time_()); - fclose(g_logFilePtr); - g_logFileOpenFlag = 0; - } - let(&g_logFileName,""); - continue; - } - - if (cmdMatches("OPEN TEX")) { - if (g_texDefsRead) { - if (g_htmlFlag) { - /* Actually it isn't clear to me this is still the case, but - to be safe I left it in */ - print2("?You cannot use both LaTeX and HTML in the same session.\n"); - print2( - "?You must EXIT and restart Metamath to switch to the other.\n"); - continue; - } - } - - /* Open a TeX file */ - let(&g_texFileName,g_fullArg[2]); - if (switchPos("/ NO_HEADER")) { - texHeaderFlag = 0; - } else { - texHeaderFlag = 1; - } - - if (switchPos("/ OLD_TEX")) { - g_oldTexFlag = 1; - } else { - g_oldTexFlag = 0; - } - g_texFilePtr = fSafeOpen(g_texFileName, "w", 0/*noVersioningFlag*/); - if (!g_texFilePtr) continue; /* Couldn't open it (err msg was provided) */ - g_texFileOpenFlag = 1; - print2("Created %s output file \"%s\".\n", - g_htmlFlag ? "HTML" : "LaTeX", g_texFileName); - printTexHeader(texHeaderFlag); - g_oldTexFlag = 0; - continue; - } - - if (cmdMatches("CLOSE TEX")) { - /* Close the TeX file */ - if (!g_texFileOpenFlag) { - print2("?Sorry, there is no LaTeX file currently open.\n"); - } else { - print2("The LaTeX output file \"%s\" has been closed.\n", - g_texFileName); - printTexTrailer(texHeaderFlag); - fclose(g_texFilePtr); - g_texFileOpenFlag = 0; - } - let(&g_texFileName,""); - continue; - } - - /* Similar to Unix 'more' */ - if (cmdMatches("MORE")) { - list1_fp = fSafeOpen(g_fullArg[1], "r", 0/*noVersioningFlag*/); - if (!list1_fp) continue; /* Couldn't open it (error msg was provided) */ - while (1) { - if (!linput(list1_fp, NULL, &str1)) break; /* End of file */ - /* Print a line on the screen */ - if (!print2("%s\n", str1)) break; /* User typed Q */ - } - fclose(list1_fp); - continue; - } /* end MORE */ - - - if (cmdMatches("FILE SEARCH")) { - /* Search the contents of a file and type on the screen */ - - type_fp = fSafeOpen(g_fullArg[2], "r", 0/*noVersioningFlag*/); - if (!type_fp) continue; /* Couldn't open it (error msg was provided) */ - fromLine = 0; - toLine = 0; - searchWindow = 0; - i = switchPos("/ FROM_LINE"); - if (i) fromLine = (long)val(g_fullArg[i + 1]); - i = switchPos("/ TO_LINE"); - if (i) toLine = (long)val(g_fullArg[i + 1]); - i = switchPos("/ WINDOW"); - if (i) searchWindow = (long)val(g_fullArg[i + 1]); - /*??? Implement SEARCH /WINDOW */ - if (i) print2("Sorry, WINDOW has not be implemented yet.\n"); - - let(&str2, g_fullArg[3]); /* Search string */ - let(&str2, edit(str2, 32)); /* Convert to upper case */ - - tmpFlag = 0; - - /* Search window buffer */ - pntrLet(&pntrTmp, pntrSpace(searchWindow)); - - j = 0; /* Line # */ - m = 0; /* # matches */ - while (linput(type_fp, NULL, &str1)) { - j++; - if (j > toLine && toLine != 0) break; - if (j >= fromLine || fromLine == 0) { - let(&str3, edit(str1, 32)); /* Convert to upper case */ - if (instr(1, str3, str2)) { /* Match occurred */ - if (!tmpFlag) { - tmpFlag = 1; - print2( - "The line number in the file is shown before each line.\n"); - } - m++; - if (!print2("%ld: %s\n", j, left(str1, - MAX_LEN - (long)strlen(str((double)j)) - 3))) break; - } - } - for (k = 1; k < searchWindow; k++) { - let((vstring *)(&pntrTmp[k - 1]), pntrTmp[k]); - } - if (searchWindow > 0) - let((vstring *)(&pntrTmp[searchWindow - 1]), str1); - } - if (!tmpFlag) { - print2("There were no matches.\n"); - } else { - if (m == 1) { - print2("There was %ld matching line in the file %s.\n", m, - g_fullArg[2]); - } else { - print2("There were %ld matching lines in the file %s.\n", m, - g_fullArg[2]); - } - } - - fclose(type_fp); - - /* Deallocate search window buffer */ - for (i = 0; i < searchWindow; i++) { - let((vstring *)(&pntrTmp[i]), ""); - } - pntrLet(&pntrTmp, NULL_PNTRSTRING); - - - continue; - } - - - if (cmdMatches("SET UNIVERSE") || cmdMatches("ADD UNIVERSE") || - cmdMatches("DELETE UNIVERSE")) { - - /*continue;*/ /* ???Not implemented */ - } /* end if xxx UNIVERSE */ - - - - if (cmdMatches("SET DEBUG FLAG")) { - print2("Notice: The DEBUG mode is intended for development use only.\n"); - print2("The printout will not be meaningful to the user.\n"); - i = (long)val(g_fullArg[3]); - if (i == 4) db4 = 1; /* Not used */ - if (i == 5) db5 = 1; /* mmpars.c statistics; mmunif.c overview */ - if (i == 6) db6 = 1; /* mmunif.c details */ - if (i == 7) db7 = 1; /* mmunif.c more details; mmveri.c */ - if (i == 8) db8 = 1; /* mmpfas.c unification calls */ - if (i == 9) db9 = 1; /* memory */ /* use SET MEMORY_STATUS ON instead */ - continue; - } - if (cmdMatches("SET DEBUG OFF")) { - db4 = 0; - db5 = 0; - db6 = 0; - db7 = 0; - db8 = 0; - db9 = 0; - print2("The DEBUG mode has been turned off.\n"); - continue; - } - - if (cmdMatches("ERASE")) { - if (g_sourceChanged) { - print2("Warning: You have not saved changes to the source.\n"); - str1 = cmdInput1("Do you want to ERASE anyway (Y, N) ? "); - if (str1[0] != 'y' && str1[0] != 'Y') { - print2("Use WRITE SOURCE to save the changes.\n"); - continue; - } - g_sourceChanged = 0; - } - eraseSource(); - g_sourceHasBeenRead = 0; /* Global variable */ - g_showStatement = 0; - g_proveStatement = 0; - print2("Metamath has been reset to the starting state.\n"); - continue; - } - - if (cmdMatches("VERIFY PROOF")) { - if (switchPos("/ SYNTAX_ONLY")) { - verifyProofs(g_fullArg[2],0); /* Parse only */ - } else { - verifyProofs(g_fullArg[2],1); /* Parse and verify */ - } - continue; - } - - if (cmdMatches("VERIFY MARKUP")) { - i = (switchPos("/ DATE_SKIP") != 0) ? 1 : 0; - j = (switchPos("/ TOP_DATE_SKIP") != 0) ? 1 : 0; - k = (switchPos("/ FILE_SKIP") != 0) ? 1 : 0; - l = (switchPos("/ UNDERSCORE_SKIP") != 0) ? 1 : 0; - m = (switchPos("/ MATHBOX_SKIP") != 0) ? 1 : 0; - n = (switchPos("/ VERBOSE") != 0) ? 1 : 0; - if (i == 1 && j == 1) { - printf( - "?Only one of / DATE_SKIP and / TOP_DATE_SKIP may be specified.\n"); - continue; - } - verifyMarkup(g_fullArg[2], - (flag)i, /* 1 = skip checking date consistency */ - (flag)j, /* 1 = skip checking top date only */ - (flag)k, /* 1 = skip checking external files GIF, mmset.html,... */ - (flag)l, /* 1 = skip checking labels for underscores */ - (flag)m, /* 1 = skip checking mathbox cross-references */ - (flag)n); /* 1 = verbose mode */ - continue; - } - - if (cmdMatches("MARKUP")) { - g_htmlFlag = 1; - g_altHtmlFlag = (switchPos("/ ALT_HTML") != 0); - if ((switchPos("/ HTML") != 0) == (switchPos("/ ALT_HTML") != 0)) { - print2("?Please specify exactly one of / HTML and / ALT_HTML.\n"); - continue; - } - i = 0; - i = ((switchPos("/ SYMBOLS") != 0) ? PROCESS_SYMBOLS : 0) - + ((switchPos("/ LABELS") != 0) ? PROCESS_LABELS : 0) - + ((switchPos("/ NUMBER_AFTER_LABEL") != 0) ? ADD_COLORED_LABEL_NUMBER : 0) - + ((switchPos("/ BIB_REFS") != 0) ? PROCESS_BIBREFS : 0) - + ((switchPos("/ UNDERSCORES") != 0) ? PROCESS_UNDERSCORES : 0); - processMarkup(g_fullArg[1], /* Input file */ - g_fullArg[2], /* Output file */ - (switchPos("/ CSS") != 0), - i); /* Action bits */ - continue; - } - - print2("?This command has not been implemented.\n"); - continue; - - } -} /* command */ - - +/*****************************************************************************/ +/* Program name: metamath */ +/* Copyright (C) 2021 NORMAN MEGILL nm at alum.mit.edu http://metamath.org */ +/* License terms: GNU General Public License Version 2 or any later version */ +/*****************************************************************************/ +/*34567890123456 (79-character line to adjust editor window) 2345678901234567*/ + +/* Copyright notice: All code in this program that was written by Norman + Megill is public domain. However, the project includes code contributions + from other people which may be GPL licensed. For more details see: + https://github.com/metamath/metamath-exe/issues/7#issuecomment-675555069 */ + +/* The overall functionality of the modules is as follows: + metamath.c - Contains main(); executes or calls commands + mmcmdl.c - Command line interpreter + mmcmds.c - Extends metamath.c command() to execute SHOW and other + commands; added after command() became too bloated (still is:) + mmdata.c - Defines global data structures and manipulates arrays + with functions similar to BASIC string functions; + memory management; converts between proof formats + mmhlpa.c - The help file, part 1. + mmhlpb.c - The help file, part 2. + mmhtbl.c - Hashtable implementation + mminou.c - Basic input and output interface + mmpars.c - Parses the source file + mmpfas.c - Proof Assistant + mmunif.c - Unification algorithm for Proof Assistant + mmveri.c - Proof verifier for source file + mmvstr.c - BASIC-like string functions + mmwtex.c - LaTeX/HTML source generation + mmwsts.c - STS source generation + mmword.c - File revision utility (for TOOLS> UPDATE) (not generally useful) +*/ + +/* Compilation instructions (gcc on Unix/Linus/Cygwin, lcc on Windows): + 1. Make sure each .c file above is present in the compilation directory and + that each .c file (except metamath.c) has its corresponding .h file + present. + 2. In the directory where these files are present, type: + gcc m*.c -o metamath + 3. For full error checking, use: + gcc m*.c -o metamath -O2 -Wall -Wextra -Wmissing-prototypes \ + -Wmissing-declarations -Wshadow -Wpointer-arith -Wcast-align \ + -Wredundant-decls -Wnested-externs -Winline -Wno-long-long \ + -Wconversion -Wstrict-prototypes -std=c99 -pedantic -Wunused-result + Note: gcc 4.9.2 (on Debian) fails with "unknown type name `ssize_t'" if + -std=c99 is used, so omit -std=c99 to work around this problem. + 4. For faster runtime, use these gcc options: + gcc m*.c -o metamath -O3 -funroll-loops -finline-functions \ + -fomit-frame-pointer -Wall -std=c99 -pedantic -fno-strict-overflow + 5. The Windows version in the download was compiled with lcc-win32 version 3.8: + lc -O m*.c -o metamath.exe + 6. On Linux, if you have autoconf, automake, and a C compiler, you + can compile with the command "autoreconf -i && ./configure && make". + See the README.TXT file for more information. +*/ + + + +#define MVERSION "0.199.pre 7-Aug-2021" +/* 0.199.pre + 4-Jan-2022 mc - change VERIFY MARKUP /TOP_DATE_SKIP and /FILE_SKIP to + /TOP_DATE_CHECK and /FILE_CHECK (with opposite meaning), and make the + skip behavior the default. + 30-Dec-2021 mc metamath.c mmdata.c mminou.c mmmaci.c - + Remove mmmaci and everything related to THINK_C compiler + 24-Dec-2021 tar mmwsts.c and others - Merge STS source generation code + originally developped in July 2017. STS stands for Structured TypeSetting and + can be used to generate MathML, which can in turn be postprocessed by MathJAX + to output mathematical typesetting (this includes indices, exponents, summands + and integrals with sets specifed below the sign, square roots with overhangs, + fraction bars, sized parentheses, etc.) The code introduces a new / STS flag + as a third alternative to / HTML and / ALT_HTML for HTML page generation, and + a / VERIFY STS option to only check the integrity of the external STS command + file. */ +/* 0.198 nm 7-Aug-2021 mmpars.c - Fix cosmetic bug in WRITE SOURCE ... /REWRAP + that prevented end of sentence (e.g. period) from appearing in column 79, + thus causing some lines to be shorter than necessary. */ +/* 0.197 nm 2-Aug-2021 mmpars.c - put two spaces between $c,v on same line + in /rewrap; mmwtex.c mmhlpa.c mminou.c - minor edits */ +/* 0.196 nm 31-Dec-2020 metamath.c mmpars.c - fix bug that deleted comments + that were followed by ${, $}, $c, $v, $d on the same line */ +/* 0.195 nm 30-Dec-2020 metamath.c - temporarily disable /REWRAP until bug fixed + 27-Sep-2020 nm mmwtex.c - prevent "htmlexturl" links from wrapping */ +/* 0.194 26-Dec-2020 nm mmwtex.c - add keyword "htmlexturl" to $t + statement in .mm file */ +/* 0.193 12-Sep-2020 nm mmcmds.c mmdata.c,h mmwtex.c,h mmhlpa.c - make the + output of /EXTRACT stable in the sense that, with the same + parameter, extract(extract(file)) = extract(file) except that the date + stamp at the top will be updated. (The first extraction even if "*" will + usually be different because it discards non-relevant content. Note that + the include file directives "$( $[ Begin..." etc. and comments with "$j" are + currently discarded.) */ +/* 0.192 4-Sep-2020 nm metamath.c - fix bug */ +/* 0.191 4-Sep-2020 nm metamath.c - add comment close */ +/* 0.190 4-Sep-2020 nm mmcmds.c - fix bug in writeExtractedSource() */ +/* 0.189 4-Sep-2020 nm mmhlpa.c - add help for WRITE SOURCE .. /EXTRACT ... + 24-Aug-2020 nm metamath.c mmcmdl.c mmcmds.c,h mmdata.c,h mmhlpa.c + mmpars.c mmpfas.c mmunif.c mmwtex.c,h - Added + WRITE SOURCE ... /EXTRACT ... */ +/* 0.188 23-Aug-2020 nm mmwtex.c, mmhlpa.c Added CONCLUSION FACT INTRODUCTION + PARAGRAPH SCOLIA SCOLION SUBSECTION TABLE to [bib] keywords */ +/* 0.187 15-Aug-2020 nm All m*.c, m*.h - put "g_" in front of all global + variable names e.g. "statements" becomes "g_statements"; also capitalized + 1st letter of original name in case of global structs e.g. "statement" + becomes "g_Statement". + 9-Aug-2020 nm mmcmdl.c, mmhlpa.c - add HELP BIBLIOGRAPHY */ +/* 0.186 8-Aug-2020 nm mmwtex.c, mmhlpa.c - add CONJECTURE, RESULT to [bib] + keywords + 8-Aug-2020 nm mmpfas.c, metamath.c - print message when IMPROVE or + MINIMIZE_WITH uses another mathbox */ +/* 0.185 5-Aug-2020 nm metamath.c mmcmdl.c mmhlpb.c mmpfas.c,h mmcmds.c + mmwtex.c,h - add /INCLUDE_MATHBOXES to to IMPROVE; notify user upon ASSIGN + from another mathbox. + 18-Jul-2020 nm mmcmds.c, mmdata.c, mmhlpb.c, metamath.c - "PROVE =" will now + resume the previous MM-PA session if there was one; allow "~" to start/end + with blank (meaning first/last statement); add "@1234" */ +/* 0.184 17-Jul-2020 nm metamath.c mmcmdl.c mmcmds.c,h mmhlpb.c mmwtex.c,h - + add checking for mathbox independence to VERIFY MARKUP; add /MATHBOX_SKIP + 4-Jul-2020 nm mmwtex.c - correct error msg for missing althtmldef + 3-Jul-2020 nm metamath.c, mmhlpa.c - allow space in TOOLS> BREAK */ +/* 0.183 30-Jun-2020 30-Jun-2020 nm mmpars.c - refine prevention of + WRITE SOURCE.../REWRAP from modifying comments containing "" + (specifically, remove indentation alignment). + 25-Jun-2020 nm metamath.c, mmcmds.c,h mmcmdl.c mmhlpb.c - add underscore + checking in VERIFY MARKUP and add /UNDERSCORE_SKIP qualifier; also check + for trailing space on lines. + 20-Jun-2020 nm mmcmds.c - check for discouragement tags in *ALT, *OLD + labels in VERIFY MARKUP. + 19-Jun-2020 nm mminou.c,h, metamath.c, mmwtex.c - dynamically allocate + buffer in print2() using vsnprintf() to calculate size needed + 18-Jun-2020 nm mmpars.c - remove error check for $e <- $f assignments. See + https://groups.google.com/d/msg/metamath/Cx_d84uorf8/0FrNYTM9BAAJ */ +/* 0.182 12-Apr-2020 nm mmwtex.c, mmphlpa.c - add "Claim" to bib ref types */ +/* 0.181 12-Feb-2020 nm (reported by David Starner) metamath.c - fix bug causing + new axioms to be used by MINIMIZE_WITH */ +/* 0.180 10-Dec-2019 nm (bj 13-Sep-2019) mmpars.c - fix "line 0" in error msg + when label clashes with math symbol + 8-Dec-2019 nm (bj 13-Oct-2019) mmhlpa.c - improve TOOLS> HELP INSERT, DELETE + 8-Dec-2019 nm (bj 19-Sep-2019) mminou.c - change bug 1511 to error message + 30-Nov-2019 nm (bj 12-Oct-2019) mmwtex.c - trigger Most Recent link on + mmtheorems.html when there is a mathbox statement (currently set.mm and + iset.mm). + 30-Nov-2019 nm (bj 13-Sep-2019) mmhlpa.c - improve help for TOOLS> DELETE and + SUBSTITUTE. + 30-Nov-2019 nm (bj 13-Sep-2019) mmwtex.c - change "g_htmlHome" in warnings to + "htmlhome". */ +/* 0.179 29-Nov-2019 nm (bj 22-Sep-2019) metamath.c - MINIMIZE_WITH axiom trace + now starts from current NEW_PROOF instead of SAVEd proof. + 23-Nov-2019 nm (bj 4-Oct-2019) metamath.c - make sure traceback flags are + cleared after MINIMIZE_WITH + 20-Nov-2019 nm mmhlpa.c - add url pointer to HELP WRITE SOURCE /SPLIT + 18-Nov-2019 nm mmhlpa.c - clarify HELP WRITE SOURCE /REWRAP + 15-Oct-2019 nm mmdata.c - add bug check info for user + 14-Oct-2019 nm mmcmds.c - use '|->' (not 'e.') as syntax hint for maps-to + 14-Oct-2019 nm mmwtex.c - remove extraneous */ +/* 0.178 10-Aug-2019 nm mminou.c - eliminate redundant fopen in fSafeOpen + 6-Aug-2019 nm mmwtex.c,h, mmcmds.c - Add error check for >1 line + section name or missing closing decoration line in getSectionHeadings() + 4-Aug-2019 nm mmhlpb.c, mmcmdl.c, metamath.c - Add /ALLOW_NEW_AXIOMS, + renamed /ALLOW_GROWTH to /MAY_GROW + 17-Jul-2019 nm mmcmdl.c, mmhlpa.c, metamath.c - Add /NO_VERSIONING to + WRITE THEOREM_LIST + 17-Jul-2019 nm metamath.c - Change line of dashes between SHOW STATEMENT + output from hardcoded 79 to current g_screenWidth */ +/* 0.177 27-Apr-2019 nm mmcmds.c -"set" -> "setvar" in htmlAllowedSubst. + mmhlpb.c - fix typos in HELP IMPROVE. */ +/* 0.176 25-Mar-2019 nm metamath.c mmcmds.h mmcmds.c mmcmdl.c mmhlpb.c - + add /TOP_DATE_SKIP to VERIFY MARKUP */ +/* 0.175 8-Mar-2019 nm mmvstr.c - eliminate warning in gcc 8.3 (patch + provided by David Starner) */ +/* 0.174 22-Feb-2019 nm mmwtex.c - fix erroneous warning when using "[[" + bracket escape in comment */ +/* 0.173 3-Feb-2019 nm mmwtex.c - fix infinite loop when "[" was the first + character in a comment */ +/* 0.172 25-Jan-2019 nm mmwtex.c - comment out bug 2343 trap (not a bug) */ +/* 0.171 13-Dec-2018 nm metamath.c, mmcmdl.c, mmhlpa.c, mmcmds.c,h, mmwtex.c,h + - add fine-grained qualfiers to MARKUP command */ +/* 0.170 12-Dec-2018 nm mmwtex.c - restore line accidentally deleted in 0.169 */ +/* 0.169 10-Dec-2018 nm metamath.c, mmcmds.c,h, mmcmdl.c, mmpars.c, mmhlpa.c, + mmwtex.c - Add MARKUP command. + 9-Dec-2018 nm mmwtex.c - escape literal "[" with "[[" in comments. */ +/* 0.168 8-Dec-2018 nm metamath.c - validate that /NO_REPEATED_STEPS is used + only with /LEMMON. + 8-Dec-2018 nm mmcmds.c - fix bug #256 reported by Jim Kingdon + (https://github.com/metamath/set.mm/issues/497). */ +/* 0.167 13-Nov-2018 nm mmcmds.c - SHOW TRACE_BACK .../COUNT now uses proof + the way it's stored (previously, it always uncompressed the proof). The + new step count (for compressed proofs) corresponds to the step count the + user would see on the web pages. + 12-Nov-2018 nm mmcmds.c - added unlimited precision arithmetic + for SHOW TRACE_BACK .../COUNT/ESSENTIAL */ +/* 0.166 31-Oct-2018 nm mmwtex.c - workaround Chrome anchor bug + 30-Oct-2018 nm mmcmds.c - put "This theorem is referenced by" after + axioms and definitions used in HTML; use "(None)" instead of suppressing + line if nothing is referenced */ +/* 0.165 20-Oct-2018 nm mmwtex.c - added ~ mmtheorems#abc type anchor + in TOC details. mmwtex.c - fix bug (reported by Benoit Jubin) that + changes "_" in labels to subscript. mmcmdl.c - remove unused COMPLETE + qualifier from SHOW PROOF. mmwtex.c - enhance special cases of web page + spacing identified by Benoit Jubin */ +/* 0.164 5-Sep-2018 nm mmwtex.c, mmhlpb.c - added NOTE to bib keywords + 14-Aug-2018 nm metamath.c - added defaultScrollMode to prevent + SET SCROLL CONTINUOUS from reverting to PROMPTED after a SUBMIT command */ +/* 0.163 4-Aug-2018 nm mmwtex.c - removed 2nd "sandbox:bighdr" anchor + in mmtheorems.html; removed Firefox and IE references; changed breadcrumb + font to be consistent with other pages; put asterisk next to TOC entries + that have associated comments */ +/* FOR FUTURE REFERENCE: search for "Thierry" in mmwtex.c to modify the link + to tirix.org structured proof site */ +/* 0.162-thierry 3-Jun-2018 nm mmwtex.c - add link to tirix.org structured + proofs */ +/* 0.162 3-Jun-2018 nm mmpars.c - re-enabled error check for $c not in + outermost scope. mmhlpa.c mmhlpb.c- improve some help messages. + mmwtex.c - added "OBSERVATION", "PROOF", AND "STATEMENT" keywords for + WRITE BIBLIOGRAPHY */ +/* 0.161 2-Feb-2018 nm mmpars.c,h mmcmds.c mmwtex.c - fix wrong file name + and line number in error messages */ +/* 0.160 24-Jan-2018 nm mmpars.c - fix bug introduced in version 0.158 */ +/* 0.159 23-Jan-2018 nm mmpars.c - fix crash due to missing include file */ +/* 0.158 22-Jan-2018 nm mminou.c - strip CRs from Windows SUBMIT files + run on Linux */ +/* 0.157 15-Jan-2018 nm Major rewrite of READ-related functions. + Added HELP MARKUP. + 9-Jan-2018 nm Track line numbers for error messages in included files + 1-Jan-2018 nm Changed HOME_DIRECTORY to ROOT_DIRECTORY + 31-Dec-2017 nm metamath.c mmcmdl.c,h mmpars.c,h mmcmds.c,h mminou.c,h + mmwtex.c mmhlpb.c mmdata.h - add virtual includes "$( Begin $[...$] $)", + $( End $[...$] $)", "$( Skip $[...$] $)" */ +/* 0.156 8-Dec-2017 nm mmwtex.c - fix bug that incorrectly gave "verify markup" + errors when there was a mathbox statement without an "extended" section */ +/* 0.155 8-Oct-2017 nm mmcmdl.c - restore accidentally removed HELP HTML; + mmhlpb.c mmwtex.c mmwtex.h,c mmcmds.c metamath.c - improve HELP and make + other cosmetic changes per Benoit Jubin's suggestions */ +/* 0.154 2-Oct-2017 nm mmunif.h,c mmcmds.c - add 2 more variables to ERASE; + metamath.c mmcmdl.c - remove obsolete OPEN/CLOSE HTML; mmhlpa.c mmhlpb.c - + fix typos reported by Benoit Jubin */ +/* 0.153 1-Oct-2017 nm mmunif.c,h mmcmds.c - Re-initialize internal nmbrStrings + in unify() after 'erase' command reported by Benoit Jubin */ +/* 0.152 26-Sep-2017 nm mmcmds.c - change default links from mpegif to mpeuni; + metamath.c - enforce minimum screen width = 3 to prevent crash reported + by Benoit Jubin */ +/* 0.151 20-Sep-2017 nm mmwtex.c - better matching to insert space between + A and y in "E. x e. ran A y R x" to prevent spurious spaces in thms rncoeq, + dfiun3g as reported by Benoit Jubin */ +/* 0.150 26-Aug-2017 nm mmcmds.c,mmwtex.h - fix hyperlink for Distinct variable + etc. lists so that it will point to mmset.html on other Explorers like NF. + Move the "Dummy variables..." to print after the "Proof of Theorem..." + line. */ +/* 0.149 21-Aug-2017 nm mmwtex.c,h mmcmds.c mmhlpb.c - add a subsubsection + "tiny" header with separator "-.-." to table of contents and theorem list; + see HELP WRITE THEOREM_LIST + 21-Aug-2017 nm mmcmds.c - remove bug check 255 + 19-Aug-2017 nm mmcmds.c - change mmset.html links to + ../mpeuni/mmset.html so they will work in NF Explorer etc. */ +/* 0.148 14-Aug-2017 nm mmcmds.c - hyperlink "Dummy variable(s)" */ +/* 0.147 13-Aug-2017 nm mmcmds.c,h - add "Dummy variable x is distinct from all + other variables." to proof web page */ +/* 0.146 26-Jun-2017 nm mmwtex.c - fix handling of local labels in + 'show proof.../tex' (bug 2341 reported by Eric Parfitt) */ +/* 0.145 16-Jun-2017 nm metamath.c mmpars.c - fix bug 1741 during + MINIMIZE_WITH; mmpfas.c - make duplicate bug numbers unique; mmhlpa.c + mmhlpb.c - adjust to prevent lcc compiler "Function too big for the + optimizer" + 29-May-2017 nm mmwtex.c mmhlpa.c - take out extraneous ... + markup tags in HTML output so w3c validator will pass */ +/* 0.144 15-May-2017 nm metamath.c mmcmds.c - add "(Revised by..." tag for + conversion of legacy .mm's if there is a 2nd date under the proof */ +/* 0.143 14-May-2017 nm metamath.c mmdata.c,h mmcmdl.c mmcmds.c mmhlpb.c - + added SET CONTRIBUTOR; for missing "(Contributed by..." use date + below proof if it exists, otherwise use today's date, in order to update + old .mm files. + 14-May-2017 Ari Ferrera - mmcmds.c - fix memory leaks in ERASE */ +/* 0.142 12-May-2017 nm metamath.c mmdata.c,h mmcmds.c - added + "#define DATE_BELOW_PROOF" in mmdata.h that if uncommented, will enable + use of the (soon-to-be obsolete) date below the proof + 4-May-2017 Ari Ferrera - mmcmds.c metamath.c mmdata.c mmcmdl.c + mminou.c mminou.h mmcmdl.h mmdata.h - fixed memory leaks and warnings + found by valgrind. + 3-May-2017 nm - metamath.c mmdata.c,h mmcmds.c,h mmpars.c,h mmhlpb.c + mmcmdl.c mmwtex.c - added xxChanged flags to statement structure so + that any part of the source can be changed; removed /CLEAN qualifier + of WRITE SOURCE; automatically put "(Contributed by ?who?..." during + SAVE NEW_PROOF or SAVE PROOF when it is missing; more VERIFY MARKUP + checking. */ +/* 0.141 2-May-2017 nm mmdata.c, metamath.c, mmcmds.c, mmhlpb.c - use + getContrib() date for WRITE RECENT instead of date below proof. This lets + us list recent $a's as well as $p's. Also, add caching to getContrib() for + speedup. */ +/* 0.140 1-May-2017 nm mmwtex.c, mmcmds.c, metamath.c - fix some LaTeX issues + reported by Ari Ferrera */ +/* 0.139 2-Jan-2017 nm metamath.c - print only one line for + 'save proof * /compressed/fast' */ +/* 0.138 26-Dec-2016 nm mmwtex.c - remove extraneous causing w3c + validation failure; put space after 1st x in "F/ x x = x"; + mmcmds.c - added checking for lines > 79 chars in VERIFY MARKUP; + mmcmds.c, mmcmdl.c, metamath.c, mmhlpb.c, mmcmds.h - added /VERBOSE to + VERIFY MARKUP */ +/* 0.137 20-Dec-2016 nm mmcmds.c - check ax-XXX $a vs axXXX $p label convention + in 'verify markup' + 18-Dec-2016 nm mmwtex.c, mmpars.c, mmdata.h - use true "header area" + between successive $a/$p for getSectionHeadings() mmcmds.c - add + header comment checking + 13-Dec-2016 nm mmdata.c,h - enhanced compareDates() to treat empty string as + older date. + 13-Dec-2016 nm metamath.c, mmcmds.c - moved mm* and Microsoft illegal file + name label check to verifyMarkup() (the VERIFY MARKUP command) instead of + checking on READ; added check of set.mm Version date to verifyMarkup(). + 13-Dec-2016 nm mmwtex.c,h - don't treat bracketed description text with + space as a bib label; add labelMatch parameter to writeBibliography() */ +/* 0.136 10-Oct-2016 mminou.c - fix resource leak bug reported by David + Binderman */ +/* 0.135 11-Sep-2016, 14-Sep-2016 metamath.c, mmpfas.c,h, mmdata.c,h, + mmpars.c,h mmcmds.c, mmcmdl.c, mmhlpb.c - added EXPAND command */ +/* 0.134 16-Aug-2016 mmwtex.c - added breadcrumbs to theorem pages; + metamath.c, mmcmdl.c, mmhlpb.c, mminou.c,.h - added /TIME to SAVE PROOF, + SHOW STATEMENT.../[ALT}HTML, MINIMIZE_WITH */ +/* 0.133 13-Aug-2016 mmwtex.c - improve mobile display with tag + mmpars.c - use updated Macintosh information */ +/* 0.132 10-Jul-2016 metamath.c, mmcmdl.c, mmcmds.c,.h, mmdata.c,.h, mmhlpb.c, + mmpfas.c - change "restricted" to "discouraged" to match set.mm markup + tags; add SET DISCOURAGEMENT OFF|ON (default ON) to turn off blocking for + convenience of advanced users + 6-Jul-2016 metamath.c - add "(void)" in front of "system(...)" to + suppress -Wunused-result warning */ +/* 0.131 10-Jun-2016 mminou.c - reverted change of 22-May-2016 because + 'minimize_with' depends on error message in string to prevent DV violations. + Todo: write a DV-checking routine for 'minimize_with', then revert + the 22-May-2016 fix for bug 126 (which only occurs when writing web + pages for .mm file with errors). + 9-Jun-2016 mmcmdl.c, metamath.c - added _EXIT_PA for use with + scripts that will give an error message outside of MM-PA> rather + than exiting metamath */ +/* 0.130 25-May-2016 mmpars.c - workaround clang warning about j = j; + mmvstr.c - workaround gcc -Wstrict-overflow warning */ +/* 0.129 24-May-2016 mmdata.c - fix bug 1393 */ +/* 0.128 22-May-2016 mminou.c - fixed error message going to html page + instead of to screen, triggering bug 126. */ +/* 0.127 10-May-2016 metamath.c, mmcmdl.c, mmhlpb.c - added /OVERRIDE to + PROVE */ +/* 0.126 3-May-2016 metamath.c, mmdata.h, mmdata.c, mmcmds.h, mmcmds.c, + mmcmdl.c, mmhlpb.c, mmpars.c - added getMarkupFlag() in mmdata.c; + Added /OVERRIDE added to ASSIGN, REPLACE, IMPROVE, MINIMIZE_WITH, + SAVE NEW_PROOF; PROVE gives warning about SAVE NEW_PROOF for locked + proof. Added SHOW RESTRICTED command. + 3-May-2016 m*.c - fix numerous conversion warnings provided by gcc 5.3.0 */ +/* 0.125 10-Mar-2016 mmpars.c - fixed bug parsing /EXPLICIT/PACKED format + 8-Mar-2016 nm mmdata.c - added "#nnn" to SHOW STATEMENT etc. to reference + statement number e.g. SHOW STATEMENT #58 shows a1i in set.mm. + 7-Mar-2016 nm mmwtex.c - added space between } and { in HTML output + 6-Mar-2016 nm mmpars.c - disabled wrapping of formula lines in + WRITE SOURCE.../REWRAP + 2-Mar-2016 nm metamat.c, mmcmdl.c, mmhlpb.c - added /FAST to + SAVE PROOF, SHOW PROOF */ +/* 0.123 25-Jan-2016 nm mmpars.c, mmdata.h, mmdata.c, mmpfas.c, mmcmds., + metamath.c, mmcmdl.c, mmwtex.c - unlocked SHOW PROOF.../PACKED, + added SHOW PROOF.../EXPLICIT */ +/* 0.122 14-Jan-2016 nm metamath.c, mmcmds.c, mmwtex.c, mmwtex.h - surrounded + math HTML output with "...; added htmlcss and + htmlfont $t commands + 10-Jan-2016 nm mmwtex.c - delete duplicate -4px style; metamath.c - + add   after char on mmascii.html + 3-Jan-2016 nm mmwtex.c - fix bug when doing SHOW STATEMENT * /ALT_HTML after + VERIFY MARKUP */ +/* 0.121 17-Nov-2015 nm metamath.c, mmcmdl.h, mmcmdl.c, mmcmds.h, mmcmds.c, + mmwtex.h, mmwtex.c, mmdata.h, mmdata.c - + 1. Moved WRITE BIBLIOGRAPHY code from metamath.c to its own function in + mmwtex.c; moved qsortStringCmp() from metamath.c to mmdata.c + 2. Added $t, comment markup, and bibliography checking to VERIFY MARKUP + 3. Added options to bug() bug-check interception to select aborting, + stepping to next bug, or ignoring subsequent bugs + 4. SHOW STATEMENT can now use both /HTML and /ALT_HTML in same session + 5. Added /HTML, /ALT_HTML to WRITE THEOREM_LIST and + WRITE RECENT_ADDITIONS */ +/* 0.120 7-Nov-2015 nm metamath.c, mmcmdl.c, mmpars.c - add VERIFY MARKUP + 4-Nov-2015 nm metamath.c, mmcmds.c/h, mmdata.c/h - move getDescription, + getSourceIndentation from mmcmds.c to mmdata.c. + metamath.c, mmdata.c - add and call parseDate() instead of in-line + code; add getContrib(), getProofDate(), buildDate(), compareDates(). */ +/* 0.119 18-Oct-2015 nm mmwtex.c - add summary TOC to Theorem List; improve + math symbol GIF image alignment + 2-Oct-2015 nm metamath.c, mmpfas.c, mmwtex.c - fix miscellaneous small + bugs or quirks */ +/* 0.118 18-Jul-2015 nm metamath.c, mmcmds.h, mmcmds.c, mmcmdl.c, mmhlpb.h, + mmhlpb.c - added /TO qualifier to SHOW TRACE_BACK. See + HELP SHOW TRACE_BACK. */ +/* 0.117 30-May-2015 + 1. nm mmwtex.c - move of Theorem List pages */ +/* 0.115 8-May-2015 nm mmwtex.c - added section header comments to + WRITE THEOREM_LIST and broke out Table of Contents page + 24-Apr-2015 nm metamath.c - add # bytes to end of "---Clip out the proof"; + reverted to no blank lines there (see 0.113 item 3) */ +/* 0.114 22-Apr-2015 nm mmcmds.c - put [-1], [-2],... offsets on 'show + new_proof/unknown' */ +/* 0.113 19-Apr-2015 so, nm metamath.c, mmdata.c + 1. SHOW LABEL % will show statements with changed proofs + 2. SHOW LABEL = will show the statement being proved in MM-PA + 3. Added blank lines before, after "---------Clip out the proof" proof + 4. Generate date only if the proof is complete */ +/* 0.112 15-Apr-2015 nm metamath.c - fix bug 1121 (reported by S. O'Rear); + mwtex.c - add "img { margin-bottom: -4px }" to CSS to align symbol GIFs; + mwtex.c - remove some hard coding for set.mm, for use with new nf.mm; + metamath.c - fix comment parsing in WRITE BIBLIOGRAPHY to ignore + math symbols */ +/* 0.111 22-Nov-2014 nm metamath.c, mmcmds.c, mmcmdl.c, mmhlpb.c - added + /NO_NEW_AXIOMS_FROM qualifier to MINIMIZE_WITH; see HELP MINIMIZE_WITH. + 21-Nov-2014 Stepan O'Rear mmdata.c, mmhlpb.c - added ~ label range specifier + to wildcards; see HELP SEARCH */ +/* 0.110 2-Nov-2014 nm mmcmds.c - fixed bug 1114 (reported by Stefan O'Rear); + metamath.c, mmhlpb.c - added "SHOW STATEMENT =" to show the statement + being proved in MM-PA (based on patch submitted by Stefan O'Rear) */ +/* 0.109 20-Aug-2014 nm mmwtex.c - fix corrupted HTML caused by misinterpreting + math symbols as comment markup (math symbols with _ [ ] or ~). Also, + allow https:// as well as http:// in ~ label markup. + 11-Jul-2014 wl mmdata.c - fix obscure crash in debugging mode db9 */ +/* 0.108 25-Jun-2014 nm + (1) metamath.c, mmcmdl.c, mmhlpb.c - MINIMIZE_WITH now checks the size + of the compressed proof, prevents $d violations, and tries forward and + reverse statment scanning order; /NO_DISTINCT, /BRIEF, /REVERSE + qualifiers were removed. + (2) mminou.c - prevent hard breaks (in the middle of a word) in too-long + lines (e.g. long URLs) in WRITE SOURCE .../REWRAP; just overflow the + screen width instead. + (3) mmpfas.c - fixed memory leak in replaceStatement() + (4) mmpfas.c - suppress inf. growth with MINIMIZE_WITH idi/ALLOW_GROWTH */ +/* 0.107 21-Jun-2014 nm metamath.c, mmcmdl.c, mmhlpb.c - added /SIZE qualifier + to SHOW PROOF; added SHOW ELAPSED_TIME; mmwtex.c - reformatted WRITE + THEOREM_LIST output; now "$(", newline, "######" starts a "part" */ +/* 0.106 30-Mar-2014 nm mmwtex.c - fix bug introduced by 0.105 that disabled + hyperlinks on literature refs in HTML comment. metamath.c - improve + messages */ +/* 0.105 15-Feb-2014 nm mmwtex.c - prevented illegal LaTeX output for certain + special characters in comments. */ +/* 0.104 14-Feb-2014 nm mmwtex.c - fixed bug 2312, mmcmds.c - enhanced ASSIGN + error message. */ +/* 0.103 4-Jan-2014 nm mmcmds.c,h - added "Allowed substitution hints" below + the "Distinct variable groups" list on generated web pages + mmwtex.c - added "*" to indicate DV's occur in Statement List entries. */ +/* 0.102 2-Jan-2014 nm mminou.c - made compressed proof line wrapping more + uniform at start of compressed part of proof */ +/* 0.101 27-Dec-2013 nm mmdata.h,c, mminou.c, mmcmdl.c, mmhlpb.c, mmvstr.c - + Improved storage efficiency of /COMPRESSED proofs (but with 20% slower run + time); added /OLD_COMPRESSION to specify old algorithm; removed end-of-line + space after label list in old algorithm; fixed linput() bug */ +/* 0.100 30-Nov-2013 nm mmpfas.c - reversed statement scan order in + proveFloating(), to speed up SHOW STATEMENT df-* /HTML; metamath.c - remove + the unknown date place holder in SAVE NEW_PROOF; Wolf Lammen mmvstr.c - + some cleanup */ +/* 0.07.99 1-Nov-2013 nm metamath.c, mmpfas.h,c, mmcmdl.h,c, mmhlpa.c, + mmhlpb.c - added UNDO, REDO, SET UNDO commands (see HELP UNDO) */ +/* 0.07.98 30-Oct-2013 Wolf Lammen mmvstr.c,h, mmiou.c, mmpars.c, + mmdata.c - improve code style and program structure */ +/* 0.07.97 20-Oct-2013 Wolf Lammen mmvstr.c,h, metamath.c - improved linput(); + nm mmcmds.c, mmdata.c - tolerate bad proofs in SHOW TRACE_BACK etc. */ +/* 0.07.96 20-Sep-2013 Wolf Lammen mmvstr.c - revised cat(); + nm mmwtex.c, mminou.c - change a print2 to printLongLine to fix bug 1150 */ +/* 0.07.95 18-Sep-2013 Wolf Lammen mmvstr.c - optimized cat(); + nm metamath.c, mmcmds.c, mmdata.c, mmpars.c, mmpfas.c, mmvstr.c, + mmwtex.c - suppress some clang warnings */ +/* 0.07.94 28-Aug-2013 Alexey Merkulov mmcmds.c, mmpars.c - fixed several + memory leaks found by valgrind --leak-check=full --show-possibly-lost=no */ +/* 0.07.93 8-Jul-2013 Wolf Lammen mmvstr.c - simplified let() function; + also many minor changes in m*.c and m*.h to assist future refactoring */ +/* 0.07.92 28-Jun-2013 nm metamath.c mmcmds.c,h mmcmdl.c mmhlpb.c- added + /NO_REPEATED_STEPS for /LEMMON mode of SHOW PROOF, SHOW NEW_PROOF. + This reverts the /LEMMON mode default display change of 31-Jan-2010 + and invokes it when desired via /NO_REPEATED_STEPS. */ +/* 0.07.91 20-May-2013 nm metamath.c mmpfas.c,h mmcmds.c,h mmcmdl.c + mmhlpb.c- added /FORBID qualifier to MINIMIZE_WITH */ +/* 0.07.90 19-May-2013 nm metamath.c mmcmds.c mmcmdl.c mmhlpb.c - added /MATCH + qualifier to SHOW TRACE_BACK */ +/* 0.07.88 18-Nov-2012 nm mmcmds.c - fixed bug 243 */ +/* 0.07.87 17-Nov-2012 nm mmwtex.c - fixed formatting problem when label + markup ends a comment in SHOW PROOF ... /HTML */ +/* 0.07.86 27-Oct-2012 nm mmcmds.c, mmwtex.c, mmwtex.h - fixed ERASE bug + caused by imperfect re-initialization; reported by Wolf Lammen */ +/* 0.07.85 10-Oct-2012 nm metamath.c, mmcmdl.c, mmwtex.c, mmwtex.h, mmhlpb.c - + added /SHOW_LEMMAS to WRITE THEOREM_LIST to bypass lemma math suppression */ +/* 0.07.84 9-Oct-2012 nm mmcmds.c - fixed bug in getStatementNum() */ +/* 0.07.83 19-Sep-2012 nm mmwtex.c - fixed bug reported by Wolf Lammen */ +/* 0.07.82 16-Sep-2012 nm metamath.c, mmpfas.c - fixed REPLACE infinite loop; + improved REPLACE message for shared dummy variables */ +/* 0.07.81 14-Sep-2012 nm metamath.c, mmcmds.c, mmcmds.h, mmcmdl.c, mmhlpb.c + - added FIRST, LAST, +nn, -nn where missing from ASSIGN, REPLACE, + IMPROVE, LET STEP. Wildcards are allowed for PROVE, ASSIGN, REPLACE + labels provided there is a unique match. */ +/* 0.07.80 4-Sep-2012 nm metamath.c, mmpfas.c, mmpfas.h, mmcmdl.c, mmhlpb.c + - added / 1, / 2, / 3, / SUBPROOFS to IMPROVE to specify search level */ +/* 0.07.79 31-Aug-2012 nm m*.c - clean up some gcc warnings */ +/* 0.07.78 28-Aug-2012 nm mmpfas.c - fix bug in 0.07.77. */ +/* 0.07.77 25-Aug-2012 nm metamath.c, mmpfas.c - Enhanced IMPROVE algorithm to + allow non-shared dummy variables in unknown steps */ +/* 0.07.76 22-Aug-2012 nm metamath.c, mmpfas.c, mmcmdl.c, mmhlpb.c - + Enhanced IMPROVE algorithm to also try REPLACE algorithm */ +/* 0.07.75 14-Aug-2012 nm metamath.c - MINIMIZE_WITH now checks current + mathbox (but not other mathboxes) even if /INCLUDE_MATHBOXES is omitted */ +/* 0.07.74 18-Mar-2012 nm mmwtex.c, mmcmds.c, metamath.c - improved texToken() + error message */ +/* 0.07.73 26-Dec-2011 nm mmwtex.c, mmpars.c - added ... in + comments for passing through raw HTML code into HTML files generated with + SHOw STATEMENT xxx / HTML */ +/* 0.07.72 25-Dec-2011 nm (obsolete) */ +/* 0.07.71 10-Nov-2011 nm metamath.c, mmcmdl.c - added /REV to MINIMIZE_WITH */ +/* 0.07.70 6-Aug-2011 nm mmwtex.c - fix handling of double quotes inside + of htmldef strings to match spec in Metamath book Appendix A p. 156 */ +/* 0.07.69 9-Jul-2011 nm mmpars.c, mmvstr.c - Untab file in WRITE SOURCE + ... /REWRAP */ +/* 0.07.68 3-Jul-2011 nm metamath.c, mminou.h, mminou.c - Nested SUBMIT calls + (SUBMIT calls inside of a SUBMIT command file) are now allowed. + Also, mmdata.c - fix memory leak. */ +/* 0.07.67 2-Jul-2011 nm metamath.c, mmcmdl.c, mmhlpa.c - Added TAG command + to TOOLS. See HELP TAG under TOOLS. (The old special-purpose TAG command + was renamed to UPDATE.) */ +/* 0.07.66 1-Jul-2011 nm metamath.c, mmcmds.c, mmpars.c, mmpars.h - Added code + to strip spurious "$( [?] $)" in WRITE SOURCE ... /CLEAN output */ +/* 0.07.65 30-Jun-2011 nm mmwtex.c - Prevent processing [...] bibliography + brackets inside of `...` math strings in comments. */ +/* 0.07.64 28-Jun-2011 nm metamath.c, mmcmdl.c - Added /INCLUDE_MATHBOXES + qualifier to MINIMIZE_WITH; without it, MINIMIZE_WITH * will skip + checking user mathboxes. */ +/* 0.07.63 26-Jun-2011 nm mmwtex.c - check that .gifs exist for htmldefs */ +/* 0.07.62 18-Jun-2011 nm mmpars.c - fixed bug where redeclaration of active + $v was not detected */ +/* 0.07.61 12-Jun-2011 nm mmpfas.c, mmcmds.c, metamath.c, mmhlpb.c - added + /FORMAT and /REWRAP qualifiers to WRITE SOURCE to format according to set.mm + conventions - set HELP WRITE SOURCE */ +/* 0.07.60 7-Jun-2011 nm mmpfas.c - fixed bug 1805 which occurred when doing + MINIMIZE_WITH weq/ALLOW_GROWTH after DELETE DELETE FLOATING_HYPOTHESES */ +/* 0.07.59 11-Dec-2010 nm mmpfas.c - increased default SET SEARCH_LIMIT from + 10000 to 25000 to accomodate df-plig web page in set.mm */ +/* 0.07.58 9-Dec-2010 nm mmpars.c - detect if same symbol is used with both + $c and $v, in order to conform with Metamath spec */ +/* 0.07.57 19-Oct-2010 nm mmpars.c - fix bug causing incorrect line count + for error messages when non-ASCII character was found; mminou.h - + increase SET WIDTH maximum from 999 to 9999 */ +/* 0.07.56 27-Sep-2010 nm mmpars.c, mmpfas.c - check for $a's with + one token e.g. "$a wff $."; if found, turn SET EMPTY_SUBSTITUTION ON + automatically. (Suggested by Mel O'Cat; patent pending.) */ +/* 0.07.55 26-Sep-2010 nm mmunif.c, mmcmds.c, mmunif.h - check for mismatched + brackets in all $a's, so that if there are any, the bracket matching + algorithm (for fewer ambiguous unifications) in mmunif.c will be turned + off. */ +/* 0.07.54 25-Sep-2010 nm mmpars.c - added $f checking to conform to the + current Metamath spec, so footnote 2 on p. 92 of Metamath book is + no longer applicable. */ +/* 0.07.53 24-Sep-2010 nm mmveri.c - fixed bug(2106), reported by Michal + Burger */ +/* 0.07.52 14-Sep-2010 nm metamath.c, mmwtex.h, mmwtex.c, mmcmds.c, + mmcmdl.c, mmhlpb.c - rewrote the LaTeX output for easier hand-editing + and embedding in LaTeX documents. The old LaTeX output is still + available with /OLD_TEX on OPEN TEX, SHOW STATEMENT, and SHOW PROOF, + but it is obsolete and will be deleted eventually if no one objects. The + new /TEX output also replaces the old /SIMPLE_TEX, which was removed. */ +/* 0.07.51 9-Sep-2010 Stefan Allen mmwtex.c - put hyperlinks on hypothesis + label references in SHOW STATEMENT * /HTML, ALT_HTML output */ +/* 0.07.50 21-Feb-2010 nm mminou.c - "./metamath < empty", where "empty" is a + 0-byte file, now exits metamath instead of producing an infinite loop. + Also, ^D now exits metamath. Reported by Cai Yufei */ +/* 0.07.49 31-Jan-2010 nm mmcmds.c - Lemmon-style proofs (SHOW PROOF xxx + /LEMON/RENUMBER) no longer have steps with dummy labels; instead, steps + are now the same as in HTML page proofs. (There is a line to comment + out if you want to revert to old behavior.) */ +/* 0.07.48 11-Sep-2009 nm mmpars.c, mm, mmvstr.c, mmdata.c - Added detection of + non-whitespace around keywords (mmpars.c); small changes to eliminate + warnings in gcc 3.4.4 (mmvstr.c, mmdata.c) */ +/* 0.07.47 2-Aug-2009 nm mmwtex.c, mmwtex.h - added user name to mathbox + pages */ +/* 0.07.46 24-Jul-2009 nm metamath.c, mmwtex.c - changed name of sandbox + to "mathbox" */ +/* 0.07.45 15-Jun-2009 nm metamath.c, mmhlpb.c - put "!" before each line of + SET ECHO ON output to make them easy to identity for creating scripts */ +/* 0.07.44 12-May-2009 Stefan Allan, nm metamath.c, mmcmdl.c, mmwtex.c - + added SHOW STATEMENT / MNEMONICS - see HELP SHOW STATEMENT */ +/* 0.07.43 29-Aug-2008 nm mmwtex.c - workaround for Unicode huge font bug in + FireFox 3 */ +/* 0.07.42 8-Aug-2008 nm metamath.c - added sandbox, Hilbert Space colors to + Definition List */ +/* 0.07.41 29-Jul-2008 nm metamath.c, mmwtex.h, mmwtex.c - Added handling of + sandbox section of Metamath Proof Explorer web pages */ +/* 0.07.40 6-Jul-2008 nm metamath.c, mmcmdl.c, mmhlpa.c, mmhlpb.c - Added + / NO_VERSIONING qualifier for SHOW STATEMENT, so website can be regenerated + in place with less temporary space required. Also, the wildcard trigger + for mmdefinitions.html, etc. is more flexible (see HELP HTML). */ +/* 0.07.39 21-May-2008 nm metamath.c, mmhlpb.c - Added wildcard handling to + statement label in SHOW TRACE_BACK. All wildcards now allow + comma-separated lists [i.e. matchesList() instead of matches()] */ +/* 0.07.38 26-Apr-2008 nm metamath.c, mmdata.h, mmdata.c, mmvstr.c, mmhlpb.c - + Enhanced / EXCEPT qualifier for MINIMIZE_WITH to handle comma-separated + wildcard list. */ +/* 0.07.37 14-Apr-2008 nm metamath.c, mmcmdl.c, mmhlpb.c - Added / JOIN + qualifier to SEARCH. */ +/* 0.07.36 7-Jan-2008 nm metamath.c, mmcmdl.c, mmhlpb.c - Added wildcard + handling for labels in SHOW USAGE. */ +/* 0.07.35 2-Jan-2008 nm mmcmdl.c, metamath.c, mmhlpb.c - Changed keywords + COMPACT to PACKED and COLUMN to START_COLUMN so that SAVE/SHOW proof can use + C to abbreviate COMPRESSED. (PACKED format is supported but "unofficial," + used mainly for debugging purposes, and is not listed in HELP SAVE + PROOF.) */ +/* 0.07.34 19-Nov-2007 nm mmwtex.c, mminou.c - Added tooltips to proof step + hyperlinks in SHOW STATEMENT.../HTML,ALT_HTML output (suggested by Reinder + Verlinde) */ +/* 0.07.33 19-Jul-2007 nm mminou.c, mmvstr.c, mmdata.c, mmword.c - added fflush + after each printf() call for proper behavior inside emacs (suggested by + Frederic Line) */ +/* 0.07.32 29-Apr-2007 nm mminou.c - fSafeOpen now stops at gap; e.g. if ~2 + doesn't exist, ~1 will be renamed to ~2, but any ~3, etc. are not touched */ +/* 0.07.31 5-Apr-2007 nm mmwtex.c - Don't make "_" in hyperlink a subscript */ +/* 0.07.30 8-Feb-2007 nm mmcmds.c, mmwtex.c Added HTML statement number info to + SHOW STATEMENT.../FULL; friendlier "Contents+1" link in mmtheorems*.html */ +/* 0.07.29 6-Feb-2007 Jason Orendorff mmpfas.c - Patch to eliminate the + duplicate "Exceeded trial limit at step n" messages */ +/* 0.07.28 22-Dec-2006 nm mmhlpb.c - Added info on quotes to HELP LET */ +/* 0.07.27 23-Oct-2006 nm metamath.c, mminou.c, mmhlpa.c, mmhlpb.c - Added + / SILENT qualifier to SUBMIT command */ +/* 0.07.26 12-Oct-2006 nm mminou.c - Fixed bug when SUBMIT file was missing + a new-line at end of file (reported by Marnix Klooster) */ +/* 0.07.25 10-Oct-2006 nm metamath.c - Fixed bug invoking TOOLS as a ./metamath + command-line argument */ +/* 0.07.24 25-Sep-2006 nm mmcmdl.c Fixed bug in + SHOW NEW_PROOF/START_COLUMN nn/LEM */ +/* 0.07.23 31-Aug-2006 nm mmwtex.c - Added Home and Contents links to bottom of + WRITE THEOREM_LIST pages */ +/* 0.07.22 26-Aug-2006 nm metamath.c, mmcmdl.c, mmhlpb.c - Changed 'IMPROVE + STEP ' to 'IMPROVE ' for user convenience and to be consistent + with ASSIGN */ +/* 0.07.21 20-Aug-2006 nm mmwtex.c - Revised small colored numbers so that all + colors have the same grayscale brightness.. */ +/* 0.07.20 19-Aug-2006 nm mmpars.c - Made the error "Required hypotheses may + not be explicitly declared" in a compressed proof non-severe, so that we + can still SAVE the proof to reformat and recover it. */ +/* 0.07.19 11-Aug-06 nm mmcmds.c - "Distinct variable group(s)" is now + "group" or "groups" as appropriate. */ +/* 0.07.18 31-Jul-06 nm mmwtex.c - added table to contents to p.1 of output of + WRITE THEOREM_LIST command. */ +/* 0.07.17 4-Jun-06 nm mmpars.c - do not allow labels to match math symbols + (new spec proposed by O'Cat). mmwtex.c - made theorem name 1st in title, + for readability in Firefox tabs. */ +/* 0.07.16 16-Apr-06 nm metamath.c, mmcmdl.c, mmpfas.c, mmhlpb.c - allow step + to be negative (relative to end of proof) for ASSIGN, UNIFY, and LET STEP + (see their HELPs). Added INITIALIZE USER to delete LET STEP assignments + (see HELP INITIALIZE). Fixed bug in LET STEP (mmpfas.c). */ +/* 0.07.15 10-Apr-06 nm metamath.c, mmvstr.c - change dates from 2-digit to + 4-digit year; make compatible with older 2-digit year. */ +/* 0.07.14 21-Mar-06 nm mmpars.c - fix bug 1722 when compressed proof has + "Z" at beginning of proof instead of after a proof step. */ +/* 0.07.13 3-Feb-06 nm mmpfas.c - minor improvement to MINIMIZE_WITH */ +/* 0.07.12 30-Jan-06 nm metamath.c, mmcmds.c, mmdata.c, mmdata.h, mmhlpa.c, + mmhlpb.c - added "?" wildcard to match single character. See HELP SEARCH. */ +/* 0.07.11 7-Jan-06 nm metamath.c, mmcmdl.c, mmhlpb.c - added EXCEPT qualifier + to MINIMIZE_WITH */ +/* 0.07.10 28-Dec-05 nm metamath.c, mmcmds.c - cosmetic tweaks */ +/* 0.07.10 11-Dec-05 nm metamath.c, mmcmdl.c, mmhlpb.c - added ASSIGN FIRST + and IMPROVE FIRST commands. Also enhanced READ error message */ +/* 0.07.9 1-Dec-05 nm mmvstr.c - added comment on how to make portable */ +/* 0.07.9 18-Nov-05 nm metamath.c, mminou.c, mminou.h, mmcmdl.c, mmhlpb.c - + added SET HEIGHT command; changed SET SCREEN_WIDTH to SET WIDTH; changed + SET HENTY_FILTER to SET JEREMY_HENTY_FILTER (to make H for HEIGHT + unambiguous); added HELP for SET JEREMY_HENTY_FILTER */ +/* 0.07.8 15-Nov-05 nm mmunif.c - now detects wrong order in bracket matching + heuristic to further reduce ambiguous unifications in Proof Assistant */ +/* 0.07.7 12-Nov-05 nm mmunif.c - add "[","]" and "[_","]_" bracket matching + heuristic to reduce ambiguous unifications in Proof Assistant. + mmwtex.c - added heuristic for HTML spacing after "sum_" token. */ +/* 0.07.6 15-Oct-05 nm mmcmds.c,mmpars.c - fixed compressed proof algorithm + to match spec in book (with new algorithm due to Marnix Klooster). + Users are warned to convert proofs when the old compression is found. */ +/* 0.07.5 6-Oct-05 nm mmpars.c - fixed bug that reset "severe error in + proof" flag when a proof with severe error also had unknown steps */ +/* 0.07.4 1-Oct-05 nm mmcmds.c - ignored bug 235, which could happen for + non-standard logics */ +/* 0.07.3 17-Sep-05 nm mmpars.c - reinstated duplicate local label checking to + conform to strict spec */ +/* 0.07.2 19-Aug-05 nm mmwtex.c - suppressed math content for lemmas in + WRITE THEOREMS output */ +/* 0.07.1 28-Jul-05 nm Added SIMPLE_TEX qualifier to SHOW STATEMENT */ +/* 0.07: Official 0.07 22-Jun-05 corresponding to Metamath book */ +/* 0.07x: Fixed to work with AMD64 with 64-bit longs by + Waldek Hebisch; deleted unused stuff in mmdata.c */ +/* 0.07w: .mm date format like "$( [7-Sep-04] $)" is now + generated and permitted (old one is tolerated too for compatibility) */ +/* Metamath Proof Verifier - main program */ +/* See the book "Metamath" for description of Metamath and run instructions */ + +/*****************************************************************************/ + + +/*----------------------------------------------------------------------*/ + + +#include +#include +#include +#include +#include +#include +#include "mmvstr.h" +#include "mmdata.h" +#include "mmcmdl.h" +#include "mmcmds.h" +#include "mmhlpa.h" +#include "mmhlpb.h" +#include "mminou.h" +#include "mmpars.h" +#include "mmveri.h" +#include "mmpfas.h" +#include "mmunif.h" +#include "mmword.h" +#include "mmwsts.h" +#include "mmwtex.h" + +void command(int argc, char *argv[]); + +int main(int argc, char *argv[]) { + +/* argc is the number of arguments; argv points to an array containing them */ + + /****** If g_listMode is set to 1 here, the startup will be Text Tools + utilities, and Metamath will be disabled ***************************/ + /* (Historically, this mode was used for the creation of a stand-alone + "TOOLS>" utility for people not interested in Metamath. This utility + was named "LIST.EXE", "tools.exe", and "tools" on VMS, DOS, and Unix + platforms respectively. The UPDATE command of TOOLS (mmword.c) was + custom-written in accordance with the version control requirements of a + company that used it; it documents the differences between two versions + of a program as C-style comments embedded in the newer version.) */ + g_listMode = 0; /* Force Metamath mode as startup */ + + + g_toolsMode = g_listMode; + + if (!g_listMode) { + /*print2("Metamath - Version %s\n", MVERSION);*/ + print2("Metamath - Version %s%s", MVERSION, space(27 - (long)strlen(MVERSION))); + } + print2("Type HELP for help, EXIT to exit.\n"); + + /* Allocate big arrays */ + initBigArrays(); + + /* Set the default contributor */ + let(&g_contributorName, DEFAULT_CONTRIBUTOR); + + /* Process a command line until EXIT */ + command(argc, argv); + + /* Close logging command file */ + if (g_listMode && g_listFile_fp != NULL) { + fclose(g_listFile_fp); + } + + return 0; + +} + + + + +void command(int argc, char *argv[]) { + /* Command line user interface -- this is an infinite loop; it fetches and + processes a command; returns only if the command is 'EXIT' or 'QUIT' and + never returns otherwise. */ + long argsProcessed = 0; /* Number of argv initial command-line + arguments processed so far */ + + long /*c,*/ i, j, k, m, l, n, p, q, r, s /*,tokenNum*/; + long stmt, step; + int subType = 0; +#define SYNTAX 4 + vstring str1 = "", str2 = "", str3 = "", str4 = "", str5= ""; + nmbrString *nmbrTmpPtr; /* Pointer only; not allocated directly */ + nmbrString *nmbrTmp = NULL_NMBRSTRING; + nmbrString *nmbrSaveProof = NULL_NMBRSTRING; + /*pntrString *pntrTmpPtr;*/ /* Pointer only; not allocated directly */ + pntrString *pntrTmp = NULL_PNTRSTRING; + pntrString *expandedProof = NULL_PNTRSTRING; + flag tmpFlag; + + /* proofSavedFlag tells us there was at least one + SAVE NEW_PROOF during the MM-PA session while the UNDO stack wasn't + empty, meaning that "UNDO stack empty" is no longer a reliable indication + that the proof wasn't changed. It is cleared upon entering MM-PA, and + set by SAVE NEW_PROOF. */ + flag proofSavedFlag = 0; + + /* Variables for SHOW PROOF */ + flag pipFlag; /* Proof-in-progress flag */ + long outStatement; /* Statement for SHOW PROOF or SHOW NEW_PROOF */ + flag explicitTargets; /* For SAVE PROOF /EXPLICIT */ + long startStep; long endStep; + /* long startIndent; */ + long endIndent; /* Also for SHOW TRACE_BACK */ + flag essentialFlag; /* Also for SHOW TRACE_BACK */ + flag renumberFlag; /* Flag to use essential step numbering */ + flag unknownFlag; + flag notUnifiedFlag; + flag reverseFlag; + long detailStep; + flag noIndentFlag; /* Flag to use non-indented display */ + long splitColumn; /* Column at which formula starts in nonindented display */ + flag skipRepeatedSteps; /* NO_REPEATED_STEPS qualifier */ + flag texFlag; /* Flag for TeX */ + flag saveFlag; /* Flag to save in source */ + flag fastFlag; /* Flag for SAVE PROOF.../FAST */ + long indentation; /* Number of spaces to indent proof */ + vstring labelMatch = ""; /* SHOW PROOF ", + g_Statement[stmt].labelName, "", + str4, "", NULL), /* Description */ + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + + g_showStatement = stmt; /* For printTexComment */ + g_outputToString = 0; /* For printTexComment */ + g_texFilePtr = list2_fp; + printTexComment(str3, /* Sends result to g_texFilePtr */ + 0, /* 1 = htmlCenterFlag */ + PROCESS_EVERYTHING, /* actionBits */ + 1 /* 1 = fileCheck */ ); + g_texFilePtr = NULL; + g_outputToString = 1; /* Restore after printTexComment */ + + /* Get HTML hypotheses => assertion */ + let(&str4, ""); + str4 = getTexOrHtmlHypAndAssertion(stmt); + printLongLine(cat("" : + cat(" BGCOLOR=", PURPLISH_BIBLIO_COLOR, ">", NULL), + */ + + (stmt < g_extHtmlStmt) + ? ">" + : (stmt < g_mathboxStmt) + ? cat(" BGCOLOR=", PURPLISH_BIBLIO_COLOR, ">", + NULL) + : cat(" BGCOLOR=", SANDBOX_COLOR, ">", NULL), + + "", + str4, "", NULL), + + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + + g_outputToString = 0; + fprintf(list2_fp, "%s", g_printString); + let(&g_printString, ""); + + if (n >= i /*RECENT_COUNT*/) break; /* We're done */ + + /* Put separator row if not last theorem */ + g_outputToString = 1; + printLongLine(cat("", + " ", NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + + /* Put the previous, current, and next statement + labels in HTML comments so a script can use them to update + web site incrementally. This would be done by searching + for "For script" and gather label between = and --> then + regenerate just those statements. Previous and next labels + are included to prevent dead links if they don't exist yet. */ + /* This section can be deleted without side effects */ + /* Find the previous statement with a web page */ + j = 0; + for (q = stmt - 1; q >= 1; q--) { + if (g_Statement[q].type == (char)p_ || + g_Statement[q].type == (char)a_ ) { + j = q; + break; + } + } + /* 13-Dec-2018 nm This isn't used anywhere yet. But fix error + in current label and also identify previous, current, next */ + if (j) print2("\n", + g_Statement[j].labelName); + /* Current statement */ + print2("\n", + g_Statement[stmt].labelName); + /* Find the next statement with a web page */ + j = 0; + for (q = stmt + 1; q <= g_statements; q++) { + if (g_Statement[q].type == (char)p_ || + g_Statement[q].type == (char)a_ ) { + j = q; + break; + } + } + if (j) print2("\n", + g_Statement[j].labelName); + + g_outputToString = 0; + fprintf(list2_fp, "%s", g_printString); + let(&g_printString, ""); + + } + } /* Next stmt - statement number */ + /* Decrement date */ + if (k > 1) { + k--; /* Decrement day */ + } else { + k = 31; /* Non-existent day 31's will never match, which is OK */ + if (l > 1) { + l--; /* Decrement month */ + } else { + l = 12; /* Dec */ + m --; /* Decrement year */ + } + } + } /* next while - Scan next date */ + + + /* Discard the input file up to the special "" comment */ + while (1) { + if (!linput(list1_fp, NULL, &str1)) { + print2( +"?Error: Could not find \"\" line in input file \"%s\".\n", + g_fullArg[2]); + tmpFlag = 1; /* Error flag to recover input file */ + break; + } + if (!strcmp(str1, "")) { + fprintf(list2_fp, "%s\n", str1); + break; + } + } + if (tmpFlag) goto wrrecent_error; + + /* Transfer the rest of the input file */ + while (1) { + if (!linput(list1_fp, NULL, &str1)) { + break; + } + + /* Update the date stamp at the bottom of the HTML page. */ + /* This is just a nicety; no error check is done. */ + if (!strcmp("This page was last updated on ", left(str1, 30))) { + let(&str1, cat(left(str1, 30), date(), ".", NULL)); + } + + fprintf(list2_fp, "%s\n", str1); + } + + print2("The %ld most recent theorem(s) were written.\n", n); + + wrrecent_error: + fclose(list1_fp); + fclose(list2_fp); + if (tmpFlag) { + /* Recover input files in case of error */ + remove(g_fullArg[2]); /* Delete output file */ + rename(cat(g_fullArg[2], "~1", NULL), g_fullArg[2]); + /* Restore input file name */ + print2("?The file \"%s\" was not modified.\n", g_fullArg[2]); + } + continue; + } /* End of "WRITE RECENT_ADDITIONS" */ + + + if (cmdMatches("SHOW LABELS")) { + linearFlag = 0; + if (switchPos("/ LINEAR")) linearFlag = 1; + if (switchPos("/ ALL")) { + m = 1; /* Include $e, $f statements */ + print2( +"The labels that match are shown with statement number, label, and type.\n"); + } else { + m = 0; /* Show $a, $p only */ + print2( +"The assertions that match are shown with statement number, label, and type.\n"); + } + j = 0; + k = 0; + let(&str2, ""); /* Line so far */ +#define COL 20 /* Column width */ +#define MIN_SPACE 2 /* At least this many spaces between columns */ + for (i = 1; i <= g_statements; i++) { + if (!g_Statement[i].labelName[0]) continue; /* No label */ + if (!m && g_Statement[i].type != (char)p_ && + g_Statement[i].type != (char)a_) continue; /* No /ALL switch */ + if (!matchesList(g_Statement[i].labelName, g_fullArg[2], '*', '?')) { + continue; + } + + let(&str1, cat(str((double)i), " ", + g_Statement[i].labelName, " $", chr(g_Statement[i].type), + NULL)); + if (!str2[0]) { + j = 0; /* # of fields on line so far */ + } + k = ((long)strlen(str2) + MIN_SPACE > j * COL) + ? (long)strlen(str2) + MIN_SPACE : j * COL; + /* Position before new str1 starts */ + if (k + (long)strlen(str1) > g_screenWidth || linearFlag) { + if (j == 0) { + /* In case of huge label, force it out anyway */ + printLongLine(str1, "", " "); + } else { + /* Line width exceeded, postpone adding str1 */ + print2("%s\n", str2); + let(&str2, str1); + j = 1; + } + } else { + /* Add new field to line */ + if (j == 0) { + let(&str2, str1); /* Don't put space before 1st label on line */ + } else { + let(&str2, cat(str2, space(k - (long)strlen(str2)), str1, NULL)); + } + j++; + } + } /* next i */ + if (str2[0]) { + print2("%s\n", str2); + let(&str2, ""); + } + let(&str1, ""); + continue; + } + + if (cmdMatches("SHOW DISCOURAGED")) { + showDiscouraged(); + continue; + } + + if (cmdMatches("SHOW SOURCE")) { + /* Currently, SHOW SOURCE only handles one statement at a time, + so use getStatementNum(). Eventually, SHOW SOURCE may become + obsolete; I don't think anyone uses it. */ + s = getStatementNum(g_fullArg[2], + 1/*startStmt*/, + g_statements + 1 /*maxStmt*/, + 1/*aAllowed*/, + 1/*pAllowed*/, + 1/*eAllowed*/, + 1/*fAllowed*/, + 0/*efOnlyForMaxStmt*/, + 1/*uniqueFlag*/); + if (s == -1) { + continue; /* Error msg was provided */ + } + g_showStatement = s; /* Update for future defaults */ + + let(&str1, ""); + str1 = outputStatement(g_showStatement, /* cleanFlag */ + 0 /* reformatFlag */); + let(&str1,edit(str1,128)); /* Trim trailing spaces */ + if (str1[strlen(str1)-1] == '\n') let(&str1, left(str1, + (long)strlen(str1) - 1)); + printLongLine(str1, "", ""); + let(&str1,""); /* Deallocate vstring */ + continue; + } /* if (cmdMatches("SHOW SOURCE")) */ + + + if (cmdMatches("SHOW STATEMENT") && ( + switchPos("/ HTML") + || switchPos("/ BRIEF_HTML") + || switchPos("/ ALT_HTML") + || switchPos("/ STS") + || switchPos("/ BRIEF_ALT_HTML"))) { + /* Special processing for the / HTML qualifiers - for each matching + statement, a .html file is opened, the statement is output, + and depending on statement type a proof or other information + is output. */ + + noVersioning = (switchPos("/ NO_VERSIONING") != 0); + i = 5; /* # arguments with only / HTML or / ALT_HTML */ + if (noVersioning) i = i + 2; + if (switchPos("/ TIME")) i = i + 2; + if (switchPos("/ STS")) i = i + 1; + if (g_rawArgs != i) { + printLongLine(cat("?The HTML qualifiers may not be combined with", + " others except / NO_VERSIONING and / TIME.\n", NULL), " ", " "); + continue; + } + + printTime = 0; + if (switchPos("/ TIME") != 0) { + printTime = 1; + } + + g_htmlFlag = 1; + + if (switchPos("/ BRIEF_HTML") || switchPos("/ BRIEF_ALT_HTML")) { + if (strcmp(g_fullArg[2], "*")) { + print2( + "?For BRIEF_HTML or BRIEF_ALT_HTML, the label must be \"*\"\n"); + goto htmlDone; + } + g_briefHtmlFlag = 1; + } else { + g_briefHtmlFlag = 0; + } + + if (switchPos("/ ALT_HTML") || switchPos("/ BRIEF_ALT_HTML")) { + g_altHtmlFlag = 1; + } else { + g_altHtmlFlag = 0; + } + + if (switchPos("/ STS")) { + stsFlag = 1; + let(&stsOutput, g_fullArg[5]); + + /* Parse the STS rules corresponding to the expected output. */ + parseSTSRules(stsOutput); + } + + q = 0; + + /* Special feature: if the match statement starts with "*", we + will also output mmascii.html, mmtheoremsall.html, and + mmdefinitions.html. So, with + SHOW STATEMENT * / HTML + these will be output plus all statements; with + SHOW STATEMENT *! / HTML + these will be output with no statements (since ! is illegal in a + statement label); with + SHOW STATEMENT ?* / HTML + all statements will be output, but without mmascii.html etc. */ + if (((char *)(g_fullArg[2]))[0] == '*' || g_briefHtmlFlag) { + s = -2; /* -2 is for ASCII table; -1 is for theorems; + 0 is for definitions */ + } else { + s = 1; + } + + for (s = s + 0; s <= g_statements; s++) { + + if (s > 0 && g_briefHtmlFlag) break; /* Only do summaries */ + + /* + s = -2: mmascii.html + s = -1: mmtheoremsall.html (used to be mmtheorems.html) + s = 0: mmdefinitions.html + s > 0: normal statement + */ + + if (s > 0) { + if (!g_Statement[s].labelName[0]) continue; /* No label */ + if (!matchesList(g_Statement[s].labelName, g_fullArg[2], '*', '?')) + continue; + if (g_Statement[s].type != (char)a_ + && g_Statement[s].type != (char)p_) continue; + } + + q = 1; /* Flag that at least one matching statement was found */ + + if (s > 0) { + g_showStatement = s; + } else { + /* We set it to 1 here so we will output the Metamath Proof + Explorer and not the Hilbert Space Explorer header for + definitions and theorems lists, when g_showStatement is + compared to g_extHtmlStmt in printTexHeader in mmwtex.c */ + g_showStatement = 1; + } + + + /*** Open the html file ***/ + g_htmlFlag = 1; + /* Open the html output file */ + switch (s) { + case -2: + let(&g_texFileName, "mmascii.html"); + break; + case -1: + let(&g_texFileName, "mmtheoremsall.html"); + break; + case 0: + let(&g_texFileName, "mmdefinitions.html"); + break; + default: + let(&g_texFileName, cat(g_Statement[g_showStatement].labelName, ".html", + NULL)); + } + /* Post processing (for pre-rendering) */ + if (stsFlag && strlen(postProcess) != 0) { + vstring pipeCommand = ""; + print2("Creating and processing HTML file \"%s\"...\n", g_texFileName); + let(&pipeCommand, cat(postProcess, " > ", g_texFileName, NULL)); + g_texFilePtr = popen(pipeCommand, "w"); + if (!g_texFilePtr) print2("?Could not execute the command \"%s\".\n", + pipeCommand); + let(&pipeCommand, ""); + } else { + print2("Creating HTML file \"%s\"...\n", g_texFileName); + g_texFilePtr = fSafeOpen(g_texFileName, "w", noVersioning); + } + if (!g_texFilePtr) goto htmlDone; /* Couldn't open it (err msg was + provided) */ + g_texFileOpenFlag = 1; + printTexHeader((s > 0) ? 1 : 0 /*texHeaderFlag*/); + if (!g_texDefsRead) { + /* If there was an error reading the $t xx.mm statement, + g_texDefsRead won't be set, and we should close out file and skip + further processing. Otherwise we will be attempting to process + uninitialized htmldef arrays and such. */ + print2("?HTML generation was aborted due to the error above.\n"); + s = g_statements + 1; /* To force loop to exit */ + goto ABORT_S; /* Go to end of loop where file is closed out */ + } + + if (s <= 0) { + g_outputToString = 1; + if (s == -2) { + printLongLine(cat("
", + "Symbol to ASCII Correspondence for Text-Only Browsers", + " (in order of appearance in $c and $v statements", + " in the database)", + "

", NULL), "", "\""); + } + /* 13-Oct-2006 nm todo - still appears - where is it? */ + if (!g_briefHtmlFlag) print2("

\n"); + print2("\n"); + break; + case -1: + print2("SUMMARY=\"List of theorems\">\n"); + break; + case 0: + print2("SUMMARY=\"List of syntax, axioms and definitions\">\n"); + break; + } + switch (s) { + case -2: + print2("\n"); + m = 0; /* Statement number map */ + let(&str3, ""); /* For storing ASCII token list in s=-2 mode */ + let(&bgcolor, MINT_BACKGROUND_COLOR); + for (i = 1; i <= g_statements; i++) { + if (s != -2 && (i == g_extHtmlStmt || i == g_mathboxStmt)) { + /* Print a row that identifies the start of the extended + database (e.g. Hilbert Space Explorer) or the user + sandboxes */ + if (i == g_extHtmlStmt) { + let(&bgcolor, PURPLISH_BIBLIO_COLOR); + } else { + let(&bgcolor, SANDBOX_COLOR); + } + printLongLine(cat("", NULL), "", "\""); + } + + if (g_Statement[i].type == (char)p_ || + g_Statement[i].type == (char)a_ ) m++; + if ((s == -1 && g_Statement[i].type != (char)p_) + || (s == 0 && g_Statement[i].type != (char)a_) + || (s == -2 && g_Statement[i].type != (char)c_ + && g_Statement[i].type != (char)v_) + ) continue; + switch (s) { + case -2: + /* Print symbol to ASCII table entry */ + /* It's a $c or $v statement, so each token generates a + table row */ + for (j = 0; j < g_Statement[i].mathStringLen; j++) { + let(&str1, g_MathToken[(g_Statement[i].mathString)[j]].tokenName); + /* Output each token only once in case of multiple decl. */ + if (!instr(1, str3, cat(" ", str1, " ", NULL))) { + let(&str3, cat(str3, " ", str1, " ", NULL)); + let(&str2, ""); + str2 = stsFlag ? + stsToken((g_Statement[i].mathString)[j], i) : + tokenToTex(g_MathToken[(g_Statement[i].mathString)[j] + ].tokenName, i/*stmt# for error msgs*/); + /* Skip any tokens (such as |- in QL Explorer) that may be suppressed */ + if (!str2[0]) continue; + /* Convert special characters to HTML entities */ + for (k = 0; k < (signed)(strlen(str1)); k++) { + if (str1[k] == '&') { + let(&str1, cat(left(str1, k), "&", + right(str1, k + 2), NULL)); + k = k + 4; + } + if (str1[k] == '<') { + let(&str1, cat(left(str1, k), "<", + right(str1, k + 2), NULL)); + k = k + 3; + } + if (str1[k] == '>') { + let(&str1, cat(left(str1, k), ">", + right(str1, k + 2), NULL)); + k = k + 3; + } + } /* next k */ + printLongLine(cat("", NULL), "", "\""); + } + } /* next j */ + /* Close out the string now to prevent memory overflow */ + fprintf(g_texFilePtr, "%s", g_printString); + let(&g_printString, ""); + break; + case -1: /* Falls through to next case */ + case 0: + let(&str1, ""); + if (s == 0 || g_briefHtmlFlag) { + let(&str1, ""); + /* Get HTML hypotheses => assertion */ + str1 = getTexOrHtmlHypAndAssertion(i); + let(&str1, cat(str1, "", NULL)); + } + + if (g_briefHtmlFlag) { + /* Get page number in mmtheorems*.html of WRITE THEOREMS */ + k = ((g_Statement[i].pinkNumber - 1) / + THEOREMS_PER_PAGE) + 1; /* Page # */ + let(&str2, cat("", NULL)); + printLongLine(str1, "", "\""); + } + /* Close out the string now to prevent overflow */ + fprintf(g_texFilePtr, "%s", g_printString); + let(&g_printString, ""); + break; + } /* end switch */ + } /* next i (statement number) */ + g_outputToString = 0; /* closing will write out the string */ + let(&bgcolor, ""); /* Deallocate (to improve fragmentation) */ + + } else { /* s > 0 */ + + if (printTime == 1) { + getRunTime(&timeIncr); /* This call just resets the time */ + } + + /*** Output the html statement body ***/ + typeStatement(g_showStatement, + 0 /*briefFlag*/, + 0 /*commentOnlyFlag*/, + 1 /*texFlag*/, /* means latex or html */ + 1 /*g_htmlFlag*/); + + if (printTime == 1) { + getRunTime(&timeIncr); + print2("SHOW STATEMENT run time = %6.2f sec for \"%s\"\n", + timeIncr, + g_texFileName); + } + + } /* if s <= 0 */ + + ABORT_S: + /*** Close the html file ***/ + printTexTrailer(1 /*texHeaderFlag*/); + if (stsFlag && strlen(postProcess) != 0) pclose(g_texFilePtr); + else fclose(g_texFilePtr); + g_texFileOpenFlag = 0; + let(&g_texFileName,""); + + } /* next s */ + + if (!q) { + /* No matching statement was found */ + printLongLine(cat("?There is no statement whose label matches \"", + g_fullArg[2], "\". ", + "Use SHOW LABELS for a list of valid labels.", NULL), "", " "); + continue; + } + + /* Complete the command processing to bypass normal SHOW STATEMENT + (non-html) below. */ + htmlDone: + continue; + } /* if (cmdMatches("SHOW STATEMENT") && switchPos("/ HTML")...) */ + + + /* Write mnemosyne.txt */ + if (cmdMatches("SHOW STATEMENT") && switchPos("/ MNEMONICS")) { + g_htmlFlag = 1; /* Use HTML, not TeX section */ + g_altHtmlFlag = 1; /* Use Unicode, not GIF */ + /* readTexDefs() rereads based on changes to g_htmlFlag, g_altHtmlFlag */ + if (2/*error*/ == readTexDefs(0 /* 1 = check errors only */, + 1 /* 1 = GIF file existence check */ )) { + continue; /* An error occurred */ + } + + let(&g_texFileName, "mnemosyne.txt"); + g_texFilePtr = fSafeOpen(g_texFileName, "w", 0/*noVersioningFlag*/); + if (!g_texFilePtr) { + /* Couldn't open file; error message was provided by fSafeOpen */ + continue; + } + print2("Creating Mnemosyne file \"%s\"...\n", g_texFileName); + + for (s = 1; s <= g_statements; s++) { + g_showStatement = s; + + if (!g_Statement[s].labelName[0]) continue; /* No label */ + if (!matchesList(g_Statement[s].labelName, g_fullArg[2], '*', '?')) + continue; + if (g_Statement[s].type != (char)a_ + && g_Statement[s].type != (char)p_) + continue; + + let(&str1, cat("
", + " ", g_Statement[g_showStatement].labelName, + "", "
", NULL)); + fprintf(g_texFilePtr, "%s", str1); + + let(&str1, cat("
\n"); + break; + case -1: + print2( + "
List of Theorems
\n"); + break; + case 0: + printLongLine(cat( + /* (in case |- suppressed) */ + "
List of Syntax, ", + "Axioms (ax-) and", + " Definitions (df-)", "
", + NULL), "", "\""); + break; + } + switch (s) { + case -2: + print2("SymbolASCII\n"); + break; + case -1: + print2( + "RefDescription\n"); + break; + case 0: + printLongLine(cat( + "Ref", + "Expression (see link for any distinct variable requirements)", + NULL), "", "\""); + break; + } + print2("
", + "The list of syntax, axioms (ax-) and definitions (df-) for", + " the ", + (i == g_extHtmlStmt) ? + g_extHtmlTitle : + "User Mathboxes", + " starts here
", + (g_altHtmlFlag ? cat("", NULL) : ""), + str2, + (g_altHtmlFlag ? "" : ""), + " ", /* This will prevent a + -4px shifted image from overlapping the + lower border of the table cell */ + "", + str1, + "
", + /*"",*/ + "", + str((double)(g_Statement[i].pinkNumber)), " ", + "", g_Statement[i].labelName, + "", NULL)); + let(&str1, cat(str2, " ", str1, NULL)); + } else { + /* Get little pink (or rainbow-colored) number */ + let(&str4, ""); + str4 = pinkHTML(i); + let(&str2, cat("
", g_Statement[i].labelName, + "", str4, NULL)); + let(&str1, cat(str2, "", str1, NULL)); + } + + print2("\n"); /* New line for HTML source readability */ + printLongLine(str1, "", "\""); + + if (s == 0 || g_briefHtmlFlag) { + /* Set s == 0 here for Web site version, + s == s for symbol version of theorem list */ + /* The below has been replaced by + getTexOrHtmlHypAndAssertion(i) above. */ + /*printTexLongMath(g_Statement[i].mathString, "", "", 0, 0);*/ + /*g_outputToString = 1;*/ /* Is reset by printTexLongMath */ + } else { + /* Theorems are listed w/ description; otherwise file is too + big for convenience */ + let(&str1, ""); + str1 = getDescription(i); + if (strlen(str1) > 29) + let(&str1, cat(left(str1, 26), "...", NULL)); + let(&str1, cat(str1, "
",NULL)); + fprintf(g_texFilePtr, "%s", str1); + + j = nmbrLen(g_Statement[g_showStatement].reqHypList); + for (i = 0; i < j; i++) { + k = g_Statement[g_showStatement].reqHypList[i]; + if (g_Statement[k].type != (char)e_ + && !(subType == SYNTAX + && g_Statement[k].type == (char)f_)) + continue; + + let(&str1, cat("", str1); + } + + + let(&str1, "
", + g_Statement[k].labelName, "", + NULL)); + fprintf(g_texFilePtr, "%s", str1); + + /* Print hypothesis */ + let(&str1, ""); /* Free any previous allocation to str1 */ + /* getTexLongMath does not return a temporary allocation; must + assign str1 directly, not with let(). It will be deallocated + with the next let(&str1,...). */ + str1 = getTexLongMath(g_Statement[k].mathString, + k/*stmt# for err msgs*/); + fprintf(g_texFilePtr, "%s
"); + fprintf(g_texFilePtr, "%s", str1); + + let(&str1, "
What is the conclusion?"); + fprintf(g_texFilePtr, "%s\n", str1); + + let(&str1, ""); + fprintf(g_texFilePtr, "%s", str1); + + let(&str1, ""); /* Free any previous allocation to str1 */ + /* getTexLongMath does not return a temporary allocation */ + str1 = getTexLongMath(g_Statement[s].mathString, s); + fprintf(g_texFilePtr, "%s", str1); + + let(&str1, ""); + fprintf(g_texFilePtr, "%s\n",str1); + } /* for(s=1;s j-3) { + print2("At least %ld bytes of memory are free.\n",j); + } else { + print2("%ld bytes of memory are free.\n",i); + } + continue; + } + + if (cmdMatches("SHOW ELAPSED_TIME")) { + timeTotal = getRunTime(&timeIncr); + print2( + "Time since last SHOW ELAPSED_TIME command = %6.2f s; total = %6.2f s\n", + timeIncr, timeTotal); + continue; + } /* if (cmdMatches("SHOW ELAPSED_TIME")) */ + + + if (cmdMatches("SHOW TRACE_BACK")) { + essentialFlag = 0; + axiomFlag = 0; + endIndent = 0; + i = switchPos("/ ESSENTIAL"); + if (i) essentialFlag = 1; /* Limit trace to essential steps only */ + i = switchPos("/ ALL"); + if (i) essentialFlag = 0; + i = switchPos("/ AXIOMS"); + if (i) axiomFlag = 1; /* Limit trace printout to axioms */ + i = switchPos("/ DEPTH"); /* Limit depth of printout */ + if (i) endIndent = (long)val(g_fullArg[i + 1]); + + i = switchPos("/ COUNT_STEPS"); + countStepsFlag = (i != 0 ? 1 : 0); + i = switchPos("/ TREE"); + treeFlag = (i != 0 ? 1 : 0); + i = switchPos("/ MATCH"); + matchFlag = (i != 0 ? 1 : 0); + if (matchFlag) { + let(&matchList, g_fullArg[i + 1]); + } else { + let(&matchList, ""); + } + i = switchPos("/ TO"); + if (i != 0) { + let(&traceToList, g_fullArg[i + 1]); + } else { + let(&traceToList, ""); + } + if (treeFlag) { + if (axiomFlag) { + print2( + "(Note: The AXIOMS switch is ignored in TREE mode.)\n"); + } + if (countStepsFlag) { + print2( + "(Note: The COUNT_STEPS switch is ignored in TREE mode.)\n"); + } + if (matchFlag) { + print2( + "(Note: The MATCH list is ignored in TREE mode.)\n"); + } + } else { + if (endIndent != 0) { + print2( + "(Note: The DEPTH is ignored if the TREE switch is not used.)\n"); + } + if (countStepsFlag) { + if (matchFlag) { + print2( + "(Note: The MATCH list is ignored in COUNT_STEPS mode.)\n"); + } + } + } + + g_showStatement = 0; + for (i = 1; i <= g_statements; i++) { + if (g_Statement[i].type != (char)p_) + continue; /* Not a $p statement; skip it */ + /* Wildcard matching */ + if (!matchesList(g_Statement[i].labelName, g_fullArg[2], '*', '?')) + continue; + + g_showStatement = i; + + if (treeFlag) { + traceProofTree(g_showStatement, essentialFlag, endIndent); + } else { + if (countStepsFlag) { + countSteps(g_showStatement, essentialFlag); + } else { + traceProof(g_showStatement, + essentialFlag, + axiomFlag, + matchList, + traceToList, + 0 /* testOnlyFlag */); + } + } + + } /* next i */ + if (g_showStatement == 0) { + printLongLine(cat("?There are no $p labels matching \"", + g_fullArg[2], "\". ", + "See HELP SHOW TRACE_BACK for matching rules.", NULL), "", " "); + } + + let(&matchList, ""); /* Deallocate memory */ + let(&traceToList, ""); /* Deallocate memory */ + continue; + } /* if (cmdMatches("SHOW TRACE_BACK")) */ + + + if (cmdMatches("SHOW USAGE")) { + + if (switchPos("/ ALL")) { + m = 1; /* Always include $e, $f statements */ + } else { + m = 0; /* If wildcards are used, show $a, $p only */ + } + + g_showStatement = 0; + for (i = 1; i <= g_statements; i++) { + if (!g_Statement[i].labelName[0]) continue; /* No label */ + if (!m && g_Statement[i].type != (char)p_ && + g_Statement[i].type != (char)a_ + /* A wildcard-free user-specified statement is always matched even + if it's a $e, i.e. it overrides omission of / ALL */ + && (instr(1, g_fullArg[2], "*") + || instr(1, g_fullArg[2], "?"))) + continue; /* No /ALL switch and wildcard and not $p, $a */ + /* Wildcard matching */ + if (!matchesList(g_Statement[i].labelName, g_fullArg[2], '*', '?')) + continue; + + g_showStatement = i; + recursiveFlag = 0; + j = switchPos("/ RECURSIVE"); + if (j) recursiveFlag = 1; /* Recursive (indirect) usage */ + j = switchPos("/ DIRECT"); + if (j) recursiveFlag = 0; /* Direct references only */ + + let(&str1, ""); + str1 = traceUsage(g_showStatement, + recursiveFlag, + 0 /* cutoffStmt */); + + /* str1[0] will be 'Y' or 'N' depending on whether there are any + statements. str1[i] will be 'Y' or 'N' depending on whether + g_Statement[i] uses g_showStatement. */ + /* Count the number of statements k = # of 'Y' */ + k = 0; + if (str1[0] == 'Y') { + /* There is at least one statement using g_showStatement */ + for (j = g_showStatement + 1; j <= g_statements; j++) { + if (str1[j] == 'Y') { + k++; + } else { + if (str1[j] != 'N') bug(1124); /* Must be 'Y' or 'N' */ + } + } + } else { + if (str1[0] != 'N') bug(1125); /* Must be 'Y' or 'N' */ + } + + if (k == 0) { + printLongLine(cat("Statement \"", + g_Statement[g_showStatement].labelName, + "\" is not referenced in the proof of any statement.", NULL), + "", " "); + } else { + if (recursiveFlag) { + let(&str2, "\" directly or indirectly affects"); + } else { + let(&str2, "\" is directly referenced in"); + } + if (k == 1) { + printLongLine(cat("Statement \"", + g_Statement[g_showStatement].labelName, + str2, " the proof of ", + str((double)k), " statement:", NULL), "", " "); + } else { + printLongLine(cat("Statement \"", + g_Statement[g_showStatement].labelName, + str2, " the proofs of ", + str((double)k), " statements:", NULL), "", " "); + } + } + + if (k != 0) { + let(&str3, " "); /* Line buffer */ + for (j = g_showStatement + 1; j <= g_statements; j++) { + if (str1[j] == 'Y') { + /* Since the output list could be huge, don't build giant + string (very slow) but output it line by line */ + if ((long)strlen(str3) + 1 + + (long)strlen(g_Statement[j].labelName) > g_screenWidth) { + /* Output and reset the line buffer */ + print2("%s\n", str3); + let(&str3, " "); + } + let(&str3, cat(str3, " ", g_Statement[j].labelName, NULL)); + } + } + if (strlen(str3) > 1) print2("%s\n", str3); + let(&str3, ""); + } else { + print2(" (None)\n"); + } /* if (k != 0) */ + } /* next i (statement matching wildcard list) */ + + if (g_showStatement == 0) { + printLongLine(cat("?There are no labels matching \"", + g_fullArg[2], "\". ", + "See HELP SHOW USAGE for matching rules.", NULL), "", " "); + } + continue; + } /* if cmdMatches("SHOW USAGE") */ + + + if (cmdMatches("SHOW PROOF") + || cmdMatches("SHOW NEW_PROOF") + || cmdMatches("SAVE PROOF") + || cmdMatches("SAVE NEW_PROOF") + || cmdMatches("MIDI")) { + if (switchPos("/ HTML")) { + print2("?HTML qualifier is obsolete - use SHOW STATEMENT * / HTML\n"); + continue; + } + + if (cmdMatches("SAVE NEW_PROOF") + && getMarkupFlag(g_proveStatement, PROOF_DISCOURAGED)) { + if (switchPos("/ OVERRIDE") == 0 && g_globalDiscouragement == 1) { + /* print2("\n"); */ /* Enable for more emphasis */ + print2( +">>> ?Error: Attempt to overwrite a proof whose modification is discouraged.\n"); + print2( + ">>> Use SAVE NEW_PROOF ... / OVERRIDE if you really want to do this.\n"); + /* print2("\n"); */ /* Enable for more emphasis */ + continue; + } else { + /* print2("\n"); */ /* Enable for more emphasis */ + print2( +">>> ?Warning: You are overwriting a proof whose modification is discouraged.\n"); + /* print2("\n"); */ /* Enable for more emphasis */ + } + } + + if (cmdMatches("SHOW PROOF") || cmdMatches("SAVE PROOF")) { + pipFlag = 0; + } else { + pipFlag = 1; /* Proof-in-progress (NEW_PROOF) flag */ + } + if (cmdMatches("SHOW")) { + saveFlag = 0; + } else { + saveFlag = 1; /* The command is SAVE PROOF */ + } + + printTime = 0; + if (switchPos("/ TIME") != 0) { /* / TIME legal in SAVE mode only */ + printTime = 1; + } + + i = switchPos("/ OLD_COMPRESSION"); + if (i) { + if (!switchPos("/ COMPRESSED")) { + print2("?/ OLD_COMPRESSION must be accompanied by / COMPRESSED.\n"); + continue; + } + } + + i = switchPos("/ FAST"); + if (i) { + if (!switchPos("/ COMPRESSED") && !switchPos("/ PACKED")) { + print2("?/ FAST must be accompanied by / COMPRESSED or / PACKED.\n"); + continue; + } + fastFlag = 1; + } else { + fastFlag = 0; + } + + if (switchPos("/ EXPLICIT")) { + if (switchPos("/ COMPRESSED")) { + print2("?/ COMPRESSED and / EXPLICIT may not be used together.\n"); + continue; + } else if (switchPos("/ NORMAL")) { + print2("?/ NORMAL and / EXPLICIT may not be used together.\n"); + continue; + } + } + if (switchPos("/ NORMAL")) { + if (switchPos("/ COMPRESSED")) { + print2("?/ NORMAL and / COMPRESSED may not be used together.\n"); + continue; + } + } + + + /* Establish defaults for omitted qualifiers */ + startStep = 0; + endStep = 0; + endIndent = 0; + essentialFlag = 1; + renumberFlag = 0; + unknownFlag = 0; + notUnifiedFlag = 0; + reverseFlag = 0; + detailStep = 0; + noIndentFlag = 0; + splitColumn = DEFAULT_COLUMN; + skipRepeatedSteps = 0; + texFlag = 0; + + i = switchPos("/ FROM_STEP"); + if (i) startStep = (long)val(g_fullArg[i + 1]); + i = switchPos("/ TO_STEP"); + if (i) endStep = (long)val(g_fullArg[i + 1]); + i = switchPos("/ DEPTH"); + if (i) endIndent = (long)val(g_fullArg[i + 1]); + /* ESSENTIAL is retained for downwards compatibility, but is + now the default, so we ignore it. */ + /* + i = switchPos("/ ESSENTIAL"); + if (i) essentialFlag = 1; + */ + i = switchPos("/ ALL"); + if (i) essentialFlag = 0; + if (i && switchPos("/ ESSENTIAL")) { + print2("?You may not specify both / ESSENTIAL and / ALL.\n"); + continue; + } + i = switchPos("/ RENUMBER"); + if (i) renumberFlag = 1; + i = switchPos("/ UNKNOWN"); + if (i) unknownFlag = 1; + i = switchPos("/ NOT_UNIFIED"); /* pip mode only */ + if (i) notUnifiedFlag = 1; + i = switchPos("/ REVERSE"); + if (i) reverseFlag = 1; + i = switchPos("/ LEMMON"); + if (i) noIndentFlag = 1; + i = switchPos("/ START_COLUMN"); + if (i) splitColumn = (long)val(g_fullArg[i + 1]); + i = switchPos("/ NO_REPEATED_STEPS"); + if (i) skipRepeatedSteps = 1; + + /* If NO_REPEATED_STEPS is specified, indentation (tree) mode will be + misleading because a hypothesis assignment will be suppressed if the + same assignment occurred earlier, i.e. it is no longer a "tree". */ + if (skipRepeatedSteps == 1 && noIndentFlag == 0) { + print2("?You must specify / LEMMON with / NO_REPEATED_STEPS\n"); + continue; + } + + i = switchPos("/ TEX") || switchPos("/ HTML") + || switchPos("/ OLD_TEX"); + if (i) texFlag = 1; + + g_oldTexFlag = 0; + if (switchPos("/ OLD_TEX")) g_oldTexFlag = 1; + + if (cmdMatches("MIDI")) { + g_midiFlag = 1; + pipFlag = 0; + saveFlag = 0; + let(&labelMatch, g_fullArg[1]); + i = switchPos("/ PARAMETER"); /* MIDI only */ + if (i) { + let(&g_midiParam, g_fullArg[i + 1]); + } else { + let(&g_midiParam, ""); + } + } else { + g_midiFlag = 0; + if (!pipFlag) let(&labelMatch, g_fullArg[2]); + } + + + if (texFlag) { + if (!g_texFileOpenFlag) { + print2( + "?You have not opened a %s file. Use the OPEN %s command first.\n", + g_htmlFlag ? "HTML" : "LaTeX", + g_htmlFlag ? "HTML" : "TEX"); + continue; + } + } + + i = switchPos("/ DETAILED_STEP"); /* non-pip mode only */ + if (i) { + detailStep = (long)val(g_fullArg[i + 1]); + if (!detailStep) detailStep = -1; /* To use as flag; error message + will occur in showDetailStep() */ + } + +/*??? Need better warnings for switch combinations that don't make sense */ + + /* Print a single message for "/compressed/fast" */ + if (switchPos("/ COMPRESSED") && fastFlag + && !strcmp("*", labelMatch)) { + print2( + "Reformatting and saving (but not recompressing) all proofs...\n"); + } + + + q = 0; /* Flag that at least one matching statement was found */ + for (stmt = 1; stmt <= g_statements; stmt++) { + /* If pipFlag (NEW_PROOF), we will iterate exactly once. This + loop of course will be entered because there is a least one + statement, and at the end of the s loop we break out of it. */ + /* If !pipFlag, get the next statement: */ + if (!pipFlag) { + if (g_Statement[stmt].type != (char)p_) continue; /* Not $p */ + if (!matchesList(g_Statement[stmt].labelName, labelMatch, '*', '?')) + continue; + g_showStatement = stmt; + } + + q = 1; /* Flag that at least one matching statement was found */ + + if (detailStep) { + /* Show the details of just one step */ + showDetailStep(g_showStatement, detailStep); + continue; + } + + if (switchPos("/ STATEMENT_SUMMARY")) { /* non-pip mode only */ + /* Just summarize the statements used in the proof */ + proofStmtSumm(g_showStatement, essentialFlag, texFlag); + continue; + } + + if (switchPos("/ SIZE")) { /* non-pip mode only */ + /* Just print the size of the stored proof and continue */ + let(&str1, space(g_Statement[g_showStatement].proofSectionLen)); + memcpy(str1, g_Statement[g_showStatement].proofSectionPtr, + (size_t)(g_Statement[g_showStatement].proofSectionLen)); + n = instr(1, str1, "$."); + if (n == 0) { + /* The original source truncates the proof before $. */ + n = g_Statement[g_showStatement].proofSectionLen; + } else { + /* If a proof is saved, it includes the $. (Should we + revisit or document better how/why this is done?) */ + n = n - 1; + } + print2("The proof source for \"%s\" has %ld characters.\n", + g_Statement[g_showStatement].labelName, n); + continue; + } + + if (switchPos("/ PACKED") || switchPos("/ NORMAL") || + switchPos("/ COMPRESSED") || switchPos("/ EXPLICIT") || saveFlag) { + /*??? Add error msg if other switches were specified. (Ignore them.)*/ + + if (saveFlag) { + if (printTime == 1) { + getRunTime(&timeIncr); /* This call just resets the time */ + } + } + + if (!pipFlag) { + outStatement = g_showStatement; + } else { + outStatement = g_proveStatement; + } + + explicitTargets = (switchPos("/ EXPLICIT") != 0) ? 1 : 0; + + /* Get the amount to indent the proof by */ + indentation = 2 + getSourceIndentation(outStatement); + + if (!pipFlag) { + parseProof(g_showStatement); /* Prints message if severe error */ + if (g_WrkProof.errorSeverity > 1) { + /* Prevent bugtrap in nmbrSquishProof -> nmbrGetSubProofLen + if proof corrupted */ + print2( + "?The proof has a severe error and cannot be displayed or saved.\n"); + continue; + } + if (fastFlag) { + /* Use the proof as is */ + nmbrLet(&nmbrSaveProof, g_WrkProof.proofString); + } else { + /* Make sure the proof is uncompressed */ + nmbrLet(&nmbrSaveProof, nmbrUnsquishProof(g_WrkProof.proofString)); + } + } else { + nmbrLet(&nmbrSaveProof, g_ProofInProgress.proof); + } + if (switchPos("/ PACKED") || switchPos("/ COMPRESSED")) { + if (!fastFlag) { + nmbrLet(&nmbrSaveProof, nmbrSquishProof(nmbrSaveProof)); + } + } + + if (switchPos("/ COMPRESSED")) { + let(&str1, compressProof(nmbrSaveProof, + outStatement, /* g_showStatement or g_proveStatement based on pipFlag */ + (switchPos("/ OLD_COMPRESSION")) ? 1 : 0)); + } else { + let(&str1, nmbrCvtRToVString(nmbrSaveProof, + explicitTargets, + outStatement /*statemNum, used only if explicitTargets*/)); + } + + + if (saveFlag) { + /* ??? This is a problem when mixing html and save proof */ + if (g_printString[0]) bug(1114); + let(&g_printString, ""); + + /* Set flag for print2() to put output in g_printString instead + of displaying it on the screen */ + g_outputToString = 1; + + } else { + if (!print2("Proof of \"%s\":\n", g_Statement[outStatement].labelName)) + break; /* Break for speedup if user quit */ + print2( +"---------Clip out the proof below this line to put it in the source file:\n"); + } + if (switchPos("/ COMPRESSED")) { + printLongLine(cat(space(indentation), str1, " $.", NULL), + space(indentation), "& "); /* "&" is special flag to break + compressed part of proof anywhere */ + } else { + printLongLine(cat(space(indentation), str1," $.", NULL), + space(indentation), " "); + } + + l = (long)(strlen(str1)); /* Save length for printout below */ + + /* SOREAR Only generate date if the proof looks complete. + This is not intended as a grading mechanism, just trying + to avoid premature output */ + if (!nmbrElementIn(1, nmbrSaveProof, -(long)'?')) { + /* Add a "(Contributed by...)" date if it isn't there */ + let(&str2, ""); + str2 = getContrib(outStatement, CONTRIBUTOR); + if (str2[0] == 0) { /* The is no contributor, so add one */ + + /* See if there is a date below the proof (for converting old + .mm files). Someday this will be obsolete, with str3 and + str4 always returned as "". */ + getProofDate(outStatement, &str3, &str4); + /* If there are two dates below the proof, the first on is + the revision date and the second the "Contributed by" date. */ + if (str4[0] != 0) { /* There are 2 dates below the proof */ + let(&str5, str3); /* 1st date is Revised by... */ + let(&str3, str4); /* 2nd date is Contributed by... */ + } else { + let(&str5, ""); + } + /* If there is no date below proof, use today's date */ + if (str3[0] == 0) let(&str3, date()); + let(&str4, cat("\n", space(indentation + 1), + "(Contributed by ", g_contributorName, + ", ", str3, ".) ", NULL)); + /* If there is a 2nd date below proof, add a "(Revised by..." + tag */ + if (str5[0] != 0) { + /* Use the DEFAULT_CONTRIBUTOR ?who? because we don't + know the reviser name (using the contributor name may + be incorrect). Also, this will trigger a warning in + VERIFY MARKUP since it may be a proof shortener rather than + a reviser. */ + let(&str4, cat(str4, "\n", space(indentation + 1), + "(Revised by ", DEFAULT_CONTRIBUTOR, + ", ", str5, ".) ", NULL)); + } + + let(&str3, space(g_Statement[outStatement].labelSectionLen)); + /* str3 will have the statement's label section w/ comment */ + memcpy(str3, g_Statement[outStatement].labelSectionPtr, + (size_t)(g_Statement[outStatement].labelSectionLen)); + i = rinstr(str3, "$)"); /* The last "$)" occurrence */ + if (i != 0 /* A description comment exists */ + && saveFlag) { /* and we are saving the proof */ + /* This isn't a perfect wrapping but we assume + 'write source .../rewrap' will be done eventually. */ + /* str3 will have the updated comment */ + let(&str3, cat(left(str3, i - 1), str4, right(str3, i), NULL)); + if (g_Statement[outStatement].labelSectionChanged == 1) { + /* Deallocate old comment if not original source */ + let(&str4, ""); /* Deallocate any previous str4 content */ + str4 = g_Statement[outStatement].labelSectionPtr; + let(&str4, ""); /* Deallocate the old content */ + } + /* Set flag that this is not the original source */ + g_Statement[outStatement].labelSectionChanged = 1; + g_Statement[outStatement].labelSectionLen = (long)strlen(str3); + /* We do a direct assignment instead of let(&...) because + labelSectionPtr may point to the middle of the giant input + file buffer, which we don't want to deallocate */ + g_Statement[outStatement].labelSectionPtr = str3; + /* Reset str3 without deallocating with let(), since it + was assigned to labelSectionPtr */ + str3 = ""; + /* Reset the cache for this statement in getContrib() */ + str3 = getContrib(outStatement, GC_RESET_STMT); + } /* if i != 0 */ + } /* if str2[0] == 0 */ + } /* if (!nmbrElementIn(1, nmbrSaveProof, -(long)'?')) */ + + if (saveFlag) { + g_sourceChanged = 1; + g_proofChanged = 0; + if (processUndoStack(NULL, PUS_GET_STATUS, "", 0)) { + /* The UNDO stack may not be empty */ + proofSavedFlag = 1; /* UNDO stack empty no longer reliably + indicates that proof hasn't changed */ + } + + /* Add an initial \n which will go after the "$=" and the + beginning of the proof */ + let(&g_printString, cat("\n", g_printString, NULL)); + if (g_Statement[outStatement].proofSectionChanged == 1) { + /* Deallocate old proof if not original source */ + let(&str1, ""); /* Deallocate any previous str1 content */ + str1 = g_Statement[outStatement].proofSectionPtr; + let(&str1, ""); /* Deallocate the proof section */ + } + /* Set flag that this is not the original source */ + g_Statement[outStatement].proofSectionChanged = 1; + if (strcmp(" $.\n", + right(g_printString, (long)strlen(g_printString) - 3))) { + bug(1128); + } + /* Note that g_printString ends with "$.\n", but those 3 characters + should not be in the proofSection. (The "$." keyword is + added between proofSection and next labelSection when the + output is written by writeOutput.) Thus we subtract 3 + from the length. But there is no need to truncate the + string; later deallocation will take care of the whole + string. */ + g_Statement[outStatement].proofSectionLen + = (long)strlen(g_printString) - 3; + /* We do a direct assignment instead of let(&...) because + proofSectionPtr may point to the middle of the giant input + file string, which we don't want to deallocate */ + g_Statement[outStatement].proofSectionPtr = g_printString; + /* Reset g_printString without deallocating with let(), since it + was assigned to proofSectionPtr */ + g_printString = ""; + g_outputToString = 0; + + + if (!pipFlag) { + if (!(fastFlag && !strcmp("*", labelMatch))) { + printLongLine( + cat("The proof of \"", g_Statement[outStatement].labelName, + "\" has been reformatted and saved internally.", + NULL), "", " "); + } + } else { + printLongLine(cat("The new proof of \"", g_Statement[outStatement].labelName, + "\" has been saved internally.", + NULL), "", " "); + } + + if (printTime == 1) { + getRunTime(&timeIncr); + print2("SAVE PROOF run time = %6.2f sec for \"%s\"\n", timeIncr, + g_Statement[outStatement].labelName); + } + + } else { + /*print2("\n");*/ /* Add a blank line to make clipping easier */ + print2(cat( + "---------The proof of \"", g_Statement[outStatement].labelName, + /* "\" to clip out ends above this line.\n",NULL)); */ + "\" (", str((double)l), " bytes) ends above this line.\n", NULL)); + } /* End if saveFlag */ + nmbrLet(&nmbrSaveProof, NULL_NMBRSTRING); + if (pipFlag) break; /* Only one iteration for NEW_PROOF stuff */ + continue; /* to next s iteration */ + } /* end if (switchPos("/ PACKED") || switchPos("/ NORMAL") || + switchPos("/ COMPRESSED") || switchPos("/ EXPLICIT") || saveFlag) */ + + if (saveFlag) bug(1112); /* Shouldn't get here */ + + if (!pipFlag) { + outStatement = g_showStatement; + } else { + outStatement = g_proveStatement; + } + if (texFlag) { + g_outputToString = 1; /* Flag for print2 to add to g_printString */ + if (!g_htmlFlag) { + if (!g_oldTexFlag) { + print2("\\begin{proof}\n"); + print2("\\begin{align}\n"); + } else { + print2("\n"); + print2("\\vspace{1ex} %%1\n"); + printLongLine(cat("Proof of ", + "{\\tt ", + asciiToTt(g_Statement[outStatement].labelName), + "}:", NULL), "", " "); + print2("\n"); + print2("\n"); + } + } else { /* g_htmlFlag */ + bug(1118); + } + g_outputToString = 0; + /* printTeXLongMath clears g_printString in LaTeX + mode before starting its output, so we must put out the + g_printString ourselves here */ + fprintf(g_texFilePtr, "%s", g_printString); + let(&g_printString, ""); /* We'll clr it anyway */ + } else { /* !texFlag */ + /* Terminal output - display the statement if wildcard is used */ + if (!pipFlag) { + if (instr(1, labelMatch, "*") || instr(1, labelMatch, "?")) { + if (!print2("Proof of \"%s\":\n", g_Statement[outStatement].labelName)) + break; /* Break for speedup if user quit */ + } + } + } + + + if (texFlag) print2("Outputting proof of \"%s\"...\n", + g_Statement[outStatement].labelName); + + typeProof(outStatement, + pipFlag, + startStep, + endStep, + endIndent, + essentialFlag, + + /* In SHOW PROOF xxx /TEX, we use renumber steps mode so that + the first step is step 1. The step number is checked for + step 1 in mmwtex.c to prevent a spurious \\ (newline) at the + start of the proof. Note that + SHOW PROOF is not available in HTML mode, so texFlag will + always mean LaTeX mode here. */ + (texFlag ? 1 : renumberFlag), + + unknownFlag, + notUnifiedFlag, + reverseFlag, + + /* In SHOW PROOF xxx /TEX, we use Lemmon mode so that the + hypothesis reference list will be available. Note that + SHOW PROOF is not available in HTML mode, so texFlag will + always mean LaTeX mode here. */ + (texFlag ? 1 : noIndentFlag), + + splitColumn, + skipRepeatedSteps, + texFlag, + g_htmlFlag); + if (texFlag) { + if (!g_htmlFlag) { + if (!g_oldTexFlag) { + g_outputToString = 1; + print2("\\end{align}\n"); + print2("\\end{proof}\n"); + print2("\n"); + g_outputToString = 0; + fprintf(g_texFilePtr, "%s", g_printString); + let(&g_printString, ""); + } else { + } + } else { /* g_htmlFlag */ + g_outputToString = 1; + print2("\n"); + print2("
\n"); + /* print trailer will close out string later */ + g_outputToString = 0; + } + } + + /*E*/ if (0) { /* for debugging: */ + printLongLine(nmbrCvtRToVString(g_WrkProof.proofString, + 0, /*explicitTargets*/ + 0 /*statemNum, used only if explicitTargets*/)," "," "); + print2("\n"); + + nmbrLet(&nmbrSaveProof, nmbrSquishProof(g_WrkProof.proofString)); + printLongLine(nmbrCvtRToVString(nmbrSaveProof, + 0, /*explicitTargets*/ + 0 /*statemNum, used only if explicitTargets*/)," "," "); + print2("\n"); + + nmbrLet(&nmbrTmp, nmbrUnsquishProof(nmbrSaveProof)); + printLongLine(nmbrCvtRToVString(nmbrTmp, + 0, /*explicitTargets*/ + 0 /*statemNum, used only if explicitTargets*/)," "," "); + + nmbrLet(&nmbrTmp, nmbrGetTargetHyp(nmbrSaveProof,g_showStatement)); + printLongLine(nmbrCvtAnyToVString(nmbrTmp)," "," "); print2("\n"); + + nmbrLet(&nmbrTmp, nmbrGetEssential(nmbrSaveProof)); + printLongLine(nmbrCvtAnyToVString(nmbrTmp)," "," "); print2("\n"); + + cleanWrkProof(); /* Deallocate verifyProof storage */ + } /* end debugging */ + + if (pipFlag) break; /* Only one iteration for NEW_PROOF stuff */ + } /* Next stmt */ + if (!q) { + /* No matching statement was found */ + printLongLine(cat("?There is no $p statement whose label matches \"", + (cmdMatches("MIDI")) ? g_fullArg[1] : g_fullArg[2], + "\". ", + "Use SHOW LABELS to see list of valid labels.", NULL), "", " "); + } else { + if (saveFlag) { + print2("Remember to use WRITE SOURCE to save changes permanently.\n"); + } + if (texFlag) { + print2("The LaTeX source was written to \"%s\".\n", g_texFileName); + g_oldTexFlag = 0; + } + } + + continue; + } /* if (cmdMatches("SHOW/SAVE [NEW_]PROOF" or" MIDI") */ + + +/*E*/ /*???????? DEBUG command for debugging only */ + if (cmdMatches("DBG")) { + print2("DEBUGGING MODE IS FOR DEVELOPER'S USE ONLY!\n"); + print2("Argument: %s\n", g_fullArg[1]); + nmbrLet(&nmbrTmp, parseMathTokens(g_fullArg[1], g_proveStatement)); + for (j = 0; j < 3; j++) { + print2("Trying depth %ld\n", j); + nmbrTmpPtr = proveFloating(nmbrTmp, g_proveStatement, j, 0, 0, + 1/*overrideFlag*/, 1/*mathboxFlag*/); + if (nmbrLen(nmbrTmpPtr)) break; + } + + print2("Result: %s\n", nmbrCvtRToVString(nmbrTmpPtr, + 0, /*explicitTargets*/ + 0 /*statemNum, used only if explicitTargets*/)); + nmbrLet(&nmbrTmpPtr, NULL_NMBRSTRING); + + continue; + } +/*E*/ /*???????? DEBUG command for debugging only */ + + if (cmdMatches("PROVE")) { + + /* Get the unique statement matching the g_fullArg[1] pattern */ + i = getStatementNum(g_fullArg[1], + 1/*startStmt*/, + g_statements + 1 /*maxStmt*/, + 0/*aAllowed*/, + 1/*pAllowed*/, + 0/*eAllowed*/, + 0/*fAllowed*/, + 0/*efOnlyForMaxStmt*/, + 1/*uniqueFlag*/); + if (i == -1) { + continue; /* Error msg was provided if not unique */ + } + g_proveStatement = i; + + + /* 1 means to override usage locks */ + overrideFlag = ( (switchPos("/ OVERRIDE")) ? 1 : 0) + || g_globalDiscouragement == 0; + if (getMarkupFlag(g_proveStatement, PROOF_DISCOURAGED)) { + if (overrideFlag == 0) { + /* print2("\n"); */ /* Enable for more emphasis */ + print2(">>> ?Error: " + "Modification of this statement's proof is discouraged.\n"); + print2(">>> You must use PROVE ... / OVERRIDE to work on it.\n"); + /* print2("\n"); */ /* Enable for more emphasis */ + continue; + } + } + + print2("Entering the Proof Assistant. " + "HELP PROOF_ASSISTANT for help, EXIT to exit.\n"); + + g_PFASmode = 1; /* Set mode for commands here and in mmcmdl.c */ + /* Note: Proof Assistant mode can equivalently be determined by: + nmbrLen(g_ProofInProgress.proof) != 0 */ + + parseProof(g_proveStatement); + verifyProof(g_proveStatement); /* Necessary to set RPN stack ptrs + before calling cleanWrkProof() */ + if (g_WrkProof.errorSeverity > 1) { + print2( + "The starting proof has a severe error. It will not be used.\n"); + nmbrLet(&nmbrSaveProof, nmbrAddElement(NULL_NMBRSTRING, -(long)'?')); + } else { + nmbrLet(&nmbrSaveProof, g_WrkProof.proofString); + } + cleanWrkProof(); /* Deallocate verifyProof storage */ + + /* Initialize the structure needed for the Proof Assistant */ + initProofStruct(&g_ProofInProgress, nmbrSaveProof, g_proveStatement); + + /* Show the user the statement to be proved */ + print2("You will be working on statement (from \"SHOW STATEMENT %s\"):\n", + g_Statement[g_proveStatement].labelName); + typeStatement(g_proveStatement /*g_showStatement*/, + 1 /*briefFlag*/, + 0 /*commentOnlyFlag*/, + 0 /*texFlag*/, + 0 /*g_htmlFlag*/); + + if (!nmbrElementIn(1, g_ProofInProgress.proof, -(long)'?')) { + print2( + "Note: The proof you are starting with is already complete.\n"); + } else { + + print2( + "Unknown step summary (from \"SHOW NEW_PROOF / UNKNOWN\"):\n"); + /* Automatically display new unknown steps + ???Future - add switch to enable/defeat this */ + typeProof(g_proveStatement, + 1 /*pipFlag*/, + 0 /*startStep*/, + 0 /*endStep*/, + 0 /*endIndent*/, + 1 /*essentialFlag*/, + 0 /*renumberFlag*/, + 1 /*unknownFlag*/, + 0 /*notUnifiedFlag*/, + 0 /*reverseFlag*/, + 0 /*noIndentFlag*/, + 0 /*splitColumn*/, + 0 /*skipRepeatedSteps*/, + 0 /*texFlag*/, + 0 /*g_htmlFlag*/); + } + + if (getMarkupFlag(g_proveStatement, PROOF_DISCOURAGED)) { + /* print2("\n"); */ /* Enable for more emphasis */ + print2( +">>> ?Warning: Modification of this statement's proof is discouraged.\n" + ); + /* print2("\n"); */ /* Enable for more emphasis */ + } + + processUndoStack(NULL, PUS_INIT, "", 0); /* Optional? */ + /* Put the initial proof into the UNDO stack; we don't need + the info string since it won't be undone */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, "", 0); + continue; + } + + + if (cmdMatches("UNDO")) { + processUndoStack(&g_ProofInProgress, PUS_UNDO, "", 0); + g_proofChanged = 1; /* Maybe make this more intelligent some day */ + /* Automatically display new unknown steps + ???Future - add switch to enable/defeat this */ + typeProof(g_proveStatement, + 1 /*pipFlag*/, + 0 /*startStep*/, + 0 /*endStep*/, + 0 /*endIndent*/, + 1 /*essentialFlag*/, + 0 /*renumberFlag*/, + 1 /*unknownFlag*/, + 0 /*notUnifiedFlag*/, + 0 /*reverseFlag*/, + 0 /*noIndentFlag*/, + 0 /*splitColumn*/, + 0 /*skipRepeatedSteps*/, + 0 /*texFlag*/, + 0 /*g_htmlFlag*/); + continue; + } + + if (cmdMatches("REDO")) { + processUndoStack(&g_ProofInProgress, PUS_REDO, "", 0); + g_proofChanged = 1; /* Maybe make this more intelligent some day */ + /* Automatically display new unknown steps + ???Future - add switch to enable/defeat this */ + typeProof(g_proveStatement, + 1 /*pipFlag*/, + 0 /*startStep*/, + 0 /*endStep*/, + 0 /*endIndent*/, + 1 /*essentialFlag*/, + 0 /*renumberFlag*/, + 1 /*unknownFlag*/, + 0 /*notUnifiedFlag*/, + 0 /*reverseFlag*/, + 0 /*noIndentFlag*/, + 0 /*splitColumn*/, + 0 /*skipRepeatedSteps*/, + 0 /*texFlag*/, + 0 /*g_htmlFlag*/); + continue; + } + + if (cmdMatches("UNIFY")) { + m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ + g_proofChangedFlag = 0; + if (cmdMatches("UNIFY STEP")) { + + s = (long)val(g_fullArg[2]); /* Step number */ + if (s > m || s < 1) { + print2("?The step must be in the range from 1 to %ld.\n", m); + continue; + } + + interactiveUnifyStep(s - 1, 1); /* 2nd arg. means print msg if + already unified */ + + /* (The interactiveUnifyStep handles all messages.) */ + /* print2("... */ + + autoUnify(1); + if (g_proofChangedFlag) { + g_proofChanged = 1; /* Cumulative flag */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + } + continue; + } + + /* "UNIFY ALL" */ + if (!switchPos("/ INTERACTIVE")) { + autoUnify(1); + if (!g_proofChangedFlag) { + print2("No new unifications were made.\n"); + } else { + print2( + "Steps were unified. SHOW NEW_PROOF / NOT_UNIFIED to see any remaining.\n"); + g_proofChanged = 1; /* Cumulative flag */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + } + } else { + q = 0; + while (1) { + /* Repeat the unifications over and over until done, since + a later unification may improve the ability of an aborted earlier + one to be done without timeout */ + g_proofChangedFlag = 0; /* This flag is set by autoUnify() and + interactiveUnifyStep() */ + autoUnify(0); + for (s = m - 1; s >= 0; s--) { + interactiveUnifyStep(s, 0); /* 2nd arg. means no msg if already + unified */ + } + autoUnify(1); /* 1 means print congratulations if complete */ + if (!g_proofChangedFlag) { + if (!q) { + print2("No new unifications were made.\n"); + } else { + /* If q=1, then we are in the 2nd or later pass, which means + there was a change in the 1st pass. */ + print2( + "Steps were unified. SHOW NEW_PROOF / NOT_UNIFIED to see any remaining.\n"); + g_proofChanged = 1; /* Cumulative flag */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + } + break; /* while (1) */ + } else { + q = 1; /* Flag that we're starting a 2nd or later pass */ + } + } /* End while (1) */ + } + /* Automatically display new unknown steps + ???Future - add switch to enable/defeat this */ + typeProof(g_proveStatement, + 1 /*pipFlag*/, + 0 /*startStep*/, + 0 /*endStep*/, + 0 /*endIndent*/, + 1 /*essentialFlag*/, + 0 /*renumberFlag*/, + 1 /*unknownFlag*/, + 0 /*notUnifiedFlag*/, + 0 /*reverseFlag*/, + 0 /*noIndentFlag*/, + 0 /*splitColumn*/, + 0 /*skipRepeatedSteps*/, + 0 /*texFlag*/, + 0 /*g_htmlFlag*/); + continue; + } + + if (cmdMatches("MATCH")) { + + maxEssential = -1; /* Default: no maximum */ + i = switchPos("/ MAX_ESSENTIAL_HYP"); + if (i) maxEssential = (long)val(g_fullArg[i + 1]); + + if (cmdMatches("MATCH STEP")) { + + s = (long)val(g_fullArg[2]); /* Step number */ + m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ + if (s > m || s < 1) { + print2("?The step must be in the range from 1 to %ld.\n", m); + continue; + } + if ((g_ProofInProgress.proof)[s - 1] != -(long)'?') { + print2( + "?Step %ld is already assigned. Only unknown steps can be matched.\n", s); + continue; + } + + interactiveMatch(s - 1, maxEssential); + n = nmbrLen(g_ProofInProgress.proof); /* New proof length */ + if (n != m) { + if (s != m) { + printLongLine(cat("Steps ", str((double)s), ":", + str((double)m), " are now ", str((double)(s - m + n)), ":", + str((double)n), ".", + NULL), + "", " "); + } else { + printLongLine(cat("Step ", str((double)m), " is now step ", str((double)n), ".", + NULL), + "", " "); + } + } + + autoUnify(1); + g_proofChanged = 1; /* Cumulative flag */ + /* 1-Nov-2013 nm Why is g_proofChanged set unconditionally above? + Do we need the processUndoStack() call? */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + + continue; + } /* End if MATCH STEP */ + + if (cmdMatches("MATCH ALL")) { + + m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ + + k = 0; + g_proofChangedFlag = 0; + + if (switchPos("/ ESSENTIAL")) { + nmbrLet(&nmbrTmp, nmbrGetEssential(g_ProofInProgress.proof)); + } + + for (s = m; s > 0; s--) { + /* Match only unknown steps */ + if ((g_ProofInProgress.proof)[s - 1] != -(long)'?') continue; + /* Match only essential steps if specified */ + if (switchPos("/ ESSENTIAL")) { + if (!nmbrTmp[s - 1]) continue; + } + + interactiveMatch(s - 1, maxEssential); + if (g_proofChangedFlag) { + k = s; /* Save earliest step changed */ + g_proofChangedFlag = 0; + } + print2("\n"); + } + if (k) { + g_proofChangedFlag = 1; /* Restore it */ + g_proofChanged = 1; /* Cumulative flag */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + print2("Steps %ld and above have been renumbered.\n", k); + } + autoUnify(1); + + continue; + } /* End if MATCH ALL */ + } + + if (cmdMatches("LET")) { + + g_errorCount = 0; + nmbrLet(&nmbrTmp, parseMathTokens(g_fullArg[4], g_proveStatement)); + if (g_errorCount) { + /* Parsing issued error message(s) */ + g_errorCount = 0; + continue; + } + + if (cmdMatches("LET VARIABLE")) { + if (((vstring)(g_fullArg[2]))[0] != '$') { + print2( + "?The target variable must be of the form \"$\", e.g. \"$23\".\n"); + continue; + } + n = (long)val(right(g_fullArg[2], 2)); + if (n < 1 || n > g_pipDummyVars) { + print2("?The target variable must be between $1 and $%ld.\n", + g_pipDummyVars); + continue; + } + + replaceDummyVar(n, nmbrTmp); + + autoUnify(1); + + + g_proofChangedFlag = 1; /* Flag to push 'undo' stack */ + g_proofChanged = 1; /* Cumulative flag */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + + } + + if (cmdMatches("LET STEP")) { + + s = getStepNum(g_fullArg[2], g_ProofInProgress.proof, + 0 /* ALL not allowed */); + if (s == -1) continue; /* Error; message was provided already */ + + /* Check to see if the statement selected is allowed */ + if (!checkMStringMatch(nmbrTmp, s - 1)) { + printLongLine(cat("?Step ", str((double)s), " cannot be unified with \"", + nmbrCvtMToVString(nmbrTmp),"\".", NULL), " ", " "); + continue; + } + + /* Assign the user string */ + nmbrLet((nmbrString **)(&((g_ProofInProgress.user)[s - 1])), nmbrTmp); + + autoUnify(1); + g_proofChangedFlag = 1; /* Flag to push 'undo' stack */ + g_proofChanged = 1; /* Cumulative flag */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + } + /* Automatically display new unknown steps + ???Future - add switch to enable/defeat this */ + typeProof(g_proveStatement, + 1 /*pipFlag*/, + 0 /*startStep*/, + 0 /*endStep*/, + 0 /*endIndent*/, + 1 /*essentialFlag*/, + 0 /*renumberFlag*/, + 1 /*unknownFlag*/, + 0 /*notUnifiedFlag*/, + 0 /*reverseFlag*/, + 0 /*noIndentFlag*/, + 0 /*splitColumn*/, + 0 /*skipRepeatedSteps*/, + 0 /*texFlag*/, + 0 /*g_htmlFlag*/); + continue; + } + + + if (cmdMatches("ASSIGN")) { + s = getStepNum(g_fullArg[1], g_ProofInProgress.proof, + 0 /* ALL not allowed */); + if (s == -1) continue; /* Error; message was provided already */ + + /* 1 means to override usage locks */ + overrideFlag = ( (switchPos("/ OVERRIDE")) ? 1 : 0) + || g_globalDiscouragement == 0; + + /* Get the unique statement matching the g_fullArg[2] pattern */ + k = getStatementNum(g_fullArg[2], + 1/*startStmt*/, + g_proveStatement /*maxStmt*/, + 1/*aAllowed*/, + 1/*pAllowed*/, + 1/*eAllowed*/, + 1/*fAllowed*/, + 1/*efOnlyForMaxStmt*/, + 1/*uniqueFlag*/); + if (k == -1) { + continue; /* Error msg was provided if not unique */ + } + + if (getMarkupFlag(k, USAGE_DISCOURAGED)) { + if (overrideFlag == 0) { + /* print2("\n"); */ /* Enable for more emphasis */ + print2( +">>> ?Error: Attempt to assign a statement whose usage is discouraged.\n"); + print2( + ">>> Use ASSIGN ... / OVERRIDE if you really want to do this.\n"); + /* print2("\n"); */ /* Enable for more emphasis */ + continue; + } else { + /* print2("\n"); */ /* Enable for more emphasis */ + print2( +">>> ?Warning: You are assigning a statement whose usage is discouraged.\n"); + /* print2("\n"); */ /* Enable for more emphasis */ + } + } + + m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ + + /* Check to see that the step is an unknown step */ + if ((g_ProofInProgress.proof)[s - 1] != -(long)'?') { + print2( + "?Step %ld is already assigned. You can only assign unknown steps.\n" + , s); + continue; + } + + /* Check to see if the statement selected is allowed */ + if (!checkStmtMatch(k, s - 1)) { + print2("?Statement \"%s\" cannot be unified with step %ld.\n", + g_Statement[k].labelName, s); + continue; + } + + assignStatement(k /*statement#*/, s - 1 /*step*/); + + n = nmbrLen(g_ProofInProgress.proof); /* New proof length */ + autoUnify(1); + + /* Automatically interact with user if step not unified */ + /* ???We might want to add a setting to defeat this if user doesn't + like it */ + /* Since ASSIGN LAST is often run from a commmand file, don't + interact if / NO_UNIFY is specified, so response is predictable */ + if (switchPos("/ NO_UNIFY") == 0) { + interactiveUnifyStep(s - m + n - 1, 2); /* 2nd arg. means print msg if + already unified */ + } /* if NO_UNIFY flag not set */ + + /* See if it's in another mathbox; if so, let user know */ + assignMathboxInfo(); + if (k > g_mathboxStmt && g_proveStatement > g_mathboxStmt) { + if (k < g_mathboxStart[getMathboxNum(g_proveStatement) - 1]) { + printLongLine(cat("\"", g_Statement[k].labelName, + "\" is in the mathbox for ", + g_mathboxUser[getMathboxNum(k) - 1], ".", + NULL), + "", " "); + } + } + + /* Automatically display new unknown steps + ???Future - add switch to enable/defeat this */ + typeProof(g_proveStatement, + 1 /*pipFlag*/, + 0 /*startStep*/, + 0 /*endStep*/, + 0 /*endIndent*/, + 1 /*essentialFlag*/, + 0 /*renumberFlag*/, + 1 /*unknownFlag*/, + 0 /*notUnifiedFlag*/, + 0 /*reverseFlag*/, + 0 /*noIndentFlag*/, + 0 /*splitColumn*/, + 0 /*skipRepeatedSteps*/, + 0 /*texFlag*/, + 0 /*g_htmlFlag*/); + + g_proofChangedFlag = 1; /* Flag to push 'undo' stack (future) */ + g_proofChanged = 1; /* Cumulative flag */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + continue; + + } /* cmdMatches("ASSIGN") */ + + + if (cmdMatches("REPLACE")) { + /* 1 means to override usage locks */ + overrideFlag = ( (switchPos("/ OVERRIDE")) ? 1 : 0) + || g_globalDiscouragement == 0; + + step = getStepNum(g_fullArg[1], g_ProofInProgress.proof, + 0 /* ALL not allowed */); + if (step == -1) continue; /* Error; message was provided already */ + + /* Get the unique statement matching the g_fullArg[2] pattern */ + stmt = getStatementNum(g_fullArg[2], + 1/*startStmt*/, + g_proveStatement /*maxStmt*/, + 1/*aAllowed*/, + 1/*pAllowed*/, + 0/*eAllowed*/, /* Not implemented (yet?) */ + 0/*fAllowed*/, /* Not implemented (yet?) */ + 1/*efOnlyForMaxStmt*/, + 1/*uniqueFlag*/); + if (stmt == -1) { + continue; /* Error msg was provided if not unique */ + } + + if (getMarkupFlag(stmt, USAGE_DISCOURAGED)) { + if (overrideFlag == 0) { + /* print2("\n"); */ /* Enable for more emphasis */ + print2( +">>> ?Error: Attempt to assign a statement whose usage is discouraged.\n"); + print2( + ">>> Use REPLACE ... / OVERRIDE if you really want to do this.\n"); + /* print2("\n"); */ /* Enable for more emphasis */ + continue; + } else { + /* print2("\n"); */ /* Enable for more emphasis */ + print2( +">>> ?Warning: You are assigning a statement whose usage is discouraged.\n"); + /* print2("\n"); */ /* Enable for more emphasis */ + } + } + + m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ + + /* Set a flag that proof has unknown steps (for autoUnify() call below) */ + if (nmbrElementIn(1, g_ProofInProgress.proof, -(long)'?')) { + p = 1; + } else { + p = 0; + } + + /* Check to see if the statement selected is allowed */ + if (!checkStmtMatch(stmt, step - 1)) { + print2("?Statement \"%s\" cannot be unified with step %ld.\n", + g_Statement[stmt].labelName, step); + continue; + } + + /* Check dummy variable status of step */ + /* For use in message later */ + dummyVarIsoFlag = checkDummyVarIsolation(step - 1); + /* 0=no dummy vars, 1=isolated dummy vars, 2=not isolated*/ + + /* Do the replacement */ + nmbrTmpPtr = replaceStatement(stmt /*statement#*/, + step - 1 /*step*/, + g_proveStatement, + 0,/*scan whole proof to maximize chance of a match*/ + 0/*noDistinct*/, + 1/* try to prove $e's */, + 1/*improveDepth*/, + overrideFlag, + /* Currently REPLACE (not often used) allows other mathboxes + silently; TODO: we may want to notify user like for ASSIGN */ + 1/*mathboxFlag*/); + if (!nmbrLen(nmbrTmpPtr)) { + print2( + "?Hypotheses of statement \"%s\" do not match known proof steps.\n", + g_Statement[stmt].labelName); + continue; + } + + /* Get the subproof at step s */ + q = subproofLen(g_ProofInProgress.proof, step - 1); + deleteSubProof(step - 1); + addSubProof(nmbrTmpPtr, step - q); + + /* Assign known subproofs */ + assignKnownSubProofs(); + /* Initialize remaining steps */ + i = nmbrLen(g_ProofInProgress.proof); + for (j = 0; j < i; j++) { + if (!nmbrLen((g_ProofInProgress.source)[j])) { + initStep(j); + } + } + /* Unify whatever can be unified */ + /* If proof wasn't complete before (p = 1), but is now, print congrats + for user */ + autoUnify((char)p); /* 0 means no "congrats" message */ + + nmbrLet(&nmbrTmpPtr, NULL_NMBRSTRING); /* Deallocate memory */ + + n = nmbrLen(g_ProofInProgress.proof); /* New proof length */ + if (nmbrElementIn(1, g_ProofInProgress.proof, -(long)'?')) { + /* The proof is not complete, so print step numbers that changed */ + if (m == n) { + print2("Step %ld was replaced with statement %s.\n", + step, g_Statement[stmt].labelName); + } else { + if (step != m) { + printLongLine(cat("Step ", str((double)step), + " was replaced with statement ", g_Statement[stmt].labelName, + ". Steps ", str((double)step), ":", + str((double)m), " are now ", str((double)(step - m + n)), ":", + str((double)n), ".", + NULL), + "", " "); + } else { + printLongLine(cat("Step ", str((double)step), + " was replaced with statement ", g_Statement[stmt].labelName, + ". Step ", str((double)m), " is now step ", str((double)n), ".", + NULL), + "", " "); + } + } + } + + g_proofChangedFlag = 1; /* Flag to push 'undo' stack */ + g_proofChanged = 1; /* Cumulative flag */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + + if (dummyVarIsoFlag == 2 && g_proofChangedFlag) { + printLongLine(cat( + "Assignments to shared working variables ($nn) are guesses. If " + "incorrect, UNDO then assign them manually with LET ", + "and try REPLACE again.", + NULL), + "", " "); + } + + + /* Automatically display new unknown steps + ???Future - add switch to enable/defeat this */ + if (g_proofChangedFlag) + typeProof(g_proveStatement, + 1 /*pipFlag*/, + 0 /*startStep*/, + 0 /*endStep*/, + 0 /*endIndent*/, + 1 /*essentialFlag*/, + 0 /*renumberFlag*/, + 1 /*unknownFlag*/, + 0 /*notUnifiedFlag*/, + 0 /*reverseFlag*/, + 0 /*noIndentFlag*/, + 0 /*splitColumn*/, + 0 /*skipRepeatedSteps*/, + 0 /*texFlag*/, + 0 /*g_htmlFlag*/); + + continue; + + } /* REPLACE */ + + + if (cmdMatches("IMPROVE")) { + + improveDepth = 0; /* Depth */ + i = switchPos("/ DEPTH"); + if (i) improveDepth = (long)val(g_fullArg[i + 1]); + if (switchPos("/ NO_DISTINCT")) p = 1; else p = 0; + /* p = 1 means don't try to use statements with $d's */ + searchAlg = 1; /* Default */ + if (switchPos("/ 1")) searchAlg = 1; + if (switchPos("/ 2")) searchAlg = 2; + if (switchPos("/ 3")) searchAlg = 3; + searchUnkSubproofs = 0; + if (switchPos("/ SUBPROOFS")) searchUnkSubproofs = 1; + + mathboxFlag = (switchPos("/ INCLUDE_MATHBOXES") != 0); + assignMathboxInfo(); /* In case it hasn't been assigned yet */ + if (g_proveStatement > g_mathboxStmt) { + /* We're in a mathbox */ + i = getMathboxNum(g_proveStatement); + if (i <= 0) bug(1130); + thisMathboxStartStmt = g_mathboxStart[i - 1]; + } else { + thisMathboxStartStmt = g_mathboxStmt; + } + + /* 1 means to override usage locks */ + overrideFlag = ( (switchPos("/ OVERRIDE")) ? 1 : 0) + || g_globalDiscouragement == 0; + + s = getStepNum(g_fullArg[1], g_ProofInProgress.proof, + 1 /* 1 = "ALL" is permissible; returns 0 */); + if (s == -1) continue; /* Error; message was provided already */ + + if (s != 0) { /* s=0 means ALL */ + m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ + + /* Get the subproof at step s */ + q = subproofLen(g_ProofInProgress.proof, s - 1); + nmbrLet(&nmbrTmp, nmbrSeg(g_ProofInProgress.proof, s - q + 1, s)); + + /*???Shouldn't this be just known?*/ + /* Check to see that the subproof has an unknown step. */ + if (!nmbrElementIn(1, nmbrTmp, -(long)'?')) { + print2( + "?Step %ld already has a proof and cannot be improved.\n", + s); + continue; + } + + /* Check dummy variable status of step */ + dummyVarIsoFlag = checkDummyVarIsolation(s - 1); + /* 0=no dummy vars, 1=isolated dummy vars, 2=not isolated*/ + if (dummyVarIsoFlag == 2) { + print2( + "?Step %ld target has shared dummy variables and cannot be improved.\n", s); + continue; /* Don't try to improve + dummy variables that aren't isolated */ + } + + if (dummyVarIsoFlag == 0) { /* No dummy vars */ + /* Only use proveFloating if no dummy vars */ + nmbrTmpPtr = proveFloating((g_ProofInProgress.target)[s - 1], + g_proveStatement, improveDepth, s - 1, (char)p/*NO_DISTINCT*/, + overrideFlag, + mathboxFlag); + } else { + nmbrTmpPtr = NULL_NMBRSTRING; /* Initialize */ + } + if (!nmbrLen(nmbrTmpPtr)) { + /* A proof for the step was not found with proveFloating(). */ + + /* Next, try REPLACE algorithm */ + if (searchAlg == 2 || searchAlg == 3) { + nmbrTmpPtr = proveByReplacement(g_proveStatement, + s - 1/*prfStep*/, /* 0 means step 1 */ + (char)p/*NO_DISTINCT*/, /* 1 means don't try stmts with $d's */ + dummyVarIsoFlag, + (char)(searchAlg - 2), /*0=proveFloat for $fs, 1=$e's also */ + improveDepth, + overrideFlag, + mathboxFlag); + } + if (!nmbrLen(nmbrTmpPtr)) { + print2("A proof for step %ld was not found.\n", s); + /* REPLACE algorithm also failed */ + continue; + } + } + + /* If q=1, subproof must be an unknown step, so don't bother to + delete it */ + /*???Won't q always be 1 here?*/ + if (q > 1) deleteSubProof(s - 1); + addSubProof(nmbrTmpPtr, s - q); + assignKnownSteps(s - q, nmbrLen(nmbrTmpPtr)); + nmbrLet(&nmbrTmpPtr, NULL_NMBRSTRING); + + n = nmbrLen(g_ProofInProgress.proof); /* New proof length */ + if (m == n) { + print2("A 1-step proof was found for step %ld.\n", s); + } else { + if (s != m || q != 1) { + printLongLine(cat("A ", str((double)(n - m + 1)), + "-step proof was found for step ", str((double)s), + ". Steps ", str((double)s), ":", + str((double)m), " are now ", str((double)(s - q + 1 - m + n)), + ":", str((double)n), ".", + NULL), + "", " "); + } else { + printLongLine(cat("A ", str((double)(n - m + 1)), + "-step proof was found for step ", str((double)s), + ". Step ", str((double)m), " is now step ", str((double)n), ".", + NULL), + "", " "); + } + } + + autoUnify(1); /* To get 'congrats' message if proof complete */ + g_proofChanged = 1; /* Cumulative flag */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + + /* End if s != 0 i.e. not IMPROVE ALL */ + } else { + /* Here, getStepNum() returned 0, meaning ALL */ + + if (!nmbrElementIn(1, g_ProofInProgress.proof, -(long)'?')) { + print2("The proof is already complete.\n"); + continue; + } + + n = 0; /* Earliest step that changed */ + + g_proofChangedFlag = 0; + + for (improveAllIter = 1; improveAllIter <= 4; improveAllIter++) { + if (improveAllIter == 1 && (searchAlg == 2 || searchAlg == 3)) + print2("Pass 1: Trying to match cut-free statements...\n"); + if (improveAllIter == 2) { + if (searchAlg == 2) { + print2("Pass 2: Trying to match all statements...\n"); + } else { + print2( +"Pass 2: Trying to match all statements, with cut-free hypothesis matches...\n" + ); + } + } + if (improveAllIter == 3 && searchUnkSubproofs) + print2("Pass 3: Trying to replace incomplete subproofs...\n"); + if (improveAllIter == 4) { + if (searchUnkSubproofs) { + print2("Pass 4: Repeating pass 1...\n"); + } else { + print2("Pass 3: Repeating pass 1...\n"); + } + } + /* improveAllIter = 1: run proveFloating only */ + /* improveAllIter = 2: run proveByReplacement on unknown steps */ + /* improveAllIter = 3: run proveByReplacement on steps with + incomplete subproofs */ + /* improveAllIter = 4: if something changed, run everything again */ + + if (improveAllIter == 3 && !searchUnkSubproofs) continue; + + m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ + + for (s = m; s > 0; s--) { + + proofStepUnk = ((g_ProofInProgress.proof)[s - 1] == -(long)'?') + ? 1 : 0; + + /* I think this is really too conservative, even + with the old algorithm, but keep it to imitate the old one */ + if (improveAllIter == 1 || searchAlg == 1) { + /* If the step is known and unified, don't do it, since nothing + would be accomplished. */ + if (!proofStepUnk) { + if (nmbrEq((g_ProofInProgress.target)[s - 1], + (g_ProofInProgress.source)[s - 1])) continue; + } + } + + /* Get the subproof at step s */ + q = subproofLen(g_ProofInProgress.proof, s - 1); + if (proofStepUnk && q != 1) bug(1120); /* Consistency check */ + nmbrLet(&nmbrTmp, nmbrSeg(g_ProofInProgress.proof, s - q + 1, s)); + + /* Improve only subproofs with unknown steps */ + if (!nmbrElementIn(1, nmbrTmp, -(long)'?')) continue; + + nmbrLet(&nmbrTmp, NULL_NMBRSTRING); /* No longer needed - dealloc */ + + /* Check dummy variable status of step */ + dummyVarIsoFlag = checkDummyVarIsolation(s - 1); + /* 0=no dummy vars, 1=isolated dummy vars, 2=not isolated*/ + if (dummyVarIsoFlag == 2) continue; /* Don't try to improve + dummy variables that aren't isolated */ + + if (dummyVarIsoFlag == 0 + && (improveAllIter == 1 + || improveAllIter == 4)) { + /* No dummy vars */ + /* Only use proveFloating if no dummy vars */ + nmbrTmpPtr = proveFloating((g_ProofInProgress.target)[s - 1], + g_proveStatement, improveDepth, s - 1, + (char)p/*NO_DISTINCT*/, + overrideFlag, + mathboxFlag); + } else { + nmbrTmpPtr = NULL_NMBRSTRING; /* Init */ + } + if (!nmbrLen(nmbrTmpPtr)) { + /* A proof for the step was not found with proveFloating(). */ + + /* Next, try REPLACE algorithm */ + if ((searchAlg == 2 || searchAlg == 3) + && ((improveAllIter == 2 && proofStepUnk) + || (improveAllIter == 3 && !proofStepUnk) + /*|| improveAllIter == 4*/)) { + nmbrTmpPtr = proveByReplacement(g_proveStatement, + s - 1/*prfStep*/, /* 0 means step 1 */ + (char)p/*NO_DISTINCT*/, /* 1 means don't try stmts w/ $d's */ + dummyVarIsoFlag, + (char)(searchAlg - 2),/*searchMethod: 0 or 1*/ + improveDepth, + overrideFlag, + mathboxFlag); + + } + if (!nmbrLen(nmbrTmpPtr)) { + /* REPLACE algorithm also failed */ + continue; + } + } + + /* If q=1, subproof must be an unknown step, so don't bother to + delete it */ + if (q > 1) deleteSubProof(s - 1); + addSubProof(nmbrTmpPtr, s - q); + assignKnownSteps(s - q, nmbrLen(nmbrTmpPtr)); + print2("A proof of length %ld was found for step %ld.\n", + nmbrLen(nmbrTmpPtr), s); + if (nmbrLen(nmbrTmpPtr) || q != 1) n = s - q + 1; + /* Save earliest step changed */ + nmbrLet(&nmbrTmpPtr, NULL_NMBRSTRING); + g_proofChangedFlag = 1; + s = s - q + 1; /* Adjust step position to account for deleted subpr */ + } /* Next step s */ + + if (g_proofChangedFlag) { + autoUnify(0); /* 0 = No 'Congrats' if done */ + } + + if (!g_proofChangedFlag + && ( (improveAllIter == 2 && !searchUnkSubproofs) + || improveAllIter == 3 + || searchAlg == 1)) { + print2("No new subproofs were found.\n"); + break; /* out of improveAllIter loop */ + } + if (g_proofChangedFlag) { + g_proofChanged = 1; /* Cumulative flag */ + } + + if (!nmbrElementIn(1, g_ProofInProgress.proof, -(long)'?')) { + break; /* Proof is complete */ + } + + if (searchAlg == 1) break; /* Old algorithm does just 1st pass */ + + } /* Next improveAllIter */ + + if (g_proofChangedFlag) { + if (n > 0) { + /* n is the first step number changed. It will be 0 if + the numbering didn't change e.g. a $e was assigned to + an unknown step. */ + print2("Steps %ld and above have been renumbered.\n", n); + } + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + } + if (!nmbrElementIn(1, g_ProofInProgress.proof, -(long)'?')) { + /* This is a redundant call; its purpose is just to give + the message if the proof is complete */ + autoUnify(1); /* 1 = 'Congrats' if done */ + } + + } /* End if IMPROVE ALL */ + + /* Automatically display new unknown steps + ???Future - add switch to enable/defeat this */ + if (g_proofChangedFlag) + typeProof(g_proveStatement, + 1 /*pipFlag*/, + 0 /*startStep*/, + 0 /*endStep*/, + 0 /*endIndent*/, + 1 /*essentialFlag*/, + 0 /*renumberFlag*/, + 1 /*unknownFlag*/, + 0 /*notUnifiedFlag*/, + 0 /*reverseFlag*/, + 0 /*noIndentFlag*/, + 0 /*splitColumn*/, + 0 /*skipRepeatedSteps*/, + 0 /*texFlag*/, + 0 /*g_htmlFlag*/); + + continue; + + } /* cmdMatches("IMPROVE") */ + + + if (cmdMatches("MINIMIZE_WITH")) { + + printTime = 0; + if (switchPos("/ TIME") != 0) { + printTime = 1; + } + if (printTime == 1) { + getRunTime(&timeIncr); /* This call just resets the time */ + } + + prntStatus = 0; /* Status flag to help determine messages + 0 = no statement was matched during scan (mainly for + error message if user typo in label field) + 1 = a statement was matched but no shorter proof + 2 = shorter proof found */ + verboseMode = (switchPos("/ VERBOSE") != 0); /* Verbose mode */ + + /* If no wildcard was used, switch to non-verbose mode + since there is no point to it and an annoying extra blank line + results */ + if (!(instr(1, g_fullArg[1], "*") || instr(1, g_fullArg[1], "?"))) i = 1; + + mayGrowFlag = (switchPos("/ MAY_GROW") != 0); + /* Mode to replace even if it doesn't reduce proof length */ + exceptPos = switchPos("/ EXCEPT"); /* Statement match to skip */ + + allowNewAxiomsMatchPos = switchPos("/ ALLOW_NEW_AXIOMS"); + if (allowNewAxiomsMatchPos != 0) { + let(&allowNewAxiomsMatchList, g_fullArg[allowNewAxiomsMatchPos + 1]); + } else { + let(&allowNewAxiomsMatchList, ""); + } + + noNewAxiomsMatchPos = switchPos("/ NO_NEW_AXIOMS_FROM"); + if (noNewAxiomsMatchPos != 0) { + let(&noNewAxiomsMatchList, g_fullArg[noNewAxiomsMatchPos + 1]); + } else { + let(&noNewAxiomsMatchList, ""); + } + + forbidMatchPos = switchPos("/ FORBID"); + if (forbidMatchPos != 0) { + let(&forbidMatchList, g_fullArg[forbidMatchPos + 1]); + } else { + let(&forbidMatchList, ""); + } + + mathboxFlag = (switchPos("/ INCLUDE_MATHBOXES") != 0); + + /* Flag to override any "usage locks" placed in the comment markup */ + overrideFlag = (switchPos("/ OVERRIDE") != 0) + || g_globalDiscouragement == 0; + + /* If a single statement is specified, don't bother to do certain + actions or print some of the messages */ + hasWildCard = 0; + /* Set hasWildCard only when there are potentially > 1 matches */ + if (strpbrk(g_fullArg[1], "*?~%,") != NULL) { + /* (See matches() function for processing of these) + "*" 0 or more char match + "?" 1 char match + "=" Most recent PROVE command statement = one statement match + "~" Statement range + "%" List of modified statements + "#" Internal statement number = one statement match + "@" Web page statement number = one statement match + "," Comma-separated fields */ + hasWildCard = 1; + } + + g_proofChangedFlag = 0; + + /* Always scan statements in current mathbox, even if + "/ INCLUDE_MATHBOXES" is omitted */ + + assignMathboxInfo(); /* In case it hasn't been assigned yet */ + if (g_proveStatement > g_mathboxStmt) { + /* We're in a mathbox */ + i = getMathboxNum(g_proveStatement); + if (i <= 0) bug(1130); + thisMathboxStartStmt = g_mathboxStart[i - 1]; + } else { + thisMathboxStartStmt = g_mathboxStmt; + } + + copyProofStruct(&saveOrigProof, g_ProofInProgress); + + /* 12-Sep-2016 nm TODO replace this w/ compressedProofSize */ + /* Get the current (original) compressed proof length + to compare it when a shorter non-compressed proof is found, to see + if the compressed proof also decreased in size */ + nmbrLet(&nmbrSaveProof, g_ProofInProgress.proof); /* Redundant? */ + nmbrLet(&nmbrSaveProof, nmbrSquishProof(g_ProofInProgress.proof)); + /* We only care about length; str1 will be discarded */ + let(&str1, compressProof(nmbrSaveProof, + g_proveStatement, /* statement being proved */ + 0 /* Normal (not "fast") compression */ + )); + origCompressedLength = (long)strlen(str1); + print2("Bytes refer to compressed proof size, " + "steps to uncompressed length.\n"); + + /* Scan forward, then reverse, then pick best result */ + for (forwRevPass = 1; forwRevPass <= 2; forwRevPass++) { + + if (forwRevPass == 1) { + if (hasWildCard) print2("Scanning forward through statements...\n"); + forwFlag = 1; + } else { + /* If growth allowed, don't bother with reverse pass */ + if (mayGrowFlag) break; + /* If nothing was found on forward pass, don't bother with rev pass */ + if (!g_proofChangedFlag) break; + /* If only one statement was specified, don't bother with rev pass */ + if (!hasWildCard) break; + print2("Scanning backward through statements...\n"); + forwFlag = 0; + /* Save proof and length from 1st pass; re-initialize */ + copyProofStruct(&save1stPassProof, g_ProofInProgress); + forwardLength = nmbrLen(g_ProofInProgress.proof); + forwardCompressedLength = oldCompressedLength; + /* Start over from original proof */ + copyProofStruct(&g_ProofInProgress, saveOrigProof); + } + + copyProofStruct(&saveProofForReverting, g_ProofInProgress); + + oldCompressedLength = origCompressedLength; + + /* If forwFlag is 0, scan from g_proveStatement-1 to 1 + If forwFlag is 1, scan from 1 to g_proveStatement-1 */ + for (k = forwFlag ? 1 : (g_proveStatement - 1); + k * (forwFlag ? 1 : -1) < (forwFlag ? g_proveStatement : 0); + k = k + (forwFlag ? 1 : -1)) { + if (!mathboxFlag && k >= g_mathboxStmt && k < thisMathboxStartStmt) { + continue; + } + + if (g_Statement[k].type != (char)p_ && g_Statement[k].type != (char)a_) + continue; + if (!matchesList(g_Statement[k].labelName, g_fullArg[1], '*', '?')) + continue; + + if (exceptPos != 0) { + /* Skip any match to the EXCEPT argument */ + if (matchesList(g_Statement[k].labelName, g_fullArg[exceptPos + 1], + '*', '?')) + continue; + } + + if (forbidMatchList[0]) { /* User provided a /FORBID list */ + /* First, we check to make sure we're not trying a statement + in the forbidMatchList directly (traceProof() won't find + this) */ + if (matchesList(g_Statement[k].labelName, forbidMatchList, '*', '?')) + continue; + } + + /* Check to see if statement comment specified a usage + restriction */ + if (!overrideFlag) { + if (getMarkupFlag(k, USAGE_DISCOURAGED)) { + continue; + } + } + + /* Print individual labels */ + if (prntStatus == 0) prntStatus = 1; /* Matched at least one */ + + m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ + nmbrLet(&nmbrTmp, g_ProofInProgress.proof); + minimizeProof(k /* trial statement */, + g_proveStatement /* statement being proved in MM-PA */, + (char)mayGrowFlag /* mayGrowFlag */); + + n = nmbrLen(g_ProofInProgress.proof); /* New proof length */ + if (!nmbrEq(nmbrTmp, g_ProofInProgress.proof)) { + /* The proof got shorter (or it changed if MAY_GROW) */ + + /* Because of the slow speed of traceBack(), + we only want to check the /FORBID list in the relatively + rare case where a minimization occurred. If the FORBID + list is matched, we then need to revert back to the + original proof. */ + if (forbidMatchList[0]) { /* User provided a /FORBID list */ + if (g_Statement[k].type == (char)p_) { + /* We only care about tracing $p statements */ + /* See if the TRACE_BACK list includes a match to the + /FORBID argument */ + if (traceProof(k, + 0, /*essentialFlag*/ + 0, /*axiomFlag*/ + forbidMatchList, + "", /*traceToList*/ + 1 /* testOnlyFlag */)) { + /* Yes, a forbidden statement occurred in traceProof() */ + /* Revert the proof to before minimization */ + copyProofStruct(&g_ProofInProgress, saveProofForReverting); + /* Skip further printout and flag setting */ + continue; /* Continue at 'Next k' loop end below */ + } + } + } + + + /* Because of the slow speed of traceBack(), + we only want to check the /NO_NEW_AXIOMS_FROM list in the + relatively rare case where a minimization occurred. If the + NO_NEW_AXIOMS_FROM condition applies, we then need to revert + back to the original proof. */ + if (n == n + 0) { /* By default, no new axioms are permitted */ + /*if (noNewAxiomsMatchList[0]) {*/ /* User provided /NO_NEW_AXIOMS_FROM */ + /* If we haven't called trace yet for the theorem being proved, + do it now. */ + if (traceProofFlags[0] == 0) { + + /* traceProofWork() was written to use the SAVEd proof and + not the proof in progress. In order to use the proof in + progress, we temporarily put the proof in progress into the + (SAVEd) statement structure to trick traceProofWork() into using + the proof in progress instead of the SAVEd proof */ + /* Use the version of the proof in progress that existed *before* the + MINIMIZE_WITH command was invoked */ + nmbrLet(&nmbrSaveProof, nmbrSquishProof(saveProofForReverting.proof)); + let(&str1, compressProof(nmbrSaveProof, + g_proveStatement, /* statement being proved in MM-PA */ + 0 /* Normal (not "fast") compression */ + )); + saveZappedProofSectionPtr + = g_Statement[g_proveStatement].proofSectionPtr; + saveZappedProofSectionLen + = g_Statement[g_proveStatement].proofSectionLen; + saveZappedProofSectionChanged + = g_Statement[g_proveStatement].proofSectionChanged; + /* Set flag that this is not the original source */ + g_Statement[g_proveStatement].proofSectionChanged = 1; + /* str1 has the new compressed trial proof after minimization */ + /* Put space before and after to satisfy "space around token" + requirement, to prevent possible error messages, and also + add "$." since parseCompressedProof() expects it */ + let(&str1, cat(" ", str1, " $.", NULL)); + /* Don't include the "$." in the length */ + g_Statement[g_proveStatement].proofSectionLen + = (long)strlen(str1) - 2; + /* We don't deallocate previous proofSectionPtr content because + we will recover it after the verifyProof() */ + g_Statement[g_proveStatement].proofSectionPtr = str1; + + traceProofWork(g_proveStatement, + 1 /*essentialFlag*/, + "", /*traceToList*/ + &traceProofFlags, /* y/n list of flags */ + &nmbrTmp /* unproved list - ignored */); + nmbrLet(&nmbrTmp, NULL_NMBRSTRING); /* Discard */ + + /* Restore the SAVEd proof */ + g_Statement[g_proveStatement].proofSectionPtr + = saveZappedProofSectionPtr; + g_Statement[g_proveStatement].proofSectionLen + = saveZappedProofSectionLen; + g_Statement[g_proveStatement].proofSectionChanged + = saveZappedProofSectionChanged; + } + let(&traceTrialFlags, ""); + traceProofWork(k, /* The trial statement */ + 1 /*essentialFlag*/, + "", /*traceToList*/ + &traceTrialFlags, /* Y/N list of flags */ + &nmbrTmp /* unproved list - ignored */); + nmbrLet(&nmbrTmp, NULL_NMBRSTRING); /* Discard */ + j = 1; /* 1 = ok to use trial statement */ + for (i = 1; i < g_proveStatement; i++) { + if (g_Statement[i].type != (char)a_) continue; /* Not $a */ + if (traceProofFlags[i] == 'Y') continue; + /* If the axiom is already used by the proof, we + don't care if the trial statement depends on it */ + if (matchesList(g_Statement[i].labelName, allowNewAxiomsMatchList, + '*', '?') == 1 + && + matchesList(g_Statement[i].labelName, noNewAxiomsMatchList, + '*', '?') != 1) { + /* If the axiom is in the list to allow and not in the list + to disallow, we don't care if the trial statement depends + on it */ + continue; + } + if (traceTrialFlags[i] == 'Y') { + /* The trial statement uses an axiom that the current + proof should avoid, so we abort it */ + j = 0; /* 0 = don't use trial statement */ + break; + } + } /* next i */ + if (j == 0) { + /* A forbidden axiom is used by the trial proof */ + /* Revert the proof to before minimization */ + copyProofStruct(&g_ProofInProgress, saveProofForReverting); + /* Skip further printout and flag setting */ + continue; /* Continue at 'Next k' loop end below */ + } + } /* end if (true) */ + + + /* Make sure the compressed proof length + decreased, otherwise revert. Also, we will use the + compressed proof for the $d check next */ + if (nmbrLen(g_Statement[k].reqDisjVarsA) || !mayGrowFlag) { + nmbrLet(&nmbrSaveProof, g_ProofInProgress.proof); + nmbrLet(&nmbrSaveProof, nmbrSquishProof(g_ProofInProgress.proof)); + let(&str1, compressProof(nmbrSaveProof, + g_proveStatement, /* statement being proved in MM-PA */ + 0 /* Normal (not "fast") compression */ + )); + newCompressedLength = (long)strlen(str1); + if (!mayGrowFlag && newCompressedLength > oldCompressedLength) { + /* The compressed proof length increased, so don't use it. + (If it stayed the same, we will use it because the uncompressed + length did decrease.) */ + /* Revert the proof to before minimization */ + if (verboseMode) { + print2( + "Reverting \"%s\": Uncompressed steps: old = %ld, new = %ld\n", + g_Statement[k].labelName, + m, n ); + print2( + " but compressed size: old = %ld bytes, new = %ld bytes\n", + oldCompressedLength, newCompressedLength); + } + copyProofStruct(&g_ProofInProgress, saveProofForReverting); + /* Skip further printout and flag setting */ + continue; /* Continue at 'Next k' loop end below */ + } + } /* if (nmbrLen(g_Statement[k].reqDisjVarsA) || !mayGrowFlag) */ + + /* Make sure there are no $d violations, otherwise revert */ + /* This requires the str1 from above */ + if (nmbrLen(g_Statement[k].reqDisjVarsA)) { + /* There is currently no way to verify a proof that doesn't + read and parse the source directly. This should be + changed in the future to make the program more modular. But + for now, we temporarily zap the source with new compressed + proof and see if there are any $d violations by looking at + the error message output */ + saveZappedProofSectionPtr + = g_Statement[g_proveStatement].proofSectionPtr; + saveZappedProofSectionLen + = g_Statement[g_proveStatement].proofSectionLen; + + saveZappedProofSectionChanged + = g_Statement[g_proveStatement].proofSectionChanged; + /* Set flag that this is not the original source */ + g_Statement[g_proveStatement].proofSectionChanged = 1; + /* str1 has the new compressed trial proof after minimization */ + /* Put space before and after to satisfy "space around token" + requirement, to prevent possible error messages, and also + add "$." since parseCompressedProof() expects it */ + let(&str1, cat(" ", str1, " $.", NULL)); + /* Don't include the "$." in the length */ + g_Statement[g_proveStatement].proofSectionLen = (long)strlen(str1) - 2; + /* We don't deallocate previous proofSectionPtr content because + we will recover it after the verifyProof() */ + g_Statement[g_proveStatement].proofSectionPtr = str1; + + g_outputToString = 1; /* Suppress error messages */ + /* parseProof, verifyProof, cleanWkrProof must be + called in sequence to assign the g_WrkProof structure, verify + the proof, and deallocate the g_WrkProof structure. Either none + of them or all of them must be called. */ + parseProof(g_proveStatement); + verifyProof(g_proveStatement); /* Must be called even if error + occurred in parseProof, to init RPN stack + for cleanWrkProof() */ + /* don't change proof if there is an error + (which could be pre-existing). */ + i = (g_WrkProof.errorSeverity > 1); + /**** Here we look at the screen output sent to a string. + This is rather crude, and someday the ability to + check proofs and $d violations should be modularized *****/ + j = instr(1, g_printString, + "There is a disjoint variable ($d) violation"); + g_outputToString = 0; /* Restore to normal output */ + let(&g_printString, ""); /* Clear out the stored error messages */ + cleanWrkProof(); /* Deallocate verifyProof storage */ + g_Statement[g_proveStatement].proofSectionPtr + = saveZappedProofSectionPtr; + g_Statement[g_proveStatement].proofSectionLen + = saveZappedProofSectionLen; + g_Statement[g_proveStatement].proofSectionChanged + = saveZappedProofSectionChanged; + if (i != 0 || j != 0) { + /* There was a verify proof error (j!=0) or $d violation (i!=0) + so don't used minimized proof */ + /* Revert the proof to before minimization */ + copyProofStruct(&g_ProofInProgress, saveProofForReverting); + /* Skip further printout and flag setting */ + continue; /* Continue at 'Next k' loop end below */ + } + } /* if (nmbrLen(g_Statement[k].reqDisjVarsA)) */ + + /* Warn user if a discouraged statement is overridden */ + if (getMarkupFlag(k, USAGE_DISCOURAGED)) { + if (!overrideFlag) bug(1126); + /* print2("\n"); */ /* Enable for more emphasis */ + print2( + ">>> ?Warning: Overriding discouraged usage of \"%s\".\n", + g_Statement[k].labelName); + /* print2("\n"); */ /* Enable for more emphasis */ + } + + if (!mayGrowFlag) { + /* Note: this is the length BEFORE indentation and wrapping, + so it is less than SHOW PROOF ... /SIZE */ + if (newCompressedLength < oldCompressedLength) { + print2( + "Proof of \"%s\" decreased from %ld to %ld bytes using \"%s\".\n", + g_Statement[g_proveStatement].labelName, + oldCompressedLength, newCompressedLength, + g_Statement[k].labelName); + } else { + if (newCompressedLength > oldCompressedLength) bug(1123); + print2( + "Proof of \"%s\" stayed at %ld bytes using \"%s\".\n", + g_Statement[g_proveStatement].labelName, + oldCompressedLength, + g_Statement[k].labelName); + print2( + " (Uncompressed steps decreased from %ld to %ld).\n", + m, n ); + } + /* (We don't care about compressed length if MAY_GROW) */ + oldCompressedLength = newCompressedLength; + } + + if (n < m && (mayGrowFlag || verboseMode)) { + print2( + "%sProof of \"%s\" decreased from %ld to %ld steps using \"%s\".\n", + (mayGrowFlag ? "" : " "), + g_Statement[g_proveStatement].labelName, + m, n, g_Statement[k].labelName); + } + /* MAY_GROW possibility */ + if (m < n) print2( + "Proof of \"%s\" increased from %ld to %ld steps using \"%s\".\n", + g_Statement[g_proveStatement].labelName, + m, n, g_Statement[k].labelName); + /* MAY_GROW possibility */ + if (m == n) print2( + "Proof of \"%s\" remained at %ld steps using \"%s\".\n", + g_Statement[g_proveStatement].labelName, + m, g_Statement[k].labelName); + + /* See if it's in another mathbox; if so, let user know */ + assignMathboxInfo(); + if (k > g_mathboxStmt && g_proveStatement > g_mathboxStmt) { + if (k < g_mathboxStart[getMathboxNum(g_proveStatement) - 1]) { + printLongLine(cat("\"", g_Statement[k].labelName, + "\" is in the mathbox for ", + g_mathboxUser[getMathboxNum(k) - 1], ".", + NULL), + " ", " "); + } + } + + prntStatus = 2; /* Found one */ + g_proofChangedFlag = 1; + + /* Save the changed proof in case we have to restore + it later */ + copyProofStruct(&saveProofForReverting, g_ProofInProgress); + + } + + } /* Next k (statement) */ + + if (g_proofChangedFlag && forwRevPass == 2) { + /* Check whether the reverse pass found a better proof than the + forward pass */ + if (verboseMode) { + print2( +"Forward vs. backward: %ld vs. %ld bytes; %ld vs. %ld steps\n", + forwardCompressedLength, + oldCompressedLength, + forwardLength, + nmbrLen(g_ProofInProgress.proof)); + } + if (oldCompressedLength < forwardCompressedLength + || (oldCompressedLength == forwardCompressedLength && + nmbrLen(g_ProofInProgress.proof) < forwardLength)) { + /* The reverse pass was better */ + print2("The backward scan results were used.\n"); + } else { + copyProofStruct(&g_ProofInProgress, save1stPassProof); + print2("The forward scan results were used.\n"); + } + } + + } /* next forwRevPass */ + + if (prntStatus == 1 && !mayGrowFlag) + print2("No shorter proof was found.\n"); + if (prntStatus == 1 && mayGrowFlag) + print2("The proof was not changed.\n"); + if (!prntStatus /* && !noDistinctFlag */) + print2("?No earlier %s$p or $a label matches \"%s\".\n", + (overrideFlag ? "" : "(allowed) "), + g_fullArg[1]); + if (!mathboxFlag && g_proveStatement >= g_mathboxStmt) { + print2( + "(Other mathboxes were not checked. Use / INCLUDE_MATHBOXES to include them.)\n"); + } + + if (printTime == 1) { + getRunTime(&timeIncr); + print2("MINIMIZE_WITH run time = %7.2f sec for \"%s\"\n", timeIncr, + g_Statement[g_proveStatement].labelName); + } + + let(&str1, ""); /* Deallocate memory */ + nmbrLet(&nmbrSaveProof, NULL_NMBRSTRING); /* Deallocate memory */ + + /* Clear these Y/N trace strings unconditionally since new axioms are no + longer allowed by default, so they may become set regardless of + qualifiers */ + let(&traceProofFlags, ""); /* Deallocate memory */ + let(&traceTrialFlags, ""); /* Deallocate memory */ + + if (allowNewAxiomsMatchList[0]) { /* User provided /NO_NEW_AXIOMS_FROM list */ + let(&allowNewAxiomsMatchList, ""); /* Deallocate memory */ + } + + if (noNewAxiomsMatchList[0]) { /* User provided /ALLOW_NEW_AXIOMS list */ + let(&noNewAxiomsMatchList, ""); /* Deallocate memory */ + } + + if (forbidMatchList[0]) { /* User provided a /FORBID list */ + let(&forbidMatchList, ""); /* Deallocate memory */ + } + + deallocProofStruct(&saveProofForReverting); /* Deallocate memory */ + deallocProofStruct(&saveOrigProof); /* Deallocate memory */ + deallocProofStruct(&save1stPassProof); /* Deallocate memory */ + + if (g_proofChangedFlag) { + g_proofChanged = 1; /* Cumulative flag */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + } + continue; + + } /* End if MINIMIZE_WITH */ + + + if (cmdMatches("EXPAND")) { + + g_proofChangedFlag = 0; + nmbrLet(&nmbrSaveProof, g_ProofInProgress.proof); + s = compressedProofSize(nmbrSaveProof, g_proveStatement); + + for (i = g_proveStatement - 1; i >= 1; i--) { + if (g_Statement[i].type != (char)p_) continue; /* Not a $p */ + if (!matchesList(g_Statement[i].labelName, g_fullArg[1], '*', '?')) { + continue; + } + sourceStatement = i; + + nmbrTmp = expandProof(nmbrSaveProof, sourceStatement); + + if (!nmbrEq(nmbrTmp, nmbrSaveProof)) { + g_proofChangedFlag = 1; + n = compressedProofSize(nmbrTmp, g_proveStatement); + printLongLine(cat("Proof of \"", + g_Statement[g_proveStatement].labelName, "\" ", + (s == n ? cat("stayed at ", str((double)s), NULL) + : cat((s < n ? "increased from " : " decreased from "), + str((double)s), " to ", str((double)n), NULL)), + " bytes after expanding \"", + g_Statement[sourceStatement].labelName, "\".", NULL), " ", " "); + s = n; + nmbrLet(&nmbrSaveProof, nmbrTmp); + } + } + + if (g_proofChangedFlag) { + g_proofChanged = 1; /* Cumulative flag */ + /* Clear the existing proof structure */ + deallocProofStruct(&g_ProofInProgress); + /* Then rebuild proof structure from new proof nmbrTmp */ + initProofStruct(&g_ProofInProgress, nmbrTmp, g_proveStatement); + /* Save the new proof structure on the undo stack */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + } else { + print2("No expansion occurred. The proof was not changed.\n"); + } + nmbrLet(&nmbrSaveProof, NULL_NMBRSTRING); + nmbrLet(&nmbrTmp, NULL_NMBRSTRING); + continue; + } /* EXPAND */ + + + if (cmdMatches("DELETE STEP") || (cmdMatches("DELETE ALL"))) { + + if (cmdMatches("DELETE STEP")) { + s = (long)val(g_fullArg[2]); /* Step number */ + } else { + s = nmbrLen(g_ProofInProgress.proof); + } + if ((g_ProofInProgress.proof)[s - 1] == -(long)'?') { + print2("?Step %ld is unknown and cannot be deleted.\n", s); + continue; + } + m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ + if (s > m || s < 1) { + print2("?The step must be in the range from 1 to %ld.\n", m); + continue; + } + + deleteSubProof(s - 1); + n = nmbrLen(g_ProofInProgress.proof); /* New proof length */ + if (m == n) { + print2("Step %ld was deleted.\n", s); + } else { + if (n > 1) { + printLongLine(cat("A ", str((double)(m - n + 1)), + "-step subproof at step ", str((double)s), + " was deleted. Steps ", str((double)s), ":", + str((double)m), " are now ", str((double)(s - m + n)), ":", + str((double)n), ".", + NULL), + "", " "); + } else { + print2("The entire proof was deleted.\n"); + } + } + + /* Automatically display new unknown steps + ???Future - add switch to enable/defeat this */ + typeProof(g_proveStatement, + 1 /*pipFlag*/, + 0 /*startStep*/, + 0 /*endStep*/, + 0 /*endIndent*/, + 1 /*essentialFlag*/, + 0 /*renumberFlag*/, + 1 /*unknownFlag*/, + 0 /*notUnifiedFlag*/, + 0 /*reverseFlag*/, + 0 /*noIndentFlag*/, + 0 /*splitColumn*/, + 0 /*skipRepeatedSteps*/, + 0 /*texFlag*/, + 0 /*g_htmlFlag*/); + + g_proofChanged = 1; /* Cumulative flag */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + + continue; + + } + + if (cmdMatches("DELETE FLOATING_HYPOTHESES")) { + + /* Get the essential step flags */ + nmbrLet(&nmbrTmp, nmbrGetEssential(g_ProofInProgress.proof)); + + m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */ + + n = 0; /* Earliest step that changed */ + g_proofChangedFlag = 0; + + for (s = m; s > 0; s--) { + + /* Skip essential steps and unknown steps */ + if (nmbrTmp[s - 1] == 1) continue; /* Not floating */ + if ((g_ProofInProgress.proof)[s - 1] == -(long)'?') continue; /* Unknown */ + + /* Get the subproof length at step s */ + q = subproofLen(g_ProofInProgress.proof, s - 1); + + deleteSubProof(s - 1); + + n = s - q + 1; /* Save earliest step changed */ + g_proofChangedFlag = 1; + s = s - q + 1; /* Adjust step position to account for deleted subpr */ + } /* Next step s */ + + if (g_proofChangedFlag) { + print2("All floating-hypothesis steps were deleted.\n"); + + if (n) { + print2("Steps %ld and above have been renumbered.\n", n); + } + + /* Automatically display new unknown steps + ???Future - add switch to enable/defeat this */ + typeProof(g_proveStatement, + 1 /*pipFlag*/, + 0 /*startStep*/, + 0 /*endStep*/, + 0 /*endIndent*/, + 1 /*essentialFlag*/, + 0 /*renumberFlag*/, + 1 /*unknownFlag*/, + 0 /*notUnifiedFlag*/, + 0 /*reverseFlag*/, + 0 /*noIndentFlag*/, + 0 /*splitColumn*/, + 0 /*skipRepeatedSteps*/, + 0 /*texFlag*/, + 0 /*g_htmlFlag*/); + + g_proofChanged = 1; /* Cumulative flag */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + } else { + print2("?There are no floating-hypothesis steps to delete.\n"); + } + + continue; + + } /* End if DELETE FLOATING_HYPOTHESES */ + + if (cmdMatches("INITIALIZE")) { + + if (cmdMatches("INITIALIZE ALL")) { + i = nmbrLen(g_ProofInProgress.proof); + + /* Reset the dummy variable counter (all will be refreshed) */ + g_pipDummyVars = 0; + + /* Initialize all steps */ + for (j = 0; j < i; j++) { + initStep(j); + } + + /* Assign known subproofs */ + assignKnownSubProofs(); + + print2("All steps have been initialized.\n"); + g_proofChanged = 1; /* Cumulative flag */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + continue; + } + + if (cmdMatches("INITIALIZE USER")) { + i = nmbrLen(g_ProofInProgress.proof); + /* Delete all LET STEP assignments */ + for (j = 0; j < i; j++) { + nmbrLet((nmbrString **)(&((g_ProofInProgress.user)[j])), + NULL_NMBRSTRING); + } + print2( + "All LET STEP user assignments have been initialized (i.e. deleted).\n"); + g_proofChanged = 1; /* Cumulative flag */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + continue; + } + + s = (long)val(g_fullArg[2]); /* Step number */ + if (s > nmbrLen(g_ProofInProgress.proof) || s < 1) { + print2("?The step must be in the range from 1 to %ld.\n", + nmbrLen(g_ProofInProgress.proof)); + continue; + } + + initStep(s - 1); + + /* Also delete LET STEPs, per HELP INITIALIZE */ + nmbrLet((nmbrString **)(&((g_ProofInProgress.user)[s - 1])), + NULL_NMBRSTRING); + + print2("Step %ld and its hypotheses have been initialized.\n", s); + + g_proofChanged = 1; /* Cumulative flag */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0); + continue; + + } + + + if (cmdMatches("SEARCH")) { + if (switchPos("/ ALL")) { + m = 1; /* Include $e, $f statements */ + } else { + m = 0; /* Show $a, $p only */ + } + + if (switchPos("/ JOIN")) { + joinFlag = 1; /* Join $e's to $a,$p for matching */ + } else { + joinFlag = 0; /* Search $a,$p by themselves */ + } + + if (switchPos("/ COMMENTS")) { + n = 1; /* Search comments */ + } else { + n = 0; /* Search statement math symbols */ + } + + let(&str1, g_fullArg[2]); /* String to match */ + + if (n) { /* COMMENTS switch */ + /* Trim leading, trailing spaces; reduce white space to space; + convert to upper case */ + let(&str1, edit(str1, 8 + 16 + 128 + 32)); + } else { /* No COMMENTS switch */ + /* Trim leading, trailing spaces; reduce white space to space */ + let(&str1, edit(str1, 8 + 16 + 128)); + + /* Change all spaces to double spaces */ + q = (long)strlen(str1); + let(&str3, space(q + q)); + s = 0; + for (p = 0; p < q; p++) { + str3[p + s] = str1[p]; + if (str1[p] == ' ') { + s++; + str3[p + s] = str1[p]; + } + } + let(&str1, left(str3, q + s)); + + /* Find single-character-match wildcard argument "$?" + (or "?" for convenience). Use ASCII 3 for the exactly-1-char + wildcard character. This is a single-character + match, not a single-token match: we need "??" to match "ph". */ + while (1) { + p = instr(1, str1, "$?"); + if (!p) break; + let(&str1, cat(left(str1, p - 1), chr(3), right(str1, p + 2), NULL)); + } + /* Allow just "?" for convenience. */ + while (1) { + p = instr(1, str1, "?"); + if (!p) break; + let(&str1, cat(left(str1, p - 1), chr(3), right(str1, p + 1), NULL)); + } + + /* Change wildcard to ASCII 2 (to be different from printable chars) */ + /* 1-Mar-02 nm - (Why are we matching with and without space? I'm not sure.) */ + /* 30-Jan-06 nm Answer: We need the double-spacing, and the removal + of space in the "with spaces" case, so that "ph $ ph" will match + "ph ph" (0-token case) - "ph $ ph" won't match this in the + (character-based, not token-based) matches(). The "with spaces" + case is for matching whole tokens, whereas the "without spaces" + case is for matching part of a token. */ + while (1) { + p = instr(1, str1, " $* "); + if (!p) break; + /* This removes the space before and after the $* */ + let(&str1, cat(left(str1, p - 1), chr(2), right(str1, p + 4), NULL)); + } + while (1) { + p = instr(1, str1, "$*"); + if (!p) break; + /* This simply replaces $* with chr(2) */ + let(&str1, cat(left(str1, p - 1), chr(2), right(str1, p + 2), NULL)); + } + /* Also allow a plain $ as a wildcard, for convenience. */ + while (1) { + p = instr(1, str1, " $ "); + if (!p) break; + let(&str1, cat(left(str1, p - 1), chr(2), right(str1, p + 3), NULL)); + } + while (1) { + /* Note: the "$" shortcut must be done last to avoid picking up + "$*" and "$?". */ + p = instr(1, str1, "$"); + if (!p) break; + let(&str1, cat(left(str1, p - 1), chr(2), right(str1, p + 1), NULL)); + } + + /* Add wildcards to beginning and end to match middle of any string */ + let(&str1, cat(chr(2), " ", str1, " ", chr(2), NULL)); + } /* End no COMMENTS switch */ + + for (i = 1; i <= g_statements; i++) { + if (!g_Statement[i].labelName[0]) continue; /* No label */ + if (!m && g_Statement[i].type != (char)p_ && + g_Statement[i].type != (char)a_) { + continue; /* No /ALL switch */ + } + if (!matchesList(g_Statement[i].labelName, g_fullArg[1], '*', '?')) + continue; + if (n) { /* COMMENTS switch */ + let(&str2, ""); + str2 = getDescription(i); /* str2 must be deallocated here */ + /* Strip linefeeds and reduce spaces; cvt to uppercase */ + j = instr(1, edit(str2, 4 + 8 + 16 + 128 + 32), str1); + if (!j) { /* No match */ + let(&str2, ""); + continue; + } + /* Strip linefeeds and reduce spaces */ + let(&str2, edit(str2, 4 + 8 + 16 + 128)); + j = j + ((long)strlen(str1) / 2); /* Center of match location */ + p = g_screenWidth - 7 - (long)strlen(str((double)i)) - + (long)strlen(g_Statement[i].labelName); + /* Longest comment portion that will fit in one line */ + q = (long)strlen(str2); /* Length of comment */ + if (q <= p) { /* Use entire comment */ + let(&str3, str2); + } else { + if (q - j <= p / 2) { /* Use right part of comment */ + let(&str3, cat("...", right(str2, q - p + 4), NULL)); + } else { + if (j <= p / 2) { /* Use left part of comment */ + let(&str3, cat(left(str2, p - 3), "...", NULL)); + } else { /* Use middle part of comment */ + let(&str3, cat("...", mid(str2, j - p / 2, p - 6), "...", + NULL)); + } + } + } + print2("%s\n", cat(str((double)i), " ", g_Statement[i].labelName, " $", + chr(g_Statement[i].type), " \"", str3, "\"", NULL)); + let(&str2, ""); + } else { /* No COMMENTS switch */ + let(&str2,nmbrCvtMToVString(g_Statement[i].mathString)); + + tmpFlag = 0; /* Flag that $p or $a is already in string */ + if (joinFlag && (g_Statement[i].type == (char)p_ || + g_Statement[i].type == (char)a_)) { + /* If $a or $p, prepend $e's to string to match */ + k = nmbrLen(g_Statement[i].reqHypList); + for (j = k - 1; j >= 0; j--) { + p = g_Statement[i].reqHypList[j]; + if (g_Statement[p].type == (char)e_) { + let(&str2, cat("$e ", + nmbrCvtMToVString(g_Statement[p].mathString), + tmpFlag ? "" : cat(" $", chr(g_Statement[i].type), NULL), + " ", str2, NULL)); + tmpFlag = 1; /* Flag that a $p or $a was added */ + } + } + } + + /* Change all spaces to double spaces */ + q = (long)strlen(str2); + let(&str3, space(q + q)); + s = 0; + for (p = 0; p < q; p++) { + str3[p + s] = str2[p]; + if (str2[p] == ' ') { + s++; + str3[p + s] = str2[p]; + } + } + let(&str2, left(str3, q + s)); + + let(&str2, cat(" ", str2, " ", NULL)); + /* We should use matches() and not matchesList() here, because + commas can be legal token characters in math symbols */ + if (!matches(str2, str1, 2/* ascii 2 0-or-more-token match char*/, + 3/* ascii 3 single-token-match char*/)) + continue; + let(&str2, edit(str2, 8 + 16 + 128)); /* Trim leading, trailing + spaces; reduce white space to space */ + printLongLine(cat(str((double)i)," ", + g_Statement[i].labelName, + tmpFlag ? "" : cat(" $", chr(g_Statement[i].type), NULL), + " ", str2, + NULL), " ", " "); + } /* End no COMMENTS switch */ + } /* Next i */ + continue; + } + + + if (cmdMatches("SET ECHO")) { + if (cmdMatches("SET ECHO ON")) { + g_commandEcho = 1; + print2("!SET ECHO ON\n"); + print2("Command line echoing is now turned on.\n"); + } else { + g_commandEcho = 0; + print2("Command line echoing is now turned off.\n"); + } + continue; + } + + if (cmdMatches("SET MEMORY_STATUS")) { + if (cmdMatches("SET MEMORY_STATUS ON")) { + print2("Memory status display has been turned on.\n"); + print2("This command is intended for debugging purposes only.\n"); + g_memoryStatus = 1; + } else { + g_memoryStatus = 0; + print2("Memory status display has been turned off.\n"); + } + continue; + } + + + if (cmdMatches("SET JEREMY_HENTY_FILTER")) { + if (cmdMatches("SET JEREMY_HENTY_FILTER ON")) { + print2("The unification equivalence filter has been turned on.\n"); + print2("This command is intended for debugging purposes only.\n"); + g_hentyFilter = 1; + } else { + print2("This command is intended for debugging purposes only.\n"); + print2("The unification equivalence filter has been turned off.\n"); + g_hentyFilter = 0; + } + continue; + } + + + if (cmdMatches("SET EMPTY_SUBSTITUTION")) { + if (cmdMatches("SET EMPTY_SUBSTITUTION ON")) { + g_minSubstLen = 0; + print2("Substitutions with empty symbol sequences is now allowed.\n"); + continue; + } + if (cmdMatches("SET EMPTY_SUBSTITUTION OFF")) { + g_minSubstLen = 1; + printLongLine(cat("The ability to substitute empty expressions", + " for variables has been turned off. Note that this may", + " make the Proof Assistant too restrictive in some cases.", + NULL), + "", " "); + continue; + } + } + + + if (cmdMatches("SET SEARCH_LIMIT")) { + s = (long)val(g_fullArg[2]); /* Timeout value */ + print2("IMPROVE search limit has been changed from %ld to %ld\n", + g_userMaxProveFloat, s); + g_userMaxProveFloat = s; + continue; + } + + if (cmdMatches("SET WIDTH")) { + s = (long)val(g_fullArg[2]); /* Screen width value */ + + /* TODO: figure out why s=2 crashes program! */ + if (s < 3) s = 3; /* Less than 3 may cause a segmentation fault */ + i = g_screenWidth; + g_screenWidth = s; + print2("Screen width has been changed from %ld to %ld.\n", + i, s); + continue; + } + + + if (cmdMatches("SET HEIGHT")) { + s = (long)val(g_fullArg[2]); /* Screen height value */ + if (s < 2) s = 2; /* Less than 2 makes no sense */ + i = g_screenHeight; + g_screenHeight = s - 1; + print2("Screen height has been changed from %ld to %ld.\n", + i + 1, s); + /* g_screenHeight is one less than the physical screen to account for the + prompt line after pausing. */ + continue; + } + + + if (cmdMatches("SET DISCOURAGEMENT")) { + if (!strcmp(g_fullArg[2], "ON")) { + g_globalDiscouragement = 1; + print2("\"(...is discouraged.)\" markup tags are now honored.\n"); + } else if (!strcmp(g_fullArg[2], "OFF")) { + print2( + "\"(...is discouraged.)\" markup tags are no longer honored.\n"); + /* print2("\n"); */ /* Enable for more emphasis */ + print2( +">>> ?Warning: This setting is intended for advanced users only. Please turn\n"); + print2( +">>> it back ON if you are not intimately familiar with this database.\n"); + /* print2("\n"); */ /* Enable for more emphasis */ + g_globalDiscouragement = 0; + } else { + bug(1129); + } + continue; + } + + + if (cmdMatches("SET CONTRIBUTOR")) { + print2("\"Contributed by...\" name was changed from \"%s\" to \"%s\"\n", + g_contributorName, g_fullArg[2]); + let(&g_contributorName, g_fullArg[2]); + continue; + } + + + if (cmdMatches("SET ROOT_DIRECTORY")) { + let(&str1, g_rootDirectory); /* Save previous one */ + let(&g_rootDirectory, edit(g_fullArg[2], 2/*discard spaces,tabs*/)); + if (g_rootDirectory[0] != 0) { /* Not an empty directory path */ + /* Add trailing "/" to g_rootDirectory if missing */ + if (instr(1, g_rootDirectory, "\\") != 0 + || instr(1, g_input_fn, "\\") != 0 + || instr(1, g_output_fn, "\\") != 0 ) { + /* Using Windows-style path (not really supported, but at least + make full path consistent) */ + if (g_rootDirectory[strlen(g_rootDirectory) - 1] != '\\') { + let(&g_rootDirectory, cat(g_rootDirectory, "\\", NULL)); + } + } else { + if (g_rootDirectory[strlen(g_rootDirectory) - 1] != '/') { + let(&g_rootDirectory, cat(g_rootDirectory, "/", NULL)); + } + } + } + if (strcmp(str1, g_rootDirectory)) { + print2("Root directory was changed from \"%s\" to \"%s\"\n", + str1, g_rootDirectory); + } + let(&str1, ""); + continue; + } + + + if (cmdMatches("SET UNDO")) { + s = (long)val(g_fullArg[2]); /* Maximum UNDOs */ + if (s < 0) s = 0; /* Less than 0 UNDOs makes no sense */ + /* Reset the stack size if it changed */ + if (processUndoStack(NULL, PUS_GET_SIZE, "", 0) != s) { + print2( + "The maximum number of UNDOs was changed from %ld to %ld\n", + processUndoStack(NULL, PUS_GET_SIZE, "", 0), s); + processUndoStack(NULL, PUS_NEW_SIZE, "", s); + if (g_PFASmode == 1) { + /* If we're in the Proof Assistant, assign the first stack + entry with the current proof (the stack was erased) */ + processUndoStack(&g_ProofInProgress, PUS_PUSH, "", 0); + } + } else { + print2("The maximum number of UNDOs was not changed.\n"); + } + continue; + } + + + if (cmdMatches("SET UNIFICATION_TIMEOUT")) { + s = (long)val(g_fullArg[2]); /* Timeout value */ + print2("Unification timeout has been changed from %ld to %ld\n", + g_userMaxUnifTrials,s); + g_userMaxUnifTrials = s; + continue; + } + + + if (cmdMatches("OPEN LOG")) { + /* Open a log file */ + let(&g_logFileName, g_fullArg[2]); + g_logFilePtr = fSafeOpen(g_logFileName, "w", 0/*noVersioningFlag*/); + if (!g_logFilePtr) continue; /* Couldn't open it (err msg was provided) */ + g_logFileOpenFlag = 1; + print2("The log file \"%s\" was opened %s %s.\n",g_logFileName, + date(),time_()); + continue; + } + + if (cmdMatches("CLOSE LOG")) { + /* Close the log file */ + if (!g_logFileOpenFlag) { + print2("?Sorry, there is no log file currently open.\n"); + } else { + print2("The log file \"%s\" was closed %s %s.\n",g_logFileName, + date(),time_()); + fclose(g_logFilePtr); + g_logFileOpenFlag = 0; + } + let(&g_logFileName,""); + continue; + } + + if (cmdMatches("OPEN TEX")) { + if (g_texDefsRead) { + if (g_htmlFlag) { + /* Actually it isn't clear to me this is still the case, but + to be safe I left it in */ + print2("?You cannot use both LaTeX and HTML in the same session.\n"); + print2( + "?You must EXIT and restart Metamath to switch to the other.\n"); + continue; + } + } + + /* Open a TeX file */ + let(&g_texFileName,g_fullArg[2]); + if (switchPos("/ NO_HEADER")) { + texHeaderFlag = 0; + } else { + texHeaderFlag = 1; + } + + if (switchPos("/ OLD_TEX")) { + g_oldTexFlag = 1; + } else { + g_oldTexFlag = 0; + } + g_texFilePtr = fSafeOpen(g_texFileName, "w", 0/*noVersioningFlag*/); + if (!g_texFilePtr) continue; /* Couldn't open it (err msg was provided) */ + g_texFileOpenFlag = 1; + print2("Created %s output file \"%s\".\n", + g_htmlFlag ? "HTML" : "LaTeX", g_texFileName); + printTexHeader(texHeaderFlag); + g_oldTexFlag = 0; + continue; + } + + if (cmdMatches("CLOSE TEX")) { + /* Close the TeX file */ + if (!g_texFileOpenFlag) { + print2("?Sorry, there is no LaTeX file currently open.\n"); + } else { + print2("The LaTeX output file \"%s\" has been closed.\n", + g_texFileName); + printTexTrailer(texHeaderFlag); + fclose(g_texFilePtr); + g_texFileOpenFlag = 0; + } + let(&g_texFileName,""); + continue; + } + + /* Similar to Unix 'more' */ + if (cmdMatches("MORE")) { + list1_fp = fSafeOpen(g_fullArg[1], "r", 0/*noVersioningFlag*/); + if (!list1_fp) continue; /* Couldn't open it (error msg was provided) */ + while (1) { + if (!linput(list1_fp, NULL, &str1)) break; /* End of file */ + /* Print a line on the screen */ + if (!print2("%s\n", str1)) break; /* User typed Q */ + } + fclose(list1_fp); + continue; + } /* end MORE */ + + + if (cmdMatches("FILE SEARCH")) { + /* Search the contents of a file and type on the screen */ + + type_fp = fSafeOpen(g_fullArg[2], "r", 0/*noVersioningFlag*/); + if (!type_fp) continue; /* Couldn't open it (error msg was provided) */ + fromLine = 0; + toLine = 0; + searchWindow = 0; + i = switchPos("/ FROM_LINE"); + if (i) fromLine = (long)val(g_fullArg[i + 1]); + i = switchPos("/ TO_LINE"); + if (i) toLine = (long)val(g_fullArg[i + 1]); + i = switchPos("/ WINDOW"); + if (i) searchWindow = (long)val(g_fullArg[i + 1]); + /*??? Implement SEARCH /WINDOW */ + if (i) print2("Sorry, WINDOW has not be implemented yet.\n"); + + let(&str2, g_fullArg[3]); /* Search string */ + let(&str2, edit(str2, 32)); /* Convert to upper case */ + + tmpFlag = 0; + + /* Search window buffer */ + pntrLet(&pntrTmp, pntrSpace(searchWindow)); + + j = 0; /* Line # */ + m = 0; /* # matches */ + while (linput(type_fp, NULL, &str1)) { + j++; + if (j > toLine && toLine != 0) break; + if (j >= fromLine || fromLine == 0) { + let(&str3, edit(str1, 32)); /* Convert to upper case */ + if (instr(1, str3, str2)) { /* Match occurred */ + if (!tmpFlag) { + tmpFlag = 1; + print2( + "The line number in the file is shown before each line.\n"); + } + m++; + if (!print2("%ld: %s\n", j, left(str1, + MAX_LEN - (long)strlen(str((double)j)) - 3))) break; + } + } + for (k = 1; k < searchWindow; k++) { + let((vstring *)(&pntrTmp[k - 1]), pntrTmp[k]); + } + if (searchWindow > 0) + let((vstring *)(&pntrTmp[searchWindow - 1]), str1); + } + if (!tmpFlag) { + print2("There were no matches.\n"); + } else { + if (m == 1) { + print2("There was %ld matching line in the file %s.\n", m, + g_fullArg[2]); + } else { + print2("There were %ld matching lines in the file %s.\n", m, + g_fullArg[2]); + } + } + + fclose(type_fp); + + /* Deallocate search window buffer */ + for (i = 0; i < searchWindow; i++) { + let((vstring *)(&pntrTmp[i]), ""); + } + pntrLet(&pntrTmp, NULL_PNTRSTRING); + + + continue; + } + + + if (cmdMatches("SET UNIVERSE") || cmdMatches("ADD UNIVERSE") || + cmdMatches("DELETE UNIVERSE")) { + + /*continue;*/ /* ???Not implemented */ + } /* end if xxx UNIVERSE */ + + + + if (cmdMatches("SET DEBUG FLAG")) { + print2("Notice: The DEBUG mode is intended for development use only.\n"); + print2("The printout will not be meaningful to the user.\n"); + i = (long)val(g_fullArg[3]); + if (i == 4) db4 = 1; /* Not used */ + if (i == 5) db5 = 1; /* mmpars.c statistics; mmunif.c overview */ + if (i == 6) db6 = 1; /* mmunif.c details */ + if (i == 7) db7 = 1; /* mmunif.c more details; mmveri.c */ + if (i == 8) db8 = 1; /* mmpfas.c unification calls */ + if (i == 9) db9 = 1; /* memory */ /* use SET MEMORY_STATUS ON instead */ + continue; + } + if (cmdMatches("SET DEBUG OFF")) { + db4 = 0; + db5 = 0; + db6 = 0; + db7 = 0; + db8 = 0; + db9 = 0; + print2("The DEBUG mode has been turned off.\n"); + continue; + } + + if (cmdMatches("ERASE")) { + if (g_sourceChanged) { + print2("Warning: You have not saved changes to the source.\n"); + str1 = cmdInput1("Do you want to ERASE anyway (Y, N) ? "); + if (str1[0] != 'y' && str1[0] != 'Y') { + print2("Use WRITE SOURCE to save the changes.\n"); + continue; + } + g_sourceChanged = 0; + } + eraseSource(); + g_sourceHasBeenRead = 0; /* Global variable */ + g_showStatement = 0; + g_proveStatement = 0; + print2("Metamath has been reset to the starting state.\n"); + continue; + } + + if (cmdMatches("VERIFY PROOF")) { + if (switchPos("/ SYNTAX_ONLY")) { + verifyProofs(g_fullArg[2],0); /* Parse only */ + } else { + verifyProofs(g_fullArg[2],1); /* Parse and verify */ + } + continue; + } + + if (cmdMatches("VERIFY MARKUP")) { + i = (switchPos("/ DATE_SKIP") != 0) ? 1 : 0; + j = (switchPos("/ TOP_DATE_SKIP") != 0) ? 1 : 0; + k = (switchPos("/ FILE_SKIP") != 0) ? 1 : 0; + l = (switchPos("/ UNDERSCORE_SKIP") != 0) ? 1 : 0; + m = (switchPos("/ MATHBOX_SKIP") != 0) ? 1 : 0; + n = (switchPos("/ VERBOSE") != 0) ? 1 : 0; + if (i == 1 && j == 1) { + printf( + "?Only one of / DATE_SKIP and / TOP_DATE_SKIP may be specified.\n"); + continue; + } + verifyMarkup(g_fullArg[2], + (flag)i, /* 1 = skip checking date consistency */ + (flag)j, /* 1 = skip checking top date only */ + (flag)k, /* 1 = skip checking external files GIF, mmset.html,... */ + (flag)l, /* 1 = skip checking labels for underscores */ + (flag)m, /* 1 = skip checking mathbox cross-references */ + (flag)n); /* 1 = verbose mode */ + continue; + } + + if (cmdMatches("MARKUP")) { + g_htmlFlag = 1; + g_altHtmlFlag = (switchPos("/ ALT_HTML") != 0); + if ((switchPos("/ HTML") != 0) == (switchPos("/ ALT_HTML") != 0)) { + print2("?Please specify exactly one of / HTML and / ALT_HTML.\n"); + continue; + } + i = 0; + i = ((switchPos("/ SYMBOLS") != 0) ? PROCESS_SYMBOLS : 0) + + ((switchPos("/ LABELS") != 0) ? PROCESS_LABELS : 0) + + ((switchPos("/ NUMBER_AFTER_LABEL") != 0) ? ADD_COLORED_LABEL_NUMBER : 0) + + ((switchPos("/ BIB_REFS") != 0) ? PROCESS_BIBREFS : 0) + + ((switchPos("/ UNDERSCORES") != 0) ? PROCESS_UNDERSCORES : 0); + processMarkup(g_fullArg[1], /* Input file */ + g_fullArg[2], /* Output file */ + (switchPos("/ CSS") != 0), + i); /* Action bits */ + continue; + } + + if (cmdMatches("VERIFY STS")) { + /* Go through all non-definition axioms, + * and check whether there is a corresponding STS scheme */ + verifySts(g_fullArg[2]); + continue; + } + + print2("?This command has not been implemented.\n"); + continue; + + } +} /* command */ + + diff --git a/mmcmdl.c b/mmcmdl.c index 212eadb5..77014fbe 100644 --- a/mmcmdl.c +++ b/mmcmdl.c @@ -1,2302 +1,2327 @@ -/*****************************************************************************/ -/* Copyright (C) 2020 NORMAN MEGILL nm at alum.mit.edu */ -/* License terms: GNU General Public License */ -/*****************************************************************************/ -/*34567890123456 (79-character line to adjust editor window) 2345678901234567*/ - -/* Command line syntax specification for Metamath */ - -#include -#include -#include -#include -#include -#include -#include "mmvstr.h" -#include "mmdata.h" -#include "mmcmdl.h" -#include "mminou.h" -#include "mmpfas.h" -#include "mmunif.h" /* For g_hentyFilter, g_userMaxUnifTrials, g_minSubstLen */ -#include "mmwtex.h" -#include "mmword.h" - -/* Global variables */ -pntrString *g_rawArgPntr = NULL_PNTRSTRING; -nmbrString *g_rawArgNmbr = NULL_NMBRSTRING; -long g_rawArgs = 0; -pntrString *g_fullArg = NULL_PNTRSTRING; -vstring g_fullArgString = ""; /* g_fullArg as one string */ -vstring g_commandPrompt = ""; -vstring g_commandLine = ""; -long g_showStatement = 0; -vstring g_logFileName = ""; -vstring g_texFileName = ""; -flag g_PFASmode = 0; /* Proof assistant mode, invoked by PROVE command */ -flag g_queryMode = 0; /* If 1, explicit questions will be asked even if - a field in the input command line is optional */ -flag g_sourceChanged = 0; /* Flag that user made some change to the source file*/ -flag g_proofChanged = 0; /* Flag that user made some change to proof in progress*/ -flag g_commandEcho = 0; /* Echo full command */ -flag g_memoryStatus = 0; /* Always show memory */ -flag g_sourceHasBeenRead = 0; /* 1 if a source file has been read in */ -vstring g_rootDirectory = ""; /* Directory prefix to use for included files */ - - - -flag processCommandLine(void) -{ - vstring defaultArg = ""; - vstring tmpStr = ""; - long i; - g_queryMode = 0; /* If 1, explicit questions will be asked even if - a field is optional */ - pntrLet(&g_fullArg, NULL_PNTRSTRING); - - if (!g_toolsMode) { - - if (!g_PFASmode) { - /* Normal mode */ - let(&tmpStr, cat("DBG|", - "HELP|READ|WRITE|PROVE|SHOW|SEARCH|SAVE|SUBMIT|OPEN|CLOSE|", - "SET|FILE|BEEP|EXIT|QUIT|ERASE|VERIFY|MARKUP|MORE|TOOLS|", - "MIDI|", - NULL)); - } else { - /* Proof assistant mode */ - let(&tmpStr, cat("DBG|", - "HELP|WRITE|SHOW|SEARCH|SAVE|SUBMIT|OPEN|CLOSE|", - "SET|FILE|BEEP|EXIT|_EXIT_PA|QUIT|VERIFY|INITIALIZE|ASSIGN|REPLACE|", - "LET|UNIFY|IMPROVE|MINIMIZE_WITH|EXPAND|MATCH|DELETE|UNDO|REDO|", - "MARKUP|MORE|TOOLS|MIDI|", - NULL)); - } - if (!getFullArg(0,tmpStr)) { - goto pclbad; - } - - if (cmdMatches("HELP")) { - if (!getFullArg(1, cat("LANGUAGE|PROOF_ASSISTANT|MM-PA|", - "BEEP|EXIT|QUIT|READ|ERASE|", - "OPEN|CLOSE|SHOW|SEARCH|SET|VERIFY|SUBMIT|SYSTEM|PROVE|FILE|WRITE|", - "MARKUP|ASSIGN|REPLACE|MATCH|UNIFY|LET|INITIALIZE|DELETE|IMPROVE|", - "MINIMIZE_WITH|EXPAND|UNDO|REDO|SAVE|DEMO|INVOKE|CLI|EXPLORE|TEX|", - "LATEX|HTML|COMMENTS|BIBLIOGRAPHY|MORE|", - "TOOLS|MIDI|$|<$>", NULL))) goto pclbad; - if (cmdMatches("HELP OPEN")) { - if (!getFullArg(2, "LOG|TEX|")) goto pclbad; - goto pclgood; - } - if (cmdMatches("HELP CLOSE")) { - if (!getFullArg(2, "LOG|TEX|")) goto pclbad; - goto pclgood; - } - if (cmdMatches("HELP SHOW")) { - if (!getFullArg(2, cat("MEMORY|SETTINGS|LABELS|SOURCE|STATEMENT|", - "PROOF|NEW_PROOF|USAGE|TRACE_BACK|ELAPSED_TIME|", - "DISCOURAGED|", - NULL))) - goto pclbad; - goto pclgood; - } - if (cmdMatches("HELP SET")) { - if (!getFullArg(2, cat( - "ECHO|SCROLL|WIDTH|HEIGHT|UNDO|UNIFICATION_TIMEOUT|", - "DISCOURAGEMENT|", - "CONTRIBUTOR|", - "ROOT_DIRECTORY|", - "EMPTY_SUBSTITUTION|SEARCH_LIMIT|JEREMY_HENTY_FILTER|", - NULL))) - goto pclbad; - goto pclgood; - } - if (cmdMatches("HELP VERIFY")) { - if (!getFullArg(2, "PROOF|MARKUP|")) - goto pclbad; - goto pclgood; - } - if (cmdMatches("HELP WRITE")) { - if (!getFullArg(2, - "SOURCE|THEOREM_LIST|BIBLIOGRAPHY|RECENT_ADDITIONS|")) - goto pclbad; - goto pclgood; - } - if (cmdMatches("HELP FILE")) { - if (!getFullArg(2, "SEARCH")) - goto pclbad; - goto pclgood; - } - if (cmdMatches("HELP SAVE")) { - if (!getFullArg(2, - "PROOF|NEW_PROOF|")) - goto pclbad; - goto pclgood; - } - goto pclgood; - } /* cmdMatches("HELP") */ - - if (cmdMatches("READ")) { - if (!getFullArg(1, "& What is the name of the source input file? ")) - goto pclbad; - /* Get any switches */ - i = 1; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, "VERIFY|")) goto pclbad; - } else { - break; - } - break; /* Break if only 1 switch is allowed */ - } /* End while for switch loop */ - goto pclgood; - } - - if (cmdMatches("WRITE")) { - if (!getFullArg(1, - "SOURCE|THEOREM_LIST|BIBLIOGRAPHY|RECENT_ADDITIONS|")) - goto pclbad; - if (cmdMatches("WRITE SOURCE")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - if (!getFullArg(2, cat( - "* What is the name of the source output file <", - g_input_fn, ">? ", NULL))) - goto pclbad; - if (!strcmp(g_input_fn, g_fullArg[2])) { - print2( - "The input file will be renamed %s~1.\n", g_input_fn); - } - - /* Get any switches */ - i = 2; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "FORMAT|REWRAP", - "|SPLIT|NO_VERSIONING|KEEP_INCLUDES|EXTRACT", - "|", NULL))) - goto pclbad; - if (lastArgMatches("EXTRACT")) { - i++; - if (!getFullArg(i, "* What statement label? ")) - goto pclbad; - } - } else { - break; - } - /* break; */ /* Break if only 1 switch is allowed */ - } /* End while for switch loop */ - - goto pclgood; - } - if (cmdMatches("WRITE THEOREM_LIST")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - /* Get any switches */ - i = 1; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "THEOREMS_PER_PAGE|SHOW_LEMMAS|HTML|ALT_HTML|NO_VERSIONING", - "|", NULL))) - goto pclbad; - if (lastArgMatches("THEOREMS_PER_PAGE")) { - i++; - if (!getFullArg(i, "# How many theorems per page <100>? ")) - goto pclbad; - } - } else { - break; - } - /* break; */ /* Break if only 1 switch is allowed */ - } - goto pclgood; - } - if (cmdMatches("WRITE BIBLIOGRAPHY")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - if (!getFullArg(2, cat( - "* What is the bibliography HTML input/output file <", - "mmbiblio.html", ">? ", NULL))) - goto pclbad; - print2( - "The old file will be renamed %s~1.\n", g_fullArg[2]); - goto pclgood; - } - if (cmdMatches("WRITE RECENT_ADDITIONS")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - if (!getFullArg(2, cat( - "* What is the Recent Additions HTML input/output file <", - "mmrecent.html", ">? ", NULL))) - goto pclbad; - print2( - "The old file will be renamed %s~1.\n", g_fullArg[2]); - - /* Get any switches */ - i = 2; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "LIMIT|HTML|ALT_HTML", - "|", NULL))) - goto pclbad; - if (lastArgMatches("LIMIT")) { - i++; - if (!getFullArg(i, "# How many most recent theorems <100>? ")) - goto pclbad; - } - } else { - break; - } - /*break;*/ /* Break if only 1 switch is allowed */ - } - goto pclgood; - } - } - - if (cmdMatches("OPEN")) { - if (!getFullArg(1, "LOG|TEX|")) goto pclbad; - if (cmdMatches("OPEN LOG")) { - if (g_logFileOpenFlag) { - printLongLine(cat( - "?Sorry, the log file \"", g_logFileName, "\" is currently open. ", - "Type CLOSE LOG to close the current log if you want to open another one." - , NULL), "", " "); - goto pclbad; - } - if (!getFullArg(2, "* What is the name of logging output file? ")) - goto pclbad; - } - if (cmdMatches("OPEN TEX")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - if (g_texFileOpenFlag) { - printLongLine(cat( - "?Sorry, the LaTeX file \"", g_texFileName, "\" is currently open. ", - "Type CLOSE TEX to close the current LaTeX file", - " if you want to open another one." - , NULL), "", " "); - goto pclbad; - } - if (!getFullArg(2, "* What is the name of LaTeX output file? ")) - goto pclbad; - - /* Get any switches */ - i = 2; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "NO_HEADER|OLD_TEX|", NULL))) - goto pclbad; - } else { - break; - } - /* break; */ /* Break if only 1 switch is allowed */ - } /* End while for switch loop */ - - } - goto pclgood; - } - - if (cmdMatches("CLOSE")) { - if (!getFullArg(1, "LOG|TEX|")) goto pclbad; - goto pclgood; - } - - if (cmdMatches("FILE")) { - if (!getFullArg(1, cat("SEARCH", NULL))) goto pclbad; - - if (cmdMatches("FILE SEARCH")) { - if (!getFullArg(2, "& What is the name of the file to search? ")) - goto pclbad; - if (!getFullArg(3, "* What is the string to search for? ")) - goto pclbad; - - - /* Get any switches */ - i = 3; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (i == 4) { - if (!getFullArg(i, cat( - "FROM_LINE|TO_LINE|", NULL))) - goto pclbad; - } else { - if (!getFullArg(i, cat( - "FROM_LINE|TO_LINE|", NULL))) - goto pclbad; - } - if (lastArgMatches("FROM_LINE")) { - i++; - if (!getFullArg(i, "# From what line number <1>? ")) - goto pclbad; - } - if (lastArgMatches("TO_LINE")) { - i++; - if (!getFullArg(i, "# To what line number <999999>? ")) - goto pclbad; - } - if (lastArgMatches("WINDOW")) { /* ???Not implemented yet */ - i++; - if (!getFullArg(i, "# How big a window around matched lines <0>? ")) - goto pclbad; - } - } else { - break; - } - /* break; */ /* Break if only 1 switch is allowed */ - } /* End while for switch loop */ - - - goto pclgood; - } /* End if (cmdMatches("FILE SEARCH")) */ - goto pclgood; - } - - if (cmdMatches("SHOW")) { - if (!g_PFASmode) { - if (!getFullArg(1, cat( - "SETTINGS|LABELS|STATEMENT|SOURCE|PROOF|MEMORY|TRACE_BACK|", - "USAGE|ELAPSED_TIME|DISCOURAGED|", NULL))) - goto pclbad; - } else { - if (!getFullArg(1, cat("NEW_PROOF|", - "SETTINGS|LABELS|STATEMENT|SOURCE|PROOF|MEMORY|TRACE_BACK|", - "USAGE|ELAPSED_TIME|DISCOURAGED|", - NULL))) - goto pclbad; - } - if (g_showStatement) { - if (g_showStatement < 1 || g_showStatement > g_statements) bug(1110); - let(&defaultArg, cat(" <",g_Statement[g_showStatement].labelName, ">", - NULL)); - } else { - let(&defaultArg, ""); - } - - - if (cmdMatches("SHOW TRACE_BACK")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - if (!getFullArg(2, - cat("* What is the statement label", defaultArg, "? ", NULL))) - goto pclbad; - - /* Get any switches */ - i = 2; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "ALL|ESSENTIAL|AXIOMS|TREE|DEPTH|COUNT_STEPS|MATCH|TO", - "|", NULL))) - goto pclbad; - if (lastArgMatches("DEPTH")) { - i++; - if (!getFullArg(i, "# How many indentation levels <999>? ")) - goto pclbad; - } - if (lastArgMatches("MATCH")) { - i++; - if (!getFullArg(i, "* What statement label? ")) - goto pclbad; - } - if (lastArgMatches("TO")) { - i++; - if (!getFullArg(i, "* What statement label? ")) - goto pclbad; - } - } else { - break; - } - /* break; */ /* Break if only 1 switch is allowed */ - } - - goto pclgood; - } /* End if (cmdMatches("SHOW TRACE_BACK")) */ - - if (cmdMatches("SHOW USAGE")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - if (!getFullArg(2, - cat("* What is the statement label", defaultArg, "? ", NULL))) - goto pclbad; - - /* Get any switches */ - i = 2; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "DIRECT|RECURSIVE|ALL", - "|", NULL))) - goto pclbad; - } else { - break; - } - /* break; */ /* Break if only 1 switch is allowed */ - } - - goto pclgood; - } /* End if (cmdMatches("SHOW USAGE")) */ - - - if (cmdMatches("SHOW LABELS")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - if (!getFullArg(2, - "* What are the labels to match (* = wildcard) <*>?")) - goto pclbad; - /* Get any switches */ - i = 2; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat("ALL|LINEAR|", NULL))) - goto pclbad; - } else { - break; - } - /*break;*/ /* Break if only 1 switch is allowed */ - } - goto pclgood; - } - if (cmdMatches("SHOW STATEMENT")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - if (!getFullArg(2, - cat("* What is the statement label", defaultArg, "? ", NULL))) - goto pclbad; - /* Get any switches */ - i = 2; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "FULL|COMMENT|TEX|OLD_TEX|HTML|ALT_HTML|TIME|BRIEF_HTML", - "|BRIEF_ALT_HTML|MNEMONICS|NO_VERSIONING|", NULL))) - goto pclbad; - } else { - break; - } - /* break; */ /* Break if only 1 switch is allowed */ - } - goto pclgood; - } - if (cmdMatches("SHOW SOURCE")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - if (!getFullArg(2, - cat("* What is the statement label", defaultArg, "? ", NULL))) { - goto pclbad; - } - goto pclgood; - } - - - if (cmdMatches("SHOW PROOF")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - if (!getFullArg(2, - cat("* What is the statement label", defaultArg, "? ", NULL))) - goto pclbad; - - /* Get any switches */ - i = 2; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "ESSENTIAL|ALL|UNKNOWN|FROM_STEP|TO_STEP|DEPTH", - "|REVERSE|VERBOSE|NORMAL|PACKED|COMPRESSED|EXPLICIT", - "|FAST|OLD_COMPRESSION", - "|STATEMENT_SUMMARY|DETAILED_STEP|TEX|OLD_TEX|HTML", - "|LEMMON|START_COLUMN|NO_REPEATED_STEPS", - "|RENUMBER|SIZE|", NULL))) - goto pclbad; - if (lastArgMatches("FROM_STEP")) { - i++; - if (!getFullArg(i, "# From what step <1>? ")) - goto pclbad; - } - if (lastArgMatches("TO_STEP")) { - i++; - if (!getFullArg(i, "# To what step <9999>? ")) - goto pclbad; - } - if (lastArgMatches("DEPTH")) { - i++; - if (!getFullArg(i, "# How many indentation levels <999>? ")) - goto pclbad; - } - if (lastArgMatches("DETAILED_STEP")) { - i++; - if (!getFullArg(i, "# Display details of what step <1>? ")) - goto pclbad; - } - if (lastArgMatches("START_COLUMN")) { - i++; - if (!getFullArg(i, cat( - "# At what column should the formula start <", - str((double)DEFAULT_COLUMN), ">? ", NULL))) - goto pclbad; - } - } else { - break; - } - /* break; */ /* Break if only 1 switch is allowed */ - } - goto pclgood; - } /* End if (cmdMatches("SHOW PROOF")) */ - - - if (cmdMatches("SHOW NEW_PROOF")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - - /* Get any switches */ - i = 1; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "ESSENTIAL|ALL|UNKNOWN|FROM_STEP|TO_STEP|DEPTH", - "|REVERSE|VERBOSE|NORMAL|PACKED|COMPRESSED|EXPLICIT", - "|OLD_COMPRESSION", - "|NOT_UNIFIED|TEX|HTML", - "|LEMMON|START_COLUMN|NO_REPEATED_STEPS", - "|RENUMBER|", NULL))) - goto pclbad; - if (lastArgMatches("FROM_STEP")) { - i++; - if (!getFullArg(i, "# From what step <1>? ")) - goto pclbad; - } - if (lastArgMatches("TO_STEP")) { - i++; - if (!getFullArg(i, "# To what step <9999>? ")) - goto pclbad; - } - if (lastArgMatches("DEPTH")) { - i++; - if (!getFullArg(i, "# How many indentation levels <999>? ")) - goto pclbad; - } - if (lastArgMatches("START_COLUMN")) { - i++; - if (!getFullArg(i, cat( - "# At what column should the formula start <", - str((double)DEFAULT_COLUMN), ">? ", NULL))) - goto pclbad; - } - } else { - break; - } - /* break; */ /* Break if only 1 switch is allowed */ - } - goto pclgood; - } /* End if (cmdMatches("SHOW NEW_PROOF")) */ - - - goto pclgood; - } /* End of SHOW */ - - if (cmdMatches("SEARCH")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - if (!getFullArg(1, - "* What are the labels to match (* = wildcard) <*>?")) - goto pclbad; - if (!getFullArg(2, "* Search for what math symbol string? ")) - goto pclbad; - /* Get any switches */ - i = 2; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat("ALL|COMMENTS|JOIN|", NULL))) - goto pclbad; - } else { - break; - } - /*break;*/ /* Break if only 1 switch is allowed */ - } - goto pclgood; - - } /* End of SEARCH */ - - - if (cmdMatches("SAVE")) { - if (!g_PFASmode) { - if (!getFullArg(1, - "PROOF|")) - goto pclbad; - } else { - if (!getFullArg(1, cat("NEW_PROOF|", - "PROOF|", - NULL))) - goto pclbad; - } - if (g_showStatement) { - if (g_showStatement < 0) bug(1111); - let(&defaultArg, cat(" <",g_Statement[g_showStatement].labelName, ">", NULL)); - } else { - let(&defaultArg, ""); - } - - - if (cmdMatches("SAVE PROOF")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - if (!getFullArg(2, - cat("* What is the statement label", defaultArg, "? ", NULL))) - goto pclbad; - - /* Get any switches */ - i = 2; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "NORMAL|PACKED|COMPRESSED|EXPLICIT", - "|FAST|OLD_COMPRESSION", - "|TIME|", NULL))) - goto pclbad; - } else { - break; - } - /* break; */ /* Break if only 1 switch is allowed */ - } - goto pclgood; - } /* End if (cmdMatches("SAVE PROOF")) */ - - - if (cmdMatches("SAVE NEW_PROOF")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - - /* Get any switches */ - i = 1; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "NORMAL|PACKED|COMPRESSED|EXPLICIT", - "|OLD_COMPRESSION|OVERRIDE", - "|", NULL))) - goto pclbad; - } else { - break; - } - /*break;*/ /* Break if only 1 switch is allowed */ - } - goto pclgood; - } /* End if (cmdMatches("SAVE NEW_PROOF")) */ - - - goto pclgood; - } /* End of SAVE */ - - - if (cmdMatches("PROVE")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - if (!g_proveStatement) g_proveStatement = g_showStatement; - if (g_proveStatement) { - let(&defaultArg, cat(" <",g_Statement[g_proveStatement].labelName, ">", NULL)); - } else { - let(&defaultArg, ""); - } - if (!getFullArg(1, - cat("* What is the label of the statement you want to try proving", - defaultArg, "? ", NULL))) - goto pclbad; - - /* Get any switches */ - i = 1; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, "OVERRIDE|")) goto pclbad; - } else { - break; - } - break; /* Break if only 1 switch is allowed */ - } /* End while for switch loop */ - - goto pclgood; - } - - /* Commands in Proof Assistant mode */ - - if (cmdMatches("MATCH")) { - if (!getFullArg(1, - "STEP|ALL|")) goto pclbad; - if (cmdMatches("MATCH STEP")) { - if (!getFullArg(2, "# What step number? ")) goto pclbad; - /* Get any switches */ - i = 2; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "MAX_ESSENTIAL_HYP|", NULL))) - goto pclbad; - if (lastArgMatches("MAX_ESSENTIAL_HYP")) { - i++; - if (!getFullArg(i, - "# Maximum number of essential hypotheses to allow for a match <0>? ")) - goto pclbad; - } - } else { - break; - } - break; /* Break if only 1 switch is allowed */ - } - goto pclgood; - } - if (cmdMatches("MATCH ALL")) { - /* Get any switches */ - i = 1; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "ESSENTIAL|MAX_ESSENTIAL_HYP|", NULL))) - goto pclbad; - if (lastArgMatches("MAX_ESSENTIAL_HYP")) { - i++; - if (!getFullArg(i, - "# Maximum number of essential hypotheses to allow for a match <0>? ")) - goto pclbad; - } - } else { - break; - } - /*break;*/ /* Break if only 1 switch is allowed */ - } - goto pclgood; - } /* End if (cmdMatches("MATCH ALL")) */ - goto pclgood; - } - - if (cmdMatches("INITIALIZE")) { - if (!getFullArg(1, - "STEP|ALL|USER|")) goto pclbad; - if (cmdMatches("INITIALIZE STEP")) { - if (!getFullArg(2, "# What step number? ")) goto pclbad; - } - goto pclgood; - } - - if (cmdMatches("IMPROVE")) { - if (!getFullArg(1, - "* What step number, or FIRST, or LAST, or ALL ? ")) goto pclbad; - /* Get any switches */ - i = 1; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, "DEPTH|NO_DISTINCT|1|2|3" - "|SUBPROOFS|OVERRIDE|INCLUDE_MATHBOXES|")) goto pclbad; - if (lastArgMatches("DEPTH")) { - i++; - if (!getFullArg(i, "# What is maximum depth for " - "searching statements with $e hypotheses <0>? ")) goto pclbad; - } - } else { - break; - } - /*break;*/ /* Do this if only 1 switch is allowed */ - } /* end while */ - goto pclgood; - } /* end if IMPROVE */ - - - if (cmdMatches("MINIMIZE_WITH")) { - if (!getFullArg(1, "* What statement label? ")) goto pclbad; - /* Get any switches */ - i = 1; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "VERBOSE|MAY_GROW|EXCEPT|OVERRIDE|INCLUDE_MATHBOXES|", - "ALLOW_NEW_AXIOMS|NO_NEW_AXIOMS_FROM|FORBID|TIME|", - NULL))) - goto pclbad; - - if (lastArgMatches("EXCEPT")) { - i++; - if (!getFullArg(i, "* What statement label match pattern? ")) - goto pclbad; - } - if (lastArgMatches("ALLOW_NEW_AXIOMS")) { - i++; - if (!getFullArg(i, "* What statement label match pattern? ")) - goto pclbad; - } - if (lastArgMatches("NO_NEW_AXIOMS_FROM")) { - i++; - if (!getFullArg(i, "* What statement label match pattern? ")) - goto pclbad; - } - if (lastArgMatches("FORBID")) { - i++; - if (!getFullArg(i, "* What statement label match pattern? ")) - goto pclbad; - } - } else { - break; - } - /*break;*/ /* Break if only 1 switch is allowed */ - } - goto pclgood; - } /* end of MINIMIZE_WITH */ - - if (cmdMatches("EXPAND")) { - if (!getFullArg(1, "* What statement label? ")) goto pclbad; - goto pclgood; - } - - if (cmdMatches("UNIFY")) { - if (!getFullArg(1, - "STEP|ALL|")) goto pclbad; - if (cmdMatches("UNIFY STEP")) { - if (!getFullArg(2, "# What step number? ")) goto pclbad; - goto pclgood; - } - if (cmdMatches("UNIFY ALL")) { - /* Get any switches */ - i = 1; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "INTERACTIVE|", NULL))) - goto pclbad; - } else { - break; - } - break; /* Break if only 1 switch is allowed */ - } - goto pclgood; - } /* End if (cmdMatches("UNIFY ALL")) */ - } - - if (cmdMatches("DELETE")) { - if (!getFullArg(1, - "STEP|ALL|FLOATING_HYPOTHESES|")) goto pclbad; - if (lastArgMatches("STEP")) { - if (!getFullArg(2, "# What step number? ")) goto pclbad; - goto pclgood; - } - goto pclgood; - } - - /*???OBSOLETE???*/ - if (cmdMatches("ADD")) { - if (!getFullArg(1, - "UNIVERSE|")) goto pclbad; - /* Note: further parsing below */ - } - - if (cmdMatches("REPLACE")) { - if (!getFullArg(1, "* What step number, or FIRST, or LAST ? ")) - goto pclbad; - if (!getFullArg(2, "* With what statement label? ")) goto pclbad; - /* Get any switches */ - i = 2; - - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "OVERRIDE|", NULL))) - goto pclbad; - } else { - break; - } - break; /* Break if only 1 switch is allowed */ - } - - goto pclgood; - } - - if (cmdMatches("LET")) { - if (!getFullArg(1, "STEP|VARIABLE|")) goto pclbad; - if (cmdMatches("LET STEP")) { - if (!getFullArg(2, "* What step number, or FIRST, or LAST ? ")) - goto pclbad; - } - if (cmdMatches("LET VARIABLE")) { - if (!getFullArg(2, "* Assign what variable (format $nn)? ")) goto pclbad; - } - if (!getFullArg(3, "=|<=>")) goto pclbad; - if (!getFullArg(4, "* With what math symbol string? ")) - goto pclbad; - goto pclgood; - } - - if (cmdMatches("ASSIGN")) { - if (!getFullArg(1, "* What step number, or FIRST, or LAST ? ")) goto pclbad; - if (!getFullArg(2, "* With what statement label? ")) goto pclbad; - /* Get any switches */ - i = 2; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, "NO_UNIFY|OVERRIDE|")) goto pclbad; - } else { - break; - } - /*break;*/ /* Break if only 1 switch is allowed */ - } - goto pclgood; - } - - if (cmdMatches("UNDO")) { - goto pclgood; - } - - if (cmdMatches("REDO")) { - goto pclgood; - } - - if (cmdMatches("SET")) { - let(&tmpStr, cat( - "WIDTH|HEIGHT|UNDO|ECHO|SCROLL|", - "DEBUG|MEMORY_STATUS|SEARCH_LIMIT|UNIFICATION_TIMEOUT|", - "DISCOURAGEMENT|", - "CONTRIBUTOR|", - "ROOT_DIRECTORY|", - "EMPTY_SUBSTITUTION|JEREMY_HENTY_FILTER|", NULL)); - if (!getFullArg(1,tmpStr)) goto pclbad; - if (cmdMatches("SET DEBUG")) { - if (!getFullArg(2, "FLAG|OFF|")) goto pclbad; - if (lastArgMatches("FLAG")) { - if (!getFullArg(3, "4|5|6|7|8|9|<5>")) goto pclbad; - } - goto pclgood; - } - - if (cmdMatches("SET ECHO")) { - if (g_commandEcho) { - if (!getFullArg(2, "ON|OFF|")) goto pclbad; - } else { - if (!getFullArg(2, "ON|OFF|")) goto pclbad; - } - goto pclgood; - } - - if (cmdMatches("SET SCROLL")) { - if (g_scrollMode == 1) { - if (!getFullArg(2, "CONTINUOUS|PROMPTED|")) goto pclbad; - } else { - if (!getFullArg(2, "CONTINUOUS|PROMPTED|")) goto pclbad; - } - goto pclgood; - } - - if (cmdMatches("SET DISCOURAGEMENT")) { - if (g_globalDiscouragement) { - if (!getFullArg(2, "ON|OFF|")) goto pclbad; - } else { - if (!getFullArg(2, "ON|OFF|")) goto pclbad; - } - goto pclgood; - } - - if (cmdMatches("SET MEMORY_STATUS")) { - if (g_memoryStatus) { - if (!getFullArg(2, "ON|OFF|")) goto pclbad; - } else { - if (!getFullArg(2, "ON|OFF|")) goto pclbad; - } - goto pclgood; - } - - - if (cmdMatches("SET JEREMY_HENTY_FILTER")) { - if (g_hentyFilter) { - if (!getFullArg(2, "ON|OFF|")) goto pclbad; - } else { - if (!getFullArg(2, "ON|OFF|")) goto pclbad; - } - goto pclgood; - } - - if (cmdMatches("SET CONTRIBUTOR")) { - if (!getFullArg(2, cat( - "* What is the contributor name for SAVE (NEW_)PROOF <", - g_contributorName, ">? ", NULL))) - goto pclbad; - goto pclgood; - } - - if (cmdMatches("SET ROOT_DIRECTORY")) { - if (!getFullArg(2, cat( - "* What is the root directory path (use space if none) <", - g_rootDirectory, ">? ", NULL))) - goto pclbad; - goto pclgood; - } - - if (cmdMatches("SET SEARCH_LIMIT")) { - if (!getFullArg(2, cat( - "# What is search limit for IMPROVE command <", - str((double)g_userMaxProveFloat), ">? ", NULL))) - goto pclbad; - goto pclgood; - } - - if (cmdMatches("SET UNIFICATION_TIMEOUT")) { - if (!getFullArg(2, cat( - "# What is maximum number of unification trials <", - str((double)g_userMaxUnifTrials), ">? ", NULL))) - goto pclbad; - goto pclgood; - } - - if (cmdMatches("SET WIDTH")) { - if (!getFullArg(2, cat( - "# What is maximum line length on your screen <", - str((double)g_screenHeight), ">? ", NULL))) - goto pclbad; - goto pclgood; - } - - if (cmdMatches("SET HEIGHT")) { - if (!getFullArg(2, cat( - "# What is number of lines your screen displays <", - str((double)g_screenHeight), ">? ", NULL))) - goto pclbad; - goto pclgood; - } - - if (cmdMatches("SET UNDO")) { - if (!getFullArg(2, cat( - "# What is the maximum number of UNDOs <", - str((double)(processUndoStack(NULL, PUS_GET_SIZE, "", 0))), - ">? ", NULL))) - goto pclbad; - goto pclgood; - } - - if (cmdMatches("SET EMPTY_SUBSTITUTION")) { - if (g_minSubstLen == 0) { - if (!getFullArg(2, "ON|OFF|")) goto pclbad; - } else { - if (!getFullArg(2, "ON|OFF|")) goto pclbad; - } - goto pclgood; - } - - } /* end if SET */ - - if (cmdMatches("ERASE")) { - goto pclgood; - } - - if (cmdMatches("MORE")) { - if (!getFullArg(1, - "* What is the name of the file to display? ")) - goto pclbad; - goto pclgood; - } - - if (cmdMatches("TOOLS")) { - goto pclgood; - } - - if (cmdMatches("VERIFY")) { - if (!getFullArg(1, - "PROOF|MARKUP|")) - goto pclbad; - if (cmdMatches("VERIFY PROOF")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - if (!getFullArg(2, - "* What are the labels to match (* = wildcard) <*>?")) - goto pclbad; - - /* Get any switches */ - i = 2; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "SYNTAX_ONLY", - "|", NULL))) - goto pclbad; - } else { - break; - } - break; /* Break if only 1 switch is allowed */ - } - - goto pclgood; - } - - if (cmdMatches("VERIFY MARKUP")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - if (!getFullArg(2, - "* What are the labels to match (* = wildcard) <*>?")) - goto pclbad; - - /* Get any switches */ - i = 2; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "DATE_SKIP|FILE_SKIP|TOP_DATE_SKIP|VERBOSE", - "|FILE_CHECK|TOP_DATE_CHECK", - "|UNDERSCORE_SKIP|MATHBOX_SKIP|", NULL))) - goto pclbad; - } else { - break; - } - /* break; */ /* Break if only 1 switch is allowed */ - } - - goto pclgood; - } - } - - if (cmdMatches("DBG")) { - /* The debug command fetches an arbitrary 2nd arg in quotes, to be handled - in whatever way is needed for debugging. */ - if (!getFullArg(1, "* What is the debugging string? ")) - goto pclbad; - goto pclgood; - } - - if (cmdMatches("MARKUP")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - if (!getFullArg(1, - "* What is the name of the input file with markup? ")) - goto pclbad; - if (!getFullArg(2, - "* What is the name of the HTML output file? ")) - goto pclbad; - - /* Get any switches */ - i = 2; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "HTML|ALT_HTML|SYMBOLS|LABELS|NUMBER_AFTER_LABEL|BIB_REFS", - "|UNDERSCORES|CSS|", NULL))) - goto pclbad; - } else { - break; - } - /*break;*/ /* Break if only 1 switch is allowed */ - } - goto pclgood; - } - - if (cmdMatches("MIDI")) { - if (g_sourceHasBeenRead == 0) { - print2("?No source file has been read in. Use READ first.\n"); - goto pclbad; - } - if (!getFullArg(1, - "* Statement label to create MIDI for (* matches any substring) <*>?")) - goto pclbad; - /* Get any switches */ - i = 1; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat("PARAMETER|", NULL))) - goto pclbad; - i++; - if (!getFullArg(i, - "* What is the parameter string ?")) - goto pclbad; - } else { - break; - } - break; /* Break if only 1 switch is allowed */ - } - goto pclgood; - } - - if (cmdMatches("EXIT") || cmdMatches("QUIT") || cmdMatches("_EXIT_PA")) { - - /* Get any switches */ - i = 0; - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "FORCE|", NULL))) - goto pclbad; - } else { - break; - } - break; /* Break if only 1 switch is allowed */ - } /* End while for switch loop */ - - goto pclgood; - } - - } else { /* g_toolsMode */ - /* Text tools mode */ - let(&tmpStr, cat( - "HELP|SUBMIT|", - "ADD|DELETE|SUBSTITUTE|S|SWAP|CLEAN|INSERT|BREAK|BUILD|MATCH|SORT|", - "UNDUPLICATE|DUPLICATE|UNIQUE|REVERSE|RIGHT|PARALLEL|NUMBER|COUNT|", - "COPY|C|TYPE|T|TAG|UPDATE|BEEP|B|EXIT|QUIT|", NULL)); - if (!getFullArg(0,tmpStr)) - goto pclbad; - - if (cmdMatches("HELP")) { - if (!getFullArg(1, cat( - "ADD|DELETE|SUBSTITUTE|S|SWAP|CLEAN|INSERT|BREAK|BUILD|MATCH|SORT|", - "UNDUPLICATE|DUPLICATE|UNIQUE|REVERSE|RIGHT|PARALLEL|NUMBER|COUNT|", - "TYPE|T|TAG|UPDATE|BEEP|B|EXIT|QUIT|", - "COPY|C|SUBMIT|SYSTEM|CLI|", - "$|<$>", NULL))) goto pclbad; - goto pclgood; - } - if (cmdMatches("ADD") || cmdMatches("TAG")) { - if (!getFullArg(1, "& Input/output file? ")) - goto pclbad; - if (!getFullArg(2, "* String to add to beginning of each line <>? ")) - goto pclbad; - if (!getFullArg(3, "* String to add to end of each line <>? ")) - goto pclbad; - if (cmdMatches("TAG")) { - if (!getFullArg(4, - "* String to match to start range (null = any line) <>? ")) - goto pclbad; - if (!getFullArg(5, - "# Which occurrence of start match to start range <1>? ")) - goto pclbad; - if (!getFullArg(6, - "* String to match to end range (null = any line) <>? ")) - goto pclbad; - if (!getFullArg(7, - "# Which occurrence of end match to end range <1>? ")) - goto pclbad; - } - goto pclgood; - } - if (cmdMatches("DELETE")) { - if (!getFullArg(1, "& Input/output file? ")) - goto pclbad; - if (!getFullArg(2, -"* String from which to start deleting (CR = beginning of line) <>? ")) - goto pclbad; - if (!getFullArg(3, -"* String at which to stop deleting (CR = end of line) <>? ")) - goto pclbad; - goto pclgood; - } - if (cmdMatches("CLEAN")) { - if (!getFullArg(1, "& Input/output file? ")) - goto pclbad; - if (!getFullArg(2, - "* Subcommand(s) (D,B,E,R,Q,T,U,P,G,C,L,V) ? ")) - goto pclbad; - goto pclgood; - } - if (cmdMatches("SWAP")) { - if (!getFullArg(1, "& Input/output file? ")) - goto pclbad; - if (!getFullArg(2, -"* Character string to match between the halves to be swapped? ")) - goto pclbad; - goto pclgood; - } - if (cmdMatches("SUBSTITUTE") || cmdMatches("S")) { - if (!getFullArg(1, "& Input/output file? ")) - goto pclbad; - if (!getFullArg(2, "* String to replace? ")) - goto pclbad; - if (!getFullArg(3, "* Replace it with <>? ")) - goto pclbad; - if (!getFullArg(4, -"* Which occurrence in the line (1,2,... or ALL or EACH) <1>? ")) - goto pclbad; - if (!getFullArg(5, -"* Additional match required on line (null = match all) <>? ")) - goto pclbad; - goto pclgood; - } - - if (cmdMatches("INSERT")) { - if (!getFullArg(1, "& Input/output file? ")) - goto pclbad; - if (!getFullArg(2, "* String to insert in each line ? ")) - goto pclbad; - if (!getFullArg(3, "# Column at which to insert the string <1>? ")) - goto pclbad; - goto pclgood; - } - if (cmdMatches("BREAK")) { - if (!getFullArg(1, "& Input/output file? ")) - goto pclbad; - if (!getFullArg(2, - "* Special characters to use as token delimiters <()[],=:;{}>? ")) - goto pclbad; - goto pclgood; - } - if (cmdMatches("MATCH")) { - if (!getFullArg(1, "& Input/output file? ")) - goto pclbad; - if (!getFullArg(2, -"* String to match on each line (null = any non-blank line) <>? ")) - goto pclbad; - if (!getFullArg(3, -"* Output those lines containing the string (Y) or those not (N) ? ")) - goto pclbad; - goto pclgood; - } - if (cmdMatches("SORT")) { - if (!getFullArg(1, "& Input/output file? ")) - goto pclbad; - if (!getFullArg(2, - "* String to start key on each line (null string = column 1) <>? ")) - goto pclbad; - goto pclgood; - } - if (cmdMatches("UNDUPLICATE") || cmdMatches("DUPLICATE") || - cmdMatches("UNIQUE") || cmdMatches("REVERSE") || cmdMatches("BUILD") - || cmdMatches("RIGHT")) { - if (!getFullArg(1, "& Input/output file? ")) - goto pclbad; - goto pclgood; - } - - if (cmdMatches("COUNT")) { - if (!getFullArg(1, "& Input file? ")) - goto pclbad; - if (!getFullArg(2, -"* String to count <;>? ")) - goto pclbad; - goto pclgood; - } - - if (cmdMatches("COPY") || cmdMatches("C")) { - if (!getFullArg(1, "* Comma-separated list of input files? ")) - goto pclbad; - if (!getFullArg(2, "* Output file? ")) - goto pclbad; - goto pclgood; - } - - - if (cmdMatches("NUMBER")) { - if (!getFullArg(1, "* Output file ? ")) - goto pclbad; - if (!getFullArg(2, "# First number <1>? ")) - goto pclbad; - if (!getFullArg(3, "# Last number <10>? ")) - goto pclbad; - if (!getFullArg(4, "# Increment <1>? ")) - goto pclbad; - goto pclgood; - } - if (cmdMatches("TYPE") || cmdMatches("T")) { - if (!getFullArg(1, "& File to display on the screen? ")) - goto pclbad; - if (!getFullArg(2, "* Num. lines to type or ALL (nothing = 10) <$>? ")) - goto pclbad; - goto pclgood; - } - - - if (cmdMatches("UPDATE")) { - print2( -"Warning: Do not comment out code - delete it before running UPDATE! If\n"); - print2( -"rerunning UPDATE, do not tamper with \"start/end of deleted section\" comments!\n"); - print2( -"Edit out tag on header comment line! Review the output file!\n"); - if (!getFullArg(1, "& Original (reference) program input file? ")) - goto pclbad; - if (!getFullArg(2, "& Edited program input file? ")) - goto pclbad; - if (!getFullArg(3, cat( -"* Edited program output file with revisions tagged <", - g_fullArg[2], ">? ", NULL))) - goto pclbad; - if (!strcmp(g_fullArg[2], g_fullArg[3])) { - print2( -"The input file will be renamed %s~1.\n", g_fullArg[2]); - } - if (!getFullArg(4, - cat("* Revision tag for added lines ? ", NULL))) - goto pclbad; - if (!getFullArg(5, -"# Successive lines required for match (more = better sync) <3>? ")) - goto pclbad; - goto pclgood; - } - - if (cmdMatches("PARALLEL")) { - if (!getFullArg(1, "& Left file? ")) - goto pclbad; - if (!getFullArg(2, "& Right file? ")) - goto pclbad; - if (!getFullArg(3, cat("* Output file <", - g_fullArg[1], ">? ", NULL))) - goto pclbad; - if (!getFullArg(4, - cat("* String to insert between the 2 input lines <>? ", NULL))) - goto pclbad; - goto pclgood; - } - - /* g_toolsMode - no qualifiers for EXIT */ - if (cmdMatches("EXIT") || cmdMatches("QUIT")) { - goto pclgood; - } - - - } /* if !g_toolsMode ... else ... */ - - if (cmdMatches("SUBMIT")) { - if (g_toolsMode) { - let(&tmpStr, " "); - } else { - let(&tmpStr, " "); - } - if (!getFullArg(1, cat("& What is the name of command file to run", - tmpStr, "? ", NULL))) { - goto pclbad; - } - - /* Get any switches */ - i = 1; /* Number of command words before switch */ - while (1) { - i++; - if (!getFullArg(i, "/|$|<$>")) goto pclbad; - if (lastArgMatches("/")) { - i++; - if (!getFullArg(i, cat( - "SILENT", - "|", NULL))) - goto pclbad; - } else { - break; - } - break; /* Break if only 1 switch is allowed */ - } /* End while for switch loop */ - - goto pclgood; - } - - if (cmdMatches("BEEP") || cmdMatches("B")) { - goto pclgood; - } - - /* Command in master list but not intercepted -- really a bug */ - print2("?This command has not been implemented yet.\n"); - print2("(This is really a bug--please report it.)\n"); - goto pclbad; - - /* Should never get here */ - - - - pclgood: - - /* Strip off the last g_fullArg if a null argument was added by getFullArg - in the case when "$" (nothing) is allowed */ - if (!strcmp(g_fullArg[pntrLen(g_fullArg) - 1], chr(3))) { - let((vstring *)(&g_fullArg[pntrLen(g_fullArg) - 1]), ""); /* Deallocate */ - pntrLet(&g_fullArg, pntrLeft(g_fullArg, pntrLen(g_fullArg) - 1)); - } - - if (pntrLen(g_fullArg) > g_rawArgs) bug(1102); - if (pntrLen(g_fullArg) < g_rawArgs) { - let(&tmpStr, cat("?Too many arguments. Use quotes around arguments with special", - " characters and around Unix file names with \"/\"s.", NULL)); - printCommandError(cat(g_commandPrompt, g_commandLine, NULL), pntrLen(g_fullArg), - tmpStr); - goto pclbad; - } - - /* Create a single string containing the g_fullArg tokens */ - let(&g_fullArgString, ""); - for (i = 0; i < pntrLen(g_fullArg); i++) { - let(&g_fullArgString, cat(g_fullArgString, " ", g_fullArg[i], NULL)); - } - let(&g_fullArgString, right(g_fullArgString, 2)); /* Strip leading space */ - - - /* Deallocate memory */ - let(&defaultArg, ""); - let(&tmpStr, ""); - return (1); - - pclbad: - /* Deallocate memory */ - let(&defaultArg, ""); - let(&tmpStr, ""); - return (0); - -} /* processCommandLine */ - - - -flag getFullArg(long arg, vstring cmdList1) -{ - /* This function converts the user's abbreviated keyword in - g_rawArgPntr[arg] to a full, upper-case keyword, - in g_fullArg[arg], matching - the available choices in cmdList. */ - /* Special cases: cmdList = "# xxx ?" - get an integer */ - /* cmdList = "* xxx ?" - get any string; - don't convert to upper case - cmdList = "& xxx ?" - same as * except - verify it is a file that exists */ - /* "$" means a null argument is acceptable; put it in as - special character chr(3) so it can be recognized */ - - pntrString *possCmd = NULL_PNTRSTRING; - long possCmds, i, j, k, m, p, q; - vstring defaultCmd = ""; - vstring infoStr = ""; - vstring tmpStr = ""; - vstring tmpArg = ""; - vstring errorLine = ""; - vstring keyword = ""; - vstring cmdList = ""; - FILE *tmpFp; - - let(&cmdList,cmdList1); /* In case cmdList1 gets deallocated when it comes - directly from a vstring function such as cat() */ - - let(&errorLine, cat(g_commandPrompt,g_commandLine, NULL)); - - /* Handle special case - integer expected */ - if (cmdList[0] == '#') { - let(&defaultCmd, - seg(cmdList,instr(1,cmdList, "<"),instr(1,cmdList, ">"))); - - /* If the argument has not been entered, prompt the user for it */ - if (g_rawArgs <= arg) { - pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); - nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, 0)); - g_rawArgs++; - if (g_rawArgs <= arg) bug(1103); - - g_queryMode = 1; - tmpArg = cmdInput1(right(cmdList,3)); - let(&errorLine,right(cmdList,3)); - if (tmpArg[0] == 0) { /* Use default argument */ - let(&tmpArg, seg(defaultCmd,2,len(defaultCmd) - 1)); - } - let((vstring *)(&g_rawArgPntr[arg]), tmpArg); - g_rawArgNmbr[arg] = len(cmdList) - 1;/* Line position for error msgs */ - - } /* End of asking user for additional argument */ - - /* Make sure that the argument is a non-negative integer */ - let(&tmpArg,g_rawArgPntr[arg]); - if (tmpArg[0] == 0) { /* Use default argument */ - /* (This code is needed in case of null string passed directly) */ - let(&tmpArg, seg(defaultCmd,2,len(defaultCmd) - 1)); - } - let(&tmpStr, str(val(tmpArg))); - let(&tmpStr, cat(string(len(tmpArg)-len(tmpStr),'0'), tmpStr, NULL)); - if (strcmp(tmpStr, tmpArg)) { - printCommandError(errorLine, arg, - "?A number was expected here."); - goto return0; - } - - let(&keyword, str(val(tmpArg))); - goto return1; - } - - - - /* Handle special case - any arbitrary string is OK */ - /* '*' means any string, '&' means a file */ - /* However, "|$<$>" also allows null string (no argument) */ - if (cmdList[0] == '*' || cmdList[0] == '&') { - let(&defaultCmd, - seg(cmdList,instr(1,cmdList, "<"),instr(1,cmdList, ">"))); - - /* If the argument has not been entered, prompt the user for it */ - if (g_rawArgs <= arg) { - if (!strcmp(defaultCmd, "<$>")) { /* End of command acceptable */ - /* Note: in this case, user will never be prompted for anything. */ - let(&keyword,chr(3)); - goto return1; - } - g_rawArgs++; - pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); - nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, 0)); - if (g_rawArgs <= arg) bug(1104); - g_queryMode = 1; - tmpArg = cmdInput1(right(cmdList,3)); - - /* Strip off any quotes around it - and tolerate lack of trailing quote */ - /******* (This is no longer done - it is confusing to the user.) - if (tmpArg[0] == '\'' || tmpArg[0] == '\"') { - if (tmpArg[0] == tmpArg[len(tmpArg) - 1]) { - let(&tmpArg, right(left(tmpArg, len(tmpArg) - 1), 2)); - } else { - let(&tmpArg, right(tmpArg, 2)); - } - } - *******/ - - let(&errorLine,right(cmdList,3)); - if (tmpArg[0] == 0) { /* Use default argument */ - let(&tmpArg, seg(defaultCmd,2,len(defaultCmd) - 1)); - } - let((vstring *)(&g_rawArgPntr[arg]), tmpArg); - g_rawArgNmbr[arg] = len(cmdList) - 1; /* Line position for error msgs */ - - } /* End of asking user for additional argument */ - - let(&keyword,g_rawArgPntr[arg]); - - /* Convert abbreviations of FIRST, LAST, ALL to - full keywords. The rest of the program works fine without doing this, - but it provides better cosmetic appearance when the command is echoed - such as in during the UNDO command. */ - if (cmdList[0] == '*') { - if ((keyword[0] == 'f' || keyword[0] == 'F') - && instr(1, cmdList, " FIRST") != 0) - let(&keyword, "FIRST"); - if ((keyword[0] == 'l' || keyword[0] == 'L') - && instr(1, cmdList, " LAST") != 0) - let(&keyword, "LAST"); - if ((keyword[0] == 'a' || keyword[0] == 'A') - && instr(1, cmdList, " ALL") != 0) - let(&keyword, "ALL"); - } - - if (keyword[0] == 0) { /* Use default argument */ - /* This case handles blank arguments on completely input command line */ - let(&keyword, seg(defaultCmd,2,len(defaultCmd) - 1)); - } - if (cmdList[0] == '&') { - /* See if file exists */ - let(&tmpStr, cat(g_rootDirectory, keyword, NULL)); - tmpFp = fopen(tmpStr, "r"); - if (!tmpFp) { - let(&tmpStr, cat("?Sorry, couldn't open the file \"", tmpStr, "\".", NULL)); - printCommandError(errorLine, arg, tmpStr); - goto return0; - } - fclose(tmpFp); - } - goto return1; - } - - - - /* Parse the choices available */ - possCmds = 0; - p = 0; - while (1) { - q = p; - p = instr(p + 1, cat(cmdList, "|", NULL), "|"); - if (!p) break; - pntrLet(&possCmd,pntrAddElement(possCmd)); - let((vstring *)(&possCmd[possCmds]),seg(cmdList,q+1,p-1)); - possCmds++; - } - if (!strcmp(left(possCmd[possCmds - 1],1), "<")) { - /* Get default argument, if any */ - defaultCmd = possCmd[possCmds - 1]; /* re-use old allocation */ - if (!strcmp(defaultCmd, "<$>")) { - let(&defaultCmd, ""); - } - pntrLet(&possCmd,pntrLeft(possCmd,possCmds - 1)); - possCmds--; - } - if (!strcmp(possCmd[possCmds - 1], "$")) { - /* Change "$" to "nothing" for printouts */ - let((vstring *)(&possCmd[possCmds - 1]), "nothing"); - } - - /* Create a string used for queries and error messages */ - if (possCmds < 1) bug(1105); - if (possCmds == 1) { - let(&infoStr,possCmd[0]); - } - if (possCmds == 2) { - let(&infoStr, cat(possCmd[0], " or ", - possCmd[1], NULL)); - } - if (possCmds > 2) { - let(&infoStr, ""); - for (i = 0; i < possCmds - 1; i++) { - let(&infoStr, cat(infoStr,possCmd[i], ", ", NULL)); - } - let(&infoStr, cat(infoStr, "or ",possCmd[possCmds - 1], NULL)); - } - - /* If the argument has not been entered, prompt the user for it */ - if (g_rawArgs <= arg && (strcmp(possCmd[possCmds - 1], "nothing") - || g_queryMode == 1)) { - - let(&tmpStr, infoStr); - if (defaultCmd[0] != 0) { - let(&tmpStr, cat(tmpStr, " ",defaultCmd, NULL)); - } - let(&tmpStr, cat(tmpStr, "? ", NULL)); - g_queryMode = 1; - if (possCmds != 1) { - tmpArg = cmdInput1(tmpStr); - } else { - /* There is only one possibility, so don't ask user */ - /* Don't print the message when "end-of-list" is the only possibility. */ - if (!strcmp(cmdList, "$|<$>")) { - let(&tmpArg, possCmd[0]); - print2("The command so far is: "); - for (i = 0; i < arg; i++) { - print2("%s ", g_fullArg[i]); - } - print2("%s\n", tmpArg); - } - } - let(&errorLine,tmpStr); - if (tmpArg[0] == 0) { /* Use default argument */ - let(&tmpArg, seg(defaultCmd,2,len(defaultCmd) - 1)); - } - - if (strcmp(tmpArg, "nothing")) { - pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); - nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, 0)); - g_rawArgs++; - if (g_rawArgs <= arg) bug(1106); - let((vstring *)(&g_rawArgPntr[arg]), tmpArg); - g_rawArgNmbr[arg] = len(tmpStr) + 1; /* Line position for error msgs */ - } - - } /* End of asking user for additional argument */ - - if (g_rawArgs <= arg) { - /* No argument was specified, and "nothing" is a valid argument */ - let(&keyword,chr(3)); - goto return1; - } - - - let(&tmpArg,edit(g_rawArgPntr[arg], 32)); /* Convert to upper case */ - j = 0; - k = 0; - m = len(tmpArg); - let(&tmpStr, ""); - /* Scan the possible arguments for a match */ - for (i = 0; i < possCmds; i++) { - if (!strcmp(possCmd[i], tmpArg)) { - /* An exact match was found, so ignore any other matches - and use this one */ - k = 1; - j = i; - break; - } - if (!strcmp(left(possCmd[i], m), tmpArg)) { - if (!k) { - let(&tmpStr, possCmd[i]); - } else { - let(&tmpStr, cat(tmpStr, ", ", possCmd[i], NULL)); - } - j = i; /* Save match position */ - k++; /* Number of matches */ - } - } - if (k < 1 || k > 1) { - if (k < 1) { - let(&tmpStr, cat("?Expected ", infoStr, ".", NULL)); - } else { - if (k == 2) { - p = instr(1,tmpStr, ", "); - let(&tmpStr, cat(left(tmpStr,p-1), " or",right(tmpStr,p+1), NULL)); - } else { - p = len(tmpStr) - 1; - while (tmpStr[p] != ',') p--; - let(&tmpStr, cat(left(tmpStr,p+1), " or",right(tmpStr,p+2), NULL)); - } - let(&tmpStr, cat("?Ambiguous keyword - please specify ",tmpStr, ".", NULL)); - } - printCommandError(errorLine, arg, tmpStr); - goto return0; - } - - let(&keyword,possCmd[j]); - goto return1; - - return1: - if (keyword[0] == 0) { - if (g_rawArgs > arg && strcmp(defaultCmd, "<>")) { - /* otherwise, "nothing" was specified */ - printCommandError("", arg, - "?No default answer is available - please be explicit."); - goto return0; - } - } - /* Add new field to g_fullArg */ - pntrLet(&g_fullArg,pntrAddElement(g_fullArg)); - if (pntrLen(g_fullArg) != arg + 1) bug(1107); - let((vstring *)(&g_fullArg[arg]),keyword); - - /* Deallocate memory */ - j = pntrLen(possCmd); - for (i = 0; i < j; i++) let((vstring *)(&possCmd[i]), ""); - pntrLet(&possCmd, NULL_PNTRSTRING); - let(&defaultCmd, ""); - let(&infoStr, ""); - let(&tmpStr, ""); - let(&tmpArg, ""); - let(&errorLine, ""); - let(&keyword, ""); - let(&cmdList, ""); - return(1); - - return0: - /* Deallocate memory */ - j = pntrLen(possCmd); - for (i = 0; i < j; i++) let((vstring *)(&possCmd[i]), ""); - pntrLet(&possCmd, NULL_PNTRSTRING); - let(&defaultCmd, ""); - let(&infoStr, ""); - let(&tmpStr, ""); - let(&tmpArg, ""); - let(&errorLine, ""); - let(&keyword, ""); - let(&cmdList, ""); - return(0); - -} /* getFullArg */ - - - -void parseCommandLine(vstring line) -{ - /* This function breaks up line into individual tokens - and puts them into g_rawArgPntr[]. g_rawArgs is the number of tokens. - g_rawArgPntr[] is the starting position of each token on the line; - the first character on the line has position 1, not 0. - - Spaces, tabs, and newlines are considered white space. Special - one-character - tokens don't have to be surrounded by white space. Characters - inside quotes are considered to be one token, and the quotes are - removed. - - */ - /* Warning: Don't deallocate these vstring constants */ - /*vstring specialOneCharTokens = "()/,=:";*/ - vstring tokenWhiteSpace = " \t\n"; - vstring tokenComment = "!"; - - - vstring tmpStr = ""; /* Dummy vstring to clean up temp alloc stack */ - flag mode; - long tokenStart, i, p, lineLen; - - vstring specialOneCharTokens = ""; - - /* Initialization to avoid compiler warning (should not be theoretically - necessary) */ - tokenStart = 0; - - if (!g_toolsMode) { - let(&specialOneCharTokens, "/="); /* List of special one-char tokens */ - } else { - let(&specialOneCharTokens, ""); - } - - lineLen = len(line); - /* mode: 0 means look for start of token, 1 means look for end of - token, 2 means look for trailing single quote, 3 means look for - trailing double quote */ - /* only "!" at beginning of line acts as comment. - This is done because sometimes ! might be legal as part of a command */ - mode = 0; - for (p = 0; p < lineLen; p++) { - let(&tmpStr, ""); /* Clean up temp alloc stack to prevent overflow */ - if (mode == 0) { - /* If character is white space, ignore it */ - if (instr(1,tokenWhiteSpace,chr(line[p]))) { - continue; - } - /* If character is comment, we're done */ - if (p == 0 && instr(1,tokenComment,chr(line[p]))) { - break; - } - /* If character is a special token, get it but don't change mode */ - if (instr(1,specialOneCharTokens,chr(line[p]))) { - pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); - nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, p+1)); - /* Save token start */ - let((vstring *)(&g_rawArgPntr[g_rawArgs]), chr(line[p])); - g_rawArgs++; - continue; - } - /* If character is a quote, set start and change mode */ - if (line[p] == '\'') { - mode = 2; - tokenStart = p + 2; - continue; - } - if (line[p] == '\"') { - mode = 3; - tokenStart = p + 2; - continue; - } - /* Character must be start of a token */ - mode = 1; - tokenStart = p + 1; - continue; - } - if (mode == 1) { - /* If character is white space, end token and change mode */ - if (instr(1,tokenWhiteSpace,chr(line[p]))) { - pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); - nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, tokenStart)); - /* Save token start */ - let((vstring *)(&g_rawArgPntr[g_rawArgs]), seg(line, tokenStart, p)); - g_rawArgs++; - mode = 0; - continue; - } - - /* If character is a special token, get it and change mode */ - if (instr(1,specialOneCharTokens,chr(line[p]))) { - pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); - nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, tokenStart)); - /* Save token start */ - let((vstring *)(&g_rawArgPntr[g_rawArgs]),seg(line, tokenStart, p)); - g_rawArgs++; - pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); - nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, p + 1)); - /* Save token start */ - let((vstring *)(&g_rawArgPntr[g_rawArgs]), chr(line[p])); - g_rawArgs++; - mode = 0; - continue; - } - - /* If character is a quote, set start and change mode */ - if (line[p] == '\'') { - pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); - nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, tokenStart)); - /* Save token start */ - let((vstring *)(&g_rawArgPntr[g_rawArgs]),seg(line, tokenStart,p)); - g_rawArgs++; - mode = 2; - tokenStart = p + 2; - continue; - } - if (line[p] == '\"') { - pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); - nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, tokenStart)); - /* Save token start */ - let((vstring *)(&g_rawArgPntr[g_rawArgs]),seg(line, tokenStart,p)); - g_rawArgs++; - mode = 3; - tokenStart = p + 2; - continue; - } - /* Character must be continuation of the token */ - continue; - } - if (mode == 2 || mode == 3) { - /* If character is a quote, end quote and change mode */ - if (line[p] == '\'' && mode == 2) { - mode = 0; - pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); - nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, tokenStart)); - /* Save token start */ - let((vstring *)(&g_rawArgPntr[g_rawArgs]), seg(line,tokenStart,p)); - g_rawArgs++; - continue; - } - if (line[p] == '\"' && mode == 3) { - mode = 0; - pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); - nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, tokenStart)); - /* Save token start */ - let((vstring *)(&g_rawArgPntr[g_rawArgs]),seg(line, tokenStart,p)); - g_rawArgs++; - continue; - } - /* Character must be continuation of quoted token */ - continue; - } - } - - /* Finished scanning the line. Finish processing last token. */ - if (mode != 0) { - pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); - nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, tokenStart)); - /* Save token start */ - let((vstring *)(&g_rawArgPntr[g_rawArgs]),seg(line,tokenStart,p)); - g_rawArgs++; - } - - /* Add length of command line prompt to each argument, to - align the error message pointer */ - for (i = 0; i < g_rawArgs; i++) { - g_rawArgNmbr[i] = g_rawArgNmbr[i] + len(g_commandPrompt); - } - - /* Deallocate */ - let(&specialOneCharTokens, ""); -} /* parseCommandLine */ - - -flag lastArgMatches(vstring argString) -{ - /* This functions checks to see if the last field was argString */ - if (!strcmp(argString, g_fullArg[pntrLen(g_fullArg)-1])) { - return (1); - } else { - return (0); - } -} /* lastArgMatches */ - -flag cmdMatches(vstring cmdString) -{ - /* This function checks that fields 0 through n of g_fullArg match - cmdString (separated by spaces). */ - long i, j, k; - vstring tmpStr = ""; - /* Count the number of spaces */ - k = len(cmdString); - j = 0; - for (i = 0; i < k; i++) { - if (cmdString[i] == ' ') j++; - } - k = pntrLen(g_fullArg); - for (i = 0; i <= j; i++) { - if (j >= k) { - /* Command to match is longer than the user's command; assume no match */ - let(&tmpStr, ""); - return (0); - } - let(&tmpStr, cat(tmpStr, " ", g_fullArg[i], NULL)); - } - if (!strcmp(cat(" ", cmdString, NULL), tmpStr)) { - let(&tmpStr, ""); - return (1); - } else { - let(&tmpStr, ""); - return (0); - } -} /* cmdMatches */ - - -long switchPos(vstring swString) -{ - /* This function checks that fields i through j of g_fullArg match - swString (separated by spaces). The first character of swString - should be "/" and must be separated from the first field - of swString with a space. The position of the "/" in g_fullArg - is returned if swString is there, otherwise 0 is returned (the first - position in g_fullArg is considered 1, not 0). */ - /* Example: if g_fullArg (combined into one string) is - "DISPLAY PROOF / UNKNOWN / START_STEP = 10 / ESSENTIAL" - and swString is "/ START_STEP", switchPos will return 5. */ - long i, j, k; - vstring tmpStr = ""; - vstring swString1 = ""; - - if (swString[0] != '/') bug(1108); - - /* Add a space after the "/" if there is none */ - if (swString[1] != ' ') { - let(&swString1, cat("/ ", right(swString,2), " ", NULL)); - } else { - let(&swString1,swString); - } - - /* Build the complete command */ - k = pntrLen(g_fullArg); - for (i = 0; i < k; i++) { - let(&tmpStr, cat(tmpStr,g_fullArg[i], " ", NULL)); - } - - k = instr(1,tmpStr,swString1); - if (!k) { - let(&swString1, ""); - let(&tmpStr, ""); - return (0); - } - - let(&tmpStr,left(tmpStr,k)); - /* Count the number of spaces - it will be the g_fullArg position */ - k = len(tmpStr); - j = 0; - for (i = 0; i < k; i++) { - if (tmpStr[i] == ' ') j++; - } - let(&tmpStr, ""); - let(&swString1, ""); - return (j + 1); -} /* switchPos */ - - -void printCommandError(vstring line1, long arg, vstring errorMsg) -{ - /* Warning: errorMsg should not a temporarily allocated string such - as the direct output of cat() */ - vstring errorPointer = ""; - vstring line = ""; - long column, tokenLength, j; - - let(&line,line1); /* Prevent deallocation in case line1 is - direct return from string function such as cat() */ - if (!line[0]) { - /* Empty line - don't print an error pointer */ - print2("%s\n", errorMsg); - let(&line, ""); - return; - } - column = g_rawArgNmbr[arg]; - tokenLength = len(g_rawArgPntr[arg]); - for (j = 0; j < column - 1; j++) { - /* Make sure that tabs on the line with the error are accounted for so - that the error pointer lines up correctly */ - if (j >= len(line)) bug(1109); - if (line[j] == '\t') { - let(&errorPointer, cat(errorPointer, "\t", NULL)); - } else { - if (line[j] == '\n') { - let(&errorPointer, ""); - } else { - let(&errorPointer, cat(errorPointer, " ", NULL)); - } - } - } - for (j = 0; j < tokenLength; j++) - let(&errorPointer, cat(errorPointer, "^", NULL)); - print2("%s\n", errorPointer); - printLongLine(errorMsg, "", " "); - let(&errorPointer, ""); - let(&line, ""); -} /* printCommandError */ - -void freeCommandLine() { - long i, j; - j = pntrLen(g_rawArgPntr); - for (i = 0; i < j; i++) let((vstring *)(&g_rawArgPntr[i]), ""); - j = pntrLen(g_fullArg); - for (i = 0; i < j; i++) let((vstring *)(&g_fullArg[i]), ""); - pntrLet(&g_fullArg, NULL_PNTRSTRING); - pntrLet(&g_rawArgPntr, NULL_PNTRSTRING); - nmbrLet(&g_rawArgNmbr, NULL_NMBRSTRING); - let(&g_fullArgString, ""); -} +/*****************************************************************************/ +/* Copyright (C) 2020 NORMAN MEGILL nm at alum.mit.edu */ +/* License terms: GNU General Public License */ +/*****************************************************************************/ +/*34567890123456 (79-character line to adjust editor window) 2345678901234567*/ + +/* Command line syntax specification for Metamath */ + +#include +#include +#include +#include +#include +#include +#include "mmvstr.h" +#include "mmdata.h" +#include "mmcmdl.h" +#include "mminou.h" +#include "mmpfas.h" +#include "mmunif.h" /* For g_hentyFilter, g_userMaxUnifTrials, g_minSubstLen */ +#include "mmwtex.h" +#include "mmword.h" + +/* Global variables */ +pntrString *g_rawArgPntr = NULL_PNTRSTRING; +nmbrString *g_rawArgNmbr = NULL_NMBRSTRING; +long g_rawArgs = 0; +pntrString *g_fullArg = NULL_PNTRSTRING; +vstring g_fullArgString = ""; /* g_fullArg as one string */ +vstring g_commandPrompt = ""; +vstring g_commandLine = ""; +long g_showStatement = 0; +vstring g_logFileName = ""; +vstring g_texFileName = ""; +flag g_PFASmode = 0; /* Proof assistant mode, invoked by PROVE command */ +flag g_queryMode = 0; /* If 1, explicit questions will be asked even if + a field in the input command line is optional */ +flag g_sourceChanged = 0; /* Flag that user made some change to the source file*/ +flag g_proofChanged = 0; /* Flag that user made some change to proof in progress*/ +flag g_commandEcho = 0; /* Echo full command */ +flag g_memoryStatus = 0; /* Always show memory */ +flag g_sourceHasBeenRead = 0; /* 1 if a source file has been read in */ +vstring g_rootDirectory = ""; /* Directory prefix to use for included files */ + + + +flag processCommandLine(void) +{ + vstring defaultArg = ""; + vstring tmpStr = ""; + long i; + g_queryMode = 0; /* If 1, explicit questions will be asked even if + a field is optional */ + pntrLet(&g_fullArg, NULL_PNTRSTRING); + + if (!g_toolsMode) { + + if (!g_PFASmode) { + /* Normal mode */ + let(&tmpStr, cat("DBG|", + "HELP|READ|WRITE|PROVE|SHOW|SEARCH|SAVE|SUBMIT|OPEN|CLOSE|", + "SET|FILE|BEEP|EXIT|QUIT|ERASE|VERIFY|MARKUP|MORE|TOOLS|", + "MIDI|", + NULL)); + } else { + /* Proof assistant mode */ + let(&tmpStr, cat("DBG|", + "HELP|WRITE|SHOW|SEARCH|SAVE|SUBMIT|OPEN|CLOSE|", + "SET|FILE|BEEP|EXIT|_EXIT_PA|QUIT|VERIFY|INITIALIZE|ASSIGN|REPLACE|", + "LET|UNIFY|IMPROVE|MINIMIZE_WITH|EXPAND|MATCH|DELETE|UNDO|REDO|", + "MARKUP|MORE|TOOLS|MIDI|", + NULL)); + } + if (!getFullArg(0,tmpStr)) { + goto pclbad; + } + + if (cmdMatches("HELP")) { + if (!getFullArg(1, cat("LANGUAGE|PROOF_ASSISTANT|MM-PA|", + "BEEP|EXIT|QUIT|READ|ERASE|", + "OPEN|CLOSE|SHOW|SEARCH|SET|VERIFY|SUBMIT|SYSTEM|PROVE|FILE|WRITE|", + "MARKUP|ASSIGN|REPLACE|MATCH|UNIFY|LET|INITIALIZE|DELETE|IMPROVE|", + "MINIMIZE_WITH|EXPAND|UNDO|REDO|SAVE|DEMO|INVOKE|CLI|EXPLORE|TEX|", + "LATEX|HTML|STS|COMMENTS|BIBLIOGRAPHY|MORE|", + "TOOLS|MIDI|$|<$>", NULL))) goto pclbad; + if (cmdMatches("HELP OPEN")) { + if (!getFullArg(2, "LOG|TEX|")) goto pclbad; + goto pclgood; + } + if (cmdMatches("HELP CLOSE")) { + if (!getFullArg(2, "LOG|TEX|")) goto pclbad; + goto pclgood; + } + if (cmdMatches("HELP SHOW")) { + if (!getFullArg(2, cat("MEMORY|SETTINGS|LABELS|SOURCE|STATEMENT|", + "PROOF|NEW_PROOF|USAGE|TRACE_BACK|ELAPSED_TIME|", + "DISCOURAGED|", + NULL))) + goto pclbad; + goto pclgood; + } + if (cmdMatches("HELP SET")) { + if (!getFullArg(2, cat( + "ECHO|SCROLL|WIDTH|HEIGHT|UNDO|UNIFICATION_TIMEOUT|", + "DISCOURAGEMENT|", + "CONTRIBUTOR|", + "ROOT_DIRECTORY|", + "EMPTY_SUBSTITUTION|SEARCH_LIMIT|JEREMY_HENTY_FILTER|", + NULL))) + goto pclbad; + goto pclgood; + } + if (cmdMatches("HELP VERIFY")) { + if (!getFullArg(2, "PROOF|MARKUP|STS|")) + goto pclbad; + goto pclgood; + } + if (cmdMatches("HELP WRITE")) { + if (!getFullArg(2, + "SOURCE|THEOREM_LIST|BIBLIOGRAPHY|RECENT_ADDITIONS|")) + goto pclbad; + goto pclgood; + } + if (cmdMatches("HELP FILE")) { + if (!getFullArg(2, "SEARCH")) + goto pclbad; + goto pclgood; + } + if (cmdMatches("HELP SAVE")) { + if (!getFullArg(2, + "PROOF|NEW_PROOF|")) + goto pclbad; + goto pclgood; + } + goto pclgood; + } /* cmdMatches("HELP") */ + + if (cmdMatches("READ")) { + if (!getFullArg(1, "& What is the name of the source input file? ")) + goto pclbad; + /* Get any switches */ + i = 1; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, "VERIFY|")) goto pclbad; + } else { + break; + } + break; /* Break if only 1 switch is allowed */ + } /* End while for switch loop */ + goto pclgood; + } + + if (cmdMatches("WRITE")) { + if (!getFullArg(1, + "SOURCE|THEOREM_LIST|BIBLIOGRAPHY|RECENT_ADDITIONS|")) + goto pclbad; + if (cmdMatches("WRITE SOURCE")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (!getFullArg(2, cat( + "* What is the name of the source output file <", + g_input_fn, ">? ", NULL))) + goto pclbad; + if (!strcmp(g_input_fn, g_fullArg[2])) { + print2( + "The input file will be renamed %s~1.\n", g_input_fn); + } + + /* Get any switches */ + i = 2; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "FORMAT|REWRAP", + "|SPLIT|NO_VERSIONING|KEEP_INCLUDES|EXTRACT", + "|", NULL))) + goto pclbad; + if (lastArgMatches("EXTRACT")) { + i++; + if (!getFullArg(i, "* What statement label? ")) + goto pclbad; + } + } else { + break; + } + /* break; */ /* Break if only 1 switch is allowed */ + } /* End while for switch loop */ + + goto pclgood; + } + if (cmdMatches("WRITE THEOREM_LIST")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + /* Get any switches */ + i = 1; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "THEOREMS_PER_PAGE|SHOW_LEMMAS|HTML|ALT_HTML|NO_VERSIONING", + "|", NULL))) + goto pclbad; + if (lastArgMatches("THEOREMS_PER_PAGE")) { + i++; + if (!getFullArg(i, "# How many theorems per page <100>? ")) + goto pclbad; + } + } else { + break; + } + /* break; */ /* Break if only 1 switch is allowed */ + } + goto pclgood; + } + if (cmdMatches("WRITE BIBLIOGRAPHY")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (!getFullArg(2, cat( + "* What is the bibliography HTML input/output file <", + "mmbiblio.html", ">? ", NULL))) + goto pclbad; + print2( + "The old file will be renamed %s~1.\n", g_fullArg[2]); + goto pclgood; + } + if (cmdMatches("WRITE RECENT_ADDITIONS")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (!getFullArg(2, cat( + "* What is the Recent Additions HTML input/output file <", + "mmrecent.html", ">? ", NULL))) + goto pclbad; + print2( + "The old file will be renamed %s~1.\n", g_fullArg[2]); + + /* Get any switches */ + i = 2; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "LIMIT|HTML|ALT_HTML", + "|", NULL))) + goto pclbad; + if (lastArgMatches("LIMIT")) { + i++; + if (!getFullArg(i, "# How many most recent theorems <100>? ")) + goto pclbad; + } + } else { + break; + } + /*break;*/ /* Break if only 1 switch is allowed */ + } + goto pclgood; + } + } + + if (cmdMatches("OPEN")) { + if (!getFullArg(1, "LOG|TEX|")) goto pclbad; + if (cmdMatches("OPEN LOG")) { + if (g_logFileOpenFlag) { + printLongLine(cat( + "?Sorry, the log file \"", g_logFileName, "\" is currently open. ", + "Type CLOSE LOG to close the current log if you want to open another one." + , NULL), "", " "); + goto pclbad; + } + if (!getFullArg(2, "* What is the name of logging output file? ")) + goto pclbad; + } + if (cmdMatches("OPEN TEX")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (g_texFileOpenFlag) { + printLongLine(cat( + "?Sorry, the LaTeX file \"", g_texFileName, "\" is currently open. ", + "Type CLOSE TEX to close the current LaTeX file", + " if you want to open another one." + , NULL), "", " "); + goto pclbad; + } + if (!getFullArg(2, "* What is the name of LaTeX output file? ")) + goto pclbad; + + /* Get any switches */ + i = 2; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "NO_HEADER|OLD_TEX|", NULL))) + goto pclbad; + } else { + break; + } + /* break; */ /* Break if only 1 switch is allowed */ + } /* End while for switch loop */ + + } + goto pclgood; + } + + if (cmdMatches("CLOSE")) { + if (!getFullArg(1, "LOG|TEX|")) goto pclbad; + goto pclgood; + } + + if (cmdMatches("FILE")) { + if (!getFullArg(1, cat("SEARCH", NULL))) goto pclbad; + + if (cmdMatches("FILE SEARCH")) { + if (!getFullArg(2, "& What is the name of the file to search? ")) + goto pclbad; + if (!getFullArg(3, "* What is the string to search for? ")) + goto pclbad; + + + /* Get any switches */ + i = 3; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (i == 4) { + if (!getFullArg(i, cat( + "FROM_LINE|TO_LINE|", NULL))) + goto pclbad; + } else { + if (!getFullArg(i, cat( + "FROM_LINE|TO_LINE|", NULL))) + goto pclbad; + } + if (lastArgMatches("FROM_LINE")) { + i++; + if (!getFullArg(i, "# From what line number <1>? ")) + goto pclbad; + } + if (lastArgMatches("TO_LINE")) { + i++; + if (!getFullArg(i, "# To what line number <999999>? ")) + goto pclbad; + } + if (lastArgMatches("WINDOW")) { /* ???Not implemented yet */ + i++; + if (!getFullArg(i, "# How big a window around matched lines <0>? ")) + goto pclbad; + } + } else { + break; + } + /* break; */ /* Break if only 1 switch is allowed */ + } /* End while for switch loop */ + + + goto pclgood; + } /* End if (cmdMatches("FILE SEARCH")) */ + goto pclgood; + } + + if (cmdMatches("SHOW")) { + if (!g_PFASmode) { + if (!getFullArg(1, cat( + "SETTINGS|LABELS|STATEMENT|SOURCE|PROOF|MEMORY|TRACE_BACK|", + "USAGE|ELAPSED_TIME|DISCOURAGED|", NULL))) + goto pclbad; + } else { + if (!getFullArg(1, cat("NEW_PROOF|", + "SETTINGS|LABELS|STATEMENT|SOURCE|PROOF|MEMORY|TRACE_BACK|", + "USAGE|ELAPSED_TIME|DISCOURAGED|", + NULL))) + goto pclbad; + } + if (g_showStatement) { + if (g_showStatement < 1 || g_showStatement > g_statements) bug(1110); + let(&defaultArg, cat(" <",g_Statement[g_showStatement].labelName, ">", + NULL)); + } else { + let(&defaultArg, ""); + } + + + if (cmdMatches("SHOW TRACE_BACK")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (!getFullArg(2, + cat("* What is the statement label", defaultArg, "? ", NULL))) + goto pclbad; + + /* Get any switches */ + i = 2; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "ALL|ESSENTIAL|AXIOMS|TREE|DEPTH|COUNT_STEPS|MATCH|TO", + "|", NULL))) + goto pclbad; + if (lastArgMatches("DEPTH")) { + i++; + if (!getFullArg(i, "# How many indentation levels <999>? ")) + goto pclbad; + } + if (lastArgMatches("MATCH")) { + i++; + if (!getFullArg(i, "* What statement label? ")) + goto pclbad; + } + if (lastArgMatches("TO")) { + i++; + if (!getFullArg(i, "* What statement label? ")) + goto pclbad; + } + } else { + break; + } + /* break; */ /* Break if only 1 switch is allowed */ + } + + goto pclgood; + } /* End if (cmdMatches("SHOW TRACE_BACK")) */ + + if (cmdMatches("SHOW USAGE")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (!getFullArg(2, + cat("* What is the statement label", defaultArg, "? ", NULL))) + goto pclbad; + + /* Get any switches */ + i = 2; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "DIRECT|RECURSIVE|ALL", + "|", NULL))) + goto pclbad; + } else { + break; + } + /* break; */ /* Break if only 1 switch is allowed */ + } + + goto pclgood; + } /* End if (cmdMatches("SHOW USAGE")) */ + + + if (cmdMatches("SHOW LABELS")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (!getFullArg(2, + "* What are the labels to match (* = wildcard) <*>?")) + goto pclbad; + /* Get any switches */ + i = 2; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat("ALL|LINEAR|", NULL))) + goto pclbad; + } else { + break; + } + /*break;*/ /* Break if only 1 switch is allowed */ + } + goto pclgood; + } + if (cmdMatches("SHOW STATEMENT")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (!getFullArg(2, + cat("* What is the statement label", defaultArg, "? ", NULL))) + goto pclbad; + /* Get any switches */ + i = 2; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "FULL|COMMENT|TEX|OLD_TEX|HTML|ALT_HTML|STS|TIME|BRIEF_HTML", + "|BRIEF_ALT_HTML|MNEMONICS|NO_VERSIONING|", NULL))) + goto pclbad; + if (lastArgMatches("STS")) { + i++; + if (strlen(stsOutput)) { + if (!getFullArg(i,cat("* Using which output mode <",stsOutput,">? ",NULL))) + goto pclbad; + } else { + if (!getFullArg(i,"* Using which output mode ? ")) + goto pclbad; + } + } + } else { + break; + } + /* break; */ /* Break if only 1 switch is allowed */ + } + goto pclgood; + } + if (cmdMatches("SHOW SOURCE")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (!getFullArg(2, + cat("* What is the statement label", defaultArg, "? ", NULL))) { + goto pclbad; + } + goto pclgood; + } + + + if (cmdMatches("SHOW PROOF")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (!getFullArg(2, + cat("* What is the statement label", defaultArg, "? ", NULL))) + goto pclbad; + + /* Get any switches */ + i = 2; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "ESSENTIAL|ALL|UNKNOWN|FROM_STEP|TO_STEP|DEPTH", + "|REVERSE|VERBOSE|NORMAL|PACKED|COMPRESSED|EXPLICIT", + "|FAST|OLD_COMPRESSION", + "|STATEMENT_SUMMARY|DETAILED_STEP|TEX|OLD_TEX|HTML", + "|LEMMON|START_COLUMN|NO_REPEATED_STEPS", + "|RENUMBER|SIZE|", NULL))) + goto pclbad; + if (lastArgMatches("FROM_STEP")) { + i++; + if (!getFullArg(i, "# From what step <1>? ")) + goto pclbad; + } + if (lastArgMatches("TO_STEP")) { + i++; + if (!getFullArg(i, "# To what step <9999>? ")) + goto pclbad; + } + if (lastArgMatches("DEPTH")) { + i++; + if (!getFullArg(i, "# How many indentation levels <999>? ")) + goto pclbad; + } + if (lastArgMatches("DETAILED_STEP")) { + i++; + if (!getFullArg(i, "# Display details of what step <1>? ")) + goto pclbad; + } + if (lastArgMatches("START_COLUMN")) { + i++; + if (!getFullArg(i, cat( + "# At what column should the formula start <", + str((double)DEFAULT_COLUMN), ">? ", NULL))) + goto pclbad; + } + } else { + break; + } + /* break; */ /* Break if only 1 switch is allowed */ + } + goto pclgood; + } /* End if (cmdMatches("SHOW PROOF")) */ + + + if (cmdMatches("SHOW NEW_PROOF")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + + /* Get any switches */ + i = 1; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "ESSENTIAL|ALL|UNKNOWN|FROM_STEP|TO_STEP|DEPTH", + "|REVERSE|VERBOSE|NORMAL|PACKED|COMPRESSED|EXPLICIT", + "|OLD_COMPRESSION", + "|NOT_UNIFIED|TEX|HTML", + "|LEMMON|START_COLUMN|NO_REPEATED_STEPS", + "|RENUMBER|", NULL))) + goto pclbad; + if (lastArgMatches("FROM_STEP")) { + i++; + if (!getFullArg(i, "# From what step <1>? ")) + goto pclbad; + } + if (lastArgMatches("TO_STEP")) { + i++; + if (!getFullArg(i, "# To what step <9999>? ")) + goto pclbad; + } + if (lastArgMatches("DEPTH")) { + i++; + if (!getFullArg(i, "# How many indentation levels <999>? ")) + goto pclbad; + } + if (lastArgMatches("START_COLUMN")) { + i++; + if (!getFullArg(i, cat( + "# At what column should the formula start <", + str((double)DEFAULT_COLUMN), ">? ", NULL))) + goto pclbad; + } + } else { + break; + } + /* break; */ /* Break if only 1 switch is allowed */ + } + goto pclgood; + } /* End if (cmdMatches("SHOW NEW_PROOF")) */ + + + goto pclgood; + } /* End of SHOW */ + + if (cmdMatches("SEARCH")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (!getFullArg(1, + "* What are the labels to match (* = wildcard) <*>?")) + goto pclbad; + if (!getFullArg(2, "* Search for what math symbol string? ")) + goto pclbad; + /* Get any switches */ + i = 2; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat("ALL|COMMENTS|JOIN|", NULL))) + goto pclbad; + } else { + break; + } + /*break;*/ /* Break if only 1 switch is allowed */ + } + goto pclgood; + + } /* End of SEARCH */ + + + if (cmdMatches("SAVE")) { + if (!g_PFASmode) { + if (!getFullArg(1, + "PROOF|")) + goto pclbad; + } else { + if (!getFullArg(1, cat("NEW_PROOF|", + "PROOF|", + NULL))) + goto pclbad; + } + if (g_showStatement) { + if (g_showStatement < 0) bug(1111); + let(&defaultArg, cat(" <",g_Statement[g_showStatement].labelName, ">", NULL)); + } else { + let(&defaultArg, ""); + } + + + if (cmdMatches("SAVE PROOF")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (!getFullArg(2, + cat("* What is the statement label", defaultArg, "? ", NULL))) + goto pclbad; + + /* Get any switches */ + i = 2; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "NORMAL|PACKED|COMPRESSED|EXPLICIT", + "|FAST|OLD_COMPRESSION", + "|TIME|", NULL))) + goto pclbad; + } else { + break; + } + /* break; */ /* Break if only 1 switch is allowed */ + } + goto pclgood; + } /* End if (cmdMatches("SAVE PROOF")) */ + + + if (cmdMatches("SAVE NEW_PROOF")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + + /* Get any switches */ + i = 1; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "NORMAL|PACKED|COMPRESSED|EXPLICIT", + "|OLD_COMPRESSION|OVERRIDE", + "|", NULL))) + goto pclbad; + } else { + break; + } + /*break;*/ /* Break if only 1 switch is allowed */ + } + goto pclgood; + } /* End if (cmdMatches("SAVE NEW_PROOF")) */ + + + goto pclgood; + } /* End of SAVE */ + + + if (cmdMatches("PROVE")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (!g_proveStatement) g_proveStatement = g_showStatement; + if (g_proveStatement) { + let(&defaultArg, cat(" <",g_Statement[g_proveStatement].labelName, ">", NULL)); + } else { + let(&defaultArg, ""); + } + if (!getFullArg(1, + cat("* What is the label of the statement you want to try proving", + defaultArg, "? ", NULL))) + goto pclbad; + + /* Get any switches */ + i = 1; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, "OVERRIDE|")) goto pclbad; + } else { + break; + } + break; /* Break if only 1 switch is allowed */ + } /* End while for switch loop */ + + goto pclgood; + } + + /* Commands in Proof Assistant mode */ + + if (cmdMatches("MATCH")) { + if (!getFullArg(1, + "STEP|ALL|")) goto pclbad; + if (cmdMatches("MATCH STEP")) { + if (!getFullArg(2, "# What step number? ")) goto pclbad; + /* Get any switches */ + i = 2; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "MAX_ESSENTIAL_HYP|", NULL))) + goto pclbad; + if (lastArgMatches("MAX_ESSENTIAL_HYP")) { + i++; + if (!getFullArg(i, + "# Maximum number of essential hypotheses to allow for a match <0>? ")) + goto pclbad; + } + } else { + break; + } + break; /* Break if only 1 switch is allowed */ + } + goto pclgood; + } + if (cmdMatches("MATCH ALL")) { + /* Get any switches */ + i = 1; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "ESSENTIAL|MAX_ESSENTIAL_HYP|", NULL))) + goto pclbad; + if (lastArgMatches("MAX_ESSENTIAL_HYP")) { + i++; + if (!getFullArg(i, + "# Maximum number of essential hypotheses to allow for a match <0>? ")) + goto pclbad; + } + } else { + break; + } + /*break;*/ /* Break if only 1 switch is allowed */ + } + goto pclgood; + } /* End if (cmdMatches("MATCH ALL")) */ + goto pclgood; + } + + if (cmdMatches("INITIALIZE")) { + if (!getFullArg(1, + "STEP|ALL|USER|")) goto pclbad; + if (cmdMatches("INITIALIZE STEP")) { + if (!getFullArg(2, "# What step number? ")) goto pclbad; + } + goto pclgood; + } + + if (cmdMatches("IMPROVE")) { + if (!getFullArg(1, + "* What step number, or FIRST, or LAST, or ALL ? ")) goto pclbad; + /* Get any switches */ + i = 1; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, "DEPTH|NO_DISTINCT|1|2|3" + "|SUBPROOFS|OVERRIDE|INCLUDE_MATHBOXES|")) goto pclbad; + if (lastArgMatches("DEPTH")) { + i++; + if (!getFullArg(i, "# What is maximum depth for " + "searching statements with $e hypotheses <0>? ")) goto pclbad; + } + } else { + break; + } + /*break;*/ /* Do this if only 1 switch is allowed */ + } /* end while */ + goto pclgood; + } /* end if IMPROVE */ + + + if (cmdMatches("MINIMIZE_WITH")) { + if (!getFullArg(1, "* What statement label? ")) goto pclbad; + /* Get any switches */ + i = 1; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "VERBOSE|MAY_GROW|EXCEPT|OVERRIDE|INCLUDE_MATHBOXES|", + "ALLOW_NEW_AXIOMS|NO_NEW_AXIOMS_FROM|FORBID|TIME|", + NULL))) + goto pclbad; + + if (lastArgMatches("EXCEPT")) { + i++; + if (!getFullArg(i, "* What statement label match pattern? ")) + goto pclbad; + } + if (lastArgMatches("ALLOW_NEW_AXIOMS")) { + i++; + if (!getFullArg(i, "* What statement label match pattern? ")) + goto pclbad; + } + if (lastArgMatches("NO_NEW_AXIOMS_FROM")) { + i++; + if (!getFullArg(i, "* What statement label match pattern? ")) + goto pclbad; + } + if (lastArgMatches("FORBID")) { + i++; + if (!getFullArg(i, "* What statement label match pattern? ")) + goto pclbad; + } + } else { + break; + } + /*break;*/ /* Break if only 1 switch is allowed */ + } + goto pclgood; + } /* end of MINIMIZE_WITH */ + + if (cmdMatches("EXPAND")) { + if (!getFullArg(1, "* What statement label? ")) goto pclbad; + goto pclgood; + } + + if (cmdMatches("UNIFY")) { + if (!getFullArg(1, + "STEP|ALL|")) goto pclbad; + if (cmdMatches("UNIFY STEP")) { + if (!getFullArg(2, "# What step number? ")) goto pclbad; + goto pclgood; + } + if (cmdMatches("UNIFY ALL")) { + /* Get any switches */ + i = 1; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "INTERACTIVE|", NULL))) + goto pclbad; + } else { + break; + } + break; /* Break if only 1 switch is allowed */ + } + goto pclgood; + } /* End if (cmdMatches("UNIFY ALL")) */ + } + + if (cmdMatches("DELETE")) { + if (!getFullArg(1, + "STEP|ALL|FLOATING_HYPOTHESES|")) goto pclbad; + if (lastArgMatches("STEP")) { + if (!getFullArg(2, "# What step number? ")) goto pclbad; + goto pclgood; + } + goto pclgood; + } + + /*???OBSOLETE???*/ + if (cmdMatches("ADD")) { + if (!getFullArg(1, + "UNIVERSE|")) goto pclbad; + /* Note: further parsing below */ + } + + if (cmdMatches("REPLACE")) { + if (!getFullArg(1, "* What step number, or FIRST, or LAST ? ")) + goto pclbad; + if (!getFullArg(2, "* With what statement label? ")) goto pclbad; + /* Get any switches */ + i = 2; + + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "OVERRIDE|", NULL))) + goto pclbad; + } else { + break; + } + break; /* Break if only 1 switch is allowed */ + } + + goto pclgood; + } + + if (cmdMatches("LET")) { + if (!getFullArg(1, "STEP|VARIABLE|")) goto pclbad; + if (cmdMatches("LET STEP")) { + if (!getFullArg(2, "* What step number, or FIRST, or LAST ? ")) + goto pclbad; + } + if (cmdMatches("LET VARIABLE")) { + if (!getFullArg(2, "* Assign what variable (format $nn)? ")) goto pclbad; + } + if (!getFullArg(3, "=|<=>")) goto pclbad; + if (!getFullArg(4, "* With what math symbol string? ")) + goto pclbad; + goto pclgood; + } + + if (cmdMatches("ASSIGN")) { + if (!getFullArg(1, "* What step number, or FIRST, or LAST ? ")) goto pclbad; + if (!getFullArg(2, "* With what statement label? ")) goto pclbad; + /* Get any switches */ + i = 2; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, "NO_UNIFY|OVERRIDE|")) goto pclbad; + } else { + break; + } + /*break;*/ /* Break if only 1 switch is allowed */ + } + goto pclgood; + } + + if (cmdMatches("UNDO")) { + goto pclgood; + } + + if (cmdMatches("REDO")) { + goto pclgood; + } + + if (cmdMatches("SET")) { + let(&tmpStr, cat( + "WIDTH|HEIGHT|UNDO|ECHO|SCROLL|", + "DEBUG|MEMORY_STATUS|SEARCH_LIMIT|UNIFICATION_TIMEOUT|", + "DISCOURAGEMENT|", + "CONTRIBUTOR|", + "ROOT_DIRECTORY|", + "EMPTY_SUBSTITUTION|JEREMY_HENTY_FILTER|", NULL)); + if (!getFullArg(1,tmpStr)) goto pclbad; + if (cmdMatches("SET DEBUG")) { + if (!getFullArg(2, "FLAG|OFF|")) goto pclbad; + if (lastArgMatches("FLAG")) { + if (!getFullArg(3, "4|5|6|7|8|9|<5>")) goto pclbad; + } + goto pclgood; + } + + if (cmdMatches("SET ECHO")) { + if (g_commandEcho) { + if (!getFullArg(2, "ON|OFF|")) goto pclbad; + } else { + if (!getFullArg(2, "ON|OFF|")) goto pclbad; + } + goto pclgood; + } + + if (cmdMatches("SET SCROLL")) { + if (g_scrollMode == 1) { + if (!getFullArg(2, "CONTINUOUS|PROMPTED|")) goto pclbad; + } else { + if (!getFullArg(2, "CONTINUOUS|PROMPTED|")) goto pclbad; + } + goto pclgood; + } + + if (cmdMatches("SET DISCOURAGEMENT")) { + if (g_globalDiscouragement) { + if (!getFullArg(2, "ON|OFF|")) goto pclbad; + } else { + if (!getFullArg(2, "ON|OFF|")) goto pclbad; + } + goto pclgood; + } + + if (cmdMatches("SET MEMORY_STATUS")) { + if (g_memoryStatus) { + if (!getFullArg(2, "ON|OFF|")) goto pclbad; + } else { + if (!getFullArg(2, "ON|OFF|")) goto pclbad; + } + goto pclgood; + } + + + if (cmdMatches("SET JEREMY_HENTY_FILTER")) { + if (g_hentyFilter) { + if (!getFullArg(2, "ON|OFF|")) goto pclbad; + } else { + if (!getFullArg(2, "ON|OFF|")) goto pclbad; + } + goto pclgood; + } + + if (cmdMatches("SET CONTRIBUTOR")) { + if (!getFullArg(2, cat( + "* What is the contributor name for SAVE (NEW_)PROOF <", + g_contributorName, ">? ", NULL))) + goto pclbad; + goto pclgood; + } + + if (cmdMatches("SET ROOT_DIRECTORY")) { + if (!getFullArg(2, cat( + "* What is the root directory path (use space if none) <", + g_rootDirectory, ">? ", NULL))) + goto pclbad; + goto pclgood; + } + + if (cmdMatches("SET SEARCH_LIMIT")) { + if (!getFullArg(2, cat( + "# What is search limit for IMPROVE command <", + str((double)g_userMaxProveFloat), ">? ", NULL))) + goto pclbad; + goto pclgood; + } + + if (cmdMatches("SET UNIFICATION_TIMEOUT")) { + if (!getFullArg(2, cat( + "# What is maximum number of unification trials <", + str((double)g_userMaxUnifTrials), ">? ", NULL))) + goto pclbad; + goto pclgood; + } + + if (cmdMatches("SET WIDTH")) { + if (!getFullArg(2, cat( + "# What is maximum line length on your screen <", + str((double)g_screenHeight), ">? ", NULL))) + goto pclbad; + goto pclgood; + } + + if (cmdMatches("SET HEIGHT")) { + if (!getFullArg(2, cat( + "# What is number of lines your screen displays <", + str((double)g_screenHeight), ">? ", NULL))) + goto pclbad; + goto pclgood; + } + + if (cmdMatches("SET UNDO")) { + if (!getFullArg(2, cat( + "# What is the maximum number of UNDOs <", + str((double)(processUndoStack(NULL, PUS_GET_SIZE, "", 0))), + ">? ", NULL))) + goto pclbad; + goto pclgood; + } + + if (cmdMatches("SET EMPTY_SUBSTITUTION")) { + if (g_minSubstLen == 0) { + if (!getFullArg(2, "ON|OFF|")) goto pclbad; + } else { + if (!getFullArg(2, "ON|OFF|")) goto pclbad; + } + goto pclgood; + } + + } /* end if SET */ + + if (cmdMatches("ERASE")) { + goto pclgood; + } + + if (cmdMatches("MORE")) { + if (!getFullArg(1, + "* What is the name of the file to display? ")) + goto pclbad; + goto pclgood; + } + + if (cmdMatches("TOOLS")) { + goto pclgood; + } + + if (cmdMatches("VERIFY")) { + if (!getFullArg(1, + "PROOF|MARKUP|STS|")) + goto pclbad; + if (cmdMatches("VERIFY PROOF")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (!getFullArg(2, + "* What are the labels to match (* = wildcard) <*>?")) + goto pclbad; + + /* Get any switches */ + i = 2; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "SYNTAX_ONLY", + "|", NULL))) + goto pclbad; + } else { + break; + } + break; /* Break if only 1 switch is allowed */ + } + + goto pclgood; + } + + if (cmdMatches("VERIFY MARKUP")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (!getFullArg(2, + "* What are the labels to match (* = wildcard) <*>?")) + goto pclbad; + + /* Get any switches */ + i = 2; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "DATE_SKIP|FILE_SKIP|TOP_DATE_SKIP|VERBOSE", + "|FILE_CHECK|TOP_DATE_CHECK", + "|UNDERSCORE_SKIP|MATHBOX_SKIP|", NULL))) + goto pclbad; + } else { + break; + } + /* break; */ /* Break if only 1 switch is allowed */ + } + + goto pclgood; + } + + if (cmdMatches("VERIFY STS")) { + if (g_statements == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (strlen(stsOutput)) { + if (!getFullArg(2,cat("* Using which output mode <",stsOutput,">? ",NULL))) + goto pclbad; + } else { + if (!getFullArg(2,"* Using which output mode ? ")) + goto pclbad; + } + goto pclgood; + } + } + + if (cmdMatches("DBG")) { + /* The debug command fetches an arbitrary 2nd arg in quotes, to be handled + in whatever way is needed for debugging. */ + if (!getFullArg(1, "* What is the debugging string? ")) + goto pclbad; + goto pclgood; + } + + if (cmdMatches("MARKUP")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (!getFullArg(1, + "* What is the name of the input file with markup? ")) + goto pclbad; + if (!getFullArg(2, + "* What is the name of the HTML output file? ")) + goto pclbad; + + /* Get any switches */ + i = 2; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "HTML|ALT_HTML|SYMBOLS|LABELS|NUMBER_AFTER_LABEL|BIB_REFS", + "|UNDERSCORES|CSS|", NULL))) + goto pclbad; + } else { + break; + } + /*break;*/ /* Break if only 1 switch is allowed */ + } + goto pclgood; + } + + if (cmdMatches("MIDI")) { + if (g_sourceHasBeenRead == 0) { + print2("?No source file has been read in. Use READ first.\n"); + goto pclbad; + } + if (!getFullArg(1, + "* Statement label to create MIDI for (* matches any substring) <*>?")) + goto pclbad; + /* Get any switches */ + i = 1; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat("PARAMETER|", NULL))) + goto pclbad; + i++; + if (!getFullArg(i, + "* What is the parameter string ?")) + goto pclbad; + } else { + break; + } + break; /* Break if only 1 switch is allowed */ + } + goto pclgood; + } + + if (cmdMatches("EXIT") || cmdMatches("QUIT") || cmdMatches("_EXIT_PA")) { + + /* Get any switches */ + i = 0; + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "FORCE|", NULL))) + goto pclbad; + } else { + break; + } + break; /* Break if only 1 switch is allowed */ + } /* End while for switch loop */ + + goto pclgood; + } + + } else { /* g_toolsMode */ + /* Text tools mode */ + let(&tmpStr, cat( + "HELP|SUBMIT|", + "ADD|DELETE|SUBSTITUTE|S|SWAP|CLEAN|INSERT|BREAK|BUILD|MATCH|SORT|", + "UNDUPLICATE|DUPLICATE|UNIQUE|REVERSE|RIGHT|PARALLEL|NUMBER|COUNT|", + "COPY|C|TYPE|T|TAG|UPDATE|BEEP|B|EXIT|QUIT|", NULL)); + if (!getFullArg(0,tmpStr)) + goto pclbad; + + if (cmdMatches("HELP")) { + if (!getFullArg(1, cat( + "ADD|DELETE|SUBSTITUTE|S|SWAP|CLEAN|INSERT|BREAK|BUILD|MATCH|SORT|", + "UNDUPLICATE|DUPLICATE|UNIQUE|REVERSE|RIGHT|PARALLEL|NUMBER|COUNT|", + "TYPE|T|TAG|UPDATE|BEEP|B|EXIT|QUIT|", + "COPY|C|SUBMIT|SYSTEM|CLI|", + "$|<$>", NULL))) goto pclbad; + goto pclgood; + } + if (cmdMatches("ADD") || cmdMatches("TAG")) { + if (!getFullArg(1, "& Input/output file? ")) + goto pclbad; + if (!getFullArg(2, "* String to add to beginning of each line <>? ")) + goto pclbad; + if (!getFullArg(3, "* String to add to end of each line <>? ")) + goto pclbad; + if (cmdMatches("TAG")) { + if (!getFullArg(4, + "* String to match to start range (null = any line) <>? ")) + goto pclbad; + if (!getFullArg(5, + "# Which occurrence of start match to start range <1>? ")) + goto pclbad; + if (!getFullArg(6, + "* String to match to end range (null = any line) <>? ")) + goto pclbad; + if (!getFullArg(7, + "# Which occurrence of end match to end range <1>? ")) + goto pclbad; + } + goto pclgood; + } + if (cmdMatches("DELETE")) { + if (!getFullArg(1, "& Input/output file? ")) + goto pclbad; + if (!getFullArg(2, +"* String from which to start deleting (CR = beginning of line) <>? ")) + goto pclbad; + if (!getFullArg(3, +"* String at which to stop deleting (CR = end of line) <>? ")) + goto pclbad; + goto pclgood; + } + if (cmdMatches("CLEAN")) { + if (!getFullArg(1, "& Input/output file? ")) + goto pclbad; + if (!getFullArg(2, + "* Subcommand(s) (D,B,E,R,Q,T,U,P,G,C,L,V) ? ")) + goto pclbad; + goto pclgood; + } + if (cmdMatches("SWAP")) { + if (!getFullArg(1, "& Input/output file? ")) + goto pclbad; + if (!getFullArg(2, +"* Character string to match between the halves to be swapped? ")) + goto pclbad; + goto pclgood; + } + if (cmdMatches("SUBSTITUTE") || cmdMatches("S")) { + if (!getFullArg(1, "& Input/output file? ")) + goto pclbad; + if (!getFullArg(2, "* String to replace? ")) + goto pclbad; + if (!getFullArg(3, "* Replace it with <>? ")) + goto pclbad; + if (!getFullArg(4, +"* Which occurrence in the line (1,2,... or ALL or EACH) <1>? ")) + goto pclbad; + if (!getFullArg(5, +"* Additional match required on line (null = match all) <>? ")) + goto pclbad; + goto pclgood; + } + + if (cmdMatches("INSERT")) { + if (!getFullArg(1, "& Input/output file? ")) + goto pclbad; + if (!getFullArg(2, "* String to insert in each line ? ")) + goto pclbad; + if (!getFullArg(3, "# Column at which to insert the string <1>? ")) + goto pclbad; + goto pclgood; + } + if (cmdMatches("BREAK")) { + if (!getFullArg(1, "& Input/output file? ")) + goto pclbad; + if (!getFullArg(2, + "* Special characters to use as token delimiters <()[],=:;{}>? ")) + goto pclbad; + goto pclgood; + } + if (cmdMatches("MATCH")) { + if (!getFullArg(1, "& Input/output file? ")) + goto pclbad; + if (!getFullArg(2, +"* String to match on each line (null = any non-blank line) <>? ")) + goto pclbad; + if (!getFullArg(3, +"* Output those lines containing the string (Y) or those not (N) ? ")) + goto pclbad; + goto pclgood; + } + if (cmdMatches("SORT")) { + if (!getFullArg(1, "& Input/output file? ")) + goto pclbad; + if (!getFullArg(2, + "* String to start key on each line (null string = column 1) <>? ")) + goto pclbad; + goto pclgood; + } + if (cmdMatches("UNDUPLICATE") || cmdMatches("DUPLICATE") || + cmdMatches("UNIQUE") || cmdMatches("REVERSE") || cmdMatches("BUILD") + || cmdMatches("RIGHT")) { + if (!getFullArg(1, "& Input/output file? ")) + goto pclbad; + goto pclgood; + } + + if (cmdMatches("COUNT")) { + if (!getFullArg(1, "& Input file? ")) + goto pclbad; + if (!getFullArg(2, +"* String to count <;>? ")) + goto pclbad; + goto pclgood; + } + + if (cmdMatches("COPY") || cmdMatches("C")) { + if (!getFullArg(1, "* Comma-separated list of input files? ")) + goto pclbad; + if (!getFullArg(2, "* Output file? ")) + goto pclbad; + goto pclgood; + } + + + if (cmdMatches("NUMBER")) { + if (!getFullArg(1, "* Output file ? ")) + goto pclbad; + if (!getFullArg(2, "# First number <1>? ")) + goto pclbad; + if (!getFullArg(3, "# Last number <10>? ")) + goto pclbad; + if (!getFullArg(4, "# Increment <1>? ")) + goto pclbad; + goto pclgood; + } + if (cmdMatches("TYPE") || cmdMatches("T")) { + if (!getFullArg(1, "& File to display on the screen? ")) + goto pclbad; + if (!getFullArg(2, "* Num. lines to type or ALL (nothing = 10) <$>? ")) + goto pclbad; + goto pclgood; + } + + + if (cmdMatches("UPDATE")) { + print2( +"Warning: Do not comment out code - delete it before running UPDATE! If\n"); + print2( +"rerunning UPDATE, do not tamper with \"start/end of deleted section\" comments!\n"); + print2( +"Edit out tag on header comment line! Review the output file!\n"); + if (!getFullArg(1, "& Original (reference) program input file? ")) + goto pclbad; + if (!getFullArg(2, "& Edited program input file? ")) + goto pclbad; + if (!getFullArg(3, cat( +"* Edited program output file with revisions tagged <", + g_fullArg[2], ">? ", NULL))) + goto pclbad; + if (!strcmp(g_fullArg[2], g_fullArg[3])) { + print2( +"The input file will be renamed %s~1.\n", g_fullArg[2]); + } + if (!getFullArg(4, + cat("* Revision tag for added lines ? ", NULL))) + goto pclbad; + if (!getFullArg(5, +"# Successive lines required for match (more = better sync) <3>? ")) + goto pclbad; + goto pclgood; + } + + if (cmdMatches("PARALLEL")) { + if (!getFullArg(1, "& Left file? ")) + goto pclbad; + if (!getFullArg(2, "& Right file? ")) + goto pclbad; + if (!getFullArg(3, cat("* Output file <", + g_fullArg[1], ">? ", NULL))) + goto pclbad; + if (!getFullArg(4, + cat("* String to insert between the 2 input lines <>? ", NULL))) + goto pclbad; + goto pclgood; + } + + /* g_toolsMode - no qualifiers for EXIT */ + if (cmdMatches("EXIT") || cmdMatches("QUIT")) { + goto pclgood; + } + + + } /* if !g_toolsMode ... else ... */ + + if (cmdMatches("SUBMIT")) { + if (g_toolsMode) { + let(&tmpStr, " "); + } else { + let(&tmpStr, " "); + } + if (!getFullArg(1, cat("& What is the name of command file to run", + tmpStr, "? ", NULL))) { + goto pclbad; + } + + /* Get any switches */ + i = 1; /* Number of command words before switch */ + while (1) { + i++; + if (!getFullArg(i, "/|$|<$>")) goto pclbad; + if (lastArgMatches("/")) { + i++; + if (!getFullArg(i, cat( + "SILENT", + "|", NULL))) + goto pclbad; + } else { + break; + } + break; /* Break if only 1 switch is allowed */ + } /* End while for switch loop */ + + goto pclgood; + } + + if (cmdMatches("BEEP") || cmdMatches("B")) { + goto pclgood; + } + + /* Command in master list but not intercepted -- really a bug */ + print2("?This command has not been implemented yet.\n"); + print2("(This is really a bug--please report it.)\n"); + goto pclbad; + + /* Should never get here */ + + + + pclgood: + + /* Strip off the last g_fullArg if a null argument was added by getFullArg + in the case when "$" (nothing) is allowed */ + if (!strcmp(g_fullArg[pntrLen(g_fullArg) - 1], chr(3))) { + let((vstring *)(&g_fullArg[pntrLen(g_fullArg) - 1]), ""); /* Deallocate */ + pntrLet(&g_fullArg, pntrLeft(g_fullArg, pntrLen(g_fullArg) - 1)); + } + + if (pntrLen(g_fullArg) > g_rawArgs) bug(1102); + if (pntrLen(g_fullArg) < g_rawArgs) { + let(&tmpStr, cat("?Too many arguments. Use quotes around arguments with special", + " characters and around Unix file names with \"/\"s.", NULL)); + printCommandError(cat(g_commandPrompt, g_commandLine, NULL), pntrLen(g_fullArg), + tmpStr); + goto pclbad; + } + + /* Create a single string containing the g_fullArg tokens */ + let(&g_fullArgString, ""); + for (i = 0; i < pntrLen(g_fullArg); i++) { + let(&g_fullArgString, cat(g_fullArgString, " ", g_fullArg[i], NULL)); + } + let(&g_fullArgString, right(g_fullArgString, 2)); /* Strip leading space */ + + + /* Deallocate memory */ + let(&defaultArg, ""); + let(&tmpStr, ""); + return (1); + + pclbad: + /* Deallocate memory */ + let(&defaultArg, ""); + let(&tmpStr, ""); + return (0); + +} /* processCommandLine */ + + + +flag getFullArg(long arg, vstring cmdList1) +{ + /* This function converts the user's abbreviated keyword in + g_rawArgPntr[arg] to a full, upper-case keyword, + in g_fullArg[arg], matching + the available choices in cmdList. */ + /* Special cases: cmdList = "# xxx ?" - get an integer */ + /* cmdList = "* xxx ?" - get any string; + don't convert to upper case + cmdList = "& xxx ?" - same as * except + verify it is a file that exists */ + /* "$" means a null argument is acceptable; put it in as + special character chr(3) so it can be recognized */ + + pntrString *possCmd = NULL_PNTRSTRING; + long possCmds, i, j, k, m, p, q; + vstring defaultCmd = ""; + vstring infoStr = ""; + vstring tmpStr = ""; + vstring tmpArg = ""; + vstring errorLine = ""; + vstring keyword = ""; + vstring cmdList = ""; + FILE *tmpFp; + + let(&cmdList,cmdList1); /* In case cmdList1 gets deallocated when it comes + directly from a vstring function such as cat() */ + + let(&errorLine, cat(g_commandPrompt,g_commandLine, NULL)); + + /* Handle special case - integer expected */ + if (cmdList[0] == '#') { + let(&defaultCmd, + seg(cmdList,instr(1,cmdList, "<"),instr(1,cmdList, ">"))); + + /* If the argument has not been entered, prompt the user for it */ + if (g_rawArgs <= arg) { + pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); + nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, 0)); + g_rawArgs++; + if (g_rawArgs <= arg) bug(1103); + + g_queryMode = 1; + tmpArg = cmdInput1(right(cmdList,3)); + let(&errorLine,right(cmdList,3)); + if (tmpArg[0] == 0) { /* Use default argument */ + let(&tmpArg, seg(defaultCmd,2,len(defaultCmd) - 1)); + } + let((vstring *)(&g_rawArgPntr[arg]), tmpArg); + g_rawArgNmbr[arg] = len(cmdList) - 1;/* Line position for error msgs */ + + } /* End of asking user for additional argument */ + + /* Make sure that the argument is a non-negative integer */ + let(&tmpArg,g_rawArgPntr[arg]); + if (tmpArg[0] == 0) { /* Use default argument */ + /* (This code is needed in case of null string passed directly) */ + let(&tmpArg, seg(defaultCmd,2,len(defaultCmd) - 1)); + } + let(&tmpStr, str(val(tmpArg))); + let(&tmpStr, cat(string(len(tmpArg)-len(tmpStr),'0'), tmpStr, NULL)); + if (strcmp(tmpStr, tmpArg)) { + printCommandError(errorLine, arg, + "?A number was expected here."); + goto return0; + } + + let(&keyword, str(val(tmpArg))); + goto return1; + } + + + + /* Handle special case - any arbitrary string is OK */ + /* '*' means any string, '&' means a file */ + /* However, "|$<$>" also allows null string (no argument) */ + if (cmdList[0] == '*' || cmdList[0] == '&') { + let(&defaultCmd, + seg(cmdList,instr(1,cmdList, "<"),instr(1,cmdList, ">"))); + + /* If the argument has not been entered, prompt the user for it */ + if (g_rawArgs <= arg) { + if (!strcmp(defaultCmd, "<$>")) { /* End of command acceptable */ + /* Note: in this case, user will never be prompted for anything. */ + let(&keyword,chr(3)); + goto return1; + } + g_rawArgs++; + pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); + nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, 0)); + if (g_rawArgs <= arg) bug(1104); + g_queryMode = 1; + tmpArg = cmdInput1(right(cmdList,3)); + + /* Strip off any quotes around it + and tolerate lack of trailing quote */ + /******* (This is no longer done - it is confusing to the user.) + if (tmpArg[0] == '\'' || tmpArg[0] == '\"') { + if (tmpArg[0] == tmpArg[len(tmpArg) - 1]) { + let(&tmpArg, right(left(tmpArg, len(tmpArg) - 1), 2)); + } else { + let(&tmpArg, right(tmpArg, 2)); + } + } + *******/ + + let(&errorLine,right(cmdList,3)); + if (tmpArg[0] == 0) { /* Use default argument */ + let(&tmpArg, seg(defaultCmd,2,len(defaultCmd) - 1)); + } + let((vstring *)(&g_rawArgPntr[arg]), tmpArg); + g_rawArgNmbr[arg] = len(cmdList) - 1; /* Line position for error msgs */ + + } /* End of asking user for additional argument */ + + let(&keyword,g_rawArgPntr[arg]); + + /* Convert abbreviations of FIRST, LAST, ALL to + full keywords. The rest of the program works fine without doing this, + but it provides better cosmetic appearance when the command is echoed + such as in during the UNDO command. */ + if (cmdList[0] == '*') { + if ((keyword[0] == 'f' || keyword[0] == 'F') + && instr(1, cmdList, " FIRST") != 0) + let(&keyword, "FIRST"); + if ((keyword[0] == 'l' || keyword[0] == 'L') + && instr(1, cmdList, " LAST") != 0) + let(&keyword, "LAST"); + if ((keyword[0] == 'a' || keyword[0] == 'A') + && instr(1, cmdList, " ALL") != 0) + let(&keyword, "ALL"); + } + + if (keyword[0] == 0) { /* Use default argument */ + /* This case handles blank arguments on completely input command line */ + let(&keyword, seg(defaultCmd,2,len(defaultCmd) - 1)); + } + if (cmdList[0] == '&') { + /* See if file exists */ + let(&tmpStr, cat(g_rootDirectory, keyword, NULL)); + tmpFp = fopen(tmpStr, "r"); + if (!tmpFp) { + let(&tmpStr, cat("?Sorry, couldn't open the file \"", tmpStr, "\".", NULL)); + printCommandError(errorLine, arg, tmpStr); + goto return0; + } + fclose(tmpFp); + } + goto return1; + } + + + + /* Parse the choices available */ + possCmds = 0; + p = 0; + while (1) { + q = p; + p = instr(p + 1, cat(cmdList, "|", NULL), "|"); + if (!p) break; + pntrLet(&possCmd,pntrAddElement(possCmd)); + let((vstring *)(&possCmd[possCmds]),seg(cmdList,q+1,p-1)); + possCmds++; + } + if (!strcmp(left(possCmd[possCmds - 1],1), "<")) { + /* Get default argument, if any */ + defaultCmd = possCmd[possCmds - 1]; /* re-use old allocation */ + if (!strcmp(defaultCmd, "<$>")) { + let(&defaultCmd, ""); + } + pntrLet(&possCmd,pntrLeft(possCmd,possCmds - 1)); + possCmds--; + } + if (!strcmp(possCmd[possCmds - 1], "$")) { + /* Change "$" to "nothing" for printouts */ + let((vstring *)(&possCmd[possCmds - 1]), "nothing"); + } + + /* Create a string used for queries and error messages */ + if (possCmds < 1) bug(1105); + if (possCmds == 1) { + let(&infoStr,possCmd[0]); + } + if (possCmds == 2) { + let(&infoStr, cat(possCmd[0], " or ", + possCmd[1], NULL)); + } + if (possCmds > 2) { + let(&infoStr, ""); + for (i = 0; i < possCmds - 1; i++) { + let(&infoStr, cat(infoStr,possCmd[i], ", ", NULL)); + } + let(&infoStr, cat(infoStr, "or ",possCmd[possCmds - 1], NULL)); + } + + /* If the argument has not been entered, prompt the user for it */ + if (g_rawArgs <= arg && (strcmp(possCmd[possCmds - 1], "nothing") + || g_queryMode == 1)) { + + let(&tmpStr, infoStr); + if (defaultCmd[0] != 0) { + let(&tmpStr, cat(tmpStr, " ",defaultCmd, NULL)); + } + let(&tmpStr, cat(tmpStr, "? ", NULL)); + g_queryMode = 1; + if (possCmds != 1) { + tmpArg = cmdInput1(tmpStr); + } else { + /* There is only one possibility, so don't ask user */ + /* Don't print the message when "end-of-list" is the only possibility. */ + if (!strcmp(cmdList, "$|<$>")) { + let(&tmpArg, possCmd[0]); + print2("The command so far is: "); + for (i = 0; i < arg; i++) { + print2("%s ", g_fullArg[i]); + } + print2("%s\n", tmpArg); + } + } + let(&errorLine,tmpStr); + if (tmpArg[0] == 0) { /* Use default argument */ + let(&tmpArg, seg(defaultCmd,2,len(defaultCmd) - 1)); + } + + if (strcmp(tmpArg, "nothing")) { + pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); + nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, 0)); + g_rawArgs++; + if (g_rawArgs <= arg) bug(1106); + let((vstring *)(&g_rawArgPntr[arg]), tmpArg); + g_rawArgNmbr[arg] = len(tmpStr) + 1; /* Line position for error msgs */ + } + + } /* End of asking user for additional argument */ + + if (g_rawArgs <= arg) { + /* No argument was specified, and "nothing" is a valid argument */ + let(&keyword,chr(3)); + goto return1; + } + + + let(&tmpArg,edit(g_rawArgPntr[arg], 32)); /* Convert to upper case */ + j = 0; + k = 0; + m = len(tmpArg); + let(&tmpStr, ""); + /* Scan the possible arguments for a match */ + for (i = 0; i < possCmds; i++) { + if (!strcmp(possCmd[i], tmpArg)) { + /* An exact match was found, so ignore any other matches + and use this one */ + k = 1; + j = i; + break; + } + if (!strcmp(left(possCmd[i], m), tmpArg)) { + if (!k) { + let(&tmpStr, possCmd[i]); + } else { + let(&tmpStr, cat(tmpStr, ", ", possCmd[i], NULL)); + } + j = i; /* Save match position */ + k++; /* Number of matches */ + } + } + if (k < 1 || k > 1) { + if (k < 1) { + let(&tmpStr, cat("?Expected ", infoStr, ".", NULL)); + } else { + if (k == 2) { + p = instr(1,tmpStr, ", "); + let(&tmpStr, cat(left(tmpStr,p-1), " or",right(tmpStr,p+1), NULL)); + } else { + p = len(tmpStr) - 1; + while (tmpStr[p] != ',') p--; + let(&tmpStr, cat(left(tmpStr,p+1), " or",right(tmpStr,p+2), NULL)); + } + let(&tmpStr, cat("?Ambiguous keyword - please specify ",tmpStr, ".", NULL)); + } + printCommandError(errorLine, arg, tmpStr); + goto return0; + } + + let(&keyword,possCmd[j]); + goto return1; + + return1: + if (keyword[0] == 0) { + if (g_rawArgs > arg && strcmp(defaultCmd, "<>")) { + /* otherwise, "nothing" was specified */ + printCommandError("", arg, + "?No default answer is available - please be explicit."); + goto return0; + } + } + /* Add new field to g_fullArg */ + pntrLet(&g_fullArg,pntrAddElement(g_fullArg)); + if (pntrLen(g_fullArg) != arg + 1) bug(1107); + let((vstring *)(&g_fullArg[arg]),keyword); + + /* Deallocate memory */ + j = pntrLen(possCmd); + for (i = 0; i < j; i++) let((vstring *)(&possCmd[i]), ""); + pntrLet(&possCmd, NULL_PNTRSTRING); + let(&defaultCmd, ""); + let(&infoStr, ""); + let(&tmpStr, ""); + let(&tmpArg, ""); + let(&errorLine, ""); + let(&keyword, ""); + let(&cmdList, ""); + return(1); + + return0: + /* Deallocate memory */ + j = pntrLen(possCmd); + for (i = 0; i < j; i++) let((vstring *)(&possCmd[i]), ""); + pntrLet(&possCmd, NULL_PNTRSTRING); + let(&defaultCmd, ""); + let(&infoStr, ""); + let(&tmpStr, ""); + let(&tmpArg, ""); + let(&errorLine, ""); + let(&keyword, ""); + let(&cmdList, ""); + return(0); + +} /* getFullArg */ + + + +void parseCommandLine(vstring line) +{ + /* This function breaks up line into individual tokens + and puts them into g_rawArgPntr[]. g_rawArgs is the number of tokens. + g_rawArgPntr[] is the starting position of each token on the line; + the first character on the line has position 1, not 0. + + Spaces, tabs, and newlines are considered white space. Special + one-character + tokens don't have to be surrounded by white space. Characters + inside quotes are considered to be one token, and the quotes are + removed. + + */ + /* Warning: Don't deallocate these vstring constants */ + /*vstring specialOneCharTokens = "()/,=:";*/ + vstring tokenWhiteSpace = " \t\n"; + vstring tokenComment = "!"; + + + vstring tmpStr = ""; /* Dummy vstring to clean up temp alloc stack */ + flag mode; + long tokenStart, i, p, lineLen; + + vstring specialOneCharTokens = ""; + + /* Initialization to avoid compiler warning (should not be theoretically + necessary) */ + tokenStart = 0; + + if (!g_toolsMode) { + let(&specialOneCharTokens, "/="); /* List of special one-char tokens */ + } else { + let(&specialOneCharTokens, ""); + } + + lineLen = len(line); + /* mode: 0 means look for start of token, 1 means look for end of + token, 2 means look for trailing single quote, 3 means look for + trailing double quote */ + /* only "!" at beginning of line acts as comment. + This is done because sometimes ! might be legal as part of a command */ + mode = 0; + for (p = 0; p < lineLen; p++) { + let(&tmpStr, ""); /* Clean up temp alloc stack to prevent overflow */ + if (mode == 0) { + /* If character is white space, ignore it */ + if (instr(1,tokenWhiteSpace,chr(line[p]))) { + continue; + } + /* If character is comment, we're done */ + if (p == 0 && instr(1,tokenComment,chr(line[p]))) { + break; + } + /* If character is a special token, get it but don't change mode */ + if (instr(1,specialOneCharTokens,chr(line[p]))) { + pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); + nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, p+1)); + /* Save token start */ + let((vstring *)(&g_rawArgPntr[g_rawArgs]), chr(line[p])); + g_rawArgs++; + continue; + } + /* If character is a quote, set start and change mode */ + if (line[p] == '\'') { + mode = 2; + tokenStart = p + 2; + continue; + } + if (line[p] == '\"') { + mode = 3; + tokenStart = p + 2; + continue; + } + /* Character must be start of a token */ + mode = 1; + tokenStart = p + 1; + continue; + } + if (mode == 1) { + /* If character is white space, end token and change mode */ + if (instr(1,tokenWhiteSpace,chr(line[p]))) { + pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); + nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, tokenStart)); + /* Save token start */ + let((vstring *)(&g_rawArgPntr[g_rawArgs]), seg(line, tokenStart, p)); + g_rawArgs++; + mode = 0; + continue; + } + + /* If character is a special token, get it and change mode */ + if (instr(1,specialOneCharTokens,chr(line[p]))) { + pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); + nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, tokenStart)); + /* Save token start */ + let((vstring *)(&g_rawArgPntr[g_rawArgs]),seg(line, tokenStart, p)); + g_rawArgs++; + pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); + nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, p + 1)); + /* Save token start */ + let((vstring *)(&g_rawArgPntr[g_rawArgs]), chr(line[p])); + g_rawArgs++; + mode = 0; + continue; + } + + /* If character is a quote, set start and change mode */ + if (line[p] == '\'') { + pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); + nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, tokenStart)); + /* Save token start */ + let((vstring *)(&g_rawArgPntr[g_rawArgs]),seg(line, tokenStart,p)); + g_rawArgs++; + mode = 2; + tokenStart = p + 2; + continue; + } + if (line[p] == '\"') { + pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); + nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, tokenStart)); + /* Save token start */ + let((vstring *)(&g_rawArgPntr[g_rawArgs]),seg(line, tokenStart,p)); + g_rawArgs++; + mode = 3; + tokenStart = p + 2; + continue; + } + /* Character must be continuation of the token */ + continue; + } + if (mode == 2 || mode == 3) { + /* If character is a quote, end quote and change mode */ + if (line[p] == '\'' && mode == 2) { + mode = 0; + pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); + nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, tokenStart)); + /* Save token start */ + let((vstring *)(&g_rawArgPntr[g_rawArgs]), seg(line,tokenStart,p)); + g_rawArgs++; + continue; + } + if (line[p] == '\"' && mode == 3) { + mode = 0; + pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); + nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, tokenStart)); + /* Save token start */ + let((vstring *)(&g_rawArgPntr[g_rawArgs]),seg(line, tokenStart,p)); + g_rawArgs++; + continue; + } + /* Character must be continuation of quoted token */ + continue; + } + } + + /* Finished scanning the line. Finish processing last token. */ + if (mode != 0) { + pntrLet(&g_rawArgPntr, pntrAddElement(g_rawArgPntr)); + nmbrLet(&g_rawArgNmbr, nmbrAddElement(g_rawArgNmbr, tokenStart)); + /* Save token start */ + let((vstring *)(&g_rawArgPntr[g_rawArgs]),seg(line,tokenStart,p)); + g_rawArgs++; + } + + /* Add length of command line prompt to each argument, to + align the error message pointer */ + for (i = 0; i < g_rawArgs; i++) { + g_rawArgNmbr[i] = g_rawArgNmbr[i] + len(g_commandPrompt); + } + + /* Deallocate */ + let(&specialOneCharTokens, ""); +} /* parseCommandLine */ + + +flag lastArgMatches(vstring argString) +{ + /* This functions checks to see if the last field was argString */ + if (!strcmp(argString, g_fullArg[pntrLen(g_fullArg)-1])) { + return (1); + } else { + return (0); + } +} /* lastArgMatches */ + +flag cmdMatches(vstring cmdString) +{ + /* This function checks that fields 0 through n of g_fullArg match + cmdString (separated by spaces). */ + long i, j, k; + vstring tmpStr = ""; + /* Count the number of spaces */ + k = len(cmdString); + j = 0; + for (i = 0; i < k; i++) { + if (cmdString[i] == ' ') j++; + } + k = pntrLen(g_fullArg); + for (i = 0; i <= j; i++) { + if (j >= k) { + /* Command to match is longer than the user's command; assume no match */ + let(&tmpStr, ""); + return (0); + } + let(&tmpStr, cat(tmpStr, " ", g_fullArg[i], NULL)); + } + if (!strcmp(cat(" ", cmdString, NULL), tmpStr)) { + let(&tmpStr, ""); + return (1); + } else { + let(&tmpStr, ""); + return (0); + } +} /* cmdMatches */ + + +long switchPos(vstring swString) +{ + /* This function checks that fields i through j of g_fullArg match + swString (separated by spaces). The first character of swString + should be "/" and must be separated from the first field + of swString with a space. The position of the "/" in g_fullArg + is returned if swString is there, otherwise 0 is returned (the first + position in g_fullArg is considered 1, not 0). */ + /* Example: if g_fullArg (combined into one string) is + "DISPLAY PROOF / UNKNOWN / START_STEP = 10 / ESSENTIAL" + and swString is "/ START_STEP", switchPos will return 5. */ + long i, j, k; + vstring tmpStr = ""; + vstring swString1 = ""; + + if (swString[0] != '/') bug(1108); + + /* Add a space after the "/" if there is none */ + if (swString[1] != ' ') { + let(&swString1, cat("/ ", right(swString,2), " ", NULL)); + } else { + let(&swString1,swString); + } + + /* Build the complete command */ + k = pntrLen(g_fullArg); + for (i = 0; i < k; i++) { + let(&tmpStr, cat(tmpStr,g_fullArg[i], " ", NULL)); + } + + k = instr(1,tmpStr,swString1); + if (!k) { + let(&swString1, ""); + let(&tmpStr, ""); + return (0); + } + + let(&tmpStr,left(tmpStr,k)); + /* Count the number of spaces - it will be the g_fullArg position */ + k = len(tmpStr); + j = 0; + for (i = 0; i < k; i++) { + if (tmpStr[i] == ' ') j++; + } + let(&tmpStr, ""); + let(&swString1, ""); + return (j + 1); +} /* switchPos */ + + +void printCommandError(vstring line1, long arg, vstring errorMsg) +{ + /* Warning: errorMsg should not a temporarily allocated string such + as the direct output of cat() */ + vstring errorPointer = ""; + vstring line = ""; + long column, tokenLength, j; + + let(&line,line1); /* Prevent deallocation in case line1 is + direct return from string function such as cat() */ + if (!line[0]) { + /* Empty line - don't print an error pointer */ + print2("%s\n", errorMsg); + let(&line, ""); + return; + } + column = g_rawArgNmbr[arg]; + tokenLength = len(g_rawArgPntr[arg]); + for (j = 0; j < column - 1; j++) { + /* Make sure that tabs on the line with the error are accounted for so + that the error pointer lines up correctly */ + if (j >= len(line)) bug(1109); + if (line[j] == '\t') { + let(&errorPointer, cat(errorPointer, "\t", NULL)); + } else { + if (line[j] == '\n') { + let(&errorPointer, ""); + } else { + let(&errorPointer, cat(errorPointer, " ", NULL)); + } + } + } + for (j = 0; j < tokenLength; j++) + let(&errorPointer, cat(errorPointer, "^", NULL)); + print2("%s\n", errorPointer); + printLongLine(errorMsg, "", " "); + let(&errorPointer, ""); + let(&line, ""); +} /* printCommandError */ + +void freeCommandLine() { + long i, j; + j = pntrLen(g_rawArgPntr); + for (i = 0; i < j; i++) let((vstring *)(&g_rawArgPntr[i]), ""); + j = pntrLen(g_fullArg); + for (i = 0; i < j; i++) let((vstring *)(&g_fullArg[i]), ""); + pntrLet(&g_fullArg, NULL_PNTRSTRING); + pntrLet(&g_rawArgPntr, NULL_PNTRSTRING); + nmbrLet(&g_rawArgNmbr, NULL_NMBRSTRING); + let(&g_fullArgString, ""); +} diff --git a/mmcmds.c b/mmcmds.c index 0fb92053..a5d2405f 100644 --- a/mmcmds.c +++ b/mmcmds.c @@ -1,6275 +1,6280 @@ -/*****************************************************************************/ -/* Copyright (C) 2020 NORMAN MEGILL nm at alum.mit.edu */ -/* License terms: GNU General Public License */ -/*****************************************************************************/ -/*34567890123456 (79-character line to adjust editor window) 2345678901234567*/ - -/* mmcmds.c - assorted user commands */ - -#include -#include -#include -#include -#include -#include -#include /* For clock() */ -#include "mmvstr.h" -#include "mmdata.h" -#include "mmcmdl.h" /* For g_texFileName */ -#include "mmcmds.h" -#include "mminou.h" -#include "mmpars.h" -#include "mmveri.h" -#include "mmwtex.h" /* For g_htmlVarColor,... */ -#include "mmpfas.h" -#include "mmunif.h" /* For g_bracketMatchInit, g_minSubstLen, - ...and g_firstConst */ - -/* Local prototypes */ -vstring bigAdd(vstring bignum1, vstring bignum2); -vstring bigSub(vstring bignum1, vstring bignum2); - -flag g_printHelp = 0; - -/* For HTML output */ -vstring g_printStringForReferencedBy = ""; - -/* For MIDI */ -flag g_midiFlag = 0; -vstring g_midiParam = ""; - -/* Type (i.e. print) a statement */ -void typeStatement(long showStmt, - flag briefFlag, - flag commentOnlyFlag, - flag texFlag, - flag htmlFlg) -{ - /* From HELP SHOW STATEMENT: Optional qualifiers: - / TEX - This qualifier will write the statement information to the - LaTeX file previously opened with OPEN TEX. - [Note: texFlag=1 and htmlFlg=0 with this qualifier.] - - / HTML - This qualifier will write the statement information to the - HTML file previously opened with OPEN HTML. - [Note: texFlag=1 and htmlFlg=1 with this qualifier.] - - / COMMENT_ONLY - This qualifier will show only the comment that - immediatley precedes the statement. This is useful when you are - using Metamath to preprocess LaTeX source you have created (see - HELP TEX) - - / BRIEF - This qualifier shows the statement and its $e hypotheses - only. - */ - long i, j, k, m, n; - vstring str1 = "", str2 = "", str3 = ""; - nmbrString *nmbrTmpPtr1; /* Pointer only; not allocated directly */ - nmbrString *nmbrTmpPtr2; /* Pointer only; not allocated directly */ - nmbrString *nmbrDDList = NULL_NMBRSTRING; - flag q1, q2; - flag type; - flag subType; - vstring htmlDistinctVars = ""; - char htmlDistinctVarsCommaFlag = 0; - vstring str4 = ""; - vstring str5 = ""; - long distVarGrps = 0; - - /* For syntax breakdown of definitions in HTML page */ - long zapStatement1stToken; - static long wffToken = -1; /* array index of the hard-coded token "wff" - - static so we only have to look it up once - set to -2 if not found */ - - subType = 0; /* Assign to prevent compiler warnings - not theor. necessary */ - - if (!showStmt) bug(225); /* Must be 1 or greater */ - - if (!commentOnlyFlag && !briefFlag) { - assignStmtFileAndLineNum(showStmt); - let(&str1, cat("Statement ", str((double)showStmt), - " is located on line ", str((double)(g_Statement[showStmt].lineNum)), - " of the file ", NULL)); - if (!texFlag) { - assignMathboxInfo(); /* In case it hasn't been assigned yet */ - /* We need to call assignMathboxInfo() to do the initial assignment, - in order to prevent "let(&" from executing during the - getMathboxUser() call below, which would corrupt the "cat()" - temporary stack (since "let(&" empties the stack). */ - printLongLine(cat(str1, - "\"", g_Statement[showStmt].fileName, - "\".", - (g_Statement[showStmt].pinkNumber == 0) ? /* !=0 means $a or $p */ - "" : - cat(" Its statement number for HTML pages is ", - str((double)(g_Statement[showStmt].pinkNumber)), ".", NULL), - ((getMathboxUser(showStmt))[0] == 0) ? - "" : - cat(" It is in the mathbox for ", getMathboxUser(showStmt), ".", - NULL), - NULL), "", " "); - } else { - if (!htmlFlg) let(&g_printString, ""); - g_outputToString = 1; /* Flag for print2 to add to g_printString */ - /* Note that printTexLongMathString resets it */ - if (!(htmlFlg && texFlag)) { - /* - printLongLine(cat(str1, "{\\tt ", - asciiToTt(g_Statement[showStmt].fileName), - "}.", NULL), "", " "); - */ - } else { - /* For categorizing html pages, we use the source file convention - that syntax statements don't start with "|-" and that axioms - have labels starting with "ax-". It is up to the database - creator to follow this standard, which is not enforced. */ -#define SYNTAX 1 -#define DEFINITION 2 -#define AXIOM 3 -#define THEOREM 4 - if (g_Statement[showStmt].type == (char)p_) { - subType = THEOREM; - } else { - /* Must be a_ due to filter in main() */ - if (g_Statement[showStmt].type != (char)a_) bug(228); - if (strcmp("|-", g_MathToken[ - (g_Statement[showStmt].mathString)[0]].tokenName)) { - subType = SYNTAX; - } else { - if (!strcmp("ax-", left(g_Statement[showStmt].labelName, 3))) { - subType = AXIOM; - } else { - subType = DEFINITION; - } - } - } - switch (subType) { - case SYNTAX: - let(&str1, "Syntax Definition"); break; - case DEFINITION: - let(&str1, "Definition"); break; - case AXIOM: - let(&str1, "Axiom"); break; - case THEOREM: - let(&str1, "Theorem"); break; - default: - bug(229); - } - - /* Print a small pink statement number after the statement */ - let(&str2, ""); - str2 = pinkHTML(showStmt); - printLongLine(cat("
", str1, - " ", g_Statement[showStmt].labelName, - "", str2, "
", NULL), "", "\""); - } /* (htmlFlg && texFlag) */ - g_outputToString = 0; - } /* texFlag */ - } - - if (!briefFlag || commentOnlyFlag) { - let(&str1, ""); - str1 = getDescription(showStmt); - if (!str1[0] /* No comment */) { - print2("?Warning: Statement \"%s\" has no comment\n", - g_Statement[showStmt].labelName); - /* We must print a blank comment to have \begin{lemma} */ - if (texFlag && !htmlFlg && !g_oldTexFlag) { - let(&str1, "TO DO: PUT DESCRIPTION HERE"); - } - } - if (str1[0]) { - if (!texFlag) { - printLongLine(cat("\"", str1, "\"", NULL), "", " "); - } else { - if (!htmlFlg) { /* LaTeX */ - if (!g_oldTexFlag) { - /* Distinguish axiom, definition, theorem */ - /* Note: changes here must be mirrored in the \end{...} below */ - if (g_Statement[showStmt].type == a_) { - if (!strcmp(left(g_Statement[showStmt].labelName, 3), "ax-")) { - let(&str3, "axiom"); - } else { - let(&str3, "definition"); - } - } else { - let(&str3, "theorem"); - } - let(&str1, cat("\\begin{", str3, "}\\label{", - left(str3, 3), ":", - g_Statement[showStmt].labelName, "} ", str1, NULL)); - } else { - /* Add separation space between theorems */ - let(&str1, cat("\n\\vspace{1ex} %2\n\n", str1, NULL)); - } - } - printTexComment(str1, /* Sends result to g_texFilePtr */ - 1, /* 1 = htmlCenterFlag */ - PROCESS_EVERYTHING, /* actionBits */ - 1 /* 1 = fileCheck */); - } - } - } - if (commentOnlyFlag && !briefFlag) goto returnPoint; - - if ((briefFlag && !texFlag) || (htmlFlg && texFlag)) { - /* In BRIEF mode screen output, show $d's */ - - if (htmlFlg && texFlag) { - let(&htmlDistinctVars, ""); - htmlDistinctVarsCommaFlag = 0; - } - - /* This algorithm is used to re-merge $d pairs - into groups of 3 or more when possible, for a more compact display. - The algorithm does not merge groups optimally, but it should be - adequate. For example, in set.mm (e.g. old r19.23aivv): - $d x ps $. $d y ps $. $d y A $. $d x y $. - produces in SHOW STATEMENT (note redundant 3rd $d): - $d ps x y $. $d y A $. $d x y $. - However, in set.mm the equivalent (and better anyway): - $d x y ps $. $d y A $. - produces the same thing when remerged in SHOW STATEMENT. */ - let(&str1, ""); - nmbrTmpPtr1 = g_Statement[showStmt].reqDisjVarsA; - nmbrTmpPtr2 = g_Statement[showStmt].reqDisjVarsB; - i = nmbrLen(nmbrTmpPtr1); - if (i /* Number of mandatory $d pairs */) { - nmbrLet(&nmbrDDList, NULL_NMBRSTRING); - for (k = 0; k < i; k++) { - /* Is one of the variables in the current list? */ - if (!nmbrElementIn(1, nmbrDDList, nmbrTmpPtr1[k]) && - !nmbrElementIn(1, nmbrDDList, nmbrTmpPtr2[k])) { - /* No, so close out the current list */ - if (!(htmlFlg && texFlag)) { - if (k == 0) let(&str1, "$d"); - else let(&str1, cat(str1, " $. $d", NULL)); - } else { - let(&htmlDistinctVars, cat(htmlDistinctVars, "   ", - NULL)); - htmlDistinctVarsCommaFlag = 0; - distVarGrps++; - } - nmbrLet(&nmbrDDList, NULL_NMBRSTRING); - } - /* Are both variables required to be distinct from all others - in current list? */ - for (n = 0; n < nmbrLen(nmbrDDList); n++) { - if (nmbrDDList[n] != nmbrTmpPtr1[k] && - nmbrDDList[n] != nmbrTmpPtr2[k]) { - q1 = 0; q2 = 0; - for (m = 0; m < i; m++) { - if ((nmbrTmpPtr1[m] == nmbrDDList[n] && - nmbrTmpPtr2[m] == nmbrTmpPtr1[k]) || - (nmbrTmpPtr2[m] == nmbrDDList[n] && - nmbrTmpPtr1[m] == nmbrTmpPtr1[k])) { - q1 = 1; /* 1st var is required to be distinct */ - } - if ((nmbrTmpPtr1[m] == nmbrDDList[n] && - nmbrTmpPtr2[m] == nmbrTmpPtr2[k]) || - (nmbrTmpPtr2[m] == nmbrDDList[n] && - nmbrTmpPtr1[m] == nmbrTmpPtr2[k])) { - q2 = 1; /* 2nd var is required to be distinct */ - } - if (q1 && q2) break; /* Found both */ - } /* Next m */ - if (!q1 || !q2) { - /* One of the variables is not required to be distinct from - all others in the current list, so close out current list */ - if (!(htmlFlg && texFlag)) { - if (k == 0) let(&str1, "$d"); - else let(&str1, cat(str1, " $. $d", NULL)); - } else { - let(&htmlDistinctVars, cat(htmlDistinctVars, "   ", - NULL)); - htmlDistinctVarsCommaFlag = 0; - distVarGrps++; - } - - nmbrLet(&nmbrDDList, NULL_NMBRSTRING); - break; /* Out of n loop */ - } - } /* If $d var in current list is not same as one we're adding */ - } /* Next n */ - /* If the variable is not already in current list, add it */ - if (!nmbrElementIn(1, nmbrDDList, nmbrTmpPtr1[k])) { - if (!(htmlFlg && texFlag)) { - let(&str1, cat(str1, " ", g_MathToken[nmbrTmpPtr1[k]].tokenName, - NULL)); - } else { - - if (htmlDistinctVarsCommaFlag) { - let(&htmlDistinctVars, cat(htmlDistinctVars, ",", NULL)); - } - htmlDistinctVarsCommaFlag = 1; - let(&str2, ""); - str2 = tokenToTex(g_MathToken[nmbrTmpPtr1[k]].tokenName, showStmt); - /* tokenToTex allocates str2; we must deallocate it */ - let(&htmlDistinctVars, cat(htmlDistinctVars, str2, NULL)); - - } - nmbrLet(&nmbrDDList, nmbrAddElement(nmbrDDList, nmbrTmpPtr1[k])); - } - if (!nmbrElementIn(1, nmbrDDList, nmbrTmpPtr2[k])) { - if (!(htmlFlg && texFlag)) { - let(&str1, cat(str1, " ", g_MathToken[nmbrTmpPtr2[k]].tokenName, - NULL)); - } else { - - if (htmlDistinctVarsCommaFlag) { - let(&htmlDistinctVars, cat(htmlDistinctVars, ",", NULL)); - } - htmlDistinctVarsCommaFlag = 1; - let(&str2, ""); - str2 = tokenToTex(g_MathToken[nmbrTmpPtr2[k]].tokenName, showStmt); - /* tokenToTex allocates str2; we must deallocate it */ - let(&htmlDistinctVars, cat(htmlDistinctVars, str2, NULL)); - - } - nmbrLet(&nmbrDDList, nmbrAddElement(nmbrDDList, nmbrTmpPtr2[k])); - } - } /* Next k */ - /* Close out entire list */ - if (!(htmlFlg && texFlag)) { - let(&str1, cat(str1, " $.", NULL)); - printLongLine(str1, " ", " "); - } else { - /* (do nothing) */ - } - } /* if i(#$d's) > 0 */ - } - - if (briefFlag || texFlag) { - /* For BRIEF mode, print $e hypotheses (only) before statement */ - /* Also do it for HTML output */ - j = nmbrLen(g_Statement[showStmt].reqHypList); - k = 0; - for (i = 0; i < j; i++) { - /* Count the number of essential hypotheses */ - if (g_Statement[g_Statement[showStmt].reqHypList[i]].type - == (char)e_) k++; - - /* For syntax definitions, also include $f hypotheses so user can more - easily match them in syntax breakdowns of axioms and definitions */ - if (subType == SYNTAX && (texFlag && htmlFlg)) { - if (g_Statement[g_Statement[showStmt].reqHypList[i]].type - == (char)f_) k++; - } - - } - if (k) { - if (texFlag) { - /* Note that printTexLongMath resets it to 0 */ - g_outputToString = 1; - } - if (texFlag && htmlFlg) { - print2("
\n", (k == 1) ? "Hypothesis" : "Hypotheses"); - print2("\n", - (k == 1) ? "Hypothesis" : "Hypotheses"); - print2("\n"); - } - for (i = 0; i < j; i++) { - k = g_Statement[showStmt].reqHypList[i]; - if (g_Statement[k].type != (char)e_ - - /* For syntax definitions, include $f hypotheses so user can more - easily match them in syntax breakdowns of axioms & definitions */ - && !(subType == SYNTAX && (texFlag && htmlFlg) - && g_Statement[k].type == (char)f_) - - ) continue; - - if (!texFlag) { - let(&str2, cat(str((double)k), " ", NULL)); - } else { - let(&str2, " "); - } - let(&str2, cat(str2, g_Statement[k].labelName, - " $", chr(g_Statement[k].type), " ", NULL)); - if (!texFlag) { - printLongLine(cat(str2, - nmbrCvtMToVString(g_Statement[k].mathString), " $.", NULL), - " "," "); - } else { /* if texFlag */ - /* texFlag was (misleadingly) included below to facilitate search - for "htmlFlg && texFlag". */ - if (!(htmlFlg && texFlag)) { - if (!g_oldTexFlag) { - /* Do nothing */ - } else { - let(&str3, space((long)strlen(str2))); - printTexLongMath(g_Statement[k].mathString, - str2, str3, 0, 0); - } - } else { - g_outputToString = 1; - print2("
%s
Ref\n"); - print2("Expression
%s\n", - g_Statement[k].labelName); - /* Print hypothesis */ - printTexLongMath(g_Statement[k].mathString, "", "", 0, 0); - } - } - } /* next i */ - if (texFlag && htmlFlg) { - g_outputToString = 1; - print2("
\n"); - } - } /* if k (#essential hyp) */ - } - - let(&str1, ""); - type = g_Statement[showStmt].type; - if (type == p_) let(&str1, " $= ..."); - if (!texFlag) - let(&str2, cat(str((double)showStmt), " ", NULL)); - else - let(&str2, " "); - let(&str2, cat(str2, g_Statement[showStmt].labelName, - " $",chr(type), " ", NULL)); - if (!texFlag) { - printLongLine(cat(str2, - nmbrCvtMToVString(g_Statement[showStmt].mathString), - str1, " $.", NULL), " ", " "); - } else { - if (!(htmlFlg && texFlag)) { /* really !htmlFlg & texFlag */ - if (!g_oldTexFlag) { - g_outputToString = 1; - print2("\\begin{align}\n"); - let(&str3, ""); - /* Get HTML hypotheses => assertion */ - str3 = getTexOrHtmlHypAndAssertion(showStmt); /* In mmwtex.c */ - printLongLine(cat(str3, - /* No space before \label to make it easier to find last - parenthesis in a post-processing script */ - "\\label{eq:", - g_Statement[showStmt].labelName, - "}", - - /* Add "\tag{..}" to use .mm labels instead of equation numbers */ - /* (Suggested by Ari Ferrera) */ - "\\tag{", - g_Statement[showStmt].labelName, - "}", - - NULL), " ", " "); - /* print2(" \\label{eq:%s}\n",g_Statement[showStmt].labelName); */ - print2("\\end{align}\n"); - - - /* Distinguish axiom, definition, theorem for LaTeX */ - /* Note: changes here must be mirrored in the \begin{...} above */ - if (g_Statement[showStmt].type == a_) { - if (!strcmp(left(g_Statement[showStmt].labelName, 3), "ax-")) { - let(&str3, "axiom"); - } else { - let(&str3, "definition"); - } - } else { - let(&str3, "theorem"); - } - print2("%s\n", cat("\\end{", str3, "}", NULL)); - - fprintf(g_texFilePtr, "%s", g_printString); - let(&g_printString, ""); - g_outputToString = 0; - - } else { /* old TeX code */ - let(&str3, space((long)strlen(str2))); /* 3rd argument of printTexLongMath - cannot be temp allocated */ - printTexLongMath(g_Statement[showStmt].mathString, - str2, str3, 0, 0); - } - } else { /* (htmlFlg && texFlag) */ - g_outputToString = 1; - print2("
\n"); - print2("\n"); - print2("\n"); - printLongLine(cat( - "
Assertion
Ref\n"); - print2("Expression
", g_Statement[showStmt].labelName, - "", NULL), " ", " "); - printTexLongMath(g_Statement[showStmt].mathString, "", "", 0, 0); - g_outputToString = 1; - print2("
\n"); - } - } - - if (briefFlag) goto returnPoint; - - switch (type) { - case a_: - case p_: - /* This is not really needed but keeps output consistent - with previous version. It puts a blank line before the HTML - "distinct variable" list. */ - if (texFlag && htmlFlg) { - g_outputToString = 1; - print2("\n"); - g_outputToString = 0; - } - - if (!texFlag) { - print2("Its mandatory hypotheses in RPN order are:\n"); - } - j = nmbrLen(g_Statement[showStmt].reqHypList); - for (i = 0; i < j; i++) { - k = g_Statement[showStmt].reqHypList[i]; - if (g_Statement[k].type != (char)e_ && (!htmlFlg && texFlag)) - continue; /* Don't put $f's in LaTeX output */ - let(&str2, cat(" ",g_Statement[k].labelName, - " $", chr(g_Statement[k].type), " ", NULL)); - if (!texFlag) { - printLongLine(cat(str2, - nmbrCvtMToVString(g_Statement[k].mathString), " $.", NULL), - " "," "); - } - } - /* This is not really needed but keeps output consistent - with previous version. It puts a blank line before the HTML - "distinct variable" list. */ - if (texFlag && htmlFlg) { - g_outputToString = 1; - print2("\n"); - g_outputToString = 0; - } - if (j == 0 && !texFlag) print2(" (None)\n"); - let(&str1, ""); - nmbrTmpPtr1 = g_Statement[showStmt].reqDisjVarsA; - nmbrTmpPtr2 = g_Statement[showStmt].reqDisjVarsB; - i = nmbrLen(nmbrTmpPtr1); - if (i) { - for (k = 0; k < i; k++) { - if (!texFlag) { - let(&str1, cat(str1, ", <", - g_MathToken[nmbrTmpPtr1[k]].tokenName, ",", - g_MathToken[nmbrTmpPtr2[k]].tokenName, ">", NULL)); - } else { - if (htmlFlg && texFlag) { - let(&str2, ""); - str2 = tokenToTex(g_MathToken[nmbrTmpPtr1[k]].tokenName, showStmt); - /* tokenToTex allocates str2; we must deallocate it */ - let(&str1, cat(str1, "   ", str2, NULL)); - let(&str2, ""); - str2 = tokenToTex(g_MathToken[nmbrTmpPtr2[k]].tokenName, showStmt); - let(&str1, cat(str1, ",", str2, NULL)); - } - } - } - if (!texFlag) - printLongLine(cat( - "Its mandatory disjoint variable pairs are: ", - right(str1,3),NULL)," "," "); - } - if (type == p_ && - nmbrLen(g_Statement[showStmt].optHypList) - && !texFlag) { - printLongLine(cat( - "Its optional hypotheses are: ", - nmbrCvtRToVString( - g_Statement[showStmt].optHypList, - 0, /*explicitTargets*/ - 0 /*statemNum, used only if explicitTargets*/), NULL), - " "," "); - } - nmbrTmpPtr1 = g_Statement[showStmt].optDisjVarsA; - nmbrTmpPtr2 = g_Statement[showStmt].optDisjVarsB; - i = nmbrLen(nmbrTmpPtr1); - if (i && type == p_) { - if (!texFlag) { - let(&str1, ""); - } - for (k = 0; k < i; k++) { - if (!texFlag) { - let(&str1, cat(str1, ", <", - g_MathToken[nmbrTmpPtr1[k]].tokenName, ",", - g_MathToken[nmbrTmpPtr2[k]].tokenName, ">", NULL)); - } /* if !texFlag */ - } /* next k */ - if (!texFlag) { - printLongLine(cat( - "Its optional disjoint variable pairs are: ", - right(str1,3),NULL)," "," "); - } - } /* if (i && type == p_) */ - - - if (texFlag && htmlFlg) { /* It's a web page */ - - if (htmlDistinctVars[0] != 0) { - g_outputToString = 1; - printLongLine(cat( - "
", - " 0) ? - "mmset.html" : - /* The following link will work in the NF and other - "Proof Explorers" */ - "../mpeuni/mmset.html", - - "#distinct\">Distinct variable group", - distVarGrps > 1 ? "s" : "", - ": ", - /* Put a span around the variable list to localize - the use of the special math font for ALT_HTML */ - (g_altHtmlFlag ? cat("", NULL) : ""), - htmlDistinctVars, - (g_altHtmlFlag ? "" : ""), - "
", - NULL), "", "\""); - g_outputToString = 0; - } - - let(&str2, ""); - str2 = htmlAllowedSubst(showStmt); - if (str2[0] != 0) { - g_outputToString = 1; - /* Print the list of allowed free variables */ - printLongLine(str2, "", "\""); - g_outputToString = 0; - } - - } /* if (texFlag && htmlFlg) */ - - if (texFlag) { - g_outputToString = 1; - if (htmlFlg && texFlag) print2("
\n"); - g_outputToString = 0; /* Restore normal output */ - break; /* case a_ or p_ */ - } - let(&str1, nmbrCvtMToVString( - g_Statement[showStmt].reqVarList)); - if (!strlen(str1)) let(&str1, "(None)"); - printLongLine(cat( - "The statement and its hypotheses require the variables: ", - str1, NULL), " ", " "); - if (type == p_ && - nmbrLen(g_Statement[showStmt].optVarList)) { - printLongLine(cat( - "These additional variables are allowed in its proof: " - ,nmbrCvtMToVString( - g_Statement[showStmt].optVarList),NULL)," ", - " "); - /*??? Add variables required by proof */ - } - /* Note: g_Statement[].reqVarList is only stored for $a and $p - statements, not for $e or $f. */ - let(&str1, nmbrCvtMToVString( - g_Statement[showStmt].reqVarList)); - if (!strlen(str1)) let(&str1, "(None)"); - printLongLine(cat("The variables it contains are: ", - str1, NULL), - " ", " "); - break; /* case a_ or p_ */ - default: - break; - } /* End switch(type) */ - if (texFlag) { - g_outputToString = 0; - } - - /* Start of finding definition for syntax statement */ - if (htmlFlg && texFlag) { - - /* For syntax declarations, find the first definition that follows - it. It is up to the user to arrange the database so that a - meaningful definition is picked. */ - if (subType == SYNTAX) { - for (i = showStmt + 1; i <= g_statements; i++) { - if (g_Statement[i].type == (char)a_) { - if (!strcmp("|-", g_MathToken[ - (g_Statement[i].mathString)[0]].tokenName)) { - /* It's a definition or axiom */ - /* See if each constant token in the syntax statement - exists in the definition; if not don't use the definition */ - j = 1; - /* We start with k=1 for 2nd token (1st is wff, class, etc.) */ - for (k = 1; k < g_Statement[showStmt].mathStringLen; k++) { - if (g_MathToken[(g_Statement[showStmt].mathString)[k]]. - tokenType == (char)con_) { - if (!nmbrElementIn(1, g_Statement[i].mathString, - (g_Statement[showStmt].mathString)[k])) { - /* The definition being considered doesn't have one of - the constant symbols in the syntax statement, so - reject it */ - j = 0; - break; /* Out of k loop */ - } - } - } /* Next k */ - if (j) { - /* Successful - use this definition or axiom as the reference */ - g_outputToString = 1; - let(&str1, left(g_Statement[i].labelName, 3)); - let(&str2, ""); - str2 = pinkHTML(i); - if (!strcmp(str1, "ax-")) { - printLongLine(cat( - "
This syntax is primitive.", - " The first axiom using it is ", - g_Statement[i].labelName, - "", str2, ".

", - NULL), "", "\""); - } else { - printLongLine(cat( - "
See definition ", - g_Statement[i].labelName, "", str2, - " for more information.

", - NULL), "", "\""); - } - - printLongLine(cat( - "
", - NULL), "", "\""); - g_outputToString = 0; - break; /* Out of i loop */ - } - } - } - } /* Next i */ - } /* if (subType == SYNTAX) */ - - - /* For definitions, we pretend that the definition is a "wff" (hard-coded - here; the .mm database provided by the user must use this convention). - We use the proof assistant tools to prove that the statement is - a wff, then we print the wff construction proof to the HTML file. */ - if (subType == DEFINITION || subType == AXIOM) { - - /* Look up the token "wff" if we haven't found it before */ - if (wffToken == -1) { /* First time */ - wffToken = -2; /* In case it's not found because the user's source - used a convention different for "wff" for wffs */ - for (i = 0; i < g_mathTokens; i++) { - if (!strcmp("wff", g_MathToken[i].tokenName)) { - wffToken = i; - break; - } - } - } - - if (wffToken >= 0) { - /* Temporarily zap statement type from $a to $p */ - if (g_Statement[showStmt].type != (char)a_) bug(231); - g_Statement[showStmt].type = (char)p_; - /* Temporarily zap statement with "wff" token in 1st position - so parseProof will not give errors (in typeProof() call) */ - zapStatement1stToken = (g_Statement[showStmt].mathString)[0]; - (g_Statement[showStmt].mathString)[0] = wffToken; - if (strcmp("|-", g_MathToken[zapStatement1stToken].tokenName)) bug(230); - - nmbrTmpPtr1 = NULL_NMBRSTRING; - nmbrLet(&nmbrTmpPtr1, g_Statement[showStmt].mathString); - - /* Find proof of formula or simple theorem (no new vars in $e's) */ - /* maxEDepth is the maximum depth at which statements with $e - hypotheses are - considered. A value of 0 means none are considered. */ - nmbrTmpPtr2 = proveFloating(nmbrTmpPtr1 /*mString*/, - showStmt /*statemNum*/, 0 /*maxEDepth*/, - 0, /*step: 0 = step 1 */ /*For messages*/ - 0, /*not noDistinct*/ - 2, /* override discouraged-usage statements silently */ - 1 /* Always allow other mathboxes */ - ); - - if (nmbrLen(nmbrTmpPtr2)) { - /* A proof for the step was found. */ - /* Get packed form of proof for shorter display */ - nmbrLet(&nmbrTmpPtr2, nmbrSquishProof(nmbrTmpPtr2)); - /* Temporarily zap proof into statement structure */ - /* (The bug check makes sure there is no proof attached to the - definition - this would be impossible) */ - if (strcmp(g_Statement[showStmt].proofSectionPtr, "")) bug(231); - if (g_Statement[showStmt].proofSectionLen != 0) bug(232); - let(&str1, nmbrCvtRToVString(nmbrTmpPtr2, - 0, /*explicitTargets*/ - 0 /*statemNum, used only if explicitTargets*/)); - /* Temporarily zap proof into the $a statement */ - g_Statement[showStmt].proofSectionPtr = str1; - g_Statement[showStmt].proofSectionLen = (long)strlen(str1) - 1; - - /* Display the HTML proof of syntax breakdown */ - typeProof(showStmt, - 0 /*pipFlag*/, - 0 /*startStep*/, - 0 /*endStep*/, - 0 /*endIndent*/, - 0 /*essentialFlag*/, /* <- also used as def flag in typeProof */ - 1 /*renumberFlag*/, - 0 /*unknownFlag*/, - 0 /*notUnifiedFlag*/, - 0 /*reverseFlag*/, - 1 /*noIndentFlag*/, - 0 /*splitColumn*/, - 0 /*skipRepeatedSteps*/, - 1 /*texFlag*/, /* Means either latex or html */ - 1 /*htmlFlg*/); - - /* Restore the zapped statement structure */ - g_Statement[showStmt].proofSectionPtr = ""; - g_Statement[showStmt].proofSectionLen = 0; - - /* Deallocate storage */ - let(&str1, ""); - nmbrLet(&nmbrTmpPtr2, NULL_NMBRSTRING); - - } else { /* if (nmbrLen(nmbrTmpPtr2)) else */ - /* Proof was not found - probable syntax error */ - if (g_outputToString != 0) bug(246); - printLongLine(cat( - "?Warning: Unable to generate syntax breakdown for \"", - g_Statement[showStmt].labelName, - "\".", NULL), " ", " "); - } - - - /* Restore the zapped statement structure */ - g_Statement[showStmt].type = (char)a_; - (g_Statement[showStmt].mathString)[0] = zapStatement1stToken; - - /* Deallocate storage */ - nmbrLet(&nmbrTmpPtr1, NULL_NMBRSTRING); - - } /* if (wffToken >= 0) */ - - } /* if (subType == DEFINITION) */ - - - } /* if (htmlFlg && texFlag) */ - /* End of finding definition for syntax statement */ - - - /* Start of creating used-by list for html page */ - if (htmlFlg && texFlag) { - /* Clear out any previous g_printString accumulation - for g_printStringForReferencedBy case below */ - fprintf(g_texFilePtr, "%s", g_printString); - let(&g_printString, ""); - /* Start outputting to g_printString */ - if (g_outputToString != 0) bug(242); - g_outputToString = 1; - if (subType != SYNTAX) { /* Only do this for - definitions, axioms, and theorems, not syntax statements */ - let(&str1, ""); - g_outputToString = 0; /* Switch output to console in case - traceUsage reports an error */ - str1 = traceUsage(showStmt, - 0, /* recursiveFlag */ - 0 /* cutoffStmt */); - g_outputToString = 1; /* Restore output to string */ - - /* str1[i] will be 'Y' if used by showStmt */ - /* Convert usage list str1 to html links */ - switch (subType) { - case AXIOM: let(&str3, "axiom"); break; - case DEFINITION: let(&str3, "definition"); break; - case THEOREM: let(&str3, "theorem"); break; - default: bug(233); - } - let(&str2, cat("", NULL)); - if (g_printString[0]) { - bug(256); - } - let(&g_printString, str2); - } /* if (subType != SYNTAX) */ - if (subType == THEOREM) { - /* The "referenced by" does not show up after the proof - because we moved the typeProof() to below. Therefore, we save - g_printString into a temporary global holding variable to print - at the proper place inside of typeProof(). Ugly but necessary - with present design. */ - /* In the case of THEOREM, we save and reset the g_printString. In the - case of != THEOREM (i.e. AXIOM and DEFINITION), g_printString will - be printed and cleared below. */ - let(&g_printStringForReferencedBy, g_printString); - let(&g_printString, ""); - } - - /* Printing of the trailer in mmwtex.c will close out string later */ - g_outputToString = 0; - } /* if (htmlFlg && texFlag) */ - /* End of used-by list for html page */ - - - /* After the block above, so referenced statements - show up first for convenience */ - if (htmlFlg && texFlag) { - /*** Output the html proof for $p statements ***/ - /* Note that we also output the axiom and definition usage - lists inside this function */ - if (g_Statement[showStmt].type == (char)p_) { - typeProof(showStmt, - 0 /*pipFlag*/, - 0 /*startStep*/, - 0 /*endStep*/, - 0 /*endIndent*/, - 1 /*essentialFlag*/, - 1 /*renumberFlag*/, - 0 /*unknownFlag*/, - 0 /*notUnifiedFlag*/, - 0 /*reverseFlag*/, - 1 /*noIndentFlag*/, - 0 /*splitColumn*/, - 0 /*skipRepeatedSteps*/, - 1 /*texFlag*/, /* Means either latex or html */ - 1 /*htmlFlg*/); - } /* if (g_Statement[showStmt].type == (char)p_) */ - } /* if (htmlFlg && texFlag) */ - /* End of html proof for $p statements */ - - /* typeProof should have cleared this out */ - if (g_printStringForReferencedBy[0]) bug(243); - - returnPoint: - /* Deallocate strings */ - nmbrLet(&nmbrDDList, NULL_NMBRSTRING); - let(&str1, ""); - let(&str2, ""); - let(&str3, ""); - let(&str4, ""); - let(&str5, ""); - let(&htmlDistinctVars, ""); -} /* typeStatement */ - - - -/* Get the HTML string of dummy variables used by a proof for the - theorem's web page. It should be called only if we're in - HTML output mode i.e. SHOW STATEMENT .../HTML or /ALT_HTML */ -/* This is HARD-CODED FOR SET.MM and will not produce meaningful - output for other databases (so far none) with $d's */ -/* Caller must deallocate returned string */ -vstring htmlDummyVars(long showStmt) -{ - nmbrString *optDVA; /* Pointer only; not allocated directly */ - nmbrString *optDVB; /* Pointer only; not allocated directly */ - long numDVs; - nmbrString *optHyp; /* Pointer only; not allocated directly */ - long numOptHyps; - vstring str1 = ""; - long k, l, n, hypStmt; - - /* Variables used while collecting a statement's dummy variables in $d's */ - long dummyVarCount; /* # of (different) dummy vars found in $d statements */ - vstring dummyVarUsed = ""; /* 'Y'/'N' indicators that we found that var */ - vstring htmlDummyVarList = ""; /* Output HTML string */ - long dummyVar; /* Current variable in a $d; test if it's a dummy variable */ - - /* This function should be called only for web page generation */ - if (!g_htmlFlag) bug(261); - - if (g_Statement[showStmt].type != p_) bug(262); - if (strcmp("|-", g_MathToken[ - (g_Statement[showStmt].mathString)[0]].tokenName)) { - /* Don't process syntax statements */ - goto RETURN_POINT; - } - - optDVA = g_Statement[showStmt].optDisjVarsA; - optDVB = g_Statement[showStmt].optDisjVarsB; - numDVs = nmbrLen(optDVA); - optHyp = g_Statement[showStmt].optHypList; - numOptHyps = nmbrLen(optHyp); - - if (numDVs == 0) { /* Don't create a hint list if no $d's */ - /*let(&htmlDummyVarList, "(no restrictions)");*/ - goto RETURN_POINT; - } - - dummyVarCount = 0; - if (numDVs != 0) { - - /* Update g_WrkProof.proofString with current proof so we can - search it later to see if it uses the dummy variable */ - parseProof(showStmt); /* Prints message if severe error */ - - /* Create an array of Y/N indicators that variable is occurs in a - $d statement as a dummy variable */ - let(&dummyVarUsed, string(g_mathTokens, 'N')); - for (k = 0; k < numDVs; k++) { - for (l = 1; l <= 2; l++) { - if (l == 1) { - dummyVar = optDVA[k]; - } else { - dummyVar = optDVB[k]; - } - /* At this point, dummyVar is just a var in the $d; we - must still check that it is in the optHypList */ - /* See if potential dummyVar is in optHypList */ - if (dummyVarUsed[dummyVar] == 'N') { - for (n = 0; n < numOptHyps; n++) { - /* Check whether dummyVar matches the 2nd token of an - optional hypothesis list entry e.g. "x" in "set x" */ - hypStmt = g_Statement[showStmt].optHypList[n]; - if (g_Statement[hypStmt].mathString[1] == dummyVar) { - /* dummyVar is a dummy variable */ - - /* See if it is used by the proof */ - /* g_WrkProof.proofString was updated by parseProof(showStmt) - above */ - if (nmbrElementIn(1, g_WrkProof.proofString, hypStmt) == 0) { - break; /* It's not used by the proof; stop hyp scan */ - } - - dummyVarUsed[dummyVar] = 'Y'; - dummyVarCount++; - /* tokenToTex allocates str1; must deallocate it first */ - let(&str1, ""); - /* Convert token to htmldef/althtmldef string */ - str1 = tokenToTex(g_MathToken[dummyVar].tokenName, - showStmt); - let(&htmlDummyVarList, cat(htmlDummyVarList, " ", str1, NULL)); - break; /* Found a match, so stop further checking */ - } - } /* next n, 0 to numOptHyps-1*/ - } /* if dummy var not used (yet) */ - } /* next l */ - } /* next k */ - } /* if (numDVs != 0) */ - - if (dummyVarCount > 0) { - let(&htmlDummyVarList, cat( - "
", - " 0) ? - "mmset.html" : - /* The following link will work in the NF and other - "Proof Explorers" */ - "../mpeuni/mmset.html", - - "#dvnote1\">Dummy variable", - /* Determine whether singular or plural */ - dummyVarCount > 1 ? "s" : "", - " ", - /* Put a span around the variable list to localize - the use of the special math font for ALT_HTML */ - (g_altHtmlFlag ? cat("", NULL) : ""), - htmlDummyVarList, - (g_altHtmlFlag ? "" : ""), - dummyVarCount > 1 ? " are mutually distinct and" : " is", - " distinct from all other variables.", - "
", - NULL)); - } /* htmlDummyVars */ - - - RETURN_POINT: - /* Deallocate strings */ - let(&dummyVarUsed, ""); - let(&str1, ""); - - return htmlDummyVarList; -} /* htmlDummyVars */ - - - -/* Get the HTML string of "allowed substitutions" list for an axiom - or theorem's web page. It should be called only if we're in - HTML output mode i.e. SHOW STATEMENT .../HTML or /ALT_HTML */ -/* This is HARD-CODED FOR SET.MM and will not produce meaningful - output for other databases (so far none) with $d's */ -/* Caller must deallocate returned string */ -vstring htmlAllowedSubst(long showStmt) -{ - nmbrString *reqHyp; /* Pointer only; not allocated directly */ - long numReqHyps; - nmbrString *reqDVA; /* Pointer only; not allocated directly */ - nmbrString *reqDVB; /* Pointer only; not allocated directly */ - long numDVs; - nmbrString *setVar = NULL_NMBRSTRING; /* set (individual) variables */ - char *strptr; - vstring str1 = ""; - long setVars; - long wffOrClassVar; - vstring setVarDVFlag = ""; - flag found, first; - long i, j, k; - vstring htmlAllowedList = ""; - long countInfo = 0; - - reqDVA = g_Statement[showStmt].reqDisjVarsA; - reqDVB = g_Statement[showStmt].reqDisjVarsB; - numDVs = nmbrLen(reqDVA); - - reqHyp = g_Statement[showStmt].reqHypList; - numReqHyps = nmbrLen(reqHyp); - - /* This function should be called only for web page generation */ - if (!g_htmlFlag) bug(250); - - if (g_Statement[showStmt].mathStringLen < 1) bug(254); - if (strcmp("|-", g_MathToken[ - (g_Statement[showStmt].mathString)[0]].tokenName)) { - /* Don't process syntax statements */ - goto RETURN_POINT; - } - - if (numDVs == 0) { /* Don't create a hint list if no $d's */ - goto RETURN_POINT; - } - - /* Collect list of all set variables in the theorem */ - /* First, count the number of set variables */ - setVars = 0; - for (i = 0; i < numReqHyps; i++) { - /* Scan "setvar" variables */ - if (g_Statement[reqHyp[i]].type == (char)e_) continue; - if (g_Statement[reqHyp[i]].type != (char)f_) bug(251); - if (g_Statement[reqHyp[i]].mathStringLen != 2) - bug(252); /* $f must have 2 tokens */ - strptr = g_MathToken[ - (g_Statement[reqHyp[i]].mathString)[0]].tokenName; - /* THE FOLLOWING IS SPECIFIC TO set.mm */ - if (strcmp("setvar", strptr)) continue; - /* Not a set variable */ - setVars++; - } - /* Next, create a list of them in setVar[] */ - j = 0; - nmbrLet(&setVar, nmbrSpace(setVars)); - for (i = 0; i < numReqHyps; i++) { - /* Scan "setvar" variables */ - if (g_Statement[reqHyp[i]].type == (char)e_) continue; - strptr = g_MathToken[ - (g_Statement[reqHyp[i]].mathString)[0]].tokenName; - if (strcmp("setvar", strptr)) continue; - /* Not a set variable */ - setVar[j] = (g_Statement[reqHyp[i]].mathString)[1]; - j++; - } - if (j != setVars) bug(253); - - /* Scan "wff" and "class" variables for attached $d's */ - for (i = 0; i < numReqHyps; i++) { - /* Look for a "wff" and "class" variable */ - if (g_Statement[reqHyp[i]].type == (char)e_) continue; - strptr = g_MathToken[ - (g_Statement[reqHyp[i]].mathString)[0]].tokenName; - if (strcmp("wff", strptr) && strcmp("class", strptr)) continue; - /* Not a wff or class variable */ - wffOrClassVar = (g_Statement[reqHyp[i]].mathString)[1]; - let(&setVarDVFlag, string(setVars, 'N')); /* No $d yet */ - /* Scan for attached $d's */ - for (j = 0; j < numDVs; j++) { - found = 0; - if (wffOrClassVar == reqDVA[j]) { - for (k = 0; k < setVars; k++) { - if (setVar[k] == reqDVB[j]) { - setVarDVFlag[k] = 'Y'; - found = 1; - break; - } - } - } - if (found) continue; - /* Repeat with swapped $d arguments */ - if (wffOrClassVar == reqDVB[j]) { - for (k = 0; k < setVars; k++) { - if (setVar[k] == reqDVA[j]) { - setVarDVFlag[k] = 'Y'; - break; - } - } - } - } /* next $d */ - - /* Collect set vars that don't have $d's with this wff or class var */ - /* First, if there aren't any, then omit this wff or class var */ - found = 0; - for (j = 0; j < setVars; j++) { - if (setVarDVFlag[j] == 'N') { - found = 1; - break; - } - } - if (found == 0) continue; /* All set vars have $d with this wff or class */ - - let(&str1, ""); - str1 = tokenToTex(g_MathToken[wffOrClassVar].tokenName, showStmt); - /* tokenToTex allocates str1; we must deallocate it eventually */ - countInfo++; - let(&htmlAllowedList, cat(htmlAllowedList, "   ", - str1, "(", NULL)); - first = 1; - for (j = 0; j < setVars; j++) { - if (setVarDVFlag[j] == 'N') { - let(&str1, ""); - str1 = tokenToTex(g_MathToken[setVar[j]].tokenName, showStmt); - let(&htmlAllowedList, cat(htmlAllowedList, - (first == 0) ? "," : "", str1, NULL)); - if (first == 0) countInfo++; - first = 0; - } - } - let(&htmlAllowedList, cat(htmlAllowedList, ")", NULL)); - - } /* next i (wff or class var) */ - - RETURN_POINT: - - if (htmlAllowedList[0] != 0) { - let(&htmlAllowedList, cat("
", - " 0) ? - "mmset.html" : - /* The following link will work in the NF and other - "Proof Explorers" */ - "../mpeuni/mmset.html", - - "#allowedsubst\">Allowed substitution hint", - ((countInfo != 1) ? "s" : ""), ": ", - (g_altHtmlFlag ? cat("", NULL) : ""), - htmlAllowedList, - (g_altHtmlFlag ? "" : ""), - "
", NULL)); - } - - /* Deallocate strings */ - nmbrLet(&setVar, NULL_NMBRSTRING); - let(&str1, ""); - let(&setVarDVFlag, ""); - - return htmlAllowedList; -} /* htmlAllowedSubst */ - - - -/* Displays a proof (or part of a proof, depending on arguments). */ -/* Note that parseProof() and verifyProof() are assumed to have been called, - so that the g_WrkProof structure elements are assigned for the current - statement. */ -/* This is also used for the MIDI output, since we conveniently - have the necessary proof information here. The function outputMidi() - is called from within. */ -void typeProof(long statemNum, - flag pipFlag, /* Means use g_ProofInProgress; statemNum must be proveStatement*/ - long startStep, long endStep, - long endIndent, - flag essentialFlag, /* <- also used as definition/axiom flag for HTML - syntax breakdown when called from typeStatement() */ - flag renumberFlag, - flag unknownFlag, - flag notUnifiedFlag, - flag reverseFlag, - flag noIndentFlag, /* Means Lemmon-style proof */ - long splitColumn, /* START_COLUMN */ - flag skipRepeatedSteps, /* NO_REPEATED_STEPS */ - flag texFlag, - flag htmlFlg - /* flag g_midiFlag - global to avoid changing many calls to typeProof() */ - ) -{ - /* From HELP SHOW PROOF: Optional qualifiers: - / ESSENTIAL - the proof tree is trimmed of all $f hypotheses before - being displayed. - / FROM_STEP - the display starts at the specified step. If - this qualifier is omitted, the display starts at the first step. - / TO_STEP - the display ends at the specified step. If this - qualifier is omitted, the display ends at the last step. - / TREE_DEPTH - Only steps at less than the specified proof - tree depth are displayed. Useful for obtaining an overview of - the proof. - / REVERSE - the steps are displayed in reverse order. - / RENUMBER - when used with / ESSENTIAL, the steps are renumbered - to correspond only to the essential steps. - / TEX - the proof is converted to LaTeX and stored in the file opened - with OPEN TEX. - / HTML - the proof is converted to HTML and stored in the file opened - with OPEN HTML. - / LEMMON - The proof is displayed in a non-indented format known - as Lemmon style, with explicit previous step number references. - If this qualifier is omitted, steps are indented in a tree format. - / START_COLUMN - Overrides the default column at which - the formula display starts in a Lemmon style display. May be - used only in conjuction with / LEMMON. - / NO_REPEATED_STEPS - When a proof step is identical to an earlier - step, it will not be repeated. Instead, a reference to it will be - changed to a reference to the earlier step. In particular, - SHOW PROOF
", - "Colors of variables: ", - g_htmlVarColor, "
This ", str3, - " is referenced by:", NULL)); - - if (str1[0] == 'Y') { /* Used by at least one */ - let(&str5, ""); /* Buffer for very long strings */ - /* Scan all future statements in str1 Y/N list */ - for (m = showStmt + 1; m <= g_statements; m++) { - /* Scan the used-by map */ - if (str1[m] != 'Y') continue; - /* Get the label */ - let(&str3, g_Statement[m].labelName); - /* It should be a $p */ - if (g_Statement[m].type != p_) bug(241); - /* Get the pink number */ - let(&str4, ""); - str4 = pinkHTML(m); - /* Assemble the href */ - let(&str2, cat(str2, "  ", - /*str3, "", str4, NULL));*/ - str3, "\n", str4, NULL)); - /* 8-Aug-2008 nm If line is very long, print it out and reset - it to speed up program (SHOW STATEMENT syl/HTML is very slow) */ - /* 8-Aug-2008 nm This doesn't solve problem, because the bottleneck - is printing g_printStringForReferencedBy below. This whole - code section needs to be redesigned to solve the speed problem. */ - /* 19-Sep-2012 nm Try again to fix SHOW STATEMENT syl/HTML speed - without a major rewrite. Unfortunately, made little difference. */ - /* 18-Jul-2015: Part of slowdown was due to the old - traceUsage algorithm that built a huge string of labels. Improved - from 313 sec to 280 sec for 'sh st syl/a'; still a problem. */ - /* Accumulate large cat buffer when small cats exceed certain size */ - if (strlen(str2) > 5000) { - let(&str5, cat(str5, str2, NULL)); - let(&str2, ""); - } - } /* next m (statement number) */ - - - } else { - /* There is no usage of this statement; print "(None)" */ - let(&str5, ""); - let(&str2, cat(str2, " (None)", NULL)); - - } /* if (str1[0] == 'Y') */ - /* Include buffer in output string */ - let(&str2, cat(str5, str2, "
\n"); - } else { - - /* For bobby.cast.org approval */ - print2("
\n"); - print2("", NULL), "", "\""); - } - } else { - /* This is a syntax breakdown "proof" of a definition called - from typeStatement */ - print2("
Proof of Theorem ", - asciiToTt(g_Statement[statemNum].labelName), - "
\n"); - print2("", NULL), "", "\""); - } - print2( - "\n"); - g_outputToString = 0; - } - - if (!pipFlag) { - parseProof(g_showStatement); - if (g_WrkProof.errorSeverity > 1) { - if (htmlFlg && texFlag) { - /* Print warning and close out proof table */ - g_outputToString = 1; - print2( - "\n"); - g_outputToString = 0; - /* Clear out g_printStringForReferencedBy to prevent bug 243 above */ - let(&g_printStringForReferencedBy, ""); - } - return; /* verifyProof() could crash */ - } - verifyProof(g_showStatement); - } - - if (!pipFlag) { - nmbrLet(&proof, g_WrkProof.proofString); /* The proof */ - if (g_midiFlag) { - /* Get the uncompressed version of the proof */ - nmbrLet(&proof, nmbrUnsquishProof(proof)); - } - } else { - nmbrLet(&proof, g_ProofInProgress.proof); /* The proof */ - } - plen = nmbrLen(proof); - - /* To reduce the number of steps displayed in an html proof, - we will use a local label to reference the 2nd or later reference to a - hypothesis, so the hypothesis won't have to be shown multiple times - in the proof. */ - if (htmlFlg && texFlag && !noIndentFlag /* Lemmon */) { - /* Only Lemmon-style proofs are implemented for html */ - bug(218); - } - if (skipRepeatedSteps) { - for (step = 0; step < plen; step++) { - stmt = proof[step]; - if (stmt < 0) continue; /* Unknown or label ref */ - type = g_Statement[stmt].type; - if (type == f_ || type == e_ /* It's a hypothesis */ - || g_Statement[stmt].numReqHyp == 0) { /* A statement w/ no hyp */ - for (i = 0; i < step; i++) { - if (stmt == proof[i]) { - /* The hypothesis at 'step' matches an earlier hypothesis at i, - so we will backreference 'step' to i with a local label */ - proof[step] = -1000 - i; - break; - } - } /* next i */ - } - } /* next step */ - } - - - /* Collect local labels */ - for (step = 0; step < plen; step++) { - stmt = proof[step]; - if (stmt <= -1000) { - stmt = -1000 - stmt; - if (!nmbrElementIn(1, localLabels, stmt)) { - nmbrLet(&localLabels, nmbrAddElement(localLabels, stmt)); - } - } - } - - /* localLabelNames[] hold an integer which, when converted to string, - is the local label name. */ - nmbrLet(&localLabelNames, nmbrSpace(plen)); - - /* Get the indentation level */ - nmbrLet(&indentationLevel, nmbrGetIndentation(proof, 0)); - - /* Get the target hypotheses */ - nmbrLet(&targetHyps, nmbrGetTargetHyp(proof, statemNum)); - - /* Get the essential step flags, if required */ - if (essentialFlag || g_midiFlag) { - nmbrLet(&essentialFlags, nmbrGetEssential(proof)); - } else { - nmbrLet(&essentialFlags, NULL_NMBRSTRING); - } - - /* We now have enough information for the MIDI output, so do it */ - if (g_midiFlag) { - outputMidi(plen, indentationLevel, - essentialFlags, g_midiParam, g_Statement[statemNum].labelName); - goto typeProof_return; - } - - /* Get the step renumbering */ - nmbrLet(&stepRenumber, nmbrSpace(plen)); /* This initializes all step - renumbering to step 0. Later, we will use (for html) the fact that - a step renumbered to 0 is a step to be skipped. */ - i = 0; - maxStepNum = 0; - for (step = 0; step < plen; step++) { - stepPrintFlag = 1; /* Note: stepPrintFlag is reused below with a - slightly different meaning (i.e. it will be printed after - a filter such as notUnified is applied) */ - if (renumberFlag && essentialFlag) { - if (!essentialFlags[step]) stepPrintFlag = 0; - } - if (skipRepeatedSteps && proof[step] < 0) stepPrintFlag = 0; - /* For standard numbering, stepPrintFlag will be always be 1 here */ - if (stepPrintFlag) { - i++; - stepRenumber[step] = i; /* Numbering for step to be printed */ - maxStepNum = i; /* To compute maxStepNumLen below */ - } - } - - /* Get the relative offset (0, -1, -2,...) for unknown steps */ - if (unknownFlag) { - /* There could be unknown steps outside of MM-PA - So remove this bugcheck, which seems spurious. I can't see that - getRelStepNums() cares whether we are in MM-PA. */ - /* if (!pipFlag) bug(255); */ - relativeStepNums = getRelStepNums(g_ProofInProgress.proof); - } - - /* Get steps not unified (pipFlag only) */ - if (notUnifiedFlag) { - if (!pipFlag) bug(205); - nmbrLet(¬UnifiedFlags, nmbrSpace(plen)); - for (step = 0; step < plen; step++) { - notUnifiedFlags[step] = 0; - if (nmbrLen(g_ProofInProgress.source[step])) { - if (!nmbrEq(g_ProofInProgress.target[step], - g_ProofInProgress.source[step])) notUnifiedFlags[step] = 1; - } - if (nmbrLen(g_ProofInProgress.user[step])) { - if (!nmbrEq(g_ProofInProgress.target[step], - g_ProofInProgress.user[step])) notUnifiedFlags[step] = 1; - } - } - } - - /* Get the printed character length of the largest step number */ - i = maxStepNum; - while (i >= 10) { - i = i/10; /* The number is printed in base 10 */ - maxStepNumLen++; - } - /* Add extra space for negative offset numbers e.g. "3:-1" */ - if (unknownFlag) { - maxStepNumOffsetLen = 3; /* :, -, # */ - j = 0; - for (i = 0; i < plen; i++) { - j = relativeStepNums[i]; - if (j <= 0) break; /* Found first unknown step (largest offset) */ - } - while (j <= -10) { - j = j/10; /* The number is printed in base 10 */ - maxStepNumOffsetLen++; - } - } - - - - /* Get local labels and maximum label length */ - /* lent = target length, lens = source length */ - for (step = 0; step < plen; step++) { - lent = (long)strlen(g_Statement[targetHyps[step]].labelName); - stmt = proof[step]; - if (stmt < 0) { - if (stmt <= -1000) { - stmt = -1000 - stmt; - /* stmt is now the step number a local label refers to */ - lens = (long)strlen(str((double)(localLabelNames[stmt]))); - let(&tmpStr1, ""); /* Clear temp alloc stack for str function */ - } else { - if (stmt != -(long)'?') bug (219); /* the only other possibility */ - lens = 1; /* '?' (unknown step) */ - } - } else { - if (nmbrElementIn(1, localLabels, step)) { - - /* The philosophy is to number all local labels with the - actual step number referenced, for better readability. This means - that if a *.mm label is a pure number, there may be ambiguity in - the proof display, but this is felt to be too rare to be a serious - drawback. */ - localLabelNames[step] = stepRenumber[step]; - - } - lens = (long)strlen(g_Statement[stmt].labelName); - } - /* Find longest label assignment, excluding local label declaration */ - if (maxLabelLen < lent + 1 + lens) { - maxLabelLen = lent + 1 + lens; /* Target, =, source */ - } - } /* Next step */ - - /* Print the steps */ - if (reverseFlag && !g_midiFlag) { - fromStep = plen - 1; - toStep = -1; - byStep = -1; - } else { - fromStep = 0; - toStep = plen; - byStep = 1; - } - for (step = fromStep; step != toStep; step = step + byStep) { - - /* Filters to decide whether to print the step */ - stepPrintFlag = 1; - if (startStep > 0) { /* The user's FROM_STEP */ - if (step + 1 < startStep) stepPrintFlag = 0; - } - if (endStep > 0) { /* The user's TO_STEP */ - if (step + 1 > endStep) stepPrintFlag = 0; - } - if (endIndent > 0) { /* The user's INDENTATION_DEPTH */ - if (indentationLevel[step] + 1 > endIndent) stepPrintFlag = 0; - } - if (essentialFlag) { - if (!essentialFlags[step]) stepPrintFlag = 0; - } - if (notUnifiedFlag) { - if (!notUnifiedFlags[step]) stepPrintFlag = 0; - } - if (unknownFlag) { - if (proof[step] != -(long)'?') stepPrintFlag = 0; - } - - /* Skip steps that are local label references for html */ - if (skipRepeatedSteps) { - if (stepRenumber[step] == 0) stepPrintFlag = 0; - } - - /* For MIDI files, ignore all qualifiers and process all steps */ - if (g_midiFlag) stepPrintFlag = 1; - - if (!stepPrintFlag) continue; - - if (noIndentFlag) { - let(&tgtLabel, ""); - } else { - let(&tgtLabel, g_Statement[targetHyps[step]].labelName); - } - let(&locLabDecl, ""); /* Local label declaration */ - stmt = proof[step]; - if (stmt < 0) { - if (stmt <= -1000) { - stmt = -1000 - stmt; - if (skipRepeatedSteps) bug(220); /* If html, a step referencing a - local label will never be printed since it will be skipped above */ - /* stmt is now the step number a local label refers to */ - if (noIndentFlag) { - let(&srcLabel, cat("@", str((double)(localLabelNames[stmt])), NULL)); - } else { - let(&srcLabel, cat("=", str((double)(localLabelNames[stmt])), NULL)); - } - type = g_Statement[proof[stmt]].type; - } else { - if (stmt != -(long)'?') bug(206); - if (noIndentFlag) { - let(&srcLabel, chr(-stmt)); /* '?' */ - } else { - let(&srcLabel, cat("=", chr(-stmt), NULL)); /* '?' */ - } - type = '?'; - } - } else { - if (nmbrElementIn(1, localLabels, step)) { - /* This statement declares a local label */ - if (noIndentFlag) { - if (!(skipRepeatedSteps)) { /* No local label declaration is - shown for html */ - let(&locLabDecl, cat("@", str((double)(localLabelNames[step])), ":", NULL)); - } - } else { - let(&locLabDecl, cat(str((double)(localLabelNames[step])), ":", NULL)); - } - } - - if (noIndentFlag) { - let(&srcLabel, g_Statement[stmt].labelName); - - /* For non-indented mode, add step numbers of hypotheses after label */ - let(&hypStr, ""); - hypStep = step - 1; - hypPtr = g_Statement[stmt].reqHypList; - for (hyp = g_Statement[stmt].numReqHyp - 1; hyp >=0; hyp--) { - if (!essentialFlag || g_Statement[hypPtr[hyp]].type == (char)e_) { - i = stepRenumber[hypStep]; - if (i == 0) { - if (!(skipRepeatedSteps)) bug(221); - if (proof[hypStep] != -(long)'?') { - if (proof[hypStep] > -1000) bug(222); - if (localLabelNames[-1000 - proof[hypStep]] == 0) bug(223); - if (localLabelNames[-1000 - proof[hypStep]] != - stepRenumber[-1000 - proof[hypStep]]) bug(224); - /* Get the step number the hypothesis refers to */ - i = stepRenumber[-1000 - proof[hypStep]]; - } else { - /* The hypothesis refers to an unknown step - use i as flag */ - i = -(long)'?'; - } - } - if (!hypStr[0]) { - if (i != -(long)'?') { - let(&hypStr, str((double)i)); - } else { - let(&hypStr, "?"); - } - } else { - /* Put comma between more than one hypothesis reference */ - if (i != -(long)'?') { - let(&hypStr, cat(str((double)i), ",", hypStr, NULL)); - } else { - let(&hypStr, cat("?", ",", hypStr, NULL)); - } - } - } - if (hyp < g_Statement[stmt].numReqHyp) { - /* Move down to previous hypothesis */ - hypStep = hypStep - subproofLen(proof, hypStep); - } - } /* Next hyp */ - - if (hypStr[0]) { - /* Add hypothesis list after label */ - let(&srcLabel, cat(hypStr, " ", srcLabel, NULL)); - } - - } else { - let(&srcLabel, cat("=", g_Statement[stmt].labelName, NULL)); - } - type = g_Statement[stmt].type; - } - - -#define PF_INDENT_INC 2 - /* Print the proof line */ - if (stepPrintFlag) { - - if (noIndentFlag) { - let(&startPrefix, cat( - space(maxStepNumLen - (long)strlen(str((double)(stepRenumber[step])))), - str((double)(stepRenumber[step])), - " ", - srcLabel, - space(splitColumn - (long)strlen(srcLabel) - (long)strlen(locLabDecl) - 1 - - maxStepNumLen - 1), - " ", locLabDecl, - NULL)); - if (pipFlag) { - let(&tgtPrefix, startPrefix); - let(&srcPrefix, cat( - space(maxStepNumLen - (long)strlen(str((double)(stepRenumber[step])))), - space((long)strlen(str((double)(stepRenumber[step])))), - " ", - space(splitColumn - 1 - - maxStepNumLen), - NULL)); - let(&userPrefix, cat( - space(maxStepNumLen - (long)strlen(str((double)(stepRenumber[step])))), - space((long)strlen(str((double)(stepRenumber[step])))), - " ", - "(User)", - space(splitColumn - (long)strlen("(User)") - 1 - - maxStepNumLen), - NULL)); - } - let(&contPrefix, space((long)strlen(startPrefix) + 4)); - } else { /* not noIndentFlag */ - - /* Compute prefix with and without step number. For 'show new_proof - /unknown', unknownFlag is set, and we add the negative offset. */ - let(&tmpStr, ""); - if (unknownFlag) { - if (relativeStepNums[step] < 0) { - let(&tmpStr, cat(" ", str((double)(relativeStepNums[step])), NULL)); - } - let(&tmpStr, cat(tmpStr, space(maxStepNumOffsetLen - - (long)(strlen(tmpStr))), NULL)); - } - - let(&startStringWithNum, cat( - space(maxStepNumLen - (long)strlen(str((double)(stepRenumber[step])))), - str((double)(stepRenumber[step])), - tmpStr, - " ", NULL)); - let(&startStringWithoutNum, space(maxStepNumLen + 1)); - - - let(&startPrefix, cat( - startStringWithNum, - space(indentationLevel[step] * PF_INDENT_INC - - (long)strlen(locLabDecl)), - locLabDecl, - tgtLabel, - srcLabel, - space(maxLabelLen - (long)strlen(tgtLabel) - - (long)strlen(srcLabel)), - NULL)); - if (pipFlag) { - let(&tgtPrefix, cat( - startStringWithNum, - space(indentationLevel[step] * PF_INDENT_INC - (long)strlen(locLabDecl)), - locLabDecl, - tgtLabel, - space((long)strlen(srcLabel)), - space(maxLabelLen - (long)strlen(tgtLabel) - (long)strlen(srcLabel)), - NULL)); - let(&srcPrefix, cat( - startStringWithoutNum, - space(indentationLevel[step] * PF_INDENT_INC - (long)strlen(locLabDecl)), - space((long)strlen(locLabDecl)), - space((long)strlen(tgtLabel)), - srcLabel, - space(maxLabelLen - (long)strlen(tgtLabel) - (long)strlen(srcLabel)), - NULL)); - let(&userPrefix, cat( - startStringWithoutNum, - space(indentationLevel[step] * PF_INDENT_INC - (long)strlen(locLabDecl)), - space((long)strlen(locLabDecl)), - space((long)strlen(tgtLabel)), - "=(User)", - space(maxLabelLen - (long)strlen(tgtLabel) - (long)strlen("=(User)")), - NULL)); - } - let(&contPrefix, ""); /* Continuation lines use whole screen width */ - } - - if (!pipFlag) { - - if (!texFlag) { - if (!g_midiFlag) { - printLongLine(cat(startPrefix," $", chr(type), " ", - nmbrCvtMToVString(g_WrkProof.mathStringPtrs[step]), - NULL), - contPrefix, - chr(1)); - /* chr(1) is right-justify flag for printLongLine */ - } - } else { /* TeX or HTML */ - printTexLongMath(g_WrkProof.mathStringPtrs[step], - cat(startPrefix, " $", chr(type), " ", NULL), - contPrefix, stmt, indentationLevel[step]); - } - - } else { /* pipFlag */ - if (texFlag) { - /* It doesn't make sense to do this and it hasn't been tested anyway */ - print2("?Unsupported: HTML or LaTeX proof for NEW_PROOF.\n"); - bug(244); - } - - if (!nmbrEq(g_ProofInProgress.target[step], g_ProofInProgress.source[step]) - && nmbrLen(g_ProofInProgress.source[step])) { - - if (!texFlag) { - printLongLine(cat(tgtPrefix, " $", chr(type), " ", - nmbrCvtMToVString(g_ProofInProgress.target[step]), - NULL), - contPrefix, - chr(1)); /* chr(1) is right-justify flag for printLongLine */ - printLongLine(cat(srcPrefix," = ", - nmbrCvtMToVString(g_ProofInProgress.source[step]), - NULL), - contPrefix, - chr(1)); /* chr(1) is right-justify flag for printLongLine */ - } else { /* TeX or HTML */ - printTexLongMath(g_ProofInProgress.target[step], - cat(tgtPrefix, " $", chr(type), " ", NULL), - contPrefix, 0, 0); - printTexLongMath(g_ProofInProgress.source[step], - cat(srcPrefix, " = ", NULL), - contPrefix, 0, 0); - } - } else { - if (!texFlag) { - printLongLine(cat(startPrefix, " $", chr(type), " ", - nmbrCvtMToVString(g_ProofInProgress.target[step]), - NULL), - contPrefix, - chr(1)); /* chr(1) is right-justify flag for printLongLine */ - } else { /* TeX or HTML */ - printTexLongMath(g_ProofInProgress.target[step], - cat(startPrefix, " $", chr(type), " ", NULL), - contPrefix, 0, 0); - } - - } - if (nmbrLen(g_ProofInProgress.user[step])) { - - if (!texFlag) { - printLongLine(cat(userPrefix, " = ", - nmbrCvtMToVString(g_ProofInProgress.user[step]), - NULL), - contPrefix, - chr(1)); /* chr(1) is right-justify flag for printLongLine */ - } else { - printTexLongMath(g_ProofInProgress.user[step], - cat(userPrefix, " = ", NULL), - contPrefix, 0, 0); - } - - } - } - } - - - } /* Next step */ - - if (!pipFlag) { - cleanWrkProof(); /* Deallocate verifyProof storage */ - } - - if (htmlFlg && texFlag) { - g_outputToString = 1; - print2("
Detailed syntax breakdown of Axiom \n"); - print2("Detailed syntax breakdown of Definition ", - asciiToTt(g_Statement[statemNum].labelName), - "
StepHypRef\n"); - print2("Expression
WARNING: Proof has a severe error.\n"); - print2("
\n"); - - printLongLine(cat( - "
", - NULL), "", "\""); - - if (essentialFlag) { /* Means this is not a syntax breakdown of a - definition which is called from typeStatement() */ - - /* Create list of syntax statements used */ - let(&statementUsedFlags, string(g_statements + 1, 'N')); /* Init. to 'no' */ - for (step = 0; step < plen; step++) { - stmt = proof[step]; - /* Convention: collect all $a's that don't begin with "|-" */ - if (stmt > 0) { - if (g_Statement[stmt].type == a_) { - if (strcmp("|-", g_MathToken[ - (g_Statement[stmt].mathString)[0]].tokenName)) { - statementUsedFlags[stmt] = 'Y'; /* Flag to use it */ - } - } - } - } - - /******************************************************************/ - /* Start of syntax hints section - for a more complete syntax hints - list in the HTML pages, parse the wffs comprising the hypotheses - and the statement, and add their syntax to the hints list. */ - - /* Look up the token "wff" (hard-coded) if we haven't found it before */ - if (wffToken == -1) { /* First time */ - wffToken = -2; /* In case it's not found because the user's source - used a convention different for "wff" for wffs */ - for (i = 0; i < g_mathTokens; i++) { - if (!strcmp("wff", g_MathToken[i].tokenName)) { - wffToken = i; - break; - } - } - } - - if (wffToken >= 0) { - - /* Scan the statement being proved and its essential hypotheses, - and find a proof for each of them expressed as a wff */ - for (i = -1; i < g_Statement[statemNum].numReqHyp; i++) { - /* i = -1 is the statement itself; i >= 0 is hypotheses i */ - if (i == -1) { - /* If it's not a $p we shouldn't be here */ - if (g_Statement[statemNum].type != (char)p_) bug(245); - nmbrTmpPtr1 = NULL_NMBRSTRING; - nmbrLet(&nmbrTmpPtr1, g_Statement[statemNum].mathString); - } else { - /* Ignore $f */ - if (g_Statement[g_Statement[statemNum].reqHypList[i]].type - == (char)f_) continue; - /* Must therefore be a $e */ - if (g_Statement[g_Statement[statemNum].reqHypList[i]].type - != (char)e_) bug(234); - nmbrTmpPtr1 = NULL_NMBRSTRING; - nmbrLet(&nmbrTmpPtr1, - g_Statement[g_Statement[statemNum].reqHypList[i]].mathString); - } - if (strcmp("|-", g_MathToken[nmbrTmpPtr1[0]].tokenName)) { - /* Since non-standard logics may not have this, - just break out of this section gracefully */ - nmbrTmpPtr2 = NULL_NMBRSTRING; /* To be known after break */ - break; - } - /* Turn "|-" assertion into a "wff" assertion */ - nmbrTmpPtr1[0] = wffToken; - - /* Find proof of formula or simple theorem (no new vars in $e's) */ - /* maxEDepth is the maximum depth at which statements with $e - hypotheses are - considered. A value of 0 means none are considered. */ - nmbrTmpPtr2 = proveFloating(nmbrTmpPtr1 /*mString*/, - statemNum /*statemNum*/, 0 /*maxEDepth*/, - 0, /* step; 0 = step 1 */ /*For messages*/ - 0, /*not noDistinct*/ - 2, /* override discouraged-usage statements silently */ - 1 /* Always allow other mathboxes */ - ); - if (!nmbrLen(nmbrTmpPtr2)) { - /* Didn't find syntax proof */ - /* Since a proof may not be found for non-standard - logics, just break out of this section gracefully */ - break; - } - - /* Add to list of syntax statements used */ - for (step = 0; step < nmbrLen(nmbrTmpPtr2); step++) { - stmt = nmbrTmpPtr2[step]; - /* Convention: collect all $a's that don't begin with "|-" */ - if (stmt > 0) { - if (statementUsedFlags[stmt] == 'N') { /* For slight speedup */ - if (g_Statement[stmt].type == a_) { - if (strcmp("|-", g_MathToken[ - (g_Statement[stmt].mathString)[0]].tokenName)) { - statementUsedFlags[stmt] = 'Y'; /* Flag to use it */ - } else { - /* In a syntax proof there should be no |- */ - /* (In the future, we may want to break instead of - calling it a bug, if it's a problem for non-standard - logics.) */ - bug(237); - } - } - } - } else { - /* proveFloating never returns a compressed proof */ - bug(238); - } - } - - /* Deallocate memory */ - nmbrLet(&nmbrTmpPtr2, NULL_NMBRSTRING); - nmbrLet(&nmbrTmpPtr1, NULL_NMBRSTRING); - } /* next i */ - /* Deallocate memory in case we broke out above */ - nmbrLet(&nmbrTmpPtr2, NULL_NMBRSTRING); - nmbrLet(&nmbrTmpPtr1, NULL_NMBRSTRING); - } /* if (wffToken >= 0) */ - /* End of syntax hints section */ - /******************************************************************/ - - let(&tmpStr, ""); - for (stmt = 1; stmt <= g_statements; stmt++) { - if (statementUsedFlags[stmt] == 'Y') { - if (!tmpStr[0]) { - let(&tmpStr, - "", NULL)); - printLongLine(tmpStr, "", "\""); - } - /* End of syntax hints list */ - - - /* Get list of axioms and definitions assumed by proof */ - let(&statementUsedFlags, ""); - traceProofWork(statemNum, - 1, /*essentialFlag*/ - "", /*traceToList*/ - &statementUsedFlags, - &unprovedList); - if ((signed)(strlen(statementUsedFlags)) != g_statements + 1) bug(227); - - /* First get axioms */ - let(&tmpStr, ""); - for (stmt = 1; stmt <= g_statements; stmt++) { - if (statementUsedFlags[stmt] == 'Y' && g_Statement[stmt].type == a_) { - let(&tmpStr1, left(g_Statement[stmt].labelName, 3)); - if (!strcmp(tmpStr1, "ax-")) { - if (!tmpStr[0]) { - let(&tmpStr, "", NULL)); - printLongLine(tmpStr, "", "\""); - } - - /* Then get definitions */ - let(&tmpStr, ""); - for (stmt = 1; stmt <= g_statements; stmt++) { - if (statementUsedFlags[stmt] == 'Y' && g_Statement[stmt].type == a_) { - let(&tmpStr1, left(g_Statement[stmt].labelName, 3)); - if (!strcmp(tmpStr1, "df-")) { - if (!tmpStr[0]) { - let(&tmpStr, - "", NULL)); - printLongLine(tmpStr, "", "\""); - } - - /* Print any unproved statements */ - if (nmbrLen(unprovedList)) { - if (nmbrLen(unprovedList) == 1 && - !strcmp(g_Statement[unprovedList[0]].labelName, - g_Statement[statemNum].labelName)) { - /* When the unproved list consists only of the statement that - was traced, it means the statement traced has no - proof (or it has a proof, but is incomplete and all earlier - ones do have complete proofs). */ - printLongLine(cat( -"", - NULL), "", "\""); - - } else { - printLongLine(cat( -"", NULL), "", "\""); - } - } - - /* End of axiom list */ - - /* Put referenced by list last */ - if (g_printStringForReferencedBy[0]) { - if (g_outputToString != 1) bug(257); - printLongLine(g_printStringForReferencedBy, "", "\""); - let(&g_printStringForReferencedBy, ""); - } else { - /* Since we always print ref-by list even if "(None)", - g_printStringForReferencedBy should never be empty */ - bug(263); - } - - } /* if essentialFlag */ - - - /* Printing of the trailer in mmwtex.c will close out string later */ - g_outputToString = 0; - } - - typeProof_return: - let(&tmpStr, ""); - let(&tmpStr1, ""); - let(&statementUsedFlags, ""); - let(&locLabDecl, ""); - let(&tgtLabel, ""); - let(&srcLabel, ""); - let(&startPrefix, ""); - let(&tgtPrefix, ""); - let(&srcPrefix, ""); - let(&userPrefix, ""); - let(&contPrefix, ""); - let(&hypStr, ""); - let(&startStringWithNum, ""); - let(&startStringWithoutNum, ""); - nmbrLet(&unprovedList, NULL_NMBRSTRING); - nmbrLet(&localLabels, NULL_NMBRSTRING); - nmbrLet(&localLabelNames, NULL_NMBRSTRING); - nmbrLet(&proof, NULL_NMBRSTRING); - nmbrLet(&targetHyps, NULL_NMBRSTRING); - nmbrLet(&indentationLevel, NULL_NMBRSTRING); - nmbrLet(&essentialFlags, NULL_NMBRSTRING); - nmbrLet(&stepRenumber, NULL_NMBRSTRING); - nmbrLet(¬UnifiedFlags, NULL_NMBRSTRING); - nmbrLet(&relativeStepNums, NULL_NMBRSTRING); -} /* typeProof() */ - -/* Show details of one proof step */ -/* Note: detailStep is the actual step number (starting with 1), not - the actual step - 1. */ -void showDetailStep(long statemNum, long detailStep) { - - long i, j, plen, step, stmt, sourceStmt, targetStmt; - vstring tmpStr = ""; - vstring tmpStr1 = ""; - nmbrString *proof = NULL_NMBRSTRING; - nmbrString *localLabels = NULL_NMBRSTRING; - nmbrString *localLabelNames = NULL_NMBRSTRING; - nmbrString *targetHyps = NULL_NMBRSTRING; - long nextLocLabNum = 1; /* Next number to be used for a local label */ - void *voidPtr; /* bsearch result */ - char type; - - /* Error check */ - i = parseProof(statemNum); - if (i) { - printLongLine("?The proof is incomplete or has an error", "", " "); - return; - } - plen = nmbrLen(g_WrkProof.proofString); - if (plen < detailStep || detailStep < 1) { - printLongLine(cat("?The step number should be from 1 to ", - str((double)plen), NULL), "", " "); - return; - } - - /* Structure getStep is declared in mmveri.h. */ - getStep.stepNum = detailStep; /* Non-zero is flag for verifyProof */ - parseProof(statemNum); /* ???Do we need to do this again? */ - verifyProof(statemNum); - - - nmbrLet(&proof, g_WrkProof.proofString); /* The proof */ - plen = nmbrLen(proof); - - /* Collect local labels */ - for (step = 0; step < plen; step++) { - stmt = proof[step]; - if (stmt <= -1000) { - stmt = -1000 - stmt; - if (!nmbrElementIn(1, localLabels, stmt)) { - nmbrLet(&localLabels, nmbrAddElement(localLabels, stmt)); - } - } - } - - /* localLabelNames[] hold an integer which, when converted to string, - is the local label name. */ - nmbrLet(&localLabelNames, nmbrSpace(plen)); - - /* Get the target hypotheses */ - nmbrLet(&targetHyps, nmbrGetTargetHyp(proof, statemNum)); - - /* Get local labels */ - for (step = 0; step < plen; step++) { - stmt = proof[step]; - if (stmt >= 0) { - if (nmbrElementIn(1, localLabels, step)) { - /* This statement declares a local label */ - /* First, get a name for the local label, using the next integer that - does not match any integer used for a statement label. */ - let(&tmpStr1, str((double)nextLocLabNum)); - while (1) { - voidPtr = (void *)bsearch(tmpStr, - g_allLabelKeyBase, (size_t)g_numAllLabelKeys, - sizeof(long), labelSrchCmp); - if (!voidPtr) break; /* It does not conflict */ - nextLocLabNum++; /* Try the next one */ - let(&tmpStr1, str((double)nextLocLabNum)); - } - localLabelNames[step] = nextLocLabNum; - nextLocLabNum++; /* Prepare for next local label */ - } - } - } /* Next step */ - - /* Print the step */ - let(&tmpStr, g_Statement[targetHyps[detailStep - 1]].labelName); - let(&tmpStr1, ""); /* Local label declaration */ - stmt = proof[detailStep - 1]; - if (stmt < 0) { - if (stmt <= -1000) { - stmt = -1000 - stmt; - /* stmt is now the step number a local label refers to */ - let(&tmpStr, cat(tmpStr,"=", str((double)(localLabelNames[stmt])), NULL)); - type = g_Statement[proof[stmt]].type; - } else { - if (stmt != -(long)'?') bug(207); - let(&tmpStr, cat(tmpStr,"=",chr(-stmt), NULL)); /* '?' */ - type = '?'; - } - } else { - if (nmbrElementIn(1, localLabels, detailStep - 1)) { - /* This statement declares a local label */ - let(&tmpStr1, cat(str((double)(localLabelNames[detailStep - 1])), ":", - NULL)); - } - let(&tmpStr, cat(tmpStr, "=", g_Statement[stmt].labelName, NULL)); - type = g_Statement[stmt].type; - } - - /* Print the proof line */ - printLongLine(cat("Proof step ", - str((double)detailStep), - ": ", - tmpStr1, - tmpStr, - " $", - chr(type), - " ", - nmbrCvtMToVString(g_WrkProof.mathStringPtrs[detailStep - 1]), - NULL), - " ", - " "); - - /* Print details about the step */ - let(&tmpStr, cat("This step assigns ", NULL)); - let(&tmpStr1, ""); - stmt = proof[detailStep - 1]; - sourceStmt = stmt; - if (stmt < 0) { - if (stmt <= -1000) { - stmt = -1000 - stmt; - /* stmt is now the step number a local label refers to */ - let(&tmpStr, cat(tmpStr, "step ", str((double)stmt), - " (via local label reference \"", - str((double)(localLabelNames[stmt])), "\") to ", NULL)); - } else { - if (stmt != -(long)'?') bug(208); - let(&tmpStr, cat(tmpStr, "an unknown statement to ", NULL)); - } - } else { - let(&tmpStr, cat(tmpStr, "source \"", g_Statement[stmt].labelName, - "\" ($", chr(g_Statement[stmt].type), ") to ", NULL)); - if (nmbrElementIn(1, localLabels, detailStep - 1)) { - /* This statement declares a local label */ - let(&tmpStr1, cat(" This step also declares the local label ", - str((double)(localLabelNames[detailStep - 1])), - ", which is used later on.", - NULL)); - } - } - targetStmt = targetHyps[detailStep - 1]; - if (detailStep == plen) { - let(&tmpStr, cat(tmpStr, "the final assertion being proved.", NULL)); - } else { - let(&tmpStr, cat(tmpStr, "target \"", g_Statement[targetStmt].labelName, - "\" ($", chr(g_Statement[targetStmt].type), ").", NULL)); - } - - let(&tmpStr, cat(tmpStr, tmpStr1, NULL)); - - if (sourceStmt >= 0) { - if (g_Statement[sourceStmt].type == a_ - || g_Statement[sourceStmt].type == p_) { - j = nmbrLen(g_Statement[sourceStmt].reqHypList); - if (j != nmbrLen(getStep.sourceHyps)) bug(209); - if (!j) { - let(&tmpStr, cat(tmpStr, - " The source assertion requires no hypotheses.", NULL)); - } else { - if (j == 1) { - let(&tmpStr, cat(tmpStr, - " The source assertion requires the hypothesis ", NULL)); - } else { - let(&tmpStr, cat(tmpStr, - " The source assertion requires the hypotheses ", NULL)); - } - for (i = 0; i < j; i++) { - let(&tmpStr, cat(tmpStr, "\"", - g_Statement[g_Statement[sourceStmt].reqHypList[i]].labelName, - "\" ($", - chr(g_Statement[g_Statement[sourceStmt].reqHypList[i]].type), - ", step ", str((double)(getStep.sourceHyps[i] + 1)), ")", NULL)); - if (i == 0 && j == 2) { - let(&tmpStr, cat(tmpStr, " and ", NULL)); - } - if (i < j - 2 && j > 2) { - let(&tmpStr, cat(tmpStr, ", ", NULL)); - } - if (i == j - 2 && j > 2) { - let(&tmpStr, cat(tmpStr, ", and ", NULL)); - } - } - let(&tmpStr, cat(tmpStr, ".", NULL)); - } - } - } - - if (detailStep < plen) { - let(&tmpStr, cat(tmpStr, - " The parent assertion of the target hypothesis is \"", - g_Statement[getStep.targetParentStmt].labelName, "\" ($", - chr(g_Statement[getStep.targetParentStmt].type),", step ", - str((double)(getStep.targetParentStep)), ").", NULL)); - } else { - let(&tmpStr, cat(tmpStr, - " The target has no parent because it is the assertion being proved.", - NULL)); - } - - printLongLine(tmpStr, "", " "); - - if (sourceStmt >= 0) { - if (g_Statement[sourceStmt].type == a_ - || g_Statement[sourceStmt].type == p_) { - print2("The source assertion before substitution was:\n"); - printLongLine(cat(" ", g_Statement[sourceStmt].labelName, " $", - chr(g_Statement[sourceStmt].type), " ", nmbrCvtMToVString( - g_Statement[sourceStmt].mathString), NULL), - " ", " "); - j = nmbrLen(getStep.sourceSubstsNmbr); - if (j == 1) { - printLongLine(cat( - "The following substitution was made to the source assertion:", - NULL),""," "); - } else { - printLongLine(cat( - "The following substitutions were made to the source assertion:", - NULL),""," "); - } - if (!j) { - print2(" (None)\n"); - } else { - print2(" Variable Substituted with\n"); - for (i = 0; i < j; i++) { - printLongLine(cat(" ", - g_MathToken[getStep.sourceSubstsNmbr[i]].tokenName," ", - space(9 - (long)strlen( - g_MathToken[getStep.sourceSubstsNmbr[i]].tokenName)), - nmbrCvtMToVString(getStep.sourceSubstsPntr[i]), NULL), - " ", " "); - } - } - } - } - - if (detailStep < plen) { - print2("The target hypothesis before substitution was:\n"); - printLongLine(cat(" ", g_Statement[targetStmt].labelName, " $", - chr(g_Statement[targetStmt].type), " ", nmbrCvtMToVString( - g_Statement[targetStmt].mathString), NULL), - " ", " "); - j = nmbrLen(getStep.targetSubstsNmbr); - if (j == 1) { - printLongLine(cat( - "The following substitution was made to the target hypothesis:", - NULL),""," "); - } else { - printLongLine(cat( - "The following substitutions were made to the target hypothesis:", - NULL),""," "); - } - if (!j) { - print2(" (None)\n"); - } else { - print2(" Variable Substituted with\n"); - for (i = 0; i < j; i++) { - printLongLine(cat(" ", - g_MathToken[getStep.targetSubstsNmbr[i]].tokenName, " ", - space(9 - (long)strlen( - g_MathToken[getStep.targetSubstsNmbr[i]].tokenName)), - nmbrCvtMToVString(getStep.targetSubstsPntr[i]), NULL), - " ", " "); - } - } - } - - cleanWrkProof(); - getStep.stepNum = 0; /* Zero is flag for verifyProof to ignore getStep info */ - - /* Deallocate getStep contents */ - j = pntrLen(getStep.sourceSubstsPntr); - for (i = 0; i < j; i++) { - nmbrLet((nmbrString **)(&getStep.sourceSubstsPntr[i]), - NULL_NMBRSTRING); - } - j = pntrLen(getStep.targetSubstsPntr); - for (i = 0; i < j; i++) { - nmbrLet((nmbrString **)(&getStep.targetSubstsPntr[i]), - NULL_NMBRSTRING); - } - nmbrLet(&getStep.sourceHyps, NULL_NMBRSTRING); - pntrLet(&getStep.sourceSubstsPntr, NULL_PNTRSTRING); - nmbrLet(&getStep.sourceSubstsNmbr, NULL_NMBRSTRING); - pntrLet(&getStep.targetSubstsPntr, NULL_PNTRSTRING); - nmbrLet(&getStep.targetSubstsNmbr, NULL_NMBRSTRING); - - /* Deallocate other strings */ - let(&tmpStr, ""); - let(&tmpStr1, ""); - nmbrLet(&localLabels, NULL_NMBRSTRING); - nmbrLet(&localLabelNames, NULL_NMBRSTRING); - nmbrLet(&proof, NULL_NMBRSTRING); - nmbrLet(&targetHyps, NULL_NMBRSTRING); - -} /* showDetailStep */ - -/* Summary of statements in proof for SHOW PROOF / STATEMENT_SUMMARY */ -void proofStmtSumm(long statemNum, flag essentialFlag, flag texFlag) { - - long i, j, k, pos, stmt, plen, slen, step; - char type; - vstring statementUsedFlags = ""; /* 'Y'/'N' flag that statement is used */ - vstring str1 = ""; - vstring str2 = ""; - vstring str3 = ""; - nmbrString *statementList = NULL_NMBRSTRING; - nmbrString *proof = NULL_NMBRSTRING; - nmbrString *essentialFlags = NULL_NMBRSTRING; - - /* This section is never called in HTML mode anymore. The code is - left in though just in case we somehow get here and the user continues - through the bug. */ - if (texFlag && g_htmlFlag) bug(239); - - if (!texFlag) { - print2("Summary of statements used in the proof of \"%s\":\n", - g_Statement[statemNum].labelName); - } else { - g_outputToString = 1; /* Flag for print2 to add to g_printString */ - if (!g_htmlFlag) { - print2("\n"); - print2("\\vspace{1ex} %%3\n"); - printLongLine(cat("Summary of statements used in the proof of ", - "{\\tt ", - asciiToTt(g_Statement[statemNum].labelName), - "}:", NULL), "", " "); - } else { - printLongLine(cat("Summary of statements used in the proof of ", - "", - asciiToTt(g_Statement[statemNum].labelName), - ":", NULL), "", "\""); - } - g_outputToString = 0; - fprintf(g_texFilePtr, "%s", g_printString); - let(&g_printString, ""); - } - - if (g_Statement[statemNum].type != p_) { - print2(" This is not a provable ($p) statement.\n"); - return; - } - - /* Don't use bad proofs (incomplete proofs are ok) */ - if (parseProof(statemNum) > 1) { - /* The proof has an error, so use the empty proof */ - nmbrLet(&proof, nmbrAddElement(NULL_NMBRSTRING, -(long)'?')); - } else { - nmbrLet(&proof, g_WrkProof.proofString); - } - - plen = nmbrLen(proof); - /* Get the essential step flags, if required */ - if (essentialFlag) { - nmbrLet(&essentialFlags, nmbrGetEssential(proof)); - } - - for (step = 0; step < plen; step++) { - if (essentialFlag) { - if (!essentialFlags[step]) continue; /* Ignore floating hypotheses */ - } - stmt = proof[step]; - if (stmt < 0) { - continue; /* Ignore '?' and local labels */ - } - if (1) { /* Limit list to $a and $p only */ - if (g_Statement[stmt].type != a_ && g_Statement[stmt].type != p_) { - continue; - } - } - /* Add this statement to the statement list if not already in it */ - if (!nmbrElementIn(1, statementList, stmt)) { - nmbrLet(&statementList, nmbrAddElement(statementList, stmt)); - } - } /* Next step */ - - /* Prepare the output */ - /* First, fill in the statementUsedFlags char array. This allows us to sort - the output by statement number without calling a sort routine. */ - slen = nmbrLen(statementList); - let(&statementUsedFlags, string(g_statements + 1, 'N')); /* Init. to 'no' */ - for (pos = 0; pos < slen; pos++) { - stmt = statementList[pos]; - if (stmt > statemNum || stmt < 1) bug(210); - statementUsedFlags[stmt] = 'Y'; - } - /* Next, build the output string */ - for (stmt = 1; stmt < statemNum; stmt++) { - if (statementUsedFlags[stmt] == 'Y') { - assignStmtFileAndLineNum(stmt); - let(&str1, cat(" is located on line ", - str((double)(g_Statement[stmt].lineNum)), - " of the file ", NULL)); - if (!texFlag) { - print2("\n"); - printLongLine(cat("Statement ", g_Statement[stmt].labelName, str1, - "\"", g_Statement[stmt].fileName, - "\".",NULL), "", " "); - } else { - g_outputToString = 1; /* Flag for print2 to add to g_printString */ - if (!g_htmlFlag) { - print2("\n"); - print2("\n"); - print2("\\vspace{1ex} %%4\n"); - printLongLine(cat("Statement {\\tt ", - asciiToTt(g_Statement[stmt].labelName), "} ", - str1, "{\\tt ", - asciiToTt(g_Statement[stmt].fileName), - "}.", NULL), "", " "); - print2("\n"); - } else { - printLongLine(cat("Statement ", - asciiToTt(g_Statement[stmt].labelName), " ", - str1, " ", - asciiToTt(g_Statement[stmt].fileName), - " ", NULL), "", "\""); - } - g_outputToString = 0; - fprintf(g_texFilePtr, "%s", g_printString); - let(&g_printString, ""); - } - - let(&str1, ""); - str1 = getDescription(stmt); - if (str1[0]) { - if (!texFlag) { - printLongLine(cat("\"", str1, "\"", NULL), "", " "); - } else { - printTexComment(str1, /* Sends result to g_texFilePtr */ - 1, /* 1 = htmlCenterFlag */ - PROCESS_EVERYTHING, /* actionBits */ - 1 /* 1 = fileCheck */); - } - } - - j = nmbrLen(g_Statement[stmt].reqHypList); - for (i = 0; i < j; i++) { - k = g_Statement[stmt].reqHypList[i]; - if (!essentialFlag || g_Statement[k].type != f_) { - let(&str2, cat(" ",g_Statement[k].labelName, - " $", chr(g_Statement[k].type), " ", NULL)); - if (!texFlag) { - printLongLine(cat(str2, - nmbrCvtMToVString(g_Statement[k].mathString), " $.", NULL), - " "," "); - } else { - let(&str3, space((long)strlen(str2))); - printTexLongMath(g_Statement[k].mathString, - str2, str3, 0, 0); - } - } - } - - let(&str1, ""); - type = g_Statement[stmt].type; - if (type == p_) let(&str1, " $= ..."); - let(&str2, cat(" ", g_Statement[stmt].labelName, - " $",chr(type), " ", NULL)); - if (!texFlag) { - printLongLine(cat(str2, - nmbrCvtMToVString(g_Statement[stmt].mathString), - str1, " $.", NULL), " ", " "); - } else { - let(&str3, space((long)strlen(str2))); - printTexLongMath(g_Statement[stmt].mathString, - str2, str3, 0, 0); - } - - } /* End if (statementUsedFlag[stmt] == 'Y') */ - } /* Next stmt */ - - let(&statementUsedFlags, ""); /* 'Y'/'N' flag that statement is used */ - let(&str1, ""); - let(&str2, ""); - let(&str3, ""); - nmbrLet(&statementList, NULL_NMBRSTRING); - nmbrLet(&proof, NULL_NMBRSTRING); - nmbrLet(&essentialFlags, NULL_NMBRSTRING); - -} /* proofStmtSumm */ - - -/* Traces back the statements used by a proof, recursively. */ -/* Returns 1 if at least one label is printed (or would be printed in - case testOnlyFlag=1); otherwise, returns 0 */ -/* matchList suppresses all output except labels matching matchList */ -/* testOnlyFlag prevents any printout; it is used to determine whether - there is an unwanted axiom for MINIMIZE_WITH /FORBID. */ -flag traceProof(long statemNum, - flag essentialFlag, - flag axiomFlag, - vstring matchList, - vstring traceToList, - flag testOnlyFlag) -{ - - long stmt, pos; - vstring statementUsedFlags = ""; /* y/n flags that statement is used */ - vstring outputString = ""; - nmbrString *unprovedList = NULL_NMBRSTRING; - flag foundFlag = 0; - - /* Make sure we're calling this with $p statements only */ - if (g_Statement[statemNum].type != (char)p_) bug(249); - - if (!testOnlyFlag) { - if (axiomFlag) { - print2( - "Statement \"%s\" assumes the following axioms ($a statements):\n", - g_Statement[statemNum].labelName); - } else if (traceToList[0] == 0) { - print2( - "The proof of statement \"%s\" uses the following earlier statements:\n", - g_Statement[statemNum].labelName); - } else { - print2( - "The proof of statement \"%s\" traces back to \"%s\" via:\n", - g_Statement[statemNum].labelName, traceToList); - } - } - - traceProofWork(statemNum, - essentialFlag, - traceToList, /* /TO argument of SHOW TRACE_BACK */ - &statementUsedFlags, - &unprovedList); - if ((signed)(strlen(statementUsedFlags)) != g_statements + 1) bug(226); - - /* Build the output string */ - let(&outputString, ""); - for (stmt = 1; stmt < statemNum; stmt++) { - if (statementUsedFlags[stmt] == 'Y') { - - if (matchList[0]) { /* There is a list to match */ - /* Don't include unmatched labels */ - if (!matchesList(g_Statement[stmt].labelName, matchList, '*', '?')) - continue; - } - - /* Skip rest of scan in testOnlyFlag mode */ - foundFlag = 1; /* At least one label would be printed */ - if (testOnlyFlag) { - goto TRACE_RETURN; - } - if (axiomFlag) { - if (g_Statement[stmt].type == a_) { - let(&outputString, cat(outputString, " ", g_Statement[stmt].labelName, - NULL)); - } - } else { - let(&outputString, cat(outputString, " ", g_Statement[stmt].labelName, - NULL)); - switch (g_Statement[stmt].type) { - case a_: let(&outputString, cat(outputString, "($a)", NULL)); break; - case e_: let(&outputString, cat(outputString, "($e)", NULL)); break; - case f_: let(&outputString, cat(outputString, "($f)", NULL)); break; - } - } - } /* End if (statementUsedFlag[stmt] == 'Y') */ - } /* Next stmt */ - - /* Skip printing in testOnlyFlag mode */ - if (testOnlyFlag) { - goto TRACE_RETURN; - } - - if (outputString[0]) { - let(&outputString, cat(" ", outputString, NULL)); - } else { - let(&outputString, " (None)"); - } - - /* Print the output */ - printLongLine(outputString, " ", " "); - - /* Print any unproved statements */ - if (nmbrLen(unprovedList)) { - print2("Warning: The following traced statement(s) were not proved:\n"); - let(&outputString, ""); - for (pos = 0; pos < nmbrLen(unprovedList); pos++) { - let(&outputString, cat(outputString, " ", g_Statement[unprovedList[ - pos]].labelName, NULL)); - } - let(&outputString, cat(" ", outputString, NULL)); - printLongLine(outputString, " ", " "); - } - - TRACE_RETURN: - /* Deallocate */ - let(&outputString, ""); - let(&statementUsedFlags, ""); - nmbrLet(&unprovedList, NULL_NMBRSTRING); - return foundFlag; -} /* traceProof */ - -/* Traces back the statements used by a proof, recursively. Returns - a nmbrString with a list of statements and unproved statements */ -void traceProofWork(long statemNum, - flag essentialFlag, - vstring traceToList, /* /TO argument of SHOW TRACE_BACK */ - vstring *statementUsedFlagsP, /* 'Y'/'N' flag that statement is used */ - nmbrString **unprovedListP) -{ - - long pos, stmt, plen, slen, step; - nmbrString *statementList = NULL_NMBRSTRING; - nmbrString *proof = NULL_NMBRSTRING; - nmbrString *essentialFlags = NULL_NMBRSTRING; - vstring traceToFilter = ""; - vstring str1 = ""; - long j; - - /* Preprocess the "SHOW TRACE_BACK ... / TO" traceToList list if any */ - if (traceToList[0] != 0) { - let(&traceToFilter, string(g_statements + 1, 'N')); /* Init. to 'no' */ - /* Wildcard match scan */ - for (stmt = 1; stmt <= g_statements; stmt++) { - if (g_Statement[stmt].type != (char)a_ - && g_Statement[stmt].type != (char)p_) - continue; /* Not a $a or $p statement; skip it */ - /* Wildcard matching */ - if (!matchesList(g_Statement[stmt].labelName, traceToList, '*', '?')) - continue; - let(&str1, ""); - str1 = traceUsage(stmt /*g_showStatement*/, - 1, /*recursiveFlag*/ - statemNum /* cutoffStmt */); - traceToFilter[stmt] = 'Y'; /* Include the statement we're showing - usage of */ - if (str1[0] == 'Y') { /* There is some usage */ - for (j = stmt + 1; j <= g_statements; j++) { - /* OR in the usage to the filter */ - if (str1[j] == 'Y') traceToFilter[j] = 'Y'; - } - } - } /* Next i (statement number) */ - } /* if (traceToList[0] != 0) */ - - nmbrLet(&statementList, nmbrSpace(g_statements)); - statementList[0] = statemNum; - slen = 1; - nmbrLet(&(*unprovedListP), NULL_NMBRSTRING); /* List of unproved statements */ - let(&(*statementUsedFlagsP), string(g_statements + 1, 'N')); /* Init. to 'no' */ - (*statementUsedFlagsP)[statemNum] = 'Y'; - for (pos = 0; pos < slen; pos++) { - if (g_Statement[statementList[pos]].type != p_) { - continue; /* Not a $p */ - } - - /* Don't use bad proofs (incomplete proofs are ok) */ - if (parseProof(statementList[pos]) > 1) { - /* The proof has an error, so use the empty proof */ - nmbrLet(&proof, nmbrAddElement(NULL_NMBRSTRING, -(long)'?')); - } else { - nmbrLet(&proof, g_WrkProof.proofString); - } - - plen = nmbrLen(proof); - /* Get the essential step flags, if required */ - if (essentialFlag) { - nmbrLet(&essentialFlags, nmbrGetEssential(proof)); - } - for (step = 0; step < plen; step++) { - if (essentialFlag) { - if (!essentialFlags[step]) continue; /* Ignore floating hypotheses */ - } - stmt = proof[step]; - if (stmt < 0) { - if (stmt > -1000) { - /* '?' */ - if (!nmbrElementIn(1, *unprovedListP, statementList[pos])) { - nmbrLet(&(*unprovedListP), nmbrAddElement(*unprovedListP, - statementList[pos])); /* Add to list of unproved statements */ - } - } - continue; /* Ignore '?' and local labels */ - } - if (1) { /* Limit list to $a and $p only */ - if (g_Statement[stmt].type != a_ && g_Statement[stmt].type != p_) { - continue; - } - } - /* Add this statement to the statement list if not already in it */ - if ((*statementUsedFlagsP)[stmt] == 'N') { - if (traceToList[0] == 0) { - statementList[slen] = stmt; - slen++; - (*statementUsedFlagsP)[stmt] = 'Y'; - } else { /* TRACE_BACK / TO */ - if (traceToFilter[stmt] == 'Y') { - statementList[slen] = stmt; - slen++; - (*statementUsedFlagsP)[stmt] = 'Y'; - } - } - } - } /* Next step */ - } /* Next pos */ - - /* Deallocate */ - nmbrLet(&essentialFlags, NULL_NMBRSTRING); - nmbrLet(&proof, NULL_NMBRSTRING); - nmbrLet(&statementList, NULL_NMBRSTRING); - let(&str1, ""); - let(&str1, ""); - return; - -} /* traceProofWork */ - -nmbrString *stmtFoundList = NULL_NMBRSTRING; -long indentShift = 0; - -/* Traces back the statements used by a proof, recursively, with tree display.*/ -void traceProofTree(long statemNum, - flag essentialFlag, long endIndent) -{ - if (g_Statement[statemNum].type != p_) { - print2("Statement %s is not a $p statement.\n", - g_Statement[statemNum].labelName); - return; - } - - printLongLine(cat("The proof tree traceback for statement \"", - g_Statement[statemNum].labelName, - "\" follows. The statements used by each proof are indented one level in,", - " below the statement being proved. Hypotheses are not included.", - NULL), - "", " "); - print2("\n"); - - nmbrLet(&stmtFoundList, NULL_NMBRSTRING); - indentShift = 0; - traceProofTreeRec(statemNum, essentialFlag, endIndent, 0); - nmbrLet(&stmtFoundList, NULL_NMBRSTRING); -} /* traceProofTree */ - - -void traceProofTreeRec(long statemNum, - flag essentialFlag, long endIndent, long recursDepth) -{ - long i, pos, stmt, plen, slen, step; - vstring outputStr = ""; - nmbrString *localFoundList = NULL_NMBRSTRING; - nmbrString *localPrintedList = NULL_NMBRSTRING; - flag unprovedFlag = 0; - nmbrString *proof = NULL_NMBRSTRING; - nmbrString *essentialFlags = NULL_NMBRSTRING; - - - let(&outputStr, ""); - outputStr = getDescription(statemNum); /* Get statement comment */ - let(&outputStr, edit(outputStr, 8 + 16 + 128)); /* Trim and reduce spaces */ - slen = len(outputStr); - for (i = 0; i < slen; i++) { - /* Change newlines to spaces in comment */ - if (outputStr[i] == '\n') { - outputStr[i] = ' '; - } - } - -#define INDENT_INCR 3 -#define MAX_LINE_LEN 79 - - if ((recursDepth * INDENT_INCR - indentShift) > - (g_screenWidth - MAX_LINE_LEN) + 50) { - indentShift = indentShift + 40 + (g_screenWidth - MAX_LINE_LEN); - print2("****** Shifting indentation. Total shift is now %ld.\n", - (long)indentShift); - } - if ((recursDepth * INDENT_INCR - indentShift) < 1 && indentShift != 0) { - indentShift = indentShift - 40 - (g_screenWidth - MAX_LINE_LEN); - print2("****** Shifting indentation. Total shift is now %ld.\n", - (long)indentShift); - } - - let(&outputStr, cat(space(recursDepth * INDENT_INCR - indentShift), - g_Statement[statemNum].labelName, " $", chr(g_Statement[statemNum].type), - " \"", edit(outputStr, 8 + 128), "\"", NULL)); - - if (len(outputStr) > MAX_LINE_LEN + (g_screenWidth - MAX_LINE_LEN)) { - let(&outputStr, cat(left(outputStr, - MAX_LINE_LEN + (g_screenWidth - MAX_LINE_LEN) - 3), "...", NULL)); - } - - if (g_Statement[statemNum].type == p_ || g_Statement[statemNum].type == a_) { - /* Only print assertions to reduce output bulk */ - print2("%s\n", outputStr); - } - - if (g_Statement[statemNum].type != p_) { - let(&outputStr, ""); - return; - } - - if (endIndent) { - /* An indentation level limit is set */ - if (endIndent < recursDepth + 2) { - let(&outputStr, ""); - return; - } - } - - /* Don't use bad proofs (incomplete proofs are ok) */ - if (parseProof(statemNum) > 1) { - /* The proof has an error, so use the empty proof */ - nmbrLet(&proof, nmbrAddElement(NULL_NMBRSTRING, -(long)'?')); - } else { - nmbrLet(&proof, g_WrkProof.proofString); - } - - plen = nmbrLen(proof); - /* Get the essential step flags, if required */ - if (essentialFlag) { - nmbrLet(&essentialFlags, nmbrGetEssential(proof)); - } - nmbrLet(&localFoundList, NULL_NMBRSTRING); - nmbrLet(&localPrintedList, NULL_NMBRSTRING); - for (step = 0; step < plen; step++) { - if (essentialFlag) { - if (!essentialFlags[step]) continue; - /* Ignore floating hypotheses */ - } - stmt = proof[step]; - if (stmt < 0) { - if (stmt > -1000) { - /* '?' */ - unprovedFlag = 1; - } - continue; /* Ignore '?' and local labels */ - } - if (!nmbrElementIn(1, localFoundList, stmt)) { - nmbrLet(&localFoundList, nmbrAddElement(localFoundList, stmt)); - } - if (!nmbrElementIn(1, stmtFoundList, stmt)) { - traceProofTreeRec(stmt, essentialFlag, endIndent, recursDepth + 1); - nmbrLet(&localPrintedList, nmbrAddElement(localPrintedList, stmt)); - nmbrLet(&stmtFoundList, nmbrAddElement(stmtFoundList, stmt)); - } - } /* Next step */ - - /* See if there are any old statements printed previously */ - slen = nmbrLen(localFoundList); - let(&outputStr, ""); - for (pos = 0; pos < slen; pos++) { - stmt = localFoundList[pos]; - if (!nmbrElementIn(1, localPrintedList, stmt)) { - /* Don't include $f, $e in output */ - if (g_Statement[stmt].type == p_ || g_Statement[stmt].type == a_) { - let(&outputStr, cat(outputStr, " ", - g_Statement[stmt].labelName, NULL)); - } - } - } - - if (len(outputStr)) { - printLongLine(cat(space(INDENT_INCR * (recursDepth + 1) - 1 - indentShift), - outputStr, " (shown above)", NULL), - space(INDENT_INCR * (recursDepth + 2) - indentShift), " "); - } - - if (unprovedFlag) { - printLongLine(cat(space(INDENT_INCR * (recursDepth + 1) - indentShift), - "*** Statement ", g_Statement[statemNum].labelName, " has not been proved." - , NULL), - space(INDENT_INCR * (recursDepth + 2)), " "); - } - - let(&outputStr, ""); - nmbrLet(&localFoundList, NULL_NMBRSTRING); - nmbrLet(&localPrintedList, NULL_NMBRSTRING); - nmbrLet(&proof, NULL_NMBRSTRING); - nmbrLet(&essentialFlags, NULL_NMBRSTRING); - -} /* traceProofTreeRec */ - - -/* Called by SHOW TRACE_BACK
", - "Colors of variables: ", - g_htmlVarColor, "
Syntax hints: "); - } - - /* Get the main symbol in the syntax */ - /* This section can be deleted if not wanted - it is custom - for set.mm and might not work with other .mm's */ - let(&tmpStr1, ""); - for (i = 1 /* Skip |- */; i < g_Statement[stmt].mathStringLen; i++) { - if (g_MathToken[(g_Statement[stmt].mathString)[i]].tokenType == - (char)con_) { - /* Skip parentheses, commas, etc. */ - if (strcmp(g_MathToken[(g_Statement[stmt].mathString)[i] - ].tokenName, "(") - && strcmp(g_MathToken[(g_Statement[stmt].mathString)[i] - ].tokenName, ",") - && strcmp(g_MathToken[(g_Statement[stmt].mathString)[i] - ].tokenName, ")") - && strcmp(g_MathToken[(g_Statement[stmt].mathString)[i] - ].tokenName, ":") - /* Use |-> rather than e. for cmpt, cmpt2 */ - && !(!strcmp(g_MathToken[(g_Statement[stmt].mathString)[i] - ].tokenName, "e.") - && (!strcmp(g_Statement[stmt].labelName, "cmpt") - || !strcmp(g_Statement[stmt].labelName, "cmpt2"))) - ) { - tmpStr1 = - tokenToTex(g_MathToken[(g_Statement[stmt].mathString)[i] - ].tokenName, stmt); - let(&tmpStr1, cat( - (g_altHtmlFlag ? cat("", NULL) : ""), - tmpStr1, - (g_altHtmlFlag ? "" : ""), - NULL)); - break; - } - } - } /* Next i */ - /* Special cases hard-coded for set.mm */ - if (!strcmp(g_Statement[stmt].labelName, "wbr")) /* binary relation */ - let(&tmpStr1, " class class class "); - if (!strcmp(g_Statement[stmt].labelName, "cv")) - let(&tmpStr1, "[set variable]"); - /* Let's don't do cv - confusing to reader */ - if (!strcmp(g_Statement[stmt].labelName, "cv")) - continue; - if (!strcmp(g_Statement[stmt].labelName, "co")) /* operation */ - let(&tmpStr1, "(class class class)"); - let(&tmpStr, cat(tmpStr, "  ", tmpStr1, NULL)); - /* End section - Get the main symbol in the syntax */ - - let(&tmpStr1, ""); - tmpStr1 = pinkHTML(stmt); - let(&tmpStr, cat(tmpStr, "", - g_Statement[stmt].labelName, "", tmpStr1, NULL)); - - - } - } - if (tmpStr[0]) { - let(&tmpStr, cat(tmpStr, - "
" - "This theorem was proved from axioms:"); - } - let(&tmpStr1, ""); - tmpStr1 = pinkHTML(stmt); - let(&tmpStr, cat(tmpStr, "  ", - g_Statement[stmt].labelName, "", tmpStr1, NULL)); - } - } - } /* next stmt */ - if (tmpStr[0]) { - let(&tmpStr, cat(tmpStr, "
This theorem depends on definitions:"); - } - let(&tmpStr1, ""); - tmpStr1 = pinkHTML(stmt); - let(&tmpStr, cat(tmpStr, "  ", - g_Statement[stmt].labelName, "", tmpStr1, NULL)); - } - } - } /* next stmt */ - if (tmpStr[0]) { - let(&tmpStr, cat(tmpStr, "
 ", -"WARNING: This theorem has an incomplete proof.
 ", -"WARNING: This proof depends on the following unproved theorem(s): ", - NULL), "", "\""); - let(&tmpStr, ""); - for (i = 0; i < nmbrLen(unprovedList); i++) { - let(&tmpStr, cat(tmpStr, " ", - g_Statement[unprovedList[i]].labelName, "", - NULL)); - } - printLongLine(cat(tmpStr, "
\n", (k == 1) ? "Hypothesis" : "Hypotheses"); + print2("\n", + (k == 1) ? "Hypothesis" : "Hypotheses"); + print2("\n"); + } + for (i = 0; i < j; i++) { + k = g_Statement[showStmt].reqHypList[i]; + if (g_Statement[k].type != (char)e_ + + /* For syntax definitions, include $f hypotheses so user can more + easily match them in syntax breakdowns of axioms & definitions */ + && !(subType == SYNTAX && (texFlag && htmlFlg) + && g_Statement[k].type == (char)f_) + + ) continue; + + if (!texFlag) { + let(&str2, cat(str((double)k), " ", NULL)); + } else { + let(&str2, " "); + } + let(&str2, cat(str2, g_Statement[k].labelName, + " $", chr(g_Statement[k].type), " ", NULL)); + if (!texFlag) { + printLongLine(cat(str2, + nmbrCvtMToVString(g_Statement[k].mathString), " $.", NULL), + " "," "); + } else { /* if texFlag */ + /* texFlag was (misleadingly) included below to facilitate search + for "htmlFlg && texFlag". */ + if (!(htmlFlg && texFlag)) { + if (!g_oldTexFlag) { + /* Do nothing */ + } else { + let(&str3, space((long)strlen(str2))); + printTexLongMath(g_Statement[k].mathString, + str2, str3, 0, 0); + } + } else { + g_outputToString = 1; + print2("
%s
Ref\n"); + print2("Expression
%s\n", + g_Statement[k].labelName); + /* Print hypothesis */ + printTexLongMath(g_Statement[k].mathString, "", "", 0, 0); + } + } + } /* next i */ + if (texFlag && htmlFlg) { + g_outputToString = 1; + print2("
\n"); + } + } /* if k (#essential hyp) */ + } + + let(&str1, ""); + type = g_Statement[showStmt].type; + if (type == p_) let(&str1, " $= ..."); + if (!texFlag) + let(&str2, cat(str((double)showStmt), " ", NULL)); + else + let(&str2, " "); + let(&str2, cat(str2, g_Statement[showStmt].labelName, + " $",chr(type), " ", NULL)); + if (!texFlag) { + printLongLine(cat(str2, + nmbrCvtMToVString(g_Statement[showStmt].mathString), + str1, " $.", NULL), " ", " "); + } else { + if (!(htmlFlg && texFlag)) { /* really !htmlFlg & texFlag */ + if (!g_oldTexFlag) { + g_outputToString = 1; + print2("\\begin{align}\n"); + let(&str3, ""); + /* Get HTML hypotheses => assertion */ + str3 = getTexOrHtmlHypAndAssertion(showStmt); /* In mmwtex.c */ + printLongLine(cat(str3, + /* No space before \label to make it easier to find last + parenthesis in a post-processing script */ + "\\label{eq:", + g_Statement[showStmt].labelName, + "}", + + /* Add "\tag{..}" to use .mm labels instead of equation numbers */ + /* (Suggested by Ari Ferrera) */ + "\\tag{", + g_Statement[showStmt].labelName, + "}", + + NULL), " ", " "); + /* print2(" \\label{eq:%s}\n",g_Statement[showStmt].labelName); */ + print2("\\end{align}\n"); + + + /* Distinguish axiom, definition, theorem for LaTeX */ + /* Note: changes here must be mirrored in the \begin{...} above */ + if (g_Statement[showStmt].type == a_) { + if (!strcmp(left(g_Statement[showStmt].labelName, 3), "ax-")) { + let(&str3, "axiom"); + } else { + let(&str3, "definition"); + } + } else { + let(&str3, "theorem"); + } + print2("%s\n", cat("\\end{", str3, "}", NULL)); + + fprintf(g_texFilePtr, "%s", g_printString); + let(&g_printString, ""); + g_outputToString = 0; + + } else { /* old TeX code */ + let(&str3, space((long)strlen(str2))); /* 3rd argument of printTexLongMath + cannot be temp allocated */ + printTexLongMath(g_Statement[showStmt].mathString, + str2, str3, 0, 0); + } + } else { /* (htmlFlg && texFlag) */ + g_outputToString = 1; + print2("
\n"); + print2("\n"); + print2("\n"); + printLongLine(cat( + "
Assertion
Ref\n"); + print2("Expression
", g_Statement[showStmt].labelName, + "", NULL), " ", " "); + printTexLongMath(g_Statement[showStmt].mathString, "", "", 0, 0); + g_outputToString = 1; + print2("
\n"); + } + } + + if (briefFlag) goto returnPoint; + + switch (type) { + case a_: + case p_: + /* This is not really needed but keeps output consistent + with previous version. It puts a blank line before the HTML + "distinct variable" list. */ + if (texFlag && htmlFlg) { + g_outputToString = 1; + print2("\n"); + g_outputToString = 0; + } + + if (!texFlag) { + print2("Its mandatory hypotheses in RPN order are:\n"); + } + j = nmbrLen(g_Statement[showStmt].reqHypList); + for (i = 0; i < j; i++) { + k = g_Statement[showStmt].reqHypList[i]; + if (g_Statement[k].type != (char)e_ && (!htmlFlg && texFlag)) + continue; /* Don't put $f's in LaTeX output */ + let(&str2, cat(" ",g_Statement[k].labelName, + " $", chr(g_Statement[k].type), " ", NULL)); + if (!texFlag) { + printLongLine(cat(str2, + nmbrCvtMToVString(g_Statement[k].mathString), " $.", NULL), + " "," "); + } + } + /* This is not really needed but keeps output consistent + with previous version. It puts a blank line before the HTML + "distinct variable" list. */ + if (texFlag && htmlFlg) { + g_outputToString = 1; + print2("\n"); + g_outputToString = 0; + } + if (j == 0 && !texFlag) print2(" (None)\n"); + let(&str1, ""); + nmbrTmpPtr1 = g_Statement[showStmt].reqDisjVarsA; + nmbrTmpPtr2 = g_Statement[showStmt].reqDisjVarsB; + i = nmbrLen(nmbrTmpPtr1); + if (i) { + for (k = 0; k < i; k++) { + if (!texFlag) { + let(&str1, cat(str1, ", <", + g_MathToken[nmbrTmpPtr1[k]].tokenName, ",", + g_MathToken[nmbrTmpPtr2[k]].tokenName, ">", NULL)); + } else { + if (htmlFlg && texFlag) { + let(&str2, ""); + str2 = tokenToTex(g_MathToken[nmbrTmpPtr1[k]].tokenName, showStmt); + /* tokenToTex allocates str2; we must deallocate it */ + let(&str1, cat(str1, "   ", str2, NULL)); + let(&str2, ""); + str2 = tokenToTex(g_MathToken[nmbrTmpPtr2[k]].tokenName, showStmt); + let(&str1, cat(str1, ",", str2, NULL)); + } + } + } + if (!texFlag) + printLongLine(cat( + "Its mandatory disjoint variable pairs are: ", + right(str1,3),NULL)," "," "); + } + if (type == p_ && + nmbrLen(g_Statement[showStmt].optHypList) + && !texFlag) { + printLongLine(cat( + "Its optional hypotheses are: ", + nmbrCvtRToVString( + g_Statement[showStmt].optHypList, + 0, /*explicitTargets*/ + 0 /*statemNum, used only if explicitTargets*/), NULL), + " "," "); + } + nmbrTmpPtr1 = g_Statement[showStmt].optDisjVarsA; + nmbrTmpPtr2 = g_Statement[showStmt].optDisjVarsB; + i = nmbrLen(nmbrTmpPtr1); + if (i && type == p_) { + if (!texFlag) { + let(&str1, ""); + } + for (k = 0; k < i; k++) { + if (!texFlag) { + let(&str1, cat(str1, ", <", + g_MathToken[nmbrTmpPtr1[k]].tokenName, ",", + g_MathToken[nmbrTmpPtr2[k]].tokenName, ">", NULL)); + } /* if !texFlag */ + } /* next k */ + if (!texFlag) { + printLongLine(cat( + "Its optional disjoint variable pairs are: ", + right(str1,3),NULL)," "," "); + } + } /* if (i && type == p_) */ + + + if (texFlag && htmlFlg) { /* It's a web page */ + + if (htmlDistinctVars[0] != 0) { + g_outputToString = 1; + printLongLine(cat( + "
", + " 0) ? + "mmset.html" : + /* The following link will work in the NF and other + "Proof Explorers" */ + "../mpeuni/mmset.html", + + "#distinct\">Distinct variable group", + distVarGrps > 1 ? "s" : "", + ": ", + /* Put a span around the variable list to localize + the use of the special math font for ALT_HTML */ + (g_altHtmlFlag ? cat("", NULL) : ""), + htmlDistinctVars, + (g_altHtmlFlag ? "" : ""), + "
", + NULL), "", "\""); + g_outputToString = 0; + } + + let(&str2, ""); + str2 = htmlAllowedSubst(showStmt); + if (str2[0] != 0) { + g_outputToString = 1; + /* Print the list of allowed free variables */ + printLongLine(str2, "", "\""); + g_outputToString = 0; + } + + } /* if (texFlag && htmlFlg) */ + + if (texFlag) { + g_outputToString = 1; + if (htmlFlg && texFlag) print2("
\n"); + g_outputToString = 0; /* Restore normal output */ + break; /* case a_ or p_ */ + } + let(&str1, nmbrCvtMToVString( + g_Statement[showStmt].reqVarList)); + if (!strlen(str1)) let(&str1, "(None)"); + printLongLine(cat( + "The statement and its hypotheses require the variables: ", + str1, NULL), " ", " "); + if (type == p_ && + nmbrLen(g_Statement[showStmt].optVarList)) { + printLongLine(cat( + "These additional variables are allowed in its proof: " + ,nmbrCvtMToVString( + g_Statement[showStmt].optVarList),NULL)," ", + " "); + /*??? Add variables required by proof */ + } + /* Note: g_Statement[].reqVarList is only stored for $a and $p + statements, not for $e or $f. */ + let(&str1, nmbrCvtMToVString( + g_Statement[showStmt].reqVarList)); + if (!strlen(str1)) let(&str1, "(None)"); + printLongLine(cat("The variables it contains are: ", + str1, NULL), + " ", " "); + break; /* case a_ or p_ */ + default: + break; + } /* End switch(type) */ + if (texFlag) { + g_outputToString = 0; + } + + /* Start of finding definition for syntax statement */ + if (htmlFlg && texFlag) { + + /* For syntax declarations, find the first definition that follows + it. It is up to the user to arrange the database so that a + meaningful definition is picked. */ + if (subType == SYNTAX) { + for (i = showStmt + 1; i <= g_statements; i++) { + if (g_Statement[i].type == (char)a_) { + if (!strcmp("|-", g_MathToken[ + (g_Statement[i].mathString)[0]].tokenName)) { + /* It's a definition or axiom */ + /* See if each constant token in the syntax statement + exists in the definition; if not don't use the definition */ + j = 1; + /* We start with k=1 for 2nd token (1st is wff, class, etc.) */ + for (k = 1; k < g_Statement[showStmt].mathStringLen; k++) { + if (g_MathToken[(g_Statement[showStmt].mathString)[k]]. + tokenType == (char)con_) { + if (!nmbrElementIn(1, g_Statement[i].mathString, + (g_Statement[showStmt].mathString)[k])) { + /* The definition being considered doesn't have one of + the constant symbols in the syntax statement, so + reject it */ + j = 0; + break; /* Out of k loop */ + } + } + } /* Next k */ + if (j) { + /* Successful - use this definition or axiom as the reference */ + g_outputToString = 1; + let(&str1, left(g_Statement[i].labelName, 3)); + let(&str2, ""); + str2 = pinkHTML(i); + if (!strcmp(str1, "ax-")) { + printLongLine(cat( + "
This syntax is primitive.", + " The first axiom using it is ", + g_Statement[i].labelName, + "", str2, ".

", + NULL), "", "\""); + } else { + printLongLine(cat( + "
See definition ", + g_Statement[i].labelName, "", str2, + " for more information.

", + NULL), "", "\""); + } + + printLongLine(cat( + "
", + NULL), "", "\""); + g_outputToString = 0; + break; /* Out of i loop */ + } + } + } + } /* Next i */ + } /* if (subType == SYNTAX) */ + + + /* For definitions, we pretend that the definition is a "wff" (hard-coded + here; the .mm database provided by the user must use this convention). + We use the proof assistant tools to prove that the statement is + a wff, then we print the wff construction proof to the HTML file. */ + if (subType == DEFINITION || subType == AXIOM) { + + /* Look up the token "wff" if we haven't found it before */ + if (wffToken == -1) { /* First time */ + wffToken = -2; /* In case it's not found because the user's source + used a convention different for "wff" for wffs */ + for (i = 0; i < g_mathTokens; i++) { + if (!strcmp("wff", g_MathToken[i].tokenName)) { + wffToken = i; + break; + } + } + } + + if (wffToken >= 0) { + /* Temporarily zap statement type from $a to $p */ + if (g_Statement[showStmt].type != (char)a_) bug(231); + g_Statement[showStmt].type = (char)p_; + /* Temporarily zap statement with "wff" token in 1st position + so parseProof will not give errors (in typeProof() call) */ + zapStatement1stToken = (g_Statement[showStmt].mathString)[0]; + (g_Statement[showStmt].mathString)[0] = wffToken; + if (strcmp("|-", g_MathToken[zapStatement1stToken].tokenName)) bug(230); + + nmbrTmpPtr1 = NULL_NMBRSTRING; + nmbrLet(&nmbrTmpPtr1, g_Statement[showStmt].mathString); + + /* Find proof of formula or simple theorem (no new vars in $e's) */ + /* maxEDepth is the maximum depth at which statements with $e + hypotheses are + considered. A value of 0 means none are considered. */ + nmbrTmpPtr2 = proveFloating(nmbrTmpPtr1 /*mString*/, + showStmt /*statemNum*/, 0 /*maxEDepth*/, + 0, /*step: 0 = step 1 */ /*For messages*/ + 0, /*not noDistinct*/ + 2, /* override discouraged-usage statements silently */ + 1 /* Always allow other mathboxes */ + ); + + if (nmbrLen(nmbrTmpPtr2)) { + /* A proof for the step was found. */ + /* Get packed form of proof for shorter display */ + nmbrLet(&nmbrTmpPtr2, nmbrSquishProof(nmbrTmpPtr2)); + /* Temporarily zap proof into statement structure */ + /* (The bug check makes sure there is no proof attached to the + definition - this would be impossible) */ + if (strcmp(g_Statement[showStmt].proofSectionPtr, "")) bug(231); + if (g_Statement[showStmt].proofSectionLen != 0) bug(232); + let(&str1, nmbrCvtRToVString(nmbrTmpPtr2, + 0, /*explicitTargets*/ + 0 /*statemNum, used only if explicitTargets*/)); + /* Temporarily zap proof into the $a statement */ + g_Statement[showStmt].proofSectionPtr = str1; + g_Statement[showStmt].proofSectionLen = (long)strlen(str1) - 1; + + /* Display the HTML proof of syntax breakdown */ + typeProof(showStmt, + 0 /*pipFlag*/, + 0 /*startStep*/, + 0 /*endStep*/, + 0 /*endIndent*/, + 0 /*essentialFlag*/, /* <- also used as def flag in typeProof */ + 1 /*renumberFlag*/, + 0 /*unknownFlag*/, + 0 /*notUnifiedFlag*/, + 0 /*reverseFlag*/, + 1 /*noIndentFlag*/, + 0 /*splitColumn*/, + 0 /*skipRepeatedSteps*/, + 1 /*texFlag*/, /* Means either latex or html */ + 1 /*htmlFlg*/); + + /* Restore the zapped statement structure */ + g_Statement[showStmt].proofSectionPtr = ""; + g_Statement[showStmt].proofSectionLen = 0; + + /* Deallocate storage */ + let(&str1, ""); + nmbrLet(&nmbrTmpPtr2, NULL_NMBRSTRING); + + } else { /* if (nmbrLen(nmbrTmpPtr2)) else */ + /* Proof was not found - probable syntax error */ + if (g_outputToString != 0) bug(246); + printLongLine(cat( + "?Warning: Unable to generate syntax breakdown for \"", + g_Statement[showStmt].labelName, + "\".", NULL), " ", " "); + } + + + /* Restore the zapped statement structure */ + g_Statement[showStmt].type = (char)a_; + (g_Statement[showStmt].mathString)[0] = zapStatement1stToken; + + /* Deallocate storage */ + nmbrLet(&nmbrTmpPtr1, NULL_NMBRSTRING); + + } /* if (wffToken >= 0) */ + + } /* if (subType == DEFINITION) */ + + + } /* if (htmlFlg && texFlag) */ + /* End of finding definition for syntax statement */ + + + /* Start of creating used-by list for html page */ + if (htmlFlg && texFlag) { + /* Clear out any previous g_printString accumulation + for g_printStringForReferencedBy case below */ + fprintf(g_texFilePtr, "%s", g_printString); + let(&g_printString, ""); + /* Start outputting to g_printString */ + if (g_outputToString != 0) bug(242); + g_outputToString = 1; + if (subType != SYNTAX) { /* Only do this for + definitions, axioms, and theorems, not syntax statements */ + let(&str1, ""); + g_outputToString = 0; /* Switch output to console in case + traceUsage reports an error */ + str1 = traceUsage(showStmt, + 0, /* recursiveFlag */ + 0 /* cutoffStmt */); + g_outputToString = 1; /* Restore output to string */ + + /* str1[i] will be 'Y' if used by showStmt */ + /* Convert usage list str1 to html links */ + switch (subType) { + case AXIOM: let(&str3, "axiom"); break; + case DEFINITION: let(&str3, "definition"); break; + case THEOREM: let(&str3, "theorem"); break; + default: bug(233); + } + let(&str2, cat("", NULL)); + if (g_printString[0]) { + bug(256); + } + let(&g_printString, str2); + } /* if (subType != SYNTAX) */ + if (subType == THEOREM) { + /* The "referenced by" does not show up after the proof + because we moved the typeProof() to below. Therefore, we save + g_printString into a temporary global holding variable to print + at the proper place inside of typeProof(). Ugly but necessary + with present design. */ + /* In the case of THEOREM, we save and reset the g_printString. In the + case of != THEOREM (i.e. AXIOM and DEFINITION), g_printString will + be printed and cleared below. */ + let(&g_printStringForReferencedBy, g_printString); + let(&g_printString, ""); + } + + /* Printing of the trailer in mmwtex.c will close out string later */ + g_outputToString = 0; + } /* if (htmlFlg && texFlag) */ + /* End of used-by list for html page */ + + + /* After the block above, so referenced statements + show up first for convenience */ + if (htmlFlg && texFlag) { + /*** Output the html proof for $p statements ***/ + /* Note that we also output the axiom and definition usage + lists inside this function */ + if (g_Statement[showStmt].type == (char)p_) { + typeProof(showStmt, + 0 /*pipFlag*/, + 0 /*startStep*/, + 0 /*endStep*/, + 0 /*endIndent*/, + 1 /*essentialFlag*/, + 1 /*renumberFlag*/, + 0 /*unknownFlag*/, + 0 /*notUnifiedFlag*/, + 0 /*reverseFlag*/, + 1 /*noIndentFlag*/, + 0 /*splitColumn*/, + 0 /*skipRepeatedSteps*/, + 1 /*texFlag*/, /* Means either latex or html */ + 1 /*htmlFlg*/); + } /* if (g_Statement[showStmt].type == (char)p_) */ + } /* if (htmlFlg && texFlag) */ + /* End of html proof for $p statements */ + + /* typeProof should have cleared this out */ + if (g_printStringForReferencedBy[0]) bug(243); + + returnPoint: + /* Deallocate strings */ + nmbrLet(&nmbrDDList, NULL_NMBRSTRING); + let(&str1, ""); + let(&str2, ""); + let(&str3, ""); + let(&str4, ""); + let(&str5, ""); + let(&htmlDistinctVars, ""); +} /* typeStatement */ + + + +/* Get the HTML string of dummy variables used by a proof for the + theorem's web page. It should be called only if we're in + HTML output mode i.e. SHOW STATEMENT .../HTML or /ALT_HTML */ +/* This is HARD-CODED FOR SET.MM and will not produce meaningful + output for other databases (so far none) with $d's */ +/* Caller must deallocate returned string */ +vstring htmlDummyVars(long showStmt) +{ + nmbrString *optDVA; /* Pointer only; not allocated directly */ + nmbrString *optDVB; /* Pointer only; not allocated directly */ + long numDVs; + nmbrString *optHyp; /* Pointer only; not allocated directly */ + long numOptHyps; + vstring str1 = ""; + long k, l, n, hypStmt; + + /* Variables used while collecting a statement's dummy variables in $d's */ + long dummyVarCount; /* # of (different) dummy vars found in $d statements */ + vstring dummyVarUsed = ""; /* 'Y'/'N' indicators that we found that var */ + vstring htmlDummyVarList = ""; /* Output HTML string */ + long dummyVar; /* Current variable in a $d; test if it's a dummy variable */ + + /* This function should be called only for web page generation */ + if (!g_htmlFlag) bug(261); + + if (g_Statement[showStmt].type != p_) bug(262); + if (strcmp("|-", g_MathToken[ + (g_Statement[showStmt].mathString)[0]].tokenName)) { + /* Don't process syntax statements */ + goto RETURN_POINT; + } + + optDVA = g_Statement[showStmt].optDisjVarsA; + optDVB = g_Statement[showStmt].optDisjVarsB; + numDVs = nmbrLen(optDVA); + optHyp = g_Statement[showStmt].optHypList; + numOptHyps = nmbrLen(optHyp); + + if (numDVs == 0) { /* Don't create a hint list if no $d's */ + /*let(&htmlDummyVarList, "(no restrictions)");*/ + goto RETURN_POINT; + } + + dummyVarCount = 0; + if (numDVs != 0) { + + /* Update g_WrkProof.proofString with current proof so we can + search it later to see if it uses the dummy variable */ + parseProof(showStmt); /* Prints message if severe error */ + + /* Create an array of Y/N indicators that variable is occurs in a + $d statement as a dummy variable */ + let(&dummyVarUsed, string(g_mathTokens, 'N')); + for (k = 0; k < numDVs; k++) { + for (l = 1; l <= 2; l++) { + if (l == 1) { + dummyVar = optDVA[k]; + } else { + dummyVar = optDVB[k]; + } + /* At this point, dummyVar is just a var in the $d; we + must still check that it is in the optHypList */ + /* See if potential dummyVar is in optHypList */ + if (dummyVarUsed[dummyVar] == 'N') { + for (n = 0; n < numOptHyps; n++) { + /* Check whether dummyVar matches the 2nd token of an + optional hypothesis list entry e.g. "x" in "set x" */ + hypStmt = g_Statement[showStmt].optHypList[n]; + if (g_Statement[hypStmt].mathString[1] == dummyVar) { + /* dummyVar is a dummy variable */ + + /* See if it is used by the proof */ + /* g_WrkProof.proofString was updated by parseProof(showStmt) + above */ + if (nmbrElementIn(1, g_WrkProof.proofString, hypStmt) == 0) { + break; /* It's not used by the proof; stop hyp scan */ + } + + dummyVarUsed[dummyVar] = 'Y'; + dummyVarCount++; + /* tokenToTex allocates str1; must deallocate it first */ + let(&str1, ""); + /* Convert token to htmldef/althtmldef string */ + str1 = tokenToTex(g_MathToken[dummyVar].tokenName, + showStmt); + let(&htmlDummyVarList, cat(htmlDummyVarList, " ", str1, NULL)); + break; /* Found a match, so stop further checking */ + } + } /* next n, 0 to numOptHyps-1*/ + } /* if dummy var not used (yet) */ + } /* next l */ + } /* next k */ + } /* if (numDVs != 0) */ + + if (dummyVarCount > 0) { + let(&htmlDummyVarList, cat( + "
", + " 0) ? + "mmset.html" : + /* The following link will work in the NF and other + "Proof Explorers" */ + "../mpeuni/mmset.html", + + "#dvnote1\">Dummy variable", + /* Determine whether singular or plural */ + dummyVarCount > 1 ? "s" : "", + " ", + /* Put a span around the variable list to localize + the use of the special math font for ALT_HTML */ + (g_altHtmlFlag ? cat("", NULL) : ""), + htmlDummyVarList, + (g_altHtmlFlag ? "" : ""), + dummyVarCount > 1 ? " are mutually distinct and" : " is", + " distinct from all other variables.", + "
", + NULL)); + } /* htmlDummyVars */ + + + RETURN_POINT: + /* Deallocate strings */ + let(&dummyVarUsed, ""); + let(&str1, ""); + + return htmlDummyVarList; +} /* htmlDummyVars */ + + + +/* Get the HTML string of "allowed substitutions" list for an axiom + or theorem's web page. It should be called only if we're in + HTML output mode i.e. SHOW STATEMENT .../HTML or /ALT_HTML */ +/* This is HARD-CODED FOR SET.MM and will not produce meaningful + output for other databases (so far none) with $d's */ +/* Caller must deallocate returned string */ +vstring htmlAllowedSubst(long showStmt) +{ + nmbrString *reqHyp; /* Pointer only; not allocated directly */ + long numReqHyps; + nmbrString *reqDVA; /* Pointer only; not allocated directly */ + nmbrString *reqDVB; /* Pointer only; not allocated directly */ + long numDVs; + nmbrString *setVar = NULL_NMBRSTRING; /* set (individual) variables */ + char *strptr; + vstring str1 = ""; + long setVars; + long wffOrClassVar; + vstring setVarDVFlag = ""; + flag found, first; + long i, j, k; + vstring htmlAllowedList = ""; + long countInfo = 0; + + reqDVA = g_Statement[showStmt].reqDisjVarsA; + reqDVB = g_Statement[showStmt].reqDisjVarsB; + numDVs = nmbrLen(reqDVA); + + reqHyp = g_Statement[showStmt].reqHypList; + numReqHyps = nmbrLen(reqHyp); + + /* This function should be called only for web page generation */ + if (!g_htmlFlag) bug(250); + + if (g_Statement[showStmt].mathStringLen < 1) bug(254); + if (strcmp("|-", g_MathToken[ + (g_Statement[showStmt].mathString)[0]].tokenName)) { + /* Don't process syntax statements */ + goto RETURN_POINT; + } + + if (numDVs == 0) { /* Don't create a hint list if no $d's */ + goto RETURN_POINT; + } + + /* Collect list of all set variables in the theorem */ + /* First, count the number of set variables */ + setVars = 0; + for (i = 0; i < numReqHyps; i++) { + /* Scan "setvar" variables */ + if (g_Statement[reqHyp[i]].type == (char)e_) continue; + if (g_Statement[reqHyp[i]].type != (char)f_) bug(251); + if (g_Statement[reqHyp[i]].mathStringLen != 2) + bug(252); /* $f must have 2 tokens */ + strptr = g_MathToken[ + (g_Statement[reqHyp[i]].mathString)[0]].tokenName; + /* THE FOLLOWING IS SPECIFIC TO set.mm */ + if (strcmp("setvar", strptr)) continue; + /* Not a set variable */ + setVars++; + } + /* Next, create a list of them in setVar[] */ + j = 0; + nmbrLet(&setVar, nmbrSpace(setVars)); + for (i = 0; i < numReqHyps; i++) { + /* Scan "setvar" variables */ + if (g_Statement[reqHyp[i]].type == (char)e_) continue; + strptr = g_MathToken[ + (g_Statement[reqHyp[i]].mathString)[0]].tokenName; + if (strcmp("setvar", strptr)) continue; + /* Not a set variable */ + setVar[j] = (g_Statement[reqHyp[i]].mathString)[1]; + j++; + } + if (j != setVars) bug(253); + + /* Scan "wff" and "class" variables for attached $d's */ + for (i = 0; i < numReqHyps; i++) { + /* Look for a "wff" and "class" variable */ + if (g_Statement[reqHyp[i]].type == (char)e_) continue; + strptr = g_MathToken[ + (g_Statement[reqHyp[i]].mathString)[0]].tokenName; + if (strcmp("wff", strptr) && strcmp("class", strptr)) continue; + /* Not a wff or class variable */ + wffOrClassVar = (g_Statement[reqHyp[i]].mathString)[1]; + let(&setVarDVFlag, string(setVars, 'N')); /* No $d yet */ + /* Scan for attached $d's */ + for (j = 0; j < numDVs; j++) { + found = 0; + if (wffOrClassVar == reqDVA[j]) { + for (k = 0; k < setVars; k++) { + if (setVar[k] == reqDVB[j]) { + setVarDVFlag[k] = 'Y'; + found = 1; + break; + } + } + } + if (found) continue; + /* Repeat with swapped $d arguments */ + if (wffOrClassVar == reqDVB[j]) { + for (k = 0; k < setVars; k++) { + if (setVar[k] == reqDVA[j]) { + setVarDVFlag[k] = 'Y'; + break; + } + } + } + } /* next $d */ + + /* Collect set vars that don't have $d's with this wff or class var */ + /* First, if there aren't any, then omit this wff or class var */ + found = 0; + for (j = 0; j < setVars; j++) { + if (setVarDVFlag[j] == 'N') { + found = 1; + break; + } + } + if (found == 0) continue; /* All set vars have $d with this wff or class */ + + let(&str1, ""); + str1 = tokenToTex(g_MathToken[wffOrClassVar].tokenName, showStmt); + /* tokenToTex allocates str1; we must deallocate it eventually */ + countInfo++; + let(&htmlAllowedList, cat(htmlAllowedList, "   ", + str1, "(", NULL)); + first = 1; + for (j = 0; j < setVars; j++) { + if (setVarDVFlag[j] == 'N') { + let(&str1, ""); + str1 = tokenToTex(g_MathToken[setVar[j]].tokenName, showStmt); + let(&htmlAllowedList, cat(htmlAllowedList, + (first == 0) ? "," : "", str1, NULL)); + if (first == 0) countInfo++; + first = 0; + } + } + let(&htmlAllowedList, cat(htmlAllowedList, ")", NULL)); + + } /* next i (wff or class var) */ + + RETURN_POINT: + + if (htmlAllowedList[0] != 0) { + let(&htmlAllowedList, cat("
", + " 0) ? + "mmset.html" : + /* The following link will work in the NF and other + "Proof Explorers" */ + "../mpeuni/mmset.html", + + "#allowedsubst\">Allowed substitution hint", + ((countInfo != 1) ? "s" : ""), ": ", + (g_altHtmlFlag ? cat("", NULL) : ""), + htmlAllowedList, + (g_altHtmlFlag ? "" : ""), + "
", NULL)); + } + + /* Deallocate strings */ + nmbrLet(&setVar, NULL_NMBRSTRING); + let(&str1, ""); + let(&setVarDVFlag, ""); + + return htmlAllowedList; +} /* htmlAllowedSubst */ + + + +/* Displays a proof (or part of a proof, depending on arguments). */ +/* Note that parseProof() and verifyProof() are assumed to have been called, + so that the g_WrkProof structure elements are assigned for the current + statement. */ +/* This is also used for the MIDI output, since we conveniently + have the necessary proof information here. The function outputMidi() + is called from within. */ +void typeProof(long statemNum, + flag pipFlag, /* Means use g_ProofInProgress; statemNum must be proveStatement*/ + long startStep, long endStep, + long endIndent, + flag essentialFlag, /* <- also used as definition/axiom flag for HTML + syntax breakdown when called from typeStatement() */ + flag renumberFlag, + flag unknownFlag, + flag notUnifiedFlag, + flag reverseFlag, + flag noIndentFlag, /* Means Lemmon-style proof */ + long splitColumn, /* START_COLUMN */ + flag skipRepeatedSteps, /* NO_REPEATED_STEPS */ + flag texFlag, + flag htmlFlg + /* flag g_midiFlag - global to avoid changing many calls to typeProof() */ + ) +{ + /* From HELP SHOW PROOF: Optional qualifiers: + / ESSENTIAL - the proof tree is trimmed of all $f hypotheses before + being displayed. + / FROM_STEP - the display starts at the specified step. If + this qualifier is omitted, the display starts at the first step. + / TO_STEP - the display ends at the specified step. If this + qualifier is omitted, the display ends at the last step. + / TREE_DEPTH - Only steps at less than the specified proof + tree depth are displayed. Useful for obtaining an overview of + the proof. + / REVERSE - the steps are displayed in reverse order. + / RENUMBER - when used with / ESSENTIAL, the steps are renumbered + to correspond only to the essential steps. + / TEX - the proof is converted to LaTeX and stored in the file opened + with OPEN TEX. + / HTML - the proof is converted to HTML and stored in the file opened + with OPEN HTML. + / LEMMON - The proof is displayed in a non-indented format known + as Lemmon style, with explicit previous step number references. + If this qualifier is omitted, steps are indented in a tree format. + / START_COLUMN - Overrides the default column at which + the formula display starts in a Lemmon style display. May be + used only in conjuction with / LEMMON. + / NO_REPEATED_STEPS - When a proof step is identical to an earlier + step, it will not be repeated. Instead, a reference to it will be + changed to a reference to the earlier step. In particular, + SHOW PROOF
", + "Colors of variables: ", + g_htmlVarColor, "
This ", str3, + " is referenced by:", NULL)); + + if (str1[0] == 'Y') { /* Used by at least one */ + let(&str5, ""); /* Buffer for very long strings */ + /* Scan all future statements in str1 Y/N list */ + for (m = showStmt + 1; m <= g_statements; m++) { + /* Scan the used-by map */ + if (str1[m] != 'Y') continue; + /* Get the label */ + let(&str3, g_Statement[m].labelName); + /* It should be a $p */ + if (g_Statement[m].type != p_) bug(241); + /* Get the pink number */ + let(&str4, ""); + str4 = pinkHTML(m); + /* Assemble the href */ + let(&str2, cat(str2, "  ", + /*str3, "", str4, NULL));*/ + str3, "\n", str4, NULL)); + /* 8-Aug-2008 nm If line is very long, print it out and reset + it to speed up program (SHOW STATEMENT syl/HTML is very slow) */ + /* 8-Aug-2008 nm This doesn't solve problem, because the bottleneck + is printing g_printStringForReferencedBy below. This whole + code section needs to be redesigned to solve the speed problem. */ + /* 19-Sep-2012 nm Try again to fix SHOW STATEMENT syl/HTML speed + without a major rewrite. Unfortunately, made little difference. */ + /* 18-Jul-2015: Part of slowdown was due to the old + traceUsage algorithm that built a huge string of labels. Improved + from 313 sec to 280 sec for 'sh st syl/a'; still a problem. */ + /* Accumulate large cat buffer when small cats exceed certain size */ + if (strlen(str2) > 5000) { + let(&str5, cat(str5, str2, NULL)); + let(&str2, ""); + } + } /* next m (statement number) */ + + + } else { + /* There is no usage of this statement; print "(None)" */ + let(&str5, ""); + let(&str2, cat(str2, " (None)", NULL)); + + } /* if (str1[0] == 'Y') */ + /* Include buffer in output string */ + let(&str2, cat(str5, str2, "
\n"); + } else { + + /* For bobby.cast.org approval */ + print2("
\n"); + print2("", NULL), "", "\""); + } + } else { + /* This is a syntax breakdown "proof" of a definition called + from typeStatement */ + print2("
Proof of Theorem ", + asciiToTt(g_Statement[statemNum].labelName), + "
\n"); + print2("", NULL), "", "\""); + } + print2( + "\n"); + g_outputToString = 0; + } + + if (!pipFlag) { + parseProof(g_showStatement); + if (g_WrkProof.errorSeverity > 1) { + if (htmlFlg && texFlag) { + /* Print warning and close out proof table */ + g_outputToString = 1; + print2( + "\n"); + g_outputToString = 0; + /* Clear out g_printStringForReferencedBy to prevent bug 243 above */ + let(&g_printStringForReferencedBy, ""); + } + return; /* verifyProof() could crash */ + } + verifyProof(g_showStatement); + } + + if (!pipFlag) { + nmbrLet(&proof, g_WrkProof.proofString); /* The proof */ + if (g_midiFlag) { + /* Get the uncompressed version of the proof */ + nmbrLet(&proof, nmbrUnsquishProof(proof)); + } + } else { + nmbrLet(&proof, g_ProofInProgress.proof); /* The proof */ + } + plen = nmbrLen(proof); + + /* To reduce the number of steps displayed in an html proof, + we will use a local label to reference the 2nd or later reference to a + hypothesis, so the hypothesis won't have to be shown multiple times + in the proof. */ + if (htmlFlg && texFlag && !noIndentFlag /* Lemmon */) { + /* Only Lemmon-style proofs are implemented for html */ + bug(218); + } + if (skipRepeatedSteps) { + for (step = 0; step < plen; step++) { + stmt = proof[step]; + if (stmt < 0) continue; /* Unknown or label ref */ + type = g_Statement[stmt].type; + if (type == f_ || type == e_ /* It's a hypothesis */ + || g_Statement[stmt].numReqHyp == 0) { /* A statement w/ no hyp */ + for (i = 0; i < step; i++) { + if (stmt == proof[i]) { + /* The hypothesis at 'step' matches an earlier hypothesis at i, + so we will backreference 'step' to i with a local label */ + proof[step] = -1000 - i; + break; + } + } /* next i */ + } + } /* next step */ + } + + + /* Collect local labels */ + for (step = 0; step < plen; step++) { + stmt = proof[step]; + if (stmt <= -1000) { + stmt = -1000 - stmt; + if (!nmbrElementIn(1, localLabels, stmt)) { + nmbrLet(&localLabels, nmbrAddElement(localLabels, stmt)); + } + } + } + + /* localLabelNames[] hold an integer which, when converted to string, + is the local label name. */ + nmbrLet(&localLabelNames, nmbrSpace(plen)); + + /* Get the indentation level */ + nmbrLet(&indentationLevel, nmbrGetIndentation(proof, 0)); + + /* Get the target hypotheses */ + nmbrLet(&targetHyps, nmbrGetTargetHyp(proof, statemNum)); + + /* Get the essential step flags, if required */ + if (essentialFlag || g_midiFlag) { + nmbrLet(&essentialFlags, nmbrGetEssential(proof)); + } else { + nmbrLet(&essentialFlags, NULL_NMBRSTRING); + } + + /* We now have enough information for the MIDI output, so do it */ + if (g_midiFlag) { + outputMidi(plen, indentationLevel, + essentialFlags, g_midiParam, g_Statement[statemNum].labelName); + goto typeProof_return; + } + + /* Get the step renumbering */ + nmbrLet(&stepRenumber, nmbrSpace(plen)); /* This initializes all step + renumbering to step 0. Later, we will use (for html) the fact that + a step renumbered to 0 is a step to be skipped. */ + i = 0; + maxStepNum = 0; + for (step = 0; step < plen; step++) { + stepPrintFlag = 1; /* Note: stepPrintFlag is reused below with a + slightly different meaning (i.e. it will be printed after + a filter such as notUnified is applied) */ + if (renumberFlag && essentialFlag) { + if (!essentialFlags[step]) stepPrintFlag = 0; + } + if (skipRepeatedSteps && proof[step] < 0) stepPrintFlag = 0; + /* For standard numbering, stepPrintFlag will be always be 1 here */ + if (stepPrintFlag) { + i++; + stepRenumber[step] = i; /* Numbering for step to be printed */ + maxStepNum = i; /* To compute maxStepNumLen below */ + } + } + + /* Get the relative offset (0, -1, -2,...) for unknown steps */ + if (unknownFlag) { + /* There could be unknown steps outside of MM-PA + So remove this bugcheck, which seems spurious. I can't see that + getRelStepNums() cares whether we are in MM-PA. */ + /* if (!pipFlag) bug(255); */ + relativeStepNums = getRelStepNums(g_ProofInProgress.proof); + } + + /* Get steps not unified (pipFlag only) */ + if (notUnifiedFlag) { + if (!pipFlag) bug(205); + nmbrLet(¬UnifiedFlags, nmbrSpace(plen)); + for (step = 0; step < plen; step++) { + notUnifiedFlags[step] = 0; + if (nmbrLen(g_ProofInProgress.source[step])) { + if (!nmbrEq(g_ProofInProgress.target[step], + g_ProofInProgress.source[step])) notUnifiedFlags[step] = 1; + } + if (nmbrLen(g_ProofInProgress.user[step])) { + if (!nmbrEq(g_ProofInProgress.target[step], + g_ProofInProgress.user[step])) notUnifiedFlags[step] = 1; + } + } + } + + /* Get the printed character length of the largest step number */ + i = maxStepNum; + while (i >= 10) { + i = i/10; /* The number is printed in base 10 */ + maxStepNumLen++; + } + /* Add extra space for negative offset numbers e.g. "3:-1" */ + if (unknownFlag) { + maxStepNumOffsetLen = 3; /* :, -, # */ + j = 0; + for (i = 0; i < plen; i++) { + j = relativeStepNums[i]; + if (j <= 0) break; /* Found first unknown step (largest offset) */ + } + while (j <= -10) { + j = j/10; /* The number is printed in base 10 */ + maxStepNumOffsetLen++; + } + } + + + + /* Get local labels and maximum label length */ + /* lent = target length, lens = source length */ + for (step = 0; step < plen; step++) { + lent = (long)strlen(g_Statement[targetHyps[step]].labelName); + stmt = proof[step]; + if (stmt < 0) { + if (stmt <= -1000) { + stmt = -1000 - stmt; + /* stmt is now the step number a local label refers to */ + lens = (long)strlen(str((double)(localLabelNames[stmt]))); + let(&tmpStr1, ""); /* Clear temp alloc stack for str function */ + } else { + if (stmt != -(long)'?') bug (219); /* the only other possibility */ + lens = 1; /* '?' (unknown step) */ + } + } else { + if (nmbrElementIn(1, localLabels, step)) { + + /* The philosophy is to number all local labels with the + actual step number referenced, for better readability. This means + that if a *.mm label is a pure number, there may be ambiguity in + the proof display, but this is felt to be too rare to be a serious + drawback. */ + localLabelNames[step] = stepRenumber[step]; + + } + lens = (long)strlen(g_Statement[stmt].labelName); + } + /* Find longest label assignment, excluding local label declaration */ + if (maxLabelLen < lent + 1 + lens) { + maxLabelLen = lent + 1 + lens; /* Target, =, source */ + } + } /* Next step */ + + /* Print the steps */ + if (reverseFlag && !g_midiFlag) { + fromStep = plen - 1; + toStep = -1; + byStep = -1; + } else { + fromStep = 0; + toStep = plen; + byStep = 1; + } + for (step = fromStep; step != toStep; step = step + byStep) { + + /* Filters to decide whether to print the step */ + stepPrintFlag = 1; + if (startStep > 0) { /* The user's FROM_STEP */ + if (step + 1 < startStep) stepPrintFlag = 0; + } + if (endStep > 0) { /* The user's TO_STEP */ + if (step + 1 > endStep) stepPrintFlag = 0; + } + if (endIndent > 0) { /* The user's INDENTATION_DEPTH */ + if (indentationLevel[step] + 1 > endIndent) stepPrintFlag = 0; + } + if (essentialFlag) { + if (!essentialFlags[step]) stepPrintFlag = 0; + } + if (notUnifiedFlag) { + if (!notUnifiedFlags[step]) stepPrintFlag = 0; + } + if (unknownFlag) { + if (proof[step] != -(long)'?') stepPrintFlag = 0; + } + + /* Skip steps that are local label references for html */ + if (skipRepeatedSteps) { + if (stepRenumber[step] == 0) stepPrintFlag = 0; + } + + /* For MIDI files, ignore all qualifiers and process all steps */ + if (g_midiFlag) stepPrintFlag = 1; + + if (!stepPrintFlag) continue; + + if (noIndentFlag) { + let(&tgtLabel, ""); + } else { + let(&tgtLabel, g_Statement[targetHyps[step]].labelName); + } + let(&locLabDecl, ""); /* Local label declaration */ + stmt = proof[step]; + if (stmt < 0) { + if (stmt <= -1000) { + stmt = -1000 - stmt; + if (skipRepeatedSteps) bug(220); /* If html, a step referencing a + local label will never be printed since it will be skipped above */ + /* stmt is now the step number a local label refers to */ + if (noIndentFlag) { + let(&srcLabel, cat("@", str((double)(localLabelNames[stmt])), NULL)); + } else { + let(&srcLabel, cat("=", str((double)(localLabelNames[stmt])), NULL)); + } + type = g_Statement[proof[stmt]].type; + } else { + if (stmt != -(long)'?') bug(206); + if (noIndentFlag) { + let(&srcLabel, chr(-stmt)); /* '?' */ + } else { + let(&srcLabel, cat("=", chr(-stmt), NULL)); /* '?' */ + } + type = '?'; + } + } else { + if (nmbrElementIn(1, localLabels, step)) { + /* This statement declares a local label */ + if (noIndentFlag) { + if (!(skipRepeatedSteps)) { /* No local label declaration is + shown for html */ + let(&locLabDecl, cat("@", str((double)(localLabelNames[step])), ":", NULL)); + } + } else { + let(&locLabDecl, cat(str((double)(localLabelNames[step])), ":", NULL)); + } + } + + if (noIndentFlag) { + let(&srcLabel, g_Statement[stmt].labelName); + + /* For non-indented mode, add step numbers of hypotheses after label */ + let(&hypStr, ""); + hypStep = step - 1; + hypPtr = g_Statement[stmt].reqHypList; + for (hyp = g_Statement[stmt].numReqHyp - 1; hyp >=0; hyp--) { + if (!essentialFlag || g_Statement[hypPtr[hyp]].type == (char)e_) { + i = stepRenumber[hypStep]; + if (i == 0) { + if (!(skipRepeatedSteps)) bug(221); + if (proof[hypStep] != -(long)'?') { + if (proof[hypStep] > -1000) bug(222); + if (localLabelNames[-1000 - proof[hypStep]] == 0) bug(223); + if (localLabelNames[-1000 - proof[hypStep]] != + stepRenumber[-1000 - proof[hypStep]]) bug(224); + /* Get the step number the hypothesis refers to */ + i = stepRenumber[-1000 - proof[hypStep]]; + } else { + /* The hypothesis refers to an unknown step - use i as flag */ + i = -(long)'?'; + } + } + if (!hypStr[0]) { + if (i != -(long)'?') { + let(&hypStr, str((double)i)); + } else { + let(&hypStr, "?"); + } + } else { + /* Put comma between more than one hypothesis reference */ + if (i != -(long)'?') { + let(&hypStr, cat(str((double)i), ",", hypStr, NULL)); + } else { + let(&hypStr, cat("?", ",", hypStr, NULL)); + } + } + } + if (hyp < g_Statement[stmt].numReqHyp) { + /* Move down to previous hypothesis */ + hypStep = hypStep - subproofLen(proof, hypStep); + } + } /* Next hyp */ + + if (hypStr[0]) { + /* Add hypothesis list after label */ + let(&srcLabel, cat(hypStr, " ", srcLabel, NULL)); + } + + } else { + let(&srcLabel, cat("=", g_Statement[stmt].labelName, NULL)); + } + type = g_Statement[stmt].type; + } + + +#define PF_INDENT_INC 2 + /* Print the proof line */ + if (stepPrintFlag) { + + if (noIndentFlag) { + let(&startPrefix, cat( + space(maxStepNumLen - (long)strlen(str((double)(stepRenumber[step])))), + str((double)(stepRenumber[step])), + " ", + srcLabel, + space(splitColumn - (long)strlen(srcLabel) - (long)strlen(locLabDecl) - 1 + - maxStepNumLen - 1), + " ", locLabDecl, + NULL)); + if (pipFlag) { + let(&tgtPrefix, startPrefix); + let(&srcPrefix, cat( + space(maxStepNumLen - (long)strlen(str((double)(stepRenumber[step])))), + space((long)strlen(str((double)(stepRenumber[step])))), + " ", + space(splitColumn - 1 + - maxStepNumLen), + NULL)); + let(&userPrefix, cat( + space(maxStepNumLen - (long)strlen(str((double)(stepRenumber[step])))), + space((long)strlen(str((double)(stepRenumber[step])))), + " ", + "(User)", + space(splitColumn - (long)strlen("(User)") - 1 + - maxStepNumLen), + NULL)); + } + let(&contPrefix, space((long)strlen(startPrefix) + 4)); + } else { /* not noIndentFlag */ + + /* Compute prefix with and without step number. For 'show new_proof + /unknown', unknownFlag is set, and we add the negative offset. */ + let(&tmpStr, ""); + if (unknownFlag) { + if (relativeStepNums[step] < 0) { + let(&tmpStr, cat(" ", str((double)(relativeStepNums[step])), NULL)); + } + let(&tmpStr, cat(tmpStr, space(maxStepNumOffsetLen + - (long)(strlen(tmpStr))), NULL)); + } + + let(&startStringWithNum, cat( + space(maxStepNumLen - (long)strlen(str((double)(stepRenumber[step])))), + str((double)(stepRenumber[step])), + tmpStr, + " ", NULL)); + let(&startStringWithoutNum, space(maxStepNumLen + 1)); + + + let(&startPrefix, cat( + startStringWithNum, + space(indentationLevel[step] * PF_INDENT_INC + - (long)strlen(locLabDecl)), + locLabDecl, + tgtLabel, + srcLabel, + space(maxLabelLen - (long)strlen(tgtLabel) + - (long)strlen(srcLabel)), + NULL)); + if (pipFlag) { + let(&tgtPrefix, cat( + startStringWithNum, + space(indentationLevel[step] * PF_INDENT_INC - (long)strlen(locLabDecl)), + locLabDecl, + tgtLabel, + space((long)strlen(srcLabel)), + space(maxLabelLen - (long)strlen(tgtLabel) - (long)strlen(srcLabel)), + NULL)); + let(&srcPrefix, cat( + startStringWithoutNum, + space(indentationLevel[step] * PF_INDENT_INC - (long)strlen(locLabDecl)), + space((long)strlen(locLabDecl)), + space((long)strlen(tgtLabel)), + srcLabel, + space(maxLabelLen - (long)strlen(tgtLabel) - (long)strlen(srcLabel)), + NULL)); + let(&userPrefix, cat( + startStringWithoutNum, + space(indentationLevel[step] * PF_INDENT_INC - (long)strlen(locLabDecl)), + space((long)strlen(locLabDecl)), + space((long)strlen(tgtLabel)), + "=(User)", + space(maxLabelLen - (long)strlen(tgtLabel) - (long)strlen("=(User)")), + NULL)); + } + let(&contPrefix, ""); /* Continuation lines use whole screen width */ + } + + if (!pipFlag) { + + if (!texFlag) { + if (!g_midiFlag) { + printLongLine(cat(startPrefix," $", chr(type), " ", + nmbrCvtMToVString(g_WrkProof.mathStringPtrs[step]), + NULL), + contPrefix, + chr(1)); + /* chr(1) is right-justify flag for printLongLine */ + } + } else { /* TeX or HTML */ + printTexLongMath(g_WrkProof.mathStringPtrs[step], + cat(startPrefix, " $", chr(type), " ", NULL), + contPrefix, stmt, indentationLevel[step]); + } + + } else { /* pipFlag */ + if (texFlag) { + /* It doesn't make sense to do this and it hasn't been tested anyway */ + print2("?Unsupported: HTML or LaTeX proof for NEW_PROOF.\n"); + bug(244); + } + + if (!nmbrEq(g_ProofInProgress.target[step], g_ProofInProgress.source[step]) + && nmbrLen(g_ProofInProgress.source[step])) { + + if (!texFlag) { + printLongLine(cat(tgtPrefix, " $", chr(type), " ", + nmbrCvtMToVString(g_ProofInProgress.target[step]), + NULL), + contPrefix, + chr(1)); /* chr(1) is right-justify flag for printLongLine */ + printLongLine(cat(srcPrefix," = ", + nmbrCvtMToVString(g_ProofInProgress.source[step]), + NULL), + contPrefix, + chr(1)); /* chr(1) is right-justify flag for printLongLine */ + } else { /* TeX or HTML */ + printTexLongMath(g_ProofInProgress.target[step], + cat(tgtPrefix, " $", chr(type), " ", NULL), + contPrefix, 0, 0); + printTexLongMath(g_ProofInProgress.source[step], + cat(srcPrefix, " = ", NULL), + contPrefix, 0, 0); + } + } else { + if (!texFlag) { + printLongLine(cat(startPrefix, " $", chr(type), " ", + nmbrCvtMToVString(g_ProofInProgress.target[step]), + NULL), + contPrefix, + chr(1)); /* chr(1) is right-justify flag for printLongLine */ + } else { /* TeX or HTML */ + printTexLongMath(g_ProofInProgress.target[step], + cat(startPrefix, " $", chr(type), " ", NULL), + contPrefix, 0, 0); + } + + } + if (nmbrLen(g_ProofInProgress.user[step])) { + + if (!texFlag) { + printLongLine(cat(userPrefix, " = ", + nmbrCvtMToVString(g_ProofInProgress.user[step]), + NULL), + contPrefix, + chr(1)); /* chr(1) is right-justify flag for printLongLine */ + } else { + printTexLongMath(g_ProofInProgress.user[step], + cat(userPrefix, " = ", NULL), + contPrefix, 0, 0); + } + + } + } + } + + + } /* Next step */ + + if (!pipFlag) { + cleanWrkProof(); /* Deallocate verifyProof storage */ + } + + if (htmlFlg && texFlag) { + g_outputToString = 1; + print2("
Detailed syntax breakdown of Axiom \n"); + print2("Detailed syntax breakdown of Definition ", + asciiToTt(g_Statement[statemNum].labelName), + "
StepHypRef\n"); + print2("Expression
WARNING: Proof has a severe error.\n"); + print2("
\n"); + + printLongLine(cat( + "
", + NULL), "", "\""); + + if (essentialFlag) { /* Means this is not a syntax breakdown of a + definition which is called from typeStatement() */ + + /* Create list of syntax statements used */ + let(&statementUsedFlags, string(g_statements + 1, 'N')); /* Init. to 'no' */ + for (step = 0; step < plen; step++) { + stmt = proof[step]; + /* Convention: collect all $a's that don't begin with "|-" */ + if (stmt > 0) { + if (g_Statement[stmt].type == a_) { + if (strcmp("|-", g_MathToken[ + (g_Statement[stmt].mathString)[0]].tokenName)) { + statementUsedFlags[stmt] = 'Y'; /* Flag to use it */ + } + } + } + } + + /******************************************************************/ + /* Start of syntax hints section - for a more complete syntax hints + list in the HTML pages, parse the wffs comprising the hypotheses + and the statement, and add their syntax to the hints list. */ + + /* Look up the token "wff" (hard-coded) if we haven't found it before */ + if (wffToken == -1) { /* First time */ + wffToken = -2; /* In case it's not found because the user's source + used a convention different for "wff" for wffs */ + for (i = 0; i < g_mathTokens; i++) { + if (!strcmp("wff", g_MathToken[i].tokenName)) { + wffToken = i; + break; + } + } + } + + if (wffToken >= 0) { + + /* Scan the statement being proved and its essential hypotheses, + and find a proof for each of them expressed as a wff */ + for (i = -1; i < g_Statement[statemNum].numReqHyp; i++) { + /* i = -1 is the statement itself; i >= 0 is hypotheses i */ + if (i == -1) { + /* If it's not a $p we shouldn't be here */ + if (g_Statement[statemNum].type != (char)p_) bug(245); + nmbrTmpPtr1 = NULL_NMBRSTRING; + nmbrLet(&nmbrTmpPtr1, g_Statement[statemNum].mathString); + } else { + /* Ignore $f */ + if (g_Statement[g_Statement[statemNum].reqHypList[i]].type + == (char)f_) continue; + /* Must therefore be a $e */ + if (g_Statement[g_Statement[statemNum].reqHypList[i]].type + != (char)e_) bug(234); + nmbrTmpPtr1 = NULL_NMBRSTRING; + nmbrLet(&nmbrTmpPtr1, + g_Statement[g_Statement[statemNum].reqHypList[i]].mathString); + } + if (strcmp("|-", g_MathToken[nmbrTmpPtr1[0]].tokenName)) { + /* Since non-standard logics may not have this, + just break out of this section gracefully */ + nmbrTmpPtr2 = NULL_NMBRSTRING; /* To be known after break */ + break; + } + /* Turn "|-" assertion into a "wff" assertion */ + nmbrTmpPtr1[0] = wffToken; + + /* Find proof of formula or simple theorem (no new vars in $e's) */ + /* maxEDepth is the maximum depth at which statements with $e + hypotheses are + considered. A value of 0 means none are considered. */ + nmbrTmpPtr2 = proveFloating(nmbrTmpPtr1 /*mString*/, + statemNum /*statemNum*/, 0 /*maxEDepth*/, + 0, /* step; 0 = step 1 */ /*For messages*/ + 0, /*not noDistinct*/ + 2, /* override discouraged-usage statements silently */ + 1 /* Always allow other mathboxes */ + ); + if (!nmbrLen(nmbrTmpPtr2)) { + /* Didn't find syntax proof */ + /* Since a proof may not be found for non-standard + logics, just break out of this section gracefully */ + break; + } + + /* Add to list of syntax statements used */ + for (step = 0; step < nmbrLen(nmbrTmpPtr2); step++) { + stmt = nmbrTmpPtr2[step]; + /* Convention: collect all $a's that don't begin with "|-" */ + if (stmt > 0) { + if (statementUsedFlags[stmt] == 'N') { /* For slight speedup */ + if (g_Statement[stmt].type == a_) { + if (strcmp("|-", g_MathToken[ + (g_Statement[stmt].mathString)[0]].tokenName)) { + statementUsedFlags[stmt] = 'Y'; /* Flag to use it */ + } else { + /* In a syntax proof there should be no |- */ + /* (In the future, we may want to break instead of + calling it a bug, if it's a problem for non-standard + logics.) */ + bug(237); + } + } + } + } else { + /* proveFloating never returns a compressed proof */ + bug(238); + } + } + + /* Deallocate memory */ + nmbrLet(&nmbrTmpPtr2, NULL_NMBRSTRING); + nmbrLet(&nmbrTmpPtr1, NULL_NMBRSTRING); + } /* next i */ + /* Deallocate memory in case we broke out above */ + nmbrLet(&nmbrTmpPtr2, NULL_NMBRSTRING); + nmbrLet(&nmbrTmpPtr1, NULL_NMBRSTRING); + } /* if (wffToken >= 0) */ + /* End of syntax hints section */ + /******************************************************************/ + + let(&tmpStr, ""); + for (stmt = 1; stmt <= g_statements; stmt++) { + if (statementUsedFlags[stmt] == 'Y') { + if (!tmpStr[0]) { + let(&tmpStr, + "", NULL)); + printLongLine(tmpStr, "", "\""); + } + /* End of syntax hints list */ + + + /* Get list of axioms and definitions assumed by proof */ + let(&statementUsedFlags, ""); + traceProofWork(statemNum, + 1, /*essentialFlag*/ + "", /*traceToList*/ + &statementUsedFlags, + &unprovedList); + if ((signed)(strlen(statementUsedFlags)) != g_statements + 1) bug(227); + + /* First get axioms */ + let(&tmpStr, ""); + for (stmt = 1; stmt <= g_statements; stmt++) { + if (statementUsedFlags[stmt] == 'Y' && g_Statement[stmt].type == a_) { + let(&tmpStr1, left(g_Statement[stmt].labelName, 3)); + if (!strcmp(tmpStr1, "ax-")) { + if (!tmpStr[0]) { + let(&tmpStr, "", NULL)); + printLongLine(tmpStr, "", "\""); + } + + /* Then get definitions */ + let(&tmpStr, ""); + for (stmt = 1; stmt <= g_statements; stmt++) { + if (statementUsedFlags[stmt] == 'Y' && g_Statement[stmt].type == a_) { + let(&tmpStr1, left(g_Statement[stmt].labelName, 3)); + if (!strcmp(tmpStr1, "df-")) { + if (!tmpStr[0]) { + let(&tmpStr, + "", NULL)); + printLongLine(tmpStr, "", "\""); + } + + /* Print any unproved statements */ + if (nmbrLen(unprovedList)) { + if (nmbrLen(unprovedList) == 1 && + !strcmp(g_Statement[unprovedList[0]].labelName, + g_Statement[statemNum].labelName)) { + /* When the unproved list consists only of the statement that + was traced, it means the statement traced has no + proof (or it has a proof, but is incomplete and all earlier + ones do have complete proofs). */ + printLongLine(cat( +"", + NULL), "", "\""); + + } else { + printLongLine(cat( +"", NULL), "", "\""); + } + } + + /* End of axiom list */ + + /* Put referenced by list last */ + if (g_printStringForReferencedBy[0]) { + if (g_outputToString != 1) bug(257); + printLongLine(g_printStringForReferencedBy, "", "\""); + let(&g_printStringForReferencedBy, ""); + } else { + /* Since we always print ref-by list even if "(None)", + g_printStringForReferencedBy should never be empty */ + bug(263); + } + + } /* if essentialFlag */ + + + /* Printing of the trailer in mmwtex.c will close out string later */ + g_outputToString = 0; + } + + typeProof_return: + let(&tmpStr, ""); + let(&tmpStr1, ""); + let(&statementUsedFlags, ""); + let(&locLabDecl, ""); + let(&tgtLabel, ""); + let(&srcLabel, ""); + let(&startPrefix, ""); + let(&tgtPrefix, ""); + let(&srcPrefix, ""); + let(&userPrefix, ""); + let(&contPrefix, ""); + let(&hypStr, ""); + let(&startStringWithNum, ""); + let(&startStringWithoutNum, ""); + nmbrLet(&unprovedList, NULL_NMBRSTRING); + nmbrLet(&localLabels, NULL_NMBRSTRING); + nmbrLet(&localLabelNames, NULL_NMBRSTRING); + nmbrLet(&proof, NULL_NMBRSTRING); + nmbrLet(&targetHyps, NULL_NMBRSTRING); + nmbrLet(&indentationLevel, NULL_NMBRSTRING); + nmbrLet(&essentialFlags, NULL_NMBRSTRING); + nmbrLet(&stepRenumber, NULL_NMBRSTRING); + nmbrLet(¬UnifiedFlags, NULL_NMBRSTRING); + nmbrLet(&relativeStepNums, NULL_NMBRSTRING); +} /* typeProof() */ + +/* Show details of one proof step */ +/* Note: detailStep is the actual step number (starting with 1), not + the actual step - 1. */ +void showDetailStep(long statemNum, long detailStep) { + + long i, j, plen, step, stmt, sourceStmt, targetStmt; + vstring tmpStr = ""; + vstring tmpStr1 = ""; + nmbrString *proof = NULL_NMBRSTRING; + nmbrString *localLabels = NULL_NMBRSTRING; + nmbrString *localLabelNames = NULL_NMBRSTRING; + nmbrString *targetHyps = NULL_NMBRSTRING; + long nextLocLabNum = 1; /* Next number to be used for a local label */ + void *voidPtr; /* bsearch result */ + char type; + + /* Error check */ + i = parseProof(statemNum); + if (i) { + printLongLine("?The proof is incomplete or has an error", "", " "); + return; + } + plen = nmbrLen(g_WrkProof.proofString); + if (plen < detailStep || detailStep < 1) { + printLongLine(cat("?The step number should be from 1 to ", + str((double)plen), NULL), "", " "); + return; + } + + /* Structure getStep is declared in mmveri.h. */ + getStep.stepNum = detailStep; /* Non-zero is flag for verifyProof */ + parseProof(statemNum); /* ???Do we need to do this again? */ + verifyProof(statemNum); + + + nmbrLet(&proof, g_WrkProof.proofString); /* The proof */ + plen = nmbrLen(proof); + + /* Collect local labels */ + for (step = 0; step < plen; step++) { + stmt = proof[step]; + if (stmt <= -1000) { + stmt = -1000 - stmt; + if (!nmbrElementIn(1, localLabels, stmt)) { + nmbrLet(&localLabels, nmbrAddElement(localLabels, stmt)); + } + } + } + + /* localLabelNames[] hold an integer which, when converted to string, + is the local label name. */ + nmbrLet(&localLabelNames, nmbrSpace(plen)); + + /* Get the target hypotheses */ + nmbrLet(&targetHyps, nmbrGetTargetHyp(proof, statemNum)); + + /* Get local labels */ + for (step = 0; step < plen; step++) { + stmt = proof[step]; + if (stmt >= 0) { + if (nmbrElementIn(1, localLabels, step)) { + /* This statement declares a local label */ + /* First, get a name for the local label, using the next integer that + does not match any integer used for a statement label. */ + let(&tmpStr1, str((double)nextLocLabNum)); + while (1) { + voidPtr = (void *)bsearch(tmpStr, + g_allLabelKeyBase, (size_t)g_numAllLabelKeys, + sizeof(long), labelSrchCmp); + if (!voidPtr) break; /* It does not conflict */ + nextLocLabNum++; /* Try the next one */ + let(&tmpStr1, str((double)nextLocLabNum)); + } + localLabelNames[step] = nextLocLabNum; + nextLocLabNum++; /* Prepare for next local label */ + } + } + } /* Next step */ + + /* Print the step */ + let(&tmpStr, g_Statement[targetHyps[detailStep - 1]].labelName); + let(&tmpStr1, ""); /* Local label declaration */ + stmt = proof[detailStep - 1]; + if (stmt < 0) { + if (stmt <= -1000) { + stmt = -1000 - stmt; + /* stmt is now the step number a local label refers to */ + let(&tmpStr, cat(tmpStr,"=", str((double)(localLabelNames[stmt])), NULL)); + type = g_Statement[proof[stmt]].type; + } else { + if (stmt != -(long)'?') bug(207); + let(&tmpStr, cat(tmpStr,"=",chr(-stmt), NULL)); /* '?' */ + type = '?'; + } + } else { + if (nmbrElementIn(1, localLabels, detailStep - 1)) { + /* This statement declares a local label */ + let(&tmpStr1, cat(str((double)(localLabelNames[detailStep - 1])), ":", + NULL)); + } + let(&tmpStr, cat(tmpStr, "=", g_Statement[stmt].labelName, NULL)); + type = g_Statement[stmt].type; + } + + /* Print the proof line */ + printLongLine(cat("Proof step ", + str((double)detailStep), + ": ", + tmpStr1, + tmpStr, + " $", + chr(type), + " ", + nmbrCvtMToVString(g_WrkProof.mathStringPtrs[detailStep - 1]), + NULL), + " ", + " "); + + /* Print details about the step */ + let(&tmpStr, cat("This step assigns ", NULL)); + let(&tmpStr1, ""); + stmt = proof[detailStep - 1]; + sourceStmt = stmt; + if (stmt < 0) { + if (stmt <= -1000) { + stmt = -1000 - stmt; + /* stmt is now the step number a local label refers to */ + let(&tmpStr, cat(tmpStr, "step ", str((double)stmt), + " (via local label reference \"", + str((double)(localLabelNames[stmt])), "\") to ", NULL)); + } else { + if (stmt != -(long)'?') bug(208); + let(&tmpStr, cat(tmpStr, "an unknown statement to ", NULL)); + } + } else { + let(&tmpStr, cat(tmpStr, "source \"", g_Statement[stmt].labelName, + "\" ($", chr(g_Statement[stmt].type), ") to ", NULL)); + if (nmbrElementIn(1, localLabels, detailStep - 1)) { + /* This statement declares a local label */ + let(&tmpStr1, cat(" This step also declares the local label ", + str((double)(localLabelNames[detailStep - 1])), + ", which is used later on.", + NULL)); + } + } + targetStmt = targetHyps[detailStep - 1]; + if (detailStep == plen) { + let(&tmpStr, cat(tmpStr, "the final assertion being proved.", NULL)); + } else { + let(&tmpStr, cat(tmpStr, "target \"", g_Statement[targetStmt].labelName, + "\" ($", chr(g_Statement[targetStmt].type), ").", NULL)); + } + + let(&tmpStr, cat(tmpStr, tmpStr1, NULL)); + + if (sourceStmt >= 0) { + if (g_Statement[sourceStmt].type == a_ + || g_Statement[sourceStmt].type == p_) { + j = nmbrLen(g_Statement[sourceStmt].reqHypList); + if (j != nmbrLen(getStep.sourceHyps)) bug(209); + if (!j) { + let(&tmpStr, cat(tmpStr, + " The source assertion requires no hypotheses.", NULL)); + } else { + if (j == 1) { + let(&tmpStr, cat(tmpStr, + " The source assertion requires the hypothesis ", NULL)); + } else { + let(&tmpStr, cat(tmpStr, + " The source assertion requires the hypotheses ", NULL)); + } + for (i = 0; i < j; i++) { + let(&tmpStr, cat(tmpStr, "\"", + g_Statement[g_Statement[sourceStmt].reqHypList[i]].labelName, + "\" ($", + chr(g_Statement[g_Statement[sourceStmt].reqHypList[i]].type), + ", step ", str((double)(getStep.sourceHyps[i] + 1)), ")", NULL)); + if (i == 0 && j == 2) { + let(&tmpStr, cat(tmpStr, " and ", NULL)); + } + if (i < j - 2 && j > 2) { + let(&tmpStr, cat(tmpStr, ", ", NULL)); + } + if (i == j - 2 && j > 2) { + let(&tmpStr, cat(tmpStr, ", and ", NULL)); + } + } + let(&tmpStr, cat(tmpStr, ".", NULL)); + } + } + } + + if (detailStep < plen) { + let(&tmpStr, cat(tmpStr, + " The parent assertion of the target hypothesis is \"", + g_Statement[getStep.targetParentStmt].labelName, "\" ($", + chr(g_Statement[getStep.targetParentStmt].type),", step ", + str((double)(getStep.targetParentStep)), ").", NULL)); + } else { + let(&tmpStr, cat(tmpStr, + " The target has no parent because it is the assertion being proved.", + NULL)); + } + + printLongLine(tmpStr, "", " "); + + if (sourceStmt >= 0) { + if (g_Statement[sourceStmt].type == a_ + || g_Statement[sourceStmt].type == p_) { + print2("The source assertion before substitution was:\n"); + printLongLine(cat(" ", g_Statement[sourceStmt].labelName, " $", + chr(g_Statement[sourceStmt].type), " ", nmbrCvtMToVString( + g_Statement[sourceStmt].mathString), NULL), + " ", " "); + j = nmbrLen(getStep.sourceSubstsNmbr); + if (j == 1) { + printLongLine(cat( + "The following substitution was made to the source assertion:", + NULL),""," "); + } else { + printLongLine(cat( + "The following substitutions were made to the source assertion:", + NULL),""," "); + } + if (!j) { + print2(" (None)\n"); + } else { + print2(" Variable Substituted with\n"); + for (i = 0; i < j; i++) { + printLongLine(cat(" ", + g_MathToken[getStep.sourceSubstsNmbr[i]].tokenName," ", + space(9 - (long)strlen( + g_MathToken[getStep.sourceSubstsNmbr[i]].tokenName)), + nmbrCvtMToVString(getStep.sourceSubstsPntr[i]), NULL), + " ", " "); + } + } + } + } + + if (detailStep < plen) { + print2("The target hypothesis before substitution was:\n"); + printLongLine(cat(" ", g_Statement[targetStmt].labelName, " $", + chr(g_Statement[targetStmt].type), " ", nmbrCvtMToVString( + g_Statement[targetStmt].mathString), NULL), + " ", " "); + j = nmbrLen(getStep.targetSubstsNmbr); + if (j == 1) { + printLongLine(cat( + "The following substitution was made to the target hypothesis:", + NULL),""," "); + } else { + printLongLine(cat( + "The following substitutions were made to the target hypothesis:", + NULL),""," "); + } + if (!j) { + print2(" (None)\n"); + } else { + print2(" Variable Substituted with\n"); + for (i = 0; i < j; i++) { + printLongLine(cat(" ", + g_MathToken[getStep.targetSubstsNmbr[i]].tokenName, " ", + space(9 - (long)strlen( + g_MathToken[getStep.targetSubstsNmbr[i]].tokenName)), + nmbrCvtMToVString(getStep.targetSubstsPntr[i]), NULL), + " ", " "); + } + } + } + + cleanWrkProof(); + getStep.stepNum = 0; /* Zero is flag for verifyProof to ignore getStep info */ + + /* Deallocate getStep contents */ + j = pntrLen(getStep.sourceSubstsPntr); + for (i = 0; i < j; i++) { + nmbrLet((nmbrString **)(&getStep.sourceSubstsPntr[i]), + NULL_NMBRSTRING); + } + j = pntrLen(getStep.targetSubstsPntr); + for (i = 0; i < j; i++) { + nmbrLet((nmbrString **)(&getStep.targetSubstsPntr[i]), + NULL_NMBRSTRING); + } + nmbrLet(&getStep.sourceHyps, NULL_NMBRSTRING); + pntrLet(&getStep.sourceSubstsPntr, NULL_PNTRSTRING); + nmbrLet(&getStep.sourceSubstsNmbr, NULL_NMBRSTRING); + pntrLet(&getStep.targetSubstsPntr, NULL_PNTRSTRING); + nmbrLet(&getStep.targetSubstsNmbr, NULL_NMBRSTRING); + + /* Deallocate other strings */ + let(&tmpStr, ""); + let(&tmpStr1, ""); + nmbrLet(&localLabels, NULL_NMBRSTRING); + nmbrLet(&localLabelNames, NULL_NMBRSTRING); + nmbrLet(&proof, NULL_NMBRSTRING); + nmbrLet(&targetHyps, NULL_NMBRSTRING); + +} /* showDetailStep */ + +/* Summary of statements in proof for SHOW PROOF / STATEMENT_SUMMARY */ +void proofStmtSumm(long statemNum, flag essentialFlag, flag texFlag) { + + long i, j, k, pos, stmt, plen, slen, step; + char type; + vstring statementUsedFlags = ""; /* 'Y'/'N' flag that statement is used */ + vstring str1 = ""; + vstring str2 = ""; + vstring str3 = ""; + nmbrString *statementList = NULL_NMBRSTRING; + nmbrString *proof = NULL_NMBRSTRING; + nmbrString *essentialFlags = NULL_NMBRSTRING; + + /* This section is never called in HTML mode anymore. The code is + left in though just in case we somehow get here and the user continues + through the bug. */ + if (texFlag && g_htmlFlag) bug(239); + + if (!texFlag) { + print2("Summary of statements used in the proof of \"%s\":\n", + g_Statement[statemNum].labelName); + } else { + g_outputToString = 1; /* Flag for print2 to add to g_printString */ + if (!g_htmlFlag) { + print2("\n"); + print2("\\vspace{1ex} %%3\n"); + printLongLine(cat("Summary of statements used in the proof of ", + "{\\tt ", + asciiToTt(g_Statement[statemNum].labelName), + "}:", NULL), "", " "); + } else { + printLongLine(cat("Summary of statements used in the proof of ", + "", + asciiToTt(g_Statement[statemNum].labelName), + ":", NULL), "", "\""); + } + g_outputToString = 0; + fprintf(g_texFilePtr, "%s", g_printString); + let(&g_printString, ""); + } + + if (g_Statement[statemNum].type != p_) { + print2(" This is not a provable ($p) statement.\n"); + return; + } + + /* Don't use bad proofs (incomplete proofs are ok) */ + if (parseProof(statemNum) > 1) { + /* The proof has an error, so use the empty proof */ + nmbrLet(&proof, nmbrAddElement(NULL_NMBRSTRING, -(long)'?')); + } else { + nmbrLet(&proof, g_WrkProof.proofString); + } + + plen = nmbrLen(proof); + /* Get the essential step flags, if required */ + if (essentialFlag) { + nmbrLet(&essentialFlags, nmbrGetEssential(proof)); + } + + for (step = 0; step < plen; step++) { + if (essentialFlag) { + if (!essentialFlags[step]) continue; /* Ignore floating hypotheses */ + } + stmt = proof[step]; + if (stmt < 0) { + continue; /* Ignore '?' and local labels */ + } + if (1) { /* Limit list to $a and $p only */ + if (g_Statement[stmt].type != a_ && g_Statement[stmt].type != p_) { + continue; + } + } + /* Add this statement to the statement list if not already in it */ + if (!nmbrElementIn(1, statementList, stmt)) { + nmbrLet(&statementList, nmbrAddElement(statementList, stmt)); + } + } /* Next step */ + + /* Prepare the output */ + /* First, fill in the statementUsedFlags char array. This allows us to sort + the output by statement number without calling a sort routine. */ + slen = nmbrLen(statementList); + let(&statementUsedFlags, string(g_statements + 1, 'N')); /* Init. to 'no' */ + for (pos = 0; pos < slen; pos++) { + stmt = statementList[pos]; + if (stmt > statemNum || stmt < 1) bug(210); + statementUsedFlags[stmt] = 'Y'; + } + /* Next, build the output string */ + for (stmt = 1; stmt < statemNum; stmt++) { + if (statementUsedFlags[stmt] == 'Y') { + assignStmtFileAndLineNum(stmt); + let(&str1, cat(" is located on line ", + str((double)(g_Statement[stmt].lineNum)), + " of the file ", NULL)); + if (!texFlag) { + print2("\n"); + printLongLine(cat("Statement ", g_Statement[stmt].labelName, str1, + "\"", g_Statement[stmt].fileName, + "\".",NULL), "", " "); + } else { + g_outputToString = 1; /* Flag for print2 to add to g_printString */ + if (!g_htmlFlag) { + print2("\n"); + print2("\n"); + print2("\\vspace{1ex} %%4\n"); + printLongLine(cat("Statement {\\tt ", + asciiToTt(g_Statement[stmt].labelName), "} ", + str1, "{\\tt ", + asciiToTt(g_Statement[stmt].fileName), + "}.", NULL), "", " "); + print2("\n"); + } else { + printLongLine(cat("Statement ", + asciiToTt(g_Statement[stmt].labelName), " ", + str1, " ", + asciiToTt(g_Statement[stmt].fileName), + " ", NULL), "", "\""); + } + g_outputToString = 0; + fprintf(g_texFilePtr, "%s", g_printString); + let(&g_printString, ""); + } + + let(&str1, ""); + str1 = getDescription(stmt); + if (str1[0]) { + if (!texFlag) { + printLongLine(cat("\"", str1, "\"", NULL), "", " "); + } else { + printTexComment(str1, /* Sends result to g_texFilePtr */ + 1, /* 1 = htmlCenterFlag */ + PROCESS_EVERYTHING, /* actionBits */ + 1 /* 1 = fileCheck */); + } + } + + j = nmbrLen(g_Statement[stmt].reqHypList); + for (i = 0; i < j; i++) { + k = g_Statement[stmt].reqHypList[i]; + if (!essentialFlag || g_Statement[k].type != f_) { + let(&str2, cat(" ",g_Statement[k].labelName, + " $", chr(g_Statement[k].type), " ", NULL)); + if (!texFlag) { + printLongLine(cat(str2, + nmbrCvtMToVString(g_Statement[k].mathString), " $.", NULL), + " "," "); + } else { + let(&str3, space((long)strlen(str2))); + printTexLongMath(g_Statement[k].mathString, + str2, str3, 0, 0); + } + } + } + + let(&str1, ""); + type = g_Statement[stmt].type; + if (type == p_) let(&str1, " $= ..."); + let(&str2, cat(" ", g_Statement[stmt].labelName, + " $",chr(type), " ", NULL)); + if (!texFlag) { + printLongLine(cat(str2, + nmbrCvtMToVString(g_Statement[stmt].mathString), + str1, " $.", NULL), " ", " "); + } else { + let(&str3, space((long)strlen(str2))); + printTexLongMath(g_Statement[stmt].mathString, + str2, str3, 0, 0); + } + + } /* End if (statementUsedFlag[stmt] == 'Y') */ + } /* Next stmt */ + + let(&statementUsedFlags, ""); /* 'Y'/'N' flag that statement is used */ + let(&str1, ""); + let(&str2, ""); + let(&str3, ""); + nmbrLet(&statementList, NULL_NMBRSTRING); + nmbrLet(&proof, NULL_NMBRSTRING); + nmbrLet(&essentialFlags, NULL_NMBRSTRING); + +} /* proofStmtSumm */ + + +/* Traces back the statements used by a proof, recursively. */ +/* Returns 1 if at least one label is printed (or would be printed in + case testOnlyFlag=1); otherwise, returns 0 */ +/* matchList suppresses all output except labels matching matchList */ +/* testOnlyFlag prevents any printout; it is used to determine whether + there is an unwanted axiom for MINIMIZE_WITH /FORBID. */ +flag traceProof(long statemNum, + flag essentialFlag, + flag axiomFlag, + vstring matchList, + vstring traceToList, + flag testOnlyFlag) +{ + + long stmt, pos; + vstring statementUsedFlags = ""; /* y/n flags that statement is used */ + vstring outputString = ""; + nmbrString *unprovedList = NULL_NMBRSTRING; + flag foundFlag = 0; + + /* Make sure we're calling this with $p statements only */ + if (g_Statement[statemNum].type != (char)p_) bug(249); + + if (!testOnlyFlag) { + if (axiomFlag) { + print2( + "Statement \"%s\" assumes the following axioms ($a statements):\n", + g_Statement[statemNum].labelName); + } else if (traceToList[0] == 0) { + print2( + "The proof of statement \"%s\" uses the following earlier statements:\n", + g_Statement[statemNum].labelName); + } else { + print2( + "The proof of statement \"%s\" traces back to \"%s\" via:\n", + g_Statement[statemNum].labelName, traceToList); + } + } + + traceProofWork(statemNum, + essentialFlag, + traceToList, /* /TO argument of SHOW TRACE_BACK */ + &statementUsedFlags, + &unprovedList); + if ((signed)(strlen(statementUsedFlags)) != g_statements + 1) bug(226); + + /* Build the output string */ + let(&outputString, ""); + for (stmt = 1; stmt < statemNum; stmt++) { + if (statementUsedFlags[stmt] == 'Y') { + + if (matchList[0]) { /* There is a list to match */ + /* Don't include unmatched labels */ + if (!matchesList(g_Statement[stmt].labelName, matchList, '*', '?')) + continue; + } + + /* Skip rest of scan in testOnlyFlag mode */ + foundFlag = 1; /* At least one label would be printed */ + if (testOnlyFlag) { + goto TRACE_RETURN; + } + if (axiomFlag) { + if (g_Statement[stmt].type == a_) { + let(&outputString, cat(outputString, " ", g_Statement[stmt].labelName, + NULL)); + } + } else { + let(&outputString, cat(outputString, " ", g_Statement[stmt].labelName, + NULL)); + switch (g_Statement[stmt].type) { + case a_: let(&outputString, cat(outputString, "($a)", NULL)); break; + case e_: let(&outputString, cat(outputString, "($e)", NULL)); break; + case f_: let(&outputString, cat(outputString, "($f)", NULL)); break; + } + } + } /* End if (statementUsedFlag[stmt] == 'Y') */ + } /* Next stmt */ + + /* Skip printing in testOnlyFlag mode */ + if (testOnlyFlag) { + goto TRACE_RETURN; + } + + if (outputString[0]) { + let(&outputString, cat(" ", outputString, NULL)); + } else { + let(&outputString, " (None)"); + } + + /* Print the output */ + printLongLine(outputString, " ", " "); + + /* Print any unproved statements */ + if (nmbrLen(unprovedList)) { + print2("Warning: The following traced statement(s) were not proved:\n"); + let(&outputString, ""); + for (pos = 0; pos < nmbrLen(unprovedList); pos++) { + let(&outputString, cat(outputString, " ", g_Statement[unprovedList[ + pos]].labelName, NULL)); + } + let(&outputString, cat(" ", outputString, NULL)); + printLongLine(outputString, " ", " "); + } + + TRACE_RETURN: + /* Deallocate */ + let(&outputString, ""); + let(&statementUsedFlags, ""); + nmbrLet(&unprovedList, NULL_NMBRSTRING); + return foundFlag; +} /* traceProof */ + +/* Traces back the statements used by a proof, recursively. Returns + a nmbrString with a list of statements and unproved statements */ +void traceProofWork(long statemNum, + flag essentialFlag, + vstring traceToList, /* /TO argument of SHOW TRACE_BACK */ + vstring *statementUsedFlagsP, /* 'Y'/'N' flag that statement is used */ + nmbrString **unprovedListP) +{ + + long pos, stmt, plen, slen, step; + nmbrString *statementList = NULL_NMBRSTRING; + nmbrString *proof = NULL_NMBRSTRING; + nmbrString *essentialFlags = NULL_NMBRSTRING; + vstring traceToFilter = ""; + vstring str1 = ""; + long j; + + /* Preprocess the "SHOW TRACE_BACK ... / TO" traceToList list if any */ + if (traceToList[0] != 0) { + let(&traceToFilter, string(g_statements + 1, 'N')); /* Init. to 'no' */ + /* Wildcard match scan */ + for (stmt = 1; stmt <= g_statements; stmt++) { + if (g_Statement[stmt].type != (char)a_ + && g_Statement[stmt].type != (char)p_) + continue; /* Not a $a or $p statement; skip it */ + /* Wildcard matching */ + if (!matchesList(g_Statement[stmt].labelName, traceToList, '*', '?')) + continue; + let(&str1, ""); + str1 = traceUsage(stmt /*g_showStatement*/, + 1, /*recursiveFlag*/ + statemNum /* cutoffStmt */); + traceToFilter[stmt] = 'Y'; /* Include the statement we're showing + usage of */ + if (str1[0] == 'Y') { /* There is some usage */ + for (j = stmt + 1; j <= g_statements; j++) { + /* OR in the usage to the filter */ + if (str1[j] == 'Y') traceToFilter[j] = 'Y'; + } + } + } /* Next i (statement number) */ + } /* if (traceToList[0] != 0) */ + + nmbrLet(&statementList, nmbrSpace(g_statements)); + statementList[0] = statemNum; + slen = 1; + nmbrLet(&(*unprovedListP), NULL_NMBRSTRING); /* List of unproved statements */ + let(&(*statementUsedFlagsP), string(g_statements + 1, 'N')); /* Init. to 'no' */ + (*statementUsedFlagsP)[statemNum] = 'Y'; + for (pos = 0; pos < slen; pos++) { + if (g_Statement[statementList[pos]].type != p_) { + continue; /* Not a $p */ + } + + /* Don't use bad proofs (incomplete proofs are ok) */ + if (parseProof(statementList[pos]) > 1) { + /* The proof has an error, so use the empty proof */ + nmbrLet(&proof, nmbrAddElement(NULL_NMBRSTRING, -(long)'?')); + } else { + nmbrLet(&proof, g_WrkProof.proofString); + } + + plen = nmbrLen(proof); + /* Get the essential step flags, if required */ + if (essentialFlag) { + nmbrLet(&essentialFlags, nmbrGetEssential(proof)); + } + for (step = 0; step < plen; step++) { + if (essentialFlag) { + if (!essentialFlags[step]) continue; /* Ignore floating hypotheses */ + } + stmt = proof[step]; + if (stmt < 0) { + if (stmt > -1000) { + /* '?' */ + if (!nmbrElementIn(1, *unprovedListP, statementList[pos])) { + nmbrLet(&(*unprovedListP), nmbrAddElement(*unprovedListP, + statementList[pos])); /* Add to list of unproved statements */ + } + } + continue; /* Ignore '?' and local labels */ + } + if (1) { /* Limit list to $a and $p only */ + if (g_Statement[stmt].type != a_ && g_Statement[stmt].type != p_) { + continue; + } + } + /* Add this statement to the statement list if not already in it */ + if ((*statementUsedFlagsP)[stmt] == 'N') { + if (traceToList[0] == 0) { + statementList[slen] = stmt; + slen++; + (*statementUsedFlagsP)[stmt] = 'Y'; + } else { /* TRACE_BACK / TO */ + if (traceToFilter[stmt] == 'Y') { + statementList[slen] = stmt; + slen++; + (*statementUsedFlagsP)[stmt] = 'Y'; + } + } + } + } /* Next step */ + } /* Next pos */ + + /* Deallocate */ + nmbrLet(&essentialFlags, NULL_NMBRSTRING); + nmbrLet(&proof, NULL_NMBRSTRING); + nmbrLet(&statementList, NULL_NMBRSTRING); + let(&str1, ""); + let(&str1, ""); + return; + +} /* traceProofWork */ + +nmbrString *stmtFoundList = NULL_NMBRSTRING; +long indentShift = 0; + +/* Traces back the statements used by a proof, recursively, with tree display.*/ +void traceProofTree(long statemNum, + flag essentialFlag, long endIndent) +{ + if (g_Statement[statemNum].type != p_) { + print2("Statement %s is not a $p statement.\n", + g_Statement[statemNum].labelName); + return; + } + + printLongLine(cat("The proof tree traceback for statement \"", + g_Statement[statemNum].labelName, + "\" follows. The statements used by each proof are indented one level in,", + " below the statement being proved. Hypotheses are not included.", + NULL), + "", " "); + print2("\n"); + + nmbrLet(&stmtFoundList, NULL_NMBRSTRING); + indentShift = 0; + traceProofTreeRec(statemNum, essentialFlag, endIndent, 0); + nmbrLet(&stmtFoundList, NULL_NMBRSTRING); +} /* traceProofTree */ + + +void traceProofTreeRec(long statemNum, + flag essentialFlag, long endIndent, long recursDepth) +{ + long i, pos, stmt, plen, slen, step; + vstring outputStr = ""; + nmbrString *localFoundList = NULL_NMBRSTRING; + nmbrString *localPrintedList = NULL_NMBRSTRING; + flag unprovedFlag = 0; + nmbrString *proof = NULL_NMBRSTRING; + nmbrString *essentialFlags = NULL_NMBRSTRING; + + + let(&outputStr, ""); + outputStr = getDescription(statemNum); /* Get statement comment */ + let(&outputStr, edit(outputStr, 8 + 16 + 128)); /* Trim and reduce spaces */ + slen = len(outputStr); + for (i = 0; i < slen; i++) { + /* Change newlines to spaces in comment */ + if (outputStr[i] == '\n') { + outputStr[i] = ' '; + } + } + +#define INDENT_INCR 3 +#define MAX_LINE_LEN 79 + + if ((recursDepth * INDENT_INCR - indentShift) > + (g_screenWidth - MAX_LINE_LEN) + 50) { + indentShift = indentShift + 40 + (g_screenWidth - MAX_LINE_LEN); + print2("****** Shifting indentation. Total shift is now %ld.\n", + (long)indentShift); + } + if ((recursDepth * INDENT_INCR - indentShift) < 1 && indentShift != 0) { + indentShift = indentShift - 40 - (g_screenWidth - MAX_LINE_LEN); + print2("****** Shifting indentation. Total shift is now %ld.\n", + (long)indentShift); + } + + let(&outputStr, cat(space(recursDepth * INDENT_INCR - indentShift), + g_Statement[statemNum].labelName, " $", chr(g_Statement[statemNum].type), + " \"", edit(outputStr, 8 + 128), "\"", NULL)); + + if (len(outputStr) > MAX_LINE_LEN + (g_screenWidth - MAX_LINE_LEN)) { + let(&outputStr, cat(left(outputStr, + MAX_LINE_LEN + (g_screenWidth - MAX_LINE_LEN) - 3), "...", NULL)); + } + + if (g_Statement[statemNum].type == p_ || g_Statement[statemNum].type == a_) { + /* Only print assertions to reduce output bulk */ + print2("%s\n", outputStr); + } + + if (g_Statement[statemNum].type != p_) { + let(&outputStr, ""); + return; + } + + if (endIndent) { + /* An indentation level limit is set */ + if (endIndent < recursDepth + 2) { + let(&outputStr, ""); + return; + } + } + + /* Don't use bad proofs (incomplete proofs are ok) */ + if (parseProof(statemNum) > 1) { + /* The proof has an error, so use the empty proof */ + nmbrLet(&proof, nmbrAddElement(NULL_NMBRSTRING, -(long)'?')); + } else { + nmbrLet(&proof, g_WrkProof.proofString); + } + + plen = nmbrLen(proof); + /* Get the essential step flags, if required */ + if (essentialFlag) { + nmbrLet(&essentialFlags, nmbrGetEssential(proof)); + } + nmbrLet(&localFoundList, NULL_NMBRSTRING); + nmbrLet(&localPrintedList, NULL_NMBRSTRING); + for (step = 0; step < plen; step++) { + if (essentialFlag) { + if (!essentialFlags[step]) continue; + /* Ignore floating hypotheses */ + } + stmt = proof[step]; + if (stmt < 0) { + if (stmt > -1000) { + /* '?' */ + unprovedFlag = 1; + } + continue; /* Ignore '?' and local labels */ + } + if (!nmbrElementIn(1, localFoundList, stmt)) { + nmbrLet(&localFoundList, nmbrAddElement(localFoundList, stmt)); + } + if (!nmbrElementIn(1, stmtFoundList, stmt)) { + traceProofTreeRec(stmt, essentialFlag, endIndent, recursDepth + 1); + nmbrLet(&localPrintedList, nmbrAddElement(localPrintedList, stmt)); + nmbrLet(&stmtFoundList, nmbrAddElement(stmtFoundList, stmt)); + } + } /* Next step */ + + /* See if there are any old statements printed previously */ + slen = nmbrLen(localFoundList); + let(&outputStr, ""); + for (pos = 0; pos < slen; pos++) { + stmt = localFoundList[pos]; + if (!nmbrElementIn(1, localPrintedList, stmt)) { + /* Don't include $f, $e in output */ + if (g_Statement[stmt].type == p_ || g_Statement[stmt].type == a_) { + let(&outputStr, cat(outputStr, " ", + g_Statement[stmt].labelName, NULL)); + } + } + } + + if (len(outputStr)) { + printLongLine(cat(space(INDENT_INCR * (recursDepth + 1) - 1 - indentShift), + outputStr, " (shown above)", NULL), + space(INDENT_INCR * (recursDepth + 2) - indentShift), " "); + } + + if (unprovedFlag) { + printLongLine(cat(space(INDENT_INCR * (recursDepth + 1) - indentShift), + "*** Statement ", g_Statement[statemNum].labelName, " has not been proved." + , NULL), + space(INDENT_INCR * (recursDepth + 2)), " "); + } + + let(&outputStr, ""); + nmbrLet(&localFoundList, NULL_NMBRSTRING); + nmbrLet(&localPrintedList, NULL_NMBRSTRING); + nmbrLet(&proof, NULL_NMBRSTRING); + nmbrLet(&essentialFlags, NULL_NMBRSTRING); + +} /* traceProofTreeRec */ + + +/* Called by SHOW TRACE_BACK
", + "Colors of variables: ", + g_htmlVarColor, "
Syntax hints: "); + } + + /* Get the main symbol in the syntax */ + /* This section can be deleted if not wanted - it is custom + for set.mm and might not work with other .mm's */ + let(&tmpStr1, ""); + for (i = 1 /* Skip |- */; i < g_Statement[stmt].mathStringLen; i++) { + if (g_MathToken[(g_Statement[stmt].mathString)[i]].tokenType == + (char)con_) { + /* Skip parentheses, commas, etc. */ + if (strcmp(g_MathToken[(g_Statement[stmt].mathString)[i] + ].tokenName, "(") + && strcmp(g_MathToken[(g_Statement[stmt].mathString)[i] + ].tokenName, ",") + && strcmp(g_MathToken[(g_Statement[stmt].mathString)[i] + ].tokenName, ")") + && strcmp(g_MathToken[(g_Statement[stmt].mathString)[i] + ].tokenName, ":") + /* Use |-> rather than e. for cmpt, cmpt2 */ + && !(!strcmp(g_MathToken[(g_Statement[stmt].mathString)[i] + ].tokenName, "e.") + && (!strcmp(g_Statement[stmt].labelName, "cmpt") + || !strcmp(g_Statement[stmt].labelName, "cmpt2"))) + ) { + tmpStr1 = + tokenToTex(g_MathToken[(g_Statement[stmt].mathString)[i] + ].tokenName, stmt); + let(&tmpStr1, cat( + (g_altHtmlFlag ? cat("", NULL) : ""), + tmpStr1, + (g_altHtmlFlag ? "" : ""), + NULL)); + break; + } + } + } /* Next i */ + /* Special cases hard-coded for set.mm */ + if (!strcmp(g_Statement[stmt].labelName, "wbr")) /* binary relation */ + let(&tmpStr1, " class class class "); + if (!strcmp(g_Statement[stmt].labelName, "cv")) + let(&tmpStr1, "[set variable]"); + /* Let's don't do cv - confusing to reader */ + if (!strcmp(g_Statement[stmt].labelName, "cv")) + continue; + if (!strcmp(g_Statement[stmt].labelName, "co")) /* operation */ + let(&tmpStr1, "(class class class)"); + let(&tmpStr, cat(tmpStr, "  ", tmpStr1, NULL)); + /* End section - Get the main symbol in the syntax */ + + let(&tmpStr1, ""); + tmpStr1 = pinkHTML(stmt); + let(&tmpStr, cat(tmpStr, "", + g_Statement[stmt].labelName, "", tmpStr1, NULL)); + + + } + } + if (tmpStr[0]) { + let(&tmpStr, cat(tmpStr, + "
" + "This theorem was proved from axioms:"); + } + let(&tmpStr1, ""); + tmpStr1 = pinkHTML(stmt); + let(&tmpStr, cat(tmpStr, "  ", + g_Statement[stmt].labelName, "", tmpStr1, NULL)); + } + } + } /* next stmt */ + if (tmpStr[0]) { + let(&tmpStr, cat(tmpStr, "
This theorem depends on definitions:"); + } + let(&tmpStr1, ""); + tmpStr1 = pinkHTML(stmt); + let(&tmpStr, cat(tmpStr, "  ", + g_Statement[stmt].labelName, "", tmpStr1, NULL)); + } + } + } /* next stmt */ + if (tmpStr[0]) { + let(&tmpStr, cat(tmpStr, "
 ", +"WARNING: This theorem has an incomplete proof.
 ", +"WARNING: This proof depends on the following unproved theorem(s): ", + NULL), "", "\""); + let(&tmpStr, ""); + for (i = 0; i < nmbrLen(unprovedList); i++) { + let(&tmpStr, cat(tmpStr, " ", + g_Statement[unprovedList[i]].labelName, "", + NULL)); + } + printLongLine(cat(tmpStr, "
\n", - "%"); - print2(" \n"); - print2(" \n"); - print2( -" \n"); - - if (texHeaderFlag) { /* For HTML, 1 means to put prev/next links */ - /* Put Previous/Next links into web page */ - print2(" \n"); - print2(" \n"); - print2(" \n"); - print2(" \n"); - print2(" which caused HTML validation failure */ - print2(" \n"); - print2(" \n"); - print2("
\"%s\"\n",\n"); - print2(" \n", - GREEN_TITLE_COLOR); - /* Allow plenty of room for long titles (although over 79 chars. will - trigger bug 1505). */ - print2("%s\n", - (g_showStatement < g_extHtmlStmt ? htmlTitle : - (g_showStatement < g_mathboxStmt ? g_extHtmlTitle : - localSandboxTitle))); - print2(" \n", "%"); - print2(" \n"); - /* Find the previous statement with a web page */ - j = 0; - k = 0; - for (i = g_showStatement - 1; i >= 1; i--) { - if (g_Statement[i].type == (char)p_ || - g_Statement[i].type == (char)a_) { - j = i; - break; - } - } - if (j == 0) { - k = 1; /* First statement flag */ - /* For the first statement, wrap to last one */ - for (i = g_statements; i >= 1; i--) { - if (g_Statement[i].type == (char)p_ || - g_Statement[i].type == (char)a_ ) { - j = i; - break; - } - } - } - if (j == 0) bug(2314); - print2(" \n", - g_Statement[j].labelName); - if (!k) { - print2(" < Previous  \n"); - } else { - print2(" < Wrap  \n"); - } - /* Find the next statement with a web page */ - j = 0; - k = 0; - for (i = g_showStatement + 1; i <= g_statements; i++) { - if (g_Statement[i].type == (char)p_ || - g_Statement[i].type == (char)a_) { - j = i; - break; - } - } - if (j == 0) { - k = 1; /* Last statement flag */ - /* For the last statement, wrap to first one */ - for (i = 1; i <= g_statements; i++) { - if (g_Statement[i].type == (char)p_ || - g_Statement[i].type == (char)a_) { - j = i; - break; - } - } - } - if (j == 0) bug(2315); - if (!k) { - print2(" Next >\n", - g_Statement[j].labelName); - } else { - print2(" Wrap >\n", - g_Statement[j].labelName); - } - - print2(" \n"); - - /* 8-Sep-03 nm - ??? Is the closing printed if there is no - altHtml? This should be tested. */ - - /* Compute the theorem list page number. ??? Temporarily - we assume it to be 100 (hardcoded). Todo: This should be fixed to use - the same as the THEOREMS_PER_PAGE in WRITE THEOREMS (have a SET - global variable in place of THEOREMS_PER_PAGE?) */ - i = ((g_Statement[g_showStatement].pinkNumber - 1) / 100) + 1; /* Page # */ - /* All thm pages now have page num after mmtheorems - since mmtheorems.html is now just the table of contents */ - let(&tmpStr, cat("mmtheorems", str((double)i), ".html#", - g_Statement[g_showStatement].labelName, NULL)); /* Link to page/stmt */ - /* Break up lines w/ long labels to prevent bug 1505 */ - printLongLine(cat("
Nearby theorems", NULL), " ", " "); - - print2(" \n"); - print2("
\n"); - print2(" Mirrors  >\n"); - print2("  Home  >\n"); - print2("  %s  >\n", - (g_showStatement < g_extHtmlStmt ? g_htmlHomeHREF : - (g_showStatement < g_mathboxStmt ? extHtmlHomeHREF : - g_htmlHomeHREF)), - (g_showStatement < g_extHtmlStmt ? htmlTitleAbbr : - (g_showStatement < g_mathboxStmt ? g_extHtmlTitleAbbr : - htmlTitleAbbr))); - print2("  Th. List  >\n"); - if (g_showStatement >= g_mathboxStmt) { - print2("  \n"); - print2(" Mathboxes  >\n"); - } - print2("  %s\n", - /* Strip off ".html" */ - left(g_texFileName, (long)strlen(g_texFileName) - 5)); - print2(" \n"); - print2(" \n"); - print2(" \n"); - - /* Add link(s) specified by htmlexturl in $t statement */ - /* The position of the theorem name is indicated with "*" in the - htmlexturl $t variable. If a literal "*" is part of the URL, - use the alternate URL encoding "%2A" */ - /* Example: (take out space in "/ *" below that was put there to prevent - compiler warnings) - htmlexturl '' + - 'Structured version  ' + - '' + - 'ASCII version  '; - */ - let(&tmpStr, htmlExtUrl); - i = 1; - while (1) { - i = instr(i, tmpStr, "*"); - if (i == 0) break; - let(&tmpStr, cat(left(tmpStr, i - 1), - g_Statement[g_showStatement].labelName, - right(tmpStr, i + 1), NULL)); - } - printLongLine(tmpStr, "", " "); - - /* Print the GIF/Unicode Font choice, if directories are specified */ - if (htmlDir[0]) { - - if (g_altHtmlFlag) { - print2(" GIF version\n", - htmlDir, g_texFileName); - - } else { - print2(" Unicode version\n", - altHtmlDir, g_texFileName); - - } - } - - } else { /* texHeaderFlag=0 for HTML means not to put prev/next links */ - /* there is no table open (mmascii, mmdefinitions), so don't - add \n", "%"); - - /* Print the GIF/Unicode Font choice, if directories are specified */ - if (htmlDir[0]) { - print2("\n"); - if (g_altHtmlFlag) { - print2("This is the Unicode version.
\n"); - print2("Change to GIF version\n", - htmlDir, g_texFileName); - } else { - print2("This is the GIF version.
\n"); - print2("Change to Unicode version\n", - altHtmlDir, g_texFileName); - } - } - else { - print2(" \n"); - } - - } - - print2("
\n"); - print2("
\n"); - - - - print2("
\n"); - - } /* g_htmlFlag */ - fprintf(g_texFilePtr, "%s", g_printString); - g_outputToString = 0; - let(&g_printString, ""); - - /* Deallocate strings */ - let(&tmpStr, ""); - -} /* printTexHeader */ - -/* Prints an embedded comment in TeX or HTML. The commentPtr must point to the first - character after the "$(" in the comment. The printout ends when the first - "$)" or null character is encountered. commentPtr must not be a temporary - allocation. htmlCenterFlag, if 1, means to center the HTML and add a - "Description:" prefix. */ -/* The output is printed to the global g_texFilePtr. */ -/* Note: the global long "g_showStatement" is referenced to determine whether - to read bibliography from mmset.html or mmhilbert.html (or other - g_htmlBibliography or extHtmlBibliography file pair). */ -/* Returns 1 if an error or warning message was printed */ -flag printTexComment(vstring commentPtr, flag htmlCenterFlag, - long actionBits, /* see below */ - /* Indicators for actionBits: - #define ERRORS_ONLY 1 - just report errors, don't print output - #define PROCESS_SYMBOLS 2 - #define PROCESS_LABELS 4 - #define ADD_COLORED_LABEL_NUMBER 8 - #define PROCESS_BIBREFS 16 - #define PROCESS_UNDERSCORES 32 - #define CONVERT_TO_HTML 64 - convert '<' to '>' unless - , present - #define METAMATH_COMMENT 128 - $) terminates string - #define PROCESS_EVERYTHING PROCESS_SYMBOLS + PROCESS_LABELS \ - + ADD_COLORED_LABEL_NUMBER + PROCESS_BIBREFS \ - + PROCESS_UNDERSCORES + CONVERT_HTML + METAMATH_COMMENT \ - */ - /* 10-Dec-2018 nm - expanded meaning of errorsOnly for MARKUP commmand: - 2 = process as if in ... preformatted mode but - don't strip ... tags - 3 = same as 2, but convert ONLY math symbols - (These new values were added instead of adding a new argument, - so as not to have to modify ~60 other calls to this function) */ - - flag fileCheck) /* 1 = check for missing external files (gifs, bib, etc.) */ -{ - vstring cmtptr; /* Not allocated */ - vstring srcptr; /* Not allocated */ - vstring lineStart; /* Not allocated */ - vstring tmpStr = ""; - vstring modeSection; /* Not allocated */ - vstring sourceLine = ""; - vstring outputLine = ""; - vstring tmp = ""; - flag textMode, mode, lastLineFlag, displayMode; - vstring tmpComment = ""; - flag preformattedMode = 0; /* HTML preformatted mode */ - - /* For bibliography hyperlinks */ - vstring bibTag = ""; - vstring bibFileName = ""; - vstring bibFileContents = ""; - vstring bibFileContentsUpper = ""; /* Uppercase version */ - vstring bibTags = ""; - long pos1, pos2, htmlpos1, htmlpos2, saveScreenWidth; - flag tmpMathMode; - - /* Variables for converting ` ` and ~ to old $m,$n and $l,$n formats in - order to re-use the old code */ - /* Note that DOLLAR_SUBST will replace the old $. */ - vstring cmt = ""; - vstring cmtMasked = ""; /* cmt with math syms blanked */ /* also mask ~ label */ - vstring tmpMasked = ""; /* tmp with math syms blanked */ - vstring tmpStrMasked = ""; /* tmpStr w/ math syms blanked */ - long i, clen; - flag returnVal = 0; /* 1 means error/warning */ - - /* Internal flags derived from actionBits argument, for MARKUP command use */ - flag errorsOnly; - flag processSymbols; - flag processLabels; - flag addColoredLabelNumber; - flag processBibrefs; - flag processUnderscores; - flag convertToHtml; - flag metamathComment; - - /* Assign local Booleans for actionBits mask */ - errorsOnly = (actionBits & ERRORS_ONLY ) != 0; - processSymbols = (actionBits & PROCESS_SYMBOLS ) != 0; - processLabels = (actionBits & PROCESS_LABELS ) != 0; - addColoredLabelNumber = (actionBits & ADD_COLORED_LABEL_NUMBER ) != 0; - processBibrefs = (actionBits & PROCESS_BIBREFS ) != 0; - processUnderscores = (actionBits & PROCESS_UNDERSCORES ) != 0; - convertToHtml = (actionBits & CONVERT_TO_HTML ) != 0; - metamathComment = (actionBits & METAMATH_COMMENT ) != 0; - - /* We must let this procedure handle switching output to string mode */ - if (g_outputToString) bug(2309); - /* The LaTeX (or HTML) file must be open */ - if (errorsOnly == 0) { - if (!g_texFilePtr) bug(2321); - } - - cmtptr = commentPtr; - - if (!g_texDefsRead) { - return returnVal; /* TeX defs were not read (error was detected - and flagged to the user elsewhere) */ - } - - /* Convert line to the old $m..$n and $l..$n formats (using DOLLAR_SUBST - instead of "$") - the old syntax is obsolete but we do this conversion - to re-use some old code */ - if (metamathComment != 0) { - i = instr(1, cmtptr, "$)"); /* If it points to source buffer */ - if (!i) i = (long)strlen(cmtptr) + 1; /* If it's a stand-alone string */ - } else { - i = (long)strlen(cmtptr) + 1; - } - let(&cmt, left(cmtptr, i - 1)); - - /* All actions on cmt should be mirrored on cmdMasked, except that - math symbols are replaced with blanks in cmdMasked */ - let(&cmtMasked, cmt); - - - /* This section is independent and can be removed without side effects */ - if (g_htmlFlag) { - /* Convert special characters <, &, etc. to HTML entities */ - /* But skip converting math symbols inside ` ` */ - /* Detect preformatted HTML (this is crude, since it - will apply to whole comment - perhaps fine-tune this later) */ - if (convertToHtml != 0) { - if (instr(1, cmt, "") != 0) preformattedMode = 1; - } else { - preformattedMode = 1; /* For MARKUP command - don't convert HTML */ - } - mode = 1; /* 1 normal, -1 math token */ - let(&tmp, ""); - let(&tmpMasked, ""); - while (1) { - pos1 = 0; - while (1) { - pos1 = instr(pos1 + 1, cmt, "`"); - if (!pos1) break; - if (cmt[pos1] == '`') { - pos1++; /* Skip `` escape */ - continue; - } - break; - } - if (!pos1) pos1 = (long)strlen(cmt) + 1; - if (mode == 1 && preformattedMode == 0) { - let(&tmpStr, ""); - /* asciiToTt() is where "<" is converted to "<" etc. */ - tmpStr = asciiToTt(left(cmt, pos1)); - let(&tmpStrMasked, tmpStr); - } else { - let(&tmpStr, left(cmt, pos1)); - if (mode == -1) { /* Math mode */ - /* Replace math symbols with spaces to prevent confusing them - with markup in sections below */ - let(&tmpStrMasked, cat(space(pos1 - 1), - mid(cmtMasked, pos1, 1), NULL)); - } else { /* Preformatted mode but not math mode */ - let(&tmpStrMasked, left(cmtMasked, pos1)); - } - } - let(&tmp, cat(tmp, tmpStr, NULL)); - let(&tmpMasked, cat(tmpMasked, tmpStrMasked, NULL)); - let(&cmt, right(cmt, pos1 + 1)); - let(&cmtMasked, right(cmtMasked, pos1 + 1)); - if (!cmt[0]) break; - mode = (char)(-mode); - } - let(&cmt, tmp); - let(&cmtMasked, tmpMasked); - let(&tmpStr, ""); /* Deallocate */ - let(&tmpStrMasked, ""); - } - - - /* Add leading and trailing HTML markup to comment here - (instead of in caller). Also convert special characters. */ - if (g_htmlFlag) { - /* This used to be done in mmcmds.c */ - if (htmlCenterFlag) { /* Note: this should be 0 in MARKUP command */ - let(&cmt, cat("
Description: ", - cmt, "
", NULL)); - let(&cmtMasked, - cat("
Description: ", - cmtMasked, "
", NULL)); - } - } - - - /* Mask out _ (underscore) in labels so they won't become subscripts - (reported by Benoit Jubin) */ - /* This section is independent and can be removed without side effects */ - if (g_htmlFlag != 0) { - pos1 = 0; - while (1) { /* Look for label start */ - pos1 = instr(pos1 + 1, cmtMasked, "~"); - if (!pos1) break; - if (cmtMasked[pos1] == '~') { - pos1++; /* Skip ~~ escape */ - continue; - } - /* Skip whitespace after ~ */ - while (1) { - if (cmtMasked[pos1] == 0) break; /* End of line */ - if (isspace((unsigned char)(cmtMasked[pos1]))) { - pos1++; - continue; - } else { /* Found start of label */ - break; - } - } - /* Skip non-whitespace after ~ find end of label */ - while (1) { - if (cmtMasked[pos1] == 0) break; /* End of line */ - if (!(isspace((unsigned char)(cmtMasked[pos1])))) { - if (cmtMasked[pos1] == '_') { - /* Put an "?" in place of label character in mask */ - cmtMasked[pos1] = '?'; - } - pos1++; - continue; - } else { /* Found end of label */ - break; - } - } /* while (1) */ - } /* while (1) */ - } /* if g_htmlFlag */ - - - /* Handle dollar signs in comments converted to LaTeX */ - /* This section is independent and can be removed without side effects */ - /* This must be done before the underscores below so subscript $'s */ - /* won't be converted to \$'s */ - if (!g_htmlFlag) { /* LaTeX */ - pos1 = 0; - while (1) { - pos1 = instr(pos1 + 1, cmt, "$"); - if (!pos1) break; - /* Don't modify anything inside of ... tags */ - if (pos1 > instr(1, cmt, "") && pos1 < instr(1, cmt, "")) - continue; - let(&cmt, cat(left(cmt, pos1 - 1), "\\$", - right(cmt, pos1 + 1), NULL)); - let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), "\\$", - right(cmtMasked, pos1 + 1), NULL)); - pos1 = pos1 + 1; /* Adjust for 2-1 extra chars in "let" above */ - } /* while (1) */ - } - - /* This section comes BEFORE the underscore handling - below, so that "{\em...}" won't be converted to "\}\em...\}" */ - /* Convert any remaining special characters for LaTeX */ - /* This section is independent and can be removed without side effects */ - if (!g_htmlFlag) { /* i.e. LaTeX mode */ - /* At this point, the comment begins e.g "\begin{lemma}\label{lem:abc}" */ - pos1 = instr(1, cmt, "} "); - if (pos1) { - pos1++; /* Start after the "}" */ - } else { - pos1 = 1; /* If not found, start from beginning of line */ - } - pos2 = (long)strlen(cmt); - tmpMathMode = 0; - for (pos1 = pos1 + 0; pos1 <= pos2; pos1++) { - /* Don't modify anything inside of math symbol strings - (imperfect - only works if `...` is not split across lines?) */ - if (cmt[pos1 - 1] == '`') tmpMathMode = (flag)(1 - tmpMathMode); - if (tmpMathMode) continue; - if (pos1 > 1) { - if (cmt[pos1 - 1] == '_' && cmt[pos1 - 2] == '$') { - /* The _ is part of "$_{...}$" earlier conversion */ - continue; - } - } - /* $%#{}&^\\|<>"~_ are converted by asciiToTt() */ - /* Omit \ and $ since they be part of an earlier converston */ - /* Omit ~ since it is part of label ref */ - /* Omit " since it legal */ - /* Because converting to \char` causes later math mode problems due to `, - we change |><_ to /)(- (an ugly workaround) */ - switch(cmt[pos1 - 1]) { - case '|': cmt[pos1 - 1] = '/'; break; - case '<': cmt[pos1 - 1] = '{'; break; - case '>': cmt[pos1 - 1] = '}'; break; - case '_': cmt[pos1 - 1] = '-'; break; - } - if (strchr("%#{}&^|<>_", cmt[pos1 - 1]) != NULL) { - let(&tmpStr, ""); - tmpStr = asciiToTt(chr(cmt[pos1 - 1])); - let(&cmt, cat(left(cmt, pos1 - 1), tmpStr, - right(cmt, pos1 + 1), NULL)); - let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), tmpStr, - right(cmtMasked, pos1 + 1), NULL)); - pos1 += (long)strlen(tmpStr) - 1; - pos2 += (long)strlen(tmpStr) - 1; - } - } /* Next pos1 */ - } /* if (!g_htmlFlag) */ - - /* Handle underscores in comments converted to HTML: Convert _abc_ - to abc for book titles, etc.; convert a_n to an for - subscripts */ - /* This section is independent and can be removed without side effects */ - if (g_htmlFlag != 0 && processUnderscores != 0) { - pos1 = 0; - while (1) { - /* Only look at non-math part of comment */ - pos1 = instr(pos1 + 1, cmtMasked, "_"); - if (!pos1) break; - /* Don't modify anything inside of ... tags */ - if (pos1 > instr(1, cmt, "") && pos1 < instr(1, cmt, "")) - continue; - - /* Don't modify external hyperlinks containing "_" */ - pos2 = pos1 - 1; - while (1) { /* Get to previous whitespace */ - if (pos2 == 0 || isspace((unsigned char)(cmt[pos2]))) break; - pos2--; - } - if (!strcmp(mid(cmt, pos2 + 2, 7), "http://")) { - continue; - } - if (!strcmp(mid(cmt, pos2 + 2, 8), "https://")) { - continue; - } - if (!strcmp(mid(cmt, pos2 + 2, 2), "mm")) { - continue; - } - - /* Opening "_" must be _ for tag */ - if (pos1 > 1) { - /* Check for not whitespace and not opening punctuation */ - if (!isspace((unsigned char)(cmt[pos1 - 2])) - && strchr(OPENING_PUNCTUATION, cmt[pos1 - 2]) == NULL) { - /* Check for not whitespace and not closing punctuation */ - if (!isspace((unsigned char)(cmt[pos1])) - && strchr(CLOSING_PUNCTUATION, cmt[pos1]) == NULL) { - - /* Found _ - assume subscript */ - /* Locate the whitepace (or end of string) that closes subscript */ - /* Note: This algorithm is not perfect in that the subscript - is assumed to end at closing punctuation, which theoretically - could be part of the subscript itself, such as a subscript - with a comma in it. */ - pos2 = pos1 + 1; - while (1) { - if (!cmt[pos2]) break; /* End of string */ - /* Look for whitespace or closing punctuation */ - if (isspace((unsigned char)(cmt[pos2])) - || strchr(OPENING_PUNCTUATION, cmt[pos2]) != NULL - || strchr(CLOSING_PUNCTUATION, cmt[pos2]) != NULL) break; - pos2++; /* Move forward through subscript */ - } - pos2++; /* Adjust for left, seg, etc. that start at 1 not 0 */ - if (g_htmlFlag) { /* HTML */ - /* Put ... around subscript */ - let(&cmt, cat(left(cmt, pos1 - 1), - "", - seg(cmt, pos1 + 1, pos2 - 1), /* Skip (delete) "_" */ - "", right(cmt, pos2), NULL)); - let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), - "", - seg(cmtMasked, pos1 + 1, pos2 - 1), /* Skip (delete) "_" */ - "", right(cmtMasked, pos2), NULL)); - pos1 = pos2 + 33; /* Adjust for 34-1 extra chars in "let" above */ - } else { /* LaTeX */ - /* Put _{...} around subscript */ - let(&cmt, cat(left(cmt, pos1 - 1), "$_{", - seg(cmt, pos1 + 1, pos2 - 1), /* Skip (delete) "_" */ - "}$", right(cmt, pos2), NULL)); - let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), "$_{", - seg(cmtMasked, pos1 + 1, pos2 - 1), /* Skip (delete) "_" */ - "}$", right(cmtMasked, pos2), NULL)); - pos1 = pos2 + 4; /* Adjust for 5-1 extra chars in "let" above */ - } - continue; - - } else { - /* Found _ - not an opening "_" */ - /* Do nothing in this case */ - continue; - } - } - } - if (!isalnum((unsigned char)(cmt[pos1]))) continue; - /* Only look at non-math part of comment */ - pos2 = instr(pos1 + 1, cmtMasked, "_"); - if (!pos2) break; - /* Closing "_" must be _ */ - if (!isalnum((unsigned char)(cmt[pos2 - 2]))) continue; - if (isalnum((unsigned char)(cmt[pos2]))) continue; - if (g_htmlFlag) { /* HTML */ - let(&cmt, cat(left(cmt, pos1 - 1), "", - seg(cmt, pos1 + 1, pos2 - 1), - "", right(cmt, pos2 + 1), NULL)); - let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), "", - seg(cmtMasked, pos1 + 1, pos2 - 1), - "", right(cmtMasked, pos2 + 1), NULL)); - pos1 = pos2 + 5; /* Adjust for 7-2 extra chars in "let" above */ - } else { /* LaTeX */ - let(&cmt, cat(left(cmt, pos1 - 1), "{\\em ", - seg(cmt, pos1 + 1, pos2 - 1), - "}", right(cmt, pos2 + 1), NULL)); - let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), "{\\em ", - seg(cmtMasked, pos1 + 1, pos2 - 1), - "}", right(cmtMasked, pos2 + 1), NULL)); - pos1 = pos2 + 4; /* Adjust for 6-2 extra chars in "let" above */ - } - } - } - - /* Convert opening double quote to `` for LaTeX */ - /* This section is independent and can be removed without side effects */ - if (!g_htmlFlag) { /* If LaTeX mode */ - i = 1; /* Even/odd counter: 1 = left quote, 0 = right quote */ - pos1 = 0; - while (1) { - /* cmtMasked has math symbols blanked */ - pos1 = instr(pos1 + 1, cmtMasked, "\""); - if (pos1 == 0) break; - if (i == 1) { - /* Warning: "`" needs to be escaped (i.e. repeated) to prevent it - from being treated as a math symbol delimiter below. So "````" - will become "``" in the LaTeX output. */ - let(&cmt, cat(left(cmt, pos1 - 1), "````", - right(cmt, pos1 + 1), NULL)); - let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), "````", - right(cmtMasked, pos1 + 1), NULL)); - } - i = 1 - i; /* Count to next even or odd */ - } - } - - /* Put bibliography hyperlinks in comments converted to HTML: - [Monk2] becomes tag, HTML is case-insensitive for A and - NAME but case-sensitive for the token after the = */ - /* Strip all whitespace */ - let(&bibFileContents, edit(bibFileContents, 2)); - /* Uppercase version for HTML tag search */ - let(&bibFileContentsUpper, edit(bibFileContents, 32)); - htmlpos1 = 0; - while (1) { /* Look for all HTML tags */ - htmlpos1 = instr(htmlpos1 + 1, bibFileContentsUpper, ""); - if (!htmlpos2) break; - htmlpos2--; /* Move to character before ">" */ - if (bibFileContents[htmlpos2 - 1] == '\'' - || bibFileContents[htmlpos2 - 1] == '"') htmlpos2--; - if (htmlpos2 <= htmlpos1) continue; /* Ignore bad HTML syntax */ - let(&tmp, cat("[", - seg(bibFileContents, htmlpos1, htmlpos2), "]", NULL)); - /* Check if tag is already in list */ - if (instr(1, bibTags, tmp)) { - printLongLine(cat("?Error: There two occurrences of", - " bibliographic reference \"", - seg(bibFileContents, htmlpos1, htmlpos2), - "\" in the file \"", bibFileName, "\".", NULL), "", " "); - returnVal = 1; /* Error/warning printed */ - } - /* Add tag to tag list */ - let(&bibTags, cat(bibTags, tmp, NULL)); - } /* end while */ - if (!bibTags[0]) { - /* No tags found; put dummy partial tag meaning "file read" */ - let(&bibTags, "["); - } - } /* end if (!bibFIleContents) */ - } /* end if (noFileCheck == 0) */ - /* Assign to permanent tag list for next time */ - if (g_showStatement < g_extHtmlStmt) { - let(&g_htmlBibliographyTags, bibTags); - /*} else {*/ - } else if (g_showStatement < g_mathboxStmt) { - let(&extHtmlBibliographyTags, bibTags); - - } else { - let(&g_htmlBibliographyTags, bibTags); - - } - /* Done reading in HTML file with bibliography */ - } /* end if (!bibTags[0]) */ - /* See if the tag we found is in the bibliography file */ - if (bibTags[0] == '[') { - /* We have a tag list from the bibliography file */ - if (!instr(1, bibTags, bibTag)) { - printLongLine(cat("?Error: The bibliographic reference \"", bibTag, - "\" in statement \"", g_Statement[g_showStatement].labelName, - "\" was not found as an anchor in the file \"", bibFileName, "\".", NULL), - "", " "); - returnVal = 1; /* Error/warning printed */ - } - } - /* End of error-checking */ - - /* Make an HTML reference for the tag */ - let(&tmp, cat("[", - seg(bibTag, 2, pos2 - pos1), "]", NULL)); - let(&cmt, cat(left(cmt, pos1 - 1), tmp, right(cmt, - pos2 + 1), NULL)); - let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), tmp, right(cmtMasked, - pos2 + 1), NULL)); - pos1 = pos1 + (long)strlen(tmp) - (long)strlen(bibTag); /* Adjust comment position */ - } /* end while(1) */ - } /* end if (bibFileName[0]) */ - } /* end of if (g_htmlFlag) */ - - /* All actions on cmt should be mirrored on cmdMasked, except that - math symbols are replaced with blanks in cmdMasked */ - if (strlen(cmt) != strlen(cmtMasked)) bug(2334); /* Should be in sync */ - - /* Starting here, we no longer use cmtMasked, so syncing it with cmt - isn't important anymore. */ - - clen = (long)strlen(cmt); - mode = 'n'; - for (i = 0; i < clen; i++) { - if (cmt[i] == '`') { - if (cmt[i + 1] == '`') { - if (processSymbols != 0) { - /* Escaped ` = actual ` */ - let(&cmt, cat(left(cmt, i + 1), right(cmt, i + 3), NULL)); - clen--; - } - } else { - /* We will still enter and exit math mode when - processSymbols=0 so as to skip ~ in math symbols. However, - we don't insert the "DOLLAR_SUBST mode" so that later on - it will look like normal text */ - /* Enter or exit math mode */ - if (mode != 'm') { - mode = 'm'; - } else { - mode = 'n'; - } - - if (processSymbols != 0) { - let(&cmt, cat(left(cmt, i), chr(DOLLAR_SUBST) /*$*/, chr(mode), - right(cmt, i+2), NULL)); - clen++; - i++; - } - - /* If symbol is preceded by opening punctuation and a space, take out - the space so it looks better. */ - if (mode == 'm' && processSymbols != 0) { - let(&tmp, mid(cmt, i - 2, 2)); - if (!strcmp("( ", tmp)) { - let(&cmt, cat(left(cmt, i - 2), right(cmt, i), NULL)); - clen = clen - 1; - } - /* We include quotes since symbols are often enclosed in them. */ - let(&tmp, mid(cmt, i - 8, 8)); - if (!strcmp("" ", right(tmp, 2)) - && strchr("( ", tmp[0]) != NULL) { - let(&cmt, cat(left(cmt, i - 2), right(cmt, i), NULL)); - clen = clen - 1; - } - let(&tmp, ""); - } - /* If symbol is followed by a space and closing punctuation, take out - the space so it looks better. */ - if (mode == 'n' && processSymbols != 0) { - /* (Why must it be i + 2 here but i + 1 in label version below? - Didn't investigate but seems strange.) */ - let(&tmp, mid(cmt, i + 2, 2)); - if (tmp[0] == ' ' && strchr(CLOSING_PUNCTUATION, tmp[1]) != NULL) { - let(&cmt, cat(left(cmt, i + 1), right(cmt, i + 3), NULL)); - clen = clen - 1; - } - /* We include quotes since symbols are often enclosed in them. */ - let(&tmp, mid(cmt, i + 2, 8)); - if (strlen(tmp) < 8) - let(&tmp, cat(tmp, space(8 - (long)strlen(tmp)), NULL)); - if (!strcmp(" "", left(tmp, 7)) - && strchr(CLOSING_PUNCTUATION, tmp[7]) != NULL) { - let(&cmt, cat(left(cmt, i + 1), right(cmt, i + 3), NULL)); - clen = clen - 1; - } - let(&tmp, ""); - } - - } - } - if (cmt[i] == '~' && mode != 'm') { - if (cmt[i + 1] == '~' /* Escaped ~ */ || processLabels == 0) { - if (processLabels != 0) { - /* Escaped ~ = actual ~ */ - let(&cmt, cat(left(cmt, i + 1), right(cmt, i + 3), NULL)); - clen--; - } - } else { - /* Enter or exit label mode */ - if (mode != 'l') { - mode = 'l'; - /* If there is whitespace after the ~, then remove - all whitespace immediately after the ~ to join the ~ to - the label. This enhances the Metamath syntax so that - whitespace is now allowed between the ~ and the label, which - makes it easier to do global substitutions of labels in a - text editor. */ - while (isspace((unsigned char)(cmt[i + 1])) && clen > i + 1) { - let(&cmt, cat(left(cmt, i + 1), right(cmt, i + 3), NULL)); - clen--; - } - } else { - /* If you see this bug, the most likely cause is a tilde - character in a comment that does not prefix a label or hyperlink. - The most common problem is the "~" inside a hyperlink that - specifies a user's directory. To fix it, use a double tilde - "~~" to escape it, which will become a single tilde on output. */ - g_outputToString = 0; - printLongLine(cat("?Warning: There is a \"~\" inside of a label", - " in the comment of statement \"", - g_Statement[g_showStatement].labelName, - "\". Use \"~~\" to escape \"~\" in an http reference.", - NULL), "", " "); - returnVal = 1; /* Error/warning printed */ - g_outputToString = 1; - mode = 'n'; - } - let(&cmt, cat(left(cmt, i), chr(DOLLAR_SUBST) /*$*/, chr(mode), - right(cmt, i+2), NULL)); - clen++; - i++; - - /* If label is preceded by opening punctuation and space, take out - the space so it looks better. */ - let(&tmp, mid(cmt, i - 2, 2)); - /*printf("tmp#%s#\n",tmp);*/ - if (!strcmp("( ", tmp) || !strcmp("[ ", tmp)) { - let(&cmt, cat(left(cmt, i - 2), right(cmt, i), NULL)); - clen = clen - 1; - } - let(&tmp, ""); - - } - } - - if (processLabels == 0 && mode == 'l') { - /* We should have prevented it from ever getting into label mode */ - bug(2344); - } - - if ((isspace((unsigned char)(cmt[i])) - || cmt[i] == '<') /* If the label ends the comment, - "" with no space will be appended before this section. */ - && mode == 'l') { - /* Whitespace exits label mode */ - mode = 'n'; - let(&cmt, cat(left(cmt, i), chr(DOLLAR_SUBST) /*$*/, chr(mode), - right(cmt, i+1), NULL)); - clen = clen + 2; - i = i + 2; - - /* If label is followed by space and end punctuation, take out the space - so it looks better. */ - let(&tmp, mid(cmt, i + 1, 2)); - if (tmp[0] == ' ' && strchr(CLOSING_PUNCTUATION, tmp[1]) != NULL) { - let(&cmt, cat(left(cmt, i), right(cmt, i + 2), NULL)); - clen = clen - 1; - } - let(&tmp, ""); - - } - /* clen should always remain comment length - do a sanity check here */ - if ((signed)(strlen(cmt)) != clen) { - bug(2311); - } - } /* Next i */ - /* End convert line to the old $m..$n and $l..$n */ - - - /* Put and at beginning of line so preformattedMode won't - be switched on or off in the middle of processing a line */ - /* This also fixes the problem where multiple ... on one - line aren't all removed in HTML output, causing w3c validation errors */ - /* Note: "Q2." will have a space around "2" because - of this fix. Instead use "Q2." or just "Q^2." */ - pos1 = -1; /* So -1 + 2 = 1 = start of string for instr() */ - while (1) { - pos1 = instr(pos1 + 2/*skip new \n*/, cmt, ""); - if (pos1 == 0 - || convertToHtml == 0 /* Don't touch in MARKUP command */ - ) break; - - /* If begins a line (after stripping spaces), don't put a \n so - that we don't trigger new paragraph mode */ - let(&tmpStr, edit(left(cmt, pos1 - 1), 2/*discard spaces & tabs*/)); - i = (long)strlen(tmpStr); - if (i == 0) continue; - if (tmpStr[i - 1] == '\n') continue; - - let(&cmt, cat(left(cmt, pos1 - 1), "\n", right(cmt, pos1), NULL)); - } - pos1 = -1; /* So -1 + 2 = 1 = start of string for instr() */ - while (1) { - pos1 = instr(pos1 + 2/*skip new \n*/, cmt, ""); - if (pos1 == 0 - || convertToHtml == 0 /* Don't touch in MARKUP command */ - ) break; - - /* If begins a line (after stripping spaces), don't put a \n so - that we don't trigger new paragraph mode */ - let(&tmpStr, edit(left(cmt, pos1 - 1), 2/*discard spaces & tabs*/)); - i = (long)strlen(tmpStr); - if (i == 0) continue; - if (tmpStr[i - 1] == '\n') continue; - - let(&cmt, cat(left(cmt, pos1 - 1), "\n", right(cmt, pos1), NULL)); - } - - - cmtptr = cmt; /* cmtptr is for scanning cmt */ - - g_outputToString = 1; /* Redirect print2 and printLongLine to g_printString */ - - while (1) { - /* Get a "line" of text, up to the next new-line. New-lines embedded - in $m and $l sections are ignored, so that these sections will not - be dangling. */ - lineStart = cmtptr; - textMode = 1; - lastLineFlag = 0; - while (1) { - if (cmtptr[0] == 0) { - lastLineFlag = 1; - break; - } - if (cmtptr[0] == '\n' && textMode) break; - /* if (cmtptr[0] == '$') { */ - if (cmtptr[0] == DOLLAR_SUBST) { - if (cmtptr[1] == ')') { - bug(2312); /* Obsolete (should never happen) */ - lastLineFlag = 1; - break; - } - } - if (cmtptr[0] == DOLLAR_SUBST /*'$'*/) { - cmtptr++; - if (cmtptr[0] == 'm') textMode = 0; /* Math mode */ - if (cmtptr[0] == 'l') textMode = 0; /* Label mode */ - if (cmtptr[0] == 'n') textMode = 1; /* Normal mode */ - } - cmtptr++; - } - let(&sourceLine, space(cmtptr - lineStart)); - memcpy(sourceLine, lineStart, (size_t)(cmtptr - lineStart)); - cmtptr++; /* Get past new-line to prepare for next line's scan */ - - /* If the line contains only math mode text, use TeX display mode. */ - displayMode = 0; - let(&tmpStr, edit(sourceLine, 8 + 128)); /* Trim spaces */ - if (!strcmp(right(tmpStr, (long)strlen(tmpStr) - 1), cat(chr(DOLLAR_SUBST), "n", - NULL))) let(&tmpStr, left(tmpStr, (long)strlen(tmpStr) - 2)); /* Strip $n */ - srcptr = tmpStr; - modeSection = getCommentModeSection(&srcptr, &mode); - let(&modeSection, ""); /* Deallocate */ - if (mode == 'm') { - modeSection = getCommentModeSection(&srcptr, &mode); - let(&modeSection, ""); /* Deallocate */ - } - let(&tmpStr, ""); /* Deallocate */ - - - /* Convert all sections of the line to text, math, or labels */ - let(&outputLine, ""); - srcptr = sourceLine; - while (1) { - modeSection = getCommentModeSection(&srcptr, &mode); - if (!mode) break; /* Done */ - let(&modeSection, right(modeSection, 3)); /* Remove mode-change command */ - switch (mode) { - case 'n': /* Normal text */ - let(&outputLine, cat(outputLine, modeSection, NULL)); - break; - case 'l': /* Label mode */ - - if (processLabels == 0) { - /* Labels should be treated as normal text */ - bug(2345); - } - - let(&modeSection, edit(modeSection, 8 + 128 + 16)); /* Discard - leading and trailing blanks; reduce spaces to one space */ - let(&tmpStr, ""); - tmpStr = asciiToTt(modeSection); - if (!tmpStr[0]) { - /* This can happen if ~ is followed by ` (start of math string) */ - g_outputToString = 0; - printLongLine(cat("?Error: There is a \"~\" with no label", - " in the comment of statement \"", - g_Statement[g_showStatement].labelName, - "\". Check that \"`\" inside of a math symbol is", - " escaped with \"``\".", - NULL), "", " "); - returnVal = 1; /* Error/warning printed */ - g_outputToString = 1; - - } - - if (!strcmp("http://", left(tmpStr, 7)) - || !strcmp("https://", left(tmpStr, 8)) - || !strcmp("mm", left(tmpStr, 2))) { - /* If the "label" begins with 'http://', then - assume it is an external hyperlink and not a real label. - This is kind of a syntax kludge but it is easy to do. - Added starting with 'mm', which is illegal - for set.mm labels - e.g. mmtheorems.html#abc */ - - if (g_htmlFlag) { - let(&outputLine, cat(outputLine, "", tmpStr, "", tmp, NULL)); - } else { - - /* Generate LaTeX version of the URL */ - i = instr(1, tmpStr, "\\char`\\~"); - /* The url{} function automatically converts ~ to LaTeX */ - if (i != 0) { - let(&tmpStr, cat(left(tmpStr, i - 1), right(tmpStr, i + 7), - NULL)); - } - let(&outputLine, cat(outputLine, "\\url{", tmpStr, - "}", tmp, NULL)); - - } - } else { - /* Do binary search through just $a's and $p's (there - are no html pages for local labels) */ - i = lookupLabel(tmpStr); - if (i < 0) { - g_outputToString = 0; - printLongLine(cat("?Warning: The label token \"", tmpStr, - "\" (referenced in comment of statement \"", - g_Statement[g_showStatement].labelName, - "\") is not a $a or $p statement label.", NULL), "", " "); - g_outputToString = 1; - returnVal = 1; /* Error/warning printed */ - } - - if (!g_htmlFlag) { - let(&outputLine, cat(outputLine, "{\\tt ", tmpStr, - "}", NULL)); - } else { - let(&tmp, ""); - if (addColoredLabelNumber != 0) { - /* When the error above occurs, i < 0 will cause pinkHTML() - to issue "(future)" for pleasant readability */ - tmp = pinkHTML(i); - } - if (i < 0) { - /* Error output - prevent broken link */ - let(&outputLine, cat(outputLine, "", tmpStr, "", tmp, NULL)); - } else { - /* Normal output - put hyperlink to the statement */ - let(&outputLine, cat(outputLine, "", tmpStr, "", tmp, NULL)); - } - } - } /* if (!strcmp("http://", left(tmpStr, 7))) ... else */ - let(&tmpStr, ""); /* Deallocate */ - break; - case 'm': /* Math mode */ - - if (processSymbols == 0) { - /* Math symbols should be treated as normal text */ - bug(2346); - } - - let(&tmpStr, ""); - tmpStr = asciiMathToTex(modeSection, g_showStatement); - if (!g_htmlFlag) { - if (displayMode) { - /* It the user's responsibility to establish equation environment - in displayMode. */ - let(&outputLine, cat(outputLine, /*"\\[",*/ edit(tmpStr, 128), - /*"\\]",*/ NULL)); /* edit = remove trailing spaces */ - } else { - let(&outputLine, cat(outputLine, "$", edit(tmpStr, 128), - "$", NULL)); /* edit = remove trailing spaces */ - } - } else { - /* Trim leading, trailing spaces in case punctuation - surrounds the math symbols in the comment */ - let(&tmpStr, edit(tmpStr, 8 + 128)); - /* Enclose math symbols in a span to be used for font selection */ - let(&tmpStr, cat( - (g_altHtmlFlag ? cat("", NULL) : ""), - tmpStr, - (g_altHtmlFlag ? "" : ""), - NULL)); - let(&outputLine, cat(outputLine, tmpStr, NULL)); /* html */ - } - let(&tmpStr, ""); /* Deallocate */ - break; - } /* End switch(mode) */ - let(&modeSection, ""); /* Deallocate */ - } - let(&outputLine, edit(outputLine, 128)); /* remove trailing spaces */ - - if (g_htmlFlag) { - /* Change blank lines into paragraph breaks except in mode */ - if (!outputLine[0]) { /* Blank line */ - if (preformattedMode == 0 - && convertToHtml == 1 /* Not MARKUP command */ - ) { /* Make it a paragraph break */ - let(&outputLine, - /* Prevent space after last paragraph */ - "

"); - } - } - /* If a statement comment has a section embedded in - ..., we keep the contents verbatim */ - pos1 = instr(1, outputLine, ""); - if (pos1 != 0 && convertToHtml == 1) { - /* The line below is probably redundant since we - set preformattedMode ealier. Maybe add a bug check to make sure - it is 1 here. */ - preformattedMode = 1; /* So we don't put

for blank lines */ - /* Strip out the "" string */ - let(&outputLine, cat(left(outputLine, pos1 - 1), - right(outputLine, pos1 + 6), NULL)); - } - pos1 = instr(1, outputLine, ""); - if (pos1 != 0 && convertToHtml == 1) { - preformattedMode = 0; - /* Strip out the "" string */ - let(&outputLine, cat(left(outputLine, pos1 - 1), - right(outputLine, pos1 + 7), NULL)); - } - } - - if (!g_htmlFlag) { /* LaTeX */ - /* Convert

...
HTML tags to LaTeX */ - /* leave this in for now */ - while (1) { - pos1 = instr(1, outputLine, "
");
-        if (pos1) {
-          let(&outputLine, cat(left(outputLine, pos1 - 1), "\\begin{verbatim} ",
-              right(outputLine, pos1 + 5), NULL));
-        } else {
-          break;
-        }
-      }
-      while (1) {
-        pos1 = instr(1, outputLine, "
"); - if (pos1) { - let(&outputLine, cat(left(outputLine, pos1 - 1), "\\end{verbatim} ", - right(outputLine, pos1 + 6), NULL)); - } else { - break; - } - } - /* strip out , */ - /* The HTML part may screw up LaTeX; maybe we should just take out - any HTML code completely in the future? */ - while (1) { - pos1 = instr(1, outputLine, ""); - if (pos1) { - let(&outputLine, cat(left(outputLine, pos1 - 1), - right(outputLine, pos1 + 6), NULL)); - } else { - break; - } - } - while (1) { - pos1 = instr(1, outputLine, ""); - if (pos1) { - let(&outputLine, cat(left(outputLine, pos1 - 1), - right(outputLine, pos1 + 7), NULL)); - } else { - break; - } - } - } - - saveScreenWidth = g_screenWidth; - /* in
 mode, we don't want to wrap the HTML
-       output with spurious newlines. Any large value will
-       do; we just need to accomodate the worst case line length that will
-       result from converting ~ label, [author], ` math ` to HTML */
-    if (preformattedMode) g_screenWidth = 50000;
-    if (errorsOnly == 0) {
-      printLongLine(outputLine, "", g_htmlFlag ? "\"" : "\\");
-    }
-    g_screenWidth = saveScreenWidth;
-
-    let(&tmp, ""); /* Clear temporary allocation stack */
-
-    if (lastLineFlag) break; /* Done */
-  } /* end while(1) */
-
-  if (g_htmlFlag) {
-    if (convertToHtml != 0) { /* Not MARKUP command */
-      print2("\n"); /* Don't change what the previous code did */
-    } else {
-      /* Add newline if string is not empty and has no newline at end */
-      if (g_printString[0] != 0) {
-        i = (long)strlen(g_printString);
-        if (g_printString[i - 1] != '\n')  {
-          print2("\n");
-        } else {
-          /* There is an extra \n added by something previous.  Until
-             we figure out what, take it off so that MARKUP output will
-             equal input when no processing qualifiers are used. */
-          if (i > 1) {
-            if (g_printString[i - 2] == '\n') {
-              let(&g_printString, left(g_printString, i - 1));
-            }
-          }
-        }
-      }
-    }
-  } else { /* LaTeX mode */
-    if (!g_oldTexFlag) {
-      /* Suppress blank line for LaTeX */
-      /* print2("\n"); */
-    } else {
-      print2("\n");
-    }
-  }
-
-  g_outputToString = 0; /* Restore normal output */
-  if (errorsOnly == 0) {
-    fprintf(g_texFilePtr, "%s", g_printString);
-  }
-
-  let(&g_printString, ""); /* Deallocate strings */
-  let(&sourceLine, "");
-  let(&outputLine, "");
-  let(&cmt, "");
-  let(&cmtMasked, "");
-  let(&tmpComment, "");
-  let(&tmp, "");
-  let(&tmpMasked, "");
-  let(&tmpStr, "");
-  let(&tmpStrMasked, "");
-  let(&bibTag, "");
-  let(&bibFileName, "");
-  let(&bibFileContents, "");
-  let(&bibFileContentsUpper, "");
-  let(&bibTags, "");
-
-  return returnVal; /* 1 if error/warning found */
-
-} /* printTexComment */
-
-
-
-void printTexLongMath(nmbrString *mathString,
-    vstring startPrefix, /* Start prefix in "screen display" mode e.g.
-         "abc $p"; it is converted to the appropriate format.  Non-zero
-         length means proof step in HTML mode, as opposed to assertion etc. */
-    vstring contPrefix, /* Prefix for continuation lines.  Not used in
-         HTML mode.  Warning:  contPrefix must not be temporarily allocated
-         (as a cat, left, etc. argument) by caller */
-    long hypStmt, /* hypStmt, if non-zero, is the statement number to be
-                     referenced next to the hypothesis link in html */
-    long indentationLevel) /* Indentation amount of proof step -
-                              note that this is 0 for last step of proof */
-{
-#define INDENTATION_OFFSET 1
-  long i;
-  long pos;
-  vstring tex = "";
-  vstring texLine = "";
-  vstring sPrefix = "";
-  vstring htmStep = "";
-  vstring htmStepTag = "";
-  vstring htmHyp = "";
-  vstring htmRef = "";
-  vstring htmLocLab = "";
-  vstring tmp = "";
-  vstring descr = "";
-  char refType = '?'; /* 'e' means $e, etc. */
-
-  let(&sPrefix, startPrefix); /* Save it; it may be temp alloc */
-
-  if (!g_texDefsRead) return; /* TeX defs were not read (error was printed) */
-  g_outputToString = 1; /* Redirect print2 and printLongLine to g_printString */
-
-  /* Note that the "tex" assignment below will be used only when !g_htmlFlag
-     and g_oldTexFlag, or when g_htmlFlag and len(sPrefix)>0 */
-  let(&tex, "");
-  tex = asciiToTt(sPrefix); /* asciiToTt allocates; we must deallocate */
-      /* Example: sPrefix = " 4 2,3 ax-mp  $a " */
-      /*          tex = "\ 4\ 2,3\ ax-mp\ \ \$a\ " in !g_htmlFlag mode */
-      /*          tex = " 4 2,3 ax-qmp  $a " in g_htmlFlag mode */
-  let(&texLine, "");
-
-  /* Get statement type of proof step reference */
-  i = instr(1, sPrefix, "$");
-  if (i) refType = sPrefix[i]; /* Character after the "$" */
-
-  if (g_htmlFlag || !g_oldTexFlag) {
-
-    /* Process a proof step prefix */
-    if (strlen(sPrefix)) { /* It's a proof step */
-      /* Make each token a separate table column for HTML */
-      /* This is a kludge that only works with /LEMMON style proofs! */
-      /* Note that asciiToTt() above puts "\ " when not in
-         g_htmlFlag mode, so use sPrefix instead of tex so it will work in
-         !g_oldTexFlag mode */
-
-      /* In HTML mode, sPrefix has two possible formats:
-           "2 ax-1  $a "
-           "3 1,2 ax-mp  $a "
-         In LaTeX mode (!g_htmlFlag), sPrefix has one format:
-           "8   maj=ax-1  $a "
-           "9 a1i=ax-mp $a " */
-
-      let(&tex, edit(sPrefix, 8/*no leading spaces*/
-           + 16/*reduce spaces and tabs*/
-           + 128/*no trailing spaces*/));
-
-      i = 0;
-      pos = 1;
-      while (pos) {
-        pos = instr(1, tex, " ");
-        if (pos) {
-          if (i > 3) { /* added for extra safety for the future */
-            bug(2316);
-          }
-          if (i == 0) let(&htmStep, left(tex, pos - 1));
-          if (i == 1) let(&htmHyp, left(tex, pos - 1));
-          if (i == 2) let(&htmRef, left(tex, pos - 1));
-          if (i == 3) let(&htmLocLab, left(tex, pos - 1));
-
-          let(&tex, right(tex, pos + 1));
-          i++;
-        }
-      }
-
-      if (i == 3 && htmRef[0] == '@') {
-        /* The referenced statement has no hypotheses but has a local
-           label e.g."2 a4s @2: $p" */
-        let(&htmLocLab, htmRef);
-        let(&htmRef, htmHyp);
-        let(&htmHyp, "");
-      }
-
-      if (i < 3) {
-        /* The referenced statement has no hypotheses e.g.
-           "4 ax-1 $a" */
-        let(&htmRef, htmHyp);
-        let(&htmHyp, "");
-
-        /* Change "maj=ax-1" to "ax-1" so \ref{} produced by
-           "show proof .../tex" will match \label{} produced by
-           "show statement .../tex" */
-        /* Earlier we set the noIndentFlag (Lemmon
-           proof) in the SHOW PROOF.../TEX call in metamath.c, so the
-           hypothesis ref list will be available just like in the HTML
-           output. */
-        /* We now consider "=" a bug since the call via typeProof() in
-           metamath.c now always has noIndentFlag = 1. */
-        if (!g_htmlFlag) {
-          pos = instr(1, htmRef, "=");
-          if (pos) bug(2342);
-        }
-      }
-    } /* if (strlen(sPrefix)) (end processing proof step prefix) */
-  }
-
-  if (!g_htmlFlag) {
-    if (g_oldTexFlag) {
-      /* Trim down long start prefixes so they won't overflow line,
-         by putting their tokens into \m macros */
-#define TRIMTHRESHOLD 60
-      i = (long)strlen(tex);
-      while (i > TRIMTHRESHOLD) {
-        if (tex[i] == '\\') {
-          /* Move to math part */
-          let(&texLine, cat("\\m{\\mbox{\\tt", right(tex, i + 1), "}}",
-              texLine, NULL));
-          /* Take off of prefix part */
-          let(&tex, left(tex, i));
-        }
-        i--;
-      }
-
-      printLongLine(cat(
-          "\\setbox\\startprefix=\\hbox{\\tt ", tex, "}", NULL), "", "\\");
-      let(&tex, ""); /* Deallocate */
-      tex = asciiToTt(contPrefix);
-      printLongLine(cat(
-          "\\setbox\\contprefix=\\hbox{\\tt ", tex, "}", NULL), "", "\\");
-      print2("\\startm\n");
-    }
-  } else { /* g_htmlFlag */
-    if (strlen(sPrefix)) { /* It's a proof step */
-
-      if (htmHyp[0] == 0)
-        let(&htmHyp, " ");  /* Insert blank field for Lemmon ref w/out hyp */
-
-      /* Put hyperlinks on hypothesis
-         label references in SHOW STATEMENT * /HTML, ALT_HTML output */
-      /* Use a separate tag to put into the math cell,
-         so it will link to the top of the math cell */
-      let(&htmStepTag, cat("","", NULL));
-      i = 1;
-      pos = 1;
-      while (pos && strcmp(htmHyp, " ")) {
-        pos = instr(i,htmHyp, ",");
-        if (!pos) pos = len(htmHyp) + 1;
-        let(&htmHyp, cat(left(htmHyp, i - 1),
-            "",
-            seg(htmHyp, i, pos - 1),
-            "",
-            right(htmHyp, pos),
-            NULL));
-        /* Break out of loop if we hit the end */
-        pos += 16 + len(seg(htmHyp, i, pos - 1)) + 1;
-        if (!instr(i, htmHyp, ",")) break;
-        i = pos;
-      }
-
-      /* Add a space after each comma so very long hypotheses
-         lists will wrap in an HTML table cell, e.g. gomaex3 in ql.mm */
-      pos = instr(1, htmHyp, ",");
-      while (pos) {
-        let(&htmHyp, cat(left(htmHyp, pos), " ", right(htmHyp, pos + 1), NULL));
-        pos = instr(pos + 1, htmHyp, ",");
-      }
-
-      if (refType == 'e' || refType == 'f') {
-        /* A hypothesis - don't include link */
-        printLongLine(cat("", htmStep, "",
-            htmHyp, "", htmRef,
-            "",
-            htmStepTag, /* Put the  tag at start of math symbol cell */
-            NULL), "", "\"");
-      } else {
-        if (hypStmt <= 0) {
-          printLongLine(cat("", htmStep, "",
-              htmHyp, "", htmRef,
-              "",
-              htmStepTag, /* Put the  tag at start of math symbol cell */
-              NULL), "", "\"");
-        } else {
-          /* Include step number reference.  The idea is that this will
-             help the user to recognized "important" (vs. early trivial
-             logic) steps.  This prints a small pink statement number
-             after the hypothesis statement label. */
-          let(&tmp, "");
-          tmp = pinkHTML(hypStmt);
-
-          /* Get description for mod below */
-          let(&descr, ""); /* Deallocate previous description */
-          descr = getDescription(hypStmt);
-          let(&descr, edit(descr, 4 + 16)); /* Discard lf/cr; reduce spaces */
-#define MAX_DESCR_LEN 87
-          if (strlen(descr) > MAX_DESCR_LEN) { /* Truncate long lines */
-            i = MAX_DESCR_LEN - 3;
-            while (i >= 0) { /* Get to previous word boundary */
-              if (descr[i] == ' ') break;
-              i--;
-            }
-            let(&descr, cat(left(descr, i), "...", NULL));
-          }
-          i = 0;
-          while (descr[i] != 0) { /* Convert double quote to single */
-            descr[i] = (char)(descr[i] == '"' ? '\'' : descr[i]);
-            i++;
-          }
-
-          printLongLine(cat("", htmStep, "",
-              htmHyp, "", htmRef,
-              "", tmp,
-              "",
-              htmStepTag, /* Put the  tag at start of math symbol cell */
-              NULL), "", "\"");
-        }
-      }
-      /* Indent web proof displays */
-      let(&tmp, "");
-      for (i = 1; i <= indentationLevel; i++) {
-        let(&tmp, cat(tmp, ". ", NULL));
-      }
-      let(&tmp, cat("",
-          tmp,
-          str((double)(indentationLevel + INDENTATION_OFFSET)), "",
-          NULL));
-      printLongLine(tmp, "", "\"");
-      let(&tmp, "");
-    } /* strlen(sPrefix) */
-  } /* g_htmlFlag */
-  let(&tex, ""); /* Deallocate */
-  let(&sPrefix, ""); /* Deallocate */
-
-  let(&tex, "");
-  tex = getTexLongMath(mathString, hypStmt);
-  let(&texLine, cat(texLine, tex, NULL));
-
-  if (!g_htmlFlag) {  /* LaTeX */
-    if (!g_oldTexFlag) {
-      if (refType == 'e' || refType == 'f') {
-        /* A hypothesis - don't include \ref{} */
-        printLongLine(cat("  ",
-            /* If not first step, so print "\\" LaTeX line break */
-            !strcmp(htmStep, "1") ? "" : "\\\\ ",
-            htmStep,  /* Step number */
-            " && ",
-            " & ",
-            texLine,
-            /* Don't put space to help prevent bad line break */
-            "&\\text{Hyp~",
-            /* The following puts a hypothesis number such as "2" if
-               $e label is "abc.2"; if no ".", will be whole label */
-            right(htmRef, instr(1, htmRef, ".") + 1),
-            "}\\notag%",
-            /* Add full label as LaTeX comment - note lack of space after
-               "%" above to prevent bad line break */
-            htmRef, NULL),
-            "    \\notag \\\\ && & \\qquad ",  /* Continuation line prefix */
-            " ");
-      } else {
-        printLongLine(cat("  ",
-            /* If not first step, so print "\\" LaTeX line break */
-            !strcmp(htmStep, "1") ? "" : "\\\\ ",
-            htmStep,  /* Step number */
-            " && ",
-
-            /* Local label if any e.g. "@2:" */
-            (htmLocLab[0] != 0) ? cat(htmLocLab, "\\ ", NULL) : "",
-
-            " & ",
-            texLine,
-            /* Don't put space to help prevent bad line break */
-
-            /* Surround \ref with \mbox for non-math-mode
-               symbolic labels (due to \tag{..} in mmcmds.c).  Also,
-               move hypotheses to after referenced label */
-            "&",
-            "(",
-
-            /* Don't make local label a \ref */
-            (htmRef[0] != '@') ?
-                cat("\\mbox{\\ref{eq:", htmRef, "}}", NULL)
-                : htmRef,
-
-            htmHyp[0] ? "," : "",
-            htmHyp,
-            ")\\notag", NULL),
-
-            "    \\notag \\\\ && & \\qquad ",  /* Continuation line prefix */
-            " ");
-      }
-    } else {
-      printLongLine(texLine, "", "\\");
-      print2("\\endm\n");
-    }
-  } else {  /* HTML */
-    printLongLine(cat(texLine, "", NULL), "", "\"");
-  }
-
-  g_outputToString = 0; /* Restore normal output */
-  fprintf(g_texFilePtr, "%s", g_printString);
-  let(&g_printString, "");
-
-  let(&descr, ""); /*Deallocate */
-  let(&htmStep, ""); /* Deallocate */
-  let(&htmStepTag, ""); /* Deallocate */
-  let(&htmHyp, ""); /* Deallocate */
-  let(&htmRef, ""); /* Deallocate */
-  let(&htmLocLab, ""); /* Deallocate */
-  let(&tmp, ""); /* Deallocate */
-  let(&texLine, ""); /* Deallocate */
-  let(&tex, ""); /* Deallocate */
-} /* printTexLongMath */
-
-void printTexTrailer(flag texTrailerFlag) {
-
-  if (texTrailerFlag) {
-    g_outputToString = 1; /* Redirect print2 and printLongLine to g_printString */
-    if (!g_htmlFlag) let(&g_printString, "");
-        /* May have stuff to be printed */
-    if (!g_htmlFlag) {
-      print2("\\end{document}\n");
-    } else {
-      print2("
\n"); - print2("\n", "%"); - print2("\n", "%"); - print2("
 \n"); - print2("\n"); - print2("Copyright terms:\n"); - print2("Public domain\n"); - print2("\n", "%"); - print2("\n"); - print2("\n"); - print2("W3C validator\n"); - print2("
\n"); - print2("\n"); - } - g_outputToString = 0; /* Restore normal output */ - fprintf(g_texFilePtr, "%s", g_printString); - let(&g_printString, ""); - } - -} /* printTexTrailer */ - - -/* WRITE THEOREM_LIST command: Write out theorem list - into mmtheorems.html, mmtheorems1.html,... */ -void writeTheoremList(long theoremsPerPage, flag showLemmas, flag noVersioning) -{ - nmbrString *nmbrStmtNmbr = NULL_NMBRSTRING; - long pages, page, assertion, assertions, lastAssertion; - long s, p, i1, i2; - vstring str1 = ""; - vstring str3 = ""; - vstring str4 = ""; - vstring prevNextLinks = ""; - long partCntr; /* Counter for hugeHdr */ - long sectionCntr; /* Counter for bigHdr */ - long subsectionCntr; /* Counter for smallHdr */ - long subsubsectionCntr; /* Counter for tinyHdr */ - vstring outputFileName = ""; - FILE *outputFilePtr; - long passNumber; /* for summary/detailed table of contents */ - - /* for table of contents */ - vstring hugeHdr = ""; - vstring bigHdr = ""; - vstring smallHdr = ""; - vstring tinyHdr = ""; - vstring hugeHdrComment = ""; - vstring bigHdrComment = ""; - vstring smallHdrComment = ""; - vstring tinyHdrComment = ""; - long stmt, i; - pntrString *pntrHugeHdr = NULL_PNTRSTRING; - pntrString *pntrBigHdr = NULL_PNTRSTRING; - pntrString *pntrSmallHdr = NULL_PNTRSTRING; - pntrString *pntrTinyHdr = NULL_PNTRSTRING; - pntrString *pntrHugeHdrComment = NULL_PNTRSTRING; - pntrString *pntrBigHdrComment = NULL_PNTRSTRING; - pntrString *pntrSmallHdrComment = NULL_PNTRSTRING; - pntrString *pntrTinyHdrComment = NULL_PNTRSTRING; - vstring hdrCommentMarker = ""; - vstring hdrCommentAnchor = ""; - flag hdrCommentAnchorDone = 0; - - /* Populate the statement map */ - /* ? ? ? Future: is assertions same as g_Statement[g_statements].pinkNumber? */ - nmbrLet(&nmbrStmtNmbr, nmbrSpace(g_statements + 1)); - assertions = 0; /* Number of $p's + $a's */ - for (s = 1; s <= g_statements; s++) { - if (g_Statement[s].type == a_ || g_Statement[s].type == p_) { - assertions++; /* Corresponds to pink number */ - nmbrStmtNmbr[assertions] = s; - } - } - if (assertions != g_Statement[g_statements].pinkNumber) bug(2328); - - /* Table of contents */ - /* Allocate array for section headers found */ - pntrLet(&pntrHugeHdr, pntrSpace(g_statements + 1)); - pntrLet(&pntrBigHdr, pntrSpace(g_statements + 1)); - pntrLet(&pntrSmallHdr, pntrSpace(g_statements + 1)); - pntrLet(&pntrTinyHdr, pntrSpace(g_statements + 1)); - pntrLet(&pntrHugeHdrComment, pntrSpace(g_statements + 1)); - pntrLet(&pntrBigHdrComment, pntrSpace(g_statements + 1)); - pntrLet(&pntrSmallHdrComment, pntrSpace(g_statements + 1)); - pntrLet(&pntrTinyHdrComment, pntrSpace(g_statements + 1)); - - pages = ((assertions - 1) / theoremsPerPage) + 1; - for (page = 0; page <= pages; page++) { - /* Open file */ - let(&outputFileName, - cat("mmtheorems", (page > 0) ? str((double)page) : "", ".html", NULL)); - print2("Creating %s\n", outputFileName); - outputFilePtr = fSafeOpen(outputFileName, "w", noVersioning); - if (!outputFilePtr) goto TL_ABORT; /* Couldn't open it (error msg was provided)*/ - - /* Output header */ - /* TODO 14-Jan-2016: why aren't we using printTexHeader? */ - - g_outputToString = 1; - print2("\n"); - print2("\n"); - print2("\n"); - print2("%s%s\n", ""); - /* Improve mobile device display per David A. Wheeler */ - print2("\n"); - - print2("\n"); - printLongLine(g_htmlCSS, "", " "); - - /* - print2("%s\n", cat("", htmlTitle, " - ", - / * Strip off ".html" * / - left(outputFileName, (long)strlen(outputFileName) - 5), - "", NULL)); - */ - /* Put page name before "Metamath Proof Explorer" etc. */ - printLongLine(cat("", - ((page == 0) - ? "TOC of Theorem List" - : cat("P. ", str((double)page), " of Theorem List", NULL)), - - " - ", - htmlTitle, - "", - NULL), "", "\""); - /* Icon for bookmark */ - print2("%s%s\n", ""); - - /* Image alignment fix */ - print2("\n"); - - print2("\n"); - print2("\n"); - print2("\n", "%"); - print2("", NULL), "", "\""); - printLongLine(cat( - "\n"); - } else { - print2("\n"); - } - } - - /* Make breadcrumb font to match other pages */ - print2("\n"); - print2( - "\n"); - print2("
", g_htmlHome, "", htmlTitle, "", - "
Theorem List (", - ((page == 0) - ? "Table of Contents" - : cat("p. ", str((double)page), " of ", str((double)pages), NULL)), - ")", - NULL), "", "\""); - - - /* Put Previous/Next links into web page */ - print2("
\n"); - - /* Output title with current page */ - /* Output previous and next */ - - - /* Assign prevNextLinks once here since it is used 3 times */ - let(&prevNextLinks, cat(" 0) - ? ((page - 1 > 0) ? str((double)page - 1) : "") - : ((pages > 0) ? str((double)pages) : ""), - ".html\">", NULL)); - if (page > 0) { - let(&prevNextLinks, cat(prevNextLinks, - "< Previous  ", NULL)); - } else { - let(&prevNextLinks, cat(prevNextLinks, "< Wrap  ", NULL)); - } - let(&prevNextLinks, cat(prevNextLinks, "", NULL)); - if (page < pages) { - let(&prevNextLinks, cat(prevNextLinks, "Next >", NULL)); - } else { - let(&prevNextLinks, cat(prevNextLinks, "Wrap >", NULL)); - } - - printLongLine(prevNextLinks, - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - - /* Finish up header */ - /* Print the GIF/Unicode Font choice, if directories are specified */ - if (htmlDir[0]) { - if (g_altHtmlFlag) { - print2("
Bad symbols? Try the\n"); - print2("
GIF\n", htmlDir, outputFileName); - print2("version.
Browser slow? Try the\n"); - print2("
Unicode\n", altHtmlDir, outputFileName); - print2("version.
\n"); - print2("
\n"); /* Add a little more vertical space */ - - /* Print some useful links */ - print2("Mirrors\n"); - print2(" > \n"); - print2("Metamath Home Page\n"); - - /* Normally, g_htmlBibliography in the .mm file will have the - project home page, and we depend on this here rather than - extracting from g_htmlHome */ - print2(" > \n", g_htmlBibliography); - - /* Put a meaningful abbreviation for the project home page - by extracting capital letters from title */ - let(&str1, ""); - s = (long)strlen(htmlTitle); - for (i = 0; i < s; i++) { - if (htmlTitle[i] >= 'A' && htmlTitle[i] <= 'Z') { - let(&str1, cat(str1, chr(htmlTitle[i]), NULL)); - } - } - print2("%s Home Page\n", str1); - - if (page != 0) { - print2(" > \n"); - print2("Theorem List Contents\n"); - } else { - print2(" > \n"); - print2("Theorem List Contents\n"); - } - - /* Assume there is a Most Recent page when the .mm has a mathbox stmt - (currently set.mm and iset.mm) */ - if (g_mathboxStmt < g_statements + 1) { - print2(" > \n"); - print2("Recent Proofs\n"); - } - - - print2("      \n", GREEN_TITLE_COLOR); - print2("This page: \n"); - - if (page == 0) { - print2(" Detailed Table of Contents \n"); - } - - print2("Page List\n"); - - /* Change breadcrumb font to match other pages */ - print2("
\n"); - print2("
\n"); - - print2("
\n"); - - /* Write out HTML page so far */ - fprintf(outputFilePtr, "%s", g_printString); - g_outputToString = 0; - let(&g_printString, ""); - - /* Add table of contents to first WRITE THEOREM page */ - if (page == 0) { /* We're on ToC page */ - - /* Pass 1: table of contents summary; pass 2: detail */ - for (passNumber = 1; passNumber <= 2; passNumber++) { - g_outputToString = 1; - if (passNumber == 1) { - print2("

Table of Contents Summary
\n"); - } else { - print2("

Detailed Table of Contents
\n"); - print2("(* means the section header has a description)
\n"); - } - - fprintf(outputFilePtr, "%s", g_printString); - - g_outputToString = 0; - let(&g_printString, ""); - - let(&hugeHdr, ""); - let(&bigHdr, ""); - let(&smallHdr, ""); - let(&tinyHdr, ""); - let(&hugeHdrComment, ""); - let(&bigHdrComment, ""); - let(&smallHdrComment, ""); - let(&tinyHdrComment, ""); - partCntr = 0; /* Initialize counters */ - sectionCntr = 0; - subsectionCntr = 0; - subsubsectionCntr = 0; - for (stmt = 1; stmt <= g_statements; stmt++) { - /* Output the headers for $a and $p statements */ - if (g_Statement[stmt].type == p_ || g_Statement[stmt].type == a_) { - hdrCommentAnchorDone = 0; - getSectionHeadings(stmt, &hugeHdr, &bigHdr, &smallHdr, - &tinyHdr, - &hugeHdrComment, &bigHdrComment, &smallHdrComment, - &tinyHdrComment, - 0, /* fineResolution */ - 0 /* fullComment */); - if (hugeHdr[0] || bigHdr[0] || smallHdr[0] || tinyHdr[0]) { - /* Write to the table of contents */ - g_outputToString = 1; - i = ((g_Statement[stmt].pinkNumber - 1) / theoremsPerPage) - + 1; /* Page # */ - /* let(&str3, cat("mmtheorems", (i == 1) ? "" : str(i), ".html#", */ - /* Note that page 1 has no number after mmtheorems */ - let(&str3, cat("mmtheorems", str((double)i), ".html#", - /* g_Statement[stmt].labelName, NULL)); */ - "mm", str((double)(g_Statement[stmt].pinkNumber)), NULL)); - /* Link to page/location - no theorem can be named "mm*" */ - let(&str4, ""); - str4 = pinkHTML(stmt); - if (hugeHdr[0]) { - - /* Create part number */ - partCntr++; - sectionCntr = 0; - subsectionCntr = 0; - subsubsectionCntr = 0; - let(&hugeHdr, cat("PART ", str((double)partCntr), "  ", - hugeHdr, NULL)); - - /* Put an asterisk before the header if the header has a comment */ - if (hugeHdrComment[0] != 0 && passNumber == 2) { - let(&hdrCommentMarker, "*"); - if (hdrCommentAnchorDone == 0) { - let(&hdrCommentAnchor, cat( - "", - - /* "​" is a "zero-width" space to - workaround Chrome bug that jumps to wrong anchor. */ - "​", - - NULL)); - hdrCommentAnchorDone = 1; - } else { - let(&hdrCommentAnchor, ""); - } - } else { - let(&hdrCommentMarker, ""); - let(&hdrCommentAnchor, ""); - } - - printLongLine(cat( - /* In detailed section, add an anchor to reach it from - summary section */ - (passNumber == 2) ? - cat("", - /* "​" is a "zero-width" space to - workaround Chrome bug that jumps to wrong anchor. */ - "​", - NULL) : "", - - /* Add an anchor to the "sandbox" theorem - for use by mmrecent.html */ - /* We use "sandbox:bighdr" for both here and - below so that either huge or big header type could - be used to start mathbox sections */ - (stmt == g_mathboxStmt && bigHdr[0] == 0 - && passNumber == 1 /* Only in summary TOC */ - ) ? - /* Note the colon so it won't conflict w/ theorem - name anchor */ - /* "​" is a "zero-width" space to - workaround Chrome bug that jumps to wrong anchor. */ - "​" : "", - - hdrCommentAnchor, - "", - hdrCommentMarker, - hugeHdr, "", - "
", NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - if (passNumber == 2) { - /* Assign to array for use during theorem output */ - let((vstring *)(&pntrHugeHdr[stmt]), hugeHdr); - let((vstring *)(&pntrHugeHdrComment[stmt]), hugeHdrComment); - } - let(&hugeHdr, ""); - let(&hugeHdrComment, ""); - } - if (bigHdr[0]) { - - /* Create section number */ - sectionCntr++; - subsectionCntr = 0; - subsubsectionCntr = 0; - let(&bigHdr, cat(str((double)partCntr), ".", str((double)sectionCntr), - "  ", - bigHdr, NULL)); - - /* Put an asterisk before the header if the header has - a comment */ - if (bigHdrComment[0] != 0 && passNumber == 2) { - let(&hdrCommentMarker, "*"); - if (hdrCommentAnchorDone == 0) { - let(&hdrCommentAnchor, cat( - "", - - /* "​" is a "zero-width" space to - workaround Chrome bug that jumps to wrong anchor. */ - "​", - - NULL)); - hdrCommentAnchorDone = 1; - } else { - let(&hdrCommentAnchor, ""); - } - } else { - let(&hdrCommentMarker, ""); - let(&hdrCommentAnchor, ""); - } - - printLongLine(cat( - "      ", /* Indentation spacing */ - - /* In detailed section, add an anchor to reach it from - summary section */ - (passNumber == 2) ? - cat("", - - /* "​" is a "zero-width" space to - workaround Chrome bug that jumps to wrong anchor. */ - "​", - - NULL) - : "", - - /* Add an anchor to the "sandbox" theorem - for use by mmrecent.html */ - (stmt == g_mathboxStmt - && passNumber == 1 /* Only in summary TOC */ - ) ? - /* Note the colon so it won't conflict w/ theorem - name anchor */ - /* "​" is a "zero-width" space to - workaround Chrome bug that jumps to wrong anchor. */ - "​" : "", - hdrCommentAnchor, - "", - hdrCommentMarker, - bigHdr, "", - "
", NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - if (passNumber == 2) { - /* Assign to array for use during theorem list output */ - let((vstring *)(&pntrBigHdr[stmt]), bigHdr); - let((vstring *)(&pntrBigHdrComment[stmt]), bigHdrComment); - } - let(&bigHdr, ""); - let(&bigHdrComment, ""); - } - if (smallHdr[0] - && passNumber == 2) { /* Skip in pass 1 (summary) */ - - /* Create subsection number */ - subsectionCntr++; - subsubsectionCntr = 0; - let(&smallHdr, cat(str((double)partCntr), ".", - str((double)sectionCntr), - ".", str((double)subsectionCntr), "  ", - smallHdr, NULL)); - - /* Put an asterisk before the header if the header has - a comment */ - if (smallHdrComment[0] != 0 && passNumber == 2) { - let(&hdrCommentMarker, "*"); - if (hdrCommentAnchorDone == 0) { - let(&hdrCommentAnchor, cat("", - - /* "​" is a "zero-width" space to - workaround Chrome bug that jumps to wrong anchor. */ - "​", - - NULL)); - hdrCommentAnchorDone = 1; - } else { - let(&hdrCommentAnchor, ""); - } - } else { - let(&hdrCommentMarker, ""); - let(&hdrCommentAnchor, ""); - } - - printLongLine(cat("            ", - hdrCommentAnchor, - "", - hdrCommentMarker, - smallHdr, "", - "   ", - g_Statement[stmt].labelName, "", - str4, - "
", NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - /* Assign to array for use during theorem output */ - let((vstring *)(&pntrSmallHdr[stmt]), smallHdr); - let(&smallHdr, ""); - let((vstring *)(&pntrSmallHdrComment[stmt]), smallHdrComment); - let(&smallHdrComment, ""); - } - - if (tinyHdr[0] && passNumber == 2) { /* Skip in pass 1 (summary) */ - - /* Create subsection number */ - subsubsectionCntr++; - let(&tinyHdr, cat(str((double)partCntr), ".", - str((double)sectionCntr), - ".", str((double)subsectionCntr), - ".", str((double)subsubsectionCntr), "  ", - tinyHdr, NULL)); - - /* Put an asterisk before the header if the header has - a comment */ - if (tinyHdrComment[0] != 0 && passNumber == 2) { - let(&hdrCommentMarker, "*"); - if (hdrCommentAnchorDone == 0) { - let(&hdrCommentAnchor, cat(" ", - - /* "​" is a "zero-width" space to - workaround Chrome bug that jumps to wrong anchor. */ - "​", - - NULL)); - hdrCommentAnchorDone = 1; - } else { - let(&hdrCommentAnchor, ""); - } - } else { - let(&hdrCommentMarker, ""); - let(&hdrCommentAnchor, ""); - } - - printLongLine(cat( - "                  ", - hdrCommentAnchor, - "", - hdrCommentMarker, - tinyHdr, "", - "   ", - g_Statement[stmt].labelName, "", - str4, - "
", NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - /* Assign to array for use during theorem output */ - let((vstring *)(&pntrTinyHdr[stmt]), tinyHdr); - let(&tinyHdr, ""); - let((vstring *)(&pntrTinyHdrComment[stmt]), tinyHdrComment); - let(&tinyHdrComment, ""); - } - - fprintf(outputFilePtr, "%s", g_printString); - g_outputToString = 0; - let(&g_printString, ""); - } /* if huge or big or small or tiny header */ - } /* if $a or $p */ - } /* next stmt */ - /* 8-May-2015 nm Do we need the HR below? */ - fprintf(outputFilePtr, "
\n"); - - } /* next passNumber */ - - } /* if page 0 */ - /* End table of contents */ - - /* Just skip over instead of a big if indent */ - if (page == 0) goto SKIP_LIST; - - - /* Put in color key */ - g_outputToString = 1; - print2("\n"); - if (g_extHtmlStmt < g_mathboxStmt) { /* g_extHtmlStmt >= g_mathboxStmt in ql.mm */ - /* ?? Currently this is customized for set.mm only!! */ - print2("

\n"); - print2("

\n"); - print2("\n"); - print2("\n"); - print2("\n"); - print2("\n"); - print2("\n"); - print2("\n"); - - /* Hilbert Space Explorer */ - print2("\n"); - print2("\n"); - print2("\n"); - print2("\n"); - - - /* Mathbox stuff */ - print2("\n"); - print2("\n"); - print2("\n"); - print2("\n"); - - - print2("
Color key:     Metamath Proof Explorer\n"); - - let(&str3, ""); - if (g_Statement[g_extHtmlStmt].pinkNumber <= 0) bug(2332); - str3 = pinkRangeHTML(nmbrStmtNmbr[1], - nmbrStmtNmbr[g_Statement[g_extHtmlStmt].pinkNumber - 1]); - printLongLine(cat("
(", str3, ")", NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - - print2("
 \"Hilbert\n"); - print2(" Hilbert Space Explorer\n"); - - let(&str3, ""); - if (g_Statement[g_mathboxStmt].pinkNumber <= 0) bug(2333); - str3 = pinkRangeHTML(g_extHtmlStmt, - nmbrStmtNmbr[g_Statement[g_mathboxStmt].pinkNumber - 1]); - printLongLine(cat("
(", str3, ")", NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - - print2("
 \"Users'\n"); - print2(" Users' Mathboxes\n"); - - let(&str3, ""); - str3 = pinkRangeHTML(g_mathboxStmt, nmbrStmtNmbr[assertions]); - printLongLine(cat("
(", str3, ")", NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - - print2("
 
\n"); - } /* end if (g_extHtmlStmt < g_mathboxStmt) */ - - /* Write out HTML page so far */ - fprintf(outputFilePtr, "%s", g_printString); - g_outputToString = 0; - let(&g_printString, ""); - - - /* Write the main table header */ - g_outputToString = 1; - print2("\n"); - print2("

\n"); - print2("\n", htmlTitle); - let(&str3, ""); - if (page < 1) bug(2335); /* Page 0 ToC should have been skipped */ - str3 = pinkHTML(nmbrStmtNmbr[(page - 1) * theoremsPerPage + 1]); - let(&str3, right(str3, (long)strlen(PINK_NBSP) + 1)); /* Discard " " */ - let(&str4, ""); - str4 = pinkHTML((page < pages) ? - nmbrStmtNmbr[page * theoremsPerPage] : - nmbrStmtNmbr[assertions]); - let(&str4, right(str4, (long)strlen(PINK_NBSP) + 1)); /* Discard " " */ - printLongLine(cat("",NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - print2("\n"); - print2("\n"); - print2("\n"); - print2("\n"); - print2("\n"); - print2("\n"); - fprintf(outputFilePtr, "%s", g_printString); - g_outputToString = 0; - let(&g_printString, ""); - - /* Find the last assertion that will be printed on the page, so - we will know when a separator between theorems is not needed */ - lastAssertion = 0; - for (assertion = (page - 1) * theoremsPerPage + 1; - assertion <= page * theoremsPerPage; assertion++) { - if (assertion > assertions) break; /* We're beyond the end */ - - lastAssertion = assertion; - } - - /* Output theorems on the page */ - for (assertion = (page - 1) * theoremsPerPage + 1; - assertion <= page * theoremsPerPage; assertion++) { - if (assertion > assertions) break; /* We're beyond the end */ - - s = nmbrStmtNmbr[assertion]; /* Statement number */ - - /* Construct the statement type label */ - if (g_Statement[s].type == p_) { - let(&str1, "Theorem"); - } else if (!strcmp("ax-", left(g_Statement[s].labelName, 3))) { - let(&str1, "Axiom"); - } else if (!strcmp("df-", left(g_Statement[s].labelName, 3))) { - let(&str1, "Definition"); - } else { - let(&str1, "Syntax"); - } - - if (s == s + 0) goto skip_date; - /* OBSOLETE */ - /* Get the date in the comment section after the statement */ - let(&str1, space(g_Statement[s + 1].labelSectionLen)); - memcpy(str1, g_Statement[s + 1].labelSectionPtr, - (size_t)(g_Statement[s + 1].labelSectionLen)); - let(&str1, edit(str1, 2)); /* Discard spaces and tabs */ - i1 = instr(1, str1, "$(["); - i2 = instr(i1, str1, "]$)"); - if (i1 && i2) { - let(&str1, seg(str1, i1 + 3, i2 - 1)); - } else { - let(&str1, ""); - } - skip_date: - - let(&str3, ""); - str3 = getDescription(s); - let(&str4, ""); - str4 = pinkHTML(s); /* Get little pink number */ - /* Output the description comment */ - /* Break up long lines for text editors with printLongLine */ - let(&g_printString, ""); - g_outputToString = 1; - print2("\n"); /* Blank line for HTML source human readability */ - - /* Table of contents */ - if (((vstring)(pntrHugeHdr[s]))[0]) { /* There is a major part break */ - printLongLine(cat( - /* The header */ - ""); - - printLongLine(cat( - /* Separator row */ - "", - NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - } - if (((vstring)(pntrBigHdr[s]))[0]) { /* There is a major section break */ - printLongLine(cat( - /* The header */ - ""); - - printLongLine(cat( - /* Separator row */ - "", - NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - } - if (((vstring)(pntrSmallHdr[s]))[0]) { /* There is a minor sec break */ - printLongLine(cat( - /* The header */ - ""); - - printLongLine(cat( - /* Separator row */ - "", - NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - } - - if (((vstring)(pntrTinyHdr[s]))[0]) { /* There is a subsubsection break */ - printLongLine(cat( - /* The header */ - ""); - - printLongLine(cat( - /* Separator row */ - "", - NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - } - - printLongLine(cat( - (s < g_extHtmlStmt) - ? "" - : (s < g_mathboxStmt) - ? cat("", NULL) - : cat("", NULL), - "\n"); - } else { - /* Output the table row with the math content */ - printLongLine(cat("" - : (s < g_mathboxStmt) - ? cat(" BGCOLOR=", PURPLISH_BIBLIO_COLOR, ">", NULL) - : cat(" BGCOLOR=", SANDBOX_COLOR, ">", NULL), - "", NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - } - - g_outputToString = 0; - fprintf(outputFilePtr, "%s", g_printString); - let(&g_printString, ""); - - if (assertion != lastAssertion) { - /* Put separator row if not last theorem */ - g_outputToString = 1; - printLongLine(cat("", NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - g_outputToString = 0; - fprintf(outputFilePtr, "%s", g_printString); - let(&g_printString, ""); - } - } /* next assertion */ - - /* Output trailer */ - g_outputToString = 1; - print2("
Theorem List for ", htmlTitle, - " - ", str3, "-", str4, - "   *Has distinct variable group(s)" - "
TypeLabelDescription
Statement
 
", - "", /* Anchor for table of contents */ - (vstring)(pntrHugeHdr[s]), - "
", - NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - - /* The comment part of the header, if any */ - if (((vstring)(pntrHugeHdrComment[s]))[0]) { - - /* Open the table row */ - /* keep comment in same table cell */ - print2("%s\n", "

"); - - /* We are currently printing to g_printString to allow use of - printLongLine(); however, the rendering function - printTexComment uses g_printString internally, so we have to - flush the current g_printString and turn off g_outputToString mode - in order to call the rendering function printTexComment. */ - /* (Question: why do the calls to printTexComment for statement - descriptions, later, not need to flush the g_printString? Is the - flushing code here redundant?) */ - /* Clear out the g_printString output in prep for printTexComment */ - g_outputToString = 0; - fprintf(outputFilePtr, "%s", g_printString); - let(&g_printString, ""); - g_showStatement = s; /* For printTexComment */ - g_texFilePtr = outputFilePtr; /* For printTexComment */ - printTexComment( /* Sends result to g_texFilePtr */ - (vstring)(pntrHugeHdrComment[s]), - 0, /* 1 = htmlCenterFlag */ - PROCESS_EVERYTHING, /* actionBits */ - 1 /* 1 = fileCheck */); - g_texFilePtr = NULL; - g_outputToString = 1; /* Restore after printTexComment */ - } - - /* Close the table row */ - print2("%s\n", "

", - " 
", - "", /* Anchor for table of contents */ - (vstring)(pntrBigHdr[s]), - "
", - NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - - /* The comment part of the header, if any */ - if (((vstring)(pntrBigHdrComment[s]))[0]) { - - /* Open the table row */ - /* keep comment in same table cell */ - print2("%s\n", "

"); - - /* We are currently printing to g_printString to allow use of - printLongLine(); however, the rendering function - printTexComment uses g_printString internally, so we have to - flush the current g_printString and turn off g_outputToString mode - in order to call the rendering function printTexComment. */ - /* (Question: why do the calls to printTexComment for statement - descriptions, later, not need to flush the g_printString? Is the - flushing code here redundant?) */ - /* Clear out the g_printString output in prep for printTexComment */ - g_outputToString = 0; - fprintf(outputFilePtr, "%s", g_printString); - let(&g_printString, ""); - g_showStatement = s; /* For printTexComment */ - g_texFilePtr = outputFilePtr; /* For printTexComment */ - printTexComment( /* Sends result to g_texFilePtr */ - (vstring)(pntrBigHdrComment[s]), - 0, /* 1 = htmlCenterFlag */ - PROCESS_EVERYTHING, /* actionBits */ - 1 /* 1 = fileCheck */); - g_texFilePtr = NULL; - g_outputToString = 1; /* Restore after printTexComment */ - } - - /* Close the table row */ - print2("%s\n", "

", - " 
", - "", /* Anchor for table of contents */ - (vstring)(pntrSmallHdr[s]), - "
", - NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - - /* The comment part of the header, if any */ - if (((vstring)(pntrSmallHdrComment[s]))[0]) { - - /* Open the table row */ - /* keep comment in same table cell */ - print2("%s\n", "

"); - - /* We are currently printing to g_printString to allow use of - printLongLine(); however, the rendering function - printTexComment uses g_printString internally, so we have to - flush the current g_printString and turn off g_outputToString mode - in order to call the rendering function printTexComment. */ - /* (Question: why do the calls to printTexComment for statement - descriptions, later, not need to flush the g_printString? Is the - flushing code here redundant?) */ - /* Clear out the g_printString output in prep for printTexComment */ - g_outputToString = 0; - fprintf(outputFilePtr, "%s", g_printString); - let(&g_printString, ""); - g_showStatement = s; /* For printTexComment */ - g_texFilePtr = outputFilePtr; /* For printTexComment */ - printTexComment( /* Sends result to g_texFilePtr */ - (vstring)(pntrSmallHdrComment[s]), - 0, /* 1 = htmlCenterFlag */ - PROCESS_EVERYTHING, /* actionBits */ - 1 /* 1 = fileCheck */); - g_texFilePtr = NULL; - g_outputToString = 1; /* Restore after printTexComment */ - } - - /* Close the table row */ - print2("%s\n", "

", - " 
", - "", /* Anchor for table of contents */ - (vstring)(pntrTinyHdr[s]), - "
", - NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - - /* The comment part of the header, if any */ - if (((vstring)(pntrTinyHdrComment[s]))[0]) { - - /* Open the table row */ - /* keep comment in same table cell */ - print2("%s\n", "

"); - - /* We are currently printing to g_printString to allow use of - printLongLine(); however, the rendering function - printTexComment uses g_printString internally, so we have to - flush the current g_printString and turn off g_outputToString mode - in order to call the rendering function printTexComment. */ - /* (Question: why do the calls to printTexComment for statement - descriptions, later, not need to flush the g_printString? Is the - flushing code here redundant?) */ - /* Clear out the g_printString output in prep for printTexComment */ - g_outputToString = 0; - fprintf(outputFilePtr, "%s", g_printString); - let(&g_printString, ""); - g_showStatement = s; /* For printTexComment */ - g_texFilePtr = outputFilePtr; /* For printTexComment */ - printTexComment( /* Sends result to g_texFilePtr */ - (vstring)(pntrTinyHdrComment[s]), - 0, /* 1 = htmlCenterFlag */ - PROCESS_EVERYTHING, /* actionBits */ - 1 /* 1 = fileCheck */); - g_texFilePtr = NULL; - g_outputToString = 1; /* Restore after printTexComment */ - } - - /* Close the table row */ - print2("%s\n", "

", - " 
", /* IE breaks up the date */ - str1, /* Date */ - "", - g_Statement[s].labelName, "", - str4, - - /* Add asterisk if statement has distinct var groups */ - (nmbrLen(g_Statement[s].reqDisjVarsA) > 0) ? "*" : "", - - "", - /* Add anchor for hyperlinking to the table row */ - "", - - NULL), /* Description */ - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - - g_showStatement = s; /* For printTexComment */ - g_outputToString = 0; /* For printTexComment */ - g_texFilePtr = outputFilePtr; /* For printTexComment */ - printTexComment( /* Sends result to g_texFilePtr */ - str3, - 0, /* 1 = htmlCenterFlag */ - PROCESS_EVERYTHING, /* actionBits */ - 1 /* 1 = fileCheck */); - g_texFilePtr = NULL; - g_outputToString = 1; /* Restore after printTexComment */ - - /* Get HTML hypotheses => assertion */ - let(&str4, ""); - str4 = getTexOrHtmlHypAndAssertion(s); /* In mmwtex.c */ - - /* Suppress the math content of lemmas, which can - be very big and not interesting */ - if (!strcmp(left(str3, 10), "Lemma for ") && !showLemmas) { - /* Suppress the table row with the math content */ - print2(" [Auxiliary lemma - not displayed.]
", - str4, "
", - " 
\n"); - print2("\n"); - - SKIP_LIST: /* (skipped when page == 0) */ - g_outputToString = 1; /* To compensate for skipped assignment above */ - - - /* Put extra Prev/Next hyperlinks here for convenience */ - print2("\n", '%'); - print2(" \n"); - print2(" \n"); - print2(" \n"); - print2(" \n"); - print2(" \n"); - print2("
\n", '%'); - print2("  \n"); - print2("  \n"); - printLongLine(cat(" ", prevNextLinks, NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - print2("
\n"); - - - print2("
\n"); - - - g_outputToString = 0; - fprintf(outputFilePtr, "%s", g_printString); - let(&g_printString, ""); - - - fprintf(outputFilePtr, "\n"); - fprintf(outputFilePtr, "
\n"); - fprintf(outputFilePtr, "Page List\n"); - fprintf(outputFilePtr, "
\n"); - - - /* Output links to the other pages */ - fprintf(outputFilePtr, "Jump to page: \n"); - for (p = 0; p <= pages; p++) { - - /* Construct the pink number range */ - let(&str3, ""); - if (p > 0) { - str3 = pinkRangeHTML( - nmbrStmtNmbr[(p - 1) * theoremsPerPage + 1], - (p < pages) ? - nmbrStmtNmbr[p * theoremsPerPage] : - nmbrStmtNmbr[assertions]); - } - - if (p == page) { - /* Current page shouldn't have link to self */ - let(&str1, (p == 0) ? "Contents" : str((double)p)); - } else { - let(&str1, cat("" : ".html\">", */ - ".html\">", - - (p == 0) ? "Contents" : str((double)p), - "", NULL)); - } - let(&str1, cat(str1, PINK_NBSP, str3, NULL)); - fprintf(outputFilePtr, "%s\n", str1); - } - - - g_outputToString = 1; - print2("
\n"); - print2("\n", '%'); - print2(" \n"); - print2(" \n"); - print2(" \n"); - print2(" \n"); - print2(" \n"); - print2("
\n", '%'); - print2("  \n"); - print2(" \n"); - print2("Copyright terms:\n"); - print2("Public domain\n"); - print2(" \n"); - printLongLine(cat(" ", prevNextLinks, NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - print2("
\n"); - print2("\n"); - g_outputToString = 0; - fprintf(outputFilePtr, "%s", g_printString); - let(&g_printString, ""); - - /* Close file */ - fclose(outputFilePtr); - } /* next page */ - - TL_ABORT: - /* Deallocate memory */ - let(&str1, ""); - let(&str3, ""); - let(&str4, ""); - let(&prevNextLinks, ""); - let(&outputFileName, ""); - let(&hugeHdr, ""); - let(&bigHdr, ""); - let(&smallHdr, ""); - let(&tinyHdr, ""); - let(&hdrCommentMarker, ""); - for (i = 0; i <= g_statements; i++) let((vstring *)(&pntrHugeHdr[i]), ""); - pntrLet(&pntrHugeHdr, NULL_PNTRSTRING); - for (i = 0; i <= g_statements; i++) let((vstring *)(&pntrBigHdr[i]), ""); - pntrLet(&pntrBigHdr, NULL_PNTRSTRING); - for (i = 0; i <= g_statements; i++) let((vstring *)(&pntrSmallHdr[i]), ""); - pntrLet(&pntrSmallHdr, NULL_PNTRSTRING); - for (i = 0; i <= g_statements; i++) let((vstring *)(&pntrTinyHdr[i]), ""); - pntrLet(&pntrTinyHdr, NULL_PNTRSTRING); - -} /* writeTheoremList */ - - -/* This function extracts any section headers in the comment sections - prior to the label of statement stmt. If a huge (####...) header isn't - found, *hugeHdrTitle will be set to the empty string. - If a big (#*#*...) header isn't found (or isn't after the last huge header), - *bigHdrTitle will be set to the empty string. If a small - (=-=-...) header isn't found (or isn't after the last huge header or - the last big header), *smallHdrTitle will be set to the empty string. - In all 3 cases, only the last occurrence of a header is considered. - If a tiny - (-.-....) header isn't found (or isn't after the last huge header or - the last big header or the last small header), *tinyHdrTitle will be - set to the empty string. - In all 4 cases, only the last occurrence of a header is considered. */ -/* -20-Jun-2015 metamath Google group email: -https://groups.google.com/g/metamath/c/QE0lwg9f5Ho/m/J8ekl_lH1I8J - -There are 4 kinds of section headers, big (####...), medium (#*#*#*...), -small (=-=-=-), and tiny (-.-.-.). - -Call the collection of (outside-of-statement) comments between two -successive $a/$p statements (i.e. those statements that generate web -pages) a "header area". The algorithm scans the header area for the -_last_ header of each type (big, medium, small, tiny) and discards all -others. Then, if there is a medium and it appears before a big, the -medium is discarded. If there is a small and it appears before a big or -medium, the small is discarded. In other words, a maximum of one header -of each type is kept, in the order big, medium, small, and tiny. - -There are two reasons for doing this: (1) it disregards headers used -for other purposes such as the headers for the set.mm-specific -information at the top that is not of general interest and (2) it -ignores headers for empty sections; for example, a mathbox user might -have a bunch of headers for sections planned for the future, but we -ignore them if those sections are empty (no $a or $p in them). -*/ -/* Return 1 if error found, 0 otherwise */ -flag getSectionHeadings(long stmt, - vstring *hugeHdrTitle, - vstring *bigHdrTitle, - vstring *smallHdrTitle, - vstring *tinyHdrTitle, - vstring *hugeHdrComment, - vstring *bigHdrComment, - vstring *smallHdrComment, - vstring *tinyHdrComment, - flag fineResolution, - flag fullComment) { - - /* for table of contents */ - vstring labelStr = ""; - long pos, pos1, pos2, pos3, pos4; - flag errorFound = 0; - flag saveOutputToString; - - /* Print any error messages to screen */ - saveOutputToString = g_outputToString; /* To restore when returning */ - g_outputToString = 0; - - /* (This initialization seems to be done redundantly by caller elsewhere, - but for WRITE SOURCE ... / EXTRACT we need to do it explicitly.) */ - let(&(*hugeHdrTitle), ""); - let(&(*bigHdrTitle), ""); - let(&(*smallHdrTitle), ""); - let(&(*tinyHdrTitle), ""); - let(&(*hugeHdrComment), ""); - let(&(*bigHdrComment), ""); - let(&(*smallHdrComment), ""); - let(&(*tinyHdrComment), ""); - - /* We now process only $a or $p statements */ - if (fineResolution == 0) { - if (g_Statement[stmt].type != a_ && g_Statement[stmt].type != p_) bug(2340); - } - - /* Get header area between this statement and the statement after the - previous $a or $p statement */ - /* pos3 and pos4 are used temporarily here; not related to later use */ - if (fineResolution == 0) { - pos3 = g_Statement[stmt].headerStartStmt; /* Statement immediately after the - previous $a or $p statement (will be this statement if previous - statement is $a or $p) */ - } else { - pos3 = stmt; /* For WRITE SOURCE ... / EXTRACT, we want every statement - treated equally */ - } - if (pos3 == 0 || pos3 > stmt) bug(2241); - pos4 = (g_Statement[stmt].labelSectionPtr - - g_Statement[pos3].labelSectionPtr) - + g_Statement[stmt].labelSectionLen; /* Length of the header area */ - let(&labelStr, space(pos4)); - memcpy(labelStr, g_Statement[pos3].labelSectionPtr, - (size_t)(pos4)); - - pos = 0; - pos2 = 0; - while (1) { /* Find last "huge" header, if any */ - /* 4-Nov-2007 nm: Obviously, the match below will not work if the - $( line has a trailing space, which some editors might insert. - The symptom is a missing table of contents entry. But to detect - this (and for the #*#* and =-=- matches below) would take a little work - and perhaps slow things down, and I don't think it is worth it. I - put a note in HELP WRITE THEOREM_LIST. */ - pos1 = pos; - pos = instr(pos + 1, labelStr, "$(\n" HUGE_DECORATION); - - /* 23-May-2008 nm Tolerate one space after "$(", to handle case of - one space added to the end of each line with TOOLS to make global - label changes are easier (still a kludge; this should be made - white-space insensitive some day) */ - pos1 = instr(pos1 + 1, labelStr, "$( \n" HUGE_DECORATION); - if (pos1 > pos) pos = pos1; - - if (!pos) break; - if (pos) pos2 = pos; - } /* while(1) */ - if (pos2) { /* Extract "huge" header */ - pos1 = pos2; /* Save "$(" position */ - pos = instr(pos2 + 4, labelStr, "\n"); /* Get to end of #### line */ - pos2 = instr(pos + 1, labelStr, "\n"); /* Find end of title line */ - - /* Error check - can't have more than 1 title line */ - if (strcmp(mid(labelStr, pos2 + 1, 4), HUGE_DECORATION)) { - print2( - "?Warning: missing closing \"%s\" decoration above statement \"%s\".\n", - HUGE_DECORATION, g_Statement[stmt].labelName); - errorFound = 1; - } - - pos3 = instr(pos2 + 1, labelStr, "\n"); /* Get to end of 2nd #### line */ - while (labelStr[(pos3 - 1) + 1] == '\n') pos3++; /* Skip 1st blank lines */ - pos4 = instr(pos3, labelStr, "$)"); /* Get to end of title comment */ - if (fullComment == 0) { - let(&(*hugeHdrTitle), seg(labelStr, pos + 1, pos2 - 1)); - let(&(*hugeHdrTitle), edit((*hugeHdrTitle), 8 + 128)); - /* Trim leading, trailing sp */ - let(&(*hugeHdrComment), seg(labelStr, pos3 + 1, pos4 - 2)); - let(&(*hugeHdrComment), edit((*hugeHdrComment), 8 + 16384)); - /* Trim leading sp, trailing sp & lf */ - } else { - /* Put entire comment in hugeHdrTitle and hugeHdrComment for /EXTRACT */ - /* Search backwards for non-space or beginning of string: */ - pos = pos1; /* pos1 is the "$" in "$(" */ - pos--; - while (pos > 0) { - if (labelStr[pos - 1] != ' ' - && labelStr[pos - 1] != '\n') break; - pos--; - } - /* pos + 1 is the start of whitespace preceding "$(" */ - /* pos4 is the "$" in "$)" */ - /* pos3 is the \n after the 2nd decoration line */ - let(&(*hugeHdrTitle), seg(labelStr, pos + 1, pos3)); - let(&(*hugeHdrComment), seg(labelStr, pos3 + 1, pos4 + 1)); - } - } - /* pos = 0; */ /* Leave pos alone so that we start with "huge" header pos, - to ignore any earlier "tiny" or "small" or "big" header */ - pos2 = 0; - while (1) { /* Find last "big" header, if any */ - pos1 = pos; - pos = instr(pos + 1, labelStr, "$(\n" BIG_DECORATION); - pos1 = instr(pos1 + 1, labelStr, "$( \n" BIG_DECORATION); - if (pos1 > pos) pos = pos1; - - if (!pos) break; - if (pos) pos2 = pos; - } - if (pos2) { /* Extract "big" header */ - pos1 = pos2; /* Save "$(" position */ - pos = instr(pos2 + 4, labelStr, "\n"); /* Get to end of #*#* line */ - pos2 = instr(pos + 1, labelStr, "\n"); /* Find end of title line */ - - /* Error check - can't have more than 1 title line */ - if (strcmp(mid(labelStr, pos2 + 1, 4), BIG_DECORATION)) { - print2( - "?Warning: missing closing \"%s\" decoration above statement \"%s\".\n", - BIG_DECORATION, g_Statement[stmt].labelName); - errorFound = 1; - } - - pos3 = instr(pos2 + 1, labelStr, "\n"); /* Get to end of 2nd #*#* line */ - while (labelStr[(pos3 - 1) + 1] == '\n') pos3++; /* Skip 1st blank lines */ - pos4 = instr(pos3, labelStr, "$)"); /* Get to end of title comment */ - if (fullComment == 0) { - let(&(*bigHdrTitle), seg(labelStr, pos + 1, pos2 - 1)); - let(&(*bigHdrTitle), edit((*bigHdrTitle), 8 + 128)); - /* Trim leading, trailing sp */ - let(&(*bigHdrComment), seg(labelStr, pos3 + 1, pos4 - 2)); - let(&(*bigHdrComment), edit((*bigHdrComment), 8 + 16384)); - /* Trim leading sp, trailing sp & lf */ - } else { - /* Put entire comment in bigHdrTitle and bigHdrComment for /EXTRACT */ - /* Search backwards for non-space or beginning of string: */ - pos = pos1; /* pos1 is the "$" in "$(" */ - pos--; - while (pos > 0) { - if (labelStr[pos - 1] != ' ' - && labelStr[pos - 1] != '\n') break; - pos--; - } - /* pos + 1 is the start of whitespace preceding "$(" */ - /* pos4 is the "$" in "$)" */ - /* pos3 is the \n after the 2nd decoration line */ - let(&(*bigHdrTitle), seg(labelStr, pos + 1, pos3)); - let(&(*bigHdrComment), seg(labelStr, pos3 + 1, pos4 + 1)); - } - } - /* pos = 0; */ /* Leave pos alone so that we start with "big" header pos, - to ignore any earlier "tiny" or "small" header */ - pos2 = 0; - while (1) { /* Find last "small" header, if any */ - pos1 = pos; - pos = instr(pos + 1, labelStr, "$(\n" SMALL_DECORATION); - pos1 = instr(pos1 + 1, labelStr, "$( \n" SMALL_DECORATION); - if (pos1 > pos) pos = pos1; - - if (!pos) break; - if (pos) pos2 = pos; - } - if (pos2) { /* Extract "small" header */ - pos1 = pos2; /* Save "$(" position */ - pos = instr(pos2 + 4, labelStr, "\n"); /* Get to end of =-=- line */ - pos2 = instr(pos + 1, labelStr, "\n"); /* Find end of title line */ - - /* Error check - can't have more than 1 title line */ - if (strcmp(mid(labelStr, pos2 + 1, 4), SMALL_DECORATION)) { - print2( - "?Warning: missing closing \"%s\" decoration above statement \"%s\".\n", - SMALL_DECORATION, g_Statement[stmt].labelName); - errorFound = 1; - } - - pos3 = instr(pos2 + 1, labelStr, "\n"); /* Get to end of 2nd =-=- line */ - while (labelStr[(pos3 - 1) + 1] == '\n') pos3++; /* Skip 1st blank lines */ - pos4 = instr(pos3, labelStr, "$)"); /* Get to end of title comment */ - if (fullComment == 0) { - let(&(*smallHdrTitle), seg(labelStr, pos + 1, pos2 - 1)); - let(&(*smallHdrTitle), edit((*smallHdrTitle), 8 + 128)); - /* Trim leading, trailing sp */ - let(&(*smallHdrComment), seg(labelStr, pos3 + 1, pos4 - 2)); - let(&(*smallHdrComment), edit((*smallHdrComment), 8 + 16384)); - /* Trim leading sp, trailing sp & lf */ - } else { - /* Put entire comment in smallHdrTitle and smallHdrComment for /EXTRACT */ - /* Search backwards for non-space or beginning of string: */ - pos = pos1; /* pos1 is the "$" in "$(" */ - pos--; - while (pos > 0) { - if (labelStr[pos - 1] != ' ' - && labelStr[pos - 1] != '\n') break; - pos--; - } - /* pos + 1 is the start of whitespace preceding "$(" */ - /* pos4 is the "$" in "$)" */ - /* pos3 is the \n after the 2nd decoration line */ - let(&(*smallHdrTitle), seg(labelStr, pos + 1, pos3)); - let(&(*smallHdrComment), seg(labelStr, pos3 + 1, pos4 + 1)); - } - } - - /* pos = 0; */ /* Leave pos alone so that we start with "small" header pos, - to ignore any earlier "tiny" header */ - pos2 = 0; - while (1) { /* Find last "tiny" header, if any */ - pos1 = pos; - pos = instr(pos + 1, labelStr, "$(\n" TINY_DECORATION); - pos1 = instr(pos1 + 1, labelStr, "$( \n" TINY_DECORATION); - if (pos1 > pos) pos = pos1; - - if (!pos) break; - if (pos) pos2 = pos; - } - if (pos2) { /* Extract "tiny" header */ - pos1 = pos2; /* Save "$(" position */ - pos = instr(pos2 + 4, labelStr, "\n"); /* Get to end of -.-. line */ - pos2 = instr(pos + 1, labelStr, "\n"); /* Find end of title line */ - - /* Error check - can't have more than 1 title line */ - if (strcmp(mid(labelStr, pos2 + 1, 4), TINY_DECORATION)) { - print2( - "?Warning: missing closing \"%s\" decoration above statement \"%s\".\n", - TINY_DECORATION, g_Statement[stmt].labelName); - errorFound = 1; - } - - pos3 = instr(pos2 + 1, labelStr, "\n"); /* Get to end of 2nd -.-. line */ - while (labelStr[(pos3 - 1) + 1] == '\n') pos3++; /* Skip 1st blank lines */ - pos4 = instr(pos3, labelStr, "$)"); /* Get to end of title comment */ - if (fullComment == 0) { - let(&(*tinyHdrTitle), seg(labelStr, pos + 1, pos2 - 1)); - let(&(*tinyHdrTitle), edit((*tinyHdrTitle), 8 + 128)); - /* Trim leading, trailing sp */ - let(&(*tinyHdrComment), seg(labelStr, pos3 + 1, pos4 - 2)); - let(&(*tinyHdrComment), edit((*tinyHdrComment), 8 + 16384)); - /* Trim leading sp, trailing sp & lf */ - } else { - /* Put entire comment in tinyHdrTitle and tinyHdrComment for /EXTRACT */ - /* Search backwards for non-space or beginning of string: */ - pos = pos1; /* pos1 is the "$" in "$(" */ - pos--; - while (pos > 0) { - if (labelStr[pos - 1] != ' ' - && labelStr[pos - 1] != '\n') break; - pos--; - } - /* pos + 1 is the start of whitespace preceding "$(" */ - /* pos4 is the "$" in "$)" */ - /* pos3 is the \n after the 2nd decoration line */ - let(&(*tinyHdrTitle), seg(labelStr, pos + 1, pos3)); - let(&(*tinyHdrComment), seg(labelStr, pos3 + 1, pos4 + 1)); - } - } - - if (errorFound == 1) { - print2(" (Note that section titles may not be longer than one line.)\n"); - } - /* Restore output stream */ - g_outputToString = saveOutputToString; - - let(&labelStr, ""); /* Deallocate string memory */ - return errorFound; -} /* getSectionHeadings */ - - -/* Returns HTML for the pink number to print after the statement labels - in HTML output. (Note that "pink" means "rainbow colored" number now.) */ -/* Warning: The caller must deallocate the returned vstring (i.e. this - function cannot be used in let statements but must be assigned to - a local vstring for local deallocation) */ -vstring pinkHTML(long statemNum) -{ - long statemMap; - vstring htmlCode = ""; - vstring hexValue = ""; - - if (statemNum > 0) { - statemMap = g_Statement[statemNum].pinkNumber; - } else { - /* -1 means the label wasn't found */ - statemMap = -1; - } - - /* Note: we put "(future)" when the label wasn't found (an error message - was also generated previously) */ - - /* With style sheet and explicit color */ - let(&hexValue, ""); - hexValue = spectrumToRGB(statemMap, g_Statement[g_statements].pinkNumber); - let(&htmlCode, cat(PINK_NBSP, - "", - (statemMap != -1) ? str((double)statemMap) : "(future)", "", NULL)); - let(&hexValue, ""); - - return htmlCode; -} /* pinkHTML */ - - -/* Returns HTML for a range of pink numbers separated by a "-". */ -/* Warning: The caller must deallocate the returned vstring (i.e. this - function cannot be used in let statements but must be assigned to - a local vstring for local deallocation) */ -vstring pinkRangeHTML(long statemNum1, long statemNum2) { - vstring htmlCode = ""; - vstring str3 = ""; - vstring str4 = ""; - - /* Construct the HTML for a pink number range */ - let(&str3, ""); - str3 = pinkHTML(statemNum1); - let(&str3, right(str3, (long)strlen(PINK_NBSP) + 1)); /* Discard " " */ - let(&str4, ""); - str4 = pinkHTML(statemNum2); - let(&str4, right(str4, (long)strlen(PINK_NBSP) + 1)); /* Discard " " */ - let(&htmlCode, cat(str3, "-", str4, NULL)); - let(&str3, ""); /* Deallocate */ - let(&str4, ""); /* Deallocate */ - return htmlCode; -} /* pinkRangeHTML */ - - -/* This function converts a "spectrum" color (1 to maxColor) to an - RBG value in hex notation for HTML. The caller must deallocate the - returned vstring to prevent memory leaks. color = 1 (red) to maxColor - (violet). A special case is the color -1, which just returns black. */ -vstring spectrumToRGB(long color, long maxColor) { - vstring str1 = ""; - double fraction, fractionInPartition; - long j, red, green, blue, partition; -/* Change PARTITIONS whenever the table below has entries added or removed! */ -#define PARTITIONS 28 - static double redRef[PARTITIONS + 1]; /* Made these */ - static double greenRef[PARTITIONS + 1]; /* static for */ - static double blueRef[PARTITIONS + 1]; /* speedup */ - static long i = -1; /* below */ - - if (i > -1) goto SKIP_INIT; - i = -1; /* For safety */ - - /* Here, we use the maximum saturation possible for a fixed L*a*b color L - (lightness) value of 53, which corresponds to 50% gray scale. - Each pure color had either brightness reduced or saturation reduced, - as required, to achieve L = 53. - - An initial partition was formed from hues 0, 15, 30, ..., 345, then the - result was divided into 1000 subpartitions, and the new partitions were - determined by reselecting partition boundaries based on where their color - difference was distinguishable (i.e. could semi-comfortably read letters - of one color with the other as a background, on an LCD display). Some - human judgment was involved, and it is probably not completely uniform or - optimal. - - A Just Noticeable Difference (JND) algorithm for spacing might be more - accurate, especially if averaged over several subjects and different - monitors. I wrote a program for that - asking the user to identify a word - in one hue with an adjacent hue as a background, in order to score a - point - but it was taking too much time, and I decided life is too short. - I think this is "good enough" though, perhaps not even noticeably - non-optimum. - - The comment at the end of each line is the hue 0-360 mapped linearly - to 1-1043 (345 = 1000, i.e. "extreme" purple or almost red). Partitions - at the end can be commented out if we want to stop at violet instead of - almost wrapping around to red via the purples, in order to more accurately - emulate the color spectrum. Be sure to update the PARTITIONS constant - above if a partition is commented out, to avoid a bug trap. */ - i++; redRef[i] = 251; greenRef[i] = 0; blueRef[i] = 0; /* 1 */ - i++; redRef[i] = 247; greenRef[i] = 12; blueRef[i] = 0; /* 10 */ - i++; redRef[i] = 238; greenRef[i] = 44; blueRef[i] = 0; /* 34 */ - i++; redRef[i] = 222; greenRef[i] = 71; blueRef[i] = 0; /* 58 */ - i++; redRef[i] = 203; greenRef[i] = 89; blueRef[i] = 0; /* 79 */ - i++; redRef[i] = 178; greenRef[i] = 108; blueRef[i] = 0; /* 109 */ - i++; redRef[i] = 154; greenRef[i] = 122; blueRef[i] = 0; /* 140 */ - i++; redRef[i] = 127; greenRef[i] = 131; blueRef[i] = 0; /* 181 */ - i++; redRef[i] = 110; greenRef[i] = 136; blueRef[i] = 0; /* 208 */ - i++; redRef[i] = 86; greenRef[i] = 141; blueRef[i] = 0; /* 242 */ - i++; redRef[i] = 60; greenRef[i] = 144; blueRef[i] = 0; /* 276 */ - i++; redRef[i] = 30; greenRef[i] = 147; blueRef[i] = 0; /* 313 */ - i++; redRef[i] = 0; greenRef[i] = 148; blueRef[i] = 22; /* 375 */ - i++; redRef[i] = 0; greenRef[i] = 145; blueRef[i] = 61; /* 422 */ - i++; redRef[i] = 0; greenRef[i] = 145; blueRef[i] = 94; /* 462 */ - i++; redRef[i] = 0; greenRef[i] = 143; blueRef[i] = 127; /* 504 */ - i++; redRef[i] = 0; greenRef[i] = 140; blueRef[i] = 164; /* 545 */ - i++; redRef[i] = 0; greenRef[i] = 133; blueRef[i] = 218; /* 587 */ - i++; redRef[i] = 3; greenRef[i] = 127; blueRef[i] = 255; /* 612 */ - i++; redRef[i] = 71; greenRef[i] = 119; blueRef[i] = 255; /* 652 */ - i++; redRef[i] = 110; greenRef[i] = 109; blueRef[i] = 255; /* 698 */ - i++; redRef[i] = 137; greenRef[i] = 99; blueRef[i] = 255; /* 740 */ - i++; redRef[i] = 169; greenRef[i] = 78; blueRef[i] = 255; /* 786 */ - i++; redRef[i] = 186; greenRef[i] = 57; blueRef[i] = 255; /* 808 */ - i++; redRef[i] = 204; greenRef[i] = 33; blueRef[i] = 249; /* 834 */ - i++; redRef[i] = 213; greenRef[i] = 16; blueRef[i] = 235; /* 853 */ - i++; redRef[i] = 221; greenRef[i] = 0; blueRef[i] = 222; /* 870 */ - i++; redRef[i] = 233; greenRef[i] = 0; blueRef[i] = 172; /* 916 */ - i++; redRef[i] = 239; greenRef[i] = 0; blueRef[i] = 132; /* 948 */ - /*i++; redRef[i] = 242; greenRef[i] = 0; blueRef[i] = 98;*/ /* 973 */ - /*i++; redRef[i] = 244; greenRef[i] = 0; blueRef[i] = 62;*/ /* 1000 */ - - if (i != PARTITIONS) { /* Double-check future edits */ - print2("? %ld partitions but PARTITIONS = %ld\n", i, (long)PARTITIONS); - bug(2326); /* Don't go further to prevent out-of-range references */ - } - - SKIP_INIT: - if (color == -1) { - let(&str1, "000000"); /* Return black for "(future)" color for labels with - missing theorems in comments */ - return str1; - } - - if (color < 1 || color > maxColor) { - bug(2327); - } - fraction = (1.0 * ((double)color - 1)) / (double)maxColor; - /* Fractional position in "spectrum" */ - partition = (long)(PARTITIONS * fraction); /* Partition number (integer) */ - if (partition >= PARTITIONS) bug(2325); /* Roundoff error? */ - fractionInPartition = 1.0 * (fraction - (1.0 * (double)partition) / PARTITIONS) - * PARTITIONS; /* The fraction of this partition it covers */ - red = (long)(1.0 * (redRef[partition] + - fractionInPartition * - (redRef[partition + 1] - redRef[partition]))); - green = (long)(1.0 * (greenRef[partition] + - fractionInPartition * - (greenRef[partition + 1] - greenRef[partition]))); - blue = (long)(1.0 * (blueRef[partition] + - fractionInPartition * - (blueRef[partition + 1] - blueRef[partition]))); - /* debug */ - /* i=1;if (g_outputToString==0) {i=0;g_outputToString=1;} */ - /* print2("p%ldc%ld\n", partition, color); g_outputToString=i; */ - /*printf("red %ld green %ld blue %ld\n", red, green, blue);*/ - - if (red < 0 || green < 0 || blue < 0 - || red > 255 || green > 255 || blue > 255) { - print2("%ld %ld %ld\n", red, green, blue); - bug(2323); - } - let(&str1, " "); - j = sprintf(str1, "%02X%02X%02X", (unsigned int)red, (unsigned int)green, - (unsigned int)blue); - if (j != 6) bug(2324); - /* debug */ - /*printf("a \n", red, green, blue);*/ - return str1; -} /* spectrumToRGB */ - - -/* Returns the HTML code for GIFs (!g_altHtmlFlag) or Unicode (g_altHtmlFlag), - or LaTeX when !g_htmlFlag, for the math string (hypothesis or conclusion) that - is passed in. */ -/* Warning: The caller must deallocate the returned vstring. */ -vstring getTexLongMath(nmbrString *mathString, long statemNum) -{ - long pos; - vstring tex = ""; - vstring texLine = ""; - vstring lastTex = ""; - flag alphnew, alphold, unknownnew, unknownold; - - if (!g_texDefsRead) bug(2322); /* TeX defs were not read */ - let(&texLine, ""); - - let(&lastTex, ""); - for (pos = 0; pos < nmbrLen(mathString); pos++) { - let(&tex, ""); - tex = tokenToTex(g_MathToken[mathString[pos]].tokenName, statemNum); - /* tokenToTex allocates tex; we must deallocate it */ - if (!g_htmlFlag) { /* LaTeX */ - /* If this token and previous token begin with letter, add a thin - space between them */ - /* Also, anything not in table will have space added */ - alphnew = !!isalpha((unsigned char)(tex[0])); - unknownnew = 0; - if (!strcmp(left(tex, 10), "\\mbox{\\rm ")) { /* Token not in table */ - unknownnew = 1; - } - alphold = !!isalpha((unsigned char)(lastTex[0])); - unknownold = 0; - if (!strcmp(left(lastTex, 10), "\\mbox{\\rm ")) { /* Token not in table*/ - unknownold = 1; - } - /* Put thin space only between letters and/or unknowns */ - if ((alphold || unknownold) && (alphnew || unknownnew)) { - /* Put additional thin space between two letters */ - if (!g_oldTexFlag) { - let(&texLine, cat(texLine, "\\,", tex, " ", NULL)); - } else { - let(&texLine, cat(texLine, "\\m{\\,", tex, "}", NULL)); - } - } else { - if (!g_oldTexFlag) { - let(&texLine, cat(texLine, "", tex, " ", NULL)); - } else { - let(&texLine, cat(texLine, "\\m{", tex, "}", NULL)); - } - } - } else { /* HTML */ - - /* When we have something like "E. x e. om x = y", the lack of - space between om and x looks ugly in HTML. This kludge adds it in - for restricted quantifiers not followed by parenthesis, in order - to make the web page look a little nicer. E.g. onminex. */ - /* Note that the space is put between the pos-1 and the pos tokens */ - if (pos >=4) { - if (!strcmp(g_MathToken[mathString[pos - 2]].tokenName, "e.") - && (!strcmp(g_MathToken[mathString[pos - 4]].tokenName, "E.") - || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "A.") - || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "prod_") - || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "E*") - || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "iota_") - || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "Disj_") - || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "E!") - || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "sum_") - || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "X_") - || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "U_") - || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "|^|_")) - && strcmp(g_MathToken[mathString[pos]].tokenName, ")") - /* It also shouldn't be restricted _to_ an expression in parens. */ - && strcmp(g_MathToken[mathString[pos - 1]].tokenName, "(") - /* ...or restricted _to_ a union or intersection */ - && strcmp(g_MathToken[mathString[pos - 1]].tokenName, "U.") - && strcmp(g_MathToken[mathString[pos - 1]].tokenName, "|^|") - /* ...or restricted _to_ an expression in braces */ - && strcmp(g_MathToken[mathString[pos - 1]].tokenName, "{")) { - let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ - } - } - /* This one puts a space between the 2 x's in a case like - "E. x x = y". E.g. cla4egf */ - if (pos >=2) { - /* Match a token starting with a letter */ - if (isalpha((unsigned char)(g_MathToken[mathString[pos]].tokenName[0]))) { - /* and make sure its length is 1 */ - if (!(g_MathToken[mathString[pos]].tokenName[1])) { - - /* Make sure previous token is a letter also, to prevent unneeded - space in "ran ( A ..." (e.g. rncoeq, dfiun3g) */ - /* Match a token starting with a letter */ - if (isalpha((unsigned char)(g_MathToken[mathString[pos - 1]].tokenName[0]))) { - /* and make sure its length is 1 */ - if (!(g_MathToken[mathString[pos - 1]].tokenName[1])) { - - /* See if it's 1st letter in a quantified expression */ - if (!strcmp(g_MathToken[mathString[pos - 2]].tokenName, "E.") - || !strcmp(g_MathToken[mathString[pos - 2]].tokenName, "A.") - || !strcmp(g_MathToken[mathString[pos - 2]].tokenName, "F/") - || !strcmp(g_MathToken[mathString[pos - 2]].tokenName, "E!") - /* space btwn A,x in "E! x e. dom A x A y" */ - || !strcmp(g_MathToken[mathString[pos - 2]].tokenName, "ran") - || !strcmp(g_MathToken[mathString[pos - 2]].tokenName, "dom") - || !strcmp(g_MathToken[mathString[pos - 2]].tokenName, "E*")) { - let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ - } - } - } - } - } - } - /* This one puts a space after a letter followed by a word token - e.g. "A" and "suc" in "A. x e. U. A suc" in limuni2 */ - if (pos >= 1) { - /* See if the next token is "suc" */ - if (!strcmp(g_MathToken[mathString[pos]].tokenName, "suc")) { - /* Match a token starting with a letter for the current token */ - if (isalpha( - (unsigned char)(g_MathToken[mathString[pos - 1]].tokenName[0]))) { - /* and make sure its length is 1 */ - if (!(g_MathToken[mathString[pos - 1]].tokenName[1])) { - let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ - } - } - } - } - /* This one puts a space before any "-." that doesn't come after - a parentheses e.g. ax-6 has both cases */ - if (pos >=1) { - /* See if we have a non-parenthesis followed by not */ - if (strcmp(g_MathToken[mathString[pos - 1]].tokenName, "(") - && !strcmp(g_MathToken[mathString[pos]].tokenName, "-.")) { - let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ - } - } - /* This one puts a space between "S" and "(" in df-iso. */ - if (pos >=4) { - if (!strcmp(g_MathToken[mathString[pos - 4]].tokenName, "Isom") - && !strcmp(g_MathToken[mathString[pos - 2]].tokenName, ",") - && !strcmp(g_MathToken[mathString[pos]].tokenName, "(")) { - let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ - } - } - /* This one puts a space between "}" and "(" in funcnvuni proof. */ - if (pos >=1) { - /* See if we have "}" followed by "(" */ - if (!strcmp(g_MathToken[mathString[pos - 1]].tokenName, "}") - && !strcmp(g_MathToken[mathString[pos]].tokenName, "(")) { - let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ - } - } - /* This one puts a space between "}" and "{" in konigsberg proof. */ - if (pos >=1) { - /* See if we have "}" followed by "(" */ - if (!strcmp(g_MathToken[mathString[pos - 1]].tokenName, "}") - && !strcmp(g_MathToken[mathString[pos]].tokenName, "{")) { - let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ - } - } - - let(&texLine, cat(texLine, tex, NULL)); - } /* if !g_htmlFlag */ - let(&lastTex, tex); /* Save for next pass */ - } /* Next pos */ - - /*x Discard redundant white space to reduce HTML file size */ - let(&texLine, edit(texLine, 8 + 16 + 128)); - - /* Enclose math symbols in a span to be used for font selection */ - let(&texLine, cat( - (g_altHtmlFlag ? cat("", NULL) : ""), - texLine, - (g_altHtmlFlag ? "" : ""), NULL)); - - let(&tex, ""); - let(&lastTex, ""); - return texLine; -} /* getTexLongMath */ - - -/* Returns the TeX, or HTML code for GIFs (!g_altHtmlFlag) or Unicode - (g_altHtmlFlag), for a statement's hypotheses and assertion in the form - hyp & ... & hyp => assertion */ -/* Warning: The caller must deallocate the returned vstring (i.e. this - function cannot be used in let statements but must be assigned to - a local vstring for local deallocation) */ -vstring getTexOrHtmlHypAndAssertion(long statemNum) { - long reqHyps, essHyps, n; - nmbrString *nmbrTmpPtr; /* Pointer only; not allocated directly */ - vstring texOrHtmlCode = ""; - vstring str2 = ""; - /* Count the number of essential hypotheses essHyps */ - essHyps = 0; - reqHyps = nmbrLen(g_Statement[statemNum].reqHypList); - let(&texOrHtmlCode, ""); - for (n = 0; n < reqHyps; n++) { - if (g_Statement[g_Statement[statemNum].reqHypList[n]].type - == (char)e_) { - essHyps++; - if (texOrHtmlCode[0]) { /* Add '&' between hypotheses */ - if (!g_htmlFlag) { - /* Hard-coded for set.mm! */ - let(&texOrHtmlCode, cat(texOrHtmlCode, - "\\quad\\&\\quad " - ,NULL)); - } else { - if (g_altHtmlFlag) { - /* Hard-coded for set.mm! */ - let(&texOrHtmlCode, cat(texOrHtmlCode, - "", - "    &   ", - "", - NULL)); - } else { - /* Hard-coded for set.mm! */ - let(&texOrHtmlCode, cat(texOrHtmlCode, - "   &   " - ,NULL)); - } - } - } /* if texOrHtmlCode[0] */ - /* Construct HTML hypothesis */ - nmbrTmpPtr = g_Statement[g_Statement[statemNum].reqHypList[n]].mathString; - let(&str2, ""); - str2 = getTexLongMath(nmbrTmpPtr, statemNum); - let(&texOrHtmlCode, cat(texOrHtmlCode, str2, NULL)); - } - } - if (essHyps) { /* Add big arrow if there were hypotheses */ - if (!g_htmlFlag) { - /* Hard-coded for set.mm! */ - let(&texOrHtmlCode, cat(texOrHtmlCode, - "\\quad\\Rightarrow\\quad " - ,NULL)); - } else { - if (g_altHtmlFlag) { - /* Hard-coded for set.mm! */ - let(&texOrHtmlCode, cat(texOrHtmlCode, - /* sans-serif to work around FF3 bug that produces - huge character heights otherwise */ - "       ", - NULL)); - } else { - /* Hard-coded for set.mm! */ - let(&texOrHtmlCode, cat(texOrHtmlCode, - "   =>   ", - NULL)); - } - } - } - /* Construct TeX or HTML assertion */ - nmbrTmpPtr = g_Statement[statemNum].mathString; - let(&str2, ""); - str2 = getTexLongMath(nmbrTmpPtr, statemNum); - let(&texOrHtmlCode, cat(texOrHtmlCode, str2, NULL)); - - /* Deallocate memory */ - let(&str2, ""); - return texOrHtmlCode; -} /* getTexOrHtmlHypAndAssertion */ - - - - -/* Called by the WRITE BIBLIOGRPAHY command and also by VERIFY MARKUP - for error checking */ -/* Returns 0 if OK, 1 if warning(s), 2 if any error */ -flag writeBibliography(vstring bibFile, - vstring labelMatch, /* Normally "*" except when called by verifyMarkup() */ - flag errorsOnly, /* 1 = no output, just warning msgs if any */ - flag fileCheck) /* 1 = check missing external files (mmbiblio.html) */ -{ - flag errFlag; - FILE *list1_fp = NULL; - FILE *list2_fp = NULL; - long lines, p2, i, j, jend, k, l, m, n, p, q, s, pass1refs; - vstring str1 = "", str2 = "", str3 = "", str4 = "", newstr = "", oldstr = ""; - pntrString *pntrTmp = NULL_PNTRSTRING; - flag warnFlag; - - n = 0; /* Old gcc 4.6.3 wrongly says may be uninit ln 5506 */ - pass1refs = 0; /* gcc 4.5.3 wrongly says may be uninit */ - if (!fileCheck && errorsOnly == 0) { - bug(2336); /* If we aren't opening files, a non-error run can't work */ - } - - /* This utility builds the bibliographical cross-references to various - textbooks and updates the user-specified file normally called - mmbiblio.html. */ - warnFlag = 0; /* 1 means warning was found, 2 that error was found */ - errFlag = 0; /* Error flag to recover input file and to set return value 2 */ - if (fileCheck) { - list1_fp = fSafeOpen(bibFile, "r", 0/*noVersioningFlag*/); - if (list1_fp == NULL) { - /* Couldn't open it (error msg was provided)*/ - return 1; - } - if (errorsOnly == 0) { - fclose(list1_fp); - /* This will rename the input mmbiblio.html as mmbiblio.html~1 */ - list2_fp = fSafeOpen(bibFile, "w", 0/*noVersioningFlag*/); - if (list2_fp == NULL) { - /* Couldn't open it (error msg was provided)*/ - return 1; - } - /* Note: in older versions the "~1" string was OS-dependent, but we - don't support VAX or THINK C anymore... Anyway we reopen it - here with the renamed file in case the OS won't let us rename - an opened file during the fSafeOpen for write above. */ - list1_fp = fSafeOpen(cat(bibFile, "~1", NULL), "r", 0/*noVersioningFlag*/); - if (list1_fp == NULL) bug(2337); - } - } - if (!g_texDefsRead) { - g_htmlFlag = 1; - if (2/*error*/ == readTexDefs(errorsOnly, fileCheck)) { - errFlag = 2; /* Error flag to recover input file */ - goto BIB_ERROR; /* An error occurred */ - } - } - - /* Transfer the input file up to the special "" comment */ - if (fileCheck) { - while (1) { - if (!linput(list1_fp, NULL, &str1)) { - print2("?Error: Could not find \"\" line in input file \"%s\".\n", - bibFile); - errFlag = 2; /* Error flag to recover input file */ - break; - } - if (errorsOnly == 0) { - fprintf(list2_fp, "%s\n", str1); - } - if (!strcmp(str1, "")) break; - } - if (errFlag) goto BIB_ERROR; - } - - p2 = 1; /* Pass 1 or 2 flag */ - lines = 0; - while (1) { - - if (p2 == 2) { /* Pass 2 */ - /* Allocate memory for sorting */ - pntrLet(&pntrTmp, pntrSpace(lines)); - lines = 0; - } - - /* Scan all $a and $p statements */ - for (i = 1; i <= g_statements; i++) { - if (g_Statement[i].type != (char)p_ && - g_Statement[i].type != (char)a_) continue; - - /* Normally labelMatch is *, but may be more specific for - use by verifyMarkup() */ - if (!matchesList(g_Statement[i].labelName, labelMatch, '*', '?')) { - continue; - } - - /* Omit ...OLD (obsolete) and ...NEW (to be implemented) statements */ - if (instr(1, g_Statement[i].labelName, "NEW")) continue; - if (instr(1, g_Statement[i].labelName, "OLD")) continue; - let(&str1, ""); - str1 = getDescription(i); /* Get the statement's comment */ - if (!instr(1, str1, "[")) continue; - l = (signed)(strlen(str1)); - for (j = 0; j < l; j++) { - if (str1[j] == '\n') str1[j] = ' '; /* Change newlines to spaces */ - if (str1[j] == '\r') bug(2338); - } - let(&str1, edit(str1, 8 + 128 + 16)); /* Reduce & trim whitespace */ - - /* Clear out math symbols in backquotes to prevent false matches - to [reference] bracket */ - k = 0; /* Math symbol mode if 1 */ - l = (signed)(strlen(str1)); - for (j = 0; j < l - 1; j++) { - if (k == 0) { - if (str1[j] == '`') { - k = 1; /* Start of math mode */ - } - } else { /* In math mode */ - if (str1[j] == '`') { /* A backquote */ - if (str1[j + 1] == '`') { - /* It is an escaped backquote */ - str1[j] = ' '; - str1[j + 1] = ' '; - } else { - k = 0; /* End of math mode */ - } - } else { /* Not a backquote */ - str1[j] = ' '; /* Clear out the math mode part */ - } - } /* end if k == 0 */ - } /* next j */ - - /* Put spaces before page #s (up to 4 digits) for sorting */ - j = 0; - while (1) { - j = instr(j + 1, str1, " p. "); /* Heuristic - match " p. " */ - if (!j) break; - if (j) { - for (k = j + 4; k <= (signed)(strlen(str1)) + 1; k++) { - if (!isdigit((unsigned char)(str1[k - 1]))) { - let(&str1, cat(left(str1, j + 2), - space(4 - (k - (j + 4))), right(str1, j + 3), NULL)); - /* Add ### after page number as marker */ - let(&str1, cat(left(str1, j + 7), "###", right(str1, j + 8), - NULL)); - break; - } - } - } - } - /* Process any bibliographic references in comment */ - j = 0; - n = 0; - while (1) { - j = instr(j + 1, str1, "["); /* Find reference (not robust) */ - if (!j) break; - - /* Fix mmbiblio.html corruption caused by - "[Copying an angle]" in df-ibcg in - set.mm.2016-09-18-JB-mbox-cleanup */ - /* Skip if there is no trailing "]" */ - jend = instr(j, str1, "]"); - if (!jend) break; - /* Skip bracketed text with spaces */ - /* This is a somewhat ugly workaround that lets us tolerate user - comments in [...] is there is at least one space. - The printTexComment() above handles this case with the - "strcspn(bibTag, " \n\r\t\f")" above; here we just have to look - for space since we already reduced \n \t to space (\f is probably - overkill, and any \r's are removed during the READ command) */ - if (instr(1, seg(str1, j, jend), " ")) continue; - /* Skip escaped bracket "[[" */ - if (str1[j] == '[') { /* (j+1)th character in str1 */ - j++; /* Skip over 2nd "[" */ - continue; - } - if (!isalnum((unsigned char)(str1[j]))) continue; /* Not start of reference */ - n++; - /* Backtrack from [reference] to a starting keyword */ - m = 0; - let(&str2, edit(str1, 32)); /* to uppercase */ - - /* (The string search below is rather inefficient; maybe improve - the algorithm if speed becomes a problem.) */ - for (k = j - 1; k >= 1; k--) { - /* **IMPORTANT** Make sure to update mmhlpb.c HELP WRITE BIBLIOGRAPHY - if new items are added to this list. */ - if (0 - /* Put the most frequent ones first to speed up search; - TODO: count occurrences in mmbiblio.html to find optimal order */ - || !strcmp(mid(str2, k, (long)strlen("THEOREM")), "THEOREM") - || !strcmp(mid(str2, k, (long)strlen("EQUATION")), "EQUATION") - || !strcmp(mid(str2, k, (long)strlen("DEFINITION")), "DEFINITION") - || !strcmp(mid(str2, k, (long)strlen("LEMMA")), "LEMMA") - || !strcmp(mid(str2, k, (long)strlen("EXERCISE")), "EXERCISE") - || !strcmp(mid(str2, k, (long)strlen("AXIOM")), "AXIOM") - || !strcmp(mid(str2, k, (long)strlen("CLAIM")), "CLAIM") - || !strcmp(mid(str2, k, (long)strlen("CHAPTER")), "CHAPTER") - || !strcmp(mid(str2, k, (long)strlen("COMPARE")), "COMPARE") - || !strcmp(mid(str2, k, (long)strlen("CONDITION")), "CONDITION") - || !strcmp(mid(str2, k, (long)strlen("CONJECTURE")), "CONJECTURE") - || !strcmp(mid(str2, k, (long)strlen("COROLLARY")), "COROLLARY") - || !strcmp(mid(str2, k, (long)strlen("EXAMPLE")), "EXAMPLE") - || !strcmp(mid(str2, k, (long)strlen("FIGURE")), "FIGURE") - || !strcmp(mid(str2, k, (long)strlen("ITEM")), "ITEM") - || !strcmp(mid(str2, k, (long)strlen("LEMMAS")), "LEMMAS") - || !strcmp(mid(str2, k, (long)strlen("LINE")), "LINE") - || !strcmp(mid(str2, k, (long)strlen("LINES")), "LINES") - || !strcmp(mid(str2, k, (long)strlen("NOTATION")), "NOTATION") - || !strcmp(mid(str2, k, (long)strlen("NOTE")), "NOTE") - || !strcmp(mid(str2, k, (long)strlen("OBSERVATION")), "OBSERVATION") - || !strcmp(mid(str2, k, (long)strlen("PART")), "PART") - || !strcmp(mid(str2, k, (long)strlen("POSTULATE")), "POSTULATE") - || !strcmp(mid(str2, k, (long)strlen("PROBLEM")), "PROBLEM") - || !strcmp(mid(str2, k, (long)strlen("PROPERTY")), "PROPERTY") - || !strcmp(mid(str2, k, (long)strlen("PROPOSITION")), "PROPOSITION") - || !strcmp(mid(str2, k, (long)strlen("REMARK")), "REMARK") - || !strcmp(mid(str2, k, (long)strlen("RESULT")), "RESULT") - || !strcmp(mid(str2, k, (long)strlen("RULE")), "RULE") - || !strcmp(mid(str2, k, (long)strlen("SCHEME")), "SCHEME") - || !strcmp(mid(str2, k, (long)strlen("SECTION")), "SECTION") - || !strcmp(mid(str2, k, (long)strlen("PROOF")), "PROOF") - || !strcmp(mid(str2, k, (long)strlen("STATEMENT")), "STATEMENT") - || !strcmp(mid(str2, k, (long)strlen("CONCLUSION")), "CONCLUSION") - || !strcmp(mid(str2, k, (long)strlen("FACT")), "FACT") - || !strcmp(mid(str2, k, (long)strlen("INTRODUCTION")), "INTRODUCTION") - || !strcmp(mid(str2, k, (long)strlen("PARAGRAPH")), "PARAGRAPH") - || !strcmp(mid(str2, k, (long)strlen("SCOLIA")), "SCOLIA") - || !strcmp(mid(str2, k, (long)strlen("SCOLION")), "SCOLION") - || !strcmp(mid(str2, k, (long)strlen("SUBSECTION")), "SUBSECTION") - || !strcmp(mid(str2, k, (long)strlen("TABLE")), "TABLE") - ) { - m = k; - break; - } - let(&str3, ""); /* Clear tmp alloc stack created by "mid" */ - } - if (!m) { - if (p2 == 1) { - print2( - "?Warning: Bibliography keyword missing in comment for \"%s\".\n", - g_Statement[i].labelName); - print2( - " (See HELP WRITE BIBLIOGRAPHY for list of keywords.)\n"); - warnFlag = 1; - } - continue; /* Not a bib ref - ignore */ - } - /* m is at the start of a keyword */ - p = instr(m, str1, "["); /* Start of bibliography reference */ - q = instr(p, str1, "]"); /* End of bibliography reference */ - if (q == 0) { - if (p2 == 1) { - print2("?Warning: Bibliography reference not found in HTML file in \"%s\".\n", - g_Statement[i].labelName); - warnFlag = 1; - } - continue; /* Pretend it is not a bib ref - ignore */ - } - s = instr(q, str1, "###"); /* Page number marker */ - if (!s) { - if (p2 == 1) { - print2("?Warning: No page number after [] bib ref in \"%s\".\n", - g_Statement[i].labelName); - warnFlag = 1; - } - continue; /* No page number given - ignore */ - } - /* Now we have a real reference; increment reference count */ - lines++; - if (p2 == 1) continue; /* In 1st pass, we just count refs */ - - let(&str2, seg(str1, m, p - 1)); /* "Theorem #" */ - let(&str3, seg(str1, p + 1, q - 1)); /* "[bibref]" w/out [] */ - let(&str4, seg(str1, q + 1, s - 1)); /* " p. nnnn" */ - str2[0] = (char)(toupper((unsigned char)(str2[0]))); - /* Eliminate noise like "of" in "Theorem 1 of [bibref]" */ - for (k = (long)strlen(str2); k >=1; k--) { - if (0 - || !strcmp(mid(str2, k, (long)strlen(" of ")), " of ") - || !strcmp(mid(str2, k, (long)strlen(" in ")), " in ") - || !strcmp(mid(str2, k, (long)strlen(" from ")), " from ") - || !strcmp(mid(str2, k, (long)strlen(" on ")), " on ") - ) { - let(&str2, left(str2, k - 1)); - break; - } - let(&str2, str2); - } - - let(&newstr, ""); - newstr = pinkHTML(i); /* Get little pink number */ - let(&oldstr, cat( - /* Construct the sorting key */ - /* The space() helps Th. 9 sort before Th. 10 on same page */ - str3, " ", str4, space(20 - (long)strlen(str2)), str2, - "|||", /* ||| means end of sort key */ - /* Construct just the statement href for combining dup refs */ - "", g_Statement[i].labelName, "", - newstr, - "&&&", /* &&& means end of statement href */ - /* Construct actual HTML table row (without ending tag - so duplicate references can be added) */ - (i < g_extHtmlStmt) - ? "" - : (i < g_mathboxStmt) - ? cat("", NULL) - : cat("", NULL), - - "[", str3, "]", str4, - "", str2, "", g_Statement[i].labelName, "", - newstr, NULL)); - /* Put construction into string array for sorting */ - let((vstring *)(&pntrTmp[lines - 1]), oldstr); - } /* while(1) */ - } /* next i */ - - /* 'lines' should be the same in both passes */ - if (p2 == 1) { - pass1refs = lines; - } else { - if (pass1refs != lines) bug(2339); - } - - if (errorsOnly == 0 && p2 == 2) { - /* - print2("Pass %ld finished. %ld references were processed.\n", p2, lines); - */ - print2("%ld references were processed.\n", lines); - } - if (p2 == 2) break; - p2++; /* Increment from pass 1 to pass 2 */ - } /* while(1) */ - - /* Sort */ - g_qsortKey = ""; - qsort(pntrTmp, (size_t)lines, sizeof(void *), qsortStringCmp); - - /* Combine duplicate references */ - let(&str1, ""); /* Last biblio ref */ - for (i = 0; i < lines; i++) { - j = instr(1, (vstring)(pntrTmp[i]), "|||"); - let(&str2, left((vstring)(pntrTmp[i]), j - 1)); - if (!strcmp(str1, str2)) { - /* Combine last with this */ - k = instr(j, (vstring)(pntrTmp[i]), "&&&"); - /* Extract statement href */ - let(&str3, seg((vstring)(pntrTmp[i]), j + 3, k -1)); - let((vstring *)(&pntrTmp[i]), - cat((vstring)(pntrTmp[i - 1]), "  ", str3, NULL)); - let((vstring *)(&pntrTmp[i - 1]), ""); /* Clear previous line */ - } - let(&str1, str2); - } - - /* Write output */ - if (fileCheck && errorsOnly == 0) { - n = 0; /* Table rows written */ - for (i = 0; i < lines; i++) { - j = instr(1, (vstring)(pntrTmp[i]), "&&&"); - if (j) { /* Don't print blanked out combined lines */ - n++; - /* Take off prefixes and reduce spaces */ - let(&str1, edit(right((vstring)(pntrTmp[i]), j + 3), 16)); - j = 1; - /* Break up long lines for text editors */ - let(&g_printString, ""); - g_outputToString = 1; - printLongLine(cat(str1, "", NULL), - " ", /* Start continuation line with space */ - "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ - g_outputToString = 0; - fprintf(list2_fp, "%s", g_printString); - let(&g_printString, ""); - } - } - } - - - /* Discard the input file up to the special "" comment */ - if (fileCheck) { - while (1) { - if (!linput(list1_fp, NULL, &str1)) { - print2( - "?Error: Could not find \"\" line in input file \"%s\".\n", - bibFile); - errFlag = 2; /* Error flag to recover input file */ - break; - } - if (!strcmp(str1, "")) { - if (errorsOnly == 0) { - fprintf(list2_fp, "%s\n", str1); - } - break; - } - } - if (errFlag) goto BIB_ERROR; - } - - if (fileCheck && errorsOnly == 0) { - /* Transfer the rest of the input file */ - while (1) { - if (!linput(list1_fp, NULL, &str1)) { - break; - } - - /* Update the date stamp at the bottom of the HTML page. */ - /* This is just a nicety; no error check is done. */ - if (!strcmp("This page was last updated on ", left(str1, 30))) { - let(&str1, cat(left(str1, 30), date(), ".", NULL)); - } - - fprintf(list2_fp, "%s\n", str1); - } - - print2("%ld table rows were written.\n", n); - /* Deallocate string array */ - for (i = 0; i < lines; i++) let((vstring *)(&pntrTmp[i]), ""); - pntrLet(&pntrTmp,NULL_PNTRSTRING); - } - - - BIB_ERROR: - if (fileCheck) { - fclose(list1_fp); - if (errorsOnly == 0) { - fclose(list2_fp); - } - if (errorsOnly == 0) { - if (errFlag) { - /* Recover input files in case of error */ - remove(bibFile); /* Delete output file */ - rename(cat(bibFile, "~1", NULL), g_fullArg[2]); - /* Restore input file name */ - print2("?The file \"%s\" was not modified.\n", g_fullArg[2]); - } - } - } - if (errFlag == 2) warnFlag = 2; - return warnFlag; -} /* writeBibliography */ - - -/* Returns 1 if stmt1 and stmt2 are in different mathboxes, 0 if - they are in the same mathbox or if one of them is not in a mathbox. */ -flag inDiffMathboxes(long stmt1, long stmt2) { - long mbox1, mbox2; - mbox1 = getMathboxNum(stmt1); - mbox2 = getMathboxNum(stmt2); - if (mbox1 == 0 || mbox2 == 0) return 0; - if (mbox1 != mbox2) return 1; - return 0; -} - -/* Returns the user of the mathbox that a statement is in, or "" - if the statement is not in a mathbox. */ -/* Caller should NOT deallocate returned string (it points directly to - g_mathboxUser[] entry) */ -vstring getMathboxUser(long stmt) { - long mbox; - mbox = getMathboxNum(stmt); - if (mbox == 0) return ""; - return g_mathboxUser[mbox - 1]; -} - -/* Given a statement number, find out what mathbox it's in (numbered starting - at 1) mainly for error messages; if it's not in a mathbox, return 0. */ -/* We assume the number of mathboxes is small enough that a linear search - won't slow things too much. */ -long getMathboxNum(long stmt) { - long mbox; - assignMathboxInfo(); /* In case it's not yet initialized */ - for (mbox = 0; mbox < g_mathboxes; mbox++) { - if (stmt < g_mathboxStart[mbox]) break; - } - return mbox; -} /* getMathboxNum */ - - -/* Assign the global variable g_mathboxStmt, the statement number with the - label "mathbox", as well as g_mathboxes, g_mathboxStart[], g_mathboxEnd[], - and g_mathboxUser[]. For speed, we do the lookup only if it hasn't been - done yet. Note that the ERASE command (eraseSource()) should set - g_mathboxStmt to zero as well as deallocate the strings. */ -/* This function will just return if g_mathboxStmt is already nonzero. */ -#define MB_LABEL "mathbox" -void assignMathboxInfo(void) { - if (g_mathboxStmt == 0) { /* Look up "mathbox" label if it hasn't been */ - g_mathboxStmt = lookupLabel(MB_LABEL); - if (g_mathboxStmt == -1) { /* There are no mathboxes */ - g_mathboxStmt = g_statements + 1; /* Default beyond db end if none */ - g_mathboxes = 0; - } else { - /* Population mathbox information variables */ - g_mathboxes = getMathboxLoc(&g_mathboxStart, &g_mathboxEnd, - &g_mathboxUser); - } - } - return; -} /* assignMathboxInfo */ - - -/* Returns the number of mathboxes, while assigning start statement, end - statement, and mathbox name. */ -#define MB_TAG "Mathbox for " -long getMathboxLoc(nmbrString **mathboxStart, nmbrString **mathboxEnd, - pntrString **mathboxUser) { - long m, p, q, tagLen, stmt; - long mathboxes = 0; - vstring comment = ""; - vstring user = ""; - assignMathboxInfo(); /* Assign g_mathboxStmt */ - tagLen = (long)strlen(MB_TAG); - /* Ensure lists are initialized */ - if (pntrLen((pntrString *)(*mathboxUser)) != 0) bug(2347); - if (nmbrLen((nmbrString *)(*mathboxStart)) != 0) bug(2348); - if (nmbrLen((nmbrString *)(*mathboxEnd)) != 0) bug(2349); - for (stmt = g_mathboxStmt + 1; stmt <= g_statements; stmt++) { - /* Heuristic to match beginning of mathbox */ - let(&comment, left(g_Statement[stmt].labelSectionPtr, - g_Statement[stmt].labelSectionLen)); - p = 0; - /* This loop will skip empty mathboxes i.e. it will get the last - "Mathbox for " in the label section comment(s) */ - while (1) { - q = instr(p + 1, comment, MB_TAG); - if (q == 0) break; - p = q; /* Save last "Mathbox for " */ - } - if (p == 0) continue; /* No "Mathbox for " in this statement's comment */ - - /* Found a mathbox; assign user and start statement */ - mathboxes++; - q = instr(p, comment, "\n"); - if (q == 0) bug(2350); /* No end of line */ - let(&user, seg(comment, p + tagLen, q - 1)); - pntrLet(&(*mathboxUser), pntrAddElement(*mathboxUser)); - (*mathboxUser)[mathboxes - 1] = ""; - let((vstring *)(&((*mathboxUser)[mathboxes - 1])), user); - nmbrLet(&(*mathboxStart), nmbrAddElement(*mathboxStart, stmt)); - } /* next stmt */ - if (mathboxes == 0) goto RETURN_POINT; - /* Assign end statements */ - nmbrLet(&(*mathboxEnd), nmbrSpace(mathboxes)); /* Pre-allocate */ - for (m = 0; m < mathboxes - 1; m++) { - (*mathboxEnd)[m] = (*mathboxStart)[m + 1] - 1; - } - (*mathboxEnd)[mathboxes - 1] = g_statements; /* Assumed end of last mathbox */ - RETURN_POINT: - let(&comment, ""); - let(&user, ""); - return mathboxes; -} /* getMathboxLoc */ +/*****************************************************************************/ +/* Copyright (C) 2021 NORMAN MEGILL nm at alum.mit.edu */ +/* License terms: GNU General Public License */ +/*****************************************************************************/ +/*34567890123456 (79-character line to adjust editor window) 2345678901234567*/ + +/* This module processes LaTeX and HTML output. */ + +#include +#include +#include +#include +#include +#include +#include "mmvstr.h" +#include "mmdata.h" +#include "mminou.h" +#include "mmpars.h" /* For rawSourceError and mathSrchCmp and lookupLabel */ +#include "mmwtex.h" +#include "mmcmdl.h" /* For g_texFileName */ +#include "mmwsts.h" /* For MathML/STS */ + +/* All LaTeX and HTML definitions are taken from the source + file (read in the by READ... command). In the source file, there should + be a single comment $( ... $) containing the keyword $t. The definitions + start after the $t and end at the $). Between $t and $), the definition + source should exist. See the file set.mm for an example. */ + +flag g_oldTexFlag = 0; /* Use TeX macros in output (obsolete) */ + +flag g_htmlFlag = 0; /* HTML flag: 0 = TeX, 1 = HTML */ +flag g_altHtmlFlag = 0; /* Use "althtmldef" instead of "htmldef". This is + intended to allow the generation of pages with the Unicode font + instead of the individual GIF files. */ +/* 19-Jul-2017 tar Added for STS/MathML output */ +flag stsFlag = 0; /* STS output (for "structural typesetting") */ +vstring stsOutput = ""; /* output mode chosen for STS (follows STS flag) */ +vstring postProcess = ""; /* command to pipe the output into (used for MathJax prerendering) */ +flag g_briefHtmlFlag = 0; /* Output statement lists only, for statement display + in other HTML pages, such as the Proof Explorer home page */ +long g_extHtmlStmt = 0; /* At this statement and above, use the exthtmlxxx + variables for title, links, etc. This was put in to allow proper + generation of the Hilbert Space Explorer extension to the set.mm + database. */ + +/* Globals to hold mathbox information. They should be re-initialized + by the ERASE command (eraseSource()). g_mathboxStmt = 0 indicates + it and the other variables haven't been initialized. */ +long g_mathboxStmt = 0; /* At this statement and above, use SANDBOX_COLOR + background for theorem, mmrecent, & mmbiblio lists */ + /* 0 means it hasn't been looked up yet; g_statements + 1 means + there is no mathbox */ +long g_mathboxes = 0; /* # of mathboxes */ +/* The following 3 strings are 0-based e.g. g_mathboxStart[0] is for + mathbox #1 */ +nmbrString *g_mathboxStart = NULL_NMBRSTRING; /* Start stmt vs. mathbox # */ +nmbrString *g_mathboxEnd = NULL_NMBRSTRING; /* End stmt vs. mathbox # */ +pntrString *g_mathboxUser = NULL_PNTRSTRING; /* User name vs. mathbox # */ + +/* This is the list of characters causing the space before the opening "`" + in a math string in a comment to be removed for HTML output. */ +#define OPENING_PUNCTUATION "(['\"" +/* This is the list of characters causing the space after the closing "`" + in a math string in a comment to be removed for HTML output. */ +#define CLOSING_PUNCTUATION ".,;)?!:]'\"_-" + +/* Tex output file */ +FILE *g_texFilePtr = NULL; +flag g_texFileOpenFlag = 0; + +/* Global variables */ +flag g_texDefsRead = 0; +struct texDef_struct *g_TexDefs; + +/* Variables local to this module (except some $t variables) */ +long numSymbs; +#define DOLLAR_SUBST 2 + /* Substitute character for $ in converting to obsolete $l,$m,$n + comments - Use '$' instead of non-printable ASCII 2 for debugging */ + +/* Variables set by the language in the set.mm etc. $t statement */ +/* Some of these are global; see mmwtex.h */ +vstring g_htmlCSS = ""; /* Set by g_htmlCSS commands */ +vstring g_htmlFont = ""; /* Set by htmlfont commands */ +vstring g_htmlVarColor = ""; /* Set by htmlvarcolor commands */ +vstring htmlExtUrl = ""; /* Set by htmlexturl command */ +vstring htmlTitle = ""; /* Set by htmltitle command */ + vstring htmlTitleAbbr = ""; /* Extracted from htmlTitle */ +vstring g_htmlHome = ""; /* Set by htmlhome command */ + /* Future - assign these in the $t set.mm comment instead of g_htmlHome */ + vstring g_htmlHomeHREF = ""; /* Extracted from g_htmlHome */ + vstring g_htmlHomeIMG = ""; /* Extracted from g_htmlHome */ +vstring g_htmlBibliography = ""; /* Optional; set by htmlbibliography command */ +vstring extHtmlLabel = ""; /* Set by exthtmllabel command - where extHtml starts */ +vstring g_extHtmlTitle = ""; /* Set by exthtmltitle command (global!) */ + vstring g_extHtmlTitleAbbr = ""; /* Extracted from htmlTitle */ +vstring extHtmlHome = ""; /* Set by exthtmlhome command */ + /* Future - assign these in the $t set.mm comment instead of g_htmlHome */ + vstring extHtmlHomeHREF = ""; /* Extracted from extHtmlHome */ + vstring extHtmlHomeIMG = ""; /* Extracted from extHtmlHome */ +vstring extHtmlBibliography = ""; /* Optional; set by exthtmlbibliography command */ +vstring htmlDir = ""; /* Directory for GIF version, set by htmldir command */ +vstring altHtmlDir = ""; /* Directory for Unicode Font version, set by + althtmldir command */ + +/* Sandbox stuff */ +vstring sandboxHome = ""; + vstring sandboxHomeHREF = ""; /* Extracted from extHtmlHome */ + vstring sandboxHomeIMG = ""; /* Extracted from extHtmlHome */ +vstring sandboxTitle = ""; + vstring sandboxTitleAbbr = ""; + +/* Variables holding all HTML tags from bibiography pages */ +vstring g_htmlBibliographyTags = ""; +vstring extHtmlBibliographyTags = ""; + + +void eraseTexDefs(void) { + /* Deallocate the texdef/htmldef storage */ + long i; + if (g_texDefsRead) { /* If not (already deallocated or never allocated) */ + g_texDefsRead = 0; + + for (i = 0; i < numSymbs; i++) { /* Deallocate structure member i */ + let(&(g_TexDefs[i].tokenName), ""); + let(&(g_TexDefs[i].texEquiv), ""); + } + free(g_TexDefs); /* Deallocate the structure */ + } + return; +} /* eraseTexDefs */ + + +/* Returns 2 if there were severe parsing errors, 1 if there were warnings but + no errors, 0 if no errors or warnings */ +flag readTexDefs( + flag errorsOnly, /* 1 = suppress non-error messages */ + flag gifCheck /* 1 = check for missing GIFs */) +{ + + char *fileBuf; + char *startPtr; + long lineNumOffset = 0; + char *fbPtr; + char *tmpPtr; + char *tmpPtr2; + long charCount; + long i, j, k, p; + long lineNum; + long tokenLength; + char zapChar; + long cmd; + long parsePass; + vstring token = ""; + vstring partialToken = ""; + FILE *tmpFp; + static flag saveHtmlFlag = -1; /* -1 to force 1st read */ + static flag saveAltHtmlFlag = 1; /* -1 to force 1st read */ + flag warningFound = 0; /* 1 if a warning was found */ + char *dollarTStmtPtr = NULL; /* Pointer to label section of statement with + the $t comment */ + + /* bsearch returned values for use in error-checking */ + void *g_mathKeyPtr; /* bsearch returned value for math symbol lookup */ + void *texDefsPtr; /* For binary search */ + + if (saveHtmlFlag != g_htmlFlag || saveAltHtmlFlag != g_altHtmlFlag + || !g_texDefsRead) { + /* One or both changed - we need to erase and re-read */ + eraseTexDefs(); + saveHtmlFlag = g_htmlFlag; /* Save for next call to readTexDefs() */ + saveAltHtmlFlag = g_altHtmlFlag; /* Save for next call to readTexDefs() */ + if (g_htmlFlag == 0 /* Tex */ && g_altHtmlFlag == 1) { + bug(2301); /* Nonsensical combination */ + } + } else { + /* Nothing changed; don't need to read again */ + return 0; /* No errors */ + } + + /* Initial values below will be overridden if a user assignment exists in the + $t comment of the xxx.mm input file */ + let(&htmlTitle, "Metamath Test Page"); /* Set by htmltitle command in $t + comment */ + let(&g_htmlHome, cat("", + ",
+    ", + "Home", NULL)); + /* Set by htmlhome command in $t comment */ + + if (errorsOnly == 0) { + print2("Reading definitions from $t statement of %s...\n", g_input_fn); + } + + /* Find the comment with the $t */ + fileBuf = ""; /* This used to point to the input file buffer of an external + latex.def file; now it's from the xxx.mm $t comment, so we + make it a normal string */ + let(&fileBuf, ""); + /* Note that g_Statement[g_statements + 1] is a special (empty) statement whose + labelSection holds any comment after the last statement. */ + for (i = 1; i <= g_statements + 1; i++) { + /* We do low-level stuff on the xxx.mm input file buffer for speed */ + tmpPtr = g_Statement[i].labelSectionPtr; + j = g_Statement[i].labelSectionLen; + /* Note that for g_Statement[g_statements + 1], the lineNum is one plus the + number of lines in the file */ + if (!fileBuf[0]) lineNumOffset = g_Statement[i].lineNum; /* Save for later */ + /* (Don't save if we're in scan to end for double $t detection) */ + zapChar = tmpPtr[j]; /* Save the original character */ + tmpPtr[j] = 0; /* Create an end-of-string */ + if (instr(1, tmpPtr, "$t")) { + /* Found a $t comment */ + /* Make sure this isn't a second one in another statement */ + /* (A second one in the labelSection of one statement will trigger + an error below.) */ + if (fileBuf[0]) { + print2( + "?Error: There are two comments containing a $t keyword in \"%s\".\n", + g_input_fn); + let(&fileBuf, ""); + return 2; + } + let(&fileBuf, tmpPtr); + tmpPtr[j] = zapChar; + dollarTStmtPtr = g_Statement[i].labelSectionPtr; + /* break; */ /* Continue to end to detect double $t */ + } + tmpPtr[j] = zapChar; /* Restore the xxx.mm input file buffer */ + } /* next i */ + /* If the $t wasn't found, fileBuf will be "", causing error message below. */ + /* Compute line number offset of beginning of g_Statement[i].labelSection for + use in error messages */ + j = (long)strlen(fileBuf); + for (i = 0; i < j; i++) { + if (fileBuf[i] == '\n') lineNumOffset--; + } + + +#define LATEXDEF 1 +#define HTMLDEF 2 +#define HTMLVARCOLOR 3 +#define HTMLTITLE 4 +#define HTMLHOME 5 +#define ALTHTMLDEF 6 +#define EXTHTMLTITLE 7 +#define EXTHTMLHOME 8 +#define EXTHTMLLABEL 9 +#define HTMLDIR 10 +#define ALTHTMLDIR 11 +#define HTMLBIBLIOGRAPHY 12 +#define EXTHTMLBIBLIOGRAPHY 13 +#define HTMLCSS 14 +#define HTMLFONT 15 +#define HTMLEXTURL 16 + + startPtr = fileBuf; + + /* Find $t command */ + while (1) { + if (startPtr[0] == '$') { + if (startPtr[1] == 't') { + startPtr++; + break; + } + } + if (startPtr[0] == 0) break; + startPtr++; + } + if (startPtr[0] == 0) { + print2("?Error: There is no $t command in the file \"%s\".\n", g_input_fn); + print2( +"The file should have exactly one comment of the form $(...$t...$) with\n"); + print2("the LaTeX and HTML definitions between $t and $).\n"); + let(&fileBuf, ""); + return 2; + } + startPtr++; /* Move to 1st char after $t */ + + /* Search for the ending $) and zap the $) to be end-of-string */ + tmpPtr = startPtr; + while (1) { + if (tmpPtr[0] == '$') { + if (tmpPtr[1] == ')') { + break; + } + } + if (tmpPtr[0] == 0) break; + tmpPtr++; + } + if (tmpPtr[0] == 0) { + print2( + "?Error: There is no $) comment closure after the $t keyword in \"%s\".\n", + g_input_fn); + let(&fileBuf, ""); + return 2; + } + + /* Make sure there aren't two comments with $t commands */ + tmpPtr2 = tmpPtr; + while (1) { + if (tmpPtr2[0] == '$') { + if (tmpPtr2[1] == 't') { + print2( + "?Error: There are two comments containing a $t keyword in \"%s\".\n", + g_input_fn); + let(&fileBuf, ""); + return 2; + } + } + if (tmpPtr2[0] == 0) break; + tmpPtr2++; + } + + /* Force end of string at the $ in $) */ + tmpPtr[0] = '\n'; + tmpPtr[1] = 0; + + charCount = tmpPtr + 1 - fileBuf; /* For bugcheck */ + + for (parsePass = 1; parsePass <= 2; parsePass++) { + /* Pass 1 - Count the number of symbols defined and alloc g_TexDefs array */ + /* Pass 2 - Assign the texDefs array */ + numSymbs = 0; + fbPtr = startPtr; + + while (1) { + + /* Get next token */ + fbPtr = fbPtr + texDefWhiteSpaceLen(fbPtr); + tokenLength = texDefTokenLen(fbPtr); + + /* Process token - command */ + if (!tokenLength) break; /* End of file */ + zapChar = fbPtr[tokenLength]; /* Char to restore after zapping source */ + fbPtr[tokenLength] = 0; /* Create end of string */ + cmd = lookup(fbPtr, + "latexdef,htmldef,htmlvarcolor,htmltitle,htmlhome" + ",althtmldef,exthtmltitle,exthtmlhome,exthtmllabel,htmldir" + ",althtmldir,htmlbibliography,exthtmlbibliography" + ",htmlcss,htmlfont,htmlexturl" + ); + fbPtr[tokenLength] = zapChar; + if (cmd == 0) { + lineNum = lineNumOffset; + for (i = 0; i < (fbPtr - fileBuf); i++) { + if (fileBuf[i] == '\n') lineNum++; + } + rawSourceError(/*fileBuf*/g_sourcePtr, + /*fbPtr*/dollarTStmtPtr + (fbPtr - fileBuf), tokenLength, + cat("Expected \"latexdef\", \"htmldef\", \"htmlvarcolor\",", + " \"htmltitle\", \"htmlhome\", \"althtmldef\",", + " \"exthtmltitle\", \"exthtmlhome\", \"exthtmllabel\",", + " \"htmldir\", \"althtmldir\",", + " \"htmlbibliography\", \"exthtmlbibliography\",", + " \"htmlcss\", \"htmlfont\",", + " or \"htmlexturl\" here.", + NULL)); + let(&fileBuf, ""); + return 2; + } + fbPtr = fbPtr + tokenLength; + + if (cmd != HTMLVARCOLOR && cmd != HTMLTITLE && cmd != HTMLHOME + && cmd != EXTHTMLTITLE && cmd != EXTHTMLHOME && cmd != EXTHTMLLABEL + && cmd != HTMLDIR && cmd != ALTHTMLDIR + && cmd != HTMLBIBLIOGRAPHY && cmd != EXTHTMLBIBLIOGRAPHY + && cmd != HTMLCSS && cmd != HTMLFONT && cmd != HTMLEXTURL) { + /* Get next token - string in quotes */ + fbPtr = fbPtr + texDefWhiteSpaceLen(fbPtr); + tokenLength = texDefTokenLen(fbPtr); + + /* Process token - string in quotes */ + if (fbPtr[0] != '\"' && fbPtr[0] != '\'') { + if (!tokenLength) { /* Abnormal end-of-file */ + fbPtr--; /* Format for error message */ + tokenLength++; + } + lineNum = lineNumOffset; + for (i = 0; i < (fbPtr - fileBuf); i++) { + if (fileBuf[i] == '\n') lineNum++; + } + rawSourceError(/*fileBuf*/g_sourcePtr, + /*fbPtr*/dollarTStmtPtr + (fbPtr - fileBuf), + tokenLength, + "Expected a quoted string here."); + let(&fileBuf, ""); + return 2; + } + if (parsePass == 2) { + zapChar = fbPtr[tokenLength - 1]; /* Chr to restore after zapping src */ + fbPtr[tokenLength - 1] = 0; /* Create end of string */ + let(&token, fbPtr + 1); /* Get ASCII token; note that leading and + trailing quotes are omitted. */ + fbPtr[tokenLength - 1] = zapChar; + + /* Change double internal quotes to single quotes */ + /* Do this only for double quotes matching the + outer quotes. fbPtr[0] is the quote character. */ + if (fbPtr[0] != '\"' && fbPtr[0] != '\'') bug(2329); + j = (long)strlen(token); + for (i = 0; i < j - 1; i++) { + if (token[i] == fbPtr[0] && + token[i + 1] == fbPtr[0]) { + let(&token, cat(left(token, + i + 1), right(token, i + 3), NULL)); + j--; + } + } + + if ((cmd == LATEXDEF && !g_htmlFlag) + || (cmd == HTMLDEF && g_htmlFlag && !g_altHtmlFlag) + || (cmd == ALTHTMLDEF && g_htmlFlag && g_altHtmlFlag)) { + g_TexDefs[numSymbs].tokenName = ""; + let(&(g_TexDefs[numSymbs].tokenName), token); + } + } /* if (parsePass == 2) */ + + fbPtr = fbPtr + tokenLength; + } /* if (cmd != HTMLVARCOLOR && cmd != HTMLTITLE && cmd != HTMLHOME...) */ + + if (cmd != HTMLVARCOLOR && cmd != HTMLTITLE && cmd != HTMLHOME + && cmd != EXTHTMLTITLE && cmd != EXTHTMLHOME && cmd != EXTHTMLLABEL + && cmd != HTMLDIR && cmd != ALTHTMLDIR + && cmd != HTMLBIBLIOGRAPHY && cmd != EXTHTMLBIBLIOGRAPHY + && cmd != HTMLCSS && cmd != HTMLFONT && cmd != HTMLEXTURL) { + /* Get next token -- "as" */ + fbPtr = fbPtr + texDefWhiteSpaceLen(fbPtr); + tokenLength = texDefTokenLen(fbPtr); + zapChar = fbPtr[tokenLength]; /* Char to restore after zapping source */ + fbPtr[tokenLength] = 0; /* Create end of string */ + if (strcmp(fbPtr, "as")) { + if (!tokenLength) { /* Abnormal end-of-file */ + fbPtr--; /* Format for error message */ + tokenLength++; + } + lineNum = lineNumOffset; + for (i = 0; i < (fbPtr - fileBuf); i++) { + if (fileBuf[i] == '\n') lineNum++; + } + rawSourceError(/*fileBuf*/g_sourcePtr, + /*fbPtr*/dollarTStmtPtr + (fbPtr - fileBuf), + tokenLength, + "Expected the keyword \"as\" here."); + let(&fileBuf, ""); + return 2; + } + fbPtr[tokenLength] = zapChar; + fbPtr = fbPtr + tokenLength; + } /* if (cmd != HTMLVARCOLOR && ... */ + + if (parsePass == 2) { + /* Initialize LaTeX/HTML equivalent */ + let(&token, ""); + } + + /* Scan "" + "" + ... until ";" found */ + while (1) { + + /* Get next token - string in quotes */ + fbPtr = fbPtr + texDefWhiteSpaceLen(fbPtr); + tokenLength = texDefTokenLen(fbPtr); + if (fbPtr[0] != '\"' && fbPtr[0] != '\'') { + if (!tokenLength) { /* Abnormal end-of-file */ + fbPtr--; /* Format for error message */ + tokenLength++; + } + lineNum = lineNumOffset; + for (i = 0; i < (fbPtr - fileBuf); i++) { + if (fileBuf[i] == '\n') lineNum++; + } + rawSourceError(/*fileBuf*/g_sourcePtr, + /*fbPtr*/dollarTStmtPtr + (fbPtr - fileBuf), + tokenLength, + "Expected a quoted string here."); + let(&fileBuf, ""); + return 2; + } + if (parsePass == 2) { + zapChar = fbPtr[tokenLength - 1]; /* Chr to restore after zapping src */ + fbPtr[tokenLength - 1] = 0; /* Create end of string */ + let(&partialToken, fbPtr + 1); /* Get ASCII token; note that leading + and trailing quotes are omitted. */ + fbPtr[tokenLength - 1] = zapChar; + + /* Change double internal quotes to single quotes */ + /* Do this only for double quotes matching the + outer quotes. fbPtr[0] is the quote character. */ + if (fbPtr[0] != '\"' && fbPtr[0] != '\'') bug(2330); + j = (long)strlen(partialToken); + for (i = 0; i < j - 1; i++) { + if (token[i] == fbPtr[0] && + token[i + 1] == fbPtr[0]) { + let(&partialToken, cat(left(partialToken, + i + 1), right(token, i + 3), NULL)); + j--; + } + } + + /* Check that string is on a single line */ + tmpPtr2 = strchr(partialToken, '\n'); + if (tmpPtr2 != NULL) { + lineNum = lineNumOffset; + for (i = 0; i < (fbPtr - fileBuf); i++) { + if (fileBuf[i] == '\n') lineNum++; + } + + rawSourceError(/*fileBuf*/g_sourcePtr, + /*fbPtr*/dollarTStmtPtr + (fbPtr - fileBuf), + tmpPtr2 - partialToken + 1 /*tokenLength on current line*/, + "String should be on a single line."); + } + + /* Combine the string part to the main token we're building */ + let(&token, cat(token, partialToken, NULL)); + + } /* (parsePass == 2) */ + + fbPtr = fbPtr + tokenLength; + + + /* Get next token - "+" or ";" */ + fbPtr = fbPtr + texDefWhiteSpaceLen(fbPtr); + tokenLength = texDefTokenLen(fbPtr); + if ((fbPtr[0] != '+' && fbPtr[0] != ';') || tokenLength != 1) { + if (!tokenLength) { /* Abnormal end-of-file */ + fbPtr--; /* Format for error message */ + tokenLength++; + } + lineNum = lineNumOffset; + for (i = 0; i < (fbPtr - fileBuf); i++) { + if (fileBuf[i] == '\n') { + lineNum++; + } + } + rawSourceError(/*fileBuf*/g_sourcePtr, + /*fbPtr*/dollarTStmtPtr + (fbPtr - fileBuf), + tokenLength, /*lineNum, g_input_fn,*/ + "Expected \"+\" or \";\" here."); + let(&fileBuf, ""); + return 2; + } + fbPtr = fbPtr + tokenLength; + + if (fbPtr[-1] == ';') break; + + } /* End while */ + + + if (parsePass == 2) { + if ((cmd == LATEXDEF && !g_htmlFlag) + || (cmd == HTMLDEF && g_htmlFlag && !g_altHtmlFlag) + || (cmd == ALTHTMLDEF && g_htmlFlag && g_altHtmlFlag)) { + g_TexDefs[numSymbs].texEquiv = ""; + let(&(g_TexDefs[numSymbs].texEquiv), token); + } + if (cmd == HTMLVARCOLOR) { + let(&g_htmlVarColor, cat(g_htmlVarColor, " ", token, NULL)); + } + if (cmd == HTMLTITLE) { + let(&htmlTitle, token); + } + if (cmd == HTMLHOME) { + let(&g_htmlHome, token); + } + if (cmd == EXTHTMLTITLE) { + let(&g_extHtmlTitle, token); + } + if (cmd == EXTHTMLHOME) { + let(&extHtmlHome, token); + } + if (cmd == EXTHTMLLABEL) { + let(&extHtmlLabel, token); + } + if (cmd == HTMLDIR) { + let(&htmlDir, token); + } + if (cmd == ALTHTMLDIR) { + let(&altHtmlDir, token); + } + if (cmd == HTMLBIBLIOGRAPHY) { + let(&g_htmlBibliography, token); + } + if (cmd == EXTHTMLBIBLIOGRAPHY) { + let(&extHtmlBibliography, token); + } + if (cmd == HTMLCSS) { + let(&g_htmlCSS, token); + /* User's CSS */ + /* Convert characters "\n" to new line - maybe do for other fields too? */ + do { + p = instr(1, g_htmlCSS, "\\n"); + if (p != 0) { + let(&g_htmlCSS, cat(left(g_htmlCSS, p - 1), "\n", + right(g_htmlCSS, p + 2), NULL)); + } + } while (p != 0); + } + if (cmd == HTMLFONT) { + let(&g_htmlFont, token); + } + if (cmd == HTMLEXTURL) { + let(&htmlExtUrl, token); + } + } + + if ((cmd == LATEXDEF && !g_htmlFlag) + || (cmd == HTMLDEF && g_htmlFlag && !g_altHtmlFlag) + || (cmd == ALTHTMLDEF && g_htmlFlag && g_altHtmlFlag)) { + numSymbs++; + } + + } /* End while */ + + if (fbPtr != fileBuf + charCount) bug(2305); + + if (parsePass == 1 ) { + if (errorsOnly == 0) { + print2("%ld typesetting statements were read from \"%s\".\n", + numSymbs, g_input_fn); + } + g_TexDefs = malloc((size_t)numSymbs * sizeof(struct texDef_struct)); + if (!g_TexDefs) outOfMemory("#99 (TeX symbols)"); + } + + } /* next parsePass */ + + + /* Sort the tokens for later lookup */ + qsort(g_TexDefs, (size_t)numSymbs, sizeof(struct texDef_struct), texSortCmp); + + /* Check for duplicate definitions */ + for (i = 1; i < numSymbs; i++) { + if (!strcmp(g_TexDefs[i].tokenName, g_TexDefs[i - 1].tokenName)) { + printLongLine(cat("?Warning: Token ", g_TexDefs[i].tokenName, + " is defined more than once in ", + g_htmlFlag + ? (g_altHtmlFlag ? "an althtmldef" : "an htmldef") + : "a latexdef", + " statement.", NULL), + "", " "); + warningFound = 1; + } + } + + /* Check to make sure all definitions are for a real math token */ + for (i = 0; i < numSymbs; i++) { + /* Note: g_mathKey, g_mathTokens, and mathSrchCmp are assigned or defined + in mmpars.c. */ + g_mathKeyPtr = (void *)bsearch(g_TexDefs[i].tokenName, g_mathKey, + (size_t)g_mathTokens, sizeof(long), mathSrchCmp); + if (!g_mathKeyPtr) { + printLongLine(cat("?Warning: The token \"", g_TexDefs[i].tokenName, + "\", which was defined in ", + g_htmlFlag + ? (g_altHtmlFlag ? "an althtmldef" : "an htmldef") + : "a latexdef", + " statement, was not declared in any $v or $c statement.", NULL), + "", " "); + warningFound = 1; + } + } + + /* Check to make sure all math tokens have typesetting definitions */ + for (i = 0; i < g_mathTokens; i++) { + texDefsPtr = (void *)bsearch(g_MathToken[i].tokenName, g_TexDefs, + (size_t)numSymbs, sizeof(struct texDef_struct), texSrchCmp); + if (!texDefsPtr) { + printLongLine(cat("?Warning: The token \"", g_MathToken[i].tokenName, + "\", which was defined in a $v or $c statement, was not declared in ", + g_htmlFlag + ? (g_altHtmlFlag ? "an althtmldef" : "an htmldef") + : "a latexdef", + " statement.", NULL), + "", " "); + warningFound = 1; + } + } + + /* Check to make sure all GIFs are present */ + if (g_htmlFlag + && !stsFlag) { /* 22-Mar-2018 Added for STS */ + for (i = 0; i < numSymbs; i++) { + tmpPtr = g_TexDefs[i].texEquiv; + k = 0; + while (1) { + j = instr(k + 1, tmpPtr, "IMG SRC="); + /* Note that only an exact match with + "IMG SRC=" is currently handled */ + if (j == 0) break; + k = instr(j + 9, g_TexDefs[i].texEquiv, mid(tmpPtr, j + 8, 1)); + /* Get position of trailing quote */ + /* Future: use strchr instead of mid() + for efficiency? */ + let(&token, seg(tmpPtr, j + 9, k - 1)); /* Get name of .gif (.png) */ + if (k == 0) break; /* Future: we may want to issue "missing + trailing quote" warning */ + /* (We test k after the let() so that the temporary string stack + entry created by mid() is emptied and won't overflow */ + if (gifCheck) { + tmpFp = fopen(token, "r"); /* See if it exists */ + if (!tmpFp) { + printLongLine(cat("?Warning: The file \"", token, + "\", which is referenced in an htmldef", + " statement, was not found.", NULL), + "", " "); + warningFound = 1; + } else { + fclose(tmpFp); + } + } + } + } + } + + + /* Look up the extended database start label */ + if (extHtmlLabel[0]) { + for (i = 1; i <= g_statements; i++) { + if (!strcmp(extHtmlLabel, g_Statement[i].labelName)) break; + } + if (i > g_statements) { + printLongLine(cat("?Warning: There is no statement with label \"", + extHtmlLabel, + "\" (specified by exthtmllabel in the database source $t comment). ", + "Use SHOW LABELS for a list of valid labels.", NULL), "", " "); + warningFound = 1; + } + g_extHtmlStmt = i; + } else { + /* There is no extended database; set threshold to beyond end of db */ + g_extHtmlStmt = g_statements + 1; + } + + assignMathboxInfo(); + /* In case there is not extended (Hilbert Space Explorer) section, + but there is a sandbox section, make the extended section "empty". */ + if (g_extHtmlStmt == g_statements + 1) g_extHtmlStmt = g_mathboxStmt; + let(&sandboxHome, cat("", + "", + ",
+    ", + "Table of Contents", NULL)); + let(&sandboxHomeHREF, "mmtheorems.html#sandbox:bighdr"); + let(&sandboxHomeIMG, "_sandbox.gif"); + let(&sandboxTitleAbbr, "Users' Mathboxes"); + let(&sandboxTitle, "Users' Mathboxes"); + + /* Extract derived variables from the $t variables */ + /* (In the future, it might be better to do this directly in the $t.) */ + i = instr(1, g_htmlHome, "HREF=\"") + 5; + if (i == 5) { + printLongLine( + "?Warning: In the $t comment, htmlhome has no 'HREF=\"'.", "", " "); + warningFound = 1; + } + j = instr(i + 1, g_htmlHome, "\""); + let(&g_htmlHomeHREF, seg(g_htmlHome, i + 1, j - 1)); + i = instr(1, g_htmlHome, "IMG SRC=\"") + 8; + if (i == 8) { + printLongLine( + "?Warning: In the $t comment, htmlhome has no 'IMG SRC=\"'.", "", " "); + warningFound = 1; + } + j = instr(i + 1, g_htmlHome, "\""); + let(&g_htmlHomeIMG, seg(g_htmlHome, i + 1, j - 1)); + + + /* Compose abbreviated title from capital letters */ + j = (long)strlen(htmlTitle); + let(&htmlTitleAbbr, ""); + for (i = 1; i <= j; i++) { + if (htmlTitle[i - 1] >= 'A' && htmlTitle[i -1] <= 'Z') { + let(&htmlTitleAbbr, cat(htmlTitleAbbr, chr(htmlTitle[i - 1]), NULL)); + } + } + let(&htmlTitleAbbr, cat(htmlTitleAbbr, " Home", NULL)); + + if (g_extHtmlStmt < g_statements + 1 /* If extended section exists */ + && g_extHtmlStmt != g_mathboxStmt) { /* and is not an empty dummy section */ + i = instr(1, extHtmlHome, "HREF=\"") + 5; + if (i == 5) { + printLongLine( + "?Warning: In the $t comment, exthtmlhome has no 'HREF=\"'.", "", " "); + warningFound = 1; + } + j = instr(i + 1, extHtmlHome, "\""); + let(&extHtmlHomeHREF, seg(extHtmlHome, i + 1, j - 1)); + i = instr(1, extHtmlHome, "IMG SRC=\"") + 8; + if (i == 8) { + printLongLine( + "?Warning: In the $t comment, exthtmlhome has no 'IMG SRC=\"'.", "", " "); + warningFound = 1; + } + j = instr(i + 1, extHtmlHome, "\""); + let(&extHtmlHomeIMG, seg(extHtmlHome, i + 1, j - 1)); + /* Compose abbreviated title from capital letters */ + j = (long)strlen(g_extHtmlTitle); + let(&g_extHtmlTitleAbbr, ""); + for (i = 1; i <= j; i++) { + if (g_extHtmlTitle[i - 1] >= 'A' && g_extHtmlTitle[i -1] <= 'Z') { + let(&g_extHtmlTitleAbbr, cat(g_extHtmlTitleAbbr, + chr(g_extHtmlTitle[i - 1]), NULL)); + } + } + let(&g_extHtmlTitleAbbr, cat(g_extHtmlTitleAbbr, " Home", NULL)); + } + + + let(&token, ""); /* Deallocate */ + let(&partialToken, ""); /* Deallocate */ + let(&fileBuf, ""); + g_texDefsRead = 1; /* Set global flag that it's been read in */ + return warningFound; /* Return indicator that parsing passed (0) or + had warning(s) (1) */ + +} /* readTexDefs */ + +/* This function returns the length of the white space starting at ptr. + Comments are considered white space. ptr should point to the first character + of the white space. If ptr does not point to a white space character, 0 + is returned. If ptr points to a null character, 0 is returned. */ +long texDefWhiteSpaceLen(char *ptr) +{ + long i = 0; + char tmpchr; + char *ptr1; + while (1) { + tmpchr = ptr[i]; + if (!tmpchr) return i; /* End of string */ + if (isalnum((unsigned char)(tmpchr))) return i; /* Alphanumeric string */ + + if (tmpchr == '/') { /* Embedded c-style comment - used to ignore + comments inside of Metamath comment for LaTeX/HTML definitions */ + if (ptr[i + 1] == '*') { + while (1) { + ptr1 = strchr(ptr + i + 2, '*'); + if (!ptr1) { + return i + (long)strlen(&ptr[i]); /* Unterminated comment - goto EOF */ + } + if (ptr1[1] == '/') break; + i = ptr1 - ptr; + } + i = ptr1 - ptr + 2; + continue; + } else { + return i; + } + } + if (isgraph((unsigned char)tmpchr)) return i; + i++; + } + bug(2307); + return 0; /* Dummy return - never executed */ +} /* texDefWhiteSpaceLen */ + + +/* This function returns the length of the token (non-white-space) starting at + ptr. Comments are considered white space. ptr should point to the first + character of the token. If ptr points to a white space character, 0 + is returned. If ptr points to a null character, 0 is returned. If ptr + points to a quoted string, the quoted string is returned. A non-alphanumeric\ + characters ends a token and is a single token. */ +long texDefTokenLen(char *ptr) +{ + long i = 0; + char tmpchr; + char *ptr1; + tmpchr = ptr[i]; + if (tmpchr == '\"') { + while (1) { + ptr1 = strchr(ptr + i + 1, '\"'); + if (!ptr1) { + return i + (long)strlen(&ptr[i]); /* Unterminated quote - goto EOF */ + } + if (ptr1[1] != '\"') return ptr1 - ptr + 1; /* Double quote is literal */ + i = ptr1 - ptr + 1; + } + } + if (tmpchr == '\'') { + while (1) { + ptr1 = strchr(ptr + i + 1, '\''); + if (!ptr1) { + return i + (long)strlen(&ptr[i]); /* Unterminated quote - goto EOF */ + } + if (ptr1[1] != '\'') return ptr1 - ptr + 1; /* Double quote is literal */ + i = ptr1 - ptr + 1; + } + } + if (ispunct((unsigned char)tmpchr)) return 1; /* Single-char token */ + while (1) { + tmpchr = ptr[i]; + if (!isalnum((unsigned char)tmpchr)) return i; /* End of alphnum. token */ + i++; + } + bug(2308); + return 0; /* Dummy return - never executed */ +} /* texDefTokenLen */ + +/* Token comparison for qsort */ +int texSortCmp(const void *key1, const void *key2) +{ + /* Returns -1 if key1 < key2, 0 if equal, 1 if key1 > key2 */ + /* Note: ptr->fld == (*ptr).fld + str.fld == (&str)->fld */ + return strcmp(((struct texDef_struct *)key1)->tokenName, + ((struct texDef_struct *)key2)->tokenName); +} /* texSortCmp */ + + +/* Token comparison for bsearch */ +int texSrchCmp(const void *key, const void *data) +{ + /* Returns -1 if key < data, 0 if equal, 1 if key > data */ + return strcmp(key, + ((struct texDef_struct *)data)->tokenName); +} /* texSrchCmp */ + +/* Convert ascii to a string of \tt tex; must not have control chars */ +/* (The caller must surround it by {\tt }) */ +/* ***Note: The caller must deallocate returned string */ +vstring asciiToTt(vstring s) +{ + + vstring ttstr = ""; + vstring tmp = ""; + long i, j, k; + + let(&ttstr, s); /* In case the input s is temporarily allocated */ + j = (long)strlen(ttstr); + + /* Put special \tt font characters in a form that TeX can understand */ + for (i = 0; i < j; i++) { + k = 1; + if (!g_htmlFlag) { + switch (ttstr[i]) { + /* For all unspecified cases, TeX will accept the character 'as is' */ + case ' ': + case '$': + case '%': + case '#': + case '{': + case '}': + case '&': + let(&ttstr,cat(left(ttstr,i),"\\",right(ttstr,i+1),NULL)); + k = 2; + break; + case '^': + let(&ttstr,cat(left(ttstr,i),"\\^{ }",right(ttstr,i+2),NULL)); + k = 5; + break; + case '\\': + case '|': + case '<': + case '>': + case '"': + case '~': + case '_': + /* Note: this conversion will work for any character, but + results in the most TeX source code. */ + let(&ttstr,cat(left(ttstr,i),"\\char`\\",right(ttstr,i+1),NULL)); + k = 8; + break; + } /* End switch mtoken[i] */ + } else { + switch (ttstr[i]) { + /* For all unspecified cases, HTML will accept the character 'as is' */ + /* Don't convert to & but leave as is. This + will allow the user to insert HTML entities for Unicode etc. + directly in the database source. */ + /* case '&': ... */ + case '<': + /* Leave in HTML tags (case must match) */ + if (!strcmp(mid(ttstr, i + 1, 6), "")) { + let(&ttstr, ttstr); /* Purge stack to prevent overflow by 'mid' */ + i = i + 6; + break; + } + if (!strcmp(mid(ttstr, i + 1, 7), "")) { + let(&ttstr, ttstr); /* Purge stack to prevent overflow by 'mid' */ + i = i + 7; + break; + } + let(&ttstr,cat(left(ttstr,i),"<",right(ttstr,i+2),NULL)); + k = 4; + break; + case '>': + let(&ttstr,cat(left(ttstr,i),">",right(ttstr,i+2),NULL)); + k = 4; + break; + case '"': + let(&ttstr,cat(left(ttstr,i),""",right(ttstr,i+2),NULL)); + k = 6; + break; + } /* End switch mtoken[i] */ + } + + if (k > 1) { /* Adjust iteration and length */ + i = i + k - 1; + j = j + k - 1; + } + } /* Next i */ + + let(&tmp, ""); /* Deallocate */ + return ttstr; +} /* asciiToTt */ + + +/* Convert ascii token to TeX equivalent */ +/* The "$" math delimiter is not placed around the returned arg. here */ +/* *** Note: The caller must deallocate the returned string */ +vstring tokenToTex(vstring mtoken, long statemNum /*for error msgs*/) +{ + vstring tex = ""; + vstring tmpStr; + long i, j, k; + void *texDefsPtr; /* For binary search */ + flag saveOutputToString; + + if (!g_texDefsRead) { + bug(2320); /* This shouldn't be called if definitions weren't read */ + } + + texDefsPtr = (void *)bsearch(mtoken, g_TexDefs, (size_t)numSymbs, + sizeof(struct texDef_struct), texSrchCmp); + if (texDefsPtr) { /* Found it */ + let(&tex, ((struct texDef_struct *)texDefsPtr)->texEquiv); + } else { + /* If it wasn't found, give user a warning... */ + saveOutputToString = g_outputToString; + g_outputToString = 0; + /* It is possible for statemNum to be 0 when + tokenToTex() is called (via getTexLongMath()) from + printTexLongMath(), when its hypStmt argument is 0 (= not associated + with a statement). (Reported by Wolf Lammen.) */ + if (statemNum < 0 || statemNum > g_statements) bug(2331); + if (statemNum > 0) { /* Include statement label in error message */ + printLongLine(cat("?Warning: In the comment for statement \"", + g_Statement[statemNum].labelName, + "\", math symbol token \"", mtoken, + "\" does not have a LaTeX and/or an HTML definition.", NULL), + "", " "); + } else { /* There is no statement associated with the error message */ + printLongLine(cat("?Warning: Math symbol token \"", mtoken, + "\" does not have a LaTeX and/or an HTML definition.", NULL), + "", " "); + } + g_outputToString = saveOutputToString; + /* ... but we'll still leave in the old default conversion anyway: */ + + /* If it wasn't found, use built-in conversion rules */ + let(&tex, mtoken); + + /* First, see if it's a tilde followed by a letter */ + /* If so, remove the tilde. (This is actually obsolete.) */ + /* (The tilde was an escape in the obsolete syntax.) */ + if (tex[0] == '~') { + if (isalpha((unsigned char)(tex[1]))) { + let(&tex, right(tex, 2)); /* Remove tilde */ + } + } + + /* Next, convert punctuation characters to tt font */ + j = (long)strlen(tex); + for (i = 0; i < j; i++) { + if (ispunct((unsigned char)(tex[i]))) { + tmpStr = asciiToTt(chr(tex[i])); + if (!g_htmlFlag) + let(&tmpStr, cat("{\\tt ", tmpStr, "}", NULL)); + k = (long)strlen(tmpStr); + let(&tex, + cat(left(tex, i), tmpStr, right(tex, i + 2), NULL)); + i = i + k - 1; /* Adjust iteration */ + j = j + k - 1; /* Adjust length */ + let(&tmpStr, ""); /* Deallocate */ + } + } /* Next i */ + + /* Make all letters Roman; put inside mbox */ + if (!g_htmlFlag) + let(&tex, cat("\\mbox{\\rm ", tex, "}", NULL)); + + } /* End if */ + + return tex; +} /* tokenToTex */ + + +/* Converts a comment section in math mode to TeX. Each math token + MUST be separated by white space. TeX "$" does not surround the output. */ +vstring asciiMathToTex(vstring mathComment, long statemNum) +{ + /* 29-Sep-2017 Thierry Arnoux added for STS */ + if(stsFlag) { + return asciiToMathSts(mathComment, statemNum); + } else { + return asciiMathToTexNoSts(mathComment, statemNum); + } +} + +/* Converts a comment section in math mode to TeX. Each math token + MUST be separated by white space. TeX "$" does not surround the output. */ +vstring asciiMathToTexNoSts(vstring mathComment, long statemNum) +{ + + vstring tex; + vstring texLine = ""; + vstring lastTex = ""; + vstring token = ""; + flag alphnew, alphold, unknownnew, unknownold; + long i; + vstring srcptr; + + srcptr = mathComment; + + let(&texLine, ""); + let(&lastTex, ""); + while(1) { + i = whiteSpaceLen(srcptr); + srcptr = srcptr + i; + i = tokenLen(srcptr); + if (!i) break; /* Done */ + let(&token, space(i)); + memcpy(token, srcptr, (size_t)i); + srcptr = srcptr + i; + /* 27 Jul 2017 tar For MathML/STS */ + if(stsFlag) tex = stsToken(tokenId(token), statemNum); + else tex = tokenToTex(token, statemNum); /* Convert token to TeX */ + /* tokenToTex allocates tex; we must deallocate it */ + + if (!g_htmlFlag) { + /* If this token and previous token begin with letter, add a thin + space between them */ + /* Also, anything not in table will have space added */ + /* Use "!!" here and below because isalpha returns an integer, whose + unspecified non-zero value could be truncated to 0 when + converted to char. Thanks to Wolf Lammen for pointing this out. */ + alphnew = !!isalpha((unsigned char)(tex[0])); + unknownnew = 0; + if (!strcmp(left(tex, 10), "\\mbox{\\rm ")) { /* Token not in table */ + unknownnew = 1; + } + alphold = !!isalpha((unsigned char)(lastTex[0])); + unknownold = 0; + if (!strcmp(left(lastTex, 10), "\\mbox{\\rm ")) { /* Token not in table*/ + unknownold = 1; + } + /* Put thin space only between letters and/or unknowns */ + if ((alphold || unknownold) && (alphnew || unknownnew)) { + /* Put additional thin space between two letters */ + let(&texLine, cat(texLine, "\\,", tex, " ", NULL)); + } else { + let(&texLine, cat(texLine, tex, " ", NULL)); + } + } else { + let(&texLine, cat(texLine, tex, NULL)); + } + let(&lastTex, ""); /* Deallocate */ + lastTex = tex; /* Pass deallocation responsibility for tex to lastTex */ + } /* End while (1) */ + + let(&lastTex, ""); /* Deallocate */ + let(&token, ""); /* Deallocate */ + + return texLine; +} /* asciiMathToTex */ + + +/* Gets the next section of a comment that is in the current mode (text, + label, or math). If 1st char. is not "$" (DOLLAR_SUBST), text mode is + assumed. mode = 0 means end of comment reached. srcptr is left at 1st + char. of start of next comment section. */ +vstring getCommentModeSection(vstring *srcptr, char *mode) +{ + vstring modeSection = ""; + vstring ptr; /* Not allocated */ + flag addMode = 0; + if (!g_outputToString) bug(2319); + + if ((*srcptr)[0] != DOLLAR_SUBST /*'$'*/) { + if ((*srcptr)[0] == 0) { /* End of string */ + *mode = 0; /* End of comment */ + return ""; + } else { + *mode = 'n'; /* Normal text */ + addMode = 1; + } + } else { + switch ((*srcptr)[1]) { + case 'l': + case 'm': + case 'n': + *mode = (*srcptr)[1]; + break; + case ')': /* Obsolete */ + bug(2317); + /* Leave old code in case user continues through the bug */ + *mode = 0; /* End of comment */ + return ""; + break; + default: + *mode = 'n'; + break; + } + } + + ptr = (*srcptr) + 1; + while (1) { + if (ptr[0] == DOLLAR_SUBST /*'$'*/) { + switch (ptr[1]) { + case 'l': + case 'm': + case 'n': + case ')': /* Obsolete (will never happen) */ + if (ptr[1] == ')') bug(2318); + let(&modeSection, space(ptr - (*srcptr))); + memcpy(modeSection, *srcptr, (size_t)(ptr - (*srcptr))); + if (addMode) { + let(&modeSection, cat(chr(DOLLAR_SUBST), "n", /*"$n"*/ modeSection, + NULL)); + } + *srcptr = ptr; + return modeSection; + break; + } + } else { + if (ptr[0] == 0) { + let(&modeSection, space(ptr - (*srcptr))); + memcpy(modeSection, *srcptr, (size_t)(ptr - (*srcptr))); + if (addMode) { + let(&modeSection, cat(chr(DOLLAR_SUBST), "n", /*"$n"*/ modeSection, + NULL)); + } + *srcptr = ptr; + return modeSection; + } + } + ptr++; + } /* End while */ + return NULL; /* Dummy return - never executes */ +} /* getCommentModeSection */ + + +/* The texHeaderFlag means this: + If !g_htmlFlag (i.e. TeX mode), then 1 means print header + If g_htmlFlag, then 1 means include "Previous Next" links on page, + based on the global g_showStatement variable +*/ +void printTexHeader(flag texHeaderFlag) +{ + + long i, j, k; + vstring tmpStr = ""; + + /* "Mathbox for " mod */ + vstring localSandboxTitle = ""; + vstring hugeHdr = ""; + vstring bigHdr = ""; + vstring smallHdr = ""; + vstring tinyHdr = ""; + vstring hugeHdrComment = ""; + vstring bigHdrComment = ""; + vstring smallHdrComment = ""; + vstring tinyHdrComment = ""; + + if (2/*error*/ == readTexDefs(0/*errorsOnly=0*/, 1 /*gifCheck=1*/)) { + print2( + "?There was an error in the $t comment's LaTeX/HTML definitions.\n"); + return; + } + /*}*/ + + g_outputToString = 1; /* Redirect print2 and printLongLine to g_printString */ + if (!g_htmlFlag) { + print2("%s This LaTeX file was created by Metamath on %s %s.\n", + "%", date(), time_()); + + if (texHeaderFlag && !g_oldTexFlag) { + print2("\\documentclass{article}\n"); + print2("\\usepackage{graphicx} %% For rotated iota\n"); + print2("\\usepackage{amssymb}\n"); + print2("\\usepackage{amsmath} %% For \\begin{align}...\n"); + print2("\\usepackage{amsthm}\n"); + print2("\\theoremstyle{plain}\n"); + print2("\\newtheorem{theorem}{Theorem}[section]\n"); + print2("\\newtheorem{definition}[theorem]{Definition}\n"); + print2("\\newtheorem{lemma}[theorem]{Lemma}\n"); + print2("\\newtheorem{axiom}{Axiom}\n"); + print2("\\allowdisplaybreaks[1] %% Allow page breaks in {align}\n"); + print2("\\usepackage[plainpages=false,pdfpagelabels]{hyperref}\n"); + print2("\\hypersetup{colorlinks} %% Get rid of boxes around links\n"); + print2("\\begin{document}\n"); + print2("\n"); + } + + if (texHeaderFlag && g_oldTexFlag) { + /* LaTeX 2e */ + print2("\\documentclass[leqno]{article}\n"); + /* LaTeX 2e */ + print2("\\usepackage{graphicx}\n"); /* For rotated iota */ + print2("\\usepackage{amssymb}\n"); + print2("\\raggedbottom\n"); + print2("\\raggedright\n"); + print2("%%\\title{Your title here}\n"); + print2("%%\\author{Your name here}\n"); + print2("\\begin{document}\n"); + print2("%%\\maketitle\n"); + print2("\\newbox\\mlinebox\n"); + print2("\\newbox\\mtrialbox\n"); + print2("\\newbox\\startprefix %% Prefix for first line of a formula\n"); + print2("\\newbox\\contprefix %% Prefix for continuation line of a formula\n"); + print2("\\def\\startm{ %% Initialize formula line\n"); + print2(" \\setbox\\mlinebox=\\hbox{\\unhcopy\\startprefix}\n"); + print2("}\n"); + print2("\\def\\m#1{ %% Add a symbol to the formula\n"); + print2(" \\setbox\\mtrialbox=\\hbox{\\unhcopy\\mlinebox $\\,#1$}\n"); + print2(" \\ifdim\\wd\\mtrialbox>\\hsize\n"); + print2(" \\box\\mlinebox\n"); + print2(" \\setbox\\mlinebox=\\hbox{\\unhcopy\\contprefix $\\,#1$}\n"); + print2(" \\else\n"); + print2(" \\setbox\\mlinebox=\\hbox{\\unhbox\\mtrialbox}\n"); + print2(" \\fi\n"); + print2("}\n"); + print2("\\def\\endm{ %% Output the last line of a formula\n"); + print2(" \\box\\mlinebox\n"); + print2("}\n"); + } + } else { /* g_htmlFlag */ + + print2("\n"); + print2("\n"); + print2("\n"); + print2("%s%s\n", ""); + /* Improve mobile device display per David A. Wheeler */ + print2("\n"); + + print2("\n"); + printLongLine(g_htmlCSS, "", " "); + + if (stsFlag) printLongLine(getSTSHeader(), "", "\n"); + + /* Put theorem name before "Metamath Proof Explorer" etc. */ + if (g_showStatement < g_extHtmlStmt) { + print2("%s\n", cat("", + /* Strip off ".html" */ + left(g_texFileName, (long)strlen(g_texFileName) - 5), + " - ", htmlTitle, + "", NULL)); + } else if (g_showStatement < g_mathboxStmt) { /* Sandbox stuff */ + print2("%s\n", cat("", + /* Strip off ".html" */ + left(g_texFileName, (long)strlen(g_texFileName) - 5), + " - ", g_extHtmlTitle, + "", NULL)); + + } else { + /* "Mathbox for " */ + /* Scan from this statement backwards until a big header is found */ + for (i = g_showStatement; i > g_mathboxStmt; i--) { + if (g_Statement[i].type == a_ || g_Statement[i].type == p_) { + /* Note: only bigHdr is used; the other 5 returned strings are + ignored */ + getSectionHeadings(i, &hugeHdr, &bigHdr, &smallHdr, + &tinyHdr, + &hugeHdrComment, &bigHdrComment, &smallHdrComment, + &tinyHdrComment, + 0, /* fineResolution */ + 0 /* fullComment */); + if (bigHdr[0] != 0) break; + } + } /* next i */ + if (bigHdr[0]) { + /* A big header was found; use it for the page title */ + let(&localSandboxTitle, bigHdr); + } else { + /* A big header was not found (should not happen if set.mm is + formatted right, but use default just in case) */ + let(&localSandboxTitle, sandboxTitle); + } + let(&hugeHdr, ""); /* Deallocate memory */ + let(&bigHdr, ""); /* Deallocate memory */ + let(&smallHdr, ""); /* Deallocate memory */ + let(&tinyHdr, ""); /* Deallocate memory */ + let(&hugeHdrComment, ""); /* Deallocate memory */ + let(&bigHdrComment, ""); /* Deallocate memory */ + let(&smallHdrComment, ""); /* Deallocate memory */ + let(&tinyHdrComment, ""); /* Deallocate memory */ + + printLongLine(cat("", + /* Strip off ".html" */ + left(g_texFileName, (long)strlen(g_texFileName) - 5), + " - ", localSandboxTitle, + "", NULL), "", "\""); + + } + /* Icon for bookmark */ + print2("%s%s\n", ""); + + print2("\n"); + print2("\n"); + + print2("\n", + "%"); + print2(" \n"); + print2(" \n"); + print2( +" \n"); + + if (texHeaderFlag) { /* For HTML, 1 means to put prev/next links */ + /* Put Previous/Next links into web page */ + print2(" \n"); + print2(" \n"); + print2(" \n"); + print2(" \n"); + print2(" which caused HTML validation failure */ + print2(" \n"); + print2(" \n"); + print2("
\"%s\"\n",\n"); + print2(" \n", + GREEN_TITLE_COLOR); + /* Allow plenty of room for long titles (although over 79 chars. will + trigger bug 1505). */ + print2("%s\n", + (g_showStatement < g_extHtmlStmt ? htmlTitle : + (g_showStatement < g_mathboxStmt ? g_extHtmlTitle : + localSandboxTitle))); + print2(" \n", "%"); + print2(" \n"); + /* Find the previous statement with a web page */ + j = 0; + k = 0; + for (i = g_showStatement - 1; i >= 1; i--) { + if (g_Statement[i].type == (char)p_ || + g_Statement[i].type == (char)a_) { + j = i; + break; + } + } + if (j == 0) { + k = 1; /* First statement flag */ + /* For the first statement, wrap to last one */ + for (i = g_statements; i >= 1; i--) { + if (g_Statement[i].type == (char)p_ || + g_Statement[i].type == (char)a_ ) { + j = i; + break; + } + } + } + if (j == 0) bug(2314); + print2(" \n", + g_Statement[j].labelName); + if (!k) { + print2(" < Previous  \n"); + } else { + print2(" < Wrap  \n"); + } + /* Find the next statement with a web page */ + j = 0; + k = 0; + for (i = g_showStatement + 1; i <= g_statements; i++) { + if (g_Statement[i].type == (char)p_ || + g_Statement[i].type == (char)a_) { + j = i; + break; + } + } + if (j == 0) { + k = 1; /* Last statement flag */ + /* For the last statement, wrap to first one */ + for (i = 1; i <= g_statements; i++) { + if (g_Statement[i].type == (char)p_ || + g_Statement[i].type == (char)a_) { + j = i; + break; + } + } + } + if (j == 0) bug(2315); + if (!k) { + print2(" Next >\n", + g_Statement[j].labelName); + } else { + print2(" Wrap >\n", + g_Statement[j].labelName); + } + + print2(" \n"); + + /* 8-Sep-03 nm - ??? Is the closing printed if there is no + altHtml? This should be tested. */ + + /* Compute the theorem list page number. ??? Temporarily + we assume it to be 100 (hardcoded). Todo: This should be fixed to use + the same as the THEOREMS_PER_PAGE in WRITE THEOREMS (have a SET + global variable in place of THEOREMS_PER_PAGE?) */ + i = ((g_Statement[g_showStatement].pinkNumber - 1) / 100) + 1; /* Page # */ + /* All thm pages now have page num after mmtheorems + since mmtheorems.html is now just the table of contents */ + let(&tmpStr, cat("mmtheorems", str((double)i), ".html#", + g_Statement[g_showStatement].labelName, NULL)); /* Link to page/stmt */ + /* Break up lines w/ long labels to prevent bug 1505 */ + printLongLine(cat("
Nearby theorems", NULL), " ", " "); + + print2(" \n"); + print2("
\n"); + print2(" Mirrors  >\n"); + print2("  Home  >\n"); + print2("  %s  >\n", + (g_showStatement < g_extHtmlStmt ? g_htmlHomeHREF : + (g_showStatement < g_mathboxStmt ? extHtmlHomeHREF : + g_htmlHomeHREF)), + (g_showStatement < g_extHtmlStmt ? htmlTitleAbbr : + (g_showStatement < g_mathboxStmt ? g_extHtmlTitleAbbr : + htmlTitleAbbr))); + print2("  Th. List  >\n"); + if (g_showStatement >= g_mathboxStmt) { + print2("  \n"); + print2(" Mathboxes  >\n"); + } + print2("  %s\n", + /* Strip off ".html" */ + left(g_texFileName, (long)strlen(g_texFileName) - 5)); + print2(" \n"); + print2(" \n"); + print2(" \n"); + + /* Add link(s) specified by htmlexturl in $t statement */ + /* The position of the theorem name is indicated with "*" in the + htmlexturl $t variable. If a literal "*" is part of the URL, + use the alternate URL encoding "%2A" */ + /* Example: (take out space in "/ *" below that was put there to prevent + compiler warnings) + htmlexturl '' + + 'Structured version  ' + + '' + + 'ASCII version  '; + */ + let(&tmpStr, htmlExtUrl); + i = 1; + while (1) { + i = instr(i, tmpStr, "*"); + if (i == 0) break; + let(&tmpStr, cat(left(tmpStr, i - 1), + g_Statement[g_showStatement].labelName, + right(tmpStr, i + 1), NULL)); + } + printLongLine(tmpStr, "", " "); + + /* Print the GIF/Unicode Font choice, if directories are specified */ + if (htmlDir[0]) { + + if (g_altHtmlFlag) { + print2(" GIF version\n", + htmlDir, g_texFileName); + + } else { + print2(" Unicode version\n", + altHtmlDir, g_texFileName); + + } + } + + } else { /* texHeaderFlag=0 for HTML means not to put prev/next links */ + /* there is no table open (mmascii, mmdefinitions), so don't + add \n", "%"); + + /* Print the GIF/Unicode Font choice, if directories are specified */ + if (htmlDir[0]) { + print2("\n"); + if (g_altHtmlFlag) { + print2("This is the Unicode version.
\n"); + print2("Change to GIF version\n", + htmlDir, g_texFileName); + } else { + print2("This is the GIF version.
\n"); + print2("Change to Unicode version\n", + altHtmlDir, g_texFileName); + } + } + else { + print2(" \n"); + } + + } + + print2("
\n"); + print2("
\n"); + + + + print2("
\n"); + + } /* g_htmlFlag */ + fprintf(g_texFilePtr, "%s", g_printString); + g_outputToString = 0; + let(&g_printString, ""); + + /* Deallocate strings */ + let(&tmpStr, ""); + +} /* printTexHeader */ + +/* Prints an embedded comment in TeX or HTML. The commentPtr must point to the first + character after the "$(" in the comment. The printout ends when the first + "$)" or null character is encountered. commentPtr must not be a temporary + allocation. htmlCenterFlag, if 1, means to center the HTML and add a + "Description:" prefix. */ +/* The output is printed to the global g_texFilePtr. */ +/* Note: the global long "g_showStatement" is referenced to determine whether + to read bibliography from mmset.html or mmhilbert.html (or other + g_htmlBibliography or extHtmlBibliography file pair). */ +/* Returns 1 if an error or warning message was printed */ +flag printTexComment(vstring commentPtr, flag htmlCenterFlag, + long actionBits, /* see below */ + /* Indicators for actionBits: + #define ERRORS_ONLY 1 - just report errors, don't print output + #define PROCESS_SYMBOLS 2 + #define PROCESS_LABELS 4 + #define ADD_COLORED_LABEL_NUMBER 8 + #define PROCESS_BIBREFS 16 + #define PROCESS_UNDERSCORES 32 + #define CONVERT_TO_HTML 64 - convert '<' to '>' unless + , present + #define METAMATH_COMMENT 128 - $) terminates string + #define PROCESS_EVERYTHING PROCESS_SYMBOLS + PROCESS_LABELS \ + + ADD_COLORED_LABEL_NUMBER + PROCESS_BIBREFS \ + + PROCESS_UNDERSCORES + CONVERT_HTML + METAMATH_COMMENT \ + */ + /* 10-Dec-2018 nm - expanded meaning of errorsOnly for MARKUP commmand: + 2 = process as if in ... preformatted mode but + don't strip ... tags + 3 = same as 2, but convert ONLY math symbols + (These new values were added instead of adding a new argument, + so as not to have to modify ~60 other calls to this function) */ + + flag fileCheck) /* 1 = check for missing external files (gifs, bib, etc.) */ +{ + vstring cmtptr; /* Not allocated */ + vstring srcptr; /* Not allocated */ + vstring lineStart; /* Not allocated */ + vstring tmpStr = ""; + vstring modeSection; /* Not allocated */ + vstring sourceLine = ""; + vstring outputLine = ""; + vstring tmp = ""; + flag textMode, mode, lastLineFlag, displayMode; + vstring tmpComment = ""; + flag preformattedMode = 0; /* HTML preformatted mode */ + + /* For bibliography hyperlinks */ + vstring bibTag = ""; + vstring bibFileName = ""; + vstring bibFileContents = ""; + vstring bibFileContentsUpper = ""; /* Uppercase version */ + vstring bibTags = ""; + long pos1, pos2, htmlpos1, htmlpos2, saveScreenWidth; + flag tmpMathMode; + + /* Variables for converting ` ` and ~ to old $m,$n and $l,$n formats in + order to re-use the old code */ + /* Note that DOLLAR_SUBST will replace the old $. */ + vstring cmt = ""; + vstring cmtMasked = ""; /* cmt with math syms blanked */ /* also mask ~ label */ + vstring tmpMasked = ""; /* tmp with math syms blanked */ + vstring tmpStrMasked = ""; /* tmpStr w/ math syms blanked */ + long i, clen; + flag returnVal = 0; /* 1 means error/warning */ + + /* Internal flags derived from actionBits argument, for MARKUP command use */ + flag errorsOnly; + flag processSymbols; + flag processLabels; + flag addColoredLabelNumber; + flag processBibrefs; + flag processUnderscores; + flag convertToHtml; + flag metamathComment; + + /* Assign local Booleans for actionBits mask */ + errorsOnly = (actionBits & ERRORS_ONLY ) != 0; + processSymbols = (actionBits & PROCESS_SYMBOLS ) != 0; + processLabels = (actionBits & PROCESS_LABELS ) != 0; + addColoredLabelNumber = (actionBits & ADD_COLORED_LABEL_NUMBER ) != 0; + processBibrefs = (actionBits & PROCESS_BIBREFS ) != 0; + processUnderscores = (actionBits & PROCESS_UNDERSCORES ) != 0; + convertToHtml = (actionBits & CONVERT_TO_HTML ) != 0; + metamathComment = (actionBits & METAMATH_COMMENT ) != 0; + + /* We must let this procedure handle switching output to string mode */ + if (g_outputToString) bug(2309); + /* The LaTeX (or HTML) file must be open */ + if (errorsOnly == 0) { + if (!g_texFilePtr) bug(2321); + } + + cmtptr = commentPtr; + + if (!g_texDefsRead) { + return returnVal; /* TeX defs were not read (error was detected + and flagged to the user elsewhere) */ + } + + /* Convert line to the old $m..$n and $l..$n formats (using DOLLAR_SUBST + instead of "$") - the old syntax is obsolete but we do this conversion + to re-use some old code */ + if (metamathComment != 0) { + i = instr(1, cmtptr, "$)"); /* If it points to source buffer */ + if (!i) i = (long)strlen(cmtptr) + 1; /* If it's a stand-alone string */ + } else { + i = (long)strlen(cmtptr) + 1; + } + let(&cmt, left(cmtptr, i - 1)); + + /* All actions on cmt should be mirrored on cmdMasked, except that + math symbols are replaced with blanks in cmdMasked */ + let(&cmtMasked, cmt); + + + /* This section is independent and can be removed without side effects */ + if (g_htmlFlag) { + /* Convert special characters <, &, etc. to HTML entities */ + /* But skip converting math symbols inside ` ` */ + /* Detect preformatted HTML (this is crude, since it + will apply to whole comment - perhaps fine-tune this later) */ + if (convertToHtml != 0) { + if (instr(1, cmt, "") != 0) preformattedMode = 1; + } else { + preformattedMode = 1; /* For MARKUP command - don't convert HTML */ + } + mode = 1; /* 1 normal, -1 math token */ + let(&tmp, ""); + let(&tmpMasked, ""); + while (1) { + pos1 = 0; + while (1) { + pos1 = instr(pos1 + 1, cmt, "`"); + if (!pos1) break; + if (cmt[pos1] == '`') { + pos1++; /* Skip `` escape */ + continue; + } + break; + } + if (!pos1) pos1 = (long)strlen(cmt) + 1; + if (mode == 1 && preformattedMode == 0) { + let(&tmpStr, ""); + /* asciiToTt() is where "<" is converted to "<" etc. */ + tmpStr = asciiToTt(left(cmt, pos1)); + let(&tmpStrMasked, tmpStr); + } else { + let(&tmpStr, left(cmt, pos1)); + if (mode == -1) { /* Math mode */ + /* Replace math symbols with spaces to prevent confusing them + with markup in sections below */ + let(&tmpStrMasked, cat(space(pos1 - 1), + mid(cmtMasked, pos1, 1), NULL)); + } else { /* Preformatted mode but not math mode */ + let(&tmpStrMasked, left(cmtMasked, pos1)); + } + } + let(&tmp, cat(tmp, tmpStr, NULL)); + let(&tmpMasked, cat(tmpMasked, tmpStrMasked, NULL)); + let(&cmt, right(cmt, pos1 + 1)); + let(&cmtMasked, right(cmtMasked, pos1 + 1)); + if (!cmt[0]) break; + mode = (char)(-mode); + } + let(&cmt, tmp); + let(&cmtMasked, tmpMasked); + let(&tmpStr, ""); /* Deallocate */ + let(&tmpStrMasked, ""); + } + + + /* Add leading and trailing HTML markup to comment here + (instead of in caller). Also convert special characters. */ + if (g_htmlFlag) { + /* This used to be done in mmcmds.c */ + if (htmlCenterFlag) { /* Note: this should be 0 in MARKUP command */ + let(&cmt, cat("
Description: ", + cmt, "
", NULL)); + let(&cmtMasked, + cat("
Description: ", + cmtMasked, "
", NULL)); + } + } + + + /* Mask out _ (underscore) in labels so they won't become subscripts + (reported by Benoit Jubin) */ + /* This section is independent and can be removed without side effects */ + if (g_htmlFlag != 0) { + pos1 = 0; + while (1) { /* Look for label start */ + pos1 = instr(pos1 + 1, cmtMasked, "~"); + if (!pos1) break; + if (cmtMasked[pos1] == '~') { + pos1++; /* Skip ~~ escape */ + continue; + } + /* Skip whitespace after ~ */ + while (1) { + if (cmtMasked[pos1] == 0) break; /* End of line */ + if (isspace((unsigned char)(cmtMasked[pos1]))) { + pos1++; + continue; + } else { /* Found start of label */ + break; + } + } + /* Skip non-whitespace after ~ find end of label */ + while (1) { + if (cmtMasked[pos1] == 0) break; /* End of line */ + if (!(isspace((unsigned char)(cmtMasked[pos1])))) { + if (cmtMasked[pos1] == '_') { + /* Put an "?" in place of label character in mask */ + cmtMasked[pos1] = '?'; + } + pos1++; + continue; + } else { /* Found end of label */ + break; + } + } /* while (1) */ + } /* while (1) */ + } /* if g_htmlFlag */ + + + /* Handle dollar signs in comments converted to LaTeX */ + /* This section is independent and can be removed without side effects */ + /* This must be done before the underscores below so subscript $'s */ + /* won't be converted to \$'s */ + if (!g_htmlFlag) { /* LaTeX */ + pos1 = 0; + while (1) { + pos1 = instr(pos1 + 1, cmt, "$"); + if (!pos1) break; + /* Don't modify anything inside of ... tags */ + if (pos1 > instr(1, cmt, "") && pos1 < instr(1, cmt, "")) + continue; + let(&cmt, cat(left(cmt, pos1 - 1), "\\$", + right(cmt, pos1 + 1), NULL)); + let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), "\\$", + right(cmtMasked, pos1 + 1), NULL)); + pos1 = pos1 + 1; /* Adjust for 2-1 extra chars in "let" above */ + } /* while (1) */ + } + + /* This section comes BEFORE the underscore handling + below, so that "{\em...}" won't be converted to "\}\em...\}" */ + /* Convert any remaining special characters for LaTeX */ + /* This section is independent and can be removed without side effects */ + if (!g_htmlFlag) { /* i.e. LaTeX mode */ + /* At this point, the comment begins e.g "\begin{lemma}\label{lem:abc}" */ + pos1 = instr(1, cmt, "} "); + if (pos1) { + pos1++; /* Start after the "}" */ + } else { + pos1 = 1; /* If not found, start from beginning of line */ + } + pos2 = (long)strlen(cmt); + tmpMathMode = 0; + for (pos1 = pos1 + 0; pos1 <= pos2; pos1++) { + /* Don't modify anything inside of math symbol strings + (imperfect - only works if `...` is not split across lines?) */ + if (cmt[pos1 - 1] == '`') tmpMathMode = (flag)(1 - tmpMathMode); + if (tmpMathMode) continue; + if (pos1 > 1) { + if (cmt[pos1 - 1] == '_' && cmt[pos1 - 2] == '$') { + /* The _ is part of "$_{...}$" earlier conversion */ + continue; + } + } + /* $%#{}&^\\|<>"~_ are converted by asciiToTt() */ + /* Omit \ and $ since they be part of an earlier converston */ + /* Omit ~ since it is part of label ref */ + /* Omit " since it legal */ + /* Because converting to \char` causes later math mode problems due to `, + we change |><_ to /)(- (an ugly workaround) */ + switch(cmt[pos1 - 1]) { + case '|': cmt[pos1 - 1] = '/'; break; + case '<': cmt[pos1 - 1] = '{'; break; + case '>': cmt[pos1 - 1] = '}'; break; + case '_': cmt[pos1 - 1] = '-'; break; + } + if (strchr("%#{}&^|<>_", cmt[pos1 - 1]) != NULL) { + let(&tmpStr, ""); + tmpStr = asciiToTt(chr(cmt[pos1 - 1])); + let(&cmt, cat(left(cmt, pos1 - 1), tmpStr, + right(cmt, pos1 + 1), NULL)); + let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), tmpStr, + right(cmtMasked, pos1 + 1), NULL)); + pos1 += (long)strlen(tmpStr) - 1; + pos2 += (long)strlen(tmpStr) - 1; + } + } /* Next pos1 */ + } /* if (!g_htmlFlag) */ + + /* Handle underscores in comments converted to HTML: Convert _abc_ + to abc for book titles, etc.; convert a_n to an for + subscripts */ + /* This section is independent and can be removed without side effects */ + if (g_htmlFlag != 0 && processUnderscores != 0) { + pos1 = 0; + while (1) { + /* Only look at non-math part of comment */ + pos1 = instr(pos1 + 1, cmtMasked, "_"); + if (!pos1) break; + /* Don't modify anything inside of ... tags */ + if (pos1 > instr(1, cmt, "") && pos1 < instr(1, cmt, "")) + continue; + + /* Don't modify external hyperlinks containing "_" */ + pos2 = pos1 - 1; + while (1) { /* Get to previous whitespace */ + if (pos2 == 0 || isspace((unsigned char)(cmt[pos2]))) break; + pos2--; + } + if (!strcmp(mid(cmt, pos2 + 2, 7), "http://")) { + continue; + } + if (!strcmp(mid(cmt, pos2 + 2, 8), "https://")) { + continue; + } + if (!strcmp(mid(cmt, pos2 + 2, 2), "mm")) { + continue; + } + + /* Opening "_" must be _ for tag */ + if (pos1 > 1) { + /* Check for not whitespace and not opening punctuation */ + if (!isspace((unsigned char)(cmt[pos1 - 2])) + && strchr(OPENING_PUNCTUATION, cmt[pos1 - 2]) == NULL) { + /* Check for not whitespace and not closing punctuation */ + if (!isspace((unsigned char)(cmt[pos1])) + && strchr(CLOSING_PUNCTUATION, cmt[pos1]) == NULL) { + + /* Found _ - assume subscript */ + /* Locate the whitepace (or end of string) that closes subscript */ + /* Note: This algorithm is not perfect in that the subscript + is assumed to end at closing punctuation, which theoretically + could be part of the subscript itself, such as a subscript + with a comma in it. */ + pos2 = pos1 + 1; + while (1) { + if (!cmt[pos2]) break; /* End of string */ + /* Look for whitespace or closing punctuation */ + if (isspace((unsigned char)(cmt[pos2])) + || strchr(OPENING_PUNCTUATION, cmt[pos2]) != NULL + || strchr(CLOSING_PUNCTUATION, cmt[pos2]) != NULL) break; + pos2++; /* Move forward through subscript */ + } + pos2++; /* Adjust for left, seg, etc. that start at 1 not 0 */ + if (g_htmlFlag) { /* HTML */ + /* Put ... around subscript */ + let(&cmt, cat(left(cmt, pos1 - 1), + "", + seg(cmt, pos1 + 1, pos2 - 1), /* Skip (delete) "_" */ + "", right(cmt, pos2), NULL)); + let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), + "", + seg(cmtMasked, pos1 + 1, pos2 - 1), /* Skip (delete) "_" */ + "", right(cmtMasked, pos2), NULL)); + pos1 = pos2 + 33; /* Adjust for 34-1 extra chars in "let" above */ + } else { /* LaTeX */ + /* Put _{...} around subscript */ + let(&cmt, cat(left(cmt, pos1 - 1), "$_{", + seg(cmt, pos1 + 1, pos2 - 1), /* Skip (delete) "_" */ + "}$", right(cmt, pos2), NULL)); + let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), "$_{", + seg(cmtMasked, pos1 + 1, pos2 - 1), /* Skip (delete) "_" */ + "}$", right(cmtMasked, pos2), NULL)); + pos1 = pos2 + 4; /* Adjust for 5-1 extra chars in "let" above */ + } + continue; + + } else { + /* Found _ - not an opening "_" */ + /* Do nothing in this case */ + continue; + } + } + } + if (!isalnum((unsigned char)(cmt[pos1]))) continue; + /* Only look at non-math part of comment */ + pos2 = instr(pos1 + 1, cmtMasked, "_"); + if (!pos2) break; + /* Closing "_" must be _ */ + if (!isalnum((unsigned char)(cmt[pos2 - 2]))) continue; + if (isalnum((unsigned char)(cmt[pos2]))) continue; + if (g_htmlFlag) { /* HTML */ + let(&cmt, cat(left(cmt, pos1 - 1), "", + seg(cmt, pos1 + 1, pos2 - 1), + "", right(cmt, pos2 + 1), NULL)); + let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), "", + seg(cmtMasked, pos1 + 1, pos2 - 1), + "", right(cmtMasked, pos2 + 1), NULL)); + pos1 = pos2 + 5; /* Adjust for 7-2 extra chars in "let" above */ + } else { /* LaTeX */ + let(&cmt, cat(left(cmt, pos1 - 1), "{\\em ", + seg(cmt, pos1 + 1, pos2 - 1), + "}", right(cmt, pos2 + 1), NULL)); + let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), "{\\em ", + seg(cmtMasked, pos1 + 1, pos2 - 1), + "}", right(cmtMasked, pos2 + 1), NULL)); + pos1 = pos2 + 4; /* Adjust for 6-2 extra chars in "let" above */ + } + } + } + + /* Convert opening double quote to `` for LaTeX */ + /* This section is independent and can be removed without side effects */ + if (!g_htmlFlag) { /* If LaTeX mode */ + i = 1; /* Even/odd counter: 1 = left quote, 0 = right quote */ + pos1 = 0; + while (1) { + /* cmtMasked has math symbols blanked */ + pos1 = instr(pos1 + 1, cmtMasked, "\""); + if (pos1 == 0) break; + if (i == 1) { + /* Warning: "`" needs to be escaped (i.e. repeated) to prevent it + from being treated as a math symbol delimiter below. So "````" + will become "``" in the LaTeX output. */ + let(&cmt, cat(left(cmt, pos1 - 1), "````", + right(cmt, pos1 + 1), NULL)); + let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), "````", + right(cmtMasked, pos1 + 1), NULL)); + } + i = 1 - i; /* Count to next even or odd */ + } + } + + /* Put bibliography hyperlinks in comments converted to HTML: + [Monk2] becomes tag, HTML is case-insensitive for A and + NAME but case-sensitive for the token after the = */ + /* Strip all whitespace */ + let(&bibFileContents, edit(bibFileContents, 2)); + /* Uppercase version for HTML tag search */ + let(&bibFileContentsUpper, edit(bibFileContents, 32)); + htmlpos1 = 0; + while (1) { /* Look for all HTML tags */ + htmlpos1 = instr(htmlpos1 + 1, bibFileContentsUpper, ""); + if (!htmlpos2) break; + htmlpos2--; /* Move to character before ">" */ + if (bibFileContents[htmlpos2 - 1] == '\'' + || bibFileContents[htmlpos2 - 1] == '"') htmlpos2--; + if (htmlpos2 <= htmlpos1) continue; /* Ignore bad HTML syntax */ + let(&tmp, cat("[", + seg(bibFileContents, htmlpos1, htmlpos2), "]", NULL)); + /* Check if tag is already in list */ + if (instr(1, bibTags, tmp)) { + printLongLine(cat("?Error: There two occurrences of", + " bibliographic reference \"", + seg(bibFileContents, htmlpos1, htmlpos2), + "\" in the file \"", bibFileName, "\".", NULL), "", " "); + returnVal = 1; /* Error/warning printed */ + } + /* Add tag to tag list */ + let(&bibTags, cat(bibTags, tmp, NULL)); + } /* end while */ + if (!bibTags[0]) { + /* No tags found; put dummy partial tag meaning "file read" */ + let(&bibTags, "["); + } + } /* end if (!bibFIleContents) */ + } /* end if (noFileCheck == 0) */ + /* Assign to permanent tag list for next time */ + if (g_showStatement < g_extHtmlStmt) { + let(&g_htmlBibliographyTags, bibTags); + /*} else {*/ + } else if (g_showStatement < g_mathboxStmt) { + let(&extHtmlBibliographyTags, bibTags); + + } else { + let(&g_htmlBibliographyTags, bibTags); + + } + /* Done reading in HTML file with bibliography */ + } /* end if (!bibTags[0]) */ + /* See if the tag we found is in the bibliography file */ + if (bibTags[0] == '[') { + /* We have a tag list from the bibliography file */ + if (!instr(1, bibTags, bibTag)) { + printLongLine(cat("?Error: The bibliographic reference \"", bibTag, + "\" in statement \"", g_Statement[g_showStatement].labelName, + "\" was not found as an anchor in the file \"", bibFileName, "\".", NULL), + "", " "); + returnVal = 1; /* Error/warning printed */ + } + } + /* End of error-checking */ + + /* Make an HTML reference for the tag */ + let(&tmp, cat("[", + seg(bibTag, 2, pos2 - pos1), "]", NULL)); + let(&cmt, cat(left(cmt, pos1 - 1), tmp, right(cmt, + pos2 + 1), NULL)); + let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), tmp, right(cmtMasked, + pos2 + 1), NULL)); + pos1 = pos1 + (long)strlen(tmp) - (long)strlen(bibTag); /* Adjust comment position */ + } /* end while(1) */ + } /* end if (bibFileName[0]) */ + } /* end of if (g_htmlFlag) */ + + /* All actions on cmt should be mirrored on cmdMasked, except that + math symbols are replaced with blanks in cmdMasked */ + if (strlen(cmt) != strlen(cmtMasked)) bug(2334); /* Should be in sync */ + + /* Starting here, we no longer use cmtMasked, so syncing it with cmt + isn't important anymore. */ + + clen = (long)strlen(cmt); + mode = 'n'; + for (i = 0; i < clen; i++) { + if (cmt[i] == '`') { + if (cmt[i + 1] == '`') { + if (processSymbols != 0) { + /* Escaped ` = actual ` */ + let(&cmt, cat(left(cmt, i + 1), right(cmt, i + 3), NULL)); + clen--; + } + } else { + /* We will still enter and exit math mode when + processSymbols=0 so as to skip ~ in math symbols. However, + we don't insert the "DOLLAR_SUBST mode" so that later on + it will look like normal text */ + /* Enter or exit math mode */ + if (mode != 'm') { + mode = 'm'; + } else { + mode = 'n'; + } + + if (processSymbols != 0) { + let(&cmt, cat(left(cmt, i), chr(DOLLAR_SUBST) /*$*/, chr(mode), + right(cmt, i+2), NULL)); + clen++; + i++; + } + + /* If symbol is preceded by opening punctuation and a space, take out + the space so it looks better. */ + if (mode == 'm' && processSymbols != 0) { + let(&tmp, mid(cmt, i - 2, 2)); + if (!strcmp("( ", tmp)) { + let(&cmt, cat(left(cmt, i - 2), right(cmt, i), NULL)); + clen = clen - 1; + } + /* We include quotes since symbols are often enclosed in them. */ + let(&tmp, mid(cmt, i - 8, 8)); + if (!strcmp("" ", right(tmp, 2)) + && strchr("( ", tmp[0]) != NULL) { + let(&cmt, cat(left(cmt, i - 2), right(cmt, i), NULL)); + clen = clen - 1; + } + let(&tmp, ""); + } + /* If symbol is followed by a space and closing punctuation, take out + the space so it looks better. */ + if (mode == 'n' && processSymbols != 0) { + /* (Why must it be i + 2 here but i + 1 in label version below? + Didn't investigate but seems strange.) */ + let(&tmp, mid(cmt, i + 2, 2)); + if (tmp[0] == ' ' && strchr(CLOSING_PUNCTUATION, tmp[1]) != NULL) { + let(&cmt, cat(left(cmt, i + 1), right(cmt, i + 3), NULL)); + clen = clen - 1; + } + /* We include quotes since symbols are often enclosed in them. */ + let(&tmp, mid(cmt, i + 2, 8)); + if (strlen(tmp) < 8) + let(&tmp, cat(tmp, space(8 - (long)strlen(tmp)), NULL)); + if (!strcmp(" "", left(tmp, 7)) + && strchr(CLOSING_PUNCTUATION, tmp[7]) != NULL) { + let(&cmt, cat(left(cmt, i + 1), right(cmt, i + 3), NULL)); + clen = clen - 1; + } + let(&tmp, ""); + } + + } + } + if (cmt[i] == '~' && mode != 'm') { + if (cmt[i + 1] == '~' /* Escaped ~ */ || processLabels == 0) { + if (processLabels != 0) { + /* Escaped ~ = actual ~ */ + let(&cmt, cat(left(cmt, i + 1), right(cmt, i + 3), NULL)); + clen--; + } + } else { + /* Enter or exit label mode */ + if (mode != 'l') { + mode = 'l'; + /* If there is whitespace after the ~, then remove + all whitespace immediately after the ~ to join the ~ to + the label. This enhances the Metamath syntax so that + whitespace is now allowed between the ~ and the label, which + makes it easier to do global substitutions of labels in a + text editor. */ + while (isspace((unsigned char)(cmt[i + 1])) && clen > i + 1) { + let(&cmt, cat(left(cmt, i + 1), right(cmt, i + 3), NULL)); + clen--; + } + } else { + /* If you see this bug, the most likely cause is a tilde + character in a comment that does not prefix a label or hyperlink. + The most common problem is the "~" inside a hyperlink that + specifies a user's directory. To fix it, use a double tilde + "~~" to escape it, which will become a single tilde on output. */ + g_outputToString = 0; + printLongLine(cat("?Warning: There is a \"~\" inside of a label", + " in the comment of statement \"", + g_Statement[g_showStatement].labelName, + "\". Use \"~~\" to escape \"~\" in an http reference.", + NULL), "", " "); + returnVal = 1; /* Error/warning printed */ + g_outputToString = 1; + mode = 'n'; + } + let(&cmt, cat(left(cmt, i), chr(DOLLAR_SUBST) /*$*/, chr(mode), + right(cmt, i+2), NULL)); + clen++; + i++; + + /* If label is preceded by opening punctuation and space, take out + the space so it looks better. */ + let(&tmp, mid(cmt, i - 2, 2)); + /*printf("tmp#%s#\n",tmp);*/ + if (!strcmp("( ", tmp) || !strcmp("[ ", tmp)) { + let(&cmt, cat(left(cmt, i - 2), right(cmt, i), NULL)); + clen = clen - 1; + } + let(&tmp, ""); + + } + } + + if (processLabels == 0 && mode == 'l') { + /* We should have prevented it from ever getting into label mode */ + bug(2344); + } + + if ((isspace((unsigned char)(cmt[i])) + || cmt[i] == '<') /* If the label ends the comment, + "" with no space will be appended before this section. */ + && mode == 'l') { + /* Whitespace exits label mode */ + mode = 'n'; + let(&cmt, cat(left(cmt, i), chr(DOLLAR_SUBST) /*$*/, chr(mode), + right(cmt, i+1), NULL)); + clen = clen + 2; + i = i + 2; + + /* If label is followed by space and end punctuation, take out the space + so it looks better. */ + let(&tmp, mid(cmt, i + 1, 2)); + if (tmp[0] == ' ' && strchr(CLOSING_PUNCTUATION, tmp[1]) != NULL) { + let(&cmt, cat(left(cmt, i), right(cmt, i + 2), NULL)); + clen = clen - 1; + } + let(&tmp, ""); + + } + /* clen should always remain comment length - do a sanity check here */ + if ((signed)(strlen(cmt)) != clen) { + bug(2311); + } + } /* Next i */ + /* End convert line to the old $m..$n and $l..$n */ + + + /* Put and at beginning of line so preformattedMode won't + be switched on or off in the middle of processing a line */ + /* This also fixes the problem where multiple ... on one + line aren't all removed in HTML output, causing w3c validation errors */ + /* Note: "Q2." will have a space around "2" because + of this fix. Instead use "Q2." or just "Q^2." */ + pos1 = -1; /* So -1 + 2 = 1 = start of string for instr() */ + while (1) { + pos1 = instr(pos1 + 2/*skip new \n*/, cmt, ""); + if (pos1 == 0 + || convertToHtml == 0 /* Don't touch in MARKUP command */ + ) break; + + /* If begins a line (after stripping spaces), don't put a \n so + that we don't trigger new paragraph mode */ + let(&tmpStr, edit(left(cmt, pos1 - 1), 2/*discard spaces & tabs*/)); + i = (long)strlen(tmpStr); + if (i == 0) continue; + if (tmpStr[i - 1] == '\n') continue; + + let(&cmt, cat(left(cmt, pos1 - 1), "\n", right(cmt, pos1), NULL)); + } + pos1 = -1; /* So -1 + 2 = 1 = start of string for instr() */ + while (1) { + pos1 = instr(pos1 + 2/*skip new \n*/, cmt, ""); + if (pos1 == 0 + || convertToHtml == 0 /* Don't touch in MARKUP command */ + ) break; + + /* If begins a line (after stripping spaces), don't put a \n so + that we don't trigger new paragraph mode */ + let(&tmpStr, edit(left(cmt, pos1 - 1), 2/*discard spaces & tabs*/)); + i = (long)strlen(tmpStr); + if (i == 0) continue; + if (tmpStr[i - 1] == '\n') continue; + + let(&cmt, cat(left(cmt, pos1 - 1), "\n", right(cmt, pos1), NULL)); + } + + + cmtptr = cmt; /* cmtptr is for scanning cmt */ + + g_outputToString = 1; /* Redirect print2 and printLongLine to g_printString */ + + while (1) { + /* Get a "line" of text, up to the next new-line. New-lines embedded + in $m and $l sections are ignored, so that these sections will not + be dangling. */ + lineStart = cmtptr; + textMode = 1; + lastLineFlag = 0; + while (1) { + if (cmtptr[0] == 0) { + lastLineFlag = 1; + break; + } + if (cmtptr[0] == '\n' && textMode) break; + /* if (cmtptr[0] == '$') { */ + if (cmtptr[0] == DOLLAR_SUBST) { + if (cmtptr[1] == ')') { + bug(2312); /* Obsolete (should never happen) */ + lastLineFlag = 1; + break; + } + } + if (cmtptr[0] == DOLLAR_SUBST /*'$'*/) { + cmtptr++; + if (cmtptr[0] == 'm') textMode = 0; /* Math mode */ + if (cmtptr[0] == 'l') textMode = 0; /* Label mode */ + if (cmtptr[0] == 'n') textMode = 1; /* Normal mode */ + } + cmtptr++; + } + let(&sourceLine, space(cmtptr - lineStart)); + memcpy(sourceLine, lineStart, (size_t)(cmtptr - lineStart)); + cmtptr++; /* Get past new-line to prepare for next line's scan */ + + /* If the line contains only math mode text, use TeX display mode. */ + displayMode = 0; + let(&tmpStr, edit(sourceLine, 8 + 128)); /* Trim spaces */ + if (!strcmp(right(tmpStr, (long)strlen(tmpStr) - 1), cat(chr(DOLLAR_SUBST), "n", + NULL))) let(&tmpStr, left(tmpStr, (long)strlen(tmpStr) - 2)); /* Strip $n */ + srcptr = tmpStr; + modeSection = getCommentModeSection(&srcptr, &mode); + let(&modeSection, ""); /* Deallocate */ + if (mode == 'm') { + modeSection = getCommentModeSection(&srcptr, &mode); + let(&modeSection, ""); /* Deallocate */ + } + let(&tmpStr, ""); /* Deallocate */ + + + /* Convert all sections of the line to text, math, or labels */ + let(&outputLine, ""); + srcptr = sourceLine; + while (1) { + modeSection = getCommentModeSection(&srcptr, &mode); + if (!mode) break; /* Done */ + let(&modeSection, right(modeSection, 3)); /* Remove mode-change command */ + switch (mode) { + case 'n': /* Normal text */ + let(&outputLine, cat(outputLine, modeSection, NULL)); + break; + case 'l': /* Label mode */ + + if (processLabels == 0) { + /* Labels should be treated as normal text */ + bug(2345); + } + + let(&modeSection, edit(modeSection, 8 + 128 + 16)); /* Discard + leading and trailing blanks; reduce spaces to one space */ + let(&tmpStr, ""); + tmpStr = asciiToTt(modeSection); + if (!tmpStr[0]) { + /* This can happen if ~ is followed by ` (start of math string) */ + g_outputToString = 0; + printLongLine(cat("?Error: There is a \"~\" with no label", + " in the comment of statement \"", + g_Statement[g_showStatement].labelName, + "\". Check that \"`\" inside of a math symbol is", + " escaped with \"``\".", + NULL), "", " "); + returnVal = 1; /* Error/warning printed */ + g_outputToString = 1; + + } + + if (!strcmp("http://", left(tmpStr, 7)) + || !strcmp("https://", left(tmpStr, 8)) + || !strcmp("mm", left(tmpStr, 2))) { + /* If the "label" begins with 'http://', then + assume it is an external hyperlink and not a real label. + This is kind of a syntax kludge but it is easy to do. + Added starting with 'mm', which is illegal + for set.mm labels - e.g. mmtheorems.html#abc */ + + if (g_htmlFlag) { + let(&outputLine, cat(outputLine, "", tmpStr, "", tmp, NULL)); + } else { + + /* Generate LaTeX version of the URL */ + i = instr(1, tmpStr, "\\char`\\~"); + /* The url{} function automatically converts ~ to LaTeX */ + if (i != 0) { + let(&tmpStr, cat(left(tmpStr, i - 1), right(tmpStr, i + 7), + NULL)); + } + let(&outputLine, cat(outputLine, "\\url{", tmpStr, + "}", tmp, NULL)); + + } + } else { + /* Do binary search through just $a's and $p's (there + are no html pages for local labels) */ + i = lookupLabel(tmpStr); + if (i < 0) { + g_outputToString = 0; + printLongLine(cat("?Warning: The label token \"", tmpStr, + "\" (referenced in comment of statement \"", + g_Statement[g_showStatement].labelName, + "\") is not a $a or $p statement label.", NULL), "", " "); + g_outputToString = 1; + returnVal = 1; /* Error/warning printed */ + } + + if (!g_htmlFlag) { + let(&outputLine, cat(outputLine, "{\\tt ", tmpStr, + "}", NULL)); + } else { + let(&tmp, ""); + if (addColoredLabelNumber != 0) { + /* When the error above occurs, i < 0 will cause pinkHTML() + to issue "(future)" for pleasant readability */ + tmp = pinkHTML(i); + } + if (i < 0) { + /* Error output - prevent broken link */ + let(&outputLine, cat(outputLine, "", tmpStr, "", tmp, NULL)); + } else { + /* Normal output - put hyperlink to the statement */ + let(&outputLine, cat(outputLine, "", tmpStr, "", tmp, NULL)); + } + } + } /* if (!strcmp("http://", left(tmpStr, 7))) ... else */ + let(&tmpStr, ""); /* Deallocate */ + break; + case 'm': /* Math mode */ + + if (processSymbols == 0) { + /* Math symbols should be treated as normal text */ + bug(2346); + } + + let(&tmpStr, ""); + tmpStr = asciiMathToTex(modeSection, g_showStatement); + if (!g_htmlFlag) { + if (displayMode) { + /* It the user's responsibility to establish equation environment + in displayMode. */ + let(&outputLine, cat(outputLine, /*"\\[",*/ edit(tmpStr, 128), + /*"\\]",*/ NULL)); /* edit = remove trailing spaces */ + } else { + let(&outputLine, cat(outputLine, "$", edit(tmpStr, 128), + "$", NULL)); /* edit = remove trailing spaces */ + } + } else { + /* Trim leading, trailing spaces in case punctuation + surrounds the math symbols in the comment */ + let(&tmpStr, edit(tmpStr, 8 + 128)); + /* Enclose math symbols in a span to be used for font selection */ + let(&tmpStr, cat( + (g_altHtmlFlag ? cat("", NULL) : ""), + tmpStr, + (g_altHtmlFlag ? "" : ""), + NULL)); + let(&outputLine, cat(outputLine, tmpStr, NULL)); /* html */ + } + let(&tmpStr, ""); /* Deallocate */ + break; + } /* End switch(mode) */ + let(&modeSection, ""); /* Deallocate */ + } + let(&outputLine, edit(outputLine, 128)); /* remove trailing spaces */ + + if (g_htmlFlag) { + /* Change blank lines into paragraph breaks except in mode */ + if (!outputLine[0]) { /* Blank line */ + if (preformattedMode == 0 + && convertToHtml == 1 /* Not MARKUP command */ + ) { /* Make it a paragraph break */ + let(&outputLine, + /* Prevent space after last paragraph */ + "

"); + } + } + /* If a statement comment has a section embedded in + ..., we keep the contents verbatim */ + pos1 = instr(1, outputLine, ""); + if (pos1 != 0 && convertToHtml == 1) { + /* The line below is probably redundant since we + set preformattedMode ealier. Maybe add a bug check to make sure + it is 1 here. */ + preformattedMode = 1; /* So we don't put

for blank lines */ + /* Strip out the "" string */ + let(&outputLine, cat(left(outputLine, pos1 - 1), + right(outputLine, pos1 + 6), NULL)); + } + pos1 = instr(1, outputLine, ""); + if (pos1 != 0 && convertToHtml == 1) { + preformattedMode = 0; + /* Strip out the "" string */ + let(&outputLine, cat(left(outputLine, pos1 - 1), + right(outputLine, pos1 + 7), NULL)); + } + } + + if (!g_htmlFlag) { /* LaTeX */ + /* Convert

...
HTML tags to LaTeX */ + /* leave this in for now */ + while (1) { + pos1 = instr(1, outputLine, "
");
+        if (pos1) {
+          let(&outputLine, cat(left(outputLine, pos1 - 1), "\\begin{verbatim} ",
+              right(outputLine, pos1 + 5), NULL));
+        } else {
+          break;
+        }
+      }
+      while (1) {
+        pos1 = instr(1, outputLine, "
"); + if (pos1) { + let(&outputLine, cat(left(outputLine, pos1 - 1), "\\end{verbatim} ", + right(outputLine, pos1 + 6), NULL)); + } else { + break; + } + } + /* strip out , */ + /* The HTML part may screw up LaTeX; maybe we should just take out + any HTML code completely in the future? */ + while (1) { + pos1 = instr(1, outputLine, ""); + if (pos1) { + let(&outputLine, cat(left(outputLine, pos1 - 1), + right(outputLine, pos1 + 6), NULL)); + } else { + break; + } + } + while (1) { + pos1 = instr(1, outputLine, ""); + if (pos1) { + let(&outputLine, cat(left(outputLine, pos1 - 1), + right(outputLine, pos1 + 7), NULL)); + } else { + break; + } + } + } + + saveScreenWidth = g_screenWidth; + /* in
 mode, we don't want to wrap the HTML
+       output with spurious newlines. Any large value will
+       do; we just need to accomodate the worst case line length that will
+       result from converting ~ label, [author], ` math ` to HTML */
+    if (preformattedMode) g_screenWidth = 50000;
+    if (errorsOnly == 0) {
+      printLongLine(outputLine, "", g_htmlFlag ? "\"" : "\\");
+    }
+    g_screenWidth = saveScreenWidth;
+
+    let(&tmp, ""); /* Clear temporary allocation stack */
+
+    if (lastLineFlag) break; /* Done */
+  } /* end while(1) */
+
+  if (g_htmlFlag) {
+    if (convertToHtml != 0) { /* Not MARKUP command */
+      print2("\n"); /* Don't change what the previous code did */
+    } else {
+      /* Add newline if string is not empty and has no newline at end */
+      if (g_printString[0] != 0) {
+        i = (long)strlen(g_printString);
+        if (g_printString[i - 1] != '\n')  {
+          print2("\n");
+        } else {
+          /* There is an extra \n added by something previous.  Until
+             we figure out what, take it off so that MARKUP output will
+             equal input when no processing qualifiers are used. */
+          if (i > 1) {
+            if (g_printString[i - 2] == '\n') {
+              let(&g_printString, left(g_printString, i - 1));
+            }
+          }
+        }
+      }
+    }
+  } else { /* LaTeX mode */
+    if (!g_oldTexFlag) {
+      /* Suppress blank line for LaTeX */
+      /* print2("\n"); */
+    } else {
+      print2("\n");
+    }
+  }
+
+  g_outputToString = 0; /* Restore normal output */
+  if (errorsOnly == 0) {
+    fprintf(g_texFilePtr, "%s", g_printString);
+  }
+
+  let(&g_printString, ""); /* Deallocate strings */
+  let(&sourceLine, "");
+  let(&outputLine, "");
+  let(&cmt, "");
+  let(&cmtMasked, "");
+  let(&tmpComment, "");
+  let(&tmp, "");
+  let(&tmpMasked, "");
+  let(&tmpStr, "");
+  let(&tmpStrMasked, "");
+  let(&bibTag, "");
+  let(&bibFileName, "");
+  let(&bibFileContents, "");
+  let(&bibFileContentsUpper, "");
+  let(&bibTags, "");
+
+  return returnVal; /* 1 if error/warning found */
+
+} /* printTexComment */
+
+
+
+void printTexLongMath(nmbrString *mathString,
+    vstring startPrefix, /* Start prefix in "screen display" mode e.g.
+         "abc $p"; it is converted to the appropriate format.  Non-zero
+         length means proof step in HTML mode, as opposed to assertion etc. */
+    vstring contPrefix, /* Prefix for continuation lines.  Not used in
+         HTML mode.  Warning:  contPrefix must not be temporarily allocated
+         (as a cat, left, etc. argument) by caller */
+    long hypStmt, /* hypStmt, if non-zero, is the statement number to be
+                     referenced next to the hypothesis link in html */
+    long indentationLevel) /* Indentation amount of proof step -
+                              note that this is 0 for last step of proof */
+{
+#define INDENTATION_OFFSET 1
+  long i;
+  long pos;
+  vstring tex = "";
+  vstring texLine = "";
+  vstring sPrefix = "";
+  vstring htmStep = "";
+  vstring htmStepTag = "";
+  vstring htmHyp = "";
+  vstring htmRef = "";
+  vstring htmLocLab = "";
+  vstring tmp = "";
+  vstring descr = "";
+  char refType = '?'; /* 'e' means $e, etc. */
+
+  let(&sPrefix, startPrefix); /* Save it; it may be temp alloc */
+
+  if (!g_texDefsRead) return; /* TeX defs were not read (error was printed) */
+  g_outputToString = 1; /* Redirect print2 and printLongLine to g_printString */
+
+  /* Note that the "tex" assignment below will be used only when !g_htmlFlag
+     and g_oldTexFlag, or when g_htmlFlag and len(sPrefix)>0 */
+  let(&tex, "");
+  tex = asciiToTt(sPrefix); /* asciiToTt allocates; we must deallocate */
+      /* Example: sPrefix = " 4 2,3 ax-mp  $a " */
+      /*          tex = "\ 4\ 2,3\ ax-mp\ \ \$a\ " in !g_htmlFlag mode */
+      /*          tex = " 4 2,3 ax-qmp  $a " in g_htmlFlag mode */
+  let(&texLine, "");
+
+  /* Get statement type of proof step reference */
+  i = instr(1, sPrefix, "$");
+  if (i) refType = sPrefix[i]; /* Character after the "$" */
+
+  if (g_htmlFlag || !g_oldTexFlag) {
+
+    /* Process a proof step prefix */
+    if (strlen(sPrefix)) { /* It's a proof step */
+      /* Make each token a separate table column for HTML */
+      /* This is a kludge that only works with /LEMMON style proofs! */
+      /* Note that asciiToTt() above puts "\ " when not in
+         g_htmlFlag mode, so use sPrefix instead of tex so it will work in
+         !g_oldTexFlag mode */
+
+      /* In HTML mode, sPrefix has two possible formats:
+           "2 ax-1  $a "
+           "3 1,2 ax-mp  $a "
+         In LaTeX mode (!g_htmlFlag), sPrefix has one format:
+           "8   maj=ax-1  $a "
+           "9 a1i=ax-mp $a " */
+
+      let(&tex, edit(sPrefix, 8/*no leading spaces*/
+           + 16/*reduce spaces and tabs*/
+           + 128/*no trailing spaces*/));
+
+      i = 0;
+      pos = 1;
+      while (pos) {
+        pos = instr(1, tex, " ");
+        if (pos) {
+          if (i > 3) { /* added for extra safety for the future */
+            bug(2316);
+          }
+          if (i == 0) let(&htmStep, left(tex, pos - 1));
+          if (i == 1) let(&htmHyp, left(tex, pos - 1));
+          if (i == 2) let(&htmRef, left(tex, pos - 1));
+          if (i == 3) let(&htmLocLab, left(tex, pos - 1));
+
+          let(&tex, right(tex, pos + 1));
+          i++;
+        }
+      }
+
+      if (i == 3 && htmRef[0] == '@') {
+        /* The referenced statement has no hypotheses but has a local
+           label e.g."2 a4s @2: $p" */
+        let(&htmLocLab, htmRef);
+        let(&htmRef, htmHyp);
+        let(&htmHyp, "");
+      }
+
+      if (i < 3) {
+        /* The referenced statement has no hypotheses e.g.
+           "4 ax-1 $a" */
+        let(&htmRef, htmHyp);
+        let(&htmHyp, "");
+
+        /* Change "maj=ax-1" to "ax-1" so \ref{} produced by
+           "show proof .../tex" will match \label{} produced by
+           "show statement .../tex" */
+        /* Earlier we set the noIndentFlag (Lemmon
+           proof) in the SHOW PROOF.../TEX call in metamath.c, so the
+           hypothesis ref list will be available just like in the HTML
+           output. */
+        /* We now consider "=" a bug since the call via typeProof() in
+           metamath.c now always has noIndentFlag = 1. */
+        if (!g_htmlFlag) {
+          pos = instr(1, htmRef, "=");
+          if (pos) bug(2342);
+        }
+      }
+    } /* if (strlen(sPrefix)) (end processing proof step prefix) */
+  }
+
+  if (!g_htmlFlag) {
+    if (g_oldTexFlag) {
+      /* Trim down long start prefixes so they won't overflow line,
+         by putting their tokens into \m macros */
+#define TRIMTHRESHOLD 60
+      i = (long)strlen(tex);
+      while (i > TRIMTHRESHOLD) {
+        if (tex[i] == '\\') {
+          /* Move to math part */
+          let(&texLine, cat("\\m{\\mbox{\\tt", right(tex, i + 1), "}}",
+              texLine, NULL));
+          /* Take off of prefix part */
+          let(&tex, left(tex, i));
+        }
+        i--;
+      }
+
+      printLongLine(cat(
+          "\\setbox\\startprefix=\\hbox{\\tt ", tex, "}", NULL), "", "\\");
+      let(&tex, ""); /* Deallocate */
+      tex = asciiToTt(contPrefix);
+      printLongLine(cat(
+          "\\setbox\\contprefix=\\hbox{\\tt ", tex, "}", NULL), "", "\\");
+      print2("\\startm\n");
+    }
+  } else { /* g_htmlFlag */
+    if (strlen(sPrefix)) { /* It's a proof step */
+
+      if (htmHyp[0] == 0)
+        let(&htmHyp, " ");  /* Insert blank field for Lemmon ref w/out hyp */
+
+      /* Put hyperlinks on hypothesis
+         label references in SHOW STATEMENT * /HTML, ALT_HTML output */
+      /* Use a separate tag to put into the math cell,
+         so it will link to the top of the math cell */
+      let(&htmStepTag, cat("","", NULL));
+      i = 1;
+      pos = 1;
+      while (pos && strcmp(htmHyp, " ")) {
+        pos = instr(i,htmHyp, ",");
+        if (!pos) pos = len(htmHyp) + 1;
+        let(&htmHyp, cat(left(htmHyp, i - 1),
+            "",
+            seg(htmHyp, i, pos - 1),
+            "",
+            right(htmHyp, pos),
+            NULL));
+        /* Break out of loop if we hit the end */
+        pos += 16 + len(seg(htmHyp, i, pos - 1)) + 1;
+        if (!instr(i, htmHyp, ",")) break;
+        i = pos;
+      }
+
+      /* Add a space after each comma so very long hypotheses
+         lists will wrap in an HTML table cell, e.g. gomaex3 in ql.mm */
+      pos = instr(1, htmHyp, ",");
+      while (pos) {
+        let(&htmHyp, cat(left(htmHyp, pos), " ", right(htmHyp, pos + 1), NULL));
+        pos = instr(pos + 1, htmHyp, ",");
+      }
+
+      if (refType == 'e' || refType == 'f') {
+        /* A hypothesis - don't include link */
+        printLongLine(cat("", htmStep, "",
+            htmHyp, "", htmRef,
+            "",
+            htmStepTag, /* Put the  tag at start of math symbol cell */
+            NULL), "", "\"");
+      } else {
+        if (hypStmt <= 0) {
+          printLongLine(cat("", htmStep, "",
+              htmHyp, "", htmRef,
+              "",
+              htmStepTag, /* Put the  tag at start of math symbol cell */
+              NULL), "", "\"");
+        } else {
+          /* Include step number reference.  The idea is that this will
+             help the user to recognized "important" (vs. early trivial
+             logic) steps.  This prints a small pink statement number
+             after the hypothesis statement label. */
+          let(&tmp, "");
+          tmp = pinkHTML(hypStmt);
+
+          /* Get description for mod below */
+          let(&descr, ""); /* Deallocate previous description */
+          descr = getDescription(hypStmt);
+          let(&descr, edit(descr, 4 + 16)); /* Discard lf/cr; reduce spaces */
+#define MAX_DESCR_LEN 87
+          if (strlen(descr) > MAX_DESCR_LEN) { /* Truncate long lines */
+            i = MAX_DESCR_LEN - 3;
+            while (i >= 0) { /* Get to previous word boundary */
+              if (descr[i] == ' ') break;
+              i--;
+            }
+            let(&descr, cat(left(descr, i), "...", NULL));
+          }
+          i = 0;
+          while (descr[i] != 0) { /* Convert double quote to single */
+            descr[i] = (char)(descr[i] == '"' ? '\'' : descr[i]);
+            i++;
+          }
+
+          printLongLine(cat("", htmStep, "",
+              htmHyp, "", htmRef,
+              "", tmp,
+              "",
+              htmStepTag, /* Put the  tag at start of math symbol cell */
+              NULL), "", "\"");
+        }
+      }
+      /* Indent web proof displays */
+      let(&tmp, "");
+      for (i = 1; i <= indentationLevel; i++) {
+        let(&tmp, cat(tmp, ". ", NULL));
+      }
+      let(&tmp, cat("",
+          tmp,
+          str((double)(indentationLevel + INDENTATION_OFFSET)), "",
+          NULL));
+      printLongLine(tmp, "", "\"");
+      let(&tmp, "");
+    } /* strlen(sPrefix) */
+  } /* g_htmlFlag */
+  let(&tex, ""); /* Deallocate */
+  let(&sPrefix, ""); /* Deallocate */
+
+  let(&tex, "");
+  tex = getTexLongMath(mathString, hypStmt);
+  let(&texLine, cat(texLine, tex, NULL));
+
+  if (!g_htmlFlag) {  /* LaTeX */
+    if (!g_oldTexFlag) {
+      if (refType == 'e' || refType == 'f') {
+        /* A hypothesis - don't include \ref{} */
+        printLongLine(cat("  ",
+            /* If not first step, so print "\\" LaTeX line break */
+            !strcmp(htmStep, "1") ? "" : "\\\\ ",
+            htmStep,  /* Step number */
+            " && ",
+            " & ",
+            texLine,
+            /* Don't put space to help prevent bad line break */
+            "&\\text{Hyp~",
+            /* The following puts a hypothesis number such as "2" if
+               $e label is "abc.2"; if no ".", will be whole label */
+            right(htmRef, instr(1, htmRef, ".") + 1),
+            "}\\notag%",
+            /* Add full label as LaTeX comment - note lack of space after
+               "%" above to prevent bad line break */
+            htmRef, NULL),
+            "    \\notag \\\\ && & \\qquad ",  /* Continuation line prefix */
+            " ");
+      } else {
+        printLongLine(cat("  ",
+            /* If not first step, so print "\\" LaTeX line break */
+            !strcmp(htmStep, "1") ? "" : "\\\\ ",
+            htmStep,  /* Step number */
+            " && ",
+
+            /* Local label if any e.g. "@2:" */
+            (htmLocLab[0] != 0) ? cat(htmLocLab, "\\ ", NULL) : "",
+
+            " & ",
+            texLine,
+            /* Don't put space to help prevent bad line break */
+
+            /* Surround \ref with \mbox for non-math-mode
+               symbolic labels (due to \tag{..} in mmcmds.c).  Also,
+               move hypotheses to after referenced label */
+            "&",
+            "(",
+
+            /* Don't make local label a \ref */
+            (htmRef[0] != '@') ?
+                cat("\\mbox{\\ref{eq:", htmRef, "}}", NULL)
+                : htmRef,
+
+            htmHyp[0] ? "," : "",
+            htmHyp,
+            ")\\notag", NULL),
+
+            "    \\notag \\\\ && & \\qquad ",  /* Continuation line prefix */
+            " ");
+      }
+    } else {
+      printLongLine(texLine, "", "\\");
+      print2("\\endm\n");
+    }
+  } else {  /* HTML */
+    printLongLine(cat(texLine, "", NULL), "", "\"");
+  }
+
+  g_outputToString = 0; /* Restore normal output */
+  fprintf(g_texFilePtr, "%s", g_printString);
+  let(&g_printString, "");
+
+  let(&descr, ""); /*Deallocate */
+  let(&htmStep, ""); /* Deallocate */
+  let(&htmStepTag, ""); /* Deallocate */
+  let(&htmHyp, ""); /* Deallocate */
+  let(&htmRef, ""); /* Deallocate */
+  let(&htmLocLab, ""); /* Deallocate */
+  let(&tmp, ""); /* Deallocate */
+  let(&texLine, ""); /* Deallocate */
+  let(&tex, ""); /* Deallocate */
+} /* printTexLongMath */
+
+void printTexTrailer(flag texTrailerFlag) {
+
+  if (texTrailerFlag) {
+    g_outputToString = 1; /* Redirect print2 and printLongLine to g_printString */
+    if (!g_htmlFlag) let(&g_printString, "");
+        /* May have stuff to be printed */
+    if (!g_htmlFlag) {
+      print2("\\end{document}\n");
+    } else {
+      print2("\n");
+      print2("\n", "%");
+      print2("\n", "%");
+      print2("
 \n"); + print2("\n"); + print2("Copyright terms:\n"); + print2("Public domain\n"); + print2("\n", "%"); + print2("\n"); + print2("\n"); + print2("W3C validator\n"); + print2("
\n"); + print2("\n"); + } + g_outputToString = 0; /* Restore normal output */ + fprintf(g_texFilePtr, "%s", g_printString); + let(&g_printString, ""); + } + +} /* printTexTrailer */ + + +/* WRITE THEOREM_LIST command: Write out theorem list + into mmtheorems.html, mmtheorems1.html,... */ +void writeTheoremList(long theoremsPerPage, flag showLemmas, flag noVersioning) +{ + nmbrString *nmbrStmtNmbr = NULL_NMBRSTRING; + long pages, page, assertion, assertions, lastAssertion; + long s, p, i1, i2; + vstring str1 = ""; + vstring str3 = ""; + vstring str4 = ""; + vstring prevNextLinks = ""; + long partCntr; /* Counter for hugeHdr */ + long sectionCntr; /* Counter for bigHdr */ + long subsectionCntr; /* Counter for smallHdr */ + long subsubsectionCntr; /* Counter for tinyHdr */ + vstring outputFileName = ""; + FILE *outputFilePtr; + long passNumber; /* for summary/detailed table of contents */ + + /* for table of contents */ + vstring hugeHdr = ""; + vstring bigHdr = ""; + vstring smallHdr = ""; + vstring tinyHdr = ""; + vstring hugeHdrComment = ""; + vstring bigHdrComment = ""; + vstring smallHdrComment = ""; + vstring tinyHdrComment = ""; + long stmt, i; + pntrString *pntrHugeHdr = NULL_PNTRSTRING; + pntrString *pntrBigHdr = NULL_PNTRSTRING; + pntrString *pntrSmallHdr = NULL_PNTRSTRING; + pntrString *pntrTinyHdr = NULL_PNTRSTRING; + pntrString *pntrHugeHdrComment = NULL_PNTRSTRING; + pntrString *pntrBigHdrComment = NULL_PNTRSTRING; + pntrString *pntrSmallHdrComment = NULL_PNTRSTRING; + pntrString *pntrTinyHdrComment = NULL_PNTRSTRING; + vstring hdrCommentMarker = ""; + vstring hdrCommentAnchor = ""; + flag hdrCommentAnchorDone = 0; + + /* Populate the statement map */ + /* ? ? ? Future: is assertions same as g_Statement[g_statements].pinkNumber? */ + nmbrLet(&nmbrStmtNmbr, nmbrSpace(g_statements + 1)); + assertions = 0; /* Number of $p's + $a's */ + for (s = 1; s <= g_statements; s++) { + if (g_Statement[s].type == a_ || g_Statement[s].type == p_) { + assertions++; /* Corresponds to pink number */ + nmbrStmtNmbr[assertions] = s; + } + } + if (assertions != g_Statement[g_statements].pinkNumber) bug(2328); + + /* Table of contents */ + /* Allocate array for section headers found */ + pntrLet(&pntrHugeHdr, pntrSpace(g_statements + 1)); + pntrLet(&pntrBigHdr, pntrSpace(g_statements + 1)); + pntrLet(&pntrSmallHdr, pntrSpace(g_statements + 1)); + pntrLet(&pntrTinyHdr, pntrSpace(g_statements + 1)); + pntrLet(&pntrHugeHdrComment, pntrSpace(g_statements + 1)); + pntrLet(&pntrBigHdrComment, pntrSpace(g_statements + 1)); + pntrLet(&pntrSmallHdrComment, pntrSpace(g_statements + 1)); + pntrLet(&pntrTinyHdrComment, pntrSpace(g_statements + 1)); + + pages = ((assertions - 1) / theoremsPerPage) + 1; + for (page = 0; page <= pages; page++) { + /* Open file */ + let(&outputFileName, + cat("mmtheorems", (page > 0) ? str((double)page) : "", ".html", NULL)); + print2("Creating %s\n", outputFileName); + outputFilePtr = fSafeOpen(outputFileName, "w", noVersioning); + if (!outputFilePtr) goto TL_ABORT; /* Couldn't open it (error msg was provided)*/ + + /* Output header */ + /* TODO 14-Jan-2016: why aren't we using printTexHeader? */ + + g_outputToString = 1; + print2("\n"); + print2("\n"); + print2("\n"); + print2("%s%s\n", ""); + /* Improve mobile device display per David A. Wheeler */ + print2("\n"); + + print2("\n"); + printLongLine(g_htmlCSS, "", " "); + + /* + print2("%s\n", cat("", htmlTitle, " - ", + / * Strip off ".html" * / + left(outputFileName, (long)strlen(outputFileName) - 5), + "", NULL)); + */ + /* Put page name before "Metamath Proof Explorer" etc. */ + printLongLine(cat("", + ((page == 0) + ? "TOC of Theorem List" + : cat("P. ", str((double)page), " of Theorem List", NULL)), + + " - ", + htmlTitle, + "", + NULL), "", "\""); + /* Icon for bookmark */ + print2("%s%s\n", ""); + + /* Image alignment fix */ + print2("\n"); + + print2("\n"); + print2("\n"); + print2("\n", "%"); + print2("", NULL), "", "\""); + printLongLine(cat( + "\n"); + } else { + print2("\n"); + } + } + + /* Make breadcrumb font to match other pages */ + print2("\n"); + print2( + "\n"); + print2("
", g_htmlHome, "", htmlTitle, "", + "
Theorem List (", + ((page == 0) + ? "Table of Contents" + : cat("p. ", str((double)page), " of ", str((double)pages), NULL)), + ")", + NULL), "", "\""); + + + /* Put Previous/Next links into web page */ + print2("
\n"); + + /* Output title with current page */ + /* Output previous and next */ + + + /* Assign prevNextLinks once here since it is used 3 times */ + let(&prevNextLinks, cat(" 0) + ? ((page - 1 > 0) ? str((double)page - 1) : "") + : ((pages > 0) ? str((double)pages) : ""), + ".html\">", NULL)); + if (page > 0) { + let(&prevNextLinks, cat(prevNextLinks, + "< Previous  ", NULL)); + } else { + let(&prevNextLinks, cat(prevNextLinks, "< Wrap  ", NULL)); + } + let(&prevNextLinks, cat(prevNextLinks, "", NULL)); + if (page < pages) { + let(&prevNextLinks, cat(prevNextLinks, "Next >", NULL)); + } else { + let(&prevNextLinks, cat(prevNextLinks, "Wrap >", NULL)); + } + + printLongLine(prevNextLinks, + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + + /* Finish up header */ + /* Print the GIF/Unicode Font choice, if directories are specified */ + if (htmlDir[0]) { + if (g_altHtmlFlag) { + print2("
Bad symbols? Try the\n"); + print2("
GIF\n", htmlDir, outputFileName); + print2("version.
Browser slow? Try the\n"); + print2("
Unicode\n", altHtmlDir, outputFileName); + print2("version.
\n"); + print2("
\n"); /* Add a little more vertical space */ + + /* Print some useful links */ + print2("Mirrors\n"); + print2(" > \n"); + print2("Metamath Home Page\n"); + + /* Normally, g_htmlBibliography in the .mm file will have the + project home page, and we depend on this here rather than + extracting from g_htmlHome */ + print2(" > \n", g_htmlBibliography); + + /* Put a meaningful abbreviation for the project home page + by extracting capital letters from title */ + let(&str1, ""); + s = (long)strlen(htmlTitle); + for (i = 0; i < s; i++) { + if (htmlTitle[i] >= 'A' && htmlTitle[i] <= 'Z') { + let(&str1, cat(str1, chr(htmlTitle[i]), NULL)); + } + } + print2("%s Home Page\n", str1); + + if (page != 0) { + print2(" > \n"); + print2("Theorem List Contents\n"); + } else { + print2(" > \n"); + print2("Theorem List Contents\n"); + } + + /* Assume there is a Most Recent page when the .mm has a mathbox stmt + (currently set.mm and iset.mm) */ + if (g_mathboxStmt < g_statements + 1) { + print2(" > \n"); + print2("Recent Proofs\n"); + } + + + print2("      \n", GREEN_TITLE_COLOR); + print2("This page: \n"); + + if (page == 0) { + print2(" Detailed Table of Contents \n"); + } + + print2("Page List\n"); + + /* Change breadcrumb font to match other pages */ + print2("
\n"); + print2("
\n"); + + print2("
\n"); + + /* Write out HTML page so far */ + fprintf(outputFilePtr, "%s", g_printString); + g_outputToString = 0; + let(&g_printString, ""); + + /* Add table of contents to first WRITE THEOREM page */ + if (page == 0) { /* We're on ToC page */ + + /* Pass 1: table of contents summary; pass 2: detail */ + for (passNumber = 1; passNumber <= 2; passNumber++) { + g_outputToString = 1; + if (passNumber == 1) { + print2("

Table of Contents Summary
\n"); + } else { + print2("

Detailed Table of Contents
\n"); + print2("(* means the section header has a description)
\n"); + } + + fprintf(outputFilePtr, "%s", g_printString); + + g_outputToString = 0; + let(&g_printString, ""); + + let(&hugeHdr, ""); + let(&bigHdr, ""); + let(&smallHdr, ""); + let(&tinyHdr, ""); + let(&hugeHdrComment, ""); + let(&bigHdrComment, ""); + let(&smallHdrComment, ""); + let(&tinyHdrComment, ""); + partCntr = 0; /* Initialize counters */ + sectionCntr = 0; + subsectionCntr = 0; + subsubsectionCntr = 0; + for (stmt = 1; stmt <= g_statements; stmt++) { + /* Output the headers for $a and $p statements */ + if (g_Statement[stmt].type == p_ || g_Statement[stmt].type == a_) { + hdrCommentAnchorDone = 0; + getSectionHeadings(stmt, &hugeHdr, &bigHdr, &smallHdr, + &tinyHdr, + &hugeHdrComment, &bigHdrComment, &smallHdrComment, + &tinyHdrComment, + 0, /* fineResolution */ + 0 /* fullComment */); + if (hugeHdr[0] || bigHdr[0] || smallHdr[0] || tinyHdr[0]) { + /* Write to the table of contents */ + g_outputToString = 1; + i = ((g_Statement[stmt].pinkNumber - 1) / theoremsPerPage) + + 1; /* Page # */ + /* let(&str3, cat("mmtheorems", (i == 1) ? "" : str(i), ".html#", */ + /* Note that page 1 has no number after mmtheorems */ + let(&str3, cat("mmtheorems", str((double)i), ".html#", + /* g_Statement[stmt].labelName, NULL)); */ + "mm", str((double)(g_Statement[stmt].pinkNumber)), NULL)); + /* Link to page/location - no theorem can be named "mm*" */ + let(&str4, ""); + str4 = pinkHTML(stmt); + if (hugeHdr[0]) { + + /* Create part number */ + partCntr++; + sectionCntr = 0; + subsectionCntr = 0; + subsubsectionCntr = 0; + let(&hugeHdr, cat("PART ", str((double)partCntr), "  ", + hugeHdr, NULL)); + + /* Put an asterisk before the header if the header has a comment */ + if (hugeHdrComment[0] != 0 && passNumber == 2) { + let(&hdrCommentMarker, "*"); + if (hdrCommentAnchorDone == 0) { + let(&hdrCommentAnchor, cat( + "", + + /* "​" is a "zero-width" space to + workaround Chrome bug that jumps to wrong anchor. */ + "​", + + NULL)); + hdrCommentAnchorDone = 1; + } else { + let(&hdrCommentAnchor, ""); + } + } else { + let(&hdrCommentMarker, ""); + let(&hdrCommentAnchor, ""); + } + + printLongLine(cat( + /* In detailed section, add an anchor to reach it from + summary section */ + (passNumber == 2) ? + cat("", + /* "​" is a "zero-width" space to + workaround Chrome bug that jumps to wrong anchor. */ + "​", + NULL) : "", + + /* Add an anchor to the "sandbox" theorem + for use by mmrecent.html */ + /* We use "sandbox:bighdr" for both here and + below so that either huge or big header type could + be used to start mathbox sections */ + (stmt == g_mathboxStmt && bigHdr[0] == 0 + && passNumber == 1 /* Only in summary TOC */ + ) ? + /* Note the colon so it won't conflict w/ theorem + name anchor */ + /* "​" is a "zero-width" space to + workaround Chrome bug that jumps to wrong anchor. */ + "​" : "", + + hdrCommentAnchor, + "", + hdrCommentMarker, + hugeHdr, "", + "
", NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + if (passNumber == 2) { + /* Assign to array for use during theorem output */ + let((vstring *)(&pntrHugeHdr[stmt]), hugeHdr); + let((vstring *)(&pntrHugeHdrComment[stmt]), hugeHdrComment); + } + let(&hugeHdr, ""); + let(&hugeHdrComment, ""); + } + if (bigHdr[0]) { + + /* Create section number */ + sectionCntr++; + subsectionCntr = 0; + subsubsectionCntr = 0; + let(&bigHdr, cat(str((double)partCntr), ".", str((double)sectionCntr), + "  ", + bigHdr, NULL)); + + /* Put an asterisk before the header if the header has + a comment */ + if (bigHdrComment[0] != 0 && passNumber == 2) { + let(&hdrCommentMarker, "*"); + if (hdrCommentAnchorDone == 0) { + let(&hdrCommentAnchor, cat( + "", + + /* "​" is a "zero-width" space to + workaround Chrome bug that jumps to wrong anchor. */ + "​", + + NULL)); + hdrCommentAnchorDone = 1; + } else { + let(&hdrCommentAnchor, ""); + } + } else { + let(&hdrCommentMarker, ""); + let(&hdrCommentAnchor, ""); + } + + printLongLine(cat( + "      ", /* Indentation spacing */ + + /* In detailed section, add an anchor to reach it from + summary section */ + (passNumber == 2) ? + cat("", + + /* "​" is a "zero-width" space to + workaround Chrome bug that jumps to wrong anchor. */ + "​", + + NULL) + : "", + + /* Add an anchor to the "sandbox" theorem + for use by mmrecent.html */ + (stmt == g_mathboxStmt + && passNumber == 1 /* Only in summary TOC */ + ) ? + /* Note the colon so it won't conflict w/ theorem + name anchor */ + /* "​" is a "zero-width" space to + workaround Chrome bug that jumps to wrong anchor. */ + "​" : "", + hdrCommentAnchor, + "", + hdrCommentMarker, + bigHdr, "", + "
", NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + if (passNumber == 2) { + /* Assign to array for use during theorem list output */ + let((vstring *)(&pntrBigHdr[stmt]), bigHdr); + let((vstring *)(&pntrBigHdrComment[stmt]), bigHdrComment); + } + let(&bigHdr, ""); + let(&bigHdrComment, ""); + } + if (smallHdr[0] + && passNumber == 2) { /* Skip in pass 1 (summary) */ + + /* Create subsection number */ + subsectionCntr++; + subsubsectionCntr = 0; + let(&smallHdr, cat(str((double)partCntr), ".", + str((double)sectionCntr), + ".", str((double)subsectionCntr), "  ", + smallHdr, NULL)); + + /* Put an asterisk before the header if the header has + a comment */ + if (smallHdrComment[0] != 0 && passNumber == 2) { + let(&hdrCommentMarker, "*"); + if (hdrCommentAnchorDone == 0) { + let(&hdrCommentAnchor, cat("", + + /* "​" is a "zero-width" space to + workaround Chrome bug that jumps to wrong anchor. */ + "​", + + NULL)); + hdrCommentAnchorDone = 1; + } else { + let(&hdrCommentAnchor, ""); + } + } else { + let(&hdrCommentMarker, ""); + let(&hdrCommentAnchor, ""); + } + + printLongLine(cat("            ", + hdrCommentAnchor, + "", + hdrCommentMarker, + smallHdr, "", + "   ", + g_Statement[stmt].labelName, "", + str4, + "
", NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + /* Assign to array for use during theorem output */ + let((vstring *)(&pntrSmallHdr[stmt]), smallHdr); + let(&smallHdr, ""); + let((vstring *)(&pntrSmallHdrComment[stmt]), smallHdrComment); + let(&smallHdrComment, ""); + } + + if (tinyHdr[0] && passNumber == 2) { /* Skip in pass 1 (summary) */ + + /* Create subsection number */ + subsubsectionCntr++; + let(&tinyHdr, cat(str((double)partCntr), ".", + str((double)sectionCntr), + ".", str((double)subsectionCntr), + ".", str((double)subsubsectionCntr), "  ", + tinyHdr, NULL)); + + /* Put an asterisk before the header if the header has + a comment */ + if (tinyHdrComment[0] != 0 && passNumber == 2) { + let(&hdrCommentMarker, "*"); + if (hdrCommentAnchorDone == 0) { + let(&hdrCommentAnchor, cat(" ", + + /* "​" is a "zero-width" space to + workaround Chrome bug that jumps to wrong anchor. */ + "​", + + NULL)); + hdrCommentAnchorDone = 1; + } else { + let(&hdrCommentAnchor, ""); + } + } else { + let(&hdrCommentMarker, ""); + let(&hdrCommentAnchor, ""); + } + + printLongLine(cat( + "                  ", + hdrCommentAnchor, + "", + hdrCommentMarker, + tinyHdr, "", + "   ", + g_Statement[stmt].labelName, "", + str4, + "
", NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + /* Assign to array for use during theorem output */ + let((vstring *)(&pntrTinyHdr[stmt]), tinyHdr); + let(&tinyHdr, ""); + let((vstring *)(&pntrTinyHdrComment[stmt]), tinyHdrComment); + let(&tinyHdrComment, ""); + } + + fprintf(outputFilePtr, "%s", g_printString); + g_outputToString = 0; + let(&g_printString, ""); + } /* if huge or big or small or tiny header */ + } /* if $a or $p */ + } /* next stmt */ + /* 8-May-2015 nm Do we need the HR below? */ + fprintf(outputFilePtr, "
\n"); + + } /* next passNumber */ + + } /* if page 0 */ + /* End table of contents */ + + /* Just skip over instead of a big if indent */ + if (page == 0) goto SKIP_LIST; + + + /* Put in color key */ + g_outputToString = 1; + print2("\n"); + if (g_extHtmlStmt < g_mathboxStmt) { /* g_extHtmlStmt >= g_mathboxStmt in ql.mm */ + /* ?? Currently this is customized for set.mm only!! */ + print2("

\n"); + print2("

\n"); + print2("\n"); + print2("\n"); + print2("\n"); + print2("\n"); + print2("\n"); + print2("\n"); + + /* Hilbert Space Explorer */ + print2("\n"); + print2("\n"); + print2("\n"); + print2("\n"); + + + /* Mathbox stuff */ + print2("\n"); + print2("\n"); + print2("\n"); + print2("\n"); + + + print2("
Color key:     Metamath Proof Explorer\n"); + + let(&str3, ""); + if (g_Statement[g_extHtmlStmt].pinkNumber <= 0) bug(2332); + str3 = pinkRangeHTML(nmbrStmtNmbr[1], + nmbrStmtNmbr[g_Statement[g_extHtmlStmt].pinkNumber - 1]); + printLongLine(cat("
(", str3, ")", NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + + print2("
 \"Hilbert\n"); + print2(" Hilbert Space Explorer\n"); + + let(&str3, ""); + if (g_Statement[g_mathboxStmt].pinkNumber <= 0) bug(2333); + str3 = pinkRangeHTML(g_extHtmlStmt, + nmbrStmtNmbr[g_Statement[g_mathboxStmt].pinkNumber - 1]); + printLongLine(cat("
(", str3, ")", NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + + print2("
 \"Users'\n"); + print2(" Users' Mathboxes\n"); + + let(&str3, ""); + str3 = pinkRangeHTML(g_mathboxStmt, nmbrStmtNmbr[assertions]); + printLongLine(cat("
(", str3, ")", NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + + print2("
 
\n"); + } /* end if (g_extHtmlStmt < g_mathboxStmt) */ + + /* Write out HTML page so far */ + fprintf(outputFilePtr, "%s", g_printString); + g_outputToString = 0; + let(&g_printString, ""); + + + /* Write the main table header */ + g_outputToString = 1; + print2("\n"); + print2("

\n"); + print2("\n", htmlTitle); + let(&str3, ""); + if (page < 1) bug(2335); /* Page 0 ToC should have been skipped */ + str3 = pinkHTML(nmbrStmtNmbr[(page - 1) * theoremsPerPage + 1]); + let(&str3, right(str3, (long)strlen(PINK_NBSP) + 1)); /* Discard " " */ + let(&str4, ""); + str4 = pinkHTML((page < pages) ? + nmbrStmtNmbr[page * theoremsPerPage] : + nmbrStmtNmbr[assertions]); + let(&str4, right(str4, (long)strlen(PINK_NBSP) + 1)); /* Discard " " */ + printLongLine(cat("",NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + print2("\n"); + print2("\n"); + print2("\n"); + print2("\n"); + print2("\n"); + print2("\n"); + fprintf(outputFilePtr, "%s", g_printString); + g_outputToString = 0; + let(&g_printString, ""); + + /* Find the last assertion that will be printed on the page, so + we will know when a separator between theorems is not needed */ + lastAssertion = 0; + for (assertion = (page - 1) * theoremsPerPage + 1; + assertion <= page * theoremsPerPage; assertion++) { + if (assertion > assertions) break; /* We're beyond the end */ + + lastAssertion = assertion; + } + + /* Output theorems on the page */ + for (assertion = (page - 1) * theoremsPerPage + 1; + assertion <= page * theoremsPerPage; assertion++) { + if (assertion > assertions) break; /* We're beyond the end */ + + s = nmbrStmtNmbr[assertion]; /* Statement number */ + + /* Construct the statement type label */ + if (g_Statement[s].type == p_) { + let(&str1, "Theorem"); + } else if (!strcmp("ax-", left(g_Statement[s].labelName, 3))) { + let(&str1, "Axiom"); + } else if (!strcmp("df-", left(g_Statement[s].labelName, 3))) { + let(&str1, "Definition"); + } else { + let(&str1, "Syntax"); + } + + if (s == s + 0) goto skip_date; + /* OBSOLETE */ + /* Get the date in the comment section after the statement */ + let(&str1, space(g_Statement[s + 1].labelSectionLen)); + memcpy(str1, g_Statement[s + 1].labelSectionPtr, + (size_t)(g_Statement[s + 1].labelSectionLen)); + let(&str1, edit(str1, 2)); /* Discard spaces and tabs */ + i1 = instr(1, str1, "$(["); + i2 = instr(i1, str1, "]$)"); + if (i1 && i2) { + let(&str1, seg(str1, i1 + 3, i2 - 1)); + } else { + let(&str1, ""); + } + skip_date: + + let(&str3, ""); + str3 = getDescription(s); + let(&str4, ""); + str4 = pinkHTML(s); /* Get little pink number */ + /* Output the description comment */ + /* Break up long lines for text editors with printLongLine */ + let(&g_printString, ""); + g_outputToString = 1; + print2("\n"); /* Blank line for HTML source human readability */ + + /* Table of contents */ + if (((vstring)(pntrHugeHdr[s]))[0]) { /* There is a major part break */ + printLongLine(cat( + /* The header */ + ""); + + printLongLine(cat( + /* Separator row */ + "", + NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + } + if (((vstring)(pntrBigHdr[s]))[0]) { /* There is a major section break */ + printLongLine(cat( + /* The header */ + ""); + + printLongLine(cat( + /* Separator row */ + "", + NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + } + if (((vstring)(pntrSmallHdr[s]))[0]) { /* There is a minor sec break */ + printLongLine(cat( + /* The header */ + ""); + + printLongLine(cat( + /* Separator row */ + "", + NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + } + + if (((vstring)(pntrTinyHdr[s]))[0]) { /* There is a subsubsection break */ + printLongLine(cat( + /* The header */ + ""); + + printLongLine(cat( + /* Separator row */ + "", + NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + } + + printLongLine(cat( + (s < g_extHtmlStmt) + ? "" + : (s < g_mathboxStmt) + ? cat("", NULL) + : cat("", NULL), + "\n"); + } else { + /* Output the table row with the math content */ + printLongLine(cat("" + : (s < g_mathboxStmt) + ? cat(" BGCOLOR=", PURPLISH_BIBLIO_COLOR, ">", NULL) + : cat(" BGCOLOR=", SANDBOX_COLOR, ">", NULL), + "", NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + } + + g_outputToString = 0; + fprintf(outputFilePtr, "%s", g_printString); + let(&g_printString, ""); + + if (assertion != lastAssertion) { + /* Put separator row if not last theorem */ + g_outputToString = 1; + printLongLine(cat("", NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + g_outputToString = 0; + fprintf(outputFilePtr, "%s", g_printString); + let(&g_printString, ""); + } + } /* next assertion */ + + /* Output trailer */ + g_outputToString = 1; + print2("
Theorem List for ", htmlTitle, + " - ", str3, "-", str4, + "   *Has distinct variable group(s)" + "
TypeLabelDescription
Statement
 
", + "", /* Anchor for table of contents */ + (vstring)(pntrHugeHdr[s]), + "
", + NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + + /* The comment part of the header, if any */ + if (((vstring)(pntrHugeHdrComment[s]))[0]) { + + /* Open the table row */ + /* keep comment in same table cell */ + print2("%s\n", "

"); + + /* We are currently printing to g_printString to allow use of + printLongLine(); however, the rendering function + printTexComment uses g_printString internally, so we have to + flush the current g_printString and turn off g_outputToString mode + in order to call the rendering function printTexComment. */ + /* (Question: why do the calls to printTexComment for statement + descriptions, later, not need to flush the g_printString? Is the + flushing code here redundant?) */ + /* Clear out the g_printString output in prep for printTexComment */ + g_outputToString = 0; + fprintf(outputFilePtr, "%s", g_printString); + let(&g_printString, ""); + g_showStatement = s; /* For printTexComment */ + g_texFilePtr = outputFilePtr; /* For printTexComment */ + printTexComment( /* Sends result to g_texFilePtr */ + (vstring)(pntrHugeHdrComment[s]), + 0, /* 1 = htmlCenterFlag */ + PROCESS_EVERYTHING, /* actionBits */ + 1 /* 1 = fileCheck */); + g_texFilePtr = NULL; + g_outputToString = 1; /* Restore after printTexComment */ + } + + /* Close the table row */ + print2("%s\n", "

", + " 
", + "", /* Anchor for table of contents */ + (vstring)(pntrBigHdr[s]), + "
", + NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + + /* The comment part of the header, if any */ + if (((vstring)(pntrBigHdrComment[s]))[0]) { + + /* Open the table row */ + /* keep comment in same table cell */ + print2("%s\n", "

"); + + /* We are currently printing to g_printString to allow use of + printLongLine(); however, the rendering function + printTexComment uses g_printString internally, so we have to + flush the current g_printString and turn off g_outputToString mode + in order to call the rendering function printTexComment. */ + /* (Question: why do the calls to printTexComment for statement + descriptions, later, not need to flush the g_printString? Is the + flushing code here redundant?) */ + /* Clear out the g_printString output in prep for printTexComment */ + g_outputToString = 0; + fprintf(outputFilePtr, "%s", g_printString); + let(&g_printString, ""); + g_showStatement = s; /* For printTexComment */ + g_texFilePtr = outputFilePtr; /* For printTexComment */ + printTexComment( /* Sends result to g_texFilePtr */ + (vstring)(pntrBigHdrComment[s]), + 0, /* 1 = htmlCenterFlag */ + PROCESS_EVERYTHING, /* actionBits */ + 1 /* 1 = fileCheck */); + g_texFilePtr = NULL; + g_outputToString = 1; /* Restore after printTexComment */ + } + + /* Close the table row */ + print2("%s\n", "

", + " 
", + "", /* Anchor for table of contents */ + (vstring)(pntrSmallHdr[s]), + "
", + NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + + /* The comment part of the header, if any */ + if (((vstring)(pntrSmallHdrComment[s]))[0]) { + + /* Open the table row */ + /* keep comment in same table cell */ + print2("%s\n", "

"); + + /* We are currently printing to g_printString to allow use of + printLongLine(); however, the rendering function + printTexComment uses g_printString internally, so we have to + flush the current g_printString and turn off g_outputToString mode + in order to call the rendering function printTexComment. */ + /* (Question: why do the calls to printTexComment for statement + descriptions, later, not need to flush the g_printString? Is the + flushing code here redundant?) */ + /* Clear out the g_printString output in prep for printTexComment */ + g_outputToString = 0; + fprintf(outputFilePtr, "%s", g_printString); + let(&g_printString, ""); + g_showStatement = s; /* For printTexComment */ + g_texFilePtr = outputFilePtr; /* For printTexComment */ + printTexComment( /* Sends result to g_texFilePtr */ + (vstring)(pntrSmallHdrComment[s]), + 0, /* 1 = htmlCenterFlag */ + PROCESS_EVERYTHING, /* actionBits */ + 1 /* 1 = fileCheck */); + g_texFilePtr = NULL; + g_outputToString = 1; /* Restore after printTexComment */ + } + + /* Close the table row */ + print2("%s\n", "

", + " 
", + "", /* Anchor for table of contents */ + (vstring)(pntrTinyHdr[s]), + "
", + NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + + /* The comment part of the header, if any */ + if (((vstring)(pntrTinyHdrComment[s]))[0]) { + + /* Open the table row */ + /* keep comment in same table cell */ + print2("%s\n", "

"); + + /* We are currently printing to g_printString to allow use of + printLongLine(); however, the rendering function + printTexComment uses g_printString internally, so we have to + flush the current g_printString and turn off g_outputToString mode + in order to call the rendering function printTexComment. */ + /* (Question: why do the calls to printTexComment for statement + descriptions, later, not need to flush the g_printString? Is the + flushing code here redundant?) */ + /* Clear out the g_printString output in prep for printTexComment */ + g_outputToString = 0; + fprintf(outputFilePtr, "%s", g_printString); + let(&g_printString, ""); + g_showStatement = s; /* For printTexComment */ + g_texFilePtr = outputFilePtr; /* For printTexComment */ + printTexComment( /* Sends result to g_texFilePtr */ + (vstring)(pntrTinyHdrComment[s]), + 0, /* 1 = htmlCenterFlag */ + PROCESS_EVERYTHING, /* actionBits */ + 1 /* 1 = fileCheck */); + g_texFilePtr = NULL; + g_outputToString = 1; /* Restore after printTexComment */ + } + + /* Close the table row */ + print2("%s\n", "

", + " 
", /* IE breaks up the date */ + str1, /* Date */ + "", + g_Statement[s].labelName, "", + str4, + + /* Add asterisk if statement has distinct var groups */ + (nmbrLen(g_Statement[s].reqDisjVarsA) > 0) ? "*" : "", + + "", + /* Add anchor for hyperlinking to the table row */ + "", + + NULL), /* Description */ + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + + g_showStatement = s; /* For printTexComment */ + g_outputToString = 0; /* For printTexComment */ + g_texFilePtr = outputFilePtr; /* For printTexComment */ + printTexComment( /* Sends result to g_texFilePtr */ + str3, + 0, /* 1 = htmlCenterFlag */ + PROCESS_EVERYTHING, /* actionBits */ + 1 /* 1 = fileCheck */); + g_texFilePtr = NULL; + g_outputToString = 1; /* Restore after printTexComment */ + + /* Get HTML hypotheses => assertion */ + let(&str4, ""); + str4 = getTexOrHtmlHypAndAssertion(s); /* In mmwtex.c */ + + /* Suppress the math content of lemmas, which can + be very big and not interesting */ + if (!strcmp(left(str3, 10), "Lemma for ") && !showLemmas) { + /* Suppress the table row with the math content */ + print2(" [Auxiliary lemma - not displayed.]
", + str4, "
", + " 
\n"); + print2("\n"); + + SKIP_LIST: /* (skipped when page == 0) */ + g_outputToString = 1; /* To compensate for skipped assignment above */ + + + /* Put extra Prev/Next hyperlinks here for convenience */ + print2("\n", '%'); + print2(" \n"); + print2(" \n"); + print2(" \n"); + print2(" \n"); + print2(" \n"); + print2("
\n", '%'); + print2("  \n"); + print2("  \n"); + printLongLine(cat(" ", prevNextLinks, NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + print2("
\n"); + + + print2("
\n"); + + + g_outputToString = 0; + fprintf(outputFilePtr, "%s", g_printString); + let(&g_printString, ""); + + + fprintf(outputFilePtr, "\n"); + fprintf(outputFilePtr, "
\n"); + fprintf(outputFilePtr, "Page List\n"); + fprintf(outputFilePtr, "
\n"); + + + /* Output links to the other pages */ + fprintf(outputFilePtr, "Jump to page: \n"); + for (p = 0; p <= pages; p++) { + + /* Construct the pink number range */ + let(&str3, ""); + if (p > 0) { + str3 = pinkRangeHTML( + nmbrStmtNmbr[(p - 1) * theoremsPerPage + 1], + (p < pages) ? + nmbrStmtNmbr[p * theoremsPerPage] : + nmbrStmtNmbr[assertions]); + } + + if (p == page) { + /* Current page shouldn't have link to self */ + let(&str1, (p == 0) ? "Contents" : str((double)p)); + } else { + let(&str1, cat("" : ".html\">", */ + ".html\">", + + (p == 0) ? "Contents" : str((double)p), + "", NULL)); + } + let(&str1, cat(str1, PINK_NBSP, str3, NULL)); + fprintf(outputFilePtr, "%s\n", str1); + } + + + g_outputToString = 1; + print2("
\n"); + print2("\n", '%'); + print2(" \n"); + print2(" \n"); + print2(" \n"); + print2(" \n"); + print2(" \n"); + print2("
\n", '%'); + print2("  \n"); + print2(" \n"); + print2("Copyright terms:\n"); + print2("Public domain\n"); + print2(" \n"); + printLongLine(cat(" ", prevNextLinks, NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + print2("
\n"); + print2("\n"); + g_outputToString = 0; + fprintf(outputFilePtr, "%s", g_printString); + let(&g_printString, ""); + + /* Close file */ + fclose(outputFilePtr); + } /* next page */ + + TL_ABORT: + /* Deallocate memory */ + let(&str1, ""); + let(&str3, ""); + let(&str4, ""); + let(&prevNextLinks, ""); + let(&outputFileName, ""); + let(&hugeHdr, ""); + let(&bigHdr, ""); + let(&smallHdr, ""); + let(&tinyHdr, ""); + let(&hdrCommentMarker, ""); + for (i = 0; i <= g_statements; i++) let((vstring *)(&pntrHugeHdr[i]), ""); + pntrLet(&pntrHugeHdr, NULL_PNTRSTRING); + for (i = 0; i <= g_statements; i++) let((vstring *)(&pntrBigHdr[i]), ""); + pntrLet(&pntrBigHdr, NULL_PNTRSTRING); + for (i = 0; i <= g_statements; i++) let((vstring *)(&pntrSmallHdr[i]), ""); + pntrLet(&pntrSmallHdr, NULL_PNTRSTRING); + for (i = 0; i <= g_statements; i++) let((vstring *)(&pntrTinyHdr[i]), ""); + pntrLet(&pntrTinyHdr, NULL_PNTRSTRING); + +} /* writeTheoremList */ + + +/* This function extracts any section headers in the comment sections + prior to the label of statement stmt. If a huge (####...) header isn't + found, *hugeHdrTitle will be set to the empty string. + If a big (#*#*...) header isn't found (or isn't after the last huge header), + *bigHdrTitle will be set to the empty string. If a small + (=-=-...) header isn't found (or isn't after the last huge header or + the last big header), *smallHdrTitle will be set to the empty string. + In all 3 cases, only the last occurrence of a header is considered. + If a tiny + (-.-....) header isn't found (or isn't after the last huge header or + the last big header or the last small header), *tinyHdrTitle will be + set to the empty string. + In all 4 cases, only the last occurrence of a header is considered. */ +/* +20-Jun-2015 metamath Google group email: +https://groups.google.com/g/metamath/c/QE0lwg9f5Ho/m/J8ekl_lH1I8J + +There are 4 kinds of section headers, big (####...), medium (#*#*#*...), +small (=-=-=-), and tiny (-.-.-.). + +Call the collection of (outside-of-statement) comments between two +successive $a/$p statements (i.e. those statements that generate web +pages) a "header area". The algorithm scans the header area for the +_last_ header of each type (big, medium, small, tiny) and discards all +others. Then, if there is a medium and it appears before a big, the +medium is discarded. If there is a small and it appears before a big or +medium, the small is discarded. In other words, a maximum of one header +of each type is kept, in the order big, medium, small, and tiny. + +There are two reasons for doing this: (1) it disregards headers used +for other purposes such as the headers for the set.mm-specific +information at the top that is not of general interest and (2) it +ignores headers for empty sections; for example, a mathbox user might +have a bunch of headers for sections planned for the future, but we +ignore them if those sections are empty (no $a or $p in them). +*/ +/* Return 1 if error found, 0 otherwise */ +flag getSectionHeadings(long stmt, + vstring *hugeHdrTitle, + vstring *bigHdrTitle, + vstring *smallHdrTitle, + vstring *tinyHdrTitle, + vstring *hugeHdrComment, + vstring *bigHdrComment, + vstring *smallHdrComment, + vstring *tinyHdrComment, + flag fineResolution, + flag fullComment) { + + /* for table of contents */ + vstring labelStr = ""; + long pos, pos1, pos2, pos3, pos4; + flag errorFound = 0; + flag saveOutputToString; + + /* Print any error messages to screen */ + saveOutputToString = g_outputToString; /* To restore when returning */ + g_outputToString = 0; + + /* (This initialization seems to be done redundantly by caller elsewhere, + but for WRITE SOURCE ... / EXTRACT we need to do it explicitly.) */ + let(&(*hugeHdrTitle), ""); + let(&(*bigHdrTitle), ""); + let(&(*smallHdrTitle), ""); + let(&(*tinyHdrTitle), ""); + let(&(*hugeHdrComment), ""); + let(&(*bigHdrComment), ""); + let(&(*smallHdrComment), ""); + let(&(*tinyHdrComment), ""); + + /* We now process only $a or $p statements */ + if (fineResolution == 0) { + if (g_Statement[stmt].type != a_ && g_Statement[stmt].type != p_) bug(2340); + } + + /* Get header area between this statement and the statement after the + previous $a or $p statement */ + /* pos3 and pos4 are used temporarily here; not related to later use */ + if (fineResolution == 0) { + pos3 = g_Statement[stmt].headerStartStmt; /* Statement immediately after the + previous $a or $p statement (will be this statement if previous + statement is $a or $p) */ + } else { + pos3 = stmt; /* For WRITE SOURCE ... / EXTRACT, we want every statement + treated equally */ + } + if (pos3 == 0 || pos3 > stmt) bug(2241); + pos4 = (g_Statement[stmt].labelSectionPtr + - g_Statement[pos3].labelSectionPtr) + + g_Statement[stmt].labelSectionLen; /* Length of the header area */ + let(&labelStr, space(pos4)); + memcpy(labelStr, g_Statement[pos3].labelSectionPtr, + (size_t)(pos4)); + + pos = 0; + pos2 = 0; + while (1) { /* Find last "huge" header, if any */ + /* 4-Nov-2007 nm: Obviously, the match below will not work if the + $( line has a trailing space, which some editors might insert. + The symptom is a missing table of contents entry. But to detect + this (and for the #*#* and =-=- matches below) would take a little work + and perhaps slow things down, and I don't think it is worth it. I + put a note in HELP WRITE THEOREM_LIST. */ + pos1 = pos; + pos = instr(pos + 1, labelStr, "$(\n" HUGE_DECORATION); + + /* 23-May-2008 nm Tolerate one space after "$(", to handle case of + one space added to the end of each line with TOOLS to make global + label changes are easier (still a kludge; this should be made + white-space insensitive some day) */ + pos1 = instr(pos1 + 1, labelStr, "$( \n" HUGE_DECORATION); + if (pos1 > pos) pos = pos1; + + if (!pos) break; + if (pos) pos2 = pos; + } /* while(1) */ + if (pos2) { /* Extract "huge" header */ + pos1 = pos2; /* Save "$(" position */ + pos = instr(pos2 + 4, labelStr, "\n"); /* Get to end of #### line */ + pos2 = instr(pos + 1, labelStr, "\n"); /* Find end of title line */ + + /* Error check - can't have more than 1 title line */ + if (strcmp(mid(labelStr, pos2 + 1, 4), HUGE_DECORATION)) { + print2( + "?Warning: missing closing \"%s\" decoration above statement \"%s\".\n", + HUGE_DECORATION, g_Statement[stmt].labelName); + errorFound = 1; + } + + pos3 = instr(pos2 + 1, labelStr, "\n"); /* Get to end of 2nd #### line */ + while (labelStr[(pos3 - 1) + 1] == '\n') pos3++; /* Skip 1st blank lines */ + pos4 = instr(pos3, labelStr, "$)"); /* Get to end of title comment */ + if (fullComment == 0) { + let(&(*hugeHdrTitle), seg(labelStr, pos + 1, pos2 - 1)); + let(&(*hugeHdrTitle), edit((*hugeHdrTitle), 8 + 128)); + /* Trim leading, trailing sp */ + let(&(*hugeHdrComment), seg(labelStr, pos3 + 1, pos4 - 2)); + let(&(*hugeHdrComment), edit((*hugeHdrComment), 8 + 16384)); + /* Trim leading sp, trailing sp & lf */ + } else { + /* Put entire comment in hugeHdrTitle and hugeHdrComment for /EXTRACT */ + /* Search backwards for non-space or beginning of string: */ + pos = pos1; /* pos1 is the "$" in "$(" */ + pos--; + while (pos > 0) { + if (labelStr[pos - 1] != ' ' + && labelStr[pos - 1] != '\n') break; + pos--; + } + /* pos + 1 is the start of whitespace preceding "$(" */ + /* pos4 is the "$" in "$)" */ + /* pos3 is the \n after the 2nd decoration line */ + let(&(*hugeHdrTitle), seg(labelStr, pos + 1, pos3)); + let(&(*hugeHdrComment), seg(labelStr, pos3 + 1, pos4 + 1)); + } + } + /* pos = 0; */ /* Leave pos alone so that we start with "huge" header pos, + to ignore any earlier "tiny" or "small" or "big" header */ + pos2 = 0; + while (1) { /* Find last "big" header, if any */ + pos1 = pos; + pos = instr(pos + 1, labelStr, "$(\n" BIG_DECORATION); + pos1 = instr(pos1 + 1, labelStr, "$( \n" BIG_DECORATION); + if (pos1 > pos) pos = pos1; + + if (!pos) break; + if (pos) pos2 = pos; + } + if (pos2) { /* Extract "big" header */ + pos1 = pos2; /* Save "$(" position */ + pos = instr(pos2 + 4, labelStr, "\n"); /* Get to end of #*#* line */ + pos2 = instr(pos + 1, labelStr, "\n"); /* Find end of title line */ + + /* Error check - can't have more than 1 title line */ + if (strcmp(mid(labelStr, pos2 + 1, 4), BIG_DECORATION)) { + print2( + "?Warning: missing closing \"%s\" decoration above statement \"%s\".\n", + BIG_DECORATION, g_Statement[stmt].labelName); + errorFound = 1; + } + + pos3 = instr(pos2 + 1, labelStr, "\n"); /* Get to end of 2nd #*#* line */ + while (labelStr[(pos3 - 1) + 1] == '\n') pos3++; /* Skip 1st blank lines */ + pos4 = instr(pos3, labelStr, "$)"); /* Get to end of title comment */ + if (fullComment == 0) { + let(&(*bigHdrTitle), seg(labelStr, pos + 1, pos2 - 1)); + let(&(*bigHdrTitle), edit((*bigHdrTitle), 8 + 128)); + /* Trim leading, trailing sp */ + let(&(*bigHdrComment), seg(labelStr, pos3 + 1, pos4 - 2)); + let(&(*bigHdrComment), edit((*bigHdrComment), 8 + 16384)); + /* Trim leading sp, trailing sp & lf */ + } else { + /* Put entire comment in bigHdrTitle and bigHdrComment for /EXTRACT */ + /* Search backwards for non-space or beginning of string: */ + pos = pos1; /* pos1 is the "$" in "$(" */ + pos--; + while (pos > 0) { + if (labelStr[pos - 1] != ' ' + && labelStr[pos - 1] != '\n') break; + pos--; + } + /* pos + 1 is the start of whitespace preceding "$(" */ + /* pos4 is the "$" in "$)" */ + /* pos3 is the \n after the 2nd decoration line */ + let(&(*bigHdrTitle), seg(labelStr, pos + 1, pos3)); + let(&(*bigHdrComment), seg(labelStr, pos3 + 1, pos4 + 1)); + } + } + /* pos = 0; */ /* Leave pos alone so that we start with "big" header pos, + to ignore any earlier "tiny" or "small" header */ + pos2 = 0; + while (1) { /* Find last "small" header, if any */ + pos1 = pos; + pos = instr(pos + 1, labelStr, "$(\n" SMALL_DECORATION); + pos1 = instr(pos1 + 1, labelStr, "$( \n" SMALL_DECORATION); + if (pos1 > pos) pos = pos1; + + if (!pos) break; + if (pos) pos2 = pos; + } + if (pos2) { /* Extract "small" header */ + pos1 = pos2; /* Save "$(" position */ + pos = instr(pos2 + 4, labelStr, "\n"); /* Get to end of =-=- line */ + pos2 = instr(pos + 1, labelStr, "\n"); /* Find end of title line */ + + /* Error check - can't have more than 1 title line */ + if (strcmp(mid(labelStr, pos2 + 1, 4), SMALL_DECORATION)) { + print2( + "?Warning: missing closing \"%s\" decoration above statement \"%s\".\n", + SMALL_DECORATION, g_Statement[stmt].labelName); + errorFound = 1; + } + + pos3 = instr(pos2 + 1, labelStr, "\n"); /* Get to end of 2nd =-=- line */ + while (labelStr[(pos3 - 1) + 1] == '\n') pos3++; /* Skip 1st blank lines */ + pos4 = instr(pos3, labelStr, "$)"); /* Get to end of title comment */ + if (fullComment == 0) { + let(&(*smallHdrTitle), seg(labelStr, pos + 1, pos2 - 1)); + let(&(*smallHdrTitle), edit((*smallHdrTitle), 8 + 128)); + /* Trim leading, trailing sp */ + let(&(*smallHdrComment), seg(labelStr, pos3 + 1, pos4 - 2)); + let(&(*smallHdrComment), edit((*smallHdrComment), 8 + 16384)); + /* Trim leading sp, trailing sp & lf */ + } else { + /* Put entire comment in smallHdrTitle and smallHdrComment for /EXTRACT */ + /* Search backwards for non-space or beginning of string: */ + pos = pos1; /* pos1 is the "$" in "$(" */ + pos--; + while (pos > 0) { + if (labelStr[pos - 1] != ' ' + && labelStr[pos - 1] != '\n') break; + pos--; + } + /* pos + 1 is the start of whitespace preceding "$(" */ + /* pos4 is the "$" in "$)" */ + /* pos3 is the \n after the 2nd decoration line */ + let(&(*smallHdrTitle), seg(labelStr, pos + 1, pos3)); + let(&(*smallHdrComment), seg(labelStr, pos3 + 1, pos4 + 1)); + } + } + + /* pos = 0; */ /* Leave pos alone so that we start with "small" header pos, + to ignore any earlier "tiny" header */ + pos2 = 0; + while (1) { /* Find last "tiny" header, if any */ + pos1 = pos; + pos = instr(pos + 1, labelStr, "$(\n" TINY_DECORATION); + pos1 = instr(pos1 + 1, labelStr, "$( \n" TINY_DECORATION); + if (pos1 > pos) pos = pos1; + + if (!pos) break; + if (pos) pos2 = pos; + } + if (pos2) { /* Extract "tiny" header */ + pos1 = pos2; /* Save "$(" position */ + pos = instr(pos2 + 4, labelStr, "\n"); /* Get to end of -.-. line */ + pos2 = instr(pos + 1, labelStr, "\n"); /* Find end of title line */ + + /* Error check - can't have more than 1 title line */ + if (strcmp(mid(labelStr, pos2 + 1, 4), TINY_DECORATION)) { + print2( + "?Warning: missing closing \"%s\" decoration above statement \"%s\".\n", + TINY_DECORATION, g_Statement[stmt].labelName); + errorFound = 1; + } + + pos3 = instr(pos2 + 1, labelStr, "\n"); /* Get to end of 2nd -.-. line */ + while (labelStr[(pos3 - 1) + 1] == '\n') pos3++; /* Skip 1st blank lines */ + pos4 = instr(pos3, labelStr, "$)"); /* Get to end of title comment */ + if (fullComment == 0) { + let(&(*tinyHdrTitle), seg(labelStr, pos + 1, pos2 - 1)); + let(&(*tinyHdrTitle), edit((*tinyHdrTitle), 8 + 128)); + /* Trim leading, trailing sp */ + let(&(*tinyHdrComment), seg(labelStr, pos3 + 1, pos4 - 2)); + let(&(*tinyHdrComment), edit((*tinyHdrComment), 8 + 16384)); + /* Trim leading sp, trailing sp & lf */ + } else { + /* Put entire comment in tinyHdrTitle and tinyHdrComment for /EXTRACT */ + /* Search backwards for non-space or beginning of string: */ + pos = pos1; /* pos1 is the "$" in "$(" */ + pos--; + while (pos > 0) { + if (labelStr[pos - 1] != ' ' + && labelStr[pos - 1] != '\n') break; + pos--; + } + /* pos + 1 is the start of whitespace preceding "$(" */ + /* pos4 is the "$" in "$)" */ + /* pos3 is the \n after the 2nd decoration line */ + let(&(*tinyHdrTitle), seg(labelStr, pos + 1, pos3)); + let(&(*tinyHdrComment), seg(labelStr, pos3 + 1, pos4 + 1)); + } + } + + if (errorFound == 1) { + print2(" (Note that section titles may not be longer than one line.)\n"); + } + /* Restore output stream */ + g_outputToString = saveOutputToString; + + let(&labelStr, ""); /* Deallocate string memory */ + return errorFound; +} /* getSectionHeadings */ + + +/* Returns HTML for the pink number to print after the statement labels + in HTML output. (Note that "pink" means "rainbow colored" number now.) */ +/* Warning: The caller must deallocate the returned vstring (i.e. this + function cannot be used in let statements but must be assigned to + a local vstring for local deallocation) */ +vstring pinkHTML(long statemNum) +{ + long statemMap; + vstring htmlCode = ""; + vstring hexValue = ""; + + if (statemNum > 0) { + statemMap = g_Statement[statemNum].pinkNumber; + } else { + /* -1 means the label wasn't found */ + statemMap = -1; + } + + /* Note: we put "(future)" when the label wasn't found (an error message + was also generated previously) */ + + /* With style sheet and explicit color */ + let(&hexValue, ""); + hexValue = spectrumToRGB(statemMap, g_Statement[g_statements].pinkNumber); + let(&htmlCode, cat(PINK_NBSP, + "", + (statemMap != -1) ? str((double)statemMap) : "(future)", "", NULL)); + let(&hexValue, ""); + + return htmlCode; +} /* pinkHTML */ + + +/* Returns HTML for a range of pink numbers separated by a "-". */ +/* Warning: The caller must deallocate the returned vstring (i.e. this + function cannot be used in let statements but must be assigned to + a local vstring for local deallocation) */ +vstring pinkRangeHTML(long statemNum1, long statemNum2) { + vstring htmlCode = ""; + vstring str3 = ""; + vstring str4 = ""; + + /* Construct the HTML for a pink number range */ + let(&str3, ""); + str3 = pinkHTML(statemNum1); + let(&str3, right(str3, (long)strlen(PINK_NBSP) + 1)); /* Discard " " */ + let(&str4, ""); + str4 = pinkHTML(statemNum2); + let(&str4, right(str4, (long)strlen(PINK_NBSP) + 1)); /* Discard " " */ + let(&htmlCode, cat(str3, "-", str4, NULL)); + let(&str3, ""); /* Deallocate */ + let(&str4, ""); /* Deallocate */ + return htmlCode; +} /* pinkRangeHTML */ + + +/* This function converts a "spectrum" color (1 to maxColor) to an + RBG value in hex notation for HTML. The caller must deallocate the + returned vstring to prevent memory leaks. color = 1 (red) to maxColor + (violet). A special case is the color -1, which just returns black. */ +vstring spectrumToRGB(long color, long maxColor) { + vstring str1 = ""; + double fraction, fractionInPartition; + long j, red, green, blue, partition; +/* Change PARTITIONS whenever the table below has entries added or removed! */ +#define PARTITIONS 28 + static double redRef[PARTITIONS + 1]; /* Made these */ + static double greenRef[PARTITIONS + 1]; /* static for */ + static double blueRef[PARTITIONS + 1]; /* speedup */ + static long i = -1; /* below */ + + if (i > -1) goto SKIP_INIT; + i = -1; /* For safety */ + + /* Here, we use the maximum saturation possible for a fixed L*a*b color L + (lightness) value of 53, which corresponds to 50% gray scale. + Each pure color had either brightness reduced or saturation reduced, + as required, to achieve L = 53. + + An initial partition was formed from hues 0, 15, 30, ..., 345, then the + result was divided into 1000 subpartitions, and the new partitions were + determined by reselecting partition boundaries based on where their color + difference was distinguishable (i.e. could semi-comfortably read letters + of one color with the other as a background, on an LCD display). Some + human judgment was involved, and it is probably not completely uniform or + optimal. + + A Just Noticeable Difference (JND) algorithm for spacing might be more + accurate, especially if averaged over several subjects and different + monitors. I wrote a program for that - asking the user to identify a word + in one hue with an adjacent hue as a background, in order to score a + point - but it was taking too much time, and I decided life is too short. + I think this is "good enough" though, perhaps not even noticeably + non-optimum. + + The comment at the end of each line is the hue 0-360 mapped linearly + to 1-1043 (345 = 1000, i.e. "extreme" purple or almost red). Partitions + at the end can be commented out if we want to stop at violet instead of + almost wrapping around to red via the purples, in order to more accurately + emulate the color spectrum. Be sure to update the PARTITIONS constant + above if a partition is commented out, to avoid a bug trap. */ + i++; redRef[i] = 251; greenRef[i] = 0; blueRef[i] = 0; /* 1 */ + i++; redRef[i] = 247; greenRef[i] = 12; blueRef[i] = 0; /* 10 */ + i++; redRef[i] = 238; greenRef[i] = 44; blueRef[i] = 0; /* 34 */ + i++; redRef[i] = 222; greenRef[i] = 71; blueRef[i] = 0; /* 58 */ + i++; redRef[i] = 203; greenRef[i] = 89; blueRef[i] = 0; /* 79 */ + i++; redRef[i] = 178; greenRef[i] = 108; blueRef[i] = 0; /* 109 */ + i++; redRef[i] = 154; greenRef[i] = 122; blueRef[i] = 0; /* 140 */ + i++; redRef[i] = 127; greenRef[i] = 131; blueRef[i] = 0; /* 181 */ + i++; redRef[i] = 110; greenRef[i] = 136; blueRef[i] = 0; /* 208 */ + i++; redRef[i] = 86; greenRef[i] = 141; blueRef[i] = 0; /* 242 */ + i++; redRef[i] = 60; greenRef[i] = 144; blueRef[i] = 0; /* 276 */ + i++; redRef[i] = 30; greenRef[i] = 147; blueRef[i] = 0; /* 313 */ + i++; redRef[i] = 0; greenRef[i] = 148; blueRef[i] = 22; /* 375 */ + i++; redRef[i] = 0; greenRef[i] = 145; blueRef[i] = 61; /* 422 */ + i++; redRef[i] = 0; greenRef[i] = 145; blueRef[i] = 94; /* 462 */ + i++; redRef[i] = 0; greenRef[i] = 143; blueRef[i] = 127; /* 504 */ + i++; redRef[i] = 0; greenRef[i] = 140; blueRef[i] = 164; /* 545 */ + i++; redRef[i] = 0; greenRef[i] = 133; blueRef[i] = 218; /* 587 */ + i++; redRef[i] = 3; greenRef[i] = 127; blueRef[i] = 255; /* 612 */ + i++; redRef[i] = 71; greenRef[i] = 119; blueRef[i] = 255; /* 652 */ + i++; redRef[i] = 110; greenRef[i] = 109; blueRef[i] = 255; /* 698 */ + i++; redRef[i] = 137; greenRef[i] = 99; blueRef[i] = 255; /* 740 */ + i++; redRef[i] = 169; greenRef[i] = 78; blueRef[i] = 255; /* 786 */ + i++; redRef[i] = 186; greenRef[i] = 57; blueRef[i] = 255; /* 808 */ + i++; redRef[i] = 204; greenRef[i] = 33; blueRef[i] = 249; /* 834 */ + i++; redRef[i] = 213; greenRef[i] = 16; blueRef[i] = 235; /* 853 */ + i++; redRef[i] = 221; greenRef[i] = 0; blueRef[i] = 222; /* 870 */ + i++; redRef[i] = 233; greenRef[i] = 0; blueRef[i] = 172; /* 916 */ + i++; redRef[i] = 239; greenRef[i] = 0; blueRef[i] = 132; /* 948 */ + /*i++; redRef[i] = 242; greenRef[i] = 0; blueRef[i] = 98;*/ /* 973 */ + /*i++; redRef[i] = 244; greenRef[i] = 0; blueRef[i] = 62;*/ /* 1000 */ + + if (i != PARTITIONS) { /* Double-check future edits */ + print2("? %ld partitions but PARTITIONS = %ld\n", i, (long)PARTITIONS); + bug(2326); /* Don't go further to prevent out-of-range references */ + } + + SKIP_INIT: + if (color == -1) { + let(&str1, "000000"); /* Return black for "(future)" color for labels with + missing theorems in comments */ + return str1; + } + + if (color < 1 || color > maxColor) { + bug(2327); + } + fraction = (1.0 * ((double)color - 1)) / (double)maxColor; + /* Fractional position in "spectrum" */ + partition = (long)(PARTITIONS * fraction); /* Partition number (integer) */ + if (partition >= PARTITIONS) bug(2325); /* Roundoff error? */ + fractionInPartition = 1.0 * (fraction - (1.0 * (double)partition) / PARTITIONS) + * PARTITIONS; /* The fraction of this partition it covers */ + red = (long)(1.0 * (redRef[partition] + + fractionInPartition * + (redRef[partition + 1] - redRef[partition]))); + green = (long)(1.0 * (greenRef[partition] + + fractionInPartition * + (greenRef[partition + 1] - greenRef[partition]))); + blue = (long)(1.0 * (blueRef[partition] + + fractionInPartition * + (blueRef[partition + 1] - blueRef[partition]))); + /* debug */ + /* i=1;if (g_outputToString==0) {i=0;g_outputToString=1;} */ + /* print2("p%ldc%ld\n", partition, color); g_outputToString=i; */ + /*printf("red %ld green %ld blue %ld\n", red, green, blue);*/ + + if (red < 0 || green < 0 || blue < 0 + || red > 255 || green > 255 || blue > 255) { + print2("%ld %ld %ld\n", red, green, blue); + bug(2323); + } + let(&str1, " "); + j = sprintf(str1, "%02X%02X%02X", (unsigned int)red, (unsigned int)green, + (unsigned int)blue); + if (j != 6) bug(2324); + /* debug */ + /*printf("a \n", red, green, blue);*/ + return str1; +} /* spectrumToRGB */ + + +/* Returns the HTML code for GIFs (!g_altHtmlFlag) or Unicode (g_altHtmlFlag), + or LaTeX when !g_htmlFlag, for the math string (hypothesis or conclusion) that + is passed in. */ +/* Warning: The caller must deallocate the returned vstring. */ +vstring getTexLongMath(nmbrString *mathString, long statemNum) +{ + long pos; + vstring tex = ""; + vstring texLine = ""; + vstring lastTex = ""; + flag alphnew, alphold, unknownnew, unknownold; + + /* 7-Jul-2017 added for STS (Structured Typesetting) */ + if(stsFlag) { + getSTSLongMath(&texLine, mathString, 1, statemNum, 0); + return texLine; + } + + if (!g_texDefsRead) bug(2322); /* TeX defs were not read */ + let(&texLine, ""); + + let(&lastTex, ""); + for (pos = 0; pos < nmbrLen(mathString); pos++) { + let(&tex, ""); + tex = tokenToTex(g_MathToken[mathString[pos]].tokenName, statemNum); + /* tokenToTex allocates tex; we must deallocate it */ + if (!g_htmlFlag) { /* LaTeX */ + /* If this token and previous token begin with letter, add a thin + space between them */ + /* Also, anything not in table will have space added */ + alphnew = !!isalpha((unsigned char)(tex[0])); + unknownnew = 0; + if (!strcmp(left(tex, 10), "\\mbox{\\rm ")) { /* Token not in table */ + unknownnew = 1; + } + alphold = !!isalpha((unsigned char)(lastTex[0])); + unknownold = 0; + if (!strcmp(left(lastTex, 10), "\\mbox{\\rm ")) { /* Token not in table*/ + unknownold = 1; + } + /* Put thin space only between letters and/or unknowns */ + if ((alphold || unknownold) && (alphnew || unknownnew)) { + /* Put additional thin space between two letters */ + if (!g_oldTexFlag) { + let(&texLine, cat(texLine, "\\,", tex, " ", NULL)); + } else { + let(&texLine, cat(texLine, "\\m{\\,", tex, "}", NULL)); + } + } else { + if (!g_oldTexFlag) { + let(&texLine, cat(texLine, "", tex, " ", NULL)); + } else { + let(&texLine, cat(texLine, "\\m{", tex, "}", NULL)); + } + } + } else { /* HTML */ + + /* When we have something like "E. x e. om x = y", the lack of + space between om and x looks ugly in HTML. This kludge adds it in + for restricted quantifiers not followed by parenthesis, in order + to make the web page look a little nicer. E.g. onminex. */ + /* Note that the space is put between the pos-1 and the pos tokens */ + if (pos >=4) { + if (!strcmp(g_MathToken[mathString[pos - 2]].tokenName, "e.") + && (!strcmp(g_MathToken[mathString[pos - 4]].tokenName, "E.") + || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "A.") + || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "prod_") + || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "E*") + || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "iota_") + || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "Disj_") + || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "E!") + || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "sum_") + || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "X_") + || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "U_") + || !strcmp(g_MathToken[mathString[pos - 4]].tokenName, "|^|_")) + && strcmp(g_MathToken[mathString[pos]].tokenName, ")") + /* It also shouldn't be restricted _to_ an expression in parens. */ + && strcmp(g_MathToken[mathString[pos - 1]].tokenName, "(") + /* ...or restricted _to_ a union or intersection */ + && strcmp(g_MathToken[mathString[pos - 1]].tokenName, "U.") + && strcmp(g_MathToken[mathString[pos - 1]].tokenName, "|^|") + /* ...or restricted _to_ an expression in braces */ + && strcmp(g_MathToken[mathString[pos - 1]].tokenName, "{")) { + let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ + } + } + /* This one puts a space between the 2 x's in a case like + "E. x x = y". E.g. cla4egf */ + if (pos >=2) { + /* Match a token starting with a letter */ + if (isalpha((unsigned char)(g_MathToken[mathString[pos]].tokenName[0]))) { + /* and make sure its length is 1 */ + if (!(g_MathToken[mathString[pos]].tokenName[1])) { + + /* Make sure previous token is a letter also, to prevent unneeded + space in "ran ( A ..." (e.g. rncoeq, dfiun3g) */ + /* Match a token starting with a letter */ + if (isalpha((unsigned char)(g_MathToken[mathString[pos - 1]].tokenName[0]))) { + /* and make sure its length is 1 */ + if (!(g_MathToken[mathString[pos - 1]].tokenName[1])) { + + /* See if it's 1st letter in a quantified expression */ + if (!strcmp(g_MathToken[mathString[pos - 2]].tokenName, "E.") + || !strcmp(g_MathToken[mathString[pos - 2]].tokenName, "A.") + || !strcmp(g_MathToken[mathString[pos - 2]].tokenName, "F/") + || !strcmp(g_MathToken[mathString[pos - 2]].tokenName, "E!") + /* space btwn A,x in "E! x e. dom A x A y" */ + || !strcmp(g_MathToken[mathString[pos - 2]].tokenName, "ran") + || !strcmp(g_MathToken[mathString[pos - 2]].tokenName, "dom") + || !strcmp(g_MathToken[mathString[pos - 2]].tokenName, "E*")) { + let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ + } + } + } + } + } + } + /* This one puts a space after a letter followed by a word token + e.g. "A" and "suc" in "A. x e. U. A suc" in limuni2 */ + if (pos >= 1) { + /* See if the next token is "suc" */ + if (!strcmp(g_MathToken[mathString[pos]].tokenName, "suc")) { + /* Match a token starting with a letter for the current token */ + if (isalpha( + (unsigned char)(g_MathToken[mathString[pos - 1]].tokenName[0]))) { + /* and make sure its length is 1 */ + if (!(g_MathToken[mathString[pos - 1]].tokenName[1])) { + let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ + } + } + } + } + /* This one puts a space before any "-." that doesn't come after + a parentheses e.g. ax-6 has both cases */ + if (pos >=1) { + /* See if we have a non-parenthesis followed by not */ + if (strcmp(g_MathToken[mathString[pos - 1]].tokenName, "(") + && !strcmp(g_MathToken[mathString[pos]].tokenName, "-.")) { + let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ + } + } + /* This one puts a space between "S" and "(" in df-iso. */ + if (pos >=4) { + if (!strcmp(g_MathToken[mathString[pos - 4]].tokenName, "Isom") + && !strcmp(g_MathToken[mathString[pos - 2]].tokenName, ",") + && !strcmp(g_MathToken[mathString[pos]].tokenName, "(")) { + let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ + } + } + /* This one puts a space between "}" and "(" in funcnvuni proof. */ + if (pos >=1) { + /* See if we have "}" followed by "(" */ + if (!strcmp(g_MathToken[mathString[pos - 1]].tokenName, "}") + && !strcmp(g_MathToken[mathString[pos]].tokenName, "(")) { + let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ + } + } + /* This one puts a space between "}" and "{" in konigsberg proof. */ + if (pos >=1) { + /* See if we have "}" followed by "(" */ + if (!strcmp(g_MathToken[mathString[pos - 1]].tokenName, "}") + && !strcmp(g_MathToken[mathString[pos]].tokenName, "{")) { + let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ + } + } + + let(&texLine, cat(texLine, tex, NULL)); + } /* if !g_htmlFlag */ + let(&lastTex, tex); /* Save for next pass */ + } /* Next pos */ + + /*x Discard redundant white space to reduce HTML file size */ + let(&texLine, edit(texLine, 8 + 16 + 128)); + + /* Enclose math symbols in a span to be used for font selection */ + let(&texLine, cat( + (g_altHtmlFlag ? cat("", NULL) : ""), + texLine, + (g_altHtmlFlag ? "" : ""), NULL)); + + let(&tex, ""); + let(&lastTex, ""); + return texLine; +} /* getTexLongMath */ + + +/* Returns the TeX, or HTML code for GIFs (!g_altHtmlFlag) or Unicode + (g_altHtmlFlag), for a statement's hypotheses and assertion in the form + hyp & ... & hyp => assertion */ +/* Warning: The caller must deallocate the returned vstring (i.e. this + function cannot be used in let statements but must be assigned to + a local vstring for local deallocation) */ +vstring getTexOrHtmlHypAndAssertion(long statemNum) { + long reqHyps, essHyps, n; + nmbrString *nmbrTmpPtr; /* Pointer only; not allocated directly */ + vstring texOrHtmlCode = ""; + vstring str2 = ""; + /* Count the number of essential hypotheses essHyps */ + essHyps = 0; + reqHyps = nmbrLen(g_Statement[statemNum].reqHypList); + let(&texOrHtmlCode, ""); + for (n = 0; n < reqHyps; n++) { + if (g_Statement[g_Statement[statemNum].reqHypList[n]].type + == (char)e_) { + essHyps++; + if (texOrHtmlCode[0]) { /* Add '&' between hypotheses */ + if (!g_htmlFlag) { + /* Hard-coded for set.mm! */ + let(&texOrHtmlCode, cat(texOrHtmlCode, + "\\quad\\&\\quad " + ,NULL)); + } else { + if (g_altHtmlFlag || stsFlag) { + /* Hard-coded for set.mm! */ + let(&texOrHtmlCode, cat(texOrHtmlCode, + "", + "    &   ", + "", + NULL)); + } else { + /* Hard-coded for set.mm! */ + let(&texOrHtmlCode, cat(texOrHtmlCode, + "   &   " + ,NULL)); + } + } + } /* if texOrHtmlCode[0] */ + /* Construct HTML hypothesis */ + nmbrTmpPtr = g_Statement[g_Statement[statemNum].reqHypList[n]].mathString; + let(&str2, ""); + str2 = getTexLongMath(nmbrTmpPtr, statemNum); + let(&texOrHtmlCode, cat(texOrHtmlCode, str2, NULL)); + } + } + if (essHyps) { /* Add big arrow if there were hypotheses */ + if (!g_htmlFlag) { + /* Hard-coded for set.mm! */ + let(&texOrHtmlCode, cat(texOrHtmlCode, + "\\quad\\Rightarrow\\quad " + ,NULL)); + } else { + if (g_altHtmlFlag || stsFlag) { + /* Hard-coded for set.mm! */ + let(&texOrHtmlCode, cat(texOrHtmlCode, + /* sans-serif to work around FF3 bug that produces + huge character heights otherwise */ + "       ", + NULL)); + } else { + /* Hard-coded for set.mm! */ + let(&texOrHtmlCode, cat(texOrHtmlCode, + "   =>   ", + NULL)); + } + } + } + /* Construct TeX or HTML assertion */ + nmbrTmpPtr = g_Statement[statemNum].mathString; + let(&str2, ""); + str2 = getTexLongMath(nmbrTmpPtr, statemNum); + let(&texOrHtmlCode, cat(texOrHtmlCode, str2, NULL)); + + /* Deallocate memory */ + let(&str2, ""); + return texOrHtmlCode; +} /* getTexOrHtmlHypAndAssertion */ + + + + +/* Called by the WRITE BIBLIOGRPAHY command and also by VERIFY MARKUP + for error checking */ +/* Returns 0 if OK, 1 if warning(s), 2 if any error */ +flag writeBibliography(vstring bibFile, + vstring labelMatch, /* Normally "*" except when called by verifyMarkup() */ + flag errorsOnly, /* 1 = no output, just warning msgs if any */ + flag fileCheck) /* 1 = check missing external files (mmbiblio.html) */ +{ + flag errFlag; + FILE *list1_fp = NULL; + FILE *list2_fp = NULL; + long lines, p2, i, j, jend, k, l, m, n, p, q, s, pass1refs; + vstring str1 = "", str2 = "", str3 = "", str4 = "", newstr = "", oldstr = ""; + pntrString *pntrTmp = NULL_PNTRSTRING; + flag warnFlag; + + n = 0; /* Old gcc 4.6.3 wrongly says may be uninit ln 5506 */ + pass1refs = 0; /* gcc 4.5.3 wrongly says may be uninit */ + if (!fileCheck && errorsOnly == 0) { + bug(2336); /* If we aren't opening files, a non-error run can't work */ + } + + /* This utility builds the bibliographical cross-references to various + textbooks and updates the user-specified file normally called + mmbiblio.html. */ + warnFlag = 0; /* 1 means warning was found, 2 that error was found */ + errFlag = 0; /* Error flag to recover input file and to set return value 2 */ + if (fileCheck) { + list1_fp = fSafeOpen(bibFile, "r", 0/*noVersioningFlag*/); + if (list1_fp == NULL) { + /* Couldn't open it (error msg was provided)*/ + return 1; + } + if (errorsOnly == 0) { + fclose(list1_fp); + /* This will rename the input mmbiblio.html as mmbiblio.html~1 */ + list2_fp = fSafeOpen(bibFile, "w", 0/*noVersioningFlag*/); + if (list2_fp == NULL) { + /* Couldn't open it (error msg was provided)*/ + return 1; + } + /* Note: in older versions the "~1" string was OS-dependent, but we + don't support VAX or THINK C anymore... Anyway we reopen it + here with the renamed file in case the OS won't let us rename + an opened file during the fSafeOpen for write above. */ + list1_fp = fSafeOpen(cat(bibFile, "~1", NULL), "r", 0/*noVersioningFlag*/); + if (list1_fp == NULL) bug(2337); + } + } + if (!g_texDefsRead) { + g_htmlFlag = 1; + if (2/*error*/ == readTexDefs(errorsOnly, fileCheck)) { + errFlag = 2; /* Error flag to recover input file */ + goto BIB_ERROR; /* An error occurred */ + } + } + + /* Transfer the input file up to the special "" comment */ + if (fileCheck) { + while (1) { + if (!linput(list1_fp, NULL, &str1)) { + print2("?Error: Could not find \"\" line in input file \"%s\".\n", + bibFile); + errFlag = 2; /* Error flag to recover input file */ + break; + } + if (errorsOnly == 0) { + fprintf(list2_fp, "%s\n", str1); + } + if (!strcmp(str1, "")) break; + } + if (errFlag) goto BIB_ERROR; + } + + p2 = 1; /* Pass 1 or 2 flag */ + lines = 0; + while (1) { + + if (p2 == 2) { /* Pass 2 */ + /* Allocate memory for sorting */ + pntrLet(&pntrTmp, pntrSpace(lines)); + lines = 0; + } + + /* Scan all $a and $p statements */ + for (i = 1; i <= g_statements; i++) { + if (g_Statement[i].type != (char)p_ && + g_Statement[i].type != (char)a_) continue; + + /* Normally labelMatch is *, but may be more specific for + use by verifyMarkup() */ + if (!matchesList(g_Statement[i].labelName, labelMatch, '*', '?')) { + continue; + } + + /* Omit ...OLD (obsolete) and ...NEW (to be implemented) statements */ + if (instr(1, g_Statement[i].labelName, "NEW")) continue; + if (instr(1, g_Statement[i].labelName, "OLD")) continue; + let(&str1, ""); + str1 = getDescription(i); /* Get the statement's comment */ + if (!instr(1, str1, "[")) continue; + l = (signed)(strlen(str1)); + for (j = 0; j < l; j++) { + if (str1[j] == '\n') str1[j] = ' '; /* Change newlines to spaces */ + if (str1[j] == '\r') bug(2338); + } + let(&str1, edit(str1, 8 + 128 + 16)); /* Reduce & trim whitespace */ + + /* Clear out math symbols in backquotes to prevent false matches + to [reference] bracket */ + k = 0; /* Math symbol mode if 1 */ + l = (signed)(strlen(str1)); + for (j = 0; j < l - 1; j++) { + if (k == 0) { + if (str1[j] == '`') { + k = 1; /* Start of math mode */ + } + } else { /* In math mode */ + if (str1[j] == '`') { /* A backquote */ + if (str1[j + 1] == '`') { + /* It is an escaped backquote */ + str1[j] = ' '; + str1[j + 1] = ' '; + } else { + k = 0; /* End of math mode */ + } + } else { /* Not a backquote */ + str1[j] = ' '; /* Clear out the math mode part */ + } + } /* end if k == 0 */ + } /* next j */ + + /* Put spaces before page #s (up to 4 digits) for sorting */ + j = 0; + while (1) { + j = instr(j + 1, str1, " p. "); /* Heuristic - match " p. " */ + if (!j) break; + if (j) { + for (k = j + 4; k <= (signed)(strlen(str1)) + 1; k++) { + if (!isdigit((unsigned char)(str1[k - 1]))) { + let(&str1, cat(left(str1, j + 2), + space(4 - (k - (j + 4))), right(str1, j + 3), NULL)); + /* Add ### after page number as marker */ + let(&str1, cat(left(str1, j + 7), "###", right(str1, j + 8), + NULL)); + break; + } + } + } + } + /* Process any bibliographic references in comment */ + j = 0; + n = 0; + while (1) { + j = instr(j + 1, str1, "["); /* Find reference (not robust) */ + if (!j) break; + + /* Fix mmbiblio.html corruption caused by + "[Copying an angle]" in df-ibcg in + set.mm.2016-09-18-JB-mbox-cleanup */ + /* Skip if there is no trailing "]" */ + jend = instr(j, str1, "]"); + if (!jend) break; + /* Skip bracketed text with spaces */ + /* This is a somewhat ugly workaround that lets us tolerate user + comments in [...] is there is at least one space. + The printTexComment() above handles this case with the + "strcspn(bibTag, " \n\r\t\f")" above; here we just have to look + for space since we already reduced \n \t to space (\f is probably + overkill, and any \r's are removed during the READ command) */ + if (instr(1, seg(str1, j, jend), " ")) continue; + /* Skip escaped bracket "[[" */ + if (str1[j] == '[') { /* (j+1)th character in str1 */ + j++; /* Skip over 2nd "[" */ + continue; + } + if (!isalnum((unsigned char)(str1[j]))) continue; /* Not start of reference */ + n++; + /* Backtrack from [reference] to a starting keyword */ + m = 0; + let(&str2, edit(str1, 32)); /* to uppercase */ + + /* (The string search below is rather inefficient; maybe improve + the algorithm if speed becomes a problem.) */ + for (k = j - 1; k >= 1; k--) { + /* **IMPORTANT** Make sure to update mmhlpb.c HELP WRITE BIBLIOGRAPHY + if new items are added to this list. */ + if (0 + /* Put the most frequent ones first to speed up search; + TODO: count occurrences in mmbiblio.html to find optimal order */ + || !strcmp(mid(str2, k, (long)strlen("THEOREM")), "THEOREM") + || !strcmp(mid(str2, k, (long)strlen("EQUATION")), "EQUATION") + || !strcmp(mid(str2, k, (long)strlen("DEFINITION")), "DEFINITION") + || !strcmp(mid(str2, k, (long)strlen("LEMMA")), "LEMMA") + || !strcmp(mid(str2, k, (long)strlen("EXERCISE")), "EXERCISE") + || !strcmp(mid(str2, k, (long)strlen("AXIOM")), "AXIOM") + || !strcmp(mid(str2, k, (long)strlen("CLAIM")), "CLAIM") + || !strcmp(mid(str2, k, (long)strlen("CHAPTER")), "CHAPTER") + || !strcmp(mid(str2, k, (long)strlen("COMPARE")), "COMPARE") + || !strcmp(mid(str2, k, (long)strlen("CONDITION")), "CONDITION") + || !strcmp(mid(str2, k, (long)strlen("CONJECTURE")), "CONJECTURE") + || !strcmp(mid(str2, k, (long)strlen("COROLLARY")), "COROLLARY") + || !strcmp(mid(str2, k, (long)strlen("EXAMPLE")), "EXAMPLE") + || !strcmp(mid(str2, k, (long)strlen("FIGURE")), "FIGURE") + || !strcmp(mid(str2, k, (long)strlen("ITEM")), "ITEM") + || !strcmp(mid(str2, k, (long)strlen("LEMMAS")), "LEMMAS") + || !strcmp(mid(str2, k, (long)strlen("LINE")), "LINE") + || !strcmp(mid(str2, k, (long)strlen("LINES")), "LINES") + || !strcmp(mid(str2, k, (long)strlen("NOTATION")), "NOTATION") + || !strcmp(mid(str2, k, (long)strlen("NOTE")), "NOTE") + || !strcmp(mid(str2, k, (long)strlen("OBSERVATION")), "OBSERVATION") + || !strcmp(mid(str2, k, (long)strlen("PART")), "PART") + || !strcmp(mid(str2, k, (long)strlen("POSTULATE")), "POSTULATE") + || !strcmp(mid(str2, k, (long)strlen("PROBLEM")), "PROBLEM") + || !strcmp(mid(str2, k, (long)strlen("PROPERTY")), "PROPERTY") + || !strcmp(mid(str2, k, (long)strlen("PROPOSITION")), "PROPOSITION") + || !strcmp(mid(str2, k, (long)strlen("REMARK")), "REMARK") + || !strcmp(mid(str2, k, (long)strlen("RESULT")), "RESULT") + || !strcmp(mid(str2, k, (long)strlen("RULE")), "RULE") + || !strcmp(mid(str2, k, (long)strlen("SCHEME")), "SCHEME") + || !strcmp(mid(str2, k, (long)strlen("SECTION")), "SECTION") + || !strcmp(mid(str2, k, (long)strlen("PROOF")), "PROOF") + || !strcmp(mid(str2, k, (long)strlen("STATEMENT")), "STATEMENT") + || !strcmp(mid(str2, k, (long)strlen("CONCLUSION")), "CONCLUSION") + || !strcmp(mid(str2, k, (long)strlen("FACT")), "FACT") + || !strcmp(mid(str2, k, (long)strlen("INTRODUCTION")), "INTRODUCTION") + || !strcmp(mid(str2, k, (long)strlen("PARAGRAPH")), "PARAGRAPH") + || !strcmp(mid(str2, k, (long)strlen("SCOLIA")), "SCOLIA") + || !strcmp(mid(str2, k, (long)strlen("SCOLION")), "SCOLION") + || !strcmp(mid(str2, k, (long)strlen("SUBSECTION")), "SUBSECTION") + || !strcmp(mid(str2, k, (long)strlen("TABLE")), "TABLE") + ) { + m = k; + break; + } + let(&str3, ""); /* Clear tmp alloc stack created by "mid" */ + } + if (!m) { + if (p2 == 1) { + print2( + "?Warning: Bibliography keyword missing in comment for \"%s\".\n", + g_Statement[i].labelName); + print2( + " (See HELP WRITE BIBLIOGRAPHY for list of keywords.)\n"); + warnFlag = 1; + } + continue; /* Not a bib ref - ignore */ + } + /* m is at the start of a keyword */ + p = instr(m, str1, "["); /* Start of bibliography reference */ + q = instr(p, str1, "]"); /* End of bibliography reference */ + if (q == 0) { + if (p2 == 1) { + print2("?Warning: Bibliography reference not found in HTML file in \"%s\".\n", + g_Statement[i].labelName); + warnFlag = 1; + } + continue; /* Pretend it is not a bib ref - ignore */ + } + s = instr(q, str1, "###"); /* Page number marker */ + if (!s) { + if (p2 == 1) { + print2("?Warning: No page number after [] bib ref in \"%s\".\n", + g_Statement[i].labelName); + warnFlag = 1; + } + continue; /* No page number given - ignore */ + } + /* Now we have a real reference; increment reference count */ + lines++; + if (p2 == 1) continue; /* In 1st pass, we just count refs */ + + let(&str2, seg(str1, m, p - 1)); /* "Theorem #" */ + let(&str3, seg(str1, p + 1, q - 1)); /* "[bibref]" w/out [] */ + let(&str4, seg(str1, q + 1, s - 1)); /* " p. nnnn" */ + str2[0] = (char)(toupper((unsigned char)(str2[0]))); + /* Eliminate noise like "of" in "Theorem 1 of [bibref]" */ + for (k = (long)strlen(str2); k >=1; k--) { + if (0 + || !strcmp(mid(str2, k, (long)strlen(" of ")), " of ") + || !strcmp(mid(str2, k, (long)strlen(" in ")), " in ") + || !strcmp(mid(str2, k, (long)strlen(" from ")), " from ") + || !strcmp(mid(str2, k, (long)strlen(" on ")), " on ") + ) { + let(&str2, left(str2, k - 1)); + break; + } + let(&str2, str2); + } + + let(&newstr, ""); + newstr = pinkHTML(i); /* Get little pink number */ + let(&oldstr, cat( + /* Construct the sorting key */ + /* The space() helps Th. 9 sort before Th. 10 on same page */ + str3, " ", str4, space(20 - (long)strlen(str2)), str2, + "|||", /* ||| means end of sort key */ + /* Construct just the statement href for combining dup refs */ + "", g_Statement[i].labelName, "", + newstr, + "&&&", /* &&& means end of statement href */ + /* Construct actual HTML table row (without ending tag + so duplicate references can be added) */ + (i < g_extHtmlStmt) + ? "" + : (i < g_mathboxStmt) + ? cat("", NULL) + : cat("", NULL), + + "[", str3, "]", str4, + "", str2, "", g_Statement[i].labelName, "", + newstr, NULL)); + /* Put construction into string array for sorting */ + let((vstring *)(&pntrTmp[lines - 1]), oldstr); + } /* while(1) */ + } /* next i */ + + /* 'lines' should be the same in both passes */ + if (p2 == 1) { + pass1refs = lines; + } else { + if (pass1refs != lines) bug(2339); + } + + if (errorsOnly == 0 && p2 == 2) { + /* + print2("Pass %ld finished. %ld references were processed.\n", p2, lines); + */ + print2("%ld references were processed.\n", lines); + } + if (p2 == 2) break; + p2++; /* Increment from pass 1 to pass 2 */ + } /* while(1) */ + + /* Sort */ + g_qsortKey = ""; + qsort(pntrTmp, (size_t)lines, sizeof(void *), qsortStringCmp); + + /* Combine duplicate references */ + let(&str1, ""); /* Last biblio ref */ + for (i = 0; i < lines; i++) { + j = instr(1, (vstring)(pntrTmp[i]), "|||"); + let(&str2, left((vstring)(pntrTmp[i]), j - 1)); + if (!strcmp(str1, str2)) { + /* Combine last with this */ + k = instr(j, (vstring)(pntrTmp[i]), "&&&"); + /* Extract statement href */ + let(&str3, seg((vstring)(pntrTmp[i]), j + 3, k -1)); + let((vstring *)(&pntrTmp[i]), + cat((vstring)(pntrTmp[i - 1]), "  ", str3, NULL)); + let((vstring *)(&pntrTmp[i - 1]), ""); /* Clear previous line */ + } + let(&str1, str2); + } + + /* Write output */ + if (fileCheck && errorsOnly == 0) { + n = 0; /* Table rows written */ + for (i = 0; i < lines; i++) { + j = instr(1, (vstring)(pntrTmp[i]), "&&&"); + if (j) { /* Don't print blanked out combined lines */ + n++; + /* Take off prefixes and reduce spaces */ + let(&str1, edit(right((vstring)(pntrTmp[i]), j + 3), 16)); + j = 1; + /* Break up long lines for text editors */ + let(&g_printString, ""); + g_outputToString = 1; + printLongLine(cat(str1, "", NULL), + " ", /* Start continuation line with space */ + "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ + g_outputToString = 0; + fprintf(list2_fp, "%s", g_printString); + let(&g_printString, ""); + } + } + } + + + /* Discard the input file up to the special "" comment */ + if (fileCheck) { + while (1) { + if (!linput(list1_fp, NULL, &str1)) { + print2( + "?Error: Could not find \"\" line in input file \"%s\".\n", + bibFile); + errFlag = 2; /* Error flag to recover input file */ + break; + } + if (!strcmp(str1, "")) { + if (errorsOnly == 0) { + fprintf(list2_fp, "%s\n", str1); + } + break; + } + } + if (errFlag) goto BIB_ERROR; + } + + if (fileCheck && errorsOnly == 0) { + /* Transfer the rest of the input file */ + while (1) { + if (!linput(list1_fp, NULL, &str1)) { + break; + } + + /* Update the date stamp at the bottom of the HTML page. */ + /* This is just a nicety; no error check is done. */ + if (!strcmp("This page was last updated on ", left(str1, 30))) { + let(&str1, cat(left(str1, 30), date(), ".", NULL)); + } + + fprintf(list2_fp, "%s\n", str1); + } + + print2("%ld table rows were written.\n", n); + /* Deallocate string array */ + for (i = 0; i < lines; i++) let((vstring *)(&pntrTmp[i]), ""); + pntrLet(&pntrTmp,NULL_PNTRSTRING); + } + + + BIB_ERROR: + if (fileCheck) { + fclose(list1_fp); + if (errorsOnly == 0) { + fclose(list2_fp); + } + if (errorsOnly == 0) { + if (errFlag) { + /* Recover input files in case of error */ + remove(bibFile); /* Delete output file */ + rename(cat(bibFile, "~1", NULL), g_fullArg[2]); + /* Restore input file name */ + print2("?The file \"%s\" was not modified.\n", g_fullArg[2]); + } + } + } + if (errFlag == 2) warnFlag = 2; + return warnFlag; +} /* writeBibliography */ + + +/* Returns 1 if stmt1 and stmt2 are in different mathboxes, 0 if + they are in the same mathbox or if one of them is not in a mathbox. */ +flag inDiffMathboxes(long stmt1, long stmt2) { + long mbox1, mbox2; + mbox1 = getMathboxNum(stmt1); + mbox2 = getMathboxNum(stmt2); + if (mbox1 == 0 || mbox2 == 0) return 0; + if (mbox1 != mbox2) return 1; + return 0; +} + +/* Returns the user of the mathbox that a statement is in, or "" + if the statement is not in a mathbox. */ +/* Caller should NOT deallocate returned string (it points directly to + g_mathboxUser[] entry) */ +vstring getMathboxUser(long stmt) { + long mbox; + mbox = getMathboxNum(stmt); + if (mbox == 0) return ""; + return g_mathboxUser[mbox - 1]; +} + +/* Given a statement number, find out what mathbox it's in (numbered starting + at 1) mainly for error messages; if it's not in a mathbox, return 0. */ +/* We assume the number of mathboxes is small enough that a linear search + won't slow things too much. */ +long getMathboxNum(long stmt) { + long mbox; + assignMathboxInfo(); /* In case it's not yet initialized */ + for (mbox = 0; mbox < g_mathboxes; mbox++) { + if (stmt < g_mathboxStart[mbox]) break; + } + return mbox; +} /* getMathboxNum */ + + +/* Assign the global variable g_mathboxStmt, the statement number with the + label "mathbox", as well as g_mathboxes, g_mathboxStart[], g_mathboxEnd[], + and g_mathboxUser[]. For speed, we do the lookup only if it hasn't been + done yet. Note that the ERASE command (eraseSource()) should set + g_mathboxStmt to zero as well as deallocate the strings. */ +/* This function will just return if g_mathboxStmt is already nonzero. */ +#define MB_LABEL "mathbox" +void assignMathboxInfo(void) { + if (g_mathboxStmt == 0) { /* Look up "mathbox" label if it hasn't been */ + g_mathboxStmt = lookupLabel(MB_LABEL); + if (g_mathboxStmt == -1) { /* There are no mathboxes */ + g_mathboxStmt = g_statements + 1; /* Default beyond db end if none */ + g_mathboxes = 0; + } else { + /* Population mathbox information variables */ + g_mathboxes = getMathboxLoc(&g_mathboxStart, &g_mathboxEnd, + &g_mathboxUser); + } + } + return; +} /* assignMathboxInfo */ + + +/* Returns the number of mathboxes, while assigning start statement, end + statement, and mathbox name. */ +#define MB_TAG "Mathbox for " +long getMathboxLoc(nmbrString **mathboxStart, nmbrString **mathboxEnd, + pntrString **mathboxUser) { + long m, p, q, tagLen, stmt; + long mathboxes = 0; + vstring comment = ""; + vstring user = ""; + assignMathboxInfo(); /* Assign g_mathboxStmt */ + tagLen = (long)strlen(MB_TAG); + /* Ensure lists are initialized */ + if (pntrLen((pntrString *)(*mathboxUser)) != 0) bug(2347); + if (nmbrLen((nmbrString *)(*mathboxStart)) != 0) bug(2348); + if (nmbrLen((nmbrString *)(*mathboxEnd)) != 0) bug(2349); + for (stmt = g_mathboxStmt + 1; stmt <= g_statements; stmt++) { + /* Heuristic to match beginning of mathbox */ + let(&comment, left(g_Statement[stmt].labelSectionPtr, + g_Statement[stmt].labelSectionLen)); + p = 0; + /* This loop will skip empty mathboxes i.e. it will get the last + "Mathbox for " in the label section comment(s) */ + while (1) { + q = instr(p + 1, comment, MB_TAG); + if (q == 0) break; + p = q; /* Save last "Mathbox for " */ + } + if (p == 0) continue; /* No "Mathbox for " in this statement's comment */ + + /* Found a mathbox; assign user and start statement */ + mathboxes++; + q = instr(p, comment, "\n"); + if (q == 0) bug(2350); /* No end of line */ + let(&user, seg(comment, p + tagLen, q - 1)); + pntrLet(&(*mathboxUser), pntrAddElement(*mathboxUser)); + (*mathboxUser)[mathboxes - 1] = ""; + let((vstring *)(&((*mathboxUser)[mathboxes - 1])), user); + nmbrLet(&(*mathboxStart), nmbrAddElement(*mathboxStart, stmt)); + } /* next stmt */ + if (mathboxes == 0) goto RETURN_POINT; + /* Assign end statements */ + nmbrLet(&(*mathboxEnd), nmbrSpace(mathboxes)); /* Pre-allocate */ + for (m = 0; m < mathboxes - 1; m++) { + (*mathboxEnd)[m] = (*mathboxStart)[m + 1] - 1; + } + (*mathboxEnd)[mathboxes - 1] = g_statements; /* Assumed end of last mathbox */ + RETURN_POINT: + let(&comment, ""); + let(&user, ""); + return mathboxes; +} /* getMathboxLoc */ diff --git a/mmwtex.h b/mmwtex.h index 70e5c17d..d532f1b1 100644 --- a/mmwtex.h +++ b/mmwtex.h @@ -1,199 +1,204 @@ -/*****************************************************************************/ -/* Copyright (C) 2020 NORMAN MEGILL nm at alum.mit.edu */ -/* License terms: GNU General Public License */ -/*****************************************************************************/ -/*34567890123456 (79-character line to adjust editor window) 2345678901234567*/ - -#ifndef METAMATH_MMWTEX_H_ -#define METAMATH_MMWTEX_H_ - -#include "mmvstr.h" -#include "mmdata.h" - -/* Colors for HTML pages. */ -#define GREEN_TITLE_COLOR "\"#006633\"" -#define MINT_BACKGROUND_COLOR "\"#EEFFFA\"" -#define PINK_NUMBER_COLOR "\"#FA8072\"" /* =salmon; was FF6666 */ -#define PURPLISH_BIBLIO_COLOR "\"#FAEEFF\"" -#define SANDBOX_COLOR "\"#FFFFD9\"" - -/* TeX flags */ -extern flag g_oldTexFlag; /* Use macros in output; obsolete; take out someday */ - -/* HTML flags */ -extern flag g_htmlFlag; /* HTML flag: 0 = TeX, 1 = HTML */ -extern flag g_altHtmlFlag; /* Use "althtmldef" instead of "htmldef". This is - intended to allow the generation of pages with the old Symbol font - instead of the individual GIF files. */ -extern flag g_briefHtmlFlag; /* Output statement only, for statement display - in other HTML pages, such as the Proof Explorer home page */ -extern long g_extHtmlStmt; /* At this statement and above, use the exthtmlxxx - variables for title, links, etc. This was put in to allow proper - generation of the Hilbert Space Explorer extension to the set.mm - database. */ -extern vstring g_extHtmlTitle; /* Title of extended section if any; set by - by exthtmltitle command in special $t comment of database source */ -extern vstring g_htmlVarColor; /* Set by htmlvarcolor commands */ -extern vstring g_htmlHome; /* Set by htmlhome command */ -extern vstring g_htmlBibliography; /* Optional; set by htmlbibliography command */ -extern vstring g_extHtmlBibliography; /* Optional; set by exthtmlbibliography - command */ -extern vstring g_htmlCSS; /* Set by htmlcss commands */ -extern vstring g_htmlFont; /* Optional; set by g_htmlFont command */ - -void eraseTexDefs(void); /* Undo readTexDefs() */ - -/* TeX/HTML/ALT_HTML word-processor-specific routines */ -/* Returns 2 if there were severe parsing errors, 1 if there were warnings but - no errors, 0 if no errors or warnings */ -flag readTexDefs( - flag errorsOnly, /* 1 = supprees non-error messages */ - flag gifCheck /* 1 = check for missing GIFs */); - -extern flag g_texDefsRead; -struct texDef_struct { /* for "erase" */ - vstring tokenName; /* ASCII token */ - vstring texEquiv; /* Converted to TeX */ -}; -extern struct texDef_struct *g_TexDefs; /* for "erase" */ - - -long texDefWhiteSpaceLen(char *ptr); -long texDefTokenLen(char *ptr); -/* Token comparison for qsort */ -int texSortCmp(const void *key1, const void *key2); -/* Token comparison for bsearch */ -int texSrchCmp(const void *key, const void *data); -/* Convert ascii to a string of \tt tex */ -/* (The caller must surround it by {\tt }) */ -vstring asciiToTt(vstring s); -vstring tokenToTex(vstring mtoken, long statemNum); -/* Converts a comment section in math mode to TeX. Each math token - MUST be separated by white space. TeX "$" does not surround the output. */ -vstring asciiMathToTex(vstring mathComment, long statemNum); -/* Gets the next section of a comment that is in the current mode (text, - label, or math). If 1st char. is not "$", text mode is assumed. - mode = 0 means end of comment reached. srcptr is left at 1st char. - of start of next comment section. */ -vstring getCommentModeSection(vstring *srcptr, char *mode); -void printTexHeader(flag texHeaderFlag); - -/* Prints an embedded comment in TeX. The commentPtr must point to the first - character after the "$(" in the comment. The printout ends when the first - "$)" or null character is encountered. commentPtr must not be a temporary - allocation. htmlCenterFlag, if 1, means to center the HTML and add a - "Description:" prefix.*/ -/* void printTexComment(vstring commentPtr, char htmlCenterFlag); */ -/* returns 1 if error/warning */ -flag printTexComment(vstring commentPtr, /* Sends result to g_texFilePtr */ - flag htmlCenterFlag, /* 1 = htmlCenterFlag */ - long actionBits, /* see indicators below */ - flag fileCheck /* 1 = fileCheck */); -/* Indicators for actionBits */ -#define ERRORS_ONLY 1 -#define PROCESS_SYMBOLS 2 -#define PROCESS_LABELS 4 -#define ADD_COLORED_LABEL_NUMBER 8 -#define PROCESS_BIBREFS 16 -#define PROCESS_UNDERSCORES 32 -/* CONVERT_TO_HTML means '<' to '<'; unless in comment (and strip it) */ -#define CONVERT_TO_HTML 64 -/* METAMATH_COMMENT means $) (as well as end-of-string) terminates string. */ -#define METAMATH_COMMENT 128 -/* PROCESS_ALL is for convenience */ -#define PROCESS_EVERYTHING PROCESS_SYMBOLS + PROCESS_LABELS \ - + ADD_COLORED_LABEL_NUMBER + PROCESS_BIBREFS \ - + PROCESS_UNDERSCORES + CONVERT_TO_HTML + METAMATH_COMMENT - -void printTexLongMath(nmbrString *proofStep, vstring startPrefix, - vstring contPrefix, long hypStmt, long indentationLevel); -void printTexTrailer(flag texHeaderFlag); - -/* Function implementing WRITE THEOREM_LIST / THEOREMS_PER_PAGE nn */ -void writeTheoremList(long theoremsPerPage, flag showLemmas, - flag noVersioning); - -#define HUGE_DECORATION "####" -#define BIG_DECORATION "#*#*" -#define SMALL_DECORATION "=-=-" -#define TINY_DECORATION "-.-." - -flag getSectionHeadings(long stmt, vstring *hugeHdrTitle, - vstring *bigHdrTitle, - vstring *smallHdrTitle, - vstring *tinyHdrTitle, - vstring *hugeHdrComment, - vstring *bigHdrComment, - vstring *smallHdrComment, - vstring *tinyHdrComment, - flag fineResolution, /* 0 = consider just successive $a/$p, 1 = all stmts */ - flag fullComment /* 1 = put $( + header + comment + $) into xxxHdrTitle */ - ); - -/* TeX normal output */ -extern flag g_texFileOpenFlag; -extern FILE *g_texFilePtr; - -/* Pink statement number HTML code for HTML pages */ -/* Warning: caller must deallocate returned string */ -vstring pinkHTML(long statemNum); - -/* Pink statement number range HTML code for HTML pages, separated by a "-" */ -/* Warning: caller must deallocate returned string */ -vstring pinkRangeHTML(long statemNum1, long statemNum2); - -#define PINK_NBSP " " /* Either "" or " " depending on taste, it is - the separator between a statement href and its pink number */ - -/* This function converts a "spectrum" color (1 to maxColor) to an - RBG value in hex notation for HTML. The caller must deallocate the - returned vstring. color = 1 (red) to maxColor (violet). */ -vstring spectrumToRGB(long color, long maxColor); - -/* Returns the HTML code for GIFs (!g_altHtmlFlag) or Unicode (g_altHtmlFlag), - or LaTeX when !g_htmlFlag, for the math string (hypothesis or conclusion) that - is passed in. */ -/* Warning: The caller must deallocate the returned vstring. */ -vstring getTexLongMath(nmbrString *mathString, long statemNum); - -/* Returns the TeX, or HTML code for GIFs (!g_altHtmlFlag) or Unicode - (g_altHtmlFlag), for a statement's hypotheses and assertion in the form - hyp & ... & hyp => assertion */ -/* Warning: The caller must deallocate the returned vstring. */ -vstring getTexOrHtmlHypAndAssertion(long statemNum); - -/* For WRITE BIBLIOGRAPHY command and error checking by VERIFY MARKUP */ -/* Returns 0 if OK, 1 if error or warning found */ -flag writeBibliography(vstring bibFile, - vstring labelMatch, /* Normally "*" except by verifyMarkup() */ - flag errorsOnly, /* 1 = no output, just warning msgs if any */ - flag fileCheck); /* 1 = check missing external files (gifs, bib, etc.) */ - -/* Globals to hold mathbox information. They should be re-initialized - by the ERASE command (eraseSource()). g_mathboxStmt = 0 indicates - it and the other variables haven't been initialized. */ -extern long g_mathboxStmt; /* stmt# of "mathbox" label; statements+1 if none */ -extern long g_mathboxes; /* # of mathboxes */ -/* The following 3 "strings" are 0-based e.g. g_mathboxStart[0] is for - mathbox #1 */ -extern nmbrString *g_mathboxStart; /* Start stmt vs. mathbox # */ -extern nmbrString *g_mathboxEnd; /* End stmt vs. mathbox # */ -extern pntrString *g_mathboxUser; /* User name vs. mathbox # */ - -/* Returns 1 if statements are in different mathboxes */ -flag inDiffMathboxes(long stmt1, long stmt2); -/* Returns the user of the mathbox that a statement is in, or "" - if the statement is not in a mathbox. */ -/* Caller should NOT deallocate returned string (it points directly to - g_mathboxUser[] entry); use directly in print2() messages */ -vstring getMathboxUser(long stmt); -/* Returns the mathbox number (starting at 1) that stmt is in, or 0 if not - in a mathbox */ -long getMathboxNum(long stmt); -/* Populates mathbox information */ -void assignMathboxInfo(void); -/* Creates lists of mathbox starts and user names */ -long getMathboxLoc(nmbrString **mathboxStart, nmbrString **mathboxEnd, - pntrString **mathboxUser); - -#endif /* METAMATH_MMWTEX_H_ */ +/*****************************************************************************/ +/* Copyright (C) 2020 NORMAN MEGILL nm at alum.mit.edu */ +/* License terms: GNU General Public License */ +/*****************************************************************************/ +/*34567890123456 (79-character line to adjust editor window) 2345678901234567*/ + +#ifndef METAMATH_MMWTEX_H_ +#define METAMATH_MMWTEX_H_ + +#include "mmvstr.h" +#include "mmdata.h" + +/* Colors for HTML pages. */ +#define GREEN_TITLE_COLOR "\"#006633\"" +#define MINT_BACKGROUND_COLOR "\"#EEFFFA\"" +#define PINK_NUMBER_COLOR "\"#FA8072\"" /* =salmon; was FF6666 */ +#define PURPLISH_BIBLIO_COLOR "\"#FAEEFF\"" +#define SANDBOX_COLOR "\"#FFFFD9\"" + +/* TeX flags */ +extern flag g_oldTexFlag; /* Use macros in output; obsolete; take out someday */ + +/* HTML flags */ +extern flag g_htmlFlag; /* HTML flag: 0 = TeX, 1 = HTML */ +extern flag g_altHtmlFlag; /* Use "althtmldef" instead of "htmldef". This is + intended to allow the generation of pages with the old Symbol font + instead of the individual GIF files. */ +/* 19-Jul-2017 tar Added for STS/MathML output */ +extern flag stsFlag; /* STS output (for "structural typesetting") */ +extern vstring stsOutput; /* output mode chosen for STS (follows STS flag) */ +extern vstring postProcess; /* command to pipe the output into (used for MathJax prerendering) */ +extern flag g_briefHtmlFlag; /* Output statement only, for statement display + in other HTML pages, such as the Proof Explorer home page */ +extern long g_extHtmlStmt; /* At this statement and above, use the exthtmlxxx + variables for title, links, etc. This was put in to allow proper + generation of the Hilbert Space Explorer extension to the set.mm + database. */ +extern vstring g_extHtmlTitle; /* Title of extended section if any; set by + by exthtmltitle command in special $t comment of database source */ +extern vstring g_htmlVarColor; /* Set by htmlvarcolor commands */ +extern vstring g_htmlHome; /* Set by htmlhome command */ +extern vstring g_htmlBibliography; /* Optional; set by htmlbibliography command */ +extern vstring g_extHtmlBibliography; /* Optional; set by exthtmlbibliography + command */ +extern vstring g_htmlCSS; /* Set by htmlcss commands */ +extern vstring g_htmlFont; /* Optional; set by g_htmlFont command */ + +void eraseTexDefs(void); /* Undo readTexDefs() */ + +/* TeX/HTML/ALT_HTML word-processor-specific routines */ +/* Returns 2 if there were severe parsing errors, 1 if there were warnings but + no errors, 0 if no errors or warnings */ +flag readTexDefs( + flag errorsOnly, /* 1 = supprees non-error messages */ + flag gifCheck /* 1 = check for missing GIFs */); + +extern flag g_texDefsRead; +struct texDef_struct { /* for "erase" */ + vstring tokenName; /* ASCII token */ + vstring texEquiv; /* Converted to TeX */ +}; +extern struct texDef_struct *g_TexDefs; /* for "erase" */ + + +long texDefWhiteSpaceLen(char *ptr); +long texDefTokenLen(char *ptr); +/* Token comparison for qsort */ +int texSortCmp(const void *key1, const void *key2); +/* Token comparison for bsearch */ +int texSrchCmp(const void *key, const void *data); +/* Convert ascii to a string of \tt tex */ +/* (The caller must surround it by {\tt }) */ +vstring asciiToTt(vstring s); +vstring tokenToTex(vstring mtoken, long statemNum); +/* Converts a comment section in math mode to TeX. Each math token + MUST be separated by white space. TeX "$" does not surround the output. */ +vstring asciiMathToTex(vstring mathComment, long statemNum); +vstring asciiMathToTexNoSts(vstring mathComment, long statemNum); +/* Gets the next section of a comment that is in the current mode (text, + label, or math). If 1st char. is not "$", text mode is assumed. + mode = 0 means end of comment reached. srcptr is left at 1st char. + of start of next comment section. */ +vstring getCommentModeSection(vstring *srcptr, char *mode); +void printTexHeader(flag texHeaderFlag); + +/* Prints an embedded comment in TeX. The commentPtr must point to the first + character after the "$(" in the comment. The printout ends when the first + "$)" or null character is encountered. commentPtr must not be a temporary + allocation. htmlCenterFlag, if 1, means to center the HTML and add a + "Description:" prefix.*/ +/* void printTexComment(vstring commentPtr, char htmlCenterFlag); */ +/* returns 1 if error/warning */ +flag printTexComment(vstring commentPtr, /* Sends result to g_texFilePtr */ + flag htmlCenterFlag, /* 1 = htmlCenterFlag */ + long actionBits, /* see indicators below */ + flag fileCheck /* 1 = fileCheck */); +/* Indicators for actionBits */ +#define ERRORS_ONLY 1 +#define PROCESS_SYMBOLS 2 +#define PROCESS_LABELS 4 +#define ADD_COLORED_LABEL_NUMBER 8 +#define PROCESS_BIBREFS 16 +#define PROCESS_UNDERSCORES 32 +/* CONVERT_TO_HTML means '<' to '<'; unless in comment (and strip it) */ +#define CONVERT_TO_HTML 64 +/* METAMATH_COMMENT means $) (as well as end-of-string) terminates string. */ +#define METAMATH_COMMENT 128 +/* PROCESS_ALL is for convenience */ +#define PROCESS_EVERYTHING PROCESS_SYMBOLS + PROCESS_LABELS \ + + ADD_COLORED_LABEL_NUMBER + PROCESS_BIBREFS \ + + PROCESS_UNDERSCORES + CONVERT_TO_HTML + METAMATH_COMMENT + +void printTexLongMath(nmbrString *proofStep, vstring startPrefix, + vstring contPrefix, long hypStmt, long indentationLevel); +void printTexTrailer(flag texHeaderFlag); + +/* Function implementing WRITE THEOREM_LIST / THEOREMS_PER_PAGE nn */ +void writeTheoremList(long theoremsPerPage, flag showLemmas, + flag noVersioning); + +#define HUGE_DECORATION "####" +#define BIG_DECORATION "#*#*" +#define SMALL_DECORATION "=-=-" +#define TINY_DECORATION "-.-." + +flag getSectionHeadings(long stmt, vstring *hugeHdrTitle, + vstring *bigHdrTitle, + vstring *smallHdrTitle, + vstring *tinyHdrTitle, + vstring *hugeHdrComment, + vstring *bigHdrComment, + vstring *smallHdrComment, + vstring *tinyHdrComment, + flag fineResolution, /* 0 = consider just successive $a/$p, 1 = all stmts */ + flag fullComment /* 1 = put $( + header + comment + $) into xxxHdrTitle */ + ); + +/* TeX normal output */ +extern flag g_texFileOpenFlag; +extern FILE *g_texFilePtr; + +/* Pink statement number HTML code for HTML pages */ +/* Warning: caller must deallocate returned string */ +vstring pinkHTML(long statemNum); + +/* Pink statement number range HTML code for HTML pages, separated by a "-" */ +/* Warning: caller must deallocate returned string */ +vstring pinkRangeHTML(long statemNum1, long statemNum2); + +#define PINK_NBSP " " /* Either "" or " " depending on taste, it is + the separator between a statement href and its pink number */ + +/* This function converts a "spectrum" color (1 to maxColor) to an + RBG value in hex notation for HTML. The caller must deallocate the + returned vstring. color = 1 (red) to maxColor (violet). */ +vstring spectrumToRGB(long color, long maxColor); + +/* Returns the HTML code for GIFs (!g_altHtmlFlag) or Unicode (g_altHtmlFlag), + or LaTeX when !g_htmlFlag, for the math string (hypothesis or conclusion) that + is passed in. */ +/* Warning: The caller must deallocate the returned vstring. */ +vstring getTexLongMath(nmbrString *mathString, long statemNum); + +/* Returns the TeX, or HTML code for GIFs (!g_altHtmlFlag) or Unicode + (g_altHtmlFlag), for a statement's hypotheses and assertion in the form + hyp & ... & hyp => assertion */ +/* Warning: The caller must deallocate the returned vstring. */ +vstring getTexOrHtmlHypAndAssertion(long statemNum); + +/* For WRITE BIBLIOGRAPHY command and error checking by VERIFY MARKUP */ +/* Returns 0 if OK, 1 if error or warning found */ +flag writeBibliography(vstring bibFile, + vstring labelMatch, /* Normally "*" except by verifyMarkup() */ + flag errorsOnly, /* 1 = no output, just warning msgs if any */ + flag fileCheck); /* 1 = check missing external files (gifs, bib, etc.) */ + +/* Globals to hold mathbox information. They should be re-initialized + by the ERASE command (eraseSource()). g_mathboxStmt = 0 indicates + it and the other variables haven't been initialized. */ +extern long g_mathboxStmt; /* stmt# of "mathbox" label; statements+1 if none */ +extern long g_mathboxes; /* # of mathboxes */ +/* The following 3 "strings" are 0-based e.g. g_mathboxStart[0] is for + mathbox #1 */ +extern nmbrString *g_mathboxStart; /* Start stmt vs. mathbox # */ +extern nmbrString *g_mathboxEnd; /* End stmt vs. mathbox # */ +extern pntrString *g_mathboxUser; /* User name vs. mathbox # */ + +/* Returns 1 if statements are in different mathboxes */ +flag inDiffMathboxes(long stmt1, long stmt2); +/* Returns the user of the mathbox that a statement is in, or "" + if the statement is not in a mathbox. */ +/* Caller should NOT deallocate returned string (it points directly to + g_mathboxUser[] entry); use directly in print2() messages */ +vstring getMathboxUser(long stmt); +/* Returns the mathbox number (starting at 1) that stmt is in, or 0 if not + in a mathbox */ +long getMathboxNum(long stmt); +/* Populates mathbox information */ +void assignMathboxInfo(void); +/* Creates lists of mathbox starts and user names */ +long getMathboxLoc(nmbrString **mathboxStart, nmbrString **mathboxEnd, + pntrString **mathboxUser); + +#endif /* METAMATH_MMWTEX_H_ */