Git init
[framework/uifw/xorg/lib/libxaw.git] / src / AsciiSrc.c
1 /*
2
3 Copyright 1989, 1994, 1998  The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24
25 */
26
27 /*
28  * AsciiSrc.c - AsciiSrc object. (For use with the text widget).
29  *
30  */
31
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <ctype.h>
38 #include <errno.h>
39 #include <X11/IntrinsicP.h>
40 #include <X11/StringDefs.h>
41 #include <X11/Xos.h>
42 #include <X11/Xfuncs.h>
43 #include <X11/Xmu/CharSet.h>
44 #include <X11/Xmu/Misc.h>
45 #include <X11/Xaw/XawInit.h>
46 #include <X11/Xaw/AsciiSrcP.h>
47 #include <X11/Xaw/MultiSrcP.h>
48 #ifndef OLDXAW
49 #include <X11/Xaw/TextSinkP.h>
50 #include <X11/Xaw/AsciiSinkP.h>
51 #endif
52 #include "Private.h"
53
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <fcntl.h>
57
58 #if (defined(ASCII_STRING) || defined(ASCII_DISK))
59 #include <X11/Xaw/AsciiText.h>          /* for Widget Classes */
60 #endif
61
62 #ifdef X_NOT_POSIX
63 #define Off_t long
64 #define Size_t unsigned int
65 #else
66 #define Off_t off_t
67 #define Size_t size_t
68 #endif
69
70 #define MAGIC_VALUE     ((XawTextPosition)-1)
71 #define streq(a, b)     (strcmp((a), (b)) == 0)
72
73 /*
74  * Class Methods
75  */
76 static void XawAsciiSrcClassInitialize(void);
77 static void XawAsciiSrcDestroy(Widget);
78 static void XawAsciiSrcGetValuesHook(Widget, ArgList, Cardinal*);
79 static void XawAsciiSrcInitialize(Widget, Widget, ArgList, Cardinal*);
80 static Boolean XawAsciiSrcSetValues(Widget, Widget, Widget,
81                                     ArgList, Cardinal*);
82 static XawTextPosition ReadText(Widget, XawTextPosition, XawTextBlock*, int);
83 static int ReplaceText(Widget, XawTextPosition, XawTextPosition,
84                        XawTextBlock*);
85 static XawTextPosition Scan(Widget, XawTextPosition, XawTextScanType,
86                             XawTextScanDirection, int, Bool);
87 static XawTextPosition Search(Widget, XawTextPosition, XawTextScanDirection,
88                               XawTextBlock*);
89
90 /*
91  * Prototypes
92  */
93 static Piece *AllocNewPiece(AsciiSrcObject, Piece*);
94 static void BreakPiece(AsciiSrcObject, Piece*);
95 static Boolean CvtAsciiTypeToString(Display*, XrmValuePtr, Cardinal*,
96                                     XrmValuePtr, XrmValuePtr, XtPointer*);
97 static void CvtStringToAsciiType(XrmValuePtr, Cardinal*,
98                                  XrmValuePtr, XrmValuePtr);
99 static Piece *FindPiece(AsciiSrcObject, XawTextPosition, XawTextPosition*);
100 static void FreeAllPieces(AsciiSrcObject);
101 static FILE *InitStringOrFile(AsciiSrcObject, Bool);
102 static void LoadPieces(AsciiSrcObject, FILE*, char*);
103 static void RemoveOldStringOrFile(AsciiSrcObject, Bool);
104 static void RemovePiece(AsciiSrcObject, Piece*);
105 static String StorePiecesInString(AsciiSrcObject);
106 static Bool WriteToFile(String, String, unsigned);
107 static Bool WritePiecesToFile(AsciiSrcObject, String);
108 static void GetDefaultPieceSize(Widget, int, XrmValue*);
109
110 /*
111  * More Prototypes
112  */
113 #ifdef ASCII_DISK
114 Widget XawAsciiDiskSourceCreate(Widget, ArgList, Cardinal);
115 #endif
116 #ifdef ASCII_STRING
117 Widget XawStringSourceCreate(Widget, ArgList, Cardinal);
118 void XawTextSetLastPos(Widget, XawTextPosition);
119 #endif
120
121 /*
122  * Initialization
123  */
124 #define offset(field) XtOffsetOf(AsciiSrcRec, ascii_src.field)
125 static XtResource resources[] = {
126   {
127     XtNstring,
128     XtCString,
129     XtRString,
130     sizeof(char*),
131     offset(string),
132     XtRString,
133     NULL
134   },
135   {
136     XtNtype,
137     XtCType,
138     XtRAsciiType,
139     sizeof(XawAsciiType),
140     offset(type),
141     XtRImmediate,
142     (XtPointer)XawAsciiString
143   },
144   {
145     XtNdataCompression,
146     XtCDataCompression,
147     XtRBoolean,
148     sizeof(Boolean),
149     offset(data_compression),
150     XtRImmediate,
151     (XtPointer)True
152   },
153   {
154     XtNpieceSize,
155     XtCPieceSize,
156     XtRInt,
157     sizeof(XawTextPosition),
158     offset(piece_size),
159     XtRCallProc,
160     (XtPointer)GetDefaultPieceSize
161   },
162 #ifdef OLDXAW
163   {
164     XtNcallback,
165     XtCCallback,
166     XtRCallback,
167     sizeof(XtPointer), 
168     offset(callback),
169     XtRCallback,
170     (XtPointer)NULL
171   },
172 #endif
173   {
174     XtNuseStringInPlace,
175     XtCUseStringInPlace,
176     XtRBoolean,
177     sizeof(Boolean),
178     offset(use_string_in_place),
179     XtRImmediate,
180     (XtPointer)False
181   },
182   {
183     XtNlength,
184     XtCLength,
185     XtRInt,
186     sizeof(int),
187     offset(ascii_length),
188     XtRImmediate,
189     (XtPointer)MAGIC_VALUE
190   },
191 #ifdef ASCII_DISK
192   {
193     XtNfile,
194     XtCFile,
195     XtRString,
196     sizeof(String),
197     offset(filename),
198     XtRString,
199     NULL
200   },
201 #endif /* ASCII_DISK */
202 };
203 #undef offset
204
205
206 #define Superclass      (&textSrcClassRec)
207 AsciiSrcClassRec asciiSrcClassRec = {
208   /* object */
209   {
210     (WidgetClass)Superclass,            /* superclass */
211     "AsciiSrc",                         /* class_name */
212     sizeof(AsciiSrcRec),                /* widget_size */
213     XawAsciiSrcClassInitialize,         /* class_initialize */
214     NULL,                               /* class_part_initialize */
215     False,                              /* class_inited */
216     XawAsciiSrcInitialize,              /* initialize */
217     NULL,                               /* initialize_hook */
218     NULL,                               /* realize */
219     NULL,                               /* actions */
220     0,                                  /* num_actions */
221     resources,                          /* resources */
222     XtNumber(resources),                /* num_resources */
223     NULLQUARK,                          /* xrm_class */
224     False,                              /* compress_motion */
225     False,                              /* compress_exposure */
226     False,                              /* compress_enterleave */
227     False,                              /* visible_interest */
228     XawAsciiSrcDestroy,                 /* destroy */
229     NULL,                               /* resize */
230     NULL,                               /* expose */
231     XawAsciiSrcSetValues,               /* set_values */
232     NULL,                               /* set_values_hook */
233     NULL,                               /* set_values_almost */
234     XawAsciiSrcGetValuesHook,           /* get_values_hook */
235     NULL,                               /* accept_focus */
236     XtVersion,                          /* version */
237     NULL,                               /* callback_private */
238     NULL,                               /* tm_table */
239     NULL,                               /* query_geometry */
240     NULL,                               /* display_accelerator */
241     NULL,                               /* extension */
242   },
243   /* text_src */
244   {
245     ReadText,                           /* Read */
246     ReplaceText,                        /* Replace */
247     Scan,                               /* Scan */
248     Search,                             /* Search */
249     XtInheritSetSelection,              /* SetSelection */
250     XtInheritConvertSelection,          /* ConvertSelection */
251   },
252   /* ascii_src */
253   {
254     NULL,                               /* extension */
255   },
256 };
257
258 WidgetClass asciiSrcObjectClass = (WidgetClass)&asciiSrcClassRec;
259
260 static XrmQuark Qstring, Qfile;
261
262 /*
263  * Implementation
264  */
265 /*
266  * Function:
267  *      XawAsciiSrcClassInitialize()
268  *
269  * Description:
270  *        Initializes the asciiSrcObjectClass and install the converters for
271  *      AsciiType <-> String.
272  */
273 static void
274 XawAsciiSrcClassInitialize(void)
275 {
276     XawInitializeWidgetSet();
277     Qstring = XrmPermStringToQuark(XtEstring);
278     Qfile = XrmPermStringToQuark(XtEfile);
279     XtAddConverter(XtRString, XtRAsciiType, CvtStringToAsciiType, NULL, 0);
280     XtSetTypeConverter(XtRAsciiType, XtRString, CvtAsciiTypeToString,
281                        NULL, 0, XtCacheNone, NULL);
282 }
283
284 /*
285  * Function:
286  *      XawAsciiSrcInitialize
287  *
288  * Parameters:
289  *      request  - widget requested by the argument list
290  *      cnew     - new widget with both resource and non resource values
291  *      args     - (unused)
292  *      num_args - (unused)
293  *
294  * Description:
295  *      Initializes the ascii src object.
296  */
297 /*ARGSUSED*/
298 static void
299 XawAsciiSrcInitialize(Widget request, Widget cnew,
300                       ArgList args, Cardinal *num_args)
301 {
302     AsciiSrcObject src = (AsciiSrcObject)cnew;
303     FILE *file;
304
305     /*
306      * Set correct flags (override resources) depending upon widget class
307      */
308     src->text_src.text_format = XawFmt8Bit;
309
310 #ifdef ASCII_DISK
311     if (XtIsSubclass(XtParent(cnew), asciiDiskWidgetClass)) {
312         src->ascii_src.type = XawAsciiFile;
313         src->ascii_src.string = src->ascii_src.filename;
314     }
315 #endif
316
317 #ifdef ASCII_STRING
318     if (XtIsSubclass(XtParent(cnew), asciiStringWidgetClass)) {
319         src->ascii_src.use_string_in_place = True;
320         src->ascii_src.type = XawAsciiString;
321     }
322 #endif
323
324 #ifdef OLDXAW
325     src->ascii_src.changes = False;
326 #else
327     src->text_src.changed = False;
328 #endif
329     src->ascii_src.allocated_string = False;
330
331     if (src->ascii_src.use_string_in_place && src->ascii_src.string == NULL)
332         src->ascii_src.use_string_in_place = False;
333
334     file = InitStringOrFile(src, src->ascii_src.type == XawAsciiFile);
335     LoadPieces(src, file, NULL);
336
337     if (file != NULL)
338         fclose(file);
339 }
340
341 /*
342  * Function:
343  *      ReadText
344  *
345  * Parameters:
346  *      w       - AsciiSource widget
347  *      pos     - position of the text to retreive.
348  *      text    - text block that will contain returned text
349  *      length  - maximum number of characters to read
350  *
351  * Description:
352  *      This function reads the source.
353  *
354  * Returns:
355  *      The character position following the retrieved text.
356  */
357 static XawTextPosition
358 ReadText(Widget w, XawTextPosition pos, XawTextBlock *text, int length)
359 {
360     AsciiSrcObject src = (AsciiSrcObject)w;
361     XawTextPosition count, start;
362     Piece *piece;
363 #ifndef OLDXAW 
364     XawTextAnchor *anchor;
365     XawTextEntity *entity;
366     XawTextPosition offset, end = pos + length;
367     Bool state;
368
369     end = XawMin(end, src->ascii_src.length);
370     while ((state = XawTextSourceAnchorAndEntity(w, pos, &anchor, &entity)) &&
371         (entity->flags & XAW_TENTF_HIDE))
372         pos = anchor->position + entity->offset + entity->length;
373     if (state == False ||
374         !(entity->flags & XAW_TENTF_REPLACE)) {
375         while (entity) {
376             offset = anchor->position + entity->offset;
377             if (offset >= end)
378                 break;
379             if (offset > pos &&
380                 (entity->flags & (XAW_TENTF_HIDE | XAW_TENTF_REPLACE))) {
381                 end = XawMin(end, offset);
382                 break;
383             }
384             if ((entity = entity->next) == NULL &&
385                 (anchor = XawTextSourceNextAnchor(w, anchor)) != NULL)
386                 entity = anchor->entities;
387         }
388     }
389     else if (state && (entity->flags & XAW_TENTF_REPLACE) && pos < end) {
390         XawTextBlock *block = (XawTextBlock*)entity->data;
391
392         offset = anchor->position + entity->offset;
393         end = XawMin(end, offset + block->length);
394         if ((length = end - pos) < 0)
395             length = 0;
396         text->length = length;
397         text->format = XawFmt8Bit;
398         if (length == 0) {
399             text->firstPos = end = offset + entity->length;
400             text->ptr = "";
401         }
402         else {
403             text->firstPos = pos;
404             text->ptr = block->ptr + (pos - offset);
405             if (pos + length < offset + block->length)
406                 end = pos + length;     /* there is data left to be read */
407             else
408                 end = offset + entity->length;
409         }
410
411         return (end);
412     }
413
414     if ((length = end - pos) < 0)
415         length = 0;
416 #endif
417
418     piece = FindPiece(src, pos, &start);
419     text->firstPos = pos;
420     text->ptr = piece->text + (pos - start);
421     count = piece->used - (pos - start);
422     text->length = Max(0, (length > count) ? count : length);
423     text->format = XawFmt8Bit;
424
425     return (pos + text->length);
426 }
427
428 /*
429  * Function:
430  *      ReplaceText
431  *
432  * Parameters:
433  *      w        - AsciiSource object
434  *      startPos - ends of text that will be replaced
435  *      endPos   - ""
436  *      text     - new text to be inserted into buffer at startPos
437  *
438  * Description:
439  *      Replaces a block of text with new text.
440  *
441  * Returns:
442  *      XawEditDone on success, XawEditError otherwise
443  */
444 /*ARGSUSED*/
445 static int
446 ReplaceText(Widget w, XawTextPosition startPos, XawTextPosition endPos,
447             XawTextBlock *text)
448 {
449     AsciiSrcObject src = (AsciiSrcObject)w;
450     Piece *start_piece, *end_piece, *temp_piece;
451     XawTextPosition start_first, end_first;
452     int length, firstPos;
453
454     /*
455      * Editing a read only source is not allowed
456      */
457     if (src->text_src.edit_mode == XawtextRead) 
458         return (XawEditError);
459
460     start_piece = FindPiece(src, startPos, &start_first);
461     end_piece = FindPiece(src, endPos, &end_first);
462
463 #ifndef OLDXAW
464     /*
465      * This is a big hack, but I can't think about a clever way to know
466      * if the character being moved forward has a negative lbearing.
467      *
468      */
469     if (start_piece->used) {
470         int i;
471
472         for (i = 0; i < src->text_src.num_text; i++) {
473             int line;
474             TextWidget ctx = (TextWidget)src->text_src.text[i];
475
476             for (line = 0; line < ctx->text.lt.lines; line++)
477                 if (startPos < ctx->text.lt.info[line + 1].position)
478                     break;
479             if (i < ctx->text.lt.lines &&
480                 startPos > ctx->text.lt.info[i].position) {
481                 AsciiSinkObject sink = (AsciiSinkObject)ctx->text.sink;
482                 XawTextAnchor *anchor;
483                 XawTextEntity *entity;
484                 XawTextProperty *property;
485                 XFontStruct *font;
486
487                 if (XawTextSourceAnchorAndEntity(w, startPos, &anchor, &entity) &&
488                     (property = XawTextSinkGetProperty(ctx->text.sink,
489                                                        entity->property)) != NULL &&
490                     (property->mask & XAW_TPROP_FONT))
491                     font = property->font;
492                 else
493                     font = sink->ascii_sink.font;
494
495                 if (font->min_bounds.lbearing < 0) {
496                     int lbearing = font->min_bounds.lbearing;
497                     unsigned char c = *(unsigned char*)
498                         (start_piece->text + (startPos - start_first));
499
500                     if (c == '\t' || c == '\n')
501                         c = ' ';
502                     else if ((c & 0177) < XawSP || c == 0177) {
503                         if (sink->ascii_sink.display_nonprinting)
504                             c = c > 0177 ? '\\' : c + '^';
505                         else
506                             c = ' ';
507                     }
508                     if (font->per_char &&
509                         (c >= font->min_char_or_byte2 && c <= font->max_char_or_byte2))
510                         lbearing = font->per_char[c - font->min_char_or_byte2].lbearing;
511                     if (lbearing < 0)
512                         _XawTextNeedsUpdating(ctx, startPos - 1, startPos);
513                 }
514             }
515         }
516     }
517
518
519 #endif
520
521     /*
522      * Remove Old Stuff
523      */
524     if (start_piece != end_piece) {
525         temp_piece = start_piece->next;
526
527         /*
528          * If empty and not the only piece then remove it.
529          */
530         if (((start_piece->used = startPos - start_first) == 0)
531             && !(start_piece->next == NULL && start_piece->prev == NULL))
532             RemovePiece(src, start_piece);
533
534         while (temp_piece != end_piece) {
535             temp_piece = temp_piece->next;
536             RemovePiece(src, temp_piece->prev);
537         }
538
539         end_piece->used -= endPos - end_first;
540         if (end_piece->used != 0)
541             memmove(end_piece->text, end_piece->text + endPos - end_first,
542                     (unsigned)end_piece->used);
543     }
544     else {                  /* We are fully in one piece */
545         if ((start_piece->used -= endPos - startPos) == 0) {
546             if (!(start_piece->next == NULL && start_piece->prev == NULL))
547                 RemovePiece(src, start_piece);
548         }
549         else {
550             memmove(start_piece->text + (startPos - start_first),
551                     start_piece->text + (endPos - start_first),
552                     (unsigned)(start_piece->used - (startPos - start_first)));
553             if (src->ascii_src.use_string_in_place
554                 && src->ascii_src.length - (endPos - startPos)
555                 < src->ascii_src.piece_size - 1)
556                 start_piece->text[src->ascii_src.length - (endPos - startPos)] =
557                     '\0';
558         }
559     }
560
561     src->ascii_src.length += -(endPos - startPos) + text->length;
562
563     if ( text->length != 0) {
564         /* 
565          * Put in the New Stuff
566          */
567         start_piece = FindPiece(src, startPos, &start_first);
568
569         length = text->length;
570         firstPos = text->firstPos;
571
572         while (length > 0) {
573             char *ptr;
574             int fill;
575
576             if (src->ascii_src.use_string_in_place) {
577                 if (start_piece->used == src->ascii_src.piece_size - 1) {
578                     /*
579                      * If we are in ascii string emulation mode. Then the
580                      *  string is not allowed to grow
581                      */
582                     start_piece->used = src->ascii_src.length =
583                         src->ascii_src.piece_size - 1;
584                     start_piece->text[src->ascii_src.length] = '\0';
585                     return (XawEditError);
586                 }
587             }
588
589             if (start_piece->used == src->ascii_src.piece_size) {
590                 BreakPiece(src, start_piece);
591                 start_piece = FindPiece(src, startPos, &start_first);
592             }
593
594             fill = Min((int)(src->ascii_src.piece_size - start_piece->used),
595                        length);
596
597             ptr = start_piece->text + (startPos - start_first);
598             memmove(ptr + fill, ptr,
599                     (unsigned)(start_piece->used - (startPos - start_first)));
600             memcpy(ptr, text->ptr + firstPos, (unsigned)fill);
601
602             startPos += fill;
603             firstPos += fill;
604             start_piece->used += fill;
605             length -= fill;
606         }
607     }
608
609     if (src->ascii_src.use_string_in_place)
610         start_piece->text[start_piece->used] = '\0';
611
612 #ifdef OLDXAW
613     src->ascii_src.changes = True;
614     XtCallCallbacks(w, XtNcallback, NULL);
615 #endif
616
617     return (XawEditDone);
618 }
619
620 /*
621  * Function:
622  *      Scan
623  *
624  * Parameters:
625  *      w        - AsciiSource object
626  *      position - position to start scanning
627  *      type     - type of thing to scan for
628  *      dir      - direction to scan
629  *                 count - which occurance if this thing to search for.
630  *                 include - whether or not to include the character found in
631  *                 the position that is returned
632  *
633  * Description:
634  *      Scans the text source for the number and type of item specified.
635  *
636  * Returns:
637  *      The position of the item found
638  *
639  * Note:
640  *        While there are only 'n' characters in the file there are n+1
641  *       possible cursor positions (one before the first character and
642  *      one after the last character
643  */
644 static XawTextPosition
645 Scan(Widget w, register XawTextPosition position, XawTextScanType type,
646      XawTextScanDirection dir, int count, Bool include)
647 {
648     AsciiSrcObject src = (AsciiSrcObject)w;
649     Piece *piece;
650     XawTextPosition first, first_eol_position = 0;
651     register char *ptr, *lim;
652     register int cnt = count;
653     register unsigned char c;
654
655     if (dir == XawsdLeft) {
656         if (position <= 0)
657             return (0);
658         --position;
659     }
660     else if (position >= src->ascii_src.length)
661         return (src->ascii_src.length);
662
663     piece = FindPiece(src, position, &first);
664     if (piece->used == 0)
665         return (0);
666
667     ptr = (position - first) + piece->text;
668
669     if (dir == XawsdRight) {
670         lim = piece->text + piece->used;
671         switch (type) {
672             case XawstEOL:
673             case XawstParagraph:
674             case XawstWhiteSpace:
675             case XawstAlphaNumeric:
676                 for (; cnt > 0; cnt--) {
677                     Bool non_space = False, first_eol = True;
678
679                     /*CONSTCOND*/
680                     while (True) {
681                         if (ptr >= lim) {
682                             piece = piece->next;
683                             if (piece == NULL)  /* End of text */
684                                 return (src->ascii_src.length);
685                             ptr = piece->text;
686                             lim = piece->text + piece->used;
687                         }
688
689                         c = *ptr++;
690                         ++position;
691
692                         if (type == XawstEOL) {
693                             if (c == '\n')
694                                 break;
695                         }
696                         else if (type == XawstAlphaNumeric) {
697                             if (!isalnum(c)) {
698                                 if (non_space)
699                                     break;
700                             }
701                             else
702                                 non_space = True;
703                         }
704                         else if (type == XawstWhiteSpace) {
705                             if (isspace(c)) {
706                                 if (non_space)
707                                     break;
708                             }
709                             else
710                                 non_space = True;
711                         }
712                         else {  /* XawstParagraph */
713                             if (first_eol) {
714                                 if (c == '\n') {
715                                     first_eol_position = position;
716                                     first_eol = False;
717                                 }
718                             }
719                             else if (c == '\n')
720                                 break;
721                             else if (!isspace(c))
722                                 first_eol = True;
723                         }
724                     }
725                 }
726                 break;
727             case XawstPositions:
728                 position += count;
729                 return (position < src->ascii_src.length ?
730                         position : src->ascii_src.length);
731             case XawstAll:
732                 return (src->ascii_src.length);
733             default:
734                 break;
735         }
736         if (!include) {
737             if (type == XawstParagraph)
738                 position = first_eol_position;
739             if (count)
740                 --position;
741         }
742     }
743     else {
744         lim = piece->text;
745         switch (type) {
746             case XawstEOL:
747             case XawstParagraph:
748             case XawstWhiteSpace:
749             case XawstAlphaNumeric:
750                 for (; cnt > 0; cnt--) {
751                     Bool non_space = False, first_eol = True;
752
753                     /*CONSTCOND*/
754                     while (True) {
755                         if (ptr < lim) {
756                             piece = piece->prev;
757                             if (piece == NULL)  /* Begining of text */
758                                 return (0);
759                             ptr = piece->text + piece->used - 1;
760                             lim = piece->text;
761                         }
762
763                         c = *ptr--;
764                         --position;
765
766                         if (type == XawstEOL) {
767                             if (c == '\n')
768                                 break;
769                         }
770                         else if (type == XawstAlphaNumeric) {
771                             if (!isalnum(c)) {
772                                 if (non_space)
773                                     break;
774                             }
775                             else
776                                 non_space = True;
777                         }
778                         else if (type == XawstWhiteSpace) {
779                             if (isspace(c)) {
780                                 if (non_space)
781                                     break;
782                             }
783                             else
784                                 non_space = True;
785                         }
786                         else {  /* XawstParagraph */
787                             if (first_eol) {
788                                 if (c == '\n') {
789                                     first_eol_position = position;
790                                     first_eol = False;
791                                 }
792                             }
793                             else if (c == '\n')
794                                 break;
795                             else if (!isspace(c))
796                                 first_eol = True;
797                         }
798                     }
799                 }
800                 break;
801             case XawstPositions:
802                 position -= count - 1;
803                 return (position > 0 ? position : 0);
804             case XawstAll:
805                 return (0);
806             default:
807                 break;
808         }
809         if (!include) {
810             if (type == XawstParagraph)
811                 position = first_eol_position;
812             if (count)
813                 ++position;
814         }
815         position++;
816     }
817
818     return (position);
819 }
820
821 /*
822  * Function:
823  *      Search
824  *
825  * Parameters:
826  *      w        - AsciiSource object
827  *      position - the position to start scanning
828  *      dir      - direction to scan
829  *      text     - text block to search for
830  *
831  * Description:
832  *      Searchs the text source for the text block passed.
833  *
834  * Returns:
835  *      The position of the item found
836  */
837 static XawTextPosition 
838 Search(Widget w, register XawTextPosition position, XawTextScanDirection dir,
839        XawTextBlock *text)
840 {
841     AsciiSrcObject src = (AsciiSrcObject)w;
842     register int count = 0;
843     register char *ptr, c;
844     char *str;
845     Piece *piece;
846     char *buf;
847     XawTextPosition first;
848     int cnt, case_sensitive;
849
850     if (dir == XawsdLeft) {
851         if (position == 0)
852             return (XawTextSearchError);
853         position--;
854     }
855
856     buf = XtMalloc((unsigned)sizeof(unsigned char) * text->length);
857     memcpy(buf, text->ptr, (unsigned)text->length);
858     piece = FindPiece(src, position, &first);
859     ptr = (position - first) + piece->text;
860     case_sensitive = text->firstPos;
861
862     if (dir == XawsdRight) {
863         str = buf;
864         c = *str;
865         /*CONSTCOND*/
866         while (1) {
867             if (*ptr++ == c
868                 || (case_sensitive && isalpha(c) && isalpha(ptr[-1])
869                     && toupper(c) == toupper(ptr[-1]))) {
870                 if (++count == text->length)
871                     break;
872                 c = *++str;
873             }
874             else if (count) {
875                 ptr -= count;
876                 str -= count;
877                 position -= count;
878                 count = 0;
879                 c = *str;
880
881                 if (ptr < piece->text) {
882                     do {
883                         cnt = piece->text - ptr;
884                         piece = piece->prev;
885                         if (piece == NULL) {
886                             XtFree(buf);
887                             return (XawTextSearchError);
888                         }
889                         ptr = piece->text + piece->used - cnt;
890                     } while (ptr < piece->text);
891                 }
892             }
893             position++;
894             if (ptr >= (piece->text + piece->used)) {
895                 do {
896                     cnt = ptr - (piece->text + piece->used);
897                     piece = piece->next;
898                     if (piece == NULL) {
899                         XtFree(buf);
900                         return (XawTextSearchError);
901                     }
902                     ptr = piece->text + cnt;
903                 } while (ptr >= (piece->text + piece->used));
904             }
905         }
906
907         position -= text->length - 1;
908     }
909     else {
910         str = buf + text->length - 1;
911         c = *str;
912         /*CONSTCOND*/
913         while (1) {
914             if (*ptr-- == c
915                 || (case_sensitive && isalpha(c) && isalpha(ptr[1])
916                     && toupper(c) == toupper(ptr[1]))) {
917                 if (++count == text->length)
918                     break;
919                 c = *--str;
920             }
921             else if (count) {
922                 ptr += count;
923                 str += count;
924                 position += count;
925                 count = 0;
926                 c = *str;
927
928                 if (ptr >= (piece->text + piece->used)) {
929                     do {
930                         cnt = ptr - (piece->text + piece->used);
931                         piece = piece->next;
932                         if (piece == NULL) {
933                             XtFree(buf);
934                             return (XawTextSearchError);
935                         }
936                         ptr = piece->text + cnt;
937                     } while (ptr >= (piece->text + piece->used));
938                 }
939             }
940             position--;
941             if (ptr < piece->text) {
942                 do {
943                     cnt = piece->text - ptr;
944                     piece = piece->prev;
945                     if (piece == NULL) {
946                         XtFree(buf);
947                         return (XawTextSearchError);
948                     }
949                     ptr = piece->text + piece->used - cnt;
950                 } while (ptr < piece->text);
951             }
952         }
953     }
954
955     XtFree(buf);
956
957     return (position);
958 }
959
960 /*
961  * Function:
962  *      XawAsciiSrcSetValues
963  *
964  * Parameters:
965  *      current  - current state of the widget
966  *      request  - what was requested
967  *      cnew     - what the widget will become
968  *      args     - representation of changed resources
969  *      num_args - number of resources that have changed
970  *
971  * Description:
972  *      Sets the values for the AsciiSource.
973  *
974  * Returns:
975  *      True if redisplay is needed
976  */
977 static Boolean
978 XawAsciiSrcSetValues(Widget current, Widget request, Widget cnew,
979                      ArgList args, Cardinal *num_args)
980 {
981     AsciiSrcObject src = (AsciiSrcObject)cnew;
982     AsciiSrcObject old_src = (AsciiSrcObject)current;
983     Bool total_reset = False, string_set = False;
984     FILE *file;
985     unsigned int i;
986
987     if (old_src->ascii_src.use_string_in_place
988         != src->ascii_src.use_string_in_place) {
989         XtAppWarning(XtWidgetToApplicationContext(cnew),
990                      "AsciiSrc: The XtNuseStringInPlace resource may "
991                      "not be changed.");
992         src->ascii_src.use_string_in_place =
993             old_src->ascii_src.use_string_in_place;
994     }
995
996     for (i = 0; i < *num_args ; i++)
997         if (streq(args[i].name, XtNstring)) {
998             string_set = True;
999             break;
1000         }
1001
1002     if (string_set || (old_src->ascii_src.type != src->ascii_src.type)) {
1003         RemoveOldStringOrFile(old_src, string_set); /* remove old info */
1004         file = InitStringOrFile(src, string_set);   /* Init new info */
1005         LoadPieces(src, file, NULL);   /* load new info into internal buffers */
1006         if (file != NULL)
1007             fclose(file);
1008 #ifndef OLDXAW
1009         for (i = 0; i < src->text_src.num_text; i++)
1010             /* Tell text widget what happened */
1011             XawTextSetSource(src->text_src.text[i], cnew, 0);
1012 #else
1013         XawTextSetSource(XtParent(cnew), cnew, 0);
1014 #endif
1015         total_reset = True;
1016     }
1017
1018     if (old_src->ascii_src.ascii_length != src->ascii_src.ascii_length)
1019         src->ascii_src.piece_size = src->ascii_src.ascii_length + 1;
1020
1021     if (!total_reset &&
1022         old_src->ascii_src.piece_size != src->ascii_src.piece_size) {
1023         String string = StorePiecesInString(old_src);
1024
1025         FreeAllPieces(old_src);
1026         LoadPieces(src, NULL, string);
1027         XtFree(string);
1028     }
1029
1030     return (False);
1031 }
1032
1033 /*
1034  * Function:
1035  *      XawAsciiSrcGetValuesHook
1036  *
1037  * Parameters:
1038  *      w        - AsciiSource Widget
1039  *      args     - argument list
1040  *      num_args - number of args
1041  *
1042  * Description:
1043  *        This is a get values hook routine that sets the
1044  *                   values specific to the ascii source.
1045  */
1046 static void
1047 XawAsciiSrcGetValuesHook(Widget w, ArgList args, Cardinal *num_args)
1048 {
1049     AsciiSrcObject src = (AsciiSrcObject)w;
1050     unsigned int i;
1051
1052     if (src->ascii_src.type == XawAsciiString) {
1053         for (i = 0; i < *num_args ; i++)
1054             if (streq(args[i].name, XtNstring)) {
1055                 if (src->ascii_src.use_string_in_place)
1056                     *((char **)args[i].value) = src->ascii_src.first_piece->text;
1057                 else if (XawAsciiSave(w))   /* If save sucessful */
1058                     *((char **)args[i].value) = src->ascii_src.string;
1059                 break;
1060             }
1061         }
1062     }
1063
1064 /*
1065  * Function:
1066  *      XawAsciiSrcDestroy
1067  *
1068  * Parameters:
1069  *      src - Ascii source object to free
1070  *
1071  * Description:
1072  *      Destroys an ascii source (frees all data)
1073  */
1074 static void
1075 XawAsciiSrcDestroy(Widget w)
1076 {
1077     RemoveOldStringOrFile((AsciiSrcObject) w, True);
1078 }
1079
1080 /*
1081  * Public routines 
1082  */
1083 /*
1084  * Function:
1085  *      XawAsciiSourceFreeString
1086  *
1087  * Parameters:
1088  *      w - AsciiSrc widget
1089  *
1090  * Description:
1091  *        Frees the string returned by a get values call
1092  *                   on the string when the source is of type string.
1093  */
1094 void
1095 XawAsciiSourceFreeString(Widget w)
1096 {
1097     AsciiSrcObject src = (AsciiSrcObject)w;
1098
1099     /* If the src is really a multi, call the multi routine */
1100     if (XtIsSubclass(w, multiSrcObjectClass)) {
1101         _XawMultiSourceFreeString(w);
1102         return;
1103     }
1104     else if (!XtIsSubclass(w, asciiSrcObjectClass)) {
1105         XtErrorMsg("bad argument", "asciiSource", "XawError",
1106                    "XawAsciiSourceFreeString's parameter must be "
1107                    "an asciiSrc or multiSrc.",
1108                    NULL, NULL);
1109     }
1110
1111     if (src->ascii_src.allocated_string && src->ascii_src.type != XawAsciiFile) {
1112         src->ascii_src.allocated_string = False;
1113         XtFree(src->ascii_src.string);
1114         src->ascii_src.string = NULL;
1115     }
1116 }
1117
1118 /*
1119  * Function:
1120  *      XawAsciiSave
1121  *
1122  * Parameters:
1123  *      w - asciiSrc Widget
1124  *
1125  * Description:
1126  *      Saves all the pieces into a file or string as required.
1127  *
1128  * Returns:
1129  *      True if the save was successful
1130  */
1131 Bool
1132 XawAsciiSave(Widget w)
1133 {
1134     AsciiSrcObject src = (AsciiSrcObject)w;
1135
1136     /* If the src is really a multi, call the multi save */
1137     if (XtIsSubclass(w, multiSrcObjectClass ))
1138         return (_XawMultiSave(w));
1139
1140     else if (!XtIsSubclass(w, asciiSrcObjectClass))
1141         XtErrorMsg("bad argument", "asciiSource", "XawError",
1142                    "XawAsciiSave's parameter must be an asciiSrc or multiSrc.",
1143                    NULL, NULL);
1144
1145     /*
1146      * If using the string in place then there is no need to play games
1147      * to get the internal info into a readable string.
1148      */
1149     if (src->ascii_src.use_string_in_place) 
1150         return (True);
1151
1152     if (src->ascii_src.type == XawAsciiFile) {
1153 #ifdef OLDXAW
1154         if (!src->ascii_src.changes)
1155 #else
1156         if (!src->text_src.changed)             /* No changes to save */
1157 #endif
1158             return (True);
1159
1160         if (WritePiecesToFile(src, src->ascii_src.string) == False)
1161             return (False);
1162     }
1163     else  {
1164         if (src->ascii_src.allocated_string == True)
1165             XtFree(src->ascii_src.string);
1166         else
1167             src->ascii_src.allocated_string = True;
1168
1169         src->ascii_src.string = StorePiecesInString(src);
1170     }
1171 #ifdef OLDXAW
1172     src->ascii_src.changes = False;
1173 #else
1174     src->text_src.changed = False;
1175 #endif
1176
1177     return (True);
1178 }
1179
1180 /*
1181  * Function:
1182  *      XawAsciiSaveAsFile
1183  *
1184  * Arguments:
1185  *      w    - AsciiSrc widget
1186  *      name - name of the file to save this file into
1187  *
1188  * Description:
1189  *      Save the current buffer as a file.
1190  *
1191  * Returns:
1192  *      True if the save was sucessful
1193  */
1194 Bool
1195 XawAsciiSaveAsFile(Widget w, _Xconst char *name)
1196 {
1197     AsciiSrcObject src = (AsciiSrcObject)w;
1198     Bool ret;
1199
1200     /* If the src is really a multi, call the multi save */
1201
1202     if (XtIsSubclass( w, multiSrcObjectClass))
1203         return (_XawMultiSaveAsFile(w, name));
1204
1205     else if (!XtIsSubclass(w, asciiSrcObjectClass))
1206         XtErrorMsg("bad argument", "asciiSource", "XawError",
1207                    "XawAsciiSaveAsFile's 1st parameter must be an "
1208                    "asciiSrc or multiSrc.",
1209                    NULL, NULL);
1210
1211     if (src->ascii_src.type == XawAsciiFile)
1212         ret = WritePiecesToFile(src, (String)name);
1213     else {
1214         String string = StorePiecesInString(src); 
1215
1216         ret = WriteToFile(string, (String)name, src->ascii_src.length);
1217         XtFree(string);
1218     }
1219
1220     return (ret);
1221 }
1222
1223 /*
1224  * Function:
1225  *      XawAsciiSourceChanged
1226  *
1227  * Parameters:
1228  *      w - ascii source widget
1229  *
1230  * Description:
1231  *      Returns true if the source has changed since last saved.
1232  *
1233  * Returns:
1234  *      A Boolean (see description).
1235  */
1236 Bool
1237 XawAsciiSourceChanged(Widget w)
1238 {
1239 #ifdef OLDXAW
1240     if (XtIsSubclass(w, multiSrcObjectClass))
1241         return (((MultiSrcObject)w)->multi_src.changes);
1242
1243     if (XtIsSubclass(w, asciiSrcObjectClass))
1244         return (((AsciiSrcObject)w)->ascii_src.changes);
1245 #else
1246     if (XtIsSubclass(w, textSrcObjectClass))
1247         return (((TextSrcObject)w)->textSrc.changed);
1248 #endif
1249     XtErrorMsg("bad argument", "asciiSource", "XawError",
1250                "XawAsciiSourceChanged parameter must be an "
1251                "asciiSrc or multiSrc.",
1252                NULL, NULL);
1253
1254     return (True);
1255 }
1256
1257 /*
1258  * Private Functions
1259  */
1260 static void
1261 RemoveOldStringOrFile(AsciiSrcObject src, Bool checkString) 
1262 {
1263     FreeAllPieces(src);
1264
1265     if (checkString && src->ascii_src.allocated_string) {
1266         XtFree(src->ascii_src.string);
1267         src->ascii_src.allocated_string = False;
1268         src->ascii_src.string = NULL;
1269     }
1270 }
1271
1272 /*
1273  * Function:
1274  *      WriteToFile
1275  *
1276  * Parameters:
1277  *      string - string to write
1278  *      name   - the name of the file
1279  *
1280  * Description:
1281  *      Write the string specified to the begining of the file specified.
1282  *
1283  * Returns:
1284  *      returns True if sucessful, False otherwise
1285  */
1286 static Bool
1287 WriteToFile(String string, String name, unsigned length)
1288 {
1289     int fd;
1290
1291     if ((fd = creat(name, 0666)) == -1)
1292         return (False);
1293
1294     if (write(fd, string, length) == -1) {
1295         close(fd);
1296         return (False);
1297     }
1298
1299     if (close(fd) == -1)
1300         return (False);
1301
1302     return (True);
1303 }
1304
1305 /*
1306  * Function:
1307  *      WritePiecesToFile
1308  *
1309  * Parameters:
1310  *      src  - ascii source object
1311  *      name - name of the file
1312  *
1313  * Description:
1314  *        Almost identical to WriteToFile, but only works for ascii src objects
1315  *      of type XawAsciiFile. This function avoids allocating temporary memory,
1316  *      what can be useful when editing very large files.
1317  *
1318  * Returns:
1319  *      returns True if sucessful, False otherwise
1320  */
1321 static Bool
1322 WritePiecesToFile(AsciiSrcObject src, String name)
1323 {
1324     Piece *piece;
1325     int fd;
1326
1327     if (src->ascii_src.data_compression) {
1328         Piece *tmp;
1329
1330         piece = src->ascii_src.first_piece;
1331         while (piece) {
1332             int bytes = src->ascii_src.piece_size - piece->used;
1333
1334             if (bytes > 0 && (tmp = piece->next) != NULL) {
1335                 bytes = XawMin(bytes, tmp->used);
1336                 memcpy(piece->text + piece->used, tmp->text, bytes);
1337                 memmove(tmp->text, tmp->text + bytes, tmp->used - bytes);
1338                 piece->used += bytes;
1339                 if ((tmp->used -= bytes) == 0) {
1340                     RemovePiece(src, tmp);
1341                     continue;
1342                 }
1343             }
1344             piece = piece->next;
1345         }
1346     }
1347
1348     if ((fd = creat(name, 0666)) == -1)
1349         return (False);
1350
1351     for (piece = src->ascii_src.first_piece; piece; piece = piece->next)
1352         if (write(fd, piece->text, piece->used) == -1) {
1353             close(fd);
1354             return (False);
1355         }
1356
1357     if (close(fd) == -1)
1358         return (False);
1359
1360     return (True);
1361 }
1362
1363 /*
1364  * Function:
1365  *      StorePiecesInString
1366  *
1367  * Parameters:
1368  *      data - ascii pointer data
1369  *
1370  * Description:
1371  *      Store the pieces in memory into a standard ascii string.
1372  */
1373 static String
1374 StorePiecesInString(AsciiSrcObject src)
1375 {
1376     String string;
1377     XawTextPosition first;
1378     Piece *piece;
1379
1380     string = XtMalloc((unsigned)(src->ascii_src.length + 1));
1381
1382     for (first = 0, piece = src->ascii_src.first_piece ; piece != NULL; 
1383          first += piece->used, piece = piece->next) 
1384       memcpy(string + first, piece->text, (unsigned)piece->used);
1385
1386     string[src->ascii_src.length] = '\0';
1387
1388     /*
1389      * This will refill all pieces to capacity
1390      */
1391     if (src->ascii_src.data_compression) {
1392         FreeAllPieces(src);
1393         LoadPieces(src, NULL, string);
1394     }
1395
1396     return (string);
1397 }
1398
1399 /*
1400  * Function:
1401  *      InitStringOrFile
1402  *
1403  * Parameters:
1404  *      src - AsciiSource
1405  *
1406  * Description:
1407  *      Initializes the string or file.
1408  */
1409 static FILE *
1410 InitStringOrFile(AsciiSrcObject src, Bool newString)
1411 {
1412     mode_t open_mode = 0;
1413     const char *fdopen_mode = NULL;
1414     int fd;
1415     FILE *file;
1416
1417     if (src->ascii_src.type == XawAsciiString) {
1418         if (src->ascii_src.string == NULL)
1419             src->ascii_src.length = 0;
1420
1421         else if (!src->ascii_src.use_string_in_place) {
1422             src->ascii_src.string = XtNewString(src->ascii_src.string);
1423             src->ascii_src.allocated_string = True;
1424             src->ascii_src.length = strlen(src->ascii_src.string);
1425         }
1426
1427         if (src->ascii_src.use_string_in_place) {
1428             if (src->ascii_src.string != NULL)
1429             src->ascii_src.length = strlen(src->ascii_src.string);
1430             /* In case the length resource is incorrectly set */
1431             if (src->ascii_src.length > src->ascii_src.ascii_length)
1432                 src->ascii_src.ascii_length = src->ascii_src.length;
1433
1434             if (src->ascii_src.ascii_length == MAGIC_VALUE)
1435                 src->ascii_src.piece_size = src->ascii_src.length;
1436             else
1437                 src->ascii_src.piece_size = src->ascii_src.ascii_length + 1;
1438         }
1439
1440         return (NULL);
1441     }
1442
1443     /*
1444      * type is XawAsciiFile
1445      */
1446     src->ascii_src.is_tempfile = False;
1447
1448     switch (src->text_src.edit_mode) {
1449         case XawtextRead:
1450             if (src->ascii_src.string == NULL)
1451                 XtErrorMsg("NoFile", "asciiSourceCreate", "XawError",
1452                            "Creating a read only disk widget and no file specified.",
1453                            NULL, NULL);
1454             open_mode = O_RDONLY;
1455             fdopen_mode = "r";
1456             break;
1457         case XawtextAppend:
1458         case XawtextEdit:
1459             if (src->ascii_src.string == NULL) {
1460                 src->ascii_src.string = "*ascii-src*";
1461                 src->ascii_src.is_tempfile = True;
1462             }
1463             else {
1464 /* O_NOFOLLOW is a FreeBSD & Linux extension */
1465 #ifdef O_NOFOLLOW
1466                 open_mode = O_RDWR | O_NOFOLLOW;
1467 #else
1468                 open_mode = O_RDWR; /* unsafe; subject to race conditions */
1469 #endif /* O_NOFOLLOW */
1470                 fdopen_mode = "r+";
1471             }
1472             break;
1473         default:
1474             XtErrorMsg("badMode", "asciiSourceCreate", "XawError",
1475                        "Bad editMode for ascii source; must be Read, "
1476                        "Append or Edit.",
1477                        NULL, NULL);
1478     }
1479
1480     /* If is_tempfile, allocate a private copy of the text
1481      * Unlikely to be changed, just to set allocated_string */
1482     if (newString || src->ascii_src.is_tempfile) {
1483         src->ascii_src.string = XtNewString(src->ascii_src.string);
1484         src->ascii_src.allocated_string = True;
1485     }
1486
1487     if (!src->ascii_src.is_tempfile) {
1488         if ((fd = open(src->ascii_src.string, open_mode, 0666)) != -1) {
1489             if ((file = fdopen(fd, fdopen_mode))) {
1490                 (void)fseek(file, 0, SEEK_END);
1491                 src->ascii_src.length = (XawTextPosition)ftell(file);
1492                 return (file);
1493             }
1494         }
1495         {
1496             String params[2];
1497             Cardinal num_params = 2;
1498
1499             params[0] = src->ascii_src.string;
1500             params[1] = strerror(errno);
1501             XtAppWarningMsg(XtWidgetToApplicationContext((Widget)src),
1502                             "openError", "asciiSourceCreate", "XawWarning",
1503                             "Cannot open file %s; %s", params, &num_params);
1504         }
1505     }
1506     src->ascii_src.length = 0;
1507     return (NULL);
1508 }
1509
1510 static void
1511 LoadPieces(AsciiSrcObject src, FILE *file, char *string)
1512 {
1513     char *ptr;
1514     Piece *piece = NULL;
1515     XawTextPosition left;
1516
1517     if (string == NULL) {
1518         if (src->ascii_src.type == XawAsciiFile) {
1519             if (src->ascii_src.length != 0) {
1520                 int len;
1521
1522                 left = 0;
1523                 fseek(file, 0, 0);
1524                 while (left < src->ascii_src.length) {
1525                     ptr = XtMalloc((unsigned)src->ascii_src.piece_size);
1526                     if ((len = fread(ptr, (Size_t)sizeof(unsigned char),
1527                                      (Size_t)src->ascii_src.piece_size, file)) < 0)
1528                         XtErrorMsg("readError", "asciiSourceCreate", "XawError",
1529                                    "fread returned error.", NULL, NULL);
1530                     piece = AllocNewPiece(src, piece);
1531                     piece->text = ptr;
1532                     piece->used = XawMin(len, src->ascii_src.piece_size);
1533                     left += piece->used;
1534                 }
1535             }
1536             else {
1537                 piece = AllocNewPiece(src, NULL);
1538                 piece->text = XtMalloc((unsigned)src->ascii_src.piece_size);
1539                 piece->used = 0;
1540             }
1541             return;
1542         }
1543         else
1544             string = src->ascii_src.string;
1545     }
1546
1547     if (src->ascii_src.use_string_in_place) {
1548         piece = AllocNewPiece(src, piece);
1549         piece->used = XawMin(src->ascii_src.length, src->ascii_src.piece_size);
1550         piece->text = src->ascii_src.string;
1551         return;
1552     }
1553
1554     ptr = string;
1555     left = src->ascii_src.length;
1556     do {
1557         piece = AllocNewPiece(src, piece);
1558
1559         piece->text = XtMalloc((unsigned)src->ascii_src.piece_size);
1560         piece->used = XawMin(left, src->ascii_src.piece_size);
1561         if (piece->used != 0)
1562             memcpy(piece->text, ptr, (unsigned)piece->used);
1563
1564         left -= piece->used;
1565         ptr += piece->used;
1566     } while (left > 0);
1567 }
1568
1569 /*
1570  * Function:
1571  *      AllocNewPiece
1572  *
1573  * Parameters:
1574  *      src - AsciiSrc Widget
1575  *      prev - piece just before this one, or NULL
1576  *
1577  * Description:
1578  *      Allocates a new piece of memory.
1579  *
1580  * Returns:
1581  *      The allocated piece
1582  */
1583 static Piece *
1584 AllocNewPiece(AsciiSrcObject src, Piece *prev)
1585 {
1586     Piece *piece = XtNew(Piece);
1587
1588     if (prev == NULL) {
1589         src->ascii_src.first_piece = piece;
1590         piece->next = NULL;
1591     }
1592     else  {
1593         if (prev->next != NULL)
1594             (prev->next)->prev = piece;
1595         piece->next = prev->next;
1596         prev->next = piece;
1597     }
1598
1599     piece->prev = prev;
1600
1601     return (piece);
1602 }
1603
1604 /*
1605  * Function:
1606  *      FreeAllPieces
1607  *
1608  * Parameters:
1609  *      src - AsciiSrc Widget
1610  *
1611  * Description:
1612  *      Frees all the pieces.
1613  */
1614 static void
1615 FreeAllPieces(AsciiSrcObject src)
1616 {
1617     Piece *next, * first = src->ascii_src.first_piece;
1618
1619 #ifdef DEBUG
1620     if (first->prev != NULL)
1621         printf("Xaw AsciiSrc Object: possible memory leak in FreeAllPieces().\n");
1622 #endif
1623
1624     for (; first != NULL ; first = next) {
1625         next = first->next;
1626         RemovePiece(src, first);
1627     }
1628 }
1629
1630 /*
1631  * Function:
1632  *      RemovePiece
1633  *
1634  * Parameters:
1635  *      piece - piece to remove
1636  *
1637  * Description:
1638  *      Removes a piece from the list.
1639  */
1640 static void
1641 RemovePiece(AsciiSrcObject src, Piece *piece)
1642 {
1643     if (piece->prev == NULL)
1644         src->ascii_src.first_piece = piece->next;
1645     else
1646         piece->prev->next = piece->next;
1647
1648     if (piece->next != NULL)
1649         piece->next->prev = piece->prev;
1650
1651     if (!src->ascii_src.use_string_in_place)
1652         XtFree(piece->text);
1653
1654     XtFree((char *)piece);
1655 }
1656
1657 /*
1658  * Function:
1659  *      FindPiece
1660  *
1661  * Parameters:
1662  *      src      - AsciiSrc Widget
1663  *      position - position that we are searching for
1664  *      first    - position of the first character in this piece (return)
1665  *
1666  * Description:
1667  *      Finds the piece containing the position indicated.
1668  *
1669  * Returns:
1670  *      the piece that contains this position
1671  */
1672 static Piece *
1673 FindPiece(AsciiSrcObject src, XawTextPosition position, XawTextPosition *first)
1674 {
1675     Piece *old_piece, *piece;
1676     XawTextPosition temp;
1677
1678     for (old_piece = NULL, piece = src->ascii_src.first_piece, temp = 0;
1679         piece; old_piece = piece, piece = piece->next)
1680         if ((temp += piece->used) > position) {
1681             *first = temp - piece->used;
1682             return (piece);
1683         }
1684
1685     *first = temp - (old_piece ? old_piece->used : 0);
1686
1687     return (old_piece); /* if we run off the end the return the last piece */
1688 }
1689     
1690 /*
1691  * Function:
1692  *      BreakPiece
1693  *
1694  * Parameters:
1695  *      src - AsciiSrc Widget
1696  *      piece - piece to break
1697  *
1698  * Description:
1699  *      Breaks a full piece into two new pieces.
1700  */
1701 #define HALF_PIECE (src->ascii_src.piece_size >> 1)
1702 static void
1703 BreakPiece(AsciiSrcObject src, Piece *piece)
1704 {
1705     Piece *cnew = AllocNewPiece(src, piece);
1706
1707     cnew->text = XtMalloc((unsigned)src->ascii_src.piece_size);
1708     memcpy(cnew->text, piece->text + HALF_PIECE,
1709            (unsigned)(src->ascii_src.piece_size - HALF_PIECE));
1710     piece->used = HALF_PIECE;
1711     cnew->used = src->ascii_src.piece_size - HALF_PIECE;
1712 }
1713
1714 /*ARGSUSED*/
1715 static void
1716 CvtStringToAsciiType(XrmValuePtr args, Cardinal *num_args,
1717                      XrmValuePtr fromVal, XrmValuePtr toVal)
1718 {
1719     static XawAsciiType type;
1720     XrmQuark q;
1721     char name[7];
1722
1723     XmuNCopyISOLatin1Lowered(name, (char *)fromVal->addr, sizeof(name));
1724     q = XrmStringToQuark(name);
1725
1726     if (q == Qstring)
1727         type = XawAsciiString;
1728     else if (q == Qfile)
1729         type = XawAsciiFile;
1730     else  {
1731         toVal->size = 0;
1732         toVal->addr = NULL;
1733         XtStringConversionWarning((char *)fromVal->addr, XtRAsciiType);
1734     }
1735
1736     toVal->size = sizeof(XawAsciiType);
1737     toVal->addr = (XPointer)&type;
1738 }
1739
1740 /*ARGSUSED*/
1741 static Boolean
1742 CvtAsciiTypeToString(Display *dpy, XrmValuePtr args, Cardinal *num_args,
1743                      XrmValuePtr fromVal, XrmValuePtr toVal,
1744                      XtPointer *data)
1745 {
1746     static String buffer;
1747     Cardinal size;
1748
1749     switch (*(XawAsciiType *)fromVal->addr) {
1750         case XawAsciiFile:
1751             buffer = XtEfile;
1752             break;
1753         case XawAsciiString:
1754             buffer = XtEstring;
1755             break;
1756         default:
1757             XawTypeToStringWarning(dpy, XtRAsciiType);
1758             toVal->addr = NULL;
1759             toVal->size = 0;
1760             return (False);
1761     }
1762
1763     size = strlen(buffer) + 1;
1764     if (toVal->addr != NULL) {
1765         if (toVal->size < size) {
1766             toVal->size = size;
1767             return (False);
1768         }
1769         strcpy((char *)toVal->addr, buffer);
1770     }
1771     else
1772         toVal->addr = (XPointer)buffer;
1773     toVal->size = sizeof(String);
1774
1775     return (True);
1776 }
1777
1778 /*ARGSUSED*/
1779 static void
1780 GetDefaultPieceSize(Widget w, int offset, XrmValue *value)
1781 {
1782     static XPointer pagesize;
1783
1784     if (pagesize == NULL) {
1785         pagesize = (XPointer)((long)_XawGetPageSize());
1786         if (pagesize < (XPointer)BUFSIZ)
1787             pagesize = (XPointer)BUFSIZ;
1788     }
1789
1790     value->addr = (XPointer)&pagesize;
1791 }
1792
1793 #if (defined(ASCII_STRING) || defined(ASCII_DISK))
1794 #  include <X11/Xaw/Cardinals.h>
1795 #endif
1796
1797 #ifdef ASCII_STRING
1798 /*
1799  * Compatability functions.
1800  */
1801 /*
1802  * Function:
1803  *      AsciiStringSourceCreate
1804  *
1805  * Parameters:
1806  *      parent   - widget that will own this source
1807  *      args     - the argument list
1808  *      num_args - ""
1809  *
1810  * Description:
1811  *      Creates a string source.
1812  *
1813  * Returns:
1814  *      A pointer to the new text source.
1815  */
1816 Widget
1817 XawStringSourceCreate(Widget parent, ArgList args, Cardinal num_args)
1818 {
1819     XawTextSource src;
1820     ArgList ascii_args;
1821     Arg temp[2];
1822
1823     XtSetArg(temp[0], XtNtype, XawAsciiString);
1824     XtSetArg(temp[1], XtNuseStringInPlace, True);
1825     ascii_args = XtMergeArgLists(temp, TWO, args, num_args);
1826
1827     src = XtCreateWidget("genericAsciiString", asciiSrcObjectClass, parent,
1828                          ascii_args, num_args + TWO);
1829     XtFree((char *)ascii_args);
1830
1831     return (src);
1832 }
1833
1834 /*
1835  * This is hacked up to try to emulate old functionality, it
1836  * may not work, as I have not old code to test it on.
1837  *
1838  * Chris D. Peterson  8/31/89.
1839  */
1840 void
1841 XawTextSetLastPos(Widget w, XawTextPosition lastPos)
1842 {
1843     AsciiSrcObject src = (AsciiSrcObject)XawTextGetSource(w);
1844
1845     src->ascii_src.piece_size = lastPos;
1846 }
1847 #endif /* ASCII_STRING */
1848
1849 #ifdef ASCII_DISK
1850 /*
1851  * Function:
1852  *      AsciiDiskSourceCreate
1853  *
1854  * Parameters:
1855  *      parent   - widget that will own this source
1856  *      args     - argument list
1857  *      num_args - ""
1858  *
1859  * Description:
1860  *      Creates a disk source.
1861  *
1862  * Returns:
1863  *      A pointer to the new text source
1864  */
1865 Widget
1866 XawDiskSourceCreate(Widget parent, ArgList args, Cardinal num_args)
1867 {
1868     XawTextSource src;
1869     ArgList ascii_args;
1870     Arg temp[1];
1871     int i;
1872
1873     XtSetArg(temp[0], XtNtype, XawAsciiFile);
1874     ascii_args = XtMergeArgLists(temp, ONE, args, num_args);
1875     num_args++;
1876
1877     for (i = 0; i < num_args; i++) 
1878         if (streq(ascii_args[i].name, XtNfile)
1879             || streq(ascii_args[i].name, XtCFile)) 
1880             ascii_args[i].name = XtNstring;
1881
1882     src = XtCreateWidget("genericAsciiDisk", asciiSrcObjectClass, parent,
1883                          ascii_args, num_args);
1884     XtFree((char *)ascii_args);
1885
1886     return (src);
1887 }
1888 #endif /* ASCII_DISK */