metamath/metamath.c
2022-05-03 20:09:32 -07:00

8103 lines
327 KiB
C

/*****************************************************************************/
/* 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
mmmaci.c - THINK C Macintosh interface (obsolete)
mmpars.c - Parses the source file
mmpfas.c - Proof Assistant
mmunif.c - Unification algorithm for Proof Assistant
mmutil.c - Miscellaneous I/O utilities (reserved for future use)
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.198 7-Aug-2021"
/* 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 <label-list>
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 "<HTML>"
(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 </TD> */
/* 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 <HTML>...</HTML>
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 </TD> 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 <head> 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 "<SPAN [g_htmlFont]>...</SPAN>; added htmlcss and
htmlfont $t commands
10-Jan-2016 nm mmwtex.c - delete duplicate -4px style; metamath.c -
add &nbsp; 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 <A NAME... tag to math symbol cell in proof pages so
hyperlink will jump to top of cell (reported by Alan Sare)
2. daw mmpfas.c - add INLINE speedup if compiler permits
3. nm metamath.c, mminou.c, mmwtex.c, mmpfas.c - fix clang -Wall warnings
(reported by David A. Wheeler) */
/* 0.116 9-May-2015 nm mmwtex.c - adjust paragraph break in 'write th';
Statement List renamed Theorem List; prevent space in after paragraph
in Theorem List; remove stray "("; put header and header comment
in same table cell; fix <TITLE> 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 <HTML>...</HTML> 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 <step>' to 'IMPROVE <step>' for user convenience and to be consistent
with ASSIGN <step> */
/* 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 <string.h>
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
/* #include <time.h> */ /* 21-Jun-2014 nm For ELAPSED_TIME */
#ifdef THINK_C
#include <console.h>
#endif
#include "mmutil.h"
#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"
#ifdef THINK_C
#include "mmmaci.h"
#endif
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 */
#ifdef THINK_C
/* Set console attributes */
console_options.pause_atexit = 0; /* No pause at exit */
console_options.title = (unsigned char*)"\pMetamath";
#endif
#ifdef THINK_C
/* The standard stream triggers the console package to initialize the
Macintosh Toolbox managers and use the console interface. cshow must
be called before using our own window to prevent crashing (THINK C
Standard Library Reference p. 43). */
cshow(stdout);
/* Initialize MacIntosh interface */
/*ToolBoxInit(); */ /* cshow did this automatically */
/* Display opening window */
/*
WindowInit();
DrawMyPicture();
*/
/* Wait for mouse click or key */
/*while (!Button());*/
#endif
/****** 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)));
}
/* if (argc < 2) */ print2("Type HELP for help, EXIT to exit.\n");
/* Allocate big arrays */
initBigArrays();
/* 14-May-2017 nm */
/* 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;
/* 1-Nov-2013 nm 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 */ /* 28-Jun-2013 nm */
flag texFlag; /* Flag for TeX */
flag saveFlag; /* Flag to save in source */
flag fastFlag; /* Flag for SAVE PROOF.../FAST */ /* 2-Jan-2017 nm */
long indentation; /* Number of spaces to indent proof */
vstring labelMatch = ""; /* SHOW PROOF <label> argument */
flag axiomFlag; /* For SHOW TRACE_BACK */
flag treeFlag; /* For SHOW TRACE_BACK */ /* 19-May-2013 nm */
flag countStepsFlag; /* For SHOW TRACE_BACK */ /* 19-May-2013 nm */
flag matchFlag; /* For SHOW TRACE_BACK */ /* 19-May-2013 nm */
vstring matchList = ""; /* For SHOW TRACE_BACK */ /* 19-May-2013 nm */
vstring traceToList = ""; /* For SHOW TRACE_BACK */ /* 18-Jul-2015 nm */
flag recursiveFlag; /* For SHOW USAGE */
long fromLine, toLine; /* For TYPE, SEARCH */
flag joinFlag; /* For SEARCH */
long searchWindow; /* For SEARCH */
FILE *type_fp; /* For TYPE, SEARCH */
long maxEssential; /* For MATCH */
nmbrString *essentialFlags = NULL_NMBRSTRING;
/* For ASSIGN/IMPROVE FIRST/LAST */
long improveDepth; /* For IMPROVE */
flag searchAlg; /* For IMPROVE */ /* 22-Aug-2012 nm */
flag searchUnkSubproofs; /* For IMPROVE */ /* 4-Sep-2012 nm */
flag dummyVarIsoFlag; /* For IMPROVE */ /* 25-Aug-2012 nm */
long improveAllIter; /* For IMPROVE ALL */ /* 25-Aug-2012 nm */
flag proofStepUnk; /* For IMPROVE ALL */ /* 25-Aug-2012 nm */
flag texHeaderFlag; /* For OPEN TEX, CLOSE TEX */
flag commentOnlyFlag; /* For SHOW STATEMENT */
flag briefFlag; /* For SHOW STATEMENT */
flag linearFlag; /* For SHOW LABELS */
vstring bgcolor = ""; /* For SHOW STATEMENT definition list */
/* 8-Aug-2008 nm */
flag verboseMode, mayGrowFlag /*, noDistinctFlag*/; /* For MINIMIZE_WITH */
long prntStatus; /* For MINIMIZE_WITH */
flag hasWildCard; /* For MINIMIZE_WITH */
long exceptPos; /* For MINIMIZE_WITH */
flag mathboxFlag; /* For MINIMIZE_WITH */ /* 28-Jun-2011 nm */
long thisMathboxStartStmt; /* For MINIMIZE_WITH */ /* 14-Aug-2012 nm */
flag forwFlag; /* For MINIMIZE_WITH */ /* 11-Nov-2011 nm */
long forbidMatchPos; /* For MINIMIZE_WITH */ /* 20-May-2013 nm */
vstring forbidMatchList = ""; /* For MINIMIZE_WITH */ /* 20-May-2013 nm */
long noNewAxiomsMatchPos; /* For NO_NEW_AXIOMS_FROM */ /* 22-Nov-2014 nm */
vstring noNewAxiomsMatchList = ""; /* For NO_NEW_AXIOMS_FROM */ /* 22-Nov-2014 */
long allowNewAxiomsMatchPos; /* For NO_NEW_AXIOMS_FROM */ /* 4-Aug-2019 nm */
vstring allowNewAxiomsMatchList = ""; /* For NO_NEW_AXIOMS_FROM */ /* 4-Aug-2019 */
vstring traceProofFlags = ""; /* For NO_NEW_AXIOMS_FROM */ /* 22-Nov-2014 nm */
vstring traceTrialFlags = ""; /* For NO_NEW_AXIOMS_FROM */ /* 22-Nov-2014 nm */
flag overrideFlag; /* For discouraged statement /OVERRIDE */ /* 3-May-2016 nm */
struct pip_struct saveProofForReverting = {
NULL_NMBRSTRING, NULL_PNTRSTRING, NULL_PNTRSTRING, NULL_PNTRSTRING };
/* For MINIMIZE_WITH */ /* 20-May-2013 nm */
long origCompressedLength; /* For MINIMIZE_WITH */ /* 25-Jun-2014 nm */
long oldCompressedLength = 0; /* For MINIMIZE_WITH */ /* 25-Jun-2014 nm */
long newCompressedLength = 0; /* For MINIMIZE_WITH */ /* 25-Jun-2014 nm */
long forwardCompressedLength = 0; /* For MINIMIZE_WITH */ /* 25-Jun-2014 nm */
long forwardLength = 0; /* For MINIMIZE_WITH */ /* 25-Jun-2014 nm */
vstring saveZappedProofSectionPtr; /* Pointer only */ /* For MINIMIZE_WITH */
long saveZappedProofSectionLen; /* For MINIMIZE_WITH */ /* 25-Jun-2014 nm */
flag saveZappedProofSectionChanged; /* For MINIMIZE_WITH */ /* 16-Jun-2017 nm */
struct pip_struct saveOrigProof = {
NULL_NMBRSTRING, NULL_PNTRSTRING, NULL_PNTRSTRING, NULL_PNTRSTRING };
/* For MINIMIZE_WITH */ /* 25-Jun-2014 nm */
struct pip_struct save1stPassProof = {
NULL_NMBRSTRING, NULL_PNTRSTRING, NULL_PNTRSTRING, NULL_PNTRSTRING };
/* For MINIMIZE_WITH */ /* 25-Jun-2014 nm */
long forwRevPass; /* 1 = forward pass */ /* 25-Jun-2014 nm */
long sourceStatement; /* For EXPAND */ /* 11-Sep-2016 nm */
flag showLemmas; /* For WRITE THEOREM_LIST */ /* 10-Oct-2012 nm */
flag noVersioning; /* For WRITE THEOREM_LIST & others */ /* 17-Jul-2019 nm */
long theoremsPerPage; /* For WRITE THEOREM_LIST */ /* 17-Jul-2019 nm */
/* g_toolsMode-specific variables */
flag commandProcessedFlag = 0; /* Set when the first command line processed;
used to exit shell command line mode */
FILE *list1_fp;
FILE *list2_fp;
FILE *list3_fp;
vstring list2_fname = "", list2_ftmpname = "";
vstring list3_ftmpname = "";
vstring oldstr = "", newstr = "";
long lines, changedLines, oldChangedLines, twoMatches, p1, p2;
long firstChangedLine;
flag cmdMode, changedFlag, outMsgFlag;
double sum;
vstring bufferedLine = "";
vstring tagStartMatch = ""; /* 2-Jul-2011 nm For TAG command */
long tagStartCount = 0; /* 2-Jul-2011 nm For TAG command */
vstring tagEndMatch = ""; /* 2-Jul-2011 nm For TAG command */
long tagEndCount = 0; /* 2-Jul-2011 nm For TAG command */
long tagStartCounter = 0; /* 2-Jul-2011 nm For TAG command */
long tagEndCounter = 0; /* 2-Jul-2011 nm For TAG command */
/* 21-Jun-2014 */
/* 16-Aug-2016 nm Now in getElapasedTime() */
/* clock_t timePrevious = 0; */ /* For SHOW ELAPSED_TIME command */
/* clock_t timeNow = 0; */ /* For SHOW ELAPSED_TIME command */
/* 16-Aug-2016 nm */
double timeTotal = 0;
double timeIncr = 0;
flag printTime; /* Set by "/ TIME" in SAVE PROOF and others */
/* 14-Aug-2018 nm */
flag defaultScrollMode = 1; /* Default to prompted mode */
/* Initialization to avoid compiler warning (should not be theoretically
necessary) */
p = 0;
q = 0;
s = 0;
texHeaderFlag = 0;
firstChangedLine = 0;
tagStartCount = 0; /* 2-Jul-2011 nm For TAG command */
tagEndCount = 0; /* 2-Jul-2011 nm For TAG command */
tagStartCounter = 0; /* 2-Jul-2011 nm For TAG command */
tagEndCounter = 0; /* 2-Jul-2011 nm For TAG command */
while (1) {
if (g_listMode) {
/* If called from the OS shell with arguments, do one command
then exit program. */
/* (However, let a SUBMIT job complete) */
if (argc > 1 && commandProcessedFlag &&
g_commandFileNestingLevel == 0) return;
}
g_errorCount = 0; /* Reset error count before each read or proof parse. */
/* Deallocate stuff that may have been used in previous pass */
let(&str1,"");
let(&str2,"");
let(&str3,"");
let(&str4,"");
let(&str5,"");
nmbrLet(&nmbrTmp, NULL_NMBRSTRING);
pntrLet(&pntrTmp, NULL_PNTRSTRING);
nmbrLet(&nmbrSaveProof, NULL_NMBRSTRING);
nmbrLet(&essentialFlags, NULL_NMBRSTRING);
j = nmbrLen(g_rawArgNmbr);
if (j != g_rawArgs) bug(1110);
j = pntrLen(g_rawArgPntr);
if (j != g_rawArgs) bug(1111);
g_rawArgs = 0;
for (i = 0; i < j; i++) let((vstring *)(&g_rawArgPntr[i]), "");
pntrLet(&g_rawArgPntr, NULL_PNTRSTRING);
nmbrLet(&g_rawArgNmbr, NULL_NMBRSTRING);
j = pntrLen(g_fullArg);
for (i = 0; i < j; i++) let((vstring *)(&g_fullArg[i]),"");
pntrLet(&g_fullArg,NULL_PNTRSTRING);
j = pntrLen(expandedProof);
if (j) {
for (i = 0; i < j; i++) {
let((vstring *)(&expandedProof[i]),"");
}
pntrLet(&expandedProof,NULL_PNTRSTRING);
}
let(&list2_fname, "");
let(&list2_ftmpname, "");
let(&list3_ftmpname, "");
let(&oldstr, "");
let(&newstr, "");
let(&labelMatch, "");
/* (End of space deallocation) */
g_midiFlag = 0; /* 8/28/00 Initialize here in case SHOW PROOF exits early */
if (g_memoryStatus) {
/*??? Change to user-friendly message */
#ifdef THINK_C
print2("Memory: string %ld xxxString %ld free %ld\n",db,db3,(long)FreeMem());
getPoolStats(&i, &j, &k);
print2("Pool: free alloc %ld used alloc %ld used actual %ld\n",i,j,k);
#else
print2("Memory: string %ld xxxString %ld\n",db,db3);
#endif
getPoolStats(&i, &j, &k);
print2("Pool: free alloc %ld used alloc %ld used actual %ld\n",i,j,k);
}
if (!g_toolsMode) {
if (g_PFASmode) {
let(&g_commandPrompt,"MM-PA> ");
} else {
let(&g_commandPrompt,"MM> ");
}
} else {
if (g_listMode) {
let(&g_commandPrompt,"Tools> ");
} else {
let(&g_commandPrompt,"TOOLS> ");
}
}
let(&g_commandLine,""); /* Deallocate previous contents */
if (!commandProcessedFlag && argc > 1 && argsProcessed < argc - 1
&& g_commandFileNestingLevel == 0) {
/* if (g_toolsMode) { */ /* 10-Oct-2006 nm Fix bug: changed to g_listMode */
if (g_listMode) {
/* If program was compiled in TOOLS mode, the command-line argument
is assumed to be a single TOOLS command; build the equivalent
TOOLS command */
for (i = 1; i < argc; i++) {
argsProcessed++;
/* Put quotes around an argument with spaces or tabs or quotes
or empty string */
if (instr(1, argv[i], " ") || instr(1, argv[i], "\t")
|| instr(1, argv[i], "\"") || instr(1, argv[i], "'")
|| (argv[i])[0] == 0) {
/* If it contains a double quote, use a single quote */
if (instr(1, argv[i], "\"")) {
let(&str1, cat("'", argv[i], "'", NULL));
} else {
/* (??? (TODO)Case of both ' and " is not handled) */
let(&str1, cat("\"", argv[i], "\"", NULL));
}
} else {
let(&str1, argv[i]);
}
let(&g_commandLine, cat(g_commandLine, (i == 1) ? "" : " ", str1, NULL));
}
} else {
/* If program was compiled in default (Metamath) mode, each command-line
argument is considered a full Metamath command. User is responsible
for ensuring necessary quotes around arguments are passed in. */
argsProcessed++;
g_scrollMode = 0; /* Set continuous scrolling until completed */
let(&g_commandLine, cat(g_commandLine, argv[argsProcessed], NULL));
if (argc == 2 && instr(1, argv[1], " ") == 0) {
/* Assume the user intended a READ command. This special mode allows
invocation via "metamath xxx.mm". */
if (instr(1, g_commandLine, "\"") || instr(1, g_commandLine, "'")) {
/* If it already has quotes don't put quotes */
let(&g_commandLine, cat("READ ", g_commandLine, NULL));
} else {
/* Put quotes so / won't be interpreted as qualifier separator */
let(&g_commandLine, cat("READ \"", g_commandLine, "\"", NULL));
}
/***** 3-Jan-2017 nm This is now done with SET ROOT_DIRECTORY
/@ 31-Dec-2017 nm @/
/@ This block of code can be removed without side effects @/
/@ "Hidden" hack for NM's convenience. :) If there is an =, change
it to space. This lets users invoke with "metamath set.mm/h=test"
or "metamath mbox/aa.mm/home=test" to specify an implicit read with
/ROOT_DIRECTORY without having a space in the argument (a space
means don't assume a read command). @/
i = instr(1, g_commandLine, "=");
if (i != 0) {
/@ Change 'READ "set.mm/h=test"' to 'READ "set.mm" / "h" "test"' @/
let(&g_commandLine, cat(left(g_commandLine, i - 1), "\" \"",
right(g_commandLine, i + 1), NULL));
while (i > 0) {
if (g_commandLine[i - 1] == '/') {
let(&g_commandLine, cat(left(g_commandLine, i - 1),
"\" / \"", right(g_commandLine, i + 1), NULL));
break;
}
i--;
}
/@ Change ' to " to prevent mismatched quotes @/
i = (long)strlen(g_commandLine);
while (i > 0) {
if (g_commandLine[i - 1] == '\'') {
g_commandLine[i - 1] = '"';
}
i--;
}
} /@ if i != 0 (end of 31-Dec-2017 NM hack) @/
*/
}
}
print2("%s\n", cat(g_commandPrompt, g_commandLine, NULL));
} else {
/* Get command from user input or SUBMIT script file */
g_commandLine = cmdInput1(g_commandPrompt);
}
if (argsProcessed == argc && !commandProcessedFlag) {
commandProcessedFlag = 1;
g_scrollMode = defaultScrollMode; /* Set prompted (default) scroll mode */
}
if (argsProcessed == argc - 1) {
argsProcessed++; /* Indicates restore scroll mode next time around */
if (g_toolsMode) {
/* If program was compiled in TOOLS mode, we're only going to execute
one command; set flag to exit next time around */
commandProcessedFlag = 1;
}
}
/* See if it's an operating system command */
/* (This is a command line that begins with a quote) */
if (g_commandLine[0] == '\'' || g_commandLine[0] == '\"') {
/* See if this computer has this feature */
if (!system(NULL)) {
print2("?This computer does not accept an operating system command.\n");
continue;
} else {
/* Strip off quote and trailing quote if any */
let(&str1, right(g_commandLine, 2));
if (g_commandLine[0]) { /* (Prevent stray pointer if empty string) */
if (g_commandLine[0] == g_commandLine[strlen(g_commandLine) - 1]) {
let(&str1, left(str1, (long)(strlen(str1)) - 1));
}
}
/* Do the operating system command */
(void)system(str1);
#ifdef VAXC
printf("\n"); /* Last line from VAX doesn't have new line */
#endif
continue;
}
}
parseCommandLine(g_commandLine);
if (g_rawArgs == 0) {
continue; /* Empty or comment line */
}
if (!processCommandLine()) {
continue;
}
if (g_commandEcho || (g_toolsMode && g_listFile_fp != NULL)) {
/* Build the complete command and print it for the user */
k = pntrLen(g_fullArg);
let(&str1,"");
for (i = 0; i < k; i++) {
if (instr(1, g_fullArg[i], " ") || instr(1, g_fullArg[i], "\t")
|| instr(1, g_fullArg[i], "\"") || instr(1, g_fullArg[i], "'")
|| ((char *)(g_fullArg[i]))[0] == 0) {
/* If the argument has spaces or tabs or quotes
or is empty string, put quotes around it */
if (instr(1, g_fullArg[i], "\"")) {
let(&str1, cat(str1, "'", g_fullArg[i], "' ", NULL));
} else {
/* (???Case of both ' and " is not handled) */
let(&str1, cat(str1, "\"", g_fullArg[i], "\" ", NULL));
}
} else {
let(&str1, cat(str1, g_fullArg[i], " ", NULL));
}
}
let(&str1, left(str1, (long)(strlen(str1)) - 1)); /* Trim trailing spc */
if (g_toolsMode && g_listFile_fp != NULL) {
/* Put line in list.tmp as command */
fprintf(g_listFile_fp, "%s\n", str1); /* Print to list command file */
}
if (g_commandEcho) {
/* 15-Jun-2009 nm Added code line below */
/* Put special character "!" before line for easier extraction to
build SUBMIT files; see also SET ECHO ON output below */
let(&str1, cat("!", str1, NULL));
/* The tilde is a special flag for printLongLine to print a
tilde before the carriage return in a split line, not after */
printLongLine(str1, "~", " ");
}
}
if (cmdMatches("BEEP") || cmdMatches("B")) {
/* Print a bell (if user types ahead "B", the bell lets him know when
his command is finished - useful for long-running commands */
print2("%c",7);
continue;
}
if (cmdMatches("HELP")) {
/* Build the complete command */
k = pntrLen(g_fullArg);
let(&str1,"");
for (i = 0; i < k; i++) {
let(&str1, cat(str1, g_fullArg[i], " ", NULL));
}
let(&str1, left(str1, (long)(strlen(str1)) - 1));
if (g_toolsMode) {
help0(str1);
help1(str1);
} else {
help1(str1);
help2(str1);
help3(str1); /* 18-Jul-2015 nm */
}
continue;
}
if (cmdMatches("SET SCROLL")) {
if (cmdMatches("SET SCROLL CONTINUOUS")) {
defaultScrollMode = 0;
g_scrollMode = 0;
print2("Continuous scrolling is now in effect.\n");
} else {
defaultScrollMode = 1;
g_scrollMode = 1;
print2("Prompted scrolling is now in effect.\n");
}
continue;
}
if (cmdMatches("EXIT") || cmdMatches("QUIT")
|| cmdMatches("_EXIT_PA")) { /* 9-Jun-2016 - for MM-PA> exit
in scripts, so it will error out in MM> (if for some reason
MM-PA wasn't entered) instead of exiting metamath */
/*??? || !strcmp(cmd,"^Z")) { */
/* 9-Jun-2016 */
if (cmdMatches("_EXIT_PA")) {
if (!g_PFASmode || (g_toolsMode && !g_listMode)) bug(1127);
/* mmcmdl.c should have caught this */
}
if (g_toolsMode && !g_listMode) {
/* Quitting tools command from within Metamath */
if (!g_PFASmode) {
print2(
"Exiting the Text Tools. Type EXIT again to exit Metamath.\n");
} else {
print2(
"Exiting the Text Tools. Type EXIT again to exit the Proof Assistant.\n");
}
g_toolsMode = 0;
continue;
}
if (g_PFASmode) {
if (g_proofChanged &&
/* If g_proofChanged, but the UNDO stack is empty (and
there were no other conditions such as stack overflow),
the proof didn't really change, so it is safe to
exit MM-PA without warning */
(processUndoStack(NULL, PUS_GET_STATUS, "", 0)
/* However, if the proof was saved earlier, UNDO stack
empty no longer indicates proof didn't change */
|| proofSavedFlag)) {
print2(
"Warning: You have not saved changes to the proof of \"%s\".\n",
g_Statement[g_proveStatement].labelName); /* 21-Jan-06 nm */
/* 17-Aug-04 nm Added / FORCE qualifier */
if (switchPos("/ FORCE") == 0) {
str1 = cmdInput1("Do you want to EXIT anyway (Y, N) <N>? ");
if (str1[0] != 'y' && str1[0] != 'Y') {
print2("Use SAVE NEW_PROOF to save the proof.\n");
continue;
}
} else {
/* User specified / FORCE, so answer question automatically */
print2("Do you want to EXIT anyway (Y, N) <N>? Y\n");
}
}
g_proofChanged = 0;
processUndoStack(NULL, PUS_INIT, "", 0);
proofSavedFlag = 0; /* Will become 1 if proof is ever saved */
print2(
"Exiting the Proof Assistant. Type EXIT again to exit Metamath.\n");
/* Deallocate proof structure */
deallocProofStruct(&g_ProofInProgress); /* 20-May-2013 nm */
/**** old deallocation before 20-May-2013
i = nmbrLen(g_ProofInProgress.proof);
nmbrLet(&g_ProofInProgress.proof, NULL_NMBRSTRING);
for (j = 0; j < i; j++) {
nmbrLet((nmbrString **)(&((g_ProofInProgress.target)[j])),
NULL_NMBRSTRING);
nmbrLet((nmbrString **)(&((g_ProofInProgress.source)[j])),
NULL_NMBRSTRING);
nmbrLet((nmbrString **)(&((g_ProofInProgress.user)[j])),
NULL_NMBRSTRING);
}
pntrLet(&g_ProofInProgress.target, NULL_PNTRSTRING);
pntrLet(&g_ProofInProgress.source, NULL_PNTRSTRING);
pntrLet(&g_ProofInProgress.user, NULL_PNTRSTRING);
*** end of old code before 20-May-2013 */
g_PFASmode = 0;
continue;
} else {
if (g_sourceChanged) {
print2("Warning: You have not saved changes to the source.\n");
/* 17-Aug-04 nm Added / FORCE qualifier */
if (switchPos("/ FORCE") == 0) {
str1 = cmdInput1("Do you want to EXIT anyway (Y, N) <N>? ");
if (str1[0] != 'y' && str1[0] != 'Y') {
print2("Use WRITE SOURCE to save the changes.\n");
continue;
}
} else {
/* User specified / FORCE, so answer question automatically */
print2("Do you want to EXIT anyway (Y, N) <N>? Y\n");
}
g_sourceChanged = 0;
}
if (g_texFileOpenFlag) {
print2("The %s file \"%s\" was closed.\n",
g_htmlFlag ? "HTML" : "LaTeX", g_texFileName);
printTexTrailer(texHeaderFlag);
fclose(g_texFilePtr);
g_texFileOpenFlag = 0;
}
if (g_logFileOpenFlag) {
print2("The log file \"%s\" was closed %s %s.\n",g_logFileName,
date(),time_());
fclose(g_logFilePtr);
g_logFileOpenFlag = 0;
}
/* 4-May-2017 Ari Ferrera */
/* Free remaining allocations before exiting */
freeCommandLine();
freeInOu();
memFreePoolPurge(0);
eraseSource();
freeData(); /* Call AFTER eraseSource()(->initBigArrays->malloc) */
let(&g_commandPrompt,"");
let(&g_commandLine,"");
let(&g_input_fn,"");
let(&g_contributorName, ""); /* 14-May-2017 nm */
return; /* Exit from program */
}
}
if (cmdMatches("SUBMIT")) {
if (g_commandFileNestingLevel == MAX_COMMAND_FILE_NESTING) {
printf("?The SUBMIT nesting level has been exceeded.\n");
continue;
}
g_commandFilePtr[g_commandFileNestingLevel + 1] = fSafeOpen(g_fullArg[1], "r",
0/*noVersioningFlag*/);
if (!g_commandFilePtr[g_commandFileNestingLevel + 1]) continue;
/* Couldn't open (err msg was provided) */
g_commandFileNestingLevel++;
g_commandFileName[g_commandFileNestingLevel] = ""; /* Initialize if nec. */
let(&g_commandFileName[g_commandFileNestingLevel], g_fullArg[1]);
/* 23-Oct-2006 nm Added / SILENT */
g_commandFileSilent[g_commandFileNestingLevel] = 0;
if (switchPos("/ SILENT")
|| g_commandFileSilentFlag /* Propagate silence from outer level */) {
g_commandFileSilent[g_commandFileNestingLevel] = 1;
} else {
g_commandFileSilent[g_commandFileNestingLevel] = 0;
}
g_commandFileSilentFlag = g_commandFileSilent[g_commandFileNestingLevel];
if (!g_commandFileSilentFlag)
print2("Taking command lines from file \"%s\"...\n",
g_commandFileName[g_commandFileNestingLevel]);
continue;
}
if (g_toolsMode) {
/* Start of g_toolsMode-specific commands */
#define ADD_MODE 1
#define DELETE_MODE 2
#define CLEAN_MODE 3
#define SUBSTITUTE_MODE 4
#define SWAP_MODE 5
#define INSERT_MODE 6
#define BREAK_MODE 7
#define BUILD_MODE 8
#define MATCH_MODE 9
#define RIGHT_MODE 10
#define TAG_MODE 11 /* 2-Jul-2011 nm Added TAG command */
cmdMode = 0;
if (cmdMatches("ADD")) cmdMode = ADD_MODE;
else if (cmdMatches("DELETE")) cmdMode = DELETE_MODE;
else if (cmdMatches("CLEAN")) cmdMode = CLEAN_MODE;
else if (cmdMatches("SUBSTITUTE") || cmdMatches("S"))
cmdMode = SUBSTITUTE_MODE;
else if (cmdMatches("SWAP")) cmdMode = SWAP_MODE;
else if (cmdMatches("INSERT")) cmdMode = INSERT_MODE;
else if (cmdMatches("BREAK")) cmdMode = BREAK_MODE;
else if (cmdMatches("BUILD")) cmdMode = BUILD_MODE;
else if (cmdMatches("MATCH")) cmdMode = MATCH_MODE;
else if (cmdMatches("RIGHT")) cmdMode = RIGHT_MODE;
else if (cmdMatches("TAG")) cmdMode = TAG_MODE;
if (cmdMode) {
list1_fp = fSafeOpen(g_fullArg[1], "r", 0/*noVersioningFlag*/);
if (!list1_fp) continue; /* Couldn't open it (error msg was provided) */
if (cmdMode == RIGHT_MODE) {
/* Find the longest line */
p = 0;
while (linput(list1_fp, NULL, &str1)) {
if (p < (signed)(strlen(str1))) p = (long)(strlen(str1));
}
rewind(list1_fp);
}
let(&list2_fname, g_fullArg[1]);
if (list2_fname[strlen(list2_fname) - 2] == '~') {
let(&list2_fname, left(list2_fname, (long)(strlen(list2_fname)) - 2));
print2("The output file will be called %s.\n", list2_fname);
}
let(&list2_ftmpname, "");
list2_ftmpname = fGetTmpName("zz~tools");
list2_fp = fSafeOpen(list2_ftmpname, "w", 0/*noVersioningFlag*/);
if (!list2_fp) continue; /* Couldn't open it (error msg was provided) */
lines = 0;
changedLines = 0;
twoMatches = 0;
changedFlag = 0;
outMsgFlag = 0;
switch (cmdMode) {
case ADD_MODE:
break;
case TAG_MODE: /* 2-Jul-2011 nm Added TAG command */
let(&tagStartMatch, g_fullArg[4]);
tagStartCount = (long)val(g_fullArg[5]);
if (tagStartCount == 0) tagStartCount = 1; /* Default */
let(&tagEndMatch, g_fullArg[6]);
tagEndCount = (long)val(g_fullArg[7]);
if (tagEndCount == 0) tagEndCount = 1; /* Default */
tagStartCounter = 0;
tagEndCounter = 0;
break;
case DELETE_MODE:
break;
case CLEAN_MODE:
let(&str4, edit(g_fullArg[2], 32));
q = 0;
if (instr(1, str4, "P") > 0) q = q + 1;
if (instr(1, str4, "D") > 0) q = q + 2;
if (instr(1, str4, "G") > 0) q = q + 4;
if (instr(1, str4, "B") > 0) q = q + 8;
if (instr(1, str4, "R") > 0) q = q + 16;
if (instr(1, str4, "C") > 0) q = q + 32;
if (instr(1, str4, "E") > 0) q = q + 128;
if (instr(1, str4, "Q") > 0) q = q + 256;
if (instr(1, str4, "L") > 0) q = q + 512;
if (instr(1, str4, "T") > 0) q = q + 1024;
if (instr(1, str4, "U") > 0) q = q + 2048;
if (instr(1, str4, "V") > 0) q = q + 4096;
break;
case SUBSTITUTE_MODE:
let(&newstr, g_fullArg[3]); /* The replacement string */
if (((vstring)(g_fullArg[4]))[0] == 'A' ||
((vstring)(g_fullArg[4]))[0] == 'a') { /* ALL */
q = -1;
} else {
q = (long)val(g_fullArg[4]);
if (q == 0) q = 1; /* The occurrence # of string to subst */
}
s = instr(1, g_fullArg[2], "\\n");
if (s) {
/*s = 1;*/ /* Replace lf flag */
q = 1; /* Only 1st occurrence makes sense in this mode */
}
if (!strcmp(g_fullArg[3], "\\n")) {
let(&newstr, "\n"); /* Replace with lf */
}
break;
case SWAP_MODE:
break;
case INSERT_MODE:
p = (long)val(g_fullArg[3]);
break;
case BREAK_MODE:
outMsgFlag = 1;
break;
case BUILD_MODE:
let(&str4, "");
outMsgFlag = 1;
break;
case MATCH_MODE:
outMsgFlag = 1;
} /* End switch */
let(&bufferedLine, "");
/*
while (linput(list1_fp, NULL, &str1)) {
*/
while (1) {
if (bufferedLine[0]) {
/* Get input from buffered line (from rejected \n replacement) */
let(&str1, bufferedLine);
let(&bufferedLine, "");
} else {
if (!linput(list1_fp, NULL, &str1)) break;
}
lines++;
oldChangedLines = changedLines;
let(&str2, str1);
switch (cmdMode) {
case ADD_MODE:
let(&str2, cat(g_fullArg[2], str1, g_fullArg[3], NULL));
if (strcmp(str1, str2)) changedLines++;
break;
case TAG_MODE: /* 2-Jul-2011 nm Added TAG command */
if (tagStartCounter < tagStartCount) {
if (instr(1, str1, tagStartMatch)) tagStartCounter++;
}
if (tagStartCounter == tagStartCount &&
tagEndCounter < tagEndCount) { /* We're in tagging range */
let(&str2, cat(g_fullArg[2], str1, g_fullArg[3], NULL));
if (strcmp(str1, str2)) changedLines++;
if (instr(1, str1, tagEndMatch)) tagEndCounter++;
}
break;
case DELETE_MODE:
p1 = instr(1, str1, g_fullArg[2]);
if (strlen(g_fullArg[2]) == 0) p1 = 1;
p2 = instr(p1, str1, g_fullArg[3]);
if (strlen(g_fullArg[3]) == 0) p2 = (long)strlen(str1) + 1;
if (p1 != 0 && p2 != 0) {
let(&str2, cat(left(str1, p1 - 1), right(str1, p2
+ (long)strlen(g_fullArg[3])), NULL));
changedLines++;
}
break;
case CLEAN_MODE:
if (q) {
let(&str2, edit(str1, q));
if (strcmp(str1, str2)) changedLines++;
}
break;
case SUBSTITUTE_MODE:
let(&str2, str1);
p = 0;
p1 = 0;
k = 1;
/* See if an additional match on line is required */
if (((vstring)(g_fullArg[5]))[0] != 0) {
if (!instr(1, str2, g_fullArg[5])) {
/* No match on line; prevent any substitution */
k = 0;
}
}
if (s && k) { /* We're asked to replace a newline char */
/* Read in the next line */
/*
if (linput(list1_fp, NULL, &str4)) {
let(&str2, cat(str1, "\\n", str4, NULL));
*/
if (linput(list1_fp, NULL, &bufferedLine)) {
/* Join the next line and see if the string matches */
if (instr(1, cat(str1, "\\n", bufferedLine, NULL),
g_fullArg[2])) {
let(&str2, cat(str1, "\\n", bufferedLine, NULL));
let(&bufferedLine, "");
} else {
k = 0; /* No match - leave bufferedLine for next pass */
}
} else { /* EOF reached */
print2("Warning: file %s has an odd number of lines\n",
g_fullArg[1]);
}
}
while (k) {
p1 = instr(p1 + 1, str2, g_fullArg[2]);
if (!p1) break;
p++;
if (p == q || q == -1) {
let(&str2, cat(left(str2, p1 - 1), newstr,
right(str2, p1 + (long)strlen(g_fullArg[2])), NULL));
if (newstr[0] == '\n') {
/* Replacement string is an lf */
lines++;
changedLines++;
}
/* 14-Sep-2010 nm Continue the search after the replacement
string, so that "SUBST 1.tmp abbb ab a ''" will change
"abbbab" to "abba" rather than "aa" */
p1 = p1 + (long)strlen(newstr) - 1;
/* p1 = p1 - (long)strlen(g_fullArg[2]) + (long)strlen(newstr); */ /* bad */
if (q != -1) break;
}
}
if (strcmp(str1, str2)) changedLines++;
break;
case SWAP_MODE:
p1 = instr(1, str1, g_fullArg[2]);
if (p1) {
p2 = instr(p1 + 1, str1, g_fullArg[2]);
if (p2) twoMatches++;
let(&str2, cat(right(str1, p1) + (long)strlen(g_fullArg[2]),
g_fullArg[2], left(str1, p1 - 1), NULL));
if (strcmp(str1, str2)) changedLines++;
}
break;
case INSERT_MODE:
if ((signed)(strlen(str2)) < p - 1)
let(&str2, cat(str2, space(p - 1 - (long)strlen(str2)), NULL));
let(&str2, cat(left(str2, p - 1), g_fullArg[2],
right(str2, p), NULL));
if (strcmp(str1, str2)) changedLines++;
break;
case BREAK_MODE:
let(&str2, str1);
changedLines++;
for (i = 0; i < (signed)(strlen(g_fullArg[2])); i++) {
p = 0;
while (1) {
p = instr(p + 1, str2, chr(((vstring)(g_fullArg[2]))[i]));
if (!p) break;
/* Put spaces arount special one-char tokens */
let(&str2, cat(left(str2, p - 1), " ",
mid(str2, p, 1),
" ", right(str2, p + 1), NULL));
/*p++;*/
/* Even though space is always a separator, it can be used
to suppress all default tokens. Go past 2nd space to prevent
infinite loop in that case. */
p += 2; /* 3-Jul-2020 nm */
}
}
let(&str2, edit(str2, 8 + 16 + 128)); /* Reduce & trim spaces */
for (p = (long)strlen(str2) - 1; p >= 0; p--) {
if (str2[p] == ' ') {
str2[p] = '\n';
changedLines++;
}
}
if (!str2[0]) changedLines--; /* Don't output blank line */
break;
case BUILD_MODE:
if (str2[0] != 0) { /* Ignore blank lines */
if (str4[0] == 0) {
let(&str4, str2);
} else {
if ((long)strlen(str4) + (long)strlen(str2) > 72) {
let(&str4, cat(str4, "\n", str2, NULL));
changedLines++;
} else {
let(&str4, cat(str4, " ", str2, NULL));
}
}
p = instr(1, str4, "\n");
if (p) {
let(&str2, left(str4, p - 1));
let(&str4, right(str4, p + 1));
} else {
let(&str2, "");
}
}
break;
case MATCH_MODE:
if (((vstring)(g_fullArg[2]))[0] == 0) {
/* Match any non-blank line */
p = str1[0];
} else {
p = instr(1, str1, g_fullArg[2]);
}
if (((vstring)(g_fullArg[3]))[0] == 'n' ||
((vstring)(g_fullArg[3]))[0] == 'N') {
p = !p;
}
if (p) changedLines++;
break;
case RIGHT_MODE:
let(&str2, cat(space(p - (long)strlen(str2)), str2, NULL));
if (strcmp(str1, str2)) changedLines++;
break;
} /* End switch(cmdMode) */
if (lines == 1) let(&str3, left(str2, 79)); /* For msg */
if (oldChangedLines != changedLines && !changedFlag) {
changedFlag = 1;
let(&str3, left(str2, 79)); /* For msg */
firstChangedLine = lines;
if ((cmdMode == SUBSTITUTE_MODE && newstr[0] == '\n')
|| cmdMode == BUILD_MODE) /* Joining lines */ {
firstChangedLine = 1; /* Better message */
}
}
if (((cmdMode != BUILD_MODE && cmdMode != BREAK_MODE)
|| str2[0] != 0)
&& (cmdMode != MATCH_MODE || p))
fprintf(list2_fp, "%s\n", str2);
} /* Next input line */
if (cmdMode == BUILD_MODE) {
if (str4[0]) {
/* Output last partial line */
fprintf(list2_fp, "%s\n", str4);
changedLines++;
if (!str3[0]) {
let(&str3, str4); /* For msg */
}
}
}
/* Remove any lines after lf for readability of msg */
p = instr(1, str3, "\n");
if (p) let(&str3, left(str3, p - 1));
if (!outMsgFlag) {
/* 18-Aug-2011 nm Make message depend on line counts */
if (!changedFlag) {
if (!lines) {
print2("The file %s has no lines.\n", g_fullArg[1]);
} else {
print2(
"The file %s has %ld line%s; none were changed. First line:\n",
list2_fname, lines, (lines == 1) ? "" : "s");
print2("%s\n", str3);
}
} else {
print2(
"The file %s has %ld line%s; %ld w%s changed. First changed line is %ld:\n",
list2_fname,
lines, (lines == 1) ? "" : "s",
changedLines, (changedLines == 1) ? "as" : "ere",
firstChangedLine);
print2("%s\n", str3);
}
if (twoMatches > 0) {
/* For SWAP command */
print2(
"Warning: %ld line%s more than one \"%s\". The first one was used.\n",
twoMatches, (twoMatches == 1) ? " has" : "s have", g_fullArg[2]);
}
} else {
/* if (changedLines == 0) let(&str3, ""); */
print2(
"The input had %ld line%s, the output has %ld line%s.%s\n",
lines, (lines == 1) ? "" : "s",
changedLines, (changedLines == 1) ? "" : "s",
(changedLines == 0) ? "" : " First output line:");
if (changedLines != 0) print2("%s\n", str3);
}
fclose(list1_fp);
fclose(list2_fp);
fSafeRename(list2_ftmpname, list2_fname);
/* Deallocate string memory */
let(&tagStartMatch, ""); /* 2-Jul-2011 nm Added TAG command */
let(&tagEndMatch, ""); /* 2-Jul-2011 nm Added TAG command */
continue;
} /* end if cmdMode for ADD, etc. */
#define SORT_MODE 1
#define UNDUPLICATE_MODE 2
#define DUPLICATE_MODE 3
#define UNIQUE_MODE 4
#define REVERSE_MODE 5
cmdMode = 0;
if (cmdMatches("SORT")) cmdMode = SORT_MODE;
else if (cmdMatches("UNDUPLICATE")) cmdMode = UNDUPLICATE_MODE;
else if (cmdMatches("DUPLICATE")) cmdMode = DUPLICATE_MODE;
else if (cmdMatches("UNIQUE")) cmdMode = UNIQUE_MODE;
else if (cmdMatches("REVERSE")) cmdMode = REVERSE_MODE;
if (cmdMode) {
list1_fp = fSafeOpen(g_fullArg[1], "r", 0/*noVersioningFlag*/);
if (!list1_fp) continue; /* Couldn't open it (error msg was provided) */
let(&list2_fname, g_fullArg[1]);
if (list2_fname[strlen(list2_fname) - 2] == '~') {
let(&list2_fname, left(list2_fname, (long)strlen(list2_fname) - 2));
print2("The output file will be called %s.\n", list2_fname);
}
let(&list2_ftmpname, "");
list2_ftmpname = fGetTmpName("zz~tools");
list2_fp = fSafeOpen(list2_ftmpname, "w", 0/*noVersioningFlag*/);
if (!list2_fp) continue; /* Couldn't open it (error msg was provided) */
/* Count the lines */
lines = 0;
while (linput(list1_fp, NULL, &str1)) lines++;
if (cmdMode != SORT_MODE && cmdMode != REVERSE_MODE) {
print2("The input file has %ld lines.\n", lines);
}
/* Close and reopen the input file */
fclose(list1_fp);
list1_fp = fSafeOpen(g_fullArg[1], "r", 0/*noVersioningFlag*/);
/* Allocate memory */
pntrLet(&pntrTmp, pntrSpace(lines));
/* Assign the lines to string array */
for (i = 0; i < lines; i++) linput(list1_fp, NULL,
(vstring *)(&pntrTmp[i]));
/* Sort */
if (cmdMode != REVERSE_MODE) {
if (cmdMode == SORT_MODE) {
g_qsortKey = g_fullArg[2]; /* Do not deallocate! */
} else {
g_qsortKey = "";
}
qsort(pntrTmp, (size_t)lines, sizeof(void *), qsortStringCmp);
} else { /* Reverse the lines */
for (i = lines / 2; i < lines; i++) {
g_qsortKey = pntrTmp[i]; /* Use g_qsortKey as handy tmp var here */
pntrTmp[i] = pntrTmp[lines - 1 - i];
pntrTmp[lines - 1 - i] = g_qsortKey;
}
}
/* Output sorted lines */
changedLines = 0;
let(&str3, "");
for (i = 0; i < lines; i++) {
j = 0; /* Flag that line should be printed */
switch (cmdMode) {
case SORT_MODE:
case REVERSE_MODE:
j = 1;
break;
case UNDUPLICATE_MODE:
if (i == 0) {
j = 1;
} else {
if (strcmp((vstring)(pntrTmp[i - 1]), (vstring)(pntrTmp[i]))) {
j = 1;
}
}
break;
case DUPLICATE_MODE:
if (i > 0) {
if (!strcmp((vstring)(pntrTmp[i - 1]), (vstring)(pntrTmp[i]))) {
if (i == lines - 1) {
j = 1;
} else {
if (strcmp((vstring)(pntrTmp[i]),
(vstring)(pntrTmp[i + 1]))) {
j = 1;
}
}
}
}
break;
case UNIQUE_MODE:
if (i < lines - 1) {
if (strcmp((vstring)(pntrTmp[i]), (vstring)(pntrTmp[i + 1]))) {
if (i == 0) {
j = 1;
} else {
if (strcmp((vstring)(pntrTmp[i - 1]),
(vstring)(pntrTmp[i]))) {
j = 1;
}
}
}
} else {
if (i == 0) {
j = 1;
} else {
if (strcmp((vstring)(pntrTmp[i - 1]),
(vstring)(pntrTmp[i]))) {
j = 1;
}
}
}
break;
} /* end switch (cmdMode) */
if (j) {
fprintf(list2_fp, "%s\n", (vstring)(pntrTmp[i]));
changedLines++;
if (changedLines == 1)
let(&str3, left((vstring)(pntrTmp[i]), 79));
}
} /* next i */
print2("The output file has %ld lines. The first line is:\n",
changedLines);
print2("%s\n", str3);
/* Deallocate memory */
for (i = 0; i < lines; i++) let((vstring *)(&pntrTmp[i]), "");
pntrLet(&pntrTmp,NULL_PNTRSTRING);
fclose(list1_fp);
fclose(list2_fp);
fSafeRename(list2_ftmpname, list2_fname);
continue;
} /* end if cmdMode for SORT, etc. */
if (cmdMatches("PARALLEL")) {
list1_fp = fSafeOpen(g_fullArg[1], "r", 0/*noVersioningFlag*/);
list2_fp = fSafeOpen(g_fullArg[2], "r", 0/*noVersioningFlag*/);
if (!list1_fp) continue; /* Couldn't open it (error msg was provided) */
if (!list2_fp) continue; /* Couldn't open it (error msg was provided) */
let(&list3_ftmpname, "");
list3_ftmpname = fGetTmpName("zz~tools");
list3_fp = fSafeOpen(list3_ftmpname, "w", 0/*noVersioningFlag*/);
if (!list3_fp) continue; /* Couldn't open it (error msg was provided) */
p1 = 1; p2 = 1; /* not eof */
p = 0; q = 0; /* lines */
j = 0; /* 1st line flag */
let(&str3, "");
while (1) {
let(&str1, "");
if (p1) {
p1 = linput(list1_fp, NULL, &str1);
if (p1) p++;
else let(&str1, "");
}
let(&str2, "");
if (p2) {
p2 = linput(list2_fp, NULL, &str2);
if (p2) q++;
else let(&str2, "");
}
if (!p1 && !p2) break;
let(&str4, cat(str1, g_fullArg[4], str2, NULL));
fprintf(list3_fp, "%s\n", str4);
if (!j) {
let(&str3, str4); /* Save 1st line for msg */
j = 1;
}
}
if (p == q) {
print2(
"The input files each had %ld lines. The first output line is:\n", p);
} else {
print2(
"Warning: file \"%s\" had %ld lines while file \"%s\" had %ld lines.\n",
g_fullArg[1], p, g_fullArg[2], q);
if (p < q) p = q;
print2("The output file \"%s\" has %ld lines. The first line is:\n",
g_fullArg[3], p);
}
print2("%s\n", str3);
fclose(list1_fp);
fclose(list2_fp);
fclose(list3_fp);
fSafeRename(list3_ftmpname, g_fullArg[3]);
continue;
}
if (cmdMatches("NUMBER")) {
list1_fp = fSafeOpen(g_fullArg[1], "w", 0/*noVersioningFlag*/);
if (!list1_fp) continue; /* Couldn't open it (error msg was provided) */
j = (long)strlen(str(val(g_fullArg[2])));
k = (long)strlen(str(val(g_fullArg[3])));
if (k > j) j = k;
for (i = (long)val(g_fullArg[2]); i <= val(g_fullArg[3]);
i = i + (long)val(g_fullArg[4])) {
let(&str1, str((double)i));
fprintf(list1_fp, "%s\n", str1);
}
fclose(list1_fp);
continue;
}
if (cmdMatches("COUNT")) {
list1_fp = fSafeOpen(g_fullArg[1], "r", 0/*noVersioningFlag*/);
if (!list1_fp) continue; /* Couldn't open it (error msg was provided) */
p1 = 0;
p2 = 0;
lines = 0;
q = 0; /* Longest line length */
i = 0; /* First longest line */
j = 0; /* Number of longest lines */
sum = 0.0; /* Sum of numeric content of lines */
firstChangedLine = 0;
while (linput(list1_fp, NULL, &str1)) {
lines++;
/* Longest line */
if (q < (signed)(strlen(str1))) {
q = (long)strlen(str1);
let(&str4, str1);
i = lines;
j = 0;
}
if (q == (signed)(strlen(str1))) {
j++;
}
if (instr(1, str1, g_fullArg[2])) {
if (!firstChangedLine) {
firstChangedLine = lines;
let(&str3, str1);
}
p1++;
p = 0;
while (1) {
p = instr(p + 1, str1, g_fullArg[2]);
if (!p) break;
p2++;
}
}
sum = sum + val(str1);
}
print2(
"The file has %ld lines. The string \"%s\" occurs %ld times on %ld lines.\n",
lines, g_fullArg[2], p2, p1);
if (firstChangedLine) {
print2("The first occurrence is on line %ld:\n", firstChangedLine);
print2("%s\n", str3);
}
print2(
"The first longest line (out of %ld) is line %ld and has %ld characters:\n",
j, i, q);
printLongLine(str4, " "/*startNextLine*/, ""/*breakMatch*/);
/* breakMatch empty means break line anywhere */ /* 6-Dec-03 */
/* print2("If each line were a number, their sum would be %s\n", str((double)sum)); */
printLongLine(cat(
"Stripping all but digits, \".\", and \"-\", the sum of lines is ",
str((double)sum), NULL), " ", " ");
fclose(list1_fp);
continue;
}
if (cmdMatches("TYPE") || cmdMatches("T")) {
list1_fp = fSafeOpen(g_fullArg[1], "r", 0/*noVersioningFlag*/);
if (!list1_fp) continue; /* Couldn't open it (error msg was provided) */
if (g_rawArgs == 2) {
n = 10;
} else {
if (((vstring)(g_fullArg[2]))[0] == 'A' ||
((vstring)(g_fullArg[2]))[0] == 'a') { /* ALL */
n = -1;
} else {
n = (long)val(g_fullArg[2]);
}
}
for (i = 0; i < n || n == -1; i++) {
if (!linput(list1_fp, NULL, &str1)) break;
if (!print2("%s\n", str1)) break;
}
fclose(list1_fp);
continue;
} /* end TYPE */
if (cmdMatches("UPDATE")) {
list1_fp = fSafeOpen(g_fullArg[1], "r", 0/*noVersioningFlag*/);
list2_fp = fSafeOpen(g_fullArg[2], "r", 0/*noVersioningFlag*/);
if (!list1_fp) continue; /* Couldn't open it (error msg was provided) */
if (!list2_fp) continue; /* Couldn't open it (error msg was provided) */
if (!getRevision(g_fullArg[4])) {
print2(
"?The revision tag must be of the form /*nn*/ or /*#nn*/. Please try again.\n");
continue;
}
let(&list3_ftmpname, "");
list3_ftmpname = fGetTmpName("zz~tools");
list3_fp = fSafeOpen(list3_ftmpname, "w", 0/*noVersioningFlag*/);
if (!list3_fp) continue; /* Couldn't open it (error msg was provided) */
revise(list1_fp, list2_fp, list3_fp, g_fullArg[4],
(long)val(g_fullArg[5]));
fSafeRename(list3_ftmpname, g_fullArg[3]);
continue;
}
if (cmdMatches("COPY") || cmdMatches("C")) {
let(&list2_ftmpname, "");
list2_ftmpname = fGetTmpName("zz~tools");
list2_fp = fSafeOpen(list2_ftmpname, "w", 0/*noVersioningFlag*/);
if (!list2_fp) continue; /* Couldn't open it (error msg was provided) */
let(&str4, cat(g_fullArg[1], ",", NULL));
lines = 0;
j = 0; /* Error flag */
while (1) {
if (!str4[0]) break; /* Done scanning list */
p = instr(1, str4, ",");
let(&str3, left(str4, p - 1));
let(&str4, right(str4, p + 1));
list1_fp = fSafeOpen((str3), "r", 0/*noVersioningFlag*/);
if (!list1_fp) { /* Couldn't open it (error msg was provided) */
j = 1; /* Error flag */
break;
}
n = 0;
while (linput(list1_fp, NULL, &str1)) {
lines++; n++;
fprintf(list2_fp, "%s\n", str1);
}
if (instr(1, g_fullArg[1], ",")) { /* More than 1 input file */
print2("The input file \"%s\" has %ld lines.\n", str3, n);
}
fclose(list1_fp);
}
if (j) continue; /* One of the input files couldn't be opened */
fclose(list2_fp);
print2("The output file \"%s\" has %ld lines.\n", g_fullArg[2], lines);
fSafeRename(list2_ftmpname, g_fullArg[2]);
continue;
}
print2("?This command has not been implemented yet.\n");
continue;
} /* End of g_toolsMode-specific commands */
if (cmdMatches("TOOLS")) {
print2(
"Entering the Text Tools utilities. Type HELP for help, EXIT to exit.\n");
g_toolsMode = 1;
continue;
}
if (cmdMatches("READ")) {
/*if (g_statements) {*/
/* 31-Dec-2017 nm */
/* We can't use 'statements > 0' for the test since the source
could be just a comment */
if (g_sourceHasBeenRead == 1) {
printLongLine(cat(
"?Sorry, reading of more than one source file is not allowed. ",
"The file \"", g_input_fn, "\" has already been READ in. ",
/* 11-Dec-05 nm */
"You may type ERASE to start over. Note that additional source ",
"files may be included in the source file with \"$[ <filename> $]\".",
/* 11-Dec-05 nm */
NULL)," "," ");
continue;
}
let(&g_input_fn, g_fullArg[1]);
/***** 3-Jan-2017 nm This is now done with SET ROOT_DIRECTORY
/@ 31-Dec-2017 nm - Added ROOT_DIRECTORY switch @/
/@ TODO - remove this and just use SET ROOT_DIRECTORY instead @/
i = switchPos("/ ROOT_DIRECTORY"); /@ Statement match to skip @/
if (i != 0) {
let(&g_rootDirectory, edit(g_fullArg[i + 1], 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 ) {
/@ 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));
}
}
}
/@
} else {
let(&g_rootDirectory, "");
@/
}
*/
let(&str1, cat(g_rootDirectory, g_input_fn, NULL));
g_input_fp = fSafeOpen(str1, "r", 0/*noVersioningFlag*/);
if (!g_input_fp) continue; /* Couldn't open it (error msg was provided
by fSafeOpen) */
fclose(g_input_fp);
readInput();
/*g_sourceHasBeenRead = 1;*/ /* Global variable - set in readInput() */
if (switchPos("/ VERIFY")) {
verifyProofs("*",1); /* Parse and verify */
} else {
/* verifyProofs("*",0); */ /* Parse only (for gross error checking) */
}
/* 13-Dec-2016 nm Moved to verifyMarkup in mmcmds.c */
/*
/@ 10/21/02 - detect Microsoft bugs reported by several users, when the
HTML output files are named "con.html" etc. @/
/@ If we want a standard error message underlining token, this could go
in mmpars.c @/
/@ From Microsoft's site:
"The following reserved words cannot be used as the name of a file:
CON, PRN, AUX, CLOCK$, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7,
COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9.
Also, reserved words followed by an extension - for example,
NUL.tx7 - are invalid file names." @/
/@ Check for labels that will lead to illegal Microsoft file names for
Windows users. Don't bother checking CLOCK$ since $ is already
illegal @/
let(&str1, cat(
",CON,PRN,AUX,NUL,COM1,COM2,COM3,COM4,COM5,COM6,COM7,",
"COM8,COM9,LPT1,LPT2,LPT3,LPT4,LPT5,LPT6,LPT7,LPT8,LPT9,", NULL));
for (i = 1; i <= g_statements; i++) {
let(&str2, cat(",", edit(g_Statement[i].labelName, 32/@uppercase@/), ",",
NULL));
if (instr(1, str1, str2) ||
/@ 5-Jan-04 mm@.html is reserved for mmtheorems.html, etc. @/
!strcmp(",MM", left(str2, 3))) {
print2("\n");
assignStmtFileAndLineNum(j); /@ 9-Jan-2018 nm @/
printLongLine(cat("?Warning in statement \"",
g_Statement[i].labelName, "\" at line ",
str((double)(g_Statement[i].lineNum)),
" in file \"", g_Statement[i].fileName,
"\". To workaround a Microsoft operating system limitation, the",
" the following reserved words cannot be used for label names:",
" CON, PRN, AUX, CLOCK$, NUL, COM1, COM2, COM3, COM4, COM5,",
" COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6,",
" LPT7, LPT8, and LPT9. Also, \"mm@.html\" is reserved for",
" Metamath file names. Use another name for this label.", NULL),
"", " ");
g_errorCount++;
}
}
/@ 10/21/02 end @/
*/
if (g_sourceHasBeenRead == 1) { /* 9-Jan-2018 nm */
if (!g_errorCount) {
let(&str1, "No errors were found.");
if (!switchPos("/ VERIFY")) {
let(&str1, cat(str1,
" However, proofs were not checked. Type VERIFY PROOF *",
" if you want to check them.",
NULL));
}
printLongLine(str1, "", " ");
} else {
print2("\n");
if (g_errorCount == 1) {
print2("One error was found.\n");
} else {
print2("%ld errors were found.\n", (long)g_errorCount);
}
}
} /* g_sourceHasBeenRead == 1 */
continue;
}
if (cmdMatches("WRITE SOURCE")) {
let(&g_output_fn, g_fullArg[2]);
/********* Deleted 28-Dec-2013 nm Now opened in writeSource()
g_output_fp = fSafeOpen(g_output_fn, "w", 0/@noVersioningFlag@/);
if (!g_output_fp) continue; /@ Couldn't open it (error msg was provided)@/
********/
/******* Deleted 3-May-2017 nm
/@ Added 24-Oct-03 nm @/
if (switchPos("/ CLEAN") > 0) {
c = 1; /@ Clean out any proof-in-progress (that user has flagged
with a ? in its date comment field) @/
} else {
c = 0; /@ Output all proofs (normal) @/
}
*******/
/********* Deleted 3-May-2017 nm
writeSource((char)c, (char)r); /@ Added arg 24-Oct-03 nm 12-Jun-2011 nm @/
fclose(g_output_fp);
if (c == 0) g_sourceChanged = 0; /@ Don't unset flag if CLEAN option
since some new proofs may not be saved. @/
***********/
/***** 3-Jan-2017 nm This is now done with SET ROOT_DIRECTORY
/@ 31-Dec-2017 nm - Added ROOT_DIRECTORY switch @/
/@ TODO - remove this qualifier; too confusing.
Use SET ROOT_DIRECTORY instead. @/
i = switchPos("/ ROOT_DIRECTORY"); /@ Statement match to skip @/
if (i != 0) {
let(&g_rootDirectory, edit(g_fullArg[i + 1], 2/@discard spaces,tabs@/));
/@ Add trailing "/" to g_rootDirectory if missing @/
if (instr(1, g_rootDirectory, "\\") != 0
|| instr(1, g_input_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));
}
}
/@
} else {
let(&g_rootDirectory, "");
@/
}
*/
/* Added 12-Jun-2011 nm */
if (switchPos("/ REWRAP") > 0) {
r = 2; /* Re-wrap then format (more aggressive than / FORMAT) */
} else if (switchPos("/ FORMAT") > 0) {
r = 1; /* Format output according to set.mm standard */
} else {
r = 0; /* Keep formatting as-is */
}
/* 24-Aug-2020 nm */
i = switchPos("/ EXTRACT");
if (i > 0) {
let(&str1, g_fullArg[i + 1]); /* List of labels */
if (r > 0
|| switchPos("/ SPLIT") > 0
|| switchPos("/ KEEP_INCLUDES") > 0) {
print2(
"?You may not use / SPLIT, / REWRAP, or / KEEP_INCLUDES with / EXTRACT.\n");
continue;
}
} else {
let(&str1, ""); /* Empty string means full db */
}
/* 3-May-2017 nm */
writeSource((char)r, /* Rewrap type */ /* Added arg 12-Jun-2011 nm */
((switchPos("/ SPLIT") > 0) ? 1 : 0), /* 31-Dec-2017 nm */
((switchPos("/ NO_VERSIONING") > 0) ? 1 : 0), /* 31-Dec-2017 nm */
((switchPos("/ KEEP_INCLUDES") > 0) ? 1 : 0), /* 31-Dec-2017 nm */
str1 /* Label list to extract */ /* 24-Aug-2020 nm */
);
/*fclose(g_output_fp);*/
g_sourceChanged = 0;
let(&str1, ""); /* Deallocate */ /* 24-Aug-2020 nm */
continue;
} /* End of WRITE SOURCE */
if (cmdMatches("WRITE THEOREM_LIST")) {
/* 4-Dec-03 - Write out an HTML summary of the theorems to
mmtheorems.html, mmtheorems1.html,... */
/* THEOREMS_PER_PAGE is the default number of proof descriptions to output. */
#define THEOREMS_PER_PAGE 100
/* theoremsPerPage is the actual number of proof descriptions to output. */
/* See if the user overrode the default. */
i = switchPos("/ THEOREMS_PER_PAGE");
if (i != 0) {
theoremsPerPage = (long)val(g_fullArg[i + 1]); /* Use user's value */
} else {
theoremsPerPage = THEOREMS_PER_PAGE; /* Use the default value */
}
showLemmas = (switchPos("/ SHOW_LEMMAS") != 0);
noVersioning = (switchPos("/ NO_VERSIONING") != 0);
/**** 17-Nov-2015 nm Deleted, no longer need this restriction
if (!g_texDefsRead) {
g_htmlFlag = 1;
print2("Reading definitions from $t statement of %s...\n", g_input_fn);
if (2/@error@/ == readTexDefs(0 /@ 1 = check errors only @/,
0 /@ 1 = no GIF file existence check @/ )) {
continue; /@ An error occurred @/
}
} else {
/@ Current limitation - can only read def's from .mm file once @/
if (!g_htmlFlag) {
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;
}
}
*** end of 17-Nov-2015 deletion */
g_htmlFlag = 1;
/* If not specified, for backwards compatibility in scripts
leave g_altHtmlFlag at current value */
if (switchPos("/ HTML") != 0) {
if (switchPos("/ ALT_HTML") != 0) {
print2("?Please specify only one of / HTML and / ALT_HTML.\n");
continue;
}
g_altHtmlFlag = 0;
} else {
if (switchPos("/ ALT_HTML") != 0) g_altHtmlFlag = 1;
}
if (2/*error*/ == readTexDefs(0 /* 1 = check errors only */,
0 /* 1 = no GIF file existence check */ )) {
continue; /* An error occurred */
}
/* Output the theorem list */
writeTheoremList(theoremsPerPage, showLemmas,
noVersioning); /* (located in mmwtex.c) */
continue;
} /* End of "WRITE THEOREM_LIST" */
if (cmdMatches("WRITE BIBLIOGRAPHY")) {
/* 10/10/02 */
/* This command builds the bibliographical cross-references to various
textbooks and updates the user-specified file normally called
mmbiblio.html. */
/* 17-Nov-2015 nm code moved to writeBibliography() in mmwtex.c */
/* (Also called by verifyMarkup() in mmcmds.c for error checking) */
writeBibliography(g_fullArg[2],
"*", /* labelMatch - all labels */
0, /* 1 = no output, just warning msgs if any */
0); /* 1 = ignore missing external files (gifs, bib, etc.) */
continue;
} /* End of "WRITE BIBLIOGRAPHY" */
if (cmdMatches("WRITE RECENT_ADDITIONS")) {
/* 18-Sep-03 -
This utility creates a list of recent proof descriptions and updates
the user-specified file normally called mmrecent.html.
*/
/* RECENT_COUNT is the default number of proof descriptions to output. */
#define RECENT_COUNT 100
/* i is the actual number of proof descriptions to output. */
/* See if the user overrode the default. */
i = switchPos("/ LIMIT");
if (i) {
i = (long)val(g_fullArg[i + 1]); /* Use user's value */
} else {
i = RECENT_COUNT; /* Use the default value */
}
/**** 17-Nov-2015 nm Deleted because readTeXDefs() now handles everything
if (!g_texDefsRead) {
g_htmlFlag = 1;
print2("Reading definitions from $t statement of %s...\n", g_input_fn);
if (2/@error@/ == readTexDefs(0 /@ 1 = check errors only @/,
0 /@ 1 = no GIF file existence check @/ )) {
continue; /@ An error occurred @/
}
} else {
/@ Current limitation - can only read def's from .mm file once @/
if (!g_htmlFlag) {
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;
}
}
**** end of 17-Nov-2015 deletion */
g_htmlFlag = 1;
/* If not specified, for backwards compatibility in scripts
leave g_altHtmlFlag at current value */
if (switchPos("/ HTML") != 0) {
if (switchPos("/ ALT_HTML") != 0) {
print2("?Please specify only one of / HTML and / ALT_HTML.\n");
continue;
}
g_altHtmlFlag = 0;
} else {
if (switchPos("/ ALT_HTML") != 0) g_altHtmlFlag = 1;
}
/* readTexDefs() rereads based on changed in g_htmlFlag, g_altHtmlFlag */
if (2/*error*/ == readTexDefs(0 /* 1 = check errors only */,
0 /* 1 = no GIF file existence check */ )) {
continue; /* An error occurred */
}
tmpFlag = 0; /* Error flag to recover input file */
list1_fp = fSafeOpen(g_fullArg[2], "r", 0/*noVersioningFlag*/);
if (list1_fp == NULL) {
/* Couldn't open it (error msg was provided)*/
continue;
}
fclose(list1_fp);
/* This will rename the input mmrecent.html as mmrecent.html~1 */
list2_fp = fSafeOpen(g_fullArg[2], "w", 0/*noVersioningFlag*/);
if (list2_fp == NULL) {
/* Couldn't open it (error msg was provided)*/
continue;
}
/* 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(g_fullArg[2], "~1", NULL), "r",
0/*noVersioningFlag*/);
if (list1_fp == NULL) bug(1117);
/* Transfer the input file up to the special "<!-- #START# -->" comment */
while (1) {
if (!linput(list1_fp, NULL, &str1)) {
print2(
"?Error: Could not find \"<!-- #START# -->\" line in input file \"%s\".\n",
g_fullArg[2]);
tmpFlag = 1; /* Error flag to recover input file */
break;
}
/* 13-May-04 nm Put in "last updated" stamp */
if (!strcmp(left(str1, 21), "<!-- last updated -->")) {
let(&str1, cat(left(str1, 21), " <I>Last updated on ", date(),
/* ??Future: make "EDT"/"EST" or other automatic */
/* " at ", time_(), " EST.</I>", NULL)); */
/* 10-Nov-04 nm Just make it "ET" for "Eastern Time" */
" at ", time_(), " ET.</I>", NULL));
}
fprintf(list2_fp, "%s\n", str1);
if (!strcmp(str1, "<!-- #START# -->")) break;
}
if (tmpFlag) goto wrrecent_error;
/* Get and parse today's date */
parseDate(date(), &k /*dd*/, &l /*mmm*/, &m /*yyyy*/); /* 4-Nov-2015 */
/************ Deleted 4-Nov-2015
let(&str1, date());
j = instr(1, str1, "-");
k = (long)val(left(str1, j - 1)); /@ Day @/
#define MONTHS "JanFebMarAprMayJunJulAugSepOctNovDec"
l = ((instr(1, MONTHS, mid(str1, j + 1, 3)) - 1) / 3) + 1; /@ 1 = Jan @/
m = str1[j + 6]; /@ Character after 2-digit year @/ /@ nm 10-Apr-06 @/
if (m == ' ' || m == ']') { /@ nm 10-Apr-06 @/
/@ Handle 2-digit year @/
m = (long)val(mid(str1, j + 5, 2)); /@ Year @/
#define START_YEAR 93 /@ Earliest 19xx year in set.mm database @/
if (m < START_YEAR) {
m = m + 2000;
} else {
m = m + 1900;
}
} else { /@ nm 10-Apr-06 @/
/@ Handle 4-digit year @/ /@ nm 10-Apr-06 @/
m = (long)val(mid(str1, j + 5, 4)); /@ Year @/ /@ nm 10-Apr-06 @/
} /@ nm 10-Apr-06 @/
*********** end of 4-Nov-2015 deletion */
#define START_YEAR 93 /* Earliest 19xx year in set.mm database */
n = 0; /* Count of how many output so far */
while (n < i /*RECENT_COUNT*/ && m > START_YEAR + 1900 - 1) {
/* Build date string to match */
/* 4-Nov-2015 nm */
/*buildDate(k, l, m, &str5);*/
buildDate(k, l, m, &str1); /* 2-May-2017 nm */
/***** Deleted 2-May-2017 nm - we no longer match date below proof
let(&str5, cat("$([", str5, "]$)", NULL));
/@ 2-digit year is obsolete, but keep for backwards compatibility @/
let(&str1, cat(left(str5, (long)strlen(str5) - 7),
right(str5, (long)strlen(str5) - 4), NULL));
*******/
/************ Deleted 4-Nov-2015
#define MONTHS "JanFebMarAprMayJunJulAugSepOctNovDec"
/@ Match for 2-digit year OBSOLETE @/
let(&str1, cat("$([", str((double)k), "-", mid(MONTHS, 3 @ l - 2, 3), "-",
right(str((double)m), 3), "]$)", NULL));
/@ Match for 4-digit year @/ /@ nm 10-Apr-06 @/
let(&str5, cat("$([", str((double)k), "-", mid(MONTHS, 3 @ l - 2, 3), "-",
str((double)m), "]$)", NULL));
*********** end of 4-Nov-2015 deletion */
for (stmt = g_statements; stmt >= 1; stmt--) {
if (g_Statement[stmt].type != (char)p_
&& g_Statement[stmt].type != (char)a_) {
continue;
}
/******** Deleted 2-May-2017 nm
/@ Get the comment section after the statement @/
let(&str2, space(g_Statement[stmt + 1].labelSectionLen));
memcpy(str2, g_Statement[stmt + 1].labelSectionPtr,
(size_t)(g_Statement[stmt + 1].labelSectionLen));
p = instr(1, str2, "$)");
let(&str2, left(str2, p + 1)); /@ Get 1st comment (if any) @/
let(&str2, edit(str2, 2)); /@ Discard spaces @/
******** end of 2-May-2017 deletion */
/* 2-May-2017 nm */
/******* Deleted 3-May-2017 nm
/@ In the call below, str3 is a dummy variable for a placeholder
(its value will be undefined because of multiple occurrences) @/
getContrib(stmt/@stmtNum@/, &str3, &str3, &str3, &str3, &str3, &str3,
&str2, /@mostRecentDate@/
0, /@printErrorsFlag@/
1); /@normal mode@/
**********/
/* 3-May-2017 nm */
let(&str2, "");
str2 = getContrib(stmt/*stmtNum*/, MOST_RECENT_DATE);
/* See if the date comment matches */
/*if (instr(1, str2, str1) || instr(1, str2, str5)) {*/ /* 10-Apr-06 */
if (!strcmp(str2, str1)) { /* 2-May-2017 nm */
/* We have a match, so increment the match count */
n++;
let(&str3, "");
str3 = getDescription(stmt);
let(&str4, "");
str4 = pinkHTML(stmt); /* 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 human readability */
printLongLine(cat(
/*
(stmt < g_extHtmlStmt) ?
"<TR>" :
cat("<TR BGCOLOR=", PURPLISH_BIBLIO_COLOR, ">", NULL),
*/
/* 29-Jul-2008 nm Sandbox stuff */
(stmt < g_extHtmlStmt)
? "<TR>"
: (stmt < g_mathboxStmt)
? cat("<TR BGCOLOR=", PURPLISH_BIBLIO_COLOR, ">",
NULL)
: cat("<TR BGCOLOR=", SANDBOX_COLOR, ">", NULL),
"<TD NOWRAP>", /* IE breaks up the date */
/* mid(str1, 4, (long)strlen(str1) - 6), */ /* Date */
/* Use 4-digit year */ /* 10-Apr-06 */
/* mid(str5, 4, (long)strlen(str5) - 6), */ /* Date */ /* 10-Apr-06 */
str2, /* Date */ /* 2-May-2017 nm */
"</TD><TD ALIGN=CENTER><A HREF=\"",
g_Statement[stmt].labelName, ".html\">",
g_Statement[stmt].labelName, "</A>",
str4, "</TD><TD ALIGN=LEFT>", NULL), /* Description */
/* 28-Dec-05 nm Added ALIGN=LEFT for IE */
" ", /* 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;
/* 18-Sep-03 ???Future - make this just return a string??? */
/* printTexComment(str3, 0); */
/* 17-Nov-2015 nm Added 3rd & 4th arguments */
printTexComment(str3, /* Sends result to g_texFilePtr */
0, /* 1 = htmlCenterFlag */
PROCESS_EVERYTHING, /* actionBits */ /* 13-Dec-2018 nm */
0 /* 1 = noFileCheck */ );
g_texFilePtr = NULL;
g_outputToString = 1; /* Restore after printTexComment */
/* Get HTML hypotheses => assertion */
let(&str4, "");
str4 = getTexOrHtmlHypAndAssertion(stmt); /* In mmwtex.c */
printLongLine(cat("</TD></TR><TR",
/*
(s < g_extHtmlStmt) ?
">" :
cat(" BGCOLOR=", PURPLISH_BIBLIO_COLOR, ">", NULL),
*/
/* 29-Jul-2008 nm Sandbox stuff */
(stmt < g_extHtmlStmt)
? ">"
: (stmt < g_mathboxStmt)
? cat(" BGCOLOR=", PURPLISH_BIBLIO_COLOR, ">",
NULL)
: cat(" BGCOLOR=", SANDBOX_COLOR, ">", NULL),
/*** old
"<TD BGCOLOR=white>&nbsp;</TD><TD COLSPAN=2 ALIGN=CENTER>",
str4, "</TD></TR>", NULL),
****/
/* 27-Oct-03 nm */
"<TD COLSPAN=3 ALIGN=CENTER>",
str4, "</TD></TR>", 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 */
/* 27-Oct-03 nm Put separator row if not last theorem */
g_outputToString = 1;
printLongLine(cat("<TR BGCOLOR=white><TD COLSPAN=3>",
"<FONT SIZE=-3>&nbsp;</FONT></TD></TR>", NULL),
" ", /* Start continuation line with space */
"\""); /* Don't break inside quotes e.g. "Arial Narrow" */
/* 29-Jul-04 nm 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("<!-- For script: previous = %s -->\n",
g_Statement[j].labelName);
/* Current statement */
print2("<!-- For script: current = %s -->\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("<!-- For script: next = %s -->\n",
g_Statement[j].labelName);
/* End of 29-Jul-04 section */
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 "<!-- #END# -->" comment */
while (1) {
if (!linput(list1_fp, NULL, &str1)) {
print2(
"?Error: Could not find \"<!-- #END# -->\" line in input file \"%s\".\n",
g_fullArg[2]);
tmpFlag = 1; /* Error flag to recover input file */
break;
}
if (!strcmp(str1, "<!-- #END# -->")) {
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 */
/* 30-Jan-06 nm Added single-character-match wildcard argument */
if (!matchesList(g_Statement[i].labelName, g_fullArg[2], '*', '?')) {
continue;
}
/* 2-Oct-2015 nm */
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++;
}
/* 2-Oct-2015 nm Deleted
let(&str1,cat(str((double)i)," ",
g_Statement[i].labelName," $",chr(g_Statement[i].type)," ",NULL));
#define COL 19 /@ Characters per column @/
if (j + (long)strlen(str1) > MAX_LEN
|| (linearFlag && j != 0)) { /@ j != 0 to suppress 1st CR @/
print2("\n");
j = 0;
k = 0;
}
if (strlen(str1) > COL || linearFlag) {
j = j + (long)strlen(str1);
k = k + (long)strlen(str1) - COL;
print2(str1);
} else {
if (k == 0) {
j = j + COL;
print2("%s%s",str1,space(COL - (long)strlen(str1)));
} else {
k = k - (COL - (long)strlen(str1));
if (k > 0) {
print2(str1);
j = j + (long)strlen(str1);
} else {
print2("%s%s",str1,space(COL - (long)strlen(str1)));
j = j + COL;
k = 0;
}
}
}
*/
} /* next i */
/* print2("\n"); */
if (str2[0]) {
print2("%s\n", str2);
let(&str2, "");
}
let(&str1, "");
continue;
}
if (cmdMatches("SHOW DISCOURAGED")) { /* was SHOW RESTRICTED */
showDiscouraged(); /* In mmcmds.c */
continue;
}
if (cmdMatches("SHOW SOURCE")) {
/* 14-Sep-2012 nm */
/* 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 */
/*********** 14-Sep-2012 replaced by getStatementNum()
for (i = 1; i <= g_statements; i++) {
if (!strcmp(g_fullArg[2],g_Statement[i].labelName)) break;
}
if (i > g_statements) {
printLongLine(cat("?There is no statement with label \"",
g_fullArg[2], "\". ",
"Use SHOW LABELS for a list of valid labels.", NULL), "", " ");
g_showStatement = 0;
continue;
}
g_showStatement = i;
************** end 14-Sep-2012 *******/
let(&str1, "");
str1 = outputStatement(g_showStatement, /*0, 3-May-2017 */ /* 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. */
/* if (g_rawArgs != 5) { */ /* obsolete */
/* 16-Aug-2016 nm */
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;
}
/* 16-Aug-2016 nm */
printTime = 0;
if (switchPos("/ TIME") != 0) {
printTime = 1;
}
/*** 17-Nov-2014 nm This restriction has been removed.
if (g_texDefsRead) {
/@ Current limitation - can only read def's from .mm file once @/
if (!g_htmlFlag) {
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");
goto htmlDone;
} else {
if ((switchPos("/ ALT_HTML") || switchPos("/ BRIEF_ALT_HTML"))
== (g_altHtmlFlag == 0)) {
print2(
"?You cannot use both HTML and ALT_HTML in the same session.\n");
print2(
"You must EXIT and restart Metamath to switch to the other.\n");
goto htmlDone;
}
}
}
*** End 17-Nov-2014 deletion */
g_htmlFlag = 1; /* 17-Nov-2015 nm */
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 (instr(1, g_fullArg[2], "*") || g_briefHtmlFlag) { */ /* obsolete */
if (((char *)(g_fullArg[2]))[0] == '*' || g_briefHtmlFlag) {
/* 6-Jul-2008 nm */
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 */
/* 30-Jan-06 nm Added single-character-match wildcard argument */
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", /* 17-Jul-2019 nm */
noVersioning /*noVersioningFlag*/);
/****** old code before 17-Jul-2019 *******
if (switchPos("/ NO_VERSIONING") == 0) {
g_texFilePtr = fSafeOpen(g_texFileName, "w", 0/@noVersioningFlag@/);
} else {
/@ 6-Jul-2008 nm Added / NO_VERSIONING @/
/@ Don't create the backup versions ~1, ~2,... @/
g_texFilePtr = fopen(g_texFileName, "w");
if (!g_texFilePtr) print2("?Could not open the file \"%s\".\n",
g_texFileName);
}
********* end of old code before 17-Jul-2019 *******/
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) {
/* 9/6/03 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("<CENTER><FONT COLOR=", GREEN_TITLE_COLOR,
"><B>",
"Symbol to ASCII Correspondence for Text-Only Browsers",
" (in order of appearance in $c and $v statements",
" in the database)",
"</B></FONT></CENTER><P>", NULL), "", "\"");
}
/* 13-Oct-2006 nm todo - </CENTER> still appears - where is it? */
if (!g_briefHtmlFlag) print2("<CENTER>\n");
print2("<TABLE BORDER CELLSPACING=0 BGCOLOR=%s\n",
MINT_BACKGROUND_COLOR);
/* For bobby.cast.org approval */
switch (s) {
case -2:
print2("SUMMARY=\"Symbol to ASCII correspondences\">\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("<TR ALIGN=LEFT><TD><B>\n");
break;
case -1:
print2(
"<CAPTION><B>List of Theorems</B></CAPTION><TR ALIGN=LEFT><TD><B>\n");
break;
case 0:
printLongLine(cat(
/*"<CAPTION><B>List of Syntax (not <FONT COLOR=\"#00CC00\">|-&nbsp;</FONT>), ",*/
/* 2/9/02 (in case |- suppressed) */
"<CAPTION><B>List of Syntax, ",
"Axioms (<FONT COLOR=", GREEN_TITLE_COLOR, ">ax-</FONT>) and",
" Definitions (<FONT COLOR=", GREEN_TITLE_COLOR,
">df-</FONT>)", "</B></CAPTION><TR ALIGN=LEFT><TD><B>",
NULL), "", "\"");
break;
}
switch (s) {
case -2:
print2("Symbol</B></TD><TD><B>ASCII\n");
break;
case -1:
print2(
"Ref</B></TD><TD><B>Description\n");
break;
case 0:
printLongLine(cat(
"Ref</B></TD><TD><B>",
"Expression (see link for any distinct variable requirements)",
NULL), "", "\"");
break;
}
print2("</B></TD></TR>\n");
m = 0; /* Statement number map */
let(&str3, ""); /* For storing ASCII token list in s=-2 mode */
let(&bgcolor, MINT_BACKGROUND_COLOR); /* 8-Aug-2008 nm Initialize */
for (i = 1; i <= g_statements; i++) {
/* 8-Aug-2008 nm Commented out: */
/*
if (i == g_extHtmlStmt && s != -2) {
/ * Print a row that identifies the start of the extended
database (e.g. Hilbert Space Explorer) * /
printLongLine(cat(
"<TR><TD COLSPAN=2 ALIGN=CENTER><A NAME=\"startext\"></A>",
"The list of syntax, axioms (ax-) and definitions (df-) for",
" the <B><FONT COLOR=", GREEN_TITLE_COLOR, ">",
g_extHtmlTitle,
"</FONT></B> starts here</TD></TR>", NULL), "", "\"");
}
*/
/* 8-Aug-2008 nm */
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("<TR BGCOLOR=", bgcolor,
"><TD COLSPAN=2 ALIGN=CENTER><A NAME=\"startext\"></A>",
"The list of syntax, axioms (ax-) and definitions (df-) for",
" the <B><FONT COLOR=", GREEN_TITLE_COLOR, ">",
(i == g_extHtmlStmt) ?
g_extHtmlTitle :
/*"User Sandboxes",*/
/* 24-Jul-2009 nm Changed name of sandbox to "mathbox" */
"User Mathboxes",
"</FONT></B> starts here</TD></TR>", 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*/);
/* 2/9/02 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), "&amp;",
right(str1, k + 2), NULL));
k = k + 4;
}
if (str1[k] == '<') {
let(&str1, cat(left(str1, k), "&lt;",
right(str1, k + 2), NULL));
k = k + 3;
}
if (str1[k] == '>') {
let(&str1, cat(left(str1, k), "&gt;",
right(str1, k + 2), NULL));
k = k + 3;
}
} /* next k */
printLongLine(cat("<TR ALIGN=LEFT><TD>",
(g_altHtmlFlag ? cat("<SPAN ", g_htmlFont, ">", NULL) : ""),
/* 14-Jan-2016 nm */
str2,
(g_altHtmlFlag ? "</SPAN>" : ""), /* 14-Jan-2016 nm */
"&nbsp;", /* 10-Jan-2016 nm This will prevent a
-4px shifted image from overlapping the
lower border of the table cell */
"</TD><TD><TT>",
str1,
"</TT></TD></TR>", 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:
/* Count the number of essential hypotheses k */
/* Not needed anymore??? since getTexOrHtmlHypAndAssertion() */
/*
k = 0;
j = nmbrLen(g_Statement[i].reqHypList);
for (n = 0; n < j; n++) {
if (g_Statement[g_Statement[i].reqHypList[n]].type
== (char)e_) {
k++;
}
}
*/
let(&str1, "");
if (s == 0 || g_briefHtmlFlag) {
let(&str1, "");
/* 18-Sep-03 Get HTML hypotheses => assertion */
str1 = getTexOrHtmlHypAndAssertion(i);
/* In mmwtex.c */
let(&str1, cat(str1, "</TD></TR>", NULL));
}
/* 13-Oct-2006 nm Made some changes to BRIEF_HTML/_ALT_HTML
to use its mmtheoremsall.html output for the Palm PDA */
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("<TR ALIGN=LEFT><TD ALIGN=LEFT>",
/*"<FONT COLOR=\"#FA8072\">",*/
"<FONT COLOR=ORANGE>",
str((double)(g_Statement[i].pinkNumber)), "</FONT> ",
"<FONT COLOR=GREEN><A HREF=\"",
"mmtheorems", (k == 1) ? "" : str((double)k), ".html#",
g_Statement[i].labelName,
"\">", g_Statement[i].labelName,
"</A></FONT>", NULL));
let(&str1, cat(str2, " ", str1, NULL));
} else {
/* Get little pink (or rainbow-colored) number */
let(&str4, "");
str4 = pinkHTML(i);
let(&str2, cat("<TR BGCOLOR=", bgcolor, /* 8-Aug-2008 nm */
" ALIGN=LEFT><TD><A HREF=\"",
g_Statement[i].labelName,
".html\">", g_Statement[i].labelName,
"</A>", str4, NULL));
let(&str1, cat(str2, "</TD><TD>", str1, NULL));
}
/* End of 13-Oct-2006 changed section */
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, "</TD></TR>", 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) */
/* print2("</TABLE></CENTER>\n"); */ /* 8/8/03 Removed - already
done somewhere else, causing validator.w3.org to fail */
g_outputToString = 0; /* closing will write out the string */
let(&bgcolor, ""); /* Deallocate (to improve fragmentation) */
} else { /* s > 0 */
/* 16-Aug-2016 nm */
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*/);
/* 16-Aug-2016 nm */
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")...) */
/******* Section for / MNEMONICS added 12-May-2009 by Stefan Allan *****/
/* Write mnemosyne.txt */
if (cmdMatches("SHOW STATEMENT") && switchPos("/ MNEMONICS")) {
/*** 17-Nov-2015 nm Deleted - removed g_htmlFlag, g_altHtmlFlag
change prohibition
if (!g_texDefsRead) {
g_htmlFlag = 1; /@ Use HTML, not TeX section @/
g_altHtmlFlag = 1; /@ Use Unicode, not GIF @/
print2("Reading definitions from $t statement of %s...\n", g_input_fn);
if (2/@error@/ == readTexDefs(0 /@ 1 = check errors only @/,
0 /@ 1 = no GIF file existence check @/ )) {
print2(
"?There was an error in the $t comment's LaTeX/HTML definitions.\n");
print2("?HTML generation was aborted due to the error above.\n");
continue; /@ An error occurred @/
}
} else {
/@ Current limitation - can only read def's from .mm file once @/
if (!g_htmlFlag) {
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;
} else {
if (!g_altHtmlFlag) {
print2(
"?You cannot use both HTML and ALT_HTML in the same session.\n");
print2(
"You must EXIT and restart Metamath to switch to the other.\n");
continue;
}
}
}
*** end of 17-Nov-2015 deletion */
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 */,
0 /* 1 = no 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 (strcmp("|-", g_MathToken[
(g_Statement[g_showStatement].mathString)[0]].tokenName)) {
subType = SYNTAX;
}
*/
if (!g_Statement[s].labelName[0]) continue; /* No label */
/* 30-Jan-06 nm Added single-character-match wildcard argument */
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("<CENTER><B><FONT SIZE=\"+1\">",
" <FONT COLOR=", GREEN_TITLE_COLOR,
" SIZE = \"+3\">", g_Statement[g_showStatement].labelName,
"</FONT></FONT></B>", "</CENTER>", NULL));
fprintf(g_texFilePtr, "%s", str1);
let(&str1, cat("<TABLE>",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("<TR ALIGN=LEFT><TD><FONT SIZE=\"+2\">",
g_Statement[k].labelName, "</FONT></TD><TD><FONT SIZE=\"+2\">",
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</FONT></TD>", str1);
}
let(&str1, "</TABLE>");
fprintf(g_texFilePtr, "%s", str1);
let(&str1, "<BR><FONT SIZE=\"+2\">What is the conclusion?</FONT>");
fprintf(g_texFilePtr, "%s\n", str1);
let(&str1, "<FONT SIZE=\"+3\">");
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, "</FONT>");
fprintf(g_texFilePtr, "%s\n",str1);
} /* for(s=1;s<g_statements;++s) */
fclose(g_texFilePtr);
g_texFileOpenFlag = 0;
let(&g_texFileName,"");
let(&str1,"");
let(&str2,"");
continue;
} /* if (cmdMatches("SHOW STATEMENT") && switchPos("/ MNEMONICS")) */
/** End of section for / MNEMONICS added 12-May-2009 by Stefan Allan *****/
/* If we get here, the user did not specify one of the qualifiers /HTML,
/BRIEF_HTML, /ALT_HTML, or /BRIEF_ALT_HTML */
if (cmdMatches("SHOW STATEMENT") && !switchPos("/ HTML")) {
texFlag = 0;
/* 14-Sep-2010 nm Added OLD_TEX */
if (switchPos("/ TEX") || switchPos("/ OLD_TEX")
|| switchPos("/ HTML"))
texFlag = 1;
briefFlag = 1;
g_oldTexFlag = 0;
if (switchPos("/ TEX")) briefFlag = 0;
/* 14-Sep-2010 nm Added OLD_TEX */
if (switchPos("/ OLD_TEX")) briefFlag = 0;
if (switchPos("/ OLD_TEX")) g_oldTexFlag = 1;
if (switchPos("/ FULL")) briefFlag = 0;
commentOnlyFlag = 0;
if (switchPos("/ COMMENT")) {
commentOnlyFlag = 1;
briefFlag = 1;
}
if (switchPos("/ FULL")) {
briefFlag = 0;
commentOnlyFlag = 0;
}
if (texFlag) {
if (!g_texFileOpenFlag) {
print2(
"?You have not opened a %s file. Use the OPEN TEX command first.\n",
g_htmlFlag ? "HTML" : "LaTeX");
continue;
}
}
if (texFlag && (commentOnlyFlag || briefFlag)) {
print2("?TEX qualifier should be used alone\n");
continue;
}
q = 0;
for (s = 1; s <= g_statements; s++) {
if (!g_Statement[s].labelName[0]) continue; /* No label */
/* We are not in MM-PA mode, or the statement isn't "=" */
/* 30-Jan-06 nm Added single-character-match wildcard argument */
if (!matchesList(g_Statement[s].labelName, g_fullArg[2], '*', '?'))
continue;
if (briefFlag || commentOnlyFlag || texFlag) {
/* For brief or comment qualifier, if label has wildcards,
show only $p and $a's */
/* 30-Jan-06 nm Added single-character-match wildcard argument */
if (g_Statement[s].type != (char)p_
&& g_Statement[s].type != (char)a_ && (instr(1, g_fullArg[2], "*")
|| instr(1, g_fullArg[2], "?")))
continue;
}
if (q && !texFlag) {
/* 17-Jul-2019 nm Changed "79" to "g_screenWidth" */
if (!print2("%s\n", string(g_screenWidth, '-'))) /* Put line between
statements */
break; /* Break for speedup if user quit */
}
if (texFlag) print2("Outputting statement \"%s\"...\n",
g_Statement[s].labelName);
q = 1; /* Flag that at least one matching statement was found */
g_showStatement = s;
typeStatement(g_showStatement,
briefFlag,
commentOnlyFlag,
texFlag,
g_htmlFlag);
} /* 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;
}
if (texFlag && !g_htmlFlag) {
print2("The LaTeX source was written to \"%s\".\n", g_texFileName);
/* 14-Sep-2010 nm Added OLD_TEX */
g_oldTexFlag = 0;
}
continue;
} /* (cmdMatches("SHOW STATEMENT") && !switchPos("/ HTML")) */
if (cmdMatches("SHOW SETTINGS")) {
print2("Metamath settings on %s at %s:\n",date(),time_());
if (g_commandEcho) {
print2("(SET ECHO...) Command ECHO is ON.\n");
} else {
print2("(SET ECHO...) Command ECHO is OFF.\n");
}
if (defaultScrollMode == 1) {
print2("(SET SCROLL...) SCROLLing mode is PROMPTED.\n");
} else {
print2("(SET SCROLL...) SCROLLing mode is CONTINUOUS.\n");
}
print2("(SET WIDTH...) Screen display WIDTH is %ld.\n", g_screenWidth);
print2("(SET HEIGHT...) Screen display HEIGHT is %ld.\n",
g_screenHeight + 1);
if (g_sourceHasBeenRead == 1) {
print2("(READ...) %ld statements have been read from \"%s\".\n",
g_statements, g_input_fn);
} else {
print2("(READ...) No source file has been read in yet.\n");
}
print2("(SET ROOT_DIRECTORY...) Root directory is \"%s\".\n",
g_rootDirectory);
print2(
"(SET DISCOURAGEMENT...) Blocking based on \"discouraged\" tags is %s.\n",
(g_globalDiscouragement ? "ON" : "OFF"));
print2(
"(SET CONTRIBUTOR...) The current contributor is \"%s\".\n",
g_contributorName);
if (g_PFASmode) {
print2("(PROVE...) The statement you are proving is \"%s\".\n",
g_Statement[g_proveStatement].labelName);
}
print2("(SET UNDO...) The maximum number of UNDOs is %ld.\n",
processUndoStack(NULL, PUS_GET_SIZE, "", 0));
print2(
"(SET UNIFICATION_TIMEOUT...) The unification timeout parameter is %ld.\n",
g_userMaxUnifTrials);
print2(
"(SET SEARCH_LIMIT...) The SEARCH_LIMIT for the IMPROVE command is %ld.\n",
g_userMaxProveFloat);
if (g_minSubstLen) {
print2(
"(SET EMPTY_SUBSTITUTION...) EMPTY_SUBSTITUTION is not allowed (OFF).\n");
} else {
print2(
"(SET EMPTY_SUBSTITUTION...) EMPTY_SUBSTITUTION is allowed (ON).\n");
}
if (g_hentyFilter) { /* 18-Nov-05 nm Added to the SHOW listing */
print2(
"(SET JEREMY_HENTY_FILTER...) The Henty filter is turned ON.\n");
} else {
print2(
"(SET JEREMY_HENTY_FILTER...) The Henty filter is turned OFF.\n");
}
if (g_showStatement) {
print2("(SHOW...) The default statement for SHOW commands is \"%s\".\n",
g_Statement[g_showStatement].labelName);
}
if (g_logFileOpenFlag) {
print2("(OPEN LOG...) The log file \"%s\" is open.\n", g_logFileName);
} else {
print2("(OPEN LOG...) No log file is currently open.\n");
}
if (g_texFileOpenFlag) {
print2("The %s file \"%s\" is open.\n", g_htmlFlag ? "HTML" : "LaTeX",
g_texFileName);
}
/* 17-Nov-2015 nm */
print2(
"(SHOW STATEMENT.../[TEX,HTML,ALT_HTML]) Current output mode is %s.\n",
g_htmlFlag
? (g_altHtmlFlag ? "ALT_HTML" : "HTML")
: "TEX (LaTeX)");
/* 21-Jun-2014 */
print2("The program is compiled for a %ld-bit CPU.\n",
(long)(8 * sizeof(long)));
print2(
"sizeof(short)=%ld, sizeof(int)=%ld, sizeof(long)=%ld, sizeof(size_t)=%ld.\n",
(long)(sizeof(short)),
(long)(sizeof(int)), (long)(sizeof(long)), (long)(sizeof(size_t)));
continue;
}
if (cmdMatches("SHOW MEMORY")) {
/*print2("%ld bytes of data memory have been used.\n",db+db3);*/
j = 32000000; /* The largest we'ed ever look for */
#ifdef THINK_C
i = FreeMem();
#else
i = getFreeSpace(j);
#endif
if (i > j-3) {
print2("At least %ld bytes of memory are free.\n",j);
} else {
print2("%ld bytes of memory are free.\n",i);
}
continue;
}
/* 21-Jun-2014 */
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")) {
/* Pre-21-May-2008
for (i = 1; i <= g_statements; i++) {
if (!strcmp(g_fullArg[2],g_Statement[i].labelName)) break;
}
if (i > g_statements) {
printLongLine(cat("?There is no statement with label \"",
g_fullArg[2], "\". ",
"Use SHOW LABELS for a list of valid labels.", NULL), "", " ");
g_showStatement = 0;
continue;
}
*/
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]);
/* 19-May-2013 nm */
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");
}
}
}
/* 21-May-2008 nm Added wildcard handling */
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;
/*** start of 19-May-2013 deletion
j = switchPos("/ TREE");
if (j) {
if (axiomFlag) {
print2(
"(Note: The AXIOMS switch is ignored in TREE mode.)\n");
}
if (switchPos("/ COUNT_STEPS")) {
print2(
"(Note: The COUNT_STEPS switch is ignored in TREE mode.)\n");
}
traceProofTree(g_showStatement, essentialFlag, endIndent);
} else {
if (endIndent != 0) {
print2(
"(Note: The DEPTH is ignored if the TREE switch is not used.)\n");
}
j = switchPos("/ COUNT_STEPS");
if (j) {
countSteps(g_showStatement, essentialFlag);
} else {
traceProof(g_showStatement, essentialFlag, axiomFlag);
}
}
*** end of 19-May-2013 deletion */
/* 19-May-2013 nm - move /TREE and /COUNT_STEPS to outside loop,
assigning new variables, for cleaner code. */
if (treeFlag) {
traceProofTree(g_showStatement, essentialFlag, endIndent);
} else {
if (countStepsFlag) {
countSteps(g_showStatement, essentialFlag);
} else {
traceProof(g_showStatement,
essentialFlag,
axiomFlag,
matchList, /* 19-May-2013 nm */
traceToList, /* 18-Jul-2015 nm */
0 /* testOnlyFlag */ /* 20-May-2013 nm */);
}
}
/* 21-May-2008 nm Added wildcard handling */
} /* 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")) {
/* 7-Jan-2008 nm Added / ALL qualifier */
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++) { /* 7-Jan-2008 */
/* 7-Jan-2008 nm Added wildcard handling */
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 */);
/************* 18-Jul-2015 nm Start of deleted code ************/
/*
/@ Count the number of statements = # of spaces @/
k = (long)strlen(str1) - (long)strlen(edit(str1, 2));
if (!k) {
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) {
let(&str1, cat(" ", str1, NULL));
} else {
let(&str1, " (None)");
}
/@ Print the output @/
printLongLine(str1, " ", " ");
*/
/********* 18-Jul-2015 nm End of deleted code ****************/
/************* 18-Jul-2015 nm Start of new code ************/
/* 18-Jul-2015 nm */
/* 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) */
/********* 18-Jul-2015 nm End of new code ****************/
} /* 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;
}
/* 3-May-2016 nm */
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 */
}
/* 16-Aug-2016 nm */
printTime = 0;
if (switchPos("/ TIME") != 0) { /* / TIME legal in SAVE mode only */
printTime = 1;
}
/* 27-Dec-2013 nm */
i = switchPos("/ OLD_COMPRESSION");
if (i) {
if (!switchPos("/ COMPRESSED")) {
print2("?/ OLD_COMPRESSION must be accompanied by / COMPRESSED.\n");
continue;
}
}
/* 2-Mar-2016 nm */
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;
}
/* 2-Mar-2016 nm */
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;
/* startIndent = 0; */ /* Not used */
endIndent = 0;
/*essentialFlag = 0;*/
essentialFlag = 1; /* 10/9/99 - friendlier default */
renumberFlag = 0;
unknownFlag = 0;
notUnifiedFlag = 0;
reverseFlag = 0;
detailStep = 0;
noIndentFlag = 0;
splitColumn = DEFAULT_COLUMN;
skipRepeatedSteps = 0; /* 28-Jun-2013 nm */
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]);
/* 10/9/99 - 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"); /* 28-Jun-2013 nm */
if (i) skipRepeatedSteps = 1; /* 28-Jun-2013 nm */
/* 8-Dec-2018 nm */
/* 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")
/* 14-Sep-2010 nm Added OLDE_TEX */
|| switchPos("/ OLD_TEX");
if (i) texFlag = 1;
/* 14-Sep-2010 nm Added OLD_TEX */
g_oldTexFlag = 0;
if (switchPos("/ OLD_TEX")) g_oldTexFlag = 1;
if (cmdMatches("MIDI")) { /* 8/28/00 */
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;
}
/**** this is now done after outputting
print2("The %s source was written to \"%s\".\n",
g_htmlFlag ? "HTML" : "LaTeX", g_texFileName);
*/
}
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 */
/* 2-Jan-2017 nm */
/* 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 */
/* 30-Jan-06 nm Added single-character-match wildcard argument */
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;
}
/* 21-Jun-2014 */
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.)*/
/* 16-Aug-2016 nm */
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) { /* 21-Aug-04 nm */
/* Prevent bugtrap in nmbrSquishProof -> */
/* nmbrGetSubProofLen if proof corrupted */
print2(
"?The proof has a severe error and cannot be displayed or saved.\n");
continue;
}
/* verifyProof(g_showStatement); */ /* Not necessary */
if (fastFlag) { /* 2-Mar-2016 nm */
/* 2-Mar-2016 nm */
/* 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) { /* 2-Mar-2016 nm */
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 /* 27-Dec-2013 nm */
));
} else {
let(&str1, nmbrCvtRToVString(nmbrSaveProof,
/* 25-Jan-2016 nm */
explicitTargets, /*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");
/* 19-Apr-2015 so */
/* 24-Apr-2015 nm Reverted */
/*print2("\n");*/ /* Add a blank line to make clipping easier */
}
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), " ");
}
/* 24-Apr-2015 nm */
l = (long)(strlen(str1)); /* Save length for printout below */
/* 3-May-2017 nm Rewrote the if block below */
/* 12-Jun-2011 nm Removed pipFlag condition so that a date
stamp will always be created if it doesn't exist */
if /*(pipFlag)*/ (1 /* Add the date proof was created */
/* 19-Apr-2015 so */
/* SOREAR Only generate date if the proof looks complete.
This is not intended as a grading mechanism, just trying
to avoid premature output */
&& !nmbrElementIn(1, nmbrSaveProof, -(long)'?')) {
/* 3-May-2017 nm */
/* 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 */
/* 14-May-2017 nm */
/* 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 ?who?, ", date(), ".) ", NULL));*/
"(Contributed by ", g_contributorName,
", ", str3, ".) ", NULL)); /* 14-May-2017 nm */
/* 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)); /* 15-May-2017 nm */
}
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 */
#ifdef DATE_BELOW_PROOF /* 12-May-2017 nm */
/* Add a date below the proof. It actually goes in the
label section of the next statement; the proof section
is not changed. */
/* (This will become obsolete eventually) */
let(&str3, space(g_Statement[outStatement + 1].labelSectionLen));
/* str3 will have the next statement's label section w/ comment */
memcpy(str3, g_Statement[outStatement + 1].labelSectionPtr,
(size_t)(g_Statement[outStatement + 1].labelSectionLen));
let(&str5, ""); /* We need to guarantee this
for the screen printout later */
if (instr(1, str3, "$( [") == 0) {
/* There is no date below proof (if there is, don't do
anything; if it is wrong, 'verify markup' will check it) */
/* Save str5 for screen printout later! */
let(&str5, cat(space(indentation),
"$( [", date(), "] $)", NULL)); /* str4 will be used
for the screen printout later */
if (saveFlag) { /* save proof, not show proof */
if (g_Statement[outStatement + 1].labelSectionChanged == 1) {
/* Deallocate old comment if not original source */
let(&str4, ""); /* Deallocate any previous str4 content */
str4 = g_Statement[outStatement + 1].labelSectionPtr;
let(&str4, ""); /* Deallocate the old content */
}
/* str3 starts after the "$." ending the proof, and should
start with "\n" */
let(&str3, edit(str3, 8/* Discard leading spaces and tabs */));
if (str3[0] != '\n') let(&str3, cat("\n", str3, NULL));
/* Add the date after the proof */
let(&str3, cat("\n", str5, str3, NULL));
/* Set flag that this is not the original source */
g_Statement[outStatement + 1].labelSectionChanged = 1;
g_Statement[outStatement + 1].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 + 1].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 + 1, GC_RESET_STMT);
} /* if saveFlag */
} /* if (instr(1, str3, "$( [") == 0) */
#endif /* end #ifdef DATE_BELOW_PROOF */ /* 12-May-2017 nm */
} /* if str2[0] == 0 */
/* At this point, str4 contains the "$( [date] $)" comment
if it would have been added to the saved proof, for use
by "show proof" */
/********* deleted 3-May-2017 - date below proof is obsolete
/@ 12-Jun-2011 nm Removed pipFlag condition so that a date
stamp will always be created if it doesn't exist @/
if ( /@ pipFlag && @/ !instr(1, str2, "$([")
/@ 7-Sep-04 Allow both "$([<date>])$" and "$( [<date>] )$" @/
/@ 19-Apr-2015 so @/
/@ SOREAR Only generate date if the proof looks complete.
This is not intended as a grading mechanism, just trying
to avoid premature output @/
&& !nmbrElementIn(1, nmbrSaveProof, -(long)'?')
&& !instr(1, str2, "$( [")) {
/@ 6/13/98 end @/
/@ No date stamp existed before. Create one for today's
date. Note that the characters after "$." at the end of
the proof normally go in the labelSection of the next
statement, but a special mode in outputStatement() (in
mmpars.c) will output the date stamp characters for a saved
proof. @/
/@ print2("%s$([%s]$)\n", space(indentation), date()); @/
/@ 4/23/04 nm Initialize with a "?" date followed by today's
date. The "?" date can be edited by the user when the
proof is becomes "official." @/
/@print2("%s$([?]$) $([%s]$)\n", space(indentation), date());@/
/@ 7-Sep-04 Put space around "[<date>]" @/
/@print2("%s$( [?] $) $( [%s] $)\n", space(indentation), date());@/
/@ 30-Nov-2013 remove the unknown date placeholder @/
print2("%s$( [%s] $)\n", space(indentation), date());
} else {
if (saveFlag && (instr(1, str2, "$([")
/@ 7-Sep-04 Allow both "$([<date>])$" and "$( [<date>] )$" @/
|| instr(1, str2, "$( ["))) {
/@ An old date stamp existed, and we're saving the proof to
the output file. Make sure the indentation of the old
date stamp (which exists in the labelSection of the
next statement) matches the indentation of the saved
proof. To do this, we "delete" the indentation spaces
on the old date in the labelSection of the next statement,
and we put the actual required indentation spaces at
the end of the saved proof. This is done because the
labelSectionPtr of the next statement does not point to
an isolated string that can be allocated/deallocated but
rather to a place in the input source buffer. @/
/@ Correct the indentation on old date @/
while ((g_Statement[outStatement + 1].labelSectionPtr)[0] !=
'$') {
/@ "Delete" spaces before old date (by moving source
buffer pointer forward), and also "delete"
the \n that comes before those spaces @/
/@ If the proof is saved a 2nd time, this loop will
not be entered because the pointer will already be
at the "$". @/
(g_Statement[outStatement + 1].labelSectionPtr)++;
(g_Statement[outStatement + 1].labelSectionLen)--;
}
if (!g_outputToString) bug(1115);
/@ The final \n will not appear in final output (done in
outputStatement() in mmpars.c) because the proofSectionLen
below is adjusted to omit it. This will allow the
space(indentation) to appear before the old date without an
intervening \n. @/
print2("%s\n", space(indentation));
}
}
******** end of deletion 3-May-2017 ******/
} /* if / *(pipFlag)* / (1) */
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 */
}
/******** deleted 3-May-2017 nm (before proofSectionChanged added)
/@ ASCII 1 is a flag that string was allocated and not part of
original source file text buffer @/
let(&g_printString, cat(chr(1), "\n", g_printString, NULL));
if (g_Statement[outStatement].proofSectionPtr[-1] == 1) {
/@ Deallocate old proof if not original source @/
let(&str1, ""); /@ Deallocate any previous str1 content @/
str1 = g_Statement[outStatement].proofSectionPtr - 1;
let(&str1, ""); /@ Deallocate the proof section @/
}
g_Statement[outStatement].proofSectionPtr = g_printString + 1;
/@ Subtr 1 char for ASCII 1 at beg, 1 char for "\n" at the end
(which is the first char of next statement's labelSection) @/
g_Statement[outStatement].proofSectionLen
= (long)strlen(g_printString) - 2;
/@ Reset g_printString without deallocating @/
g_printString = "";
g_outputToString = 0;
**********/
/* 3-May-2017 nm */
/* 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), "", " ");
}
/* 16-Aug-2016 nm */
if (printTime == 1) {
getRunTime(&timeIncr);
print2("SAVE PROOF run time = %6.2f sec for \"%s\"\n", timeIncr,
g_Statement[outStatement].labelName);
}
} else {
#ifdef DATE_BELOW_PROOF /* 12-May-2017 nm */
/* Print the date on the screen if it would be added to the file */
if (str5[0] != 0) print2("%s\n", str5);
#endif /*#ifdef DATE_BELOW_PROOF*/ /* 12-May-2017 nm */
/* 19-Apr-2015 so */
/* 24-Apr-2015 nm Reverted */
/*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)); */
/* 24-Apr-2015 nm */
"\" (", 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) {
/* 14-Sep-2010 nm */
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);
/*???? The code below is obsolete - now down in show statement*/
/*
print2("<CENTER><TABLE BORDER CELLSPACING=0 BGCOLOR=%s>\n",
MINT_BACKGROUND_COLOR);
print2("<CAPTION><B>Proof of Theorem <FONT\n");
printLongLine(cat(" COLOR=", GREEN_TITLE_COLOR, ">",
asciiToTt(g_Statement[outStatement].labelName),
"</FONT></B></CAPTION>", NULL), "", "\"");
print2(
"<TR><TD><B>Step</B></TD><TD><B>Hyp</B></TD><TD><B>Ref</B>\n");
print2("</TD><TD><B>Expression</B></TD></TR>\n");
*/
}
g_outputToString = 0;
/* 8/26/99: Obsolete: */
/* printTexLongMath in typeProof will do this
fprintf(g_texFilePtr, "%s", g_printString);
let(&g_printString, "");
*/
/* 8/26/99: printTeXLongMath now 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) {
/* 30-Jan-06 nm Added single-character-match wildcard argument */
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,
/* 1-May-2017 nm */
/* 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),
/*was: renumberFlag,*/
unknownFlag,
notUnifiedFlag,
reverseFlag,
/* 1-May-2017 nm */
/* 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),
/*was: noIndentFlag,*/
splitColumn,
skipRepeatedSteps, /* 28-Jun-2013 nm */
texFlag,
g_htmlFlag);
if (texFlag) {
if (!g_htmlFlag) {
/* 14-Sep-2010 nm */
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("</TABLE>\n");
print2("</CENTER>\n");
/* print trailer will close out string later */
g_outputToString = 0;
}
}
/*???CLEAN UP */
/*nmbrLet(&g_WrkProof.proofString, nmbrSaveProof);*/
/*E*/ if (0) { /* for debugging: */
printLongLine(nmbrCvtRToVString(g_WrkProof.proofString,
/* 25-Jan-2016 nm */
0, /*explicitTargets*/
0 /*statemNum, used only if explicitTargets*/)," "," ");
print2("\n");
nmbrLet(&nmbrSaveProof, nmbrSquishProof(g_WrkProof.proofString));
printLongLine(nmbrCvtRToVString(nmbrSaveProof,
/* 25-Jan-2016 nm */
0, /*explicitTargets*/
0 /*statemNum, used only if explicitTargets*/)," "," ");
print2("\n");
nmbrLet(&nmbrTmp, nmbrUnsquishProof(nmbrSaveProof));
printLongLine(nmbrCvtRToVString(nmbrTmp,
/* 25-Jan-2016 nm */
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);
/* 14-Sep-2010 nm Added OLD_TEX */
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,
/* 25-Jan-2016 nm */
0, /*explicitTargets*/
0 /*statemNum, used only if explicitTargets*/));
nmbrLet(&nmbrTmpPtr, NULL_NMBRSTRING);
continue;
}
/*E*/ /*???????? DEBUG command for debugging only */
if (cmdMatches("PROVE")) {
/* 14-Sep-2012 nm */
/* 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;
/* 10-May-2016 nm */
/* 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;
}
}
/*********** 14-Sep-2012 replaced by getStatementNum()
/@??? Make sure only $p statements are allowed. @/
for (i = 1; i <= g_statements; i++) {
if (!strcmp(g_fullArg[1],g_Statement[i].labelName)) break;
}
if (i > g_statements) {
printLongLine(cat("?There is no statement with label \"",
g_fullArg[1], "\". ",
"Use SHOW LABELS for a list of valid labels.", NULL), "", " ");
g_proveStatement = 0;
continue;
}
g_proveStatement = i;
if (g_Statement[g_proveStatement].type != (char)p_) {
printLongLine(cat("?Statement \"", g_fullArg[1],
"\" is not a $p statement.", NULL), "", " ");
g_proveStatement = 0;
continue;
}
************** end of 14-Sep-2012 deletion ************/
print2(
"Entering the Proof Assistant. HELP PROOF_ASSISTANT for help, EXIT to exit.\n");
/* Obsolete:
print2("You will be working on the proof of statement %s:\n",
g_Statement[g_proveStatement].labelName);
printLongLine(cat(" $p ", nmbrCvtMToVString(
g_Statement[g_proveStatement].mathString), NULL), " ", " ");
*/
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 */
/* 11-Sep-2016 nm */
/* Initialize the structure needed for the Proof Assistant */
initProofStruct(&g_ProofInProgress, nmbrSaveProof, g_proveStatement);
/****** 11-Sep-2016 nm Replaced by initProofStruct()
/@ Right now, only non-packed proofs are handled. @/
nmbrLet(&nmbrSaveProof, nmbrUnsquishProof(nmbrSaveProof));
/@ Assign initial proof structure @/
if (nmbrLen(g_ProofInProgress.proof)) bug(1113); /@ Should've been deall.@/
nmbrLet(&g_ProofInProgress.proof, nmbrSaveProof);
i = nmbrLen(g_ProofInProgress.proof);
pntrLet(&g_ProofInProgress.target, pntrNSpace(i));
pntrLet(&g_ProofInProgress.source, pntrNSpace(i));
pntrLet(&g_ProofInProgress.user, pntrNSpace(i));
nmbrLet((nmbrString @@)(&((g_ProofInProgress.target)[i - 1])),
g_Statement[g_proveStatement].mathString);
g_pipDummyVars = 0;
/@ Assign known subproofs @/
assignKnownSubProofs();
/@ Initialize remaining steps @/
for (j = 0; j < i/@proof length@/; j++) {
if (!nmbrLen((g_ProofInProgress.source)[j])) {
initStep(j);
}
}
/@ Unify whatever can be unified @/
autoUnify(0); /@ 0 means no "congrats" message @/
**** end of 11-Sep-2016 deletion ************/
/*
print2(
"Periodically save your work with SAVE NEW_PROOF and WRITE SOURCE.\n");
print2(
"There is no UNDO command yet. You can OPEN LOG to track what you've done.\n");
*/
/* 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");
/* 6/14/98 - 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*/, /* 28-Jun-2013 nm */
0 /*texFlag*/,
0 /*g_htmlFlag*/);
/* 6/14/98 end */
}
/* 3-May-2016 nm */
if (getMarkupFlag(g_proveStatement, PROOF_DISCOURAGED)) {
/* print2("\n"); */ /* Enable for more emphasis */
print2(
">>> ?Warning: Modification of this statement's proof is discouraged.\n"
);
/*
print2(
">>> You must use SAVE NEW_PROOF ... / OVERRIDE to save it.\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;
}
/* 1-Nov-2013 nm Added UNDO */
if (cmdMatches("UNDO")) {
processUndoStack(&g_ProofInProgress, PUS_UNDO, "", 0);
g_proofChanged = 1; /* Maybe make this more intelligent some day */
/* 6/14/98 - 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*/, /* 28-Jun-2013 nm */
0 /*texFlag*/,
0 /*g_htmlFlag*/);
/* 6/14/98 end */
continue;
}
/* 1-Nov-2013 nm Added REDO */
if (cmdMatches("REDO")) {
processUndoStack(&g_ProofInProgress, PUS_REDO, "", 0);
g_proofChanged = 1; /* Maybe make this more intelligent some day */
/* 6/14/98 - 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*/, /* 28-Jun-2013 nm */
0 /*texFlag*/,
0 /*g_htmlFlag*/);
/* 6/14/98 end */
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) */
}
/* 6/14/98 - 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*/, /* 28-Jun-2013 nm */
0 /*texFlag*/,
0 /*g_htmlFlag*/);
/* 6/14/98 end */
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 \"$<integer>\", 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")) {
/* 14-Sep-2012 nm */
s = getStepNum(g_fullArg[2], g_ProofInProgress.proof,
0 /* ALL not allowed */);
if (s == -1) continue; /* Error; message was provided already */
/************** 14-Sep-2012 replaced by getStepNum()
s = (long)val(g_fullArg[2]); /@ Step number @/
/@ 16-Apr-06 nm Added LET STEP n where n <= 0: 0 = last,
-1 = penultimate, etc. _unknown_ step @/
/@ Unlike ASSIGN LAST/FIRST and IMPROVE LAST/FIRST, it probably
doesn't make sense to add LAST/FIRST to LET STEP since known
steps can also be LET. The main purpose of LET STEP n, n<=0, is
to use with scripting for mmj2 imports. @/
offset = 0;
if (s <= 0) {
offset = - s + 1;
s = 1; /@ Temp. until we figure out which step @/
}
/@ End of 16-Apr-06 @/
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;
}
/@ 16-Apr-06 nm Added LET STEP n where n <= 0: 0 = last,
1 = penultimate, etc. _unknown_ step @/
if (offset > 0) { /@ step <= 0 @/
/@ Get the essential step flags @/
s = 0; /@ Use as flag that step was found @/
nmbrLet(&essentialFlags, nmbrGetEssential(g_ProofInProgress.proof));
/@ Scan proof backwards until last essential unknown step found @/
/@ 16-Apr-06 - count back 'offset' unknown steps @/
j = offset;
for (i = m; i >= 1; i--) {
if (essentialFlags[i - 1]
&& (g_ProofInProgress.proof)[i - 1] == -(long)'?') {
j--;
if (j == 0) {
/@ Found it @/
s = i;
break;
}
}
} /@ Next i @/
if (s == 0) {
if (offset == 1) {
print2("?There are no unknown essential steps.\n");
} else {
print2("?There are not at least %ld unknown essential steps.\n",
offset);
}
continue;
}
} /@ if offset > 0 @/
/@ End of 16-Apr-06 @/
******************** end 14-Sep-2012 deletion ********/
/* 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);
}
/* 6/14/98 - 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*/, /* 28-Jun-2013 nm */
0 /*texFlag*/,
0 /*g_htmlFlag*/);
/* 6/14/98 end */
continue;
}
if (cmdMatches("ASSIGN")) {
/* 10/4/99 - Added LAST - this means the last unknown step shown
with SHOW NEW_PROOF/ESSENTIAL/UNKNOWN */
/* 11-Dec-05 nm - Added FIRST - this means the first unknown step shown
with SHOW NEW_PROOF/ESSENTIAL/UNKNOWN */
/* 16-Apr-06 nm - Handle nonpositive step number: 0 = last,
-1 = penultimate, etc.*/
/* 14-Sep-2012 nm All the above now done by getStepNum() */
s = getStepNum(g_fullArg[1], g_ProofInProgress.proof,
0 /* ALL not allowed */);
if (s == -1) continue; /* Error; message was provided already */
/* 3-May-2016 nm */
/* 1 means to override usage locks */
overrideFlag = ( (switchPos("/ OVERRIDE")) ? 1 : 0)
|| g_globalDiscouragement == 0;
/****** replaced by getStepNum() nm 14-Sep-2012
offset = 0; /@ 16-Apr-06 @/
let(&str1, g_fullArg[1]); /@ To avoid void pointer problems with g_fullArg @/
if (toupper((unsigned char)(str1[0])) == 'L'
|| toupper((unsigned char)(str1[0])) == 'F') {
/@ "ASSIGN LAST" or "ASSIGN FIRST" @/
/@ 11-Dec-05 nm @/
s = 1; /@ Temporary until we figure out which step @/
offset = 1; /@ 16-Apr-06 @/
} else {
s = (long)val(g_fullArg[1]); /@ Step number @/
if (strcmp(g_fullArg[1], str((double)s))) {
print2("?Expected either a number or FIRST or LAST after ASSIGN.\n");
/@ 11-Dec-05 nm @/
continue;
}
if (s <= 0) { /@ 16-Apr-06 @/
offset = - s + 1; /@ 16-Apr-06 @/
s = 1; /@ Temporary until we figure out which step @/ /@ 16-Apr-06 @/
} /@ 16-Apr-06 @/
}
******************** end 14-Sep-2012 deletion ********/
/* 14-Sep-2012 nm */
/* 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 */
}
/*********** 14-Sep-2012 replaced by getStatementNum()
for (i = 1; i <= g_statements; i++) {
if (!strcmp(g_fullArg[2], g_Statement[i].labelName)) {
/@ If a $e or $f, it must be a hypothesis of the statement
being proved @/
if (g_Statement[i].type == (char)e_ || g_Statement[i].type == (char)f_){
if (!nmbrElementIn(1, g_Statement[g_proveStatement].reqHypList, i) &&
!nmbrElementIn(1, g_Statement[g_proveStatement].optHypList, i))
continue;
}
break;
}
}
if (i > g_statements) {
printLongLine(cat("?The statement with label \"",
g_fullArg[2],
"\" was not found or is not a hypothesis of the statement ",
"being proved. ",
"Use SHOW LABELS for a list of valid labels.", NULL), "", " ");
continue;
}
k = i;
if (k >= g_proveStatement) {
print2(
"?You must specify a statement that occurs earlier the one being proved.\n");
continue;
}
***************** end of 14-Sep-2012 deletion ************/
/* 3-May-2016 nm */
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 */
/****** replaced by getStepNum() nm 14-Sep-2012
if (s > m || s < 1) {
print2("?The step must be in the range from 1 to %ld.\n", m);
continue;
}
/@ 10/4/99 - For ASSIGN FIRST/LAST command, figure out the last unknown
essential step @/ /@ 11-Dec-05 nm - Added LAST @/
/@if (toupper(str1[0]) == 'L' || toupper(str1[0]) == 'F') {@/
/@ "ASSIGN LAST or FIRST" @/ /@ 11-Dec-05 nm @/
if (offset > 0) { /@ LAST, FIRST, or step <= 0 @/ /@ 16-Apr-06 @/
/@ Get the essential step flags @/
s = 0; /@ Use as flag that step was found @/
nmbrLet(&essentialFlags, nmbrGetEssential(g_ProofInProgress.proof));
/@ if (toupper((unsigned char)(str1[0])) == 'L') { @/
if (toupper((unsigned char)(str1[0])) != 'F') { /@ 16-Apr-06 @/
/@ Scan proof backwards until last essential unknown step is found @/
/@ 16-Apr-06 - count back 'offset' unknown steps @/
j = offset; /@ 16-Apr-06 @/
for (i = m; i >= 1; i--) {
if (essentialFlags[i - 1]
&& (g_ProofInProgress.proof)[i - 1] == -(long)'?') {
j--; /@ 16-Apr-06 @/
if (j == 0) { /@ 16-Apr-06 @/
/@ Found it @/
s = i;
break;
} /@ 16-Apr-06 @/
}
} /@ Next i @/
} else {
/@ 11-Dec-05 nm Added ASSIGN FIRST @/
/@ Scan proof forwards until first essential unknown step is found @/
for (i = 1; i <= m; i++) {
if (essentialFlags[i - 1]
&& (g_ProofInProgress.proof)[i - 1] == -(long)'?') {
/@ Found it @/
s = i;
break;
}
} /@ Next i @/
}
if (s == 0) {
if (offset == 1) { /@ 16-Apr-06 @/
print2("?There are no unknown essential steps.\n");
} else { /@ 16-Apr-06 @/
print2("?There are not at least %ld unknown essential steps.\n",
offset); /@ 16-Apr-06 @/
} /@ 16-Apr-06 @/
continue;
}
}
******************** end 14-Sep-2012 deletion ********/
/* 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 */
/* 8-Apr-05 nm 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 */
/******* 8-Apr-05 nm Commented out:
if (m == n) {
print2("Step %ld was assigned statement %s.\n",
s, g_Statement[k].labelName);
} else {
if (s != m) {
printLongLine(cat("Step ", str((double)s),
" was assigned statement ", g_Statement[k].labelName,
". Steps ", str((double)s), ":",
str((double)m), " are now ", str((double)(s - m + n)), ":", str((double)n), ".",
NULL),
"", " ");
} else {
printLongLine(cat("Step ", str((double)s),
" was assigned statement ", g_Statement[k].labelName,
". Step ", str((double)m), " is now step ", str((double)n), ".",
NULL),
"", " ");
}
}
*********/
/* 8-Apr-05 nm Added: */
/* 1-Nov-2013 nm No longer needed because of UNDO
printLongLine(cat("To undo the assignment, DELETE STEP ",
str((double)(s - m + n)), " and if needed INITIALIZE, UNIFY.",
NULL),
"", " ");
*/
/* 5-Aug-2020 nm */
/* 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),
"", " ");
}
}
/* 6/14/98 - 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*/, /* 28-Jun-2013 nm */
0 /*texFlag*/,
0 /*g_htmlFlag*/);
/* 6/14/98 end */
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")) {
/* s = (long)val(g_fullArg[1]); obsolete */ /* Step number */
/* 3-May-2016 nm */
/* 1 means to override usage locks */
overrideFlag = ( (switchPos("/ OVERRIDE")) ? 1 : 0)
|| g_globalDiscouragement == 0;
/* 14-Sep-2012 nm */
step = getStepNum(g_fullArg[1], g_ProofInProgress.proof,
0 /* ALL not allowed */);
if (step == -1) continue; /* Error; message was provided already */
/* This limitation is due to the assignKnownSteps call below which
does not tolerate unknown steps. */
/******* 10/20/02 Limitation removed
if (nmbrElementIn(1, g_ProofInProgress.proof, -(long)'?')) {
print2("?The proof must be complete before you can use REPLACE.\n");
continue;
}
*******/
/* 14-Sep-2012 nm */
/* 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 */
}
/*********** 14-Sep-2012 replaced by getStatementNum()
for (i = 1; i <= g_statements; i++) {
if (!strcmp(g_fullArg[2], g_Statement[i].labelName)) {
/@ If a $e or $f, it must be a hypothesis of the statement
being proved @/
if (g_Statement[i].type == (char)e_ || g_Statement[i].type == (char)f_){
if (!nmbrElementIn(1, g_Statement[g_proveStatement].reqHypList, i) &&
!nmbrElementIn(1, g_Statement[g_proveStatement].optHypList, i))
continue;
}
break;
}
}
if (i > g_statements) {
printLongLine(cat("?The statement with label \"",
g_fullArg[2],
"\" was not found or is not a hypothesis of the statement ",
"being proved. ",
"Use SHOW LABELS for a list of valid labels.", NULL), "", " ");
continue;
}
k = i;
if (k >= g_proveStatement) {
print2(
"?You must specify a statement that occurs earlier the one being proved.\n");
continue;
}
****************************** end of 14-Sep-2012 deletion *********/
/* 3-May-2016 nm */
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 */
/************** 14-Sep-2012 replaced by getStepNum()
if (s > m || s < 1) {
print2("?The step must be in the range from 1 to %ld.\n", m);
continue;
}
************* end of 14-Sep-2012 deletion **************/
/* Check to see that the step is a known step */
/* 22-Aug-2012 nm This check was deleted because it is unnecessary */
/*
if ((g_ProofInProgress.proof)[s - 1] == -(long)'?') {
print2(
"?Step %ld is unknown. You can only replace known steps.\n"
, s);
continue;
}
*/
/* 10/20/02 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;
}
/* 16-Sep-2012 nm */
/* 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, /* 3-May-2016 nm */
/* Currently REPLACE (not often used) allows other mathboxes
silently; TODO: we may want to notify user like for ASSIGN */
1/*mathboxFlag*/ /* 5-Aug-2020 nm */
);
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);
/* 10/20/02 Replaced "assignKnownSteps" with code from entry of PROVE
command so REPLACE can be done in partial proofs */
/*assignKnownSteps(s - q, nmbrLen(nmbrTmpPtr));*/ /* old code */
/* 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 */
/* end 10/20/02 */
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),
"", " ");
}
}
}
/*autoUnify(1);*/
/************ delete 19-Sep-2012 nm - not needed for REPLACE *******
/@ Automatically interact with user if step not unified @/
/@ ???We might want to add a setting to defeat this if user doesn't
like it @/
if (1 /@ ???Future setting flag @/) {
interactiveUnifyStep(step - m + n - 1, 2); /@ 2nd arg. means print
msg if already unified @/
}
*************** end 19-Sep-2012 deletion ********************/
g_proofChangedFlag = 1; /* Flag to push 'undo' stack */
g_proofChanged = 1; /* Cumulative flag */
processUndoStack(&g_ProofInProgress, PUS_PUSH, g_fullArgString, 0);
/* 16-Sep-2012 nm */
/*
if (dummyVarIsoFlag == 2 && g_proofChangedFlag) {
printLongLine(cat(
"Assignments to shared working variables ($nn) are guesses. If "
"incorrect, to undo DELETE STEP ",
str((double)(step - m + n)),
", INITIALIZE, UNIFY, then assign them manually with LET ",
"and try REPLACE again.",
NULL),
"", " ");
}
*/
/* 25-Feb-2014 nm */
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),
"", " ");
}
/* 14-Sep-2012 nm - 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*/, /* 28-Jun-2013 nm */
0 /*texFlag*/,
0 /*g_htmlFlag*/);
/* 14-Sep-2012 end */
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 */
/* 22-Aug-2012 nm Added */
searchAlg = 1; /* Default */
if (switchPos("/ 1")) searchAlg = 1;
if (switchPos("/ 2")) searchAlg = 2;
if (switchPos("/ 3")) searchAlg = 3;
/* 4-Sep-2012 nm Added */
searchUnkSubproofs = 0;
if (switchPos("/ SUBPROOFS")) searchUnkSubproofs = 1;
mathboxFlag = (switchPos("/ INCLUDE_MATHBOXES") != 0); /* 5-Aug-2020 */
/* 5-Aug-2020 nm */
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;
}
/* 3-May-2016 nm */
/* 1 means to override usage locks */
overrideFlag = ( (switchPos("/ OVERRIDE")) ? 1 : 0)
|| g_globalDiscouragement == 0;
/* 14-Sep-2012 nm */
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 */
/**************** 14-Sep-2012 nm replaced with getStepNum()
/@ 26-Aug-2006 nm Changed 'IMPROVE STEP <step>' to 'IMPROVE <step>' @/
let(&str1, g_fullArg[1]); /@ To avoid void pointer problems with g_fullArg @/
if (toupper((unsigned char)(str1[0])) != 'A') {
/@ 16-Apr-06 nm - Handle nonpositive step number: 0 = last,
-1 = penultimate, etc.@/
offset = 0; /@ 16-Apr-06 @/
/@ 10/4/99 - Added LAST - this means the last unknown step shown
with SHOW NEW_PROOF/ESSENTIAL/UNKNOWN @/
if (toupper((unsigned char)(str1[0])) == 'L'
|| toupper((unsigned char)(str1[0])) == 'F') {
/@ 'IMPROVE LAST' or 'IMPROVE FIRST' @/
s = 1; /@ Temporary until we figure out which step @/
offset = 1; /@ 16-Apr-06 @/
} else {
if (toupper((unsigned char)(str1[0])) == 'S') {
print2(
"?\"IMPROVE STEP <step>\" is obsolete. Use \"IMPROVE <step>\".\n");
continue;
}
s = (long)val(g_fullArg[1]); /@ Step number @/
if (strcmp(g_fullArg[1], str((double)s))) {
print2(
"?Expected a number or FIRST or LAST or ALL after IMPROVE.\n");
continue;
}
if (s <= 0) { /@ 16-Apr-06 @/
offset = - s + 1; /@ 16-Apr-06 @/
s = 1; /@ Temporary until we figure out step @/ /@ 16-Apr-06 @/
} /@ 16-Apr-06 @/
}
/@ End of 26-Aug-2006 change @/
/@ ------- Old code before 26-Aug-2006 -------
if (cmdMatches("IMPROVE STEP") || cmdMatches("IMPROVE LAST") ||
cmdMatches("IMPROVE FIRST")) { /# 11-Dec-05 nm #/
/# 16-Apr-06 nm - Handle nonpositive step number: 0 = last,
-1 = penultimate, etc.#/
offset = 0; /# 16-Apr-06 #/
/# 10/4/99 - Added LAST - this means the last unknown step shown
with SHOW NEW_PROOF/ESSENTIAL/UNKNOWN #/
if (cmdMatches("IMPROVE LAST") || cmdMatches("IMPROVE FIRST")) {
/# "IMPROVE LAST or FIRST" #/ /# 11-Dec-05 nm #/
s = 1; /# Temporary until we figure out which step #/
offset = 1; /# 16-Apr-06 #/
} else {
s = val(g_fullArg[2]); /# Step number #/
if (s <= 0) { /# 16-Apr-06 #/
offset = - s + 1; /# 16-Apr-06 #/
s = 1; /# Temp. until we figure out which step #/ /# 16-Apr-06 #/
} /# 16-Apr-06 #/
}
------- End of old code ------- @/
**************** end of 14-Sep-2012 nm ************/
m = nmbrLen(g_ProofInProgress.proof); /* Original proof length */
/**************** 14-Sep-2012 nm replaced with getStepNum()
if (s > m || s < 1) {
print2("?The step must be in the range from 1 to %ld.\n", m);
continue;
}
/@ 10/4/99 - For IMPROVE FIRST/LAST command, figure out the last
unknown essential step @/ /@ 11-Dec-05 nm - Added FIRST @/
/@if (cmdMatches("IMPROVE LAST") || cmdMatches("IMPROVE FIRST")) {@/
/@ IMPROVE LAST or FIRST @/ /@ 11-Dec-05 nm @/
if (offset > 0) { /@ LAST, FIRST, or step <= 0 @/ /@ 16-Apr-06 @/
/@ Get the essential step flags @/
s = 0; /@ Use as flag that step was found @/
nmbrLet(&essentialFlags, nmbrGetEssential(g_ProofInProgress.proof));
/@if (cmdMatches("IMPROVE LAST")) {@/
/@if (!cmdMatches("IMPROVE FIRST")) {@/ /@ 16-Apr-06 @/
if (toupper((unsigned char)(str1[0])) != 'F') { /@ 26-Aug-2006 @/
/@ Scan proof backwards until last essential unknown step found @/
/@ 16-Apr-06 - count back 'offset' unknown steps @/
j = offset; /@ 16-Apr-06 @/
for (i = m; i >= 1; i--) {
if (essentialFlags[i - 1]
&& (g_ProofInProgress.proof)[i - 1] == -(long)'?') {
j--; /@ 16-Apr-06 @/
if (j == 0) { /@ 16-Apr-06 @/
/@ Found it @/
s = i;
break;
} /@ 16-Apr-06 @/
}
} /@ Next i @/
} else {
/@ 11-Dec-05 nm Added IMPROVE FIRST @/
/@ Scan proof forwards until first essential unknown step found @/
for (i = 1; i <= m; i++) {
if (essentialFlags[i - 1]
&& (g_ProofInProgress.proof)[i - 1] == -(long)'?') {
/@ Found it @/
s = i;
break;
}
} /@ Next i @/
}
if (s == 0) {
if (offset == 1) { /@ 16-Apr-06 @/
print2("?There are no unknown essential steps.\n");
} else { /@ 16-Apr-06 @/
print2("?There are not at least %ld unknown essential steps.\n",
offset); /@ 16-Apr-06 @/
} /@ 16-Apr-06 @/
continue;
}
} /@ if offset > 0 @/
**************** end of 14-Sep-2012 nm ************/
/* 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;
}
/* 25-Aug-2012 nm */
/* 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 */
}
/********* Deleted old code 25-Aug-2012 nm
/@ Check to see that the step has no dummy variables. @/
j = 0; /@ Break flag @/
for (i = 0; i < nmbrLen((g_ProofInProgress.target)[s - 1]); i++) {
if (((nmbrString @)((g_ProofInProgress.target)[s - 1]))[i] > mathTokens) {
j = 1;
break;
}
}
if (j) {
print2(
"?Step %ld target has dummy variables and cannot be improved.\n", s);
continue;
}
********/
if (dummyVarIsoFlag == 0) { /* No dummy vars */ /* 25-Aug-2012 nm */
/* Only use proveFloating if no dummy vars */
nmbrTmpPtr = proveFloating((g_ProofInProgress.target)[s - 1],
g_proveStatement, improveDepth, s - 1, (char)p/*NO_DISTINCT*/,
overrideFlag, /* 3-May-2016 nm */
mathboxFlag /* 5-Aug-2020 nm */
);
} else {
nmbrTmpPtr = NULL_NMBRSTRING; /* Initialize */ /* 25-Aug-2012 nm */
}
if (!nmbrLen(nmbrTmpPtr)) {
/* A proof for the step was not found with proveFloating(). */
/* 22-Aug-2012 nm 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, /* 4-Sep-2012 */
overrideFlag, /* 3-May-2016 nm */
mathboxFlag /* 5-Aug-2020 nm */
);
}
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 */ /* 14-Sep-2012 nm */
} else {
/* Here, getStepNum() returned 0, meaning ALL */ /* 14-Sep-2012 nm */
/*if (cmdMatches("IMPROVE ALL")) {*/ /* obsolete */
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++) {
/* 25-Aug-2012 nm */
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; /* 25-Aug-2012 nm Added for clearer code */
/* 22-Aug-2012 nm 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) { /* 22-Aug-2012 nm */
/* 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); /* 25-Aug-2012 nm 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 */
/* 25-Aug-2012 nm */
/* 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 */
/********* Deleted old code now done by checkDummyVarIsolation()
25-Aug-2012 nm
/@ Check to see that the step has no dummy variables. @/
j = 0; /@ Break flag @/
for (i = 0; i < nmbrLen((g_ProofInProgress.target)[s - 1]); i++) {
if (((nmbrString @)((g_ProofInProgress.target)[s - 1]))[i] >
mathTokens) {
j = 1;
break;
}
}
if (j) {
/@ Step has dummy variables and cannot be improved. @/
continue;
}
********/
if (dummyVarIsoFlag == 0
&& (improveAllIter == 1
|| improveAllIter == 4)) {
/* No dummy vars */ /* 25-Aug-2012 nm */
/* Only use proveFloating if no dummy vars */
nmbrTmpPtr = proveFloating((g_ProofInProgress.target)[s - 1],
g_proveStatement, improveDepth, s - 1,
(char)p/*NO_DISTINCT*/,
overrideFlag, /* 3-May-2016 nm */
mathboxFlag /* 5-Aug-2020 nm */
);
} else {
nmbrTmpPtr = NULL_NMBRSTRING; /* Init */ /* 25-Aug-2012 nm */
}
if (!nmbrLen(nmbrTmpPtr)) {
/* A proof for the step was not found with proveFloating(). */
/* 22-Aug-2012 nm 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, /* 4-Sep-2012 */
overrideFlag, /* 3-May-2016 nm */
mathboxFlag /* 5-Aug-2020 nm */
);
}
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 */
/* 6/14/98 - 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*/, /* 28-Jun-2013 nm */
0 /*texFlag*/,
0 /*g_htmlFlag*/);
/* 6/14/98 end */
continue;
} /* cmdMatches("IMPROVE") */
if (cmdMatches("MINIMIZE_WITH")) {
/* 16-Aug-2016 nm */
printTime = 0;
if (switchPos("/ TIME") != 0) {
printTime = 1;
}
if (printTime == 1) {
getRunTime(&timeIncr); /* This call just resets the time */
}
/* q = 0; */ /* Line length */ /* 25-Jun-2014 deleted */
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("/ BRIEF") == 0); */ /* Non-verbose mode */
/* 4-Feb-2013 nm VERBOSE is now default */
verboseMode = (switchPos("/ VERBOSE") != 0); /* Verbose mode */
/* 30-Jan-06 nm Added single-character-match wildcard argument */
if (!(instr(1, g_fullArg[1], "*") || instr(1, g_fullArg[1], "?"))) i = 1;
/* 16-Feb-05 If no wildcard was used, switch to non-verbose mode
since there is no point to it and an annoying extra blank line
results */
mayGrowFlag = (switchPos("/ MAY_GROW") != 0);
/* Mode to replace even if it doesn't reduce proof length */
/* 25-Jun-2014 nm /NO_DISTINCT is obsolete
noDistinctFlag = (switchPos("/ NO_DISTINCT") != 0);
*/
/* Skip trying statements with $d */
exceptPos = switchPos("/ EXCEPT"); /* Statement match to skip */
/* 7-Jan-06 */
/* 4-Aug-2019 nm */
allowNewAxiomsMatchPos = switchPos("/ ALLOW_NEW_AXIOMS");
if (allowNewAxiomsMatchPos != 0) {
let(&allowNewAxiomsMatchList, g_fullArg[allowNewAxiomsMatchPos + 1]);
} else {
let(&allowNewAxiomsMatchList, "");
}
/* 20-May-2013 nm */
noNewAxiomsMatchPos = switchPos("/ NO_NEW_AXIOMS_FROM");
if (noNewAxiomsMatchPos != 0) {
let(&noNewAxiomsMatchList, g_fullArg[noNewAxiomsMatchPos + 1]);
} else {
let(&noNewAxiomsMatchList, "");
}
/* 20-May-2013 nm */
forbidMatchPos = switchPos("/ FORBID");
if (forbidMatchPos != 0) {
let(&forbidMatchList, g_fullArg[forbidMatchPos + 1]);
} else {
let(&forbidMatchList, "");
}
mathboxFlag = (switchPos("/ INCLUDE_MATHBOXES") != 0); /* 28-Jun-2011 */
/* 25-Jun-2014 nm /REVERSE is obsolete
forwFlag = (switchPos("/ REVERSE") != 0); /@ 10-Nov-2011 nm @/
*/
/****** 5-Aug-2020 nm Replaced w/ assignMathboxInfo() below
if (g_mathboxStmt == 0) { /@ Look up "mathbox" label if it hasn't been @/
g_mathboxStmt = lookupLabel("mathbox");
if (g_mathboxStmt == -1)
g_mathboxStmt = g_statements + 1; /@ Default beyond db end if none @/
}
*******/
/* 3-May-2016 nm */
/* Flag to override any "usage locks" placed in the comment markup */
overrideFlag = (switchPos("/ OVERRIDE") != 0)
|| g_globalDiscouragement == 0;
/* 25-Jun-2014 nm */
/* If a single statement is specified, don't bother to do certain
actions or print some of the messages */
/* 18-Jul-2020 nm New code*/
hasWildCard = 0;
/* (Note strpbrk warning in mmpars.c) */
/*if (strpbrk(g_fullArg[1], "*?=~%#@,") != NULL) {*/
/* 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;
}
/****** 18-Jul-2020 nm Deleted old code:
hasWildCard = (instr(1, g_fullArg[1], "*")
|| instr(1, g_fullArg[1], "?")
|| instr(1, g_fullArg[1], ",")
|| instr(1, g_fullArg[1], "~") /@ 3-May-2014 nm label~label range @/
);
********/
g_proofChangedFlag = 0;
/* Added 14-Aug-2012 nm */
/* Always scan statements in current mathbox, even if
"/ INCLUDE_MATHBOXES" is omitted */
/* 5-Aug-2020 nm */
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;
}
/****** 5-Aug-2020 deleted old code
thisMathboxStartStmt = g_mathboxStmt;
/@ Will become start of current (g_proveStatement's) mathbox @/
if (g_proveStatement > g_mathboxStmt) {
/@ We're in a mathbox @/
for (k = g_proveStatement; k >= g_mathboxStmt; k--) {
let(&str1, left(g_Statement[k].labelSectionPtr,
g_Statement[k].labelSectionLen));
/@ Heuristic to match beginning of mathbox @/
if (instr(1, str1, "Mathbox for") != 0) {
/@ Found beginning of current mathbox @/
thisMathboxStartStmt = k;
break;
}
}
}
**************/
/* 25-Jun-2014 nm */
copyProofStruct(&saveOrigProof, g_ProofInProgress);
/* 12-Sep-2016 nm TODO replace this w/ compressedProofSize */
/* 25-Jun-2014 nm 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");
/* 25-Jun-2014 nm forwRevPass outer loop added */
/* Scan forward, then reverse, then pick best result */
for (forwRevPass = 1; forwRevPass <= 2; forwRevPass++) {
/* 25-Jun-2014 nm */
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);
}
/* 20-May-2013 nm */
/*
if (forbidMatchList[0]) { /@ User provided a /FORBID list @/
/@ Save the proof structure in case we have to revert a
forbidden match. @/
copyProofStruct(&saveProofForReverting, g_ProofInProgress);
}
*/
/* 25-Jun-2014 nm */
copyProofStruct(&saveProofForReverting, g_ProofInProgress);
oldCompressedLength = origCompressedLength;
/* for (k = 1; k < g_proveStatement; k++) { */
/* 10-Nov-2011 nm */
/* 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)) {
/* 28-Jun-2011 */
/* Scan mathbox statements only if INCLUDE_MATHBOXES specified */
/*if (!mathboxFlag && k >= g_mathboxStmt) continue;*/
/* 14-Aug-2012 nm */
if (!mathboxFlag && k >= g_mathboxStmt && k < thisMathboxStartStmt) {
continue;
}
if (g_Statement[k].type != (char)p_ && g_Statement[k].type != (char)a_)
continue;
/* 30-Jan-06 nm Added single-character-match wildcard argument */
if (!matchesList(g_Statement[k].labelName, g_fullArg[1], '*', '?'))
continue;
/* 25-Jun-2014 nm /NO_DISTINCT is obsolete
if (noDistinctFlag) {
/@ Skip the statement if it has a $d requirement. This option
prevents illegal minimizations that would violate $d requirements
since MINIMIZE_WITH does not check for $d violations. @/
if (nmbrLen(g_Statement[k].reqDisjVarsA)) {
/@ 30-Jan-06 nm Added single-character-match wildcard argument @/
if (!(instr(1, g_fullArg[1], "@") || instr(1, g_fullArg[1], "?")))
print2("?\"%s\" has a $d requirement\n", g_fullArg[1]);
continue;
}
}
*/
/* 7-Jan-06 nm - Added EXCEPT switch */
if (exceptPos != 0) {
/* Skip any match to the EXCEPT argument */
/* 30-Jan-06 nm Added single-character-match wildcard argument */
if (matchesList(g_Statement[k].labelName, g_fullArg[exceptPos + 1],
'*', '?'))
continue;
}
/* 20-May-2013 nm */
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;
}
/* 3-May-2016 nm */
/* 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 */
/* 25-Jun-2014 nm Don't list matched statements anymore
if (verboseMode) {
q = q + (long)strlen(g_Statement[k].labelName) + 1;
if (q > 72) {
q = (long)strlen(g_Statement[k].labelName) + 1;
print2("\n");
}
print2("%s ",g_Statement[k].labelName);
}
*/
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) */
/* 20-May-2013 nm 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*/ /* 18-Jul-2015 nm */
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 */
}
}
}
/* 22-Nov-2014 nm 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. */
/* 4-Aug-2019 nm */
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) {
/******** start of 29-Nov-2019 nm ************/
/* 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 */
/* Bad code line between 4-Aug-2019 and 12-Feb-2020: */
/*nmbrLet(&nmbrSaveProof, nmbrSquishProof(g_ProofInProgress.proof));*/ /* Bad! */
/* 12-Feb-2020 nm */
/* 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;
/******** end of 29-Nov-2019 nm ************/
traceProofWork(g_proveStatement,
1 /*essentialFlag*/,
"", /*traceToList*/ /* 18-Jul-2015 nm */
&traceProofFlags, /* y/n list of flags */
&nmbrTmp /* unproved list - ignored */);
nmbrLet(&nmbrTmp, NULL_NMBRSTRING); /* Discard */
/******** start of 29-Nov-2019 nm ************/
/* Restore the SAVEd proof */
g_Statement[g_proveStatement].proofSectionPtr
= saveZappedProofSectionPtr;
g_Statement[g_proveStatement].proofSectionLen
= saveZappedProofSectionLen;
g_Statement[g_proveStatement].proofSectionChanged
= saveZappedProofSectionChanged; /* 16-Jun-2017 nm */
/******** end of 29-Nov-2019 nm ************/
}
let(&traceTrialFlags, "");
traceProofWork(k, /* The trial statement */
1 /*essentialFlag*/,
"", /*traceToList*/ /* 18-Jul-2015 nm */
&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) { /* 4-Aug-2019 nm */
/* 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 (matchesList(g_Statement[i].labelName, noNewAxiomsMatchList,
'@', '?') != 1) {
/@ If the axiom isn't in the list to avoid, 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) */
/* 25-Jun-2014 nm 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) */
/* 25-Jun-2014 nm */
/* 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;
/****** Obsolete due to 3-May-2017 update
/@ (search for "chr(1)" above for explanation) @/
let(&str1, cat(chr(1), "\n", str1, " $.\n", NULL));
g_Statement[g_proveStatement].proofSectionPtr = str1 + 1; /@ Compressed
proof generated above @/
g_Statement[g_proveStatement].proofSectionLen =
newCompressedLength + 4;
*******/
/******** start of 16-Jun-2017 nm ************/
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;
/******** end of 16-Jun-2017 nm ************/
g_outputToString = 1; /* Suppress error messages */
/* i = parseProof(g_proveStatement); */
/* if (i != 0) bug(1121); */
/* i = verifyProof(g_proveStatement); */
/* if (i != 0) bug(1122); */
/* 15-Apr-2015 nm 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() */
/* 15-Apr-2015 nm - 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; /* 16-Jun-2017 nm */
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)) */
/* 25-Jun-2014 nm - not needed since trials now suppressed */
/*
if (verboseMode) {
print2("\n");
}
*/
/*if (nmbrLen(g_Statement[k].reqDisjVarsA) || !mayGrowFlag) {*/
/* 3-May-2016 nm */
/* 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);
/* Distinct variable warning (obsolete) */
/*
if (nmbrLen(g_Statement[k].reqDisjVarsA)) {
printLongLine(cat("Note: \"", g_Statement[k].labelName,
"\" has $d constraints.",
" SAVE NEW_PROOF then VERIFY PROOF to check them.",
NULL), "", " ");
}
*/
/* q = 0; */ /* Line length for label list */ /* 25-Jun-2014 del */
/* 8-Aug-2020 nm */
/* 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;
/* deleted 25-Jun-2014:
/@ 20-May-2012 nm @/
if (forbidMatchList[0]) { /@ User provided a /FORBID list @/
/@ Save the changed proof in case we have to restore
it later @/
copyProofStruct(&saveProofForReverting, g_ProofInProgress);
}
*/
/* 25-Jun-2014 nm */
/* Save the changed proof in case we have to restore
it later */
copyProofStruct(&saveProofForReverting, g_ProofInProgress);
}
} /* Next k (statement) */
/* 25-Jun-2014 nm - not needed since trials now suppressed */
/*
if (verboseMode) {
if (prntStatus) print2("\n");
}
*/
if (g_proofChangedFlag && forwRevPass == 2) {
/* 25-Jun-2014 nm */
/* 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) "), /* 3-May-2016 nm */
g_fullArg[1]);
/* 25-Jun-2014 nm /NO_DISTINCT is obsolete
if (!prntStatus && noDistinctFlag) {
/@ 30-Jan-06 nm Added single-character-match wildcard argument @/
if (instr(1, g_fullArg[1], "@") || instr(1, g_fullArg[1], "?"))
print2("?No earlier $p or $a label (without $d) matches \"%s\".\n",
g_fullArg[1]);
}
*/
/* 28-Jun-2011 nm */
if (!mathboxFlag && g_proveStatement >= g_mathboxStmt) {
print2(
"(Other mathboxes were not checked. Use / INCLUDE_MATHBOXES to include them.)\n");
}
/* 16-Aug-2016 nm */
if (printTime == 1) {
getRunTime(&timeIncr);
print2("MINIMIZE_WITH run time = %7.2f sec for \"%s\"\n", timeIncr,
g_Statement[g_proveStatement].labelName);
}
/* 23-Nov-2019 nm */
let(&str1, ""); /* Deallocate memory */
nmbrLet(&nmbrSaveProof, NULL_NMBRSTRING); /* Deallocate memory */
/* 23-Nov-2019 nm */
/* 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 */
/* 4-Aug-2019 nm */
if (allowNewAxiomsMatchList[0]) { /* User provided /NO_NEW_AXIOMS_FROM list */
let(&allowNewAxiomsMatchList, ""); /* Deallocate memory */
}
/* 22-Nov-2014 nm */
if (noNewAxiomsMatchList[0]) { /* User provided /ALLOW_NEW_AXIOMS list */
let(&noNewAxiomsMatchList, ""); /* Deallocate memory */
}
/* 20-May-2013 nm */
if (forbidMatchList[0]) { /* User provided a /FORBID list */
/*deallocProofStruct(&saveProofForReverting);*/ /* Deallocate memory */
let(&forbidMatchList, ""); /* Deallocate memory */
}
/* 25-Jun-2014 nm */
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 */
/* 11-Sep-2016 nm Added EXPAND command */
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 */
/* 30-Jan-06 nm Added single-character-match wildcard argument */
if (!matchesList(g_Statement[i].labelName, g_fullArg[1], '*', '?')) {
continue;
}
sourceStatement = i;
nmbrTmp = expandProof(nmbrSaveProof,
sourceStatement /*, g_proveStatement*/);
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");
}
}
/* 6/14/98 - 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*/, /* 28-Jun-2013 nm */
0 /*texFlag*/,
0 /*g_htmlFlag*/);
/* 6/14/98 end */
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);
}
/* 6/14/98 - 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*/, /* 28-Jun-2013 nm */
0 /*texFlag*/,
0 /*g_htmlFlag*/);
/* 6/14/98 end */
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;
}
/* Added 16-Apr-06 nm */
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;
}
/* End 16-Apr-06 */
/* cmdMatches("INITIALIZE STEP") */
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 */ /* 16-Apr-06 */
nmbrLet((nmbrString **)(&((g_ProofInProgress.user)[s - 1])), /* 16-Apr-06 */
NULL_NMBRSTRING); /* 16-Apr-06 */
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 */
}
/* 14-Apr-2008 nm added */
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));
/* 30-Jan-06 nm Added 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));
}
/* End of 30-Jan-06 addition */
/* Change wildcard to ASCII 2 (to be different from printable chars) */
/* 1/3/02 (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));
}
/* 1/3/02 Also allow a plain $ as a wildcard, for convenience. */
while (1) {
p = instr(1, str1, " $ ");
if (!p) break;
/* 30-Jan-06 nm Bug fix - changed "2" to "3" below in order to
properly match 0 tokens */
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 */
}
/* 30-Jan-06 nm Added single-character-match wildcard argument */
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));
/* 14-Apr-2008 nm JOIN flag */
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));
/* 30-Jan-06 nm Added single-character-match wildcard argument */
/* 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;
/* 15-Jun-2009 nm Added "!" (see 15-Jun-2009 note above) */
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")) { /* 18-Nov-85 nm Was SCREEN_WIDTH */
s = (long)val(g_fullArg[2]); /* Screen width value */
/************ 19-Jun-2020 nm printBuffer is now dynamically allocated
if (s >= PRINTBUFFERSIZE - 1) {
print2(
"?Maximum screen width is %ld. Recompile with larger PRINTBUFFERSIZE in\n",
(long)(PRINTBUFFERSIZE - 2));
print2("mminou.h if you need more.\n");
continue;
}
*************/
/* 26-Sep-2017 nm */
/* 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; /* 26-Sep-2017 nm - print with new screen width */
print2("Screen width has been changed from %ld to %ld.\n",
i, s);
continue;
}
if (cmdMatches("SET HEIGHT")) { /* 18-Nov-05 nm Added */
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;
}
/* 10-Jul-2016 nm */
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;
}
/* 14-May-2017 nm */
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;
}
/* 31-Dec-2017 nm */
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;
}
/* 1-Nov-2013 nm Added UNDO */
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")) {
/* 2-Oct-2017 nm OPEN HTML is very obsolete, no need to warn anymore
if (cmdMatches("OPEN TEX") || cmdMatches("OPEN HTML") ) {
if (cmdMatches("OPEN HTML")) {
print2("?OPEN HTML is obsolete - use SHOW STATEMENT * / HTML\n");
continue;
}
*/
/* 17-Nov-2015 TODO: clean up mixed LaTeX/HTML attempts (check
g_texFileOpenFlag when switching to HTML & close LaTeX file) */
if (g_texDefsRead) {
/* Current limitation - can only read .def once */
/* 2-Oct-2017 nm OPEN HTML is obsolete */
/*if (cmdMatches("OPEN HTML") != g_htmlFlag) {*/
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;
}
}
/* 2-Oct-2017 nm OPEN HTML is obsolete */
/*g_htmlFlag = cmdMatches("OPEN HTML");*/
/* Open a TeX file */
let(&g_texFileName,g_fullArg[2]);
if (switchPos("/ NO_HEADER")) {
texHeaderFlag = 0;
} else {
texHeaderFlag = 1;
}
/* 14-Sep-2010 nm Added OLD_TEX */
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;
/* 2-Oct-2017 nm OPEN HTML is obsolete */
print2("Created %s output file \"%s\".\n",
g_htmlFlag ? "HTML" : "LaTeX", g_texFileName);
printTexHeader(texHeaderFlag);
g_oldTexFlag = 0;
continue;
}
/* 2-Oct-2017 nm CLOSE HTML is obsolete */
/******
if (cmdMatches("CLOSE TEX") || cmdMatches("CLOSE HTML")) {
if (cmdMatches("CLOSE HTML")) {
print2("?CLOSE HTML is obsolete - use SHOW STATEMENT @ / HTML\n");
continue;
}
/@ Close the TeX file @/
if (!g_texFileOpenFlag) {
print2("?Sorry, there is no %s file currently open.\n",
g_htmlFlag ? "HTML" : "LaTeX");
} else {
print2("The %s output file \"%s\" has been closed.\n",
g_htmlFlag ? "HTML" : "LaTeX", g_texFileName);
printTexTrailer(texHeaderFlag);
fclose(g_texFilePtr);
g_texFileOpenFlag = 0;
}
let(&g_texFileName,"");
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) <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 */ /* 31-Dec-2017 nm */
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;
}
/* 7-Nov-2015 nm New */ /* 17-Nov-2015 nm Updated */
/* 25-Jun-2020 nm Added UNDERSCORE_SKIP */
/* 17-Jul-2020 nm Added MATHBOX_SKIP */
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 */ /* 26-Dec-2016 nm */
continue;
}
/* 10-Dec-2018 nm Added */
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 */