#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>
#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)
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*);
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*);
#ifdef ASCII_DISK
Widget XawAsciiDiskSourceCreate(Widget, ArgList, Cardinal);
#endif
#ifdef ASCII_STRING
Widget XawStringSourceCreate(Widget, ArgList, Cardinal);
void XawTextSetLastPos(Widget, XawTextPosition);
#endif
#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
};
#undef offset
#define Superclass (&textSrcClassRec)
AsciiSrcClassRec asciiSrcClassRec = {
{
(WidgetClass)Superclass,
"AsciiSrc",
sizeof(AsciiSrcRec),
XawAsciiSrcClassInitialize,
NULL,
False,
XawAsciiSrcInitialize,
NULL,
NULL,
NULL,
0,
resources,
XtNumber(resources),
NULLQUARK,
False,
False,
False,
False,
XawAsciiSrcDestroy,
NULL,
NULL,
XawAsciiSrcSetValues,
NULL,
NULL,
XawAsciiSrcGetValuesHook,
NULL,
XtVersion,
NULL,
NULL,
NULL,
NULL,
NULL,
},
{
ReadText,
ReplaceText,
Scan,
Search,
XtInheritSetSelection,
XtInheritConvertSelection,
},
{
NULL,
},
};
WidgetClass asciiSrcObjectClass = (WidgetClass)&asciiSrcClassRec;
static XrmQuark Qstring, Qfile;
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);
}
static void
XawAsciiSrcInitialize(Widget request, Widget cnew,
ArgList args, Cardinal *num_args)
{
AsciiSrcObject src = (AsciiSrcObject)cnew;
FILE *file;
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);
}
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;
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);
}
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;
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
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
if (start_piece != end_piece) {
temp_piece = start_piece->next;
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 {
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) {
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) {
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);
}
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;
while (True) {
if (ptr >= lim) {
piece = piece->next;
if (piece == NULL)
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 {
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;
while (True) {
if (ptr < lim) {
piece = piece->prev;
if (piece == NULL)
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 {
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);
}
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;
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;
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);
}
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);
file = InitStringOrFile(src, string_set);
LoadPieces(src, file, NULL);
if (file != NULL)
fclose(file);
#ifndef OLDXAW
for (i = 0; i < src->text_src.num_text; i++)
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);
}
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))
*((char **)args[i].value) = src->ascii_src.string;
break;
}
}
}
static void
XawAsciiSrcDestroy(Widget w)
{
RemoveOldStringOrFile((AsciiSrcObject) w, True);
}
void
XawAsciiSourceFreeString(Widget w)
{
AsciiSrcObject src = (AsciiSrcObject)w;
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;
}
}
Bool
XawAsciiSave(Widget w)
{
AsciiSrcObject src = (AsciiSrcObject)w;
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 (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)
#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);
}
Bool
XawAsciiSaveAsFile(Widget w, _Xconst char *name)
{
AsciiSrcObject src = (AsciiSrcObject)w;
Bool ret;
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);
}
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);
}
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;
}
}
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);
}
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);
}
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';
if (src->ascii_src.data_compression) {
FreeAllPieces(src);
LoadPieces(src, NULL, string);
}
return (string);
}
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);
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);
}
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, 0);
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 {
#ifdef O_NOFOLLOW
open_mode = O_RDWR | O_NOFOLLOW;
#else
open_mode = O_RDWR;
#endif
fdopen_mode = "r+";
}
break;
default:
XtErrorMsg("badMode", "asciiSourceCreate", "XawError",
"Bad editMode for ascii source; must be Read, "
"Append or Edit.",
NULL, NULL);
}
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);
}
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);
}
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);
}
}
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);
}
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);
}
#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;
}
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;
}
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);
}
static void
GetDefaultPieceSize(Widget w, int offset, XrmValue *value)
{
static XPointer pagesize;
if (pagesize == 0) {
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
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);
}
void
XawTextSetLastPos(Widget w, XawTextPosition lastPos)
{
AsciiSrcObject src = (AsciiSrcObject)XawTextGetSource(w);
src->ascii_src.piece_size = lastPos;
}
#endif
#ifdef ASCII_DISK
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