1 /* $XConsortium: AsciiSrc.c,v 1.65 94/04/17 20:11:45 kaleb Exp $ */
2
3 /*
4
5 Copyright (c) 1989, 1994 X Consortium
6
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 Except as contained in this notice, the name of the X Consortium shall not be
25 used in advertising or otherwise to promote the sale, use or other dealings
26 in this Software without prior written authorization from the X Consortium.
27
28 */
29
30 /*
31 * AsciiSrc.c - AsciiSrc object. (For use with the text widget).
32 *
33 */
34
35 #include "Xaw3dP.h"
36 #include <X11/IntrinsicP.h>
37 #include <stdio.h>
38 #include <ctype.h>
39 #include <errno.h>
40 #include <X11/StringDefs.h>
41 #include <X11/Xos.h>
42 #ifndef X_NOT_STDC_ENV
43 #include <stdlib.h>
44 #endif
45 #include <X11/Xfuncs.h>
46 #include <X11/Xaw3d/XawInit.h>
47 #include <X11/Xaw3d/AsciiSrcP.h>
48 #include <X11/Xmu/Misc.h>
49 #include <X11/Xmu/CharSet.h>
50 #ifdef XAW_INTERNATIONALIZATION
51 #include <X11/Xaw3d/MultiSrcP.h>
52 #endif
53
54
55 #if (defined(ASCII_STRING) || defined(ASCII_DISK))
56 # include <X11/Xaw3d/AsciiText.h> /* for Widget Classes. */
57 #endif
58
59
60 /****************************************************************
61 *
62 * Full class record constant
63 *
64 ****************************************************************/
65
66 /* Private Data */
67
68 static int magic_value = MAGIC_VALUE;
69
70 #define offset(field) XtOffsetOf(AsciiSrcRec, ascii_src.field)
71
72 static XtResource resources[] = {
73 {XtNstring, XtCString, XtRString, sizeof (char *),
74 offset(string), XtRString, NULL},
75 {XtNtype, XtCType, XtRAsciiType, sizeof (XawAsciiType),
76 offset(type), XtRImmediate, (XtPointer)XawAsciiString},
77 {XtNdataCompression, XtCDataCompression, XtRBoolean, sizeof (Boolean),
78 offset(data_compression), XtRImmediate, (XtPointer) TRUE},
79 {XtNpieceSize, XtCPieceSize, XtRInt, sizeof (XawTextPosition),
80 offset(piece_size), XtRImmediate, (XtPointer) BUFSIZ},
81 {XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer),
82 offset(callback), XtRCallback, (XtPointer)NULL},
83 {XtNuseStringInPlace, XtCUseStringInPlace, XtRBoolean, sizeof (Boolean),
84 offset(use_string_in_place), XtRImmediate, (XtPointer) FALSE},
85 {XtNlength, XtCLength, XtRInt, sizeof (int),
86 offset(ascii_length), XtRInt, (XtPointer) &magic_value},
87
88 #ifdef ASCII_DISK
89 {XtNfile, XtCFile, XtRString, sizeof (String),
90 offset(filename), XtRString, NULL},
91 #endif /* ASCII_DISK */
92 };
93 #undef offset
94
95 static XawTextPosition Scan(), Search(), ReadText();
96 static int ReplaceText();
97 static Piece * FindPiece(), * AllocNewPiece();
98 static FILE * InitStringOrFile();
99 static void FreeAllPieces(), RemovePiece(), BreakPiece(), LoadPieces();
100 static void RemoveOldStringOrFile(), CvtStringToAsciiType();
101 static void ClassInitialize(), Initialize(), Destroy(), GetValuesHook();
102 static String MyStrncpy(), StorePiecesInString();
103 static Boolean SetValues(), WriteToFile();
104 #ifdef X_NOT_STDC_ENV
105 extern int errno;
106 #endif
107
108 #ifdef X_NOT_POSIX
109 #define Off_t long
110 #define Size_t unsigned int
111 #else
112 #define Off_t off_t
113 #define Size_t size_t
114 #endif
115
116 #define superclass (&textSrcClassRec)
117 AsciiSrcClassRec asciiSrcClassRec = {
118 {
119 /* core_class fields */
120 /* superclass */ (WidgetClass) superclass,
121 /* class_name */ "AsciiSrc",
122 /* widget_size */ sizeof(AsciiSrcRec),
123 /* class_initialize */ ClassInitialize,
124 /* class_part_initialize */ NULL,
125 /* class_inited */ FALSE,
126 /* initialize */ Initialize,
127 /* initialize_hook */ NULL,
128 /* realize */ NULL,
129 /* actions */ NULL,
130 /* num_actions */ 0,
131 /* resources */ resources,
132 /* num_resources */ XtNumber(resources),
133 /* xrm_class */ NULLQUARK,
134 /* compress_motion */ FALSE,
135 /* compress_exposure */ FALSE,
136 /* compress_enterleave */ FALSE,
137 /* visible_interest */ FALSE,
138 /* destroy */ Destroy,
139 /* resize */ NULL,
140 /* expose */ NULL,
141 /* set_values */ SetValues,
142 /* set_values_hook */ NULL,
143 /* set_values_almost */ NULL,
144 /* get_values_hook */ GetValuesHook,
145 /* accept_focus */ NULL,
146 /* version */ XtVersion,
147 /* callback_private */ NULL,
148 /* tm_table */ NULL,
149 /* query_geometry */ NULL,
150 /* display_accelerator */ NULL,
151 /* extension */ NULL
152 },
153 /* textSrc_class fields */
154 {
155 /* Read */ ReadText,
156 /* Replace */ ReplaceText,
157 /* Scan */ Scan,
158 /* Search */ Search,
159 /* SetSelection */ XtInheritSetSelection,
160 /* ConvertSelection */ XtInheritConvertSelection
161 },
162 /* asciiSrc_class fields */
163 {
164 /* Keep the compiler happy */ '\0'
165 }
166 };
167
168 WidgetClass asciiSrcObjectClass = (WidgetClass)&asciiSrcClassRec;
169
170 /************************************************************
171 *
172 * Semi-Public Interfaces.
173 *
174 ************************************************************/
175
176 /* Function Name: ClassInitialize
177 * Description: Class Initialize routine, called only once.
178 * Arguments: none.
179 * Returns: none.
180 */
181
182 static void
ClassInitialize()183 ClassInitialize()
184 {
185 XawInitializeWidgetSet();
186 XtAddConverter( XtRString, XtRAsciiType, CvtStringToAsciiType,
187 NULL, (Cardinal) 0);
188 }
189
190 /* Function Name: Initialize
191 * Description: Initializes the simple menu widget
192 * Arguments: request - the widget requested by the argument list.
193 * new - the new widget with both resource and non
194 * resource values.
195 * Returns: none.
196 */
197
198 /* ARGSUSED */
199 static void
Initialize(request,new,args,num_args)200 Initialize(request, new, args, num_args)
201 Widget request, new;
202 ArgList args;
203 Cardinal *num_args;
204 {
205 AsciiSrcObject src = (AsciiSrcObject) new;
206 FILE * file;
207
208 /*
209 * Set correct flags (override resources) depending upon widget class.
210 */
211
212 src->text_src.text_format = XawFmt8Bit; /* data format. */
213
214 #ifdef ASCII_DISK
215 if (XtIsSubclass(XtParent(new), asciiDiskWidgetClass)) {
216 src->ascii_src.type = XawAsciiFile;
217 src->ascii_src.string = src->ascii_src.filename;
218 }
219 #endif
220
221 #ifdef ASCII_STRING
222 if (XtIsSubclass(XtParent(new), asciiStringWidgetClass)) {
223 src->ascii_src.use_string_in_place = TRUE;
224 src->ascii_src.type = XawAsciiString;
225 }
226 #endif
227
228 src->ascii_src.changes = FALSE;
229 src->ascii_src.allocated_string = FALSE;
230
231 file = InitStringOrFile(src, src->ascii_src.type == XawAsciiFile);
232 LoadPieces(src, file, NULL);
233
234 if (file != NULL) fclose(file);
235 }
236
237 /* Function Name: ReadText
238 * Description: This function reads the source.
239 * Arguments: w - the AsciiSource widget.
240 * pos - position of the text to retreive.
241 * RETURNED text - text block that will contain returned text.
242 * length - maximum number of characters to read.
243 * Returns: The number of characters read into the buffer.
244 */
245
246 static XawTextPosition
ReadText(w,pos,text,length)247 ReadText(w, pos, text, length)
248 Widget w;
249 XawTextPosition pos;
250 XawTextBlock *text;
251 int length;
252 {
253 AsciiSrcObject src = (AsciiSrcObject) w;
254 XawTextPosition count, start;
255 Piece * piece = FindPiece(src, pos, &start);
256
257 text->firstPos = pos;
258 text->ptr = piece->text + (pos - start);
259 count = piece->used - (pos - start);
260 text->length = (length > count) ? count : length;
261 return(pos + text->length);
262 }
263
264 /* Function Name: ReplaceText.
265 * Description: Replaces a block of text with new text.
266 * Arguments: w - the AsciiSource widget.
267 * startPos, endPos - ends of text that will be removed.
268 * text - new text to be inserted into buffer at startPos.
269 * Returns: XawEditError or XawEditDone.
270 */
271
272 /*ARGSUSED*/
273 static int
ReplaceText(w,startPos,endPos,text)274 ReplaceText (w, startPos, endPos, text)
275 Widget w;
276 XawTextPosition startPos, endPos;
277 XawTextBlock *text;
278 {
279 AsciiSrcObject src = (AsciiSrcObject) w;
280 Piece *start_piece, *end_piece, *temp_piece;
281 XawTextPosition start_first, end_first;
282 int length, firstPos;
283
284 /*
285 * Editing a read only source is not allowed.
286 */
287
288 if (src->text_src.edit_mode == XawtextRead)
289 return(XawEditError);
290
291 start_piece = FindPiece(src, startPos, &start_first);
292 end_piece = FindPiece(src, endPos, &end_first);
293
294 src->ascii_src.changes = TRUE; /* We have changed the buffer. */
295
296 /*
297 * Remove Old Stuff.
298 */
299
300 if (start_piece != end_piece) {
301 temp_piece = start_piece->next;
302
303 /*
304 * If empty and not the only piece then remove it.
305 */
306
307 if ( ((start_piece->used = startPos - start_first) == 0) &&
308 !((start_piece->next == NULL) && (start_piece->prev == NULL)) )
309 RemovePiece(src, start_piece);
310
311 while (temp_piece != end_piece) {
312 temp_piece = temp_piece->next;
313 RemovePiece(src, temp_piece->prev);
314 }
315 end_piece->used -= endPos - end_first;
316 if (end_piece->used != 0)
317 MyStrncpy(end_piece->text, (end_piece->text + endPos - end_first),
318 (int) end_piece->used);
319 }
320 else { /* We are fully in one piece. */
321 if ( (start_piece->used -= endPos - startPos) == 0) {
322 if ( !((start_piece->next == NULL) && (start_piece->prev == NULL)) )
323 RemovePiece(src, start_piece);
324 }
325 else {
326 MyStrncpy(start_piece->text + (startPos - start_first),
327 start_piece->text + (endPos - start_first),
328 (int) (start_piece->used - (startPos - start_first)) );
329 if ( src->ascii_src.use_string_in_place &&
330 ((src->ascii_src.length - (endPos - startPos)) <
331 (src->ascii_src.piece_size - 1)) )
332 start_piece->text[src->ascii_src.length - (endPos - startPos)] = '\0';
333 }
334 }
335
336 src->ascii_src.length += -(endPos - startPos) + text->length;
337
338 if ( text->length != 0) {
339
340 /*
341 * Put in the New Stuff.
342 */
343
344 start_piece = FindPiece(src, startPos, &start_first);
345
346 length = text->length;
347 firstPos = text->firstPos;
348
349 while (length > 0) {
350 char * ptr;
351 int fill;
352
353 if (src->ascii_src.use_string_in_place) {
354 if (start_piece->used == (src->ascii_src.piece_size - 1)) {
355 /*
356 * If we are in ascii string emulation mode. Then the
357 * string is not allowed to grow.
358 */
359 start_piece->used = src->ascii_src.length =
360 src->ascii_src.piece_size - 1;
361 start_piece->text[src->ascii_src.length] = '\0';
362 return(XawEditError);
363 }
364 }
365
366
367 if (start_piece->used == src->ascii_src.piece_size) {
368 BreakPiece(src, start_piece);
369 start_piece = FindPiece(src, startPos, &start_first);
370 }
371
372 fill = Min((int)(src->ascii_src.piece_size - start_piece->used), length);
373
374 ptr = start_piece->text + (startPos - start_first);
375 MyStrncpy(ptr + fill, ptr,
376 (int) start_piece->used - (startPos - start_first));
377 strncpy(ptr, text->ptr + firstPos, fill);
378
379 startPos += fill;
380 firstPos += fill;
381 start_piece->used += fill;
382 length -= fill;
383 }
384 }
385
386 if (src->ascii_src.use_string_in_place)
387 start_piece->text[start_piece->used] = '\0';
388
389 XtCallCallbacks(w, XtNcallback, NULL); /* Call callbacks, we have changed
390 the buffer. */
391
392 return(XawEditDone);
393 }
394
395 /* Function Name: Scan
396 * Description: Scans the text source for the number and type
397 * of item specified.
398 * Arguments: w - the AsciiSource widget.
399 * position - the position to start scanning.
400 * type - type of thing to scan for.
401 * dir - direction to scan.
402 * count - which occurance if this thing to search for.
403 * include - whether or not to include the character found in
404 * the position that is returned.
405 * Returns: the position of the item found.
406 *
407 * Note: While there are only 'n' characters in the file there are n+1
408 * possible cursor positions (one before the first character and
409 * one after the last character.
410 */
411
412 static
413 XawTextPosition
Scan(w,position,type,dir,count,include)414 Scan (w, position, type, dir, count, include)
415 Widget w;
416 XawTextPosition position;
417 XawTextScanType type;
418 XawTextScanDirection dir;
419 int count;
420 Boolean include;
421 {
422 AsciiSrcObject src = (AsciiSrcObject) w;
423 int inc;
424 Piece* piece;
425 XawTextPosition first, first_eol_position = 0;
426 char* ptr;
427
428 if (type == XawstAll) { /* Optomize this common case. */
429 if (dir == XawsdRight)
430 return(src->ascii_src.length);
431 return(0); /* else. */
432 }
433
434 if (position > src->ascii_src.length)
435 position = src->ascii_src.length;
436
437 if ( dir == XawsdRight ) {
438 if (position == src->ascii_src.length)
439 /*
440 * Scanning right from src->ascii_src.length???
441 */
442 return(src->ascii_src.length);
443 inc = 1;
444 }
445 else {
446 if (position == 0)
447 return(0); /* Scanning left from 0??? */
448 inc = -1;
449 position--;
450 }
451
452 piece = FindPiece(src, position, &first);
453
454 /*
455 * If the buffer is empty then return 0.
456 */
457
458 if ( piece->used == 0 ) return(0);
459
460 ptr = (position - first) + piece->text;
461
462 switch (type) {
463 case XawstEOL:
464 case XawstParagraph:
465 case XawstWhiteSpace:
466 for ( ; count > 0 ; count-- ) {
467 Boolean non_space = FALSE, first_eol = TRUE;
468 /* CONSTCOND */
469 while (TRUE) {
470 unsigned char c = *ptr;
471
472 ptr += inc;
473 position += inc;
474
475 if (type == XawstWhiteSpace) {
476 if (isspace(c)) {
477 if (non_space)
478 break;
479 }
480 else
481 non_space = TRUE;
482 }
483 else if (type == XawstEOL) {
484 if (c == '\n') break;
485 }
486 else { /* XawstParagraph */
487 if (first_eol) {
488 if (c == '\n') {
489 first_eol_position = position;
490 first_eol = FALSE;
491 }
492 }
493 else
494 if ( c == '\n')
495 break;
496 else if ( !isspace(c) )
497 first_eol = TRUE;
498 }
499
500
501 if ( ptr < piece->text ) {
502 piece = piece->prev;
503 if (piece == NULL) /* Begining of text. */
504 return(0);
505 ptr = piece->text + piece->used - 1;
506 }
507 else if ( ptr >= (piece->text + piece->used) ) {
508 piece = piece->next;
509 if (piece == NULL) /* End of text. */
510 return(src->ascii_src.length);
511 ptr = piece->text;
512 }
513 }
514 }
515 if (!include) {
516 if ( type == XawstParagraph)
517 position = first_eol_position;
518 position -= inc;
519 }
520 break;
521 case XawstPositions:
522 position += count * inc;
523 break;
524 case XawstAll: /* handled in special code above */
525 default:
526 break;
527 }
528
529 if ( dir == XawsdLeft )
530 position++;
531
532 if (position >= src->ascii_src.length)
533 return(src->ascii_src.length);
534 if (position < 0)
535 return(0);
536
537 return(position);
538 }
539
540 /* Function Name: Search
541 * Description: Searchs the text source for the text block passed
542 * Arguments: w - the AsciiSource Widget.
543 * position - the position to start scanning.
544 * dir - direction to scan.
545 * text - the text block to search for.
546 * Returns: the position of the item found.
547 */
548
549 static XawTextPosition
Search(w,position,dir,text)550 Search(w, position, dir, text)
551 Widget w;
552 XawTextPosition position;
553 XawTextScanDirection dir;
554 XawTextBlock * text;
555 {
556 AsciiSrcObject src = (AsciiSrcObject) w;
557 int inc, count = 0;
558 char * ptr;
559 Piece * piece;
560 char * buf;
561 XawTextPosition first;
562
563 if ( dir == XawsdRight )
564 inc = 1;
565 else {
566 inc = -1;
567 if (position == 0)
568 return(XawTextSearchError); /* scanning left from 0??? */
569 position--;
570 }
571
572 buf = XtMalloc((unsigned)sizeof(unsigned char) * text->length);
573 strncpy(buf, (text->ptr + text->firstPos), text->length);
574 piece = FindPiece(src, position, &first);
575 ptr = (position - first) + piece->text;
576
577 /* CONSTCOND */
578 while (TRUE) {
579 if (*ptr == ((dir == XawsdRight) ? *(buf + count)
580 : *(buf + text->length - count - 1)) ) {
581 if (count == (text->length - 1))
582 break;
583 else
584 count++;
585 }
586 else {
587 if (count != 0) {
588 position -=inc * count;
589 ptr -= inc * count;
590 }
591 count = 0;
592 }
593
594 ptr += inc;
595 position += inc;
596
597 while ( ptr < piece->text ) {
598 piece = piece->prev;
599 if (piece == NULL) { /* Begining of text. */
600 XtFree(buf);
601 return(XawTextSearchError);
602 }
603 ptr = piece->text + piece->used - 1;
604 }
605
606 while ( ptr >= (piece->text + piece->used) ) {
607 piece = piece->next;
608 if (piece == NULL) { /* End of text. */
609 XtFree(buf);
610 return(XawTextSearchError);
611 }
612 ptr = piece->text;
613 }
614 }
615
616 XtFree(buf);
617 if (dir == XawsdLeft)
618 return(position);
619 return(position - (text->length - 1));
620 }
621
622 /* Function Name: SetValues
623 * Description: Sets the values for the AsciiSource.
624 * Arguments: current - current state of the widget.
625 * request - what was requested.
626 * new - what the widget will become.
627 * Returns: True if redisplay is needed.
628 */
629
630 /* ARGSUSED */
631 static Boolean
SetValues(current,request,new,args,num_args)632 SetValues(current, request, new, args, num_args)
633 Widget current, request, new;
634 ArgList args;
635 Cardinal * num_args;
636 {
637 AsciiSrcObject src = (AsciiSrcObject) new;
638 AsciiSrcObject old_src = (AsciiSrcObject) current;
639 Boolean total_reset = FALSE, string_set = FALSE;
640 FILE * file;
641 int i;
642
643 if ( old_src->ascii_src.use_string_in_place !=
644 src->ascii_src.use_string_in_place ) {
645 XtAppWarning( XtWidgetToApplicationContext(new),
646 "AsciiSrc: The XtNuseStringInPlace resource may not be changed.");
647 src->ascii_src.use_string_in_place =
648 old_src->ascii_src.use_string_in_place;
649 }
650
651 for (i = 0; i < *num_args ; i++ )
652 if (streq(args[i].name, XtNstring)) {
653 string_set = TRUE;
654 break;
655 }
656
657 if ( string_set || (old_src->ascii_src.type != src->ascii_src.type) ) {
658 RemoveOldStringOrFile(old_src, string_set); /* remove old info. */
659 file = InitStringOrFile(src, string_set); /* Init new info. */
660 LoadPieces(src, file, NULL); /* load new info into internal buffers. */
661 if (file != NULL) fclose(file);
662 XawTextSetSource( XtParent(new), new, 0); /* Tell text widget
663 what happened. */
664 total_reset = TRUE;
665 }
666
667 if ( old_src->ascii_src.ascii_length != src->ascii_src.ascii_length )
668 src->ascii_src.piece_size = src->ascii_src.ascii_length;
669
670 if ( !total_reset &&
671 (old_src->ascii_src.piece_size != src->ascii_src.piece_size) ) {
672 String string = StorePiecesInString(old_src);
673 FreeAllPieces(old_src);
674 LoadPieces(src, NULL, string);
675 XtFree(string);
676 }
677
678 return(FALSE);
679 }
680
681 /* Function Name: GetValuesHook
682 * Description: This is a get values hook routine that sets the
683 * values specific to the ascii source.
684 * Arguments: w - the AsciiSource Widget.
685 * args - the argument list.
686 * num_args - the number of args.
687 * Returns: none.
688 */
689
690 static void
GetValuesHook(w,args,num_args)691 GetValuesHook(w, args, num_args)
692 Widget w;
693 ArgList args;
694 Cardinal * num_args;
695 {
696 AsciiSrcObject src = (AsciiSrcObject) w;
697 int i;
698
699 if (src->ascii_src.type == XawAsciiString) {
700 for (i = 0; i < *num_args ; i++ )
701 if (streq(args[i].name, XtNstring)) {
702 if (src->ascii_src.use_string_in_place) {
703 *((char **) args[i].value) = src->ascii_src.first_piece->text;
704 }
705 else {
706 if (XawAsciiSave(w)) /* If save sucessful. */
707 *((char **) args[i].value) = src->ascii_src.string;
708 }
709 break;
710 }
711 }
712 }
713
714 /* Function Name: Destroy
715 * Description: Destroys an ascii source (frees all data)
716 * Arguments: src - the Ascii source Widget to free.
717 * Returns: none.
718 */
719
720 static void
Destroy(w)721 Destroy (w)
722 Widget w;
723 {
724 RemoveOldStringOrFile((AsciiSrcObject) w, True);
725 }
726
727 /************************************************************
728 *
729 * Public routines
730 *
731 ************************************************************/
732
733 /* Function Name: XawAsciiSourceFreeString
734 * Description: Frees the string returned by a get values call
735 * on the string when the source is of type string.
736 * Arguments: w - the AsciiSrc widget.
737 * Returns: none.
738 */
739
740 void
741 #if NeedFunctionPrototypes
XawAsciiSourceFreeString(Widget w)742 XawAsciiSourceFreeString(Widget w)
743 #else
744 XawAsciiSourceFreeString(w)
745 Widget w;
746 #endif
747 {
748 AsciiSrcObject src = (AsciiSrcObject) w;
749
750 /* If the src is really a multi, call the multi routine.*/
751
752 #ifdef XAW_INTERNATIONALIZATION
753 if ( XtIsSubclass( w, multiSrcObjectClass ) ) {
754 _XawMultiSourceFreeString( w );
755 return;
756 }
757 else
758 #endif
759 if ( !XtIsSubclass( w, asciiSrcObjectClass ) ) {
760 XtErrorMsg("bad argument", "asciiSource", "XawError",
761 #ifdef XAW_INTERNATIONALIZATION
762 "XawAsciiSourceFreeString's parameter must be an asciiSrc or multiSrc.",
763 #else
764 "XawAsciiSourceFreeString's parameter must be an asciiSrc.",
765 #endif
766 NULL, NULL);
767 }
768
769 if (src->ascii_src.allocated_string && src->ascii_src.type != XawAsciiFile) {
770 src->ascii_src.allocated_string = FALSE;
771 XtFree(src->ascii_src.string);
772 src->ascii_src.string = NULL;
773 }
774 }
775
776 /* Function Name: XawAsciiSave
777 * Description: Saves all the pieces into a file or string as required.
778 * Arguments: w - the asciiSrc Widget.
779 * Returns: TRUE if the save was successful.
780 */
781
782 Boolean
783 #if NeedFunctionPrototypes
XawAsciiSave(Widget w)784 XawAsciiSave(Widget w)
785 #else
786 XawAsciiSave(w)
787 Widget w;
788 #endif
789 {
790 AsciiSrcObject src = (AsciiSrcObject) w;
791
792 /* If the src is really a multi, call the multi save. */
793
794 #ifdef XAW_INTERNATIONALIZATION
795 if ( XtIsSubclass( w, multiSrcObjectClass ) )
796 return( _XawMultiSave( w ) );
797 else
798 #endif
799 if ( !XtIsSubclass( w, asciiSrcObjectClass ) ) {
800 XtErrorMsg("bad argument", "asciiSource", "XawError",
801 #ifdef XAW_INTERNATIONALIZATION
802 "XawAsciiSave's parameter must be an asciiSrc or multiSrc.",
803 #else
804 "XawAsciiSave's parameter must be an asciiSrc.",
805 #endif
806 NULL, NULL);
807 }
808
809 /*
810 * If using the string in place then there is no need to play games
811 * to get the internal info into a readable string.
812 */
813
814 if (src->ascii_src.use_string_in_place)
815 return(TRUE);
816
817 if (src->ascii_src.type == XawAsciiFile) {
818 char * string;
819
820 if (!src->ascii_src.changes) /* No changes to save. */
821 return(TRUE);
822
823 string = StorePiecesInString(src);
824
825 if (WriteToFile(string, src->ascii_src.string) == FALSE) {
826 XtFree(string);
827 return(FALSE);
828 }
829 XtFree(string);
830 }
831 else {
832 if (src->ascii_src.allocated_string == TRUE)
833 XtFree(src->ascii_src.string);
834 else
835 src->ascii_src.allocated_string = TRUE;
836
837 src->ascii_src.string = StorePiecesInString(src);
838 }
839 src->ascii_src.changes = FALSE;
840 return(TRUE);
841 }
842
843 /* Function Name: XawAsciiSaveAsFile
844 * Description: Save the current buffer as a file.
845 * Arguments: w - the AsciiSrc widget.
846 * name - name of the file to save this file into.
847 * Returns: True if the save was sucessful.
848 */
849
850 Boolean
851 #if NeedFunctionPrototypes
XawAsciiSaveAsFile(Widget w,_Xconst char * name)852 XawAsciiSaveAsFile(Widget w, _Xconst char* name)
853 #else
854 XawAsciiSaveAsFile(w, name)
855 Widget w;
856 String name;
857 #endif
858 {
859 AsciiSrcObject src = (AsciiSrcObject) w;
860 String string;
861 Boolean ret;
862
863 /* If the src is really a multi, call the multi save. - */
864
865 #ifdef XAW_INTERNATIONALIZATION
866 if ( XtIsSubclass( w, multiSrcObjectClass ) )
867 return( _XawMultiSaveAsFile( w, name ) );
868 else
869 #endif
870 if ( !XtIsSubclass( w, asciiSrcObjectClass ) ) {
871 XtErrorMsg("bad argument", "asciiSource", "XawError",
872 #ifdef XAW_INTERNATIONALIZATION
873 "XawAsciiSaveAsFile's 1st parameter must be an asciiSrc or multiSrc.",
874 #else
875 "XawAsciiSaveAsFile's 1st parameter must be an asciiSrc.",
876 #endif
877 NULL, NULL);
878 }
879
880 string = StorePiecesInString(src);
881
882 ret = WriteToFile(string, name);
883 XtFree(string);
884 return(ret);
885 }
886
887 /* Function Name: XawAsciiSourceChanged
888 * Description: Returns true if the source has changed since last saved.
889 * Arguments: w - the ascii source widget.
890 * Returns: a Boolean (see description).
891 */
892
893 Boolean
894 #if NeedFunctionPrototypes
XawAsciiSourceChanged(Widget w)895 XawAsciiSourceChanged(Widget w)
896 #else
897 XawAsciiSourceChanged(w)
898 Widget w;
899 #endif
900 {
901 #ifdef XAW_INTERNATIONALIZATION
902 if ( XtIsSubclass( w, multiSrcObjectClass ) )
903 return( ( (MultiSrcObject) w )->multi_src.changes );
904 #endif
905
906 if ( XtIsSubclass( w, asciiSrcObjectClass ) )
907 return( ( (AsciiSrcObject) w)->ascii_src.changes );
908
909 XtErrorMsg("bad argument", "asciiSource", "XawError",
910 #ifdef XAW_INTERNATIONALIZATION
911 "XawAsciiSourceChanged parameter must be an asciiSrc or multiSrc.",
912 #else
913 "XawAsciiSourceChanged parameter must be an asciiSrc.",
914 #endif
915 NULL, NULL);
916
917 return( True ); /* for gcc -Wall */
918 }
919
920 /************************************************************
921 *
922 * Private Functions.
923 *
924 ************************************************************/
925
926 static void
RemoveOldStringOrFile(src,checkString)927 RemoveOldStringOrFile(src, checkString)
928 AsciiSrcObject src;
929 Boolean checkString;
930 {
931 FreeAllPieces(src);
932
933 if (checkString && src->ascii_src.allocated_string) {
934 XtFree(src->ascii_src.string);
935 src->ascii_src.allocated_string = False;
936 src->ascii_src.string = NULL;
937 }
938 }
939
940 /* Function Name: WriteToFile
941 * Description: Write the string specified to the begining of the file
942 * specified.
943 * Arguments: string - string to write.
944 * name - the name of the file
945 * Returns: returns TRUE if sucessful, FALSE otherwise.
946 */
947
948 static Boolean
WriteToFile(string,name)949 WriteToFile(string, name)
950 String string, name;
951 {
952 int fd;
953
954 if ( ((fd = creat(name, 0666)) == -1 ) ||
955 (write(fd, string, sizeof(unsigned char) * strlen(string)) == -1) )
956 return(FALSE);
957
958 if ( close(fd) == -1 )
959 return(FALSE);
960
961 return(TRUE);
962 }
963
964 /* Function Name: StorePiecesInString
965 * Description: store the pieces in memory into a standard ascii string.
966 * Arguments: data - the ascii pointer data.
967 * Returns: none.
968 */
969
970 static String
StorePiecesInString(src)971 StorePiecesInString(src)
972 AsciiSrcObject src;
973 {
974 String string;
975 XawTextPosition first;
976 Piece * piece;
977
978 string = XtMalloc((unsigned) sizeof(unsigned char) *
979 src->ascii_src.length + 1);
980
981 for (first = 0, piece = src->ascii_src.first_piece ; piece != NULL;
982 first += piece->used, piece = piece->next)
983 strncpy(string + first, piece->text, piece->used);
984
985 string[src->ascii_src.length] = '\0'; /* NULL terminate this sucker. */
986
987 /*
988 * This will refill all pieces to capacity.
989 */
990
991 if (src->ascii_src.data_compression) {
992 FreeAllPieces(src);
993 LoadPieces(src, NULL, string);
994 }
995
996 return(string);
997 }
998
999 /* Function Name: InitStringOrFile.
1000 * Description: Initializes the string or file.
1001 * Arguments: src - the AsciiSource.
1002 * Returns: none - May exit though.
1003 */
1004
1005 static FILE *
InitStringOrFile(src,newString)1006 InitStringOrFile(src, newString)
1007 AsciiSrcObject src;
1008 Boolean newString;
1009 {
1010 char * open_mode = NULL;
1011 FILE * file;
1012 char fileName[TMPSIZ];
1013
1014 if (src->ascii_src.type == XawAsciiString) {
1015
1016 if (src->ascii_src.string == NULL)
1017 src->ascii_src.length = 0;
1018
1019 else if (! src->ascii_src.use_string_in_place) {
1020 src->ascii_src.string = XtNewString(src->ascii_src.string);
1021 src->ascii_src.allocated_string = True;
1022 src->ascii_src.length = strlen(src->ascii_src.string);
1023 }
1024
1025 if (src->ascii_src.use_string_in_place) {
1026 src->ascii_src.length = strlen(src->ascii_src.string);
1027 /* In case the length resource is incorrectly set */
1028 if (src->ascii_src.length > src->ascii_src.ascii_length)
1029 src->ascii_src.ascii_length = src->ascii_src.length;
1030
1031 if (src->ascii_src.ascii_length == MAGIC_VALUE)
1032 src->ascii_src.piece_size = src->ascii_src.length;
1033 else
1034 src->ascii_src.piece_size = src->ascii_src.ascii_length + 1;
1035 }
1036
1037 return(NULL);
1038 }
1039
1040 /*
1041 * type is XawAsciiFile.
1042 */
1043
1044 src->ascii_src.is_tempfile = FALSE;
1045
1046 switch (src->text_src.edit_mode) {
1047 case XawtextRead:
1048 if (src->ascii_src.string == NULL)
1049 XtErrorMsg("NoFile", "asciiSourceCreate", "XawError",
1050 "Creating a read only disk widget and no file specified.",
1051 NULL, 0);
1052 open_mode = "r";
1053 break;
1054 case XawtextAppend:
1055 case XawtextEdit:
1056 if (src->ascii_src.string == NULL) {
1057 src->ascii_src.string = fileName;
1058 (void) tmpnam(src->ascii_src.string);
1059 src->ascii_src.is_tempfile = TRUE;
1060 open_mode = "w";
1061 } else
1062 open_mode = "r+";
1063 break;
1064 default:
1065 XtErrorMsg("badMode", "asciiSourceCreate", "XawError",
1066 "Bad editMode for ascii source; must be Read, Append or Edit.",
1067 NULL, NULL);
1068 }
1069
1070 /* Allocate new memory for the temp filename, because it is held in
1071 * a stack variable, not static memory. This widget does not need
1072 * to keep the private state field is_tempfile -- it is only accessed
1073 * in this routine, and its former setting is unused.
1074 */
1075 if (newString || src->ascii_src.is_tempfile) {
1076 src->ascii_src.string = XtNewString(src->ascii_src.string);
1077 src->ascii_src.allocated_string = TRUE;
1078 }
1079
1080 if (!src->ascii_src.is_tempfile) {
1081 if ((file = fopen(src->ascii_src.string, open_mode)) != 0) {
1082 (void) fseek(file, (Off_t)0, 2);
1083 src->ascii_src.length = (XawTextPosition) ftell(file);
1084 return file;
1085 } else {
1086 String params[2];
1087 Cardinal num_params = 2;
1088
1089 params[0] = src->ascii_src.string;
1090 params[1] = strerror(errno);
1091 XtAppWarningMsg(XtWidgetToApplicationContext((Widget)src),
1092 "openError", "asciiSourceCreate", "XawWarning",
1093 "Cannot open file %s; %s", params, &num_params);
1094 }
1095 }
1096 src->ascii_src.length = 0;
1097 return((FILE *)NULL);
1098 }
1099
1100 static void
LoadPieces(src,file,string)1101 LoadPieces(src, file, string)
1102 AsciiSrcObject src;
1103 FILE * file;
1104 char * string;
1105 {
1106 char *local_str, *ptr;
1107 Piece * piece = NULL;
1108 XawTextPosition left;
1109
1110 if (string == NULL) {
1111 if (src->ascii_src.type == XawAsciiFile) {
1112 local_str = XtMalloc((unsigned) (src->ascii_src.length + 1)
1113 * sizeof(unsigned char));
1114 if (src->ascii_src.length != 0) {
1115 fseek(file, (Off_t)0, 0);
1116 src->ascii_src.length = fread(local_str, (Size_t)sizeof(unsigned char),
1117 (Size_t)src->ascii_src.length, file);
1118 if (src->ascii_src.length <= 0)
1119 XtErrorMsg("readError", "asciiSourceCreate", "XawError",
1120 "fread returned error.", NULL, NULL);
1121 }
1122 local_str[src->ascii_src.length] = '\0';
1123 }
1124 else
1125 local_str = src->ascii_src.string;
1126 }
1127 else
1128 local_str = string;
1129
1130 if (src->ascii_src.use_string_in_place) {
1131 piece = AllocNewPiece(src, piece);
1132 piece->used = Min(src->ascii_src.length, src->ascii_src.piece_size);
1133 piece->text = src->ascii_src.string;
1134 return;
1135 }
1136
1137 ptr = local_str;
1138 left = src->ascii_src.length;
1139
1140 do {
1141 piece = AllocNewPiece(src, piece);
1142
1143 piece->text = XtMalloc((unsigned)src->ascii_src.piece_size
1144 * sizeof(unsigned char));
1145 piece->used = Min(left, src->ascii_src.piece_size);
1146 if (piece->used != 0)
1147 strncpy(piece->text, ptr, piece->used);
1148
1149 left -= piece->used;
1150 ptr += piece->used;
1151 } while (left > 0);
1152
1153 if ( (src->ascii_src.type == XawAsciiFile) && (string == NULL) )
1154 XtFree(local_str);
1155 }
1156
1157 /* Function Name: AllocNewPiece
1158 * Description: Allocates a new piece of memory.
1159 * Arguments: src - The AsciiSrc Widget.
1160 * prev - the piece just before this one, or NULL.
1161 * Returns: the allocated piece.
1162 */
1163
1164 static Piece *
AllocNewPiece(src,prev)1165 AllocNewPiece(src, prev)
1166 AsciiSrcObject src;
1167 Piece * prev;
1168 {
1169 Piece * piece = XtNew(Piece);
1170
1171 if (prev == NULL) {
1172 src->ascii_src.first_piece = piece;
1173 piece->next = NULL;
1174 }
1175 else {
1176 if (prev->next != NULL)
1177 (prev->next)->prev = piece;
1178 piece->next = prev->next;
1179 prev->next = piece;
1180 }
1181
1182 piece->prev = prev;
1183
1184 return(piece);
1185 }
1186
1187 /* Function Name: FreeAllPieces
1188 * Description: Frees all the pieces
1189 * Arguments: src - The AsciiSrc Widget.
1190 * Returns: none.
1191 */
1192
1193 static void
FreeAllPieces(src)1194 FreeAllPieces(src)
1195 AsciiSrcObject src;
1196 {
1197 Piece * next, * first = src->ascii_src.first_piece;
1198
1199 if (first->prev != NULL)
1200 (void) printf("Xaw AsciiSrc Object: possible memory leak in FreeAllPieces().\n");
1201
1202 for ( ; first != NULL ; first = next ) {
1203 next = first->next;
1204 RemovePiece(src, first);
1205 }
1206 }
1207
1208 /* Function Name: RemovePiece
1209 * Description: Removes a piece from the list.
1210 * Arguments:
1211 * piece - the piece to remove.
1212 * Returns: none.
1213 */
1214
1215 static void
RemovePiece(src,piece)1216 RemovePiece(src, piece)
1217 AsciiSrcObject src;
1218 Piece * piece;
1219 {
1220 if (piece->prev == NULL)
1221 src->ascii_src.first_piece = piece->next;
1222 else
1223 (piece->prev)->next = piece->next;
1224
1225 if (piece->next != NULL)
1226 (piece->next)->prev = piece->prev;
1227
1228 if (!src->ascii_src.use_string_in_place)
1229 XtFree(piece->text);
1230
1231 XtFree((char *)piece);
1232 }
1233
1234 /* Function Name: FindPiece
1235 * Description: Finds the piece containing the position indicated.
1236 * Arguments: src - The AsciiSrc Widget.
1237 * position - the position that we are searching for.
1238 * RETURNED first - the position of the first character in this piece.
1239 * Returns: piece - the piece that contains this position.
1240 */
1241
1242 static Piece *
FindPiece(src,position,first)1243 FindPiece(src, position, first)
1244 AsciiSrcObject src;
1245 XawTextPosition position, *first;
1246 {
1247 Piece * old_piece = NULL, * piece = src->ascii_src.first_piece;
1248 XawTextPosition temp;
1249
1250 for ( temp = 0 ; piece != NULL ; temp += piece->used, piece = piece->next ) {
1251 *first = temp;
1252 old_piece = piece;
1253
1254 if ((temp + piece->used) > position)
1255 return(piece);
1256 }
1257 return(old_piece); /* if we run off the end the return the last piece */
1258 }
1259
1260 /* Function Name: MyStrncpy
1261 * Description: Just like string copy, but slower and will always
1262 * work on overlapping strings.
1263 * Arguments: (same as strncpy) - s1, s2 - strings to copy (2->1).
1264 * n - the number of chars to copy.
1265 * Returns: s1.
1266 */
1267
1268 static String
MyStrncpy(s1,s2,n)1269 MyStrncpy(s1, s2, n)
1270 char * s1, * s2;
1271 int n;
1272 {
1273 char buf[256];
1274 char* temp;
1275
1276 if (n == 0) return s1;
1277
1278 if (n < sizeof buf) temp = buf;
1279 else temp = XtMalloc((unsigned)sizeof(unsigned char) * n);
1280
1281 strncpy(temp, s2, n); /* Saber has a bug that causes it to generate*/
1282 strncpy(s1, temp, n); /* a bogus warning message here (CDP 6/32/89)*/
1283
1284 if (temp != buf) XtFree(temp);
1285 return s1;
1286 }
1287
1288 /* Function Name: BreakPiece
1289 * Description: Breaks a full piece into two new pieces.
1290 * Arguments: src - The AsciiSrc Widget.
1291 * piece - the piece to break.
1292 * Returns: none.
1293 */
1294
1295 #define HALF_PIECE (src->ascii_src.piece_size/2)
1296
1297 static void
BreakPiece(src,piece)1298 BreakPiece(src, piece)
1299 AsciiSrcObject src;
1300 Piece * piece;
1301 {
1302 Piece * new = AllocNewPiece(src, piece);
1303
1304 new->text = XtMalloc(src->ascii_src.piece_size * sizeof(unsigned char));
1305 strncpy(new->text, piece->text + HALF_PIECE,
1306 src->ascii_src.piece_size - HALF_PIECE);
1307 piece->used = HALF_PIECE;
1308 new->used = src->ascii_src.piece_size - HALF_PIECE;
1309 }
1310
1311 /* ARGSUSED */
1312 static void
CvtStringToAsciiType(args,num_args,fromVal,toVal)1313 CvtStringToAsciiType(args, num_args, fromVal, toVal)
1314 XrmValuePtr args; /* unused */
1315 Cardinal *num_args; /* unused */
1316 XrmValuePtr fromVal;
1317 XrmValuePtr toVal;
1318 {
1319 static XawAsciiType type;
1320 static XrmQuark XtQEstring = NULLQUARK;
1321 static XrmQuark XtQEfile;
1322 XrmQuark q;
1323 char lowerName[40];
1324
1325 if (XtQEstring == NULLQUARK) {
1326 XtQEstring = XrmPermStringToQuark(XtEstring);
1327 XtQEfile = XrmPermStringToQuark(XtEfile);
1328 }
1329
1330 if (strlen ((char*)fromVal->addr) < sizeof lowerName) {
1331 XmuCopyISOLatin1Lowered(lowerName, (char *) fromVal->addr);
1332 q = XrmStringToQuark(lowerName);
1333
1334 if (q == XtQEstring) type = XawAsciiString;
1335 else if (q == XtQEfile) type = XawAsciiFile;
1336 else {
1337 toVal->size = 0;
1338 toVal->addr = NULL;
1339 return;
1340 }
1341 toVal->size = sizeof type;
1342 toVal->addr = (XPointer) &type;
1343 return;
1344 }
1345 toVal->size = 0;
1346 toVal->addr = NULL;
1347 }
1348
1349 #if (defined(ASCII_STRING) || defined(ASCII_DISK))
1350 # include <X11/Xaw3d/Cardinals.h>
1351 #endif
1352
1353 #ifdef ASCII_STRING
1354 /************************************************************
1355 *
1356 * Compatability functions.
1357 *
1358 ************************************************************/
1359
1360 /* Function Name: AsciiStringSourceCreate
1361 * Description: Creates a string source.
1362 * Arguments: parent - the widget that will own this source.
1363 * args, num_args - the argument list.
1364 * Returns: a pointer to the new text source.
1365 */
1366
1367 Widget
XawStringSourceCreate(parent,args,num_args)1368 XawStringSourceCreate(parent, args, num_args)
1369 Widget parent;
1370 ArgList args;
1371 Cardinal num_args;
1372 {
1373 XawTextSource src;
1374 ArgList ascii_args;
1375 Arg temp[2];
1376
1377 XtSetArg(temp[0], XtNtype, XawAsciiString);
1378 XtSetArg(temp[1], XtNuseStringInPlace, TRUE);
1379 ascii_args = XtMergeArgLists(temp, TWO, args, num_args);
1380
1381 src = XtCreateWidget("genericAsciiString", asciiSrcObjectClass, parent,
1382 ascii_args, num_args + TWO);
1383 XtFree((char *)ascii_args);
1384 return(src);
1385 }
1386
1387 /*
1388 * This is hacked up to try to emulate old functionality, it
1389 * may not work, as I have not old code to test it on.
1390 *
1391 * Chris D. Peterson 8/31/89.
1392 */
1393
1394 void
XawTextSetLastPos(w,lastPos)1395 XawTextSetLastPos (w, lastPos)
1396 Widget w;
1397 XawTextPosition lastPos;
1398 {
1399 AsciiSrcObject src = (AsciiSrcObject) XawTextGetSource(w);
1400
1401 src->ascii_src.piece_size = lastPos;
1402 }
1403 #endif /* ASCII_STRING */
1404
1405 #ifdef ASCII_DISK
1406 /* Function Name: AsciiDiskSourceCreate
1407 * Description: Creates a disk source.
1408 * Arguments: parent - the widget that will own this source.
1409 * args, num_args - the argument list.
1410 * Returns: a pointer to the new text source.
1411 */
1412
1413 Widget
XawDiskSourceCreate(parent,args,num_args)1414 XawDiskSourceCreate(parent, args, num_args)
1415 Widget parent;
1416 ArgList args;
1417 Cardinal num_args;
1418 {
1419 XawTextSource src;
1420 ArgList ascii_args;
1421 Arg temp[1];
1422 int i;
1423
1424 XtSetArg(temp[0], XtNtype, XawAsciiFile);
1425 ascii_args = XtMergeArgLists(temp, ONE, args, num_args);
1426 num_args++;
1427
1428 for (i = 0; i < num_args; i++)
1429 if (streq(ascii_args[i].name, XtNfile) ||
1430 streq(ascii_args[i].name, XtCFile))
1431 ascii_args[i].name = XtNstring;
1432
1433 src = XtCreateWidget("genericAsciiDisk", asciiSrcObjectClass, parent,
1434 ascii_args, num_args);
1435 XtFree((char *)ascii_args);
1436 return(src);
1437 }
1438 #endif /* ASCII_DISK */
1439