|
|
1.1 root 1: /*
2: * text.c
3: *
4: * Copyright (c) 1985 Massachusetts Institue of Technology
5: * Copyright (c) 1986 Sun Microsystems, Inc.
6: * Copyright (c) 1986 David C. Martin, UC Berkeley
7: *
8: * David C. Martin
9: * ARPA: [email protected]
10: * UUCP: ..!ucbvax!dcmartin
11: *
12: * $Log: text.c,v $
13: * Revision 10.5 86/11/29 13:48:49 jg
14: * fixes from Berkeley
15: *
16: * Revision 1.10 86/07/27 13:49:58 dcmartin
17: * removed debugging statements
18: *
19: * Revision 1.9 86/07/25 14:45:48 dcmartin
20: * modified PrintTextMask() to handle variable width fonts
21: *
22: * Revision 1.8 86/07/17 10:37:29 dcmartin
23: * release version w/ support for variable width text
24: *
25: * Revision 1.7 86/07/17 10:32:19 dcmartin
26: *
27: */
28:
29: #ifndef lint
30: static char rcs_id[] = "$Header: text.c,v 10.5 86/11/29 13:48:49 jg Rel $";
31: #endif lint
32:
33: #include <X/mit-copyright.h>
34:
35: /*
36: * The Sun X drivers are a product of Sun Microsystems, Inc. and are provided
37: * for unrestricted use provided that this legend is included on all tape
38: * media and as a part of the software program in whole or part. Users
39: * may copy or modify these drivers without charge, but are not authorized
40: * to license or distribute them to anyone else except as part of a product or
41: * program developed by the user.
42: *
43: * THE SUN X DRIVERS ARE PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND
44: * INCLUDING THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A
45: * PARTICULAR PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE
46: * PRACTICE.
47: *
48: * The Sun X Drivers are provided with no support and without any obligation
49: * on the part of Sun Microsystems, Inc. to assist in their use, correction,
50: * modification or enhancement.
51: *
52: * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
53: * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THE SUN X
54: * DRIVERS OR ANY PART THEREOF.
55: *
56: * In no event will Sun Microsystems, Inc. be liable for any lost revenue
57: * or profits or other special, indirect and consequential damages, even if
58: * Sun has been advised of the possibility of such damages.
59: *
60: * Sun Microsystems, Inc.
61: * 2550 Garcia Avenue
62: * Mountain View, California 94043
63: */
64:
65: #ifdef sun
66:
67: /*
68: * ToDo:
69: * Color
70: */
71:
72: #include "Xsun.h"
73: #ifndef stdin
74: #include <stdio.h>
75: #endif
76: #include <pixrect/memreg.h>
77: #include <pixrect/cg2reg.h>
78:
79: /* I've put in some rather ugly hacks, in the name of performance. The
80: global variables private_* are really extra parameters to the batchrop
81: routines. I did this, rather than adding parameters, because I wanted to
82: do the least violence to the "official" specs of batchrop -- this way X
83: will vaguely work on displays that don't use one of the tuned batchrops.
84: JAG */
85:
86: int private_fgcolor, private_bgcolor, private_czmask;
87:
88: extern struct pixrect *PixRect;
89:
90: #define MAXCHARS 400
91:
92: extern int
93: PrintText(text, textlen, font, fore, back, charpad, spacepad, dstx, dsty,
94: clips, clipcount, func, zmask)
95: register unsigned char *text;
96: FONT *font;
97: int textlen, fore, back, charpad, spacepad, dstx, dsty;
98: CLIP *clips;
99: int clipcount, zmask;
100: int func;
101: {
102: extern CURSOR *CurrentCursor;
103: extern CursorDisplayed;
104: int cleft, ctop, cwidth, cheight;
105: int op;
106: extern char FBMap[];
107: unsigned char *limit = text +
108: (textlen < MAXCHARS ? textlen : MAXCHARS);
109: register int w = 0;
110: int bsize = 0;
111: int lheight;
112: int sbot, sright;
113: static struct pr_prpos bat[MAXCHARS];
114:
115: private_czmask = zmask;
116: private_fgcolor = fore;
117: private_bgcolor = back;
118: if (fore & 1)
119: func += 0x20;
120: if (back & 1)
121: func += 0x10;
122: func = FBMap[func];
123: op = SUN_FROM_X_OP(func) | PIX_COLOR(fore);
124: /* this is a gross abuse of C, but ... */
125: {
126: register struct pixfont *pf;
127: register struct pr_prpos *p;
128: register struct pixchar *pc;
129: register int pwidth = 0;
130:
131: pf = (struct pixfont *) font->data;
132: p = bat;
133: lheight = pf->pf_defaultsize.y;
134: if (charpad == 0 && spacepad == 0) {
135: /* for each character in the text */
136: while (text < limit) {
137: pc = &(pf->pf_char[*text++]);
138: if (pc == 0 || pc->pc_pr == NULL)
139: continue;
140: p->pr = pc->pc_pr;
141: /*
142: * pr_batchrop() is confusing...
143: * you must give the offset for the previous
144: * pixrect
145: */
146: p->pos.x = pwidth;
147: /* store the character width */
148: pwidth = pc->pc_adv.x;
149: /* increment the total width */
150: w += pwidth;
151: p++;
152: bsize++;
153: }
154: } else {
155: /* for efficiency ... */
156: struct pixchar *space = &(pf->pf_char[font->space]);
157:
158: while (text < limit) {
159: pc = &(pf->pf_char[*text++]);
160: if (pc == (struct pixchar *) NULL ||
161: pc->pc_pr == (struct pixrect *) NULL)
162: continue;
163: p->pr = pc->pc_pr;
164: /*
165: * pr_batchrop() is confusing...
166: * you must give the offset for the previous
167: * pixrect
168: */
169: p->pos.x = pwidth;
170: /* store the character width */
171: pwidth = pc->pc_adv.x + charpad;
172: /* add space? */
173: if (pc == space)
174: pwidth += spacepad;
175: /* increment the total width */
176: w += pwidth;
177: p++;
178: bsize++;
179: }
180: }
181: } /* end gross abuse */
182: /* determine the right and bottom of the region */
183: sbot = dsty + lheight;
184: sright = dstx + w;
185: /* if the cursor is where we want to put text get rid of it */
186: if (CursorDisplayed) {
187: extern DEVICE *CurrentDevice;
188: register vsCursor *ms = CurrentDevice->mouse;
189: register CURSOR *cs = CurrentCursor;
190:
191: if (ms->y < sbot &&
192: ms->x < sright &&
193: ms->y + cs->height > dsty &&
194: ms->x + cs->width > dstx)
195: DisplayCursor(NULL);
196: }
197: do {
198: GetNextClip(clips, cleft, ctop, cwidth, cheight);
199: if (dsty >= ctop &&
200: sbot <= ctop + cheight &&
201: dstx >= cleft &&
202: sright <= cleft + cwidth) {
203: pr_batchrop(PixRect, dstx - bat[0].pos.x, dsty,
204: op | PIX_DONTCLIP, bat, bsize);
205: } else {
206: struct pixrect *region;
207:
208: if (dsty > ctop + cheight)
209: continue;
210: if (dsty + lheight <= ctop)
211: continue;
212: region = pr_region(PixRect, cleft, ctop, cwidth,
213: cheight);
214: pr_batchrop(region, dstx - cleft - bat[0].pos.x,
215: dsty - ctop, op, bat, bsize);
216: pr_destroy(region);
217: }
218: } while (--clipcount > 0);
219: /* redisplay the cursor if we zapped it */
220: if (!CursorDisplayed)
221: DisplayCursor(CurrentCursor);
222: } /* end PrintText() */
223:
224: extern int
225: PrintTextMask(text, textlen, font, srcpix, charpad, spacepad, dstx, dsty,
226: clips, clipcount, func, zmask)
227: unsigned char *text;
228: FONT *font;
229: int textlen, srcpix, charpad, spacepad, dstx, dsty;
230: CLIP *clips;
231: int clipcount, zmask;
232: register int func;
233: {
234: extern CURSOR *CurrentCursor;
235: extern CursorDisplayed;
236: int cleft, ctop, cwidth, cheight;
237: int op;
238: extern char SSMap[];
239: unsigned char *limit = text +
240: (textlen < MAXCHARS ? textlen : MAXCHARS);
241: register int w = 0;
242: static struct pr_prpos bat[MAXCHARS];
243: int bsize = 0, lheight, sbot, sright;
244:
245: SetZmask(PixRect, &zmask);
246: private_bgcolor = -1;
247: private_fgcolor = srcpix;
248: if (PixRect->pr_depth == 1) {
249: if ((srcpix & 1) == 0)
250: func += 0x10;
251: op = SUN_FROM_X_OP(SSMap[func]) &
252: PIX_SRC | PIX_NOT(PIX_SRC) & PIX_DST;
253: } else
254: op = SUN_FROM_X_OP(func);
255: if (PixRect->pr_depth > 1)
256: op |= PIX_COLOR(srcpix);
257: /* this is a gross abuse of C, but ... */
258: {
259: register struct pixfont *pf;
260: register struct pr_prpos *p;
261: register struct pixchar *pc;
262: register int pwidth = 0;
263:
264: pf = (struct pixfont *) font->data;
265: p = bat;
266: lheight = pf->pf_defaultsize.y;
267: if (charpad == 0 && spacepad == 0) {
268: /* for each character in the text */
269: while (text < limit) {
270: pc = &(pf->pf_char[*text++]);
271: if (pc == 0 || pc->pc_pr == NULL)
272: continue;
273: p->pr = pc->pc_pr;
274: /*
275: * pr_batchrop() is confusing...
276: * you must give the offset for the previous
277: * pixrect
278: */
279: p->pos.x = pwidth;
280: /* store the character width */
281: pwidth = pc->pc_adv.x;
282: /* increment the total width */
283: w += pwidth;
284: p++;
285: bsize++;
286: }
287: } else {
288: /* for efficiency ... */
289: struct pixchar *space = &(pf->pf_char[font->space]);
290:
291: while (text < limit) {
292: pc = &(pf->pf_char[*text++]);
293: if (pc == 0 || pc->pc_pr == NULL)
294: continue;
295: p->pr = pc->pc_pr;
296: /*
297: * pr_batchrop() is confusing...
298: * you must give the offset for the previous
299: * pixrect
300: */
301: p->pos.x = pwidth;
302: /* store the character width */
303: pwidth = pc->pc_adv.x + charpad;
304: /* add space? */
305: if (pc == space)
306: pwidth += spacepad;
307: /* increment the total width */
308: w += pwidth;
309: p++;
310: bsize++;
311: }
312: }
313: } /* end gross abuse */
314: /* determine right/bottom corner */
315: sbot = dsty + lheight;
316: sright = dstx + w;
317: /* if the cursor is display where we wish to output -- zap it */
318: if (CursorDisplayed) {
319: extern DEVICE *CurrentDevice;
320: register vsCursor *ms = CurrentDevice->mouse;
321: register CURSOR *cs = CurrentCursor;
322:
323: if (ms->y < sbot &&
324: ms->x < sright &&
325: ms->y + cs->height > dsty &&
326: ms->x + cs->width > dstx)
327: DisplayCursor(NULL);
328: }
329: do {
330: GetNextClip(clips, cleft, ctop, cwidth, cheight);
331: if (dsty >= ctop &&
332: sbot <= ctop + cheight &&
333: dstx >= cleft &&
334: sright <= cleft + cwidth)
335: pr_batchrop(PixRect, dstx - bat[0].pos.x, dsty,
336: op | PIX_DONTCLIP, bat, bsize);
337: else {
338: struct pixrect *region;
339: if (dsty > ctop + cheight)
340: continue;
341: if (dsty + lheight <= ctop)
342: continue;
343: region = pr_region(PixRect, cleft, ctop, cwidth,
344: cheight);
345: pr_batchrop(region, dstx - cleft - bat[0].pos.x,
346: dsty - ctop, op, bat, bsize);
347: pr_destroy(region);
348: }
349: } while (--clipcount > 0);
350: /* restore cursor if we zapped it */
351: if (!CursorDisplayed)
352: DisplayCursor(CurrentCursor);
353: /* another gross abuse of C... */
354: {
355: static allmask = -1;
356:
357: SetZmask(PixRect, &allmask);
358: }
359: } /* end PrintTextMask() */
360:
361:
362: /*
363: * Copyright (c) 1983 by Sun Microsystems, Inc.
364: */
365:
366: /*
367: * Memory batchrop
368: */
369:
370:
371: extern char pr_reversedst[];
372: extern struct pixrectops mem_ops;
373:
374:
375:
376: #define MEMBATCH(IfClip, IfMask, op, IfReverse) \
377: for (; --count >= 0; src++) { \
378: dst.pos.x += src->pos.x; \
379: dp = dp0 + (((dskew = xoff0 + dst.pos.x) >> 3) & ~1); \
380: dskew &= 0xF; \
381: spr = src->pr; \
382: sizex = spr->pr_size.x; \
383: sizey = spr->pr_size.y; \
384: sprd = mpr_d(spr); \
385: if (sprd->md_linebytes != 2) \
386: goto hard; \
387: sp = (u_short *) sprd->md_image; \
388: IfClip( if (dst.pos.x + sizex > limx) \
389: goto hard; \
390: if (dst.pos.y + sizey > limy) \
391: sizey = limy - dst.pos.y; \
392: if (dst.pos.x < 0) \
393: goto hard; \
394: if (dst.pos.y < 0) { \
395: sizey += dst.pos.y; \
396: sp -= dst.pos.y; \
397: dp -= pr_product(dst.pos.y, vert); \
398: } \
399: if (sizex <= 0) \
400: continue; \
401: ,) \
402: if (--sizey>=0) \
403: if (dskew + sizex <= 16) { \
404: IfMask( register short mask; \
405: mask = 0x8000; \
406: sizex -= 1; \
407: mask >>= sizex; \
408: ((unsigned short) mask) >>= dskew; \
409: IfReverse(mask = ~mask;,),) \
410: do { \
411: IfMask(*(u_short *) dp IfReverse(&,|)= mask;,) \
412: *(u_short *) dp op (*sp++ >> dskew); \
413: dp += vert; \
414: } while (--sizey != -1); \
415: } \
416: else { \
417: IfMask( register long mask; \
418: mask = 0x80000000; \
419: sizex -= 1; \
420: mask >>= sizex; \
421: ((unsigned long) mask) >>= dskew; \
422: IfReverse(mask = ~mask;,),) \
423: dskew = 16 - dskew; \
424: do { \
425: IfMask(*(u_int *) dp IfReverse(&,|)= mask;,) \
426: *(u_int *) dp op (*sp++ << dskew); \
427: dp += vert; \
428: } while (--sizey != -1); \
429: } \
430: }
431:
432: #define MTRUE(a,b) a
433: #define MFALSE(a,b) b
434:
435: #define ClippedOp(mask,op,revmask) \
436: if(clip) MEMBATCH(MTRUE,mask,op,revmask) \
437: else MEMBATCH(MFALSE,mask,op,revmask)
438:
439: mem_batchrop(dst, op, src, count)
440: struct pr_prpos dst;
441: int op;
442: struct pr_prpos *src;
443: short count;
444: {
445: register u_short *sp;
446: register char *dp;
447: char *dp0;
448: register char *handy;
449: register short sizex, sizey;
450: register vert, dskew;
451: int dskew0, xoff0;
452: int errors = 0;
453: int clip, limx, limy;
454: int oppassed = op;
455:
456: /*
457: * Preliminaries: get pixrect data and image pointers; decide whether
458: * clipping. If not clipping, normalize op, else compute limits for
459: * cursors for later comparisons.
460: */
461:
462: clip = 0;
463: if (!(op & PIX_DONTCLIP)) {
464: clip = 1;
465: limx = dst.pr->pr_size.x;
466: limy = dst.pr->pr_size.y;
467: }
468: op = (op >> 1) & 0xf; /* Kill dontclip, just keep useful */
469: /*
470: * If destination is reverse video, invert function. FIXME: we dont
471: * deal with a reverse video source. Admittedly its unlikely that
472: * anyone will call batchrop with a device pixrect as source (since we
473: * copy the whole pixrect), but this is a bug.
474: */
475: if (mpr_d(dst.pr)->md_flags & MP_REVERSEVIDEO)
476: op = pr_reversedst[op];
477:
478: vert = mpr_d(dst.pr)->md_linebytes;
479: #define dprd ((struct mpr_data *)handy)
480: dprd = mpr_d(dst.pr);
481: xoff0 = dprd->md_offset.x;
482: dp0 = (char *) ((int) dprd->md_image
483: + pr_product(dprd->md_linebytes,
484: dst.pos.y + dprd->md_offset.y));
485: #undef dprd
486: restart:
487: #define spr ((struct pixrect *)handy)
488: #define sprd ((struct mpr_data *)handy)
489: switch (op) {
490: case (PIX_SRC ^ PIX_DST) >> 1:
491: ClippedOp(MFALSE, ^=, MTRUE);
492: break;
493: case PIX_SRC >> 1:
494: ClippedOp(MTRUE, |=, MTRUE);
495: break;
496: case PIX_NOT(PIX_SRC) >> 1:
497: ClippedOp(MTRUE, ^=, MFALSE);
498: break;
499: case (PIX_SRC | PIX_DST) >> 1:
500: ClippedOp(MFALSE, |=, MTRUE);
501: break;
502: case (PIX_NOT(PIX_SRC) & PIX_DST) >> 1:
503: ClippedOp(MFALSE, &=~, MTRUE);
504: break;
505: default:
506: for (; --count >= 0; src++) {
507: dst.pos.x += src->pos.x;
508: errors |= mem_rop(dst.pr, dst.pos, src->pr->pr_size,
509: oppassed, src->pr, 0, 0);
510: }
511: }
512: return errors;
513: hard:
514: if (dst.pos.x + sizex <= 0)
515: /*
516: * Completely clipped on left...
517: */
518: ;
519: else {
520: errors |= mem_rop(dst.pr, dst.pos, src->pr->pr_size,
521: oppassed, src->pr, 0, 0);
522: }
523: src++;
524: goto restart;
525: }
526:
527: /*
528: * cg2batch.c: Sun2 Color batchrop
529: */
530:
531: extern struct pixrectops mem_ops;
532:
533:
534: extern short mrc_lmasktable[];
535: extern short mrc_rmasktable[];
536:
537: #define resolution unused, 0
538:
539: cg2_batchrop(dst, op, src, count)
540: struct pr_prpos dst;
541: int op;
542: struct pr_prpos *src;
543: register int count;
544: {
545: register short sizey;
546: register int tem, w, prime, linebytes;
547: register short *bx, *leftx, *ma;
548: register struct memropc *ropregs;
549: short sizex;
550: int clip;
551: struct pixrect *pr;
552: short *ma_homey;
553: short homex, homey, limx, limy, dstx, dsty, by;
554:
555: struct cg2fb *fb;
556: struct mpr_data *md;
557: int oppassed = op;
558: int errors = 0;
559: short color;
560:
561: if (count <= 0)
562: return (0);
563:
564: /*
565: * Preliminaries: get pixrect data and frame buffer pointers; decide
566: * whether clipping. If not clipping, normalize op, else compute
567: * limits for cursors for later comparisons.
568: */
569: #define dbd ((struct cg2pr *)leftx)
570: dbd = cg2_d(dst.pr);
571: homex = dbd->cgpr_offset.x;
572: homey = dbd->cgpr_offset.y;
573: #define FB ((struct cg2fb *)leftx)
574: FB = dbd->cgpr_va;
575: fb = FB;
576: #undef dbd
577: ropregs = &FB->ropcontrol[CG2_ALLROP].ropregs;
578: if (op & PIX_DONTCLIP) {
579: op &= ~PIX_DONTCLIP;
580: clip = 0;
581: }
582: else {
583: clip = 1;
584: limx = homex + dst.pr->pr_size.x;
585: limy = homey + dst.pr->pr_size.y;
586: }
587: dstx = homex + dst.pos.x;
588: dsty = homey + dst.pos.y;
589: if (private_bgcolor < 0) {
590: FB->ppmask.reg = private_fgcolor; /* set colored text */
591: ropregs->mrc_pattern = -1;
592: FB->ppmask.reg = ~private_fgcolor;
593: ropregs->mrc_pattern = 0;
594: FB->ppmask.reg = private_czmask;
595: switch (op & 0x1E) {
596: case PIX_SRC ^ PIX_DST:
597: ropregs->mrc_op = CG_SRC & (CG_MASK ^ CG_DEST) | ~CG_SRC & CG_DEST;
598: break;
599: case PIX_NOT(PIX_DST):
600: ropregs->mrc_op = CG_SRC & (~CG_DEST) | ~CG_SRC & CG_DEST;
601: break;
602: default:
603: ropregs->mrc_op = CG_SRC & CG_MASK | ~CG_SRC & CG_DEST;
604: break;
605: }
606: }
607: else {
608: FB->ppmask.reg = private_fgcolor & private_bgcolor;
609: ropregs->mrc_op = ~0;
610: FB->ppmask.reg = ~(private_fgcolor | private_bgcolor);
611: ropregs->mrc_op = 0;
612: FB->ppmask.reg = private_fgcolor & ~private_bgcolor;
613: ropregs->mrc_op = CG_SRC;
614: FB->ppmask.reg = ~private_fgcolor & private_bgcolor;
615: ropregs->mrc_op = ~CG_SRC;
616: FB->ppmask.reg = private_czmask;
617: }
618: FB->status.reg.ropmode = PWWWRD;
619: linebytes = cg2_linebytes(FB, PWWWRD);
620: #undef FB
621:
622: for (; --count >= 0; src++) {
623: /*
624: * Update destination x and y by pre-advance amount. If no pixrect
625: * for this, then skip to next.
626: */
627: dstx += src->pos.x;
628: pr = src->pr;
629: if (pr == 0)
630: continue;
631: sizex = pr->pr_size.x;
632: sizey = pr->pr_size.y;
633: md = mpr_d(pr);
634: ma = md->md_image;
635:
636: /*
637: * Grab sizes and address of image. If clipping (rare case
638: * hopefully) compare cursors against limits.
639: */
640: by = dsty;
641: tem = 0;
642: if (clip) {
643: if (dstx + sizex > limx)
644: sizex = limx - dstx;
645: if (dsty + sizey > limy)
646: sizey = limy - dsty;
647: if (dsty < homey) { /* works if pr_depth = 1! */
648: tem = homey - dsty;
649: by += tem;
650: ma += pr_product(tem, (md->md_linebytes >> 1));
651: sizey -= tem;
652: tem = 0;
653: }
654: if (dstx < homex) {
655: tem = homex - dstx;
656: ma += tem >> 4;
657: sizex -= tem;
658: }
659: if (sizex <= 0)
660: continue;
661: }
662:
663: /*
664: * Hard case: characters greater than 16 wide.
665: */
666: ma_homey = ma;
667:
668: /* set the ROP chip word width and opcount */
669:
670: w = cg2_prskew(dstx); /* source skew is 0 */
671: ropregs->mrc_shift = (w & 0xF) | (1 << 8);
672: prime = !w;
673: w = (sizex + w + (tem & 0xF) - 1) >> 4;
674: ropregs->mrc_width = w;
675: ropregs->mrc_opcount = w;
676:
677: /* set the ROP chip end masks */
678:
679: ropregs->mrc_mask1 =
680: mrc_lmasktable[(tem += dstx) & 0xf];
681: ropregs->mrc_mask2 =
682: mrc_rmasktable[(sizex + tem - 1) & 0xf];
683:
684: leftx = cg2_ropwordaddr(fb, 0, tem, by);
685: tem = md->md_linebytes;
686: if (--sizey >= 0)
687: if (w) {
688: w++;
689: do {
690: register short i = w;
691: ma = ma_homey;
692: bx = leftx;
693: if (prime)
694: ropregs->mrc_source1 = *ma++;
695: while (i--)
696: *bx++ = *ma++;
697: (char *) ma_homey += tem;
698: (char *) leftx += linebytes;
699: } while (--sizey != -1);
700: }
701: else {
702: bx = leftx;
703: ma = ma_homey;
704: if (prime) {
705: ma++;
706: do {
707: ma--;
708: ropregs->mrc_source1 = *ma++;
709: *bx = *ma;
710: (char *) ma += tem;
711: (char *) bx += linebytes;
712: } while (--sizey != -1);
713: }
714: else
715: do {
716: *bx = *ma;
717: (char *) ma += tem;
718: (char *) bx += linebytes;
719: } while (--sizey != -1);
720: }
721: }
722:
723: return (errors);
724: }
725:
726: #endif sun
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.