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