3 Copyright 1989, 1994, 1998 The Open Group
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
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
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.
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.
28 * AsciiSrc.c - AsciiSrc object. (For use with the text widget).
39 #include <X11/IntrinsicP.h>
40 #include <X11/StringDefs.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>
49 #include <X11/Xaw/TextSinkP.h>
50 #include <X11/Xaw/AsciiSinkP.h>
54 #include <sys/types.h>
58 #if (defined(ASCII_STRING) || defined(ASCII_DISK))
59 #include <X11/Xaw/AsciiText.h> /* for Widget Classes */
64 #define Size_t unsigned int
70 #define MAGIC_VALUE ((XawTextPosition)-1)
71 #define streq(a, b) (strcmp((a), (b)) == 0)
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,
82 static XawTextPosition ReadText(Widget, XawTextPosition, XawTextBlock*, int);
83 static int ReplaceText(Widget, XawTextPosition, XawTextPosition,
85 static XawTextPosition Scan(Widget, XawTextPosition, XawTextScanType,
86 XawTextScanDirection, int, Bool);
87 static XawTextPosition Search(Widget, XawTextPosition, XawTextScanDirection,
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*);
114 Widget XawAsciiDiskSourceCreate(Widget, ArgList, Cardinal);
117 Widget XawStringSourceCreate(Widget, ArgList, Cardinal);
118 void XawTextSetLastPos(Widget, XawTextPosition);
124 #define offset(field) XtOffsetOf(AsciiSrcRec, ascii_src.field)
125 static XtResource resources[] = {
139 sizeof(XawAsciiType),
142 (XtPointer)XawAsciiString
149 offset(data_compression),
157 sizeof(XawTextPosition),
160 (XtPointer)GetDefaultPieceSize
178 offset(use_string_in_place),
187 offset(ascii_length),
189 (XtPointer)MAGIC_VALUE
201 #endif /* ASCII_DISK */
206 #define Superclass (&textSrcClassRec)
207 AsciiSrcClassRec asciiSrcClassRec = {
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 */
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 */
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 */
239 NULL, /* query_geometry */
240 NULL, /* display_accelerator */
241 NULL, /* extension */
246 ReplaceText, /* Replace */
249 XtInheritSetSelection, /* SetSelection */
250 XtInheritConvertSelection, /* ConvertSelection */
254 NULL, /* extension */
258 WidgetClass asciiSrcObjectClass = (WidgetClass)&asciiSrcClassRec;
260 static XrmQuark Qstring, Qfile;
267 * XawAsciiSrcClassInitialize()
270 * Initializes the asciiSrcObjectClass and install the converters for
271 * AsciiType <-> String.
274 XawAsciiSrcClassInitialize(void)
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);
286 * XawAsciiSrcInitialize
289 * request - widget requested by the argument list
290 * cnew - new widget with both resource and non resource values
292 * num_args - (unused)
295 * Initializes the ascii src object.
299 XawAsciiSrcInitialize(Widget request, Widget cnew,
300 ArgList args, Cardinal *num_args)
302 AsciiSrcObject src = (AsciiSrcObject)cnew;
306 * Set correct flags (override resources) depending upon widget class
308 src->text_src.text_format = XawFmt8Bit;
311 if (XtIsSubclass(XtParent(cnew), asciiDiskWidgetClass)) {
312 src->ascii_src.type = XawAsciiFile;
313 src->ascii_src.string = src->ascii_src.filename;
318 if (XtIsSubclass(XtParent(cnew), asciiStringWidgetClass)) {
319 src->ascii_src.use_string_in_place = True;
320 src->ascii_src.type = XawAsciiString;
325 src->ascii_src.changes = False;
327 src->text_src.changed = False;
329 src->ascii_src.allocated_string = False;
331 if (src->ascii_src.use_string_in_place && src->ascii_src.string == NULL)
332 src->ascii_src.use_string_in_place = False;
334 file = InitStringOrFile(src, src->ascii_src.type == XawAsciiFile);
335 LoadPieces(src, file, NULL);
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
352 * This function reads the source.
355 * The character position following the retrieved text.
357 static XawTextPosition
358 ReadText(Widget w, XawTextPosition pos, XawTextBlock *text, int length)
360 AsciiSrcObject src = (AsciiSrcObject)w;
361 XawTextPosition count, start;
364 XawTextAnchor *anchor;
365 XawTextEntity *entity;
366 XawTextPosition offset, end = pos + length;
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)) {
376 offset = anchor->position + entity->offset;
380 (entity->flags & (XAW_TENTF_HIDE | XAW_TENTF_REPLACE))) {
381 end = XawMin(end, offset);
384 if ((entity = entity->next) == NULL &&
385 (anchor = XawTextSourceNextAnchor(w, anchor)) != NULL)
386 entity = anchor->entities;
389 else if (state && (entity->flags & XAW_TENTF_REPLACE) && pos < end) {
390 XawTextBlock *block = (XawTextBlock*)entity->data;
392 offset = anchor->position + entity->offset;
393 end = XawMin(end, offset + block->length);
394 if ((length = end - pos) < 0)
396 text->length = length;
397 text->format = XawFmt8Bit;
399 text->firstPos = end = offset + entity->length;
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 */
408 end = offset + entity->length;
414 if ((length = end - pos) < 0)
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;
425 return (pos + text->length);
433 * w - AsciiSource object
434 * startPos - ends of text that will be replaced
436 * text - new text to be inserted into buffer at startPos
439 * Replaces a block of text with new text.
442 * XawEditDone on success, XawEditError otherwise
446 ReplaceText(Widget w, XawTextPosition startPos, XawTextPosition endPos,
449 AsciiSrcObject src = (AsciiSrcObject)w;
450 Piece *start_piece, *end_piece, *temp_piece;
451 XawTextPosition start_first, end_first;
452 int length, firstPos;
455 * Editing a read only source is not allowed
457 if (src->text_src.edit_mode == XawtextRead)
458 return (XawEditError);
460 start_piece = FindPiece(src, startPos, &start_first);
461 end_piece = FindPiece(src, endPos, &end_first);
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.
469 if (start_piece->used) {
472 for (i = 0; i < src->text_src.num_text; i++) {
474 TextWidget ctx = (TextWidget)src->text_src.text[i];
476 for (line = 0; line < ctx->text.lt.lines; line++)
477 if (startPos < ctx->text.lt.info[line + 1].position)
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;
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;
493 font = sink->ascii_sink.font;
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));
500 if (c == '\t' || c == '\n')
502 else if ((c & 0177) < XawSP || c == 0177) {
503 if (sink->ascii_sink.display_nonprinting)
504 c = c > 0177 ? '\\' : c + '^';
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;
512 _XawTextNeedsUpdating(ctx, startPos - 1, startPos);
524 if (start_piece != end_piece) {
525 temp_piece = start_piece->next;
528 * If empty and not the only piece then remove it.
530 if (((start_piece->used = startPos - start_first) == 0)
531 && !(start_piece->next == NULL && start_piece->prev == NULL))
532 RemovePiece(src, start_piece);
534 while (temp_piece != end_piece) {
535 temp_piece = temp_piece->next;
536 RemovePiece(src, temp_piece->prev);
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);
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);
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)] =
561 src->ascii_src.length += -(endPos - startPos) + text->length;
563 if ( text->length != 0) {
565 * Put in the New Stuff
567 start_piece = FindPiece(src, startPos, &start_first);
569 length = text->length;
570 firstPos = text->firstPos;
576 if (src->ascii_src.use_string_in_place) {
577 if (start_piece->used == src->ascii_src.piece_size - 1) {
579 * If we are in ascii string emulation mode. Then the
580 * string is not allowed to grow
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);
589 if (start_piece->used == src->ascii_src.piece_size) {
590 BreakPiece(src, start_piece);
591 start_piece = FindPiece(src, startPos, &start_first);
594 fill = Min((int)(src->ascii_src.piece_size - start_piece->used),
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);
604 start_piece->used += fill;
609 if (src->ascii_src.use_string_in_place)
610 start_piece->text[start_piece->used] = '\0';
613 src->ascii_src.changes = True;
614 XtCallCallbacks(w, XtNcallback, NULL);
617 return (XawEditDone);
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
634 * Scans the text source for the number and type of item specified.
637 * The position of the item found
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
644 static XawTextPosition
645 Scan(Widget w, register XawTextPosition position, XawTextScanType type,
646 XawTextScanDirection dir, int count, Bool include)
648 AsciiSrcObject src = (AsciiSrcObject)w;
650 XawTextPosition first, first_eol_position = 0;
651 register char *ptr, *lim;
652 register int cnt = count;
653 register unsigned char c;
655 if (dir == XawsdLeft) {
660 else if (position >= src->ascii_src.length)
661 return (src->ascii_src.length);
663 piece = FindPiece(src, position, &first);
664 if (piece->used == 0)
667 ptr = (position - first) + piece->text;
669 if (dir == XawsdRight) {
670 lim = piece->text + piece->used;
674 case XawstWhiteSpace:
675 case XawstAlphaNumeric:
676 for (; cnt > 0; cnt--) {
677 Bool non_space = False, first_eol = True;
683 if (piece == NULL) /* End of text */
684 return (src->ascii_src.length);
686 lim = piece->text + piece->used;
692 if (type == XawstEOL) {
696 else if (type == XawstAlphaNumeric) {
704 else if (type == XawstWhiteSpace) {
712 else { /* XawstParagraph */
715 first_eol_position = position;
721 else if (!isspace(c))
729 return (position < src->ascii_src.length ?
730 position : src->ascii_src.length);
732 return (src->ascii_src.length);
737 if (type == XawstParagraph)
738 position = first_eol_position;
748 case XawstWhiteSpace:
749 case XawstAlphaNumeric:
750 for (; cnt > 0; cnt--) {
751 Bool non_space = False, first_eol = True;
757 if (piece == NULL) /* Begining of text */
759 ptr = piece->text + piece->used - 1;
766 if (type == XawstEOL) {
770 else if (type == XawstAlphaNumeric) {
778 else if (type == XawstWhiteSpace) {
786 else { /* XawstParagraph */
789 first_eol_position = position;
795 else if (!isspace(c))
802 position -= count - 1;
803 return (position > 0 ? position : 0);
810 if (type == XawstParagraph)
811 position = first_eol_position;
826 * w - AsciiSource object
827 * position - the position to start scanning
828 * dir - direction to scan
829 * text - text block to search for
832 * Searchs the text source for the text block passed.
835 * The position of the item found
837 static XawTextPosition
838 Search(Widget w, register XawTextPosition position, XawTextScanDirection dir,
841 AsciiSrcObject src = (AsciiSrcObject)w;
842 register int count = 0;
843 register char *ptr, c;
847 XawTextPosition first;
848 int cnt, case_sensitive;
850 if (dir == XawsdLeft) {
852 return (XawTextSearchError);
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;
862 if (dir == XawsdRight) {
868 || (case_sensitive && isalpha(c) && isalpha(ptr[-1])
869 && toupper(c) == toupper(ptr[-1]))) {
870 if (++count == text->length)
881 if (ptr < piece->text) {
883 cnt = piece->text - ptr;
887 return (XawTextSearchError);
889 ptr = piece->text + piece->used - cnt;
890 } while (ptr < piece->text);
894 if (ptr >= (piece->text + piece->used)) {
896 cnt = ptr - (piece->text + piece->used);
900 return (XawTextSearchError);
902 ptr = piece->text + cnt;
903 } while (ptr >= (piece->text + piece->used));
907 position -= text->length - 1;
910 str = buf + text->length - 1;
915 || (case_sensitive && isalpha(c) && isalpha(ptr[1])
916 && toupper(c) == toupper(ptr[1]))) {
917 if (++count == text->length)
928 if (ptr >= (piece->text + piece->used)) {
930 cnt = ptr - (piece->text + piece->used);
934 return (XawTextSearchError);
936 ptr = piece->text + cnt;
937 } while (ptr >= (piece->text + piece->used));
941 if (ptr < piece->text) {
943 cnt = piece->text - ptr;
947 return (XawTextSearchError);
949 ptr = piece->text + piece->used - cnt;
950 } while (ptr < piece->text);
962 * XawAsciiSrcSetValues
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
972 * Sets the values for the AsciiSource.
975 * True if redisplay is needed
978 XawAsciiSrcSetValues(Widget current, Widget request, Widget cnew,
979 ArgList args, Cardinal *num_args)
981 AsciiSrcObject src = (AsciiSrcObject)cnew;
982 AsciiSrcObject old_src = (AsciiSrcObject)current;
983 Bool total_reset = False, string_set = False;
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 "
992 src->ascii_src.use_string_in_place =
993 old_src->ascii_src.use_string_in_place;
996 for (i = 0; i < *num_args ; i++)
997 if (streq(args[i].name, XtNstring)) {
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 */
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);
1013 XawTextSetSource(XtParent(cnew), cnew, 0);
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;
1022 old_src->ascii_src.piece_size != src->ascii_src.piece_size) {
1023 String string = StorePiecesInString(old_src);
1025 FreeAllPieces(old_src);
1026 LoadPieces(src, NULL, string);
1035 * XawAsciiSrcGetValuesHook
1038 * w - AsciiSource Widget
1039 * args - argument list
1040 * num_args - number of args
1043 * This is a get values hook routine that sets the
1044 * values specific to the ascii source.
1047 XawAsciiSrcGetValuesHook(Widget w, ArgList args, Cardinal *num_args)
1049 AsciiSrcObject src = (AsciiSrcObject)w;
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;
1066 * XawAsciiSrcDestroy
1069 * src - Ascii source object to free
1072 * Destroys an ascii source (frees all data)
1075 XawAsciiSrcDestroy(Widget w)
1077 RemoveOldStringOrFile((AsciiSrcObject) w, True);
1085 * XawAsciiSourceFreeString
1088 * w - AsciiSrc widget
1091 * Frees the string returned by a get values call
1092 * on the string when the source is of type string.
1095 XawAsciiSourceFreeString(Widget w)
1097 AsciiSrcObject src = (AsciiSrcObject)w;
1099 /* If the src is really a multi, call the multi routine */
1100 if (XtIsSubclass(w, multiSrcObjectClass)) {
1101 _XawMultiSourceFreeString(w);
1104 else if (!XtIsSubclass(w, asciiSrcObjectClass)) {
1105 XtErrorMsg("bad argument", "asciiSource", "XawError",
1106 "XawAsciiSourceFreeString's parameter must be "
1107 "an asciiSrc or multiSrc.",
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;
1123 * w - asciiSrc Widget
1126 * Saves all the pieces into a file or string as required.
1129 * True if the save was successful
1132 XawAsciiSave(Widget w)
1134 AsciiSrcObject src = (AsciiSrcObject)w;
1136 /* If the src is really a multi, call the multi save */
1137 if (XtIsSubclass(w, multiSrcObjectClass ))
1138 return (_XawMultiSave(w));
1140 else if (!XtIsSubclass(w, asciiSrcObjectClass))
1141 XtErrorMsg("bad argument", "asciiSource", "XawError",
1142 "XawAsciiSave's parameter must be an asciiSrc or multiSrc.",
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.
1149 if (src->ascii_src.use_string_in_place)
1152 if (src->ascii_src.type == XawAsciiFile) {
1154 if (!src->ascii_src.changes)
1156 if (!src->text_src.changed) /* No changes to save */
1160 if (WritePiecesToFile(src, src->ascii_src.string) == False)
1164 if (src->ascii_src.allocated_string == True)
1165 XtFree(src->ascii_src.string);
1167 src->ascii_src.allocated_string = True;
1169 src->ascii_src.string = StorePiecesInString(src);
1172 src->ascii_src.changes = False;
1174 src->text_src.changed = False;
1182 * XawAsciiSaveAsFile
1185 * w - AsciiSrc widget
1186 * name - name of the file to save this file into
1189 * Save the current buffer as a file.
1192 * True if the save was sucessful
1195 XawAsciiSaveAsFile(Widget w, _Xconst char *name)
1197 AsciiSrcObject src = (AsciiSrcObject)w;
1200 /* If the src is really a multi, call the multi save */
1202 if (XtIsSubclass( w, multiSrcObjectClass))
1203 return (_XawMultiSaveAsFile(w, name));
1205 else if (!XtIsSubclass(w, asciiSrcObjectClass))
1206 XtErrorMsg("bad argument", "asciiSource", "XawError",
1207 "XawAsciiSaveAsFile's 1st parameter must be an "
1208 "asciiSrc or multiSrc.",
1211 if (src->ascii_src.type == XawAsciiFile)
1212 ret = WritePiecesToFile(src, (String)name);
1214 String string = StorePiecesInString(src);
1216 ret = WriteToFile(string, (String)name, src->ascii_src.length);
1225 * XawAsciiSourceChanged
1228 * w - ascii source widget
1231 * Returns true if the source has changed since last saved.
1234 * A Boolean (see description).
1237 XawAsciiSourceChanged(Widget w)
1240 if (XtIsSubclass(w, multiSrcObjectClass))
1241 return (((MultiSrcObject)w)->multi_src.changes);
1243 if (XtIsSubclass(w, asciiSrcObjectClass))
1244 return (((AsciiSrcObject)w)->ascii_src.changes);
1246 if (XtIsSubclass(w, textSrcObjectClass))
1247 return (((TextSrcObject)w)->textSrc.changed);
1249 XtErrorMsg("bad argument", "asciiSource", "XawError",
1250 "XawAsciiSourceChanged parameter must be an "
1251 "asciiSrc or multiSrc.",
1261 RemoveOldStringOrFile(AsciiSrcObject src, Bool checkString)
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;
1277 * string - string to write
1278 * name - the name of the file
1281 * Write the string specified to the begining of the file specified.
1284 * returns True if sucessful, False otherwise
1287 WriteToFile(String string, String name, unsigned length)
1291 if ((fd = creat(name, 0666)) == -1)
1294 if (write(fd, string, length) == -1) {
1299 if (close(fd) == -1)
1310 * src - ascii source object
1311 * name - name of the file
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.
1319 * returns True if sucessful, False otherwise
1322 WritePiecesToFile(AsciiSrcObject src, String name)
1327 if (src->ascii_src.data_compression) {
1330 piece = src->ascii_src.first_piece;
1332 int bytes = src->ascii_src.piece_size - piece->used;
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);
1344 piece = piece->next;
1348 if ((fd = creat(name, 0666)) == -1)
1351 for (piece = src->ascii_src.first_piece; piece; piece = piece->next)
1352 if (write(fd, piece->text, piece->used) == -1) {
1357 if (close(fd) == -1)
1365 * StorePiecesInString
1368 * data - ascii pointer data
1371 * Store the pieces in memory into a standard ascii string.
1374 StorePiecesInString(AsciiSrcObject src)
1377 XawTextPosition first;
1380 string = XtMalloc((unsigned)(src->ascii_src.length + 1));
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);
1386 string[src->ascii_src.length] = '\0';
1389 * This will refill all pieces to capacity
1391 if (src->ascii_src.data_compression) {
1393 LoadPieces(src, NULL, string);
1407 * Initializes the string or file.
1410 InitStringOrFile(AsciiSrcObject src, Bool newString)
1412 mode_t open_mode = 0;
1413 const char *fdopen_mode = NULL;
1417 if (src->ascii_src.type == XawAsciiString) {
1418 if (src->ascii_src.string == NULL)
1419 src->ascii_src.length = 0;
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);
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;
1434 if (src->ascii_src.ascii_length == MAGIC_VALUE)
1435 src->ascii_src.piece_size = src->ascii_src.length;
1437 src->ascii_src.piece_size = src->ascii_src.ascii_length + 1;
1444 * type is XawAsciiFile
1446 src->ascii_src.is_tempfile = False;
1448 switch (src->text_src.edit_mode) {
1450 if (src->ascii_src.string == NULL)
1451 XtErrorMsg("NoFile", "asciiSourceCreate", "XawError",
1452 "Creating a read only disk widget and no file specified.",
1454 open_mode = O_RDONLY;
1459 if (src->ascii_src.string == NULL) {
1460 src->ascii_src.string = "*ascii-src*";
1461 src->ascii_src.is_tempfile = True;
1464 /* O_NOFOLLOW is a FreeBSD & Linux extension */
1466 open_mode = O_RDWR | O_NOFOLLOW;
1468 open_mode = O_RDWR; /* unsafe; subject to race conditions */
1469 #endif /* O_NOFOLLOW */
1474 XtErrorMsg("badMode", "asciiSourceCreate", "XawError",
1475 "Bad editMode for ascii source; must be Read, "
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;
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);
1497 Cardinal num_params = 2;
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);
1506 src->ascii_src.length = 0;
1511 LoadPieces(AsciiSrcObject src, FILE *file, char *string)
1514 Piece *piece = NULL;
1515 XawTextPosition left;
1517 if (string == NULL) {
1518 if (src->ascii_src.type == XawAsciiFile) {
1519 if (src->ascii_src.length != 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);
1532 piece->used = XawMin(len, src->ascii_src.piece_size);
1533 left += piece->used;
1537 piece = AllocNewPiece(src, NULL);
1538 piece->text = XtMalloc((unsigned)src->ascii_src.piece_size);
1544 string = src->ascii_src.string;
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;
1555 left = src->ascii_src.length;
1557 piece = AllocNewPiece(src, piece);
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);
1564 left -= piece->used;
1574 * src - AsciiSrc Widget
1575 * prev - piece just before this one, or NULL
1578 * Allocates a new piece of memory.
1581 * The allocated piece
1584 AllocNewPiece(AsciiSrcObject src, Piece *prev)
1586 Piece *piece = XtNew(Piece);
1589 src->ascii_src.first_piece = piece;
1593 if (prev->next != NULL)
1594 (prev->next)->prev = piece;
1595 piece->next = prev->next;
1609 * src - AsciiSrc Widget
1612 * Frees all the pieces.
1615 FreeAllPieces(AsciiSrcObject src)
1617 Piece *next, * first = src->ascii_src.first_piece;
1620 if (first->prev != NULL)
1621 printf("Xaw AsciiSrc Object: possible memory leak in FreeAllPieces().\n");
1624 for (; first != NULL ; first = next) {
1626 RemovePiece(src, first);
1635 * piece - piece to remove
1638 * Removes a piece from the list.
1641 RemovePiece(AsciiSrcObject src, Piece *piece)
1643 if (piece->prev == NULL)
1644 src->ascii_src.first_piece = piece->next;
1646 piece->prev->next = piece->next;
1648 if (piece->next != NULL)
1649 piece->next->prev = piece->prev;
1651 if (!src->ascii_src.use_string_in_place)
1652 XtFree(piece->text);
1654 XtFree((char *)piece);
1662 * src - AsciiSrc Widget
1663 * position - position that we are searching for
1664 * first - position of the first character in this piece (return)
1667 * Finds the piece containing the position indicated.
1670 * the piece that contains this position
1673 FindPiece(AsciiSrcObject src, XawTextPosition position, XawTextPosition *first)
1675 Piece *old_piece, *piece;
1676 XawTextPosition temp;
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;
1685 *first = temp - (old_piece ? old_piece->used : 0);
1687 return (old_piece); /* if we run off the end the return the last piece */
1695 * src - AsciiSrc Widget
1696 * piece - piece to break
1699 * Breaks a full piece into two new pieces.
1701 #define HALF_PIECE (src->ascii_src.piece_size >> 1)
1703 BreakPiece(AsciiSrcObject src, Piece *piece)
1705 Piece *cnew = AllocNewPiece(src, piece);
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;
1716 CvtStringToAsciiType(XrmValuePtr args, Cardinal *num_args,
1717 XrmValuePtr fromVal, XrmValuePtr toVal)
1719 static XawAsciiType type;
1723 XmuNCopyISOLatin1Lowered(name, (char *)fromVal->addr, sizeof(name));
1724 q = XrmStringToQuark(name);
1727 type = XawAsciiString;
1728 else if (q == Qfile)
1729 type = XawAsciiFile;
1733 XtStringConversionWarning((char *)fromVal->addr, XtRAsciiType);
1736 toVal->size = sizeof(XawAsciiType);
1737 toVal->addr = (XPointer)&type;
1742 CvtAsciiTypeToString(Display *dpy, XrmValuePtr args, Cardinal *num_args,
1743 XrmValuePtr fromVal, XrmValuePtr toVal,
1746 static String buffer;
1749 switch (*(XawAsciiType *)fromVal->addr) {
1753 case XawAsciiString:
1757 XawTypeToStringWarning(dpy, XtRAsciiType);
1763 size = strlen(buffer) + 1;
1764 if (toVal->addr != NULL) {
1765 if (toVal->size < size) {
1769 strcpy((char *)toVal->addr, buffer);
1772 toVal->addr = (XPointer)buffer;
1773 toVal->size = sizeof(String);
1780 GetDefaultPieceSize(Widget w, int offset, XrmValue *value)
1782 static XPointer pagesize;
1784 if (pagesize == NULL) {
1785 pagesize = (XPointer)((long)_XawGetPageSize());
1786 if (pagesize < (XPointer)BUFSIZ)
1787 pagesize = (XPointer)BUFSIZ;
1790 value->addr = (XPointer)&pagesize;
1793 #if (defined(ASCII_STRING) || defined(ASCII_DISK))
1794 # include <X11/Xaw/Cardinals.h>
1799 * Compatability functions.
1803 * AsciiStringSourceCreate
1806 * parent - widget that will own this source
1807 * args - the argument list
1811 * Creates a string source.
1814 * A pointer to the new text source.
1817 XawStringSourceCreate(Widget parent, ArgList args, Cardinal num_args)
1823 XtSetArg(temp[0], XtNtype, XawAsciiString);
1824 XtSetArg(temp[1], XtNuseStringInPlace, True);
1825 ascii_args = XtMergeArgLists(temp, TWO, args, num_args);
1827 src = XtCreateWidget("genericAsciiString", asciiSrcObjectClass, parent,
1828 ascii_args, num_args + TWO);
1829 XtFree((char *)ascii_args);
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.
1838 * Chris D. Peterson 8/31/89.
1841 XawTextSetLastPos(Widget w, XawTextPosition lastPos)
1843 AsciiSrcObject src = (AsciiSrcObject)XawTextGetSource(w);
1845 src->ascii_src.piece_size = lastPos;
1847 #endif /* ASCII_STRING */
1852 * AsciiDiskSourceCreate
1855 * parent - widget that will own this source
1856 * args - argument list
1860 * Creates a disk source.
1863 * A pointer to the new text source
1866 XawDiskSourceCreate(Widget parent, ArgList args, Cardinal num_args)
1873 XtSetArg(temp[0], XtNtype, XawAsciiFile);
1874 ascii_args = XtMergeArgLists(temp, ONE, args, num_args);
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;
1882 src = XtCreateWidget("genericAsciiDisk", asciiSrcObjectClass, parent,
1883 ascii_args, num_args);
1884 XtFree((char *)ascii_args);
1888 #endif /* ASCII_DISK */