15dfecf96Smrg/*
25dfecf96Smrg * Copyright (c) 2002 by The XFree86 Project, Inc.
35dfecf96Smrg *
45dfecf96Smrg * Permission is hereby granted, free of charge, to any person obtaining a
55dfecf96Smrg * copy of this software and associated documentation files (the "Software"),
65dfecf96Smrg * to deal in the Software without restriction, including without limitation
75dfecf96Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
85dfecf96Smrg * and/or sell copies of the Software, and to permit persons to whom the
95dfecf96Smrg * Software is furnished to do so, subject to the following conditions:
105dfecf96Smrg *
115dfecf96Smrg * The above copyright notice and this permission notice shall be included in
125dfecf96Smrg * all copies or substantial portions of the Software.
135dfecf96Smrg *
145dfecf96Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
155dfecf96Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
165dfecf96Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
175dfecf96Smrg * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
185dfecf96Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
195dfecf96Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
205dfecf96Smrg * SOFTWARE.
215dfecf96Smrg *
225dfecf96Smrg * Except as contained in this notice, the name of the XFree86 Project shall
235dfecf96Smrg * not be used in advertising or otherwise to promote the sale, use or other
245dfecf96Smrg * dealings in this Software without prior written authorization from the
255dfecf96Smrg * XFree86 Project.
265dfecf96Smrg *
275dfecf96Smrg * Author: Paulo César Pereira de Andrade
285dfecf96Smrg */
295dfecf96Smrg
305dfecf96Smrg/* $XFree86: xc/programs/xedit/lisp/xedit.c,v 1.25 2003/04/27 18:17:35 tsi Exp $ */
315dfecf96Smrg
325dfecf96Smrg#include "../xedit.h"
335dfecf96Smrg#include <X11/Xaw/TextSrcP.h>	/* Needs some private definitions */
345dfecf96Smrg#include <X11/Xaw/TextSinkP.h>	/* Also needs private definitions... */
355dfecf96Smrg#include <X11/Xmu/Xmu.h>
365dfecf96Smrg#define XEDIT_LISP_PRIVATE
375dfecf96Smrg#include "xedit.h"
385dfecf96Smrg#include <signal.h>
395dfecf96Smrg
405dfecf96Smrg/* Initialize to enter lisp */
415dfecf96Smrg#define LISP_SETUP()						\
425dfecf96Smrg    int lisp__running = lisp__data.running
435dfecf96Smrg
445dfecf96Smrg/* XXX Maybe should use ualarm or better, setitimer, but one
455dfecf96Smrg *     second seens good enough to check for interrupts */
465dfecf96Smrg
475dfecf96Smrg#define	ENABLE_SIGALRM()					\
485dfecf96Smrg    old_sigalrm = signal(SIGALRM, SigalrmHandler);		\
495dfecf96Smrg    alarm(1)
505dfecf96Smrg
515dfecf96Smrg#define DISABLE_SIGALRM()					\
525dfecf96Smrg    alarm(0);							\
535dfecf96Smrg    signal(SIGALRM, old_sigalrm)
545dfecf96Smrg
555dfecf96Smrg/* Enter lisp */
565dfecf96Smrg#define LISP_ENTER()						\
575dfecf96Smrg    if (!lisp__running) {					\
585dfecf96Smrg	lisp__data.running = 1;					\
595dfecf96Smrg	XFlush(XtDisplay(textwindow));				\
605dfecf96Smrg	ENABLE_SIGALRM();					\
615dfecf96Smrg	if (sigsetjmp(lisp__data.jmp, 1) != 0) {		\
625dfecf96Smrg	    DISABLE_SIGALRM();					\
635dfecf96Smrg	    lisp__data.running = 0;				\
645dfecf96Smrg	    return;						\
655dfecf96Smrg	}							\
665dfecf96Smrg    }
675dfecf96Smrg
685dfecf96Smrg/* Leave lisp */
695dfecf96Smrg#define LISP_LEAVE()						\
705dfecf96Smrg    if (!lisp__running) {					\
715dfecf96Smrg	DISABLE_SIGALRM();					\
725dfecf96Smrg	LispTopLevel();						\
735dfecf96Smrg	lisp__data.running = 0;					\
745dfecf96Smrg    }
755dfecf96Smrg
765dfecf96Smrg/*
775dfecf96Smrg * Types
785dfecf96Smrg */
795dfecf96Smrgtypedef struct {
805dfecf96Smrg    XawTextPosition left, right;
815dfecf96Smrg    XrmQuark property;
825dfecf96Smrg} EntityInfo;
835dfecf96Smrg
845dfecf96Smrg/*
855dfecf96Smrg * Prototypes
865dfecf96Smrg */
875dfecf96Smrgstatic Bool ControlGPredicate(Display*, XEvent*, XPointer);
885dfecf96Smrgstatic ssize_t WriteToStdout(int, const void*, size_t);
895dfecf96Smrgstatic ssize_t WriteToStderr(int, const void*, size_t);
905dfecf96Smrgstatic ssize_t WrapWrite(Widget, const void*, size_t);
915dfecf96Smrgstatic void XeditUpdateModeInfos(void);
925dfecf96Smrgstatic void XeditPrint(Widget, LispObj*, int);
935dfecf96Smrgstatic void XeditInteractiveCallback(Widget, XtPointer, XtPointer);
945dfecf96Smrgstatic void XeditIndentationCallback(Widget, XtPointer, XtPointer);
955dfecf96Smrgstatic LispObj *XeditCharAt(LispBuiltin*, int);
965dfecf96Smrgstatic LispObj *XeditSearch(LispBuiltin*, XawTextScanDirection);
975dfecf96Smrg
985dfecf96Smrg/*
995dfecf96Smrg * Initialization
1005dfecf96Smrg */
1015dfecf96Smrgstatic void (*old_sigalrm)(int);
1025dfecf96Smrg
1035dfecf96SmrgEditModeInfo *mode_infos;
1045dfecf96SmrgCardinal num_mode_infos;
1055dfecf96Smrg
1065dfecf96Smrgstatic LispObj *Oauto_modes, *Oauto_mode, *Osyntax_highlight, *Osyntable_indent;
1075dfecf96Smrg
1085dfecf96Smrg/* Just to make calling interactive reparse easier */
1095dfecf96Smrgstatic LispObj interactive_arguments[4];
1105dfecf96Smrg
1115dfecf96Smrgstatic LispObj *justify_modes[4];
1125dfecf96Smrgstatic LispObj *wrap_modes[3];
1135dfecf96Smrgstatic LispObj *scan_types[6];
1145dfecf96Smrgstatic LispObj *scan_directions[2];
1155dfecf96Smrgstatic LispObj execute_stream;
1165dfecf96Smrgstatic LispString execute_string;
1175dfecf96Smrgstatic LispObj result_stream;
1185dfecf96Smrgstatic LispString result_string;
1195dfecf96Smrgstatic XawTextPropertyList **property_lists;
1205dfecf96Smrgstatic Cardinal num_property_lists;
1215dfecf96Smrg
1225dfecf96Smrg/* Some hacks to (at lest try to) avoid problems reentering Xlib while
1235dfecf96Smrg * testing for user interrupts */
1245dfecf96Smrgstatic volatile int disable_timeout, request_timeout;
1255dfecf96Smrg
1265dfecf96Smrgextern int pagesize;
1275dfecf96Smrg
1285dfecf96Smrgstatic LispBuiltin xeditbuiltins[] = {
1295dfecf96Smrg    {LispFunction, Xedit_AddEntity, "add-entity offset length identifier"},
1305dfecf96Smrg    {LispFunction, Xedit_AutoFill, "auto-fill &optional value"},
1315dfecf96Smrg    {LispFunction, Xedit_Background, "background &optional color"},
1325dfecf96Smrg    {LispFunction, Xedit_CharAfter, "char-after &optional offset"},
1335dfecf96Smrg    {LispFunction, Xedit_CharBefore, "char-before &optional offset"},
1345dfecf96Smrg    {LispFunction, Xedit_ClearEntities, "clear-entities left right"},
1355dfecf96Smrg    {LispFunction, Xedit_ConvertPropertyList, "convert-property-list name definition"},
1365dfecf96Smrg    {LispFunction, Xedit_Font, "font &optional font"},
1375dfecf96Smrg    {LispFunction, Xedit_Foreground, "foreground &optional color"},
1385dfecf96Smrg    {LispFunction, Xedit_GotoChar, "goto-char offset"},
1395dfecf96Smrg    {LispFunction, Xedit_HorizontalScrollbar, "horizontal-scrollbar &optional state"},
1405dfecf96Smrg    {LispFunction, Xedit_Insert, "insert text"},
1415dfecf96Smrg    {LispFunction, Xedit_Justification, "justification &optional value"},
1425dfecf96Smrg    {LispFunction, Xedit_LeftColumn, "left-column &optional left"},
1435dfecf96Smrg    {LispFunction, Xedit_Point, "point"},
1445dfecf96Smrg    {LispFunction, Xedit_PointMax, "point-max"},
1455dfecf96Smrg    {LispFunction, Xedit_PointMin, "point-min"},
1465dfecf96Smrg    {LispFunction, Xedit_PropertyList, "property-list &optional value"},
1475dfecf96Smrg    {LispFunction, Xedit_ReadText, "read-text offset length"},
1485dfecf96Smrg    {LispFunction, Xedit_ReplaceText, "replace-text left right text"},
1495dfecf96Smrg    {LispFunction, Xedit_RightColumn, "right-column &optional right"},
1505dfecf96Smrg    {LispFunction, Xedit_Scan, "scan offset type direction &key count include"},
1515dfecf96Smrg    {LispFunction, Xedit_SearchBackward, "search-backward string &optional offset ignore-case"},
1525dfecf96Smrg    {LispFunction, Xedit_SearchForward, "search-forward string &optional offset ignore-case"},
1535dfecf96Smrg    {LispFunction, Xedit_VerticalScrollbar, "vertical-scrollbar &optional state"},
1545dfecf96Smrg    {LispFunction, Xedit_WrapMode, "wrap-mode &optional value"},
1555dfecf96Smrg
1565dfecf96Smrg	/* This should be available from elsewhere at some time... */
1575dfecf96Smrg    {LispFunction, Xedit_XrmStringToQuark, "xrm-string-to-quark string"},
1585dfecf96Smrg};
1595dfecf96Smrg
1605dfecf96Smrg/*
1615dfecf96Smrg * Implementation
1625dfecf96Smrg */
1635dfecf96Smrg/*ARGUSED*/
1645dfecf96Smrgstatic Bool
1655dfecf96SmrgControlGPredicate(Display *display, XEvent *event, XPointer arguments)
1665dfecf96Smrg{
1675dfecf96Smrg    char buffer[2];
1685dfecf96Smrg
1695dfecf96Smrg    return ((event->type == KeyPress || event->type == KeyRelease) &&
1705dfecf96Smrg	    (event->xkey.state & ControlMask) &&
1715dfecf96Smrg	    XLookupString(&(event->xkey), buffer, sizeof(buffer), NULL, NULL) &&
1725dfecf96Smrg	    buffer[0] == '\a');
1735dfecf96Smrg}
1745dfecf96Smrg
1755dfecf96Smrg/*ARGSUSED*/
176f765521fSmrgstatic void
1775dfecf96SmrgSigalrmHandler(int signum)
1785dfecf96Smrg{
1795dfecf96Smrg    XEvent event;
1805dfecf96Smrg
1815dfecf96Smrg    if (disable_timeout) {
1825dfecf96Smrg	request_timeout = 1;
1835dfecf96Smrg	return;
1845dfecf96Smrg    }
1855dfecf96Smrg
1865dfecf96Smrg    /* Check if user pressed C-g */
1875dfecf96Smrg    if (XCheckIfEvent(XtDisplay(textwindow), &event, ControlGPredicate, NULL)) {
1885dfecf96Smrg	XPutBackEvent(XtDisplay(textwindow), &event);
1895dfecf96Smrg	alarm(0);
1905dfecf96Smrg	/* Tell a signal was received, print message for SIGINT */
1915dfecf96Smrg	LispSignal(SIGINT);
1925dfecf96Smrg    }
1935dfecf96Smrg    else
1945dfecf96Smrg	alarm(1);
1955dfecf96Smrg}
1965dfecf96Smrg
1975dfecf96Smrgstatic ssize_t
1985dfecf96SmrgWrapWrite(Widget output, const void *buffer, size_t nbytes)
1995dfecf96Smrg{
2005dfecf96Smrg    XawTextBlock block;
2015dfecf96Smrg    XawTextPosition position;
2025dfecf96Smrg
2035dfecf96Smrg    disable_timeout = 1;
2045dfecf96Smrg    position = XawTextGetInsertionPoint(output);
2055dfecf96Smrg    block.firstPos = 0;
2065dfecf96Smrg    block.format = FMT8BIT;
2075dfecf96Smrg    block.length = nbytes;
2085dfecf96Smrg    block.ptr = (String)buffer;
2095dfecf96Smrg    XawTextReplace(output, position, position, &block);
2105dfecf96Smrg    XawTextSetInsertionPoint(output, position + block.length);
2115dfecf96Smrg    disable_timeout = 0;
2125dfecf96Smrg
2135dfecf96Smrg    if (request_timeout) {
2145dfecf96Smrg	XFlush(XtDisplay(output));
2155dfecf96Smrg	request_timeout = 0;
2165dfecf96Smrg	SigalrmHandler(SIGALRM);
2175dfecf96Smrg    }
2185dfecf96Smrg
2195dfecf96Smrg    return ((ssize_t)nbytes);
2205dfecf96Smrg}
2215dfecf96Smrg
2225dfecf96Smrgstatic ssize_t
2235dfecf96SmrgWriteToStdout(int fd, const void *buffer, size_t nbytes)
2245dfecf96Smrg{
2255dfecf96Smrg    return (WrapWrite(textwindow, buffer, nbytes));
2265dfecf96Smrg}
2275dfecf96Smrg
2285dfecf96Smrgstatic ssize_t
2295dfecf96SmrgWriteToStderr(int fd, const void *buffer, size_t nbytes)
2305dfecf96Smrg{
2315dfecf96Smrg    return (WrapWrite(messwidget, buffer, nbytes));
2325dfecf96Smrg}
2335dfecf96Smrg
2345dfecf96Smrgvoid
2355dfecf96SmrgLispXeditInitialize(void)
2365dfecf96Smrg{
2375dfecf96Smrg    int i;
2385dfecf96Smrg    char *string;
2395dfecf96Smrg    LispObj *xedit, *list, *savepackage;
2405dfecf96Smrg
2415dfecf96Smrg    LispSetFileWrite(Stdout, WriteToStdout);
2425dfecf96Smrg    LispSetFileWrite(Stderr, WriteToStderr);
2435dfecf96Smrg
2445dfecf96Smrg    justify_modes[0]	= KEYWORD("LEFT");
2455dfecf96Smrg    justify_modes[1]	= KEYWORD("RIGHT");
2465dfecf96Smrg    justify_modes[2]	= KEYWORD("CENTER");
2475dfecf96Smrg    justify_modes[3]	= KEYWORD("FULL");
2485dfecf96Smrg
2495dfecf96Smrg    wrap_modes[0]	= KEYWORD("NEVER");
2505dfecf96Smrg    wrap_modes[1]	= KEYWORD("LINE");
2515dfecf96Smrg    wrap_modes[2]	= KEYWORD("WORD");
2525dfecf96Smrg
2535dfecf96Smrg    scan_types[0]	= KEYWORD("POSITIONS");
2545dfecf96Smrg    scan_types[1]	= KEYWORD("WHITE-SPACE");
2555dfecf96Smrg    scan_types[2]	= KEYWORD("EOL");
2565dfecf96Smrg    scan_types[3]	= KEYWORD("PARAGRAPH");
2575dfecf96Smrg    scan_types[4]	= KEYWORD("ALL");
2585dfecf96Smrg    scan_types[5]	= KEYWORD("ALPHA-NUMERIC");
2595dfecf96Smrg
2605dfecf96Smrg    scan_directions[0]	= justify_modes[0];
2615dfecf96Smrg    scan_directions[1]	= justify_modes[1];
2625dfecf96Smrg
2635dfecf96Smrg    /* Remember value of current package */
2645dfecf96Smrg    savepackage = PACKAGE;
2655dfecf96Smrg
2665dfecf96Smrg    /* Create the XEDIT package */
2675dfecf96Smrg    xedit = LispNewPackage(STRING("XEDIT"), NIL);
2685dfecf96Smrg
2695dfecf96Smrg    /* Update list of packages */
2705dfecf96Smrg    PACK = CONS(xedit, PACK);
2715dfecf96Smrg
2725dfecf96Smrg    /* Temporarily switch to the XEDIT package */
2735dfecf96Smrg    lisp__data.pack = lisp__data.savepack = xedit->data.package.package;
2745dfecf96Smrg    PACKAGE = xedit;
2755dfecf96Smrg
2765dfecf96Smrg    /* Add XEDIT builtin functions */
2775dfecf96Smrg    for (i = 0; i < sizeof(xeditbuiltins) / sizeof(xeditbuiltins[0]); i++)
2785dfecf96Smrg	LispAddBuiltinFunction(&xeditbuiltins[i]);
2795dfecf96Smrg
2805dfecf96Smrg    /* Create these objects in the xedit package */
2815dfecf96Smrg    Oauto_modes		= STATIC_ATOM("*AUTO-MODES*");
2825dfecf96Smrg    Oauto_mode		= STATIC_ATOM("AUTO-MODE");
2835dfecf96Smrg    Osyntax_highlight	= STATIC_ATOM("SYNTAX-HIGHLIGHT");
2845dfecf96Smrg    Osyntable_indent	= STATIC_ATOM("SYNTABLE-INDENT");
2855dfecf96Smrg
2865dfecf96Smrg    /*  Import symbols from the LISP and EXT packages */
2875dfecf96Smrg    for (list = PACK; CONSP(list); list = CDR(list)) {
2885dfecf96Smrg	string = THESTR(CAR(list)->data.package.name);
2895dfecf96Smrg	if (strcmp(string, "LISP") == 0 || strcmp(string, "EXT") == 0)
2905dfecf96Smrg	    LispUsePackage(CAR(list));
2915dfecf96Smrg    }
2925dfecf96Smrg
2935dfecf96Smrg    /* Restore previous package */
2945dfecf96Smrg    lisp__data.pack = savepackage->data.package.package;
2955dfecf96Smrg    PACKAGE = savepackage;
2965dfecf96Smrg
2975dfecf96Smrg    /* Initialize helper static objects used when executing expressions */
2985dfecf96Smrg    execute_stream.type = LispStream_t;
2995dfecf96Smrg    execute_stream.data.stream.source.string = &execute_string;
3005dfecf96Smrg    execute_stream.data.stream.pathname = NIL;
3015dfecf96Smrg    execute_stream.data.stream.type = LispStreamString;
3025dfecf96Smrg    execute_stream.data.stream.readable = 1;
3035dfecf96Smrg    execute_stream.data.stream.writable = 0;
3045dfecf96Smrg    execute_string.output = 0;
3055dfecf96Smrg    result_stream.type = LispStream_t;
3065dfecf96Smrg    result_stream.data.stream.source.string = &result_string;
3075dfecf96Smrg    result_stream.data.stream.pathname = NIL;
3085dfecf96Smrg    result_stream.data.stream.type = LispStreamString;
3095dfecf96Smrg    result_stream.data.stream.readable = 0;
3105dfecf96Smrg    result_stream.data.stream.writable = 1;
3115dfecf96Smrg    result_string.string = XtMalloc(pagesize);
3125dfecf96Smrg    result_string.space = pagesize;
3135dfecf96Smrg
3145dfecf96Smrg    /* Initialize interactive edition function arguments */
3155dfecf96Smrg    /* first argument is syntax table */
3165dfecf96Smrg    interactive_arguments[0].type = LispCons_t;
3175dfecf96Smrg    interactive_arguments[0].data.cons.cdr = &interactive_arguments[1];
3185dfecf96Smrg    /* second argument is where to start reparsing */
3195dfecf96Smrg    interactive_arguments[1].type = LispCons_t;
3205dfecf96Smrg    interactive_arguments[1].data.cons.cdr = &interactive_arguments[2];
3215dfecf96Smrg    /* third argument is where to stop reparsing */
3225dfecf96Smrg    interactive_arguments[2].type = LispCons_t;
3235dfecf96Smrg    interactive_arguments[2].data.cons.cdr = &interactive_arguments[3];
3245dfecf96Smrg    /* fourth argument is interactive flag */
3255dfecf96Smrg    interactive_arguments[3].type = LispCons_t;
3265dfecf96Smrg    interactive_arguments[3].data.cons.car = T;
3275dfecf96Smrg    interactive_arguments[3].data.cons.cdr = NIL;
3285dfecf96Smrg
3295dfecf96Smrg    /* Load extra functions and data type definitions */
3305dfecf96Smrg    EXECUTE("(require \"xedit\")");
3315dfecf96Smrg
3325dfecf96Smrg
3335dfecf96Smrg    /*
3345dfecf96Smrg     *	This assumes that the *auto-modes* variable is a list where every
3355dfecf96Smrg     * item has the format:
3365dfecf96Smrg     *	    (regexp string-desc load-file-desc . symbol-name)
3375dfecf96Smrg     *	Minimal error checking is done.
3385dfecf96Smrg     */
3395dfecf96Smrg
3405dfecf96Smrg    if (Oauto_modes->data.atom->a_object) {
3415dfecf96Smrg	LispObj *desc, *modes = Oauto_modes->data.atom->property->value;
3425dfecf96Smrg
3435dfecf96Smrg	for (; CONSP(modes); modes = CDR(modes)) {
3445dfecf96Smrg	    list = CAR(modes);
3455dfecf96Smrg
3465dfecf96Smrg	    desc = NIL;
3475dfecf96Smrg	    for (i = 0; i < 3 && CONSP(list); i++, list = CDR(list)) {
3485dfecf96Smrg		if (i == 1)
3495dfecf96Smrg		    desc = CAR(list);
3505dfecf96Smrg	    }
3515dfecf96Smrg	    if (i == 3 && STRINGP(desc)) {
3525dfecf96Smrg		mode_infos = (EditModeInfo*)
3535dfecf96Smrg		    XtRealloc((XtPointer)mode_infos, sizeof(EditModeInfo) *
3545dfecf96Smrg			      (num_mode_infos + 1));
3555dfecf96Smrg		mode_infos[num_mode_infos].desc = XtNewString(THESTR(desc));
3565dfecf96Smrg		mode_infos[num_mode_infos].symbol = list;
3575dfecf96Smrg		mode_infos[num_mode_infos].syntax = NULL;
3585dfecf96Smrg		++num_mode_infos;
3595dfecf96Smrg	    }
3605dfecf96Smrg	}
3615dfecf96Smrg    }
3625dfecf96Smrg}
3635dfecf96Smrg
3645dfecf96Smrgstatic void
3655dfecf96SmrgXeditUpdateModeInfos(void)
3665dfecf96Smrg{
3675dfecf96Smrg    int i;
3685dfecf96Smrg
3695dfecf96Smrg    for (i = 0; i < num_mode_infos; i++) {
3705dfecf96Smrg	if (mode_infos[i].symbol &&
3715dfecf96Smrg	    mode_infos[i].syntax == NULL &&
3725dfecf96Smrg	    XSYMBOLP(mode_infos[i].symbol) &&
3735dfecf96Smrg	    mode_infos[i].symbol->data.atom->a_object)
3745dfecf96Smrg	    mode_infos[i].syntax =
3755dfecf96Smrg		mode_infos[i].symbol->data.atom->property->value;
3765dfecf96Smrg    }
3775dfecf96Smrg}
3785dfecf96Smrg
3795dfecf96Smrgvoid
3805dfecf96SmrgXeditLispExecute(Widget output, XawTextPosition left, XawTextPosition right)
3815dfecf96Smrg{
3825dfecf96Smrg    GC_ENTER();
3835dfecf96Smrg    LISP_SETUP();
3845dfecf96Smrg    int alloced, return_count;
3855dfecf96Smrg    XawTextBlock block;
3865dfecf96Smrg    XawTextPosition position;
3875dfecf96Smrg    char *string, *ptr;
3885dfecf96Smrg    LispObj *result, *code, *_cod, *returns;
3895dfecf96Smrg
3905dfecf96Smrg    LISP_ENTER();
3915dfecf96Smrg
3925dfecf96Smrg    position = left;
3935dfecf96Smrg    XawTextSourceRead(XawTextGetSource(textwindow), left, &block, right - left);
3945dfecf96Smrg    if (block.length < right - left) {
3955dfecf96Smrg	alloced = 1;
3965dfecf96Smrg	string = ptr = LispMalloc(right - left);
3975dfecf96Smrg	memcpy(ptr, block.ptr, block.length);
3985dfecf96Smrg	position = left + block.length;
3995dfecf96Smrg	ptr += block.length;
4005dfecf96Smrg	for (; position < right;) {
4015dfecf96Smrg	    XawTextSourceRead(XawTextGetSource(textwindow),
4025dfecf96Smrg			      position, &block, right - position);
4035dfecf96Smrg	    memcpy(ptr, block.ptr, block.length);
4045dfecf96Smrg	    position += block.length;
4055dfecf96Smrg	    ptr += block.length;
4065dfecf96Smrg	}
4075dfecf96Smrg    }
4085dfecf96Smrg    else {
4095dfecf96Smrg	alloced = 0;
4105dfecf96Smrg	string = block.ptr;
4115dfecf96Smrg    }
4125dfecf96Smrg
4135dfecf96Smrg    execute_string.string = string;
4145dfecf96Smrg    execute_string.length = right - left;
4155dfecf96Smrg    execute_string.input = 0;
4165dfecf96Smrg    LispPushInput(&execute_stream);
4175dfecf96Smrg    _cod = COD;
4185dfecf96Smrg    result = NIL;
4195dfecf96Smrg    if ((code = LispRead()) != NULL)
4205dfecf96Smrg	result = EVAL(code);
4215dfecf96Smrg    COD = _cod;
4225dfecf96Smrg    LispPopInput(&execute_stream);
4235dfecf96Smrg
4245dfecf96Smrg    returns = NIL;
4255dfecf96Smrg    if (RETURN_COUNT > 0) {
4265dfecf96Smrg	GC_PROTECT(result);
4275dfecf96Smrg	returns = _cod = CONS(RETURN(0), NIL);
4285dfecf96Smrg	GC_PROTECT(returns);
4295dfecf96Smrg	for (return_count = 1; return_count < RETURN_COUNT; return_count++) {
4305dfecf96Smrg	    RPLACD(_cod, CONS(RETURN(return_count), NIL));
4315dfecf96Smrg	    _cod = CDR(_cod);
4325dfecf96Smrg	}
4335dfecf96Smrg    }
4345dfecf96Smrg    LispFflush(Stdout);
4355dfecf96Smrg    LispUpdateResults(code, result);
4365dfecf96Smrg    if (RETURN_COUNT >= 0) {
4375dfecf96Smrg	XeditPrint(output, result, 1);
4385dfecf96Smrg	for (; CONSP(returns); returns = CDR(returns))
4395dfecf96Smrg	    XeditPrint(output, CAR(returns), 0);
4405dfecf96Smrg    }
4415dfecf96Smrg
4425dfecf96Smrg    if (alloced)
4435dfecf96Smrg	LispFree(string);
4445dfecf96Smrg    GC_LEAVE();
4455dfecf96Smrg
4465dfecf96Smrg    LISP_LEAVE();
4475dfecf96Smrg}
4485dfecf96Smrg
4495dfecf96Smrgstatic void
4505dfecf96SmrgXeditPrint(Widget output, LispObj *object, int newline)
4515dfecf96Smrg{
4525dfecf96Smrg    XawTextBlock block;
4535dfecf96Smrg    XawTextPosition position;
4545dfecf96Smrg
4555dfecf96Smrg    result_string.length = result_string.output = 0;
4565dfecf96Smrg    if (newline) {
4575dfecf96Smrg	position = XawTextGetInsertionPoint(output);
4585dfecf96Smrg	if (position != XawTextSourceScan(XawTextGetSource(output),
4595dfecf96Smrg					  position, XawstEOL,
4605dfecf96Smrg					  XawsdLeft, 1, False))
4615dfecf96Smrg	    LispSputc(&result_string, '\n');
4625dfecf96Smrg    }
4635dfecf96Smrg    LispWriteObject(&result_stream, object);
4645dfecf96Smrg    LispSputc(&result_string, '\n');
4655dfecf96Smrg
4665dfecf96Smrg    position = XawTextGetInsertionPoint(output);
4675dfecf96Smrg    block.firstPos = 0;
4685dfecf96Smrg    block.format = FMT8BIT;
4695dfecf96Smrg    block.length = result_string.length;
4705dfecf96Smrg    block.ptr = result_string.string;
4715dfecf96Smrg    XawTextReplace(output, position, position, &block);
4725dfecf96Smrg    XawTextSetInsertionPoint(output, position + block.length);
4735dfecf96Smrg}
4745dfecf96Smrg
4755dfecf96Smrg/*
4765dfecf96Smrg *  This function is defined here to avoid exporting all the lisp interfaces
4775dfecf96Smrg * to the core xedit code.
4785dfecf96Smrg */
4795dfecf96Smrgvoid
4805dfecf96SmrgXeditLispSetEditMode(xedit_flist_item *item, LispObj *symbol)
4815dfecf96Smrg{
4825dfecf96Smrg    GC_ENTER();
4835dfecf96Smrg    LISP_SETUP();
4845dfecf96Smrg    LispObj *syntax, *name;
4855dfecf96Smrg
4865dfecf96Smrg    item->xldata = (XeditLispData*)XtCalloc(1, sizeof(XeditLispData));
4875dfecf96Smrg
4885dfecf96Smrg    LISP_ENTER();
4895dfecf96Smrg
4905dfecf96Smrg    /* Create an object that represents the buffer filename.
4915dfecf96Smrg     * Note that the entire path is passed to the auto-mode
4925dfecf96Smrg     * function, so that directory names may be also be used
4935dfecf96Smrg     * when determining a file type. */
4945dfecf96Smrg    name = STRING(item->filename);
4955dfecf96Smrg    GC_PROTECT(name);
4965dfecf96Smrg
4975dfecf96Smrg    /*  Call the AUTO-MODE function to check if there is a
4985dfecf96Smrg     * syntax definition for the file being loaded */
4995dfecf96Smrg    if (symbol == NULL)
5005dfecf96Smrg	syntax = APPLY1(Oauto_mode, name);
5015dfecf96Smrg    else
5025dfecf96Smrg	syntax = APPLY2(Oauto_mode, name, symbol);
5035dfecf96Smrg
5045dfecf96Smrg    /* Don't need the name object anymore */
5055dfecf96Smrg    GC_LEAVE();
5065dfecf96Smrg
5075dfecf96Smrg    if (syntax != NIL) {
5085dfecf96Smrg	Arg arg[1];
5095dfecf96Smrg	LispObj arguments;
5105dfecf96Smrg	XawTextPropertyList *property_list;
5115dfecf96Smrg
5125dfecf96Smrg	item->xldata->syntax = syntax;
5135dfecf96Smrg
5145dfecf96Smrg	/* Apply the syntax highlight to the current buffer */
5155dfecf96Smrg	arguments.type = LispCons_t;
5165dfecf96Smrg	arguments.data.cons.car = syntax;
5175dfecf96Smrg	arguments.data.cons.cdr = NIL;
5185dfecf96Smrg	LispFuncall(Osyntax_highlight, &arguments, 1);
5195dfecf96Smrg
5205dfecf96Smrg	/*  The previous call added the property list to the widget,
5215dfecf96Smrg	 * remember it when switching sources. */
5225dfecf96Smrg	XtSetArg(arg[0], XawNtextProperties, &property_list);
5235dfecf96Smrg	XtGetValues(XawTextGetSink(textwindow), arg, 1);
5245dfecf96Smrg	item->properties = property_list;
5255dfecf96Smrg
5265dfecf96Smrg	/* Add callback for interactive changes */
5275dfecf96Smrg	XtAddCallback(item->source, XtNpropertyCallback,
5285dfecf96Smrg		      XeditInteractiveCallback, item->xldata);
5295dfecf96Smrg
5305dfecf96Smrg	/* Update information as a new file may have been loaded */
5315dfecf96Smrg	XeditUpdateModeInfos();
5325dfecf96Smrg    }
5335dfecf96Smrg    else
5345dfecf96Smrg	item->properties = NULL;
5355dfecf96Smrg
5365dfecf96Smrg    LISP_LEAVE();
5375dfecf96Smrg}
5385dfecf96Smrg
5395dfecf96Smrgvoid
5405dfecf96SmrgXeditLispUnsetEditMode(xedit_flist_item *item)
5415dfecf96Smrg{
5425dfecf96Smrg    if (item->xldata) {
5435dfecf96Smrg	XtRemoveCallback(item->source, XtNpropertyCallback,
5445dfecf96Smrg			 XeditInteractiveCallback, item->xldata);
5455dfecf96Smrg	XtFree((XtPointer)item->xldata);
5465dfecf96Smrg	item->xldata = NULL;
5475dfecf96Smrg    }
5485dfecf96Smrg}
5495dfecf96Smrg
5505dfecf96Smrg#define MAX_INFOS	32
5515dfecf96Smrg/*
5525dfecf96Smrg *  This callback tries to do it's best in generating correct output while
5535dfecf96Smrg * also doing minimal work/redrawing of the screen. It probably will fail
5545dfecf96Smrg * for some syntax-definitions, or will just not properly repaint the
5555dfecf96Smrg * screen. In the later case, just press Ctrl+L.
5565dfecf96Smrg *  There isn't yet any command to force reparsing of some regions, and if
5575dfecf96Smrg * the parser becomes confused, you may need to go to a line, press a space
5585dfecf96Smrg * and undo, just to force it to reparse the line, and possibly some extra
5595dfecf96Smrg * lines until the parser thinks the display is in sync.
5605dfecf96Smrg *  Sometimes it will repaint a lot more of text than what is being requested
5615dfecf96Smrg * by this callback, this should be fixed at some time, as for certain cases
5625dfecf96Smrg * it is also required some redesign in the Xaw interface.
5635dfecf96Smrg */
5645dfecf96Smrgstatic void
5655dfecf96SmrgXeditInteractiveCallback(Widget w, XtPointer client_data, XtPointer call_data)
5665dfecf96Smrg{
5675dfecf96Smrg    LISP_SETUP();
5685dfecf96Smrg    XeditLispData *data = (XeditLispData*)client_data;
5695dfecf96Smrg    LispObj *syntax = data->syntax;
5705dfecf96Smrg    XawTextPropertyInfo *info = (XawTextPropertyInfo*)call_data;
5715dfecf96Smrg    LispObj *result, *syntable;
5725dfecf96Smrg    XawTextAnchor *anchor;
5735dfecf96Smrg    XawTextEntity *entity;
5745dfecf96Smrg    XawTextPosition first, last, left, right, begin, next, tmp, position;
5755dfecf96Smrg    int i, j, indent;
5765dfecf96Smrg    TextSrcObject src = (TextSrcObject)w;
5775dfecf96Smrg    EntityInfo oinfo[MAX_INFOS], ninfo[MAX_INFOS];
5785dfecf96Smrg    XrmQuark props[MAX_INFOS];
5795dfecf96Smrg    int num_oinfo, num_ninfo, num_props;
5805dfecf96Smrg    XmuScanline *clip, *oclip, *nclip;
5815dfecf96Smrg    XmuSegment segment, *seg;
5825dfecf96Smrg
5835dfecf96Smrg    if (data->disable_highlight)
5845dfecf96Smrg	return;
5855dfecf96Smrg
5865dfecf96Smrg    LISP_ENTER();
5875dfecf96Smrg
5885dfecf96Smrg    first = XawTextSourceScan(w, 0, XawstAll, XawsdLeft, 1, True);
5895dfecf96Smrg    last = XawTextSourceScan(w, 0, XawstAll, XawsdRight, 1, True);
5905dfecf96Smrg
5915dfecf96Smrg    left = info->left;
5925dfecf96Smrg    right = left + info->block->length;
5935dfecf96Smrg
5945dfecf96Smrg    /* For now, only call the indent hook if a single character was typed */
5955dfecf96Smrg    indent = (info->right == left) && (right == left + 1);
5965dfecf96Smrg
5975dfecf96Smrg    /* Always reparse full lines */
5985dfecf96Smrg    left = begin = XawTextSourceScan(w, left, XawstEOL, XawsdLeft, 1, False);
5995dfecf96Smrg    right = next = XawTextSourceScan(w, right, XawstEOL, XawsdRight, 1, False);
6005dfecf96Smrg
6015dfecf96Smrg
6025dfecf96Smrg    /*  Check properties in the modified text. If a complex nested syntax
6035dfecf96Smrg     * table was parsed, the newline has it's default property, so, while
6045dfecf96Smrg     * the newline has a property, backup a line to make sure everything is
6055dfecf96Smrg     * properly parsed.
6065dfecf96Smrg     *  Maybe should limit the number of backuped lines, but if the parsing
6075dfecf96Smrg     * becomes noticeable slow, better to rethink the syntax definition. */
6085dfecf96Smrg    while (left > first) {
6095dfecf96Smrg	position = XawTextSourceScan(w, left, XawstEOL, XawsdLeft, 1, True);
6105dfecf96Smrg	if (XawTextSourceAnchorAndEntity(w, position, &anchor, &entity))
6115dfecf96Smrg	    left = XawTextSourceScan(w, left, XawstEOL, XawsdLeft, 2, False);
6125dfecf96Smrg	else
6135dfecf96Smrg	    break;
6145dfecf96Smrg    }
6155dfecf96Smrg
6165dfecf96Smrg    /*	While the newline after the right position has a "hidden" property,
6175dfecf96Smrg     * keep incrementing a line to be reparsed. */
6185dfecf96Smrg    while (right < last) {
6195dfecf96Smrg	if (XawTextSourceAnchorAndEntity(w, right, &anchor, &entity))
6205dfecf96Smrg	    right = XawTextSourceScan(w, right, XawstEOL, XawsdRight, 2, False);
6215dfecf96Smrg	else
6225dfecf96Smrg	    break;
6235dfecf96Smrg    }
6245dfecf96Smrg
6255dfecf96Smrg#ifndef MAX
6265dfecf96Smrg#define MAX(a, b)	((a) > (b) ? (a) : (b))
6275dfecf96Smrg#endif
6285dfecf96Smrg
6295dfecf96Smrg#ifndef MIN
6305dfecf96Smrg#define MIN(a, b)	((a) < (b) ? (a) : (b))
6315dfecf96Smrg#endif
6325dfecf96Smrg
6335dfecf96Smrg#define STORE_STATE(count, info, from, to)				\
6345dfecf96Smrg    (count) = 0;							\
6355dfecf96Smrg    if ((anchor = XawTextSourceFindAnchor(w, (from))) != NULL) {	\
6365dfecf96Smrg	entity = anchor->entities;					\
6375dfecf96Smrg	/* Find first entity in the region to parse */			\
6385dfecf96Smrg	while (entity &&						\
6395dfecf96Smrg	       anchor->position + entity->offset + entity->length <=	\
6405dfecf96Smrg	       (from))							\
6415dfecf96Smrg	    entity = entity->next;					\
6425dfecf96Smrg	/* Loop storing information */					\
6435dfecf96Smrg	while (entity &&						\
6445dfecf96Smrg	    (position = anchor->position + entity->offset) < (to)) {	\
6455dfecf96Smrg	    (info)[(count)].left = MAX(position, (from));		\
6465dfecf96Smrg	    position += entity->length;					\
6475dfecf96Smrg	    (info)[(count)].right = MIN(position, (to));		\
6485dfecf96Smrg	    (info)[(count)].property = entity->property;		\
6495dfecf96Smrg	    /* If the changes are so complex, user need press Ctrl+L */	\
6505dfecf96Smrg	    if (++(count) >= MAX_INFOS)					\
6515dfecf96Smrg		break;							\
6525dfecf96Smrg	    if ((entity = entity->next) == NULL &&			\
6535dfecf96Smrg		(anchor = XawTextSourceNextAnchor(w, anchor)) != NULL)	\
6545dfecf96Smrg		entity = anchor->entities;				\
6555dfecf96Smrg	}								\
6565dfecf96Smrg    }
6575dfecf96Smrg
6585dfecf96Smrg    /* Remember old state */
6595dfecf96Smrg    STORE_STATE(num_oinfo, oinfo, begin, right);
6605dfecf96Smrg
6615dfecf96Smrg    /* Reparse the lines in the modified/edited range of text */
6625dfecf96Smrg    interactive_arguments[0].data.cons.car = syntax;
6635dfecf96Smrg    interactive_arguments[1].data.cons.car = FIXNUM(left);
6645dfecf96Smrg    interactive_arguments[2].data.cons.car = FIXNUM(right);
6655dfecf96Smrg    result = APPLY(Osyntax_highlight, &interactive_arguments[0]);
6665dfecf96Smrg    /* Indent table is the second return value */
6675dfecf96Smrg    if (RETURN_COUNT)
6685dfecf96Smrg	syntable = RETURN(0);
6695dfecf96Smrg    else
6705dfecf96Smrg	syntable = NIL;
6715dfecf96Smrg
6725dfecf96Smrg    /* This normally is the same value as right, but the parser may have
6735dfecf96Smrg     * continued when the syntax table stack did not finish. */
6745dfecf96Smrg    if (FIXNUMP(result))
6755dfecf96Smrg	right = FIXNUM_VALUE(result);
6765dfecf96Smrg
6775dfecf96Smrg    LISP_LEAVE();
6785dfecf96Smrg
6795dfecf96Smrg    /* Check what have changed */
6805dfecf96Smrg    STORE_STATE(num_ninfo, ninfo, begin, right);
6815dfecf96Smrg
6825dfecf96Smrg    /* Initialize to redraw everything. */
6835dfecf96Smrg    clip = XmuNewScanline(0, begin, right);
6845dfecf96Smrg
6855dfecf96Smrg#define CLIP_MASK(mask, from, to)					\
6865dfecf96Smrg    if ((from) < (to)) {						\
6875dfecf96Smrg	segment.x1 = (from);						\
6885dfecf96Smrg	segment.x2 = (to);						\
6895dfecf96Smrg	XmuScanlineOrSegment((mask), &segment);				\
6905dfecf96Smrg    }
6915dfecf96Smrg
6925dfecf96Smrg    oclip = XmuNewScanline(0, 0, 0);
6935dfecf96Smrg    nclip = XmuNewScanline(0, 0, 0);
6945dfecf96Smrg
6955dfecf96Smrg#define CLIP_DEFAULT(mask, from, info, num_info)			\
6965dfecf96Smrg    for (tmp = (from), i = 0; i < (num_info); i++) {			\
6975dfecf96Smrg	CLIP_MASK((mask), tmp, (info)[i].left);				\
6985dfecf96Smrg	tmp = (info)[i].right;						\
6995dfecf96Smrg    }
7005dfecf96Smrg
7015dfecf96Smrg    /* First generate masks of regions with the default property */
7025dfecf96Smrg    CLIP_DEFAULT(oclip, begin, oinfo, num_oinfo);
7035dfecf96Smrg    CLIP_DEFAULT(nclip, begin, ninfo, num_ninfo);
7045dfecf96Smrg
7055dfecf96Smrg    /* Store unchanged region in oclip */
7065dfecf96Smrg    XmuScanlineAnd(oclip, nclip);
7075dfecf96Smrg
7085dfecf96Smrg    /* Don't need to redraw the region in oclip */
7095dfecf96Smrg    XmuScanlineXor(clip, oclip);
7105dfecf96Smrg
7115dfecf96Smrg#define LIST_PROPERTIES(prop, num_prop, info, num_info)			\
7125dfecf96Smrg    (num_prop) = 0;							\
7135dfecf96Smrg    for (i = 0; i < (num_info); i++) {					\
7145dfecf96Smrg	for (j = 0; j < (num_prop); j++)				\
7155dfecf96Smrg	    if ((prop)[j] == (info)[i].property)			\
7165dfecf96Smrg		break;							\
7175dfecf96Smrg	if (j == (num_prop))						\
7185dfecf96Smrg	    (prop)[(num_prop)++] = (info)[i].property;			\
7195dfecf96Smrg    }
7205dfecf96Smrg
7215dfecf96Smrg    /* Prepare to generate masks of regions of text with defined properties */
7225dfecf96Smrg    LIST_PROPERTIES(props, num_props, oinfo, num_oinfo);
7235dfecf96Smrg
7245dfecf96Smrg#define CLIP_PROPERTY(mask, prop, info, num_info)			\
7255dfecf96Smrg    for (j = 0; j < (num_info); j++) {					\
7265dfecf96Smrg	if ((info)[j].property == (prop)) {				\
7275dfecf96Smrg	    CLIP_MASK((mask), (info)[j].left, (info)[j].right);		\
7285dfecf96Smrg	}								\
7295dfecf96Smrg    }
7305dfecf96Smrg
7315dfecf96Smrg    /* Only care about the old properties, new ones need to be redrawn */
7325dfecf96Smrg    for (i = 0; i < num_props; i++) {
7335dfecf96Smrg	XrmQuark property = props[i];
7345dfecf96Smrg
7355dfecf96Smrg	/* Reset oclip and nclip */
7365dfecf96Smrg	XmuScanlineXor(oclip, oclip);
7375dfecf96Smrg	XmuScanlineXor(nclip, nclip);
7385dfecf96Smrg
7395dfecf96Smrg	/* Generate masks */
7405dfecf96Smrg	CLIP_PROPERTY(oclip, property, oinfo, num_oinfo);
7415dfecf96Smrg	CLIP_PROPERTY(nclip, property, ninfo, num_ninfo);
7425dfecf96Smrg
7435dfecf96Smrg	/* Store unchanged region in oclip */
7445dfecf96Smrg	XmuScanlineAnd(oclip, nclip);
7455dfecf96Smrg
7465dfecf96Smrg	/* Don't need to redraw the region in oclip */
7475dfecf96Smrg	XmuScanlineXor(clip, oclip);
7485dfecf96Smrg	XmuOptimizeScanline(clip);
7495dfecf96Smrg    }
7505dfecf96Smrg
7515dfecf96Smrg    XmuDestroyScanline(oclip);
7525dfecf96Smrg    XmuDestroyScanline(nclip);
7535dfecf96Smrg
7545dfecf96Smrg    /* Tell Xaw that need update some regions */
7555dfecf96Smrg    for (seg = clip->segment; seg; seg = seg->next) {
7565dfecf96Smrg	for (i = 0; i < src->textSrc.num_text; i++)
7575dfecf96Smrg	    /* This really should have an exported interface... */
7585dfecf96Smrg	    _XawTextNeedsUpdating((TextWidget)(src->textSrc.text[i]),
7595dfecf96Smrg				  seg->x1, seg->x2 + (seg->x2 > next));
7605dfecf96Smrg    }
7615dfecf96Smrg    XmuDestroyScanline(clip);
7625dfecf96Smrg
7635dfecf96Smrg    data->syntable = syntable;
7645dfecf96Smrg    /* XXX check lisp__running to know if at the toplevel parsing state */
7655dfecf96Smrg    if (indent && syntable != NIL && !lisp__running &&
7665dfecf96Smrg	/* Doing an undo, probably will need an exported interface for this
7675dfecf96Smrg	 * case. Should not change the text now. */
7685dfecf96Smrg	(!src->textSrc.enable_undo || !src->textSrc.undo_state))
7695dfecf96Smrg	XtAddCallback(textwindow, XtNpositionCallback,
7705dfecf96Smrg		      XeditIndentationCallback, data);
7715dfecf96Smrg}
7725dfecf96Smrg
7735dfecf96Smrg/*
7745dfecf96Smrg * This callback is called if the syntax table where the cursor is located
7755dfecf96Smrg * defines an indentation function.
7765dfecf96Smrg */
7775dfecf96Smrgstatic void
7785dfecf96SmrgXeditIndentationCallback(Widget w, XtPointer client_data, XtPointer call_data)
7795dfecf96Smrg{
7805dfecf96Smrg    LISP_SETUP();
7815dfecf96Smrg    LispObj *indentp;
7825dfecf96Smrg    XeditLispData *data = (XeditLispData*)client_data;
7835dfecf96Smrg
7845dfecf96Smrg    data->disable_highlight = True;
7855dfecf96Smrg    XtRemoveCallback(w, XtNpositionCallback, XeditIndentationCallback, data);
7865dfecf96Smrg
7875dfecf96Smrg    LISP_ENTER();
7885dfecf96Smrg
7895dfecf96Smrg    /* Get pointer to indentation function */
7905dfecf96Smrg    indentp = APPLY1(Osyntable_indent, data->syntable);
7915dfecf96Smrg
7925dfecf96Smrg    /* Execute indentation function */
7935dfecf96Smrg    if (indentp != NIL)
7945dfecf96Smrg	APPLY2(indentp, data->syntax, data->syntable);
7955dfecf96Smrg
7965dfecf96Smrg    data->disable_highlight = False;
7975dfecf96Smrg
7985dfecf96Smrg    LISP_LEAVE();
7995dfecf96Smrg}
8005dfecf96Smrg
8015dfecf96Smrg/************************************************************************
8025dfecf96Smrg * Builtin functions
8035dfecf96Smrg ************************************************************************/
8045dfecf96SmrgLispObj *
8055dfecf96SmrgXedit_AddEntity(LispBuiltin *builtin)
8065dfecf96Smrg/*
8075dfecf96Smrg add-entity offset length identifier
8085dfecf96Smrg */
8095dfecf96Smrg{
8105dfecf96Smrg    LispObj *offset, *length, *identifier;
8115dfecf96Smrg
8125dfecf96Smrg    identifier = ARGUMENT(2);
8135dfecf96Smrg    length = ARGUMENT(1);
8145dfecf96Smrg    offset = ARGUMENT(0);
8155dfecf96Smrg
8165dfecf96Smrg    CHECK_INDEX(offset);
8175dfecf96Smrg    CHECK_INDEX(length);
8185dfecf96Smrg    CHECK_LONGINT(identifier);
8195dfecf96Smrg
8205dfecf96Smrg    return (XawTextSourceAddEntity(XawTextGetSource(textwindow), 0, 0, NULL,
8215dfecf96Smrg				   FIXNUM_VALUE(offset), FIXNUM_VALUE(length),
8225dfecf96Smrg				   LONGINT_VALUE(identifier)) ? T : NIL);
8235dfecf96Smrg}
8245dfecf96Smrg
8255dfecf96SmrgLispObj *
8265dfecf96SmrgXedit_AutoFill(LispBuiltin *builtin)
8275dfecf96Smrg/*
8285dfecf96Smrg auto-fill &optional value
8295dfecf96Smrg */
8305dfecf96Smrg{
8315dfecf96Smrg    Arg arg[1];
8325dfecf96Smrg    Boolean state;
8335dfecf96Smrg
8345dfecf96Smrg    LispObj *value;
8355dfecf96Smrg
8365dfecf96Smrg    value = ARGUMENT(0);
8375dfecf96Smrg
8385dfecf96Smrg    if (value != UNSPEC) {
8395dfecf96Smrg	XtSetArg(arg[0], XtNautoFill, value == NIL ? False : True);
8405dfecf96Smrg	XtSetValues(textwindow, arg, 1);
8415dfecf96Smrg    }
8425dfecf96Smrg    else {
8435dfecf96Smrg	XtSetArg(arg[0], XtNautoFill, &state);
8445dfecf96Smrg	XtGetValues(textwindow, arg, 1);
8455dfecf96Smrg	value = state ? T : NIL;
8465dfecf96Smrg    }
8475dfecf96Smrg
8485dfecf96Smrg    return (value);
8495dfecf96Smrg}
8505dfecf96Smrg
8515dfecf96SmrgLispObj *
8525dfecf96SmrgXedit_Background(LispBuiltin *builtin)
8535dfecf96Smrg/*
8545dfecf96Smrg background &optional color
8555dfecf96Smrg */
8565dfecf96Smrg{
8575dfecf96Smrg    Pixel pixel;
8585dfecf96Smrg    Arg arg[1];
8595dfecf96Smrg    XrmValue from, to;
8605dfecf96Smrg
8615dfecf96Smrg    LispObj *color;
8625dfecf96Smrg
8635dfecf96Smrg    color = ARGUMENT(0);
8645dfecf96Smrg
8655dfecf96Smrg    if (color != UNSPEC) {
8665dfecf96Smrg	CHECK_STRING(color);
8675dfecf96Smrg
8685dfecf96Smrg	from.size = STRLEN(color);
8695dfecf96Smrg	from.addr = (XtPointer)THESTR(color);
8705dfecf96Smrg	to.size = sizeof(Pixel);
8715dfecf96Smrg	to.addr = (XtPointer)&pixel;
8725dfecf96Smrg
8735dfecf96Smrg	if (!XtConvertAndStore(XawTextGetSink(textwindow),
8745dfecf96Smrg			       XtRString, &from, XtRPixel, &to))
8755dfecf96Smrg	    LispDestroy("cannot convert %s to Pixel", STROBJ(color));
8765dfecf96Smrg
8775dfecf96Smrg	XtSetArg(arg[0], XtNbackground, pixel);
8785dfecf96Smrg	XtSetValues(textwindow, arg, 1);
8795dfecf96Smrg    }
8805dfecf96Smrg    else {
8815dfecf96Smrg	from.size = sizeof(Pixel);
8825dfecf96Smrg	from.addr = (XtPointer)&pixel;
8835dfecf96Smrg	to.size = 0;
8845dfecf96Smrg	to.addr = NULL;
8855dfecf96Smrg
8865dfecf96Smrg	XtSetArg(arg[0], XtNbackground, &pixel);
8875dfecf96Smrg	XtGetValues(XawTextGetSink(textwindow), arg, 1);
8885dfecf96Smrg	/* This cannot fail */
8895dfecf96Smrg	XtConvertAndStore(textwindow, XtRPixel, &from, XtRString, &to);
8905dfecf96Smrg
8915dfecf96Smrg	color = STRING(to.addr);
8925dfecf96Smrg    }
8935dfecf96Smrg
8945dfecf96Smrg    return (color);
8955dfecf96Smrg}
8965dfecf96Smrg
8975dfecf96Smrgstatic LispObj *
8985dfecf96SmrgXeditCharAt(LispBuiltin *builtin, int before)
8995dfecf96Smrg{
9005dfecf96Smrg    Widget source = XawTextGetSource(textwindow);
9015dfecf96Smrg    XawTextPosition first, point, last;
9025dfecf96Smrg    XawTextBlock block;
9035dfecf96Smrg
9045dfecf96Smrg    LispObj *offset;
9055dfecf96Smrg
9065dfecf96Smrg    offset = ARGUMENT(0);
9075dfecf96Smrg    if (offset != UNSPEC) {
9085dfecf96Smrg	CHECK_INDEX(offset);
9095dfecf96Smrg    }
9105dfecf96Smrg
9115dfecf96Smrg    first = XawTextSourceScan(source, 0, XawstAll, XawsdLeft, 1, True);
9125dfecf96Smrg    if (FIXNUMP(offset))
9135dfecf96Smrg	point = FIXNUM_VALUE(offset);
9145dfecf96Smrg    else
9155dfecf96Smrg	point = XawTextGetInsertionPoint(textwindow);
9165dfecf96Smrg    if (before && point > first) {
9175dfecf96Smrg	XawTextPosition position =
9185dfecf96Smrg	    XawTextSourceScan(source, point, XawstPositions, XawsdLeft, 1, True);
9195dfecf96Smrg
9205dfecf96Smrg	if (position < point)
9215dfecf96Smrg	    point = position;
9225dfecf96Smrg	else
9235dfecf96Smrg	    return (NIL);
9245dfecf96Smrg    }
9255dfecf96Smrg    last = XawTextSourceScan(source, 0, XawstAll, XawsdRight, 1, True);
9265dfecf96Smrg
9275dfecf96Smrg    if (point < first || point > last)
9285dfecf96Smrg	return (NIL);
9295dfecf96Smrg
9305dfecf96Smrg    XawTextSourceRead(source, point, &block, 1);
9315dfecf96Smrg
9325dfecf96Smrg    return (block.length ? SCHAR(*(unsigned char*)block.ptr) : NIL);
9335dfecf96Smrg}
9345dfecf96Smrg
9355dfecf96SmrgLispObj *
9365dfecf96SmrgXedit_CharAfter(LispBuiltin *builtin)
9375dfecf96Smrg/*
9385dfecf96Smrg char-after &optional offset
9395dfecf96Smrg */
9405dfecf96Smrg{
9415dfecf96Smrg    return (XeditCharAt(builtin, 0));
9425dfecf96Smrg}
9435dfecf96Smrg
9445dfecf96SmrgLispObj *
9455dfecf96SmrgXedit_CharBefore(LispBuiltin *builtin)
9465dfecf96Smrg/*
9475dfecf96Smrg char-before &optional offset
9485dfecf96Smrg */
9495dfecf96Smrg{
9505dfecf96Smrg    return (XeditCharAt(builtin, 1));
9515dfecf96Smrg}
9525dfecf96Smrg
9535dfecf96SmrgLispObj *
9545dfecf96SmrgXedit_ClearEntities(LispBuiltin *builtin)
9555dfecf96Smrg/*
9565dfecf96Smrg clear-entities left right
9575dfecf96Smrg */
9585dfecf96Smrg{
9595dfecf96Smrg    LispObj *left, *right;
9605dfecf96Smrg
9615dfecf96Smrg    right = ARGUMENT(1);
9625dfecf96Smrg    left = ARGUMENT(0);
9635dfecf96Smrg
9645dfecf96Smrg    CHECK_INDEX(left);
9655dfecf96Smrg    CHECK_INDEX(right);
9665dfecf96Smrg
9675dfecf96Smrg    XawTextSourceClearEntities(XawTextGetSource(textwindow),
9685dfecf96Smrg			       FIXNUM_VALUE(left), FIXNUM_VALUE(right));
9695dfecf96Smrg
9705dfecf96Smrg    return (T);
9715dfecf96Smrg}
9725dfecf96Smrg
9735dfecf96SmrgLispObj *
9745dfecf96SmrgXedit_ConvertPropertyList(LispBuiltin *builtin)
9755dfecf96Smrg/*
9765dfecf96Smrg convert-property-list name definition
9775dfecf96Smrg */
9785dfecf96Smrg{
9795dfecf96Smrg    LispObj *result;
9805dfecf96Smrg    XawTextPropertyList *property_list;
9815dfecf96Smrg
9825dfecf96Smrg    LispObj *name, *definition;
9835dfecf96Smrg
9845dfecf96Smrg    definition = ARGUMENT(1);
9855dfecf96Smrg    name = ARGUMENT(0);
9865dfecf96Smrg
9875dfecf96Smrg    CHECK_STRING(name);
9885dfecf96Smrg    CHECK_STRING(definition);
9895dfecf96Smrg
9905dfecf96Smrg    result = NIL;
9915dfecf96Smrg    property_list = XawTextSinkConvertPropertyList(THESTR(name),
9925dfecf96Smrg						   THESTR(definition),
9935dfecf96Smrg						   topwindow->core.screen,
9945dfecf96Smrg						   topwindow->core.colormap,
9955dfecf96Smrg						   topwindow->core.depth);
9965dfecf96Smrg
9975dfecf96Smrg    if (property_list) {
9985dfecf96Smrg	Cardinal i;
9995dfecf96Smrg
10005dfecf96Smrg	for (i = 0; i < num_property_lists; i++)
10015dfecf96Smrg	    /* Check if a new property list was created */
10025dfecf96Smrg	    if (property_lists[i]->identifier == property_list->identifier)
10035dfecf96Smrg		break;
10045dfecf96Smrg
10055dfecf96Smrg	/* Remember this pointer when asked back for it */
10065dfecf96Smrg	if (i == num_property_lists) {
10075dfecf96Smrg	    property_lists = (XawTextPropertyList**)
10085dfecf96Smrg		XtRealloc((XtPointer)property_lists,
10095dfecf96Smrg			  sizeof(XawTextPropertyList) *
10105dfecf96Smrg			  (num_property_lists + 1));
10115dfecf96Smrg	    property_lists[num_property_lists++] = property_list;
10125dfecf96Smrg	}
10135dfecf96Smrg	result = INTEGER(property_list->identifier);
10145dfecf96Smrg    }
10155dfecf96Smrg
10165dfecf96Smrg    return (result);
10175dfecf96Smrg}
10185dfecf96Smrg
10195dfecf96SmrgLispObj *
10205dfecf96SmrgXedit_Font(LispBuiltin *builtin)
10215dfecf96Smrg/*
10225dfecf96Smrg font &optional font
10235dfecf96Smrg */
10245dfecf96Smrg{
10255dfecf96Smrg    XFontStruct *font_struct;
10265dfecf96Smrg    Arg arg[1];
10275dfecf96Smrg    XrmValue from, to;
10285dfecf96Smrg
10295dfecf96Smrg    LispObj *font;
10305dfecf96Smrg
10315dfecf96Smrg    font = ARGUMENT(0);
10325dfecf96Smrg
10335dfecf96Smrg    if (font != UNSPEC) {
10345dfecf96Smrg	CHECK_STRING(font);
10355dfecf96Smrg
10365dfecf96Smrg	from.size = STRLEN(font);
10375dfecf96Smrg	from.addr = (XtPointer)THESTR(font);
10385dfecf96Smrg	to.size = sizeof(XFontStruct*);
10395dfecf96Smrg	to.addr = (XtPointer)&font_struct;
10405dfecf96Smrg
10415dfecf96Smrg	if (!XtConvertAndStore(textwindow, XtRString, &from, XtRFontStruct, &to))
10425dfecf96Smrg	    LispDestroy("cannot convert %s to FontStruct", STROBJ(font));
10435dfecf96Smrg
10445dfecf96Smrg	XtSetArg(arg[0], XtNfont, font_struct);
10455dfecf96Smrg	XtSetValues(textwindow, arg, 1);
10465dfecf96Smrg    }
10475dfecf96Smrg    else {
10485dfecf96Smrg	from.size = sizeof(XFontStruct*);
10495dfecf96Smrg	from.addr = (XtPointer)&font_struct;
10505dfecf96Smrg	to.size = 0;
10515dfecf96Smrg	to.addr = NULL;
10525dfecf96Smrg
10535dfecf96Smrg	XtSetArg(arg[0], XtNfont, &font_struct);
10545dfecf96Smrg	XtGetValues(XawTextGetSink(textwindow), arg, 1);
10555dfecf96Smrg	/* This cannot fail */
10565dfecf96Smrg	XtConvertAndStore(textwindow, XtRFontStruct, &from, XtRString, &to);
10575dfecf96Smrg
10585dfecf96Smrg	font = STRING(to.addr);
10595dfecf96Smrg    }
10605dfecf96Smrg
10615dfecf96Smrg    return (font);
10625dfecf96Smrg}
10635dfecf96Smrg
10645dfecf96SmrgLispObj *
10655dfecf96SmrgXedit_Foreground(LispBuiltin *builtin)
10665dfecf96Smrg/*
10675dfecf96Smrg foreground &optional color
10685dfecf96Smrg */
10695dfecf96Smrg{
10705dfecf96Smrg    Pixel pixel;
10715dfecf96Smrg    Arg arg[1];
10725dfecf96Smrg    XrmValue from, to;
10735dfecf96Smrg
10745dfecf96Smrg    LispObj *color;
10755dfecf96Smrg
10765dfecf96Smrg    color = ARGUMENT(0);
10775dfecf96Smrg
10785dfecf96Smrg    if (color != UNSPEC) {
10795dfecf96Smrg	CHECK_STRING(color);
10805dfecf96Smrg
10815dfecf96Smrg	from.size = STRLEN(color);
10825dfecf96Smrg	from.addr = (XtPointer)THESTR(color);
10835dfecf96Smrg	to.size = sizeof(Pixel);
10845dfecf96Smrg	to.addr = (XtPointer)&pixel;
10855dfecf96Smrg
10865dfecf96Smrg	if (!XtConvertAndStore(XawTextGetSink(textwindow),
10875dfecf96Smrg			       XtRString, &from, XtRPixel, &to))
10885dfecf96Smrg	    LispDestroy("cannot convert %s to Pixel", STROBJ(color));
10895dfecf96Smrg
10905dfecf96Smrg	XtSetArg(arg[0], XtNforeground, pixel);
10915dfecf96Smrg	XtSetValues(textwindow, arg, 1);
10925dfecf96Smrg    }
10935dfecf96Smrg    else {
10945dfecf96Smrg	from.size = sizeof(Pixel);
10955dfecf96Smrg	from.addr = (XtPointer)&pixel;
10965dfecf96Smrg	to.size = 0;
10975dfecf96Smrg	to.addr = NULL;
10985dfecf96Smrg
10995dfecf96Smrg	XtSetArg(arg[0], XtNforeground, &pixel);
11005dfecf96Smrg	XtGetValues(XawTextGetSink(textwindow), arg, 1);
11015dfecf96Smrg	/* This cannot fail */
11025dfecf96Smrg	XtConvertAndStore(textwindow, XtRPixel, &from, XtRString, &to);
11035dfecf96Smrg
11045dfecf96Smrg	color = STRING(to.addr);
11055dfecf96Smrg    }
11065dfecf96Smrg
11075dfecf96Smrg    return (color);
11085dfecf96Smrg}
11095dfecf96Smrg
11105dfecf96SmrgLispObj *
11115dfecf96SmrgXedit_GotoChar(LispBuiltin *builtin)
11125dfecf96Smrg/*
11135dfecf96Smrg goto-char offset
11145dfecf96Smrg */
11155dfecf96Smrg{
11165dfecf96Smrg    LispObj *offset;
11175dfecf96Smrg    XawTextPosition point;
11185dfecf96Smrg
11195dfecf96Smrg    offset = ARGUMENT(0);
11205dfecf96Smrg
11215dfecf96Smrg    CHECK_INDEX(offset);
11225dfecf96Smrg    XawTextSetInsertionPoint(textwindow, FIXNUM_VALUE(offset));
11235dfecf96Smrg    point = XawTextGetInsertionPoint(textwindow);
11245dfecf96Smrg    if (point != FIXNUM_VALUE(offset))
11255dfecf96Smrg	offset = FIXNUM(point);
11265dfecf96Smrg
11275dfecf96Smrg    return (offset);
11285dfecf96Smrg}
11295dfecf96Smrg
11305dfecf96SmrgLispObj *
11315dfecf96SmrgXedit_HorizontalScrollbar(LispBuiltin *builtin)
11325dfecf96Smrg/*
11335dfecf96Smrg horizontal-scrollbar &optional state
11345dfecf96Smrg */
11355dfecf96Smrg{
11365dfecf96Smrg    Arg arg[1];
11375dfecf96Smrg    XawTextScrollMode scroll;
11385dfecf96Smrg
11395dfecf96Smrg    LispObj *state;
11405dfecf96Smrg
11415dfecf96Smrg    state = ARGUMENT(0);
11425dfecf96Smrg
11435dfecf96Smrg    if (state != UNSPEC) {
11445dfecf96Smrg	scroll = state == NIL ? XawtextScrollNever : XawtextScrollAlways;
11455dfecf96Smrg	XtSetArg(arg[0], XtNscrollHorizontal, scroll);
11465dfecf96Smrg	XtSetValues(textwindow, arg, 1);
11475dfecf96Smrg    }
11485dfecf96Smrg    else {
11495dfecf96Smrg	XtSetArg(arg[0], XtNscrollHorizontal, &scroll);
11505dfecf96Smrg	XtGetValues(textwindow, arg, 1);
11515dfecf96Smrg	state = scroll == XawtextScrollAlways ? T : NIL;
11525dfecf96Smrg    }
11535dfecf96Smrg
11545dfecf96Smrg    return (state);
11555dfecf96Smrg}
11565dfecf96Smrg
11575dfecf96SmrgLispObj *
11585dfecf96SmrgXedit_Insert(LispBuiltin *builtin)
11595dfecf96Smrg/*
11605dfecf96Smrg insert text
11615dfecf96Smrg */
11625dfecf96Smrg{
11635dfecf96Smrg    XawTextPosition point = XawTextGetInsertionPoint(textwindow);
11645dfecf96Smrg    XawTextBlock block;
11655dfecf96Smrg
11665dfecf96Smrg    LispObj *text;
11675dfecf96Smrg
11685dfecf96Smrg    text = ARGUMENT(0);
11695dfecf96Smrg
11705dfecf96Smrg    CHECK_STRING(text);
11715dfecf96Smrg
11725dfecf96Smrg    block.firstPos = 0;
11735dfecf96Smrg    block.format = FMT8BIT;
11745dfecf96Smrg    block.length = STRLEN(text);
11755dfecf96Smrg    block.ptr = THESTR(text);
11765dfecf96Smrg    XawTextReplace(textwindow, point, point, &block);
11775dfecf96Smrg    XawTextSetInsertionPoint(textwindow, point + block.length);
11785dfecf96Smrg
11795dfecf96Smrg    return (text);
11805dfecf96Smrg}
11815dfecf96Smrg
11825dfecf96SmrgLispObj *
11835dfecf96SmrgXedit_Justification(LispBuiltin *builtin)
11845dfecf96Smrg/*
11855dfecf96Smrg justification &optional value
11865dfecf96Smrg */
11875dfecf96Smrg{
11885dfecf96Smrg    int i;
11895dfecf96Smrg    Arg arg[1];
11905dfecf96Smrg    XawTextJustifyMode justify;
11915dfecf96Smrg
11925dfecf96Smrg    LispObj *value;
11935dfecf96Smrg
11945dfecf96Smrg    value = ARGUMENT(0);
11955dfecf96Smrg
11965dfecf96Smrg    if (value != UNSPEC) {
11975dfecf96Smrg	for (i = 0; i < 4; i++)
11985dfecf96Smrg	    if (value == justify_modes[i])
11995dfecf96Smrg		break;
12005dfecf96Smrg	if (i >= 4)
12015dfecf96Smrg	    LispDestroy("%s: argument must be "
12025dfecf96Smrg			":LEFT, :RIGHT, :CENTER, or :FULL, not %s",
12035dfecf96Smrg			STRFUN(builtin), STROBJ(value));
12045dfecf96Smrg	XtSetArg(arg[0], XtNjustifyMode, (XawTextJustifyMode)i);
12055dfecf96Smrg	XtSetValues(textwindow, arg, 1);
12065dfecf96Smrg    }
12075dfecf96Smrg    else {
12085dfecf96Smrg	XtSetArg(arg[0], XtNjustifyMode, &justify);
12095dfecf96Smrg	XtGetValues(textwindow, arg, 1);
12105dfecf96Smrg	i = (int)justify;
12115dfecf96Smrg	if (i <= 0 || i >= 4)
12125dfecf96Smrg	    i = 0;
12135dfecf96Smrg	value = justify_modes[i];
12145dfecf96Smrg    }
12155dfecf96Smrg
12165dfecf96Smrg    return (value);
12175dfecf96Smrg}
12185dfecf96Smrg
12195dfecf96SmrgLispObj *
12205dfecf96SmrgXedit_LeftColumn(LispBuiltin *builtin)
12215dfecf96Smrg/*
12225dfecf96Smrg left-column &optional left
12235dfecf96Smrg */
12245dfecf96Smrg{
12255dfecf96Smrg    short left;
12265dfecf96Smrg    Arg arg[1];
12275dfecf96Smrg
12285dfecf96Smrg    LispObj *oleft;
12295dfecf96Smrg
12305dfecf96Smrg    oleft = ARGUMENT(0);
12315dfecf96Smrg
12325dfecf96Smrg    if (oleft != UNSPEC) {
12335dfecf96Smrg	CHECK_INDEX(oleft);
12345dfecf96Smrg	if (FIXNUM_VALUE(oleft) >= 32767)
12355dfecf96Smrg	    left = 32767;
12365dfecf96Smrg	else
12375dfecf96Smrg	    left = FIXNUM_VALUE(oleft);
12385dfecf96Smrg
12395dfecf96Smrg	XtSetArg(arg[0], XtNleftColumn, left);
12405dfecf96Smrg	XtSetValues(textwindow, arg, 1);
12415dfecf96Smrg    }
12425dfecf96Smrg    else {
12435dfecf96Smrg	XtSetArg(arg[0], XtNleftColumn, &left);
12445dfecf96Smrg	XtGetValues(textwindow, arg, 1);
12455dfecf96Smrg
12465dfecf96Smrg	oleft = FIXNUM((long)left);
12475dfecf96Smrg    }
12485dfecf96Smrg
12495dfecf96Smrg    return (oleft);
12505dfecf96Smrg}
12515dfecf96Smrg
12525dfecf96SmrgLispObj *
12535dfecf96SmrgXedit_Point(LispBuiltin *builtin)
12545dfecf96Smrg/*
12555dfecf96Smrg point
12565dfecf96Smrg */
12575dfecf96Smrg{
12585dfecf96Smrg    return (FIXNUM(XawTextGetInsertionPoint(textwindow)));
12595dfecf96Smrg}
12605dfecf96Smrg
12615dfecf96SmrgLispObj *
12625dfecf96SmrgXedit_PointMax(LispBuiltin *builtin)
12635dfecf96Smrg/*
12645dfecf96Smrg point-max
12655dfecf96Smrg */
12665dfecf96Smrg{
12675dfecf96Smrg    return (FIXNUM(XawTextSourceScan(XawTextGetSource(textwindow), 0,
12685dfecf96Smrg				     XawstAll, XawsdRight, 1, True)));
12695dfecf96Smrg}
12705dfecf96Smrg
12715dfecf96SmrgLispObj *
12725dfecf96SmrgXedit_PointMin(LispBuiltin *builtin)
12735dfecf96Smrg/*
12745dfecf96Smrg point-min
12755dfecf96Smrg */
12765dfecf96Smrg{
12775dfecf96Smrg    return (FIXNUM(XawTextSourceScan(XawTextGetSource(textwindow), 0,
12785dfecf96Smrg				     XawstAll, XawsdLeft, 1, True)));
12795dfecf96Smrg}
12805dfecf96Smrg
12815dfecf96SmrgLispObj *
12825dfecf96SmrgXedit_PropertyList(LispBuiltin *builtin)
12835dfecf96Smrg/*
12845dfecf96Smrg property-list &optional value
12855dfecf96Smrg */
12865dfecf96Smrg{
12875dfecf96Smrg    Arg arg[1];
12885dfecf96Smrg    XawTextPropertyList *property_list;
12895dfecf96Smrg
12905dfecf96Smrg    LispObj *value;
12915dfecf96Smrg
12925dfecf96Smrg    value = ARGUMENT(0);
12935dfecf96Smrg
12945dfecf96Smrg    if (value != UNSPEC) {
12955dfecf96Smrg	Cardinal i;
12965dfecf96Smrg	XrmQuark quark;
12975dfecf96Smrg
12985dfecf96Smrg	CHECK_LONGINT(value);
12995dfecf96Smrg	property_list = NULL;
13005dfecf96Smrg	quark = LONGINT_VALUE(value);
13015dfecf96Smrg	for (i = 0; i < num_property_lists; i++)
13025dfecf96Smrg	    if (property_lists[i]->identifier == quark) {
13035dfecf96Smrg		property_list = property_lists[i];
13045dfecf96Smrg		break;
13055dfecf96Smrg	    }
13065dfecf96Smrg
13075dfecf96Smrg	if (property_list) {
13085dfecf96Smrg	    XtSetArg(arg[0], XawNtextProperties, property_list);
13095dfecf96Smrg	    XtSetValues(XawTextGetSink(textwindow), arg, 1);
13105dfecf96Smrg	}
13115dfecf96Smrg	else
13125dfecf96Smrg	    /* Maybe should generate an error here */
13135dfecf96Smrg	    value = NIL;
13145dfecf96Smrg    }
13155dfecf96Smrg    else {
13165dfecf96Smrg	XtSetArg(arg[0], XawNtextProperties, &property_list);
13175dfecf96Smrg	XtGetValues(XawTextGetSink(textwindow), arg, 1);
13185dfecf96Smrg	if (property_list)
13195dfecf96Smrg	    value = INTEGER(property_list->identifier);
13205dfecf96Smrg    }
13215dfecf96Smrg
13225dfecf96Smrg    return (value);
13235dfecf96Smrg}
13245dfecf96Smrg
13255dfecf96SmrgLispObj *
13265dfecf96SmrgXedit_ReadText(LispBuiltin *builtin)
13275dfecf96Smrg/*
13285dfecf96Smrg read-text offset length
13295dfecf96Smrg */
13305dfecf96Smrg{
13315dfecf96Smrg    XawTextPosition last = XawTextSourceScan(XawTextGetSource(textwindow), 0,
13325dfecf96Smrg					     XawstAll, XawsdRight, 1, True);
13335dfecf96Smrg    XawTextPosition from, to, len;
13345dfecf96Smrg    XawTextBlock block;
13355dfecf96Smrg    char *string, *ptr;
13365dfecf96Smrg
13375dfecf96Smrg    LispObj *offset, *length;
13385dfecf96Smrg
13395dfecf96Smrg    length = ARGUMENT(1);
13405dfecf96Smrg    offset = ARGUMENT(0);
13415dfecf96Smrg
13425dfecf96Smrg    CHECK_INDEX(offset);
13435dfecf96Smrg    CHECK_INDEX(length);
13445dfecf96Smrg
13455dfecf96Smrg    from = FIXNUM_VALUE(offset);
13465dfecf96Smrg    to = from + FIXNUM_VALUE(length);
13475dfecf96Smrg    if (from > last)
13485dfecf96Smrg	from = last;
13495dfecf96Smrg    if (to > last)
13505dfecf96Smrg	to = last;
13515dfecf96Smrg
13525dfecf96Smrg    if (from == to)
13535dfecf96Smrg	return (STRING(""));
13545dfecf96Smrg
13555dfecf96Smrg    len = to - from;
13565dfecf96Smrg    string = LispMalloc(len);
13575dfecf96Smrg
13585dfecf96Smrg    for (ptr = string; from < to;) {
13595dfecf96Smrg	XawTextSourceRead(XawTextGetSource(textwindow), from, &block, to - from);
13605dfecf96Smrg	memcpy(ptr, block.ptr, block.length);
13615dfecf96Smrg	ptr += block.length;
13625dfecf96Smrg	from += block.length;
13635dfecf96Smrg    }
13645dfecf96Smrg
13655dfecf96Smrg    return (LSTRING2(string, len));
13665dfecf96Smrg}
13675dfecf96Smrg
13685dfecf96SmrgLispObj *
13695dfecf96SmrgXedit_ReplaceText(LispBuiltin *builtin)
13705dfecf96Smrg/*
13715dfecf96Smrg replace-text left right text
13725dfecf96Smrg */
13735dfecf96Smrg{
13745dfecf96Smrg    XawTextPosition last = XawTextSourceScan(XawTextGetSource(textwindow), 0,
13755dfecf96Smrg					     XawstAll, XawsdRight, 1, True);
13765dfecf96Smrg    XawTextPosition left, right;
13775dfecf96Smrg    XawTextBlock block;
13785dfecf96Smrg
13795dfecf96Smrg    LispObj *oleft, *oright, *text;
13805dfecf96Smrg
13815dfecf96Smrg    text = ARGUMENT(2);
13825dfecf96Smrg    oright = ARGUMENT(1);
13835dfecf96Smrg    oleft = ARGUMENT(0);
13845dfecf96Smrg
13855dfecf96Smrg    CHECK_INDEX(oleft);
13865dfecf96Smrg    CHECK_INDEX(oright);
13875dfecf96Smrg    CHECK_STRING(text);
13885dfecf96Smrg
13895dfecf96Smrg    left = FIXNUM_VALUE(oleft);
13905dfecf96Smrg    right = FIXNUM_VALUE(oright);
13915dfecf96Smrg    if (left > last)
13925dfecf96Smrg	left = last;
13935dfecf96Smrg    if (left > right)
13945dfecf96Smrg	right = left;
13955dfecf96Smrg    else if (right > last)
13965dfecf96Smrg	right = last;
13975dfecf96Smrg
13985dfecf96Smrg    block.firstPos = 0;
13995dfecf96Smrg    block.format = FMT8BIT;
14005dfecf96Smrg    block.length = STRLEN(text);
14015dfecf96Smrg    block.ptr = THESTR(text);
14025dfecf96Smrg    XawTextReplace(textwindow, left, right, &block);
14035dfecf96Smrg
14045dfecf96Smrg    return (text);
14055dfecf96Smrg}
14065dfecf96Smrg
14075dfecf96SmrgLispObj *
14085dfecf96SmrgXedit_RightColumn(LispBuiltin *builtin)
14095dfecf96Smrg/*
14105dfecf96Smrg right-column &optional right
14115dfecf96Smrg */
14125dfecf96Smrg{
14135dfecf96Smrg    short right;
14145dfecf96Smrg    Arg arg[1];
14155dfecf96Smrg
14165dfecf96Smrg    LispObj *oright;
14175dfecf96Smrg
14185dfecf96Smrg    oright = ARGUMENT(0);
14195dfecf96Smrg
14205dfecf96Smrg    if (oright != UNSPEC) {
14215dfecf96Smrg	CHECK_INDEX(oright);
14225dfecf96Smrg	if (FIXNUM_VALUE(oright) >= 32767)
14235dfecf96Smrg	    right = 32767;
14245dfecf96Smrg	else
14255dfecf96Smrg	    right = FIXNUM_VALUE(oright);
14265dfecf96Smrg
14275dfecf96Smrg	XtSetArg(arg[0], XtNrightColumn, right);
14285dfecf96Smrg	XtSetValues(textwindow, arg, 1);
14295dfecf96Smrg    }
14305dfecf96Smrg    else {
14315dfecf96Smrg	XtSetArg(arg[0], XtNrightColumn, &right);
14325dfecf96Smrg	XtGetValues(textwindow, arg, 1);
14335dfecf96Smrg
14345dfecf96Smrg	oright = FIXNUM(right);
14355dfecf96Smrg    }
14365dfecf96Smrg
14375dfecf96Smrg    return (oright);
14385dfecf96Smrg}
14395dfecf96Smrg
14405dfecf96SmrgLispObj *
14415dfecf96SmrgXedit_Scan(LispBuiltin *builtin)
14425dfecf96Smrg/*
14435dfecf96Smrg scan offset type direction &key count include
14445dfecf96Smrg */
14455dfecf96Smrg{
14465dfecf96Smrg    int i;
14475dfecf96Smrg    XawTextPosition offset;
14485dfecf96Smrg    XawTextScanType type;
14495dfecf96Smrg    XawTextScanDirection direction;
14505dfecf96Smrg    int count;
14515dfecf96Smrg
14525dfecf96Smrg    LispObj *ooffset, *otype, *odirection, *ocount, *include;
14535dfecf96Smrg
14545dfecf96Smrg    include = ARGUMENT(4);
14555dfecf96Smrg    if (include == UNSPEC)
14565dfecf96Smrg	include = NIL;
14575dfecf96Smrg    ocount = ARGUMENT(3);
14585dfecf96Smrg    odirection = ARGUMENT(2);
14595dfecf96Smrg    otype = ARGUMENT(1);
14605dfecf96Smrg    ooffset = ARGUMENT(0);
14615dfecf96Smrg
14625dfecf96Smrg    CHECK_INDEX(ooffset);
14635dfecf96Smrg    offset = FIXNUM_VALUE(ooffset);
14645dfecf96Smrg
14655dfecf96Smrg    for (i = 0; i < 2; i++)
14665dfecf96Smrg	if (odirection == scan_directions[i])
14675dfecf96Smrg	    break;
14685dfecf96Smrg    if (i >= 2)
14695dfecf96Smrg	LispDestroy("%s: direction must be "
14705dfecf96Smrg		    ":LEFT or :RIGHT, not %s",
14715dfecf96Smrg		    STRFUN(builtin), STROBJ(odirection));
14725dfecf96Smrg    direction = (XawTextScanDirection)i;
14735dfecf96Smrg
14745dfecf96Smrg    for (i = 0; i < 6; i++)
14755dfecf96Smrg	if (otype == scan_types[i])
14765dfecf96Smrg	    break;
14775dfecf96Smrg    if (i >= 6)
14785dfecf96Smrg	LispDestroy("%s: direction must be "
14795dfecf96Smrg		    ":POSITIONS, :WHITE-SPACE, :EOL, "
14805dfecf96Smrg		    ":PARAGRAPH, :ALL, or :ALPHA-NUMERIC, not %s",
14815dfecf96Smrg		    STRFUN(builtin), STROBJ(otype));
14825dfecf96Smrg    type = (XawTextScanType)i;
14835dfecf96Smrg
14845dfecf96Smrg    if (ocount == UNSPEC)
14855dfecf96Smrg	count = 1;
14865dfecf96Smrg    else {
14875dfecf96Smrg	CHECK_INDEX(ocount);
14885dfecf96Smrg	count = FIXNUM_VALUE(ocount);
14895dfecf96Smrg    }
14905dfecf96Smrg
14915dfecf96Smrg    offset = XawTextSourceScan(XawTextGetSource(textwindow),
14925dfecf96Smrg			       offset, type, direction, count,
14935dfecf96Smrg			       include != NIL);
14945dfecf96Smrg
14955dfecf96Smrg    return (FIXNUM(offset));
14965dfecf96Smrg}
14975dfecf96Smrg
14985dfecf96Smrgstatic LispObj *
14995dfecf96SmrgXeditSearch(LispBuiltin *builtin, XawTextScanDirection direction)
15005dfecf96Smrg{
15015dfecf96Smrg    XawTextBlock block;
15025dfecf96Smrg    XawTextPosition position;
15035dfecf96Smrg
15045dfecf96Smrg    LispObj *string, *offset, *ignore_case;
15055dfecf96Smrg
15065dfecf96Smrg    ignore_case = ARGUMENT(2);
15075dfecf96Smrg    offset = ARGUMENT(1);
15085dfecf96Smrg    string = ARGUMENT(0);
15095dfecf96Smrg
15105dfecf96Smrg    CHECK_STRING(string);
15115dfecf96Smrg    if (offset != UNSPEC) {
15125dfecf96Smrg	CHECK_INDEX(offset);
15135dfecf96Smrg	position = FIXNUM_VALUE(offset);
15145dfecf96Smrg    }
15155dfecf96Smrg    else
15165dfecf96Smrg	position = XawTextGetInsertionPoint(textwindow);
15175dfecf96Smrg
15185dfecf96Smrg    block.firstPos = (ignore_case != UNSPEC && ignore_case != NIL) ? 1 : 0;
15195dfecf96Smrg    block.format = FMT8BIT;
15205dfecf96Smrg    block.length = STRLEN(string);
15215dfecf96Smrg    block.ptr = THESTR(string);
15225dfecf96Smrg    position = XawTextSourceSearch(XawTextGetSource(textwindow),
15235dfecf96Smrg				   position, direction, &block);
15245dfecf96Smrg
15255dfecf96Smrg    return (position != XawTextSearchError ? FIXNUM(position) : NIL);
15265dfecf96Smrg}
15275dfecf96Smrg
15285dfecf96Smrg
15295dfecf96SmrgLispObj *
15305dfecf96SmrgXedit_SearchBackward(LispBuiltin *builtin)
15315dfecf96Smrg/*
15325dfecf96Smrg search-backward string &optional offset ignore-case
15335dfecf96Smrg */
15345dfecf96Smrg{
15355dfecf96Smrg    return (XeditSearch(builtin, XawsdLeft));
15365dfecf96Smrg}
15375dfecf96Smrg
15385dfecf96SmrgLispObj *
15395dfecf96SmrgXedit_SearchForward(LispBuiltin *builtin)
15405dfecf96Smrg/*
15415dfecf96Smrg search-forward string &optional offset ignore-case
15425dfecf96Smrg */
15435dfecf96Smrg{
15445dfecf96Smrg    return (XeditSearch(builtin, XawsdRight));
15455dfecf96Smrg}
15465dfecf96Smrg
15475dfecf96SmrgLispObj *
15485dfecf96SmrgXedit_VerticalScrollbar(LispBuiltin *builtin)
15495dfecf96Smrg/*
15505dfecf96Smrg vertical-scrollbar &optional state
15515dfecf96Smrg */
15525dfecf96Smrg{
15535dfecf96Smrg    Arg arg[1];
15545dfecf96Smrg    XawTextScrollMode scroll;
15555dfecf96Smrg
15565dfecf96Smrg    LispObj *state;
15575dfecf96Smrg
15585dfecf96Smrg    state = ARGUMENT(0);
15595dfecf96Smrg
15605dfecf96Smrg    if (state != UNSPEC) {
15615dfecf96Smrg	scroll = state == NIL ? XawtextScrollNever : XawtextScrollAlways;
15625dfecf96Smrg	XtSetArg(arg[0], XtNscrollVertical, scroll);
15635dfecf96Smrg	XtSetValues(textwindow, arg, 1);
15645dfecf96Smrg    }
15655dfecf96Smrg    else {
15665dfecf96Smrg	XtSetArg(arg[0], XtNscrollVertical, &scroll);
15675dfecf96Smrg	XtGetValues(textwindow, arg, 1);
15685dfecf96Smrg	state = scroll == XawtextScrollAlways ? T : NIL;
15695dfecf96Smrg    }
15705dfecf96Smrg
15715dfecf96Smrg    return (state);
15725dfecf96Smrg}
15735dfecf96Smrg
15745dfecf96SmrgLispObj *
15755dfecf96SmrgXedit_WrapMode(LispBuiltin *builtin)
15765dfecf96Smrg/*
15775dfecf96Smrg wrap-mode &optional value
15785dfecf96Smrg */
15795dfecf96Smrg{
15805dfecf96Smrg    int i;
15815dfecf96Smrg    Arg arg[1];
15825dfecf96Smrg    XawTextWrapMode wrap;
15835dfecf96Smrg
15845dfecf96Smrg    LispObj *value;
15855dfecf96Smrg
15865dfecf96Smrg    value = ARGUMENT(0);
15875dfecf96Smrg
15885dfecf96Smrg    if (value != UNSPEC) {
15895dfecf96Smrg	for (i = 0; i < 3; i++)
15905dfecf96Smrg	    if (value == wrap_modes[i])
15915dfecf96Smrg		break;
15925dfecf96Smrg	if (i >= 3)
15935dfecf96Smrg	    LispDestroy("%s: argument must be "
15945dfecf96Smrg			":NEVER, :LINE, or :WORD, not %s",
15955dfecf96Smrg			STRFUN(builtin), STROBJ(value));
15965dfecf96Smrg	XtSetArg(arg[0], XtNwrap, (XawTextWrapMode)i);
15975dfecf96Smrg	XtSetValues(textwindow, arg, 1);
15985dfecf96Smrg    }
15995dfecf96Smrg    else {
16005dfecf96Smrg	XtSetArg(arg[0], XtNwrap, &wrap);
16015dfecf96Smrg	XtGetValues(textwindow, arg, 1);
16025dfecf96Smrg	i = (int)wrap;
16035dfecf96Smrg	if (i <= 0 || i >= 3)
16045dfecf96Smrg	    i = 0;
16055dfecf96Smrg	value = wrap_modes[i];
16065dfecf96Smrg    }
16075dfecf96Smrg
16085dfecf96Smrg    return (value);
16095dfecf96Smrg}
16105dfecf96Smrg
16115dfecf96SmrgLispObj *
16125dfecf96SmrgXedit_XrmStringToQuark(LispBuiltin *builtin)
16135dfecf96Smrg/*
16145dfecf96Smrg xrm-string-to-quark string
16155dfecf96Smrg */
16165dfecf96Smrg{
16175dfecf96Smrg    LispObj *string;
16185dfecf96Smrg
16195dfecf96Smrg    string = ARGUMENT(0);
16205dfecf96Smrg
16215dfecf96Smrg    CHECK_STRING(string);
16225dfecf96Smrg
16235dfecf96Smrg    return (INTEGER(XrmStringToQuark(THESTR(string))));
16245dfecf96Smrg}
1625