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