pax_global_header00006660000000000000000000000064135737763710014535gustar00rootroot0000000000000052 comment=469e1b253f29be838411e2cc9c93d7704297059c metamath-exe-master/000077500000000000000000000000001357377637100147515ustar00rootroot00000000000000metamath-exe-master/LICENSE.TXT000066400000000000000000000431101357377637100164330ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. metamath-exe-master/Makefile.am000066400000000000000000000011701357377637100170040ustar00rootroot00000000000000bin_PROGRAMS = metamath noinst_HEADERS = \ mmcmdl.h \ mmcmds.h \ mmdata.h \ mmhlpa.h \ mmhlpb.h \ mminou.h \ mmmaci.h \ mmpars.h \ mmpfas.h \ mmunif.h \ mmutil.h \ mmveri.h \ mmvstr.h \ mmword.h \ mmwtex.h metamath_SOURCES = \ metamath.c \ mmcmdl.c \ mmcmds.c \ mmdata.c \ mmhlpa.c \ mmhlpb.c \ mminou.c \ mmmaci.c \ mmpars.c \ mmpfas.c \ mmunif.c \ mmutil.c \ mmveri.c \ mmvstr.c \ mmword.c \ mmwtex.c \ $(noinst_HEADERS) dist_pkgdata_DATA = \ big-unifier.mm \ demo0.mm \ miu.mm \ peano.mm \ ql.mm \ set.mm EXTRA_DIST = \ LICENSE.TXT \ README.TXT \ __README.TXT man_MANS = metamath.1 metamath-exe-master/README.TXT000066400000000000000000000123441357377637100163130ustar00rootroot00000000000000This package contains the metamath program and several Metamath databases. Copyright --------- The metamath program is copyright under the terms of the GNU GPL license version 2 or later. See the file LICENSE.TXT in this directory. Individual databases (*.mm files) are either public domain or under the GNU GPL, as indicated by comments in their headers. See http://us.metamath.org/copyright.html for further license and copyright information that applies to the content of this package. Instructions ------------ For Windows, click on "metamath.exe" and type "read set.mm". For Unix/Linux/Cygwin/MacOSX using the gcc compiler, compile with the command "gcc m*.c -o metamath", then type "./metamath set.mm" to run. As an alternative, if you have autoconf, automake, and a C compiler, you can compile with the command "autoreconf -i && ./configure && make". This "autoconf" approach automatically finds your compiler and its options, and configure takes the usual options (e.g., "--prefix=/usr"). The resulting executable will typically be faster because it will check for and enable available optimizations; tests found that the "improve" command ran 28% faster on gcc when using an autoconf-generated "configure". You can again type "./metamath set.mm" to run. After "make" you may install it elsewhere using "sudo make install" (note that this installs ".mm" files in the pkgdata directory, by default "/usr/local/share/metamath/"). If you install it this way, you can then run metamath as "metamath /usr/share/metamath/set.mm", copy set.mm locally (cp /usr/share/metamath/set.mm . ; metamath set.mm), or run metamath and type: read "/usr/share/metamath/set.mm" (note that inside metamath, filenames containing "/" must be quoted). Optional enhancements --------------------- For optimized performance under gcc, you can compile as follows: gcc m*.c -o metamath -O3 -funroll-loops -finline-functions \ -fomit-frame-pointer -Wall -pedantic If your compiler supports it, you can also add the option -DINLINE=inline to achieve the 28% performance increase described above. On Linux/MacOSX/Unix, the Metamath program will be more pleasant to use if you run it inside of rlwrap http://utopia.knoware.nl/~hlub/rlwrap/ (checked 3-Jun-2015) which provides up-arrow command history and other command-line editing features. After you install rlwrap per its instructions, invoke the Metamath program with "rlwrap ./metamath set.mm". In some Linux distributions (such as Debian Woody), if the Backspace key doesn't delete characters typed after the "MM>" prompt, try adding this line to your ~/.bash_profile file: stty echoe echok echoctl echoke Using rlwrap as described above will also solve this problem. Additional MacOSX information ----------------------------- On MacOSX, select the Terminal application from Applications/Utilities to get to the command line. On recent versions of MacOSX, you need to install gcc separately. Typing "whereis gcc" will return "/usr/bin/gcc" if it is installed. The XCode package is typically used to install it, but it can also be installed without XCode; see https://github.com/kennethreitz/osx-gcc-installer/ (checked 15-Feb-2014) Optional rlwrap user interface enhancement ------------------------------------------ On Linux/MacOSX/Unix, the Metamath program will be more pleasant to use if you run it inside of rlwrap: http://utopia.knoware.nl/~hlub/uck/rlwrap/ (checked 15-Feb-2014) which provides up-arrow command history and other command-line editing features. After you install rlwrap per its instructions, invoke the Metamath program with "rlwrap ./metamath set.mm". (The Windows version of the Metamath program was compiled with lcc, which has similar features built-in.) Windows Compilation ------------------- To reproduce the included metamath.exe for Windows, use lcc-win32 version 3.8, with the following command: lc -O m*.c -o metamath.exe Further suggestions ------------------- Once in the program, use the "help" command to guide you. For more information, see the Metamath book available at http://metamath.org . To uninstall ------------ To uninstall, just delete the "metamath" directory - nothing else (Registry, etc.) is touched in your system. If you used autoconf's "make install" to install it in system locations, you can use "make uninstall" to remove it. List of databases ----------------- The data base files included are: set.mm - logic and set theory database (see Ch. 3 of the Metamath book). The Metamath Proof Explorer pages were generated from this database. nf.mm - logic and set theory database for Quine's New Foundations set theory. hol.mm - higher order logic (simple type theory) database. iset.mm - intuitionistic logic database. ql.mm - quantum logic database. The Quantum Logic Explorer pages were generated from this database. demo0.mm - demo of simple formal system (see Ch. 2 of the Metamath book) miu.mm - Hofstadter's MIU-system (see Appendix D of the Metamath book) big-unifier.mm - A unification stress test (see comments in the file). peano.mm - A nicely commented presentation of Peano arithmetic, written by Robert Solovay (unlike the ones above, this database is NOT public domain but is copyright under the terms of the GNU GPL license) metamath-exe-master/configure.ac000066400000000000000000000041221357377637100172360ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.65]) AC_INIT([metamath], [0.114], [nm.NOSPAM@alum.mit.edu]) AC_CONFIG_SRCDIR([metamath.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign]) AC_CONFIG_FILES([Makefile]) # Checks for programs. AC_PROG_CC AC_PROG_INSTALL # Checks for libraries. # Checks for header files. AC_CHECK_HEADERS([limits.h stdlib.h string.h]) AC_HEADER_STDBOOL # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_SIZE_T # Checks for library functions. AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS([strchr strcspn strstr]) # Enable gcc warning flags, but only if they seem to work new_CFLAGS="-Wall -Wextra" saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $new_CFLAGS" AC_MSG_CHECKING([[for gcc warning flags]]) AC_LINK_IFELSE( [AC_LANG_PROGRAM([[ #include int f() { return 0; } ]])], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) AM_CFLAGS="$AM_CFLAGS $new_CFLAGS"]) # Try to optimize. AC_MSG_CHECKING([[for optimization flags]]) new_CFLAGS="-O3 -funroll-loops -finline-functions -fomit-frame-pointer" saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $new_CFLAGS" # Remove any existing "-O2", or it will override what we're doing. CFLAGS=$( printf "%s" "$CFLAGS" | sed -e 's/ -O2/ /' ) AC_LINK_IFELSE( [AC_LANG_PROGRAM([[ #include int f() { return 0; } ]])], [AC_MSG_RESULT([yes]) CFLAGS="$saved_CFLAGS" CFLAGS=$( printf "%s" "$CFLAGS" | sed -e 's/ -O2/ /' ) AM_CFLAGS="$AM_CFLAGS $new_CFLAGS"], [AC_MSG_RESULT([no]) CFLAGS="$saved_CFLAGS"]) # Can we use "inline"? We don't use AC_C _INLINE because metamath.c # does not include the autoconf-generated file. AC_MSG_CHECKING([[for 'inline' support]]) new_CFLAGS="-DINLINE=inline" saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $new_CFLAGS" AC_COMPILE_IFELSE( [AC_LANG_SOURCE([[ inline int f(void) {} ]])], [AC_MSG_RESULT([yes]) AM_CFLAGS="$AM_CFLAGS $new_CFLAGS"], [AC_MSG_RESULT([no])]) CFLAGS="$saved_CFLAGS" echo "CFLAGS=$CFLAGS" AC_SUBST([AM_CFLAGS]) AC_SUBST([CFLAGS]) AC_OUTPUT metamath-exe-master/metamath.1000066400000000000000000000103211357377637100166300ustar00rootroot00000000000000.\" t -*- coding: UTF-8 -*- .\" Man page for metamath .\" .\" Copyright (C) 2018 Aaron Puchert. .\" .\" This program is free software; you can redistribute it and/or modify .\" it under the terms of the GNU General Public License as published by .\" the Free Software Foundation; either version 2 of the License, or .\" (at your option) any later version. .\" .\" This program is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the .\" GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" along with this program; if not, write to the Free Software .\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA .\" .TH metamath 1 "2018-02-04" Metamath "User Manuals" .SH NAME metamath \- Formal proof verifier and proof assistant .SH SYNOPSIS .BI "metamath [ " "commands" " | " "file" " ]" .SH DESCRIPTION .B metamath is a formal proof verifier and proof assistant for the Metamath language. It can be initialized via a series of .I commands or with a data base .IR file , which can then be explored interactively. .PP For details about the Metamath language and the command-line interface, type .B help into the command prompt, or read the Metamath book [1], which should have been installed along with the package. .SH LANGUAGE A Metamath database consists of a sequence of three kinds of tokens separated by white space (which is any sequence of one or more white space characters). The set of keyword tokens is .BR ${ ", " $} ", " $c ", " $v ", " $f ", " $e ", " $d ", " $a ", " $p ", " .BR $. ", " $= ", " $( ", " $) ", " $[ ", and " $] . The latter four are called auxiliary or preprocessing keywords. A .I label token consists of any combination of letters, digits, and the characters hyphen, underscore, and period. The label of an assertion is used to refer to it in a proof. A math .I symbol token may consist of any combination of the 93 printable .BR ascii (7) characters other than .BR $ . All tokens are case-sensitive. .TP .BI $( " comment " $) Comments are ignored. .TP .BI $[ " file " $] Include the contents of a .IR file . .TP .BI ${ " statements " $} Scoped block of statements. A math symbol becomes active when declared and stays active until the end of the block in which it is declared. .TP .BI $v " symbols " $. Declare .I symbols as variables. A variable may not be declared a second time while it is active, but it may be declared again (as a variable, but not as a constant) after it becomes inactive. .TP .BI $c " symbols " $. Declare .I symbols as constants. A constant must be declared in the outermost block and may not be declared a second time. .TP .IB "label " $f " constant variable " $. Variable-type hypothesis to specify the nature or type of a variable (such as `let x be an integer.'). A variable must have its type specified in a .B $f statement before it may be used in a .BR $e ", " $a ", or " $p statement. There may not be two active .B $f statements containing the same variable. .TP .IB "label " $e " constant symbols " $. Logical hypothesis, expressing a logical truth (such as `assume x is prime') that must be established in order for an assertion requiring it to also be true. .TP .BI $d " variables " $. Disjoint variable restriction. For distinct active .IR variables , it forbids the substitution of one variable with another. .TP .IB "label " $a " constant symbols " $. Axiomatic assertion. .TP .IB "label " $p " constant symbols " $= " proof " $. Provable assertion. The .I proof is a sequence of statement .IR label s. This label sequence serves as a set of instructions that the Metamath program uses to construct a series of math symbol sequences. The construction must ultimately result in the math symbol sequence contained between the .BR $p " and " $= keywords of the .B $p statement. For details, see section 4.3 in [1]. Proofs are most easily written using the interactive prompt in .BR metamath . .SH FILES .I /usr/share/metamath .RS Data base files for several formal theories. .SH SEE ALSO .B "[1]" Norman Megill: .UR http://us.metamath.org/downloads/metamath.pdf Metamath, A Computer Language for Pure Mathematics .UE . metamath-exe-master/metamath.c000066400000000000000000012070061357377637100167230ustar00rootroot00000000000000/*****************************************************************************/ /* Program name: metamath */ /* Copyright (C) 2019 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*/ /* Contributors: In the future, the license may be changed to the MIT license or public domain. Therefore I request that any patches that are contributed be free of copyright restrictions (i.e. public domain) in order to provide this flexibility. Thank you. - NM */ /* This program should compile without warnings using: 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 -ansi -pedantic -Wunused-result For faster runtime, use: gcc m*.c -o metamath -O3 -funroll-loops -finline-functions \ -fomit-frame-pointer -Wall -ansi -pedantic -fno-strict-overflow With the lcc compiler on Windows, use: lc -O m*.c -o metamath.exe */ #define MVERSION "0.180 10-Dec-2019" /* 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 "htmlHome" in warnings to "htmlhome". */ /* 0.179 29-Nov-2019 nm (bj 22-Sep-2019) metamath.c - MINIMIZE_WITH axiom trace now starts from current NEW_PROOF instead of SAVEd proof. 23-Nov-2019 nm (bj 4-Oct-2019) metamath.c - make sure traceback flags are cleared after MINIMIZE_WITH 20-Nov-2019 nm mmhlpa.c - add url pointer to HELP WRITE SOURCE /SPLIT 18-Nov-2019 nm mmhlpa.c - clarify HELP WRITE SOURCE /REWRAP 15-Oct-2019 nm mmdata.c - add bug check info for user 14-Oct-2019 nm mmcmds.c - use '|->' (not 'e.') as syntax hint for maps-to 14-Oct-2019 nm mmwtex.c - remove extraneous */ /* 0.178 10-Aug-2019 nm mminou.c - eliminate redundant fopen in fSafeOpen 6-Aug-2019 nm mmwtex.c,h, mmcmds.c - Add error check for >1 line section name or missing closing decoration line in getSectionHeadings() 4-Aug-2019 nm mmhlpb.c, mmcmdl.c, metamath.c - Add /ALLOW_NEW_AXIOMS, renamed /ALLOW_GROWTH to /MAY_GROW 17-Jul-2019 nm mmcmdl.c, mmhlpa.c, metamath.c - Add /NO_VERSIONING to WRITE THEOREM_LIST 17-Jul-2019 nm metamath.c - Change line of dashes between SHOW STATEMENT output from hardcoded 79 to current screenWidth */ /* 0.177 27-Apr-2019 nm mmcmds.c -"set" -> "setvar" in htmlAllowedSubst. mmhlpb.c - fix typos in HELP IMPROVE. */ /* 0.176 25-Mar-2019 nm metamath.c mmcmds.h mmcmds.c mmcmdl.c mmhlpb.c - add /TOP_DATE_SKIP to VERIFY MARKUP */ /* 0.175 8-Mar-2019 nm mmvstr.c - eliminate warning in gcc 8.3 (patch provided by David Starner) */ /* 0.174 22-Feb-2019 nm mmwtex.c - fix erroneous warning when using "[[" bracket escape in comment */ /* 0.173 3-Feb-2019 nm mmwtex.c - fix infinite loop when "[" was the first character in a comment */ /* 0.172 25-Jan-2019 nm mmwtex.c - comment out bug 2343 trap (not a bug) */ /* 0.171 13-Dec-2018 nm metamath.c, mmcmdl.c, mmhlpa.c, mmcmds.c,h, mmwtex.c,h - add fine-grained qualfiers to MARKUP command */ /* 0.170 12-Dec-2018 nm mmwtex.c - restore line accidentally deleted in 0.169 */ /* 0.169 10-Dec-2018 nm metamath.c, mmcmds.c,h, mmcmdl.c, mmpars.c, mmhlpa.c, mmwtex.c - Add MARKUP command. 9-Dec-2018 nm mmwtex.c - escape literal "[" with "[[" in comments. */ /* 0.168 8-Dec-2018 nm metamath.c - validate that /NO_REPEATED_STEPS is used only with /LEMMON. 8-Dec-2018 nm mmcmds.c - fix bug #256 reported by Jim Kingdon (https://github.com/metamath/set.mm/issues/497). */ /* 0.167 13-Nov-2018 nm mmcmds.c - SHOW TRACE_BACK .../COUNT now uses proof the way it's stored (previously, it always uncompressed the proof). The new step count (for compressed proofs) corresponds to the step count the user would see on the web pages. 12-Nov-2018 nm mmcmds.c - added unlimited precision arithmetic for SHOW TRACE_BACK .../COUNT/ESSENTIAL */ /* 0.166 31-Oct-2018 nm mmwtex.c - workaround Chrome anchor bug 30-Oct-2018 nm mmcmds.c - put "This theorem is referenced by" after axioms and definitions used in HTML; use "(None)" instead of suppressing line if nothing is referenced */ /* 0.165 20-Oct-2018 nm mmwtex.c - added ~ mmtheorems#abc type anchor in TOC details. mmwtex.c - fix bug (reported by Benoit Jubin) that changes "_" in labels to subscript. mmcmdl.c - remove unused COMPLETE qualifier from SHOW PROOF. mmwtex.c - enhance special cases of web page spacing identified by Benoit Jubin */ /* 0.164 5-Sep-2018 nm mmwtex.c, mmhlpb.c - added NOTE to bib keywords 14-Aug-2018 nm metamath.c - added defaultScrollMode to prevent SET SCROLL CONTINUOUS from reverting to PROMPTED after a SUBMIT command */ /* 0.163 4-Aug-2018 nm mmwtex.c - removed 2nd "sandbox:bighdr" anchor in mmtheorems.html; removed Firefox and IE references; changed breadcrumb font to be consistent with other pages; put asterisk next to TOC entries that have associated comments */ /* FOR FUTURE REFERENCE: search for "Thierry" in mmwtex.c to modify the link to tirix.org structured proof site */ /* 0.162-thierry 3-Jun-2018 nm mmwtex.c - add link to tirix.org structured proofs */ /* 0.162 3-Jun-2018 nm mmpars.c - re-enabled error check for $c not in outermost scope. mmhlpa.c mmhlpb.c- improve some help messages. mmwtex.c - added "Observation", "Proof", and "Statement" keywords for WRITE BIBLIOGRAPHY */ /* 0.161 2-Feb-2018 nm mmpars.c,h mmcmds.c mmwtex.c - fix wrong file name and line number in error messages */ /* 0.160 24-Jan-2018 nm mmpars.c - fix bug introduced in version 0.158 */ /* 0.159 23-Jan-2018 nm mmpars.c - fix crash due to missing include file */ /* 0.158 22-Jan-2018 nm mminou.c - strip CRs from Windows SUBMIT files run on Linux */ /* 0.157 15-Jan-2018 nm Major rewrite of READ-related functions. Added HELP MARKUP. 9-Jan-2018 nm Track line numbers for error messages in included files 1-Jan-2018 nm Changed HOME_DIRECTORY to ROOT_DIRECTORY 31-Dec-2017 nm metamath.c mmcmdl.c,h mmpars.c,h mmcmds.c,h mminou.c,h mmwtex.c mmhlpb.c mmdata.h - add virtual includes "$( Begin $[...$] $)", $( End $[...$] $)", "$( Skip $[...$] $)" */ /* 0.156 8-Dec-2017 nm mmwtex.c - fix bug that incorrectly gave "verify markup" errors when there was a mathbox statement without an "extended" section */ /* 0.155 8-Oct-2017 nm mmcmdl.c - restore accidentally removed HELP HTML; mmhlpb.c mmwtex.c mmwtex.h,c mmcmds.c metamath.c - improve HELP and make other cosmetic changes per Benoit Jubin's suggestions */ /* 0.154 2-Oct-2017 nm mmunif.h,c mmcmds.c - add 2 more variables to ERASE; metamath.c mmcmdl.c - remove obsolete OPEN/CLOSE HTML; mmhlpa.c mmhlpb.c - fix typos reported by Benoit Jubin */ /* 0.153 1-Oct-2017 nm mmunif.c,h mmcmds.c - Re-initialize internal nmbrStrings in unify() after 'erase' command reported by Benoit Jubin */ /* 0.152 26-Sep-2017 nm mmcmds.c - change default links from mpegif to mpeuni; metamath.c - enforce minimum screen width = 3 to prevent crash reported by Benoit Jubin */ /* 0.151 20-Sep-2017 nm mmwtex.c - better matching to insert space between A and y in "E. x e. ran A y R x" to prevent spurious spaces in thms rncoeq, dfiun3g as reported by Benoit Jubin */ /* 0.150 26-Aug-2017 nm mmcmds.c,mmwtex.h - fix hyperlink for Distinct variable etc. lists so that it will point to mmset.html on other Explorers like NF. Move the "Dummy variables..." to print after the "Proof of Theorem..." line. */ /* 0.149 21-Aug-2017 nm mmwtex.c,h mmcmds.c mmhlpb.c - add a subsubsection "tiny" header with separator "-.-." to table of contents and theorem list; see HELP WRITE THEOREM_LIST 21-Aug-2017 nm mmcmds.c - remove bug check 255 19-Aug-2017 nm mmcmds.c - change mmset.html links to ../mpeuni/mmset.html so they will work in NF Explorer etc. */ /* 0.148 14-Aug-2017 nm mmcmds.c - hyperlink "Dummy variable(s)" */ /* 0.147 13-Aug-2017 nm mmcmds.c,h - add "Dummy variable x is distinct from all other variables." to proof web page */ /* 0.146 26-Jun-2017 nm mmwtex.c - fix handling of local labels in 'show proof.../tex' (bug 2341 reported by Eric Parfitt) */ /* 0.145 16-Jun-2017 nm metamath.c mmpars.c - fix bug 1741 during MINIMIZE_WITH; mmpfas.c - make duplicate bug numbers unique; mmhlpa.c mmhlpb.c - adjust to prevent lcc compiler "Function too big for the optimizer" 29-May-2017 nm mmwtex.c mmhlpa.c - take out extraneous ... markup tags in HTML output so w3c validator will pass */ /* 0.144 15-May-2017 nm metamath.c mmcmds.c - add "(Revised by..." tag for conversion of legacy .mm's if there is a 2nd date under the proof */ /* 0.143 14-May-2017 nm metamath.c mmdata.c,h mmcmdl.c mmcmds.c mmhlpb.c - added SET CONTRIBUTOR; for missing "(Contributed by..." use date below proof if it exists, otherwise use today's date, in order to update old .mm files. 14-May-2017 Ari Ferrera - mmcmds.c - fix memory leaks in ERASE */ /* 0.142 12-May-2017 nm metamath.c mmdata.c,h mmcmds.c - added "#define DATE_BELOW_PROOF" in mmdata.h that if uncommented, will enable use of the (soon-to-be obsolete) date below the proof 4-May-2017 Ari Ferrera - mmcmds.c metamath.c mmdata.c mmcmdl.c mminou.c mminou.h mmcmdl.h mmdata.h - fixed memory leaks and warnings found by valgrind. 3-May-2017 nm - metamath.c mmdata.c,h mmcmds.c,h mmpars.c,h mmhlpb.c mmcmdl.c mmwtex.c - added xxChanged flags to statement structure so that any part of the source can be changed; removed /CLEAN qualifier of WRITE SOURCE; automatically put "(Contributed by ?who?..." during SAVE NEW_PROOF or SAVE PROOF when it is missing; more VERIFY MARKUP checking. */ /* 0.141 2-May-2017 nm mmdata.c, metamath.c, mmcmds.c, mmhlpb.c - use getContrib() date for WRITE RECENT instead of date below proof. This lets us list recent $a's as well as $p's. Also, add caching to getContrib() for speedup. */ /* 0.140 1-May-2017 nm mmwtex.c, mmcmds.c, metamath.c - fix some LaTeX issues reported by Ari Ferrera */ /* 0.139 2-Jan-2017 nm metamath.c - print only one line for 'save proof * /compressed/fast' */ /* 0.138 26-Dec-2016 nm mmwtex.c - remove extraneous causing w3c validation failure; put space after 1st x in "F/ x x = x"; mmcmds.c - added checking for lines > 79 chars in VERIFY MARKUP; mmcmds.c, mmcmdl.c, metamath.c, mmhlpb.c, mmcmds.h - added /VERBOSE to VERIFY MARKUP */ /* 0.137 20-Dec-2016 nm mmcmds.c - check ax-XXX $a vs axXXX $p label convention in 'verify markup' 18-Dec-2016 nm mmwtex.c, mmpars.c, mmdata.h - use true "header area" between successive $a/$p for getSectionHeadings() mmcmds.c - add header comment checking 13-Dec-2016 nm mmdata.c,h - enhanced compareDates() to treat empty string as older date. 13-Dec-2016 nm metamath.c, mmcmds.c - moved mm* and Microsoft illegal file name label check to verifyMarkup() (the VERIFY MARKUP command) instead of checking on READ; added check of set.mm Version date to verifyMarkup(). 13-Dec-2016 nm mmwtex.c,h - don't treat bracketed description text with space as a bib label; add labelMatch parameter to writeBibliography() */ /* 0.136 10-Oct-2016 mminou.c - fix resource leak bug reported by David Binderman */ /* 0.135 11-Sep-2016, 14-Sep-2016 metamath.c, mmpfas.c,h, mmdata.c,h, mmpars.c,h mmcmds.c, mmcmdl.c, mmhlpb.c - added EXPAND command */ /* 0.134 16-Aug-2016 mmwtex.c - added breadcrumbs to theorem pages; metamath.c, mmcmdl.c, mmhlpb.c, mminou.c,.h - added /TIME to SAVE PROOF, SHOW STATEMENT.../[ALT}HTML, MINIMIZE_WITH */ /* 0.133 13-Aug-2016 mmwtex.c - improve mobile display with tag mmpars.c - use updated Macintosh information */ /* 0.132 10-Jul-2016 metamath.c, mmcmdl.c, mmcmds.c,.h, mmdata.c,.h, mmhlpb.c, mmpfas.c - change "restricted" to "discouraged" to match set.mm markup tags; add SET DISCOURAGEMENT OFF|ON (default ON) to turn off blocking for convenience of advanced users 6-Jul-2016 metamath.c - add "(void)" in front of "system(...)" to suppress -Wunused-result warning */ /* 0.131 10-Jun-2016 mminou.c - reverted change of 22-May-2016 because 'minimize_with' depends on error message in string to prevent DV violations. Todo: write a DV-checking routine for 'minimize_with', then revert the 22-May-2016 fix for bug 126 (which only occurs when writing web pages for .mm file with errors). 9-Jun-2016 mmcmdl.c, metamath.c - added _EXIT_PA for use with scripts that will give an error message outside of MM-PA> rather than exiting metamath */ /* 0.130 25-May-2016 mmpars.c - workaround clang warning about j = j; mmvstr.c - workaround gcc -Wstrict-overflow warning */ /* 0.129 24-May-2016 mmdata.c - fix bug 1393 */ /* 0.128 22-May-2016 mminou.c - fixed error message going to html page instead of to screen, triggering bug 126. */ /* 0.127 10-May-2016 metamath.c, mmcmdl.c, mmhlpb.c - added /OVERRIDE to PROVE */ /* 0.126 3-May-2016 metamath.c, mmdata.h, mmdata.c, mmcmds.h, mmcmds.c, mmcmdl.c, mmhlpb.c, mmpars.c - added getMarkupFlag() in mmdata.c; Added /OVERRIDE added to ASSIGN, REPLACE, IMPROVE, MINIMIZE_WITH, SAVE NEW_PROOF; PROVE gives warning about SAVE NEW_PROOF for locked proof. Added SHOW RESTRICTED command. 3-May-2016 m*.c - fix numerous conversion warnings provided by gcc 5.3.0 */ /* 0.125 10-Mar-2016 mmpars.c - fixed bug parsing /EXPLICIT/PACKED format 8-Mar-2016 nm mmdata.c - added "#nnn" to SHOW STATEMENT etc. to reference statement number e.g. SHOW STATEMENT #58 shows a1i in set.mm. 7-Mar-2016 nm mmwtex.c - added space between } and { in HTML output 6-Mar-2016 nm mmpars.c - disabled wrapping of formula lines in WRITE SOURCE.../REWRAP 2-Mar-2016 nm metamat.c, mmcmdl.c, mmhlpb.c - added /FAST to SAVE PROOF, SHOW PROOF */ /* 0.123 25-Jan-2016 nm mmpars.c, mmdata.h, mmdata.c, mmpfas.c, mmcmds., metamath.c, mmcmdl.c, mmwtex.c - unlocked SHOW PROOF.../PACKED, added SHOW PROOF.../EXPLICIT */ /* 0.122 14-Jan-2016 nm metamath.c, mmcmds.c, mmwtex.c, mmwtex.h - surrounded math HTML output with "...; added htmlcss and htmlfont $t commands 10-Jan-2016 nm mmwtex.c - delete duplicate -4px style; metamath.c - add   after char on mmascii.html 3-Jan-2016 nm mmwtex.c - fix bug when doing SHOW STATEMENT * /ALT_HTML after VERIFY MARKUP */ /* 0.121 17-Nov-2015 nm metamath.c, mmcmdl.h, mmcmdl.c, mmcmds.h, mmcmds.c, mmwtex.h, mmwtex.c, mmdata.h, mmdata.c - 1. Moved WRITE BIBLIOGRAPHY code from metamath.c to its own function in mmwtex.c; moved qsortStringCmp() from metamath.c to mmdata.c 2. Added $t, comment markup, and bibliography checking to VERIFY MARKUP 3. Added options to bug() bug-check interception to select aborting, stepping to next bug, or ignoring subsequent bugs 4. SHOW STATEMENT can now use both /HTML and /ALT_HTML in same session 5. Added /HTML, /ALT_HTML to WRITE THEOREM_LIST and WRITE RECENT_ADDITIONS */ /* 0.120 7-Nov-2015 nm metamath.c, mmcmdl.c, mmpars.c - add VERIFY MARKUP 4-Nov-2015 nm metamath.c, mmcmds.c/h, mmdata.c/h - move getDescription, getSourceIndentation from mmcmds.c to mmdata.c. metamath.c, mmdata.c - add and call parseDate() instead of in-line code; add getContrib(), getProofDate(), buildDate(), compareDates(). */ /* 0.119 18-Oct-2015 nm mmwtex.c - add summary TOC to Theorem List; improve math symbol GIF image alignment 2-Oct-2015 nm metamath.c, mmpfas.c, mmwtex.c - fix miscellaneous small bugs or quirks */ /* 0.118 18-Jul-2015 nm metamath.c, mmcmds.h, mmcmds.c, mmcmdl.c, mmhlpb.h, mmhlpb.c - added /TO qualifier to SHOW TRACE_BACK. See HELP SHOW TRACE_BACK. */ /* 0.117 30-May-2015 1. nm mmwtex.c - move of Theorem List pages */ /* 0.115 8-May-2015 nm mmwtex.c - added section header comments to WRITE THEOREM_LIST and broke out Table of Contents page 24-Apr-2015 nm metamath.c - add # bytes to end of "---Clip out the proof"; reverted to no blank lines there (see 0.113 item 3) */ /* 0.114 22-Apr-2015 nm mmcmds.c - put [-1], [-2],... offsets on 'show new_proof/unknown' */ /* 0.113 19-Apr-2015 so, nm metamath.c, mmdata.c 1. SHOW LABEL % will show statements with changed proofs 2. SHOW LABEL = will show the statement being proved in MM-PA 3. Added blank lines before, after "---------Clip out the proof" proof 4. Generate date only if the proof is complete */ /* 0.112 15-Apr-2015 nm metamath.c - fix bug 1121 (reported by S. O'Rear); mwtex.c - add "img { margin-bottom: -4px }" to CSS to align symbol GIFs; mwtex.c - remove some hard coding for set.mm, for use with new nf.mm; metamath.c - fix comment parsing in WRITE BIBLIOGRAPHY to ignore math symbols */ /* 0.111 22-Nov-2014 nm metamath.c, mmcmds.c, mmcmdl.c, mmhlpb.c - added /NO_NEW_AXIOMS_FROM qualifier to MINIMIZE_WITH; see HELP MINIMIZE_WITH. 21-Nov-2014 Stepan O'Rear mmdata.c, mmhlpb.c - added ~ label range specifier to wildcards; see HELP SEARCH */ /* 0.110 2-Nov-2014 nm mmcmds.c - fixed bug 1114 (reported by Stefan O'Rear); metamath.c, mmhlpb.c - added "SHOW STATEMENT =" to show the statement being proved in MM-PA */ /* 0.109 20-Aug-2014 nm mmwtex.c - fix corrupted HTML caused by misinterpreting math symbols as comment markup (math symbols with _ [ ] or ~). Also, allow https:// as well as http:// in ~ label markup. 11-Jul-2014 wl mmdata.c - fix obscure crash in debugging mode db9 */ /* 0.108 25-Jun-2014 nm (1) metamath.c, mmcmdl.c, mmhlpb.c - MINIMIZE_WITH now checks the size of the compressed proof, prevents $d violations, and tries forward and reverse statment scanning order; /NO_DISTINCT, /BRIEF, /REVERSE qualifiers were removed. (2) mminou.c - prevent hard breaks (in the middle of a word) in too-long lines (e.g. long URLs) in WRITE SOURCE .../REWRAP; just overflow the screen width instead. (3) mmpfas.c - fixed memory leak in replaceStatement() (4) mmpfas.c - suppress inf. growth with MINIMIZE_WITH idi/ALLOW_GROWTH */ /* 0.107 21-Jun-2014 nm metamath.c, mmcmdl.c, mmhlpb.c - added /SIZE qualifier to SHOW PROOF; added SHOW ELAPSED_TIME; mmwtex.c - reformatted WRITE THEOREM_LIST output; now "$(", newline, "######" starts a "part" */ /* 0.106 30-Mar-2014 nm mmwtex.c - fix bug introduced by 0.105 that disabled hyperlinks on literature refs in HTML comment. metamath.c - improve messages */ /* 0.105 15-Feb-2014 nm mmwtex.c - prevented illegal LaTeX output for certain special characters in comments. */ /* 0.104 14-Feb-2014 nm mmwtex.c - fixed bug 2312, mmcmds.c - enhanced ASSIGN error message. */ /* 0.103 4-Jan-2014 nm mmcmds.c,h - added "Allowed substitution hints" below the "Distinct variable groups" list on generated web pages mmwtex.c - added "*" to indicate DV's occur in Statement List entries. */ /* 0.102 2-Jan-2014 nm mminou.c - made compressed proof line wrapping more uniform at start of compressed part of proof */ /* 0.101 27-Dec-2013 nm mmdata.h,c, mminou.c, mmcmdl.c, mmhlpb.c, mmvstr.c - Improved storage efficiency of /COMPRESSED proofs (but with 20% slower run time); added /OLD_COMPRESSION to specify old algorithm; removed end-of-line space after label list in old algorithm; fixed linput() bug */ /* 0.100 30-Nov-2013 nm mmpfas.c - reversed statement scan order in proveFloating(), to speed up SHOW STATEMENT df-* /HTML; metamath.c - remove the unknown date place holder in SAVE NEW_PROOF; Wolf Lammen mmvstr.c - some cleanup */ /* 0.07.99 1-Nov-2013 nm metamath.c, mmpfas.h,c, mmcmdl.h,c, mmhlpa.c, mmhlpb.c - added UNDO, REDO, SET UNDO commands (see HELP UNDO) */ /* 0.07.98 30-Oct-2013 Wolf Lammen mmvstr.c,h, mmiou.c, mmpars.c, mmdata.c - improve code style and program structure */ /* 0.07.97 20-Oct-2013 Wolf Lammen mmvstr.c,h, metamath.c - improved linput(); nm mmcmds.c, mmdata.c - tolerate bad proofs in SHOW TRACE_BACK etc. */ /* 0.07.96 20-Sep-2013 Wolf Lammen mmvstr.c - revised cat(); nm mmwtex.c, mminou.c - change a print2 to printLongLine to fix bug 1150 */ /* 0.07.95 18-Sep-2013 Wolf Lammen mmvstr.c - optimized cat(); nm metamath.c, mmcmds.c, mmdata.c, mmpars.c, mmpfas.c, mmvstr.c, mmwtex.c - suppress some clang warnings */ /* 0.07.94 28-Aug-2013 Alexey Merkulov mmcmds.c, mmpars.c - fixed several memory leaks found by valgrind --leak-check=full --show-possibly-lost=no */ /* 0.07.93 8-Jul-2013 Wolf Lammen mmvstr.c - simplified let() function; also many minor changes in m*.c and m*.h to assist future refactoring */ /* 0.07.92 28-Jun-2013 nm metamath.c mmcmds.c,h mmcmdl.c mmhlpb.c- added /NO_REPEATED_STEPS for /LEMMON mode of SHOW PROOF, SHOW NEW_PROOF. This reverts the /LEMMON mode default display change of 31-Jan-2010 and invokes it when desired via /NO_REPEATED_STEPS. */ /* 0.07.91 20-May-2013 nm metamath.c mmpfas.c,h mmcmds.c,h mmcmdl.c mmhlpb.c- added /FORBID qualifier to MINIMIZE_WITH */ /* 0.07.90 19-May-2013 nm metamath.c mmcmds.c mmcmdl.c mmhlpb.c - added /MATCH qualifier to SHOW TRACE_BACK */ /* 0.07.88 18-Nov-2012 nm mmcmds.c - fixed bug 243 */ /* 0.07.87 17-Nov-2012 nm mmwtex.c - fixed formatting problem when label markup ends a comment in SHOW PROOF ... /HTML */ /* 0.07.86 27-Oct-2012 nm mmcmds.c, mmwtex.c, mmwtex.h - fixed ERASE bug caused by imperfect re-initialization; reported by Wolf Lammen */ /* 0.07.85 10-Oct-2012 nm metamath.c, mmcmdl.c, mmwtex.c, mmwtex.h, mmhlpb.c - added /SHOW_LEMMAS to WRITE THEOREM_LIST to bypass lemma math suppression */ /* 0.07.84 9-Oct-2012 nm mmcmds.c - fixed bug in getStatementNum() */ /* 0.07.83 19-Sep-2012 nm mmwtex.c - fixed bug reported by Wolf Lammen */ /* 0.07.82 16-Sep-2012 nm metamath.c, mmpfas.c - fixed REPLACE infinite loop; improved REPLACE message for shared dummy variables */ /* 0.07.81 14-Sep-2012 nm metamath.c, mmcmds.c, mmcmds.h, mmcmdl.c, mmhlpb.c - added FIRST, LAST, +nn, -nn where missing from ASSIGN, REPLACE, IMPROVE, LET STEP. Wildcards are allowed for PROVE, ASSIGN, REPLACE labels provided there is a unique match. */ /* 0.07.80 4-Sep-2012 nm metamath.c, mmpfas.c, mmpfas.h, mmcmdl.c, mmhlpb.c - added / 1, / 2, / 3, / SUBPROOFS to IMPROVE to specify search level */ /* 0.07.79 31-Aug-2012 nm m*.c - clean up some gcc warnings */ /* 0.07.78 28-Aug-2012 nm mmpfas.c - fix bug in 0.07.77. */ /* 0.07.77 25-Aug-2012 nm metamath.c, mmpfas.c - Enhanced IMPROVE algorithm to allow non-shared dummy variables in unknown steps */ /* 0.07.76 22-Aug-2012 nm metamath.c, mmpfas.c, mmcmdl.c, mmhlpb.c - Enhanced IMPROVE algorithm to also try REPLACE algorithm */ /* 0.07.75 14-Aug-2012 nm metamath.c - MINIMIZE_WITH now checks current mathbox (but not other mathboxes) even if /INCLUDE_MATHBOXES is omitted */ /* 0.07.74 18-Mar-2012 nm mmwtex.c, mmcmds.c, metamath.c - improved texToken() error message */ /* 0.07.73 26-Dec-2011 nm mmwtex.c, mmpars.c - added ... in comments for passing through raw HTML code into HTML files generated with SHOw STATEMENT xxx / HTML */ /* 0.07.72 25-Dec-2011 nm (obsolete) */ /* 0.07.71 10-Nov-2011 nm metamath.c, mmcmdl.c - added /REV to MINIMIZE_WITH */ /* 0.07.70 6-Aug-2011 nm mmwtex.c - fix handling of double quotes inside of htmldef strings to match spec in Metamath book Appendix A p. 156 */ /* 0.07.69 9-Jul-2011 nm mmpars.c, mmvstr.c - Untab file in WRITE SOURCE ... /REWRAP */ /* 0.07.68 3-Jul-2011 nm metamath.c, mminou.h, mminou.c - Nested SUBMIT calls (SUBMIT calls inside of a SUBMIT command file) are now allowed. Also, mmdata.c - fix memory leak. */ /* 0.07.67 2-Jul-2011 nm metamath.c, mmcmdl.c, mmhlpa.c - Added TAG command to TOOLS. See HELP TAG under TOOLS. (The old special-purpose TAG command was renamed to UPDATE.) */ /* 0.07.66 1-Jul-2011 nm metamath.c, mmcmds.c, mmpars.c, mmpars.h - Added code to strip spurious "$( [?] $)" in WRITE SOURCE ... /CLEAN output */ /* 0.07.65 30-Jun-2011 nm mmwtex.c - Prevent processing [...] bibliography brackets inside of `...` math strings in comments. */ /* 0.07.64 28-Jun-2011 nm metamath.c, mmcmdl.c - Added /INCLUDE_MATHBOXES qualifier to MINIMIZE_WITH; without it, MINIMIZE_WITH * will skip checking user mathboxes. */ /* 0.07.63 26-Jun-2011 nm mmwtex.c - check that .gifs exist for htmldefs */ /* 0.07.62 18-Jun-2011 nm mmpars.c - fixed bug where redeclaration of active $v was not detected */ /* 0.07.61 12-Jun-2011 nm mmpfas.c, mmcmds.c, metamath.c, mmhlpb.c - added /FORMAT and /REWRAP qualifiers to WRITE SOURCE to format according to set.mm conventions - set HELP WRITE SOURCE */ /* 0.07.60 7-Jun-2011 nm mmpfas.c - fixed bug 1805 which occurred when doing MINIMIZE_WITH weq/ALLOW_GROWTH after DELETE DELETE FLOATING_HYPOTHESES */ /* 0.07.59 11-Dec-2010 nm mmpfas.c - increased default SET SEARCH_LIMIT from 10000 to 25000 to accomodate df-plig web page in set.mm */ /* 0.07.58 9-Dec-2010 nm mmpars.c - detect if same symbol is used with both $c and $v, in order to conform with Metamath spec */ /* 0.07.57 19-Oct-2010 nm mmpars.c - fix bug causing incorrect line count for error messages when non-ASCII character was found; mminou.h - increase SET WIDTH maximum from 999 to 9999 */ /* 0.07.56 27-Sep-2010 nm mmpars.c, mmpfas.c - check for $a's with one token e.g. "$a wff $."; if found, turn SET EMPTY_SUBSTITUTION ON automatically. (Suggested by Mel O'Cat; patent pending.) */ /* 0.07.55 26-Sep-2010 nm mmunif.c, mmcmds.c, mmunif.h - check for mismatched brackets in all $a's, so that if there are any, the bracket matching algorithm (for fewer ambiguous unifications) in mmunif.c will be turned off. */ /* 0.07.54 25-Sep-2010 nm mmpars.c - added $f checking to conform to the current Metamath spec, so footnote 2 on p. 92 of Metamath book is no longer applicable. */ /* 0.07.53 24-Sep-2010 nm mmveri.c - fixed bug(2106), reported by Michal Burger */ /* 0.07.52 14-Sep-2010 nm metamath.c, mmwtex.h, mmwtex.c, mmcmds.c, mmcmdl.c, mmhlpb.c - rewrote the LaTeX output for easier hand-editing and embedding in LaTeX documents. The old LaTeX output is still available with /OLD_TEX on OPEN TEX, SHOW STATEMENT, and SHOW PROOF, but it is obsolete and will be deleted eventually if no one objects. The new /TEX output also replaces the old /SIMPLE_TEX, which was removed. */ /* 0.07.51 9-Sep-2010 Stefan Allen mmwtex.c - put hyperlinks on hypothesis label references in SHOW STATEMENT * /HTML, ALT_HTML output */ /* 0.07.50 21-Feb-2010 nm mminou.c - "./metamath < empty", where "empty" is a 0-byte file, now exits metamath instead of producing an infinite loop. Also, ^D now exits metamath. Reported by Cai Yufei */ /* 0.07.49 31-Jan-2010 nm mmcmds.c - Lemmon-style proofs (SHOW PROOF xxx /LEMON/RENUMBER) no longer have steps with dummy labels; instead, steps are now the same as in HTML page proofs. (There is a line to comment out if you want to revert to old behavior.) */ /* 0.07.48 11-Sep-2009 nm mmpars.c, mm, mmvstr.c, mmdata.c - Added detection of non-whitespace around keywords (mmpars.c); small changes to eliminate warnings in gcc 3.4.4 (mmvstr.c, mmdata.c) */ /* 0.07.47 2-Aug-2009 nm mmwtex.c, mmwtex.h - added user name to mathbox pages */ /* 0.07.46 24-Jul-2009 nm metamath.c, mmwtex.c - changed name of sandbox to "mathbox" */ /* 0.07.45 15-Jun-2009 nm metamath.c, mmhlpb.c - put "!" before each line of SET ECHO ON output to make them easy to identity for creating scripts */ /* 0.07.44 12-May-2009 Stefan Allan, nm metamath.c, mmcmdl.c, mmwtex.c - added SHOW STATEMENT / MNEMONICS - see HELP SHOW STATEMENT */ /* 0.07.43 29-Aug-2008 nm mmwtex.c - workaround for Unicode huge font bug in FireFox 3 */ /* 0.07.42 8-Aug-2008 nm metamath.c - added sandbox, Hilbert Space colors to Definition List */ /* 0.07.41 29-Jul-2008 nm metamath.c, mmwtex.h, mmwtex.c - Added handling of sandbox section of Metamath Proof Explorer web pages */ /* 0.07.40 6-Jul-2008 nm metamath.c, mmcmdl.c, mmhlpa.c, mmhlpb.c - Added / NO_VERSIONING qualifier for SHOW STATEMENT, so website can be regenerated in place with less temporary space required. Also, the wildcard trigger for mmdefinitions.html, etc. is more flexible (see HELP HTML). */ /* 0.07.39 21-May-2008 nm metamath.c, mmhlpb.c - Added wildcard handling to statement label in SHOW TRACE_BACK. All wildcards now allow comma-separated lists [i.e. matchesList() instead of matches()] */ /* 0.07.38 26-Apr-2008 nm metamath.c, mmdata.h, mmdata.c, mmvstr.c, mmhlpb.c - Enhanced / EXCEPT qualifier for MINIMIZE_WITH to handle comma-separated wildcard list. */ /* 0.07.37 14-Apr-2008 nm metamath.c, mmcmdl.c, mmhlpb.c - Added / JOIN qualifier to SEARCH. */ /* 0.07.36 7-Jan-2008 nm metamath.c, mmcmdl.c, mmhlpb.c - Added wildcard handling for labels in SHOW USAGE. */ /* 0.07.35 2-Jan-2008 nm mmcmdl.c, metamath.c, mmhlpb.c - Changed keywords COMPACT to PACKED and COLUMN to START_COLUMN so that SAVE/SHOW proof can use C to abbreviate COMPRESSED. (PACKED format is supported but "unofficial," used mainly for debugging purposes, and is not listed in HELP SAVE PROOF.) */ /* 0.07.34 19-Nov-2007 nm mmwtex.c, mminou.c - Added tooltips to proof step hyperlinks in SHOW STATEMENT.../HTML,ALT_HTML output (suggested by Reinder Verlinde) */ /* 0.07.33 19-Jul-2007 nm mminou.c, mmvstr.c, mmdata.c, mmword.c - added fflush after each printf() call for proper behavior inside emacs (suggested by Frederic Line) */ /* 0.07.32 29-Apr-2007 nm mminou.c - fSafeOpen now stops at gap; e.g. if ~2 doesn't exist, ~1 will be renamed to ~2, but any ~3, etc. are not touched */ /* 0.07.31 5-Apr-2007 nm mmwtex.c - Don't make "_" in hyperlink a subscript */ /* 0.07.30 8-Feb-2007 nm mmcmds.c, mmwtex.c Added HTML statement number info to SHOW STATEMENT.../FULL; friendlier "Contents+1" link in mmtheorems*.html */ /* 0.07.29 6-Feb-2007 Jason Orendorff mmpfas.c - Patch to eliminate the duplicate "Exceeded trial limit at step n" messages */ /* 0.07.28 22-Dec-2006 nm mmhlpb.c - Added info on quotes to HELP LET */ /* 0.07.27 23-Oct-2006 nm metamath.c, mminou.c, mmhlpa.c, mmhlpb.c - Added / SILENT qualifier to SUBMIT command */ /* 0.07.26 12-Oct-2006 nm mminou.c - Fixed bug when SUBMIT file was missing a new-line at end of file (reported by Marnix Klooster) */ /* 0.07.25 10-Oct-2006 nm metamath.c - Fixed bug invoking TOOLS as a ./metamath command-line argument */ /* 0.07.24 25-Sep-2006 nm mmcmdl.c Fixed bug in SHOW NEW_PROOF/START_COLUMN nn/LEM */ /* 0.07.23 31-Aug-2006 nm mmwtex.c - Added Home and Contents links to bottom of WRITE THEOREM_LIST pages */ /* 0.07.22 26-Aug-2006 nm metamath.c, mmcmdl.c, mmhlpb.c - Changed 'IMPROVE STEP ' to 'IMPROVE ' for user convenience and to be consistent with ASSIGN */ /* 0.07.21 20-Aug-2006 nm mmwtex.c - Revised small colored numbers so that all colors have the same grayscale brightness.. */ /* 0.07.20 19-Aug-2006 nm mmpars.c - Made the error "Required hypotheses may not be explicitly declared" in a compressed proof non-severe, so that we can still SAVE the proof to reformat and recover it. */ /* 0.07.19 11-Aug-06 nm mmcmds.c - "Distinct variable group(s)" is now "group" or "groups" as appropriate. */ /* 0.07.18 31-Jul-06 nm mmwtex.c - added table to contents to p.1 of output of WRITE THEOREM_LIST command. */ /* 0.07.17 4-Jun-06 nm mmpars.c - do not allow labels to match math symbols (new spec proposed by O'Cat). mmwtex.c - made theorem name 1st in title, for readability in Firefox tabs. */ /* 0.07.16 16-Apr-06 nm metamath.c, mmcmdl.c, mmpfas.c, mmhlpb.c - allow step to be negative (relative to end of proof) for ASSIGN, UNIFY, and LET STEP (see their HELPs). Added INITIALIZE USER to delete LET STEP assignments (see HELP INITIALIZE). Fixed bug in LET STEP (mmpfas.c). */ /* 0.07.15 10-Apr-06 nm metamath.c, mmvstr.c - change dates from 2-digit to 4-digit year; make compatible with older 2-digit year. */ /* 0.07.14 21-Mar-06 nm mmpars.c - fix bug 1722 when compressed proof has "Z" at beginning of proof instead of after a proof step. */ /* 0.07.13 3-Feb-06 nm mmpfas.c - minor improvement to MINIMIZE_WITH */ /* 0.07.12 30-Jan-06 nm metamath.c, mmcmds.c, mmdata.c, mmdata.h, mmhlpa.c, mmhlpb.c - added "?" wildcard to match single character. See HELP SEARCH. */ /* 0.07.11 7-Jan-06 nm metamath.c, mmcmdl.c, mmhlpb.c - added EXCEPT qualifier to MINIMIZE_WITH */ /* 0.07.10 28-Dec-05 nm metamath.c, mmcmds.c - cosmetic tweaks */ /* 0.07.10 11-Dec-05 nm metamath.c, mmcmdl.c, mmhlpb.c - added ASSIGN FIRST and IMPROVE FIRST commands. Also enhanced READ error message */ /* 0.07.9 1-Dec-05 nm mmvstr.c - added comment on how to make portable */ /* 0.07.9 18-Nov-05 nm metamath.c, mminou.c, mminou.h, mmcmdl.c, mmhlpb.c - added SET HEIGHT command; changed SET SCREEN_WIDTH to SET WIDTH; changed SET HENTY_FILTER to SET JEREMY_HENTY_FILTER (to make H for HEIGHT unambiguous); added HELP for SET JEREMY_HENTY_FILTER */ /* 0.07.8 15-Nov-05 nm mmunif.c - now detects wrong order in bracket matching heuristic to further reduce ambiguous unifications in Proof Assistant */ /* 0.07.7 12-Nov-05 nm mmunif.c - add "[","]" and "[_","]_" bracket matching heuristic to reduce ambiguous unifications in Proof Assistant. mmwtex.c - added heuristic for HTML spacing after "sum_" token. */ /* 0.07.6 15-Oct-05 nm mmcmds.c,mmpars.c - fixed compressed proof algorithm to match spec in book (with new algorithm due to Marnix Klooster). Users are warned to convert proofs when the old compression is found. */ /* 0.07.5 6-Oct-05 nm mmpars.c - fixed bug that reset "severe error in proof" flag when a proof with severe error also had unknown steps */ /* 0.07.4 1-Oct-05 nm mmcmds.c - ignored bug 235, which could happen for non-standard logics */ /* 0.07.3 17-Sep-05 nm mmpars.c - reinstated duplicate local label checking to conform to strict spec */ /* 0.07.2 19-Aug-05 nm mmwtex.c - suppressed math content for lemmas in WRITE THEOREMS output */ /* 0.07.1 28-Jul-05 nm Added SIMPLE_TEX qualifier to SHOW STATEMENT */ /* 0.07: Official 0.07 22-Jun-05 corresponding to Metamath book */ /* 0.07x: Fixed to work with AMD64 with 64-bit longs by Waldek Hebisch; deleted unused stuff in mmdata.c */ /* 0.07w: .mm date format like "$( [7-Sep-04] $)" is now generated and permitted (old one is tolerated too for compatibility) */ /* Metamath Proof Verifier - main program */ /* See the book "Metamath" for description of Metamath and run instructions */ /* 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 ---------------------------------- */ /*****************************************************************************/ /* These are the instructions for the gcc compiler (standard in Linux and Cygwin for 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 metamath.c m*.c -o metamath 3. For better speed and error checking, use these gcc options: gcc m*.c -o metamath -O3 -funroll-loops -finline-functions \ -fomit-frame-pointer -Wall -ansi -pedantic 4. The Windows version in the download was compiled with LCC-Win32: lc -O m*.c -o metamath.exe */ /*****************************************************************************/ /*----------------------------------------------------------------------*/ #include #include #include #include #include #include /* #include */ /* 21-Jun-2014 nm For ELAPSED_TIME */ #ifdef THINK_C #include #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 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.) */ listMode = 0; /* Force Metamath mode as startup */ toolsMode = listMode; if (!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(&contributorName, DEFAULT_CONTRIBUTOR); /* Process a command line until EXIT */ command(argc, argv); /* Close logging command file */ if (listMode && listFile_fp != NULL) { fclose(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 ", statement[stmt].labelName, "", str4, "", 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" */ showStatement = stmt; /* For printTexComment */ outputToString = 0; /* For printTexComment */ 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 texFilePtr */ 0, /* 1 = htmlCenterFlag */ PROCESS_EVERYTHING, /* actionBits */ /* 13-Dec-2018 nm */ 0 /* 1 = noFileCheck */ ); texFilePtr = NULL; outputToString = 1; /* Restore after printTexComment */ /* Get HTML hypotheses => assertion */ let(&str4, ""); str4 = getTexOrHtmlHypAndAssertion(stmt); /* In mmwtex.c */ printLongLine(cat("" : cat(" BGCOLOR=", PURPLISH_BIBLIO_COLOR, ">", NULL), */ /* 29-Jul-2008 nm Sandbox stuff */ (stmt < extHtmlStmt) ? ">" : (stmt < sandboxStmt) ? cat(" BGCOLOR=", PURPLISH_BIBLIO_COLOR, ">", NULL) : cat(" BGCOLOR=", SANDBOX_COLOR, ">", NULL), /*** old " ", str4, "", NULL), ****/ /* 27-Oct-03 nm */ "", str4, "", NULL), " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ outputToString = 0; fprintf(list2_fp, "%s", printString); let(&printString, ""); if (n >= i /*RECENT_COUNT*/) break; /* We're done */ /* 27-Oct-03 nm Put separator row if not last theorem */ outputToString = 1; printLongLine(cat("", " ", 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 (statement[q].type == (char)p_ || statement[q].type == (char)a_ ) { j = q; break; } } /* 13-Dec-2018 nm This isn't used anywhere yet. But fix error in current label and also identify previous, current, next */ if (j) print2("\n", statement[j].labelName); /* Current statement */ print2("\n", statement[stmt].labelName); /* Find the next statement with a web page */ j = 0; for (q = stmt + 1; q <= statements; q++) { if (statement[q].type == (char)p_ || statement[q].type == (char)a_ ) { j = q; break; } } if (j) print2("\n", statement[j].labelName); /* End of 29-Jul-04 section */ outputToString = 0; fprintf(list2_fp, "%s", printString); let(&printString, ""); } } /* Next stmt - statement number */ /* Decrement date */ if (k > 1) { k--; /* Decrement day */ } else { k = 31; /* Non-existent day 31's will never match, which is OK */ if (l > 1) { l--; /* Decrement month */ } else { l = 12; /* Dec */ m --; /* Decrement year */ } } } /* next while - Scan next date */ /* Discard the input file up to the special "" comment */ while (1) { if (!linput(list1_fp, NULL, &str1)) { print2( "?Error: Could not find \"\" line in input file \"%s\".\n", fullArg[2]); tmpFlag = 1; /* Error flag to recover input file */ break; } if (!strcmp(str1, "")) { fprintf(list2_fp, "%s\n", str1); break; } } if (tmpFlag) goto wrrecent_error; /* Transfer the rest of the input file */ while (1) { if (!linput(list1_fp, NULL, &str1)) { break; } /* Update the date stamp at the bottom of the HTML page. */ /* This is just a nicety; no error check is done. */ if (!strcmp("This page was last updated on ", left(str1, 30))) { let(&str1, cat(left(str1, 30), date(), ".", NULL)); } fprintf(list2_fp, "%s\n", str1); } print2("The %ld most recent theorem(s) were written.\n", n); wrrecent_error: fclose(list1_fp); fclose(list2_fp); if (tmpFlag) { /* Recover input files in case of error */ remove(fullArg[2]); /* Delete output file */ rename(cat(fullArg[2], "~1", NULL), fullArg[2]); /* Restore input file name */ print2("?The file \"%s\" was not modified.\n", 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 <= statements; i++) { if (!statement[i].labelName[0]) continue; /* No label */ if (!m && statement[i].type != (char)p_ && statement[i].type != (char)a_) continue; /* No /ALL switch */ /* 30-Jan-06 nm Added single-character-match wildcard argument */ if (!matchesList(statement[i].labelName, fullArg[2], '*', '?')) { continue; } /* 2-Oct-2015 nm */ let(&str1, cat(str((double)i), " ", statement[i].labelName, " $", chr(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) > 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)," ", statement[i].labelName," $",chr(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(fullArg[2], 1/*startStmt*/, statements + 1 /*maxStmt*/, 1/*aAllowed*/, 1/*pAllowed*/, 1/*eAllowed*/, 1/*fAllowed*/, 0/*efOnlyForMaxStmt*/, 1/*uniqueFlag*/); if (s == -1) { continue; /* Error msg was provided */ } showStatement = s; /* Update for future defaults */ /*********** 14-Sep-2012 replaced by getStatementNum() for (i = 1; i <= statements; i++) { if (!strcmp(fullArg[2],statement[i].labelName)) break; } if (i > statements) { printLongLine(cat("?There is no statement with label \"", fullArg[2], "\". ", "Use SHOW LABELS for a list of valid labels.", NULL), "", " "); showStatement = 0; continue; } showStatement = i; ************** end 14-Sep-2012 *******/ let(&str1, ""); str1 = outputStatement(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 (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 (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 (texDefsRead) { /@ Current limitation - can only read def's from .mm file once @/ if (!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")) == (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 */ htmlFlag = 1; /* 17-Nov-2015 nm */ if (switchPos("/ BRIEF_HTML") || switchPos("/ BRIEF_ALT_HTML")) { if (strcmp(fullArg[2], "*")) { print2( "?For BRIEF_HTML or BRIEF_ALT_HTML, the label must be \"*\"\n"); goto htmlDone; } briefHtmlFlag = 1; } else { briefHtmlFlag = 0; } if (switchPos("/ ALT_HTML") || switchPos("/ BRIEF_ALT_HTML")) { altHtmlFlag = 1; } else { 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, fullArg[2], "*") || briefHtmlFlag) { */ /* obsolete */ if (((char *)(fullArg[2]))[0] == '*' || 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 <= statements; s++) { if (s > 0 && 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 (!statement[s].labelName[0]) continue; /* No label */ /* 30-Jan-06 nm Added single-character-match wildcard argument */ if (!matchesList(statement[s].labelName, fullArg[2], '*', '?')) continue; if (statement[s].type != (char)a_ && statement[s].type != (char)p_) continue; } q = 1; /* Flag that at least one matching statement was found */ if (s > 0) { 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 showStatement is compared to extHtmlStmt in printTexHeader in mmwtex.c */ showStatement = 1; } /*** Open the html file ***/ htmlFlag = 1; /* Open the html output file */ switch (s) { case -2: let(&texFileName, "mmascii.html"); break; case -1: let(&texFileName, "mmtheoremsall.html"); break; case 0: let(&texFileName, "mmdefinitions.html"); break; default: let(&texFileName, cat(statement[showStatement].labelName, ".html", NULL)); } print2("Creating HTML file \"%s\"...\n", texFileName); texFilePtr = fSafeOpen(texFileName, "w", /* 17-Jul-2019 nm */ noVersioning /*noVersioningFlag*/); /****** old code before 17-Jul-2019 ******* if (switchPos("/ NO_VERSIONING") == 0) { texFilePtr = fSafeOpen(texFileName, "w", 0/@noVersioningFlag@/); } else { /@ 6-Jul-2008 nm Added / NO_VERSIONING @/ /@ Don't create the backup versions ~1, ~2,... @/ texFilePtr = fopen(texFileName, "w"); if (!texFilePtr) print2("?Could not open the file \"%s\".\n", texFileName); } ********* end of old code before 17-Jul-2019 *******/ if (!texFilePtr) goto htmlDone; /* Couldn't open it (err msg was provided) */ texFileOpenFlag = 1; printTexHeader((s > 0) ? 1 : 0 /*texHeaderFlag*/); if (!texDefsRead) { /* 9/6/03 If there was an error reading the $t xx.mm statement, 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 = statements + 1; /* To force loop to exit */ goto ABORT_S; /* Go to end of loop where file is closed out */ } if (s <= 0) { outputToString = 1; if (s == -2) { printLongLine(cat("
", "Symbol to ASCII Correspondence for Text-Only Browsers", " (in order of appearance in $c and $v statements", " in the database)", "

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

\n"); print2("\n"); break; case -1: print2("SUMMARY=\"List of theorems\">\n"); break; case 0: print2("SUMMARY=\"List of syntax, axioms and definitions\">\n"); break; } switch (s) { case -2: print2("\n"); m = 0; /* Statement number map */ let(&str3, ""); /* For storing ASCII token list in s=-2 mode */ let(&bgcolor, MINT_BACKGROUND_COLOR); /* 8-Aug-2008 nm Initialize */ for (i = 1; i <= statements; i++) { /* 8-Aug-2008 nm Commented out: */ /* if (i == extHtmlStmt && s != -2) { / * Print a row that identifies the start of the extended database (e.g. Hilbert Space Explorer) * / printLongLine(cat( "", NULL), "", "\""); } */ /* 8-Aug-2008 nm */ if (s != -2 && (i == extHtmlStmt || i == sandboxStmt)) { /* Print a row that identifies the start of the extended database (e.g. Hilbert Space Explorer) or the user sandboxes */ if (i == extHtmlStmt) { let(&bgcolor, PURPLISH_BIBLIO_COLOR); } else { let(&bgcolor, SANDBOX_COLOR); } printLongLine(cat("", NULL), "", "\""); } if (statement[i].type == (char)p_ || statement[i].type == (char)a_ ) m++; if ((s == -1 && statement[i].type != (char)p_) || (s == 0 && statement[i].type != (char)a_) || (s == -2 && statement[i].type != (char)c_ && 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 < statement[i].mathStringLen; j++) { let(&str1, mathToken[(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(mathToken[(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), "&", right(str1, k + 2), NULL)); k = k + 4; } if (str1[k] == '<') { let(&str1, cat(left(str1, k), "<", right(str1, k + 2), NULL)); k = k + 3; } if (str1[k] == '>') { let(&str1, cat(left(str1, k), ">", right(str1, k + 2), NULL)); k = k + 3; } } /* next k */ printLongLine(cat("", NULL), "", "\""); } } /* next j */ /* Close out the string now to prevent memory overflow */ fprintf(texFilePtr, "%s", printString); let(&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(statement[i].reqHypList); for (n = 0; n < j; n++) { if (statement[statement[i].reqHypList[n]].type == (char)e_) { k++; } } */ let(&str1, ""); if (s == 0 || briefHtmlFlag) { let(&str1, ""); /* 18-Sep-03 Get HTML hypotheses => assertion */ str1 = getTexOrHtmlHypAndAssertion(i); /* In mmwtex.c */ let(&str1, cat(str1, "", NULL)); } /* 13-Oct-2006 nm Made some changes to BRIEF_HTML/_ALT_HTML to use its mmtheoremsall.html output for the Palm PDA */ if (briefHtmlFlag) { /* Get page number in mmtheorems*.html of WRITE THEOREMS */ k = ((statement[i].pinkNumber - 1) / THEOREMS_PER_PAGE) + 1; /* Page # */ let(&str2, cat("", NULL)); printLongLine(str1, "", "\""); } /* Close out the string now to prevent overflow */ fprintf(texFilePtr, "%s", printString); let(&printString, ""); break; } /* end switch */ } /* next i (statement number) */ /* print2("
\n"); break; case -1: print2( "
List of Theorems
\n"); break; case 0: printLongLine(cat( /*"
List of Syntax (not |- ), ",*/ /* 2/9/02 (in case |- suppressed) */ "List of Syntax, ", "Axioms (ax-) and", " Definitions (df-)", "
", NULL), "", "\""); break; } switch (s) { case -2: print2("SymbolASCII\n"); break; case -1: print2( "RefDescription\n"); break; case 0: printLongLine(cat( "Ref", "Expression (see link for any distinct variable requirements)", NULL), "", "\""); break; } print2("
", "The list of syntax, axioms (ax-) and definitions (df-) for", " the ", extHtmlTitle, " starts here
", "The list of syntax, axioms (ax-) and definitions (df-) for", " the ", (i == extHtmlStmt) ? extHtmlTitle : /*"User Sandboxes",*/ /* 24-Jul-2009 nm Changed name of sandbox to "mathbox" */ "User Mathboxes", " starts here
", (altHtmlFlag ? cat("", NULL) : ""), /* 14-Jan-2016 nm */ str2, (altHtmlFlag ? "" : ""), /* 14-Jan-2016 nm */ " ", /* 10-Jan-2016 nm This will prevent a -4px shifted image from overlapping the lower border of the table cell */ "", str1, "
", /*"",*/ "", str((double)(statement[i].pinkNumber)), " ", "", statement[i].labelName, "", NULL)); let(&str1, cat(str2, " ", str1, NULL)); } else { /* Get little pink (or rainbow-colored) number */ let(&str4, ""); str4 = pinkHTML(i); let(&str2, cat("
", statement[i].labelName, "", str4, NULL)); let(&str1, cat(str2, "", str1, NULL)); } /* End of 13-Oct-2006 changed section */ print2("\n"); /* New line for HTML source readability */ printLongLine(str1, "", "\""); if (s == 0 || 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(statement[i].mathString, "", "", 0, 0);*/ /*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, "
\n"); */ /* 8/8/03 Removed - already done somewhere else, causing validator.w3.org to fail */ 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(showStatement, 0 /*briefFlag*/, 0 /*commentOnlyFlag*/, 1 /*texFlag*/, /* means latex or html */ 1 /*htmlFlag*/); /* 16-Aug-2016 nm */ if (printTime == 1) { getRunTime(&timeIncr); print2("SHOW STATEMENT run time = %6.2f sec for \"%s\"\n", timeIncr, texFileName); } } /* if s <= 0 */ ABORT_S: /*** Close the html file ***/ printTexTrailer(1 /*texHeaderFlag*/); fclose(texFilePtr); texFileOpenFlag = 0; let(&texFileName,""); } /* next s */ if (!q) { /* No matching statement was found */ printLongLine(cat("?There is no statement whose label matches \"", 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 htmlFlag, altHtmlFlag change prohibition if (!texDefsRead) { htmlFlag = 1; /@ Use HTML, not TeX section @/ altHtmlFlag = 1; /@ Use Unicode, not GIF @/ print2("Reading definitions from $t statement of %s...\n", 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 (!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 (!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 */ htmlFlag = 1; /* Use HTML, not TeX section */ altHtmlFlag = 1; /* Use Unicode, not GIF */ /* readTexDefs() rereads based on changes to htmlFlag, altHtmlFlag */ if (2/*error*/ == readTexDefs(0 /* 1 = check errors only */, 0 /* 1 = no GIF file existence check */ )) { continue; /* An error occurred */ } let(&texFileName,"mnemosyne.txt"); texFilePtr = fSafeOpen(texFileName, "w", 0/*noVersioningFlag*/); if (!texFilePtr) { /* Couldn't open file; error message was provided by fSafeOpen */ continue; } print2("Creating Mnemosyne file \"%s\"...\n", texFileName); for (s = 1; s <= statements; s++) { showStatement = s; /* if (strcmp("|-", mathToken[ (statement[showStatement].mathString)[0]].tokenName)) { subType = SYNTAX; } */ if (!statement[s].labelName[0]) continue; /* No label */ /* 30-Jan-06 nm Added single-character-match wildcard argument */ if (!matchesList(statement[s].labelName, fullArg[2], '*', '?')) continue; if (statement[s].type != (char)a_ && statement[s].type != (char)p_) continue; let(&str1, cat("
", " ", statement[showStatement].labelName, "", "
", NULL)); fprintf(texFilePtr, "%s", str1); let(&str1, cat("",NULL)); fprintf(texFilePtr, "%s", str1); j = nmbrLen(statement[showStatement].reqHypList); for (i = 0; i < j; i++) { k = statement[showStatement].reqHypList[i]; if (statement[k].type != (char)e_ && !(subType == SYNTAX && statement[k].type == (char)f_)) continue; let(&str1, cat("", str1); } let(&str1, "
", statement[k].labelName, "", NULL)); fprintf(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(statement[k].mathString, k/*stmt# for err msgs*/); fprintf(texFilePtr, "%s
"); fprintf(texFilePtr, "%s", str1); let(&str1, "
What is the conclusion?"); fprintf(texFilePtr, "%s\n", str1); let(&str1, ""); fprintf(texFilePtr, "%s", str1); let(&str1, ""); /* Free any previous allocation to str1 */ /* getTexLongMath does not return a temporary allocation */ str1 = getTexLongMath(statement[s].mathString, s); fprintf(texFilePtr, "%s", str1); let(&str1, ""); fprintf(texFilePtr, "%s\n",str1); } /* for(s=1;s j-3) { print2("At least %ld bytes of memory are free.\n",j); } else { print2("%ld bytes of memory are free.\n",i); } continue; } /* 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 <= statements; i++) { if (!strcmp(fullArg[2],statement[i].labelName)) break; } if (i > statements) { printLongLine(cat("?There is no statement with label \"", fullArg[2], "\". ", "Use SHOW LABELS for a list of valid labels.", NULL), "", " "); 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(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, fullArg[i + 1]); } else { let(&matchList, ""); } i = switchPos("/ TO"); if (i != 0) { let(&traceToList, 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 */ showStatement = 0; for (i = 1; i <= statements; i++) { if (statement[i].type != (char)p_) continue; /* Not a $p statement; skip it */ /* Wildcard matching */ if (!matchesList(statement[i].labelName, fullArg[2], '*', '?')) continue; 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(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(showStatement, essentialFlag); } else { traceProof(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(showStatement, essentialFlag, endIndent); } else { if (countStepsFlag) { countSteps(showStatement, essentialFlag); } else { traceProof(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 (showStatement == 0) { printLongLine(cat("?There are no $p labels matching \"", 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 */ } showStatement = 0; for (i = 1; i <= statements; i++) { /* 7-Jan-2008 */ /* 7-Jan-2008 nm Added wildcard handling */ if (!statement[i].labelName[0]) continue; /* No label */ if (!m && statement[i].type != (char)p_ && 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, fullArg[2], "*") || instr(1, fullArg[2], "?"))) continue; /* No /ALL switch and wildcard and not $p, $a */ /* Wildcard matching */ if (!matchesList(statement[i].labelName, fullArg[2], '*', '?')) continue; 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(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 \"", statement[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 \"", statement[showStatement].labelName, str2, " the proof of ", str((double)k), " statement:", NULL), "", " "); } else { printLongLine(cat("Statement \"", statement[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 statement[i] uses showStatement. */ /* Count the number of statements k = # of 'Y' */ k = 0; if (str1[0] == 'Y') { /* There is at least one statement using showStatement */ for (j = showStatement + 1; j <= 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 \"", statement[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 \"", statement[showStatement].labelName, str2, " the proof of ", str((double)k), " statement:", NULL), "", " "); } else { printLongLine(cat("Statement \"", statement[showStatement].labelName, str2, " the proofs of ", str((double)k), " statements:", NULL), "", " "); } } if (k != 0) { let(&str3, " "); /* Line buffer */ for (j = showStatement + 1; j <= 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(statement[j].labelName) > screenWidth) { /* Output and reset the line buffer */ print2("%s\n", str3); let(&str3, " "); } let(&str3, cat(str3, " ", 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 (showStatement == 0) { printLongLine(cat("?There are no labels matching \"", 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(proveStatement, PROOF_DISCOURAGED)) { if (switchPos("/ OVERRIDE") == 0 && 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(fullArg[i + 1]); i = switchPos("/ TO_STEP"); if (i) endStep = (long)val(fullArg[i + 1]); i = switchPos("/ DEPTH"); if (i) endIndent = (long)val(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(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 */ oldTexFlag = 0; if (switchPos("/ OLD_TEX")) oldTexFlag = 1; if (cmdMatches("MIDI")) { /* 8/28/00 */ midiFlag = 1; pipFlag = 0; saveFlag = 0; let(&labelMatch, fullArg[1]); i = switchPos("/ PARAMETER"); /* MIDI only */ if (i) { let(&midiParam, fullArg[i + 1]); } else { let(&midiParam, ""); } } else { midiFlag = 0; if (!pipFlag) let(&labelMatch, fullArg[2]); } if (texFlag) { if (!texFileOpenFlag) { print2( "?You have not opened a %s file. Use the OPEN %s command first.\n", htmlFlag ? "HTML" : "LaTeX", htmlFlag ? "HTML" : "TEX"); continue; } /**** this is now done after outputting print2("The %s source was written to \"%s\".\n", htmlFlag ? "HTML" : "LaTeX", texFileName); */ } i = switchPos("/ DETAILED_STEP"); /* non-pip mode only */ if (i) { detailStep = (long)val(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 <= 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 (statement[stmt].type != (char)p_) continue; /* Not $p */ /* 30-Jan-06 nm Added single-character-match wildcard argument */ if (!matchesList(statement[stmt].labelName, labelMatch, '*', '?')) continue; showStatement = stmt; } q = 1; /* Flag that at least one matching statement was found */ if (detailStep) { /* Show the details of just one step */ showDetailStep(showStatement, detailStep); continue; } if (switchPos("/ STATEMENT_SUMMARY")) { /* non-pip mode only */ /* Just summarize the statements used in the proof */ proofStmtSumm(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(statement[showStatement].proofSectionLen)); memcpy(str1, statement[showStatement].proofSectionPtr, (size_t)(statement[showStatement].proofSectionLen)); n = instr(1, str1, "$."); if (n == 0) { /* The original source truncates the proof before $. */ n = statement[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", statement[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 = showStatement; } else { outStatement = proveStatement; } explicitTargets = (switchPos("/ EXPLICIT") != 0) ? 1 : 0; /* Get the amount to indent the proof by */ indentation = 2 + getSourceIndentation(outStatement); if (!pipFlag) { parseProof(showStatement); /* Prints message if severe error */ if (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(showStatement); */ /* Not necessary */ if (fastFlag) { /* 2-Mar-2016 nm */ /* 2-Mar-2016 nm */ /* Use the proof as is */ nmbrLet(&nmbrSaveProof, wrkProof.proofString); } else { /* Make sure the proof is uncompressed */ nmbrLet(&nmbrSaveProof, nmbrUnsquishProof(wrkProof.proofString)); } } else { nmbrLet(&nmbrSaveProof, 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, /* showStatement or 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 (printString[0]) bug(1114); let(&printString, ""); /* Set flag for print2() to put output in printString instead of displaying it on the screen */ outputToString = 1; } else { if (!print2("Proof of \"%s\":\n", 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 ", 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(statement[outStatement].labelSectionLen)); /* str3 will have the statement's label section w/ comment */ memcpy(str3, statement[outStatement].labelSectionPtr, (size_t)(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 (statement[outStatement].labelSectionChanged == 1) { /* Deallocate old comment if not original source */ let(&str4, ""); /* Deallocate any previous str4 content */ str4 = statement[outStatement].labelSectionPtr; let(&str4, ""); /* Deallocate the old content */ } /* Set flag that this is not the original source */ statement[outStatement].labelSectionChanged = 1; 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 */ 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(statement[outStatement + 1].labelSectionLen)); /* str3 will have the next statement's label section w/ comment */ memcpy(str3, statement[outStatement + 1].labelSectionPtr, (size_t)(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 (statement[outStatement + 1].labelSectionChanged == 1) { /* Deallocate old comment if not original source */ let(&str4, ""); /* Deallocate any previous str4 content */ str4 = 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 */ statement[outStatement + 1].labelSectionChanged = 1; 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 */ 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 "$([])$" and "$( [] )$" @/ /@ 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 "[]" @/ /@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 "$([])$" and "$( [] )$" @/ || 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 ((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 "$". @/ (statement[outStatement + 1].labelSectionPtr)++; (statement[outStatement + 1].labelSectionLen)--; } if (!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) { sourceChanged = 1; 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(&printString, cat(chr(1), "\n", printString, NULL)); if (statement[outStatement].proofSectionPtr[-1] == 1) { /@ Deallocate old proof if not original source @/ let(&str1, ""); /@ Deallocate any previous str1 content @/ str1 = statement[outStatement].proofSectionPtr - 1; let(&str1, ""); /@ Deallocate the proof section @/ } statement[outStatement].proofSectionPtr = 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) @/ statement[outStatement].proofSectionLen = (long)strlen(printString) - 2; /@ Reset printString without deallocating @/ printString = ""; outputToString = 0; **********/ /* 3-May-2017 nm */ /* Add an initial \n which will go after the "$=" and the beginning of the proof */ let(&printString, cat("\n", printString, NULL)); if (statement[outStatement].proofSectionChanged == 1) { /* Deallocate old proof if not original source */ let(&str1, ""); /* Deallocate any previous str1 content */ str1 = statement[outStatement].proofSectionPtr; let(&str1, ""); /* Deallocate the proof section */ } /* Set flag that this is not the original source */ statement[outStatement].proofSectionChanged = 1; if (strcmp(" $.\n", right(printString, (long)strlen(printString) - 3))) { bug(1128); } /* Note that 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. */ statement[outStatement].proofSectionLen = (long)strlen(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 */ statement[outStatement].proofSectionPtr = printString; /* Reset printString without deallocating with let(), since it was assigned to proofSectionPtr */ printString = ""; outputToString = 0; if (!pipFlag) { if (!(fastFlag && !strcmp("*", labelMatch))) { printLongLine( cat("The proof of \"", statement[outStatement].labelName, "\" has been reformatted and saved internally.", NULL), "", " "); } } else { printLongLine(cat("The new proof of \"", 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, 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 \"", 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 = showStatement; } else { outStatement = proveStatement; } if (texFlag) { outputToString = 1; /* Flag for print2 to add to printString */ if (!htmlFlag) { if (!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(statement[outStatement].labelName), "}:", NULL), "", " "); print2("\n"); print2("\n"); } } else { /* htmlFlag */ bug(1118); /*???? The code below is obsolete - now down in show statement*/ /* print2("
\n", MINT_BACKGROUND_COLOR); print2("", NULL), "", "\""); print2( "\n"); */ } outputToString = 0; /* 8/26/99: Obsolete: */ /* printTexLongMath in typeProof will do this fprintf(texFilePtr, "%s", printString); let(&printString, ""); */ /* 8/26/99: printTeXLongMath now clears printString in LaTeX mode before starting its output, so we must put out the printString ourselves here */ fprintf(texFilePtr, "%s", printString); let(&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", statement[outStatement].labelName)) break; /* Break for speedup if user quit */ } } } if (texFlag) print2("Outputting proof of \"%s\"...\n", 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, htmlFlag); if (texFlag) { if (!htmlFlag) { /* 14-Sep-2010 nm */ if (!oldTexFlag) { outputToString = 1; print2("\\end{align}\n"); print2("\\end{proof}\n"); print2("\n"); outputToString = 0; fprintf(texFilePtr, "%s", printString); let(&printString, ""); } else { } } else { /* htmlFlag */ outputToString = 1; print2("
Proof of Theorem ", asciiToTt(statement[outStatement].labelName), "
StepHypRef\n"); print2("Expression
\n"); print2("
\n"); /* print trailer will close out string later */ outputToString = 0; } } /*???CLEAN UP */ /*nmbrLet(&wrkProof.proofString, nmbrSaveProof);*/ /*E*/ if (0) { /* for debugging: */ printLongLine(nmbrCvtRToVString(wrkProof.proofString, /* 25-Jan-2016 nm */ 0, /*explicitTargets*/ 0 /*statemNum, used only if explicitTargets*/)," "," "); print2("\n"); nmbrLet(&nmbrSaveProof, nmbrSquishProof(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,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")) ? fullArg[1] : 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", texFileName); /* 14-Sep-2010 nm Added OLD_TEX */ 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", fullArg[1]); nmbrLet(&nmbrTmp, parseMathTokens(fullArg[1], proveStatement)); for (j = 0; j < 3; j++) { print2("Trying depth %ld\n", j); nmbrTmpPtr = proveFloating(nmbrTmp, proveStatement, j, 0, 0, 1/*overrideFlag*/); 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 fullArg[1] pattern */ i = getStatementNum(fullArg[1], 1/*startStmt*/, 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 */ } proveStatement = i; /* 10-May-2016 nm */ /* 1 means to override usage locks */ overrideFlag = ( (switchPos("/ OVERRIDE")) ? 1 : 0) || globalDiscouragement == 0; if (getMarkupFlag(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 <= statements; i++) { if (!strcmp(fullArg[1],statement[i].labelName)) break; } if (i > statements) { printLongLine(cat("?There is no statement with label \"", fullArg[1], "\". ", "Use SHOW LABELS for a list of valid labels.", NULL), "", " "); proveStatement = 0; continue; } proveStatement = i; if (statement[proveStatement].type != (char)p_) { printLongLine(cat("?Statement \"", fullArg[1], "\" is not a $p statement.", NULL), "", " "); 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", statement[proveStatement].labelName); printLongLine(cat(" $p ", nmbrCvtMToVString( statement[proveStatement].mathString), NULL), " ", " "); */ PFASmode = 1; /* Set mode for commands here and in mmcmdl.c */ /* Note: Proof Assistant mode can equivalently be determined by: nmbrLen(proofInProgress.proof) != 0 */ parseProof(proveStatement); verifyProof(proveStatement); /* Necessary to set RPN stack ptrs before calling cleanWrkProof() */ if (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, wrkProof.proofString); } cleanWrkProof(); /* Deallocate verifyProof storage */ /* 11-Sep-2016 nm */ /* Initialize the structure needed for the Proof Assistant */ initProofStruct(&proofInProgress, nmbrSaveProof, 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(proofInProgress.proof)) bug(1113); /@ Should've been deall.@/ nmbrLet(&proofInProgress.proof, nmbrSaveProof); i = nmbrLen(proofInProgress.proof); pntrLet(&proofInProgress.target, pntrNSpace(i)); pntrLet(&proofInProgress.source, pntrNSpace(i)); pntrLet(&proofInProgress.user, pntrNSpace(i)); nmbrLet((nmbrString @@)(&((proofInProgress.target)[i - 1])), statement[proveStatement].mathString); pipDummyVars = 0; /@ Assign known subproofs @/ assignKnownSubProofs(); /@ Initialize remaining steps @/ for (j = 0; j < i/@proof length@/; j++) { if (!nmbrLen((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", statement[proveStatement].labelName); typeStatement(proveStatement /*showStatement*/, 1 /*briefFlag*/, 0 /*commentOnlyFlag*/, 0 /*texFlag*/, 0 /*htmlFlag*/); if (!nmbrElementIn(1, 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(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 /*htmlFlag*/); /* 6/14/98 end */ } /* 3-May-2016 nm */ if (getMarkupFlag(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(&proofInProgress, PUS_PUSH, "", 0); continue; } /* 1-Nov-2013 nm Added UNDO */ if (cmdMatches("UNDO")) { processUndoStack(&proofInProgress, PUS_UNDO, "", 0); 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(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 /*htmlFlag*/); /* 6/14/98 end */ continue; } /* 1-Nov-2013 nm Added REDO */ if (cmdMatches("REDO")) { processUndoStack(&proofInProgress, PUS_REDO, "", 0); 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(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 /*htmlFlag*/); /* 6/14/98 end */ continue; } if (cmdMatches("UNIFY")) { m = nmbrLen(proofInProgress.proof); /* Original proof length */ proofChangedFlag = 0; if (cmdMatches("UNIFY STEP")) { s = (long)val(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 (proofChangedFlag) { proofChanged = 1; /* Cumulative flag */ processUndoStack(&proofInProgress, PUS_PUSH, fullArgString, 0); } continue; } /* "UNIFY ALL" */ if (!switchPos("/ INTERACTIVE")) { autoUnify(1); if (!proofChangedFlag) { print2("No new unifications were made.\n"); } else { print2( "Steps were unified. SHOW NEW_PROOF / NOT_UNIFIED to see any remaining.\n"); proofChanged = 1; /* Cumulative flag */ processUndoStack(&proofInProgress, PUS_PUSH, 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 */ 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 (!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"); proofChanged = 1; /* Cumulative flag */ processUndoStack(&proofInProgress, PUS_PUSH, 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(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 /*htmlFlag*/); /* 6/14/98 end */ continue; } if (cmdMatches("MATCH")) { maxEssential = -1; /* Default: no maximum */ i = switchPos("/ MAX_ESSENTIAL_HYP"); if (i) maxEssential = (long)val(fullArg[i + 1]); if (cmdMatches("MATCH STEP")) { s = (long)val(fullArg[2]); /* Step number */ m = nmbrLen(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 ((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(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); proofChanged = 1; /* Cumulative flag */ /* 1-Nov-2013 nm Why is proofChanged set unconditionally above? Do we need the processUndoStack() call? */ processUndoStack(&proofInProgress, PUS_PUSH, fullArgString, 0); continue; } /* End if MATCH STEP */ if (cmdMatches("MATCH ALL")) { m = nmbrLen(proofInProgress.proof); /* Original proof length */ k = 0; proofChangedFlag = 0; if (switchPos("/ ESSENTIAL")) { nmbrLet(&nmbrTmp, nmbrGetEssential(proofInProgress.proof)); } for (s = m; s > 0; s--) { /* Match only unknown steps */ if ((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 (proofChangedFlag) { k = s; /* Save earliest step changed */ proofChangedFlag = 0; } print2("\n"); } if (k) { proofChangedFlag = 1; /* Restore it */ proofChanged = 1; /* Cumulative flag */ processUndoStack(&proofInProgress, PUS_PUSH, fullArgString, 0); print2("Steps %ld and above have been renumbered.\n", k); } autoUnify(1); continue; } /* End if MATCH ALL */ } if (cmdMatches("LET")) { errorCount = 0; nmbrLet(&nmbrTmp, parseMathTokens(fullArg[4], proveStatement)); if (errorCount) { /* Parsing issued error message(s) */ errorCount = 0; continue; } if (cmdMatches("LET VARIABLE")) { if (((vstring)(fullArg[2]))[0] != '$') { print2( "?The target variable must be of the form \"$\", e.g. \"$23\".\n"); continue; } n = (long)val(right(fullArg[2], 2)); if (n < 1 || n > pipDummyVars) { print2("?The target variable must be between $1 and $%ld.\n", pipDummyVars); continue; } replaceDummyVar(n, nmbrTmp); autoUnify(1); proofChangedFlag = 1; /* Flag to push 'undo' stack */ proofChanged = 1; /* Cumulative flag */ processUndoStack(&proofInProgress, PUS_PUSH, fullArgString, 0); } if (cmdMatches("LET STEP")) { /* 14-Sep-2012 nm */ s = getStepNum(fullArg[2], proofInProgress.proof, 0 /* ALL not allowed */); if (s == -1) continue; /* Error; message was provided already */ /************** 14-Sep-2012 replaced by getStepNum() s = (long)val(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(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(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] && (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 **)(&((proofInProgress.user)[s - 1])), nmbrTmp); autoUnify(1); proofChangedFlag = 1; /* Flag to push 'undo' stack */ proofChanged = 1; /* Cumulative flag */ processUndoStack(&proofInProgress, PUS_PUSH, fullArgString, 0); } /* 6/14/98 - Automatically display new unknown steps ???Future - add switch to enable/defeat this */ typeProof(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 /*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(fullArg[1], 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) || globalDiscouragement == 0; /****** replaced by getStepNum() nm 14-Sep-2012 offset = 0; /@ 16-Apr-06 @/ let(&str1, fullArg[1]); /@ To avoid void pointer problems with 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(fullArg[1]); /@ Step number @/ if (strcmp(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 fullArg[2] pattern */ k = getStatementNum(fullArg[2], 1/*startStmt*/, 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 <= statements; i++) { if (!strcmp(fullArg[2], statement[i].labelName)) { /@ If a $e or $f, it must be a hypothesis of the statement being proved @/ if (statement[i].type == (char)e_ || statement[i].type == (char)f_){ if (!nmbrElementIn(1, statement[proveStatement].reqHypList, i) && !nmbrElementIn(1, statement[proveStatement].optHypList, i)) continue; } break; } } if (i > statements) { printLongLine(cat("?The statement with label \"", 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 >= 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(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(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] && (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] && (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 ((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", statement[k].labelName, s); continue; } assignStatement(k /*statement#*/, s - 1 /*step*/); n = nmbrLen(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, statement[k].labelName); } else { if (s != m) { printLongLine(cat("Step ", str((double)s), " was assigned statement ", 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 ", 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), "", " "); */ /* 6/14/98 - Automatically display new unknown steps ???Future - add switch to enable/defeat this */ typeProof(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 /*htmlFlag*/); /* 6/14/98 end */ proofChangedFlag = 1; /* Flag to push 'undo' stack (future) */ proofChanged = 1; /* Cumulative flag */ processUndoStack(&proofInProgress, PUS_PUSH, fullArgString, 0); continue; } /* cmdMatches("ASSIGN") */ if (cmdMatches("REPLACE")) { /* s = (long)val(fullArg[1]); obsolete */ /* Step number */ /* 3-May-2016 nm */ /* 1 means to override usage locks */ overrideFlag = ( (switchPos("/ OVERRIDE")) ? 1 : 0) || globalDiscouragement == 0; /* 14-Sep-2012 nm */ step = getStepNum(fullArg[1], 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, 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 fullArg[2] pattern */ stmt = getStatementNum(fullArg[2], 1/*startStmt*/, 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 <= statements; i++) { if (!strcmp(fullArg[2], statement[i].labelName)) { /@ If a $e or $f, it must be a hypothesis of the statement being proved @/ if (statement[i].type == (char)e_ || statement[i].type == (char)f_){ if (!nmbrElementIn(1, statement[proveStatement].reqHypList, i) && !nmbrElementIn(1, statement[proveStatement].optHypList, i)) continue; } break; } } if (i > statements) { printLongLine(cat("?The statement with label \"", 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 >= 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(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 ((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, 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", 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*/, 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 */ ); if (!nmbrLen(nmbrTmpPtr)) { print2( "?Hypotheses of statement \"%s\" do not match known proof steps.\n", statement[stmt].labelName); continue; } /* Get the subproof at step s */ q = subproofLen(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(proofInProgress.proof); for (j = 0; j < i; j++) { if (!nmbrLen((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(proofInProgress.proof); /* New proof length */ if (nmbrElementIn(1, 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, statement[stmt].labelName); } else { if (step != m) { printLongLine(cat("Step ", str((double)step), " was replaced with statement ", 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 ", 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 ********************/ proofChangedFlag = 1; /* Flag to push 'undo' stack */ proofChanged = 1; /* Cumulative flag */ processUndoStack(&proofInProgress, PUS_PUSH, fullArgString, 0); /* 16-Sep-2012 nm */ /* if (dummyVarIsoFlag == 2 && 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 && 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 (proofChangedFlag) typeProof(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 /*htmlFlag*/); /* 14-Sep-2012 end */ continue; } /* REPLACE */ if (cmdMatches("IMPROVE")) { improveDepth = 0; /* Depth */ i = switchPos("/ DEPTH"); if (i) improveDepth = (long)val(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; /* 3-May-2016 nm */ /* 1 means to override usage locks */ overrideFlag = ( (switchPos("/ OVERRIDE")) ? 1 : 0) || globalDiscouragement == 0; /* 14-Sep-2012 nm */ s = getStepNum(fullArg[1], proofInProgress.proof, 1 /* ALL not allowed */); 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 ' to 'IMPROVE ' @/ let(&str1, fullArg[1]); /@ To avoid void pointer problems with 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 \" is obsolete. Use \"IMPROVE \".\n"); continue; } s = (long)val(fullArg[1]); /@ Step number @/ if (strcmp(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(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(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(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] && (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] && (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(proofInProgress.proof, s - 1); nmbrLet(&nmbrTmp, nmbrSeg(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((proofInProgress.target)[s - 1]); i++) { if (((nmbrString @)((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((proofInProgress.target)[s - 1], proveStatement, improveDepth, s - 1, (char)p/*NO_DISTINCT*/, overrideFlag /* 3-May-2016 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(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 */ ); } 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(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 */ proofChanged = 1; /* Cumulative flag */ processUndoStack(&proofInProgress, PUS_PUSH, 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, proofInProgress.proof, -(long)'?')) { print2("The proof is already complete.\n"); continue; } n = 0; /* Earliest step that changed */ 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(proofInProgress.proof); /* Original proof length */ for (s = m; s > 0; s--) { proofStepUnk = ((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((proofInProgress.target)[s - 1], (proofInProgress.source)[s - 1])) continue; } } /* Get the subproof at step s */ q = subproofLen(proofInProgress.proof, s - 1); if (proofStepUnk && q != 1) { bug(1120); /* 25-Aug-2012 nm Consistency check */ } nmbrLet(&nmbrTmp, nmbrSeg(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((proofInProgress.target)[s - 1]); i++) { if (((nmbrString @)((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((proofInProgress.target)[s - 1], proveStatement, improveDepth, s - 1, (char)p/*NO_DISTINCT*/, overrideFlag /* 3-May-2016 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(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 */ ); } 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); proofChangedFlag = 1; s = s - q + 1; /* Adjust step position to account for deleted subpr */ } /* Next step s */ if (proofChangedFlag) { autoUnify(0); /* 0 = No 'Congrats' if done */ } if (!proofChangedFlag && ( (improveAllIter == 2 && !searchUnkSubproofs) || improveAllIter == 3 || searchAlg == 1)) { print2("No new subproofs were found.\n"); break; /* out of improveAllIter loop */ } if (proofChangedFlag) { proofChanged = 1; /* Cumulative flag */ } if (!nmbrElementIn(1, proofInProgress.proof, -(long)'?')) { break; /* Proof is complete */ } if (searchAlg == 1) break; /* Old algorithm does just 1st pass */ } /* Next improveAllIter */ if (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(&proofInProgress, PUS_PUSH, fullArgString, 0); } if (!nmbrElementIn(1, 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 (proofChangedFlag) typeProof(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 /*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, fullArg[1], "*") || instr(1, 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, fullArg[allowNewAxiomsMatchPos + 1]); } else { let(&allowNewAxiomsMatchList, ""); } /* 20-May-2013 nm */ noNewAxiomsMatchPos = switchPos("/ NO_NEW_AXIOMS_FROM"); if (noNewAxiomsMatchPos != 0) { let(&noNewAxiomsMatchList, fullArg[noNewAxiomsMatchPos + 1]); } else { let(&noNewAxiomsMatchList, ""); } /* 20-May-2013 nm */ forbidMatchPos = switchPos("/ FORBID"); if (forbidMatchPos != 0) { let(&forbidMatchList, 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 @/ */ if (sandboxStmt == 0) { /* Look up "mathbox" label if it hasn't been */ sandboxStmt = lookupLabel("mathbox"); if (sandboxStmt == -1) sandboxStmt = 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) || 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 */ hasWildCard = (instr(1, fullArg[1], "*") || instr(1, fullArg[1], "?") || instr(1, fullArg[1], ",") || instr(1, fullArg[1], "~") /* 3-May-2014 nm label~label range */ ); proofChangedFlag = 0; /* Added 14-Aug-2012 nm */ /* Always scan statements in current mathbox, even if "/ INCLUDE_MATHBOXES" is omitted */ thisMathboxStmt = sandboxStmt; /* Will become start of current (proveStatement's) mathbox */ if (proveStatement > sandboxStmt) { /* We're in a mathbox */ for (k = proveStatement; k >= sandboxStmt; k--) { let(&str1, left(statement[k].labelSectionPtr, statement[k].labelSectionLen)); /* Heuristic to match beginning of mathbox */ if (instr(1, str1, "Mathbox for") != 0) { /* Found beginning of current mathbox */ thisMathboxStmt = k; break; } } } /* 25-Jun-2014 nm */ copyProofStruct(&saveOrigProof, 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, proofInProgress.proof); /* Redundant? */ nmbrLet(&nmbrSaveProof, nmbrSquishProof(proofInProgress.proof)); /* We only care about length; str1 will be discarded */ let(&str1, compressProof(nmbrSaveProof, 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 (!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, proofInProgress); forwardLength = nmbrLen(proofInProgress.proof); forwardCompressedLength = oldCompressedLength; /* Start over from original proof */ copyProofStruct(&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, proofInProgress); } */ /* 25-Jun-2014 nm */ copyProofStruct(&saveProofForReverting, proofInProgress); oldCompressedLength = origCompressedLength; /* for (k = 1; k < proveStatement; k++) { */ /* 10-Nov-2011 nm */ /* We use bottom-up scanning as the default (forwFlag=0) since empirically it seems to lead to shorter proofs */ /* If forwFlag is 0, scan from proveStatement-1 to 1 If forwFlag is 1, scan from 1 to proveStatement-1 */ for (k = forwFlag ? 1 : (proveStatement - 1); k * (forwFlag ? 1 : -1) < (forwFlag ? proveStatement : 0); k = k + (forwFlag ? 1 : -1)) { /* 28-Jun-2011 */ /* Scan mathbox statements only if INCLUDE_MATHBOXES specified */ /*if (!mathboxFlag && k >= sandboxStmt) continue;*/ /* 14-Aug-2012 nm */ if (!mathboxFlag && k >= sandboxStmt && k < thisMathboxStmt) continue; if (statement[k].type != (char)p_ && statement[k].type != (char)a_) continue; /* 30-Jan-06 nm Added single-character-match wildcard argument */ if (!matchesList(statement[k].labelName, 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(statement[k].reqDisjVarsA)) { /@ 30-Jan-06 nm Added single-character-match wildcard argument @/ if (!(instr(1, fullArg[1], "@") || instr(1, fullArg[1], "?"))) print2("?\"%s\" has a $d requirement\n", 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(statement[k].labelName, 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(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(statement[k].labelName) + 1; if (q > 72) { q = (long)strlen(statement[k].labelName) + 1; print2("\n"); } print2("%s ",statement[k].labelName); } */ m = nmbrLen(proofInProgress.proof); /* Original proof length */ nmbrLet(&nmbrTmp, proofInProgress.proof); minimizeProof(k /* trial statement */, proveStatement /* statement being proved in MM-PA */, (char)mayGrowFlag /* mayGrowFlag */); n = nmbrLen(proofInProgress.proof); /* New proof length */ if (!nmbrEq(nmbrTmp, 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 (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(&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. So 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 */ nmbrLet(&nmbrSaveProof, proofInProgress.proof); nmbrLet(&nmbrSaveProof, nmbrSquishProof(proofInProgress.proof)); let(&str1, compressProof(nmbrSaveProof, proveStatement, /* statement being proved in MM-PA */ 0 /* Normal (not "fast") compression */ )); saveZappedProofSectionPtr = statement[proveStatement].proofSectionPtr; saveZappedProofSectionLen = statement[proveStatement].proofSectionLen; saveZappedProofSectionChanged = statement[proveStatement].proofSectionChanged; /* Set flag that this is not the original source */ statement[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 */ statement[proveStatement].proofSectionLen = (long)strlen(str1) - 2; /* We don't deallocate previous proofSectionPtr content because we will recover it after the verifyProof() */ statement[proveStatement].proofSectionPtr = str1; /******** end of 29-Nov-2019 nm ************/ traceProofWork(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 */ statement[proveStatement].proofSectionPtr = saveZappedProofSectionPtr; statement[proveStatement].proofSectionLen = saveZappedProofSectionLen; statement[proveStatement].proofSectionChanged = saveZappedProofSectionChanged; /* 16-Jun-2017 nm */ /******** end of 29-Nov-2019 nm ************/ } let(&traceTrialFlags, ""); traceProofWork(k, 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 < proveStatement; i++) { if (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(statement[i].labelName, allowNewAxiomsMatchList, '*', '?') == 1 && matchesList(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(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(&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(statement[k].reqDisjVarsA) || !mayGrowFlag) { nmbrLet(&nmbrSaveProof, proofInProgress.proof); nmbrLet(&nmbrSaveProof, nmbrSquishProof(proofInProgress.proof)); let(&str1, compressProof(nmbrSaveProof, 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", statement[k].labelName, m, n ); print2( " but compressed size: old = %ld bytes, new = %ld bytes\n", oldCompressedLength, newCompressedLength); } copyProofStruct(&proofInProgress, saveProofForReverting); /* Skip further printout and flag setting */ continue; /* Continue at 'Next k' loop end below */ } } /* if (nmbrLen(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(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 = statement[proveStatement].proofSectionPtr; saveZappedProofSectionLen = statement[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)); statement[proveStatement].proofSectionPtr = str1 + 1; /@ Compressed proof generated above @/ statement[proveStatement].proofSectionLen = newCompressedLength + 4; *******/ /******** start of 16-Jun-2017 nm ************/ saveZappedProofSectionChanged = statement[proveStatement].proofSectionChanged; /* Set flag that this is not the original source */ statement[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 */ statement[proveStatement].proofSectionLen = (long)strlen(str1) - 2; /* We don't deallocate previous proofSectionPtr content because we will recover it after the verifyProof() */ statement[proveStatement].proofSectionPtr = str1; /******** end of 16-Jun-2017 nm ************/ outputToString = 1; /* Suppress error messages */ /* i = parseProof(proveStatement); */ /* if (i != 0) bug(1121); */ /* i = verifyProof(proveStatement); */ /* if (i != 0) bug(1122); */ /* 15-Apr-2015 nm parseProof, verifyProof, cleanWkrProof must be called in sequence to assign the wrkProof structure, verify the proof, and deallocate the wrkProof structure. Either none of them or all of them must be called. */ parseProof(proveStatement); verifyProof(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 = (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, printString, "There is a disjoint variable ($d) violation"); outputToString = 0; /* Restore to normal output */ let(&printString, ""); /* Clear out the stored error messages */ cleanWrkProof(); /* Deallocate verifyProof storage */ statement[proveStatement].proofSectionPtr = saveZappedProofSectionPtr; statement[proveStatement].proofSectionLen = saveZappedProofSectionLen; statement[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(&proofInProgress, saveProofForReverting); /* Skip further printout and flag setting */ continue; /* Continue at 'Next k' loop end below */ } } /* if (nmbrLen(statement[k].reqDisjVarsA)) */ /* 25-Jun-2014 nm - not needed since trials now suppressed */ /* if (verboseMode) { print2("\n"); } */ /*if (nmbrLen(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", 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", statement[proveStatement].labelName, oldCompressedLength, newCompressedLength, statement[k].labelName); } else { if (newCompressedLength > oldCompressedLength) bug(1123); print2( "Proof of \"%s\" stayed at %ld bytes using \"%s\".\n", statement[proveStatement].labelName, oldCompressedLength, 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 ? "" : " "), statement[proveStatement].labelName, m, n, statement[k].labelName); } /* MAY_GROW possibility */ if (m < n) print2( "Proof of \"%s\" increased from %ld to %ld steps using \"%s\".\n", statement[proveStatement].labelName, m, n, statement[k].labelName); /* MAY_GROW possibility */ if (m == n) print2( "Proof of \"%s\" remained at %ld steps using \"%s\".\n", statement[proveStatement].labelName, m, statement[k].labelName); /* Distinct variable warning (obsolete) */ /* if (nmbrLen(statement[k].reqDisjVarsA)) { printLongLine(cat("Note: \"", 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 */ prntStatus = 2; /* Found one */ proofChangedFlag = 1; /* 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, proofInProgress); } */ /* 25-Jun-2014 nm */ /* Save the changed proof in case we have to restore it later */ copyProofStruct(&saveProofForReverting, proofInProgress); } } /* Next k (statement) */ /* 25-Jun-2014 nm - not needed since trials now suppressed */ /* if (verboseMode) { if (prntStatus) print2("\n"); } */ if (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(proofInProgress.proof)); } if (oldCompressedLength < forwardCompressedLength || (oldCompressedLength == forwardCompressedLength && nmbrLen(proofInProgress.proof) < forwardLength)) { /* The reverse pass was better */ print2("The backward scan results were used.\n"); } else { copyProofStruct(&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 */ 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, fullArg[1], "@") || instr(1, fullArg[1], "?")) print2("?No earlier $p or $a label (without $d) matches \"%s\".\n", fullArg[1]); } */ /* 28-Jun-2011 nm */ if (!mathboxFlag && proveStatement >= sandboxStmt) { 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, statement[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 (proofChangedFlag) { proofChanged = 1; /* Cumulative flag */ processUndoStack(&proofInProgress, PUS_PUSH, fullArgString, 0); } continue; } /* End if MINIMIZE_WITH */ /* 11-Sep-2016 nm Added EXPAND command */ if (cmdMatches("EXPAND")) { proofChangedFlag = 0; nmbrLet(&nmbrSaveProof, proofInProgress.proof); s = compressedProofSize(nmbrSaveProof, proveStatement); for (i = proveStatement - 1; i >= 1; i--) { if (statement[i].type != (char)p_) continue; /* Not a $p */ /* 30-Jan-06 nm Added single-character-match wildcard argument */ if (!matchesList(statement[i].labelName, fullArg[1], '*', '?')) { continue; } sourceStatement = i; nmbrTmp = expandProof(nmbrSaveProof, sourceStatement /*, proveStatement*/); if (!nmbrEq(nmbrTmp, nmbrSaveProof)) { proofChangedFlag = 1; n = compressedProofSize(nmbrTmp, proveStatement); printLongLine(cat("Proof of \"", statement[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 \"", statement[sourceStatement].labelName, "\".", NULL), " ", " "); s = n; nmbrLet(&nmbrSaveProof, nmbrTmp); } } if (proofChangedFlag) { proofChanged = 1; /* Cumulative flag */ /* Clear the existing proof structure */ deallocProofStruct(&proofInProgress); /* Then rebuild proof structure from new proof nmbrTmp */ initProofStruct(&proofInProgress, nmbrTmp, proveStatement); /* Save the new proof structure on the undo stack */ processUndoStack(&proofInProgress, PUS_PUSH, 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(fullArg[2]); /* Step number */ } else { s = nmbrLen(proofInProgress.proof); } if ((proofInProgress.proof)[s - 1] == -(long)'?') { print2("?Step %ld is unknown and cannot be deleted.\n", s); continue; } m = nmbrLen(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(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(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 /*htmlFlag*/); /* 6/14/98 end */ proofChanged = 1; /* Cumulative flag */ processUndoStack(&proofInProgress, PUS_PUSH, fullArgString, 0); continue; } if (cmdMatches("DELETE FLOATING_HYPOTHESES")) { /* Get the essential step flags */ nmbrLet(&nmbrTmp, nmbrGetEssential(proofInProgress.proof)); m = nmbrLen(proofInProgress.proof); /* Original proof length */ n = 0; /* Earliest step that changed */ proofChangedFlag = 0; for (s = m; s > 0; s--) { /* Skip essential steps and unknown steps */ if (nmbrTmp[s - 1] == 1) continue; /* Not floating */ if ((proofInProgress.proof)[s - 1] == -(long)'?') continue; /* Unknown */ /* Get the subproof length at step s */ q = subproofLen(proofInProgress.proof, s - 1); deleteSubProof(s - 1); n = s - q + 1; /* Save earliest step changed */ proofChangedFlag = 1; s = s - q + 1; /* Adjust step position to account for deleted subpr */ } /* Next step s */ if (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(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 /*htmlFlag*/); /* 6/14/98 end */ proofChanged = 1; /* Cumulative flag */ processUndoStack(&proofInProgress, PUS_PUSH, 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(proofInProgress.proof); /* Reset the dummy variable counter (all will be refreshed) */ pipDummyVars = 0; /* Initialize all steps */ for (j = 0; j < i; j++) { initStep(j); } /* Assign known subproofs */ assignKnownSubProofs(); print2("All steps have been initialized.\n"); proofChanged = 1; /* Cumulative flag */ processUndoStack(&proofInProgress, PUS_PUSH, fullArgString, 0); continue; } /* Added 16-Apr-06 nm */ if (cmdMatches("INITIALIZE USER")) { i = nmbrLen(proofInProgress.proof); /* Delete all LET STEP assignments */ for (j = 0; j < i; j++) { nmbrLet((nmbrString **)(&((proofInProgress.user)[j])), NULL_NMBRSTRING); } print2( "All LET STEP user assignments have been initialized (i.e. deleted).\n"); proofChanged = 1; /* Cumulative flag */ processUndoStack(&proofInProgress, PUS_PUSH, fullArgString, 0); continue; } /* End 16-Apr-06 */ /* cmdMatches("INITIALIZE STEP") */ s = (long)val(fullArg[2]); /* Step number */ if (s > nmbrLen(proofInProgress.proof) || s < 1) { print2("?The step must be in the range from 1 to %ld.\n", nmbrLen(proofInProgress.proof)); continue; } initStep(s - 1); /* Also delete LET STEPs, per HELP INITIALIZE */ /* 16-Apr-06 */ nmbrLet((nmbrString **)(&((proofInProgress.user)[s - 1])), /* 16-Apr-06 */ NULL_NMBRSTRING); /* 16-Apr-06 */ print2( "Step %ld and its hypotheses have been initialized.\n", s); proofChanged = 1; /* Cumulative flag */ processUndoStack(&proofInProgress, PUS_PUSH, 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, 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 <= statements; i++) { if (!statement[i].labelName[0]) continue; /* No label */ if (!m && statement[i].type != (char)p_ && statement[i].type != (char)a_) { continue; /* No /ALL switch */ } /* 30-Jan-06 nm Added single-character-match wildcard argument */ if (!matchesList(statement[i].labelName, 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 = screenWidth - 7 - (long)strlen(str((double)i)) - (long)strlen(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), " ", statement[i].labelName, " $", chr(statement[i].type), " \"", str3, "\"", NULL)); let(&str2, ""); } else { /* No COMMENTS switch */ let(&str2,nmbrCvtMToVString(statement[i].mathString)); /* 14-Apr-2008 nm JOIN flag */ tmpFlag = 0; /* Flag that $p or $a is already in string */ if (joinFlag && (statement[i].type == (char)p_ || statement[i].type == (char)a_)) { /* If $a or $p, prepend $e's to string to match */ k = nmbrLen(statement[i].reqHypList); for (j = k - 1; j >= 0; j--) { p = statement[i].reqHypList[j]; if (statement[p].type == (char)e_) { let(&str2, cat("$e ", nmbrCvtMToVString(statement[p].mathString), tmpFlag ? "" : cat(" $", chr(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)," ", statement[i].labelName, tmpFlag ? "" : cat(" $", chr(statement[i].type), NULL), " ", str2, NULL), " ", " "); } /* End no COMMENTS switch */ } /* Next i */ continue; } if (cmdMatches("SET ECHO")) { if (cmdMatches("SET ECHO ON")) { 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 { 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"); memoryStatus = 1; } else { 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"); hentyFilter = 1; } else { print2("This command is intended for debugging purposes only.\n"); print2("The unification equivalence filter has been turned off.\n"); hentyFilter = 0; } continue; } if (cmdMatches("SET EMPTY_SUBSTITUTION")) { if (cmdMatches("SET EMPTY_SUBSTITUTION ON")) { minSubstLen = 0; print2("Substitutions with empty symbol sequences is now allowed.\n"); continue; } if (cmdMatches("SET EMPTY_SUBSTITUTION OFF")) { 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(fullArg[2]); /* Timeout value */ print2("IMPROVE search limit has been changed from %ld to %ld\n", userMaxProveFloat, s); userMaxProveFloat = s; continue; } if (cmdMatches("SET WIDTH")) { /* 18-Nov-85 nm Was SCREEN_WIDTH */ s = (long)val(fullArg[2]); /* Screen width value */ 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 = screenWidth; 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(fullArg[2]); /* Screen height value */ if (s < 2) s = 2; /* Less than 2 makes no sense */ i = screenHeight; screenHeight = s - 1; print2("Screen height has been changed from %ld to %ld.\n", i + 1, s); /* 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(fullArg[2], "ON")) { globalDiscouragement = 1; print2("\"(...is discouraged.)\" markup tags are now honored.\n"); } else if (!strcmp(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 */ 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", contributorName, fullArg[2]); let(&contributorName, fullArg[2]); continue; } /* 31-Dec-2017 nm */ if (cmdMatches("SET ROOT_DIRECTORY")) { let(&str1, rootDirectory); /* Save previous one */ let(&rootDirectory, edit(fullArg[2], 2/*discard spaces,tabs*/)); if (rootDirectory[0] != 0) { /* Not an empty directory path */ /* Add trailing "/" to rootDirectory if missing */ if (instr(1, rootDirectory, "\\") != 0 || instr(1, input_fn, "\\") != 0 || instr(1, output_fn, "\\") != 0 ) { /* Using Windows-style path (not really supported, but at least make full path consistent) */ if (rootDirectory[strlen(rootDirectory) - 1] != '\\') { let(&rootDirectory, cat(rootDirectory, "\\", NULL)); } } else { if (rootDirectory[strlen(rootDirectory) - 1] != '/') { let(&rootDirectory, cat(rootDirectory, "/", NULL)); } } } if (strcmp(str1, rootDirectory)){ print2("Root directory was changed from \"%s\" to \"%s\"\n", str1, rootDirectory); } let(&str1, ""); continue; } /* 1-Nov-2013 nm Added UNDO */ if (cmdMatches("SET UNDO")) { s = (long)val(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 (PFASmode == 1) { /* If we're in the Proof Assistant, assign the first stack entry with the current proof (the stack was erased) */ processUndoStack(&proofInProgress, PUS_PUSH, "", 0); } } else { print2("The maximum number of UNDOs was not changed.\n"); } continue; } if (cmdMatches("SET UNIFICATION_TIMEOUT")) { s = (long)val(fullArg[2]); /* Timeout value */ print2("Unification timeout has been changed from %ld to %ld\n", userMaxUnifTrials,s); userMaxUnifTrials = s; continue; } if (cmdMatches("OPEN LOG")) { /* Open a log file */ let(&logFileName, fullArg[2]); logFilePtr = fSafeOpen(logFileName, "w", 0/*noVersioningFlag*/); if (!logFilePtr) continue; /* Couldn't open it (err msg was provided) */ logFileOpenFlag = 1; print2("The log file \"%s\" was opened %s %s.\n",logFileName, date(),time_()); continue; } if (cmdMatches("CLOSE LOG")) { /* Close the log file */ if (!logFileOpenFlag) { print2("?Sorry, there is no log file currently open.\n"); } else { print2("The log file \"%s\" was closed %s %s.\n",logFileName, date(),time_()); fclose(logFilePtr); logFileOpenFlag = 0; } let(&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 texFileOpenFlag when switching to HTML & close LaTeX file) */ if (texDefsRead) { /* Current limitation - can only read .def once */ /* 2-Oct-2017 nm OPEN HTML is obsolete */ /*if (cmdMatches("OPEN HTML") != htmlFlag) {*/ if (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 */ /*htmlFlag = cmdMatches("OPEN HTML");*/ /* Open a TeX file */ let(&texFileName,fullArg[2]); if (switchPos("/ NO_HEADER")) { texHeaderFlag = 0; } else { texHeaderFlag = 1; } /* 14-Sep-2010 nm Added OLD_TEX */ if (switchPos("/ OLD_TEX")) { oldTexFlag = 1; } else { oldTexFlag = 0; } texFilePtr = fSafeOpen(texFileName, "w", 0/*noVersioningFlag*/); if (!texFilePtr) continue; /* Couldn't open it (err msg was provided) */ texFileOpenFlag = 1; /* 2-Oct-2017 nm OPEN HTML is obsolete */ print2("Created %s output file \"%s\".\n", htmlFlag ? "HTML" : "LaTeX", texFileName); printTexHeader(texHeaderFlag); 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 (!texFileOpenFlag) { print2("?Sorry, there is no %s file currently open.\n", htmlFlag ? "HTML" : "LaTeX"); } else { print2("The %s output file \"%s\" has been closed.\n", htmlFlag ? "HTML" : "LaTeX", texFileName); printTexTrailer(texHeaderFlag); fclose(texFilePtr); texFileOpenFlag = 0; } let(&texFileName,""); continue; } *****/ if (cmdMatches("CLOSE TEX")) { /* Close the TeX file */ if (!texFileOpenFlag) { print2("?Sorry, there is no LaTeX file currently open.\n"); } else { print2("The LaTeX output file \"%s\" has been closed.\n", texFileName); printTexTrailer(texHeaderFlag); fclose(texFilePtr); texFileOpenFlag = 0; } let(&texFileName,""); continue; } /* Similar to Unix 'more' */ if (cmdMatches("MORE")) { list1_fp = fSafeOpen(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(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(fullArg[i + 1]); i = switchPos("/ TO_LINE"); if (i) toLine = (long)val(fullArg[i + 1]); i = switchPos("/ WINDOW"); if (i) searchWindow = (long)val(fullArg[i + 1]); /*??? Implement SEARCH /WINDOW */ if (i) print2("Sorry, WINDOW has not be implemented yet.\n"); let(&str2, 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, fullArg[2]); } else { print2("There were %ld matching lines in the file %s.\n", m, 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(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 (sourceChanged) { print2("Warning: You have not saved changes to the source.\n"); str1 = cmdInput1("Do you want to ERASE anyway (Y, N) ? "); if (str1[0] != 'y' && str1[0] != 'Y') { print2("Use WRITE SOURCE to save the changes.\n"); continue; } sourceChanged = 0; } eraseSource(); sourceHasBeenRead = 0; /* Global variable */ /* 31-Dec-2017 nm */ showStatement = 0; proveStatement = 0; print2("Metamath has been reset to the starting state.\n"); continue; } if (cmdMatches("VERIFY PROOF")) { if (switchPos("/ SYNTAX_ONLY")) { verifyProofs(fullArg[2],0); /* Parse only */ } else { verifyProofs(fullArg[2],1); /* Parse and verify */ } continue; } /* 7-Nov-2015 nm Added */ /* 17-Nov-2015 nm Updated */ if (cmdMatches("VERIFY MARKUP")) { i = (switchPos("/ DATE_SKIP") != 0) ? 1 : 0; m = (switchPos("/ TOP_DATE_SKIP") != 0) ? 1 : 0; j = (switchPos("/ FILE_SKIP") != 0) ? 1 : 0; k = (switchPos("/ VERBOSE") != 0) ? 1 : 0; if (i == 1 && m == 1) { printf( "?Only one of / DATE_SKIP and / TOP_DATE_SKIP may be specified.\n"); continue; } verifyMarkup(fullArg[2], (flag)i, /* 1 = skip checking date consistency */ (flag)m, /* 1 = skip checking top date only */ (flag)j, /* 1 = skip checking external files GIF, mmset.html,... */ (flag)k); /* 1 = verbose mode */ /* 26-Dec-2016 nm */ continue; } /* 10-Dec-2018 nm Added */ if (cmdMatches("MARKUP")) { htmlFlag = 1; 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(fullArg[1], /* Input file */ fullArg[2], /* Output file */ (switchPos("/ CSS") != 0), i); /* Action bits */ continue; } print2("?This command has not been implemented.\n"); continue; } } /* command */ metamath-exe-master/mmcmdl.c000066400000000000000000002356421357377637100164020ustar00rootroot00000000000000/*****************************************************************************/ /* Copyright (C) 2019 NORMAN MEGILL nm at alum.mit.edu */ /* License terms: GNU General Public License */ /*****************************************************************************/ /*34567890123456 (79-character line to adjust editor window) 2345678901234567*/ /* Command line syntax specification for Metamath */ #include #include #include #include #include #include #include "mmvstr.h" #include "mmdata.h" #include "mmcmdl.h" #include "mminou.h" #include "mmpfas.h" #include "mmunif.h" /* For hentyFilter, userMaxUnifTrials, minSubstLen */ #include "mmwtex.h" #include "mmword.h" /* Global variables */ pntrString *rawArgPntr = NULL_PNTRSTRING; nmbrString *rawArgNmbr = NULL_NMBRSTRING; long rawArgs = 0; pntrString *fullArg = NULL_PNTRSTRING; vstring fullArgString = ""; /* 1-Nov-2013 nm fullArg as one string */ vstring commandPrompt = ""; vstring commandLine = ""; long showStatement = 0; vstring logFileName = ""; vstring texFileName = ""; flag PFASmode = 0; /* Proof assistant mode, invoked by PROVE command */ flag queryMode = 0; /* If 1, explicit questions will be asked even if a field in the input command line is optional */ flag sourceChanged = 0; /* Flag that user made some change to the source file*/ flag proofChanged = 0; /* Flag that user made some change to proof in progress*/ flag commandEcho = 0; /* Echo full command */ flag memoryStatus = 0; /* Always show memory */ /* 31-Dec-2017 nm */ flag sourceHasBeenRead = 0; /* 1 if a source file has been read in */ /* 31-Dec-2017 nm */ vstring rootDirectory = ""; /* Directory prefix to use for included files */ flag processCommandLine(void) { vstring defaultArg = ""; vstring tmpStr = ""; long i; queryMode = 0; /* If 1, explicit questions will be asked even if a field is optional */ pntrLet(&fullArg, NULL_PNTRSTRING); if (!toolsMode) { if (!PFASmode) { /* Normal mode */ let(&tmpStr, cat("DBG|", "HELP|READ|WRITE|PROVE|SHOW|SEARCH|SAVE|SUBMIT|OPEN|CLOSE|", /* 10-Dec-2018 nm Added MARKUP */ "SET|FILE|BEEP|EXIT|QUIT|ERASE|VERIFY|MARKUP|MORE|TOOLS|", "MIDI|", NULL)); } else { /* Proof assistant mode */ let(&tmpStr, cat("DBG|", "HELP|WRITE|SHOW|SEARCH|SAVE|SUBMIT|OPEN|CLOSE|", /* 9-Jun-2016 nm Added _EXIT_PA */ "SET|FILE|BEEP|EXIT|_EXIT_PA|QUIT|VERIFY|INITIALIZE|ASSIGN|REPLACE|", /* 11-Sep-2016 nm Added EXPAND */ "LET|UNIFY|IMPROVE|MINIMIZE_WITH|EXPAND|MATCH|DELETE|UNDO|REDO|", /* 10-Dec-2018 nm Added MARKUP */ "MARKUP|MORE|TOOLS|MIDI|", NULL)); } if (!getFullArg(0,tmpStr)) { goto pclbad; } if (cmdMatches("HELP")) { /* 15-Jan-2018 nm Added MARKUP */ if (!getFullArg(1, cat("LANGUAGE|PROOF_ASSISTANT|MM-PA|", "BEEP|EXIT|QUIT|READ|ERASE|", "OPEN|CLOSE|SHOW|SEARCH|SET|VERIFY|SUBMIT|SYSTEM|PROVE|FILE|WRITE|", /* 10-Dec-2018 nm Added MARKUP */ "MARKUP|ASSIGN|REPLACE|MATCH|UNIFY|LET|INITIALIZE|DELETE|IMPROVE|", /* 11-Sep-2016 nm Added EXPAND */ "MINIMIZE_WITH|EXPAND|UNDO|REDO|SAVE|DEMO|INVOKE|CLI|EXPLORE|TEX|", "LATEX|HTML|COMMENTS|MORE|", "TOOLS|MIDI|$|<$>", NULL))) goto pclbad; if (cmdMatches("HELP OPEN")) { /*if (!getFullArg(2, "LOG|TEX|HTML|")) goto pclbad;*/ /* 2-Oct-2017 nm Removed HTML */ if (!getFullArg(2, "LOG|TEX|")) goto pclbad; goto pclgood; } if (cmdMatches("HELP CLOSE")) { /*if (!getFullArg(2, "LOG|TEX|HTML|")) goto pclbad;*/ /* 2-Oct-2017 nm Removed HTML */ if (!getFullArg(2, "LOG|TEX|")) goto pclbad; goto pclgood; } if (cmdMatches("HELP SHOW")) { if (!getFullArg(2, cat("MEMORY|SETTINGS|LABELS|SOURCE|STATEMENT|", "PROOF|NEW_PROOF|USAGE|TRACE_BACK|ELAPSED_TIME|", "DISCOURAGED|", NULL))) goto pclbad; goto pclgood; } if (cmdMatches("HELP SET")) { if (!getFullArg(2, cat( "ECHO|SCROLL|WIDTH|HEIGHT|UNDO|UNIFICATION_TIMEOUT|", "DISCOURAGEMENT|", "CONTRIBUTOR|", /* 14-May-2017 nm */ "ROOT_DIRECTORY|", /* 31-Dec-2017 nm */ "EMPTY_SUBSTITUTION|SEARCH_LIMIT|JEREMY_HENTY_FILTER|", NULL))) goto pclbad; goto pclgood; } if (cmdMatches("HELP VERIFY")) { if (!getFullArg(2, "PROOF|MARKUP|")) goto pclbad; goto pclgood; } if (cmdMatches("HELP WRITE")) { if (!getFullArg(2, "SOURCE|THEOREM_LIST|BIBLIOGRAPHY|RECENT_ADDITIONS|")) goto pclbad; goto pclgood; } if (cmdMatches("HELP FILE")) { if (!getFullArg(2, "SEARCH")) goto pclbad; goto pclgood; } if (cmdMatches("HELP SAVE")) { if (!getFullArg(2, "PROOF|NEW_PROOF|")) goto pclbad; goto pclgood; } goto pclgood; } if (cmdMatches("READ")) { if (!getFullArg(1, "& What is the name of the source input file? ")) goto pclbad; /* Get any switches */ i = 1; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, "VERIFY|")) goto pclbad; } else { break; } break; /* Break if only 1 switch is allowed */ } /* End while for switch loop */ goto pclgood; } if (cmdMatches("WRITE")) { if (!getFullArg(1, "SOURCE|THEOREM_LIST|BIBLIOGRAPHY|RECENT_ADDITIONS|")) goto pclbad; if (cmdMatches("WRITE SOURCE")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } if (!getFullArg(2, cat( "* What is the name of the source output file <", input_fn, ">? ", NULL))) goto pclbad; if (!strcmp(input_fn, fullArg[2])) { print2( "The input file will be renamed %s~1.\n", input_fn); } /* Get any switches */ i = 2; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( /* 3-May-2017 nm Removed CLEAN */ "FORMAT|REWRAP", /* 31-Dec-2017 nm Added SPLIT, NO_VERSIONING, KEEP_INCLUDES */ "|SPLIT|NO_VERSIONING|KEEP_INCLUDES", "|", NULL))) goto pclbad; } else { break; } /* break; */ /* Break if only 1 switch is allowed */ } /* End while for switch loop */ goto pclgood; } if (cmdMatches("WRITE THEOREM_LIST")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } /* Get any switches */ i = 1; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "THEOREMS_PER_PAGE|SHOW_LEMMAS|HTML|ALT_HTML|NO_VERSIONING", "|", NULL))) goto pclbad; if (lastArgMatches("THEOREMS_PER_PAGE")) { i++; if (!getFullArg(i, "# How many theorems per page <100>? ")) goto pclbad; } } else { break; } /* break; */ /* Break if only 1 switch is allowed */ } goto pclgood; } if (cmdMatches("WRITE BIBLIOGRAPHY")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } if (!getFullArg(2, cat( "* What is the bibliography HTML input/output file <", "mmbiblio.html", ">? ", NULL))) goto pclbad; print2( "The old file will be renamed %s~1.\n", fullArg[2]); goto pclgood; } if (cmdMatches("WRITE RECENT_ADDITIONS")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } if (!getFullArg(2, cat( "* What is the Recent Additions HTML input/output file <", "mmrecent.html", ">? ", NULL))) goto pclbad; print2( "The old file will be renamed %s~1.\n", fullArg[2]); /* Get any switches */ i = 2; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "LIMIT|HTML|ALT_HTML", "|", NULL))) goto pclbad; if (lastArgMatches("LIMIT")) { i++; if (!getFullArg(i, "# How many most recent theorems <100>? ")) goto pclbad; } } else { break; } /*break;*/ /* Break if only 1 switch is allowed */ } goto pclgood; } } if (cmdMatches("OPEN")) { /*if (!getFullArg(1, "LOG|TEX|HTML|")) goto pclbad;*/ /* 2-Oct-2017 nm Removed HTML */ if (!getFullArg(1, "LOG|TEX|")) goto pclbad; if (cmdMatches("OPEN LOG")) { if (logFileOpenFlag) { printLongLine(cat( "?Sorry, the log file \"", logFileName, "\" is currently open. ", "Type CLOSE LOG to close the current log if you want to open another one." , NULL), "", " "); goto pclbad; } if (!getFullArg(2, "* What is the name of logging output file? ")) goto pclbad; } if (cmdMatches("OPEN TEX")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } if (texFileOpenFlag) { printLongLine(cat( "?Sorry, the LaTeX file \"", texFileName, "\" is currently open. ", "Type CLOSE TEX to close the current LaTeX file", " if you want to open another one." , NULL), "", " "); goto pclbad; } if (!getFullArg(2, "* What is the name of LaTeX output file? ")) goto pclbad; /* Get any switches */ i = 2; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "NO_HEADER|OLD_TEX|", NULL))) goto pclbad; } else { break; } /* break; */ /* Break if only 1 switch is allowed */ } /* End while for switch loop */ } /* 2-Oct-2017 nm OPEN HTML is obsolete */ /******* if (cmdMatches("OPEN HTML")) { if (texFileOpenFlag) { printLongLine(cat( "?Sorry, the HTML file \"",texFileName, "\" is currently open. ", "Type CLOSE HTML to close the current HTML file", " if you want to open another one." , NULL), "", " "); goto pclbad; } if (!getFullArg(2, "@ What is the name of HTML output file? ")) goto pclbad; /@ Get any switches @/ i = 2; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "NO_HEADER|", NULL))) goto pclbad; } else { break; } break; /@ Break if only 1 switch is allowed @/ } /@ End while for switch loop @/ } ****/ goto pclgood; } if (cmdMatches("CLOSE")) { /*if (!getFullArg(1, "LOG|TEX|HTML|")) goto pclbad;*/ /* 2-Oct-2017 nm Removed HTML */ if (!getFullArg(1, "LOG|TEX|")) goto pclbad; goto pclgood; } if (cmdMatches("FILE")) { if (!getFullArg(1, cat("SEARCH", NULL))) goto pclbad; if (cmdMatches("FILE SEARCH")) { if (!getFullArg(2, "& What is the name of the file to search? ")) goto pclbad; if (!getFullArg(3, "* What is the string to search for? ")) goto pclbad; /* Get any switches */ i = 3; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (i == 4) { if (!getFullArg(i, cat( "FROM_LINE|TO_LINE|", NULL))) goto pclbad; } else { if (!getFullArg(i, cat( "FROM_LINE|TO_LINE|", NULL))) goto pclbad; } if (lastArgMatches("FROM_LINE")) { i++; if (!getFullArg(i, "# From what line number <1>? ")) goto pclbad; } if (lastArgMatches("TO_LINE")) { i++; if (!getFullArg(i, "# To what line number <999999>? ")) goto pclbad; } if (lastArgMatches("WINDOW")) { /* ???Not implemented yet */ i++; if (!getFullArg(i, "# How big a window around matched lines <0>? ")) goto pclbad; } } else { break; } /* break; */ /* Break if only 1 switch is allowed */ } /* End while for switch loop */ goto pclgood; } /* End if (cmdMatches("FILE SEARCH")) */ goto pclgood; } if (cmdMatches("SHOW")) { if (!PFASmode) { if (!getFullArg(1, cat( "SETTINGS|LABELS|STATEMENT|SOURCE|PROOF|MEMORY|TRACE_BACK|", "USAGE|ELAPSED_TIME|DISCOURAGED|", NULL))) goto pclbad; } else { if (!getFullArg(1, cat("NEW_PROOF|", "SETTINGS|LABELS|STATEMENT|SOURCE|PROOF|MEMORY|TRACE_BACK|", "USAGE|ELAPSED_TIME|DISCOURAGED|", NULL))) goto pclbad; } if (showStatement) { if (showStatement < 1 || showStatement > statements) bug(1110); let(&defaultArg, cat(" <",statement[showStatement].labelName, ">", NULL)); } else { let(&defaultArg, ""); } if (cmdMatches("SHOW TRACE_BACK")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } if (!getFullArg(2, cat("* What is the statement label", defaultArg, "? ", NULL))) goto pclbad; /* Get any switches */ i = 2; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( /* 19-May-2013 nm Added MATCH */ "ALL|ESSENTIAL|AXIOMS|TREE|DEPTH|COUNT_STEPS|MATCH|TO", "|", NULL))) goto pclbad; if (lastArgMatches("DEPTH")) { i++; if (!getFullArg(i, "# How many indentation levels <999>? ")) goto pclbad; } /* 13-May-2013 nm Added MATCH */ if (lastArgMatches("MATCH")) { i++; if (!getFullArg(i, "* What statement label? ")) goto pclbad; } /* 18-Jul-2015 nm Added MATCH */ if (lastArgMatches("TO")) { i++; if (!getFullArg(i, "* What statement label? ")) goto pclbad; } } else { break; } /* break; */ /* Break if only 1 switch is allowed */ } goto pclgood; } /* End if (cmdMatches("SHOW TRACE_BACK")) */ if (cmdMatches("SHOW USAGE")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } if (!getFullArg(2, cat("* What is the statement label", defaultArg, "? ", NULL))) goto pclbad; /* Get any switches */ i = 2; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "DIRECT|RECURSIVE|ALL", "|", NULL))) goto pclbad; } else { break; } /* break; */ /* Break if only 1 switch is allowed */ } goto pclgood; } /* End if (cmdMatches("SHOW USAGE")) */ if (cmdMatches("SHOW LABELS")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } if (!getFullArg(2, "* What are the labels to match (* = wildcard) <*>?")) goto pclbad; /* Get any switches */ i = 2; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat("ALL|LINEAR|", NULL))) goto pclbad; } else { break; } /*break;*/ /* Break if only 1 switch is allowed */ } goto pclgood; } if (cmdMatches("SHOW STATEMENT")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } if (!getFullArg(2, cat("* What is the statement label", defaultArg, "? ", NULL))) goto pclbad; /* Get any switches */ i = 2; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "FULL|COMMENT|TEX|OLD_TEX|HTML|ALT_HTML|TIME|BRIEF_HTML", /* 12-May-2009 sa Added MNEMONICS */ "|BRIEF_ALT_HTML|MNEMONICS|NO_VERSIONING|", NULL))) goto pclbad; } else { break; } /* break; */ /* Break if only 1 switch is allowed */ } goto pclgood; } if (cmdMatches("SHOW SOURCE")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } if (!getFullArg(2, cat("* What is the statement label", defaultArg, "? ", NULL))) { goto pclbad; } goto pclgood; } if (cmdMatches("SHOW PROOF")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } if (!getFullArg(2, cat("* What is the statement label", defaultArg, "? ", NULL))) goto pclbad; /* Get any switches */ i = 2; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "ESSENTIAL|ALL|UNKNOWN|FROM_STEP|TO_STEP|DEPTH", /*"|REVERSE|VERBOSE|NORMAL|COMPRESSED",*/ "|REVERSE|VERBOSE|NORMAL|PACKED|COMPRESSED|EXPLICIT", "|FAST", /* 2-Mar-2016 nm */ "|OLD_COMPRESSION", /* 27-Dec-2013 nm */ /* 14-Sep-2010 nm Added OLD_TEX */ "|STATEMENT_SUMMARY|DETAILED_STEP|TEX|OLD_TEX|HTML", "|LEMMON|START_COLUMN|NO_REPEATED_STEPS", "|RENUMBER|SIZE|", NULL))) goto pclbad; if (lastArgMatches("FROM_STEP")) { i++; if (!getFullArg(i, "# From what step <1>? ")) goto pclbad; } if (lastArgMatches("TO_STEP")) { i++; if (!getFullArg(i, "# To what step <9999>? ")) goto pclbad; } if (lastArgMatches("DEPTH")) { i++; if (!getFullArg(i, "# How many indentation levels <999>? ")) goto pclbad; } if (lastArgMatches("DETAILED_STEP")) { i++; if (!getFullArg(i, "# Display details of what step <1>? ")) goto pclbad; } if (lastArgMatches("START_COLUMN")) { i++; if (!getFullArg(i, cat( "# At what column should the formula start <", str((double)DEFAULT_COLUMN), ">? ", NULL))) goto pclbad; } } else { break; } /* break; */ /* Break if only 1 switch is allowed */ } goto pclgood; } /* End if (cmdMatches("SHOW PROOF")) */ if (cmdMatches("SHOW NEW_PROOF")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } /* Get any switches */ i = 1; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "ESSENTIAL|ALL|UNKNOWN|FROM_STEP|TO_STEP|DEPTH", /*"|REVERSE|VERBOSE|NORMAL|COMPRESSED",*/ "|REVERSE|VERBOSE|NORMAL|PACKED|COMPRESSED|EXPLICIT", "|OLD_COMPRESSION", /* 27-Dec-2013 nm */ "|NOT_UNIFIED|TEX|HTML", "|LEMMON|START_COLUMN|NO_REPEATED_STEPS", "|RENUMBER|", NULL))) goto pclbad; if (lastArgMatches("FROM_STEP")) { i++; if (!getFullArg(i, "# From what step <1>? ")) goto pclbad; } if (lastArgMatches("TO_STEP")) { i++; if (!getFullArg(i, "# To what step <9999>? ")) goto pclbad; } if (lastArgMatches("DEPTH")) { i++; if (!getFullArg(i, "# How many indentation levels <999>? ")) goto pclbad; } if (lastArgMatches("START_COLUMN")) { i++; if (!getFullArg(i, cat( "# At what column should the formula start <", str((double)DEFAULT_COLUMN), ">? ", NULL))) goto pclbad; } } else { break; } /* break; */ /* Break if only 1 switch is allowed */ } goto pclgood; } /* End if (cmdMatches("SHOW NEW_PROOF")) */ goto pclgood; } /* End of SHOW */ if (cmdMatches("SEARCH")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } if (!getFullArg(1, "* What are the labels to match (* = wildcard) <*>?")) goto pclbad; if (!getFullArg(2, "* Search for what math symbol string? ")) goto pclbad; /* Get any switches */ i = 2; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat("ALL|COMMENTS|JOIN|", NULL))) goto pclbad; } else { break; } /*break;*/ /* Break if only 1 switch is allowed */ } goto pclgood; } /* End of SEARCH */ if (cmdMatches("SAVE")) { if (!PFASmode) { if (!getFullArg(1, "PROOF|")) goto pclbad; } else { if (!getFullArg(1, cat("NEW_PROOF|", "PROOF|", NULL))) goto pclbad; } if (showStatement) { if (showStatement < 0) bug(1111); let(&defaultArg, cat(" <",statement[showStatement].labelName, ">", NULL)); } else { let(&defaultArg, ""); } if (cmdMatches("SAVE PROOF")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } if (!getFullArg(2, cat("* What is the statement label", defaultArg, "? ", NULL))) goto pclbad; /* Get any switches */ i = 2; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "NORMAL|PACKED|COMPRESSED|EXPLICIT", "|FAST|OLD_COMPRESSION", /* 27-Dec-2013 nm */ "|TIME|", NULL))) goto pclbad; } else { break; } /* break; */ /* Break if only 1 switch is allowed */ } goto pclgood; } /* End if (cmdMatches("SAVE PROOF")) */ if (cmdMatches("SAVE NEW_PROOF")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } /* Get any switches */ i = 1; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "NORMAL|PACKED|COMPRESSED|EXPLICIT", /* 27-Dec-2013 nm Added / OLD_COMPRESSION */ /* 3-May-2016 nm Added / OVERRIDE */ "|OLD_COMPRESSION|OVERRIDE", "|", NULL))) goto pclbad; } else { break; } /*break;*/ /* Break if only 1 switch is allowed */ } goto pclgood; } /* End if (cmdMatches("SAVE NEW_PROOF")) */ goto pclgood; } /* End of SAVE */ if (cmdMatches("PROVE")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } if (!proveStatement) proveStatement = showStatement; if (proveStatement) { let(&defaultArg, cat(" <",statement[proveStatement].labelName, ">", NULL)); } else { let(&defaultArg, ""); } if (!getFullArg(1, cat("* What is the label of the statement you want to try proving", defaultArg, "? ", NULL))) goto pclbad; /* 10-May-2016 nm */ /* Get any switches */ i = 1; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, "OVERRIDE|")) goto pclbad; } else { break; } break; /* Break if only 1 switch is allowed */ } /* End while for switch loop */ goto pclgood; } /* Commands in Proof Assistant mode */ if (cmdMatches("MATCH")) { if (!getFullArg(1, "STEP|ALL|")) goto pclbad; if (cmdMatches("MATCH STEP")) { if (!getFullArg(2, "# What step number? ")) goto pclbad; /* Get any switches */ i = 2; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "MAX_ESSENTIAL_HYP|", NULL))) goto pclbad; if (lastArgMatches("MAX_ESSENTIAL_HYP")) { i++; if (!getFullArg(i, "# Maximum number of essential hypotheses to allow for a match <0>? ")) goto pclbad; } } else { break; } break; /* Break if only 1 switch is allowed */ } goto pclgood; } if (cmdMatches("MATCH ALL")) { /* Get any switches */ i = 1; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "ESSENTIAL|MAX_ESSENTIAL_HYP|", NULL))) goto pclbad; if (lastArgMatches("MAX_ESSENTIAL_HYP")) { i++; if (!getFullArg(i, "# Maximum number of essential hypotheses to allow for a match <0>? ")) goto pclbad; } } else { break; } /*break;*/ /* Break if only 1 switch is allowed */ } goto pclgood; } /* End if (cmdMatches("MATCH ALL")) */ goto pclgood; } if (cmdMatches("INITIALIZE")) { if (!getFullArg(1, "STEP|ALL|USER|")) goto pclbad; /* 16-Apr-06 nm Added USER */ if (cmdMatches("INITIALIZE STEP")) { if (!getFullArg(2, "# What step number? ")) goto pclbad; } goto pclgood; } /* 26-Aug-2006 nm Changed "IMPROVE STEP " to just "IMPROVE " for user convenience (and consistency with "ASSIGN" command) */ if (cmdMatches("IMPROVE")) { if (!getFullArg(1, "* What step number, or FIRST, or LAST, or ALL ? ")) goto pclbad; /* 11-Dec-05 nm */ /* Get any switches */ i = 1; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, /* 3-May-2016 nm Added / OVERRIDE */ "DEPTH|NO_DISTINCT|1|2|3|SUBPROOFS|OVERRIDE|") ) goto pclbad; if (lastArgMatches("DEPTH")) { i++; if (!getFullArg(i, "# What is maximum depth for searching statements with $e hypotheses <0>? ")) goto pclbad; } } else { break; } /*break;*/ /* Do this if only 1 switch is allowed */ } /* end while */ goto pclgood; } /* end if IMPROVE */ /* ------- Old version before 26-Aug-2006 ------- if (cmdMatches("IMPROVE")) { if (!getFullArg(1, "STEP|ALL|FIRST|LAST|")) goto pclbad; if (cmdMatches("IMPROVE STEP")) { if (!getFullArg(2, "# What step number? ")) goto pclbad; } if (cmdMatches("IMPROVE STEP") || cmdMatches("IMPROVE ALL") || cmdMatches("IMPROVE LAST") || cmdMatches("IMPROVE FIRST")) { /@ 11-Dec-05 nm @/ /@ Get switches @/ if (cmdMatches("IMPROVE STEP")) { i = 2; } else { i = 1; } while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, "DEPTH|NO_DISTINCT|") ) goto pclbad; if (lastArgMatches("DEPTH")) { i++; if (!getFullArg(i, "# What is maximum depth for searching statements with $e hypotheses <0>? ")) goto pclbad; } } else { break; } /@break;@/ /@ Do this if only 1 switch is allowed @/ } /@ end while @/ goto pclgood; } /@ end if IMPROVE STEP or IMPROVE ALL @/ } ------- End of old version ------- */ if (cmdMatches("MINIMIZE_WITH")) { if (!getFullArg(1, "* What statement label? ")) goto pclbad; /* Get any switches */ i = 1; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( /* "BRIEF|VERBOSE|ALLOW_GROWTH|NO_DISTINCT|EXCEPT|", "REVERSE|INCLUDE_MATHBOXES|FORBID|", NULL))) */ "VERBOSE|MAY_GROW|EXCEPT|OVERRIDE|INCLUDE_MATHBOXES|", "ALLOW_NEW_AXIOMS|NO_NEW_AXIOMS_FROM|FORBID|TIME|", NULL))) /* 7-Jan-06 nm Added EXCEPT */ /* 28-Jun-2011 nm Added INCLUDE_MATHBOXES */ /* 10-Nov-2011 nm Added REVERSE */ /* 25-Jun-2014 nm Removed REVERSE, NO_DISTINCT */ /* 22-Nov-2014 nm Added NO_NEW_AXIOMS_FROM */ /* 3-May-2016 nm Added / OVERRIDE */ /* 4-Aug-2019 nm Added ALLOW_NEW_AXIOMS; changed ALLOW_GROWTH to MAY_GROW */ goto pclbad; /* 7-Jan-06 nm Added EXCEPT */ if (lastArgMatches("EXCEPT")) { i++; if (!getFullArg(i, "* What statement label match pattern? ")) goto pclbad; } /* 4-Aug-2019 nm Added ALLOW_NEW_AXIOMS */ if (lastArgMatches("ALLOW_NEW_AXIOMS")) { i++; if (!getFullArg(i, "* What statement label match pattern? ")) goto pclbad; } /* 22-Nov-2014 nm Added NO_NEW_AXIOMS_FROM */ if (lastArgMatches("NO_NEW_AXIOMS_FROM")) { i++; if (!getFullArg(i, "* What statement label match pattern? ")) goto pclbad; } /* 20-May-2013 nm Added FORBID */ if (lastArgMatches("FORBID")) { i++; if (!getFullArg(i, "* What statement label match pattern? ")) goto pclbad; } } else { break; } /*break;*/ /* Break if only 1 switch is allowed */ } goto pclgood; } /* end of MINIMIZE_WITH */ /* 11-Sep-2016 nm */ if (cmdMatches("EXPAND")) { if (!getFullArg(1, "* What statement label? ")) goto pclbad; goto pclgood; } if (cmdMatches("UNIFY")) { if (!getFullArg(1, "STEP|ALL|")) goto pclbad; if (cmdMatches("UNIFY STEP")) { if (!getFullArg(2, "# What step number? ")) goto pclbad; goto pclgood; } if (cmdMatches("UNIFY ALL")) { /* Get any switches */ i = 1; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "INTERACTIVE|", NULL))) goto pclbad; } else { break; } break; /* Break if only 1 switch is allowed */ } goto pclgood; } /* End if (cmdMatches("UNIFY ALL")) */ } if (cmdMatches("DELETE")) { if (!getFullArg(1, "STEP|ALL|FLOATING_HYPOTHESES|")) goto pclbad; if (lastArgMatches("STEP")) { if (!getFullArg(2, "# What step number? ")) goto pclbad; goto pclgood; } goto pclgood; } /*???OBSOL???*/ if (cmdMatches("ADD")) { if (!getFullArg(1, "UNIVERSE|")) goto pclbad; /* Note: further parsing below */ } if (cmdMatches("REPLACE")) { /* 14-Sep-2012 nm Added FIRST, LAST */ if (!getFullArg(1, "* What step number, or FIRST, or LAST ? ")) goto pclbad; if (!getFullArg(2, "* With what statement label? ")) goto pclbad; /* Get any switches */ i = 2; /* 3-May-2016 nm Added / OVERRIDE */ while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "OVERRIDE|", NULL))) goto pclbad; } else { break; } break; /* Break if only 1 switch is allowed */ } goto pclgood; } if (cmdMatches("LET")) { if (!getFullArg(1, "STEP|VARIABLE|")) goto pclbad; if (cmdMatches("LET STEP")) { if (!getFullArg(2, "* What step number, or FIRST, or LAST ? ")) goto pclbad; } if (cmdMatches("LET VARIABLE")) { if (!getFullArg(2, "* Assign what variable (format $nn)? ")) goto pclbad; } if (!getFullArg(3, "=|<=>")) goto pclbad; if (!getFullArg(4, "* With what math symbol string? ")) goto pclbad; goto pclgood; } if (cmdMatches("ASSIGN")) { if (!getFullArg(1, "* What step number, or FIRST, or LAST ? ")) goto pclbad; /* 11-Dec-05 nm */ if (!getFullArg(2, "* With what statement label? ")) goto pclbad; /* Get any switches */ i = 2; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( /* 3-May-2016 nm Added / OVERRIDE */ "NO_UNIFY|OVERRIDE|", NULL))) goto pclbad; } else { break; } /*break;*/ /* Break if only 1 switch is allowed */ } goto pclgood; } if (cmdMatches("UNDO")) { goto pclgood; } if (cmdMatches("REDO")) { goto pclgood; } if (cmdMatches("SET")) { let(&tmpStr, cat( /*"ECHO|SCROLL|UNIVERSE|",*/ "WIDTH|HEIGHT|UNDO|ECHO|SCROLL|", "DEBUG|MEMORY_STATUS|SEARCH_LIMIT|UNIFICATION_TIMEOUT|", "DISCOURAGEMENT|", /* 10-Jul-2016 nm */ "CONTRIBUTOR|", /* 14-May-2017 nm */ "ROOT_DIRECTORY|", /* 31-Dec-2017 nm */ "EMPTY_SUBSTITUTION|JEREMY_HENTY_FILTER|", NULL)); if (!getFullArg(1,tmpStr)) goto pclbad; if (cmdMatches("SET DEBUG")) { if (!getFullArg(2, "FLAG|OFF|")) goto pclbad; if (lastArgMatches("FLAG")) { if (!getFullArg(3, "4|5|6|7|8|9|<5>")) goto pclbad; } goto pclgood; } if (cmdMatches("SET ECHO")) { if (commandEcho) { if (!getFullArg(2, "ON|OFF|")) goto pclbad; } else { if (!getFullArg(2, "ON|OFF|")) goto pclbad; } goto pclgood; } if (cmdMatches("SET SCROLL")) { if (scrollMode == 1) { if (!getFullArg(2, "CONTINUOUS|PROMPTED|")) goto pclbad; } else { if (!getFullArg(2, "CONTINUOUS|PROMPTED|")) goto pclbad; } goto pclgood; } if (cmdMatches("SET DISCOURAGEMENT")) { /* 10-Jul-2016 nm */ if (globalDiscouragement) { if (!getFullArg(2, "ON|OFF|")) goto pclbad; } else { if (!getFullArg(2, "ON|OFF|")) goto pclbad; } goto pclgood; } if (cmdMatches("SET MEMORY_STATUS")) { if (memoryStatus) { if (!getFullArg(2, "ON|OFF|")) goto pclbad; } else { if (!getFullArg(2, "ON|OFF|")) goto pclbad; } goto pclgood; } if (cmdMatches("SET JEREMY_HENTY_FILTER")) { if (hentyFilter) { if (!getFullArg(2, "ON|OFF|")) goto pclbad; } else { if (!getFullArg(2, "ON|OFF|")) goto pclbad; } goto pclgood; } if (cmdMatches("SET CONTRIBUTOR")) { if (!getFullArg(2, cat( "* What is the contributor name for SAVE (NEW_)PROOF <", contributorName, ">? ", NULL))) goto pclbad; goto pclgood; } if (cmdMatches("SET ROOT_DIRECTORY")) { if (!getFullArg(2, cat( "* What is the root directory path (use space if none) <", rootDirectory, ">? ", NULL))) goto pclbad; goto pclgood; } if (cmdMatches("SET SEARCH_LIMIT")) { if (!getFullArg(2, cat( "# What is search limit for IMPROVE command <", str((double)userMaxProveFloat), ">? ", NULL))) goto pclbad; goto pclgood; } if (cmdMatches("SET UNIFICATION_TIMEOUT")) { if (!getFullArg(2, cat( "# What is maximum number of unification trials <", str((double)userMaxUnifTrials), ">? ", NULL))) goto pclbad; goto pclgood; } if (cmdMatches("SET WIDTH")) { if (!getFullArg(2, cat( "# What is maximum line length on your screen <", str((double)screenWidth), ">? ", NULL))) goto pclbad; goto pclgood; } if (cmdMatches("SET HEIGHT")) { if (!getFullArg(2, cat( "# What is number of lines your screen displays <", str((double)screenHeight), ">? ", NULL))) goto pclbad; goto pclgood; } if (cmdMatches("SET UNDO")) { if (!getFullArg(2, cat( "# What is the maximum number of UNDOs <", str((double)(processUndoStack(NULL, PUS_GET_SIZE, "", 0))), ">? ", NULL))) goto pclbad; goto pclgood; } if (cmdMatches("SET EMPTY_SUBSTITUTION")) { if (minSubstLen == 0) { if (!getFullArg(2, "ON|OFF|")) goto pclbad; } else { if (!getFullArg(2, "ON|OFF|")) goto pclbad; } goto pclgood; } } /* end if SET */ /************** 31-Dec-2017 nm Delete unused stuff if (cmdMatches("INPUT")) { if (!getFullArg(1, "PROOF|")) goto pclbad; goto pclgood; } if (cmdMatches("SET UNIVERSE") || cmdMatches("ADD UNIVERSE") || cmdMatches("DELETE UNIVERSE")) { /@ Get a list of statement labels @/ i = 1; while (1) { i++; /@??? The user will never be asked this. @/ if (!getFullArg(i, "@ Statement label or '@' or '$f'|$<$>? ")) goto pclbad; if (lastArgMatches("")) goto pclgood; /@ End of argument list @/ } /@ end while @/ } /@ end if xxx UNIVERSE @/ ************/ if (cmdMatches("ERASE")) { goto pclgood; } if (cmdMatches("MORE")) { if (!getFullArg(1, "* What is the name of the file to display? ")) goto pclbad; goto pclgood; } if (cmdMatches("TOOLS")) { goto pclgood; } if (cmdMatches("VERIFY")) { if (!getFullArg(1, "PROOF|MARKUP|")) goto pclbad; if (cmdMatches("VERIFY PROOF")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } if (!getFullArg(2, "* What are the labels to match (* = wildcard) <*>?")) goto pclbad; /* Get any switches */ i = 2; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "SYNTAX_ONLY", "|", NULL))) goto pclbad; } else { break; } break; /* Break if only 1 switch is allowed */ } goto pclgood; } /* 7-Nov-2015 nm */ if (cmdMatches("VERIFY MARKUP")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } if (!getFullArg(2, "* What are the labels to match (* = wildcard) <*>?")) goto pclbad; /* Get any switches */ i = 2; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "DATE_SKIP|FILE_SKIP|TOP_DATE_SKIP|VERBOSE", "|", NULL))) goto pclbad; } else { break; } /* break; */ /* Break if only 1 switch is allowed */ } goto pclgood; } } if (cmdMatches("DBG")) { /* The debug command fetches an arbitrary 2nd arg in quotes, to be handled in whatever way is needed for debugging. */ if (!getFullArg(1, "* What is the debugging string? ")) goto pclbad; goto pclgood; } /* 10-Dec-2018 nm Added MARKUP command*/ if (cmdMatches("MARKUP")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } if (!getFullArg(1, "* What is the name of the input file with markup? ")) goto pclbad; if (!getFullArg(2, "* What is the name of the HTML output file? ")) goto pclbad; /* Get any switches */ i = 2; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "HTML|ALT_HTML|SYMBOLS|LABELS|NUMBER_AFTER_LABEL|BIB_REFS", "|UNDERSCORES|CSS|", NULL))) goto pclbad; } else { break; } /*break;*/ /* Break if only 1 switch is allowed */ } goto pclgood; } if (cmdMatches("MIDI")) { if (sourceHasBeenRead == 0) { print2("?No source file has been read in. Use READ first.\n"); goto pclbad; } if (!getFullArg(1, "* Statement label to create MIDI for (* matches any substring) <*>?")) goto pclbad; /* Get any switches */ i = 1; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat("PARAMETER|", NULL))) goto pclbad; i++; if (!getFullArg(i, "* What is the parameter string ?")) goto pclbad; } else { break; } break; /* Break if only 1 switch is allowed */ } goto pclgood; } if (cmdMatches("EXIT") || cmdMatches("QUIT") || cmdMatches("_EXIT_PA")) { /* 9-Jun-2016 nm */ /* Get any switches */ i = 0; while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "FORCE|", NULL))) goto pclbad; } else { break; } break; /* Break if only 1 switch is allowed */ } /* End while for switch loop */ goto pclgood; } } else { /* toolsMode */ /* Text tools mode */ let(&tmpStr, cat( "HELP|SUBMIT|", "ADD|DELETE|SUBSTITUTE|S|SWAP|CLEAN|INSERT|BREAK|BUILD|MATCH|SORT|", "UNDUPLICATE|DUPLICATE|UNIQUE|REVERSE|RIGHT|PARALLEL|NUMBER|COUNT|", "COPY|C|TYPE|T|TAG|UPDATE|BEEP|B|EXIT|QUIT|", NULL)); if (!getFullArg(0,tmpStr)) goto pclbad; if (cmdMatches("HELP")) { if (!getFullArg(1, cat( "ADD|DELETE|SUBSTITUTE|S|SWAP|CLEAN|INSERT|BREAK|BUILD|MATCH|SORT|", "UNDUPLICATE|DUPLICATE|UNIQUE|REVERSE|RIGHT|PARALLEL|NUMBER|COUNT|", "TYPE|T|TAG|UPDATE|BEEP|B|EXIT|QUIT|", "COPY|C|SUBMIT|SYSTEM|CLI|", "$|<$>", NULL))) goto pclbad; goto pclgood; } if (cmdMatches("ADD") || cmdMatches("TAG")) { if (!getFullArg(1, "& Input/output file? ")) goto pclbad; if (!getFullArg(2, "* String to add to beginning of each line <>? ")) goto pclbad; if (!getFullArg(3, "* String to add to end of each line <>? ")) goto pclbad; if (cmdMatches("TAG")) { if (!getFullArg(4, "* String to match to start range (null = any line) <>? ")) goto pclbad; if (!getFullArg(5, "# Which occurrence of start match to start range <1>? ")) goto pclbad; if (!getFullArg(6, "* String to match to end range (null = any line) <>? ")) goto pclbad; if (!getFullArg(7, "# Which occurrence of end match to end range <1>? ")) goto pclbad; } goto pclgood; } if (cmdMatches("DELETE")) { if (!getFullArg(1, "& Input/output file? ")) goto pclbad; if (!getFullArg(2, "* String from which to start deleting (CR = beginning of line) <>? ")) goto pclbad; if (!getFullArg(3, "* String at which to stop deleting (CR = end of line) <>? ")) goto pclbad; goto pclgood; } if (cmdMatches("CLEAN")) { if (!getFullArg(1, "& Input/output file? ")) goto pclbad; if (!getFullArg(2, "* Subcommand(s) (D,B,E,R,Q,T,U,P,G,C,L,V) ? ")) goto pclbad; goto pclgood; } if (cmdMatches("SWAP")) { if (!getFullArg(1, "& Input/output file? ")) goto pclbad; if (!getFullArg(2, "* Character string to match between the halves to be swapped? ")) goto pclbad; goto pclgood; } if (cmdMatches("SUBSTITUTE") || cmdMatches("S")) { if (!getFullArg(1, "& Input/output file? ")) goto pclbad; if (!getFullArg(2, "* String to replace? ")) goto pclbad; if (!getFullArg(3, "* Replace it with <>? ")) goto pclbad; if (!getFullArg(4, "* Which occurrence in the line (1,2,... or ALL or EACH) <1>? ")) goto pclbad; if (!getFullArg(5, "* Additional match required on line (null = match all) <>? ")) goto pclbad; goto pclgood; } if (cmdMatches("INSERT")) { if (!getFullArg(1, "& Input/output file? ")) goto pclbad; if (!getFullArg(2, "* String to insert in each line ? ")) goto pclbad; if (!getFullArg(3, "# Column at which to insert the string <1>? ")) goto pclbad; goto pclgood; } if (cmdMatches("BREAK")) { if (!getFullArg(1, "& Input/output file? ")) goto pclbad; if (!getFullArg(2, "* Special characters to use as token delimiters <()[],=:;{}>? ")) goto pclbad; goto pclgood; } if (cmdMatches("MATCH")) { if (!getFullArg(1, "& Input/output file? ")) goto pclbad; if (!getFullArg(2, "* String to match on each line (null = any non-blank line) <>? ")) goto pclbad; if (!getFullArg(3, "* Output those lines containing the string (Y) or those not (N) ? ")) goto pclbad; goto pclgood; } if (cmdMatches("SORT")) { if (!getFullArg(1, "& Input/output file? ")) goto pclbad; if (!getFullArg(2, "* String to start key on each line (null string = column 1) <>? ")) goto pclbad; goto pclgood; } if (cmdMatches("UNDUPLICATE") || cmdMatches("DUPLICATE") || cmdMatches("UNIQUE") || cmdMatches("REVERSE") || cmdMatches("BUILD") || cmdMatches("RIGHT")) { if (!getFullArg(1, "& Input/output file? ")) goto pclbad; goto pclgood; } if (cmdMatches("COUNT")) { if (!getFullArg(1, "& Input file? ")) goto pclbad; if (!getFullArg(2, "* String to count <;>? ")) goto pclbad; goto pclgood; } if (cmdMatches("COPY") || cmdMatches("C")) { if (!getFullArg(1, "* Comma-separated list of input files? ")) goto pclbad; if (!getFullArg(2, "* Output file? ")) goto pclbad; goto pclgood; } if (cmdMatches("NUMBER")) { if (!getFullArg(1, "* Output file ? ")) goto pclbad; if (!getFullArg(2, "# First number <1>? ")) goto pclbad; if (!getFullArg(3, "# Last number <10>? ")) goto pclbad; if (!getFullArg(4, "# Increment <1>? ")) goto pclbad; goto pclgood; } if (cmdMatches("TYPE") || cmdMatches("T")) { if (!getFullArg(1, "& File to display on the screen? ")) goto pclbad; if (!getFullArg(2, "* Num. lines to type or ALL (nothing = 10) <$>? ")) goto pclbad; goto pclgood; } if (cmdMatches("UPDATE")) { print2( "Warning: Do not comment out code - delete it before running UPDATE! If\n"); print2( "rerunning UPDATE, do not tamper with \"start/end of deleted section\" comments!\n"); print2( "Edit out tag on header comment line! Review the output file!\n"); if (!getFullArg(1, "& Original (reference) program input file? ")) goto pclbad; if (!getFullArg(2, "& Edited program input file? ")) goto pclbad; if (!getFullArg(3, cat( "* Edited program output file with revisions tagged <", fullArg[2], ">? ", NULL))) goto pclbad; if (!strcmp(fullArg[2], fullArg[3])) { print2( "The input file will be renamed %s~1.\n", fullArg[2]); } if (!getFullArg(4, cat("* Revision tag for added lines ? ", NULL))) goto pclbad; if (!getFullArg(5, "# Successive lines required for match (more = better sync) <3>? ")) goto pclbad; goto pclgood; } if (cmdMatches("PARALLEL")) { if (!getFullArg(1, "& Left file? ")) goto pclbad; if (!getFullArg(2, "& Right file? ")) goto pclbad; if (!getFullArg(3, cat("* Output file <", fullArg[1], ">? ", NULL))) goto pclbad; if (!getFullArg(4, cat("* String to insert between the 2 input lines <>? ", NULL))) goto pclbad; goto pclgood; } /* toolsMode - no qualifiers for EXIT */ if (cmdMatches("EXIT") || cmdMatches("QUIT")) { goto pclgood; } } /* if !toolsMode ... else ... */ if (cmdMatches("SUBMIT")) { if (toolsMode) { let(&tmpStr, " "); } else { let(&tmpStr, " "); } if (!getFullArg(1, cat("& What is the name of command file to run", tmpStr, "? ", NULL))) { goto pclbad; } /* 23-Oct-2006 nm Added / SILENT qualifier */ /* Get any switches */ i = 1; /* Number of command words before switch */ while (1) { i++; if (!getFullArg(i, "/|$|<$>")) goto pclbad; if (lastArgMatches("/")) { i++; if (!getFullArg(i, cat( "SILENT", "|", NULL))) goto pclbad; } else { break; } break; /* Break if only 1 switch is allowed */ } /* End while for switch loop */ goto pclgood; } if (cmdMatches("BEEP") || cmdMatches("B")) { goto pclgood; } /* Command in master list but not intercepted -- really a bug */ print2("?This command has not been implemented yet.\n"); print2("(This is really a bug--please report it.)\n"); goto pclbad; /* Should never get here */ pclgood: /* Strip off the last fullArg if a null argument was added by getFullArg in the case when "$" (nothing) is allowed */ if (!strcmp(fullArg[pntrLen(fullArg) - 1], chr(3))) { let((vstring *)(&fullArg[pntrLen(fullArg) - 1]), ""); /* Deallocate */ pntrLet(&fullArg, pntrLeft(fullArg, pntrLen(fullArg) - 1)); } if (pntrLen(fullArg) > rawArgs) bug(1102); if (pntrLen(fullArg) < rawArgs) { let(&tmpStr, cat("?Too many arguments. Use quotes around arguments with special", " characters and around Unix file names with \"/\"s.", NULL)); printCommandError(cat(commandPrompt, commandLine, NULL), pntrLen(fullArg), tmpStr); goto pclbad; } /* 1-Nov-2013 nm Create a single string containing the fullArg tokens */ let(&fullArgString, ""); for (i = 0; i < pntrLen(fullArg); i++) { let(&fullArgString, cat(fullArgString, " ", fullArg[i], NULL)); } let(&fullArgString, right(fullArgString, 2)); /* Strip leading space */ /* Deallocate memory */ let(&defaultArg, ""); let(&tmpStr, ""); return (1); pclbad: /* Deallocate memory */ let(&defaultArg, ""); let(&tmpStr, ""); return (0); } /* processCommandLine */ flag getFullArg(long arg, vstring cmdList1) { /* This function converts the user's abbreviated keyword in rawArgPntr[arg] to a full, upper-case keyword, in fullArg[arg], matching the available choices in cmdList. */ /* Special cases: cmdList = "# xxx ?" - get an integer */ /* cmdList = "* xxx ?" - get any string; don't convert to upper case cmdList = "& xxx ?" - same as * except verify it is a file that exists */ /* "$" means a null argument is acceptable; put it in as special character chr(3) so it can be recognized */ pntrString *possCmd = NULL_PNTRSTRING; long possCmds, i, j, k, m, p, q; vstring defaultCmd = ""; vstring infoStr = ""; vstring tmpStr = ""; vstring tmpArg = ""; vstring errorLine = ""; vstring keyword = ""; vstring cmdList = ""; FILE *tmpFp; let(&cmdList,cmdList1); /* In case cmdList1 gets deallocated when it comes directly from a vstring function such as cat() */ let(&errorLine, cat(commandPrompt,commandLine, NULL)); /* Handle special case - integer expected */ if (cmdList[0] == '#') { let(&defaultCmd, seg(cmdList,instr(1,cmdList, "<"),instr(1,cmdList, ">"))); /* If the argument has not been entered, prompt the user for it */ if (rawArgs <= arg) { pntrLet(&rawArgPntr, pntrAddElement(rawArgPntr)); nmbrLet(&rawArgNmbr, nmbrAddElement(rawArgNmbr, 0)); rawArgs++; if (rawArgs <= arg) bug(1103); queryMode = 1; tmpArg = cmdInput1(right(cmdList,3)); let(&errorLine,right(cmdList,3)); if (tmpArg[0] == 0) { /* Use default argument */ let(&tmpArg, seg(defaultCmd,2,len(defaultCmd) - 1)); } let((vstring *)(&rawArgPntr[arg]), tmpArg); rawArgNmbr[arg] = len(cmdList) - 1;/* Line position for error msgs */ } /* End of asking user for additional argument */ /* Make sure that the argument is a non-negative integer */ let(&tmpArg,rawArgPntr[arg]); if (tmpArg[0] == 0) { /* Use default argument */ /* (This code is needed in case of null string passed directly) */ let(&tmpArg, seg(defaultCmd,2,len(defaultCmd) - 1)); } let(&tmpStr, str(val(tmpArg))); let(&tmpStr, cat(string(len(tmpArg)-len(tmpStr),'0'), tmpStr, NULL)); if (strcmp(tmpStr, tmpArg)) { printCommandError(errorLine, arg, "?A number was expected here."); goto return0; } let(&keyword, str(val(tmpArg))); goto return1; } /* Handle special case - any arbitrary string is OK */ /* '*' means any string, '&' means a file */ /* However, "|$<$>" also allows null string (no argument) */ if (cmdList[0] == '*' || cmdList[0] == '&') { let(&defaultCmd, seg(cmdList,instr(1,cmdList, "<"),instr(1,cmdList, ">"))); /* If the argument has not been entered, prompt the user for it */ if (rawArgs <= arg) { if (!strcmp(defaultCmd, "<$>")) { /* End of command acceptable */ /* Note: in this case, user will never be prompted for anything. */ let(&keyword,chr(3)); goto return1; } rawArgs++; pntrLet(&rawArgPntr, pntrAddElement(rawArgPntr)); nmbrLet(&rawArgNmbr, nmbrAddElement(rawArgNmbr, 0)); if (rawArgs <= arg) bug(1104); queryMode = 1; tmpArg = cmdInput1(right(cmdList,3)); /* Strip off any quotes around it and tolerate lack of trailing quote */ /******* (This is no longer done - it is confusing to the user.) if (tmpArg[0] == '\'' || tmpArg[0] == '\"') { if (tmpArg[0] == tmpArg[len(tmpArg) - 1]) { let(&tmpArg, right(left(tmpArg, len(tmpArg) - 1), 2)); } else { let(&tmpArg, right(tmpArg, 2)); } } *******/ let(&errorLine,right(cmdList,3)); if (tmpArg[0] == 0) { /* Use default argument */ let(&tmpArg, seg(defaultCmd,2,len(defaultCmd) - 1)); } let((vstring *)(&rawArgPntr[arg]), tmpArg); rawArgNmbr[arg] = len(cmdList) - 1; /* Line position for error msgs */ } /* End of asking user for additional argument */ let(&keyword,rawArgPntr[arg]); /* 1-Nov-2013 nm */ /* Convert abbreviations of FIRST, LAST, ALL to full keywords. The rest of the program works fine without doing this, but it provides better cosmetic appearance when the command is echoed such as in during the UNDO command. */ if (cmdList[0] == '*') { if ((keyword[0] == 'f' || keyword[0] == 'F') && instr(1, cmdList, " FIRST") != 0) let(&keyword, "FIRST"); if ((keyword[0] == 'l' || keyword[0] == 'L') && instr(1, cmdList, " LAST") != 0) let(&keyword, "LAST"); if ((keyword[0] == 'a' || keyword[0] == 'A') && instr(1, cmdList, " ALL") != 0) let(&keyword, "ALL"); } if (keyword[0] == 0) { /* Use default argument */ /* This case handles blank arguments on completely input command line */ let(&keyword, seg(defaultCmd,2,len(defaultCmd) - 1)); } if (cmdList[0] == '&') { /* See if file exists */ let(&tmpStr, cat(rootDirectory, keyword, NULL)); /* 9-Jan-2018 nm */ tmpFp = fopen(tmpStr, "r"); if (!tmpFp) { let(&tmpStr, cat( /*"?Sorry, couldn't open the file \"", keyword, "\".", NULL));*/ "?Sorry, couldn't open the file \"", tmpStr, "\".", NULL)); /* 9-Jan-2018 nm */ printCommandError(errorLine, arg, tmpStr); goto return0; } fclose(tmpFp); } goto return1; } /* Parse the choices available */ possCmds = 0; p = 0; while (1) { q = p; p = instr(p + 1, cat(cmdList, "|", NULL), "|"); if (!p) break; pntrLet(&possCmd,pntrAddElement(possCmd)); let((vstring *)(&possCmd[possCmds]),seg(cmdList,q+1,p-1)); possCmds++; } if (!strcmp(left(possCmd[possCmds - 1],1), "<")) { /* Get default argument, if any */ defaultCmd = possCmd[possCmds - 1]; /* re-use old allocation */ if (!strcmp(defaultCmd, "<$>")) { let(&defaultCmd, ""); } pntrLet(&possCmd,pntrLeft(possCmd,possCmds - 1)); possCmds--; } if (!strcmp(possCmd[possCmds - 1], "$")) { /* Change "$" to "nothing" for printouts */ let((vstring *)(&possCmd[possCmds - 1]), "nothing"); } /* Create a string used for queries and error messages */ if (possCmds < 1) bug(1105); if (possCmds == 1) { let(&infoStr,possCmd[0]); } if (possCmds == 2) { let(&infoStr, cat(possCmd[0], " or ", possCmd[1], NULL)); } if (possCmds > 2) { let(&infoStr, ""); for (i = 0; i < possCmds - 1; i++) { let(&infoStr, cat(infoStr,possCmd[i], ", ", NULL)); } let(&infoStr, cat(infoStr, "or ",possCmd[possCmds - 1], NULL)); } /* If the argument has not been entered, prompt the user for it */ if (rawArgs <= arg && (strcmp(possCmd[possCmds - 1], "nothing") || queryMode == 1)) { let(&tmpStr, infoStr); if (defaultCmd[0] != 0) { let(&tmpStr, cat(tmpStr, " ",defaultCmd, NULL)); } let(&tmpStr, cat(tmpStr, "? ", NULL)); queryMode = 1; if (possCmds != 1) { tmpArg = cmdInput1(tmpStr); } else { /* There is only one possibility, so don't ask user */ /* Don't print the message when "end-of-list" is the only possibility. */ if (!strcmp(cmdList, "$|<$>")) { let(&tmpArg, possCmd[0]); print2("The command so far is: "); for (i = 0; i < arg; i++) { print2("%s ", fullArg[i]); } print2("%s\n", tmpArg); } } let(&errorLine,tmpStr); if (tmpArg[0] == 0) { /* Use default argument */ let(&tmpArg, seg(defaultCmd,2,len(defaultCmd) - 1)); } if (strcmp(tmpArg, "nothing")) { pntrLet(&rawArgPntr, pntrAddElement(rawArgPntr)); nmbrLet(&rawArgNmbr, nmbrAddElement(rawArgNmbr, 0)); rawArgs++; if (rawArgs <= arg) bug(1106); let((vstring *)(&rawArgPntr[arg]), tmpArg); rawArgNmbr[arg] = len(tmpStr) + 1; /* Line position for error msgs */ } } /* End of asking user for additional argument */ if (rawArgs <= arg) { /* No argument was specified, and "nothing" is a valid argument */ let(&keyword,chr(3)); goto return1; } let(&tmpArg,edit(rawArgPntr[arg], 32)); /* Convert to upper case */ j = 0; k = 0; m = len(tmpArg); let(&tmpStr, ""); /* Scan the possible arguments for a match */ for (i = 0; i < possCmds; i++) { if (!strcmp(possCmd[i], tmpArg)) { /* An exact match was found, so ignore any other matches and use this one */ k = 1; j = i; break; } if (!strcmp(left(possCmd[i], m), tmpArg)) { if (!k) { let(&tmpStr, possCmd[i]); } else { let(&tmpStr, cat(tmpStr, ", ", possCmd[i], NULL)); } j = i; /* Save match position */ k++; /* Number of matches */ } } if (k < 1 || k > 1) { if (k < 1) { let(&tmpStr, cat("?Expected ", infoStr, ".", NULL)); } else { if (k == 2) { p = instr(1,tmpStr, ", "); let(&tmpStr, cat(left(tmpStr,p-1), " or",right(tmpStr,p+1), NULL)); } else { p = len(tmpStr) - 1; while (tmpStr[p] != ',') p--; let(&tmpStr, cat(left(tmpStr,p+1), " or",right(tmpStr,p+2), NULL)); } let(&tmpStr, cat("?Ambiguous keyword - please specify ",tmpStr, ".", NULL)); } printCommandError(errorLine, arg, tmpStr); goto return0; } let(&keyword,possCmd[j]); goto return1; return1: if (keyword[0] == 0) { if (rawArgs > arg && strcmp(defaultCmd, "<>")) { /* otherwise, "nothing" was specified */ printCommandError("", arg, "?No default answer is available - please be explicit."); goto return0; } } /* Add new field to fullArg */ pntrLet(&fullArg,pntrAddElement(fullArg)); if (pntrLen(fullArg) != arg + 1) bug(1107); let((vstring *)(&fullArg[arg]),keyword); /* Deallocate memory */ j = pntrLen(possCmd); for (i = 0; i < j; i++) let((vstring *)(&possCmd[i]), ""); pntrLet(&possCmd, NULL_PNTRSTRING); let(&defaultCmd, ""); let(&infoStr, ""); let(&tmpStr, ""); let(&tmpArg, ""); let(&errorLine, ""); let(&keyword, ""); let(&cmdList, ""); return(1); return0: /* Deallocate memory */ j = pntrLen(possCmd); for (i = 0; i < j; i++) let((vstring *)(&possCmd[i]), ""); pntrLet(&possCmd, NULL_PNTRSTRING); let(&defaultCmd, ""); let(&infoStr, ""); let(&tmpStr, ""); let(&tmpArg, ""); let(&errorLine, ""); let(&keyword, ""); let(&cmdList, ""); return(0); } /* getFullArg */ void parseCommandLine(vstring line) { /* This function breaks up line into individual tokens and puts them into rawArgPntr[]. rawArgs is the number of tokens. rawArgPntr[] is the starting position of each token on the line; the first character on the line has position 1, not 0. Spaces, tabs, and newlines are considered white space. Special one-character tokens don't have to be surrounded by white space. Characters inside quotes are considered to be one token, and the quotes are removed. */ /* Warning: Don't deallocate these vstring constants */ /*vstring specialOneCharTokens = "()/,=:";*/ vstring tokenWhiteSpace = " \t\n"; vstring tokenComment = "!"; vstring tmpStr = ""; /* Dummy vstring to clean up temp alloc stack */ flag mode; long tokenStart, i, p, lineLen; vstring specialOneCharTokens = ""; /* Initialization to avoid compiler warning (should not be theoretically necessary) */ tokenStart = 0; if (!toolsMode) { /* 5-Nov-99: We only really need / and = Took out the others so user will have less need to put quotes around e.g. single tokens in SEARCH command let(&specialOneCharTokens, "()/,=:"); */ let(&specialOneCharTokens, "/="); /* List of special one-char tokens */ } else { let(&specialOneCharTokens, ""); } lineLen = len(line); /* mode: 0 means look for start of token, 1 means look for end of token, 2 means look for trailing single quote, 3 means look for trailing double quote */ /* 2/20/99 - only "!" at beginning of line now acts as comment - This was done because sometimes ! might be legal as part of a command */ mode = 0; for (p = 0; p < lineLen; p++) { let(&tmpStr, ""); /* Clean up temp alloc stack to prevent overflow */ if (mode == 0) { /* If character is white space, ignore it */ if (instr(1,tokenWhiteSpace,chr(line[p]))) { continue; } /* If character is comment, we're done */ if (p == 0 && /* 2/20/99 */ instr(1,tokenComment,chr(line[p]))) { break; } /* If character is a special token, get it but don't change mode */ if (instr(1,specialOneCharTokens,chr(line[p]))) { pntrLet(&rawArgPntr, pntrAddElement(rawArgPntr)); nmbrLet(&rawArgNmbr, nmbrAddElement(rawArgNmbr, p+1)); /* Save token start */ let((vstring *)(&rawArgPntr[rawArgs]), chr(line[p])); rawArgs++; continue; } /* If character is a quote, set start and change mode */ if (line[p] == '\'') { mode = 2; tokenStart = p + 2; continue; } if (line[p] == '\"') { mode = 3; tokenStart = p + 2; continue; } /* Character must be start of a token */ mode = 1; tokenStart = p + 1; continue; } if (mode == 1) { /* If character is white space, end token and change mode */ if (instr(1,tokenWhiteSpace,chr(line[p]))) { pntrLet(&rawArgPntr, pntrAddElement(rawArgPntr)); nmbrLet(&rawArgNmbr, nmbrAddElement(rawArgNmbr, tokenStart)); /* Save token start */ let((vstring *)(&rawArgPntr[rawArgs]), seg(line, tokenStart, p)); rawArgs++; mode = 0; continue; } /* If character is comment, we're done */ /* 2/20/99 - see above if (instr(1,tokenComment,chr(line[p]))) { pntrLet(&rawArgPntr, pntrAddElement(rawArgPntr)); nmbrLet(&rawArgNmbr, nmbrAddElement(rawArgNmbr, tokenStart)); let((vstring *)(&rawArgPntr[rawArgs]), seg(line,tokenStart,p)); rawArgs++; mode = 0; break; } 2/20/99 */ /* If character is a special token, get it and change mode */ if (instr(1,specialOneCharTokens,chr(line[p]))) { pntrLet(&rawArgPntr, pntrAddElement(rawArgPntr)); nmbrLet(&rawArgNmbr, nmbrAddElement(rawArgNmbr, tokenStart)); /* Save token start */ let((vstring *)(&rawArgPntr[rawArgs]),seg(line, tokenStart, p)); rawArgs++; pntrLet(&rawArgPntr, pntrAddElement(rawArgPntr)); nmbrLet(&rawArgNmbr, nmbrAddElement(rawArgNmbr, p + 1)); /* Save token start */ let((vstring *)(&rawArgPntr[rawArgs]), chr(line[p])); rawArgs++; mode = 0; continue; } /* If character is a quote, set start and change mode */ if (line[p] == '\'') { pntrLet(&rawArgPntr, pntrAddElement(rawArgPntr)); nmbrLet(&rawArgNmbr, nmbrAddElement(rawArgNmbr, tokenStart)); /* Save token start */ let((vstring *)(&rawArgPntr[rawArgs]),seg(line, tokenStart,p)); rawArgs++; mode = 2; tokenStart = p + 2; continue; } if (line[p] == '\"') { pntrLet(&rawArgPntr, pntrAddElement(rawArgPntr)); nmbrLet(&rawArgNmbr, nmbrAddElement(rawArgNmbr, tokenStart)); /* Save token start */ let((vstring *)(&rawArgPntr[rawArgs]),seg(line, tokenStart,p)); rawArgs++; mode = 3; tokenStart = p + 2; continue; } /* Character must be continuation of the token */ continue; } if (mode == 2 || mode == 3) { /* If character is a quote, end quote and change mode */ if (line[p] == '\'' && mode == 2) { mode = 0; pntrLet(&rawArgPntr, pntrAddElement(rawArgPntr)); nmbrLet(&rawArgNmbr, nmbrAddElement(rawArgNmbr, tokenStart)); /* Save token start */ let((vstring *)(&rawArgPntr[rawArgs]), seg(line,tokenStart,p)); rawArgs++; continue; } if (line[p] == '\"' && mode == 3) { mode = 0; pntrLet(&rawArgPntr, pntrAddElement(rawArgPntr)); nmbrLet(&rawArgNmbr, nmbrAddElement(rawArgNmbr, tokenStart)); /* Save token start */ let((vstring *)(&rawArgPntr[rawArgs]),seg(line, tokenStart,p)); rawArgs++; continue; } /* Character must be continuation of quoted token */ continue; } } /* Finished scanning the line. Finish processing last token. */ if (mode != 0) { pntrLet(&rawArgPntr, pntrAddElement(rawArgPntr)); nmbrLet(&rawArgNmbr, nmbrAddElement(rawArgNmbr, tokenStart)); /* Save token start */ let((vstring *)(&rawArgPntr[rawArgs]),seg(line,tokenStart,p)); rawArgs++; } /* Add length of command line prompt to each argument, to align the error message pointer */ for (i = 0; i < rawArgs; i++) { rawArgNmbr[i] = rawArgNmbr[i] + len(commandPrompt); } /* Deallocate */ let(&specialOneCharTokens, ""); } /* parseCommandLine */ flag lastArgMatches(vstring argString) { /* This functions checks to see if the last field was argString */ if (!strcmp(argString, fullArg[pntrLen(fullArg)-1])) { return (1); } else { return (0); } } /* lastArgMatches */ flag cmdMatches(vstring cmdString) { /* This function checks that fields 0 through n of fullArg match cmdString (separated by spaces). */ long i, j, k; vstring tmpStr = ""; /* Count the number of spaces */ k = len(cmdString); j = 0; for (i = 0; i < k; i++) { if (cmdString[i] == ' ') j++; } k = pntrLen(fullArg); for (i = 0; i <= j; i++) { if (j >= k) { /* Command to match is longer than the user's command; assume no match */ let(&tmpStr, ""); return (0); } let(&tmpStr, cat(tmpStr, " ", fullArg[i], NULL)); } if (!strcmp(cat(" ", cmdString, NULL), tmpStr)) { let(&tmpStr, ""); return (1); } else { let(&tmpStr, ""); return (0); } } /* cmdMatches */ long switchPos(vstring swString) { /* This function checks that fields i through j of fullArg match swString (separated by spaces). The first character of swString should be "/" and must be separated from the first field of swString with a space. The position of the "/" in fullArg is returned if swString is there, otherwise 0 is returned (the first position in fullArg is considered 1, not 0). */ /* Example: if fullArg (combined into one string) is "DISPLAY PROOF / UNKNOWN / START_STEP = 10 / ESSENTIAL" and swString is "/ START_STEP", switchPos will return 5. */ long i, j, k; vstring tmpStr = ""; vstring swString1 = ""; if (swString[0] != '/') bug(1108); /* Add a space after the "/" if there is none */ if (swString[1] != ' ') { let(&swString1, cat("/ ", right(swString,2), " ", NULL)); } else { let(&swString1,swString); } /* Build the complete command */ k = pntrLen(fullArg); for (i = 0; i < k; i++) { let(&tmpStr, cat(tmpStr,fullArg[i], " ", NULL)); } k = instr(1,tmpStr,swString1); if (!k) { let(&swString1, ""); let(&tmpStr, ""); return (0); } let(&tmpStr,left(tmpStr,k)); /* Count the number of spaces - it will be the fullArg position */ k = len(tmpStr); j = 0; for (i = 0; i < k; i++) { if (tmpStr[i] == ' ') j++; } let(&tmpStr, ""); let(&swString1, ""); return (j + 1); } /* switchPos */ void printCommandError(vstring line1, long arg, vstring errorMsg) { /* Warning: errorMsg should not a temporarily allocated string such as the direct output of cat() */ vstring errorPointer = ""; vstring line = ""; long column, tokenLength, j; let(&line,line1); /* Prevent deallocation in case line1 is direct return from string function such as cat() */ if (!line[0]) { /* Empty line - don't print an error pointer */ print2("%s\n", errorMsg); let(&line, ""); return; } column = rawArgNmbr[arg]; tokenLength = len(rawArgPntr[arg]); for (j = 0; j < column - 1; j++) { /* Make sure that tabs on the line with the error are accounted for so that the error pointer lines up correctly */ if (j >= len(line)) bug(1109); if (line[j] == '\t') { let(&errorPointer, cat(errorPointer, "\t", NULL)); } else { if (line[j] == '\n') { let(&errorPointer, ""); } else { let(&errorPointer, cat(errorPointer, " ", NULL)); } } } for (j = 0; j < tokenLength; j++) let(&errorPointer, cat(errorPointer, "^", NULL)); print2("%s\n", errorPointer); printLongLine(errorMsg, "", " "); let(&errorPointer, ""); let(&line, ""); } /* printCommandError */ /* 4-May-2017 Ari Ferrera */ void freeCommandLine() { long i, j; j = pntrLen(rawArgPntr); for (i = 0; i < j; i++) let((vstring *)(&rawArgPntr[i]), ""); j = pntrLen(fullArg); for (i = 0; i < j; i++) let((vstring *)(&fullArg[i]), ""); pntrLet(&fullArg, NULL_PNTRSTRING); pntrLet(&rawArgPntr, NULL_PNTRSTRING); nmbrLet(&rawArgNmbr, NULL_NMBRSTRING); let(&fullArgString, ""); } metamath-exe-master/mmcmdl.h000066400000000000000000000037351357377637100164030ustar00rootroot00000000000000/*****************************************************************************/ /* Copyright (C) 2018 NORMAN MEGILL nm at alum.mit.edu */ /* License terms: GNU General Public License */ /*****************************************************************************/ /*34567890123456 (79-character line to adjust editor window) 2345678901234567*/ #ifndef METAMATH_MMCMDL_H_ #define METAMATH_MMCMDL_H_ #include "mmvstr.h" #include "mmdata.h" flag processCommandLine(void); flag getFullArg(long arg, vstring cmdList); void parseCommandLine(vstring line); flag lastArgMatches(vstring argString); flag cmdMatches(vstring cmdString); long switchPos(vstring swString); void printCommandError(vstring line, long arg, vstring errorMsg); void freeCommandLine(void); /* 4-May-2017 Ari Ferrera */ #define DEFAULT_COLUMN 16 extern pntrString *rawArgPntr; extern nmbrString *rawArgNmbr; extern long rawArgs; extern pntrString *fullArg; extern vstring fullArgString; /* 1-Nov-2013 nm fullArg as one string */ extern vstring commandPrompt; extern vstring commandLine; extern long showStatement; extern vstring logFileName; extern vstring texFileName; extern flag PFASmode; /* Proof assistant mode, invoked by PROVE command */ extern flag queryMode; /* If 1, explicit questions will be asked even if a field in the input command line is optional */ extern flag sourceChanged; /* Flag that user made some change to the source file*/ extern flag proofChanged; /* Flag that user made some change to proof in progress*/ extern flag commandEcho; /* Echo full command */ extern flag memoryStatus; /* Always show memory */ /* 31-Dec-2017 nm */ extern flag sourceHasBeenRead; /* 1 if a source file has been read in */ /* 31-Dec-2017 nm */ extern vstring rootDirectory; /* Directory to use for included files */ #endif /* METAMATH_MMCMDL_H_ */ metamath-exe-master/mmcmds.c000066400000000000000000007021011357377637100163760ustar00rootroot00000000000000/*****************************************************************************/ /* Copyright (C) 2018 NORMAN MEGILL nm at alum.mit.edu */ /* License terms: GNU General Public License */ /*****************************************************************************/ /*34567890123456 (79-character line to adjust editor window) 2345678901234567*/ /* mmcmds.c - assorted user commands */ #include #include #include #include #include #include #include /* 28-May-04 nm For clock() */ #include "mmvstr.h" #include "mmdata.h" #include "mmcmdl.h" /* For texFileName */ #include "mmcmds.h" #include "mminou.h" #include "mmpars.h" #include "mmveri.h" #include "mmwtex.h" /* For htmlVarColor,... */ #include "mmpfas.h" #include "mmunif.h" /* 26-Sep-2010 nm For bracketMatchInit, minSubstLen */ /* 1-Oct-2017 nm ...and firstConst */ /* 12-Nov-2018 nm */ /* Local prototypes */ vstring bigAdd(vstring bignum1, vstring bignum2); vstring bigSub(vstring bignum1, vstring bignum2); /* vstring mainFileName = ""; */ /* 28-Dec-05 nm Obsolete */ flag printHelp = 0; /* For HTML output */ vstring printStringForReferencedBy = ""; /* For MIDI */ flag midiFlag = 0; vstring midiParam = ""; /* Type (i.e. print) a statement */ void typeStatement(long showStmt, flag briefFlag, flag commentOnlyFlag, flag texFlag, flag htmlFlg) { /* From HELP SHOW STATEMENT: Optional qualifiers: / TEX - This qualifier will write the statement information to the LaTeX file previously opened with OPEN TEX. [Note: texFlag=1 and htmlFlg=0 with this qualifier.] / HTML - This qualifier will write the statement information to the HTML file previously opened with OPEN HTML. [Note: texFlag=1 and htmlFlg=1 with this qualifier.] / COMMENT_ONLY - This qualifier will show only the comment that immediatley precedes the statement. This is useful when you are using Metamath to preprocess LaTeX source you have created (see HELP TEX) / BRIEF - This qualifier shows the statement and its $e hypotheses only. */ long i, j, k, m, n; vstring str1 = "", str2 = "", str3 = ""; nmbrString *nmbrTmpPtr1; /* Pointer only; not allocated directly */ nmbrString *nmbrTmpPtr2; /* Pointer only; not allocated directly */ nmbrString *nmbrDDList = NULL_NMBRSTRING; flag q1, q2; flag type; flag subType; vstring htmlDistinctVars = ""; /* 12/23/01 */ char htmlDistinctVarsCommaFlag = 0; /* 12/23/01 */ vstring str4 = ""; /* 10/10/02 */ vstring str5 = ""; /* 19-Sep-2012 nm */ long distVarGrps = 0; /* 11-Aug-2006 nm */ /* For syntax breakdown of definitions in HTML page */ long zapStatement1stToken; static long wffToken = -1; /* array index of the hard-coded token "wff" - static so we only have to look it up once - set to -2 if not found */ subType = 0; /* Assign to prevent compiler warnings - not theor. necessary */ if (!showStmt) bug(225); /* Must be 1 or greater */ if (!commentOnlyFlag && !briefFlag) { assignStmtFileAndLineNum(showStmt); /* 9-Jan-2018 nm */ let(&str1, cat("Statement ", str((double)showStmt), " is located on line ", str((double)(statement[showStmt].lineNum)), " of the file ", NULL)); if (!texFlag) { printLongLine(cat(str1, "\"", statement[showStmt].fileName, "\".", /* 8-Feb-2007 nm Added HTML page info to SHOW STATEMENT ... /FULL */ (statement[showStmt].pinkNumber == 0) ? /* !=0 means $a or $p */ "" : cat(" Its statement number for HTML pages is ", str((double)(statement[showStmt].pinkNumber)), ".", NULL), NULL), "", " "); } else { if (!htmlFlg) let(&printString, ""); outputToString = 1; /* Flag for print2 to add to printString */ /* Note that printTexLongMathString resets it */ if (!(htmlFlg && texFlag)) { /* printLongLine(cat(str1, "{\\tt ", asciiToTt(statement[showStmt].fileName), "}.", NULL), "", " "); */ } else { /* For categorizing html pages, we use the source file convention that syntax statements don't start with "|-" and that axioms have labels starting with "ax-". It is up to the database creator to follow this standard, which is not enforced. */ #define SYNTAX 1 #define DEFINITION 2 #define AXIOM 3 #define THEOREM 4 if (statement[showStmt].type == (char)p_) { subType = THEOREM; } else { /* Must be a_ due to filter in main() */ if (statement[showStmt].type != (char)a_) bug(228); if (strcmp("|-", mathToken[ (statement[showStmt].mathString)[0]].tokenName)) { subType = SYNTAX; } else { if (!strcmp("ax-", left(statement[showStmt].labelName, 3))) { subType = AXIOM; } else { subType = DEFINITION; } } } switch (subType) { case SYNTAX: let(&str1, "Syntax Definition"); break; case DEFINITION: let(&str1, "Definition"); break; case AXIOM: let(&str1, "Axiom"); break; case THEOREM: let(&str1, "Theorem"); break; default: bug(229); } /* Print a small pink statement number after the statement */ let(&str2, ""); str2 = pinkHTML(showStmt); printLongLine(cat("
", str1, " ", statement[showStmt].labelName, "", str2, "
", NULL), "", "\""); } /* (htmlFlg && texFlag) */ outputToString = 0; } /* texFlag */ } if (!briefFlag || commentOnlyFlag) { let(&str1, ""); str1 = getDescription(showStmt); if (!str1[0] /* No comment */ #ifdef DATE_BELOW_PROOF /* 12-May-2017 nm */ || (str1[0] == '[' && str1[strlen(str1) - 1] == ']') /* 7-Sep-04 Allow both "$([])$" and "$( [] )$" */ || (strlen(str1) > 1 && str1[1] == '[' && str1[strlen(str1) - 2] == ']') /* Make sure getDescription() didn't pick up date stamp from previous proof */ #endif /* 12-May-2017 nm */ ) { print2("?Warning: Statement \"%s\" has no comment\n", statement[showStmt].labelName); /* 14-Sep-2010 nm We must print a blank comment to have \begin{lemma} */ if (texFlag && !htmlFlg && !oldTexFlag) { let(&str1, "TO DO: PUT DESCRIPTION HERE"); } } if (str1[0]) { if (!texFlag) { printLongLine(cat("\"", str1, "\"", NULL), "", " "); } else { /* 10/10/02 This is now done in mmwtex.c printTexComment */ /* Although it will affect the 2nd (and only other) call to printTexComment below, that call is obsolete and there should be no side effect. */ /******* if (htmlFlg && texFlag) { let(&str1, cat("
Description: ", str1, "

", NULL)); } *******/ if (!htmlFlg) { /* LaTeX */ if (!oldTexFlag) { /* 14-Sep-2010 */ /* 1-May-2017 nm */ /* Distinguish axiom, definition, theorem */ /* Note: changes here must be mirrored in the \end{...} below */ if (statement[showStmt].type == a_) { if (!strcmp(left(statement[showStmt].labelName, 3), "ax-")) { let(&str3, "axiom"); } else { let(&str3, "definition"); } } else { let(&str3, "theorem"); } let(&str1, cat("\\begin{", str3, "}\\label{", left(str3, 3), ":", statement[showStmt].labelName, "} ", str1, NULL)); /* old code before 1-May-2017: let(&str1, cat("\\begin{lemma}\\label{lem:", statement[showStmt].labelName, "} ", str1, NULL)); */ } else { /* 6-Dec-03 Add separation space between theorems */ let(&str1, cat("\n\\vspace{1ex} %2\n\n", str1, NULL)); } } /* printTexComment(str1, 1); */ /* 17-Nov-2015 nm Add 3rd & 4th arguments */ printTexComment(str1, /* Sends result to texFilePtr */ 1, /* 1 = htmlCenterFlag */ PROCESS_EVERYTHING, /* actionBits */ /* 13-Dec-2018 nm */ 0 /* 1 = noFileCheck */); } } } if (commentOnlyFlag && !briefFlag) goto returnPoint; if ((briefFlag && !texFlag) || (htmlFlg && texFlag) /* HTML page 12/23/01 */) { /* In BRIEF mode screen output, show $d's */ /* This section was added 8/31/99 */ /* 12/23/01 - added algorithm to HTML pages also; the string to print out is stored in htmlDistinctVars for later printing */ /* 12/23/01 */ if (htmlFlg && texFlag) { let(&htmlDistinctVars, ""); htmlDistinctVarsCommaFlag = 0; } /* Note added 22-Aug-04: This algorithm is used to re-merge $d pairs into groups of 3 or more when possible, for a more compact display. The algorithm does not merge groups optimally, but it should be adequate. For example, in set.mm (e.g. old r19.23aivv): $d x ps $. $d y ps $. $d y A $. $d x y $. produces in SHOW STATEMENT (note redundant 3rd $d): $d ps x y $. $d y A $. $d x y $. However, in set.mm the equivalent (and better anyway): $d x y ps $. $d y A $. produces the same thing when remerged in SHOW STATEMENT. */ let(&str1, ""); nmbrTmpPtr1 = statement[showStmt].reqDisjVarsA; nmbrTmpPtr2 = statement[showStmt].reqDisjVarsB; i = nmbrLen(nmbrTmpPtr1); if (i /* Number of mandatory $d pairs */) { nmbrLet(&nmbrDDList, NULL_NMBRSTRING); for (k = 0; k < i; k++) { /* Is one of the variables in the current list? */ if (!nmbrElementIn(1, nmbrDDList, nmbrTmpPtr1[k]) && !nmbrElementIn(1, nmbrDDList, nmbrTmpPtr2[k])) { /* No, so close out the current list */ if (!(htmlFlg && texFlag)) { /* 12/23/01 */ if (k == 0) let(&str1, "$d"); else let(&str1, cat(str1, " $. $d", NULL)); } else { /* 12/23/01 */ let(&htmlDistinctVars, cat(htmlDistinctVars, "   ", NULL)); htmlDistinctVarsCommaFlag = 0; distVarGrps++; /* 11-Aug-2006 nm */ } nmbrLet(&nmbrDDList, NULL_NMBRSTRING); } /* Are both variables required to be distinct from all others in current list? */ for (n = 0; n < nmbrLen(nmbrDDList); n++) { if (nmbrDDList[n] != nmbrTmpPtr1[k] && nmbrDDList[n] != nmbrTmpPtr2[k]) { q1 = 0; q2 = 0; for (m = 0; m < i; m++) { if ((nmbrTmpPtr1[m] == nmbrDDList[n] && nmbrTmpPtr2[m] == nmbrTmpPtr1[k]) || (nmbrTmpPtr2[m] == nmbrDDList[n] && nmbrTmpPtr1[m] == nmbrTmpPtr1[k])) { q1 = 1; /* 1st var is required to be distinct */ } if ((nmbrTmpPtr1[m] == nmbrDDList[n] && nmbrTmpPtr2[m] == nmbrTmpPtr2[k]) || (nmbrTmpPtr2[m] == nmbrDDList[n] && nmbrTmpPtr1[m] == nmbrTmpPtr2[k])) { q2 = 1; /* 2nd var is required to be distinct */ } if (q1 && q2) break; /* Found both */ } /* Next m */ if (!q1 || !q2) { /* One of the variables is not required to be distinct from all others in the current list, so close out current list */ if (!(htmlFlg && texFlag)) { if (k == 0) let(&str1, "$d"); else let(&str1, cat(str1, " $. $d", NULL)); } else { /* 12/23/01 */ let(&htmlDistinctVars, cat(htmlDistinctVars, "   ", NULL)); htmlDistinctVarsCommaFlag = 0; distVarGrps++; /* 11-Aug-2006 nm */ } nmbrLet(&nmbrDDList, NULL_NMBRSTRING); break; /* Out of n loop */ } } /* If $d var in current list is not same as one we're adding */ } /* Next n */ /* If the variable is not already in current list, add it */ if (!nmbrElementIn(1, nmbrDDList, nmbrTmpPtr1[k])) { if (!(htmlFlg && texFlag)) { let(&str1, cat(str1, " ", mathToken[nmbrTmpPtr1[k]].tokenName, NULL)); } else { /* 12/23/01 */ if (htmlDistinctVarsCommaFlag) { let(&htmlDistinctVars, cat(htmlDistinctVars, ",", NULL)); } htmlDistinctVarsCommaFlag = 1; let(&str2, ""); str2 = tokenToTex(mathToken[nmbrTmpPtr1[k]].tokenName, showStmt); /* tokenToTex allocates str2; we must deallocate it */ let(&htmlDistinctVars, cat(htmlDistinctVars, str2, NULL)); } nmbrLet(&nmbrDDList, nmbrAddElement(nmbrDDList, nmbrTmpPtr1[k])); } if (!nmbrElementIn(1, nmbrDDList, nmbrTmpPtr2[k])) { if (!(htmlFlg && texFlag)) { let(&str1, cat(str1, " ", mathToken[nmbrTmpPtr2[k]].tokenName, NULL)); } else { /* 12/23/01 */ if (htmlDistinctVarsCommaFlag) { let(&htmlDistinctVars, cat(htmlDistinctVars, ",", NULL)); } htmlDistinctVarsCommaFlag = 1; let(&str2, ""); str2 = tokenToTex(mathToken[nmbrTmpPtr2[k]].tokenName, showStmt); /* tokenToTex allocates str2; we must deallocate it */ let(&htmlDistinctVars, cat(htmlDistinctVars, str2, NULL)); } nmbrLet(&nmbrDDList, nmbrAddElement(nmbrDDList, nmbrTmpPtr2[k])); } } /* Next k */ /* Close out entire list */ if (!(htmlFlg && texFlag)) { let(&str1, cat(str1, " $.", NULL)); printLongLine(str1, " ", " "); } else { /* 12/23/01 */ /* (do nothing) */ /*let(&htmlDistinctVars, cat(htmlDistinctVars, "
", NULL));*/ } } /* if i(#$d's) > 0 */ } if (briefFlag || texFlag /*(texFlag && htmlFlg)*/) { /* 6-Dec-03 */ /* For BRIEF mode, print $e hypotheses (only) before statement */ /* Also do it for HTML output */ /* 6-Dec-03 For the LaTeX output, now print hypotheses before statement */ j = nmbrLen(statement[showStmt].reqHypList); k = 0; for (i = 0; i < j; i++) { /* Count the number of essential hypotheses */ if (statement[statement[showStmt].reqHypList[i]].type == (char)e_) k++; /* Added 5/26/03 */ /* For syntax definitions, also include $f hypotheses so user can more easily match them in syntax breakdowns of axioms and definitions */ if (subType == SYNTAX && (texFlag && htmlFlg)) { if (statement[statement[showStmt].reqHypList[i]].type == (char)f_) k++; } } if (k) { if (texFlag) { /* Note that printTexLongMath resets it to 0 */ outputToString = 1; } if (texFlag && htmlFlg) { print2("
\n", (k == 1) ? "Hypothesis" : "Hypotheses"); print2("\n", (k == 1) ? "Hypothesis" : "Hypotheses"); print2("\n"); } for (i = 0; i < j; i++) { k = statement[showStmt].reqHypList[i]; if (statement[k].type != (char)e_ /* Added 5/26/03 */ /* For syntax definitions, include $f hypotheses so user can more easily match them in syntax breakdowns of axioms & definitions */ && !(subType == SYNTAX && (texFlag && htmlFlg) && statement[k].type == (char)f_) ) continue; if (!texFlag) { let(&str2, cat(str((double)k), " ", NULL)); } else { let(&str2, " "); } let(&str2, cat(str2, statement[k].labelName, " $", chr(statement[k].type), " ", NULL)); if (!texFlag) { printLongLine(cat(str2, nmbrCvtMToVString(statement[k].mathString), " $.", NULL), " "," "); } else { /* if texFlag */ /* texFlag was (misleadingly) included below to facilitate search for "htmlFlg && texFlag". */ if (!(htmlFlg && texFlag)) { if (!oldTexFlag) { /* 14-Sep-2010 nm */ /* Do nothing */ } else { let(&str3, space((long)strlen(str2))); printTexLongMath(statement[k].mathString, str2, str3, 0, 0); } } else { outputToString = 1; print2("
%s
Ref\n"); print2("Expression
%s\n", statement[k].labelName); /* Print hypothesis */ printTexLongMath(statement[k].mathString, "", "", 0, 0); } } } /* next i */ if (texFlag && htmlFlg) { outputToString = 1; print2("
\n"); } } /* if k (#essential hyp) */ } let(&str1, ""); type = statement[showStmt].type; if (type == p_) let(&str1, " $= ..."); if (!texFlag) let(&str2, cat(str((double)showStmt), " ", NULL)); else let(&str2, " "); let(&str2, cat(str2, statement[showStmt].labelName, " $",chr(type), " ", NULL)); if (!texFlag) { printLongLine(cat(str2, nmbrCvtMToVString(statement[showStmt].mathString), str1, " $.", NULL), " ", " "); } else { if (!(htmlFlg && texFlag)) { /* really !htmlFlg & texFlag */ if (!oldTexFlag) { /* 14-Sep-2010 nm new LaTeX code: */ outputToString = 1; print2("\\begin{align}\n"); let(&str3, ""); /* Get HTML hypotheses => assertion */ str3 = getTexOrHtmlHypAndAssertion(showStmt); /* In mmwtex.c */ printLongLine(cat(str3, /* No space before \label to make it easier to find last parenthesis in a post-processing script */ "\\label{eq:", statement[showStmt].labelName, "}", /* 1-May-2017 nm */ /* Add "\tag{..}" to use .mm labels instead of equation numbers */ /* (Suggested by Ari Ferrera) */ "\\tag{", statement[showStmt].labelName, "}", NULL), " ", " "); /* print2(" \\label{eq:%s}\n",statement[showStmt].labelName); */ print2("\\end{align}\n"); /* 1-May-2017 nm */ /* Distinguish axiom, definition, theorem for LaTeX */ /* Note: changes here must be mirrored in the \begin{...} above */ if (statement[showStmt].type == a_) { if (!strcmp(left(statement[showStmt].labelName, 3), "ax-")) { let(&str3, "axiom"); } else { let(&str3, "definition"); } } else { let(&str3, "theorem"); } print2("%s\n", cat("\\end{", str3, "}", NULL)); /* old code before 1-May-2017: print2("\\end{lemma}\n"); */ fprintf(texFilePtr, "%s", printString); let(&printString, ""); outputToString = 0; } else { /* old TeX code */ let(&str3, space((long)strlen(str2))); /* 3rd argument of printTexLongMath cannot be temp allocated */ printTexLongMath(statement[showStmt].mathString, str2, str3, 0, 0); } } else { /* (htmlFlg && texFlag) */ outputToString = 1; print2("
\n"); print2("\n"); print2("\n"); printLongLine(cat( "
Assertion
Ref\n"); print2("Expression
", statement[showStmt].labelName, "", NULL), " ", " "); printTexLongMath(statement[showStmt].mathString, "", "", 0, 0); outputToString = 1; print2("
\n"); } } if (briefFlag) goto returnPoint; /* 6-Dec-03 In the LaTeX output, the hypotheses used to be printed after the statement. Now they are printed before (see above 6-Dec-03 comments), so some code below is commented out. */ switch (type) { case a_: case p_: /* 6-Dec-03 This is not really needed but keeps output consistent with previous version. It puts a blank line before the HTML "distinct variable" list. */ if (texFlag && htmlFlg) { /* 6-Dec-03 */ outputToString = 1; print2("\n"); outputToString = 0; } /*if (!(htmlFlg && texFlag)) {*/ if (!texFlag) { /* 6-Dec-03 fix */ print2("Its mandatory hypotheses in RPN order are:\n"); } /*if (texFlag) outputToString = 0;*/ /* 6-Dec-03 */ j = nmbrLen(statement[showStmt].reqHypList); for (i = 0; i < j; i++) { k = statement[showStmt].reqHypList[i]; if (statement[k].type != (char)e_ && (!htmlFlg && texFlag)) continue; /* 9/2/99 Don't put $f's in LaTeX output */ let(&str2, cat(" ",statement[k].labelName, " $", chr(statement[k].type), " ", NULL)); if (!texFlag) { printLongLine(cat(str2, nmbrCvtMToVString(statement[k].mathString), " $.", NULL), " "," "); } else { if (!(htmlFlg && texFlag)) { /* LaTeX */ /*let(&str3, space((long)strlen(str2)));*/ /* 6-Dec-03 */ /* This clears out printString */ /*printTexLongMath(statement[k].mathString, str2, str3, 0, 0);*/ /* 6-Dec-03 */ } } } /* 6-Dec-03 This is not really needed but keeps output consistent with previous version. It puts a blank line before the HTML "distinct variable" list. */ if (texFlag && htmlFlg) { /* 6-Dec-03 */ outputToString = 1; print2("\n"); outputToString = 0; } /*if (j == 0 && !(htmlFlg && texFlag)) print2(" (None)\n");*/ if (j == 0 && !texFlag) print2(" (None)\n"); /* 6-Dec-03 fix */ let(&str1, ""); nmbrTmpPtr1 = statement[showStmt].reqDisjVarsA; nmbrTmpPtr2 = statement[showStmt].reqDisjVarsB; i = nmbrLen(nmbrTmpPtr1); if (i) { for (k = 0; k < i; k++) { if (!texFlag) { let(&str1, cat(str1, ", <", mathToken[nmbrTmpPtr1[k]].tokenName, ",", mathToken[nmbrTmpPtr2[k]].tokenName, ">", NULL)); } else { if (htmlFlg && texFlag) { let(&str2, ""); str2 = tokenToTex(mathToken[nmbrTmpPtr1[k]].tokenName, showStmt); /* tokenToTex allocates str2; we must deallocate it */ let(&str1, cat(str1, "   ", str2, NULL)); let(&str2, ""); str2 = tokenToTex(mathToken[nmbrTmpPtr2[k]].tokenName, showStmt); let(&str1, cat(str1, ",", str2, NULL)); } } } if (!texFlag) printLongLine(cat( "Its mandatory disjoint variable pairs are: ", right(str1,3),NULL)," "," "); } if (type == p_ && nmbrLen(statement[showStmt].optHypList) && !texFlag) { printLongLine(cat( "Its optional hypotheses are: ", nmbrCvtRToVString( statement[showStmt].optHypList, /* 25-Jan-2016 nm */ 0, /*explicitTargets*/ 0 /*statemNum, used only if explicitTargets*/), NULL), " "," "); } nmbrTmpPtr1 = statement[showStmt].optDisjVarsA; nmbrTmpPtr2 = statement[showStmt].optDisjVarsB; i = nmbrLen(nmbrTmpPtr1); if (i && type == p_) { if (!texFlag) { let(&str1, ""); } else { if (htmlFlg && texFlag) { /* 12/1/01 don't output dummy variables let(&str1, cat(str1, "   (Dummy variables for use in proof:) ", NULL)); */ } } for (k = 0; k < i; k++) { if (!texFlag) { let(&str1, cat(str1, ", <", mathToken[nmbrTmpPtr1[k]].tokenName, ",", mathToken[nmbrTmpPtr2[k]].tokenName, ">", NULL)); } /* if !texFlag */ } /* next k */ if (!texFlag) { printLongLine(cat( "Its optional disjoint variable pairs are: ", right(str1,3),NULL)," "," "); } } /* if (i && type == p_) */ /* Before 12/23/01 ********** Future: once stable, take out redundant code producing str1 if (texFlag && htmlFlg && str1[0]) { outputToString = 1; printLongLine(cat("
Substitutions into these variable", " pairs may not have variables in common: ", str1, "
", NULL), "", " "); outputToString = 0; } ***********/ /* 12/23/01 */ if (texFlag && htmlFlg) { /* It's a web page */ if (htmlDistinctVars[0] != 0) { outputToString = 1; printLongLine(cat( "
", " 0) ? "mmset.html" : /* The following link will work in the NF and other "Proof Explorers" */ "../mpeuni/mmset.html", /* 19-Aug-2017, 26-Sep-2017 nm */ "#distinct\">Distinct variable group", /* 11-Aug-2006 nm Determine whether "group" or "groups". */ distVarGrps > 1 ? "s" : "", /* 11-Aug-2006 */ ": ", /* 14-Jan-2016 nm Put a span around the variable list to localize the use of the special math font for ALT_HTML */ (altHtmlFlag ? cat("", NULL) : ""), /* 14-Jan-2016 nm */ htmlDistinctVars, (altHtmlFlag ? "" : ""), "
", NULL), "", "\""); outputToString = 0; } /* 26-Aug-2017 nm Moved this down into proof section */ /* /@ 13-Aug-2017 nm @/ let(&str3, ""); if (type == p_) { str3 = htmlDummyVars(showStmt); if (str3[0] != 0) { outputToString = 1; /@ We don't need
if code is surrounded by
...
if (htmlDistinctVars[0] != 0) print2("
\n"); @/ /@ Print the list of dummy variables @/ printLongLine(str3, "", "\""); outputToString = 0; } } /@ (end of 13-Aug-2017) @/ */ /* 4-Jan-2014 nm */ let(&str2, ""); str2 = htmlAllowedSubst(showStmt); if (str2[0] != 0) { outputToString = 1; /* We don't need
if code is surrounded by
...
if (htmlDistinctVars[0] != 0 || str3[0] != 0) print2("
\n"); */ /* Print the list of allowed free variables */ printLongLine(str2, "", "\""); outputToString = 0; } } /* if (texFlag && htmlFlg) */ if (texFlag) { outputToString = 1; if (htmlFlg && texFlag) print2("
\n"); outputToString = 0; /* Restore normal output */ /* will be done automatically at closing fprintf(texFilePtr, "%s", printString); let(&printString, ""); */ break; /* case a_ or p_ */ } let(&str1, nmbrCvtMToVString( statement[showStmt].reqVarList)); if (!strlen(str1)) let(&str1, "(None)"); printLongLine(cat( "The statement and its hypotheses require the variables: ", str1, NULL), " ", " "); if (type == p_ && nmbrLen(statement[showStmt].optVarList)) { printLongLine(cat( "These additional variables are allowed in its proof: " ,nmbrCvtMToVString( statement[showStmt].optVarList),NULL)," ", " "); /*??? Add variables required by proof */ } /* Note: statement[].reqVarList is only stored for $a and $p statements, not for $e or $f. */ let(&str1, nmbrCvtMToVString( statement[showStmt].reqVarList)); if (!strlen(str1)) let(&str1, "(None)"); printLongLine(cat("The variables it contains are: ", str1, NULL), " ", " "); break; /* case a_ or p_ */ default: break; } /* End switch(type) */ if (texFlag) { outputToString = 0; /* will be done automatically at closing fprintf(texFilePtr, "%s", printString); let(&printString, ""); */ } /* Start of finding definition for syntax statement */ if (htmlFlg && texFlag) { /* For syntax declarations, find the first definition that follows it. It is up to the user to arrange the database so that a meaningful definition is picked. */ if (subType == SYNTAX) { for (i = showStmt + 1; i <= statements; i++) { if (statement[i].type == (char)a_) { if (!strcmp("|-", mathToken[ (statement[i].mathString)[0]].tokenName)) { /* It's a definition or axiom */ /* See if each constant token in the syntax statement exists in the definition; if not don't use the definition */ j = 1; /* We start with k=1 for 2nd token (1st is wff, class, etc.) */ for (k = 1; k < statement[showStmt].mathStringLen; k++) { if (mathToken[(statement[showStmt].mathString)[k]]. tokenType == (char)con_) { if (!nmbrElementIn(1, statement[i].mathString, (statement[showStmt].mathString)[k])) { /* The definition being considered doesn't have one of the constant symbols in the syntax statement, so reject it */ j = 0; break; /* Out of k loop */ } } } /* Next k */ if (j) { /* Successful - use this definition or axiom as the reference */ outputToString = 1; let(&str1, left(statement[i].labelName, 3)); let(&str2, ""); str2 = pinkHTML(i); if (!strcmp(str1, "ax-")) { printLongLine(cat( "
This syntax is primitive.", " The first axiom using it is ", statement[i].labelName, "", str2, ".

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

", NULL), "", "\""); } /* 10/10/02 Moved here from mmwtex.c */ /*print2("Colors of variables:\n");*/ printLongLine(cat( "
", NULL), "", "\""); outputToString = 0; break; /* Out of i loop */ } } } } /* Next i */ } /* if (subType == SYNTAX) */ /* For definitions, we pretend that the definition is a "wff" (hard-coded here; the .mm database provided by the user must use this convention). We use the proof assistant tools to prove that the statement is a wff, then we print the wff construction proof to the HTML file. */ if (subType == DEFINITION || subType == AXIOM) { /* Look up the token "wff" if we haven't found it before */ if (wffToken == -1) { /* First time */ wffToken = -2; /* In case it's not found because the user's source used a convention different for "wff" for wffs */ for (i = 0; i < mathTokens; i++) { if (!strcmp("wff", mathToken[i].tokenName)) { wffToken = i; break; } } } if (wffToken >= 0) { /* Temporarily zap statement type from $a to $p */ if (statement[showStmt].type != (char)a_) bug(231); statement[showStmt].type = (char)p_; /* Temporarily zap statement with "wff" token in 1st position so parseProof will not give errors (in typeProof() call) */ zapStatement1stToken = (statement[showStmt].mathString)[0]; (statement[showStmt].mathString)[0] = wffToken; if (strcmp("|-", mathToken[zapStatement1stToken].tokenName)) bug(230); nmbrTmpPtr1 = NULL_NMBRSTRING; nmbrLet(&nmbrTmpPtr1, statement[showStmt].mathString); /* Find proof of formula or simple theorem (no new vars in $e's) */ /* maxEDepth is the maximum depth at which statements with $e hypotheses are considered. A value of 0 means none are considered. */ nmbrTmpPtr2 = proveFloating(nmbrTmpPtr1 /*mString*/, showStmt /*statemNum*/, 0 /*maxEDepth*/, 0, /*step: 0 = step 1 */ /*For messages*/ 0, /*not noDistinct*/ /* 3-May-2016 nm */ 2 /* override discouraged-usage statements silently */ ); if (nmbrLen(nmbrTmpPtr2)) { /* A proof for the step was found. */ /* Get packed form of proof for shorter display */ nmbrLet(&nmbrTmpPtr2, nmbrSquishProof(nmbrTmpPtr2)); /* Temporarily zap proof into statement structure */ /* (The bug check makes sure there is no proof attached to the definition - this would be impossible) */ if (strcmp(statement[showStmt].proofSectionPtr, "")) bug(231); if (statement[showStmt].proofSectionLen != 0) bug(232); let(&str1, nmbrCvtRToVString(nmbrTmpPtr2, /* 25-Jan-2016 nm */ 0, /*explicitTargets*/ 0 /*statemNum, used only if explicitTargets*/)); /* Temporarily zap proof into the $a statement */ statement[showStmt].proofSectionPtr = str1; statement[showStmt].proofSectionLen = (long)strlen(str1) - 1; /* Display the HTML proof of syntax breakdown */ typeProof(showStmt, 0 /*pipFlag*/, 0 /*startStep*/, 0 /*endStep*/, 0 /*endIndent*/, 0 /*essentialFlag*/, /* <- also used as def flag in typeProof */ 1 /*renumberFlag*/, 0 /*unknownFlag*/, 0 /*notUnifiedFlag*/, 0 /*reverseFlag*/, 1 /*noIndentFlag*/, 0 /*splitColumn*/, 0 /*skipRepeatedSteps*/, /* 28-Jun-2013 nm */ 1 /*texFlag*/, /* Means either latex or html */ 1 /*htmlFlg*/); /* Restore the zapped statement structure */ statement[showStmt].proofSectionPtr = ""; statement[showStmt].proofSectionLen = 0; /* Deallocate storage */ let(&str1, ""); nmbrLet(&nmbrTmpPtr2, NULL_NMBRSTRING); } else { /* if (nmbrLen(nmbrTmpPtr2)) else */ /* 5-Aug-2011 nm */ /* Proof was not found - probable syntax error */ if (outputToString != 0) bug(246); printLongLine(cat( "?Warning: Unable to generate syntax breakdown for \"", statement[showStmt].labelName, "\".", NULL), " ", " "); } /* Restore the zapped statement structure */ statement[showStmt].type = (char)a_; (statement[showStmt].mathString)[0] = zapStatement1stToken; /* Deallocate storage */ nmbrLet(&nmbrTmpPtr1, NULL_NMBRSTRING); } /* if (wffToken >= 0) */ } /* if (subType == DEFINITION) */ } /* if (htmlFlg && texFlag) */ /* End of finding definition for syntax statement */ /* 10/6/99 - Start of creating used-by list for html page */ if (htmlFlg && texFlag) { /* 10/25/02 Clear out any previous printString accumulation for printStringForReferencedBy case below */ fprintf(texFilePtr, "%s", printString); let(&printString, ""); /* Start outputting to printString */ if (outputToString != 0) bug(242); outputToString = 1; if (subType != SYNTAX) { /* Only do this for definitions, axioms, and theorems, not syntax statements */ let(&str1, ""); outputToString = 0; /* Switch output to console in case traceUsage reports an error */ /* 8-Dec-2018 nm */ str1 = traceUsage(showStmt, 0, /* recursiveFlag */ 0 /* cutoffStmt */); outputToString = 1; /* Restore output to string */ /* 8-Dec-2018 nm */ /* if (str1[0]) { */ /* Used by at least one */ /* 18-Jul-2015 nm */ /* 30-Oct-2018 nm Commented out, and block unindented: */ /*if (str1[0] == 'Y') {*/ /* Used by at least one */ /* 30-Oct-2018 nm */ /* We now output this all the time, using "(None)" if none, per request of Benoit Jubin */ /* str1[i] will be 'Y' if used by showStmt */ /* Convert usage list str1 to html links */ switch (subType) { case AXIOM: let(&str3, "axiom"); break; case DEFINITION: let(&str3, "definition"); break; case THEOREM: let(&str3, "theorem"); break; default: bug(233); } /******* pre 10/10/02 let(&str2, cat("This ", str3, " is referenced by: ", NULL)); *******/ /* 10/10/02 */ let(&str2, cat("", NULL)); @/ /@ old @/ /@ 19-Sep-2012 nm Include buffer in output string@/ let(&str2, cat(str5, str2, "", NULL)); printLongLine(str2, "", "\""); */ /**************** 18-Jul-2015 End of deleted code *********/ let(&str5, ""); /* Buffer for very long strings */ /* 19-Sep-2012 nm */ /* Scan all future statements in str1 Y/N list */ for (m = showStmt + 1; m <= statements; m++) { /* Scan the used-by map */ if (str1[m] != 'Y') continue; /* Get the label */ let(&str3, statement[m].labelName); /* It should be a $p */ if (statement[m].type != p_) bug(241); /* Get the pink number */ let(&str4, ""); str4 = pinkHTML(m); /* Assemble the href */ let(&str2, cat(str2, "  ", /*str3, "", str4, NULL));*/ str3, "\n", str4, NULL)); /* 18-Jul-2015 nm */ /* 8-Aug-2008 nm If line is very long, print it out and reset it to speed up program (SHOW STATEMENT syl/HTML is very slow) */ /* 8-Aug-2008 nm This doesn't solve problem, because the bottleneck is printing printStringForReferencedBy below. This whole code section needs to be redesigned to solve the speed problem. */ /* 19-Sep-2012 nm Try again to fix SHOW STATEMENT syl/HTML speed without a major rewrite. Unfortunately, made little difference. */ /* 18-Jul-2015: Part of slowdown was due to the old traceUsage algorithm that built a huge string of labels. Improved from 313 sec to 280 sec for 'sh st syl/a'; still a problem. */ /* Accumulate large cat buffer when small cats exceed certain size */ if (strlen(str2) > 5000) { let(&str5, cat(str5, str2, NULL)); let(&str2, ""); } /* End 19-Sep-2012 */ } /* next m (statement number) */ /* 30-Oct-2018 nm Added "else" clause to print "(None)" if no refs */ } else { /* There is no usage of this statement; print "(None)" */ let(&str5, ""); let(&str2, cat(str2, " (None)", NULL)); } /* if (str1[0] == 'Y') */ /* let(&str2, cat(str2, "", NULL)); */ /* old */ /* 19-Sep-2012 nm Include buffer in output string*/ let(&str2, cat(str5, str2, "", NULL)); /*printLongLine(str2, "", "\"");*/ /* 18-Jul-2015 nm Deleted */ if (printString[0]) { bug(256); /* 18-Jul-2015 nm */ } let(&printString, str2); /* 18-Jul-2015 nm */ } /* if (subType != SYNTAX) */ if (subType == THEOREM) { /* 10/25/02 The "referenced by" does not show up after the proof because we moved the typeProof() to below. Therefore, we save printString into a temporary global holding variable to print at the proper place inside of typeProof(). Ugly but necessary with present design. */ /* In the case of THEOREM, we save and reset the printString. In the case of != THEOREM (i.e. AXIOM and DEFINITION), printString will be printed and cleared below. */ let(&printStringForReferencedBy, printString); let(&printString, ""); } /* Printing of the trailer in mmwtex.c will close out string later */ outputToString = 0; } /* if (htmlFlg && texFlag) */ /* 10/6/99 - End of used-by list for html page */ /* 10/25/02 Moved this to after the block above, so referenced statements show up first for convenience */ if (htmlFlg && texFlag) { /*** Output the html proof for $p statements ***/ /* Note that we also output the axiom and definition usage lists inside this function */ if (statement[showStmt].type == (char)p_) { typeProof(showStmt, 0 /*pipFlag*/, 0 /*startStep*/, 0 /*endStep*/, 0 /*endIndent*/, 1 /*essentialFlag*/, 1 /*renumberFlag*/, 0 /*unknownFlag*/, 0 /*notUnifiedFlag*/, 0 /*reverseFlag*/, 1 /*noIndentFlag*/, 0 /*splitColumn*/, 0 /*skipRepeatedSteps*/, /* 28-Jun-2013 nm */ 1 /*texFlag*/, /* Means either latex or html */ 1 /*htmlFlg*/); } /* if (statement[showStmt].type == (char)p_) */ } /* if (htmlFlg && texFlag) */ /* End of html proof for $p statements */ /* typeProof should have cleared this out */ if (printStringForReferencedBy[0]) bug(243); returnPoint: /* Deallocate strings */ nmbrLet(&nmbrDDList, NULL_NMBRSTRING); let(&str1, ""); let(&str2, ""); let(&str3, ""); let(&str4, ""); let(&str5, ""); let(&htmlDistinctVars, ""); } /* typeStatement */ /* 13-Aug-2017 nm */ /* Get the HTML string of dummy variables used by a proof for the theorem's web page. It should be called only if we're in HTML output mode i.e. SHOW STATEMENT .../HTML or /ALT_HTML */ /* This is HARD-CODED FOR SET.MM and will not produce meaningful output for other databases (so far none) with $d's */ /* Caller must deallocate returned string */ vstring htmlDummyVars(long showStmt) { nmbrString *optDVA; /* Pointer only; not allocated directly */ nmbrString *optDVB; /* Pointer only; not allocated directly */ long numDVs; nmbrString *optHyp; /* Pointer only; not allocated directly */ long numOptHyps; vstring str1 = ""; long k, l, n, hypStmt; /* Variables used while collecting a statement's dummy variables in $d's */ long dummyVarCount; /* # of (different) dummy vars found in $d statements */ vstring dummyVarUsed = ""; /* 'Y'/'N' indicators that we found that var */ vstring htmlDummyVarList = ""; /* Output HTML string */ long dummyVar; /* Current variable in a $d; test if it's a dummy variable */ /* This function should be called only for web page generation */ /*if (!(htmlFlag && texFlag)) bug(261);*/ /* texFlag is not global */ if (!htmlFlag) bug(261); if (statement[showStmt].type != p_) bug(262); if (strcmp("|-", mathToken[ (statement[showStmt].mathString)[0]].tokenName)) { /* Don't process syntax statements */ goto RETURN_POINT; } optDVA = statement[showStmt].optDisjVarsA; optDVB = statement[showStmt].optDisjVarsB; numDVs = nmbrLen(optDVA); optHyp = statement[showStmt].optHypList; numOptHyps = nmbrLen(optHyp); if (numDVs == 0) { /* Don't create a hint list if no $d's */ /*let(&htmlDummyVarList, "(no restrictions)");*/ goto RETURN_POINT; } dummyVarCount = 0; if (numDVs != 0) { /* Update wrkProof.proofString with current proof so we can search it later to see if it uses the dummy variable */ parseProof(showStmt); /* Prints message if severe error */ /* Create an array of Y/N indicators that variable is occurs in a $d statement as a dummy variable */ let(&dummyVarUsed, string(mathTokens, 'N')); for (k = 0; k < numDVs; k++) { for (l = 1; l <= 2; l++) { if (l == 1) { dummyVar = optDVA[k]; } else { dummyVar = optDVB[k]; } /* At this point, dummyVar is just a var in the $d; we must still check that it is in the optHypList */ /* See if potential dummyVar is in optHypList */ if (dummyVarUsed[dummyVar] == 'N') { for (n = 0; n < numOptHyps; n++) { /* Check whether dummyVar matches the 2nd token of an optional hypothesis list entry e.g. "x" in "set x" */ hypStmt = statement[showStmt].optHypList[n]; if (statement[hypStmt].mathString[1] == dummyVar) { /* dummyVar is a dummy variable */ /* See if it is used by the proof */ /* wrkProof.proofString was updated by parseProof(showStmt) above */ if (nmbrElementIn(1, wrkProof.proofString, hypStmt) == 0) { break; /* It's not used by the proof; stop hyp scan */ } dummyVarUsed[dummyVar] = 'Y'; dummyVarCount++; /* tokenToTex allocates str1; must deallocate it first */ let(&str1, ""); /* Convert token to htmldef/althtmldef string */ str1 = tokenToTex(mathToken[dummyVar].tokenName, showStmt); let(&htmlDummyVarList, cat(htmlDummyVarList, " ", str1, NULL)); break; /* Found a match, so stop further checking */ } } /* next n, 0 to numOptHyps-1*/ } /* if dummy var not used (yet) */ } /* next l */ } /* next k */ } /* if (numDVs != 0) */ if (dummyVarCount > 0) { let(&htmlDummyVarList, cat( "
", " 0) ? "mmset.html" : /* The following link will work in the NF and other "Proof Explorers" */ "../mpeuni/mmset.html", /* 19-Aug-2017, 26-Sep-2017 nm */ "#dvnote1\">Dummy variable", /* Determine whether singular or plural */ dummyVarCount > 1 ? "s" : "", " ", /* 14-Aug-2017 nm */ /* 14-Jan-2016 nm Put a span around the variable list to localize the use of the special math font for ALT_HTML */ (altHtmlFlag ? cat("", NULL) : ""), /* 14-Jan-2016 nm */ htmlDummyVarList, (altHtmlFlag ? "" : ""), /* dummyVarCount > 1 ? " are assumed to be mutually distinct and" : " is assumed to be", */ dummyVarCount > 1 ? " are mutually distinct and" : " is", " distinct from all other variables.", "
", NULL)); } /* htmlDummyVars */ RETURN_POINT: /* Deallocate strings */ let(&dummyVarUsed, ""); let(&str1, ""); return htmlDummyVarList; } /* htmlDummyVars */ /* 4-Jan-2014 nm */ /* Get the HTML string of "allowed substitutions" list for an axiom or theorem's web page. It should be called only if we're in HTML output mode i.e. SHOW STATEMENT .../HTML or /ALT_HTML */ /* This is HARD-CODED FOR SET.MM and will not produce meaningful output for other databases (so far none) with $d's */ /* Caller must deallocate returned string */ vstring htmlAllowedSubst(long showStmt) { nmbrString *reqHyp; /* Pointer only; not allocated directly */ long numReqHyps; nmbrString *reqDVA; /* Pointer only; not allocated directly */ nmbrString *reqDVB; /* Pointer only; not allocated directly */ long numDVs; nmbrString *setVar = NULL_NMBRSTRING; /* set (individual) variables */ char *strptr; vstring str1 = ""; long setVars; long wffOrClassVar; vstring setVarDVFlag = ""; flag found, first; long i, j, k; vstring htmlAllowedList = ""; long countInfo = 0; reqDVA = statement[showStmt].reqDisjVarsA; reqDVB = statement[showStmt].reqDisjVarsB; numDVs = nmbrLen(reqDVA); reqHyp = statement[showStmt].reqHypList; numReqHyps = nmbrLen(reqHyp); /* This function should be called only for web page generation */ /*if (!(htmlFlag && texFlag)) bug(250);*/ /* texFlag is not global */ if (!htmlFlag) bug(250); if (statement[showStmt].mathStringLen < 1) bug(254); if (strcmp("|-", mathToken[ (statement[showStmt].mathString)[0]].tokenName)) { /* Don't process syntax statements */ goto RETURN_POINT; } if (numDVs == 0) { /* Don't create a hint list if no $d's */ /*let(&htmlAllowedList, "(no restrictions)");*/ goto RETURN_POINT; } /* Collect list of all set variables in the theorem */ /* First, count the number of set variables */ setVars = 0; for (i = 0; i < numReqHyps; i++) { /* Scan "setvar" variables */ if (statement[reqHyp[i]].type == (char)e_) continue; if (statement[reqHyp[i]].type != (char)f_) bug(251); if (statement[reqHyp[i]].mathStringLen != 2) bug(252); /* $f must have 2 tokens */ strptr = mathToken[ (statement[reqHyp[i]].mathString)[0]].tokenName; /* THE FOLLOWING IS SPECIFIC TO set.mm */ if (strcmp("setvar", strptr)) continue; /* Not a set variable */ setVars++; } /* Next, create a list of them in setVar[] */ j = 0; nmbrLet(&setVar, nmbrSpace(setVars)); for (i = 0; i < numReqHyps; i++) { /* Scan "setvar" variables */ if (statement[reqHyp[i]].type == (char)e_) continue; strptr = mathToken[ (statement[reqHyp[i]].mathString)[0]].tokenName; if (strcmp("setvar", strptr)) continue; /* Not a set variable */ setVar[j] = (statement[reqHyp[i]].mathString)[1]; j++; } if (j != setVars) bug(253); /* Scan "wff" and "class" variables for attached $d's */ for (i = 0; i < numReqHyps; i++) { /* Look for a "wff" and "class" variable */ if (statement[reqHyp[i]].type == (char)e_) continue; strptr = mathToken[ (statement[reqHyp[i]].mathString)[0]].tokenName; if (strcmp("wff", strptr) && strcmp("class", strptr)) continue; /* Not a wff or class variable */ wffOrClassVar = (statement[reqHyp[i]].mathString)[1]; let(&setVarDVFlag, string(setVars, 'N')); /* No $d yet */ /* Scan for attached $d's */ for (j = 0; j < numDVs; j++) { found = 0; if (wffOrClassVar == reqDVA[j]) { for (k = 0; k < setVars; k++) { if (setVar[k] == reqDVB[j]) { setVarDVFlag[k] = 'Y'; found = 1; break; } } } if (found) continue; /* Repeat with swapped $d arguments */ if (wffOrClassVar == reqDVB[j]) { for (k = 0; k < setVars; k++) { if (setVar[k] == reqDVA[j]) { setVarDVFlag[k] = 'Y'; break; } } } } /* next $d */ /* Collect set vars that don't have $d's with this wff or class var */ /* First, if there aren't any, then omit this wff or class var */ found = 0; for (j = 0; j < setVars; j++) { if (setVarDVFlag[j] == 'N') { found = 1; break; } } if (found == 0) continue; /* All set vars have $d with this wff or class */ let(&str1, ""); str1 = tokenToTex(mathToken[wffOrClassVar].tokenName, showStmt); /* tokenToTex allocates str1; we must deallocate it eventually */ countInfo++; let(&htmlAllowedList, cat(htmlAllowedList, "   ", str1, "(", NULL)); first = 1; for (j = 0; j < setVars; j++) { if (setVarDVFlag[j] == 'N') { let(&str1, ""); str1 = tokenToTex(mathToken[setVar[j]].tokenName, showStmt); let(&htmlAllowedList, cat(htmlAllowedList, (first == 0) ? "," : "", str1, NULL)); if (first == 0) countInfo++; first = 0; } } let(&htmlAllowedList, cat(htmlAllowedList, ")", NULL)); } /* next i (wff or class var) */ RETURN_POINT: if (htmlAllowedList[0] != 0) { let(&htmlAllowedList, cat("
", " 0) ? "mmset.html" : /* The following link will work in the NF and other "Proof Explorers" */ "../mpeuni/mmset.html", /* 19-Aug-2017, 26-Sep-2017 nm */ "#allowedsubst\">Allowed substitution hint", ((countInfo != 1) ? "s" : ""), ": ", (altHtmlFlag ? cat("", NULL) : ""), /* 14-Jan-2016 nm */ htmlAllowedList, (altHtmlFlag ? "" : ""), /* 14-Jan-2016 nm */ "
", NULL)); } /* Deallocate strings */ nmbrLet(&setVar, NULL_NMBRSTRING); let(&str1, ""); let(&setVarDVFlag, ""); return htmlAllowedList; } /* htmlAllowedSubst */ /* Displays a proof (or part of a proof, depending on arguments). */ /* Note that parseProof() and verifyProof() are assumed to have been called, so that the wrkProof structure elements are assigned for the current statement. */ /* 8/28/00 - this is also used for the MIDI output, since we conveniently have the necessary proof information here. The function outputMidi() is called from within. */ void typeProof(long statemNum, flag pipFlag, /* Means use proofInProgress; statemNum must be proveStatement*/ long startStep, long endStep, long endIndent, flag essentialFlag, /* <- also used as definition/axiom flag for HTML syntax breakdown when called from typeStatement() */ flag renumberFlag, flag unknownFlag, flag notUnifiedFlag, flag reverseFlag, flag noIndentFlag, /* Means Lemmon-style proof */ long splitColumn, /* START_COLUMN */ flag skipRepeatedSteps, /* NO_REPEATED_STEPS */ /* 28-Jun-2013 nm */ flag texFlag, flag htmlFlg /* htmlFlg added 6/27/99 */ /* flag midiFlag - global to avoid changing many calls to typeProof() */ ) { /* From HELP SHOW PROOF: Optional qualifiers: / ESSENTIAL - the proof tree is trimmed of all $f hypotheses before being displayed. / FROM_STEP - the display starts at the specified step. If this qualifier is omitted, the display starts at the first step. / TO_STEP - the display ends at the specified step. If this qualifier is omitted, the display ends at the last step. / TREE_DEPTH - Only steps at less than the specified proof tree depth are displayed. Useful for obtaining an overview of the proof. / REVERSE - the steps are displayed in reverse order. / RENUMBER - when used with / ESSENTIAL, the steps are renumbered to correspond only to the essential steps. / TEX - the proof is converted to LaTeX and stored in the file opened with OPEN TEX. / HTML - the proof is converted to HTML and stored in the file opened with OPEN HTML. / LEMMON - The proof is displayed in a non-indented format known as Lemmon style, with explicit previous step number references. If this qualifier is omitted, steps are indented in a tree format. / START_COLUMN - Overrides the default column at which the formula display starts in a Lemmon style display. May be used only in conjuction with / LEMMON. / NO_REPEATED_STEPS - When a proof step is identical to an earlier step, it will not be repeated. Instead, a reference to it will be changed to a reference to the earlier step. In particular, SHOW PROOF
", "Colors of variables: ", htmlVarColor, "
This ", str3, " is referenced by:", NULL)); if (str1[0] == 'Y') { /* Used by at least one */ /********* 18-Jul-2015 Deleted code *********************/ /* /@ Convert str1 to trailing space after each label @/ let(&str1, cat(right(str1, 2), " ", NULL)); let(&str5, ""); /@ Buffer for very long strings @/ /@ 19-Sep-2012 nm @/ i = 0; while (1) { j = i + 1; i = instr(j, str1, " "); if (!i) break; /@ Extract the label @/ let(&str3, seg(str1, j, i - 1)); /@ Find the statement number @/ m = lookupLabel(str3); if (m < 0) { /@ The lookup should never fail @/ bug(240); continue; } /@ It should be a $p @/ if (statement[m].type != p_) bug(241); /@ Get the pink number @/ let(&str4, ""); str4 = pinkHTML(m); /@ Assemble the href @/ let(&str2, cat(str2, "  ", str3, "", str4, NULL)); /@ 8-Aug-2008 nm If line is very long, print it out and reset it to speed up program (SHOW STATEMENT syl/HTML is very slow) @/ /@ 8-Aug-2008 nm This doesn't solve problem, because the bottleneck is printing printStringForReferencedBy below. This whole code section needs to be redesigned to solve the speed problem. @/ /@ if (strlen(str2) > 500) { printLongLine(str2, "", "\""); let(&str2, ""); } @/ /@ 19-Sep-2012 nm Try again to fix SHOW STATEMENT syl/HTML speed without a major rewrite @/ /@ Unfortunately, makes little difference. Using lcc: orig real 1m6.676s 500 real 1m2.285s 3000 real 1m2.181s 3000 real 1m1.663s 3000 real 1m1.785s 5000 real 1m0.678s 5000 real 1m0.169s 5000 real 1m1.951s 5000 real 1m2.307s 5000 real 1m1.717s 7000 real 1m2.048s 7000 real 1m2.012s 7000 real 1m1.817s 10000 real 1m2.779s 10000 real 1m1.830s 20000 real 1m1.431s 50000 real 1m1.325s 100000 real 1m3.172s 100000 real 1m4.657s (Added 17-Jul-2015: The 1 minute is probably due to the old traceUsage algorithm that built a huge string of labels; should be faster now.) @/ /@ Accumulate large cat buffer when small cats exceed certain size @/ if (strlen(str2) > 5000) { let(&str5, cat(str5, str2, NULL)); let(&str2, ""); } /@ End 19-Sep-2012 @/ } /@ let(&str2, cat(str2, "
\n"); } else { /* End of 26-Aug-2017 */ /* For bobby.cast.org approval */ print2("
\n"); print2("", NULL), "", "\""); } } else { /* This is a syntax breakdown "proof" of a definition called from typeStatement */ print2("
Proof of Theorem ", asciiToTt(statement[statemNum].labelName), "
\n"); print2("", NULL), "", "\""); } print2( "\n"); outputToString = 0; /* printTexLongMath in typeProof will do this fprintf(texFilePtr, "%s", printString); let(&printString, ""); */ } if (!pipFlag) { parseProof(showStatement); if (wrkProof.errorSeverity > 1) { /* 2-Nov-2014 nm Prevent population of printString outside of web page generation to fix bug 1114 (reported by Sefan O'Rear). */ if (htmlFlg && texFlag) { /* Print warning and close out proof table */ outputToString = 1; print2( "\n"); outputToString = 0; /* 18-Nov-2012 nm Fix bug 243 */ /* Clear out printStringForReferencedBy to prevent bug 243 above */ let(&printStringForReferencedBy, ""); } return; /* verifyProof() could crash */ } verifyProof(showStatement); } if (!pipFlag) { nmbrLet(&proof, wrkProof.proofString); /* The proof */ if (midiFlag) { /* 8/28/00 */ /* Get the uncompressed version of the proof */ nmbrLet(&proof, nmbrUnsquishProof(proof)); } } else { nmbrLet(&proof, proofInProgress.proof); /* The proof */ } plen = nmbrLen(proof); /* 6/27/99 - to reduce the number of steps displayed in an html proof, we will use a local label to reference the 2nd or later reference to a hypothesis, so the hypothesis won't have to be shown multiple times in the proof. 31-Jan-2010 - do this for all Lemmon-style proofs */ if (htmlFlg && texFlag && !noIndentFlag /* Lemmon */) { /* Only Lemmon-style proofs are implemented for html */ bug(218); } /*if (htmlFlg && texFlag) {*/ /* pre-31-Jan-2010 */ /* 31-Jan-2010 nm Do this for all Lemmon-style proofs */ if (skipRepeatedSteps) { for (step = 0; step < plen; step++) { stmt = proof[step]; if (stmt < 0) continue; /* Unknown or label ref */ type = statement[stmt].type; if (type == f_ || type == e_ /* It's a hypothesis */ || statement[stmt].numReqHyp == 0) { /* A statement w/ no hyp */ for (i = 0; i < step; i++) { if (stmt == proof[i]) { /* The hypothesis at 'step' matches an earlier hypothesis at i, so we will backreference 'step' to i with a local label */ proof[step] = -1000 - i; break; } } /* next i */ } } /* next step */ } /* Collect local labels */ for (step = 0; step < plen; step++) { stmt = proof[step]; if (stmt <= -1000) { stmt = -1000 - stmt; if (!nmbrElementIn(1, localLabels, stmt)) { nmbrLet(&localLabels, nmbrAddElement(localLabels, stmt)); } } } /* localLabelNames[] hold an integer which, when converted to string, is the local label name. */ nmbrLet(&localLabelNames, nmbrSpace(plen)); /* Get the indentation level */ nmbrLet(&indentationLevel, nmbrGetIndentation(proof, 0)); /* Get the target hypotheses */ nmbrLet(&targetHyps, nmbrGetTargetHyp(proof, statemNum)); /* Get the essential step flags, if required */ if (essentialFlag || midiFlag) { nmbrLet(&essentialFlags, nmbrGetEssential(proof)); } else { nmbrLet(&essentialFlags, NULL_NMBRSTRING); } /* 8/28/00 We now have enough information for the MIDI output, so do it */ if (midiFlag) { outputMidi(plen, indentationLevel, essentialFlags, midiParam, statement[statemNum].labelName); goto typeProof_return; } /* Get the step renumbering */ nmbrLet(&stepRenumber, nmbrSpace(plen)); /* This initializes all step renumbering to step 0. Later, we will use (for html) the fact that a step renumbered to 0 is a step to be skipped (6/27/99). */ i = 0; maxStepNum = 0; for (step = 0; step < plen; step++) { stepPrintFlag = 1; /* Note: stepPrintFlag is reused below with a slightly different meaning (i.e. it will be printed after a filter such as notUnified is applied) */ if (renumberFlag && essentialFlag) { if (!essentialFlags[step]) stepPrintFlag = 0; } /* if (htmlFlg && texFlag && proof[step] < 0) stepPrintFlag = 0; */ /* 31-Jan-2010 nm changed to: */ if (skipRepeatedSteps && proof[step] < 0) stepPrintFlag = 0; /* For standard numbering, stepPrintFlag will be always be 1 here */ if (stepPrintFlag) { i++; stepRenumber[step] = i; /* Numbering for step to be printed */ maxStepNum = i; /* To compute maxStepNumLen below */ } } /* 22-Apr-2015 nm */ /* Get the relative offset (0, -1, -2,...) for unknown steps */ if (unknownFlag) { /* 21-Aug-2017 nm There could be unknown steps outside of MM-PA So remove this bugcheck, which seems spurious. I can't see that getRelStepNums() cares whether we are in MM-PA. */ /* if (!pipFlag) { bug(255); } */ relativeStepNums = getRelStepNums(proofInProgress.proof); } /* Get steps not unified (pipFlag only) */ if (notUnifiedFlag) { if (!pipFlag) bug(205); nmbrLet(¬UnifiedFlags, nmbrSpace(plen)); for (step = 0; step < plen; step++) { notUnifiedFlags[step] = 0; if (nmbrLen(proofInProgress.source[step])) { if (!nmbrEq(proofInProgress.target[step], proofInProgress.source[step])) notUnifiedFlags[step] = 1; } if (nmbrLen(proofInProgress.user[step])) { if (!nmbrEq(proofInProgress.target[step], proofInProgress.user[step])) notUnifiedFlags[step] = 1; } } } /* Get the printed character length of the largest step number */ i = maxStepNum; while (i >= 10) { i = i/10; /* The number is printed in base 10 */ maxStepNumLen++; } /* 22-Apr-2015 nm */ /* Add extra space for negative offset numbers e.g. "3:-1" */ if (unknownFlag) { maxStepNumOffsetLen = 3; /* :, -, # */ j = 0; for (i = 0; i < plen; i++) { j = relativeStepNums[i]; if (j <= 0) break; /* Found first unknown step (largest offset) */ } while (j <= -10) { j = j/10; /* The number is printed in base 10 */ maxStepNumOffsetLen++; } } /* Get local labels and maximum label length */ /* lent = target length, lens = source length */ for (step = 0; step < plen; step++) { lent = (long)strlen(statement[targetHyps[step]].labelName); stmt = proof[step]; if (stmt < 0) { if (stmt <= -1000) { stmt = -1000 - stmt; /* stmt is now the step number a local label refers to */ lens = (long)strlen(str((double)(localLabelNames[stmt]))); let(&tmpStr1, ""); /* Clear temp alloc stack for str function */ } else { if (stmt != -(long)'?') bug (219); /* the only other possibility */ lens = 1; /* '?' (unknown step) */ } } else { if (nmbrElementIn(1, localLabels, step)) { /* 6/27/99 The new philosophy is to number all local labels with the actual step number referenced, for better readability. This means that if a *.mm label is a pure number, there may be ambiguity in the proof display, but this is felt to be too rare to be a serious drawback. */ localLabelNames[step] = stepRenumber[step]; } lens = (long)strlen(statement[stmt].labelName); } /* Find longest label assignment, excluding local label declaration */ if (maxLabelLen < lent + 1 + lens) { maxLabelLen = lent + 1 + lens; /* Target, =, source */ } } /* Next step */ /* Print the steps */ if (reverseFlag && !midiFlag /* 8/28/00 */ ) { fromStep = plen - 1; toStep = -1; byStep = -1; } else { fromStep = 0; toStep = plen; byStep = 1; } for (step = fromStep; step != toStep; step = step + byStep) { /* Filters to decide whether to print the step */ stepPrintFlag = 1; if (startStep > 0) { /* The user's FROM_STEP */ if (step + 1 < startStep) stepPrintFlag = 0; } if (endStep > 0) { /* The user's TO_STEP */ if (step + 1 > endStep) stepPrintFlag = 0; } if (endIndent > 0) { /* The user's INDENTATION_DEPTH */ if (indentationLevel[step] + 1 > endIndent) stepPrintFlag = 0; } if (essentialFlag) { if (!essentialFlags[step]) stepPrintFlag = 0; } if (notUnifiedFlag) { if (!notUnifiedFlags[step]) stepPrintFlag = 0; } if (unknownFlag) { if (proof[step] != -(long)'?') stepPrintFlag = 0; } /* 6/27/99 Skip steps that are local label references for html */ /* if (htmlFlg && texFlag) { */ /* 31-Jan-2010 nm changed to: */ if (skipRepeatedSteps) { if (stepRenumber[step] == 0) stepPrintFlag = 0; } /* 8/28/00 For MIDI files, ignore all qualifiers and process all steps */ if (midiFlag) stepPrintFlag = 1; if (!stepPrintFlag) continue; if (noIndentFlag) { let(&tgtLabel, ""); } else { let(&tgtLabel, statement[targetHyps[step]].labelName); } let(&locLabDecl, ""); /* Local label declaration */ stmt = proof[step]; if (stmt < 0) { if (stmt <= -1000) { stmt = -1000 - stmt; /* if (htmlFlg && texFlag) bug(220); */ /* 31-Jan-2010 nm Changed to: */ if (skipRepeatedSteps) bug(220); /* If html, a step referencing a local label will never be printed since it will be skipped above */ /* stmt is now the step number a local label refers to */ if (noIndentFlag) { let(&srcLabel, cat("@", str((double)(localLabelNames[stmt])), NULL)); } else { let(&srcLabel, cat("=", str((double)(localLabelNames[stmt])), NULL)); } type = statement[proof[stmt]].type; } else { if (stmt != -(long)'?') bug(206); if (noIndentFlag) { let(&srcLabel, chr(-stmt)); /* '?' */ } else { let(&srcLabel, cat("=", chr(-stmt), NULL)); /* '?' */ } type = '?'; } } else { if (nmbrElementIn(1, localLabels, step)) { /* This statement declares a local label */ if (noIndentFlag) { /* if (!(htmlFlg && texFlag)) { */ /* 31-Jan-2010 nm Changed to: */ if (!(skipRepeatedSteps)) { /* No local label declaration is shown for html */ let(&locLabDecl, cat("@", str((double)(localLabelNames[step])), ":", NULL)); } } else { let(&locLabDecl, cat(str((double)(localLabelNames[step])), ":", NULL)); } } if (noIndentFlag) { let(&srcLabel, statement[stmt].labelName); /* For non-indented mode, add step numbers of hypotheses after label */ let(&hypStr, ""); hypStep = step - 1; hypPtr = statement[stmt].reqHypList; for (hyp = statement[stmt].numReqHyp - 1; hyp >=0; hyp--) { if (!essentialFlag || statement[hypPtr[hyp]].type == (char)e_) { i = stepRenumber[hypStep]; if (i == 0) { /* if (!(htmlFlg && texFlag)) bug(221); */ /* 31-Jan-2010 nm Changed to: */ if (!(skipRepeatedSteps)) bug(221); if (proof[hypStep] != -(long)'?') { if (proof[hypStep] > -1000) bug(222); if (localLabelNames[-1000 - proof[hypStep]] == 0) bug(223); if (localLabelNames[-1000 - proof[hypStep]] != stepRenumber[-1000 - proof[hypStep]]) bug(224); /* Get the step number the hypothesis refers to */ i = stepRenumber[-1000 - proof[hypStep]]; } else { /* The hypothesis refers to an unknown step - use i as flag */ i = -(long)'?'; } } if (!hypStr[0]) { if (i != -(long)'?') { let(&hypStr, str((double)i)); } else { let(&hypStr, "?"); } } else { /* Put comma between more than one hypothesis reference */ if (i != -(long)'?') { let(&hypStr, cat(str((double)i), ",", hypStr, NULL)); } else { let(&hypStr, cat("?", ",", hypStr, NULL)); } } } if (hyp < statement[stmt].numReqHyp) { /* Move down to previous hypothesis */ hypStep = hypStep - subproofLen(proof, hypStep); } } /* Next hyp */ if (hypStr[0]) { /* Add hypothesis list after label */ let(&srcLabel, cat(hypStr, " ", srcLabel, NULL)); } } else { let(&srcLabel, cat("=", statement[stmt].labelName, NULL)); } type = statement[stmt].type; } #define PF_INDENT_INC 2 /* Print the proof line */ if (stepPrintFlag) { if (noIndentFlag) { let(&startPrefix, cat( space(maxStepNumLen - (long)strlen(str((double)(stepRenumber[step])))), str((double)(stepRenumber[step])), " ", srcLabel, space(splitColumn - (long)strlen(srcLabel) - (long)strlen(locLabDecl) - 1 - maxStepNumLen - 1), " ", locLabDecl, NULL)); if (pipFlag) { let(&tgtPrefix, startPrefix); let(&srcPrefix, cat( space(maxStepNumLen - (long)strlen(str((double)(stepRenumber[step])))), space((long)strlen(str((double)(stepRenumber[step])))), " ", space(splitColumn - 1 - maxStepNumLen), NULL)); let(&userPrefix, cat( space(maxStepNumLen - (long)strlen(str((double)(stepRenumber[step])))), space((long)strlen(str((double)(stepRenumber[step])))), " ", "(User)", space(splitColumn - (long)strlen("(User)") - 1 - maxStepNumLen), NULL)); } let(&contPrefix, space((long)strlen(startPrefix) + 4)); } else { /* not noIndentFlag */ /* 22-Apr-2015 nm */ /* Compute prefix with and without step number. For 'show new_proof /unknown', unknownFlag is set, and we add the negative offset. */ let(&tmpStr, ""); if (unknownFlag) { if (relativeStepNums[step] < 0) { let(&tmpStr, cat(" ", str((double)(relativeStepNums[step])), NULL)); } let(&tmpStr, cat(tmpStr, space(maxStepNumOffsetLen - (long)(strlen(tmpStr))), NULL)); } let(&startStringWithNum, cat( space(maxStepNumLen - (long)strlen(str((double)(stepRenumber[step])))), str((double)(stepRenumber[step])), tmpStr, " ", NULL)); let(&startStringWithoutNum, space(maxStepNumLen + 1)); let(&startPrefix, cat( startStringWithNum, space(indentationLevel[step] * PF_INDENT_INC - (long)strlen(locLabDecl)), locLabDecl, tgtLabel, srcLabel, space(maxLabelLen - (long)strlen(tgtLabel) - (long)strlen(srcLabel)), NULL)); if (pipFlag) { let(&tgtPrefix, cat( startStringWithNum, space(indentationLevel[step] * PF_INDENT_INC - (long)strlen(locLabDecl)), locLabDecl, tgtLabel, space((long)strlen(srcLabel)), space(maxLabelLen - (long)strlen(tgtLabel) - (long)strlen(srcLabel)), NULL)); let(&srcPrefix, cat( startStringWithoutNum, space(indentationLevel[step] * PF_INDENT_INC - (long)strlen(locLabDecl)), space((long)strlen(locLabDecl)), space((long)strlen(tgtLabel)), srcLabel, space(maxLabelLen - (long)strlen(tgtLabel) - (long)strlen(srcLabel)), NULL)); let(&userPrefix, cat( startStringWithoutNum, space(indentationLevel[step] * PF_INDENT_INC - (long)strlen(locLabDecl)), space((long)strlen(locLabDecl)), space((long)strlen(tgtLabel)), "=(User)", space(maxLabelLen - (long)strlen(tgtLabel) - (long)strlen("=(User)")), NULL)); } /* let(&contPrefix, space(maxStepNumLen + 1 + indentationLevel[step] * PF_INDENT_INC + maxLabelLen + 4)); */ let(&contPrefix, ""); /* Continuation lines use whole screen width */ } if (!pipFlag) { if (!texFlag) { if (!midiFlag) { /* 8/28/00 */ printLongLine(cat(startPrefix," $", chr(type), " ", nmbrCvtMToVString(wrkProof.mathStringPtrs[step]), NULL), contPrefix, chr(1)); /* chr(1) is right-justify flag for printLongLine */ } } else { /* TeX or HTML */ printTexLongMath(wrkProof.mathStringPtrs[step], cat(startPrefix, " $", chr(type), " ", NULL), contPrefix, stmt, indentationLevel[step]); } } else { /* pipFlag */ if (texFlag) { /* nm 3-Feb-04 Added this bug check - it doesn't make sense to do this and it hasn't been tested anyway */ print2("?Unsupported: HTML or LaTeX proof for NEW_PROOF.\n"); bug(244); } if (!nmbrEq(proofInProgress.target[step], proofInProgress.source[step]) && nmbrLen(proofInProgress.source[step])) { if (!texFlag) { printLongLine(cat(tgtPrefix, " $", chr(type), " ", nmbrCvtMToVString(proofInProgress.target[step]), NULL), contPrefix, chr(1)); /* chr(1) is right-justify flag for printLongLine */ printLongLine(cat(srcPrefix," = ", nmbrCvtMToVString(proofInProgress.source[step]), NULL), contPrefix, chr(1)); /* chr(1) is right-justify flag for printLongLine */ } else { /* TeX or HTML */ printTexLongMath(proofInProgress.target[step], cat(tgtPrefix, " $", chr(type), " ", NULL), contPrefix, 0, 0); printTexLongMath(proofInProgress.source[step], cat(srcPrefix, " = ", NULL), contPrefix, 0, 0); } } else { if (!texFlag) { printLongLine(cat(startPrefix, " $", chr(type), " ", nmbrCvtMToVString(proofInProgress.target[step]), NULL), contPrefix, chr(1)); /* chr(1) is right-justify flag for printLongLine */ } else { /* TeX or HTML */ printTexLongMath(proofInProgress.target[step], cat(startPrefix, " $", chr(type), " ", NULL), contPrefix, 0, 0); } } if (nmbrLen(proofInProgress.user[step])) { if (!texFlag) { printLongLine(cat(userPrefix, " = ", nmbrCvtMToVString(proofInProgress.user[step]), NULL), contPrefix, chr(1)); /* chr(1) is right-justify flag for printLongLine */ } else { printTexLongMath(proofInProgress.user[step], cat(userPrefix, " = ", NULL), contPrefix, 0, 0); } } } } } /* Next step */ if (!pipFlag) { cleanWrkProof(); /* Deallocate verifyProof storage */ } if (htmlFlg && texFlag) { outputToString = 1; print2("
Detailed syntax breakdown of Axiom \n"); print2("Detailed syntax breakdown of Definition ", asciiToTt(statement[statemNum].labelName), "
StepHypRef\n"); print2("Expression
WARNING: Proof has a severe error.\n"); print2("
\n"); /* 10/10/02 Moved here from mmwtex.c */ /*print2("Colors of variables:\n");*/ printLongLine(cat( "
", NULL), "", "\""); if (essentialFlag) { /* Means this is not a syntax breakdown of a definition which is called from typeStatement() */ /* Create list of syntax statements used */ let(&statementUsedFlags, string(statements + 1, 'N')); /* Init. to 'no' */ for (step = 0; step < plen; step++) { stmt = proof[step]; /* Convention: collect all $a's that don't begin with "|-" */ if (stmt > 0) { if (statement[stmt].type == a_) { if (strcmp("|-", mathToken[ (statement[stmt].mathString)[0]].tokenName)) { statementUsedFlags[stmt] = 'Y'; /* Flag to use it */ } } } } /******************************************************************/ /* Start of section added 2/5/02 - for a more complete syntax hints list in the HTML pages, parse the wffs comprising the hypotheses and the statement, and add their syntax to the hints list. */ /* Look up the token "wff" (hard-coded) if we haven't found it before */ if (wffToken == -1) { /* First time */ wffToken = -2; /* In case it's not found because the user's source used a convention different for "wff" for wffs */ for (i = 0; i < mathTokens; i++) { if (!strcmp("wff", mathToken[i].tokenName)) { wffToken = i; break; } } } if (wffToken >= 0) { /* Scan the statement being proved and its essential hypotheses, and find a proof for each of them expressed as a wff */ for (i = -1; i < statement[statemNum].numReqHyp; i++) { /* i = -1 is the statement itself; i >= 0 is hypotheses i */ if (i == -1) { /* If it's not a $p we shouldn't be here */ if (statement[statemNum].type != (char)p_) bug(245); nmbrTmpPtr1 = NULL_NMBRSTRING; nmbrLet(&nmbrTmpPtr1, statement[statemNum].mathString); } else { /* Ignore $f */ if (statement[statement[statemNum].reqHypList[i]].type == (char)f_) continue; /* Must therefore be a $e */ if (statement[statement[statemNum].reqHypList[i]].type != (char)e_) bug(234); nmbrTmpPtr1 = NULL_NMBRSTRING; nmbrLet(&nmbrTmpPtr1, statement[statement[statemNum].reqHypList[i]].mathString); } if (strcmp("|-", mathToken[nmbrTmpPtr1[0]].tokenName)) { /* 1-Oct-05 nm Since non-standard logics may not have this, just break out of this section gracefully */ nmbrTmpPtr2 = NULL_NMBRSTRING; /* To be known after break */ break; /* bug(235); */ /* 1-Oct-05 nm No longer a bug */ } /* Turn "|-" assertion into a "wff" assertion */ nmbrTmpPtr1[0] = wffToken; /* Find proof of formula or simple theorem (no new vars in $e's) */ /* maxEDepth is the maximum depth at which statements with $e hypotheses are considered. A value of 0 means none are considered. */ nmbrTmpPtr2 = proveFloating(nmbrTmpPtr1 /*mString*/, statemNum /*statemNum*/, 0 /*maxEDepth*/, 0, /* step; 0 = step 1 */ /*For messages*/ 0, /*not noDistinct*/ /* 3-May-2016 nm */ 2 /* override discouraged-usage statements silently */ ); if (!nmbrLen(nmbrTmpPtr2)) { /* 1-Oct-05 nm Since a proof may not be found for non-standard logics, just break out of this section gracefully */ break; /* bug(236); */ /* Didn't find syntax proof */ } /* Add to list of syntax statements used */ for (step = 0; step < nmbrLen(nmbrTmpPtr2); step++) { stmt = nmbrTmpPtr2[step]; /* Convention: collect all $a's that don't begin with "|-" */ if (stmt > 0) { if (statementUsedFlags[stmt] == 'N') { /* For slight speedup */ if (statement[stmt].type == a_) { if (strcmp("|-", mathToken[ (statement[stmt].mathString)[0]].tokenName)) { statementUsedFlags[stmt] = 'Y'; /* Flag to use it */ } else { /* In a syntax proof there should be no |- */ /* (In the future, we may want to break instead of calling it a bug, if it's a problem for non-standard logics.) */ bug(237); } } } } else { /* proveFloating never returns a compressed proof */ bug(238); } } /* Deallocate memory */ nmbrLet(&nmbrTmpPtr2, NULL_NMBRSTRING); nmbrLet(&nmbrTmpPtr1, NULL_NMBRSTRING); } /* next i */ /* 1-Oct-05 nm Deallocate memory in case we broke out above */ nmbrLet(&nmbrTmpPtr2, NULL_NMBRSTRING); nmbrLet(&nmbrTmpPtr1, NULL_NMBRSTRING); } /* if (wffToken >= 0) */ /* End of section added 2/5/02 */ /******************************************************************/ let(&tmpStr, ""); for (stmt = 1; stmt <= statements; stmt++) { if (statementUsedFlags[stmt] == 'Y') { if (!tmpStr[0]) { let(&tmpStr, /* 10/10/02 */ /*"Syntax hints: ");*/ "", NULL)); printLongLine(tmpStr, "", "\""); } /* End of syntax hints list */ /* 10/25/02 Output "referenced by" list here */ /* 30-Oct-2018 nm Moved this block to after axioms/defs lists */ /* if (printStringForReferencedBy[0]) { /@ printLongLine takes 130 sec for 'sh st syl/a' @/ /@printLongLine(printStringForReferencedBy, "", "\"");@/ /@ 18-Jul-2015 nm Speedup for 'sh st syl/a' @/ if (outputToString != 1) bug(257); let(&printString, cat(printString, printStringForReferencedBy, NULL)); let(&printStringForReferencedBy, ""); } */ /* Get list of axioms and definitions assumed by proof */ let(&statementUsedFlags, ""); traceProofWork(statemNum, 1, /*essentialFlag*/ "", /*traceToList*/ /* 18-Jul-2015 nm */ &statementUsedFlags, /*&statementUsedFlags*/ &unprovedList /* &unprovedList */); if ((signed)(strlen(statementUsedFlags)) != statements + 1) bug(227); /* First get axioms */ let(&tmpStr, ""); for (stmt = 1; stmt <= statements; stmt++) { if (statementUsedFlags[stmt] == 'Y' && statement[stmt].type == a_) { let(&tmpStr1, left(statement[stmt].labelName, 3)); if (!strcmp(tmpStr1, "ax-")) { if (!tmpStr[0]) { let(&tmpStr, /******* 10/10/02 "The theorem was proved from these axioms: "); *******/ "", NULL)); printLongLine(tmpStr, "", "\""); } /* 10/10/02 Then get definitions */ let(&tmpStr, ""); for (stmt = 1; stmt <= statements; stmt++) { if (statementUsedFlags[stmt] == 'Y' && statement[stmt].type == a_) { let(&tmpStr1, left(statement[stmt].labelName, 3)); if (!strcmp(tmpStr1, "df-")) { if (!tmpStr[0]) { let(&tmpStr, "", NULL)); printLongLine(tmpStr, "", "\""); } /* Print any unproved statements */ if (nmbrLen(unprovedList)) { if (nmbrLen(unprovedList) == 1 && !strcmp(statement[unprovedList[0]].labelName, statement[statemNum].labelName)) { /* When the unproved list consists only of the statement that was traced, it means the statement traced has no proof (or it has a proof, but is incomplete and all earlier ones do have complete proofs). */ printLongLine(cat( "", NULL), "", "\""); } else { printLongLine(cat( "", NULL), "", "\""); } } /* End of axiom list */ /* 30-Oct-2018 nm Moved down from above to put referenced by list last */ if (printStringForReferencedBy[0]) { /* printLongLine takes 130 sec for 'sh st syl/a' */ /*printLongLine(printStringForReferencedBy, "", "\"");*/ /* 18-Jul-2015 nm Speedup for 'sh st syl/a' */ if (outputToString != 1) bug(257); /* 30-Oct-2018 nm Deleted line: */ /*let(&printString, cat(printString, printStringForReferencedBy, NULL));*/ /* 30-Oct-2018 nm Added line: */ printLongLine(printStringForReferencedBy, "", "\""); let(&printStringForReferencedBy, ""); /* 30-Oct-2018 nm */ } else { /* Since we now always print ref-by list even if "(None)", printStringForReferencedBy should never be empty */ bug(263); } } /* if essentialFlag */ /* Printing of the trailer in mmwtex.c will close out string later */ outputToString = 0; } typeProof_return: let(&tmpStr, ""); let(&tmpStr1, ""); let(&statementUsedFlags, ""); let(&locLabDecl, ""); let(&tgtLabel, ""); let(&srcLabel, ""); let(&startPrefix, ""); let(&tgtPrefix, ""); let(&srcPrefix, ""); let(&userPrefix, ""); let(&contPrefix, ""); let(&hypStr, ""); let(&startStringWithNum, ""); /* 22-Apr-2015 nm */ let(&startStringWithoutNum, ""); /* 22-Apr-2015 nm */ nmbrLet(&unprovedList, NULL_NMBRSTRING); nmbrLet(&localLabels, NULL_NMBRSTRING); nmbrLet(&localLabelNames, NULL_NMBRSTRING); nmbrLet(&proof, NULL_NMBRSTRING); nmbrLet(&targetHyps, NULL_NMBRSTRING); nmbrLet(&indentationLevel, NULL_NMBRSTRING); nmbrLet(&essentialFlags, NULL_NMBRSTRING); nmbrLet(&stepRenumber, NULL_NMBRSTRING); nmbrLet(¬UnifiedFlags, NULL_NMBRSTRING); nmbrLet(&relativeStepNums, NULL_NMBRSTRING); /* 22-Apr-2015 nm */ } /* typeProof() */ /* Show details of one proof step */ /* Note: detailStep is the actual step number (starting with 1), not the actual step - 1. */ void showDetailStep(long statemNum, long detailStep) { long i, j, plen, step, stmt, sourceStmt, targetStmt; vstring tmpStr = ""; vstring tmpStr1 = ""; nmbrString *proof = NULL_NMBRSTRING; nmbrString *localLabels = NULL_NMBRSTRING; nmbrString *localLabelNames = NULL_NMBRSTRING; nmbrString *targetHyps = NULL_NMBRSTRING; long nextLocLabNum = 1; /* Next number to be used for a local label */ void *voidPtr; /* bsearch result */ char type; /* Error check */ i = parseProof(statemNum); if (i) { printLongLine("?The proof is incomplete or has an error", "", " "); return; } plen = nmbrLen(wrkProof.proofString); if (plen < detailStep || detailStep < 1) { printLongLine(cat("?The step number should be from 1 to ", str((double)plen), NULL), "", " "); return; } /* Structure getStep is declared in mmveri.h. */ getStep.stepNum = detailStep; /* Non-zero is flag for verifyProof */ parseProof(statemNum); /* ???Do we need to do this again? */ verifyProof(statemNum); nmbrLet(&proof, wrkProof.proofString); /* The proof */ plen = nmbrLen(proof); /* Collect local labels */ for (step = 0; step < plen; step++) { stmt = proof[step]; if (stmt <= -1000) { stmt = -1000 - stmt; if (!nmbrElementIn(1, localLabels, stmt)) { nmbrLet(&localLabels, nmbrAddElement(localLabels, stmt)); } } } /* localLabelNames[] hold an integer which, when converted to string, is the local label name. */ nmbrLet(&localLabelNames, nmbrSpace(plen)); /* Get the target hypotheses */ nmbrLet(&targetHyps, nmbrGetTargetHyp(proof, statemNum)); /* Get local labels */ for (step = 0; step < plen; step++) { stmt = proof[step]; if (stmt >= 0) { if (nmbrElementIn(1, localLabels, step)) { /* This statement declares a local label */ /* First, get a name for the local label, using the next integer that does not match any integer used for a statement label. */ let(&tmpStr1, str((double)nextLocLabNum)); while (1) { voidPtr = (void *)bsearch(tmpStr, allLabelKeyBase, (size_t)numAllLabelKeys, sizeof(long), labelSrchCmp); if (!voidPtr) break; /* It does not conflict */ nextLocLabNum++; /* Try the next one */ let(&tmpStr1, str((double)nextLocLabNum)); } localLabelNames[step] = nextLocLabNum; nextLocLabNum++; /* Prepare for next local label */ } } } /* Next step */ /* Print the step */ let(&tmpStr, statement[targetHyps[detailStep - 1]].labelName); let(&tmpStr1, ""); /* Local label declaration */ stmt = proof[detailStep - 1]; if (stmt < 0) { if (stmt <= -1000) { stmt = -1000 - stmt; /* stmt is now the step number a local label refers to */ let(&tmpStr, cat(tmpStr,"=", str((double)(localLabelNames[stmt])), NULL)); type = statement[proof[stmt]].type; } else { if (stmt != -(long)'?') bug(207); let(&tmpStr, cat(tmpStr,"=",chr(-stmt), NULL)); /* '?' */ type = '?'; } } else { if (nmbrElementIn(1, localLabels, detailStep - 1)) { /* This statement declares a local label */ let(&tmpStr1, cat(str((double)(localLabelNames[detailStep - 1])), ":", NULL)); } let(&tmpStr, cat(tmpStr, "=", statement[stmt].labelName, NULL)); type = statement[stmt].type; } /* Print the proof line */ printLongLine(cat("Proof step ", str((double)detailStep), ": ", tmpStr1, tmpStr, " $", chr(type), " ", nmbrCvtMToVString(wrkProof.mathStringPtrs[detailStep - 1]), NULL), " ", " "); /* Print details about the step */ let(&tmpStr, cat("This step assigns ", NULL)); let(&tmpStr1, ""); stmt = proof[detailStep - 1]; sourceStmt = stmt; if (stmt < 0) { if (stmt <= -1000) { stmt = -1000 - stmt; /* stmt is now the step number a local label refers to */ let(&tmpStr, cat(tmpStr, "step ", str((double)stmt), " (via local label reference \"", str((double)(localLabelNames[stmt])), "\") to ", NULL)); } else { if (stmt != -(long)'?') bug(208); let(&tmpStr, cat(tmpStr, "an unknown statement to ", NULL)); } } else { let(&tmpStr, cat(tmpStr, "source \"", statement[stmt].labelName, "\" ($", chr(statement[stmt].type), ") to ", NULL)); if (nmbrElementIn(1, localLabels, detailStep - 1)) { /* This statement declares a local label */ let(&tmpStr1, cat(" This step also declares the local label ", str((double)(localLabelNames[detailStep - 1])), ", which is used later on.", NULL)); } } targetStmt = targetHyps[detailStep - 1]; if (detailStep == plen) { let(&tmpStr, cat(tmpStr, "the final assertion being proved.", NULL)); } else { let(&tmpStr, cat(tmpStr, "target \"", statement[targetStmt].labelName, "\" ($", chr(statement[targetStmt].type), ").", NULL)); } let(&tmpStr, cat(tmpStr, tmpStr1, NULL)); if (sourceStmt >= 0) { if (statement[sourceStmt].type == a_ || statement[sourceStmt].type == p_) { j = nmbrLen(statement[sourceStmt].reqHypList); if (j != nmbrLen(getStep.sourceHyps)) bug(209); if (!j) { let(&tmpStr, cat(tmpStr, " The source assertion requires no hypotheses.", NULL)); } else { if (j == 1) { let(&tmpStr, cat(tmpStr, " The source assertion requires the hypothesis ", NULL)); } else { let(&tmpStr, cat(tmpStr, " The source assertion requires the hypotheses ", NULL)); } for (i = 0; i < j; i++) { let(&tmpStr, cat(tmpStr, "\"", statement[statement[sourceStmt].reqHypList[i]].labelName, "\" ($", chr(statement[statement[sourceStmt].reqHypList[i]].type), ", step ", str((double)(getStep.sourceHyps[i] + 1)), ")", NULL)); if (i == 0 && j == 2) { let(&tmpStr, cat(tmpStr, " and ", NULL)); } if (i < j - 2 && j > 2) { let(&tmpStr, cat(tmpStr, ", ", NULL)); } if (i == j - 2 && j > 2) { let(&tmpStr, cat(tmpStr, ", and ", NULL)); } } let(&tmpStr, cat(tmpStr, ".", NULL)); } } } if (detailStep < plen) { let(&tmpStr, cat(tmpStr, " The parent assertion of the target hypothesis is \"", statement[getStep.targetParentStmt].labelName, "\" ($", chr(statement[getStep.targetParentStmt].type),", step ", str((double)(getStep.targetParentStep)), ").", NULL)); } else { let(&tmpStr, cat(tmpStr, " The target has no parent because it is the assertion being proved.", NULL)); } printLongLine(tmpStr, "", " "); if (sourceStmt >= 0) { if (statement[sourceStmt].type == a_ || statement[sourceStmt].type == p_) { print2("The source assertion before substitution was:\n"); printLongLine(cat(" ", statement[sourceStmt].labelName, " $", chr(statement[sourceStmt].type), " ", nmbrCvtMToVString( statement[sourceStmt].mathString), NULL), " ", " "); j = nmbrLen(getStep.sourceSubstsNmbr); if (j == 1) { printLongLine(cat( "The following substitution was made to the source assertion:", NULL),""," "); } else { printLongLine(cat( "The following substitutions were made to the source assertion:", NULL),""," "); } if (!j) { print2(" (None)\n"); } else { print2(" Variable Substituted with\n"); for (i = 0; i < j; i++) { printLongLine(cat(" ", mathToken[getStep.sourceSubstsNmbr[i]].tokenName," ", space(9 - (long)strlen( mathToken[getStep.sourceSubstsNmbr[i]].tokenName)), nmbrCvtMToVString(getStep.sourceSubstsPntr[i]), NULL), " ", " "); } } } } if (detailStep < plen) { print2("The target hypothesis before substitution was:\n"); printLongLine(cat(" ", statement[targetStmt].labelName, " $", chr(statement[targetStmt].type), " ", nmbrCvtMToVString( statement[targetStmt].mathString), NULL), " ", " "); j = nmbrLen(getStep.targetSubstsNmbr); if (j == 1) { printLongLine(cat( "The following substitution was made to the target hypothesis:", NULL),""," "); } else { printLongLine(cat( "The following substitutions were made to the target hypothesis:", NULL),""," "); } if (!j) { print2(" (None)\n"); } else { print2(" Variable Substituted with\n"); for (i = 0; i < j; i++) { printLongLine(cat(" ", mathToken[getStep.targetSubstsNmbr[i]].tokenName, " ", space(9 - (long)strlen( mathToken[getStep.targetSubstsNmbr[i]].tokenName)), nmbrCvtMToVString(getStep.targetSubstsPntr[i]), NULL), " ", " "); } } } cleanWrkProof(); getStep.stepNum = 0; /* Zero is flag for verifyProof to ignore getStep info */ /* Deallocate getStep contents */ j = pntrLen(getStep.sourceSubstsPntr); for (i = 0; i < j; i++) { nmbrLet((nmbrString **)(&getStep.sourceSubstsPntr[i]), NULL_NMBRSTRING); } j = pntrLen(getStep.targetSubstsPntr); for (i = 0; i < j; i++) { nmbrLet((nmbrString **)(&getStep.targetSubstsPntr[i]), NULL_NMBRSTRING); } nmbrLet(&getStep.sourceHyps, NULL_NMBRSTRING); pntrLet(&getStep.sourceSubstsPntr, NULL_PNTRSTRING); nmbrLet(&getStep.sourceSubstsNmbr, NULL_NMBRSTRING); pntrLet(&getStep.targetSubstsPntr, NULL_PNTRSTRING); nmbrLet(&getStep.targetSubstsNmbr, NULL_NMBRSTRING); /* Deallocate other strings */ let(&tmpStr, ""); let(&tmpStr1, ""); nmbrLet(&localLabels, NULL_NMBRSTRING); nmbrLet(&localLabelNames, NULL_NMBRSTRING); nmbrLet(&proof, NULL_NMBRSTRING); nmbrLet(&targetHyps, NULL_NMBRSTRING); } /* showDetailStep */ /* Summary of statements in proof for SHOW PROOF / STATEMENT_SUMMARY */ void proofStmtSumm(long statemNum, flag essentialFlag, flag texFlag) { long i, j, k, pos, stmt, plen, slen, step; char type; vstring statementUsedFlags = ""; /* 'Y'/'N' flag that statement is used */ vstring str1 = ""; vstring str2 = ""; vstring str3 = ""; nmbrString *statementList = NULL_NMBRSTRING; nmbrString *proof = NULL_NMBRSTRING; nmbrString *essentialFlags = NULL_NMBRSTRING; /* 10/10/02 This section is never called in HTML mode anymore. The code is left in though just in case we somehow get here and the user continues through the bug. */ if (texFlag && htmlFlag) bug(239); if (!texFlag) { print2("Summary of statements used in the proof of \"%s\":\n", statement[statemNum].labelName); } else { outputToString = 1; /* Flag for print2 to add to printString */ if (!htmlFlag) { print2("\n"); print2("\\vspace{1ex} %%3\n"); printLongLine(cat("Summary of statements used in the proof of ", "{\\tt ", asciiToTt(statement[statemNum].labelName), "}:", NULL), "", " "); } else { printLongLine(cat("Summary of statements used in the proof of ", "", asciiToTt(statement[statemNum].labelName), ":", NULL), "", "\""); } outputToString = 0; fprintf(texFilePtr, "%s", printString); let(&printString, ""); } if (statement[statemNum].type != p_) { print2(" This is not a provable ($p) statement.\n"); return; } /* 20-Oct-2013 nm Don't use bad proofs (incomplete proofs are ok) */ if (parseProof(statemNum) > 1) { /* The proof has an error, so use the empty proof */ nmbrLet(&proof, nmbrAddElement(NULL_NMBRSTRING, -(long)'?')); } else { nmbrLet(&proof, wrkProof.proofString); } plen = nmbrLen(proof); /* Get the essential step flags, if required */ if (essentialFlag) { nmbrLet(&essentialFlags, nmbrGetEssential(proof)); } for (step = 0; step < plen; step++) { if (essentialFlag) { if (!essentialFlags[step]) continue; /* Ignore floating hypotheses */ } stmt = proof[step]; if (stmt < 0) { continue; /* Ignore '?' and local labels */ } if (1) { /* Limit list to $a and $p only */ if (statement[stmt].type != a_ && statement[stmt].type != p_) { continue; } } /* Add this statement to the statement list if not already in it */ if (!nmbrElementIn(1, statementList, stmt)) { nmbrLet(&statementList, nmbrAddElement(statementList, stmt)); } } /* Next step */ /* Prepare the output */ /* First, fill in the statementUsedFlags char array. This allows us to sort the output by statement number without calling a sort routine. */ slen = nmbrLen(statementList); let(&statementUsedFlags, string(statements + 1, 'N')); /* Init. to 'no' */ for (pos = 0; pos < slen; pos++) { stmt = statementList[pos]; if (stmt > statemNum || stmt < 1) bug(210); statementUsedFlags[stmt] = 'Y'; } /* Next, build the output string */ for (stmt = 1; stmt < statemNum; stmt++) { if (statementUsedFlags[stmt] == 'Y') { assignStmtFileAndLineNum(stmt); /* 9-Jan-2018 nm */ let(&str1, cat(" is located on line ", str((double)(statement[stmt].lineNum)), " of the file ", NULL)); if (!texFlag) { print2("\n"); printLongLine(cat("Statement ", statement[stmt].labelName, str1, "\"", statement[stmt].fileName, "\".",NULL), "", " "); } else { outputToString = 1; /* Flag for print2 to add to printString */ if (!htmlFlag) { print2("\n"); print2("\n"); print2("\\vspace{1ex} %%4\n"); printLongLine(cat("Statement {\\tt ", asciiToTt(statement[stmt].labelName), "} ", str1, "{\\tt ", asciiToTt(statement[stmt].fileName), "}.", NULL), "", " "); print2("\n"); } else { printLongLine(cat("Statement ", asciiToTt(statement[stmt].labelName), " ", str1, " ", asciiToTt(statement[stmt].fileName), " ", NULL), "", "\""); } outputToString = 0; fprintf(texFilePtr, "%s", printString); let(&printString, ""); } /* type = statement[stmt].type; */ /* 18-Sep-2013 Not used */ let(&str1, ""); str1 = getDescription(stmt); if (str1[0]) { if (!texFlag) { printLongLine(cat("\"", str1, "\"", NULL), "", " "); } else { /* printTexComment(str1, 1); */ /* 17-Nov-2015 nm Added 3rd & 4th arguments */ printTexComment(str1, /* Sends result to texFilePtr */ 1, /* 1 = htmlCenterFlag */ PROCESS_EVERYTHING, /* actionBits */ /* 13-Dec-2018 nm */ 0 /* 1 = noFileCheck */); } } /* print2("Its mandatory hypotheses in RPN order are:\n"); */ j = nmbrLen(statement[stmt].reqHypList); for (i = 0; i < j; i++) { k = statement[stmt].reqHypList[i]; if (!essentialFlag || statement[k].type != f_) { let(&str2, cat(" ",statement[k].labelName, " $", chr(statement[k].type), " ", NULL)); if (!texFlag) { printLongLine(cat(str2, nmbrCvtMToVString(statement[k].mathString), " $.", NULL), " "," "); } else { let(&str3, space((long)strlen(str2))); printTexLongMath(statement[k].mathString, str2, str3, 0, 0); } } } let(&str1, ""); type = statement[stmt].type; if (type == p_) let(&str1, " $= ..."); let(&str2, cat(" ", statement[stmt].labelName, " $",chr(type), " ", NULL)); if (!texFlag) { printLongLine(cat(str2, nmbrCvtMToVString(statement[stmt].mathString), str1, " $.", NULL), " ", " "); } else { let(&str3, space((long)strlen(str2))); printTexLongMath(statement[stmt].mathString, str2, str3, 0, 0); } } /* End if (statementUsedFlag[stmt] == 'Y') */ } /* Next stmt */ let(&statementUsedFlags, ""); /* 'Y'/'N' flag that statement is used */ let(&str1, ""); let(&str2, ""); let(&str3, ""); nmbrLet(&statementList, NULL_NMBRSTRING); nmbrLet(&proof, NULL_NMBRSTRING); nmbrLet(&essentialFlags, NULL_NMBRSTRING); } /* proofStmtSumm */ /* Traces back the statements used by a proof, recursively. */ /* Returns 1 if at least one label is printed (or would be printed in case testOnlyFlag=1); otherwise, returns 0 */ /* matchList suppresses all output except labels matching matchList */ /* testOnlyFlag prevents any printout; it is used to determine whether there is an unwanted axiom for MINIMIZE_WITH /FORBID. */ /* void traceProof(long statemNum, */ /* before 20-May-2013 */ flag traceProof(long statemNum, /* 20-May-2013 nm */ flag essentialFlag, flag axiomFlag, vstring matchList, /* 19-May-2013 nm */ vstring traceToList, /* 18-Jul-2015 nm */ flag testOnlyFlag /* 20-May-2013 nm */) { long stmt, pos; vstring statementUsedFlags = ""; /* y/n flags that statement is used */ vstring outputString = ""; nmbrString *unprovedList = NULL_NMBRSTRING; flag foundFlag = 0; /* Make sure we're calling this with $p statements only */ if (statement[statemNum].type != (char)p_) bug(249); if (!testOnlyFlag) { /* 20-May-2013 nm */ if (axiomFlag) { print2( "Statement \"%s\" assumes the following axioms ($a statements):\n", statement[statemNum].labelName); } else if (traceToList[0] == 0) { print2( "The proof of statement \"%s\" uses the following earlier statements:\n", statement[statemNum].labelName); } else { print2( "The proof of statement \"%s\" traces back to \"%s\" via:\n", statement[statemNum].labelName, traceToList); } } traceProofWork(statemNum, essentialFlag, traceToList, /* 18-Jul-2015 nm */ &statementUsedFlags, &unprovedList); if ((signed)(strlen(statementUsedFlags)) != statements + 1) bug(226); /* Build the output string */ let(&outputString, ""); for (stmt = 1; stmt < statemNum; stmt++) { if (statementUsedFlags[stmt] == 'Y') { /* 19-May-2013 nm - Added MATCH qualifier */ if (matchList[0]) { /* There is a list to match */ /* Don't include unmatched labels */ if (!matchesList(statement[stmt].labelName, matchList, '*', '?')) continue; } /* 20-May-2013 nm Skip rest of scan in testOnlyFlag mode */ foundFlag = 1; /* At least one label would be printed */ if (testOnlyFlag) { goto TRACE_RETURN; } if (axiomFlag) { if (statement[stmt].type == a_) { let(&outputString, cat(outputString, " ", statement[stmt].labelName, NULL)); } } else { let(&outputString, cat(outputString, " ", statement[stmt].labelName, NULL)); switch (statement[stmt].type) { case a_: let(&outputString, cat(outputString, "($a)", NULL)); break; case e_: let(&outputString, cat(outputString, "($e)", NULL)); break; case f_: let(&outputString, cat(outputString, "($f)", NULL)); break; } } } /* End if (statementUsedFlag[stmt] == 'Y') */ } /* Next stmt */ /* 20-May-2013 nm Skip printing in testOnlyFlag mode */ if (testOnlyFlag) { goto TRACE_RETURN; } if (outputString[0]) { let(&outputString, cat(" ", outputString, NULL)); } else { let(&outputString, " (None)"); } /* Print the output */ printLongLine(outputString, " ", " "); /* Print any unproved statements */ if (nmbrLen(unprovedList)) { print2("Warning: the following traced statement(s) were not proved:\n"); let(&outputString, ""); for (pos = 0; pos < nmbrLen(unprovedList); pos++) { let(&outputString, cat(outputString, " ", statement[unprovedList[ pos]].labelName, NULL)); } let(&outputString, cat(" ", outputString, NULL)); printLongLine(outputString, " ", " "); } TRACE_RETURN: /* Deallocate */ let(&outputString, ""); let(&statementUsedFlags, ""); nmbrLet(&unprovedList, NULL_NMBRSTRING); return foundFlag; } /* traceProof */ /* Traces back the statements used by a proof, recursively. Returns a nmbrString with a list of statements and unproved statements */ void traceProofWork(long statemNum, flag essentialFlag, vstring traceToList, /* 18-Jul-2015 nm */ vstring *statementUsedFlagsP, /* 'Y'/'N' flag that statement is used */ nmbrString **unprovedListP) { long pos, stmt, plen, slen, step; nmbrString *statementList = NULL_NMBRSTRING; nmbrString *proof = NULL_NMBRSTRING; nmbrString *essentialFlags = NULL_NMBRSTRING; vstring traceToFilter = ""; /* 18-Jul-2015 nm */ vstring str1 = ""; /* 18-Jul-2015 nm */ long j; /* 18-Jul-2015 nm */ /* 18-Jul-2015 nm */ /* Preprocess the "SHOW TRACE_BACK ... / TO" traceToList list if any */ if (traceToList[0] != 0) { let(&traceToFilter, string(statements + 1, 'N')); /* Init. to 'no' */ /* Wildcard match scan */ for (stmt = 1; stmt <= statements; stmt++) { if (statement[stmt].type != (char)a_ && statement[stmt].type != (char)p_) continue; /* Not a $a or $p statement; skip it */ /* Wildcard matching */ if (!matchesList(statement[stmt].labelName, traceToList, '*', '?')) continue; let(&str1, ""); str1 = traceUsage(stmt /*showStatement*/, 1, /*recursiveFlag*/ statemNum /* cutoffStmt */); traceToFilter[stmt] = 'Y'; /* Include the statement we're showing usage of */ if (str1[0] == 'Y') { /* There is some usage */ for (j = stmt + 1; j <= statements; j++) { /* OR in the usage to the filter */ if (str1[j] == 'Y') traceToFilter[j] = 'Y'; } } } /* Next i (statement number) */ } /* if (traceToList[0] != 0) */ nmbrLet(&statementList, nmbrSpace(statements)); statementList[0] = statemNum; slen = 1; nmbrLet(&(*unprovedListP), NULL_NMBRSTRING); /* List of unproved statements */ let(&(*statementUsedFlagsP), string(statements + 1, 'N')); /* Init. to 'no' */ (*statementUsedFlagsP)[statemNum] = 'Y'; /* nm 22-Nov-2014 */ for (pos = 0; pos < slen; pos++) { if (statement[statementList[pos]].type != p_) { continue; /* Not a $p */ } /* 20-Oct-2013 nm Don't use bad proofs (incomplete proofs are ok) */ if (parseProof(statementList[pos]) > 1) { /* The proof has an error, so use the empty proof */ nmbrLet(&proof, nmbrAddElement(NULL_NMBRSTRING, -(long)'?')); } else { nmbrLet(&proof, wrkProof.proofString); } plen = nmbrLen(proof); /* Get the essential step flags, if required */ if (essentialFlag) { nmbrLet(&essentialFlags, nmbrGetEssential(proof)); } for (step = 0; step < plen; step++) { if (essentialFlag) { if (!essentialFlags[step]) continue; /* Ignore floating hypotheses */ } stmt = proof[step]; if (stmt < 0) { if (stmt > -1000) { /* '?' */ if (!nmbrElementIn(1, *unprovedListP, statementList[pos])) { nmbrLet(&(*unprovedListP), nmbrAddElement(*unprovedListP, statementList[pos])); /* Add to list of unproved statements */ } } continue; /* Ignore '?' and local labels */ } if (1) { /* Limit list to $a and $p only */ if (statement[stmt].type != a_ && statement[stmt].type != p_) { continue; } } /* Add this statement to the statement list if not already in it */ if ((*statementUsedFlagsP)[stmt] == 'N') { /*(*statementUsedFlagsP)[stmt] = 'Y';*/ /* 18-Jul-2015 deleted */ /* 18-Jul-2015 nm */ if (traceToList[0] == 0) { statementList[slen] = stmt; slen++; (*statementUsedFlagsP)[stmt] = 'Y'; } else { if (traceToFilter[stmt] == 'Y') { statementList[slen] = stmt; slen++; (*statementUsedFlagsP)[stmt] = 'Y'; } } } } /* Next step */ } /* Next pos */ /* Deallocate */ nmbrLet(&essentialFlags, NULL_NMBRSTRING); nmbrLet(&proof, NULL_NMBRSTRING); nmbrLet(&statementList, NULL_NMBRSTRING); let(&str1, ""); let(&str1, ""); return; } /* traceProofWork */ nmbrString *stmtFoundList = NULL_NMBRSTRING; long indentShift = 0; /* Traces back the statements used by a proof, recursively, with tree display.*/ void traceProofTree(long statemNum, flag essentialFlag, long endIndent) { if (statement[statemNum].type != p_) { print2("Statement %s is not a $p statement.\n", statement[statemNum].labelName); return; } printLongLine(cat("The proof tree traceback for statement \"", statement[statemNum].labelName, "\" follows. The statements used by each proof are indented one level in,", " below the statement being proved. Hypotheses are not included.", NULL), "", " "); print2("\n"); nmbrLet(&stmtFoundList, NULL_NMBRSTRING); indentShift = 0; traceProofTreeRec(statemNum, essentialFlag, endIndent, 0); nmbrLet(&stmtFoundList, NULL_NMBRSTRING); } /* traceProofTree */ void traceProofTreeRec(long statemNum, flag essentialFlag, long endIndent, long recursDepth) { long i, pos, stmt, plen, slen, step; vstring outputStr = ""; nmbrString *localFoundList = NULL_NMBRSTRING; nmbrString *localPrintedList = NULL_NMBRSTRING; flag unprovedFlag = 0; nmbrString *proof = NULL_NMBRSTRING; nmbrString *essentialFlags = NULL_NMBRSTRING; let(&outputStr, ""); outputStr = getDescription(statemNum); /* Get statement comment */ let(&outputStr, edit(outputStr, 8 + 16 + 128)); /* Trim and reduce spaces */ slen = len(outputStr); for (i = 0; i < slen; i++) { /* Change newlines to spaces in comment */ if (outputStr[i] == '\n') { outputStr[i] = ' '; } } #define INDENT_INCR 3 #define MAX_LINE_LEN 79 if ((recursDepth * INDENT_INCR - indentShift) > (screenWidth - MAX_LINE_LEN) + 50) { indentShift = indentShift + 40 + (screenWidth - MAX_LINE_LEN); print2("****** Shifting indentation. Total shift is now %ld.\n", (long)indentShift); } if ((recursDepth * INDENT_INCR - indentShift) < 1 && indentShift != 0) { indentShift = indentShift - 40 - (screenWidth - MAX_LINE_LEN); print2("****** Shifting indentation. Total shift is now %ld.\n", (long)indentShift); } let(&outputStr, cat(space(recursDepth * INDENT_INCR - indentShift), statement[statemNum].labelName, " $", chr(statement[statemNum].type), " \"", edit(outputStr, 8 + 128), "\"", NULL)); if (len(outputStr) > MAX_LINE_LEN + (screenWidth - MAX_LINE_LEN)) { let(&outputStr, cat(left(outputStr, MAX_LINE_LEN + (screenWidth - MAX_LINE_LEN) - 3), "...", NULL)); } if (statement[statemNum].type == p_ || statement[statemNum].type == a_) { /* Only print assertions to reduce output bulk */ print2("%s\n", outputStr); } if (statement[statemNum].type != p_) { let(&outputStr, ""); return; } if (endIndent) { /* An indentation level limit is set */ if (endIndent < recursDepth + 2) { let(&outputStr, ""); return; } } /* 20-Oct-2013 nm Don't use bad proofs (incomplete proofs are ok) */ if (parseProof(statemNum) > 1) { /* The proof has an error, so use the empty proof */ nmbrLet(&proof, nmbrAddElement(NULL_NMBRSTRING, -(long)'?')); } else { nmbrLet(&proof, wrkProof.proofString); } plen = nmbrLen(proof); /* Get the essential step flags, if required */ if (essentialFlag) { nmbrLet(&essentialFlags, nmbrGetEssential(proof)); } nmbrLet(&localFoundList, NULL_NMBRSTRING); nmbrLet(&localPrintedList, NULL_NMBRSTRING); for (step = 0; step < plen; step++) { if (essentialFlag) { if (!essentialFlags[step]) continue; /* Ignore floating hypotheses */ } stmt = proof[step]; if (stmt < 0) { if (stmt > -1000) { /* '?' */ unprovedFlag = 1; } continue; /* Ignore '?' and local labels */ } if (!nmbrElementIn(1, localFoundList, stmt)) { nmbrLet(&localFoundList, nmbrAddElement(localFoundList, stmt)); } if (!nmbrElementIn(1, stmtFoundList, stmt)) { traceProofTreeRec(stmt, essentialFlag, endIndent, recursDepth + 1); nmbrLet(&localPrintedList, nmbrAddElement(localPrintedList, stmt)); nmbrLet(&stmtFoundList, nmbrAddElement(stmtFoundList, stmt)); } } /* Next step */ /* See if there are any old statements printed previously */ slen = nmbrLen(localFoundList); let(&outputStr, ""); for (pos = 0; pos < slen; pos++) { stmt = localFoundList[pos]; if (!nmbrElementIn(1, localPrintedList, stmt)) { /* Don't include $f, $e in output */ if (statement[stmt].type == p_ || statement[stmt].type == a_) { let(&outputStr, cat(outputStr, " ", statement[stmt].labelName, NULL)); } } } if (len(outputStr)) { printLongLine(cat(space(INDENT_INCR * (recursDepth + 1) - 1 - indentShift), outputStr, " (shown above)", NULL), space(INDENT_INCR * (recursDepth + 2) - indentShift), " "); } if (unprovedFlag) { printLongLine(cat(space(INDENT_INCR * (recursDepth + 1) - indentShift), "*** Statement ", statement[statemNum].labelName, " has not been proved." , NULL), space(INDENT_INCR * (recursDepth + 2)), " "); } let(&outputStr, ""); nmbrLet(&localFoundList, NULL_NMBRSTRING); nmbrLet(&localPrintedList, NULL_NMBRSTRING); nmbrLet(&proof, NULL_NMBRSTRING); nmbrLet(&essentialFlags, NULL_NMBRSTRING); } /* traceProofTreeRec */ /* Called by SHOW TRACE_BACK
", "Colors of variables: ", htmlVarColor, "
Syntax hints: "); } /* 10/6/99 - Get the main symbol in the syntax */ /* This section can be deleted if not wanted - it is custom for set.mm and might not work with other .mm's */ let(&tmpStr1, ""); for (i = 1 /* Skip |- */; i < statement[stmt].mathStringLen; i++) { if (mathToken[(statement[stmt].mathString)[i]].tokenType == (char)con_) { /* Skip parentheses, commas, etc. */ if (strcmp(mathToken[(statement[stmt].mathString)[i] ].tokenName, "(") && strcmp(mathToken[(statement[stmt].mathString)[i] ].tokenName, ",") && strcmp(mathToken[(statement[stmt].mathString)[i] ].tokenName, ")") && strcmp(mathToken[(statement[stmt].mathString)[i] ].tokenName, ":") /* 14-Oct-2019 nm Use |-> rather than e. for cmpt, cmpt2 */ && !(!strcmp(mathToken[(statement[stmt].mathString)[i] ].tokenName, "e.") && (!strcmp(statement[stmt].labelName, "cmpt") || !strcmp(statement[stmt].labelName, "cmpt2"))) ) { tmpStr1 = tokenToTex(mathToken[(statement[stmt].mathString)[i] ].tokenName, stmt); /* 14-Jan-2016 nm */ let(&tmpStr1, cat( (altHtmlFlag ? cat("", NULL) : ""), /* 14-Jan-2016 nm */ tmpStr1, (altHtmlFlag ? "" : ""), NULL)); break; } } } /* Next i */ /* Special cases hard-coded for set.mm */ if (!strcmp(statement[stmt].labelName, "wbr")) /* binary relation */ let(&tmpStr1, " class class class "); if (!strcmp(statement[stmt].labelName, "cv")) let(&tmpStr1, "[set variable]"); /* 10/10/02 Let's don't do cv - confusing to reader */ if (!strcmp(statement[stmt].labelName, "cv")) continue; if (!strcmp(statement[stmt].labelName, "co")) /* operation */ let(&tmpStr1, "(class class class)"); let(&tmpStr, cat(tmpStr, "  ", tmpStr1, NULL)); /* End of 10/6/99 section - Get the main symbol in the syntax */ let(&tmpStr1, ""); tmpStr1 = pinkHTML(stmt); /******* 10/10/02 let(&tmpStr, cat(tmpStr, "", statement[stmt].labelName, "   ", NULL)); *******/ let(&tmpStr, cat(tmpStr, "", statement[stmt].labelName, "", tmpStr1, NULL)); } } if (tmpStr[0]) { let(&tmpStr, cat(tmpStr, "
This theorem was proved from axioms:"); } let(&tmpStr1, ""); tmpStr1 = pinkHTML(stmt); let(&tmpStr, cat(tmpStr, "  ", statement[stmt].labelName, "", tmpStr1, NULL)); } } } /* next stmt */ if (tmpStr[0]) { let(&tmpStr, cat(tmpStr, "
This theorem depends on definitions:"); } let(&tmpStr1, ""); tmpStr1 = pinkHTML(stmt); let(&tmpStr, cat(tmpStr, "  ", statement[stmt].labelName, "", tmpStr1, NULL)); } } } /* next stmt */ if (tmpStr[0]) { let(&tmpStr, cat(tmpStr, "
 ", "WARNING: This theorem has an incomplete proof.
 ", "WARNING: This proof depends on the following unproved theorem(s): ", NULL), "", "\""); let(&tmpStr, ""); for (i = 0; i < nmbrLen(unprovedList); i++) { let(&tmpStr, cat(tmpStr, " ", statement[unprovedList[i]].labelName, "", NULL)); } printLongLine(cat(tmpStr, "
\n", "%"); print2(" \n"); print2(" \n"); print2(" \n"); /* print2(" \n"); */ /* 26-Dec-2016 nm Delete extra */ /* print2("
\"%s\"\n",\n"); print2(" \n", GREEN_TITLE_COLOR); /* Allow plenty of room for long titles (although over 79 chars. will trigger bug 1505). */ print2("%s\n", (showStatement < extHtmlStmt ? htmlTitle : (showStatement < sandboxStmt ? extHtmlTitle : localSandboxTitle))); print2("
\n", "%"); print2("", NULL), "", "\""); /@} else {@/ } else if (showStatement < sandboxStmt) { /@ 29-Jul-2008 nm Sandbox stuff @/ printLongLine(cat("ROWSPAN=2>", extHtmlHome, "", NULL), "", "\""); /@ 29-Jul-2008 nm Sandbox stuff @/ } else { printLongLine(cat("ROWSPAN=2>", sandboxHome, "", NULL), "", "\""); } if (showStatement < extHtmlStmt) { printLongLine(cat( "\n"); print2(" \n"); print2(" \n"); print2(" \n"); print2(" \n"); print2(" \n"); print2("
\n"); print2("Home\n"); print2(""); */ /* if (showStatement < extHtmlStmt) { printLongLine(cat("ROWSPAN=2>", htmlHome, "", htmlTitle, "", NULL), "", "\""); /@} else {@/ } else if (showStatement < sandboxStmt) { /@ 29-Jul-2008 nm Sandbox stuff @/ printLongLine(cat( "", extHtmlTitle, "", NULL), "", "\""); /@ 29-Jul-2008 nm Sandbox stuff @/ } else { printLongLine(cat( "", /@sandboxTitle,@/ /@ 2-Aug-2009 nm - "Mathbox for " mod @/ localSandboxTitle, "", NULL), "", "\""); } */ if (texHeaderFlag) { /* For HTML, 1 means to put prev/next links */ /* Put Previous/Next links into web page */ print2(" \n", "%"); print2(" \n"); /* Find the previous statement with a web page */ j = 0; k = 0; for (i = showStatement - 1; i >= 1; i--) { if ((statement[i].type == (char)p_ || statement[i].type == (char)a_ ) /* Skip dummy "xxx..." statements. We rely on lazy evaluation to prevent array bound overflow. */ /* 16-Aug-2016 nm Took out this obsolete feature */ /* && (statement[i].labelName[0] != 'x' || statement[i].labelName[1] != 'x' || statement[i].labelName[2] != 'x') */ ) { j = i; break; } } if (j == 0) { k = 1; /* First statement flag */ /* For the first statement, wrap to last one */ for (i = statements; i >= 1; i--) { if ((statement[i].type == (char)p_ || statement[i].type == (char)a_ ) /* Skip dummy "xxx..." statements. We rely on lazy evaluation to prevent array bound overflow. */ /* 16-Aug-2016 nm Took out this obsolete feature */ /* && (statement[i].labelName[0] != 'x' || statement[i].labelName[1] != 'x' || statement[i].labelName[2] != 'x') */ ) { j = i; break; } } } if (j == 0) bug(2314); print2(" \n", statement[j].labelName); if (!k) { print2(" < Previous  \n"); } else { print2(" < Wrap  \n"); } /* Find the next statement with a web page */ j = 0; k = 0; for (i = showStatement + 1; i <= statements; i++) { if ((statement[i].type == (char)p_ || statement[i].type == (char)a_ ) /* Skip dummy "xxx..." statements. We rely on lazy evaluation to prevent array bound overflow. */ /* 16-Aug-2016 nm Took out this obsolete feature */ /* && (statement[i].labelName[0] != 'x' || statement[i].labelName[1] != 'x' || statement[i].labelName[2] != 'x') */ ) { j = i; break; } } if (j == 0) { k = 1; /* Last statement flag */ /* For the last statement, wrap to first one */ for (i = 1; i <= statements; i++) { if ((statement[i].type == (char)p_ || statement[i].type == (char)a_ ) /* Skip dummy "xxx..." statements. We rely on lazy evaluation to prevent array bound overflow. */ /* 16-Aug-2016 nm Took out this obsolete feature */ /* && (statement[i].labelName[0] != 'x' || statement[i].labelName[1] != 'x' || statement[i].labelName[2] != 'x') */ ) { j = i; break; } } } if (j == 0) bug(2315); /*print2("Next\n",*/ if (!k) { print2(" Next >\n", statement[j].labelName); } else { print2(" Wrap >\n", statement[j].labelName); } print2(" \n"); /* ??? Is the closing printed if there is no altHtml? This should be tested. 8/9/03 ndm */ /* 15-Aug-04 nm Compute the theorem list page number. ??? Temporarily we assume it to be 100 (hardcoded). Todo: This should be fixed to use the same as the THEOREMS_PER_PAGE in WRITE THEOREMS (have a SET global variable in place of THEOREMS_PER_PAGE?) */ i = ((statement[showStatement].pinkNumber - 1) / 100) + 1; /* Page # */ /* let(&tmpStr, cat("mmtheorems", (i == 1) ? "" : str(i), ".html#", */ /* 18-Jul-2015 nm - all thm pages now have page num after mmtheorems since mmtheorems.html is now just the table of contents */ let(&tmpStr, cat("mmtheorems", str((double)i), ".html#", statement[showStatement].labelName, NULL)); /* Link to page/stmt */ /*print2("
Nearby theorems\n", tmpStr);*/ /* 3-May-2017 nm Break up lines w/ long labels to prevent bug 1505 */ printLongLine(cat("
Nearby theorems", NULL), " ", " "); /* Print the GIF/Unicode Font choice, if directories are specified */ /* if (htmlDir[0]) { if (altHtmlFlag) { print2("
GIF version\n", htmlDir, texFileName); } else { print2("
Unicode version\n", altHtmlDir, texFileName); } } */ print2(" \n"); print2("
\n"); print2(" Mirrors  >\n"); print2("  Home  >\n"); print2("  %s  >\n", (showStatement < extHtmlStmt ? htmlHomeHREF : (showStatement < sandboxStmt ? extHtmlHomeHREF : htmlHomeHREF)), (showStatement < extHtmlStmt ? htmlTitleAbbr : (showStatement < sandboxStmt ? extHtmlTitleAbbr : htmlTitleAbbr))); print2("  Th. List  >\n"); if (showStatement >= sandboxStmt) { print2("  \n"); print2(" Mathboxes  >\n"); } print2("  %s\n", /* Strip off ".html" */ left(texFileName, (long)strlen(texFileName) - 5)); print2(" \n"); print2(" \n"); print2(" \n"); /* 3-Jun-2018 nm Add link to Thierry Arnoux's site */ /* This was added to version 0.162 to become 0.162-thierry */ /****** THIS IS TEMPORARY AND MAY BE CHANGED OR DELETED *********/ printLongLine(cat(" Structured version  ", NULL), "", " "); /****** END OF LINKING TO THIERRY ARNOUX'S SITE ************/ /* Print the GIF/Unicode Font choice, if directories are specified */ if (htmlDir[0]) { if (altHtmlFlag) { print2(" GIF version\n", htmlDir, texFileName); } else { print2(" Unicode version\n", altHtmlDir, texFileName); } } } else { /* texHeaderFlag=0 for HTML means not to put prev/next links */ /*print2(" which caused HTML validation failure */ print2(" \n", "%"); /* Print the GIF/Unicode Font choice, if directories are specified */ if (htmlDir[0]) { print2("\n"); if (altHtmlFlag) { print2("This is the Unicode version.
\n"); print2("Change to GIF version\n", htmlDir, texFileName); } else { print2("This is the GIF version.
\n"); print2("Change to Unicode version\n", altHtmlDir, texFileName); } } else { print2(" \n"); } } print2("
\n"); print2("
\n"); print2("
\n"); } /* htmlFlag */ fprintf(texFilePtr, "%s", printString); outputToString = 0; let(&printString, ""); /* Deallocate strings */ let(&tmpStr, ""); } /* printTexHeader */ /* Prints an embedded comment in TeX or HTML. The commentPtr must point to the first character after the "$(" in the comment. The printout ends when the first "$)" or null character is encountered. commentPtr must not be a temporary allocation. htmlCenterFlag, if 1, means to center the HTML and add a "Description:" prefix. */ /* The output is printed to the global texFilePtr. */ /* Note: the global long "showStatement" is referenced to determine whether to read bibliography from mmset.html or mmhilbert.html (or other htmlBibliography or extHtmlBibliography file pair). */ /* Returns 1 if an error or warning message was printed */ /* 17-Nov-2015 */ flag printTexComment(vstring commentPtr, flag htmlCenterFlag, /* 17-Nov-2015 nm */ long actionBits, /* see below */ /* 13-Dec-2018 */ /* Indicators for actionBits: #define ERRORS_ONLY 1 - just report errors, don't print output #define PROCESS_SYMBOLS 2 #define PROCESS_LABELS 4 #define ADD_COLORED_LABEL_NUMBER 8 #define PROCESS_BIBREFS 16 #define PROCESS_UNDERSCORES 32 #define CONVERT_TO_HTML 64 - convert '<' to '>' unless , present #define METAMATH_COMMENT 128 - $) terminates string #define PROCESS_EVERYTHING PROCESS_SYMBOLS + PROCESS_LABELS \ + ADD_COLORED_LABEL_NUMBER + PROCESS_BIBREFS \ + PROCESS_UNDERSCORES + CONVERT_HTML + METAMATH_COMMENT \ */ /* 10-Dec-2018 nm - expanded meaning of errorsOnly for MARKUP commmand: 2 = process as if in ... preformatted mode but don't strip ... tags 3 = same as 2, but convert ONLY math symbols (These new values were added instead of addina a new argument, so as not to have to modify ~60 other calls to this function) */ flag noFileCheck) /* 1 = ignore missing external files (gifs, bib, etc.) */ { vstring cmtptr; /* Not allocated */ vstring srcptr; /* Not allocated */ vstring lineStart; /* Not allocated */ vstring tmpStr = ""; vstring modeSection; /* Not allocated */ vstring sourceLine = ""; vstring outputLine = ""; vstring tmp = ""; flag textMode, mode, lastLineFlag, displayMode; vstring tmpComment = ""; /* Added 10/10/02 */ /* 11/15/02 A comment section with
...
is formatted into a monospaced text table */ /* 26-Dec-2011 nm - changed
 to more general  */
  /*flag preformattedMode = 0; /@ HTML 
 preformatted mode @/ */
  flag preformattedMode = 0; /* HTML  preformatted mode */

  /* 10/10/02 For bibliography hyperlinks */
  vstring bibTag = "";
  vstring bibFileName = "";
  vstring bibFileContents = "";
  vstring bibFileContentsUpper = ""; /* Uppercase version */
  vstring bibTags = "";
  long pos1, pos2, htmlpos1, htmlpos2, saveScreenWidth;
  flag tmpMathMode; /* 15-Feb-2014 nm */

  /* Variables for converting ` ` and ~ to old $m,$n and $l,$n formats in
     order to re-use the old code */
  /* Note that DOLLAR_SUBST will replace the old $. */
  vstring cmt = "";
  vstring cmtMasked = ""; /* cmt with math syms blanked */ /* 20-Aug-2014 nm */
          /* 20-Oct-2018 - also mask ~ label */
  vstring tmpMasked = ""; /* tmp with math syms blanked */ /* 20-Aug-2014 nm */
  vstring tmpStrMasked = ""; /* tmpStr w/ math syms blanked */ /* 20-Aug-2014 */
  long i, clen;
  flag returnVal = 0; /* 1 means error/warning */ /* 17-Nov-2015 nm */

  /* 13-Dec-2018 nm */
  /* Internal flags derived from actionBits argument, for MARKUP command use */
  flag errorsOnly;
  flag processSymbols;
  flag processLabels;
  flag addColoredLabelNumber;
  flag processBibrefs;
  flag processUnderscores;
  flag convertToHtml;
  flag metamathComment;

  /* Assign local Booleans for actionBits mask */
  errorsOnly = (actionBits & ERRORS_ONLY ) != 0;
  processSymbols = (actionBits & PROCESS_SYMBOLS ) != 0;
  processLabels = (actionBits & PROCESS_LABELS ) != 0;
  addColoredLabelNumber = (actionBits & ADD_COLORED_LABEL_NUMBER ) != 0;
  processBibrefs = (actionBits & PROCESS_BIBREFS ) != 0;
  processUnderscores = (actionBits & PROCESS_UNDERSCORES ) != 0;
  convertToHtml = (actionBits & CONVERT_TO_HTML ) != 0;
  metamathComment = (actionBits & METAMATH_COMMENT ) != 0;

  /* We must let this procedure handle switching output to string mode */
  if (outputToString) bug(2309);
  /* The LaTeX (or HTML) file must be open */
  if (errorsOnly == 0) {   /* 17-Nov-2015 nm */
    if (!texFilePtr) bug(2321);
  }

  cmtptr = commentPtr;

  if (!texDefsRead) {
    return returnVal; /* TeX defs were not read (error was detected
                               and flagged to the user elsewhere) */
  }

  /* Convert line to the old $m..$n and $l..$n formats (using DOLLAR_SUBST
     instead of "$") - the old syntax is obsolete but we do this conversion
     to re-use some old code */
  if (metamathComment != 0) {
    i = instr(1, cmtptr, "$)");      /* If it points to source buffer */
    if (!i) i = (long)strlen(cmtptr) + 1;  /* If it's a stand-alone string */
  } else {
    i = (long)strlen(cmtptr) + 1;
  }
  let(&cmt, left(cmtptr, i - 1));

  /* All actions on cmt should be mirrored on cmdMasked, except that
     math symbols are replaced with blanks in cmdMasked */
  let(&cmtMasked, cmt); /* 20-Aug-2014 nm */


  /* This section is independent and can be removed without side effects */
  if (htmlFlag) {
    /* Convert special characters <, &, etc. to HTML entities */
    /* But skip converting math symbols inside ` ` */
    /* 26-Dec-2011 nm Detect preformatted HTML (this is crude, since it
       will apply to whole comment - perhaps fine-tune this later) */
    if (convertToHtml != 0) { /* 13-Dec-2018 nm */
      if (instr(1, cmt, "") != 0) preformattedMode = 1;
    } else {
      preformattedMode = 1; /* For MARKUP command - don't convert HTML */
    }
    mode = 1; /* 1 normal, -1 math token */
    let(&tmp, "");
    let(&tmpMasked, "");
    while (1) {
      pos1 = 0;
      while (1) {
        pos1 = instr(pos1 + 1, cmt, "`");
        if (!pos1) break;
        if (cmt[pos1] == '`') {
          pos1++;  /* Skip `` escape */
          continue;
        }
        break;
      }
      if (!pos1) pos1 = (long)strlen(cmt) + 1;
      if (mode == 1 && preformattedMode == 0) {
        let(&tmpStr, "");
        /* asciiToTt() is where "<" is converted to "<" etc. */
        tmpStr = asciiToTt(left(cmt, pos1));
        let(&tmpStrMasked, tmpStr);
      } else {
        let(&tmpStr, left(cmt, pos1));
        /* 20-Aug-2014 nm */
        if (mode == -1) { /* Math mode */
          /* Replace math symbols with spaces to prevent confusing them
             with markup in sections below */
          let(&tmpStrMasked, cat(space(pos1 - 1),
              mid(cmtMasked, pos1, 1), NULL));
        } else { /* Preformatted mode but not math mode */
          let(&tmpStrMasked, left(cmtMasked, pos1));
        }
      }
      let(&tmp, cat(tmp, tmpStr, NULL));
      let(&tmpMasked, cat(tmpMasked, tmpStrMasked, NULL));
      let(&cmt, right(cmt, pos1 + 1));
      let(&cmtMasked, right(cmtMasked, pos1 + 1));
      if (!cmt[0]) break;
      mode = (char)(-mode);
    }
    let(&cmt, tmp);
    let(&cmtMasked, tmpMasked);
    let(&tmpStr, ""); /* Deallocate */
    let(&tmpStrMasked, "");
  }


  /* 10/10/02 Add leading and trailing HTML markup to comment here
     (instead of in caller).  Also convert special characters. */
  if (htmlFlag) {
    /* This used to be done in mmcmds.c */
    if (htmlCenterFlag) {  /* Note:  this should be 0 in MARKUP command */
      let(&cmt, cat("
Description: ", cmt, "
", NULL)); let(&cmtMasked, cat("
Description: ", cmtMasked, "
", NULL)); } } /* Added Oct-20-2018 nm */ /* Mask out _ (underscore) in labels so they won't become subscripts (reported by Benoit Jubin) */ /* This section is independent and can be removed without side effects */ if (htmlFlag != 0 /* && processSymbols != 0*/ /* Mode 3 processes symbols only */ /* (Actually we should do this all the time; this is the mask) */ ) { pos1 = 0; while (1) { /* Look for label start */ pos1 = instr(pos1 + 1, cmtMasked, "~"); if (!pos1) break; if (cmtMasked[pos1] == '~') { pos1++; /* Skip ~~ escape */ continue; } /* Skip whitespace after ~ */ while (1) { if (cmtMasked[pos1] == 0) break; /* End of line */ if (isspace((unsigned char)(cmtMasked[pos1]))) { pos1++; continue; } else { /* Found start of label */ break; } } /* Skip non-whitespace after ~ find end of label */ while (1) { if (cmtMasked[pos1] == 0) break; /* End of line */ if (!(isspace((unsigned char)(cmtMasked[pos1])))) { if (cmtMasked[pos1] == '_') { /* Put an "?" in place of label character in mask */ cmtMasked[pos1] = '?'; } pos1++; continue; } else { /* Found end of label */ break; } } /* while (1) */ } /* while (1) */ } /* if htmlFlag */ /* 5-Dec-03 Handle dollar signs in comments converted to LaTeX */ /* This section is independent and can be removed without side effects */ /* This must be done before the underscores below so subscript $'s */ /* won't be converted to \$'s */ if (!htmlFlag) { /* LaTeX */ /* MARKUP command doesn't handle LaTeX */ /* 25-Jan-2019 nm - this gets set by PROCESS_EVERYTHING in many calls; it's not specific to MARKUP and not a bug. */ /* if (metamathComment != 0) bug(2343); */ pos1 = 0; while (1) { pos1 = instr(pos1 + 1, cmt, "$"); if (!pos1) break; /* /@ Don't modify anything inside of
...
tags @/ if (pos1 > instr(1, cmt, "
") && pos1 < instr(1, cmt, "
")) continue; */ /* Don't modify anything inside of ... tags */ if (pos1 > instr(1, cmt, "") && pos1 < instr(1, cmt, "")) continue; let(&cmt, cat(left(cmt, pos1 - 1), "\\$", right(cmt, pos1 + 1), NULL)); let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), "\\$", right(cmtMasked, pos1 + 1), NULL)); pos1 = pos1 + 1; /* Adjust for 2-1 extra chars in "let" above */ } /* while (1) */ } /* 15-Feb-2014 nm */ /* 1-May-2017 nm - moved this section up to BEFORE the underscore handling below, so that "{\em...}" won't be converted to "\}\em...\}" */ /* Convert any remaining special characters for LaTeX */ /* This section is independent and can be removed without side effects */ if (!htmlFlag) { /* i.e. LaTeX mode */ /* At this point, the comment begins e.g "\begin{lemma}\label{lem:abc}" */ pos1 = instr(1, cmt, "} "); if (pos1) { pos1++; /* Start after the "}" */ } else { pos1 = 1; /* If not found, start from beginning of line */ } pos2 = (long)strlen(cmt); tmpMathMode = 0; for (pos1 = pos1 + 0; pos1 <= pos2; pos1++) { /* Don't modify anything inside of math symbol strings (imperfect - only works if `...` is not split across lines?) */ if (cmt[pos1 - 1] == '`') tmpMathMode = (flag)(1 - tmpMathMode); if (tmpMathMode) continue; if (pos1 > 1) { if (cmt[pos1 - 1] == '_' && cmt[pos1 - 2] == '$') { /* The _ is part of "$_{...}$" earlier conversion */ continue; } } /* $%#{}&^\\|<>"~_ are converted by asciiToTt() */ /* Omit \ and $ since they be part of an earlier converston */ /* Omit ~ since it is part of label ref */ /* Omit " since it legal */ /* Because converting to \char` causes later math mode problems due to `, we change |><_ to /)(- (an ugly workaround) */ switch(cmt[pos1 - 1]) { case '|': cmt[pos1 - 1] = '/'; break; case '<': cmt[pos1 - 1] = '{'; break; case '>': cmt[pos1 - 1] = '}'; break; case '_': cmt[pos1 - 1] = '-'; break; } if (strchr("%#{}&^|<>_", cmt[pos1 - 1]) != NULL) { let(&tmpStr, ""); tmpStr = asciiToTt(chr(cmt[pos1 - 1])); let(&cmt, cat(left(cmt, pos1 - 1), tmpStr, right(cmt, pos1 + 1), NULL)); let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), tmpStr, right(cmtMasked, pos1 + 1), NULL)); pos1 += (long)strlen(tmpStr) - 1; pos2 += (long)strlen(tmpStr) - 1; } } /* Next pos1 */ } /* if (!htmlFlag) */ /* 10-Oct-02 Handle underscores in comments converted to HTML: Convert _abc_ to abc for book titles, etc.; convert a_n to an for subscripts */ /* 5-Dec-03 Added LaTeX handling */ /* This section is independent and can be removed without side effects */ if (htmlFlag != 0 /* 5-Dec-03 */ && processUnderscores != 0) { /* 13-Dec-2018 nm */ pos1 = 0; while (1) { /* pos1 = instr(pos1 + 1, cmt, "_"); */ /* 20-Aug-2014 nm Only look at non-math part of comment */ pos1 = instr(pos1 + 1, cmtMasked, "_"); if (!pos1) break; /* /@ Don't modify anything inside of
...
tags @/ if (pos1 > instr(1, cmt, "
") && pos1 < instr(1, cmt, "
")) continue; */ /* Don't modify anything inside of ... tags */ if (pos1 > instr(1, cmt, "") && pos1 < instr(1, cmt, "")) continue; /* 23-Jul-2006 nm Don't modify anything inside of math symbol strings (imperfect - only works if `...` is not split across lines) */ /* 20-Aug-2014 nm No longer necessary since we now use cmtMasked */ /* if (pos1 > instr(1, cmt, "`") && pos1 < instr(instr(1, cmt, "`") + 1, cmt, "`")) continue; */ /* 5-Apr-2007 nm Don't modify external hyperlinks containing "_" */ pos2 = pos1 - 1; while (1) { /* Get to previous whitespace */ if (pos2 == 0 || isspace((unsigned char)(cmt[pos2]))) break; pos2--; } if (!strcmp(mid(cmt, pos2 + 2, 7), "http://")) { continue; } /* 20-Aug-2014 nm Add https */ if (!strcmp(mid(cmt, pos2 + 2, 8), "https://")) { continue; } /* 20-Oct-2018 nm Add mm */ if (!strcmp(mid(cmt, pos2 + 2, 2), "mm")) { continue; } /* Opening "_" must be _ for tag */ if (pos1 > 1) { /* Check for not whitespace and not opening punctuation */ if (!isspace((unsigned char)(cmt[pos1 - 2])) && strchr(OPENING_PUNCTUATION, cmt[pos1 - 2]) == NULL) { /* Check for not whitespace and not closing punctuation */ if (!isspace((unsigned char)(cmt[pos1])) && strchr(CLOSING_PUNCTUATION, cmt[pos1]) == NULL) { /* 28-Sep-03 - Added subscript handling */ /* Found _ - assume subscript */ /* Locate the whitepace (or end of string) that closes subscript */ /* Note: This algorithm is not perfect in that the subscript is assumed to end at closing punctuation, which theoretically could be part of the subscript itself, such as a subscript with a comma in it. */ pos2 = pos1 + 1; while (1) { if (!cmt[pos2]) break; /* End of string */ /* Look for whitespace or closing punctuation */ if (isspace((unsigned char)(cmt[pos2])) || strchr(OPENING_PUNCTUATION, cmt[pos2]) != NULL || strchr(CLOSING_PUNCTUATION, cmt[pos2]) != NULL) break; pos2++; /* Move forward through subscript */ } pos2++; /* Adjust for left, seg, etc. that start at 1 not 0 */ if (htmlFlag) { /* HTML */ /* Put ... around subscript */ let(&cmt, cat(left(cmt, pos1 - 1), "", seg(cmt, pos1 + 1, pos2 - 1), /* Skip (delete) "_" */ "", right(cmt, pos2), NULL)); let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), "", seg(cmtMasked, pos1 + 1, pos2 - 1), /* Skip (delete) "_" */ "", right(cmtMasked, pos2), NULL)); pos1 = pos2 + 33; /* Adjust for 34-1 extra chars in "let" above */ } else { /* LaTeX */ /* Put _{...} around subscript */ let(&cmt, cat(left(cmt, pos1 - 1), "$_{", seg(cmt, pos1 + 1, pos2 - 1), /* Skip (delete) "_" */ "}$", right(cmt, pos2), NULL)); let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), "$_{", seg(cmtMasked, pos1 + 1, pos2 - 1), /* Skip (delete) "_" */ "}$", right(cmtMasked, pos2), NULL)); pos1 = pos2 + 4; /* Adjust for 5-1 extra chars in "let" above */ } continue; /* 23-Sep-03 - End of subscript handling */ } else { /* Found _ - not an opening "_" */ /* Do nothing in this case */ continue; } } } if (!isalnum((unsigned char)(cmt[pos1]))) continue; /* pos2 = instr(pos1 + 1, cmt, "_"); */ /* 20-Aug-2014 nm Only look at non-math part of comment */ pos2 = instr(pos1 + 1, cmtMasked, "_"); if (!pos2) break; /* Closing "_" must be _ */ if (!isalnum((unsigned char)(cmt[pos2 - 2]))) continue; if (isalnum((unsigned char)(cmt[pos2]))) continue; if (htmlFlag) { /* HTML */ let(&cmt, cat(left(cmt, pos1 - 1), "", seg(cmt, pos1 + 1, pos2 - 1), "", right(cmt, pos2 + 1), NULL)); let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), "", seg(cmtMasked, pos1 + 1, pos2 - 1), "", right(cmtMasked, pos2 + 1), NULL)); pos1 = pos2 + 5; /* Adjust for 7-2 extra chars in "let" above */ } else { /* LaTeX */ let(&cmt, cat(left(cmt, pos1 - 1), "{\\em ", seg(cmt, pos1 + 1, pos2 - 1), "}", right(cmt, pos2 + 1), NULL)); let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), "{\\em ", seg(cmtMasked, pos1 + 1, pos2 - 1), "}", right(cmtMasked, pos2 + 1), NULL)); pos1 = pos2 + 4; /* Adjust for 6-2 extra chars in "let" above */ } } } /* 1-May-2017 nm */ /* Convert opening double quote to `` for LaTeX */ /* This section is independent and can be removed without side effects */ if (!htmlFlag) { /* If LaTeX mode */ i = 1; /* Even/odd counter: 1 = left quote, 0 = right quote */ pos1 = 0; while (1) { /* cmtMasked has math symbols blanked */ pos1 = instr(pos1 + 1, cmtMasked, "\""); if (pos1 == 0) break; if (i == 1) { /* Warning: "`" needs to be escaped (i.e. repeated) to prevent it from being treated as a math symbol delimiter below. So "````" will become "``" in the LaTeX output. */ let(&cmt, cat(left(cmt, pos1 - 1), "````", right(cmt, pos1 + 1), NULL)); let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), "````", right(cmtMasked, pos1 + 1), NULL)); } i = 1 - i; /* Count to next even or odd */ } } /* 10/10/02 Put bibliography hyperlinks in comments converted to HTML: [Monk2] becomes tag, HTML is case-insensitive for A and NAME but case-sensitive for the token after the = */ /* Strip all whitespace */ let(&bibFileContents, edit(bibFileContents, 2)); /* Uppercase version for HTML tag search */ let(&bibFileContentsUpper, edit(bibFileContents, 32)); htmlpos1 = 0; while (1) { /* Look for all HTML tags */ htmlpos1 = instr(htmlpos1 + 1, bibFileContentsUpper, ""); if (!htmlpos2) break; htmlpos2--; /* Move to character before ">" */ if (bibFileContents[htmlpos2 - 1] == '\'' || bibFileContents[htmlpos2 - 1] == '"') htmlpos2--; if (htmlpos2 <= htmlpos1) continue; /* Ignore bad HTML syntax */ let(&tmp, cat("[", seg(bibFileContents, htmlpos1, htmlpos2), "]", NULL)); /* Check if tag is already in list */ if (instr(1, bibTags, tmp)) { printLongLine(cat("?Error: There two occurrences of", " bibliographic reference \"", seg(bibFileContents, htmlpos1, htmlpos2), "\" in the file \"", bibFileName, "\".", NULL), "", " "); returnVal = 1; /* Error/warning printed */ /* 17-Nov-2015 nm */ } /* Add tag to tag list */ let(&bibTags, cat(bibTags, tmp, NULL)); } /* end while */ if (!bibTags[0]) { /* No tags found; put dummy partial tag meaning "file read" */ let(&bibTags, "["); } } /* end if (!bibFIleContents) */ } /* end if (noFileCheck == 0) */ /* Assign to permanent tag list for next time */ if (showStatement < extHtmlStmt) { let(&htmlBibliographyTags, bibTags); /*} else {*/ } else if (showStatement < sandboxStmt) { /* 29-Jul-2008 nm Sandbox stuff */ let(&extHtmlBibliographyTags, bibTags); /* 29-Jul-2008 nm Sandbox stuff */ } else { let(&htmlBibliographyTags, bibTags); } /* Done reading in HTML file with bibliography */ } /* end if (!bibTags[0]) */ /* See if the tag we found is in the bibliography file */ if (bibTags[0] == '[') { /* We have a tag list from the bibliography file */ if (!instr(1, bibTags, bibTag)) { printLongLine(cat("?Error: The bibliographic reference \"", bibTag, "\" in statement \"", statement[showStatement].labelName, "\" was not found as an anchor in the file \"", bibFileName, "\".", NULL), "", " "); returnVal = 1; /* Error/warning printed */ /* 17-Nov-2015 nm */ } } /* End of error-checking */ /* Make an HTML reference for the tag */ let(&tmp, cat("[", seg(bibTag, 2, pos2 - pos1), "]", NULL)); let(&cmt, cat(left(cmt, pos1 - 1), tmp, right(cmt, pos2 + 1), NULL)); let(&cmtMasked, cat(left(cmtMasked, pos1 - 1), tmp, right(cmtMasked, pos2 + 1), NULL)); pos1 = pos1 + (long)strlen(tmp) - (long)strlen(bibTag); /* Adjust comment position */ } /* end while(1) */ } /* end if (bibFileName[0]) */ } /* end of if (htmlFlag) */ /* 10/10/02 End of bibliography hyperlinks */ /* All actions on cmt should be mirrored on cmdMasked, except that math symbols are replaced with blanks in cmdMasked */ if (strlen(cmt) != strlen(cmtMasked)) bug(2334); /* Should be in sync */ /* Starting here, we no longer use cmtMasked, so syncing it with cmt isn't important anymore. */ clen = (long)strlen(cmt); mode = 'n'; for (i = 0; i < clen; i++) { if (cmt[i] == '`') { if (cmt[i + 1] == '`') { if (processSymbols != 0) { /* 13-Dec-2018 nm */ /* Escaped ` = actual ` */ let(&cmt, cat(left(cmt, i + 1), right(cmt, i + 3), NULL)); clen--; } } else { /* 13-Dec-2018 nm We will still enter and exit math mode when processSymbols=0 so as to skip ~ in math symbols. However, we don't insert the "DOLLAR_SUBST mode" so that later on it will look like normal text */ /* Enter or exit math mode */ if (mode != 'm') { mode = 'm'; } else { mode = 'n'; } if (processSymbols != 0) { /* 13-Dec-2018 nm */ let(&cmt, cat(left(cmt, i), chr(DOLLAR_SUBST) /*$*/, chr(mode), right(cmt, i+2), NULL)); clen++; i++; } /* 10/10/02 */ /* If symbol is preceded by opening punctuation and a space, take out the space so it looks better. */ if (mode == 'm' && processSymbols != 0 /* 13-Dec-2018 nm */ ) { let(&tmp, mid(cmt, i - 2, 2)); if (!strcmp("( ", tmp)) { let(&cmt, cat(left(cmt, i - 2), right(cmt, i), NULL)); clen = clen - 1; } /* We include quotes since symbols are often enclosed in them. */ let(&tmp, mid(cmt, i - 8, 8)); if (!strcmp("" ", right(tmp, 2)) && strchr("( ", tmp[0]) != NULL) { let(&cmt, cat(left(cmt, i - 2), right(cmt, i), NULL)); clen = clen - 1; } let(&tmp, ""); } /* If symbol is followed by a space and closing punctuation, take out the space so it looks better. */ if (mode == 'n' && processSymbols != 0 /* 13-Dec-2018 nm */ ) { /* (Why must it be i + 2 here but i + 1 in label version below? Didn't investigate but seems strange.) */ let(&tmp, mid(cmt, i + 2, 2)); if (tmp[0] == ' ' && strchr(CLOSING_PUNCTUATION, tmp[1]) != NULL) { let(&cmt, cat(left(cmt, i + 1), right(cmt, i + 3), NULL)); clen = clen - 1; } /* We include quotes since symbols are often enclosed in them. */ let(&tmp, mid(cmt, i + 2, 8)); if (strlen(tmp) < 8) let(&tmp, cat(tmp, space(8 - (long)strlen(tmp)), NULL)); if (!strcmp(" "", left(tmp, 7)) && strchr(CLOSING_PUNCTUATION, tmp[7]) != NULL) { let(&cmt, cat(left(cmt, i + 1), right(cmt, i + 3), NULL)); clen = clen - 1; } let(&tmp, ""); } } } if (cmt[i] == '~' && mode != 'm') { if (cmt[i + 1] == '~' /* Escaped ~ */ || processLabels == 0 /* 13-Dec-2018 nm */ ) { if (processLabels != 0) { /* 13-Dec-2018 nm */ /* Escaped ~ = actual ~ */ let(&cmt, cat(left(cmt, i + 1), right(cmt, i + 3), NULL)); clen--; } } else { /* Enter or exit label mode */ if (mode != 'l') { mode = 'l'; /* 9/5/99 - If there is whitespace after the ~, then remove all whitespace immediately after the ~ to join the ~ to the label. This enhances the Metamath syntax so that whitespace is now allowed between the ~ and the label, which makes it easier to do global substitutions of labels in a text editor. */ while (isspace((unsigned char)(cmt[i + 1])) && clen > i + 1) { let(&cmt, cat(left(cmt, i + 1), right(cmt, i + 3), NULL)); clen--; } } else { /* This really should never happen */ /* 1-Oct-04 If you see this bug, the most likely cause is a tilde character in a comment that does not prefix a label or hyperlink. The most common problem is the "~" inside a hyperlink that specifies a user's directory. To fix it, use a double tilde "~~" to escape it, which will become a single tilde on output. (At some future point this bug should be converted to a meaningful error message that doesn't abort the program.) */ /* bug(2310); */ /* 2-Oct-2015 nm Changed to error message */ outputToString = 0; printLongLine(cat("?Warning: There is a \"~\" inside of a label", " in the comment of statement \"", statement[showStatement].labelName, "\". Use \"~~\" to escape \"~\" in an http reference.", NULL), "", " "); returnVal = 1; /* Error/warning printed */ /* 17-Nov-2015 nm */ outputToString = 1; mode = 'n'; } let(&cmt, cat(left(cmt, i), chr(DOLLAR_SUBST) /*$*/, chr(mode), right(cmt, i+2), NULL)); clen++; i++; /* 10/10/02 */ /* If label is preceded by opening punctuation and space, take out the space so it looks better. */ let(&tmp, mid(cmt, i - 2, 2)); /*printf("tmp#%s#\n",tmp);*/ if (!strcmp("( ", tmp) || !strcmp("[ ", tmp)) { let(&cmt, cat(left(cmt, i - 2), right(cmt, i), NULL)); clen = clen - 1; } let(&tmp, ""); } } if (processLabels == 0 && mode == 'l') { /* We should have prevented it from ever getting into label mode */ bug(2344); /* 13-Dec-2018 nm */ } if ((isspace((unsigned char)(cmt[i])) || cmt[i] == '<') /* 17-Nov-2012 nm If the label ends the comment, "" with no space will be appended before this section. */ && mode == 'l') { /* Whitespace exits label mode */ mode = 'n'; let(&cmt, cat(left(cmt, i), chr(DOLLAR_SUBST) /*$*/, chr(mode), right(cmt, i+1), NULL)); clen = clen + 2; i = i + 2; /* 10/10/02 */ /* If label is followed by space and end punctuation, take out the space so it looks better. */ let(&tmp, mid(cmt, i + 1, 2)); if (tmp[0] == ' ' && strchr(CLOSING_PUNCTUATION, tmp[1]) != NULL) { let(&cmt, cat(left(cmt, i), right(cmt, i + 2), NULL)); clen = clen - 1; } let(&tmp, ""); } /* clen should always remain comment length - do a sanity check here */ if ((signed)(strlen(cmt)) != clen) { bug(2311); } } /* Next i */ /* End convert line to the old $m..$n and $l..$n */ /* 29-May-2017 nm */ /* Put and at beginning of line so preformattedMode won't be switched on or off in the middle of processing a line */ /* This also fixes the problem where multiple ... on one line aren't all removed in HTML output, causing w3c validation errors */ /* Note: "Q2." will have a space around "2" because of this fix. Instead use "Q2." or just "Q^2." */ pos1 = -1; /* So -1 + 2 = 1 = start of string for instr() */ while (1) { pos1 = instr(pos1 + 2/*skip new \n*/, cmt, ""); if (pos1 == 0 || convertToHtml == 0 /* Don't touch in MARKUP command */ /* 13-Dec-2018 nm */ ) break; /* If begins a line (after stripping spaces), don't put a \n so that we don't trigger new paragraph mode */ let(&tmpStr, edit(left(cmt, pos1 - 1), 2/*discard spaces & tabs*/)); i = (long)strlen(tmpStr); if (i == 0) continue; if (tmpStr[i - 1] == '\n') continue; let(&cmt, cat(left(cmt, pos1 - 1), "\n", right(cmt, pos1), NULL)); } pos1 = -1; /* So -1 + 2 = 1 = start of string for instr() */ while (1) { pos1 = instr(pos1 + 2/*skip new \n*/, cmt, ""); if (pos1 == 0 || convertToHtml == 0 /* Don't touch in MARKUP command */ /* 13-Dec-2018 nm */ ) break; /* If begins a line (after stripping spaces), don't put a \n so that we don't trigger new paragraph mode */ let(&tmpStr, edit(left(cmt, pos1 - 1), 2/*discard spaces & tabs*/)); i = (long)strlen(tmpStr); if (i == 0) continue; if (tmpStr[i - 1] == '\n') continue; let(&cmt, cat(left(cmt, pos1 - 1), "\n", right(cmt, pos1), NULL)); } cmtptr = cmt; /* cmtptr is for scanning cmt */ outputToString = 1; /* Redirect print2 and printLongLine to printString */ /*let(&printString, "");*/ /* May have stuff to be printed 7/4/98 */ while (1) { /* Get a "line" of text, up to the next new-line. New-lines embedded in $m and $l sections are ignored, so that these sections will not be dangling. */ lineStart = cmtptr; textMode = 1; lastLineFlag = 0; while (1) { if (cmtptr[0] == 0) { lastLineFlag = 1; break; } if (cmtptr[0] == '\n' && textMode) break; /* if (cmtptr[0] == '$') { */ if (cmtptr[0] == DOLLAR_SUBST) { /* 14-Feb-2014 nm */ if (cmtptr[1] == ')') { bug(2312); /* Obsolete (should never happen) */ lastLineFlag = 1; break; } } if (cmtptr[0] == DOLLAR_SUBST /*'$'*/) { cmtptr++; if (cmtptr[0] == 'm') textMode = 0; /* Math mode */ if (cmtptr[0] == 'l') textMode = 0; /* Label mode */ if (cmtptr[0] == 'n') textMode = 1; /* Normal mode */ } cmtptr++; } let(&sourceLine, space(cmtptr - lineStart)); memcpy(sourceLine, lineStart, (size_t)(cmtptr - lineStart)); cmtptr++; /* Get past new-line to prepare for next line's scan */ /* If the line contains only math mode text, use TeX display mode. */ displayMode = 0; let(&tmpStr, edit(sourceLine, 8 + 128)); /* Trim spaces */ if (!strcmp(right(tmpStr, (long)strlen(tmpStr) - 1), cat(chr(DOLLAR_SUBST), "n", NULL))) let(&tmpStr, left(tmpStr, (long)strlen(tmpStr) - 2)); /* Strip $n */ srcptr = tmpStr; modeSection = getCommentModeSection(&srcptr, &mode); let(&modeSection, ""); /* Deallocate */ if (mode == 'm') { modeSection = getCommentModeSection(&srcptr, &mode); let(&modeSection, ""); /* Deallocate */ /* 9/9/99 displayMode is obsolete. Because it depends on a manual user edit, by default it will create a LaTeX error. Turn it off. */ /*if (mode == 0) displayMode = 1;*/ /* No text after math mode text */ } let(&tmpStr, ""); /* Deallocate */ /* Convert all sections of the line to text, math, or labels */ let(&outputLine, ""); srcptr = sourceLine; while (1) { modeSection = getCommentModeSection(&srcptr, &mode); if (!mode) break; /* Done */ let(&modeSection, right(modeSection, 3)); /* Remove mode-change command */ switch (mode) { case 'n': /* Normal text */ let(&outputLine, cat(outputLine, modeSection, NULL)); break; case 'l': /* Label mode */ if (processLabels == 0) { /* 13-Dec-2018 nm */ /* Labels should be treated as normal text */ bug(2345); } let(&modeSection, edit(modeSection, 8 + 128 + 16)); /* Discard leading and trailing blanks; reduce spaces to one space */ let(&tmpStr, ""); tmpStr = asciiToTt(modeSection); if (!tmpStr[0]) { /* Can't be blank */ /* bug(2313); */ /* 2-Oct-2015 nm Commented out */ /* 2-Oct-2015 nm */ /* This can happen if ~ is followed by ` (start of math string) */ outputToString = 0; printLongLine(cat("?Error: There is a \"~\" with no label", " in the comment of statement \"", statement[showStatement].labelName, "\". Check that \"`\" inside of a math symbol is", " escaped with \"``\".", NULL), "", " "); returnVal = 1; /* Error/warning printed */ /* 17-Nov-2015 nm */ outputToString = 1; } /* 10/10/02 - obsolete */ /* 9/5/99 - Make sure the label in a comment corresponds to a real statement so we won't have broken HTML links (or misleading LaTeX information) - since label references in comments are rare, we just do a linear scan instead of binary search */ /******* 10/10/02 for (i = 1; i <= statements; i++) { if (!strcmp(statement[i].labelName, tmpStr)) break; } if (i > statements) { outputToString = 0; printLongLine(cat("?Error: Statement \"", tmpStr, "\" (referenced in comment) does not exist.", NULL), "", " "); outputToString = 1; returnVal = 1; } *******/ if (!strcmp("http://", left(tmpStr, 7)) || !strcmp("https://", left(tmpStr, 8)) /* 20-Aug-2014 nm */ || !strcmp("mm", left(tmpStr, 2)) /* 20-Oct-2018 nm */ ) { /* 4/13/04 nm - If the "label" begins with 'http://', then assume it is an external hyperlink and not a real label. This is kind of a syntax kludge but it is easy to do. 20-Oct-2018 nm - Added starting with 'mm', which is illegal for set.mm labels - e.g. mmtheorems.html#abc */ if (htmlFlag) { let(&outputLine, cat(outputLine, "", tmpStr, "", tmp, NULL)); } else { /* 1-May-2017 nm */ /* Generate LaTeX version of the URL */ i = instr(1, tmpStr, "\\char`\\~"); /* The url{} function automatically converts ~ to LaTeX */ if (i != 0) { let(&tmpStr, cat(left(tmpStr, i - 1), right(tmpStr, i + 7), NULL)); } let(&outputLine, cat(outputLine, "\\url{", tmpStr, "}", tmp, NULL)); } } else { /* 10/10/02 Do binary search through just $a's and $p's (there are no html pages for local labels) */ i = lookupLabel(tmpStr); if (i < 0) { outputToString = 0; printLongLine(cat("?Warning: The label token \"", tmpStr, "\" (referenced in comment of statement \"", statement[showStatement].labelName, "\") is not a $a or $p statement label.", NULL), "", " "); outputToString = 1; returnVal = 1; /* Error/warning printed */ /* 17-Nov-2015 nm */ } if (!htmlFlag) { let(&outputLine, cat(outputLine, "{\\tt ", tmpStr, "}", NULL)); } else { let(&tmp, ""); if (addColoredLabelNumber != 0) { /* 13-Dec-2018 nm */ /* When the error above occurs, i < 0 will cause pinkHTML() to issue "(future)" for pleasant readability */ tmp = pinkHTML(i); } if (i < 0) { /* Error output - prevent broken link */ let(&outputLine, cat(outputLine, "", tmpStr, "", tmp, NULL)); } else { /* Normal output - put hyperlink to the statement */ let(&outputLine, cat(outputLine, "", tmpStr, "", tmp, NULL)); } } } /* if (!strcmp("http://", left(tmpStr, 7))) ... else */ let(&tmpStr, ""); /* Deallocate */ break; case 'm': /* Math mode */ if (processSymbols == 0) { /* 13-Dec-2018 nm */ /* Math symbols should be treated as normal text */ bug(2345); } let(&tmpStr, ""); tmpStr = asciiMathToTex(modeSection, showStatement); if (!htmlFlag) { if (displayMode) { /* It the user's responsibility to establish equation environment in displayMode. */ let(&outputLine, cat(outputLine, /*"\\[",*/ edit(tmpStr, 128), /*"\\]",*/ NULL)); /* edit = remove trailing spaces */ } else { let(&outputLine, cat(outputLine, "$", edit(tmpStr, 128), "$", NULL)); /* edit = remove trailing spaces */ } } else { /* 10/25/02 Trim leading, trailing spaces in case punctuation surrounds the math symbols in the comment */ let(&tmpStr, edit(tmpStr, 8 + 128)); /* 14-Jan-2016 nm */ /* Enclose math symbols in a span to be used for font selection */ let(&tmpStr, cat( (altHtmlFlag ? cat("", NULL) : ""), /* 14-Jan-2016 nm */ tmpStr, (altHtmlFlag ? "" : ""), /* 14-Jan-2016 nm */ NULL)); let(&outputLine, cat(outputLine, tmpStr, NULL)); /* html */ } let(&tmpStr, ""); /* Deallocate */ break; } /* End switch(mode) */ let(&modeSection, ""); /* Deallocate */ } let(&outputLine, edit(outputLine, 128)); /* remove trailing spaces */ if (htmlFlag) { /* Change blank lines into paragraph breaks except in mode */ if (!outputLine[0]) { /* Blank line */ if (preformattedMode == 0 && convertToHtml == 1 /* Not MARKUP command */ /* 13-Dec-2018 nm */ ) { /* Make it a paragraph break */ let(&outputLine, /* "

"); */ /* 9-May-2015 nm Prevent space after last paragraph */ "

"); } } /* 11/15/02 If a statement comment has a section embedded in

...
, we make it a table with monospaced text and a background color */ /* pos1 = instr(1, outputLine, "
"); */
      /* 26-Dec-2011 nm - changed 
 to more general  */
      pos1 = instr(1, outputLine, "");
      if (pos1 != 0
          && convertToHtml == 1 /* 13-Dec-2018 nm */
          ) {
        /* 26-Dec-2011 nm - The line below is probably redundant since we
           set preformattedMode ealier.  Maybe add a bug check to make sure
           it is 1 here. */
        preformattedMode = 1; /* So we don't put 

for blank lines */ /* 26-Dec-2011 nm - Took out fancy table for simplicity let(&outputLine, cat(left(outputLine, pos1 - 1), "

", right(outputLine, pos1), NULL)); */ /* 26-Dec-2011 nm - Strip out the "" string */ let(&outputLine, cat(left(outputLine, pos1 - 1), right(outputLine, pos1 + 6), NULL)); } /* pos1 = instr(1, outputLine, ""); */ pos1 = instr(1, outputLine, ""); if (pos1 != 0 && convertToHtml == 1 /* 13-Dec-2018 nm */ ) { preformattedMode = 0; /* 26-Dec-2011 nm - Took out fancy table for simplicity let(&outputLine, cat(left(outputLine, pos1 + 5), "
", right(outputLine, pos1 + 6), NULL)); */ /* 26-Dec-2011 nm - Strip out the "" string */ let(&outputLine, cat(left(outputLine, pos1 - 1), right(outputLine, pos1 + 7), NULL)); } } if (!htmlFlag) { /* LaTeX */ /* Convert
...
HTML tags to LaTeX */ /* 26-Dec-2011 nm - leave this in for now */ while (1) { pos1 = instr(1, outputLine, "
");
        if (pos1) {
          let(&outputLine, cat(left(outputLine, pos1 - 1), "\\begin{verbatim} ",
              right(outputLine, pos1 + 5), NULL));
        } else {
          break;
        }
      }
      while (1) {
        pos1 = instr(1, outputLine, "
"); if (pos1) { let(&outputLine, cat(left(outputLine, pos1 - 1), "\\end{verbatim} ", right(outputLine, pos1 + 6), NULL)); } else { break; } } /* 26-Dec-2011 nm - strip out , */ /* The HTML part may screw up LaTeX; maybe we should just take out any HTML code completely in the future? */ while (1) { pos1 = instr(1, outputLine, ""); if (pos1) { let(&outputLine, cat(left(outputLine, pos1 - 1), right(outputLine, pos1 + 6), NULL)); } else { break; } } while (1) { pos1 = instr(1, outputLine, ""); if (pos1) { let(&outputLine, cat(left(outputLine, pos1 - 1), right(outputLine, pos1 + 7), NULL)); } else { break; } } } saveScreenWidth = screenWidth; /* 26-Dec-2011 nm - in
 mode, we don't want to wrap the HTML
       output with spurious newlines */
    if (preformattedMode) screenWidth = PRINTBUFFERSIZE - 2;
    if (errorsOnly == 0) {
      printLongLine(outputLine, "", htmlFlag ? "\"" : "\\");
    }
    screenWidth = saveScreenWidth;

    let(&tmp, ""); /* Clear temporary allocation stack */

    if (lastLineFlag) break; /* Done */
  } /* end while(1) */

  if (htmlFlag) {
    if (convertToHtml != 0) { /* Not MARKUP command */ /* 13-Dec-2018 nm */
      print2("\n"); /* Don't change what the previous code did */
    } else {
      /* 13-Dec-2018 nm */
      /* Add newline if string is not empty and has no newline at end */
      if (printString[0] != 0) {
        i = (long)strlen(printString);
        if (printString[i - 1] != '\n')  {
          print2("\n");
        } else {
          /* 13-Dec-2018 nm */
          /* There is an extra \n added by something previous.  Until
             we figure out what, take it off so that MARKUP output will
             equal input when no processing qualifiers are used. */
          if (i > 1) {
            if (printString[i - 2] == '\n') {
              let(&printString, left(printString, i - 1));
            }
          }
        }
      }
    }
  } else { /* LaTeX mode */
    if (!oldTexFlag) {
      /* 14-Sep-2010 nm Suppress blank line for LaTeX */
      /* print2("\n"); */
    } else {
      print2("\n");
    }
  }

  outputToString = 0; /* Restore normal output */
  if (errorsOnly == 0) { /* 17-Nov-2015 nm */
    fprintf(texFilePtr, "%s", printString);
  }

  let(&printString, ""); /* Deallocate strings */
  let(&sourceLine, "");
  let(&outputLine, "");
  let(&cmt, "");
  let(&cmtMasked, "");
  let(&tmpComment, "");
  let(&tmp, "");
  let(&tmpMasked, "");
  let(&tmpStr, "");
  let(&tmpStrMasked, "");
  let(&bibTag, "");
  let(&bibFileName, "");
  let(&bibFileContents, "");
  let(&bibFileContentsUpper, "");
  let(&bibTags, "");

  return returnVal; /* 1 if error/warning found */

} /* printTexComment */



void printTexLongMath(nmbrString *mathString,
    vstring startPrefix, /* Start prefix in "screen display" mode e.g.
         "abc $p"; it is converted to the appropriate format.  Non-zero
         length means proof step in HTML mode, as opposed to assertion etc. */
    vstring contPrefix, /* Prefix for continuation lines.  Not used in
         HTML mode.  Warning:  contPrefix must not be temporarily allocated
         (as a cat, left, etc. argument) by caller */
    long hypStmt, /* hypStmt, if non-zero, is the statement number to be
                     referenced next to the hypothesis link in html */
    long indentationLevel) /* nm 3-Feb-04 Indentation amount of proof step -
                              note that this is 0 for last step of proof */
{
/* 23-Apr-04 nm Changed "top" level from 0 to 1 - hopefully slightly less
   confusing since before user had to scroll to bottom to know that it
   started at 0 and not 1 */
#define INDENTATION_OFFSET 1
  long i;
  long pos;
  vstring tex = "";
  vstring texLine = "";
  vstring sPrefix = ""; /* 7/3/98 */
  vstring htmStep = ""; /* 7/4/98 */
  vstring htmStepTag = ""; /* 30-May-2015 nm */
  vstring htmHyp = ""; /* 7/4/98 */
  vstring htmRef = ""; /* 7/4/98 */
  vstring htmLocLab = ""; /* 7/4/98 */
  vstring tmp = "";  /* 10/10/02 */
  vstring descr = ""; /* 19-Nov-2007 nm */
  char refType = '?'; /* 14-Sep-2010 nm  'e' means $e, etc. */

  let(&sPrefix, startPrefix); /* 7/3/98 Save it; it may be temp alloc */

  if (!texDefsRead) return; /* TeX defs were not read (error was printed) */
  outputToString = 1; /* Redirect print2 and printLongLine to printString */
  /* May have stuff to be printed 7/4/98 */
  /*if (!htmlFlag) let(&printString, "");*/ /* Removed 6-Dec-03 */

  /* Note that the "tex" assignment below will be used only when !htmlFlag
     and oldTexFlag, or when htmlFlag and len(sPrefix)>0 */
  let(&tex, "");
  tex = asciiToTt(sPrefix); /* asciiToTt allocates; we must deallocate */
      /* Example: sPrefix = " 4 2,3 ax-mp  $a " */
      /*          tex = "\ 4\ 2,3\ ax-mp\ \ \$a\ " in !htmlFlag mode */
      /*          tex = " 4 2,3 ax-qmp  $a " in htmlFlag mode */
  let(&texLine, "");

  /* 14-Sep-2010 nm Get statement type of proof step reference */
  i = instr(1, sPrefix, "$");
  if (i) refType = sPrefix[i]; /* Character after the "$" */

  /* 14-Sep-2010 nm Moved this code from below to use for !oldTexFlag */
  if (htmlFlag || !oldTexFlag) {

    /* Process a proof step prefix */
    if (strlen(sPrefix)) { /* It's a proof step */
      /* Make each token a separate table column for HTML */
      /* This is a kludge that only works with /LEMMON style proofs! */
      /* 14-Sep-2010 nm Note that asciiToTt() above puts "\ " when not in
         htmlFlag mode, so use sPrefix instead of tex so it will work in
         !oldTexFlag mode */

      /* 1-May-2017 nm Fix for non-/LEMMON format used by TeX mode */
      /* In HTML mode, sPrefix has two possible formats:
           "2 ax-1  $a "
           "3 1,2 ax-mp  $a "
         In LaTeX mode (!htmlFlag), sPrefix has one format:
           "8   maj=ax-1  $a "
           "9 a1i=ax-mp $a " */
      /* Later on 1-May-2017: the LaTeX mode now returns same as HTML mode. */

      /* let(&tex, edit(tex, 8 + 16 + 128)); */
      let(&tex, edit(sPrefix, 8/*no leading spaces*/
           + 16/*reduce spaces and tabs*/
           + 128/*no trailing spaces*/));

      i = 0;
      pos = 1;
      while (pos) {
        pos = instr(1, tex, " ");
        if (pos) {
          if (i > 3) { /* 2/8/02 - added for extra safety for the future */
            bug(2316);
          }
          /* Deleted 26-Jun-2017 nm - this check is too conservative; we
             could have starting tex="2 1 a4s @2: $p" which will result
             in pos=4, i=3.  "show proof drsb1/tex" triggered this bug. */
          /*
          if (!htmlFlag && i > 2) { /@ 1-May-2017 nm @/
            bug(2341);
          }
          */
          if (i == 0) let(&htmStep, left(tex, pos - 1));
          if (i == 1) let(&htmHyp, left(tex, pos - 1));
          if (i == 2) let(&htmRef, left(tex, pos - 1));
          /* 26-Jun-2017 nm */
          if (i == 3) let(&htmLocLab, left(tex, pos - 1));

          let(&tex, right(tex, pos + 1));
          i++;
        }
      }

      /* 26-Jun-2017 nm */
      if (i == 3 && htmRef[0] == '@') {
        /* The referenced statement has no hypotheses but has a local
           label e.g."2 a4s @2: $p" */
        let(&htmLocLab, htmRef);
        let(&htmRef, htmHyp);
        let(&htmHyp, "");
      }

      if (i < 3) {
        /* The referenced statement has no hypotheses e.g.
           "4 ax-1 $a" */
        let(&htmRef, htmHyp);
        let(&htmHyp, "");

        /* 1-May-2017 nm Fix bug reported by Ari Ferrera*/
        /* Change "maj=ax-1" to "ax-1" so \ref{} produced by
           "show proof .../tex" will match \label{} produced by
           "show statement .../tex" */
        /* Later on 1-May-2017:  earlier we set the noIndentFlag (Lemmon
           proof) in the SHOW PROOF.../TEX call in metamath.c, so the
           hypothesis ref list will be available just like in the HTML
           output. */
        /* 1-May-2017 nm - Delete the below if we keep the noIndentFlag solution. */
        /*
        if (!htmlFlag) {
          pos = instr(1, htmRef, "=");
          if (!pos) bug(2342);
          let(&htmRef, right(htmRef, pos + 1));
        }
        */
        /* We now consider "=" a bug since the call via typeProof() in
           metamath.c now always has noIndentFlag = 1. */
        if (!htmlFlag) {
          pos = instr(1, htmRef, "=");
          if (pos) bug(2342);
        }


      }
    } /* if (strlen(sPrefix)) (end processing proof step prefix) */
  }

  if (!htmlFlag) {

    /* 27-Jul-05 nm Added SIMPLE_TEX */
    if (!oldTexFlag) {
      /* 14-Sep-2010 nm Old 27-Jul-05 version commented out: */
      /* printLongLine(cat("\\texttt{", tex, "}", NULL), "", " ");  */
      /* let(&tex, ""); */ /* Deallocate */
      /* tex = asciiToTt(contPrefix); */
      /* printLongLine(cat("\\texttt{", tex, "}", NULL), "", " "); */
      /* print2("\\begin{eqnarray}\n"); */
    } else {
      /* 9/2/99 Trim down long start prefixes so they won't overflow line,
         by putting their tokens into \m macros */
#define TRIMTHRESHOLD 60
      i = (long)strlen(tex);
      while (i > TRIMTHRESHOLD) {
        if (tex[i] == '\\') {
          /* Move to math part */
          let(&texLine, cat("\\m{\\mbox{\\tt", right(tex, i + 1), "}}",
              texLine, NULL));
          /* Take off of prefix part */
          let(&tex, left(tex, i));
        }
        i--;
      }

      printLongLine(cat(
          "\\setbox\\startprefix=\\hbox{\\tt ", tex, "}", NULL), "", "\\");
      let(&tex, ""); /* Deallocate */
      tex = asciiToTt(contPrefix);
      printLongLine(cat(
          "\\setbox\\contprefix=\\hbox{\\tt ", tex, "}", NULL), "", "\\");
      print2("\\startm\n");
    }
  } else { /* htmlFlag */
    if (strlen(sPrefix)) { /* It's a proof step */

      if (htmHyp[0] == 0)
        let(&htmHyp, " ");  /* Insert blank field for Lemmon ref w/out hyp */

      /*** Start of 9-Sep-2010 ***/
      /* 9-Sep-2010 Stefan Allen - put hyperlinks on hypothesis
         label references in SHOW STATEMENT * /HTML, ALT_HTML output */
      /*Add hyperlink references to the proof */
      /* let(&htmStep, cat("",htmStep,"",NULL)); */
      /* 30-May-2015 nm Use a separate tag to put into the math cell,
         so it will link to the top of the math cell */
      let(&htmStepTag, cat("","", NULL));
      i = 1;
      pos = 1;
      while (pos && strcmp(htmHyp, " ")) {
        pos = instr(i,htmHyp, ",");
        if (!pos) pos = len(htmHyp) + 1;
        let(&htmHyp, cat(left(htmHyp, i - 1),
            "",
            seg(htmHyp, i, pos - 1),
            "",
            right(htmHyp, pos),
            NULL));
        /* Break out of loop if we hit the end */
        pos += 16 + len(seg(htmHyp, i, pos - 1)) + 1;
        if (!instr(i, htmHyp, ",")) break;
        i = pos;
      }
      /*** End of 9-Sep-2010 ***/

      /* 2/8/02 Add a space after each comma so very long hypotheses
         lists will wrap in an HTML table cell, e.g. gomaex3 in ql.mm */
      pos = instr(1, htmHyp, ",");
      while (pos) {
        let(&htmHyp, cat(left(htmHyp, pos), " ", right(htmHyp, pos + 1), NULL));
        pos = instr(pos + 1, htmHyp, ",");
      }

      /* if (!strcmp(tex, "$e") || !strcmp(tex, "$f")) { */ /* Old */
      if (refType == 'e' || refType == 'f') { /* 14-Sep-2010 nm Speedup */
        /* A hypothesis - don't include link */
        printLongLine(cat("", htmStep, "",
            htmHyp, "", htmRef,
            "",
            htmStepTag, /* 30-May-2015 nm */
                /* Put the  tag at start of math symbol cell */
            NULL), "", "\"");
      } else {
        if (hypStmt <= 0) {
          printLongLine(cat("", htmStep, "",
              htmHyp, "", htmRef,
              "",
              htmStepTag, /* 30-May-2015 nm */
                /* Put the  tag at start of math symbol cell */
              NULL), "", "\"");
        } else {
          /* Include step number reference.  The idea is that this will
             help the user to recognized "important" (vs. early trivial
             logic) steps.  This prints a small pink statement number
             after the hypothesis statement label. */
          let(&tmp, "");
          tmp = pinkHTML(hypStmt);
          /* Special case for pink number here: to make table more compact,
             we allow the pink number to break off of the href by changing
             PINK_NBSP to a space.  Elsewhere we don't allow such line
             breaks. */
          /* 10/14/02 I decided I don't like it so I took it out. */
          /*******
          let(&tmp, cat(" ", right(tmp, (long)strlen(PINK_NBSP) + 1), NULL));
          *******/

#define TOOLTIP
#ifdef TOOLTIP
          /* 19-Nov-2007 nm Get description for mod below */
          let(&descr, ""); /* Deallocate previous description */
          descr = getDescription(hypStmt);
          let(&descr, edit(descr, 4 + 16)); /* Discard lf/cr; reduce spaces */
#define MAX_DESCR_LEN 87
          if (strlen(descr) > MAX_DESCR_LEN) { /* Truncate long lines */
            i = MAX_DESCR_LEN - 3;
            while (i >= 0) { /* Get to previous word boundary */
              if (descr[i] == ' ') break;
              i--;
            }
            let(&descr, cat(left(descr, i), "...", NULL));
          }
          i = 0;
          while (descr[i] != 0) { /* Convert double quote to single */
            descr[i] = (char)(descr[i] == '"' ? '\'' : descr[i]);
            i++;
          }
#endif

          printLongLine(cat("", htmStep, "",
              htmHyp, "", htmRef,
              "", tmp,
              "",
              htmStepTag, /* 30-May-2015 nm */
                /* Put the  tag at start of math symbol cell */
              NULL), "", "\"");
        }
      }
#ifdef INDENT_HTML_PROOFS
      /* nm 3-Feb-04 Experiment to indent web proof displays */
      let(&tmp, "");
      for (i = 1; i <= indentationLevel; i++) {
        let(&tmp, cat(tmp, ". ", NULL));
      }
      let(&tmp, cat("",
          tmp,
          str((double)(indentationLevel + INDENTATION_OFFSET)), "",
          NULL));
      printLongLine(tmp, "", "\"");
      let(&tmp, "");
#endif
    } /* strlen(sPrefix) */
  } /* htmlFlag */
  let(&tex, ""); /* Deallocate */
  let(&sPrefix, ""); /* Deallocate */

  let(&tex, "");
  tex = getTexLongMath(mathString, hypStmt); /* 20-Sep-03 */
  let(&texLine, cat(texLine, tex, NULL));

  if (!htmlFlag) {  /* LaTeX */
    /* 27-Jul-05 nm Added for new LaTeX (!oldTexFlag) */
    if (!oldTexFlag) {
      /* 14-Sep-2010 nm */
      if (refType == 'e' || refType == 'f') {
        /* A hypothesis - don't include \ref{} */
        printLongLine(cat("  ",
            /* If not first step, so print "\\" LaTeX line break */
            !strcmp(htmStep, "1") ? "" : "\\\\ ",
            htmStep,  /* Step number */
            " && ",
            " & ",
            texLine,
            /* Don't put space to help prevent bad line break */
            "&\\text{Hyp~",
            /* The following puts a hypothesis number such as "2" if
               $e label is "abc.2"; if no ".", will be whole label */
            right(htmRef, instr(1, htmRef, ".") + 1),
            "}\\notag%",
            /* Add full label as LaTeX comment - note lack of space after
               "%" above to prevent bad line break */
            htmRef, NULL),
            "    \\notag \\\\ && & \\qquad ",  /* Continuation line prefix */
            " ");
      } else {
        printLongLine(cat("  ",
            /* If not first step, so print "\\" LaTeX line break */
            !strcmp(htmStep, "1") ? "" : "\\\\ ",
            htmStep,  /* Step number */
            " && ",

            /* Local label if any e.g. "@2:" */ /* 26-Jun-2017 nm */
            (htmLocLab[0] != 0) ? cat(htmLocLab, "\\ ", NULL) : "",

            " & ",
            texLine,
            /* Don't put space to help prevent bad line break */

            /* 1-May-2017 nm Surround \ref with \mbox for non-math-mode
               symbolic labels (due to \tag{..} in mmcmds.c).  Also,
               move hypotheses to after referenced label */
            "&",
            "(",

            /* Don't make local label a \ref */ /* 26-Jun-2017 nm */
            (htmRef[0] != '@') ?
                cat("\\mbox{\\ref{eq:", htmRef, "}}", NULL)
                : htmRef,

            htmHyp[0] ? "," : "",
            htmHyp,
            ")\\notag", NULL),
            /* before 1-May-2017:
            "&", htmHyp, htmHyp[0] ? "," : "",
            "(\\ref{eq:", htmRef, "})\\notag", NULL),
            */

            "    \\notag \\\\ && & \\qquad ",  /* Continuation line prefix */
            " ");
      }
      /* 14-Sep-2010 nm - commented out below */
      /* printLongLine(texLine, "", " "); */
      /* print2("\\end{eqnarray}\n"); */
      /* 6 && \vdash& ( B \ton_3 B ) \ton_3 A & (\ref{eq:q2}),4,5 \notag \\ */
      /*print2(" & (\\ref{eq:%s}%s \\notag\n",???,??? );*/
    } else {
      printLongLine(texLine, "", "\\");
      print2("\\endm\n");
    }
  } else {  /* HTML */
    printLongLine(cat(texLine, "", NULL), "", "\"");
  }

  outputToString = 0; /* Restore normal output */
  fprintf(texFilePtr, "%s", printString);
  let(&printString, "");

  let(&descr, ""); /*Deallocate */  /* 17-Nov-2007 nm */
  let(&htmStep, ""); /* Deallocate */
  let(&htmStepTag, ""); /* Deallocate */
  let(&htmHyp, ""); /* Deallocate */
  let(&htmRef, ""); /* Deallocate */
  let(&htmLocLab, ""); /* Deallocate */ /* 26-Jun-2017 nm */
  let(&tmp, ""); /* Deallocate */
  let(&texLine, ""); /* Deallocate */
  let(&tex, ""); /* Deallocate */
} /* printTexLongMath */

void printTexTrailer(flag texTrailerFlag) {

  if (texTrailerFlag) {
    outputToString = 1; /* Redirect print2 and printLongLine to printString */
    if (!htmlFlag) let(&printString, "");
        /* May have stuff to be printed 7/4/98 */
    if (!htmlFlag) {
      print2("\\end{document}\n");
    } else {
      /*******  10/10/02 Moved to mmcmds.c so it can be printed immediately
                after proof; made htmlVarColor global for this
      print2("Colors of variables:\n");
      printLongLine(cat(htmlVarColor, "", NULL), "", " ");
      *******/
      print2("
\n"); print2("\n", "%"); print2("\n", "%"); print2("
 \n"); print2("\n"); /* print2("Definition list |\n"); print2("Theorem list
\n"); */ /* print2("Copyright © 2002 \n"); print2("The Metamath Home Page is\n"); */ /* print2("metamath.org mirrors\n"); */ print2("Copyright terms:\n"); print2("Public domain\n"); print2("
\n", "%"); print2("\n"); print2("\n"); print2("W3C validator\n"); print2("
\n"); /* Todo: Decide to use or not use this */ /* print2("\n"); print2("\n"); */ print2("\n"); } outputToString = 0; /* Restore normal output */ fprintf(texFilePtr, "%s", printString); let(&printString, ""); } } /* printTexTrailer */ /* Added 4-Dec-03 - WRITE THEOREM_LIST command: Write out theorem list into mmtheorems.html, mmtheorems1.html,... */ void writeTheoremList(long theoremsPerPage, flag showLemmas, flag noVersioning) { nmbrString *nmbrStmtNmbr = NULL_NMBRSTRING; long pages, page, assertion, assertions, lastAssertion; long s, p, i1, i2; vstring str1 = ""; vstring str3 = ""; vstring str4 = ""; vstring prevNextLinks = ""; long partCntr; /* Counter for hugeHdr */ /* 21-Jun-2014 */ long sectionCntr; /* Counter for bigHdr */ /* 21-Jun-2014 */ long subsectionCntr; /* Counter for smallHdr */ /* 21-Jun-2014 */ long subsubsectionCntr; /* Counter for tinyHdr */ /* 21-Aug-2017 */ vstring outputFileName = ""; FILE *outputFilePtr; long passNumber; /* 18-Oct-2015 1/2 for summary/detailed table of contents */ /* 31-Jul-2006 for table of contents mod */ vstring hugeHdr = ""; /* 21-Jun-2014 nm */ vstring bigHdr = ""; vstring smallHdr = ""; vstring tinyHdr = ""; /* 21-Aug-2017 nm */ vstring hugeHdrComment = ""; /* 8-May-2015 nm */ vstring bigHdrComment = ""; /* 8-May-2015 nm */ vstring smallHdrComment = ""; /* 8-May-2015 nm */ vstring tinyHdrComment = ""; /* 21-Aug-2017 nm */ long stmt, i; pntrString *pntrHugeHdr = NULL_PNTRSTRING; pntrString *pntrBigHdr = NULL_PNTRSTRING; pntrString *pntrSmallHdr = NULL_PNTRSTRING; pntrString *pntrTinyHdr = NULL_PNTRSTRING; /* 21-Aug-2017 nm */ pntrString *pntrHugeHdrComment = NULL_PNTRSTRING; /* 8-May-2015 nm */ pntrString *pntrBigHdrComment = NULL_PNTRSTRING; /* 8-May-2015 nm */ pntrString *pntrSmallHdrComment = NULL_PNTRSTRING; /* 8-May-2015 nm */ pntrString *pntrTinyHdrComment = NULL_PNTRSTRING; /* 21-Aug-2017 nm */ vstring hdrCommentMarker = ""; /* 4-Aug-2018 nm */ vstring hdrCommentAnchor = ""; /* 20-Oct-2018 nm */ flag hdrCommentAnchorDone = 0; /* 20-Oct-2018 nm */ /* Populate the statement map */ /* ? ? ? Future: is assertions same as statement[statements].pinkNumber? */ nmbrLet(&nmbrStmtNmbr, nmbrSpace(statements + 1)); assertions = 0; /* Number of $p's + $a's */ for (s = 1; s <= statements; s++) { if (statement[s].type == a_ || statement[s].type == p_) { assertions++; /* Corresponds to pink number */ nmbrStmtNmbr[assertions] = s; } } if (assertions != statement[statements].pinkNumber) bug(2328); /* 31-Jul-2006 nm Table of contents mod */ /* Allocate array for section headers found */ pntrLet(&pntrHugeHdr, pntrSpace(statements + 1)); pntrLet(&pntrBigHdr, pntrSpace(statements + 1)); pntrLet(&pntrSmallHdr, pntrSpace(statements + 1)); pntrLet(&pntrTinyHdr, pntrSpace(statements + 1)); /* 21-Aug-2017 nm */ pntrLet(&pntrHugeHdrComment, pntrSpace(statements + 1)); /* 8-May-2015 nm */ pntrLet(&pntrBigHdrComment, pntrSpace(statements + 1)); /* 8-May-2015 nm */ pntrLet(&pntrSmallHdrComment, pntrSpace(statements + 1)); /* 8-May-2015 nm */ pntrLet(&pntrTinyHdrComment, pntrSpace(statements + 1)); /* 21-Aug-2017 nm */ pages = ((assertions - 1) / theoremsPerPage) + 1; /* for (page = 1; page <= pages; page++) { */ /* 8-May-2015 nm */ for (page = 0; page <= pages; page++) { /* Open file */ let(&outputFileName, /* cat("mmtheorems", (page > 1) ? str(page) : "", ".html", NULL)); */ /* 8-May-2015 nm */ cat("mmtheorems", (page > 0) ? str((double)page) : "", ".html", NULL)); print2("Creating %s\n", outputFileName); outputFilePtr = fSafeOpen(outputFileName, "w", noVersioning); if (!outputFilePtr) goto TL_ABORT; /* Couldn't open it (error msg was provided)*/ /* Output header */ /* TODO 14-Jan-2016: why aren't we using printTexHeader? */ outputToString = 1; print2( "\n"); print2("\n"); print2("\n"); print2("%s%s\n", ""); /* 13-Aug-2016 nm */ /* Improve mobile device display per David A. Wheeler */ print2( "\n" ); print2("\n"); printLongLine(htmlCSS, "", " "); /* print2("%s\n", cat("", htmlTitle, " - ", / * Strip off ".html" * / left(outputFileName, (long)strlen(outputFileName) - 5), "", NULL)); */ /* 4-Jun-06 nm - Put page name before "Metamath Proof Explorer" etc. */ /* 15-Nov-2015 nm - Change print2() to printLongLine() */ printLongLine(cat("", /* Strip off ".html" */ /* left(outputFileName, (long)strlen(outputFileName) - 5), */ /* "List p. ", str(page), */ /* 21-Jun-2014 */ /* 9-May-2015 nm */ ((page == 0) ? "TOC of Theorem List" : cat("P. ", str((double)page), " of Theorem List", NULL)), " - ", htmlTitle, "", NULL), "", "\""); /* Icon for bookmark */ print2("%s%s\n", ""); /* 18-Oct-2015 nm Image alignment fix */ print2( "\n"); print2("\n"); print2("\n"); print2("\n", "%"); print2("", NULL), "", "\""); printLongLine(cat( "\n"); /* 4-Aug-2018 nm - removed Firefox and IE browser references print2("\n", htmlDir, outputFileName); */ } else { print2("\n"); } } /*print2("
", htmlHome, "", htmlTitle, "", "
Statement List (", */ /* 9-May-2015 nm */ ">Theorem List (", ((page == 0) ? "Table of Contents" /* : cat("(p. ", str(page), " of ", str(pages), NULL)), */ /* 9-May-2015 nm Remove stray "(" */ : cat("p. ", str((double)page), " of ", str((double)pages), NULL)), ")", NULL), "", "\""); /* Put Previous/Next links into web page */ print2("
\n"); /* Output title with current page */ /* Output previous and next */ /* 21-Jun-2014 nm Assign prevNextLinks once here since it is used 3 times */ let(&prevNextLinks, cat(" 1) ? ((page - 1 > 1) ? str(page - 1) : "") : ((pages > 1) ? str(pages) : ""), */ /* 8-May-2015 */ (page > 0) ? ((page - 1 > 0) ? str((double)page - 1) : "") : ((pages > 0) ? str((double)pages) : ""), ".html\">", NULL)); /* if (page > 1) { */ /* 8-May-2015 */ if (page > 0) { let(&prevNextLinks, cat(prevNextLinks, "< Previous  ", NULL)); } else { let(&prevNextLinks, cat(prevNextLinks, "< Wrap  ", NULL)); } let(&prevNextLinks, cat(prevNextLinks, "", NULL)); if (page < pages) { let(&prevNextLinks, cat(prevNextLinks, "Next >", NULL)); } else { let(&prevNextLinks, cat(prevNextLinks, "Wrap >", NULL)); } printLongLine(prevNextLinks, " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ /********* old code that the above printLongLine replaces let(&str1, cat(" 1) ? ((page - 1 > 1) ? str(page - 1) : "") : ((pages > 1) ? str(pages) : ""), ".html\">", NULL)); if (page > 1) { print2("%s< Previous  \n", str1); } else { print2("%s< Wrap  \n", str1); } let(&str1, cat("", NULL)); if (page < pages) { print2("%sNext >\n", str1); } else { print2("%sWrap >\n", str1); } ******************************/ /* Finish up header */ /* Print the GIF/Unicode Font choice, if directories are specified */ if (htmlDir[0]) { if (altHtmlFlag) { /* 4-Aug-2018 nm */ print2("
Bad symbols? Try the\n"); print2("
GIF\n", htmlDir, outputFileName); print2("version.
Bad symbols?\n"); print2("Use Firefox
\n"); print2("(or GIF version for IE).
Browser slow? Try the\n"); print2("
Unicode\n", altHtmlDir, outputFileName); print2("version.
\n");*/ /*print2("
\n");*/ /* 4-Aug-2018 nm */ /* Make breadcrumb font to match other pages */ print2("\n"); print2( "\n"); print2("
\n"); /* Add a little more vertical space */ /* Print some useful links */ /* print2("
\n"); */ print2("Mirrors\n"); print2(" > \n"); print2("Metamath Home Page\n"); /* print2(" > \n"); */ /* 15-Apr-2015 nm */ /* Normally, htmlBibliography in the .mm file will have the project home page, and we depend on this here rather than extracting from htmlHome */ print2(" > \n", htmlBibliography); /* print2("MPE Home Page\n"); */ /* 15-Apr-2015 nm */ /* Put a meaningful abbreviation for the project home page by extracting capital letters from title */ let(&str1, ""); s = (long)strlen(htmlTitle); for (i = 0; i < s; i++) { if (htmlTitle[i] >= 'A' && htmlTitle[i] <= 'Z') { let(&str1, cat(str1, chr(htmlTitle[i]), NULL)); } } print2("%s Home Page\n", str1); /* if (page != 1) { */ /* 8-May-2015 nm */ if (page != 0) { print2(" > \n"); /* print2("Statement List Contents\n"); */ /* 9-May-2015 nm */ print2("Theorem List Contents\n"); } else { print2(" > \n"); /* print2("Statement List Contents\n"); */ /* 9-May-2015 nm */ print2("Theorem List Contents\n"); } /***** /@ 15-Apr-2015 nm @/ /@ Use "extHtmlStmt <= statements" as an indicator that we're doing Metamath Proof Explorer; the others don't have mmrecent.html pages @/ /@if (extHtmlStmt <= statements) {@/ /@ extHtmlStmt = statements + 1 unless mmset.html @/ /@ 8-Dec-2017 nm @/ if (extHtmlStmt < sandboxStmt) { /@ extHtmlStmt >= sandboxStmt unless mmset.html @/ *****/ /* 30-Nov-2019 nm */ /* Assume there is a Most Recent page when the .mm has a mathbox stmt (currently set.mm and iset.mm) */ if (sandboxStmt < statements + 1) { print2(" > \n"); print2("Recent Proofs\n"); } print2("      \n", GREEN_TITLE_COLOR); print2("This page: \n"); /* 8-May-2015 nm Deleted, since ToC is now separate page: */ /* if (page == 1) { print2("Start of list    \n"); } */ /* 18-Oct-2015 nm */ if (page == 0) { print2( " Detailed Table of Contents \n"); } print2("Page List\n"); /* 4-Aug-2018 nm */ /* Change breadcrumb font to match other pages */ print2("\n"); print2("\n"); print2("\n"); /* print2("
\n"); */ print2("
\n"); /* Write out HTML page so far */ fprintf(outputFilePtr, "%s", printString); outputToString = 0; let(&printString, ""); /***** 21-Jun-2014 Moved to bottom of page ******** /@ Output links to the other pages @/ fprintf(outputFilePtr, "Jump to page: \n"); for (p = 1; p <= pages; p++) { /@ Construct the pink number range @/ let(&str3, ""); str3 = pinkRangeHTML( nmbrStmtNmbr[(p - 1) @ theoremsPerPage + 1], (p < pages) ? nmbrStmtNmbr[p @ theoremsPerPage] : nmbrStmtNmbr[assertions]); /@ 31-Jul-2006 nm Change "1" to "Contents + 1" @/ if (p == page) { let(&str1, (p == 1) ? "Contents + 1" : str(p) /@ 31-Jul-2006 nm @/ ); /@ Current page shouldn't have link to self @/ } else { let(&str1, cat("" : ".html\">", @/ /@ 31-Aug-2006 nm @/ ".html\">", /@ 8-Feb-2007 nm Friendlier, because you can start scrolling through the page before it finishes loading, without its jumping to #mmtc (start of Table of Contents) when it's done. @/ (p == 1) ? "Contents + 1" : str(p) /@ 31-Jul-2006 nm @/ , "", NULL)); } let(&str1, cat(str1, PINK_NBSP, str3, NULL)); fprintf(outputFilePtr, "%s\n", str1); } ******** end of 21-Jun-2014 move *******/ /* 31-Jul-2006 nm Add table of contents to first WRITE THEOREM page */ /* if (page == 1) { */ /* We're on page 1 */ /* 8-May-2015 nm */ if (page == 0) { /* We're on ToC page */ /* Pass 1: table of contents summary; pass 2: detail */ /* 18-Oct-2015 */ for (passNumber = 1; passNumber <= 2; passNumber++) { outputToString = 1; /* 18-Oct-2015 deleted print2( "

Table of Contents
\n"); */ /* 18-Oct-2015 nm */ if (passNumber == 1) { /* 24-Oct-2018 nm Temporary hopefully */ /* 31-Oct-2018 nm Implemented workaround; see below under this date */ /* print2("

The Chrome browser has a\n"); print2("bug that hyperlinks to incorrect anchors.\n"); print2("If you click on PART 2 in the summary, it should go to PART 2 in\n"); print2("the detailed section. If it goes to PART 1, your browser has the bug.\n"); print2("If your Chrome version works, let me (Norm Megill) know\n"); print2("the version number so I can mention it here. Otherwise you will\n"); print2("need another browser to navigate. This page works with Firefox\n"); print2("and Internet Explorer and passes validator.w3.org.\n"); print2("
\n"); */ print2( "

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

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

\n"); print2("

\n"); print2("\n"); print2("\n"); print2("\n"); print2("\n"); print2("\n"); print2("\n"); /* Hilbert Space Explorer */ print2("\n"); print2("\n"); print2("\n"); print2("\n"); /* 29-Jul-2008 nm Sandbox stuff */ print2("\n"); print2("\n"); print2("\n"); print2("\n"); print2("
Color key:     Metamath Proof Explorer\n"); let(&str3, ""); if (statement[extHtmlStmt].pinkNumber <= 0) bug(2332); str3 = pinkRangeHTML(nmbrStmtNmbr[1], nmbrStmtNmbr[statement[extHtmlStmt].pinkNumber - 1]); printLongLine(cat("
(", str3, ")", NULL), " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ print2("
 \"Hilbert\n"); print2(" Hilbert Space Explorer\n"); let(&str3, ""); /* str3 = pinkRangeHTML(extHtmlStmt, nmbrStmtNmbr[assertions]); */ if (statement[sandboxStmt].pinkNumber <= 0) bug(2333); str3 = pinkRangeHTML(extHtmlStmt, nmbrStmtNmbr[statement[sandboxStmt].pinkNumber - 1]); printLongLine(cat("
(", str3, ")", NULL), " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ print2("
 \"User\n");*/ /* 24-Jul-2009 nm Changed name of sandbox to "mathbox" */ "BORDER=0 ALT=\"Users' Mathboxes\" HEIGHT=32 WIDTH=32 ALIGN=MIDDLE>\n"); /*print2(" User Sandboxes\n");*/ /* 24-Jul-2009 nm Changed name of sandbox to "mathbox" */ print2(" Users' Mathboxes\n"); let(&str3, ""); str3 = pinkRangeHTML(sandboxStmt, nmbrStmtNmbr[assertions]); printLongLine(cat("
(", str3, ")", NULL), " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ print2("
 
\n"); } /* end if (extHtmlStmt < sandboxStmt) */ /* Write out HTML page so far */ fprintf(outputFilePtr, "%s", printString); outputToString = 0; let(&printString, ""); /* Write the main table header */ outputToString = 1; print2("\n"); print2("

\n"); print2("\n", htmlTitle); */ /* 9-May-2015 nm */ print2("SUMMARY=\"Theorem List for %s\">\n", htmlTitle); let(&str3, ""); if (page < 1) bug(2335); /* Page 0 ToC should have been skipped */ str3 = pinkHTML(nmbrStmtNmbr[(page - 1) * theoremsPerPage + 1]); let(&str3, right(str3, (long)strlen(PINK_NBSP) + 1)); /* Discard " " */ let(&str4, ""); str4 = pinkHTML((page < pages) ? nmbrStmtNmbr[page * theoremsPerPage] : nmbrStmtNmbr[assertions]); let(&str4, right(str4, (long)strlen(PINK_NBSP) + 1)); /* Discard " " */ /* printLongLine(cat("",NULL), " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ print2("\n"); print2("\n"); print2("\n"); print2("\n"); print2("\n"); print2("\n"); fprintf(outputFilePtr, "%s", printString); outputToString = 0; let(&printString, ""); /* Find the last assertion that will be printed on the page, so we will know when a separator between theorems is not needed */ lastAssertion = 0; for (assertion = (page - 1) * theoremsPerPage + 1; assertion <= page * theoremsPerPage; assertion++) { if (assertion > assertions) break; /* We're beyond the end */ /* nm 22-Jan-04 Don't count statements whose names begin with "xxx" because they will not be output */ /* 9-May-2015 nm Can this be deleted? Do we need it anymore? */ /* Deleted 4-Aug-2018 nm if (strcmp("xxx", left(statement[s].labelName, 3))) { lastAssertion = assertion; } let(&str1, ""); /@ Purge string stack if too many left()'s @/ */ /* 4-Aug-2018 nm The above was replaced with: */ lastAssertion = assertion; } /* Output theorems on the page */ for (assertion = (page - 1) * theoremsPerPage + 1; assertion <= page * theoremsPerPage; assertion++) { if (assertion > assertions) break; /* We're beyond the end */ s = nmbrStmtNmbr[assertion]; /* Statement number */ /* Output only $p's, not $a's */ /*if (statement[s].type != p_) continue;*/ /* Now do everything */ /********* Deleted 3-May-2017 nm /@ nm 22-Jan-04 Skip statements whose labels begin "xxx" - this means they are temporary placeholders created by WRITE SOURCE / CLEAN in writeInput() in mmcmds.c @/ let(&str1, ""); /@ Purge string stack if too many left()'s @/ /@ 9-May-2015 nm Can this be deleted? Do we need it anymore? @/ if (!strcmp("xxx", left(statement[s].labelName, 3))) continue; ******/ /* Construct the statement type label */ if (statement[s].type == p_) { let(&str1, "Theorem"); } else if (!strcmp("ax-", left(statement[s].labelName, 3))) { let(&str1, "Axiom"); } else if (!strcmp("df-", left(statement[s].labelName, 3))) { let(&str1, "Definition"); } else { let(&str1, "Syntax"); } if (s == s + 0) goto skip_date; /* OBSOLETE */ /* Get the date in the comment section after the statement */ let(&str1, space(statement[s + 1].labelSectionLen)); memcpy(str1, statement[s + 1].labelSectionPtr, (size_t)(statement[s + 1].labelSectionLen)); let(&str1, edit(str1, 2)); /* Discard spaces and tabs */ i1 = instr(1, str1, "$(["); i2 = instr(i1, str1, "]$)"); if (i1 && i2) { let(&str1, seg(str1, i1 + 3, i2 - 1)); } else { let(&str1, ""); } skip_date: let(&str3, ""); str3 = getDescription(s); let(&str4, ""); str4 = pinkHTML(s); /* Get little pink number */ /* Output the description comment */ /* Break up long lines for text editors with printLongLine */ let(&printString, ""); outputToString = 1; print2("\n"); /* Blank line for HTML source human readability */ /* 31-Jul-2006 nm Table of contents mod */ if (((vstring)(pntrHugeHdr[s]))[0]) { /* There is a major part break */ printLongLine(cat( /* 21-Jun-2014 */ /* The header */ "", */ /* 9-May-2015 nm */ "", NULL), " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ /* 8-May-2015 nm */ /* The comment part of the header, if any */ if (((vstring)(pntrHugeHdrComment[s]))[0]) { /* Open the table row */ /* print2("%s\n", ""); */ /* 9-May-2015 nm */ } /* 9-May-2015 nm */ /* Close the table row */ print2("%s\n", ""); printLongLine(cat( /* 21-Jun-2014 */ /* Separator row */ "", NULL), " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ } if (((vstring)(pntrBigHdr[s]))[0]) { /* There is a major section break */ printLongLine(cat( /* The header */ "", */ /* 9-May-2015 nm */ "", NULL), " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ /* 8-May-2015 nm */ /* The comment part of the header, if any */ if (((vstring)(pntrBigHdrComment[s]))[0]) { /* Open the table row */ /* print2("%s\n", ""); */ /* 9-May-2015 nm */ } /* 9-May-2015 nm */ /* Close the table row */ print2("%s\n", ""); printLongLine(cat( /* 21-Jun-2014 */ /* Separator row */ "", NULL), " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ } if (((vstring)(pntrSmallHdr[s]))[0]) { /* There is a minor sec break */ printLongLine(cat( /* The header */ "", */ /* 9-May-2015 nm */ "", NULL), " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ /* 8-May-2015 nm */ /* The comment part of the header, if any */ if (((vstring)(pntrSmallHdrComment[s]))[0]) { /* Open the table row */ /* print2("%s\n", ""); */ /* 9-May-2015 nm */ } /* 9-May-2015 nm */ /* Close the table row */ print2("%s\n", ""); printLongLine(cat( /* 21-Jun-2014 */ /* Separator row */ "", NULL), " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ } /* Added 21-Aug-2017 nm */ if (((vstring)(pntrTinyHdr[s]))[0]) { /* There is a subsubsection break */ printLongLine(cat( /* The header */ "", */ /* 9-May-2015 nm */ "", NULL), " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ /* 8-May-2015 nm */ /* The comment part of the header, if any */ if (((vstring)(pntrTinyHdrComment[s]))[0]) { /* Open the table row */ /* print2("%s\n", ""); */ /* 9-May-2015 nm */ } /* 9-May-2015 nm */ /* Close the table row */ print2("%s\n", ""); printLongLine(cat( /* 21-Jun-2014 */ /* Separator row */ "", NULL), " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ } /* (End of 21-Aug-2017 addition) */ printLongLine(cat( (s < extHtmlStmt) ? "" : (s < sandboxStmt) ? cat("", NULL) /* 29-Jul-2008 nm Sandbox stuff */ : cat("", NULL), "\n"); } else { /* Output the table row with the math content */ printLongLine(cat("" : cat(" BGCOLOR=", PURPLISH_BIBLIO_COLOR, ">", NULL), */ /* 29-Jul-2008 nm Sandbox stuff */ (s < extHtmlStmt) ? ">" : (s < sandboxStmt) ? cat(" BGCOLOR=", PURPLISH_BIBLIO_COLOR, ">", NULL) : cat(" BGCOLOR=", SANDBOX_COLOR, ">", NULL), /*** old "", NULL), ****/ /* 27-Oct-03 nm */ "", NULL), " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ } outputToString = 0; fprintf(outputFilePtr, "%s", printString); let(&printString, ""); if (assertion != lastAssertion) { /* Put separator row if not last theorem */ outputToString = 1; printLongLine(cat("", NULL), " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ outputToString = 0; fprintf(outputFilePtr, "%s", printString); let(&printString, ""); } } /* next assertion */ /* Output trailer */ outputToString = 1; print2("
Statement List for ", htmlTitle, */ /* 9-May-2015 nm */ printLongLine(cat("Theorem List for ", htmlTitle, " - ", str3, "-", str4, /* 21-Jun-2014 - redundant, since it's in the title now "", " - Page ", str(page), " of ", str(pages), "", */ "   *Has distinct variable group(s)" "
TypeLabelDescription
Statement
 
", */ /* 9-May-2015 nm */ ">
", "", /* Anchor for table of contents */ (vstring)(pntrHugeHdr[s]), /* "
"); */\ /* 9-May-2015 nm - keep comment in same table cell */ print2("%s\n", "

"); /* We are currently printing to printString to allow use of printLongLine(); however, the rendering function printTexComment uses printString internally, so we have to flush the current printString and turn off outputToString mode in order to call the rendering function printTexComment. */ /* (Question: why do the calls to printTexComment for statement descriptions, later, not need to flush the printString? Is the flushing code here redundant?) */ /* Clear out the printString output in prep for printTexComment */ outputToString = 0; fprintf(outputFilePtr, "%s", printString); let(&printString, ""); showStatement = s; /* For printTexComment */ texFilePtr = outputFilePtr; /* For printTexComment */ /* 8-May-2015 ???Future - make this just return a string??? */ /* printTexComment((vstring)(pntrHugeHdrComment[s]), 0); */ /* 17-Nov-2015 nm Add 3rd & 4th arguments */ printTexComment( /* Sends result to texFilePtr */ (vstring)(pntrHugeHdrComment[s]), 0, /* 1 = htmlCenterFlag */ PROCESS_EVERYTHING, /* actionBits */ /* 13-Dec-2018 nm */ 0 /* 1 = noFileCheck */); texFilePtr = NULL; outputToString = 1; /* Restore after printTexComment */ /* Close the table row */ /* print2("%s\n", "

", " 
", */ /* 9-May-2015 nm */ ">
", "", /* Anchor for table of contents */ (vstring)(pntrBigHdr[s]), /* "
"); */\ /* 9-May-2015 nm - keep comment in same table cell */ print2("%s\n", "

"); /* We are currently printing to printString to allow use of printLongLine(); however, the rendering function printTexComment uses printString internally, so we have to flush the current printString and turn off outputToString mode in order to call the rendering function printTexComment. */ /* (Question: why do the calls to printTexComment for statement descriptions, later, not need to flush the printString? Is the flushing code here redundant?) */ /* Clear out the printString output in prep for printTexComment */ outputToString = 0; fprintf(outputFilePtr, "%s", printString); let(&printString, ""); showStatement = s; /* For printTexComment */ texFilePtr = outputFilePtr; /* For printTexComment */ /* 8-May-2015 ???Future - make this just return a string??? */ /* printTexComment((vstring)(pntrBigHdrComment[s]), 0); */ /* 17-Nov-2015 nm Add 3rd & 4th arguments */ printTexComment( /* Sends result to texFilePtr */ (vstring)(pntrBigHdrComment[s]), 0, /* 1 = htmlCenterFlag */ PROCESS_EVERYTHING, /* actionBits */ /* 13-Dec-2018 nm */ 0 /* 1 = noFileCheck */); texFilePtr = NULL; outputToString = 1; /* Restore after printTexComment */ /* Close the table row */ /* print2("%s\n", "

", " 
", */ /* 9-May-2015 nm */ ">
", "", /* Anchor for table of contents */ (vstring)(pntrSmallHdr[s]), /* "
"); */\ /* 9-May-2015 nm - keep comment in same table cell */ print2("%s\n", "

"); /* We are currently printing to printString to allow use of printLongLine(); however, the rendering function printTexComment uses printString internally, so we have to flush the current printString and turn off outputToString mode in order to call the rendering function printTexComment. */ /* (Question: why do the calls to printTexComment for statement descriptions, later, not need to flush the printString? Is the flushing code here redundant?) */ /* Clear out the printString output in prep for printTexComment */ outputToString = 0; fprintf(outputFilePtr, "%s", printString); let(&printString, ""); showStatement = s; /* For printTexComment */ texFilePtr = outputFilePtr; /* For printTexComment */ /* 8-May-2015 ???Future - make this just return a string??? */ /* printTexComment((vstring)(pntrSmallHdrComment[s]), 0); */ /* 17-Nov-2015 nm Add 3rd & 4th arguments */ printTexComment( /* Sends result to texFilePtr */ (vstring)(pntrSmallHdrComment[s]), 0, /* 1 = htmlCenterFlag */ PROCESS_EVERYTHING, /* actionBits */ /* 13-Dec-2018 nm */ 0 /* 1 = noFileCheck */); texFilePtr = NULL; outputToString = 1; /* Restore after printTexComment */ /* Close the table row */ /* print2("%s\n", "

", " 
", */ /* 9-May-2015 nm */ ">
", "", /* Anchor for table of contents */ (vstring)(pntrTinyHdr[s]), /* "
"); */\ /* 9-May-2015 nm - keep comment in same table cell */ print2("%s\n", "

"); /* We are currently printing to printString to allow use of printLongLine(); however, the rendering function printTexComment uses printString internally, so we have to flush the current printString and turn off outputToString mode in order to call the rendering function printTexComment. */ /* (Question: why do the calls to printTexComment for statement descriptions, later, not need to flush the printString? Is the flushing code here redundant?) */ /* Clear out the printString output in prep for printTexComment */ outputToString = 0; fprintf(outputFilePtr, "%s", printString); let(&printString, ""); showStatement = s; /* For printTexComment */ texFilePtr = outputFilePtr; /* For printTexComment */ /* 8-May-2015 ???Future - make this just return a string??? */ /* printTexComment((vstring)(pntrTinyHdrComment[s]), 0); */ /* 17-Nov-2015 nm Add 3rd & 4th arguments */ printTexComment( /* Sends result to texFilePtr */ (vstring)(pntrTinyHdrComment[s]), 0, /* 1 = htmlCenterFlag */ PROCESS_EVERYTHING, /* actionBits */ /* 13-Dec-2018 nm */ 0 /* 1 = noFileCheck */); texFilePtr = NULL; outputToString = 1; /* Restore after printTexComment */ /* Close the table row */ /* print2("%s\n", "

", " 
", /* IE breaks up the date */ str1, /* Date */ "", statement[s].labelName, "", str4, /* 5-Jan-2014 nm */ /* Add asterisk if statement has distinct var groups */ (nmbrLen(statement[s].reqDisjVarsA) > 0) ? "*" : "", "", /* 15-Aug-04 nm - Add anchor for hyperlinking to the table row */ "", NULL), /* Description */ " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ showStatement = s; /* For printTexComment */ outputToString = 0; /* For printTexComment */ texFilePtr = outputFilePtr; /* For printTexComment */ /* 18-Sep-03 ???Future - make this just return a string??? */ /* printTexComment(str3, 0); */ /* Sends result to texFilePtr */ /* 17-Nov-2015 nm Add 3rd & 4th arguments */ printTexComment( /* Sends result to texFilePtr */ str3, 0, /* 1 = htmlCenterFlag */ PROCESS_EVERYTHING, /* actionBits */ /* 13-Dec-2018 nm */ 0 /* 1 = noFileCheck */); texFilePtr = NULL; outputToString = 1; /* Restore after printTexComment */ /* Get HTML hypotheses => assertion */ let(&str4, ""); str4 = getTexOrHtmlHypAndAssertion(s); /* In mmwtex.c */ /* 19-Aug-05 nm Suppress the math content of lemmas, which can be very big and not interesting */ if (!strcmp(left(str3, 10), "Lemma for ") && !showLemmas) { /* 10-Oct-2012 nm */ /* Suppress the table row with the math content */ print2(" [Auxiliary lemma - not displayed.]
 ", str4, "
", str4, "
", " 
\n"); print2("\n"); /* 8-May-2015 */ SKIP_LIST: /* (skipped when page == 0) */ outputToString = 1; /* To compensate for skipped assignment above */ /* 21-Jun-2014 nm Put extra Prev/Next hyperlinks here for convenience */ print2("\n", '%'); print2(" \n"); print2(" \n"); print2(" \n"); print2(" \n"); print2(" \n"); print2("
\n", '%'); print2("  \n"); /* print2(" \n"); print2(" MPE Home  \n"); print2( " Table of contents\n"); */ print2("  \n"); printLongLine(cat(" ", prevNextLinks, NULL), " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ print2("
\n"); print2("
\n"); outputToString = 0; fprintf(outputFilePtr, "%s", printString); let(&printString, ""); fprintf(outputFilePtr, "\n"); fprintf(outputFilePtr, "
\n"); fprintf(outputFilePtr, "Page List\n"); fprintf(outputFilePtr, "
\n"); /* 21-Jun-2014 nm Moved page list to bottom */ /* Output links to the other pages */ fprintf(outputFilePtr, "Jump to page: \n"); /* for (p = 1; p <= pages; p++) { */ /* 8-May-2015 */ for (p = 0; p <= pages; p++) { /* Construct the pink number range */ let(&str3, ""); if (p > 0) { /* 8-May-2015 */ str3 = pinkRangeHTML( nmbrStmtNmbr[(p - 1) * theoremsPerPage + 1], (p < pages) ? nmbrStmtNmbr[p * theoremsPerPage] : nmbrStmtNmbr[assertions]); } /* 31-Jul-2006 nm Change "1" to "Contents + 1" */ if (p == page) { let(&str1, /* (p == 1) ? "Contents + 1" : str(p) */ /* 31-Jul-2006 nm */ /* 8-May-2015 nm */ (p == 0) ? "Contents" : str((double)p) ); /* Current page shouldn't have link to self */ } else { let(&str1, cat("" : ".html\">", */ /* 31-Aug-2006 nm */ ".html\">", /* 8-Feb-2007 nm Friendlier, because you can start scrolling through the page before it finishes loading, without its jumping to #mmtc (start of Table of Contents) when it's done. */ /* (p == 1) ? "Contents + 1" : str(p) */ /* 31-Jul-2006 nm */ /* 8-May-2015 nm */ (p == 0) ? "Contents" : str((double)p) , "", NULL)); } let(&str1, cat(str1, PINK_NBSP, str3, NULL)); fprintf(outputFilePtr, "%s\n", str1); } /* End of 21-Jun-2014 */ outputToString = 1; print2("
\n"); /* nm 22-Jan-04 Take out date because it causes an unnecessary incremental site update */ /* print2("
\n"); print2("This page was last updated on %s.\n", date()); print2("
\n"); */ /* print2("
\n"); print2("metamath.org mirrors\n"); print2("
\n"); */ /* Add a "Previous" and "Next" links to bottom of page for convenience */ /************ 21-Jun-2014 nm Done above, put into prevNextLinks string let(&str1, cat(" 1) ? ((page - 1 > 1) ? str(page - 1) : "") : ((pages > 1) ? str(pages) : ""), ".html\">", NULL)); if (page > 1) { let(&str1, cat(str1, "< Previous  ", NULL)); } else { let(&str1, cat(str1, "< Wrap  ", NULL)); } let(&str1, cat(str1, "", NULL)); if (page < pages) { let(&str1, cat(str1, "Next >", NULL)); } else { let(&str1, cat(str1, "Wrap >", NULL)); } *************/ print2("\n", '%'); print2(" \n"); /*print2(" \n", '%');*/ /* 31-Aug-2006 nm Changed above line to the 4 following lines: */ print2(" \n"); print2(" \n"); print2(" \n"); print2(" \n"); print2("
 \n", '%'); print2("  \n"); /* print2(" \n"); print2(" MPE Home  \n"); print2( " Table of contents\n"); */ print2(" \n"); /* print2(" metamath.org mirrors\n"); */ print2("Copyright terms:\n"); print2("Public domain\n"); print2(" \n"); /*printLongLine(cat(" ", str1, NULL),*/ printLongLine(cat(" ", prevNextLinks, NULL), /* 21-Jun-2014 */ " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ print2("
\n"); /* Todo: Decide to use or not use this */ /* print2("\n"); print2(""); */ print2("\n"); outputToString = 0; fprintf(outputFilePtr, "%s", printString); let(&printString, ""); /* Close file */ fclose(outputFilePtr); } /* next page */ TL_ABORT: /* Deallocate memory */ let(&str1, ""); let(&str3, ""); let(&str4, ""); let(&prevNextLinks, ""); let(&outputFileName, ""); let(&hugeHdr, ""); let(&bigHdr, ""); let(&smallHdr, ""); let(&tinyHdr, ""); /* 21-Aug-2017 nm */ let(&hdrCommentMarker, ""); /* 4-Aug-2018 */ for (i = 0; i <= statements; i++) let((vstring *)(&pntrHugeHdr[i]), ""); pntrLet(&pntrHugeHdr, NULL_PNTRSTRING); for (i = 0; i <= statements; i++) let((vstring *)(&pntrBigHdr[i]), ""); pntrLet(&pntrBigHdr, NULL_PNTRSTRING); for (i = 0; i <= statements; i++) let((vstring *)(&pntrSmallHdr[i]), ""); pntrLet(&pntrSmallHdr, NULL_PNTRSTRING); /* 21-Aug-2017 nm */ for (i = 0; i <= statements; i++) let((vstring *)(&pntrTinyHdr[i]), ""); pntrLet(&pntrTinyHdr, NULL_PNTRSTRING); } /* writeTheoremList */ /* 18-Dec-2016 nm - use true "header area" as described below, and ensure statement argument is $p or $a */ /* 2-Aug-2009 nm - broke this function out from writeTheoremList() */ /* 21-Jun-2014 nm - added hugeHdrTitle */ /* 21-Aug-2017 nm - added tinyHdrTitle */ /* 8-May-2015 nm - added hugeHdrComment, bigHdrComment, smallHdrComment */ /* 21-Aug-2017 nm - added tinyHdrComment */ /* This function extracts any section headers in the comment sections prior to the label of statement stmt. If a huge (####...) header isn't found, *hugeHdrTitle will be set to the empty string. If a big (#*#*...) header isn't found (or isn't after the last huge header), *bigHdrTitle will be set to the empty string. If a small (=-=-...) header isn't found (or isn't after the last huge header or the last big header), *smallHdrTitle will be set to the empty string. In all 3 cases, only the last occurrence of a header is considered. If a tiny (-.-....) header isn't found (or isn't after the last huge header or the last big header or the last small header), *tinyHdrTitle will be set to the empty string. In all 4 cases, only the last occurrence of a header is considered. */ /* 20-Jun-2015 metamath Google group email: There are 3 kinds of section headers, big (####...), medium (#*#*#*...), and small (=-=-=-). Call the collection of (outside-of-statement) comments between two successive $a/$p statements (i.e. those statements that generate web pages) a "header area". The algorithm scans the header area for the _last_ header of each type (big, medium, small) and discards all others. Then, if there is a medium and it appears before a big, the medium is discarded. If there is a small and it appears before a big or medium, the small is discarded. In other words, a maximum of one header of each type is kept, in the order big, medium, and small. There are two reasons for doing this: (1) it disregards headers used for other purposes such as the headers for the set.mm-specific information at the top that is not of general interest and (2) it ignores headers for empty sections; for example, a mathbox user might have a bunch of headers for sections planned for the future, but we ignore them if those sections are empty (no $a or $p in them). 6-Aug-2019 nm: added error checking; added error checking 21-Aug-2017 nm: added "tiny" to "big, medium, small". */ /*void getSectionHeadings(long stmt, vstring *hugeHdrTitle, vstring *bigHdrTitle,*/ /* Return 1 if error found, 0 otherwise */ /* 6-Aug-2019 nm */ flag getSectionHeadings(long stmt, vstring *hugeHdrTitle, vstring *bigHdrTitle, vstring *smallHdrTitle, vstring *tinyHdrTitle, /* 21-Aug-2017 nm */ /* Added 8-May-2015 nm */ vstring *hugeHdrComment, vstring *bigHdrComment, vstring *smallHdrComment, vstring *tinyHdrComment) { /* 21-Aug-2017 nm */ #define HUGE_DECORATION "####" #define BIG_DECORATION "#*#*" #define SMALL_DECORATION "=-=-" #define TINY_DECORATION "-.-." /* 31-Jul-2006 for table of contents mod */ vstring labelStr = ""; long pos, pos1, pos2, pos3, pos4; flag errorFound = 0; /* 6-Aug-2019 nm */ flag saveOutputToString; /* 6-Aug-2019 nm */ /* 6-Aug-2019 nm */ /* Print any error messages to screen */ saveOutputToString = outputToString; /* To restore when returning */ outputToString = 0; /* 18-Dec-2016 nm */ /* We now process only $a or $p statements */ if (statement[stmt].type != a_ && statement[stmt].type != p_) bug(2340); /* 18-Dec-2016 nm */ /* Get header area between this statement and the statement after the previous $a or $p statement */ /* pos3 and pos4 are used temporarily here; not related to later use */ pos3 = statement[stmt].headerStartStmt; /* Statement immediately after the previous $a or $p statement (will be this statement if previous statement is $a or $p) */ if (pos3 == 0 || pos3 > stmt) bug(2241); pos4 = (statement[stmt].labelSectionPtr - statement[pos3].labelSectionPtr) + statement[stmt].labelSectionLen; /* Length of the header area */ let(&labelStr, space(pos4)); memcpy(labelStr, statement[pos3].labelSectionPtr, (size_t)(pos4)); /* Old code before 18-Dec-2016 /@ Get headers from comment section between statements @/ let(&labelStr, space(statement[stmt].labelSectionLen)); memcpy(labelStr, statement[stmt].labelSectionPtr, (size_t)(statement[stmt].labelSectionLen)); */ pos = 0; pos2 = 0; while (1) { /* Find last "huge" header, if any */ /* 4-Nov-2007 nm: Obviously, the match below will not work if the $( line has a trailing space, which some editors might insert. The symptom is a missing table of contents entry. But to detect this (and for the #*#* and =-=- matches below) would take a little work and perhaps slow things down, and I don't think it is worth it. I put a note in HELP WRITE THEOREM_LIST. */ pos1 = pos; /* 23-May-2008 */ pos = instr(pos + 1, labelStr, "$(\n" HUGE_DECORATION); /* 23-May-2008 nm Tolerate one space after "$(", to handle case of one space added to the end of each line with TOOLS to make global label changes are easier (still a kludge; this should be made white-space insensitive some day) */ pos1 = instr(pos1 + 1, labelStr, "$( \n" HUGE_DECORATION); if (pos1 > pos) pos = pos1; if (!pos) break; if (pos) pos2 = pos; } if (pos2) { /* Extract "huge" header */ pos = instr(pos2 + 4, labelStr, "\n"); /* Get to end of #### line */ pos2 = instr(pos + 1, labelStr, "\n"); /* Find end of title line */ /* Error check - can't have more than 1 title line */ /* 6-Aug-2019 nm */ if (strcmp(mid(labelStr, pos2 + 1, 4), HUGE_DECORATION)) { print2( "?Warning: missing closing \"%s\" decoration above statement \"%s\".\n", HUGE_DECORATION, statement[stmt].labelName); errorFound = 1; } pos3 = instr(pos2 + 1, labelStr, "\n"); /* Get to end of 2nd #### line */ while (labelStr[(pos3 - 1) + 1] == '\n') pos3++; /* Skip 1st blank lines */ pos4 = instr(pos3, labelStr, "$)"); /* Get to end of title comment */ let(&(*hugeHdrTitle), seg(labelStr, pos + 1, pos2 - 1)); let(&(*hugeHdrTitle), edit((*hugeHdrTitle), 8 + 128)); /* Trim leading, trailing sp */ let(&(*hugeHdrComment), seg(labelStr, pos3 + 1, pos4 - 2)); let(&(*hugeHdrComment), edit((*hugeHdrComment), 8 + 16384)); /* Trim leading sp, trailing sp & lf */ } /* pos = 0; */ /* Leave pos alone so that we start with "huge" header pos, to ignore any earlier "tiny" or "small" or "big" header */ pos2 = 0; while (1) { /* Find last "big" header, if any */ /* nm 4-Nov-2007: Obviously, the match below will not work if the $( line has a trailing space, which some editors might insert. The symptom is a missing table of contents entry. But to detect this (and for the =-=- match below) would take a little work and perhaps slow things down, and I don't think it is worth it. I put a note in HELP WRITE THEOREM_LIST. */ pos1 = pos; /* 23-May-2008 */ pos = instr(pos + 1, labelStr, "$(\n" BIG_DECORATION); /* 23-May-2008 nm Tolerate one space after "$(", to handle case of one space added to the end of each line with TOOLS to make global label changes are easier (still a kludge; this should be made white-space insensitive some day) */ pos1 = instr(pos1 + 1, labelStr, "$( \n" BIG_DECORATION); if (pos1 > pos) pos = pos1; if (!pos) break; if (pos) pos2 = pos; } if (pos2) { /* Extract "big" header */ pos = instr(pos2 + 4, labelStr, "\n"); /* Get to end of #*#* line */ pos2 = instr(pos + 1, labelStr, "\n"); /* Find end of title line */ /* Error check - can't have more than 1 title line */ /* 6-Aug-2019 nm */ if (strcmp(mid(labelStr, pos2 + 1, 4), BIG_DECORATION)) { print2( "?Warning: missing closing \"%s\" decoration above statement \"%s\".\n", BIG_DECORATION, statement[stmt].labelName); errorFound = 1; } pos3 = instr(pos2 + 1, labelStr, "\n"); /* Get to end of 2nd #*#* line */ while (labelStr[(pos3 - 1) + 1] == '\n') pos3++; /* Skip 1st blank lines */ pos4 = instr(pos3, labelStr, "$)"); /* Get to end of title comment */ let(&(*bigHdrTitle), seg(labelStr, pos + 1, pos2 - 1)); let(&(*bigHdrTitle), edit((*bigHdrTitle), 8 + 128)); /* Trim leading, trailing sp */ let(&(*bigHdrComment), seg(labelStr, pos3 + 1, pos4 - 2)); let(&(*bigHdrComment), edit((*bigHdrComment), 8 + 16384)); /* Trim leading sp, trailing sp & lf */ } /* pos = 0; */ /* Leave pos alone so that we start with "big" header pos, to ignore any earlier "tiny" or "small" header */ pos2 = 0; while (1) { /* Find last "small" header, if any */ pos1 = pos; /* 23-May-2008 */ pos = instr(pos + 1, labelStr, "$(\n" SMALL_DECORATION); /* 23-May-2008 nm Tolerate one space after "$(", to handle case of one space added to the end of each line with TOOLS to make global label changes are easier (still a kludge; this should be made white-space insensitive some day) */ pos1 = instr(pos1 + 1, labelStr, "$( \n" SMALL_DECORATION); if (pos1 > pos) pos = pos1; if (!pos) break; if (pos) pos2 = pos; } if (pos2) { /* Extract "small" header */ pos = instr(pos2 + 4, labelStr, "\n"); /* Get to end of =-=- line */ pos2 = instr(pos + 1, labelStr, "\n"); /* Find end of title line */ /* Error check - can't have more than 1 title line */ /* 6-Aug-2019 nm */ if (strcmp(mid(labelStr, pos2 + 1, 4), SMALL_DECORATION)) { print2( "?Warning: missing closing \"%s\" decoration above statement \"%s\".\n", SMALL_DECORATION, statement[stmt].labelName); errorFound = 1; } pos3 = instr(pos2 + 1, labelStr, "\n"); /* Get to end of 2nd =-=- line */ while (labelStr[(pos3 - 1) + 1] == '\n') pos3++; /* Skip 1st blank lines */ pos4 = instr(pos3, labelStr, "$)"); /* Get to end of title comment */ let(&(*smallHdrTitle), seg(labelStr, pos + 1, pos2 - 1)); let(&(*smallHdrTitle), edit((*smallHdrTitle), 8 + 128)); /* Trim leading, trailing sp */ let(&(*smallHdrComment), seg(labelStr, pos3 + 1, pos4 - 2)); let(&(*smallHdrComment), edit((*smallHdrComment), 8 + 16384)); /* Trim leading sp, trailing sp & lf */ } /* Added 21-Aug-2017 nm */ /* pos = 0; */ /* Leave pos alone so that we start with "small" header pos, to ignore any earlier "tiny" header */ pos2 = 0; while (1) { /* Find last "tiny" header, if any */ pos1 = pos; /* 23-May-2008 */ pos = instr(pos + 1, labelStr, "$(\n" TINY_DECORATION); /* 23-May-2008 nm Tolerate one space after "$(", to handle case of one space added to the end of each line with TOOLS to make global label changes are easier (still a kludge; this should be made white-space insensitive some day) */ pos1 = instr(pos1 + 1, labelStr, "$( \n" TINY_DECORATION); if (pos1 > pos) pos = pos1; if (!pos) break; if (pos) pos2 = pos; } if (pos2) { /* Extract "tiny" header */ pos = instr(pos2 + 4, labelStr, "\n"); /* Get to end of -.-. line */ pos2 = instr(pos + 1, labelStr, "\n"); /* Find end of title line */ /* Error check - can't have more than 1 title line */ /* 6-Aug-2019 nm */ if (strcmp(mid(labelStr, pos2 + 1, 4), TINY_DECORATION)) { print2( "?Warning: missing closing \"%s\" decoration above statement \"%s\".\n", TINY_DECORATION, statement[stmt].labelName); errorFound = 1; } pos3 = instr(pos2 + 1, labelStr, "\n"); /* Get to end of 2nd -.-. line */ while (labelStr[(pos3 - 1) + 1] == '\n') pos3++; /* Skip 1st blank lines */ pos4 = instr(pos3, labelStr, "$)"); /* Get to end of title comment */ let(&(*tinyHdrTitle), seg(labelStr, pos + 1, pos2 - 1)); let(&(*tinyHdrTitle), edit((*tinyHdrTitle), 8 + 128)); /* Trim leading, trailing sp */ let(&(*tinyHdrComment), seg(labelStr, pos3 + 1, pos4 - 2)); let(&(*tinyHdrComment), edit((*tinyHdrComment), 8 + 16384)); /* Trim leading sp, trailing sp & lf */ } /* (End of 21-Aug-2017 addition) */ /* 6-Aug-2019 nm */ if (errorFound == 1) { print2(" (Note that section titles may not be longer than one line.)\n"); } /* Restore output stream */ outputToString = saveOutputToString; let(&labelStr, ""); /* Deallocate string memory */ return errorFound; /* 6-Aug-2019 nm */ } /* getSectionHeadings */ /* Returns the pink number printed next to statement labels in HTML output */ /* The pink number only counts $a and $p statements, unlike the statement number which also counts $f, $e, $c, $v, ${, $} */ /* 10/10/02 This is no longer used? */ #ifdef DUMMY /* For commenting it out */ long pinkNumber(long statemNum) { long statemMap = 0; long i; /* Statement map for number of showStatement - this makes the statement number more meaningful, by counting only $a and $p. */ /* ???This could be done once if we want to speed things up, but be careful because it will have to be redone if ERASE then READ. For the future it could be added to the statement[] structure. */ statemMap = 0; for (i = 1; i <= statemNum; i++) { if (statement[i].type == a_ || statement[i].type == p_) statemMap++; } return statemMap; } /* pinkNumber */ #endif /* Added 10/10/02 */ /* Returns HTML for the pink number to print after the statement labels in HTML output. (Note that "pink" means "rainbow colored" number now.) */ /* Warning: The caller must deallocate the returned vstring (i.e. this function cannot be used in let statements but must be assigned to a local vstring for local deallocation) */ vstring pinkHTML(long statemNum) { long statemMap; vstring htmlCode = ""; vstring hexValue = ""; /* The pink number only counts $a and $p statements, unlike the statement number which also counts $f, $e, $c, $v, ${, $} */ /* 10/25/02 Added pinkNumber to the statement[] structure for speedup. */ /* statemMap = 0; for (i = 1; i <= statemNum; i++) { if (statement[i].type == a_ || statement[i].type == p_) statemMap++; } */ if (statemNum > 0) { statemMap = statement[statemNum].pinkNumber; } else { /* -1 means the label wasn't found */ statemMap = -1; } /* Note: we put "(future)" when the label wasn't found (an error message was also generated previously) */ /* Without style sheet */ /* let(&htmlCode, cat(PINK_NBSP, "", (statemMap != -1) ? str(statemMap) : "(future)", "", NULL)); */ #ifndef RAINBOW_OPTION /* With style sheet */ let(&htmlCode, cat(PINK_NBSP, "", (statemMap != -1) ? str((double)statemMap) : "(future)", "", NULL)); #endif #ifdef RAINBOW_OPTION /* ndm 10-Jan-04 With style sheet and explicit color */ let(&hexValue, ""); hexValue = spectrumToRGB(statemMap, statement[statements].pinkNumber); let(&htmlCode, cat(PINK_NBSP, "", (statemMap != -1) ? str((double)statemMap) : "(future)", "", NULL)); #endif let(&hexValue, ""); return htmlCode; } /* pinkHTML */ /* Added 25-Aug-04 */ /* Returns HTML for a range of pink numbers separated by a "-". */ /* Warning: The caller must deallocate the returned vstring (i.e. this function cannot be used in let statements but must be assigned to a local vstring for local deallocation) */ vstring pinkRangeHTML(long statemNum1, long statemNum2) { vstring htmlCode = ""; vstring str3 = ""; vstring str4 = ""; /* Construct the HTML for a pink number range */ let(&str3, ""); str3 = pinkHTML(statemNum1); let(&str3, right(str3, (long)strlen(PINK_NBSP) + 1)); /* Discard " " */ let(&str4, ""); str4 = pinkHTML(statemNum2); let(&str4, right(str4, (long)strlen(PINK_NBSP) + 1)); /* Discard " " */ let(&htmlCode, cat(str3, "-", str4, NULL)); let(&str3, ""); /* Deallocate */ let(&str4, ""); /* Deallocate */ return htmlCode; } /* pinkRangeHTML */ #ifdef RAINBOW_OPTION /* 20-Aug-2006 nm This section was revised so that all colors have the same grayscale brightness. */ /* This function converts a "spectrum" color (1 to maxColor) to an RBG value in hex notation for HTML. The caller must deallocate the returned vstring to prevent memory leaks. color = 1 (red) to maxColor (violet). A special case is the color -1, which just returns black. */ /* ndm 10-Jan-04 */ vstring spectrumToRGB(long color, long maxColor) { vstring str1 = ""; double fraction, fractionInPartition; long j, red, green, blue, partition; /* Change PARTITIONS whenever the table below has entries added or removed! */ #define PARTITIONS 28 static double redRef[PARTITIONS + 1]; /* 20-Aug-2006 nm Made these */ static double greenRef[PARTITIONS + 1]; /* static for */ static double blueRef[PARTITIONS + 1]; /* speedup */ static long i = -1; /* below */ if (i > -1) goto SKIP_INIT; /* 20-Aug-2006 nm - Speedup */ i = -1; /* For safety */ #define L53empirical #ifdef L53empirical /* Here, we use the maximum saturation possible for a fixed L*a*b color L (lightness) value of 53, which corresponds to 50% gray scale. Each pure color had either brightness reduced or saturation reduced, as required, to achieve L = 53. The partitions in the 'ifdef L53obsolete' below were divided into 1000 subpartitions, then new partitions were determined by reselecting partition boundaries based on where their color difference was distinguishable (i.e. could semi-comfortably read letters of one color with the other as a background, on an LCD display). Some human judgment was involved, and it is probably not completely uniform or optimal. A Just Noticeable Difference (JND) algorithm for spacing might be more accurate, especially if averaged over several subjects and different monitors. I wrote a program for that - asking the user to identify a word in one hue with an adjacent hue as a background, in order to score a point - but it was taking too much time, and I decided life is too short. I think this is "good enough" though, perhaps not even noticeably non-optimum. The comment at the end of each line is the hue 0-360 mapped linearly to 1-1043 (345 = 1000, i.e. "extreme" purple or almost red). Partitions at the end can be commented out if we want to stop at violet instead of almost wrapping around to red via the purples, in order to more accurately emulate the color spectrum. Be sure to update the PARTITIONS constant above if a partition is commented out, to avoid a bug trap. */ i++; redRef[i] = 251; greenRef[i] = 0; blueRef[i] = 0; /* 1 */ i++; redRef[i] = 247; greenRef[i] = 12; blueRef[i] = 0; /* 10 */ i++; redRef[i] = 238; greenRef[i] = 44; blueRef[i] = 0; /* 34 */ i++; redRef[i] = 222; greenRef[i] = 71; blueRef[i] = 0; /* 58 */ i++; redRef[i] = 203; greenRef[i] = 89; blueRef[i] = 0; /* 79 */ i++; redRef[i] = 178; greenRef[i] = 108; blueRef[i] = 0; /* 109 */ i++; redRef[i] = 154; greenRef[i] = 122; blueRef[i] = 0; /* 140 */ i++; redRef[i] = 127; greenRef[i] = 131; blueRef[i] = 0; /* 181 */ i++; redRef[i] = 110; greenRef[i] = 136; blueRef[i] = 0; /* 208 */ i++; redRef[i] = 86; greenRef[i] = 141; blueRef[i] = 0; /* 242 */ i++; redRef[i] = 60; greenRef[i] = 144; blueRef[i] = 0; /* 276 */ i++; redRef[i] = 30; greenRef[i] = 147; blueRef[i] = 0; /* 313 */ i++; redRef[i] = 0; greenRef[i] = 148; blueRef[i] = 22; /* 375 */ i++; redRef[i] = 0; greenRef[i] = 145; blueRef[i] = 61; /* 422 */ i++; redRef[i] = 0; greenRef[i] = 145; blueRef[i] = 94; /* 462 */ i++; redRef[i] = 0; greenRef[i] = 143; blueRef[i] = 127; /* 504 */ i++; redRef[i] = 0; greenRef[i] = 140; blueRef[i] = 164; /* 545 */ i++; redRef[i] = 0; greenRef[i] = 133; blueRef[i] = 218; /* 587 */ i++; redRef[i] = 3; greenRef[i] = 127; blueRef[i] = 255; /* 612 */ i++; redRef[i] = 71; greenRef[i] = 119; blueRef[i] = 255; /* 652 */ i++; redRef[i] = 110; greenRef[i] = 109; blueRef[i] = 255; /* 698 */ i++; redRef[i] = 137; greenRef[i] = 99; blueRef[i] = 255; /* 740 */ i++; redRef[i] = 169; greenRef[i] = 78; blueRef[i] = 255; /* 786 */ i++; redRef[i] = 186; greenRef[i] = 57; blueRef[i] = 255; /* 808 */ i++; redRef[i] = 204; greenRef[i] = 33; blueRef[i] = 249; /* 834 */ i++; redRef[i] = 213; greenRef[i] = 16; blueRef[i] = 235; /* 853 */ i++; redRef[i] = 221; greenRef[i] = 0; blueRef[i] = 222; /* 870 */ i++; redRef[i] = 233; greenRef[i] = 0; blueRef[i] = 172; /* 916 */ i++; redRef[i] = 239; greenRef[i] = 0; blueRef[i] = 132; /* 948 */ /*i++; redRef[i] = 242; greenRef[i] = 0; blueRef[i] = 98;*/ /* 973 */ /*i++; redRef[i] = 244; greenRef[i] = 0; blueRef[i] = 62;*/ /* 1000 */ #endif #ifdef L53obsolete /* THIS IS OBSOLETE AND FOR HISTORICAL REFERENCE ONLY; IT MAY BE DELETED. */ /* Here, we use the maximum saturation possible for a given L value of 53. Each pure color has either brightness reduced or saturation reduced, as appropriate, until the LAB color L (lightness) value is 53. The comment at the end of each line is the hue (0 to 360). Unfortunately, equal hue differences are not equally distinguishable. The commented-out lines were an unsuccessful attempt to make them more uniform before the final empirical table above was determined. */ i++; redRef[i] = 251; greenRef[i] = 0; blueRef[i] = 0; /* 0 r */ i++; redRef[i] = 234; greenRef[i] = 59; blueRef[i] = 0; /* 15 */ i++; redRef[i] = 196; greenRef[i] = 98; blueRef[i] = 0; /* 30 */ i++; redRef[i] = 160; greenRef[i] = 120; blueRef[i] = 0; /* 45 */ /*i++; redRef[i] = 131; greenRef[i] = 131; blueRef[i] = 0;*/ /* 60 */ i++; redRef[i] = 104; greenRef[i] = 138; blueRef[i] = 0; /* 75 */ /*i++; redRef[i] = 72; greenRef[i] = 144; blueRef[i] = 0;*/ /* 90 */ /*i++; redRef[i] = 37; greenRef[i] = 147; blueRef[i] = 0;*/ /* 105 */ i++; redRef[i] = 0; greenRef[i] = 148; blueRef[i] = 0; /* 120 g */ /*i++; redRef[i] = 0; greenRef[i] = 148; blueRef[i] = 37;*/ /* 135 */ /*i++; redRef[i] = 0; greenRef[i] = 145; blueRef[i] = 73;*/ /* 150 */ i++; redRef[i] = 0; greenRef[i] = 145; blueRef[i] = 109; /* 165 */ /*i++; redRef[i] = 0; greenRef[i] = 142; blueRef[i] = 142;*/ /* 180 */ /*i++; redRef[i] = 0; greenRef[i] = 139; blueRef[i] = 185;*/ /* 195 */ i++; redRef[i] = 0; greenRef[i] = 128; blueRef[i] = 255; /* 210 */ /*i++; redRef[i] = 73; greenRef[i] = 119; blueRef[i] = 255;*/ /* 225 */ i++; redRef[i] = 110; greenRef[i] = 110; blueRef[i] = 255; /* 240 b */ i++; redRef[i] = 138; greenRef[i] = 99; blueRef[i] = 255; /* 255 */ i++; redRef[i] = 168; greenRef[i] = 81; blueRef[i] = 255; /* 270 */ i++; redRef[i] = 201; greenRef[i] = 40; blueRef[i] = 255; /* 285 */ i++; redRef[i] = 222; greenRef[i] = 0; blueRef[i] = 222; /* 300 */ i++; redRef[i] = 233; greenRef[i] = 0; blueRef[i] = 175; /* 315 */ i++; redRef[i] = 241; greenRef[i] = 0; blueRef[i] = 120; /* 330 */ /*i++; redRef[i] = 245; greenRef[i] = 0; blueRef[i] = 61;*/ /* 345 */ #endif #ifdef L68obsolete /* THIS IS OBSOLETE AND FOR HISTORICAL REFERENCE ONLY; IT MAY BE DELETED. */ /* Each pure color has either brightness reduced or saturation reduced, as appropriate, until the LAB color L (lightness) value is 68. L = 68 was for the original pink color #FA8072, but the purples end up too light to be seen easily on some monitors */ i++; redRef[i] = 255; greenRef[i] = 122; blueRef[i] = 122; /* 0 r */ i++; redRef[i] = 255; greenRef[i] = 127; blueRef[i] = 0; /* 30 */ i++; redRef[i] = 207; greenRef[i] = 155; blueRef[i] = 0; /* 45 */ i++; redRef[i] = 170; greenRef[i] = 170; blueRef[i] = 0; /* 60 */ i++; redRef[i] = 93; greenRef[i] = 186; blueRef[i] = 0; /* 90 */ i++; redRef[i] = 0; greenRef[i] = 196; blueRef[i] = 0; /* 120 g */ i++; redRef[i] = 0; greenRef[i] = 190; blueRef[i] = 94; /* 150 */ i++; redRef[i] = 0; greenRef[i] = 185; blueRef[i] = 185; /* 180 */ i++; redRef[i] = 87; greenRef[i] = 171; blueRef[i] = 255; /* 210 */ i++; redRef[i] = 156; greenRef[i] = 156; blueRef[i] = 255; /* 240 b */ i++; redRef[i] = 197; greenRef[i] = 140; blueRef[i] = 255; /* 270 */ /*i++; redRef[i] = 223; greenRef[i] = 126; blueRef[i] = 255;*/ /* 285 */ i++; redRef[i] = 255; greenRef[i] = 100; blueRef[i] = 255; /* 300 */ i++; redRef[i] = 255; greenRef[i] = 115; blueRef[i] = 185; /* 330 */ #endif #ifdef L53S57obsolete /* THIS IS OBSOLETE AND FOR HISTORICAL REFERENCE ONLY; IT MAY BE DELETED. */ /* Saturation is constant 57%; LAB color L (lightness) is constant 53. This looks nice - colors are consistent pastels due to holding saturation constant (the maximum possible due to blue) - but we lose some of the distinguishability provided by saturated colors */ i++; redRef[i] = 206; greenRef[i] = 89; blueRef[i] = 89; /* 0 r */ i++; redRef[i] = 184; greenRef[i] = 105; blueRef[i] = 79; /* 15 */ i++; redRef[i] = 164; greenRef[i] = 117; blueRef[i] = 71; /* 30 */ i++; redRef[i] = 145; greenRef[i] = 124; blueRef[i] = 62; /* 45 */ /*i++; redRef[i] = 130; greenRef[i] = 130; blueRef[i] = 56;*/ /* 60 */ /*i++; redRef[i] = 116; greenRef[i] = 135; blueRef[i] = 58;*/ /* 75 */ i++; redRef[i] = 98; greenRef[i] = 137; blueRef[i] = 59; /* 90 */ /*i++; redRef[i] = 80; greenRef[i] = 140; blueRef[i] = 60;*/ /* 105 */ i++; redRef[i] = 62; greenRef[i] = 144; blueRef[i] = 62; /* 120 g */ /*i++; redRef[i] = 61; greenRef[i] = 143; blueRef[i] = 82;*/ /* 135 */ i++; redRef[i] = 61; greenRef[i] = 142; blueRef[i] = 102; /* 150 */ /*i++; redRef[i] = 60; greenRef[i] = 139; blueRef[i] = 119;*/ /* 165 */ /*i++; redRef[i] = 60; greenRef[i] = 140; blueRef[i] = 140;*/ /* 180 */ /*i++; redRef[i] = 68; greenRef[i] = 136; blueRef[i] = 159;*/ /* 195 */ i++; redRef[i] = 80; greenRef[i] = 132; blueRef[i] = 185; /* 210 */ /*i++; redRef[i] = 93; greenRef[i] = 124; blueRef[i] = 216;*/ /* 225 */ i++; redRef[i] = 110; greenRef[i] = 110; blueRef[i] = 255; /* 240 b */ i++; redRef[i] = 139; greenRef[i] = 104; blueRef[i] = 242; /* 255 */ i++; redRef[i] = 159; greenRef[i] = 96; blueRef[i] = 223; /* 270 */ i++; redRef[i] = 178; greenRef[i] = 89; blueRef[i] = 207; /* 285 */ i++; redRef[i] = 191; greenRef[i] = 82; blueRef[i] = 191; /* 300 */ i++; redRef[i] = 194; greenRef[i] = 83; blueRef[i] = 166; /* 315 */ i++; redRef[i] = 199; greenRef[i] = 86; blueRef[i] = 142; /* 330 */ /*i++; redRef[i] = 202; greenRef[i] = 87; blueRef[i] = 116;*/ /* 345 */ #endif if (i != PARTITIONS) { /* Double-check future edits */ print2("? %ld partitions but PARTITIONS = %ld\n", i, (long)PARTITIONS); bug(2326); /* Don't go further to prevent out-of-range references */ } SKIP_INIT: if (color == -1) { let(&str1, "000000"); /* Return black for "(future)" color for labels with missing theorems in comments */ return str1; } if (color < 1 || color > maxColor) { bug(2327); } fraction = (1.0 * ((double)color - 1)) / (double)maxColor; /* Fractional position in "spectrum" */ partition = (long)(PARTITIONS * fraction); /* Partition number (integer) */ if (partition >= PARTITIONS) bug(2325); /* Roundoff error? */ fractionInPartition = 1.0 * (fraction - (1.0 * (double)partition) / PARTITIONS) * PARTITIONS; /* The fraction of this partition it covers */ red = (long)(1.0 * (redRef[partition] + fractionInPartition * (redRef[partition + 1] - redRef[partition]))); green = (long)(1.0 * (greenRef[partition] + fractionInPartition * (greenRef[partition + 1] - greenRef[partition]))); blue = (long)(1.0 * (blueRef[partition] + fractionInPartition * (blueRef[partition + 1] - blueRef[partition]))); /* debug */ /* i=1;if (outputToString==0) {i=0;outputToString=1;} */ /* print2("p%ldc%ld\n", partition, color); outputToString=i; */ /*printf("red %ld green %ld blue %ld\n", red, green, blue);*/ if (red < 0 || green < 0 || blue < 0 || red > 255 || green > 255 || blue > 255) { print2("%ld %ld %ld\n", red, green, blue); bug(2323); } let(&str1, " "); j = sprintf(str1, "%02X%02X%02X", (unsigned int)red, (unsigned int)green, (unsigned int)blue); if (j != 6) bug(2324); /* debug */ /*printf("a \n", red, green, blue);*/ return str1; } /* spectrumToRGB */ #endif /* #ifdef RAINBOW_OPTION */ /* Added 20-Sep-03 (broken out of printTexLongMath() for better modularization) */ /* Returns the HTML code for GIFs (!altHtmlFlag) or Unicode (altHtmlFlag), or LaTeX when !htmlFlag, for the math string (hypothesis or conclusion) that is passed in. */ /* Warning: The caller must deallocate the returned vstring. */ vstring getTexLongMath(nmbrString *mathString, long statemNum) { long pos; vstring tex = ""; vstring texLine = ""; vstring lastTex = ""; flag alphnew, alphold, unknownnew, unknownold; if (!texDefsRead) bug(2322); /* TeX defs were not read */ let(&texLine, ""); let(&lastTex, ""); for (pos = 0; pos < nmbrLen(mathString); pos++) { let(&tex, ""); tex = tokenToTex(mathToken[mathString[pos]].tokenName, statemNum); /* tokenToTex allocates tex; we must deallocate it */ if (!htmlFlag) { /* LaTeX */ /* If this token and previous token begin with letter, add a thin space between them */ /* Also, anything not in table will have space added */ alphnew = !!isalpha((unsigned char)(tex[0])); unknownnew = 0; if (!strcmp(left(tex, 10), "\\mbox{\\rm ")) { /* Token not in table */ unknownnew = 1; } alphold = !!isalpha((unsigned char)(lastTex[0])); unknownold = 0; if (!strcmp(left(lastTex, 10), "\\mbox{\\rm ")) { /* Token not in table*/ unknownold = 1; } /*if ((alphold && alphnew) || unknownold || (unknownnew && pos > 0)) {*/ /* Put thin space only between letters and/or unknowns 11/3/94 */ if ((alphold || unknownold) && (alphnew || unknownnew)) { /* Put additional thin space between two letters */ /* 27-Jul-05 nm Added for new LaTeX output */ if (!oldTexFlag) { let(&texLine, cat(texLine, "\\,", tex, " ", NULL)); } else { let(&texLine, cat(texLine, "\\m{\\,", tex, "}", NULL)); } } else { /* 27-Jul-05 nm Added for new LaTeX output */ if (!oldTexFlag) { let(&texLine, cat(texLine, "", tex, " ", NULL)); } else { let(&texLine, cat(texLine, "\\m{", tex, "}", NULL)); } } } else { /* HTML */ /* 7/27/03 When we have something like "E. x e. om x = y", the lack of space between om and x looks ugly in HTML. This kludge adds it in for restricted quantifiers not followed by parenthesis, in order to make the web page look a little nicer. E.g. onminex. */ /* Note that the space is put between the pos-1 and the pos tokens */ if (pos >=4) { if (!strcmp(mathToken[mathString[pos - 2]].tokenName, "e.") && (!strcmp(mathToken[mathString[pos - 4]].tokenName, "E.") || !strcmp(mathToken[mathString[pos - 4]].tokenName, "A.") /* 20-Oct-2018 nm per Benoit's 3-Sep, 18-Sep, 9-Oct emails */ || !strcmp(mathToken[mathString[pos - 4]].tokenName, "prod_") || !strcmp(mathToken[mathString[pos - 4]].tokenName, "E*") || !strcmp(mathToken[mathString[pos - 4]].tokenName, "iota_") || !strcmp(mathToken[mathString[pos - 4]].tokenName, "Disj_") /* 6-Apr-04 nm - indexed E! */ || !strcmp(mathToken[mathString[pos - 4]].tokenName, "E!") /* 12-Nov-05 nm - finite sums */ || !strcmp(mathToken[mathString[pos - 4]].tokenName, "sum_") /* 30-Sep-06 nm - infinite cartesian product */ || !strcmp(mathToken[mathString[pos - 4]].tokenName, "X_") /* 23-Jan-04 nm - indexed union, intersection */ || !strcmp(mathToken[mathString[pos - 4]].tokenName, "U_") || !strcmp(mathToken[mathString[pos - 4]].tokenName, "|^|_")) /* 23-Jan-04 nm - add space even for parenthesized arg */ /*&& strcmp(mathToken[mathString[pos]].tokenName, "(")*/ && strcmp(mathToken[mathString[pos]].tokenName, ")") /* It also shouldn't be restricted _to_ an expression in parens. */ && strcmp(mathToken[mathString[pos - 1]].tokenName, "(") /* ...or restricted _to_ a union or intersection 1-Feb-05 */ && strcmp(mathToken[mathString[pos - 1]].tokenName, "U.") && strcmp(mathToken[mathString[pos - 1]].tokenName, "|^|") /* ...or restricted _to_ an expression in braces */ && strcmp(mathToken[mathString[pos - 1]].tokenName, "{")) { let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ } } /* This one puts a space between the 2 x's in a case like "E. x x = y". E.g. cla4egf */ if (pos >=2) { /* Match a token starting with a letter */ if (isalpha((unsigned char)(mathToken[mathString[pos]].tokenName[0]))) { /* and make sure its length is 1 */ if (!(mathToken[mathString[pos]].tokenName[1])) { /* 20-Sep-2017 nm */ /* Make sure previous token is a letter also, to prevent unneeded space in "ran ( A ..." (e.g. rncoeq, dfiun3g) */ /* Match a token starting with a letter */ if (isalpha((unsigned char)(mathToken[mathString[pos - 1]].tokenName[0]))) { /* and make sure its length is 1 */ if (!(mathToken[mathString[pos - 1]].tokenName[1])) { /* See if it's 1st letter in a quantified expression */ if (!strcmp(mathToken[mathString[pos - 2]].tokenName, "E.") || !strcmp(mathToken[mathString[pos - 2]].tokenName, "A.") /* 26-Dec-2016 nm - "not free in" binder */ || !strcmp(mathToken[mathString[pos - 2]].tokenName, "F/") /* 6-Apr-04 nm added E!, E* */ || !strcmp(mathToken[mathString[pos - 2]].tokenName, "E!") /* 4-Jun-06 nm added dom, ran for space btwn A,x in "E! x e. dom A x A y" */ || !strcmp(mathToken[mathString[pos - 2]].tokenName, "ran") || !strcmp(mathToken[mathString[pos - 2]].tokenName, "dom") || !strcmp(mathToken[mathString[pos - 2]].tokenName, "E*")) { let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ } } /* 20-Sep-2017 nm */ } /* 20-Sep-2017 nm */ } } } /* This one puts a space after a letter followed by a word token e.g. "A" and "suc" in "A. x e. U. A suc" in limuni2 1-Feb-05 */ if (pos >= 1) { /* See if the next token is "suc" */ if (!strcmp(mathToken[mathString[pos]].tokenName, "suc")) { /* Match a token starting with a letter for the current token */ if (isalpha( (unsigned char)(mathToken[mathString[pos - 1]].tokenName[0]))) { /* and make sure its length is 1 */ if (!(mathToken[mathString[pos - 1]].tokenName[1])) { let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ } } } } /* This one puts a space before any "-." that doesn't come after a parentheses e.g. ax-6 has both cases */ if (pos >=1) { /* See if we have a non-parenthesis followed by not */ if (strcmp(mathToken[mathString[pos - 1]].tokenName, "(") && !strcmp(mathToken[mathString[pos]].tokenName, "-.")) { let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ } } /* nm 9-Feb-04 This one puts a space between "S" and "(" in df-iso. */ if (pos >=4) { if (!strcmp(mathToken[mathString[pos - 4]].tokenName, "Isom") && !strcmp(mathToken[mathString[pos - 2]].tokenName, ",") && !strcmp(mathToken[mathString[pos]].tokenName, "(")) { let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ } } /* nm 11-Aug-04 This one puts a space between "}" and "(" in funcnvuni proof. */ if (pos >=1) { /* See if we have "}" followed by "(" */ if (!strcmp(mathToken[mathString[pos - 1]].tokenName, "}") && !strcmp(mathToken[mathString[pos]].tokenName, "(")) { let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ } } /* 7-Mar-2016 nm This one puts a space between "}" and "{" in konigsberg proof. */ if (pos >=1) { /* See if we have "}" followed by "(" */ if (!strcmp(mathToken[mathString[pos - 1]].tokenName, "}") && !strcmp(mathToken[mathString[pos]].tokenName, "{")) { let(&texLine, cat(texLine, " ", NULL)); /* Add a space */ } } /* 7/27/03 end */ let(&texLine, cat(texLine, tex, NULL)); } /* if !htmlFlag */ let(&lastTex, tex); /* Save for next pass */ } /* Next pos */ /* 8/9/03 Discard redundant white space to reduce HTML file size */ let(&texLine, edit(texLine, 8 + 16 + 128)); /* 1-Feb-2016 nm */ /* Enclose math symbols in a span to be used for font selection */ let(&texLine, cat( (altHtmlFlag ? cat("", NULL) : ""), texLine, (altHtmlFlag ? "" : ""), NULL)); let(&tex, ""); let(&lastTex, ""); return texLine; } /* getTexLongMath */ /* Added 18-Sep-03 (broken out of metamath.c for better modularization) */ /* Returns the TeX, or HTML code for GIFs (!altHtmlFlag) or Unicode (altHtmlFlag), for a statement's hypotheses and assertion in the form hyp & ... & hyp => assertion */ /* Warning: The caller must deallocate the returned vstring (i.e. this function cannot be used in let statements but must be assigned to a local vstring for local deallocation) */ vstring getTexOrHtmlHypAndAssertion(long statemNum) { long reqHyps, essHyps, n; nmbrString *nmbrTmpPtr; /* Pointer only; not allocated directly */ vstring texOrHtmlCode = ""; vstring str2 = ""; /* Count the number of essential hypotheses essHyps */ essHyps = 0; reqHyps = nmbrLen(statement[statemNum].reqHypList); let(&texOrHtmlCode, ""); for (n = 0; n < reqHyps; n++) { if (statement[statement[statemNum].reqHypList[n]].type == (char)e_) { essHyps++; if (texOrHtmlCode[0]) { /* Add '&' between hypotheses */ if (!htmlFlag) { /* Hard-coded for set.mm! */ let(&texOrHtmlCode, cat(texOrHtmlCode, "\\quad\\&\\quad " ,NULL)); } else { if (altHtmlFlag) { /* Hard-coded for set.mm! */ let(&texOrHtmlCode, cat(texOrHtmlCode, /* 8/8/03 - Changed from Symbol to Unicode */ /* "    &   " */ "", /* 1-Feb-2016 nm */ "    &   ", "", /* 1-Feb-2016 nm */ NULL)); } else { /* Hard-coded for set.mm! */ let(&texOrHtmlCode, cat(texOrHtmlCode, "   &   " ,NULL)); } } } /* if texOrHtmlCode[0] */ /* Construct HTML hypothesis */ nmbrTmpPtr = statement[statement[statemNum].reqHypList[n]].mathString; let(&str2, ""); str2 = getTexLongMath(nmbrTmpPtr, statemNum); let(&texOrHtmlCode, cat(texOrHtmlCode, str2, NULL)); } } if (essHyps) { /* Add big arrow if there were hypotheses */ if (!htmlFlag) { /* Hard-coded for set.mm! */ let(&texOrHtmlCode, cat(texOrHtmlCode, "\\quad\\Rightarrow\\quad " ,NULL)); } else { if (altHtmlFlag) { /* Hard-coded for set.mm! */ let(&texOrHtmlCode, cat(texOrHtmlCode, /* 8/8/03 - Changed from Symbol to Unicode */ /* "    Þ   " */ /* 29-Aug-2008 nm - added sans-serif to work around FF3 bug that produces huge character heights otherwise */ /* "    ⇒   " */ "       " ,NULL)); } else { /* Hard-coded for set.mm! */ let(&texOrHtmlCode, cat(texOrHtmlCode, "   =>   " ,NULL)); } } } /* Construct TeX or HTML assertion */ nmbrTmpPtr = statement[statemNum].mathString; let(&str2, ""); str2 = getTexLongMath(nmbrTmpPtr, statemNum); let(&texOrHtmlCode, cat(texOrHtmlCode, str2, NULL)); /* Deallocate memory */ let(&str2, ""); return texOrHtmlCode; } /* getTexOrHtmlHypAndAssertion */ /* Added 17-Nov-2015 (broken out of metamath.c for better modularization) */ /* Called by the WRITE BIBLIOGRPAHY command and also by VERIFY MARKUP for error checking */ /* Returns 0 if OK, 1 if warning(s), 2 if any error */ flag writeBibliography(vstring bibFile, vstring labelMatch, /* Normally "*" except when called by verifyMarkup() */ flag errorsOnly, /* 1 = no output, just warning msgs if any */ flag noFileCheck) /* 1 = ignore missing external files (mmbiblio.html) */ { flag errFlag; FILE *list1_fp = NULL; FILE *list2_fp = NULL; long lines, p2, i, j, jend, k, l, m, n, p, q, s, pass1refs; vstring str1 = "", str2 = "", str3 = "", str4 = "", newstr = "", oldstr = ""; pntrString *pntrTmp = NULL_PNTRSTRING; flag warnFlag; n = 0; /* 14-Jan-2016 nm Old gcc 4.6.3 wrongly says may be uninit ln 5506 */ pass1refs = 0; /* 25-Jan-2016 gcc 4.5.3 wrongly says may be uninit */ if (noFileCheck == 1 && errorsOnly == 0) { bug(2336); /* If we aren't opening files, a non-error run can't work */ } /* 10/10/02 */ /* This utility builds the bibliographical cross-references to various textbooks and updates the user-specified file normally called mmbiblio.html. */ warnFlag = 0; /* 1 means warning was found, 2 that error was found */ errFlag = 0; /* Error flag to recover input file and to set return value 2 */ if (noFileCheck == 0) { list1_fp = fSafeOpen(bibFile, "r", 0/*noVersioningFlag*/); if (list1_fp == NULL) { /* Couldn't open it (error msg was provided)*/ return 1; } if (errorsOnly == 0) { fclose(list1_fp); /* This will rename the input mmbiblio.html as mmbiblio.html~1 */ list2_fp = fSafeOpen(bibFile, "w", 0/*noVersioningFlag*/); if (list2_fp == NULL) { /* Couldn't open it (error msg was provided)*/ return 1; } /* Note: in older versions the "~1" string was OS-dependent, but we don't support VAX or THINK C anymore... Anyway we reopen it here with the renamed file in case the OS won't let us rename an opened file during the fSafeOpen for write above. */ list1_fp = fSafeOpen(cat(bibFile, "~1", NULL), "r", 0/*noVersioningFlag*/); if (list1_fp == NULL) bug(2337); } } if (!texDefsRead) { htmlFlag = 1; /* Now done in readTexDefs() * if (errorsOnly == 0 ) { print2("Reading definitions from $t statement of %s...\n", input_fn); } */ if (2/*error*/ == readTexDefs(errorsOnly, noFileCheck)) { errFlag = 2; /* Error flag to recover input file */ goto BIB_ERROR; /* An error occurred */ } } /* Transfer the input file up to the special "" comment */ if (noFileCheck == 0) { while (1) { if (!linput(list1_fp, NULL, &str1)) { print2( "?Error: Could not find \"\" line in input file \"%s\".\n", bibFile); errFlag = 2; /* Error flag to recover input file */ break; } if (errorsOnly == 0) { fprintf(list2_fp, "%s\n", str1); } if (!strcmp(str1, "")) break; } if (errFlag) goto BIB_ERROR; } p2 = 1; /* Pass 1 or 2 flag */ lines = 0; while (1) { if (p2 == 2) { /* Pass 2 */ /* Allocate memory for sorting */ pntrLet(&pntrTmp, pntrSpace(lines)); lines = 0; } /* Scan all $a and $p statements */ for (i = 1; i <= statements; i++) { if (statement[i].type != (char)p_ && statement[i].type != (char)a_) continue; /* 13-Dec-2016 nm */ /* Normally labelMatch is *, but may be more specific for use by verifyMarkup() */ if (!matchesList(statement[i].labelName, labelMatch, '*', '?')) { continue; } /* Omit ...OLD (obsolete) and ...NEW (to be implemented) statements */ if (instr(1, statement[i].labelName, "NEW")) continue; if (instr(1, statement[i].labelName, "OLD")) continue; let(&str1, ""); str1 = getDescription(i); /* Get the statement's comment */ if (!instr(1, str1, "[")) continue; l = (signed)(strlen(str1)); for (j = 0; j < l; j++) { if (str1[j] == '\n') str1[j] = ' '; /* Change newlines to spaces */ if (str1[j] == '\r') bug(2338); } let(&str1, edit(str1, 8 + 128 + 16)); /* Reduce & trim whitespace */ /* 15-Apr-2015 nm */ /* Clear out math symbols in backquotes to prevent false matches to [reference] bracket */ k = 0; /* Math symbol mode if 1 */ l = (signed)(strlen(str1)); for (j = 0; j < l - 1; j++) { if (k == 0) { if (str1[j] == '`') { k = 1; /* Start of math mode */ } } else { /* In math mode */ if (str1[j] == '`') { /* A backquote */ if (str1[j + 1] == '`') { /* It is an escaped backquote */ str1[j] = ' '; str1[j + 1] = ' '; } else { k = 0; /* End of math mode */ } } else { /* Not a backquote */ str1[j] = ' '; /* Clear out the math mode part */ } } /* end if k == 0 */ } /* next j */ /* Put spaces before page #s (up to 4 digits) for sorting */ j = 0; while (1) { j = instr(j + 1, str1, " p. "); /* Heuristic - match " p. " */ if (!j) break; if (j) { for (k = j + 4; k <= (signed)(strlen(str1)) + 1; k++) { if (!isdigit((unsigned char)(str1[k - 1]))) { let(&str1, cat(left(str1, j + 2), space(4 - (k - (j + 4))), right(str1, j + 3), NULL)); /* Add ### after page number as marker */ let(&str1, cat(left(str1, j + 7), "###", right(str1, j + 8), NULL)); break; } } } } /* Process any bibliographic references in comment */ j = 0; n = 0; while (1) { j = instr(j + 1, str1, "["); /* Find reference (not robust) */ if (!j) break; /* 13-Dec-2016 nm Fix mmbiblio.html corruption caused by "[Copying an angle]" in df-ibcg in set.mm.2016-09-18-JB-mbox-cleanup */ /* Skip if there is no trailing "]" */ jend = instr(j, str1, "]"); if (!jend) break; /* Skip bracketed text with spaces */ /* This is a somewhat ugly workaround that lets us tolerate user comments in [...] is there is at least one space. The printTexComment() above handles this case with the "strcspn(bibTag, " \n\r\t\f")" above; here we just have to look for space since we already reduced \n \t to space (\f is probably overkill, and any \r's are removed during the READ command) */ if (instr(1, seg(str1, j, jend), " ")) continue; /* 22-Feb-2019 nm */ /* Skip escaped bracket "[[" */ if (str1[j] == '[') { /* (j+1)th character in str1 */ j++; /* Skip over 2nd "[" */ continue; } if (!isalnum((unsigned char)(str1[j]))) continue; /* Not start of reference */ n++; /* Backtrack from [reference] to a starting keyword */ m = 0; let(&str2, edit(str1, 32)); /* to uppercase */ /* (The string search below is rather inefficient; maybe improve the algorithm if speed becomes a problem.) */ for (k = j - 1; k >= 1; k--) { /* **IMPORTANT** Make sure to update mmhlpb.c HELP WRITE BIBLIOGRAPHY if new items are added to this list. */ if (0 /* Do not add SCHEMA but use AXIOM SCHEMA or THEOREM SCHEMA */ /* Put the most frequent ones first to speed up search */ || !strcmp(mid(str2, k, (long)strlen("THEOREM")), "THEOREM") || !strcmp(mid(str2, k, (long)strlen("EQUATION")), "EQUATION") || !strcmp(mid(str2, k, (long)strlen("DEFINITION")), "DEFINITION") || !strcmp(mid(str2, k, (long)strlen("LEMMA")), "LEMMA") || !strcmp(mid(str2, k, (long)strlen("EXERCISE")), "EXERCISE") || !strcmp(mid(str2, k, (long)strlen("AXIOM")), "AXIOM") || !strcmp(mid(str2, k, (long)strlen("CHAPTER")), "CHAPTER") || !strcmp(mid(str2, k, (long)strlen("COMPARE")), "COMPARE") || !strcmp(mid(str2, k, (long)strlen("CONDITION")), "CONDITION") || !strcmp(mid(str2, k, (long)strlen("COROLLARY")), "COROLLARY") || !strcmp(mid(str2, k, (long)strlen("EXAMPLE")), "EXAMPLE") || !strcmp(mid(str2, k, (long)strlen("FIGURE")), "FIGURE") || !strcmp(mid(str2, k, (long)strlen("ITEM")), "ITEM") || !strcmp(mid(str2, k, (long)strlen("LEMMAS")), "LEMMAS") || !strcmp(mid(str2, k, (long)strlen("LINE")), "LINE") || !strcmp(mid(str2, k, (long)strlen("LINES")), "LINES") || !strcmp(mid(str2, k, (long)strlen("NOTATION")), "NOTATION") || !strcmp(mid(str2, k, (long)strlen("NOTE")), "NOTE") || !strcmp(mid(str2, k, (long)strlen("OBSERVATION")), "OBSERVATION") || !strcmp(mid(str2, k, (long)strlen("PART")), "PART") || !strcmp(mid(str2, k, (long)strlen("POSTULATE")), "POSTULATE") || !strcmp(mid(str2, k, (long)strlen("PROBLEM")), "PROBLEM") || !strcmp(mid(str2, k, (long)strlen("PROPERTY")), "PROPERTY") || !strcmp(mid(str2, k, (long)strlen("PROPOSITION")), "PROPOSITION") || !strcmp(mid(str2, k, (long)strlen("REMARK")), "REMARK") || !strcmp(mid(str2, k, (long)strlen("RULE")), "RULE") || !strcmp(mid(str2, k, (long)strlen("SCHEME")), "SCHEME") || !strcmp(mid(str2, k, (long)strlen("SECTION")), "SECTION") /* Added 3-Jun-2018 nm */ || !strcmp(mid(str2, k, (long)strlen("PROOF")), "PROOF") || !strcmp(mid(str2, k, (long)strlen("STATEMENT")), "STATEMENT") ) { m = k; break; } let(&str3, ""); /* Clear tmp alloc stack created by "mid" */ } if (!m) { if (p2 == 1) { print2( "?Warning: Bibliography keyword missing in comment for \"%s\".\n", statement[i].labelName); print2( " (See HELP WRITE BIBLIOGRAPHY for list of keywords.)\n"); warnFlag = 1; } continue; /* Not a bib ref - ignore */ } /* m is at the start of a keyword */ p = instr(m, str1, "["); /* Start of bibliograpy reference */ q = instr(p, str1, "]"); /* End of bibliography reference */ if (q == 0) { if (p2 == 1) { print2( "?Warning: Bibliography reference not found in HTML file in \"%s\".\n", statement[i].labelName); warnFlag = 1; } continue; /* Pretend it is not a bib ref - ignore */ } s = instr(q, str1, "###"); /* Page number marker */ if (!s) { if (p2 == 1) { print2( "?Warning: No page number after [] bib ref in \"%s\".\n", statement[i].labelName); warnFlag = 1; } continue; /* No page number given - ignore */ } /* Now we have a real reference; increment reference count */ lines++; if (p2 == 1) continue; /* In 1st pass, we just count refs */ let(&str2, seg(str1, m, p - 1)); /* "Theorem #" */ let(&str3, seg(str1, p + 1, q - 1)); /* "[bibref]" w/out [] */ let(&str4, seg(str1, q + 1, s - 1)); /* " p. nnnn" */ str2[0] = (char)(toupper((unsigned char)(str2[0]))); /* Eliminate noise like "of" in "Theorem 1 of [bibref]" */ for (k = (long)strlen(str2); k >=1; k--) { if (0 || !strcmp(mid(str2, k, (long)strlen(" of ")), " of ") || !strcmp(mid(str2, k, (long)strlen(" in ")), " in ") || !strcmp(mid(str2, k, (long)strlen(" from ")), " from ") || !strcmp(mid(str2, k, (long)strlen(" on ")), " on ") ) { let(&str2, left(str2, k - 1)); break; } let(&str2, str2); } let(&newstr, ""); newstr = pinkHTML(i); /* Get little pink number */ let(&oldstr, cat( /* Construct the sorting key */ /* The space() helps Th. 9 sort before Th. 10 on same page */ str3, " ", str4, space(20 - (long)strlen(str2)), str2, "|||", /* ||| means end of sort key */ /* Construct just the statement href for combining dup refs */ "", statement[i].labelName, "", newstr, "&&&", /* &&& means end of statement href */ /* Construct actual HTML table row (without ending tag so duplicate references can be added) */ /* (i < extHtmlStmt) ? "" : cat("", NULL), */ /* 29-Jul-2008 nm Sandbox stuff */ (i < extHtmlStmt) ? "" : (i < sandboxStmt) ? cat("", NULL) : cat("", NULL), "[", str3, "]", str4, "", str2, "", statement[i].labelName, "", newstr, NULL)); /* Put construction into string array for sorting */ let((vstring *)(&pntrTmp[lines - 1]), oldstr); } /* while(1) */ } /* next i */ /* 'lines' should be the same in both passes */ if (p2 == 1) { pass1refs = lines; } else { if (pass1refs != lines) bug(2339); } if (errorsOnly == 0 && p2 == 2) { /* print2("Pass %ld finished. %ld references were processed.\n", p2, lines); */ print2("%ld references were processed.\n", lines); } if (p2 == 2) break; p2++; /* Increment from pass 1 to pass 2 */ } /* while(1) */ /* Sort */ qsortKey = ""; qsort(pntrTmp, (size_t)lines, sizeof(void *), qsortStringCmp); /* Combine duplicate references */ let(&str1, ""); /* Last biblio ref */ for (i = 0; i < lines; i++) { j = instr(1, (vstring)(pntrTmp[i]), "|||"); let(&str2, left((vstring)(pntrTmp[i]), j - 1)); if (!strcmp(str1, str2)) { /* n++; */ /* 17-Nov-2015 nm Deleted - why was this here? */ /* Combine last with this */ k = instr(j, (vstring)(pntrTmp[i]), "&&&"); /* Extract statement href */ let(&str3, seg((vstring)(pntrTmp[i]), j + 3, k -1)); let((vstring *)(&pntrTmp[i]), cat((vstring)(pntrTmp[i - 1]), "  ", str3, NULL)); let((vstring *)(&pntrTmp[i - 1]), ""); /* Clear previous line */ } let(&str1, str2); } /* Write output */ if (noFileCheck == 0 && errorsOnly == 0) { n = 0; /* Table rows written */ for (i = 0; i < lines; i++) { j = instr(1, (vstring)(pntrTmp[i]), "&&&"); if (j) { /* Don't print blanked out combined lines */ n++; /* Take off prefixes and reduce spaces */ let(&str1, edit(right((vstring)(pntrTmp[i]), j + 3), 16)); j = 1; /* Break up long lines for text editors */ let(&printString, ""); outputToString = 1; printLongLine(cat(str1, "", NULL), " ", /* Start continuation line with space */ "\""); /* Don't break inside quotes e.g. "Arial Narrow" */ outputToString = 0; fprintf(list2_fp, "%s", printString); let(&printString, ""); } } } /* Discard the input file up to the special "" comment */ if (noFileCheck == 0) { while (1) { if (!linput(list1_fp, NULL, &str1)) { print2( "?Error: Could not find \"\" line in input file \"%s\".\n", bibFile); errFlag = 2; /* Error flag to recover input file */ break; } if (!strcmp(str1, "")) { if (errorsOnly == 0) { fprintf(list2_fp, "%s\n", str1); } break; } } if (errFlag) goto BIB_ERROR; } if (noFileCheck == 0 && errorsOnly == 0) { /* Transfer the rest of the input file */ while (1) { if (!linput(list1_fp, NULL, &str1)) { break; } /* Update the date stamp at the bottom of the HTML page. */ /* This is just a nicety; no error check is done. */ if (!strcmp("This page was last updated on ", left(str1, 30))) { let(&str1, cat(left(str1, 30), date(), ".", NULL)); } fprintf(list2_fp, "%s\n", str1); } print2("%ld table rows were written.\n", n); /* Deallocate string array */ for (i = 0; i < lines; i++) let((vstring *)(&pntrTmp[i]), ""); pntrLet(&pntrTmp,NULL_PNTRSTRING); } BIB_ERROR: if (noFileCheck == 0) { fclose(list1_fp); if (errorsOnly == 0) { fclose(list2_fp); } if (errorsOnly == 0) { if (errFlag) { /* Recover input files in case of error */ remove(bibFile); /* Delete output file */ rename(cat(bibFile, "~1", NULL), fullArg[2]); /* Restore input file name */ print2("?The file \"%s\" was not modified.\n", fullArg[2]); } } } if (errFlag == 2) warnFlag = 2; return warnFlag; } /* writeBibliography */ metamath-exe-master/mmwtex.h000066400000000000000000000217731357377637100164550ustar00rootroot00000000000000/*****************************************************************************/ /* Copyright (C) 2019 NORMAN MEGILL nm at alum.mit.edu */ /* License terms: GNU General Public License */ /*****************************************************************************/ /*34567890123456 (79-character line to adjust editor window) 2345678901234567*/ #ifndef METAMATH_MMWTEX_H_ #define METAMATH_MMWTEX_H_ #include "mmvstr.h" #include "mmdata.h" /* Colors for HTML pages. */ #define GREEN_TITLE_COLOR "\"#006633\"" #define MINT_BACKGROUND_COLOR "\"#EEFFFA\"" #define PINK_NUMBER_COLOR "\"#FA8072\"" /* =salmon; was FF6666 */ #define PURPLISH_BIBLIO_COLOR "\"#FAEEFF\"" /* 29-Jul-2008 nm Sandbox stuff */ #define SANDBOX_COLOR "\"#FFFFD9\"" /* TeX flags */ /* 14-Sep-2010 nm Removed simpleTexFlag; added oldTexFlag */ extern flag oldTexFlag; /* Use macros in output; obsolete; take out someday */ /* HTML flags */ extern flag htmlFlag; /* HTML flag: 0 = TeX, 1 = HTML */ extern flag altHtmlFlag; /* Use "althtmldef" instead of "htmldef". This is intended to allow the generation of pages with the old Symbol font instead of the individual GIF files. */ extern flag briefHtmlFlag; /* Output statement only, for statement display in other HTML pages, such as the Proof Explorer home page */ extern long extHtmlStmt; /* At this statement and above, use the exthtmlxxx variables for title, links, etc. This was put in to allow proper generation of the Hilbert Space Explorer extension to the set.mm database. */ extern vstring extHtmlTitle; /* Title of extended section if any; set by by exthtmltitle command in special $t comment of database source */ extern vstring htmlVarColor; /* Set by htmlvarcolor commands */ /* Added 26-Aug-2017 nm for use by mmcmds.c */ extern vstring htmlHome; /* Set by htmlhome command */ /* Added 10/13/02 for use in metamath.c bibliography cross-reference */ extern vstring htmlBibliography; /* Optional; set by htmlbibliography command */ extern vstring extHtmlBibliography; /* Optional; set by exthtmlbibliography command */ extern vstring htmlCSS; /* Set by htmlcss commands */ /* 14-Jan-2016 nm */ /* Added 14-Jan-2016 */ extern vstring htmlFont; /* Optional; set by htmlfont command */ /* 29-Jul-2008 nm Sandbox stuff */ extern long sandboxStmt; /* At this statement and above, use sandbox stuff */ void eraseTexDefs(void); /* Undo readTexDefs() */ /* TeX/HTML/ALT_HTML word-processor-specific routines */ /* Returns 2 if there were severe parsing errors, 1 if there were warnings but no errors, 0 if no errors or warnings */ flag readTexDefs( flag errorsOnly, /* 1 = supprees non-error messages */ flag noGifCheck /* 1 = don't check for missing GIFs */); extern flag texDefsRead; struct texDef_struct { /* 27-Oct-2012 nm Made global for "erase" */ vstring tokenName; /* ASCII token */ vstring texEquiv; /* Converted to TeX */ }; extern struct texDef_struct *texDefs; /* 27-Oct-2012 nm Now glob for "erase" */ long texDefWhiteSpaceLen(char *ptr); long texDefTokenLen(char *ptr); /* Token comparison for qsort */ int texSortCmp(const void *key1, const void *key2); /* Token comparison for bsearch */ int texSrchCmp(const void *key, const void *data); /* Convert ascii to a string of \tt tex */ /* (The caller must surround it by {\tt }) */ vstring asciiToTt(vstring s); vstring tokenToTex(vstring mtoken, long statemNum); /* Converts a comment section in math mode to TeX. Each math token MUST be separated by white space. TeX "$" does not surround the output. */ vstring asciiMathToTex(vstring mathComment, long statemNum); /* Gets the next section of a comment that is in the current mode (text, label, or math). If 1st char. is not "$", text mode is assumed. mode = 0 means end of comment reached. srcptr is left at 1st char. of start of next comment section. */ vstring getCommentModeSection(vstring *srcptr, char *mode); void printTexHeader(flag texHeaderFlag); /* Prints an embedded comment in TeX. The commentPtr must point to the first character after the "$(" in the comment. The printout ends when the first "$)" or null character is encountered. commentPtr must not be a temporary allocation. htmlCenterFlag, if 1, means to center the HTML and add a "Description:" prefix.*/ /* void printTexComment(vstring commentPtr, char htmlCenterFlag); */ /* 17-Nov-2015 nm Added 3rd & 4th arguments; returns 1 if error/warning */ flag printTexComment(vstring commentPtr, /* Sends result to texFilePtr */ flag htmlCenterFlag, /* 1 = htmlCenterFlag */ long actionBits, /* see indicators below */ flag noFileCheck /* 1 = noFileCheck */); /* Indicators for actionBits */ #define ERRORS_ONLY 1 #define PROCESS_SYMBOLS 2 #define PROCESS_LABELS 4 #define ADD_COLORED_LABEL_NUMBER 8 #define PROCESS_BIBREFS 16 #define PROCESS_UNDERSCORES 32 /* CONVERT_TO_HTML means '<' to '<'; unless in comment (and strip it) */ #define CONVERT_TO_HTML 64 /* METAMATH_COMMENT means $) (as well as end-of-string) terminates string. */ #define METAMATH_COMMENT 128 /* PROCESS_ALL is for convenience */ #define PROCESS_EVERYTHING PROCESS_SYMBOLS + PROCESS_LABELS \ + ADD_COLORED_LABEL_NUMBER + PROCESS_BIBREFS \ + PROCESS_UNDERSCORES + CONVERT_TO_HTML + METAMATH_COMMENT void printTexLongMath(nmbrString *proofStep, vstring startPrefix, vstring contPrefix, long hypStmt, long indentationLevel); void printTexTrailer(flag texHeaderFlag); /* Added 4-Dec-03 Function implementing WRITE THEOREM_LIST / THEOREMS_PER_PAGE nn */ void writeTheoremList(long theoremsPerPage, flag showLemmas, flag noVersioning); /* 2-Aug-2009 nm - broke this function out from writeTheoremList() */ /* 20-Jun-2014 nm - added hugeHdrAddr */ /* 21-Aug-2017 nm - added tinyHdrAddr */ /* 6-Aug-2019 mm - changed return type from void to flag (=char) */ flag getSectionHeadings(long stmt, vstring *hugeHdrTitle, vstring *bigHdrTitle, vstring *smallHdrTitle, vstring *tinyHdrTitle, /* Added 8-May-2015 nm */ vstring *hugeHdrComment, vstring *bigHdrComment, vstring *smallHdrComment, vstring *tinyHdrComment); /* TeX symbol dictionary */ extern FILE *tex_dict_fp; /* File pointers */ extern vstring tex_dict_fn; /* File names */ /* TeX normal output */ extern flag texFileOpenFlag; extern FILE *texFilePtr; /* Pink statement number for HTML pages */ /* 10/10/02 (This is no longer used?) */ /* long pinkNumber(long statemNum); */ /* Pink statement number HTML code for HTML pages - added 10/10/02 */ /* Warning: caller must deallocate returned string */ vstring pinkHTML(long statemNum); /* Pink statement number range HTML code for HTML pages, separated by a "-" - added 24-Aug-04 */ /* Warning: caller must deallocate returned string */ vstring pinkRangeHTML(long statemNum1, long statemNum2); #define PINK_NBSP " " /* Either "" or " " depending on taste, it is the separator between a statement href and its pink number */ /* 30-Jan-04 nm Comment out the following line to go back to the pink-only color for the little statement numbers on the HTML pages */ #define RAINBOW_OPTION /* "Rainbow" instead of pink color for little numbers */ #ifdef RAINBOW_OPTION /* This function converts a "spectrum" color (1 to maxColor) to an RBG value in hex notation for HTML. The caller must deallocate the returned vstring. color = 1 (red) to maxColor (violet). */ /* ndm 10-Jan-04 */ vstring spectrumToRGB(long color, long maxColor); #endif #define INDENT_HTML_PROOFS /* nm 3-Feb-04 - indentation experiment */ /* Added 20-Sep-03 (broken out of printTexLongMath() for better modularization) */ /* Returns the HTML code for GIFs (!altHtmlFlag) or Unicode (altHtmlFlag), or LaTeX when !htmlFlag, for the math string (hypothesis or conclusion) that is passed in. */ /* Warning: The caller must deallocate the returned vstring. */ vstring getTexLongMath(nmbrString *mathString, long statemNum); /* Added 18-Sep-03 (transferred from metamath.c) */ /* Returns the TeX, or HTML code for GIFs (!altHtmlFlag) or Unicode (altHtmlFlag), for a statement's hypotheses and assertion in the form hyp & ... & hyp => assertion */ /* Warning: The caller must deallocate the returned vstring. */ /* 14-Sep-2010 nm Changed name from getHTMLHypAndAssertion() */ vstring getTexOrHtmlHypAndAssertion(long statemNum); /* Added 17-Nov-2015 (broken out of metamath.c for better modularization) */ /* For WRITE BIBLIOGRAPHY command and error checking by VERIFY MARKUP */ /* Returns 0 if OK, 1 if error or warning found */ flag writeBibliography(vstring bibFile, vstring labelMatch, /* Normally "*" except by verifyMarkup() */ flag errorsOnly, /* 1 = no output, just warning msgs if any */ flag noFileCheck); /* 1 = ignore missing external files (gifs, bib, etc.) */ #endif /* METAMATH_MMWTEX_H_ */