Annotation of OpenXM_contrib/gmp/tests/mpz/reuse.c, Revision 1.1.1.1
1.1 ohara 1: /* Test that routines allow reusing a source variable as destination.
2:
3: Test all relevant functions except:
4: mpz_bin_ui
5: mpz_nextprime
6: mpz_mul_si
7: mpz_addmul_ui (should this really allow a+=a*c?)
8:
9: Copyright 1996, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
10:
11: This file is part of the GNU MP Library.
12:
13: The GNU MP Library is free software; you can redistribute it and/or modify
14: it under the terms of the GNU Lesser General Public License as published by
15: the Free Software Foundation; either version 2.1 of the License, or (at your
16: option) any later version.
17:
18: The GNU MP Library is distributed in the hope that it will be useful, but
19: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20: or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
21: License for more details.
22:
23: You should have received a copy of the GNU Lesser General Public License
24: along with the GNU MP Library; see the file COPYING.LIB. If not, write to
25: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26: MA 02111-1307, USA. */
27:
28: #include <stdio.h>
29: #include <stdlib.h>
30: #include <string.h>
31:
32: #include "gmp.h"
33: #include "gmp-impl.h"
34: #include "tests.h"
35:
36: #if __GMP_LIBGMP_DLL
37:
38: /* FIXME: When linking to a DLL libgmp, mpz_add etc can't be used as
39: initializers for global variables because they're effectively global
40: variables (function pointers) themselves. Perhaps calling a test
41: function successively with mpz_add etc would be better. */
42:
43: int
44: main (void)
45: {
46: printf ("Test suppressed for windows DLL\n");
47: exit (0);
48: }
49:
50:
51: #else /* ! DLL_EXPORT */
52:
53: void dump _PROTO ((char *, mpz_t, mpz_t, mpz_t));
54:
55: typedef void (*dss_func) _PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr));
56: typedef void (*dsi_func) _PROTO ((mpz_ptr, mpz_srcptr, unsigned long int));
57: typedef unsigned long int (*dsi_div_func) _PROTO ((mpz_ptr, mpz_srcptr, unsigned long int));
58: typedef unsigned long int (*ddsi_div_func) _PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int));
59: typedef void (*ddss_div_func) _PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr));
60: typedef void (*ds_func) _PROTO ((mpz_ptr, mpz_srcptr));
61:
62:
63: void
64: mpz_xinvert (mpz_ptr r, mpz_srcptr a, mpz_srcptr b)
65: {
66: int res;
67: res = mpz_invert (r, a, b);
68: if (res == 0)
69: mpz_set_ui (r, 0);
70: }
71:
72: dss_func dss_funcs[] =
73: {
74: mpz_add, mpz_sub, mpz_mul,
75: mpz_cdiv_q, mpz_cdiv_r, mpz_fdiv_q, mpz_fdiv_r, mpz_tdiv_q, mpz_tdiv_r,
76: mpz_xinvert,
77: mpz_gcd, mpz_lcm, mpz_and, mpz_ior, mpz_xor
78: };
79: char *dss_func_names[] =
80: {
81: "mpz_add", "mpz_sub", "mpz_mul",
82: "mpz_cdiv_q", "mpz_cdiv_r", "mpz_fdiv_q", "mpz_fdiv_r", "mpz_tdiv_q", "mpz_tdiv_r",
83: "mpz_xinvert",
84: "mpz_gcd", "mpz_lcm", "mpz_and", "mpz_ior", "mpz_xor"
85: };
86: char dss_func_division[] = {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
87:
88: dsi_func dsi_funcs[] =
89: {
90: /* Don't change order here without changing the code in main(). */
91: mpz_add_ui, mpz_mul_ui, mpz_sub_ui,
92: mpz_fdiv_q_2exp, mpz_fdiv_r_2exp,
93: mpz_cdiv_q_2exp, mpz_cdiv_r_2exp,
94: mpz_tdiv_q_2exp, mpz_tdiv_r_2exp,
95: mpz_mul_2exp,
96: mpz_pow_ui
97: };
98: char *dsi_func_names[] =
99: {
100: "mpz_add_ui", "mpz_mul_ui", "mpz_sub_ui",
101: "mpz_fdiv_q_2exp", "mpz_fdiv_r_2exp",
102: "mpz_cdiv_q_2exp", "mpz_cdiv_r_2exp",
103: "mpz_tdiv_q_2exp", "mpz_tdiv_r_2exp",
104: "mpz_mul_2exp",
105: "mpz_pow_ui"
106: };
107:
108: dsi_div_func dsi_div_funcs[] =
109: {
110: mpz_cdiv_q_ui, mpz_cdiv_r_ui,
111: mpz_fdiv_q_ui, mpz_fdiv_r_ui,
112: mpz_tdiv_q_ui, mpz_tdiv_r_ui
113: };
114: char *dsi_div_func_names[] =
115: {
116: "mpz_cdiv_q_ui", "mpz_cdiv_r_ui",
117: "mpz_fdiv_q_ui", "mpz_fdiv_r_ui",
118: "mpz_tdiv_q_ui", "mpz_tdiv_r_ui"
119: };
120:
121: ddsi_div_func ddsi_div_funcs[] =
122: {
123: mpz_cdiv_qr_ui,
124: mpz_fdiv_qr_ui,
125: mpz_tdiv_qr_ui
126: };
127: char *ddsi_div_func_names[] =
128: {
129: "mpz_cdiv_qr_ui",
130: "mpz_fdiv_qr_ui",
131: "mpz_tdiv_qr_ui"
132: };
133:
134: ddss_div_func ddss_div_funcs[] =
135: {
136: mpz_cdiv_qr,
137: mpz_fdiv_qr,
138: mpz_tdiv_qr
139: };
140: char *ddss_div_func_names[] =
141: {
142: "mpz_cdiv_qr",
143: "mpz_fdiv_qr",
144: "mpz_tdiv_qr"
145: };
146:
147: ds_func ds_funcs[] =
148: {
149: mpz_abs, mpz_com, mpz_neg, mpz_sqrt
150: };
151: char *ds_func_names[] =
152: {
153: "mpz_abs", "mpz_com", "mpz_neg", "mpz_sqrt"
154: };
155:
156:
157: /* Really use `defined (__STDC__)' here; we want it to be true for Sun C */
158: #if defined (__STDC__) || defined (__cplusplus)
159: #define FAIL(class,indx,op1,op2,op3) \
160: do { \
161: class##_funcs[indx] = 0; \
162: dump (class##_func_names[indx], op1, op2, op3); \
163: failures++; \
164: } while (0)
165: #define FAIL2(fname,op1,op2,op3) \
166: do { \
167: dump (#fname, op1, op2, op3); \
168: failures++; \
169: } while (0)
170: #else
171: #define FAIL(class,indx,op1,op2,op3) \
172: do { \
173: class/**/_funcs[indx] = 0; \
174: dump (class/**/_func_names[indx], op1, op2, op3); \
175: failures++; \
176: } while (0)
177: #define FAIL2(fname,op1,op2,op3) \
178: do { \
179: dump ("fname", op1, op2, op3); \
180: failures++; \
181: } while (0)
182: #endif
183:
184:
185: int
186: main (int argc, char **argv)
187: {
188: int i;
189: int pass, reps = 1000;
190: mpz_t in1, in2, in3;
191: unsigned long int in2i;
192: mp_size_t size;
193: mpz_t res1, res2, res3;
194: mpz_t ref1, ref2, ref3;
195: mpz_t t;
196: unsigned long int r1, r2;
197: long failures = 0;
198: gmp_randstate_ptr rands;
199: mpz_t bs;
200: unsigned long bsi, size_range;
201:
202: tests_start ();
203: rands = RANDS;
204:
205: mpz_init (bs);
206:
207: if (argc == 2)
208: reps = atoi (argv[1]);
209:
210: mpz_init (in1);
211: mpz_init (in2);
212: mpz_init (in3);
213: mpz_init (ref1);
214: mpz_init (ref2);
215: mpz_init (ref3);
216: mpz_init (res1);
217: mpz_init (res2);
218: mpz_init (res3);
219: mpz_init (t);
220:
221: for (pass = 1; pass <= reps; pass++)
222: {
223: mpz_urandomb (bs, rands, 32);
224: size_range = mpz_get_ui (bs) % 10 + 2;
225:
226: mpz_urandomb (bs, rands, size_range);
227: size = mpz_get_ui (bs);
228: mpz_rrandomb (in1, rands, size);
229:
230: mpz_urandomb (bs, rands, size_range);
231: size = mpz_get_ui (bs);
232: mpz_rrandomb (in2, rands, size);
233:
234: mpz_urandomb (bs, rands, size_range);
235: size = mpz_get_ui (bs);
236: mpz_rrandomb (in3, rands, size);
237:
238: mpz_urandomb (bs, rands, 3);
239: bsi = mpz_get_ui (bs);
240: if ((bsi & 1) != 0)
241: mpz_neg (in1, in1);
242: if ((bsi & 1) != 0)
243: mpz_neg (in2, in2);
244: if ((bsi & 1) != 0)
245: mpz_neg (in3, in3);
246:
247: for (i = 0; i < sizeof (dss_funcs) / sizeof (dss_func); i++)
248: {
249: if (dss_funcs[i] == 0)
250: continue;
251: if (dss_func_division[i] && mpz_sgn (in2) == 0)
252: continue;
253:
254: (dss_funcs[i]) (ref1, in1, in2);
255:
256: mpz_set (res1, in1);
257: (dss_funcs[i]) (res1, res1, in2);
258: if (mpz_cmp (ref1, res1) != 0)
259: FAIL (dss, i, in1, in2, NULL);
260:
261: mpz_set (res1, in2);
262: (dss_funcs[i]) (res1, in1, res1);
263: if (mpz_cmp (ref1, res1) != 0)
264: FAIL (dss, i, in1, in2, NULL);
265: }
266:
267: for (i = 0; i < sizeof (ddss_div_funcs) / sizeof (ddss_div_func); i++)
268: {
269: if (ddss_div_funcs[i] == 0)
270: continue;
271: if (mpz_sgn (in2) == 0)
272: continue;
273:
274: (ddss_div_funcs[i]) (ref1, ref2, in1, in2);
275:
276: mpz_set (res1, in1);
277: (ddss_div_funcs[i]) (res1, res2, res1, in2);
278: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
279: FAIL (ddss_div, i, in1, in2, NULL);
280:
281: mpz_set (res2, in1);
282: (ddss_div_funcs[i]) (res1, res2, res2, in2);
283: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
284: FAIL (ddss_div, i, in1, in2, NULL);
285:
286: mpz_set (res1, in2);
287: (ddss_div_funcs[i]) (res1, res2, in1, res1);
288: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
289: FAIL (ddss_div, i, in1, in2, NULL);
290:
291: mpz_set (res2, in2);
292: (ddss_div_funcs[i]) (res1, res2, in1, res2);
293: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
294: FAIL (ddss_div, i, in1, in2, NULL);
295: }
296:
297: for (i = 0; i < sizeof (ds_funcs) / sizeof (ds_func); i++)
298: {
299: if (ds_funcs[i] == 0)
300: continue;
301: if (strcmp (ds_func_names[i], "mpz_sqrt") == 0
302: && mpz_sgn (in1) < 0)
303: continue;
304:
305: (ds_funcs[i]) (ref1, in1);
306:
307: mpz_set (res1, in1);
308: (ds_funcs[i]) (res1, res1);
309: if (mpz_cmp (ref1, res1) != 0)
310: FAIL (ds, i, in1, in2, NULL);
311: }
312:
313: in2i = mpz_get_ui (in2);
314:
315: for (i = 0; i < sizeof (dsi_funcs) / sizeof (dsi_func); i++)
316: {
317: if (dsi_funcs[i] == 0)
318: continue;
319: if (strcmp (dsi_func_names[i], "mpz_fdiv_q_2exp") == 0)
320: /* Limit exponent to something reasonable for the division
321: functions. Without this, we'd normally shift things off
322: the end and just generate the trivial values 1, 0, -1. */
323: in2i %= 0x1000;
324: if (strcmp (dsi_func_names[i], "mpz_mul_2exp") == 0)
325: /* Limit exponent more for mpz_mul_2exp to save time. */
326: in2i %= 0x100;
327: if (strcmp (dsi_func_names[i], "mpz_pow_ui") == 0)
328: /* Limit exponent yet more for mpz_pow_ui to save time. */
329: in2i %= 0x10;
330:
331: (dsi_funcs[i]) (ref1, in1, in2i);
332:
333: mpz_set (res1, in1);
334: (dsi_funcs[i]) (res1, res1, in2i);
335: if (mpz_cmp (ref1, res1) != 0)
336: FAIL (dsi, i, in1, in2, NULL);
337: }
338:
339: if (in2i != 0) /* Don't divide by 0. */
340: {
341: for (i = 0; i < sizeof (dsi_div_funcs) / sizeof (dsi_div_funcs); i++)
342: {
343: r1 = (dsi_div_funcs[i]) (ref1, in1, in2i);
344:
345: mpz_set (res1, in1);
346: r2 = (dsi_div_funcs[i]) (res1, res1, in2i);
347: if (mpz_cmp (ref1, res1) != 0 || r1 != r2)
348: FAIL (dsi_div, i, in1, in2, NULL);
349: }
350:
351: for (i = 0; i < sizeof (ddsi_div_funcs) / sizeof (ddsi_div_funcs); i++)
352: {
353: r1 = (ddsi_div_funcs[i]) (ref1, ref2, in1, in2i);
354:
355: mpz_set (res1, in1);
356: r2 = (ddsi_div_funcs[i]) (res1, res2, res1, in2i);
357: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 || r1 != r2)
358: FAIL (ddsi_div, i, in1, in2, NULL);
359:
360: mpz_set (res2, in1);
361: (ddsi_div_funcs[i]) (res1, res2, res2, in2i);
362: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 || r1 != r2)
363: FAIL (ddsi_div, i, in1, in2, NULL);
364: }
365: }
366:
367: if (mpz_sgn (in1) >= 0)
368: {
369: mpz_sqrtrem (ref1, ref2, in1);
370:
371: mpz_set (res1, in1);
372: mpz_sqrtrem (res1, res2, res1);
373: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
374: FAIL2 (mpz_sqrtrem, in1, NULL, NULL);
375:
376: mpz_set (res2, in1);
377: mpz_sqrtrem (res1, res2, res2);
378: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
379: FAIL2 (mpz_sqrtrem, in1, NULL, NULL);
380: }
381:
382: if (mpz_sgn (in1) >= 0)
383: {
384: mpz_root (ref1, in1, in2i % 0x100 + 1);
385:
386: mpz_set (res1, in1);
387: mpz_root (res1, res1, in2i % 0x100 + 1);
388: if (mpz_cmp (ref1, res1) != 0)
389: FAIL2 (mpz_root, in1, in2, NULL);
390: }
391:
392: if (pass < reps / 2) /* run fewer tests since gcdext lots of time */
393: {
394: mpz_gcdext (ref1, ref2, ref3, in1, in2);
395:
396: mpz_set (res1, in1);
397: mpz_gcdext (res1, res2, res3, res1, in2);
398: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
399: || mpz_cmp (ref3, res3) != 0)
400: FAIL2 (mpz_gcdext, in1, in2, NULL);
401:
402: mpz_set (res2, in1);
403: mpz_gcdext (res1, res2, res3, res2, in2);
404: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
405: || mpz_cmp (ref3, res3) != 0)
406: FAIL2 (mpz_gcdext, in1, in2, NULL);
407:
408: mpz_set (res3, in1);
409: mpz_gcdext (res1, res2, res3, res3, in2);
410: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
411: || mpz_cmp (ref3, res3) != 0)
412: FAIL2 (mpz_gcdext, in1, in2, NULL);
413:
414: mpz_set (res1, in2);
415: mpz_gcdext (res1, res2, res3, in1, res1);
416: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
417: || mpz_cmp (ref3, res3) != 0)
418: FAIL2 (mpz_gcdext, in1, in2, NULL);
419:
420: mpz_set (res2, in2);
421: mpz_gcdext (res1, res2, res3, in1, res2);
422: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
423: || mpz_cmp (ref3, res3) != 0)
424: FAIL2 (mpz_gcdext, in1, in2, NULL);
425:
426: mpz_set (res3, in2);
427: mpz_gcdext (res1, res2, res3, in1, res3);
428: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
429: || mpz_cmp (ref3, res3) != 0)
430: FAIL2 (mpz_gcdext, in1, in2, NULL);
431:
432: mpz_set (res1, in1);
433: mpz_gcdext (res1, res2, NULL, res1, in2);
434: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
435: || mpz_cmp (ref3, res3) != 0)
436: FAIL2 (mpz_gcdext, in1, in2, NULL);
437:
438: mpz_set (res2, in1);
439: mpz_gcdext (res1, res2, NULL, res2, in2);
440: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
441: || mpz_cmp (ref3, res3) != 0)
442: FAIL2 (mpz_gcdext, in1, in2, NULL);
443:
444: mpz_set (res1, in2);
445: mpz_gcdext (res1, res2, NULL, in1, res1);
446: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
447: || mpz_cmp (ref3, res3) != 0)
448: FAIL2 (mpz_gcdext, in1, in2, NULL);
449:
450: mpz_set (res2, in2);
451: mpz_gcdext (res1, res2, NULL, in1, res2);
452: if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
453: || mpz_cmp (ref3, res3) != 0)
454: FAIL2 (mpz_gcdext, in1, in2, NULL);
455: }
456:
457: /* Don't run mpz_powm for huge exponents or when undefined. */
458: if (mpz_sizeinbase (in2, 2) < 250 && mpz_sgn (in3) != 0
459: && (mpz_sgn (in2) >= 0 || mpz_invert (t, in1, in3)))
460: {
461: mpz_powm (ref1, in1, in2, in3);
462:
463: mpz_set (res1, in1);
464: mpz_powm (res1, res1, in2, in3);
465: if (mpz_cmp (ref1, res1) != 0)
466: FAIL2 (mpz_powm, in1, in2, in3);
467:
468: mpz_set (res1, in2);
469: mpz_powm (res1, in1, res1, in3);
470: if (mpz_cmp (ref1, res1) != 0)
471: FAIL2 (mpz_powm, in1, in2, in3);
472:
473: mpz_set (res1, in3);
474: mpz_powm (res1, in1, in2, res1);
475: if (mpz_cmp (ref1, res1) != 0)
476: FAIL2 (mpz_powm, in1, in2, in3);
477: }
478:
479: /* Don't run mpz_powm_ui when undefined. */
480: if (mpz_sgn (in3) != 0)
481: {
482: mpz_powm_ui (ref1, in1, in2i, in3);
483:
484: mpz_set (res1, in1);
485: mpz_powm_ui (res1, res1, in2i, in3);
486: if (mpz_cmp (ref1, res1) != 0)
487: FAIL2 (mpz_powm_ui, in1, in2, in3);
488:
489: mpz_set (res1, in3);
490: mpz_powm_ui (res1, in1, in2i, res1);
491: if (mpz_cmp (ref1, res1) != 0)
492: FAIL2 (mpz_powm_ui, in1, in2, in3);
493: }
494:
495: {
496: r1 = mpz_gcd_ui (ref1, in1, in2i);
497:
498: mpz_set (res1, in1);
499: r2 = mpz_gcd_ui (res1, res1, in2i);
500: if (mpz_cmp (ref1, res1) != 0)
501: FAIL2 (mpz_gcd_ui, in1, in2, NULL);
502: }
503:
504: if (mpz_cmp_ui (in2, 1L) > 0 && mpz_sgn (in1) != 0)
505: {
506: /* Test mpz_remove */
507: mpz_remove (ref1, in1, in2);
508:
509: mpz_set (res1, in1);
510: mpz_remove (res1, res1, in2);
511: if (mpz_cmp (ref1, res1) != 0)
512: FAIL2 (mpz_remove, in1, in2, NULL);
513:
514: mpz_set (res1, in2);
515: mpz_remove (res1, in1, res1);
516: if (mpz_cmp (ref1, res1) != 0)
517: FAIL2 (mpz_remove, in1, in2, NULL);
518: }
519:
520: if (mpz_sgn (in2) != 0)
521: {
522: /* Test mpz_divexact */
523: mpz_mul (t, in1, in2);
524: mpz_divexact (ref1, t, in2);
525:
526: mpz_set (res1, t);
527: mpz_divexact (res1, res1, in2);
528: if (mpz_cmp (ref1, res1) != 0)
529: FAIL2 (mpz_divexact, t, in2, NULL);
530:
531: mpz_set (res1, in2);
532: mpz_divexact (res1, t, res1);
533: if (mpz_cmp (ref1, res1) != 0)
534: FAIL2 (mpz_divexact, t, in2, NULL);
535: }
536:
537: if (mpz_sgn (in2) > 0)
538: {
539: /* Test mpz_divexact_gcd, same as mpz_divexact */
540: mpz_mul (t, in1, in2);
541: mpz_divexact_gcd (ref1, t, in2);
542:
543: mpz_set (res1, t);
544: mpz_divexact_gcd (res1, res1, in2);
545: if (mpz_cmp (ref1, res1) != 0)
546: FAIL2 (mpz_divexact_gcd, t, in2, NULL);
547:
548: mpz_set (res1, in2);
549: mpz_divexact_gcd (res1, t, res1);
550: if (mpz_cmp (ref1, res1) != 0)
551: FAIL2 (mpz_divexact_gcd, t, in2, NULL);
552: }
553: }
554:
555: if (failures != 0)
556: {
557: fprintf (stderr, "mpz/reuse: %ld error%s\n", failures, "s" + (failures == 1));
558: exit (1);
559: }
560:
561: mpz_clear (bs);
562: mpz_clear (in1);
563: mpz_clear (in2);
564: mpz_clear (in3);
565: mpz_clear (ref1);
566: mpz_clear (ref2);
567: mpz_clear (ref3);
568: mpz_clear (res1);
569: mpz_clear (res2);
570: mpz_clear (res3);
571: mpz_clear (t);
572:
573: tests_end ();
574: exit (0);
575: }
576:
577: void
578: dump (char *name, mpz_t in1, mpz_t in2, mpz_t in3)
579: {
580: printf ("failure in %s (", name);
581: mpz_out_str (stdout, -16, in1);
582: if (in2 != NULL)
583: {
584: printf (" ");
585: mpz_out_str (stdout, -16, in2);
586: }
587: if (in3 != NULL)
588: {
589: printf (" ");
590: mpz_out_str (stdout, -16, in3);
591: }
592: printf (")\n");
593: }
594:
595: #endif /* ! DLL_EXPORT */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>