|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T
Length: 37520 (0x9290) Types: TextFile Names: »Tty.c,v«
└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89 └─⟦34cc4e2f7⟧ »./UNRELEASED/xgdb3.2.tar.Z« └─⟦80fac5d7c⟧ └─⟦this⟧ »./RCS/Tty.c,v«
head 1.1; access ; symbols ; locks hubbard:1.1; strict; comment @ * @; 1.1 date 89.07.05.15.35.40; author hubbard; state Exp; branches ; next ; desc @Initial checkin, Beta version 0.1. @ 1.1 log @Initial revision @ text @\f /*- * Tty.c -- * Functions to implement the TTY widget -- a subclass of the * text widget that acts much like a standard tty, except * there's no process running under it. * * Copyright (c) 1988 by the Regents of the University of California * * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies. The University of California * makes no representations about the suitability of this * software for any purpose. It is provided "as is" without * express or implied warranty. * * Author: Adam deBoor, U.C. Berkeley. * * Log */ #ifndef lint static char rcsid[] = "$Header: /usr/ben/jkh/src/xgdb/RCS/Tty.c,v 1.2 89/05/28 18:27:48 jkh Exp Locker: jkh $ SPRITE (Berkeley)"; #endif lint #include "IntrinsicP.h" #include "Xos.h" #include "StringDefs.h" #include "TtyP.h" #include "xgdb.h" #include <sys/file.h> #include <varargs.h> #include <ctype.h> #define TTY_BUF_SIZE 1024 XtTextSource XtTtySourceCreate(); void XtTtySourceDestroy(); void XtTtySourceSetFence(); static int defOptions = scrollVertical|scrollOnOverflow|wordBreak; static XtResource resources[] = { { XtNenterCallback, XtCCallback, XtRCallback, sizeof(caddr_t), XtOffset(TtyWidget, tty.enter), XtRCallback, (caddr_t)NULL }, { XtNprompt, XtCPrompt, XtRString, sizeof(char *), XtOffset(TtyWidget, tty.prompt.ptr), XtRString, NULL }, { XtNtextOptions, XtCTextOptions, XtRInt, sizeof(int), XtOffset(TtyWidget, text.options), XtRInt, (caddr_t)&defOptions }, { XtNinterruptCallback, XtCCallback, XtRCallback, sizeof(caddr_t), XtOffset(TtyWidget, tty.interrupt), XtRCallback, (caddr_t)NULL }, }; static void Enter(), KillLine(), SetMark(), SaveRegion(), Interrupt(); static XtActionsRec actions[] = { {"enter", Enter}, {"backward-delete-to-prompt", KillLine }, {"set-mark", SetMark }, {"save-region", SaveRegion }, {"interrupt", Interrupt }, {NULL, NULL} }; /* * New translations -- adds enter to the various newline() translations. */ static char defaultTranslations[] = "Meta<Key>0xffff: delete-previous-word()\n\ <Key>0xffff: delete-previous-character()\n\ <Key>0xff0d: newline() enter()\n\ <Key>0xff08: delete-previous-character()\n\ Ctrl<Key>@@: set-mark()\n\ Ctrl<Key>\32: set-mark()\n\ Ctrl<Key>A: beginning-of-line()\n\ Ctrl<Key>B: backward-character()\n\ Meta<Key>B: backward-word()\n\ Ctrl<Key>C: interrupt()\n\ Ctrl<Key>D: delete-selection()\n\ Ctrl<Key>E: end-of-line()\n\ Ctrl<Key>F: forward-character()\n\ Meta<Key>F: forward-word()\n\ Ctrl<Key>H: delete-previous-character()\n\ Ctrl<Key>J: newline() enter()\n\ Ctrl<Key>L: redraw-display()\n\ Ctrl<Key>M: newline() enter()\n\ Ctrl<Key>N: next-line()\n\ Ctrl<Key>P: previous-line()\n\ Ctrl Meta<Key>V: next-page()\n\ Meta<Key>V: previous-page()\n\ Ctrl<Key>W: delete-previous-word()\n\ Meta<Key>W: save-region()\n\ Ctrl<Key>X: backward-delete-to-prompt()\n\ Ctrl<Key>Y: unkill()\n\ Meta<Key>Y: stuff()\n\ Ctrl<Key>V: stuff()\n\ Meta<Key>\\<: beginning-of-file()\n\ Meta<Key>\\>: end-of-file()\n\ <FocusIn>: focus-in()\n\ <FocusOut>: focus-out()\n\ Ctrl<Btn1Down>: select-start()\n\ Ctrl Button3<PtrMoved>: extend-adjust()\n\ Ctrl<Btn3Up>: extend-end()\n\ None<Btn1Down>: select-start()\n\ Button3<PtrMoved>: extend-adjust()\n\ None<Btn3Up>: extend-end()\n\ !Button1<PtrMoved>: extend-adjust()\n\ None<Btn1Up>: extend-end()\n\ None<Btn2Down>: stuff()\n\ <Key>: insert-char()\n\ Shift<Key>: insert-char()"; static void Initialize(), Destroy(), InitializeHook(); static Boolean SetValues(); TtyClassRec ttyClassRec = { { /* core fields */ (WidgetClass) &textClassRec, /* superclass */ "Tty", /* class_name */ sizeof(TtyRec), /* widget_size */ NULL, /* class_initialize */ NULL, /* class_part_init */ FALSE, /* class_inited */ Initialize, /* initialize */ InitializeHook, /* initialize_hook */ XtInheritRealize, /* realize */ actions, /* actions */ XtNumber(actions), /* num_actions */ resources, /* resources */ XtNumber(resources), /* num_ resource */ NULLQUARK, /* xrm_class */ TRUE, /* compress_motion */ FALSE, /* compress_exposure*/ TRUE, /* compress_enterleave*/ FALSE, /* visible_interest */ Destroy, /* destroy */ XtInheritResize, /* resize */ XtInheritExpose, /* expose */ SetValues, /* set_values */ NULL, /* set_values_hook */ XtInheritSetValuesAlmost, /* set_values_almost*/ NULL, /* get_values_hook */ XtInheritAcceptFocus, /* accept_focus */ XtVersion, /* version */ NULL, /* callback_private */ defaultTranslations, /* tm_table */ XtInheritQueryGeometry, /* query_geometry */ XtInheritDisplayAccelerator, /* display_accelerator*/ NULL /* extension */ }, }; WidgetClass ttyWidgetClass = (WidgetClass)&ttyClassRec; /*- *----------------------------------------------------------------------- * Initialize -- * Initialize a Tty widget -- duplicate prompt string, if any and * initialize startPos and prompted. * * Results: * None. * * Side Effects: * See above. * *----------------------------------------------------------------------- */ static void Initialize(request, new) Widget request; Widget new; { TtyWidget tty = (TtyWidget)new; tty->tty.prompted = FALSE; if (tty->tty.prompt.ptr != (char *)NULL) { char *prompt; tty->tty.prompt.length = strlen(tty->tty.prompt.ptr); prompt = XtMalloc(tty->tty.prompt.length + 1); (void)strcpy(prompt, tty->tty.prompt.ptr); tty->tty.prompt.ptr = prompt; } else { tty->tty.prompt.ptr = ""; tty->tty.prompt.length = 0; } tty->tty.prompt.firstPos = 0; tty->tty.markPos = 0; /* * Deal with geometry */ /* superclass Initialize can't set the following, * as it didn't know the source or sink when it was called */ if (request->core.height == DEFAULT_TEXT_HEIGHT) new->core.height = DEFAULT_TEXT_HEIGHT; } /*- *----------------------------------------------------------------------- * InitializeHook -- * Create the necessary sources and sinks for this beastie. Code * snarfed from DiskCreateSourceSink in AsciiText.c since we must * have editType set to append and it's not a proper resource. * * Results: * None. * * Side Effects: * The source and sink are created for the widget. * *----------------------------------------------------------------------- */ static void InitializeHook(w, args, num_args) Widget w; ArgList args; Cardinal *num_args; { TtyWidget tty = (TtyWidget)w; tty->text.source = XtTtySourceCreate(w, args, *num_args); tty->text.sink = XtAsciiSinkCreate(w, args, *num_args); /* * Seek to the end of the file. */ tty->text.lastPos = /* GETLASTPOS */ (*tty->text.source->Scan) (tty->text.source, 0, XtstAll, XtsdRight, 1, TRUE ); /* * If no height specified, stuff in a reasonable one -- * 24 lines high. */ if (tty->core.height == DEFAULT_TEXT_HEIGHT) { tty->core.height = (2*yMargin) + 2 + (*tty->text.sink->MaxHeight)(tty, 24); } /* * Redisplay the entire thing */ ForceBuildLineTable((TextWidget)tty); } /*- *----------------------------------------------------------------------- * Destroy -- * Free the prompt string. * * Results: * None. * * Side Effects: * The prompt string c'est freed. * *----------------------------------------------------------------------- */ static void Destroy(w) Widget w; { TtyWidget tty = (TtyWidget)w; XtTtySourceDestroy(tty->text.source); XtAsciiSinkDestroy(tty->text.sink); /* XtFree(tty->tty.prompt.ptr); This tosses its cookies */ } /*- *----------------------------------------------------------------------- * SetValues -- * Change the values for the given tty widget. Can only change the * prompt string. * * Results: * FALSE. * * Side Effects: * Frees old prompt string and duplicates new. * *----------------------------------------------------------------------- */ static Boolean SetValues(current, request, new) Widget current; Widget request; Widget new; { TtyWidget curTty = (TtyWidget)current; TtyWidget reqTty = (TtyWidget)request; TtyWidget newTty = (TtyWidget)new; if (reqTty->tty.prompt.ptr != curTty->tty.prompt.ptr) { char *prompt; XtFree(curTty->tty.prompt.ptr); newTty->tty.prompt.length = strlen(newTty->tty.prompt.ptr); prompt = XtMalloc(newTty->tty.prompt.length + 1); (void)strcpy(prompt, newTty->tty.prompt.ptr); newTty->tty.prompt.ptr = prompt; } return (FALSE); } /*- *----------------------------------------------------------------------- * XtTtyNumColumns -- * Return the number of columns in the given tty widget. * * Results: * The number of columns in the widget. * * Side Effects: * None. * *----------------------------------------------------------------------- */ int XtTtyNumColumns(w) Widget w; { TtyWidget tty = (TtyWidget)w; int charWidth; int charHeight; XtTextPosition nlPos; XtTextPosition junkPos; Entry("XtTtyNumColumns"); /* * AsciiSink treats a newline as a space, giving us the average * character width, so find the most-recent newline in the file and * get its width, then divide the total width of the window by that * to get the number of columns. */ nlPos = (* tty->text.source->Scan)(tty->text.source, tty->text.insertPos, XtstEOL, XtsdLeft, 1, TRUE); (* tty->text.sink->FindDistance)(tty, nlPos, 0, nlPos + 1, &charWidth, &junkPos, &charHeight); Leave((tty->core.width - tty->text.leftmargin) / charWidth); } /*- *----------------------------------------------------------------------- * XtTtyPrompt -- * Place a prompt in the window. * * Results: * None. * * Side Effects: * The prompt string is put in the window at its end. * *----------------------------------------------------------------------- */ void XtTtyPrompt(w) Widget w; { TtyWidget tty = (TtyWidget)w; XtTextPosition pos; Entry("XtTtyPrompt"); pos = tty->text.lastPos; XtTextReplace(w, pos, pos, &tty->tty.prompt); tty->tty.startPos = pos + tty->tty.prompt.length; XtTextSetInsertionPoint(w, tty->tty.startPos); XtTtySourceSetFence(tty->text.source, tty->tty.startPos); tty->tty.prompted = TRUE; Leave_void; } /*- *----------------------------------------------------------------------- * XtTtyPrintf -- * Perform a printf to the given widget at its end. The buffer used * is as big as that used in the Tty source. This is a kludge, * however. What should happen is either the proper-sized buffer * should be determined, allocated, printed-to and broken into * decent-sized chunks for TtyReplaceText, or the thing printed * piecemeal, thus replicating printf into here... * * Results: * None. * * Side Effects: * The characters are added to the window. * *----------------------------------------------------------------------- */ /*VARARGS*/ void XtTtyPrintf(va_alist) va_dcl { TtyWidget tty; char string[TTY_BUF_SIZE]; XtTextBlock text; XtTextPosition last; register char *cp; char *cpStart; va_list args; va_list nextArgs; char savec; Boolean fancy; Entry("XtTtyPrintf"); va_start(args); tty = va_arg(args, TtyWidget); cpStart = cp = va_arg(args, char *); last = tty->text.lastPos; while (*cp != '\0') { if (*cp != '%') { cp++; } else { if (cp != cpStart) { if (cp - cpStart < TTY_BUF_SIZE) { text.firstPos = 0; text.ptr = cpStart; text.length = cp - cpStart; XtTextReplace((Widget)tty, last, last, &text); last += text.length; } else { *cp = '\0'; XtTtyPutString((Widget)tty, cpStart); *cp = '%'; last += cp - cpStart; } } cpStart = cp; cp++; nextArgs = args; fancy = FALSE; charswitch: switch(*cp) { case '*': /* * Argument specifies width -- pop it now */ (void)va_arg(nextArgs, int); fancy = TRUE; case '+': case '-': case ' ': case '#': case '.': case 'l': case 'h': cp++; fancy = TRUE; goto charswitch; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': cp++; while (isdigit(*cp)) { cp++; } fancy = TRUE; goto charswitch; case 'd': cp++; savec = *cp; *cp = '\0'; (void)va_arg(nextArgs, int); vsprintf(string, cpStart, args); XtTtyPutString(tty, string); *cp = savec; break; case 'u': case 'o': case 'X': case 'x': cp++; savec = *cp; *cp = '\0'; (void)va_arg(nextArgs, unsigned int); vsprintf(string, cpStart, args); XtTtyPutString(tty, string); *cp = savec; break; case 'E': case 'e': case 'f': case 'G': case 'g': cp++; savec = *cp; *cp = '\0'; (void)va_arg(nextArgs, double); vsprintf(string, cpStart, args); XtTtyPutString(tty, string); *cp = savec; break; case 'c': (void)va_arg(nextArgs, int); case '%': cp++; savec = *cp; *cp = '\0'; vsprintf(string, cpStart, args); XtTtyPutString(tty, string); *cp = savec; break; case 's': cp++; if ((args == nextArgs) && !fancy) { char *s = va_arg(nextArgs, char *); XtTtyPutString(tty, s); } else { /* * XXX: Should worry about length here, but what * the heck? */ savec = *cp; *cp = '\0'; (void)va_arg(nextArgs, char *); vsprintf(string, cpStart, args); XtTtyPutString(tty, string); *cp = savec; } break; } cpStart = cp; args = nextArgs; last = tty->text.lastPos; } } if (cp - cpStart < TTY_BUF_SIZE) { text.firstPos = 0; text.ptr = cpStart; text.length = cp - cpStart; XtTextReplace((Widget)tty, last, last, &text); last += text.length; } else { XtTtyPutString((Widget)tty, cpStart); last += cp - cpStart; } XtTextSetInsertionPoint((Widget)tty, last); Leave_void; } /*- *----------------------------------------------------------------------- * XtTtyPutString -- * Outputs the string, without formatting, to the given widget. * * Results: * None. * * Side Effects: * See above. * *----------------------------------------------------------------------- */ void XtTtyPutString(w, string) Widget w; char *string; { TtyWidget tty = (TtyWidget)w; XtTextBlock text; XtTextPosition last; Entry("XtTtyPutString"); /* expand any tabs and control characters "in situ". */ string = (String)expand_string(string, '\0'); text.ptr = string; text.firstPos = 0; text.length = strlen(string); last = tty->text.lastPos; if (text.length < TTY_BUF_SIZE) { XtTextReplace((Widget)tty, last, last, &text); XtTextSetInsertionPoint((Widget)tty, last + text.length); } else { int length; #ifndef min #define min(a,b) ((a)<(b)?(a):(b)) #endif length = text.length; while (length != 0) { text.length = min(TTY_BUF_SIZE-1, length); XtTextReplace((Widget)tty, last, last, &text); length -= text.length; text.firstPos += text.length; last += text.length; } XtTextSetInsertionPoint((Widget)tty, last); } Leave_void; } /*XXX: No function officially exported to snag the text, so use one * that's unofficially exported (though the comments say it's sort of ok) */ extern char *_XtTextGetText( /* ctx, left, right */ ); /************************************************************* * * Action procedures * ************************************************************/ /*- *----------------------------------------------------------------------- * Enter -- * Extract the text typed since the last prompt and pass it off * to the enterCallback function(s). * * Results: * None. * * Side Effects: * The enterCallback function(s) are called. * *----------------------------------------------------------------------- */ /*ARGSUSED*/ static void Enter(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { TtyWidget tty = (TtyWidget)w; XtTextPosition cur; char *text; if (tty->tty.prompted) { cur = tty->text.lastPos; tty->tty.prompted = FALSE; text = _XtTextGetText((TextWidget)w, tty->tty.startPos, cur); XtCallCallbacks(w, XtNenterCallback, (caddr_t)text); XtFree(text); } } /*- *----------------------------------------------------------------------- * KillLine -- * Kill all the text back to the prompt. * * Results: * None. * * Side Effects: * The text from the last prompt to the end of the file is * nuked. * *----------------------------------------------------------------------- */ /*ARGSUSED*/ static void KillLine(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { TtyWidget tty = (TtyWidget)w; XtTextPosition cur; XtTextBlock text; if (tty->tty.prompted) { cur = tty->text.lastPos; text.length = text.firstPos = 0; text.ptr = ""; XtTextReplace(w, tty->tty.startPos, cur, &text); } } /*- *----------------------------------------------------------------------- * SetMark -- * Record the current point for later reference. * * Results: * None. * * Side Effects: * tty->tty.markPos is changed. * *----------------------------------------------------------------------- */ /*ARGSUSED*/ static void SetMark(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { TtyWidget tty = (TtyWidget)w; tty->tty.markPos = XtTextGetInsertionPoint(w); } /*- *----------------------------------------------------------------------- * SaveRegion -- * Save the text between the current point and the last mark in * cut buffer 1. * * Results: * None. * * Side Effects: * Cut buffer 1 is changed. * *----------------------------------------------------------------------- */ /*ARGSUSED*/ static void SaveRegion(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { TtyWidget tty = (TtyWidget)w; char *ptr; XtTextPosition cur; cur = XtTextGetInsertionPoint(w); if (cur < tty->tty.markPos) { ptr = _XtTextGetText((TextWidget)w, cur, tty->tty.markPos); } else { ptr = _XtTextGetText((TextWidget)w, tty->tty.markPos, cur); } XStoreBuffer(XtDisplay(w), ptr, strlen(ptr), 1); XtFree(ptr); } /*- *----------------------------------------------------------------------- * Interrupt -- * Handle an interrupt. Calls the functions in the interruptCallback * list for the widget. * * Results: * * Side Effects: * *----------------------------------------------------------------------- */ /*ARGSUSED*/ static void Interrupt(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { XtCallCallbacks(w, XtNinterruptCallback, (caddr_t)NULL); } /************************************************************* * * Tty Source Functions * *************************************************************/ /* * The following code is modified from DiskSrc.c. Aside from renaming, * it also allows text to be removed from the end of the file, thus * allowing for line-editing. */ #define TMPSIZ 32 /* bytes to allocate for tmpnam */ extern char *tmpnam(); /** private TtySource definitions **/ typedef struct _TtySourceData { /* resources */ char *fileName; /* private data */ Boolean is_tempfile; int fd; XtTextPosition position, /* file position of first char in buffer */ length, /* length of file */ fence; /* file position beyond which characters * may not be deleted */ char buffer[TTY_BUF_SIZE]; /* piece of file in memory */ int charsInBuffer; /* number of bytes used in memory */ int dirtyStart; /* Start of dirty section (buffer index) */ int dirtyEnd; /* End of dirty section (buffer index) */ } TtySourceData, *TtySourcePtr; #define Increment(data, position, direction)\ {\ if (direction == XtsdLeft) {\ if (position > 0) \ position -= 1;\ }\ else {\ if (position < data->length)\ position += 1;\ }\ } static XtResource diskResources[] = { {XtNfile, XtCFile, XtRString, sizeof (char *), XtOffset(TtySourcePtr, fileName), XtRString, NULL}, }; /*- *----------------------------------------------------------------------- * TtyFillBuffer -- * Read text starting at the given position into memory. Attempts * to keep the read position centered in the buffer (for some reason) * * Results: * ? * * Side Effects: * The buffer is filled with characters. * *----------------------------------------------------------------------- */ static void TtyFillBuffer (data, pos, length, modify) TtySourcePtr data; XtTextPosition pos; long length; Boolean modify; /* TRUE if intend to modify the buffer. * i.e. there must be length bytes available * in the buffer when we return */ { long readPos; #ifdef DEBUG_TTY printf("FillBuffer: pos = %d, length = %d, cur=%d, curLength = %d\n", pos, length, data->position, data->charsInBuffer); #endif if (!modify && ((pos + length) > data->length)) { /* * If not going to write the buffer, don't worry if we haven't * got exactly the right amount of data if the dude is trying to * read beyond the end of the file... */ length = data->length - pos; #ifdef DEBUG_TTY printf("FillBuffer: length = %d\n", length); #endif } if ((pos < data->position) || (pos >= (data->position + data->charsInBuffer - length))) { if (length > TTY_BUF_SIZE / 2) { /* * If the caller wants more characters than half a buffer's worth, * don't bother trying to center the position in the buffer -- * just place it at the beginning. */ readPos = pos; } else if (pos < (TTY_BUF_SIZE / 2)) { /* * Position before halfway point of buffer -- read from start * of file. */ readPos = 0; } else if (pos >= data->length - TTY_BUF_SIZE) { /* * Position in last buffer of file -- read last buffer, * but leave room enough at the end for length bytes. */ readPos = data->length - (TTY_BUF_SIZE - length); } else { /* * Read so pos is in center. */ readPos = pos - (TTY_BUF_SIZE / 2); } if (readPos < 0) { readPos = 0; } if (readPos != data->position) { if (data->dirtyStart >= 0) { /* * If any data are dirty, flush them to disk before changing * positions. */ #ifdef DEBUG_TTY printf("FillBuffer: dirty = [%d, %d]\n", data->dirtyStart, data->dirtyEnd); #endif lseek(data->fd, data->position + data->dirtyStart, L_SET); write(data->fd, data->buffer + data->dirtyStart, data->dirtyEnd - data->dirtyStart + 1); data->dirtyStart = data->dirtyEnd = -1; } lseek(data->fd, readPos, L_SET); data->charsInBuffer = read(data->fd, data->buffer, TTY_BUF_SIZE); data->position = readPos; #ifdef DEBUG_TTY printf("FillBuffer: cur = %d, curLength = %d\n", data->position, data->charsInBuffer); #endif } } } /*- *----------------------------------------------------------------------- * TtyLook -- * TtyLook to the right or left (based on 'direction') of the given * position and return the character found there. * * Results: * The appropriate character. * * Side Effects: * The buffer is filled as necessary. * *----------------------------------------------------------------------- */ static char TtyLook(data, position, direction) TtySourcePtr data; /* Private data */ XtTextPosition position; /* Current position (between two * characters, you know) */ XtTextScanDirection direction; /* Direction to look */ { if (direction == XtsdLeft) { if (position == 0) { return('\n'); } else { if ((position <= data->position) || (position > data->position + data->charsInBuffer)) { TtyFillBuffer(data, position - 1, 1, FALSE); } return(data->buffer[position - data->position - 1]); } } else { if (position == data->length) { return('\n'); } else { if ((position < data->position) || (position >= data->position + data->charsInBuffer)) { TtyFillBuffer(data, position, 1, FALSE); } return(data->buffer[position - data->position]); } } } /*- *----------------------------------------------------------------------- * TtyReadText -- * Read text from the file. * * Results: * The position after the characters read. * * Side Effects: * The buffer is filled and *text changed. * *----------------------------------------------------------------------- */ static XtTextPosition TtyReadText (src, pos, text, length) XtTextSource src; XtTextPosition pos; /** starting position */ XtTextBlock *text; /** RETURNED: text read in */ int length; /** max number of bytes to read **/ { XtTextPosition count; TtySourcePtr data; data = (TtySourcePtr) src->data; if (length > TTY_BUF_SIZE) { XtError("TtyReadText: length > buffer size"); } if ((pos < data->position) || (data->position + data->charsInBuffer < pos + length)) { TtyFillBuffer(data, pos, length, FALSE); } text->firstPos = pos; text->ptr = data->buffer + (pos - data->position); count = data->charsInBuffer - (pos - data->position); text->length = (length > count) ? count : length; if ((text->length == 0) && (pos != data->length) && (length != 0)){ XtError("Premature EOF"); } return pos + text->length; } /*- *----------------------------------------------------------------------- * TtyReplaceText -- * Replace text at the end of the file. If endPos is not the end of * the file, an error is generated. * * Results: * PositionError or EditDone if successful. * * Side Effects: * Characters may be removed from the end of the file and/or added * to it. * *----------------------------------------------------------------------- */ static int TtyReplaceText (src, startPos, endPos, text) XtTextSource src; XtTextPosition startPos; XtTextPosition endPos; XtTextBlock *text; { char *tmpPtr; TtySourcePtr data; data = (TtySourcePtr) src->data; if ((endPos != data->length) || (startPos < data->fence)) { return (PositionError); } if (startPos != endPos) { /* * Seek to the new end position and truncate the file to that * length. */ data->length = startPos; ftruncate(data->fd, data->length); if (data->position + data->charsInBuffer > data->length) { /* * Reduce the number of characters in the buffer if it contains * the last block of the file */ data->charsInBuffer = data->length - data->position; } if (data->dirtyEnd > data->charsInBuffer) { /* * Trim dirty area to fit buffer */ data->dirtyEnd = data->charsInBuffer - 1; } if (data->dirtyStart > data->charsInBuffer) { /* * If dirty area is now beyond buffer, nothing's * dirty anymore */ data->dirtyStart = data->dirtyEnd = -1; } } /* write the new text to the end of the file */ if (text->length > 0) { int tmp; if (data->charsInBuffer + text->length > TTY_BUF_SIZE) { /* * Text won't fit in buffer -- refill it so it will. */ if (text->length > TTY_BUF_SIZE) { XtError("TtyReplaceText: length > buffer size"); } TtyFillBuffer(data, startPos, text->length, TRUE); } tmpPtr = data->buffer + (startPos - data->position); bcopy(text->ptr + text->firstPos, tmpPtr, text->length); tmp = tmpPtr - data->buffer; if ((tmp < data->dirtyStart) || (data->dirtyStart < 0)) { data->dirtyStart = tmp; } tmp = (tmpPtr - data->buffer) + text->length - 1; if (tmp > data->dirtyEnd) { data->dirtyEnd = tmp; } data->charsInBuffer += text->length; data->length += text->length; } return (EditDone); } /*- *----------------------------------------------------------------------- * TtySetLastPos -- * Set the bounding point for the file. * * Results: * None. * * Side Effects: * The length recorded in the private data for this source * is altered. * *----------------------------------------------------------------------- */ static int TtySetLastPos (src, lastPos) XtTextSource src; XtTextPosition lastPos; { ((TtySourceData *)(src->data))->length = lastPos; return(EditDone); } /*- *----------------------------------------------------------------------- * TtyGetLastPos -- * Return the last position in the source. * * Results: * The last position in the file is returned. * * Side Effects: * None. * *----------------------------------------------------------------------- */ static XtTextPosition TtyGetLastPos(src) XtTextSource src; { return ((TtySourceData *)(src->data))->length; } /*- *----------------------------------------------------------------------- * TtyScan -- * Scan through the file in the proper direction for the desired * thing. * * Results: * The new position. * * Side Effects: * May refill the internal buffer. * *----------------------------------------------------------------------- */ static XtTextPosition TtyScan (src, pos, sType, dir, count, include) XtTextSource src; /* Source to use */ XtTextPosition pos; /* Starting position */ XtTextScanType sType; /* Type of scan desired */ XtTextScanDirection dir; /* Direction in which to go */ int count; /* Number of sTypes to skip */ Boolean include; /* Scan inclusively? */ { TtySourcePtr data; XtTextPosition position; int i, incr; char c; data = (TtySourcePtr) src->data; position = pos; switch (sType) { case XtstPositions: /* * Scan count positions in the desired direction. */ if (!include && count > 0) { count -= 1; } if (dir == XtsdLeft) { position -= count; if (position < 0) { position = 0; } } else { position += count; if (position > data->length) { position = data->length; } } break; case XtstWhiteSpace: /* * Skip to and over count bits of whitespace */ incr = (dir == XtsdLeft) ? -1 : 1; for (i = 0; i < count; i++) { while (position >= 0 && position <= data->length) { c = TtyLook(data, position, dir); if ((c == ' ') || (c == '\t') || (c == '\n')) { break; } position += incr; } if (i + 1 != count) { position += incr; } } if (include) { position += incr; } if (position < 0) { position = 0; } else if (position > data->length) { position = data->length; } break; case XtstEOL: for (i = 0; i < count; i++) { while (position >= 0 && position <= data->length) { if (TtyLook(data, position, dir) == '\n') break; Increment(data, position, dir); } if (i + 1 != count) Increment(data, position, dir); } if (include) { /* later!!!check for last char in file # eol */ Increment(data, position, dir); } break; case XtstAll: if (dir == XtsdLeft) position = 0; else position = data->length; } return(position); } /*- *----------------------------------------------------------------------- * TtyAddWidget -- * Warn that this function was called. * * Results: * None. * * Side Effects: * A warning is printed. * *----------------------------------------------------------------------- */ /*ARGSUSED*/ static void TtyAddWidget(src, w) XtTextSource src; Widget w; { XtWarning("TtyAddWidget called"); } /*- *----------------------------------------------------------------------- * TtyRemoveWidget -- * Warn that this function was called. * * Results: * None. * * Side Effects: * A warning is printed. * *----------------------------------------------------------------------- */ /*ARGSUSED*/ static void TtyRemoveWidget(src, w) XtTextSource src; Widget w; { XtWarning("TtyRemoveWidget called"); } /*- *----------------------------------------------------------------------- * TtySetSelection -- * Warn that this function was called. * * Results: * None. * * Side Effects: * A warning is printed. * *----------------------------------------------------------------------- */ /*ARGSUSED*/ static void TtySetSelection(src, left, right) XtTextSource src; XtTextPosition left; XtTextPosition right; { /* XtWarning("TtySetSelection called"); */ } /*- *----------------------------------------------------------------------- * TtyGetSelection -- * Warn that this function was called. * * Results: * None. * * Side Effects: * A warning is printed. * *----------------------------------------------------------------------- */ /*ARGSUSED*/ static Boolean TtyGetSelection(src, left, right) XtTextSource src; XtTextPosition left; XtTextPosition right; { XtWarning("TtyGetSelection called"); } /******* Public routines **********/ /*- *----------------------------------------------------------------------- * XtTtySourceCreate -- * Create a tty source. Only allows edit_mode XttextAppend, though * the caller may specify a file to use either in args or as a * fileName resource. * * Results: * The new source. * * Side Effects: * The file is opened and, if no fileName resource was found, a * temporary file is created. The widget must be properly destroyed * for the temporary file to be unlinked. * *----------------------------------------------------------------------- */ XtTextSource XtTtySourceCreate(parent, args, num_args) Widget parent; ArgList args; Cardinal num_args; { XtTextSource src; TtySourcePtr data; src = XtNew(XtTextSourceRec); data = XtNew(TtySourceData); src->Read = TtyReadText; src->Replace = TtyReplaceText; src->GetLastPos = TtyGetLastPos; src->SetLastPos = TtySetLastPos; src->Scan = TtyScan; src->AddWidget = TtyAddWidget; src->RemoveWidget = TtyRemoveWidget; src->SetSelection = TtySetSelection; src->GetSelection = TtyGetSelection; src->edit_mode = XttextAppend; src->data = (caddr_t)data; XtGetSubresources (parent, (caddr_t)data, XtNtextSource, XtCTextSource, diskResources, XtNumber(diskResources), args, num_args); if (data->fileName == NULL) { data->fileName = tmpnam (XtMalloc((unsigned)TMPSIZ)); data->is_tempfile = TRUE; } else { data->is_tempfile = FALSE; } if ((data->fd = open(data->fileName, O_RDWR|O_CREAT|O_TRUNC, 0666)) == 0) { XtError("Cannot open source file in XtTtySourceCreate"); } data->fence = data->length = 0; data->position = data->length; data->dirtyStart = data->dirtyEnd = -1; data->charsInBuffer = 0; return src; } /*- *----------------------------------------------------------------------- * XtTtySourceSetFence -- * Set the boundary beyond which characters may not be deleted. * * Results: * None. * * Side Effects: * data->fence is set to the given position. * *----------------------------------------------------------------------- */ void XtTtySourceSetFence(src, fence) XtTextSource src; XtTextPosition fence; { TtySourcePtr data; data = (TtySourcePtr)src->data; if (fence <= data->length && fence >= 0) { data->fence = fence; } } /*- *----------------------------------------------------------------------- * XtTtySourceDestroy -- * Free up data associated with this source, including the * XtTextSource structure itself. * * Results: * None. * * Side Effects: * Memory is freed and any temporary file opened is unlinked. * *----------------------------------------------------------------------- */ void XtTtySourceDestroy (src) XtTextSource src; { TtySourcePtr data; data = (TtySourcePtr) src->data; if (data->is_tempfile) { unlink(data->fileName); XtFree((char *) data->fileName); } close(data->fd); XtFree((char *) data); XtFree((char *) src); } @