diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/tex-it |
Initial commit
Diffstat (limited to 'support/tex-it')
-rw-r--r-- | support/tex-it/CHANGES | 274 | ||||
-rw-r--r-- | support/tex-it/COPYING | 280 | ||||
-rw-r--r-- | support/tex-it/README | 98 | ||||
-rw-r--r-- | support/tex-it/chkscr.pl | 42 | ||||
-rw-r--r-- | support/tex-it/texit.pl | 2686 | ||||
-rw-r--r-- | support/tex-it/texit.tex | 672 | ||||
-rw-r--r-- | support/tex-it/texitrc.os2 | 59 | ||||
-rw-r--r-- | support/tex-it/texitrc.unx | 157 |
8 files changed, 4268 insertions, 0 deletions
diff --git a/support/tex-it/CHANGES b/support/tex-it/CHANGES new file mode 100644 index 0000000000..ab46c667d2 --- /dev/null +++ b/support/tex-it/CHANGES @@ -0,0 +1,274 @@ +$Id: CHANGES 1.6 1993/12/30 17:27:16 norm Exp $ + +This file documents the changes to TeXit: + +Version 1.35: + +- $DEFAULTLATEXFORMAT added to specify default LaTeX variant (it could be + a LaTeX file, a LaTeX+NFSS file, a LaTeX+NFSS2 file, an AMS LaTeX file, + or ... + +- Added support for LaTeX2e + +- Added an option to allow the TEXINPUTS path to be specified differently + for different formats. Right now, for example, TEXINPUTS2E will be used + in place of TEXINPUTS when formatting LaTeX2e documents. + +- Running under X11, TeXit will change the title bar and the icon title + to reflect the action being performed. For long jobs, this makes it + easy to tell if the iconified TeXit process has finished. If you want + this functionality, you must set $SETXTITLE=1; in your .texitrc file. + +Version 1.34: + +- Reorganized the initialization code for the format file names, printable + names, and parsing routines. + +- Added support for finding the position of the first error in a TeX log. + The '%E' in a command (the editing command, for example) is replaced + by the name of the file containing the error and `%e' is replaced by the + line number of the error. + +- TeXit verifies that TeX will be able to find the format file that you've + requested. This will help users with non-standard format file names track + down problems quickly. + +- Parsing the LaTeX log has been extended to add dependencies for bibliography + style files and bibliography databases. + +- The environment variables that contain the paths for searching for biblio + files and format files are stored in $ENV_TEXINPUTS, $ENV_BIBINPUTS, and + $ENV_TEXFMTS. These should be changed in your .texitrc file to reflect + the correct environment variables. + +- The Local-Variables and other format-file clues no longer override the + values established by a % Format:, % Master:, or % Mode: line in the + document. + +- Error messages for unrecognized warnings in LaTeX now use the format + "filename: line-number: warning" if the line number occurs in the + message, otherwise the format "filename: warning" is used. + +- If you define $DEFAULT_PRINTER, it will be the default printer queue if + you do not specify one. + +- Made STDOUT unbuffered + +- Print %done message while parsing LOG file. For very large log files, + earlier versions of TeXit gave the impression that they were hung... + +- If a raw input filename is given (one with no path component), then + TeXit will search for the file in the $ENV_TEXINPUTS path. + +Version 1.33: + +- Parsing the log files now notices which files are \input and adds them + to the dependency list for the document. You no longer have to list + all of the included files in the rules section of your document. + +- Now prints a summary of unrecognized LaTeX warning messages. Some trivial + messages are ignored (moved Marginpars, NFSS font substitutions, etc.). The + "NFSS2 Info: ***" messages _are_ displayed. + +- Added a show status subroutine and a default command for it: [?] status. + This can be used to view the list of files that TeXit things your document + depends on (? dep), the rules TeXit is using (? rules) or the value of + an Perl variable (? <varname>). "? ?" summarizes the show status syntax. + It's basically a debugging option... + +- Added an -nfss2ltx option for the NFSS2. + +Version 1.32: + +- Never publicly released + +Version 1.31: + +- Never publicly released + +Version 1.30: + +- Parsing LaTeX log files now notices that a BBL file is missing. This + handles \nocite{*}. Using \nocite{} doesn't produce a citation missing + warning so simply checking for the warning could miss a document that + had a \nocite but no \cites. + +- Parsing the log files now determines which files are included (styles + or \input, etc.) and adds them to the list of dependencies + after the first TeX run. + +- Added a [?] option to show the current status of TeXit. This is really + kindof a debugging option, but it does let you see a short summary of the + dependencies or rules of a document as well as any Perl variable defined + in TeXit. + +- When parsing LaTeX files, TeXit now records unrecognized warnings (identified + by the word "Warning:") and summarizes them at the end of processing. The + %WARNINGS array should be used for this purpose if you want to support it + in other formats. + +Version 1.29: + +- Added the &cleanup_files subroutine to simplify adding files to be erased + in TeXit rules. + +- Updated the documentation. It's still not great, but it's better. + +Version 1.28: + +- Added call to &dependent_files_are_newer() in each &interpret_<format>_log. + It was a stupid oversight to have forgotten. + +- Removed spurious carriage return after print options. + +- Changed TEXCMD{}s to use "%t" instead of "%s". This was necessary to fix + some weirdness with TeX paths. TeX always stores the DVI file in the + current directory and strips off the last extension _given_ so I've made + the filename passed to TeX consistent, the ".tex" is always left on if it + was ever present. This makes it easier to figure out what the names of + auxilliary files will be. + +- Added 'find_on_path' subroutine which looks for a file on a colon or + semi-colon seperated path name. Used in my .texitrc file, for example. + +- Made lots of changes to my .texitrc file to emphasis the fact that the + .texitrc file isn't a Perl file (it's read by require_hack) and to show + some examples that users have requested from me. + +- Added "n files deleted." message to cleanup. + +Version 1.27: + +- Added -clean option and $CLEANPROMPT variable to control whether or + not you are prompted for confirmation before cleaning up files. + If you use the '-clean' option, you will not be prompted. + +- Made -once call cleanup before exiting if $CLEANONEXIT is true and + $CLEANPROMPT is false. + +- Fixed bug that caused files with extensions other than ".tex" not to be + processed correctly. + +- Added default extensions list for cleaning up TeXinfo files. + +- Removed "dvi" from the default list of extensions to remove when cleaning + up files. You can add it back in with a .texitrc file or a TeXit rule + in your document. + +- Added 'lot', 'lof', and 'toc' to the list of cleanup extensions for LaTeX + +- Added check for multiply defined references in LaTeX. TeXit retries + once to fix the references (since they may have been fixed, but still + persist in the AUX file) and then gives up. It'll never succeed so + why keep trying? + +- Added support for a list of rules that are format-dependent. A list of + rules named "@$TEXFORMAT_rules" is executed before your document rules. + The list "@default_rules" is executed before those. So, for example, + if you are processing a LaTeX document, first @default_rules get executed, + then @latex_rules, then the rules defined by your document. + + Check out the rules defined in ``texitrc.unx'' for an example of some + rules for LaTeX documents. + +- Added parsing and interpretation for the Texinfo format + +- Reworked the &dependencies_changed() code to run seperate subroutines for + parsing and analyzing the log file. Plain TeX, LaTeX, and Texinfo are + currently supported, but it's much easier to add other formats now. + +- Changed the way &dependson() works. It now builds a list of files that + TeXit checks automatically. This is an improvement because earlier + versions of TeXit couldn't check the dependencies of your document when + you simply pressed Enter at the TeXit prompt. + +- New feature: $CMDPROMPT{key} keys that begin with "!" are valid but they + are not printed in the prompt string. + +- New feature: if $DVIQUERY{type} is set, TeXit will prompt the user for + DVI driver options. The $DVIQUERY{type} string is the prompt. These + options are appended (with a space) to any previous options. + +- New feature: if $PRINTQUERY{Q} is set, TeXit will prompt the user for + printer options. See above. + +- New feature: if defined, the setting of $PRINTCONFIRM{Q} overrides the + global setting of $CONFIRMPRINT. It should be "yes", "no", "0", or "1". + +- Added name of file being processed to the "Again?" prompt. + +Version 1.26: + +- Changed name of %formats array to %format. +- Added %formatname array to get the printable name of the format. + + %format{"latex"} = "lplain" + %formatname{"latex"} = "LaTeX" + +- $DEFAULTFORMAT is now "plain". TeXit can usually figure out that a + file is LaTeX, so it makes more sense to assume a document that cannot + be deduced is Plain. +- Added $CLEANONEXIT flag. If $CLEANONEXIT is set, TeXit will ask if you + want to delete auxilliary files on your way out. +- Added symbolic names for all the standard prompts. This makes it easier + to delete them, or add them to the AUTOCMD list... +- Added %DEFAULTCMD to customize an blank response at the prompt. If you + simply press enter w/o entering an option, TeXit pretends that you entered + "$DEFAULTCMD{key}". In this context, "key" is the _last_ choice that you + entered. For example, to make "View" the default choice after running + TeX, set: + + $DEFAULTCMD{$TeXReply} = $ViewReply; + +- Added %AUTOCMD to chain commands together. If $AUTOCMD{key} is set, + TeXit runs "$AUTOCMD{key}" after running whatever "key" refered to w/o + returning to the prompt. For example, to add a new choice "[T]ex and View" + which runs TeX and then automatically runs View, use: + + $TeXandViewReply = "[T]eX & View"; + $CMDPROMPT{$TeXandViewReply} = $CMDPROMPT{$TeXReply}; + $CMDTEST{$TeXandViewReply} = $CMDTEST{$TeXReply}; + $AUTOCMD{$TeXandViewReply} = $ViewReply; + $AUTOOPT{$TeXandViewReply} = ""; + + The array %AUTOOPT holds options that should be used for the automatic + command. +- Added $AUTOMAX to control chaining. TeXit will never perform more than + $AUTOMAX automatic commands. This prevents infinite loops. +- Added $TEXERROR to indicate what return code from TeX is a fatal error. + Some implementations of TeX (notably emTeX) return a non-zero error code + when non-fatal errors occur. TeXit assumes that if the return code from + TeX is less than $TEXERROR, the error doesn't count. +- Made $TEXCMD an associative array so that different formats can + have different command strings. $TEXCMD{"default"} is now the default. +- Made analagous change to $TEXOPTS. +- Added warning message when TeXit can't figure out the format +- No longer escape backslashes in rules. This means that you have to + use "\\" where "\" used to suffice. Advantage: you can now refer to + Perl variables in your rules (prefix them with one backslash). +- Added %S, %T, and %D meta-symbols in commands. They have the same + meaning as %s, %t and %d but forward slashes are translated into + backslashes before substitution. This is so they can be passed to + DOS and OS/2 programs which expect pathnames to be delimited with + backslashes. +- Improved handling of return codes from programs. +- Print warning if return code is non-zero +- Parse LaTeX log file for "foiltex" and "slitex" formats +- Print rules before evaluating them in $VERBOSE mode +- Automatically recognize the "foiltex" format +- No longer run BibTeX if the AUX file is missing +- Made it possible for prompt keys [x] to be any non-whitespace char + instead of only letters. +- Added -menu option. If -menu is used, TeX is not run before displaying + the menu for the first time. +- Reworked the logic for running BibTeX. Now only run BibTeX if there + are new missing citations. This means BibTeX is usually only run once + rather than twice. + +Version 1.25 + + Never released + +Version 1.24 + + Initial release diff --git a/support/tex-it/COPYING b/support/tex-it/COPYING new file mode 100644 index 0000000000..c7aea1896f --- /dev/null +++ b/support/tex-it/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, 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 diff --git a/support/tex-it/README b/support/tex-it/README new file mode 100644 index 0000000000..aedbdd40b5 --- /dev/null +++ b/support/tex-it/README @@ -0,0 +1,98 @@ +README for TeXit v1.35. + +This is just a slightly altered version of the first README file (for +version 1.24). See the CHANGES file for a list of new features. + +TeXit is a Perl script for running TeX. It has the following features: + + 1) TeXit examines the log file produced by TeX and tries to determine + when TeX needs to be run again in order to resolve references + and citations. + + 2) TeXit is smart enough to run BibTeX, if necessary and can easily + be told to run MakeIndex if necessary. + + 3) After your document has been formatted, TeXit provides a menu that + offers other options including: BibTeXing, Viewing, Viewing with + Ghostview, Printing, and Cleanup. Cleanup deletes the extra files + that get created when you run TeX (aux, log, ilg, blg, etc.). + + 4) TeXit remains "smart" about your document. If you run BibTeX, for + example, TeXit automatically reruns TeX. + + 5) TeXit has lots of hooks for customization. You can easily add new + printer queues, new printer types, and new commands without editing + the body of the script. It's all done with init files. + + For example, here's how I add a "query printer" command to the + menu: + + # Adding a query printer option... + $CMDPROMPT{"[q]uery printer"} = '&run("lpq -P%o", $opts); $REASK;'; + $CMDTEST{"[q]uery printer"} = ''; + + (Allright, I admit it's a bit ugly to read, but it's nicer than + having to modify the script!) + + 6) You can add "TeXit rules" to a document to indicate that the document + has unusual dependencies. These rules are added in TeX comments at + the bottom of your document (like Emacs `Local Variables' if you're + familiar with them). For example, the following rule tells + TeXit about your index: + + % &makeindex('-o driver.ind driver.idx') + % if &missing('driver.ind') || &changed('driver.idx'); + + When processing a document that contains this rule, TeXit will + automatically re-run TeX if the file "driver.ind" does not exist + or if "driver.idx" changes during a TeX run. + + This next rule handles a diagram created with TreeTeX. If "texittr.tlo" + changes or "texittr.tli" doesn't exist, TeXit will run the command + indicated (which asynchronously runs a command on another workstation + because TreeTeX doesn't build right for the workstation I usually use) + and then wait for "texittr.tli" to spring into existence. + + % &run('treetex texittr'), &waitfor('texittr.tli') + % if &changed('texittr.tlo') || &missing('texittr.tli'); + + Since this document creates some extra files, I push those onto the + cleanup list so that TeXit will delete them when I'm done: + + % push(@cleanup_files, ('texittr.tli','texittr.tlo')) # + % if $first_time; + + 7) The script is heavily commented and the author is pretty friendly about + answering questions (even if I do say so myself ;-) + + 8) I've banged out a few pages of documentation. Hopefully the docs make + it easier to use rather than harder, although I admit I was up pretty + late writing them and I don't really have the time to do it well just + at the moment. + + 9) It's free. + +A lot of the features in TeXit were inspired by features in AUC-TeX. Even +though AUC-TeX does most of these things, I find TeXit handy. For one thing, +my machine at home is way too slow to run AUC-TeX, but it runs TeXit pretty +well (after Perl finishes compiling it, anyway ;-). + +Lots of people have retreived it and I haven't had any complaints, so I +gather it works pretty well. + +Obviously, you have to have Perl installed on your system to use this script. +Perl is pretty cool in its own right, so I recommend you go out and get it +if you don't already have it. + +If you are interested in trying out TeXit, you can get it by anonymous ftp +from: ibis.cs.umass.edu:/pub/norm/tex/texit/*. + +If you try it, please let me know how you like it, or even if you like it. ;-) + + Be seeing you... + norm +--- +Norman Walsh | University of Massachusetts, Amherst, MA 01003 +<walsh@cs.umass.edu> | CMPSCI Dept., LGRC A210 | Standard disclaimer applies + + diff --git a/support/tex-it/chkscr.pl b/support/tex-it/chkscr.pl new file mode 100644 index 0000000000..b37c52f72a --- /dev/null +++ b/support/tex-it/chkscr.pl @@ -0,0 +1,42 @@ +#!/usr/local/bin/perl + +$prevline = ""; +@badlines = (); +$prevbad = 0; +while (<>) { + chop; + + push (@badlines, $_) if $prevbad; + $prevbad = 0; + next if /\s*#/; + next if /.*\}\s*$/; + next if /.*\{\s*$/; + next if /.*,\s*$/; + next if /^\s*$/; + + if (!/.*;\s*$/) { + push (@badlines, $_); + $prevbad = 1; + } +} + +$even = 0; +foreach $line (@badlines) { + if ($even) { + $ok = 0; + if ($line =~ /.*;\s*$/ && $line =~ /^\s*if/) { + $ok = 1; + } + if (! $ok) { + print "---\n"; + print $prevline, "\n"; + print $line, "\n"; + } + + $even = 0; + } else { + $even = 1; + $prevline = $line; + } +} + diff --git a/support/tex-it/texit.pl b/support/tex-it/texit.pl new file mode 100644 index 0000000000..8c4c428e8a --- /dev/null +++ b/support/tex-it/texit.pl @@ -0,0 +1,2686 @@ +#! /usr/local/bin/perl -- # -*-Perl-*- + +######################################################################## +# TeXit: a Perl script for running TeX. +# +# Copyright (C) 1993 by Norman Walsh. <norm@ora.com> +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# Comments, questions, suggestions, and even flames welcome. +# +# See "display_usage" at the bottom of this file for information +# about how to use TeXit. +######################################################################## + +($VERSION = '$Revision: 1.36 $ ') =~ s/.*: (\d+.\d+).*/$1/; +print "This is TeXit v$VERSION. "; +print "Copyright (C) 1993 by Norman Walsh.\n"; + +($revision, $patchlevel) = &perl_version_info(); + +if ($revision lt "4.0.1.7" || + ($revision eq "4.0.1.7" && $patchlevel < 35)) { + print "***********************************", + "***********************************\n"; + print " WARNING: Your Perl is old. TeXit may or may not work.\n"; + print " In particular, options may not be interpreted correctly.\n"; + print "***********************************", + "***********************************\n"; +} + +######################################################################## +# Load standard library routines for handling abbreviations. I use +# this for the command line options. +# +require "abbrev.pl"; + +######################################################################## +# Initialize associative arrays of format information. +# +# &setup_format (common-name, printable-name, parser-name, format-name); +# +# Where: +# +# common-name : The (unique) internal (to TeXit) name of the format +# printable-name : What we tell the user this format is called +# parser-name : Which "parse_<parser-name>_log" routine gets called +# format-name : What is the '&<format-name>' filename of this format +# +&setup_format ("amslatex", "AMSLaTeX", "latex", "lplain", "" ); +&setup_format ("amstex", "AMSTeX", "default", "amstex", "" ); +&setup_format ("foiltex", "FoilTeX", "latex", "fltplain", "" ); +&setup_format ("lamstex", "LAMSTeX", "default", "lamstex", "" ); +&setup_format ("latex", "LaTeX", "latex", "lplain", "" ); +&setup_format ("lollipop", "Lollipop", "default", "lollipop", "" ); +&setup_format ("nfss2ltx", "LaTeX (NFSS2)", "latex", "nfss2ltx", "" ); +&setup_format ("plain", "Plain TeX", "default", "plain", "" ); +&setup_format ("slitex", "SliTeX", "latex", "splain", "" ); +&setup_format ("texinfo", "Texinfo", "texinfo", "plain", "" ); +&setup_format ("latex2e", "LaTeX2e", "latex", "latex2e", "2E" ); + +######################################################################## +# Global defaults. These should be set to reasonable values when the +# script is installed. The values below are reasonable for many Unix +# installations. +# +# To override these defaults, when TeXit begins, it loads each of the +# following files, if they exist: +# +# A system-wide init file (if configured to do so) +# ~/.texitrc (.texitrc in the users home directory) +# /path/.texitrc (/path is the path of the tex file being processed) +# foo (for each "-initfile foo" specified on the command line) +# +# They are loaded in that order and each can over-ride the values of +# the preceding. Or any of the defaults shown below: +# +$TEXITRC = ".texitrc"; # Filename for init files ~/.texitrc ... + +$DEFAULTFORMAT = "plain"; # Default format to use... +$DEFAULTLATEXFORMAT = "latex"; # Default LaTeX format to use... +$VERBOSE = 0; # Lots of messages... +$TEXITFASTEXIT = 1; # Empty line at prompt == quit +$ONCE = 0; # Run once, no prompting? (-once) +$GOTOMENU = 0; # Go right to menu? (-menu) +$CONFIRMPRINT = 1; # Ask before printing? +$CLEANONEXIT = 0; # Cleanup automatically on exit? +$CLEANPROMPT = 1; # Should we ask first? (-clean) +$SETXTITLE = 0; # Should we alter the X11 title/icon name? + +%DEPENDSON = (); # what does the DVI file depend on? + +%WARNINGS = (); # are there any warnings parse_<format>_log + # didn't recognize? +%DEFAULTCMD = (); # no default commands +%AUTOCMD = (); # no automatic commands +$AUTOMAX = 1; # how many automatic commands can occur + # in a row? + +$TEXERROR = 1; # Return code from TEX that indicates an + # an error. Under emTeX, make this 2. + # emTeX returns 1 for overfull boxes, etc. + # which arent really errors. +$ERRORLINE = 0; # What line did the TeX error occur on... +$ERRORFILE = ""; # What file was being processed... +%Parens = (); +$ParenLevel = 0; + +$ENV_TEXINPUTS = "TEXINPUTS"; # Name of TEXINPUTS environment variable +$ENV_BIBINPUTS = "BIBINPUTS"; # Name of BIBINPUTS environment variable +$ENV_TEXFMTS = "TEXFORMATS";# Name of TEXFORMATS environment variable + +$TEXRETRIES = 4; # How many retries before we give up? + +$TEXHEADERSIZE = 20; # number of lines at the top of each + # document that TeXit searches for + # formatting clues. + +$QuitReply = "e[x]it"; # To leave TeXit +$TeXReply = "[t]ex"; # To run TeX +$CleanupReply = "[c]leanup"; # To cleanup files +$BibTeXReply = "[b]ibtex"; # To run BibTeX +$GhostviewReply= "[g]hostview";# To run Ghostview +$PrintReply = "[p]rint"; # To print +$ViewReply = "[v]iew"; # To view +$StatusReply = "[?]status"; # To get a status report from TeXit + +$TEX = "virtex"; # TeX, the program +$BIBTEX = "bibtex"; # BibTeX +$MAKEINDEX = "makeindex"; # MakeIndex +$VIEW = "xdvi"; # A previewer +$GSVIEW = "ghostview"; # Ghostview, another previewer + +# The following commands are used to run each of the above programs. +# See the 'run' subroutine for a description of the %-variable +# substitution that is performed. Also, note that Perl $VARIABLE +# substitution is performed too. +# +# The $TEXCMDs are stored in an associative array because not all +# format files can be run with the same command line. +# +$TEXCMD{"default"} = '$TEX "%F %o \\input{%t}"'; +$TEXCMD{"plain"} = '$TEX "%F %o \\input %t"'; +$TEXCMD{"texinfo"} = '$TEX "%F %o \\input %t"'; +$BIBTEXCMD = '$BIBTEX %o %s'; +$MAKEINDEXCMD = '$MAKEINDEX %o %s'; +$VIEWCMD = '$VIEW %o %d'; +$GSVIEWCMD = '$GSVIEW %o %s.ps'; + +# Default options for each of the above commands. These options +# are _always_ used (where %o occurs in the command) if they are +# set, so choose wisely. They come before any additional options +# specified at the TeXit prompt. +# +$TEXOPTS{"default"} = ""; +$BIBTEXOPTS = ""; +$MAKEINDEXOPTS = ""; +$VIEWOPTS = ""; +$GSVIEWOPTS = ""; + +######################################################################## +# Printer initialization. It works like this: the user selects a +# printer queue "Q". Then $PRQUEUE{"Q"} determines the printer _type_. +# Ordinarily, the user never knows about the type, but it is used +# to lookup the DVI driver and printer commands. In particular: +# +# $PRQUEUE{"Q"} = "TYPE" +# +# $DVICMD{"TYPE"} = DVI driver command (with substitutions) +# $DVIOPT{"TYPE"} = Default options for driver +# $DVIQUERY{"TYPE"} = Ask for additional DVI options? +# If $DVIQUERY{"TYPE"} is defined, TeXit will ask +# the user for additional dvi driver options (using +# the value of $DVIQUERY{"TYPE"} as the prompt). +# These options are added to any options entered +# at the prompt. +# +# $PRINTCMD{"Q"} = How to print resulting file (with substitution) +# $PRINTOPT{"Q"} = Default options for driver +# $PRINTQUERY{"Q"} = Ask for additional printer options? See above. +# $PRINTCONFIRM{"Q"}= Yes or No? Overrides $CONFIRMPRINT... +# +# Ordinarily, all of the above variables should be set for each queue +# and it is an error for them to be unset. However, the following +# exception is made: if the $PRINTCMD{"Q"} isn't set, then the file +# is run through a DVI driver but is not printed. +# +# Note: Ghostview is implemented this way, but it is also hard coded +# later on as an option in it's own right because we can be a little +# more intelligent about it. +# +# It would clearly have been possible to do configuration in other +# ways, in particular by using a single print command with different +# printer options ("lpr -P%p" for example). But that has disadvantages +# too and it doesn't save much time or space. +# +$PRQUEUE{"Local"} = "ps"; # A 'local' printer +$PRQUEUE{"File"} = "ps"; # Just save the PS file +$PRQUEUE{"ghostview"} = "ps"; # Ghostview + +$PRINTCMD{"Local"} = 'lpr %o %s.ps'; +$PRINTOPT{"Local"} = ""; + +$PRINTCMD{"File"} = ""; +$PRINTOPT{"File"} = ""; + +$PRINTCMD{"ghostview"} = '$GSVIEW %o %s.ps'; +$PRINTOPT{"ghostview"} = ""; + +$DVICMD{"ps"} = 'dvips %o %d'; +$DVIOPT{"ps"} = ""; + +######################################################################## +# The $CleanupReply option looks for a list of files to delete in the +# list "@cleanup_files". These are usually set by perl commands in the +# document since there aren't any default _files_ to delete. +# +# It also looks for a list of extensions in the list "@cleanup_<format>" +# If the file <texbasefile>.<ext> exists, it is deleted during cleanup +# +@cleanup_files = (); +@cleanup_plain = ('log'); +@cleanup_texinfo = ('log', 'aux', 'cp','fn','ky','pg','toc','tp','vr'); +@cleanup_latex = ('log', 'aux', 'blg', 'ilg', 'lot', 'lof', 'toc'); +@cleanup_nfss2ltx = ('log', 'aux', 'blg', 'ilg', 'lot', 'lof', 'toc'); +@cleanup_latex2e = ('log', 'aux', 'blg', 'ilg', 'lot', 'lof', 'toc'); + +######################################################################## +# The system default, user default, and directory default initfiles +# have to be kept around until we're ready to load them. That's what +# the @TEXITINIT list is for. Ordinarily this is initialized empty. +# But if you always want to load a system-wide init file, perhaps +# "/usr/local/lib/texitrc" then you can initialize TEXITINIT to +# include that file. +# +@TEXITINIT = (); + +# Unfortunately, we want to run the system default files before the +# files specified with -initfile on the command line, but we don't +# find out what the name of the directory default is until after we've +# parsed the command line. To circumvent this problem, we store +# initfiles from the command line in a seperate array. +# +@TEXITCMDLINE = (); # leave this empty + +######################################################################## +# Locate the user-default init file and store it on the TEXITINIT list. +# Some installations might not have a HOME environment variable to +# contain the home directory, so we let them specify a TEXIT env. var. +# instead. +# +$_ = $ENV{"TEXIT"}; +$_ = $ENV{"HOME"} if $_ eq ""; +$_ .= "/" if $_ && $_ !~ /.*\/$/; +$texitrc = $_ . $TEXITRC; +print "Looking for user-init file: $texitrc\n" if $VERBOSE; +unshift(@TEXITINIT, $texitrc) if -r $texitrc; + +######################################################################## +# make STDOUT unbuffered so we can print messages w/o newlines in them +# +select(STDOUT); $| = 1; + +######################################################################## +# Get ready to parse the arguments... +# +# The associative array "cmdlineopts" is built to hold all of the +# possible, unambiguous command line options. It will later be used +# to get back the full name (i.e. $cmdlineopts{"ini"} = "initfile"). +# +{ + local (@formatlist) = keys (%format); + %cmdlineopts = (); + &abbrev (*cmdlineopts, + 'initfile', 'verbose', 'once', 'menu', 'clean', + 'bibtex', 'makeindex', 'tex', + @formatlist); +} + +# Build the case statement for parsing the options. This code builds +# an associative array and 'eval's it to get the cases. It's a little +# obscure, but it works. +# +# If a valid option is not found in the case statement, it is assumed +# to be the name of a format file. This saves a whole bunch of cases. +# Note: the lines inbetween &case and ENDCASE _are not_ evaluated +# by the Perl compiler at compile time...they are 'eval'ed at runtime. +# +&case (*casefoo,<<'ENDCASE'); + initfile $texitrc = $ARGV[0] || "no file"; shift; + verbose $VERBOSE = 1; + once $ONCE = 1; + menu $GOTOMENU = 1; + clean $CLEANPROMPT = 0; + tex $runtexfirst = 1; + bibtex $runbibtexfirst = 1; + makeindex $runmakeindexfirst = 1; +ENDCASE + +# make sure a few things are undefined +undef ($TEXFORMAT); +undef ($texitrc); +undef ($runtexfirst); +undef ($runbibtexfirst); +undef ($runmakeindexfirst); + +# Now look at the arguments, keep scanning through them as long as +# they begin with a hyphen. Anything after that has to be a filename +# +while ($ARGV[0] =~ /^-(.*)/ && shift) { + ($option = $1) =~ tr/A-Z/a-z/; + $option = $cmdlineopts{$option}; # find long opt + die "Unrecognized or ambiguous option: -$1.\n" + if $option eq ""; + + if (defined($casefoo{$option})) { + # Ok, it's one of the arms of the case statement + eval $casefoo{$option}; + if (defined($texitrc)) { + # The only arm that isn't self-contained is the -initfile arm. + # For that option, we have to check for the initfile and save + # it for later. + die "You forgot the file name after \"-$1\".\n" + if $texitrc eq "no file"; + + die "Initfile does not exist: $texitrc\n" + if ! -r $texitrc; + + print "Looking for -initfile: $texitrc\n" if $VERBOSE; + unshift(@TEXITCMDLINE, $texitrc); + undef ($texitrc); + } + } else { + # It's not one of the arms of the case, so it must be a format. + $TEXFORMAT = $option; + } +} + +######################################################################## +# What's left on the command line must be the name of the file that +# contains the document to process. Anything else must be options to +# TeX. Make sure they begin with an escape (you can put \relax +# in front if you need to). Note: this verifies that the user +# escaped the shell command line correctly. +# +$texfile = $ARGV[0] || &display_usage(); # display_usage doesn't return +shift; + +if (defined($ARGV[0])) { + local ($texescape, $printescape); + $texescape = "\\\\"; + $texescape = "@" if $TEXFORMAT eq "texinfo"; + eval "\$printescape = \"$texescape\""; + if ($ARGV[0] !~ /^$texescape.*/) { + print "TeX options must begin with a \"$printescape\". "; + die "Use ${printescape}relax if necessary.\n"; + } + + $CMDLINEOPTS = join (" ", @ARGV); +} + +######################################################################## +# Locate the requested TeX file. It's either in the current (or +# specified) directory or no path was specified and it's on the +# TEXINPUTS path. +# +$qualifiedtexfile = &cleanup_texfilename($texfile); +if (! -e $qualifiedtexfile) { + if ($texfile !~ /[\/\\]/) { # no path... + $qualifiedtexfile = &find_on_path("$ENV{$ENV_TEXINPUTS}", + "$texfile"); + $qualifiedtexfile = &find_on_path("$ENV{$ENV_TEXINPUTS}", + "$texfile" . ".tex") + if $qualifiedtexfile eq ""; + + die "Cannot find \"$texfile[.tex]\" on $ENV_TEXINPUTS path.\n" + if $qualifiedtexfile eq ""; + + $texfile = $qualifiedtexfile; + } else { + die "Cannot find \"$texfile[.tex]\".\n"; + } +} else { + $texfile = $qualifiedtexfile; +} + +######################################################################## +# Maybe the file has an emacs-style "local variables" definition that +# describes the file. Here, we only care about the local variables +# "TeX-master" and "mode". These are the same variables AUC-TeX uses. +# The TeX-master file means that _this_ file is some sub-part of a +# larger document. The larger document is pointed to by TeX-master. +# The "mode" is what format this is in (Plain TeX, LaTeX, ... etc.) +# +# Alternatively, if you don't use Emacs, you can get the same logic +# out of TeXit by putting: +# +# % Master: file +# % Mode: format % or Format: format +# +# somewhere near the top (within the first $TEXHEADERSIZE lines) of +# your document. In this case, the line must begin with a percent +# sign and there must be nothing else on the line. The Master: and +# Mode: commands must each appear on a line of their own. If you +# specify both a Master: and a TeX-master in the local variables, the +# TeX-master will win (simply because it comes later in the file). +# The same goes for mode:. +# +# Other than that, TeXit tries to be smart about what format to use, +# looking for things that are clues to the format. Unfortunately, +# TeXit is easy to fool, so you may need a -<format> on the command +# line sometimes. +# +&get_local_vars ($texfile); + +# If this file has a master, load the local vars from the master file +# as well...these override variables from the initial file, but that's +# probably for the best anyway... +# +# TeX-master = "t" is special, it means _this_ file is the master file +# (i.e. it's `true' that this is the master file). +# +# If there isn't a master file, then $texfile is the master. +# +$texmaster = $texvars{"TeX-master"}; +if (defined($texmaster) && $texmaster ne "t") { + $texmaster = &cleanup_texfilename($texmaster); + print "Processing $texfile ... superceded by master file.\n"; + die "Cannot read master file: $texmaster" if (! -r $texmaster); + &get_local_vars ($texmaster); +} else { + $texmaster = $texfile; +} + +if ($texvars{"mode"} eq "") { + if ($TEXFORMAT eq "") { + print "\nI can't figure out what format this file uses, ", + "and you didn't say, so \nI'm going to guess that ", + "it's a \"$formatname{$DEFAULTFORMAT}\" file. Use ", + "the \"-format\" \noption if this is a bad guess.\n\n"; + + $texvars{"mode"} = $DEFAULTFORMAT; + } else { + $texvars{"mode"} = $TEXFORMAT; + } +} + +######################################################################## +# Split the master filename up into a path, name, and extension +# +($TEXFILEPATH,$TEXFILENAME,$TEXFILEEXT) = &splitfn($texmaster,".tex"); +$DEPENDSON{$texmaster} = 1; + +######################################################################## +# Build up the default array of commands. +# +# Prompt with "key" if $CMDPROMPT{key} exists and the test $CMDTEST{key} +# succeeds. A null test succeeds by default. The string enclosed in +# square brackets in the key is what the user has to enter to select +# that option. +# +# TeXit `eval's $CMDPROMPT{key} if the user selects the option "key". +# +# Use single quotes when building the command to be evaluated _and_ +# the test so that $VAR substitution isn't performed prematurely! +# +# The commands to run tex, cleanup the directory, and quit are used +# elsewhere. Change the definitions of $xxxReply to make them different. +# But don't change what they _mean_!!! +# + +$RETEX = "last ASKLOOP"; +$REASK = "next ASKLOOP"; + +$CMDPROMPT{$TeXReply} = '$RETEX'; +$CMDPROMPT{$CleanupReply} = '&cleanup("$opts"); $REASK'; +$CMDPROMPT{$QuitReply} = 'print "Thank you for using TeXit!\n\n";exit(0)'; +$CMDPROMPT{$StatusReply} = '&showstatus("$opts"); $REASK'; + +$CMDTEST{$TeXReply} = ''; +$CMDTEST{$CleanupReply} = '&files_to_cleanup()'; +$CMDTEST{$QuitReply} = ''; +$CMDTEST{$StatusReply} = ''; + +# It would be ok to change these... +# +$CMDPROMPT{$BibTeXReply} = '&bibtexcmd("$opts"); $RETEX'; +$CMDPROMPT{$GhostviewReply} = '&ghostviewcmd("$opts"); $REASK'; +$CMDPROMPT{$PrintReply} = '&printcmd("$opts"); $REASK'; +$CMDPROMPT{$ViewReply} = '&viewcmd("$opts"); $REASK'; + +$CMDTEST{$BibTeXReply} = '"$BIBTEX" && -r &auxfile("aux")'; +$CMDTEST{$GhostviewReply} = '"$GSVIEW" && -r &auxfile("dvi")'; +$CMDTEST{$PrintReply} = '"%PRQUEUE" && -r &auxfile("dvi")'; +$CMDTEST{$ViewReply} = '"$VIEW" && -r &auxfile("dvi")'; + +######################################################################## +# Look for a directory-local init file. Then load all the init files +# that we've found. Load the global one, then the user-global one, +# then the directory-local one then all the user specified ones, in +# order. +# +# Note: init files are just bits of Perl code so they can really do +# anything you want. But they have to be legal Perl. Usually they +# just set some global vars. +# +# Yes, "require_hack" is ugly. But read the comments in that routine +# and you'll see why it was necessary. +# +$texitrc = $TEXFILEPATH . $TEXITRC; +print "Looking for local init file: $texitrc\n" if $VERBOSE; +unshift (@TEXITINIT, $texitrc) if -r $texitrc; + +while (@TEXITINIT) { + $texitrc = pop(@TEXITINIT); + if (-r $texitrc) { + &require_hack ($texitrc); + } else { + warn "Can't read initfile: $texitrc\n"; + } +} + +while (@TEXITCMDLINE) { + $texitrc = pop(@TEXITCMDLINE); + if (-r $texitrc) { + &require_hack ($texitrc); + } else { + warn "Can't read initfile: $texitrc\n"; + } +} + +undef($texitrc); + +######################################################################## +# Now that all the initialization code has been run, build up an +# abbreviation list for the printer queues. +# +{ + local ($queue,@prlist); + + foreach $queue (keys %PRQUEUE) { + unshift(@prlist, $queue); + } + + %pr_queue_names = (); + &abbrev (*pr_queue_names, @prlist); +} + +######################################################################## +# Pick a format. Tell the user if we don't agree about the format +# they demanded. Shift the format to lowercase for using as a key in +# the %format associative array. +# +# Bail out if we can't find the format in the %format. +# +print "Processing $TEXFILEPATH$TEXFILENAME.$TEXFILEEXT ... "; +if ($TEXFORMAT ne "" && $TEXFORMAT ne $texvars{"mode"}) { + print "it looks like a $formatname{$texvars{mode}} file to me,\n"; + print "but you said it was a $formatname{$TEXFORMAT} file. "; + print "Suit yourself.\n"; +} elsif ($TEXFORMAT eq "") { + print "it looks like a $formatname{$texvars{mode}} file to me.\n"; + if ($texvars{"mode"} eq "latex" && $DEFAULTLATEXFORMAT) { + $TEXFORMAT = $DEFAULTLATEXFORMAT; + print "(Using $formatname{$TEXFORMAT} variant of LaTeX.)\n"; + } +} else { + print "using $formatname{$TEXFORMAT}, like you said.\n"; +} + +$TEXFORMAT = $texvars{"mode"} if $TEXFORMAT eq ""; +$TEXFORMAT =~ tr/A-Z/a-z/; + +die "Don't know what format file to use for \"$TEXFORMAT\".\n" + if $format{$TEXFORMAT} eq ""; + +######################################################################## +# Let's make sure we can process this format... +# +{ + local ($path) = $ENV{$ENV_TEXFMTS} || "/usr/local/lib/tex/formats"; + local ($formatfile) = $format{$TEXFORMAT} . ".fmt"; + local ($formatpath) = &find_on_path($path, $formatfile); + + if ($formatpath eq "") { + print "\nCan't find the format file for "; + print "$formatname{$TEXFORMAT} on the $ENV_TEXFMTS path.\n"; + die "Can't continue without \"$formatfile\".\n"; + } +} + +# If the user has specified an alternate inputs environment for this +# format, temporarily set the environment for TeX... +if ($altinputenv{$TEXFORMAT} + && $ENV{"$ENV_TEXINPUTS$altinputenv{$TEXFORMAT}"}) { + $ENV{"$ENV_TEXINPUTS"} = $ENV{"$ENV_TEXINPUTS$altinputenv{$TEXFORMAT}"}; + print "Adjusting $ENV_TEXINPUTS environment variable for this format.\n"; +} + +######################################################################## +# Evaluate the PLC commands for this document. +# +# PLC commands are bits of Perl that usually look something like this: +# +# % &makeindex('-o driver.ind driver.idx') +# % if &missing('driver.ind') || &changed('driver.idx'); +# % &bibtex('driver') if &newer('jigsaw.bib','driver.bbl'); +# +# This says run MakeIndex if "driver.ind" is missing or "driver.idx" +# changes over the course of a TeX run. And run BibTeX if the +# bibliography file is newer than the BBL file (it'll also get run +# automatically if any citations are unresolved). +# +# $first_time is true now so that &missing, &dependson, &changed, and +# &newer all return false regardless of the condition tested. This +# way we can initialize some globals before we run TeX for the first +# time (to see if files change on the first run, for example). +# +# VERBOSE is forced off temporarily so that no stupid messages are +# printed, even if the user wants them. Note the dynamic scoping +# nature of Perl. +# + +{ + local ($VERBOSE) = 0; + local ($first_time) = 1; + local ($line, @the_rules); + + @the_rules = @default_rules; + foreach $line (@the_rules) { + eval $line; + die "Invalid rule in \@default_rules: $line\n" if $@; + } + + eval "\@the_rules = \@${TEXFORMAT}_rules"; + foreach $line (@the_rules) { + eval $line; + die "Invalid rule in \@${TEXFORMAT}_rules: $line\n" if $@; + } + + foreach $line (@PLCRULES) { + eval $line; + die "Invalid PLC rule: $line\n" if $@; + } +} + +{ + # Now print out the rules, if the user wants to see them... + + local ($line, @the_rules); + + if ($VERBOSE && @default_rules) { + print "Default rules:\n"; + foreach $line (@default_rules) { + print " $line\n"; + } + print "\n"; + } + + eval "\@the_rules = \@${TEXFORMAT}_rules"; + if ($VERBOSE && @the_rules) { + print "$TEXFORMAT rules:\n"; + foreach $line (@the_rules) { + print " $line\n"; + } + print "\n"; + } + + if ($VERBOSE && @PLCRULES) { + print "Your document defined the following rules:\n"; + foreach $line (@PLCRULES) { + print " $line\n"; + } + print "\n"; + } +} + +######################################################################## +# If the user asked us to run MakeIndex or BibTeX first, run them now. +# +if ($runbibtexfirst) { + if (-r &auxfile("aux")) { + &bibtexcmd(""); + } else { + print "There's no AUX file to run BibTeX against.\n"; + } +} +undef($runbibtexfirst); + +if ($runmakeindexfirst) { + if (-r &auxfile("idx")) { + &makeindexcmd(""); + } else { + print "There's no IDX file to run MakeIndex against.\n"; + } +} +undef($runmakeindexfirst); + +######################################################################## +# Ok, now it's time to run TeX. Run TeX repeatedly until an error +# occurs, the dependencies don't change or we've tried more than four +# times. If it doesn't work in four tries, it never will. +# +$opts = ""; # user specified options after the prompt +$changed = 0; # did the file change on this run? +$runcount = 0; # how many times have we run TeX in a row? + +# Think about BibTeX: every time we run it, it changes the BBL file and +# potentially causes us to decide to run TeX again. But if the list of +# missing citations doesn't change after the first run, running again +# won't help. So we keep track of the missing citations between runs +# and only run BibTeX when it changes. +# +%missingcites = (); # last missing cite list + +# If not -menu, assume we'll TeX first... +# +$changed = !$GOTOMENU; + +# If the tex file and the dvi file and the log file all exist, maybe +# we don't actually have to run TeX first...maybe the user just wants +# to print or preview or something and they're used to typing "texit". +# +if (!$GOTOMENU && !$runtexfirst) { # if the user doesn't insist... + $changed = &dependencies_changed () + if (-r $texmaster && -r &auxfile("dvi") && -r &auxfile("log")); + %missingcites = (); # the results from an old log don't count +} +undef($runtexfirst); + +$autocount = 0; # No automatic commands yet... +$lastcmd = $TeXReply; # assume we ran tex... +TEXLOOP: for(;;) { # don't stop till the user says quit. + if ($changed) { + $ERRORLINE = 0; # No errors occurred... + $ERRORFILE = ""; # + $rc = &texcmd($opts); # run TeX + # If the return code is less than TEXERROR, set it to zero. + # This canonicalizes the test for success when running a program + $rc = 0 if $rc < $TEXERROR; + + # 9 Sep 93: the former test at this location failed to handle + # a document that _required_ four tries to process correctly. + $changed = 0; + $changed = 1 if $rc == 0 && &dependencies_changed (); + next TEXLOOP if $changed && $runcount < $TEXRETRIES; + } else { + $rc = 0; + } + + if ($rc != 0) { + warn "TeX failed. All bets are off.\n\n"; + ($ERRORFILE, $ERRORLINE) = &find_error_line(); + } + + if ($runcount >= $TEXRETRIES && $changed) { + print "\nI've tried $TEXRETRIES times and it still "; + print "isn't right...I give up.\n\n"; + exit 1 if $ONCE; + } else { + if ($ONCE) { + &cleanup("") if $CLEANONEXIT && !$CLEANPROMPT && !$rc; + exit $rc; + } + } + + $changed = 1; # assume it'll change before we get back to top... + + ASKLOOP: for (;;) { + # User can change anything while we're sitting at the prompt, so + # reset runcount and citation list. + $runcount = 0; + %missingcites = (); + + &set_x_titles("TeXit"); + + if ($rc == 0 + && $AUTOCMD{$lastcmd} ne "" + && $CMDPROMPT{$AUTOCMD{$lastcmd}} ne "" + && $autocount < $AUTOMAX) { + $cmd = $AUTOCMD{$lastcmd}; + $opts = ""; + $autocount++; + } else { + $rc = 0; + $autocount = 0; + ($cmd, $opts) = &get_command(); + } + + if ($cmd eq "") { + $cmd = $QuitReply; + $cmd = $DEFAULTCMD{$lastcmd} if $DEFAULTCMD{$lastcmd} ne ""; + $cmd = "redo" if !$TEXITFASTEXIT && $DEFAULTCMD{$lastcmd} eq ""; + + # Unless the last thing we did was cleanup, re-running TeX + # supercedes other commands if the DVI file is gone or any + # dependent files are newer... + if ($lastcmd ne $CleanupReply) { + if (! -r &auxfile("dvi")) { + print "\n", &auxfile("dvi"), " disappeared.\n"; + $cmd = $TeXReply; + } elsif (&dependent_files_are_newer()) { + print "\nA file that the document ", + "depends on has changed.\n"; + $cmd = $TeXReply; + } + } + } + + next if $cmd eq "redo"; + + # Special case for $QuitReply if CLEANONEXIT is true: + # + if ($cmd eq $QuitReply && $CLEANONEXIT) { + $AUTOCMD{$CleanupReply} = $QuitReply; # exit w/o asking next + $CLEANONEXIT = 0; # Prevent reexecution of this code... + $cmd = $CleanupReply; + $opts = ""; + } + + if (($cmd eq $QuitReply) && $SETXTITLE) { + local ($host, $cwd); + chop($host = `hostname`); + chop($cwd = `pwd`); + &set_xterm_title("$host: $cwd"); + &set_xicon_title("$host"); + } + + $lastcmd = $cmd; + + # Ok, now it's time to 'eval' the command. + # + # First, copy it and protect any quotations in it from premature + # replacement. Note: the user has to protect backslashes by + # escaping them (i.e. in order to get "\" use "\\"). This is + # necessary so that the user can use a backslash to protect + # dollar signs for variable assignment. + # + # Then eval it once to do $-var substitution. + # + # Then eval it again to really do the work... + # + $thecmd = $CMDPROMPT{$cmd}; + $thecmd =~ s/\"/\\"/g; # protect double quotes + eval "\$thecmd = \"$thecmd\""; + eval ( $thecmd ); + die "Invalid command defined for $cmd: $CMDPROMPT{$cmd}\n" if $@; + } +} + +######################################################################## +# These subroutines execute the expected commands. They are here, with +# nice names, so that the PLC commands can use them and be easy to read. +# Internally, different routines are used so that %-var substitution is +# preformed. Note that it _isn't_ preformed here. +# +# &tex("foo") ==> $TEX foo +# +sub tex { + local ($opts) = @_; + local ($exopts); + + $exopts = join(" ",$TEXOPTS{$TEXFORMAT},$CMDLINEOPTS,$opts); + + &run($TEX . $exopts, ""); +} + +sub bibtex { + local ($opts) = @_; + + &run($BIBTEX . " " . $BIBTEXOPTS . " " . $opts, ""); +} + +sub makeindex { + local ($opts) = @_; + + &run($MAKEINDEX . " " . $MAKEINDEXOPTS . " " . $opts, ""); +} + +######################################################################## +# These are the subroutines used internally where all we want to pass +# in are the _additional_ options. +# +# &texcmd("foo") => $TEXCMD with $TEXOPTS and "foo" inserted as options +# and all other %-var substitution performed. +# +sub texcmd { + local ($opts) = @_; + local ($rc, $extex, $exopt); + + $extex = $TEXCMD{"default"}; + $extex = $TEXCMD{$TEXFORMAT} if $TEXCMD{$TEXFORMAT} ne ""; + $exopt = join (" ", $TEXOPTS{$TEXFORMAT}, $CMDLINEOPTS, $opts); + + $rc = &run ($extex, $exopt); + $runcount++; + $rc; +} + +sub bibtexcmd { + local ($opts) = @_; + local ($rc); + + if (! -r &auxfile("aux")) { + print "Cannot run BibTeX, no AUX file." if $VERBOSE; + $rc = -1; + } else { + $rc = &run ($BIBTEXCMD, $BIBTEXOPTS . " " . $opts); + } + + $rc; +} + +sub makeindexcmd { + local ($opts) = @_; + + &run($MAKEINDEXCMD, $MAKEINDEXOPTS . " " . $opts); +} + +sub viewcmd { + local ($opts) = @_; + + &run ($VIEWCMD, $VIEWOPTS . " " . $opts); +} + +sub printcmd { + local ($opts) = @_; + local ($queueopt, $dviuseropts, $prtuseropts); + local ($rc, $type); + local ($dvicmd, $dviopt, $prtcmd, $prtopt); + local ($doit,$queue); + local ($confirm) = $CONFIRMPRINT; + + $queueopt = ""; + + # parse the user-specified options for a printer queue and options + if ($opts =~ /^\s*(\S+)\s*(.*)$/) { + $queueopt = $1; + $opts = $2; + } + + # if the queue name starts with "-" or "/", assume that it's an option, + # not a queue name... + if ($queueopt =~ /^(-|\/)/) { + $opts = "$queueopt $opts"; + $queueopt = ""; + } + + # if no queue is specified, use the default printer queue + $queueopt = $DEFAULT_PRINTER if $queueopt eq ""; + + if ($queueopt eq "") { + print "You must specify a printer queue (use \"p <printer>\").\n"; + return(0); + } + + # Special case, if the queue is "?", list the queues we know about. + if ($queueopt eq "?") { + &print_long_list("\nThe following queues are available: ", + sort(keys(%PRQUEUE))); + print "\n"; + return (0); + } + + $queue = $pr_queue_names{$queueopt}; + + if (!defined ($PRQUEUE{$queue})) { + warn "There is no printer queue named \"$queueopt\".\n"; + return 0; + } + + ($dviuseropts, $prtuseropts) = split (/\|/, $opts); + + $type = $PRQUEUE{$queue}; + + if (!defined ($DVICMD{$type})) { + warn "There is no DVI driver for \"$type\" printers.\n"; + return 0; + } + + $dvicmd = $DVICMD{$type}; + $dviopt = $DVIOPT{$type}; + + if ($DVIQUERY{$type} ne "") { + print $DVIQUERY{$type}; + $_ = scalar (<STDIN>); + $dviuseropts .= " " . $_; + } + + $prtcmd = $PRINTCMD{$queue}; + $prtopt = $PRINTOPT{$queue}; + + $rc = &run ($dvicmd, $dviopt . " " . $dviuseropts); + + warn "DVI driver failed.\n" if $rc; + + $doit = ($prtcmd ne ""); # really print it... + + if (defined($PRINTCONFIRM{$queue})) { + undef $confirm; + $confirm = 0 if "0" =~ /^$PRINTCONFIRM{$queue}/i; + $confirm = 0 if "no" =~ /^$PRINTCONFIRM{$queue}/i; + $confirm = 0 if "false" =~ /^$PRINTCONFIRM{$queue}/i; + $confirm = 1 if "1" =~ /^$PRINTCONFIRM{$queue}/i; + $confirm = 1 if "yes" =~ /^$PRINTCONFIRM{$queue}/i; + $confirm = 1 if "true" =~ /^$PRINTCONFIRM{$queue}/i; + if (! defined($confirm)) { + print "\nI don't know what `$PRINTCONFIRM{$queue}' means, "; + print "I'll assume that it means "; + print "`yes'.\n" if $CONFIRMPRINT; + print "`no'.\n" if !$CONFIRMPRINT; + $confirm = $CONFIRMPRINT; + } + } + + # Wait! If the driver failed or there's a queue other than + # Ghostview selected, ask and make sure. + # + if ($rc || ($doit && ($queue ne "ghostview") && $confirm)) { + print "Really print to $queue? "; + $_ = scalar (<STDIN>); chop; + $doit = 0 if !/^y/i; + } + + if ($doit) { + if ($PRINTQUERY{$queue} ne "") { + print $PRINTQUERY{$queue}; + $_ = scalar (<STDIN>); + $prtuseropts .= " " . $_; + } + $rc = &run ($prtcmd, $prtopt . " " . $prtuseropts); + } else { + print "Print command aborted.\n" if ($prtcmd ne ""); + $rc = -1; + } + + $rc; +} + +######################################################################## +# Ghostview is a little special. The print commands always have to +# run the DVI driver because they don't know what kind of file might +# be produced, but with Ghostview, we know that it'll be the master +# document name with '.ps' on the end. So, if that exists and is +# newer than the DVI file, don't bother running the DVI driver again. +# +# Note also that Ghostview knows what type it is, so the type doesn't +# have to be in the printer queue. This means you can remove the +# Ghostview printer from the queue list even if you don't have any +# other PS printers. +# +# Oh, also, we always run the DVI driver again if the user entered +# DVI driver options at the prompt... +# +sub ghostviewcmd { + local ($opts) = @_; + local ($queue, $dviuseropts, $prtuseropts); + local ($rc, $type); + local ($dvicmd, $dviopt, $prtcmd, $prtopt); + local ($doit); + local ($psfile) = &auxfile("ps"); + + ($dviuseropts, $prtuseropts) = split (/\|/, $opts); + + $type = "ps"; + + if (!defined ($DVICMD{$type})) { + warn "There is no DVI driver for \"$type\" output.\n"; + return 0; + } + + $dvicmd = $DVICMD{$type}; + $dviopt = $DVIOPT{$type}; + + if ((! -r $psfile || (&mtime($psfile) < &mtime(&auxfile("dvi")))) + || $dviuseropts ne "") { + $rc = &run ($dvicmd, $dviopt . " " . $dviuseropts); + } else { + print "\nPostScript file already exists.\n"; + $rc = 0; + } + + $doit = 1; + if ($rc) { + warn "DVI driver failed.\n"; + print "Preview anyway? "; + $_ = scalar (<STDIN>); chop; + $doit = 1 if /^y/i; + } + + if ($doit) { + $rc = &run ($GSVIEWCMD, $GSVIEWOPTS . " " . $prtuseropts); + } + + $rc; +} + +######################################################################## +# Add new files to the @cleanup_files array. This call makes sure that +# duplicate filenames are not added. It simplifies the TeXit rules +# for extending the list of files to clean up. Simply saying: +# +# push(@cleanup_files, 'one', 'two'); +# +# is a bad idea because it'll add "one" and "two" each time the document +# is processed. On the other hand, expecting users to type the rule: +# +# push(@cleanup_files, 'one', 'two') if $first_time; +# +# is unrealistic. So now they can just call cleanup_files... +# +sub cleanup_files { + local (@newfiles) = @_; + local ($file, $files, $newfile, $add); + + $add = 1; + foreach $newfile (@newfiles) { + foreach $file (@cleanup_files) { + $add = 0; + last if $file eq $newfile; + $add = 1; + } + push (@cleanup_files, $newfile) if ($add); + } +} + +######################################################################## +# Go out there and find all the files that have to be cleaned up. +# Return them in a list. +# +sub files_to_cleanup { + local ($opts) = @_; + local (%thefiles); + local ($file, @filelist, $ext, @extlist); + + @filelist = (); + + # throw them all in an associative array first to + # avoid duplicates. + foreach $file (@cleanup_files) { + $file =~ s/\\/\//; # \ -> / + $file = $TEXFILEPATH . $file if $file !~ /\//; + $thefiles{$file} = 1; + } + + # find the list of extensions in "@cleanup_<format>". + eval "\@extlist = \@cleanup_$TEXFORMAT"; + if (@extlist) { + local ($file); + foreach $ext (@extlist) { + $file = &auxfile($ext); + $thefiles{$file} = 1; + } + } + + # now put them in a regular array + foreach $file (keys %thefiles) { + if (-e $file) { + unshift(@filelist, $file); + } + } + + # return that array + + @filelist; +} + +######################################################################## +# Delete any files that have to be cleaned up... +# +sub cleanup { + local ($opts) = @_; + local (@filelist, $_); + + @filelist = &files_to_cleanup(); + + # if there are any files to be deleted, ask the user to confirm + # and then blow 'em away... + if (@filelist) { + &print_long_list ("\nDelete: ", sort @filelist); + print "\n"; + if ($CLEANPROMPT) { + print "Really delete these files? "; + $_ = scalar (<STDIN>); chop; + } else { + $_ = "yes"; + } + + if (/^y/i) { + print "\n", unlink(@filelist), " files deleted.\n"; + } else { + print "\nCleanup aborted.\n"; + } + + print "\n"; + } +} + +######################################################################## +# The workhorse. This routine takes a command string and an options +# string. The command string is subjected to the following +# interpolation: +# +# IN ORDER TO HANDLE SOME TEX WEIRDNESS WITH FILENAMES, THIS MACRO ASSUMES +# THAT YOU PASSED '%t' TO THE TEX PROGRAM, IF YOU PASS '%s', THIS CODE +# WILL MAKE INCORRECT SUBSTITUTIONS FOR SOME VARIABLES! +# +# 1) It is "eval"ed so that Perl variables in the +# string are replaced with their values, i.e. +# "$TEX foo" -> "virtex foo" if $TEX="virtex". +# +# 2) %-substitution is performed. The following +# substitutions are currently supported: +# +# %F = format name (&lplain) +# %s = base document name (myfile) +# [ this used to mean /path/file w/o an extension, it now +# means the name of the DVI file w/o the .dvi extension ] +# %t = tex document name (/path/file.tex) +# %d = dvi document name (myfile.dvi) +# %e = error line, if there was one, otherwise 0 +# %E = file containing error, if there was one +# %o = the options passed into run +# +# %S, %T, and %D are the same as %s, %t, and %d except that +# pathname components are seperated by backslashes. This is a +# hack for MS-DOS and OS/2. +# +# TeX has some funny rules about path names: +# +# - The DVI file always goes in the current directory, +# the path is ignored. +# +# - To form the dvi filename, TeX strips off the last extension that +# *you* provide and appends .dvi. For example: +# +# You say: You mean: Dvi file: +# ------------- ------------ ------------ +# test.foo test.foo.tex test.dvi +# test.foo test.foo test.dvi +# test.foo.tex test.foo.tex test.foo.dvi +# test.foo.bar test.foo.bar test.foo.dvi +# +sub run { + local ($cmd,$opts) = @_; + local ($format) = "&" . $format{$TEXFORMAT}; + local ($texbase, $dvifile, $texfile); + local ($Texbase, $Dvifile, $Texfile); + local ($rc,$title); + + $texfile = $TEXFILEPATH . $TEXFILENAME . "." . $TEXFILEEXT; + $texbase = $TEXFILENAME; + $dvifile = &auxfile ("dvi"); + + ($Texbase = $texbase) =~ s#/#\\#g; + ($Texfile = $texfile) =~ s#/#\\#g; + ($Dvifile = $dvifile) =~ s#/#\\#g; + + # $cmd may be of the form "$TEX ..." and we want to + # expand the definition of $TEX, etc. + $cmd =~ s/\\/\\\\/g; # protect \'s + $cmd =~ s/\"/\\\"/g; # protect "'s + eval "\$cmd = \"$cmd\""; + + # Now substitute for `%' options... + $cmd =~ s/\%F/$format/g; + $cmd =~ s/\%s/$texbase/g; + $cmd =~ s/\%t/$texfile/g; + $cmd =~ s/\%d/$dvifile/g; + $cmd =~ s/\%S/$Texbase/g; + $cmd =~ s/\%T/$Texfile/g; + $cmd =~ s/\%D/$Dvifile/g; + $cmd =~ s/\%e/$ERRORLINE/g if $ERRORLINE; + $cmd =~ s/\%E/$ERRORFILE/g if $ERRORLINE; + $cmd =~ s/\%o/$opts/g; + + $cmd =~ s/\s+/ /g; # remove extranous whitespace, (display hack). + + $title = (split(/\s/, $cmd))[0]; + &set_xterm_title("TeXit: $title"); + &set_xicon_title("$title"); + + print "\n$cmd\n"; + $rc = system "$cmd"; + + if ($rc > 0) { + local (@parms); + @parms = split (/\s+/, $cmd); + print "\nNote: $parms[0] ended with return code $rc.\n"; + } + + $rc; +} + +######################################################################## +# Gets a command from the user by building a prompt up from the +# %CMDPROMPT and %CMDTEST arrays. A particular entry is only allowed +# if an eval of it's %CMDTEST returns true. +# +# &get_command() returns a two element list. The first element is +# index into the %CMDPROMPT array, the second element is any additional +# arguments supplied by the user. +# +sub get_command { + local (%commands, $_, $options); + local ($promptstring, $promptprefix); + local ($line, $thetest, $result); + + %commands = (); + $promptstring = ""; + $promptprefix = "Again? "; + $line = $promptprefix; + + # look for a stupid configuration error where a CMDTEST has + # gotten misspelled. + foreach $cmdname (keys %CMDTEST) { + die "$cmdname is defined as a CMDTEST but not as a CMDPROMPT.\n" + if !defined($CMDPROMPT{$cmdname}); + } + + foreach $cmdname (sort keys %CMDPROMPT) { + $thetest = $CMDTEST{$cmdname}; + $result = 1; + if ($thetest ne "") { + eval "\$result = $thetest"; + die "Bad CMDTEST: $thetest\n" if $@; + } + + if ($result) { + local ($cmdkey) = $cmdname; + $cmdkey =~ s/^.*\[(.*)\].*$/$1/; + die "No command string in square brackets: $cmdname\n" + if $cmdkey eq ""; + die "Duplicate command: $cmdname = $commands{$cmdkey}\n" + if defined($commands{$cmdkey}); + $commands{$cmdkey} = $cmdname; + if ($cmdname !~ /^!.*/) { + if (length($line . $cmdname) < 60) { + $line .= $cmdname . ", "; + } else { + $promptstring .= $line . "\n"; + $line = " " x length($promptprefix) . $cmdname . ", "; + } + } + } + } + + $line =~ s/(.*),\s*$/$1/; # remove the last ", "... + $promptstring .= $line . ": "; + + for (;;) { + ($cmdkey, $options) = ("", ""); + print "\nProcessing: $TEXFILEPATH$TEXFILENAME.$TEXFILEEXT\n", + $promptstring; + $_ = scalar(<STDIN>); chop; + ($cmdkey, $options) = ($1, $2) if /\s*(\S+)\s*(.*)/; + last if $commands{$cmdkey} ne "" || $_ eq ""; + print "\nI don't understand the command: $cmdkey\n\n"; + } + + ($commands{$cmdkey}, $options); +} + +######################################################################## +# Parse the TeX file looking for a local variables section. Build +# the associative array "%texvars" to hold the variables. +# +sub get_local_vars { + local($texfile) = @_; + local(@parms, $in_locals, $near_top, $in_plc, $plc_line); + + open (TEXFILE, $texfile) || die "Can't read $texfile.\n"; + + $in_locals = 0; # have we found the start of the local vars? + $in_plc = 0; # are we in the PLC commands? + $near_top = $TEXHEADERSIZE; # are we in the "header" area? + + @PLCRULES = (); # throw away any rules we've already found + + while (<TEXFILE>) { + chop; + + if ($near_top) { + $texvars{"TeX-master"} = $1 if /\%+\s*master:\s*(\S+)\s*$/i; + $texvars{"mode"} = $1 if /\%+\s*format:\s*(\S+)\s*$/i; + $texvars{"mode"} = $1 if /\%+\s*mode:\s*(\S+)\s*$/i; + + if (!defined($texvars{"mode"})) { + $texvars{"mode"} = "latex" if (/^\\documentstyle/); + $texvars{"mode"} = "latex2e" if (/^\\documentclass/); + $texvars{"mode"} = "slitex" if (/^\\documentstyle.*\{slides\}/); + $texvars{"mode"} = "foiltex" if (/^\\documentstyle.*\{foils\}/); + $texvars{"mode"} = "amstex" if (/^\\document\s*$/); + $texvars{"mode"} = "lollipop" if (/^\\Define\w+:\w+/); + $texvars{"mode"} = "texinfo" if (/^\@node/); + $texvars{"mode"} = "texinfo" if (/^\@ifinfo/); + $texvars{"mode"} = "texinfo" if (/input texinfo/); + } + + $near_top--; + } + + $in_locals = 0 if $in_locals && /End:\s*$/; + + if ($in_locals) { + local($_) = $_; + s/^\W*//; # remove leading whitespace + @parms = split(/[: \t\"\']+/); + $var = $parms[0]; + shift(@parms); + $val = join(" ",@parms); + $texvars{$var} = $val if !defined($texvars{$var}); + } + + # the [V] makes sure Emacs doesn't get confused when editing + # texit.pl + $in_locals = 1 if /Local [V]ariables:\s*$/; + + if ($in_plc && /End\s+TeXit\s+rules:\s*$/) { + push (@PLCRULES, $plc_line) if $plc_line ne ""; + undef($plc_line); + $in_plc = 0; + } + + if ($in_plc) { + local ($line) = $_; + local ($lastline) = /.*;\s*$/; # ends with a semicolon? + $line =~ s/\s*\%*\s*(.*)/$1/; # trim leading whitespace + $line =~ s/(.*)([^\\])(\#)(.*)$/$1$2/; # trim trailing comments + $line = "" if $line =~ /^\#/; # _only_ a comment? + $plc_line .= $line . " " if $line ne ""; + if ($lastline) { + push (@PLCRULES, $plc_line); + $plc_line = ""; + } + } + + $in_plc = 1 if /Start\s+TeXit\s+rules:\s*$/; + } + + warn "Unended local variables section?\n" if $in_locals; + die "Unended TeXit rules section!\n" if $in_plc; + + close (TEXFILE); +} + +######################################################################## +# Cleanup the TeX filename. Add the extension ".tex" if it doesn't +# already have an extension. +# +sub cleanup_texfilename { + local($texfile) = @_; + local($path,$base,$ext) = &splitfn($texfile,".tex"); + + $ext = "tex" if ($ext eq ""); + + $path . $base . "." . $ext; +} + +######################################################################## +# Break a filename into it's path, basename, and extension components. +# The path returned always ends with a slash. "./" is returned if the +# file has no path. If the filename passed in does not exist, the +# default extension passed in is tried (actually, is assumed to be +# correct). +# +sub splitfn { + local ($filename, $defext) = @_; + local ($path, $basename, $ext) = ("", "", ""); + + $filename =~ tr/\\/\//; # translate \ into / + + $filename = $filename . $defext if ! -r $filename; + + if ($filename =~ /\//) { + ($path = $filename) =~ s/\/[^\/]*$//; + ($basename = $filename) =~ s/.*\///; + } + else { + $path = "."; + $basename = $filename; + } + + if ($basename =~ /\./) { + ($ext = $basename) =~ s/.*\.//; + $basename =~ s/\.[^.]*$//; + } + + ($path . "/",$basename,$ext); +} + +######################################################################## +# Print a %done message when scanning LOGFILE +# +sub percent_done { + local ($logfile) = @_; + + if ($logfile) { + $LOGSIZE = -s $logfile; + $LOGPERC = 0; + $LOGPREV = 0; + } else { + $LOGPERC = int (tell(LOGFILE) / $LOGSIZE * 100.0); + printf "Parsing log file...%d%% done\r", $LOGPERC + if $LOGPERC > $LOGPREV; + $LOGPREV = $LOGPERC; + } +} + +######################################################################## +# Search the log file looking for the (first) line that contains an +# error. +# +sub find_error_line { + local ($logfile) = &auxfile("log"); + local ($prevtext, $curfile, $paren, $rest, $temp); + local ($line) = 0; + + &init_parse_log_filenames(); + + $curfile = ""; + + if (-r $logfile) { + &percent_done($logfile); + open (LOGFILE, $logfile); + while (<LOGFILE>) { + chop; + &percent_done(); + + ($paren, $rest, $temp) = &parse_log_filenames($_); + while ($paren eq "(" || $paren eq ")") { + $curfile = $temp; + ($paren, $rest, $temp) = &parse_log_filenames($rest); + } + + if ($prevtext =~ /^! .*$/ + && /^l\.([0-9]+) /) { + $line = $1; + } + + last if $line; + + $prevtext = $_; + } + close (LOGFILE); + } + + ($curfile, $line); +} + +######################################################################## +# Look through the log file for warnings. +# +sub parse_default_log { + # only looks for new dependency files... + local ($paren, $rest, $tempfile, $curfile); + local ($logfile) = &auxfile("log"); + + &init_parse_log_filenames(); + + if (-r $logfile) { + &percent_done ($logfile); + open (LOGFILE, $logfile); + while (<LOGFILE>) { + chop; + &percent_done (); + + ($paren, $rest, $tempfile) = &parse_log_filenames($_); + while ($paren eq "(" || $paren eq ")") { + $curfile = $tempfile; + printf("Adding dependency for `%s'.\n", $curfile) + if !defined($DEPENDSON{$curfile}) && $VERBOSE; + $DEPENDSON{$curfile} = 1; + ($paren, $rest, $tempfile) = &parse_log_filenames($rest); + } + } + } + close (LOGFILE); +} + +######################################################################## +# Look through the log file for the LaTeX warnings. +# +sub parse_latex_log { + local ($newbib, $misbib, $newref, $badref, $badfont) = (0, 0, 0, 0, 0); + local ($hastoc, $haslof, $haslot) = (0, 0, 0); + local ($font, $reference, $citation); + local ($inputfile, $warning); + local ($logfile) = &auxfile("log"); + local ($auxfile) = &auxfile("aux"); + local ($paren, $rest, $curfile, $tempfile); + + # These are global values. + undef (%citelist); # undefined citations + undef (%reflist); # undefined references + undef (%fontlist); # NFSS substituted fonts + undef (%refmultlist); # multiply defined references + undef (%WARNINGS); # Unrecognized warning messages + + &init_parse_log_filenames(); + + if (-r $logfile) { + &percent_done ($logfile); + open (LOGFILE, $logfile); + while (<LOGFILE>) { + chop; + &percent_done (); + + $warning = 0; + + ($paren, $rest, $tempfile) = &parse_log_filenames($_); + while ($paren eq "(" || $paren eq ")") { + $curfile = $tempfile; + printf("Adding dependency for `%s'.\n", $curfile) + if !defined($DEPENDSON{$curfile}) && $VERBOSE; + $DEPENDSON{$curfile} = 1; + ($paren, $rest, $tempfile) = &parse_log_filenames($rest); + } + + if (/LaTeX Warning: Citation/) { + $newbib = 1; + ($citation = $_) =~ s/.*`(.*)'.*/$1/; # '` + $citelist{$citation} = 1; + $warning = 1; + } + + if (/LaTeX Warning: Reference/) { + ($reference = $_) =~ s/.*\`(.*)\'.*/$1/; + $reflist{$reference} = 1; + $badref = 1; + $warning = 1; + } + + if (/LaTeX Warning: Label `(.*)' multiply defined/) { # '` + $refmultlist{$1} = 1; + $badref = 1; + $warning = 1; + } + + if (/Warning: Font\/shape.*undefined/) { + ($font = $_) =~ s/.*\`(\S+)\s*\'.*/$1/; + $fontlist{$font} = 1; + $badfont = 1; + $warning = 1; + } + + if (/Warning: Font\/shape.*not available/) { + ($font = $_) =~ s/.*\`(\S+)\s*\'.*/$1/; + $fontlist{$font} = 1; + $badfont = 1; + $warning = 1; + } + + if (/LaTeX Warning: Label\(s\) may have changed/) { + $newref = 1; + $warning = 1; + } + + # LaTeX2e + if (/LaTeX Warning: There are unresolved references./) { + $warning = 1; + } + + if (/LaTeX Warning: Marginpar on page .* moved./ + || /Warning: Using `.*' instead on input line [0-9]+./ # '` + || /Warning: Using external font `.*' instead on input/ # '` + || /Warning: Substituting `.*' instead on input/) { # '` + $warning = 1; # don't bother to show these warnings. + } + + if ((/Warning:/ && !$warning) + || /NFSS Info: \*\*\*/) { + $WARNINGS{$_} = $curfile; + } + + if (/No file .*\.bbl\./) { + $misbib = 1; + } + + # see if the file should have TOC, LOF, and LOT files... + $hastoc = 1 if /tf\@toc/; + $haslof = 1 if /tf\@lof/; + $haslot = 1 if /tf\@lot/; + } + close (LOGFILE); + } + + if (-r $auxfile) { + open (AUXFILE, $auxfile); + while (<AUXFILE>) { + chop; + + if (/\\bibstyle\{(.+)\}/) { + local ($name, $fullname); + $name = $1 . ".bst"; + $fullname = &find_on_path($ENV{"$ENV_TEXINPUTS"}, $name); + if ($fullname ne "" + && -r $fullname + && !defined($DEPENDSON{$fullname})) { + printf("Adding dependency for `%s'.\n", $fullname) + if !defined($DEPENDSON{$fullname}) && $VERBOSE; + $DEPENDSON{$fullname} = 1; + } + } + + if (/\\bibdata\{(.+)\}/) { + local (@filelist, $fullname, $name); + + @filelist = split(/,/, $1); + while (($name = shift @filelist)) { + $name = $name . ".bib"; + $fullname = &find_on_path($ENV{"$ENV_BIBINPUTS"}, $name); + if ($fullname ne "" + && -r $fullname + && !defined($DEPENDSON{$fullname})) { + printf("Adding dependency for `%s'.\n", $fullname) + if !defined($DEPENDSON{$fullname}) && $VERBOSE; + $DEPENDSON{$fullname} = 1; + } + } + } + } + close (AUXFILE); + } + + ($newbib, $misbib, $newref, $badref, $badfont, $hastoc, $haslof, $haslot); +} + +######################################################################## +# Look through the log file for the Texinfo warnings. +# +sub parse_texinfo_log { + local ($newref, $badref) = (0, 0); + local ($logfile) = &auxfile("log"); + local ($ref); + local ($paren, $rest, $tempfile, $curfile); + + undef (%reflist); # undefined references + + &init_parse_log_filenames(); + + if (-r $logfile) { + &percent_done ($logfile); + open (LOGFILE, $logfile); + while (<LOGFILE>) { + chop; + &percent_done (); + + ($paren, $rest, $tempfile) = &parse_log_filenames($_); + while ($paren eq "(" || $paren eq ")") { + $curfile = $tempfile; + printf("Adding dependency for `%s'.\n", $curfile) + if !defined($DEPENDSON{$curfile}) && $VERBOSE; + $DEPENDSON{$curfile} = 1; + ($paren, $rest, $tempfile) = &parse_log_filenames($rest); + } + + if (/Undefined cross reference \`(.*)\'./) { + $badref = 1; + $ref = $1; + $ref = $1 if $ref =~ /(.*)-[^\-]*/; + $reflist{$ref} = 1; + } + + $newref = 1 + if /Cross reference values unknown; you must run TeX again./; + } + close (LOGFILE); + } + + ($newref, $badref); +} + +######################################################################## +# This routine aids in the parsing of log files be locating filenames +# within the log. Filenames included in a document always appear as +# '(filename...' in the log. +# +# NOTE: if unbalanced parenthesis occur in the log file (because someone +# printed them in a \typeout command or some such), all bets are +# off! +# +# FURTHER NOTE: this routine returns the top of the filename stack +# whenever a close paren is seen, so you will get the +# same files more than once... +# +# This routine uses the global variables %ParenLevel and %Parens which +# it initializes appropriately... +# +# ********************************************************************** +# THIS ROUTINE IS NOT RE-ENTRANT! IT REQUIRES STATE SAVED ACROSS CALLS! +# ********************************************************************** +# +sub init_parse_log_filenames { + %Parens = (); + $ParenLevel = 0; +} + +sub parse_log_filenames { + local ($rest) = @_; + local ($paren, $curfile); + local (@result) = (); + + undef ($curfile); + + while ($rest =~ /^[^()]*(\(|\))(.*)/) { + $paren = $1; + $rest = $2; + + ($curfile = $rest) =~ s/\s*(\S+)/$1/; # leading whitesp + $curfile =~ s/^([^() ]+).*/$1/; # trailing ( and ) + + if ($paren eq "(") { + $ParenLevel++; + if (-r $curfile) { + $Parens{$ParenLevel} = $curfile; + } else { + $Parens{$ParenLevel} = '*'; + } + } else { + $ParenLevel--; + $curfile = $Parens{$ParenLevel}; + } + + last if -r $curfile; + + undef ($curfile); + } + + if ($curfile) { + @result = ("$paren", "$rest", "$curfile"); + } + + @result; +} + +######################################################################## +# This routine is called after each run of TeX to see if TeX needs to +# be run again. TeX needs to be run twice when documents contain +# cross references, lists of tables, or other things which cannot be +# completely determined in a single pass. Sometimes TeX needs to be +# run three times. +# +# Since different formats print different messages in the log file, +# there is no universal way to determine if TeX needs to be run again. +# +# This routine calls "&parse_FORMAT_log()" to extract information from +# the log file and "&interpret_FORMAT_log()" to decide what to do with +# the information. "&parse_FORMAT_log()" should return a list, this +# list is passed to "&interpret_FORMAT_log()". +# +# FORMAT = $parsename{$TEXFORMAT}. +# +# Currently only "default" and "latex" FORMATs exist. The default +# format just looks to see if the DVI file still exists or if the +# master file is newer than the DVI file. +# +# The latex format does a lot more. +# +# If you write new &parse_FORMAT_log()/&interpret_FORMAT_log() routines, +# remember to do the same checking that &interpret_default_log() does +# and remember to run the users PLC commands at an appropriate place. +# Copying and modifying the latex versions is probably the best way +# to start. +# +sub dependencies_changed { + local (@parselist, $sub); + + $changed = 0; + + eval "\@parselist = &parse_$parsename{$TEXFORMAT}_log();"; + eval "\$changed = &interpret_$parsename{$TEXFORMAT}_log(\@parselist);"; + + $changed; +} + +######################################################################## +# Called by the interpret_FORMAT_routines, this function returns +# true if the dvi file is missing or the master document is more +# recent than the dvi file... +# +sub document_is_newer { + local ($changed) = 0; + + if (! -r &auxfile("dvi")) { + print &auxfile("dvi"), " is missing.\n" if $VERBOSE; + $changed = 1; + } elsif (&mtime(&auxfile("dvi")) < &mtime($texmaster)) { + print "$texmaster is newer than ", &auxfile("dvi"), ".\n" + if $VERBOSE; + $changed = 1; + } + + $changed; +} + +######################################################################## +# Called by the interpret_FORMAT_routines, this function runs the +# @default_rules, @FORMAT_rules, and user rules... +# Input: $changed +# Output: new value of $changed +# +sub run_rules { + local ($changed) = @_; + local ($line, @the_rules); + + @the_rules = @default_rules; + foreach $line (@the_rules) { + print "Rule: $line\n" if $VERBOSE; + eval $line; + die "Invalid rule: $line\n" if $@; + } + + eval "\@the_rules = \@${TEXFORMAT}_rules"; + foreach $line (@the_rules) { + print "Rule: $line\n" if $VERBOSE; + eval $line; + die "Invalid rule: $line\n" if $@; + } + + foreach $line (@PLCRULES) { + print "Rule: $line\n" if $VERBOSE; + eval $line; + die "Invalid rule: $line\n" if $@; + } + + $changed; +} + +######################################################################## +# Input: the list of values returned by parse_default_log(). +# Output: prints informative messages. +# Returns: 1 if TeX should be run again... +# +sub interpret_default_log { + local ($changed) = 0; + + $changed = &document_is_newer(); + $changed = &run_rules($changed); + $changed = 1 if &dependent_files_are_newer(); + + print "\nAs far as I can tell, the document is up to date.\n" + if !$changed; + + $changed; +} + +######################################################################## +# Input: the list of values returned by parse_latex_log(). +# Output: prints informative messages. +# Returns: 1 if TeX should be run again... +# +sub interpret_latex_log { + local ($newbib, $misbib, $newref, $badref, $badfont, + $hastoc, $haslof, $haslot) = @_; + local ($changed) = 0; + local ($warning); + + $changed = &document_is_newer(); + + # If the document should have TOC, LOF, or LOT files but they + # don't actually exist, then the document has to be TeX'd + # again. + if (($hastoc && ! -r &auxfile("toc")) + || ($haslof && ! -r &auxfile("lof")) + || ($haslot && ! -r &auxfile("lot"))) { + $changed = 1; + print "Table of contents disappeared.\n" + if $hastoc && ! -r &auxfile("toc"); + print "List of figures disappeared.\n" + if $haslof && ! -r &auxfile("lof"); + print "List of tables disappeared.\n" + if $haslot && ! -r &auxfile("lot"); + } + + # If there are unknown citations... + if ($newbib) { + local ($wasdiff) = 0; + + &print_long_list ("Missing citations: ", keys(%citelist)); + + # calculate the intersection between the currently missing + # citations and the ones that were missing last time. If they + # are different, run BibTeX. Since missingcites begins empty, + # this will force BibTeX to be run at least once if there are + # any missing citations. + { + local (%mark, @diff, $_); + grep($mark{$_}++, keys(%missingcites)); + @diff = grep(!$mark{$_}, keys(%citelist)); + if (@diff) { + $rc = &bibtexcmd (""); + print "\n"; + $changed = 1; + $wasdiff = 1; + } + } + + if (%missingcites) { + print "Bibliography database(s) may be incomplete.\n"; + if (! $wasdiff) { + print "The same citations are missing. ", + "Running BibTeX again won't help.\n"; + } + } + print "\n"; + + %missingcites = %citelist; + } + + if ($misbib && ! $newbib) { + $rc = &bibtexcmd(""); + print "\n"; + } + + # If there are unknown references... + if ($badref) { + if (%reflist) { + &print_long_list ("Missing references: ", + keys(%reflist)); + print "\n"; + } + if (%refmultlist) { + &print_long_list ("Multiply defined references: ", + keys(%refmultlist)); + print "\n"; + # Retry once if the error is found on the first pass + # because the error persists in the AUX file through + # one run after the user fixes the problem. + $newref = 0 if $runcount > 1; + } + } + + # Just FYI about substituted fonts... + if ($badfont) { + &print_long_list ("FYI: substituted fonts: ", + keys(%fontlist)); + print "\n"; + } + + # If there are Warnings that TeXit doesn't understand... + if (%WARNINGS) { + print "\nThe following (unrecognized) warnings appear ", + "in the log file:\n"; + foreach $warning (keys %WARNINGS) { + if ($warning =~ /input line ([0-9]+)./) { + printf "%s: %d: %s\n", $WARNINGS{$warning}, $1, $warning; + } else { + print $WARNINGS{$warning}, ": ", $warning, "\n"; + } + } + } + + # The file has changed if there are new references... + $changed = $changed || $newref; + + $changed = &run_rules($changed); + $changed = 1 if &dependent_files_are_newer(); + + if (!$changed) { + if ($newbib || $badref) { + print "\nThe document is still incorrect, "; + print "but TeXing again won't help.\n"; + print "Some citations cannot be found. " + if $newbib; + print "Some references cannot be found or cannot be resolved." + if $badref; + print "\n\n"; + } else { + print "\nAs far as I can tell, the document is up to date.\n"; + } + } else { + print "\n"; + } + + $changed; +} + +######################################################################## +# Input: the list of values returned by parse_texinfo_log(). +# Output: prints informative messages. +# Returns: 1 if TeX should be run again... +# +sub interpret_texinfo_log { + local ($newref, $badref) = @_; + local ($changed) = 0; + + # If there are unknown references... + if ($badref) { + if (%reflist) { + print "\n"; + &print_long_list ("Missing references: ", + keys(%reflist)); + print "\n"; + } + } + + $changed = &document_is_newer() || $newref; + $changed = &run_rules($changed); + $changed = 1 if &dependent_files_are_newer(); + + if (!$changed) { + if ($badref) { + print "The document is still incorrect, "; + print "but TeXing again won't help.\n"; + print "Some references cannot be found or cannot be resolved." + if $badref; + print "\n\n"; + } else { + print "As far as I can tell, the document is up to date.\n"; + } + } + + $changed; +} + +######################################################################## +# Input: an extension, `ext' +# Output: the filename $TEXFILEPATH . $TEXFILENAME . `.ext' +# Note: auxilliary files are always placed in the current directory, +# the path is ignored. This is a change from v1.27 to be more +# compatible with TeX. +# +sub auxfile { + local($ext) = @_; + local($dot); + + $dot = ""; + $dot = "." if $ext ne "" && $ext !~ /^\./; + + $TEXFILENAME . $dot . $ext; +} + +######################################################################## +# Input: none +# Output: true if any file in %DEPENDSON is newer than DVI file +# +sub dependent_files_are_newer { + local($file, $rerun); + + $rerun = 0; + if (-r &auxfile("dvi")) { + foreach $file (keys %DEPENDSON) { + if (-r $file) { + if (&mtime(&auxfile("dvi")) < &mtime($file)) { + print "$file newer than DVI file? Yes.\n" + if $VERBOSE; + $rerun = 1; + } else { + print "$file newer than DVI file? No.\n" + if $VERBOSE; + } + } else { + print "$file newer than DVI file? No (doesn't exist).\n" + if $VERBOSE; + } + } + } + + $rerun; +} + +######################################################################## +# Input: list of files +# Output: None. Sets the %DEPENDSON list... +# +sub dependson { + local(@filelist) = @_; + local($file); + + foreach $file (@filelist) { + $DEPENDSON{$file} = 1; + } +} + +######################################################################## +# Input: list of files +# Output: true if any file is missing +# +sub missing { + local(@filelist) = @_; + local($missing, $file); + + $missing = 0; + + foreach $file (@filelist) { + if (defined($ifmissing{$file})) { + if (! -r $file) { + print "Missing: $file? Yes.\n" if $VERBOSE; + $missing = 1; + } else { + print "Missing: $file? No.\n" if $VERBOSE; + } + } else { + $ifmissing{$file} = 1; + } + } + + $missing && (!$first_time); +} + +######################################################################## +# Input: list of files +# Output: waits until they all exist (and are readable) +# +sub waitfor { + local(@filelist) = @_; + local(@missing, $file); + + @missing = (); + + foreach $file (@filelist) { + push (@missing, $file) if (! -r $file); + } + + if ($VERBOSE && @missing) { + &print_long_list ("\nWaiting for: ",@filelist); + print "\n"; + } + + foreach $file (@missing) { + while (! -r $file) { + sleep 1; + } + } +} + +######################################################################## +# Input: list of files +# Output: true if any file has changed. A file has changed if its +# checksum is different from the preceding call. Files that +# are missing both times are currently the same. +# +sub changed { + local(@filelist) = @_; + local($changed, $savecheck, $file); + + $changed = 0; + + foreach $file (@filelist) { + if (defined($ifchanged{$file})) { + $savecheck = &checksum($file); + if ($ifchanged{$file} != $savecheck) { + print "Changed: $file? Yes.\n" if $VERBOSE; + $ifchanged{$file} = $savecheck; + $changed = 1; + } else { + print "Changed: $file? No.\n" if $VERBOSE; + } + } else { + $ifchanged{$file} = &checksum($file); + } + } + + $changed && (!$first_time); +} + +######################################################################## +# Calculate a checksum for a file. +# +sub checksum { + local($file) = @_; + local($/, $checksum); + + undef $/; + + if (-r $file) { + open (CHECKSUM, $file); + $checksum = unpack("%32C*", <CHECKSUM>); + close (CHECKSUM); + } else { + $checksum = "none"; + } + + $checksum; +} + +######################################################################## +# Input: two lists of files. The lists must be quoted strings so that +# they can be seperated easily. The two strings are split on +# "/, /" so they _can_ include multiple files. +# Output: true if _any_ of the first list of files is newer than _any_ +# of the second list of files _or_ any of the second list of +# files is missing. +# +sub newer { + local ($newfile, $oldfile) = @_; + local (@newfiles,@oldfiles); + local ($file, $missing, $newer); + + @newfiles = split(/[, ]/, $newfile); + @oldfiles = split(/[, ]/, $oldfile); + + die "Bad call to &newer(). No files in `new' list.\n" + if !@newfiles; + die "Bad call to &newer(). No files in `old' list.\n" + if !@oldfiles; + + $newer = 0; + + # Find the oldest old file. All must exist. + undef $oldfile; + foreach $file (@oldfiles) { + $newer = 1, $missing = $file, last if ! -r $file; + $oldfile = $file + if (! $oldfile || (&mtime($file) < &mtime($oldfile))); + } + + # Find the newest new file. + undef $newfile; + foreach $file (@newfiles) { + $newfile = $file + if (-r $file + && (! $newfile || (&mtime($file) > &mtime($newfile)))); + } + + warn "None of the `new' files exist: @newfiles\n" + if ! $newfile; + + $newer = $newer + || ($newfile && (&mtime($newfile) > &mtime($oldfile))); + + if ($newer) { + if ($oldfile) { + print "$newfile newer than $oldfile? Yes.\n" + if $VERBOSE; + } else { + print "$missing doesn't exist, so $newfile is newer.\n" + if $VERBOSE; + } + } else { + print "$newfile newer than $oldfile? No.\n" + if $VERBOSE; + } + + $newer && (!$first_time); +} + +######################################################################## +# This routine prints a message followed by a potentially long list of +# items, seperated by spaces. It will never allow "word wrap" to occur +# in the middle of a word. There has to be a better way, using Perl's +# report generation to do this, but I haven't looked yet. +# +sub print_long_list { + local ($message,@thelist) = @_; + local ($line) = $message; + local ($item, $displaystring) = ("", ""); + + foreach $item (@thelist) { + if (length($line . $item) < 73) { + $line .= $item . ", "; + } else { + $displaystring .= $line . "\n"; + $line = $item . ", "; + } + } + + $line =~ s/(.*),\s*$/$1/; # remove the last ", "... + $displaystring .= $line . "\n"; + + print $displaystring; +} + +######################################################################## +# Shows the current status of TeXit. This is kindof a debugging option +# and kindof a 'satisfy my curiousity' option. It isn't really very +# complete yet. +sub showstatus { + local($opts) = @_; + + print "\n"; + + if ($opts eq "?" || $opts eq "") { + print "Status options:\n"; + print " rules = rules\n"; + print " dep = document dependencies\n"; + print " <var> = value of Perl variable <var>\n"; + } elsif ($opts eq "rules") { + local ($line, @the_rules); + + @the_rules = @default_rules; + foreach $line (@the_rules) { + print "Default rule: $line\n"; + } + + eval "\@the_rules = \@${TEXFORMAT}_rules"; + foreach $line (@the_rules) { + print "$TEXFORMAT rule: $line\n"; + } + + foreach $line (@PLCRULES) { + print "Document rule: $line\n"; + } + } elsif ($opts eq "dep") { + local ($line); + + print "This document depends on the following files:\n"; + foreach $line (keys %DEPENDSON) { + print "\t$line\n"; + } + } else { + local ($arg, $svalue, %pvalue, @avalue, $line, $isdef); + + $isdef = 0; + + eval "\$arg = defined(\$$opts);"; + if ($arg) { + eval "\$svalue = \$$opts;"; + print "\$$opts = $svalue\n"; + $isdef = 1; + } + + eval "\$arg = defined(\%$opts);"; + if ($arg) { + print "\%$opts:\n"; + eval "\%pvalue = \%$opts;"; + foreach $line (keys %pvalue) { + print "$line = $pvalue{$line}\n"; + } + $isdef = 1; + } + + eval "\$arg = defined(\@$opts);"; + if ($arg) { + print "\@$opts:\n"; + eval "\@avalue = \@$opts;"; + foreach $line (@avalue) { + print "$line\n"; + } + $isdef = 1; + } + + if (! $isdef) { + print "$opts is undefined.\n"; + } + } +} + +######################################################################## +# Setup the $format{}, $formatname{}, and $parsename{} associative +# arrays for finding the format file name, printable name, and parser +# name for each format. +sub setup_format { + local ($common_name, $printable_name, + $parser_name, $format_name, $alt_inputenv) = @_; + + $format{$common_name} = $format_name; + $formatname{$common_name} = $printable_name; + $parsename{$common_name} = $parser_name; + $altinputenv{$common_name} = $alt_inputenv; +} + +######################################################################## +# Builds an associative array for a pascal-like case statement. This +# is a bit obscure and relies on Perl's ability to evaluate strings +# that look like code at runtime. +sub case { + local(*assoc,$_) = @_; + for (split(/\n/)) { + /^\s*(\S+)\s+(.*)/; + for (eval $1) { + $assoc{$_} = $2; + } + } +} + +######################################################################## +# Return Perl version info... +# +sub perl_version_info { + local($savestar) = $*; + + $* = 1; + + $] =~ /^.*Revision: ([\d.]+) .*\nPatch level: (\d+).*$/; + $revision = $1; + $patchlevel = $2; + + $* = $savestar; + + ($revision, $patchlevel); +} + +######################################################################## +# This hack gets around problems with MS-DOS and OS/2 ports of Perl. +# Some ports get confused when presented with "require d:/path/file" +# because they think "d:/path/file" should appear somewhere in @INC +# because it doesn't begin with a slash. Sigh. This code isn't as +# nice as "require" but it works... +# +sub require_hack { + local($file) = @_; + local($line); + + print "Loading init file: $file\n" if $VERBOSE; + + $line = ""; + open (INIT, $file); + while (<INIT>) { + $line = $line . $_; + if (/;\s*$/) { + eval $line; + die "Error in init file: $file at line $..\n" if $@; + $line = ""; + } + } + close (INIT); + + die "Missing \";\" at end of init file: $file.\n" + if ($line !~ /^\s*$/); +} + +######################################################################## +# This hack gets around problems with (at least) the OS/2 port of Perl. +# The OS/2 port (maybe the MS-DOS port?) have one _hell_ of an annoying +# bug. The test "-M file" returns a large positive number instead of +# a negative number for files that are newer than the start-time of the +# script (someone probably did an unsigned computation where a signed +# computation was required...) The result is that -M file1 > -M file2 +# if file2 existed when the script began and file1 did not. Really +# bad. +# +# Caveat, on a working system: +# +# -M file1 > -M file2 ==> &mtime(file1) < &mtime(file2) +# +sub mtime { + local ($file) = @_; + local ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, + $atime, $mtime, $ctime, $blksize, $blocks); + + if (-r $file) { + ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, + $atime, $mtime, $ctime, $blksize, $blocks) = stat($file); + } else { + $mtime = -1; + } + + $mtime; +} + +######################################################################## +# This helpful little routine locates a file on a path. The path can +# be ":" or ";" delimited. If the file is found, it's fully qualified +# name is returned, otherwise the null string is returned. If the +# input path contains "/" or "\" then either it is returned (if the file +# specified exists) or the empty string is returned, the path _is not_ +# searched. +# +sub find_on_path { + local($path, $file) = @_; + local($dir, $filename); + + $filename = ""; + + if ($file =~ /\/|\\/) { + $filename = $file if -e $file; + } else { + foreach $dir (split(/;|:/,$path)) { + $dir =~ s/\\/\//g; + $filename = $dir . "/" . $file; + last if -e $filename; + $filename = ""; + } + } + $filename; +} + +######################################################################## +# Sometimes it is helpful to have a .texitrc file (especially in a +# working directory) update the paths used by TeX. These two routines +# are a big help... +# +sub del_from_path { + local($path,$dir) = @_; + local(@paths,$outpath,$curdir,$place); + + @paths = split(/$PATHSEP/,$path); + + $outpath = ""; + for ($place = 0; $place <= $#paths; $place++) { + $curdir = @paths[$place]; + $outpath = sprintf("%s$PATHSEP%s", $outpath, $curdir) + if $curdir && $curdir ne $dir; + } + + $outpath = $1 if $outpath =~ /^$PATHSEP+([^$PATHSEP].*)$/; + $outpath = $1 if $outpath =~ /^(.*[^$PATHSEP])$PATHSEP+$/; + + $outpath; +} + +sub add_to_path { + local($path,$dir,$front) = @_; + local(@paths,$outpath,$curdir,$place); + + $path = &del_from_path($path,$dir); # remove it if it's already there + + if ($front) { + $path = $dir . $PATHSEP . $path; + } else { + $path = $path . $PATHSEP . $dir; + } + + $path; +} + +######################################################################## +# For texit running under X11, this routine changes the title to reflect +# what's going on now...works for the iconized xterm too! +# +sub set_xterm_title { + local ($title) = @_; + + print STDOUT "]2;$title" if $SETXTITLE; +} + +sub set_xicon_title { + local ($title) = @_; + + print STDOUT "]1;$title" if $SETXTITLE; +} + +sub set_x_titles { + local ($title) = @_; + &set_xterm_title ($title); + &set_xicon_title ($title); +} + +######################################################################## +# I'm sure this could be improved...but real docs should be written +# anyway so there's no need to go overboard here. That's my excuse, +# in any event. +# +sub display_usage { + local (@formatlist, $item); + + print "#" x 72, "\n"; + print <<'EOF'; +Usage: texit <options> texfile[.tex] +Where <options> may be: + -<format> process `texfile' using the named format. + -once process document once and exit. Returns 0 + if the document seems ok after processing. + -clean suppress prompt message when cleaning up files. + -menu skip the initial run of TeX and go straight to the menu. + -verbose display additional status messages. + -initfile init load the file "init" during initialization. + -tex force an initial run of TeX, even if it doesn't + seem necessary. + -bibtex start by running BibTeX (instead of TeX). + -makeindex start by running MakeIndex. + +TeXit tries to figure out the format of your document, so you don't +have to specify it. Of course, you have to specify it if TeXit guesses +wrong. Better yet, stick in an Emacs-style local var section to define +the format or a "% Format: format" line at the top of your document. + +You only have to specify enough of the option string to make it +unambiguous (e.g. "-v" is good enough for -verbose). + +EOF + + foreach $item (keys %format) { + unshift(@formatlist, $item) if !defined($casefoo{$item}); + } + + &print_long_list("TeXit recognizes the following format names: ", + sort(@formatlist)); + print "#" x 72, "\n"; + exit 2; +} + diff --git a/support/tex-it/texit.tex b/support/tex-it/texit.tex new file mode 100644 index 0000000000..0c13b51cd0 --- /dev/null +++ b/support/tex-it/texit.tex @@ -0,0 +1,672 @@ +\documentstyle{article} +% +% If you don't have Anthony Bloesch's ``treetex.sty'' file, just remove +% that style option. The ``right thing'' will happen when you process +% the document. + +%% #!/usr/local/bin/perl +%% dependency on format file names... + +\partopsep=0pt +\topsep=0pt +\parindent=0pt +\parskip=\baselineskip + +\def\desctree{% +Consider a \LaTeX\footnote{There's nothing special about \LaTeX\ in this +example, it's just convienient to select the \LaTeX\ format because it has +support for bibliographies and indices built in. Similar arguments can be +made about other formats with different arrangements of supporting files.} +document composed of a main file, \verb|main.tex|, and two included files, +\verb|chap1.tex| and \verb|chap2.tex|. Assume that the document has a +bibliography and an index (\verb|main.bbl| and \verb|main.ind|). The +bibliography is constructed from \verb|myrefs.bib| by Bib\TeX and the index is +constructed by MakeIndex from the \verb|main.idx| file produced by \TeX{}ing +the document. +} + +\def\maketree{% +Consider a \LaTeX\footnote{There's nothing special about \LaTeX\ in this +example, it's just convienient to select the \LaTeX\ format because it has +support for bibliographies and indices built in. Similar arguments can be +made about other formats with different arrangements of supporting files.} +document composed of several files as shown in the diagram below. Assume that +the bibliography (\verb|main.bbl|) is constructed from \verb|myrefs.bib| by +Bib\TeX and the index is constructed by MakeIndex from the \verb|main.idx| +file produced by \TeX{}ing the document. + +\begin{center} + \def\treefbox##1{\fbox{{\tt ##1}}} + \begin{tree}{texittr} + \rootnode{\treefbox{main.tex}} + \treenode{nodeA}{root}{\treefbox{chap1.tex}} + \treenode{nodeB}{root}{\treefbox{chap2.tex}} + \treenode{nodeC}{root}{\treefbox{main.bbl}} + \treenode{nodeD}{root}{\treefbox{main.ind}} + \treenode{nodeE}{nodeC}{\treefbox{myrefs.bib}} + \treenode{nodeF}{nodeE}{\treefbox{plain.bst}} + \treenode{nodeG}{nodeD}{\treefbox{main.idx}} + \end{tree} +\end{center} +} + +% if you include the ``treetex'' style, you can have a nice drawing +% in your document. +\makeatletter +\@ifundefined{tree}{\let\drawdoc\desctree}{\let\drawdoc\maketree} +% something else while I've got the @ right... +\def\@listI{\leftmargin\leftmargini \parsep 4\p@ plus2\p@ minus\p@ +\topsep 0\p@ plus0\p@ minus0\p@ +\itemsep 4\p@ plus2\p@ minus\p@} +\makeatother + +\title{TeXit \\ An intelligent script for running \TeX % + \\ \ \\ {\small Version 1.29}} +\author{Norman Walsh \\ {\tt walsh@cs.umass.edu}} +\date{August 16, 1993} + +\begin{document} + +\maketitle + +\section{What is TeXit?} + +TeXit is a Perl script designed to automate the task of processing documents +with \TeX. It runs \TeX\ with the correct format and tries to intelligently +determine when \TeX\ needs to be run a second, or even third, time in order +to get correctly typeset output. + +`Out of the box', TeXit is configured to recognize \LaTeX, Plain \TeX, and +Texinfo files, but it can easily be extended to other formats. One of the +nice features of TeXit is that you can provide document-specific ``rules'' to +determine how many times \TeX\ needs to be run. + +By the way, I tried to make a ``minimal'' TeXit and decided it wasn't worth +it. The difference in startup speed was too small to justify the expense +of maintaining two versions. Honest. + +This document describes TeXit, but you should also look at the +``\verb|texit.pl|'' file. I tried to put informative comments next to all of +the variables that you might want to change. If you do want to change them, +{\em do it in an initialization file} (see Section~\ref{sec:init}). {\bf Don't +change the script!} + +\section{Legal Mumbo-Jumbo} + +TeXit is distributed under the terms of the GNU General Public License, +version 2 or later. + +Use at your own risk. I take no responsibility for {\it any\/} problems +you have, whether or not they are caused by TeXit. On the other hand, +if you do have problems, I'll be as helpful as I can ;-) + +\section{What Does It Do?} + +\drawdoc + +Such a document forms a tree-like graph\footnote{It's tree-like because you +can't have a cycle in the ``main branches'' (i.e. the included files) but it's +also a graph because there can be cross references between any two nodes.}. + +In the worst case, getting this document to print correctly requires +{\em eight\/} steps! + +\begin{enumerate} + \item Run \LaTeX\ (this generates \verb|main.idx| and \verb|main.aux|). + \item Run \LaTeX\ again to satisfy any cross references. + \item Run Bib\TeX\ (this generates \verb|main.bbl|). + \item Run MakeIndex (this generates \verb|main.ind|). + \item Run \LaTeX\ (this builds the ``final document''). Except that + the bibliography citations have changed a page break so the references + are wrong. + \item Run \LaTeX\ again to satisfy any cross references. + \item Run MakeIndex since the index may be wrong. + \item Run \LaTeX\ to build the final document. +\end{enumerate} + +As if that weren't enough to warrant the aid of a script to do the dirty +work, you might also like to setup \TeX\ as a compiler from within your +editor, but you want to run \LaTeX\ on ``\verb|main.tex|'' even if you +happen to be editing ``\verb|chap02.tex|''. + +TeXit can handle all of these problems. + +\subsection{Finding the Right File} + +When TeXit processes a file, the first thing it looks for is some indication +that the file it was given is part of some larger document. If it discovers +that this is the case, it abandons the current file in favor of the ``master'' +file. + +There are two ways that you can indicate that a file is part of a larger +document: + +\begin{itemize} + \item Place ``\verb|% master: main.tex|'' on a line by itself near the + top of your document. This identifies ``\verb|main.tex|'' as + the master file. + \item Include ``\verb|% TeX-master: main.tex|'' in an Emacs ``Local + Variables'' section at the bottom of your file. If you don't + use Emacs, don't worry about this. +\end{itemize} + +\subsection{Finding the Right Format} + +Next, TeXit needs to determine what format to use. You can force TeXit +to select a particular mode with the ``\verb|-|{\em format\/}'' command-line +switch, or by inserting a command in your document: + +\begin{itemize} + \item Place ``\verb|% mode: latex|'' or ``\verb|% format: latex|'' on a + line by itself near the top of your document. This identifies + ``\verb|latex|'' as the format to use. TeXit figures out the + actual format file name, you just tell it in English. Running TeXit + without any arguments will give you a list of formats. + \item Include \verb|% mode: latex| in an Emacs ``Local + Variables'' section at the bottom of your file. If you don't + use Emacs, don't worry about this. +\end{itemize} + +If you don't specify a format, TeXit assumes that the document is Plain \TeX\ +unless it finds one of the following: + +\begin{itemize} +\item ``\verb|\documentstyle[|{\em any options\/}\verb|]{slides}|'' + indicates Sli\TeX. + +\item ``\verb|\documentstyle[|{\em any options\/}\verb|]{foils}|'' + indicates Foil\TeX. + +\item ``\verb|\documentsytle|'' + indicates \LaTeX. + +\item ``\verb|\document |{\em something\/}'' + indicates AMS\TeX. + +\item ``\verb|\Define|{\em xxx\/}\verb|:|{\em yyy\/}'' + indicates Lollipop. + +\item ``\verb|@node|'' or ``\verb|@ifinfo|'' or ``\verb|input texinfo|'' + indicates Texinfo. +\end{itemize} + +TeXit only searches the first \verb|$TEXHEADERSIZE| lines for these commands. +With the exception of ``\verb|input texinfo|'', they must occur at the +very beginning of a line to be recognized. + +After processing your document, TeXit looks at the log file and re-runs \TeX\ +if the references have changed or the citations have changed. TeXit provides +support for \LaTeX\ and Texinfo logs at the moment. Other formats will be +added upon request. + +\section{More Power!\protect\footnote{grunt, Grunt, GRUNT! ;-) This is a +poor joke. It'll only make sense if you're familiar with the television +sit-com {\em Home Improvement}.}} + +You can extend TeXit by adding ``rules'' to your documents. Rules tell +TeXit how the various pieces of your document are related. It is similar +to ``make'' in many regards, but it is a little better than make for \TeX\ +documents since it can examine the contents as well as the time-stamp +of a file. + +Rules are added by placing a ``rules'' section in your main document file. +For example, this document has the following rules: + +% hackery here so that the first line isn't noticed by TeXit... +\verb| % Start TeXit |\verb|rules:| +\vskip-\baselineskip\vskip-\parskip +\begin{verbatim} + % &cleanup_files ('texittr.tli','texittr.tlo'); + % + % # it doesn't really have this rule, I just wanted to make the + % # example more interesting + % &bibtex('texit') if &newer('myrefs.bib') + % || &missing('texit.bbl'); + % + % &run(treetex texittr'), + % &waitfor('texittr.tli') if &changed('texittr.tlo') + % || &missing('texittr.tli'); + % + % &dependson('texittr.tli'); + % End TeXit rules: +\end{verbatim} + +The ``\verb|Start TeXit rules:|'' and ``\verb|End TeXit rules:|'' lines are +markers. They are required. Leading ``\%'' signs and whitespace are ignored. +Note: if you are using a \TeX\ format that uses some other comment character, +you'll have to protect the rules in some other way. You can't simply use any +comment character that you want. + +The catch is that your rules have to be valid Perl statements. I've +tried to make most of the common things easy to add by hiding them in +functions. If you use the syntax shown, everything will be ok. + +TeXit rules can extend over over multiple lines, but some care must be taken. +When TeXit is parsing the rules, it assumes that any line that {\em ends\/} +with a semi-colon ends the rule. Trailing Perl comments (unescaped ``\#'' +marks) are trimmed off. This allows you to build up a compound statement like +this: + +\begin{verbatim} + % if ($some_conditional) { + % do_this ; # use perl comment to hide the semicolon + % and_this ; # (make sure you hide each one) + % } ; +\end{verbatim} + +Rules can ``do anything'' since they're written in Perl. Use care: don't +change any of TeXit's variables! The rules for a document are evaluated +{\em every\/} time the document is processed. If you want some rules to +be evaluated only once, you can test against ``\verb|$first_time|''. This +variable will only be true once, right before the document is processed +for the first time. + +The following variables are defined before the rules are executed: + +\begin{itemize} + \item \verb|$TEXFILEPATH| + + The pathname of the master file (it always ends in a slash and + is equal to ``./'' if the file has no other path). + + \item \verb|$TEXFILENAME| + + The base name of the master file (no path, no extension). + + \item \verb|$TEXFILEEXT| + + The extension of the master file. + + \item \verb|$TEXFORMAT| + + The english name of the format that TeXit decided to use. +\end{itemize} + +\section{A Short Lesson in Rules} + +If you aren't a Perl aficionado, the following guidelines will help you write +right rules. But be warned, not every statement in this section is the whole +truth. + +Most rules have the form: + +\begin{center} + \verb|&|{\it command}\verb|(|{\it arguments}\verb|) if |% + {\it predicates}\verb|;| +\end{center} + +The following commands are available: + +\begin{itemize} + \item \verb|&bibtex('|{\it arguments}\verb|')| + + Runs the BibTeX program with the arguments specified. + + \item \verb|&tex('|{\it arguments}\verb|')| + + Runs the \TeX\ program with the arguments specified. + + \item \verb|&makeindex('|{\it arguments}\verb|')| + + Runs the MakeIndex program with the arguments specified. + + \item \verb|&run('|{\it command arguments}\verb|')| + + The most general form, this command runs whatever you pass + it, just as if you typed it at the shell prompt. + + \item \verb|&waitfor('|{\it file1}\verb|', '|% + {\it file2}\verb|',|\ldots\verb|)| + + Waits until all the files specified exist. Use care, this can + cause TeXit to ``hang'' forever. I added this condition so that + I could run commands asynchronously on another machine and make + TeXit pause until they were done. + + \item \verb|&auxfile("ext")| + + Returns the name of the auxilliary file with the extension + ``ext''. This allows you to test for files, like the DVI file: + + For example, the test ``\verb|-r &auxfile("dvi")|'' returns true + if the DVI file is readable. + + \item \verb|&cleanup_files('|{\it file1}\verb|', '|% + {\it file2}\verb|',| \ldots\verb|)| + + This command adds ``{\it file1\/}'', ``{\it file2}'', etc., to the + list of files that should be deleted by the cleanup choice. + +\end{itemize} + +The following predicates are available: + +\begin{itemize} + \item \verb|$first_time| + + TeXit runs all of your rules once before running \TeX\ for the + first time. During that one run, the \verb|&first_run| predicate + will be true. All of the other predicates return false during + the first run. + + \item \verb|&dependson('|{\it file1}\verb|', '|% + {\it file2}\verb|',| \ldots\verb|)| + + Tells TeXit that the DVI file for your document depends on + all of the files listed. If any of these files are newer than + the DVI file, \TeX\ will be run again. + + TeXit evaluates your rules in the order they are written. Make + sure that all of your \verb|&dependson| rules occur last. + + \item \verb|&missing('|{\it file1}\verb|', '|% + {\it file2}\verb|',| \ldots\verb|)| + + Returns true if any of the files specified are missing (i.e. + unreadable by your effective userid). + + \item \verb|&changed('|{\it file1}\verb|', '|% + {\it file2}\verb|',| \ldots\verb|)| + + Returns true if any of the files specified have changed since the + last time \TeX\ was run. TeXit saves a checksum of each file across + runs of \TeX\ and compares the checksums. + + \item \verb|&newer('|{\it nfile1, nfile2, \ldots}\verb|', '|% + {\it ofile1, ofile2, \ldots}\verb|')| + + Returns true if any of the ``{\it nfiles}'' are newer than any + of the ``{\it ofiles}'' or if any of the ``{\it ofiles}'' don't + exist. + + Note the different calling sequence for this predicate. You must + pass only two elements to this function: {\em put the list of files + in quotes!} This is different than all the other predicates, I know. + Sorry about that. +\end{itemize} + +\section{Built in Commands} + +When TeXit finishes processing your document, it presents the ``Again?'' +prompt. You should respond to the ``Again?'' prompt with the letter(s) in +square brackets for the command that you want to issue. For example, to run +the ``\verb|[p]rint|'' command, reply ``p''. You can insert a space and +additional options. For example ``p -Pdept1'' runs the print command with the +additional options ``-Pdept1''. How (or if) that argument is interpreted +depends on the command. + +By default, TeXit is configured to supply the following commands: + +\begin{itemize} + \item \verb|[b]ibtex|, \verb|[g]hostview|, \verb|[t]ex|, \verb|[v]iew| + + Runs BibTeX, Ghostview, \TeX, or your previewer, respectively. + + \item \verb|[p]rint| + + Runs a printer. You {\em must\/} specify the name of the printer + queue as an option. Use ``p ?'' to get a list of queues. Additional + options, after the queue name, are passed to either the DVI driver + or the print command: options before a ``\verb+|+'' go to the DVI + driver, options after go the print command. + + For example, the following command ``\verb+p dept1 -p1 -l1|-K2+'' + prints your job to the ``dept1'' printer queue. The DVI driver + sees the options ``-p1 -l1'' and the printer command sees the + options ``-K2''. + + \item \verb|[c]leanup| + + Deletes auxilliary files (log, aux, etc.). This can be configured + in document rules and/or \verb|.texitrc| files. + + \item \verb|e[x]it| + + Exits TeXit. +\end{itemize} + +Section~\ref{sec:examples} illustrates how you can add your own commands. + +\section{Other Initialization} +\label{sec:init} + +The first thing TeXit does after parsing your command line arguments and +finding out what document you want to process is load initialization files. +These files typically set variables like \verb|$TEXRETRIES| and +\verb|$TEXHEADERSIZE|. If they exist, the following scripts are loaded (in +this order): + +\begin{itemize} + \item Some global configuration file + + Support for this option requires editing the script. I don't expect it + to be done very often. + + \item \verb|~/.texitrc| + + The script file found in your home directory. TeXit finds your home + directory by looking for the ``\verb|TEXIT|'' environment + variable and the ``\verb|HOME|'' environment variable. It uses whichever + it finds first. + + You really should set one or the other. If neither is set, your + home directory effectively becomes the current directory. Probably + not what you had in mind. + + \item \verb|$TEXFILEPATH/.texitrc| + + The script file in the same directory as your \TeX\ master document + file. + + \item \verb|-initfile |{\it ifile} + + Finally, any init files that you specify as options are loaded. If you + specify more than one, they are loaded in the order specified. +\end{itemize} + +\section{Some Examples} +\label{sec:examples} + +This section demonstrates some customizations performed in ``\verb|.texitrc|'' +files. These examples should help you figure out how to do some of the +customizations you're likely to want. You can alway send me email if you +want help with a particular customization. + +\subsection{Adding a new command} + +Let's add the \verb|dvitty| program as a new command. First, define +the program name and the command. These could be combined, but it's +better not to for reasons that will become clear in a moment. + +\begin{verbatim} + $DVITTY = "/usr/local/bin/dvi2tty"; + $DVITTYCMD = "$DVITTY %o %d"; +\end{verbatim} + +Table~\ref{tab:percentsubst} shows all of the \%-substitutions that +you can include in the command. + +\begin{table} + \begin{center} + \begin{tabular}{|l|l|} + \hline + \verb|%F| & The format file name \\ + \verb|%s| & The base name of the \TeX\ master file \\ + \verb|%t| & The \TeX\ master file with its extension \\ + \verb|%d| & The DVI file\\ + \verb|%o| & Any options added to the command by the user\\ + \verb|%D| & The DVI file with ``/'' translated to ``$\backslash$''. \\ + \verb|%S| & The base name with ``/'' translated to ``$\backslash$''. \\ + \verb|%T| & The master file with its extension and with ``/'' translated to ``$\backslash$''. \\ + \hline + \end{tabular} + \caption{Percent substitutions performed by TeXit.} + \label{tab:percentsubst} + \end{center} +\end{table} + +The next thing that you need to do is tell TeXit to present this as an option +to the user. In order to do this, you must define two more commands: +\verb|$CMDPROMPT{|{\it cmd-name}\verb|}| and \verb|$CMDTEST{|{\it +cmd-name}\verb|}|. The ``{\it cmd-name}'' is the prompt-string that +will be displayed to the user. Some portion of that string must be in square +brackets. That portion is what the user must enter to run the choice. The +\verb|$CMDPROMPT| is the Perl string that is evaluated if the user +selects that command and the \verb|$CMDTEST| string is evaluated before the +prompt is displayed to see if that command is allowed now. Both of these +strings should be defined in {\em single quotes\/} so that Perl doesn't +do any interpolation when it's defining the command. The \verb|$CMDPROMPT| +string should end with either ``\verb|$RETEX|'' or ``\verb|$REASK|'' depending +on whether you want to re-run \TeX\ or redisplay the prompt. + +Here's how \verb|dvitty| is defined: + +\begin{verbatim} + $CMDPROMPT{"dvi2[tty]"} = '&run($DVITTYCMD, "$opts"); $REASK;'; + $CMDTEST{"dvi2[tty]"} + = '"$DVITTY" && -x "$DVITTY" && -r &auxfile("dvi")'; +\end{verbatim} + +These commands indicate that: + +\begin{itemize} + \item TeXit should add ``\verb|dvi2[tty]|'' to the prompt. + \item The user must respond ``\verb|tty|'' to select this option. + \item The option is only available if \verb|$DVITTY| is defined and + executable and the DVI file exists. + \item If selected, TeXit should run the \verb|$DVITTYCMD| with any + options the user specified (always stored in ``\verb|$opts|'') + and then redisplay the prompt. +\end{itemize} + +Another example: adding a printer queue command. This one's done +a bit sloppily, but it works. + +\begin{verbatim} + $CMDPROMPT{"[q]uery printer"} + = '&run("lpq -P%o", "$opts"); $REASK;'; + $CMDTEST{"[q]uery printer"} = ''; +\end{verbatim} + +\subsection{Adding a New Printer} + +Assuming that the program ``\verb|dvi2bam|'' translates DVI files into output +for the Bambleweenie 2000 printer (translating ``file.dvi'' to ``file.bbw''), +the following commands add the ``\verb|neato|'' printer to TeXit. + +\begin{verbatim} + $DVIBAM = "/usr/local/bin/dvi2bam"; + $DVIBAMCMD = "$DVIBAM %o %d"; + + $PRQUEUE{"neato"} = "bamble"; + $PRINTCMD{"neato"} = "lpr %o %s.bbw"; + $PRINTOPT{"neato"} = "-Pneato"; + + $DVICMD{"bamble"} = $DVIBAMCMD; + $DVIOPT{"bamble"} = ""; +\end{verbatim} + +Adding a new printer, ``\verb|myprinter|'', of the same type is a simple +matter: + +\begin{verbatim} + $PRQUEUE{"myprinter"} = "bamble"; + $PRINTCMD{"myprinter"} = "lpr %o %s.bbw"; + $PRINTOPT{"myprinter"} = "-Pmyprinter"; +\end{verbatim} + +\subsection{Removing a Command} + +To remove a command, undefine one of the things that its ``\verb|$CMDTEST|'' +string tests. For example, to remove Ghostview: + +\begin{verbatim} + undef($GSVIEW); +\end{verbatim} + +This is why you should always put a simple command-defined type test in +your ``\verb|$CMDTEST|'' strings. + +To completely remove a command, delete its entries in the \verb|$CMDTEST| +{\em and\/} \verb|$CMDPROMPT| arrays. If you only delete its entry +in the \verb|$CMDTEST| array, the command will always be available (a +null test is true by default). If you only delete its entry in the +\verb|$CMDPROMPT| array, you will get a runtime error (this is intentional, +it helps catch typos in the array definitions). + +\begin{verbatim} + delete $CMDPROMPT{"[b]ibtex"}; + delete $CMDTEST{"[b]ibtex"}; +\end{verbatim} + +\subsection{Removing a Printer} + +To remove a printer, delete its ``\verb|$PRQUEUE|'' entry. For example, +the following command removes the ``Local'' printer: + +\begin{verbatim} + delete $PRQUEUE{"Local"}; +\end{verbatim} + +\subsection{Other Examples} + +Look in the \verb|.texitrc| files supplied with TeXit for more ideas +and examples. + +\section{Running under OS/2} + +The following file, ``\verb|texit.cmd|'' demonstrates how \verb|texit.pl| +can be run under OS/2. This sort of hackery might not be necessary if you +put \verb|texit.pl| in the Perl library path, but I don't because +the compiled-in path is \verb|c:\perl\lib| which I'm unwilling to use. +I could recompile Perl, I suppose, but on my 386SX box that'd probably +take about a year and a half. Not to mention all the disk space I don't +have. Actually, there's a bug in this port that I would like +to fix, but I won't be able to do that for a while. + +The tricks are: + +\begin{itemize} + \item You have to get the whole pathname to Perl and OS/2 only + passes the path of the command you typed (so if it's on your PATH, it + only gets ``\verb|texit|''. + + \item Having put the pathname on the ``extproc'' line, you have to do + a ``shift'' to get rid of the name that OS/2 put on the command line. + + \item In order for Perl to find the file ``\verb|require|''d, + it must be on the \verb|@INC| path. (You see, it begins with a + drive letter (not a ``/'') so Perl thinks it has to look + for the file. The bug. Sigh.) +\end{itemize} + +\begin{verbatim} + extproc perl -x e:/emtex/texit.cmd + #! perl + shift; # get rid of TEXIT.CMD shoved on by OS/2 + push (@INC, "e:/emtex"); # add emtex to search path + push (@INC, "e:/Perl/lib"); # perl path + require "texit.pl" +\end{verbatim} + +\section{Questions, Suggestions, or Flames?} + +I know this documentation is incomplete (and badly written). I'll try to +answer any questions that you ask and entertain any suggestions that you might +have (no matter {\em how\/} entertaining I think they are ;-). + +In my own defense, I {\em did\/} put lots of comments in the script. It +shouldn't be too inscrutable. + +\end{document} + + +% Start TeXit rules: +% &cleanup_files ('texittr.tli','texittr.tlo'); +% +%# &run('treetex texittr'), &waitfor('texittr.tli') +%# if &changed('texittr.tlo') || &missing('texittr.tli'); +% +% &dependson('texittr.tli'); +% End TeXit rules: + diff --git a/support/tex-it/texitrc.os2 b/support/tex-it/texitrc.os2 new file mode 100644 index 0000000000..267d254df3 --- /dev/null +++ b/support/tex-it/texitrc.os2 @@ -0,0 +1,59 @@ +# This is my .texitrc for OS/2 using emTeX + +# I like to delete a lot more files... +# +@cleanup_latex = ('dvi', 'aux','log','blg','ilg','ind','idx','bbl'); + +# emTeX returns error code 1 for overfull boxes and other non-fatal +# errors, so set $TEXERROR to 2. +# +$TEXERROR = 2; + +# Prompt me to delete files when I'm done using TeXit... +# +$CLEANONEXIT = 1; + +$TEX = "tex386"; # The emTeX executables... +$MAKEINDEX = "makeindx"; +$VIEW = "v.cmd"; # Batch file to view DVI with DVISCR + +$TEXCMD{"default"} = '$TEX %F %o \\input{%s}'; +$TEXCMD{"plain"} = '$TEX %F %o \\input %s'; +$TEXCMD{"texinfo"} = '$TEX %F %o \\input %s'; +$VIEWCMD = '$VIEW %D %o'; + +$DEFAULTFORMAT = "plain"; # Run Plain TeX by default + +%PRQUEUE = (); # Delete all default printers + +$PRQUEUE{"Local"} = "pcl"; # Add Local PCL printer (LaserJet) +$PRQUEUE{"File"} = "pcl"; # Print to file is a PCL printer too + +$DVICMD{"pcl"} = 'lj3.btm %D %o'; # lj3.btm is a batch file to run dvihplj +$DVIOPT{"pcl"} = ""; + +$PRINTCMD{"Local"} = 'copy /b %S.pcl %o lpt1'; +$PRINTOPT{"Local"} = ""; + +$PRINTCMD{"File"} = ""; +$PRINTOPT{"File"} = ""; + +# Delete Ghostview... +delete $CMDPROMPT{$GhostviewReply}; +delete $CMDTEST{$GhostviewReply}; + +# Default action when hitting Enter after TeXing is Viewing... +$DEFAULTCMD{$TeXReply} = $ViewReply; + +# Add a new command which runs TeX and then automatically runs View... +$TeXandViewReply = "[T]eX & View"; +$CMDPROMPT{$TeXandViewReply} = $CMDPROMPT{$TeXReply}; +$CMDTEST{$TeXandViewReply} = $CMDTEST{$TeXReply}; +$AUTOCMD{$TeXandViewReply} = $ViewReply; +$AUTOOPT{$TeXandViewReply} = ""; + +# Add a run-any-command option... +$RunCommand = "[!] run command"; +$CMDPROMPT{$RunCommand} = '&run("$opts",""); $REASK;'; +$CMDTEST{$RunCommand} = ""; + diff --git a/support/tex-it/texitrc.unx b/support/tex-it/texitrc.unx new file mode 100644 index 0000000000..1296c99db8 --- /dev/null +++ b/support/tex-it/texitrc.unx @@ -0,0 +1,157 @@ +########################################################################; +## PLEASE REMEMBER THAT THIS ISN'T REALLY A PERL FILE. IT'S ACTUALLY ##; +## READ AND "EVAL"ED ON A LINE BY LINE BASIS. THE EVALUATOR ACCUM- ##; +## ULATES LINES UNTIL IT FINDS ONE THAT ENDS IN A SEMICOLON. USE ##; +## COMMENT CHARACTERS TO PROTECT SEMICOLONS IN COMPOUND STATEMENTS AND##; +## SEMICOLONS AT THE END OF COMMENTS TO AVOID ACCUMULATING A BUNCH OF ##; +## COMMENTS INTO A STATEMENT. MOST OF THE TIME, PERL SEEMS TO "DO THE##; +## RIGHT THING", BUT IT DOESN'T HURT TO BE CAREFUL. ##; +########################################################################; +## SEE THE COMMENT FOR THE 'require_hack' SUBROUTINE IN texit.pl FOR ##; +## AN EXPLANATION OF THIS UNFORTUNATE BEHAVIOR. IT REALLY ISN'T MY ##; +## FAULT, HONEST! ##; +########################################################################; +# ; +# The .texitrc file that I use on my Unix box at work ; +# ; +# I like to delete a lot more files... ; + +@cleanup_latex = ('aux','log','blg','ilg','ind','idx','bbl','ps'); + +@latex_rules = ( + '$changed = 1 if &changed($TEXFILEPATH . $TEXFILENAME . ".bbl");', + '$changed = 1 if &changed($TEXFILEPATH . $TEXFILENAME . ".toc");', + '$changed = 1 if &changed($TEXFILEPATH . $TEXFILENAME . ".lot");', + '$changed = 1 if &changed($TEXFILEPATH . $TEXFILENAME . ".lof");' +); + +# Ask me about deleting those files on exit.. ; +$CLEANONEXIT = 1; + +# Add some local printers...some PostScript, a PostScript @ 600dpi ; +# and a special printer to demonstrate how TeXit can be setup to ask ; +# for options. ; +# ; +$PRQUEUE{"oos"} = "ps"; +$PRQUEUE{"joshua"} = "ps"; +$PRQUEUE{"xerox1"} = "ps"; +$PRQUEUE{"woper"} = "ps600"; +$PRQUEUE{"qtest"} = "psq"; + +$DVICMD{"psq"} = $DVICMD{"ps"}; +$DVIOPT{"psq"} = $DVIOPT{"ps"}; +$DVIQUERY{"psq"} = "Additional DVI options? "; + +$DVICMD{"ps600"} = "dvips %o %d"; +$DVIOPT{"ps600"} = "-Pwoper"; + +$PRINTCMD{"oos"} = "lpr %o %s.ps"; +$PRINTOPT{"oos"} = "-Poos"; + +$PRINTCMD{"joshua"} = "lpr %o %s.ps"; +$PRINTOPT{"joshua"} = "-Pjoshua"; + +$PRINTCMD{"xerox1"} = "lpr %o %s.ps"; +$PRINTOPT{"xerox1"} = "-Pxerox1 -K2"; + +$PRINTCMD{"woper"} = "lpr %o %s.ps"; +$PRINTOPT{"woper"} = "-Pwoper"; + +$PRINTCMD{"qtest"} = $PRINTCMD{"oos"}; +$PRINTOPT{"qtest"} = $PRINTOPT{"oos"}; +$PRINTQUERY{"qtest"}= "Additional lpr options? "; +$PRINTCONFIRM{"qtest"} = "no"; + +# Rather than having two options, dvitty and Xdvi, let's switch between ; +# them based on the terminal type...actually, just as an example, let's ; +# make the test even more complicated: ; +# ; +# - run xdvi if TERM=xterm ; +# - run dvgt if we're on a Sparc and not an xterm ; +# - run dvi2tty if we're not on a Sparc or an xterm ; +# ; +# This code assumes that your login script sets $HOSTTYPE and $TERM... ; +# ; +if ($ENV{"TERM"} eq "xterm") { + $VIEWCMD = '$VIEW %o %d >/dev/null 2>1 &'; # run xdvi in the background... +} elsif ($ENV{"HOSTTYPE"} eq "sparc") { + $VIEW = "dvigt"; # avoid end of expr +} else { + $VIEW = "dvi2tty"; # avoid end of expr +}; + +# Let's make sure we can find the previewer and turn off the option if ; +# we can't. Print a warning message in that case too... ; +# ; +if (&find_on_path ($ENV{"PATH"}, $VIEW) eq "") { + print "*** Can't find previewer ($VIEW) on path. "; # + print "Viewing disabled. ***\n"; # + delete $CMDTEST{$ViewReply}; # + delete $CMDPROMPT{$ViewReply}; # +}; + +# Uncomment this code if you _always_ want a choice for dvi2tty instead ; +# of using the switch above. For example, if you want dvi2tty as a choice ; +# even if you are running on an Xterm. ; +# ; +#$DVITTY = "/exp/rcf/share/tex/bin/dvi2tty"; +#$DVITTYCMD = "$DVITTY %o %d"; +#$DvittyReply = "dvi2[tty]"; +#$CMDPROMPT{$DvittyReply} = '&run("$DVITTYCMD", "$opts"); $REASK;'; +#$CMDTEST{$DvittyReply} = '"$DVITTY" && -x "$DVITTY" && -r &auxfile("dvi")'; + +# Setting up dvips as a command...; +#$DVIPS = "/usr/local/bin/dvips"; +#$DVIPSCMD = "$DVIPS -o %s.ps %d"; +#$DvipsReply = "dvi[ps]"; +#$CMDPROMPT{$DvipsReply} = '&run("$DVIPSCMD", "$opts"); $REASK;'; +#$CMDTEST{$DvipsReply} = '"$DVIPS" && -x "$DVIPS" && -r &auxfile("dvi")'; + +# Adding a query printer option...; +# +$LpqReply = "[q]uery printer"; +$CMDPROMPT{$LpqReply} = '&run("lpq -P%o", $opts); $REASK;'; +$CMDTEST{$LpqReply} = ''; + +# Delete Ghostview... ; +# ; +delete $CMDPROMPT{$GhostviewReply}; +delete $CMDTEST{$GhostviewReply}; + +# Default action when hitting Enter after TeXing is Viewing... ; +# ; +$DEFAULTCMD{$TeXReply} = $ViewReply; + +# Add a new command which runs TeX and then automatically runs View... ; +# ; +$TeXandViewReply = "[T]eX & View"; +$CMDPROMPT{$TeXandViewReply} = $CMDPROMPT{$TeXReply}; +$CMDTEST{$TeXandViewReply} = $CMDTEST{$TeXReply}; +$AUTOCMD{$TeXandViewReply} = $ViewReply; +$AUTOOPT{$TeXandViewReply} = ""; + +# let ! run any command, but don't bother to show the prompt...The fact ; +# that there are two !'s in this example is coincidence, they are ; +# unrelated. ; +# ; +$RunCommand = "![!] run command"; +$CMDPROMPT{$RunCommand} = '&run("$opts",""); $REASK;'; +$CMDTEST{$RunCommand} = ''; + +# Add an edit command. This is kind of funky because we want to edit ; +# the master TeX file if no option is given, but edit the file specified; +# if a file is given... ; +# We get the editor from the "EDITOR" environment variable or use emacs.; +# This option is hidden because I never use it (the joys of an Xterm, ; +# I guess ;-). It's included just because it's an interesting example. ; +# ; +$EditCommand = "![e]dit a file"; +$EDITOR = $ENV{"EDITOR"}; +$EDITOR = "emacs" if $EDITOR eq ""; +$CMDPROMPT{$EditCommand} = + 'if ("\$opts" eq "") { + &run("\$EDITOR %o &", + \$TEXFILEPATH . \$TEXFILENAME . "." . \$TEXFILEEXT); # + } else { + &run("\$EDITOR %o &", "\$opts"); } '; +$CMDTEST{$EditCommand} = ""; |