groff: update vendor branch to v1.20.1
[dragonfly.git] / contrib / groff / contrib / hdtbl / hdmisc.tmac
1 .\"     -*-     mode: roff      -*-
2 .ig
3
4 hdmisc.tmac
5
6 This file is part of groff, the GNU roff type-setting system.
7
8 Copyright (C) 2005, 2006, 2009 Free Software Foundation, Inc.
9 written by Joachim Walsdorff <Joachim.Walsdorff@urz.uni-heidelberg.de>.
10
11 groff is free software; you can redistribute it and/or modify it under
12 the terms of the GNU General Public License as published by the Free
13 Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
15
16 groff is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19 for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
23
24 ..
25 .
26 .
27 .\" %beginstrip%
28 .
29 .if d getarg \
30 .  nx
31 .
32 .
33 .\"     ******************************************************************
34 .\"     **      Some macros and default settings needed by hdtbl        **
35 .\"     ******************************************************************
36 .
37 .
38 .\"     Utility macro:  .getarg <key> ...
39 .\"
40 .\"             Get macro argument.  This macro searches <key> in the
41 .\"             remaining arguments and assigns its value to a string
42 .\"             register named <key>.  The following syntax forms are
43 .\"             recognized.
44 .\"
45 .\"                     <key>=<val>     Assign <val> to string <key>.
46 .\"                                     <val> must not contain spaces.
47 .\"                     <key>='<val>'   Assign <val> to string <key>.
48 .\"                                     <val> can contain spaces.
49 .\"                     <key>=          Assign `=' to string <key>.
50 .\"                     <key>           Assign `key' to string <key>.
51 .\"
52 .\"             After return, the string `args' contains the remaining
53 .\"             arguments.
54 .\"
55 .\"             Example: With the definition of string `foo' as
56 .\"
57 .\"                     .ds foo aaa=xxx bbb ccc='yyy zzz' ddd= eee
58 .\"
59 .\"             a call to `getarg' with
60 .\"
61 .\"                     .getarg ccc \*[foo]
62 .\"
63 .\"             sets string `ccc' to value `yyy zzz'.  The string `args'
64 .\"             now contains `aaa=xxx bbb ddd= eee'.  An additional call
65 .\"             like
66 .\"
67 .\"                     .getarg ddd \*[args]
68 .\"
69 .\"             sets string `ddd' to value `=', and `args' contains
70 .\"             `aaa=xxx bbb eee'.
71 .de getarg
72 .  ds \\$1
73 .  ds args
74 .
75 .  if (\\n[.$] < 2) \
76 .    return
77 .
78 .  ds $1 \\$1\"
79 .  shift
80 .
81 .  length * \\*[$1]
82 .  while \\n[.$] \{\
83 .    ds * "\\$1\"
84 .    ds ** "\\$1\"
85 .    length ** \\*[**]
86 .    shift
87 .    if (\\n[*] > \\n[**]) \{\
88 .      as args " "\\*[**]"\"                    value too short, repeat
89 .      continue
90 .    \}
91 .    substring * 0 (\\n[*] - 1)
92 .    \" The surrounding \? escapes emulate string comparison.
93 .    ie !"\?\\*[$1]\?"\?\\*[*]\?" \{\
94 .      as args " "\\*[**]"\"                    key not found, repeat
95 .      continue
96 .    \}
97 .    el \{\
98 .      ie "\?\\*[**]\?"\?\\*[$1]\?" \
99 .        ds \\*[$1] \\*[$1]\"                   return key as string
100 .      el \{\
101 .        ie "\?\\*[**]\?"\?\\*[$1]=\?" \
102 .          ds \\*[$1] =\"                       return `='
103 .        el \{\
104 .          substring ** (\\n[*] + 1) -1
105 .          ds * \\*[**]\"
106 .          substring * 0 0
107 .
108 .          \" check whether value starts with quote
109 .          if "\?\\*[*]\?"\?'\?" \{\
110 .            substring ** 1 -1
111 .            ds * \\*[**]\"
112 .            substring * -1 -1
113 .
114 .            \" search final quote
115 .            ie "\?\\*[*]\?"\?'\?" \
116 .              substring ** 0 -2
117 .            el \{\
118 .              as \\*[$1] \\*[**] \"            not found, append argument
119 .
120 .              while 1 \{\
121 .                ds ** \\$1\"                   get next argument
122 .                ds * \\$1\"
123 .                shift
124 .                substring * -1 -1
125 .
126 .                if "\?\\*[*]\?"\?'\?" \{\
127 .                  substring ** 0 -2
128 .                  break                \"      break if no final quote
129 .                \}
130 .
131 .                as \\*[$1] \\*[**] \"          otherwise append and repeat
132 .              \}
133 .          \}\}
134 .
135 .          as \\*[$1] \\*[**]\"
136 .        \}
137 .
138 .        as args " \\$@\"
139 .    \}\}
140 .
141 .    return
142 .  \}
143 ..
144 .
145 .
146 .\"     Utility macro:  .index <string1> <string2>
147 .\"
148 .\"             Check whether <string2> is a substring of <string2> and
149 .\"             return its position in number register `index', starting
150 .\"             with 1.  If not found, return 0.  If <string2> is empty,
151 .\"             set `index' to -999.
152 .de index
153 .  if "\\$2"" \{\
154 .    nr index -999
155 .    return
156 .  \}
157 .
158 .  length ** \\$1\a
159 .  length $2 \\$2
160 .  nr * 0-1 1
161 .
162 .  while (\\n+[*] < \\n[**]) \{\
163 .    ds * \\$1\a\"
164 .    substring * \\n[*] (\\n[*] + \\n[$2] - 1)
165 .    \" The surrounding \? escapes emulate string comparison.
166 .    if "\?\\*[*]\?"\?\\$2\?" \
167 .      break
168 .  \}
169 .
170 .  ie (\\n[*] == \\n[**]) \
171 .    nr index 0
172 .  el \
173 .    nr index (\\n[*] + 1)
174 ..
175 .
176 .
177 .\"     ******************************************************************
178 .\"     ********        non-accumulating space .SP [v]          **********
179 .\"     **                                                              **
180 .\"     **      nl vor erster Seite -1, oben auf Seite 0 resp. tH       **
181 .\"     **      .k nach .sp oder .br 0,                                 **
182 .\"     **              sonst Laenge der angefangenen Zeile             **
183 .\"     **      Der Merker M# fuer vorangegangenes .SP wird in .HM am   **
184 .\"     **      Seitenanfang zurueckgesetzt.                            **
185 .\"     **      ganz richtig ist .sp + .br = .br + .sp = .sp            **
186 .\"     ******************************************************************
187 .de SP
188 .  if (\\n[nl] < 0) \
189 .    br                 \"      start very first page
190 .  nr * \\n[.p]         \"      save current page length
191 .
192 .  ie "\\$1"" \
193 .    pl +1              \"      without arg increase page length by 1v
194 .  el \
195 .    pl +\\$1           \"      otherwise use \\$1
196 .
197 .  nr ** (\\n[.p] - \\n[*])     \" ** now holds arg for .SP in base units
198 .  pl \\n[*]u           \"      restore page length
199 .
200 .  \" we do nothing at start of new page or column
201 .  if ((\\n[nl] - \\n[tH]) & (\\n[nl] - \\n[<<]) : \\n[.k]) \{\
202 .    ie ((\\n[.d] - \\n[M#]) : \\n[.k]) \{\
203 .      sp \\n[**]u      \"      execute .sp
204 .      nr S# \\n[**]    \"      store ** in S#
205 .    \}
206 .    el \{\
207 .      if (\\n[**] - \\n[S#]) \{\
208 .        sp (\\n[**]u - \\n[S#]u)\"     emit difference to previous .SP
209 .        nr S# \\n[**]  \"      store ** in S#
210 .    \}\}
211 .
212 .    nr M# \\n[.d]      \"      store vertical position .d in M#
213 .  \}
214 ..
215 .
216 .
217 .\"     ******************************************************************
218 .\"     **              Perform all arguments once                      **
219 .\"     **                      P1 is nestable                          **
220 .\"     ******************************************************************
221 .de P1
222 .  \" `while' command is about five times faster than recursion!
223 .  while \\n[.$] \{\
224 .    nop \\$1
225 .    shift
226 .  \}
227 ..
228 .
229 .
230 .\"     ******************************************************************
231 .\"     **      Hilfsmakro zum Einstellen von Schriftgroesse und        **
232 .\"     **      Zeilenabstand, bezogen auf Anfangswerte \n[s] und \n[v] **
233 .\"     **      sowie fuer Hyphenation:                                 **
234 .\"     **              .pv s v hy# hart;  macht .br                    **
235 .\"     **      Bei 4. Argument setzen der Register s und v und hy.     **
236 .\"     **      Fuer angefangene Zeile die vorgefundenen Einstellungen  **
237 .\"     ******************************************************************
238 .de pv
239 .  br
240 .
241 .  if \\n[.$] \
242 .    ps (\\n[s]u * \\$1z / 1z)
243 .
244 .  ie (\\n[.$] - 1) \
245 .    vs (\\n[v]u * \\$2p / 1p)
246 .  el \{\
247 .    vs (\\n[v]u * \\$1p / 1p)
248 .    return
249 .  \}
250 .
251 .  if !""\\$3" \
252 .    hy \\$3
253 .
254 .  if !""\\$4" \{\
255 .    nr v \\n[.v]
256 .    nr s \\n[.ps]
257 .    nr hy \\n[.hy]
258 .  \}
259 ..
260 .
261 .
262 .\"     ******************************************************************
263 .\"     **              Hilfsmakros pop/pops/popr (pop stackelement):   **
264 .\"     **              pop or popr:    pop register                    **
265 .\"     **              pops:           pop string                      **
266 .\"     **              .pop[s|r] reg|string stackname                  **
267 .\"     **                  reg|string: name of reg/string to get the   **
268 .\"     **                       popped element                         **
269 .\"     **                  stack: name of stack                        **
270 .\"     ******************************************************************
271 .de *pop
272 .  ie "\\$1"pops" \
273 .    ds \\$2 \\$4\"             pop first stackelement
274 .  el \
275 .    nr \\$2 \\$4
276 .
277 .  ds $3 \\$3\"                 remember stackname
278 .  shift 4              \"      shift four args
279 .
280 .  ds \\*[$3] "\\$@\"           fill stack with remaining elements
281 ..
282 .
283 .de pop
284 .  *pop \\$0 \\$1 \\$2 \\*[\\$2]
285 ..
286 .
287 .als popr pop
288 .als pops pop
289 .
290 .
291 .\"     ******************************************************************
292 .\"     **              processs diversion                              **
293 .\"     ******************************************************************
294 .de DI
295 .  nr * \\n[.u]
296 .  nf           \"      diversion is already formatted - output it unchanged
297 .  \\$1         \"      output the diversion ...
298 .  rm \\$1      \"      ... and remove it
299 .  if \\n[*] \
300 .    fi         \"      reactivate formatting
301 ..
302 .
303 .
304 .\"     ******************************************************************
305 .\"     **      Some macros and the page setup used by the examples     **
306 .\"     ******************************************************************
307 .
308 .\"     ******************************************************************
309 .\"     **      some of the following macros use system commands        **
310 .\"     **      and are therefore `unsafe': they need the `-U' argument **
311 .\"     **      when calling groff/troff                                **
312 .\"     ******************************************************************
313 .
314 .\"     ******************************************************************
315 .\"     **              Header macro for the examples                   **
316 .\"     ******************************************************************
317 .de H
318 .  nr *w* (17 * \w\a\\$*\a / 10 + 4n)
319 .  TBL border=1n \
320        bc=yellow \
321        bgc=red4 \
322        fgc=yellow \
323        csp=0 \
324        fst=TB \
325        "fsz=1.7 1.5" \
326        hal=c \
327        tal=c \
328        "width=(\\n[*w*]+4n)<?\n[.l]"
329 .  TR .TD
330 .  P1 \\$*
331 .  ETB
332 .  SP
333 ..
334 .
335 .
336 .\"     ******************************************************************
337 .\"     **      Utility macro for the date, requires UNIX date.         **
338 .\"     **      after return string *date contains the date in the      **
339 .\"     **      standard form of the Unix date-command,                 **
340 .\"     **      for example "Sun Dec  5 22:27:57     2004"              **
341 .\"     ******************************************************************
342 .de date
343 .  pso bash -c "echo -n .ds *date\ ;date"
344 .  tm \\*[*date] ***
345 ..
346 .
347 .
348 .\"     ******************************************************************
349 .\"     **      Utility macro for time measurement, requires UNIX date  **
350 .\"     **      .time s[tart]|[end]                                     **
351 .\"     **              .time start:                                    **
352 .\"     **                      reg *time gets the start-time (seconds) **
353 .\"     **              .time [end]:                                    **
354 .\"     **                      reg *time gets the difference of the    **
355 .\"     **                              end- and start-time (seconds)   **
356 .\"     ******************************************************************
357 .de time
358 .  ds * \\$1\"
359 .  substring * 0 0
360 .  ie "\\*[*]"s" \
361 .    pso bash -c "echo -n .nr *time 0+;date +%s"
362 .  el \{\
363 .   pso bash -c "echo -n .nr *time -;date +%s"
364 .   nr *time 0-\\n[*time]
365 .   tm elapsed time: \\n[*time] seconds
366 .  \}
367 ..
368 .
369 .
370 .\"     ******************************************************************
371 .\"     **              Perform n-times all the arbitrary arguments     **
372 .\"     **              .PN n a2 a3 ...                                 **
373 .\"     **                      PN is nestable                          **
374 .\"     ******************************************************************
375 .de PN
376 .  nr *pn +1
377 .  nr PN\\n[*pn] (\\$1 + 1) 1
378 .  shift
379 .
380 .  while \\n-[PN\\n[*pn]] \
381 .    P1 \\$@
382 .
383 .  nr *pn -1
384 ..
385 .
386 .
387 .\"     Utility macro:  .d2x decimal_number [base [string_name]]
388 .\"
389 .\"             Convert `decimal_number' to another base `base' (in the
390 .\"             range 1..16) and store the result in string `string_name'.
391 .\"             If `base' is missing or empty, convert to a hexadecimal
392 .\"             number.  If `string_name' is missing or empty, return value
393 .\"             in string `hex#', otherwise return the value in both
394 .\"             `string_name' and `hex#'.
395 .\"
396 .\"             The base value 1 is handled specially: The returned
397 .\"             string contains the character `|' `decimal_number' times
398 .\"             (for example, input value 4 yields `||||').
399 .ds d2x-0 0\"
400 .ds d2x-1 1\"
401 .ds d2x-2 2\"
402 .ds d2x-3 3\"
403 .ds d2x-4 4\"
404 .ds d2x-5 5\"
405 .ds d2x-6 6\"
406 .ds d2x-7 7\"
407 .ds d2x-8 8\"
408 .ds d2x-9 9\"
409 .ds d2x-10 A\"
410 .ds d2x-11 B\"
411 .ds d2x-12 C\"
412 .ds d2x-13 D\"
413 .ds d2x-14 E\"
414 .ds d2x-15 F\"
415 .
416 .
417 .de d2x
418 .  if !\B\a\\$1\a \{\
419 .    tm \\n[.F]:\\n[.c]: invalid or missing first argument
420 .    tm1 "     usage: `.d2x decimal_number [base [string_name]]'
421 .    return
422 .  \}
423 .
424 .  nr i# (-1) 1
425 .  nr j# 1
426 .  ds hex#
427 .  nr dec# (\\$1) 1
428 .
429 .  if !\\$1 \
430 .    nr dec# (-\\n[dec#])
431 .
432 .  ie !"\\$2"" \{\
433 .    ie !\B\a\\$2\a \
434 .      tm \\n[.F]:\\n[.c]: invalid base `\\$2'
435 .    el \
436 .      ie ((\\$2 < 1) : (\\$2 > 16)) \
437 .        tm \\n[.F]:\\n[.c]: invalid base `\\$2'
438 .      el \
439 .        nr b# \\$2
440 .  \}\}
441 .  el \
442 .    nr b# 16
443 .
444 .  nr xb# 1
445 .
446 .  ie (\\n[b#] == 1) \{\
447 .    nr dec# +1
448 .    while \\n-[dec#] \
449 .      as hex# |\"
450 .  \}
451 .  el \{\
452 .    while (\\n[dec#] - \\n[xb#]) \{\
453 .      nr xb# (\\n[xb#] * \\n[b#])
454 .      nr j# +1
455 .    \}
456 .
457 .    while (\\n+[i#] < \\n[j#]) \{\
458 .      nr ** (\\n[dec#] / \\n[xb#])
459 .      as hex# \\*[d2x-\\n[**]]\"
460 .      nr dec# (\\n[dec#] - (\\n[xb#] * \\n[**]))
461 .      nr xb# (\\n[xb#] / \\n[b#])
462 .    \}
463 .  \}
464 .
465 .  \" strip leading zero, if any
466 .  ds * \\*[hex#]\"
467 .  substring * 0 0
468 .  if "\\*[*]"0" \
469 .    substring hex# 1 -1
470 .
471 .  if (\\$1 < 0) \
472 .    ds hex# -\\*[hex#]\"
473 .
474 .  if !"\\$3"" \{\
475 .    ie !\A\a\\$3\a \
476 .      tm \\n[.F]:\\n[.c]: invalid string name `\\$3'
477 .    el \
478 .      ds \\$3 \\*[hex#]\"
479 .  \}
480 ..
481 .
482 .
483 .\"     Utility macro:  .random#
484 .\"                     .random-seed seed1 seed2
485 .\"
486 .\"             Return pseudo-random numbers in the range 0..0xFFFFFF,
487 .\"             represented as the concatenation of `#' and six
488 .\"             hexadecimal digits, in the string `#random'.  The
489 .\"             macro `random-seed' can be used to set seed values,
490 .\"             which should be integers in the range 1..2147483562 and
491 .\"             1..2147483398 for `seed1' and `seed2', respectively
492 .\"             (the macro applies a modulo operation to assure this
493 .\"             range).  If `random-seed' isn't called the registers
494 .\"             `seconds', `minutes', `hours', `dy', `mo', `year', and
495 .\"             `$$' are used to compute it.
496 .\"
497 .\"             The used generator is presented in L'Ecuyer's 1988 paper
498 .\"             `Efficient and Portable Combined Random Number
499 .\"             Generators', which combines two Multiplicative Linear
500 .\"             Congruential Generators (MLCGs) to achieve a period of
501 .\"             2.3*10^18.
502 .af hours 00
503 .af minutes 00
504 .af seconds 00
505 .af year 0000
506 .af mo 00
507 .af dy 00
508 .
509 .ds random-s1 \n[minutes]\n[seconds]\n[$$]\n[hours]\"
510 .\" prevent overflow
511 .substring random-s1 0 8
512 .
513 .nr random-s1 (\*[random-s1] % 2147483562)
514 .nr random-s2 \n[dy]\n[year]\n[mo]
515 .
516 .
517 .de random-seed
518 .  if !(\\n[.$] == 2) \{\
519 .    tm1 "random-seed: Invalid number of arguments.
520 .    tm1 "             usage: `.random-seed seed1 seed2'
521 .    return
522 .  \}
523 .
524 .  nr random-s1 (\\$1 % 2147483562)
525 .  nr random-s2 (\\$2 % 2147483398)
526 ..
527 .
528 .
529 .de random#
530 .  nr * (\\n[random-s1] / 53668)
531 .  nr random-s1 (40014 * (\\n[random-s1] - (\\n[*] * 53668)) \
532                 - (\\n[*] * 12211))
533 .  if !\\n[random-s1] \
534 .    nr random-s1 +2147483563
535 .
536 .  nr * (\\n[random-s2] / 52774)
537 .  nr random-s2 (40692 * (\\n[random-s2] - (\\n[*] * 52774)) \
538                 - (\\n[*] * 3791))
539 .  if !\\n[random-s2] \
540 .    nr random-s2 +2147483399
541 .
542 .  nr * (\\n[random-s1] - \\n[random-s2])
543 .  if (\\n[*] < 1) \
544 .    nr * +2147483562
545 .
546 .  \" reduce the result to the leftmost 24 bits
547 .  nr * (\\n[*] / 128)
548 .
549 .  d2x \\n[*]
550 .  ds hex# 000000\\*[hex#]\"
551 .  substring hex# -6
552 .  ds #random #\\*[hex#]\"
553 ..
554 .
555 .
556 .\"     ******************************************************************
557 .\"     **                      minimal Page setup                      **
558 .\"     ******************************************************************
559 .
560 .nr s \n[.ps]
561 .nr v \n[.v]
562 .pv 1.2 1.2 "" X
563 .nr l 6.6i                              \"      set text width
564 .ll \n[l]u
565 .nr o 2c                                \"      set offset
566 .po \n[o]u
567 .nr p 29.7c                             \"      set paper length (A4)
568 .pl \n[p]u
569 .nr tH 1i                               \"      set top margin
570 .sp |\n[tH]u
571 .
572 .ev 99
573 .lt \n[l]u
574 .ev
575 .
576 .
577 .de HM
578 .  sp |.5i                              \"      print header in top margin
579 .  tl \\*[t*HM]
580 .  sp |\\n[tH]u
581 .  ev
582 ..
583 .
584 .
585 .de BM
586 .  ev 99
587 .  sp |(\\n[p]u - .5i)                  \"      print footer in bottom margin
588 .  tl \\*[t*BM]
589 .  bp
590 ..
591 .
592 .
593 .de EM
594 .  rm BM                        \"      no page number at bottom of last page
595 .
596 .  if !"\\*[t*kept]"" \{\
597 .    tm1 "hdtbl: Not all tables have been printed.
598 .    tm1 "       Add `.bp' at the end of your document.
599 .  \}
600 .  if !"\\*[t*held]"" \{\
601 .    tm1 "hdtbl: There are held tables which haven't been printed.
602 .    tm1 "       Add `.t*free' at the end of your document.
603 .  \}
604 .  if \\n[t*#] \
605 .    tm hdtbl: Missing `.ETB' macro at end of document.
606 ..
607 .
608 .
609 .em EM
610 .
611 .if "\n[.m]"" \
612 .  gcolor black
613 .if "\n[.M]"" \
614 .  fcolor white
615 .
616 .mso hdtbl.tmac\"                       load table macros
617 .
618 .\" EOF