Version bump.
[u/mdw/catacomb] / mp.h
CommitLineData
d03ab969 1/* -*-c-*-
2 *
a790733d 3 * $Id: mp.h,v 1.3 1999/11/19 13:19:14 mdw Exp $
d03ab969 4 *
d3409d5e 5 * Simple multiprecision arithmetic
d03ab969 6 *
7 * (c) 1999 Straylight/Edgeware
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of Catacomb.
13 *
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 */
29
30/*----- Revision history --------------------------------------------------*
31 *
32 * $Log: mp.h,v $
a790733d 33 * Revision 1.3 1999/11/19 13:19:14 mdw
34 * Fix const annotation.
35 *
d3409d5e 36 * Revision 1.2 1999/11/17 18:02:16 mdw
37 * New multiprecision integer arithmetic suite.
d03ab969 38 *
39 */
40
41#ifndef MP_H
42#define MP_H
43
44#ifdef __cplusplus
45 extern "C" {
46#endif
47
48/*----- Header files ------------------------------------------------------*/
49
d3409d5e 50#include <assert.h>
d03ab969 51#include <string.h>
52
d3409d5e 53#include <mLib/sub.h>
54
55#ifndef MPW_H
56# include "mpw.h"
d03ab969 57#endif
58
59#ifndef MPX_H
60# include "mpx.h"
61#endif
62
d03ab969 63/*----- Data structures ---------------------------------------------------*/
64
65typedef struct mp {
d3409d5e 66 mpw *v, *vl;
67 size_t sz;
68 unsigned f;
69 unsigned ref;
d03ab969 70} mp;
71
d3409d5e 72#define MP_NEG 1u
73#define MP_BURN 2u
74#define MP_CONST 4u
75#define MP_UNDEF 8u
d03ab969 76
d3409d5e 77/*----- Useful constants --------------------------------------------------*/
d03ab969 78
d3409d5e 79extern mp mp_const[];
d03ab969 80
d3409d5e 81#define MP_ZERO (&mp_const[0])
82#define MP_ONE (&mp_const[1])
83#define MP_TWO (&mp_const[2])
84#define MP_THREE (&mp_const[3])
85#define MP_FOUR (&mp_const[4])
86#define MP_FIVE (&mp_const[5])
87#define MP_TEN (&mp_const[6])
88#define MP_MONE (&mp_const[7])
d03ab969 89
d3409d5e 90#define MP_NEW ((mp *)0)
d03ab969 91
d3409d5e 92/*----- Memory allocation hooks -------------------------------------------*/
d03ab969 93
d3409d5e 94#ifndef MPARENA_H
95# include "mparena.h"
96#endif
97
98/* --- @MP_ARENA@ --- *
d03ab969 99 *
d3409d5e 100 * This selects where memory is allocated from. Tweak to use more fancy
101 * things like custom arenas.
102 */
103
104#ifndef MP_ARENA
105# define MP_ARENA MPARENA_GLOBAL
106#endif
107
108/* --- @MP_ALLOC@ --- *
d03ab969 109 *
d3409d5e 110 * Arguments: @size_t sz@ = size required
111 *
112 * Returns: Pointer to an allocated vector of the requested size.
d03ab969 113 *
d3409d5e 114 * Use: Hook for vector allocation.
d03ab969 115 */
116
d3409d5e 117#ifndef MP_ALLOC
118# define MP_ALLOC(sz) mpalloc(MP_ARENA, (sz))
119#endif
d03ab969 120
d3409d5e 121/* --- @MP_FREE@ --- *
122 *
123 * Arguments: @mpw *v@ = pointer to vector
d03ab969 124 *
d3409d5e 125 * Returns: ---
d03ab969 126 *
d3409d5e 127 * Use: Hook for vector deallocation.
d03ab969 128 */
129
d3409d5e 130#ifndef MP_FREE
131# define MP_FREE(v) mpfree(MP_ARENA, (v))
132#endif
d03ab969 133
d3409d5e 134/*----- Paranoia management -----------------------------------------------*/
135
136/* --- @mp_burn@ --- *
d03ab969 137 *
d3409d5e 138 * Arguments: @mp *m@ = pointer to a multiprecision integer
d03ab969 139 *
140 * Returns: ---
141 *
d3409d5e 142 * Use: Marks the integer as `burn-after-use'. When the integer's
143 * memory is deallocated, it is deleted so that traces can't
144 * remain in the swap file. In theory.
d03ab969 145 */
146
d3409d5e 147extern void mp_burn(mp */*m*/);
d03ab969 148
d3409d5e 149/*----- Trivial macros ----------------------------------------------------*/
150
151/* --- @MP_LEN@ --- *
d03ab969 152 *
d3409d5e 153 * Arguments: @mp *m@ = pointer to a multiprecision integer
d03ab969 154 *
d3409d5e 155 * Returns: Length of the integer, in words.
d03ab969 156 */
157
d3409d5e 158#define MP_LEN(m) ((m)->vl - ((m)->v))
d03ab969 159
d3409d5e 160/*----- Memory management and reference counting --------------------------*/
161
162/* --- @mp_create@ --- *
d03ab969 163 *
d3409d5e 164 * Arguments: @size_t sz@ = size of vector required
d03ab969 165 *
d3409d5e 166 * Returns: Pointer to pristine new MP structure with enough memory
167 * bolted onto it.
d03ab969 168 *
d3409d5e 169 * Use: Creates a new multiprecision integer with indeterminate
170 * contents. The integer has a single reference.
d03ab969 171 */
172
d3409d5e 173extern mp *mp_create(size_t /*sz*/);
d03ab969 174
d3409d5e 175/* --- @mp_build@ --- *
d03ab969 176 *
d3409d5e 177 * Arguments: @mp *m@ = pointer to an MP block to fill in
178 * @mpw *v@ = pointer to a word array
179 * @mpw *vl@ = pointer just past end of array
d03ab969 180 *
181 * Returns: ---
182 *
d3409d5e 183 * Use: Creates a multiprecision integer representing some smallish
184 * number. You must provide storage for the number and dispose
185 * of it when you've finished with it. The number is marked as
186 * constant while it exists.
d03ab969 187 */
188
d3409d5e 189extern void mp_build(mp */*m*/, mpw */*v*/, mpw */*vl*/);
d03ab969 190
d3409d5e 191/* --- @mp_destroy@ --- *
d03ab969 192 *
d3409d5e 193 * Arguments: @mp *m@ = pointer to a multiprecision integer
d03ab969 194 *
195 * Returns: ---
196 *
d3409d5e 197 * Use: Destroys a multiprecision integer. The reference count isn't
198 * checked. Don't use this function if you don't know what
199 * you're doing: use @mp_drop@ instead.
d03ab969 200 */
201
d3409d5e 202extern void mp_destroy(mp */*m*/);
d03ab969 203
d3409d5e 204/* --- @mp_copy@ --- *
d03ab969 205 *
d3409d5e 206 * Arguments: @mp *m@ = pointer to a multiprecision integer
d03ab969 207 *
d3409d5e 208 * Returns: A copy of the given multiprecision integer.
209 *
210 * Use: Copies the given integer. In fact you just get another
211 * reference to the same old one again.
d03ab969 212 */
213
d3409d5e 214extern mp *mp_copy(mp */*m*/);
d03ab969 215
d3409d5e 216#define MP_COPY(m) ((m)->ref++, (m))
217
218/* --- @mp_drop@ --- *
d03ab969 219 *
d3409d5e 220 * Arguments: @mp *m@ = pointer to a multiprecision integer
d03ab969 221 *
222 * Returns: ---
223 *
d3409d5e 224 * Use: Drops a reference to an integer which isn't wanted any more.
225 * If there are no more references, the integer is destroyed.
d03ab969 226 */
227
d3409d5e 228extern void mp_drop(mp */*m*/);
d03ab969 229
d3409d5e 230#define MP_DROP(m) do { \
231 mp *_mm = (m); \
232 if (_mm->ref > 1) \
233 _mm->ref--; \
234 else if (!(_mm->f & MP_CONST)) \
235 mp_destroy(_mm); \
236} while (0)
237
238/* --- @mp_split@ --- *
d03ab969 239 *
d3409d5e 240 * Arguments: @mp *m@ = pointer to a multiprecision integer
d03ab969 241 *
d3409d5e 242 * Returns: A reference to the same integer, possibly with a different
243 * address.
d03ab969 244 *
d3409d5e 245 * Use: Splits off a modifiable version of the integer referred to.
d03ab969 246 */
247
d3409d5e 248extern mp *mp_split(mp */*m*/);
249
250#define MP_SPLIT(m) do { \
251 mp *_mm = (m); \
252 if ((_mm->f & MP_CONST) || _mm->ref != 1) { \
253 mp *_dd = mp_create(_mm->sz); \
254 _dd->vl = _dd->v + MP_LEN(_mm); \
255 _dd->f = _mm->f & (MP_NEG | MP_BURN); \
256 memcpy(_dd->v, _mm->v, MPWS(MP_LEN(_mm))); \
257 _dd->ref = 1; \
258 _mm->ref--; \
259 (m) = _dd; \
260 } \
261} while (0)
d03ab969 262
d3409d5e 263/* --- @mp_resize@ --- *
d03ab969 264 *
d3409d5e 265 * Arguments: @mp *m@ = pointer to a multiprecision integer
266 * @size_t sz@ = new size
d03ab969 267 *
d3409d5e 268 * Returns: ---
d03ab969 269 *
d3409d5e 270 * Use: Resizes the vector containing the integer's digits. The new
271 * size must be at least as large as the current integer's
272 * length. The integer's length is increased and new digits are
273 * filled with zeroes. This isn't really intended for client
274 * use.
d03ab969 275 */
276
d3409d5e 277extern void mp_resize(mp */*m*/, size_t /*sz*/);
278
279#define MP_RESIZE(m, ssz) do { \
280 mp *_m = (m); \
281 size_t _sz = (ssz); \
282 size_t _len = MP_LEN(_m); \
283 mpw *_v = MP_ALLOC(_sz); \
284 memcpy(_v, _m->v, MPWS(_len)); \
285 if (_m->f & MP_BURN) \
286 memset(_m->v, 0, MPWS(_m->sz)); \
287 MP_FREE(_m->v); \
288 _m->v = _v; \
289 _m->vl = _v + _len; \
290 _m->sz = _sz; \
291} while (0)
d03ab969 292
d3409d5e 293/* --- @mp_ensure@ --- *
d03ab969 294 *
d3409d5e 295 * Arguments: @mp *m@ = pointer to a multiprecision integer
296 * @size_t sz@ = required size
d03ab969 297 *
298 * Returns: ---
299 *
d3409d5e 300 * Use: Ensures that the integer has enough space for @sz@ digits.
301 * The value is not changed.
d03ab969 302 */
303
d3409d5e 304extern void mp_ensure(mp */*m*/, size_t /*sz*/);
305
306#define MP_ENSURE(m, ssz) do { \
307 mp *_mm = (m); \
308 size_t _ssz = (ssz); \
309 size_t _len = MP_LEN(_mm); \
310 if (_ssz > _mm->sz) \
311 MP_RESIZE(_mm, _ssz); \
312 if (!(_mm->f & MP_UNDEF) && _ssz > _len) { \
313 memset(_mm->vl, 0, MPWS(_ssz - _len)); \
314 _mm->vl = _mm->v + _ssz; \
315 } \
316} while (0)
d03ab969 317
d3409d5e 318/* --- @mp_modify@ --- *
d03ab969 319 *
d3409d5e 320 * Arguments: @mp *m@ = pointer to a multiprecision integer
321 * @size_t sz@ = size required
d03ab969 322 *
d3409d5e 323 * Returns: Pointer to the integer (possibly different).
d03ab969 324 *
d3409d5e 325 * Use: Prepares an integer to be overwritten. It's split off from
326 * other references to the same integer, and sufficient space is
327 * allocated.
d03ab969 328 */
329
d3409d5e 330extern mp *mp_modify(mp */*m*/, size_t /*sz*/);
d03ab969 331
d3409d5e 332#define MP_MODIFY(m, sz) do { \
333 size_t _rq = (sz); \
334 mp *_m = (m); \
335 if (_m == MP_NEW) \
336 _m = mp_create(_rq); \
337 else { \
338 MP_SPLIT(_m); \
339 MP_ENSURE(_m, _rq); \
340 } \
341 _m->vl = _m->v + _rq; \
342 (m) = _m; \
343} while (0)
344
345/*----- Size manipulation -------------------------------------------------*/
346
347/* --- @mp_shrink@ --- *
d03ab969 348 *
d3409d5e 349 * Arguments: @mp *m@ = pointer to a multiprecision integer
d03ab969 350 *
351 * Returns: ---
352 *
d3409d5e 353 * Use: Reduces the recorded length of an integer. This doesn't
354 * reduce the amount of memory used, although it can improve
355 * performance a bit. To reduce memory, use @mp_minimize@
356 * instead. This can't change the value of an integer, and is
357 * therefore safe to use even when there are multiple
358 * references.
d03ab969 359 */
360
d3409d5e 361extern void mp_shrink(mp */*m*/);
d03ab969 362
d3409d5e 363#define MP_SHRINK(m) do { \
364 mp *_mm = (m); \
365 MPX_SHRINK(_mm->v, _mm->vl); \
366 if (!MP_LEN(_mm)) \
367 _mm->f &= ~MP_NEG; \
368} while (0)
369
370/* --- @mp_minimize@ --- *
d03ab969 371 *
d3409d5e 372 * Arguments: @mp *m@ = pointer to a multiprecision integer
d03ab969 373 *
374 * Returns: ---
375 *
d3409d5e 376 * Use: Reduces the amount of memory an integer uses. It's best to
377 * do this to numbers which aren't going to change in the
378 * future.
d03ab969 379 */
380
d3409d5e 381extern void mp_minimize(mp */*m*/);
d03ab969 382
d3409d5e 383/*----- Bit scanning ------------------------------------------------------*/
d03ab969 384
d3409d5e 385#ifndef MPSCAN_H
386# include "mpscan.h"
387#endif
388
389/* --- @mp_scan@ --- *
d03ab969 390 *
d3409d5e 391 * Arguments: @mpscan *sc@ = pointer to bitscanner block
392 * @const mp *m@ = pointer to a multiprecision integer
d03ab969 393 *
394 * Returns: ---
395 *
d3409d5e 396 * Use: Initializes a bitscanner on a multiprecision integer.
d03ab969 397 */
398
d3409d5e 399extern void mp_scan(mpscan */*sc*/, const mp */*m*/);
400
401#define MP_SCAN(sc, m) do { \
a790733d 402 const mp *_mm = (m); \
d3409d5e 403 mpscan *_sc = (sc); \
404 MPSCAN_INITX(_sc, _mm->v, _mm->vl); \
405} while (0)
406
407/* --- Other bitscanning aliases --- */
408
409#define mp_step mpscan_step
410#define mp_bit mpscan_bit
411
412#define MP_STEP MPSCAN_STEP
413#define MP_BIT MPSCAN_BIT
414
415/*----- Loading and storing -----------------------------------------------*/
d03ab969 416
d3409d5e 417/* --- @mp_octets@ --- *
d03ab969 418 *
d3409d5e 419 * Arguments: @const mp *m@ = a multiprecision integer
d03ab969 420 *
d3409d5e 421 * Returns: The number of octets required to represent @m@.
d03ab969 422 *
d3409d5e 423 * Use: Calculates the external storage required for a multiprecision
424 * integer.
d03ab969 425 */
426
d3409d5e 427extern size_t mp_octets(const mp *m);
d03ab969 428
d3409d5e 429/* --- @mp_loadl@ --- *
d03ab969 430 *
d3409d5e 431 * Arguments: @mp *d@ = destination
432 * @const void *pv@ = pointer to source data
433 * @size_t sz@ = size of the source data
d03ab969 434 *
d3409d5e 435 * Returns: Resulting multiprecision number.
d03ab969 436 *
d3409d5e 437 * Use: Loads a multiprecision number from an array of octets. The
438 * first byte in the array is the least significant. More
439 * formally, if the bytes are %$b_0, b_1, \ldots, b_{n-1}$%
440 * then the result is %$N = \sum_{0 \le i < n} b_i 2^{8i}$%.
d03ab969 441 */
442
d3409d5e 443extern mp *mp_loadl(mp */*d*/, const void */*pv*/, size_t /*sz*/);
d03ab969 444
d3409d5e 445/* --- @mp_storel@ --- *
446 *
447 * Arguments: @const mp *m@ = source
448 * @void *pv@ = pointer to output array
449 * @size_t sz@ = size of the output array
450 *
451 * Returns: ---
452 *
453 * Use: Stores a multiprecision number in an array of octets. The
454 * first byte in the array is the least significant. If the
455 * array is too small to represent the number, high-order bits
456 * are truncated; if the array is too large, high order bytes
457 * are filled with zeros. More formally, if the number is
458 * %$N = \sum{0 \le i} b_i 2^{8i}$% where %$0 \le b_i < 256$%,
459 * then the array is %$b_0, b_1, \ldots, b_{n-1}$%.
460 */
d03ab969 461
d3409d5e 462extern void mp_storel(const mp */*m*/, void */*pv*/, size_t /*sz*/);
d03ab969 463
d3409d5e 464/* --- @mp_loadb@ --- *
d03ab969 465 *
d3409d5e 466 * Arguments: @mp *d@ = destination
467 * @const void *pv@ = pointer to source data
468 * @size_t sz@ = size of the source data
d03ab969 469 *
d3409d5e 470 * Returns: Resulting multiprecision number.
d03ab969 471 *
d3409d5e 472 * Use: Loads a multiprecision number from an array of octets. The
473 * last byte in the array is the least significant. More
474 * formally, if the bytes are %$b_{n-1}, b_{n-2}, \ldots, b_0$%
475 * then the result is %$N = \sum_{0 \le i < n} b_i 2^{8i}$%.
d03ab969 476 */
477
d3409d5e 478extern mp *mp_loadb(mp */*d*/, const void */*pv*/, size_t /*sz*/);
d03ab969 479
d3409d5e 480/* --- @mp_storeb@ --- *
d03ab969 481 *
d3409d5e 482 * Arguments: @const mp *m@ = source
483 * @void *pv@ = pointer to output array
484 * @size_t sz@ = size of the output array
d03ab969 485 *
486 * Returns: ---
487 *
d3409d5e 488 * Use: Stores a multiprecision number in an array of octets. The
489 * last byte in the array is the least significant. If the
490 * array is too small to represent the number, high-order bits
491 * are truncated; if the array is too large, high order bytes
492 * are filled with zeros. More formally, if the number is
493 * %$N = \sum{0 \le i} b_i 2^{8i}$% where %$0 \le b_i < 256$%,
494 * then the array is %$b_{n-1}, b_{n-2}, \ldots, b_0$%.
d03ab969 495 */
496
d3409d5e 497extern void mp_storeb(const mp */*m*/, void */*pv*/, size_t /*sz*/);
d03ab969 498
d3409d5e 499/*----- Simple arithmetic -------------------------------------------------*/
d03ab969 500
d3409d5e 501/* --- @mp_2c@ --- *
d03ab969 502 *
d3409d5e 503 * Arguments: @mp *d@ = destination
504 * @mp *a@ = source
d03ab969 505 *
d3409d5e 506 * Returns: Result, @a@ converted to two's complement notation.
507 */
508
509extern mp *mp_2c(mp */*d*/, mp */*a*/);
510
511/* --- @mp_sm@ --- *
512 *
513 * Arguments: @mp *d@ = destination
514 * @mp *a@ = source
d03ab969 515 *
d3409d5e 516 * Returns: Result, @a@ converted to the native signed-magnitude
517 * notation.
d03ab969 518 */
519
d3409d5e 520extern mp *mp_sm(mp */*d*/, mp */*a*/);
d03ab969 521
d3409d5e 522/* --- @mp_lsl@ --- *
d03ab969 523 *
d3409d5e 524 * Arguments: @mp *d@ = destination
525 * @const mp *a@ = source
526 * @size_t n@ = number of bits to move
d03ab969 527 *
d3409d5e 528 * Returns: Result, @a@ shifted left by @n@.
529 */
530
531extern mp *mp_lsl(mp */*d*/, const mp */*a*/, size_t /*n*/);
532
533/* --- @mp_lsr@ --- *
534 *
535 * Arguments: @mp *d@ = destination
536 * @const mp *a@ = source
537 * @size_t n@ = number of bits to move
d03ab969 538 *
d3409d5e 539 * Returns: Result, @a@ shifted left by @n@.
d03ab969 540 */
541
d3409d5e 542extern mp *mp_lsr(mp */*d*/, const mp */*a*/, size_t /*n*/);
d03ab969 543
d3409d5e 544/* --- @mp_cmp@ --- *
d03ab969 545 *
d3409d5e 546 * Arguments: @const mp *a, *b@ = two numbers
d03ab969 547 *
d3409d5e 548 * Returns: Less than, equal to or greater than zero, according to
549 * whether @a@ is less than, equal to or greater than @b@.
550 */
551
552extern int mp_cmp(const mp */*a*/, const mp */*b*/);
553
554#define MP_CMP(a, op, b) (mp_cmp((a), (b)) op 0)
555
556/* --- @mp_add@ --- *
d03ab969 557 *
d3409d5e 558 * Arguments: @mp *d@ = destination
559 * @const mp *a, *b@ = sources
560 *
561 * Returns: Result, @a@ added to @b@.
d03ab969 562 */
563
d3409d5e 564extern mp *mp_add(mp */*d*/, const mp */*a*/, const mp */*b*/);
d03ab969 565
d3409d5e 566/* --- @mp_sub@ --- *
567 *
568 * Arguments: @mp *d@ = destination
569 * @const mp *a, *b@ = sources
570 *
571 * Returns: Result, @b@ subtracted from @a@.
572 */
d03ab969 573
d3409d5e 574extern mp *mp_sub(mp */*d*/, const mp */*a*/, const mp */*b*/);
575
576/* --- @mp_mul@ --- *
d03ab969 577 *
d3409d5e 578 * Arguments: @mp *d@ = destination
579 * @const mp *a, *b@ = sources
d03ab969 580 *
d3409d5e 581 * Returns: Result, @a@ multiplied by @b@.
582 */
583
584extern mp *mp_mul(mp */*d*/, const mp */*a*/, const mp */*b*/);
585
586/* --- @mp_sqr@ --- *
587 *
588 * Arguments: @mp *d@ = destination
589 * @const mp *a@ = source
590 *
591 * Returns: Result, @a@ squared.
592 */
593
594extern mp *mp_sqr(mp */*d*/, const mp */*a*/);
595
596/* --- @mp_div@ --- *
d03ab969 597 *
d3409d5e 598 * Arguments: @mp **qq, **rr@ = destination, quotient and remainder
599 * @const mp *a, *b@ = sources
600 *
601 * Use: Calculates the quotient and remainder when @a@ is divided by
602 * @b@.
d03ab969 603 */
604
d3409d5e 605extern void mp_div(mp **/*qq*/, mp **/*rr*/,
606 const mp */*a*/, const mp */*b*/);
607
608/*----- More advanced algorithms ------------------------------------------*/
d03ab969 609
d3409d5e 610/* --- @mp_gcd@ --- *
d03ab969 611 *
d3409d5e 612 * Arguments: @mp **gcd, **xx, **yy@ = where to write the results
613 * @mp *a, *b@ = sources (must be nonzero)
d03ab969 614 *
615 * Returns: ---
616 *
d3409d5e 617 * Use: Calculates @gcd(a, b)@, and two numbers @x@ and @y@ such that
618 * @ax + by = gcd(a, b)@. This is useful for computing modular
619 * inverses. Neither @a@ nor @b@ may be zero. Note that,
620 * unlike @mp_div@ for example, it is not possible to specify
621 * explicit destinations -- new MPs are always allocated.
d03ab969 622 */
623
d3409d5e 624extern void mp_gcd(mp **/*gcd*/, mp **/*xx*/, mp **/*yy*/,
625 mp */*a*/, mp */*b*/);
626
627/*----- Test harness support ----------------------------------------------*/
628
629#include <mLib/testrig.h>
630
631#ifndef MPTEXT_H
632# include "mptext.h"
633#endif
634
635extern const test_type type_mp;
d03ab969 636
637/*----- That's all, folks -------------------------------------------------*/
638
639#ifdef __cplusplus
640 }
641#endif
642
643#endif