AsciiSrc.c revision c889a3bf
1/* 2 3Copyright 1989, 1994, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25*/ 26 27/* 28 * AsciiSrc.c - AsciiSrc object. (For use with the text widget). 29 * 30 */ 31 32#ifdef HAVE_CONFIG_H 33#include <config.h> 34#endif 35#include <stdio.h> 36#include <stdlib.h> 37#include <ctype.h> 38#include <errno.h> 39#include <X11/IntrinsicP.h> 40#include <X11/StringDefs.h> 41#include <X11/Xos.h> 42#include <X11/Xfuncs.h> 43#include <X11/Xmu/CharSet.h> 44#include <X11/Xmu/Misc.h> 45#include <X11/Xaw/XawInit.h> 46#include <X11/Xaw/AsciiSrcP.h> 47#include <X11/Xaw/MultiSrcP.h> 48#ifndef OLDXAW 49#include <X11/Xaw/TextSinkP.h> 50#include <X11/Xaw/AsciiSinkP.h> 51#endif 52#include "Private.h" 53 54#include <sys/types.h> 55#include <sys/stat.h> 56#include <fcntl.h> 57 58#if (defined(ASCII_STRING) || defined(ASCII_DISK)) 59#include <X11/Xaw/AsciiText.h> /* for Widget Classes */ 60#endif 61 62#ifdef X_NOT_POSIX 63#define Off_t long 64#define Size_t unsigned int 65#else 66#define Off_t off_t 67#define Size_t size_t 68#endif 69 70#define MAGIC_VALUE ((XawTextPosition)-1) 71#define streq(a, b) (strcmp((a), (b)) == 0) 72 73/* 74 * Class Methods 75 */ 76static void XawAsciiSrcClassInitialize(void); 77static void XawAsciiSrcDestroy(Widget); 78static void XawAsciiSrcGetValuesHook(Widget, ArgList, Cardinal*); 79static void XawAsciiSrcInitialize(Widget, Widget, ArgList, Cardinal*); 80static Boolean XawAsciiSrcSetValues(Widget, Widget, Widget, 81 ArgList, Cardinal*); 82static XawTextPosition ReadText(Widget, XawTextPosition, XawTextBlock*, int); 83static int ReplaceText(Widget, XawTextPosition, XawTextPosition, 84 XawTextBlock*); 85static XawTextPosition Scan(Widget, XawTextPosition, XawTextScanType, 86 XawTextScanDirection, int, Bool); 87static XawTextPosition Search(Widget, XawTextPosition, XawTextScanDirection, 88 XawTextBlock*); 89 90/* 91 * Prototypes 92 */ 93static Piece *AllocNewPiece(AsciiSrcObject, Piece*); 94static void BreakPiece(AsciiSrcObject, Piece*); 95static Boolean CvtAsciiTypeToString(Display*, XrmValuePtr, Cardinal*, 96 XrmValuePtr, XrmValuePtr, XtPointer*); 97static void CvtStringToAsciiType(XrmValuePtr, Cardinal*, 98 XrmValuePtr, XrmValuePtr); 99static Piece *FindPiece(AsciiSrcObject, XawTextPosition, XawTextPosition*); 100static void FreeAllPieces(AsciiSrcObject); 101static FILE *InitStringOrFile(AsciiSrcObject, Bool); 102static void LoadPieces(AsciiSrcObject, FILE*, char*); 103static void RemoveOldStringOrFile(AsciiSrcObject, Bool); 104static void RemovePiece(AsciiSrcObject, Piece*); 105static String StorePiecesInString(AsciiSrcObject); 106static Bool WriteToFile(String, String, unsigned); 107static Bool WritePiecesToFile(AsciiSrcObject, String); 108static void GetDefaultPieceSize(Widget, int, XrmValue*); 109 110/* 111 * More Prototypes 112 */ 113#ifdef ASCII_DISK 114Widget XawAsciiDiskSourceCreate(Widget, ArgList, Cardinal); 115#endif 116#ifdef ASCII_STRING 117Widget XawStringSourceCreate(Widget, ArgList, Cardinal); 118void XawTextSetLastPos(Widget, XawTextPosition); 119#endif 120 121/* 122 * Initialization 123 */ 124#define offset(field) XtOffsetOf(AsciiSrcRec, ascii_src.field) 125static XtResource resources[] = { 126 { 127 XtNstring, 128 XtCString, 129 XtRString, 130 sizeof(char*), 131 offset(string), 132 XtRString, 133 NULL 134 }, 135 { 136 XtNtype, 137 XtCType, 138 XtRAsciiType, 139 sizeof(XawAsciiType), 140 offset(type), 141 XtRImmediate, 142 (XtPointer)XawAsciiString 143 }, 144 { 145 XtNdataCompression, 146 XtCDataCompression, 147 XtRBoolean, 148 sizeof(Boolean), 149 offset(data_compression), 150 XtRImmediate, 151 (XtPointer)True 152 }, 153 { 154 XtNpieceSize, 155 XtCPieceSize, 156 XtRInt, 157 sizeof(XawTextPosition), 158 offset(piece_size), 159 XtRCallProc, 160 (XtPointer)GetDefaultPieceSize 161 }, 162#ifdef OLDXAW 163 { 164 XtNcallback, 165 XtCCallback, 166 XtRCallback, 167 sizeof(XtPointer), 168 offset(callback), 169 XtRCallback, 170 (XtPointer)NULL 171 }, 172#endif 173 { 174 XtNuseStringInPlace, 175 XtCUseStringInPlace, 176 XtRBoolean, 177 sizeof(Boolean), 178 offset(use_string_in_place), 179 XtRImmediate, 180 (XtPointer)False 181 }, 182 { 183 XtNlength, 184 XtCLength, 185 XtRInt, 186 sizeof(int), 187 offset(ascii_length), 188 XtRImmediate, 189 (XtPointer)MAGIC_VALUE 190 }, 191#ifdef ASCII_DISK 192 { 193 XtNfile, 194 XtCFile, 195 XtRString, 196 sizeof(String), 197 offset(filename), 198 XtRString, 199 NULL 200 }, 201#endif /* ASCII_DISK */ 202}; 203#undef offset 204 205 206#define Superclass (&textSrcClassRec) 207AsciiSrcClassRec asciiSrcClassRec = { 208 /* object */ 209 { 210 (WidgetClass)Superclass, /* superclass */ 211 "AsciiSrc", /* class_name */ 212 sizeof(AsciiSrcRec), /* widget_size */ 213 XawAsciiSrcClassInitialize, /* class_initialize */ 214 NULL, /* class_part_initialize */ 215 False, /* class_inited */ 216 XawAsciiSrcInitialize, /* initialize */ 217 NULL, /* initialize_hook */ 218 NULL, /* realize */ 219 NULL, /* actions */ 220 0, /* num_actions */ 221 resources, /* resources */ 222 XtNumber(resources), /* num_resources */ 223 NULLQUARK, /* xrm_class */ 224 False, /* compress_motion */ 225 False, /* compress_exposure */ 226 False, /* compress_enterleave */ 227 False, /* visible_interest */ 228 XawAsciiSrcDestroy, /* destroy */ 229 NULL, /* resize */ 230 NULL, /* expose */ 231 XawAsciiSrcSetValues, /* set_values */ 232 NULL, /* set_values_hook */ 233 NULL, /* set_values_almost */ 234 XawAsciiSrcGetValuesHook, /* get_values_hook */ 235 NULL, /* accept_focus */ 236 XtVersion, /* version */ 237 NULL, /* callback_private */ 238 NULL, /* tm_table */ 239 NULL, /* query_geometry */ 240 NULL, /* display_accelerator */ 241 NULL, /* extension */ 242 }, 243 /* text_src */ 244 { 245 ReadText, /* Read */ 246 ReplaceText, /* Replace */ 247 Scan, /* Scan */ 248 Search, /* Search */ 249 XtInheritSetSelection, /* SetSelection */ 250 XtInheritConvertSelection, /* ConvertSelection */ 251 }, 252 /* ascii_src */ 253 { 254 NULL, /* extension */ 255 }, 256}; 257 258WidgetClass asciiSrcObjectClass = (WidgetClass)&asciiSrcClassRec; 259 260static XrmQuark Qstring, Qfile; 261 262/* 263 * Implementation 264 */ 265/* 266 * Function: 267 * XawAsciiSrcClassInitialize() 268 * 269 * Description: 270 * Initializes the asciiSrcObjectClass and install the converters for 271 * AsciiType <-> String. 272 */ 273static void 274XawAsciiSrcClassInitialize(void) 275{ 276 XawInitializeWidgetSet(); 277 Qstring = XrmPermStringToQuark(XtEstring); 278 Qfile = XrmPermStringToQuark(XtEfile); 279 XtAddConverter(XtRString, XtRAsciiType, CvtStringToAsciiType, NULL, 0); 280 XtSetTypeConverter(XtRAsciiType, XtRString, CvtAsciiTypeToString, 281 NULL, 0, XtCacheNone, NULL); 282} 283 284/* 285 * Function: 286 * XawAsciiSrcInitialize 287 * 288 * Parameters: 289 * request - widget requested by the argument list 290 * cnew - new widget with both resource and non resource values 291 * args - (unused) 292 * num_args - (unused) 293 * 294 * Description: 295 * Initializes the ascii src object. 296 */ 297/*ARGSUSED*/ 298static void 299XawAsciiSrcInitialize(Widget request, Widget cnew, 300 ArgList args, Cardinal *num_args) 301{ 302 AsciiSrcObject src = (AsciiSrcObject)cnew; 303 FILE *file; 304 305 /* 306 * Set correct flags (override resources) depending upon widget class 307 */ 308 src->text_src.text_format = XawFmt8Bit; 309 310#ifdef ASCII_DISK 311 if (XtIsSubclass(XtParent(cnew), asciiDiskWidgetClass)) { 312 src->ascii_src.type = XawAsciiFile; 313 src->ascii_src.string = src->ascii_src.filename; 314 } 315#endif 316 317#ifdef ASCII_STRING 318 if (XtIsSubclass(XtParent(cnew), asciiStringWidgetClass)) { 319 src->ascii_src.use_string_in_place = True; 320 src->ascii_src.type = XawAsciiString; 321 } 322#endif 323 324#ifdef OLDXAW 325 src->ascii_src.changes = False; 326#else 327 src->text_src.changed = False; 328#endif 329 src->ascii_src.allocated_string = False; 330 331 if (src->ascii_src.use_string_in_place && src->ascii_src.string == NULL) 332 src->ascii_src.use_string_in_place = False; 333 334 file = InitStringOrFile(src, src->ascii_src.type == XawAsciiFile); 335 LoadPieces(src, file, NULL); 336 337 if (file != NULL) 338 fclose(file); 339} 340 341/* 342 * Function: 343 * ReadText 344 * 345 * Parameters: 346 * w - AsciiSource widget 347 * pos - position of the text to retreive. 348 * text - text block that will contain returned text 349 * length - maximum number of characters to read 350 * 351 * Description: 352 * This function reads the source. 353 * 354 * Returns: 355 * The character position following the retrieved text. 356 */ 357static XawTextPosition 358ReadText(Widget w, XawTextPosition pos, XawTextBlock *text, int length) 359{ 360 AsciiSrcObject src = (AsciiSrcObject)w; 361 XawTextPosition count, start; 362 Piece *piece; 363#ifndef OLDXAW 364 XawTextAnchor *anchor; 365 XawTextEntity *entity; 366 XawTextPosition offset, end = pos + length; 367 Bool state; 368 369 end = XawMin(end, src->ascii_src.length); 370 while ((state = XawTextSourceAnchorAndEntity(w, pos, &anchor, &entity)) && 371 (entity->flags & XAW_TENTF_HIDE)) 372 pos = anchor->position + entity->offset + entity->length; 373 if (state == False || 374 !(entity->flags & XAW_TENTF_REPLACE)) { 375 while (entity) { 376 offset = anchor->position + entity->offset; 377 if (offset >= end) 378 break; 379 if (offset > pos && 380 (entity->flags & (XAW_TENTF_HIDE | XAW_TENTF_REPLACE))) { 381 end = XawMin(end, offset); 382 break; 383 } 384 if ((entity = entity->next) == NULL && 385 (anchor = XawTextSourceNextAnchor(w, anchor)) != NULL) 386 entity = anchor->entities; 387 } 388 } 389 else if (state && (entity->flags & XAW_TENTF_REPLACE) && pos < end) { 390 XawTextBlock *block = (XawTextBlock*)entity->data; 391 392 offset = anchor->position + entity->offset; 393 end = XawMin(end, offset + block->length); 394 if ((length = end - pos) < 0) 395 length = 0; 396 text->length = length; 397 text->format = XawFmt8Bit; 398 if (length == 0) { 399 text->firstPos = end = offset + entity->length; 400 text->ptr = ""; 401 } 402 else { 403 text->firstPos = pos; 404 text->ptr = block->ptr + (pos - offset); 405 if (pos + length < offset + block->length) 406 end = pos + length; /* there is data left to be read */ 407 else 408 end = offset + entity->length; 409 } 410 411 return (end); 412 } 413 414 if ((length = end - pos) < 0) 415 length = 0; 416#endif 417 418 piece = FindPiece(src, pos, &start); 419 text->firstPos = pos; 420 text->ptr = piece->text + (pos - start); 421 count = piece->used - (pos - start); 422 text->length = Max(0, (length > count) ? count : length); 423 text->format = XawFmt8Bit; 424 425 return (pos + text->length); 426} 427 428/* 429 * Function: 430 * ReplaceText 431 * 432 * Parameters: 433 * w - AsciiSource object 434 * startPos - ends of text that will be replaced 435 * endPos - "" 436 * text - new text to be inserted into buffer at startPos 437 * 438 * Description: 439 * Replaces a block of text with new text. 440 * 441 * Returns: 442 * XawEditDone on success, XawEditError otherwise 443 */ 444/*ARGSUSED*/ 445static int 446ReplaceText(Widget w, XawTextPosition startPos, XawTextPosition endPos, 447 XawTextBlock *text) 448{ 449 AsciiSrcObject src = (AsciiSrcObject)w; 450 Piece *start_piece, *end_piece, *temp_piece; 451 XawTextPosition start_first, end_first; 452 int length, firstPos; 453 454 /* 455 * Editing a read only source is not allowed 456 */ 457 if (src->text_src.edit_mode == XawtextRead) 458 return (XawEditError); 459 460 start_piece = FindPiece(src, startPos, &start_first); 461 end_piece = FindPiece(src, endPos, &end_first); 462 463#ifndef OLDXAW 464 /* 465 * This is a big hack, but I can't think about a clever way to know 466 * if the character being moved forward has a negative lbearing. 467 * 468 */ 469 if (start_piece->used) { 470 int i; 471 472 for (i = 0; i < src->text_src.num_text; i++) { 473 int line; 474 TextWidget ctx = (TextWidget)src->text_src.text[i]; 475 476 for (line = 0; line < ctx->text.lt.lines; line++) 477 if (startPos < ctx->text.lt.info[line + 1].position) 478 break; 479 if (i < ctx->text.lt.lines && 480 startPos > ctx->text.lt.info[i].position) { 481 AsciiSinkObject sink = (AsciiSinkObject)ctx->text.sink; 482 XawTextAnchor *anchor; 483 XawTextEntity *entity; 484 XawTextProperty *property; 485 XFontStruct *font; 486 487 if (XawTextSourceAnchorAndEntity(w, startPos, &anchor, &entity) && 488 (property = XawTextSinkGetProperty(ctx->text.sink, 489 entity->property)) != NULL && 490 (property->mask & XAW_TPROP_FONT)) 491 font = property->font; 492 else 493 font = sink->ascii_sink.font; 494 495 if (font->min_bounds.lbearing < 0) { 496 int lbearing = font->min_bounds.lbearing; 497 unsigned char c = *(unsigned char*) 498 (start_piece->text + (startPos - start_first)); 499 500 if (c == '\t' || c == '\n') 501 c = ' '; 502 else if ((c & 0177) < XawSP || c == 0177) { 503 if (sink->ascii_sink.display_nonprinting) 504 c = c > 0177 ? '\\' : c + '^'; 505 else 506 c = ' '; 507 } 508 if (font->per_char && 509 (c >= font->min_char_or_byte2 && c <= font->max_char_or_byte2)) 510 lbearing = font->per_char[c - font->min_char_or_byte2].lbearing; 511 if (lbearing < 0) 512 _XawTextNeedsUpdating(ctx, startPos - 1, startPos); 513 } 514 } 515 } 516 } 517 518 519#endif 520 521 /* 522 * Remove Old Stuff 523 */ 524 if (start_piece != end_piece) { 525 temp_piece = start_piece->next; 526 527 /* 528 * If empty and not the only piece then remove it. 529 */ 530 if (((start_piece->used = startPos - start_first) == 0) 531 && !(start_piece->next == NULL && start_piece->prev == NULL)) 532 RemovePiece(src, start_piece); 533 534 while (temp_piece != end_piece) { 535 temp_piece = temp_piece->next; 536 RemovePiece(src, temp_piece->prev); 537 } 538 539 end_piece->used -= endPos - end_first; 540 if (end_piece->used != 0) 541 memmove(end_piece->text, end_piece->text + endPos - end_first, 542 (unsigned)end_piece->used); 543 } 544 else { /* We are fully in one piece */ 545 if ((start_piece->used -= endPos - startPos) == 0) { 546 if (!(start_piece->next == NULL && start_piece->prev == NULL)) 547 RemovePiece(src, start_piece); 548 } 549 else { 550 memmove(start_piece->text + (startPos - start_first), 551 start_piece->text + (endPos - start_first), 552 (unsigned)(start_piece->used - (startPos - start_first))); 553 if (src->ascii_src.use_string_in_place 554 && src->ascii_src.length - (endPos - startPos) 555 < src->ascii_src.piece_size - 1) 556 start_piece->text[src->ascii_src.length - (endPos - startPos)] = 557 '\0'; 558 } 559 } 560 561 src->ascii_src.length += -(endPos - startPos) + text->length; 562 563 if ( text->length != 0) { 564 /* 565 * Put in the New Stuff 566 */ 567 start_piece = FindPiece(src, startPos, &start_first); 568 569 length = text->length; 570 firstPos = text->firstPos; 571 572 while (length > 0) { 573 char *ptr; 574 int fill; 575 576 if (src->ascii_src.use_string_in_place) { 577 if (start_piece->used == src->ascii_src.piece_size - 1) { 578 /* 579 * If we are in ascii string emulation mode. Then the 580 * string is not allowed to grow 581 */ 582 start_piece->used = src->ascii_src.length = 583 src->ascii_src.piece_size - 1; 584 start_piece->text[src->ascii_src.length] = '\0'; 585 return (XawEditError); 586 } 587 } 588 589 if (start_piece->used == src->ascii_src.piece_size) { 590 BreakPiece(src, start_piece); 591 start_piece = FindPiece(src, startPos, &start_first); 592 } 593 594 fill = Min((int)(src->ascii_src.piece_size - start_piece->used), 595 length); 596 597 ptr = start_piece->text + (startPos - start_first); 598 memmove(ptr + fill, ptr, 599 (unsigned)(start_piece->used - (startPos - start_first))); 600 memcpy(ptr, text->ptr + firstPos, (unsigned)fill); 601 602 startPos += fill; 603 firstPos += fill; 604 start_piece->used += fill; 605 length -= fill; 606 } 607 } 608 609 if (src->ascii_src.use_string_in_place) 610 start_piece->text[start_piece->used] = '\0'; 611 612#ifdef OLDXAW 613 src->ascii_src.changes = True; 614 XtCallCallbacks(w, XtNcallback, NULL); 615#endif 616 617 return (XawEditDone); 618} 619 620/* 621 * Function: 622 * Scan 623 * 624 * Parameters: 625 * w - AsciiSource object 626 * position - position to start scanning 627 * type - type of thing to scan for 628 * dir - direction to scan 629 * count - which occurance if this thing to search for. 630 * include - whether or not to include the character found in 631 * the position that is returned 632 * 633 * Description: 634 * Scans the text source for the number and type of item specified. 635 * 636 * Returns: 637 * The position of the item found 638 * 639 * Note: 640 * While there are only 'n' characters in the file there are n+1 641 * possible cursor positions (one before the first character and 642 * one after the last character 643 */ 644static XawTextPosition 645Scan(Widget w, register XawTextPosition position, XawTextScanType type, 646 XawTextScanDirection dir, int count, Bool include) 647{ 648 AsciiSrcObject src = (AsciiSrcObject)w; 649 Piece *piece; 650 XawTextPosition first, first_eol_position = 0; 651 register char *ptr, *lim; 652 register int cnt = count; 653 register unsigned char c; 654 655 if (dir == XawsdLeft) { 656 if (position <= 0) 657 return (0); 658 --position; 659 } 660 else if (position >= src->ascii_src.length) 661 return (src->ascii_src.length); 662 663 piece = FindPiece(src, position, &first); 664 if (piece->used == 0) 665 return (0); 666 667 ptr = (position - first) + piece->text; 668 669 if (dir == XawsdRight) { 670 lim = piece->text + piece->used; 671 switch (type) { 672 case XawstEOL: 673 case XawstParagraph: 674 case XawstWhiteSpace: 675 case XawstAlphaNumeric: 676 for (; cnt > 0; cnt--) { 677 Bool non_space = False, first_eol = True; 678 679 /*CONSTCOND*/ 680 while (True) { 681 if (ptr >= lim) { 682 piece = piece->next; 683 if (piece == NULL) /* End of text */ 684 return (src->ascii_src.length); 685 ptr = piece->text; 686 lim = piece->text + piece->used; 687 } 688 689 c = *ptr++; 690 ++position; 691 692 if (type == XawstEOL) { 693 if (c == '\n') 694 break; 695 } 696 else if (type == XawstAlphaNumeric) { 697 if (!isalnum(c)) { 698 if (non_space) 699 break; 700 } 701 else 702 non_space = True; 703 } 704 else if (type == XawstWhiteSpace) { 705 if (isspace(c)) { 706 if (non_space) 707 break; 708 } 709 else 710 non_space = True; 711 } 712 else { /* XawstParagraph */ 713 if (first_eol) { 714 if (c == '\n') { 715 first_eol_position = position; 716 first_eol = False; 717 } 718 } 719 else if (c == '\n') 720 break; 721 else if (!isspace(c)) 722 first_eol = True; 723 } 724 } 725 } 726 break; 727 case XawstPositions: 728 position += count; 729 return (position < src->ascii_src.length ? 730 position : src->ascii_src.length); 731 case XawstAll: 732 return (src->ascii_src.length); 733 default: 734 break; 735 } 736 if (!include) { 737 if (type == XawstParagraph) 738 position = first_eol_position; 739 if (count) 740 --position; 741 } 742 } 743 else { 744 lim = piece->text; 745 switch (type) { 746 case XawstEOL: 747 case XawstParagraph: 748 case XawstWhiteSpace: 749 case XawstAlphaNumeric: 750 for (; cnt > 0; cnt--) { 751 Bool non_space = False, first_eol = True; 752 753 /*CONSTCOND*/ 754 while (True) { 755 if (ptr < lim) { 756 piece = piece->prev; 757 if (piece == NULL) /* Begining of text */ 758 return (0); 759 ptr = piece->text + piece->used - 1; 760 lim = piece->text; 761 } 762 763 c = *ptr--; 764 --position; 765 766 if (type == XawstEOL) { 767 if (c == '\n') 768 break; 769 } 770 else if (type == XawstAlphaNumeric) { 771 if (!isalnum(c)) { 772 if (non_space) 773 break; 774 } 775 else 776 non_space = True; 777 } 778 else if (type == XawstWhiteSpace) { 779 if (isspace(c)) { 780 if (non_space) 781 break; 782 } 783 else 784 non_space = True; 785 } 786 else { /* XawstParagraph */ 787 if (first_eol) { 788 if (c == '\n') { 789 first_eol_position = position; 790 first_eol = False; 791 } 792 } 793 else if (c == '\n') 794 break; 795 else if (!isspace(c)) 796 first_eol = True; 797 } 798 } 799 } 800 break; 801 case XawstPositions: 802 position -= count - 1; 803 return (position > 0 ? position : 0); 804 case XawstAll: 805 return (0); 806 default: 807 break; 808 } 809 if (!include) { 810 if (type == XawstParagraph) 811 position = first_eol_position; 812 if (count) 813 ++position; 814 } 815 position++; 816 } 817 818 return (position); 819} 820 821/* 822 * Function: 823 * Search 824 * 825 * Parameters: 826 * w - AsciiSource object 827 * position - the position to start scanning 828 * dir - direction to scan 829 * text - text block to search for 830 * 831 * Description: 832 * Searchs the text source for the text block passed. 833 * 834 * Returns: 835 * The position of the item found 836 */ 837static XawTextPosition 838Search(Widget w, register XawTextPosition position, XawTextScanDirection dir, 839 XawTextBlock *text) 840{ 841 AsciiSrcObject src = (AsciiSrcObject)w; 842 register int count = 0; 843 register char *ptr, c; 844 char *str; 845 Piece *piece; 846 char *buf; 847 XawTextPosition first; 848 int cnt, case_sensitive; 849 850 if (dir == XawsdLeft) { 851 if (position == 0) 852 return (XawTextSearchError); 853 position--; 854 } 855 856 buf = XtMalloc((unsigned)sizeof(unsigned char) * text->length); 857 memcpy(buf, text->ptr, (unsigned)text->length); 858 piece = FindPiece(src, position, &first); 859 ptr = (position - first) + piece->text; 860 case_sensitive = text->firstPos; 861 862 if (dir == XawsdRight) { 863 str = buf; 864 c = *str; 865 /*CONSTCOND*/ 866 while (1) { 867 if (*ptr++ == c 868 || (case_sensitive && isalpha(c) && isalpha(ptr[-1]) 869 && toupper(c) == toupper(ptr[-1]))) { 870 if (++count == text->length) 871 break; 872 c = *++str; 873 } 874 else if (count) { 875 ptr -= count; 876 str -= count; 877 position -= count; 878 count = 0; 879 c = *str; 880 881 if (ptr < piece->text) { 882 do { 883 cnt = piece->text - ptr; 884 piece = piece->prev; 885 if (piece == NULL) { 886 XtFree(buf); 887 return (XawTextSearchError); 888 } 889 ptr = piece->text + piece->used - cnt; 890 } while (ptr < piece->text); 891 } 892 } 893 position++; 894 if (ptr >= (piece->text + piece->used)) { 895 do { 896 cnt = ptr - (piece->text + piece->used); 897 piece = piece->next; 898 if (piece == NULL) { 899 XtFree(buf); 900 return (XawTextSearchError); 901 } 902 ptr = piece->text + cnt; 903 } while (ptr >= (piece->text + piece->used)); 904 } 905 } 906 907 position -= text->length - 1; 908 } 909 else { 910 str = buf + text->length - 1; 911 c = *str; 912 /*CONSTCOND*/ 913 while (1) { 914 if (*ptr-- == c 915 || (case_sensitive && isalpha(c) && isalpha(ptr[1]) 916 && toupper(c) == toupper(ptr[1]))) { 917 if (++count == text->length) 918 break; 919 c = *--str; 920 } 921 else if (count) { 922 ptr += count; 923 str += count; 924 position += count; 925 count = 0; 926 c = *str; 927 928 if (ptr >= (piece->text + piece->used)) { 929 do { 930 cnt = ptr - (piece->text + piece->used); 931 piece = piece->next; 932 if (piece == NULL) { 933 XtFree(buf); 934 return (XawTextSearchError); 935 } 936 ptr = piece->text + cnt; 937 } while (ptr >= (piece->text + piece->used)); 938 } 939 } 940 position--; 941 if (ptr < piece->text) { 942 do { 943 cnt = piece->text - ptr; 944 piece = piece->prev; 945 if (piece == NULL) { 946 XtFree(buf); 947 return (XawTextSearchError); 948 } 949 ptr = piece->text + piece->used - cnt; 950 } while (ptr < piece->text); 951 } 952 } 953 } 954 955 XtFree(buf); 956 957 return (position); 958} 959 960/* 961 * Function: 962 * XawAsciiSrcSetValues 963 * 964 * Parameters: 965 * current - current state of the widget 966 * request - what was requested 967 * cnew - what the widget will become 968 * args - representation of changed resources 969 * num_args - number of resources that have changed 970 * 971 * Description: 972 * Sets the values for the AsciiSource. 973 * 974 * Returns: 975 * True if redisplay is needed 976 */ 977static Boolean 978XawAsciiSrcSetValues(Widget current, Widget request, Widget cnew, 979 ArgList args, Cardinal *num_args) 980{ 981 AsciiSrcObject src = (AsciiSrcObject)cnew; 982 AsciiSrcObject old_src = (AsciiSrcObject)current; 983 Bool total_reset = False, string_set = False; 984 FILE *file; 985 unsigned int i; 986 987 if (old_src->ascii_src.use_string_in_place 988 != src->ascii_src.use_string_in_place) { 989 XtAppWarning(XtWidgetToApplicationContext(cnew), 990 "AsciiSrc: The XtNuseStringInPlace resource may " 991 "not be changed."); 992 src->ascii_src.use_string_in_place = 993 old_src->ascii_src.use_string_in_place; 994 } 995 996 for (i = 0; i < *num_args ; i++) 997 if (streq(args[i].name, XtNstring)) { 998 string_set = True; 999 break; 1000 } 1001 1002 if (string_set || (old_src->ascii_src.type != src->ascii_src.type)) { 1003 RemoveOldStringOrFile(old_src, string_set); /* remove old info */ 1004 file = InitStringOrFile(src, string_set); /* Init new info */ 1005 LoadPieces(src, file, NULL); /* load new info into internal buffers */ 1006 if (file != NULL) 1007 fclose(file); 1008#ifndef OLDXAW 1009 for (i = 0; i < src->text_src.num_text; i++) 1010 /* Tell text widget what happened */ 1011 XawTextSetSource(src->text_src.text[i], cnew, 0); 1012#else 1013 XawTextSetSource(XtParent(cnew), cnew, 0); 1014#endif 1015 total_reset = True; 1016 } 1017 1018 if (old_src->ascii_src.ascii_length != src->ascii_src.ascii_length) 1019 src->ascii_src.piece_size = src->ascii_src.ascii_length + 1; 1020 1021 if (!total_reset && 1022 old_src->ascii_src.piece_size != src->ascii_src.piece_size) { 1023 String string = StorePiecesInString(old_src); 1024 1025 FreeAllPieces(old_src); 1026 LoadPieces(src, NULL, string); 1027 XtFree(string); 1028 } 1029 1030 return (False); 1031} 1032 1033/* 1034 * Function: 1035 * XawAsciiSrcGetValuesHook 1036 * 1037 * Parameters: 1038 * w - AsciiSource Widget 1039 * args - argument list 1040 * num_args - number of args 1041 * 1042 * Description: 1043 * This is a get values hook routine that sets the 1044 * values specific to the ascii source. 1045 */ 1046static void 1047XawAsciiSrcGetValuesHook(Widget w, ArgList args, Cardinal *num_args) 1048{ 1049 AsciiSrcObject src = (AsciiSrcObject)w; 1050 unsigned int i; 1051 1052 if (src->ascii_src.type == XawAsciiString) { 1053 for (i = 0; i < *num_args ; i++) 1054 if (streq(args[i].name, XtNstring)) { 1055 if (src->ascii_src.use_string_in_place) 1056 *((char **)args[i].value) = src->ascii_src.first_piece->text; 1057 else if (XawAsciiSave(w)) /* If save sucessful */ 1058 *((char **)args[i].value) = src->ascii_src.string; 1059 break; 1060 } 1061 } 1062 } 1063 1064/* 1065 * Function: 1066 * XawAsciiSrcDestroy 1067 * 1068 * Parameters: 1069 * src - Ascii source object to free 1070 * 1071 * Description: 1072 * Destroys an ascii source (frees all data) 1073 */ 1074static void 1075XawAsciiSrcDestroy(Widget w) 1076{ 1077 RemoveOldStringOrFile((AsciiSrcObject) w, True); 1078} 1079 1080/* 1081 * Public routines 1082 */ 1083/* 1084 * Function: 1085 * XawAsciiSourceFreeString 1086 * 1087 * Parameters: 1088 * w - AsciiSrc widget 1089 * 1090 * Description: 1091 * Frees the string returned by a get values call 1092 * on the string when the source is of type string. 1093 */ 1094void 1095XawAsciiSourceFreeString(Widget w) 1096{ 1097 AsciiSrcObject src = (AsciiSrcObject)w; 1098 1099 /* If the src is really a multi, call the multi routine */ 1100 if (XtIsSubclass(w, multiSrcObjectClass)) { 1101 _XawMultiSourceFreeString(w); 1102 return; 1103 } 1104 else if (!XtIsSubclass(w, asciiSrcObjectClass)) { 1105 XtErrorMsg("bad argument", "asciiSource", "XawError", 1106 "XawAsciiSourceFreeString's parameter must be " 1107 "an asciiSrc or multiSrc.", 1108 NULL, NULL); 1109 } 1110 1111 if (src->ascii_src.allocated_string && src->ascii_src.type != XawAsciiFile) { 1112 src->ascii_src.allocated_string = False; 1113 XtFree(src->ascii_src.string); 1114 src->ascii_src.string = NULL; 1115 } 1116} 1117 1118/* 1119 * Function: 1120 * XawAsciiSave 1121 * 1122 * Parameters: 1123 * w - asciiSrc Widget 1124 * 1125 * Description: 1126 * Saves all the pieces into a file or string as required. 1127 * 1128 * Returns: 1129 * True if the save was successful 1130 */ 1131Bool 1132XawAsciiSave(Widget w) 1133{ 1134 AsciiSrcObject src = (AsciiSrcObject)w; 1135 1136 /* If the src is really a multi, call the multi save */ 1137 if (XtIsSubclass(w, multiSrcObjectClass )) 1138 return (_XawMultiSave(w)); 1139 1140 else if (!XtIsSubclass(w, asciiSrcObjectClass)) 1141 XtErrorMsg("bad argument", "asciiSource", "XawError", 1142 "XawAsciiSave's parameter must be an asciiSrc or multiSrc.", 1143 NULL, NULL); 1144 1145 /* 1146 * If using the string in place then there is no need to play games 1147 * to get the internal info into a readable string. 1148 */ 1149 if (src->ascii_src.use_string_in_place) 1150 return (True); 1151 1152 if (src->ascii_src.type == XawAsciiFile) { 1153#ifdef OLDXAW 1154 if (!src->ascii_src.changes) 1155#else 1156 if (!src->text_src.changed) /* No changes to save */ 1157#endif 1158 return (True); 1159 1160 if (WritePiecesToFile(src, src->ascii_src.string) == False) 1161 return (False); 1162 } 1163 else { 1164 if (src->ascii_src.allocated_string == True) 1165 XtFree(src->ascii_src.string); 1166 else 1167 src->ascii_src.allocated_string = True; 1168 1169 src->ascii_src.string = StorePiecesInString(src); 1170 } 1171#ifdef OLDXAW 1172 src->ascii_src.changes = False; 1173#else 1174 src->text_src.changed = False; 1175#endif 1176 1177 return (True); 1178} 1179 1180/* 1181 * Function: 1182 * XawAsciiSaveAsFile 1183 * 1184 * Arguments: 1185 * w - AsciiSrc widget 1186 * name - name of the file to save this file into 1187 * 1188 * Description: 1189 * Save the current buffer as a file. 1190 * 1191 * Returns: 1192 * True if the save was sucessful 1193 */ 1194Bool 1195XawAsciiSaveAsFile(Widget w, _Xconst char *name) 1196{ 1197 AsciiSrcObject src = (AsciiSrcObject)w; 1198 Bool ret; 1199 1200 /* If the src is really a multi, call the multi save */ 1201 1202 if (XtIsSubclass( w, multiSrcObjectClass)) 1203 return (_XawMultiSaveAsFile(w, name)); 1204 1205 else if (!XtIsSubclass(w, asciiSrcObjectClass)) 1206 XtErrorMsg("bad argument", "asciiSource", "XawError", 1207 "XawAsciiSaveAsFile's 1st parameter must be an " 1208 "asciiSrc or multiSrc.", 1209 NULL, NULL); 1210 1211 if (src->ascii_src.type == XawAsciiFile) 1212 ret = WritePiecesToFile(src, (String)name); 1213 else { 1214 String string = StorePiecesInString(src); 1215 1216 ret = WriteToFile(string, (String)name, src->ascii_src.length); 1217 XtFree(string); 1218 } 1219 1220 return (ret); 1221} 1222 1223/* 1224 * Function: 1225 * XawAsciiSourceChanged 1226 * 1227 * Parameters: 1228 * w - ascii source widget 1229 * 1230 * Description: 1231 * Returns true if the source has changed since last saved. 1232 * 1233 * Returns: 1234 * A Boolean (see description). 1235 */ 1236Bool 1237XawAsciiSourceChanged(Widget w) 1238{ 1239#ifdef OLDXAW 1240 if (XtIsSubclass(w, multiSrcObjectClass)) 1241 return (((MultiSrcObject)w)->multi_src.changes); 1242 1243 if (XtIsSubclass(w, asciiSrcObjectClass)) 1244 return (((AsciiSrcObject)w)->ascii_src.changes); 1245#else 1246 if (XtIsSubclass(w, textSrcObjectClass)) 1247 return (((TextSrcObject)w)->textSrc.changed); 1248#endif 1249 XtErrorMsg("bad argument", "asciiSource", "XawError", 1250 "XawAsciiSourceChanged parameter must be an " 1251 "asciiSrc or multiSrc.", 1252 NULL, NULL); 1253 1254 return (True); 1255} 1256 1257/* 1258 * Private Functions 1259 */ 1260static void 1261RemoveOldStringOrFile(AsciiSrcObject src, Bool checkString) 1262{ 1263 FreeAllPieces(src); 1264 1265 if (checkString && src->ascii_src.allocated_string) { 1266 XtFree(src->ascii_src.string); 1267 src->ascii_src.allocated_string = False; 1268 src->ascii_src.string = NULL; 1269 } 1270} 1271 1272/* 1273 * Function: 1274 * WriteToFile 1275 * 1276 * Parameters: 1277 * string - string to write 1278 * name - the name of the file 1279 * 1280 * Description: 1281 * Write the string specified to the begining of the file specified. 1282 * 1283 * Returns: 1284 * returns True if sucessful, False otherwise 1285 */ 1286static Bool 1287WriteToFile(String string, String name, unsigned length) 1288{ 1289 int fd; 1290 1291 if ((fd = creat(name, 0666)) == -1) 1292 return (False); 1293 1294 if (write(fd, string, length) == -1) { 1295 close(fd); 1296 return (False); 1297 } 1298 1299 if (close(fd) == -1) 1300 return (False); 1301 1302 return (True); 1303} 1304 1305/* 1306 * Function: 1307 * WritePiecesToFile 1308 * 1309 * Parameters: 1310 * src - ascii source object 1311 * name - name of the file 1312 * 1313 * Description: 1314 * Almost identical to WriteToFile, but only works for ascii src objects 1315 * of type XawAsciiFile. This function avoids allocating temporary memory, 1316 * what can be useful when editing very large files. 1317 * 1318 * Returns: 1319 * returns True if sucessful, False otherwise 1320 */ 1321static Bool 1322WritePiecesToFile(AsciiSrcObject src, String name) 1323{ 1324 Piece *piece; 1325 int fd; 1326 1327 if (src->ascii_src.data_compression) { 1328 Piece *tmp; 1329 1330 piece = src->ascii_src.first_piece; 1331 while (piece) { 1332 int bytes = src->ascii_src.piece_size - piece->used; 1333 1334 if (bytes > 0 && (tmp = piece->next) != NULL) { 1335 bytes = XawMin(bytes, tmp->used); 1336 memcpy(piece->text + piece->used, tmp->text, bytes); 1337 memmove(tmp->text, tmp->text + bytes, tmp->used - bytes); 1338 piece->used += bytes; 1339 if ((tmp->used -= bytes) == 0) { 1340 RemovePiece(src, tmp); 1341 continue; 1342 } 1343 } 1344 piece = piece->next; 1345 } 1346 } 1347 1348 if ((fd = creat(name, 0666)) == -1) 1349 return (False); 1350 1351 for (piece = src->ascii_src.first_piece; piece; piece = piece->next) 1352 if (write(fd, piece->text, piece->used) == -1) { 1353 close(fd); 1354 return (False); 1355 } 1356 1357 if (close(fd) == -1) 1358 return (False); 1359 1360 return (True); 1361} 1362 1363/* 1364 * Function: 1365 * StorePiecesInString 1366 * 1367 * Parameters: 1368 * data - ascii pointer data 1369 * 1370 * Description: 1371 * Store the pieces in memory into a standard ascii string. 1372 */ 1373static String 1374StorePiecesInString(AsciiSrcObject src) 1375{ 1376 String string; 1377 XawTextPosition first; 1378 Piece *piece; 1379 1380 string = XtMalloc((unsigned)(src->ascii_src.length + 1)); 1381 1382 for (first = 0, piece = src->ascii_src.first_piece ; piece != NULL; 1383 first += piece->used, piece = piece->next) 1384 memcpy(string + first, piece->text, (unsigned)piece->used); 1385 1386 string[src->ascii_src.length] = '\0'; 1387 1388 /* 1389 * This will refill all pieces to capacity 1390 */ 1391 if (src->ascii_src.data_compression) { 1392 FreeAllPieces(src); 1393 LoadPieces(src, NULL, string); 1394 } 1395 1396 return (string); 1397} 1398 1399/* 1400 * Function: 1401 * InitStringOrFile 1402 * 1403 * Parameters: 1404 * src - AsciiSource 1405 * 1406 * Description: 1407 * Initializes the string or file. 1408 */ 1409static FILE * 1410InitStringOrFile(AsciiSrcObject src, Bool newString) 1411{ 1412 mode_t open_mode = 0; 1413 const char *fdopen_mode = NULL; 1414 int fd; 1415 FILE *file; 1416 1417 if (src->ascii_src.type == XawAsciiString) { 1418 if (src->ascii_src.string == NULL) 1419 src->ascii_src.length = 0; 1420 1421 else if (!src->ascii_src.use_string_in_place) { 1422 src->ascii_src.string = XtNewString(src->ascii_src.string); 1423 src->ascii_src.allocated_string = True; 1424 src->ascii_src.length = strlen(src->ascii_src.string); 1425 } 1426 1427 if (src->ascii_src.use_string_in_place) { 1428 if (src->ascii_src.string != NULL) 1429 src->ascii_src.length = strlen(src->ascii_src.string); 1430 /* In case the length resource is incorrectly set */ 1431 if (src->ascii_src.length > src->ascii_src.ascii_length) 1432 src->ascii_src.ascii_length = src->ascii_src.length; 1433 1434 if (src->ascii_src.ascii_length == MAGIC_VALUE) 1435 src->ascii_src.piece_size = src->ascii_src.length; 1436 else 1437 src->ascii_src.piece_size = src->ascii_src.ascii_length + 1; 1438 } 1439 1440 return (NULL); 1441 } 1442 1443 /* 1444 * type is XawAsciiFile 1445 */ 1446 src->ascii_src.is_tempfile = False; 1447 1448 switch (src->text_src.edit_mode) { 1449 case XawtextRead: 1450 if (src->ascii_src.string == NULL) 1451 XtErrorMsg("NoFile", "asciiSourceCreate", "XawError", 1452 "Creating a read only disk widget and no file specified.", 1453 NULL, NULL); 1454 open_mode = O_RDONLY; 1455 fdopen_mode = "r"; 1456 break; 1457 case XawtextAppend: 1458 case XawtextEdit: 1459 if (src->ascii_src.string == NULL) { 1460 src->ascii_src.string = "*ascii-src*"; 1461 src->ascii_src.is_tempfile = True; 1462 } 1463 else { 1464/* O_NOFOLLOW is a FreeBSD & Linux extension */ 1465#ifdef O_NOFOLLOW 1466 open_mode = O_RDWR | O_NOFOLLOW; 1467#else 1468 open_mode = O_RDWR; /* unsafe; subject to race conditions */ 1469#endif /* O_NOFOLLOW */ 1470 fdopen_mode = "r+"; 1471 } 1472 break; 1473 default: 1474 XtErrorMsg("badMode", "asciiSourceCreate", "XawError", 1475 "Bad editMode for ascii source; must be Read, " 1476 "Append or Edit.", 1477 NULL, NULL); 1478 } 1479 1480 /* If is_tempfile, allocate a private copy of the text 1481 * Unlikely to be changed, just to set allocated_string */ 1482 if (newString || src->ascii_src.is_tempfile) { 1483 src->ascii_src.string = XtNewString(src->ascii_src.string); 1484 src->ascii_src.allocated_string = True; 1485 } 1486 1487 if (!src->ascii_src.is_tempfile) { 1488 if ((fd = open(src->ascii_src.string, open_mode, 0666)) != -1) { 1489 if ((file = fdopen(fd, fdopen_mode))) { 1490 (void)fseek(file, 0, SEEK_END); 1491 src->ascii_src.length = (XawTextPosition)ftell(file); 1492 return (file); 1493 } 1494 else 1495 close(fd); 1496 } 1497 { 1498 String params[2]; 1499 Cardinal num_params = 2; 1500 1501 params[0] = src->ascii_src.string; 1502 params[1] = strerror(errno); 1503 XtAppWarningMsg(XtWidgetToApplicationContext((Widget)src), 1504 "openError", "asciiSourceCreate", "XawWarning", 1505 "Cannot open file %s; %s", params, &num_params); 1506 } 1507 } 1508 src->ascii_src.length = 0; 1509 return (NULL); 1510} 1511 1512static void 1513LoadPieces(AsciiSrcObject src, FILE *file, char *string) 1514{ 1515 char *ptr; 1516 Piece *piece = NULL; 1517 XawTextPosition left; 1518 1519 if (string == NULL) { 1520 if (src->ascii_src.type == XawAsciiFile) { 1521 if (src->ascii_src.length != 0) { 1522 int len; 1523 1524 left = 0; 1525 fseek(file, 0, 0); 1526 while (left < src->ascii_src.length) { 1527 ptr = XtMalloc((unsigned)src->ascii_src.piece_size); 1528 if ((len = fread(ptr, (Size_t)sizeof(unsigned char), 1529 (Size_t)src->ascii_src.piece_size, file)) < 0) 1530 XtErrorMsg("readError", "asciiSourceCreate", "XawError", 1531 "fread returned error.", NULL, NULL); 1532 piece = AllocNewPiece(src, piece); 1533 piece->text = ptr; 1534 piece->used = XawMin(len, src->ascii_src.piece_size); 1535 left += piece->used; 1536 } 1537 } 1538 else { 1539 piece = AllocNewPiece(src, NULL); 1540 piece->text = XtMalloc((unsigned)src->ascii_src.piece_size); 1541 piece->used = 0; 1542 } 1543 return; 1544 } 1545 else 1546 string = src->ascii_src.string; 1547 } 1548 1549 if (src->ascii_src.use_string_in_place) { 1550 piece = AllocNewPiece(src, piece); 1551 piece->used = XawMin(src->ascii_src.length, src->ascii_src.piece_size); 1552 piece->text = src->ascii_src.string; 1553 return; 1554 } 1555 1556 ptr = string; 1557 left = src->ascii_src.length; 1558 do { 1559 piece = AllocNewPiece(src, piece); 1560 1561 piece->text = XtMalloc((unsigned)src->ascii_src.piece_size); 1562 piece->used = XawMin(left, src->ascii_src.piece_size); 1563 if (piece->used != 0) 1564 memcpy(piece->text, ptr, (unsigned)piece->used); 1565 1566 left -= piece->used; 1567 ptr += piece->used; 1568 } while (left > 0); 1569} 1570 1571/* 1572 * Function: 1573 * AllocNewPiece 1574 * 1575 * Parameters: 1576 * src - AsciiSrc Widget 1577 * prev - piece just before this one, or NULL 1578 * 1579 * Description: 1580 * Allocates a new piece of memory. 1581 * 1582 * Returns: 1583 * The allocated piece 1584 */ 1585static Piece * 1586AllocNewPiece(AsciiSrcObject src, Piece *prev) 1587{ 1588 Piece *piece = XtNew(Piece); 1589 1590 if (prev == NULL) { 1591 src->ascii_src.first_piece = piece; 1592 piece->next = NULL; 1593 } 1594 else { 1595 if (prev->next != NULL) 1596 (prev->next)->prev = piece; 1597 piece->next = prev->next; 1598 prev->next = piece; 1599 } 1600 1601 piece->prev = prev; 1602 1603 return (piece); 1604} 1605 1606/* 1607 * Function: 1608 * FreeAllPieces 1609 * 1610 * Parameters: 1611 * src - AsciiSrc Widget 1612 * 1613 * Description: 1614 * Frees all the pieces. 1615 */ 1616static void 1617FreeAllPieces(AsciiSrcObject src) 1618{ 1619 Piece *next, * first = src->ascii_src.first_piece; 1620 1621#ifdef DEBUG 1622 if (first->prev != NULL) 1623 printf("Xaw AsciiSrc Object: possible memory leak in FreeAllPieces().\n"); 1624#endif 1625 1626 for (; first != NULL ; first = next) { 1627 next = first->next; 1628 RemovePiece(src, first); 1629 } 1630} 1631 1632/* 1633 * Function: 1634 * RemovePiece 1635 * 1636 * Parameters: 1637 * piece - piece to remove 1638 * 1639 * Description: 1640 * Removes a piece from the list. 1641 */ 1642static void 1643RemovePiece(AsciiSrcObject src, Piece *piece) 1644{ 1645 if (piece->prev == NULL) 1646 src->ascii_src.first_piece = piece->next; 1647 else 1648 piece->prev->next = piece->next; 1649 1650 if (piece->next != NULL) 1651 piece->next->prev = piece->prev; 1652 1653 if (!src->ascii_src.use_string_in_place) 1654 XtFree(piece->text); 1655 1656 XtFree((char *)piece); 1657} 1658 1659/* 1660 * Function: 1661 * FindPiece 1662 * 1663 * Parameters: 1664 * src - AsciiSrc Widget 1665 * position - position that we are searching for 1666 * first - position of the first character in this piece (return) 1667 * 1668 * Description: 1669 * Finds the piece containing the position indicated. 1670 * 1671 * Returns: 1672 * the piece that contains this position 1673 */ 1674static Piece * 1675FindPiece(AsciiSrcObject src, XawTextPosition position, XawTextPosition *first) 1676{ 1677 Piece *old_piece, *piece; 1678 XawTextPosition temp; 1679 1680 for (old_piece = NULL, piece = src->ascii_src.first_piece, temp = 0; 1681 piece; old_piece = piece, piece = piece->next) 1682 if ((temp += piece->used) > position) { 1683 *first = temp - piece->used; 1684 return (piece); 1685 } 1686 1687 *first = temp - (old_piece ? old_piece->used : 0); 1688 1689 return (old_piece); /* if we run off the end the return the last piece */ 1690} 1691 1692/* 1693 * Function: 1694 * BreakPiece 1695 * 1696 * Parameters: 1697 * src - AsciiSrc Widget 1698 * piece - piece to break 1699 * 1700 * Description: 1701 * Breaks a full piece into two new pieces. 1702 */ 1703#define HALF_PIECE (src->ascii_src.piece_size >> 1) 1704static void 1705BreakPiece(AsciiSrcObject src, Piece *piece) 1706{ 1707 Piece *cnew = AllocNewPiece(src, piece); 1708 1709 cnew->text = XtMalloc((unsigned)src->ascii_src.piece_size); 1710 memcpy(cnew->text, piece->text + HALF_PIECE, 1711 (unsigned)(src->ascii_src.piece_size - HALF_PIECE)); 1712 piece->used = HALF_PIECE; 1713 cnew->used = src->ascii_src.piece_size - HALF_PIECE; 1714} 1715 1716/*ARGSUSED*/ 1717static void 1718CvtStringToAsciiType(XrmValuePtr args, Cardinal *num_args, 1719 XrmValuePtr fromVal, XrmValuePtr toVal) 1720{ 1721 static XawAsciiType type; 1722 XrmQuark q; 1723 char name[7]; 1724 1725 XmuNCopyISOLatin1Lowered(name, (char *)fromVal->addr, sizeof(name)); 1726 q = XrmStringToQuark(name); 1727 1728 if (q == Qstring) 1729 type = XawAsciiString; 1730 else if (q == Qfile) 1731 type = XawAsciiFile; 1732 else { 1733 toVal->size = 0; 1734 toVal->addr = NULL; 1735 XtStringConversionWarning((char *)fromVal->addr, XtRAsciiType); 1736 } 1737 1738 toVal->size = sizeof(XawAsciiType); 1739 toVal->addr = (XPointer)&type; 1740} 1741 1742/*ARGSUSED*/ 1743static Boolean 1744CvtAsciiTypeToString(Display *dpy, XrmValuePtr args, Cardinal *num_args, 1745 XrmValuePtr fromVal, XrmValuePtr toVal, 1746 XtPointer *data) 1747{ 1748 static String buffer; 1749 Cardinal size; 1750 1751 switch (*(XawAsciiType *)fromVal->addr) { 1752 case XawAsciiFile: 1753 buffer = XtEfile; 1754 break; 1755 case XawAsciiString: 1756 buffer = XtEstring; 1757 break; 1758 default: 1759 XawTypeToStringWarning(dpy, XtRAsciiType); 1760 toVal->addr = NULL; 1761 toVal->size = 0; 1762 return (False); 1763 } 1764 1765 size = strlen(buffer) + 1; 1766 if (toVal->addr != NULL) { 1767 if (toVal->size < size) { 1768 toVal->size = size; 1769 return (False); 1770 } 1771 strcpy((char *)toVal->addr, buffer); 1772 } 1773 else 1774 toVal->addr = (XPointer)buffer; 1775 toVal->size = sizeof(String); 1776 1777 return (True); 1778} 1779 1780/*ARGSUSED*/ 1781static void 1782GetDefaultPieceSize(Widget w, int offset, XrmValue *value) 1783{ 1784 static XPointer pagesize; 1785 1786 if (pagesize == NULL) { 1787 pagesize = (XPointer)((long)_XawGetPageSize()); 1788 if (pagesize < (XPointer)BUFSIZ) 1789 pagesize = (XPointer)BUFSIZ; 1790 } 1791 1792 value->addr = (XPointer)&pagesize; 1793} 1794 1795#if (defined(ASCII_STRING) || defined(ASCII_DISK)) 1796# include <X11/Xaw/Cardinals.h> 1797#endif 1798 1799#ifdef ASCII_STRING 1800/* 1801 * Compatability functions. 1802 */ 1803/* 1804 * Function: 1805 * AsciiStringSourceCreate 1806 * 1807 * Parameters: 1808 * parent - widget that will own this source 1809 * args - the argument list 1810 * num_args - "" 1811 * 1812 * Description: 1813 * Creates a string source. 1814 * 1815 * Returns: 1816 * A pointer to the new text source. 1817 */ 1818Widget 1819XawStringSourceCreate(Widget parent, ArgList args, Cardinal num_args) 1820{ 1821 XawTextSource src; 1822 ArgList ascii_args; 1823 Arg temp[2]; 1824 1825 XtSetArg(temp[0], XtNtype, XawAsciiString); 1826 XtSetArg(temp[1], XtNuseStringInPlace, True); 1827 ascii_args = XtMergeArgLists(temp, TWO, args, num_args); 1828 1829 src = XtCreateWidget("genericAsciiString", asciiSrcObjectClass, parent, 1830 ascii_args, num_args + TWO); 1831 XtFree((char *)ascii_args); 1832 1833 return (src); 1834} 1835 1836/* 1837 * This is hacked up to try to emulate old functionality, it 1838 * may not work, as I have not old code to test it on. 1839 * 1840 * Chris D. Peterson 8/31/89. 1841 */ 1842void 1843XawTextSetLastPos(Widget w, XawTextPosition lastPos) 1844{ 1845 AsciiSrcObject src = (AsciiSrcObject)XawTextGetSource(w); 1846 1847 src->ascii_src.piece_size = lastPos; 1848} 1849#endif /* ASCII_STRING */ 1850 1851#ifdef ASCII_DISK 1852/* 1853 * Function: 1854 * AsciiDiskSourceCreate 1855 * 1856 * Parameters: 1857 * parent - widget that will own this source 1858 * args - argument list 1859 * num_args - "" 1860 * 1861 * Description: 1862 * Creates a disk source. 1863 * 1864 * Returns: 1865 * A pointer to the new text source 1866 */ 1867Widget 1868XawDiskSourceCreate(Widget parent, ArgList args, Cardinal num_args) 1869{ 1870 XawTextSource src; 1871 ArgList ascii_args; 1872 Arg temp[1]; 1873 int i; 1874 1875 XtSetArg(temp[0], XtNtype, XawAsciiFile); 1876 ascii_args = XtMergeArgLists(temp, ONE, args, num_args); 1877 num_args++; 1878 1879 for (i = 0; i < num_args; i++) 1880 if (streq(ascii_args[i].name, XtNfile) 1881 || streq(ascii_args[i].name, XtCFile)) 1882 ascii_args[i].name = XtNstring; 1883 1884 src = XtCreateWidget("genericAsciiDisk", asciiSrcObjectClass, parent, 1885 ascii_args, num_args); 1886 XtFree((char *)ascii_args); 1887 1888 return (src); 1889} 1890#endif /* ASCII_DISK */ 1891