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