1 /* $XConsortium: MultiSrc.c,v 1.6 94/04/17 20:12:25 kaleb Exp $ */
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>
77 /****************************************************************
79 * Full class record constant
81 ****************************************************************/
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
},
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
},
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))
122 static void (MyWStrncpy
)();
125 extern char *tmpnam();
126 #ifdef X_NOT_STDC_ENV
132 #define Size_t unsigned int
135 #define Size_t size_t
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
,
155 /* resources */ resources
,
156 /* num_resources */ XtNumber(resources
),
157 /* xrm_class */ NULLQUARK
,
162 /* destroy */ Destroy
,
165 /* set_values */ SetValues
,
166 /* set_values_hook */ NULL
,
168 /* get_values_hook */ GetValuesHook
,
170 /* version */ XtVersion
,
171 /* callback_private */ NULL
,
177 { /* textSrc_class fields */
179 /* Replace */ ReplaceText
,
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.
207 XawInitializeWidgetSet();
208 XtAddConverter( XtRString
, XtRMultiType
, CvtStringToMultiType
,
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
222 Initialize(request
, new, args
, num_args
)
227 MultiSrcObject src
= (MultiSrcObject
) new;
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
)
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.
283 ReplaceText( w
, startPos
, endPos
, u_text_p
)
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
;
293 Boolean local_artificial_block
= False
;
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. */
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 */
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 */
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
);
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
;
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
);
423 start_piece
->used
+= 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. */
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
);
445 /* Function Name: Scan
446 * Description: Scans the text source for the number and type
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.
464 Scan( w
, position
, type
, dir
, count
, include
)
466 XawTextPosition position
;
467 XawTextScanType type
;
468 XawTextScanDirection dir
;
472 MultiSrcObject src
= (MultiSrcObject
) w
;
475 XawTextPosition first
, first_eol_position
;
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
);
503 piece
= FindPiece(src
, position
, &first
);
505 if ( piece
->used
== 0 ) return(0); /* i.e., buffer is empty. */
507 ptr
= (position
- first
) + piece
->text
;
512 case XawstWhiteSpace
:
513 for ( ; count
> 0 ; count
-- ) {
514 Boolean non_space
= FALSE
, first_eol
= TRUE
;
522 if (type
== XawstWhiteSpace
) {
530 else if (type
== XawstEOL
) {
531 if (c
== _Xaw_atowc(XawLF
)) break;
533 else { /* XawstParagraph */
535 if (c
== _Xaw_atowc(XawLF
)) {
536 first_eol_position
= position
;
541 if ( c
== _Xaw_atowc(XawLF
))
543 else if ( !iswspace(c
) )
548 if ( ptr
< piece
->text
) {
550 if (piece
== NULL
) /* Begining of text. */
552 ptr
= piece
->text
+ piece
->used
- 1;
554 else if ( ptr
>= (piece
->text
+ piece
->used
) ) {
556 if (piece
== NULL
) /* End of text. */
557 return(src
->multi_src
.length
);
563 if ( type
== XawstParagraph
)
564 position
= first_eol_position
;
569 position
+= count
* inc
;
571 /* case XawstAll: ---- handled in special code above */
574 if ( dir
== XawsdLeft
)
577 if (position
>= src
->multi_src
.length
)
578 return(src
->multi_src
.length
);
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
)
597 XawTextPosition position
;
598 XawTextScanDirection dir
;
601 MultiSrcObject src
= (MultiSrcObject
) w
;
606 Display
* d
= XtDisplay(XtParent(w
));
609 XawTextPosition first
;
612 /* STEP 1: First, a brief sanity check. */
614 if ( dir
== XawsdRight
)
619 return(XawTextSearchError
); /* scanning left from 0??? */
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
] );
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
;
655 if (*ptr
== ((dir
== XawsdRight
) ? *(buf
+ count
)
656 : *(buf
+ wtarget_len
- count
- 1)) ) {
657 if (count
== (text
->length
- 1))
664 position
-=inc
* count
;
673 while ( ptr
< piece
->text
) {
675 if (piece
== NULL
) { /* Begining of text. */
677 return(XawTextSearchError
);
679 ptr
= piece
->text
+ piece
->used
- 1;
682 while ( ptr
>= (piece
->text
+ piece
->used
) ) {
684 if (piece
== NULL
) { /* End of text. */
686 return(XawTextSearchError
);
692 XtFree( (char *) buf
);
693 if (dir
== XawsdLeft
)
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.
708 SetValues(current
, request
, new, args
, num_args
)
709 Widget current
, request
, new;
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
;
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
)) {
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);
742 LoadPieces(src
, file
, NULL
);
743 if (file
!= NULL
) fclose(file
);
744 XawTextSetSource( XtParent(new), new, 0); /* Tell text widget
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
);
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
);
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.
784 GetValuesHook(w
, args
, num_args
)
789 MultiSrcObject src
= (MultiSrcObject
) w
;
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
;
800 if (_XawMultiSave(w
)) /* If save sucessful. */
801 *((char **) args
[i
].value
) = src
->multi_src
.string
;
808 /* Function Name: Destroy
809 * Description: Destroys an multi source (frees all data)
810 * Arguments: src - the Multi source Widget to free.
818 RemoveOldStringOrFile((MultiSrcObject
) w
, True
);
821 /************************************************************
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.
833 * The public interface is XawAsciiSourceFreeString!
837 #if NeedFunctionPrototypes
838 _XawMultiSourceFreeString(
841 _XawMultiSourceFreeString(w
)
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)!
865 #if NeedFunctionPrototypes
873 MultiSrcObject src
= (MultiSrcObject
) w
;
874 XtAppContext app_con
= XtWidgetToApplicationContext(w
);
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
)
885 if (src
->multi_src
.type
== XawAsciiFile
) {
887 if (!src
->multi_src
.changes
) /* No changes to save. */
890 mb_string
= StorePiecesInString( src
);
892 if ( mb_string
!= 0 ) {
893 if ( WriteToFile( mb_string
, src
->multi_src
.string
) == FALSE
) {
898 src
->multi_src
.changes
= FALSE
;
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
);
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
);
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
);
927 src
->multi_src
.allocated_string
= TRUE
;
929 src
->multi_src
.string
= mb_string
;
931 src
->multi_src
.changes
= FALSE
;
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!
945 #if NeedFunctionPrototypes
950 _XawMultiSaveAsFile(w
, name
)
955 MultiSrcObject src
= (MultiSrcObject
) w
;
959 mb_string
= StorePiecesInString( src
);
961 if ( mb_string
!= 0 ) {
962 ret
= WriteToFile( mb_string
, name
);
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
);
974 /************************************************************
978 ************************************************************/
981 RemoveOldStringOrFile(src
, checkString
)
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
997 * Arguments: string - string to write.
998 * name - the name of the file
999 * Returns: returns TRUE if sucessful, FALSE otherwise.
1003 WriteToFile(string
, name
)
1004 String string
, name
;
1008 if ( ((fd
= creat(name
, 0666)) == -1 ) ||
1009 (write(fd
, string
, sizeof(unsigned char) * strlen(string
)) == -1) )
1012 if ( close(fd
) == -1 )
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!
1027 StorePiecesInString(src
)
1032 int char_count
= src
->multi_src
.length
;
1033 XawTextPosition first
;
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.
1072 InitStringOrFile(src
, newString
)
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
) {
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
;
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
;
1108 src
->multi_src
.piece_size
= src
->multi_src
.multi_length
+ 1;
1111 /*((TextWidget)src->object.parent)->text.lastPos = src->multi_src.length;*/
1116 * type is XawAsciiFile.
1119 src
->multi_src
.is_tempfile
= FALSE
;
1121 switch (src
->text_src
.edit_mode
) {
1123 if (src
->multi_src
.string
== NULL
)
1124 XtErrorMsg("NoFile", "multiSourceCreate", "XawError",
1125 "Creating a read only disk widget and no file specified.",
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
;
1145 XtErrorMsg("badMode", "multiSourceCreate", "XawError",
1146 "Bad editMode for multi source; must be Read, Append or Edit.",
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
);
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
);
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. */
1191 LoadPieces(src
, file
, 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
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
);
1227 if (src
->multi_src
.length
!= 0) {
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 ) {
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
;
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
;
1276 left
= local_length
;
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
;
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.
1303 AllocNewPiece(src
, prev
)
1307 MultiPiece
* piece
= XtNew(MultiPiece
);
1310 src
->multi_src
.first_piece
= piece
;
1314 if (prev
->next
!= NULL
)
1315 (prev
->next
)->prev
= piece
;
1316 piece
->next
= prev
->next
;
1325 /* Function Name: FreeAllPieces
1326 * Description: Frees all the pieces
1327 * Arguments: src - The MultiSrc Widget.
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
) {
1342 RemovePiece(src
, first
);
1346 /* Function Name: RemovePiece
1347 * Description: Removes a piece from the list.
1349 * piece - the piece to remove.
1354 RemovePiece(src
, piece
)
1358 if (piece
->prev
== NULL
)
1359 src
->multi_src
.first_piece
= piece
->next
;
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.
1381 FindPiece(src
, position
, first
)
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
) {
1392 if ((temp
+ piece
->used
) > position
)
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.
1405 #define HALF_PIECE (src->multi_src.piece_size/2)
1408 BreakPiece(src
, 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. */
1425 CvtStringToMultiType(args
, num_args
, fromVal
, toVal
)
1426 XrmValuePtr args
; /* unused */
1427 Cardinal
* num_args
; /* unused */
1428 XrmValuePtr fromVal
;
1431 static XawAsciiType type
;
1432 static XrmQuark XtQEstring
= NULLQUARK
;
1433 static XrmQuark XtQEfile
;
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
;
1453 toVal
->size
= sizeof type
;
1454 toVal
->addr
= (XPointer
) &type
;