diff options
Diffstat (limited to 'libXaw/src/AsciiSrc.c')
-rw-r--r-- | libXaw/src/AsciiSrc.c | 1886 |
1 files changed, 1886 insertions, 0 deletions
diff --git a/libXaw/src/AsciiSrc.c b/libXaw/src/AsciiSrc.c new file mode 100644 index 000000000..eb569fc9f --- /dev/null +++ b/libXaw/src/AsciiSrc.c @@ -0,0 +1,1886 @@ +/* $Xorg: AsciiSrc.c,v 1.4 2001/02/09 02:03:42 xorgcvs Exp $ */ + +/* + +Copyright 1989, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +/* $XFree86: xc/lib/Xaw/AsciiSrc.c,v 1.33 2002/07/04 17:04:20 paulo Exp $ */ + +/* + * AsciiSrc.c - AsciiSrc object. (For use with the text widget). + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <X11/IntrinsicP.h> +#include <X11/StringDefs.h> +#include <X11/Xos.h> +#include <X11/Xfuncs.h> +#include <X11/Xmu/CharSet.h> +#include <X11/Xmu/Misc.h> +#include <X11/Xaw/XawInit.h> +#include <X11/Xaw/AsciiSrcP.h> +#include <X11/Xaw/MultiSrcP.h> +#ifndef OLDXAW +#include <X11/Xaw/TextSinkP.h> +#include <X11/Xaw/AsciiSinkP.h> +#endif +#include "Private.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#if (defined(ASCII_STRING) || defined(ASCII_DISK)) +#include <X11/Xaw/AsciiText.h> /* for Widget Classes */ +#endif + +#ifdef X_NOT_POSIX +#define Off_t long +#define Size_t unsigned int +#else +#define Off_t off_t +#define Size_t size_t +#endif + +#define MAGIC_VALUE ((XawTextPosition)-1) +#define streq(a, b) (strcmp((a), (b)) == 0) + +/* + * Class Methods + */ +static void XawAsciiSrcClassInitialize(void); +static void XawAsciiSrcDestroy(Widget); +static void XawAsciiSrcGetValuesHook(Widget, ArgList, Cardinal*); +static void XawAsciiSrcInitialize(Widget, Widget, ArgList, Cardinal*); +static Boolean XawAsciiSrcSetValues(Widget, Widget, Widget, + ArgList, Cardinal*); +static XawTextPosition ReadText(Widget, XawTextPosition, XawTextBlock*, int); +static int ReplaceText(Widget, XawTextPosition, XawTextPosition, + XawTextBlock*); +static XawTextPosition Scan(Widget, XawTextPosition, XawTextScanType, + XawTextScanDirection, int, Bool); +static XawTextPosition Search(Widget, XawTextPosition, XawTextScanDirection, + XawTextBlock*); + +/* + * Prototypes + */ +static Piece *AllocNewPiece(AsciiSrcObject, Piece*); +static void BreakPiece(AsciiSrcObject, Piece*); +static Boolean CvtAsciiTypeToString(Display*, XrmValuePtr, Cardinal*, + XrmValuePtr, XrmValuePtr, XtPointer*); +static void CvtStringToAsciiType(XrmValuePtr, Cardinal*, + XrmValuePtr, XrmValuePtr); +static Piece *FindPiece(AsciiSrcObject, XawTextPosition, XawTextPosition*); +static void FreeAllPieces(AsciiSrcObject); +static FILE *InitStringOrFile(AsciiSrcObject, Bool); +static void LoadPieces(AsciiSrcObject, FILE*, char*); +static void RemoveOldStringOrFile(AsciiSrcObject, Bool); +static void RemovePiece(AsciiSrcObject, Piece*); +static String StorePiecesInString(AsciiSrcObject); +static Bool WriteToFile(String, String, unsigned); +static Bool WritePiecesToFile(AsciiSrcObject, String); +static void GetDefaultPieceSize(Widget, int, XrmValue*); + +/* + * More Prototypes + */ +#ifdef ASCII_DISK +Widget XawAsciiDiskSourceCreate(Widget, ArgList, Cardinal); +#endif +#ifdef ASCII_STRING +Widget XawStringSourceCreate(Widget, ArgList, Cardinal); +void XawTextSetLastPos(Widget, XawTextPosition); +#endif + +/* + * Initialization + */ +#define offset(field) XtOffsetOf(AsciiSrcRec, ascii_src.field) +static XtResource resources[] = { + { + XtNstring, + XtCString, + XtRString, + sizeof(char*), + offset(string), + XtRString, + NULL + }, + { + XtNtype, + XtCType, + XtRAsciiType, + sizeof(XawAsciiType), + offset(type), + XtRImmediate, + (XtPointer)XawAsciiString + }, + { + XtNdataCompression, + XtCDataCompression, + XtRBoolean, + sizeof(Boolean), + offset(data_compression), + XtRImmediate, + (XtPointer)True + }, + { + XtNpieceSize, + XtCPieceSize, + XtRInt, + sizeof(XawTextPosition), + offset(piece_size), + XtRCallProc, + (XtPointer)GetDefaultPieceSize + }, +#ifdef OLDXAW + { + XtNcallback, + XtCCallback, + XtRCallback, + sizeof(XtPointer), + offset(callback), + XtRCallback, + (XtPointer)NULL + }, +#endif + { + XtNuseStringInPlace, + XtCUseStringInPlace, + XtRBoolean, + sizeof(Boolean), + offset(use_string_in_place), + XtRImmediate, + (XtPointer)False + }, + { + XtNlength, + XtCLength, + XtRInt, + sizeof(int), + offset(ascii_length), + XtRImmediate, + (XtPointer)MAGIC_VALUE + }, +#ifdef ASCII_DISK + { + XtNfile, + XtCFile, + XtRString, + sizeof(String), + offset(filename), + XtRString, + NULL + }, +#endif /* ASCII_DISK */ +}; +#undef offset + + +#define Superclass (&textSrcClassRec) +AsciiSrcClassRec asciiSrcClassRec = { + /* object */ + { + (WidgetClass)Superclass, /* superclass */ + "AsciiSrc", /* class_name */ + sizeof(AsciiSrcRec), /* widget_size */ + XawAsciiSrcClassInitialize, /* class_initialize */ + NULL, /* class_part_initialize */ + False, /* class_inited */ + XawAsciiSrcInitialize, /* initialize */ + NULL, /* initialize_hook */ + NULL, /* realize */ + NULL, /* actions */ + 0, /* num_actions */ + resources, /* resources */ + XtNumber(resources), /* num_resources */ + NULLQUARK, /* xrm_class */ + False, /* compress_motion */ + False, /* compress_exposure */ + False, /* compress_enterleave */ + False, /* visible_interest */ + XawAsciiSrcDestroy, /* destroy */ + NULL, /* resize */ + NULL, /* expose */ + XawAsciiSrcSetValues, /* set_values */ + NULL, /* set_values_hook */ + NULL, /* set_values_almost */ + XawAsciiSrcGetValuesHook, /* get_values_hook */ + NULL, /* accept_focus */ + XtVersion, /* version */ + NULL, /* callback_private */ + NULL, /* tm_table */ + NULL, /* query_geometry */ + NULL, /* display_accelerator */ + NULL, /* extension */ + }, + /* text_src */ + { + ReadText, /* Read */ + ReplaceText, /* Replace */ + Scan, /* Scan */ + Search, /* Search */ + XtInheritSetSelection, /* SetSelection */ + XtInheritConvertSelection, /* ConvertSelection */ + }, + /* ascii_src */ + { + NULL, /* extension */ + }, +}; + +WidgetClass asciiSrcObjectClass = (WidgetClass)&asciiSrcClassRec; + +static XrmQuark Qstring, Qfile; + +/* + * Implementation + */ +/* + * Function: + * XawAsciiSrcClassInitialize() + * + * Description: + * Initializes the asciiSrcObjectClass and install the converters for + * AsciiType <-> String. + */ +static void +XawAsciiSrcClassInitialize(void) +{ + XawInitializeWidgetSet(); + Qstring = XrmPermStringToQuark(XtEstring); + Qfile = XrmPermStringToQuark(XtEfile); + XtAddConverter(XtRString, XtRAsciiType, CvtStringToAsciiType, NULL, 0); + XtSetTypeConverter(XtRAsciiType, XtRString, CvtAsciiTypeToString, + NULL, 0, XtCacheNone, NULL); +} + +/* + * Function: + * XawAsciiSrcInitialize + * + * Parameters: + * request - widget requested by the argument list + * cnew - new widget with both resource and non resource values + * args - (unused) + * num_args - (unused) + * + * Description: + * Initializes the ascii src object. + */ +/*ARGSUSED*/ +static void +XawAsciiSrcInitialize(Widget request, Widget cnew, + ArgList args, Cardinal *num_args) +{ + AsciiSrcObject src = (AsciiSrcObject)cnew; + FILE *file; + + /* + * Set correct flags (override resources) depending upon widget class + */ + src->text_src.text_format = XawFmt8Bit; + +#ifdef ASCII_DISK + if (XtIsSubclass(XtParent(cnew), asciiDiskWidgetClass)) { + src->ascii_src.type = XawAsciiFile; + src->ascii_src.string = src->ascii_src.filename; + } +#endif + +#ifdef ASCII_STRING + if (XtIsSubclass(XtParent(cnew), asciiStringWidgetClass)) { + src->ascii_src.use_string_in_place = True; + src->ascii_src.type = XawAsciiString; + } +#endif + +#ifdef OLDXAW + src->ascii_src.changes = False; +#else + src->text_src.changed = False; +#endif + src->ascii_src.allocated_string = False; + + if (src->ascii_src.use_string_in_place && src->ascii_src.string == NULL) + src->ascii_src.use_string_in_place = False; + + file = InitStringOrFile(src, src->ascii_src.type == XawAsciiFile); + LoadPieces(src, file, NULL); + + if (file != NULL) + fclose(file); +} + +/* + * Function: + * ReadText + * + * Parameters: + * w - AsciiSource widget + * pos - position of the text to retreive. + * text - text block that will contain returned text + * length - maximum number of characters to read + * + * Description: + * This function reads the source. + * + * Returns: + * The character position following the retrieved text. + */ +static XawTextPosition +ReadText(Widget w, XawTextPosition pos, XawTextBlock *text, int length) +{ + AsciiSrcObject src = (AsciiSrcObject)w; + XawTextPosition count, start; + Piece *piece; +#ifndef OLDXAW + XawTextAnchor *anchor; + XawTextEntity *entity; + XawTextPosition offset, end = pos + length; + Bool state; + + end = XawMin(end, src->ascii_src.length); + while ((state = XawTextSourceAnchorAndEntity(w, pos, &anchor, &entity)) && + (entity->flags & XAW_TENTF_HIDE)) + pos = anchor->position + entity->offset + entity->length; + if (state == False || + !(entity->flags & XAW_TENTF_REPLACE)) { + while (entity) { + offset = anchor->position + entity->offset; + if (offset >= end) + break; + if (offset > pos && + (entity->flags & (XAW_TENTF_HIDE | XAW_TENTF_REPLACE))) { + end = XawMin(end, offset); + break; + } + if ((entity = entity->next) == NULL && + (anchor = XawTextSourceNextAnchor(w, anchor)) != NULL) + entity = anchor->entities; + } + } + else if (state && (entity->flags & XAW_TENTF_REPLACE) && pos < end) { + XawTextBlock *block = (XawTextBlock*)entity->data; + + offset = anchor->position + entity->offset; + end = XawMin(end, offset + block->length); + if ((length = end - pos) < 0) + length = 0; + text->length = length; + text->format = XawFmt8Bit; + if (length == 0) { + text->firstPos = end = offset + entity->length; + text->ptr = ""; + } + else { + text->firstPos = pos; + text->ptr = block->ptr + (pos - offset); + if (pos + length < offset + block->length) + end = pos + length; /* there is data left to be read */ + else + end = offset + entity->length; + } + + return (end); + } + + if ((length = end - pos) < 0) + length = 0; +#endif + + piece = FindPiece(src, pos, &start); + text->firstPos = pos; + text->ptr = piece->text + (pos - start); + count = piece->used - (pos - start); + text->length = Max(0, (length > count) ? count : length); + text->format = XawFmt8Bit; + + return (pos + text->length); +} + +/* + * Function: + * ReplaceText + * + * Parameters: + * w - AsciiSource object + * startPos - ends of text that will be replaced + * endPos - "" + * text - new text to be inserted into buffer at startPos + * + * Description: + * Replaces a block of text with new text. + * + * Returns: + * XawEditDone on success, XawEditError otherwise + */ +/*ARGSUSED*/ +static int +ReplaceText(Widget w, XawTextPosition startPos, XawTextPosition endPos, + XawTextBlock *text) +{ + AsciiSrcObject src = (AsciiSrcObject)w; + Piece *start_piece, *end_piece, *temp_piece; + XawTextPosition start_first, end_first; + int length, firstPos; + + /* + * Editing a read only source is not allowed + */ + if (src->text_src.edit_mode == XawtextRead) + return (XawEditError); + + start_piece = FindPiece(src, startPos, &start_first); + end_piece = FindPiece(src, endPos, &end_first); + +#ifndef OLDXAW + /* + * This is a big hack, but I can't think about a clever way to know + * if the character being moved forward has a negative lbearing. + * + */ + if (start_piece->used) { + int i; + + for (i = 0; i < src->text_src.num_text; i++) { + int line; + TextWidget ctx = (TextWidget)src->text_src.text[i]; + + for (line = 0; line < ctx->text.lt.lines; line++) + if (startPos < ctx->text.lt.info[line + 1].position) + break; + if (i < ctx->text.lt.lines && + startPos > ctx->text.lt.info[i].position) { + AsciiSinkObject sink = (AsciiSinkObject)ctx->text.sink; + XawTextAnchor *anchor; + XawTextEntity *entity; + XawTextProperty *property; + XFontStruct *font; + + if (XawTextSourceAnchorAndEntity(w, startPos, &anchor, &entity) && + (property = XawTextSinkGetProperty(ctx->text.sink, + entity->property)) != NULL && + (property->mask & XAW_TPROP_FONT)) + font = property->font; + else + font = sink->ascii_sink.font; + + if (font->min_bounds.lbearing < 0) { + int lbearing = font->min_bounds.lbearing; + unsigned char c = *(unsigned char*) + (start_piece->text + (startPos - start_first)); + + if (c == '\t' || c == '\n') + c = ' '; + else if ((c & 0177) < XawSP || c == 0177) { + if (sink->ascii_sink.display_nonprinting) + c = c > 0177 ? '\\' : c + '^'; + else + c = ' '; + } + if (font->per_char && + (c >= font->min_char_or_byte2 && c <= font->max_char_or_byte2)) + lbearing = font->per_char[c - font->min_char_or_byte2].lbearing; + if (lbearing < 0) + _XawTextNeedsUpdating(ctx, startPos - 1, startPos); + } + } + } + } + + +#endif + + /* + * Remove Old Stuff + */ + if (start_piece != end_piece) { + temp_piece = start_piece->next; + + /* + * If empty and not the only piece then remove it. + */ + if (((start_piece->used = startPos - start_first) == 0) + && !(start_piece->next == NULL && start_piece->prev == NULL)) + RemovePiece(src, start_piece); + + while (temp_piece != end_piece) { + temp_piece = temp_piece->next; + RemovePiece(src, temp_piece->prev); + } + + end_piece->used -= endPos - end_first; + if (end_piece->used != 0) + memmove(end_piece->text, end_piece->text + endPos - end_first, + (unsigned)end_piece->used); + } + else { /* We are fully in one piece */ + if ((start_piece->used -= endPos - startPos) == 0) { + if (!(start_piece->next == NULL && start_piece->prev == NULL)) + RemovePiece(src, start_piece); + } + else { + memmove(start_piece->text + (startPos - start_first), + start_piece->text + (endPos - start_first), + (unsigned)(start_piece->used - (startPos - start_first))); + if (src->ascii_src.use_string_in_place + && src->ascii_src.length - (endPos - startPos) + < src->ascii_src.piece_size - 1) + start_piece->text[src->ascii_src.length - (endPos - startPos)] = + '\0'; + } + } + + src->ascii_src.length += -(endPos - startPos) + text->length; + + if ( text->length != 0) { + /* + * Put in the New Stuff + */ + start_piece = FindPiece(src, startPos, &start_first); + + length = text->length; + firstPos = text->firstPos; + + while (length > 0) { + char *ptr; + int fill; + + if (src->ascii_src.use_string_in_place) { + if (start_piece->used == src->ascii_src.piece_size - 1) { + /* + * If we are in ascii string emulation mode. Then the + * string is not allowed to grow + */ + start_piece->used = src->ascii_src.length = + src->ascii_src.piece_size - 1; + start_piece->text[src->ascii_src.length] = '\0'; + return (XawEditError); + } + } + + if (start_piece->used == src->ascii_src.piece_size) { + BreakPiece(src, start_piece); + start_piece = FindPiece(src, startPos, &start_first); + } + + fill = Min((int)(src->ascii_src.piece_size - start_piece->used), + length); + + ptr = start_piece->text + (startPos - start_first); + memmove(ptr + fill, ptr, + (unsigned)(start_piece->used - (startPos - start_first))); + memcpy(ptr, text->ptr + firstPos, (unsigned)fill); + + startPos += fill; + firstPos += fill; + start_piece->used += fill; + length -= fill; + } + } + + if (src->ascii_src.use_string_in_place) + start_piece->text[start_piece->used] = '\0'; + +#ifdef OLDXAW + src->ascii_src.changes = True; + XtCallCallbacks(w, XtNcallback, NULL); +#endif + + return (XawEditDone); +} + +/* + * Function: + * Scan + * + * Parameters: + * w - AsciiSource object + * position - position to start scanning + * type - type of thing to scan for + * dir - direction to scan + * count - which occurance if this thing to search for. + * include - whether or not to include the character found in + * the position that is returned + * + * Description: + * Scans the text source for the number and type of item specified. + * + * Returns: + * The position of the item found + * + * Note: + * While there are only 'n' characters in the file there are n+1 + * possible cursor positions (one before the first character and + * one after the last character + */ +static XawTextPosition +Scan(Widget w, register XawTextPosition position, XawTextScanType type, + XawTextScanDirection dir, int count, Bool include) +{ + AsciiSrcObject src = (AsciiSrcObject)w; + Piece *piece; + XawTextPosition first, first_eol_position = 0; + register char *ptr, *lim; + register int cnt = count; + register unsigned char c; + + if (dir == XawsdLeft) { + if (position <= 0) + return (0); + --position; + } + else if (position >= src->ascii_src.length) + return (src->ascii_src.length); + + piece = FindPiece(src, position, &first); + if (piece->used == 0) + return (0); + + ptr = (position - first) + piece->text; + + if (dir == XawsdRight) { + lim = piece->text + piece->used; + switch (type) { + case XawstEOL: + case XawstParagraph: + case XawstWhiteSpace: + case XawstAlphaNumeric: + for (; cnt > 0; cnt--) { + Bool non_space = False, first_eol = True; + + /*CONSTCOND*/ + while (True) { + if (ptr >= lim) { + piece = piece->next; + if (piece == NULL) /* End of text */ + return (src->ascii_src.length); + ptr = piece->text; + lim = piece->text + piece->used; + } + + c = *ptr++; + ++position; + + if (type == XawstEOL) { + if (c == '\n') + break; + } + else if (type == XawstAlphaNumeric) { + if (!isalnum(c)) { + if (non_space) + break; + } + else + non_space = True; + } + else if (type == XawstWhiteSpace) { + if (isspace(c)) { + if (non_space) + break; + } + else + non_space = True; + } + else { /* XawstParagraph */ + if (first_eol) { + if (c == '\n') { + first_eol_position = position; + first_eol = False; + } + } + else if (c == '\n') + break; + else if (!isspace(c)) + first_eol = True; + } + } + } + break; + case XawstPositions: + position += count; + return (position < src->ascii_src.length ? + position : src->ascii_src.length); + case XawstAll: + return (src->ascii_src.length); + default: + break; + } + if (!include) { + if (type == XawstParagraph) + position = first_eol_position; + if (count) + --position; + } + } + else { + lim = piece->text; + switch (type) { + case XawstEOL: + case XawstParagraph: + case XawstWhiteSpace: + case XawstAlphaNumeric: + for (; cnt > 0; cnt--) { + Bool non_space = False, first_eol = True; + + /*CONSTCOND*/ + while (True) { + if (ptr < lim) { + piece = piece->prev; + if (piece == NULL) /* Begining of text */ + return (0); + ptr = piece->text + piece->used - 1; + lim = piece->text; + } + + c = *ptr--; + --position; + + if (type == XawstEOL) { + if (c == '\n') + break; + } + else if (type == XawstAlphaNumeric) { + if (!isalnum(c)) { + if (non_space) + break; + } + else + non_space = True; + } + else if (type == XawstWhiteSpace) { + if (isspace(c)) { + if (non_space) + break; + } + else + non_space = True; + } + else { /* XawstParagraph */ + if (first_eol) { + if (c == '\n') { + first_eol_position = position; + first_eol = False; + } + } + else if (c == '\n') + break; + else if (!isspace(c)) + first_eol = True; + } + } + } + break; + case XawstPositions: + position -= count - 1; + return (position > 0 ? position : 0); + case XawstAll: + return (0); + default: + break; + } + if (!include) { + if (type == XawstParagraph) + position = first_eol_position; + if (count) + ++position; + } + position++; + } + + return (position); +} + +/* + * Function: + * Search + * + * Parameters: + * w - AsciiSource object + * position - the position to start scanning + * dir - direction to scan + * text - text block to search for + * + * Description: + * Searchs the text source for the text block passed. + * + * Returns: + * The position of the item found + */ +static XawTextPosition +Search(Widget w, register XawTextPosition position, XawTextScanDirection dir, + XawTextBlock *text) +{ + AsciiSrcObject src = (AsciiSrcObject)w; + register int count = 0; + register char *ptr, c; + char *str; + Piece *piece; + char *buf; + XawTextPosition first; + int cnt, case_sensitive; + + if (dir == XawsdLeft) { + if (position == 0) + return (XawTextSearchError); + position--; + } + + buf = XtMalloc((unsigned)sizeof(unsigned char) * text->length); + memcpy(buf, text->ptr, (unsigned)text->length); + piece = FindPiece(src, position, &first); + ptr = (position - first) + piece->text; + case_sensitive = text->firstPos; + + if (dir == XawsdRight) { + str = buf; + c = *str; + /*CONSTCOND*/ + while (1) { + if (*ptr++ == c + || (case_sensitive && isalpha(c) && isalpha(ptr[-1]) + && toupper(c) == toupper(ptr[-1]))) { + if (++count == text->length) + break; + c = *++str; + } + else if (count) { + ptr -= count; + str -= count; + position -= count; + count = 0; + c = *str; + + if (ptr < piece->text) { + do { + cnt = piece->text - ptr; + piece = piece->prev; + if (piece == NULL) { + XtFree(buf); + return (XawTextSearchError); + } + ptr = piece->text + piece->used - cnt; + } while (ptr < piece->text); + } + } + position++; + if (ptr >= (piece->text + piece->used)) { + do { + cnt = ptr - (piece->text + piece->used); + piece = piece->next; + if (piece == NULL) { + XtFree(buf); + return (XawTextSearchError); + } + ptr = piece->text + cnt; + } while (ptr >= (piece->text + piece->used)); + } + } + + position -= text->length - 1; + } + else { + str = buf + text->length - 1; + c = *str; + /*CONSTCOND*/ + while (1) { + if (*ptr-- == c + || (case_sensitive && isalpha(c) && isalpha(ptr[1]) + && toupper(c) == toupper(ptr[1]))) { + if (++count == text->length) + break; + c = *--str; + } + else if (count) { + ptr += count; + str += count; + position += count; + count = 0; + c = *str; + + if (ptr >= (piece->text + piece->used)) { + do { + cnt = ptr - (piece->text + piece->used); + piece = piece->next; + if (piece == NULL) { + XtFree(buf); + return (XawTextSearchError); + } + ptr = piece->text + cnt; + } while (ptr >= (piece->text + piece->used)); + } + } + position--; + if (ptr < piece->text) { + do { + cnt = piece->text - ptr; + piece = piece->prev; + if (piece == NULL) { + XtFree(buf); + return (XawTextSearchError); + } + ptr = piece->text + piece->used - cnt; + } while (ptr < piece->text); + } + } + } + + XtFree(buf); + + return (position); +} + +/* + * Function: + * XawAsciiSrcSetValues + * + * Parameters: + * current - current state of the widget + * request - what was requested + * cnew - what the widget will become + * args - representation of changed resources + * num_args - number of resources that have changed + * + * Description: + * Sets the values for the AsciiSource. + * + * Returns: + * True if redisplay is needed + */ +static Boolean +XawAsciiSrcSetValues(Widget current, Widget request, Widget cnew, + ArgList args, Cardinal *num_args) +{ + AsciiSrcObject src = (AsciiSrcObject)cnew; + AsciiSrcObject old_src = (AsciiSrcObject)current; + Bool total_reset = False, string_set = False; + FILE *file; + unsigned int i; + + if (old_src->ascii_src.use_string_in_place + != src->ascii_src.use_string_in_place) { + XtAppWarning(XtWidgetToApplicationContext(cnew), + "AsciiSrc: The XtNuseStringInPlace resource may " + "not be changed."); + src->ascii_src.use_string_in_place = + old_src->ascii_src.use_string_in_place; + } + + for (i = 0; i < *num_args ; i++) + if (streq(args[i].name, XtNstring)) { + string_set = True; + break; + } + + if (string_set || (old_src->ascii_src.type != src->ascii_src.type)) { + RemoveOldStringOrFile(old_src, string_set); /* remove old info */ + file = InitStringOrFile(src, string_set); /* Init new info */ + LoadPieces(src, file, NULL); /* load new info into internal buffers */ + if (file != NULL) + fclose(file); +#ifndef OLDXAW + for (i = 0; i < src->text_src.num_text; i++) + /* Tell text widget what happened */ + XawTextSetSource(src->text_src.text[i], cnew, 0); +#else + XawTextSetSource(XtParent(cnew), cnew, 0); +#endif + total_reset = True; + } + + if (old_src->ascii_src.ascii_length != src->ascii_src.ascii_length) + src->ascii_src.piece_size = src->ascii_src.ascii_length + 1; + + if (!total_reset && + old_src->ascii_src.piece_size != src->ascii_src.piece_size) { + String string = StorePiecesInString(old_src); + + FreeAllPieces(old_src); + LoadPieces(src, NULL, string); + XtFree(string); + } + + return (False); +} + +/* + * Function: + * XawAsciiSrcGetValuesHook + * + * Parameters: + * w - AsciiSource Widget + * args - argument list + * num_args - number of args + * + * Description: + * This is a get values hook routine that sets the + * values specific to the ascii source. + */ +static void +XawAsciiSrcGetValuesHook(Widget w, ArgList args, Cardinal *num_args) +{ + AsciiSrcObject src = (AsciiSrcObject)w; + unsigned int i; + + if (src->ascii_src.type == XawAsciiString) { + for (i = 0; i < *num_args ; i++) + if (streq(args[i].name, XtNstring)) { + if (src->ascii_src.use_string_in_place) + *((char **)args[i].value) = src->ascii_src.first_piece->text; + else if (XawAsciiSave(w)) /* If save sucessful */ + *((char **)args[i].value) = src->ascii_src.string; + break; + } + } + } + +/* + * Function: + * XawAsciiSrcDestroy + * + * Parameters: + * src - Ascii source object to free + * + * Description: + * Destroys an ascii source (frees all data) + */ +static void +XawAsciiSrcDestroy(Widget w) +{ + RemoveOldStringOrFile((AsciiSrcObject) w, True); +} + +/* + * Public routines + */ +/* + * Function: + * XawAsciiSourceFreeString + * + * Parameters: + * w - AsciiSrc widget + * + * Description: + * Frees the string returned by a get values call + * on the string when the source is of type string. + */ +void +XawAsciiSourceFreeString(Widget w) +{ + AsciiSrcObject src = (AsciiSrcObject)w; + + /* If the src is really a multi, call the multi routine */ + if (XtIsSubclass(w, multiSrcObjectClass)) { + _XawMultiSourceFreeString(w); + return; + } + else if (!XtIsSubclass(w, asciiSrcObjectClass)) { + XtErrorMsg("bad argument", "asciiSource", "XawError", + "XawAsciiSourceFreeString's parameter must be " + "an asciiSrc or multiSrc.", + NULL, NULL); + } + + if (src->ascii_src.allocated_string && src->ascii_src.type != XawAsciiFile) { + src->ascii_src.allocated_string = False; + XtFree(src->ascii_src.string); + src->ascii_src.string = NULL; + } +} + +/* + * Function: + * XawAsciiSave + * + * Parameters: + * w - asciiSrc Widget + * + * Description: + * Saves all the pieces into a file or string as required. + * + * Returns: + * True if the save was successful + */ +Bool +XawAsciiSave(Widget w) +{ + AsciiSrcObject src = (AsciiSrcObject)w; + + /* If the src is really a multi, call the multi save */ + if (XtIsSubclass(w, multiSrcObjectClass )) + return (_XawMultiSave(w)); + + else if (!XtIsSubclass(w, asciiSrcObjectClass)) + XtErrorMsg("bad argument", "asciiSource", "XawError", + "XawAsciiSave's parameter must be an asciiSrc or multiSrc.", + NULL, NULL); + + /* + * If using the string in place then there is no need to play games + * to get the internal info into a readable string. + */ + if (src->ascii_src.use_string_in_place) + return (True); + + if (src->ascii_src.type == XawAsciiFile) { +#ifdef OLDXAW + if (!src->ascii_src.changes) +#else + if (!src->text_src.changed) /* No changes to save */ +#endif + return (True); + + if (WritePiecesToFile(src, src->ascii_src.string) == False) + return (False); + } + else { + if (src->ascii_src.allocated_string == True) + XtFree(src->ascii_src.string); + else + src->ascii_src.allocated_string = True; + + src->ascii_src.string = StorePiecesInString(src); + } +#ifdef OLDXAW + src->ascii_src.changes = False; +#else + src->text_src.changed = False; +#endif + + return (True); +} + +/* + * Function: + * XawAsciiSaveAsFile + * + * Arguments: + * w - AsciiSrc widget + * name - name of the file to save this file into + * + * Description: + * Save the current buffer as a file. + * + * Returns: + * True if the save was sucessful + */ +Bool +XawAsciiSaveAsFile(Widget w, _Xconst char *name) +{ + AsciiSrcObject src = (AsciiSrcObject)w; + Bool ret; + + /* If the src is really a multi, call the multi save */ + + if (XtIsSubclass( w, multiSrcObjectClass)) + return (_XawMultiSaveAsFile(w, name)); + + else if (!XtIsSubclass(w, asciiSrcObjectClass)) + XtErrorMsg("bad argument", "asciiSource", "XawError", + "XawAsciiSaveAsFile's 1st parameter must be an " + "asciiSrc or multiSrc.", + NULL, NULL); + + if (src->ascii_src.type == XawAsciiFile) + ret = WritePiecesToFile(src, (String)name); + else { + String string = StorePiecesInString(src); + + ret = WriteToFile(string, (String)name, src->ascii_src.length); + XtFree(string); + } + + return (ret); +} + +/* + * Function: + * XawAsciiSourceChanged + * + * Parameters: + * w - ascii source widget + * + * Description: + * Returns true if the source has changed since last saved. + * + * Returns: + * A Boolean (see description). + */ +Bool +XawAsciiSourceChanged(Widget w) +{ +#ifdef OLDXAW + if (XtIsSubclass(w, multiSrcObjectClass)) + return (((MultiSrcObject)w)->multi_src.changes); + + if (XtIsSubclass(w, asciiSrcObjectClass)) + return (((AsciiSrcObject)w)->ascii_src.changes); +#else + if (XtIsSubclass(w, textSrcObjectClass)) + return (((TextSrcObject)w)->textSrc.changed); +#endif + XtErrorMsg("bad argument", "asciiSource", "XawError", + "XawAsciiSourceChanged parameter must be an " + "asciiSrc or multiSrc.", + NULL, NULL); + + return (True); +} + +/* + * Private Functions + */ +static void +RemoveOldStringOrFile(AsciiSrcObject src, Bool checkString) +{ + FreeAllPieces(src); + + if (checkString && src->ascii_src.allocated_string) { + XtFree(src->ascii_src.string); + src->ascii_src.allocated_string = False; + src->ascii_src.string = NULL; + } +} + +/* + * Function: + * WriteToFile + * + * Parameters: + * string - string to write + * name - the name of the file + * + * Description: + * Write the string specified to the begining of the file specified. + * + * Returns: + * returns True if sucessful, False otherwise + */ +static Bool +WriteToFile(String string, String name, unsigned length) +{ + int fd; + + if ((fd = creat(name, 0666)) == -1 + || write(fd, string, length) == -1) + return (False); + + if (close(fd) == -1) + return (False); + + return (True); +} + +/* + * Function: + * WritePiecesToFile + * + * Parameters: + * src - ascii source object + * name - name of the file + * + * Description: + * Almost identical to WriteToFile, but only works for ascii src objects + * of type XawAsciiFile. This function avoids allocating temporary memory, + * what can be useful when editing very large files. + * + * Returns: + * returns True if sucessful, False otherwise + */ +static Bool +WritePiecesToFile(AsciiSrcObject src, String name) +{ + Piece *piece; + int fd; + + if (src->ascii_src.data_compression) { + Piece *tmp; + + piece = src->ascii_src.first_piece; + while (piece) { + int bytes = src->ascii_src.piece_size - piece->used; + + if (bytes > 0 && (tmp = piece->next) != NULL) { + bytes = XawMin(bytes, tmp->used); + memcpy(piece->text + piece->used, tmp->text, bytes); + memmove(tmp->text, tmp->text + bytes, tmp->used - bytes); + piece->used += bytes; + if ((tmp->used -= bytes) == 0) { + RemovePiece(src, tmp); + continue; + } + } + piece = piece->next; + } + } + + if ((fd = creat(name, 0666)) == -1) + return (False); + + for (piece = src->ascii_src.first_piece; piece; piece = piece->next) + if (write(fd, piece->text, piece->used) == -1) + return (False); + + if (close(fd) == -1) + return (False); + + return (True); +} + +/* + * Function: + * StorePiecesInString + * + * Parameters: + * data - ascii pointer data + * + * Description: + * Store the pieces in memory into a standard ascii string. + */ +static String +StorePiecesInString(AsciiSrcObject src) +{ + String string; + XawTextPosition first; + Piece *piece; + + string = XtMalloc((unsigned)(src->ascii_src.length + 1)); + + for (first = 0, piece = src->ascii_src.first_piece ; piece != NULL; + first += piece->used, piece = piece->next) + memcpy(string + first, piece->text, (unsigned)piece->used); + + string[src->ascii_src.length] = '\0'; + + /* + * This will refill all pieces to capacity + */ + if (src->ascii_src.data_compression) { + FreeAllPieces(src); + LoadPieces(src, NULL, string); + } + + return (string); +} + +/* + * Function: + * InitStringOrFile + * + * Parameters: + * src - AsciiSource + * + * Description: + * Initializes the string or file. + */ +static FILE * +InitStringOrFile(AsciiSrcObject src, Bool newString) +{ + mode_t open_mode = 0; + const char *fdopen_mode = NULL; + int fd; + FILE *file; + + if (src->ascii_src.type == XawAsciiString) { + if (src->ascii_src.string == NULL) + src->ascii_src.length = 0; + + else if (!src->ascii_src.use_string_in_place) { + src->ascii_src.string = XtNewString(src->ascii_src.string); + src->ascii_src.allocated_string = True; + src->ascii_src.length = strlen(src->ascii_src.string); + } + + if (src->ascii_src.use_string_in_place) { + if (src->ascii_src.string != NULL) + src->ascii_src.length = strlen(src->ascii_src.string); + /* In case the length resource is incorrectly set */ + if (src->ascii_src.length > src->ascii_src.ascii_length) + src->ascii_src.ascii_length = src->ascii_src.length; + + if (src->ascii_src.ascii_length == MAGIC_VALUE) + src->ascii_src.piece_size = src->ascii_src.length; + else + src->ascii_src.piece_size = src->ascii_src.ascii_length + 1; + } + + return (NULL); + } + + /* + * type is XawAsciiFile + */ + src->ascii_src.is_tempfile = False; + + switch (src->text_src.edit_mode) { + case XawtextRead: + if (src->ascii_src.string == NULL) + XtErrorMsg("NoFile", "asciiSourceCreate", "XawError", + "Creating a read only disk widget and no file specified.", + NULL, NULL); + open_mode = O_RDONLY; + fdopen_mode = "r"; + break; + case XawtextAppend: + case XawtextEdit: + if (src->ascii_src.string == NULL) { + src->ascii_src.string = "*ascii-src*"; + src->ascii_src.is_tempfile = True; + } + else { +/* O_NOFOLLOW is a FreeBSD & Linux extension */ +#ifdef O_NOFOLLOW + open_mode = O_RDWR | O_NOFOLLOW; +#else + open_mode = O_RDWR; /* unsafe; subject to race conditions */ +#endif /* O_NOFOLLOW */ + fdopen_mode = "r+"; + } + break; + default: + XtErrorMsg("badMode", "asciiSourceCreate", "XawError", + "Bad editMode for ascii source; must be Read, " + "Append or Edit.", + NULL, NULL); + } + + /* If is_tempfile, allocate a private copy of the text + * Unlikely to be changed, just to set allocated_string */ + if (newString || src->ascii_src.is_tempfile) { + src->ascii_src.string = XtNewString(src->ascii_src.string); + src->ascii_src.allocated_string = True; + } + + if (!src->ascii_src.is_tempfile) { + if ((fd = open(src->ascii_src.string, open_mode, 0666)) != -1) { + if ((file = fdopen(fd, fdopen_mode))) { + (void)fseek(file, 0, SEEK_END); + src->ascii_src.length = (XawTextPosition)ftell(file); + return (file); + } + } + { + String params[2]; + Cardinal num_params = 2; + + params[0] = src->ascii_src.string; + params[1] = strerror(errno); + XtAppWarningMsg(XtWidgetToApplicationContext((Widget)src), + "openError", "asciiSourceCreate", "XawWarning", + "Cannot open file %s; %s", params, &num_params); + } + } + src->ascii_src.length = 0; + return (NULL); +} + +static void +LoadPieces(AsciiSrcObject src, FILE *file, char *string) +{ + char *ptr; + Piece *piece = NULL; + XawTextPosition left; + + if (string == NULL) { + if (src->ascii_src.type == XawAsciiFile) { + if (src->ascii_src.length != 0) { + int len; + + left = 0; + fseek(file, 0, 0); + while (left < src->ascii_src.length) { + ptr = XtMalloc((unsigned)src->ascii_src.piece_size); + if ((len = fread(ptr, (Size_t)sizeof(unsigned char), + (Size_t)src->ascii_src.piece_size, file)) < 0) + XtErrorMsg("readError", "asciiSourceCreate", "XawError", + "fread returned error.", NULL, NULL); + piece = AllocNewPiece(src, piece); + piece->text = ptr; + piece->used = XawMin(len, src->ascii_src.piece_size); + left += piece->used; + } + } + else { + piece = AllocNewPiece(src, NULL); + piece->text = XtMalloc((unsigned)src->ascii_src.piece_size); + piece->used = 0; + } + return; + } + else + string = src->ascii_src.string; + } + + if (src->ascii_src.use_string_in_place) { + piece = AllocNewPiece(src, piece); + piece->used = XawMin(src->ascii_src.length, src->ascii_src.piece_size); + piece->text = src->ascii_src.string; + return; + } + + ptr = string; + left = src->ascii_src.length; + do { + piece = AllocNewPiece(src, piece); + + piece->text = XtMalloc((unsigned)src->ascii_src.piece_size); + piece->used = XawMin(left, src->ascii_src.piece_size); + if (piece->used != 0) + memcpy(piece->text, ptr, (unsigned)piece->used); + + left -= piece->used; + ptr += piece->used; + } while (left > 0); +} + +/* + * Function: + * AllocNewPiece + * + * Parameters: + * src - AsciiSrc Widget + * prev - piece just before this one, or NULL + * + * Description: + * Allocates a new piece of memory. + * + * Returns: + * The allocated piece + */ +static Piece * +AllocNewPiece(AsciiSrcObject src, Piece *prev) +{ + Piece *piece = XtNew(Piece); + + if (prev == NULL) { + src->ascii_src.first_piece = piece; + piece->next = NULL; + } + else { + if (prev->next != NULL) + (prev->next)->prev = piece; + piece->next = prev->next; + prev->next = piece; + } + + piece->prev = prev; + + return (piece); +} + +/* + * Function: + * FreeAllPieces + * + * Parameters: + * src - AsciiSrc Widget + * + * Description: + * Frees all the pieces. + */ +static void +FreeAllPieces(AsciiSrcObject src) +{ + Piece *next, * first = src->ascii_src.first_piece; + +#ifdef DEBUG + if (first->prev != NULL) + printf("Xaw AsciiSrc Object: possible memory leak in FreeAllPieces().\n"); +#endif + + for (; first != NULL ; first = next) { + next = first->next; + RemovePiece(src, first); + } +} + +/* + * Function: + * RemovePiece + * + * Parameters: + * piece - piece to remove + * + * Description: + * Removes a piece from the list. + */ +static void +RemovePiece(AsciiSrcObject src, Piece *piece) +{ + if (piece->prev == NULL) + src->ascii_src.first_piece = piece->next; + else + piece->prev->next = piece->next; + + if (piece->next != NULL) + piece->next->prev = piece->prev; + + if (!src->ascii_src.use_string_in_place) + XtFree(piece->text); + + XtFree((char *)piece); +} + +/* + * Function: + * FindPiece + * + * Parameters: + * src - AsciiSrc Widget + * position - position that we are searching for + * first - position of the first character in this piece (return) + * + * Description: + * Finds the piece containing the position indicated. + * + * Returns: + * the piece that contains this position + */ +static Piece * +FindPiece(AsciiSrcObject src, XawTextPosition position, XawTextPosition *first) +{ + Piece *old_piece, *piece; + XawTextPosition temp; + + for (old_piece = NULL, piece = src->ascii_src.first_piece, temp = 0; + piece; old_piece = piece, piece = piece->next) + if ((temp += piece->used) > position) { + *first = temp - piece->used; + return (piece); + } + + *first = temp - (old_piece ? old_piece->used : 0); + + return (old_piece); /* if we run off the end the return the last piece */ +} + +/* + * Function: + * BreakPiece + * + * Parameters: + * src - AsciiSrc Widget + * piece - piece to break + * + * Description: + * Breaks a full piece into two new pieces. + */ +#define HALF_PIECE (src->ascii_src.piece_size >> 1) +static void +BreakPiece(AsciiSrcObject src, Piece *piece) +{ + Piece *cnew = AllocNewPiece(src, piece); + + cnew->text = XtMalloc((unsigned)src->ascii_src.piece_size); + memcpy(cnew->text, piece->text + HALF_PIECE, + (unsigned)(src->ascii_src.piece_size - HALF_PIECE)); + piece->used = HALF_PIECE; + cnew->used = src->ascii_src.piece_size - HALF_PIECE; +} + +/*ARGSUSED*/ +static void +CvtStringToAsciiType(XrmValuePtr args, Cardinal *num_args, + XrmValuePtr fromVal, XrmValuePtr toVal) +{ + static XawAsciiType type; + XrmQuark q; + char name[7]; + + XmuNCopyISOLatin1Lowered(name, (char *)fromVal->addr, sizeof(name)); + q = XrmStringToQuark(name); + + if (q == Qstring) + type = XawAsciiString; + else if (q == Qfile) + type = XawAsciiFile; + else { + toVal->size = 0; + toVal->addr = NULL; + XtStringConversionWarning((char *)fromVal->addr, XtRAsciiType); + } + + toVal->size = sizeof(XawAsciiType); + toVal->addr = (XPointer)&type; +} + +/*ARGSUSED*/ +static Boolean +CvtAsciiTypeToString(Display *dpy, XrmValuePtr args, Cardinal *num_args, + XrmValuePtr fromVal, XrmValuePtr toVal, + XtPointer *data) +{ + static String buffer; + Cardinal size; + + switch (*(XawAsciiType *)fromVal->addr) { + case XawAsciiFile: + buffer = XtEfile; + break; + case XawAsciiString: + buffer = XtEstring; + break; + default: + XawTypeToStringWarning(dpy, XtRAsciiType); + toVal->addr = NULL; + toVal->size = 0; + return (False); + } + + size = strlen(buffer) + 1; + if (toVal->addr != NULL) { + if (toVal->size < size) { + toVal->size = size; + return (False); + } + strcpy((char *)toVal->addr, buffer); + } + else + toVal->addr = (XPointer)buffer; + toVal->size = sizeof(String); + + return (True); +} + +/*ARGSUSED*/ +static void +GetDefaultPieceSize(Widget w, int offset, XrmValue *value) +{ + static XPointer pagesize; + + if (pagesize == NULL) { + pagesize = (XPointer)((long)_XawGetPageSize()); + if (pagesize < (XPointer)BUFSIZ) + pagesize = (XPointer)BUFSIZ; + } + + value->addr = (XPointer)&pagesize; +} + +#if (defined(ASCII_STRING) || defined(ASCII_DISK)) +# include <X11/Xaw/Cardinals.h> +#endif + +#ifdef ASCII_STRING +/* + * Compatability functions. + */ +/* + * Function: + * AsciiStringSourceCreate + * + * Parameters: + * parent - widget that will own this source + * args - the argument list + * num_args - "" + * + * Description: + * Creates a string source. + * + * Returns: + * A pointer to the new text source. + */ +Widget +XawStringSourceCreate(Widget parent, ArgList args, Cardinal num_args) +{ + XawTextSource src; + ArgList ascii_args; + Arg temp[2]; + + XtSetArg(temp[0], XtNtype, XawAsciiString); + XtSetArg(temp[1], XtNuseStringInPlace, True); + ascii_args = XtMergeArgLists(temp, TWO, args, num_args); + + src = XtCreateWidget("genericAsciiString", asciiSrcObjectClass, parent, + ascii_args, num_args + TWO); + XtFree((char *)ascii_args); + + return (src); +} + +/* + * This is hacked up to try to emulate old functionality, it + * may not work, as I have not old code to test it on. + * + * Chris D. Peterson 8/31/89. + */ +void +XawTextSetLastPos(Widget w, XawTextPosition lastPos) +{ + AsciiSrcObject src = (AsciiSrcObject)XawTextGetSource(w); + + src->ascii_src.piece_size = lastPos; +} +#endif /* ASCII_STRING */ + +#ifdef ASCII_DISK +/* + * Function: + * AsciiDiskSourceCreate + * + * Parameters: + * parent - widget that will own this source + * args - argument list + * num_args - "" + * + * Description: + * Creates a disk source. + * + * Returns: + * A pointer to the new text source + */ +Widget +XawDiskSourceCreate(Widget parent, ArgList args, Cardinal num_args) +{ + XawTextSource src; + ArgList ascii_args; + Arg temp[1]; + int i; + + XtSetArg(temp[0], XtNtype, XawAsciiFile); + ascii_args = XtMergeArgLists(temp, ONE, args, num_args); + num_args++; + + for (i = 0; i < num_args; i++) + if (streq(ascii_args[i].name, XtNfile) + || streq(ascii_args[i].name, XtCFile)) + ascii_args[i].name = XtNstring; + + src = XtCreateWidget("genericAsciiDisk", asciiSrcObjectClass, parent, + ascii_args, num_args); + XtFree((char *)ascii_args); + + return (src); +} +#endif /* ASCII_DISK */ |