gtk+3: fix dependencies for new gnome/accessibility/at-spi2-core
[oi-userland.git] / components / x11 / libXaw5 / src / MultiSrc.c
blob14267b1d9b3ddf901e0810d6255d10642f9b6358
1 /* $XConsortium: MultiSrc.c,v 1.6 94/04/17 20:12:25 kaleb Exp $ */
3 /*
4 * Copyright 1991 by OMRON Corporation
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name OMRON not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. OMRON makes no representations
13 * about the suitability of this software for any purpose. It is provided
14 * "as is" without express or implied warranty.
16 * OMRON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL OMRON BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
24 * Authors: Chris Peterson MIT X Consortium
25 * Li Yuhong OMRON Corporation
26 * Frank Sheeran OMRON Corporation
28 * Much code taken from X11R3 String and Disk Sources.
33 Copyright (c) 1991, 1994 X Consortium
35 Permission is hereby granted, free of charge, to any person obtaining a copy
36 of this software and associated documentation files (the "Software"), to deal
37 in the Software without restriction, including without limitation the rights
38 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
39 copies of the Software, and to permit persons to whom the Software is
40 furnished to do so, subject to the following conditions:
42 The above copyright notice and this permission notice shall be included in
43 all copies or substantial portions of the Software.
45 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
46 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
47 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
48 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
49 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
50 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52 Except as contained in this notice, the name of the X Consortium shall not be
53 used in advertising or otherwise to promote the sale, use or other dealings
54 in this Software without prior written authorization from the X Consortium.
59 * MultiSrc.c - MultiSrc object. (For use with the text widget).
63 #include <X11/IntrinsicP.h>
64 #include <X11/StringDefs.h>
65 #include <X11/Xfuncs.h>
66 #include <X11/Xaw/XawInit.h>
67 #include "MultiSrcP.h"
68 #include <X11/Xaw/XawImP.h>
69 #include <X11/Xmu/Misc.h>
70 #include <X11/Xmu/CharSet.h>
71 #include "XawI18n.h"
72 #include <X11/Xos.h>
73 #include <stdio.h>
74 #include <ctype.h>
75 #include <errno.h>
77 /****************************************************************
79 * Full class record constant
81 ****************************************************************/
83 /* Private Data */
85 static int magic_value = MAGIC_VALUE;
87 #define offset(field) XtOffsetOf(MultiSrcRec, multi_src.field)
89 static XtResource resources[] = {
90 {XtNstring, XtCString, XtRString, sizeof (XtPointer),
91 offset(string), XtRPointer, NULL},
92 {XtNtype, XtCType, XtRMultiType, sizeof (XawAsciiType),
93 offset(type), XtRImmediate, (XtPointer)XawAsciiString},
94 /* not used. */
95 {XtNdataCompression, XtCDataCompression, XtRBoolean, sizeof (Boolean),
96 offset(data_compression), XtRImmediate, (XtPointer) FALSE},
97 {XtNpieceSize, XtCPieceSize, XtRInt, sizeof (XawTextPosition),
98 offset(piece_size), XtRImmediate, (XtPointer) BUFSIZ},
99 {XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer),
100 offset(callback), XtRCallback, (XtPointer)NULL},
101 {XtNuseStringInPlace, XtCUseStringInPlace, XtRBoolean, sizeof (Boolean),
102 offset(use_string_in_place), XtRImmediate, (XtPointer) FALSE},
103 {XtNlength, XtCLength, XtRInt, sizeof (int),
104 offset(multi_length), XtRInt, (XtPointer) &magic_value},
107 #undef offset
109 static XawTextPosition Scan(), Search(), ReadText();
110 static int ReplaceText();
111 static MultiPiece * FindPiece(), * AllocNewPiece();
112 static FILE * InitStringOrFile();
113 static void FreeAllPieces(), RemovePiece(), BreakPiece(), LoadPieces();
114 static void RemoveOldStringOrFile(), CvtStringToMultiType();
115 static void ClassInitialize(), Initialize(), Destroy(), GetValuesHook();
116 static String StorePiecesInString();
117 static Boolean SetValues(), WriteToFile();
119 #define MyWStrncpy( t,s,wcnt ) (void) memmove( (t), (s), (wcnt)*sizeof(wchar_t))
121 #ifndef MyWStrncpy
122 static void (MyWStrncpy)();
123 #endif
125 extern char *tmpnam();
126 #ifdef X_NOT_STDC_ENV
127 extern int errno;
128 #endif
130 #ifdef X_NOT_POSIX
131 #define Off_t long
132 #define Size_t unsigned int
133 #else
134 #define Off_t off_t
135 #define Size_t size_t
136 #endif
138 extern wchar_t* _XawTextMBToWC();
139 extern char *_XawTextWCToMB();
141 #define superclass (&textSrcClassRec)
142 MultiSrcClassRec multiSrcClassRec = {
143 { /* object_class fields */
144 /* superclass */ (WidgetClass) superclass,
145 /* class_name */ "MultiSrc",
146 /* widget_size */ sizeof(MultiSrcRec),
147 /* class_initialize */ ClassInitialize,
148 /* class_part_initialize */ NULL,
149 /* class_inited */ FALSE,
150 /* initialize */ Initialize,
151 /* initialize_hook */ NULL,
152 /* pad */ NULL,
153 /* pad */ NULL,
154 /* pad */ 0,
155 /* resources */ resources,
156 /* num_resources */ XtNumber(resources),
157 /* xrm_class */ NULLQUARK,
158 /* pad */ FALSE,
159 /* pad */ FALSE,
160 /* pad */ FALSE,
161 /* pad */ FALSE,
162 /* destroy */ Destroy,
163 /* pad */ NULL,
164 /* pad */ NULL,
165 /* set_values */ SetValues,
166 /* set_values_hook */ NULL,
167 /* pad */ NULL,
168 /* get_values_hook */ GetValuesHook,
169 /* pad */ NULL,
170 /* version */ XtVersion,
171 /* callback_private */ NULL,
172 /* pad */ NULL,
173 /* pad */ NULL,
174 /* pad */ NULL,
175 /* extension */ NULL
177 { /* textSrc_class fields */
178 /* Read */ ReadText,
179 /* Replace */ ReplaceText,
180 /* Scan */ Scan,
181 /* Search */ Search,
182 /* SetSelection */ XtInheritSetSelection,
183 /* ConvertSelection */ XtInheritConvertSelection
185 { /* multiSrc_class fields */
186 /* Keep the compiler happy */ '\0'
190 WidgetClass multiSrcObjectClass = (WidgetClass)&multiSrcClassRec;
192 /************************************************************
194 * Semi-Public Interfaces.
196 ************************************************************/
198 /* Function Name: ClassInitialize
199 * Description: Class Initialize routine, called only once.
200 * Arguments: none.
201 * Returns: none.
204 static void
205 ClassInitialize()
207 XawInitializeWidgetSet();
208 XtAddConverter( XtRString, XtRMultiType, CvtStringToMultiType,
209 NULL, (Cardinal) 0);
212 /* Function Name: Initialize
213 * Description: Initializes the simple menu widget
214 * Arguments: request - the widget requested by the argument list.
215 * new - the new widget with both resource and non
216 * resource values.
217 * Returns: none.
220 /* ARGSUSED */
221 static void
222 Initialize(request, new, args, num_args)
223 Widget request, new;
224 ArgList args;
225 Cardinal* num_args;
227 MultiSrcObject src = (MultiSrcObject) new;
228 FILE * file;
231 * Set correct flags (override resources) depending upon widget class.
234 src->multi_src.changes = FALSE;
235 src->multi_src.allocated_string = FALSE;
237 file = InitStringOrFile(src, src->multi_src.type == XawAsciiFile);
238 LoadPieces(src, file, NULL);
240 if (file != NULL) fclose(file);
241 src->text_src.text_format = XawFmtWide;
245 /* Function Name: ReadText
246 * Description: This function reads the source.
247 * Arguments: w - the MultiSource widget.
248 * pos - position of the text to retreive.
249 * RETURNED text - text block that will contain returned text.
250 * length - maximum number of characters to read.
251 * Returns: The number of characters read into the buffer.
254 static XawTextPosition
255 ReadText(w, pos, text, length)
256 Widget w;
257 XawTextPosition pos;
258 XawTextBlock* text;
259 int length;
261 MultiSrcObject src = (MultiSrcObject) w;
262 XawTextPosition count, start;
263 MultiPiece * piece = FindPiece(src, pos, &start);
265 text->format = XawFmtWide;
266 text->firstPos = pos;
267 text->ptr = (char *)(piece->text + (pos - start));
268 count = piece->used - (pos - start);
269 text->length = (length > count) ? count : length;
270 return(pos + text->length);
273 /* Function Name: ReplaceText.
274 * Description: Replaces a block of text with new text.
275 * Arguments: w - the MultiSource widget.
276 * startPos, endPos - ends of text that will be removed.
277 * text - new text to be inserted into buffer at startPos.
278 * Returns: XawEditError or XawEditDone.
281 /*ARGSUSED*/
282 static int
283 ReplaceText( w, startPos, endPos, u_text_p)
284 Widget w;
285 XawTextPosition startPos, endPos;
286 XawTextBlock* u_text_p;
288 MultiSrcObject src = (MultiSrcObject) w;
289 MultiPiece *start_piece, *end_piece, *temp_piece;
290 XawTextPosition start_first, end_first;
291 int length, firstPos;
292 wchar_t *wptr;
293 Boolean local_artificial_block = False;
294 XawTextBlock text;
296 /* STEP 1: The user handed me a text block called `u_text' that may be
297 * in either FMTWIDE or FMT8BIT (ie MB.) Later code needs the block
298 * `text' to hold FMTWIDE. So, this copies `u_text' to `text', and if
299 * `u_text' was MB, I knock it up to WIDE. */
301 if ( u_text_p->length == 0 ) /* if so, the block contents never ref'd. */
302 text.length = 0;
304 else if ( u_text_p->format == XawFmtWide) {
305 local_artificial_block = False; /* ie, don't have to free it ourselves*/
306 text.firstPos = u_text_p->firstPos;
307 text.length = u_text_p->length;
308 text.ptr = u_text_p->ptr;
309 /* text.format is unneeded */
311 } else {
312 /* WARNING! u_text->firstPos and length are in units of CHAR, not CHARACTERS! */
314 local_artificial_block = True; /* ie, have to free it ourselves */
315 text.firstPos = 0;
316 text.length = u_text_p->length; /* _XawTextMBToWC converts this to wchar len. */
318 text.ptr = (char*)_XawTextMBToWC( XtDisplay(XtParent(w)),
319 &(u_text_p->ptr[u_text_p->firstPos]), &(text.length) );
321 /* I assert the following assignment is not needed - since Step 4
322 depends on length, it has no need of a terminating NULL. I think
323 the ASCII-version has the same needless NULL. */
324 /*((wchar_t*)text.ptr)[ text.length ] = NULL;*/
328 /* STEP 2: some initialization... */
330 if (src->text_src.edit_mode == XawtextRead)
331 return(XawEditError);
333 start_piece = FindPiece(src, startPos, &start_first);
334 end_piece = FindPiece(src, endPos, &end_first);
337 /* STEP 3: remove the empty pieces... */
339 if (start_piece != end_piece) {
340 temp_piece = start_piece->next;
342 /* If empty and not the only piece then remove it. */
344 if ( ((start_piece->used = startPos - start_first) == 0) &&
345 !((start_piece->next == NULL) && (start_piece->prev == NULL)) )
346 RemovePiece(src, start_piece);
348 while (temp_piece != end_piece) {
349 temp_piece = temp_piece->next;
350 RemovePiece(src, temp_piece->prev);
352 end_piece->used -= endPos - end_first;
353 if (end_piece->used != 0)
354 MyWStrncpy(end_piece->text, (end_piece->text + endPos - end_first),
355 (int) end_piece->used);
357 else { /* We are fully in one piece. */
358 if ( (start_piece->used -= endPos - startPos) == 0) {
359 if ( !((start_piece->next == NULL) && (start_piece->prev == NULL)) )
360 RemovePiece(src, start_piece);
362 else {
363 MyWStrncpy(start_piece->text + (startPos - start_first),
364 start_piece->text + (endPos - start_first),
365 (int) (start_piece->used - (startPos - start_first)) );
366 if ( src->multi_src.use_string_in_place &&
367 ((src->multi_src.length - (endPos - startPos)) <
368 (src->multi_src.piece_size - 1)) )
369 start_piece->text[src->multi_src.length - (endPos - startPos)] = (wchar_t)0;
373 src->multi_src.length += text.length -(endPos - startPos);
374 /*((TextWidget)src->object.parent)->text.lastPos = src->multi_src.length;*/
378 /* STEP 4: insert the new stuff */
380 if ( text.length != 0) {
382 start_piece = FindPiece(src, startPos, &start_first);
384 length = text.length;
385 firstPos = text.firstPos;
387 while (length > 0) {
388 wchar_t* ptr;
389 int fill;
391 if (src->multi_src.use_string_in_place) {
392 if (start_piece->used == (src->multi_src.piece_size - 1)) {
394 * The string is used in place, then the string
395 * is not allowed to grow.
397 start_piece->used = src->multi_src.length =
398 src->multi_src.piece_size - 1;
399 /*((TextWidget)src->object.parent)->text.lastPos = src->multi_src.length;*/
402 start_piece->text[src->multi_src.length] = (wchar_t)0;
403 return(XawEditError);
408 if (start_piece->used == src->multi_src.piece_size) {
409 BreakPiece(src, start_piece);
410 start_piece = FindPiece(src, startPos, &start_first);
413 fill = Min((int)(src->multi_src.piece_size - start_piece->used), length);
415 ptr = start_piece->text + (startPos - start_first);
416 MyWStrncpy(ptr + fill, ptr,
417 (int) start_piece->used - (startPos - start_first));
418 wptr =(wchar_t *)text.ptr;
419 (void)wcsncpy(ptr, wptr + firstPos, fill);
421 startPos += fill;
422 firstPos += fill;
423 start_piece->used += fill;
424 length -= fill;
428 if ( local_artificial_block == True )
430 /* In other words, text is not the u_text that the user handed me but
431 one I made myself. I only care, because I need to free the string. */
433 XFree( text.ptr );
435 if (src->multi_src.use_string_in_place)
436 start_piece->text[start_piece->used] = (wchar_t)0;
438 src->multi_src.changes = TRUE;
440 XtCallCallbacks(w, XtNcallback, NULL);
442 return(XawEditDone);
445 /* Function Name: Scan
446 * Description: Scans the text source for the number and type
447 * of item specified.
448 * Arguments: w - the MultiSource widget.
449 * position - the position to start scanning.
450 * type - type of thing to scan for.
451 * dir - direction to scan.
452 * count - which occurance if this thing to search for.
453 * include - whether or not to include the character found in
454 * the position that is returned.
455 * Returns: the position of the item found.
457 * Note: While there are only 'n' characters in the file there are n+1
458 * possible cursor positions (one before the first character and
459 * one after the last character.
462 static
463 XawTextPosition
464 Scan( w, position, type, dir, count, include )
465 Widget w;
466 XawTextPosition position;
467 XawTextScanType type;
468 XawTextScanDirection dir;
469 int count;
470 Boolean include;
472 MultiSrcObject src = (MultiSrcObject) w;
473 int inc;
474 MultiPiece * piece;
475 XawTextPosition first, first_eol_position;
476 wchar_t * ptr;
478 if (type == XawstAll) { /* Optimize this common case. */
479 if (dir == XawsdRight)
480 return(src->multi_src.length);
481 return(0); /* else. */
485 /* STEP 1: basic sanity checks */
487 if (position > src->multi_src.length)
488 position = src->multi_src.length;
491 if ( dir == XawsdRight ) {
492 if (position == src->multi_src.length)
493 return(src->multi_src.length);
494 inc = 1;
496 else {
497 if (position == 0)
498 return(0);
499 inc = -1;
500 position--;
503 piece = FindPiece(src, position, &first);
505 if ( piece->used == 0 ) return(0); /* i.e., buffer is empty. */
507 ptr = (position - first) + piece->text;
509 switch (type) {
510 case XawstEOL:
511 case XawstParagraph:
512 case XawstWhiteSpace:
513 for ( ; count > 0 ; count-- ) {
514 Boolean non_space = FALSE, first_eol = TRUE;
515 /* CONSTCOND */
516 while (TRUE) {
517 wchar_t c = *ptr;
519 ptr += inc;
520 position += inc;
522 if (type == XawstWhiteSpace) {
523 if (iswspace(c)) {
524 if (non_space)
525 break;
527 else
528 non_space = TRUE;
530 else if (type == XawstEOL) {
531 if (c == _Xaw_atowc(XawLF)) break;
533 else { /* XawstParagraph */
534 if (first_eol) {
535 if (c == _Xaw_atowc(XawLF)) {
536 first_eol_position = position;
537 first_eol = FALSE;
540 else
541 if ( c == _Xaw_atowc(XawLF))
542 break;
543 else if ( !iswspace(c) )
544 first_eol = TRUE;
548 if ( ptr < piece->text ) {
549 piece = piece->prev;
550 if (piece == NULL) /* Begining of text. */
551 return(0);
552 ptr = piece->text + piece->used - 1;
554 else if ( ptr >= (piece->text + piece->used) ) {
555 piece = piece->next;
556 if (piece == NULL) /* End of text. */
557 return(src->multi_src.length);
558 ptr = piece->text;
562 if (!include) {
563 if ( type == XawstParagraph)
564 position = first_eol_position;
565 position -= inc;
567 break;
568 case XawstPositions:
569 position += count * inc;
570 break;
571 /* case XawstAll: ---- handled in special code above */
574 if ( dir == XawsdLeft )
575 position++;
577 if (position >= src->multi_src.length)
578 return(src->multi_src.length);
579 if (position < 0)
580 return(0);
582 return(position);
585 /* Function Name: Search
586 * Description: Searchs the text source for the text block passed
587 * Arguments: w - the MultiSource Widget.
588 * position - the position to start scanning.
589 * dir - direction to scan.
590 * text - the text block to search for.
591 * Returns: the position of the item found.
594 static XawTextPosition
595 Search(w, position, dir, text )
596 Widget w;
597 XawTextPosition position;
598 XawTextScanDirection dir;
599 XawTextBlock* text;
601 MultiSrcObject src = (MultiSrcObject) w;
602 int inc, count = 0;
603 wchar_t * ptr;
604 wchar_t* wtarget;
605 int wtarget_len;
606 Display * d = XtDisplay(XtParent(w));
607 MultiPiece * piece;
608 wchar_t* buf;
609 XawTextPosition first;
612 /* STEP 1: First, a brief sanity check. */
614 if ( dir == XawsdRight )
615 inc = 1;
616 else {
617 inc = -1;
618 if (position == 0)
619 return(XawTextSearchError); /* scanning left from 0??? */
620 position--;
624 /* STEP 2: Ensure I have a local wide string.. */
626 /* Since this widget stores 32bit chars, I check here to see if
627 I'm being passed a string claiming to be 8bit chars (ie, MB text.)
628 If that is the case, naturally I convert to 32bit format. */
630 /*if the block was FMT8BIT, length will convert to REAL wchar count below */
631 wtarget_len = text->length;
633 if ( text->format == XawFmtWide )
634 wtarget = &( ((wchar_t*)text->ptr) [text->firstPos] );
635 else
637 /* The following converts wtarget_len from byte len to wchar count */
638 wtarget = _XawTextMBToWC( d, &text->ptr[ text->firstPos ], &wtarget_len );
641 /* OK, I can now assert that wtarget holds wide characters, wtarget_len
642 holds an accurate count of those characters, and that firstPos has been
643 effectively factored out of the following computations. */
646 /* STEP 3: SEARCH! */
648 buf = (wchar_t *)XtMalloc((unsigned)sizeof(wchar_t) * wtarget_len );
649 (void)wcsncpy(buf, wtarget, wtarget_len );
650 piece = FindPiece(src, position, &first);
651 ptr = (position - first) + piece->text;
653 /* CONSTCOND */
654 while (TRUE) {
655 if (*ptr == ((dir == XawsdRight) ? *(buf + count)
656 : *(buf + wtarget_len - count - 1)) ) {
657 if (count == (text->length - 1))
658 break;
659 else
660 count++;
662 else {
663 if (count != 0) {
664 position -=inc * count;
665 ptr -= inc * count;
667 count = 0;
670 ptr += inc;
671 position += inc;
673 while ( ptr < piece->text ) {
674 piece = piece->prev;
675 if (piece == NULL) { /* Begining of text. */
676 XtFree((char *)buf);
677 return(XawTextSearchError);
679 ptr = piece->text + piece->used - 1;
682 while ( ptr >= (piece->text + piece->used) ) {
683 piece = piece->next;
684 if (piece == NULL) { /* End of text. */
685 XtFree((char *)buf);
686 return(XawTextSearchError);
688 ptr = piece->text;
692 XtFree( (char *) buf );
693 if (dir == XawsdLeft)
694 return( position );
695 return( position - ( wtarget_len - 1 ) );
698 /* Function Name: SetValues
699 * Description: Sets the values for the MultiSource.
700 * Arguments: current - current state of the widget.
701 * request - what was requested.
702 * new - what the widget will become.
703 * Returns: True if redisplay is needed.
706 /* ARGSUSED */
707 static Boolean
708 SetValues(current, request, new, args, num_args)
709 Widget current, request, new;
710 ArgList args;
711 Cardinal* num_args;
713 MultiSrcObject src = (MultiSrcObject) new;
714 MultiSrcObject old_src = (MultiSrcObject) current;
715 XtAppContext app_con = XtWidgetToApplicationContext(new);
716 Boolean total_reset = FALSE, string_set = FALSE;
717 FILE * file;
718 int i;
720 if ( old_src->multi_src.use_string_in_place !=
721 src->multi_src.use_string_in_place ) {
722 XtAppWarning( app_con,
723 "MultiSrc: The XtNuseStringInPlace resources may not be changed.");
724 src->multi_src.use_string_in_place =
725 old_src->multi_src.use_string_in_place;
728 for (i = 0; i < *num_args ; i++ )
729 if (streq(args[i].name, XtNstring)) {
730 string_set = TRUE;
731 break;
734 if ( string_set || (old_src->multi_src.type != src->multi_src.type) ) {
735 RemoveOldStringOrFile(old_src, string_set);
736 file = InitStringOrFile(src, string_set);
738 /* Load pieces does this logic for us, but it shouldn't. Its messy.*/
739 /*if (old_src->multi_src.type == XawAsciiString)
740 LoadPieces(src, NULL, src->multi_src.string);
741 else*/
742 LoadPieces(src, file, NULL);
743 if (file != NULL) fclose(file);
744 XawTextSetSource( XtParent(new), new, 0); /* Tell text widget
745 what happened. */
746 total_reset = TRUE;
749 if ( old_src->multi_src.multi_length != src->multi_src.multi_length )
750 src->multi_src.piece_size = src->multi_src.multi_length;
752 if ( !total_reset && (old_src->multi_src.piece_size
753 != src->multi_src.piece_size) ) {
754 String mb_string = StorePiecesInString( old_src );
756 if ( mb_string != 0 ) {
757 FreeAllPieces( old_src );
758 LoadPieces( src, NULL, mb_string );
759 XtFree( mb_string );
760 } else {
761 /* If the buffer holds bad chars, don't touch it... */
762 XtAppWarningMsg( app_con,
763 "convertError", "multiSource", "XawError",
764 XtName( XtParent( (Widget) old_src ) ), NULL, NULL );
765 XtAppWarningMsg( app_con,
766 "convertError", "multiSource", "XawError",
767 "Non-character code(s) in buffer.", NULL, NULL );
771 return(FALSE);
774 /* Function Name: GetValuesHook
775 * Description: This is a get values hook routine that sets the
776 * values specific to the multi source.
777 * Arguments: w - the MultiSource Widget.
778 * args - the argument list.
779 * num_args - the number of args.
780 * Returns: none.
783 static void
784 GetValuesHook(w, args, num_args)
785 Widget w;
786 ArgList args;
787 Cardinal* num_args;
789 MultiSrcObject src = (MultiSrcObject) w;
790 int i;
792 if (src->multi_src.type == XawAsciiString) {
793 for (i = 0; i < *num_args ; i++ )
794 if (streq(args[i].name, XtNstring)) {
795 if (src->multi_src.use_string_in_place) {
796 *((char **) args[i].value) = (char *)
797 src->multi_src.first_piece->text;
799 else {
800 if (_XawMultiSave(w)) /* If save sucessful. */
801 *((char **) args[i].value) = src->multi_src.string;
803 break;
808 /* Function Name: Destroy
809 * Description: Destroys an multi source (frees all data)
810 * Arguments: src - the Multi source Widget to free.
811 * Returns: none.
814 static void
815 Destroy (w)
816 Widget w;
818 RemoveOldStringOrFile((MultiSrcObject) w, True);
821 /************************************************************
823 * Public routines
825 ************************************************************/
827 /* Function Name: XawMultiSourceFreeString
828 * Description: Frees the string returned by a get values call
829 * on the string when the source is of type string.
830 * Arguments: w - the MultiSrc widget.
831 * Returns: none.
833 * The public interface is XawAsciiSourceFreeString!
836 void
837 #if NeedFunctionPrototypes
838 _XawMultiSourceFreeString(
839 Widget w)
840 #else
841 _XawMultiSourceFreeString(w)
842 Widget w;
843 #endif
845 MultiSrcObject src = (MultiSrcObject) w;
847 /*if (src->multi_src.allocated_string&& src->multi_src.type != XawAsciiFile) {*/
848 /* ASSERT: src->multi_src.allocated_string -> we MUST free .string! */
849 if ( src->multi_src.allocated_string ) {
850 XtFree(src->multi_src.string);
851 src->multi_src.allocated_string = FALSE;
852 src->multi_src.string = NULL;
856 /* Function Name: _XawMultiSave
857 * Description: Saves all the pieces into a file or string as required.
858 * Arguments: w - the multiSrc Widget.
859 * Returns: TRUE if the save was successful.
861 * The public interface is XawAsciiSave(w)!
864 Bool
865 #if NeedFunctionPrototypes
866 _XawMultiSave(
867 Widget w)
868 #else
869 _XawMultiSave(w)
870 Widget w;
871 #endif
873 MultiSrcObject src = (MultiSrcObject) w;
874 XtAppContext app_con = XtWidgetToApplicationContext(w);
875 char * mb_string;
878 * If using the string in place then there is no need to play games
879 * to get the internal info into a readable string.
882 if (src->multi_src.use_string_in_place)
883 return(TRUE);
885 if (src->multi_src.type == XawAsciiFile) {
887 if (!src->multi_src.changes) /* No changes to save. */
888 return(TRUE);
890 mb_string = StorePiecesInString( src );
892 if ( mb_string != 0 ) {
893 if ( WriteToFile( mb_string, src->multi_src.string ) == FALSE ) {
894 XtFree( mb_string );
895 return( FALSE );
897 XtFree( mb_string );
898 src->multi_src.changes = FALSE;
899 return( TRUE );
900 } else {
901 /* If the buffer holds bad chars, don't touch it... */
902 XtAppWarningMsg( app_con,
903 "convertError", "multiSource", "XawError",
904 "Due to illegal characters, file not saved.", NULL, NULL);
905 return( FALSE );
908 else {
910 /* THIS FUNCTIONALITY IS UNDOCUMENTED, probably UNNEEDED? The manual
911 says this routine's only function is to save files to disk. -Sheeran */
913 mb_string = StorePiecesInString( src );
915 if ( mb_string == 0 ) {
916 /* If the buffer holds bad chars, don't touch it... */
917 XtAppWarningMsg( app_con,
918 "convertError", "multiSource", "XawError",
919 XtName( XtParent( (Widget) src ) ), NULL, NULL);
920 return( FALSE );
923 /* assert: mb_string holds good characters so the buffer is fine */
924 if (src->multi_src.allocated_string == TRUE)
925 XtFree(src->multi_src.string);
926 else
927 src->multi_src.allocated_string = TRUE;
929 src->multi_src.string = mb_string;
931 src->multi_src.changes = FALSE;
932 return(TRUE);
935 /* Function Name: XawMultiSaveAsFile
936 * Description: Save the current buffer as a file.
937 * Arguments: w - the MultiSrc widget.
938 * name - name of the file to save this file into.
939 * Returns: True if the save was sucessful.
941 * The public interface is XawAsciiSaveAsFile!
944 Bool
945 #if NeedFunctionPrototypes
946 _XawMultiSaveAsFile(
947 Widget w,
948 _Xconst char* name)
949 #else
950 _XawMultiSaveAsFile(w, name)
951 Widget w;
952 String name;
953 #endif
955 MultiSrcObject src = (MultiSrcObject) w;
956 String mb_string;
957 Boolean ret;
959 mb_string = StorePiecesInString( src );
961 if ( mb_string != 0 ) {
962 ret = WriteToFile( mb_string, name );
963 XtFree( mb_string );
964 return( ret );
967 /* otherwise there was a conversion error. So print widget name too. */
968 XtAppWarningMsg( XtWidgetToApplicationContext(w),
969 "convertError", "multiSource", "XawError",
970 XtName( XtParent( (Widget) src ) ), NULL, NULL);
971 return( False );
974 /************************************************************
976 * Private Functions.
978 ************************************************************/
980 static void
981 RemoveOldStringOrFile(src, checkString)
982 MultiSrcObject src;
983 Boolean checkString;
985 FreeAllPieces(src);
987 if (checkString && src->multi_src.allocated_string) {
988 XtFree(src->multi_src.string);
989 src->multi_src.allocated_string = False;
990 src->multi_src.string = NULL;
994 /* Function Name: WriteToFile
995 * Description: Write the string specified to the begining of the file
996 * specified.
997 * Arguments: string - string to write.
998 * name - the name of the file
999 * Returns: returns TRUE if sucessful, FALSE otherwise.
1002 static Boolean
1003 WriteToFile(string, name)
1004 String string, name;
1006 int fd;
1008 if ( ((fd = creat(name, 0666)) == -1 ) ||
1009 (write(fd, string, sizeof(unsigned char) * strlen(string)) == -1) )
1010 return(FALSE);
1012 if ( close(fd) == -1 )
1013 return(FALSE);
1015 return(TRUE);
1019 /* Function Name: StorePiecesInString
1020 * Description: store the pieces in memory into a char string.
1021 * Arguments: src - the multiSrc to gather data from
1022 * Returns: char *mb_string. Caller must free.
1023 * or 0: conversion error. Caller must panic!
1026 static String
1027 StorePiecesInString(src)
1028 MultiSrcObject src;
1030 wchar_t* wc_string;
1031 char *mb_string;
1032 int char_count = src->multi_src.length;
1033 XawTextPosition first;
1034 MultiPiece * piece;
1036 /* I believe the char_count + 1 and the NULL termination are unneeded! FS*/
1038 wc_string = (wchar_t*) XtMalloc((unsigned)(char_count + 1) * sizeof(wchar_t));
1040 for (first = 0, piece = src->multi_src.first_piece ; piece != NULL;
1041 first += piece->used, piece = piece->next)
1042 (void) wcsncpy( wc_string + first, piece->text, piece->used );
1044 wc_string[ char_count ] = (wchar_t)0; /* NULL terminate this sucker. */
1047 /* This will refill all pieces to capacity. */
1049 if ( src->multi_src.data_compression ) {
1050 FreeAllPieces( src );
1051 LoadPieces( src, NULL, (char *)wc_string );
1054 /* Lastly, convert it to a MB format and send it back. */
1056 mb_string = _XawTextWCToMB( XtDisplayOfObject( (Widget)src ),
1057 wc_string, &char_count );
1059 /* NOTE THAT mb_string MAY BE ZERO IF THE CONVERSION FAILED. */
1060 XtFree( (char*) wc_string );
1061 return( mb_string );
1065 /* Function Name: InitStringOrFile.
1066 * Description: Initializes the string or file.
1067 * Arguments: src - the MultiSource.
1068 * Returns: none - May exit though.
1071 static FILE *
1072 InitStringOrFile(src, newString)
1073 MultiSrcObject src;
1074 Boolean newString;
1076 char * open_mode;
1077 FILE * file;
1078 char fileName[TMPSIZ];
1079 Display *d = XtDisplayOfObject((Widget)src);
1081 if (src->multi_src.type == XawAsciiString) {
1083 if (src->multi_src.string == NULL)
1084 src->multi_src.length = 0;
1086 else if (! src->multi_src.use_string_in_place) {
1087 int length;
1088 String temp = XtNewString(src->multi_src.string);
1089 if ( src->multi_src.allocated_string )
1090 XtFree( src->multi_src.string );
1091 src->multi_src.allocated_string = True;
1092 src->multi_src.string = temp;
1094 length = strlen(src->multi_src.string);
1096 /* Wasteful, throwing away the WC string, but need side effect! */
1097 (void) _XawTextMBToWC(d, src->multi_src.string, &length);
1098 src->multi_src.length = (XawTextPosition) length;
1099 } else {
1100 src->multi_src.length = strlen(src->multi_src.string);
1101 /* In case the length resource is incorrectly set */
1102 if (src->multi_src.length > src->multi_src.multi_length)
1103 src->multi_src.multi_length = src->multi_src.length;
1105 if (src->multi_src.multi_length == MAGIC_VALUE)
1106 src->multi_src.piece_size = src->multi_src.length;
1107 else
1108 src->multi_src.piece_size = src->multi_src.multi_length + 1;
1111 /*((TextWidget)src->object.parent)->text.lastPos = src->multi_src.length;*/
1112 return(NULL);
1116 * type is XawAsciiFile.
1119 src->multi_src.is_tempfile = FALSE;
1121 switch (src->text_src.edit_mode) {
1122 case XawtextRead:
1123 if (src->multi_src.string == NULL)
1124 XtErrorMsg("NoFile", "multiSourceCreate", "XawError",
1125 "Creating a read only disk widget and no file specified.",
1126 NULL, 0);
1127 open_mode = "r";
1128 break;
1129 case XawtextAppend:
1130 case XawtextEdit:
1131 if (src->multi_src.string == NULL) {
1133 if ( src->multi_src.allocated_string )
1134 XtFree( src->multi_src.string );
1135 src->multi_src.allocated_string = False;
1136 src->multi_src.string = fileName;
1138 (void) tmpnam(src->multi_src.string);
1139 src->multi_src.is_tempfile = TRUE;
1140 open_mode = "w";
1141 } else
1142 open_mode = "r+";
1143 break;
1144 default:
1145 XtErrorMsg("badMode", "multiSourceCreate", "XawError",
1146 "Bad editMode for multi source; must be Read, Append or Edit.",
1147 NULL, NULL);
1150 /* Allocate new memory for the temp filename, because it is held in
1151 * a stack memory buffer. We must verify that all routines that set
1152 * .string first check .allocated_string and free it - plumbing Sheeran.
1154 if (newString || src->multi_src.is_tempfile) {
1155 if ( src->multi_src.allocated_string )
1156 XtFree( src->multi_src.string );
1157 src->multi_src.string = XtNewString(src->multi_src.string);
1158 src->multi_src.allocated_string = TRUE;
1161 if (!src->multi_src.is_tempfile) {
1162 if ((file = fopen(src->multi_src.string, open_mode)) != 0) {
1163 (void) fseek(file, (Off_t)0, 2);
1164 src->multi_src.length = ftell (file);
1165 return file;
1166 } else {
1167 String params[2];
1168 Cardinal num_params = 2;
1170 params[0] = src->multi_src.string;
1171 params[1] = strerror(errno);
1172 XtAppWarningMsg(XtWidgetToApplicationContext((Widget)src),
1173 "openError", "multiSourceCreate", "XawWarning",
1174 "Cannot open file %s; %s", params, &num_params);
1177 src->multi_src.length = 0;
1178 return((FILE *)NULL);
1179 #undef StrLen
1182 /* LoadPieces: This routine takes either the MB contents of open file `file' or the
1183 MB contents of string or the MB contents of src->multi_src.string and places
1184 them in Pieces in WC format.
1186 CAUTION: You must have src->multi_src.length set to file length bytes
1187 when src->multi_src.type == XawAsciiFile. src->multi_src.length must be
1188 the length of the parameter string if string is non-NULL. */
1190 static void
1191 LoadPieces(src, file, string)
1192 MultiSrcObject src;
1193 FILE* file;
1194 char* string;
1196 Display *d = XtDisplayOfObject((Widget)src);
1197 wchar_t* local_str, *ptr;
1198 MultiPiece* piece = NULL;
1199 XawTextPosition left;
1200 int bytes = sizeof(wchar_t);
1201 char* temp_mb_holder = NULL;
1204 * This is tricky - the _XawTextMBtoWC converter uses its 3rd arg
1205 * in as MB length, out as WC length. We want local_length to be
1206 * WC count.
1208 int local_length = src->multi_src.length;
1210 if (string != NULL) {
1212 * ASSERT: IF our caller passed a non-null string, THEN
1213 * src->multi_src.length is currently string's * byte count,
1214 * AND string is in a MB format.
1216 local_str = _XawTextMBToWC(d, (char *)string, &local_length);
1217 src->multi_src.length = (XawTextPosition) local_length;
1218 } else if (src->multi_src.type != XawAsciiFile) {
1220 * here, we are not changing the contents, just reloading,
1221 * so don't change len...
1223 local_length = src->multi_src.string ?
1224 strlen( src->multi_src.string ) : 0;
1225 local_str = _XawTextMBToWC( d, (char*)src->multi_src.string, &local_length );
1226 } else {
1227 if (src->multi_src.length != 0) {
1228 temp_mb_holder =
1229 XtMalloc((unsigned)(src->multi_src.length + 1) * sizeof(unsigned char));
1230 fseek(file, (Off_t)0, 0);
1231 src->multi_src.length = fread (temp_mb_holder,
1232 (Size_t)sizeof(unsigned char),
1233 (Size_t)src->multi_src.length, file);
1234 if (src->multi_src.length <= 0)
1235 XtAppErrorMsg( XtWidgetToApplicationContext ((Widget) src),
1236 "readError", "multiSource", "XawError",
1237 "fread returned error.", NULL, NULL);
1238 local_length = src->multi_src.length;
1239 local_str = _XawTextMBToWC(d, temp_mb_holder, &local_length);
1240 src->multi_src.length = local_length;
1242 if ( local_str == 0 ) {
1243 String params[2];
1244 Cardinal num_params;
1245 static char err_text[] =
1246 "<<< FILE CONTENTS NOT REPRESENTABLE IN THIS LOCALE >>>";
1248 params[0] = XtName(XtParent((Widget)src));
1249 params[1] = src->multi_src.string;
1250 num_params = 2;
1252 XtAppWarningMsg( XtWidgetToApplicationContext((Widget)src),
1253 "readLocaleError", "multiSource", "XawError",
1254 "%s: The file `%s' contains characters not representable in this locale.",
1255 params, &num_params);
1256 src->multi_src.length = sizeof err_text;
1257 local_length = src->multi_src.length;
1258 local_str = _XawTextMBToWC(d, err_text, &local_length);
1259 src->multi_src.length = local_length;
1261 } else { /*ASSERT that since following while loop looks at local_length
1262 this isn't needed. Sheeran, Omron KK, 1993/07/15
1263 temp_mb_holder[src->multi_src.length] = '\0';*/
1264 local_str = (wchar_t*)temp_mb_holder;
1268 if (src->multi_src.use_string_in_place) {
1269 piece = AllocNewPiece(src, piece);
1270 piece->used = Min(src->multi_src.length, src->multi_src.piece_size);
1271 piece->text = (wchar_t*)src->multi_src.string;
1272 return;
1275 ptr = local_str;
1276 left = local_length;
1278 do {
1279 piece = AllocNewPiece(src, piece);
1281 piece->text = (wchar_t*)XtMalloc(src->multi_src.piece_size * bytes);
1282 piece->used = Min(left, src->multi_src.piece_size);
1283 if (piece->used != 0)
1284 (void) wcsncpy(piece->text, ptr, piece->used);
1286 left -= piece->used;
1287 ptr += piece->used;
1288 } while (left > 0);
1290 if ( temp_mb_holder )
1291 XtFree( (char*) temp_mb_holder );
1295 /* Function Name: AllocNewPiece
1296 * Description: Allocates a new piece of memory.
1297 * Arguments: src - The MultiSrc Widget.
1298 * prev - the piece just before this one, or NULL.
1299 * Returns: the allocated piece.
1302 static MultiPiece *
1303 AllocNewPiece(src, prev)
1304 MultiSrcObject src;
1305 MultiPiece * prev;
1307 MultiPiece * piece = XtNew(MultiPiece);
1309 if (prev == NULL) {
1310 src->multi_src.first_piece = piece;
1311 piece->next = NULL;
1313 else {
1314 if (prev->next != NULL)
1315 (prev->next)->prev = piece;
1316 piece->next = prev->next;
1317 prev->next = piece;
1320 piece->prev = prev;
1322 return(piece);
1325 /* Function Name: FreeAllPieces
1326 * Description: Frees all the pieces
1327 * Arguments: src - The MultiSrc Widget.
1328 * Returns: none.
1331 static void
1332 FreeAllPieces(src)
1333 MultiSrcObject src;
1335 MultiPiece * next, * first = src->multi_src.first_piece;
1337 if (first->prev != NULL)
1338 printf("Xaw MultiSrc Object: possible memory leak in FreeAllPieces().\n");
1340 for ( ; first != NULL ; first = next ) {
1341 next = first->next;
1342 RemovePiece(src, first);
1346 /* Function Name: RemovePiece
1347 * Description: Removes a piece from the list.
1348 * Arguments:
1349 * piece - the piece to remove.
1350 * Returns: none.
1353 static void
1354 RemovePiece(src, piece)
1355 MultiSrcObject src;
1356 MultiPiece* piece;
1358 if (piece->prev == NULL)
1359 src->multi_src.first_piece = piece->next;
1360 else
1361 (piece->prev)->next = piece->next;
1363 if (piece->next != NULL)
1364 (piece->next)->prev = piece->prev;
1366 if (!src->multi_src.use_string_in_place)
1367 XtFree((char *)piece->text);
1369 XtFree((char *)piece);
1372 /* Function Name: FindPiece
1373 * Description: Finds the piece containing the position indicated.
1374 * Arguments: src - The MultiSrc Widget.
1375 * position - the position that we are searching for.
1376 * RETURNED first - the position of the first character in this piece.
1377 * Returns: piece - the piece that contains this position.
1380 static MultiPiece *
1381 FindPiece(src, position, first)
1382 MultiSrcObject src;
1383 XawTextPosition position, *first;
1385 MultiPiece * old_piece, * piece = src->multi_src.first_piece;
1386 XawTextPosition temp;
1388 for ( temp = 0 ; piece != NULL ; temp += piece->used, piece = piece->next ) {
1389 *first = temp;
1390 old_piece = piece;
1392 if ((temp + piece->used) > position)
1393 return(piece);
1395 return(old_piece); /* if we run off the end the return the last piece */
1398 /* Function Name: BreakPiece
1399 * Description: Breaks a full piece into two new pieces.
1400 * Arguments: src - The MultiSrc Widget.
1401 * piece - the piece to break.
1402 * Returns: none.
1405 #define HALF_PIECE (src->multi_src.piece_size/2)
1407 static void
1408 BreakPiece(src, piece)
1409 MultiSrcObject src;
1410 MultiPiece* piece;
1412 MultiPiece * new = AllocNewPiece(src, piece);
1414 new->text = (wchar_t*)XtMalloc(src->multi_src.piece_size * sizeof(wchar_t));
1415 (void) wcsncpy(new->text, piece->text + HALF_PIECE,
1416 src->multi_src.piece_size - HALF_PIECE);
1417 piece->used = HALF_PIECE;
1418 new->used = src->multi_src.piece_size - HALF_PIECE;
1421 /* Convert string "XawAsciiString" and "XawAsciiFile" to quarks. */
1423 /* ARGSUSED */
1424 static void
1425 CvtStringToMultiType(args, num_args, fromVal, toVal)
1426 XrmValuePtr args; /* unused */
1427 Cardinal* num_args; /* unused */
1428 XrmValuePtr fromVal;
1429 XrmValuePtr toVal;
1431 static XawAsciiType type;
1432 static XrmQuark XtQEstring = NULLQUARK;
1433 static XrmQuark XtQEfile;
1434 XrmQuark q;
1435 char lowerName[40];
1437 if (XtQEstring == NULLQUARK) {
1438 XtQEstring = XrmPermStringToQuark(XtEstring);
1439 XtQEfile = XrmPermStringToQuark(XtEfile);
1442 if (strlen ((char*) fromVal->addr) < sizeof lowerName) {
1443 XmuCopyISOLatin1Lowered(lowerName, (char *) fromVal->addr);
1444 q = XrmStringToQuark(lowerName);
1446 if (q == XtQEstring) type = XawAsciiString;
1447 else if (q == XtQEfile) type = XawAsciiFile;
1448 else {
1449 toVal->size = 0;
1450 toVal->addr = NULL;
1451 return;
1453 toVal->size = sizeof type;
1454 toVal->addr = (XPointer) &type;
1455 return;
1457 toVal->size = 0;
1458 toVal->addr = NULL;