1/* 2 * Copyright 1991 by OMRON Corporation 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name OMRON not be used in 9 * advertising or publicity pertaining to distribution of the software without 10 * specific, written prior permission. OMRON makes no representations 11 * about the suitability of this software for any purpose. It is provided 12 * "as is" without express or implied warranty. 13 * 14 * OMRON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL OMRON BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 * 22 * Authors: Chris Peterson MIT X Consortium 23 * Li Yuhong OMRON Corporation 24 * Frank Sheeran OMRON Corporation 25 * 26 * Much code taken from X11R3 String and Disk Sources. 27 */ 28 29/* 30 31Copyright 1991, 1994, 1998 The Open Group 32 33Permission to use, copy, modify, distribute, and sell this software and its 34documentation for any purpose is hereby granted without fee, provided that 35the above copyright notice appear in all copies and that both that 36copyright notice and this permission notice appear in supporting 37documentation. 38 39The above copyright notice and this permission notice shall be included in 40all copies or substantial portions of the Software. 41 42THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 43IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 44FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 45OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 46AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 47CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 48 49Except as contained in this notice, the name of The Open Group shall not be 50used in advertising or otherwise to promote the sale, use or other dealings 51in this Software without prior written authorization from The Open Group. 52 53*/ 54 55#ifdef HAVE_CONFIG_H 56#include <config.h> 57#endif 58#include <stdio.h> 59#include <stdlib.h> 60#include <ctype.h> 61#include <errno.h> 62#include <X11/IntrinsicP.h> 63#include <X11/StringDefs.h> 64#include <X11/Xfuncs.h> 65#include <X11/Xos.h> 66#include <X11/Xmu/CharSet.h> 67#include <X11/Xmu/Misc.h> 68#include <X11/Xaw/XawInit.h> 69#include <X11/Xaw/MultiSrcP.h> 70#include <X11/Xaw/XawImP.h> 71#include "XawI18n.h" 72#include "Private.h" 73 74#include <sys/types.h> 75#include <sys/stat.h> 76#include <fcntl.h> 77 78#ifndef O_CLOEXEC 79#define O_CLOEXEC 0 80#endif 81 82#define MAGIC_VALUE ((XawTextPosition)-1) 83#define streq(a, b) (strcmp((a), (b)) == 0) 84 85 86/* 87 * Class Methods 88 */ 89static XawTextPosition ReadText(Widget, XawTextPosition, XawTextBlock*, int); 90static int ReplaceText(Widget, XawTextPosition, XawTextPosition, 91 XawTextBlock*); 92static XawTextPosition Scan(Widget, XawTextPosition, XawTextScanType, 93 XawTextScanDirection, int, Bool); 94static XawTextPosition Search(Widget, XawTextPosition, XawTextScanDirection, 95 XawTextBlock*); 96static void XawMultiSrcClassInitialize(void); 97static void XawMultiSrcDestroy(Widget); 98static void XawMultiSrcInitialize(Widget, Widget, ArgList, Cardinal*); 99static Boolean XawMultiSrcSetValues(Widget, Widget, Widget, 100 ArgList, Cardinal*); 101static void XawMultiSrcGetValuesHook(Widget, ArgList, Cardinal*); 102 103/* 104 * Prototypes 105 */ 106static MultiPiece *AllocNewPiece(MultiSrcObject, MultiPiece*); 107static void BreakPiece(MultiSrcObject, MultiPiece*); 108static Boolean CvtMultiTypeToString(Display*, XrmValuePtr, Cardinal*, 109 XrmValuePtr, XrmValuePtr, XtPointer*); 110static void CvtStringToMultiType(XrmValuePtr, Cardinal*, 111 XrmValuePtr, XrmValuePtr); 112static MultiPiece *FindPiece(MultiSrcObject, XawTextPosition, 113 XawTextPosition*); 114static void FreeAllPieces(MultiSrcObject); 115static FILE *InitStringOrFile(MultiSrcObject, Bool); 116static void LoadPieces(MultiSrcObject, FILE*, char*); 117static void RemovePiece(MultiSrcObject, MultiPiece*); 118static void RemoveOldStringOrFile(MultiSrcObject, Bool); 119static char * StorePiecesInString(MultiSrcObject); 120static Bool WriteToFile(String, String); 121static void GetDefaultPieceSize(Widget, int, XrmValue*); 122 123/* 124 * Initialization 125 */ 126#define offset(field) XtOffsetOf(MultiSrcRec, multi_src.field) 127static XtResource resources[] = { 128 { 129 XtNstring, 130 XtCString, 131 XtRString, 132 sizeof(XtPointer), 133 offset(string), 134 XtRPointer, 135 NULL 136 }, 137 { 138 XtNtype, 139 XtCType, 140 XtRMultiType, 141 sizeof(XawAsciiType), 142 offset(type), 143 XtRImmediate, 144 (XtPointer)XawAsciiString 145 }, 146 { 147 XtNdataCompression, 148 XtCDataCompression, 149 XtRBoolean, 150 sizeof(Boolean), 151 offset(data_compression), 152 XtRImmediate, 153 (XtPointer)False 154 }, 155 { 156 XtNpieceSize, 157 XtCPieceSize, 158 XtRInt, 159 sizeof(XawTextPosition), 160 offset(piece_size), 161 XtRCallProc, 162 (XtPointer)GetDefaultPieceSize 163 }, 164#ifdef OLDXAW 165 { 166 XtNcallback, 167 XtCCallback, 168 XtRCallback, 169 sizeof(XtPointer), 170 offset(callback), 171 XtRCallback, 172 (XtPointer)NULL 173 }, 174#endif 175 { 176 XtNuseStringInPlace, 177 XtCUseStringInPlace, 178 XtRBoolean, 179 sizeof(Boolean), 180 offset(use_string_in_place), 181 XtRImmediate, 182 (XtPointer)False 183 }, 184 { 185 XtNlength, 186 XtCLength, 187 XtRInt, 188 sizeof(int), 189 offset(multi_length), 190 XtRImmediate, 191 (XtPointer)MAGIC_VALUE 192 }, 193}; 194#undef offset 195 196#define superclass (&textSrcClassRec) 197MultiSrcClassRec multiSrcClassRec = { 198 /* object */ 199 { 200 (WidgetClass)superclass, /* superclass */ 201 "MultiSrc", /* class_name */ 202 sizeof(MultiSrcRec), /* widget_size */ 203 XawMultiSrcClassInitialize, /* class_initialize */ 204 NULL, /* class_part_initialize */ 205 False, /* class_inited */ 206 XawMultiSrcInitialize, /* initialize */ 207 NULL, /* initialize_hook */ 208 NULL, /* obj1 */ 209 NULL, /* obj2 */ 210 0, /* obj3 */ 211 resources, /* resources */ 212 XtNumber(resources), /* num_resources */ 213 NULLQUARK, /* xrm_class */ 214 False, /* obj4 */ 215 False, /* obj5 */ 216 False, /* obj6 */ 217 False, /* obj7 */ 218 XawMultiSrcDestroy, /* destroy */ 219 NULL, /* obj8 */ 220 NULL, /* obj9 */ 221 XawMultiSrcSetValues, /* set_values */ 222 NULL, /* set_values_hook */ 223 NULL, /* obj10 */ 224 XawMultiSrcGetValuesHook, /* get_values_hook */ 225 NULL, /* obj11 */ 226 XtVersion, /* version */ 227 NULL, /* callback_private */ 228 NULL, /* obj12 */ 229 NULL, /* obj13 */ 230 NULL, /* obj14 */ 231 NULL, /* extension */ 232 }, 233 /* text_src */ 234 { 235 ReadText, /* Read */ 236 ReplaceText, /* Replace */ 237 Scan, /* Scan */ 238 Search, /* Search */ 239 XtInheritSetSelection, /* SetSelection */ 240 XtInheritConvertSelection, /* ConvertSelection */ 241#ifndef OLDXAW 242 NULL 243#endif 244 }, 245 /* multi_src */ 246 { 247 NULL, /* extension */ 248 }, 249}; 250 251WidgetClass multiSrcObjectClass = (WidgetClass)&multiSrcClassRec; 252 253static XrmQuark Qstring, Qfile; 254 255/* 256 * Implementation 257 */ 258static void 259XawMultiSrcClassInitialize(void) 260{ 261 XawInitializeWidgetSet(); 262 Qstring = XrmPermStringToQuark(XtEstring); 263 Qfile = XrmPermStringToQuark(XtEfile); 264 XtAddConverter(XtRString, XtRMultiType, CvtStringToMultiType, NULL, 0); 265 XtSetTypeConverter(XtRMultiType, XtRString, CvtMultiTypeToString, NULL, 0, 266 XtCacheNone, NULL); 267} 268 269/* 270 * Function: 271 * XawMultiSrcInitialize 272 * 273 * Parameters: 274 * request - widget requested by the argument list 275 * cnew - the new widget with both resource and non resource values 276 * args - (unused) 277 * num_args - (unused) 278 * 279 * Description: 280 * Initializes the multi src object 281 */ 282/*ARGSUSED*/ 283static void 284XawMultiSrcInitialize(Widget request _X_UNUSED, Widget cnew, 285 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 286{ 287 MultiSrcObject src = (MultiSrcObject)cnew; 288 FILE *file; 289 290 /* 291 * Set correct flags (override resources) depending upon widget class 292 */ 293#ifdef OLDXAW 294 src->multi_src.changes = False; 295#else 296 src->text_src.changed = False; 297#endif 298 src->multi_src.allocated_string = False; 299 300 if (src->multi_src.use_string_in_place && src->multi_src.string == NULL) 301 src->multi_src.use_string_in_place = False; 302 303 file = InitStringOrFile(src, src->multi_src.type == XawAsciiFile); 304 LoadPieces(src, file, NULL); 305 306 if (file != NULL) 307 fclose(file); 308 src->text_src.text_format = (XrmQuark)XawFmtWide; 309} 310 311/* 312 * Function: 313 * ReadText 314 * 315 * Parameters: 316 * w - MultiSource object 317 * pos - position of the text to retrieve 318 * text - text block that will contain returned text 319 * length - maximum number of characters to read 320 * 321 * Description: 322 * This function reads the source. 323 * 324 * Returns: 325 * The character position following the retrieved text. 326 */ 327static XawTextPosition 328ReadText(Widget w, XawTextPosition pos, XawTextBlock *text, int length) 329{ 330 MultiSrcObject src = (MultiSrcObject)w; 331 XawTextPosition count, start; 332 MultiPiece *piece = FindPiece(src, pos, &start); 333 334 text->format = XawFmtWide; 335 text->firstPos = (int)pos; 336 text->ptr = (char *)(piece->text + (pos - start)); 337 count = piece->used - (pos - start); 338 text->length = (int)(Max(0, (length > count) ? count : length)); 339 340 return (pos + text->length); 341} 342 343/* 344 * Function: 345 * ReplaceText 346 * 347 * Parameters: 348 * w - MultiSource object 349 * startPos - ends of text that will be removed 350 * endPos - "" 351 * text - new text to be inserted into buffer at startPos 352 * 353 * Description: 354 * Replaces a block of text with new text. 355 * 356 * Returns: 357 * XawEditDone on success, XawEditError otherwise 358 */ 359/*ARGSUSED*/ 360static int 361ReplaceText(Widget w, XawTextPosition startPos, XawTextPosition endPos, 362 XawTextBlock *u_text_p) 363{ 364 MultiSrcObject src = (MultiSrcObject)w; 365 MultiPiece *start_piece, *end_piece, *temp_piece; 366 XawTextPosition start_first, end_first; 367 int length, firstPos; 368 wchar_t *wptr; 369 Bool local_artificial_block = False; 370 XawTextBlock text; 371 372 /* STEP 1: The user handed me a text block called `u_text' that may be 373 * in either FMTWIDE or FMT8BIT (ie MB.) Later code needs the block 374 * `text' to hold FMTWIDE. So, this copies `u_text' to `text', and if 375 * `u_text' was MB, I knock it up to WIDE 376 */ 377 if (u_text_p->length == 0) /* if so, the block contents never ref'd */ 378 text.length = 0; 379 380 else if (u_text_p->format == XawFmtWide) { 381 local_artificial_block = False; /* don't have to free it ourselves */ 382 text.firstPos = u_text_p->firstPos; 383 text.length = u_text_p->length; 384 text.ptr = u_text_p->ptr; 385 } 386 else { 387 /* 388 * WARNING! u_text->firstPos and length are in units of CHAR, 389 * not CHARACTERS! 390 */ 391 local_artificial_block = True; /* have to free it ourselves */ 392 text.firstPos = 0; 393 text.length = u_text_p->length; /* _XawTextMBToWC converts this 394 * to wchar len 395 */ 396 397 text.ptr = (char*)_XawTextMBToWC(XtDisplay(XtParent(w)), 398 &u_text_p->ptr[u_text_p->firstPos], 399 &text.length); 400 401 /* I assert the following assignment is not needed - since Step 4 402 depends on length, it has no need of a terminating NULL. I think 403 the ASCII-version has the same needless NULL. */ 404 /*((wchar_t*)text.ptr)[ text.length ] = NULL;*/ 405 } 406 407 /* STEP 2: some initialization... */ 408 if (src->text_src.edit_mode == XawtextRead) 409 return (XawEditError); 410 411 if ((start_piece = FindPiece(src, startPos, &start_first)) == NULL) 412 return XawEditError; 413 if ((end_piece = FindPiece(src, endPos, &end_first)) == NULL) 414 return XawEditError; 415 416 /* STEP 3: remove the empty pieces... */ 417 if (start_piece != end_piece) { 418 if ((temp_piece = start_piece->next) == NULL) 419 return XawEditError; 420 421 /* If empty and not the only piece then remove it */ 422 if (((start_piece->used = startPos - start_first) == 0) 423 && !(start_piece->next == NULL && start_piece->prev == NULL)) 424 RemovePiece(src, start_piece); 425 426 while (temp_piece != end_piece) { 427 temp_piece = temp_piece->next; 428 RemovePiece(src, temp_piece->prev); 429 } 430 end_piece->used -= endPos - end_first; 431 if (end_piece->used != 0) 432 memmove(end_piece->text, end_piece->text + endPos - end_first, 433 (size_t)end_piece->used * sizeof(wchar_t)); 434 } 435 else { /* We are fully in one piece */ 436 if ((start_piece->used -= endPos - startPos) == 0) { 437 if (!(start_piece->next == NULL && start_piece->prev == NULL)) 438 RemovePiece(src, start_piece); 439 } 440 else { 441 memmove(start_piece->text + (startPos - start_first), 442 start_piece->text + (endPos - start_first), 443 (size_t)(start_piece->used - (startPos - start_first)) * 444 sizeof(wchar_t)); 445 if (src->multi_src.use_string_in_place && 446 ((src->multi_src.length - (endPos - startPos)) 447 < src->multi_src.piece_size - 1)) 448 start_piece->text[src->multi_src.length - (endPos - startPos)] = 449 (wchar_t)0; 450 } 451 } 452 453 src->multi_src.length += text.length -(endPos - startPos); 454 455 /* STEP 4: insert the new stuff */ 456 if ( text.length != 0) { 457 start_piece = FindPiece(src, startPos, &start_first); 458 length = text.length; 459 firstPos = text.firstPos; 460 461 while (length > 0) { 462 wchar_t *ptr; 463 int fill; 464 465 if (src->multi_src.use_string_in_place) { 466 if (start_piece->used == src->multi_src.piece_size - 1) { 467 468 /* 469 * The string is used in place, then the string 470 * is not allowed to grow 471 */ 472 start_piece->used = src->multi_src.length = 473 src->multi_src.piece_size - 1; 474 475 start_piece->text[src->multi_src.length] = (wchar_t)0; 476 return (XawEditError); 477 } 478 } 479 480 if (start_piece->used == src->multi_src.piece_size) { 481 BreakPiece(src, start_piece); 482 start_piece = FindPiece(src, startPos, &start_first); 483 } 484 485 fill = Min((int)(src->multi_src.piece_size - start_piece->used), length); 486 487 ptr = start_piece->text + (startPos - start_first); 488 memmove(ptr + fill, ptr, (size_t)(start_piece->used - 489 (startPos - start_first)) * sizeof(wchar_t)); 490 wptr =(wchar_t *)text.ptr; 491 (void)wcsncpy(ptr, wptr + firstPos, (size_t)fill); 492 493 startPos += fill; 494 firstPos += fill; 495 start_piece->used += fill; 496 length -= fill; 497 } 498 } 499 500 if (local_artificial_block == True) 501 /* In other words, text is not the u_text that the user handed me but 502 one I made myself. I only care, because I need to free the string */ 503 XtFree(text.ptr); 504 505 if (src->multi_src.use_string_in_place) 506 start_piece->text[start_piece->used] = (wchar_t)0; 507 508#ifdef OLDXAW 509 src->multi_src.changes = True; 510 XtCallCallbacks(w, XtNcallback, NULL); 511#endif 512 513 return (XawEditDone); 514} 515 516/* 517 * Function: 518 * Scan 519 * 520 * Parameters: 521 * w - MultiSource widget 522 * position - position to start scanning 523 * type - type of thing to scan for 524 * dir - direction to scan 525 * count - which occurrence of this thing to search for 526 * include - whether or not to include the character found in 527 * the position that is returned 528 * 529 * Description: 530 * Scans the text source for the number and type of item specified. 531 * 532 * Returns: 533 * The position of the item found 534 * 535 * Note: 536 * While there are only 'n' characters in the file there are n+1 537 * possible cursor positions (one before the first character and 538 * one after the last character 539 */ 540static XawTextPosition 541Scan(Widget w, register XawTextPosition position, XawTextScanType type, 542 XawTextScanDirection dir, int count, Bool include) 543{ 544 MultiSrcObject src = (MultiSrcObject)w; 545 register char inc; 546 MultiPiece *piece; 547 XawTextPosition first, first_eol_position = position; 548 register wchar_t *ptr; 549 int cnt = count; 550 551 if (type == XawstAll) { 552 if (dir == XawsdRight) 553 return (src->multi_src.length); 554 return (0); 555 } 556 557 /* STEP 1: basic sanity checks */ 558 if (position > src->multi_src.length) 559 position = src->multi_src.length; 560 561 if (dir == XawsdRight) { 562 if (position == src->multi_src.length) 563 return (src->multi_src.length); 564 inc = 1; 565 } 566 else { 567 if (position == 0) 568 return (0); 569 inc = -1; 570 position--; 571 } 572 573 piece = FindPiece(src, position, &first); 574 575 if (piece->used == 0) 576 return (0); 577 578 ptr = (position - first) + piece->text; 579 580 switch (type) { 581 case XawstEOL: 582 case XawstParagraph: 583 case XawstWhiteSpace: 584 case XawstAlphaNumeric: 585 for (; cnt > 0 ; cnt--) { 586 Bool non_space = False, first_eol = True; 587 588 /*CONSTCOND*/ 589 while (True) { 590 register wchar_t c; 591 592 if (ptr < piece->text) { 593 piece = piece->prev; 594 if (piece == NULL) /* Beginning of text */ 595 return (0); 596 ptr = piece->text + piece->used - 1; 597 } 598 else if (ptr >= piece->text + piece->used) { 599 piece = piece->next; 600 if (piece == NULL) /* End of text */ 601 return (src->multi_src.length); 602 ptr = piece->text; 603 } 604 605 c = *ptr; 606 ptr += inc; 607 position += inc; 608 609 if (type == XawstAlphaNumeric) { 610 if (!iswalnum((wint_t)c)) { 611 if (non_space) 612 break; 613 } 614 else 615 non_space = True; 616 } 617 else if (type == XawstWhiteSpace) { 618 if (iswspace(c)) { 619 if (non_space) 620 break; 621 } 622 else 623 non_space = True; 624 } 625 else if (type == XawstEOL) { 626 if (c == _Xaw_atowc(XawLF)) 627 break; 628 } 629 else { /* XawstParagraph */ 630 if (first_eol) { 631 if (c == _Xaw_atowc(XawLF)) { 632 first_eol_position = position; 633 first_eol = False; 634 } 635 } 636 else 637 if (c == _Xaw_atowc(XawLF)) 638 break; 639 else if (!iswspace(c)) 640 first_eol = True; 641 } 642 } 643 } 644 if (!include) { 645 if (type == XawstParagraph) 646 position = first_eol_position; 647 if (count) 648 position -= inc; 649 } 650 break; 651 case XawstPositions: 652 position += count * inc; 653 break; 654 default: 655 break; 656 } 657 658 if (dir == XawsdLeft) 659 position++; 660 661 if (position >= src->multi_src.length) 662 return (src->multi_src.length); 663 if (position < 0) 664 return (0); 665 666 return (position); 667} 668 669/* 670 * Function: 671 * Search 672 * 673 * Parameters: 674 * w - MultiSource objecy 675 * position - position to start scanning 676 * dir - direction to scan 677 * text - text block to search for 678 * 679 * Description: 680 * Searches the text source for the text block passed. 681 * 682 * Returns: 683 * The position of the item found 684 */ 685static XawTextPosition 686Search(Widget w, register XawTextPosition position, XawTextScanDirection dir, 687 XawTextBlock *text) 688{ 689 MultiSrcObject src = (MultiSrcObject)w; 690 register int count = 0; 691 wchar_t *ptr; 692 wchar_t *wtarget; 693 int wtarget_len; 694 Display *d = XtDisplay(XtParent(w)); 695 MultiPiece *piece; 696 wchar_t *buf; 697 XawTextPosition first; 698 register char inc; 699 int cnt; 700 701 /* STEP 1: First, a brief sanity check */ 702 if (dir == XawsdRight) 703 inc = 1; 704 else { 705 inc = -1; 706 if (position == 0) 707 return (XawTextSearchError); 708 position--; 709 } 710 711 /* STEP 2: Ensure I have a local wide string.. */ 712 713 /* Since this widget stores 32bit chars, I check here to see if 714 I'm being passed a string claiming to be 8bit chars (ie, MB text.) 715 If that is the case, naturally I convert to 32bit format */ 716 717 /*if the block was FMT8BIT, length will convert to REAL wchar count below */ 718 wtarget_len = text->length; 719 720 if (text->format == XawFmtWide) 721 wtarget = &(((wchar_t*)text->ptr) [text->firstPos]); 722 else { 723 /* The following converts wtarget_len from byte len to wchar count */ 724 wtarget = _XawTextMBToWC(d, &text->ptr[text->firstPos], &wtarget_len); 725 } 726 727 /* OK, I can now assert that wtarget holds wide characters, wtarget_len 728 holds an accurate count of those characters, and that firstPos has been 729 effectively factored out of the following computations */ 730 731 /* STEP 3: SEARCH! */ 732 buf = (wchar_t *)XtMalloc((Cardinal)(sizeof(wchar_t) * (size_t)wtarget_len)); 733 (void)wcsncpy(buf, wtarget, (size_t)wtarget_len); 734 piece = FindPiece(src, position, &first); 735 ptr = (position - first) + piece->text; 736 737 /*CONSTCOND*/ 738 while (True) { 739 if (*ptr == (dir == XawsdRight ? *(buf + count) 740 : *(buf + wtarget_len - count - 1))) { 741 if (count == text->length - 1) 742 break; 743 else 744 count++; 745 } 746 else { 747 if (count != 0) { 748 position -=inc * count; 749 ptr -= inc * count; 750 } 751 count = 0; 752 } 753 754 ptr += inc; 755 position += inc; 756 757 while (ptr < piece->text) { 758 cnt = (int)(piece->text - ptr); 759 760 piece = piece->prev; 761 if (piece == NULL) { /* Beginning of text */ 762 XtFree((char *)buf); 763 return (XawTextSearchError); 764 } 765 ptr = piece->text + piece->used - cnt; 766 } 767 768 while (ptr >= piece->text + piece->used) { 769 cnt = (int)(ptr - (piece->text + piece->used)); 770 771 piece = piece->next; 772 if (piece == NULL) { /* End of text */ 773 XtFree((char *)buf); 774 return (XawTextSearchError); 775 } 776 ptr = piece->text + cnt; 777 } 778 } 779 780 XtFree((char *)buf); 781 if (dir == XawsdLeft) 782 return(position); 783 784 return(position - (wtarget_len - 1)); 785} 786 787/* 788 * Function: 789 * XawMultiSrcSetValues 790 * 791 * Parameters: 792 * current - current state of the widget 793 * request - what was requested 794 * cnew - what the widget will become 795 * args - representation of resources that have changed 796 * num_args - number of changed resources 797 * 798 * Description: 799 * Sets the values for the MultiSource. 800 * 801 * Returns: 802 * True if redisplay is needed 803 */ 804static Boolean 805XawMultiSrcSetValues(Widget current, Widget request _X_UNUSED, Widget cnew, 806 ArgList args, Cardinal *num_args) 807{ 808 MultiSrcObject src = (MultiSrcObject)cnew; 809 MultiSrcObject old_src = (MultiSrcObject)current; 810 XtAppContext app_con = XtWidgetToApplicationContext(cnew); 811 Bool total_reset = False, string_set = False; 812 FILE *file; 813 unsigned int i; 814 815 if (old_src->multi_src.use_string_in_place 816 != src->multi_src.use_string_in_place) { 817 XtAppWarning(app_con, 818 "MultiSrc: The XtNuseStringInPlace resources " 819 "may not be changed."); 820 src->multi_src.use_string_in_place = 821 old_src->multi_src.use_string_in_place; 822 } 823 824 for (i = 0; i < *num_args ; i++) 825 if (streq(args[i].name, XtNstring)) { 826 string_set = True; 827 break; 828 } 829 830 if (string_set || old_src->multi_src.type != src->multi_src.type) { 831 RemoveOldStringOrFile(old_src, string_set); 832 src->multi_src.allocated_string = old_src->multi_src.allocated_string; 833 file = InitStringOrFile(src, string_set); 834 835 LoadPieces(src, file, NULL); 836 if (file != NULL) 837 fclose(file); 838#ifndef OLDXAW 839 for (i = 0; i < src->text_src.num_text; i++) 840 /* Tell text widget what happened */ 841 XawTextSetSource(src->text_src.text[i], cnew, 0); 842#else 843 XawTextSetSource(XtParent(cnew), cnew, 0); 844#endif 845 total_reset = True; 846 } 847 848 if (old_src->multi_src.multi_length != src->multi_src.multi_length) 849 src->multi_src.piece_size = src->multi_src.multi_length + 1; 850 851 if ( !total_reset && old_src->multi_src.piece_size 852 != src->multi_src.piece_size) { 853 char * mb_string = StorePiecesInString(old_src); 854 855 if (mb_string != 0) { 856 FreeAllPieces(old_src); 857 LoadPieces(src, NULL, mb_string); 858 XtFree(mb_string); 859 } 860 else { 861 /* If the buffer holds bad chars, don't touch it... */ 862 XtAppWarningMsg(app_con, 863 "convertError", "multiSource", "XawError", 864 XtName(XtParent((Widget)old_src)), NULL, NULL); 865 XtAppWarningMsg(app_con, 866 "convertError", "multiSource", "XawError", 867 "Non-character code(s) in buffer.", NULL, NULL); 868 } 869 } 870 871 return (False); 872} 873 874static void 875XawMultiSrcGetValuesHook(Widget w, ArgList args, Cardinal *num_args) 876{ 877 MultiSrcObject src = (MultiSrcObject)w; 878 Cardinal i; 879 880 if (src->multi_src.type == XawAsciiString) { 881 for (i = 0; i < *num_args ; i++) { 882 if (streq(args[i].name, XtNstring)) { 883 if (src->multi_src.use_string_in_place) 884 *((char **)args[i].value) = (char *) 885 src->multi_src.first_piece->text; 886 else if (_XawMultiSave(w)) /* If save successful */ 887 *((char **)args[i].value) = (char *)src->multi_src.string; 888 break; 889 } 890 } 891 } 892} 893 894static void 895XawMultiSrcDestroy(Widget w) 896{ 897 RemoveOldStringOrFile((MultiSrcObject) w, True); 898} 899 900/* 901 * Public routines 902 */ 903/* 904 * Function: 905 * XawMultiSourceFreeString 906 * 907 * Parameters: 908 * w - MultiSrc widget 909 * 910 * Description: 911 * Frees the string returned by a get values call 912 * on the string when the source is of type string. 913 * 914 * Note: 915 * The public interface is XawAsciiSourceFreeString! 916 */ 917void 918_XawMultiSourceFreeString(Widget w) 919{ 920 MultiSrcObject src = (MultiSrcObject)w; 921 922 if (src->multi_src.allocated_string) { 923 XtFree((char *)src->multi_src.string); 924 src->multi_src.allocated_string = False; 925 src->multi_src.string = NULL; 926 } 927} 928 929/* 930 * Function: 931 * _XawMultiSave 932 * 933 * Parameters: 934 * w - multiSrc Widget 935 * 936 * Description: 937 * Saves all the pieces into a file or string as required. 938 * 939 * Returns: 940 * True if the save was successful 941 * 942 * Note: 943 * The public interface is XawAsciiSave(w)! 944 */ 945Bool 946_XawMultiSave(Widget w) 947{ 948 MultiSrcObject src = (MultiSrcObject)w; 949 XtAppContext app_con = XtWidgetToApplicationContext(w); 950 char *mb_string; 951 952 /* 953 * If using the string in place then there is no need to play games 954 * to get the internal info into a readable string 955 */ 956 if (src->multi_src.use_string_in_place) 957 return (True); 958 959 if (src->multi_src.type == XawAsciiFile) { 960#ifdef OLDXAW 961 if (!src->multi_src.changes) 962#else 963 if (!src->text_src.changed) /* No changes to save */ 964#endif 965 return (True); 966 967 mb_string = StorePiecesInString(src); 968 969 if (mb_string != 0) { 970 if (WriteToFile(mb_string, (String)src->multi_src.string) == False) { 971 XtFree(mb_string); 972 return (False); 973 } 974 XtFree(mb_string); 975#ifndef OLDXAW 976 src->text_src.changed = False; 977#else 978 src->multi_src.changes = False; 979#endif 980 return (True); 981 } 982 else { 983 /* If the buffer holds bad chars, don't touch it... */ 984 XtAppWarningMsg(app_con, 985 "convertError", "multiSource", "XawError", 986 "Due to illegal characters, file not saved.", 987 NULL, NULL); 988 return (False); 989 } 990 } 991 else { 992 /* THIS FUNCTIONALITY IS UNDOCUMENTED, probably UNNEEDED? The manual 993 says this routine's only function is to save files to 994 disk. -Sheeran */ 995 mb_string = StorePiecesInString(src); 996 997 if (mb_string == 0) { 998 /* If the buffer holds bad chars, don't touch it... */ 999 XtAppWarningMsg(app_con, 1000 "convertError", "multiSource", "XawError", 1001 XtName(XtParent((Widget)src)), NULL, NULL); 1002 return (False); 1003 } 1004 1005 /* assert: mb_string holds good characters so the buffer is fine */ 1006 if (src->multi_src.allocated_string == True) 1007 XtFree((char *)src->multi_src.string); 1008 else 1009 src->multi_src.allocated_string = True; 1010 1011 src->multi_src.string = mb_string; 1012 } 1013#ifdef OLDXAW 1014 src->multi_src.changes = False; 1015#else 1016 src->text_src.changed = False; 1017#endif 1018 1019 return (True); 1020} 1021 1022/* 1023 * Function: 1024 * XawMultiSaveAsFile 1025 * 1026 * Parameters: 1027 * w - MultiSrc widget 1028 * name - name of the file to save this file into 1029 * 1030 * Description: 1031 * Save the current buffer as a file. 1032 * 1033 * Returns: 1034 * True if the save was successful 1035 * 1036 * Note: 1037 * The public interface is XawAsciiSaveAsFile! 1038 */ 1039Bool 1040_XawMultiSaveAsFile(Widget w, _Xconst char* name) 1041{ 1042 MultiSrcObject src = (MultiSrcObject)w; 1043 char *mb_string = StorePiecesInString(src); 1044 1045 if (mb_string != 0) { 1046 Bool ret = WriteToFile(mb_string, (String)name); 1047 XtFree(mb_string); 1048 1049 return (ret); 1050 } 1051 1052 /* otherwise there was a conversion error. So print widget name too */ 1053 XtAppWarningMsg(XtWidgetToApplicationContext(w), 1054 "convertError", "multiSource", "XawError", 1055 XtName(XtParent(w)), NULL, NULL); 1056 1057 return (False); 1058} 1059 1060/* 1061 * Private Functions 1062 */ 1063static void 1064RemoveOldStringOrFile(MultiSrcObject src, Bool checkString) 1065{ 1066 FreeAllPieces(src); 1067 1068 if (checkString && src->multi_src.allocated_string) { 1069 XtFree((char *)src->multi_src.string); 1070 src->multi_src.allocated_string = False; 1071 src->multi_src.string = NULL; 1072 } 1073} 1074 1075/* 1076 * Function: 1077 * WriteToFile 1078 * 1079 * Parameters: 1080 * string - string to write 1081 * name - name of the file 1082 * 1083 * Description: 1084 * Write the string specified to the beginning of the file specified. 1085 * 1086 * Returns: 1087 * Returns True if successful, False otherwise 1088 */ 1089static Bool 1090WriteToFile(String string, String name) 1091{ 1092 int fd; 1093 Bool result = True; 1094 1095 if ((fd = open(name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0666)) == -1) 1096 return (False); 1097 1098 if (write(fd, string, strlen(string)) == -1) 1099 result = False; 1100 1101 if (close(fd) == -1) 1102 return (False); 1103 1104 return (result); 1105} 1106 1107 1108/* 1109 * Function: 1110 * StorePiecesInString 1111 * 1112 * Parameters: 1113 * src - the multiSrc object to gather data from 1114 * 1115 * Description: 1116 * Store the pieces in memory into a char string. 1117 * 1118 * Returns: 1119 * mb_string: Caller must free 1120 * (or) 1121 * NULL: conversion error 1122 */ 1123static char * 1124StorePiecesInString(MultiSrcObject src) 1125{ 1126 wchar_t *wc_string; 1127 char *mb_string; 1128 int char_count = (int)src->multi_src.length; 1129 XawTextPosition first; 1130 MultiPiece *piece; 1131 1132 /* I believe the char_count + 1 and the NULL termination are unneeded! FS */ 1133 wc_string = (wchar_t*)XtMalloc((Cardinal)((size_t)(char_count + 1) * sizeof(wchar_t))); 1134 1135 for (first = 0, piece = src->multi_src.first_piece ; piece != NULL; 1136 first += piece->used, piece = piece->next) 1137 (void)wcsncpy(wc_string + first, piece->text, (size_t)piece->used); 1138 1139 wc_string[char_count] = 0; 1140 1141 /* This will refill all pieces to capacity */ 1142 if (src->multi_src.data_compression) { 1143 FreeAllPieces(src); 1144 LoadPieces(src, NULL, (char *)wc_string); 1145 } 1146 1147 /* Lastly, convert it to a MB format and send it back */ 1148 mb_string = _XawTextWCToMB(XtDisplayOfObject((Widget)src), 1149 wc_string, &char_count); 1150 1151 /* NOTE THAT mb_string MAY BE ZERO IF THE CONVERSION FAILED */ 1152 XtFree((char*)wc_string); 1153 1154 return (mb_string); 1155} 1156 1157/* 1158 * Function: 1159 * InitStringOrFile 1160 * 1161 * Parameters: 1162 * src - MultiSource 1163 * 1164 * Description: 1165 * Initializes the string or file. 1166 */ 1167static FILE * 1168InitStringOrFile(MultiSrcObject src, Bool newString) 1169{ 1170 mode_t open_mode = 0; 1171 const char *fdopen_mode = NULL; 1172 int fd; 1173 FILE *file; 1174 Display *d = XtDisplayOfObject((Widget)src); 1175 1176 if (src->multi_src.type == XawAsciiString) { 1177 if (src->multi_src.string == NULL) 1178 src->multi_src.length = 0; 1179 1180 else if (!src->multi_src.use_string_in_place) { 1181 int length; 1182 char * temp = XtNewString((char *)src->multi_src.string); 1183 1184 if (src->multi_src.allocated_string) 1185 XtFree((char *)src->multi_src.string); 1186 src->multi_src.allocated_string = True; 1187 src->multi_src.string = temp; 1188 1189 length = (int)strlen((char *)src->multi_src.string); 1190 1191 /* Wasteful, throwing away the WC string, but need side effect! */ 1192 (void)_XawTextMBToWC(d, (char *)src->multi_src.string, &length); 1193 src->multi_src.length = (XawTextPosition)length; 1194 } 1195 else { 1196 src->multi_src.length = (XawTextPosition)strlen((char *)src->multi_src.string); 1197 /* In case the length resource is incorrectly set */ 1198 if (src->multi_src.length > src->multi_src.multi_length) 1199 src->multi_src.multi_length = (int)src->multi_src.length; 1200 1201 if (src->multi_src.multi_length == MAGIC_VALUE) 1202 src->multi_src.piece_size = src->multi_src.length; 1203 else 1204 src->multi_src.piece_size = src->multi_src.multi_length + 1; 1205 } 1206 1207 return (NULL); 1208 } 1209 1210 /* 1211 * type is XawAsciiFile 1212 */ 1213 src->multi_src.is_tempfile = False; 1214 1215 switch (src->text_src.edit_mode) { 1216 case XawtextRead: 1217 if (src->multi_src.string == NULL) 1218 XtErrorMsg("NoFile", "multiSourceCreate", "XawError", 1219 "Creating a read only disk widget and no file specified.", 1220 NULL, 0); 1221 open_mode = O_RDONLY | O_CLOEXEC; 1222 fdopen_mode = "r"; 1223 break; 1224 case XawtextAppend: 1225 case XawtextEdit: 1226 if (src->multi_src.string == NULL) { 1227 src->multi_src.string = (char *)"*multi-src*"; 1228 src->multi_src.is_tempfile = True; 1229 } 1230 else { 1231/* O_NOFOLLOW was a FreeBSD & Linux extension, now adopted by POSIX */ 1232#ifdef O_NOFOLLOW 1233 open_mode = O_RDWR | O_NOFOLLOW | O_CLOEXEC; 1234#else 1235 open_mode = O_RDWR; /* unsafe; subject to race conditions */ 1236#endif 1237 fdopen_mode = "r+"; 1238 } 1239 break; 1240 default: 1241 XtErrorMsg("badMode", "multiSourceCreate", "XawError", 1242 "Bad editMode for multi source; must be " 1243 "Read, Append or Edit.", NULL, NULL); 1244 } 1245 1246 /* If is_tempfile, allocate a private copy of the text 1247 * Unlikely to be changed, just to set allocated_string */ 1248 if (newString || src->multi_src.is_tempfile) { 1249 char * temp = XtNewString((char *)src->multi_src.string); 1250 1251 if (src->multi_src.allocated_string) 1252 XtFree((char *)src->multi_src.string); 1253 src->multi_src.string = temp; 1254 src->multi_src.allocated_string = True; 1255 } 1256 1257 if (!src->multi_src.is_tempfile) { 1258 if ((fd = open((char *)src->multi_src.string, (int)open_mode, 0666)) != -1) { 1259 if ((file = fdopen(fd, fdopen_mode)) != NULL) { 1260 (void)fseek(file, 0, SEEK_END); 1261 src->multi_src.length = (XawTextPosition)ftell(file); 1262 return(file); 1263 } 1264 else 1265 close(fd); 1266 } 1267 { 1268 String params[2]; 1269 Cardinal num_params = 2; 1270 1271 params[0] = (String)src->multi_src.string; 1272 params[1] = strerror(errno); 1273 XtAppWarningMsg(XtWidgetToApplicationContext((Widget)src), 1274 "openError", "multiSourceCreate", "XawWarning", 1275 "Cannot open file %s; %s", params, &num_params); 1276 } 1277 } 1278 src->multi_src.length = 0; 1279 return (NULL); 1280} 1281 1282/* LoadPieces: This routine takes either the MB contents of open file 1283 `file' or the MB contents of string or the MB contents of 1284 src->multi_src.string and places them in Pieces in WC format. 1285 1286 CAUTION: You must have src->multi_src.length set to file length bytes 1287 when src->multi_src.type == XawAsciiFile. src->multi_src.length must be 1288 the length of the parameter string if string is non-NULL 1289*/ 1290static void 1291LoadPieces(MultiSrcObject src, FILE *file, char *string) 1292{ 1293 Display *d = XtDisplayOfObject((Widget)src); 1294 wchar_t* local_str, *ptr; 1295 MultiPiece* piece = NULL; 1296 XawTextPosition left; 1297 int bytes = sizeof(wchar_t); 1298 char* temp_mb_holder = NULL; 1299 1300 /* 1301 * This is tricky - the _XawTextMBtoWC converter uses its 3rd arg 1302 * in as MB length, out as WC length. We want local_length to be 1303 * WC count. 1304 */ 1305 int local_length = (int)src->multi_src.length; 1306 1307 if (string != NULL) { 1308 /* 1309 * ASSERT: IF our caller passed a non-null string, THEN 1310 * src->multi_src.length is currently string's * byte count, 1311 * AND string is in a MB format 1312 */ 1313 local_str = _XawTextMBToWC(d, (char *)string, &local_length); 1314 src->multi_src.length = (XawTextPosition) local_length; 1315 } 1316 else if (src->multi_src.type != XawAsciiFile) { 1317 /* 1318 * here, we are not changing the contents, just reloading, 1319 * so don't change len... 1320 */ 1321 local_length = (int)(src->multi_src.string ? 1322 strlen((char *)src->multi_src.string) : 0); 1323 local_str = _XawTextMBToWC(d, (char *)src->multi_src.string, 1324 &local_length); 1325 } 1326 else { 1327 if (src->multi_src.length != 0) { 1328 temp_mb_holder = 1329 XtMalloc((Cardinal)((size_t)(src->multi_src.length + 1) * sizeof(unsigned char))); 1330 fseek(file, 0, SEEK_SET); 1331 src->multi_src.length = (XawTextPosition)fread(temp_mb_holder, 1332 sizeof(unsigned char), 1333 (size_t)src->multi_src.length, file); 1334 if (src->multi_src.length <= 0) 1335 XtAppErrorMsg(XtWidgetToApplicationContext ((Widget) src), 1336 "readError", "multiSource", "XawError", 1337 "fread returned error.", NULL, NULL); 1338 local_length = (int)src->multi_src.length; 1339 local_str = _XawTextMBToWC(d, temp_mb_holder, &local_length); 1340 src->multi_src.length = local_length; 1341 1342 if (local_str == 0) { 1343 String params[2]; 1344 Cardinal num_params; 1345 static char err_text[] = 1346 "<<< FILE CONTENTS NOT REPRESENTABLE IN THIS LOCALE >>>"; 1347 1348 params[0] = XtName(XtParent((Widget)src)); 1349 params[1] = src->multi_src.string; 1350 num_params = 2; 1351 1352 XtAppWarningMsg(XtWidgetToApplicationContext((Widget)src), 1353 "readLocaleError", "multiSource", "XawError", 1354 "%s: The file `%s' contains characters " 1355 "not representable in this locale.", 1356 params, &num_params); 1357 src->multi_src.length = sizeof err_text; 1358 local_length = (int)src->multi_src.length; 1359 local_str = _XawTextMBToWC(d, err_text, &local_length); 1360 src->multi_src.length = local_length; 1361 } 1362 } 1363 else 1364 /* ASSERT that since following while loop looks at local_length 1365 this isn't needed. Sheeran, Omron KK, 1993/07/15 1366 temp_mb_holder[src->multi_src.length] = '\0'; */ 1367 local_str = (wchar_t*)temp_mb_holder; 1368 } 1369 1370 if (src->multi_src.use_string_in_place) { 1371 piece = AllocNewPiece(src, piece); 1372 piece->used = Min(src->multi_src.length, src->multi_src.piece_size); 1373 piece->text = (wchar_t*)src->multi_src.string; 1374 return; 1375 } 1376 1377 ptr = local_str; 1378 left = local_length; 1379 1380 do { 1381 piece = AllocNewPiece(src, piece); 1382 1383 piece->text = (wchar_t*)XtMalloc((unsigned)(src->multi_src.piece_size 1384 * bytes)); 1385 piece->used = Min(left, src->multi_src.piece_size); 1386 if (piece->used != 0) 1387 (void)wcsncpy(piece->text, ptr, (size_t)piece->used); 1388 1389 left -= piece->used; 1390 ptr += piece->used; 1391 } while (left > 0); 1392 1393 if (temp_mb_holder) 1394 XtFree((char*)temp_mb_holder); 1395} 1396 1397/* 1398 * Function: 1399 * AllocNewPiece 1400 * 1401 * Parameters: 1402 * src - MultiSrc Widget 1403 * prev - the piece just before this one, or NULL 1404 * 1405 * Description: 1406 * Allocates a new piece of memory. 1407 * 1408 * Returns: 1409 * The allocated piece 1410 */ 1411static MultiPiece * 1412AllocNewPiece(MultiSrcObject src, MultiPiece *prev) 1413{ 1414 MultiPiece *piece = XtNew(MultiPiece); 1415 1416 if (prev == NULL) { 1417 src->multi_src.first_piece = piece; 1418 piece->next = NULL; 1419 } 1420 else { 1421 if (prev->next != NULL) 1422 (prev->next)->prev = piece; 1423 piece->next = prev->next; 1424 prev->next = piece; 1425 } 1426 1427 piece->prev = prev; 1428 1429 return (piece); 1430} 1431 1432/* 1433 * Function: 1434 * FreeAllPieces 1435 * 1436 * Parameters: 1437 * src - MultiSrc Widget 1438 * 1439 * Description: 1440 * Frees all the pieces 1441 */ 1442static void 1443FreeAllPieces(MultiSrcObject src) 1444{ 1445 MultiPiece *next, *first = src->multi_src.first_piece; 1446 1447#ifdef DEBUG 1448 if (first->prev != NULL) 1449 printf("Xaw MultiSrc Object: possible memory leak in FreeAllPieces().\n"); 1450#endif 1451 1452 for (; first != NULL ; first = next) { 1453 next = first->next; 1454 RemovePiece(src, first); 1455 } 1456} 1457 1458/* 1459 * Function: 1460 * RemovePiece 1461 * 1462 * Parameters: 1463 * piece - piece to remove 1464 * 1465 * Description: 1466 * Removes a piece from the list. 1467 */ 1468static void 1469RemovePiece(MultiSrcObject src, MultiPiece *piece) 1470{ 1471 if (piece->prev == NULL) 1472 src->multi_src.first_piece = piece->next; 1473 else 1474 piece->prev->next = piece->next; 1475 1476 if (piece->next != NULL) 1477 piece->next->prev = piece->prev; 1478 1479 if (!src->multi_src.use_string_in_place) 1480 XtFree((char *)piece->text); 1481 1482 XtFree((char *)piece); 1483} 1484 1485/* 1486 * Function: 1487 * FindPiece 1488 * 1489 * Parameters: 1490 * src - MultiSrc Widget 1491 * position - position that we are searching for 1492 * first - position of the first character in this piece (return) 1493 * 1494 * Description: 1495 * Finds the piece containing the position indicated. 1496 * 1497 * Returns: 1498 * Piece that contains this position 1499 */ 1500static MultiPiece * 1501FindPiece(MultiSrcObject src, XawTextPosition position, XawTextPosition *first) 1502{ 1503 MultiPiece *old_piece, *piece; 1504 XawTextPosition temp; 1505 1506 for (old_piece = NULL, piece = src->multi_src.first_piece, temp = 0; 1507 piece; old_piece = piece, piece = piece->next) 1508 if ((temp += piece->used) > position) { 1509 *first = temp - piece->used; 1510 return (piece); 1511 } 1512 1513 *first = temp - (old_piece ? old_piece->used : 0); 1514 1515 return (old_piece); /* if we run off the end the return the last piece */ 1516} 1517 1518/* 1519 * Function: 1520 * BreakPiece 1521 * 1522 * Parameters: 1523 * src - MultiSrc Widget 1524 * piece - piece to break 1525 * 1526 * Description: 1527 * Breaks a full piece into two new pieces. 1528 */ 1529#define HALF_PIECE (src->multi_src.piece_size >> 1) 1530static void 1531BreakPiece(MultiSrcObject src, MultiPiece *piece) 1532{ 1533 MultiPiece *cnew = AllocNewPiece(src, piece); 1534 1535 cnew->text = (wchar_t *) 1536 XtMalloc((Cardinal)((size_t)src->multi_src.piece_size * sizeof(wchar_t))); 1537 (void)wcsncpy(cnew->text, piece->text + HALF_PIECE, 1538 (size_t)(src->multi_src.piece_size - HALF_PIECE)); 1539 piece->used = HALF_PIECE; 1540 cnew->used = src->multi_src.piece_size - HALF_PIECE; 1541} 1542 1543/*ARGSUSED*/ 1544static void 1545CvtStringToMultiType(XrmValuePtr args _X_UNUSED, Cardinal *num_args _X_UNUSED, 1546 XrmValuePtr fromVal, XrmValuePtr toVal) 1547{ 1548 static XawAsciiType type = XawAsciiString; 1549 XrmQuark q; 1550 char name[7]; 1551 1552 XmuNCopyISOLatin1Lowered(name, (char *)fromVal->addr, sizeof(name)); 1553 q = XrmStringToQuark(name); 1554 1555 if (q == Qstring) 1556 type = XawAsciiString; 1557 if (q == Qfile) 1558 type = XawAsciiFile; 1559 else { 1560 toVal->size = 0; 1561 toVal->addr = NULL; 1562 XtStringConversionWarning((char *)fromVal->addr, XtRAsciiType); 1563 } 1564 1565 toVal->size = sizeof(XawAsciiType); 1566 toVal->addr = (XPointer)&type; 1567} 1568 1569/*ARGSUSED*/ 1570static Boolean 1571CvtMultiTypeToString(Display *dpy, XrmValuePtr args _X_UNUSED, Cardinal *num_args _X_UNUSED, 1572 XrmValuePtr fromVal, XrmValuePtr toVal, 1573 XtPointer *data _X_UNUSED) 1574{ 1575 static String buffer; 1576 Cardinal size; 1577 1578 switch (*(XawAsciiType *)fromVal->addr) { 1579 case XawAsciiFile: 1580 buffer = XtEfile; 1581 break; 1582 case XawAsciiString: 1583 buffer = XtEstring; 1584 break; 1585 default: 1586 XawTypeToStringWarning(dpy, XtRAsciiType); 1587 toVal->addr = NULL; 1588 toVal->size = 0; 1589 return (False); 1590 } 1591 1592 size = (Cardinal)strlen(buffer) + 1; 1593 if (toVal->addr != NULL) { 1594 if (toVal->size < size) { 1595 toVal->size = size; 1596 return (False); 1597 } 1598 strcpy((char *)toVal->addr, buffer); 1599 } 1600 else 1601 toVal->addr = (XPointer)buffer; 1602 toVal->size = sizeof(String); 1603 1604 return (True); 1605} 1606 1607/*ARGSUSED*/ 1608static void 1609GetDefaultPieceSize(Widget w _X_UNUSED, int offset _X_UNUSED, XrmValue *value) 1610{ 1611 static XPointer pagesize; 1612 1613 if (pagesize == 0) { 1614 pagesize = (XPointer)((long)_XawGetPageSize()); 1615 if (pagesize < (XPointer)BUFSIZ) 1616 pagesize = (XPointer)BUFSIZ; 1617 } 1618 1619 value->addr = (XPointer)&pagesize; 1620} 1621