├── README.md
├── LICENSE
└── mathgrep
/README.md:
--------------------------------------------------------------------------------
1 | # NAME
2 |
3 | mathgrep - grep through a LaTeX document looking only in math sections
4 |
5 | # SYNOPSIS
6 |
7 | mathgrep [OPTION]... CODE [FILE]...
8 | Apply CODE to mathematics in each FILE or standard input.
9 | Example: mathgrep '/\\hbar/' quantum.tex classical.tex
10 |
11 | Options:
12 | -e, --code CODE Use CODE
13 | -i, --[no]inline Apply CODE to inline math
14 | -d, --[no]display Apply CODE to display math
15 | -E, --environments ENVS Apply CODE to ENVS
16 | -c, --count Only print a count of matching lines per FILE
17 | -l, --files-with-matches Only print FILE names containing matches
18 | -L, --files-without-matches Only print FILE names containing no match
19 | -n, --line-number Print line number with output lines
20 | -R, --preamble Skip preamble (before \begin{document})
21 | -O, --postamble Skip postamble (after \end{document})
22 | -r, --replace [EXT] Print all lines; if EXT is specified then backup
23 | FILE to FILEEXT and redirect output to FILE
24 | -S, --start NUM Start applying CODE at line NUM
25 | -F, --finish NUM Stop applying CODE at line NUM
26 | -U, --colo[u]r [COLOUR] Highlight matches in COLOUR (default: red)
27 | -P, --[no]separate Print a separator between matches
28 | -C, --context NUM Print NUM lines of output context
29 | -B, --before-context NUM Print NUM lines of leading context
30 | -A, --after-context NUM Print NUM lines of trailing context
31 | -h, -?, --help Print help message
32 | --man Print man page
33 | --gpl Print GPL
34 | -v, --verbose Increase verbosity
35 | -s, --quiet Suppress verbosity
36 | -V, --version Print version and exit
37 |
38 | # DESCRIPTION
39 |
40 | **mathgrep** goes through the specified input FILEs (or standard input
41 | if no FILEs are given) applying CODE to any mathematics it
42 | finds. By default, **mathgrep** prints any lines containing
43 | mathematics on which CODE evaluated successfully.
44 |
45 | The CODE is a bit of perl code which does something to `$_`.
46 | For grep-like performace try `m/regexp/`. **mathgrep** can also do
47 | search-and-replace.
48 |
49 | The CODE is evaluated on the whole of a section of mathematics in one
50 | go, even if the mathematics splits across several lines. All the
51 | lines containing the section of mathematics are printed if CODE
52 | evaluated successfully.
53 |
54 | The options and their behaviour are as like to those of grep as I could
55 | make them.
56 |
57 | # OPTIONS
58 |
59 | - **-A NUM, --after-context NUM**
60 |
61 | Print NUM lines of trailing context after a line on which CODE
62 | executes successfully.
63 |
64 | - **-B, --before-context NUM**
65 |
66 | Print NUM lines of leading context after a line on which CODE executes
67 | successfully.
68 |
69 | - **-C, --context NUM**
70 |
71 | Print NUM lines of context either side of a line on which CODE
72 | executes successfully.
73 |
74 | - **-c, --count**
75 |
76 | Suppress normal output, instead print a count of the number of
77 | sections of mathematics on which CODE evaluated successfully. Note:
78 | this may not be the exact number of matches as CODE is applied once to
79 | each section of mathematics.
80 |
81 | - **-d, --\[no\]display**
82 |
83 | Toggles whether to look in display math environments.
84 |
85 | - **-E, --environments ENV\[,ENV\]...**
86 |
87 | Allows the user to specify a list of extra environments to look in.
88 | These are always checked. Multiple instances of this option are
89 | allowed, as are comma-separated lists.
90 |
91 | - **-e, --code CODE**
92 |
93 | Specifies the CODE to apply. This gives a way to ensure that the code
94 | is not swallowed up in another option. Another way is to finish the
95 | list of options with **--** before specifying the CODE.
96 |
97 | - **-F, --finish NUM**
98 |
99 | Finish checking the input after NUM lines. Subsequent lines may still
100 | be printed depending on the status of the **--after-context**,
101 | **--context**, or **--replace** options.
102 |
103 | - **-h, -?, --help**
104 |
105 | Print a summary of all the options and exit.
106 |
107 | - **-i, --\[no\]inline**
108 |
109 | Toggles whether to look in inline math environments.
110 |
111 | - **-l, --files-with-matches**
112 |
113 | Suppress normal output, instead just print the FILE name of a FILE on
114 | which CODE evaluated successfully at least once. Can be meaningfully
115 | combined with **--count**.
116 |
117 | - **-L, --files-without-matches**
118 |
119 | Suppress normal output, instead just print the FILE name of a FILE on
120 | which CODE did not evaluate successfully at all. Cannot be
121 | meaningfully combined with **--count**.
122 |
123 | - **--man**
124 |
125 | Print this manpage and exit.
126 |
127 | - **--gpl**
128 |
129 | Display the GNU Public License and exit (note: it actually displays the GPL
130 | that comes with Perl so if your installation of Perl is not set up correctly
131 | then this might not work).
132 |
133 | - **-n, --line-number**
134 |
135 | Prefix each line of output with its line number within its input file.
136 | Note: if CODE has mucked about with the number of lines in a section
137 | of mathematics then the line count may go a little awry within that
138 | section but it will correct itself again for the next section.
139 |
140 | - **-O, --postamble**
141 |
142 | Stop applying CODE to maths when `\end{document}` has been reached.
143 |
144 | - **-P, --\[no\]separate**
145 |
146 | Toggle whether to print a separator between matches. Default is on,
147 | unless **--replace** has been specified. The separator is `%---%` so
148 | won't mess up running LaTeX on the output.
149 |
150 | - **-R, --preamble**
151 |
152 | Don't start applying CODE to maths until `\begin{document}` has been
153 | reached.
154 |
155 | - **-r, --replace \[EXT\]**
156 |
157 | Prints all lines whether CODE successfully ran or not. If EXT is
158 | specified then it backups up FILE to FILEEXT and redirects the output
159 | to FILE. Similar to the **-i** option of perl.
160 |
161 | - **-s, --quiet**
162 |
163 | Suppress verbosity.
164 |
165 | - **-S, --start NUM**
166 |
167 | Only apply CODE to maths found on or after line NUM. Note: depending
168 | on **--before-context**, **--context**, or **--replace** then lines
169 | before NUM may still be printed.
170 |
171 | - **-U, --colo\[u\]r \[COLOUR\]**
172 |
173 | If CODE is of the form `m/PATTERN/[cgimosx]` or one of its simple
174 | variants then this option colours the matching text; red if COLOUR is
175 | not specified.
176 |
177 | - **-v, --verbose**
178 |
179 | Increase the verbosity level.
180 |
181 | - **-V, --version**
182 |
183 | Print version number and exit.
184 |
185 | # EXAMPLES
186 |
187 | Suppose that `quantum.tex` is
188 |
189 | \documentclass{article}
190 |
191 | \newcommand{\texthbar}{\(\hbar\)}
192 |
193 | \begin{document}
194 |
195 | The number \(\hbar\) is very small. The product, \(\hbar\hbar\) is
196 | miniscule. On the other hand, \(c\), the speed of light is very big.
197 | \[
198 | \hbar = \frac{h}{2\pi}
199 | \]
200 | \begin{myenv}
201 | Think of hbar as your friend.
202 | \end{myenv}
203 |
204 | \end{document}
205 |
206 | Some junk involving \(\hbar\).
207 |
208 | Then the following examples produce the specified output
209 |
210 | `mathgrep '/hbar/' quantum.tex`
211 |
212 | %---%
213 | \newcommand{\texthbar}{\(\hbar\)}
214 | %---%
215 | The number \(\hbar\) is very small. The product, \(\hbar\hbar\) is
216 | %---%
217 | \[
218 | \hbar = \frac{h}{2\pi}
219 | \]
220 | %---%
221 | Some junk involving \(\hbar\).
222 |
223 | `mathgrep --replace -- 's/hbar/hfoo/g' quantum.tex`
224 |
225 | \documentclass{article}
226 |
227 | \newcommand{\texthbar}{\(\hfoo\)}
228 |
229 | \begin{document}
230 |
231 | The number \(\hfoo\) is very small. The product, \(\hfoo\hfoo\) is
232 | miniscule. On the other hand, \(c\), the speed of light is very big.
233 | \[
234 | \hfoo = \frac{h}{2\pi}
235 | \]
236 | \begin{myenv}
237 | Think of hbar as your friend.
238 | \end{myenv}
239 |
240 | \end{document}
241 |
242 | Some junk involving \(\hfoo\).
243 |
244 | Note the `g` option on the `s///`, otherwise the line "The
245 | number..." would have been:
246 |
247 | The number \(\hfoo\) is very small. The product, \(\hfoo\hbar\) is
248 |
249 | `mathgrep --replace .orig 's/hbar/hfoo/g' quantum.tex`
250 |
251 | Produces no output, but `quantum.tex` is now the altered text above
252 | and `quantum.tex.orig` is the original.
253 |
254 | `mathgrep --preamble '/hbar/' quantum.tex`
255 |
256 | %---%
257 | The number \(\hbar\) is very small. The product, \(\hbar\hbar\) is
258 | %---%
259 | \[
260 | \hbar = \frac{h}{2\pi}
261 | \]
262 | %---%
263 | Some junk involving \(\hbar\).
264 |
265 | `mathgrep --postamble '/hbar/' quantum.tex`
266 |
267 | %---%
268 | \newcommand{\texthbar}{\(\hbar\)}
269 | %---%
270 | The number \(\hbar\) is very small. The product, \(\hbar\hbar\) is
271 | %---%
272 | \[
273 | \hbar = \frac{h}{2\pi}
274 | \]
275 |
276 | `mathgrep --noinline --nodisplay --environments myenv '/hbar/' quantum.tex`
277 |
278 | %---%
279 | \begin{myenv}
280 | Think of hbar as your friend.
281 | \end{myenv}
282 |
283 | # NOTES
284 |
285 | This program determines what is mathematics by looking for a matched
286 | pair; for example, `\(` and `\)`. It does not check that the end of
287 | the pair is the correct one, just that it is the next one. Thus on
288 | encountering the text:
289 |
290 | \(x = y \text{ if \(a = b\), otherwise } x = z\)
291 |
292 | the program thinks that `x = y \text{ if \(a = b` is the next bit of
293 | mathematics. Consequently, it won't see the `x = z` part at all.
294 | This sort of thing only happens when the **same** type of mathematical
295 | environment is used inside and outside the `\text` command. On
296 | encountering the text:
297 |
298 | \[x = y \text{ if \(a = b\), otherwise } x = z\]
299 |
300 | then the whole of the inner part is considered as mathematics. Note
301 | that a byproduct of this is that the arguments of `\text` and
302 | `\intertext` are viewed as being in mathematics.
303 |
304 | Another place where this might cause a problem is if you define an
305 | alias for a standard math environment:
306 |
307 | \let\myendalign\endalign
308 | \begin{align}
309 | x = y
310 | \end{myalign}
311 |
312 | then this program will continue slurping in input until it finds the
313 | next `\end{align}`.
314 |
315 | Currently this program does not consider $ and $$ to have anything to
316 | do with mathematics. This is partly because the coding is a bit
317 | tricky (consider the text `$x=y$$a=b$`) but also because $ and $$ are
318 | not actually LaTeX commands but are inherited from TeX. Whilst $ is
319 | synonymous with \\(, $$ and \\\[ are actually slightly different (take a
320 | look at `latex.ltx` if you don't believe me). Maybe if I get bored
321 | one day I'll take a look at implementing it.
322 |
323 | # BUGS
324 |
325 | Whad'dya mean, "I've found a bug."? Impossible. There are no bugs,
326 | only features. To tell me about features, send an email to
327 |
328 | loopspace@mathforge.org
329 |
330 | With the following in the subject line:
331 |
332 | Howay man, av fund ah borg een maathgrip.
333 |
334 | Or open an issue on github at: https://github.com/loopspace/mathgrep
335 |
336 | # AUTHOR
337 |
338 | Andrew Stacey
339 |
340 | # LICENSE
341 |
342 | Copyright (C) 2007 Andrew Stacey
343 |
344 | This program is free software; you can redistribute it and/or mod ify
345 | it under the terms of the GNU General Public License as published by
346 | the Free Software Foundation; either version 2 of the License, or any
347 | later version.
348 |
349 | This program is distributed in the hope that it will be useful, but
350 | WITHOUT ANY WARRANTY; without even the implied warranty of
351 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
352 | General Public License for more details.
353 |
354 | You should have received a copy of the GNU General Public License
355 | along with this program; if not, write to the Free Software
356 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
357 | USA.
358 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/mathgrep:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl -w
2 | #
3 | # mathgrep - grep through a LaTeX document looking only in math sections
4 | #
5 | # Copyright (C) 2007--2016 Andrew Stacey
6 | #
7 | # This program is free software; you can redistribute it and/or mod
8 | # ify it under the terms of the GNU General Public License as
9 | # published by the Free Software Foundation; either version 2 of the
10 | # License, or any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful, but
13 | # WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 | # General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with this program; if not, write to the Free Software
19 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 | # USA.
21 | #
22 |
23 |
24 | use Term::ANSIColor;
25 | use Getopt::Long qw(:config auto_help bundling);
26 | use Pod::Usage;
27 | use strict;
28 |
29 | my (
30 | $inline, # Toggle inline math
31 | $display, # Toggle display math
32 | $count, # Output count of successes
33 | $filename, # Output filename
34 | $lines, # Output line numbers
35 | $preamble, # Skip preamble
36 | $postamble, # Skip postamble
37 | $separate, # Toggle print separator
38 | $help, # Print simple help
39 | $start, # Line to start at
40 | $finish, # Line to finish at
41 | $textcolour, # Whether to colour matches
42 | $defaultcolour, # Default colour for matches
43 | $code, # Perl expr to apply
44 | $man, # Print man page
45 | $gpl, # Print perlgpl
46 | $infile, # Current input file
47 | $matchcount, # Number of successes
48 | $mathend, # Point in line where math ends
49 | $mathstart, # Point in line where math starts
50 | $postmath, # Stuff on line after math
51 | $match, # Did this match succeed?
52 | $premath, # Stuff on line before math
53 | $endmath, # String to match at end of math
54 | $offset, # Offset to start looking at
55 | $mathpattern, # Recognise start of math
56 | $replace, # Are we doing a replace?
57 | $displaymathpattern, # Recognise display math
58 | $extramathpattern, # Recognise extra math
59 | $inlinemathpattern, # Recognise inline math
60 | $reset, # Reset colour
61 | $after, # Context lines after
62 | $before, # Context lines before
63 | $verbose, # Verbosity level
64 | $line, # Current line in file
65 | $mathline, # Line no. at start of math
66 | $outmemory, # Memory for output routine
67 | $outsub, # Output subroutine
68 | $finalout, # Final output subroutine
69 | $presub, # Preamble subroutine
70 | $postsub, # Postamble subroutine
71 | $inhandle, # Input filehandle
72 | $outhandle, # Output filehandle
73 | $version, # Version option
74 | $verstring, # Version message
75 | $insub # Subroutine to set up input
76 | );
77 |
78 | my @mathpatterns; # Used to assemble math pattern
79 | my @mathenvs; # Display math environments
80 | my @extraenvs; # Extra math envs specified by user
81 | my @lines; # Current lines in input
82 |
83 | #
84 | # Default options
85 | #
86 |
87 | $verbose = 0; # No verbosity
88 | $inline = 1; # Check inline math
89 | $display = 1; # Check display math
90 | $after = 0; # No context after match
91 | $before = 0; # No context before match
92 | $defaultcolour = "red"; # Default colour
93 | $verstring = "mathgrep version 1.0, Copyright (C) 2007 Andrew Stacey\nmathgrep comes with ABSOLUTELY NO WARRANTY; for details type\n `mathgrep --man'.\nThis is free software, and you are welcome to redistribute it under certain\nconditions; type `mathgrep --man' for details.";
94 |
95 |
96 |
97 | #
98 | # Get commandline options
99 | #
100 |
101 | GetOptions (
102 | "i|inline!" => \$inline,
103 | # Do we exec on inline maths?
104 | "d|display!" => \$display,
105 | # Do we exec on display maths?
106 | "E|environments=s" => \@extraenvs,
107 | # Extra environments to check
108 | "c|count" => \$count,
109 | # Print a count of successes
110 | "l|files-with-matches" => \$filename,
111 | # Print successful filenames
112 | "L|files-without-matches" => sub {my ($a,$b) = @_; $filename = 0},
113 | # Print successful filenames
114 | "n|line-number" => \$lines,
115 | # Print line numbers
116 | "R|preamble" => \$preamble,
117 | # Do we exec in preamble?
118 | "O|postamble" => \$postamble,
119 | # Do we exec in postamble?
120 | "r|replace:s" => \$replace,
121 | # Are we doing a replace?
122 | "S|start=i" => \$start,
123 | # Line number to start at
124 | "F|finish=i" => \$finish,
125 | # Line number to finish at
126 | "U|colour|color:s" => sub {my ($a, $b) = @_; $textcolour = ($b ? $b : $defaultcolour);},
127 | # Colour in matches
128 | "P|separate!" => \$separate,
129 | # Do we print a separator
130 | "C|context=i" => sub {my ($a,$b) = @_; $after = $before = $b;},
131 | # Lines of context to print
132 | "B|before-context=i" => \$before,
133 | # Lines before a match to print
134 | "A|after-context=i" => \$after,
135 | # Lines after a match to print
136 | "h|?|help" => \$help,
137 | # Print help and exit
138 | "man" => \$man,
139 | # Print help and exit
140 | "gpl" => \$gpl,
141 | # Print perlgpl page and exit
142 | "v|verbose+" => \$verbose,
143 | # Verbosity level
144 | "s|quiet" => sub {$verbose = 0},
145 | "V|version" => \$version,
146 | "e|code=s" => \$code
147 | # Specify code
148 | ) or pod2usage(2);
149 |
150 | # Do our best to make sure that we have a code
151 | @ARGV and !$code and ($code = shift @ARGV);
152 |
153 | # Certain simple conditions mean that we cannot continue
154 | die "$verstring\n" if $version;
155 | pod2usage(-exitval => 1, -verbose => 0) if $help;
156 | pod2usage(-verbose => 2 ) if $man;
157 | exec 'perldoc perlgpl' if $gpl;
158 | pod2usage("$0: No code given.") if (!defined($code));
159 | pod2usage("$0: No files given.") if ((@ARGV == 0) && (-t STDIN));
160 |
161 | # Sort out colour. Only works if code is reasonably simple.
162 |
163 | if (defined($textcolour)) {
164 |
165 | my ($pre,$post,$mods);
166 |
167 | eval {$textcolour = color $textcolour};
168 | pod2usage("$0: Couldn't figure out colour $textcolour: $@\n") if ($@);
169 | $reset = color 'reset';
170 |
171 | pod2usage("$0: Can't mix colour and replace\n") if ($code =~ /^\s*s/);
172 |
173 | $code =~ s/^\s*m?(.)/s$1(/;
174 | $pre = $1;
175 | $code =~ s/(.)([egimosx]*)\s*$/)$1/;
176 | $post = $1;
177 | $mods = $2 . "g";
178 | if ($pre ne $post) {
179 | $code .= $pre;
180 | }
181 | $code .= $textcolour . "\$1" . $reset . $post . $mods;
182 | }
183 |
184 | # Sanity check!
185 | $_ = "junk";
186 | eval $code;
187 | pod2usage("Code doesn't compute: " . $code . "\n$@\n") if $@;
188 |
189 | # The default for the separator should be on, but not if we're doing a
190 | # replace
191 |
192 | $separate = (defined($replace) ? 0 : 1) unless (defined($separate));
193 |
194 | # The way this is set up, we actually need one line more of context
195 | # after a match than we think we do.
196 | $after++;
197 |
198 | &debug(2,"Using code: $code");
199 |
200 | # Assemble the pattern to match against to decide whether or not we
201 | # are in mathematics.
202 |
203 | # Extra environments can be specified using multiple --environments
204 | # options or as comma-separated lists after one such
205 |
206 | @extraenvs and (@extraenvs = split(/,/, join(',', @extraenvs)));
207 |
208 | @mathenvs = ("math", "displaymath","equation", "eqnarray", "align", "gather", "multline", "flalign", "alignat");
209 |
210 | $displaymathpattern = '\\\\begin\{(' . join("\\*?|", @mathenvs) . "\\*?" . ')\}|\\\\\\[';
211 | $inlinemathpattern = '\\\\\(';
212 | $extramathpattern = '\\\\begin\{(' . join("\\*?|", @extraenvs) . "\\*?" . ')\}';
213 |
214 | $inline and push @mathpatterns, $inlinemathpattern;
215 | $display and push @mathpatterns, $displaymathpattern;
216 | @extraenvs and push @mathpatterns, $extramathpattern;
217 |
218 | $mathpattern = join ("|", @mathpatterns);
219 |
220 | pod2usage("$0: No mathematical delimiters specified.\n") unless $mathpattern;
221 |
222 | # If we're not to search past \end{document} we need to know about
223 | # that.
224 |
225 | if ($postamble) {
226 | $mathpattern .= '|\\\\end\{document\}';
227 | }
228 |
229 | # Set up the output routine. Returns anonymous subroutines which
230 | # decide how to process the output.
231 | #
232 | # $outsub gets passed:
233 | # a reference to an array containing the lines to output
234 | # whether or not the last match was successful
235 | # the line number of the start of the array
236 | # a reference to the filehandle to print to
237 | # a reference to an array which allows $outsub to "remember" information
238 | #
239 | # $finalout gets passed:
240 | # the current filename
241 | # the number of matches
242 | # a reference to the filehandle to print to
243 | #
244 | # Neither returns anything
245 |
246 | ($outsub, $finalout) = &outinit(
247 | defined($replace),
248 | $count,
249 | $filename,
250 | $lines,
251 | $after,
252 | $before,
253 | $separate,
254 | \$outmemory
255 | );
256 |
257 | # These routines get called at the start and finish of processing a
258 | # file. The intention is that $presub gets us to where we want to
259 | # start matching and $postsub deals with whatever is left of the file
260 | # once we stop matching.
261 | #
262 | # $presub gets given the input filehandle, the output routine, the
263 | # output filehandle, and the output memory string; it returns the
264 | # first line of input to check and the offset to start at.
265 | #
266 | # $postsub gets given the input filehandle, the output routine, the
267 | # output filehandle, and the output memory string; it returns nothing.
268 |
269 | ($presub, $postsub) = &preinit(
270 | $preamble,
271 | $start,
272 | $after,
273 | defined($replace)
274 | );
275 |
276 | # This sets up the input. It takes one argument, the current
277 | # filename, and returns two references to filehandles: the input and
278 | # output.
279 |
280 | $insub = &ininit(
281 | $replace
282 | );
283 |
284 | # If we have no files, we must be using STDIN. We've already gone
285 | # through a few tests to be sure that we actually have some input so
286 | # we should be fairly safe here.
287 |
288 | unshift(@ARGV, "-") unless @ARGV;
289 |
290 | FILE: foreach $infile (@ARGV) {
291 |
292 | # Reset the number of successes at the start of each file
293 |
294 | $matchcount = 0;
295 |
296 | &debug(2,"Checking file $infile");
297 |
298 | unless (($inhandle,$outhandle) = &$insub($infile)) {
299 | &debug(1, "Couldn't set up input for $infile, skipping");
300 | next FILE;
301 | }
302 |
303 | unless (($line, $offset) = &$presub($inhandle,$outsub,$outhandle,\$outmemory)) {
304 | &debug(1, "No valid input in $infile, skipping");
305 | next FILE;
306 | }
307 |
308 | # Start with some pure, pristine input; possibly with an offset
309 | # value in $offset.
310 |
311 | PROCESS: while () {
312 |
313 | if ($line =~ /^[^%]{$offset}[^%]*?($mathpattern)/) {
314 |
315 | # It's possible that this match was against an
316 | # \end{document} so we first rule out that possibility. We
317 | # don't need to condition this on '$postamble' since we
318 | # could only have matched this if '$postamble' was already
319 | # set.
320 |
321 | if ($1 eq '\end{document}') {
322 |
323 | # Still need to process the line, though.
324 |
325 | &$outsub([$line],0,$.,$outhandle,\$outmemory);
326 |
327 | last PROCESS;
328 | }
329 |
330 | # Otherwise, we matched the start of a math environment
331 | # after the offset (and before any comments); record where
332 | # we started and figure out how this environment should
333 | # end.
334 |
335 | $mathline = $.;
336 | $mathstart = $+[0];
337 | $endmath = &endmath($1);
338 |
339 | # Start forming our array of lines to check
340 | @lines = ($line);
341 |
342 | # Do we have an $endmath on this line?
343 |
344 | if ($lines[0] =~ /^[^%]{$mathstart}[^%]*?($endmath)/) {
345 |
346 | # Record, for posterity, the point in the string where
347 | # this environment ended. This isn't quite the offset
348 | # that we'll need as a replace might do something a bit
349 | # funny; so we record the distance to the /end/ of the
350 | # line.
351 |
352 | $mathend = length($lines[0]) - $-[1];
353 |
354 | } else {
355 |
356 | # No we don't so let's slurp in more input until we get
357 | # a match on the end of this particular math
358 | # environment. Record the end point as before.
359 |
360 | do {
361 | eof($inhandle) and do {
362 | &debug(1,"Input ended while waiting for $endmath");
363 | next FILE;
364 | };
365 |
366 | $line = <$inhandle>;
367 |
368 | push @lines, $line;
369 |
370 | # We might have gotten to the end of where we're
371 | # supposed to get to
372 |
373 | } until (($lines[$#lines] =~ /^[^%]*$endmath/) or (defined($finish) and ($. >= $finish)));
374 |
375 | # If we got a match, it will be before a comment
376 | # character so recording the point at which the
377 | # $endmath started is simple.
378 |
379 | if ($lines[$#lines] =~ /^[^%]*$endmath/) {
380 | $lines[$#lines] =~ /$endmath/;
381 | $mathend = length($lines[$#lines]) - $-[0];
382 | } else {
383 |
384 | # If we didn't get a match but we have still
385 | # reached this point then we have reached the end
386 | # of our input. We still want to process that
387 | # which we have, though.
388 |
389 | $mathend = 0;
390 | }
391 | }
392 |
393 | # We now have a chunk of maths, we know where it started
394 | # and where it ended. Extract the bits before and after
395 | # the maths. This would be a bit neater if "-0" and "0"
396 | # were different numbers as far as substr was concerned!
397 |
398 | $premath = substr($lines[0],0,$mathstart);
399 | if ($mathend) {
400 | $postmath = substr($lines[$#lines],-$mathend);
401 | } else {
402 | $postmath = "";
403 | }
404 |
405 | # Now set $_ to the mathematical bit in the middle. Handle
406 | # two different cases depending on how many lines of input
407 | # we have.
408 |
409 | if ($#lines == 0) {
410 | if ($mathend) {
411 | $_ = substr($lines[0],$mathstart,-$mathend);
412 | } else {
413 | $_ = substr($lines[0],$mathstart);
414 | }
415 | } else {
416 | $_ = substr($lines[0],$mathstart);
417 | for (my $i = 1; $i < $#lines; $i++) {
418 | $_ .= $lines[$i];
419 | }
420 | if ($mathend) {
421 | $_ .= substr($lines[$#lines],0,-$mathend);
422 | } else {
423 | $_ .= $lines[$#lines];
424 | }
425 | }
426 |
427 | # This is where we carry out the match or replacement. Had
428 | # to look at the '/usr/bin/rename' script to see how best
429 | # to handle this. Keep a record of the number of matches,
430 | # simpler to just do this than check $count for whether we
431 | # need to.
432 |
433 | ($match = eval $code) and $matchcount++;
434 |
435 | # Now we decide what to do depending on whether or not we
436 | # got a match. Basic idea is that whatever happened, we
437 | # process all but the last line of our current batch of
438 | # input. The last line of input gets saved for the next
439 | # iteration as there may be more maths on it.
440 |
441 | @lines = split(/(?<=\n)/, $premath . $_ . $postmath);
442 |
443 | $line = pop @lines;
444 |
445 | $offset = length($line) - $mathend;
446 |
447 | &$outsub(\@lines,$match,$mathline,$outhandle,\$outmemory);
448 |
449 | } else {
450 |
451 | # No more maths, so process the current line and proceed.
452 |
453 | &$outsub([$line],0,$.,$outhandle,\$outmemory);
454 |
455 | # Get the next load of input, checking that we can, of
456 | # course.
457 |
458 | if (eof($inhandle)) {
459 | last PROCESS;
460 | }
461 |
462 | $line = <$inhandle>;
463 | $offset = 0;
464 | }
465 |
466 | # Do we exit here?
467 |
468 | if (defined($finish) and ($. > $finish)) {
469 |
470 | # Yes we do, so send the current line off to be processed
471 | # and stop processing lines.
472 |
473 | &$outsub([$line],0,$.,$outhandle,\$outmemory);
474 | last PROCESS;
475 | }
476 | }
477 |
478 | # No more lines to process, but we may still be called upon to
479 | # output some more of our input.
480 |
481 | &$postsub($inhandle,$outsub,$outhandle,\$outmemory);
482 |
483 | &$finalout($infile, $matchcount, $outhandle);
484 |
485 | close $inhandle;
486 | close $outhandle unless ($outhandle eq *STDOUT{IO});
487 | }
488 |
489 | exit;
490 |
491 | # Print helpful messages or debuging messages depending on the
492 | # verbosity level
493 |
494 | sub debug {
495 | my ($v, $m) = @_;
496 | chomp($m);
497 | $m .= "\n";
498 | print STDERR $m if ($v <= $verbose);
499 | }
500 |
501 | # Sets up the subroutines to be run either side of the matching
502 | # process. Returns references to the subroutines.
503 | #
504 | # $pr gets given the input filehandle, the output routine, the output
505 | # filehandle, and the output memory string; it returns the first line
506 | # of input to check and the offset to start at.
507 | #
508 | # $po gets given the input filehandle, the output routine, the output
509 | # filehandle, and the output memory string; it returns nothing.
510 |
511 |
512 | sub preinit {
513 | my ($p, $s, $a, $r) = @_;
514 | my ($pr,$po);
515 | if ($p and $s) {
516 | $pr = sub {
517 | my ($fh,$o,$of,$om) = @_;
518 | return (undef, undef) if eof($fh);
519 |
520 | PREAMBLE: while (<$fh>) {
521 | if (/^[^%]*\\begin\{document\}/) {
522 | last PREAMBLE;
523 | }
524 | &$o([$_],0,$.,$of,$om);
525 | }
526 |
527 | if ($. >= $s) {
528 | return ($_,$+[0]);
529 | }
530 |
531 | while (<$fh>) {
532 | if ($. = $s) {
533 | return ($_,0);
534 | }
535 | &$o([$_],0,$.,$of,$om);
536 | }
537 | return (undef, undef);
538 | };
539 | } elsif ($p) {
540 | $pr = sub {
541 | my ($fh, $o,$of,$om) = @_;
542 | return (undef, undef) if eof($fh);
543 |
544 | while (<$fh>) {
545 | if (/^[^%]*\\begin\{document\}/) {
546 | return ($_,$+[0]);
547 | }
548 | &$o([$_],0,$.,$of,$om);
549 | }
550 | return (undef, undef);
551 | };
552 | } elsif ($s) {
553 | $pr = sub {
554 | my ($fh, $o,$of,$om) = @_;
555 | return (undef, undef) if eof($fh);
556 |
557 | while (<$fh>) {
558 | if ($. = $s) {
559 | return ($_,0);
560 | }
561 | &$o([$_],0,$.,$of,$om);
562 | }
563 | return (undef, undef);
564 | };
565 | } else {
566 | $pr = sub {
567 | my ($fh, $o,$of,$om) = @_;
568 | return (undef, undef) if eof($fh);
569 |
570 | $_ = <$fh>;
571 | return ($_,0);
572 | };
573 | }
574 |
575 | if ($r) {
576 | $po = sub {
577 | my ($fh, $o,$of,$om) = @_;
578 |
579 | while (<$fh>) {
580 | &$o([$_],0,$.,$of,$om);
581 | }
582 |
583 | return;
584 | };
585 | } elsif ($a) {
586 | $po = sub {
587 | my ($fh, $o,$of,$om) = @_;
588 | my $l;
589 |
590 | for (my $i = 0; $i <$a; $i++) {
591 | return if eof($fh);
592 | $l = <$fh>;
593 | &$o([$l],0,$.,$of,$om);
594 | }
595 |
596 | return;
597 | };
598 | } else {
599 | $po = sub {};
600 | };
601 |
602 | return ($pr, $po);
603 | }
604 |
605 | # This takes the string matched at the beginning of a math section and
606 | # returns the regexp which matches at the end.
607 |
608 | sub endmath {
609 | my ($b) = @_;
610 | my $e;
611 | $e = "\\" . $b;
612 | $e =~ s/\*/\\*/;
613 | $e =~ s/\(/\\)/;
614 | $e =~ s/\[/\\]/;
615 | $e =~ s/\{/\\\{/g;
616 | $e =~ s/begin/end/;
617 |
618 | # If we're supposed to stop at an '\end{document}' then let's add
619 | # that to the '$endmath' string to be sure that we stop when we
620 | # get there.
621 |
622 | if ($postamble) {
623 | $e .= '|\\end\{document\}';
624 | }
625 |
626 | return $e;
627 | }
628 |
629 | # This sets up the input routine. It returns a reference to a
630 | # subroutine; this subroutine takes as input the input filename and
631 | # returns references to the input and output filehandles.
632 |
633 | sub ininit {
634 | my ($r) = @_;
635 |
636 | $r and return sub {
637 | my ($i) = @_;
638 | my ($j,$p);
639 |
640 | my $b = $i . $r;
641 | if (-e $b) {
642 | unlink $b or
643 | return (undef,undef);
644 | }
645 |
646 |
647 | link $i, $b
648 | and unlink $i
649 | and open ($j, $b)
650 | and open ($p, ">$i")
651 | and return ($j,$p);
652 |
653 | return (undef,undef);
654 | };
655 |
656 | return sub {
657 | my ($i) = @_;
658 | my $j;
659 |
660 | open ($j, $i)
661 | and return ($j, *STDOUT{IO});
662 |
663 | return (undef,undef)
664 | }
665 | }
666 |
667 | # Set up the ouput routines. The input to the normal output
668 | # subroutine consists of:
669 | # a reference to an array of lines
670 | # whether those lines matched
671 | # the starting line number
672 | # the filehandle to print output on
673 | # a reference to a string which gives the routine "memory"; this can
674 | # be different depending on what the routine wants to remember.
675 | #
676 | # We also set up a routine to be called at the end of each file, this
677 | # takes the filename, the number of matches, and the output filehandle
678 | # as input.
679 |
680 | sub outinit {
681 | my ($r,$c,$f,$l,$a,$b,$s,$u) = @_;
682 | my ($o, $e);
683 |
684 | if ($r) {
685 | $$$u[0] = ($s ? "%---%\n" : "");
686 | $$$u[1] = 0;
687 | $o = sub {
688 | my ($ol,$om,$os,$oh,$ou) = @_;
689 | if ($om != $$$ou[1]) {
690 | print $oh $$$ou[0];
691 | }
692 | for (my $i = 0; $i <= $#$ol; $i++) {
693 | print $oh $$ol[$i];
694 | }
695 | $$$ou[1] = $om;
696 | };
697 |
698 | $e = sub {};
699 |
700 | return ($o, $e);
701 | }
702 |
703 | if ($c and $f) {
704 |
705 | $o = sub {
706 | };
707 |
708 | $e = sub {
709 | my ($ei, $em, $eh) = @_;
710 | print $eh $ei . ": " . $em . "\n";
711 | };
712 |
713 | return ($o, $e);
714 | }
715 |
716 | if (defined($f)) {
717 |
718 | $o = sub {};
719 |
720 | $e = sub {
721 | my ($ei, $em, $eh) = @_;
722 | if (($f and $em) or (!$f and !$em)) {
723 | print $eh $ei . "\n";
724 | }
725 | };
726 |
727 | return ($o,$e);
728 | }
729 |
730 | if ($c) {
731 |
732 |
733 | $o = sub {
734 | };
735 |
736 | $e = sub {
737 | my ($ei, $em, $eh) = @_;
738 | print $eh $em . "\n";
739 | };
740 |
741 | return ($o, $e);
742 | }
743 |
744 | # For this routine, $outmemory is a reference to an array:
745 | # 0: the separator to print between matches
746 | # 1: whether to print a separator next time
747 | # 2: an array of previous lines that we may need to print,
748 | # depending on the setting of $before
749 | # 3: the number of lines we still need to print to ensure that we
750 | # print $after lines after a match
751 |
752 | $$$u[0] = ($s ? "%---%\n" : "");
753 | $$$u[2] = [];
754 |
755 | $o = sub {
756 | my ($ol,$om,$os,$oh,$ou) = @_;
757 |
758 | if ($om) {
759 | print $oh $$$ou[0] if ($$$ou[1]);
760 |
761 | print $oh join('', @{$$$ou[2]});
762 | for (my $i = 0; $i <= $#$ol; $i++) {
763 | if ($l) {
764 | print $oh " " x (4 - length($os)) . $os . ":";
765 | $os++;
766 | }
767 | print $oh $$ol[$i];
768 | }
769 | $$$ou[3] = $a;
770 | $$$ou[2] = [];
771 | $$$ou[1] = 0;
772 | } elsif ($$$ou[3]) {
773 |
774 | if (@{$ol}) {
775 | if ($l) {
776 | print $oh " " x (4 - length($os)) . $os;
777 | print $oh ($$$ou[3] == $a ? ":" : "-");
778 | }
779 |
780 | print $oh join('', @{$ol});
781 | $$$ou[3]--;
782 | }
783 | } else {
784 | if (@{$ol}) {
785 | if ($l) {
786 | push @{$$$ou[2]}, " " x (4 - length($os)) . $os . "-" . $$ol[0];
787 | } else {
788 | push @{$$$ou[2]}, $$ol[0];
789 | }
790 | }
791 |
792 | if ($#{$$$ou[2]} >= $b) {
793 | shift @{$$$ou[2]};
794 | $$$ou[1] = 1;
795 | }
796 | }
797 | };
798 |
799 | $e = sub {};
800 |
801 | return ($o, $e);
802 | }
803 |
804 | __END__
805 |
806 | =head1 NAME
807 |
808 | mathgrep - grep through a LaTeX document looking only in math sections
809 |
810 | =head1 SYNOPSIS
811 |
812 | mathgrep [OPTION]... CODE [FILE]...
813 | Apply CODE to mathematics in each FILE or standard input.
814 | Example: mathgrep '/\\hbar/' quantum.tex classical.tex
815 |
816 | Options:
817 | -e, --code CODE Use CODE
818 | -i, --[no]inline Apply CODE to inline math
819 | -d, --[no]display Apply CODE to display math
820 | -E, --environments ENVS Apply CODE to ENVS
821 | -c, --count Only print a count of matching lines per FILE
822 | -l, --files-with-matches Only print FILE names containing matches
823 | -L, --files-without-matches Only print FILE names containing no match
824 | -n, --line-number Print line number with output lines
825 | -R, --preamble Skip preamble (before \begin{document})
826 | -O, --postamble Skip postamble (after \end{document})
827 | -r, --replace [EXT] Print all lines; if EXT is specified then backup
828 | FILE to FILEEXT and redirect output to FILE
829 | -S, --start NUM Start applying CODE at line NUM
830 | -F, --finish NUM Stop applying CODE at line NUM
831 | -U, --colo[u]r [COLOUR] Highlight matches in COLOUR (default: red)
832 | -P, --[no]separate Print a separator between matches
833 | -C, --context NUM Print NUM lines of output context
834 | -B, --before-context NUM Print NUM lines of leading context
835 | -A, --after-context NUM Print NUM lines of trailing context
836 | -h, -?, --help Print help message
837 | --man Print man page
838 | --gpl Print GPL
839 | -v, --verbose Increase verbosity
840 | -s, --quiet Suppress verbosity
841 | -V, --version Print version and exit
842 |
843 |
844 | =head1 DESCRIPTION
845 |
846 | B goes through the specified input FILEs (or standard input
847 | if no FILEs are given) applying CODE to any mathematics it
848 | finds. By default, B prints any lines containing
849 | mathematics on which CODE evaluated successfully.
850 |
851 | The CODE is a bit of perl code which does something to C<$_>.
852 | For grep-like performace try C. B can also do
853 | search-and-replace.
854 |
855 | The CODE is evaluated on the whole of a section of mathematics in one
856 | go, even if the mathematics splits across several lines. All the
857 | lines containing the section of mathematics are printed if CODE
858 | evaluated successfully.
859 |
860 | The options and their behaviour are as like to those of grep as I could
861 | make them.
862 |
863 | =head1 OPTIONS
864 |
865 | =over 8
866 |
867 | =item B<-A NUM, --after-context NUM>
868 |
869 | Print NUM lines of trailing context after a line on which CODE
870 | executes successfully.
871 |
872 | =item B<-B, --before-context NUM>
873 |
874 | Print NUM lines of leading context after a line on which CODE executes
875 | successfully.
876 |
877 | =item B<-C, --context NUM>
878 |
879 | Print NUM lines of context either side of a line on which CODE
880 | executes successfully.
881 |
882 | =item B<-c, --count>
883 |
884 | Suppress normal output, instead print a count of the number of
885 | sections of mathematics on which CODE evaluated successfully. Note:
886 | this may not be the exact number of matches as CODE is applied once to
887 | each section of mathematics.
888 |
889 | =item B<-d, --[no]display>
890 |
891 | Toggles whether to look in display math environments.
892 |
893 | =item B<-E, --environments ENV[,ENV]...>
894 |
895 | Allows the user to specify a list of extra environments to look in.
896 | These are always checked. Multiple instances of this option are
897 | allowed, as are comma-separated lists.
898 |
899 | =item B<-e, --code CODE>
900 |
901 | Specifies the CODE to apply. This gives a way to ensure that the code
902 | is not swallowed up in another option. Another way is to finish the
903 | list of options with B<--> before specifying the CODE.
904 |
905 | =item B<-F, --finish NUM>
906 |
907 | Finish checking the input after NUM lines. Subsequent lines may still
908 | be printed depending on the status of the B<--after-context>,
909 | B<--context>, or B<--replace> options.
910 |
911 | =item B<-h, -?, --help>
912 |
913 | Print a summary of all the options and exit.
914 |
915 | =item B<-i, --[no]inline>
916 |
917 | Toggles whether to look in inline math environments.
918 |
919 | =item B<-l, --files-with-matches>
920 |
921 | Suppress normal output, instead just print the FILE name of a FILE on
922 | which CODE evaluated successfully at least once. Can be meaningfully
923 | combined with B<--count>.
924 |
925 | =item B<-L, --files-without-matches>
926 |
927 | Suppress normal output, instead just print the FILE name of a FILE on
928 | which CODE did not evaluate successfully at all. Cannot be
929 | meaningfully combined with B<--count>.
930 |
931 | =item B<--man>
932 |
933 | Print this manpage and exit.
934 |
935 | =item B<--gpl>
936 |
937 | Display the GNU Public License and exit (note: it actually displays the GPL
938 | that comes with Perl so if your installation of Perl is not set up correctly
939 | then this might not work).
940 |
941 | =item B<-n, --line-number>
942 |
943 | Prefix each line of output with its line number within its input file.
944 | Note: if CODE has mucked about with the number of lines in a section
945 | of mathematics then the line count may go a little awry within that
946 | section but it will correct itself again for the next section.
947 |
948 | =item B<-O, --postamble>
949 |
950 | Stop applying CODE to maths when C<\end{document}> has been reached.
951 |
952 | =item B<-P, --[no]separate>
953 |
954 | Toggle whether to print a separator between matches. Default is on,
955 | unless B<--replace> has been specified. The separator is C<%---%> so
956 | won't mess up running LaTeX on the output.
957 |
958 | =item B<-R, --preamble>
959 |
960 | Don't start applying CODE to maths until C<\begin{document}> has been
961 | reached.
962 |
963 | =item B<-r, --replace [EXT]>
964 |
965 | Prints all lines whether CODE successfully ran or not. If EXT is
966 | specified then it backups up FILE to FILEEXT and redirects the output
967 | to FILE. Similar to the B<-i> option of perl.
968 |
969 | =item B<-s, --quiet>
970 |
971 | Suppress verbosity.
972 |
973 | =item B<-S, --start NUM>
974 |
975 | Only apply CODE to maths found on or after line NUM. Note: depending
976 | on B<--before-context>, B<--context>, or B<--replace> then lines
977 | before NUM may still be printed.
978 |
979 | =item B<-U, --colo[u]r [COLOUR]>
980 |
981 | If CODE is of the form C or one of its simple
982 | variants then this option colours the matching text; red if COLOUR is
983 | not specified.
984 |
985 | =item B<-v, --verbose>
986 |
987 | Increase the verbosity level.
988 |
989 | =item B<-V, --version>
990 |
991 | Print version number and exit.
992 |
993 | =back
994 |
995 | =head1 EXAMPLES
996 |
997 | Suppose that F is
998 |
999 | \documentclass{article}
1000 |
1001 | \newcommand{\texthbar}{\(\hbar\)}
1002 |
1003 | \begin{document}
1004 |
1005 | The number \(\hbar\) is very small. The product, \(\hbar\hbar\) is
1006 | miniscule. On the other hand, \(c\), the speed of light is very big.
1007 | \[
1008 | \hbar = \frac{h}{2\pi}
1009 | \]
1010 | \begin{myenv}
1011 | Think of hbar as your friend.
1012 | \end{myenv}
1013 |
1014 | \end{document}
1015 |
1016 | Some junk involving \(\hbar\).
1017 |
1018 | Then the following examples produce the specified output
1019 |
1020 | C
1021 |
1022 | %---%
1023 | \newcommand{\texthbar}{\(\hbar\)}
1024 | %---%
1025 | The number \(\hbar\) is very small. The product, \(\hbar\hbar\) is
1026 | %---%
1027 | \[
1028 | \hbar = \frac{h}{2\pi}
1029 | \]
1030 | %---%
1031 | Some junk involving \(\hbar\).
1032 |
1033 |
1034 | C
1035 |
1036 | \documentclass{article}
1037 |
1038 | \newcommand{\texthbar}{\(\hfoo\)}
1039 |
1040 | \begin{document}
1041 |
1042 | The number \(\hfoo\) is very small. The product, \(\hfoo\hfoo\) is
1043 | miniscule. On the other hand, \(c\), the speed of light is very big.
1044 | \[
1045 | \hfoo = \frac{h}{2\pi}
1046 | \]
1047 | \begin{myenv}
1048 | Think of hbar as your friend.
1049 | \end{myenv}
1050 |
1051 | \end{document}
1052 |
1053 | Some junk involving \(\hfoo\).
1054 |
1055 | Note the C option on the C, otherwise the line "The
1056 | number..." would have been:
1057 |
1058 | The number \(\hfoo\) is very small. The product, \(\hfoo\hbar\) is
1059 |
1060 | C
1061 |
1062 | Produces no output, but F is now the altered text above
1063 | and F is the original.
1064 |
1065 | C
1066 |
1067 | %---%
1068 | The number \(\hbar\) is very small. The product, \(\hbar\hbar\) is
1069 | %---%
1070 | \[
1071 | \hbar = \frac{h}{2\pi}
1072 | \]
1073 | %---%
1074 | Some junk involving \(\hbar\).
1075 |
1076 | C
1077 |
1078 | %---%
1079 | \newcommand{\texthbar}{\(\hbar\)}
1080 | %---%
1081 | The number \(\hbar\) is very small. The product, \(\hbar\hbar\) is
1082 | %---%
1083 | \[
1084 | \hbar = \frac{h}{2\pi}
1085 | \]
1086 |
1087 | C
1088 |
1089 | %---%
1090 | \begin{myenv}
1091 | Think of hbar as your friend.
1092 | \end{myenv}
1093 |
1094 |
1095 | =head1 NOTES
1096 |
1097 | This program determines what is mathematics by looking for a matched
1098 | pair; for example, C<\(> and C<\)>. It does not check that the end of
1099 | the pair is the correct one, just that it is the next one. Thus on
1100 | encountering the text:
1101 |
1102 | \(x = y \text{ if \(a = b\), otherwise } x = z\)
1103 |
1104 | the program thinks that C is the next bit of
1105 | mathematics. Consequently, it won't see the C part at all.
1106 | This sort of thing only happens when the B type of mathematical
1107 | environment is used inside and outside the C<\text> command. On
1108 | encountering the text:
1109 |
1110 | \[x = y \text{ if \(a = b\), otherwise } x = z\]
1111 |
1112 | then the whole of the inner part is considered as mathematics. Note
1113 | that a byproduct of this is that the arguments of C<\text> and
1114 | C<\intertext> are viewed as being in mathematics.
1115 |
1116 | Another place where this might cause a problem is if you define an
1117 | alias for a standard math environment:
1118 |
1119 | \let\myendalign\endalign
1120 | \begin{align}
1121 | x = y
1122 | \end{myalign}
1123 |
1124 | then this program will continue slurping in input until it finds the
1125 | next C<\end{align}>.
1126 |
1127 | Currently this program does not consider $ and $$ to have anything to
1128 | do with mathematics. This is partly because the coding is a bit
1129 | tricky (consider the text C<$x=y$$a=b$>) but also because $ and $$ are
1130 | not actually LaTeX commands but are inherited from TeX. Whilst $ is
1131 | synonymous with \(, $$ and \[ are actually slightly different (take a
1132 | look at F if you don't believe me). Maybe if I get bored
1133 | one day I'll take a look at implementing it.
1134 |
1135 | =head1 BUGS
1136 |
1137 | Whad'dya mean, "I've found a bug."? Impossible. There are no bugs,
1138 | only features. To tell me about features, send an email to
1139 |
1140 | loopspace@mathforge.org
1141 |
1142 | With the following in the subject line:
1143 |
1144 | Howay man, av fund ah borg een maathgrip.
1145 |
1146 | Or open an issue on github at: https://github.com/loopspace/mathgrep
1147 |
1148 | =head1 AUTHOR
1149 |
1150 | Andrew Stacey
1151 |
1152 | =head1 LICENSE
1153 |
1154 | Copyright (C) 2007 Andrew Stacey
1155 |
1156 | This program is free software; you can redistribute it and/or mod ify
1157 | it under the terms of the GNU General Public License as published by
1158 | the Free Software Foundation; either version 2 of the License, or any
1159 | later version.
1160 |
1161 | This program is distributed in the hope that it will be useful, but
1162 | WITHOUT ANY WARRANTY; without even the implied warranty of
1163 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1164 | General Public License for more details.
1165 |
1166 | You should have received a copy of the GNU General Public License
1167 | along with this program; if not, write to the Free Software
1168 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
1169 | USA.
1170 |
1171 | =cut
1172 |
--------------------------------------------------------------------------------