nedit-5.6.orig/0000755000175000017500000000000011110456077012114 5ustar paulpaulnedit-5.6.orig/Microline/0000755000175000017500000000000011107644404014034 5ustar paulpaulnedit-5.6.orig/Microline/XmL/0000755000175000017500000000000011107644403014533 5ustar paulpaulnedit-5.6.orig/Microline/XmL/Folder.c0000644000175000017500000032270310470434621016122 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include "FolderP.h" #include #include #include #include #include #include #ifdef SUNOS4 int fprintf(FILE *, char *, ...); #endif /* Create and Destroy */ static void ClassInitialize(); static void Initialize(Widget req, Widget newW, ArgList args, Cardinal *nargs); static void Destroy(Widget w); /* Geometry, Drawing, Entry and Picking */ static void Realize(Widget w, XtValueMask *valueMask, XSetWindowAttributes *attr); static void Redisplay(Widget w, XExposeEvent *event, Region region); static void Layout(XmLFolderWidget f, int resizeIfNeeded); static void LayoutTopBottom(XmLFolderWidget f, int resizeIfNeeded); static void LayoutLeftRight(XmLFolderWidget f, int resizeIfNeeded); static void Resize(Widget w); static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *); static void ChangeManaged(Widget w); static void ConstraintInitialize(Widget, Widget w, ArgList args, Cardinal *nargs); static void ConstraintDestroy(Widget w); static void SetActiveTab(XmLFolderWidget f, Widget w, XEvent *event, Boolean notify); static void DrawTabPixmap(XmLFolderWidget f, Widget tab, int active); static void DrawManagerShadowLeftRight(XmLFolderWidget f, XRectangle *rect); static void DrawManagerShadowTopBottom(XmLFolderWidget f, XRectangle *rect); static void DrawTabHighlight(XmLFolderWidget f, Widget w); static void SetTabPlacement(XmLFolderWidget f, Widget tab); static void GetTabRect(XmLFolderWidget f, Widget tab, XRectangle *rect, int includeShadow); static void DrawTabShadowArcTopBottom(XmLFolderWidget f, Widget w); static void DrawTabShadowArcLeftRight(XmLFolderWidget f, Widget w); static void DrawTabShadowLineTopBottom(XmLFolderWidget f, Widget w); static void DrawTabShadowLineLeftRight(XmLFolderWidget f, Widget w); static void DrawTabShadowNoneTopBottom(XmLFolderWidget f, Widget w); static void DrawTabShadowNoneLeftRight(XmLFolderWidget f, Widget w); static void SetGC(XmLFolderWidget f, int type); /* Getting and Setting Values */ static Boolean SetValues(Widget curW, Widget reqW, Widget newW, ArgList args, Cardinal *nargs); static Boolean ConstraintSetValues(Widget curW, Widget, Widget newW, ArgList, Cardinal *); static void CopyFontList(XmLFolderWidget f); static Boolean CvtStringToCornerStyle(Display *dpy, XrmValuePtr args, Cardinal *numArgs, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data); static Boolean CvtStringToFolderResizePolicy(Display *dpy, XrmValuePtr args, Cardinal *numArgs, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data); static Boolean CvtStringToTabPlacement(Display *dpy, XrmValuePtr args, Cardinal *numArgs, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data); /* Utility */ static void GetCoreBackground(Widget w, int, XrmValue *value); static void GetDefaultTabWidgetClass(Widget w, int, XrmValue *value); static void GetManagerForeground(Widget w, int, XrmValue *value); static Boolean ServerDrawsArcsLarge(Display *dpy, int debug); /* Actions, Callbacks and Handlers */ static void Activate(Widget w, XEvent *event, String *, Cardinal *); static void PrimActivate(Widget w, XtPointer, XtPointer); static void PrimFocusIn(Widget w, XEvent *event, String *, Cardinal *); static void PrimFocusOut(Widget w, XEvent *event, String *, Cardinal *); static XtActionsRec actions[] = { { "XmLFolderActivate", Activate }, { "XmLFolderPrimFocusIn", PrimFocusIn }, { "XmLFolderPrimFocusOut", PrimFocusOut }, }; #define MAX_TAB_ROWS 64 #define GC_SHADOWBOT 0 #define GC_SHADOWTOP 1 #define GC_BLANK 2 #define GC_UNSET 3 /* Folder Translations */ static char translations[] = ": XmLFolderActivate()\n\ : ManagerEnter()\n\ : ManagerLeave()\n\ : ManagerFocusOut()\n\ : ManagerFocusIn()"; /* Primitive Child Translations */ static char primTranslations[] = ": XmLFolderPrimFocusIn() PrimitiveFocusIn()\n\ : XmLFolderPrimFocusOut() PrimitiveFocusOut()"; static XtResource resources[] = { /* Folder Resources */ { XmNtabWidgetClass, XmCTabWidgetClass, XmRWidgetClass, sizeof(WidgetClass), XtOffset(XmLFolderWidget, folder.tabWidgetClass), XmRCallProc, (XtPointer)GetDefaultTabWidgetClass, }, { XmNactivateCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLFolderWidget, folder.activateCallback), XmRImmediate, (XtPointer)0, }, { XmNactiveTab, XmCActiveTab, XmRInt, sizeof(int), XtOffset(XmLFolderWidget, folder.activeTab), XmRImmediate, (XtPointer)-1, }, { XmNautoSelect, XmCAutoSelect, XmRBoolean, sizeof(Boolean), XtOffset(XmLFolderWidget, folder.autoSelect), XmRImmediate, (XtPointer)True, }, { XmNblankBackground, XmCBlankBackground, XmRPixel, sizeof(Pixel), XtOffset(XmLFolderWidget, folder.blankBg), XmRCallProc, (XtPointer)GetCoreBackground, }, { XmNblankBackgroundPixmap, XmCBlankBackgroundPixmap, XmRManForegroundPixmap, sizeof(Pixmap), XtOffset(XmLFolderWidget, folder.blankPix), XmRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP, }, { XmNcornerDimension, XmCCornerDimension, XmRDimension, sizeof(Dimension), XtOffset(XmLFolderWidget, folder.cornerDimension), XmRImmediate, (XtPointer)2, }, { XmNcornerStyle, XmCCornerStyle, XmRCornerStyle, sizeof(unsigned char), XtOffset(XmLFolderWidget, folder.cornerStyle), XmRImmediate, (XtPointer)XmCORNER_ARC, }, { XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList), XtOffset(XmLFolderWidget, folder.fontList), XmRImmediate, (XtPointer)0, }, { XmNhighlightThickness, XmCHighlightThickness, XmRDimension, sizeof(Dimension), XtOffset(XmLFolderWidget, folder.highlightThickness), XmRImmediate, (XtPointer)2, }, { XmNinactiveBackground, XmCInactiveBackground, XmRPixel, sizeof(Pixel), XtOffset(XmLFolderWidget, folder.inactiveBg), XmRCallProc, (XtPointer)GetCoreBackground, }, { XmNinactiveForeground, XmCInactiveForeground, XmRPixel, sizeof(Pixel), XtOffset(XmLFolderWidget, folder.inactiveFg), XmRCallProc, (XtPointer)GetManagerForeground, }, { XmNmarginHeight, XmCMarginHeight, XmRDimension, sizeof(Dimension), XtOffset(XmLFolderWidget, folder.marginHeight), XmRImmediate, (XtPointer)0, }, { XmNmarginWidth, XmCMarginWidth, XmRDimension, sizeof(Dimension), XtOffset(XmLFolderWidget, folder.marginWidth), XmRImmediate, (XtPointer)0, }, { XmNminTabWidth, XmCminTabWidth, XmRDimension, sizeof(Dimension), XtOffset(XmLFolderWidget, folder.minTabWidth), XmRImmediate, (XtPointer)0, }, { XmNmaxTabWidth, XmCmaxTabWidth, XmRDimension, sizeof(Dimension), XtOffset(XmLFolderWidget, folder.maxTabWidth), XmRImmediate, (XtPointer)100, }, { XmNpixmapMargin, XmCPixmapMargin, XmRDimension, sizeof(Dimension), XtOffset(XmLFolderWidget, folder.pixmapMargin), XmRImmediate, (XtPointer)2, }, { XmNresizePolicy, XmCFolderResizePolicy, XmRFolderResizePolicy, sizeof(unsigned char), XtOffset(XmLFolderWidget, folder.resizePolicy), XmRImmediate, (XtPointer)XmRESIZE_STATIC, }, { XmNrotateWhenLeftRight, XmCRotateWhenLeftRight, XmRBoolean, sizeof(Boolean), XtOffset(XmLFolderWidget, folder.allowRotate), XmRImmediate, (XtPointer)True, }, { XmNspacing, XmCSpacing, XmRDimension, sizeof(Dimension), XtOffset(XmLFolderWidget, folder.spacing), XmRImmediate, (XtPointer)0, }, { XmNtabBarHeight, XmCTabBarHeight, XmRDimension, sizeof(Dimension), XtOffset(XmLFolderWidget, folder.tabBarHeight), XmRImmediate, (XtPointer)0, }, { XmNtabCount, XmCTabCount, XmRInt, sizeof(int), XtOffset(XmLFolderWidget, folder.tabCount), XmRImmediate, (XtPointer)0, }, { XmNtabPlacement, XmCTabPlacement, XmRTabPlacement, sizeof(unsigned char), XtOffset(XmLFolderWidget, folder.tabPlacement), XmRImmediate, (XtPointer)XmFOLDER_TOP, }, { XmNtabsPerRow, XmCTabsPerRow, XmRInt, sizeof(int), XtOffset(XmLFolderWidget, folder.tabsPerRow), XmRImmediate, (XtPointer)0, }, { XmNtabWidgetList, XmCReadOnly, XmRPointer, sizeof(XtPointer), XtOffset(XmLFolderWidget, folder.tabs), XmRImmediate, (XtPointer)0, }, { XmNtabTranslations, XmCTranslations, XmRTranslationTable, sizeof(XtTranslations), XtOffset(XmLFolderWidget, folder.primTrans), XmRString, (XtPointer)primTranslations, }, { XmNdebugLevel, XmCDebugLevel, XmRInt, sizeof(int), XtOffset(XmLFolderWidget, folder.debugLevel), XmRImmediate, (XtPointer)0, }, /* Overridden inherited resources */ { XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension, sizeof(Dimension), XtOffset(XmLFolderWidget, manager.shadow_thickness), XmRImmediate, (XtPointer)2, }, }; static XtResource constraint_resources[] = { /* Folder Constraint Resources */ { XmNtabFreePixmaps, XmCTabFreePixmaps, XmRBoolean, sizeof(Boolean), XtOffset(XmLFolderConstraintPtr, folder.freePix), XmRImmediate, (XtPointer)False, }, { XmNtabInactivePixmap, XmCTabInactivePixmap, XmRPrimForegroundPixmap, sizeof(Pixmap), XtOffset(XmLFolderConstraintPtr, folder.inactPix), XmRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP, }, { XmNtabManagedName, XmCTabManagedName, XmRString, sizeof(char *), XtOffset(XmLFolderConstraintPtr, folder.managedName), XmRImmediate, (XtPointer)0, }, { XmNtabManagedWidget, XmCTabManagedWidget, XmRWidget, sizeof(Widget), XtOffset(XmLFolderConstraintPtr, folder.managedW), XmRImmediate, (XtPointer)0, }, { XmNtabPixmap, XmCTabPixmap, XmRPrimForegroundPixmap, sizeof(Pixmap), XtOffset(XmLFolderConstraintPtr, folder.pix), XmRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP, }, }; XmLFolderClassRec xmlFolderClassRec = { { /* core_class */ (WidgetClass)&xmManagerClassRec, /* superclass */ "XmLFolder", /* class_name */ sizeof(XmLFolderRec), /* widget_size */ ClassInitialize, /* class_init */ 0, /* class_part_init */ FALSE, /* class_inited */ (XtInitProc)Initialize, /* initialize */ 0, /* initialize_hook */ (XtRealizeProc)Realize, /* realize */ (XtActionList)actions, /* actions */ (Cardinal)XtNumber(actions), /* num_actions */ (XtResource *)resources, /* resources */ XtNumber(resources), /* num_resources */ NULLQUARK, /* xrm_class */ TRUE, /* compress_motion */ XtExposeCompressMultiple, /* compress_exposure */ TRUE, /* compress_enterlv */ TRUE, /* visible_interest */ (XtWidgetProc)Destroy, /* destroy */ (XtWidgetProc)Resize, /* resize */ (XtExposeProc)Redisplay, /* expose */ (XtSetValuesFunc)SetValues, /* set_values */ 0, /* set_values_hook */ XtInheritSetValuesAlmost, /* set_values_almost */ 0, /* get_values_hook */ 0, /* accept_focus */ XtVersion, /* version */ 0, /* callback_private */ translations, /* tm_table */ 0, /* query_geometry */ 0, /* display_acceleratr */ 0, /* extension */ }, { /* composite_class */ (XtGeometryHandler)GeometryManager, /* geometry_manager */ (XtWidgetProc)ChangeManaged, /* change_managed */ XtInheritInsertChild, /* insert_child */ XtInheritDeleteChild, /* delete_child */ 0, /* extension */ }, { /* constraint_class */ (XtResource *)constraint_resources, /* subresources */ XtNumber(constraint_resources), /* subresource_count */ sizeof(XmLFolderConstraintRec), /* constraint_size */ (XtInitProc)ConstraintInitialize, /* initialize */ (XtWidgetProc)ConstraintDestroy, /* destroy */ (XtSetValuesFunc)ConstraintSetValues, /* set_values */ 0, /* extension */ }, { /* manager_class */ XtInheritTranslations, /* translations */ 0, /* syn resources */ 0, /* num syn_resources */ 0, /* get_cont_resources */ 0, /* num_get_cont_resrc */ XmInheritParentProcess, /* parent_process */ 0, /* extension */ }, { /* folder_class */ 0, /* unused */ } }; WidgetClass xmlFolderWidgetClass = (WidgetClass)&xmlFolderClassRec; /* Create and Destroy */ static void ClassInitialize(void) { XmLInitialize(); XtSetTypeConverter(XmRString, XmRCornerStyle, CvtStringToCornerStyle, 0, 0, XtCacheNone, 0); XtSetTypeConverter(XmRString, XmRFolderResizePolicy, CvtStringToFolderResizePolicy, 0, 0, XtCacheNone, 0); XtSetTypeConverter(XmRString, XmRTabPlacement, CvtStringToTabPlacement, 0, 0, XtCacheNone, 0); } static void Initialize(Widget req, Widget newW, ArgList args, Cardinal *narg) { Display *dpy; /* Window root;*/ XmLFolderWidget f, request; f = (XmLFolderWidget)newW; dpy = XtDisplay((Widget)f); request = (XmLFolderWidget)req; if (f->core.width == 0) f->core.width = 100; if (f->core.height == 0) f->core.height = 100; f->folder.gc = 0; f->folder.tabAllocCount = 32; f->folder.tabs = (Widget *)malloc(sizeof(Widget) * 32); f->folder.tabHeight = 0; f->folder.tabWidth = 0; f->folder.activeW = 0; f->folder.focusW = 0; f->folder.allowLayout = 1; f->folder.activeRow = -1; CopyFontList(f); if (f->folder.tabBarHeight) { XmLWarning((Widget)f, "Initialize() - can't set tabBarHeight"); f->folder.tabBarHeight = 0; } if (f->folder.tabCount) { XmLWarning((Widget)f, "Initialize() - can't set tabCount"); f->folder.tabCount = 0; } if (f->folder.activeTab != -1) { XmLWarning((Widget)f, "Initialize() - can't set activeTab"); f->folder.activeTab = -1; } if (f->folder.cornerDimension < 1) { XmLWarning((Widget)f, "Initialize() - cornerDimension can't be < 1"); f->folder.cornerDimension = 1; } f->folder.serverDrawsArcsLarge = ServerDrawsArcsLarge(dpy, f->folder.debugLevel); if (f->folder.minTabWidth <= 0) { /* a quick hack to determine the minimum tab width - enough to show at least one character of the tab string */ XmString st = XmStringCreateSimple("W"); f->folder.minTabWidth = XmStringWidth(f->folder.fontList, st); XmStringFree(st); } } static void Destroy(Widget w) { XmLFolderWidget f; Display *dpy; f = (XmLFolderWidget)w; dpy = XtDisplay(w); if (f->folder.debugLevel) fprintf(stderr, "Folder destroy: \n"); if (f->folder.tabs) free((char *)f->folder.tabs); if (f->folder.gc) XFreeGC(dpy, f->folder.gc); XmFontListFree(f->folder.fontList); } /* Geometry, Drawing, Entry and Picking */ static void Realize(Widget w, XtValueMask *valueMask, XSetWindowAttributes *attr) { XmLFolderWidget f; Display *dpy; WidgetClass superClass; XtRealizeProc realize; XGCValues values; XtGCMask mask; f = (XmLFolderWidget)w; dpy = XtDisplay(f); superClass = xmlFolderWidgetClass->core_class.superclass; realize = superClass->core_class.realize; (*realize)(w, valueMask, attr); if (!f->folder.gc) { values.foreground = f->manager.foreground; mask = GCForeground; f->folder.gc = XCreateGC(dpy, XtWindow(f), mask, &values); if (f->folder.autoSelect == True && f->folder.tabCount) XmLFolderSetActiveTab(w, 0, False); } } static void Redisplay(Widget w, XExposeEvent *event, Region region) { Display *dpy; Window win; XmLFolderWidget f; XmLFolderConstraintRec *fc; XRectangle eRect, rRect, rect; /* XSegment *topSeg, *botSeg; */ /* int tCount, bCount; */ Widget tab; int i, st, ht; /*, x, y; */ f = (XmLFolderWidget)w; if (!XtIsRealized(w)) return; if (!f->core.visible) return; dpy = XtDisplay(f); win = XtWindow(f); st = f->manager.shadow_thickness; ht = f->folder.highlightThickness; if (event) { eRect.x = event->x; eRect.y = event->y; eRect.width = event->width; eRect.height = event->height; if (f->folder.debugLevel > 1) fprintf(stderr, "XmLFolder: Redisplay x %d y %d w %d h %d\n", event->x, event->y, event->width, event->height); } else { eRect.x = 0; eRect.y = 0; eRect.width = f->core.width; eRect.height = f->core.height; } if (!eRect.width || !eRect.height) return; if (f->folder.tabPlacement == XmFOLDER_TOP) { rRect.x = 0; rRect.y = f->folder.tabHeight; rRect.width = f->core.width; rRect.height = f->core.height - f->folder.tabHeight; } else if (f->folder.tabPlacement == XmFOLDER_BOTTOM) { rRect.x = 0; rRect.y = 0; rRect.width = f->core.width; rRect.height = f->core.height - f->folder.tabHeight; } if (f->folder.tabPlacement == XmFOLDER_LEFT) { rRect.x = f->folder.tabWidth; rRect.y = 0; rRect.width = f->core.width - f->folder.tabWidth; rRect.height = f->core.height; } if (f->folder.tabPlacement == XmFOLDER_RIGHT) { rRect.x = 0; rRect.y = 0; rRect.width = f->core.width - f->folder.tabWidth; rRect.height = f->core.height; } if (XmLRectIntersect(&eRect, &rRect) != XmLRectOutside) { if (f->folder.tabPlacement == XmFOLDER_TOP || f->folder.tabPlacement == XmFOLDER_BOTTOM) DrawManagerShadowTopBottom(f, &rRect); else DrawManagerShadowLeftRight(f, &rRect); } if (!f->folder.tabCount) return; rRect.x = 0; rRect.y = 0; rRect.width = 0; rRect.height = 0; /* Draw tabs */ for (i = 0; i < f->folder.tabCount; i++) { tab = f->folder.tabs[i]; if (!XtIsManaged(tab)) continue; fc = (XmLFolderConstraintRec *)(tab->core.constraints); GetTabRect(f, tab, &rRect, 0); /* include spacing in intersect test */ rect = rRect; if (f->folder.tabPlacement == XmFOLDER_TOP || f->folder.tabPlacement == XmFOLDER_BOTTOM) rect.width += f->folder.spacing; else rect.height += f->folder.spacing; /* include indent in intersect test */ if (f->folder.tabsPerRow) { if (rRect.x == 2) rect.x = 0; if (rRect.y == 2) rect.y = 0; if (rRect.x + rRect.width == f->core.width - 2) rect.width += 2; if (rRect.y + rRect.height == f->core.height - 2) rect.height += 2; } if (XmLRectIntersect(&eRect, &rect) == XmLRectOutside) continue; if (event && XRectInRegion(region, rect.x, rect.y, rect.width, rect.height) == RectangleOut) continue; if (f->folder.debugLevel > 1) fprintf(stderr, "XmLFolder: Redisplay tab for widget %d\n", i); if (tab == f->folder.activeW) { XtVaSetValues(tab, XmNbackground, f->core.background_pixel, XmNforeground, f->manager.foreground, NULL); } else { XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg); XFillRectangle(dpy, win, f->folder.gc, rRect.x, rRect.y, rRect.width, rRect.height); XtVaSetValues(tab, XmNbackground, f->folder.inactiveBg, XmNforeground, f->folder.inactiveFg, NULL); } if (f->folder.tabPlacement == XmFOLDER_TOP || f->folder.tabPlacement == XmFOLDER_BOTTOM) { if (f->folder.cornerStyle == XmCORNER_LINE) DrawTabShadowLineTopBottom(f, tab); else if (f->folder.cornerStyle == XmCORNER_ARC) DrawTabShadowArcTopBottom(f, tab); else DrawTabShadowNoneTopBottom(f, tab); } else { if (f->folder.cornerStyle == XmCORNER_LINE) DrawTabShadowLineLeftRight(f, tab); else if (f->folder.cornerStyle == XmCORNER_ARC) DrawTabShadowArcLeftRight(f, tab); else DrawTabShadowNoneLeftRight(f, tab); } if (f->folder.focusW == tab) DrawTabHighlight(f, tab); if (tab == f->folder.activeW && fc->folder.pix != XmUNSPECIFIED_PIXMAP && (fc->folder.maxPixWidth || fc->folder.maxPixHeight)) DrawTabPixmap(f, tab, 1); else if (tab != f->folder.activeW && fc->folder.inactPix != XmUNSPECIFIED_PIXMAP && (fc->folder.maxPixWidth || fc->folder.maxPixHeight)) DrawTabPixmap(f, tab, 0); SetGC(f, GC_BLANK); /* draw indent */ if (f->folder.tabsPerRow) { if (rRect.x == 2) { rect = rRect; rect.x = 0; rect.width = 2; XFillRectangle(dpy, win, f->folder.gc, rect.x, rect.y, rect.width, rect.height); } if (rRect.y == 2) { rect = rRect; rect.y = 0; rect.height = 2; XFillRectangle(dpy, win, f->folder.gc, rect.x, rect.y, rect.width, rect.height); } if (rRect.x + rRect.width == f->core.width - 2) { rect = rRect; rect.x = f->core.width - 2; rect.width = 2; XFillRectangle(dpy, win, f->folder.gc, rect.x, rect.y, rect.width, rect.height); } if (rRect.y + rRect.height == f->core.height - 2) { rect = rRect; rect.y = f->core.height - 2; rect.height = 2; XFillRectangle(dpy, win, f->folder.gc, rect.x, rect.y, rect.width, rect.height); } } if (f->folder.spacing) { if (f->folder.tabPlacement == XmFOLDER_TOP || f->folder.tabPlacement == XmFOLDER_BOTTOM) XFillRectangle(dpy, win, f->folder.gc, rRect.x + rRect.width, rRect.y, f->folder.spacing, rRect.height); else XFillRectangle(dpy, win, f->folder.gc, rRect.x, rRect.y + rRect.height, rRect.width, f->folder.spacing); } SetGC(f, GC_UNSET); } /* Draw empty area */ if (!f->folder.tabsPerRow) { if (f->folder.tabPlacement == XmFOLDER_TOP || f->folder.tabPlacement == XmFOLDER_BOTTOM) { rRect.x += rRect.width + f->folder.spacing; if ((int)f->core.width > rRect.x) { if (f->folder.tabPlacement == XmFOLDER_TOP) rRect.y = 0; else rRect.y = f->core.height - f->folder.tabHeight; rRect.width = f->core.width - rRect.x; rRect.height = f->folder.tabHeight; SetGC(f, GC_BLANK); XFillRectangle(dpy, win, f->folder.gc, rRect.x, rRect.y, rRect.width, rRect.height); SetGC(f, GC_UNSET); } } else { rRect.y += rRect.height + f->folder.spacing; if ((int)f->core.height > rRect.y) { if (f->folder.tabPlacement == XmFOLDER_LEFT) rRect.x = 0; else rRect.x = f->core.width - f->folder.tabWidth; rRect.width = f->folder.tabWidth; rRect.height = f->core.height - rRect.y; SetGC(f, GC_BLANK); XFillRectangle(dpy, win, f->folder.gc, rRect.x, rRect.y, rRect.width, rRect.height); SetGC(f, GC_UNSET); } } } } static void Layout(XmLFolderWidget f, int resizeIfNeeded) { /* Window win;*/ if (!f->folder.allowLayout) return; f->folder.allowLayout = 0; if (f->folder.tabPlacement == XmFOLDER_LEFT || f->folder.tabPlacement == XmFOLDER_RIGHT) LayoutLeftRight(f, resizeIfNeeded); else LayoutTopBottom(f, resizeIfNeeded); if (XtIsRealized((Widget)f) && f->core.visible) XClearArea(XtDisplay(f), XtWindow(f), 0, 0, 0, 0, True); f->folder.allowLayout = 1; } static void LayoutTopBottom(XmLFolderWidget f, int resizeIfNeeded) { Display *dpy; Window root; int i, tabNum, x, y, w, h, pad1, pad2; int rowNum, numRows, rowHeight, rowX, rowY; WidgetList children; Widget tab, child; XmLFolderConstraintRec *fc; XtGeometryResult result; unsigned int inactPixHeight, pixHeight; unsigned int inactPixWidth, pixWidth; unsigned int pixBW, pixDepth; Dimension height, minHeight; Dimension width, minWidth, borderWidth; Dimension co; int st, ht; int tabFit = 0, tgtTabWidth = 0; int tabPaddingWidth, tailSpace = 0; Boolean map, isManaged; struct { int width, height, numTabs, y; } rows[MAX_TAB_ROWS]; dpy = XtDisplay(f); children = f->composite.children; st = f->manager.shadow_thickness; ht = f->folder.highlightThickness; /* calculate corner offset */ if (f->folder.cornerStyle == XmCORNER_LINE) co = (Dimension)((double)f->folder.cornerDimension * .5 + .99); else if (f->folder.cornerStyle == XmCORNER_ARC) co = (Dimension)((double)f->folder.cornerDimension * .3 + .99); else co = 0; /* caculate tabHeight, minWidth, minHeight, row y positions, */ /* row heights and tab pixmap dimensions */ rowX = 0; rowY = 0; rowHeight = 0; rowNum = 0; tabNum = 0; minWidth = 0; if (f->folder.tabCount && f->folder.resizePolicy == XmRESIZE_PACK) { int maxTabWidth = f->folder.maxTabWidth; int tabEffCount = 0; for (i = 0; i < f->folder.tabCount; i++) { tab = f->folder.tabs[i]; if (!XtIsManaged(tab)) continue; tabEffCount++; } tabPaddingWidth = (st + co + f->folder.marginWidth + ht + f->folder.tabs[0]->core.border_width) * 2; if (maxTabWidth * tabEffCount > f->core.width) { tgtTabWidth = f->core.width/tabEffCount - tabPaddingWidth; tailSpace = f->core.width % tabEffCount; tabFit = 1; /* if tabs get too small */ if (tgtTabWidth < f->folder.minTabWidth) { tgtTabWidth = f->folder.minTabWidth; tabFit = 0; } } else { tgtTabWidth = maxTabWidth - tabPaddingWidth; tabFit = 0; } } for (i = 0; i < f->folder.tabCount; i++) { tab = f->folder.tabs[i]; if (!XtIsManaged(tab)) continue; if (f->folder.resizePolicy == XmRESIZE_PACK) { if (tabFit) { XtVaSetValues(tab, XmNwidth, tailSpace? tgtTabWidth+1: tgtTabWidth, NULL); if (tailSpace) tailSpace--; } else { XtVaSetValues(tab, XmNwidth, tgtTabWidth, NULL); } } fc = (XmLFolderConstraintRec *)(tab->core.constraints); /* check for start of a new row */ fc->folder.firstInRow = False; if (!tabNum) fc->folder.firstInRow = True; if (f->folder.tabsPerRow && tabNum == f->folder.tabsPerRow) { fc->folder.firstInRow = True; /* store prev row values and start next row */ if (rowX) rowX -= f->folder.spacing; rows[rowNum].y = rowY; rows[rowNum].width = rowX; rows[rowNum].height = rowHeight; rows[rowNum].numTabs = tabNum; if (f->folder.debugLevel) { fprintf(stderr, "XmLFolder: Layout: "); fprintf(stderr, "row %d: y %d w %d h %d numTabs %d\n", rowNum, rowY, rowX, rowHeight, tabNum); } rowY += rowHeight; rowHeight = 0; if (rowX > (int)minWidth) minWidth = rowX; rowX = 0; tabNum = 0; rowNum++; if (rowNum == MAX_TAB_ROWS - 1) { XmLWarning((Widget)f, "Layout ERROR - too many rows\n"); return; } } /* make sure row height > maximum tab height */ height = co + st + tab->core.height + tab->core.border_width * 2 + f->folder.marginHeight * 2 + ht * 2; if ((int)height > rowHeight) rowHeight = height; /* calc pixmap dimensions/maximum pixmap height */ fc->folder.pixWidth = 0; fc->folder.pixHeight = 0; fc->folder.inactPixWidth = 0; fc->folder.inactPixHeight = 0; fc->folder.maxPixWidth = 0; fc->folder.maxPixHeight = 0; if (fc->folder.pix != XmUNSPECIFIED_PIXMAP) { XGetGeometry(dpy, fc->folder.pix, &root, &x, &y, &pixWidth, &pixHeight, &pixBW, &pixDepth); fc->folder.pixWidth = pixWidth; fc->folder.maxPixWidth = pixWidth; fc->folder.pixHeight = pixHeight; fc->folder.maxPixHeight = pixHeight; height = co + st + pixHeight + f->folder.marginHeight * 2 + ht * 2; if ((int)height > rowHeight) rowHeight = height; } if (fc->folder.inactPix != XmUNSPECIFIED_PIXMAP) { XGetGeometry(dpy, fc->folder.inactPix, &root, &x, &y, &inactPixWidth, &inactPixHeight, &pixBW, &pixDepth); fc->folder.inactPixWidth = inactPixWidth; if (inactPixWidth > fc->folder.maxPixWidth) fc->folder.maxPixWidth = inactPixWidth; fc->folder.inactPixHeight = inactPixHeight; if (inactPixHeight > fc->folder.maxPixHeight) fc->folder.maxPixHeight = inactPixHeight; height = co + st + inactPixHeight + f->folder.marginHeight * 2 + ht * 2; if ((int)height > rowHeight) rowHeight = height; } /* increment rowX to move on to the next tab */ rowX += st * 2 + co * 2 + f->folder.marginWidth * 2 + ht * 2 + XtWidth(tab) + tab->core.border_width * 2; if (fc->folder.maxPixWidth) rowX += fc->folder.maxPixWidth + f->folder.pixmapMargin; rowX += f->folder.spacing; tabNum++; fc->folder.row = rowNum; } /* complete calcuations for last row */ if (rowX) rowX -= f->folder.spacing; rows[rowNum].y = rowY; rows[rowNum].width = rowX; rows[rowNum].height = rowHeight; rows[rowNum].numTabs = tabNum; numRows = rowNum + 1; if (f->folder.debugLevel) { fprintf(stderr, "XmLFolder: Layout: "); fprintf(stderr, "row %d: y %d w %d h %d numTabs %d\n", rowNum, rowY, rowX, rowHeight, tabNum); } f->folder.tabHeight = rowY + rowHeight; f->folder.tabBarHeight = f->folder.tabHeight; minHeight = f->folder.tabHeight; if ((int)minWidth < rowX) minWidth = rowX; /* add space for indent of upper rows */ if (f->folder.tabsPerRow && minWidth) minWidth += 4; if (f->folder.debugLevel) { fprintf(stderr, "XmLFolder: Layout: "); fprintf(stderr, "tab bar minimum w %d h %d\n", (int)minWidth, (int)minHeight); } /* calculate width and height of non-tab children ensure */ /* minWidth > width and minHeight > height */ for (i = 0; i < f->composite.num_children; i++) { child = children[i]; if (XtIsSubclass(child, xmPrimitiveWidgetClass)) continue; height = XtHeight(child) + f->folder.tabHeight + st * 2; if (XtIsWidget(child)) height += child->core.border_width * 2; if (height > minHeight) minHeight = height; width = XtWidth(child) + st * 2; if (XtIsWidget(child)) width += child->core.border_width * 2; if (width > minWidth) minWidth = width; } if (f->folder.debugLevel) { fprintf(stderr, "XmLFolder: Layout: "); fprintf(stderr, "with non-tabs minimum w %d h %d\n", (int)minWidth, (int)minHeight); } /* Resize folder if needed */ if (resizeIfNeeded && f->folder.resizePolicy != XmRESIZE_NONE) { if (minWidth <= 0) minWidth = 1; if (minHeight <= 0) minHeight = 1; result = XtMakeResizeRequest((Widget)f, minWidth, minHeight, &width, &height); if (result == XtGeometryAlmost) XtMakeResizeRequest((Widget)f, width, height, NULL, NULL); } /* move active row to bottom */ tab = f->folder.activeW; if (tab) { fc = (XmLFolderConstraintRec *)(tab->core.constraints); rowNum = fc->folder.row; f->folder.activeRow = rowNum; rows[rowNum].y = f->folder.tabHeight - rows[rowNum].height; for (i = rowNum + 1; i < numRows; i++) rows[i].y -= rows[rowNum].height; } else f->folder.activeRow = -1; /* configure tab children */ for (i = 0; i < f->folder.tabCount; i++) { tab = f->folder.tabs[i]; if (!XtIsManaged(tab)) continue; fc = (XmLFolderConstraintRec *)(tab->core.constraints); rowNum = fc->folder.row; /* calculate tab x */ if (fc->folder.firstInRow == True) { if (f->folder.tabsPerRow && rowNum != f->folder.activeRow) x = 2; else x = 0; } fc->folder.x = x; x += st + co + f->folder.marginWidth + ht; if (fc->folder.maxPixWidth) x += fc->folder.maxPixWidth + f->folder.pixmapMargin; /* calculate tab y and tab height */ fc->folder.height = rows[rowNum].height; if (f->folder.tabPlacement == XmFOLDER_TOP) { fc->folder.y = rows[rowNum].y; y = fc->folder.y + fc->folder.height - f->folder.marginHeight - ht - XtHeight(tab) - tab->core.border_width * 2; } else { fc->folder.y = f->core.height - rows[rowNum].y - rows[rowNum].height; y = fc->folder.y + f->folder.marginHeight + ht; } /* calculate tab padding */ pad1 = 0; pad2 = 0; w = f->core.width - rows[rowNum].width; if (rowNum != f->folder.activeRow) w -= 4; if (f->folder.tabsPerRow && w > 0) { pad1 = w / (rows[rowNum].numTabs * 2); pad2 = pad1; if (fc->folder.firstInRow == True) pad2 += w - (pad1 * rows[rowNum].numTabs * 2); } x += pad1; /* move tab widget into place */ XtMoveWidget(tab, x, y); /* calculate tab width and move to next tab */ x += pad2 + XtWidth(tab) + tab->core.border_width * 2 + ht + f->folder.marginWidth + co + st; fc->folder.width = x - fc->folder.x; x += f->folder.spacing; } /* configure non-tab children */ for (i = 0; i < f->composite.num_children; i++) { child = children[i]; if (XtIsSubclass(child, xmPrimitiveWidgetClass)) continue; if (f->folder.resizePolicy == XmRESIZE_NONE) continue; w = (int)f->core.width - st * 2; h = (int)f->core.height - (int)f->folder.tabHeight - st * 2; if (h <= 0 || w <= 0) continue; /* manager widgets will not configure correctly unless they */ /* are managed, so manage then unmapped if they are unmanaged */ isManaged = True; if (!XtIsManaged(child)) { XtVaGetValues(child, XmNmappedWhenManaged, &map, NULL); XtVaSetValues(child, XmNmappedWhenManaged, False, NULL); XtManageChild(child); isManaged = False; } x = st; if (f->folder.tabPlacement == XmFOLDER_TOP) y = f->folder.tabHeight + st; else y = st; width = w; height = h; borderWidth = 0; if (XtIsWidget(child)) borderWidth = child->core.border_width; XtConfigureWidget(child, x, y, width, height, borderWidth); if (isManaged == False) { XtUnmanageChild(child); XtVaSetValues(child, XmNmappedWhenManaged, map, NULL); } } } static void LayoutLeftRight(XmLFolderWidget f, int resizeIfNeeded) { Display *dpy; Window root; int i, tabNum, x, y, w, h, pad1, pad2; int rowNum, numRows, rowWidth, rowX, rowY; WidgetList children; Widget tab, child; XmLFolderConstraintRec *fc; XtGeometryResult result; unsigned int inactPixHeight, pixHeight; unsigned int inactPixWidth, pixWidth; unsigned int pixBW, pixDepth; Dimension height, minHeight; Dimension width, minWidth, borderWidth; Dimension co; int st, ht; Boolean map, isManaged; struct { int width, height, numTabs, x; } rows[MAX_TAB_ROWS]; dpy = XtDisplay(f); children = f->composite.children; st = f->manager.shadow_thickness; ht = f->folder.highlightThickness; /* calculate corner offset */ if (f->folder.cornerStyle == XmCORNER_LINE) co = (Dimension)((double)f->folder.cornerDimension * .5 + .99); else if (f->folder.cornerStyle == XmCORNER_ARC) co = (Dimension)((double)f->folder.cornerDimension * .3 + .99); else co = 0; /* caculate tabWidth, minWidth, minHeight, row x positions, */ /* row widths and tab pixmap dimensions */ rowX = 0; rowY = 0; rowWidth = 0; rowNum = 0; tabNum = 0; minHeight = 0; for (i = 0; i < f->folder.tabCount; i++) { tab = f->folder.tabs[i]; if (!XtIsManaged(tab)) continue; fc = (XmLFolderConstraintRec *)(tab->core.constraints); /* check for start of a new row */ fc->folder.firstInRow = False; if (!tabNum) fc->folder.firstInRow = True; if (f->folder.tabsPerRow && tabNum == f->folder.tabsPerRow) { fc->folder.firstInRow = True; /* store prev row values and start next row */ if (rowY) rowY -= f->folder.spacing; rows[rowNum].x = rowX; rows[rowNum].height = rowY; rows[rowNum].width = rowWidth; rows[rowNum].numTabs = tabNum; if (f->folder.debugLevel) { fprintf(stderr, "XmLFolder: Layout: "); fprintf(stderr, "row %d: x %d w %d h %d numTabs %d\n", rowNum, rowX, rowWidth, rowY, tabNum); } rowX += rowWidth; rowWidth = 0; if (rowY > (int)minHeight) minHeight = rowY; rowY = 0; tabNum = 0; rowNum++; if (rowNum == MAX_TAB_ROWS - 1) { XmLWarning((Widget)f, "Layout ERROR - too many rows\n"); return; } } /* make sure row width > maximum tab width */ width = co + st + tab->core.width + tab->core.border_width * 2 + f->folder.marginHeight * 2 + ht * 2; if ((int)width > rowWidth) rowWidth = width; /* calc pixmap dimensions/maximum pixmap width */ pixWidth = 0; pixHeight = 0; fc->folder.pixWidth = 0; fc->folder.pixHeight = 0; fc->folder.inactPixWidth = 0; fc->folder.inactPixHeight = 0; fc->folder.maxPixWidth = 0; fc->folder.maxPixHeight = 0; if (fc->folder.pix != XmUNSPECIFIED_PIXMAP) { XGetGeometry(dpy, fc->folder.pix, &root, &x, &y, &pixWidth, &pixHeight, &pixBW, &pixDepth); fc->folder.pixWidth = pixWidth; fc->folder.maxPixWidth = pixWidth; fc->folder.pixHeight = pixHeight; fc->folder.maxPixHeight = pixHeight; width = co + st + pixWidth + f->folder.marginHeight * 2 + ht * 2; if ((int)width > rowWidth) rowWidth = width; } if (fc->folder.inactPix != XmUNSPECIFIED_PIXMAP) { XGetGeometry(dpy, fc->folder.inactPix, &root, &x, &y, &inactPixWidth, &inactPixHeight, &pixBW, &pixDepth); fc->folder.inactPixWidth = inactPixWidth; if (inactPixWidth > fc->folder.maxPixWidth) fc->folder.maxPixWidth = inactPixWidth; fc->folder.inactPixHeight = inactPixHeight; if (inactPixHeight > fc->folder.maxPixHeight) fc->folder.maxPixHeight = inactPixHeight; width = co + st + inactPixWidth + f->folder.marginHeight * 2 + ht * 2; if ((int)width > rowWidth) rowWidth = width; } /* increment rowY to move on to the next tab */ rowY += st * 2 + co * 2 + f->folder.marginWidth * 2 + ht * 2 + XtHeight(tab) + tab->core.border_width * 2; if (fc->folder.maxPixHeight) rowY += fc->folder.maxPixHeight + f->folder.pixmapMargin; rowY += f->folder.spacing; tabNum++; fc->folder.row = rowNum; } /* complete calcuations for last row */ if (rowY) rowY -= f->folder.spacing; rows[rowNum].x = rowX; rows[rowNum].height = rowY; rows[rowNum].width = rowWidth; rows[rowNum].numTabs = tabNum; numRows = rowNum + 1; if (f->folder.debugLevel) { fprintf(stderr, "XmLFolder: Layout: "); fprintf(stderr, "row %d: x %d w %d h %d numTabs %d\n", rowNum, rowX, rowWidth, rowY, tabNum); } f->folder.tabWidth = rowX + rowWidth; f->folder.tabBarHeight = f->folder.tabWidth; minWidth = f->folder.tabWidth; if ((int)minHeight < rowY) minHeight = rowY; /* add space for indent of upper rows */ if (f->folder.tabsPerRow && minHeight) minHeight += 4; if (f->folder.debugLevel) { fprintf(stderr, "XmLFolder: Layout: "); fprintf(stderr, "tab bar minimum w %d h %d\n", (int)minWidth, (int)minHeight); } /* calculate width and height of non-tab children ensure */ /* minWidth > width and minHeight > height */ for (i = 0; i < f->composite.num_children; i++) { child = children[i]; if (XtIsSubclass(child, xmPrimitiveWidgetClass)) continue; height = XtHeight(child) + st * 2; if (XtIsWidget(child)) height += f->core.border_width * 2; if (height > minHeight) minHeight = height; width = XtWidth(child) + f->folder.tabWidth + st * 2; if (XtIsWidget(child)) width += f->core.border_width * 2; if (width > minWidth) minWidth = width; } if (f->folder.debugLevel) { fprintf(stderr, "XmLFolder: Layout: "); fprintf(stderr, "with non-tabs minimum w %d h %d\n", (int)minWidth, (int)minHeight); } /* Resize folder if needed */ if (resizeIfNeeded && f->folder.resizePolicy != XmRESIZE_NONE) { if (minWidth <= 0) minWidth = 1; if (minHeight <= 0) minHeight = 1; result = XtMakeResizeRequest((Widget)f, minWidth, minHeight, &width, &height); if (result == XtGeometryAlmost) XtMakeResizeRequest((Widget)f, width, height, NULL, NULL); } /* move active row to bottom */ tab = f->folder.activeW; if (tab) { fc = (XmLFolderConstraintRec *)(tab->core.constraints); rowNum = fc->folder.row; f->folder.activeRow = rowNum; rows[rowNum].x = f->folder.tabWidth - rows[rowNum].width; for (i = rowNum + 1; i < numRows; i++) rows[i].x -= rows[rowNum].width; } else f->folder.activeRow = -1; /* configure tab children */ for (i = 0; i < f->folder.tabCount; i++) { tab = f->folder.tabs[i]; if (!XtIsManaged(tab)) continue; fc = (XmLFolderConstraintRec *)(tab->core.constraints); rowNum = fc->folder.row; /* calculate tab x */ if (fc->folder.firstInRow == True) { if (f->folder.tabsPerRow && rowNum != f->folder.activeRow) y = 2; else y = 0; } fc->folder.y = y; y += st + co + f->folder.marginWidth + ht; if (fc->folder.maxPixHeight) y += fc->folder.maxPixHeight + f->folder.pixmapMargin; /* calculate tab x and tab width */ fc->folder.width = rows[rowNum].width; if (f->folder.tabPlacement == XmFOLDER_LEFT) { fc->folder.x = rows[rowNum].x; x = fc->folder.x + fc->folder.width - f->folder.marginHeight - ht - XtWidth(tab) - tab->core.border_width * 2; } else { fc->folder.x = f->core.width - rows[rowNum].x - rows[rowNum].width; x = fc->folder.x + f->folder.marginHeight + ht; } /* calculate tab padding */ pad1 = 0; pad2 = 0; h = f->core.height - rows[rowNum].height; if (rowNum != f->folder.activeRow) h -= 4; if (f->folder.tabsPerRow && h > 0) { pad1 = h / (rows[rowNum].numTabs * 2); pad2 = pad1; if (fc->folder.firstInRow == True) pad2 += h - (pad1 * rows[rowNum].numTabs * 2); } y += pad1; /* move tab widget into place */ XtMoveWidget(tab, x, y); /* calculate tab height and move to next tab */ y += pad2 + XtHeight(tab) + tab->core.border_width * 2 + ht + f->folder.marginWidth + co + st; fc->folder.height = y - fc->folder.y; y += f->folder.spacing; } /* configure non-tab children */ for (i = 0; i < f->composite.num_children; i++) { child = children[i]; if (XtIsSubclass(child, xmPrimitiveWidgetClass)) continue; if (f->folder.resizePolicy == XmRESIZE_NONE) continue; w = (int)f->core.width - (int)f->folder.tabWidth - st * 2; h = (int)f->core.height - st * 2; if (h <= 0 || w <= 0) continue; /* manager widgets will not configure correctly unless they */ /* are managed, so manage then unmapped if they are unmanaged */ isManaged = True; if (!XtIsManaged(child)) { XtVaGetValues(child, XmNmappedWhenManaged, &map, NULL); XtVaSetValues(child, XmNmappedWhenManaged, False, NULL); XtManageChild(child); isManaged = False; } y = st; if (f->folder.tabPlacement == XmFOLDER_LEFT) x = f->folder.tabWidth + st; else x = st; width = w; height = h; borderWidth = 0; if (XtIsWidget(child)) borderWidth = child->core.border_width; XtConfigureWidget(child, x, y, width, height, borderWidth); if (isManaged == False) { XtUnmanageChild(child); XtVaSetValues(child, XmNmappedWhenManaged, map, NULL); } } } static void Resize(Widget w) { XmLFolderWidget f; f = (XmLFolderWidget)w; Layout(f, 0); } static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *allow) { XmLFolderWidget f; f = (XmLFolderWidget)XtParent(w); if (f->folder.resizePolicy != XmRESIZE_STATIC || XtIsSubclass(w, xmPrimitiveWidgetClass)) { if (request->request_mode & CWWidth) w->core.width = request->width; if (request->request_mode & CWHeight) w->core.height = request->height; if (request->request_mode & CWX) w->core.x = request->x; if (request->request_mode & CWY) w->core.y = request->y; if (request->request_mode & CWBorderWidth) w->core.border_width = request->border_width; Layout(f, 1); return XtGeometryYes; } return XtGeometryNo; } static void ChangeManaged(Widget w) { XmLFolderWidget f; f = (XmLFolderWidget)w; Layout(f, 1); _XmNavigChangeManaged(w); } static void ConstraintInitialize(Widget req, Widget w, ArgList args, Cardinal *narg) { XmLFolderWidget f; XmLFolderConstraintRec *fc; if (!XtIsRectObj(w)) return; f = (XmLFolderWidget)XtParent(w); if (f->folder.debugLevel) fprintf(stderr, "XmLFolder: Constraint Init\n"); fc = (XmLFolderConstraintRec *)(w->core.constraints); fc->folder.x = 0; fc->folder.y = 0; fc->folder.width = 0; fc->folder.height = 0; fc->folder.maxPixWidth = 0; fc->folder.maxPixHeight = 0; fc->folder.row = -1; fc->folder.firstInRow = False; if (fc->folder.managedName) fc->folder.managedName = (char *)strdup(fc->folder.managedName); if (XtIsSubclass(w, xmPrimitiveWidgetClass)) { XtOverrideTranslations(w, f->folder.primTrans); XtAddCallback(w, XmNactivateCallback, PrimActivate, 0); XtVaSetValues(w, XmNhighlightThickness, 0, XmNshadowThickness, 0, NULL); if (XtIsSubclass(w, xmLabelWidgetClass)) XtVaSetValues(w, XmNfillOnArm, False, NULL); /* add child to tabs list */ if (f->folder.tabAllocCount < f->folder.tabCount + 1) { f->folder.tabAllocCount *= 2; f->folder.tabs = (Widget *)realloc((char *)f->folder.tabs, sizeof(Widget) * f->folder.tabAllocCount); } f->folder.tabs[f->folder.tabCount++] = w; } if (XmIsDrawnButton(w)) SetTabPlacement(f, w); #ifdef XmLEVAL if (f->folder.tabCount > 6) { fprintf(stderr, "XmL: evaluation version only supports <= 6 tabs\n"); exit(0); } #endif } static void ConstraintDestroy(Widget w) { XmLFolderWidget f; XmLFolderConstraintRec *fc; int i, j, activePos; if (!XtIsRectObj(w)) return; f = (XmLFolderWidget)XtParent(w); if (f->folder.debugLevel) fprintf(stderr, "XmLFolder: Constraint Destroy\n"); if (f->folder.focusW == w) f->folder.focusW = 0; fc = (XmLFolderConstraintRec *)(w->core.constraints); if (fc->folder.managedName) free((char *)fc->folder.managedName); if (fc->folder.freePix == True) { if (fc->folder.pix != XmUNSPECIFIED_PIXMAP) XFreePixmap(XtDisplay(w), fc->folder.pix); if (fc->folder.inactPix != XmUNSPECIFIED_PIXMAP) XFreePixmap(XtDisplay(w), fc->folder.inactPix); } if (XtIsSubclass(w, xmPrimitiveWidgetClass)) { XtRemoveCallback(w, XmNactivateCallback, PrimActivate, 0); /* remove child from tabs list and calculate active pos */ activePos = -1; j = 0; for (i = 0; i < f->folder.tabCount; i++) if (f->folder.tabs[i] != w) { if (f->folder.activeW == f->folder.tabs[i]) activePos = j; f->folder.tabs[j++] = f->folder.tabs[i]; } if (j != f->folder.tabCount - 1) XmLWarning((Widget)f, "ConstraintDestroy() - bad child list"); f->folder.tabCount = j; f->folder.activeTab = activePos; if (activePos == -1) f->folder.activeW = 0; } } static void DrawTabPixmap(XmLFolderWidget f, Widget tab, int active) { Display *dpy; Window win; int x, y; Pixmap pixmap; Dimension pixWidth, pixHeight, ht; XmLFolderConstraintRec *fc; x = 0; y = 0; dpy = XtDisplay(f); win = XtWindow(f); fc = (XmLFolderConstraintRec *)(tab->core.constraints); ht = f->folder.highlightThickness; if (active) { pixWidth = fc->folder.pixWidth; pixHeight = fc->folder.pixHeight; pixmap = fc->folder.pix; } else { pixWidth = fc->folder.inactPixWidth; pixHeight = fc->folder.inactPixHeight; pixmap = fc->folder.inactPix; } if (f->folder.tabPlacement == XmFOLDER_TOP) { x = tab->core.x - pixWidth - ht - f->folder.pixmapMargin; y = tab->core.y + tab->core.height - pixHeight; } else if (f->folder.tabPlacement == XmFOLDER_BOTTOM) { x = tab->core.x - fc->folder.pixWidth - ht - f->folder.pixmapMargin; y = tab->core.y; } else if (f->folder.tabPlacement == XmFOLDER_LEFT) { x = tab->core.x + tab->core.width - pixWidth; y = tab->core.y - pixHeight - f->folder.pixmapMargin - ht; } else if (f->folder.tabPlacement == XmFOLDER_RIGHT) { x = tab->core.x; y = tab->core.y - pixHeight - f->folder.pixmapMargin - ht; } XCopyArea(dpy, pixmap, win, f->folder.gc, 0, 0, pixWidth, pixHeight, x, y); } static void DrawManagerShadowTopBottom(XmLFolderWidget f, XRectangle *rect) { Display *dpy; Window win; XmLFolderConstraintRec *fc; XSegment *topSeg, *botSeg; int i, bCount, tCount, st, botOff, isManaged; dpy = XtDisplay(f); win = XtWindow(f); st = f->manager.shadow_thickness; if (!st) return; botOff = f->core.height - f->folder.tabHeight - 1; topSeg = (XSegment *)malloc(sizeof(XSegment) * st * 2); botSeg = (XSegment *)malloc(sizeof(XSegment) * st * 2); /* top shadow */ fc = 0; if (f->folder.activeW) fc = (XmLFolderConstraintRec *)(f->folder.activeW->core.constraints); tCount = 0; if (fc) for (i = 0; i < st; i++) { topSeg[tCount].x1 = rect->x + i; topSeg[tCount].y1 = rect->y + i; topSeg[tCount].x2 = fc->folder.x + i; topSeg[tCount].y2 = rect->y + i; if (rect->x != fc->folder.x) tCount++; topSeg[tCount].x1 = rect->x + fc->folder.x + fc->folder.width - i - 1; topSeg[tCount].y1 = rect->y + i; topSeg[tCount].x2 = rect->x + rect->width - i - 1; topSeg[tCount].y2 = rect->y + i; if (fc->folder.x + fc->folder.width != rect->width) tCount++; } else for (i = 0; i < st; i++) { topSeg[tCount].x1 = rect->x + i; topSeg[tCount].y1 = rect->y + i; topSeg[tCount].x2 = rect->x + rect->width - i - 1; topSeg[tCount].y2 = rect->y + i; tCount++; } if (f->folder.tabPlacement == XmFOLDER_BOTTOM) for (i = 0 ; i < tCount; i++) { topSeg[i].y1 = botOff - topSeg[i].y1; topSeg[i].y2 = botOff - topSeg[i].y2; } if (tCount) { if (f->folder.tabPlacement == XmFOLDER_BOTTOM) SetGC(f, GC_SHADOWBOT); else SetGC(f, GC_SHADOWTOP); XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount); SetGC(f, GC_UNSET); } /* see if there's any composite widgets in the folder */ isManaged = 0; for (i = 0; i < f->composite.num_children; i++) { Widget child = f->composite.children[i]; if (!XtIsSubclass(child, xmPrimitiveWidgetClass) && XtIsManaged(child)) { isManaged = 1; break; } } /* no need to draw shadow for the manager area if there isn't any composite widgets in the folder */ if (!isManaged) { free((char *)topSeg); free((char *)botSeg); return; } /* left shadow */ tCount = 0; for (i = 0; i < st; i++) { topSeg[tCount].x1 = rect->x + i; topSeg[tCount].y1 = rect->y + i; topSeg[tCount].x2 = rect->x + i; topSeg[tCount].y2 = rect->y + rect->height - i - 1; tCount++; } if (tCount) { SetGC(f, GC_SHADOWTOP); XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount); SetGC(f, GC_UNSET); } /* right shadow */ bCount = 0; for (i = 0; i < st; i++) { botSeg[bCount].x1 = rect->x + rect->width - i - 1; botSeg[bCount].y1 = rect->y + i; botSeg[bCount].x2 = rect->x + rect->width - i - 1; botSeg[bCount].y2 = rect->y + rect->height - i - 1; bCount++; } if (bCount) { SetGC(f, GC_SHADOWBOT); XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount); SetGC(f, GC_UNSET); } /* bottom shadow */ bCount = 0; for (i = 0; i < st; i++) { botSeg[bCount].x1 = rect->x + i; botSeg[bCount].y1 = rect->y + rect->height - i - 1; botSeg[bCount].x2 = rect->x + rect->width - i - 1; botSeg[bCount].y2 = rect->y + rect->height - i - 1; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) { botSeg[bCount].y1 = botOff - botSeg[bCount].y1; botSeg[bCount].y2 = botOff - botSeg[bCount].y2; } bCount++; } if (bCount) { if (f->folder.tabPlacement == XmFOLDER_TOP) SetGC(f, GC_SHADOWBOT); else SetGC(f, GC_SHADOWTOP); XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount); SetGC(f, GC_UNSET); } free((char *)topSeg); free((char *)botSeg); } static void DrawManagerShadowLeftRight(XmLFolderWidget f, XRectangle *rect) { Display *dpy; Window win; XmLFolderConstraintRec *fc; XSegment *topSeg, *botSeg; int i, bCount, tCount, st, rightOff; dpy = XtDisplay(f); win = XtWindow(f); st = f->manager.shadow_thickness; if (!st) return; rightOff = f->core.width - f->folder.tabWidth - 1; topSeg = (XSegment *)malloc(sizeof(XSegment) * st * 2); botSeg = (XSegment *)malloc(sizeof(XSegment) * st * 2); /* left shadow */ fc = 0; if (f->folder.activeW) fc = (XmLFolderConstraintRec *)(f->folder.activeW->core.constraints); tCount = 0; if (fc) for (i = 0; i < st; i++) { topSeg[tCount].x1 = rect->x + i; topSeg[tCount].y1 = rect->y + i; topSeg[tCount].x2 = rect->x + i; topSeg[tCount].y2 = fc->folder.y + i; if (rect->y != fc->folder.y) tCount++; topSeg[tCount].x1 = rect->x + i; topSeg[tCount].y1 = rect->y + fc->folder.y + fc->folder.height - i - 1; topSeg[tCount].x2 = rect->x + i; topSeg[tCount].y2 = rect->y + rect->height - i - 1; if (fc->folder.y + fc->folder.height != rect->height) tCount++; } else for (i = 0; i < st; i++) { topSeg[tCount].x1 = rect->x + i; topSeg[tCount].y1 = rect->y + i; topSeg[tCount].x2 = rect->x + i; topSeg[tCount].y2 = rect->y + rect->height - i - 1; tCount++; } if (f->folder.tabPlacement == XmFOLDER_RIGHT) for (i = 0 ; i < tCount; i++) { topSeg[i].x1 = rightOff - topSeg[i].x1; topSeg[i].x2 = rightOff - topSeg[i].x2; } if (tCount) { if (f->folder.tabPlacement == XmFOLDER_RIGHT) SetGC(f, GC_SHADOWBOT); else SetGC(f, GC_SHADOWTOP); XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount); SetGC(f, GC_UNSET); } /* top shadow */ tCount = 0; for (i = 0; i < st; i++) { topSeg[tCount].x1 = rect->x + i; topSeg[tCount].y1 = rect->y + i; topSeg[tCount].x2 = rect->x + rect->width - i - 1; topSeg[tCount].y2 = rect->y + i; tCount++; } if (tCount) { SetGC(f, GC_SHADOWTOP); XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount); SetGC(f, GC_UNSET); } /* bottom shadow */ bCount = 0; for (i = 0; i < st; i++) { botSeg[bCount].x1 = rect->x + i; botSeg[bCount].y1 = rect->y + rect->height - i - 1; botSeg[bCount].x2 = rect->x + rect->width - i - 1; botSeg[bCount].y2 = rect->y + rect->height - i - 1; bCount++; } if (bCount) { SetGC(f, GC_SHADOWBOT); XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount); SetGC(f, GC_UNSET); } /* right shadow */ bCount = 0; for (i = 0; i < st; i++) { botSeg[bCount].x1 = rect->x + rect->width - i - 1; botSeg[bCount].y1 = rect->y + i; botSeg[bCount].x2 = rect->x + rect->width - i - 1; botSeg[bCount].y2 = rect->y + rect->height - i - 1; if (f->folder.tabPlacement == XmFOLDER_RIGHT) { botSeg[bCount].x1 = rightOff - botSeg[bCount].x1; botSeg[bCount].x2 = rightOff - botSeg[bCount].x2; } bCount++; } if (bCount) { if (f->folder.tabPlacement == XmFOLDER_LEFT) SetGC(f, GC_SHADOWBOT); else SetGC(f, GC_SHADOWTOP); XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount); SetGC(f, GC_UNSET); } free((char *)topSeg); free((char *)botSeg); } static void DrawTabShadowArcTopBottom(XmLFolderWidget f, Widget w) { XmLFolderConstraintRec *fc; Display *dpy; Window win; XSegment *topSeg, *botSeg; XRectangle rect, rect2; XArc arc; int tCount, bCount; int i, st, cd, botOff; dpy = XtDisplay(f); win = XtWindow(f); fc = (XmLFolderConstraintRec *)(w->core.constraints); botOff = 2 * fc->folder.y + fc->folder.height - 1; st = f->manager.shadow_thickness; if (!st) return; cd = f->folder.cornerDimension; tCount = 0; bCount = 0; topSeg = (XSegment *)malloc(sizeof(XSegment) * st); botSeg = (XSegment *)malloc(sizeof(XSegment) * st); for (i = 0; i < st; i++) { /* left tab shadow */ topSeg[tCount].x1 = fc->folder.x + i; topSeg[tCount].y1 = fc->folder.y + cd + st; topSeg[tCount].x2 = fc->folder.x + i; topSeg[tCount].y2 = fc->folder.y + fc->folder.height - 1; if (w == f->folder.activeW) topSeg[tCount].y2 += i; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) { topSeg[tCount].y1 = botOff - topSeg[tCount].y1; topSeg[tCount].y2 = botOff - topSeg[tCount].y2; } tCount++; /* right tab shadow */ botSeg[bCount].x1 = fc->folder.x + fc->folder.width - i - 1; botSeg[bCount].y1 = fc->folder.y + cd + st; botSeg[bCount].x2 = fc->folder.x + fc->folder.width - i - 1; botSeg[bCount].y2 = fc->folder.y + fc->folder.height - 1; if (w == f->folder.activeW) botSeg[bCount].y2 += i; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) { botSeg[bCount].y1 = botOff - botSeg[bCount].y1; botSeg[bCount].y2 = botOff - botSeg[bCount].y2; } bCount++; } if (tCount) { SetGC(f, GC_SHADOWTOP); XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount); SetGC(f, GC_UNSET); } if (bCount) { SetGC(f, GC_SHADOWBOT); XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount); SetGC(f, GC_UNSET); } tCount = 0; for (i = 0; i < st; i++) { /* top tab shadow */ topSeg[tCount].x1 = fc->folder.x + cd + st; topSeg[tCount].y1 = fc->folder.y + i; topSeg[tCount].x2 = fc->folder.x + fc->folder.width - cd - st - 1; topSeg[tCount].y2 = fc->folder.y + i; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) { topSeg[tCount].y1 = botOff - topSeg[tCount].y1; topSeg[tCount].y2 = botOff - topSeg[tCount].y2; } tCount++; } if (tCount) { if (f->folder.tabPlacement == XmFOLDER_BOTTOM) SetGC(f, GC_SHADOWBOT); else SetGC(f, GC_SHADOWTOP); XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount); SetGC(f, GC_UNSET); } free((char *)topSeg); free((char *)botSeg); /* left corner blank background */ rect.x = fc->folder.x; rect.y = fc->folder.y; rect.width = cd + st; rect.height = cd + st; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) rect.y = fc->folder.y + fc->folder.height - rect.height; SetGC(f, GC_BLANK); XFillRectangle(dpy, win, f->folder.gc, rect.x, rect.y, rect.width, rect.height); SetGC(f, GC_UNSET); /* left arc */ /* various X Servers have problems drawing arcs - so set clip rect */ /* and draw two circles, one smaller than the other, for corner */ XSetClipRectangles(dpy, f->folder.gc, 0, 0, &rect, 1, Unsorted); arc.x = rect.x; arc.y = rect.y; arc.width = rect.width * 2; arc.height = rect.height * 2; if (f->folder.serverDrawsArcsLarge == True) { arc.width -= 1; arc.height -= 1; } arc.angle1 = 0 * 64; arc.angle2 = 360 * 64; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) arc.y = fc->folder.y + fc->folder.height - arc.height; SetGC(f, GC_SHADOWTOP); XFillArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height, arc.angle1, arc.angle2); XDrawArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height, arc.angle1, arc.angle2); SetGC(f, GC_UNSET); rect2 = rect; rect2.x += st; rect2.width -= st; rect2.height -= st; if (f->folder.tabPlacement == XmFOLDER_TOP) rect2.y += st; XSetClipRectangles(dpy, f->folder.gc, 0, 0, &rect2, 1, Unsorted); if (w == f->folder.activeW) XSetForeground(dpy, f->folder.gc, f->core.background_pixel); else XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg); arc.x += st; arc.y += st; arc.width -= st * 2; arc.height -= st * 2; XFillArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height, arc.angle1, arc.angle2); XDrawArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height, arc.angle1, arc.angle2); XSetClipMask(dpy, f->folder.gc, None); /* right corner blank background */ rect.x = fc->folder.x + fc->folder.width - cd - st; SetGC(f, GC_BLANK); XFillRectangle(dpy, win, f->folder.gc, rect.x, rect.y, rect.width, rect.height); SetGC(f, GC_UNSET); /* right arc */ XSetClipRectangles(dpy, f->folder.gc, 0, 0, &rect, 1, Unsorted); arc.x = rect.x - cd - st; arc.y = rect.y; arc.width = rect.width * 2; arc.height = rect.height * 2; if (f->folder.serverDrawsArcsLarge == True) { arc.width -= 1; arc.height -= 1; } arc.angle1 = 0 * 64; arc.angle2 = 360 * 64; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) arc.y = fc->folder.y + fc->folder.height - arc.height; SetGC(f, GC_SHADOWBOT); XFillArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height, arc.angle1, arc.angle2); XDrawArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height, arc.angle1, arc.angle2); SetGC(f, GC_UNSET); rect2 = rect; rect2.width -= st; rect2.height -= st; if (f->folder.tabPlacement == XmFOLDER_TOP) rect2.y += st; XSetClipRectangles(dpy, f->folder.gc, 0, 0, &rect2, 1, Unsorted); if (w == f->folder.activeW) XSetForeground(dpy, f->folder.gc, f->core.background_pixel); else XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg); arc.x += st; arc.y += st; arc.width -= st * 2; arc.height -= st * 2; XFillArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height, arc.angle1, arc.angle2); XDrawArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height, arc.angle1, arc.angle2); XSetClipMask(dpy, f->folder.gc, None); } static void DrawTabShadowArcLeftRight(XmLFolderWidget f, Widget w) { XmLFolderConstraintRec *fc; Display *dpy; Window win; XSegment *topSeg, *botSeg; XRectangle rect, rect2; XArc arc; int tCount, bCount; int i, st, cd, rightOff; dpy = XtDisplay(f); win = XtWindow(f); fc = (XmLFolderConstraintRec *)(w->core.constraints); rightOff = 2 * fc->folder.x + fc->folder.width - 1; st = f->manager.shadow_thickness; if (!st) return; cd = f->folder.cornerDimension; tCount = 0; bCount = 0; topSeg = (XSegment *)malloc(sizeof(XSegment) * st); botSeg = (XSegment *)malloc(sizeof(XSegment) * st); for (i = 0; i < st; i++) { /* top tab shadow */ topSeg[tCount].x1 = fc->folder.x + cd + st; topSeg[tCount].y1 = fc->folder.y + i; topSeg[tCount].x2 = fc->folder.x + fc->folder.width - 1; if (w == f->folder.activeW) topSeg[tCount].x2 += i; topSeg[tCount].y2 = fc->folder.y + i; if (f->folder.tabPlacement == XmFOLDER_RIGHT) { topSeg[tCount].x1 = rightOff - topSeg[tCount].x1; topSeg[tCount].x2 = rightOff - topSeg[tCount].x2; } tCount++; /* bottom tab shadow */ botSeg[bCount].x1 = fc->folder.x + cd + st; botSeg[bCount].y1 = fc->folder.y + fc->folder.height - i - 1; botSeg[bCount].x2 = fc->folder.x + fc->folder.width - 1; if (w == f->folder.activeW) botSeg[bCount].x2 += i; botSeg[bCount].y2 = fc->folder.y + fc->folder.height - i - 1; if (f->folder.tabPlacement == XmFOLDER_RIGHT) { botSeg[bCount].x1 = rightOff - botSeg[bCount].x1; botSeg[bCount].x2 = rightOff - botSeg[bCount].x2; } bCount++; } if (tCount) { SetGC(f, GC_SHADOWTOP); XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount); SetGC(f, GC_UNSET); } if (bCount) { SetGC(f, GC_SHADOWBOT); XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount); SetGC(f, GC_UNSET); } tCount = 0; for (i = 0; i < st; i++) { /* left tab shadow */ topSeg[tCount].x1 = fc->folder.x + i; topSeg[tCount].y1 = fc->folder.y + cd + st; topSeg[tCount].x2 = fc->folder.x + i; topSeg[tCount].y2 = fc->folder.y + fc->folder.height - cd - st - 1; if (f->folder.tabPlacement == XmFOLDER_RIGHT) { topSeg[tCount].x1 = rightOff - topSeg[tCount].x1; topSeg[tCount].x2 = rightOff - topSeg[tCount].x2; } tCount++; } if (tCount) { if (f->folder.tabPlacement == XmFOLDER_RIGHT) SetGC(f, GC_SHADOWBOT); else SetGC(f, GC_SHADOWTOP); XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount); SetGC(f, GC_UNSET); } free((char *)topSeg); free((char *)botSeg); /* top corner blank background */ rect.x = fc->folder.x; rect.y = fc->folder.y; rect.width = cd + st; rect.height = cd + st; if (f->folder.tabPlacement == XmFOLDER_RIGHT) rect.x = fc->folder.x + fc->folder.width - rect.width; SetGC(f, GC_BLANK); XFillRectangle(dpy, win, f->folder.gc, rect.x, rect.y, rect.width, rect.height); SetGC(f, GC_UNSET); /* top arc */ XSetClipRectangles(dpy, f->folder.gc, 0, 0, &rect, 1, Unsorted); arc.x = rect.x; arc.y = rect.y; arc.width = rect.width * 2; arc.height = rect.height * 2; if (f->folder.serverDrawsArcsLarge == True) { arc.width -= 1; arc.height -= 1; } arc.angle1 = 0 * 64; arc.angle2 = 360 * 64; if (f->folder.tabPlacement == XmFOLDER_RIGHT) arc.x = fc->folder.x + fc->folder.width - arc.width; SetGC(f, GC_SHADOWTOP); XFillArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height, arc.angle1, arc.angle2); XDrawArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height, arc.angle1, arc.angle2); SetGC(f, GC_UNSET); rect2 = rect; rect2.width -= st; rect2.height -= st; rect2.y += st; if (f->folder.tabPlacement == XmFOLDER_LEFT) rect2.x += st; XSetClipRectangles(dpy, f->folder.gc, 0, 0, &rect2, 1, Unsorted); if (w == f->folder.activeW) XSetForeground(dpy, f->folder.gc, f->core.background_pixel); else XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg); arc.x += st; arc.y += st; arc.width -= st * 2; arc.height -= st * 2; XFillArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height, arc.angle1, arc.angle2); XDrawArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height, arc.angle1, arc.angle2); XSetClipMask(dpy, f->folder.gc, None); /* bottom corner blank background */ rect.y = fc->folder.y + fc->folder.height - cd - st; SetGC(f, GC_BLANK); XFillRectangle(dpy, win, f->folder.gc, rect.x, rect.y, rect.width, rect.height); SetGC(f, GC_UNSET); /* bottom arc */ XSetClipRectangles(dpy, f->folder.gc, 0, 0, &rect, 1, Unsorted); arc.x = rect.x; arc.y = rect.y - cd - st; arc.width = rect.width * 2; arc.height = rect.height * 2; if (f->folder.serverDrawsArcsLarge == True) { arc.width -= 1; arc.height -= 1; } arc.angle1 = 0 * 64; arc.angle2 = 360 * 64; if (f->folder.tabPlacement == XmFOLDER_RIGHT) arc.x = fc->folder.x + fc->folder.width - arc.width; SetGC(f, GC_SHADOWBOT); XFillArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height, arc.angle1, arc.angle2); XDrawArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height, arc.angle1, arc.angle2); SetGC(f, GC_UNSET); rect2 = rect; rect2.width -= st; rect2.height -= st; if (f->folder.tabPlacement == XmFOLDER_LEFT) rect2.x += st; XSetClipRectangles(dpy, f->folder.gc, 0, 0, &rect2, 1, Unsorted); if (w == f->folder.activeW) XSetForeground(dpy, f->folder.gc, f->core.background_pixel); else XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg); arc.x += st; arc.y += st; arc.width -= st * 2; arc.height -= st * 2; XFillArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height, arc.angle1, arc.angle2); XDrawArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height, arc.angle1, arc.angle2); XSetClipMask(dpy, f->folder.gc, None); } static void DrawTabShadowLineTopBottom(XmLFolderWidget f, Widget w) { XmLFolderConstraintRec *fc; Display *dpy; Window win; XSegment *topSeg, *botSeg; XPoint points[4]; int tCount, bCount, botOff, i, st, cd, y; dpy = XtDisplay(f); win = XtWindow(f); fc = (XmLFolderConstraintRec *)(w->core.constraints); botOff = 2 * fc->folder.y + fc->folder.height - 1; st = f->manager.shadow_thickness; if (!st) return; cd = f->folder.cornerDimension; tCount = 0; bCount = 0; topSeg = (XSegment *)malloc(sizeof(XSegment) * st); botSeg = (XSegment *)malloc(sizeof(XSegment) * st); for (i = 0; i < st; i++) { /* left tab shadow */ topSeg[tCount].x1 = fc->folder.x + i; topSeg[tCount].y1 = fc->folder.y + cd + st; topSeg[tCount].x2 = fc->folder.x + i; topSeg[tCount].y2 = fc->folder.y + fc->folder.height - 1; if (w == f->folder.activeW) topSeg[tCount].y2 += i; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) { topSeg[tCount].y1 = botOff - topSeg[tCount].y1; topSeg[tCount].y2 = botOff - topSeg[tCount].y2; } tCount++; /* right tab shadow */ botSeg[bCount].x1 = fc->folder.x + fc->folder.width - i - 1; botSeg[bCount].y1 = fc->folder.y + cd + st; botSeg[bCount].x2 = fc->folder.x + fc->folder.width - i - 1; botSeg[bCount].y2 = fc->folder.y + fc->folder.height - 1; if (w == f->folder.activeW) botSeg[bCount].y2 += i; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) { botSeg[bCount].y1 = botOff - botSeg[bCount].y1; botSeg[bCount].y2 = botOff - botSeg[bCount].y2; } bCount++; } if (tCount) { SetGC(f, GC_SHADOWTOP); XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount); SetGC(f, GC_UNSET); } if (bCount) { SetGC(f, GC_SHADOWBOT); XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount); SetGC(f, GC_UNSET); } tCount = 0; for (i = 0; i < st; i++) { /* top tab shadow */ topSeg[tCount].x1 = fc->folder.x + cd + st; topSeg[tCount].y1 = fc->folder.y + i; topSeg[tCount].x2 = fc->folder.x + fc->folder.width - cd - st - 1; topSeg[tCount].y2 = fc->folder.y + i; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) { topSeg[tCount].y1 = botOff - topSeg[tCount].y1; topSeg[tCount].y2 = botOff - topSeg[tCount].y2; } tCount++; } if (tCount) { if (f->folder.tabPlacement == XmFOLDER_TOP) SetGC(f, GC_SHADOWTOP); else SetGC(f, GC_SHADOWBOT); XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount); SetGC(f, GC_UNSET); } free((char *)topSeg); free((char *)botSeg); /* left top line */ points[0].x = fc->folder.x; points[0].y = fc->folder.y + cd + st - 1; points[1].x = fc->folder.x + cd + st - 1; points[1].y = fc->folder.y; points[2].x = fc->folder.x + cd + st - 1; points[2].y = fc->folder.y + cd + st - 1; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) { points[0].y = botOff - points[0].y; points[1].y = botOff - points[1].y; points[2].y = botOff - points[2].y; } y = fc->folder.y; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) y = fc->folder.y + fc->folder.height - cd - st; SetGC(f, GC_BLANK); XFillRectangle(dpy, win, f->folder.gc, fc->folder.x, y, cd + st, cd + st); SetGC(f, GC_UNSET); SetGC(f, GC_SHADOWTOP); XFillPolygon(dpy, win, f->folder.gc, points, 3, Nonconvex, CoordModeOrigin); points[3].x = points[0].x; points[3].y = points[0].y; XDrawLines(dpy, win, f->folder.gc, points, 4, CoordModeOrigin); SetGC(f, GC_UNSET); if (w == f->folder.activeW) XSetForeground(dpy, f->folder.gc, f->core.background_pixel); else XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg); points[0].x += st; points[1].y += st; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) points[1].y -= st * 2; XFillPolygon(dpy, win, f->folder.gc, points, 3, Nonconvex, CoordModeOrigin); points[3].x = points[0].x; points[3].y = points[0].y; XDrawLines(dpy, win, f->folder.gc, points, 4, CoordModeOrigin); /* right top line */ points[0].x = fc->folder.x + fc->folder.width - 1; points[0].y = fc->folder.y + cd + st - 1; points[1].x = fc->folder.x + fc->folder.width - cd - st; points[1].y = fc->folder.y; points[2].x = fc->folder.x + fc->folder.width - cd - st; points[2].y = fc->folder.y + cd + st - 1; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) { points[0].y = botOff - points[0].y; points[1].y = botOff - points[1].y; points[2].y = botOff - points[2].y; } y = fc->folder.y; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) y = fc->folder.y + fc->folder.height - cd - st; SetGC(f, GC_BLANK); XFillRectangle(dpy, win, f->folder.gc, fc->folder.x + fc->folder.width - cd - st, y, cd + st, cd + st); SetGC(f, GC_UNSET); if (f->folder.tabPlacement == XmFOLDER_TOP) SetGC(f, GC_SHADOWTOP); else SetGC(f, GC_SHADOWBOT); XFillPolygon(dpy, win, f->folder.gc, points, 3, Nonconvex, CoordModeOrigin); points[3].x = points[0].x; points[3].y = points[0].y; XDrawLines(dpy, win, f->folder.gc, points, 4, CoordModeOrigin); SetGC(f, GC_UNSET); if (w == f->folder.activeW) XSetForeground(dpy, f->folder.gc, f->core.background_pixel); else XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg); points[0].x -= st; points[1].y += st; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) points[1].y -= st * 2; XFillPolygon(dpy, win, f->folder.gc, points, 3, Nonconvex, CoordModeOrigin); points[3].x = points[0].x; points[3].y = points[0].y; XDrawLines(dpy, win, f->folder.gc, points, 4, CoordModeOrigin); } static void DrawTabShadowLineLeftRight(XmLFolderWidget f, Widget w) { XmLFolderConstraintRec *fc; Display *dpy; Window win; XSegment *topSeg, *botSeg; XPoint points[4]; int tCount, bCount, rightOff, i, st, cd, x; dpy = XtDisplay(f); win = XtWindow(f); fc = (XmLFolderConstraintRec *)(w->core.constraints); rightOff = 2 * fc->folder.x + fc->folder.width - 1; st = f->manager.shadow_thickness; if (!st) return; cd = f->folder.cornerDimension; tCount = 0; bCount = 0; topSeg = (XSegment *)malloc(sizeof(XSegment) * st); botSeg = (XSegment *)malloc(sizeof(XSegment) * st); for (i = 0; i < st; i++) { /* top tab shadow */ topSeg[tCount].x1 = fc->folder.x + cd + st; topSeg[tCount].y1 = fc->folder.y + i; topSeg[tCount].x2 = fc->folder.x + fc->folder.width - 1; if (w == f->folder.activeW) topSeg[tCount].x2 += i; topSeg[tCount].y2 = fc->folder.y + i; if (f->folder.tabPlacement == XmFOLDER_RIGHT) { topSeg[tCount].x1 = rightOff - topSeg[tCount].x1; topSeg[tCount].x2 = rightOff - topSeg[tCount].x2; } tCount++; /* bottom tab shadow */ botSeg[bCount].x1 = fc->folder.x + cd + st; botSeg[bCount].y1 = fc->folder.y + fc->folder.height - i - 1; botSeg[bCount].x2 = fc->folder.x + fc->folder.width - 1; if (w == f->folder.activeW) botSeg[bCount].x2 += i; botSeg[bCount].y2 = fc->folder.y + fc->folder.height - i - 1; if (f->folder.tabPlacement == XmFOLDER_RIGHT) { botSeg[bCount].x1 = rightOff - botSeg[bCount].x1; botSeg[bCount].x2 = rightOff - botSeg[bCount].x2; } bCount++; } if (tCount) { SetGC(f, GC_SHADOWTOP); XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount); SetGC(f, GC_UNSET); } if (bCount) { SetGC(f, GC_SHADOWBOT); XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount); SetGC(f, GC_UNSET); } tCount = 0; for (i = 0; i < st; i++) { /* left tab shadow */ topSeg[tCount].x1 = fc->folder.x + i; topSeg[tCount].y1 = fc->folder.y + cd + st; topSeg[tCount].x2 = fc->folder.x + i; topSeg[tCount].y2 = fc->folder.y + fc->folder.height - cd - st - 1; if (f->folder.tabPlacement == XmFOLDER_RIGHT) { topSeg[tCount].x1 = rightOff - topSeg[tCount].x1; topSeg[tCount].x2 = rightOff - topSeg[tCount].x2; } tCount++; } if (tCount) { if (f->folder.tabPlacement == XmFOLDER_LEFT) SetGC(f, GC_SHADOWTOP); else SetGC(f, GC_SHADOWBOT); XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount); SetGC(f, GC_UNSET); } free((char *)topSeg); free((char *)botSeg); /* top line */ points[0].x = fc->folder.x + cd + st - 1; points[0].y = fc->folder.y; points[1].x = fc->folder.x; points[1].y = fc->folder.y + cd + st - 1; points[2].x = fc->folder.x + cd + st - 1; points[2].y = fc->folder.y + cd + st - 1; if (f->folder.tabPlacement == XmFOLDER_RIGHT) { points[0].x = rightOff - points[0].x; points[1].x = rightOff - points[1].x; points[2].x = rightOff - points[2].x; } if (f->folder.tabPlacement == XmFOLDER_RIGHT) x = fc->folder.x + fc->folder.width - cd - st; else x = fc->folder.x; SetGC(f, GC_BLANK); XFillRectangle(dpy, win, f->folder.gc, x, fc->folder.y, cd + st, cd + st); SetGC(f, GC_UNSET); SetGC(f, GC_SHADOWTOP); XFillPolygon(dpy, win, f->folder.gc, points, 3, Nonconvex, CoordModeOrigin); points[3].x = points[0].x; points[3].y = points[0].y; XDrawLines(dpy, win, f->folder.gc, points, 4, CoordModeOrigin); SetGC(f, GC_UNSET); if (w == f->folder.activeW) XSetForeground(dpy, f->folder.gc, f->core.background_pixel); else XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg); points[0].y += st; points[1].x += st; if (f->folder.tabPlacement == XmFOLDER_RIGHT) points[1].x -= st * 2; XFillPolygon(dpy, win, f->folder.gc, points, 3, Nonconvex, CoordModeOrigin); points[3].x = points[0].x; points[3].y = points[0].y; XDrawLines(dpy, win, f->folder.gc, points, 4, CoordModeOrigin); /* bottom line */ points[0].x = fc->folder.x + cd + st - 1; points[0].y = fc->folder.y + fc->folder.height - 1; points[1].x = fc->folder.x; points[1].y = fc->folder.y + fc->folder.height - cd - st; points[2].x = fc->folder.x + cd + st - 1; points[2].y = fc->folder.y + fc->folder.height - cd - st; if (f->folder.tabPlacement == XmFOLDER_RIGHT) { points[0].x = rightOff - points[0].x; points[1].x = rightOff - points[1].x; points[2].x = rightOff - points[2].x; } if (f->folder.tabPlacement == XmFOLDER_RIGHT) x = fc->folder.x + fc->folder.width - cd - st; else x = fc->folder.x; SetGC(f, GC_BLANK); XFillRectangle(dpy, win, f->folder.gc, x, fc->folder.y + fc->folder.height - cd - st, cd + st, cd + st); SetGC(f, GC_UNSET); SetGC(f, GC_SHADOWBOT); XFillPolygon(dpy, win, f->folder.gc, points, 3, Nonconvex, CoordModeOrigin); points[3].x = points[0].x; points[3].y = points[0].y; XDrawLines(dpy, win, f->folder.gc, points, 4, CoordModeOrigin); SetGC(f, GC_UNSET); if (w == f->folder.activeW) XSetForeground(dpy, f->folder.gc, f->core.background_pixel); else XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg); points[0].y -= st; points[1].x += st; if (f->folder.tabPlacement == XmFOLDER_RIGHT) points[1].x -= st * 2; XFillPolygon(dpy, win, f->folder.gc, points, 3, Nonconvex, CoordModeOrigin); points[3].x = points[0].x; points[3].y = points[0].y; XDrawLines(dpy, win, f->folder.gc, points, 4, CoordModeOrigin); } static void DrawTabShadowNoneTopBottom(XmLFolderWidget f, Widget w) { XmLFolderConstraintRec *fc; Display *dpy; Window win; XSegment *topSeg, *botSeg; int i, st, botOff, tCount, bCount; dpy = XtDisplay(f); win = XtWindow(f); fc = (XmLFolderConstraintRec *)(w->core.constraints); botOff = 2 * fc->folder.y + fc->folder.height - 1; st = f->manager.shadow_thickness; if (!st) return; tCount = 0; bCount = 0; topSeg = (XSegment *)malloc(sizeof(XSegment) * st * 2); botSeg = (XSegment *)malloc(sizeof(XSegment) * st * 2); for (i = 0; i < st; i++) { /* left tab shadow */ topSeg[tCount].x1 = fc->folder.x + i; topSeg[tCount].y1 = fc->folder.y + i; topSeg[tCount].x2 = fc->folder.x + i; topSeg[tCount].y2 = fc->folder.y + fc->folder.height - 1; if (w == f->folder.activeW) topSeg[tCount].y2 += i; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) { topSeg[tCount].y1 = botOff - topSeg[tCount].y1; topSeg[tCount].y2 = botOff - topSeg[tCount].y2; } tCount++; /* right tab shadow */ botSeg[bCount].x1 = fc->folder.x + fc->folder.width - 1 - i; botSeg[bCount].y1 = fc->folder.y + i; botSeg[bCount].x2 = fc->folder.x + fc->folder.width - 1 - i; botSeg[bCount].y2 = fc->folder.y + fc->folder.height - 1; if (w == f->folder.activeW) botSeg[bCount].y2 += i; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) { botSeg[bCount].y1 = botOff - botSeg[bCount].y1; botSeg[bCount].y2 = botOff - botSeg[bCount].y2; } bCount++; } if (tCount) { SetGC(f, GC_SHADOWTOP); XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount); SetGC(f, GC_UNSET); } if (bCount) { SetGC(f, GC_SHADOWBOT); XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount); SetGC(f, GC_UNSET); } tCount = 0; for (i = 0; i < st; i++) { /* top tab shadow */ topSeg[tCount].x1 = fc->folder.x + i + 1; topSeg[tCount].y1 = fc->folder.y + i; topSeg[tCount].x2 = fc->folder.x + fc->folder.width - i - 1; topSeg[tCount].y2 = fc->folder.y + i; if (f->folder.tabPlacement == XmFOLDER_BOTTOM) { topSeg[tCount].y1 = botOff - topSeg[tCount].y1; topSeg[tCount].y2 = botOff - topSeg[tCount].y2; } tCount++; } if (tCount) { if (f->folder.tabPlacement == XmFOLDER_TOP) SetGC(f, GC_SHADOWTOP); else SetGC(f, GC_SHADOWBOT); XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount); SetGC(f, GC_UNSET); } free((char *)topSeg); free((char *)botSeg); } static void DrawTabShadowNoneLeftRight(XmLFolderWidget f, Widget w) { XmLFolderConstraintRec *fc; Display *dpy; Window win; XSegment *topSeg, *botSeg; int i, st, rightOff, tCount, bCount; dpy = XtDisplay(f); win = XtWindow(f); fc = (XmLFolderConstraintRec *)(w->core.constraints); rightOff = 2 * fc->folder.x + fc->folder.width - 1; st = f->manager.shadow_thickness; if (!st) return; tCount = 0; bCount = 0; topSeg = (XSegment *)malloc(sizeof(XSegment) * st * 2); botSeg = (XSegment *)malloc(sizeof(XSegment) * st * 2); for (i = 0; i < st; i++) { /* bottom tab shadow */ topSeg[tCount].x1 = fc->folder.x + i; topSeg[tCount].y1 = fc->folder.y + i; topSeg[tCount].x2 = fc->folder.x + fc->folder.width - 1; if (w == f->folder.activeW) topSeg[tCount].x2 += i; topSeg[tCount].y2 = fc->folder.y + i; if (f->folder.tabPlacement == XmFOLDER_RIGHT) { topSeg[tCount].x1 = rightOff - topSeg[tCount].x1; topSeg[tCount].x2 = rightOff - topSeg[tCount].x2; } tCount++; /* top tab shadow */ botSeg[bCount].x1 = fc->folder.x + i; botSeg[bCount].y1 = fc->folder.y + fc->folder.height - i - 1; botSeg[bCount].x2 = fc->folder.x + fc->folder.width - 1; if (w == f->folder.activeW) botSeg[bCount].x2 += i; botSeg[bCount].y2 = fc->folder.y + fc->folder.height - i - 1; if (f->folder.tabPlacement == XmFOLDER_RIGHT) { botSeg[bCount].x1 = rightOff - botSeg[bCount].x1; botSeg[bCount].x2 = rightOff - botSeg[bCount].x2; } bCount++; } if (tCount) { SetGC(f, GC_SHADOWTOP); XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount); SetGC(f, GC_UNSET); } if (bCount) { SetGC(f, GC_SHADOWBOT); XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount); SetGC(f, GC_UNSET); } tCount = 0; for (i = 0; i < st; i++) { /* left tab shadow */ topSeg[tCount].x1 = fc->folder.x + i; topSeg[tCount].y1 = fc->folder.y + i + 1; topSeg[tCount].x2 = fc->folder.x + i; topSeg[tCount].y2 = fc->folder.y + fc->folder.height - i - 1; if (f->folder.tabPlacement == XmFOLDER_RIGHT) { topSeg[tCount].x1 = rightOff - topSeg[tCount].x1; topSeg[tCount].x2 = rightOff - topSeg[tCount].x2; } tCount++; } if (tCount) { if (f->folder.tabPlacement == XmFOLDER_RIGHT) SetGC(f, GC_SHADOWBOT); else SetGC(f, GC_SHADOWTOP); XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount); SetGC(f, GC_UNSET); } free((char *)topSeg); free((char *)botSeg); } static void SetGC(XmLFolderWidget f, int type) { Display *dpy; XGCValues values; XtGCMask mask; dpy = XtDisplay(f); if (type == GC_SHADOWBOT) { mask = GCForeground; values.foreground = f->manager.bottom_shadow_color; if (f->manager.bottom_shadow_pixmap != XmUNSPECIFIED_PIXMAP) { mask |= GCFillStyle | GCTile; values.fill_style = FillTiled; values.tile = f->manager.bottom_shadow_pixmap; } XChangeGC(dpy, f->folder.gc, mask, &values); } else if (type == GC_SHADOWTOP) { mask = GCForeground; values.foreground = f->manager.top_shadow_color; if (f->manager.top_shadow_pixmap != XmUNSPECIFIED_PIXMAP) { mask |= GCFillStyle | GCTile; values.fill_style = FillTiled; values.tile = f->manager.top_shadow_pixmap; } XChangeGC(dpy, f->folder.gc, mask, &values); } else if (type == GC_BLANK) { mask = GCForeground; values.foreground = f->folder.blankBg; if (f->folder.blankPix != XmUNSPECIFIED_PIXMAP) { mask |= GCFillStyle | GCTile; values.fill_style = FillTiled; values.tile = f->folder.blankPix; } XChangeGC(dpy, f->folder.gc, mask, &values); } else { mask = GCFillStyle; values.fill_style = FillSolid; XChangeGC(dpy, f->folder.gc, mask, &values); } } static void DrawTabHighlight(XmLFolderWidget f, Widget w) { XmLFolderConstraintRec *fc; Display *dpy; Window win; int ht; if (!XtIsRealized(w)) return; if (!f->core.visible) return; dpy = XtDisplay(f); win = XtWindow(f); fc = (XmLFolderConstraintRec *)(w->core.constraints); ht = f->folder.highlightThickness; if (f->folder.focusW == w) XSetForeground(dpy, f->folder.gc, f->manager.highlight_color); else { if (f->folder.activeW == w) XSetForeground(dpy, f->folder.gc, f->core.background_pixel); else XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg); } XFillRectangle(dpy, win, f->folder.gc, w->core.x - ht, w->core.y - ht, XtWidth(w) + w->core.border_width * 2 + ht * 2, XtHeight(w) + w->core.border_width * 2 + ht * 2); } static void SetTabPlacement(XmLFolderWidget f, Widget tab) { if (!XmIsDrawnButton(tab)) return; if (f->folder.allowRotate == True && f->folder.tabPlacement == XmFOLDER_LEFT) XmLDrawnButtonSetType(tab, XmDRAWNB_STRING, XmDRAWNB_UP); else if (f->folder.allowRotate == True && f->folder.tabPlacement == XmFOLDER_RIGHT) XmLDrawnButtonSetType(tab, XmDRAWNB_STRING, XmDRAWNB_DOWN); else XmLDrawnButtonSetType(tab, XmDRAWNB_STRING, XmDRAWNB_RIGHT); if (XtIsRealized(tab)) XClearArea(XtDisplay(tab), XtWindow(tab), 0, 0, 0, 0, True); } static void GetTabRect(XmLFolderWidget f, Widget tab, XRectangle *rect, int includeShadow) { XmLFolderConstraintRec *fc; int st; st = f->manager.shadow_thickness; fc = (XmLFolderConstraintRec *)(tab->core.constraints); rect->x = fc->folder.x; rect->y = fc->folder.y; rect->width = fc->folder.width; rect->height = fc->folder.height; if (includeShadow) { if (f->folder.tabPlacement == XmFOLDER_TOP) rect->height += st; else if (f->folder.tabPlacement == XmFOLDER_BOTTOM) { rect->y -= st; rect->height += st; } else if (f->folder.tabPlacement == XmFOLDER_LEFT) rect->width += st; else { rect->x -= st; rect->width += st; } } } static void SetActiveTab(XmLFolderWidget f, Widget w, XEvent *event, Boolean notify) { XmLFolderCallbackStruct cbs; XmLFolderConstraintRec *fc, *cfc; int i, j, pos; Display *dpy; Window win; Widget activeW, child, mw, managedW; WidgetList children; XRectangle rect; char *name, buf[256]; win = (Window)NULL; if (f->folder.activeW == w) return; dpy = 0; if (XtIsRealized((Widget)f) && f->core.visible) { dpy = XtDisplay(f); win = XtWindow(f); } pos = -1; for (i = 0; i < f->folder.tabCount; i++) if (w == f->folder.tabs[i]) pos = i; cbs.allowActivate = 1; cbs.layoutNeeded = 0; if (notify == True) { if (f->folder.debugLevel) fprintf(stderr, "XmLFolder: activated %d\n", pos); cbs.reason = XmCR_ACTIVATE; cbs.event = event; cbs.pos = pos; XtCallCallbackList((Widget)f, f->folder.activateCallback, &cbs); } if (!cbs.allowActivate) return; /* redraw current active tab */ activeW = f->folder.activeW; if (activeW && dpy) { GetTabRect(f, activeW, &rect, 1); XClearArea(dpy, win, rect.x, rect.y, rect.width, rect.height, True); } f->folder.activeTab = pos; f->folder.activeW = w; if (!w) return; /* Not sure this needs to be in the 3.0 (Microline) stuff */ PrimFocusIn(w, NULL, NULL, NULL); /* if we selected a tab not in active row - move row into place */ if (f->folder.tabsPerRow) { fc = (XmLFolderConstraintRec *)(w->core.constraints); if (fc->folder.row != f->folder.activeRow) Layout(f, False); } /* manage this tabs managed widget if it exists */ children = f->composite.children; f->folder.allowLayout = 0; for (i = 0; i < f->composite.num_children; i++) { child = children[i]; if (!XtIsSubclass(child, xmPrimitiveWidgetClass)) continue; fc = (XmLFolderConstraintRec *)(child->core.constraints); managedW = 0; if (fc->folder.managedName) { for (j = 0; j < f->composite.num_children; j++) { mw = children[j]; if (XtIsSubclass(mw, xmPrimitiveWidgetClass)) continue; name = XtName(mw); if (name && !strcmp(name, fc->folder.managedName)) managedW = mw; cfc = (XmLFolderConstraintRec *)(mw->core.constraints); name = cfc->folder.managedName; if (name && !strcmp(name, fc->folder.managedName)) managedW = mw; } if (!managedW) { sprintf(buf, "SetActiveTab() - managed widget named "); strcat(buf, fc->folder.managedName); strcat(buf, " not found"); XmLWarning(child, buf); } } else managedW = fc->folder.managedW; if (managedW) { if (w == child && !XtIsManaged(managedW)) XtManageChild(managedW); if (w != child && XtIsManaged(managedW)) XtUnmanageChild(managedW); } } f->folder.allowLayout = 1; /* redraw new active tab */ if (dpy) { GetTabRect(f, w, &rect, 1); XClearArea(dpy, win, rect.x, rect.y, rect.width, rect.height, True); XmProcessTraversal(w, XmTRAVERSE_CURRENT); } if (cbs.layoutNeeded) Layout(f, 0); } /* Utility */ static void GetCoreBackground(Widget w, int offset, XrmValue *value) { value->addr = (caddr_t)&w->core.background_pixel; } static void GetDefaultTabWidgetClass(Widget w, int offset, XrmValue *value) { value->addr = (caddr_t)&xmDrawnButtonWidgetClass; } static void GetManagerForeground(Widget w, int offset, XrmValue *value) { XmLFolderWidget f; f = (XmLFolderWidget)w; value->addr = (caddr_t)&f->manager.foreground; } static Boolean ServerDrawsArcsLarge(Display *dpy, int debug) { Pixmap pixmap; XImage *image; Window root; long pixel; int x, y, width, height, result; GC gc; root = DefaultRootWindow(dpy); width = 5; height = 5; pixmap = XCreatePixmap(dpy, root, width, height, 1); gc = XCreateGC(dpy, pixmap, 0L, NULL); XSetForeground(dpy, gc, 0L); XFillRectangle(dpy, pixmap, gc, 0, 0, width, height); XSetForeground(dpy, gc, 1L); XDrawArc(dpy, pixmap, gc, 0, 0, width, height, 0, 360 * 64); image = XGetImage(dpy, pixmap, 0, 0, width, height, AllPlanes, ZPixmap); if (debug) { fprintf(stderr, "Test X server drawn arc (%d by %d):\n", width, height); for (y = 0; y < height; y++) { fprintf(stderr, " "); for (x = 0; x < width; x++) { pixel = XGetPixel(image, x, y); if (pixel == 0L) fprintf(stderr, "."); else fprintf(stderr, "X"); } fprintf(stderr, "\n"); } } if (XGetPixel(image, width - 1, height / 2) != 1L) { result = 1; if (debug) fprintf(stderr, "X Server Draws Arcs 1 Pixel Large\n"); } else { result = 0; if (debug) fprintf(stderr, "X Server Draws Arcs Within Bounds\n"); } XDestroyImage(image); XFreeGC(dpy, gc); XFreePixmap(dpy, pixmap); return result; } /* Getting and Setting Values */ static Boolean SetValues(Widget curW, Widget reqW, Widget newW, ArgList args, Cardinal *narg) { XmLFolderWidget f; XmLFolderWidget cur; int i; Boolean needsLayout, needsRedisplay; f = (XmLFolderWidget)newW; cur = (XmLFolderWidget)curW; needsLayout = False; needsRedisplay = False; #define NE(value) (f->value != cur->value) if (NE(folder.tabBarHeight)) { XmLWarning((Widget)f, "SetValues() - can't set tabBarHeight"); f->folder.tabBarHeight = cur->folder.tabBarHeight; } if (NE(folder.tabCount)) { XmLWarning((Widget)f, "SetValues() - can't set tabCount"); f->folder.tabCount = cur->folder.tabCount; } if (NE(folder.activeTab)) { XmLWarning((Widget)f, "SetValues() - can't set activeTab"); f->folder.activeTab = cur->folder.activeTab; } if (f->folder.cornerDimension < 1) { XmLWarning((Widget)f, "SetValues() - cornerDimension can't be < 1"); f->folder.cornerDimension = cur->folder.cornerDimension; } if (NE(folder.tabPlacement) || NE(folder.allowRotate)) { f->folder.allowLayout = 0; for (i = 0; i < f->folder.tabCount; i++) SetTabPlacement(f, f->folder.tabs[i]); f->folder.allowLayout = 1; needsLayout = True; } if (NE(folder.inactiveBg) || NE(folder.blankBg) || NE(folder.blankPix) || NE(folder.inactiveFg)) needsRedisplay = True; if (NE(folder.cornerDimension) || NE(folder.cornerStyle) || NE(folder.highlightThickness) || NE(folder.marginHeight) || NE(folder.marginWidth) || NE(folder.pixmapMargin) || NE(manager.shadow_thickness) || NE(folder.tabsPerRow) || NE(folder.spacing)) needsLayout = True; if (NE(folder.fontList)) { XmFontListFree(cur->folder.fontList); CopyFontList(f); } #undef NE if (needsLayout == True) Layout(f, 1); return needsRedisplay; } static void CopyFontList(XmLFolderWidget f) { if (!f->folder.fontList) f->folder.fontList = XmLFontListCopyDefault((Widget)f); else f->folder.fontList = XmFontListCopy(f->folder.fontList); if (!f->folder.fontList) XmLWarning((Widget)f, "- fatal error - font list NULL"); } static Boolean ConstraintSetValues(Widget curW, Widget reqW, Widget newW, ArgList args, Cardinal *narg) { XmLFolderConstraintRec *cons, *curCons; XmLFolderWidget f; int i, hasLabelChange; f = (XmLFolderWidget)XtParent(newW); if (!XtIsRectObj(newW)) return False; cons = (XmLFolderConstraintRec *)newW->core.constraints; curCons = (XmLFolderConstraintRec *)curW->core.constraints; #define NE(value) (cons->value != curCons->value) if (NE(folder.managedName)) { if (curCons->folder.managedName) free((char *)curCons->folder.managedName); if (cons->folder.managedName) cons->folder.managedName = (char *)strdup(cons->folder.managedName); } #undef NE hasLabelChange = 0; if (XtIsSubclass(newW, xmPrimitiveWidgetClass)) { for (i = 0; i < *narg; i++) if (args[i].name && !strcmp(args[i].name, XmNlabelString)) hasLabelChange = 1; if (hasLabelChange && (f->folder.tabPlacement == XmFOLDER_LEFT || f->folder.tabPlacement == XmFOLDER_RIGHT)) { f->folder.allowLayout = 0; for (i = 0; i < f->folder.tabCount; i++) SetTabPlacement(f, f->folder.tabs[i]); f->folder.allowLayout = 1; } } if (hasLabelChange || curCons->folder.pix != cons->folder.pix || curCons->folder.inactPix != cons->folder.inactPix) Layout((XmLFolderWidget)XtParent(curW), 1); return False; } static Boolean CvtStringToCornerStyle(Display *dpy, XrmValuePtr args, Cardinal *narg, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data) { static XmLStringToUCharMap map[] = { { "CORNER_NONE", XmCORNER_NONE }, { "CORNER_LINE", XmCORNER_LINE }, { "CORNER_ARC", XmCORNER_ARC }, { 0, 0 }, }; return XmLCvtStringToUChar(dpy, "XmRCornerStyle", map, fromVal, toVal); } static Boolean CvtStringToFolderResizePolicy(Display *dpy, XrmValuePtr args, Cardinal *narg, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data) { static XmLStringToUCharMap map[] = { { "RESIZE_NONE", XmRESIZE_NONE }, { "RESIZE_STATIC", XmRESIZE_STATIC }, { "RESIZE_DYNAMIC", XmRESIZE_DYNAMIC }, { "RESIZE_PACK", XmRESIZE_PACK }, { 0, 0 }, }; return XmLCvtStringToUChar(dpy, "XmRFolderResizePolicy", map, fromVal, toVal); } static Boolean CvtStringToTabPlacement(Display *dpy, XrmValuePtr args, Cardinal *narg, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data) { static XmLStringToUCharMap map[] = { { "FOLDER_TOP", XmFOLDER_TOP }, { "FOLDER_LEFT", XmFOLDER_LEFT }, { "FOLDER_BOTTOM", XmFOLDER_BOTTOM }, { "FOLDER_RIGHT", XmFOLDER_RIGHT }, { 0, 0 }, }; return XmLCvtStringToUChar(dpy, "XmRTabPlacement", map, fromVal, toVal); } /* Actions, Callbacks and Handlers */ static void Activate(Widget w, XEvent *event, String *params, Cardinal *nparam) { XmLFolderWidget f; XButtonEvent *be; XRectangle rect; Widget tab; int i; f = (XmLFolderWidget)w; if (!event || event->type != ButtonPress) return; be = (XButtonEvent *)event; if (f->folder.debugLevel) fprintf(stderr, "XmLFolder: ButtonPress %d %d\n", be->x, be->y); for (i = 0; i < f->folder.tabCount; i++) { tab = f->folder.tabs[i]; if (!XtIsManaged(tab) || !XtIsSensitive(tab)) continue; GetTabRect(f, tab, &rect, 0); if (be->x > rect.x && be->x < rect.x + (int)rect.width && be->y > rect.y && be->y < rect.y + (int)rect.height) { if (f->folder.debugLevel) fprintf(stderr, "XmLFolder: Pressed tab %d\n", i); SetActiveTab(f, tab, event, True); return; } } } static void PrimActivate(Widget w, XtPointer clientData, XtPointer callData) { XmLFolderWidget f; XmAnyCallbackStruct *cbs; f = (XmLFolderWidget)XtParent(w); cbs = (XmAnyCallbackStruct *)callData; SetActiveTab(f, w, cbs->event, True); } static void PrimFocusIn(Widget w, XEvent *event, String *params, Cardinal *nparam) { XmLFolderWidget f; Widget prevW; f = (XmLFolderWidget)XtParent(w); prevW = f->folder.focusW; f->folder.focusW = w; DrawTabHighlight(f, w); if (prevW) DrawTabHighlight(f, prevW); XmProcessTraversal(w, XmTRAVERSE_CURRENT); } static void PrimFocusOut(Widget w, XEvent *event, String *params, Cardinal *nparam) { XmLFolderWidget f; Widget prevW; f = (XmLFolderWidget)XtParent(w); prevW = f->folder.focusW; f->folder.focusW = 0; if (prevW) DrawTabHighlight(f, prevW); DrawTabHighlight(f, w); } /* Public Functions */ Widget XmLCreateFolder(Widget parent, char *name, ArgList arglist, Cardinal argcount) { return XtCreateWidget(name, xmlFolderWidgetClass, parent, arglist, argcount); } Widget XmLFolderAddBitmapTab(Widget w, XmString string, char *bitmapBits, int bitmapWidth, int bitmapHeight) { XmLFolderWidget f; Widget tab; Pixmap pix, inactPix; Window root; Display *dpy; int depth; char name[20]; if (!XmLIsFolder(w)) { XmLWarning(w, "AddBitmapTab() - widget not a XmLFolder"); return 0; } f = (XmLFolderWidget)w; dpy = XtDisplay(w); root = DefaultRootWindow(dpy); depth = DefaultDepthOfScreen(XtScreen(w)); pix = XCreatePixmapFromBitmapData(dpy, root, bitmapBits, bitmapWidth, bitmapHeight, f->manager.foreground, f->core.background_pixel, depth); inactPix = XCreatePixmapFromBitmapData(dpy, root, bitmapBits, bitmapWidth, bitmapHeight, f->folder.inactiveFg, f->folder.inactiveBg, depth); sprintf(name, "tab%d", f->folder.tabCount); tab = XtVaCreateManagedWidget(name, f->folder.tabWidgetClass, w, XmNfontList, f->folder.fontList, XmNmarginWidth, 0, XmNmarginHeight, 0, XmNlabelString, string, XmNtabPixmap, pix, XmNtabInactivePixmap, inactPix, XmNtabFreePixmaps, True, NULL); return tab; } Widget XmLFolderAddBitmapTabForm(Widget w, XmString string, char *bitmapBits, int bitmapWidth, int bitmapHeight) { Widget form, tab; XmLFolderWidget f; char name[20]; if (!XmLIsFolder(w)) { XmLWarning(w, "AddBitmapTabForm() - widget not a XmLFolder"); return 0; } f = (XmLFolderWidget)w; tab = XmLFolderAddBitmapTab(w, string, bitmapBits, bitmapWidth, bitmapHeight); sprintf(name, "form%d", f->folder.tabCount); form = XtVaCreateManagedWidget(name, xmFormWidgetClass, w, XmNbackground, f->core.background_pixel, NULL); XtVaSetValues(tab, XmNtabManagedWidget, form, NULL); return form; } Widget XmLFolderAddTab(Widget w, XmString string) { Widget tab; XmLFolderWidget f; char name[20]; if (!XmLIsFolder(w)) { XmLWarning(w, "AddTab() - widget not a XmLFolder"); return 0; } f = (XmLFolderWidget)w; sprintf(name, "tab%d", f->folder.tabCount); tab = XtVaCreateManagedWidget(name, f->folder.tabWidgetClass, w, XmNfontList, f->folder.fontList, XmNmarginWidth, 0, XmNmarginHeight, 0, XmNlabelString, string, NULL); return tab; } Widget XmLFolderAddTabFromClass(Widget w, XmString string) { Widget tab; XmLFolderWidget f; char name[20]; if (!XmLIsFolder(w)) { XmLWarning(w, "AddTab() - widget not a XmLFolder"); return 0; } f = (XmLFolderWidget)w; sprintf(name, "tab%d", f->folder.tabCount); tab = XtVaCreateManagedWidget(name, f->folder.tabWidgetClass, /* xmDrawnButtonWidgetClass, */ w, XmNfontList, f->folder.fontList, /* XmNmarginWidth, 0, */ /* XmNmarginHeight, 0, */ XmNlabelString, string, NULL); return tab; } Widget XmLFolderAddTabForm(Widget w, XmString string) { Widget form, tab; XmLFolderWidget f; char name[20]; if (!XmLIsFolder(w)) { XmLWarning(w, "AddBitmapTabForm() - widget not a XmLFolder"); return 0; } f = (XmLFolderWidget)w; tab = XmLFolderAddTab(w, string); sprintf(name, "form%d", f->folder.tabCount); form = XtVaCreateManagedWidget(name, xmFormWidgetClass, w, XmNbackground, f->core.background_pixel, NULL); XtVaSetValues(tab, XmNtabManagedWidget, form, NULL); return form; } void XmLFolderSetActiveTab(Widget w, int position, Boolean notify) { XmLFolderWidget f; if (!XmLIsFolder(w)) { XmLWarning(w, "SetActiveTab() - widget not a XmLFolder"); return; } f = (XmLFolderWidget)w; if (position < 0 || position >= f->folder.tabCount) { XmLWarning(w, "SetActiveTab() - invalid position"); return; } SetActiveTab(f, f->folder.tabs[position], 0, notify); } nedit-5.6.orig/Microline/XmL/Folder.h0000644000175000017500000000653010245647600016127 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #ifndef XmLFolderH #define XmLFolderH #include "XmL.h" #ifdef XmL_CPP extern "C" { #endif extern WidgetClass xmlFolderWidgetClass; typedef struct _XmLFolderClassRec *XmLFolderWidgetClass; typedef struct _XmLFolderRec *XmLFolderWidget; #define XmLIsFolder(w) XtIsSubclass((w), xmlFolderWidgetClass) Widget XmLCreateFolder(Widget parent, char *name, ArgList arglist, Cardinal argcount); Widget XmLFolderAddBitmapTab(Widget w, XmString string, char *bitmapBits, int bitmapWidth, int bitmapHeight); Widget XmLFolderAddBitmapTabForm(Widget w, XmString string, char *bitmapBits, int bitmapWidth, int bitmapHeight); Widget XmLFolderAddTab(Widget w, XmString string); Widget XmLFolderAddTabFromClass(Widget w, XmString string); Widget XmLFolderAddTabForm(Widget w, XmString string); void XmLFolderSetActiveTab(Widget w, int position, Boolean notify); #ifdef XmL_CPP } #endif #endif nedit-5.6.orig/Microline/XmL/FolderP.h0000644000175000017500000001044110107542711016235 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #ifndef XmLFolderPH #define XmLFolderPH #include #ifdef MOTIF11 #else #include #endif #include "Folder.h" typedef struct _XmLFolderPart { int debugLevel; Boolean serverDrawsArcsLarge; unsigned char cornerStyle, tabPlacement, resizePolicy; Boolean allowRotate, autoSelect; GC gc; Pixel inactiveBg, inactiveFg, blankBg; Pixmap blankPix; WidgetList tabs; int tabCount, tabAllocCount; Dimension marginWidth, marginHeight, spacing; Dimension cornerDimension, highlightThickness; Dimension pixmapMargin; Dimension tabHeight, tabWidth, tabBarHeight; Dimension minTabWidth, maxTabWidth; int tabsPerRow, activeRow; XtTranslations primTrans; Widget focusW, activeW; int activeTab; char allowLayout; XtCallbackList activateCallback; XmFontList fontList; WidgetClass tabWidgetClass; } XmLFolderPart; typedef struct _XmLFolderRec { CorePart core; CompositePart composite; ConstraintPart constraint; XmManagerPart manager; XmLFolderPart folder; } XmLFolderRec; typedef struct _XmLFolderClassPart { int unused; } XmLFolderClassPart; typedef struct _XmLFolderClassRec { CoreClassPart core_class; CompositeClassPart composite_class; ConstraintClassPart constraint_class; XmManagerClassPart manager_class; XmLFolderClassPart folder_class; } XmLFolderClassRec; extern XmLFolderClassRec xmlFolderClassRec; typedef struct _XmLFolderConstraintPart { Position x, y; Dimension width, height; Dimension maxPixWidth, maxPixHeight; Dimension pixWidth, pixHeight; Dimension inactPixWidth, inactPixHeight; int row; Boolean firstInRow; Boolean freePix; Pixmap pix, inactPix; char *managedName; Widget managedW; } XmLFolderConstraintPart; typedef struct _XmLFolderConstraintRec { XmManagerConstraintPart manager; XmLFolderConstraintPart folder; } XmLFolderConstraintRec, *XmLFolderConstraintPtr; #endif nedit-5.6.orig/Microline/XmL/Grid.c0000644000175000017500000107067310077552125015606 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include "GridP.h" #include #include #include #include #ifndef MOTIF11 #include #endif #include #include #include #include #ifdef SUNOS4 int fprintf(FILE *, char *, ...); int fseek(FILE *, long, int); int fread(char *, int, int, FILE *); #endif /* Create and Destroy */ static void ClassInitialize(void); static void ClassPartInitialize(WidgetClass wc); static void Initialize(Widget req, Widget newW, ArgList args, Cardinal *nargs); static void Destroy(Widget w); /* Geometry, Drawing, Entry and Picking */ static void Realize(Widget w, XtValueMask *valueMask, XSetWindowAttributes *attr); static void Redisplay(Widget w, XExposeEvent *event, Region region); static void DrawResizeLine(XmLGridWidget g, int xy, int erase); static void DrawXORRect(XmLGridWidget g, int xy, int size, int isVert, int erase); static void DefineCursor(XmLGridWidget g, char defineCursor); static void DrawArea(XmLGridWidget g, int type, int row, int col); static void ExtendSelectRange(XmLGridWidget g, int *type, int *fr, int *lr, int *fc, int *lc); static void ExtendSelect(XmLGridWidget g, XEvent *event, Boolean set, int row, int col); static void SelectTypeArea(XmLGridWidget g, int type, XEvent *event, int row, int col, Boolean select, Boolean notify); static int GetSelectedArea(XmLGridWidget g, int type, int *rowPos, int *colPos, int count); static void ChangeManaged(Widget w); static void Resize(Widget w); static void PlaceScrollbars(XmLGridWidget w); static void VertLayout(XmLGridWidget g, int resizeIfNeeded); static void HorizLayout(XmLGridWidget g, int resizeIfNeeded); static void ApplyVisibleRows(XmLGridWidget g); static void ApplyVisibleCols(XmLGridWidget g); static void VisPosChanged(XmLGridWidget g, int isVert); static void RecalcVisPos(XmLGridWidget g, int isVert); static int PosToVisPos(XmLGridWidget g, int pos, int isVert); static int VisPosToPos(XmLGridWidget g, int visPos, int isVert); static unsigned char ColPosToType(XmLGridWidget g, int pos); static int ColPosToTypePos(XmLGridWidget g, unsigned char type, int pos); static unsigned char RowPosToType(XmLGridWidget g, int pos); static int RowPosToTypePos(XmLGridWidget g, unsigned char type, int pos); static int ColTypePosToPos(XmLGridWidget g, unsigned char type, int pos, int allowNeg); static int RowTypePosToPos(XmLGridWidget g, unsigned char type, int pos, int allowNeg); static int ScrollRowBottomPos(XmLGridWidget g, int row); static int ScrollColRightPos(XmLGridWidget g, int col); static int PosIsResize(XmLGridWidget g, int x, int y, int *row, int *col, int *isVert); static int XYToRowCol(XmLGridWidget g, int x, int y, int *row, int *col); static int RowColToXY(XmLGridWidget g, int row, int col, Boolean clipped, XRectangle *rect); static int RowColFirstSpan(XmLGridWidget g, int row, int col, int *spanRow, int *spanCol, XRectangle *rect, Boolean lookLeft, Boolean lookUp); static void RowColSpanRect(XmLGridWidget g, int row, int col, XRectangle *rect); static XmLGridCell GetCell(XmLGridWidget g, int row, int col); static int GetColWidth(XmLGridWidget g, int col); static int GetRowHeight(XmLGridWidget g, int row); static int ColIsVisible(XmLGridWidget g, int col); static int RowIsVisible(XmLGridWidget g, int row); static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *); static void ScrollCB(Widget w, XtPointer, XtPointer); static int FindNextFocus(XmLGridWidget g, int row, int col, int rowDir, int colDir, int *nextRow, int *nextCol); static int SetFocus(XmLGridWidget g, int row, int col, int rowDir, int colDir); static void ChangeFocus(XmLGridWidget g, int row, int col); static void MakeColVisible(XmLGridWidget g, int col); static void MakeRowVisible(XmLGridWidget g, int row); static void TextAction(XmLGridWidget g, int action); /* Getting and Setting Values */ static void GetSubValues(Widget w, ArgList args, Cardinal *nargs); static void SetSubValues(Widget w, ArgList args, Cardinal *nargs); static Boolean SetValues(Widget curW, Widget, Widget newW, ArgList args, Cardinal *nargs); static void CopyFontList(XmLGridWidget g); static Boolean CvtStringToSizePolicy(Display *dpy, XrmValuePtr args, Cardinal *numArgs, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data); static Boolean CvtStringToSelectionPolicy(Display *dpy, XrmValuePtr args, Cardinal *numArgs, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data); static Boolean CvtStringToRowColType(Display *dpy, XrmValuePtr args, Cardinal *numArgs, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data); static Boolean CvtStringToCellAlignment(Display *dpy, XrmValuePtr args, Cardinal *numArgs, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data); static Boolean CvtStringToCellType(Display *dpy, XrmValuePtr args, Cardinal *numArgs, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data); static Boolean CvtStringToCellBorderType(Display *dpy, XrmValuePtr args, Cardinal *numArgs, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data); static void SetSimpleHeadings(XmLGridWidget g, char *data); static void SetSimpleWidths(XmLGridWidget g, char *data); /* Getting and Setting Row Values */ static void GetRowValueMask(XmLGridWidget g, char *s, long *mask); static void _GetRowValueMask(XmLGridWidget g, char *s, long *mask); static void GetRowValue(XmLGridWidget g, XmLGridRow row, XtArgVal value, long mask); static void _GetRowValue(XmLGridWidget g, XmLGridRow row, XtArgVal value, long mask); static int SetRowValues(XmLGridWidget g, XmLGridRow row, long mask); static int _SetRowValues(XmLGridWidget g, XmLGridRow row, long mask); /* Getting and Setting Column Values */ static void GetColumnValueMask(XmLGridWidget g, char *s, long *mask); static void _GetColumnValueMask(XmLGridWidget g, char *s, long *mask); static void GetColumnValue(XmLGridWidget g, XmLGridColumn col, XtArgVal value, long mask); static void _GetColumnValue(XmLGridWidget g, XmLGridColumn col, XtArgVal value, long mask); static int SetColumnValues(XmLGridWidget g, XmLGridColumn col, long mask); static int _SetColumnValues(XmLGridWidget g, XmLGridColumn col, long mask); /* Getting and Setting Cell Values */ static void CellValueGetMask(char *s, long *mask); static void GetCellValue(XmLGridCell cell, XtArgVal value, long mask); static XmLGridCellRefValues *CellRefValuesCreate(XmLGridWidget g, XmLGridCellRefValues *copy); static void SetCellValuesPreprocess(XmLGridWidget g, long mask); static int SetCellHasRefValues(long mask); static int SetCellValuesResize(XmLGridWidget g, XmLGridRow row, XmLGridColumn col, XmLGridCell cell, long mask); static int _SetCellValuesResize(XmLGridWidget g, XmLGridRow row, XmLGridColumn col, XmLGridCell cell, long mask); static void SetCellValues(XmLGridWidget g, XmLGridCell cell, long mask); static void SetCellRefValues(XmLGridWidget g, XmLGridCellRefValues *values, long mask); static int SetCellRefValuesCompare(void *, void **, void **); static void SetCellRefValuesPreprocess(XmLGridWidget g, int row, int col, XmLGridCell cell, long mask); /* Read, Write, Copy, Paste */ static int Read(XmLGridWidget g, int format, char delimiter, int row, int col, char *data); static void Write(XmLGridWidget g, FILE *file, int format, char delimiter, Boolean skipHidden, int row, int col, int nrow, int ncol); static char *CopyDataCreate(XmLGridWidget g, int selected, int row, int col, int nrow, int ncol); static Boolean Copy(XmLGridWidget g, Time time, int selected, int row, int col, int nrow, int ncol); static Boolean Paste(XmLGridWidget g, int row, int col); /* Utility */ static void GetCoreBackground(Widget w, int, XrmValue *value); static void GetManagerForeground(Widget w, int, XrmValue *value); static void ClipRectToReg(XmLGridWidget g, XRectangle *rect, GridReg *reg); static char *FileToString(FILE *file); static char *CvtXmStringToStr(XmString str); static XmLGridWidget WidgetToGrid(Widget w, char *funcname); /* Actions, Callbacks and Handlers */ static void ButtonMotion(Widget w, XEvent *event, String *, Cardinal *); static void DragTimer(XtPointer, XtIntervalId *); static void CursorMotion(Widget w, XEvent *event, String *, Cardinal *); static void Edit(Widget w, XEvent *event, String *, Cardinal *); static void EditCancel(Widget w, XEvent *event, String *, Cardinal *); static void EditComplete(Widget w, XEvent *event, String *, Cardinal *); static void DragStart(Widget w, XEvent *event, String *, Cardinal *); static Boolean DragConvert(Widget w, Atom *selection, Atom *target, Atom *type, XtPointer *value, unsigned long *length, int *format); static void DragFinish(Widget w, XtPointer clientData, XtPointer callData); static void DropRegister(XmLGridWidget g, Boolean set); static void DropStart(Widget w, XtPointer clientData, XtPointer callData); static void DropTransfer(Widget w, XtPointer clientData, Atom *selType, Atom *type, XtPointer value, unsigned long *length, int *format); static void Select(Widget w, XEvent *event, String *, Cardinal *); static void PopupSelect(Widget w, XEvent *event, String *, Cardinal *); static void TextActivate(Widget w, XtPointer clientData, XtPointer callData); static void TextFocus(Widget w, XtPointer clientData, XtPointer callData); static void TextMapped(Widget w, XtPointer closure, XEvent *event, Boolean *ctd); static void TextModifyVerify(Widget w, XtPointer clientData, XtPointer callData); static void Traverse(Widget w, XEvent *event, String *, Cardinal *); /* XFE Additions */ static void EditTimer(XtPointer, XtIntervalId *); static void CreateHideUnhideButtons(XmLGridWidget g); static void HideAction(Widget w, XEvent *event, String *, Cardinal *); static void UnhideAction(Widget w, XEvent *event, String *, Cardinal *); static void setHideUnhideSensitivity(Widget w); static void MenuArm(Widget w, XEvent *event, String *, Cardinal *); static void MenuDisarm(Widget w, XEvent *event, String *, Cardinal *); static void ResizeColumnToFit(XmLGridWidget g, int x); static int SizeColumnsToFit(XmLGridWidget g, int start_at); static void GridCrossingEH(Widget w, XtPointer closure, XEvent *event, Boolean *ctd); static void GridInvokeCellCrossingCallbacks(Widget w,XtCallbackList list, int reason,XEvent * event, int row,int col); static void GridCrossingEH(Widget w,XtPointer closure,XEvent * event, Boolean * ctd); /* XmLGridRow */ static XmLGridRow XmLGridRowNew(Widget grid); static void XmLGridRowFree(Widget grid, XmLGridRow row); static XmLGridRow _GridRowNew(Widget grid); static void _GridRowFree(XmLGridRow row); static XmLArray XmLGridRowCells(XmLGridRow row); static int XmLGridRowGetPos(XmLGridRow row); static int XmLGridRowGetVisPos(XmLGridRow row); static Boolean XmLGridRowIsHidden(XmLGridRow row); static Boolean XmLGridRowIsSelected(XmLGridRow row); static void XmLGridRowSetSelected(XmLGridRow row, Boolean selected); static void XmLGridRowSetVisPos(XmLGridRow row, int visPos); static int XmLGridRowHeightInPixels(XmLGridRow row); static void XmLGridRowHeightChanged(XmLGridRow row); /* XmLGridColumn */ static XmLGridColumn XmLGridColumnNew(Widget grid); static void XmLGridColumnFree(Widget grid, XmLGridColumn column); static XmLGridColumn _GridColumnNew(Widget grid); static void _GridColumnFree(XmLGridColumn column); static int XmLGridColumnGetPos(XmLGridColumn column); static int XmLGridColumnGetVisPos(XmLGridColumn column); static Boolean XmLGridColumnIsHidden(XmLGridColumn column); static Boolean XmLGridColumnIsSelected(XmLGridColumn column); static void XmLGridColumnSetSelected(XmLGridColumn column, Boolean selected); static void XmLGridColumnSetVisPos(XmLGridColumn column, int visPos); static int XmLGridColumnWidthInPixels(XmLGridColumn column); static void XmLGridColumnWidthChanged(XmLGridColumn column); /* XmLGridCell */ static XmLGridCell XmLGridCellNew(); static void XmLGridCellFree(Widget grid, XmLGridCell cell); static int XmLGridCellAction(XmLGridCell cell, Widget w, XmLGridCallbackStruct *cbs); static int _GridCellAction(XmLGridCell cell, Widget w, XmLGridCallbackStruct *cbs); static XmLGridCellRefValues *XmLGridCellGetRefValues(XmLGridCell cell); static void XmLGridCellSetRefValues(XmLGridCell cell, XmLGridCellRefValues *values); static void XmLGridCellDerefValues(XmLGridCellRefValues *values); static Boolean XmLGridCellInRowSpan(XmLGridCell cell); static Boolean XmLGridCellInColumnSpan(XmLGridCell cell); static Boolean XmLGridCellIsSelected(XmLGridCell cell); static Boolean XmLGridCellIsValueSet(XmLGridCell cell); static void XmLGridCellSetValueSet(XmLGridCell cell, Boolean set); static void XmLGridCellSetInRowSpan(XmLGridCell cell, Boolean set); static void XmLGridCellSetInColumnSpan(XmLGridCell cell, Boolean set); static void XmLGridCellSetSelected(XmLGridCell cell, Boolean selected); static void XmLGridCellAllocIcon(XmLGridCell cell); static void XmLGridCellAllocPixmap(XmLGridCell cell); static void XmLGridCellSetString(XmLGridCell cell, XmString string, Boolean copy); static XmString XmLGridCellGetString(XmLGridCell cell); static void XmLGridCellSetToggle(XmLGridCell cell, Boolean state); static Boolean XmLGridCellGetToggle(XmLGridCell cell); static void XmLGridCellSetPixmap(XmLGridCell cell, Pixmap pixmap, Dimension width, Dimension height); static void XmLGridCellSetPixmask(XmLGridCell cell, Pixmap pixmask); static XmLGridCellPixmap *XmLGridCellGetPixmap(XmLGridCell cell); /* static void XmLGridCellClearTextString(XmLGridCell cell, Widget w); */ static int _XmLGridCellConfigureText(XmLGridCell cell, Widget w, XRectangle *rect); static int _XmLGridCellBeginTextEdit(XmLGridCell cell, Widget w, XRectangle *clipRect); static void _XmLGridCellCompleteTextEdit(XmLGridCell cell, Widget w); static void _XmLGridCellInsertText(XmLGridCell cell, Widget w); static int _XmLGridCellGetHeight(XmLGridCell cell, Widget w,XmLGridRow row); static int _XmLGridCellGetWidth(XmLGridCell cell, Widget w,XmLGridColumn col); static void _XmLGridCellFreeValue(XmLGridCell cell); /*Xfe Additions*/ static Boolean XmLGridCellDrawSort(XmLGridCell cell); static Boolean XmLGridCellSortAscending(XmLGridCell cell); static void XmLGridCellSetDrawSort(XmLGridCell cell, Boolean drawSort); static void XmLGridCellSetSortAscending(XmLGridCell cell, Boolean ascending); static XtActionsRec actions[] = { { "XmLGridEditComplete", EditComplete }, { "XmLGridButtonMotion", ButtonMotion }, { "XmLGridCursorMotion", CursorMotion }, { "XmLGridEditCancel", EditCancel }, { "XmLGridEdit", Edit }, { "XmLGridSelect", Select }, { "XmLGridPopupSelect", PopupSelect }, { "XmLGridDragStart", DragStart }, { "XmLGridTraverse", Traverse }, /* XFE Additions */ { "XmLGridHideColumn", HideAction }, { "XmLGridUnhideColumn", UnhideAction }, { "MenuArm", MenuArm }, { "MenuDisarm", MenuDisarm }, }; #define TEXT_HIDE 1 #define TEXT_SHOW 2 #define TEXT_EDIT 3 #define TEXT_EDIT_CANCEL 4 #define TEXT_EDIT_COMPLETE 5 #define TEXT_EDIT_INSERT 6 /* future defines */ #define XmTOGGLE_CELL 240 /* backwards compatibility defines */ #define XmTEXT_CELL 250 #define XmLABEL_CELL 251 /* Cursors */ #define horizp_width 19 #define horizp_height 13 static unsigned char horizp_bits[] = { 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0xff, 0x07, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x20, 0x46, 0x00, 0x30, 0xc6, 0x00, 0x38, 0xc6, 0x01, 0xfc, 0xff, 0x03, 0x38, 0xc6, 0x01, 0x30, 0xc6, 0x00, 0x20, 0x46, 0x00, 0x00, 0x06, 0x00 }; #define horizm_width 19 #define horizm_height 13 static unsigned char horizm_bits[] = { 0xff, 0x0f, 0x00, 0xff, 0x0f, 0x00, 0xff, 0x0f, 0x00, 0xff, 0x0f, 0x00, 0x60, 0x6f, 0x00, 0x70, 0xef, 0x00, 0x78, 0xef, 0x01, 0xfc, 0xff, 0x03, 0xfe, 0xff, 0x07, 0xfc, 0xff, 0x03, 0x78, 0xef, 0x01, 0x70, 0xef, 0x00, 0x60, 0x6f, 0x00 }; #define vertp_width 13 #define vertp_height 19 static unsigned char vertp_bits[] = { 0x06, 0x00, 0x06, 0x00, 0x06, 0x01, 0x86, 0x03, 0xc6, 0x07, 0xe6, 0x0f, 0x06, 0x01, 0x06, 0x01, 0x06, 0x01, 0xfe, 0x1f, 0xfe, 0x1f, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03, 0x00, 0x01, 0x00, 0x00}; #define vertm_width 13 #define vertm_height 19 static unsigned char vertm_bits[] = { 0x0f, 0x00, 0x0f, 0x01, 0x8f, 0x03, 0xcf, 0x07, 0xef, 0x0f, 0xff, 0x1f, 0xff, 0x1f, 0x8f, 0x03, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0x80, 0x03, 0xf0, 0x1f, 0xf0, 0x1f, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03, 0x00, 0x01}; /* Grid Translations */ static char translations[] = ": XmLGridButtonMotion()\n\ : XmLGridCursorMotion()\n\ ~Ctrl ~Shift : XmLGridSelect(BEGIN)\n\ ~Ctrl Shift : XmLGridSelect(EXTEND)\n\ Ctrl ~Shift : XmLGridSelect(TOGGLE)\n\ : XmLGridSelect(END)\n\ : XmLGridDragStart()\n\ ~Ctrl ~Shift : XmLGridPopupSelect(BEGIN)\n\ ~Ctrl Shift : XmLGridPopupSelect(EXTEND)\n\ Ctrl ~Shift : XmLGridPopupSelect(TOGGLE)\n\ : ManagerEnter()\n\ : ManagerLeave()\n\ : ManagerFocusOut()\n\ : ManagerFocusIn()"; /* Text Translations */ static char traverseTranslations[] = "~Ctrl ~Shift osfUp: XmLGridTraverse(UP)\n\ ~Ctrl Shift osfUp: XmLGridTraverse(EXTEND_UP)\n\ Ctrl ~Shift osfUp: XmLGridTraverse(PAGE_UP)\n\ ~Ctrl ~Shift osfDown: XmLGridTraverse(DOWN)\n\ ~Ctrl Shift osfDown: XmLGridTraverse(EXTEND_DOWN)\n\ Ctrl ~Shift osfDown: XmLGridTraverse(PAGE_DOWN)\n\ ~Ctrl ~Shift osfLeft: XmLGridTraverse(LEFT)\n\ ~Ctrl Shift osfLeft: XmLGridTraverse(EXTEND_LEFT)\n\ Ctrl ~Shift osfLeft: XmLGridTraverse(PAGE_LEFT)\n\ ~Ctrl ~Shift osfRight: XmLGridTraverse(RIGHT)\n\ ~Ctrl Shift osfRight: XmLGridTraverse(EXTEND_RIGHT)\n\ Ctrl ~Shift osfRight: XmLGridTraverse(PAGE_RIGHT)\n\ ~Ctrl ~Shift osfPageUp: XmLGridTraverse(PAGE_UP)\n\ ~Ctrl Shift osfPageUp: XmLGridTraverse(EXTEND_PAGE_UP)\n\ Ctrl ~Shift osfPageUp: XmLGridTraverse(PAGE_LEFT)\n\ Ctrl Shift osfPageUp: XmLGridTraverse(EXTEND_PAGE_LEFT)\n\ ~Ctrl Shift osfPageDown: XmLGridTraverse(EXTEND_PAGE_DOWN)\n\ Ctrl ~Shift osfPageDown: XmLGridTraverse(PAGE_RIGHT)\n\ ~Ctrl ~Shift osfPageDown: XmLGridTraverse(PAGE_DOWN)\n\ Ctrl Shift osfPageDown: XmLGridTraverse(EXTEND_PAGE_RIGHT)\n\ ~Ctrl ~Shift Tab: XmLGridTraverse(RIGHT)\n\ ~Ctrl Shift Tab: XmLGridTraverse(LEFT)\n\ ~Ctrl ~Shift Home: XmLGridTraverse(TO_TOP)\n\ ~Ctrl ~Shift osfBeginLine: XmLGridTraverse(TO_TOP)\n\ Ctrl ~Shift Home: XmLGridTraverse(TO_TOP_LEFT)\n\ ~Ctrl ~Shift End: XmLGridTraverse(TO_BOTTOM)\n\ ~Ctrl ~Shift osfEndLine: XmLGridTraverse(TO_BOTTOM)\n\ Ctrl ~Shift End: XmLGridTraverse(TO_BOTTOM_RIGHT)\n\ osfInsert: XmLGridEdit()\n\ F2: XmLGridEdit()\n\ ~Ctrl ~Shift space: XmLGridSelect(BEGIN)\n\ ~Ctrl Shift space: XmLGridSelect(EXTEND)\n\ Ctrl ~Shift space: XmLGridSelect(TOGGLE)\n\ space: XmLGridSelect(END)"; /* You can't put multiple actions for any translation where one translation changes the translation table XmLGridComplete() and XmLGridCancel() do this and these actions can't be combined with others */ static char editTranslations[] = "~Ctrl ~Shift osfDown: XmLGridEditComplete(DOWN)\n\ ~Ctrl Shift Tab: XmLGridEditComplete(LEFT)\n\ ~Ctrl ~Shift Tab: XmLGridEditComplete(RIGHT)\n\ ~Ctrl ~Shift osfUp: XmLGridEditComplete(UP)\n\ osfCancel: XmLGridEditCancel()\n\ Escape: XmLGridEditCancel()"; #if 0 static char hideButtonTranslations[] = ",: XmLGridHideColumn()"; static char unhideButtonTranslations[] = ",: XmLGridUnhideColumn()"; #endif /*0*/ static XtResource resources[] = { /* Grid Resources */ { XmNactivateCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLGridWidget, grid.activateCallback), XmRImmediate, (XtPointer)0, }, { XmNaddCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLGridWidget, grid.addCallback), XmRImmediate, (XtPointer)0, }, { XmNallowColumnHide, XmCAllowColumnHide, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.allowColHide), XmRImmediate, (XtPointer)False, }, { XmNallowColumnResize, XmCAllowColumnResize, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.allowColResize), XmRImmediate, (XtPointer)False, }, { XmNallowDragSelected, XmCAllowDragSelected, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.allowDrag), XmRImmediate, (XtPointer)False, }, { XmNallowDrop, XmCAllowDrop, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.allowDrop), XmRImmediate, (XtPointer)False, }, { XmNallowRowHide, XmCAllowRowHide, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.allowRowHide), XmRImmediate, (XtPointer)False, }, { XmNallowRowResize, XmCAllowRowResize, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.allowRowResize), XmRImmediate, (XtPointer)False, }, { XmNautoSelect, XmCAutoSelect, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.autoSelect), XmRImmediate, (XtPointer)True, }, { XmNblankBackground, XmCBlankBackground, XmRPixel, sizeof(Pixel), XtOffset(XmLGridWidget, grid.blankBg), XmRCallProc, (XtPointer)GetCoreBackground, }, { XmNbottomFixedCount, XmCBottomFixedCount, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.bottomFixedCount), XmRImmediate, (XtPointer)0, }, { XmNbottomFixedMargin, XmCBottomFixedMargin, XmRDimension, sizeof(Dimension), XtOffset(XmLGridWidget, grid.bottomFixedMargin), XmRImmediate, (XtPointer)0, }, { XmNcellDefaults, XmCCellDefaults, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.cellDefaults), XmRImmediate, (XtPointer)False, }, { XmNcellDrawCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLGridWidget, grid.cellDrawCallback), XmRImmediate, (XtPointer)0, }, { XmNcellDropCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLGridWidget, grid.cellDropCallback), XmRImmediate, (XtPointer)0, }, { XmNcellFocusCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLGridWidget, grid.cellFocusCallback), XmRImmediate, (XtPointer)0, }, { XmNcellPasteCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLGridWidget, grid.cellPasteCallback), XmRImmediate, (XtPointer)0, }, { XmNcolumns, XmCColumns, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.colCount), XmRImmediate, (XtPointer)0, }, { XmNdeleteCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLGridWidget, grid.deleteCallback), XmRImmediate, (XtPointer)0, }, { XmNdeselectCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLGridWidget, grid.deselectCallback), XmRImmediate, (XtPointer)0, }, { XmNdebugLevel, XmCDebugLevel, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.debugLevel), XmRImmediate, (XtPointer)0, }, { XmNeditCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLGridWidget, grid.editCallback), XmRImmediate, (XtPointer)0, }, { XmNeditTranslations, XmCTranslations, XmRTranslationTable, sizeof(XtTranslations), XtOffset(XmLGridWidget, grid.editTrans), XmRString, (XtPointer)editTranslations, }, { XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList), XtOffset(XmLGridWidget, grid.fontList), XmRImmediate, (XtPointer)0 }, { XmNfooterColumns, XmCFooterColumns, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.footerColCount), XmRImmediate, (XtPointer)0, }, { XmNfooterRows, XmCFooterRows, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.footerRowCount), XmRImmediate, (XtPointer)0, }, { XmNglobalPixmapHeight, XmCGlobalPixmapHeight, XmRDimension, sizeof(Dimension), XtOffset(XmLGridWidget, grid.globalPixmapHeight), XmRImmediate, (XtPointer)0, }, { XmNglobalPixmapWidth, XmCGlobalPixmapWidth, XmRDimension, sizeof(Dimension), XtOffset(XmLGridWidget, grid.globalPixmapWidth), XmRImmediate, (XtPointer)0, }, { XmNheadingColumns, XmCHeadingColumns, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.headingColCount), XmRImmediate, (XtPointer)0, }, { XmNheadingRows, XmCHeadingRows, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.headingRowCount), XmRImmediate, (XtPointer)0, }, { XmNhiddenColumns, XmCHiddenColumns, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.hiddenColCount), XmRImmediate, (XtPointer)0, }, { XmNhiddenRows, XmCHiddenRows, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.hiddenRowCount), XmRImmediate, (XtPointer)0, }, { XmNhighlightRowMode, XmCHighlightRowMode, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.highlightRowMode), XmRImmediate, (XtPointer)False, }, { XmNhighlightThickness, XmCHighlightThickness, XmRDimension, sizeof(Dimension), XtOffset(XmLGridWidget, grid.highlightThickness), XmRImmediate, (XtPointer)2, }, { XmNhorizontalScrollBar, XmCHorizontalScrollBar, XmRWidget, sizeof(Widget), XtOffset(XmLGridWidget, grid.hsb), XmRImmediate, (XtPointer)0, }, { XmNhorizontalSizePolicy, XmCHorizontalSizePolicy, XmRGridSizePolicy, sizeof(unsigned char), XtOffset(XmLGridWidget, grid.hsPolicy), XmRImmediate, (XtPointer)XmCONSTANT, }, { XmNhsbDisplayPolicy, XmCHsbDisplayPolicy, XmRScrollBarDisplayPolicy, sizeof(unsigned char), XtOffset(XmLGridWidget, grid.hsbDisplayPolicy), XmRImmediate, (XtPointer)XmAS_NEEDED, }, { XmNimmediateDraw, XmCImmediateDraw, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.immediateDraw), XmRImmediate, (XtPointer)False, }, { XmNlayoutFrozen, XmCLayoutFrozen, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.layoutFrozen), XmRImmediate, (XtPointer)False, }, { XmNleftFixedCount, XmCLeftFixedCount, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.leftFixedCount), XmRImmediate, (XtPointer)0, }, { XmNleftFixedMargin, XmCLeftFixedMargin, XmRDimension, sizeof(Dimension), XtOffset(XmLGridWidget, grid.leftFixedMargin), XmRImmediate, (XtPointer)0, }, { XmNminColumnWidth, XmCMinColumnWidth, XmRDimension, sizeof(Dimension), XtOffset(XmLGridWidget, grid.minColWidth), XmRImmediate, (XtPointer)0, }, { XmNrightFixedCount, XmCRightFixedCount, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.rightFixedCount), XmRImmediate, (XtPointer)0, }, { XmNrightFixedMargin, XmCRightFixedMargin, XmRDimension, sizeof(Dimension), XtOffset(XmLGridWidget, grid.rightFixedMargin), XmRImmediate, (XtPointer)0, }, { XmNresizeCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLGridWidget, grid.resizeCallback), XmRImmediate, (XtPointer)0, }, { XmNrows, XmCRows, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.rowCount), XmRImmediate, (XtPointer)0, }, { XmNscrollBarMargin, XmCScrollBarMargin, XmRDimension, sizeof(Dimension), XtOffset(XmLGridWidget, grid.scrollBarMargin), XmRImmediate, (XtPointer)2, }, { XmNscrollCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLGridWidget, grid.scrollCallback), XmRImmediate, (XtPointer)0, }, { XmNscrollColumn, XmCScrollColumn, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.cScrollCol), XmRImmediate, (XtPointer)0, }, { XmNscrollRow, XmCScrollRow, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.cScrollRow), XmRImmediate, (XtPointer)0, }, { XmNselectCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLGridWidget, grid.selectCallback), XmRImmediate, (XtPointer)0, }, { XmNselectionPolicy, XmCGridSelectionPolicy, XmRGridSelectionPolicy, sizeof(unsigned char), XtOffset(XmLGridWidget, grid.selectionPolicy), XmRImmediate, (XtPointer)XmSELECT_BROWSE_ROW, }, { XmNselectBackground, XmCSelectBackground, XmRPixel, sizeof(Pixel), XtOffset(XmLGridWidget, grid.selectBg), XmRCallProc, (XtPointer)GetManagerForeground, }, { XmNselectForeground, XmCSelectForeground, XmRPixel, sizeof(Pixel), XtOffset(XmLGridWidget, grid.selectFg), XmRCallProc, (XtPointer)GetCoreBackground, }, { XmNshadowRegions, XmCShadowRegions, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.shadowRegions), XmRImmediate, (XtPointer)511, }, { XmNshadowType, XmCShadowType, XmRShadowType, sizeof(unsigned char), XtOffset(XmLGridWidget, grid.shadowType), XmRImmediate, (XtPointer)XmSHADOW_IN, }, { XmNsimpleHeadings, XmCSimpleHeadings, XmRString, sizeof(char *), XtOffset(XmLGridWidget, grid.simpleHeadings), XmRImmediate, (XtPointer)0, }, { XmNsimpleWidths, XmCSimpleWidths, XmRString, sizeof(char *), XtOffset(XmLGridWidget, grid.simpleWidths), XmRImmediate, (XtPointer)0, }, { XmNtextWidget, XmCTextWidget, XmRWidget, sizeof(Widget), XtOffset(XmLGridWidget, grid.text), XmRImmediate, (XtPointer)0, }, { XmNtoggleBottomColor, XmCToggleBottomColor, XmRPixel, sizeof(Pixel), XtOffset(XmLGridWidget, grid.toggleBotColor), XmRCallProc, (XtPointer)GetManagerForeground, }, { XmNtoggleTopColor, XmCToggleTopColor, XmRPixel, sizeof(Pixel), XtOffset(XmLGridWidget, grid.toggleTopColor), XmRCallProc, (XtPointer)GetManagerForeground, }, { XmNtoggleSize, XmCToggleSize, XmRDimension, sizeof(Dimension), XtOffset(XmLGridWidget, grid.toggleSize), XmRImmediate, (XtPointer)16, }, { XmNtraverseTranslations, XmCTranslations, XmRTranslationTable, sizeof(XtTranslations), XtOffset(XmLGridWidget, grid.traverseTrans), XmRString, (XtPointer)traverseTranslations, }, { XmNtopFixedCount, XmCTopFixedCount, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.topFixedCount), XmRImmediate, (XtPointer)0, }, { XmNtopFixedMargin, XmCTopFixedMargin, XmRDimension, sizeof(Dimension), XtOffset(XmLGridWidget, grid.topFixedMargin), XmRImmediate, (XtPointer)0, }, { XmNuseAverageFontWidth, XmCUseAverageFontWidth, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.useAvgWidth), XmRImmediate, (XtPointer)True, }, { XmNverticalScrollBar, XmCVerticalScrollBar, XmRWidget, sizeof(Widget), XtOffset(XmLGridWidget, grid.vsb), XmRImmediate, (XtPointer)0, }, { XmNverticalSizePolicy, XmCVerticalSizePolicy, XmRGridSizePolicy, sizeof(unsigned char), XtOffset(XmLGridWidget, grid.vsPolicy), XmRImmediate, (XtPointer)XmCONSTANT, }, { XmNvisibleColumns, XmCVisibleColumns, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.visibleCols), XmRImmediate, (XtPointer)0, }, { XmNvisibleRows, XmCVisibleRows, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.visibleRows), XmRImmediate, (XtPointer)0, }, { XmNvsbDisplayPolicy, XmCVsbDisplayPolicy, XmRScrollBarDisplayPolicy, sizeof(unsigned char), XtOffset(XmLGridWidget, grid.vsbDisplayPolicy), XmRImmediate, (XtPointer)XmAS_NEEDED, }, /* Xfe Additions*/ { XmNpopupCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLGridWidget, grid.popupCallback), XmRImmediate, (XtPointer)0, }, { XmNenterCellCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLGridWidget, grid . enterCellCallback), XmRImmediate, (XtPointer) NULL }, { XmNleaveCellCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLGridWidget, grid . leaveCellCallback), XmRImmediate, (XtPointer) NULL }, { XmNenterGridCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLGridWidget, grid . enterGridCallback), XmRImmediate, (XtPointer) NULL }, { XmNleaveGridCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLGridWidget, grid . leaveGridCallback), XmRImmediate, (XtPointer) NULL }, /* Row Resources */ { XmNrow, XmCGridRow, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.cellRow), XmRImmediate, (XtPointer)-1, }, { XmNrowUserData, XmCUserData, XmRPointer, sizeof(XtPointer), XtOffset(XmLGridWidget, grid.rowUserData), XmRImmediate, (XtPointer)0, }, { XmNrowHeight, XmCRowHeight, XmRDimension, sizeof(Dimension), XtOffset(XmLGridWidget, grid.rowHeight), XmRImmediate, (XtPointer)0, }, { XmNrowRangeEnd, XmCRowRangeEnd, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.cellRowRangeEnd), XmRImmediate, (XtPointer)-1, }, { XmNrowRangeStart, XmCRowRangeStart, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.cellRowRangeStart), XmRImmediate, (XtPointer)-1, }, { XmNrowSizePolicy, XmCRowSizePolicy, XmRGridSizePolicy, sizeof(unsigned char), XtOffset(XmLGridWidget, grid.rowSizePolicy), XmRImmediate, (XtPointer)0, }, { XmNrowStep, XmCRowStep, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.rowStep), XmRImmediate, (XtPointer)1, }, { XmNrowType, XmCRowType, XmRRowType, sizeof(unsigned char), XtOffset(XmLGridWidget, grid.rowType), XmRImmediate, (XtPointer)XmINVALID_TYPE, }, /* Column Resources */ { XmNcolumn, XmCGridColumn, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.cellCol), XmRImmediate, (XtPointer)-1, }, { XmNcolumnUserData, XmCUserData, XmRPointer, sizeof(XtPointer), XtOffset(XmLGridWidget, grid.colUserData), XmRImmediate, (XtPointer)0, }, { XmNcolumnResizable, XmCColumnResizable, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.colResizable), XmRImmediate, (XtPointer)TRUE, }, { XmNcolumnWidth, XmCColumnWidth, XmRDimension, sizeof(Dimension), XtOffset(XmLGridWidget, grid.colWidth), XmRImmediate, (XtPointer)0, }, { XmNcolumnRangeEnd, XmCColumnRangeEnd, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.cellColRangeEnd), XmRImmediate, (XtPointer)-1, }, { XmNcolumnRangeStart, XmCColumnRangeStart, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.cellColRangeStart), XmRImmediate, (XtPointer)-1, }, { XmNcolumnSizePolicy, XmCColumnSizePolicy, XmRGridSizePolicy, sizeof(unsigned char), XtOffset(XmLGridWidget, grid.colSizePolicy), XmRImmediate, (XtPointer)0, }, { XmNcolumnStep, XmCColumnStep, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.colStep), XmRImmediate, (XtPointer)1, }, { XmNcolumnType, XmCColumnType, XmRColumnType, sizeof(unsigned char), XtOffset(XmLGridWidget, grid.colType), XmRImmediate, (XtPointer)XmINVALID_TYPE, }, /* xfe Column Resource additions */ { XmNcolumnHidden, XmCColumnHidden, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.colHidden), XmRImmediate, (XtPointer)FALSE, }, { XmNcolumnSortType, XmCColumnSortType, XmRColumnSortType, sizeof(unsigned char), XtOffset(XmLGridWidget, grid.colSortType), XmRImmediate, (XtPointer)XmSORT_NONE, }, /* Cell Resources */ { XmNcellAlignment, XmCCellAlignment, XmRCellAlignment, sizeof(unsigned char), XtOffset(XmLGridWidget, grid.cellValues.alignment), XmRImmediate, (XtPointer)0, }, { XmNcellBackground, XmCCellBackground, XmRPixel, sizeof(Pixel), XtOffset(XmLGridWidget, grid.cellValues.background), XmRImmediate, (XtPointer)0, }, { XmNcellBottomBorderColor, XmCCellBottomBorderColor, XmRPixel, sizeof(Pixel), XtOffset(XmLGridWidget, grid.cellValues.bottomBorderColor), XmRImmediate, (XtPointer)0, }, { XmNcellBottomBorderType, XmCCellBottomBorderType, XmRCellBorderType, sizeof(unsigned char), XtOffset(XmLGridWidget, grid.cellValues.bottomBorderType), XmRImmediate, (XtPointer)0, }, { XmNcellColumnSpan, XmCCellColumnSpan, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.cellValues.columnSpan), XmRImmediate, (XtPointer)0, }, { XmNcellEditable, XmCCellEditable, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.cellValues.editable), XmRImmediate, (XtPointer)False, }, { XmNcellFontList, XmCCellFontList, XmRFontList, sizeof(XmFontList), XtOffset(XmLGridWidget, grid.cellValues.fontList), XmRImmediate, (XtPointer)0, }, { XmNcellForeground, XmCCellForeground, XmRPixel, sizeof(Pixel), XtOffset(XmLGridWidget, grid.cellValues.foreground), XmRImmediate, (XtPointer)0, }, { XmNcellLeftBorderColor, XmCCellLeftBorderColor, XmRPixel, sizeof(Pixel), XtOffset(XmLGridWidget, grid.cellValues.leftBorderColor), XmRImmediate, (XtPointer)0, }, { XmNcellLeftBorderType, XmCCellLeftBorderType, XmRCellBorderType, sizeof(unsigned char), XtOffset(XmLGridWidget, grid.cellValues.leftBorderType), XmRImmediate, (XtPointer)0, }, { XmNcellMarginBottom, XmCCellMarginBottom, XmRDimension, sizeof(Dimension), XtOffset(XmLGridWidget, grid.cellValues.bottomMargin), XmRImmediate, (XtPointer)0, }, { XmNcellMarginLeft, XmCCellMarginLeft, XmRDimension, sizeof(Dimension), XtOffset(XmLGridWidget, grid.cellValues.leftMargin), XmRImmediate, (XtPointer)0, }, { XmNcellMarginRight, XmCCellMarginRight, XmRDimension, sizeof(Dimension), XtOffset(XmLGridWidget, grid.cellValues.rightMargin), XmRImmediate, (XtPointer)0, }, { XmNcellMarginTop, XmCCellMarginTop, XmRDimension, sizeof(Dimension), XtOffset(XmLGridWidget, grid.cellValues.topMargin), XmRImmediate, (XtPointer)0, }, { XmNcellPixmap, XmCCellPixmap, XmRManForegroundPixmap, sizeof(Pixmap), XtOffset(XmLGridWidget, grid.cellPixmap), XmRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP, }, { XmNcellPixmapMask, XmCCellPixmapMask, XtRBitmap, sizeof(Pixmap), XtOffset(XmLGridWidget, grid.cellPixmapMask), XmRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP, }, { XmNcellRightBorderColor, XmCCellRightBorderColor, XmRPixel, sizeof(Pixel), XtOffset(XmLGridWidget, grid.cellValues.rightBorderColor), XmRImmediate, (XtPointer)0, }, { XmNcellRightBorderType, XmCCellRightBorderType, XmRCellBorderType, sizeof(unsigned char), XtOffset(XmLGridWidget, grid.cellValues.rightBorderType), XmRImmediate, (XtPointer)0, }, { XmNcellRowSpan, XmCCellRowSpan, XmRInt, sizeof(int), XtOffset(XmLGridWidget, grid.cellValues.rowSpan), XmRImmediate, (XtPointer)0, }, { XmNcellString, XmCXmString, XmRXmString, sizeof(XmString), XtOffset(XmLGridWidget, grid.cellString), XmRImmediate, (XtPointer)0, }, { XmNcellToggleSet, XmCCellToggleSet, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.cellToggleSet), XmRImmediate, (XtPointer)False, }, { XmNcellTopBorderColor, XmCCellTopBorderColor, XmRPixel, sizeof(Pixel), XtOffset(XmLGridWidget, grid.cellValues.topBorderColor), XmRImmediate, (XtPointer)0, }, { XmNcellTopBorderType, XmCCellTopBorderType, XmRCellBorderType, sizeof(unsigned char), XtOffset(XmLGridWidget, grid.cellValues.topBorderType), XmRImmediate, (XtPointer)0, }, { XmNcellType, XmCCellType, XmRCellType, sizeof(unsigned char), XtOffset(XmLGridWidget, grid.cellValues.type), XmRImmediate, (XtPointer)XmSTRING_CELL, }, { XmNcellUserData, XmCUserData, XmRPointer, sizeof(XtPointer), XtOffset(XmLGridWidget, grid.cellValues.userData), XmRImmediate, (XtPointer)0, }, /* Overridden inherited resources */ { XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension, sizeof(Dimension), XtOffset(XmLGridWidget, manager.shadow_thickness), XmRImmediate, (XtPointer)2, }, /* XFE Addition*/ { XmNhideUnhideButtons, XmCHideUnhideButtons, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.hideUnhideButtons), XmRImmediate, (XtPointer)False, }, { XmNsingleClickActivation, XmCSingleClickActivation, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.singleClickActivation), XmRImmediate, (XtPointer)False, }, #if 0 { XmNhideButtonTranslations, XmCTranslations, XmRTranslationTable, sizeof(XtTranslations), XtOffset(XmLGridWidget, grid.hideButtonTrans), XmRString, (XtPointer)hideButtonTranslations, }, { XmNunhideButtonTranslations, XmCTranslations, XmRTranslationTable, sizeof(XtTranslations), XtOffset(XmLGridWidget, grid.unhideButtonTrans), XmRString, (XtPointer)unhideButtonTranslations, }, #endif /*0*/ { XmNuseTextWidget, XmCUseTextWidget, XmRBoolean, sizeof(Boolean), XtOffset(XmLGridWidget, grid.useTextWidget), XmRImmediate, (XtPointer)True, }, { XmNiconSpacing, XmCIconSpacing, XmRHorizontalDimension, sizeof(Dimension), XtOffset(XmLGridWidget, grid.iconSpacing), XmRImmediate, (XtPointer) 4, }, }; XmLGridClassRec xmlGridClassRec = { { /* core_class */ (WidgetClass)&xmManagerClassRec, /* superclass */ "XmLGrid", /* class_name */ sizeof(XmLGridRec), /* widget_size */ ClassInitialize, /* class_init */ ClassPartInitialize, /* class_part_init */ FALSE, /* class_inited */ (XtInitProc)Initialize, /* initialize */ 0, /* initialize_hook */ (XtRealizeProc)Realize, /* realize */ (XtActionList)actions, /* actions */ (Cardinal)XtNumber(actions), /* num_actions */ (XtResource *)resources, /* resources */ XtNumber(resources), /* num_resources */ NULLQUARK, /* xrm_class */ TRUE, /* compress_motion */ XtExposeCompressMaximal, /* compress_exposure */ TRUE, /* compress_enterleav */ TRUE, /* visible_interest */ (XtWidgetProc)Destroy, /* destroy */ (XtWidgetProc)Resize, /* resize */ (XtExposeProc)Redisplay, /* expose */ (XtSetValuesFunc)SetValues, /* set_values */ 0, /* set_values_hook */ XtInheritSetValuesAlmost, /* set_values_almost */ (XtArgsProc)GetSubValues, /* get_values_hook */ 0, /* accept_focus */ XtVersion, /* version */ 0, /* callback_private */ translations, /* tm_table */ 0, /* query_geometry */ 0, /* display_accelerato */ 0, /* extension */ }, { /* composite_class */ (XtGeometryHandler)GeometryManager, /* geometry_manager */ (XtWidgetProc)ChangeManaged, /* change_managed */ XtInheritInsertChild, /* insert_child */ XtInheritDeleteChild, /* delete_child */ 0, /* extension */ }, { /* constraint_class */ 0, /* subresources */ 0, /* subresource_count */ sizeof(XmLGridConstraintRec), /* constraint_size */ 0, /* initialize */ 0, /* destroy */ 0, /* set_values */ 0, /* extension */ }, { /* manager_class */ XtInheritTranslations, /* translations */ 0, /* syn resources */ 0, /* num syn_resources */ 0, /* get_cont_resources */ 0, /* num_get_cont_res */ XmInheritParentProcess, /* parent_process */ 0, /* extension */ }, { /* grid_class */ 0, /* initial rows */ 0, /* initial columns */ XmInheritGridPreLayout, /* pre layout */ sizeof(struct _XmLGridRowRec), /* row rec size */ _GridRowNew, /* row new */ _GridRowFree, /* row free */ _GetRowValueMask, /* get row value mask */ _GetRowValue, /* get row value */ _SetRowValues, /* set row values */ sizeof(struct _XmLGridColumnRec), /* column rec size */ _GridColumnNew, /* column new */ _GridColumnFree, /* column free */ _GetColumnValueMask, /* get col value mask */ _GetColumnValue, /* get column value */ _SetColumnValues, /* set column values */ _SetCellValuesResize, /* set cell vl resize */ _GridCellAction, /* cell action */ } }; WidgetClass xmlGridWidgetClass = (WidgetClass)&xmlGridClassRec; /* Create and Destroy */ static void ClassInitialize(void) { int off1, off2; XmLInitialize(); XtSetTypeConverter(XmRString, XmRGridSizePolicy, CvtStringToSizePolicy, 0, 0, XtCacheNone, 0); XtSetTypeConverter(XmRString, XmRColumnType, CvtStringToRowColType, 0, 0, XtCacheNone, 0); XtSetTypeConverter(XmRString, XmRRowType, CvtStringToRowColType, 0, 0, XtCacheNone, 0); XtSetTypeConverter(XmRString, XmRGridSelectionPolicy, CvtStringToSelectionPolicy, 0, 0, XtCacheNone, 0); XtSetTypeConverter(XmRString, XmRCellAlignment, CvtStringToCellAlignment, 0, 0, XtCacheNone, 0); XtSetTypeConverter(XmRString, XmRCellType, CvtStringToCellType, 0, 0, XtCacheNone, 0); XtSetTypeConverter(XmRString, XmRCellBorderType, CvtStringToCellBorderType, 0, 0, XtCacheNone, 0); /* long must be > 2 bytes for cell mask to work */ if (sizeof(long) < 3) fprintf(stderr, "xmlGridClass: fatal error: long < 3 bytes\n"); /* compiler sanity check - make sure array pos lines up */ off1 = XtOffset(XmLArrayItem *, pos); off2 = XtOffset(XmLGridColumn, grid.pos); if (off1 != off2) fprintf(stderr, "xmlGridClass: fatal error: column pos offset bad\n"); off2 = XtOffset(XmLGridRow, grid.pos); if (off1 != off2) fprintf(stderr, "xmlGridClass: fatal error: row pos offset bad\n"); } static void ClassPartInitialize(WidgetClass wc) { XmLGridWidgetClass c, sc; c = (XmLGridWidgetClass)wc; sc = (XmLGridWidgetClass)c->core_class.superclass; #define INHERIT_PROC(proc, inherit) \ if (c->grid_class.proc == inherit) \ c->grid_class.proc = sc->grid_class.proc; INHERIT_PROC(rowNewProc, XmInheritGridRowNew) INHERIT_PROC(rowFreeProc, XmInheritGridRowFree) INHERIT_PROC(getRowValueMaskProc, XmInheritGridGetRowValueMask) INHERIT_PROC(getRowValueProc, XmInheritGridGetRowValue) INHERIT_PROC(setRowValuesProc, XmInheritGridSetRowValues) INHERIT_PROC(columnNewProc, XmInheritGridColumnNew) INHERIT_PROC(columnFreeProc, XmInheritGridColumnFree) INHERIT_PROC(getColumnValueMaskProc, XmInheritGridGetColumnValueMask) INHERIT_PROC(getColumnValueProc, XmInheritGridGetColumnValue) INHERIT_PROC(setColumnValuesProc, XmInheritGridSetColumnValues) INHERIT_PROC(setCellValuesResizeProc, XmInheritGridSetCellValuesResize) INHERIT_PROC(cellActionProc, XmInheritGridCellAction) #undef INHERIT_PROC } static void Initialize(Widget reqW, Widget newW, ArgList args, Cardinal *narg) { XmLGridWidget g, request; Display *dpy; Pixmap pix, pixMask; Pixel white, black; XColor fg, bg; GridReg *reg; int i, valid, hc, c, fc, hr, r, fr; Boolean layoutFrozen; #ifdef POINTER_FOCUS_CHECK unsigned char kfp; Widget shell; #endif g = (XmLGridWidget)newW; dpy = XtDisplay((Widget)g); request = (XmLGridWidget)reqW; #ifdef POINTER_FOCUS_CHECK shell = XmLShellOfWidget(newW); if (shell && XmIsVendorShell(shell)) { XtVaGetValues(shell, XmNkeyboardFocusPolicy, &kfp, NULL); if (kfp == XmPOINTER) XmLWarning(newW, "keyboardFocusPolicy of XmPOINTER not supported"); } #endif black = BlackPixelOfScreen(XtScreen((Widget)g)); white = WhitePixelOfScreen(XtScreen((Widget)g)); g->grid.rowArray = XmLArrayNew(1, 1); g->grid.colArray = XmLArrayNew(1, 1); if (g->core.width <= 0) g->core.width = 100; if (g->core.height <= 0) g->core.height = 100; CopyFontList(g); if (g->grid.useTextWidget) { g->grid.text = XtVaCreateManagedWidget("text", xmTextWidgetClass, (Widget)g, XmNmarginHeight, 0, XmNmarginWidth, 3, XmNshadowThickness, 0, XmNhighlightThickness, 0, XmNx, 0, XmNy, 0, XmNwidth, 40, XmNheight, 40, XmNbackground, g->core.background_pixel, XmNforeground, g->manager.foreground, NULL); XtOverrideTranslations(g->grid.text, g->grid.traverseTrans); XtAddEventHandler(g->grid.text, StructureNotifyMask, True, (XtEventHandler)TextMapped, (XtPointer)0); XtAddCallback(g->grid.text, XmNactivateCallback, TextActivate, 0); XtAddCallback(g->grid.text, XmNfocusCallback, TextFocus, 0); XtAddCallback(g->grid.text, XmNlosingFocusCallback, TextFocus, 0); XtAddCallback(g->grid.text, XmNmodifyVerifyCallback, TextModifyVerify, 0); } g->grid.hsb = XtVaCreateWidget( "hsb", xmScrollBarWidgetClass, (Widget)g, XmNincrement, 1, XmNorientation, XmHORIZONTAL, XmNtraversalOn, False, XmNbackground, g->core.background_pixel, /* Don't force foreground on IRIX - it screws up the thumb color in sgiMode */ #ifndef IRIX XmNforeground, g->manager.foreground, #endif XmNtopShadowColor, g->manager.top_shadow_color, XmNbottomShadowColor, g->manager.bottom_shadow_color, NULL); XtAddCallback(g->grid.hsb, XmNdragCallback, ScrollCB, 0); XtAddCallback(g->grid.hsb, XmNvalueChangedCallback, ScrollCB, 0); g->grid.vsb = XtVaCreateWidget( "vsb", xmScrollBarWidgetClass, (Widget)g, XmNorientation, XmVERTICAL, XmNincrement, 1, XmNtraversalOn, False, XmNbackground, g->core.background_pixel, /* Don't force foreground on IRIX - it screws up the thumb color in sgiMode */ #ifndef IRIX XmNforeground, g->manager.foreground, #endif XmNtopShadowColor, g->manager.top_shadow_color, XmNbottomShadowColor, g->manager.bottom_shadow_color, NULL); XtAddCallback(g->grid.vsb, XmNdragCallback, ScrollCB, 0); XtAddCallback(g->grid.vsb, XmNvalueChangedCallback, ScrollCB, 0); if (g->grid.hideUnhideButtons) { CreateHideUnhideButtons(g); } else { g->grid.hideButton = 0; g->grid.unhideButton = 0; } g->grid.inResize = False; /* Cursors */ fg.red = ~0; fg.green = ~0; fg.blue = ~0; fg.pixel = white; fg.flags = DoRed | DoGreen | DoBlue; bg.red = 0; bg.green = 0; bg.blue = 0; bg.pixel = black; bg.flags = DoRed | DoGreen | DoBlue; pix = XCreatePixmapFromBitmapData(dpy, DefaultRootWindow(dpy), (char *)horizp_bits, horizp_width, horizp_height, 0, 1, 1); pixMask = XCreatePixmapFromBitmapData(dpy, DefaultRootWindow(dpy), (char *)horizm_bits, horizm_width, horizm_height, 1, 0, 1); g->grid.hResizeCursor = XCreatePixmapCursor(dpy, pix, pixMask, &fg, &bg, 9, 9); XFreePixmap(dpy, pix); XFreePixmap(dpy, pixMask); pix = XCreatePixmapFromBitmapData(dpy, DefaultRootWindow(dpy), (char *)vertp_bits, vertp_width, vertp_height, 0, 1, 1); pixMask = XCreatePixmapFromBitmapData(dpy, DefaultRootWindow(dpy), (char *)vertm_bits, vertm_width, vertm_height, 1, 0, 1); g->grid.vResizeCursor = XCreatePixmapCursor(dpy, pix, pixMask, &fg, &bg, 9, 9); XFreePixmap(dpy, pix); XFreePixmap(dpy, pixMask); g->grid.cursorDefined = CursorNormal; g->grid.focusIn = 0; g->grid.focusRow = -1; g->grid.focusCol = -1; g->grid.mayHaveRowSpans = 0; g->grid.scrollCol = 0; g->grid.scrollRow = 0; g->grid.textHidden = 1; g->grid.inMode = InNormal; g->grid.inEdit = 0; g->grid.singleColScrollMode = 0; g->grid.layoutStack = 0; g->grid.needsHorizLayout = 0; g->grid.needsVertLayout = 0; g->grid.recalcHorizVisPos = 0; g->grid.recalcVertVisPos = 0; g->grid.vertVisChangedHint = 0; g->grid.defCellValues = CellRefValuesCreate(g, 0); g->grid.defCellValues->refCount = 1; g->grid.ignoreModifyVerify = 0; g->grid.extendRow = -1; g->grid.extendCol = -1; g->grid.extendToRow = -1; g->grid.extendToCol = -1; g->grid.extendSelect = True; g->grid.lastSelectRow = -1; g->grid.lastSelectCol = -1; g->grid.lastSelectTime = 0; g->grid.dragTimerSet = 0; g->grid.editTimerSet = 0; g->grid.gc = 0; /* * Support for: * * XmNenterCellCallback * XmNenterCellCallback * XmNenterCallback * XmNleaveCallback */ g->grid.lastCursorMotionRow = -1; g->grid.lastCursorMotionCol = -1; XtAddEventHandler(newW, EnterWindowMask | LeaveWindowMask, True, (XtEventHandler) GridCrossingEH, (XtPointer) NULL); reg = g->grid.reg; for (i = 0; i < 9; i++) { reg[i].x = 0; reg[i].y = 0; reg[i].width = 0; reg[i].height = 0; reg[i].row = 0; reg[i].col = 0; reg[i].nrow = 0; reg[i].ncol = 0; } layoutFrozen = g->grid.layoutFrozen; g->grid.layoutFrozen = True; if (g->grid.hiddenColCount || g->grid.hiddenRowCount) { XmLWarning(newW, "Initialize() - can't set hidden rows or columns"); g->grid.hiddenColCount = 0; g->grid.hiddenRowCount = 0; } hc = g->grid.headingColCount; c = XmLGridClassPartOfWidget(g).initialCols; if (c < g->grid.colCount) c = g->grid.colCount; fc = g->grid.footerColCount; hr = g->grid.headingRowCount; r = XmLGridClassPartOfWidget(g).initialRows; if (r < g->grid.rowCount) r = g->grid.rowCount ; fr = g->grid.footerRowCount; g->grid.headingColCount = 0; g->grid.colCount = 0; g->grid.footerColCount = 0; g->grid.headingRowCount = 0; g->grid.rowCount = 0; g->grid.footerRowCount = 0; XmLGridAddColumns(newW, XmHEADING, -1, hc); XmLGridAddColumns(newW, XmCONTENT, -1, c); XmLGridAddColumns(newW, XmFOOTER, -1, fc); XmLGridAddRows(newW, XmHEADING, -1, hr); XmLGridAddRows(newW, XmCONTENT, -1, r); XmLGridAddRows(newW, XmFOOTER, -1, fr); if (g->grid.simpleHeadings) { g->grid.simpleHeadings = (char *)strdup(g->grid.simpleHeadings); SetSimpleHeadings(g, g->grid.simpleHeadings); } if (g->grid.simpleWidths) { g->grid.simpleWidths = (char *)strdup(g->grid.simpleWidths); SetSimpleWidths(g, g->grid.simpleWidths); } if (g->grid.visibleRows) ApplyVisibleRows(g); if (g->grid.visibleCols && g->grid.hsPolicy == XmCONSTANT) ApplyVisibleCols(g); g->grid.layoutFrozen = layoutFrozen; VertLayout(g, 1); HorizLayout(g, 1); PlaceScrollbars(g); valid = 1; for (i = 0; i < *narg; i++) { if (!args[i].name) continue; if (!strcmp(args[i].name, XmNrows) || !strcmp(args[i].name, XmNcolumns)) continue; if (!strncmp(args[i].name, "row", 3) || !strncmp(args[i].name, "column", 6) || !strncmp(args[i].name, "cell", 4)) valid = 0; } if (!valid) XmLWarning(newW, "Initialize() - can't set row,column or cell values in init"); DropRegister(g, g->grid.allowDrop); } static void Destroy(Widget w) { XmLGridWidget g; Display *dpy; int i, count; g = (XmLGridWidget)w; dpy = XtDisplay(w); if (g->grid.dragTimerSet) XtRemoveTimeOut(g->grid.dragTimerId); if (g->grid.editTimerSet) XtRemoveTimeOut(g->grid.editTimerId); DefineCursor(g, CursorNormal); XFreeCursor(dpy, g->grid.hResizeCursor); XFreeCursor(dpy, g->grid.vResizeCursor); if (g->grid.gc) { XFreeGC(dpy, g->grid.gc); XFreeFont(dpy, g->grid.fallbackFont); } XmFontListFree(g->grid.fontList); XmLGridCellDerefValues(g->grid.defCellValues); ExtendSelect(g, (XEvent *)0, False, -1, -1); count = XmLArrayGetCount(g->grid.rowArray); for (i = 0; i < count; i++) XmLGridRowFree(w, (XmLGridRow)XmLArrayGet(g->grid.rowArray, i)); XmLArrayFree(g->grid.rowArray); count = XmLArrayGetCount(g->grid.colArray); for (i = 0; i < count; i++) XmLGridColumnFree(w, (XmLGridColumn)XmLArrayGet(g->grid.colArray, i)); XmLArrayFree(g->grid.colArray); if (g->grid.simpleHeadings) free((char *)g->grid.simpleHeadings); if (g->grid.simpleWidths) free((char *)g->grid.simpleWidths); } /* Geometry, Drawing, Entry and Picking */ static void Realize(Widget w, XtValueMask *valueMask, XSetWindowAttributes *attr) { XmLGridWidget g; Display *dpy; WidgetClass superClass; XtRealizeProc realize; XGCValues values; XtGCMask mask; static char dashes[2] = { 1, 1 }; g = (XmLGridWidget)w; dpy = XtDisplay(g); superClass = xmlGridWidgetClass->core_class.superclass; realize = superClass->core_class.realize; (*realize)(w, valueMask, attr); if (!g->grid.gc) { g->grid.fallbackFont = XLoadQueryFont(dpy, "fixed"); values.foreground = g->manager.foreground; values.font = g->grid.fallbackFont->fid; mask = GCForeground | GCFont; g->grid.gc = XCreateGC(dpy, XtWindow(g), mask, &values); XSetDashes(dpy, g->grid.gc, 0, dashes, 2); if (g->grid.selectionPolicy == XmSELECT_BROWSE_ROW && g->grid.autoSelect == True && g->grid.rowCount) XmLGridSelectRow(w, 0, False); } } static void Redisplay(Widget w, XExposeEvent *event, Region region) { XmLGridWidget g; Display *dpy; Window win; XmLGridCell cell; XmLGridRow row; XmLGridColumn col; XmLGridCellRefValues *cellValues; XmLGridDrawStruct ds; XmLGridCallbackStruct cbs; GridReg *reg; XRectangle eRect, rRect, clipRect, rect[6]; int i, n, st, c, r, sc, sr, width, height, rowHeight; int lastVisPos, visPos, hasDrawCB; Boolean spanUp, spanLeft; g = (XmLGridWidget)w; if (!XtIsRealized((Widget)g)) return; if (!g->core.visible) return; if (g->grid.layoutFrozen == True) XmLWarning(w, "Redisplay() - layout frozen is True during redraw"); dpy = XtDisplay(g); win = XtWindow(g); st = g->manager.shadow_thickness; reg = g->grid.reg; if (event) { eRect.x = event->x; eRect.y = event->y; eRect.width = event->width; eRect.height = event->height; if (g->grid.debugLevel > 1) fprintf(stderr, "XmLGrid: Redisplay x %d y %d w %d h %d\n", event->x, event->y, event->width, event->height); } else { eRect.x = 0; eRect.y = 0; eRect.width = g->core.width; eRect.height = g->core.height; } if (!eRect.width || !eRect.height) return; /* Hide any XORed graphics */ DrawResizeLine(g, 0, 1); hasDrawCB = 0; if (XtHasCallbacks(w, XmNcellDrawCallback) == XtCallbackHasSome) hasDrawCB = 1; /* Add extra shadow around the whole widget * if 512 is set for shadow regions */ if (g->grid.shadowRegions == 512 && g->manager.shadow_thickness && XmLRectIntersect(&eRect, &rRect) != XmLRectInside) { #ifdef MOTIF11 _XmDrawShadow(dpy, win, g->manager.bottom_shadow_GC, g->manager.top_shadow_GC, g->manager.shadow_thickness, 0,0, g->core.width, g->core.height); #else _XmDrawShadows(dpy, win, g->manager.top_shadow_GC, g->manager.bottom_shadow_GC, 0,0, g->core.width, g->core.height, g->manager.shadow_thickness, g->grid.shadowType); #endif } /* end of extra shadow */ for (i = 0; i < 9; i++) { if (!reg[i].width || !reg[i].height) continue; rRect.x = reg[i].x; rRect.y = reg[i].y; rRect.width = reg[i].width; rRect.height = reg[i].height; if (XmLRectIntersect(&eRect, &rRect) == XmLRectOutside) continue; if (g->grid.debugLevel > 2) fprintf(stderr, "XmLGrid: Redisplay region %d shadows\n", i); rRect.x += st; rRect.width -= st * 2; rRect.y += st; rRect.height -= st * 2; if (XmLRectIntersect(&eRect, &rRect) != XmLRectInside && g->manager.shadow_thickness && g->grid.shadowRegions != 512) { if (g->grid.shadowRegions & (1 << i)) #ifdef MOTIF11 _XmDrawShadow(dpy, win, g->manager.bottom_shadow_GC, g->manager.top_shadow_GC, g->manager.shadow_thickness, reg[i].x, reg[i].y, reg[i].width, reg[i].height); #else _XmDrawShadows(dpy, win, g->manager.top_shadow_GC, g->manager.bottom_shadow_GC, reg[i].x, reg[i].y, reg[i].width, reg[i].height, g->manager.shadow_thickness, g->grid.shadowType); #endif else #ifdef MOTIF11 _XmEraseShadow(dpy, win, g->manager.shadow_thickness, reg[i].x, reg[i].y, reg[i].width, reg[i].height); #else _XmClearBorder(dpy, win, reg[i].x, reg[i].y, reg[i].width, reg[i].height, g->manager.shadow_thickness); #endif } rRect.x += st; height = 0; if (g->grid.debugLevel > 2) fprintf(stderr, "XmLGrid: Redisplay region %d content\n", i); for (r = reg[i].row; r < reg[i].row + reg[i].nrow; r++) { rowHeight = GetRowHeight(g, r); if (!rowHeight && !g->grid.mayHaveRowSpans) continue; width = 0; for (c = reg[i].col; c < reg[i].col + reg[i].ncol; c++) { rRect.x = reg[i].x + st + width; rRect.y = reg[i].y + st + height; if (g->grid.singleColScrollMode) rRect.x -= g->grid.singleColScrollPos; rRect.width = GetColWidth(g, c); #if 0 if (i == 1 && r == reg[1].row && c == reg[1].col - 1) { rRect.width -= 10; } #endif /*0 slamm */ rRect.height = rowHeight; width += rRect.width; cell = GetCell(g, r, c); if (!cell) continue; cellValues = XmLGridCellGetRefValues(cell); spanUp = False; spanLeft = False; if (XmLGridCellInRowSpan(cell)) { if (r == reg[i].row) { spanUp = True; if (c == reg[i].col) spanLeft = True; } else continue; } if (XmLGridCellInColumnSpan(cell)) { if (c == reg[i].col) spanLeft = True; else continue; } sr = r; sc = c; if (spanUp == True || spanLeft == True || cellValues->rowSpan || cellValues->columnSpan) { if (RowColFirstSpan(g, r, c, &sr, &sc, &rRect, spanLeft, spanUp) == -1) continue; RowColSpanRect(g, sr, sc, &rRect); } if (!rRect.width || !rRect.height) continue; clipRect = rRect; ClipRectToReg(g, &clipRect, ®[i]); if (!clipRect.width || !clipRect.height) continue; if (event && XRectInRegion(region, clipRect.x, clipRect.y, clipRect.width, clipRect.height) == RectangleOut) continue; cell = GetCell(g, sr, sc); if (!cell) continue; cellValues = XmLGridCellGetRefValues(cell); cbs.reason = XmCR_CELL_DRAW; cbs.event = (XEvent *)event; cbs.rowType = RowPosToType(g, sr); cbs.row = RowPosToTypePos(g, cbs.rowType, sr); cbs.columnType = ColPosToType(g, sc); cbs.column = ColPosToTypePos(g, cbs.columnType, sc); cbs.clipRect = &clipRect; cbs.drawInfo = &ds; ds.gc = g->grid.gc; ds.cellRect = &rRect; ds.topMargin = cellValues->topMargin; ds.bottomMargin = cellValues->bottomMargin; ds.leftMargin = cellValues->leftMargin; ds.rightMargin = cellValues->rightMargin; ds.background = cellValues->background; ds.foreground = cellValues->foreground; ds.fontList = cellValues->fontList; ds.alignment = cellValues->alignment; ds.selectBackground = g->grid.selectBg; ds.selectForeground = g->grid.selectFg; row = (XmLGridRow)XmLArrayGet(g->grid.rowArray, sr); col = (XmLGridColumn)XmLArrayGet(g->grid.colArray, sc); ds.drawFocusType = XmDRAW_FOCUS_NONE; if (g->grid.focusRow == sr && g->grid.highlightRowMode == True && g->grid.focusIn) { RecalcVisPos(g, 0); visPos = XmLGridColumnGetVisPos(col); lastVisPos = XmLArrayGetCount(g->grid.colArray) - g->grid.hiddenColCount - 1; if (visPos == 0 && visPos == lastVisPos) ds.drawFocusType = XmDRAW_FOCUS_CELL; else if (visPos == 0) ds.drawFocusType = XmDRAW_FOCUS_LEFT; else if (visPos == lastVisPos) ds.drawFocusType = XmDRAW_FOCUS_RIGHT; else ds.drawFocusType = XmDRAW_FOCUS_MID; } if (g->grid.focusRow == sr && g->grid.focusCol == sc && g->grid.highlightRowMode == False && g->grid.focusIn) ds.drawFocusType = XmDRAW_FOCUS_CELL; if (XmLGridRowIsSelected(row) == True || XmLGridColumnIsSelected(col) == True || XmLGridCellIsSelected(cell) == True) ds.drawSelected = True; else ds.drawSelected = False; if (g->grid.selectionPolicy == XmSELECT_CELL && g->grid.focusIn && g->grid.focusRow == sr && g->grid.focusCol == sc) ds.drawSelected = False; ds.stringDirection = g->manager.string_direction; XmLGridCellAction(cell, (Widget)g, &cbs); if (hasDrawCB) XtCallCallbackList(w, g->grid.cellDrawCallback, (XtPointer)&cbs); } height += rowHeight; } } if (g->grid.debugLevel > 1) fprintf(stderr, "XmLGrid: Redisplay non-cell areas\n"); n = 0; if (reg[0].width && g->grid.leftFixedMargin) { rect[n].x = reg[0].width; rect[n].y = 0; rect[n].width = g->grid.leftFixedMargin; rect[n].height = g->core.height; n++; } if (reg[2].width && g->grid.rightFixedMargin) { width = 0; if (reg[0].ncol) width += reg[0].width + g->grid.leftFixedMargin; if (reg[1].ncol) width += reg[1].width; rect[n].x = width; rect[n].y = 0; rect[n].width = g->grid.rightFixedMargin; rect[n].height = g->core.height; n++; } if (reg[0].height && g->grid.topFixedMargin) { rect[n].x = 0; rect[n].y = reg[0].height; rect[n].width = g->core.width; rect[n].height = g->grid.topFixedMargin; n++; } if (reg[6].height && g->grid.bottomFixedMargin) { rect[n].x = 0; height = 0; if (reg[0].nrow) height += reg[0].height + g->grid.topFixedMargin; if (reg[3].nrow) height += reg[3].height; rect[n].y = height; rect[n].width = g->core.width; rect[n].height = g->grid.bottomFixedMargin; n++; } width = reg[1].width; if (reg[0].ncol) width += reg[0].width + g->grid.leftFixedMargin; if (reg[2].ncol) width += g->grid.rightFixedMargin + reg[2].width; if (width < (int)g->core.width) { rect[n].x = width; rect[n].y = 0; rect[n].width = g->core.width - width; rect[n].height = g->core.height; n++; } height = reg[3].height; if (reg[0].nrow) height += reg[0].height + g->grid.topFixedMargin; if (reg[6].nrow) height += g->grid.bottomFixedMargin + reg[6].height; if (height < (int)g->core.height) { rect[n].x = 0; rect[n].y = height; rect[n].width = g->core.width; rect[n].height = g->core.height - height; n++; } for (i = 0; i < n; i++) { if (XmLRectIntersect(&eRect, &rect[i]) == XmLRectOutside) continue; XClearArea(dpy, win, rect[i].x, rect[i].y, rect[i].width, rect[i].height, False); } n = 0; if (reg[1].width) { width = 0; for (c = reg[1].col; c < reg[1].col + reg[1].ncol; c++) width += GetColWidth(g, c); for (i = 1; i < 9; i += 3) if (reg[i].height && width < reg[i].width - st * 2) { rect[n].x = reg[i].x + st + width; rect[n].y = reg[i].y + st; rect[n].width = reg[i].x + reg[i].width - rect[n].x - st; rect[n].height = reg[i].height - st * 2; n++; } } if (reg[3].height) { height = 0; for (r = reg[3].row; r < reg[3].row + reg[3].nrow; r++) height += GetRowHeight(g, r); for (i = 3; i < 6; i++) if (reg[i].width && height < reg[i].height - st * 2) { rect[n].x = reg[i].x + st; rect[n].y = reg[i].y + st + height; rect[n].width = reg[i].width - st * 2; rect[n].height = reg[i].y + reg[i].height - rect[n].y - st; n++; } } XSetForeground(dpy, g->grid.gc, g->grid.blankBg); for (i = 0; i < n; i++) { if (XmLRectIntersect(&eRect, &rect[i]) == XmLRectOutside) continue; XFillRectangle(dpy, win, g->grid.gc, rect[i].x, rect[i].y, rect[i].width, rect[i].height); } /* Show any XORed graphics */ DrawResizeLine(g, 0, 1); } static void DrawResizeLine(XmLGridWidget g, int xy, int erase) { if (g->grid.inMode != InResize) return; if (g->grid.hsPolicy == XmRESIZE_IF_POSSIBLE && !g->grid.resizeIsVert) return; DrawXORRect(g, xy, 2, g->grid.resizeIsVert, erase); } static void DrawXORRect(XmLGridWidget g, int xy, int size, int isVert, int erase) { Display *dpy; Window win; GC gc; Pixel black, white; int oldXY, maxX, maxY; if (!XtIsRealized((Widget)g)) return; /* erase is (0 == none) (1 == hide/show) (2 == permenent erase) */ dpy = XtDisplay(g); win = XtWindow(g); gc = g->grid.gc; XSetFunction(dpy, gc, GXinvert); black = BlackPixelOfScreen(XtScreen((Widget)g)); white = WhitePixelOfScreen(XtScreen((Widget)g)); XSetForeground(dpy, gc, black ^ white); maxX = g->core.width; if (XtIsManaged(g->grid.vsb)) maxX -= g->grid.vsb->core.width + g->grid.scrollBarMargin; maxY = g->core.height; if (XtIsManaged(g->grid.hsb)) maxY -= g->grid.hsb->core.height + g->grid.scrollBarMargin; oldXY = g->grid.resizeLineXY; if (isVert) { if (oldXY != -1) XFillRectangle(dpy, win, gc, 0, oldXY, maxX, size); } else { if (oldXY != -1) XFillRectangle(dpy, win, gc, oldXY, 0, size, maxY); } if (!erase) { if (isVert) { if (xy > maxY) xy = maxY - 2; if (xy < 0) xy = 0; XFillRectangle(dpy, win, gc, 0, xy, maxX, size); } else { if (xy > maxX) xy = maxX - 2; if (xy < 0) xy = 0; XFillRectangle(dpy, win, gc, xy, 0, size, maxY); } g->grid.resizeLineXY = xy; } else if (erase == 2) g->grid.resizeLineXY = -1; XSetFunction(dpy, gc, GXcopy); } static void DefineCursor(XmLGridWidget g, char defineCursor) { Display *dpy; Window win; if (!XtIsRealized((Widget)g)) return; dpy = XtDisplay(g); win = XtWindow(g); if (defineCursor != g->grid.cursorDefined) XUndefineCursor(dpy, win); if (defineCursor == CursorVResize) XDefineCursor(dpy, win, g->grid.vResizeCursor); else if (defineCursor == CursorHResize) XDefineCursor(dpy, win, g->grid.hResizeCursor); g->grid.cursorDefined = defineCursor; } static void DrawArea(XmLGridWidget g, int type, int row, int col) { GridReg *reg; Display *dpy; Window win; XExposeEvent event; XRectangle rect[3]; Region region; int i, j, n; Dimension width, height, st; if (g->grid.layoutFrozen == True) return; if (!XtIsRealized((Widget)g)) return; if (!g->core.visible) return; dpy = XtDisplay(g); win = XtWindow(g); reg = g->grid.reg; st = g->manager.shadow_thickness; if (g->grid.debugLevel > 1) fprintf(stderr, "XmLGrid: DrawArea %d %d %d\n", type, row, col); n = 0; switch (type) { case DrawAll: { rect[n].x = 0; rect[n].y = 0; rect[n].width = g->core.width; rect[n].height = g->core.height; n++; break; } case DrawHScroll: { for (i = 1; i < 9; i += 3) { if (!reg[i].width || !reg[i].height) continue; rect[n].x = reg[i].x + st; rect[n].y = reg[i].y + st; rect[n].width = reg[i].width - st * 2; rect[n].height = reg[i].height - st * 2; n++; } break; } case DrawVScroll: { for (i = 3; i < 6; i++) { if (!reg[i].width || !reg[i].height) continue; rect[n].x = reg[i].x + st; rect[n].y = reg[i].y + st; rect[n].width = reg[i].width - st * 2; rect[n].height = reg[i].height - st * 2; n++; } break; } case DrawRow: { for (i = 0; i < 9; i++) { if (!reg[i].width || !reg[i].height) continue; if (!(row >= reg[i].row && row < reg[i].row + reg[i].nrow)) continue; height = 0; for (j = reg[i].row; j < row; j++) height += GetRowHeight(g, j); rect[n].x = reg[i].x + st; rect[n].y = reg[i].y + st + height; rect[n].width = reg[i].width - st * 2; rect[n].height = GetRowHeight(g, row); ClipRectToReg(g, &rect[n], ®[i]); n++; } break; } case DrawCol: { for (i = 0; i < 9; i++) { if (!reg[i].width || !reg[i].height) continue; if (!(col >= reg[i].col && col < reg[i].col + reg[i].ncol)) continue; width = 0; for (j = reg[i].col; j < col; j++) width += GetColWidth(g, j); rect[n].x = reg[i].x + st + width; rect[n].y = reg[i].y + st; rect[n].width = GetColWidth(g, col); rect[n].height = reg[i].height - st * 2; ClipRectToReg(g, &rect[n], ®[i]); n++; } break; } case DrawCell: { if (!RowColToXY(g, row, col, True, &rect[n])) n++; break; } } for (i = 0; i < n; i++) { if (!rect[i].width || !rect[i].height) continue; event.type = Expose; event.window = win; event.display = dpy; event.x = rect[i].x; event.y = rect[i].y; event.width = rect[i].width; event.height = rect[i].height; event.send_event = True; event.count = 0; if (g->grid.immediateDraw) { region = XCreateRegion(); XUnionRectWithRegion(&rect[i], region, region); Redisplay((Widget)g, &event, region); XDestroyRegion(region); } else XSendEvent(dpy, win, False, ExposureMask, (XEvent *)&event); if (g->grid.debugLevel > 1) fprintf(stderr, "XmLGrid: DrawArea expose x %d y %d w %d h %d\n", event.x, event.y, event.width, event.height); } } static void ExtendSelectRange(XmLGridWidget g, int *type, int *fr, int *lr, int *fc, int *lc) { int r, c; if ((g->grid.selectionPolicy == XmSELECT_MULTIPLE_ROW) || (ColPosToType(g, g->grid.extendCol) != XmCONTENT)) *type = SelectRow; else if (RowPosToType(g, g->grid.extendRow) != XmCONTENT) *type = SelectCol; else *type = SelectCell; r = g->grid.extendToRow; if (r < g->grid.headingRowCount) r = g->grid.headingRowCount; if (r >= g->grid.headingRowCount + g->grid.rowCount) r = g->grid.headingRowCount + g->grid.rowCount - 1; if (*type == SelectCol) { *fr = 0; *lr = 1; } else if (g->grid.extendRow < r) { *fr = g->grid.extendRow; *lr = r; } else { *fr = r; *lr = g->grid.extendRow; } c = g->grid.extendToCol; if (c < g->grid.headingColCount) c = g->grid.headingColCount; if (c >= g->grid.headingColCount + g->grid.colCount) c = g->grid.headingColCount + g->grid.colCount - 1; if (*type == SelectRow) { *fc = 0; *lc = 1; } else if (g->grid.extendCol < c) { *fc = g->grid.extendCol; *lc = c; } else { *fc = c; *lc = g->grid.extendCol; } } static void ExtendSelect(XmLGridWidget g, XEvent *event, Boolean set, int row, int col) { int type; int r, fr, lr; int c, fc, lc; if (row == -1 || col == -1) { g->grid.extendRow = -1; g->grid.extendCol = -1; g->grid.extendToRow = -1; g->grid.extendToCol = -1; g->grid.extendSelect = True; return; } if (RowPosToType(g, row) == XmFOOTER || ColPosToType(g, col) == XmFOOTER) return; if ((g->grid.extendToRow == row && g->grid.extendToCol == col) || (g->grid.extendRow == -1 && row == g->grid.focusRow && g->grid.extendCol == -1 && col == g->grid.focusCol)) return; if (g->grid.extendRow != -1 && g->grid.extendCol != -1) { /* clear previous extend */ ExtendSelectRange(g, &type, &fr, &lr, &fc, &lc); for (r = fr; r <= lr; r += 1) for (c = fc; c <= lc; c += 1) SelectTypeArea(g, type, event, RowPosToTypePos(g, XmCONTENT, r), ColPosToTypePos(g, XmCONTENT, c), False, True); } else { g->grid.extendRow = g->grid.focusRow; g->grid.extendCol = g->grid.focusCol; } if (set == True) { g->grid.extendRow = row; g->grid.extendCol = col; } if (g->grid.extendRow < 0 || g->grid.extendCol < 0) return; g->grid.extendToRow = row; g->grid.extendToCol = col; /* set new extend */ ExtendSelectRange(g, &type, &fr, &lr, &fc, &lc); for (r = fr; r <= lr; r += 1) for (c = fc; c <= lc; c += 1) SelectTypeArea(g, type, event, RowPosToTypePos(g, XmCONTENT, r), ColPosToTypePos(g, XmCONTENT, c), g->grid.extendSelect, True); } static void SelectTypeArea(XmLGridWidget g, int type, XEvent *event, int row, int col, Boolean select, Boolean notify) { Widget w; XmLGridRow rowp; XmLGridColumn colp; XmLGridCell cellp; int r, fr, lr, hrc; int c, fc, lc, hcc; int badPos, hasCB; XmLGridCallbackStruct cbs; w = (Widget)g; hrc = g->grid.headingRowCount; hcc = g->grid.headingColCount; cbs.event = event; cbs.rowType = XmCONTENT; cbs.columnType = XmCONTENT; hasCB = 0; if (select == True) { if (type == SelectRow) cbs.reason = XmCR_SELECT_ROW; else if (type == SelectCol) cbs.reason = XmCR_SELECT_COLUMN; else if (type == SelectCell) cbs.reason = XmCR_SELECT_CELL; if (XtHasCallbacks(w, XmNselectCallback) == XtCallbackHasSome) hasCB = 1; } else { if (type == SelectRow) cbs.reason = XmCR_DESELECT_ROW; else if (type == SelectCol) cbs.reason = XmCR_DESELECT_COLUMN; else if (type == SelectCell) cbs.reason = XmCR_DESELECT_CELL; if (XtHasCallbacks(w, XmNdeselectCallback) == XtCallbackHasSome) hasCB = 1; } if (row != -1) { fr = hrc + row; lr = fr + 1; } else { fr = hrc; lr = XmLArrayGetCount(g->grid.rowArray) - g->grid.footerRowCount; } if (col != -1) { fc = hcc + col; lc = fc + 1; } else { fc = hcc; lc = XmLArrayGetCount(g->grid.colArray) - g->grid.footerColCount; } badPos = 0; for (r = fr; r < lr; r++) for (c = fc; c < lc; c++) { if (type == SelectRow) { rowp = (XmLGridRow)XmLArrayGet(g->grid.rowArray, r); if (!rowp) { badPos = 1; continue; } if (XmLGridRowIsSelected(rowp) == select) continue; if (select == True && (g->grid.selectionPolicy == XmSELECT_BROWSE_ROW || g->grid.selectionPolicy == XmSELECT_SINGLE_ROW)) SelectTypeArea(g, SelectRow, event, -1, 0, False, notify); XmLGridRowSetSelected(rowp, select); if (RowIsVisible(g, r)) DrawArea(g, DrawRow, r, 0); if (notify && hasCB) { cbs.row = r - hrc; if (select == True) XtCallCallbackList(w, g->grid.selectCallback, (XtPointer)&cbs); else XtCallCallbackList(w, g->grid.deselectCallback, (XtPointer)&cbs); } } else if (type == SelectCol) { colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, c); if (!colp) { badPos = 1; continue; } if (XmLGridColumnIsSelected(colp) == select) continue; XmLGridColumnSetSelected(colp, select); if (ColIsVisible(g, c)) DrawArea(g, DrawCol, 0, c); if (notify && hasCB) { cbs.column = c - hcc; if (select == True) XtCallCallbackList(w, g->grid.selectCallback, (XtPointer)&cbs); else XtCallCallbackList(w, g->grid.deselectCallback, (XtPointer)&cbs); } } else if (type == SelectCell) { cellp = GetCell(g, r, c); if (!cellp) { badPos = 1; continue; } if (XmLGridCellIsSelected(cellp) == select) continue; XmLGridCellSetSelected(cellp, select); DrawArea(g, DrawCell, r, c); if (notify && hasCB) { cbs.column = c - hcc; cbs.row = r - hrc; if (select == True) XtCallCallbackList(w, g->grid.selectCallback, (XtPointer)&cbs); else XtCallCallbackList(w, g->grid.deselectCallback, (XtPointer)&cbs); } } } if (badPos) XmLWarning((Widget)g, "SelectTypeArea() - bad position"); } static int GetSelectedArea(XmLGridWidget g, int type, int *rowPos, int *colPos, int count) { XmLGridRow row; XmLGridColumn col; XmLGridCell cell; int r, fr, lr; int c, fc, lc; int n; if (type == SelectCol) { fr = 0; lr = 1; } else { fr = g->grid.headingRowCount; lr = XmLArrayGetCount(g->grid.rowArray) - g->grid.footerRowCount; } if (type == SelectRow) { fc = 0; lc = 1; } else { fc = g->grid.headingColCount; lc = XmLArrayGetCount(g->grid.colArray) - g->grid.footerColCount; } n = 0; for (r = fr; r < lr; r++) for (c = fc; c < lc; c++) { if (type == SelectRow) { row = (XmLGridRow)XmLArrayGet(g->grid.rowArray, r); if (row && XmLGridRowIsSelected(row) == True) { if (rowPos && n < count) rowPos[n] = r - fr; n++; } } else if (type == SelectCol) { col = (XmLGridColumn)XmLArrayGet(g->grid.colArray, c); if (col && XmLGridColumnIsSelected(col) == True) { if (colPos && n < count) colPos[n] = c - fc; n++; } } else if (type == SelectCell) { cell = GetCell(g, r, c); if (cell && XmLGridCellIsSelected(cell) == True) { if (rowPos && colPos && n < count) { rowPos[n] = r - fr; colPos[n] = c - fc; } n++; } } } return n; } static void ChangeManaged(Widget w) { _XmNavigChangeManaged(w); } static void Resize(Widget w) { XmLGridWidget g; XmLGridCallbackStruct cbs; g = (XmLGridWidget)w; if (!g->grid.inResize) { cbs.reason = XmCR_RESIZE_GRID; g->grid.inResize = True; XtCallCallbackList((Widget)g, g->grid.resizeCallback, (XtPointer)&cbs); g->grid.inResize = False; } VertLayout(g, 0); HorizLayout(g, 0); PlaceScrollbars(g); DrawArea(g, DrawAll, 0, 0); } static void PlaceScrollbars(XmLGridWidget g) { int x, y; int width, height; Widget vsb, hsb; Dimension st, headingRowHeight = 0; st = g->manager.shadow_thickness; vsb = g->grid.vsb; hsb = g->grid.hsb; width = g->core.width; if (XtIsManaged(vsb)) width -= vsb->core.width; if (width <= 0) width = 1; y = g->core.height - hsb->core.height; XtConfigureWidget(hsb, 0, y, width, hsb->core.height, 0); height = g->core.height; if (XtIsManaged(hsb)) height -= hsb->core.height; y = 0; if (g->grid.headingRowCount > 0) { XmLGridRow rowp; rowp = (XmLGridRow)XmLArrayGet(g->grid.rowArray, 0); headingRowHeight = XmLGridRowHeightInPixels(rowp) + st; } if (g->grid.hideUnhideButtons && g->grid.hideButton && g->grid.unhideButton) { int buttonWidth = vsb->core.width - 4; if (headingRowHeight == 0) headingRowHeight = 20; /* if there is at least heading row, we make the height of the button the height of the first heading row. This is pretty braindead... */ XtConfigureWidget(g->grid.unhideButton, g->core.width - buttonWidth*2 - st, y + st, buttonWidth, headingRowHeight - st, 0); XtConfigureWidget(g->grid.hideButton, g->core.width - buttonWidth - st, y + st, buttonWidth, headingRowHeight - st, 0); setHideUnhideSensitivity((Widget)g); /* once we've positioned it, make sure it's managed. Doing it in this order (position, then manage) reduces screen flickering -- the button doesn't flash on in the upper left corner for an instant. */ if (!XtIsManaged(g->grid.hideButton)) XtManageChild(g->grid.hideButton); if (!XtIsManaged(g->grid.unhideButton)) XtManageChild(g->grid.unhideButton); } if (height <= 0) width = 1; x = g->core.width - vsb->core.width; XtConfigureWidget(vsb, x, y + headingRowHeight + g->manager.shadow_thickness, vsb->core.width, height - headingRowHeight - g->manager.shadow_thickness, 0); } void _XmLGridLayout(XmLGridWidget g) { VertLayout(g, 1); HorizLayout(g, 1); } static void VertLayout(XmLGridWidget g, int resizeIfNeeded) { GridReg *reg; int i, j, st2, height, rowCount; int topNRow, topHeight; int midRow, midY, midNRow, midHeight; int botRow, botY, botNRow, botHeight; int scrollChanged, needsSB, needsResize, cRow; int maxRow, maxPos, maxHeight, newHeight, sliderSize; int horizSizeChanged; XtWidgetGeometry req; XmLGridCallbackStruct cbs; XmLGridPreLayoutProc preLayoutProc; if (g->grid.layoutFrozen == True) { g->grid.needsVertLayout = 1; return; } maxRow = maxPos = maxHeight = newHeight = horizSizeChanged = 0; preLayoutProc = XmLGridClassPartOfWidget(g).preLayoutProc; if (g->grid.layoutStack < 2 && preLayoutProc != XmInheritGridPreLayout) horizSizeChanged = preLayoutProc(g, 1); scrollChanged = 0; needsResize = 0; needsSB = 0; rowCount = XmLArrayGetCount(g->grid.rowArray); reg = g->grid.reg; st2 = g->manager.shadow_thickness * 2; TextAction(g, TEXT_HIDE); topHeight = 0; topNRow = g->grid.topFixedCount; if (topNRow > g->grid.rowCount + g->grid.headingRowCount) topNRow = g->grid.rowCount + g->grid.headingRowCount; if (topNRow) { topHeight += st2; for (i = 0; i < topNRow; i++) topHeight += GetRowHeight(g, i); } botHeight = 0; botNRow = g->grid.bottomFixedCount; if (topNRow + botNRow > rowCount) botNRow = rowCount - topNRow; botRow = rowCount - botNRow; if (botNRow) { botHeight += st2; for (i = botRow; i < rowCount; i++) botHeight += GetRowHeight(g, i); } height = 0; if (topNRow) height += topHeight + g->grid.topFixedMargin; midY = height; if (botNRow) height += botHeight + g->grid.bottomFixedMargin; if (XtIsManaged(g->grid.hsb)) { height += g->grid.hsb->core.height; height += g->grid.scrollBarMargin; } maxHeight = g->core.height - height; if (g->grid.vsPolicy != XmCONSTANT) { if (rowCount == topNRow + botNRow) midHeight = 0; else midHeight = st2; for (i = topNRow; i < rowCount - botNRow; i++) midHeight += GetRowHeight(g, i); midRow = topNRow; midNRow = rowCount - topNRow - botNRow; needsResize = 1; newHeight = midHeight + height; if (g->grid.debugLevel) fprintf(stderr, "XmLGrid: VertLayout VARIABLE height\n"); } else { if (maxHeight < st2) maxHeight = 0; height = st2; j = rowCount - botNRow - 1; for (i = j; i >= topNRow; i--) { height += GetRowHeight(g, i); if (height > maxHeight) break; } i++; if (i > j) i = j; maxRow = i; if (maxRow < topNRow) maxRow = topNRow; if (g->grid.debugLevel) fprintf(stderr, "XmLGrid: VertLayout max scroll row %d\n", i); if (maxRow == topNRow) { if (g->grid.scrollRow != topNRow) { scrollChanged = 1; g->grid.scrollRow = topNRow; } midRow = topNRow; midHeight = maxHeight; midNRow = rowCount - topNRow - botNRow; if (g->grid.debugLevel) fprintf(stderr, "XmLGrid: VertLayout everything fits\n"); } else { if (g->grid.scrollRow < topNRow) { scrollChanged = 1; g->grid.scrollRow = topNRow; if (g->grid.debugLevel) fprintf(stderr, "XmLGrid: VertLayout scrolled < topRow\n"); } if (g->grid.scrollRow > maxRow) { if (g->grid.debugLevel) fprintf(stderr, "XmLGrid: VertLayout scrolled > maxRow\n"); scrollChanged = 1; g->grid.scrollRow = maxRow; } height = st2; midNRow = 0; for (i = g->grid.scrollRow; i < rowCount - botNRow; i++) { midNRow++; height += GetRowHeight(g, i); if (height >= maxHeight) break; } needsSB = 1; midRow = g->grid.scrollRow; midHeight = maxHeight; } } botY = midY + midHeight; if (botNRow) botY += g->grid.bottomFixedMargin; for (i = 0; i < 3; i++) { reg[i].y = 0; reg[i].height = topHeight; reg[i].row = 0; reg[i].nrow = topNRow; } for (i = 3; i < 6; i++) { reg[i].y = midY; reg[i].height = midHeight; reg[i].row = midRow; reg[i].nrow = midNRow; } for (i = 6; i < 9; i++) { reg[i].y = botY; reg[i].height = botHeight; reg[i].row = botRow; reg[i].nrow = botNRow; } if (g->grid.debugLevel) { fprintf(stderr, "XmLGrid: VertLayout TOP %3dy %3dh %3dr %3dnr\n", reg[0].y, reg[0].height, reg[0].row, reg[0].nrow); fprintf(stderr, "XmLGrid: VertLayout MID %3dy %3dh %3dr %3dnr\n", reg[3].y, reg[3].height, reg[3].row, reg[3].nrow); fprintf(stderr, "XmLGrid: VertLayout BOT %3dy %3dh %3dr %3dnr\n", reg[6].y, reg[6].height, reg[6].row, reg[6].nrow); } if (needsSB) { if (!XtIsManaged(g->grid.vsb)) { XtManageChild(g->grid.vsb); horizSizeChanged = 1; } if (g->grid.debugLevel) fprintf(stderr, "XmLGrid: VertLayout set sb values\n"); maxPos = PosToVisPos(g, maxRow, 1); sliderSize = PosToVisPos(g, rowCount - botNRow - 1, 1) - maxPos + 1; XtVaSetValues(g->grid.vsb, XmNminimum, PosToVisPos(g, topNRow, 1), XmNmaximum, maxPos + sliderSize, XmNsliderSize, sliderSize, XmNpageIncrement, sliderSize, XmNvalue, PosToVisPos(g, g->grid.scrollRow, 1), NULL); } else if (g->grid.vsPolicy == XmCONSTANT && g->grid.vsbDisplayPolicy == XmSTATIC) { if (!XtIsManaged(g->grid.vsb)) { XtManageChild(g->grid.vsb); horizSizeChanged = 1; } if (g->grid.debugLevel) fprintf(stderr, "XmLGrid: VertLayout vsb not needed but static\n"); XtVaSetValues(g->grid.vsb, XmNminimum, 0, XmNmaximum, 1, XmNsliderSize, 1, XmNpageIncrement, 1, XmNvalue, 0, NULL); } else { if (XtIsManaged(g->grid.vsb)) { XtUnmanageChild(g->grid.vsb); horizSizeChanged = 1; } } if (needsResize && resizeIfNeeded) { if (newHeight < 1) newHeight = 1; req.request_mode = CWHeight; req.height = newHeight; if (g->grid.debugLevel) fprintf(stderr, "XmLGrid: VertLayout Req h %d\n", (int)newHeight); XtMakeGeometryRequest((Widget)g, &req, NULL); PlaceScrollbars(g); } if (scrollChanged) DrawArea(g, DrawVScroll, 0, 0); TextAction(g, TEXT_SHOW); cRow = g->grid.scrollRow - g->grid.headingRowCount; if (cRow != g->grid.cScrollRow) { g->grid.cScrollRow = cRow; cbs.reason = XmCR_SCROLL_ROW; cbs.rowType = XmCONTENT; cbs.row = cRow; XtCallCallbackList((Widget)g, g->grid.scrollCallback, (XtPointer)&cbs); } if (horizSizeChanged) { if (g->grid.layoutStack > 2) XmLWarning((Widget)g, "VertLayout() - recursion error"); else { g->grid.layoutStack++; HorizLayout(g, resizeIfNeeded); g->grid.layoutStack--; } PlaceScrollbars(g); } } static void HorizLayout(XmLGridWidget g, int resizeIfNeeded) { GridReg *reg; int i, j, st2, width, colCount; int leftNCol, leftWidth; int midCol, midX, midNCol, midWidth; int rightCol, rightX, rightNCol, rightWidth; int scrollChanged, needsSB, needsResize, cCol; int maxCol, maxPos, maxWidth, newWidth, sliderSize; int vertSizeChanged; XtWidgetGeometry req; XmLGridCallbackStruct cbs; XmLGridPreLayoutProc preLayoutProc; if (g->grid.layoutFrozen == True) { g->grid.needsHorizLayout = 1; return; } maxCol = maxPos = newWidth = vertSizeChanged = 0; preLayoutProc = XmLGridClassPartOfWidget(g).preLayoutProc; if (g->grid.layoutStack < 2 && preLayoutProc != XmInheritGridPreLayout) vertSizeChanged = preLayoutProc(g, 0); scrollChanged = 0; needsResize = 0; needsSB = 0; if (g->grid.hsPolicy == XmRESIZE_IF_POSSIBLE && g->grid.visibleCols) colCount = g->grid.visibleCols; else colCount = g->grid.colCount + g->grid.headingColCount + g->grid.footerColCount; if (g->grid.hsPolicy == XmRESIZE_IF_POSSIBLE) { SizeColumnsToFit(g, 0); } reg = g->grid.reg; st2 = g->manager.shadow_thickness * 2; TextAction(g, TEXT_HIDE); leftWidth = 0; leftNCol = g->grid.leftFixedCount; if (leftNCol > g->grid.colCount + g->grid.headingColCount) leftNCol = g->grid.colCount + g->grid.headingColCount; if (leftNCol) { leftWidth += st2; for (i = 0; i < leftNCol; i++) leftWidth += GetColWidth(g, i); } rightWidth = 0; rightNCol = g->grid.rightFixedCount; if (rightNCol + leftNCol > colCount) rightNCol = colCount - leftNCol; rightCol = colCount - rightNCol; if (rightNCol) { rightWidth += st2; for (i = rightCol; i < colCount; i++) rightWidth += GetColWidth(g, i); } width = 0; if (leftNCol) width += leftWidth + g->grid.leftFixedMargin; midX = width; if (rightNCol) width += rightWidth + g->grid.rightFixedMargin; if (XtIsManaged(g->grid.vsb)) { width += g->grid.vsb->core.width; width += g->grid.scrollBarMargin; } maxWidth = g->core.width - width; if (g->grid.hsPolicy == XmVARIABLE || g->grid.hsPolicy == XmRESIZE_IF_POSSIBLE) { if (colCount == leftNCol + rightNCol) midWidth = 0; else midWidth = st2; /* This assumes the show/hide buttons will be wider than the vertical scrollbar */ if (g->grid.hsPolicy == XmRESIZE_IF_POSSIBLE) { if (g->grid.hideUnhideButtons) midWidth += XtWidth(g->grid.hideButton) * 2; else if (XtIsManaged(g->grid.vsb)) midWidth += XtWidth(g->grid.vsb); } for (i = leftNCol; i < colCount - rightNCol; i++) midWidth += GetColWidth(g, i); midCol = leftNCol; midNCol = colCount - leftNCol - rightNCol; needsResize = 1; newWidth = midWidth + width; if (g->grid.debugLevel) { if (g->grid.hsPolicy == XmVARIABLE) fprintf(stderr, "XmLGrid: HorizLayout VARIABLE width\n"); else fprintf(stderr, "XmLGrid: HorizLayout REZISE_IF_POSSIBLE\n"); } } else { if (maxWidth < st2) maxWidth = 0; width = st2; j = colCount - rightNCol - 1; for (i = j; i >= leftNCol; i--) { width += GetColWidth(g, i); if (width > maxWidth) break; } i++; if (i > j) i = j; maxCol = i; if (maxCol < leftNCol) maxCol = leftNCol; if (g->grid.debugLevel) fprintf(stderr, "XmLGrid: HorizLayout max scroll col %d\n", i); if (maxCol == leftNCol) { if (g->grid.scrollCol != leftNCol) { scrollChanged = 1; g->grid.scrollCol = leftNCol; } midCol = leftNCol; midWidth = maxWidth; midNCol = colCount - leftNCol - rightNCol; if (g->grid.debugLevel) fprintf(stderr, "XmLGrid: HorizLayout everything fits\n"); } else { if (g->grid.scrollCol < leftNCol) { scrollChanged = 1; g->grid.scrollCol = leftNCol; if (g->grid.debugLevel) fprintf(stderr, "XmLGrid: HorizLayout scroll < leftCol\n"); } if (g->grid.scrollCol > maxCol) { if (g->grid.debugLevel) fprintf(stderr, "XmLGrid: HorizLayout scroll > maxCol\n"); scrollChanged = 1; g->grid.scrollCol = maxCol; } width = st2; midNCol = 0; for (i = g->grid.scrollCol; i < colCount - rightNCol; i++) { midNCol++; width += GetColWidth(g, i); if (width >= maxWidth) break; } needsSB = 1; midCol = g->grid.scrollCol; midWidth = maxWidth; } } rightX = midX + midWidth; if (rightNCol) rightX += g->grid.rightFixedMargin; for (i = 0; i < 9; i += 3) { reg[i].x = 0; reg[i].width = leftWidth; reg[i].col = 0; reg[i].ncol = leftNCol; } for (i = 1; i < 9; i += 3) { reg[i].x = midX; reg[i].width = midWidth; reg[i].col = midCol; reg[i].ncol = midNCol; } for (i = 2; i < 9; i += 3) { reg[i].x = rightX; reg[i].width = rightWidth; reg[i].col = rightCol; reg[i].ncol = rightNCol; } if (g->grid.debugLevel) { fprintf(stderr, "XmLGrid: HorizLayout LFT %3dx %3dw %3dc %3dnc\n", reg[0].x, reg[0].width, reg[0].col, reg[0].ncol); fprintf(stderr, "XmLGrid: HorizLayout MID %3dx %3dw %3dc %3dnc\n", reg[1].x, reg[1].width, reg[1].col, reg[1].ncol); fprintf(stderr, "XmLGrid: HorizLayout RHT %3dx %3dw %3dc %3dnc\n", reg[2].x, reg[2].width, reg[2].col, reg[2].ncol); } if (g->grid.hsPolicy == XmCONSTANT && colCount == 1 && g->grid.colCount == 1 && width > maxWidth) { /* Single Column Pixel Scroll Mode */ if (g->grid.singleColScrollMode) { i = g->grid.singleColScrollPos; if (i < 0) i = 0; else if (i > width - maxWidth) i = width - maxWidth; } else i = 0; XtVaSetValues(g->grid.hsb, XmNminimum, 0, XmNmaximum, width - maxWidth + 1, XmNsliderSize, 1, XmNpageIncrement, ((width - maxWidth) / 4) + 1, XmNvalue, i, NULL); if (!XtIsManaged(g->grid.hsb)) { XtManageChild(g->grid.hsb); vertSizeChanged = 1; } g->grid.singleColScrollMode = 1; g->grid.singleColScrollPos = i; } else g->grid.singleColScrollMode = 0; if (g->grid.singleColScrollMode) ; else if (needsSB) { if (g->grid.debugLevel) fprintf(stderr, "XmLGrid: HorizLayout set sb values\n"); if (!XtIsManaged(g->grid.hsb)) { XtManageChild(g->grid.hsb); vertSizeChanged = 1; } maxPos = PosToVisPos(g, maxCol, 0); sliderSize = PosToVisPos(g, colCount - rightNCol - 1, 0) - maxPos + 1; XtVaSetValues(g->grid.hsb, XmNminimum, PosToVisPos(g, leftNCol, 0), XmNmaximum, maxPos + sliderSize, XmNsliderSize, sliderSize, XmNpageIncrement, sliderSize, XmNvalue, PosToVisPos(g, g->grid.scrollCol, 0), NULL); } else if (g->grid.hsPolicy == XmCONSTANT && g->grid.hsbDisplayPolicy == XmSTATIC) { if (!XtIsManaged(g->grid.hsb)) { XtManageChild(g->grid.hsb); vertSizeChanged = 1; } if (g->grid.debugLevel) fprintf(stderr, "XmLGrid: HorizLayout hsb not needed - static\n"); XtVaSetValues(g->grid.hsb, XmNminimum, 0, XmNmaximum, 1, XmNsliderSize, 1, XmNpageIncrement, 1, XmNvalue, 0, NULL); } else { if (XtIsManaged(g->grid.hsb)) { XtUnmanageChild(g->grid.hsb); vertSizeChanged = 1; } } if (needsResize && resizeIfNeeded) { if (newWidth < 1) newWidth = 1; req.request_mode = CWWidth; req.width = newWidth; if (g->grid.debugLevel) fprintf(stderr, "XmLGrid: HorizLayout Req w %d\n", (int)newWidth); XtMakeGeometryRequest((Widget)g, &req, NULL); PlaceScrollbars(g); } if (scrollChanged) DrawArea(g, DrawHScroll, 0, 0); TextAction(g, TEXT_SHOW); cCol = g->grid.scrollCol - g->grid.headingColCount; if (cCol != g->grid.cScrollCol) { g->grid.cScrollCol = cCol; cbs.reason = XmCR_SCROLL_COLUMN; cbs.columnType = XmCONTENT; cbs.column = cCol; XtCallCallbackList((Widget)g, g->grid.scrollCallback, (XtPointer)&cbs); } if (vertSizeChanged) { if (g->grid.layoutStack > 2) XmLWarning((Widget)g, "HorizLayout() - recursion error"); else { g->grid.layoutStack++; VertLayout(g, resizeIfNeeded); g->grid.layoutStack--; } PlaceScrollbars(g); } } static void ApplyVisibleRows(XmLGridWidget g) { XtWidgetGeometry req; XmLGridCellRefValues *cellValues; if (g->grid.vsPolicy != XmCONSTANT) { XmLWarning((Widget)g, "verticalSizePolicy must be XmCONSTANT to set visibleRows"); return; } cellValues = g->grid.defCellValues; req.request_mode = CWHeight; req.height = g->manager.shadow_thickness * 2 + g->grid.visibleRows * (4 + cellValues->fontHeight + cellValues->topMargin + cellValues->bottomMargin); if (g->grid.hsPolicy == XmCONSTANT && g->grid.hsbDisplayPolicy == XmSTATIC) req.height += g->grid.scrollBarMargin + XtHeight(g->grid.hsb); XtMakeGeometryRequest((Widget)g, &req, NULL); } static void ApplyVisibleCols(XmLGridWidget g) { XtWidgetGeometry req; XmLGridCellRefValues *cellValues; if (g->grid.hsPolicy != XmCONSTANT) { XmLWarning((Widget)g, "horizontalSizePolicy must be XmCONSTANT to set visibleColumns"); return; } cellValues = g->grid.defCellValues; req.request_mode = CWWidth; req.width = g->manager.shadow_thickness * 2 + g->grid.visibleCols * (4 + 8 * cellValues->fontWidth + cellValues->leftMargin + cellValues->rightMargin); if (g->grid.vsPolicy == XmCONSTANT && g->grid.vsbDisplayPolicy == XmSTATIC) req.width += g->grid.scrollBarMargin + XtWidth(g->grid.vsb); XtMakeGeometryRequest((Widget)g, &req, NULL); } static void VisPosChanged(XmLGridWidget g, int isVert) { if (isVert) { g->grid.recalcVertVisPos = 1; g->grid.vertVisChangedHint = 1; } else g->grid.recalcHorizVisPos = 1; } static void RecalcVisPos(XmLGridWidget g, int isVert) { XmLGridRow row; XmLGridColumn col; int i, count, visPos; if (g->grid.layoutFrozen == True) XmLWarning((Widget)g, "RecalcVisPos() - layout is frozen"); visPos = 0; if (isVert) { if (!g->grid.recalcVertVisPos) return; count = XmLArrayGetCount(g->grid.rowArray); for (i = 0; i < count; i++) { row = (XmLGridRow)XmLArrayGet(g->grid.rowArray, i); XmLGridRowSetVisPos(row, visPos); if (!XmLGridRowIsHidden(row)) visPos++; } g->grid.recalcVertVisPos = 0; } else { if (!g->grid.recalcHorizVisPos) return; count = XmLArrayGetCount(g->grid.colArray); for (i = 0; i < count; i++) { col = (XmLGridColumn)XmLArrayGet(g->grid.colArray, i); XmLGridColumnSetVisPos(col, visPos); if (!XmLGridColumnIsHidden(col)) visPos++; } g->grid.recalcHorizVisPos = 0; } } static int PosToVisPos(XmLGridWidget g, int pos, int isVert) { int visPos; XmLGridRow row; XmLGridColumn col; if (isVert) { if (!g->grid.hiddenRowCount) visPos = pos; else { RecalcVisPos(g, isVert); row = (XmLGridRow)XmLArrayGet(g->grid.rowArray, pos); if (row) visPos = XmLGridRowGetVisPos(row); else visPos = -1; } } else { if (!g->grid.hiddenColCount) visPos = pos; else { RecalcVisPos(g, isVert); col = (XmLGridColumn)XmLArrayGet(g->grid.colArray, pos); if (col) visPos = XmLGridColumnGetVisPos(col); else visPos = -1; } } if (visPos == -1) XmLWarning((Widget)g, "PosToVisPos() - invalid pos"); return visPos; } static int VisPosToPos(XmLGridWidget g, int visPos, int isVert) { XmLGridRow row; XmLGridColumn col; int i1, i2, vp1, vp2, ic, mid, val, count; if (isVert) { if (!g->grid.hiddenRowCount) return visPos; count = XmLArrayGetCount(g->grid.rowArray); if (!count) { XmLWarning((Widget)g, "VisPosToPos() - called when no rows exist"); return -1; } RecalcVisPos(g, isVert); row = (XmLGridRow)XmLArrayGet(g->grid.rowArray, 0); vp1 = XmLGridRowGetVisPos(row); row = (XmLGridRow)XmLArrayGet(g->grid.rowArray, count - 1); vp2 = XmLGridRowGetVisPos(row); if (visPos < vp1 || visPos > vp2) { XmLWarning((Widget)g, "VisPosToPos() - invalid Vert visPos"); return -1; } } else { if (!g->grid.hiddenColCount) return visPos; count = XmLArrayGetCount(g->grid.colArray); if (!count) { XmLWarning((Widget)g, "VisPosToPos() - called when no cols exist"); return -1; } RecalcVisPos(g, isVert); col = (XmLGridColumn)XmLArrayGet(g->grid.colArray, 0); vp1 = XmLGridColumnGetVisPos(col); col = (XmLGridColumn)XmLArrayGet(g->grid.colArray, count - 1); vp2 = XmLGridColumnGetVisPos(col); if (visPos < vp1 || visPos > vp2) { XmLWarning((Widget)g, "VisPosToPos() - invalid Horiz visPos"); return -1; } } i1 = 0; i2 = count; ic = 0; while (1) { mid = i1 + (i2 - i1) / 2; if (isVert) { row = (XmLGridRow)XmLArrayGet(g->grid.rowArray, mid); val = XmLGridRowGetVisPos(row); } else { col = (XmLGridColumn)XmLArrayGet(g->grid.colArray, mid); val = XmLGridColumnGetVisPos(col); } if (visPos > val) i1 = mid; else if (visPos < val) i2 = mid; else break; if (++ic > 1000) return -1; /* inf loop */ } return mid; } static unsigned char ColPosToType(XmLGridWidget g, int pos) { unsigned char type; if (pos < g->grid.headingColCount) type = XmHEADING; else if (pos < g->grid.headingColCount + g->grid.colCount) type = XmCONTENT; else type = XmFOOTER; return type; } static int ColPosToTypePos(XmLGridWidget g, unsigned char type, int pos) { int c; if (type == XmHEADING) c = pos; else if (type == XmCONTENT) c = pos - g->grid.headingColCount; else c = pos - g->grid.headingColCount - g->grid.colCount; return c; } static unsigned char RowPosToType(XmLGridWidget g, int pos) { unsigned char type; if (pos < g->grid.headingRowCount) type = XmHEADING; else if (pos < g->grid.headingRowCount + g->grid.rowCount) type = XmCONTENT; else type = XmFOOTER; return type; } static int RowPosToTypePos(XmLGridWidget g, unsigned char type, int pos) { int r; if (type == XmHEADING) r = pos; else if (type == XmCONTENT) r = pos - g->grid.headingRowCount; else r = pos - g->grid.headingRowCount - g->grid.rowCount; return r; } static int ColTypePosToPos(XmLGridWidget g, unsigned char type, int pos, int allowNeg) { if (pos < 0) { if (!allowNeg) return -1; if (type == XmHEADING) pos = g->grid.headingColCount; else if (type == XmFOOTER || type == XmALL_TYPES) pos = g->grid.headingColCount + g->grid.colCount + g->grid.footerColCount; else /* XmCONTENT */ pos = g->grid.headingColCount + g->grid.colCount; } else { if (type == XmALL_TYPES) ; else if (type == XmHEADING) { if (pos >= g->grid.headingColCount) return -1; } else if (type == XmFOOTER) { if (pos >= g->grid.footerColCount) return -1; pos += g->grid.headingColCount + g->grid.colCount; } else /* XmCONTENT */ { if (pos >= g->grid.colCount) return -1; pos += g->grid.headingColCount; } } return pos; } static int RowTypePosToPos(XmLGridWidget g, unsigned char type, int pos, int allowNeg) { if (pos < 0) { if (!allowNeg) return -1; if (type == XmHEADING) pos = g->grid.headingRowCount; else if (type == XmFOOTER || type == XmALL_TYPES) pos = g->grid.headingRowCount + g->grid.rowCount + g->grid.footerRowCount; else /* XmCONTENT */ pos = g->grid.headingRowCount + g->grid.rowCount; } else { if (type == XmALL_TYPES) ; else if (type == XmHEADING) { if (pos >= g->grid.headingRowCount) return -1; } else if (type == XmFOOTER) { if (pos >= g->grid.footerRowCount) return -1; pos += g->grid.headingRowCount + g->grid.rowCount; } else /* XmCONTENT */ { if (pos >= g->grid.rowCount) return -1; pos += g->grid.headingRowCount; } } return pos; } static int ScrollRowBottomPos(XmLGridWidget g, int row) { int r, h, height; if (g->grid.vsPolicy == XmVARIABLE) return -1; height = g->grid.reg[4].height; h = 0; r = row; while (r >= 0) { h += GetRowHeight(g, r); if (h > height) break; r--; } if (r != row) r++; return r; } static int ScrollColRightPos(XmLGridWidget g, int col) { int c, w, width; if (g->grid.hsPolicy == XmVARIABLE) return -1; width = g->grid.reg[4].width; w = 0; c = col; while (c >= 0) { w += GetColWidth(g, c); if (w >= width) break; c--; } if (c != col) c++; return c; } static int PosIsResize(XmLGridWidget g, int x, int y, int *row, int *col, int *isVert) { XRectangle rect; int i, nx, ny, margin; /* check for bottom resize */ if (g->grid.allowRowResize == True) for (i = 0; i < 2; i++) { nx = x; ny = y - (4 * i); if (XYToRowCol(g, nx, ny, row, col) != -1 && RowColToXY(g, *row, *col, False, &rect) != -1 && ColPosToType(g, *col) == XmHEADING) { margin = ny - (rect.y + rect.height); if (margin > -5 && margin < 5) { *isVert = 1; return 1; } } } /* check for right resize */ if (g->grid.allowColResize == True) for (i = 0; i < 2; i++) { XmLGridColumn colp; int c; nx = x - (4 * i); ny = y; if (XYToRowCol(g, nx, ny, row, col) != -1 && RowColToXY(g, *row, *col, False, &rect) != -1 && RowPosToType(g, *row) == XmHEADING && *col != XmLArrayGetCount(g->grid.colArray) - 1) { Boolean foundResizable = 0; colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, *col); if (!colp->grid.resizable) continue; for (c = *col + 1; c < XmLArrayGetCount(g->grid.colArray); c ++) { colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, c); if (colp->grid.resizable && (g->grid.hsPolicy != XmRESIZE_IF_POSSIBLE || (g->grid.visibleCols == 0 || c < g->grid.visibleCols)) ) { foundResizable = True; break; } } if (!foundResizable) return 0; margin = nx - (rect.x + rect.width); if (margin > -5 && margin < 5) { *isVert = 0; return 1; } } } return 0; } int XmLGridPosIsResize(Widget g, int x, int y) { int row, col; int isVert; return PosIsResize((XmLGridWidget) g, x, y, &row, &col, &isVert); } static int XYToRowCol(XmLGridWidget g, int x, int y, int *row, int *col) { XRectangle xyRect, rect; GridReg *reg; int i, r, c; int width, height; int st; reg = g->grid.reg; st = g->manager.shadow_thickness; xyRect.x = x; xyRect.y = y; xyRect.width = 1; xyRect.height = 1; for (i = 0; i < 9; i++) { if (!reg[i].width || !reg[i].height) continue; rect.x = reg[i].x + st; rect.y = reg[i].y + st; rect.width = reg[i].width - st * 2; rect.height = reg[i].height - st * 2; if (XmLRectIntersect(&xyRect, &rect) == XmLRectOutside) continue; height = 0; for (r = reg[i].row; r < reg[i].row + reg[i].nrow; r++) { width = 0; for (c = reg[i].col; c < reg[i].col + reg[i].ncol; c++) { rect.x = reg[i].x + st + width; rect.y = reg[i].y + st + height; rect.width = GetColWidth(g, c); rect.height = GetRowHeight(g, r); if (g->grid.singleColScrollMode) rect.x -= g->grid.singleColScrollPos; ClipRectToReg(g, &rect, ®[i]); if (XmLRectIntersect(&xyRect, &rect) != XmLRectOutside) { if (!RowColFirstSpan(g, r, c, row, col, 0, True, True)) return 0; /* SUCCESS */ else return -1; } width += GetColWidth(g, c); } height += GetRowHeight(g, r); } } return -1; } static int RowColToXY(XmLGridWidget g, int row, int col, Boolean clipped, XRectangle *rect) { XmLGridCell cell; XmLGridCellRefValues *cellValues; GridReg *reg; Dimension st; int i, r, c, off; reg = g->grid.reg; st = g->manager.shadow_thickness; cell = GetCell(g, row, col); if (!cell) return -1; cellValues = XmLGridCellGetRefValues(cell); if (!cellValues) return -1; for (i = 0; i < 9; i++) { if (!reg[i].width || !reg[i].height) continue; if (!(col >= reg[i].col && col < reg[i].col + reg[i].ncol && row >= reg[i].row && row < reg[i].row + reg[i].nrow)) continue; off = 0; for (r = reg[i].row; r < row; r++) off += GetRowHeight(g, r); rect->y = reg[i].y + st + off; rect->height = GetRowHeight(g, row); if (cellValues->rowSpan) for (r = row + 1; r <= row + cellValues->rowSpan; r++) rect->height += GetRowHeight(g, r); off = 0; for (c = reg[i].col; c < col; c++) off += GetColWidth(g, c); rect->x = reg[i].x + st + off; rect->width = GetColWidth(g, col); if (cellValues->columnSpan) for (c = col + 1; c <= col + cellValues->columnSpan; c++) rect->width += GetColWidth(g, c); if (g->grid.singleColScrollMode) rect->x -= g->grid.singleColScrollPos; if (clipped == True) ClipRectToReg(g, rect, ®[i]); return 0; } return -1; } static int RowColFirstSpan(XmLGridWidget g, int row, int col, int *firstRow, int *firstCol, XRectangle *rect, Boolean lookLeft, Boolean lookUp) { XmLGridCell cell; int done; done = 0; while (!done) { cell = GetCell(g, row, col); if (!cell) return -1; if (XmLGridCellInRowSpan(cell) == True) { if (lookUp == True) { row--; if (rect) rect->y -= GetRowHeight(g, row); } else row = -1; if (row < 0) done = 1; } else if (XmLGridCellInColumnSpan(cell) == True) { if (lookLeft == True) { col--; if (rect) rect->x -= GetColWidth(g, col); } else col = -1; if (col < 0) done = 1; } else done = 1; } if (row < 0 || col < 0) return -1; *firstRow = row; *firstCol = col; return 0; } static void RowColSpanRect(XmLGridWidget g, int row, int col, XRectangle *rect) { XmLGridCell cell; XmLGridCellRefValues *cellValues; int r, c; cell = GetCell(g, row, col); cellValues = XmLGridCellGetRefValues(cell); rect->width = 0; rect->height = 0; for (r = row; r <= row + cellValues->rowSpan; r++) rect->height += GetRowHeight(g, r); for (c = col; c <= col + cellValues->columnSpan; c++) rect->width += GetColWidth(g, c); } static XmLGridCell GetCell(XmLGridWidget g, int row, int col) { XmLGridRow rowp; rowp = (XmLGridRow)XmLArrayGet(g->grid.rowArray, row); if (!rowp) return 0; return (XmLGridCell)XmLArrayGet(XmLGridRowCells(rowp), col); } static int GetColWidth(XmLGridWidget g, int col) { XmLGridColumn colp; colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, col); if (!colp) return 0; return XmLGridColumnWidthInPixels(colp); } static int GetRowHeight(XmLGridWidget g, int row) { XmLGridRow rowp; rowp = (XmLGridRow)XmLArrayGet(g->grid.rowArray, row); if (!rowp) return 0; return XmLGridRowHeightInPixels(rowp); } static int ColIsVisible(XmLGridWidget g, int col) { XmLGridColumn c; int i, c1, c2; c = (XmLGridColumn)XmLArrayGet(g->grid.colArray, col); if (!c) { XmLWarning((Widget)g, "ColumnIsVisible() - invalid column"); return -1; } if (XmLGridColumnIsHidden(c) == True) return 0; if (g->grid.hsPolicy != XmCONSTANT) return 1; for (i = 0; i < 3; i ++) { c1 = g->grid.reg[i].col; c2 = c1 + g->grid.reg[i].ncol; if (col >= c1 && col < c2) return 1; } return 0; } static int RowIsVisible(XmLGridWidget g, int row) { XmLGridRow r; int i, r1, r2; r = (XmLGridRow)XmLArrayGet(g->grid.rowArray, row); if (!r) { XmLWarning((Widget)g, "RowIsVisible() - invalid row"); return -1; } if (XmLGridRowIsHidden(r) == True) return 0; if (g->grid.vsPolicy != XmCONSTANT) return 1; for (i = 0; i < 9; i += 3) { r1 = g->grid.reg[i].row; r2 = r1 + g->grid.reg[i].nrow; if (row >= r1 && row < r2) return 1; } return 0; } static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *allow) { if (request->request_mode & CWWidth) w->core.width = request->width; if (request->request_mode & CWHeight) w->core.height = request->height; if (request->request_mode & CWX) w->core.x = request->x; if (request->request_mode & CWY) w->core.y = request->y; if (request->request_mode & CWBorderWidth) w->core.border_width = request->border_width; return XtGeometryYes; } static void ScrollCB(Widget w, XtPointer clientData, XtPointer callData) { XmLGridWidget g; XmScrollBarCallbackStruct *cbs; unsigned char orientation; int visPos; g = (XmLGridWidget)(XtParent(w)); cbs = (XmScrollBarCallbackStruct *)callData; visPos = cbs->value; XtVaGetValues(w, XmNorientation, &orientation, NULL); if (orientation == XmHORIZONTAL && g->grid.singleColScrollMode) { g->grid.singleColScrollPos = visPos; DrawArea(g, DrawHScroll, 0, 0); } else if (orientation == XmVERTICAL) { if (visPos == PosToVisPos(g, g->grid.scrollRow, 1)) return; g->grid.scrollRow = VisPosToPos(g, visPos, 1); VertLayout(g, 0); DrawArea(g, DrawVScroll, 0, 0); } else { if (visPos == PosToVisPos(g, g->grid.scrollCol, 0)) return; g->grid.scrollCol = VisPosToPos(g, visPos, 0); HorizLayout(g, 0); DrawArea(g, DrawHScroll, 0, 0); } } static int FindNextFocus(XmLGridWidget g, int row, int col, int rowDir, int colDir, int *nextRow, int *nextCol) { int traverse; int hrc, hcc, rc, cc; XmLGridColumn colp; XmLGridRow rowp; XmLGridCell cell; hcc = g->grid.headingColCount; cc = g->grid.colCount; hrc = g->grid.headingRowCount; rc = g->grid.rowCount; if (!rc || !cc) return -1; if (col < hcc) col = hcc; else if (col >= hcc + cc) col = hcc + cc - 1; if (row < hrc) row = hrc; else if (row >= hrc + rc) row = hrc + rc - 1; traverse = 0; while (1) { if (row < hrc || row >= hrc + rc) break; if (col < hcc || col >= hcc + cc) break; rowp = (XmLGridRow)XmLArrayGet(g->grid.rowArray, row); colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, col); cell = GetCell(g, row, col); if (cell && RowPosToType(g, row) == XmCONTENT && ColPosToType(g, col) == XmCONTENT && XmLGridCellInRowSpan(cell) == False && XmLGridCellInColumnSpan(cell) == False && XmLGridRowIsHidden(rowp) == False && XmLGridColumnIsHidden(colp) == False) { traverse = 1; break; } if (!rowDir && !colDir) break; row += rowDir; col += colDir; } if (!traverse) return -1; *nextRow = row; *nextCol = col; return 0; } static int SetFocus(XmLGridWidget g, int row, int col, int rowDir, int colDir) { if (FindNextFocus(g, row, col, rowDir, colDir, &row, &col) == -1) return -1; ChangeFocus(g, row, col); return 0; } static void ChangeFocus(XmLGridWidget g, int row, int col) { XmLGridCell cell; XmLGridCallbackStruct cbs; int focusRow, focusCol; focusRow = g->grid.focusRow; focusCol = g->grid.focusCol; g->grid.focusRow = row; g->grid.focusCol = col; if (focusRow != -1 && focusCol != -1) { cell = GetCell(g, focusRow, focusCol); if (cell) { if (g->grid.highlightRowMode == True) DrawArea(g, DrawRow, focusRow, 0); else DrawArea(g, DrawCell, focusRow, focusCol); cbs.reason = XmCR_CELL_FOCUS_OUT; cbs.columnType = ColPosToType(g, focusCol); cbs.column = ColPosToTypePos(g, cbs.columnType, focusCol); cbs.rowType = RowPosToType(g, focusRow); cbs.row = RowPosToTypePos(g, cbs.rowType, focusRow); XmLGridCellAction(cell, (Widget)g, &cbs); XtCallCallbackList((Widget)g, g->grid.cellFocusCallback, (XtPointer)&cbs); } } if (row != -1 && col != -1) { cell = GetCell(g, row, col); if (cell) { if (g->grid.highlightRowMode == True) DrawArea(g, DrawRow, row, 0); else DrawArea(g, DrawCell, row, col); cbs.reason = XmCR_CELL_FOCUS_IN; cbs.columnType = ColPosToType(g, col); cbs.column = ColPosToTypePos(g, cbs.columnType, col); cbs.rowType = RowPosToType(g, row); cbs.row = RowPosToTypePos(g, cbs.rowType, row); XmLGridCellAction(cell, (Widget)g, &cbs); XtCallCallbackList((Widget)g, g->grid.cellFocusCallback, (XtPointer)&cbs); } else { if (!XmLArrayGet(g->grid.rowArray, row)) g->grid.focusRow = -1; if (!XmLArrayGet(g->grid.colArray, col)) g->grid.focusCol = -1; } } } static void MakeColVisible(XmLGridWidget g, int col) { int st, width, scrollWidth, scrollCol, prevScrollCol; if (g->grid.hsPolicy != XmCONSTANT) return; if (col < g->grid.leftFixedCount || col >= XmLArrayGetCount(g->grid.colArray) - g->grid.rightFixedCount) return; st = g->manager.shadow_thickness; scrollCol = col; if (col > g->grid.scrollCol) { scrollWidth = g->grid.reg[4].width - st * 2; width = 0; while (1) { width += GetColWidth(g, scrollCol); if (width > scrollWidth) break; if (scrollCol < g->grid.leftFixedCount) break; scrollCol--; } scrollCol++; if (scrollCol > col) scrollCol = col; /* only scroll if needed */ if (scrollCol < g->grid.scrollCol) scrollCol = g->grid.scrollCol; } if (scrollCol == g->grid.scrollCol) return; prevScrollCol = g->grid.scrollCol; g->grid.scrollCol = scrollCol; HorizLayout(g, 0); if (g->grid.scrollCol != prevScrollCol) DrawArea(g, DrawHScroll, 0, 0); } static void MakeRowVisible(XmLGridWidget g, int row) { int st, height, scrollHeight, scrollRow, prevScrollRow; if (g->grid.vsPolicy != XmCONSTANT) return; if (row < g->grid.topFixedCount || row >= XmLArrayGetCount(g->grid.rowArray) - g->grid.bottomFixedCount) return; st = g->manager.shadow_thickness; scrollRow = row; if (row > g->grid.scrollRow) { scrollHeight = g->grid.reg[4].height - st * 2; height = 0; while (1) { height += GetRowHeight(g, scrollRow); if (height > scrollHeight) break; if (scrollRow < g->grid.topFixedCount) break; scrollRow--; } scrollRow++; if (scrollRow > row) scrollRow = row; /* only scroll if needed */ if (scrollRow < g->grid.scrollRow) scrollRow = g->grid.scrollRow; } if (scrollRow == g->grid.scrollRow) return; prevScrollRow = g->grid.scrollRow; g->grid.scrollRow = scrollRow; VertLayout(g, 0); if (g->grid.scrollRow != prevScrollRow) DrawArea(g, DrawVScroll, 0, 0); } static void TextAction(XmLGridWidget g, int action) { int row, col, reason, ret, isVisible; XRectangle rect; XtTranslations trans; WidgetClass wc; XmLGridCell cellp; XmLGridCallbackStruct cbs; if (!g->grid.text || !XtIsRealized(g->grid.text)) return; row = g->grid.focusRow; col = g->grid.focusCol; if (row == -1 || col == -1) return; isVisible = 0; if (RowColToXY(g, row, col, True, &rect) != -1) isVisible = 1; cellp = GetCell(g, row, col); if (!cellp) return; cbs.rowType = XmCONTENT; cbs.row = RowPosToTypePos(g, XmCONTENT, row); cbs.columnType = XmCONTENT; cbs.column = ColPosToTypePos(g, XmCONTENT, col); cbs.clipRect = ▭ switch (action) { case TEXT_EDIT: case TEXT_EDIT_INSERT: { if (g->grid.inEdit || !isVisible) return; g->grid.inEdit = 1; if (action == TEXT_EDIT) cbs.reason = XmCR_EDIT_BEGIN; else cbs.reason = XmCR_EDIT_INSERT; ret = XmLGridCellAction(cellp, (Widget)g, &cbs); if (ret) { reason = cbs.reason; cbs.reason = XmCR_CONF_TEXT; XmLGridCellAction(cellp, (Widget)g, &cbs); cbs.reason = reason; wc = g->grid.text->core.widget_class; trans = (XtTranslations)wc->core_class.tm_table; XtVaSetValues(g->grid.text, XmNtranslations, trans, NULL); XtOverrideTranslations(g->grid.text, g->grid.editTrans); XtMapWidget(g->grid.text); g->grid.textHidden = 0; XtCallCallbackList((Widget)g, g->grid.editCallback, (XtPointer)&cbs); } else g->grid.inEdit = 0; break; } case TEXT_EDIT_CANCEL: case TEXT_EDIT_COMPLETE: { if (!g->grid.inEdit) return; if (action == TEXT_EDIT_COMPLETE) cbs.reason = XmCR_EDIT_COMPLETE; else cbs.reason = XmCR_EDIT_CANCEL; XmLGridCellAction(cellp, (Widget)g, &cbs); wc = g->grid.text->core.widget_class; trans = (XtTranslations)wc->core_class.tm_table; XtVaSetValues(g->grid.text, XmNtranslations, trans, NULL); XtOverrideTranslations(g->grid.text, g->grid.traverseTrans); XtCallCallbackList((Widget)g, g->grid.editCallback, (XtPointer)&cbs); XmTextSetString(g->grid.text, ""); XmTextSetInsertionPosition(g->grid.text, 0); g->grid.inEdit = 0; XtUnmapWidget(g->grid.text); g->grid.textHidden = 1; XtConfigureWidget(g->grid.text, 0, 0, 30, 10, 0); break; } case TEXT_HIDE: { if (g->grid.textHidden || !isVisible) return; XtUnmapWidget(g->grid.text); g->grid.textHidden = 1; break; } case TEXT_SHOW: { if (!g->grid.textHidden || !g->grid.inEdit || !isVisible) return; if (rect.width == 0 || rect.height == 0) TextAction(g, TEXT_EDIT_CANCEL); else { cbs.reason = XmCR_CONF_TEXT; XmLGridCellAction(cellp, (Widget)g, &cbs); XtMapWidget(g->grid.text); g->grid.textHidden = 0; } break; } } } /* Getting and Setting Values */ static void GetSubValues(Widget w, ArgList args, Cardinal *nargs) { XmLGridWidget g; int i, c; long mask; XmLGridRow row; XmLGridColumn col; XmLGridCell cell; g = (XmLGridWidget)w; row = 0; col = 0; for (i = 0; i < *nargs; i++) { if (!args[i].name) continue; if (!strncmp(args[i].name, "row", 3)) { if (!strcmp(args[i].name, XmNrowPtr)) { row = (XmLGridRow)args[i].value; continue; } mask = 0; GetRowValueMask(g, args[i].name, &mask); if (!mask) continue; if (!row) { XmLWarning(w, "GetValues() - invalid row"); continue; } GetRowValue(g, row, args[i].value, mask); } else if (!strncmp(args[i].name, "column", 6)) { if (!strcmp(args[i].name, XmNcolumnPtr)) { col = (XmLGridColumn)args[i].value; continue; } mask = 0; GetColumnValueMask(g, args[i].name, &mask); if (!mask) continue; if (!col) { XmLWarning(w, "GetValues() - invalid column"); continue; } GetColumnValue(g, col, args[i].value, mask); } else if (!strncmp(args[i].name, "cell", 4)) { mask = 0; CellValueGetMask(args[i].name, &mask); if (!mask) continue; if (!row || !col) { XmLWarning(w, "GetValues() - invalid cell"); continue; } c = XmLGridColumnGetPos(col); cell = (XmLGridCell)XmLArrayGet(XmLGridRowCells(row), c); GetCellValue(cell, args[i].value, mask); } } } static void SetSubValues(Widget w, ArgList args, Cardinal *nargs) { XmLGridWidget g; XmLGridRow row; XmLGridColumn col; XmLGridCell cell; XmLGridCellRefValues *values, *newValues, *prevValues; XmLArray cellArray; int r, r1, r2, rowsValid; int c, c1, c2, cd1, cd2, colsValid; unsigned char rowType, colType; long rowMask, colMask, cellMask; int i, nRefValues, allCols; int needsHorizResize, needsVertResize; char buf[256]; newValues = (XmLGridCellRefValues *)NULL; g = (XmLGridWidget)w; needsHorizResize = 0; needsVertResize = 0; rowMask = 0; colMask = 0; cellMask = 0; for (i = 0; i < *nargs; i++) { if (!args[i].name) continue; if (!strncmp(args[i].name, "row", 3)) { if (!strcmp(args[i].name, XmNrowPtr)) XmLWarning(w, "SetValues() - can't use XmNrowPtr"); GetRowValueMask(g, args[i].name, &rowMask); } else if (!strncmp(args[i].name, "column", 6)) { if (!strcmp(args[i].name, XmNcolumnPtr)) XmLWarning(w, "SetValues() - can't use XmNcolumnPtr"); GetColumnValueMask(g, args[i].name, &colMask); } else if (!strncmp(args[i].name, "cell", 4)) CellValueGetMask(args[i].name, &cellMask); else if (rowMask || colMask || cellMask) { sprintf(buf, "SetValues() - %s is not a row/column/cell resource", args[i].name); XmLWarning(w, buf); } } if (rowMask || colMask || cellMask) { if (g->grid.rowType == XmINVALID_TYPE) rowType = XmCONTENT; else rowType = g->grid.rowType; rowsValid = 1; if (g->grid.cellRowRangeStart != -1 && g->grid.cellRowRangeEnd != -1) { r1 = RowTypePosToPos(g, rowType, g->grid.cellRowRangeStart, 0); r2 = RowTypePosToPos(g, rowType, g->grid.cellRowRangeEnd, 0); if (r1 < 0 || r2 < 0 || r1 > r2) rowsValid = 0; r2++; } else if (g->grid.cellRow != -1) { r1 = RowTypePosToPos(g, rowType, g->grid.cellRow, 0); if (r1 == -1) rowsValid = 0; r2 = r1 + 1; } else { r1 = RowTypePosToPos(g, rowType, 0, 0); if (r1 == -1) r1 = 0; r2 = RowTypePosToPos(g, rowType, -1, 1); } if (!rowsValid) { XmLWarning(w, "SetValues() - invalid row(s) specified"); r1 = 0; r2 = 0; } if (g->grid.colType == XmINVALID_TYPE) colType = XmCONTENT; else colType = g->grid.colType; colsValid = 1; if (g->grid.cellColRangeStart != -1 && g->grid.cellColRangeEnd != -1) { c1 = ColTypePosToPos(g, colType, g->grid.cellColRangeStart, 0); c2 = ColTypePosToPos(g, colType, g->grid.cellColRangeEnd, 0); if (c1 < 0 || c2 < 0 || c1 > c2) colsValid = 0; c2++; } else if (g->grid.cellCol != -1) { c1 = ColTypePosToPos(g, colType, g->grid.cellCol, 0); if (c1 == -1) colsValid = 0; c2 = c1 + 1; } else { c1 = ColTypePosToPos(g, colType, 0, 0); if (c1 == -1) c1 = 0; c2 = ColTypePosToPos(g, colType, -1, 1); } if (!colsValid) { XmLWarning(w, "SetValues() - invalid column(s) specified"); c1 = 0; c2 = 0; } if (g->grid.debugLevel) { fprintf(stderr, "XmLGrid: SetValues for rows %d to %d\n", r1, r2); fprintf(stderr, "XmLGrid: & columns %d to %d\n", c1, c2); } if (rowMask) for (r = r1; r < r2; r += g->grid.rowStep) { row = (XmLGridRow)XmLArrayGet(g->grid.rowArray, r); if (!row) continue; if (SetRowValues(g, row, rowMask)) needsVertResize = 1; DrawArea(g, DrawRow, r, 0); } if (colMask) for (c = c1; c < c2; c += g->grid.colStep) { col = (XmLGridColumn)XmLArrayGet(g->grid.colArray, c); if (!col) continue; if (SetColumnValues(g, col, colMask)) needsHorizResize = 1; DrawArea(g, DrawCol, 0, c); } if (cellMask) SetCellValuesPreprocess(g, cellMask); if (cellMask && g->grid.cellDefaults == True) { allCols = 0; if (g->grid.colType == XmINVALID_TYPE && g->grid.cellCol == -1 && g->grid.cellColRangeStart == -1 && g->grid.cellColRangeEnd == -1 && g->grid.colStep == 1) allCols = 1; if (allCols) { /* set cell default values */ newValues = CellRefValuesCreate(g, g->grid.defCellValues); newValues->refCount = 1; SetCellRefValues(g, newValues, cellMask); if (newValues->rowSpan || newValues->columnSpan) { newValues->rowSpan = 0; newValues->columnSpan = 0; XmLWarning((Widget)g, "SetValues() - can't set default cell spans"); } XmLGridCellDerefValues(g->grid.defCellValues); g->grid.defCellValues = newValues; cd1 = 0; cd2 = XmLArrayGetCount(g->grid.colArray); } else { cd1 = c1; cd2 = c2; } /* set column cell default values */ for (c = cd1; c < cd2; c += g->grid.colStep) { col = (XmLGridColumn)XmLArrayGet(g->grid.colArray, c); if (!col) continue; if (allCols && !col->grid.defCellValues) continue; if (col->grid.defCellValues) newValues = CellRefValuesCreate(g, col->grid.defCellValues); else newValues = CellRefValuesCreate(g, g->grid.defCellValues); newValues->refCount = 1; SetCellRefValues(g, newValues, cellMask); if (newValues->rowSpan || newValues->columnSpan) { newValues->rowSpan = 0; newValues->columnSpan = 0; XmLWarning((Widget)g, "SetValues() - can't set default cell spans"); } if (col->grid.defCellValues) XmLGridCellDerefValues(col->grid.defCellValues); col->grid.defCellValues = newValues; } } else if (cellMask) { /* set cell values */ if (SetCellHasRefValues(cellMask)) { cellArray = XmLArrayNew(0, 0); XmLArrayAdd(cellArray, -1, (r2 - r1) * (c2 - c1)); nRefValues = 0; for (r = r1; r < r2; r += g->grid.rowStep) for (c = c1; c < c2; c += g->grid.colStep) { cell = GetCell(g, r, c); if (!cell) continue; SetCellRefValuesPreprocess(g, r, c, cell, cellMask); XmLArraySet(cellArray, nRefValues, cell); nRefValues++; } XmLArraySort(cellArray, SetCellRefValuesCompare, (void *)&cellMask, 0, nRefValues); prevValues = 0; for (i = 0; i < nRefValues; i++) { cell = (XmLGridCell)XmLArrayGet(cellArray, i); values = XmLGridCellGetRefValues(cell); if (values != prevValues) { newValues = CellRefValuesCreate(g, values); SetCellRefValues(g, newValues, cellMask); } XmLGridCellSetRefValues(cell, newValues); prevValues = values; } XmLArrayFree(cellArray); } for (r = r1; r < r2; r += g->grid.rowStep) for (c = c1; c < c2; c += g->grid.colStep) { row = (XmLGridRow)XmLArrayGet(g->grid.rowArray, r); col = (XmLGridColumn)XmLArrayGet(g->grid.colArray, c); cell = GetCell(g, r, c); if (!row || !col || !cell) continue; if (SetCellValuesResize(g, row, col, cell, cellMask)) { needsHorizResize = 1; needsVertResize = 1; } SetCellValues(g, cell, cellMask); if (!needsHorizResize && !needsVertResize) DrawArea(g, DrawCell, r, c); } } } if (needsHorizResize) HorizLayout(g, 1); if (needsVertResize) VertLayout(g, 1); if (needsHorizResize || needsVertResize) DrawArea(g, DrawAll, 0, 0); g->grid.rowType = XmINVALID_TYPE; g->grid.colType = XmINVALID_TYPE; g->grid.rowStep = 1; g->grid.colStep = 1; g->grid.cellRow = -1; g->grid.cellRowRangeStart = -1; g->grid.cellRowRangeEnd = -1; g->grid.cellCol = -1; g->grid.cellColRangeStart = -1; g->grid.cellColRangeEnd = -1; g->grid.cellDefaults = False; } static Boolean SetValues(Widget curW, Widget reqW, Widget newW, ArgList args, Cardinal *nargs) { XmLGridWidget g, cur; int hc, c, fc, hr, r, fr; int tfc, bfc, lfc, rfc; int needsVertLayout, needsHorizLayout, needsRedraw; XmLGridCellRefValues *cellValues; g = (XmLGridWidget)newW; cur = (XmLGridWidget)curW; needsRedraw = 0; needsVertLayout = 0; needsHorizLayout = 0; #define NE(value) (g->value != cur->value) if (NE(grid.cScrollCol)) { g->grid.scrollCol = g->grid.cScrollCol + g->grid.headingColCount; needsHorizLayout = 1; needsRedraw = 1; } if (NE(grid.cScrollRow)) { g->grid.scrollRow = g->grid.cScrollRow + g->grid.headingRowCount; needsVertLayout = 1; needsRedraw = 1; } if (NE(grid.bottomFixedCount) || NE(grid.bottomFixedMargin) || NE(grid.topFixedCount) || NE(grid.topFixedMargin) || NE(grid.vsbDisplayPolicy)) { needsVertLayout = 1; needsRedraw = 1; } if (NE(grid.leftFixedCount) || NE(grid.leftFixedMargin) || NE(grid.rightFixedCount) || NE(grid.rightFixedMargin) || NE(grid.hsbDisplayPolicy)) { needsHorizLayout = 1; needsRedraw = 1; } if (NE(grid.layoutFrozen)) { if (g->grid.layoutFrozen == False) { if (g->grid.needsVertLayout == True) { needsVertLayout = 1; g->grid.needsVertLayout = False; } if (g->grid.needsHorizLayout == True) { needsHorizLayout = 1; g->grid.needsHorizLayout = False; } needsRedraw = 1; } } if (NE(grid.scrollBarMargin) || NE(manager.shadow_thickness) || NE(core.border_width) || NE(grid.vsPolicy) || NE(grid.hsPolicy)) { needsVertLayout = 1; needsHorizLayout = 1; needsRedraw = 1; } if (NE(grid.blankBg) || NE(grid.highlightThickness) || NE(grid.selectBg) || NE(grid.selectFg) || NE(grid.toggleTopColor) || NE(grid.toggleBotColor) || NE(grid.shadowRegions) || NE(grid.shadowType)) needsRedraw = 1; if (NE(grid.fontList)) { XmFontListFree(cur->grid.fontList); CopyFontList(g); cellValues = CellRefValuesCreate(g, g->grid.defCellValues); cellValues->refCount = 1; XmFontListFree(cellValues->fontList); cellValues->fontList = XmFontListCopy(g->grid.fontList); XmLFontListGetDimensions(cellValues->fontList, &cellValues->fontWidth, &cellValues->fontHeight, g->grid.useAvgWidth); XmLGridCellDerefValues(g->grid.defCellValues); g->grid.defCellValues = cellValues; } if (NE(grid.allowDrop)) DropRegister(g, g->grid.allowDrop); if (g->grid.rowStep < 1) { XmLWarning(newW, "SetValues() - rowStep can't be < 1"); g->grid.rowStep = 1; } if (g->grid.colStep < 1) { XmLWarning(newW, "SetValues() - colStep can't be < 1"); g->grid.colStep = 1; } if (NE(grid.hsb) || NE(grid.vsb) || NE(grid.text)) { XmLWarning(newW, "SetValues() - child Widgets are read-only"); g->grid.hsb = cur->grid.hsb; g->grid.vsb = cur->grid.vsb; g->grid.text = cur->grid.text; } if (NE(grid.useTextWidget)) { XmLWarning(newW, "SetValues() - can't set use of text widget"); g->grid.useTextWidget = cur->grid.useTextWidget; } if (NE(grid.hiddenColCount) || NE(grid.hiddenRowCount)) { XmLWarning(newW, "SetValues() - can't set hidden rows or columns"); g->grid.hiddenColCount = cur->grid.hiddenColCount; g->grid.hiddenRowCount = cur->grid.hiddenRowCount; } /* store fixed counts, add/removing rows/columns can change these */ tfc = -1; bfc = -1; lfc = -1; rfc = -1; if (NE(grid.topFixedCount)) tfc = g->grid.topFixedCount; if (NE(grid.bottomFixedCount)) bfc = g->grid.bottomFixedCount; if (NE(grid.leftFixedCount)) lfc = g->grid.leftFixedCount; if (NE(grid.rightFixedCount)) rfc = g->grid.rightFixedCount; g->grid.topFixedCount = cur->grid.topFixedCount; g->grid.bottomFixedCount = cur->grid.bottomFixedCount; g->grid.leftFixedCount = cur->grid.leftFixedCount; g->grid.rightFixedCount = cur->grid.rightFixedCount; hc = g->grid.headingColCount - cur->grid.headingColCount; c = g->grid.colCount - cur->grid.colCount; fc = g->grid.footerColCount - cur->grid.footerColCount; hr = g->grid.headingRowCount - cur->grid.headingRowCount; r = g->grid.rowCount - cur->grid.rowCount; fr = g->grid.footerRowCount - cur->grid.footerRowCount; g->grid.headingColCount = cur->grid.headingColCount; g->grid.colCount = cur->grid.colCount; g->grid.footerColCount = cur->grid.footerColCount; g->grid.headingRowCount = cur->grid.headingRowCount; g->grid.rowCount = cur->grid.rowCount; g->grid.footerRowCount = cur->grid.footerRowCount; if (hc > 0) XmLGridAddColumns((Widget)g, XmHEADING, -1, hc); if (hc < 0) XmLGridDeleteColumns((Widget)g, XmHEADING, g->grid.headingColCount + hc, -(hc)); if (c > 0) XmLGridAddColumns((Widget)g, XmCONTENT, -1, c); if (c < 0) XmLGridDeleteColumns((Widget)g, XmCONTENT, g->grid.colCount + c, -(c)); if (fc > 0) XmLGridAddColumns((Widget)g, XmFOOTER, -1, fc); if (fc < 0) XmLGridDeleteColumns((Widget)g, XmFOOTER, g->grid.footerColCount + fc, -(fc)); if (hr > 0) XmLGridAddRows((Widget)g, XmHEADING, -1, hr); if (hr < 0) XmLGridDeleteRows((Widget)g, XmHEADING, g->grid.headingRowCount + hr, -(hr)); if (r > 0) XmLGridAddRows((Widget)g, XmCONTENT, -1, r); if (r < 0) XmLGridDeleteRows((Widget)g, XmCONTENT, g->grid.rowCount + r, -(r)); if (fr > 0) XmLGridAddRows((Widget)g, XmFOOTER, -1, fr); if (fr < 0) XmLGridDeleteRows((Widget)g, XmFOOTER, g->grid.footerRowCount + fr, -(fr)); /* restore fixed counts if user specified */ if (tfc != -1) g->grid.topFixedCount = tfc; if (bfc != -1) g->grid.bottomFixedCount = bfc; if (lfc != -1) g->grid.leftFixedCount = lfc; if (rfc != -1) g->grid.rightFixedCount = rfc; if (g->grid.topFixedCount < g->grid.headingRowCount) { XmLWarning(newW, "SetValues() - can't set topFixedCount < headingRowCount"); g->grid.topFixedCount = cur->grid.topFixedCount; } if (g->grid.bottomFixedCount < g->grid.footerRowCount) { XmLWarning(newW, "SetValues() - can't set bottomFixedCount < footerRowCount"); g->grid.bottomFixedCount = cur->grid.bottomFixedCount; } if (g->grid.leftFixedCount < g->grid.headingColCount) { XmLWarning(newW, "SetValues() - can't set leftFixedCount < headingColumnCount"); g->grid.leftFixedCount = cur->grid.leftFixedCount; } if (g->grid.rightFixedCount < g->grid.footerColCount) { XmLWarning(newW, "SetValues() - can't set rightFixedCount < footerColumnCount"); g->grid.rightFixedCount = cur->grid.rightFixedCount; } if (NE(grid.simpleHeadings)) { if (cur->grid.simpleHeadings) free((char *)cur->grid.simpleHeadings); if (g->grid.simpleHeadings) { g->grid.simpleHeadings = (char *)strdup(g->grid.simpleHeadings); SetSimpleHeadings(g, g->grid.simpleHeadings); } } if (NE(grid.simpleWidths)) { if (cur->grid.simpleWidths) free((char *)cur->grid.simpleWidths); if (g->grid.simpleWidths) { g->grid.simpleWidths = (char *)strdup(g->grid.simpleWidths); SetSimpleWidths(g, g->grid.simpleWidths); } } if (NE(grid.visibleRows)) { ApplyVisibleRows(g); needsVertLayout = 1; needsRedraw = 1; } if (NE(grid.visibleCols)) { if (g->grid.hsPolicy == XmRESIZE_IF_POSSIBLE) XmLGridSetVisibleColumnCount((Widget)g, g->grid.visibleCols); else ApplyVisibleCols(g); needsHorizLayout = 1; needsRedraw = 1; } /* for the hidden columns stuff */ if (NE(grid.hideUnhideButtons)) { if (g->grid.hideUnhideButtons) { CreateHideUnhideButtons(g); } else { XtDestroyWidget(g->grid.hideButton); XtDestroyWidget(g->grid.unhideButton); g->grid.hideButton = 0; g->grid.unhideButton = 0; } needsVertLayout = 1; needsHorizLayout = 1; needsRedraw = 1; } #undef NE SetSubValues(newW, args, nargs); if (needsVertLayout) VertLayout(g, 1); if (needsHorizLayout) HorizLayout(g, 1); if (needsRedraw) DrawArea(g, DrawAll, 0, 0); return (False); } static void CopyFontList(XmLGridWidget g) { if (!g->grid.fontList) g->grid.fontList = XmLFontListCopyDefault((Widget)g); else g->grid.fontList = XmFontListCopy(g->grid.fontList); if (!g->grid.fontList) XmLWarning((Widget)g, "- fatal error - font list NULL"); } static Boolean CvtStringToSizePolicy(Display *dpy, XrmValuePtr args, Cardinal *narg, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data) { static XmLStringToUCharMap map[] = { { "CONSTANT", XmCONSTANT }, { "VARIABLE", XmVARIABLE }, { "RESIZE_IF_POSSIBLE", XmRESIZE_IF_POSSIBLE }, { 0, 0 }, }; return XmLCvtStringToUChar(dpy, "XmRGridSizePolicy", map, fromVal, toVal); } static Boolean CvtStringToRowColType(Display *dpy, XrmValuePtr args, Cardinal *narg, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data) { static XmLStringToUCharMap map[] = { { "HEADING", XmHEADING }, { "CONTENT", XmCONTENT }, { "FOOTER", XmFOOTER }, { "ALL_TYPES", XmALL_TYPES }, { 0, 0 }, }; return XmLCvtStringToUChar(dpy, "XmRRowColType", map, fromVal, toVal); } static Boolean CvtStringToSelectionPolicy(Display *dpy, XrmValuePtr args, Cardinal *narg, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data) { static XmLStringToUCharMap map[] = { { "SELECT_NONE", XmSELECT_NONE }, { "SELECT_SINGLE_ROW", XmSELECT_SINGLE_ROW }, { "SELECT_BROWSE_ROW", XmSELECT_BROWSE_ROW }, { "SELECT_MULTIPLE_ROW", XmSELECT_MULTIPLE_ROW }, { "SELECT_CELL", XmSELECT_CELL }, { 0, 0 }, }; return XmLCvtStringToUChar(dpy, "XmRGridSelectionPolicy", map, fromVal, toVal); } static Boolean CvtStringToCellAlignment(Display *dpy, XrmValuePtr args, Cardinal *narg, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data) { static XmLStringToUCharMap map[] = { { "ALIGNMENT_LEFT", XmALIGNMENT_LEFT }, { "ALIGNMENT_CENTER", XmALIGNMENT_CENTER }, { "ALIGNMENT_RIGHT", XmALIGNMENT_RIGHT }, { "ALIGNMENT_TOP_LEFT", XmALIGNMENT_TOP_LEFT }, { "ALIGNMENT_TOP", XmALIGNMENT_TOP }, { "ALIGNMENT_TOP_RIGHT", XmALIGNMENT_TOP_RIGHT }, { "ALIGNMENT_BOTTOM_LEFT", XmALIGNMENT_BOTTOM_LEFT }, { "ALIGNMENT_BOTTOM", XmALIGNMENT_BOTTOM }, { "ALIGNMENT_BOTTOM_RIGHT", XmALIGNMENT_BOTTOM_RIGHT }, { 0, 0 }, }; return XmLCvtStringToUChar(dpy, "XmRGridCellAlignment", map, fromVal, toVal); } static Boolean CvtStringToCellBorderType(Display *dpy, XrmValuePtr args, Cardinal *narg, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data) { static XmLStringToUCharMap map[] = { { "BORDER_NONE", XmBORDER_NONE }, { "BORDER_LINE", XmBORDER_LINE }, { "BORDER_DASH", XmBORDER_DASH }, { 0, 0 }, }; return XmLCvtStringToUChar(dpy, "XmRGridCellBorderType", map, fromVal, toVal); } static Boolean CvtStringToCellType(Display *dpy, XrmValuePtr args, Cardinal *narg, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data) { static XmLStringToUCharMap map[] = { { "ICON_CELL", XmICON_CELL }, { "STRING_CELL", XmSTRING_CELL }, { "PIXMAP_CELL", XmPIXMAP_CELL }, { "TOGGLE_CELL", XmTOGGLE_CELL }, { 0, 0 }, }; return XmLCvtStringToUChar(dpy, "XmRGridCellType", map, fromVal, toVal); } static void SetSimpleHeadings(XmLGridWidget g, char *data) { char *c; int n, count; if (!data || !*data) return; c = data; n = 1; while (*c) { if (*c == '|') n++; c++; } count = XmLArrayGetCount(g->grid.colArray); if (n > count) { XmLWarning((Widget)g, "SetSimpleHeadings() - headings given for non-existing columns"); return; } if (g->grid.headingRowCount < 1) { XmLWarning((Widget)g, "SetSimpleHeadings() - no heading row exists"); return; } XmLGridSetStrings((Widget)g, data); } static void SetSimpleWidths(XmLGridWidget g, char *data) { XmLGridColumn colp; int i, n, colCount, valid; Dimension prevWidth; unsigned char prevSizePolicy; long mask; struct WidthRec { Dimension width; unsigned char sizePolicy; } *widths; if (!data) return; i = ((int)strlen(data) / 2) + 1; widths = (struct WidthRec *)malloc(i * sizeof(struct WidthRec)); valid = 1; n = 0; while (*data) { if (*data >= '0' && *data <= '9') { widths[n].width = atoi(data); while (*data >= '0' && *data <= '9') data++; } else { valid = 0; break; } if (*data == 'c' || *data == 'C') { widths[n].sizePolicy = XmVARIABLE; data++; } else if (*data == 'p' || *data == 'P') { widths[n].sizePolicy = XmCONSTANT; data++; } else { valid = 0; break; } while (*data == ' ') data++; n++; } if (!valid) { free((char *)widths); XmLWarning((Widget)g, "SetSimpleWidths() - invalid widths string"); return; } colCount = XmLArrayGetCount(g->grid.colArray); if (n > colCount) { free((char *)widths); XmLWarning((Widget)g, "SetSimpleWidths() - widths given for non-existing columns"); return; } prevWidth = g->grid.colWidth; prevSizePolicy = g->grid.colSizePolicy; for (i = 0; i < n; i++) { colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, i); if (!colp) continue; GetColumnValueMask(g, XmNcolumnWidth, &mask); GetColumnValueMask(g, XmNcolumnSizePolicy, &mask); g->grid.colWidth = widths[i].width; g->grid.colSizePolicy = widths[i].sizePolicy; SetColumnValues(g, colp, mask); } free((char *)widths); g->grid.colWidth = prevWidth; g->grid.colSizePolicy = prevSizePolicy; HorizLayout(g, 1); DrawArea(g, DrawAll, 0, 0); } /* Getting and Setting Row Values */ static void GetRowValueMask(XmLGridWidget g, char *s, long *mask) { XmLGridClassPartOfWidget(g).getRowValueMaskProc(g, s, mask); } /* Only to be called through Grid class */ static void _GetRowValueMask(XmLGridWidget g, char *s, long *mask) { static XrmQuark qHeight, qSizePolicy, qUserData; static int quarksValid = 0; XrmQuark q; if (!quarksValid) { qHeight = XrmStringToQuark(XmNrowHeight); qSizePolicy = XrmStringToQuark(XmNrowSizePolicy); qUserData = XrmStringToQuark(XmNrowUserData); quarksValid = 1; } q = XrmStringToQuark(s); if (q == qHeight) *mask |= XmLGridRowHeight; else if (q == qSizePolicy) *mask |= XmLGridRowSizePolicy; else if (q == qUserData) *mask |= XmLGridRowUserData; } static void GetRowValue(XmLGridWidget g, XmLGridRow row, XtArgVal value, long mask) { XmLGridClassPartOfWidget(g).getRowValueProc(g, row, value, mask); } /* Only to be called through Grid class */ static void _GetRowValue(XmLGridWidget g, XmLGridRow row, XtArgVal value, long mask) { switch (mask) { case XmLGridRowHeight: *((Dimension *)value) = row->grid.height; break; case XmLGridRowSizePolicy: *((unsigned char *)value) = row->grid.sizePolicy; break; case XmLGridRowUserData: *((XtPointer *)value) = (XtPointer)row->grid.userData; break; } } static int SetRowValues(XmLGridWidget g, XmLGridRow row, long mask) { return XmLGridClassPartOfWidget(g).setRowValuesProc(g, row, mask); } /* Only to be called through Grid class */ static int _SetRowValues(XmLGridWidget g, XmLGridRow row, long mask) { int needsResize = 0, visible = 0; Boolean newIsHidden; if (mask & XmLGridRowHeight || mask & XmLGridRowSizePolicy) { visible = RowIsVisible(g, XmLGridRowGetPos(row)); XmLGridRowHeightChanged(row); } if (mask & XmLGridRowHeight) { if (g->grid.rowHeight > 0) newIsHidden = False; else newIsHidden = True; if (XmLGridRowIsHidden(row) != newIsHidden) { if (newIsHidden == True) g->grid.hiddenRowCount++; else g->grid.hiddenRowCount--; VisPosChanged(g, 1); needsResize = 1; } if (visible && !g->grid.inResize) needsResize = 1; row->grid.height = g->grid.rowHeight; } if (mask & XmLGridRowSizePolicy) { row->grid.sizePolicy = g->grid.rowSizePolicy; if (visible && !g->grid.inResize) needsResize = 1; } if (mask & XmLGridRowUserData) row->grid.userData = g->grid.rowUserData; return needsResize; } /* Getting and Setting Column Values */ static void GetColumnValueMask(XmLGridWidget g, char *s, long *mask) { XmLGridClassPartOfWidget(g).getColumnValueMaskProc(g, s, mask); } /* Only to be called through Grid class */ static void _GetColumnValueMask(XmLGridWidget g, char *s, long *mask) { static XrmQuark qWidth, qSizePolicy, qUserData, qResizable; static XrmQuark qHidden, qSortType; static int quarksValid = 0; XrmQuark q; if (!quarksValid) { qWidth = XrmStringToQuark(XmNcolumnWidth); qSizePolicy = XrmStringToQuark(XmNcolumnSizePolicy); qUserData = XrmStringToQuark(XmNcolumnUserData); qResizable = XrmStringToQuark(XmNcolumnResizable); qHidden = XrmStringToQuark(XmNcolumnHidden); qSortType = XrmStringToQuark(XmNcolumnSortType); quarksValid = 1; } q = XrmStringToQuark(s); if (q == qWidth) *mask |= XmLGridColumnWidth; else if (q == qSizePolicy) *mask |= XmLGridColumnSizePolicy; else if (q == qUserData) *mask |= XmLGridColumnUserData; else if (q == qResizable) *mask |= XmLGridColumnResizable; else if (q == qHidden) *mask |= XmLGridColumnHidden; else if (q == qSortType) *mask |= XmLGridColumnSortType; } static void GetColumnValue(XmLGridWidget g, XmLGridColumn col, XtArgVal value, long mask) { XmLGridClassPartOfWidget(g).getColumnValueProc(g, col, value, mask); } /* Only to be called through Grid class */ static void _GetColumnValue(XmLGridWidget g, XmLGridColumn col, XtArgVal value, long mask) { switch (mask) { case XmLGridColumnWidth: *((Dimension *)value) = col->grid.width; break; case XmLGridColumnSizePolicy: *((unsigned char *)value) = col->grid.sizePolicy; break; case XmLGridColumnUserData: *((XtPointer *)value) = col->grid.userData; break; case XmLGridColumnResizable: *((Boolean *)value) = col->grid.resizable; break; case XmLGridColumnHidden: *((Boolean *)value) = col->grid.hidden; break; case XmLGridColumnSortType: *((unsigned char *)value) = col->grid.sort; break; } } static int SetColumnValues(XmLGridWidget g, XmLGridColumn col, long mask) { return XmLGridClassPartOfWidget(g).setColumnValuesProc(g, col, mask); } /* Only to be called through Grid class */ static int _SetColumnValues(XmLGridWidget g, XmLGridColumn col, long mask) { int needsResize = 0, visible = 0; Boolean newIsHidden; if (mask & XmLGridColumnWidth || mask & XmLGridColumnSizePolicy) { visible = ColIsVisible(g, XmLGridColumnGetPos(col)); XmLGridColumnWidthChanged(col); } if (mask & XmLGridColumnWidth) { if (g->grid.colWidth > 0) newIsHidden = False; else newIsHidden = True; if (XmLGridColumnIsHidden(col) != newIsHidden) { if (newIsHidden == True) g->grid.hiddenColCount++; else g->grid.hiddenRowCount--; VisPosChanged(g, 0); needsResize = 1; } if (visible && !g->grid.inResize) needsResize = 1; col->grid.width = g->grid.colWidth; } if (mask & XmLGridColumnSizePolicy) { col->grid.sizePolicy = g->grid.colSizePolicy; if (visible && !g->grid.inResize) needsResize = 1; if (col->grid.sizePolicy != XmCONSTANT && g->grid.hsPolicy == XmRESIZE_IF_POSSIBLE) { XmLWarning((Widget)g, "XmNcolumnSizePolicy must equal XmCONSTANT"); } } if (mask & XmLGridColumnUserData) col->grid.userData = g->grid.colUserData; if (mask & XmLGridColumnResizable) col->grid.resizable = g->grid.colResizable; if (mask & XmLGridColumnHidden) col->grid.hidden = g->grid.colHidden; if (mask & XmLGridColumnSortType) XmLGridSetSort((Widget)g, XmLGridColumnGetPos(col), g->grid.colSortType); return needsResize; } /* Getting and Setting Cell Values */ static void CellValueGetMask(char *s, long *mask) { static XrmQuark qAlignment, qBackground, qBottomBorderColor; static XrmQuark qBottomBorderType, qColumnSpan; static XrmQuark qEditable, qFontList, qForeground; static XrmQuark qLeftBorderColor, qLeftBorderType; static XrmQuark qMarginBottom, qMarginLeft, qMarginRight; static XrmQuark qMarginTop, qPixmap, qPixmapMask; static XrmQuark qRightBorderColor, qRightBorderType; static XrmQuark qRowSpan, qString, qToggleSet; static XrmQuark qTopBorderColor, qTopBorderType, qType; static XrmQuark qUserData; static int quarksValid = 0; XrmQuark q; if (!quarksValid) { qAlignment = XrmStringToQuark(XmNcellAlignment); qBackground = XrmStringToQuark(XmNcellBackground); qBottomBorderColor = XrmStringToQuark(XmNcellBottomBorderColor); qBottomBorderType = XrmStringToQuark(XmNcellBottomBorderType); qColumnSpan = XrmStringToQuark(XmNcellColumnSpan); qEditable = XrmStringToQuark(XmNcellEditable); qFontList = XrmStringToQuark(XmNcellFontList); qForeground = XrmStringToQuark(XmNcellForeground); qLeftBorderColor = XrmStringToQuark(XmNcellLeftBorderColor); qLeftBorderType = XrmStringToQuark(XmNcellLeftBorderType); qMarginBottom = XrmStringToQuark(XmNcellMarginBottom); qMarginLeft = XrmStringToQuark(XmNcellMarginLeft); qMarginRight = XrmStringToQuark(XmNcellMarginRight); qMarginTop= XrmStringToQuark(XmNcellMarginTop); qPixmap = XrmStringToQuark(XmNcellPixmap); qPixmapMask = XrmStringToQuark(XmNcellPixmapMask); qRightBorderColor = XrmStringToQuark(XmNcellRightBorderColor); qRightBorderType = XrmStringToQuark(XmNcellRightBorderType); qRowSpan = XrmStringToQuark(XmNcellRowSpan); qString = XrmStringToQuark(XmNcellString); qToggleSet = XrmStringToQuark(XmNcellToggleSet); qTopBorderColor = XrmStringToQuark(XmNcellTopBorderColor); qTopBorderType = XrmStringToQuark(XmNcellTopBorderType); qType = XrmStringToQuark(XmNcellType); qUserData = XrmStringToQuark(XmNcellUserData); quarksValid = 1; } q = XrmStringToQuark(s); if (q == qAlignment) *mask |= XmLGridCellAlignment; else if (q == qBackground) *mask |= XmLGridCellBackground; else if (q == qBottomBorderColor) *mask |= XmLGridCellBottomBorderColor; else if (q == qBottomBorderType) *mask |= XmLGridCellBottomBorderType; else if (q == qColumnSpan) *mask |= XmLGridCellColumnSpan; else if (q == qEditable) *mask |= XmLGridCellEditable; else if (q == qFontList) *mask |= XmLGridCellFontList; else if (q == qForeground) *mask |= XmLGridCellForeground; else if (q == qLeftBorderColor) *mask |= XmLGridCellLeftBorderColor; else if (q == qLeftBorderType) *mask |= XmLGridCellLeftBorderType; else if (q == qMarginBottom) *mask |= XmLGridCellMarginBottom; else if (q == qMarginLeft) *mask |= XmLGridCellMarginLeft; else if (q == qMarginRight) *mask |= XmLGridCellMarginRight; else if (q == qMarginTop) *mask |= XmLGridCellMarginTop; else if (q == qPixmap) *mask |= XmLGridCellPixmapF; else if (q == qPixmapMask) *mask |= XmLGridCellPixmapMask; else if (q == qRightBorderColor) *mask |= XmLGridCellRightBorderColor; else if (q == qRightBorderType) *mask |= XmLGridCellRightBorderType; else if (q == qRowSpan) *mask |= XmLGridCellRowSpan; else if (q == qString) *mask |= XmLGridCellString; else if (q == qToggleSet) *mask |= XmLGridCellToggleSet; else if (q == qTopBorderColor) *mask |= XmLGridCellTopBorderColor; else if (q == qTopBorderType) *mask |= XmLGridCellTopBorderType; else if (q == qType) *mask |= XmLGridCellType; else if (q == qUserData) *mask |= XmLGridCellUserData; } static void GetCellValue(XmLGridCell cell, XtArgVal value, long mask) { XmLGridCellRefValues *values; XmLGridCellPixmap *pix; XmString str; values = XmLGridCellGetRefValues(cell); switch (mask) { case XmLGridCellAlignment: *((unsigned char *)value) = values->alignment; break; case XmLGridCellBackground: *((Pixel *)value) = values->background; break; case XmLGridCellBottomBorderColor: *((Pixel *)value) = values->bottomBorderColor; break; case XmLGridCellBottomBorderType: *((unsigned char *)value) = values->bottomBorderType; break; case XmLGridCellColumnSpan: *((int *)value) = values->columnSpan; break; case XmLGridCellEditable: *((Boolean *)value) = values->editable; break; case XmLGridCellFontList: *((XmFontList *)value) = values->fontList; break; case XmLGridCellForeground: *((Pixel *)value) = values->foreground; break; case XmLGridCellLeftBorderColor: *((Pixel *)value) = values->leftBorderColor; break; case XmLGridCellLeftBorderType: *((unsigned char *)value) = values->leftBorderType; break; case XmLGridCellMarginBottom: *((Dimension *)value) = values->bottomMargin; break; case XmLGridCellMarginLeft: *((Dimension *)value) = values->leftMargin; break; case XmLGridCellMarginRight: *((Dimension *)value) = values->rightMargin; break; case XmLGridCellMarginTop: *((Dimension *)value) = values->topMargin; break; case XmLGridCellPixmapF: pix = XmLGridCellGetPixmap(cell); if (pix) *((Pixmap *)value) = pix->pixmap; else *((Pixmap *)value) = (Pixmap)XmUNSPECIFIED_PIXMAP; break; case XmLGridCellPixmapMask: pix = XmLGridCellGetPixmap(cell); if (pix) *((Pixmap *)value) = pix->pixmask; else *((Pixmap *)value) = (Pixmap)XmUNSPECIFIED_PIXMAP; break; case XmLGridCellRightBorderColor: *((Pixel *)value) = values->rightBorderColor; break; case XmLGridCellRightBorderType: *((unsigned char *)value) = values->rightBorderType; break; case XmLGridCellRowSpan: *((int *)value) = values->rowSpan; break; case XmLGridCellString: str = XmLGridCellGetString(cell); if (str) *((XmString *)value) = XmStringCopy(str); else *((XmString *)value) = 0; break; case XmLGridCellToggleSet: *((Boolean *)value) = XmLGridCellGetToggle(cell); break; case XmLGridCellTopBorderColor: *((Pixel *)value) = values->topBorderColor; break; case XmLGridCellTopBorderType: *((unsigned char *)value) = values->topBorderType; break; case XmLGridCellType: *((unsigned char *)value) = values->type; break; case XmLGridCellUserData: *((XtPointer *)value) = (XtPointer)values->userData; break; } } static XmLGridCellRefValues * CellRefValuesCreate(XmLGridWidget g, XmLGridCellRefValues *copy) { short width, height; XmLGridCellRefValues *values; values = (XmLGridCellRefValues *)malloc(sizeof(XmLGridCellRefValues)); if (!copy) { /* default values */ values->bottomBorderType = XmBORDER_LINE; values->leftBorderType = XmBORDER_LINE; values->rightBorderType = XmBORDER_LINE; values->topBorderType = XmBORDER_LINE; XmLFontListGetDimensions(g->grid.fontList, &width, &height, g->grid.useAvgWidth); values->alignment = XmALIGNMENT_CENTER; values->background = g->core.background_pixel; values->bottomBorderColor = g->manager.bottom_shadow_color; values->bottomMargin = 0; values->columnSpan = 0; values->editable = False; values->fontHeight = height; values->fontList = XmFontListCopy(g->grid.fontList); values->fontWidth = width; values->foreground = g->manager.foreground; values->leftBorderColor = g->manager.top_shadow_color; values->leftMargin = 0; values->refCount = 0; values->rightBorderColor = g->manager.bottom_shadow_color; values->rightMargin = 0; values->rowSpan = 0; values->topBorderColor = g->manager.top_shadow_color; values->topMargin = 0; values->type = XmSTRING_CELL; values->userData = 0; } else { /* copy values */ *values = *copy; values->fontList = XmFontListCopy(copy->fontList); values->refCount = 0; } return values; } static void SetCellValuesPreprocess(XmLGridWidget g, long mask) { XmLGridCellRefValues *newValues; int x, y; short width, height; Display *dpy; Window pixRoot; unsigned int pixWidth, pixHeight; unsigned int pixBW, pixDepth; /* calculate font width and height if set */ newValues = &g->grid.cellValues; if (mask & XmLGridCellFontList) { XmLFontListGetDimensions(newValues->fontList, &width, &height, g->grid.useAvgWidth); newValues->fontWidth = width; newValues->fontHeight = height; } if (mask & XmLGridCellPixmapF) { if (g->grid.cellPixmap != XmUNSPECIFIED_PIXMAP && g->grid.globalPixmapWidth && g->grid.globalPixmapHeight) { g->grid.cellPixmapWidth = g->grid.globalPixmapWidth; g->grid.cellPixmapHeight = g->grid.globalPixmapHeight; } else if (g->grid.cellPixmap != XmUNSPECIFIED_PIXMAP) { dpy = XtDisplay(g); XGetGeometry(dpy, g->grid.cellPixmap, &pixRoot, &x, &y, &pixWidth, &pixHeight, &pixBW, &pixDepth); g->grid.cellPixmapWidth = (Dimension)pixWidth; g->grid.cellPixmapHeight = (Dimension)pixHeight; } else { g->grid.cellPixmapWidth = 0; g->grid.cellPixmapHeight = 0; } } } static int SetCellHasRefValues(long mask) { long unrefMask; /* return 1 if mask contains any reference counted values */ unrefMask = XmLGridCellPixmapF | XmLGridCellPixmapMask | XmLGridCellString | XmLGridCellToggleSet; mask = mask | unrefMask; mask = mask ^ unrefMask; if (!mask) return 0; return 1; } static int SetCellValuesResize(XmLGridWidget g, XmLGridRow row, XmLGridColumn col, XmLGridCell cell, long mask) { return XmLGridClassPartOfWidget(g).setCellValuesResizeProc(g, row, col, cell, mask); } static int _SetCellValuesResize(XmLGridWidget g, XmLGridRow row, XmLGridColumn col, XmLGridCell cell, long mask) { XmLGridCellPixmap *cellPix; int pixResize, needsResize, rowVisible, colVisible; needsResize = 0; pixResize = 0; if (mask & XmLGridCellPixmapF) { pixResize = 1; if (!(mask & XmLGridCellType)) { /* no resize needed if we replace with an equal size pixmap */ cellPix = XmLGridCellGetPixmap(cell); if (cellPix && cellPix->pixmap != XmUNSPECIFIED_PIXMAP && g->grid.cellPixmap != XmUNSPECIFIED_PIXMAP) { if (cellPix->width == g->grid.cellPixmapWidth && cellPix->height == g->grid.cellPixmapHeight) pixResize = 0; } } } if (mask & XmLGridCellType || mask & XmLGridCellFontList || pixResize || mask & XmLGridCellRowSpan || mask & XmLGridCellColumnSpan || mask & XmLGridCellMarginLeft || mask & XmLGridCellMarginRight || mask & XmLGridCellMarginTop || mask & XmLGridCellMarginBottom) { XmLGridRowHeightChanged(row); XmLGridColumnWidthChanged(col); rowVisible = RowIsVisible(g, XmLGridRowGetPos(row)); colVisible = ColIsVisible(g, XmLGridColumnGetPos(col)); if (rowVisible | colVisible) needsResize = 1; } return needsResize; } static void SetCellValues(XmLGridWidget g, XmLGridCell cell, long mask) { /* set non-reference counted cell values */ if (mask & XmLGridCellPixmapF) XmLGridCellSetPixmap(cell, g->grid.cellPixmap, g->grid.cellPixmapWidth, g->grid.cellPixmapHeight); if (mask & XmLGridCellPixmapMask) XmLGridCellSetPixmask(cell, g->grid.cellPixmapMask); if (mask & XmLGridCellString) XmLGridCellSetString(cell, g->grid.cellString, True); if (mask & XmLGridCellToggleSet) XmLGridCellSetToggle(cell, g->grid.cellToggleSet); } static void SetCellRefValues(XmLGridWidget g, XmLGridCellRefValues *values, long mask) { XmLGridCellRefValues *newValues; /* set reference counted cell values */ newValues = &g->grid.cellValues; if (mask & XmLGridCellAlignment) values->alignment = newValues->alignment; if (mask & XmLGridCellBackground) values->background = newValues->background; if (mask & XmLGridCellBottomBorderColor) values->bottomBorderColor = newValues->bottomBorderColor; if (mask & XmLGridCellBottomBorderType) values->bottomBorderType = newValues->bottomBorderType; if (mask & XmLGridCellColumnSpan) values->columnSpan = newValues->columnSpan; if (mask & XmLGridCellEditable) values->editable = newValues->editable; if (mask & XmLGridCellFontList) { XmFontListFree(values->fontList); values->fontList = XmFontListCopy(newValues->fontList); values->fontWidth = newValues->fontWidth; values->fontHeight = newValues->fontHeight; } if (mask & XmLGridCellForeground) values->foreground = newValues->foreground; if (mask & XmLGridCellLeftBorderColor) values->leftBorderColor = newValues->leftBorderColor; if (mask & XmLGridCellLeftBorderType) values->leftBorderType = newValues->leftBorderType; if (mask & XmLGridCellRightBorderColor) values->rightBorderColor = newValues->rightBorderColor; if (mask & XmLGridCellRightBorderType) values->rightBorderType = newValues->rightBorderType; if (mask & XmLGridCellMarginBottom) values->bottomMargin = newValues->bottomMargin; if (mask & XmLGridCellMarginLeft) values->leftMargin = newValues->leftMargin; if (mask & XmLGridCellMarginRight) values->rightMargin = newValues->rightMargin; if (mask & XmLGridCellMarginTop) values->topMargin = newValues->topMargin; if (mask & XmLGridCellRowSpan) values->rowSpan = newValues->rowSpan; if (mask & XmLGridCellTopBorderColor) values->topBorderColor = newValues->topBorderColor; if (mask & XmLGridCellTopBorderType) values->topBorderType = newValues->topBorderType; if (mask & XmLGridCellType) { values->type = newValues->type; /* backwards compatibility cell types */ if (values->type == XmLABEL_CELL) { values->type = XmSTRING_CELL; values->editable = False; } else if (values->type == XmTEXT_CELL) { values->type = XmSTRING_CELL; values->editable = True; } } if (mask & XmLGridCellUserData) values->userData = newValues->userData; } static int SetCellRefValuesCompare(void *userData, void **item1, void **item2) { XmLGridCell cell1, cell2; XmLGridCellRefValues *values1, *values2; long mask; mask = *((long *)userData); cell1 = (XmLGridCell)*item1; cell2 = (XmLGridCell)*item2; values1 = XmLGridCellGetRefValues(cell1); values2 = XmLGridCellGetRefValues(cell2); if (values1 == values2) return 0; #define RVCOMPARE(res, var) \ if (!(mask & res)) \ { \ if (values1->var < values2->var) \ return -1; \ if (values1->var > values2->var) \ return 1; \ } RVCOMPARE(XmLGridCellAlignment, alignment) RVCOMPARE(XmLGridCellBackground, background) RVCOMPARE(XmLGridCellBottomBorderColor, bottomBorderColor) RVCOMPARE(XmLGridCellBottomBorderType, bottomBorderType) RVCOMPARE(XmLGridCellColumnSpan, columnSpan) RVCOMPARE(XmLGridCellEditable, editable) RVCOMPARE(XmLGridCellFontList, fontList) RVCOMPARE(XmLGridCellForeground, foreground) RVCOMPARE(XmLGridCellLeftBorderColor, leftBorderColor) RVCOMPARE(XmLGridCellLeftBorderType, leftBorderType) RVCOMPARE(XmLGridCellMarginBottom, bottomMargin) RVCOMPARE(XmLGridCellMarginLeft, leftMargin) RVCOMPARE(XmLGridCellMarginRight, rightMargin) RVCOMPARE(XmLGridCellMarginTop, topMargin) RVCOMPARE(XmLGridCellRightBorderColor, rightBorderColor) RVCOMPARE(XmLGridCellRightBorderType, rightBorderType) RVCOMPARE(XmLGridCellRowSpan, rowSpan) RVCOMPARE(XmLGridCellTopBorderColor, topBorderColor) RVCOMPARE(XmLGridCellTopBorderType, topBorderType) RVCOMPARE(XmLGridCellType, type) RVCOMPARE(XmLGridCellUserData, userData) #undef RVCOMPARE /* If the two cell values are equal, we merge them into one record here. This speeds up the sort and will allow the merge to compare just the values pointers to test equality. Note that this will not merge every possible item that could be merged, we don't want to do that because of the performance impact */ if (values1 < values2) XmLGridCellSetRefValues(cell1, values2); else XmLGridCellSetRefValues(cell2, values1); return 0; } static void SetCellRefValuesPreprocess(XmLGridWidget g, int row, int col, XmLGridCell cell, long mask) { int r, c, rowSpan, colSpan; XmLGridCell spanCell; XmLGridCellRefValues *oldValues, *newValues; unsigned char oldType, newType; XmLGridCallbackStruct cbs; if (mask & XmLGridCellType) { oldType = XmLGridCellGetRefValues(cell)->type; newType = g->grid.cellValues.type; if (oldType != newType) { cbs.reason = XmCR_FREE_VALUE; XmLGridCellAction(cell, (Widget)g, &cbs); } } if (mask & XmLGridCellRowSpan || mask & XmLGridCellColumnSpan) { /* expose old cell area in case the span area shrinks */ DrawArea(g, DrawCell, row, col); oldValues = XmLGridCellGetRefValues(cell); newValues = &g->grid.cellValues; if (mask & XmLGridCellRowSpan) { g->grid.mayHaveRowSpans = 1; if (newValues->rowSpan < 0) { XmLWarning((Widget)g, "SetValues() - row span can't be < 0"); newValues->rowSpan = 0; } rowSpan = newValues->rowSpan; } else rowSpan = oldValues->rowSpan; if (mask & XmLGridCellColumnSpan) { if (newValues->columnSpan < 0) { XmLWarning((Widget)g, "SetValues() - column span can't be < 0"); newValues->columnSpan = 0; } colSpan = newValues->columnSpan; } else colSpan = oldValues->columnSpan; /* clear old span */ for (c = col; c <= col + oldValues->columnSpan; c++) for (r = row; r <= row + oldValues->rowSpan; r++) { /* skip the cell itself */ if (c == col && r == row) continue; spanCell = GetCell(g, r, c); if (!spanCell) continue; XmLGridCellSetInRowSpan(spanCell, False); XmLGridCellSetInColumnSpan(spanCell, False); } /* set new span */ for (c = col; c <= col + colSpan; c++) for (r = row; r <= row + rowSpan; r++) { /* skip the cell itself */ if (c == col && r == row) continue; spanCell = GetCell(g, r, c); if (!spanCell) continue; if (r == row) XmLGridCellSetInColumnSpan(spanCell, True); else XmLGridCellSetInRowSpan(spanCell, True); } } } /* Read, Write, Copy, Paste */ static int Read(XmLGridWidget g, int format, char delimiter, int row, int col, char *data) { char *c1, *c2, buf[256], *bufp; int r, c, i, j, len, n, needsResize, allowSet, done; XmString str; XmLGridCell cell; XmLGridRow rowp; XmLGridColumn colp; XmLGridCellRefValues *cellValues; XmLGridCallbackStruct cbs; if (format == XmFORMAT_PAD) { XmLWarning((Widget)g, "Read() - FORMAT_PAD not supported"); return 0; } if (format == XmFORMAT_XL || format == XmFORMAT_DROP || format == XmFORMAT_PASTE) delimiter = '\t'; c1 = data; c2 = data; r = row; c = col; needsResize = 0; done = 0; n = 0; while (!done) { if (!(*c2) || *c2 == delimiter || *c2 == '\n') { len = c2 - c1; if (len < 256) bufp = buf; else bufp = (char *)malloc(len + 1); if (format == XmFORMAT_XL) { /* strip leading and trailing double-quotes */ if (len && c1[0] == '"') { c1++; len--; } if (len && c1[len - 1] == '"') len--; } j = 0; for (i = 0; i < len; i++) { if (c1[0] == '\\' && c1[1] == 'n') { bufp[j++] = '\n'; c1 += 2; i++; } else bufp[j++] = *c1++; } bufp[j] = 0; j = 0; str = XmStringCreateLtoR(bufp, XmSTRING_DEFAULT_CHARSET); if (bufp != buf) free((char *)bufp); rowp = (XmLGridRow)XmLArrayGet(g->grid.rowArray, r); colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, c); cell = GetCell(g, r, c); allowSet = 1; if (cell && (format == XmFORMAT_PASTE || format == XmFORMAT_DROP)) { cellValues = XmLGridCellGetRefValues(cell); if (cellValues->type != XmSTRING_CELL || cellValues->editable != True || RowPosToType(g, r) != XmCONTENT || ColPosToType(g, c) != XmCONTENT) allowSet = 0; } if (cell && allowSet) { XmLGridCellSetString(cell, str, False); if (SetCellValuesResize(g, rowp, colp, cell, XmLGridCellString)) needsResize = 1; if (!needsResize) DrawArea(g, DrawCell, r, c); cbs.columnType = ColPosToType(g, c); cbs.column = ColPosToTypePos(g, cbs.columnType, c); cbs.rowType = RowPosToType(g, r); cbs.row = RowPosToTypePos(g, cbs.rowType, r); if (format == XmFORMAT_PASTE) { cbs.reason = XmCR_CELL_PASTE; XtCallCallbackList((Widget)g, g->grid.cellPasteCallback, (XtPointer)&cbs); } else if (format == XmFORMAT_DROP) { cbs.reason = XmCR_CELL_DROP; XtCallCallbackList((Widget)g, g->grid.cellDropCallback, (XtPointer)&cbs); } n++; } else XmStringFree(str); } if (!(*c2)) done = 1; else if (*c2 == delimiter) { c++; c1 = c2 + 1; } else if (*c2 == '\n') { r++; c = col; c1 = c2 + 1; } c2++; } if (needsResize) { VertLayout(g, 1); HorizLayout(g, 1); DrawArea(g, DrawAll, 0, 0); } return n; } static void Write(XmLGridWidget g, FILE *file, int format, char delimiter, Boolean skipHidden, int row, int col, int nrow, int ncol) { int r, c, i, first, last; char *cs = NULL; Boolean set; XmString str; XmLGridColumn colp; XmLGridRow rowp; XmLGridCell cell; first = 1; for (r = row; r < row + nrow; r++) { rowp = (XmLGridRow)XmLArrayGet(g->grid.rowArray, r); if (!rowp) continue; if (skipHidden == True && XmLGridRowIsHidden(rowp) == True) continue; if (first) first = 0; else fprintf(file, "\n"); for (c = col; c < col + ncol; c++) { colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, c); if (!colp) continue; if (skipHidden == True && XmLGridColumnIsHidden(colp) == True) continue; cell = GetCell(g, r, c); if (!cell) continue; str = XmLGridCellGetString(cell); set = False; if (str) { cs = CvtXmStringToStr(str); if (cs) set = True; } if (set == False) cs = ""; fprintf(file, "%s", cs); last = 0; if (c == col + ncol - 1) last = 1; if (!last && format == XmFORMAT_DELIMITED) fprintf(file, "%c", delimiter); else if (!last && format == XmFORMAT_XL) fprintf(file, "\t"); else if (format == XmFORMAT_PAD) { if (colp->grid.sizePolicy == XmVARIABLE) for (i = 0; i < (int)(colp->grid.width - strlen(cs)); i++) fprintf(file, " "); } if (set == True) free(cs); } } } static char * CopyDataCreate(XmLGridWidget g, int selected, int row, int col, int nrow, int ncol) { XmLGridColumn colp; XmLGridRow rowp; XmLGridCell cell; char *buf, *cs = NULL; XmString str; Boolean set; int r, c, wroteStr, bufsize, buflen, len; if (selected) { row = 0; nrow = XmLArrayGetCount(g->grid.rowArray); col = 0; ncol = XmLArrayGetCount(g->grid.colArray); } bufsize = 1024; buflen = 0; buf = (char *)malloc(bufsize); for (r = row; r < row + nrow; r++) { wroteStr = 0; rowp = (XmLGridRow)XmLArrayGet(g->grid.rowArray, r); if (!rowp) continue; for (c = col; c < col + ncol; c++) { colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, c); if (!colp) continue; cell = GetCell(g, r, c); if (!cell) continue; if (selected && XmLGridRowIsSelected(rowp) == False && XmLGridColumnIsSelected(colp) == False && XmLGridCellIsSelected(cell) == False) continue; str = XmLGridCellGetString(cell); set = False; if (str) { cs = CvtXmStringToStr(str); if (cs) set = True; } if (set == False) cs = ""; if (wroteStr) buf[buflen++] = '\t'; len = strlen(cs); /* allocate if string plus tab plus new-line plus 0 if too large */ while (len + buflen + 3 > bufsize) bufsize *= 2; buf = (char *)realloc(buf, bufsize); strcpy(&buf[buflen], cs); buflen += len; if (set == True) free(cs); wroteStr = 1; } if (wroteStr) buf[buflen++] = '\n'; } if (!buflen) { free((char *)buf); return 0; } buf[buflen - 1] = 0; return buf; } static Boolean Copy(XmLGridWidget g, Time time, int selected, int row, int col, int nrow, int ncol) { int i; long itemID; Display *dpy; Window win; XmString clipStr; char *buf; #ifdef MOTIF11 int dataID; #else long ldataID; #endif if (!XtIsRealized((Widget)g)) { XmLWarning((Widget)g, "Copy() - widget not realized"); return False; } dpy = XtDisplay((Widget)g); win = XtWindow((Widget)g); buf = CopyDataCreate(g, selected, row, col, nrow, ncol); if (!buf) return False; clipStr = XmStringCreateSimple("Grid Copy"); for (i = 0; i < 10000; i++) if (XmClipboardStartCopy(dpy, win, clipStr, time, NULL, NULL, &itemID) == ClipboardSuccess) break; XmStringFree(clipStr); if (i == 10000) { XmLWarning((Widget)g, "Copy() - start clipboard copy failed"); return False; } for (i = 0; i < 10000; i++) #ifdef MOTIF11 if (XmClipboardCopy(dpy, win, itemID, "STRING", buf, (long)strlen(buf) + 1, 0, &dataID) == ClipboardSuccess) #else if (XmClipboardCopy(dpy, win, itemID, "STRING", buf, (long)strlen(buf) + 1, 0, &ldataID) == ClipboardSuccess) #endif break; free((char *)buf); if (i == 10000) { XmLWarning((Widget)g, "Copy() - clipboard copy transfer failed"); return False; } for (i = 0; i < 10000; i++) if (XmClipboardEndCopy(dpy, win, itemID) == ClipboardSuccess) break; if (i == 10000) { XmLWarning((Widget)g, "Copy() - end clipboard copy failed"); return False; } return True; } static Boolean Paste(XmLGridWidget g, int row, int col) { Display *dpy; Window win; int i, res, done; unsigned long len, reclen; char *buf; if (!XtIsRealized((Widget)g)) { XmLWarning((Widget)g, "Paste() - widget not realized"); return False; } dpy = XtDisplay((Widget)g); win = XtWindow((Widget)g); for (i = 0; i < 10000; i++) if (XmClipboardInquireLength(dpy, win, "STRING", &len) == ClipboardSuccess) break; if (i == 10000) { XmLWarning((Widget)g, "Paste() - can't retrieve clipboard length"); return False; } if (!len) return False; buf = (char *)malloc((int)len); done = 0; while (!done) { res = XmClipboardRetrieve(dpy, win, "STRING", buf, len, &reclen, NULL); switch (res) { case ClipboardSuccess: done = 2; break; case ClipboardTruncate: case ClipboardNoData: done = 1; break; case ClipboardLocked: break; } } if (done != 2 || reclen != len) { free((char *)buf); XmLWarning((Widget)g, "Paste() - retrieve from clipboard failed"); return False; } Read(g, XmFORMAT_PASTE, 0, row, col, buf); free((char *)buf); return True; } /* Utility */ static void GetCoreBackground(Widget w, int offset, XrmValue *value) { value->addr = (caddr_t)&w->core.background_pixel; } static void GetManagerForeground(Widget w, int offset, XrmValue *value) { XmLGridWidget g; g = (XmLGridWidget)w; value->addr = (caddr_t)&g->manager.foreground; } static void ClipRectToReg(XmLGridWidget g, XRectangle *rect, GridReg *reg) { int i, st; XRectangle regRect; st = g->manager.shadow_thickness; if (!reg->width || !reg->height) i = XmLRectOutside; else { regRect.x = reg->x + st; regRect.y = reg->y + st; regRect.width = reg->width - st * 2; regRect.height = reg->height - st * 2; i = XmLRectIntersect(rect, ®Rect); } if (i == XmLRectInside) return; if (i == XmLRectOutside) { rect->width = 0; rect->height = 0; return; } if (rect->y + (int)rect->height - 1 >= reg->y + (int)reg->height - st) rect->height = reg->y + reg->height - rect->y - st; if (rect->x + (int)rect->width - 1 >= reg->x + (int)reg->width - st) rect->width = reg->x + reg->width - rect->x - st; if (rect->y < reg->y + st) { rect->height -= (reg->y + st) - rect->y; rect->y = reg->y + st; } if (rect->x < reg->x + st) { rect->width -= (reg->x + st) - rect->x; rect->x = reg->x + st; } } static char * FileToString(FILE *file) { long len, n; char *s; if (!file) return 0; fseek(file, 0L, 2); len = ftell(file); s = (char *)malloc((int)len + 1); if (!s) return 0; s[len] = 0; fseek(file, 0L, 0); n = fread(s, 1, (int)len, file); if (n != len) { free((char *)s); return 0; } return s; } static char * CvtXmStringToStr(XmString str) { XmStringContext context; XmStringCharSet charset; XmStringDirection dir; Boolean sep; char *text, *c; int len, size; if (!XmStringInitContext(&context, str)) return 0; size = 0; c = 0; while (XmStringGetNextSegment(context, &text, &charset, &dir, &sep)) { len = strlen(text); size += len + 3; if (!c) { c = (char *)malloc(size); *c = 0; } else c = (char *)realloc(c, size); strcat(c, text); if (sep == True) { len = strlen(c); c[len] = '\\'; c[len + 1] = 'n'; c[len + 2] = 0; } XtFree(text); XtFree(charset); } XmStringFreeContext(context); return c; } static XmLGridWidget WidgetToGrid(Widget w, char *funcname) { char buf[256]; if (!XmLIsGrid(w)) { sprintf(buf, "%s - widget not an XmLGrid", funcname); XmLWarning(w, buf); return 0; } return (XmLGridWidget)w; } /* Actions, Callbacks and Handlers */ static void ButtonMotion(Widget w, XEvent *event, String *params, Cardinal *nparam) { XmLGridWidget g; XMotionEvent *me; char dragTimerSet; int row, col, x, y; if (event->type != MotionNotify) return; g = (XmLGridWidget)w; me = (XMotionEvent *)event; if (g->grid.inMode == InResize) { if (g->grid.resizeIsVert) DrawResizeLine(g, me->y, 0); else { DrawResizeLine(g, me->x, 0); if (g->grid.hsPolicy == XmRESIZE_IF_POSSIBLE) ResizeColumnToFit(g, me->x); } } /* drag scrolling */ dragTimerSet = 0; if (g->grid.inMode == InSelect) { if (g->grid.vsPolicy == XmCONSTANT) { y = g->grid.reg[4].y; if (g->grid.selectionPolicy == XmSELECT_CELL && g->grid.extendRow != -1 && g->grid.extendCol != -1 && RowPosToType(g, g->grid.extendRow) == XmHEADING) ; else if (me->y < y) dragTimerSet |= DragUp; y += g->grid.reg[4].height; if (me->y > y) dragTimerSet |= DragDown; } if (g->grid.hsPolicy == XmCONSTANT) { x = g->grid.reg[4].x; if (g->grid.selectionPolicy == XmSELECT_CELL && g->grid.extendCol != -1 && g->grid.extendRow != -1 && ColPosToType(g, g->grid.extendCol) == XmHEADING) ; else if (me->x < x) dragTimerSet |= DragLeft; x += g->grid.reg[4].width; if (me->x > x) dragTimerSet |= DragRight; } } if (!g->grid.dragTimerSet && dragTimerSet) g->grid.dragTimerId = XtAppAddTimeOut(XtWidgetToApplicationContext(w), 80, DragTimer, (caddr_t)g); else if (g->grid.dragTimerSet && !dragTimerSet) XtRemoveTimeOut(g->grid.dragTimerId); g->grid.dragTimerSet = dragTimerSet; /* Extend Selection */ if (g->grid.inMode == InSelect && XYToRowCol(g, me->x, me->y, &row, &col) != -1) { TextAction(g, TEXT_EDIT_CANCEL); if (g->grid.selectionPolicy == XmSELECT_MULTIPLE_ROW && RowPosToType(g, row) == XmCONTENT) ExtendSelect(g, event, False, row, col); else if (g->grid.selectionPolicy == XmSELECT_CELL) ExtendSelect(g, event, False, row, col); } if (g->grid.inMode == InSelect && g->grid.selectionPolicy == XmSELECT_BROWSE_ROW && XYToRowCol(g, me->x, me->y, &row, &col) != -1) { if (RowPosToType(g, row) == XmCONTENT) { if (!SetFocus(g, row, col, 0, 1)) SelectTypeArea(g, SelectRow, event, RowPosToTypePos(g, XmCONTENT, g->grid.focusRow), 0, True, True); } } } static void DragTimer(XtPointer clientData, XtIntervalId *intervalId) { Widget w; XmLGridWidget g; XRectangle rect; XmLGridRow rowp; XmLGridColumn colp; int r, c, min, max, inc, pi, ss, value, newValue; int extRow, extCol; g = (XmLGridWidget)clientData; w = (Widget)g; extRow = -1; extCol = -1; if (g->grid.vsPolicy == XmCONSTANT && ((g->grid.dragTimerSet & DragUp) || (g->grid.dragTimerSet & DragDown))) { XtVaGetValues(g->grid.vsb, XmNminimum, &min, XmNmaximum, &max, XmNvalue, &value, XmNsliderSize, &ss, XmNincrement, &inc, XmNpageIncrement, &pi, NULL); newValue = value; if (g->grid.dragTimerSet & DragUp) newValue--; else newValue++; if (newValue != value && newValue >= min && newValue <= (max - ss)) { XmScrollBarSetValues(g->grid.vsb, newValue, ss, inc, pi, True); r = g->grid.reg[4].row; if (g->grid.dragTimerSet & DragDown) r += g->grid.reg[4].nrow - 1; /* simple check to make sure row selected is totally visible */ if (g->grid.reg[4].nrow) { rowp = (XmLGridRow)XmLArrayGet(g->grid.rowArray, r); if (rowp && !RowColToXY(g, r, 0, True, &rect)) { if (GetRowHeight(g, r) != rect.height) r--; } } if (g->grid.selectionPolicy == XmSELECT_BROWSE_ROW) { if (!SetFocus(g, r, g->grid.focusCol, -1, 1)) SelectTypeArea(g, SelectRow, (XEvent *)0, RowPosToTypePos(g, XmCONTENT, g->grid.focusRow), 0, True, True); } else if (g->grid.selectionPolicy == XmSELECT_MULTIPLE_ROW) ExtendSelect(g, (XEvent *)0, False, r, g->grid.focusCol); else if (g->grid.selectionPolicy == XmSELECT_CELL) { extRow = r; extCol = g->grid.extendToCol; } } } if (g->grid.hsPolicy == XmCONSTANT && ((g->grid.dragTimerSet & DragLeft) || (g->grid.dragTimerSet & DragRight))) { XtVaGetValues(g->grid.hsb, XmNminimum, &min, XmNmaximum, &max, XmNvalue, &value, XmNsliderSize, &ss, XmNincrement, &inc, XmNpageIncrement, &pi, NULL); newValue = value; if (g->grid.dragTimerSet & DragLeft) newValue--; else newValue++; if (newValue != value && newValue >= min && newValue <= (max - ss)) { XmScrollBarSetValues(g->grid.hsb, newValue, ss, inc, pi, True); c = g->grid.reg[4].col; if (g->grid.dragTimerSet & DragRight) c += g->grid.reg[4].ncol - 1; if (g->grid.selectionPolicy == XmSELECT_CELL) { /* simple check to make sure col selected is totally visible */ if (g->grid.reg[4].ncol) { colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, c); if (colp && !RowColToXY(g, c, 0, True, &rect)) { if (GetColWidth(g, c) != rect.width) c--; } } if (extRow == -1) extRow = g->grid.extendToRow; extCol = c; } } } if (extRow != -1 && extCol != -1) ExtendSelect(g, (XEvent *)0, False, extRow, extCol); g->grid.dragTimerId = XtAppAddTimeOut(XtWidgetToApplicationContext(w), 80, DragTimer, (caddr_t)g); } /*----------------------------------------------------------------------*/ static void CursorMotion(Widget w, XEvent *event, String *params, Cardinal *nparam) { XmLGridWidget g; XMotionEvent *me; int isVert, row, col; char defineCursor; if (event->type != MotionNotify) return; g = (XmLGridWidget)w; me = (XMotionEvent *)event; defineCursor = CursorNormal; { int motionRow; int motionCol; int newMotionRow = -1; int newMotionCol = -1; Boolean invokeEnterCellCallback = False; if (XYToRowCol(g,me->x,me->y,&motionRow,&motionCol) != -1) { if (motionRow != g->grid.lastCursorMotionRow || motionCol != g->grid.lastCursorMotionCol) { newMotionRow = motionRow; newMotionCol = motionCol; invokeEnterCellCallback = True; } } if (g->grid.lastCursorMotionRow != -1 && g->grid.lastCursorMotionCol != -1) { /* Invoke XmNleaveCellCallback */ GridInvokeCellCrossingCallbacks(w, g->grid.leaveCellCallback, XmCR_LEAVE_CELL, event, g->grid.lastCursorMotionRow, g->grid.lastCursorMotionCol); } if (invokeEnterCellCallback) { /* Invoke XmNenterCellCallback */ GridInvokeCellCrossingCallbacks(w, g->grid.enterCellCallback, XmCR_ENTER_CELL, event, newMotionRow, newMotionCol); } g->grid.lastCursorMotionRow = newMotionRow; g->grid.lastCursorMotionCol = newMotionCol; } if (PosIsResize(g, me->x, me->y, &row, &col, &isVert)) { if (isVert) defineCursor = CursorVResize; else defineCursor = CursorHResize; } DefineCursor(g, defineCursor); } /*----------------------------------------------------------------------*/ static void Edit(Widget w, XEvent *event, String *params, Cardinal *nparam) { XmLGridWidget g; g = (XmLGridWidget)XtParent(w); TextAction(g, TEXT_EDIT_INSERT); } static void EditCancel(Widget w, XEvent *event, String *params, Cardinal *nparam) { XmLGridWidget g; g = (XmLGridWidget)XtParent(w); TextAction(g, TEXT_EDIT_CANCEL); } static void EditComplete(Widget w, XEvent *event, String *params, Cardinal *nparam) { XmLGridWidget g; g = (XmLGridWidget)XtParent(w); TextAction(g, TEXT_EDIT_COMPLETE); if (*nparam == 1) Traverse(w, event, params, nparam); } #ifndef MOTIF11 extern Widget _XmGetTextualDragIcon(Widget); #endif static void DragStart(Widget w, XEvent *event, String *params, Cardinal *nparam) { #ifndef MOTIF11 XmLGridWidget g; Widget dragIcon; Atom exportTargets[1]; Arg args[10]; char *data; XButtonEvent *be; int row, col; XmLGridColumn colp; XmLGridRow rowp; XmLGridCell cell; static XtCallbackRec dragFinish[2] = { { DragFinish, NULL }, { NULL, NULL } }; g = (XmLGridWidget)w; be = (XButtonEvent *)event; if (!g->grid.allowDrag || !be) return; if (XYToRowCol(g, be->x, be->y, &row, &col) == -1) return; rowp = (XmLGridRow)XmLArrayGet(g->grid.rowArray, row); colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, col); cell = GetCell(g, row, col); if (!rowp || !colp || !cell) return; if (XmLGridRowIsSelected(rowp) == False && XmLGridColumnIsSelected(colp) == False && XmLGridCellIsSelected(cell) == False) return; data = CopyDataCreate(g, 1, 0, 0, 0, 0); if (!data) return; dragIcon = _XmGetTextualDragIcon((Widget)w); exportTargets[0] = XA_STRING; dragFinish[0].closure = (XtPointer)data; XtSetArg(args[0], XmNconvertProc, DragConvert); XtSetArg(args[1], XmNexportTargets, exportTargets); XtSetArg(args[2], XmNnumExportTargets, 1); XtSetArg(args[3], XmNdragOperations, XmDROP_COPY); XtSetArg(args[4], XmNsourceCursorIcon, dragIcon); XtSetArg(args[4], XmNclientData, (XtPointer)data); XtSetArg(args[5], XmNdragDropFinishCallback, dragFinish); XmDragStart(w, event, args, 6); #endif } static Boolean DragConvert(Widget w, Atom *selection, Atom *target, Atom *type, XtPointer *value, unsigned long *length, int *format) { #ifdef MOTIF11 return FALSE; #else Atom targetsA, timestampA, multipleA, *exportTargets; int n; char *data, *dataCopy; if (!XmIsDragContext(w)) return FALSE; targetsA = XInternAtom(XtDisplay(w), "TARGETS", FALSE); timestampA = XInternAtom(XtDisplay(w), "TIMESTAMP", FALSE); multipleA = XInternAtom(XtDisplay(w), "MULTIPLE", FALSE); if (*target == targetsA) { n = 4; exportTargets = (Atom *)XtMalloc(sizeof(Atom) * n); exportTargets[0] = XA_STRING; exportTargets[1] = targetsA; exportTargets[2] = multipleA; exportTargets[3] = timestampA; *type = XA_ATOM; *value = (XtPointer)exportTargets; *format = 32; *length = (n * sizeof(Atom)) >> 2; return TRUE; } else if (*target == XA_STRING) { XtVaGetValues(w, XmNclientData, &data, NULL); *type = XA_STRING; dataCopy = XtMalloc(strlen(data)); strncpy(dataCopy, data, strlen(data)); *value = (XtPointer)dataCopy; *length = strlen(data); *format = 8; return TRUE; } return FALSE; #endif } static void DragFinish(Widget w, XtPointer clientData, XtPointer callData) { free ((char *)clientData); } static void DropRegister(XmLGridWidget g, Boolean set) { #ifndef MOTIF11 Atom importTargets[1]; Arg args[4]; if (set == True) { importTargets[0] = XA_STRING; XtSetArg(args[0], XmNdropSiteOperations, XmDROP_COPY); XtSetArg(args[1], XmNimportTargets, importTargets); XtSetArg(args[2], XmNnumImportTargets, 1); XtSetArg(args[3], XmNdropProc, DropStart); XmDropSiteRegister((Widget)g, args, 4); } else XmDropSiteUnregister((Widget)g); #endif } static void DropStart(Widget w, XtPointer clientData, XtPointer callData) { #ifndef MOTIF11 XmLGridWidget g; XmDropProcCallbackStruct *cbs; XmDropTransferEntryRec te[2]; Atom *exportTargets; Arg args[10]; int row, col, i, n, valid; g = (XmLGridWidget)w; cbs = (XmDropProcCallbackStruct *)callData; if (g->grid.allowDrop == False || cbs->dropAction == XmDROP_HELP) { cbs->dropSiteStatus = XmINVALID_DROP_SITE; return; } valid = 0; if (XYToRowCol(g, cbs->x, cbs->y, &row, &col) != -1 && cbs->dropAction == XmDROP && cbs->operation == XmDROP_COPY) { XtVaGetValues(cbs->dragContext, XmNexportTargets, &exportTargets, XmNnumExportTargets, &n, NULL); for (i = 0; i < n; i++) if (exportTargets[i] == XA_STRING) valid = 1; } if (!valid) { cbs->operation = (long)XmDROP_NOOP; cbs->dropSiteStatus = XmINVALID_DROP_SITE; XtSetArg(args[0], XmNtransferStatus, XmTRANSFER_FAILURE); XtSetArg(args[1], XmNnumDropTransfers, 0); XmDropTransferStart(cbs->dragContext, args, 2); return; } g->grid.dropLoc.row = row; g->grid.dropLoc.col = col; cbs->operation = (long)XmDROP_COPY; te[0].target = XA_STRING; te[0].client_data = (XtPointer)g; XtSetArg(args[0], XmNdropTransfers, te); XtSetArg(args[1], XmNnumDropTransfers, 1); XtSetArg(args[2], XmNtransferProc, DropTransfer); XmDropTransferStart(cbs->dragContext, args, 3); #endif } static void DropTransfer(Widget w, XtPointer clientData, Atom *selType, Atom *type, XtPointer value, unsigned long *length, int *format) { #ifndef MOTIF11 XmLGridWidget g; char *buf; int len; if (!value) return; g = (XmLGridWidget)clientData; len = (int)*length; if (len < 0) return; buf = (char *)malloc(len + 1); strncpy(buf, (char *)value, len); XtFree((char *)value); buf[len] = 0; Read(g, XmFORMAT_DROP, 0, g->grid.dropLoc.row, g->grid.dropLoc.col, buf); free((char *)buf); #endif } static void Select(Widget w, XEvent *event, String *params, Cardinal *nparam) { XmLGridWidget g; Display *dpy; Window win; static XrmQuark qACTIVATE, qBEGIN, qEXTEND, qEND; static XrmQuark qTOGGLE; static int quarksValid = 0; XrmQuark q; int isVert; int row, col, resizeRow, resizeCol; XButtonEvent *be; XRectangle rect; XmLGridRow rowp; XmLGridCell cellp; XmLGridColumn colp; XmLGridCallbackStruct cbs; Boolean flag; if (*nparam != 1) return; if (XmLIsGrid(w)) g = (XmLGridWidget)w; else g = (XmLGridWidget)XtParent(w); dpy = XtDisplay(g); win = XtWindow(g); if (!quarksValid) { qACTIVATE = XrmStringToQuark("ACTIVATE"); qBEGIN = XrmStringToQuark("BEGIN"); qEXTEND = XrmStringToQuark("EXTEND"); qEND = XrmStringToQuark("END"); qTOGGLE = XrmStringToQuark("TOGGLE"); } q = XrmStringToQuark(params[0]); be = 0; if (event->type == KeyPress || event->type == KeyRelease) { row = g->grid.focusRow; col = g->grid.focusCol; } else /* Button */ { be = (XButtonEvent *)event; if (XYToRowCol(g, be->x, be->y, &row, &col) == -1) { row = -1; col = -1; } } /* double click activate check */ if (q == qBEGIN && be) { if (row != -1 && col != -1 && row == g->grid.focusRow && col == g->grid.focusCol ) { int doubleClickTime = XtGetMultiClickTime(dpy); Time timeSinceLastClick = be->time - g->grid.lastSelectTime; if (timeSinceLastClick < doubleClickTime) { /* Clear inplace editing if some other event happens */ if (g->grid.editTimerSet) { XtRemoveTimeOut(g->grid.editTimerId); g->grid.editTimerSet = 0; } /* Second click came within double click time */ q = qACTIVATE; } else if (!g->grid.editTimerSet && g->grid.lastSelectTime != 0) { /* Only begin an edit when we are sure we don't * have a double click */ if (!g->grid.singleClickActivation) { g->grid.editTimerId = XtAppAddTimeOut(XtWidgetToApplicationContext(w), doubleClickTime*2, EditTimer, (caddr_t)g); g->grid.editTimerSet = 1; } } } g->grid.lastSelectRow = row; g->grid.lastSelectCol = col; g->grid.lastSelectTime = be->time; } else if (q == qBEGIN) g->grid.lastSelectTime = 0; if (q == qBEGIN && be && PosIsResize(g, be->x, be->y, &resizeRow, &resizeCol, &isVert)) { g->grid.resizeIsVert = isVert; g->grid.inMode = InResize; g->grid.resizeLineXY = -1; g->grid.resizeRow = resizeRow; g->grid.resizeCol = resizeCol; if (isVert) { DrawResizeLine(g, be->y, 0); DefineCursor(g, CursorVResize); } else { DrawResizeLine(g, be->x, 0); DefineCursor(g, CursorHResize); } } else if (q == qBEGIN || q == qEXTEND || q == qTOGGLE) { if (g->grid.inMode != InNormal) return; if (row == -1 || col == -1) return; if (RowPosToType(g, row) == XmCONTENT && ColPosToType(g, col) == XmCONTENT) { TextAction(g, TEXT_EDIT_COMPLETE); if (q != qEXTEND) { SetFocus(g, row, col, 0, 1); ExtendSelect(g, event, False, -1, -1); } XmProcessTraversal(g->grid.text, XmTRAVERSE_CURRENT); } if (g->grid.selectionPolicy == XmSELECT_MULTIPLE_ROW && RowPosToType(g, row) == XmCONTENT) { flag = True; rowp = (XmLGridRow)XmLArrayGet(g->grid.rowArray, row); #if 0 /* Don't want single click to unselect something. -slamm */ if (q == qBEGIN && rowp && XmLGridRowIsSelected(rowp) == True) flag = False; #endif /* 0 -slamm */ if (q == qTOGGLE && rowp && XmLGridRowIsSelected(rowp) == True) flag = False; if (q == qBEGIN) SelectTypeArea(g, SelectRow, event, -1, 0, False, True); if (be && q == qEXTEND) ExtendSelect(g, event, False, row, col); else SelectTypeArea(g, SelectRow, event, RowPosToTypePos(g, XmCONTENT, row), 0, flag, True); } if (g->grid.selectionPolicy == XmSELECT_CELL) { if (q == qBEGIN) { SelectTypeArea(g, SelectCell, event, -1, -1, False, True); SelectTypeArea(g, SelectRow, event, -1, 0, False, True); SelectTypeArea(g, SelectCol, event, 0, -1, False, True); } else if (q == qTOGGLE) ExtendSelect(g, event, False, -1, -1); if (RowPosToType(g, row) == XmFOOTER || ColPosToType(g, col) == XmFOOTER) ExtendSelect(g, event, False, -1, -1); if (be && q == qEXTEND) ExtendSelect(g, event, False, row, col); else if (RowPosToType(g, row) == XmCONTENT && ColPosToType(g, col) == XmCONTENT) { flag = True; cellp = GetCell(g, row, col); if (q == qTOGGLE && cellp && XmLGridCellIsSelected(cellp) == True) flag = False; SelectTypeArea(g, SelectCell, event, RowPosToTypePos(g, XmCONTENT, row), ColPosToTypePos(g, XmCONTENT, col), flag, True); } else if (RowPosToType(g, row) == XmHEADING && ColPosToType(g, col) == XmCONTENT) { if (q == qTOGGLE) { colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, col); if (colp && XmLGridColumnIsSelected(colp) == True) g->grid.extendSelect = False; } ExtendSelect(g, event, True, row, col); } else if (ColPosToType(g, col) == XmHEADING && RowPosToType(g, row) == XmCONTENT) { if (q == qTOGGLE) { rowp = (XmLGridRow)XmLArrayGet(g->grid.rowArray, row); if (rowp && XmLGridRowIsSelected(rowp) == True) g->grid.extendSelect = False; } ExtendSelect(g, event, True, row, col); } } if (g->grid.selectionPolicy == XmSELECT_SINGLE_ROW && RowPosToType(g, row) == XmCONTENT) { flag = True; rowp = (XmLGridRow)XmLArrayGet(g->grid.rowArray, row); if (rowp && XmLGridRowIsSelected(rowp) == True) flag = False; SelectTypeArea(g, SelectRow, event, RowPosToTypePos(g, XmCONTENT, row), 0, flag, True); } if (g->grid.selectionPolicy == XmSELECT_BROWSE_ROW && RowPosToType(g, row) == XmCONTENT) SelectTypeArea(g, SelectRow, event, RowPosToTypePos(g, XmCONTENT, row), 0, True, True); if (g->grid.selectionPolicy == XmSELECT_NONE || (g->grid.selectionPolicy == XmSELECT_BROWSE_ROW && RowPosToType(g, row) != XmCONTENT) || (g->grid.selectionPolicy == XmSELECT_SINGLE_ROW && RowPosToType(g, row) != XmCONTENT) || (g->grid.selectionPolicy == XmSELECT_MULTIPLE_ROW && RowPosToType(g, row) != XmCONTENT) ) { cbs.reason = XmCR_SELECT_CELL; cbs.event = event; cbs.columnType = ColPosToType(g, col); cbs.column = ColPosToTypePos(g, cbs.columnType, col); cbs.rowType = RowPosToType(g, row); cbs.row = RowPosToTypePos(g, cbs.rowType, row); XtCallCallbackList((Widget)g, g->grid.selectCallback, (XtPointer)&cbs); } g->grid.inMode = InSelect; } else if (q == qEND && g->grid.inMode == InResize) { int r, c, width, height; r = g->grid.resizeRow; c = g->grid.resizeCol; g->grid.resizeRow = -1; g->grid.resizeCol = -1; if (!RowColToXY(g, r, c, False, &rect)) { if (g->grid.resizeIsVert) { cbs.rowType = RowPosToType(g, r); cbs.row = RowPosToTypePos(g, cbs.rowType, r); height = 0; if (g->grid.resizeLineXY > rect.y) height = g->grid.resizeLineXY - rect.y - (rect.height - GetRowHeight(g, r)); if (height < 6 && g->grid.allowRowHide == False) height = 6; XtVaSetValues((Widget)g, XmNrowType, cbs.rowType, XmNrow, cbs.row, XmNrowHeight, height, XmNrowSizePolicy, XmCONSTANT, NULL); cbs.reason = XmCR_RESIZE_ROW; } else { cbs.columnType = ColPosToType(g, c); cbs.column = ColPosToTypePos(g, cbs.columnType, c); width = 0; if (g->grid.resizeLineXY > rect.x) width = g->grid.resizeLineXY - rect.x - (rect.width - GetColWidth(g, c)); if (width < 6 && g->grid.allowColHide == False) width = 6; XtVaSetValues((Widget)g, XmNcolumnType, cbs.columnType, XmNcolumn, cbs.column, XmNcolumnWidth, width, XmNcolumnSizePolicy, XmCONSTANT, NULL); cbs.reason = XmCR_RESIZE_COLUMN; } XtCallCallbackList((Widget)g, g->grid.resizeCallback, (XtPointer)&cbs); } DrawResizeLine(g, 0, 2); DefineCursor(g, CursorNormal); g->grid.inMode = InNormal; } else if (q == qEND) { g->grid.inMode = InNormal; if (g->grid.dragTimerSet) XtRemoveTimeOut(g->grid.dragTimerId); g->grid.dragTimerSet = 0; /* XFE Additions to handle button up events in menus - they generate activate events */ { if (XmIsMenuShell(XmLShellOfWidget((Widget)g))) { cbs.reason = XmCR_ACTIVATE; cbs.event = event; cbs.columnType = ColPosToType(g, col); cbs.column = ColPosToTypePos(g, cbs.columnType, col); cbs.rowType = RowPosToType(g, row); cbs.row = RowPosToTypePos(g, cbs.rowType, row); XtCallCallbackList((Widget)g, g->grid.activateCallback, (XtPointer)&cbs); } } } if (q == qBEGIN && g->grid.singleClickActivation) { cbs.reason = XmCR_ACTIVATE; cbs.event = event; cbs.columnType = ColPosToType(g, col); cbs.column = ColPosToTypePos(g, cbs.columnType, col); cbs.rowType = RowPosToType(g, row); cbs.row = RowPosToTypePos(g, cbs.rowType, row); XtCallCallbackList((Widget)g, g->grid.activateCallback, (XtPointer)&cbs); } if (q == qACTIVATE) { cbs.reason = XmCR_ACTIVATE; cbs.event = event; cbs.columnType = ColPosToType(g, col); cbs.column = ColPosToTypePos(g, cbs.columnType, col); cbs.rowType = RowPosToType(g, row); cbs.row = RowPosToTypePos(g, cbs.rowType, row); XtCallCallbackList((Widget)g, g->grid.activateCallback, (XtPointer)&cbs); } } /* * Selection policy when posting a context menu. * If over a current selection, leave the selection alone. * Otherwise, change the selection the same as Select(), * except do not allow dragging to extend the selection. */ static void PopupSelect(Widget w, XEvent *event, String *params, Cardinal *nparam) { XmLGridWidget g; int row, col; XButtonEvent *be; XmLGridRow rowp; XmLGridCallbackStruct cbs; if (*nparam != 1) return; if (XmLIsGrid(w)) g = (XmLGridWidget)w; else g = (XmLGridWidget)XtParent(w); be = 0; if (event->type == KeyPress || event->type == KeyRelease) { row = g->grid.focusRow; col = g->grid.focusCol; } else /* Button */ { be = (XButtonEvent *)event; if (XYToRowCol(g, be->x, be->y, &row, &col) == -1) { row = -1; col = -1; } } if (RowPosToType(g, row) == XmCONTENT) { XmLGridRow rowp; rowp = (XmLGridRow)XmLArrayGet(g->grid.rowArray, row); if (rowp && !XmLGridRowIsSelected(rowp)) { String end_params[1]; end_params[0] = "END"; Select(w, event, params, nparam); Select(w, event, end_params, nparam); } } if (XtHasCallbacks(w, XmNpopupCallback) == XtCallbackHasSome) { cbs.reason = XmCR_SHOW_POPUP; cbs.event = event; cbs.columnType = ColPosToType(g, col); cbs.column = ColPosToTypePos(g, cbs.columnType, col); cbs.rowType = RowPosToType(g, row); cbs.row = RowPosToTypePos(g, cbs.rowType, row); XtCallCallbackList((Widget)g, g->grid.popupCallback, (XtPointer)&cbs); } } static void Traverse(Widget w, XEvent *event, String *params, Cardinal *nparam) { XmLGridWidget g; static XrmQuark qDOWN, qEXTEND_DOWN, qEXTEND_LEFT; static XrmQuark qEXTEND_PAGE_DOWN, qEXTEND_PAGE_LEFT; static XrmQuark qEXTEND_PAGE_RIGHT, qEXTEND_PAGE_UP; static XrmQuark qEXTEND_RIGHT, qEXTEND_UP, qLEFT, qPAGE_DOWN; static XrmQuark qPAGE_LEFT, qPAGE_RIGHT, qPAGE_UP, qRIGHT; static XrmQuark qTO_BOTTOM, qTO_BOTTOM_RIGHT, qTO_LEFT; static XrmQuark qTO_RIGHT, qTO_TOP, qTO_TOP_LEFT, qUP; static int quarksValid = 0; int extend, focusRow, focusCol, rowDir, colDir; int rowLoc, colLoc, prevRowLoc, prevColLoc; int scrollRow, scrollCol, prevScrollRow, prevScrollCol; XrmQuark q; g = (XmLGridWidget)XtParent(w); if (*nparam != 1) return; if (!quarksValid) { qDOWN = XrmStringToQuark("DOWN"); qEXTEND_DOWN = XrmStringToQuark("EXTEND_DOWN"); qEXTEND_LEFT = XrmStringToQuark("EXTEND_LEFT"); qEXTEND_PAGE_DOWN = XrmStringToQuark("EXTEND_PAGE_DOWN"); qEXTEND_PAGE_LEFT = XrmStringToQuark("EXTEND_PAGE_LEFT"); qEXTEND_PAGE_RIGHT = XrmStringToQuark("EXTEND_PAGE_RIGHT"); qEXTEND_PAGE_UP = XrmStringToQuark("EXTEND_PAGE_UP"); qEXTEND_RIGHT = XrmStringToQuark("EXTEND_RIGHT"); qEXTEND_UP = XrmStringToQuark("EXTEND_UP"); qLEFT = XrmStringToQuark("LEFT"); qPAGE_DOWN = XrmStringToQuark("PAGE_DOWN"); qPAGE_LEFT = XrmStringToQuark("PAGE_LEFT"); qPAGE_RIGHT = XrmStringToQuark("PAGE_RIGHT"); qPAGE_UP = XrmStringToQuark("PAGE_UP"); qRIGHT = XrmStringToQuark("RIGHT"); qTO_BOTTOM = XrmStringToQuark("TO_BOTTOM"); qTO_BOTTOM_RIGHT = XrmStringToQuark("TO_BOTTOM_RIGHT"); qTO_LEFT = XrmStringToQuark("TO_LEFT"); qTO_RIGHT = XrmStringToQuark("TO_RIGHT"); qTO_TOP = XrmStringToQuark("TO_TOP"); qTO_TOP_LEFT = XrmStringToQuark("TO_TOP_LEFT"); qUP = XrmStringToQuark("UP"); quarksValid = 1; } q = XrmStringToQuark(params[0]); extend = 0; /* map the extends to their counterparts and set extend flag */ if (q == qEXTEND_DOWN) { q = qDOWN; extend = 1; } else if (q == qEXTEND_LEFT) { q = qLEFT; extend = 1; } else if (q == qEXTEND_PAGE_DOWN) { q = qPAGE_DOWN; extend = 1; } else if (q == qEXTEND_PAGE_LEFT) { q = qPAGE_LEFT; extend = 1; } else if (q == qEXTEND_PAGE_RIGHT) { q = qPAGE_RIGHT; extend = 1; } else if (q == qEXTEND_PAGE_UP) { q = qPAGE_UP; extend = 1; } else if (q == qEXTEND_RIGHT) { q = qRIGHT; extend = 1; } else if (q == qEXTEND_UP) { q = qUP; extend = 1; } if (extend && g->grid.selectionPolicy != XmSELECT_MULTIPLE_ROW && g->grid.selectionPolicy != XmSELECT_CELL) return; if (extend && g->grid.extendRow != -1 && g->grid.extendCol != -1) { focusRow = g->grid.extendToRow; focusCol = g->grid.extendToCol; } else { focusRow = g->grid.focusRow; focusCol = g->grid.focusCol; } rowDir = 0; colDir = 0; if (focusRow < g->grid.topFixedCount) prevRowLoc = 0; else if (focusRow >= XmLArrayGetCount(g->grid.rowArray) - g->grid.bottomFixedCount) prevRowLoc = 2; else prevRowLoc = 1; if (focusCol < g->grid.leftFixedCount) prevColLoc = 0; else if (focusCol >= XmLArrayGetCount(g->grid.colArray) - g->grid.rightFixedCount) prevColLoc = 2; else prevColLoc = 1; /* calculate new focus row, col and walk direction */ if (q == qDOWN) { focusRow++; rowDir = 1; } else if (q == qLEFT) { focusCol--; colDir = -1; } else if (q == qPAGE_DOWN) { if (prevRowLoc == 1) focusRow = g->grid.reg[4].row + g->grid.reg[4].nrow - 1; if (focusRow == g->grid.focusRow) focusRow += 4; rowDir = 1; } else if (q == qPAGE_LEFT) { if (prevColLoc == 1) focusCol = g->grid.reg[4].col - 1; if (focusCol == g->grid.focusCol) focusCol -= 4; colDir = -1; } else if (q == qPAGE_RIGHT) { if (prevColLoc == 1) focusCol = g->grid.reg[4].col + g->grid.reg[4].ncol - 1; if (focusCol == g->grid.focusCol) focusCol += 4; colDir = 1; } else if (q == qPAGE_UP) { if (prevRowLoc == 1) focusRow = g->grid.reg[4].row - 1; if (focusRow == g->grid.focusRow) focusRow -= 4; rowDir = -1; } else if (q == qRIGHT) { focusCol++; colDir = 1; } else if (q == qTO_BOTTOM) { focusRow = XmLArrayGetCount(g->grid.rowArray) - 1; rowDir = -1; } else if (q == qTO_BOTTOM_RIGHT) { focusCol = XmLArrayGetCount(g->grid.colArray) - 1; focusRow = XmLArrayGetCount(g->grid.rowArray) - 1; rowDir = -1; colDir = -1; } else if (q == qTO_LEFT) { focusCol = 0; colDir = 1; } else if (q == qTO_RIGHT) { focusCol = XmLArrayGetCount(g->grid.colArray) - 1; colDir = -1; } else if (q == qTO_TOP) { focusRow = 0; rowDir = 1; } else if (q == qTO_TOP_LEFT) { focusCol = 0; focusRow = 0; rowDir = 1; colDir = 1; } else if (q == qUP) { focusRow -= 1; rowDir = -1; } if (!rowDir && !colDir) return; if (extend) { if (FindNextFocus(g, focusRow, focusCol, rowDir, colDir, &focusRow, &focusCol) == -1) return; ExtendSelect(g, event, False, focusRow, focusCol); } else { if (SetFocus(g, focusRow, focusCol, rowDir, colDir) == -1) return; ExtendSelect(g, event, False, -1, -1); focusRow = g->grid.focusRow; focusCol = g->grid.focusCol; if (g->grid.selectionPolicy == XmSELECT_CELL) { SelectTypeArea(g, SelectRow, event, -1, 0, False, True); SelectTypeArea(g, SelectCol, event, 0, -1, False, True); SelectTypeArea(g, SelectCell, event, -1, -1, False, True); SelectTypeArea(g, SelectCell, event, RowPosToTypePos(g, XmCONTENT, focusRow), ColPosToTypePos(g, XmCONTENT, focusCol), True, True); } else if (g->grid.selectionPolicy == XmSELECT_BROWSE_ROW) SelectTypeArea(g, SelectRow, event, RowPosToTypePos(g, XmCONTENT, focusRow), 0, True, True); } scrollRow = -1; scrollCol = -1; if (q == qPAGE_UP) scrollRow = ScrollRowBottomPos(g, focusRow); else if (q == qPAGE_DOWN) scrollRow = focusRow; else if (q == qPAGE_LEFT) scrollCol = ScrollColRightPos(g, focusCol); else if (q == qPAGE_RIGHT) scrollCol = focusCol; else { if (focusRow < g->grid.topFixedCount) rowLoc = 0; else if (focusRow >= XmLArrayGetCount(g->grid.rowArray) - g->grid.bottomFixedCount) rowLoc = 2; else rowLoc = 1; if (prevRowLoc != 0 && rowLoc == 0) scrollRow = g->grid.reg[0].nrow; else if (prevRowLoc != 2 && rowLoc == 2) scrollRow = g->grid.reg[6].row - 1; if (focusCol < g->grid.leftFixedCount) colLoc = 0; else if (focusCol >= XmLArrayGetCount(g->grid.colArray) - g->grid.rightFixedCount) colLoc = 2; else colLoc = 1; if (prevColLoc != 0 && colLoc == 0) scrollCol = g->grid.reg[0].ncol; else if (prevColLoc != 2 && colLoc == 2) scrollCol = g->grid.reg[2].col - 1; } if (g->grid.vsPolicy == XmVARIABLE) ; else if (scrollRow != -1) { prevScrollRow = g->grid.scrollRow; g->grid.scrollRow = scrollRow; VertLayout(g, 0); if (g->grid.scrollRow != prevScrollRow) DrawArea(g, DrawVScroll, 0, 0); } else MakeRowVisible(g, focusRow); if (g->grid.hsPolicy == XmVARIABLE) ; else if (scrollCol != -1) { prevScrollCol = g->grid.scrollCol; g->grid.scrollCol = scrollCol; HorizLayout(g, 0); if (g->grid.scrollCol != prevScrollCol) DrawArea(g, DrawHScroll, 0, 0); } else MakeColVisible(g, focusCol); } static void TextActivate(Widget w, XtPointer clientData, XtPointer callData) { XmLGridWidget g; XmAnyCallbackStruct *cbs; String params[1]; Cardinal nparam; cbs = (XmAnyCallbackStruct *)callData; g = (XmLGridWidget)XtParent(w); if (g->grid.inEdit) { nparam = 0; EditComplete(w, cbs->event, params, &nparam); } else { params[0] = "ACTIVATE"; nparam = 1; Select(XtParent(w), cbs->event, params, &nparam); } } static void TextFocus(Widget w, XtPointer clientData, XtPointer callData) { XmLGridWidget g; XmAnyCallbackStruct *cbs; int focusRow, focusCol; cbs = (XmAnyCallbackStruct *)callData; g = (XmLGridWidget)XtParent(w); if (cbs->reason == XmCR_FOCUS) g->grid.focusIn = 1; else g->grid.focusIn = 0; focusRow = g->grid.focusRow; focusCol = g->grid.focusCol; if (focusRow != -1 && focusCol != -1) { if (g->grid.highlightRowMode == True) DrawArea(g, DrawRow, focusRow, 0); else DrawArea(g, DrawCell, focusRow, focusCol); } } static void TextMapped(Widget w, XtPointer clientData, XEvent *event, Boolean *con) { XmLGridWidget g; g = (XmLGridWidget)(XtParent(w)); if (event->type != MapNotify) return; if (g->grid.textHidden) XtUnmapWidget(g->grid.text); } static void TextModifyVerify(Widget w, XtPointer clientData, XtPointer callData) { XmLGridWidget g; XmTextVerifyCallbackStruct *cbs; g = (XmLGridWidget)XtParent(w); cbs = (XmTextVerifyCallbackStruct *)callData; if (!cbs->event || g->grid.ignoreModifyVerify || g->grid.inEdit) return; TextAction(g, TEXT_EDIT); if (!g->grid.inEdit) cbs->doit = False; } /* XmLGridRow */ static XmLGridRow XmLGridRowNew(Widget grid) { return XmLGridClassPartOfWidget(grid).rowNewProc(grid); } /* Only to be called through Grid class */ static XmLGridRow _GridRowNew(Widget grid) { XmLGridWidget g; XmLGridRow row; int size; g = (XmLGridWidget)grid; size = XmLGridClassPartOfWidget(grid).rowRecSize; row = (XmLGridRow)malloc(size); row->grid.grid = grid; row->grid.heightInPixels = 0; row->grid.heightInPixelsValid = 0; row->grid.height = 1; row->grid.selected = False; row->grid.sizePolicy = XmVARIABLE; row->grid.userData = 0; row->grid.cellArray = XmLArrayNew(0, 0); return row; } static void XmLGridRowFree(Widget grid, XmLGridRow row) { XmLGridClassPartOfWidget(grid).rowFreeProc(row); } /* Only to be called through Grid class */ static void _GridRowFree(XmLGridRow row) { int i, count; count = XmLArrayGetCount(row->grid.cellArray); for (i = 0; i < count; i++) XmLGridCellFree(row->grid.grid, (XmLGridCell)XmLArrayGet(row->grid.cellArray, i)); XmLArrayFree(row->grid.cellArray); free ((char *)row); } static XmLArray XmLGridRowCells(XmLGridRow row) { return row->grid.cellArray; } static int XmLGridRowGetPos(XmLGridRow row) { return row->grid.pos; } static int XmLGridRowGetVisPos(XmLGridRow row) { return row->grid.visPos; } static Boolean XmLGridRowIsHidden(XmLGridRow row) { if (!row->grid.height) return True; return False; } static Boolean XmLGridRowIsSelected(XmLGridRow row) { return row->grid.selected; } static void XmLGridRowSetSelected(XmLGridRow row, Boolean selected) { row->grid.selected = selected; } static void XmLGridRowSetVisPos(XmLGridRow row, int visPos) { row->grid.visPos = visPos; } static int XmLGridRowHeightInPixels(XmLGridRow row) { int i, count; Dimension height, maxHeight; XmLGridWidget g; XmLGridCell cell; XmLGridCallbackStruct cbs; XmLGridCellRefValues *cellValues; if (row->grid.sizePolicy == XmCONSTANT) return row->grid.height; if (!row->grid.height) return 0; if (!row->grid.heightInPixelsValid) { g = (XmLGridWidget)row->grid.grid; count = XmLArrayGetCount(row->grid.cellArray); if (!count) { cellValues = g->grid.defCellValues; maxHeight = 4 + row->grid.height * cellValues->fontHeight + cellValues->topMargin + cellValues->bottomMargin; } else maxHeight = 0; for (i = 0; i < count; i++) { cell = (XmLGridCell)XmLArrayGet(row->grid.cellArray, i); cbs.reason = XmCR_PREF_HEIGHT; cbs.rowType = RowPosToType(g, row->grid.pos); cbs.row = RowPosToTypePos(g, cbs.rowType, row->grid.pos); cbs.columnType = ColPosToType(g, i); cbs.column = ColPosToTypePos(g, cbs.columnType, i); cbs.object = (void *)row; height = XmLGridCellAction(cell, (Widget)g, &cbs); if (height > maxHeight) maxHeight = height; } row->grid.heightInPixels = maxHeight; row->grid.heightInPixelsValid = 1; } return row->grid.heightInPixels; } static void XmLGridRowHeightChanged(XmLGridRow row) { row->grid.heightInPixelsValid = 0; } /* XmLGridColumn */ static XmLGridColumn XmLGridColumnNew(Widget grid) { return XmLGridClassPartOfWidget(grid).columnNewProc(grid); } /* Only to be called through Grid class */ static XmLGridColumn _GridColumnNew(Widget grid) { XmLGridWidget g; XmLGridColumn column; int size; g = (XmLGridWidget)grid; size = XmLGridClassPartOfWidget(grid).columnRecSize; column = (XmLGridColumn)malloc(size); column->grid.grid = grid; column->grid.widthInPixels = 0; column->grid.widthInPixelsValid = 0; column->grid.defCellValues = 0; column->grid.selected = False; column->grid.sizePolicy = XmVARIABLE; column->grid.width = 8; column->grid.userData = 0; column->grid.resizable = True; column->grid.hidden = 0; return column; } static void XmLGridColumnFree(Widget grid, XmLGridColumn column) { XmLGridClassPartOfWidget(grid).columnFreeProc(column); } /* Only to be called through Grid class */ static void _GridColumnFree(XmLGridColumn column) { if (column->grid.defCellValues) XmLGridCellDerefValues(column->grid.defCellValues); free((char *)column); } static int XmLGridColumnGetPos(XmLGridColumn column) { return column->grid.pos; } static int XmLGridColumnGetVisPos(XmLGridColumn column) { return column->grid.visPos; } static Boolean XmLGridColumnIsHidden(XmLGridColumn column) { return column->grid.width == 0 || column->grid.hidden; } static Boolean XmLGridColumnIsSelected(XmLGridColumn column) { return column->grid.selected; } static void XmLGridColumnSetSelected(XmLGridColumn column, Boolean selected) { column->grid.selected = selected; } static void XmLGridColumnSetVisPos(XmLGridColumn column, int visPos) { column->grid.visPos = visPos; } static int XmLGridColumnWidthInPixels(XmLGridColumn column) { int i, count; Dimension width, maxWidth; XmLGridCell cell; XmLGridWidget g; XmLGridCallbackStruct cbs; XmLGridCellRefValues *cellValues; if (column->grid.sizePolicy == XmCONSTANT) return column->grid.width; if (!column->grid.width) return 0; if (!column->grid.widthInPixelsValid) { g = (XmLGridWidget)column->grid.grid; count = XmLArrayGetCount(g->grid.rowArray); if (!count) { cellValues = g->grid.defCellValues; maxWidth = 4 + column->grid.width * cellValues->fontWidth + cellValues->leftMargin + cellValues->rightMargin; } else maxWidth = 0; for (i = 0; i < count; i++) { cell = GetCell(g, i, column->grid.pos); cbs.reason = XmCR_PREF_WIDTH; cbs.rowType = RowPosToType(g, i); cbs.row = RowPosToTypePos(g, cbs.rowType, i); cbs.columnType = ColPosToType(g, column->grid.pos); cbs.column = ColPosToTypePos(g, cbs.columnType, column->grid.pos); cbs.object = (void *)column; width = XmLGridCellAction(cell, (Widget)g, &cbs); if (width > maxWidth) maxWidth = width; } column->grid.widthInPixels = maxWidth; column->grid.widthInPixelsValid = 1; } return column->grid.widthInPixels; } static void XmLGridColumnWidthChanged(XmLGridColumn column) { column->grid.widthInPixelsValid = 0; } /* XmLGridCell */ static XmLGridCell XmLGridCellNew(void) { XmLGridCell c; c = (XmLGridCell)malloc(sizeof(struct _XmLGridCellRec)); c->cell.refValues = 0; c->cell.flags = 0; return c; } static void XmLGridCellFree(Widget grid, XmLGridCell cell) { XmLGridCallbackStruct cbs; cbs.reason = XmCR_FREE_VALUE; XmLGridCellAction(cell, grid, &cbs); XmLGridCellDerefValues(cell->cell.refValues); free((char *)cell); } static int XmLGridCellAction(XmLGridCell cell, Widget w, XmLGridCallbackStruct *cbs) { return XmLGridClassPartOfWidget(w).cellActionProc(cell, w, cbs); } /* Only to be called through Grid class */ static int _GridCellAction(XmLGridCell cell, Widget w, XmLGridCallbackStruct *cbs) { int ret; ret = 0; switch (cbs->reason) { case XmCR_CELL_DRAW: _XmLGridCellDrawBackground(cell, w, cbs->clipRect, cbs->drawInfo); _XmLGridCellDrawValue(cell, w, cbs->clipRect, cbs->drawInfo); _XmLGridCellDrawBorders(cell, w, cbs->clipRect, cbs->drawInfo); break; case XmCR_CELL_FOCUS_IN: break; case XmCR_CELL_FOCUS_OUT: break; case XmCR_CONF_TEXT: _XmLGridCellConfigureText(cell, w, cbs->clipRect); break; case XmCR_EDIT_BEGIN: ret = _XmLGridCellBeginTextEdit(cell, w, cbs->clipRect); break; case XmCR_EDIT_CANCEL: break; case XmCR_EDIT_COMPLETE: _XmLGridCellCompleteTextEdit(cell, w); break; case XmCR_EDIT_INSERT: ret = _XmLGridCellBeginTextEdit(cell, w, cbs->clipRect); if (ret) _XmLGridCellInsertText(cell, w); break; case XmCR_FREE_VALUE: _XmLGridCellFreeValue(cell); break; case XmCR_PREF_HEIGHT: ret = _XmLGridCellGetHeight(cell, w,(XmLGridRow)cbs->object); break; case XmCR_PREF_WIDTH: ret = _XmLGridCellGetWidth(cell, w,(XmLGridColumn)cbs->object); break; } return ret; } static XmLGridCellRefValues * XmLGridCellGetRefValues(XmLGridCell cell) { return cell->cell.refValues; } static void XmLGridCellSetRefValues(XmLGridCell cell, XmLGridCellRefValues *values) { values->refCount++; XmLGridCellDerefValues(cell->cell.refValues); cell->cell.refValues = values; } static void XmLGridCellDerefValues(XmLGridCellRefValues *values) { if (!values) return; values->refCount--; if (!values->refCount) { XmFontListFree(values->fontList); free((char *)values); } } static Boolean XmLGridCellInRowSpan(XmLGridCell cell) { if (cell->cell.flags & XmLGridCellInRowSpanFlag) return True; return False; } static Boolean XmLGridCellInColumnSpan(XmLGridCell cell) { if (cell->cell.flags & XmLGridCellInColumnSpanFlag) return True; return False; } static Boolean XmLGridCellIsSelected(XmLGridCell cell) { if (cell->cell.flags & XmLGridCellSelectedFlag) return True; return False; } static Boolean XmLGridCellIsValueSet(XmLGridCell cell) { if (cell->cell.flags & XmLGridCellValueSetFlag) return True; return False; } static void XmLGridCellSetValueSet(XmLGridCell cell, Boolean set) { cell->cell.flags |= XmLGridCellValueSetFlag; if (set != True) cell->cell.flags ^= XmLGridCellValueSetFlag; } static void XmLGridCellSetInRowSpan(XmLGridCell cell, Boolean set) { cell->cell.flags |= XmLGridCellInRowSpanFlag; if (set != True) cell->cell.flags ^= XmLGridCellInRowSpanFlag; } static void XmLGridCellSetInColumnSpan(XmLGridCell cell, Boolean set) { cell->cell.flags |= XmLGridCellInColumnSpanFlag; if (set != True) cell->cell.flags ^= XmLGridCellInColumnSpanFlag; } static void XmLGridCellSetSelected(XmLGridCell cell, Boolean selected) { cell->cell.flags |= XmLGridCellSelectedFlag; if (selected != True) cell->cell.flags ^= XmLGridCellSelectedFlag; } /*Xfe Additions*/ static Boolean XmLGridCellDrawSort(XmLGridCell cell) { if (cell->cell.flags & XmLGridCellDrawSortFlag) return True; return False; } static Boolean XmLGridCellSortAscending(XmLGridCell cell) { if (cell->cell.flags & XmLGridCellSortAscendingFlag) return True; return False; } static void XmLGridCellSetDrawSort(XmLGridCell cell, Boolean drawSort) { cell->cell.flags |= XmLGridCellDrawSortFlag; if (drawSort != True) cell->cell.flags ^= XmLGridCellDrawSortFlag; } static void XmLGridCellSetSortAscending(XmLGridCell cell, Boolean ascending) { cell->cell.flags |= XmLGridCellSortAscendingFlag; if (ascending != True) cell->cell.flags ^= XmLGridCellSortAscendingFlag; } static void XmLGridCellAllocIcon(XmLGridCell cell) { XmLGridCellIcon *icon; icon = (XmLGridCellIcon *)malloc(sizeof(XmLGridCellIcon)); icon->pix.pixmap = XmUNSPECIFIED_PIXMAP; icon->pix.pixmask = XmUNSPECIFIED_PIXMAP; icon->pix.width = 0; icon->pix.height = 0; icon->string = 0; cell->cell.value = (void *)icon; XmLGridCellSetValueSet(cell, True); } static void XmLGridCellAllocPixmap(XmLGridCell cell) { XmLGridCellPixmap *pix; pix = (XmLGridCellPixmap *)malloc(sizeof(XmLGridCellPixmap)); pix->width = 0; pix->height = 0; pix->pixmap = XmUNSPECIFIED_PIXMAP; pix->pixmask = XmUNSPECIFIED_PIXMAP; cell->cell.value = (void *)pix; XmLGridCellSetValueSet(cell, True); } static void XmLGridCellSetString(XmLGridCell cell, XmString string, Boolean copy) { XmLGridCellIcon *icon; if (cell->cell.refValues->type == XmSTRING_CELL) { _XmLGridCellFreeValue(cell); if (string) { if (copy == True) cell->cell.value = (void *)XmStringCopy(string); else cell->cell.value = (void *)string; XmLGridCellSetValueSet(cell, True); } else XmLGridCellSetValueSet(cell, False); } else if (cell->cell.refValues->type == XmICON_CELL) { if (XmLGridCellIsValueSet(cell) == False) XmLGridCellAllocIcon(cell); icon = (XmLGridCellIcon *)cell->cell.value; if (icon->string) XmStringFree(icon->string); if (string && copy == True) icon->string = XmStringCopy(string); else icon->string = string; } else if (string && copy == False) XmStringFree(string); } static XmString XmLGridCellGetString(XmLGridCell cell) { XmString str; str = 0; if (cell->cell.refValues->type == XmSTRING_CELL) { if (XmLGridCellIsValueSet(cell) == True) str = (XmString)cell->cell.value; } else if (cell->cell.refValues->type == XmICON_CELL) { if (XmLGridCellIsValueSet(cell) == True) str = ((XmLGridCellIcon *)cell->cell.value)->string; } return str; } static void XmLGridCellSetToggle(XmLGridCell cell, Boolean state) { if (cell->cell.refValues->type == XmTOGGLE_CELL) { if (state) cell->cell.value = (void *)1; else cell->cell.value = (void *)0; XmLGridCellSetValueSet(cell, True); } } static Boolean XmLGridCellGetToggle(XmLGridCell cell) { Boolean toggled; toggled = False; if (cell->cell.refValues->type == XmTOGGLE_CELL) { if (XmLGridCellIsValueSet(cell) == True && cell->cell.value == (void *)1) toggled = True; } return toggled; } static void XmLGridCellSetPixmap(XmLGridCell cell, Pixmap pixmap, Dimension width, Dimension height) { XmLGridCellPixmap *pix; pix = 0; if (cell->cell.refValues->type == XmPIXMAP_CELL) { if (XmLGridCellIsValueSet(cell) == False) XmLGridCellAllocPixmap(cell); pix = (XmLGridCellPixmap *)cell->cell.value; } else if (cell->cell.refValues->type == XmICON_CELL) { if (XmLGridCellIsValueSet(cell) == False) XmLGridCellAllocIcon(cell); pix = &((XmLGridCellIcon *)cell->cell.value)->pix; } if (!pix) return; pix->pixmap = pixmap; pix->height = height; pix->width = width; } static void XmLGridCellSetPixmask(XmLGridCell cell, Pixmap pixmask) { XmLGridCellPixmap *pix; if (XmLGridCellIsValueSet(cell) == False) { fprintf(stderr, "XmLGridCellSetPixmask: pixmap must be set "); fprintf(stderr, "before pixmask\n"); return; } pix = 0; if (cell->cell.refValues->type == XmPIXMAP_CELL) pix = (XmLGridCellPixmap *)cell->cell.value; else if (cell->cell.refValues->type == XmICON_CELL) pix = &((XmLGridCellIcon *)cell->cell.value)->pix; if (!pix) return; pix->pixmask = pixmask; } static XmLGridCellPixmap * XmLGridCellGetPixmap(XmLGridCell cell) { XmLGridCellPixmap *pix; pix = 0; if (cell->cell.refValues->type == XmPIXMAP_CELL) { if (XmLGridCellIsValueSet(cell) == True) pix = (XmLGridCellPixmap *)cell->cell.value; } else if (cell->cell.refValues->type == XmICON_CELL) { if (XmLGridCellIsValueSet(cell) == True) pix = &((XmLGridCellIcon *)cell->cell.value)->pix; } return pix; } /* Only to be called by XmLGridCellAction() */ void _XmLGridCellDrawBackground(XmLGridCell cell, Widget w, XRectangle *clipRect, XmLGridDrawStruct *ds) { Display *dpy; Window win; dpy = XtDisplay(w); win = XtWindow(w); if (ds->drawSelected == True) XSetForeground(dpy, ds->gc, ds->selectBackground); else XSetForeground(dpy, ds->gc, ds->background); XFillRectangle(dpy, win, ds->gc, clipRect->x, clipRect->y, clipRect->width, clipRect->height); } /* Only to be called by XmLGridCellAction() */ void _XmLGridCellDrawBorders(XmLGridCell cell, Widget w, XRectangle *clipRect, XmLGridDrawStruct *ds) { XmLGridWidget g; Display *dpy; Window win; GC gc; Pixel black, white; int x1, x2, y1, y2, loff, roff; int drawLeft, drawRight, drawBot, drawTop; XRectangle *cellRect; unsigned char borderType; g = (XmLGridWidget)w; dpy = XtDisplay(w); win = XtWindow(w); gc = ds->gc; cellRect = ds->cellRect; black = BlackPixelOfScreen(XtScreen(w)); white = WhitePixelOfScreen(XtScreen(w)); x1 = clipRect->x; x2 = clipRect->x + clipRect->width - 1; y1 = clipRect->y; y2 = clipRect->y + clipRect->height - 1; drawLeft = 1; drawRight = 1; drawBot = 1; drawTop = 1; if (cellRect->x != clipRect->x) drawLeft = 0; if (cellRect->x + cellRect->width != clipRect->x + clipRect->width) drawRight = 0; if (cellRect->y != clipRect->y) drawTop = 0; if (cellRect->y + cellRect->height != clipRect->y + clipRect->height) drawBot = 0; borderType = cell->cell.refValues->rightBorderType; if (borderType != XmBORDER_NONE && drawRight) { if (borderType == XmBORDER_DASH) XSetLineAttributes(dpy, gc, 0, LineOnOffDash, CapButt, JoinMiter); XSetForeground(dpy, gc, cell->cell.refValues->rightBorderColor); XDrawLine(dpy, win, gc, x2, y1, x2, y2); if (borderType == XmBORDER_DASH) XSetLineAttributes(dpy, gc, 0, LineSolid, CapButt, JoinMiter); } borderType = cell->cell.refValues->bottomBorderType; if (borderType != XmBORDER_NONE && drawBot) { if (borderType == XmBORDER_DASH) XSetLineAttributes(dpy, gc, 0, LineOnOffDash, CapButt, JoinMiter); XSetForeground(dpy, gc, cell->cell.refValues->bottomBorderColor); XDrawLine(dpy, win, gc, x1, y2, x2, y2); if (borderType == XmBORDER_DASH) XSetLineAttributes(dpy, gc, 0, LineSolid, CapButt, JoinMiter); } borderType = cell->cell.refValues->topBorderType; if (borderType != XmBORDER_NONE && drawTop) { if (borderType == XmBORDER_DASH) XSetLineAttributes(dpy, gc, 0, LineOnOffDash, CapButt, JoinMiter); XSetForeground(dpy, gc, cell->cell.refValues->topBorderColor); XDrawLine(dpy, win, gc, x1, y1, x2, y1); if (borderType == XmBORDER_DASH) XSetLineAttributes(dpy, gc, 0, LineSolid, CapButt, JoinMiter); } borderType = cell->cell.refValues->leftBorderType; if (borderType != XmBORDER_NONE && drawLeft) { if (borderType == XmBORDER_DASH) XSetLineAttributes(dpy, gc, 0, LineOnOffDash, CapButt, JoinMiter); XSetForeground(dpy, gc, cell->cell.refValues->leftBorderColor); XDrawLine(dpy, win, gc, x1, y1, x1, y2); if (borderType == XmBORDER_DASH) XSetLineAttributes(dpy, gc, 0, LineSolid, CapButt, JoinMiter); } if (ds->drawFocusType == XmDRAW_FOCUS_NONE) return; if (ds->drawFocusType == XmDRAW_FOCUS_LEFT) drawRight = 0; else if (ds->drawFocusType == XmDRAW_FOCUS_RIGHT) drawLeft = 0; else if (ds->drawFocusType == XmDRAW_FOCUS_MID) { drawLeft = 0; drawRight = 0; } if (!drawLeft) loff = 0; else loff = 2; if (!drawRight) roff = 0; else roff = 2; if (g->grid.highlightThickness < 2) return; XSetForeground(dpy, gc, g->manager.highlight_color); if (drawTop) XDrawLine(dpy, win, gc, x1, y1, x2, y1); if (drawLeft) XDrawLine(dpy, win, gc, x1, y1 + 2, x1, y2); if (drawRight) XDrawLine(dpy, win, gc, x2, y1 + 2, x2, y2); if (drawBot) XDrawLine(dpy, win, gc, x1 + loff, y2, x2 - roff, y2); if (drawTop && clipRect->height > 1) XDrawLine(dpy, win, gc, x1, y1 + 1, x2, y1 + 1); if (drawBot && (int)clipRect->height > 1 && (int)clipRect->width > roff && (int)clipRect->width > loff) XDrawLine(dpy, win, gc, x1 + loff, y2 - 1, x2 - roff, y2 - 1); if (clipRect->width > 1 && clipRect->height > 2) { if (drawLeft) XDrawLine(dpy, win, gc, x1 + 1, y1 + 2, x1 + 1, y2); if (drawRight) XDrawLine(dpy, win, gc, x2 - 1, y1 + 2, x2 - 1, y2); } } /* Only to be called by XmLGridCellAction() */ void _XmLGridCellDrawValue(XmLGridCell cell, Widget w, XRectangle *clipRect, XmLGridDrawStruct *ds) { XmLGridWidget g; Display *dpy; XmLGridCellPixmap *pix; XmLGridCellIcon *icon; XRectangle cellRect; XmLGridCellRefValues *cellValues; int type, horizMargin, vertMargin, xoff; g = (XmLGridWidget)w; cellRect = *ds->cellRect; cellValues = cell->cell.refValues; horizMargin = ds->leftMargin + ds->rightMargin; vertMargin = ds->topMargin + ds->bottomMargin; if (horizMargin >= (int)cellRect.width || vertMargin >= (int)cellRect.height) return; type = cellValues->type; cellRect.x += ds->leftMargin; cellRect.y += ds->topMargin; cellRect.width -= horizMargin; cellRect.height -= vertMargin; dpy = XtDisplay(w); if (type == XmSTRING_CELL && XmLGridCellIsValueSet(cell) == True) { if (ds->drawSelected == True) XSetForeground(dpy, ds->gc, ds->selectForeground); else XSetForeground(dpy, ds->gc, ds->foreground); XmLStringDraw(w, (XmString)cell->cell.value, ds->stringDirection, ds->fontList, ds->alignment, ds->gc, &cellRect, clipRect); } if (type == XmPIXMAP_CELL && XmLGridCellIsValueSet(cell) == True) { pix = (XmLGridCellPixmap *)cell->cell.value; XmLPixmapDraw(w, pix->pixmap, pix->pixmask, pix->width, pix->height, ds->alignment, ds->gc, &cellRect, clipRect); } if (type == XmICON_CELL && XmLGridCellIsValueSet(cell) == True) { icon = (XmLGridCellIcon *)cell->cell.value; if (icon->pix.pixmap != XmUNSPECIFIED_PIXMAP) { XmLPixmapDraw(w, icon->pix.pixmap, icon->pix.pixmask, icon->pix.width, icon->pix.height, ds->alignment, ds->gc, &cellRect, clipRect); xoff = icon->pix.width + g->grid.iconSpacing; cellRect.x += xoff; if (xoff < (int)cellRect.width) cellRect.width -= xoff; else cellRect.width = 0; } if (cellRect.width && icon->string) { if (ds->drawSelected == True) XSetForeground(dpy, ds->gc, ds->selectForeground); else XSetForeground(dpy, ds->gc, ds->foreground); XmLStringDraw(w, icon->string, ds->stringDirection, ds->fontList, ds->alignment, ds->gc, &cellRect, clipRect); } } if (type == XmTOGGLE_CELL) XmLDrawToggle(w, XmLGridCellGetToggle(cell), g->grid.toggleSize, ds->alignment, ds->gc, ds->background, g->grid.toggleTopColor, g->grid.toggleBotColor, ds->foreground, &cellRect, clipRect); if (cellRect.width > cellRect.height - 4 && XmLGridCellDrawSort(cell)) { int arrow_direction = XmLGridCellSortAscending(cell); int arrow_size = cellRect.height * 0.75; if (arrow_size > 0) { XSetForeground(dpy, ds->gc, ds->background); _XmDrawArrow(dpy, XtWindow(w), ((XmManagerWidget)g)->manager.bottom_shadow_GC, ((XmManagerWidget)g)->manager.top_shadow_GC, ds->gc, cellRect.x + cellRect.width - arrow_size - 2, cellRect.y + (cellRect.height / 2 - arrow_size / 2), arrow_size, arrow_size, 2, arrow_direction); } } } /* Only to be called by XmLGridCellAction() */ static int _XmLGridCellConfigureText(XmLGridCell cell, Widget w, XRectangle *rect) { XmLGridWidget g; g = (XmLGridWidget)w; XtConfigureWidget(g->grid.text, rect->x, rect->y, rect->width, rect->height, 0); return(0); } /* Only to be called by XmLGridCellAction() */ static int _XmLGridCellBeginTextEdit(XmLGridCell cell, Widget w, XRectangle *clipRect) { XmLGridWidget g = (XmLGridWidget)w; Widget text; if ((cell->cell.refValues->type != XmSTRING_CELL && cell->cell.refValues->type != XmICON_CELL) || cell->cell.refValues->editable != True || g->grid.useTextWidget != True) return 0; XtVaGetValues(w, XmNtextWidget, &text, NULL); XtVaSetValues(text, XmNfontList, cell->cell.refValues->fontList, NULL); return 1; } /* Only to be called by XmLGridCellAction() */ static void _XmLGridCellCompleteTextEdit(XmLGridCell cell, Widget w) { XmLGridWidget g = (XmLGridWidget)w; Widget text; char *s; int i, len; if ((cell->cell.refValues->type != XmSTRING_CELL && cell->cell.refValues->type != XmICON_CELL) || cell->cell.refValues->editable != True || g->grid.useTextWidget != True) return; XtVaGetValues(w, XmNtextWidget, &text, NULL); s = XmTextGetString(text); len = strlen(s); for (i = 0; i < len - 1; i++) if (s[i] == '\\' && s[i + 1] == 'n') { s[i] = '\n'; strcpy(&s[i + 1], &s[i + 2]); } XmLGridCellSetString(cell, XmStringCreateLtoR(s, XmSTRING_DEFAULT_CHARSET), False); #if 0 if (XmLGridCellIsValueSet(cell) == True) XmStringFree((XmString)cell->cell.value); if (strlen(s)) { cell->cell.value = (void *)XmStringCreateLtoR(s, XmSTRING_DEFAULT_CHARSET); XmLGridCellSetValueSet(cell, True); } else XmLGridCellSetValueSet(cell, False); #endif /*0*/ XtFree(s); } /* Only to be called by XmLGridCellAction() */ static void _XmLGridCellInsertText(XmLGridCell cell, Widget w) { XmLGridWidget g = (XmLGridWidget)w; char *s; Widget text = NULL; if ((cell->cell.refValues->type != XmSTRING_CELL && cell->cell.refValues->type != XmICON_CELL) || cell->cell.refValues->editable != True || g->grid.useTextWidget != True) return; XtVaGetValues(w, XmNtextWidget, &text, NULL); s = 0; if (XmLGridCellIsValueSet(cell) == True) s = CvtXmStringToStr(XmLGridCellGetString(cell)); if (s) { XmTextSetString(text, s); free(s); } else XmTextSetString(text, ""); XmTextSetInsertionPosition(text, XmTextGetLastPosition(text)); XmProcessTraversal(text, XmTRAVERSE_CURRENT); } /* Only to be called by XmLGridCellAction() */ static int _XmLGridCellGetHeight(XmLGridCell cell, Widget w, XmLGridRow row) { XmLGridCellPixmap *pix; XmLGridCellIcon *icon; XmLGridCellRefValues *cellValues; int height, pixHeight; cellValues = cell->cell.refValues; height = -1; if (cellValues->type == XmPIXMAP_CELL) { if (XmLGridCellIsValueSet(cell) == True) { pix = (XmLGridCellPixmap *)cell->cell.value; if (pix->height) height = 4 + pix->height + cellValues->topMargin + cellValues->bottomMargin; } } else if (cellValues->type == XmICON_CELL) { pixHeight = 0; if (XmLGridCellIsValueSet(cell) == True) { icon = (XmLGridCellIcon *)cell->cell.value; if (icon->pix.pixmap != XmUNSPECIFIED_PIXMAP && icon->pix.height) pixHeight = 4 + icon->pix.height + cellValues->topMargin + cellValues->bottomMargin; } height = 4 + row->grid.height * cellValues->fontHeight + cellValues->topMargin + cellValues->bottomMargin; if (pixHeight > height) height = pixHeight; } else if (cellValues->type == XmTOGGLE_CELL) height = 4 + 16 + cellValues->topMargin + cellValues->bottomMargin; else if (cellValues->type == XmSTRING_CELL) { height = 4 + row->grid.height * cellValues->fontHeight + cellValues->topMargin + cellValues->bottomMargin; } if (height < 0 || cellValues->rowSpan) height = 4; return height; } /* Only to be called by XmLGridCellAction() */ static int _XmLGridCellGetWidth(XmLGridCell cell, Widget w, XmLGridColumn col) { XmLGridWidget g = (XmLGridWidget)w; XmLGridCellPixmap *pix; XmLGridCellIcon *icon; XmLGridCellRefValues *cellValues; int width; cellValues = cell->cell.refValues; width = -1; if (cellValues->type == XmPIXMAP_CELL) { if (XmLGridCellIsValueSet(cell) == True) { pix = (XmLGridCellPixmap *)cell->cell.value; if (pix->width) width = 4 + pix->width + cellValues->leftMargin + cellValues->rightMargin; } } else if (cellValues->type == XmICON_CELL) { width = 4 + col->grid.width * cellValues->fontWidth + cellValues->leftMargin + cellValues->rightMargin; if (XmLGridCellIsValueSet(cell) == True) { icon = (XmLGridCellIcon *)cell->cell.value; if (icon->pix.pixmap != XmUNSPECIFIED_PIXMAP && icon->pix.width) width += icon->pix.width + g->grid.iconSpacing; } } else if (cellValues->type == XmTOGGLE_CELL) width = 4 + 16 + cellValues->leftMargin + cellValues->rightMargin; else if (cellValues->type == XmSTRING_CELL) width = 4 + col->grid.width * cellValues->fontWidth + cellValues->leftMargin + cellValues->rightMargin; if (width < 0 || cellValues->columnSpan) width = 4; return width; } /* Only to be called by XmLGridCellAction() */ static void _XmLGridCellFreeValue(XmLGridCell cell) { int type; XmLGridCellIcon *icon; if (XmLGridCellIsValueSet(cell) == False) return; type = cell->cell.refValues->type; if (type == XmSTRING_CELL) XmStringFree((XmString)cell->cell.value); else if (type == XmPIXMAP_CELL) free((char *)cell->cell.value); else if (type == XmICON_CELL) { icon = (XmLGridCellIcon *)cell->cell.value; if (icon->string) XmStringFree(icon->string); free((char *)icon); } XmLGridCellSetValueSet(cell, False); } /* Public Functions */ Widget XmLCreateGrid(Widget parent, char *name, ArgList arglist, Cardinal argcount) { return XtCreateWidget(name, xmlGridWidgetClass, parent, arglist, argcount); } void XmLGridAddColumns(Widget w, unsigned char type, int position, int count) { XmLGridWidget g; XmLGridColumn col; XmLGridRow row; XmLGridCell cell; XmLGridCallbackStruct cbs; int i, j, rowCount, hasAddCB, redraw; g = WidgetToGrid(w, "AddColumns()"); if (!g) return; if (count <= 0) return; redraw = 0; position = ColTypePosToPos(g, type, position, 1); if (position < 0) position = ColTypePosToPos(g, type, -1, 1); /* adjust count */ if (type == XmHEADING) { g->grid.headingColCount += count; g->grid.leftFixedCount += count; redraw = 1; } else if (type == XmFOOTER) { g->grid.footerColCount += count; g->grid.rightFixedCount += count; redraw = 1; } else /* XmCONTENT */ g->grid.colCount += count; hasAddCB = 0; if (XtHasCallbacks(w, XmNaddCallback) == XtCallbackHasSome) hasAddCB = 1; /* add columns */ XmLArrayAdd(g->grid.colArray, position, count); for (i = 0; i < count; i++) { col = 0; if (hasAddCB) { cbs.reason = XmCR_ADD_COLUMN; cbs.columnType = type; cbs.object = 0; XtCallCallbackList(w, g->grid.addCallback, (XtPointer)&cbs); col = (XmLGridColumn)cbs.object; } if (!col) col = XmLGridColumnNew(w); XmLArraySet(g->grid.colArray, position + i, col); } /* add cells */ rowCount = XmLArrayGetCount(g->grid.rowArray); for (j = 0; j < rowCount; j++) { row = (XmLGridRow)XmLArrayGet(g->grid.rowArray, j); XmLArrayAdd(XmLGridRowCells(row), position, count); for (i = position; i < position + count; i++) { cell = 0; if (hasAddCB) { cbs.reason = XmCR_ADD_CELL; cbs.rowType = RowPosToType(g, j); cbs.columnType = type; cbs.object = 0; XtCallCallbackList(w, g->grid.addCallback, (XtPointer)&cbs); cell = (XmLGridCell)cbs.object; } if (!cell) cell = XmLGridCellNew(); col = (XmLGridColumn)XmLArrayGet(g->grid.colArray, i); if (col->grid.defCellValues) XmLGridCellSetRefValues(cell, col->grid.defCellValues); else XmLGridCellSetRefValues(cell, g->grid.defCellValues); XmLArraySet(XmLGridRowCells(row), i, cell); } XmLGridRowHeightChanged(row); } for (i = position; i < position + count; i++) { col = (XmLGridColumn)XmLArrayGet(g->grid.colArray, i); XmLGridColumnWidthChanged(col); } /* sanity check */ if (XmLArrayGetCount(g->grid.colArray) != g->grid.headingColCount + g->grid.colCount + g->grid.footerColCount) XmLWarning(w, "AddColumns() - count sanity check failed"); /* maintain scroll and focus position */ if (g->grid.hsPolicy == XmCONSTANT) { if (type == XmCONTENT && g->grid.colCount == count) g->grid.scrollCol = 0; else if (position <= g->grid.scrollCol) g->grid.scrollCol += count; } if (position <= g->grid.focusCol) g->grid.focusCol += count; VisPosChanged(g, 0); HorizLayout(g, 1); VertLayout(g, 1); if (g->grid.focusCol == -1 && type == XmCONTENT) { if (g->grid.focusRow != -1) SetFocus(g, g->grid.focusRow, position, 0, 0); else g->grid.focusCol = position; } for (i = position; i < position + count; i++) redraw |= ColIsVisible(g, i); if (redraw) DrawArea(g, DrawAll, 0, 0); } void XmLGridAddRows(Widget w, unsigned char type, int position, int count) { XmLGridWidget g; XmLGridRow row; XmLGridColumn col; XmLGridCell cell; XmLGridCallbackStruct cbs; int i, j, hasAddCB, redraw, colCount; g = WidgetToGrid(w, "AddRows()"); if (!g) return; if (count <= 0) return; redraw = 0; position = RowTypePosToPos(g, type, position, 1); if (position < 0) position = RowTypePosToPos(g, type, -1, 1); /* adjust count */ if (type == XmHEADING) { g->grid.headingRowCount += count; g->grid.topFixedCount += count; redraw = 1; } else if (type == XmFOOTER) { g->grid.footerRowCount += count; g->grid.bottomFixedCount += count; redraw = 1; } else /* XmCONTENT */ g->grid.rowCount += count; /* add rows and cells */ XmLArrayAdd(g->grid.rowArray, position, count); colCount = XmLArrayGetCount(g->grid.colArray); hasAddCB = 0; if (XtHasCallbacks(w, XmNaddCallback) == XtCallbackHasSome) hasAddCB = 1; for (i = 0; i < count; i++) { row = 0; if (hasAddCB) { cbs.reason = XmCR_ADD_ROW; cbs.rowType = type; cbs.object = 0; XtCallCallbackList(w, g->grid.addCallback, (XtPointer)&cbs); row = (XmLGridRow)cbs.object; } if (!row) row = XmLGridRowNew(w); XmLArraySet(g->grid.rowArray, position + i, row); XmLArrayAdd(XmLGridRowCells(row), 0, colCount); for (j = 0; j < colCount; j++) { cell = 0; if (hasAddCB) { cbs.reason = XmCR_ADD_CELL; cbs.rowType = type; cbs.columnType = ColPosToType(g, j); cbs.object = 0; XtCallCallbackList(w, g->grid.addCallback, (XtPointer)&cbs); cell = (XmLGridCell)cbs.object; } if (!cell) cell = XmLGridCellNew(); col = (XmLGridColumn)XmLArrayGet(g->grid.colArray, j); if (col->grid.defCellValues) XmLGridCellSetRefValues(cell, col->grid.defCellValues); else XmLGridCellSetRefValues(cell, g->grid.defCellValues); XmLArraySet(XmLGridRowCells(row), j, cell); } XmLGridRowHeightChanged(row); } for (j = 0; j < colCount; j++) { col = (XmLGridColumn)XmLArrayGet(g->grid.colArray, j); XmLGridColumnWidthChanged(col); } /* sanity check */ if (XmLArrayGetCount(g->grid.rowArray) != g->grid.headingRowCount + g->grid.rowCount + g->grid.footerRowCount) XmLWarning(w, "AddRows() - count sanity check failed"); /* maintain scroll and focus position */ if (g->grid.vsPolicy == XmCONSTANT) { if (type == XmCONTENT && g->grid.rowCount == count) g->grid.scrollRow = 0; else if (position <= g->grid.scrollRow) g->grid.scrollRow += count; } if (position <= g->grid.focusRow) g->grid.focusRow += count; VisPosChanged(g, 1); HorizLayout(g, 1); VertLayout(g, 1); if (g->grid.focusRow == -1 && type == XmCONTENT) { if (g->grid.focusCol != -1) SetFocus(g, position, g->grid.focusCol, 0, 0); else g->grid.focusRow = position; } for (i = position; i < position + count; i++) redraw |= RowIsVisible(g, i); if (redraw) DrawArea(g, DrawAll, 0, 0); #ifdef XmLEVAL if (g->grid.rowCount > 100) { fprintf(stderr, "XmL: evaluation version only supports <= 100 rows\n"); exit(0); } #endif } void XmLGridDeleteAllColumns(Widget w, unsigned char type) { XmLGridWidget g; int n; g = WidgetToGrid(w, "DeleteAllColumns()"); if (!g) return; if (type == XmHEADING) n = g->grid.headingColCount; else if (type == XmCONTENT) n = g->grid.colCount; else if (type == XmFOOTER) n = g->grid.footerColCount; else { XmLWarning(w, "DeleteAllColumns() - invalid type"); return; } if (!n) return; XmLGridDeleteColumns(w, type, 0, n); } void XmLGridDeleteAllRows(Widget w, unsigned char type) { XmLGridWidget g; int n; g = WidgetToGrid(w, "DeleteAllRows()"); if (!g) return; if (type == XmHEADING) n = g->grid.headingRowCount; else if (type == XmCONTENT) n = g->grid.rowCount; else if (type == XmFOOTER) n = g->grid.footerRowCount; else { XmLWarning(w, "DeleteAllRows() - invalid type"); return; } if (!n) return; XmLGridDeleteRows(w, type, 0, n); } void XmLGridDeselectAllRows(Widget w, Boolean notify) { XmLGridWidget g; g = WidgetToGrid(w, "DeselectAllRows()"); if (!g) return; SelectTypeArea(g, SelectRow, (XEvent *)0, -1, 0, False, notify); } void XmLGridDeselectAllColumns(Widget w, Boolean notify) { XmLGridWidget g; g = WidgetToGrid(w, "DeselectAllColumns()"); if (!g) return; SelectTypeArea(g, SelectCol, (XEvent *)0, 0, -1, False, notify); } void XmLGridDeselectAllCells(Widget w, Boolean notify) { XmLGridWidget g; g = WidgetToGrid(w, "DeselectAllCells()"); if (!g) return; SelectTypeArea(g, SelectCell, (XEvent *)0, -1, -1, False, notify); } void XmLGridDeselectCell(Widget w, int row, int column, Boolean notify) { XmLGridWidget g; g = WidgetToGrid(w, "DeselectCell()"); if (!g) return; SelectTypeArea(g, SelectCell, (XEvent *)0, row, column, False, notify); } void XmLGridDeselectColumn(Widget w, int column, Boolean notify) { XmLGridWidget g; g = WidgetToGrid(w, "DeselectColumn()"); if (!g) return; SelectTypeArea(g, SelectCol, (XEvent *)0, 0, column, False, notify); } void XmLGridDeselectRow(Widget w, int row, Boolean notify) { XmLGridWidget g; g = WidgetToGrid(w, "DeselectRow()"); if (!g) return; SelectTypeArea(g, SelectRow, (XEvent *)0, row, 0, False, notify); } void XmLGridDeleteColumns(Widget w, unsigned char type, int position, int count) { XmLGridWidget g; XmLGridRow row; XmLGridColumn col; XmLGridCallbackStruct cbs; int changeFocus, i, j, rowCount, lastPos, redraw; g = WidgetToGrid(w, "DeleteColumns()"); if (!g) return; if (count <= 0) return; lastPos = ColTypePosToPos(g, type, position + count - 1, 0); position = ColTypePosToPos(g, type, position, 0); if (position < 0 || lastPos < 0) { XmLWarning(w, "DeleteColumns() - invalid position"); return; } changeFocus = 0; if (position <= g->grid.focusCol && lastPos >= g->grid.focusCol) { /* deleting focus col */ TextAction(g, TEXT_EDIT_CANCEL); ChangeFocus(g, g->grid.focusRow, -1); changeFocus = 1; } redraw = 0; if (XtHasCallbacks(w, XmNdeleteCallback) == XtCallbackHasSome) for (i = position; i < position + count; i++) { rowCount = XmLArrayGetCount(g->grid.rowArray); for (j = 0; j < rowCount; j++) { row = (XmLGridRow)XmLArrayGet(g->grid.rowArray, j); cbs.reason = XmCR_DELETE_CELL; cbs.rowType = RowPosToType(g, j); cbs.row = RowPosToTypePos(g, cbs.rowType, i); cbs.columnType = type; cbs.column = RowPosToTypePos(g, cbs.columnType, j); cbs.object = XmLArrayGet(XmLGridRowCells(row), i); XtCallCallbackList(w, g->grid.deleteCallback, (XtPointer)&cbs); } cbs.reason = XmCR_DELETE_COLUMN; cbs.columnType = type; cbs.column = RowPosToTypePos(g, cbs.columnType, i); cbs.object = XmLArrayGet(g->grid.colArray, i); XtCallCallbackList(w, g->grid.deleteCallback, (XtPointer)&cbs); } /* adjust count */ if (type == XmHEADING) { g->grid.headingColCount -= count; g->grid.leftFixedCount -= count; redraw = 1; } else if (type == XmFOOTER) { g->grid.footerColCount -= count; g->grid.rightFixedCount -= count; redraw = 1; } else /* XmCONTENT */ g->grid.colCount -= count; for (i = position; i < position + count; i++) { col = (XmLGridColumn)XmLArrayGet(g->grid.colArray, i); if (XmLGridColumnIsHidden(col) == True) g->grid.hiddenColCount--; redraw |= ColIsVisible(g, i); } /* delete columns */ for (i = position; i < position + count; i++) { col = (XmLGridColumn)XmLArrayGet(g->grid.colArray, i); XmLGridColumnFree(w, col); } XmLArrayDel(g->grid.colArray, position, count); /* delete cells */ rowCount = XmLArrayGetCount(g->grid.rowArray); for (i = 0; i < rowCount; i++) { row = (XmLGridRow)XmLArrayGet(g->grid.rowArray, i); for (j = position; j < position + count; j++) XmLGridCellFree(w, (XmLGridCell)XmLArrayGet(XmLGridRowCells(row), j)); XmLArrayDel(XmLGridRowCells(row), position, count); XmLGridRowHeightChanged(row); } /* sanity check */ if (XmLArrayGetCount(g->grid.colArray) != g->grid.headingColCount + g->grid.colCount + g->grid.footerColCount) XmLWarning(w, "DeleteColumns() - count sanity check failed"); /* maintain scroll and focus position */ if (g->grid.hsPolicy == XmCONSTANT) { if (lastPos < g->grid.scrollCol) g->grid.scrollCol -= count; else if (position <= g->grid.scrollCol) g->grid.scrollCol = position; } if (lastPos < g->grid.focusCol) g->grid.focusCol -= count; VisPosChanged(g, 0); HorizLayout(g, 1); VertLayout(g, 1); if (changeFocus) { SetFocus(g, g->grid.focusRow, position, 0, 1); if (g->grid.focusCol == -1) SetFocus(g, g->grid.focusRow, position, 0, -1); } if (redraw) DrawArea(g, DrawAll, 0, 0); } void XmLGridDeleteRows(Widget w, unsigned char type, int position, int count) { XmLGridWidget g; XmLGridRow row; XmLGridColumn col; XmLGridCallbackStruct cbs; int changeFocus, i, j, colCount, lastPos, redraw; g = WidgetToGrid(w, "DeleteRows()"); if (!g) return; if (count <= 0) return; lastPos = RowTypePosToPos(g, type, position + count - 1, 0); position = RowTypePosToPos(g, type, position, 0); if (position < 0 || lastPos < 0) { XmLWarning(w, "DeleteRows() - invalid position"); return; } changeFocus = 0; if (position <= g->grid.focusRow && lastPos >= g->grid.focusRow) { /* deleting focus row */ TextAction(g, TEXT_EDIT_CANCEL); ChangeFocus(g, -1, g->grid.focusCol); changeFocus = 1; } redraw = 0; if (XtHasCallbacks(w, XmNdeleteCallback) == XtCallbackHasSome) for (i = position; i < position + count; i++) { row = (XmLGridRow)XmLArrayGet(g->grid.rowArray, i); colCount = XmLArrayGetCount(g->grid.colArray); for (j = 0; j < colCount; j++) { cbs.reason = XmCR_DELETE_CELL; cbs.rowType = type; cbs.row = RowPosToTypePos(g, cbs.rowType, i); cbs.columnType = ColPosToType(g, j); cbs.column = ColPosToTypePos(g, cbs.columnType, j); cbs.object = XmLArrayGet(XmLGridRowCells(row), j); XtCallCallbackList(w, g->grid.deleteCallback, (XtPointer)&cbs); } cbs.reason = XmCR_DELETE_ROW; cbs.rowType = type; cbs.row = RowPosToTypePos(g, cbs.rowType, i); cbs.object = (void *)row; XtCallCallbackList(w, g->grid.deleteCallback, (XtPointer)&cbs); } /* adjust count */ if (type == XmHEADING) { g->grid.headingRowCount -= count; g->grid.topFixedCount -= count; redraw = 1; } else if (type == XmFOOTER) { g->grid.footerRowCount -= count; g->grid.bottomFixedCount -= count; redraw = 1; } else /* XmCONTENT */ g->grid.rowCount -= count; for (i = position; i < position + count; i++) { row = (XmLGridRow)XmLArrayGet(g->grid.rowArray, i); if (XmLGridRowIsHidden(row) == True) g->grid.hiddenRowCount--; redraw |= RowIsVisible(g, i); } /* delete rows and cells */ for (i = position; i < position + count; i++) { row = (XmLGridRow)XmLArrayGet(g->grid.rowArray, i); XmLGridRowFree(w, row); } XmLArrayDel(g->grid.rowArray, position, count); colCount = XmLArrayGetCount(g->grid.colArray); for (i = 0; i < colCount; i++) { col = (XmLGridColumn)XmLArrayGet(g->grid.colArray, i); XmLGridColumnWidthChanged(col); } /* sanity check */ if (XmLArrayGetCount(g->grid.rowArray) != g->grid.headingRowCount + g->grid.rowCount + g->grid.footerRowCount) XmLWarning(w, "DeleteRows() - count sanity check failed"); /* maintain scroll and focus position */ if (g->grid.vsPolicy == XmCONSTANT) { if (lastPos < g->grid.scrollRow) g->grid.scrollRow -= count; else if (position <= g->grid.scrollRow) g->grid.scrollRow = position; } if (lastPos < g->grid.focusRow) g->grid.focusRow -= count; VisPosChanged(g, 1); HorizLayout(g, 1); VertLayout(g, 1); if (changeFocus) { SetFocus(g, position, g->grid.focusCol, 1, 0); if (g->grid.focusRow == -1) SetFocus(g, position, g->grid.focusCol, -1, 0); } if (redraw) DrawArea(g, DrawAll, 0, 0); } void XmLGridGetFocus(Widget w, int *row, int *column, Boolean *focusIn) { XmLGridWidget g; unsigned char rowType, colType; g = WidgetToGrid(w, "GetFocus()"); if (!g) return; if (g->grid.focusIn) *focusIn = True; else *focusIn = False; if (g->grid.focusRow < 0 || g->grid.focusCol < 0) { *row = -1; *column = -1; return; } rowType = RowPosToType(g, g->grid.focusRow); colType = ColPosToType(g, g->grid.focusCol); if (rowType != XmCONTENT || colType != XmCONTENT) { *row = -1; *column = -1; XmLWarning(w, "GetFocus() - focus row/column invalid\n"); return; } *row = RowPosToTypePos(g, XmCONTENT, g->grid.focusRow); *column = ColPosToTypePos(g, XmCONTENT, g->grid.focusCol); } XmLGridRow XmLGridGetRow(Widget w, unsigned char rowType, int row) { XmLGridWidget g; XmLGridRow r; int pos; g = WidgetToGrid(w, "GetRow()"); if (!g) return 0; pos = RowTypePosToPos(g, rowType, row, 0); r = (XmLGridRow)XmLArrayGet(g->grid.rowArray, pos); if (!r) XmLWarning(w, "GetRow() - invalid row"); return r; } int XmLGridEditBegin(Widget w, Boolean insert, int row, int column) { XmLGridWidget g; int r, c; XRectangle rect; g = WidgetToGrid(w, "EditBegin()"); if (!g) return -1; if (column < 0 || column >= g->grid.colCount) { XmLWarning(w, "EditBegin() - invalid column"); return -1; } if (row < 0 || row >= g->grid.rowCount) { XmLWarning(w, "EditBegin() - invalid row"); return -1; } r = RowTypePosToPos(g, XmCONTENT, row, 0); c = ColTypePosToPos(g, XmCONTENT, column, 0); if (RowColToXY(g, r, c, True, &rect) == -1) { XmLWarning(w, "EditBegin() - cell must be visible to begin edit"); return -1; } if (SetFocus(g, r, c, 0, 0) == -1) { XmLWarning(w, "EditBegin() - can't set focus to cell"); return -1; } if (insert == False) TextAction(g, TEXT_EDIT); else TextAction(g, TEXT_EDIT_INSERT); return 0; } void XmLGridEditCancel(Widget w) { XmLGridWidget g; g = WidgetToGrid(w, "EditCancel()"); if (!g) return; TextAction(g, TEXT_EDIT_CANCEL); } void XmLGridEditComplete(Widget w) { XmLGridWidget g; g = WidgetToGrid(w, "EditComplete()"); if (!g) return; TextAction(g, TEXT_EDIT_COMPLETE); } XmLGridColumn XmLGridGetColumn(Widget w, unsigned char columnType, int column) { XmLGridWidget g; XmLGridColumn c; int pos; g = WidgetToGrid(w, "GetColumn()"); if (!g) return 0; pos = ColTypePosToPos(g, columnType, column, 0); c = (XmLGridColumn)XmLArrayGet(g->grid.colArray, pos); if (!c) XmLWarning(w, "GetColumn() - invalid column"); return c; } int XmLGridGetSelectedCellCount(Widget w) { XmLGridWidget g; g = WidgetToGrid(w, "GetSelectedCellCount()"); if (!g) return -1; return GetSelectedArea(g, SelectCell, 0, 0, 0); } int XmLGridGetSelectedCells(Widget w, int *rowPositions, int *columnPositions, int count) { XmLGridWidget g; int n; g = WidgetToGrid(w, "GetSelectedCells()"); if (!g) return -1; n = GetSelectedArea(g, SelectCell, rowPositions, columnPositions, count); if (count != n) { XmLWarning(w, "GetSelectedCells() - count is incorrect"); return -1; } return 0; } int XmLGridGetSelectedColumnCount(Widget w) { XmLGridWidget g; g = WidgetToGrid(w, "GetSelectedColumnCount()"); if (!g) return -1; return GetSelectedArea(g, SelectCol, 0, 0, 0); } int XmLGridGetSelectedColumns(Widget w, int *positions, int count) { XmLGridWidget g; int n; g = WidgetToGrid(w, "GetSelectedColumns()"); if (!g) return -1; n = GetSelectedArea(g, SelectCol, 0, positions, count); if (count != n) { XmLWarning(w, "GetSelectedColumns() - count is incorrect"); return -1; } return 0; } int XmLGridGetSelectedRow(Widget w) { XmLGridWidget g; int n, pos; g = WidgetToGrid(w, "GetSelectedRow()"); if (!g) return -1; n = GetSelectedArea(g, SelectRow, &pos, 0, 1); if (n != 1) return -1; return pos; } int XmLGridGetSelectedRowCount(Widget w) { XmLGridWidget g; g = WidgetToGrid(w, "GetSelectedRowCount()"); if (!g) return -1; return GetSelectedArea(g, SelectRow, 0, 0, 0); } int XmLGridGetSelectedRows(Widget w, int *positions, int count) { XmLGridWidget g; int n; g = WidgetToGrid(w, "GetSelectedRows()"); if (!g) return -1; n = GetSelectedArea(g, SelectRow, positions, 0, count); if (count != n) { XmLWarning(w, "GetSelectedRows() - count is incorrect"); return -1; } return 0; } Boolean XmLGridColumnIsVisible(Widget w, int col) { XmLGridWidget g; g = WidgetToGrid(w, "ColumnIsVisible()"); if (!g) return -1; if (!ColIsVisible(g, g->grid.headingColCount + col)) return False; return True; } void XmLGridMoveColumns(Widget w, int newPosition, int position, int count) { XmLGridWidget g; XmLGridRow row; int i, np, p, rowCount; g = WidgetToGrid(w, "MoveColumns()"); if (!g) return; np = ColTypePosToPos(g, XmCONTENT, newPosition, 0); p = ColTypePosToPos(g, XmCONTENT, position, 0); if (XmLArrayMove(g->grid.colArray, np, p, count) == -1) { XmLWarning(w, "MoveColumns() - invalid position"); return; } rowCount = XmLArrayGetCount(g->grid.rowArray); for (i = 0; i < rowCount; i++) { row = XmLArrayGet(g->grid.rowArray, i); XmLArrayMove(XmLGridRowCells(row), np, p, count); } VisPosChanged(g, 0); HorizLayout(g, 1); DrawArea(g, DrawAll, 0, 0); } void XmLGridMoveRows(Widget w, int newPosition, int position, int count) { XmLGridWidget g; int np, p; g = WidgetToGrid(w, "MoveRows()"); if (!g) return; np = RowTypePosToPos(g, XmCONTENT, newPosition, 0); p = RowTypePosToPos(g, XmCONTENT, position, 0); if (XmLArrayMove(g->grid.rowArray, np, p, count) == -1) { XmLWarning(w, "MoveRows() - invalid position/count"); return; } VisPosChanged(g, 1); VertLayout(g, 1); DrawArea(g, DrawAll, 0, 0); } void XmLGridReorderColumns(Widget w, int *newPositions, int position, int count) { XmLGridWidget g; XmLGridRow row; int i, *np, p, rowCount, status; g = WidgetToGrid(w, "ReorderColumns()"); if (!g) return; if (count <= 0) return; p = ColTypePosToPos(g, XmCONTENT, position, 0); np = (int *)malloc(sizeof(int) * count); for (i = 0; i < count; i++) np[i] = ColTypePosToPos(g, XmCONTENT, newPositions[i], 0); status = XmLArrayReorder(g->grid.colArray, np, p, count); if (status < 0) { free((char *)np); XmLWarning(w, "ReorderColumns() - invalid position/count"); return; } rowCount = XmLArrayGetCount(g->grid.rowArray); for (i = 0; i < rowCount; i++) { row = XmLArrayGet(g->grid.rowArray, i); XmLArrayReorder(XmLGridRowCells(row), np, p, count); } free((char *)np); VisPosChanged(g, 0); HorizLayout(g, 1); DrawArea(g, DrawAll, 0, 0); } void XmLGridReorderRows(Widget w, int *newPositions, int position, int count) { XmLGridWidget g; int i, *np, p, status; g = WidgetToGrid(w, "ReorderRows()"); if (!g) return; if (count <= 0) return; p = RowTypePosToPos(g, XmCONTENT, position, 0); np = (int *)malloc(sizeof(int) * count); for (i = 0; i < count; i++) np[i] = RowTypePosToPos(g, XmCONTENT, newPositions[i], 0); status = XmLArrayReorder(g->grid.rowArray, np, p, count); free((char *)np); if (status == -1) { XmLWarning(w, "ReorderRows() - invalid position/count"); return; } VisPosChanged(g, 1); VertLayout(g, 1); DrawArea(g, DrawAll, 0, 0); } int XmLGridRowColumnToXY(Widget w, unsigned char rowType, int row, unsigned char columnType, int column, Boolean clipped, XRectangle *rect) { XmLGridWidget g; int r, c; g = WidgetToGrid(w, "RowColumnToXY()"); if (!g) return -1; r = RowTypePosToPos(g, rowType, row, 0); c = ColTypePosToPos(g, columnType, column, 0); if (r < 0 || r >= XmLArrayGetCount(g->grid.rowArray) || c < 0 || c >= XmLArrayGetCount(g->grid.colArray)) { /* XmLWarning(w, "RowColumnToXY() - invalid position");*/ return -1; } return RowColToXY(g, r, c, clipped, rect); } Boolean XmLGridRowIsVisible(Widget w, int row) { XmLGridWidget g; g = WidgetToGrid(w, "RowIsVisible()"); if (!g) return -1; if (!RowIsVisible(g, g->grid.headingRowCount + row)) return False; return True; } void XmLGridSelectAllRows(Widget w, Boolean notify) { XmLGridWidget g; g = WidgetToGrid(w, "SelectAllRows()"); if (!g) return; SelectTypeArea(g, SelectRow, (XEvent *)0, -1, 0, True, notify); } void XmLGridSelectAllColumns(Widget w, Boolean notify) { XmLGridWidget g; g = WidgetToGrid(w, "SelectAllColumns()"); if (!g) return; SelectTypeArea(g, SelectCol, (XEvent *)0, 0, -1, True, notify); } void XmLGridSelectAllCells(Widget w, Boolean notify) { XmLGridWidget g; g = WidgetToGrid(w, "SelectAllCells()"); if (!g) return; SelectTypeArea(g, SelectCell, (XEvent *)0, -1, -1, True, notify); } void XmLGridSelectCell(Widget w, int row, int column, Boolean notify) { XmLGridWidget g; g = WidgetToGrid(w, "SelectCell()"); if (!g) return; SelectTypeArea(g, SelectCell, (XEvent *)0, row, column, True, notify); } void XmLGridSelectColumn(Widget w, int column, Boolean notify) { XmLGridWidget g; g = WidgetToGrid(w, "SelectColumn()"); if (!g) return; SelectTypeArea(g, SelectCol, (XEvent *)0, 0, column, True, notify); } void XmLGridSelectRow(Widget w, int row, Boolean notify) { XmLGridWidget g; g = WidgetToGrid(w, "SelectRow()"); if (!g) return; SelectTypeArea(g, SelectRow, (XEvent *)0, row, 0, True, notify); } int XmLGridSetFocus(Widget w, int row, int column) { XmLGridWidget g; int r, c; g = WidgetToGrid(w, "SetFocus()"); if (!g) return -1; if (row < 0 || row >= g->grid.rowCount) { XmLWarning(w, "SetFocus() - invalid row"); return -1; } if (column < 0 || column >= g->grid.colCount) { XmLWarning(w, "SetFocus() - invalid column"); return -1; } r = RowTypePosToPos(g, XmCONTENT, row, 0); c = ColTypePosToPos(g, XmCONTENT, column, 0); return SetFocus(g, r, c, 0, 0); } int XmLGridXYToRowColumn(Widget w, int x, int y, unsigned char *rowType, int *row, unsigned char *columnType, int *column) { XmLGridWidget g; int r, c; g = WidgetToGrid(w, "XYToRowColumn()"); if (!g) return -1; if (XYToRowCol(g, x, y, &r, &c) == -1) return -1; *rowType = RowPosToType(g, r); *row = RowPosToTypePos(g, *rowType, r); *columnType = ColPosToType(g, c); *column = ColPosToTypePos(g, *columnType, c); return 0; } void XmLGridRedrawAll(Widget w) { XmLGridWidget g; g = WidgetToGrid(w, "RedrawAll()"); if (!g) return; DrawArea(g, DrawAll, 0, 0); } void XmLGridRedrawCell(Widget w, unsigned char rowType, int row, unsigned char columnType, int column) { XmLGridWidget g; int r, c; g = WidgetToGrid(w, "RedrawCell()"); if (!g) return; r = RowTypePosToPos(g, rowType, row, 0); c = ColTypePosToPos(g, columnType, column, 0); DrawArea(g, DrawCell, r, c); } void XmLGridRedrawColumn(Widget w, unsigned char type, int column) { XmLGridWidget g; int c; g = WidgetToGrid(w, "RedrawColumn()"); if (!g) return; c = ColTypePosToPos(g, type, column, 0); DrawArea(g, DrawCol, 0, c); } void XmLGridRedrawRow(Widget w, unsigned char type, int row) { XmLGridWidget g; int r; g = WidgetToGrid(w, "RedrawRow()"); if (!g) return; r = RowTypePosToPos(g, type, row, 0); DrawArea(g, DrawRow, r, 0); } int XmLGridRead(Widget w, FILE *file, int format, char delimiter) { XmLGridWidget g; char *data; int n; g = WidgetToGrid(w, "Read()"); if (!g) return 0; if (!file) { XmLWarning(w, "Read() - file is NULL"); return 0; } data = FileToString(file); if (!data) { XmLWarning(w, "Read() - error loading file"); return 0; } n = Read(g, format, delimiter, 0, 0, data); free((char *)data); return n; } int XmLGridReadPos(Widget w, FILE *file, int format, char delimiter, unsigned char rowType, int row, unsigned char columnType, int column) { XmLGridWidget g; char *data; int r, c, n; g = WidgetToGrid(w, "ReadPos()"); if (!g) return 0; if (!file) { XmLWarning(w, "ReadPos() - file is NULL"); return 0; } data = FileToString(file); if (!data) { XmLWarning(w, "ReadPos() - error loading file"); return 0; } r = RowTypePosToPos(g, rowType, row, 0); c = ColTypePosToPos(g, columnType, column, 0); n = Read(g, format, delimiter, r, c, data); free((char *)data); return n; } int XmLGridSetStrings(Widget w, char *data) { XmLGridWidget g; g = WidgetToGrid(w, "SetStrings()"); if (!g) return 0; return Read(g, XmFORMAT_DELIMITED, '|', 0, 0, data); } int XmLGridSetStringsPos(Widget w, unsigned char rowType, int row, unsigned char columnType, int column, char *data) { XmLGridWidget g; int r, c; g = WidgetToGrid(w, "SetStringsPos()"); if (!g) return 0; r = RowTypePosToPos(g, rowType, row, 0); c = ColTypePosToPos(g, columnType, column, 0); return Read(g, XmFORMAT_DELIMITED, '|', r, c, data); } int XmLGridWrite(Widget w, FILE *file, int format, char delimiter, Boolean skipHidden) { XmLGridWidget g; int nrow, ncol; g = WidgetToGrid(w, "Write()"); if (!g) return 0; nrow = XmLArrayGetCount(g->grid.rowArray); ncol = XmLArrayGetCount(g->grid.colArray); Write(g, file, format, delimiter, skipHidden, 0, 0, nrow, ncol); return 0; } int XmLGridWritePos(Widget w, FILE *file, int format, char delimiter, Boolean skipHidden, unsigned char rowType, int row, unsigned char columnType, int column, int nrow, int ncolumn) { XmLGridWidget g; int r, c; g = WidgetToGrid(w, "WritePos()"); if (!g) return 0; r = RowTypePosToPos(g, rowType, row, 0); c = ColTypePosToPos(g, columnType, column, 0); Write(g, file, format, delimiter, skipHidden, r, c, nrow, ncolumn); return 0; } Boolean XmLGridCopyPos(Widget w, Time time, unsigned char rowType, int row, unsigned char columnType, int column, int nrow, int ncolumn) { XmLGridWidget g; int r, c; g = WidgetToGrid(w, "CopyPos()"); if (!g) return False; r = RowTypePosToPos(g, rowType, row, 0); c = ColTypePosToPos(g, columnType, column, 0); return Copy(g, time, 0, r, c, nrow, ncolumn); } Boolean XmLGridCopySelected(Widget w, Time time) { XmLGridWidget g; g = WidgetToGrid(w, "CopySelected()"); if (!g) return False; return Copy(g, time, 1, 0, 0, 0, 0); } Boolean XmLGridPaste(Widget w) { XmLGridWidget g; int r, c; g = WidgetToGrid(w, "Paste()"); if (!g) return False; r = g->grid.focusRow; c = g->grid.focusCol; if (r < 0 || c < 0) { XmLWarning(w, "Paste() - no cell has focus"); return False; } return Paste(g, r, c); } Boolean XmLGridPastePos(Widget w, unsigned char rowType, int row, unsigned char columnType, int column) { XmLGridWidget g; int r, c; g = WidgetToGrid(w, "PastePos()"); if (!g) return False; r = RowTypePosToPos(g, rowType, row, 0); c = ColTypePosToPos(g, columnType, column, 0); return Paste(g, r, c); } /* XFE Additions below here */ static void EditTimer(XtPointer clientData, XtIntervalId *intervalId) { XmLGridWidget g; g = (XmLGridWidget)clientData; g->grid.editTimerSet = 0; g->grid.lastSelectTime = 0; TextAction(g,TEXT_EDIT_INSERT); } void XmLGridSetVisibleColumnCount(Widget w, int new_num_visible) { XmLGridWidget g = (XmLGridWidget)w; int ii, num_columns, visible_count; XmLGridColumn colp; visible_count = 0; num_columns = XmLArrayGetCount(g->grid.colArray); if (new_num_visible == 0) return; for (ii = 0; ii < num_columns; ii ++) { colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, ii); if (colp->grid.hidden && visible_count < new_num_visible) { colp->grid.hidden = False; } else if (!colp->grid.hidden && visible_count >= new_num_visible) { colp->grid.hidden = True; } if (!colp->grid.hidden) visible_count++; } if (visible_count < num_columns) g->grid.visibleCols = visible_count; else g->grid.visibleCols = 0; setHideUnhideSensitivity(w); HorizLayout(g, 1); DrawArea(g, DrawAll, 0, 0); } static void HideColumn(Widget w, XtPointer clientData, XtPointer callData) { Widget g = (Widget) clientData; XmLGridHideRightColumn(g); } static void UnhideColumn(Widget w, XtPointer clientData, XtPointer callData) { Widget g = (Widget) clientData; XmLGridUnhideRightColumn(g); } static void CreateHideUnhideButtons(XmLGridWidget g) { if (!g->grid.hideUnhideButtons) { XmLWarning((Widget)g,"CreateHideUnhideButtons - Creating buttons when XmNhideUnhideButtons is False."); return; } g->grid.hideButton = XtVaCreateWidget( "hide", xmDrawnButtonWidgetClass, (Widget)g, XmNhighlightThickness, 0, XmNshadowThickness, 1, XmNtraversalOn, False, XmNbackground, g->core.background_pixel, XmNforeground, g->manager.foreground, XmNtopShadowColor, g->manager.top_shadow_color, XmNbottomShadowColor, g->manager.bottom_shadow_color, NULL); g->grid.unhideButton = XtVaCreateWidget( "unhide", xmDrawnButtonWidgetClass, (Widget)g, XmNhighlightThickness, 0, XmNshadowThickness, 1, XmNtraversalOn, False, XmNbackground, g->core.background_pixel, XmNforeground, g->manager.foreground, XmNtopShadowColor, g->manager.top_shadow_color, XmNbottomShadowColor, g->manager.bottom_shadow_color, NULL); XmLDrawnButtonSetType(g->grid.hideButton, XmDRAWNB_SMALLARROW, XmDRAWNB_RIGHT); XmLDrawnButtonSetType(g->grid.unhideButton, XmDRAWNB_SMALLARROW, XmDRAWNB_LEFT); XtAddCallback(g->grid.hideButton, XmNactivateCallback, HideColumn, (XtPointer)g); XtAddCallback(g->grid.unhideButton, XmNactivateCallback, UnhideColumn, (XtPointer)g); #if 0 XtOverrideTranslations(g->grid.unhideButton, g->grid.unhideButtonTrans); XtOverrideTranslations(g->grid.hideButton, g->grid.hideButtonTrans); #endif /*0*/ } static void HideAction(Widget w, XEvent *event, String *params, Cardinal *num_params) { XmLGridHideRightColumn(w); } static void UnhideAction(Widget w, XEvent *event, String *params, Cardinal *num_params) { XmLGridUnhideRightColumn(w); } static void setHideUnhideSensitivity(Widget w) { XmLGridWidget g = (XmLGridWidget)w; int total_columns = XmLArrayGetCount(g->grid.colArray); Boolean can_unhide, can_hide; if (!g->grid.hideUnhideButtons) return; /* If visibleCols is zero, that means all the columns are visible. */ if (g->grid.visibleCols == 0) { can_unhide = 0; can_hide = (total_columns > 1); } else { can_unhide = (g->grid.visibleCols < total_columns); can_hide = (g->grid.visibleCols > 1); } XtSetSensitive(g->grid.unhideButton, can_unhide); XtSetSensitive(g->grid.hideButton, can_hide); } void XmLGridHideRightColumn(Widget w) { XmLGridWidget g = (XmLGridWidget)w; int total_columns = XmLArrayGetCount(g->grid.colArray); if (total_columns <= 1) return; /* If visibleCols is zero, that means all the columns are visible. */ if (g->grid.visibleCols == 0 || g->grid.visibleCols > total_columns) XmLGridSetVisibleColumnCount(w, total_columns - 1); else XmLGridSetVisibleColumnCount(w, g->grid.visibleCols - 1); } void XmLGridUnhideRightColumn(Widget w) { XmLGridWidget g = (XmLGridWidget)w; int total_columns = XmLArrayGetCount(g->grid.colArray); /* If visibleCols is zero, that means all the columns are visible. */ if ( g->grid.visibleCols != 0 && g->grid.visibleCols < total_columns) XmLGridSetVisibleColumnCount(w, g->grid.visibleCols + 1); } static void MenuArm(Widget w, XEvent *event, String *params, Cardinal *num_params) { XmLGridWidget g = (XmLGridWidget)w; SelectTypeArea(g, SelectRow, (XEvent *)0, g->grid.lastSelectRow, 0, False, False); g->grid.inMode = InSelect; } static void MenuDisarm(Widget w, XEvent *event, String *params, Cardinal *num_params) { XmLGridWidget g = (XmLGridWidget)w; g->grid.inMode = InNormal; } static void ResizeColumnToFit(XmLGridWidget g, int new_x) { XmLGridColumn colp; int width = 0; XRectangle rect; if (!RowColToXY(g, 0, g->grid.resizeCol, False, &rect)) { if (new_x > rect.x) width = (new_x - rect.x) - (rect.width - GetColWidth(g, g->grid.resizeCol)); if (width < g->grid.minColWidth) width = g->grid.minColWidth; /*printf("col(%d) resize_xy(%3d) colx(%3d) colw(%3d) column_width(%3d) new_width(%3d)\n", g->grid.resizeCol, g->grid.resizeLineXY, rect.x, rect.width, GetColWidth(g, g->grid.resizeCol), width);*/ /* Resize all columns to the right */ colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, g->grid.resizeCol); colp->grid.width = width; SizeColumnsToFit(g, g->grid.resizeCol + 1); HorizLayout(g, 0); DrawArea(g, DrawAll, 0, 0); g->grid.resizeLineXY = rect.x + width; } } static int SizeColumnsToFit(XmLGridWidget g, int starting_at) { int resizable_width = 0; int delta = 0; float hidden_col_adjust; int ii, num_columns; XmLGridColumn colp; /* Total the width of the columns and also total how much of that can be resized */ delta = g->core.width; delta -= g->manager.shadow_thickness * 2; if (g->grid.hideUnhideButtons) { delta -= g->grid.unhideButton->core.width; delta -= g->grid.hideButton->core.width; } else if (XtIsManaged(g->grid.vsb)) { delta -= g->grid.vsb->core.width; } num_columns = g->grid.colCount + g->grid.headingColCount + g->grid.footerColCount; for (ii = 0; ii < num_columns; ii ++) { colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, ii); if (colp->grid.sizePolicy != XmCONSTANT) { if (g->grid.debugLevel) XmLWarning((Widget)g, "SizeColumnsToFit() - only valid for XmNcolumnSizePolicy == XmCONSTANT"); colp->grid.sizePolicy = XmCONSTANT; } if (!g->grid.visibleCols || ii < g->grid.visibleCols) { delta -= colp->grid.width; if (ii >= starting_at && colp->grid.resizable) resizable_width += colp->grid.width; } } if (delta == 0 || resizable_width <= 0) return delta; if (g->grid.debugLevel) { fprintf(stderr,"Applying delta(%d) from %d to %d (%d resizable)\n", delta, starting_at, num_columns - 1, resizable_width); } hidden_col_adjust = (float)delta / resizable_width; /* Adjust each column to fit based on its percentage of the total width */ for (ii = starting_at; ii < num_columns ; ii ++) { int col_width; int col_delta; int new_col_width; colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, ii); col_width = colp->grid.width; if (!colp->grid.resizable || col_width == 0) continue; if (colp->grid.hidden) col_delta = (int)(hidden_col_adjust * col_width); else if (col_width < resizable_width && resizable_width > 0) col_delta = delta * ((float)col_width / resizable_width); else col_delta = delta; new_col_width = col_width + col_delta; if (new_col_width < g->grid.minColWidth) { new_col_width = g->grid.minColWidth; col_delta = col_width - new_col_width; } if (!colp->grid.hidden) { delta -= col_delta; resizable_width -= col_width; } colp->grid.width = new_col_width; if (g->grid.debugLevel) fprintf (stderr, "Column %d, width %d -> %d, new delta %d, new resizable width %d\n", ii, col_width, new_col_width, delta, resizable_width); } return delta; } void XmLGridGetSort(Widget w, int *column, unsigned char *sortType) { XmLGridWidget g = (XmLGridWidget)w; XmLGridColumn colp; int num_columns = XmLArrayGetCount(g->grid.colArray); int ii; *column = 0; *sortType = XmSORT_NONE; for (ii = 0; ii < num_columns; ii ++) { colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, ii); if (colp && colp->grid.sort != XmSORT_NONE) { *column = ii; *sortType = colp->grid.sort; break; } } } void XmLGridSetSort(Widget w, int column, unsigned char sortType) { XmLGridWidget g = (XmLGridWidget)w; XmLGridRow rowp; XmLGridColumn colp; XmLGridCell cellp; int old_sort_column; unsigned char old_sort_type; /*printf("XmLGridSetSort: (%d,%s)\n", column, sortType == XmSORT_NONE ? "none" : sortType == XmSORT_ASCENDING ? "ascending" : "descending"); */ /* Clear old sort resource */ XmLGridGetSort(w, &old_sort_column, &old_sort_type); if (old_sort_type != XmSORT_NONE) { colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, old_sort_column); if (colp) colp->grid.sort = XmSORT_NONE; } colp = (XmLGridColumn)XmLArrayGet(g->grid.colArray, column); colp->grid.sort = sortType; /* Clear any existing cell sort masks. */ rowp = (XmLGridRow)XmLArrayGet(g->grid.rowArray, 0); if (rowp) { int ii, count; count = XmLArrayGetCount(rowp->grid.cellArray); for (ii = 0; ii < count; ii++) { cellp = (XmLGridCell)XmLArrayGet(rowp->grid.cellArray, ii); if (XmLGridCellDrawSort(cellp)) { DrawArea(g, DrawCell, 0, ii); XmLGridCellSetDrawSort(cellp, False); } } } /* Set the cell mask of the heading cell. */ cellp = GetCell(g, 0, column); if (cellp) { XmLGridCellSetDrawSort(cellp, True); if (sortType == XmSORT_NONE) XmLGridCellSetDrawSort(cellp, False); else if (sortType == XmSORT_ASCENDING) XmLGridCellSetSortAscending(cellp, True); else if (sortType == XmSORT_DESCENDING) XmLGridCellSetSortAscending(cellp, False); DrawArea(g, DrawCell, 0, column); } } /*----------------------------------------------------------------------*/ static void GridInvokeCallbacks(Widget w, XtCallbackList list, int reason, XEvent * event) { XmLGridWidget g = (XmLGridWidget)w; /* Make sure widget is alive and callback list is not NULL */ if (!g->core.being_destroyed && list) { XmAnyCallbackStruct cbs; cbs.event = event; cbs.reason = reason; /* Invoke the Callback List */ XtCallCallbackList(w,list,&cbs); } } /*----------------------------------------------------------------------*/ static void GridInvokeCellCrossingCallbacks(Widget w, XtCallbackList list, int reason, XEvent * event, int row, int col) { XmLGridWidget g = (XmLGridWidget)w; /* Make sure widget is alive and callback list is not NULL */ if (!g->core.being_destroyed && list) { if (row != -1 && col != -1) { XmLGridCell cell; XmLGridCallbackStruct cbs; cell = GetCell(g, row, col); if (cell) { cbs.reason = XmCR_CELL_FOCUS_OUT; cbs.columnType = ColPosToType(g, col); cbs.column = ColPosToTypePos(g, cbs.columnType, col); cbs.rowType = RowPosToType(g, row); cbs.row = RowPosToTypePos(g, cbs.rowType, row); /* XmLGridCellAction(cell, (Widget)g, &cbs); */ /* Invoke the Callback List */ XtCallCallbackList(w,list,&cbs); } } } } /*----------------------------------------------------------------------*/ static void GridCrossingEH(Widget w, XtPointer closure, XEvent * event, Boolean * ctd) { XmLGridWidget g = (XmLGridWidget)w; if (event) { if (event->type == EnterNotify) { /* Invoke XmNenterGridCallback */ GridInvokeCallbacks(w, g->grid.enterGridCallback, XmCR_ENTER_GRID, event); /* printf("Enter(%s)\n",XtName(w)); */ } else if (event->type == LeaveNotify) { g->grid.lastCursorMotionRow = -1; g->grid.lastCursorMotionCol = -1; /* Invoke XmNleaveGridCallback */ GridInvokeCallbacks(w, g->grid.leaveGridCallback, XmCR_LEAVE_GRID, event); /* printf("Leave(%s)\n",XtName(w)); */ } } *ctd = True; } /*----------------------------------------------------------------------*/ nedit-5.6.orig/Microline/XmL/Grid.h0000644000175000017500000001743410245647600015606 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #ifndef XmLGridH #define XmLGridH #include "XmL.h" #include #ifdef XmL_CPP extern "C" { #endif extern WidgetClass xmlGridWidgetClass; typedef struct _XmLGridClassRec *XmLGridWidgetClass; typedef struct _XmLGridRec *XmLGridWidget; typedef struct _XmLGridRowRec *XmLGridRow; typedef struct _XmLGridColumnRec *XmLGridColumn; typedef struct _XmLGridCellRec *XmLGridCell; #define XmLIsGrid(w) XtIsSubclass((w), xmlGridWidgetClass) Widget XmLCreateGrid(Widget parent, char *name, ArgList arglist, Cardinal argcount); void XmLGridAddColumns(Widget w, unsigned char type, int position, int count); void XmLGridAddRows(Widget w, unsigned char type, int position, int count); Boolean XmLGridColumnIsVisible(Widget w, int column); Boolean XmLGridCopyPos(Widget w, Time time, unsigned char rowType, int row, unsigned char columnType, int column, int nrow, int ncolumn); Boolean XmLGridCopySelected(Widget w, Time time); void XmLGridDeleteAllColumns(Widget w, unsigned char type); void XmLGridDeleteAllRows(Widget w, unsigned char type); void XmLGridDeleteColumns(Widget w, unsigned char type, int position, int count); void XmLGridDeleteRows(Widget w, unsigned char type, int position, int count); void XmLGridDeselectAllCells(Widget w, Boolean notify); void XmLGridDeselectAllColumns(Widget w, Boolean notify); void XmLGridDeselectAllRows(Widget w, Boolean notify); void XmLGridDeselectCell(Widget w, int row, int column, Boolean notify); void XmLGridDeselectColumn(Widget w, int column, Boolean notify); void XmLGridDeselectRow(Widget w, int row, Boolean notify); int XmLGridEditBegin(Widget w, Boolean insert, int row, int column); void XmLGridEditCancel(Widget w); void XmLGridEditComplete(Widget w); XmLGridColumn XmLGridGetColumn(Widget w, unsigned char columnType, int column); void XmLGridGetFocus(Widget w, int *row, int *column, Boolean *focusIn); XmLGridRow XmLGridGetRow(Widget w, unsigned char rowType, int row); int XmLGridGetSelectedCellCount(Widget w); int XmLGridGetSelectedCells(Widget w, int *rowPositions, int *columnPositions, int count); int XmLGridGetSelectedColumnCount(Widget w); int XmLGridGetSelectedColumns(Widget w, int *positions, int count); int XmLGridGetSelectedRow(Widget w); int XmLGridGetSelectedRowCount(Widget w); int XmLGridGetSelectedRows(Widget w, int *positions, int count); void XmLGridMoveColumns(Widget w, int newPosition, int position, int count); void XmLGridMoveRows(Widget w, int newPosition, int position, int count); Boolean XmLGridPaste(Widget w); Boolean XmLGridPastePos(Widget w, unsigned char rowType, int row, unsigned char columnType, int column); int XmLGridRead(Widget w, FILE *file, int format, char delimiter); int XmLGridReadPos(Widget w, FILE *file, int format, char delimiter, unsigned char rowType, int row, unsigned char columnType, int column); void XmLGridRedrawAll(Widget w); void XmLGridRedrawCell(Widget w, unsigned char rowType, int row, unsigned char columnType, int column); void XmLGridRedrawColumn(Widget w, unsigned char type, int column); void XmLGridRedrawRow(Widget w, unsigned char type, int row); void XmLGridReorderColumns(Widget w, int *newPositions, int position, int count); void XmLGridReorderRows(Widget w, int *newPositions, int position, int count); int XmLGridRowColumnToXY(Widget w, unsigned char rowType, int row, unsigned char columnType, int column, Boolean clipped, XRectangle *rect); Boolean XmLGridRowIsVisible(Widget w, int row); void XmLGridSelectAllCells(Widget w, Boolean notify); void XmLGridSelectAllColumns(Widget w, Boolean notify); void XmLGridSelectAllRows(Widget w, Boolean notify); void XmLGridSelectCell(Widget w, int row, int column, Boolean notify); void XmLGridSelectColumn(Widget w, int column, Boolean notify); void XmLGridSelectRow(Widget w, int row, Boolean notify); int XmLGridSetFocus(Widget w, int row, int column); int XmLGridSetStrings(Widget w, char *data); int XmLGridSetStringsPos(Widget w, unsigned char rowType, int row, unsigned char columnType, int column, char *data); int XmLGridWrite(Widget w, FILE *file, int format, char delimiter, Boolean skipHidden); int XmLGridWritePos(Widget w, FILE *file, int format, char delimiter, Boolean skipHidden, unsigned char rowType, int row, unsigned char columnType, int column, int nrow, int ncolumn); int XmLGridXYToRowColumn(Widget w, int x, int y, unsigned char *rowType, int *row, unsigned char *columnType, int *column); int XmLGridPosIsResize(Widget g, int x, int y); void XmLGridSetVisibleColumnCount(Widget w, int num_visible); void XmLGridHideRightColumn(Widget w); void XmLGridUnhideRightColumn(Widget w); int XmLGridGetRowCount(Widget w); int XmLGridGetColumnCount(Widget w); /* extern */ void XmLGridXYToCellTracking(Widget widget, int x, /* input only args. */ int y, /* input only args. */ Boolean * m_inGrid, /* input/output args. */ int * m_lastRow, /* input/output args. */ int * m_lastCol, /* input/output args. */ unsigned char * m_lastRowtype,/* input/output args. */ unsigned char * m_lastColtype,/* input/output args. */ int * outRow, /* output only args. */ int * outCol, /* output only args. */ Boolean * enter, /* output only args. */ Boolean * leave); /* output only args. */ void XmLGridGetSort(Widget w, int *column, unsigned char *sortType); void XmLGridSetSort(Widget w, int column, unsigned char sortType); #ifdef XmL_CPP } #endif #endif nedit-5.6.orig/Microline/XmL/GridP.h0000644000175000017500000003562610077552126015732 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #ifndef XmLGridPH #define XmLGridPH #include #include #ifndef MOTIF11 #include #include #include #include #endif #include "Grid.h" #ifdef XmL_ANSIC void _XmLGridLayout(XmLGridWidget g); void _XmLGridCellDrawBackground(XmLGridCell cell, Widget w, XRectangle *clipRect, XmLGridDrawStruct *ds); void _XmLGridCellDrawBorders(XmLGridCell cell, Widget w, XRectangle *clipRect, XmLGridDrawStruct *ds); void _XmLGridCellDrawValue(XmLGridCell cell, Widget w, XRectangle *clipRect, XmLGridDrawStruct *ds); typedef int (*XmLGridPreLayoutProc)(XmLGridWidget g, int isVert); typedef XmLGridRow (*XmLGridRowNewProc)(Widget grid); typedef void (*XmLGridRowFreeProc)(XmLGridRow); typedef void (*XmLGridGetRowValueMaskProc)(XmLGridWidget g, char *s, long *mask); typedef void (*XmLGridGetRowValueProc)(XmLGridWidget g, XmLGridRow row, XtArgVal value, long mask); typedef int (*XmLGridSetRowValuesProc)(XmLGridWidget g, XmLGridRow row, long mask); typedef XmLGridColumn (*XmLGridColumnNewProc)(Widget grid); typedef void (*XmLGridColumnFreeProc)(XmLGridColumn); typedef void (*XmLGridGetColumnValueMaskProc)(XmLGridWidget g, char *s, long *mask); typedef void (*XmLGridGetColumnValueProc)(XmLGridWidget g, XmLGridColumn col, XtArgVal value, long mask); typedef int (*XmLGridSetColumnValuesProc)(XmLGridWidget g, XmLGridColumn col, long mask); typedef int (*XmLGridSetCellValuesResizeProc)(XmLGridWidget g, XmLGridRow row, XmLGridColumn col, XmLGridCell cell, long mask); typedef int (*XmLGridCellActionProc)(XmLGridCell, Widget, XmLGridCallbackStruct *); #else void _XmLGridLayout(); void _XmLGridCellDrawBackground(); void _XmLGridCellDrawBorders(); void _XmLGridCellDrawValue(); typedef int (*XmLGridPreLayoutProc)(); typedef XmLGridRow (*XmLGridRowNewProc)(); typedef void (*XmLGridRowFreeProc)() ; typedef void (*XmLGridGetRowValueMaskProc)(); typedef void (*XmLGridGetRowValueProc)(); typedef int (*XmLGridSetRowValuesProc)(); typedef XmLGridColumn (*XmLGridColumnNewProc)() ; typedef void (*XmLGridColumnFreeProc)() ; typedef void (*XmLGridGetColumnValueMaskProc)(); typedef void (*XmLGridGetColumnValueProc)(); typedef int (*XmLGridSetColumnValuesProc)(); typedef int (*XmLGridSetCellValuesResizeProc)(); typedef int (*XmLGridCellActionProc)(); #endif #define XmLGridClassPartOfWidget(w) \ ((XmLGridWidgetClass)XtClass(w))->grid_class #define XmInheritGridPreLayout ((XmLGridPreLayoutProc)_XtInherit) #define XmInheritGridRowNew ((XmLGridRowNewProc)_XtInherit) #define XmInheritGridRowFree ((XmLGridRowFreeProc)_XtInherit) #define XmInheritGridGetRowValueMask ((XmLGridGetRowValueMaskProc)_XtInherit) #define XmInheritGridGetRowValue ((XmLGridGetRowValueProc)_XtInherit) #define XmInheritGridSetRowValues ((XmLGridSetRowValuesProc)_XtInherit) #define XmInheritGridColumnNew ((XmLGridColumnNewProc)_XtInherit) #define XmInheritGridColumnFree ((XmLGridColumnFreeProc)_XtInherit) #define XmInheritGridGetColumnValueMask \ ((XmLGridGetColumnValueMaskProc)_XtInherit) #define XmInheritGridGetColumnValue ((XmLGridGetColumnValueProc)_XtInherit) #define XmInheritGridSetColumnValues ((XmLGridSetColumnValuesProc)_XtInherit) #define XmInheritGridSetCellValuesResize \ ((XmLGridSetCellValuesResizeProc)_XtInherit) #define XmInheritGridCellAction ((XmLGridCellActionProc)_XtInherit) /* row value mask for get/set values */ #define XmLGridRowHeight (1L<<0) #define XmLGridRowSizePolicy (1L<<1) #define XmLGridRowUserData (1L<<2) #define XmLGridRowValueMaskLen 3 /* column value mask for get/set values */ #define XmLGridColumnWidth (1L<<0) #define XmLGridColumnSizePolicy (1L<<1) #define XmLGridColumnUserData (1L<<2) #define XmLGridColumnResizable (1L<<3) #define XmLGridColumnHidden (1L<<4) #define XmLGridColumnSortType (1L<<5) #define XmLGridColumnValueMaskLen 6 /* flags for XmLGridCell flags member */ #define XmLGridCellSelectedFlag (1 << 0) #define XmLGridCellValueSetFlag (1 << 1) #define XmLGridCellInRowSpanFlag (1 << 2) #define XmLGridCellInColumnSpanFlag (1 << 3) #define XmLGridCellDrawSortFlag (1 << 4) #define XmLGridCellSortAscendingFlag (1 << 5) /* cell value mask for get/set values */ #define XmLGridCellAlignment (1L<<0) #define XmLGridCellBackground (1L<<1) #define XmLGridCellBottomBorderColor (1L<<2) #define XmLGridCellBottomBorderType (1L<<3) #define XmLGridCellColumnSpan (1L<<4) #define XmLGridCellEditable (1L<<5) #define XmLGridCellFontList (1L<<6) #define XmLGridCellForeground (1L<<7) #define XmLGridCellLeftBorderColor (1L<<8) #define XmLGridCellLeftBorderType (1L<<9) #define XmLGridCellMarginBottom (1L<<10) #define XmLGridCellMarginLeft (1L<<11) #define XmLGridCellMarginRight (1L<<12) #define XmLGridCellMarginTop (1L<<13) #define XmLGridCellPixmapF (1L<<14) #define XmLGridCellPixmapMask (1L<<15) #define XmLGridCellRightBorderColor (1L<<16) #define XmLGridCellRightBorderType (1L<<17) #define XmLGridCellRowSpan (1L<<18) #define XmLGridCellString (1L<<19) #define XmLGridCellToggleSet (1L<<20) #define XmLGridCellTopBorderColor (1L<<21) #define XmLGridCellTopBorderType (1L<<22) #define XmLGridCellType (1L<<23) #define XmLGridCellUserData (1L<<24) /* This is now a resource */ /* #define XmLICON_SPACING 4 */ enum { DrawAll, DrawHScroll, DrawVScroll, DrawRow, DrawCol, DrawCell }; enum { SelectRow, SelectCol, SelectCell }; enum { CursorNormal, CursorHResize, CursorVResize }; enum { InNormal, InSelect, InResize, InMove }; enum { DragLeft = 1, DragRight = 2, DragUp = 4, DragDown = 8 }; typedef struct { int x, y, width, height; int row, col, nrow, ncol; } GridReg; typedef struct { int row, col; } GridDropLoc; typedef struct { unsigned char alignment; Pixel background; Pixel bottomBorderColor; char bottomBorderType; Dimension bottomMargin; int columnSpan; Boolean editable; short fontHeight; XmFontList fontList; short fontWidth; Pixel foreground; Pixel leftBorderColor; char leftBorderType; Dimension leftMargin; int refCount; Pixel rightBorderColor; char rightBorderType; Dimension rightMargin; int rowSpan; Pixel topBorderColor; char topBorderType; Dimension topMargin; unsigned char type; void *userData; } XmLGridCellRefValues; typedef struct { Pixmap pixmap, pixmask; Dimension width, height; } XmLGridCellPixmap; typedef struct { XmString string; XmLGridCellPixmap pix; } XmLGridCellIcon; typedef struct _XmLGridCellPart { XmLGridCellRefValues *refValues; unsigned char flags; void *value; } XmLGridCellPart; struct _XmLGridCellRec { XmLGridCellPart cell; }; typedef struct _XmLGridRowPart { int pos; /* required first for Array autonumber */ Dimension height; unsigned char sizePolicy; Boolean selected; XtPointer userData; Dimension heightInPixels; unsigned int heightInPixelsValid:1; Widget grid; int visPos; XmLArray cellArray; } XmLGridRowPart; struct _XmLGridRowRec { XmLGridRowPart grid; }; typedef struct _XmLGridColumnPart { int pos; /* required first for Array autonumber */ Dimension width; unsigned char sizePolicy; Boolean selected; XtPointer userData; XmLGridCellRefValues *defCellValues; Widget grid; Dimension widthInPixels; unsigned int widthInPixelsValid:1; Boolean resizable; int visPos; /* xfe additions */ Boolean hidden; unsigned char sort; } XmLGridColumnPart; struct _XmLGridColumnRec { XmLGridColumnPart grid; }; typedef struct _XmLGridPart { /* resource values */ int leftFixedCount, rightFixedCount; int headingRowCount, footerRowCount; int topFixedCount, bottomFixedCount; int headingColCount, footerColCount; Dimension leftFixedMargin, rightFixedMargin; Dimension topFixedMargin, bottomFixedMargin; Dimension scrollBarMargin; Dimension highlightThickness; Dimension toggleSize; Dimension globalPixmapWidth, globalPixmapHeight; unsigned char selectionPolicy; Boolean layoutFrozen, immediateDraw; int debugLevel; unsigned char vsPolicy, hsPolicy; unsigned char hsbDisplayPolicy, vsbDisplayPolicy; int rowCount, colCount; int hiddenRowCount, hiddenColCount; int shadowRegions; unsigned char shadowType; Widget hsb, vsb, text; XmFontList fontList; Pixel blankBg, selectBg, selectFg; Pixel defaultCellBg, defaultCellFg; Pixel toggleTopColor, toggleBotColor; int visibleCols, visibleRows; char *simpleHeadings, *simpleWidths; XtTranslations editTrans, traverseTrans; Boolean allowRowHide, allowColHide; Boolean allowRowResize, allowColResize; Boolean allowDrag, allowDrop; Boolean autoSelect; Boolean highlightRowMode; Boolean useAvgWidth; int scrollRow, scrollCol, cScrollRow, cScrollCol; XtCallbackList addCallback, deleteCallback; XtCallbackList cellDrawCallback, cellFocusCallback; XtCallbackList cellDropCallback, cellPasteCallback; XtCallbackList activateCallback, editCallback; XtCallbackList selectCallback, deselectCallback; XtCallbackList resizeCallback, scrollCallback; XtCallbackList enterCellCallback; XtCallbackList leaveCellCallback; XtCallbackList enterGridCallback; XtCallbackList leaveGridCallback; /* XFE Additions */ XtCallbackList popupCallback; Boolean hideUnhideButtons; Boolean singleClickActivation; Widget hideButton; Widget unhideButton; XtTranslations hideButtonTrans; XtTranslations unhideButtonTrans; Boolean inResize; Boolean useTextWidget; Dimension iconSpacing; Dimension minColWidth; int lastCursorMotionRow; int lastCursorMotionCol; unsigned char colSortType; /* private data */ GC gc; Cursor hResizeCursor, vResizeCursor; XFontStruct *fallbackFont; char ignoreModifyVerify; char focusIn, inEdit, inMode; char singleColScrollMode; int singleColScrollPos; char cursorDefined, textHidden, resizeIsVert; char mayHaveRowSpans; int layoutStack; char needsHorizLayout, needsVertLayout; char recalcHorizVisPos, recalcVertVisPos; char vertVisChangedHint; char dragTimerSet; XtIntervalId dragTimerId; int resizeRow, resizeCol, resizeLineXY; int extendRow, extendCol, extendToRow, extendToCol; Boolean extendSelect; int lastSelectRow, lastSelectCol; Time lastSelectTime; int focusRow, focusCol; XmLArray rowArray; XmLArray colArray; GridReg reg[9]; GridDropLoc dropLoc; /* resources use by SetSubValues and GetSubValues */ Boolean cellDefaults; int cellRow, cellCol; int cellColRangeStart, cellColRangeEnd; int cellRowRangeStart, cellRowRangeEnd; int rowStep, colStep; unsigned char rowType, colType; Boolean colHidden; /* cell resources */ XmString cellString; Boolean cellToggleSet; Pixmap cellPixmap, cellPixmapMask; Dimension cellPixmapWidth, cellPixmapHeight; XmLGridCellRefValues cellValues, *defCellValues; /* row resources */ Dimension rowHeight; unsigned char rowSizePolicy; Boolean rowSelected; XtPointer rowUserData; /* column resources */ Dimension colWidth; unsigned char colSizePolicy; Boolean colSelected; XtPointer colUserData; Boolean colResizable; /* xfe additions */ /* Edit timer is used for inplace editing */ char editTimerSet; XtIntervalId editTimerId; } XmLGridPart; typedef struct _XmLGridRec { CorePart core; CompositePart composite; ConstraintPart constraint; XmManagerPart manager; XmLGridPart grid; } XmLGridRec; typedef struct _XmLGridClassPart { int initialRows; int initialCols; XmLGridPreLayoutProc preLayoutProc; int rowRecSize; XmLGridRowNewProc rowNewProc; XmLGridRowFreeProc rowFreeProc; XmLGridGetRowValueMaskProc getRowValueMaskProc; XmLGridGetRowValueProc getRowValueProc; XmLGridSetRowValuesProc setRowValuesProc; int columnRecSize; XmLGridColumnNewProc columnNewProc; XmLGridColumnFreeProc columnFreeProc; XmLGridGetColumnValueMaskProc getColumnValueMaskProc; XmLGridGetColumnValueProc getColumnValueProc; XmLGridSetColumnValuesProc setColumnValuesProc; XmLGridSetCellValuesResizeProc setCellValuesResizeProc; XmLGridCellActionProc cellActionProc; } XmLGridClassPart; typedef struct _XmLGridClassRec { CoreClassPart core_class; CompositeClassPart composite_class; ConstraintClassPart constraint_class; XmManagerClassPart manager_class; XmLGridClassPart grid_class; } XmLGridClassRec; extern XmLGridClassRec xmlGridClassRec; typedef struct _XmLGridConstraintPart { int unused; } XmLGridConstraintPart; typedef struct _XmLGridConstraintRec { XmManagerConstraintPart manager; XmLGridConstraintPart grid; } XmLGridConstraintRec, *XmLGridConstraintPtr; #endif nedit-5.6.orig/Microline/XmL/GridUtil.c0000644000175000017500000001310410077552126016426 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ /*----------------------------------------------------------------------*/ /* */ /* Name: */ /* */ /* Description: XmLGrid misc utilities. They are here in order not to */ /* continue bloating Grid.c beyond hope. */ /* */ /* Author: Ramiro Estrugo */ /* */ /* Created: Thu May 28 21:55:45 PDT 1998 */ /* */ /*----------------------------------------------------------------------*/ #include "GridP.h" #include /*----------------------------------------------------------------------*/ /* extern */ int XmLGridGetRowCount(Widget w) { XmLGridWidget g = (XmLGridWidget) w; assert( g != NULL ); #ifdef DEBUG_ramiro { int rows = 0; XtVaGetValues(w,XmNrows,&rows,NULL); assert( rows == g->grid.rowCount ); } #endif return g->grid.rowCount; } /*----------------------------------------------------------------------*/ /* extern */ int XmLGridGetColumnCount(Widget w) { XmLGridWidget g = (XmLGridWidget) w; assert( g != NULL ); #ifdef DEBUG_ramiro { int columns = 0; XtVaGetValues(w,XmNcolumns,&columns,NULL); assert( columns == g->grid.colCount ); } #endif return g->grid.colCount; } /*----------------------------------------------------------------------*/ /* extern */ void XmLGridXYToCellTracking(Widget widget, int x, /* input only args. */ int y, /* input only args. */ Boolean * m_inGrid, /* input/output args. */ int * m_lastRow, /* input/output args. */ int * m_lastCol, /* input/output args. */ unsigned char * m_lastRowtype, /* input/output args. */ unsigned char * m_lastColtype,/* input/output args. */ int * outRow, /* output only args. */ int * outCol, /* output only args. */ Boolean * enter, /* output only args. */ Boolean * leave) /* output only args. */ { int m_totalLines = 0; int m_numcolumns = 0; int row = 0; int column = 0; unsigned char rowtype = XmCONTENT; unsigned char coltype = XmCONTENT; if (0 > XmLGridXYToRowColumn(widget, x, y, &rowtype, &row, &coltype, &column)) { /* In grid; but, not in any cells */ /* treat it as a leave */ *enter = FALSE; *leave = TRUE; return; }/* if */ m_totalLines = XmLGridGetRowCount(widget); m_numcolumns = XmLGridGetColumnCount(widget); if ((row < m_totalLines) && (column < m_numcolumns) && ((*m_lastRow != row)|| (*m_lastCol != column) || (*m_lastRowtype != rowtype)|| (*m_lastColtype != coltype))) { *outRow = (rowtype == XmHEADING)?-1:row; *outCol = column; if (*m_inGrid == False) { *m_inGrid = True; /* enter a cell */ *enter = TRUE; *leave = FALSE; }/* if */ else { /* Cruising among cells */ *enter = TRUE; *leave = TRUE; }/* else */ *m_lastRow = row; *m_lastCol = column; *m_lastRowtype = rowtype ; *m_lastColtype = coltype ; }/* row /col in grid */ } /*----------------------------------------------------------------------*/ nedit-5.6.orig/Microline/XmL/Makefile0000644000175000017500000000663210077552126016207 0ustar paulpaul#! gmake # # ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1 # # The contents of this file are subject to the Mozilla Public License Version # 1.1 (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License # for the specific language governing rights and limitations under the # License. # # The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), # in which case the provisions of the GPL or the LGPL are applicable instead # of those above. If you wish to allow use of your version of this file only # under the terms of either the GPL or the LGPL, and not to allow others to # use your version of this file under the terms of the MPL, indicate your # decision by deleting the provisions above and replace them with the notice # and other provisions required by the GPL or the LGPL. If you do not delete # the provisions above, a recipient may use your version of this file under # the terms of any one of the MPL, the GPL or the LGPL. # # In addition, as a special exception to the GNU GPL, the copyright holders # give permission to link the code of this program with the Motif and Open # Motif libraries (or with modified versions of these that use the same # license), and distribute linked combinations including the two. You # must obey the GNU General Public License in all respects for all of # the code used other than linking with Motif/Open Motif. If you modify # this file, you may extend this exception to your version of the file, # but you are not obligated to do so. If you do not wish to do so, # delete this exception statement from your version. # # ***** END LICENSE BLOCK ***** ########################################################################## # # Name: Makefile # Description: Makefile for Microline Widget library # Author: Ramiro Estrugo # ########################################################################## DEPTH = ../../../.. # XmL headers are exported to dist/include/XmL MODULE = Microline/XmL INCL_SUBDIR = /XmL LIBRARY_NAME = XmL # There are unused widgets. They are currently not needed to build Mozilla, # but that might change in the future. ifdef XFE_WIDGETS_BUILD_UNUSED XFE_EXTRA_DEFINES += -DXFE_WIDGETS_BUILD_UNUSED UNUSED_CSRCS = \ Progress.c \ $(NULL) UNUSED_EXPORTS = \ Progress.h \ ProgressP.h \ $(NULL) endif CSRCS = \ $(UNUSED_CSRCS) \ Folder.c \ Grid.c \ GridUtil.c \ Tree.c \ XmL.c \ $(NULL) REQUIRES = Microline EXPORTS = \ $(UNUSED_EXPORTS) \ Folder.h \ FolderP.h \ Grid.h \ GridP.h \ Tree.h \ TreeP.h \ XmL.h \ $(NULL) include $(DEPTH)/config/rules.mk DEFINES += $(XFE_EXTRA_DEFINES) nedit-5.6.orig/Microline/XmL/Makefile.common0000644000175000017500000000064707772504713017505 0ustar paulpaul# $Id: Makefile.common,v 1.1 2003/12/25 06:55:07 tksoh Exp $ # # Platform independent part of make procedure for Nirvana utilities directory, # included by machine specific makefiles. # .c.o: $(CC) -c -I.. $(CFLAGS) -o $@ $< OBJS = Folder.o XmL.o all: libXmL.a libXmL.a: $(OBJS) $(AR) $(ARFLAGS) libXmL.a $(OBJS) clean: rm -f $(OBJS) libXmL.a # Get the dependencies for all objects include Makefile.dependencies nedit-5.6.orig/Microline/XmL/Makefile.dependencies0000644000175000017500000000007707772504713020640 0ustar paulpaulXmL.o: XmL.c XmL.h Folder.o: Folder.c Folder.h FolderP.h XmL.h nedit-5.6.orig/Microline/XmL/Makefile.in0000644000175000017500000000711510077552126016611 0ustar paulpaul#! gmake # # ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1 # # The contents of this file are subject to the Mozilla Public License Version # 1.1 (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License # for the specific language governing rights and limitations under the # License. # # The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), # in which case the provisions of the GPL or the LGPL are applicable instead # of those above. If you wish to allow use of your version of this file only # under the terms of either the GPL or the LGPL, and not to allow others to # use your version of this file under the terms of the MPL, indicate your # decision by deleting the provisions above and replace them with the notice # and other provisions required by the GPL or the LGPL. If you do not delete # the provisions above, a recipient may use your version of this file under # the terms of any one of the MPL, the GPL or the LGPL. # # In addition, as a special exception to the GNU GPL, the copyright holders # give permission to link the code of this program with the Motif and Open # Motif libraries (or with modified versions of these that use the same # license), and distribute linked combinations including the two. You # must obey the GNU General Public License in all respects for all of # the code used other than linking with Motif/Open Motif. If you modify # this file, you may extend this exception to your version of the file, # but you are not obligated to do so. If you do not wish to do so, # delete this exception statement from your version. # # ***** END LICENSE BLOCK ***** ########################################################################## # # Name: Makefile # Description: Makefile for Microline Widget library # Author: Ramiro Estrugo # ########################################################################## DEPTH = ../../../.. topsrcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk # XmL headers are exported to dist/include/XmL MODULE = Microline/XmL INCL_SUBDIR = /XmL LIBRARY_NAME = XmL # There are unused widgets. They are currently not needed to build Mozilla, # but that might change in the future. ifdef XFE_WIDGETS_BUILD_UNUSED XFE_EXTRA_DEFINES += -DXFE_WIDGETS_BUILD_UNUSED UNUSED_CSRCS = \ Progress.c \ $(NULL) UNUSED_EXPORTS = \ Progress.h \ ProgressP.h \ $(NULL) endif CSRCS = \ $(UNUSED_CSRCS) \ Folder.c \ Grid.c \ GridUtil.c \ Tree.c \ XmL.c \ $(NULL) REQUIRES = Microline EXPORTS = \ $(UNUSED_EXPORTS) \ Folder.h \ FolderP.h \ Grid.h \ GridP.h \ Tree.h \ TreeP.h \ XmL.h \ $(NULL) EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) include $(topsrcdir)/config/rules.mk CFLAGS += $(FE_X_CFLAGS) DEFINES += $(XFE_EXTRA_DEFINES) nedit-5.6.orig/Microline/XmL/Progress.c0000644000175000017500000004315410704702042016506 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include "ProgressP.h" #include #include #include static void ClassInitialize(void); static void Initialize(Widget , Widget, ArgList, Cardinal *); static void Resize(Widget); static void Destroy(Widget); static void Realize(Widget w, XtValueMask *valueMask, XSetWindowAttributes *attr); static void Redisplay(Widget, XEvent *, Region); static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *); static void CopyFontList(XmLProgressWidget p); static void TimeStr(char *, int); static void DrawBarMeter(XmLProgressWidget p, XRectangle *rect); static void DrawBoxesMeter(XmLProgressWidget p, XRectangle *rect); static void DrawString(XmLProgressWidget, XmString, int, int, int, XRectangle *, XRectangle *); static Boolean CvtStringToMeterStyle(Display *dpy, XrmValuePtr args, Cardinal *numArgs, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data); static XtResource resources[] = { { XmNcompleteValue, XmCCompleteValue, XtRInt, sizeof(int), XtOffset(XmLProgressWidget, progress.completeValue), XtRImmediate, (caddr_t)100 }, { XmNnumBoxes, XmCNumBoxes, XtRInt, sizeof(int), XtOffset(XmLProgressWidget, progress.numBoxes), XtRImmediate, (caddr_t)10 }, { XmNvalue, XmCValue, XtRInt, sizeof(int), XtOffset(XmLProgressWidget, progress.value), XtRImmediate, (caddr_t)0 }, { XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList), XtOffset(XmLProgressWidget, progress.fontList), XmRImmediate, (XtPointer)0, }, { XmNmeterStyle, XmCMeterStyle, XmRMeterStyle, sizeof(unsigned char), XtOffset(XmLProgressWidget, progress.meterStyle), XmRImmediate, (XtPointer)XmMETER_BAR, }, { XmNshowTime, XmCShowTime, XmRBoolean, sizeof(Boolean), XtOffset(XmLProgressWidget, progress.showTime), XmRImmediate, (XtPointer)False }, { XmNshowPercentage, XmCShowPercentage, XmRBoolean, sizeof(Boolean), XtOffset(XmLProgressWidget, progress.showPercentage), XmRImmediate, (XtPointer)True } }; XmLProgressClassRec xmlProgressClassRec = { { /* Core */ (WidgetClass)&xmPrimitiveClassRec, /* superclass */ "XmLProgress", /* class_name */ sizeof(XmLProgressRec), /* widget_size */ ClassInitialize, /* class_initialize */ NULL, /* class_part_initialize */ FALSE, /* class_inited */ (XtInitProc)Initialize, /* initialize */ NULL, /* initialize_hook */ (XtRealizeProc)Realize, /* realize */ NULL, /* actions */ 0, /* num_actions */ resources, /* resources */ XtNumber(resources), /* num_resources */ NULLQUARK, /* xrm_class */ TRUE, /* compress_motion */ FALSE, /* compress_exposure */ TRUE, /* compress_enterleave */ TRUE, /* visible_interest */ (XtWidgetProc)Destroy, /* destroy */ (XtWidgetProc)Resize, /* resize */ (XtExposeProc)Redisplay, /* expose */ (XtSetValuesFunc)SetValues, /* set_values */ NULL, /* set_values_hook */ XtInheritSetValuesAlmost, /* set_values_almost */ NULL, /* get_values_hook */ NULL, /* accept_focus */ XtVersion, /* version */ NULL, /* callback_private */ XtInheritTranslations, /* tm_table */ NULL, /* query_geometry */ NULL, /* display_accelerator */ NULL, /* extension */ }, { /* Primitive */ (XtWidgetProc)_XtInherit, /* border_highlight */ (XtWidgetProc)_XtInherit, /* border_unhighlight */ XtInheritTranslations, /* translations */ NULL, /* arm_and_activate */ NULL, /* syn_resources */ 0, /* num_syn_resources */ NULL, /* extension */ }, { /* Progress */ 0, /* unused */ } }; WidgetClass xmlProgressWidgetClass = (WidgetClass)&xmlProgressClassRec; static void ClassInitialize(void) { XmLInitialize(); XtSetTypeConverter(XmRString, XmRMeterStyle, CvtStringToMeterStyle, 0, 0, XtCacheNone, 0); } static void Initialize(Widget reqW, Widget newW, ArgList args, Cardinal *narg) { XmLProgressWidget p; p = (XmLProgressWidget)newW; if (!p->core.width) p->core.width = 200; if (!p->core.height) p->core.height = 30; p->progress.gc = 0; p->progress.startTime = time(0); CopyFontList(p); if (p->progress.completeValue < 1) { XmLWarning(newW, "Initialize() - complete value can't be < 1"); p->progress.completeValue = 1; } if (p->progress.numBoxes < 1) { XmLWarning(newW, "Initialize() - number of boxes can't be < 1"); p->progress.numBoxes = 1; } if (p->progress.value < 0) { XmLWarning(newW, "Initialize() - value can't be < 0"); p->progress.value = 0; } if (p->progress.value > p->progress.completeValue) { XmLWarning(newW, "Initialize() - value can't be > completeValue"); p->progress.value = p->progress.completeValue; } XtVaSetValues(newW, XmNtraversalOn, False, NULL); } static void Resize(Widget w) { Display *dpy; Window win; if (!XtIsRealized(w)) return; dpy = XtDisplay(w); win = XtWindow(w); XClearArea(dpy, win, 0, 0, 0, 0, True); } static void Destroy(Widget w) { Display *dpy; XmLProgressWidget p; p = (XmLProgressWidget)w; dpy = XtDisplay(w); if (p->progress.gc) { XFreeGC(dpy, p->progress.gc); XFreeFont(dpy, p->progress.fallbackFont); } XmFontListFree(p->progress.fontList); } static void Realize(Widget w, XtValueMask *valueMask, XSetWindowAttributes *attr) { XmLProgressWidget p; Display *dpy; WidgetClass superClass; XtRealizeProc realize; XGCValues values; /* XtGCMask mask;*/ p = (XmLProgressWidget)w; dpy = XtDisplay(p); superClass = xmlProgressWidgetClass->core_class.superclass; realize = superClass->core_class.realize; (*realize)(w, valueMask, attr); if (!p->progress.gc) { p->progress.fallbackFont = XLoadQueryFont(dpy, "fixed"); values.font = p->progress.fallbackFont->fid; p->progress.gc = XCreateGC(dpy, XtWindow(p), GCFont, &values); } } static void Redisplay(Widget w, XEvent *event, Region region) { XmLProgressWidget p; Display *dpy; Window win; XRectangle rect; int st; if (!XtIsRealized(w) || !w->core.visible) return; p = (XmLProgressWidget)w; dpy = XtDisplay(w); win = XtWindow(w); st = p->primitive.shadow_thickness; rect.x = st; rect.y = st; rect.width = p->core.width - st * 2; rect.height = p->core.height - st * 2; if (p->progress.meterStyle == XmMETER_BAR) DrawBarMeter(p, &rect); else if (p->progress.meterStyle == XmMETER_BOXES) DrawBoxesMeter(p, &rect); #ifdef MOTIF11 _XmDrawShadow(dpy, win, p->primitive.bottom_shadow_GC, p->primitive.top_shadow_GC, p->primitive.shadow_thickness, 0, 0, p->core.width, p->core.height); #else _XmDrawShadows(dpy, win, p->primitive.top_shadow_GC, p->primitive.bottom_shadow_GC, 0, 0, p->core.width, p->core.height, p->primitive.shadow_thickness, XmSHADOW_IN); #endif } static void DrawBoxesMeter(XmLProgressWidget p, XRectangle *rect) { Display *dpy; Window win; int i, j, st, nb, x1, x2; dpy = XtDisplay(p); win = XtWindow(p); st = p->primitive.shadow_thickness; nb = p->progress.numBoxes; if (nb * st * 2 > (int)rect->width) return; if (p->progress.completeValue) j = (int)((long)nb * (long)p->progress.value / (long)p->progress.completeValue); else j = 0; x2 = 0; for (i = 0; i < nb; i++) { if (i < j) XSetForeground(dpy, p->progress.gc, p->primitive.foreground); else XSetForeground(dpy, p->progress.gc, p->core.background_pixel); x1 = x2; if (i == nb - 1) x2 = rect->width; else x2 = ((int)rect->width * (i + 1)) / nb; XFillRectangle(dpy, win, p->progress.gc, rect->x + x1 + st, rect->y + st, x2 - x1 - st * 2, rect->height - st * 2); #ifdef MOTIF11 _XmDrawShadow(dpy, win, p->primitive.bottom_shadow_GC, p->primitive.top_shadow_GC, p->primitive.shadow_thickness, rect->x + x1, rect->y, x2 - x1, rect->height); #else _XmDrawShadows(dpy, win, p->primitive.top_shadow_GC, p->primitive.bottom_shadow_GC, rect->x + x1, rect->y, x2 - x1, rect->height, p->primitive.shadow_thickness, XmSHADOW_IN); #endif } } static void DrawBarMeter(XmLProgressWidget p, XRectangle *rect) { Display *dpy; Window win; int timeLeft, timeSoFar; time_t currentTime; XmString str; Dimension strWidth, strHeight; XRectangle lRect, rRect; int percent; char c[10]; long l; dpy = XtDisplay(p); win = XtWindow(p); /* Left Rect */ if (p->progress.completeValue) l = (long)rect->width * (long)p->progress.value / (long)p->progress.completeValue; else l = 0; lRect.x = rect->x; lRect.y = rect->y; lRect.width = (Dimension)l; lRect.height = rect->height; XSetForeground(dpy, p->progress.gc, p->primitive.foreground); XFillRectangle(dpy, win, p->progress.gc, lRect.x, lRect.y, lRect.width, lRect.height); /* Right Rect */ rRect.x = rect->x + (int)l; rRect.y = rect->y; rRect.width = rect->width - (Dimension)l; rRect.height = rect->height; XSetForeground(dpy, p->progress.gc, p->core.background_pixel); XFillRectangle(dpy, win, p->progress.gc, rRect.x, rRect.y, rRect.width, rRect.height); if (p->progress.completeValue) percent = (int)(((long)p->progress.value * 100) / (long)p->progress.completeValue); else percent = 0; /* percent complete */ sprintf(c, "%d%c", percent, '%'); str = XmStringCreateSimple(c); XmStringExtent(p->progress.fontList, str, &strWidth, &strHeight); if (p->progress.showPercentage) DrawString(p, str, rect->x + rect->width / 2 - (int)strWidth / 2, rect->y + rect->height / 2 - (int)strHeight / 2, strWidth, &lRect, &rRect); XmStringFree(str); /* Left Time */ currentTime = time(0); timeSoFar = (int)(currentTime - p->progress.startTime); if (p->progress.showTime && p->progress.value && p->progress.value != p->progress.completeValue && timeSoFar) { TimeStr(c, timeSoFar); str = XmStringCreateSimple(c); XmStringExtent(p->progress.fontList, str, &strWidth, &strHeight); DrawString(p, str, rect->x + 5, rect->y + rect->height / 2 - (int)strHeight / 2, strWidth, &lRect, &rRect); XmStringFree(str); } /* Right Time */ timeLeft = 0; if (percent) timeLeft = (timeSoFar * 100 / percent) - timeSoFar; if (p->progress.showTime && percent && percent != 100 && timeLeft) { TimeStr(c, timeLeft); str = XmStringCreateSimple(c); XmStringExtent(p->progress.fontList, str, &strWidth, &strHeight); DrawString(p, str, rect->x + rect->width - strWidth - 5, rect->y + rect->height / 2 - (int)strHeight / 2, strWidth, &lRect, &rRect); XmStringFree(str); } } static void DrawString(XmLProgressWidget p, XmString str, int x, int y, int strWidth, XRectangle *lRect, XRectangle *rRect) { Display *dpy; Window win; dpy = XtDisplay(p); win = XtWindow(p); if (lRect->width && lRect->height) { XSetForeground(dpy, p->progress.gc, p->core.background_pixel); XSetClipRectangles(dpy, p->progress.gc, 0, 0, lRect, 1, Unsorted); XmStringDraw(dpy, win, p->progress.fontList, str, p->progress.gc, x, y, strWidth, XmALIGNMENT_BEGINNING, XmSTRING_DIRECTION_L_TO_R, 0); XSetClipMask(dpy, p->progress.gc, None); } if (rRect->width && rRect->height) { XSetForeground(dpy, p->progress.gc, p->primitive.foreground); XSetClipRectangles(dpy, p->progress.gc, 0, 0, rRect, 1, Unsorted); XmStringDraw(dpy, win, p->progress.fontList, str, p->progress.gc, x, y, strWidth, XmALIGNMENT_BEGINNING, XmSTRING_DIRECTION_L_TO_R, 0); XSetClipMask(dpy, p->progress.gc, None); } } static void TimeStr(char *c, int seconds) { int h, m, s; s = seconds; m = s / 60; s -= m * 60; h = m / 60; m -= h * 60; if (h > 99) h = 99; if (h > 0 && m < 10) sprintf(c, "%d:0%d hr", h, m); else if (h > 0) sprintf(c, "%d:%d hr", h, m); else if (m > 0 && s < 10) sprintf(c, "%d:0%d min", m, s); else if (m > 0) sprintf(c, "%d:%d min", m, s); else sprintf(c, "%d sec", s); } static Boolean SetValues(Widget curW, Widget reqW, Widget newW, ArgList args, Cardinal *narg) { XmLProgressWidget cur, p; XtAppContext app; cur = (XmLProgressWidget)curW; p = (XmLProgressWidget)newW; app = XtWidgetToApplicationContext(curW); if (p->progress.value == 0) p->progress.startTime = time(0); if (p->progress.completeValue < 1) { XmLWarning(newW, "SetValues() - complete value can't be < 1"); p->progress.completeValue = 1; } if (p->progress.numBoxes < 1) { XmLWarning(newW, "SetValues() - number of boxes can't be < 1"); p->progress.numBoxes = 1; } if (p->progress.value < 0) { XmLWarning(newW, "SetValues() - value can't be < 0"); p->progress.value = 0; } if (p->progress.value > p->progress.completeValue) { XmLWarning(newW, "SetValues() - value can't be > completeValue"); p->progress.value = p->progress.completeValue; } if (p->progress.fontList != cur->progress.fontList) { XmFontListFree(cur->progress.fontList); CopyFontList(p); } /* display changes immediately since we may be not get back to XNextEvent if the calling application is computing */ if (p->core.background_pixel != cur->core.background_pixel || p->primitive.foreground != cur->primitive.foreground || p->progress.value != cur->progress.value || p->progress.completeValue != cur->progress.completeValue || p->progress.fontList != cur->progress.fontList || p->progress.showTime != cur->progress.showTime || p->progress.showPercentage != cur->progress.showPercentage || p->progress.meterStyle != cur->progress.meterStyle || p->progress.numBoxes != cur->progress.numBoxes || p->primitive.shadow_thickness != cur->primitive.shadow_thickness) { Redisplay(newW, 0, 0); XFlush(XtDisplay(newW)); XmUpdateDisplay(newW); } return FALSE; } static void CopyFontList(XmLProgressWidget p) { if (!p->progress.fontList) p->progress.fontList = XmLFontListCopyDefault((Widget)p); else p->progress.fontList = XmFontListCopy(p->progress.fontList); if (!p->progress.fontList) XmLWarning((Widget)p, "- fatal error - font list NULL"); } static Boolean CvtStringToMeterStyle(Display *dpy, XrmValuePtr args, Cardinal *narg, XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *data) { static XmLStringToUCharMap map[] = { { "METER_BAR", XmMETER_BAR }, { "METER_BOXES", XmMETER_BOXES }, { 0, 0 }, }; return XmLCvtStringToUChar(dpy, "XmRMeterStyle", map, fromVal, toVal); } /* Public Functions */ Widget XmLCreateProgress(Widget parent, char *name, ArgList arglist, Cardinal argcount) { return XtCreateWidget(name, xmlProgressWidgetClass, parent, arglist, argcount); } nedit-5.6.orig/Microline/XmL/Progress.h0000644000175000017500000000571310245647600016522 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #ifndef XmLProgressH #define XmLProgressH #include "XmL.h" #ifdef XmL_CPP extern "C" { #endif extern WidgetClass xmlProgressWidgetClass; typedef struct _XmLProgressClassRec *XmLProgressWidgetClass; typedef struct _XmLProgressRec *XmLProgressWidget; #define XmLIsProgress(w) XtIsSubclass((w), xmlProgressWidgetClass) #ifdef XmL_ANSIC Widget XmLCreateProgress(Widget parent, char *name, ArgList arglist, Cardinal argcount); #else Widget XmLCreateProgress(); #endif #ifdef XmL_CPP } #endif #endif nedit-5.6.orig/Microline/XmL/ProgressP.h0000644000175000017500000000651310077552126016642 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #ifndef XmLProgressPH #define XmLProgressPH #include #include #ifdef MOTIF11 #else #include #include #endif #include #include "Progress.h" typedef struct _XmLProgressPart { int completeValue, value; Boolean showTime; Boolean showPercentage; XmFontList fontList; GC gc; time_t startTime; XFontStruct *fallbackFont; unsigned char meterStyle; int numBoxes; } XmLProgressPart; typedef struct _XmLProgressRec { CorePart core; XmPrimitivePart primitive; XmLProgressPart progress; } XmLProgressRec; typedef struct _XmLProgressClassPart { int null; } XmLProgressClassPart; typedef struct _XmLProgressClassRec { CoreClassPart core_class; XmPrimitiveClassPart primitive_class; XmLProgressClassPart progress_class; } XmLProgressClassRec; extern XmLProgressClassRec xmlProgressClassRec; #endif nedit-5.6.orig/Microline/XmL/Tree.c0000644000175000017500000011634010470434621015604 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include "TreeP.h" #include static void Initialize(Widget req, Widget newW, ArgList args, Cardinal *nargs); static void Destroy(Widget w); static Boolean SetValues(Widget curW, Widget, Widget newW, ArgList args, Cardinal *nargs); static int _PreLayout(XmLGridWidget g, int isVert); static int _TreeCellAction(XmLGridCell cell, Widget w, XmLGridCallbackStruct *cbs); static void DrawIconCell(XmLGridCell cell, Widget w, int row, XRectangle *clipRect, XmLGridDrawStruct *ds); static void DrawConnectingLine(Display *dpy, Window win, GC gc, XRectangle *clipRect, int offFlag, int x1, int y1, int x2, int y2); static void BtnPress(Widget w, XtPointer closure, XEvent *event, Boolean *ctd); static void Activate(Widget w, XtPointer clientData, XtPointer callData); static void SwitchRowState(XmLTreeWidget t, int row, XEvent *event); static XmLGridRow _RowNew(Widget tree); static void _GetRowValueMask(XmLGridWidget g, char *s, long *mask); static void _GetRowValue(XmLGridWidget g, XmLGridRow r, XtArgVal value, long mask); static int _SetRowValues(XmLGridWidget g, XmLGridRow r, long mask); static int _SetCellValuesResize(XmLGridWidget g, XmLGridRow row, XmLGridColumn col, XmLGridCell cell, long mask); static void GetManagerForeground(Widget w, int, XrmValue *value); static void CreateDefaultPixmaps(XmLTreeWidget t); static XmLTreeWidget WidgetToTree(Widget w, char *funcname); static XtResource resources[] = { { XmNcollapseCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLTreeWidget, tree.collapseCallback), XmRImmediate, (XtPointer)0, }, { XmNconnectingLineColor, XmCConnectingLineColor, XmRPixel, sizeof(Pixel), XtOffset(XmLTreeWidget, tree.lineColor), XmRCallProc, (XtPointer)GetManagerForeground, }, { XmNexpandCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XmLTreeWidget, tree.expandCallback), XmRImmediate, (XtPointer)0, }, { XmNlevelSpacing, XmCLevelSpacing, XmRDimension, sizeof(Dimension), XtOffset(XmLTreeWidget, tree.levelSpacing), XmRImmediate, (XtPointer)11, }, { XmNplusMinusColor, XmCPlusMinusColor, XmRPixel, sizeof(Pixel), XtOffset(XmLTreeWidget, tree.pmColor), XmRCallProc, (XtPointer)GetManagerForeground, }, /* Row Resources */ { XmNrowExpands, XmCRowExpands, XmRBoolean, sizeof(Boolean), XtOffset(XmLTreeWidget, tree.rowExpands), XmRImmediate, (XtPointer)False, }, { XmNrowIsExpanded, XmCRowIsExpanded, XmRBoolean, sizeof(Boolean), XtOffset(XmLTreeWidget, tree.rowIsExpanded), XmRImmediate, (XtPointer)True, }, { XmNrowLevel, XmCRowLevel, XmRInt, sizeof(int), XtOffset(XmLTreeWidget, tree.rowLevel), XmRImmediate, (XtPointer)0, }, /* XmNignorePixmaps. Causes the tree to NOT render any pixmaps */ { XmNignorePixmaps, XmCIgnorePixmaps, XmRBoolean, sizeof(Boolean), XtOffset(XmLTreeWidget, tree.ignorePixmaps), XmRImmediate, (XtPointer) False, }, }; XmLTreeClassRec xmlTreeClassRec = { { /* core_class */ (WidgetClass)&xmlGridClassRec, /* superclass */ "XmLTree", /* class_name */ sizeof(XmLTreeRec), /* widget_size */ (XtProc)NULL, /* class_init */ 0, /* class_part_init */ FALSE, /* class_inited */ (XtInitProc)Initialize, /* initialize */ 0, /* initialize_hook */ XtInheritRealize, /* realize */ NULL, /* actions */ 0, /* num_actions */ resources, /* resources */ XtNumber(resources), /* num_resources */ NULLQUARK, /* xrm_class */ TRUE, /* compress_motion */ XtExposeCompressMaximal, /* compress_exposure */ TRUE, /* compress_enterleav */ TRUE, /* visible_interest */ (XtWidgetProc)Destroy, /* destroy */ XtInheritResize, /* resize */ XtInheritExpose, /* expose */ (XtSetValuesFunc)SetValues, /* set_values */ 0, /* set_values_hook */ XtInheritSetValuesAlmost, /* set_values_almost */ 0, /* get_values_hook */ 0, /* accept_focus */ XtVersion, /* version */ 0, /* callback_private */ XtInheritTranslations, /* tm_table */ 0, /* query_geometry */ 0, /* display_accelerato */ 0, /* extension */ }, { /* composite_class */ XtInheritGeometryManager, /* geometry_manager */ XtInheritChangeManaged, /* change_managed */ XtInheritInsertChild, /* insert_child */ XtInheritDeleteChild, /* delete_child */ 0, /* extension */ }, { /* constraint_class */ 0, /* subresources */ 0, /* subresource_count */ sizeof(XmLTreeConstraintRec), /* constraint_size */ 0, /* initialize */ 0, /* destroy */ 0, /* set_values */ 0, /* extension */ }, { /* manager_class */ XtInheritTranslations, /* translations */ 0, /* syn resources */ 0, /* num syn_resources */ 0, /* get_cont_resources */ 0, /* num_get_cont_resou */ XmInheritParentProcess, /* parent_process */ 0, /* extension */ }, { /* grid_class */ 0, /* initial rows */ 1, /* initial cols */ _PreLayout, /* post layout */ sizeof(struct _XmLTreeRowRec), /* row rec size */ _RowNew, /* row new */ XmInheritGridRowFree, /* row free */ _GetRowValueMask, /* get row value mask */ _GetRowValue, /* get row value */ _SetRowValues, /* set row values */ sizeof(struct _XmLGridColumnRec), /* column rec size */ XmInheritGridColumnNew, /* column new */ XmInheritGridColumnFree, /* column free */ XmInheritGridGetColumnValueMask, /* get col value mask */ XmInheritGridGetColumnValue, /* get column value */ XmInheritGridSetColumnValues, /* set column values */ _SetCellValuesResize, /* set cell vl resize */ _TreeCellAction, /* cell action */ }, { /* tree_class */ 0, /* unused */ } }; WidgetClass xmlTreeWidgetClass = (WidgetClass)&xmlTreeClassRec; static void Initialize(Widget reqW, Widget newW, ArgList args, Cardinal *narg) { XmLTreeWidget t; t = (XmLTreeWidget)newW; if ((int) t->core.width <= 0) t->core.width = 100; if (t->core.height <= (Dimension) 0) t->core.height = 100; t->tree.defaultPixmapsCreated = 0; t->tree.linesData = 0; t->tree.linesSize = 0; t->tree.recalcTreeWidth = 0; if (t->grid.rowCount) { XmLWarning(newW, "Initialize() - can't set XmNrows"); XmLGridDeleteAllRows(newW, XmCONTENT); } XtAddCallback(newW, XmNactivateCallback, Activate, NULL); XtAddEventHandler(newW, ButtonPressMask, True, (XtEventHandler)BtnPress, (XtPointer)0); XtVaSetValues(newW, XmNcellDefaults, True, XmNcolumn, 0, XmNcellType, XmICON_CELL, NULL); } static void Destroy(Widget w) { XmLTreeWidget t; Display *dpy; XWindowAttributes attr; t = (XmLTreeWidget)w; dpy = XtDisplay(t); if (t->tree.linesData) free((char *)t->tree.linesData); if (t->tree.defaultPixmapsCreated) { XGetWindowAttributes(dpy, XtWindow(w), &attr); XFreePixmap(dpy, t->tree.filePixmask); XFreePixmap(dpy, t->tree.folderPixmask); XFreePixmap(dpy, t->tree.folderOpenPixmask); XFreePixmap(dpy, t->tree.filePixmask); XFreePixmap(dpy, t->tree.folderPixmask); XFreePixmap(dpy, t->tree.folderOpenPixmask); XFreeColors(dpy, attr.colormap, t->tree.pixColors, 4, 0L); } } static Boolean SetValues(Widget curW, Widget reqW, Widget newW, ArgList args, Cardinal *nargs) { XmLTreeWidget t, cur; XmLGridColumn col; Boolean needsResize, needsRedraw; t = (XmLTreeWidget)newW; cur = (XmLTreeWidget)curW; needsResize = False; needsRedraw = False; #define NE(value) (t->value != cur->value) if (NE(grid.rowCount)) XmLWarning(newW, "SetValues() - can't set XmNrows"); if (NE(tree.pmColor) || NE(tree.lineColor)) needsRedraw = True; if (NE(tree.levelSpacing) || t->tree.recalcTreeWidth) { col = XmLGridGetColumn(newW, XmCONTENT, 0); if (col) col->grid.widthInPixelsValid = 0; t->tree.recalcTreeWidth = 0; needsResize = True; needsRedraw = True; } #undef NE if (needsResize) _XmLGridLayout((XmLGridWidget)t); if (needsRedraw) XmLGridRedrawAll((Widget)t); return False; } static int _PreLayout(XmLGridWidget g, int isVert) { XmLTreeWidget t; XmLTreeRow row; Widget w; int i, j, size, maxLevel, hideLevel, lineWidth; char *thisLine, *prevLine; t = (XmLTreeWidget)g; w = (Widget)g; if (!t->grid.vertVisChangedHint) return 0; /* ?? */ t->grid.vertVisChangedHint = 0; /* top down calculation of hidden states and maxLevel */ hideLevel = -1; maxLevel = 0; t->grid.layoutFrozen = True; for (i = 0; i < t->grid.rowCount; i++) { row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, i); if (row->tree.level > maxLevel) maxLevel = row->tree.level; if (hideLevel != -1 && row->tree.level > hideLevel) { if (row->grid.height) XtVaSetValues(w, XmNrow, i, XmNrowHeight, 0, NULL); } else { if (row->tree.expands == True && row->tree.isExpanded == False) hideLevel = row->tree.level; else hideLevel = -1; if (!row->grid.height) XtVaSetValues(w, XmNrow, i, XmNrowHeight, 1, NULL); } } t->grid.layoutFrozen = False; t->tree.linesMaxLevel = maxLevel; if (!t->grid.rowCount) return 0; /* bottom up calculation of connecting lines */ lineWidth = maxLevel + 1; size = lineWidth * t->grid.rowCount; if (t->tree.linesSize < size) { if (t->tree.linesData) free((char *)t->tree.linesData); t->tree.linesSize = size; t->tree.linesData = (char *)malloc(size); } prevLine = 0; thisLine = &t->tree.linesData[size - lineWidth]; for (i = t->grid.rowCount - 1; i >= 0; i--) { row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, i); if (!row->grid.height) { thisLine -= lineWidth; continue; } for (j = 0; j < row->tree.level - 1; j++) { if (prevLine && (prevLine[j] == 'L' || prevLine[j] == 'I' || prevLine[j] == 'E')) thisLine[j] = 'I'; else thisLine[j] = ' '; } if (row->tree.level) { if (prevLine && (prevLine[j] == 'L' || prevLine[j] == 'I' || prevLine[j] == 'E')) thisLine[j++] = 'E'; else thisLine[j++] = 'L'; } thisLine[j++] = 'O'; for (; j < lineWidth; j++) thisLine[j] = ' '; prevLine = thisLine; thisLine -= lineWidth; } if (prevLine) { for (i = 0; i < lineWidth; i++) { if (prevLine[i] == 'L') prevLine[i] = '-'; else if (prevLine[i] == 'E') prevLine[i] = 'P'; } } /* if we are in VertLayout(), the horizontal size may need */ /* recomputing because of the row hides. */ if (isVert) return 1; /* if we are in HorizLayout(), the vertical recomputation */ /* will be happening regardless, since row changes (vertical) */ /* are why we are here */ return 0; } static int _TreeCellAction(XmLGridCell cell, Widget w, XmLGridCallbackStruct *cbs) { XmLTreeWidget t; XmLTreeRow row; XmLGridColumn col; XmLGridWidgetClass sc; XmLGridCellActionProc cellActionProc; XmLGridCellRefValues *cellValues; XmLGridCellIcon *icon; /* XRectangle *rect, cRect;*/ int ret, h, isTreeCell; Dimension default_icon_width = 16; Dimension default_icon_height = 16; t = (XmLTreeWidget)w; if (cbs->rowType == XmCONTENT && cbs->columnType == XmCONTENT && cbs->column == 0) isTreeCell = 1; else isTreeCell = 0; sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass; cellActionProc = sc->grid_class.cellActionProc; ret = 0; /* Check for ignore pixmaps */ if (t->tree.ignorePixmaps) { default_icon_width = 0; default_icon_height = 0; } switch (cbs->reason) { case XmCR_CELL_DRAW: if (isTreeCell) DrawIconCell(cell, w, cbs->row, cbs->clipRect, cbs->drawInfo); else ret = cellActionProc(cell, w, cbs); break; case XmCR_CONF_TEXT: if (isTreeCell) { int iconOffset; cellValues = cell->cell.refValues; row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, cbs->row); icon = (XmLGridCellIcon *)cell->cell.value; iconOffset = 4 + cellValues->leftMargin + t->tree.levelSpacing * 2 * row->tree.level; if (!icon) iconOffset += default_icon_width; else if (icon->pix.pixmap == XmUNSPECIFIED_PIXMAP) iconOffset += default_icon_width; else iconOffset += icon->pix.width; cbs->clipRect->x += iconOffset; if (cbs->clipRect->width > iconOffset) cbs->clipRect->width -= iconOffset; else cbs->clipRect->width = 0; } ret = cellActionProc(cell, w, cbs); break; case XmCR_PREF_HEIGHT: ret = cellActionProc(cell, w, cbs); if (isTreeCell) { cellValues = cell->cell.refValues; if (cellValues->type != XmICON_CELL) return 0; icon = (XmLGridCellIcon *)cell->cell.value; h = 4 + default_icon_height + cellValues->topMargin + cellValues->bottomMargin; if (icon && icon->pix.pixmap == XmUNSPECIFIED_PIXMAP && ret < h) ret = h; } break; case XmCR_PREF_WIDTH: if (isTreeCell) { cellValues = cell->cell.refValues; if (cellValues->type != XmICON_CELL) return 0; icon = (XmLGridCellIcon *)cell->cell.value; col = (XmLGridColumn)cbs->object; row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, cbs->row); if (row->tree.stringWidthValid == False) { if (icon && icon->string) row->tree.stringWidth = XmStringWidth(cellValues->fontList, icon->string); else row->tree.stringWidth = 0; row->tree.stringWidthValid = True; } ret = 4 + cellValues->leftMargin + t->tree.levelSpacing * 2 * row->tree.level + t->grid.iconSpacing + row->tree.stringWidth + cellValues->rightMargin; if (!icon) ret += default_icon_width; else if (icon->pix.pixmap == XmUNSPECIFIED_PIXMAP) ret += default_icon_width; else ret += icon->pix.width; if (!row->grid.height) ret = 0; } else ret = cellActionProc(cell, w, cbs); break; default: ret = cellActionProc(cell, w, cbs); break; } return ret; } static void DrawIconCell(XmLGridCell cell, Widget w, int row, XRectangle *clipRect, XmLGridDrawStruct *ds) { XmLTreeWidget t; XmLTreeRow rowp; XmLGridCellRefValues *cellValues; XmLGridCellIcon *icon; XRectangle *cellRect, rect; Display *dpy; Window win; char *thisLine; int i, clipSet, pixWidth, pixHeight; int xoff, xoff2, midy, oddFlag, x1, y1, x2, y2; Pixmap pixmap, pixmask; t = (XmLTreeWidget)w; rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, row); dpy = XtDisplay(w); win = XtWindow(w); cellValues = cell->cell.refValues; if (cellValues->type != XmICON_CELL) return; icon = (XmLGridCellIcon *)cell->cell.value; if (!icon) return; cellRect = ds->cellRect; if (!t->tree.linesData) { XmLWarning(w, "DrawIconCell() - no lines data calculated"); return; } /* draw background */ XSetForeground(dpy, ds->gc, cell->cell.refValues->background); XFillRectangle(dpy, win, ds->gc, clipRect->x, clipRect->y, clipRect->width, clipRect->height); if (t->grid.singleColScrollMode) oddFlag = t->grid.singleColScrollPos & 1; else oddFlag = 0; pixWidth = 0; xoff = t->tree.levelSpacing; xoff2 = xoff * 2; y1 = cellRect->y; y2 = cellRect->y + cellRect->height - 1; midy = cellRect->y + cellRect->height / 2; if (midy & 1) midy += 1; /* draw connecting lines and pixmap */ XSetForeground(dpy, ds->gc, t->tree.lineColor); thisLine = &t->tree.linesData[row * (t->tree.linesMaxLevel + 1)]; for (i = 0; i <= t->tree.linesMaxLevel; i++) { x1 = cellRect->x + (xoff2 * i); if (x1 >= clipRect->x + (int)clipRect->width) continue; switch (thisLine[i]) { case 'O': if (!t->tree.ignorePixmaps) { rect.x = x1; rect.y = cellRect->y; rect.width = cellRect->width; rect.height = cellRect->height; if (icon->pix.pixmap != XmUNSPECIFIED_PIXMAP) { pixmap = icon->pix.pixmap; pixmask = icon->pix.pixmask; pixWidth = icon->pix.width; pixHeight = icon->pix.height; } else { if (!t->tree.defaultPixmapsCreated) CreateDefaultPixmaps(t); if (rowp->tree.expands && rowp->tree.isExpanded) { pixmap = t->tree.folderOpenPixmap; pixmask = t->tree.folderOpenPixmask; } else if (rowp->tree.expands) { pixmap = t->tree.folderPixmap; pixmask = t->tree.folderPixmask; } else { pixmap = t->tree.filePixmap; pixmask = t->tree.filePixmask; } pixWidth = 16; pixHeight = 16; } XmLPixmapDraw(w, pixmap, pixmask, pixWidth, pixHeight, XmALIGNMENT_BOTTOM_LEFT, ds->gc, &rect, clipRect); } /* !t->tree.ignorePixmaps */ break; case 'I': DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag, x1 + xoff, y1, x1 + xoff, y2); break; case 'E': DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag, x1 + xoff, y1, x1 + xoff, y2); DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag, x1 + xoff, midy, x1 + xoff2, midy); break; case 'L': DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag, x1 + xoff, y1, x1 + xoff, midy); DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag, x1 + xoff, midy, x1 + xoff2, midy); break; case 'P': DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag, x1 + xoff, midy, x1 + xoff, y2); DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag, x1 + xoff, midy, x1 + xoff2, midy); break; case '-': DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag, x1 + xoff, midy, x1 + xoff2, midy); break; } } clipSet = 0; /* draw expand/collapse graphic */ rect.x = cellRect->x + (rowp->tree.level - 1) * xoff2 + xoff - 5; rect.y = midy - 5; rect.width = 11; rect.height = 11; i = XmLRectIntersect(&rect, clipRect); if (rowp->tree.expands && rowp->tree.level && i != XmLRectOutside) { if (i == XmLRectPartial) { clipSet = 1; XSetClipRectangles(dpy, ds->gc, 0, 0, clipRect, 1, Unsorted); } x1 = rect.x; x2 = rect.x + rect.width - 1; y1 = rect.y; y2 = rect.y + rect.height - 1; XSetForeground(dpy, ds->gc, cellValues->background); XFillRectangle(dpy, win, ds->gc, x1, y1, 11, 11); XSetForeground(dpy, ds->gc, t->tree.lineColor); XDrawLine(dpy, win, ds->gc, x1 + 2, y1 + 1, x2 - 2, y1 + 1); XDrawLine(dpy, win, ds->gc, x2 - 1, y1 + 2, x2 - 1, y2 - 2); XDrawLine(dpy, win, ds->gc, x1 + 2, y2 - 1, x2 - 2, y2 - 1); XDrawLine(dpy, win, ds->gc, x1 + 1, y1 + 2, x1 + 1, y2 - 2); XSetForeground(dpy, ds->gc, t->tree.pmColor); if (!rowp->tree.isExpanded) XDrawLine(dpy, win, ds->gc, x1 + 5, y1 + 3, x1 + 5, y1 + 7); XDrawLine(dpy, win, ds->gc, x1 + 3, y1 + 5, x1 + 7, y1 + 5); } /* draw select background and highlight */ i = rowp->tree.level * xoff2 + pixWidth + t->grid.iconSpacing; rect.x = cellRect->x + i; rect.y = cellRect->y; rect.height = cellRect->height; rect.width = 0; if (t->grid.colCount == 1 && rowp->tree.stringWidthValid) rect.width = rowp->tree.stringWidth + 4; else if ((int)cellRect->width > i) rect.width = cellRect->width - i; i = XmLRectIntersect(&rect, clipRect); if (i != XmLRectOutside && ds->drawSelected) { if (i == XmLRectPartial && !clipSet) { clipSet = 1; XSetClipRectangles(dpy, ds->gc, 0, 0, clipRect, 1, Unsorted); } XSetForeground(dpy, ds->gc, ds->selectBackground); XFillRectangle(dpy, win, ds->gc, rect.x, rect.y, rect.width, rect.height); } if (ds->drawFocusType != XmDRAW_FOCUS_NONE && t->grid.highlightThickness >= 2) { if (i == XmLRectPartial && !clipSet) { clipSet = 1; XSetClipRectangles(dpy, ds->gc, 0, 0, clipRect, 1, Unsorted); } XSetForeground(dpy, ds->gc, t->manager.highlight_color); x1 = rect.x; x2 = rect.x + rect.width - 1; y1 = rect.y; y2 = rect.y + rect.height - 1; XDrawLine(dpy, win, ds->gc, x1, y1, x2, y1); if (ds->drawFocusType == XmDRAW_FOCUS_CELL || ds->drawFocusType == XmDRAW_FOCUS_RIGHT) XDrawLine(dpy, win, ds->gc, x2, y1, x2, y2); XDrawLine(dpy, win, ds->gc, x1, y2, x2, y2); XDrawLine(dpy, win, ds->gc, x1, y1, x1, y2); y1 += 1; y2 -= 1; XDrawLine(dpy, win, ds->gc, x1, y2, x2, y2); XDrawLine(dpy, win, ds->gc, x1, y1, x2, y1); x1 += 1; x2 -= 1; XDrawLine(dpy, win, ds->gc, x1, y1, x1, y2); if (ds->drawFocusType == XmDRAW_FOCUS_CELL || ds->drawFocusType == XmDRAW_FOCUS_RIGHT) XDrawLine(dpy, win, ds->gc, x2, y1, x2, y2); } /* draw string */ if (icon->string) { if (ds->drawSelected == True) XSetForeground(dpy, ds->gc, ds->selectForeground); else XSetForeground(dpy, ds->gc, cellValues->foreground); XmLStringDraw(w, icon->string, ds->stringDirection, cellValues->fontList, XmALIGNMENT_LEFT, ds->gc, &rect, clipRect); } if (clipSet) XSetClipMask(dpy, ds->gc, None); } static void DrawConnectingLine(Display *dpy, Window win, GC gc, XRectangle *clipRect, int oddFlag, int x1, int y1, int x2, int y2) { int i, x, y; XPoint points[100]; i = 0; for (x = x1; x <= x2; x++) for (y = y1; y <= y2; y++) { if ((((x + oddFlag) & 1) == (y & 1)) || x < clipRect->x || x >= (clipRect->x + (int)clipRect->width) || y < clipRect->y || y >= (clipRect->y + (int)clipRect->height)) continue; points[i].x = x; points[i].y = y; if (++i < 100) continue; XDrawPoints(dpy, win, gc, points, i, CoordModeOrigin); i = 0; } if (i) XDrawPoints(dpy, win, gc, points, i, CoordModeOrigin); } static void BtnPress(Widget w, XtPointer closure, XEvent *event, Boolean *ctd) { XmLTreeWidget t; XmLTreeRow rowp; unsigned char rowType, colType; int row, col, x1, y1, x2, y2, xoff; XRectangle rect; XButtonEvent *be; static int lastRow = -1; static Time lastSelectTime = 0; t = (XmLTreeWidget)w; if (event->type != ButtonPress) return; be = (XButtonEvent *)event; if (be->button != Button1 || be->state & ControlMask || be->state & ShiftMask) return; if (XmLGridXYToRowColumn(w, be->x, be->y, &rowType, &row, &colType, &col) == -1) return; rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, row); if (rowType != XmCONTENT || colType != XmCONTENT || col != 0) return; if (XmLGridRowColumnToXY(w, rowType, row, colType, col, False, &rect) == -1) return; if ((be->time - lastSelectTime) < XtGetMultiClickTime(XtDisplay(w)) && lastRow == row) { /* activate callback will be handling expand/collapse */ lastSelectTime = be->time; return; } /* * If the Grid is using single click activation the activateCallback * called from Select() will take care of collapsing and * expanding. */ if (((XmLGridWidget)w)->grid.singleClickActivation) return; lastSelectTime = be->time; lastRow = row; xoff = t->tree.levelSpacing; x1 = rect.x + (rowp->tree.level - 1) * xoff * 2 + xoff - 6; x2 = x1 + 13; y1 = rect.y + rect.height / 2 - 6; y2 = y1 + 13; if (be->x > x2 || be->x < x1 || be->y > y2 || be->y < y1) return; SwitchRowState(t, row, event); /* Avoid having a cell edited when expand/collapse is done. * Yes, this is a hack. By setting this to zero, Grid.c:Select() * will ignore this click are a second click that would trigger * inplace editing. */ ((XmLGridWidget)w)->grid.lastSelectTime = 0; } static void Activate(Widget w, XtPointer clientData, XtPointer callData) { XmLTreeWidget t; XmLGridCallbackStruct *cbs; t = (XmLTreeWidget)w; cbs = (XmLGridCallbackStruct *)callData; if (cbs->rowType != XmCONTENT) if (t->grid.selectionPolicy == XmSELECT_CELL && (cbs->columnType != XmCONTENT || cbs->column != 0)) return; SwitchRowState(t, cbs->row, cbs->event); } static void SwitchRowState(XmLTreeWidget t, int row, XEvent *event) { Widget w; XmLTreeRow rowp; XmLGridCallbackStruct cbs; w = (Widget)t; rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, row); if (rowp->tree.expands == False) return; cbs.event = event; cbs.columnType = XmCONTENT; cbs.column = 0; cbs.rowType = XmCONTENT; cbs.row = row; if (rowp->tree.isExpanded == True) { XtVaSetValues(w, XmNrow, row, XmNrowIsExpanded, False, NULL); cbs.reason = XmCR_COLLAPSE_ROW; XtCallCallbackList(w, t->tree.collapseCallback, (XtPointer)&cbs); } else { XtVaSetValues(w, XmNrow, row, XmNrowIsExpanded, True, NULL); cbs.reason = XmCR_EXPAND_ROW; XtCallCallbackList(w, t->tree.expandCallback, (XtPointer)&cbs); } } /* Only to be called through Grid class */ static XmLGridRow _RowNew(Widget tree) { XmLGridWidgetClass sc; XmLTreeRow row; sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass; row = (XmLTreeRow)sc->grid_class.rowNewProc(tree); row->tree.level = 0; row->tree.expands = False; row->tree.isExpanded = True; row->tree.hasSiblings = False; row->tree.stringWidth = 0; row->tree.stringWidthValid = False; return (XmLGridRow)row; } /* Only to be called through Grid class */ static void _GetRowValueMask(XmLGridWidget g, char *s, long *mask) { XmLGridWidgetClass sc; static XrmQuark qLevel, qExpands, qIsExpanded; static int quarksValid = 0; XrmQuark q; sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass; sc->grid_class.getRowValueMaskProc(g, s, mask); if (!quarksValid) { qLevel = XrmStringToQuark(XmNrowLevel); qExpands = XrmStringToQuark(XmNrowExpands); qIsExpanded = XrmStringToQuark(XmNrowIsExpanded); quarksValid = 1; } q = XrmStringToQuark(s); if (q == qLevel) *mask |= XmLTreeRowLevel; else if (q == qExpands) *mask |= XmLTreeRowExpands; else if (q == qIsExpanded) *mask |= XmLTreeRowIsExpanded; } /* Only to be called through Grid class */ static void _GetRowValue(XmLGridWidget g, XmLGridRow r, XtArgVal value, long mask) { XmLGridWidgetClass sc; XmLTreeRow row; sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass; sc->grid_class.getRowValueProc(g, r, value, mask); row = (XmLTreeRow)r; switch (mask) { case XmLTreeRowLevel: *((int *)value) = row->tree.level; break; case XmLTreeRowExpands: *((Boolean *)value) = row->tree.expands; break; case XmLTreeRowIsExpanded: *((Boolean *)value) = row->tree.isExpanded; break; } } /* Only to be called through Grid class */ static int _SetRowValues(XmLGridWidget g, XmLGridRow r, long mask) { XmLGridWidgetClass sc; int needsResize; XmLTreeRow row; XmLTreeWidget t; sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass; needsResize = sc->grid_class.setRowValuesProc(g, r, mask); t = (XmLTreeWidget)g; row = (XmLTreeRow)r; if ((mask & XmLGridRowHeight) && needsResize) t->tree.recalcTreeWidth = 1; if (mask & XmLTreeRowLevel) { row->tree.level = t->tree.rowLevel; t->tree.recalcTreeWidth = 1; t->grid.vertVisChangedHint = 1; needsResize = 1; } if (mask & XmLTreeRowExpands) { row->tree.expands = t->tree.rowExpands; t->grid.vertVisChangedHint = 1; needsResize = 1; } if (mask & XmLTreeRowIsExpanded) { row->tree.isExpanded = t->tree.rowIsExpanded; t->grid.vertVisChangedHint = 1; needsResize = 1; } return needsResize; } /* Only to be called through Grid class */ static int _SetCellValuesResize(XmLGridWidget g, XmLGridRow row, XmLGridColumn col, XmLGridCell cell, long mask) { XmLGridWidgetClass sc; int needsResize; sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass; needsResize = 0; if (col->grid.pos == g->grid.headingColCount && row->grid.pos >= g->grid.headingRowCount && row->grid.pos < g->grid.headingRowCount + g->grid.rowCount) { if (mask & XmLGridCellFontList) { row->grid.heightInPixelsValid = 0; ((XmLTreeRow)row)->tree.stringWidthValid = False; col->grid.widthInPixelsValid = 0; needsResize = 1; } if (mask & XmLGridCellString) { ((XmLTreeRow)row)->tree.stringWidthValid = False; col->grid.widthInPixelsValid = 0; needsResize = 1; } } if (sc->grid_class.setCellValuesResizeProc(g, row, col, cell, mask)) needsResize = 1; return needsResize; } /* Utility */ static void GetManagerForeground(Widget w, int offset, XrmValue *value) { XmLTreeWidget t; t = (XmLTreeWidget)w; value->addr = (caddr_t)&t->manager.foreground; } static void CreateDefaultPixmaps(XmLTreeWidget t) { Display *dpy; Window win; XWindowAttributes attr; XColor color; Pixmap pixmap; Pixel pixel; XImage *image; int i, x, y; enum { white = 0, black = 1, yellow = 2, gray = 3 }; static unsigned short colors[4][3] = { { 65535, 65535, 65535 }, { 0, 0, 0 }, { 57344, 57344, 0 }, { 32768, 32768, 32768 }, }; static unsigned char fileMask_bits[] = { 0xf8, 0x0f, 0xfc, 0x1f, 0xfc, 0x3f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xf8, 0x7f }; static unsigned char folderMask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xf0, 0x0f, 0xfc, 0x3f, 0xfe, 0x7f, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xf8, 0x7f }; static unsigned char folderOpenMask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xf0, 0x0f, 0xfc, 0x3f, 0xfe, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xf0, 0x7f }; static char icons[3][16][16] = { { " GGGGGGGGG ", " GWWWWWWWWKK ", " GWWWWWWWWKWK ", " GWWWWWWWWKKKK ", " GWWWWWWWWWWGK ", " GWGGGGGGGWWGK ", " GWWKKKKKKKWGK ", " GWWWWWWWWWWGK ", " GWGGGGGGGWWGK ", " GWWKKKKKKKWGK ", " GWWWWWWWWWWGK ", " GWGGGGGGGWWGK ", " GWWKKKKKKKWGK ", " GWWWWWWWWWWGK ", " GGGGGGGGGGGGK ", " KKKKKKKKKKKK ", }, { " ", " ", " GGGGGG ", " GYYYYYYG ", " GGYYYYYYYYGG ", " GWWWWWWWWWWWYG ", " GWYYYYYYYYYYYGK", " GWYYYYYYYYYYYGK", " GWYYYYYYYYYYYGK", " GWYYYYYYYYYYYGK", " GWYYYYYYYYYYYGK", " GWYYYYYYYYYYYGK", " GWYYYYYYYYYYYGK", " GYYYYYYYYYYYYGK", " GGGGGGGGGGGGKK", " KKKKKKKKKKKK ", }, { " ", " ", " GGGGGG ", " GYYYYYYG ", " GGYYYYYYYYGG ", " GYYYYYYYYYYYYG ", " GYYYYYYYYYYYYGK", "GGGGGGGGGGGYYYGK", "GWWWWWWWWWYKYYGK", "GWYYYYYYYYYKYYGK", " GYYYYYYYYYYKYGK", " GYYYYYYYYYYKYGK", " GYYYYYYYYYYKGK", " GYYYYYYYYYYKGK", " GGGGGGGGGGGKK", " KKKKKKKKKKK ", }, }; dpy = XtDisplay(t); win = XtWindow(t); XGetWindowAttributes(dpy, win, &attr); t->tree.filePixmask = XCreatePixmapFromBitmapData(dpy, win, (char *)fileMask_bits, 16, 16, 1L, 0L, 1); t->tree.folderPixmask = XCreatePixmapFromBitmapData(dpy, win, (char *)folderMask_bits, 16, 16, 1L, 0L, 1); t->tree.folderOpenPixmask = XCreatePixmapFromBitmapData(dpy, win, (char *)folderOpenMask_bits, 16, 16, 1L, 0L, 1); for (i = 0; i < 4; i++) { color.red = colors[i][0]; color.green = colors[i][1]; color.blue = colors[i][2]; color.flags = DoRed | DoGreen | DoBlue; if (XAllocColor(dpy, attr.colormap, &color)) t->tree.pixColors[i] = color.pixel; else { color.flags = 0; XAllocColor(dpy, attr.colormap, &color); t->tree.pixColors[i] = color.pixel; } } image = XCreateImage(dpy, attr.visual, attr.depth, ZPixmap, 0, NULL, 16, 16, XBitmapPad(dpy), 0); if (!image) XmLWarning((Widget)t, "CreateDefaultPixmaps() - can't allocate image"); else image->data = (char *)malloc(image->bytes_per_line * 16); for (i = 0; i < 3; i++) { pixmap = XCreatePixmap(dpy, win, 16, 16, attr.depth); for (x = 0; x < 16; x++) for (y = 0; y < 16; y++) { switch (icons[i][y][x]) { case ' ': pixel = t->core.background_pixel; break; case 'W': pixel = t->tree.pixColors[white]; break; case 'K': pixel = t->tree.pixColors[black]; break; case 'Y': pixel = t->tree.pixColors[yellow]; break; case 'G': pixel = t->tree.pixColors[gray]; break; } XPutPixel(image, x, y, pixel); } if (image) XPutImage(dpy, pixmap, t->grid.gc, image, 0, 0, 0, 0, 16, 16); if (i == 0) t->tree.filePixmap = pixmap; else if (i == 1) t->tree.folderPixmap = pixmap; else t->tree.folderOpenPixmap = pixmap; } if (image) XDestroyImage(image); t->tree.defaultPixmapsCreated = 1; } static XmLTreeWidget WidgetToTree(Widget w, char *funcname) { char buf[256]; if (!XmLIsTree(w)) { sprintf(buf, "%s - widget not an XmLTree", funcname); XmLWarning(w, buf); return 0; } return (XmLTreeWidget)w; } /* Public Functions */ Widget XmLCreateTree(Widget parent, char *name, ArgList arglist, Cardinal argcount) { return XtCreateWidget(name, xmlTreeWidgetClass, parent, arglist, argcount); } void XmLTreeAddRow(Widget w, int level, Boolean expands, Boolean isExpanded, int position, Pixmap pixmap, Pixmap pixmask, XmString string) { XmLTreeRowDefinition row; row.level = level; row.expands = expands; row.isExpanded = isExpanded; row.pixmap = pixmap; row.pixmask = pixmask; row.string = string; XmLTreeAddRows(w, &row, 1, position); } void XmLTreeAddRows(Widget w, XmLTreeRowDefinition *rows, int count, int position) { XmLTreeWidget t; XmLTreeRow row; int i, level; unsigned char layoutFrozen; t = WidgetToTree(w, "XmLTreeAddRows()"); if (!t || count <= 0) return; if (position < 0 || position > t->grid.rowCount) position = t->grid.rowCount; layoutFrozen = t->grid.layoutFrozen; if (layoutFrozen == False) XtVaSetValues(w, XmNlayoutFrozen, True, NULL); XmLGridAddRows(w, XmCONTENT, position, count); for (i = 0; i < count; i++) { row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, position + i); if (!row) continue; level = rows[i].level; if (level < 0) level = 0; row->tree.level = level; row->tree.expands = rows[i].expands; row->tree.isExpanded = rows[i].isExpanded; XtVaSetValues(w, XmNrow, position + i, XmNcolumn, 0, XmNcellString, rows[i].string, XmNcellPixmap, rows[i].pixmap, XmNcellPixmapMask, rows[i].pixmask, NULL); } if (layoutFrozen == False) XtVaSetValues(w, XmNlayoutFrozen, False, NULL); } void XmLTreeDeleteChildren(Widget w, int row) { XmLTreeWidget t; XmLTreeRow rowp; int ii, jj, level, rows; t = WidgetToTree(w, "XmLTreeDeleteChildren()"); rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, row); level = rowp->tree.level; rows = t->grid.rowCount; ii = row + 1; while (ii < rows) { rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, ii); if (rowp->tree.level <= level) break; ii++; } jj = ii - row - 1; if (jj > 0) XmLGridDeleteRows(w, XmCONTENT, row + 1, jj); } nedit-5.6.orig/Microline/XmL/Tree.h0000644000175000017500000000626710245647600015622 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #ifndef XmLTreeH #define XmLTreeH #include "XmL.h" #include "Grid.h" #ifdef XmL_CPP extern "C" { #endif extern WidgetClass xmlTreeWidgetClass; typedef struct _XmLTreeClassRec *XmLTreeWidgetClass; typedef struct _XmLTreeRec *XmLTreeWidget; typedef struct _XmLTreeRowRec *XmLTreeRow; #define XmLIsTree(w) XtIsSubclass((w), xmlTreeWidgetClass) Widget XmLCreateTree(Widget parent, char *name, ArgList arglist, Cardinal argcount); void XmLTreeAddRow(Widget w, int level, Boolean expands, Boolean isExpaned, int position, Pixmap pixmap, Pixmap pixmask, XmString string); void XmLTreeAddRows(Widget w, XmLTreeRowDefinition *rows, int count, int position); void XmLTreeDeleteChildren(Widget w, int position); #ifdef XmL_CPP } #endif #endif nedit-5.6.orig/Microline/XmL/TreeP.h0000644000175000017500000001066710077552126015742 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #ifndef XmLTreePH #define XmLTreePH #include #ifndef MOTIF11 #include #include #endif #include "Tree.h" #include "GridP.h" /* row value mask for get/set values */ #define RVML XmLGridRowValueMaskLen #define XmLTreeRowLevel (1L << (RVML)) #define XmLTreeRowExpands (1L << (RVML + 1)) #define XmLTreeRowIsExpanded (1L << (RVML + 2)) typedef struct _XmLTreeRowPart { Boolean expands; int level; Boolean hasChildren, hasSiblings, isExpanded; Dimension stringWidth; Boolean stringWidthValid; } XmLTreeRowPart; struct _XmLTreeRowRec { XmLGridRowPart grid; XmLTreeRowPart tree; }; typedef struct _XmLTreePart { /* resources */ Dimension levelSpacing; Pixel lineColor, pmColor; XtCallbackList collapseCallback, expandCallback; /* private data */ char *linesData; int linesSize, linesMaxLevel; int recalcTreeWidth; char defaultPixmapsCreated; Pixel pixColors[4]; Pixmap filePixmask, folderPixmask, folderOpenPixmask; Pixmap filePixmap, folderPixmap, folderOpenPixmap; /* row resources */ int rowLevel; Boolean rowExpands, rowIsExpanded; /* Causes the tree to NOT render any pixmaps */ Boolean ignorePixmaps; } XmLTreePart; typedef struct _XmLTreeRec { CorePart core; CompositePart composite; ConstraintPart constraint; XmManagerPart manager; XmLGridPart grid; XmLTreePart tree; } XmLTreeRec; typedef struct _XmLTreeClassPart { int unused; } XmLTreeClassPart; typedef struct _XmLTreeClassRec { CoreClassPart core_class; CompositeClassPart composite_class; ConstraintClassPart constraint_class; XmManagerClassPart manager_class; XmLGridClassPart grid_class; XmLTreeClassPart tree_class; } XmLTreeClassRec; extern XmLTreeClassRec xmlTreeClassRec; typedef struct _XmLTreeConstraintPart { int unused; } XmLTreeConstraintPart; typedef struct _XmLTreeConstraintRec { XmManagerConstraintPart manager; XmLGridConstraintPart grid; XmLTreeConstraintPart tree; } XmLTreeConstraintRec, *XmLTreeConstraintPtr; #endif nedit-5.6.orig/Microline/XmL/XmL.c0000644000175000017500000011227510245647600015413 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include "XmL.h" #include #include #include #include #include #include #ifdef MOTIF11 #include #else #include #endif #include #include #include #include #ifdef SUNOS4 int fprintf(FILE *, char *, ...); #endif static void XmLDrawnBDestroyCB(Widget w, XtPointer clientData, XtPointer); static void XmLDrawnBDrawCB(Widget, XtPointer, XtPointer); static void XmLDrawnBDrawStringCB(Widget, XtPointer, XtPointer); static int XmLDrawCalc(Widget w, Dimension width, Dimension height, unsigned char alignment, XRectangle *rect, XRectangle *clipRect, int *x, int *y); static void XmLFontGetAverageWidth(XFontStruct *fs, short *width); static void XmLMessageBoxResponse(Widget, XtPointer, XtPointer); static void XmLMessageBoxWMDelete(Widget, XtPointer, XtPointer); static void XmLSortFunc(char *lvec, char *rvec); struct _XmLArrayRec { char _autonumber, _growFast; int _count, _size; void **_items; }; XmLArray XmLArrayNew(char autonumber, char growFast) { XmLArray array; array = (XmLArray)malloc(sizeof(struct _XmLArrayRec)); array->_count = 0; array->_size = 0; array->_items = 0; array->_autonumber = autonumber; array->_growFast = growFast; return array; } void XmLArrayFree(XmLArray array) { if (array->_items) free((char *)array->_items); free((char *)array); } void XmLArrayAdd(XmLArray array, int pos, int count) { int i; void **items; if (count < 1) return; if (pos < 0 || pos > array->_count) pos = array->_count; if (array->_count + count >= array->_size) { if (array->_growFast) { if (!array->_size) array->_size = count + 256; else array->_size = (array->_count + count) * 2; } else array->_size = array->_count + count; items = (void **)malloc(sizeof(void *) * array->_size); if (array->_items) { for (i = 0; i < array->_count; i++) items[i] = array->_items[i]; free((char *)array->_items); } array->_items = items; } for (i = array->_count + count - 1; i >= pos + count; i--) { array->_items[i] = array->_items[i - count]; if (array->_autonumber) ((XmLArrayItem *)array->_items[i])->pos = i; } for (i = pos; i < pos + count; i++) array->_items[i] = 0; array->_count += count; } int XmLArrayDel(XmLArray array, int pos, int count) { int i; if (pos < 0 || pos + count > array->_count) return -1; for (i = pos; i < array->_count - count; i++) { array->_items[i] = array->_items[i + count]; if (array->_autonumber) ((XmLArrayItem *)array->_items[i])->pos = i; } array->_count -= count; if (!array->_count) { if (array->_items) free((char *)array->_items); array->_items = 0; array->_size = 0; } return 0; } int XmLArraySet(XmLArray array, int pos, void *item) { if (pos < 0 || pos >= array->_count) return -1; if (array->_items[pos]) fprintf(stderr, "XmLArraySet: warning: overwriting pointer\n"); array->_items[pos] = item; if (array->_autonumber) ((XmLArrayItem *)array->_items[pos])->pos = pos; return 0; } void * XmLArrayGet(XmLArray array, int pos) { if (pos < 0 || pos >= array->_count) return 0; return array->_items[pos]; } int XmLArrayGetCount(XmLArray array) { return array->_count; } int XmLArrayMove(XmLArray array, int newPos, int pos, int count) { void **items; int i; if (count <= 0) return -1; if (newPos < 0 || newPos + count > array->_count) return -1; if (pos < 0 || pos + count > array->_count) return -1; if (pos == newPos) return 0; /* copy items to move */ items = (void **)malloc(sizeof(void *) * count); for (i = 0; i < count; i++) items[i] = array->_items[pos + i]; /* move real items around */ if (newPos < pos) for (i = pos + count - 1; i >= newPos + count; i--) { array->_items[i] = array->_items[i - count]; if (array->_autonumber) ((XmLArrayItem *)array->_items[i])->pos = i; } else for (i = pos; i < newPos; i++) { array->_items[i] = array->_items[i + count]; if (array->_autonumber) ((XmLArrayItem *)array->_items[i])->pos = i; } /* move items copy back */ for (i = 0; i < count; i++) { array->_items[newPos + i] = items[i]; if (array->_autonumber) ((XmLArrayItem *)array->_items[newPos + i])->pos = newPos + i; } free((char *)items); return 0; } int XmLArrayReorder(XmLArray array, int *newPositions, int pos, int count) { int i; void **items; if (count <= 0) return -1; if (pos < 0 || pos + count > array->_count) return -1; for (i = 0; i < count; i++) { if (newPositions[i] < pos || newPositions[i] >= pos + count) return -1; } items = (void **)malloc(sizeof(void *) * count); for (i = 0; i < count; i++) items[i] = array->_items[newPositions[i]]; for (i = 0; i < count; i++) { array->_items[pos + i] = items[i]; if (array->_autonumber) ((XmLArrayItem *)array->_items[pos + i])->pos = pos + i; } free((char *)items); return 0; } int XmLArraySort(XmLArray array, XmLArrayCompareFunc compare, void *userData, int pos, int count) { int i; if (pos < 0 || pos + count > array->_count) return -1; XmLSort(&array->_items[pos], count, sizeof(void *), (XmLSortCompareFunc)compare, userData); if (array->_autonumber) for (i = pos; i < pos + count; i++) ((XmLArrayItem *)array->_items[i])->pos = i; return 0; } Boolean XmLCvtStringToUChar(Display *dpy, char *resname, XmLStringToUCharMap *map, XrmValuePtr fromVal, XrmValuePtr toVal) { char *from; int i, /*num,*/ valid; from = (char *)fromVal->addr; valid = 0; i = 0; while (map[i].name) { if (!strcmp(from, map[i].name)) { valid = 1; break; } i++; } if (!valid) { XtDisplayStringConversionWarning(dpy, from, resname); toVal->size = 0; toVal->addr = 0; return False; } if (toVal->addr) { if (toVal->size < sizeof(unsigned char)) { toVal->size = sizeof(unsigned char); return False; } *(unsigned char *)(toVal->addr) = map[i].value; } else toVal->addr = (caddr_t)&map[i].value; toVal->size = sizeof(unsigned char); return True; } int XmLDateDaysInMonth(int m, int y) { static int d[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; if (m < 1 || m > 12 || y < 1753 || y > 9999) return -1; if (m == 2 && (!((y % 4) && (y % 100)) || !(y % 400))) return 29; return d[m - 1]; } /* Calculation from Communications Of The ACM, Vol 6, No 8, p 444 */ /* sun is 0, sat is 6 */ int XmLDateWeekDay(int m, int d, int y) { long jd, j1, j2; if (m < 1 || m > 12 || d < 1 || d > XmLDateDaysInMonth(m, y) || y < 1753 || y > 9999) return -1; if (m > 2) m -= 3; else { m += 9; y--; } j1 = y / 100; j2 = y - 100 * j1; jd = (146097 * j1) / 4 + (1461 * j2) / 4 + (153 * m + 2) / 5 + 1721119 + d; return (jd + 1) % 7; } typedef struct { GC gc; int type; int dir; XFontStruct *fontStruct; } XmLDrawnBData; void XmLDrawnButtonSetType(Widget w, int drawnType, int drawnDir) { XmLDrawnBData *dd; XmDrawnButtonWidget b; XmString str; XmFontList fontlist; XGCValues values; XtGCMask mask; Dimension width, height, dim; Dimension highlightThickness, shadowThickness; Dimension marginWidth, marginHeight; Dimension marginTop, marginBottom, marginLeft, marginRight; if (!XtIsSubclass(w, xmDrawnButtonWidgetClass)) { XmLWarning(w, "DrawnButtonSetType() - not an XmDrawnButton"); return; } XtVaSetValues(w, XmNpushButtonEnabled, True, NULL); XtRemoveAllCallbacks(w, XmNexposeCallback); XtRemoveAllCallbacks(w, XmNresizeCallback); if (drawnType == XmDRAWNB_STRING && drawnDir == XmDRAWNB_RIGHT) { XtVaSetValues(w, XmNlabelType, XmSTRING, NULL); return; } b = (XmDrawnButtonWidget)w; dd = (XmLDrawnBData *)malloc(sizeof(XmLDrawnBData)); dd->type = drawnType; dd->dir = drawnDir; dd->gc = 0; if (dd->type == XmDRAWNB_STRING) { XtVaGetValues(w, XmNlabelString, &str, XmNfontList, &fontlist, XmNhighlightThickness, &highlightThickness, XmNshadowThickness, &shadowThickness, XmNmarginHeight, &marginHeight, XmNmarginWidth, &marginWidth, XmNmarginTop, &marginTop, XmNmarginBottom, &marginBottom, XmNmarginLeft, &marginLeft, XmNmarginRight, &marginRight, NULL); if (!str && XtName(w)) str = XmStringCreateSimple(XtName(w)); if (!str) str = XmStringCreateSimple(""); XmStringExtent(fontlist, str, &width, &height); XmStringFree(str); if (drawnDir == XmDRAWNB_UP || drawnDir == XmDRAWNB_DOWN) { dim = width; width = height; height = dim; } height += (highlightThickness + shadowThickness + marginHeight) * 2 + marginTop + marginBottom; width += (highlightThickness + shadowThickness + marginWidth) * 2 + marginLeft + marginRight; /* change to pixmap type so label string isnt drawn */ XtVaSetValues(w, XmNlabelType, XmPIXMAP, NULL); XtVaSetValues(w, XmNwidth, width, XmNheight, height, NULL); XtAddCallback(w, XmNexposeCallback, XmLDrawnBDrawStringCB, (XtPointer)dd); XtAddCallback(w, XmNresizeCallback, XmLDrawnBDrawStringCB, (XtPointer)dd); } else { mask = GCForeground; values.foreground = b->primitive.foreground; dd->gc = XtGetGC(w, mask, &values); XtAddCallback(w, XmNexposeCallback, XmLDrawnBDrawCB, (XtPointer)dd); XtAddCallback(w, XmNresizeCallback, XmLDrawnBDrawCB, (XtPointer)dd); } XtAddCallback(w, XmNdestroyCallback, XmLDrawnBDestroyCB, (XtPointer)dd); } static void XmLDrawnBDestroyCB(Widget w, XtPointer clientData, XtPointer callData) { XmLDrawnBData *dd; dd = (XmLDrawnBData *)clientData; if (dd->type == XmDRAWNB_STRING) { if (dd->gc) { XFreeGC(XtDisplay(w), dd->gc); XFreeFont(XtDisplay(w), dd->fontStruct); } } else XtReleaseGC(w, dd->gc); free((char *)dd); } static void XmLDrawnBDrawStringCB(Widget w, XtPointer clientData, XtPointer callData) { XmLDrawnBData *dd; XmFontList fontlist; XmString str; XmStringDirection stringDir; unsigned char drawDir, alignment; int width, height, xoff, yoff, drawWidth; Pixel fg; Dimension highlightThickness; Dimension shadowThickness, marginWidth, marginHeight; Dimension marginLeft, marginRight, marginTop, marginBottom; if (!XtIsRealized(w)) return; dd = (XmLDrawnBData *)clientData; XtVaGetValues(w, XmNlabelString, &str, NULL); if (!str && XtName(w)) str = XmStringCreateSimple(XtName(w)); if (!str) return; XtVaGetValues(w, XmNforeground, &fg, XmNfontList, &fontlist, XmNalignment, &alignment, XmNhighlightThickness, &highlightThickness, XmNshadowThickness, &shadowThickness, XmNmarginWidth, &marginWidth, XmNmarginHeight, &marginHeight, XmNmarginLeft, &marginLeft, XmNmarginRight, &marginRight, XmNmarginTop, &marginTop, XmNmarginBottom, &marginBottom, NULL); xoff = highlightThickness + shadowThickness + marginLeft + marginWidth; yoff = highlightThickness + shadowThickness + marginTop + marginHeight; width = XtWidth(w) - xoff - xoff + marginLeft - marginRight; height = XtHeight(w) - yoff - yoff + marginTop - marginBottom; if (XmIsManager(XtParent(w))) XtVaGetValues(XtParent(w), XmNstringDirection, &stringDir, NULL); else stringDir = XmSTRING_DIRECTION_L_TO_R; switch (dd->dir) { case XmDRAWNB_LEFT: drawDir = XmSTRING_LEFT; break; case XmDRAWNB_UP: drawDir = XmSTRING_UP; break; case XmDRAWNB_DOWN: drawDir = XmSTRING_DOWN; break; default: drawDir = XmSTRING_RIGHT; break; } if (drawDir == XmSTRING_LEFT || drawDir == XmSTRING_RIGHT) drawWidth = width; else drawWidth = height; if (!dd->gc) { dd->gc = XCreateGC(XtDisplay(w), XtWindow(w), 0, NULL); dd->fontStruct = XLoadQueryFont(XtDisplay(w), "fixed"); if (!dd->fontStruct) { XmLWarning(w, "DrawnBDrawString() - FATAL can't load fixed font"); return; } XSetFont(XtDisplay(w), dd->gc, dd->fontStruct->fid); } XSetForeground(XtDisplay(w), dd->gc, fg); XmLStringDrawDirection(XtDisplay(w), XtWindow(w), fontlist, str, dd->gc, xoff, yoff, drawWidth, alignment, stringDir, drawDir); XmStringFree(str); } static void XmLDrawnBDrawCB(Widget w, XtPointer clientData, XtPointer callData) { XmLDrawnBData *dd; XmDrawnButtonWidget b; /* unsigned char drawDir;*/ /* unsigned char alignment;*/ Display *dpy; Window win; GC gc; XPoint p[2][5]; XSegment seg; int np[2]; int i, j, temp; int md, type, dir; int avgx, avgy, xoff, yoff, st; if (!XtIsRealized(w)) return; dd = (XmLDrawnBData *)clientData; type = dd->type; dir = dd->dir; gc = dd->gc; b = (XmDrawnButtonWidget)w; win = XtWindow(w); dpy = XtDisplay(w); st = b->primitive.shadow_thickness; i = st * 2 + b->primitive.highlight_thickness * 2; /* calculate max dimension */ md = XtWidth(w) - i; if (md > ((int)XtHeight(w) - i)) md = XtHeight(w) - i; if (md < 4) return; xoff = ((int)XtWidth(w) - md) / 2; yoff = ((int)XtHeight(w) - md) / 2; np[0] = 0; np[1] = 0; switch (type) { case XmDRAWNB_SMALLARROW: p[0][0].x = md / 4; p[0][0].y = md / 4; p[0][1].x = md / 4; p[0][1].y = md - md / 4; p[0][2].x = md - md / 4; p[0][2].y = md / 2; np[0] = 3; break; case XmDRAWNB_ARROW: p[0][0].x = md / 6; p[0][0].y = md / 6; p[0][1].x = md / 6; p[0][1].y = md - md / 6; p[0][2].x = md - md / 6; p[0][2].y = md / 2; np[0] = 3; break; case XmDRAWNB_ARROWLINE: p[0][0].x = md / 5; p[0][0].y = md / 5; p[0][1].x = md / 5; p[0][1].y = md - md / 5; p[0][2].x = md - md / 5; p[0][2].y = md / 2; np[0] = 3; p[1][0].x = md - md / 5 + 1; p[1][0].y = md / 5; p[1][1].x = md - md / 5 + 1; p[1][1].y = md - md / 5; p[1][2].x = md - md / 10; p[1][2].y = md - md / 5; p[1][3].x = md - md / 10; p[1][3].y = md / 5; np[1] = 4; break; case XmDRAWNB_DOUBLEARROW: /* odd major dimensions can give jagged lines */ if (md % 2) md -= 1; p[0][0].x = md / 10; p[0][0].y = md / 10; p[0][1].x = md / 10; p[0][1].y = md - md / 10; p[0][2].x = md / 2; p[0][2].y = md / 2; np[0] = 3; p[1][0].x = md - md / 2; p[1][0].y = md / 10; p[1][1].x = md - md / 2; p[1][1].y = md - md / 10; p[1][2].x = md - md / 10; p[1][2].y = md / 2; np[1] = 3; break; case XmDRAWNB_SQUARE: p[0][0].x = md / 3; p[0][0].y = md / 3; p[0][1].x = md / 3; p[0][1].y = md - md / 3; p[0][2].x = md - md / 3; p[0][2].y = md - md / 3; p[0][3].x = md - md / 3; p[0][3].y = md / 3; np[0] = 4; break; case XmDRAWNB_DOUBLEBAR: p[0][0].x = md / 3; p[0][0].y = md / 4; p[0][1].x = md / 3; p[0][1].y = md - md / 4; p[0][2].x = md / 2 - md / 10; p[0][2].y = md - md / 4; p[0][3].x = md / 2 - md / 10; p[0][3].y = md / 4; np[0] = 4; p[1][0].x = md - md / 3; p[1][0].y = md / 4; p[1][1].x = md - md / 3; p[1][1].y = md - md / 4; p[1][2].x = md - md / 2 + md / 10; p[1][2].y = md - md / 4; p[1][3].x = md - md / 2 + md / 10; p[1][3].y = md / 4; np[1] = 4; break; } for (i = 0; i < 2; i++) { avgx = 0; avgy = 0; for (j = 0; j < np[i]; j++) { switch (dir) { case XmDRAWNB_RIGHT: /* points unchanged */ break; case XmDRAWNB_LEFT: p[i][j].x = md - p[i][j].x - 1; break; case XmDRAWNB_UP: temp = p[i][j].x; p[i][j].x = p[i][j].y; p[i][j].y = md - temp; break; case XmDRAWNB_DOWN: temp = p[i][j].x; p[i][j].x = p[i][j].y; p[i][j].y = temp; break; } p[i][j].x += xoff; p[i][j].y += yoff; avgx += p[i][j].x; avgy += p[i][j].y; } if (!np[i]) continue; avgx /= np[i]; avgy /= np[i]; XFillPolygon(dpy, win, gc, p[i], np[i], Nonconvex, CoordModeOrigin); p[i][np[i]].x = p[i][0].x; p[i][np[i]].y = p[i][0].y; for (j = 0; j < np[i]; j++) { seg.x1 = p[i][j].x; seg.y1 = p[i][j].y; seg.x2 = p[i][j + 1].x; seg.y2 = p[i][j + 1].y; if ((seg.x1 <= avgx && seg.x2 <= avgx) || (seg.y1 <= avgy && seg.y2 <= avgy)) XDrawSegments(dpy, win, b->primitive.bottom_shadow_GC, &seg, 1); else XDrawSegments(dpy, win, b->primitive.top_shadow_GC, &seg, 1); } } } #define XmLDrawNODRAW 0 #define XmLDrawNOCLIP 1 #define XmLDrawCLIPPED 2 static int XmLDrawCalc(Widget w, Dimension width, Dimension height, unsigned char alignment, XRectangle *rect, XRectangle *clipRect, int *x, int *y) { if (rect->width <= 4 || rect->height <= 4 || clipRect->width < 3 || clipRect->height < 3 || !width || !height || !XtIsRealized(w) || XmLRectIntersect(rect, clipRect) == XmLRectOutside) return XmLDrawNODRAW; if (alignment == XmALIGNMENT_TOP_LEFT || alignment == XmALIGNMENT_LEFT || alignment == XmALIGNMENT_BOTTOM_LEFT) *x = rect->x + 2; else if (alignment == XmALIGNMENT_TOP || alignment == XmALIGNMENT_CENTER || alignment == XmALIGNMENT_BOTTOM) *x = rect->x + ((int)rect->width - (int)width) / 2; else *x = rect->x + rect->width - width - 2; if (alignment == XmALIGNMENT_TOP || alignment == XmALIGNMENT_TOP_LEFT || alignment == XmALIGNMENT_TOP_RIGHT) *y = rect->y + 2; else if (alignment == XmALIGNMENT_LEFT || alignment == XmALIGNMENT_CENTER || alignment == XmALIGNMENT_RIGHT) *y = rect->y + ((int)rect->height - (int)height) / 2; else *y = rect->y + rect->height - height - 2; if (clipRect->x == rect->x && clipRect->y == rect->y && clipRect->width == rect->width && clipRect->height == rect->height && (int)width + 4 <= (int)clipRect->width && (int)height + 4 <= (int)clipRect->height) return XmLDrawNOCLIP; return XmLDrawCLIPPED; } void XmLDrawToggle(Widget w, Boolean state, Dimension size, unsigned char alignment, GC gc, Pixel backgroundColor, Pixel topColor, Pixel bottomColor, Pixel checkColor, XRectangle *rect, XRectangle *clipRect) { Display *dpy; Window win; XPoint point[5]; int x, y, cx[3], cy[4], drawType; drawType = XmLDrawCalc(w, size, size, alignment, rect, clipRect, &x, &y); if (size < 3 || drawType == XmLDrawNODRAW) return; dpy = XtDisplay(w); win = XtWindow(w); if (drawType == XmLDrawCLIPPED) XSetClipRectangles(dpy, gc, 0, 0, clipRect, 1, Unsorted); /* background */ XSetForeground(dpy, gc, backgroundColor); XFillRectangle(dpy, win, gc, x, y, size, size); /* box shadow */ XSetForeground(dpy, gc, topColor); point[0].x = x; point[0].y = y + size - 1; point[1].x = x; point[1].y = y; point[2].x = x + size - 1; point[2].y = y; XDrawLines(dpy, win, gc, point, 3, CoordModeOrigin); point[1].x = x + size - 1; point[1].y = y + size - 1; XSetForeground(dpy, gc, bottomColor); XDrawLines(dpy, win, gc, point, 3, CoordModeOrigin); if (state == True) { /* check */ cx[0] = x + 1; cx[1] = x + (((int)size - 3) / 3) + 1; cx[2] = x + size - 2; cy[0] = y + 1; cy[1] = y + (((int)size - 3) / 2) + 1; cy[2] = y + ((((int)size - 3) * 2) / 3) + 1; cy[3] = y + size - 2; point[0].x = cx[0]; point[0].y = cy[1]; point[1].x = cx[1]; point[1].y = cy[3]; point[2].x = cx[2]; point[2].y = cy[0]; point[3].x = cx[1]; point[3].y = cy[2]; point[4].x = point[0].x; point[4].y = point[0].y; XSetForeground(dpy, gc, checkColor); XFillPolygon(dpy, win, gc, point, 4, Nonconvex, CoordModeOrigin); XDrawLines(dpy, win, gc, point, 5, CoordModeOrigin); } if (drawType == XmLDrawCLIPPED) XSetClipMask(dpy, gc, None); } int XmLRectIntersect(XRectangle *r1, XRectangle *r2) { if (!r1->width || !r1->height || !r2->width || !r2->height) return XmLRectOutside; if (r1->x + (int)r1->width - 1 < r2->x || r1->x > r2->x + (int)r2->width - 1 || r1->y + (int)r1->height - 1 < r2->y || r1->y > r2->y + (int)r2->height - 1) return XmLRectOutside; if (r1->x >= r2->x && r1->x + (int)r1->width <= r2->x + (int)r2->width && r1->y >= r2->y && r1->y + (int)r1->height <= r2->y + (int)r2->height) return XmLRectInside; /* r1 inside r2 */ return XmLRectPartial; } XmFontList XmLFontListCopyDefault(Widget widget) { Widget parent; XFontStruct *font; XmFontList fontList, fl; fontList = 0; parent = XtParent(widget); while (parent) { fl = 0; if (XmIsVendorShell(parent) || XmIsMenuShell(parent)) XtVaGetValues(parent, XmNdefaultFontList, &fl, NULL); else if (XmIsBulletinBoard(parent)) XtVaGetValues(parent, XmNbuttonFontList, &fl, NULL); if (fl) { fontList = XmFontListCopy(fl); parent = 0; } if (parent) parent = XtParent(parent); } if (!fontList) { font = XLoadQueryFont(XtDisplay(widget), "fixed"); if (!font) XmLWarning(widget, "FontListCopyDefault() - FATAL ERROR - can't load fixed font"); fontList = XmFontListCreate(font, XmSTRING_DEFAULT_CHARSET); } return fontList; } void XmLFontListGetDimensions(XmFontList fontList, short *width, short *height, Boolean useAverageWidth) { XmStringCharSet charset; XmFontContext context; XFontStruct *fs; short w, h; #if XmVersion < 2000 /* --- begin code to work around Motif 1.x internal bug */ typedef struct { XmFontList nextFontList; Boolean unused; } XmFontListContextRec; typedef struct { XFontStruct *font; XmStringCharSet unused; } XmFontListRec; XmFontList nextFontList; #endif *width = 0; *height = 0; if (XmFontListInitFontContext(&context, fontList)) { while (1) { #if XmVersion < 2000 /* --- begin code to work around Motif internal bug */ /* --- this code must be removed for Motif 2.0 */ nextFontList = ((XmFontListContextRec *)context)->nextFontList; if (!nextFontList) break; if (!((XmFontListRec *)nextFontList)->font) break; /* --- end Motif workaround code */ #endif if (XmFontListGetNextFont(context, &charset, &fs) == False) break; XtFree(charset); if (useAverageWidth == True) XmLFontGetAverageWidth(fs, &w); else w = fs->max_bounds.width; h = fs->max_bounds.ascent + fs->max_bounds.descent; if (*height < h) *height = h; if (*width < w) *width = w; } XmFontListFreeFontContext(context); } } static void XmLFontGetAverageWidth(XFontStruct *fs, short *width) { long aw, n; int r, c, mm, i; XCharStruct *cs; n = 0; aw = 0; mm = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1; for (r = fs->min_byte1; r <= fs->max_byte1; r++) for (c = fs->min_char_or_byte2; c <= fs->max_char_or_byte2; c++) { if (!fs->per_char) continue; i = ((r - fs->min_byte1) * mm) + (c - fs->min_char_or_byte2); cs = &fs->per_char[i]; if (!cs->width) continue; aw += cs->width; n++; } if (n) aw = aw / n; else aw = fs->min_bounds.width; *width = (short)aw; } int _XmLKey; void XmLInitialize(void) { static int first = 1; if (!first) return; first = 0; #ifdef XmLEVAL fprintf(stderr, "XmL: This is an evalation version of the Microline\n"); fprintf(stderr, "XmL: Widget Library. Some features are disabled.\n"); #endif #ifdef XmLJAVA if (_XmLKey != 444) { fprintf(stderr, "XmL: Error: This version of the library will only"); fprintf(stderr, "XmL: work with JAVA.\n"); exit(0); } #endif } int XmLMessageBox(Widget w, char *string, Boolean okOnly) { int status = 0; Widget dialog, shell; Arg args[3]; XtAppContext context; XmString str, titleStr; String shellTitle; Atom WM_DELETE_WINDOW; str = XmStringCreateLtoR(string, XmSTRING_DEFAULT_CHARSET); XtSetArg(args[0], XmNmessageString, str); XtSetArg(args[1], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL); shell = XmLShellOfWidget(w); if (shell) XtVaGetValues(shell, XmNtitle, &shellTitle, NULL); if (shell && shellTitle) titleStr = XmStringCreateLtoR(shellTitle, XmSTRING_DEFAULT_CHARSET); else titleStr = XmStringCreateSimple("Notice"); XtSetArg(args[2], XmNdialogTitle, titleStr); if (okOnly == True) dialog = XmCreateMessageDialog(XtParent(w), "popup", args, 3); else dialog = XmCreateQuestionDialog(XtParent(w), "popup", args, 3); WM_DELETE_WINDOW = XmInternAtom(XtDisplay(w), "WM_DELETE_WINDOW", False); XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, XmLMessageBoxWMDelete, (caddr_t)&status); XmStringFree(str); XmStringFree(titleStr); XtAddCallback(dialog, XmNokCallback, XmLMessageBoxResponse, (XtPointer)&status); if (okOnly == True) { XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON)); XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON)); } else { XtAddCallback(dialog, XmNcancelCallback, XmLMessageBoxResponse, (XtPointer)&status); XtAddCallback(dialog, XmNhelpCallback, XmLMessageBoxResponse, (XtPointer)&status); } XtManageChild(dialog); context = XtWidgetToApplicationContext(w); while (!status || XtAppPending(context)) XtAppProcessEvent(context, XtIMAll); XtDestroyWidget(dialog); return status; } static void XmLMessageBoxWMDelete(Widget w, XtPointer clientData, XtPointer callData) { int *status = (int *)clientData; *status = 1; } static void XmLMessageBoxResponse(Widget w, XtPointer clientData, XtPointer callData) { int *status = (int *)clientData; XmAnyCallbackStruct *reason; reason = (XmAnyCallbackStruct *)callData; switch (reason->reason) { case XmCR_OK: *status = 1; break; case XmCR_CANCEL: *status = 2; break; case XmCR_HELP: *status = 3; break; } } void XmLPixmapDraw(Widget w, Pixmap pixmap, Pixmap pixmask, int pixmapWidth, int pixmapHeight, unsigned char alignment, GC gc, XRectangle *rect, XRectangle *clipRect) { Display *dpy; Window win; int px, py, x, y, width, height, drawType; if (pixmap == XmUNSPECIFIED_PIXMAP) return; dpy = XtDisplay(w); win = XtWindow(w); width = pixmapWidth; height = pixmapHeight; if (!width || !height) { alignment = XmALIGNMENT_TOP_LEFT; width = clipRect->width - 4; height = clipRect->height - 4; } drawType = XmLDrawCalc(w, width, height, alignment, rect, clipRect, &x, &y); if (drawType == XmLDrawNODRAW) return; px = 0; py = 0; /* clip top */ if (clipRect->y > y && clipRect->y < y + height - 1) { py = clipRect->y - y; y += py; height -= py; } /* clip bottom */ if (clipRect->y + (int)clipRect->height - 1 >= y && clipRect->y + (int)clipRect->height - 1 <= y + height - 1) height = clipRect->y + clipRect->height - y; /* clip left */ if (clipRect->x > x && clipRect->x < x + width - 1) { px = clipRect->x - x; x += px; width -= px; } /* clip right */ if (clipRect->x + (int)clipRect->width - 1 >= x && clipRect->x + (int)clipRect->width - 1 <= x + width - 1) width = clipRect->x + clipRect->width - x; if (pixmask != XmUNSPECIFIED_PIXMAP) { XSetClipMask(dpy, gc, pixmask); XSetClipOrigin(dpy, gc, x - px, y - py); } XSetGraphicsExposures(dpy, gc, False); XCopyArea(dpy, pixmap, win, gc, px, py, width, height, x, y); XSetGraphicsExposures(dpy, gc, True); if (pixmask != XmUNSPECIFIED_PIXMAP) { XSetClipMask(dpy, gc, None); XSetClipOrigin(dpy, gc, 0, 0); } } Widget XmLShellOfWidget(Widget w) { while(1) { if (!w) return 0; if (XtIsSubclass(w, shellWidgetClass)) return w; w = XtParent(w); } } static XmLSortCompareFunc XmLSortCompare; static int XmLSortEleSize; static void *XmLSortUserData; void XmLSort(void *base, int numItems, unsigned int itemSize, XmLSortCompareFunc compare, void *userData) { XmLSortCompareFunc oldCompare; int oldEleSize; void *oldUserData; char *lvec, *rvec; if (numItems < 2) return; /* for sorts within a sort compare function, we must save any global sort variables on the local stack and restore them when finished */ oldCompare = XmLSortCompare; oldEleSize = XmLSortEleSize; oldUserData = XmLSortUserData; XmLSortCompare = compare; XmLSortEleSize = itemSize; XmLSortUserData = userData; lvec = (char *)base; rvec = lvec + (numItems - 1) * itemSize; XmLSortFunc(lvec, rvec); XmLSortCompare = oldCompare; XmLSortEleSize = oldEleSize; XmLSortUserData = oldUserData; } #define SWAP(p1, p2) \ { \ if (p1 != p2) \ { \ int zi; \ char zc; \ for (zi = 0; zi < XmLSortEleSize; zi++) \ { \ zc = (p1)[zi]; \ (p1)[zi] = (p2)[zi]; \ (p2)[zi] = zc; \ } \ }\ } static void XmLSortFunc(char *lvec, char *rvec) { int i; char *nlvec, *nrvec, *pvec; start: i = (*XmLSortCompare)(XmLSortUserData, lvec, rvec); /* two item sort */ if (rvec == lvec + XmLSortEleSize) { if (i > 0) SWAP(lvec, rvec) return; } /* find mid of three items */ pvec = lvec + ((rvec - lvec) / (XmLSortEleSize * 2)) * XmLSortEleSize; if (i < 0) { i = (*XmLSortCompare)(XmLSortUserData, lvec, pvec); if (i > 0) pvec = lvec; else if (i == 0) pvec = rvec; } else if (i > 0) { i = (*XmLSortCompare)(XmLSortUserData, rvec, pvec); if (i > 0) pvec = rvec; else if (i == 0) pvec = lvec; } else { pvec = lvec + XmLSortEleSize; while (1) { i = (*XmLSortCompare)(XmLSortUserData, lvec, pvec); if (i < 0) break; else if (i > 0) { pvec = lvec; break; } if (pvec == rvec) return; pvec += XmLSortEleSize; } } /* partition the set */ nlvec = lvec; nrvec = rvec; while (1) { if (pvec == nrvec) pvec = nlvec; else if (pvec == nlvec) pvec = nrvec; SWAP(nrvec, nlvec) while ((*XmLSortCompare)(XmLSortUserData, nlvec, pvec) < 0) nlvec += XmLSortEleSize; while ((*XmLSortCompare)(XmLSortUserData, nrvec, pvec) >= 0) nrvec -= XmLSortEleSize; if (nlvec > nrvec) break; } /* sort partitioned sets */ if (lvec < nlvec - XmLSortEleSize) XmLSortFunc(lvec, nlvec - XmLSortEleSize); if (nlvec < rvec) { lvec = nlvec; goto start; } } void XmLStringDraw(Widget w, XmString string, XmStringDirection stringDir, XmFontList fontList, unsigned char alignment, GC gc, XRectangle *rect, XRectangle *clipRect) { Display *dpy; Window win; Dimension width, height; int x, y, drawType; unsigned char strAlignment; if (!string) return; dpy = XtDisplay(w); win = XtWindow(w); XmStringExtent(fontList, string, &width, &height); drawType = XmLDrawCalc(w, width, height, alignment, rect, clipRect, &x, &y); if (drawType == XmLDrawNODRAW) return; x = rect->x + 2; if (alignment == XmALIGNMENT_LEFT || alignment == XmALIGNMENT_TOP_LEFT || alignment == XmALIGNMENT_BOTTOM_LEFT) strAlignment = XmALIGNMENT_BEGINNING; else if (alignment == XmALIGNMENT_CENTER || alignment == XmALIGNMENT_TOP || alignment == XmALIGNMENT_BOTTOM) if (width <= rect->width - 4) strAlignment = XmALIGNMENT_CENTER; else strAlignment = XmALIGNMENT_BEGINNING; else strAlignment = XmALIGNMENT_END; /* XmStringDraw clipping doesnt work in all cases so we use a clip region for clipping */ if (drawType == XmLDrawCLIPPED) XSetClipRectangles(dpy, gc, 0, 0, clipRect, 1, Unsorted); XmStringDraw(dpy, win, fontList, string, gc, x, y, rect->width - 4, strAlignment, stringDir, clipRect); if (drawType == XmLDrawCLIPPED) XSetClipMask(dpy, gc, None); } void XmLStringDrawDirection(Display *dpy, Window win, XmFontList fontlist, XmString string, GC gc, int x, int y, Dimension width, unsigned char alignment, unsigned char layout_direction, unsigned char drawing_direction) { Screen *screen; XFontStruct *fontStruct; XImage *sourceImage, *destImage; Pixmap pixmap; GC pixmapGC; /* int sourceWidth, sourceHeight;*/ int destWidth, destHeight; int stringWidth, stringHeight; int i, j, bytesPerLine; Dimension dW, dH; char *data; screen = DefaultScreenOfDisplay(dpy); XmStringExtent(fontlist, string, &dW, &dH); stringWidth = (int)dW; stringHeight = (int)dH; if (!stringWidth || !stringHeight) return; /* draw string into 1 bit deep pixmap */ pixmap = XCreatePixmap(dpy, win, stringWidth, stringHeight, 1); pixmapGC = XCreateGC(dpy, pixmap, 0, NULL); fontStruct = XLoadQueryFont(dpy, "fixed"); if (!fontStruct) { fprintf(stderr, "XmLStringDrawDirection: error - "); fprintf(stderr, "can't load fixed font\n"); return; } XSetFont(dpy, pixmapGC, fontStruct->fid); XSetBackground(dpy, pixmapGC, 0L); XSetForeground(dpy, pixmapGC, 0L); XFillRectangle(dpy, pixmap, pixmapGC, 0, 0, stringWidth, stringHeight); XSetForeground(dpy, pixmapGC, 1L); XmStringDraw(dpy, pixmap, fontlist, string, pixmapGC, 0, 0, stringWidth, XmALIGNMENT_BEGINNING, layout_direction, 0); XFreeFont(dpy, fontStruct); /* copy 1 bit deep pixmap into source image */ sourceImage = XGetImage(dpy, pixmap, 0, 0, stringWidth, stringHeight, 1, XYPixmap); XFreePixmap(dpy, pixmap); /* draw rotated text into destination image */ if (drawing_direction == XmSTRING_UP || drawing_direction == XmSTRING_DOWN) { destWidth = stringHeight; destHeight = stringWidth; } else { destWidth = stringWidth; destHeight = stringHeight; } bytesPerLine = (destWidth - 1) / 8 + 1; data = (char *)malloc(bytesPerLine * destHeight); destImage = XCreateImage(dpy, DefaultVisualOfScreen(screen), 1, XYBitmap, 0, data, destWidth, destHeight, 8, 0); for (i = 0; i < stringWidth; i++) for (j = 0; j < stringHeight; j++) { if (drawing_direction == XmSTRING_UP) XPutPixel(destImage, j, i, XGetPixel(sourceImage, stringWidth - i - 1, j)); else if (drawing_direction == XmSTRING_DOWN) XPutPixel(destImage, stringHeight - j - 1, stringWidth - i - 1, XGetPixel(sourceImage, stringWidth - i - 1, j)); else if (drawing_direction == XmSTRING_LEFT) XPutPixel(destImage, i, stringHeight - j - 1, XGetPixel(sourceImage, stringWidth - i - 1, j)); else XPutPixel(destImage, i, j, XGetPixel(sourceImage, i, j)); } XDestroyImage(sourceImage); /* copy rotated image into 1 bit deep pixmap */ pixmap = XCreatePixmap(dpy, win, destWidth, destHeight, 1); XPutImage(dpy, pixmap, pixmapGC, destImage, 0, 0, 0, 0, destWidth, destHeight); XDestroyImage(destImage); XFreeGC(dpy, pixmapGC); /* adjust position for alignment */ if (drawing_direction == XmSTRING_UP || drawing_direction == XmSTRING_DOWN) { if (alignment == XmALIGNMENT_BEGINNING) ; else if (alignment == XmALIGNMENT_CENTER) y += width / 2 - stringWidth / 2; else if (alignment == XmALIGNMENT_END) y += (int)width - stringWidth; } else { if (alignment == XmALIGNMENT_BEGINNING) ; else if (alignment == XmALIGNMENT_CENTER) x += width / 2 - stringWidth / 2; else if (alignment == XmALIGNMENT_END) x += (int)width - stringWidth; } /* draw the pixmap as a stipple in the window */ XSetStipple(dpy, gc, pixmap); XSetFillStyle(dpy, gc, FillStippled); XSetTSOrigin(dpy, gc, x % destWidth, y % destHeight); XFillRectangle(dpy, win, gc, x, y, destWidth, destHeight); XFreePixmap(dpy, pixmap); XSetFillStyle(dpy, gc, FillSolid); } void XmLWarning(Widget w, char *msg) { XtAppContext app; char s[512], *cname, *name; WidgetClass c; app = XtWidgetToApplicationContext(w); name = XtName(w); if (!name) name = "[No Name]"; c = XtClass(w); cname = c->core_class.class_name; if (!cname) cname = "[No Class]"; sprintf(s, "%s: %s: %s\n", cname, name, msg); XtAppWarning(app, s); } nedit-5.6.orig/Microline/XmL/XmL.h0000644000175000017500000005563710107542711015422 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #ifndef XmLH #define XmLH #include #if defined(__cplusplus) || defined(c_plusplus) #define XmL_CPP 1 #endif #if defined(_STDC_) || defined(__STDC__) || defined(XmL_CPP) #ifndef _NO_PROTO #define XmL_ANSIC 1 #endif #endif #define XmLVERSION_301 #ifdef XmL_CPP extern "C" { #endif /* shared resources */ #define XmNautoSelect "autoSelect" #define XmCAutoSelect "AutoSelect" #define XmNblankBackground "blankBackground" #define XmCBlankBackground "BlankBackground" #define XmNdebugLevel "debugLevel" #define XmCDebugLevel "DebugLevel" /* Folder resources */ #define XmNacceptResize "acceptResize" #define XmCAcceptResize "AcceptResize" #define XmNactiveTab "activeTab" #define XmCActiveTab "ActiveTab" #define XmNblankBackgroundPixmap "blankBackgroundPixmap" #define XmCBlankBackgroundPixmap "BlankBackgroundPixmap" #define XmNcornerDimension "cornerDimension" #define XmCCornerDimension "CornerDimension" #define XmNcornerStyle "cornerStyle" #define XmCCornerStyle "CornerStyle" #define XmRCornerStyle "CornerStyle" #define XmNinactiveBackground "inactiveBackground" #define XmCInactiveBackground "InactiveBackground" #define XmNinactiveForeground "inactiveForeground" #define XmCInactiveForeground "InactiveForeground" #define XmNpixmapMargin "pixmapMargin" #define XmCPixmapMargin "PixmapMargin" #define XmCFolderResizePolicy "FolderResizePolicy" #define XmRFolderResizePolicy "FolderResizePolicy" #define XmNrotateWhenLeftRight "rotateWhenLeftRight" #define XmCRotateWhenLeftRight "RotateWhenLeftRight" #define XmNtabBarHeight "tabBarHeight" #define XmCTabBarHeight "TabBarHeight" #define XmNminTabWidth "minTabWidth" #define XmCminTabWidth "MinTabWidth" #define XmNmaxTabWidth "maxTabWidth" #define XmCmaxTabWidth "MaxTabWidth" #define XmNtabCount "tabCount" #define XmCTabCount "TabCount" #define XmNtabPlacement "tabPlacement" #define XmCTabPlacement "TabPlacement" #define XmRTabPlacement "TabPlacement" #define XmNtabsPerRow "tabsPerRow" #define XmCTabsPerRow "TabsPerRow" #define XmNtabTranslations "tabTranslations" #define XmNtabWidgetList "tabWidgetList" #define XmNtabWidgetClass "tabWidgetClass" #define XmCTabWidgetClass "TabWidgetClass" /* Folder Constraint resources */ #define XmNtabFreePixmaps "tabFreePixmaps" #define XmCTabFreePixmaps "TabFreePixmaps" #define XmNtabInactivePixmap "tabInactivePixmap" #define XmCTabInactivePixmap "TabInactivePixmap" #define XmNtabManagedName "tabManagedName" #define XmCTabManagedName "TabManagedName" #define XmNtabManagedWidget "tabManagedWidget" #define XmCTabManagedWidget "TabManagedWidget" #define XmNtabPixmap "tabPixmap" #define XmCTabPixmap "TabPixmap" /* Folder callbacks */ typedef struct { int reason; XEvent *event; int pos; int allowActivate; int layoutNeeded; } XmLFolderCallbackStruct; /* Folder defines */ #define XmCORNER_NONE 0 #define XmCORNER_LINE 1 #define XmCORNER_ARC 2 #define XmFOLDER_TOP 0 #define XmFOLDER_LEFT 1 #define XmFOLDER_BOTTOM 2 #define XmFOLDER_RIGHT 3 #define XmRESIZE_STATIC 10 #define XmRESIZE_DYNAMIC 11 #define XmRESIZE_PACK 12 /* Grid resources */ #define XmNaddCallback "addCallback" #define XmNallowColumnHide "allowColumnHide" #define XmCAllowColumnHide "AllowColumnHide" #define XmNallowColumnResize "allowColumnResize" #define XmCAllowColumnResize "AllowColumnResize" #define XmNallowDragSelected "allowDragSelected" #define XmCAllowDragSelected "AllowDragSelected" #define XmNallowDrop "allowDrop" #define XmCAllowDrop "AllowDrop" #define XmNallowRowHide "allowRowHide" #define XmCAllowRowHide "AllowRowHide" #define XmNallowRowResize "allowRowResize" #define XmCAllowRowResize "AllowRowResize" #define XmNbottomFixedCount "bottomFixedCount" #define XmCBottomFixedCount "BottomFixedCount" #define XmNbottomFixedMargin "bottomFixedMargin" #define XmCBottomFixedMargin "BottomFixedMargin" #define XmNcellDefaults "cellDefaults" #define XmCCellDefaults "CellDefaults" #define XmNcellDrawCallback "cellDrawCallback" #define XmNcellDropCallback "cellDropCallback" #define XmNcellFocusCallback "cellFocusCallback" #define XmNcellPasteCallback "cellPasteCallback" #define XmNdeleteCallback "deleteCallback" #define XmNdeselectCallback "deselectCallback" #define XmNeditCallback "editCallback" #define XmNeditTranslations "editTranslations" #define XmNfooterColumns "footerColumns" #define XmCFooterColumns "FooterColumns" #define XmNfooterRows "footerRows" #define XmCFooterRows "FooterRows" #define XmNglobalPixmapHeight "globalPixmapHeight" #define XmCGlobalPixmapHeight "GlobalPixmapHeight" #define XmNglobalPixmapWidth "globalPixmapWidth" #define XmCGlobalPixmapWidth "GlobalPixmapWidth" #define XmCGridSelectionPolicy "GridSelectionPolicy" #define XmRGridSelectionPolicy "GridSelectionPolicy" #define XmRGridSizePolicy "GridSizePolicy" #define XmNheadingColumns "headingColumns" #define XmCHeadingColumns "HeadingColumns" #define XmNheadingRows "headingRows" #define XmCHeadingRows "HeadingRows" #define XmNhiddenColumns "hiddenColumns" #define XmCHiddenColumns "HiddenColumns" #define XmNhiddenRows "hiddenRows" #define XmCHiddenRows "HiddenRows" #define XmNhighlightRowMode "highlightRowMode" #define XmCHighlightRowMode "HighlightRowMode" #define XmNhorizontalSizePolicy "horizontalSizePolicy" #define XmCHorizontalSizePolicy "HorizontalSizePolicy" #define XmNhsbDisplayPolicy "hsbDisplayPolicy" #define XmCHsbDisplayPolicy "HsbDisplayPolicy" #define XmNimmediateDraw "immediateDraw" #define XmCImmediateDraw "ImmediateDraw" #define XmNlayoutFrozen "layoutFrozen" #define XmCLayoutFrozen "LayoutFrozen" #define XmNleftFixedCount "leftFixedCount" #define XmCLeftFixedCount "LeftFixedCount" #define XmNleftFixedMargin "leftFixedMargin" #define XmCLeftFixedMargin "LeftFixedMargin" #define XmNrightFixedCount "rightFixedCount" #define XmCRightFixedCount "RightFixedCount" #define XmNrightFixedMargin "rightFixedMargin" #define XmCRightFixedMargin "RightFixedMargin" #define XmNscrollBarMargin "scrollBarMargin" #define XmCScrollBarMargin "ScrollBarMargin" #define XmNscrollCallback "scrollCallback" #define XmNscrollColumn "scrollColumn" #define XmCScrollColumn "ScrollColumn" #define XmNscrollRow "scrollRow" #define XmCScrollRow "ScrollRow" #define XmNsimpleHeadings "simpleHeadings" #define XmCSimpleHeadings "SimpleHeadings" #define XmNsimpleWidths "simpleWidths" #define XmCSimpleWidths "SimpleWidths" #ifndef XmNselectCallback /* OM 2.2.3 defines this too. */ #define XmNselectCallback "selectCallback" #endif #define XmNselectForeground "selectForeground" #define XmCSelectForeground "SelectForeground" #define XmNselectBackground "selectBackground" #define XmCSelectBackground "SelectBackground" #define XmNshadowRegions "shadowRegions" #define XmCShadowRegions "ShadowRegions" #define XmNtextWidget "textWidget" #define XmCTextWidget "TextWidget" #define XmNtoggleTopColor "toggleTopColor" #define XmCToggleTopColor "ToggleTopColor" #define XmNtoggleBottomColor "toggleBottomColor" #define XmCToggleBottomColor "ToggleBottomColor" #define XmNtoggleSize "toggleSize" #define XmCToggleSize "ToggleSize" #define XmNtopFixedCount "topFixedCount" #define XmCTopFixedCount "TopFixedCount" #define XmNtopFixedMargin "topFixedMargin" #define XmCTopFixedMargin "TopFixedMargin" #define XmNtraverseTranslations "traverseTranslations" #define XmNuseAverageFontWidth "useAverageFontWidth" #define XmCUseAverageFontWidth "UseAverageFontWidth" #define XmNverticalSizePolicy "verticalSizePolicy" #define XmCVerticalSizePolicy "VerticalSizePolicy" #define XmNvisibleColumns "visibleColumns" #define XmCVisibleColumns "VisibleColumns" #define XmNvisibleRows "visibleRows" #define XmCVisibleRows "VisibleRows" #define XmNvsbDisplayPolicy "vsbDisplayPolicy" #define XmCVsbDisplayPolicy "VsbDisplayPolicy" #define XmNiconSpacing "iconSpacing" #define XmCIconSpacing "IconSpacing" /* XFE Additions */ #define XmNhideUnhideButtons "hideUnhideButtons" #define XmCHideUnhideButtons "HideUnhideButtons" #define XmNsingleClickActivation "singleClickActivation" #define XmCSingleClickActivation "SingleClickActivation" #define XmNuseTextWidget "useTextWidget" #define XmCUseTextWidget "UseTextWidget" #define XmNcolumnSortType "columnSortType" #define XmCColumnSortType "ColumnSortType" #define XmRColumnSortType "ColumnSortType" #if 0 #define XmNhideButtonTranslations "hideButtonTranslations" #define XmNunhideButtonTranslations "unhideButtonTranslations" #endif /*0*/ #define XmNminColumnWidth "minColumnWidth" #define XmCMinColumnWidth "MinColumnWidth" #define XmNenterCellCallback "enterCellCallback" #define XmNleaveCellCallback "leaveCellCallback" #define XmNenterGridCallback "enterGridCallback" #define XmNleaveGridCallback "leaveGridCallback" /* Grid Row/Column/Cell resources */ #define XmNrow "row" #define XmCGridRow "row" #define XmNrowHeight "rowHeight" #define XmCRowHeight "RowHeight" #define XmNrowPtr "rowPtr" #define XmNrowRangeEnd "rowRangeEnd" #define XmCRowRangeEnd "RowRangeEnd" #define XmNrowRangeStart "rowRangeStart" #define XmCRowRangeStart "RowRangeStart" #define XmNrowSizePolicy "rowSizePolicy" #define XmCRowSizePolicy "RowSizePolicy" #define XmNrowStep "rowStep" #define XmCRowStep "RowStep" #define XmNrowType "rowType" #define XmCRowType "RowType" #define XmRRowType "RowType" #define XmNrowUserData "rowUserData" #define XmNcolumn "column" #define XmCGridColumn "Column" #define XmNcolumnPtr "columnPtr" #define XmNcolumnRangeEnd "columnRangeEnd" #define XmCColumnRangeEnd "ColumnRangeEnd" #define XmNcolumnRangeStart "columnRangeStart" #define XmCColumnRangeStart "ColumnRangeStart" #define XmNcolumnResizable "columnResizable" #define XmCColumnResizable "ColumnResizable" #define XmNcolumnSizePolicy "columnSizePolicy" #define XmCColumnSizePolicy "ColumnSizePolicy" #define XmNcolumnHidden "columnHidden" #define XmCColumnHidden "ColumnHidden" #define XmNcolumnStep "columnStep" #define XmCColumnStep "ColumnStep" #define XmNcolumnType "columnType" #define XmCColumnType "ColumnType" #define XmRColumnType "ColumnType" #define XmNcolumnWidth "columnWidth" #define XmCColumnWidth "ColumnWidth" #define XmNcolumnUserData "columnUserData" #define XmNcellAlignment "cellAlignment" #define XmCCellAlignment "CellAlignment" #define XmRCellAlignment "CellAlignment" #define XmNcellBackground "cellBackground" #define XmCCellBackground "CellBackground" #define XmRCellBorderType "CellBorderType" #define XmNcellBottomBorderType "cellBottomBorderType" #define XmCCellBottomBorderType "CellBottomBorderType" #define XmNcellBottomBorderColor "cellBottomBorderColor" #define XmCCellBottomBorderColor "CellBottomBorderColor" #define XmNcellColumnSpan "cellColumnSpan" #define XmCCellColumnSpan "CellColumnSpan" #define XmNcellEditable "cellEditable" #define XmCCellEditable "CellEditable" #define XmNcellForeground "cellForeground" #define XmCCellForeground "CellForeground" #define XmNcellFontList "cellFontList" #define XmCCellFontList "CellFontList" #define XmNcellLeftBorderType "cellLeftBorderType" #define XmCCellLeftBorderType "CellLeftBorderType" #define XmNcellLeftBorderColor "cellLeftBorderColor" #define XmCCellLeftBorderColor "CellLeftBorderColor" #define XmNcellMarginBottom "cellMarginBottom" #define XmCCellMarginBottom "CellMarginBottom" #define XmNcellMarginLeft "cellMarginLeft" #define XmCCellMarginLeft "CellMarginLeft" #define XmNcellMarginRight "cellMarginRight" #define XmCCellMarginRight "CellMarginRight" #define XmNcellMarginTop "cellMarginTop" #define XmCCellMarginTop "CellMarginTop" #define XmNcellPixmap "cellPixmap" #define XmCCellPixmap "CellPixmap" #define XmNcellPixmapMask "cellPixmapMask" #define XmCCellPixmapMask "CellPixmapMask" #define XmNcellRightBorderType "cellRightBorderType" #define XmCCellRightBorderType "CellRightBorderType" #define XmNcellRightBorderColor "cellRightBorderColor" #define XmCCellRightBorderColor "CellRightBorderColor" #define XmNcellRowSpan "cellRowSpan" #define XmCCellRowSpan "CellRowSpan" #define XmNcellString "cellString" #define XmNcellToggleSet "cellToggleSet" #define XmCCellToggleSet "CellToggleSet" #define XmNcellTopBorderType "cellTopBorderType" #define XmCCellTopBorderType "CellTopBorderType" #define XmNcellTopBorderColor "cellTopBorderColor" #define XmCCellTopBorderColor "CellTopBorderColor" #define XmNcellType "cellType" #define XmCCellType "CellType" #define XmRCellType "CellType" #define XmNcellUserData "cellUserData" /* Grid callbacks */ typedef struct _XmLGridDrawStruct { GC gc; XRectangle *cellRect; Dimension topMargin; Dimension bottomMargin; Dimension leftMargin; Dimension rightMargin; Pixel foreground; Pixel background; Pixel selectForeground; Pixel selectBackground; XmFontList fontList; unsigned char alignment; Boolean drawSelected; int drawFocusType; XmStringDirection stringDirection; } XmLGridDrawStruct; typedef struct _XmLGridCallbackStruct { int reason; XEvent *event; unsigned char rowType, columnType; int row, column; XRectangle *clipRect; XmLGridDrawStruct *drawInfo; void *object; } XmLGridCallbackStruct; #define XmCR_ADD_ROW 900 #define XmCR_ADD_COLUMN 901 #define XmCR_ADD_CELL 902 #define XmCR_CELL_DRAW 903 #define XmCR_CELL_DROP 904 #define XmCR_CELL_FOCUS_IN 905 #define XmCR_CELL_FOCUS_OUT 906 #define XmCR_CELL_PASTE 907 #define XmCR_CONF_TEXT 908 #define XmCR_PREF_WIDTH 909 #define XmCR_DELETE_ROW 910 #define XmCR_DELETE_COLUMN 911 #define XmCR_DELETE_CELL 912 #define XmCR_EDIT_BEGIN 913 #define XmCR_EDIT_INSERT 914 #define XmCR_EDIT_CANCEL 915 #define XmCR_EDIT_COMPLETE 916 #define XmCR_FREE_VALUE 917 #define XmCR_RESIZE_ROW 918 #define XmCR_RESIZE_COLUMN 919 #define XmCR_PREF_HEIGHT 920 #define XmCR_SCROLL_ROW 921 #define XmCR_SCROLL_COLUMN 922 #define XmCR_SELECT_CELL 923 #define XmCR_SELECT_COLUMN 924 #define XmCR_SELECT_ROW 925 #define XmCR_DESELECT_CELL 926 #define XmCR_DESELECT_COLUMN 927 #define XmCR_DESELECT_ROW 928 /* xfe added callback reason */ #define XmCR_RESIZE_GRID 929 #define XmCR_SHOW_POPUP 930 #define XmCR_SINGLECLICK 931 #define XmCR_ENTER_CELL 931 #define XmCR_ENTER_GRID 932 #define XmCR_LEAVE_CELL 933 #define XmCR_LEAVE_GRID 934 /* Grid defines */ #define XmCONTENT 0 #define XmHEADING 1 #define XmFOOTER 2 #define XmALL_TYPES 3 #define XmINVALID_TYPE 4 #define XmICON_CELL 0 #define XmPIXMAP_CELL 1 #define XmSTRING_CELL 2 #define XmBORDER_NONE 0 #define XmBORDER_LINE 1 #define XmBORDER_DASH 2 #define XmFORMAT_DELIMITED 1 #define XmFORMAT_XL 2 #define XmFORMAT_PAD 3 #define XmFORMAT_PASTE 4 #define XmFORMAT_DROP 5 #define XmSELECT_NONE 1 #define XmSELECT_SINGLE_ROW 2 #define XmSELECT_BROWSE_ROW 3 #define XmSELECT_MULTIPLE_ROW 4 #define XmSELECT_CELL 5 #define XmDRAW_FOCUS_NONE 1 #define XmDRAW_FOCUS_CELL 2 #define XmDRAW_FOCUS_LEFT 3 #define XmDRAW_FOCUS_MID 4 #define XmDRAW_FOCUS_RIGHT 5 #define XmTRAVERSE_EXTEND_DOWN 20 #define XmTRAVERSE_EXTEND_LEFT 21 #define XmTRAVERSE_EXTEND_RIGHT 22 #define XmTRAVERSE_EXTEND_UP 23 #define XmTRAVERSE_PAGE_DOWN 24 #define XmTRAVERSE_PAGE_LEFT 25 #define XmTRAVERSE_PAGE_RIGHT 26 #define XmTRAVERSE_PAGE_UP 27 #define XmTRAVERSE_TO_BOTTOM 28 #define XmTRAVERSE_TO_TOP 29 #define XmALIGNMENT_LEFT 0 #ifndef XmALIGNMENT_CENTER #define XmALIGNMENT_CENTER 1 #endif #define XmALIGNMENT_RIGHT 2 #define XmALIGNMENT_TOP_LEFT 3 #define XmALIGNMENT_TOP 4 #define XmALIGNMENT_TOP_RIGHT 5 #define XmALIGNMENT_BOTTOM_LEFT 6 #define XmALIGNMENT_BOTTOM 7 #define XmALIGNMENT_BOTTOM_RIGHT 8 /* xfe additions */ #define XmSORT_NONE 0 #define XmSORT_ASCENDING 1 #define XmSORT_DESCENDING 2 /* Progress resources */ #define XmNcompleteValue "completeValue" #define XmCCompleteValue "CompleteValue" #define XmNnumBoxes "numBoxes" #define XmCNumBoxes "NumBoxes" #define XmNmeterStyle "meterStyle" #define XmCMeterStyle "MeterStyle" #define XmRMeterStyle "MeterStyle" #define XmNshowPercentage "showPercentage" #define XmCShowPercentage "ShowPercentage" #define XmNshowTime "showTime" #define XmCShowTime "ShowTime" /* Progress defines */ #define XmMETER_BAR 0 #define XmMETER_BOXES 1 /* Tree resources */ #define XmNcollapseCallback "collapseCallback" #define XmNconnectingLineColor "connectingLineColor" #define XmCConnectingLineColor "ConnectingLineColor" #define XmNexpandCallback "expandCallback" #define XmNlevelSpacing "levelSpacing" #define XmCLevelSpacing "LevelSpacing" #define XmNplusMinusColor "plusMinusColor" #define XmCPlusMinusColor "PlusMinusColor" #define XmNrowExpands "rowExpands" #define XmCRowExpands "RowExpands" #define XmNrowIsExpanded "rowIsExpanded" #define XmCRowIsExpanded "RowIsExpanded" #define XmNrowLevel "rowLevel" #define XmCRowLevel "RowLevel" #define XmNignorePixmaps "ignorePixmaps" #define XmCIgnorePixmaps "IgnorePixmaps" /* Tree callbacks */ typedef struct { int level; Boolean expands; Boolean isExpanded; Pixmap pixmap, pixmask; XmString string; } XmLTreeRowDefinition; #define XmCR_COLLAPSE_ROW 950 #define XmCR_EXPAND_ROW 951 /* Backwards compatibility */ #ifdef XmLBACKWARDS_COMPATIBILITY #define XmNfooterColumnCount "footerColumns" #define XmNfooterRowCount "footerRows" #define XmNheadingColumnCount "headingColumns" #define XmNheadingRowCount "headingRows" #define XmNcellBottomBorderPixel "cellBottomBorderColor" #define XmCCellBottomBorderPixel "CellBottomBorderColor" #define XmNcellLeftBorderPixel "cellLeftBorderColor" #define XmCCellLeftBorderPixel "CellLeftBorderColor" #define XmNcellRightBorderPixel "cellRightBorderColor" #define XmCCellRightBorderPixel "CellRightBorderColor" #define XmNcellTopBorderPixel "cellTopBorderColor" #define XmCCellTopBorderPixel "CellTopBorderColor" #define XmTEXT_CELL 250 #define XmLABEL_CELL 251 typedef void XmLCGridRow; typedef void XmLCGridColumn; typedef void XmLCGridCell; #endif /* Utility defines */ #define XmDRAWNB_ARROW 0 #define XmDRAWNB_ARROWLINE 1 #define XmDRAWNB_DOUBLEARROW 2 #define XmDRAWNB_SQUARE 3 #define XmDRAWNB_DOUBLEBAR 4 #define XmDRAWNB_STRING 5 #define XmDRAWNB_SMALLARROW 6 #define XmDRAWNB_RIGHT 0 #define XmDRAWNB_LEFT 1 #define XmDRAWNB_UP 2 #define XmDRAWNB_DOWN 3 #define XmSTRING_RIGHT 0 #define XmSTRING_LEFT 1 #define XmSTRING_UP 2 #define XmSTRING_DOWN 3 enum { XmLRectInside, XmLRectOutside, XmLRectPartial }; typedef struct { int pos; } XmLArrayItem; typedef struct _XmLArrayRec *XmLArray; typedef struct { char *name; unsigned char value; } XmLStringToUCharMap; /* Utility functions */ typedef int (*XmLSortCompareFunc)(void *userData, void *l, void *r); typedef int (*XmLArrayCompareFunc)(void *, void **, void **); XmLArray XmLArrayNew(char autonumber, char growFast); void XmLArrayFree(XmLArray array); void XmLArrayAdd(XmLArray array, int pos, int count); int XmLArrayDel(XmLArray array, int pos, int count); int XmLArraySet(XmLArray array, int pos, void *item); void *XmLArrayGet(XmLArray array, int pos); int XmLArrayGetCount(XmLArray array); int XmLArrayMove(XmLArray array, int newPos, int pos, int count); int XmLArrayReorder(XmLArray array, int *newPositions, int pos, int count); int XmLArraySort(XmLArray array, XmLArrayCompareFunc compare, void *userData, int pos, int count); Boolean XmLCvtStringToUChar(Display *dpy, char *resname, XmLStringToUCharMap *map, XrmValuePtr fromVal, XrmValuePtr toVal); int XmLDateDaysInMonth(int m, int y); int XmLDateWeekDay(int m, int d, int y); void XmLDrawnButtonSetType(Widget w, int drawnType, int drawnDir); void XmLDrawToggle(Widget w, Boolean state, Dimension size, unsigned char alignment, GC gc, Pixel backgroundColor, Pixel topColor, Pixel bottomColor, Pixel checkColor, XRectangle *rect, XRectangle *clipRect); XmFontList XmLFontListCopyDefault(Widget widget); void XmLFontListGetDimensions(XmFontList fontList, short *width, short *height, Boolean useAverageWidth); void XmLInitialize(void); int XmLMessageBox(Widget w, char *string, Boolean okOnly); void XmLPixmapDraw(Widget w, Pixmap pixmap, Pixmap pixmask, int pixmapWidth, int pixmapHeight, unsigned char alignment, GC gc, XRectangle *rect, XRectangle *clipRect); int XmLRectIntersect(XRectangle *r1, XRectangle *r2); Widget XmLShellOfWidget(Widget w); void XmLSort(void *base, int numItems, unsigned int itemSize, XmLSortCompareFunc, void *userData); void XmLStringDraw(Widget w, XmString string, XmStringDirection stringDir, XmFontList fontList, unsigned char alignment, GC gc, XRectangle *rect, XRectangle *clipRect); void XmLStringDrawDirection(Display *dpy, Window win, XmFontList fontlist, XmString string, GC gc, int x, int y, Dimension width, unsigned char alignment, unsigned char layout_direction, unsigned char drawing_direction); void XmLWarning(Widget w, char *msg); #ifdef XmL_CPP } #endif #endif nedit-5.6.orig/Microline/XmL/XmL.uih0000644000175000017500000001715410077552126015757 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ ! Common Resources value XmNblankBackground : argument ('blankBackground', color); XmNautoSelect : argument ('autoSelect', boolean); XmNdebugLevel : argument ('debugLevel', integer); ! Folder Widget procedure XmLCreateFolder(); ! Folder Resources value XmNcornerDimension : argument ('cornerDimension', integer); XmNcornerStyle : argument ('cornerStyle', integer); CornerNone : 0; CornerLine : 1; CornerArc : 2; XmNinactiveBackground : argument ('inactiveBackground', color); XmNinactiveForeground : argument ('inactiveForeground', color); XmNpixmapMargin : argument ('pixmapMargin', integer); ResizeStatic : 10; ResizeDynamic : 11; XmNrotateWhenLeftRight : argument ('rotateWhenRightLeft', boolean); XmNtabPlacement : argument ('tabPlacement', integer); FolderTop : 0; FolderLeft : 1; FolderBottom : 2; FolderRight : 3; XmNtabsPerRow : argument ('tabsPerRow', integer); ! Folder Constraint resources XmNtabFreePixmaps : argument ('tabFreePixmaps', boolean); XmNtabManagedName : argument ('tabManagedName', string); XmNtabManagedWidget : argument ('tabManagedWidget', any); ! Grid Widget procedure XmLCreateGrid(); ! Grid Resources value XmNallowColumnHide : argument ('allowColumnHide', boolean); XmNallowColumnResize : argument ('allowColumnResize', boolean); XmNallowDragSelected : argument ('allowDragSelected', boolean); XmNallowDrop : argument ('allowDrop', boolean); XmNallowRowHide : argument ('allowRowHide', boolean); XmNallowRowResize : argument ('allowRowResize', boolean); XmNbottomFixedCount : argument ('bottomFixedCount', integer); XmNbottomFixedMargin : argument ('bottomFixedMargin', integer); XmNfooterColumns : argument ('footerColumns', integer); XmNfooterRows : argument ('footerRows', integer); XmNglobalPixmapHeight : argument ('globalPixmapHeight', integer); XmNglobalPixmapWidth : argument ('globalPixmapWidth', integer); XmNheadingColumns : argument ('headingColumns', integer); XmNheadingRows : argument ('headingRows', integer); XmNhighlightRowMode : argument ('highlightRowMode', boolean); XmNhorizontalSizePolicy : argument ('horizontalSizePolicy', integer); XmNhsbDisplayPolicy : argument ('hsbDisplayPolicy', integer); XmNimmediateDraw : argument ('immediateDraw', boolean); XmNleftFixedCount : argument ('leftFixedCount', integer); XmNleftFixedMargin : argument ('leftFixedMargin', integer); XmNrightFixedCount : argument ('rightFixedCount', integer); XmNrightFixedMargin : argument ('rightFixedMargin', integer); XmNscrollBarMargin : argument ('scrollBarMargin', integer); SelectNone : 1; SelectSingleRow : 2; SelectBrowseRow : 3; SelectMultipleRow : 4; SelectCell : 5; XmNselectBackground : argument ('selectBackground', color); XmNselectForeground : argument ('selectForeground', color); XmNshadowRegions : argument ('shadowRegions', integer); XmNsimpleHeadings : argument ('simpleHeadings', string); XmNsimpleWidths : argument ('simpleWidths', string); XmNtopFixedCount : argument ('topFixedCount', integer); XmNtopFixedMargin : argument ('topFixedMargin', integer); XmNuseAverageFontWidth : argument ('useAverageFontWidth', boolean); XmNverticalSizePolicy : argument ('verticalSizePolicy', integer); XmNvisibleColumns : argument ('visibleColumns', integer); XmNvisibleRows : argument ('visibleRows', integer); XmNvsbDisplayPolicy : argument ('vsbDisplayPolicy', integer); ! Grid Callbacks value XmNaddCallback : reason ('addCallback'); XmNcellDrawCallback : reason ('cellDrawCallback'); XmNcellDropCallback : reason ('cellDropCallback'); XmNcellFocusCallback : reason ('cellFocusCallback'); XmNcellPasteCallback : reason ('cellPasteCallback'); XmNdeleteCallback : reason ('deleteCallback'); XmNdeselectCallback : reason ('deselectCallback'); XmNeditCallback : reason ('editCallback'); XmNscrollCallback : reason ('scrollCallback'); XmNselectCallback : reason ('selectCallback'); ! Progress Widget procedure XmLCreateProgress(); ! Progress Resources value XmNcompleteValue : argument ('completeValue', integer); XmNmeterStyle : argument ('meterStyle', integer); MeterBar : 0; MeterBoxes : 1; XmNnumBoxes : argument ('numBoxes', integer); XmNshowTime : argument ('showTime', boolean); XmNshowPercentage : argument ('showPercentage', boolean); ! Tree Widget procedure XmLCreateTree(); ! Tree Resources value XmNconnectingLineColor : argument ('connectingLineColor', color); XmNlevelSpacing : argument ('levelSpacing', integer); XmNplusMinusColor : argument ('plusMinusColor', color); ! Tree Callbacks value XmNexpandCallback : reason ('expandCallback'); XmNcollapseCallback : reason ('collapseCallback'); nedit-5.6.orig/Microline/man/0000755000175000017500000000000011107644406014611 5ustar paulpaulnedit-5.6.orig/Microline/man/XmLArrayAdd.3x0000644000175000017500000000615110077552126017202 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLArrayAdd 3X "R1" "XML1" "XML" .SH NAME XmLArrayAdd \- add space to an array .SH SYNTAX void XmLArrayAdd(\fIarray\fP, \fIpos\fP, \fIcount\fP) .br XmLArray \fIarray\fP; .br int \fIpos\fP; .br int \fIcount\fP; .LP .SH ARGUMENTS .IP \fIarray\fP 1i array to add to .IP \fIpos\fP 1i position to add at .IP \fIcount\fP 1i size of space to add .SH DESCRIPTION Adds (\fIcount\fP * sizeof(void *)) bytes of space at position \fIpos\fP to the \fIarray\fP given. Use XmLArraySet() to set the values in the array after adding space. .SH "SEE ALSO" XmLArrayDel(3X) XmLArrayFree(3X) XmLArrayGet(3X) XmLArrayGetCount(3X) XmLArrayMove(3X) XmLArrayNew(3X) XmLArrayReorder(3X) XmLArraySet(3X) XmLArraySort(3X) nedit-5.6.orig/Microline/man/XmLArrayDel.3x0000644000175000017500000000634310077552126017221 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLArrayDel 3X "R1" "XML1" "XML" .SH NAME XmLArrayDel \- remove space from an array .SH SYNTAX int XmLArrayDel(\fIarray\fP, \fIpos\fP, \fIcount\fP) .br XmLArray \fIarray\fP; .br int \fIpos\fP; .br int \fIcount\fP; .LP .SH ARGUMENTS .IP \fIarray\fP 1i array to remove from .IP \fIpos\fP 1i position to start removal .IP \fIcount\fP 1i size of space to remove .SH DESCRIPTION Removes (\fIcount\fP * sizeof(void *)) bytes of space at position \fIpos\fP from the \fIarray\fP given. This call only removes space from the array, it does not free individual elements. .SH RETURN VALUE 0 upon success and -1 upon failure (a value passed is out of range). .SH "SEE ALSO" XmLArrayAdd(3X) XmLArrayFree(3X) XmLArrayGet(3X) XmLArrayGetCount(3X) XmLArrayMove(3X) XmLArrayNew(3X) XmLArrayReorder(3X) XmLArraySet(3X) XmLArraySort(3X) nedit-5.6.orig/Microline/man/XmLArrayFree.3x0000644000175000017500000000565610077552126017404 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLArrayFree 3X "R1" "XML1" "XML" .SH NAME XmLArrayFree \- free an array .SH SYNTAX void XmLArrayFree(\fIarray\fP) .br XmLArray \fIarray\fP; .LP .SH ARGUMENTS .IP \fIarray\fP 1i array to free .SH DESCRIPTION Frees the \fIarray\fP given and any space allocated by the array. This function does not free the individual elements of the array. .SH "SEE ALSO" XmLArrayAdd(3X) XmLArrayDel(3X) XmLArrayGet(3X) XmLArrayGetCount(3X) XmLArrayMove(3X) XmLArrayNew(3X) XmLArrayReorder(3X) XmLArraySet(3X) XmLArraySort(3X) nedit-5.6.orig/Microline/man/XmLArrayGet.3x0000644000175000017500000000606710077552126017237 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLArrayGet 3X "R1" "XML1" "XML" .SH NAME XmLArrayGet \- retrieve a pointer from an array .SH SYNTAX void *XmLArrayGet(\fIarray\fP, \fIpos\fP) .br XmLArray \fIarray\fP; .br int \fIpos\fP; .LP .SH ARGUMENTS .IP \fIarray\fP 1i array to retrieve from .IP \fIpos\fP 1i position of the pointer to retrieve .SH DESCRIPTION Returns the pointer at the position \fIpos\fP in the \fIarray\fP given. .SH RETURN VALUE The pointer at the given position or NULL if the position is invalid. .SH "SEE ALSO" XmLArrayAdd(3X) XmLArrayDel(3X) XmLArrayFree(3X) XmLArrayGetCount(3X) XmLArrayMove(3X) XmLArrayNew(3X) XmLArrayReorder(3X) XmLArraySet(3X) XmLArraySort(3X) nedit-5.6.orig/Microline/man/XmLArrayGetCount.3x0000644000175000017500000000566010077552126020246 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLArrayGetCount 3X "R1" "XML1" "XML" .SH NAME XmLArrayGetCount \- return size of an array .SH SYNTAX int XmLArrayGetCount(\fIarray\fP) .br XmLArray \fIarray\fP; .LP .SH ARGUMENTS .IP \fIarray\fP 1i array to query .SH DESCRIPTION Returns the size of \fIarray\fP in units of number of pointers it can hold. .SH RETURN VALUE The size of the array. .SH "SEE ALSO" XmLArrayAdd(3X) XmLArrayDel(3X) XmLArrayFree(3X) XmLArrayGet(3X) XmLArrayMove(3X) XmLArrayNew(3X) XmLArrayReorder(3X) XmLArraySet(3X) XmLArraySort(3X) nedit-5.6.orig/Microline/man/XmLArrayMove.3x0000644000175000017500000000661110077552126017421 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLArrayMove 3X "R1" "XML1" "XML" .SH NAME XmLArrayMove \- move items in an array .SH SYNTAX int XmLArrayMove(\fIarray\fP, \fInewPos\fP, \fIpos\fP, \fIcount\fP) .br XmLArray \fIarray\fP; .br int \fInewPos\fP; .br int \fIpos\fP; .br int \fIcount\fP; .LP .SH ARGUMENTS .IP \fIarray\fP 1i array to operate on .IP \fInewPos\fP 1i position to move to .IP \fIpos\fP 1i position to move from .IP \fIcount\fP 1i number of items to move .SH DESCRIPTION Moves \fIcount\fP pointers starting at position \fIpos\fP in the \fIarray\fP to the new position \fInewPos\fP. The existing pointers at the new location are moved down to accommodate the move. No pointers are overwritten by this call and the size of the array will remain unchanged. .SH RETURN VALUE 0 upon success and -1 upon failure (a value passed is out of range). .SH "SEE ALSO" XmLArrayAdd(3X) XmLArrayDel(3X) XmLArrayFree(3X) XmLArrayGet(3X) XmLArrayGetCount(3X) XmLArrayNew(3X) XmLArrayReorder(3X) XmLArraySet(3X) XmLArraySort(3X) nedit-5.6.orig/Microline/man/XmLArrayNew.3x0000644000175000017500000000735410077552126017251 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLArrayNew 3X "R1" "XML1" "XML" .SH NAME XmLArrayNew \- creates an array object .SH SYNTAX XmLArray XmLArrayNew(\fIautonumber\fP, \fIgrowFast\fP) .br char \fIautonumber\fP; .br char \fIgrowFast\fP; .LP .SH ARGUMENTS .IP \fIautonumber\fP 1i If set to 1, the pointers in the array are assumed to be pointers to structures containing an integer as the first element which will be set to the position of the item in the array. The array will set this value with the current position of the element whenever position of the item changes. If set to 0, the array will never dereference the pointers contained in the array. .IP \fIgrowFast\fP 1i If set to 1, the array will grow quickly as items are added to it. This will cause the amount of memory the array takes up to usually be greater than the current space for elements. If set to 0, the array will always be the size of the current space for the elements contained in the array. .SH DESCRIPTION Creates an array object and returns it. An array object is used to hold an array of pointers. This object should be freed with XmLArrayFree() when it is no longer used. .SH RETURN VALUE The newly allocate array object. .SH "SEE ALSO" XmLArrayAdd(3X) XmLArrayDel(3X) XmLArrayFree(3X) XmLArrayGet(3X) XmLArrayGetCount(3X) XmLArrayMove(3X) XmLArrayReorder(3X) XmLArraySet(3X) XmLArraySort(3X) nedit-5.6.orig/Microline/man/XmLArrayReorder.3x0000644000175000017500000000670510077552126020121 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLArrayReorder 3X "R1" "XML1" "XML" .SH NAME XmLArrayReorder \- reorder items in an array .SH SYNTAX int XmLArrayReorder(\fIarray\fP, \fInewPositions\fP, \fIpos\fP, \fIcount\fP) .br XmLArray \fIarray\fP; .br int \fInewPositions\fP; .br int \fIpos\fP; .br int \fIcount\fP; .LP .SH ARGUMENTS .IP \fIarray\fP 1i array to operate on .IP \fInewPositions\fP 1i new positions of items .IP \fIpos\fP 1i start position of items to reorder .IP \fIcount\fP 1i number of items to reorder .SH DESCRIPTION Reorders the \fIarray\fP by ordering \fIcount\fP pointers at position \fIpos\fP to the positions specified in the \fInewPositions\fP array. The newPositions array should contain numbers starting at pos and ending at pos + count - 1. This function does not free the newPositions array passed in. .SH RETURN VALUE 0 upon success and -1 upon failure (a value passed is out of range). .SH "SEE ALSO" XmLArrayAdd(3X) XmLArrayDel(3X) XmLArrayFree(3X) XmLArrayGet(3X) XmLArrayGetCount(3X) XmLArrayNew(3X) XmLArrayReorder(3X) XmLArraySet(3X) XmLArraySort(3X) nedit-5.6.orig/Microline/man/XmLArraySet.3x0000644000175000017500000000620210077552126017242 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLArraySet 3X "R1" "XML1" "XML" .SH NAME XmLArraySet \- set a pointer element in an array .SH SYNTAX int XmLArraySet(\fIarray\fP, \fIpos\fP, \fIitem\fP) .br XmLArray \fIarray\fP; .br int \fIpos\fP; .br void *\fIitem\fP; .LP .SH ARGUMENTS .IP \fIarray\fP 1i array to set in .IP \fIpos\fP 1i position of the pointer to set .IP \fIitem\fP 1i value of the item to set .SH DESCRIPTION Sets the pointer at the position \fIpos\fP in the \fIarray\fP given to \fIitem\fP. .SH RETURN VALUE 0 upon success and -1 upon failure (a value passed is out of range). .SH "SEE ALSO" XmLArrayAdd(3X) XmLArrayDel(3X) XmLArrayFree(3X) XmLArrayGetCount(3X) XmLArrayMove(3X) XmLArrayNew(3X) XmLArrayReorder(3X) XmLArraySet(3X) XmLArraySort(3X) nedit-5.6.orig/Microline/man/XmLArraySort.3x0000644000175000017500000000675010077552126017446 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLArraySort 3X "R1" "XML1" "XML" .SH NAME XmLArraySort \- sort an array .SH SYNTAX int XmLArraySort(\fIarray\fP, \fIcompare\fP, \fIuserData\fP, \ \fIpos\fP, \fIcount\fP) .br XmLArray \fIarray\fP; .br XmLArrayCompareFunc \fIcompare\fP; .br void *\fIuserData\fP; .br int \fIpos\fP; .br int \fIcount\fP; .LP .SH ARGUMENTS .IP \fIarray\fP 1i the array to sort .IP \fIcompare\fP 1i the comparison function for pointers in the array .IP \fIuserData\fP 1i an application defined pointer to pass to the sort function .IP \fIpos\fP 1i start position in array to sort .IP \fIcount\fP 1i number of items in array to sort .SH DESCRIPTION Sorts \fIcount\fP number of elements starting at position \fIpos\fP in \fIarray\fP using the \fIcompare\fP function given. The \fIuserData\fP argument is passed as data to the comparison function. .SH RETURN VALUE 0 upon success and -1 upon failure (a value passed is out of range). .SH "SEE ALSO" XmLArrayAdd(3X) XmLArrayDel(3X) XmLArrayFree(3X) XmLArrayGet(3X) XmLArrayGetCount(3X) XmLArrayMove(3X) XmLArrayNew(3X) XmLArrayReorder(3X) XmLArraySet(3X) nedit-5.6.orig/Microline/man/XmLCreateFolder.3x0000644000175000017500000000614010077552126020050 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLCreateFolder 3X "R1" "XML1" "XML" .SH NAME XmLCreateFolder \- create an instance of a Folder widget .SH SYNTAX Widget XmLCreateFolder(\fIparent\fP, \fIname\fP, \fIarglist\fP, \fIargcount\fP) .br Widget \fIparent\fP; .br char *\fIname\fP; .br ArgList \fIarglist\fP; .br Cardinal \fIargcount\fP; .LP .SH ARGUMENTS .IP \fIparent\fP 1i new widgets parent widget ID .IP \fIname\fP 1i name of the newly created widget .IP \fIarglist\fP 1i resource name/value pairs .IP \fIargcount\fP 1i count of pairs in arglist .SH DESCRIPTION Creates an instance of a Folder widget and returns its widget ID. .SH RETURN VALUE The widget ID of the newly created Folder widget. .SH "SEE ALSO" XmLFolder(3X) nedit-5.6.orig/Microline/man/XmLCreateGrid.3x0000644000175000017500000000612210077552126017522 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLCreateGrid 3X "R1" "XML1" "XML" .SH NAME XmLCreateGrid \- create an instance of a Grid widget .SH SYNTAX Widget XmLCreateGrid(\fIparent\fP, \fIname\fP, \fIarglist\fP, \fIargcount\fP) .br Widget \fIparent\fP; .br char *\fIname\fP; .br ArgList \fIarglist\fP; .br Cardinal \fIargcount\fP; .LP .SH ARGUMENTS .IP \fIparent\fP 1i new widgets parent widget ID .IP \fIname\fP 1i name of the newly created widget .IP \fIarglist\fP 1i resource name/value pairs .IP \fIargcount\fP 1i count of pairs in arglist .SH DESCRIPTION Creates an instance of a Grid widget and returns its widget ID. .SH RETURN VALUE The widget ID of the newly created Grid widget. .SH "SEE ALSO" XmLGrid(3X) nedit-5.6.orig/Microline/man/XmLCreateProgress.3x0000644000175000017500000000615610077552126020450 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLCreateProgress 3X "R1" "XML1" "XML" .SH NAME XmLCreateProgress \- create an instance of a Progress widget .SH SYNTAX Widget XmLCreateProgress(\fIparent\fP, \fIname\fP, \fIarglist\fP, \fIargcount\fP) .br Widget \fIparent\fP; .br char *\fIname\fP; .br ArgList \fIarglist\fP; .br Cardinal \fIargcount\fP; .LP .SH ARGUMENTS .IP \fIparent\fP 1i new widgets parent widget ID .IP \fIname\fP 1i name of the newly created widget .IP \fIarglist\fP 1i resource name/value pairs .IP \fIargcount\fP 1i count of pairs in arglist .SH DESCRIPTION Creates an instance of a Progress widget and returns its widget ID. .SH RETURN VALUE The widget ID of the newly created Progress widget. .SH "SEE ALSO" XmLProgress(3X) nedit-5.6.orig/Microline/man/XmLCreateTree.3x0000644000175000017500000000612210077552126017534 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLCreateTree 3X "R1" "XML1" "XML" .SH NAME XmLCreateTree \- create an instance of a Tree widget .SH SYNTAX Widget XmLCreateTree(\fIparent\fP, \fIname\fP, \fIarglist\fP, \fIargcount\fP) .br Widget \fIparent\fP; .br char *\fIname\fP; .br ArgList \fIarglist\fP; .br Cardinal \fIargcount\fP; .LP .SH ARGUMENTS .IP \fIparent\fP 1i new widgets parent widget ID .IP \fIname\fP 1i name of the newly created widget .IP \fIarglist\fP 1i resource name/value pairs .IP \fIargcount\fP 1i count of pairs in arglist .SH DESCRIPTION Creates an instance of a Tree widget and returns its widget ID. .SH RETURN VALUE The widget ID of the newly created Tree widget. .SH "SEE ALSO" XmLTree(3X) nedit-5.6.orig/Microline/man/XmLCvtStringToUChar.3x0000644000175000017500000000713110077552126020663 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLCvtStringToUChar 3X "R1" "XML1" "XML" .SH NAME XmLCvtStringToUChar \- unsigned char resource converter .SH SYNTAX Boolean XmLCvtStringToUChar(\fIdpy\fP, \fIresname\fP, \fImap\fP, \ \fIfromVal\fP, \fItoVal\fP) .br Display *\fIdpy\fP; .br char *\fIresname\fP; .br XmLStringToUCharMap *\fImap\fP; .br XrmValuePtr \fIfromVal\fP; .br XrmValuePtr \fItoVal\fP; .LP .SH ARGUMENTS .IP \fIdpy\fP 1i the display .IP \fIresname\fP 1i the resource name .IP \fImap\fP 1i the mappings of string to unsigned char .IP \fIfromVal\fP 1i the resource value from .IP \fItoVal\fP 1i the resource value to .SH DESCRIPTION This function can be used in a widget to perform resource conversion from a string to an unsigned char. This function should be called inside a widgets resource converter where parameters \fIdpy\fP, \fIfromVal\fP and \fItoVal\fP are available to be passed in. The \fIresname\fP parameter identifies the resource and the \fImap\fP array is an array of mappings from strings to unsigned chars. A NULL string should be used in the last array element to terminate the array. .SH RETURN VALUE True if conversion was successful and toVal is filled in and False if conversion was unsuccessful. nedit-5.6.orig/Microline/man/XmLDateDaysInMonth.3x0000644000175000017500000000567210077552126020515 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLDateDaysInMonth 3X "R1" "XML1" "XML" .SH NAME XmLDateDaysInMonth \- calculates number of days in month .SH SYNTAX int XmLDateDaysInMonth(\fIm\fP, \fIy\fP) .br int \fIm\fP; .br int \fIy\fP; .LP .SH ARGUMENTS .IP \fIm\fP 1i month 1 to 12 .IP \fIy\fP 1i year 1753 to 9999 .SH DESCRIPTION Calculates the number of days in a given month \fIm\fP and year \fIy\fP. .SH RETURN VALUE The number of days in the given month and year. A value of -1 is returned if a passed value is out of range. .SH "SEE ALSO" XmLDateWeekDay(3X) nedit-5.6.orig/Microline/man/XmLDateWeekDay.3x0000644000175000017500000000603010077552126017636 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLDateWeekDay 3X "R1" "XML1" "XML" .SH NAME XmLDateWeekDay \- calculates the weekday for a given date .SH SYNTAX int XmLDateWeekDay(\fIm\fP, \fId\fP, \fIy\fP) .br int \fIm\fP; .br int \fId\fP; .br int \fIy\fP; .LP .SH ARGUMENTS .IP \fIm\fP 1i month 1 to 12 .IP \fId\fP 1i day 1 to number of days in month .IP \fIy\fP 1i year 1753 to 9999 .SH DESCRIPTION Calculates the weekday for the given day \fId\fP, month \fIm\fP, and year \fIy\fP. .SH RETURN VALUE 0 for Sunday, 1 for Monday and so on through 6 for Saturday. A value of -1 is returned if a passed value is out of range. .SH "SEE ALSO" XmLDateDaysInMonth(3X) nedit-5.6.orig/Microline/man/XmLDrawnButtonSetType.3x0000644000175000017500000000667710077552126021315 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLDrawnButtonSetType 3X "R1" "XML1" "XML" .SH NAME XmLDrawnButtonSetType \- adds graphics to a DrawnButton widget .SH SYNTAX void XmLDrawnButtonSetType(\fIwidget\fP, \fIdrawnType\fP, \fIdrawnDir\fP) .br Widget \fIwidget\fP; .br int \fIdrawnType\fP; .br int \fIdrawnDir\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i DrawnButton widget ID .IP \fIdrawnType\fP 1i type of button to display .IP \fIdrawnDir\fP 1i direction of button to display .SH DESCRIPTION Given a \fIwidget\fP of class XmDrawnButton this function attaches expose and realize callbacks to the widget to display the specified graphic in the button. This function also sets the widget's XmNpushButtonEnabled resource to True. The \fIdrawnType\fP value given must be one of the following: XmDRAWNB_ARROW, XmDRAWNB_ARROWLINE, XmDRAWNB_DOUBLEARROW, XmDRAWNB_SQUARE ,XmDRAWNB_DOUBLEBAR or XmDRAWNB_STRING. The \fIdrawnDir\fP value given must be XmDRAWNB_RIGHT, XmDRAWNB_LEFT, XmDRAWNB_UP, or XmDRAWNB_DOWN. The graphics inside the button are drawn in the widget's foreground color. nedit-5.6.orig/Microline/man/XmLFolder.3x0000644000175000017500000003772510077552126016741 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLFolder 3X "R1" "XML1" "XML" .SH NAME XmLFolder .SH SYNOPSIS #include .LP .SH DESCRIPTION Provides a Folder containing tabs along the top, bottom, left or right and an area managed by the tabs in the center. Each tab consists of a Primitive widget surrounded by tab decorations including an optional pixmap. Any non-Primitive widget children of the Folder are placed in the center area. The widgets contained in the tabs can be assigned a non-Primitive widget to display/manage when the tab widget is selected. .SS Class Information Folder inherits from XmManager, Constraint, Composite and Core. Its class pointer is xmlFolderWidgetClass. Its class name is XmLFolder. .SS New Resources .nf .ft B Name Class Type Default Access .ft P XmNactiveTab XmCActiveTab int -1 G XmNautoSelect XmCAutoSelect Boolean True CSG XmNblankBackground XmCBlankBackground Pixel dynamic CSG XmNblankBackgroundPixmap XmCBlankBackgroundPixmap Pixmap dynamic CSG XmNcornerDimension XmCCornerDimension Dimension 2 CSG XmNcornerStyle XmCCornerStyle unsigned char XmCORNER_ARC CSG XmNdebugLevel XmCDebugLevel int 0 CSG XmNfontList XmCFontList XmFontList dynamic CSG XmNhighlightThickness XmCHighlightThickness Dimension 2 CSG XmNinactiveBackground XmCInactiveBackground Pixel dynamic CSG XmNinactiveForeground XmCInactiveForeground Pixel dynamic CSG XmNmarginHeight XmCMarginHeight Dimension 0 CSG XmNmarginWidth XmCMarginWidth Dimension 0 CSG XmNpixmapMargin XmCPixmapMargin Dimension 2 CSG XmNresizePolicy XmCFolderResizePolicy XmRFolderResizePolicy XmRESIZE_STATIC CSG XmNrotateWhenLeftRight XmCRotateWhenLeftRight Boolean True CSG XmNspacing XmCSpacing Dimension 0 CSG XmNtabBarHeight XmCTabBarHeight Dimension dynamic G XmNtabCount XmCTabCount int 0 G XmNtabPlacement XmCTabPlacement unsigned char XmFOLDER_TOP CSG XmNtabsPerRow XmCTabsPerRow int 0 CSG XmNtabTranslations XmCTranslations XtTranslations [focus translations] CG XmNtabWidgetList XmCReadOnly WidgetList dynamic G .fi .IP XmNactiveTab The position of the currently active tab. The first tab on the left has a position of 0. If no tab is active, this value equals -1. .IP XmNautoSelect If True (the default), the Folder will activate its first tab when it is realized. No callback is generated by this action. If False, no initial tab will be activated. .IP XmNblankBackground The color of the area between tabs, around tabs, and between tabs and the edge of the Folder. .IP XmNblankBackgroundPixmap The pixmap to display as a background (tiled) in the blank background area. See XmNblankBackground. .IP XmNcornerDimension If XmNcornerStyle is XmCORNER_LINE, this value is used to determine the length of the lines that clip the corners of the tabs. The greater this value is, the longer the corner lines will be. If XmNcornerStyle is XmCORNER_ARC, this value is used to determine the sizes of the arcs in the corners of the tabs. If XmNcornerStyle is XmCORNER_NONE, this resource has no effect. .IP XmNcornerStyle Defines the type of corners on the individual tabs. Possible values: .nf XmCORNER_NONE /* no corners */ XmCORNER_LINE /* corners are beveled */ XmCORNER_ARC /* corners are round */ .fi .IP XmNdebugLevel If set to a value greater than 0, debugging messages will be printed to stderr. When set to 0 (the default) only error messages will be generated. .IP XmNfontList The default font list for tabs created with the XmLFolderAddTab() functions. Changing this value does not affect existing widgets. If this value is NULL, a font list is obtained from the nearest parent that is a subclass of BulletinBoard, MenuShell, or VendorShell. .IP XmNhighlightThickness The thickness of the highlight drawn around the Primitive widget contained in the active tab. When a Primitive widget is added to the Folder, its highlightThickness is set to 0. The Folder is responsible for drawing the highlight in the active tab. This is necessary because if the Primitive widget were allowed to draw the highlight, it would erase the highlight with an incorrect color. .IP XmNinactiveBackground The background color of inactive tabs. This value is initially set to the background color of the Folder widget. .IP XmNinactiveForeground The foreground color of inactive tabs. This value is initially set to the foreground color of the Folder widget. .IP XmNmarginHeight If tab placement is on the top or bottom, this value is the margin between tab widgets and the top of tabs, and between tab widgets and the bottom of tabs. If tab placement is on the left or right, this value is the margin between tab widgets and the left of tabs, and between tab widgets and the right of tabs. .IP XmNmarginWidth If tab placement is on the top or bottom, this value is the margin between tab widgets and the left of tabs, and between tab widgets and the right of tabs. If tab placement is on the left or right, this value is the margin between tab widgets and the top of tabs and between tab widgets and bottoms of tabs. .IP XmNpixmapMargin The margin between the tab widget and any pixmap to its left. .IP XmNresizePolicy This policy determines when the Folder should perform a request for a new size from its parent. A policy of XmRESIZE_STATIC (the default) will cause the Folder to initially request a size which includes the preferred size of its children and then reject any subsequent resize requests from its non-tab widget children. A policy of XmRESIZE_DYNAMIC will cause the Folder to resize itself to include the preferred size of any of its children whenever its children change size. A policy of XmRESIZE_NONE will cause the Folder to never generate a resize request and also will cause it not to perform geometry management on its non-tab widget children. Possible values: .nf XmRESIZE_NONE /* no resize requests and no placement or geometry management of non-tab children */ XmRESIZE_STATIC /* initially layout to include preferred size of children */ XmRESIZE_DYNAMIC /* dynamically resize as children request new size */ .fi .IP XmNrotateWhenLeftRight If True, XmDrawnButton based tabs (including tabs created with the XmLFolderAddTab() functions) will display their text vertically instead of horizontally if they are placed on the left or right of the Folder. This occurs when the Folder's XmNtabPlacement resource is XmFOLDER_LEFT or XmFOLDER_RIGHT. Tabs on the left would have their text drawn up and tabs on the right would have their text drawn down. If False, tabs are left oriented horizontally regardless of their placement. .IP XmNspacing The amount of space between tabs. .IP XmNtabBarHeight The height, in pixels, of the tab bar. If tab placement is on the left or right, this value is the width of the tab bar. This value may not be set and is only valid after the Folder has been managed and has performed its layout. .IP XmNtabCount The number of tabs displayed. .IP XmNtabPlacement Where to place the tabs. Possible values: .nf XmFOLDER_TOP /* top left to right */ XmFOLDER_BOTTOM /* bottom left to right */ XmFOLDER_LEFT /* left top to bottom */ XmFOLDER_RIGHT /* right top to bottom */ .fi .IP XmNtabsPerRow If set to 0 (the default), the Folder will place tabs in a single row one after another during layout. If non-zero, this value specifies the number of rows of tabs to appear in the Folder and the Folder will pad each row to the width of the Folder by proportionally sizing the tabs based on their contents and the width of the row. .IP XmNtabTranslations The translation table used to augment the translations of Primitive widgets added to the Folder. The Folder overrides the FocusIn and FocusOut translations of its Primitive widget children allowing it to draw and erase tab highlights. .IP XmNtabWidgetList The list of widgets contained inside the tabs. These widgets are subclasses of XmPrimitive. .SS Constraint Resources Folder defines the following constraint resources. .nf .ft B Name Class Type Default Access .ft P XmNtabFreePixmaps XmCTabFreePixmap Boolean False CSG XmNtabInactivePixmap XmCTabInactivePixmap Pixmap XmUNSPECIFIED_PIXMAP CSG XmNtabManagedName XmCTabManagedName String NULL CSG XmNtabManagedWidget XmCTabManagedWidget Widget NULL CSG XmNtabPixmap XmCTabPixmap Pixmap XmUNSPECIFIED_PIXMAP CSG .fi .IP XmNtabFreePixmaps If True, the Folder will call XFreePixmap on the XmNtabPixmap and XmNtabInactivePixmap pixmaps when this widget is destroyed. This value is set to True for tabs created by the XmLFolderAddBitmapTab() functions. .IP XmNtabInactivePixmap The pixmap to appear in the left of the tab when the tab is inactive. .IP XmNtabManagedName By setting a managed name on a tab widget and setting the same managed name on a Manager widget, you specify that the tab manages the Manager widget. You can also specify that a tab manages a specific Manager widget by setting the managed name on the tab widget to the name (XtName) of the Manager widget. If a tab widget has a managed name, the XmNtabManagedWidget resource of the tab widget is ignored. .IP XmNtabManagedWidget Specifies a widget to be managed when this widget is activated. When this widget is deactivated, its managed widget will be unmanaged. This resource allows Manager widgets contained in the center of the Folder to be attached to tabs, so when a user selects a tab its attached Manager widget will be displayed on the screen. .IP XmNtabPixmap The pixmap to appear in the left of the tab when the tab is active. .SS Callback Resources Folder defines the following callback resources. .nf .ft B Callback Reason .ft P XmNactivateCallback XmCR_ACTIVATE .fi .SS Callback Structure Each callback function is passed a pointer to the structure shown below. .nf typedef struct { int reason; /* callback reason */ XEvent *event; /* event callback or NULL */ int pos; /* position of tab to act */ int allowActivate; /* allow/disallow act (1/0) */ } XmLFolderCallbackStruct; .fi pos will be set to the position of the tab (with 0 as the first tab on the left) to activate for XmNactivateCallback callbacks. If allowActivate is set to 0 by the callback function, the tab will not be activated and the attempt to activate the given tab will be rejected. .SS Inherited Resources Folder inherits the resources shown below. .nf .ft B Resource From Resource From .ft P XmNaccelerators Core XmNinitialResourcePersist Core XmNancestorSensitive Core XmNinsertPosition Composite XmNbackground Core XmNmappedWhenManaged Core XmNbackgroundPixmap Core XmNnavagationType Manager XmNborderColor Core XmNnumChildren Composite XmNborderPixmap Core XmNscreen Core XmNborderWidth Core XmNsensitive Core XmNbottomShadowColor Manager XmNshadowThicknses Manager XmNbottomShadowPixmap Manager XmNstringDirection Manager XmNchildren Composite XmNtopShadowColor Manager XmNcolormap Core XmNtopShadowPixmap Manager XmNdepth Core XmNtranslations Core XmNdestroyCallback Core XmNtraversalOn Manager XmNforeground Manager XmNunitType Manager XmNheight Core XmNuserData Manager XmNhelpCallback Manager XmNwidth Core XmNhighlightColor Manager XmNx Core XmNhighlightPixmap Manager XmNy Core .fi .SS Folder Translations Folder defines the translations shown below. .nf .ft B Event Action .ft P BSelect Press XmLFolderActivate() .fi .SS Folder Primitive Translations Folder overrides the translations shown below for all of its Primitive widget children. .nf .ft B Event Action .ft P FocusIn PrimitiveFocusIn() XmLFolderPrimFocusIn() FocusOut PrimtiveFocusOut() XmLFolderPrimFocusOut() .fi .SS Action Routines Folder defines the actions shown below. .IP XmLFolderActivate() Activates the tab at the location of the event passed to the action routine. .IP XmLFolderPrimFocusIn() Draws a highlight around the given widget. .IP XmLFolderPrimFocusOut() Erases the highlight around the given widget. .SH "SEE ALSO" XmLCreateFolder(3X) XmLFolderAddBitmapTab(3X) XmLFolderAddBitmapTabForm(3X) XmLFolderAddTab(3X) XmLFolderAddTabForm(3X) XmLFolderSetActiveTab(3X) nedit-5.6.orig/Microline/man/XmLFolderAddBitmapTab.3x0000644000175000017500000000653110077552126021125 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLFolderAddBitmapTab 3X "R1" "XML1" "XML" .SH NAME XmLFolderAddBitmapTab \- add a tab to a Folder containing a string and bitmap .SH SYNTAX Widget XmLFolderAddBitmapTab(\fIwidget\fP, \fIstring\fP, \ \fIbitmapBits\fP, \fIbitmapWidth\fP, \fIbitmapHeight\fP) .br Widget \fIwidget\fP; .br XmString \fIstring\fP; .br char *\fIbitmapBits\fP; .br int \fIbitmapWidth\fP; .br int \fIbitmapHeight\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Folder widget ID .IP \fIstring\fP 1i string to display in the tab .IP \fIbitmapBits\fP 1i bitmap to display in the tab .IP \fIbitmapWidth\fP 1i width of the bitmap in pixels .IP \fIbitmapHeight\fP 1i height of the bitmap in pixels .SH DESCRIPTION Adds a tab to the Folder \fIwidget\fP containing the \fIstring\fP and \fIbitmap\fP specified. .SH RETURN VALUE Returns the widget ID of the DrawnButton widget contained in the tab. .SH "SEE ALSO" XmLFolderAddBitmapTabForm(3X) XmLFolderAddTab(3X) XmLFolder(3X) nedit-5.6.orig/Microline/man/XmLFolderAddBitmapTabForm.3x0000644000175000017500000000665310077552126021756 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLFolderAddBitmapTabForm 3X "R1" "XML1" "XML" .SH NAME XmLFolderAddBitmapTabForm \- add a tab to a Folder containing a string and bitmap and a form managed by the tab .SH SYNTAX Widget XmLFolderAddBitmapTabForm(\fIwidget\fP, \fIstring\fP, \ \fIbitmapBits\fP, \fIbitmapWidth\fP, \fIbitmapHeight\fP) .br Widget \fIwidget\fP; .br XmString \fIstring\fP; .br char *\fIbitmapBits\fP; .br int \fIbitmapWidth\fP; .br int \fIbitmapHeight\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Folder widget ID .IP \fIstring\fP 1i string to display in the tab .IP \fIbitmapBits\fP 1i bitmap to display in the tab .IP \fIbitmapWidth\fP 1i width of the bitmap in pixels .IP \fIbitmapHeight\fP 1i height of the bitmap in pixels .SH DESCRIPTION Adds a tab to the Folder \fIwidget\fP containing the \fIstring\fP and \fIbitmap\fP specified and adds a form (XmForm widget) to the Folder which is managed by that tab. .SH RETURN VALUE Returns the widget ID of the Form widget managed by the new tab. .SH "SEE ALSO" XmLFolderAddTab(3X) XmLFolder(3X) nedit-5.6.orig/Microline/man/XmLFolderAddTab.3x0000644000175000017500000000572110077552126017770 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLFolderAddTab 3X "R1" "XML1" "XML" .SH NAME XmLFolderAddTab \- add a tab to a Folder containing a string .SH SYNTAX Widget XmLFolderAddTab(\fIwidget\fP, \fIstring\fP) .br Widget \fIwidget\fP; .br XmString \fIstring\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Folder widget ID .IP \fIstring\fP 1i string to display in the tab .SH DESCRIPTION Adds a tab to a Folder containing the \fIstring\fP specified. .SH RETURN VALUE Returns the widget ID of the DrawnButton widget contained in the tab. .SH "SEE ALSO" XmLFolderAddBitmapTab(3X) XmLFolder(3X) nedit-5.6.orig/Microline/man/XmLFolderAddTabForm.3x0000644000175000017500000000612510077552126020613 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLFolderAddTabForm 3X "R1" "XML1" "XML" .SH NAME XmLFolderAddTabForm \- add a tab to a Folder containing a string and a form managed by the tab .SH SYNTAX Widget XmLFolderAddTabForm(\fIwidget\fP, \fIstring\fP) .br Widget \fIwidget\fP; .br XmString \fIstring\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Folder widget ID .IP \fIstring\fP 1i string to display in the tab .SH DESCRIPTION Adds a tab to the Folder \fIwidget\fP containing the \fIstring\fP specified and adds a form (XmForm widget) to the Folder which is managed by that tab. .SH RETURN VALUE Returns the widget ID of the Form widget managed by the new tab. .SH "SEE ALSO" XmLFolderAddBitmapTabForm(3X) XmLFolder(3X) nedit-5.6.orig/Microline/man/XmLFolderSetActiveTab.3x0000644000175000017500000000632210077552126021165 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLFolderSetActiveTab 3X "R1" "XML1" "XML" .SH NAME XmLFolderSetActiveTab \- activate a tab at a given position .SH SYNTAX void XmLFolderSetActiveTab(\fIwidget\fP, \fIposition\fP, \fInotify\fP) .br Widget \fIwidget\fP; .br int \fIposition\fP; .br Boolean \fInotify\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Folder widget ID .IP \fIposition\fP 1i active tab position .IP \fInotify\fP 1i if True, activate callback will be called .SH DESCRIPTION Activates a tab at the given \fIposition\fP. If the activated tab manages a widget, that widget will be managed and any other widgets managed by other tabs will be unmanaged. The Folder's XmNactivateCallback callbacks will be called if \fInotify\fP is True and the position passed is different from the current active position. .SH "SEE ALSO" XmLFolder(3X) nedit-5.6.orig/Microline/man/XmLFontListCopyDefault.3x0000644000175000017500000000577410077552126021427 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLFontListCopyDefault 3X "R1" "XML1" "XML" .SH NAME XmLFontListCopyDefault \- returns a copy of the default font list for a widget .SH SYNTAX XmLFontList XmLFontListCopyDefault(\fIwidget\fP) .br Widget \fIwidget\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i widget to retrieve default font list for .SH DESCRIPTION Returns a copy of the default font list for the given \fIwidget\fP. The default font list is found by looking for the font list default of the nearest BulletinBoard, MenuShell or VendorShell parent. .SH RETURN VALUE A copy of the default font list for the given \fIwidget\fP. nedit-5.6.orig/Microline/man/XmLFontListGetDimensions.3x0000644000175000017500000000657210077552126021755 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLFontListGetDimensions 3X "R1" "XML1" "XML" .SH NAME XmLFontListGetDimensions \- calculates overall width and height of characters in a font list .SH SYNTAX void XmLFontListGetDimensions(\fIfontList\fP, \fIwidth\fP, \ \fIheight\fP, \fIuseAverageWidth\fP) .br XmFontList \fIfontList\fP; .br short *\fIwidth\fP; .br short *\fIheight\fP; .br Boolean \fIuseAverageWidth\fP; .LP .SH ARGUMENTS .IP \fIfontList\fP 1i font list .IP \fIwidth\fP 1i maximum or average character width in fontlist .IP \fIheight\fP 1i maximum character height in fontlist .IP \fIuseAverageWidth\fP 1i if True, return average glyph width instead of maximum glyph width .SH DESCRIPTION Calculates the overall \fIwidth\fP and \fIheight\fP of the characters in a given \fIfontList\fP. The height returned is the height of the tallest glyph. If \fIuseAverageWidth\fP is False, the width returned is the width of the widest glyph. If True, the width returned is the average width of all of the glyphs. nedit-5.6.orig/Microline/man/XmLGrid.3x0000644000175000017500000017336310077552126016412 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGrid 3X "R1" "XML1" "XML" .SH NAME XmLGrid .SH SYNOPSIS #include .LP .SH DESCRIPTION A Grid consists of cells in rows and columns. There are two basic cell types, defined by the nature of the cell content: STRING (XmString format), and PIXMAP (pixmap images). STRING cells may allow editing. Cells and regions within the Grid may be formatted with borders and shadowing. Rows and columns may be fixed on the top, bottom, left and right to remain in view while scrolling horizontally or vertically. There may be heading and footer rows at the top and bottom, and heading and footer columns at the left and right, in addition to the content rows and columns in the center of the Grid. While headings and footers must be fixed, content rows may scroll or may also be fixed on the top, bottom, left and right. .SS Class Information Grid inherits from XmManager, Constraint, Composite and Core. Its class pointer is xmlGridWidgetClass. Its class name is XmLGrid. .SS New Resources The Grid resources defined below affect its overall behavior, layout and appearance. Definitions of resources affecting rows, columns and cells follow the Grid resource definitions. .nf .ft B Name Class Type Default Access .ft P XmNallowColumnHide XmCAllowColumnHide Boolean False CSG XmNallowColumnResize XmCAllowColumnResize Boolean False CSG XmNallowDragSelected XmCAllowDragSelected Boolean False CSG XmNallowDrop XmCAllowDrop Boolean False CSG XmNallowRowHide XmCAllowRowHide Boolean False CSG XmNallowRowResize XmCAllowRowResize Boolean False CSG XmNautoSelect XmCAutoSelect Boolean True CSG XmNblankBackground XmCBlankBackground Pixel Dynamic CSG XmNbottomFixedCount XmCBottomFixedCount int 0 CSG XmNbottomFixedMargin XmCBottomFixedMargin Dimension 0 CSG XmNcolumns XmCColumns int 0 CSG XmNdebugLevel XmCDebugLevel int 0 CSG XmNeditTranslations XmCTranslations XtTranslations Dynamic CSG XmNfontList XmCFontList XmFontList Dynamic CSG XmNfooterColumns XmCFooterColumns int 0 CSG XmNfooterRows XmCFooterRows int 0 CSG XmNglobalPixmapHeight XmCGlobalPixmapHeight Dimension 0 CSG XmNglobalPixmapWidth XmCGlobalPixmapWidth Dimension 0 CSG XmNheadingColumns XmCHeadingColumns int 0 CSG XmNheadingRows XmCHeadingRows int 0 CSG XmNhiddenColumns XmCHiddenColumns int 0 G XmNhiddenRows XmCHiddenRows int 0 G XmNhighlightRowMode XmCHighlightRowMode Boolean False CSG XmNhighlightThickness XmCHighlightThickness Dimension 2 CSG XmNhorizontalScrollBar XmCHorizontalScrollBar Widget Dynamic G XmNhorizontalSizePolicy XmCHorizontalSizePolicy unsigned char XmCONSTANT CSG XmNhsbDisplayPolicy XmCHsbDisplayPolicy unsigned char XmAS_NEEDED CSG XmNimmediateDraw XmCImmediateDraw Boolean False CSG XmNlayoutFrozen XmCLayoutFrozen Boolean False CSG XmNleftFixedCount XmCLeftFixedCount int 0 CSG XmNleftFixedMargin XmCLeftFixedMargin Dimension 0 CSG XmNrightFixedCount XmCRightFixedCount int 0 CSG XmNrightFixedMargin XmCRightFixedMargin Dimension 0 CSG XmNrows XmCRows int 0 CSG XmNscrollBarMargin XmCScrollBarMargin Dimension 2 CSG XmNscrollColumn XmCScrollColumn int Dynamic CSG XmNscrollRow XmCScrollRow int Dynamic CSG XmNselectBackground XmCSelectBackground Pixel Dynamic CSG XmNselectForeground XmCSelectForeground Pixel Dynamic CSG XmNselectionPolicy XmCGridSelectionPolicy unsigned char XmSELECT_BROWSE_ROW CSG XmNshadowRegions XmCShadowRegions int 511 CSG XmNshadowType XmCShadowType unsigned char XmSHADOW_IN CSG XmNsimpleHeadings XmCSimpleHeadings String NULL CSG XmNsimpleWidths XmCSimpleWidths String NULL CSG XmNtextWidget XmCTextWidget Widget Dynamic G XmNtopFixedCount XmCTopFixedCount int 0 CSG XmNtopFixedMargin XmCTopFixedMargin Dimension 0 CSG XmNtraverseTranslations XmCTranslations XtTranslations Dynamic CSG XmNuseAverageFontWidth XmCUseAverageFontWidth Boolean True CSG XmNverticalScrollBar XmCVerticalScrollBar Widget 0 G XmNverticalSizePolicy XmCVerticalSizePolicy unsigned char XmCONSTANT CSG XmNvisibleColumns XmCVisibleColumns int 0 CSG XmNvisibleRows XmCVisibleRows int 0 CSG XmNvsbDisplayPolicy XmCVsbDisplayPolicy unsigned char XmAS_NEEDED CSG .fi .IP XmNallowColumnHide This resource only has effect when XmNallowColumnResize is True. If the user is able to resize columns, this resource controls whether a user can hide a column by resizing it to a zero width. If True, a user may size columns to a zero width (hiding them) and if False (the default), a user will not be able to resize a column to a zero width. .IP XmNallowColumnResize If True, the user may resize a column by dragging the right edge of a cell in a heading row. When the user resizes a column, the column's XmNcolumnSizePolicy is set to XmCONSTANT and the column's XmNcolumnWidth is set to the pixel width chosen by the user. If the Grid contains no heading rows, this resource has no effect. If False, interactive column resizing is disabled. .IP XmNallowDragSelected If True, the user may interactively drag cell contents (strings) to a drop site. If False, dragging is disabled. .IP XmNallowDrop If True, the user is allow to drop cell contents (strings) into the Grid. If False, the Grid will not register itself as a drop site. .IP XmNallowRowHide This resource only has effect when XmNallowRowResize is True. If the user is able to resize rows, this resource controls whether a user can hide a row by resizing it to a zero height. If True, a user may size rows to a zero height (hiding them) and if False (the default), a user will not be able to resize a row to a zero height. .IP XmNallowRowResize If True, the user may resize a row by dragging the bottom edge of a cell in a heading column. When the user resizes a row, the row's XmNrowSizePolicy is set to XmCONSTANT and the row's XmNrowHeight is set to the pixel height chosen by the user. If the Grid contains no heading columns, this resource has no effect. If False, interactive row resizing is disabled. .IP XmNautoSelect If set to True (the default) and the Grid's XmNselectionPolicy is XmSELECT_BROWSE_ROW, the Grid will select its first row when it is realized. No callback is generated by this action. If False, no initial row will be selected. .IP XmNblankBackground If a Grid has a horizontal scrollbar which is scrolled completely to the right or a vertical scrollbar which is scrolled to the bottom, an empty area can exist after the last set of scrolling cells. The color of this empty region is set by the XmNblankBackground resource. It will only be visible when the Grid is scrolled fully to the right or bottom. This value is initially set to the background color of the Grid widget. .IP XmNbottomFixedCount The number of fixed rows at the bottom of the Grid including footer rows. Since footer rows must be fixed, this value may not be set smaller than the number of footer rows. If this value is greater than the total number of rows, then as additional rows are added they will be fixed until this value is reached. .IP XmNbottomFixedMargin The height, in pixels, of the margin between the bottom fixed rows and any rows above them. .IP XmNcolumns The number of content columns. Setting this value will add content columns to the Grid if the value set is greater than the current number of content columns. Likewise, setting this value to a number less than the current number of content columns will cause content columns to be deleted. The Grid updates this resource to reflect the current number of content columns every time a content column is added or removed. To get the total number of columns in the Grid (heading, content and footer) add this value to the number of heading and footer columns. .IP XmNdebugLevel If set to a value greater than 0, debugging messages will be printed to stderr. When set to 0 (the default) only error messages will be reported. .IP XmNeditTranslations The translations merged into the Text widget child of the Grid when the Grid goes from traverse mode into edit mode. .IP XmNfontList The default font list for new cells. Changing this resource does not affect existing cells. If this value is NULL, a font list is obtained from the nearest parent that is a subclass of BulletinBoard, MenuShell, or VendorShell. .IP XmNfooterColumns The number of footer columns. Setting this value will add footer columns to the Grid if the value set is greater than the current number of footer columns. Likewise, setting this value to a number less than the current number of footer columns will cause footer columns to be deleted. The Grid updates this resource to reflect the current number of footer columns every time a footer column is added or removed. .IP XmNfooterRows The number of footer rows. Setting this value will add footer rows to the Grid if the value set is greater than the current number of footer rows. Likewise, setting this value to a number less than the current number of footer rows will cause footer rows to be deleted. The Grid updates this resource to reflect the current number of footer rows every time a footer row is added or removed. .IP XmNglobalPixmapHeight If non-zero, this value specifies the height of every pixmap contained in the cells of the Grid. You should set this resource only if all cell pixmaps have equal size. If you set this resource, you should also set XmNglobalPixmapWidth to the width of the pixmaps. Setting this value will increase performance when setting cell pixmaps since if this value is not set, the Grid will need to perform a query to determine the dimensions of any pixmap set. You should leave this value at 0 (the default) if you have pixmaps of varying size in the Grid. .IP XmNglobalPixmapWidth This resource should be used with XmNglobalPixmapHeight. See XmNglobalPixmapHeight for details. .IP XmNheadingColumns The number of heading columns. Setting this value will add heading columns to the Grid if the value set is greater than the current number of heading columns. Likewise, setting this value to a number less than the current number of heading columns will cause heading columns to be deleted. The Grid updates this resource to reflect the current number of heading columns every time a heading column is added or removed. .IP XmNheadingRows The number of heading rows. Setting this value will add heading rows to the Grid if the value set is greater than the current number of heading rows. Likewise, setting this value to a number less than the current number of heading rows will cause heading rows to be deleted. The Grid updates this resource to reflect the current number of heading rows every time a heading row is added or removed. .IP XmNhiddenColumns The total number of hidden columns. The Grid updates this resource every time a column is hidden or unhidden. Hidden columns are columns with a width of 0. .IP XmNhiddenRows The total number of hidden rows. The Grid updates this resource every time a row is hidden or unhidden. Hidden rows are rows with a height of 0. .IP XmNhighlightRowMode If True, a highlight is drawn around the entire row containing the cell which has focus instead of just around the current cell which has focus. If False (the default), when a cell has focus, the highlight will be drawn only around that cell. .IP XmNhighlightThickness The thickness of the highlight rectangle drawn in cells with focus. This value must be 0 or 2. .IP XmNhorizontalScrollBar The widget ID of the Grid's horizontal ScrollBar. .IP XmNhorizontalSizePolicy Determines how the Grid sizes itself horizontally. Possible values: .nf XmVARIABLE /* Grid always requests full width */ XmCONSTANT /* user or parent sets Grid width and scrollbar is displayed if required */ .fi If this value is XmVARIABLE, the Grid determines the amount of horizontal space required to display the entire Grid and requests this space from its parent. When the width of the Grid changes, it will request more or less space causing it to shrink or expand as its parent widget allows. It will appear truncated, without a horizontal ScrollBar, if not enough space is given by the parent. If this value is XmCONSTANT the user or the parent widget must define the Grid’s width and a horizontal ScrollBar will appear if needed. .IP XmNhsbDisplayPolicy When XmNhorizontalSizePolicy is XmCONSTANT, this resource controls whether to display the horizontal scroll bar if all rows fit in the viewing area. Possible values: .nf XmSTATIC /* scrollbar always displays */ XmAS_NEEDED /* scrolbar only displayed when scrolling is possible */ .fi .IP XmNimmediateDraw If False (the default), the Grid queues up and compresses drawing events. For example, if you change a cell's background and later change the cell's foreground, the Grid will only draw the cell once to reflect the changes. This drawing compression includes sending expose events to the X Server. If you do not want the Grid to queue and compress drawing events, you should set this value to True. You would want to set this resource to True in the case where you had a very slow connection to an X Server (over a serial line for instance). If set to True and the line to the X Server is slow, more drawing will be performed but the the drawing will show up faster. .IP XmNlayoutFrozen If True, the Grid's layout is frozen and the Grid will not recompute its layout until this resource is set to False. When this resource is set back to False, the layout will be recomputed and the entire Grid will redraw. When rows or columns are added to or deleted from the Grid, or if row heights, column widths or margins are changed, the Grid must recompute its layout by determining which cells to display on the screen. If a number of changes to the Grid layout are going to take place, then by setting this resource to True before executing the first change and setting it to False after the last change is requested, the Grid will not recompute its layout after each change. Setting this value will not affect what is displayed on the screen as it is only used to increase performance. If only a single layout change is requested, such as when adding or deleting a single range of rows or columns, this resource should not be used in an attempt to increase performance as the change may not require a redraw of the Grid. This resource should also not be used around code which does not cause the Grid to recompute its layout, such as changing cell or border colors, as that would decrease performance. .IP XmNleftFixedCount The number of fixed columns at the left of the Grid including heading columns. Since heading columns must be fixed, this value may not be set smaller than the number of heading columns. If this value is greater than the total number of columns, then as additional columns are added they will be fixed until this value is reached. .IP XmNleftFixedMargin The width, in pixels, of the margin between the left fixed columns and any columns to their right. .IP XmNrightFixedCount The number of fixed columns at the right of the Grid including footer columns. Since footer columns must be fixed, this value may not be set smaller than the number of footer columns. If this value is greater than the total number of columns, then as additional columns are added they will be fixed until this value is reached. .IP XmNrightFixedMargin The width, in pixels, of the margin between the right fixed columns and any columns to their left. .IP XmNrows The number of content rows. Setting this value will add content rows to the Grid if the value set is greater than the current number of content rows. Likewise, setting this value to a number less than the current number of content rows will cause content rows to be deleted. The Grid updates this resource to reflect the current number of content rows every time a content row is added or removed. To get the total number of rows in the Grid (heading, content and footer) add this value to the number of heading and footer rows. .IP XmNscrollBarMargin The margin, in pixels, between the ScrollBars and the displayed cells. .IP XmNscrollColumn The left-most scrolling content column currently displayed. This value may be set to change the current scroll position. If setting this value causes the scroll position to change, the Grid's scroll callbacks will be called. If this value is set greater than the last possible scrolling column, the Grid will scroll to the last possible scrolling column. If this value is set less than the first possible scrolling column, the Grid will scroll to the first possible scrolling column. .IP XmNscrollRow The top scrolling content row currently displayed. This value may be set to change the current scroll position. If setting this value causes the scroll position to change, the Grid's scroll callbacks will be called. If this value is set greater than the last possible scrolling row, the Grid will scroll to the last possible scrolling row. If this value is set less than the first possible scrolling row, the Grid will scroll to the first possible scrolling row. .IP XmNselectBackground The background color of cells, rows or columns which are currently selected. This value is initially set to the foreground color of the Grid widget. .IP XmNselectForeground The foreground color of cells, rows or columns which are currently selected. This value is initially set to the background color of the Grid widget. .IP XmNselectionPolicy Determines the types of selections allowed in the Grid. In SELECT_NONE mode, user selections have no effect by default and cell select callbacks are called each time a user selects a cell. The application may set selections of rows/columns or cells. In SELECT_SINGLE_ROW mode, one or zero content rows may be selected. In SELECT_BROWSE_ROW mode, one content row must be selected at all times. In SELECT_MULTIPLE_ROW, multiple content rows may be selected. In any of the SELECT_..._ROW modes, when cells in heading or footer rows are selected by a user, the Grid will call its cell select callbacks. Therefore, the application must be sure to check the type of selection made in its select callback(s). In SELECT_CELL mode, arbitrary regions of cells in content rows and content columns may be selected. A user may select cells in heading rows to select columns and cells in heading columns to select rows. Possible values: .nf XmSELECT_NONE /* no selections */ XmSELECT_SINGLE_ROW /* 0 or 1 row selection */ XmSELECT_BROWSE_ROW /* 1 row selection */ XmSELECT_MULTIPLE_ROW /* multiple row selection */ XmSELECT_CELL /* multiple row, column, cell selections */ .fi .IP XmNshadowRegions Determines which regions are drawn with shadows. There are 9 regions in the Grid numbered as follows: .nf 1 2 4 8 16 32 64 128 256 .fi Where 1, 2 and 4 combine to make the top fixed rows. 1, 8 and 64 combine into the left fixed columns, 16 is the scrolling region, etc. The value should be set to the summation of the region’s numbers which should be drawn with a shadow. For example, if this value is set to 428 (64 + 128 + 256) the Grid will draw a shadow box around each region in the bottom row. Regions not included are drawn without shadows. .IP XmNshadowType The type of shadows to draw around the regions of the Grid. Possible values: .nf XmSHADOW_ETCHED_IN /* etched in appearance */ XmSHADOW_ETCHED_OUT /* etched out appearance */ XmSHADOW_IN /* inset appearance */ XmSHADOW_OUT /* outset appearance */ .fi .IP XmNsimpleHeadings This resource may be used to set cell strings in the first heading row in a Grid with a simple C string. The value passed should be a null-terminated C string containing headings separated by the pipe symbol. A heading row must exist at the time of this call which contains the number of cells which will be affected or the Grid will generate a warning. The following example sets the headings of a Grid to "First", "Second" and "Third": .nf XtVaSetValues(grid, XmNsimpleHeadings, "First|Second|Third", NULL); .fi The Grid makes a copy of the string passed to it for this resource in a SetValues call. The Grid will return a pointer to this internal copy of the string if GetValues is called for this resource and the pointer returned should not be freed by an application. .IP XmNsimpleWidths This resource may be used to set the widths of columns in a Grid. The value passed should be a null-terminated C string containing numbers specifying widths and a letter 'p' or 'c' following the number to indicate whether the width is in pixels or characters. A space should be used after each letter to separate columns. The columns affected by the call must exist at the time a value is set, or the Grid will generate a warning. The following example sets the width of the first column to 10 characters wide and the second column to 20 pixels wide: .nf XtVaSetValues(grid, XmNsimpleWidths, "10c 20p", NULL); .fi The Grid makes a copy of the string passed to it for this resource in a SetValues call. The Grid will return a pointer to this internal copy of the string if GetValues is called for this resource and the pointer returned should not be freed by an application. .IP XmNtextWidget The widget ID of the Grid's Text widget. .IP XmNtopFixedCount The number of fixed rows at the top of the Grid including heading rows. Since heading rows must be fixed, this value may not be set smaller than the number of heading rows. If this value is greater than the total number of rows, then as additional rows are added they will be fixed until this value is reached. .IP XmNtopFixedMargin The height, in pixels, of the margin between the top fixed rows and any rows below them. .IP XmNtraverseTranslations The translations merged into the Text widget child of the Grid when the Grid goes from edit mode into traverse mode. .IP XmNuseAverageFontWidth Cells in the Grid which contain text calculate their preferred width based on the font list character width of the font list assigned to the cell. The Grid calculates the font list character width when font lists are assigned to cells. If the value of this resource is True, the font list character width will be calculated by averaging all of the glyph widths in the font list. If this value is False, the font list character width will equal the the maximum glyph width in the font list. Changing this resource only affects font lists assigned after this value is changed, it does not affect the current layout of the Grid. Also, this resource only affects cells containing proportional fonts since a fixed width font's average glyph width will equal its maximum glyph width. .IP XmNverticalScrollBar The widget ID of the Grid's vertical ScrollBar. .IP XmNverticalSizePolicy Determines how the Grid sizes itself vertically. Possible values: .nf XmVARIABLE /* Grid always requests full height */ XmCONSTANT /* user or parent sets Grid height and scrollbar is displayed if needed */ .fi If this value is XmVARIABLE, the Grid determines the amount of vertical space required to display the entire Grid and requests this space from its parent. When the height of the Grid changes, it will request more or less space causing it to shrink or expand as its parent widget allows. It will appear truncated, without a vertical ScrollBar, if not enough space is given by the parent. If this value is XmCONSTANT the user or the parent widget must define the Grids height and a vertical ScrollBar will appear if needed. .IP XmNvisibleColumns Setting this resource causes the Grid to request a width from its parent equal to the value set multiplied by the width of a standard 8 character wide cell. The actual width in pixels requested is: .nf shadowThickness * 2 + value * (4 + 8 * defaultFontWidth + defaultLeftMargin + defaultRightMargin) .fi The width requested is not determined using any existing column values. For example, if you have 3 columns which are each 20 characters wide and you set XmNvisibleColumns to 3, the width requested will not fit the 3 columns of 20 characters, it will fit 3 columns of 8 characters (without Grid borders). The width requested does depend on the default font in the Grid, however, to determine the width of a standard 8 character wide cell. If you want the Grid to request a width equal to the width of the existing columns, see the XmNhorizontalSizePolicy resource's XmVARIABLE setting. .IP XmNvisibleRows Setting this resource causes the Grid to request a height from its parent equal to the value set multiplied by the height of a default 1 character height cell. The actual height in pixels requested is: .nf shadowThickness * 2 + value * (4 + defaultFontHeight + defaultTopMargin + defaultBottomMargin) .fi The height requested is not determined using any existing row values. For example, if you have 10 rows which are each 3 characters high and you set XmNvisibleRows to 10, the height requested will not fit the 10 existing rows, it will fit fit 10 rows of 1 character height (without Grid borders). The height requested does depend on the default font in the Grid, however, to determine the height of a standard cell. If you want the Grid to request a height equal to the height of the existing rows, see the XmNverticalSizePolicy resource's XmVARIABLE setting. .IP XmNvsbDisplayPolicy When XmNverticalSizePolicy is XmCONSTANT, this resource controls whether to display the vertical scroll bar if all rows fit in the viewing area. Possible values: .nf XmSTATIC /* scrollbar always displays */ XmAS_NEEDED /* scrolbar only displayed when scrolling is possible */ .fi .SS Row/Column/Cell Resources Grid defines the resources in the table below affecting rows, columns and cells. A SetValues call can set values for a single column using XmNcolumn or for a range of columns using XmNcolumnRangeStart and XmNcolumnRangeEnd. Row values can be set using XmNrow or XmNrowRangeStart and XmNrowRangeEnd. Cell values can be set for a single cell using XmNcolumn and XmNrow, or a range of cells using a variety of combinations of row and column specifications. A GetValues call can retrieve values for a column using XmNcolumnPtr, a row using XmNrowPtr, and a cell using both XmNcolumnPtr and XmNrowPtr. .nf .ft B Name Class Type Default Access .ft P XmNcellAlignment XmCCellAlignment unsigned char XmALIGNMENT_CENTER SG XmNcellBackground XmCCellBackground Pixel Dynamic SG XmNcellBottomBorderColor XmCCellBottomBorderColor Pixel Dynamic SG XmNcellBottomBorderType XmCBottomBorderType unsigned char XmBORDER_LINE SG XmNcellColumnSpan XmCCellColumnSpan int 0 SG XmNcellDefaults XmCCellDefaults Boolean False S XmNcellEditable XmCCellEditable Boolean False SG XmNcellFontList XmCCellFontList XmFontList Dynamic SG XmNcellForeground XmCCellForeground Pixel Dynamic SG XmNcellLeftBorderColor XmCCellLeftBorderColor Pixel Dynamic SG XmNcellLeftBorderType XmCCellLeftBorderType unsigned char XmBORDER_LINE SG XmNcellMarginBottom XmCCellMarginBottom Dimension 0 SG XmNcellMarginLeft XmCCellMarginLeft Dimension 0 SG XmNcellMarginRight XmCCellMarginRight Dimension 0 SG XmNcellMarginTop XmCCellMarginTop Dimension 0 SG XmNcellPixmap XmCCellPixmap Pixmap XmUNSPECIFIED_PIXMAP SG XmNcellPixmapMask XmCCellPixmapMask Pixmap XmUNSPECIFIED_PIXMAP SG XmNcellRightBorderColor XmCCellRightBorderColor Pixel Dynamic SG XmNcellRightBorderType XmCCellRightBorderType unsigned char XmBORDER_LINE SG XmNcellRowSpan XmCCellRowSpan int 0 SG XmNcellString XmCXmString XmString NULL SG XmNcellTopBorderColor XmCCellTopBorderColor Pixel Dynamic SG XmNcellTopBorderType XmCCellTopBorderType unsigned char XmBORDER_LINE SG XmNcellType XmCCellType unsigned char XmSTRING_CELL SG XmNcellUserData XmCUserData XtPointer 0 SG XmNcolumn XmCGridColumn int -1 S XmNcolumnPtr (none) XtPointer 0 G XmNcolumnRangeEnd XmCColumnRangeEnd int -1 S XmNcolumnRangeStart XmCColumnRangeStart int -1 S XmNcolumnSizePolicy XmCColumnSizePolicy unsigned char XmVARIABLE SG XmNcolumnStep XmCColumnStep int 1 S XmNcolumnType XmCColumnType unsigned char XmCONTENT S XmNcolumnWidth XmCColumnWidth Dimension 8 SG XmNcolumnUserData XmCUserData XtPointer 0 SG XmNrow XmCGridRow int -1 S XmNrowHeight XmCRowHeight Dimension 1 SG XmNrowPtr (none) XtPointer 0 G XmNrowRangeEnd XmCRowRangeEnd int -1 S XmNrowRangeStart XmCRowRangeStart int -1 S XmNrowSizePolicy XmCRowSizePolicy unsigned char XmVARIABLE SG XmNrowStep XmCRowStep int 1 S XmNrowType XmCRowType unsigned char XmCONTENT S XmNrowUserData XmCUserData XtPointer 0 SG .fi .IP XmNcellAlignment Determines the alignment of the XmString or Pixmap contained in the cell. Possible values: .nf XmALIGNMENT_LEFT /* left, centered vertically */ XmALIGNMENT_CENTER /* centered horizontally and vertically */ XmALIGNMENT_RIGHT /* right, centered vertically */ XmALIGNMENT_TOP_LEFT /* top left */ XmALIGNMENT_TOP /* top, centered horizontally */ XmALIGNMENT_TOP_RIGHT /* top right */ XmALIGNMENT_BOTTOM_LEFT /* bottom left */ XmALIGNMENT_BOTTOM /* bottom, centered horizontally */ XmALIGNMENT_BOTTOM_RIGHT /* bottom right */ .fi If a cell Pixmap does not have a width or height set, the cell's alignment will be top left regardless of the value of this resource since any other alignment could not be calculated. .IP XmNcellBackground The cell's background color. .IP XmNcellBottomBorderColor The color of the cell's bottom border. If the cell's bottom border type is XmBORDER_NONE, no bottom border will be drawn and this resource has no effect. The default value of this resource is the bottom shadow color of the Grid. .IP XmNcellBottomBorderType Determines the type of border to draw at the bottom of the cell. Possible values: .nf XmBORDER_NONE /* no border */ XmBORDER_DASH /* dashed line */ XmBORDER_LINE /* line border */ .fi .IP XmNcellColumnSpan The number of columns to the right that are spanned by this cell. You may combine this with a row span to span both rows and columns. When a cell spans into adjacent cells, those spanned cells are not displayed; instead, the contents of the spanning cell are displayed in the spanned area. This effectively makes the spanning cell larger while not changing the cell's row or column size. If cell spans overlap, the visual behavior of the spanned cells will become undefined. If rows or columns are added or deleted inside a spanned area, the visual behavior of the spanned cells will become undefined. If rows or columns are moved or reordered in a way which does not preserve existing cell spans, the visual behavior of the spanned cells will become undefined. The width of a column span in pixels cannnot exceed the maximum value of the type Dimension. Setting a column span on a cell sets its preferred cell width to 4 pixels. All cells in a span must exist at the time the span is set. .IP XmNcellDefaults Setting this value to True in a SetValues call indicates that the call is setting the default cell values. The default cell values can be assigned on a per-column basis by setting this resource to True and setting a column (using XmNcolumn) or a range of columns in the SetValues call. For example, to set the default editibility for cells in column 0 to editable, you could: .nf XtVaSetValues(grid, XmNcellDefaults, True, XmNcolumn, 0, XmNcellEditable, True, NULL); .fi This specifies that any cell created (cells are created by adding rows or columns) in column 0 will be editable by default. If you do not specify a column in a SetValues call where XmNcellDefaults is True, the default cell values in the call will be set for all columns. Inotherwords, it will set the defaults for any new cell created. This value is always reset to False after a SetValues call completes. .IP XmNcellEditable Allow (True) or disallow (False) a user either by typing, using a cut/paste or drag/drop operation, to edit the cell. This may only be set to True for cells with a XmNcellType of XmSTRING_CELL. .IP XmNcellFontList The font list used for the cell's text. By default, the value of this resource is set to the Grid's XmNfontList. Changing this value may cause the row or column containing the cell to resize if the row's XmNrowSizePolicy or the column's XmNcolumnSizePolicy is XmVARIABLE. .IP XmNcellForeground The cell's foreground color. .IP XmNcellLeftBorderColor The color of the cell's left border. If the cell's left border type is XmBORDER_NONE, no left border will be drawn and this resource has no effect. The default value of this resource is the top shadow color of the Grid. .IP XmNcellLeftBorderType Determines the type of border to draw at the left of the cell. Possible values: .nf XmBORDER_NONE /* no border */ XmBORDER_DASH /* dashed line */ XmBORDER_LINE /* line border */ .fi .IP XmNcellMarginBottom The height, in pixels, of the margin between the bottom of the cell and the cell's contents. .IP XmNcellMarginLeft The width, in pixels, of the margin between the left of the cell and the cell's contents. .IP XmNcellMarginRight The width, in pixels, of the margin between the right of the cell and the cell's contents. .IP XmNcellMarginTop The height, in pixels, of the margin between the top of the cell and the cell's contents. .IP XmNcellPixmap The Pixmap to draw in the cell if the cell's type is XmPIXMAP_CELL. As in other widgets, the Grid does not make a copy of the Pixmap. Therefore, the Pixmap should not be freed until it is no longer required to be displayed by the Grid. Changing this value may cause the row or column containing the cell to resize if the row's XmNrowSizePolicy or the column's XmNcolumnSizePolicy is XmVARIABLE. This value may be XmUNSPECIFIED_PIXMAP. .IP XmNcellPixmapMask The pixmap mask to use when drawing a cell if the cell's type is XmPIXMAP_CELL. This value must be either XmUNSPECIFIED_PIXMAP (the default) or a Pixmap of depth 1. If set to a Pixmap of depth 1, the Pixmap specified will be used as a mask for drawing the cell's contents. As in other widgets, the Grid does not make a copy of the Pixmap passed. Therefore, the Pixmap should not be freed until it is no longer required to be used by the Grid. .IP XmNcellRightBorderColor The color of the cell's right border. If the cell's right border type is XmBORDER_NONE, no right border will be drawn and this resource has no effect. The default value of this resource is the bottom shadow color of the Grid. .IP XmNcellRightBorderType Determines the type of border to draw at the right of the cell. Possible values: .nf XmBORDER_NONE /* no border */ XmBORDER_DASH /* dashed line */ XmBORDER_LINE /* line border */ .fi .IP XmNcellRowSpan The number of rows below that are spanned by this cell. You may combine this with a column span to span both rows and columns. When a cell spans into adjacent cells, those spanned cells are not displayed; instead, the contents of the spanning cell are displayed in the spanned area. This effectively makes the spanning cell larger while not changing the cell's row or column size. If cell spans overlap, the visual behavior of the spanned cells will become undefined. If rows or columns are added or deleted inside a spanned area, the visual behavior of the spanned cells will become undefined. If rows or columns are moved or reordered in a way which does not preserve existing cell spans, the visual behavior of the spanned cells will become undefined. The height of a row span in pixels cannnot exceed the maximum value of the type Dimension. Setting a row span on a cell sets its preferred cell height to 4 pixels. All cells in a span must exist at the time the span is set. .IP XmNcellString The compound string to draw in the cell if the cell's type is XmSTRING_CELL. As in other widgets, the Grid makes a copy of the string and so the string may be freed after it is used to set this value. Retrieving this value will return a copy of the cell's string, therefore the retrieved string should be freed when it will no longer be used. This value may be NULL. .IP XmNcellTopBorderColor The color of the cell's top border. If the cell's top border type is XmBORDER_NONE, no top border will be drawn and this resource has no effect. The default value of this resource is the top shadow color of the Grid. .IP XmNcellTopBorderType Determines the type of border to draw at the top of the cell. Possible values: .nf XmBORDER_NONE /* no border */ XmBORDER_DASH /* dashed line */ XmBORDER_LINE /* line border */ .fi .IP XmNcellType The type of the cell. Possible values: .nf XmSTRING_CELL /* cell displaying XmString */ XmPIXMAP_CELL /* cell displaying a Pixmap */ .fi Changing this value may cause the row or column containing the cell to resize if the row's XmNrowSizePolicy or the column's XmNcolumnSizePolicy is XmVARIABLE. Changing a cell's type from XmSTRING_CELL to XmPIXMAP_CELL will free the XmNcellString currently contained in the cell and will set the XmNcellString to NULL. Changing from XmPIXMAP_CELL to XmSTRING_CELL will cause the cell's XmNcellPixmap to be set to XmUNSPECIFIED_PIXMAP. .IP XmNcellUserData A pointer value unused by the Grid. This resource allows you to attach a pointer to any cell in the Grid. .IP XmNcolumn Defines which column(s) or cell(s) a SetValues call will affect. A value of -1 (the default) means all columns. This value is always reset to -1 after the SetValues call completes. The value of 0 defines the first column of a column type. This resource may not be used in a GetValues call. .IP XmNcolumnPtr Defines which column, or column a cell is contained in, a GetValues call should retrieve values for. This value is a pointer to a column which should be obtained using XmLGridGetColumn(). This resource may not be used in a SetValues call. .IP XmNcolumnRangeEnd Defines the last column or column of cells in a range which a SetValues call will affect. This resource may not be used in a GetValues call. This resource must be used with the XmNcolumnRangeStart resource. .IP XmNcolumnRangeStart Defines the first column or column of cells in a range which a SetValues call will affect. This resource may not be used in a GetValues call. This resource must be used with the XmNcolumnRangeEnd resource. .IP XmNcolumnSizePolicy Defines how the column width is determined. Possible values: .nf XmCONSTANT /* column size is fixed */ XmVARIABLE /* column may resize when cell size changes */ .fi If XmVARIABLE, the column will size itself to the maximum preferred width of the column's cells. For cells containing text, this usually equals the cell's average or maximum font list glyph width multiplied by the XmNcolumnWidth (plus space for borders, etc). If XmCONSTANT, the XmNcolumnWidth value is assumed to be in pixels and the column width will equal that value. .IP XmNcolumnStep Defines the column increment when setting values of multiple columns or cells in a SetValues call. For example, a column step of 2 will skip every other column. This value is 1 by default and will reset to 1 after a SetValues call completes. .IP XmNcolumnType Defines which type of columns or cells a SetValues call will affect. This resource may not be used in a GetValues call. Possible values: .nf XmALL_TYPES /* all column types - heading, content and footer */ XmCONTENT /* columns containing the Grid's contents */ XmHEADING /* heading columns on the far left */ XmFOOTER /* footer columns on the far right */ .fi This resource is used along with XmNcolumn or XmNcolumnRangeStart and XmNcolumnRangeEnd and determines which type of column the column or column range specifies. By default, this value is set to XmCONTENT. This value is always reset to XmCONTENT after a SetValues call completes. .IP XmNcolumnUserData A pointer value unused by the Grid. This resource allows you to attach a pointer to any column in the Grid. .IP XmNcolumnWidth If XmNcolumnSizePolicy is XmVARIABLE, the value of this resource represents the column width in characters and if a font list in any cell in the column is changed, the column will resize if required. The pixel width of a column is determined by the maximum preferred width of the column's cells. Cells containing text usually determine their preferred width by multiplying the cell's average or maximum font list glyph width by the column's XmNcolumnWidth. Pixmap cells ignore this resource since their preferred width is the width of their pixmap. If XmNcolumnSizePolicy is XmCONSTANT, the value of this resource represents the column width in pixels. .IP XmNrow Defines which row(s) or cell(s) a SetValues call will affect. A value of -1 (the default) means all rows. The value of 0 defines the first row of a row type. This value is always reset to -1 after a SetValues call completes. This resource may not be used in a GetValues call. .IP XmNrowHeight If XmNrowSizePolicy is XmVARIABLE, the value of this resource represents the row height in characters and if a font list in any cell in this row is changed, the row will resize if required. The pixel height of a row is determined by the maximum preferred height of the row's cells. Cells containing text usually determine their preferred height by taking their maximum font list character height and multiplying it by the row's XmNrowHeight. Pixmap cells ignore this resource since their preferred height is the height of their pixmap. If XmNrowSizePolicy is XmCONSTANT, the value of this resource represents the row height in pixels. .IP XmNrowPtr Defines which row, or row a cell is contained in, a GetValues call should retrieve values for. This value is a pointer to a row which should be obtained using XmLGridGetRow(). This resource may not be used in a SetValues call. .IP XmNrowRangeEnd Defines the last row or row of cells in a range which a SetValues call will affect. This resource may not be used in a GetValues call. This resource must be used with the XmNrowRangeStart resource. .IP XmNrowRangeStart Defines the first row or row of cells in a range which a SetValues call will affect. This resource may not be used in a GetValues call. This resource must be used with the XmNrowRangeEnd resource. .IP XmNrowSizePolicy Defines how the row height is determined. Possible values: .nf XmCONSTANT /* row size is fixed */ XmVARIABLE /* row may resize when cell size changes */ .fi If XmVARIABLE, the row will size itself to the maximum preferred height of the row's cells. For cells containing text, this usually equals the cell's maximum font list glyph height multiplied by the XmNrowHeight (plus space for borders, etc). If XmCONSTANT, the XmNrowHeight value is assumed to be in pixels and the row height will equal that value. .IP XmNrowStep Defines the row increment when setting values of multiple rows or cells in a SetValues call. For example, a row step of 2 will skip every other row. This value is 1 by default and will reset to 1 when a SetValue call completes. .IP XmNrowType Defines which type of rows or cells a SetValues call will affect. This resource may not be used in a GetValues call. Possible values: .nf XmALL_TYPES /* all row types - heading/content and footer */ XmCONTENT /* rows containing the Grid's contents */ XmHEADING /* heading rows on the top */ XmFOOTER /* footer rows on the bottom */ .fi This resource is used along with XmNrow or XmNrowRangeStart and XmNrowRangeEnd and determines which type of row the row or row range specifies. By default, this value is set to XmCONTENT. This value is always reset to XmCONTENT after a SetValues call completes. .IP XmNrowUserData A pointer value unused by the Grid. This resource allows you to attach a pointer to any row in the Grid. .SS Callback Resources Grid defines the following callback resources. .nf .ft B Callback Reasons Called When .ft P XmNactivateCallback XmCR_ACTIVATE Cell is activated with Return or double-click XmNaddCallback XmCR_ADD_CELL Row, column or cell is XmCR_ADD_COLUMN created by calling a function XmCR_ADD_ROW which adds rows or columns XmNcellDrawCallback XmCR_CELL_DRAW Cell is drawn XmNcellDropCallback XmCR_CELL_DROP Cell value was changed by new value dropped into cell XmNcellFocusCallback XmCR_CELL_FOCUS_IN Focus cell is set or changed XmCR_CELL_FOCUS_OUT XmNcellPasteCallback XmCR_CELL_PASTE Cell value was changed by new value pasted into cell XmNdeleteCallback XmCR_DELETE_CELL Row, column or cell is XmCR_DELETE_COLUMN deleted by calling a XmCR_DELETE_ROW function which deletes rows or columns XmNdeselectCallback XmCR_DESELECT_CELL Row, column or cell XmCR_DESELECT_COLUMN changes from selected XmCR_DESELECT_ROW to deselected (see also XmNselectionPolicy resource) XmNeditCallback XmCR_EDIT_BEGIN Cell edit begins, cancels, XmCR_EDIT_CANCEL completes or when an XmCR_EDIT_COMPLETE insert-begin occurs in XmCR_EDIT_INSERT a cell XmNresizeCallback XmCR_RESIZE_ROW Row or column is resized XmCR_RESIZE_COLUMN interactively XmNscrollCallback XmCR_SCROLL_ROW Current scrolled row or XmCR_SCROLL_COLUMN column position changes XmNselectCallback XmCR_SELECT_CELL Row, column or cell is XmCR_SELECT_COLUMN selected (see also XmCR_SELECT_ROW XmNselectionPolicy resource) .fi .SS Callback Structure Each callback function is passed a pointer to the structure shown below; however, only those values which are meaningful for the callback are set. .nf typedef struct { int reason; /* callback reason */ XEvent *event; /* event causing callback or NULL */ unsigned char rowType, columnType; /* row and column types */ int row, int column; /* row and column positions */ XRectangle *clipRect; /* clipping rectangle */ XmLGridDrawInfoStruct *drawInfo; /* pointer to draw info */ void *object; /* reserved */ } XmLGridCallbackStruct; .fi The drawInfo pointer is set to point to the structure below for XmNcellDraw callbacks. .nf typedef struct { GC gc; /* GC used for drawing */ XRectangle *cellRect; /* location/dimensions of cell (unclipped) */ Dimension topMargin; /* cell margins */ Dimension bottomMargin; Dimension leftMargin; Dimension rightMargin; Pixel foreground; /* cell foreground */ Pixel background; /* cell background */ Pixel selectForeground; /* cell foreground if selected */ Pixel selectBackground; /* cell background if selected */ XmFontList fontList; /* cell fontlist */ unsigned char alignment; /* cell alignment */ Boolean drawSelected; /* True if cell, row or column selected */ int drawFocusType; /* type of focus cell has, one of: XmDRAW_FOCUS_NONE - cell does not have focus XmDRAW_FOCUS_CELL - focus is in cell XmDRAW_FOCUS_LEFT - cell is leftmost in focus row XmDRAW_FOCUS_RIGHT - cell is rightmost in focus row XmDRAW_FOCUS_MID - cell is in middle of focus row */ XmStringDirection stringDirection; /* direction for string drawing */ } XmLGridDrawInfoStruct; .fi The following table shows which values are set for which callback reasons. Elements not set will have undefined values. .nf .ft B Reason Values Set .ft P XmCR_ACTIVATE event, rowType, columnType, row, column XmCR_ADD_CELL rowType, columnType XmCR_ADD_COLUMN columnType XmCR_ADD_ROW rowType XmCR_CELL_DRAW event, rowType, columnType, row, column, clipRect, drawInfo XmCR_CELL_DROP rowType, columnType, row, column XmCR_CELL_FOCUS_IN rowType, columnType, row, column XmCR_CELL_FOCUS_OUT rowType, columnType, row, column XmCR_CELL_PASTE rowType, columnType, row, column XmCR_DELETE_CELL rowType, columnType XmCR_DELETE_COLUMN columnType XmCR_DELETE_ROW rowType XmCR_DESELECT_CELL event, rowType, columnType, row, column XmCR_DESELECT_COLUMN event, columnType, column XmCR_DESELECT_ROW event, rowType, row XmCR_EDIT_BEGIN rowType, columnType, row, column XmCR_EDIT_COMPLETE rowType, columnType, row, column XmCR_EDIT_CANCEL rowType, columnType, row, column, clipRect XmCR_EDIT_INSERT rowType, columnType, row, column, clipRect XmCR_RESIZE_ROW rowType, row XmCR_RESIZE_COLUMN columnType, column XmCR_SCROLL_ROW rowType, row XmCR_SCROLL_COLUMN columnType, column XmCR_SELECT_CELL event, rowType, columnType, row, column XmCR_SELECT_COLUMN event, columnType, column XmCR_SELECT_ROW event, rowType, row .ni .SS Inherited Resources Grid inherits the resources shown below. The Grid resets its default XmNshadow-Thickness to 2. .nf .ft B Resource From Resource From .ft P XmNaccelerators Core XmNinitialResourcePersist Core XmNancestorSensitive Core XmNinsertPosition Composite XmNbackground Core XmNmappedWhenManaged Core XmNbackgroundPixmap Core XmNnavagationType Manager XmNborderColor Core XmNnumChildren Composite XmNborderPixmap Core XmNscreen Core XmNborderWidth Core XmNsensitive Core XmNbottomShadowColor Manager XmNshadowThicknses Manager XmNbottomShadowPixmap Manager XmNstringDirection Manager XmNchildren Composite XmNtopShadowColor Manager XmNcolormap Core XmNtopShadowPixmap Manager XmNdepth Core XmNtranslations Core XmNdestroyCallback Core XmNtraversalOn Manager XmNforeground Manager XmNunitType Manager XmNheight Core XmNuserData Manager XmNhelpCallback Manager XmNwidth Core XmNhighlightColor Manager XmNx Core XmNhighlightPixmap Manager XmNy Core .fi .SS Grid Translations Grid defines the translations shown below. .nf .ft B Event Action Event Action .ft P BSelect Press XmLGridSelect(BEGIN) BExtend Motion XmLGridButtonMotion() BExtend Press XmLGridSelect(EXTEND) BToggle Motion XmLGridButtonMotion() BToggle Press XmLGridSelect(TOGGLE) BSelect Release XmLGridSelect(END) BSelect Motion XmLGridButtonMotion() BExtend Release XmLGridSelect(END) BDrag Press XmLGridDragStart() .fi .SS Grid Text Traverse Translations When the Grid widget enters traverse mode, it overrides its Text widget child's translations with those shown below. .nf .ft B Event Action .ft P KUp XmLGridTraverse(UP) MCtrl KPageDown XmLGridTraverse(PAGE_RIGHT) MShift KUp XmLGridTraverse(EXTEND_UP) MCtrl MShift KPageDown XmLGridTraverse(EXTEND_ PAGE_RIGHT) MCtrl KUp XmLGridTraverse(PAGE_UP) KTab XmLGridTraverse(RIGHT) KDown XmLGridTraverse(DOWN) MShift KTab XmLGridTraverse(LEFT) MShift KDown XmLGridTraverse(EXTEND_DOWN) KBeginLine XmLGridTraverse(TO_TOP) MCtrl KDown XmLGridTraverse(PAGE_DOWN) KEndLine XmLGridTraverse(TO_BOTTOM) KLeft XmLGridTraverse(LEFT) KHome XmLGridTraverse(TO_TOP) MShift KLeft XmLGridTraverse(EXTEND_LEFT) MCtrl KHome XmLGridTraverse(TO_TOP_LEFT) MCtrl KLeft XmLGridTraverse(PAGE_LEFT) KEnd XmLGridTraverse(TO_BOTTOM) KRight XmLGridTraverse(RIGHT) MCtrl KEnd XmLGridTraverse(TO_BOTTOM_RIGHT) MShift KRight XmLGridTraverse(EXTEND_RIGHT) KInsert XmLGridEdit() MCtrl KRight XmLGridTraverse(PAGE_RIGHT) KF2 XmLGridEdit() KPageUp XmLGridTraverse(PAGE_UP) KSelect Press XmLGridSelect(BEGIN) MShift KPageUp XmLGridTraverse(EXTEND_ PAGE_UP) MCtrl KSelect Press XmLGridSelect(TOGGLE) MCtrl KPageUp XmLGridTraverse(PAGE_LEFT) KSelect Release XmLGridSelect(END) MCtrl MShift KPageUp XmLGridTraverse(EXTEND_ PAGE_LEFT) KEntend Press XmLGridSelect(EXTEND) KPageDown XmLGridTraverse(PAGE_DOWN) KExtend Release XmLGridSelect(END) MShift KPageDown XmLGridTraverse(EXTEND_ PAGE_DOWN) KActivate XmLGridSelect(ACTIVATE) .fi .SS Grid Text Edit Translations When the Grid widget enters edit mode, it overrides its Text widget child's translations with those shown below. .nf .ft B Event Action Event Action .ft P KDown XmLGridEditComplete(DOWN) KCancel XmLGridEditCancel() MShift KTab XmLGridEditComplete(LEFT) KActivate XmLGridEditComplete() KTab XmLGridEditComplete(RIGHT) KUp XmLGridEditComplete(UP) .fi .SS Action Routines Grid defines the actions shown below. .IP XmLGridButtonMotion() Moves any active resize line or extends the current selection if needed. .IP XmLGridCursorMotion() Changes the cursor to a resize cursor if it is over a resize area. .IP XmLGridDragStart() Begins a drag of the selected cells if required. .IP XmLGridEdit() Enters the Grid into edit mode and begins an edit of the current focus cell. .IP XmLGridEditCancel() Cancels any cell edit in progress and returns the Grid to traverse mode. .IP XmLGridEditComplete(direction) Completes any edit in progress and traverses in the direction specified. .IP XmLGridSelect(mode) Begins or completes selection of the mode type given depending on the event passed to the action function. .IP XmLGridTraverse(direction) Traverses in the given direction from the current focus cell. If traversal is successful, the new focus cell will be made visible, scrolling the Grid if necessary. .SH "SEE ALSO" XmLCreateGrid(3X) XmLGridAddColumns(3X) XmLGridAddRows(3X) XmLGridColumnIsVisible(3X) XmLGridDeleteAllColumns(3X) XmLGridDeleteAllRows(3X) XmLGridDeleteColumns(3X) XmLGridDeleteRows(3X) XmLGridDeselectAllCells(3X) XmLGridDeselectAllColumns(3X) XmLGridDeselectAllRows(3X) XmLGridDeselectCell(3X) XmLGridDeselectColumn(3X) XmLGridDeselectRow(3X) XmLGridEditBegin(3X) XmLGridEditCancel(3X) XmLGridEditComplete(3X) XmLGridGetColumn(3X) XmLGridGetFocus(3X) XmLGridGetRow(3X) XmLGridGetSelectedCellCount(3X) XmLGridGetSelectedCells(3X) XmLGridGetSelectedColumnCount(3X) XmLGridGetSelectedColumns(3X) XmLGridGetSelectedRow(3X) XmLGridGetSelectedRowCount(3X) XmLGridGetSelectedRows(3X) XmLGridMoveColumns(3X) XmLGridMoveRows(3X) XmLGridRead(3X) XmLGridReadPos(3X) XmLGridRedrawAll(3X) XmLGridRedrawCell(3X) XmLGridRedrawColumn(3X) XmLGridRedrawRow(3X) XmLGridReorderColumns(3X) XmLGridReorderRows(3X) XmLGridRowColumnToXY(3X) XmLGridRowlsVisible(3X) XmLGridSelectAllCells(3X) XmLGridSelectAllColumns(3X) XmLGridSelectAllRows(3X) XmLGridSelectCell(3X) XmLGridSelectColumn(3X) XmLGridSelectRow(3X) XmLGridSetFocus(3X) XmLGridSetStrings(3X) XmLGridSetStringsPos(3X) XmLGridWrite(3X) XmLGridWritePos(3X) XmLGridXYToRowColumn(3X) nedit-5.6.orig/Microline/man/XmLGridAddColumns.3x0000644000175000017500000000672310077552126020357 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridAddColumns 3X "R1" "XML1" "XML" .SH NAME XmLGridAddColumns \- add columns to a Grid .SH SYNTAX void XmLGridAddColumns(\fIwidget\fP, \fItype\fP, \ \fIposition\fP, \fIcount\fP) .br Widget \fIwidget\fP; .br unsigned char \fItype\fP; .br int \fIposition\fP; .br int \fIcount\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fItype\fP 1i type of column .IP \fIposition\fP 1i position of first column .IP \fIcount\fP 1i number of columns to add .SH DESCRIPTION Adds \fIcount\fP columns of the given \fItype\fP at the specified \fIposition\fP. See the XmLGrid man page for an explaination of column types. A position of 0 indicates the first column of the given type. A position of -1 specifies after the last position of that column type. The Grid will call its XmNaddCallback callbacks for each column and cell it creates. It will remain scrolled to the column scrolled to prior to the addition of columns, and focus will remain in the column which had focus prior to the addition of the columns. .SH "SEE ALSO" XmLGrid(3X) XmLGridAddRows(3X) nedit-5.6.orig/Microline/man/XmLGridAddRows.3x0000644000175000017500000000664610077552126017675 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridAddRows 3X "R1" "XML1" "XML" .SH NAME XmLGridAddRows \- add rows to a Grid .SH SYNTAX void XmLGridAddRows(\fIwidget\fP, \fItype\fP, \ \fIposition\fP, \fIcount\fP) .br Widget \fIwidget\fP; .br unsigned char \fItype\fP; .br int \fIposition\fP; .br int \fIcount\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fItype\fP 1i type of row .IP \fIposition\fP 1i position of first row .IP \fIcount\fP 1i number of rows to add .SH DESCRIPTION Adds \fIcount\fP rows of the given \fItype\fP at the specified \fIposition\fP. See the XmLGrid man page for an explaination of row types. A position of 0 indicates the first row of the given type. A position of -1 specifies after the last position of that row type. The Grid will call its XmNaddCallback callbacks for each row and cell it creates. It will remain scrolled to the row scrolled to prior to the addition of rows, and focus will remain in the row which had focus prior to the addition of the rows. .SH "SEE ALSO" XmLGrid(3X) XmLGridAddColumns(3X) nedit-5.6.orig/Microline/man/XmLGridColumnIsVisible.3x0000644000175000017500000000573610077552126021400 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridColumnIsVisible 3X "R1" "XML1" "XML" .SH NAME XmLGridColumnIsVisible \- determine visiblily of a content column .SH SYNTAX void XmLGridColumnIsVisible(\fIwidget\fP, \fIcolumn\fP) .br Widget \fIwidget\fP; .br int \fIcolumn\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIcolumn\fP 1i position of content column .SH DESCRIPTION Determines visibility of a content column. .SH RETURN VALUE Returns True if any part of the content column given is visible to the user, and False otherwise. .SH "SEE ALSO" XmLGrid(3X) XmLGridRowIsVisible(3X) nedit-5.6.orig/Microline/man/XmLGridCopyPos.3x0000644000175000017500000000727210077552126017722 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridCopyPos 3X "R1" "XML1" "XML" .SH NAME XmLGridCopyPos \- copy the string contents of cells in a Grid at a given location to the clipboard .SH SYNTAX Boolean XmLGridCopyPos(\fIwidget\fP, \fItime\fP, \fIrowType\fP, \fIrow\fP, \ \fIcolumnType\fP, \fIcolumn\fP, \fInrow\fP, \fIncolumn\fP) .br Widget \fIwidget\fP; .br Time \fItime\fP; .br unsigned char \fIrowType\fP; .br int \fIrow\fP; .br unsigned char \fIcolumnType\fP; .br int \fIcolumn\fP; .br int \fInrow\fP; .br int \fIncolumn\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fItime\fP 1i Time of event .IP \fIrowType\fP 1i type of first row .IP \fIrow\fP 1i location of first row .IP \fIcolumnType\fP 1i type of first column .IP \fIcolumn\fP 1i location of first column .IP \fInrow\fP 1i number of rows .IP \fIncolumn\fP 1i number of columns .SH DESCRIPTION Copies the contents of cells in \fInrow\fP number of rows and \fIncolumn\fP number of columns to the clipboard starting at the row and column specified by \fIrowType\fP, \fIrow\fP, \fIcolumnType\fP, and \fIcolumn\fP. The \fItime\fP parameter should be set to the time of the event (most likely CurrentTime). .SH RETURN VALUE A value of True is returned upon success, and False is returned upon failure. .SH "SEE ALSO" XmLGridCopySelected(3X) XmLGridPaste(3X) nedit-5.6.orig/Microline/man/XmLGridCopySelected.3x0000644000175000017500000000607010077552126020704 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridCopySelected 3X "R1" "XML1" "XML" .SH NAME XmLGridCopySelected \- copy the string contents of selected cells in a Grid to the clipboard .SH SYNTAX Boolean XmLGridCopySelected(\fIwidget\fP, \fItime\fP) .br Widget \fIwidget\fP; .br Time \fItime\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fItime\fP 1i Time of event .SH DESCRIPTION Copies the contents any selected cells in a Grid to the clipboard. The \fItime\fP parameter should be set to the time of the event (most likely CurrentTime). .SH RETURN VALUE True is returned upon success, and False is returned upon failure. .SH "SEE ALSO" XmLGridCopyPos(3X) XmLGridPaste(3X) nedit-5.6.orig/Microline/man/XmLGridDeleteAllColumns.3x0000644000175000017500000000663210077552126021521 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridDeleteAllColumns 3X "R1" "XML1" "XML" .SH NAME XmLGridDeleteAllColumns \- delete all columns of a given type .SH SYNTAX void XmLGridDeleteAllColumns(\fIwidget\fP, \fItype\fP) .br Widget \fIwidget\fP; .br unsigned char \fItype\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fItype\fP 1i type of column .SH DESCRIPTION Deletes all columns of the given type. The Grid will call its XmNdeleteCallback callbacks for each column and cell deleted. If possible, the focus will remain in the column which had focus prior to the deletion of columns. If the cell which has focus is in one of the columns deleted, the Grid's XmNcellFocusCallback callbacks will be called with a reason of XmCR_CELL_FOCUS_OUT before that column is deleted. If a cell in one of the columns is currently being edited, the Grid's XmNeditCallback callbacks will be called with a reason of XmCR_EDIT_CANCEL before that column is deleted. .SH "SEE ALSO" XmLGrid(3X) XmLGridDeleteColumns(3X) XmLGridDeleteAllRows(3X) nedit-5.6.orig/Microline/man/XmLGridDeleteAllRows.3x0000644000175000017500000000656310077552126021036 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridDeleteAllRows 3X "R1" "XML1" "XML" .SH NAME XmLGridDeleteAllRows \- delete all rows of a given type .SH SYNTAX void XmLGridDeleteAllRows(\fIwidget\fP, \fItype\fP) .br Widget \fIwidget\fP; .br unsigned char \fItype\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fItype\fP 1i type of row .SH DESCRIPTION Deletes all rows of the given type. The Grid will call its XmNdeleteCallback callbacks for each row and cell deleted. If possible, the focus will remain in the row which had focus prior to the deletion of rows. If the cell which has focus is in one of the rows deleted, the Grid's XmNcellFocusCallback callbacks will be called with a reason of XmCR_CELL_FOCUS_OUT before that row is deleted. If a cell in one of the rows is currently being edited, the Grid's XmNeditCallback callbacks will be called with a reason of XmCR_EDIT_CANCEL before that row is deleted. .SH "SEE ALSO" XmLGrid(3X) XmLGridDeleteRows(3X) XmLGridDeleteAllColumns(3X) nedit-5.6.orig/Microline/man/XmLGridDeleteColumns.3x0000644000175000017500000000721510077552126021066 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridDeleteColumns 3X "R1" "XML1" "XML" .SH NAME XmLGridDeleteColumns \- delete columns in a Grid .SH SYNTAX void XmLGridDeleteColumns(\fIwidget\fP, \fItype\fP, \ \fIposition\fP, \fIcount\fP) .br Widget \fIwidget\fP; .br unsigned char \fItype\fP; .br int \fIposition\fP; .br int \fIcount\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fItype\fP 1i type of column .IP \fIposition\fP 1i position of first column .IP \fIcount\fP 1i number of columns to delete .SH DESCRIPTION Deletes \fIcount\fP columns of the given \fItype\fP in the Grid at the specified \fIposition\fP. A position of 0 indicates the first column of the given type. The Grid will call its XmNdeleteCallback callbacks for each column and cell deleted. If possible, the focus will remain in the column which had focus prior to the deletion of columns. If the cell which has focus is in one of the columns deleted, the Grid's XmNcellFocusCallback callbacks will be called with a reason of XmCR_CELL_FOCUS_OUT before that column is deleted. If a cell in one of the columns is currently being edited, the Grid's XmNeditCallback callbacks will be called with a reason of XmCR_EDIT_CANCEL before that column is deleted. .SH "SEE ALSO" XmLGrid(3X) XmLGridDeleteRows(3X) nedit-5.6.orig/Microline/man/XmLGridDeleteRows.3x0000644000175000017500000000714010077552126020375 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridDeleteRows 3X "R1" "XML1" "XML" .SH NAME XmLGridDeleteRows \- delete rows in a Grid .SH SYNTAX void XmLGridDeleteRows(\fIwidget\fP, \fItype\fP, \ \fIposition\fP, \fIcount\fP) .br Widget \fIwidget\fP; .br unsigned char \fItype\fP; .br int \fIposition\fP; .br int \fIcount\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fItype\fP 1i type of row .IP \fIposition\fP 1i position of first row .IP \fIcount\fP 1i number of rows to delete .SH DESCRIPTION Deletes \fIcount\fP rows of the given \fItype\fP in the Grid at the specified \fIposition\fP. A position of 0 indicates the first row of the given type. The Grid will call its XmNdeleteCallback callbacks for each row and cell deleted. If possible, the focus will remain in the row which had focus prior to the deletion of rows. If the cell which has focus is in one of the rows deleted, the Grid's XmNcellFocusCallback callbacks will be called with a reason of XmCR_CELL_FOCUS_OUT before that row is deleted. If a cell in one of the rows is currently being edited, the Grid's XmNeditCallback callbacks will be called with a reason of XmCR_EDIT_CANCEL before that row is deleted. .SH "SEE ALSO" XmLGrid(3X) XmLGridDeleteColumns(3X) nedit-5.6.orig/Microline/man/XmLGridDeselectAllCells.3x0000644000175000017500000000576310077552126021475 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridDeselectAllCells 3X "R1" "XML1" "XML" .SH NAME XmLGridDeselectAllCells \- deselect all content cells .SH SYNTAX void XmLGridDeselectAllCells(\fIwidget\fP, \fInotify\fP) .br Widget \fIwidget\fP; .br Boolean \fInotify\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fInotify\fP 1i if True, deselect callbacks will be called .SH DESCRIPTION Deselects all content cells in the Grid. If \fInotify\fP is True, the Grid's XmNdeselectCallback callbacks will be called for each cell deselected. .SH "SEE ALSO" XmLGridDeselectAllRows(3X) XmLGridDeselectAllColumns(3X) nedit-5.6.orig/Microline/man/XmLGridDeselectAllColumns.3x0000644000175000017500000000577510077552126022056 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridDeselectAllColumns 3X "R1" "XML1" "XML" .SH NAME XmLGridDeselectAllColumns \- deselect all content columns .SH SYNTAX void XmLGridDeselectAllColumns(\fIwidget\fP, \fInotify\fP) .br Widget \fIwidget\fP; .br Boolean \fInotify\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fInotify\fP 1i if True, deselect callbacks will be called .SH DESCRIPTION Deselects all content columns in the Grid. If \fInotify\fP is True, the Grid's XmNdeselectCallback callbacks will be called for each column deselected. .SH "SEE ALSO" XmLGridDeselectAllCells(3X) XmLGridDeselectAllRows(3X) nedit-5.6.orig/Microline/man/XmLGridDeselectAllRows.3x0000644000175000017500000000575610077552126021367 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridDeselectAllRows 3X "R1" "XML1" "XML" .SH NAME XmLGridDeselectAllRows \- deselect all content rows .SH SYNTAX void XmLGridDeselectAllRows(\fIwidget\fP, \fInotify\fP) .br Widget \fIwidget\fP; .br Boolean \fInotify\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fInotify\fP 1i if True, deselect callbacks will be called .SH DESCRIPTION Deselects all content rows in the Grid. If \fInotify\fP is True, the Grid's XmNdeselectCallback callbacks will be called for each row deselected. .SH "SEE ALSO" XmLGridDeselectAllCells(3X) XmLGridDeselectAllColumns(3X) nedit-5.6.orig/Microline/man/XmLGridDeselectCell.3x0000644000175000017500000000631210077552126020650 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridDeselectCell 3X "R1" "XML1" "XML" .SH NAME XmLGridDeselectCell \- deselect a cell .SH SYNTAX void XmLGridDeselectCell(\fIwidget\fP, \fIrow\fP, \ \fIcolumn\fP, \fInotify\fP) .br Widget \fIwidget\fP; .br int \fIrow\fP; .br int \fIcolumn\fP; .br Boolean \fInotify\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIrow\fP 1i position of content row .IP \fIcolumn\fP 1i position of content column .IP \fInotify\fP 1i if True, deselect callbacks will be called .SH DESCRIPTION Deselects the cell in the Grid at the content \fIrow\fP and content \fIcolumn\fP specified. If \fInotify\fP is True and the cell is currently selected, the Grid's XmNdeselectCallback callbacks will be called. .SH "SEE ALSO" XmLGridDeselectAllCells(3X) XmLGridDeselectRow(3X) XmLGridDeselectColumn(3X) nedit-5.6.orig/Microline/man/XmLGridDeselectColumn.3x0000644000175000017500000000607110077552126021230 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridDeselectColumn 3X "R1" "XML1" "XML" .SH NAME XmLGridDeselectColumn \- deselect a column .SH SYNTAX void XmLGridDeselectColumn(\fIwidget\fP, \fIcolumn\fP, \fInotify\fP) .br Widget \fIwidget\fP; .br int \fIcolumn\fP; .br Boolean \fInotify\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIcolumn\fP 1i position of content column .IP \fInotify\fP 1i if True, deselect callbacks will be called .SH DESCRIPTION Deselects the specified content \fIcolumn\fP in the Grid. If \fInotify\fP is True and the column is currently selected, the Grid's XmNdeselectCallback callbacks will be called. .SH "SEE ALSO" XmLGridDeselectAllColumns(3X) nedit-5.6.orig/Microline/man/XmLGridDeselectRow.3x0000644000175000017500000000603010077552126020535 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridDeselectRow 3X "R1" "XML1" "XML" .SH NAME XmLGridDeselectRow \- deselect a row .SH SYNTAX void XmLGridDeselectRow(\fIwidget\fP, \fIrow\fP, \fInotify\fP) .br Widget \fIwidget\fP; .br int \fIrow\fP; .br Boolean \fInotify\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIrow\fP 1i position of content row .IP \fInotify\fP 1i if True, deselect callbacks will be called .SH DESCRIPTION Deselects the specified content \fIrow\fP in the Grid. If \fInotify\fP is True and the row is currently selected, the Grid's XmNdeselectCallback callbacks will be called. .SH "SEE ALSO" XmLGridDeselectAllRows(3X) nedit-5.6.orig/Microline/man/XmLGridEditBegin.3x0000644000175000017500000000671110077552126020155 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridEditBegin 3X "R1" "XML1" "XML" .SH NAME XmLGridEditBegin \- begin an edit in a cell .SH SYNTAX int XmLGridEditBegin(\fIwidget\fP, \fIinsert\fP, \fIrow\fP, \fIcolumn\fP) .br Widget \fIwidget\fP; .br Boolean \fIinsert\fP; .br int \fIrow\fP; .br int \fIcolumn\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIinsert\fP 1i insert flag .IP \fIrow\fP 1i position of content row .IP \fIcolumn\fP 1i position of content column .SH DESCRIPTION Begin editing a cell at the given content \fIrow\fP and content \fIcolumn\fP. If \fIinsert\fP is True, the edit will begin with the text widget containing the existing cell contents. If False, the text widget child of the Grid will be cleared when the edit begins. If the function is successful, the Grid's XmNeditCallback callbacks will be called. .SH RETURN VALUE If the cell position specified is invalid or the cell can not be edited, a value of -1 will be returned. A value of 0 is returned if this function is successful. .SH "SEE ALSO" XmLGridEditCancel(3X) XmLGridEditComplete(3X) nedit-5.6.orig/Microline/man/XmLGridEditCancel.3x0000644000175000017500000000556310077552126020322 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridEditCancel 3X "R1" "XML1" "XML" .SH NAME XmLGridEditCancel \- cancel any cell edit in progress .SH SYNTAX void XmLGridEditCancel(\fIwidget\fP) .br Widget \fIwidget\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .SH DESCRIPTION Cancels a cell edit which is in progress. If a cell is being edited, the Grid's XmNeditCallbacks will be called with a reason of XmCR_EDIT_CANCEL. .SH "SEE ALSO" XmLGridEditBegin(3X) XmLGridEditComplete(3X) nedit-5.6.orig/Microline/man/XmLGridEditComplete.3x0000644000175000017500000000556010077552126020702 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridEditComplete 3X "R1" "XML1" "XML" .SH NAME XmLGridEditComplete \- completes a cell edit .SH SYNTAX void XmLGridEditComplete(\fIwidget\fP) .br Widget \fIwidget\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .SH DESCRIPTION Completes a cell edit which is in progress. If a cell is being edited, the Grid's XmNeditCallbacks will be called with a reason of XmCR_EDIT_COMPLETE. .SH "SEE ALSO" XmLGridEditBegin(3X) XmLGridEditCancel(3X) nedit-5.6.orig/Microline/man/XmLGridGetColumn.3x0000644000175000017500000000613610077552126020221 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridGetColumn 3X "R1" "XML1" "XML" .SH NAME XmLGridGetColumn \- return a pointer to a column .SH SYNTAX XmLGridColumn XmLGridGetColumn(\fIwidget\fP, \fItype\fP, \fIcolumn\fP) .br Widget \fIwidget\fP; .br unsigned char \fItype\fP; .br int \fIcolumn\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fItype\fP 1i type of column .IP \fIcolumn\fP 1i position of column .SH DESCRIPTION Returns a pointer to the column at position \fIcolumn\fP of type \fItype\fP. This pointer can be used in a GetValues call to retrieve values for the column. .SH RETURN VALUE A pointer to the column at the given location or NULL if the column position is invalid. .SH "SEE ALSO" XmLGrid(3X) nedit-5.6.orig/Microline/man/XmLGridGetFocus.3x0000644000175000017500000000635610077552126020047 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridGetFocus 3X "R1" "XML1" "XML" .SH NAME XmLGridGetFocus \- return the position of the current focus cell in a Grid .SH SYNTAX void XmLGridGetFocus(\fIwidget\fP, \fIrow\fP, \ \fIcolumn\fP, \fIfocusIn\fP) .br Widget \fIwidget\fP; .br int *\fIrow\fP; .br int *\fIcolumn\fP; .br Boolean *\fIfocusIn\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIrow\fP 1i position of content row .IP \fIcolumn\fP 1i position of content column .IP \fIfocusIn\fP 1i True if focus is in widget .SH DESCRIPTION Returns the content \fIrow\fP and content \fIcolumn\fP which currently has focus. If focus is currently in the Grid, \fIfocusIn\fP will be set to True. Otherwise, it will be set to False. The row or column returned may be set to -1 which indicates that no cell in the Grid has focus. .SH "SEE ALSO" XmLGridSetFocus(3X) nedit-5.6.orig/Microline/man/XmLGridGetRow.3x0000644000175000017500000000606110077552126017530 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridGetRow 3X "R1" "XML1" "XML" .SH NAME XmLGridGetRow \- return a pointer to a row .SH SYNTAX XmLGridRow XmLGridGetRow(\fIwidget\fP, \fItype\fP, \fIrow\fP) .br Widget \fIwidget\fP; .br unsigned char \fItype\fP; .br int \fIrow\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fItype\fP 1i type of row .IP \fIrow\fP 1i position of row .SH DESCRIPTION Returns a pointer to the row at position \fIrow\fP of type \fItype\fP. This pointer can be used in a GetValues call to retrieve values for the row. .SH RETURN VALUE A pointer to the row at the given location or NULL if the row position is invalid. .SH "SEE ALSO" XmLGrid(3X) nedit-5.6.orig/Microline/man/XmLGridGetSelectedCellCount.3x0000644000175000017500000000565410077552126022331 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridGetSelectedCellCount 3X "R1" "XML1" "XML" .SH NAME XmLGridGetSelectedCellCount \- return number of currently selected cells .SH SYNTAX int XmLGridGetSelectedCellCount(\fIwidget\fP) .br Widget \fIwidget\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .SH DESCRIPTION Returns the number of currently selected cells. Only cells in content rows and columns may be selected. .SH RETURN VALUE The number of currently selected cells. .SH "SEE ALSO" XmLGridGetSelectedCells(3X) XmLGridSelectCell(3X) nedit-5.6.orig/Microline/man/XmLGridGetSelectedCells.3x0000644000175000017500000000744210077552126021500 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridGetSelectedCells 3X "R1" "XML1" "XML" .SH NAME XmLGridGetSelectedCells \- retrieve positions of currently selected cells .SH SYNTAX int XmLGridGetSelectedCells(\fIwidget\fP, \fIrowPositions\fP, \ \fIcolumnPositions\fP, \fIcount\fP) .br Widget \fIwidget\fP; .br int *\fIrowPositions\fP; .br int *\fIcolumnPositions\fP; .br int \fIcount\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIrowPositions\fP 1i position of content rows .IP \fIcolumnPositions\fP 1i positions of content columns .IP \fIcount\fP 1i number of position pairs .SH DESCRIPTION Returns the row and column positions of the currently selected cells. The \fIcount\fP value passed to this function must equal the number of currently selected cells. The number of currently selected cells can be found by calling XmLGridGetSelectedCellCount(). The \fIrowPositions\fP and \fIcolumnPositions\fP arrays must be allocated before calling this function and must have enough space to hold the positions which will be returned. This function does not allocate memory; it is the application's responsibility to allocate and deallocate the space used to hold the row and column positions. .SH RETURN VALUE 0 is returned upon successful completion. A value of -1 is returned and an error message is generated if count does not equal the number of currently selected cells. .SH "SEE ALSO" XmLGridGetSelectedCellCount(3X) nedit-5.6.orig/Microline/man/XmLGridGetSelectedColumnCount.3x0000644000175000017500000000565210077552126022705 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridGetSelectedColumnCount 3X "R1" "XML1" "XML" .SH NAME XmLGridGetSelectedColumnCount \- return number of currently selected columns .SH SYNTAX int XmLGridGetSelectedColumnCount(\fIwidget\fP) .br Widget \fIwidget\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .SH DESCRIPTION Returns the number of currently selected columns. Only content columns may be selected. .SH RETURN VALUE The number of currently selected columns. .SH "SEE ALSO" XmLGridGetSelectedColumns(3X) XmLGridSelectColumn(3X) nedit-5.6.orig/Microline/man/XmLGridGetSelectedColumns.3x0000644000175000017500000000722510077552126022055 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridGetSelectedColumns 3X "R1" "XML1" "XML" .SH NAME XmLGridGetSelectedColumns \- retrieve positions of currently selected columns .SH SYNTAX int XmLGridGetSelectedColumns(\fIwidget\fP, \fIpositions\fP, \fIcount\fP) .br Widget \fIwidget\fP; .br int *\fIpositions\fP; .br int \fIcount\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIpositions\fP 1i positions of content columns .IP \fIcount\fP 1i number of positions .SH DESCRIPTION Returns the \fIpositions\fP of the currently selected content columns. The \fIcount\fP value passed to this function must equal the number of currently selected columns. The number of currently selected columns can be found by calling XmLGridGetSelectedColumnCount(). The column positions arrays must be allocated before calling this function and must have enough space to hold the positions which will be returned. This function does not allocate memory; it is the application's responsibility to allocate and deallocate the space used to hold the column positions. .SH RETURN VALUE 0 is returned upon successful completion. A value of -1 is returned and an error message is generated if count does not equal the number of currently selected columns. .SH "SEE ALSO" XmLGridGetSelectedColumnCount(3X) nedit-5.6.orig/Microline/man/XmLGridGetSelectedRow.3x0000644000175000017500000000600110077552126021173 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridGetSelectedRow 3X "R1" "XML1" "XML" .SH NAME XmLGridGetSelectedRow \- retrieve position of the currently selected row .SH SYNTAX int XmLGridGetSelectedRow(\fIwidget\fP) .br Widget \fIwidget\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .SH DESCRIPTION When XmNselectionPolicy is XmSELECT_SINGLE_ROW or XmSELECT_BROWSE_ROW, this function returns the content row position of the currently selected row or -1 if no row is selected. .SH RETURN VALUE The content row position of the currently selected row or -1 if no row is is selected. .SH "SEE ALSO" XmLGridGetSelectedRows(3X) nedit-5.6.orig/Microline/man/XmLGridGetSelectedRowCount.3x0000644000175000017500000000561710077552126022220 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridGetSelectedRowCount 3X "R1" "XML1" "XML" .SH NAME XmLGridGetSelectedRowCount \- return number of currently selected rows .SH SYNTAX int XmLGridGetSelectedRowCount(\fIwidget\fP) .br Widget \fIwidget\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .SH DESCRIPTION Returns the number of currently selected rows. Only content rows may be selected. .SH RETURN VALUE The number of currently selected rows. .SH "SEE ALSO" XmLGridGetSelectedRows(3X) XmLGridSelectRow(3X) nedit-5.6.orig/Microline/man/XmLGridGetSelectedRows.3x0000644000175000017500000000715610077552126021372 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridGetSelectedRows 3X "R1" "XML1" "XML" .SH NAME XmLGridGetSelectedRows \- retrieve positions of currently selected rows .SH SYNTAX int XmLGridGetSelectedRows(\fIwidget\fP, \fIpositions\fP, \fIcount\fP) .br Widget \fIwidget\fP; .br int *\fIpositions\fP; .br int \fIcount\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIpositions\fP 1i positions of content rows .IP \fIcount\fP 1i number of positions .SH DESCRIPTION Returns the \fIpositions\fP of the currently selected content rows. The \fIcount\fP value passed to this function must equal the number of currently selected rows. The number of currently selected rows can be found by calling XmLGridGetSelectedRowCount(). The row positions arrays must be allocated before calling this function and must have enough space to hold the positions which will be returned. This function does not allocate memory; it is the application's responsibility to allocate and deallocate the space used to hold the row positions. .SH RETURN VALUE 0 is returned upon successful completion. A value of -1 is returned and an error message is generated if count does not equal the number of currently selected rows. .SH "SEE ALSO" XmLGridGetSelectedRowCount(3X) nedit-5.6.orig/Microline/man/XmLGridMoveColumns.3x0000644000175000017500000000610410077552126020566 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridMoveColumns 3X "R1" "XML1" "XML" .SH NAME XmLGridMoveColumns \- move columns to a new location .SH SYNTAX void XmLGridMoveColumns(\fIwidget\fP, \fInewPosition\fP, \ \fIposition\fP, \fIcount\fP) .br Widget \fIwidget\fP; .br int \fInewPosition\fP; .br int \fIposition\fP; .br int \fIcount\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fInewPosition\fP 1i first position of content columns to move to .IP \fIposition\fP 1i first position of content columns to move from .IP \fIcount\fP 1i number of columns to move .SH DESCRIPTION Moves \fIcount\fP content columns at \fIposition\fP to \fInewPosition\fP. .SH "SEE ALSO" XmLGridMoveRows(3X) nedit-5.6.orig/Microline/man/XmLGridMoveRows.3x0000644000175000017500000000605710077552126020107 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridMoveRows 3X "R1" "XML1" "XML" .SH NAME XmLGridMoveRows \- move rows to a new location .SH SYNTAX void XmLGridMoveRows(\fIwidget\fP, \fInewPosition\fP, \ \fIposition\fP, \fIcount\fP) .br Widget \fIwidget\fP; .br int \fInewPosition\fP; .br int \fIposition\fP; .br int \fIcount\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fInewPosition\fP 1i first position of content rows to move to .IP \fIposition\fP 1i first position of content rows to move from .IP \fIcount\fP 1i number of rows to move .SH DESCRIPTION Moves \fIcount\fP content rows at \fIposition\fP to \fInewPosition\fP. .SH "SEE ALSO" XmLGridMoveColumns(3X) nedit-5.6.orig/Microline/man/XmLGridPaste.3x0000644000175000017500000000575410077552126017405 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridPaste 3X "R1" "XML1" "XML" .SH NAME XmLGridPaste \- paste cell contents from the clipboard into a Grid .SH SYNTAX Boolean XmLGridPaste(\fIwidget\fP) .br Widget \fIwidget\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .SH DESCRIPTION Pastes cell contents (strings) from the clipboard into a Grid starting at the current focus location. This function does not invoke any callbacks. .SH RETURN VALUE A value of True is returned upon success, and False is returned upon failure. .SH "SEE ALSO" XmLGridCopyPos(3X) XmLGridCopySelected(3X) cXmLGridPastePos(3X) nedit-5.6.orig/Microline/man/XmLGridPastePos.3x0000644000175000017500000000666710077552126020073 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridPastePos 3X "R1" "XML1" "XML" .SH NAME XmLGridPastePos \- paste cell contents from the clipboard into a Grid at a specified location .SH SYNTAX Boolean XmLGridPastePos(\fIwidget\fP, \fIrowType\fP, \fIrow\fP, \fIcolumnType\fP, \fIcolumn\fP) .br Widget \fIwidget\fP; .br unsigned char \fIrowType\fP; .br int \fIrow\fP; .br unsigned char \fIcolumnType\fP; .br int \fIcolumn\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIrowType\fP 1i type of first row location .IP \fIrow\fP 1i location of first row .IP \fIcolumnType\fP 1i type of first column location .IP \fIcolumn\fP 1i location of first column .SH DESCRIPTION Pastes cell contents (strings) from the clipboard into a Grid starting at the row and column specified by the given \fIrowType\fP, \fIrow\fP, \fIcolumnType\fP, and \fIcolumn\fP. This function does not invoke any callbacks. .SH RETURN VALUE A value of True is returned upon success, and False is returned upon failure. .SH "SEE ALSO" XmLGridCopyPos(3X) XmLGridCopySelected(3X) XmLGridPaste(3X) nedit-5.6.orig/Microline/man/XmLGridRead.3x0000644000175000017500000000672010077552126017176 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridRead 3X "R1" "XML1" "XML" .SH NAME XmLGridRead \- import data from a file into a Grid .SH SYNTAX int XmLGridRead(\fIwidget\fP, \fIfile\fP, \fIformat\fP, \fIdelimiter\fP) .br Widget \fIwidget\fP; .br FILE *\fIfile\fP; .br int \fIformat\fP; .br char \fIdelimiter\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIfile\fP 1i file to read from .IP \fIformat\fP 1i format of the file .IP \fIdelimiter\fP 1i delimiter if format is XmFORMAT_DELIMITED .SH DESCRIPTION Imports data from a \fIfile\fP in a given \fIformat\fP into a Grid starting at the top, left-most cell. Format must be either XmFORMAT_XL, where tabs separate columns and cell data is possibly surrounded by double-quotes, or XmFORMAT_DELIMITED, where data is delimited by the \fIdelimiter\fP given. In either case, a new-line signifies a new row. The rows and columns imported into must exist at the time of this call. This function does not invoke any callbacks. .SH RETURN VALUE The number of cells which had values set by this function. .SH "SEE ALSO" XmLGridReadPos(3X) nedit-5.6.orig/Microline/man/XmLGridReadPos.3x0000644000175000017500000000764110077552126017663 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridReadPos 3X "R1" "XML1" "XML" .SH NAME XmLGridReadPos \- import data from a file to a specified location in a Grid .SH SYNTAX int XmLGridReadPos(\fIwidget\fP, \fIfile\fP, \fIformat\fP, \ \fIdelimiter\fP, \fIrowType\fP, \fIrow\fP, \fIcolumnType\fP, \fIcolumn\fP) .br Widget \fIwidget\fP; .br FILE *\fIfile\fP; .br int \fIformat\fP; .br char \fIdelimiter\fP; .br unsigned char \fIrowType\fP; .br int \fIrow\fP; .br unsigned char \fIcolumnType\fP; .br int \fIcolumn\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIfile\fP 1i file to read from .IP \fIformat\fP 1i format of the file .IP \fIdelimiter\fP 1i delimiter if format is XmFORMAT_DELIMITED .IP \fIrowType\fP 1i type of first row location .IP \fIrow\fP 1i location of first row .IP \fIcolumnType\fP 1i type of first column location .IP \fIcolumn\fP 1i location of first column .SH DESCRIPTION Imports data from a \fIfile\fP in a given \fIformat\fP into the Grid starting at the row and column specified by the given \fIrowType\fP, \fIrow\fP, \fIcolumnType\fP, and \fIcolumn\fP. Format must be either XmFORMAT_XL, where tabs separate columns and cell data is possibly surrounded by double-quotes, or XmFORMAT_DELIMITED, where data is delimited by the \fIdelimiter\fP given. In either case, a new-line signifies a new row. The rows and columns imported into must exist at the time of this call. This function does not invoke any callbacks. .SH RETURN VALUE The number of cells which had values set by this function. .SH "SEE ALSO" XmLGridRead(3X) nedit-5.6.orig/Microline/man/XmLGridRedrawAll.3x0000644000175000017500000000557110077552126020203 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridRedrawAll 3X "R1" "XML1" "XML" .SH NAME XmLGridRedrawAll \- redraw all cells in a Grid .SH SYNTAX void XmLGridRedrawAll(\fIwidget\fP) .br Widget \fIwidget\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .SH DESCRIPTION Redraws all the cells in a Grid. This function is normally only used to redraw a Grid which performs drawing using an XmNcellDrawCallback. .SH "SEE ALSO" XmLGridRedrawCell(3X) XmLGridRedrawRow(3X) XmLGridRedrawColumn(3X) nedit-5.6.orig/Microline/man/XmLGridRedrawCell.3x0000644000175000017500000000636210077552126020351 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridRedrawCell 3X "R1" "XML1" "XML" .SH NAME XmLGridRedrawCell \- redraw a cell .SH SYNTAX void XmLGridRedrawCell(\fIwidget\fP, \fIrowType\fP, \fIrow\fP, \ \fIcolumnType\fP, \fIcolumn\fP) .br Widget \fIwidget\fP; .br unsigned char \fIrowType\fP; .br int \fIrow\fP; .br unsigned char \fIcolumnType\fP; .br int \fIcolumn\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIrowType\fP 1i type of row .IP \fIrow\fP 1i position of row .IP \fIcolumnType\fP 1i type of column .IP \fIcolumn\fP 1i position of column .SH DESCRIPTION Redraws the cell at the \fIcolumn\fP of type \fIcolumnType\fP and \fIrow\fP of type \fIrowType\fP. This function is normally only used to redraw areas in a Grid which perform drawing using an XmNcellDrawCallback. .SH "SEE ALSO" XmLGridRedrawAll(3X) XmLGridRedrawRow(3X) XmLGridRedrawColumn(3X) nedit-5.6.orig/Microline/man/XmLGridRedrawColumn.3x0000644000175000017500000000606010077552126020722 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridRedrawColumn 3X "R1" "XML1" "XML" .SH NAME XmLGridRedrawColumn \- redraw a column .SH SYNTAX void XmLGridRedrawColumn(\fIwidget\fP, \fItype\fP, \fIcolumn\fP) .br Widget \fIwidget\fP; .br unsigned char \fItype\fP; .br int \fIcolumn\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fItype\fP 1i type of column .IP \fIcolumn\fP 1i position of column .SH DESCRIPTION Redraws the column at position \fIcolumn\fP of type \fItype\fP. This function is normally only used to redraw areas in a Grid which perform drawing using an XmNcellDrawCallback. .SH "SEE ALSO" XmLGridRedrawAll(3X) XmLGridRedrawCell(3X) XmLGridRedrawRow(3X) nedit-5.6.orig/Microline/man/XmLGridRedrawRow.3x0000644000175000017500000000602210077552126020232 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridRedrawRow 3X "R1" "XML1" "XML" .SH NAME XmLGridRedrawRow \- redraw a row .SH SYNTAX void XmLGridRedrawRow(\fIwidget\fP, \fItype\fP, \fIrow\fP) .br Widget \fIwidget\fP; .br unsigned char \fItype\fP; .br int \fIrow\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fItype\fP 1i type of row .IP \fIrow\fP 1i position of row .SH DESCRIPTION Redraws the row at position \fIrow\fP of type \fItype\fP. This function is normally only used to redraw areas in a Grid which perform drawing using an XmNcellDrawCallback. .SH "SEE ALSO" XmLGridRedrawAll(3X) XmLGridRedrawCell(3X) XmLGridRedrawColumn(3X) nedit-5.6.orig/Microline/man/XmLGridReorderColumns.3x0000644000175000017500000000620610077552126021265 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridReorderColumns 3X "R1" "XML1" "XML" .SH NAME XmLGridReorderColumns \- reorder columns in a Grid .SH SYNTAX void XmLGridReorderColumns(\fIwidget\fP, \fInewPositions\fP, \ \fIposition\fP, \fIcount\fP) .br Widget \fIwidget\fP; .br int *\fInewPositions\fP; .br int \fIposition\fP; .br int \fIcount\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fInewPositions\fP 1i new positions of content columns .IP \fIposition\fP 1i first position of content columns to reorder .IP \fIcount\fP 1i number of columns to reorder .SH DESCRIPTION Changes the positions of \fIcount\fP content columns starting at \fIposition\fP to the positions specified in the \fInewPositions\fP array. .SH "SEE ALSO" XmLGridReorderRows(3X) nedit-5.6.orig/Microline/man/XmLGridReorderRows.3x0000644000175000017500000000616110077552126020577 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridReorderRows 3X "R1" "XML1" "XML" .SH NAME XmLGridReorderRows \- reorder rows in a Grid .SH SYNTAX void XmLGridReorderRows(\fIwidget\fP, \fInewPositions\fP, \ \fIposition\fP, \fIcount\fP) .br Widget \fIwidget\fP; .br int *\fInewPositions\fP; .br int \fIposition\fP; .br int \fIcount\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fInewPositions\fP 1i new positions of content rows .IP \fIposition\fP 1i first position of content rows to reorder .IP \fIcount\fP 1i number of rows to reorder .SH DESCRIPTION Changes the positions of \fIcount\fP content rows starting at \fIposition\fP to the positions specified in the \fInewPositions\fP array. .SH "SEE ALSO" XmLGridReorderColumns(3X) nedit-5.6.orig/Microline/man/XmLGridRowColumnToXY.3x0000644000175000017500000000757710077552126021047 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridRowColumnToXY 3X "R1" "XML1" "XML" .SH NAME XmLGridRowColumnToXY \- return coordinates of a cell .SH SYNTAX int XmLGridRowColumnToXY(\fIwidget\fP, \fIrowType\fP, \fIrow\fP, \ \fIcolumnType\fP, \fIcolumn\fP, \fIclipped\fP, \fIrect\fP) .br Widget \fIwidget\fP; .br unsigned char \fIrowType\fP; .br int \fIrow\fP; .br unsigned char \fIcolumnType\fP; .br int \fIcolumn\fP; .br Boolean \fIclipped\fP; .br XRectangle *\fIrect\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIrowType\fP 1i type of row .IP \fIrow\fP 1i position of row .IP \fIcolumnType\fP 1i type of column .IP \fIcolumn\fP 1i position of column .IP \fIclipped\fP 1i return clipped or unclipped coordinates .IP \fIrect\fP 1i cell geometry .SH DESCRIPTION Returns the current coordinates of the cell specified by the \fIrow\fP of type \fIrowType\fP and \fIcolumn\fP of type \fIcolumnType\fP in the rectangle \fIrect\fP. If \fIclipped\fP is True, the rectangle returned will be the cell's rectangle clipped to the current viewing area. If \fIclipped\fP is False, the rectangle returned will be the cell's unclipped rectangle, a rectangle with the full width and height of the cell, not clipped to the viewport. The unclipped cell rectangle is usually used to determine positioning based on cell alignment. .SH RETURN VALUE 0 is returned upon success, and a value of -1 is returned if the row and column position is invalid or if the cell is currently not visible. .SH "SEE ALSO" XmLGridXYToRowColumn(3X) nedit-5.6.orig/Microline/man/XmLGridRowIsVisible.3x0000644000175000017500000000570310077552126020704 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridRowIsVisible 3X "R1" "XML1" "XML" .SH NAME XmLGridRowIsVisible \- determine visiblily of a content row .SH SYNTAX void XmLGridRowIsVisible(\fIwidget\fP, \fIrow\fP) .br Widget \fIwidget\fP; .br int \fIrow\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIrow\fP 1i position of content row .SH DESCRIPTION Determines visibility of a content row. .SH RETURN VALUE Returns True if any part of the content row given is visible to the user, and False otherwise. .SH "SEE ALSO" XmLGrid(3X) XmLGridColumnIsVisible(3X) nedit-5.6.orig/Microline/man/XmLGridSelectAllCells.3x0000644000175000017500000000573710077552126021165 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridSelectAllCells 3X "R1" "XML1" "XML" .SH NAME XmLGridSelectAllCells \- select all content cells .SH SYNTAX void XmLGridSelectAllCells(\fIwidget\fP, \fInotify\fP) .br Widget \fIwidget\fP; .br Boolean \fInotify\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fInotify\fP 1i if True, select callbacks will be called .SH DESCRIPTION Selects all content cells in the Grid. If \fInotify\fP is True, the Grid's XmNselectCallback callbacks will be called for each cell selected. .SH "SEE ALSO" XmLGridSelectAllRows(3X) XmLGridSelectAllColumns(3X) nedit-5.6.orig/Microline/man/XmLGridSelectAllColumns.3x0000644000175000017500000000575110077552126021537 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridSelectAllColumns 3X "R1" "XML1" "XML" .SH NAME XmLGridSelectAllColumns \- select all content columns .SH SYNTAX void XmLGridSelectAllColumns(\fIwidget\fP, \fInotify\fP) .br Widget \fIwidget\fP; .br Boolean \fInotify\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fInotify\fP 1i if True, select callbacks will be called .SH DESCRIPTION Selects all content columns in the Grid. If \fInotify\fP is True, the Grid's XmNselectCallback callbacks will be called for each column selected. .SH "SEE ALSO" XmLGridSelectAllCells(3X) XmLGridSelectAllRows(3X) nedit-5.6.orig/Microline/man/XmLGridSelectAllRows.3x0000644000175000017500000000573210077552126021050 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridSelectAllRows 3X "R1" "XML1" "XML" .SH NAME XmLGridSelectAllRows \- select all content rows .SH SYNTAX void XmLGridSelectAllRows(\fIwidget\fP, \fInotify\fP) .br Widget \fIwidget\fP; .br Boolean \fInotify\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fInotify\fP 1i if True, select callbacks will be called .SH DESCRIPTION Selects all content rows in the Grid. If \fInotify\fP is True, the Grid's XmNselectCallback callbacks will be called for each row selected. .SH "SEE ALSO" XmLGridSelectAllCells(3X) XmLGridSelectAllColumns(3X) nedit-5.6.orig/Microline/man/XmLGridSelectCell.3x0000644000175000017500000000627010077552126020342 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridSelectCell 3X "R1" "XML1" "XML" .SH NAME XmLGridSelectCell \- select a cell .SH SYNTAX void XmLGridSelectCell(\fIwidget\fP, \fIrow\fP, \ \fIcolumn\fP, \fInotify\fP) .br Widget \fIwidget\fP; .br int \fIrow\fP; .br int \fIcolumn\fP; .br Boolean \fInotify\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIrow\fP 1i position of content row .IP \fIcolumn\fP 1i position of content column .IP \fInotify\fP 1i if True, select callbacks will be called .SH DESCRIPTION Selects the cell in the Grid at the content \fIrow\fP and content \fIcolumn\fP specified. If \fInotify\fP is True and the cell is currently deselected, the Grid's XmNselectCallback callbacks will be called. .SH "SEE ALSO" XmLGridSelectAllCells(3X) XmLGridSelectRow(3X) XmLGridSelectColumn(3X) nedit-5.6.orig/Microline/man/XmLGridSelectColumn.3x0000644000175000017500000000605310077552126020717 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridSelectColumn 3X "R1" "XML1" "XML" .SH NAME XmLGridSelectColumn \- select a column .SH SYNTAX void XmLGridSelectColumn(\fIwidget\fP, \fIcolumn\fP, \fInotify\fP) .br Widget \fIwidget\fP; .br int \fIcolumn\fP; .br Boolean \fInotify\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIcolumn\fP 1i position of content column .IP \fInotify\fP 1i if True, select callbacks will be called .SH DESCRIPTION Selects the specified content \fIcolumn\fP in the Grid. If \fInotify\fP is True and the column is currently deselected, the Grid's XmNselectCallback callbacks will be called. .SH "SEE ALSO" XmLGridSelectAllColumns(3X) nedit-5.6.orig/Microline/man/XmLGridSelectRow.3x0000644000175000017500000000601210077552126020224 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridSelectRow 3X "R1" "XML1" "XML" .SH NAME XmLGridSelectRow \- select a row .SH SYNTAX void XmLGridSelectRow(\fIwidget\fP, \fIrow\fP, \fInotify\fP) .br Widget \fIwidget\fP; .br int \fIrow\fP; .br Boolean \fInotify\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIrow\fP 1i position of content row .IP \fInotify\fP 1i if True, select callbacks will be called .SH DESCRIPTION Selects the specified content \fIrow\fP in the Grid. If \fInotify\fP is True and the row is currently deselected, the Grid's XmNselectCallback callbacks will be called. .SH "SEE ALSO" XmLGridSelectAllRows(3X) nedit-5.6.orig/Microline/man/XmLGridSetFocus.3x0000644000175000017500000000607310077552126020057 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridSetFocus 3X "R1" "XML1" "XML" .SH NAME XmLGridSetFocus \- set focus to a cell .SH SYNTAX void XmLGridSetFocus(\fIwidget\fP, \fIrow\fP, \fIcolumn\fP) .br Widget \fIwidget\fP; .br int \fIrow\fP; .br int \fIcolumn\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIrow\fP 1i position of content row .IP \fIcolumn\fP 1i position of content column .SH DESCRIPTION Sets focus to the cell at the given content row and content column. .SH RETURN VALUE Upon success, a value of 0 will be returned. A value of -1 will be returned if the cell position specified is invalid or the cell can not accept focus. .SH "SEE ALSO" XmLGridGetFocus(3X) nedit-5.6.orig/Microline/man/XmLGridSetStrings.3x0000644000175000017500000000623010077552126020424 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridSetStrings 3X "R1" "XML1" "XML" .SH NAME XmLGridSetStrings \- set strings in a Grid .SH SYNTAX int XmLGridSetStrings(\fIwidget\fP, \fIdata\fP) .br Widget \fIwidget\fP; .br char *\fIdata\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIdata\fP 1i pointer to pipe-separated string data .SH DESCRIPTION Sets cell strings in the Grid starting at the top left cell with the strings contained in \fIdata\fP. The string data should be in pipe-separated format where pipes signify the start of a new column and new-lines signify the start of new rows. The rows and columns set must exist at the time of this call. .SH RETURN VALUE The number of cells which had values set by this function. .SH "SEE ALSO" XmLGridSetStringsPos(3X) nedit-5.6.orig/Microline/man/XmLGridSetStringsPos.3x0000644000175000017500000000716010077552126021111 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridSetStringsPos 3X "R1" "XML1" "XML" .SH NAME XmLGridSetStringsPos \- set strings in a Grid at a specified location .SH SYNTAX int XmLGridSetStringsPos(\fIwidget\fP, \fIrowType\fP, \fIrow\fP, \ \fIcolumnType\fP, \fIcolumn\fP, \fIdata\fP) .br Widget \fIwidget\fP; .br unsigned char \fIrowType\fP; .br int \fIrow\fP; .br unsigned char \fIcolumnType\fP; .br int \fIcolumn\fP; .br char *\fIdata\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIrowType\fP 1i type of first row location .IP \fIrow\fP 1i location of first row .IP \fIcolumnType\fP 1i type of first column location .IP \fIcolumn\fP 1i location of first column .IP \fIdata\fP 1i pointer to pipe-separated string data .SH DESCRIPTION Sets cell strings in the Grid with the strings contained in \fIdata\fP, starting at the row and column specified by the given \fIrowType\fP, \fIrow\fP, \fIcolumnType\fP, and \fIcolumn\fP. The string data should be in pipe-separated format where pipes signify the start of a new column and new-lines signify the start of new rows. The rows and columns set must exist at the time of this call. .SH RETURN VALUE The number of cells which had values set by this function. .SH "SEE ALSO" XmLGridSetStrings(3X) nedit-5.6.orig/Microline/man/XmLGridWrite.3x0000644000175000017500000000710410077552126017412 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridWrite 3X "R1" "XML1" "XML" .SH NAME XmLGridWrite \- write the string contents of cells in a Grid into a file .SH SYNTAX int XmLGridWrite(\fIwidget\fP, \fIfile\fP, \fIformat\fP, \fIdelimiter\fP, \fIskipHidden\fP) .br Widget \fIwidget\fP; .br FILE *\fIfile\fP; .br int \fIformat\fP; .br char \fIdelimiter\fP; .br Boolean \fIskipHidden\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIfile\fP 1i file to write to .IP \fIformat\fP 1i format of the file .IP \fIdelimiter\fP 1i delimiter if format is XmFORMAT_DELIMITED .IP \fIskipHidden\fP 1i if True, skip hidden rows and columns .SH DESCRIPTION Writes all cell contents in the Grid to a \fIfile\fP in the given \fIformat\fP. If \fIskipHidden\fP is True, data in hidden rows or columns will not be included. Format must be one of the following: XmFORMAT_XL, where tabs separate columns and cell data is possibly surrounded by double-quotes, XmFORMAT_PAD, where columns are padded with spaces or XmFORMAT_DELIMITED, where data is delimited by the \fIdelimiter\fP given. .SH RETURN VALUE A value of 0 is returned upon success, and a value of -1 is returned upon failure. .SH "SEE ALSO" XmLGridWritePos(3X) nedit-5.6.orig/Microline/man/XmLGridWritePos.3x0000644000175000017500000001034110077552126020071 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridWritePos 3X "R1" "XML1" "XML" .SH NAME XmLGridWritePos \- write the string contents of cells in a Grid at a given location into a file .SH SYNTAX int XmLGridWritePos(\fIwidget\fP, \fIfile\fP, \fIformat\fP, \fIdelimiter\fP, \fIskipHidden\fP, \fIrowType\fP, \fIrow\fP, \ \fIcolumnType\fP, \fIcolumn\fP, \fInrow\fP, \fIncolumn\fP) .br Widget \fIwidget\fP; .br FILE *\fIfile\fP; .br int \fIformat\fP; .br char \fIdelimiter\fP; .br Boolean \fIskipHidden\fP; .br unsigned char \fIrowType\fP; .br int \fIrow\fP; .br unsigned char \fIcolumnType\fP; .br int \fIcolumn\fP; .br int \fInrow\fP; .br int \fIncolumn\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIfile\fP 1i file to write to .IP \fIformat\fP 1i format of the file .IP \fIdelimiter\fP 1i delimiter if format is XmFORMAT_DELIMITED .IP \fIskipHidden\fP 1i if True, skip hidden rows and columns .IP \fIrowType\fP 1i type of first row .IP \fIrow\fP 1i location of first row .IP \fIcolumnType\fP 1i type of first column .IP \fIcolumn\fP 1i location of first column .IP \fInrow\fP 1i number of rows .IP \fIncolumn\fP 1i number of columns .SH DESCRIPTION Writes the contents of cells in \fInrow\fP number of rows and \fIncolumn\fP number of columns to a \fIfile\fP in the given \fIformat\fP starting at the row and column specified by \fIrowType\fP, \fIrow\fP, \fIcolumnType\fP, and \fIcolumn\fP. If \fIskipHidden\fP is True, data in hidden rows or columns will not be included. Format must be one of the following: XmFORMAT_XL, where tabs separate columns and cell data is possibly surrounded by double-quotes, XmFORMAT_PAD, where columns are padded with spaces or XmFORMAT_DELIMITED, where data is delimited by the \fIdelimiter\fP given. .SH RETURN VALUE A value of 0 is returned upon success, and a value of -1 is returned upon failure. .SH "SEE ALSO" XmLGridWrite(3X) nedit-5.6.orig/Microline/man/XmLGridXYToRowColumn.3x0000644000175000017500000000720610077552126021034 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLGridXYToRowColumn 3X "R1" "XML1" "XML" .SH NAME XmLGridXYToRowColumn \- locate the cell at a given position .SH SYNTAX int XmLGridXYToRowColumn(\fIwidget\fP, \fIx\fP, \fIy\fP, \ \fIrowType\fP, \fIrow\fP, \fIcolumnType\fP, \fIcolumn\fP) .br Widget \fIwidget\fP; .br int \fIx\fP; .br int \fIy\fP; .br unsigned char *\fIrowType\fP; .br int *\fIrow\fP; .br unsigned char *\fIcolumnType\fP; .br int *\fIcolumn\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Grid widget ID .IP \fIx\fP 1i x-coordinate relative to Grid's top left .IP \fIy\fP 1i y-coordinate relative to Grid's top left .IP \fIrowType\fP 1i type of row .IP \fIrow\fP 1i position of row .IP \fIcolumnType\fP 1i type of column .IP \fIcolumn\fP 1i position of column .SH DESCRIPTION Returns the position of the cell containing the \fIx\fP and \fIy\fP coordinates specified. Upon success, a value of 0 will be returned and \fIrowType\fP and \fIrow\fP will be set the type of row and row position, respectively, and \fIcolumnType\fP and \fIcolumn\fP will be set to the type of column and column position, respectively. .SH RETURN VALUE If no cell exists at the location specified, a value of -1 will be returned. Upon success, a value of 0 will be returned. .SH "SEE ALSO" XmLGrid(3X) nedit-5.6.orig/Microline/man/XmLMessageBox.3x0000644000175000017500000000652110077552127017552 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLMessageBox 3X "R1" "XML1" "XML" .SH NAME XmLMessageBox \- display a simple message dialog .SH SYNTAX int XmLMessageBox(\fIwidget\fP, \fIstring\fP, \fIokOnly\fP) .br Widget \fIwidget\fP; .br XmString \fIstring\fP; .br Boolean \fIokOnly\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i widget the MessageBox should appear in front of .IP \fIstring\fP 1i message to display .IP \fIokOnly\fP 1i display 1 or 3 buttons .SH DESCRIPTION Displays a message dialog containing a \fIstring\fP and an Ok button if \fIokOnly\fP is True, or a question dialog with three buttons (Ok, Cancel, and Help) and a string if okOnly is False. This function will not return until the user chooses one of the buttons. If the user closes the window via the title bar, the action chosen is assumed to be Ok. The dialog will appear in front of the given \fIwidget\fP. .SH RETURN VALUE The number of the button chosen, where 1 is Ok, 2 is Cancel, and 3 is Help. nedit-5.6.orig/Microline/man/XmLPixmapDraw.3x0000644000175000017500000001013710077552127017567 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLPixmapDraw 3X "R1" "XML1" "XML" .SH NAME XmLPixmapDraw \- draws a pixmap clipped and aligned in a widget .SH SYNTAX void XmLPixmapDraw(\fIwidget\fP, \fIpixmap\fP, \fIpixmask\fP, \ \fIpixmapWidth\fP, \fIpixmapHeight\fP, \fIalignment\fP, \ \fIgc\fP, \fIrect\fP, \fIclipRect\fP) .br Widget \fIwidget\fP; .br Pixmap \fIpixmap\fP; .br Pixmap \fIpixmask\fP; .br int \fIpixmapWidth\fP; .br int \fIpixmapHeight\fP; .br unsigned char \fIalignment\fP; .br GC \fIgc\fP; .br XRectangle *\fIrect\fP; .br XRectangle *\fIclipRect\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i drawing destination widget .IP \fIpixmap\fP 1i pixmap to draw .IP \fIpixmask\fP 1i pixmap mask for drawing .IP \fIpixmapWidth\fP 1i width of pixmap in pixels .IP \fIpixmapHeight\fP 1i height of pixmap in pixels .IP \fIalignment\fP 1i alignment .IP \fIgc\fP 1i graphics context for drawing .IP \fIrect\fP 1i source rectangle .IP \fIclipRect\fP 1i destination/clipping rectangle .SH DESCRIPTION Draws a \fIpixmap\fP of width \fIpixmapWidth\fP and height \fIpixmapHeight\fP using the GC \fIgc\fP in the window of the \fIwidget\fP given. The \fIpixmask\fP parameter must be either set to XmUNSPECIFIED_PIXMAP or a Pixmap of depth one. If a Pixmap is specified, it is used as a mask to restrict the area drawn. The \fIrect\fP parameter indicates the rectangle used to determine alignment. The \fIclipRect\fP rectangle parameter given indicates the rectangle used to clip the drawing. \fIAlignment\fP must be one of the following: XmALIGNMENT_TOP_LEFT, XmALIGNMENT_TOP, XmALIGNMENT_TOP_RIGHT, XmALIGNMENT_LEFT, XmALIGNMENT_CENTER, XmALIGNMENT_RIGHT, XmALIGNMENT_BOTTOM_LEFT, XmALIGNMENT_BOTTOM or XmALIGNMENT_BOTTOM_RIGHT .SH "SEE ALSO" XmLStringDraw(3X) nedit-5.6.orig/Microline/man/XmLProgress.3x0000644000175000017500000001503210077552127017316 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLProgress 3X "R1" "XML1" "XML" .SH NAME XmLFolder .SH SYNOPSIS #include .LP .SH DESCRIPTION A progress bar which can be used to chart completion of a task. Along with a Progress meter, this widget may optionally display text with percentage completion and elapsed and estimated time to completion. .SS Class Information Progress inherits from XmPrimitive and Core. Its class pointer is xmlProgressWidgetClass. Its class name is XmLProgress. .SS New Resources .nf .ft B Name Class Type Default Access .ft P XmNcompleteValue XmCCompleteValue int 100 CSG XmNfontList XmCFontList XmFontList fixed CSG XmNmeterStyle XmCMeterStyle unsigned char XmMETER_BAR CSG XmNnumBoxes XmCNumBoxes int 10 CSG XmNshowPercentage XmCShowPercentage Boolean True CSG XmNshowTime XmCShowTime Boolean False CSG XmNvalue XmCValue int 0 CSG .fi .IP XmNcompleteValue Defines the maximum value of the XmNvalue resource. When the XmNvalue resource reaches this number, the Progress bar will show 100% complete. This value is used to determine the percentage to complete and to estimate time to completion. .IP XmNfontList The font list used for drawing the percentage complete and estimated time. .IP XmNmeterStyle The style of the meter to draw. Possible values: .nf XmMETER_BAR /* standard bar meter */ XmMETER_BOXES /* shadowed boxes meter */ .fi Only the XmMETER_BAR style can display the percentage complete indicator and optional and estimated time to completion. .IP XmNnumBoxes When XmNmeterStyle is XmMETER_BOXES, this resource defines the number of boxes to display in the meter. .IP XmNshowPercentage If set to True, text will be shown centered in the widget displaying the current percentage complete. The percentage complete is calculated by dividing the XmNvalue by the XmNcompleteValue. .IP XmNshowTime If set to True, the widget will display the elapsed time in the left of the widget and the estimated time remaining on the right. The estimated time remaining is calculated using the XmNvalue, the XmNcompleteValue and the start time. The start time is the last time the XmNvalue was set to 0. No estimated time is shown when XmNvalue is 0 or when it is equal to the XmNcompleteValue. If set to False, only a percentage complete indicator will be shown. .IP XmNvalue A value from 0 to the XmNcompleteValue which defines how much progress has taken place. When this value is set to 0, the current time is stored as the start time for calculating estimated time to completion. .SS Inherited Resources Progress inherits the resources shown below .nf .ft B Resource From Resource From .ft P XmNaccelerators Core XmNhighlightPixmap Primitive XmNancestorSensitive Core XmNhighlightThickness Primitive XmNbackground Core XmNinitialResourcesPersistent Core XmNbackgroundPixmap Core XmNmappedWhenManaged Core XmNborderColor Core XmNnavagationType Primitive XmNborderPixmap Core XmNscreen Core XmNborderWidth Core XmNsensitive Core XmNbottomShadowColor Primitive XmNshadowThickness Primitive XmNbottomShadowPixmap Primitive XmNtopShadowColor Primitive XmNcolormap Core XmNtopShadowPixmap Primitive XmNdepth Core XmNtranslations Core XmNdestroyCallback Core XmNtraversalOn Primitive XmNforeground Primitive XmNunitType Primitive XmNheight Core XmNuserData Primitive XmNhelpCallback Primitive XmNwidth Core XmNhighlightColor Primitive XmNx Core XmNhighlightOnEnter Primitive XmNy Core .fi .SH "SEE ALSO" XmLCreateProgress(3X) nedit-5.6.orig/Microline/man/XmLRectIntersect.3x0000644000175000017500000000556310077552127020300 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLRectIntersect 3X "R1" "XML1" "XML" .SH NAME XmLRectIntersect \- determines if two rectangle intersect .SH SYNTAX int XmLRectIntersect(\fIr1\fP, \fIr2\fP) .br XRectangle *\fIr1\fP; .br XRectangle *\fIr2\fP; .LP .SH ARGUMENTS .IP \fIr1\fP 1i rectangle 1 .IP \fIr2\fP 1i rectangle 2 .SH DESCRIPTION Determines if the two rectangles \fIr1\fP and \fIr2\fP intersect. .SH RETURN VALUE 1 if the rectangles r1 and r2 intersect, and a value of 0 otherwise. nedit-5.6.orig/Microline/man/XmLShellOfWidget.3x0000644000175000017500000000541510077552127020216 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLShellOfWidget 3X "R1" "XML1" "XML" .SH NAME XmLShellOfWidget \- returns the Shell widget of the given widget .SH SYNTAX void XmLShellOfWidget(\fIwidget\fP) .br Widget \fIwidget\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i widget ID .SH DESCRIPTION Returns the Shell widget of the given widget. .SH RETURN VALUE The Shell widget of the given widget. nedit-5.6.orig/Microline/man/XmLSort.3x0000644000175000017500000000677210077552127016454 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLSort 3X "R1" "XML1" "XML" .SH NAME XmLSort \- sort an array using a quicksort algorithm .SH SYNTAX void XmLSort(\fIbase\fP, \fInumItems\fP, \ \fIitemSize\fP, \fIcompare\fP, \fIuserData\fP) .br void *\fIbase\fP; .br int \fInumItems\fP; .br unsigned int \fIitemSize\fP; .br XmLSortCompareFunc \fIcompare\fP; .br void *\fIuserData\fP; .LP .SH ARGUMENTS .IP \fIbase\fP 1i base of array to sort .IP \fInumItems\fP 1i number of items to be sorted .IP \fIitemSize\fP 1i size of items to be sorted .IP \fIcompare\fP 1i comparison function .IP \fIuserData\fP 1i user data .SH DESCRIPTION Performs a median-of-three quicksort to sort the array starting at the address \fIbase\fP which contains \fInumItems\fP items of size \fIitemSize\fP. The \fIcompare\fP function given is used to compare items, and when sorting occurs, it is passed pointers to the two items to compare, as well as the \fIuserData\fP pointer given to this function. The compare function must return a value less than, greater than, or equal to 0 based on whether the first item is less than, greater than, or equal to the second item. nedit-5.6.orig/Microline/man/XmLStringDraw.3x0000644000175000017500000000755310077552127017607 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLStringDraw 3X "R1" "XML1" "XML" .SH NAME XmLStringDraw \- draws a string clipped and aligned in a widget .SH SYNTAX void XmLStringDraw(\fIwidget\fP, \fIstring\fP, \fIstringDir\fP, \ \fIfontList\fP, \fIalignment\fP, \fIgc\fP, \fIrect\fP, \fIclipRect\fP) .br Widget \fIwidget\fP; .br String \fIstring\fP; .br XmStringDirection \fIstringDir\fP; .br XmFontList \fIfontList\fP; .br unsigned char \fIalignment\fP; .br GC \fIgc\fP; .br XRectangle *\fIrect\fP; .br XRectangle *\fIclipRect\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i drawing destination widget .IP \fIstring\fP 1i string to draw .IP \fIstringDir\fP 1i direction to draw string in .IP \fIfontList\fP 1i font list used to draw string .IP \fIalignment\fP 1i alignment .IP \fIgc\fP 1i graphics context for drawing .IP \fIrect\fP 1i source rectangle .IP \fIclipRect\fP 1i destination/clipping rectangle .SH DESCRIPTION Draws a \fIstring\fP in the direction \fIstringDir\fP using the font list \fIfontList\fP and the GC \fIgc\fP in the window of the \fIwidget\fP given. The \fIrect\fP parameter indicates the rectangle used to determine alignment. The \fIclipRect\fP rectangle parameter given indicates the rectangle used to clip the drawing. \fIAlignment\fP must be one of the following: XmALIGNMENT_TOP_LEFT, XmALIGNMENT_TOP, XmALIGNMENT_TOP_RIGHT, XmALIGNMENT_LEFT, XmALIGNMENT_CENTER, XmALIGNMENT_RIGHT, XmALIGNMENT_BOTTOM_LEFT, XmALIGNMENT_BOTTOM or XmALIGNMENT_BOTTOM_RIGHT .SH "SEE ALSO" XmLPixmapDraw(3X) nedit-5.6.orig/Microline/man/XmLStringDrawDirection.3x0000644000175000017500000001026010077552127021435 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLStringDrawDirection 3X "R1" "XML1" "XML" .SH NAME XmLStringDrawDirection \- draws a string in the given direction .SH SYNTAX void XmLStringDrawDirection(\fIdpy\fP, \fIwin\fP, \fIfontList\fP, \ \fIstring\fP, \fIgc\fP, \fIx\fP, \fIy\fP, \fIwidth\fP, \ \fIalignment\fP, \fIlayout_direction\fP, \fIdrawing_direction\fP) .br Display *\fIdpy\fP; .br Window \fIwin\fP; .br XmFontList \fIfontList\fP; .br XmString \fIstring\fP; .br GC \fIgc\fP; .br int \fIx\fP; .br int \fIy\fP; .br Dimension \fIwidth\fP; .br unsigned char \fIalignment\fP; .br unsigned char \fIlayout_direction\fP; .br unsigned char \fIdrawing_direction\fP; .LP .SH ARGUMENTS .IP \fIdpy\fP 1i destination display .IP \fIwin\fP 1i destination window .IP \fIfontList\fP 1i font list used to draw string .IP \fIstring\fP 1i string to draw .IP \fIgc\fP 1i graphics context for drawing .IP \fIx\fP 1i x position .IP \fIy\fP 1i y position .IP \fIwidth\fP 1i width for alignment .IP \fIalignment\fP 1i alignment .IP \fIlayout_direction\fP 1i layout direction for drawing .IP \fIdrawing_direction\fP 1i direction to draw .SH DESCRIPTION Draws a \fIstring\fP in the direction \fIdrawing_direction\fP using the font list \fIfontList\fP and the GC \fIgc\fP in the window \fIwin\fP on the display \fIdpy\fP. The string is drawn at the \fIx\fP and \fIy\fP location given. The \fIwidth\fP parameter is used solely for determining alignment. The \fIalignment\fP parameter must be one of: XmALIGNMENT_BEGINNING, XmALIGNMENT_CENTER or XmALIGNMENT_END. The \fIlayout_direction\fP parameter is used to draw the string right or left for internationalization (see XmStringDraw). The \fIdrawing_direction\fP parameter must be one of: XmSTRING_UP, XmSTRING_DOWN, XmSTRING_LEFT or XmSTRING_RIGHT. .SH "SEE ALSO" XmLStringDraw(3x), XmLPixmapDraw(3X) nedit-5.6.orig/Microline/man/XmLTree.3x0000644000175000017500000003074010077552127016414 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLTree 3X "R1" "XML1" "XML" .SH NAME XmLTree .SH SYNOPSIS #include .LP .SH DESCRIPTION A Tree is a subclass of the Grid widget which displays a hierarchical tree with a Pixmap, XmString, connecting lines and possibly an expand/collapse graphic in the cells of its first column. Each row in the Tree has a position and level which is used to determine its relationship to other rows in the Tree. Rows may be expanded or collapsed by clicking on an expand/collapse graphic or by activating a row with the keyboard. The Tree inherits all the abilities of the Grid widget, allowing it to contain multiple columns and rows of varying types, heading and fixed rows and columns, interactive row and column resizing, cell borders, etc. .SS Class Information Tree inherits from XmLGrid, XmManager, Constraint, Composite and Core. Its class pointer is xmlTreeWidgetClass. Its class name is XmLTree. .SS New Resources The Tree resources defined below affect its overall layout and appearance. Definitions of resources affecting rows, columns and cells follow the Tree resource definitions. .nf .ft B Name Class Type Default Access .ft P XmNconnectingLineColor XmCConnectingLineColor Pixel Dynamic CSG XmNlevelSpacing XmCLevelSpacing Dimension 11 CSG XmNplusMinusColor XmCPlusMinusColor Pixel Dynamic CSG .fi .IP XmNconnectingLineColor The color of the line which is drawn connecting parents, children and siblings in the first column of the Tree. This values defaults to the foreground color of the Tree. .IP XmNlevelSpacing The indent in pixels for each level in the Tree. .IP XmNplusMinusColor The color of the plus and minus expand/collapse graphics drawn next to parent nodes which may be expanded. This value defaults to the foreground color of the Tree. .SS Row/Column/Cell Resources Tree defines the resources in the table below affecting rows. In addition to these row resources, the Tree inherits all the row, column and cell resources which exist in the Grid. .nf .ft B Name Class Type Default Access .ft P XmNrowExpands XmCRowExpands Boolean False SG XmNrowIsExpanded XmCRowIsExpanded Boolean True SG XmNrowLevel XmCRowLevel int 0 SG .fi .IP XmNrowExpands True if the row may expand (it is a parent) and False otherwise. .IP XmNrowIsExpanded True if the row is currently expanded and False otherwise. If this resource is set to False, the Tree will hide all children of this row. Children of this row are determined to be all rows which are of a level greater than this row's until we find the next row which is of this row's level or less (a sibling or parent of this row). Rows are hidden by setting their XmNrowHeight to 0. If this resource is set to True, the Tree will show all children of this row. Rows are shown by setting their XmNrowHeight to 1. The value of this resource has no meaning if XmNrowExpands is False. .IP XmNrowLevel The level of the row in the Tree. .SS Callback Resources Tree defines the following callback resources. .nf .ft B Callback Reasons Called When .ft P XmNcollapseCallback XmCR_COLLAPSE_ROW Row is collapsed by activate or by clicking on collapse graphic XmNexpandCallback XmCR_EXPAND_ROW Row is expanded by activate or by clicking on expand graphic .fi .SS Callback Structure Each callback function is passed a pointer to a XmLGridCallbackStruct structure. See the XmLGrid's Callback Structure section for the full structure definition. The following table shows which values are set for which callback reasons. Elements not set will have undefined values. .nf .ft B Reason Values Set .ft P XmCR_COLLAPSE_ROW event, rowType, row XmCR_EXPAND_ROW event, rowType, row .ni .SS Inherited Resources Tree inherits the resources shown below. .nf .ft B Resource From Resource From .ft P XmNaccelerators Core XmNimmediateDraw Grid XmNallowColumnHide Grid XmNinitialResourcePersist Core XmNallowColumnResize Grid XmNinsertPosition Composite XmNallowDragSelected Grid XmNlayoutFrozen Grid XmNallowDrop Grid XmNleftFixedCount Grid XmNallowRowHide Grid XmNleftFixedMargin Grid XmNallowRowResize Grid XmNmappedWhenManaged Core XmNancestorSensitive Core XmNnavagationType Manager XmNautoSelect Grid XmNnumChildren Composite XmNbackground Core XmNrightFixedCount Grid XmNbackgroundPixmap Core XmNrightFixedMargin Grid XmNblankBackground Grid XmNrows Grid XmNborderColor Core XmNscreen Core XmNborderPixmap Core XmNscrollBarMargin Grid XmNborderWidth Core XmNscrollColumn Grid XmNbottomFixedCount Grid XmNscrollRow Grid XmNbottomFixedMargin Grid XmNselectBackground Grid XmNbottomShadowColor Manager XmNselectForeground Grid XmNbottomShadowPixmap Manager XmNselectionPolicy Grid XmNchildren Composite XmNsensitive Core XmNcolormap Core XmNshadowRegions Grid XmNcolumns Grid XmNshadowThicknses Manager XmNdebugLevel Grid XmNshadowType Grid XmNdepth Core XmNsimpleHeadings Grid XmNdestroyCallback Core XmNsimpleWidths Grid XmNeditTranslations Grid XmNstringDirection Manager XmNfontList Grid XmNtextWidget Grid XmNfooterColumns Grid XmNtopFixedCount Grid XmNfooterRows Grid XmNtopFixedMargin Grid XmNforeground Manager XmNtopShadowColor Manager XmNglobalPixmapHeight Grid XmNtopShadowPixmap Manager XmNglobalPixmapWidth Grid XmNtranslations Core XmNheadingColumns Grid XmNtraversalOn Manager XmNheadingRows Grid XmNtraverseTranslations Grid XmNheight Core XmNunitType Manager XmNhelpCallback Manager XmNuseAverageFontWidth Grid XmNhiddenColumns Grid XmNuserData Manager XmNhiddenRows Grid XmNverticalScrollBar Grid XmNhighlightColor Manager XmNverticalSizePolicy Grid XmNhighlightThickness Grid XmNvisibleColumns Grid XmNhighlightPixmap Manager XmNvisibleRows Grid XmNhighlightRowMode Grid XmNvsbDisplayPolicy Grid XmNhorizontalScrollBar Grid XmNwidth Core XmNhorizontalSizePolicy Grid XmNx Core XmNhsbDisplayPolicy Grid XmNy Core .fi .SS Inherited Row/Column/Cell Resources Tree inherits the row/column and cell resources shown below. .nf .ft B Resource From Resource From .ft P XmNcellAlignment Grid XmNcellTopBorderColor Grid XmNcellBackground Grid XmNcellTopBorderType Grid XmNcellBottomBorderColor Grid XmNcellType Grid XmNcellBottomBorderType Grid XmNcellUserData Grid XmNcellColumnSpan Grid XmNcolumn Grid XmNcellDefaults Grid XmNcolumnPtr Grid XmNcellEditable Grid XmNcolumnRangeEnd Grid XmNcellFontList Grid XmNcolumnRangeStart Grid XmNcellForeground Grid XmNcolumnSizePolicy Grid XmNcellLeftBorderColor Grid XmNcolumnStep Grid XmNcellLeftBorderType Grid XmNcolumnType Grid XmNcellMarginBottom Grid XmNcolumnWidth Grid XmNcellMarginLeft Grid XmNcolumnUserData Grid XmNcellMarginRight Grid XmNrow Grid XmNcellMarginTop Grid XmNrowHeight Grid XmNcellPixmap Grid XmNrowPtr Grid XmNcellPixmapMask Grid XmNrowRangeEnd Grid XmNcellRightBorderColor Grid XmNrowRangeStart Grid XmNcellRightBorderType Grid XmNrowSizePolicy Grid XmNcellRowSpan Grid XmNrowStep Grid XmNcellString Grid XmNrowType Grid .fi .SH "SEE ALSO" XmLTreeAddRow(3X) XmLTreeAddRows(3X) XmLGridAddColumns(3X) XmLGridColumnIsVisible(3X) XmLGridDeleteAllColumns(3X) XmLGridDeleteAllRows(3X) XmLGridDeleteColumns(3X) XmLGridDeleteRows(3X) XmLGridDeselectAllCells(3X) XmLGridDeselectAllColumns(3X) XmLGridDeselectAllRows(3X) XmLGridDeselectCell(3X) XmLGridDeselectColumn(3X) XmLGridDeselectRow(3X) XmLGridEditBegin(3X) XmLGridEditCancel(3X) XmLGridEditComplete(3X) XmLGridGetColumn(3X) XmLGridGetFocus(3X) XmLGridGetRow(3X) XmLGridGetSelectedCellCount(3X) XmLGridGetSelectedCells(3X) XmLGridGetSelectedColumnCount(3X) XmLGridGetSelectedColumns(3X) XmLGridGetSelectedRow(3X) XmLGridGetSelectedRowCount(3X) XmLGridGetSelectedRows(3X) XmLGridMoveColumns(3X) XmLGridMoveRows(3X) XmLGridRead(3X) XmLGridReadPos(3X) XmLGridRedrawAll(3X) XmLGridRedrawCell(3X) XmLGridRedrawColumn(3X) XmLGridRedrawRow(3X) XmLGridReorderColumns(3X) XmLGridReorderRows(3X) XmLGridRowColumnToXY(3X) XmLGridRowlsVisible(3X) XmLGridSelectAllCells(3X) XmLGridSelectAllColumns(3X) XmLGridSelectAllRows(3X) XmLGridSelectCell(3X) XmLGridSelectColumn(3X) XmLGridSelectRow(3X) XmLGridSetFocus(3X) XmLGridSetStrings(3X) XmLGridSetStringsPos(3X) XmLGridWrite(3X) XmLGridWritePos(3X) XmLGridXYToRowColumn(3X) nedit-5.6.orig/Microline/man/XmLTreeAddRow.3x0000644000175000017500000000744310077552127017521 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLTreeAddRow 3X "R1" "XML1" "XML" .SH NAME XmLTreeAddRow \- add a row to a Tree .SH SYNTAX void XmLTreeAddRow(\fIwidget\fP, \fIlevel\fP, \fIexpands\fP, \ \fIisExpanded\fP, \fIposition\fP, \fIpixmap\fP, \fIpixmask\fP, \ \fIstring\fP) .br Widget \fIwidget\fP; .br int \fIlevel\fP; .br Boolean \fIexpands\fP; .br Boolean \fIisExpanded\fP; .br int \fIposition\fP; .br Pixmap \fIpixmap\fP; .br Pixmap \fIpixmask\fP; .br XmString \fIstring\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Tree widget ID .IP \fIlevel\fP 1i level of row .IP \fIexpands\fP 1i flag indicating whether row may expand .IP \fIisExpanded\fP 1i flag indicating current state of row .IP \fIposition\fP 1i position of row .IP \fIpixmap\fP 1i pixmap for icon .IP \fIpixmask\fP 1i pixmask for icon .IP \fIstring\fP 1i string to display next to pixmap .SH DESCRIPTION Adds a content row of \fIlevel\fP to the Tree at \fIposition\fP. The \fIpixmap\fP, \fIpixmask\fP and \fIstring\fP will appear in the first cell of the row. The pixmap and pixmask values may be XmUNSPECIFIED_PIXMAP, in which case, the default pixmap will be displayed. If \fIexpands\fP is True, the row may be expanded by the user. The \fIisExpanded\fP flag indicates if the row is currently expanded (True) or not (False). The XmString string passed is copied by the Tree and should be freed when it is no longer used. .SH "SEE ALSO" XmLTree(3X) XmLTreeAddRows(3X) nedit-5.6.orig/Microline/man/XmLTreeAddRows.3x0000644000175000017500000000746710077552127017712 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLTreeAddRows 3X "R1" "XML1" "XML" .SH NAME XmLTreeAddRows \- add rows to a Tree .SH SYNTAX void XmLTreeAddRows(\fIwidget\fP, \fIrows\fP, \fIcount\fP, \fIposition\fP) .br Widget \fIwidget\fP; .br XmLTreeRowDefinition *\fIrows\fP; .br int \fIcount\fP; .br int \fIposition\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i Tree widget ID .IP \fIrows\fP 1i array definining rows to add .IP \fIcount\fP 1i number of rows .IP \fIposition\fP 1i position of rows to add .SH DESCRIPTION Adds \fIcount\fP content rows to the Tree at the specified \fIposition\fP. A position of 0 indicates the first position and a position of -1 specifies after the last position. The row levels, expansion abilities, expansion states, strings and pixmaps for the rows are defined by their value in the \fIrows\fP array passed to this function. Each item in the array defines a row to be added to the Tree. The \fIpixmap\fP, \fIpixmask\fP and \fIstring\fPs defined will appear in the first cell of the row. The pixmap and pixmask values may be XmUNSPECIFIED_PIXMAP, in which case, the default pixmap will be displayed. If \fIexpands\fP is True for a row, the row may be expanded by the user. The \fIisExpanded\fP flag indicates if a row is currently expanded (True) or not (False). The XmString strings contained in the array are copied by the Tree and should be freed when they are no longer used. .SH "SEE ALSO" XmLTree(3X) XmLTreeAddRow(3X) nedit-5.6.orig/Microline/man/XmLWarning.3x0000644000175000017500000000555610077552127017131 0ustar paulpaul.\" ***** BEGIN LICENSE BLOCK ***** .\" Version: MPL 1.1/GPL 2.0/LGPL 2.1 .\" .\" The contents of this file are subject to the Mozilla Public License Version .\" 1.1 (the "License"); you may not use this file except in compliance with .\" the License. You may obtain a copy of the License at .\" http://www.mozilla.org/MPL/ .\" .\" Software distributed under the License is distributed on an "AS IS" basis, .\" WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License .\" for the specific language governing rights and limitations under the .\" License. .\" .\" The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . .\" .\" The Initial Developer of the Original Code is .\" Netscape Communications Corporation. .\" Portions created by the Initial Developer are Copyright (C) 1998 .\" the Initial Developer. All Rights Reserved. .\" .\" Contributor(s): .\" .\" Alternatively, the contents of this file may be used under the terms of .\" either the GNU General Public License Version 2 or later (the "GPL"), or .\" the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), .\" in which case the provisions of the GPL or the LGPL are applicable instead .\" of those above. If you wish to allow use of your version of this file only .\" under the terms of either the GPL or the LGPL, and not to allow others to .\" use your version of this file under the terms of the MPL, indicate your .\" decision by deleting the provisions above and replace them with the notice .\" and other provisions required by the GPL or the LGPL. If you do not delete .\" the provisions above, a recipient may use your version of this file under .\" the terms of any one of the MPL, the GPL or the LGPL. .\" .\" In addition, as a special exception to the GNU GPL, the copyright holders .\" give permission to link the code of this program with the Motif and Open .\" Motif libraries (or with modified versions of these that use the same .\" license), and distribute linked combinations including the two. You .\" must obey the GNU General Public License in all respects for all of .\" the code used other than linking with Motif/Open Motif. If you modify .\" this file, you may extend this exception to your version of the file, .\" but you are not obligated to do so. If you do not wish to do so, .\" delete this exception statement from your version. .\" .\" ***** END LICENSE BLOCK ***** .TH XmLWarning 3X "R1" "XML1" "XML" .SH NAME XmLWarning \- display a widget XtWarning message .SH SYNTAX void XmLWarning(\fIwidget\fP, \fImsg\fP) .br Widget \fIwidget\fP; .br char *\fImsg\fP; .LP .SH ARGUMENTS .IP \fIwidget\fP 1i widget to display message for .IP \fImsg\fP 1i warning message to display .SH DESCRIPTION For use in widgets only, this function generates an XtWarning message containing the string \fImsg\fP for the given \fIwidget\fP. nedit-5.6.orig/Microline/Makefile0000644000175000017500000000147310220261123015465 0ustar paulpaul# $Id: Makefile,v 1.3 2005/03/23 12:34:27 edg Exp $ SHELL=/bin/sh # # Makefile for NEdit text editor # # Targets are the suffixes of the system-specific makefiles in # the makefiles/ directory. # For example, to build NEdit for Solaris, give the command # # make solaris # # This builds an intermediate library in the util/ directory, # then builds the nedit and nc executables in the source/ directory. # all: @echo "Please specify target:" @echo "(For example, type \"make linux\" for a Linux system.)" @(cd ../makefiles && ls -C Makefile* | sed -e 's/Makefile.//g') .DEFAULT: @- (cd XmL; if [ -f ../../makefiles/Makefile.$@ -a ! -f ./Makefile.$@ ];\ then ln -s ../../makefiles/Makefile.$@ .; fi) @- (cd XmL; $(MAKE) -f Makefile.$@ libXmL.a) clean: @- (cd XmL; $(MAKE) -f Makefile.common clean) nedit-5.6.orig/Microline/examples/0000755000175000017500000000000011107644404015652 5ustar paulpaulnedit-5.6.orig/Microline/examples/Makefile0000644000175000017500000001112410077552126017315 0ustar paulpaul#! gmake # # ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1 # # The contents of this file are subject to the Mozilla Public License Version # 1.1 (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License # for the specific language governing rights and limitations under the # License. # # The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), # in which case the provisions of the GPL or the LGPL are applicable instead # of those above. If you wish to allow use of your version of this file only # under the terms of either the GPL or the LGPL, and not to allow others to # use your version of this file under the terms of the MPL, indicate your # decision by deleting the provisions above and replace them with the notice # and other provisions required by the GPL or the LGPL. If you do not delete # the provisions above, a recipient may use your version of this file under # the terms of any one of the MPL, the GPL or the LGPL. # # In addition, as a special exception to the GNU GPL, the copyright holders # give permission to link the code of this program with the Motif and Open # Motif libraries (or with modified versions of these that use the same # license), and distribute linked combinations including the two. You # must obey the GNU General Public License in all respects for all of # the code used other than linking with Motif/Open Motif. If you modify # this file, you may extend this exception to your version of the file, # but you are not obligated to do so. If you do not wish to do so, # delete this exception statement from your version. # # ***** END LICENSE BLOCK ***** # # This make file was copied from ns/cmd/xfe/XfeWidgets/tests/Makefile # and tweaked. A lot of the rules and logic can probably be shared. # Stuff should be shared in # # DEPTH = ../../../.. ifdef XFE_WIDGETS_BUILD_UNUSED UNUSED_CSRCS = \ demo.c \ prog1.c \ prog2.c \ prog3.c \ uil1.c \ util1.c \ $(NULL) endif CSRCS = \ $(UNUSED_CSRCS) \ folder1.c \ folder2.c \ folder3.c \ folder4.c \ grid1.c \ grid2.c \ grid3.c \ grid4.c \ grid5.c \ grid6.c \ tree1.c \ tree2.c \ tree3.c \ tree4.c \ tree5.c \ $(NULL) REQUIRES = \ Microline PROGS = $(addprefix $(OBJDIR)/, $(CSRCS:.c=.exe)) include $(DEPTH)/config/rules.mk include $(DEPTH)/cmd/xfe/XfeWidgets/XfeWidgets.mk all:: $(PROGS) install:: $(PROGS) LDFLAGS = SHARED_XFE_LIBS = $(DIST)/bin/libXmL.$(DLL_SUFFIX) STATIC_XFE_LIBS = $(DIST)/lib/libXmL.a DIST_FLAGS = -L$(DIST)/bin ifeq ($(OS_ARCH),AIX) XFE_FLAGS = $(STATIC_XFE_LIBS) else XFE_FLAGS = $(SHARED_XFE_LIBS) endif ifeq ($(OS_ARCH),Linux) -include $(DEPTH)/config/motif.mk endif XM_LD_FLAGS = -lMrm -lXm $(NS_MOTIF2_XP_LD_FLAGS) X_LD_FLAGS = $(XM_LD_FLAGS) -lXt -lXmu -lXext -lX11 OS_BEFORE_FLAGS = OS_AFTER_FLAGS = ifeq ($(OS_ARCH),SunOS) OS_BEFORE_LDFLAGS =\ -L/usr/dt/lib \ -L/usr/openwin/lib OS_AFTER_LDFLAGS =\ -lw \ -lintl \ -lsocket \ -lnsl \ -lgen \ -lm \ -ldl endif ifeq ($(OS_ARCH),AIX) OS_BEFORE_LDFLAGS =\ -L/usr/dt/lib endif ifeq ($(OS_ARCH),IRIX) endif ifeq ($(OS_ARCH),Linux) OS_BEFORE_LDFLAGS = -L/usr/X11R6/lib endif ifeq ($(OS_ARCH),HP-UX) OS_BEFORE_LDFLAGS = -L$(DIST)/bin endif LDFLAGS =\ $(OS_BEFORE_LDFLAGS) \ $(DIST_FLAGS) \ $(XFE_FLAGS) \ $(X_LD_FLAGS) \ $(OS_AFTER_LDFLAGS) ## ## Test dependancies ## #OTHER_DEPS = Makefile $(XFE_FLAGS) OTHER_DEPS = $(XFE_FLAGS) ## ## Resource source rule ## #$(OBJDIR)/%.ad.c:: %.ad # Makefile # @$(MAKE_OBJDIR) # @echo 'char * fallback_resources[] = {' > $@; \ # ./ad2c $< >> $@; \ # echo '0};' >> $@ ## ## Resource object rule ## #$(OBJDIR)/%.ad.o: $(OBJDIR)/%.ad.c # @$(MAKE_OBJDIR) # $(CC) -o $@ -c $< ## ## Binary link rule ## $(OBJDIR)/%.exe: $(OBJDIR)/%.o $(OTHER_DEPS) @$(MAKE_OBJDIR) $(XFE_PURIFY) $(CC) -o $@ $< $(LDFLAGS) nedit-5.6.orig/Microline/examples/Makefile.in0000644000175000017500000001127710077552126017733 0ustar paulpaul#! gmake # # ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1 # # The contents of this file are subject to the Mozilla Public License Version # 1.1 (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License # for the specific language governing rights and limitations under the # License. # # The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . # # The Initial Developer of the Original Code is # Netscape Communications Corporation. # Portions created by the Initial Developer are Copyright (C) 1998 # the Initial Developer. All Rights Reserved. # # Contributor(s): # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), # in which case the provisions of the GPL or the LGPL are applicable instead # of those above. If you wish to allow use of your version of this file only # under the terms of either the GPL or the LGPL, and not to allow others to # use your version of this file under the terms of the MPL, indicate your # decision by deleting the provisions above and replace them with the notice # and other provisions required by the GPL or the LGPL. If you do not delete # the provisions above, a recipient may use your version of this file under # the terms of any one of the MPL, the GPL or the LGPL. # # In addition, as a special exception to the GNU GPL, the copyright holders # give permission to link the code of this program with the Motif and Open # Motif libraries (or with modified versions of these that use the same # license), and distribute linked combinations including the two. You # must obey the GNU General Public License in all respects for all of # the code used other than linking with Motif/Open Motif. If you modify # this file, you may extend this exception to your version of the file, # but you are not obligated to do so. If you do not wish to do so, # delete this exception statement from your version. # # ***** END LICENSE BLOCK ***** # # This make file was copied from ns/cmd/xfe/XfeWidgets/tests/Makefile # and tweaked. A lot of the rules and logic can probably be shared. # Stuff should be shared in # # DEPTH = ../../../.. topsrcdir = @top_srcdir@ VPATH = @srcdir@ srcdir = @srcdir@ include $(DEPTH)/config/autoconf.mk ifdef XFE_WIDGETS_BUILD_UNUSED UNUSED_CSRCS = \ demo.c \ prog1.c \ prog2.c \ prog3.c \ uil1.c \ util1.c \ $(NULL) endif CSRCS = \ $(UNUSED_CSRCS) \ folder1.c \ folder2.c \ folder3.c \ folder4.c \ grid1.c \ grid2.c \ grid3.c \ grid4.c \ grid5.c \ grid6.c \ tree1.c \ tree2.c \ tree3.c \ tree4.c \ tree5.c \ $(NULL) REQUIRES = \ Microline PROGS = $(addprefix $(OBJDIR)/, $(CSRCS:.c=.exe)) include $(topsrcdir)/config/rules.mk include $(topsrcdir)/cmd/xfe/XfeWidgets/XfeWidgets.mk all:: $(PROGS) install:: $(PROGS) LDFLAGS = SHARED_XFE_LIBS = $(DIST)/bin/libXmL.$(DLL_SUFFIX) STATIC_XFE_LIBS = $(DIST)/lib/libXmL.a DIST_FLAGS = -L$(DIST)/bin ifeq ($(OS_ARCH),AIX) XFE_FLAGS = $(STATIC_XFE_LIBS) else XFE_FLAGS = $(SHARED_XFE_LIBS) endif ifeq ($(OS_ARCH),Linux) -include $(DEPTH)/config/motif.mk endif XM_LD_FLAGS = -lMrm -lXm $(NS_MOTIF2_XP_LD_FLAGS) X_LD_FLAGS = $(XM_LD_FLAGS) -lXt -lXmu -lXext -lX11 OS_BEFORE_FLAGS = OS_AFTER_FLAGS = ifeq ($(OS_ARCH),SunOS) OS_BEFORE_LDFLAGS =\ -L/usr/dt/lib \ -L/usr/openwin/lib OS_AFTER_LDFLAGS =\ -lw \ -lintl \ -lsocket \ -lnsl \ -lgen \ -lm \ -ldl endif ifeq ($(OS_ARCH),AIX) OS_BEFORE_LDFLAGS =\ -L/usr/dt/lib endif ifeq ($(OS_ARCH),IRIX) endif ifeq ($(OS_ARCH),Linux) OS_BEFORE_LDFLAGS = -L/usr/X11R6/lib endif ifeq ($(OS_ARCH),HP-UX) OS_BEFORE_LDFLAGS = -L$(DIST)/bin endif LDFLAGS =\ $(OS_BEFORE_LDFLAGS) \ $(DIST_FLAGS) \ $(XFE_FLAGS) \ $(X_LD_FLAGS) \ $(OS_AFTER_LDFLAGS) ## ## Test dependancies ## #OTHER_DEPS = Makefile $(XFE_FLAGS) OTHER_DEPS = $(XFE_FLAGS) ## ## Resource source rule ## #$(OBJDIR)/%.ad.c:: %.ad # Makefile # @$(MAKE_OBJDIR) # @echo 'char * fallback_resources[] = {' > $@; \ # ./ad2c $< >> $@; \ # echo '0};' >> $@ ## ## Resource object rule ## #$(OBJDIR)/%.ad.o: $(OBJDIR)/%.ad.c # @$(MAKE_OBJDIR) # $(CC) -o $@ -c $< ## ## Binary link rule ## $(OBJDIR)/%.exe: $(OBJDIR)/%.o $(OTHER_DEPS) @$(MAKE_OBJDIR) $(XFE_PURIFY) $(CC) -o $@ $< $(LDFLAGS) nedit-5.6.orig/Microline/examples/demo.c0000644000175000017500000032353710077552126016763 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void CreateWidgetEdit(); static Widget AddWidgetSample(); static void CreateText(); static void CreatePixmap(); void AddCoverTabForm(); void AddIntroTabForm(); void AddFolderTabForm(); void AddGridTabForm(); void AddProgTabForm(); void AddTreeTabForm(); /* Main Window */ static void exitCB(); static void editCB(); static void folderCB(); #define BOLDFONT "-*-helvetica-bold-r-*--*-100-*-*-*-*-iso8859-1" main(argc, argv) int argc; char *argv[]; { XtAppContext context; Widget w, shell, form, folder; int i; XrmDatabase db; static String resources[] = { "*fontList: -*-helvetica-medium-r-*--*-100-*-*-*-*-iso8859-1", "*XmText.fontList: -*-helvetica-medium-r-*--*-100-*-*-*-*-iso8859-1", "*XmLProgress.fontList: -*-helvetica-bold-r-*--*-100-*-*-*-*-iso8859-1", "*background: #D0D0D0", "*foreground: black", "*topShadowColor: white", "*bottomShadowColor: #404040", "*XmLGrid.topShadowColor: #F0F0F0", "*XmLGrid.selectBackground: #000060", "*XmLGrid.selectForeground: white", "*XmLProgress.topShadowColor: #E0E0E0", "*XmLProgress.bottomShadowColor: #404040", "*XmToggleButton.selectColor: blue", "*XmToggleButton.marginHeight: 0", "*XmToggleButton.spacing: 4", "*XmText.marginHeight: 2", "*XmForm.marginHeight: 8", "*XmForm.marginWidth: 10", "*XmForm.horizontalSpacing: 8", "*XmForm.verticalSpacing: 10", "*XmLabel.marginWidth: 0", "*XmLFolder.XmForm.marginHeight: 16", "*XmLFolder.XmForm.marginWidth: 16", "*XmPushButton.marginHeight: 4", "*WidgetEdit*name.foreground: #000060", "*WidgetEdit*class.foreground: #000060", "*WidgetEdit*XmText.background: white", "*XmLTree.blankBackground: white", "*XmLTree.selectBackground: #000060", "*XmLTree.selectForeground: white", "*XmLTree.connectingLineColor: black", NULL }; shell = XtVaAppInitialize(&context, "Test", NULL, 0, #ifdef X11R4 (Cardinal *)&argc, argv, resources, NULL); #else (int *)&argc, argv, resources, NULL); #endif /* Force override of the falback resources. Normally, we would have an app-default file or similar but since this is a demo, we don't want the user to have to set anything up to run */ db = XtDatabase(XtDisplay(shell)); i = 0; while (resources[i]) { XrmPutLineResource(&db, resources[i]); i++; } XtVaSetValues( shell, XmNtitle, "Microline Widget Library", NULL); form = XtVaCreateWidget("form", xmFormWidgetClass, shell, XmNshadowThickness, 0, NULL); w = XtVaCreateManagedWidget("Exit", xmPushButtonWidgetClass, form, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNwidth, 100, NULL); XtAddCallback(w, XmNactivateCallback, exitCB, (XtPointer)shell); w = XtVaCreateManagedWidget("Editor", xmPushButtonWidgetClass, form, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, w, XmNbottomAttachment, XmATTACH_FORM, XmNwidth, 100, NULL); XtAddCallback(w, XmNactivateCallback, editCB, NULL); CreateWidgetEdit(form); folder = XtVaCreateManagedWidget("folder", xmlFolderWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, w, XmNbottomOffset, 5, XmNtabsPerRow, 3, NULL); AddCoverTabForm(folder); AddIntroTabForm(folder); AddGridTabForm(folder); AddTreeTabForm(folder); AddFolderTabForm(folder); AddProgTabForm(folder); XtAddCallback(folder, XmNactivateCallback, folderCB, NULL); XtManageChild(form); XtRealizeWidget(shell); XtAppMainLoop(context); } static void exitCB(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { Widget shell; shell = (Widget)clientData; exit(0); } /* Widget Editor Functions */ static void _getResourceAsString(); static void _editCB(); static void _editCommandCB(); static void _editChooseCB(); static void _editShowCB(); static void _editCloseCB(); static void _wmCloseCB(); Widget _editDialog, _editClassL, _editNameL, _editGrid, _editCommandT; Widget _editWidget; Boolean _editShowInherited, _editDialogUp; int _editRow, _editCol; static void CreateWidgetEdit(parent) Widget parent; { Widget form, w; Widget chooseB, closeB; Atom WM_DELETE_WINDOW; _editWidget = 0; _editShowInherited = 0; _editDialogUp = False; _editDialog = XtVaAppCreateShell("WidgetEdit", "WidgetEdit", topLevelShellWidgetClass, XtDisplay(parent), XtNtitle, "Widget Editor", XmNdeleteResponse, XmDO_NOTHING, NULL); WM_DELETE_WINDOW = XmInternAtom(XtDisplay(parent), "WM_DELETE_WINDOW", False); XmAddWMProtocolCallback(_editDialog, WM_DELETE_WINDOW, _wmCloseCB, (XtPointer)_editDialog); form = XtVaCreateWidget("form", xmFormWidgetClass, _editDialog, XmNautoUnmanage, False, XmNshadowThickness, 0, NULL); /* Top Row */ w = XtVaCreateManagedWidget("Name:", xmLabelWidgetClass, form, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL); _editNameL = XtVaCreateManagedWidget("name", xmLabelWidgetClass, form, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, w, XmNtopAttachment, XmATTACH_FORM, NULL); w = XtVaCreateManagedWidget("Class:", xmLabelWidgetClass, form, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, _editNameL, XmNtopAttachment, XmATTACH_FORM, NULL); _editClassL = XtVaCreateManagedWidget("class", xmLabelWidgetClass, form, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, w, XmNtopAttachment, XmATTACH_FORM, NULL); w = XtVaCreateManagedWidget("Show All", xmToggleButtonWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 4, XmNrightAttachment, XmATTACH_FORM, NULL); XtAddCallback(w, XmNvalueChangedCallback, _editShowCB, 0); _editGrid = XtVaCreateManagedWidget("Grid", xmlGridWidgetClass, form, XtVaTypedArg, XmNblankBackground, XmRString, "white", 6, XmNcolumns, 4, XmNsimpleWidths, "16c 18c 24c 16c", XmNvisibleColumns, 9, XmNheadingRows, 1, XmNvsbDisplayPolicy, XmSTATIC, XmNsimpleHeadings, "Class|Type|Resource|Value", XmNvisibleRows, 8, XmNshadowThickness, 0, XmNscrollBarMargin, 4, XmNselectionPolicy, XmSELECT_NONE, XmNallowColumnResize, True, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, w, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); XtVaSetValues(_editGrid, XmNcellDefaults, True, XmNcellMarginRight, 2, XmNcellAlignment, XmALIGNMENT_LEFT, XtVaTypedArg, XmNcellBackground, XmRString, "white", 6, XmNcellLeftBorderType, XmBORDER_NONE, XmNcellRightBorderType, XmBORDER_NONE, XmNcellTopBorderType, XmBORDER_NONE, XmNcellBottomBorderType, XmBORDER_NONE, NULL); XtVaSetValues(_editGrid, XmNcellDefaults, True, XmNcolumn, 3, XmNcellEditable, True, NULL); XtAddCallback(_editGrid, XmNeditCallback, _editCB, 0); w = XtVaCreateManagedWidget("Command", xmLabelWidgetClass, form, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 11, XmNleftAttachment, XmATTACH_FORM, NULL); _editCommandT = XtVaCreateManagedWidget("editCommandT", xmTextWidgetClass, form, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, w, NULL); XtAddCallback(_editCommandT, XmNactivateCallback, _editCommandCB, 0); /* Bottom Row */ chooseB = XtVaCreateManagedWidget("Choose", xmPushButtonWidgetClass, form, XmNbottomAttachment, XmATTACH_FORM, XmNmarginWidth, 18, NULL); XtAddCallback(chooseB, XmNactivateCallback, _editChooseCB, 0); closeB = XtVaCreateManagedWidget("Close", xmPushButtonWidgetClass, form, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNmarginWidth, 24, NULL); XtAddCallback(closeB, XmNactivateCallback, _editCloseCB, 0); XtVaSetValues(chooseB, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, closeB, NULL); XtVaSetValues(_editCommandT, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, chooseB, NULL); XtVaSetValues(_editGrid, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, closeB, NULL); XtManageChild(form); } static void SetEditWidget(w) Widget w; { WidgetClass wc, superWc; XtResourceList resList; char className[50], *resName, *resType; Cardinal resCount; int i, j, n, skip, done, superSize; char resVal[50], line[100]; XmString str; char *s; static char *skipType[] = { "Callback", 0 }; _editWidget = w; if (_editWidget) s = XtName(_editWidget); else s = "none"; if (s) { str = XmStringCreateSimple(s); XtVaSetValues(_editNameL, XmNlabelString, str, NULL); XmStringFree(str); } if (_editWidget) { wc = XtClass(_editWidget); s = wc->core_class.class_name; } else s = "none"; if (s) { str = XmStringCreateSimple(s); XtVaSetValues(_editClassL, XmNlabelString, str, NULL); XmStringFree(str); } if (!_editWidget) { XmLGridDeleteAllRows(_editGrid, XmCONTENT); return; } n = 0; done = 0; XtVaSetValues(_editGrid, XmNlayoutFrozen, True, NULL); XmLGridDeleteAllRows(_editGrid, XmCONTENT); while (!done) { if (!wc) { wc = XtClass(XtParent(_editWidget)); XtGetConstraintResourceList(wc, &resList, &resCount); sprintf(className, "%s [C]", wc->core_class.class_name); superSize = 0; done = 1; } else { XtGetResourceList(wc, &resList, &resCount); sprintf(className, wc->core_class.class_name); superWc = wc->core_class.superclass; if (superWc) superSize = superWc->core_class.widget_size; } for (i = 0; i < resCount; i++) { resName = resList[i].resource_name; resType = resList[i].resource_type; if (resList[i].resource_offset < superSize) continue; skip = 0; for (j = 0; skipType[j]; j++) if (!strcmp(skipType[j], resType)) skip = 1; if (skip) continue; _getResourceAsString(resName, resType, resVal); sprintf(line, "%s|%s|%s|%s", className, resType, resName, resVal); XmLGridAddRows(_editGrid, XmCONTENT, -1, 1); XmLGridSetStringsPos(_editGrid, XmCONTENT, n, XmCONTENT, 0, line); n++; } wc = wc->core_class.superclass; XtFree((char *)resList); if (_editShowInherited == False) done = 1; } XtVaSetValues(_editGrid, XmNlayoutFrozen, False, NULL); } static void _getResourceAsString(res, type, str) char *res; char *type; char *str; { Boolean bool; Dimension dimension; int i; static char *skipRes[] = { XmNrowExpands, XmNrowIsExpanded, XmNrowHeight, XmNrowLevel, XmNcolumnWidth, XmNcellColumnSpan, XmNcellEditable, XmNcellMarginBottom, XmNcellMarginLeft, XmNcellMarginRight, XmNcellMarginTop, XmNcellRowSpan, XmNcellToggleSet, 0 }; for (i = 0; skipRes[i]; i++) if (!strcmp(skipRes[i], res)) { sprintf(str, ""); return; } if (!strcmp(type, XmRInt)) { XtVaGetValues(_editWidget, res, &i, NULL); sprintf(str, "%d", i); } else if (!strcmp(type, XmRDimension)) { XtVaGetValues(_editWidget, res, &dimension, NULL); sprintf(str, "%d", (int)dimension); } else if (!strcmp(type, XmRBoolean)) { XtVaGetValues(_editWidget, res, &bool, NULL); if (bool == True) sprintf(str, "True"); else sprintf(str, "False"); } else sprintf(str, ""); } static void _editCB(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { XmLGridCallbackStruct *cbs; int resRow, rowType, row, rowEnd, colType, col, colEnd; XmLGridRow rowp; XmLGridColumn colp; XmString resStr, valStr; char *s, *resS, *valS; static char *emptyValS = ""; cbs = (XmLGridCallbackStruct *)callData; if (cbs->reason != XmCR_EDIT_COMPLETE) return; resRow = cbs->row; /* get resource and value */ rowp = XmLGridGetRow(_editGrid, XmCONTENT, resRow); colp = XmLGridGetColumn(_editGrid, XmCONTENT, 2); XtVaGetValues(_editGrid, XmNrowPtr, rowp, XmNcolumnPtr, colp, XmNcellString, &resStr, NULL); if (!resStr) resS = 0; else XmStringGetLtoR(resStr, XmSTRING_DEFAULT_CHARSET, &resS); colp = XmLGridGetColumn(_editGrid, XmCONTENT, 3); XtVaGetValues(_editGrid, XmNrowPtr, rowp, XmNcolumnPtr, colp, XmNcellString, &valStr, NULL); if (!valStr) valS = emptyValS; else XmStringGetLtoR(valStr, XmSTRING_DEFAULT_CHARSET, &valS); if (XmLIsGrid(_editWidget)) XtVaSetValues(_editWidget, XmNrow, _editRow, XmNcolumn, _editCol, XtVaTypedArg, resS, XmRString, valS, strlen(valS) + 1, NULL); else XtVaSetValues(_editWidget, XtVaTypedArg, resS, XmRString, valS, strlen(valS) + 1, NULL); if (resS) XtFree(resS); if (resStr) XmStringFree(resStr); if (valS != emptyValS) XtFree(valS); if (valStr) XmStringFree(valStr); } static void _editCommandCB(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { char op[40], *cmd; int *rowPos, *colPos, *newPos; int i, l1, l2, l3, l4, n, count; XmString str; cmd = XmTextGetString(_editCommandT); if (_editWidget && XmLIsGrid(_editWidget)) { n = sscanf(cmd, "%s %d %d %d %d", op, &l1, &l2, &l3, &l4); /* Tree commands */ if (!strcmp(op, "addTreeRow") && n == 5) { str = XmStringCreateSimple("New Node"); XmLTreeAddRow(_editWidget, l1, (Boolean)l2, (Boolean)l3, l4, XmUNSPECIFIED_PIXMAP, XmUNSPECIFIED_PIXMAP, str); XmStringFree(str); } /* Grid commands */ else if (!strcmp(op, "addHRows") && n == 3) XmLGridAddRows(_editWidget, XmHEADING, l1, l2); else if (!strcmp(op, "addFRows") && n == 3) XmLGridAddRows(_editWidget, XmFOOTER, l1, l2); else if (!strcmp(op, "addRows") && n == 3) XmLGridAddRows(_editWidget, XmCONTENT, l1, l2); else if (!strcmp(op, "addHColumns") && n == 3) XmLGridAddColumns(_editWidget, XmHEADING, l1, l2); else if (!strcmp(op, "addFColumns") && n == 3) XmLGridAddColumns(_editWidget, XmFOOTER, l1, l2); else if (!strcmp(op, "addColumns") && n == 3) XmLGridAddColumns(_editWidget, XmCONTENT, l1, l2); else if (!strcmp(op, "deleteHRows") && n == 3) XmLGridDeleteRows(_editWidget, XmHEADING, l1, l2); else if (!strcmp(op, "deleteFRows") && n == 3) XmLGridDeleteRows(_editWidget, XmFOOTER, l1, l2); else if (!strcmp(op, "deleteRows") && n == 3) XmLGridDeleteRows(_editWidget, XmCONTENT, l1, l2); else if (!strcmp(op, "deleteHColumns") && n == 3) XmLGridDeleteColumns(_editWidget, XmHEADING, l1, l2); else if (!strcmp(op, "deleteFColumns") && n == 3) XmLGridDeleteColumns(_editWidget, XmFOOTER, l1, l2); else if (!strcmp(op, "deleteColumns") && n == 3) XmLGridDeleteColumns(_editWidget, XmCONTENT, l1, l2); else if (!strcmp(op, "copyPos") && n == 3) XmLGridCopyPos(_editWidget, CurrentTime, XmCONTENT, l1, XmCONTENT, l2, 3, 3); else if (!strcmp(op, "copySelected") && n == 1) XmLGridCopySelected(_editWidget, CurrentTime); else if (!strcmp(op, "paste") && n == 1) XmLGridPaste(_editWidget); else if (!strcmp(op, "pastePos") && n == 3) XmLGridPastePos(_editWidget, XmCONTENT, l1, XmCONTENT, l2); else if (!strcmp(op, "moveColumns") && n == 1) XmLGridMoveColumns(_editWidget, 3, 1, 2); else if (!strcmp(op, "moveRows") && n == 1) XmLGridMoveRows(_editWidget, 3, 1, 2); else if (!strcmp(op, "printSelected") && n == 1) { printf ("--- Current Selections ---\n"); count = XmLGridGetSelectedRowCount(_editWidget); if (count) { rowPos = (int *)malloc(sizeof(int) * count); XmLGridGetSelectedRows(_editWidget, rowPos, count); printf ("Selected Rows: "); for (i = 0; i < count; i++) printf ("%d ", rowPos[i]); printf ("\n"); free((char *)rowPos); } count = XmLGridGetSelectedColumnCount(_editWidget); if (count) { colPos = (int *)malloc(sizeof(int) * count); XmLGridGetSelectedColumns(_editWidget, colPos, count); printf ("Selected Columns: "); for (i = 0; i < count; i++) printf ("%d ", colPos[i]); printf ("\n"); free((char *)colPos); } count = XmLGridGetSelectedCellCount(_editWidget); if (count) { colPos = (int *)malloc(sizeof(int) * count); rowPos = (int *)malloc(sizeof(int) * count); XmLGridGetSelectedCells(_editWidget, rowPos, colPos, count); printf ("Selected Cells: "); for (i = 0; i < count; i++) printf ("[%d %d] ", rowPos[i], colPos[i]); printf ("\n"); free((char *)colPos); free((char *)rowPos); } } else if (!strcmp(op, "setCell") && n == 3) { printf ("WidgetEdit: set row %d col %d\n", l1, l2); _editRow = l1; _editCol = l2; } else if (!strcmp(op, "reorderColumns") && n == 1) { XtVaGetValues(_editWidget, XmNcolumns, &count, NULL); newPos = (int *)malloc(count * sizeof(int)); for (i = 0; i < count; i++) newPos[i] = i + 1; newPos[count - 1] = 0; XmLGridReorderColumns(_editWidget, newPos, 0, count); free((char *)newPos); } else if (!strcmp(op, "reorderRows") && n == 1) { XtVaGetValues(_editWidget, XmNrows, &count, NULL); newPos = (int *)malloc(count * sizeof(int)); for (i = 0; i < count; i++) newPos[i] = i + 1; newPos[count - 1] = 0; XmLGridReorderRows(_editWidget, newPos, 0, count); free((char *)newPos); } else if (!strcmp(op, "write") && n == 1) XmLGridWrite(_editWidget, stdout, XmFORMAT_DELIMITED, '|', True); else if (!strcmp(op, "writeXL") && n == 1) XmLGridWrite(_editWidget, stdout, XmFORMAT_XL, 0, True); else if (!strcmp(op, "writePAD") && n == 1) XmLGridWrite(_editWidget, stdout, XmFORMAT_PAD, 0, True); else if (!strcmp(op, "writePos") && n == 3) XmLGridWritePos(_editWidget, stdout, XmFORMAT_DELIMITED, '|', True, XmCONTENT, 0, XmCONTENT, 0, l1, l2); else fprintf(stderr, "WidgetEdit: unknown command %s\n", cmd); } XtFree(cmd); XmTextSetString(_editCommandT, ""); } static void _editChooseCB(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { Cursor cursor; Widget editW; cursor = XCreateFontCursor(XtDisplay(w), XC_hand2); editW = XmTrackingLocate(w, cursor, False); if (editW) SetEditWidget(editW); XFreeCursor(XtDisplay(w), cursor); } static void _editShowCB(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { XmToggleButtonCallbackStruct *cbs; cbs = (XmToggleButtonCallbackStruct *)callData; _editShowInherited = cbs->set; SetEditWidget(_editWidget); } static void _wmCloseCB(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { XtPopdown(XmLShellOfWidget((Widget)clientData)); _editDialogUp = False; } static void _editCloseCB(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { XtPopdown(XmLShellOfWidget(w)); _editDialogUp = False; } /* Callbacks which manipulate the Widget Editor */ static void folderCB(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { XmLFolderCallbackStruct *cbs; extern Widget _folder, _grid, _progress, _tree; cbs = (XmLFolderCallbackStruct *)callData; switch (cbs->pos) { case 2: _editWidget = _grid; break; case 3: _editWidget = _tree; break; case 4: _editWidget = _folder; break; case 5: _editWidget = _progress; break; default: _editWidget = 0; break; } if (_editDialogUp == True) SetEditWidget(_editWidget); } static void editCB(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { SetEditWidget(_editWidget); XtPopup(_editDialog, XtGrabNone); _editDialogUp = True; } /* Utility to add a sample tab and form to a folder, returning the form in the sample Folder created. */ static Widget AddWidgetSample(folder, name, desc) Widget folder; char *name, *desc; { Widget form, sampleFolder, sampleForm; XmString str; char buf[20]; int i; sprintf(buf, "%s Widget", name); str = XmStringCreateSimple(buf); form = XmLFolderAddTabForm(folder, str); XmStringFree(str); sampleFolder = XtVaCreateManagedWidget("sampleFolder", xmlFolderWidgetClass, form, XmNtabPlacement, XmFOLDER_RIGHT, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_POSITION, XmNbottomPosition, 55, XmNtabsPerRow, 3, NULL); for (i = 0; i < 3; i++) { if (!i) sprintf(buf, "%s One", name); else if (i == 1) sprintf(buf, "%s Two", name); else sprintf(buf, "%s Three", name); str = XmStringCreateSimple(buf); XmLFolderAddTab(sampleFolder, str); XmStringFree(str); } sampleForm = XtVaCreateManagedWidget("sampleForm", xmFormWidgetClass, sampleFolder, NULL); CreateText(form, desc, sampleFolder, 1); return sampleForm; } static void CreateText(form, data, topWidget, scrollVert) Widget form; char *data; Widget topWidget; int scrollVert; { Widget text, sb; int n; Arg args[20]; XtSetArg(args[0], XmNleftAttachment, XmATTACH_FORM); XtSetArg(args[1], XmNrightAttachment, XmATTACH_FORM); XtSetArg(args[2], XmNbottomAttachment, XmATTACH_FORM); XtSetArg(args[3], XmNwordWrap, True); XtSetArg(args[4], XmNscrollHorizontal, False); XtSetArg(args[5], XmNeditMode, XmMULTI_LINE_EDIT); XtSetArg(args[6], XmNeditable, False); XtSetArg(args[7], XmNcursorPositionVisible, False); XtSetArg(args[8], XmNhighlightThickness, 0); XtSetArg(args[9], XmNtopAttachment, XmATTACH_WIDGET); XtSetArg(args[10], XmNtopWidget, topWidget); n = 11; if (!scrollVert) { XtSetArg(args[11], XmNscrollVertical, False); n = 12; } text = XmCreateScrolledText(form, "text", args, n); XmTextSetString(text, data); XtManageChild(text); XtVaSetValues(text, XtVaTypedArg, XmNbackground, XmRString, "#D0D0D0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNshadowThickness, 0, NULL); if (scrollVert) { XtVaGetValues(XtParent(text), XmNverticalScrollBar, &sb, NULL); XtVaSetValues(sb, XmNshadowThickness, 2, NULL); } #ifndef MOTIF11 /* multiple drop site in the same area conflict with one another */ /* even if they are unmanaged - a Motif bug */ XmDropSiteUnregister(text); #endif } static void CreatePixmap(w, color, pixmap, pixmask, bits, width, height) Widget w; int color; Pixmap *pixmap, *pixmask; char *bits; int width, height; { Display *dpy; Window root; int depth; XColor col; Pixel black, white, fg, bg; dpy = XtDisplay(w); root = DefaultRootWindow(dpy); depth = DefaultDepthOfScreen(XtScreen(w)); black = BlackPixelOfScreen(XtScreen(w)); white = WhitePixelOfScreen(XtScreen(w)); XtVaGetValues(w, XmNbackground, &bg, NULL); col.red = 0; col.green = 0; col.blue = 0; if (color == 0) fg = white; else if (color == 1) fg = black; else { if (color == 2) col.green = 40000; else if (color == 3) col.red = 45000; else if (color == 4) col.blue = 30000; col.flags = DoRed | DoGreen | DoBlue; XAllocColor(dpy, DefaultColormapOfScreen(XtScreen(w)), &col); fg = col.pixel; } *pixmap = XCreatePixmapFromBitmapData(dpy, root, bits, width, height, fg, bg, depth); *pixmask = XCreatePixmapFromBitmapData(dpy, root, bits, width, height, 1L, 0L, 1); } /* Cover Tab Form */ #define cover_width 230 #define cover_height 240 static unsigned char cover_bits[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x80,0x07,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00, 0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x03,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0xff, 0x01,0x00,0xc0,0x0f,0x00,0x00,0xe0,0x00,0x80,0x03,0x00,0x00,0x3c,0x00,0x00, 0x00,0x00,0x38,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x80,0xff,0x01, 0x00,0x30,0x1c,0x00,0x00,0xe0,0x00,0x80,0x01,0x00,0x00,0x3e,0x00,0x00,0x00, 0x00,0x18,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x60,0xe0,0x01,0x00, 0x0c,0x38,0x00,0x00,0x20,0x00,0x80,0x01,0x00,0x80,0x01,0x00,0x00,0x00,0x00, 0x18,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x10,0xe0,0x00,0x00,0x06, 0x78,0x00,0x00,0x00,0x00,0xc0,0x01,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x1c, 0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x10,0xd0,0x00,0x00,0x03,0x70, 0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x0c,0x00, 0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x18,0xd8,0x00,0x80,0x01,0x70,0x00, 0x00,0x00,0x00,0xc0,0x00,0x00,0xe0,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00, 0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x18,0xc8,0x00,0x80,0x01,0x70,0x18,0x08, 0x30,0xe0,0xc0,0xe0,0x01,0x60,0x00,0x00,0x3c,0x00,0x0f,0x0c,0x1e,0x00,0x00, 0x00,0xc0,0x00,0x00,0x00,0x00,0x18,0xc4,0x00,0xc0,0x01,0x70,0x1e,0x0e,0x3c, 0xf0,0xe1,0xf0,0x01,0x70,0x00,0x00,0x7f,0xc0,0x1f,0x0e,0x1f,0x00,0x00,0x00, 0xc0,0x00,0x00,0x00,0x00,0x38,0xc6,0x00,0xc0,0x00,0xf0,0x0d,0x06,0x1b,0x8c, 0x61,0x98,0x00,0x70,0x00,0x80,0x79,0x60,0x1e,0x86,0x09,0x00,0x00,0x00,0xc0, 0x00,0x00,0x00,0x00,0x08,0xc3,0x00,0xe0,0x00,0x70,0x0c,0x06,0x18,0x8e,0x60, 0x04,0x00,0x30,0x00,0xe0,0x70,0x38,0x1c,0x46,0x00,0x00,0x00,0x00,0xc0,0x00, 0x00,0x00,0x00,0x00,0xe1,0x00,0xe0,0x00,0x70,0x0e,0x07,0x1c,0x06,0x70,0x03, 0x00,0x30,0x00,0x60,0x70,0x18,0x1c,0x37,0x00,0x00,0x00,0x00,0xc0,0x00,0x00, 0x00,0x00,0x80,0xe1,0x00,0xe0,0x00,0x30,0x06,0x03,0x1c,0x07,0xf0,0x01,0x00, 0x30,0x00,0x70,0x70,0x1c,0x1c,0x1f,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, 0x00,0xc0,0xff,0x00,0xe0,0x00,0x38,0x06,0x03,0x0c,0x07,0xf0,0x01,0x00,0x38, 0x00,0x30,0x70,0x0c,0x1c,0x1f,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00, 0x60,0xe0,0x00,0xe0,0x00,0x18,0x86,0x03,0x0c,0x03,0xb0,0x03,0x00,0x18,0x00, 0x39,0x30,0x0e,0x0c,0x3b,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x20, 0xe0,0x00,0xe0,0x00,0x18,0x87,0x01,0x8e,0x03,0x38,0x03,0x00,0x18,0x80,0x39, 0x38,0x0e,0x8e,0x33,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x10,0x60, 0x00,0xe0,0x00,0x0c,0x83,0x01,0x8e,0x03,0x38,0x03,0x00,0x0c,0x80,0x38,0x18, 0x0e,0x86,0x33,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x1c,0x60,0x00, 0xc0,0x01,0x06,0xc3,0x11,0x86,0x03,0x19,0x07,0x00,0x04,0xe0,0x38,0x0c,0x0e, 0x83,0x71,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0xc0,0x0f,0xe0,0x0c,0xc0, 0x01,0x03,0xb3,0x0d,0xe6,0xc3,0x18,0x06,0x80,0xff,0x7f,0x78,0x06,0x9e,0x81, 0x61,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0xc0,0x07,0xe0,0x07,0x80,0xc7, 0x81,0xcf,0x03,0x9f,0x3f,0x1c,0x0e,0xc0,0xff,0x7f,0xf8,0x03,0xfe,0xc0,0xe1, 0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0xe0,0x01,0x70,0x00,0x00,0xff,0x01, 0xc3,0x00,0x06,0x0f,0x0c,0x0c,0xe0,0xff,0x3f,0xf0,0x00,0x3c,0xc0,0xc0,0x00, 0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x00, 0x00,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x00, 0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x04,0x00, 0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x00, 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x04,0x00,0x00, 0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x00,0x00, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1e,0x04,0x00,0x00,0x00, 0x00,0x70,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x00,0x00,0x00,0xc0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x0e,0x00,0x00,0x00,0x00, 0xe0,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xce,0x00,0x00,0x00,0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x03,0x00,0x00,0x00,0x00,0x80, 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0xc0,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x0c,0x00,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06, 0x00,0x18,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00, 0x18,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x1c, 0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x01,0x03,0x00,0x0c,0x30, 0x38,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x07,0x03,0x00,0x0c,0x38,0x3c, 0xd8,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x84,0xe1,0x7f,0x80,0xff,0x39,0x3b,0xc6, 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x91,0x03,0x40,0x0e,0xd8,0x38,0xc7,0x01, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x83,0x81,0x01,0x00,0x06,0x38,0x18,0xe3,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x80,0xc3,0x81,0x01,0x00,0x06,0x1c,0x9c,0x33,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x80,0xc1,0xc0,0x01,0x00,0x07,0x0c,0x9c,0x1b,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x80,0xc1,0xc0,0x01,0x00,0x07,0x0c,0xcc,0x07,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xc0,0xe1,0xc0,0x00,0x00,0x03,0x0c,0xcc,0x01,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0xe1,0xc0,0x00,0x00,0x03,0x0e,0xce,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x71, 0xe4,0x10,0x80,0x43,0x06,0xce,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x6d,0xe3, 0x0c,0x80,0x33,0x06,0xee,0xe3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xe3,0xe0,0x03, 0x80,0x0f,0x07,0xde,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x31,0xc0,0x00,0x00, 0x03,0x01,0x86,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xc0,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x3f,0xc0,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x3f,0xc0,0xfc,0xff,0xff,0xff,0xff,0x3f,0xf8,0xff,0xff,0xff,0x1f,0xfe, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x3f,0xc0,0x0c,0xfe,0x1f,0x3e,0xfc,0x07,0xe3,0x0f,0x00,0xff,0x03,0xf0,0x1f, 0xfe,0x0f,0x1f,0xfe,0xcf,0x07,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f, 0xc0,0x0c,0xfe,0x1f,0x3e,0xfc,0xc3,0xdf,0x0f,0x1f,0xfc,0xf1,0xc3,0x1f,0xfe, 0x0f,0x1f,0xfc,0xcf,0x87,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xc0, 0x0c,0xfc,0x0f,0x3e,0xfc,0xf1,0x9f,0x0f,0x3f,0xfc,0xf8,0x87,0x1f,0xfe,0x0f, 0x1f,0xfc,0xcf,0x87,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xc0,0x0c, 0xfc,0x0f,0x3e,0xfc,0xf8,0x3f,0x0f,0x7f,0x7c,0xf8,0x0f,0x1f,0xfe,0x0f,0x1f, 0xf8,0xcf,0x87,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xc0,0x0c,0xf8, 0x07,0x3e,0x7c,0xf8,0x7f,0x0e,0x7f,0x78,0xfc,0x0f,0x1f,0xfe,0x0f,0x1f,0xf0, 0xcf,0x87,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xc0,0x0c,0xf8,0x07, 0x3e,0x7c,0xfc,0xff,0x0f,0x7f,0x38,0xfc,0x1f,0x1e,0xfe,0x0f,0x9f,0xf0,0xcf, 0x87,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xc0,0x4c,0xf8,0x17,0x3e, 0x3c,0xfc,0xff,0x0f,0x7f,0x38,0xfe,0x1f,0x1e,0xfe,0x0f,0x9f,0xe0,0xcf,0x87, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xc0,0x4c,0xf0,0x13,0x3e,0x3c, 0xfc,0xff,0x0f,0x7f,0x18,0xfe,0x1f,0x1e,0xfe,0x0f,0x9f,0xc1,0xcf,0x87,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xc0,0xcc,0xf0,0x13,0x3e,0x3c,0xfc, 0xff,0x0f,0x7f,0x18,0xfe,0x1f,0x1c,0xfe,0x0f,0x9f,0x83,0xcf,0x87,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xc0,0xcc,0xe0,0x19,0x3e,0x1c,0xfe,0xff, 0x0f,0x3f,0x1c,0xfe,0x1f,0x1c,0xfe,0x0f,0x9f,0x83,0xcf,0x87,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x3f,0xc0,0xcc,0xe1,0x19,0x3e,0x1c,0xfe,0xff,0x0f, 0x1f,0x1c,0xfe,0x3f,0x1c,0xfe,0x0f,0x9f,0x07,0xcf,0x07,0x80,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x3f,0xc0,0xcc,0xe1,0x1d,0x3e,0x1c,0xfe,0xff,0x0f,0x01, 0x1f,0xfe,0x3f,0x1c,0xfe,0x0f,0x9f,0x0f,0xce,0x07,0x80,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x3f,0xc0,0xcc,0xc1,0x1c,0x3e,0x1c,0xfe,0xff,0x0f,0xc3,0x1f, 0xfe,0x3f,0x1c,0xfe,0x0f,0x9f,0x0f,0xce,0x87,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x3f,0xc0,0xcc,0xc3,0x1c,0x3e,0x1c,0xfe,0xff,0x0f,0xc3,0x1f,0xfe, 0x3f,0x1c,0xfe,0x0f,0x9f,0x1f,0xcc,0x87,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x3f,0xc0,0xcc,0x03,0x1e,0x3e,0x1c,0xfc,0xff,0x0f,0x87,0x1f,0xfe,0x1f, 0x1c,0xfe,0x0f,0x9f,0x3f,0xc8,0x87,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x3f,0xc0,0xcc,0x07,0x1e,0x3e,0x1c,0xfc,0xff,0x0f,0x87,0x1f,0xfe,0x1f,0x1e, 0xfe,0x0f,0x9f,0x7f,0xc8,0x87,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f, 0xc0,0xcc,0x07,0x1e,0x3e,0x3c,0xfc,0xff,0x0f,0x0f,0x3f,0xfe,0x1f,0x1e,0xfe, 0x0f,0x9f,0x7f,0xc0,0x87,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xc0, 0xcc,0x07,0x1f,0x3e,0x3c,0xfc,0xff,0x0c,0x0f,0x3f,0xfc,0x1f,0x1e,0xfe,0x0f, 0x9f,0xff,0xc0,0x87,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xc0,0xcc, 0x0f,0x1f,0x3e,0x7c,0xf8,0x7f,0x0e,0x1f,0x3e,0xfc,0x0f,0x1f,0xfe,0x0f,0x9f, 0xff,0xc1,0x87,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xc0,0xcc,0x8f, 0x1f,0x3e,0xfc,0xf0,0x3f,0x0f,0x1f,0x7e,0xfc,0x8f,0x1f,0xfe,0x0f,0x9f,0xff, 0xc1,0x87,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xc0,0xcc,0x9f,0x1f, 0x3e,0xfc,0xe0,0x1f,0x0f,0x3f,0xfc,0xf8,0x87,0x1f,0xfe,0x0f,0x9f,0xff,0xc3, 0x87,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xc0,0xcc,0x9f,0x1f,0x3e, 0xfc,0x83,0x87,0x0f,0x3f,0xfc,0xf1,0xc3,0x1f,0x00,0x0c,0x9f,0xff,0xc7,0x07, 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xc0,0xcc,0xff,0x1f,0x3e,0xfc, 0x07,0xe0,0x0f,0x7f,0xf8,0x03,0xf0,0x1f,0x00,0x0c,0x9f,0xff,0xc7,0x07,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xc0,0xfc,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xc0,0xfc,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x3f,0xc0,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x3f,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xc0,0xf0,0x07,0xf8,0x03,0xfc,0xf9,0x81,0xff,0xff,0x00, 0x00,0xf8,0x0f,0x00,0xfc,0xff,0x7f,0xfe,0xff,0xff,0x01,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc0,0xe0,0x07,0xf8,0x03,0xfc,0xf8,0x81,0xff,0xff,0x03,0x00, 0xff,0x7f,0x00,0xfc,0xff,0x7f,0xfe,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xc0,0xe0,0x07,0xf8,0x07,0xfc,0xf8,0x81,0xff,0xff,0x0f,0x80,0xff, 0xff,0x01,0xfc,0xff,0x7f,0xfe,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0xe0,0x0f,0xf8,0x07,0xfc,0xf8,0x81,0xff,0xff,0x1f,0xc0,0xff,0xff, 0x03,0xfc,0xff,0x7f,0xfe,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xc0,0xc0,0x0f,0xfc,0x07,0x7e,0xf8,0x81,0x1f,0xc0,0x3f,0xe0,0x0f,0xf8,0x07, 0xfc,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0xc0,0x0f,0xfc,0x07,0x7e,0xf8,0x81,0x1f,0x00,0x3f,0xf0,0x07,0xe0,0x0f,0xfc, 0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xc0, 0x0f,0xbc,0x0f,0x7e,0xf8,0x81,0x1f,0x00,0x7f,0xf8,0x03,0xc0,0x0f,0xfc,0x00, 0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x80,0x1f, 0xbc,0x0f,0x3e,0xf8,0x81,0x1f,0x00,0x7e,0xf8,0x01,0x00,0x00,0xfc,0x00,0x00, 0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x80,0x1f,0xbe, 0x0f,0x3f,0xf8,0x81,0x1f,0x00,0xfe,0xf8,0x01,0x00,0x00,0xfc,0x00,0x00,0x00, 0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x80,0x1f,0xbe,0x0f, 0x3f,0xf8,0x81,0x1f,0x00,0xfc,0xfc,0x00,0x00,0x00,0xfc,0xff,0x3f,0x00,0xfc, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x1f,0x1e,0x1f,0x1f, 0xf8,0x81,0x1f,0x00,0xfc,0xfc,0x00,0xfe,0x0f,0xfc,0xff,0x3f,0x00,0xfc,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x3f,0x1e,0x1f,0x1f,0xf8, 0x81,0x1f,0x00,0xfc,0xfc,0x00,0xfe,0x0f,0xfc,0xff,0x3f,0x00,0xfc,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x3f,0x1f,0x9f,0x1f,0xf8,0x81, 0x1f,0x00,0xfc,0xfc,0x00,0xfe,0x0f,0xfc,0xff,0x3f,0x00,0xfc,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x3e,0x1f,0x9e,0x0f,0xf8,0x81,0x1f, 0x00,0xfc,0xfc,0x00,0xfe,0x0f,0xfc,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x7e,0x0f,0xbe,0x0f,0xf8,0x81,0x1f,0x00, 0xfc,0xfc,0x01,0x80,0x0f,0xfc,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xc0,0x00,0x7e,0x0f,0xbe,0x0f,0xf8,0x81,0x1f,0x00,0x7e, 0xf8,0x01,0x80,0x0f,0xfc,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc0,0x00,0xfc,0x0f,0xfc,0x07,0xf8,0x81,0x1f,0x00,0x7f,0xf8, 0x03,0xc0,0x0f,0xfc,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xc0,0x00,0xfc,0x07,0xfc,0x07,0xf8,0x81,0x1f,0x00,0x3f,0xf0,0x07, 0xe0,0x0f,0xfc,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0x00,0xf8,0x07,0xfc,0x07,0xf8,0x81,0x1f,0xc0,0x3f,0xe0,0x1f,0xf8, 0x0f,0xfc,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xc0,0x00,0xf8,0x07,0xfc,0x03,0xf8,0x81,0xff,0xff,0x1f,0xc0,0xff,0xff,0x0f, 0xfc,0xff,0xff,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0x00,0xf8,0x07,0xf8,0x03,0xf8,0x81,0xff,0xff,0x0f,0x80,0xff,0x7f,0x0f,0xfc, 0xff,0xff,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00, 0xf0,0x03,0xf8,0x03,0xf8,0x81,0xff,0xff,0x03,0x00,0xfe,0x3f,0x0f,0xfc,0xff, 0xff,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0xf0, 0x03,0xf8,0x01,0xf8,0x81,0xff,0xff,0x00,0x00,0xf0,0x07,0x0f,0xfc,0xff,0xff, 0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xc0,0x01,0x00,0x3c,0xf0,0xff,0x07,0xe0,0xff,0x0f,0x00,0x80,0x03,0x00,0xfe, 0xff,0xe1,0x03,0x00,0x38,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0x01,0x00,0x3c,0xf0,0x00,0x1f,0xe0,0x01,0x3f,0x00,0x80,0x03,0x00,0x1e,0xe0, 0xc3,0x07,0x00,0x1c,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01, 0x00,0x3c,0xf0,0x00,0x3c,0xe0,0x01,0x78,0x00,0xc0,0x07,0x00,0x1e,0x80,0x8f, 0x0f,0x00,0x0e,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x00, 0x3c,0xf0,0x00,0x3c,0xe0,0x01,0xf8,0x00,0xc0,0x07,0x00,0x1e,0x00,0x0f,0x1f, 0x00,0xe7,0xc7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x00,0x3c, 0xf0,0x00,0x3c,0xe0,0x01,0xf0,0x00,0x60,0x0f,0x00,0x1e,0x00,0x0f,0x1e,0x80, 0x43,0xc7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x00,0x3c,0xf0, 0x00,0x3c,0xe0,0x01,0xf0,0x00,0x30,0x1f,0x00,0x1e,0x00,0x0f,0x3c,0x80,0x41, 0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x00,0x3c,0xf0,0x00, 0x3c,0xe0,0x01,0x78,0x00,0x30,0x1e,0x00,0x1e,0x00,0x0f,0x78,0xc0,0x01,0xc0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x00,0x3c,0xf0,0x00,0x1c, 0xe0,0x01,0x78,0x00,0x18,0x3c,0x00,0x1e,0x80,0x07,0xf8,0xe0,0x00,0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x00,0x3c,0xf0,0x80,0x07,0xe0, 0x01,0x3e,0x00,0x18,0x3c,0x00,0x1e,0xc0,0x03,0xf0,0x61,0x00,0xc0,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x00,0x3c,0xf0,0xff,0x00,0xe0,0xff, 0x07,0x00,0x0c,0x78,0x00,0xfe,0x7f,0x00,0xe0,0x19,0x00,0xc0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x00,0x3c,0xf0,0xc0,0x0f,0xe0,0x7f,0x00, 0x00,0x0c,0xf8,0x00,0xfe,0x07,0x00,0xc0,0x1f,0x00,0xc0,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xc0,0x01,0x00,0x3c,0xf0,0x00,0x1e,0xe0,0xfd,0x00,0x00, 0xfe,0xff,0x00,0x9e,0x0f,0x00,0x80,0x0f,0x00,0xc0,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc0,0x01,0x00,0x3c,0xf0,0x00,0x7c,0xe0,0xf9,0x00,0x00,0xff, 0xff,0x01,0x1e,0x1f,0x00,0x00,0x0f,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xc0,0x01,0x00,0x3c,0xf0,0x00,0x78,0xe0,0xf1,0x03,0x00,0x03,0xe0, 0x01,0x1e,0x3e,0x00,0x00,0x0f,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0x01,0x00,0x3c,0xf0,0x00,0x78,0xe0,0xc1,0x07,0x80,0x01,0xc0,0x03, 0x1e,0x78,0x00,0x00,0x0f,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xc0,0x01,0x00,0x3c,0xf0,0x00,0x78,0xe0,0x81,0x07,0x80,0x01,0xc0,0x03,0x1e, 0xf0,0x00,0x00,0x0f,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0x01,0x00,0x3c,0xf0,0x00,0x78,0xe0,0x01,0x1f,0xc0,0x00,0x80,0x07,0x1e,0xe0, 0x03,0x00,0x0f,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01, 0x00,0x3c,0xf0,0x00,0x78,0xe0,0x01,0x3e,0xe0,0x00,0x00,0x0f,0x1e,0xc0,0x07, 0x00,0x0f,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x00, 0x3c,0xf0,0x00,0x3c,0xe0,0x01,0x7c,0x60,0x00,0x00,0x0e,0x1e,0x80,0x07,0x00, 0x0f,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x1f,0x3c, 0xf0,0x00,0x0f,0xe0,0x01,0xf8,0x71,0x00,0x00,0x1e,0x1e,0x00,0x1f,0x00,0x0f, 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0x1f,0x3c,0xf0, 0xff,0x03,0xe0,0x01,0xe0,0x33,0x00,0x00,0x1c,0x1e,0x00,0x3e,0x00,0x0f,0x00, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0, 0x03,0x00,0xfc,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x0f, 0x00,0xfe,0x01,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x1c,0x00, 0x87,0x03,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x18,0x00,0x03, 0x03,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x18,0x80,0x01,0x06, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x80,0x01,0x06,0xc0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x80,0x01,0x06,0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x07,0x80,0x01,0x06,0xc0,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x0f,0x80,0x01,0x06,0xc0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x80,0x01,0x06,0xc0,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x30,0x80,0x01,0x06,0xc0,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x30,0x80,0x01,0x06,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x30,0x80,0x01,0x06,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x0c,0x30,0x80,0x01,0x06,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x1c,0x38,0x00,0x03,0x03,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18, 0x1c,0x00,0x87,0x03,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x0f, 0x06,0xfe,0x01,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x03,0x06, 0xfc,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00, 0x00,0x80,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, 0x40,0x20,0x40,0x70,0x38,0x3c,0x00,0x82,0xc3,0xe1,0x40,0x90,0x00,0x00,0x48, 0x00,0x00,0x78,0x00,0x1c,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x20, 0x46,0x60,0x88,0x44,0x04,0x00,0x43,0x24,0x12,0xc1,0x18,0x00,0x00,0x08,0x00, 0x00,0x84,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x10,0x89, 0x50,0x88,0x44,0x02,0x80,0x42,0x24,0x12,0xc0,0x98,0x18,0xe5,0x48,0x1a,0x0e, 0x84,0x38,0x7f,0x44,0x8e,0x72,0x00,0x00,0xc0,0x00,0x00,0x00,0x90,0x90,0x40, 0x88,0x44,0x1e,0x00,0x42,0x24,0xd2,0x40,0x95,0x24,0x13,0x49,0x26,0x11,0x04, 0x44,0x52,0x44,0x91,0x89,0x00,0x00,0xc0,0x00,0x00,0x00,0x90,0x80,0x40,0xc8, 0x64,0x22,0x00,0x42,0x26,0x33,0x41,0x95,0x04,0x11,0x49,0x22,0x11,0x78,0x44, 0x92,0x2a,0x90,0x88,0x00,0x00,0xc0,0x00,0x00,0x00,0x90,0x80,0x40,0xb0,0x58, 0x20,0x00,0x82,0xc5,0x12,0x41,0x95,0x04,0x11,0x49,0x22,0x1f,0x80,0x44,0x92, 0x2a,0x9e,0xf8,0x00,0x00,0xc0,0x00,0x00,0x00,0x90,0x90,0x40,0x80,0x40,0x20, 0x00,0x02,0x04,0x12,0x41,0x95,0x04,0x11,0x49,0x22,0x01,0x84,0x44,0x92,0x2a, 0x91,0x08,0x00,0x00,0xc0,0x00,0x00,0x00,0x10,0x89,0x40,0x88,0x44,0x22,0x00, 0x42,0x24,0x12,0x41,0x92,0x24,0x11,0x49,0x22,0x11,0x84,0x44,0x12,0x11,0x99, 0x88,0x00,0x00,0xc0,0x00,0x00,0x00,0x20,0x46,0x40,0x70,0x38,0x1c,0x02,0x82, 0xc3,0xe1,0x40,0x92,0x18,0xe1,0x48,0x22,0x0e,0x78,0x38,0x32,0x11,0x96,0x70, 0x00,0x00,0xc0,0x00,0x00,0x00,0x40,0x20,0x00,0x00,0x00,0x00,0x02,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0x00,0x00,0x00,0x80,0x1f,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0 }; Pixmap coverPixmapW, coverPixmapB, coverPixmask; GC coverGC; static void CoverExpose(); void AddCoverTabForm(folder) Widget folder; { Widget form, da; Display *dpy; Window root; XmString str; str = XmStringCreateSimple("Cover Page"); form = XmLFolderAddTabForm(folder, str); XmStringFree(str); CreatePixmap(form, 0, &coverPixmapW, &coverPixmask, (char *)cover_bits, cover_width, cover_height); CreatePixmap(form, 1, &coverPixmapB, &coverPixmask, (char *)cover_bits, cover_width, cover_height); dpy = XtDisplay(form); root = DefaultRootWindow(dpy); coverGC = XCreateGC(dpy, root, 0, NULL); da = XtVaCreateManagedWidget("drawArea", xmDrawingAreaWidgetClass, form, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); XtAddCallback(da, XmNexposeCallback, CoverExpose, NULL); } static void CoverExpose(w, clientData, callData) Widget w; XtPointer clientData, callData; { XRectangle rect; Pixel black, white; XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, False); black = BlackPixelOfScreen(XtScreen(w)); white = WhitePixelOfScreen(XtScreen(w)); rect.x = 1; rect.y = 1; XtVaGetValues(w, XmNwidth, &rect.width, XmNheight, &rect.height, NULL); XmLPixmapDraw(w, coverPixmapW, coverPixmask, cover_width, cover_height, XmALIGNMENT_CENTER, coverGC, &rect, &rect); rect.x = 0; rect.y = 0; XmLPixmapDraw(w, coverPixmapB, coverPixmask, cover_width, cover_height, XmALIGNMENT_CENTER, coverGC, &rect, &rect); } /* Intro Tab Form */ #define logo_width 230 #define logo_height 90 static unsigned char logo_bits[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xf8,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc0,0xf8,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc0,0xf8,0xff,0xff,0xff,0xff,0x7f, 0xf0,0xff,0xff,0xff,0x3f,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc0,0x18,0xfc,0x3f,0x7c,0xf8,0x0f,0xc6, 0x1f,0x00,0xfe,0x07,0xe0,0x3f,0xfc,0x1f,0x3e,0xfc,0x9f,0x0f,0x00,0xfe,0xff, 0xff,0xff,0xff,0xff,0xff,0x7f,0xc0,0x18,0xfc,0x3f,0x7c,0xf8,0x87,0xbf,0x1f, 0x3e,0xf8,0xe3,0x87,0x3f,0xfc,0x1f,0x3e,0xf8,0x9f,0x0f,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x7f,0xc0,0x18,0xf8,0x1f,0x7c,0xf8,0xe3,0x3f,0x1f,0x7e, 0xf8,0xf1,0x0f,0x3f,0xfc,0x1f,0x3e,0xf8,0x9f,0x0f,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x7f,0xc0,0x18,0xf8,0x1f,0x7c,0xf8,0xf1,0x7f,0x1e,0xfe,0xf8, 0xf0,0x1f,0x3e,0xfc,0x1f,0x3e,0xf0,0x9f,0x0f,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x7f,0xc0,0x18,0xf0,0x0f,0x7c,0xf8,0xf0,0xff,0x1c,0xfe,0xf0,0xf8, 0x1f,0x3e,0xfc,0x1f,0x3e,0xe0,0x9f,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x7f,0xc0,0x18,0xf0,0x0f,0x7c,0xf8,0xf8,0xff,0x1f,0xfe,0x70,0xf8,0x3f, 0x3c,0xfc,0x1f,0x3e,0xe1,0x9f,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x7f,0xc0,0x98,0xf0,0x2f,0x7c,0x78,0xf8,0xff,0x1f,0xfe,0x70,0xfc,0x3f,0x3c, 0xfc,0x1f,0x3e,0xc1,0x9f,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, 0xc0,0x98,0xe0,0x27,0x7c,0x78,0xf8,0xff,0x1f,0xfe,0x30,0xfc,0x3f,0x3c,0xfc, 0x1f,0x3e,0x83,0x9f,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc0, 0x98,0xe1,0x27,0x7c,0x78,0xf8,0xff,0x1f,0xfe,0x30,0xfc,0x3f,0x38,0xfc,0x1f, 0x3e,0x07,0x9f,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc0,0x98, 0xc1,0x33,0x7c,0x38,0xfc,0xff,0x1f,0x7e,0x38,0xfc,0x3f,0x38,0xfc,0x1f,0x3e, 0x07,0x9f,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc0,0x98,0xc3, 0x33,0x7c,0x38,0xfc,0xff,0x1f,0x3e,0x38,0xfc,0x7f,0x38,0xfc,0x1f,0x3e,0x0f, 0x9e,0x0f,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc0,0x98,0xc3,0x3b, 0x7c,0x38,0xfc,0xff,0x1f,0x02,0x3e,0xfc,0x7f,0x38,0xfc,0x1f,0x3e,0x1f,0x9c, 0x0f,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc0,0x98,0x83,0x39,0x7c, 0x38,0xfc,0xff,0x1f,0x86,0x3f,0xfc,0x7f,0x38,0xfc,0x1f,0x3e,0x1f,0x9c,0x0f, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc0,0x98,0x87,0x39,0x7c,0x38, 0xfc,0xff,0x1f,0x86,0x3f,0xfc,0x7f,0x38,0xfc,0x1f,0x3e,0x3f,0x98,0x0f,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc0,0x98,0x07,0x3c,0x7c,0x38,0xf8, 0xff,0x1f,0x0e,0x3f,0xfc,0x3f,0x38,0xfc,0x1f,0x3e,0x7f,0x90,0x0f,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc0,0x98,0x0f,0x3c,0x7c,0x38,0xf8,0xff, 0x1f,0x0e,0x3f,0xfc,0x3f,0x3c,0xfc,0x1f,0x3e,0xff,0x90,0x0f,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0x7f,0xc0,0x98,0x0f,0x3c,0x7c,0x78,0xf8,0xff,0x1f, 0x1e,0x7e,0xfc,0x3f,0x3c,0xfc,0x1f,0x3e,0xff,0x80,0x0f,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x7f,0xc0,0x98,0x0f,0x3e,0x7c,0x78,0xf8,0xff,0x19,0x1e, 0x7e,0xf8,0x3f,0x3c,0xfc,0x1f,0x3e,0xff,0x81,0x0f,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x7f,0xc0,0x98,0x1f,0x3e,0x7c,0xf8,0xf0,0xff,0x1c,0x3e,0x7c, 0xf8,0x1f,0x3e,0xfc,0x1f,0x3e,0xff,0x83,0x0f,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0x7f,0xc0,0x98,0x1f,0x3f,0x7c,0xf8,0xe1,0x7f,0x1e,0x3e,0xfc,0xf8, 0x1f,0x3f,0xfc,0x1f,0x3e,0xff,0x83,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x7f,0xc0,0x98,0x3f,0x3f,0x7c,0xf8,0xc1,0x3f,0x1e,0x7e,0xf8,0xf1,0x0f, 0x3f,0xfc,0x1f,0x3e,0xff,0x87,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x7f,0xc0,0x98,0x3f,0x3f,0x7c,0xf8,0x07,0x0f,0x1f,0x7e,0xf8,0xe3,0x87,0x3f, 0x00,0x18,0x3e,0xff,0x8f,0x0f,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, 0xc0,0x98,0xff,0x3f,0x7c,0xf8,0x0f,0xc0,0x1f,0xfe,0xf0,0x07,0xe0,0x3f,0x00, 0x18,0x3e,0xff,0x8f,0x0f,0x00,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc0, 0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc0,0xf8, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc0,0xf8,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xe0,0x0f,0xf0,0x07, 0xf8,0xf3,0x03,0xff,0xff,0x01,0x00,0xf0,0x1f,0x00,0xf8,0xff,0xff,0xfc,0xff, 0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xc0,0x0f,0xf0,0x07,0xf8, 0xf1,0x03,0xff,0xff,0x07,0x00,0xfe,0xff,0x00,0xf8,0xff,0xff,0xfc,0xff,0xff, 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xc0,0x0f,0xf0,0x0f,0xf8,0xf1, 0x03,0xff,0xff,0x1f,0x00,0xff,0xff,0x03,0xf8,0xff,0xff,0xfc,0xff,0xff,0x03, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xc0,0x1f,0xf0,0x0f,0xf8,0xf1,0x03, 0xff,0xff,0x3f,0x80,0xff,0xff,0x07,0xf8,0xff,0xff,0xfc,0xff,0xff,0x03,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x80,0x1f,0xf8,0x0f,0xfc,0xf0,0x03,0x3f, 0x80,0x7f,0xc0,0x1f,0xf0,0x0f,0xf8,0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xc0,0x80,0x1f,0xf8,0x0f,0xfc,0xf0,0x03,0x3f,0x00, 0x7e,0xe0,0x0f,0xc0,0x1f,0xf8,0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xc0,0x80,0x1f,0x78,0x1f,0xfc,0xf0,0x03,0x3f,0x00,0xfe, 0xf0,0x07,0x80,0x1f,0xf8,0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc0,0x00,0x3f,0x78,0x1f,0x7c,0xf0,0x03,0x3f,0x00,0xfc,0xf0, 0x03,0x00,0x00,0xf8,0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xc0,0x00,0x3f,0x7c,0x1f,0x7e,0xf0,0x03,0x3f,0x00,0xfc,0xf1,0x03, 0x00,0x00,0xf8,0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0x00,0x3f,0x7c,0x1f,0x7e,0xf0,0x03,0x3f,0x00,0xf8,0xf9,0x01,0x00, 0x00,0xf8,0xff,0x7f,0x00,0xf8,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xc0,0x00,0x3e,0x3c,0x3e,0x3e,0xf0,0x03,0x3f,0x00,0xf8,0xf9,0x01,0xfc,0x1f, 0xf8,0xff,0x7f,0x00,0xf8,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0x00,0x7e,0x3c,0x3e,0x3e,0xf0,0x03,0x3f,0x00,0xf8,0xf9,0x01,0xfc,0x1f,0xf8, 0xff,0x7f,0x00,0xf8,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00, 0x7e,0x3e,0x3e,0x3f,0xf0,0x03,0x3f,0x00,0xf8,0xf9,0x01,0xfc,0x1f,0xf8,0xff, 0x7f,0x00,0xf8,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x7c, 0x3e,0x3c,0x1f,0xf0,0x03,0x3f,0x00,0xf8,0xf9,0x01,0xfc,0x1f,0xf8,0x01,0x00, 0x00,0xf8,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0xfc,0x1e, 0x7c,0x1f,0xf0,0x03,0x3f,0x00,0xf8,0xf9,0x03,0x00,0x1f,0xf8,0x01,0x00,0x00, 0xf8,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0xfc,0x1e,0x7c, 0x1f,0xf0,0x03,0x3f,0x00,0xfc,0xf0,0x03,0x00,0x1f,0xf8,0x01,0x00,0x00,0xf8, 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0xf8,0x1f,0xf8,0x0f, 0xf0,0x03,0x3f,0x00,0xfe,0xf0,0x07,0x80,0x1f,0xf8,0x01,0x00,0x00,0xf8,0x01, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0xf8,0x0f,0xf8,0x0f,0xf0, 0x03,0x3f,0x00,0x7e,0xe0,0x0f,0xc0,0x1f,0xf8,0x01,0x00,0x00,0xf8,0x01,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0xf0,0x0f,0xf8,0x0f,0xf0,0x03, 0x3f,0x80,0x7f,0xc0,0x3f,0xf0,0x1f,0xf8,0x01,0x00,0x00,0xf8,0x01,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0xf0,0x0f,0xf8,0x07,0xf0,0x03,0xff, 0xff,0x3f,0x80,0xff,0xff,0x1f,0xf8,0xff,0xff,0x01,0xf8,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0xf0,0x0f,0xf0,0x07,0xf0,0x03,0xff,0xff, 0x1f,0x00,0xff,0xff,0x1e,0xf8,0xff,0xff,0x01,0xf8,0x01,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xc0,0x00,0xe0,0x07,0xf0,0x07,0xf0,0x03,0xff,0xff,0x07, 0x00,0xfc,0x7f,0x1e,0xf8,0xff,0xff,0x01,0xf8,0x01,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc0,0x00,0xe0,0x07,0xf0,0x03,0xf0,0x03,0xff,0xff,0x01,0x00, 0xe0,0x0f,0x1e,0xf8,0xff,0xff,0x01,0xf8,0x01,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x78,0xe0,0xff,0x0f,0xc0,0xff, 0x1f,0x00,0x00,0x07,0x00,0xfc,0xff,0xc3,0x07,0x00,0x70,0xc0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x78,0xe0,0x01,0x3e,0xc0,0x03,0x7e, 0x00,0x00,0x07,0x00,0x3c,0xc0,0x87,0x0f,0x00,0x38,0xc0,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x78,0xe0,0x01,0x78,0xc0,0x03,0xf0,0x00, 0x80,0x0f,0x00,0x3c,0x00,0x1f,0x1f,0x00,0x1c,0xc0,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x80,0x03,0x00,0x78,0xe0,0x01,0x78,0xc0,0x03,0xf0,0x01,0x80, 0x0f,0x00,0x3c,0x00,0x1e,0x3e,0x00,0xce,0xcf,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x80,0x03,0x00,0x78,0xe0,0x01,0x78,0xc0,0x03,0xe0,0x01,0xc0,0x1e, 0x00,0x3c,0x00,0x1e,0x3c,0x00,0x87,0xce,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x80,0x03,0x00,0x78,0xe0,0x01,0x78,0xc0,0x03,0xe0,0x01,0x60,0x3e,0x00, 0x3c,0x00,0x1e,0x78,0x00,0x83,0xca,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x80,0x03,0x00,0x78,0xe0,0x01,0x78,0xc0,0x03,0xf0,0x00,0x60,0x3c,0x00,0x3c, 0x00,0x1e,0xf0,0x80,0x03,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, 0x03,0x00,0x78,0xe0,0x01,0x38,0xc0,0x03,0xf0,0x00,0x30,0x78,0x00,0x3c,0x00, 0x0f,0xf0,0xc1,0x01,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03, 0x00,0x78,0xe0,0x01,0x0f,0xc0,0x03,0x7c,0x00,0x30,0x78,0x00,0x3c,0x80,0x07, 0xe0,0xc3,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00, 0x78,0xe0,0xff,0x01,0xc0,0xff,0x0f,0x00,0x18,0xf0,0x00,0xfc,0xff,0x00,0xc0, 0x33,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x78, 0xe0,0x81,0x1f,0xc0,0xff,0x00,0x00,0x18,0xf0,0x01,0xfc,0x0f,0x00,0x80,0x3f, 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x78,0xe0, 0x01,0x3c,0xc0,0xfb,0x01,0x00,0xfc,0xff,0x01,0x3c,0x1f,0x00,0x00,0x1f,0x00, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x78,0xe0,0x01, 0xf8,0xc0,0xf3,0x01,0x00,0xfe,0xff,0x03,0x3c,0x3e,0x00,0x00,0x1e,0x00,0xc0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x78,0xe0,0x01,0xf0, 0xc0,0xe3,0x07,0x00,0x06,0xc0,0x03,0x3c,0x7c,0x00,0x00,0x1e,0x00,0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x78,0xe0,0x01,0xf0,0xc0, 0x83,0x0f,0x00,0x03,0x80,0x07,0x3c,0xf0,0x00,0x00,0x1e,0x00,0xc0,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x78,0xe0,0x01,0xf0,0xc0,0x03, 0x0f,0x00,0x03,0x80,0x07,0x3c,0xe0,0x01,0x00,0x1e,0x00,0xc0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x78,0xe0,0x01,0xf0,0xc0,0x03,0x3e, 0x80,0x01,0x00,0x0f,0x3c,0xc0,0x07,0x00,0x1e,0x00,0xc0,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x78,0xe0,0x01,0xf0,0xc0,0x03,0x7c,0xc0, 0x01,0x00,0x1e,0x3c,0x80,0x0f,0x00,0x1e,0x00,0xc0,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x80,0x03,0x00,0x78,0xe0,0x01,0x78,0xc0,0x03,0xf8,0xc0,0x00, 0x00,0x1c,0x3c,0x00,0x0f,0x00,0x1e,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x80,0x03,0x3e,0x78,0xe0,0x01,0x1e,0xc0,0x03,0xf0,0xe3,0x00,0x00, 0x3c,0x3c,0x00,0x3e,0x00,0x1e,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x80,0xff,0x3f,0x78,0xe0,0xff,0x07,0xc0,0x03,0xc0,0x67,0x00,0x00,0x38, 0x3c,0x00,0x7c,0x00,0x1e,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0 }; void AddIntroTabForm(folder) Widget folder; { Widget form, label; Pixmap pixmap, pixmask; XmString str; static char *desc = "Welcome to a Quick Look at the Microline Widget Library version 3.0. \ This program presents an overview of widgets contained in the library.\ \n\n\ If you understand widget resources, you may want to try clicking the Editor \ button to display and edit some of the example widget's resources. \ Please note that the editor is blank for the Cover Page and this \ Introduction screen.\ \n\n\ Further information on the library including pricing, supported platforms, \ licensing policies, etc. may be found on our web site \ http://www.mlsoft.com. You can also email us at info@mlsoft.com.\ \n\n\ Microline Widget Library is a trademark of Microline Software. \ All other trademarks are the property of their respective owners."; str = XmStringCreateSimple("Introduction"); form = XmLFolderAddTabForm(folder, str); XmStringFree(str); CreatePixmap(form, 1, &pixmap, &pixmask, (char *)logo_bits, logo_width, logo_height); label = XtVaCreateManagedWidget("label", xmLabelWidgetClass, form, XmNlabelType, XmPIXMAP, XmNlabelPixmap, pixmap, XmNmarginHeight, 25, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); CreateText(form, desc, label, 0); } /* Folder Tab Form */ #define sphere_width 10 #define sphere_height 10 static unsigned char sphere_bits[] = { 0x00, 0x00, 0x78, 0x00, 0xf4, 0x00, 0xe2, 0x01, 0xf6, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfc, 0x00, 0x78, 0x00, 0x00, 0x00}; #define cross_width 10 #define cross_height 10 static unsigned char cross_bits[] = { 0x00, 0x00, 0x30, 0x00, 0xb4, 0x00, 0x30, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0x30, 0x00, 0xb4, 0x00, 0x30, 0x00, 0x00, 0x00}; static Pixmap spherePixmap; static Pixmap spherePixmask; static Pixmap crossPixmap; static Pixmap crossPixmask; static void FolderSwitchCB(); Widget _folder; void AddFolderTabForm(folder) Widget folder; { Widget form, w, sampleForm; XmString str; int i; static char *labels[] = { "Configuration", "Appearance", "Documents", "Keys" }; static char *desc = "The Folder widget provides a folder containing single or \ multiple rows of tabs along the top, bottom, left or right \ and an area managed by the tabs in the center.\ \n\n\ The Folder One sample contains a single row of tabs with arc-style \ corners, each containing a pixmap image.\ \n\n\ The Folder Two sample also contains a single row of tabs but placed on the \ bottom with the \"none\" corner style. If you increase \ the width of the demo program, you will notice that this row of tabs \ will always fill the entire row with the individual tabs taking up \ a width proportional to their contents and the width of the row.\ \n\n\ The Folder Three sample contains tabs in 2 rows placed on the right. \ Again, the size of the tabs are proportional to the size of \ their contents and will fit to the row.\ \n\n\ The Folder is a Manager widget and each tab \ consists of a Primitive widget (usually a DrawnButton widget) \ surrounded by tab decorations including an optional pixmap. \ Any non-Primitive widget children of the Folder are placed in \ the center area. Tab widgets may be assigned a widget \ in the center area of the folder to display/manage when the \ tab is selected or the application can change the contents \ in the center area itself as tabs are selected.\ \n\n\ Resources exist to set the style of the corners, pixmaps \ to display in the tabs, number of tabs per row, \ various colors, sizes and spacing in and around the tabs. \ Also, since the tabs themselves \ have Primitive widgets like DrawnButtons inside of them, they \ retain all display abilities of their respective Primitive \ widgets. DrawnButton tabs, for example, may be displayed with \ different fonts, character sets, colors, alignments, etc.\ \n\n\ Tabs may be be added or deleted by adding or deleting \ Primitive-based widgets to the Folder. Callbacks are provided \ which can notify an application when a tab is activated, allowing \ the application to either accept or reject the activation.\ \n\n\ The 3.0 release adds multiple rows of tabs, improved tab layout \ and also a rewrite of the Folder's geometry management.\ \n\n\ Keyboard traversal of the tabs is supported by using the arrow \ keys to move from one tab to the next. Tabs may be activated \ by either selection with the mouse or by activating their \ underlying Primitive widget. For example, DrawnButton tabs \ may be activated by pressing the space bar when focus is in the tab."; form = AddWidgetSample(folder, "Folder", desc); _folder = XtVaCreateManagedWidget("sampleFolder", xmlFolderWidgetClass, form, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNmarginWidth, 4, NULL); CreatePixmap(_folder, 4, &spherePixmap, &spherePixmask, (char *)sphere_bits, sphere_width, sphere_height); CreatePixmap(_folder, 2, &crossPixmap, &crossPixmask, (char *)cross_bits, cross_width, cross_height); for (i = 0; i < 4; i++) { str = XmStringCreateSimple(labels[i]); w = XmLFolderAddTab(_folder, str); XmStringFree(str); if (i % 2) XtVaSetValues(w, XmNtabPixmap, crossPixmap, XmNtabInactivePixmap, crossPixmap, NULL); else XtVaSetValues(w, XmNtabPixmap, spherePixmap, XmNtabInactivePixmap, spherePixmap, NULL); } sampleForm = XtVaCreateManagedWidget("sampleForm", xmFormWidgetClass, _folder, NULL); str = XmStringCreateLtoR("\nSample Folder\nPage Area\n", XmSTRING_DEFAULT_CHARSET); XtVaCreateManagedWidget("label", xmLabelWidgetClass, sampleForm, XmNlabelString, str, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); XmStringFree(str); XtAddCallback(XtParent(form), XmNactivateCallback, FolderSwitchCB, NULL); } static void FolderSwitchCB(w, clientData, callData) Widget w; XtPointer clientData, callData; { XmLFolderCallbackStruct *cbs; cbs = (XmLFolderCallbackStruct *)callData; if (cbs->pos == 0) XtVaSetValues(_folder, XmNcornerStyle, XmCORNER_ARC, XmNcornerDimension, 2, XmNtabPlacement, XmFOLDER_TOP, XmNtabsPerRow, 0, NULL); else if (cbs->pos == 1) XtVaSetValues(_folder, XmNcornerStyle, XmCORNER_NONE, XmNtabPlacement, XmFOLDER_BOTTOM, XmNtabsPerRow, 4, NULL); else XtVaSetValues(_folder, XmNcornerStyle, XmCORNER_ARC, XmNcornerDimension, 3, XmNtabPlacement, XmFOLDER_RIGHT, XmNtabsPerRow, 2, NULL); } /* Grid Tab Form */ static void GridSwitchCB(); static void GridSample1(); static void GridSample2(); static void GridSample3(); Widget _grid; void AddGridTabForm(folder) Widget folder; { Widget form; XmString str; static char *desc = "The Grid widget provides an editable grid of \ cells containing text or images in rows and columns.\ \n\n\ The Grid One sample above is a multiple row selection Grid which \ allows column resizing by dragging column headings larger or smaller. \ It contains one heading row and has columns fixed on the left and right. \ The arrows in the Price column are an example of pixmap (image) cell \ types.\ \n\n\ The Grid Two sample demonstrates cell spanning (the 1995 Income \ Summary heading spans 2 columns) and control of cell borders, \ colors and alignment. This Grid is set to not allow selection.\ \n\n\ The Grid Three sample allows editing and is set to allow \ selection of mulitple rows, columns and/or cells. Note that an \ edit may be accepted by pressing Return or by moving to a new \ location and may be rejected with the Escape key. You may \ edit an existing cell's contents using the F2 or Insert key. \ This Grid also supports interactive row and column resizing. \ Drag and drop is permitted by selecting an area to be dragged \ and performing a drag-and-drop operation (using mouse button 2) \ to copy the selected area to another location.\ \n\n\ The Grid includes a number of advanced features such as:\ \n\ - string (editable or non-editable XmString format) or pixmap cells\n\ - keyboard traversal using arrow keys, page keys, etc.\n\ - add, delete, reorder, move and hiding of rows/columns\n\ - heading, content and footer rows/columns\n\ - top, bottom, left and/or right fixed rows/columns\n\ - rows/column intelligently size to cell fonts/images\n\ - user-adjustable row/column sizes\n\ - cells may span rows/columns\n\ - full control of cell borders and colors\n\ - 9 cell alignment options (top-left, center, etc)\n\ - uses reference-counted cell attributes to save memory\n\ - SetValues on ranges of cells/rows/columns\n\ - callbacks for select, activate, draw, edit, focus, etc.\n\ - cut, paste, drag and drop of cell contents\n\ - ASCII file import and export\ \n\n\ The Grid widget is ideal for replacing single-column Motif \ scrolled lists with multi-column lists. Its also perfect for creating \ high-performance tables. Tables may be created where the data \ displayed is not kept in the Grid itself but retrieved from a \ database when it needs to be displayed. This direct database \ access can save memory and time loading/storing the table. \ Click-sorting may be added to the table to allow a user to \ sort rows by clicking on a column heading.\ \n\n\ Cell attributes in the Grid are reference counted. If a number \ of cells in the Grid have similar attributes (color, fonts, etc) \ they may all contain a pointer to the same attributes structure \ instead of creating an attributes structure for each individual \ cell. This reference counting is transparent to a programmer \ creating a Grid.\ \n\n\ Cells may have borders set on the top, bottom, left and right and \ have a number of color/alignment options. Keyboard traversal is \ provided using the standard Motif key mappings of Page Up, \ Page Down, Home, etc. Selection modes are provided to allow \ selection of a single row (browse mode or single mode), multiple \ rows and arbitrary regions of rows, columns and cells. \ Functions are provided to easily import data to and from text \ files.\ \n\n\ The 3.0 release has added resources allowing you to specify cell \ defaults on a per-column basis (e.g. all cells in column 2 will be \ editable). Also, the Grid's layout has improved for sizing policies \ where scrollbars appear as needed. The Grid now will use all the \ space it can for data instead of not using the space where the \ scrollbars would appear. \ \n\n\ A number of resources have been added in the 3.0 release to support \ better integration with interface builders. You can now add and \ delete rows and also set column widths and simple headings through \ resources.\ \n\n\ Internally the Grid is a Manager widget which contains two \ ScrollBar children and one Text widget child."; form = AddWidgetSample(folder, "Grid", desc); _grid = XtVaCreateManagedWidget("grid", xmlGridWidgetClass, form, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); GridSample1(); XtAddCallback(XtParent(form), XmNactivateCallback, GridSwitchCB, NULL); } static void GridSwitchCB(w, clientData, callData) Widget w; XtPointer clientData, callData; { XmLFolderCallbackStruct *cbs; Pixel bg; cbs = (XmLFolderCallbackStruct *)callData; /* reset defaults to grid */ XtVaSetValues(_grid, XmNallowDragSelected, False, XmNallowDrop, False, XmNallowColumnResize, False, XmNallowRowResize, False, XmNhighlightRowMode, False, XmNheadingRows, 0, XmNrows, 0, XmNfooterRows, 0, XmNheadingColumns, 0, XmNcolumns, 0, XmNfooterColumns, 0, XmNshadowThickness, 2, XmNtopFixedCount, 0, XmNbottomFixedCount, 0, XmNleftFixedCount, 0, XmNrightFixedCount, 0, NULL); XtVaGetValues(_grid, XmNbackground, &bg, NULL); XtVaSetValues(_grid, XmNcellDefaults, True, XmNcellBackground, bg, XmNcellAlignment, XmALIGNMENT_CENTER, XmNcellLeftBorderType, XmBORDER_LINE, XmNcellRightBorderType, XmBORDER_LINE, XmNcellTopBorderType, XmBORDER_LINE, XmNcellBottomBorderType, XmBORDER_LINE, NULL); if (cbs->pos == 0) GridSample1(); else if (cbs->pos == 1) GridSample2(); else GridSample3(); } static Pixmap upPixmap = XmUNSPECIFIED_PIXMAP; static Pixmap upPixmask; static Pixmap downPixmap = XmUNSPECIFIED_PIXMAP; static Pixmap downPixmask; #define up_width 12 #define up_height 16 static unsigned char up_bits[] = { 0x00, 0x00, 0x60, 0x00, 0xf0, 0x00, 0xf8, 0x01, 0xfc, 0x03, 0xfe, 0x07, 0xfe, 0x07, 0xf6, 0x06, 0xf2, 0x04, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00}; #define down_width 12 #define down_height 16 static unsigned char down_bits[] = { 0x00, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf2, 0x04, 0xf6, 0x06, 0xfe, 0x07, 0xfe, 0x07, 0xfc, 0x03, 0xf8, 0x01, 0xf0, 0x00, 0x60, 0x00, 0x00, 0x00}; static void GridSample1() { static char *data = "Name|Price||Change|Close Date|Location|Yield\n\ TZZ 3.0 Tana Zin|102.23||-1.2|1/1/94|Tomano, RE|5.6%\n\ BLC 4.5 Board L|103.23||+2.5|2/15/94|Rino, LO|6.8%\n\ DGB 5.4 Dig Gen|101.53||+3.7|6/20/94|Carolana, CA|7.5%\n\ KLC 5.3 Kord L|108.98||-2.5|2/15/94|Cannes, CA|8.7%\n\ LLO 3.4 Liw Lol|107.24||+2.2|2/20/94|Tenise, MI|6.7%\n\ MMN 3.1 Mon Mor|105.63||+1.4|2/15/94|Waterton, MN|6.3%\n\ PLP 4.3 Pol Lab|102.12||-2.3|2/20/94|Holard, LM|7.6%\n\ SZN 4.5 Siml Zi|101.11||+1.6|2/15/94|Tempest, CA|5.4%\n\ TTL 5.6 Towa Tin|101.12||+2.7|3/15/94|Conila, OK|6.7%\n\ ULD 5.4 Upl La D|105.12||-2.2|4/15/94|Mandrill, HI|7.8%"; XtVaSetValues(_grid, XmNlayoutFrozen, True, NULL); XtVaSetValues(_grid, XmNallowColumnResize, True, XmNselectionPolicy, XmSELECT_MULTIPLE_ROW, XmNhighlightRowMode, True, XmNheadingRows, 1, XmNcolumns, 7, XmNsimpleWidths, "18c 8c 16p 8c 12c 16c 6c", XmNrightFixedCount, 1, XmNleftFixedCount, 1, NULL); XtVaSetValues(_grid, XmNcellDefaults, True, XtVaTypedArg, XmNcellBackground, XmRString, "white", 6, XmNcellLeftBorderType, XmBORDER_NONE, XmNcellRightBorderType, XmBORDER_NONE, XmNcellTopBorderType, XmBORDER_NONE, XmNcellBottomBorderType, XmBORDER_NONE, NULL); XtVaSetValues(_grid, XmNrowType, XmHEADING, XmNcolumn, 1, XmNcellColumnSpan, 1, NULL); XtVaSetValues(_grid, XmNcellDefaults, True, XmNcellAlignment, XmALIGNMENT_RIGHT, NULL); XtVaSetValues(_grid, XmNcellDefaults, True, XmNcolumn, 0, XmNcellAlignment, XmALIGNMENT_LEFT, NULL); XtVaSetValues(_grid, XmNcellDefaults, True, XmNcolumn, 1, XmNcellRightBorderType, XmBORDER_NONE, NULL); XtVaSetValues(_grid, XmNcellDefaults, True, XmNcolumn, 2, XmNcellType, XmPIXMAP_CELL, XmNcellLeftBorderType, XmBORDER_NONE, NULL); XmLGridAddRows(_grid, XmCONTENT, -1, 10); XmLGridSetStrings(_grid, data); if (upPixmap == XmUNSPECIFIED_PIXMAP) CreatePixmap(_grid, 2, &upPixmap, &upPixmask, (char *)up_bits, up_width, up_height); if (downPixmap == XmUNSPECIFIED_PIXMAP) CreatePixmap(_grid, 3, &downPixmap, &downPixmask, (char *)down_bits, down_width, down_height); XtVaSetValues(_grid, XmNcolumn, 2, XmNcellPixmap, upPixmap, XmNcellPixmapMask, upPixmask, NULL); XtVaSetValues(_grid, XmNcolumn, 2, XmNrowStep, 3, XmNcellPixmap, downPixmap, XmNcellPixmapMask, downPixmask, NULL); XtVaSetValues(_grid, XmNlayoutFrozen, False, NULL); } static void GridSample2() { static char *data = "|1995 Income Summary\n\ |Shampoo|Conditioner|Soap|Total\n\ Revenues:\n\ Sales|$ 1,600,000|$ 1,000,000|$ 800,000|$ 3,400,000\n\ Less Discounts|(16,000)|(10,000)|(8,000)|(34,000)\n\ Less Return Allowance|(8,000)|(5,000)|(4,000)|(17,000)\n\ Net Revenue|1,576,000|985,000|792,000|3,349,000\n\ \n\ Less Expenses:\n\ Cost of Goods Sold|(640,000)|(330,000)|(264,000)|(1,234,000)\n\ Salary Expense|(380,000)|(280,000)|(180,000)|(840,000)\n\ Marketing Expense|(157,600)|(98,500)|(79,200)|(335,300)\n\ Rent Expense|(36,000)|(36,000)|(36,000)|(108,000)\n\ Misc. Other Expense|(36,408)|(22,335)|(16,776)|(75,519)\n\ Total Expenses|(1,250,008)|(766,835)|(575,976)|(2,592,819)\n\ \n\ Income Tax Expense|(130,397)|(87,266)|(86,410)|(304,072)\n\ Net Income|195,595|130,899|129,614|456,109"; XtVaSetValues(_grid, XmNlayoutFrozen, True, NULL); XtVaSetValues(_grid, XmNheadingColumns, 1, XmNcolumns, 3, XmNfooterColumns, 1, XmNsimpleWidths, "22c 12c 12c 12c 12c", XmNselectionPolicy, XmSELECT_NONE, NULL); /* add 'Income Summary' heading row */ XtVaSetValues(_grid, XmNcellDefaults, True, XmNcellLeftBorderType, XmBORDER_NONE, XmNcellRightBorderType, XmBORDER_NONE, XmNcellTopBorderType, XmBORDER_NONE, XtVaTypedArg, XmNcellBottomBorderColor, XmRString, "black", 6, XmNcellAlignment, XmALIGNMENT_CENTER, XtVaTypedArg, XmNcellForeground, XmRString, "#000080", 8, NULL); XmLGridAddRows(_grid, XmHEADING, -1, 1); XtVaSetValues(_grid, XmNrowType, XmHEADING, XmNrow, 0, XmNcolumn, 0, XmNcellColumnSpan, 2, NULL); /* add 'Shampoo Conditioner Soap' heading row */ XtVaSetValues(_grid, XmNcellDefaults, True, XtVaTypedArg, XmNcellBackground, XmRString, "white", 6, XtVaTypedArg, XmNcellForeground, XmRString, "black", 6, XmNcellBottomBorderType, XmBORDER_NONE, NULL); XmLGridAddRows(_grid, XmHEADING, -1, 1); /* bold heading rows */ XtVaSetValues(_grid, XmNrowType, XmHEADING, XmNcolumnType, XmALL_TYPES, XtVaTypedArg, XmNcellFontList, XmRString, BOLDFONT, strlen(BOLDFONT) + 1, NULL); /* add content and footer rows */ XtVaSetValues(_grid, XmNcellDefaults, True, XmNcellAlignment, XmALIGNMENT_RIGHT, NULL); XmLGridAddRows(_grid, XmCONTENT, -1, 15); XmLGridAddRows(_grid, XmFOOTER, -1, 1); /* left justify left-most (heading) column */ XtVaSetValues(_grid, XmNcolumn, 0, XmNcolumnType, XmHEADING, XmNrowType, XmALL_TYPES, XmNcellAlignment, XmALIGNMENT_LEFT, NULL); /* bold 'Revenues' cell */ XtVaSetValues(_grid, XmNcolumnType, XmHEADING, XmNcolumn, 0, XmNrow, 0, XtVaTypedArg, XmNcellFontList, XmRString, BOLDFONT, strlen(BOLDFONT) + 1, NULL); /* bold 'Less Expenses' cell */ XtVaSetValues(_grid, XmNcolumnType, XmHEADING, XmNcolumn, 0, XmNrow, 6, XtVaTypedArg, XmNcellFontList, XmRString, BOLDFONT, strlen(BOLDFONT) + 1, NULL); /* grey middle and footer content column */ XtVaSetValues(_grid, XmNrowType, XmALL_TYPES, XmNcolumnType, XmALL_TYPES, XmNcolumnRangeStart, 2, XmNcolumnRangeEnd, 4, XmNcolumnStep, 2, XtVaTypedArg, XmNcellBackground, XmRString, "#E8E8E8", 8, NULL); /* set 'Income Summary' heading row yellow */ XtVaSetValues(_grid, XmNcolumnType, XmALL_TYPES, XmNrowType, XmHEADING, XmNrow, 0, XtVaTypedArg, XmNcellBackground, XmRString, "#FFFF00", 8, NULL); /* blue and bold 'Net Revenue' and 'Total Expenses' rows */ XtVaSetValues(_grid, XmNrowRangeStart, 4, XmNrowRangeEnd, 12, XmNrowStep, 8, XmNcolumnType, XmALL_TYPES, XtVaTypedArg, XmNcellForeground, XmRString, "white", 6, XtVaTypedArg, XmNcellBackground, XmRString, "#000080", 8, XtVaTypedArg, XmNcellFontList, XmRString, BOLDFONT, strlen(BOLDFONT) + 1, NULL); /* blue and bold 'Net Income' footer row */ XtVaSetValues(_grid, XmNrow, 0, XmNrowType, XmFOOTER, XmNcolumnType, XmALL_TYPES, XtVaTypedArg, XmNcellForeground, XmRString, "white", 6, XtVaTypedArg, XmNcellBackground, XmRString, "#000080", 8, XtVaTypedArg, XmNcellFontList, XmRString, BOLDFONT, strlen(BOLDFONT) + 1, NULL); XmLGridSetStrings(_grid, data); XtVaSetValues(_grid, XmNlayoutFrozen, False, NULL); } static void GridSample3() { char buf[4]; int i; XtVaSetValues(_grid, XmNlayoutFrozen, True, NULL); XtVaSetValues(_grid, XmNallowDragSelected, True, XmNallowDrop, True, XmNhsbDisplayPolicy, XmSTATIC, XmNvsbDisplayPolicy, XmSTATIC, XmNselectionPolicy, XmSELECT_CELL, XmNallowColumnResize, True, XmNallowRowResize, True, XmNshadowThickness, 1, NULL); XtVaSetValues(_grid, XmNcellDefaults, True, XmNcellEditable, True, XmNcellAlignment, XmALIGNMENT_RIGHT, XtVaTypedArg, XmNcellBackground, XmRString, "white", 6, XmNcellLeftBorderType, XmBORDER_NONE, XmNcellTopBorderType, XmBORDER_NONE, NULL); XtVaSetValues(_grid, XmNheadingRows, 1, XmNheadingColumns, 1, XmNcolumns, 26, XmNrows, 100, NULL); XtVaSetValues(_grid, XmNlayoutFrozen, False, NULL); for (i = 0; i < 26; i++) { sprintf(buf, "%c", 'A' + i); XmLGridSetStringsPos(_grid, XmHEADING, 0, XmCONTENT, i, buf); } for (i = 0; i < 100; i++) { sprintf(buf, "%d", i + 1); XmLGridSetStringsPos(_grid, XmCONTENT, i, XmHEADING, 0, buf); } XtVaSetValues(_grid, XmNrowType, XmALL_TYPES, XmNcolumnType, XmHEADING, XmNcolumn, 0, XmNcellAlignment, XmALIGNMENT_CENTER, XtVaTypedArg, XmNcellBackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNcellFontList, XmRString, BOLDFONT, strlen(BOLDFONT) + 1, XmNcellLeftBorderType, XmBORDER_LINE, XmNcellTopBorderType, XmBORDER_LINE, NULL); XtVaSetValues(_grid, XmNrowType, XmHEADING, XmNrow, 0, XmNcellAlignment, XmALIGNMENT_CENTER, XtVaTypedArg, XmNcellBackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNcellFontList, XmRString, BOLDFONT, strlen(BOLDFONT) + 1, XmNcellLeftBorderType, XmBORDER_LINE, XmNcellTopBorderType, XmBORDER_LINE, NULL); } /* Progress Tab Form */ static void ProgSwitchCB(); static void ProgSweepCB(); Widget _progress; void AddProgTabForm(folder) Widget folder; { Widget form, button; XmString str; static char *desc = "The Progress widget may be used to chart the completion of a task.\ \n\n\ The Progress One sample displays a standard bar-style Progress widget. \ You may press the Quick Sweep or the Slow Sweep button to chart progress \ of a simulated task.\ \n\n\ The Progress Two sample displays a box-style Progress widget with 20 boxes.\ \n\n\ The Progress Three sample contains a bar-style Progress widget which \ displays elapsed time and estimated time to completion. \ Press the Slow Sweep button to display this behavior. These \ times are calculated automatically by the Progress widget. \ \n\n\ Resources exist to set colors, fonts, shadows, the style of the \ meter bar and the values used to determine level of completeness. \ \n\n\ The Progress widget is a subclasss of the Primitive widget."; form = AddWidgetSample(folder, "Progress", desc); _progress = XtVaCreateManagedWidget("progress", xmlProgressWidgetClass, form, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_POSITION, XmNtopPosition, 30, XmNheight, 24, XmNvalue, 50, XtVaTypedArg, XmNforeground, XmRString, "#0000C0", 8, XtVaTypedArg, XmNbackground, XmRString, "white", 6, NULL); button = XtVaCreateManagedWidget("Quick Sweep", xmPushButtonWidgetClass, form, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNmarginWidth, 15, NULL); XtAddCallback(button, XmNactivateCallback, ProgSweepCB, (XtPointer)1); button = XtVaCreateManagedWidget("Slow Sweep", xmPushButtonWidgetClass, form, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, button, XmNbottomAttachment, XmATTACH_FORM, XmNmarginWidth, 15, NULL); XtAddCallback(button, XmNactivateCallback, ProgSweepCB, (XtPointer)0); XtAddCallback(XtParent(form), XmNactivateCallback, ProgSwitchCB, NULL); } static void ProgSwitchCB(w, clientData, callData) Widget w; XtPointer clientData, callData; { XmLFolderCallbackStruct *cbs; cbs = (XmLFolderCallbackStruct *)callData; if (cbs->pos == 0) XtVaSetValues(_progress, XmNvalue, 50, XmNshadowThickness, 2, XmNmeterStyle, XmMETER_BAR, XtVaTypedArg, XmNforeground, XmRString, "#0000C0", 8, XmNshowTime, False, NULL); else if (cbs->pos == 1) XtVaSetValues(_progress, XmNvalue, 50, XmNshadowThickness, 1, XmNmeterStyle, XmMETER_BOXES, XmNnumBoxes, 20, XtVaTypedArg, XmNforeground, XmRString, "#0000C0", 8, XmNshowTime, False, NULL); else XtVaSetValues(_progress, XmNvalue, 50, XmNshadowThickness, 2, XmNmeterStyle, XmMETER_BAR, XtVaTypedArg, XmNforeground, XmRString, "#E00000", 8, XmNshowTime, True, NULL); } static void ProgSweepCB(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { int i, quickSweep; quickSweep = (int)clientData; if (quickSweep) for (i = 0; i <= 100; i += 4) XtVaSetValues(_progress, XmNvalue, i, NULL); else { for (i = 0; i <= 100; i += 23) { XtVaSetValues(_progress, XmNvalue, i, NULL); sleep(1); } XtVaSetValues(_progress, XmNvalue, 100, NULL); } } /* Tree Tab Form */ static void TreeSwitchCB(); static void TreeSample(); Widget _tree; void AddTreeTabForm(folder) Widget folder; { Widget form, w; XmString str; static char *desc = "The Tree widget may be used to display hierarchical data and \ parent-child relationships.\ \n\n\ The Tree One sample contains a simple Tree in browse select mode. \ Note that horizontal scrolling is on a per-pixel basis while vertical \ scrolling is on a per-row basis and the horizontal and vertical \ scrollbars only appear as needed. The plus and minus indicators \ may be used to expand and collapse rows. Activating a row \ with Return or by double clicking on it will toggle the expanded \ state of the row.\ \n\n\ The Tree Two sample contains a Tree in multiple row select mode with \ application defined pixmaps.\ \n\n\ The Tree Three sample displays a Tree in browse select mode containing \ multiple columns. The columns support interactive resizing by \ dragging a column heading larger or smaller.\ \n\n\ The Tree widget is a subclass of the Grid, meaning it includes all the \ functionality of the Grid widget. This includes selection policies \ of single row, multiple row, etc. as well as full control over colors, \ fonts, alignment, borders, etc. on a per-cell basis. The Tree \ also supports all the other features of the Grid, including heading, \ content and footer rows and columns, various cell types etc.\ \n\n\ An application may add rows to the Tree and let the Tree handle \ the expansion and collapse of rows, or for large trees, \ an application may handle the expansion and collapse of rows \ by adding (creating) and deleting rows dynamically as needed.\ \n\n\ Resources exist to set the indent level, various colors of the \ Tree, etc. As stated earlier, the Tree also contains all the \ resources available in the Grid.\ \n\n\ This widget is new in the 3.0 release."; form = AddWidgetSample(folder, "Tree", desc); _tree = XtVaCreateManagedWidget("tree", xmlTreeWidgetClass, form, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); TreeSample(0); XtAddCallback(XtParent(form), XmNactivateCallback, TreeSwitchCB, NULL); } static void TreeSwitchCB(w, clientData, callData) Widget w; XtPointer clientData, callData; { XmLFolderCallbackStruct *cbs; cbs = (XmLFolderCallbackStruct *)callData; TreeSample(cbs->pos); } #define dot_width 16 #define dot_height 16 static unsigned char dot_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0xe0, 0x0f, 0xb0, 0x1f, 0x18, 0x3f, 0xb8, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf0, 0x1f, 0xe0, 0x0f, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00}; #define win_width 16 #define win_height 16 static unsigned char win_bits[] = { 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x08, 0x40, 0xe8, 0x6f, 0xe8, 0x61, 0xe8, 0x61, 0xe8, 0x61, 0x28, 0x60, 0x28, 0x60, 0x28, 0x60, 0x08, 0x60, 0x08, 0x60, 0xe8, 0x7f, 0xf0, 0x7f, 0x00, 0x00}; static Pixmap dotPixmap = XmUNSPECIFIED_PIXMAP; static Pixmap dotPixmask; static Pixmap winPixmap = XmUNSPECIFIED_PIXMAP; static Pixmap winPixmask; static void TreeSample(num) int num; { XmLTreeRowDefinition *rows; int i, n, size, level; Pixel bg; char buf[80]; static struct { Boolean expands; int level; } defs[10] = { True, 0, True, 1, True, 2, False, 3, False, 2, False, 2, True, 1, False, 2, False, 2, True, 2, }; if (dotPixmap == XmUNSPECIFIED_PIXMAP) CreatePixmap(_tree, 4, &dotPixmap, &dotPixmask, (char *)dot_bits, dot_width, dot_height); if (winPixmap == XmUNSPECIFIED_PIXMAP) CreatePixmap(_tree, 1, &winPixmap, &winPixmask, (char *)win_bits, win_width, win_height); XtVaSetValues(_tree, XmNlayoutFrozen, True, NULL); XmLGridDeleteAllRows(_tree, XmCONTENT); XtVaSetValues(_tree, XmNallowColumnResize, False, XmNheadingRows, 0, XmNcolumns, 1, XmNshadowThickness, 1, XmNselectionPolicy, XmSELECT_BROWSE_ROW, XmNhighlightRowMode, False, XmNglobalPixmapWidth, 0, XmNglobalPixmapHeight, 0, NULL); XtVaSetValues(_tree, XmNcolumn, 0, XmNcolumnSizePolicy, XmVARIABLE, NULL); XtVaGetValues(_tree, XmNbackground, &bg, NULL); XtVaSetValues(_tree, XmNcellDefaults, True, XmNcellBackground, bg, XmNcellLeftBorderType, XmBORDER_LINE, XmNcellRightBorderType, XmBORDER_LINE, XmNcellTopBorderType, XmBORDER_LINE, XmNcellBottomBorderType, XmBORDER_LINE, XmNcellAlignment, XmALIGNMENT_CENTER, NULL); n = 100; if (num == 1) XtVaSetValues(_tree, XmNselectionPolicy, XmSELECT_MULTIPLE_ROW, XmNglobalPixmapWidth, 16, XmNglobalPixmapHeight, 16, NULL); else if (num == 2) XtVaSetValues(_tree, XmNhighlightRowMode, True, XmNheadingRows, 1, XmNcolumns, 5, XmNsimpleHeadings, "Object|Position|Size|Method|Note", XmNsimpleWidths, "1c 10c 10c 15c 15c", XmNallowColumnResize, True, NULL); XtVaSetValues(_tree, XmNcellDefaults, True, XtVaTypedArg, XmNcellBackground, XmRString, "white", 6, XmNcellLeftBorderType, XmBORDER_NONE, XmNcellRightBorderType, XmBORDER_NONE, XmNcellTopBorderType, XmBORDER_NONE, XmNcellBottomBorderType, XmBORDER_NONE, XmNcellAlignment, XmALIGNMENT_RIGHT, NULL); if (num == 2) XtVaSetValues(_tree, XmNcellDefaults, True, XmNcolumnRangeStart, 3, XmNcolumnRangeEnd, 4, XmNcellAlignment, XmALIGNMENT_CENTER, NULL); size = sizeof(XmLTreeRowDefinition); rows = (XmLTreeRowDefinition *)malloc(size * n); level = 0; for (i = 0; i < n; i++) { rows[i].level = defs[i % 10].level; rows[i].expands = defs[i % 10].expands; rows[i].isExpanded = True; if (num < 2) { if (i % 30 >= 10) rows[i].level += 3; if (i % 30 >= 20) rows[i].level += 3; } if (num != 1) { rows[i].pixmap = XmUNSPECIFIED_PIXMAP; rows[i].pixmask = XmUNSPECIFIED_PIXMAP; } else { if (rows[i].expands == True) { rows[i].pixmap = dotPixmap; rows[i].pixmask = dotPixmask; } else { rows[i].pixmap = winPixmap; rows[i].pixmask = winPixmask; } } if (num == 0) sprintf(buf, "Row %d Level %d\n", i, rows[i].level); else if (num == 2) { if (rows[i].expands) sprintf(buf, "Composite"); else if (i % 5) sprintf(buf, "Curve"); else sprintf(buf, "Surface"); } else { if (rows[i].expands == True) sprintf(buf, "Sector Number %d-%d%d", rows[i].level, i % 2, i + 413); else sprintf(buf, "Item Number %d%d%d", i % 12, i % 3, i % 2); } rows[i].string = XmStringCreateSimple(buf); } XmLTreeAddRows(_tree, rows, n, -1); for (i = 0; i < n; i++) { XmStringFree(rows[i].string); if (num == 2) { sprintf(buf, "%d %d|%d points|Open|In Progress", i % 20, i % 15, i % 4); XmLGridSetStringsPos(_tree, XmCONTENT, i, XmCONTENT, 1, buf); } } free((char *)rows); XtVaSetValues(_tree, XmNlayoutFrozen, False, NULL); } nedit-5.6.orig/Microline/examples/folder1.c0000644000175000017500000000664110077552126017365 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include #include main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell, folder, form; XmString str; char buf[20]; int i; shell = XtAppInitialize(&app, "Folder1", NULL, 0, &argc, argv, NULL, NULL, 0); folder = XtVaCreateManagedWidget("folder", xmlFolderWidgetClass, shell, NULL); for (i = 0; i < 3; i++) { /* Add a tab and Form managed by the tab to the Folder */ sprintf(buf, "Tab %d", i); str = XmStringCreateSimple(buf); form = XmLFolderAddTabForm(folder, str); XmStringFree(str); /* Add a Label as a child of the Form */ sprintf(buf, "Form %d", i); XtVaCreateManagedWidget(buf, xmLabelWidgetClass, form, XmNmarginWidth, 100, XmNmarginHeight, 80, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); } XtRealizeWidget(shell); XtAppMainLoop(app); } nedit-5.6.orig/Microline/examples/folder2.c0000644000175000017500000001127010077552126017360 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include #include main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell, form, folder, tab, folderForm; XmString str; char pageName[20], tabName[20]; int i; shell = XtAppInitialize(&app, "Folder2", NULL, 0, &argc, argv, NULL, NULL, 0); form = XtVaCreateManagedWidget("form", xmFormWidgetClass, shell, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XmNmarginWidth, 8, XmNmarginHeight, 8, XmNshadowThickness, 0, NULL); folder = XtVaCreateManagedWidget("folder", xmlFolderWidgetClass, form, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNtabPlacement, XmFOLDER_RIGHT, XmNmarginWidth, 10, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); for (i = 0; i < 3; i++) { sprintf(pageName, "Page %d", i); /* Add a tab (DrawnButton) to the Folder */ sprintf(tabName, "Tab %d", i); str = XmStringCreateSimple(tabName); tab = XtVaCreateManagedWidget("tab", xmDrawnButtonWidgetClass, folder, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNlabelString, str, XmNtabManagedName, pageName, NULL); XmStringFree(str); /* Add a Form to the Folder which will appear in the page */ /* area. This Form will be managed by the tab created above */ /* because it has the same tabManagedName as the tab widget */ folderForm = XtVaCreateManagedWidget("folderForm", xmFormWidgetClass, folder, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XmNtabManagedName, pageName, NULL); /* Add a Label as a child of the Form */ XtVaCreateManagedWidget(pageName, xmLabelWidgetClass, folderForm, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNmarginWidth, 100, XmNmarginHeight, 80, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); } XtRealizeWidget(shell); XtAppMainLoop(app); } nedit-5.6.orig/Microline/examples/folder3.c0000644000175000017500000001147510077552126017370 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include #include main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell, form, folder, shellForm, label, button; XmString str; char buf[20]; int i; static char tabName[6][20] = { "Standard", "PTEL Server", "NTEL Server", "Advanced", "Transfer Address", "Multimedia" }; shell = XtAppInitialize(&app, "Folder3", NULL, 0, &argc, argv, NULL, NULL, 0); form = XtVaCreateManagedWidget("form", xmFormWidgetClass, shell, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XmNmarginWidth, 10, XmNmarginHeight, 10, XmNshadowThickness, 0, NULL); folder = XtVaCreateManagedWidget("folder", xmlFolderWidgetClass, form, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNtabsPerRow, 3, XmNmarginWidth, 10, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); for (i = 0; i < 6; i++) { /* Add a tab and Form managed by the tab to the Folder */ str = XmStringCreateSimple(tabName[i]); shellForm = XmLFolderAddTabForm(folder, str); XmStringFree(str); XtVaSetValues(shellForm, XmNmarginWidth, 8, XmNmarginHeight, 8, NULL); /* Add a Label as a child of the Form */ sprintf(buf, "Label For Page %d", i); label = XtVaCreateManagedWidget(buf, xmLabelWidgetClass, shellForm, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNmarginWidth, 100, XmNmarginHeight, 80, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); /* Add a Button to pages 0 and 1 */ if (i < 2) { button = XtVaCreateManagedWidget("Sample Button", xmPushButtonWidgetClass, shellForm, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNmarginWidth, 5, NULL); XtVaSetValues(label, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button, NULL); } else XtVaSetValues(label, XmNbottomAttachment, XmATTACH_FORM, NULL); } XtRealizeWidget(shell); XtAppMainLoop(app); } nedit-5.6.orig/Microline/examples/folder4.c0000644000175000017500000001723210077552126017366 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include #include #include void addTab(); void removeTab(); void activate(); #define sphere_width 16 #define sphere_height 16 static unsigned char sphere_bits[] = { 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0x38, 0x3f, 0xb8, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf0, 0x1f, 0xe0, 0x0f, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; #define monitor_width 16 #define monitor_height 16 static unsigned char monitor_bits[] = { 0x00, 0x00, 0xf8, 0x3f, 0xf8, 0x3f, 0x18, 0x30, 0x58, 0x37, 0x18, 0x30, 0x58, 0x37, 0x18, 0x30, 0xf8, 0x3f, 0xf8, 0x3f, 0x80, 0x03, 0x80, 0x03, 0xf0, 0x1f, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00}; Widget folder, label; Pixmap monitorPixmap, spherePixmap; main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell, form, folderForm, addButton, removeButton; Pixel black, grey; shell = XtAppInitialize(&app, "Folder4", NULL, 0, &argc, argv, NULL, NULL, 0); XtVaSetValues(shell, XmNallowShellResize, True, NULL); form = XtVaCreateManagedWidget("form", xmFormWidgetClass, shell, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XmNmarginWidth, 8, XmNmarginHeight, 8, XmNhorizontalSpacing, 4, XmNverticalSpacing, 4, XmNshadowThickness, 0, NULL); /* Create Pixmaps with grey background (from form) */ black = BlackPixelOfScreen(XtScreen(shell)); XtVaGetValues(form, XmNbackground, &grey, NULL); spherePixmap = XCreatePixmapFromBitmapData(XtDisplay(shell), DefaultRootWindow(XtDisplay(shell)), sphere_bits, sphere_width, sphere_height, black, grey, DefaultDepthOfScreen(XtScreen(shell))); monitorPixmap = XCreatePixmapFromBitmapData(XtDisplay(shell), DefaultRootWindow(XtDisplay(shell)), monitor_bits, monitor_width, monitor_height, black, grey, DefaultDepthOfScreen(XtScreen(shell))); removeButton = XtVaCreateManagedWidget("Remove Tab", xmPushButtonWidgetClass, form, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNmarginWidth, 10, NULL); XtAddCallback(removeButton, XmNactivateCallback, removeTab, NULL); addButton = XtVaCreateManagedWidget("Add Tab", xmPushButtonWidgetClass, form, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, removeButton, XmNbottomAttachment, XmATTACH_FORM, XmNmarginWidth, 20, NULL); XtAddCallback(addButton, XmNactivateCallback, addTab, NULL); folder = XtVaCreateManagedWidget("folder", xmlFolderWidgetClass, form, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNtabsPerRow, 4, XmNcornerStyle, XmCORNER_NONE, XmNspacing, 1, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, removeButton, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNresizePolicy, XmRESIZE_DYNAMIC, NULL); XtAddCallback(folder, XmNactivateCallback, activate, NULL); /* Add a Form to the Folder, this will appear in the page area */ folderForm = XtVaCreateManagedWidget("form", xmFormWidgetClass, folder, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, NULL); /* Add a Label as a child of the Form */ label = XtVaCreateManagedWidget("Page Area", xmLabelWidgetClass, folderForm, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNmarginWidth, 100, XmNmarginHeight, 80, XmNrecomputeSize, False, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); XtRealizeWidget(shell); XtAppMainLoop(app); } void addTab(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { Widget tabButton, form; int count; char tabName[30]; XmString str; Pixmap pixmap; XtVaGetValues(folder, XmNtabCount, &count, NULL); /* Every other tab will have a sphere pixmap */ if (count % 2) pixmap = spherePixmap; else pixmap = monitorPixmap; /* Add a tab (DrawnButton) to the Folder */ sprintf(tabName, "Tab %d", count); str = XmStringCreateSimple(tabName); tabButton = XtVaCreateManagedWidget("tab", xmDrawnButtonWidgetClass, folder, XmNlabelString, str, XmNmarginWidth, 8, XmNtabPixmap, pixmap, XmNtabInactivePixmap, pixmap, NULL); XmStringFree(str); } void removeTab(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { int count; WidgetList tabs; XtVaGetValues(folder, XmNtabCount, &count, XmNtabWidgetList, &tabs, NULL); if (!count) return; XtDestroyWidget(tabs[count - 1]); } void activate(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { XmLFolderCallbackStruct *cbs; XmString str; char buf[20]; int pos; /* Change the Label in the page area to reflect */ /* the selected position */ cbs = (XmLFolderCallbackStruct *)callData; sprintf(buf, "Page %d", cbs->pos); str = XmStringCreateSimple(buf); XtVaSetValues(label, XmNlabelString, str, NULL); } nedit-5.6.orig/Microline/examples/grid1.c0000644000175000017500000000626310077552126017037 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include static char *data = "Europe|CD-ROM|$29\n\ Yugoslovia|Floppy|$39\n\ North America|Tape|$29\n\ South America|CD-ROM|$49\n\ Japan|Tape|$49\n\ Russia|Floppy|$49\n\ Poland|CD-ROM|$39\n\ Norway|CD-ROM|$29\n\ England|Tape|$49\n\ Jordan|CD-ROM|$39"; main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell, grid; shell = XtAppInitialize(&app, "Grid1", NULL, 0, &argc, argv, NULL, NULL, 0); grid = XtVaCreateManagedWidget("grid", xmlGridWidgetClass, shell, XmNrows, 10, XmNvisibleRows, 7, XmNcolumns, 3, XmNsimpleWidths, "20c 8c 8c", XmNhorizontalSizePolicy, XmVARIABLE, NULL); XmLGridSetStrings(grid, data); XtRealizeWidget(shell); XtAppMainLoop(app); } nedit-5.6.orig/Microline/examples/grid2.c0000644000175000017500000001353410077552126017037 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include void showSelected(); static char *data = "Country|Media|Price\n\ Europe|CD-ROM|$29\n\ Yugoslovia|Floppy|$39\n\ North America|Tape|$29\n\ South America|CD-ROM|$49\n\ Japan|Tape|$49\n\ Russia|Floppy|$49\n\ Poland|CD-ROM|$39\n\ Norway|CD-ROM|$29\n\ England|Tape|$49\n\ Jordan|CD-ROM|$39"; Widget grid; main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell, form, button; XmString str; shell = XtAppInitialize(&app, "Grid2", NULL, 0, &argc, argv, NULL, NULL, 0); form = XtVaCreateManagedWidget("form", xmFormWidgetClass, shell, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XmNmarginWidth, 5, XmNmarginHeight, 5, XmNverticalSpacing, 5, XmNshadowThickness, 0, NULL); str = XmStringCreateSimple("Print Selected"); button = XtVaCreateManagedWidget("button", xmPushButtonWidgetClass, form, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNlabelString, str, NULL); XmStringFree(str); XtAddCallback(button, XmNactivateCallback, showSelected, NULL); /* Create a Grid in multiple row select mode with 1 heading row */ /* and 3 columns */ grid = XtVaCreateManagedWidget("grid", xmlGridWidgetClass, form, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XtVaTypedArg, XmNselectBackground, XmRString, "#000080", 8, XtVaTypedArg, XmNselectForeground, XmRString, "white", 6, XtVaTypedArg, XmNblankBackground, XmRString, "white", 6, XmNheadingRows, 1, XmNvisibleRows, 7, XmNcolumns, 3, XmNsimpleWidths, "20c 10c 10c", XmNhorizontalSizePolicy, XmVARIABLE, XmNvsbDisplayPolicy, XmSTATIC, XmNhighlightRowMode, True, XmNselectionPolicy, XmSELECT_MULTIPLE_ROW, XmNshadowThickness, 0, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); /* Set default cell values for new cells (which will be the */ /* cells created when we add content rows) */ XtVaSetValues(grid, XmNcellDefaults, True, XtVaTypedArg, XmNcellBackground, XmRString, "white", 6, XmNcellLeftBorderType, XmBORDER_NONE, XmNcellRightBorderType, XmBORDER_NONE, XmNcellTopBorderType, XmBORDER_NONE, XmNcellBottomBorderType, XmBORDER_NONE, NULL); /* Set default cell alignment for new cells in columns 0 and 1 */ XtVaSetValues(grid, XmNcellDefaults, True, XmNcolumnRangeStart, 0, XmNcolumnRangeEnd, 1, XmNcellAlignment, XmALIGNMENT_LEFT, NULL); /* Set default cell alignment for new cells in column 2 */ XtVaSetValues(grid, XmNcellDefaults, True, XmNcolumn, 2, XmNcellAlignment, XmALIGNMENT_RIGHT, NULL); /* Add 10 content rows */ XtVaSetValues(grid, XmNrows, 10, NULL); XmLGridSetStrings(grid, data); XtRealizeWidget(shell); XtAppMainLoop(app); } void showSelected(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { int i, count, *pos; printf ("Selected Rows: "); count = XmLGridGetSelectedRowCount(grid); if (count) { pos = (int *)malloc(sizeof(int) * count); XmLGridGetSelectedRows(grid, pos, count); for (i = 0; i < count; i++) printf ("%d ", pos[i]); free((char *)pos); } else printf ("none"); printf ("\n"); } nedit-5.6.orig/Microline/examples/grid3.c0000644000175000017500000002245410077552126017041 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include #include #include Widget label, text, grid, gridText; static int busy = 0; void cellFocus(); void textModify(); void copy(); void paste(); main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell, form, copyButton, pasteButton; XmString str; char buf[4]; int i; shell = XtAppInitialize(&app, "Grid3", NULL, 0, &argc, argv, NULL, NULL, 0); form = XtVaCreateManagedWidget("form", xmFormWidgetClass, shell, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XmNshadowThickness, 0, NULL); str = XmStringCreateSimple("(A 1)"); label = XtVaCreateManagedWidget("label", xmLabelWidgetClass, form, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNtopAttachment, XmATTACH_FORM, XmNmarginHeight, 4, XmNleftAttachment, XmATTACH_FORM, XmNlabelString, str, NULL); XmStringFree(str); pasteButton = XtVaCreateManagedWidget("Paste To Focus", xmPushButtonWidgetClass, form, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNrightAttachment, XmATTACH_FORM, XmNmarginHeight, 0, NULL); XtAddCallback(pasteButton, XmNactivateCallback, paste, NULL); copyButton = XtVaCreateManagedWidget("Copy Selected", xmPushButtonWidgetClass, form, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, pasteButton, XmNmarginHeight, 0, NULL); XtAddCallback(copyButton, XmNactivateCallback, copy, NULL); text = XtVaCreateManagedWidget("text", xmTextWidgetClass, form, XtVaTypedArg, XmNbackground, XmRString, "white", 6, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, label, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, copyButton, XmNmarginHeight, 0, NULL); /* Create a Grid with 1 heading column and 1 heading row */ grid = XtVaCreateManagedWidget("grid", xmlGridWidgetClass, form, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNheadingColumns, 1, XmNcolumns, 26, XmNvisibleColumns, 8, XmNhsbDisplayPolicy, XmSTATIC, XmNrows, 100, XmNheadingRows, 1, XmNvisibleRows, 12, XmNvsbDisplayPolicy, XmSTATIC, XmNallowDragSelected, True, XmNallowDrop, True, XmNallowRowResize, True, XmNallowColumnResize, True, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, text, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNshadowThickness, 0, XmNselectionPolicy, XmSELECT_CELL, NULL); /* Make all cells in the content rows and content columns */ /* (the data cells) editable and set their borders and color */ XtVaSetValues(grid, XmNcellEditable, True, XtVaTypedArg, XmNcellBackground, XmRString, "white", 6, XmNcellAlignment, XmALIGNMENT_RIGHT, XmNcellTopBorderType, XmBORDER_NONE, XmNcellLeftBorderType, XmBORDER_NONE, XtVaTypedArg, XmNcellRightBorderColor, XmRString, "#606060", 8, XtVaTypedArg, XmNcellBottomBorderColor, XmRString, "#606060", 8, NULL); /* Add callbacks which update the Label and to synchronize */ /* the Text widget outside the Grid with the one inside the Grid */ XtAddCallback(grid, XmNcellFocusCallback, cellFocus, NULL); XtAddCallback(text, XmNvalueChangedCallback, textModify, NULL); XtVaGetValues(grid, XmNtextWidget, &gridText, NULL); XtAddCallback(gridText, XmNvalueChangedCallback, textModify, NULL); XtVaSetValues(gridText, XtVaTypedArg, XmNbackground, XmRString, "white", 6, NULL); /* Set the labels on the heading rows and columns */ for (i = 0; i < 26; i++) { sprintf(buf, "%c", 'A' + i); XmLGridSetStringsPos(grid, XmHEADING, 0, XmCONTENT, i, buf); } for (i = 0; i < 100; i++) { sprintf(buf, "%d", i + 1); XmLGridSetStringsPos(grid, XmCONTENT, i, XmHEADING, 0, buf); } XtRealizeWidget(shell); XtAppMainLoop(app); } void cellFocus(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { XmLGridCallbackStruct *cbs; XmLGridRow row; XmLGridColumn column; Widget sharedText; XmString str; char buf[10], *c; cbs = (XmLGridCallbackStruct *)callData; if (cbs->reason != XmCR_CELL_FOCUS_IN) return; /* Update the Label to reflect the new focus position */ sprintf(buf, "(%c %d)", 'A' + cbs->column, cbs->row + 1); str = XmStringCreateSimple(buf); XtVaSetValues(label, XmNlabelString, str, NULL); XmStringFree(str); /* Set the Text widget outside the Grid to the string contained */ /* in the new focus cell. We set busy here because this change will */ /* generate a valueChanged callback and we want to notify our */ /* valueChanged callback not to do any processing because of */ /* this change */ if (busy) return; busy = 1; row = XmLGridGetRow(w, cbs->rowType, cbs->row); column = XmLGridGetColumn(w, cbs->columnType, cbs->column); XtVaGetValues(w, XmNrowPtr, row, XmNcolumnPtr, column, XmNcellString, &str, NULL); c = 0; if (str) XmStringGetLtoR(str, XmSTRING_DEFAULT_CHARSET, &c); if (c) { XmTextSetString(text, c); XtFree(c); XmTextSetSelection(text, 0, XmTextGetLastPosition(text), CurrentTime); } else XmTextSetString(text, ""); if (str) XmStringFree(str); busy = 0; } void textModify(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { int row, column; Boolean focusIn; XmString str; char *c; /* If either Text widget changes (the Grid's Text widget or */ /* the Text widget outside of the Grid), update the other one */ /* to reflect to change and update the Grid itself if the */ /* Text widget outside the Grid changes. We set busy in this */ /* function to keep the XmTextSetString() from causing this */ /* callback to be called while inside the callback. */ if (busy) return; busy = 1; c = XmTextGetString(w); if (w == gridText) XmTextSetString(text, c); else { XmLGridGetFocus(grid, &row, &column, &focusIn); if (row != -1 && column != -1) { str = XmStringCreateSimple(c); XtVaSetValues(grid, XmNrow, row, XmNcolumn, column, XmNcellString, str, NULL); XmStringFree(str); XmTextSetString(gridText, c); } } XtFree(c); busy = 0; } void copy(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { XmLGridCopySelected(grid, CurrentTime); } void paste(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { /* This pastes starting at the current focus cell, an alternative */ /* method of pasting would be to have the user select an area */ /* to paste into. To perform this, we could get the selected area */ /* and use XmLGridPastePos() to paste into that area */ XmLGridPaste(grid); } nedit-5.6.orig/Microline/examples/grid4.c0000644000175000017500000002275210077552126017043 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include void cellSelect(); void showSelected(); #define HEADINGFONT "-*-helvetica-bold-o-*--*-100-*-*-*-*-iso8859-1" #define CONTENTFONT "-*-helvetica-medium-r-*--*-100-*-*-*-*-iso8859-1" #define check_width 9 #define check_height 9 static unsigned char check_bits[] = { 0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x61, 0x00, 0x37, 0x00, 0x3e, 0x00, 0x1c, 0x00, 0x08, 0x00, 0x00, 0x00}; #define nocheck_width 9 #define nocheck_height 9 static char nocheck_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static char *data[20] = { "3|Bob Thompson|bobt@teledyne.com", "12|Darl Simon|ds@atg.org", "14|Jacq Frontier|jf@terrax.com", "19|Patty Lee|patlee@isis.com", "22|Michal Barnes|mickeyb@softorb.com", "23|Dave Schultz|daves@timing.com", "23|Eric Stanley|ericst@aldor.com", "29|Tim Winters|timw@terra.com", "31|Agin Tomitu|agt@umn.edu", "33|Betty Tinner|bett@ost.edu", "37|Tom Smith|tsmith@netwld.com", "38|Rick Wild|raw@mlsoft.com", "41|Al Joyce|aj@ulm.edu", "41|Tim Burtan|timb@autoc.com", "41|George Marlin|gjm@eyeln.com", "41|Bill Boxer|billb@idesk.com", "41|Maria Montez|marm@ohio.edu", "41|Yin Fang|aj@utxs.edu", "41|Suzy Saps|ss@umg.edu", "41|Jerry Rodgers|jr@lyra.com", }; Pixmap nocheckPix, checkPix; Widget grid; main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell, form, button; Pixel blackPixel, whitePixel; Pixmap pix; int i; shell = XtAppInitialize(&app, "Grid4", NULL, 0, &argc, argv, NULL, NULL, 0); /* Create the pixmaps used for checkmarks */ blackPixel = BlackPixelOfScreen(XtScreen(shell)); whitePixel = WhitePixelOfScreen(XtScreen(shell)); checkPix = XCreatePixmapFromBitmapData(XtDisplay(shell), DefaultRootWindow(XtDisplay(shell)), check_bits, check_width, check_height, blackPixel, whitePixel, DefaultDepthOfScreen(XtScreen(shell))); nocheckPix = XCreatePixmapFromBitmapData(XtDisplay(shell), DefaultRootWindow(XtDisplay(shell)), nocheck_bits, nocheck_width, nocheck_height, blackPixel, whitePixel, DefaultDepthOfScreen(XtScreen(shell))); form = XtVaCreateManagedWidget("form", xmFormWidgetClass, shell, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XmNshadowThickness, 0, NULL); button = XtVaCreateManagedWidget("Show Selected", xmPushButtonWidgetClass, form, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, NULL); XtAddCallback(button, XmNactivateCallback, showSelected, NULL); /* Create a Grid with 4 columns. We set the fontList in this */ /* function for the Grid to use when calculating the visible rows */ grid = XtVaCreateManagedWidget("grid", xmlGridWidgetClass, form, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XtVaTypedArg, XmNfontList, XmRString, CONTENTFONT, strlen(CONTENTFONT) + 1, XmNcolumns, 4, XmNsimpleWidths, "3c 4c 17c 20c", XmNhorizontalSizePolicy, XmVARIABLE, XmNvsbDisplayPolicy, XmSTATIC, XmNvisibleRows, 13, XmNselectionPolicy, XmSELECT_NONE, XmNhighlightRowMode, True, XmNshadowType, XmSHADOW_ETCHED_IN, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button, NULL); XtAddCallback(grid, XmNselectCallback, cellSelect, NULL); /* Freeze the Grid's layout since we will be making changes which */ /* would cause the Grid to recompute its layout. The Grid will */ /* recompute its layout when layoutFrozen is set back to False */ XtVaSetValues(grid, XmNlayoutFrozen, True, NULL); /* Set defaults for new cells and aligments for new cells in */ /* columns 1-3. Then, add a heading row */ XtVaSetValues(grid, XmNcellDefaults, True, XtVaTypedArg, XmNcellFontList, XmRString, HEADINGFONT, strlen(HEADINGFONT) + 1, XtVaTypedArg, XmNcellBackground, XmRString, "#000080", 8, XtVaTypedArg, XmNcellForeground, XmRString, "white", 6, XmNcellLeftBorderType, XmBORDER_NONE, XmNcellRightBorderType, XmBORDER_NONE, XmNcellTopBorderType, XmBORDER_NONE, XmNcellBottomBorderType, XmBORDER_NONE, NULL); XtVaSetValues(grid, XmNcellDefaults, True, XmNcolumn, 1, XmNcellAlignment, XmALIGNMENT_RIGHT, NULL); XtVaSetValues(grid, XmNcellDefaults, True, XmNcolumnRangeStart, 2, XmNcolumnRangeEnd, 3, XmNcellAlignment, XmALIGNMENT_LEFT, NULL); XmLGridAddRows(grid, XmHEADING, -1, 1); /* Set the headings */ XmLGridSetStrings(grid, "OD|Qty|Name|EMail Addr"); /* Set defaults for new cells. Also, set the default cell type */ /* for cells in column 0 to pixmap cell. Then add the content rows */ XtVaSetValues(grid, XmNcellDefaults, True, XtVaTypedArg, XmNcellFontList, XmRString, CONTENTFONT, strlen(CONTENTFONT) + 1, XtVaTypedArg, XmNcellBackground, XmRString, "white", 6, XtVaTypedArg, XmNcellForeground, XmRString, "black", 6, XmNcellBottomBorderType, XmBORDER_LINE, XtVaTypedArg, XmNcellBottomBorderColor, XmRString, "black", 6, NULL); XtVaSetValues(grid, XmNcellDefaults, True, XmNcolumn, 0, XmNcellType, XmPIXMAP_CELL, NULL); XmLGridAddRows(grid, XmCONTENT, -1, 20); /* Set the content rows, Rows 2, 4, 5, 8 and 13 will have checkmarks */ for (i = 0; i < 20; i++) { XmLGridSetStringsPos(grid, XmCONTENT, i, XmCONTENT, 1, data[i]); if (i == 2 || i == 4 || i == 5 || i == 8 || i == 13) pix = checkPix; else pix = nocheckPix; XtVaSetValues(grid, XmNcolumn, 0, XmNrow, i, XmNcellPixmap, pix, NULL); } XtVaSetValues(grid, XmNlayoutFrozen, False, NULL); XtRealizeWidget(shell); XtAppMainLoop(app); } void showSelected(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { XmLGridRow row; XmLGridColumn column; Pixmap pix; int i, n; /* Display the selected rows, these are the rows which have a */ /* checkPix Pixmap in the first cell in the row */ printf ("Selected Rows: "); XtVaGetValues(grid, XmNrows, &n, NULL); for (i = 0; i < n; i++) { row = XmLGridGetRow(grid, XmCONTENT, i); column = XmLGridGetColumn(grid, XmCONTENT, 0); XtVaGetValues(grid, XmNrowPtr, row, XmNcolumnPtr, column, XmNcellPixmap, &pix, NULL); if (pix == checkPix) printf ("%d ", i); } printf ("\n"); } void cellSelect(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { XmLGridCallbackStruct *cbs; XmLGridRow row; XmLGridColumn column; Pixmap pix; cbs = (XmLGridCallbackStruct *)callData; if (cbs->reason != XmCR_SELECT_CELL) return; if (cbs->rowType != XmCONTENT) return; /* Toggle the Pixmap in the first cell */ row = XmLGridGetRow(w, cbs->rowType, cbs->row); column = XmLGridGetColumn(w, XmCONTENT, 0); XtVaGetValues(w, XmNrowPtr, row, XmNcolumnPtr, column, XmNcellPixmap, &pix, NULL); if (pix == nocheckPix) pix = checkPix; else pix = nocheckPix; XtVaSetValues(w, XmNrow, cbs->row, XmNcolumn, 0, XmNcellPixmap, pix, NULL); } nedit-5.6.orig/Microline/examples/grid5.c0000644000175000017500000001666310077552126017050 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include #define TITLEFONT "-*-helvetica-bold-r-*--*-140-*-*-*-*-iso8859-1" #define BOLDFONT "-*-helvetica-bold-r-*--*-120-*-*-*-*-iso8859-1" #define TEXTFONT "-*-helvetica-medium-r-*--*-100-*-*-*-*-iso8859-1" static char *data = "|1996 Income Summary\n\ |Shampoo|Conditioner|Soap|Total\n\ Revenues:\n\ Sales|$ 1,600,000|$ 1,000,000|$ 800,000|$ 3,400,000\n\ Less Discounts|(16,000)|(10,000)|(8,000)|(34,000)\n\ Less Return Allowance|(8,000)|(5,000)|(4,000)|(17,000)\n\ Net Revenue|1,576,000|985,000|792,000|3,349,000\n\ \n\ Less Expenses:\n\ Cost of Goods Sold|(640,000)|(330,000)|(264,000)|(1,234,000)\n\ Salary Expense|(380,000)|(280,000)|(180,000)|(840,000)\n\ Marketing Expense|(157,600)|(98,500)|(79,200)|(335,300)\n\ Rent Expense|(36,000)|(36,000)|(36,000)|(108,000)\n\ Misc. Other Expense|(36,408)|(22,335)|(16,776)|(75,519)\n\ Total Expenses|(1,250,008)|(766,835)|(575,976)|(2,592,819)\n\ \n\ Income Tax Expense|(130,397)|(87,266)|(86,410)|(304,072)\n\ Net Income|195,595|130,899|129,614|456,109"; main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell, grid; int i, r; shell = XtAppInitialize(&app, "Grid5", NULL, 0, &argc, argv, NULL, NULL, 0); grid = XtVaCreateManagedWidget("grid", xmlGridWidgetClass, shell, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XmNheadingColumns, 1, XmNcolumns, 3, XmNfooterColumns, 1, XmNsimpleWidths, "24c 11c 11c 11c 11c", XmNvisibleColumns, 10, XmNvisibleRows, 14, XtVaTypedArg, XmNfontList, XmRString, TEXTFONT, strlen(TEXTFONT) + 1, XmNselectionPolicy, XmSELECT_NONE, NULL); XtVaSetValues(grid, XmNlayoutFrozen, True, NULL); /* Add 'Income Summary' heading row with yellow background */ XtVaSetValues(grid, XmNcellDefaults, True, XtVaTypedArg, XmNcellBackground, XmRString, "#FFFF00", 8, XtVaTypedArg, XmNcellForeground, XmRString, "#000080", 8, XmNcellLeftBorderType, XmBORDER_NONE, XmNcellRightBorderType, XmBORDER_NONE, XmNcellTopBorderType, XmBORDER_NONE, XtVaTypedArg, XmNcellBottomBorderColor, XmRString, "black", 6, XmNcellAlignment, XmALIGNMENT_CENTER, NULL); XmLGridAddRows(grid, XmHEADING, -1, 1); /* Set span on '1996 Income Summary' cell in heading row */ XtVaSetValues(grid, XmNrowType, XmHEADING, XmNrow, 0, XmNcolumn, 0, XmNcellColumnSpan, 2, XtVaTypedArg, XmNcellFontList, XmRString, TITLEFONT, strlen(TITLEFONT) + 1, NULL); /* Add 'Shampoo Conditioner Soap' heading row with white background */ XtVaSetValues(grid, XmNcellDefaults, True, XtVaTypedArg, XmNcellFontList, XmRString, BOLDFONT, strlen(BOLDFONT) + 1, XtVaTypedArg, XmNcellBackground, XmRString, "white", 6, XtVaTypedArg, XmNcellForeground, XmRString, "black", 6, XmNcellBottomBorderType, XmBORDER_NONE, NULL); XmLGridAddRows(grid, XmHEADING, -1, 1); /* Add content and footer rows with heading column 0 left justified */ XtVaSetValues(grid, XmNcellDefaults, True, XmNcellAlignment, XmALIGNMENT_RIGHT, XtVaTypedArg, XmNcellFontList, XmRString, TEXTFONT, strlen(TEXTFONT) + 1, NULL); XtVaSetValues(grid, XmNcellDefaults, True, XmNcolumnType, XmHEADING, XmNcolumn, 0, XmNcellAlignment, XmALIGNMENT_LEFT, NULL); XmLGridAddRows(grid, XmCONTENT, -1, 15); /* Add footer row with blue background */ XtVaSetValues(grid, XmNcellDefaults, True, XtVaTypedArg, XmNcellForeground, XmRString, "white", 6, XtVaTypedArg, XmNcellBackground, XmRString, "#000080", 8, XtVaTypedArg, XmNcellFontList, XmRString, BOLDFONT, strlen(BOLDFONT) + 1, NULL); XmLGridAddRows(grid, XmFOOTER, -1, 1); /* Bold 'Revenues' cell */ XtVaSetValues(grid, XmNcolumnType, XmHEADING, XmNcolumn, 0, XmNrow, 0, XtVaTypedArg, XmNcellFontList, XmRString, BOLDFONT, strlen(BOLDFONT) + 1, NULL); /* Bold 'Less Expenses' cell */ XtVaSetValues(grid, XmNcolumnType, XmHEADING, XmNcolumn, 0, XmNrow, 6, XtVaTypedArg, XmNcellFontList, XmRString, BOLDFONT, strlen(BOLDFONT) + 1, NULL); /* Grey middle and footer content column */ XtVaSetValues(grid, XmNcolumnType, XmALL_TYPES, XmNcolumnRangeStart, 2, XmNcolumnRangeEnd, 4, XmNcolumnStep, 2, XtVaTypedArg, XmNcellBackground, XmRString, "#E8E8E8", 8, NULL); /* Grey 'Conditioner' and 'Total' cell in heading row 1 */ XtVaSetValues(grid, XmNrowType, XmHEADING, XmNrow, 1, XmNcolumnType, XmALL_TYPES, XmNcolumnRangeStart, 2, XmNcolumnRangeEnd, 4, XmNcolumnStep, 2, XtVaTypedArg, XmNcellBackground, XmRString, "#E8E8E8", 8, NULL); /* Blue and bold 'Net Revenue' and 'Total Expenses' rows */ XtVaSetValues(grid, XmNrowRangeStart, 4, XmNrowRangeEnd, 12, XmNrowStep, 8, XmNcolumnType, XmALL_TYPES, XtVaTypedArg, XmNcellForeground, XmRString, "white", 6, XtVaTypedArg, XmNcellBackground, XmRString, "#000080", 8, XtVaTypedArg, XmNcellFontList, XmRString, BOLDFONT, strlen(BOLDFONT) + 1, NULL); XtVaSetValues(grid, XmNlayoutFrozen, False, NULL); XmLGridSetStrings(grid, data); XtRealizeWidget(shell); XtAppMainLoop(app); } nedit-5.6.orig/Microline/examples/grid6.c0000644000175000017500000003110310077552126017033 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include #include /* DATABASE PROTOTYPE FUNCTIONS */ int dbTableNumRows = 14; int dbTableNumColumns = 5; typedef enum { ID, Desc, Price, Qty, UnitPrice, Buyer } DbTableColumnID; typedef struct { DbTableColumnID id; char label[15]; int width; unsigned char cellAlignment; Boolean cellEditable; } DbTableColumn; DbTableColumn dbTableColumns[] = { { Desc, "Description", 16, XmALIGNMENT_LEFT, True }, { Price, "Price", 9, XmALIGNMENT_LEFT, True }, { Qty, "Qty", 5, XmALIGNMENT_LEFT, True }, { UnitPrice, "Unit Prc", 9, XmALIGNMENT_LEFT, False }, { Buyer, "Buyer", 15, XmALIGNMENT_LEFT, True }, }; typedef struct { char key[10]; char desc[20]; float price; int qty; char buyer[20]; } DbTableRow; DbTableRow dbTableRows[] = { { "key01", "Staples", 1.32, 100, "Tim Pick" }, { "key02", "Notebooks", 1.11, 4, "Mary Miner" }, { "key03", "3-Ring Binders", 2.59, 2, "Mary Miner" }, { "key04", "Pads", 1.23, 3, "Tim Pick" }, { "key05", "Scissors", 4.41, 1, "Mary Miner" }, { "key06", "Pens", .29, 4, "Mary Miner" }, { "key07", "Pencils", .10, 5, "Tim Pick" }, { "key08", "Markers", .95, 3, "Mary Miner" }, { "key09", "Fax Paper", 3.89, 100, "Bob Coal" }, { "key10", "3.5\" Disks", 15.23, 30, "Tim Pick" }, { "key11", "8mm Tape", 32.22, 2, "Bob Coal" }, { "key12", "Toner", 35.69, 1, "Tim Pick" }, { "key13", "Paper Cups", 4.25, 3, "Bob Coal" }, { "key14", "Paper Clips", 2.09, 3, "Tim Pick" }, }; DbTableRow *dbFindRow(rowKey) char *rowKey; { int i; for (i = 0; i < dbTableNumRows; i++) if (!strcmp(rowKey, dbTableRows[i].key)) return &dbTableRows[i]; return 0; } int dbCompareRowKeys(userData, l, r) void *userData; void *l; void *r; { DbTableRow *dbRow1, *dbRow2; float u1, u2; dbRow1 = dbFindRow(*(char **)l); dbRow2 = dbFindRow(*(char **)r); switch ((int)userData) { case Desc: return strcmp(dbRow1->desc, dbRow2->desc); case Price: u1 = dbRow1->price - dbRow2->price; if (u1 < 0) return -1; else if (u1 == 0) return 0; return 1; case Qty: return dbRow1->qty - dbRow2->qty; case UnitPrice: u1 = dbRow1->price / (float)dbRow1->qty; u2 = dbRow2->price / (float)dbRow2->qty; if (u1 < u2) return -1; else if (u1 == u2) return 0; else return 1; case Buyer: return strcmp(dbRow1->buyer, dbRow2->buyer); } return (int)(dbRow1 - dbRow2); } char **dbGetRowKeysSorted(sortColumnID) int sortColumnID; { char **keys; int i; keys = (char **)malloc(sizeof(char *) * dbTableNumRows); for (i = 0; i < dbTableNumRows; i++) keys[i] = dbTableRows[i].key; XmLSort(keys, dbTableNumRows, sizeof(char *), dbCompareRowKeys, (void *)sortColumnID); return keys; } /* GRID FUNCTIONS */ void setRowKeysInGridSorted(grid, sortColumnID) Widget grid; int sortColumnID; { char **keys; int i; keys = dbGetRowKeysSorted(sortColumnID); /* Place a pointer to each row key in each rows userData */ for (i = 0; i < dbTableNumRows; i++) XtVaSetValues(grid, XmNrow, i, XmNrowUserData, (XtPointer)keys[i], NULL); free((char *)keys); } void cellSelect(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { XmLGridCallbackStruct *cbs; XmLGridColumn column; XtPointer columnUserData; cbs = (XmLGridCallbackStruct *)callData; if (cbs->rowType != XmHEADING) return; /* Cancel any edits in progress */ XmLGridEditCancel(w); column = XmLGridGetColumn(w, cbs->columnType, cbs->column); XtVaGetValues(w, XmNcolumnPtr, column, XmNcolumnUserData, &columnUserData, NULL); XtVaSetValues(w, XmNcolumn, cbs->column, XmNcolumnSortType, XmSORT_ASCENDING, NULL); setRowKeysInGridSorted(w, (DbTableColumnID)columnUserData); XmLGridRedrawAll(w); } void cellDraw(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { XmLGridCallbackStruct *cbs; XmLGridDrawStruct *ds; XmLGridRow row; XmLGridColumn column; XtPointer rowUserData, columnUserData; DbTableRow *dbRow; XRectangle cellRect; int horizMargin, vertMargin; XmString str; char buf[50]; cbs = (XmLGridCallbackStruct *)callData; if (cbs->rowType != XmCONTENT) return; ds = cbs->drawInfo; /* Retrieve userData from the cells row */ row = XmLGridGetRow(w, cbs->rowType, cbs->row); XtVaGetValues(w, XmNrowPtr, row, XmNrowUserData, &rowUserData, NULL); /* Retrieve userData from cells column */ column = XmLGridGetColumn(w, cbs->columnType, cbs->column); XtVaGetValues(w, XmNcolumnPtr, column, XmNcolumnUserData, &columnUserData, NULL); /* Retrieve the cells value from the database */ dbRow = dbFindRow((char *)rowUserData); switch ((DbTableColumnID)columnUserData) { case Desc: sprintf(buf, "%s", dbRow->desc); break; case Price: sprintf(buf, "$%4.2f", dbRow->price); break; case Qty: sprintf(buf, "%d", dbRow->qty); break; case UnitPrice: sprintf(buf, "$%4.2f", dbRow->price / (float)dbRow->qty); break; case Buyer: sprintf(buf, "%s", dbRow->buyer); break; } /* Compensate for cell margins */ cellRect = *ds->cellRect; horizMargin = ds->leftMargin + ds->rightMargin; vertMargin = ds->topMargin + ds->bottomMargin; if (horizMargin >= (int)cellRect.width || vertMargin >= (int)cellRect.height) return; cellRect.x += ds->leftMargin; cellRect.y += ds->topMargin; cellRect.width -= horizMargin; cellRect.height -= vertMargin; /* Draw the string */ str = XmStringCreateSimple(buf); if (ds->drawSelected == True) XSetForeground(XtDisplay(w), ds->gc, ds->selectForeground); else XSetForeground(XtDisplay(w), ds->gc, ds->foreground); XmLStringDraw(w, str, ds->stringDirection, ds->fontList, ds->alignment, ds->gc, &cellRect, cbs->clipRect); XmStringFree(str); } void cellEdit(w, clientData, callData) Widget w; XtPointer clientData; XtPointer callData; { XmLGridCallbackStruct *cbs; XmLGridRow row; XmLGridColumn column; XtPointer rowUserData, columnUserData; DbTableRow *dbRow; Widget text; float f; int i; char *value; Boolean redrawRow; cbs = (XmLGridCallbackStruct *)callData; /* For a production version, this function should also handle XmCR_EDIT_INSERT by retrieving the current value from the database and performing an XmTextSetString on the text widget in the grid with that value. This allows a user to hit insert or F2 to modify an existing cell value */ if (cbs->reason != XmCR_EDIT_COMPLETE) return; /* Get the value the user just typed in */ XtVaGetValues(w, XmNtextWidget, &text, NULL); value = XmTextGetString(text); if (!value) return; /* Retrieve userData from the cells row */ row = XmLGridGetRow(w, cbs->rowType, cbs->row); XtVaGetValues(w, XmNrowPtr, row, XmNrowUserData, &rowUserData, NULL); /* Retrieve userData from cells column */ column = XmLGridGetColumn(w, cbs->columnType, cbs->column); XtVaGetValues(w, XmNcolumnPtr, column, XmNcolumnUserData, &columnUserData, NULL); /* Set new value in the database */ redrawRow = False; dbRow = dbFindRow((char *)rowUserData); switch ((DbTableColumnID)columnUserData) { case Desc: if ((int)strlen(value) < 20) strcpy(dbRow->desc, value); break; case Price: if (sscanf(value, "%f", &f) == 1) { dbRow->price = f; redrawRow = True; } break; case Qty: if (sscanf(value, "%d", &i) == 1) { dbRow->qty = i; redrawRow = True; } break; case Buyer: if ((int)strlen(value) < 20) strcpy(dbRow->buyer, value); break; } /* Redraw the row if we need to redisplay unit price */ if (redrawRow == True) XmLGridRedrawRow(w, cbs->rowType, cbs->row); /* Set the cellString to NULL - its is set to the value the user typed in the text widget at this point */ XtVaSetValues(w, XmNrow, cbs->row, XmNcolumn, cbs->column, XmNcellString, NULL, NULL); XtFree(value); } main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell, grid; XmString str; int i; shell = XtAppInitialize(&app, "Grid6", NULL, 0, &argc, argv, NULL, NULL, 0); grid = XtVaCreateManagedWidget("grid", xmlGridWidgetClass, shell, XmNhorizontalSizePolicy, XmVARIABLE, XmNvisibleRows, 10, XmNvsbDisplayPolicy, XmSTATIC, XmNselectionPolicy, XmSELECT_NONE, XmNshadowThickness, 0, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, NULL); XtAddCallback(grid, XmNcellDrawCallback, cellDraw, NULL); XtAddCallback(grid, XmNeditCallback, cellEdit, NULL); XtAddCallback(grid, XmNselectCallback, cellSelect, NULL); XtVaSetValues(grid, XmNlayoutFrozen, True, NULL); XmLGridAddColumns(grid, XmCONTENT, -1, dbTableNumColumns); /* Setup columns and column cell defaults based on */ /* database description */ for (i = 0; i < dbTableNumColumns; i++) { /* Set the width and the id on the column */ XtVaSetValues(grid, XmNcolumn, i, XmNcolumnUserData, (XtPointer)dbTableColumns[i].id, XmNcolumnWidth, dbTableColumns[i].width, NULL); /* Set the default cell alignment and editibility for */ /* cells in the column */ XtVaSetValues(grid, XmNcellDefaults, True, XmNcolumn, i, XmNcellAlignment, dbTableColumns[i].cellAlignment, XmNcellEditable, dbTableColumns[i].cellEditable, NULL); } /* Add the heading row */ XmLGridAddRows(grid, XmHEADING, -1, 1); /* Set the column headings */ for (i = 0; i < dbTableNumColumns; i++) { /* Set the column heading label */ str = XmStringCreateSimple(dbTableColumns[i].label); XtVaSetValues(grid, XmNrowType, XmHEADING, XmNrow, 0, XmNcolumn, i, XmNcellString, str, NULL); XmStringFree(str); } /* Set cell defaults for content rows */ XtVaSetValues(grid, XmNcellDefaults, True, XtVaTypedArg, XmNcellBackground, XmRString, "white", 6, XmNcellLeftBorderType, XmBORDER_NONE, XmNcellRightBorderType, XmBORDER_NONE, XmNcellTopBorderType, XmBORDER_NONE, XmNcellBottomBorderType, XmBORDER_NONE, XmNcellMarginLeft, 1, XmNcellMarginRight, 1, NULL); XmLGridAddRows(grid, XmCONTENT, -1, dbTableNumRows); XtVaSetValues(grid, XmNlayoutFrozen, False, NULL); /* Set the row keys in the rows */ setRowKeysInGridSorted(grid, Desc); XtRealizeWidget(shell); XtAppMainLoop(app); } nedit-5.6.orig/Microline/examples/prog1.c0000644000175000017500000000577010077552126017063 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell, progress; shell = XtAppInitialize(&app, "Prog1", NULL, 0, &argc, argv, NULL, NULL, 0); progress = XtVaCreateManagedWidget("progress", xmlProgressWidgetClass, shell, XtVaTypedArg, XmNbackground, XmRString, "white", 6, XtVaTypedArg, XmNforeground, XmRString, "#000080", 8, XmNwidth, 300, XmNheight, 25, NULL); XtVaSetValues(progress, XmNvalue, 50, NULL); XtRealizeWidget(shell); XtAppMainLoop(app); } nedit-5.6.orig/Microline/examples/prog2.c0000644000175000017500000000654110077552126017061 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include Boolean compute(); Widget progress; main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell; shell = XtAppInitialize(&app, "Prog2", NULL, 0, &argc, argv, NULL, NULL, 0); progress = XtVaCreateManagedWidget("progress", xmlProgressWidgetClass, shell, XmNshowTime, True, XtVaTypedArg, XmNbackground, XmRString, "white", 6, XtVaTypedArg, XmNforeground, XmRString, "#800000", 8, XmNwidth, 300, XmNheight, 25, NULL); XtAppAddWorkProc(app, compute, NULL); XtRealizeWidget(shell); XtAppMainLoop(app); } Boolean compute(clientData) XtPointer clientData; { int i; XtVaSetValues(progress, XmNvalue, 0, XmNcompleteValue, 7, NULL); for (i = 0; i < 7; i++) { XtVaSetValues(progress, XmNvalue, i, NULL); /* perform processing */ sleep(1); } XtVaSetValues(progress, XmNvalue, i, NULL); return(FALSE); } nedit-5.6.orig/Microline/examples/prog3.c0000644000175000017500000000676610077552126017073 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include Boolean compute(); Widget progress; main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell; shell = XtAppInitialize(&app, "Prog3", NULL, 0, &argc, argv, NULL, NULL, 0); progress = XtVaCreateManagedWidget("progress", xmlProgressWidgetClass, shell, XtVaTypedArg, XmNbackground, XmRString, "white", 6, XtVaTypedArg, XmNforeground, XmRString, "#000080", 8, XtVaTypedArg, XmNtopShadowColor, XmRString, "#D0D0D0", 8, XtVaTypedArg, XmNbottomShadowColor, XmRString, "black", 6, XmNmeterStyle, XmMETER_BOXES, XmNnumBoxes, 20, XmNwidth, 300, XmNheight, 20, XmNshadowThickness, 1, NULL); XtAppAddWorkProc(app, compute, NULL); XtRealizeWidget(shell); XtAppMainLoop(app); } Boolean compute(clientData) XtPointer clientData; { int i; XtVaSetValues(progress, XmNvalue, 0, XmNcompleteValue, 7, NULL); for (i = 0; i < 7; i++) { XtVaSetValues(progress, XmNvalue, i, NULL); sleep(1); } XtVaSetValues(progress, XmNvalue, i, NULL); return(FALSE); } nedit-5.6.orig/Microline/examples/tree1.c0000644000175000017500000001013610077552126017043 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell, tree; Pixmap pixmap, pixmask; XmString str; shell = XtAppInitialize(&app, "Tree1", NULL, 0, &argc, argv, NULL, NULL, 0); tree = XtVaCreateManagedWidget("tree", xmlTreeWidgetClass, shell, XmNvisibleRows, 10, XmNwidth, 250, NULL); XtVaSetValues(tree, XmNlayoutFrozen, True, NULL); pixmap = XmUNSPECIFIED_PIXMAP; pixmask = XmUNSPECIFIED_PIXMAP; str = XmStringCreateSimple("Root"); XmLTreeAddRow(tree, 0, True, True, -1, pixmap, pixmask, str); XmStringFree(str); str = XmStringCreateSimple("Level 1 Parent"); XmLTreeAddRow(tree, 1, True, True, -1, pixmap, pixmask, str); XmStringFree(str); str = XmStringCreateSimple("1st Child of Level 1 Parent"); XmLTreeAddRow(tree, 2, False, False, -1, pixmap, pixmask, str); XmStringFree(str); str = XmStringCreateSimple("2nd Child of Level 1 Parent"); XmLTreeAddRow(tree, 2, False, False, -1, pixmap, pixmask, str); XmStringFree(str); str = XmStringCreateSimple("Level 2 Parent"); XmLTreeAddRow(tree, 2, True, True, -1, pixmap, pixmask, str); XmStringFree(str); str = XmStringCreateSimple("Child of Level 2 Parent"); XmLTreeAddRow(tree, 3, False, False, -1, pixmap, pixmask, str); XmStringFree(str); str = XmStringCreateSimple("Level 1 Parent"); XmLTreeAddRow(tree, 1, True, True, -1, pixmap, pixmask, str); XmStringFree(str); str = XmStringCreateSimple("Child of Level 1 Parent"); XmLTreeAddRow(tree, 2, False, False, -1, pixmap, pixmask, str); XmStringFree(str); XtVaSetValues(tree, XmNlayoutFrozen, False, NULL); XtRealizeWidget(shell); XtAppMainLoop(app); } nedit-5.6.orig/Microline/examples/tree2.c0000644000175000017500000001055110077552126017045 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell, tree; int i, n, size; XmString str; XmLTreeRowDefinition *rows; static struct { Boolean expands; int level; char *string; } data[] = { { True, 0, "Root" }, { True, 1, "Level 1 Parent" }, { False, 2, "1st Child of Level 1 Parent" }, { False, 2, "2nd Child of Level 1 Parent" }, { True, 2, "Level 2 Parent" }, { False, 3, "Child of Level 2 Parent" }, { True, 1, "Level 1 Parent" }, { False, 2, "Child of Level 1 Parent" }, }; shell = XtAppInitialize(&app, "Tree2", NULL, 0, &argc, argv, NULL, NULL, 0); tree = XtVaCreateManagedWidget("tree", xmlTreeWidgetClass, shell, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 6, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XtVaTypedArg, XmNblankBackground, XmRString, "white", 6, XtVaTypedArg, XmNselectBackground, XmRString, "#000080", 8, XtVaTypedArg, XmNselectForeground, XmRString, "white", 6, XtVaTypedArg, XmNconnectingLineColor, XmRString, "#808080", 8, XmNvisibleRows, 10, XmNwidth, 250, NULL); XtVaSetValues(tree, XmNcellDefaults, True, XtVaTypedArg, XmNcellBackground, XmRString, "white", 6, NULL); /* Create a TreeRowDefinition array from the data array */ /* and add rows to the Tree */ n = 8; size = sizeof(XmLTreeRowDefinition) * n; rows = (XmLTreeRowDefinition *)malloc(size); for (i = 0; i < n; i++) { rows[i].level = data[i].level; rows[i].expands = data[i].expands; rows[i].isExpanded = True; rows[i].pixmap = XmUNSPECIFIED_PIXMAP; rows[i].pixmask = XmUNSPECIFIED_PIXMAP; rows[i].string = XmStringCreateSimple(data[i].string); } XmLTreeAddRows(tree, rows, n, -1); /* Free the TreeRowDefintion array (and XmStrings) we created above */ for (i = 0; i < n; i++) XmStringFree(rows[i].string); free((char *)rows); XtRealizeWidget(shell); XtAppMainLoop(app); } nedit-5.6.orig/Microline/examples/tree3.c0000644000175000017500000001456510077552126017057 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include #define sphere_width 16 #define sphere_height 16 static unsigned char sphere_bits[] = { 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0x38, 0x3f, 0xb8, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf0, 0x1f, 0xe0, 0x0f, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; #define monitor_width 16 #define monitor_height 16 static unsigned char monitor_bits[] = { 0x00, 0x00, 0xf8, 0x3f, 0xf8, 0x3f, 0x18, 0x30, 0x58, 0x37, 0x18, 0x30, 0x58, 0x37, 0x18, 0x30, 0xf8, 0x3f, 0xf8, 0x3f, 0x80, 0x03, 0x80, 0x03, 0xf0, 0x1f, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00}; main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell, tree; XmLTreeRowDefinition *rows; Pixmap monitorPixmap, spherePixmap; Pixel black, white; int i, n, size; static struct { Boolean expands; int level; char *string; } data[] = { { True, 0, "Root" }, { True, 1, "Parent A" }, { False, 2, "Node A1" }, { False, 2, "Node A2" }, { True, 2, "Parent B" }, { False, 3, "Node B1" }, { False, 3, "Node B2" }, { True, 1, "Parent C" }, { False, 2, "Node C1" }, { True, 1, "Parent D" }, { False, 2, "Node D1" }, }; shell = XtAppInitialize(&app, "Tree3", NULL, 0, &argc, argv, NULL, NULL, 0); black = BlackPixelOfScreen(XtScreen(shell)); white = WhitePixelOfScreen(XtScreen(shell)); spherePixmap = XCreatePixmapFromBitmapData(XtDisplay(shell), DefaultRootWindow(XtDisplay(shell)), sphere_bits, sphere_width, sphere_height, black, white, DefaultDepthOfScreen(XtScreen(shell))); monitorPixmap = XCreatePixmapFromBitmapData(XtDisplay(shell), DefaultRootWindow(XtDisplay(shell)), monitor_bits, monitor_width, monitor_height, black, white, DefaultDepthOfScreen(XtScreen(shell))); /* Create a Tree with 3 columns and 1 heading row in multiple */ /* select mode. We also set globalPixmapWidth and height here */ /* which specifys that every Pixmap we set on the Tree will be */ /* the size specified (16x16). This will increase performance. */ tree = XtVaCreateManagedWidget("tree", xmlTreeWidgetClass, shell, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XtVaTypedArg, XmNblankBackground, XmRString, "white", 6, XtVaTypedArg, XmNselectBackground, XmRString, "#000080", 8, XtVaTypedArg, XmNselectForeground, XmRString, "white", 6, XtVaTypedArg, XmNconnectingLineColor, XmRString, "#808080", 8, XmNallowColumnResize, True, XmNheadingRows, 1, XmNvisibleRows, 14, XmNcolumns, 3, XmNvisibleColumns, 5, XmNsimpleWidths, "12c 8c 10c", XmNsimpleHeadings, "All Folders|SIZE|DATA2", XmNselectionPolicy, XmSELECT_MULTIPLE_ROW, XmNhighlightRowMode, True, XmNglobalPixmapWidth, 16, XmNglobalPixmapHeight, 16, NULL); /* Set default values for new cells (the cells in the content rows) */ XtVaSetValues(tree, XmNcellDefaults, True, XtVaTypedArg, XmNcellBackground, XmRString, "white", 6, XmNcellLeftBorderType, XmBORDER_NONE, XmNcellRightBorderType, XmBORDER_NONE, XmNcellTopBorderType, XmBORDER_NONE, XmNcellBottomBorderType, XmBORDER_NONE, NULL); /* Create a TreeRowDefinition array from the data array */ /* and add rows to the Tree */ n = 11; size = sizeof(XmLTreeRowDefinition) * n; rows = (XmLTreeRowDefinition *)malloc(size); for (i = 0; i < n; i++) { rows[i].level = data[i].level; rows[i].expands = data[i].expands; rows[i].isExpanded = True; if (data[i].expands) rows[i].pixmap = spherePixmap; else rows[i].pixmap = monitorPixmap; rows[i].pixmask = XmUNSPECIFIED_PIXMAP; rows[i].string = XmStringCreateSimple(data[i].string); } XmLTreeAddRows(tree, rows, n, -1); /* Free the TreeRowDefintion array we created above and set strings */ /* in column 1 and 2 */ for (i = 0; i < n; i++) { XmStringFree(rows[i].string); XmLGridSetStringsPos(tree, XmCONTENT, i, XmCONTENT, 1, "1032|1123"); } free((char *)rows); XtRealizeWidget(shell); XtAppMainLoop(app); } nedit-5.6.orig/Microline/examples/tree4.c0000644000175000017500000002215010077552126017045 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include #include #include #include void rowExpand(); void rowCollapse(); void rowDelete(); void cellSelect(); Widget grid; main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell, form, tree; XmString str; shell = XtAppInitialize(&app, "Tree4", NULL, 0, &argc, argv, NULL, NULL, 0); form = XtVaCreateManagedWidget("form", xmFormWidgetClass, shell, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XmNshadowThickness, 0, NULL); /* Add Tree to left of Form */ tree = XtVaCreateManagedWidget("tree", xmlTreeWidgetClass, form, XmNhorizontalSizePolicy, XmCONSTANT, XmNautoSelect, False, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XtVaTypedArg, XmNblankBackground, XmRString, "white", 6, XtVaTypedArg, XmNselectBackground, XmRString, "#000080", 8, XtVaTypedArg, XmNselectForeground, XmRString, "white", 6, XtVaTypedArg, XmNconnectingLineColor, XmRString, "#808080", 8, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 45, NULL); XtVaSetValues(tree, XmNcellDefaults, True, XtVaTypedArg, XmNcellBackground, XmRString, "white", 6, NULL); /* Add a single row containing the root path to the Tree */ str = XmStringCreateSimple("/"); XmLTreeAddRow(tree, 1, True, False, 0, XmUNSPECIFIED_PIXMAP, XmUNSPECIFIED_PIXMAP, str); XmStringFree(str); XtVaSetValues(tree, XmNrow, 0, XmNrowUserData, strdup("/"), NULL); XtAddCallback(tree, XmNexpandCallback, rowExpand, NULL); XtAddCallback(tree, XmNcollapseCallback, rowCollapse, NULL); XtAddCallback(tree, XmNdeleteCallback, rowDelete, NULL); XtAddCallback(tree, XmNselectCallback, cellSelect, NULL); /* Add a Grid to the right of the Form and set cell defaults */ grid = XtVaCreateManagedWidget("grid", xmlGridWidgetClass, form, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XtVaTypedArg, XmNblankBackground, XmRString, "white", 6, XtVaTypedArg, XmNselectBackground, XmRString, "#000080", 8, XtVaTypedArg, XmNselectForeground, XmRString, "white", 6, XmNcolumns, 3, XmNsimpleWidths, "24c 12c 10c", XmNsimpleHeadings, "Name|Type|Size", XmNvisibleColumns, 6, XmNallowColumnResize, True, XmNheadingRows, 1, XmNvisibleRows, 16, XmNhighlightRowMode, True, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 46, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); XtVaSetValues(grid, XmNcellDefaults, True, XtVaTypedArg, XmNcellBackground, XmRString, "white", 6, XmNcellTopBorderType, XmBORDER_NONE, XmNcellBottomBorderType, XmBORDER_NONE, XmNcellRightBorderType, XmBORDER_NONE, XmNcellLeftBorderType, XmBORDER_NONE, XmNcellAlignment, XmALIGNMENT_LEFT, NULL); XtVaSetValues(grid, XmNcellDefaults, True, XmNcolumn, 2, XmNcellAlignment, XmALIGNMENT_RIGHT, NULL); /* Invoke the select callback for the first row in the Tree */ /* to fill the Grid with the data for the root path */ XmLGridSelectRow(tree, 0, True); XtRealizeWidget(shell); XtAppMainLoop(app); } void rowExpand(w, clientData, callData) Widget w; XtPointer clientData, callData; { XmLGridCallbackStruct *cbs; XmLGridRow row; int level, pos; DIR *dir; struct dirent *d; struct stat s; char *path, fullpath[1024]; XmString str; /* Retrieve the path of the directory expanded. This is kept */ /* in the row's rowUserData */ cbs = (XmLGridCallbackStruct *)callData; row = XmLGridGetRow(w, XmCONTENT, cbs->row); XtVaGetValues(w, XmNrowPtr, row, XmNrowUserData, &path, XmNrowLevel, &level, NULL); pos = cbs->row + 1; dir = opendir(path); if (!dir) return; /* Add the subdirectories of the directory expanded to the Tree */ XtVaSetValues(w, XmNlayoutFrozen, True, NULL); while (d = readdir(dir)) { if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) continue; sprintf(fullpath, "%s/%s", path, d->d_name); if (lstat(fullpath, &s) == -1) continue; if (!S_ISDIR(s.st_mode)) continue; str = XmStringCreateSimple(d->d_name); XmLTreeAddRow(w, level + 1, True, False, pos, XmUNSPECIFIED_PIXMAP, XmUNSPECIFIED_PIXMAP, str); XmStringFree(str); XtVaSetValues(w, XmNrow, pos, XmNrowUserData, strdup(fullpath), NULL); pos++; } closedir(dir); XtVaSetValues(w, XmNlayoutFrozen, False, NULL); } void rowCollapse(w, clientData, callData) Widget w; XtPointer clientData, callData; { XmLGridCallbackStruct *cbs; XmLGridRow row; char *path; int i, j, level, rows; /* Collapse the row by deleting the rows in the tree which */ /* are children of the collapsed row. */ cbs = (XmLGridCallbackStruct *)callData; XmLTreeDeleteChildren(w, cbs->row); } void rowDelete(w, clientData, callData) Widget w; XtPointer clientData, callData; { /* Free the path contained in the rowUserData of the rows deleted */ XmLGridCallbackStruct *cbs; XmLGridRow row; char *path; cbs = (XmLGridCallbackStruct *)callData; if (cbs->rowType != XmCONTENT || cbs->reason != XmCR_DELETE_ROW) return; row = XmLGridGetRow(w, XmCONTENT, cbs->row); XtVaGetValues(w, XmNrowPtr, row, XmNrowUserData, &path, NULL); if (path) free(path); } void cellSelect(w, clientData, callData) Widget w; XtPointer clientData, callData; { XmLGridCallbackStruct *cbs; XmLGridRow row; DIR *dir; struct stat s; struct dirent *d; char *path, fullpath[1024], buf[256]; int pos; /* Retrieve the directory selected */ cbs = (XmLGridCallbackStruct *)callData; if (cbs->rowType != XmCONTENT) return; row = XmLGridGetRow(w, XmCONTENT, cbs->row); XtVaGetValues(w, XmNrowPtr, row, XmNrowUserData, &path, NULL); dir = opendir(path); if (!dir) return; /* Add a row for each file in the directory to the Grid */ pos = 0; XtVaSetValues(grid, XmNlayoutFrozen, True, NULL); XmLGridDeleteAllRows(grid, XmCONTENT); while (d = readdir(dir)) { sprintf(fullpath, "%s/%s", path, d->d_name); if (lstat(fullpath, &s) == -1) continue; XmLGridAddRows(grid, XmCONTENT, pos, 1); XmLGridSetStringsPos(grid, XmCONTENT, pos, XmCONTENT, 0, d->d_name); if (S_ISDIR(s.st_mode)) sprintf(buf, "Directory"); else if (S_ISLNK(s.st_mode)) sprintf(buf, "Link"); else sprintf(buf, "File"); XmLGridSetStringsPos(grid, XmCONTENT, pos, XmCONTENT, 1, buf); sprintf(buf, "%d", (int)s.st_size); XmLGridSetStringsPos(grid, XmCONTENT, pos, XmCONTENT, 2, buf); pos++; } closedir(dir); XtVaSetValues(grid, XmNlayoutFrozen, False, NULL); } nedit-5.6.orig/Microline/examples/tree5.c0000644000175000017500000002000210077552126017040 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include #define sphere_width 16 #define sphere_height 16 static unsigned char sphere_bits[] = { 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0x38, 0x3f, 0xb8, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf0, 0x1f, 0xe0, 0x0f, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; #define monitor_width 16 #define monitor_height 16 static unsigned char monitor_bits[] = { 0x00, 0x00, 0xf8, 0x3f, 0xf8, 0x3f, 0x18, 0x30, 0x58, 0x37, 0x18, 0x30, 0x58, 0x37, 0x18, 0x30, 0xf8, 0x3f, 0xf8, 0x3f, 0x80, 0x03, 0x80, 0x03, 0xf0, 0x1f, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00}; #if 0 void hide_cb(Widget w, XtPointer clientData, XtPointer cb_data) { Widget tree = (Widget) clientData; XmLGridHideRightColumn(tree); } void show_cb(Widget w, XtPointer clientData, XtPointer cb_data) { Widget tree = (Widget) clientData; XmLGridUnhideRightColumn(tree); } #endif /*0*/ main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell, tree, form, hideB, showB; XmLTreeRowDefinition *rows; Pixmap monitorPixmap, spherePixmap; Pixel black, white; int i, n, size; static struct { Boolean expands; int level; char *string; } data[] = { { True, 0, "Root" }, { True, 1, "Parent A" }, { False, 2, "Node A1" }, { False, 2, "Node A2" }, { True, 2, "Parent B" }, { False, 3, "Node B1" }, { False, 3, "Node B2" }, { True, 1, "Parent C" }, { False, 2, "Node C1" }, { True, 1, "Parent D" }, { False, 2, "Node D1" }, }; shell = XtAppInitialize(&app, "Tree3", NULL, 0, &argc, argv, NULL, NULL, 0); black = BlackPixelOfScreen(XtScreen(shell)); white = WhitePixelOfScreen(XtScreen(shell)); spherePixmap = XCreatePixmapFromBitmapData(XtDisplay(shell), DefaultRootWindow(XtDisplay(shell)), sphere_bits, sphere_width, sphere_height, black, white, DefaultDepthOfScreen(XtScreen(shell))); monitorPixmap = XCreatePixmapFromBitmapData(XtDisplay(shell), DefaultRootWindow(XtDisplay(shell)), monitor_bits, monitor_width, monitor_height, black, white, DefaultDepthOfScreen(XtScreen(shell))); form = XtVaCreateManagedWidget("form", xmFormWidgetClass, shell, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XmNshadowThickness, 0, NULL); #if 0 hideB = XtVaCreateManagedWidget("hide", xmPushButtonWidgetClass, form, XmNleftAttachment, XmATTACH_NONE, XmNtopAttachment, XmATTACH_POSITION, XmNtopPosition, 30, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, NULL); showB = XtVaCreateManagedWidget("show", xmPushButtonWidgetClass, form, XmNleftAttachment, XmATTACH_NONE, XmNtopAttachment, XmATTACH_POSITION, XmNtopPosition, 30, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, hideB, NULL); #endif /*0*/ /* Create a Tree with 3 columns and 1 heading row in multiple */ /* select mode. We also set globalPixmapWidth and height here */ /* which specifys that every Pixmap we set on the Tree will be */ /* the size specified (16x16). This will increase performance. */ tree = XtVaCreateManagedWidget("tree", xmlTreeWidgetClass, form, XtVaTypedArg, XmNbackground, XmRString, "#C0C0C0", 8, XtVaTypedArg, XmNforeground, XmRString, "black", 6, XtVaTypedArg, XmNblankBackground, XmRString, "white", 6, XtVaTypedArg, XmNselectBackground, XmRString, "#000080", 8, XtVaTypedArg, XmNselectForeground, XmRString, "white", 6, XtVaTypedArg, XmNconnectingLineColor, XmRString, "#808080", 8, XmNhorizontalSizePolicy, XmRESIZE_IF_POSSIBLE, XmNallowColumnResize, True, XmNheadingRows, 1, XmNvisibleRows, 14, XmNcolumns, 3, XmNvisibleColumns, 1, XmNhideUnhideButtons, True, XmNsimpleWidths, "80c 40c 40c", XmNsimpleHeadings, "All Folders|SIZE|DATA2", XmNselectionPolicy, XmSELECT_MULTIPLE_ROW, XmNhighlightRowMode, True, XmNglobalPixmapWidth, 16, XmNglobalPixmapHeight, 16, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, #if 0 XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, showB, #endif /*0*/ XmNdebugLevel, 2, NULL); /* Set default values for new cells (the cells in the content rows) */ XtVaSetValues(tree, XmNcellDefaults, True, XtVaTypedArg, XmNcellBackground, XmRString, "white", 6, XmNcellEditable, True, XmNcellLeftBorderType, XmBORDER_NONE, XmNcellRightBorderType, XmBORDER_NONE, XmNcellTopBorderType, XmBORDER_NONE, XmNcellBottomBorderType, XmBORDER_NONE, NULL); #if 0 XtAddCallback(hideB, XmNactivateCallback, hide_cb, (XtPointer)tree); XtAddCallback(showB, XmNactivateCallback, show_cb, (XtPointer)tree); #endif /*0*/ /* Create a TreeRowDefinition array from the data array */ /* and add rows to the Tree */ n = 11; size = sizeof(XmLTreeRowDefinition) * n; rows = (XmLTreeRowDefinition *)malloc(size); for (i = 0; i < n; i++) { rows[i].level = data[i].level; rows[i].expands = data[i].expands; rows[i].isExpanded = True; if (data[i].expands) rows[i].pixmap = spherePixmap; else rows[i].pixmap = monitorPixmap; rows[i].pixmask = XmUNSPECIFIED_PIXMAP; rows[i].string = XmStringCreateSimple(data[i].string); } XmLTreeAddRows(tree, rows, n, -1); /* Free the TreeRowDefintion array we created above and set strings */ /* in column 1 and 2 */ for (i = 0; i < n; i++) { XmStringFree(rows[i].string); XmLGridSetStringsPos(tree, XmCONTENT, i, XmCONTENT, 1, "1032|1123"); } free((char *)rows); XtRealizeWidget(shell); XtAppMainLoop(app); } nedit-5.6.orig/Microline/examples/uil1.c0000644000175000017500000001030310077552126016671 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include #include #include #include main(argc, argv) int argc; String argv[]; { Display *dpy; XtAppContext app; Widget toplevel, tree, shellForm; Pixmap pixmap; XmString str; MrmHierarchy hier; MrmCode clas; static char *files[] = { "uil1.uid" }; MrmInitialize (); XtToolkitInitialize(); app = XtCreateApplicationContext(); dpy = XtOpenDisplay(app, NULL, argv[0], "Uil1", NULL, 0, &argc, argv); if (dpy == NULL) { fprintf(stderr, "%s: Can't open display\n", argv[0]); exit(1); } toplevel = XtVaAppCreateShell(argv[0], NULL, applicationShellWidgetClass, dpy, XmNwidth, 400, XmNheight, 300, NULL); if (MrmOpenHierarchy (1, files, NULL, &hier) != MrmSUCCESS) printf ("can't open hierarchy\n"); MrmRegisterClass(0, NULL, "XmLCreateFolder", XmLCreateFolder, xmlFolderWidgetClass); MrmRegisterClass(0, NULL, "XmLCreateGrid", XmLCreateGrid, xmlGridWidgetClass); MrmRegisterClass(0, NULL, "XmLCreateProgress", XmLCreateProgress, xmlProgressWidgetClass); MrmRegisterClass(0, NULL, "XmLCreateTree", XmLCreateTree, xmlTreeWidgetClass); if (MrmFetchWidget(hier, "shellForm", toplevel, &shellForm, &clas) != MrmSUCCESS) printf("can't fetch shellForm\n"); tree = XtNameToWidget(shellForm, "*tree"); /* Add two rows to the Tree */ pixmap = XmUNSPECIFIED_PIXMAP; str = XmStringCreateSimple("Root"); XmLTreeAddRow(tree, 0, True, True, -1, pixmap, pixmap, str); XmStringFree(str); str = XmStringCreateSimple("Child of Root"); XmLTreeAddRow(tree, 1, False, False, -1, pixmap, pixmap, str); XmStringFree(str); XtManageChild(shellForm); XtRealizeWidget(toplevel); XtAppMainLoop(app); return (0); } nedit-5.6.orig/Microline/examples/uil1.uil0000644000175000017500000001251410077552126017246 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ module uil1 version = 'v1.0' names = case_sensitive include file 'XmL/XmL.uih'; value grey : color('#C0C0C0', background); lightGrey : color('#E0E0E0', background); black : color('#000000', foreground); white : color('#FFFFFF', background); darkBlue : color('#000080', foreground); object shellForm : XmForm { arguments { XmNbackground = grey; XmNmarginWidth = 10; XmNmarginHeight = 10; XmNshadowThickness = 0; }; controls { user_defined folder; }; }; object folder : user_defined procedure XmLCreateFolder { arguments { XmNbackground = grey; XmNforeground = black; XmNtabsPerRow = 2; XmNtopAttachment = XmATTACH_FORM; XmNbottomAttachment = XmATTACH_FORM; XmNleftAttachment = XmATTACH_FORM; XmNrightAttachment = XmATTACH_FORM; }; controls { XmDrawnButton tabOne; XmDrawnButton tabTwo; XmDrawnButton tabThree; XmDrawnButton tabFour; XmForm folderForm; }; }; object tabOne: XmDrawnButton { arguments { XmNlabelString = compound_string('Configuration'); }; }; object tabTwo: XmDrawnButton { arguments { XmNlabelString = compound_string('Settings'); }; }; object tabThree: XmDrawnButton { arguments { XmNlabelString = compound_string('Resources'); }; }; object tabFour: XmDrawnButton { arguments { XmNlabelString = compound_string('Hardware Types'); }; }; object folderForm : XmForm { arguments { XmNbackground = grey; XmNhorizontalSpacing = 10; XmNverticalSpacing = 10; }; controls { user_defined tree; user_defined grid; user_defined progress; }; }; object tree : user_defined procedure XmLCreateTree { arguments { XmNbackground = grey; XmNforeground = black; XmNleftAttachment = XmATTACH_FORM; XmNrightAttachment = XmATTACH_FORM; XmNtopAttachment = XmATTACH_FORM; XmNbottomAttachment = XmATTACH_POSITION; XmNbottomPosition = 25; }; }; object grid : user_defined procedure XmLCreateGrid { arguments { XmNbackground = grey; XmNforeground = black; XmNselectBackground = darkBlue; XmNselectForeground = white; XmNleftAttachment = XmATTACH_FORM; XmNrightAttachment = XmATTACH_FORM; XmNtopAttachment = XmATTACH_POSITION; XmNtopPosition = 30; XmNbottomAttachment = XmATTACH_POSITION; XmNbottomPosition = 80; XmNcolumns = 5; XmNheadingRows = 1; XmNsimpleHeadings = "Name|Width|Height|X|Y"; XmNsimpleWidths = "20c 10c 10c 8c 8c"; XmNrows = 20; XmNleftFixedCount = 1; }; }; object progress : user_defined procedure XmLCreateProgress { arguments { XmNtopShadowColor = lightGrey; XmNbottomShadowColor = black; XmNbackground = white; XmNforeground = darkBlue; XmNleftAttachment = XmATTACH_FORM; XmNrightAttachment = XmATTACH_FORM; XmNtopAttachment = XmATTACH_POSITION; XmNtopPosition = 85; XmNheight = 20; XmNshadowThickness = 1; XmNmeterStyle = MeterBoxes; XmNnumBoxes = 20; XmNvalue = 70; XmNcompleteValue = 200; }; }; end module; nedit-5.6.orig/Microline/examples/util1.c0000644000175000017500000000721610077552126017066 0ustar paulpaul/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data . * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * In addition, as a special exception to the GNU GPL, the copyright holders * give permission to link the code of this program with the Motif and Open * Motif libraries (or with modified versions of these that use the same * license), and distribute linked combinations including the two. You * must obey the GNU General Public License in all respects for all of * the code used other than linking with Motif/Open Motif. If you modify * this file, you may extend this exception to your version of the file, * but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget shell, form, button[4][5]; int i, j; static int types[5] = { XmDRAWNB_ARROW, XmDRAWNB_ARROWLINE, XmDRAWNB_DOUBLEARROW, XmDRAWNB_SQUARE, XmDRAWNB_DOUBLEBAR }; static int dirs[4] = { XmDRAWNB_RIGHT, XmDRAWNB_LEFT, XmDRAWNB_UP, XmDRAWNB_DOWN }; shell = XtAppInitialize(&app, "Grid1", NULL, 0, &argc, argv, NULL, NULL, 0); form = XtVaCreateManagedWidget("form", xmFormWidgetClass, shell, XmNfractionBase, 5, XmNshadowThickness, 0, NULL); for (i = 0 ; i < 4; i++) for (j = 0; j < 5; j++) { button[i][j] = XtVaCreateManagedWidget("drawnB", xmDrawnButtonWidgetClass, form, XmNtopAttachment, XmATTACH_POSITION, XmNtopPosition, i, XmNbottomAttachment, XmATTACH_POSITION, XmNbottomPosition, i + 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, j, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, j + 1, XmNwidth, 30, XmNheight, 30, NULL); XmLDrawnButtonSetType(button[i][j], types[j], dirs[i]); } XtRealizeWidget(shell); XtAppMainLoop(app); } nedit-5.6.orig/COPYRIGHT0000644000175000017500000003524007321556140013414 0ustar paulpaulGNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS nedit-5.6.orig/ChangeLog0000644000175000017500000105117710642437014013701 0ustar paulpaul2007-07-02 21:53 ajbj * source/window.c (1.199): A couple of small mistakes caught by Bert Wesarg. 2007-06-01 20:32 tringali * source/nedit.c (REL-5-5.1): Backport ARGB fix to 5.5 2007-05-09 13:11 ajbj * source/preferences.c (1.152): Changed "Complete Word" macro to use \w instead of \l and changed its comments. 2007-03-18 08:54 yooden * source/userCmds.c (1.55): Adds stdout/in/err help texts to Shell Menu dialog, as pointed out in @discuss by Gerald Grabner. 2007-03-18 08:34 yooden * source/text.c (1.54): Fix for SF#682004 This adds a call to BufSubstituteNullChars() when a control code is self-inserted (as with ALT-CTRL-a, for example). (Fix from Mark Geary.) 2007-03-04 23:54 yooden * source/: file.c (1.110), window.c (1.198): Fix for SF#1645661 Another fixfix, this adds missing initializers for device/inode. 2007-03-04 23:44 yooden * source/textDisp.c (1.69): Fix for SF#1608609 Some leftovers from fixing SF#464967/SF#1041077: The cursor is now redrawn in all cases. 2007-03-04 23:26 yooden * source/: file.c (1.109), preferences.c (1.151), tags.c (1.66), window.c (1.197), window.h (1.31): Fix for SF#1578869 NEdit's old file-not-found dialog, while user-unfriendly, at least did not crash. The new did, so this change removes the Close button again. Also localizes source/window.c:deleteDocument() from DeleteDocument(). 2007-03-04 23:17 yooden * ReleaseNotes (1.56): Added three entries to release notes about recently fixed bugs. 2007-03-02 00:01 ajbj * source/preferences.c (1.150): Fixed #1574071 built-in macro "Make C prototypes" doesn't work as suggested. 2007-01-30 19:42 arnef * source/window.c (1.196): Fix for 1645223, 'nc -wait' doesn't work when detaching/moving tab (from Bert Wesarg) 2007-01-30 13:51 ajbj * source/interpret.c (1.47): Fixed unused macros PEEK_INT and PEEK_STRING (for future use, if any). 2007-01-25 23:51 ajbj * source/macro.c (1.113): Bert Wesarg's fix of #1640304: ident read buffer overflow in parsing 'define'. 2007-01-15 14:04 ajbj * source/interpret.c (1.46): Changed DEBUG_ASSEMBLY code to use new instruction union from previous commit. 2007-01-12 22:44 tringali * source/nedit.c (1.99): Disable warnings unless "-xwarn" debug switch is passed in. 2007-01-12 16:17 tringali * source/: interpret.c (1.45), interpret.h (1.20), parse.y (1.29), parse_noyacc.c (1.10): SF 1625283: Replace nonportable casts with unions 2007-01-07 13:18 yooden * source/: textDisp.c (1.68), textDisp.h (1.30): Various cleanups: - Makes a function in textDisp.c non-global. - Style - Add "nedit:" to error messages - Comments 2007-01-04 01:42 yooden * ReleaseNotes (1.55), doc/help.etx (1.106), source/macro.c (1.112): This merges the two functions new_filename_dialog() and exist_filename_dialog() to one new function filename_dialog(). The memory leak is also fixed, but the other bugs remain for now. (Fix for pseudo-bug SF#1600022) 2007-01-04 00:10 yooden * source/preferences.c (1.149): Replaces default macros 'Complete Word' and 'Fill Sel. w/Char' with new alternatives by Jörg Fischer. (Fix for pseudo-bug SF#1578888) 2007-01-04 00:02 yooden * util/misc.c (1.85): Fix for SF#1245502 This fixes two bugs pointed out in the tracker. One allows for : as accelerators, the other fixes a wrong boolean. 2007-01-03 23:40 yooden * ReleaseNotes (1.54), source/text.c (1.53): Fix for SF#1066692 If emulated tabs are on, make the inserted indent deletable by tab. Round this up by faking the column a bit to the right to let the user delete half-tabs with one keypress. (Thanks to Tony Balinski) 2006-12-02 12:01 yooden * source/: textBuf.c (1.36), textBuf.h (1.21), textDisp.c (1.67): Some leftovers from the last two patches. 2006-12-02 10:27 yooden * source/file.c (1.108), source/highlight.c (1.54), source/highlightData.c (1.78), source/macro.c (1.111), source/menu.c (1.138), source/preferences.c (1.148), source/rangeset.c (1.17), source/search.c (1.85), source/selection.c (1.32), source/shell.c (1.42), source/smartIndent.c (1.40), source/textDisp.c (1.66), source/textSel.c (1.17), source/userCmds.c (1.54), source/window.c (1.195), util/fontsel.c (1.29), util/misc.c (1.84): Removes a number of 'if (NULL == foo)' from XtFree. Also changes some error messages from "NEdit:" to "nedit:" and minos cleanup. 2006-12-02 09:38 yooden * source/: file.c (1.107), highlight.c (1.53), interpret.c (1.44), interpret.h (1.19), macro.c (1.110), textBuf.c (1.35), textBuf.h (1.20), textDisp.c (1.65), textDisp.h (1.29): Makes a number of parameters const, changes some types to Boolean and changes some style. 2006-11-28 20:11 arnef * source/window.c (1.194): Fix for #1525831 Initialise window->fileClosedAtom to None when creating new Document. Thereby nc -wait doesn't return when closing file opened in a tab 2006-11-22 21:16 yooden * README (1.49): Adds comment about Linux linkage mode (now dynamic, then static). 2006-11-22 20:59 yooden * source/file.c (1.106): Changed type in fresh bug fix. 2006-11-22 15:13 yooden * source/preferences.c (1.147): Adds the two styles Operator and Bracket. (Fix for pseudo-bug SF#1600018) 2006-11-22 14:16 yooden * source/preferences.c (1.146): Fix for SF#1592236 Adds a missing downcast from const. 2006-11-22 13:45 yooden * ReleaseNotes (1.53), doc/help.etx (1.105), source/macro.c (1.109), source/nedit.h (1.68): This adds the special macro variable $VERSION which returns NEdit's version number ('5006' for NEdit 5.6). (Fixes pseudo-bug #1576902) 2006-11-07 22:04 n8gray * source/nedit.c (1.98): Changed the default mode of the file-selection dialog to path-relative. It's more like what people expect these days. Also changed the default size to 500x400. I would have made it bigger, but perhaps somebody out there still uses 640x480... 2006-11-07 19:16 ajbj * source/file.c (1.105): Fix for SF Bug #1588932 line number not shown correctly 2006-11-02 13:24 edg * source/file.c (1.104): Closed another path that could lead to the crash of SF bug #1578869: hitting 'Close' in the dialog has the same effect as closing the window via the window manager. 2006-10-29 22:22 edg * ReleaseNotes (1.52), source/file.c (1.103): Fix for SF bug #1578869: NEdit crashed on window close. 2006-10-29 13:23 yooden * ReleaseNotes (1.51): Adds a ReleaseNotes entry for Scotts fix of SF#1564907. 2006-10-26 22:09 edg * source/highlightData.c (1.77): Python highlight pattern updates (new keywords for 2.4 and 2.5). 2006-10-26 21:42 edg * ReleaseNotes (1.50), source/nedit.c (1.97), util/misc.c (1.83): Removed the apparently unreliable detection of problematic ARGB visuals and set XLIB_SKIP_ARGB_VISUALS before opening the display instead. This should solve SF bug #1579544 and duplicates (#1030467, #1030192, ...). 2006-10-26 02:20 tringali * makefiles/: Makefile.linux (1.14), Makefile.linux-static (1.1): SF #1572838: Linux binary should be dynamic by default 2006-10-26 02:15 tringali * source/nedit.c (1.96): Remove UTF8 from LC_CTYPE for OpenMotif 2.2.3, based on Eddy's experience 2006-10-20 15:44 ajbj * doc/help.etx (1.104), source/smartIndent.c (1.39): Corrected smart indent Type-in Macro usage information. 2006-10-17 13:00 yooden * source/: text.c (1.52), window.c (1.193): Fix for #1543586 The fix for #906878 activated the cursor blink for any new pane. This is now modified to be only called for active panes. 2006-10-17 12:39 yooden * ReleaseNotes (1.49), source/nedit.c (1.95): Fox for SF#1525074 Motif menu accelerators prevent use of clipboard translations in the i-search bar. This change removes accelerators, their job is in turn done by text widget translations. 2006-10-17 11:52 yooden * ReleaseNotes (1.48), source/search.c (1.84): Fix for SF#1508608 NEdit works slightly different on forward and backward searches. This is fixed by letting a repeated search start at the beginning of a selected search result instead of at the end. 2006-10-17 10:10 yooden * ReleaseNotes (1.47), source/shift.c (1.18): Fix for SF#1333103 NEdit's case change always modified the buffer, even if replacee and replacement were identical. This is now checked during the casing, so that the replacement is only done if necessary. (Thanks to Dimitar Zhekov) 2006-10-16 19:52 tringali * util/motif.c (1.6): 0.95.0 has the menu unposting bug, too. Verified with LessTif's test suite. 2006-10-16 14:26 yooden * ReleaseNotes (1.46), source/highlightData.c (1.76), source/preferences.c (1.145), source/preferences.h (1.55): Fix for SF#1117848 A few more states are checked to find out whether the user is working on a new syntax highlighting pattern, and make it usable immediately. 2006-10-16 13:45 yooden * doc/help.etx (1.103): Fix for SF#1046832 Adds an explanation for -untabbed mode. 2006-10-13 13:56 tringali * util/motif.c (1.5): Add LessTif 0.94.4 to known-bad list 2006-10-13 07:26 ajbj * source/: file.c (1.102), highlight.c (1.52), highlight.h (1.15), macro.c (1.108), rangeset.c (1.16), rangeset.h (1.7), search.c (1.83), search.h (1.28), shift.c (1.17), tags.c (1.65), textBuf.c (1.34), textBuf.h (1.19), textDisp.c (1.64), textSel.c (1.16), window.c (1.192): Extended use of BufAsString() and addition of const: see SF bug 1528893. 2006-09-30 17:26 yooden * source/nedit.c (1.94): Adds unistd.h to include files for access(). 2006-09-30 17:18 yooden * doc/help.etx (1.102): Fixes another small documentation bug about the use of single digit marks. 2006-09-30 17:07 yooden * source/macro.c (1.107): Fix for fix for SF#1493662 This removes some spurious changes to get NEdit to compile under Solaris. 2006-09-30 16:54 yooden * ReleaseNotes (1.45), source/file.c (1.101): Fix for SF#1371896 NEdit sets the language mode for freshly-saved documents even if the user chose a language mode already. This is changed. 2006-09-30 16:46 tringali * doc/help.etx (1.101): Updated credits to be a bit more readable 2006-09-30 16:36 yooden * ReleaseNotes (1.44), doc/help.etx (1.100), source/macro.c (1.106), source/search.c (1.82): Fix for SF#1066765, #1078397, #1110024, #1471868 Various documentation fixes, some reformating and a few text changes in other parts of the code. 2006-09-30 16:29 yooden * ReleaseNotes (1.43), source/file.c (1.100): Fix for SF#1066144 The "File not found" NEdt pops up when a document is focused which file is missing is unfriendly to the user. This is fixed by adding the most usual case (and removing one which is still available elsewhere) and by slightly more detailed information. 2006-09-30 16:12 yooden * ReleaseNotes (1.42), source/window.c (1.191), source/window.h (1.30): Fix for SF#1055649 The window size is changed repeatedly if two document with large difference in size are used in the same window. This is fixed by giving all documents a gutter of the same size. 2006-09-30 16:09 tringali * source/nedit.c (1.93): SF 1564907: guard against bogus XKEYSYMDB 2006-09-27 11:51 michaelsmith * makefiles/buildvms.com (1.2), source/macro.c (1.105), source/window.c (1.190): BUG #1395689 Patches to permit nedit to be compiled under OpenVMS VMS compilation script and patches contributed by zinser@zinser.no-ip.info 2006-08-22 13:23 yooden * util/getfiles.c (1.36): Using Lesstif, util/getfiles.c compiled only with a warning about a missing #include . 2006-08-17 17:33 ajbj * source/search.c (1.81): Fix for bug 1541650 where non-regex replace-in-selection didn't work. 2006-08-15 21:16 yooden * Microline/XmL/Folder.c (1.7), Microline/XmL/Tree.c (1.3), source/menu.c (1.137), source/preferences.c (1.144): Removes some compiler warnings and minor bugs on VMS. It compiles and runs on Linux, I have no way to check it on VMS. 2006-08-15 18:55 ajbj * source/: preferences.h (1.54), search.c (1.80): Made function prototypes match their definitions (added "const"). This corrects broken builds. 2006-08-15 18:36 ajbj * source/preferences.c (1.143): Adds a line to the nedit.rc file header commentary: ! (User settings in X "application defaults" format) which allows copies to be recognised as X app default files for syntax highlighting using the language detection regex for X Resources. 2006-08-13 21:47 yooden * source/: highlightData.c (1.75), preferences.c (1.142), rangeset.c (1.15), regularExp.c (1.30), search.c (1.79): This fixes several small issues: - Some bugs in various language modes pointed out by Volker Kuhlmann. - Some compiler warning (function footprint) caused from my latest changes. - Some compiler warnings (variable initialisation) from elsewhere. - One stuck return. 2006-08-13 18:41 yooden * ReleaseNotes (1.41), doc/help.etx (1.99), source/file.c (1.99), source/nedit.h (1.67), source/preferences.c (1.141), source/preferences.h (1.53), source/window.c (1.189): Fix for SF#1027788 On opening a symlink, NEdit as yet creates a new document. This behaviour is now optional: If the new resource nedit.honorSymlinks is set to false, NEdit will try to detect whether the file is already opened with another filename. 2006-08-13 18:02 yooden * ReleaseNotes (1.40), doc/help.etx (1.98), source/nedit.h (1.66), source/preferences.c (1.140), source/preferences.h (1.52), source/regularExp.c (1.29), source/regularExp.h (1.14), source/search.c (1.78), source/search.h (1.27): Fix for SF#1015499 An internal buffer limits the size of replace operation; the result was truncated at 511 characters. This change increases the buffer limit to 5119 characters and prevents data loss by catching an already existing internal error higher up the call chain. A new resource let's the user decide how the error is handled then. 2006-08-12 13:40 yooden * ReleaseNotes (1.39), doc/help.etx (1.97), source/file.c (1.98), source/preferences.c (1.139), source/preferences.h (1.51): Fix for SF#1003241 NEdit converts all open files into an internal Unix-like representation. This mechanism is lacking for files which contains both LF and CRLF. This patch adds the resource 'nedit.forceOSConversion' which, if set to False, prohibits all internal conversion. DOS and Mac files are no longer conveniently editable, but the stranger file types are editable at all. 2006-08-09 08:50 edg * source/highlightData.c (1.74): Proper fix for part of SF bug #1536451, correcting my previous attempt. 2006-08-08 18:06 tringali * util/system.h (1.18): Updates for newer Solaris (sparc + x86) boxes. 2006-08-08 10:59 edg * ReleaseNotes (1.38), source/highlightData.c (1.73), util/managedList.c (1.15): Fixes for SF bug #1536451: highlighting pattern capacity overflow. Limits on the number of patterns per set were not properly checked, or not checked at all. 2006-08-07 15:41 edg * ReleaseNotes (1.37), source/regularExp.c (1.28): Fix for SF bug #1536002: highlighting pattern compilation crash. An invalid size was used in a malloc call, causing memory corruption. 2006-08-06 18:34 edg * util/getfiles.c (1.35): Workaround for a Lesstif bug that caused a crash in the Save As dialog when a proportional font is used (reported by Alexey Kuznetsov at the discuss list). 2006-05-31 16:39 n8gray * source/macro.c (1.104): Added #include as potential fix for SF #1493662. Also fixed an unused variable warning. 2006-04-21 21:13 ajbj * source/: macro.c (1.103), textBuf.c (1.33), textBuf.h (1.18): From patch 1191453: Avoiding buffer copying in macro search; use the text buffer directly instead. 2006-04-11 06:29 n8gray * source/window.c (1.188): Since I'm on a roll, this is TK's fix for SF bug 1460456: Crash when saving over open file. 2006-04-11 01:14 n8gray * doc/help.etx (1.96), source/help_data.h (1.86), source/help_topic.h (1.75), source/macro.c (1.102), util/getfiles.c (1.34), util/getfiles.h (1.11): Adds two new (long overdue!) builtin functions to the macro language for displaying file-selection dialogs: new_filename_dialog exist_filename_dialog Includes one unbracketed if statement, just as flamebait. :-) 2006-03-17 14:20 edg * ReleaseNotes (1.36), util/getfiles.c (1.33): Fix for SF bug #1451337: current file name does not appear in "save as" dialog box 2006-03-17 10:05 edg * util/misc.c (1.82): Suppressed one more usually bogus clipboard locking warning. 2006-03-17 09:31 edg * ChangeLog (1.43): Long overdue ChangeLog update (cvs2cl.pl -b -r -t --accum --gmt). 2006-02-11 10:37 yooden * ReleaseNotes (1.35), source/macro.c (1.101), util/utils.c (1.25), util/utils.h (1.15): Fix for SF#622291 If a macro file is loaded with load_macro_file() (ie. from another macro) and code segments alternate with function definitions, the code segments were executed in reverse order. This is fixed by adding a stack to store and reverse the plain code segments. 2006-02-10 22:10 ajbj * source/rangeset.c (1.14): Fixed broken "optimisation" - noticed by TK Soh 2006-02-05 18:29 yooden * makefiles/Makefile.solaris (1.11): Fix for SF#860249 Some reports indicate that setting NO_XMIM is the more useful option on Solaris. 2006-02-05 16:31 yooden * util/: utils.c (1.24), utils.h (1.14): This removes some bogus 'extern' declarations from util/utils.[ch]. 2006-02-02 20:24 yooden * source/: menu.c (1.136), preferences.c (1.138), preferences.h (1.50), search.c (1.77): Fix for SF#1406894 I removed the shell setting from TempStringPrefs. While PrefData.shell is touched in translatePrefFormats() (putting in the default shell), there is no need to use the more complicated storage. Also included are some related small changes: - The menu entry 'Select Shell' is renamed to 'Command Shell'. - I removed the arbitray restriction found in MAX_SH_LEN and replaced all references with MAXPATHLEN. 2006-01-14 11:42 yooden * source/file.c (1.97): Reorders the #include directives, as pointed out by Martin Zinser. 2006-01-14 10:26 yooden * source/menu.c (1.135): This moves the "Sort Open Prev. Menu" entry into the "Customize Menus" submenu, as suggested by Dimitar Zhekov on discuss@. 2006-01-02 23:10 yooden * source/menu.c (1.134): Doh. For some reason it worked without #include before. 2006-01-02 22:35 yooden * ReleaseNotes (1.34), doc/help.etx (1.95), source/menu.c (1.133), source/preferences.c (1.137), source/preferences.h (1.49), source/shell.c (1.41): Fix for SF#403738 and SF#880607 This cleans up the shell problems by - bringing the shell setting into NEdit's normal settings, removing it from the X server's setting. - Changing the default shell to the user's login shell, falling back on sh. I also smuggled in a change to ReleaseNotes about SF#557032 I forgot then. 2006-01-02 22:18 yooden * source/file.c (1.96): Removes redundand #ifdefs within eponymous #ifndefs. 2006-01-02 22:07 yooden * source/menu.c (1.132): Cleanup for the recent changes on the history database handling. This pulls together the file check on the existing file on disk. 2005-12-28 22:19 tringali * source/help.c (1.105): Fix incorrect reporting of bad vs. unknown. 2005-12-27 20:55 yooden * doc/help.etx (1.94): This cuts a long paragraph in the help into multiple smaller paragraphs. 2005-12-18 03:46 tksoh * source/menu.c (1.131): Fix premature setting of mtime tracking variable on nedit.history file. 2005-12-17 19:23 yooden * source/: menu.c (1.130), nedit.h (1.65), window.c (1.187): Fix for SF#1381893 As TK pointed out in the original bug report (SF#557032), internal state is not adequate to keep the file history consistent if more than one session is running. Once you accept that external state must be checked you don't need to keep internal state at all. So this patch removes the prevOpenMenuValid flag from WindowInfo and the rest of the code. Validity of the menu is determined using only the directory entry of the history file. 2005-12-14 23:08 yooden * source/menu.c (1.129): Fix for SF#557032, based on TK's fix attached there. NEdit's file history is now read not only once at startup, but also every time a file the history is written and before the menu is refreshed. This catches files written by other instances of NEdit. 2005-12-10 23:21 yooden * source/textDisp.c (1.63): Fix for SF#1368576 The fix for SF#464967 increased the area processed by redisplayLine() by one to let it know that the cursor should be redrawn. This was done by increasing the endIndex given to redisplayLine() by one. Sadly, endIndex is INT_MAX in some cases, which prevented redisplays completely in certain cases. This fix moves the incrementation to a saner place. Neither the bugs fixed with SF#464967 nor any of the examples given in SF#1368576's description are visible. Again, I notice no drawbacks. 2005-12-01 14:31 tringali * Xlt/: BubbleButton.c (1.9), BubbleButtonP.h (1.5), SlideC.c (1.5), SlideCP.h (1.4): Revert out partoffset stuff - it's Motif 2 only. Need to rewrite so it's conditional 2005-11-30 17:52 tringali * source/macro.c (1.100): Avoid crash if cancel accelerator is unset. 2005-11-30 17:48 tringali * Xlt/: BubbleButton.c (1.8), BubbleButtonP.h (1.4), SlideC.c (1.4), SlideCP.h (1.3): Patch from ICS to do proper subclassing - this will make it more immune to binary incompatible changes in OpenMotif. 2005-11-29 20:37 n8gray * source/smartIndent.c (1.38): Fix for bug #1369091. Matlab autoindent init macro should end with a newline. 2005-11-28 22:43 yooden * ReleaseNotes (1.33), source/highlightData.c (1.72): Fix for SF#858874 There was a tiny typo in Ada's syntax highlighting pattern. 2005-11-28 21:51 yooden * util/check_lin_tif.c (1.13): Removes a warning from GCC: warning: ISO C89 forbids mixed declarations and code This is simply done by wrapping blocks around the declarations. 2005-11-28 21:35 yooden * ReleaseNotes (1.32): Adds comment about fix to SF#464967 and SF#1041077 to ReleaseNotes. 2005-11-26 00:17 yooden * source/textDisp.c (1.62): Fix for SF#464967. The area redisplayed from within TextDRedisplayRange() is appended by one character. This is necessary to let the logic in redisplayLine() know that the caret should be redrawn (hasCursor = true) which in turn triggers the redraw by calling drawCursor() later in the function. Both representations of the bug described in the bug report plus two more for multi-line redraws are fixed. I noticed no drawbacks. 2005-11-25 19:58 yooden * util/misc.c (1.81): MaCke sure we get no compile errors.VS: Committing in . 2005-11-20 06:48 n8gray * util/misc.c (1.80): Make sure we get the prototype for select on OS X systems. 2005-11-18 10:40 edg * util/misc.c (1.79): Removed another unnecessary warning: XmClipboardInquireLength() can legally fail when the clipboard is empty. 2005-11-08 22:22 edg * source/: file.c (1.95), nedit.h (1.64), window.c (1.186): Fix for SF bug #1345424: externally changed file status not recognised. The file's uid and gid are now recorded too to detect any changes. 2005-09-23 14:23 edg * util/misc.c (1.78): Partially reverted my previous checkin: the empty clipboard check should not have been removed; only the warning. 2005-09-23 14:18 edg * util/misc.c (1.77): Removed an unnecessary warning: XmClipboardRetrieve can legally fail when the clipboard is empty. 2005-09-23 14:08 tringali * source/nedit.c (1.92): Disable UTF8 stomping where it's not a problem (OM2.2.3+) 2005-08-13 19:29 edg * source/macro.c (1.99), source/textSel.c (1.15), util/misc.c (1.76), util/misc.h (1.28): Added clipboard spinlocks to make clipboard manipulations more robust, especially in the presence of other applications accessing the clipboard. 2005-08-06 04:56 tksoh * source/window.c (1.185): Fixed bug where line number panel didn't adjust to fully display the last line number (10000) when newline was added, with 9999 lines in the tab before addition. 2005-08-06 04:31 tksoh * source/nc.c (1.47): Fixed nc's prompt on -ask. 2005-07-30 18:05 edg * source/server.c (1.33): Presumable fix for SF bug #1078786: "-untabbed" option of nc sometimes ignored. The option now works as intended with (older) window managers that are not _NET_WM compliant. 2005-06-22 07:34 edg * doc/help.etx (1.93), source/help_data.h (1.85), source/help_topic.h (1.74): More documentation updates by Joerg Fischer. 2005-06-20 10:54 edg * doc/help.etx (1.92), doc/nedit.pod (1.9), source/help_data.h (1.84), source/help_topic.h (1.73): More documentation updates by Joerg Fisher. 2005-06-09 16:44 edg * doc/help.etx (1.91), source/help_data.h (1.83), source/help_topic.h (1.72): Typo fixes (Joerg Fischer). 2005-05-30 07:44 edg * doc/help.etx (1.90), source/help_data.h (1.82), source/help_topic.h (1.71): Typo fix (Joerg Fischer). 2005-05-27 16:58 edg * source/regularExp.c (1.27): Fix for SF bug #1204893: regular expressen cuts replaced textparts. A warning is now written to stderr when truncation occurs. (Ideally, all errors and warnings should be signaled via dialogs, but that requires architectural changes). 2005-05-27 16:50 edg * source/shell.c (1.40): Minor fix. 2005-05-27 16:49 edg * README (1.48), Microline/XmL/Folder.h (1.3), Microline/XmL/Grid.h (1.3), Microline/XmL/Progress.h (1.3), Microline/XmL/Tree.h (1.3), Microline/XmL/XmL.c (1.3), Xlt/BubbleButton.c (1.7), Xlt/BubbleButtonP.h (1.3), Xlt/SlideC.c (1.3), Xlt/SlideCP.h (1.2), makefiles/buildvms.com (1.1), source/comnedit.com (1.10), source/file.c (1.94), source/lnknedit.com (1.8), source/menu.c (1.128), source/shell.c (1.39), source/window.c (1.184), util/comutil.com (1.5): VMS porting fixes contributed by Michael Smith. 2005-04-15 14:16 edg * source/shell.c (1.38): Fix for SF bug#1183759: HP compiler uninitialized variable. The variable isn't actually used when it isn't initialized. 2005-03-23 12:34 edg * Microline/Makefile (1.3), Microline/Makefile.in (1.3), Xlt/Makefile (1.1): Fix for SF bug #1066152: Microline Widget Library does not Compile Added a working makefile for the Microline and Xlt subdirectories. 2005-03-06 15:38 tringali * util/motif.c (1.4): Bug 1087192: avoid LessTif 0.93.95b 2005-03-03 14:49 edg * doc/help.etx (1.89), doc/nc.pod (1.7), doc/nedit.pod (1.8), source/help_data.h (1.81), source/help_topic.h (1.70), source/nc.c (1.46), source/nedit.c (1.91): Added -h/-help command line options and clarified warn-on-exit. 2005-02-24 18:23 edg * source/highlightData.c (1.71): Extended C, C++, Yacc, and Lex patterns to recognize strings inside preprocessor lines to avoid erroneous matching of comment pattern on strings. 2005-02-23 03:00 ajbj * source/preferences.c (1.136): Changed default line wrap mode to continuous (SF bug 1124850, rfe 1087257). 2005-02-18 11:10 edg * doc/help.etx (1.88), source/help_data.h (1.80), source/help_topic.h (1.69): Minor clarification in regex help. 2005-02-16 07:18 n8gray * source/menu.c (1.127): Makes unloadTipsAP refresh any existing tear-offs. 2005-02-16 05:09 ajbj * doc/help.etx (1.87), source/help_data.h (1.79), source/help_topic.h (1.68): Added help information on the new macro string escape sequences. 2005-02-16 03:44 ajbj * source/: parse.y (1.28), parse_noyacc.c (1.9): Adds Patch 970487: \xXX and \0ooo style escaped characters to macro strings. Nothing in the help about this (yet). 2005-02-15 09:13 edg * source/menu.c (1.126): Fix for SF bug #1122813: Tab-related crash on posting unload calltips file menu. 2005-02-15 03:44 tringali * util/: motif.c (1.3), motif.h (1.2): Added Motif exception to license 2005-02-15 01:10 n8gray * source/: menu.c (1.125), preferences.c (1.135), tags.c (1.64), tags.h (1.16): Calltips files are now reference-counted. This should address bug #1025123 - Error loading default calltips file. Fixing this uncovered another bug, however, that I haven't been able to fix. I'll file a bug on it later. Also, can somebody look at menu.c, compare unloadTagsAP with unloadTipsAP, and address my comment on the latter? 2005-02-14 23:45 yooden * util/motif.c (1.2): Removes warning. 2005-02-14 22:18 yooden * source/nedit.c (1.90), util/prefFile.c (1.26): This sets the maximum tab width to 150. This prevents some resizing of the tabs, making the UI less jumpy. It is also what most users probably expect from the tabs, since most apps work with tabs of limited size. This also slightly changes some error messages. 2005-02-14 14:40 tringali * util/: motif.c (1.1), motif.h (1.1): Minor cleanup of Motif checker to keep #ifdef's all in one place (part 2) 2005-02-12 12:04 edg * util/misc.c (1.75): Fix for SF bug #1030467: "Enabling Composite Extension in Xorg 6.8 breaks Nedit", presumably also for SF bug #1048304: "Very slow resizing of Nedit window on Xorg 6.8", and possibly also for SF bug #1070918: "new tab -> Segmentation fault", and SF bug #1030192: "X_PolyFillRectange error with X 6.8 and xcompmgr" 2005-02-12 01:53 tringali * source/help.c (1.104), source/nedit.c (1.89), util/Makefile.common (1.9), util/check_lin_tif.c (1.12): Minor cleanup of Motif checker to keep #ifdef's all in one place. 2005-02-11 02:42 ajbj * doc/help.etx (1.86), source/help_data.h (1.78), source/help_topic.h (1.67), source/macro.c (1.98): Integrated patch 1003088 allowing substring to drop the end position argument. It also uses negative positions as measurements from the end of the string. 2005-02-11 01:46 ajbj * doc/help.etx (1.85), source/help_data.h (1.77), source/help_topic.h (1.66), source/macro.c (1.97): Integrated patch 991602, removing limits on the number of buttons in dialogs. 2005-02-10 03:35 ajbj * source/macro.c (1.96): Buffer length fixes to rangeset functions I forgot when changing rangeset.c. 2005-02-06 12:31 yooden * doc/help.etx (1.84): Changes documentation for the replace_range() macro function. This function moves the cursor when it is in the replaced range. In these cases, the cursor has no clear best position, so a documentation is all we can do. 2005-02-02 09:15 edg * source/textDrag.c (1.11): Added dummy initializations to suppress bogus compiler warnings. 2005-02-02 09:08 edg * source/nedit.c (1.88): Minor leak fix. 2005-02-02 09:07 edg * source/macro.c (1.95): Fix for the critical split() macro bug reported by Joerg Fischer: using a zero-width assertion pattern as the split pattern (regex mode) resulted in a seemingly endless loop (ended by a crash). Zero-width assertion patterns now work as expected. Eg: split("abcdef", "(?=c)", "regex") -> "ab", "cdef". 2005-01-31 14:39 edg * ChangeLog (1.42): Regenerated (cvs2cl.pl -b -r -t --accum --gmt). 2005-01-31 14:34 edg * source/: preferences.c (1.134), userCmds.c (1.53), userCmds.h (1.11): Fix for SF bug #1113183: lang. mode seq. change - user menu LM dependency not update. (Patch by Uwe Lehnert) 2005-01-29 01:57 ajbj * source/rangeset.c (1.13): Fix for SF bug 1111849: the calculation of maxpos in rangesets should give the valid text length in the text buffer. It doesn't, since it adds in the size of the buffer's gap! 2005-01-18 20:58 n8gray * source/nedit.c (1.87): Adds bindings for Ctrl-f/g to the help system. 2005-01-06 06:23 ajbj * source/macro.c (1.94): The previous focus window filename fixes did not cope with pathless documents such as the initial Untitled window. This patch does a simple name search before attempting a search using normalized names. 2005-01-06 06:09 ajbj * util/misc.c (1.74): Fix for bug 1096970: the patch fixes focus change problems in RadioButtonChangeState() by saving the widget with focus then restoring focus after the button has been properly set (only required for some buggy Motifs). 2004-12-24 13:05 tksoh * source/window.c (1.183): Fixed a bug where rangesets do not get highlighted (colored) properly when the host document is detached/attached, if syntax highlighting is on. 2004-12-23 22:25 edg * doc/help.etx (1.83), source/file.c (1.93), source/help.c (1.103), source/help_data.h (1.76), source/help_topic.h (1.65), source/highlightData.c (1.70), source/menu.c (1.124), source/preferences.c (1.133), source/preferences.h (1.48), source/search.c (1.76), source/smartIndent.c (1.37), source/tags.c (1.63), source/userCmds.c (1.52), source/window.c (1.182), source/window.h (1.29), source/windowTitle.c (1.15), util/misc.c (1.73), util/misc.h (1.27): Fix for SF bug #1067619: focus on raise. By default, NEdit no longer requests the input focus when a window is raised. This default can be overridden by setting the X-resource "nedit.focusOnRaise" to True. The raise_window() action routine also accepts an optional extra argument: 'focus' or 'nofocus', which can be used to override the focus behaviour determined by the resource. 2004-12-17 11:54 edg * source/: search.c (1.75), search.h (1.26), window.c (1.181): Fix for SF bug #1086664: Repeatable crash closing window. Closing a window while a modal dialog is up, triggered from a find or replace dialog button action routine, is virtually impossible. We can prevent illegal accesses to destroyed windows (which is the reason for the crash), but we cannot avoid that Motif accesses structures that get destroyed in the process. Therefore, it is now no longer possible to close a window via the window manager during the execution of a search dialog button action routine in that window. 2004-12-05 01:23 tksoh * source/file.c (1.92): Fix for SF Bug #1063542: On some systems, such as Solaris 2.6, the "New File" dialog does not appear when trying to open a non-existing file with nc, while the NEdit window is iconized. 2004-12-05 01:15 tksoh * source/menu.c (1.123): Fix for SF Bug #1076412: "Unload Tags File" menu tear-offs not refreshed after unloading tags files. Tear-offs will be closed when all tags files are unloaded. 2004-11-26 18:25 edg * doc/help.etx (1.82), source/help_data.h (1.75), source/help_topic.h (1.64), source/highlight.c (1.51), source/preferences.c (1.132), source/regularExp.c (1.26), source/regularExp.h (1.13), source/search.c (1.74): Fix for SF bug #1067402: Error in syntax highlighting with sub-pattern. For this, the regular expression needed to be extended such that it allows imposing a boundary on the matching (instead of letting matches extend till the terminating \0). This also enabled me to lift a minor limitation of the look-behind matching. Also fixed 5 probably very old bugs in the regex engine that could easily result in crashes (try replacing \y+ with abc in an empty document for an instant crash). 2004-11-26 17:54 edg * util/misc.c (1.72): Minor leak fix. 2004-11-23 14:37 tringali * source/interpret.c (1.43): Remove sprintf call - this won't compile on many platforms. 2004-11-21 16:53 yooden * source/interpret.c (1.42): Makes error message construction a little more robust by replacing sprintf() with snprintf(). There is a constant already in use for this (MAX_ERR_MSG_LEN), so we should use it to prevent mishaps. 2004-11-09 21:58 yooden * doc/setext (1.13), source/calltips.h (1.4), source/file.h (1.15), source/highlight.h (1.14), source/highlightData.h (1.13), source/interpret.h (1.18), source/macro.h (1.8), source/menu.h (1.13), source/nedit.h (1.63), source/parse.h (1.7), source/preferences.h (1.47), source/rbTree.h (1.5), source/regexConvert.h (1.7), source/regularExp.h (1.12), source/search.h (1.25), source/selection.h (1.7), source/server.h (1.7), source/server_common.c (1.6), source/server_common.h (1.3), source/shell.h (1.9), source/shift.h (1.6), source/smartIndent.h (1.8), source/tags.h (1.15), source/text.h (1.23), source/textBuf.h (1.17), source/textDisp.h (1.28), source/textDrag.h (1.5), source/textP.h (1.12), source/textSel.h (1.6), source/undo.h (1.8), source/userCmds.h (1.10), source/window.h (1.28), source/windowTitle.c (1.14), source/windowTitle.h (1.5), util/DialogF.h (1.11), util/clearcase.c (1.6), util/clearcase.h (1.5), util/fileUtils.h (1.12), util/fontsel.h (1.11), util/getfiles.h (1.10), util/managedList.h (1.7), util/misc.h (1.26), util/prefFile.h (1.8), util/printUtils.h (1.9), util/utils.h (1.13), util/vmsParam.h (1.6), util/vmsUtils.h (1.7): A large number of files carried a pointer to the wrong licence (LGPL), probably introduced by a pasting error during the licence clarification. This was changed to point to the GPL. 2004-11-09 19:37 yooden * source/: macro.c (1.93), menu.c (1.122): Two problems with potentially too long pathnames are fixed: 1. The open() action procedure handled the results of ParseFilename wrong: It was only checked for each single component whether it's > MAXPATHLEN, not for the combination. This is fixed now. 2. If the pathname given to focus_window() is > MAXPATHLEN, the function returns with an error now. 2004-11-07 20:03 edg * source/macro.c (1.92): Fix for my "fix" for SF bug #1060749: truncate the string to MAXPATHLEN + other improvements suggested by Tony. 2004-11-05 08:44 edg * source/macro.c (1.91): Fix for SF bug #1060749: focusWindowMS (macro.c) causes crash. 2004-11-02 12:55 edg * source/shell.c (1.37): Enabled the navigation keys (arrows, page-up/down, ...) for shell output dialogs. 2004-10-18 19:27 arnef * source/calltips.c (1.9), source/rangeset.c (1.12), source/tags.c (1.62), source/textDisp.c (1.61), source/window.c (1.180), util/check_lin_tif.c (1.11), util/misc.c (1.71), util/utils.c (1.23): Added missing 'static'. Changed to initial lower case letter on two static functions. 2004-10-18 16:05 yooden * makefiles/Makefile.linux (1.13): Reverts accidental checkin of Linux makefile. 2004-10-18 15:54 yooden * doc/help.etx (1.81), makefiles/Makefile.linux (1.12), source/file.c (1.91), source/macro.c (1.90), source/menu.c (1.121), source/nedit.c (1.86), source/tags.c (1.61), util/fileUtils.c (1.33), util/utils.c (1.22): This fixes two bugs: 1. SF#873188 2. focus_window() didn't work if the pathname had extra slashes. Both items were affected by pathname creation quirks in source/file.c and util/fileUtils.c and there is the straightforward focus_window change in macro.c. Changes in other files are documentation or cleanups. I don't have access to OS/2 or Cygwin systems, so please have a close look on these two. VMS should not be affected. 2004-10-15 18:04 arnef * source/: interpret.c (1.41), interpret.h (1.17), nedit.c (1.85), preferences.c (1.131), preferences.h (1.46), tags.c (1.60), userCmds.c (1.51), userCmds.h (1.9): Added missing void in declarations and definitions (continuation of work done by edg 04/10/14 14:53:25) 2004-10-15 13:57 edg * source/nedit.c (1.84), util/misc.c (1.70): This should fix the problems that we have with drag icons when using non-default visuals (especially on Solaris). All shells that Motif creates beyond our control should now inherit the proper (non-default) visual etc. via the resource database. An exception is made for Lesstif, which seems to be able to deal with non-default visuals on its own (and which doesn't like us to impose visuals). Drag-and-drop operations are now enabled under all circumstances as they should no longer result in crashes (opening the path for patches that rely on d&d). 2004-10-14 21:55 edg * source/server.c (1.32): Added missing initialization (Arne Førlie). 2004-10-14 21:53 edg * source/userCmds.h (1.8): Added missing void in declaration (Arne Førlie) 2004-10-13 17:38 tringali * util/system.h (1.17): Guess compiler for older SGI boxes. 2004-10-08 22:58 yooden * ReleaseNotes (1.31), source/highlightData.c (1.69): Adds a pattern for nested command substitution in the shell pattern set. 2004-10-08 22:26 yooden * ReleaseNotes (1.30), source/shell.c (1.36): The status bar reflects a changed keybinding in the shell command banner. This is brought over from the similar code for macros. 2004-10-08 21:55 yooden * ReleaseNotes (1.29), source/text.c (1.51), source/text.h (1.22), source/window.c (1.179): Fixes SF#906878 (Cursor blinks while typing) by introducing the new function ResetCursorBlink() which can be used to reset the caret blink timer. 2004-10-08 11:35 edg * ChangeLog (1.41): Regenerated (cvs2cl.pl -b -r -t --accum --gmt). 2004-10-08 11:24 edg * source/window.c (1.178): Fix for replace dialog buttons not being updated when switching tabs, possibly resulting in temporarily inconsistent button states. Candidate fix for 5.5.1. 2004-10-07 22:34 yooden * doc/help.etx (1.80), source/file.c (1.90), source/menu.c (1.120), source/nedit.h (1.62), source/preferences.c (1.130), source/preferences.h (1.45), source/search.c (1.73), source/search.h (1.24), source/text.c (1.50), source/text.h (1.21), source/textDisp.c (1.60), source/textDisp.h (1.27), source/textP.h (1.11), source/window.c (1.177), source/window.h (1.27), util/getfiles.c (1.32), util/getfiles.h (1.9), util/prefFile.c (1.25): I was asked to elaborate on this commit. So here goes: This commit is a mistake because the codebase is made worse by it. The code removed is of higher quality than the average commit, is of use to many users of NEdit and would have been the basis for even more improvements in code quality and usability. Ironically, this commit is the result of all the things it claimed to heal: That one developer considers the repository his personal playground and forces his view onto others. While there is no basis for the original complaint, the aggressive tone, stubborn insistence and insulting nature of the comeback makes it clear that this something much different than honest care about the community process. What could have been a minor nuisance was blown out of all proportation and made to a personal vendetta. At the same time, any attempts to get to a closure were not ignored, but actively impeded, any calming voice was shouted down. Despite all this, I figured the commit would put an end to the unpleasant situation and would offer the opportunity to restart. Despite the attempts to prevent this, I'd still rather work on NEdit than defend against personal attacks. So with this commit I take back the added features Hidden Files (SF#502840), Wrap Hairline (SF#701337 variant) and Smart Case Search (SF#685618) committed on 2004-10-01. 2004-10-07 10:27 edg * source/undo.c (1.18): Fix for SF bug #988220: backup file?. The backup file was not removed when a redo operation returned the document to the state where it matches the saved file. Closing the document then left behind the backup file. 2004-10-02 13:31 yooden * source/: menu.c (1.119), textDisp.c (1.59): Fixes a wrong assumption about the hairline code. 2004-10-01 10:13 yooden * doc/help.etx (1.79), source/menu.c (1.118), source/nedit.h (1.61), source/preferences.c (1.129), source/preferences.h (1.44), source/text.c (1.49), source/text.h (1.20), source/textDisp.c (1.58), source/textDisp.h (1.26), source/textP.h (1.10), source/window.c (1.176), source/window.h (1.26), util/prefFile.c (1.24): Adds an optional hairline at the wrap column. 2004-10-01 10:06 yooden * doc/help.etx (1.78), source/file.c (1.89), source/help_data.h (1.74), source/menu.c (1.117), source/nedit.h (1.60), source/preferences.c (1.128), source/preferences.h (1.43), util/getfiles.c (1.31), util/getfiles.h (1.8): Adds a widget to (un)display hidden files in the FSB. 2004-10-01 09:50 yooden * doc/help.etx (1.77), source/menu.c (1.116), source/nedit.h (1.59), source/preferences.c (1.127), source/search.c (1.72), source/search.h (1.23), source/window.c (1.175): Adds a smart search mode, which toggles caseness in regex searches. ============================================================================ 2004-09-30 REL-5-5 branch created ============================================================================ 2004-09-30 22:52 n8gray * README (1.47): Oops -- missed a bit of CVS conflict detrius. 2004-09-30 22:51 n8gray * Makefile (1.19), README (1.46), ReleaseNotes (1.28), source/nc.c (1.45): Updating version information in preparation for 5.5 release. 2004-09-30 21:35 edg * README (1.45): Removed obsolete "KNOWN DEFECTS" section. 2004-09-30 11:31 edg * ChangeLog (1.40): Regenerated (cvs2cl.pl -b -r -t --accum --gmt). 2004-09-30 11:30 edg * README (1.44), ReleaseNotes (1.27): Updates for 5.5 2004-09-16 00:50 n8gray * source/: menu.c (1.115), window.c (1.174): Addressing Bug 1023089: can't open new tab. Let's see if this phrasing is more clear. The File menu now has either: New New Window or: New New Tab depending on the user's "open new files in..." preference. 2004-09-07 06:19 n8gray * source/menu.c (1.114): Fixed spelling of incrementalSearchLine resource as reported by Arne Forlie. 2004-09-02 10:50 edg * source/userCmds.c (1.50): Shell command dialog: renamed window to document. 2004-09-02 10:49 edg * source/: nedit.c (1.83), shell.c (1.35): Fixes for the state of the File->Close menu item (bug reported by Arne Førlie). Also made the output of a shell command go to a new window or a new tab, depending on the user preference wrt. tabbed editing. 2004-09-01 20:42 n8gray * source/menu.c (1.113): Fix the "New Tab" menu item in the tab context menu. 2004-09-01 20:19 n8gray * source/window.c (1.173): Clean out dead variables in DetachDocument. 2004-09-01 15:50 tksoh * source/window.c (1.172): Fix for SF Bug #1020035: Detaching/Moving non-top tab should not change top tab. 2004-08-31 23:37 n8gray * source/window.c (1.171): This should fix bug 1011233 - Openning new window from a tabbed window diminishes size. The comment says that the previous version was supposed to reduce flickering but it caused these size problems and I didn't notice any appreciable difference in the flickering without it. 2004-08-26 06:51 n8gray * Makefile (1.18), README (1.43), ReleaseNotes (1.26), source/nc.c (1.44) (utags: BETA-5-5-RC2): Updating version info for RC2. 2004-08-24 12:12 edg * ChangeLog (1.39, BETA-5-5-RC2): Regenerated (cvs2cl.pl -b -r -t --accum --gmt). 2004-08-24 11:37 edg * source/file.c (1.88, BETA-5-5-RC2): Fix for SF bug #999021 Using exit() in a macro causes hang. 2004-08-20 19:33 n8gray * doc/help.etx (1.76), source/help_data.h (1.73), source/menu.c (1.112), source/nedit.c (1.82), source/nedit.h (1.58), source/preferences.c (1.126), source/window.c (1.170), source/window.h (1.25): Committing Tony Ballinski's fix for bug #1005442: documentation for rangeset_set_mode( r, type ) not clear 2004-08-20 16:37 edg * doc/help.etx (1.75), source/help_data.h (1.72), source/help_topic.h (1.63), source/regularExp.c (1.25): Fix for SF bug #1008656: word delimiters ignored. Partially reverted the implementation of '<', '>', and \B back to the pre-5.4 behaviour, without giving up the fix for the problem that we wanted to solve in 5.4. Word boundaries are now again defined in terms of the delimiter set (which makes things more consistent overall), but word boundary operators still test both the previous and the next character (the pre-5.4 version only tested one character, causing surprising matches, eg., between to spaces). 2004-08-16 10:12 edg * doc/help.etx (1.74), source/help_data.h (1.71), source/help_topic.h (1.62): Documentation fix for regex boundary expression semantics. 2004-08-15 02:09 tksoh * Microline/XmL/: Folder.c (1.6), FolderP.h (1.5), XmL.h (1.6): Added resource XmLFolder.minTabWidth to fix SF bug #1005064, where tabs were getting wrong sizes when too many tabs were opened. 2004-08-12 16:51 edg * source/window.c (1.169): Avoid replace dialog button sensitivity updates when the dialog is not mapped and the selection is altered. In this way many indirect status checks for all files are avoided (triggered by updating the sensitivity of the "Multiple Files..." button). 2004-08-12 13:43 edg * source/window.c (1.168): Fix for SF bug #1006830: "Warn on Exit" doesn't work sometimes. 2004-08-12 09:06 edg * source/file.c (1.87): Avoid "File Modified Externally" dialogs for tabs that are not visible (similar to minimized windows). 2004-08-10 22:28 yooden * source/nedit.c (1.81): Adds limits.h. 2004-08-09 22:20 n8gray * README (1.42), util/misc.c (1.69): It appears I never committed the updated RC1 README file. Here it is. This also contains a minor correction to the comment documentation for QueryDesktop. There have been no functional changes. 2004-08-09 16:48 edg * source/: nedit.c (1.80), window.c (1.167): Restored the "invalid default virtual key binding" workaround that had become effectively disabled due to the shell widget hierarchy reorganization. (Bug report at discuss list by Timothy Paige: page-up,page-down on sun keyboard.) 2004-08-04 17:43 n8gray * source/preferences.c (1.125): Bump the prefs file version to prevent repeated conversion. 2004-08-04 08:05 n8gray * source/preferences.c (1.124): Notify user when prefs file gets changed for 5.5. 2004-08-01 10:06 yooden * source/file.c (1.86), source/help.c (1.102), source/highlight.c (1.50), source/highlightData.c (1.68), source/macro.c (1.89), source/menu.c (1.111), source/preferences.c (1.123), source/search.c (1.71), source/selection.c (1.31), source/shell.c (1.34), source/smartIndent.c (1.36), source/tags.c (1.59), source/userCmds.c (1.49), util/DialogF.c (1.31), util/fontsel.c (1.28), util/getfiles.c (1.30), util/misc.c (1.68), util/misc.h (1.25), util/printUtils.c (1.25): Dialog OK's are getting less blanks, more margin. 2004-08-01 07:55 yooden * doc/help.etx (1.73), source/help_data.h (1.70), source/help_topic.h (1.61): Fixes some leftovers of the licence clarification. 2004-07-29 13:47 tringali * util/DialogF.c (1.30): SF #999820 - spaces in dialog button mnemonics 2004-07-28 18:02 n8gray * source/: text.c (1.48), window.c (1.166): Fix for bug 996786: Problems with Overtype mode. 2004-07-27 18:25 n8gray * README (1.41): Minor grammatical fix. 2004-07-27 18:23 n8gray * README (1.40): Updated feature list for 5.5. 2004-07-26 22:52 n8gray * util/system.h (1.16): Fixes test for PowerPC architecture in OS X. 2004-07-25 22:24 yooden * Makefile (1.17): Increase Posixication level. 2004-07-24 17:41 yooden * README (1.39), doc/help.etx (1.72): License change, step 4: Mention of the Mozilla project. 2004-07-23 18:52 n8gray * source/window.c (1.165, BETA-5-5): Fix for bug 996216: Detach Tab/Move tab don't keep non-default word delimiters. 2004-07-23 18:40 n8gray * source/window.c (1.164): Purely cosmetic. Renamed cloneTextPane to cloneTextPanes and moved functions around so that cloneTextPanes, cloneDocument, cloneUndoItems, DetachDocument, and MoveDocument are together. 2004-07-23 18:07 n8gray * source/window.c (1.163): Applied TK Soh's patch to correct the colors of detached multi-pane windows. Fixes bug #996248. 2004-07-21 20:57 yooden * Microline/XmL/: Folder.c (1.5), FolderP.h (1.4), XmL.h (1.5) (utags: BETA-5-5): License change, step 3: Reapply changes to Mozilla widgets 2004-07-21 20:38 yooden * Microline/Makefile (1.2, BETA-5-5), Microline/Makefile.in (1.2, BETA-5-5), Microline/XmL/Folder.c (1.4), Microline/XmL/Folder.h (1.2, BETA-5-5), Microline/XmL/FolderP.h (1.3), Microline/XmL/Grid.c (1.2, BETA-5-5), Microline/XmL/Grid.h (1.2, BETA-5-5), Microline/XmL/GridP.h (1.2, BETA-5-5), Microline/XmL/GridUtil.c (1.2, BETA-5-5), Microline/XmL/Makefile (1.2, BETA-5-5), Microline/XmL/Makefile.in (1.2, BETA-5-5), Microline/XmL/Progress.c (1.2, BETA-5-5), Microline/XmL/Progress.h (1.2, BETA-5-5), Microline/XmL/ProgressP.h (1.2, BETA-5-5), Microline/XmL/Tree.c (1.2, BETA-5-5), Microline/XmL/Tree.h (1.2, BETA-5-5), Microline/XmL/TreeP.h (1.2, BETA-5-5), Microline/XmL/XmL.c (1.2, BETA-5-5), Microline/XmL/XmL.h (1.4), Microline/XmL/XmL.uih (1.2, BETA-5-5), Microline/examples/Makefile (1.2, BETA-5-5), Microline/examples/Makefile.in (1.2, BETA-5-5), Microline/examples/demo.c (1.2, BETA-5-5), Microline/examples/folder1.c (1.2, BETA-5-5), Microline/examples/folder2.c (1.2, BETA-5-5), Microline/examples/folder3.c (1.2, BETA-5-5), Microline/examples/folder4.c (1.2, BETA-5-5), Microline/examples/grid1.c (1.2, BETA-5-5), Microline/examples/grid2.c (1.2, BETA-5-5), Microline/examples/grid3.c (1.2, BETA-5-5), Microline/examples/grid4.c (1.2, BETA-5-5), Microline/examples/grid5.c (1.2, BETA-5-5), Microline/examples/grid6.c (1.2, BETA-5-5), Microline/examples/prog1.c (1.2, BETA-5-5), Microline/examples/prog2.c (1.2, BETA-5-5), Microline/examples/prog3.c (1.2, BETA-5-5), Microline/examples/tree1.c (1.2, BETA-5-5), Microline/examples/tree2.c (1.2, BETA-5-5), Microline/examples/tree3.c (1.2, BETA-5-5), Microline/examples/tree4.c (1.2, BETA-5-5), Microline/examples/tree5.c (1.2, BETA-5-5), Microline/examples/uil1.c (1.2, BETA-5-5), Microline/examples/uil1.uil (1.2, BETA-5-5), Microline/examples/util1.c (1.2, BETA-5-5), Microline/man/XmLArrayAdd.3x (1.2, BETA-5-5), Microline/man/XmLArrayDel.3x (1.2, BETA-5-5), Microline/man/XmLArrayFree.3x (1.2, BETA-5-5), Microline/man/XmLArrayGet.3x (1.2, BETA-5-5), Microline/man/XmLArrayGetCount.3x (1.2, BETA-5-5), Microline/man/XmLArrayMove.3x (1.2, BETA-5-5), Microline/man/XmLArrayNew.3x (1.2, BETA-5-5), Microline/man/XmLArrayReorder.3x (1.2, BETA-5-5), Microline/man/XmLArraySet.3x (1.2, BETA-5-5), Microline/man/XmLArraySort.3x (1.2, BETA-5-5), Microline/man/XmLCreateFolder.3x (1.2, BETA-5-5), Microline/man/XmLCreateGrid.3x (1.2, BETA-5-5), Microline/man/XmLCreateProgress.3x (1.2, BETA-5-5), Microline/man/XmLCreateTree.3x (1.2, BETA-5-5), Microline/man/XmLCvtStringToUChar.3x (1.2, BETA-5-5), Microline/man/XmLDateDaysInMonth.3x (1.2, BETA-5-5), Microline/man/XmLDateWeekDay.3x (1.2, BETA-5-5), Microline/man/XmLDrawnButtonSetType.3x (1.2, BETA-5-5), Microline/man/XmLFolder.3x (1.2, BETA-5-5), Microline/man/XmLFolderAddBitmapTab.3x (1.2, BETA-5-5), Microline/man/XmLFolderAddBitmapTabForm.3x (1.2, BETA-5-5), Microline/man/XmLFolderAddTab.3x (1.2, BETA-5-5), Microline/man/XmLFolderAddTabForm.3x (1.2, BETA-5-5), Microline/man/XmLFolderSetActiveTab.3x (1.2, BETA-5-5), Microline/man/XmLFontListCopyDefault.3x (1.2, BETA-5-5), Microline/man/XmLFontListGetDimensions.3x (1.2, BETA-5-5), Microline/man/XmLGrid.3x (1.2, BETA-5-5), Microline/man/XmLGridAddColumns.3x (1.2, BETA-5-5), Microline/man/XmLGridAddRows.3x (1.2, BETA-5-5), Microline/man/XmLGridColumnIsVisible.3x (1.2, BETA-5-5), Microline/man/XmLGridCopyPos.3x (1.2, BETA-5-5), Microline/man/XmLGridCopySelected.3x (1.2, BETA-5-5), Microline/man/XmLGridDeleteAllColumns.3x (1.2, BETA-5-5), Microline/man/XmLGridDeleteAllRows.3x (1.2, BETA-5-5), Microline/man/XmLGridDeleteColumns.3x (1.2, BETA-5-5), Microline/man/XmLGridDeleteRows.3x (1.2, BETA-5-5), Microline/man/XmLGridDeselectAllCells.3x (1.2, BETA-5-5), Microline/man/XmLGridDeselectAllColumns.3x (1.2, BETA-5-5), Microline/man/XmLGridDeselectAllRows.3x (1.2, BETA-5-5), Microline/man/XmLGridDeselectCell.3x (1.2, BETA-5-5), Microline/man/XmLGridDeselectColumn.3x (1.2, BETA-5-5), Microline/man/XmLGridDeselectRow.3x (1.2, BETA-5-5), Microline/man/XmLGridEditBegin.3x (1.2, BETA-5-5), Microline/man/XmLGridEditCancel.3x (1.2, BETA-5-5), Microline/man/XmLGridEditComplete.3x (1.2, BETA-5-5), Microline/man/XmLGridGetColumn.3x (1.2, BETA-5-5), Microline/man/XmLGridGetFocus.3x (1.2, BETA-5-5), Microline/man/XmLGridGetRow.3x (1.2, BETA-5-5), Microline/man/XmLGridGetSelectedCellCount.3x (1.2, BETA-5-5), Microline/man/XmLGridGetSelectedCells.3x (1.2, BETA-5-5), Microline/man/XmLGridGetSelectedColumnCount.3x (1.2, BETA-5-5), Microline/man/XmLGridGetSelectedColumns.3x (1.2, BETA-5-5), Microline/man/XmLGridGetSelectedRow.3x (1.2, BETA-5-5), Microline/man/XmLGridGetSelectedRowCount.3x (1.2, BETA-5-5), Microline/man/XmLGridGetSelectedRows.3x (1.2, BETA-5-5), Microline/man/XmLGridMoveColumns.3x (1.2, BETA-5-5), Microline/man/XmLGridMoveRows.3x (1.2, BETA-5-5), Microline/man/XmLGridPaste.3x (1.2, BETA-5-5), Microline/man/XmLGridPastePos.3x (1.2, BETA-5-5), Microline/man/XmLGridRead.3x (1.2, BETA-5-5), Microline/man/XmLGridReadPos.3x (1.2, BETA-5-5), Microline/man/XmLGridRedrawAll.3x (1.2, BETA-5-5), Microline/man/XmLGridRedrawCell.3x (1.2, BETA-5-5), Microline/man/XmLGridRedrawColumn.3x (1.2, BETA-5-5), Microline/man/XmLGridRedrawRow.3x (1.2, BETA-5-5), Microline/man/XmLGridReorderColumns.3x (1.2, BETA-5-5), Microline/man/XmLGridReorderRows.3x (1.2, BETA-5-5), Microline/man/XmLGridRowColumnToXY.3x (1.2, BETA-5-5), Microline/man/XmLGridRowIsVisible.3x (1.2, BETA-5-5), Microline/man/XmLGridSelectAllCells.3x (1.2, BETA-5-5), Microline/man/XmLGridSelectAllColumns.3x (1.2, BETA-5-5), Microline/man/XmLGridSelectAllRows.3x (1.2, BETA-5-5), Microline/man/XmLGridSelectCell.3x (1.2, BETA-5-5), Microline/man/XmLGridSelectColumn.3x (1.2, BETA-5-5), Microline/man/XmLGridSelectRow.3x (1.2, BETA-5-5), Microline/man/XmLGridSetFocus.3x (1.2, BETA-5-5), Microline/man/XmLGridSetStrings.3x (1.2, BETA-5-5), Microline/man/XmLGridSetStringsPos.3x (1.2, BETA-5-5), Microline/man/XmLGridWrite.3x (1.2, BETA-5-5), Microline/man/XmLGridWritePos.3x (1.2, BETA-5-5), Microline/man/XmLGridXYToRowColumn.3x (1.2, BETA-5-5), Microline/man/XmLMessageBox.3x (1.2, BETA-5-5), Microline/man/XmLPixmapDraw.3x (1.2, BETA-5-5), Microline/man/XmLProgress.3x (1.2, BETA-5-5), Microline/man/XmLRectIntersect.3x (1.2, BETA-5-5), Microline/man/XmLShellOfWidget.3x (1.2, BETA-5-5), Microline/man/XmLSort.3x (1.2, BETA-5-5), Microline/man/XmLStringDraw.3x (1.2, BETA-5-5), Microline/man/XmLStringDrawDirection.3x (1.2, BETA-5-5), Microline/man/XmLTree.3x (1.2, BETA-5-5), Microline/man/XmLTreeAddRow.3x (1.2, BETA-5-5), Microline/man/XmLTreeAddRows.3x (1.2, BETA-5-5), Microline/man/XmLWarning.3x (1.2, BETA-5-5), util/vmsParam.h (1.5, BETA-5-5): License change, step 2: Import of Mozilla files with new license 2004-07-21 11:32 yooden * README (1.38, BETA-5-5), doc/help.etx (1.71, BETA-5-5), doc/nc.pod (1.6, BETA-5-5), doc/nedit.pod (1.7, BETA-5-5), doc/setext (1.12, BETA-5-5), source/calltips.c (1.8, BETA-5-5), source/calltips.h (1.3, BETA-5-5), source/file.c (1.85, BETA-5-5), source/file.h (1.14, BETA-5-5), source/help.c (1.101, BETA-5-5), source/help.h (1.12, BETA-5-5), source/help_data.h (1.69, BETA-5-5), source/help_topic.h (1.60, BETA-5-5), source/highlight.c (1.49, BETA-5-5), source/highlight.h (1.13, BETA-5-5), source/highlightData.c (1.67, BETA-5-5), source/highlightData.h (1.12, BETA-5-5), source/interpret.c (1.40, BETA-5-5), source/interpret.h (1.16, BETA-5-5), source/linkdate.c (1.4, BETA-5-5), source/macro.c (1.88, BETA-5-5), source/macro.h (1.7, BETA-5-5), source/menu.c (1.110, BETA-5-5), source/menu.h (1.12, BETA-5-5), source/nc.c (1.43, BETA-5-5), source/nedit.c (1.79, BETA-5-5), source/nedit.h (1.57, BETA-5-5), source/parse.h (1.6, BETA-5-5), source/preferences.c (1.122, BETA-5-5), source/preferences.h (1.42, BETA-5-5), source/rangeset.c (1.11, BETA-5-5), source/rangeset.h (1.6, BETA-5-5), source/rbTree.h (1.4, BETA-5-5), source/regexConvert.c (1.10, BETA-5-5), source/regexConvert.h (1.6, BETA-5-5), source/regularExp.c (1.24, BETA-5-5), source/regularExp.h (1.11, BETA-5-5), source/search.c (1.70, BETA-5-5), source/search.h (1.22, BETA-5-5), source/selection.c (1.30, BETA-5-5), source/selection.h (1.6, BETA-5-5), source/server.c (1.31, BETA-5-5), source/server.h (1.6, BETA-5-5), source/server_common.c (1.5, BETA-5-5), source/server_common.h (1.2, BETA-5-5), source/shell.c (1.33, BETA-5-5), source/shell.h (1.8, BETA-5-5), source/shift.c (1.16, BETA-5-5), source/shift.h (1.5, BETA-5-5), source/smartIndent.c (1.35, BETA-5-5), source/smartIndent.h (1.7, BETA-5-5), source/tags.c (1.58, BETA-5-5), source/tags.h (1.14, BETA-5-5), source/text.c (1.47, BETA-5-5), source/text.h (1.19, BETA-5-5), source/textBuf.c (1.32, BETA-5-5), source/textBuf.h (1.16, BETA-5-5), source/textDisp.c (1.57, BETA-5-5), source/textDisp.h (1.25, BETA-5-5), source/textDrag.c (1.10, BETA-5-5), source/textDrag.h (1.4, BETA-5-5), source/textP.h (1.9, BETA-5-5), source/textSel.c (1.14, BETA-5-5), source/textSel.h (1.5, BETA-5-5), source/undo.c (1.17, BETA-5-5), source/undo.h (1.7, BETA-5-5), source/userCmds.c (1.48, BETA-5-5), source/userCmds.h (1.7, BETA-5-5), source/window.c (1.162), source/window.h (1.24, BETA-5-5), source/windowTitle.c (1.13, BETA-5-5), source/windowTitle.h (1.4, BETA-5-5), util/DialogF.c (1.29, BETA-5-5), util/DialogF.h (1.10, BETA-5-5), util/check_lin_tif.c (1.10, BETA-5-5), util/clearcase.c (1.5, BETA-5-5), util/clearcase.h (1.4, BETA-5-5), util/fileUtils.c (1.32, BETA-5-5), util/fileUtils.h (1.11, BETA-5-5), util/fontsel.c (1.27, BETA-5-5), util/fontsel.h (1.10, BETA-5-5), util/getfiles.c (1.29, BETA-5-5), util/getfiles.h (1.7, BETA-5-5), util/managedList.c (1.14, BETA-5-5), util/managedList.h (1.6, BETA-5-5), util/misc.c (1.67, BETA-5-5), util/misc.h (1.24, BETA-5-5), util/prefFile.c (1.23, BETA-5-5), util/prefFile.h (1.7, BETA-5-5), util/printUtils.c (1.24, BETA-5-5), util/printUtils.h (1.8, BETA-5-5), util/system.h (1.15, BETA-5-5), util/utils.c (1.21, BETA-5-5), util/utils.h (1.12, BETA-5-5), util/vmsUtils.c (1.6, BETA-5-5), util/vmsUtils.h (1.6, BETA-5-5): License change, step 1: Added Motif clause to a lot of files. 2004-07-20 01:40 n8gray * source/window.c (1.161): The stats line copies its font from the Row/Column widget. 2004-07-18 23:13 yooden * source/shift.c (1.15): Fixes inconsistency between 'Fill Paragraph' and wrap. 2004-07-18 22:30 yooden * doc/help.etx (1.70), source/file.c (1.84), source/help.c (1.100), source/help_data.h (1.68), source/help_topic.h (1.59), source/highlight.c (1.48), source/highlightData.c (1.66), source/macro.c (1.87), source/menu.c (1.109), source/nedit.c (1.78), source/preferences.c (1.121), source/search.c (1.69), source/selection.c (1.29), source/shell.c (1.32), source/smartIndent.c (1.34), source/tags.c (1.57), source/userCmds.c (1.47), source/windowTitle.c (1.12), util/fontsel.c (1.26), util/getfiles.c (1.28), util/misc.c (1.66), util/printUtils.c (1.23): Fixes some of the misnamed dialogs. 2004-07-15 21:17 n8gray * source/: help.c (1.99), nedit.c (1.77): Fix for bug 873469: nedit -V requires X server. Fix due to T. Haude with slight modification. (argument scanning stops if it sees "--".) 2004-07-15 18:47 edg * ReleaseNotes (1.25, BETA-5-5): Added bug #987102 to the list of bugs fixed in 5.5. 2004-07-15 18:39 edg * source/regularExp.c (1.23): Fix for SF bug #987102: segmentation fault on replace. Regex recursion is now limited to 10000. The API could still be extended to handle errors more gracefully (error messages are currently written to stderr). 2004-07-15 18:30 edg * source/nedit.c (1.76): Added Lesstif-specific suppression of harmless but annoying warnings generated by non-production versions of the library. Developers can see the suppressed messages by adding -DDEBUG_LESSTIF_WARNINGS to their compile flags. So far, I've added 3 messages to the suppression list, but the list can easily be extended if more of these messages show up. 2004-07-15 18:26 edg * util/check_lin_tif.c (1.9): Added OpenMotif 2.2.3 and Lesstif 0.93.94 to the "known good" lists. (I didn't add 0.93.95 since it doesn't officially exist yet). 2004-07-15 17:08 edg * source/calltips.c (1.7): Removed the custom fix for SF bug #925951 again. It is covered by the fix for bug #991700. 2004-07-15 17:06 edg * source/nedit.c (1.75): Fix for SF bug #991700: 5.5 crash. The workaround to prevent this crash was executed too late due to the reorganization of the shells. 2004-07-15 09:07 yooden * source/file.c (1.83): Small optimization in backupFileName() 2004-07-15 02:03 yooden * makefiles/Makefile.solarisx86 (1.1, BETA-5-5): Added Makefile for Solaris x86. 2004-07-15 01:47 yooden * source/: highlightData.c (1.65), preferences.c (1.120): Fixes two small issues wrt C++. 2004-07-14 19:51 n8gray * source/menu.c (1.108): There were two accelerators for 'T' in the File menu. I changed "Load Tags File" to use 'g' instead. 2004-07-14 19:48 n8gray * makefiles/Makefile.macosx (1.7, BETA-5-5): Adding the -mdynamic-no-pic gcc flag to get cleaner code on OS X. 2004-07-14 13:31 yooden * source/file.c (1.82): Someone forgot to call stat() before querying the statbuf. 2004-07-13 11:44 edg * source/menu.c (1.107): Another crash fix: tab context popup menu didn't inherit proper visual. 2004-07-13 11:35 edg * Xlt/BubbleButton.c (1.6, BETA-5-5): Crash fix: bubblebutton tooltips didn't inherit proper visual (Tk Soh). 2004-07-12 20:08 edg * source/search.c (1.68): Fix for incremental search bar clear button crash reported by Yury Burkatovsky. It wasn't as hard as I thought it would be. 2004-07-09 12:20 edg * ReleaseNotes (1.24): First stab at the release notes for 5.5. 2004-07-09 07:44 edg * util/misc.c (1.65): Inserted some casts to suppress harmless warnings on Solaris. 2004-07-08 13:07 edg * source/help.c (1.98): More fundamental fix for SF bug #982589: Help font inconsistent with window size. The help window size calculation is now based on the actual fixed font used in the help window. 2004-07-08 06:29 n8gray * Makefile (1.16, BETA-5-5), README (1.37), source/help_data.h (1.67), source/help_topic.h (1.58), source/nc.c (1.42): Man, that was a quick beta! Back to RC1. 2004-07-07 08:18 edg * ChangeLog (1.38, BETA-5-5): Regenerated (cvs2cl.pl -b -r -t --accum --gmt). 2004-07-07 01:39 n8gray * README (1.36), makefiles/Makefile.macosx (1.6): Updating some OS X documentation. 2004-07-07 03:14 n8gray * Makefile (1.15), README (1.35), source/help_data.h (1.66), source/nc.c (1.41): I guess we should go to BETA1 before RC1. 2004-07-07 02:51 n8gray * Makefile (1.14), README (1.34), source/help_data.h (1.65), source/help_topic.h (1.57), source/nc.c (1.40): Updating version information for 5.5RC1. 2004-07-03 00:16 edg * source/highlightData.c (1.64): Minor update to the Python patterns: added new built-in functions, exceptions, warnings, ... that were introduced in Python 2.3. 2004-06-30 13:56 edg * source/help.c (1.97): Increased the help window size from 65 to 75 columns as a workaround for the window becoming smaller due to changes in the font specifications. (SF bug #982589: Help font inconsistent with window size) 2004-06-28 10:23 edg * source/menu.c (1.106): Fix for SF bug #933146: VMS Open Previous DB file error. 2004-06-23 15:25 edg * source/server.c (1.30): Race condition fix for SF bug #978104: nedit -sync option. The server missed the first property change in synchronous mode. 2004-06-21 09:42 edg * doc/help.etx (1.69), source/help_data.h (1.64), source/help_topic.h (1.56): Cross-reference fixes (Yury Burkatovsky). 2004-06-13 03:08 tksoh * source/window.c (1.160): Fixed shrinking-window bug on some window manager such as Metacity, where window would shrink when switching between documents with different font size. 2004-06-11 12:33 edg * Microline/XmL/XmL.h (1.3): Fixed a #define collision when compiling with OM 2.2.3. 2004-06-11 12:16 edg * source/: menu.c (1.105), nedit.h (1.56), window.c (1.159): Fixes for SF bug #779454: SGI_CUSTOM & windows names. Removed all obsolete SGI_WINDOW_TITLE stuff. 2004-06-11 10:14 edg * source/highlightData.c (1.63): Removed unused declaration. 2004-06-10 19:04 edg * doc/help.etx (1.68), source/help_data.h (1.63), source/help_topic.h (1.55): More help updates from Joerg Fischer. 2004-06-10 19:01 edg * source/: highlight.c (1.47), highlightData.c (1.62), macro.c (1.86): Commit SF patch #970491: Forbid deletion of the "Plain" Text Drawing Style (Tony Balinski). 2004-06-09 19:52 edg * source/: userCmds.c (1.46), window.c (1.158): Crash fix: bgMenuUndo/RedoItem were memcopied when opening multiple tabs in a window. This could eventually result in accesses to destroyed bg menu items (and crashes), but only when the tabs use different language modes. That's why crashes were rather rare (and the illegal accesses didn't always result in a crash). 2004-06-08 17:36 edg * doc/help.etx (1.67), doc/nc.pod (1.5), doc/nedit.pod (1.6), source/help_data.h (1.62), source/help_topic.h (1.54): Help updates: tabbed editing and incremental search bar (Joerg Fischer). 2004-06-08 17:30 edg * source/server.c (1.29), util/misc.c (1.64), util/misc.h (1.23): Committed SF patch #963120: Open tab in window on current desktop. New files opened via nc no longer appear in a tab of some pseudo-random window, possible on a different window manager desktop, but on a window of the current desktop. If no window exists on the current desktop, a new one is created. Requires the window manager to be EWMH compliant, but falls back to the old behaviour for non-compliant wms. 2004-06-08 17:08 tringali * source/shell.c (1.31): Fix from Tony Balinski: close unused fds so that shell commands can be invoked asynchronously. Otherwise, we will wait for the command to end even if the input/output/error streams were redirected to /dev/null. 2004-06-01 14:23 edg * source/server_common.c (1.4): Memory leak and malloc/free mismatch fixes. 2004-05-25 21:31 tringali * source/nedit.c (1.74): Don't use labelFontList et al on Cygwin/LessTif. 2004-05-16 14:02 tksoh * source/window.c (1.157): Fixed coredump if offers to save file were refused when closing window with several modified documents. 2004-05-12 11:21 edg * source/interpret.c (1.39): Missed a spot in the debug code when I applied the macro string changes. 2004-05-11 21:56 edg * doc/help.etx (1.66), doc/nc.pod (1.4), doc/nedit.pod (1.5), source/help_data.h (1.61), source/help_topic.h (1.53): Updated rangeset documentation (SF bug #922282) and -do documentation (Joerg, with remarks of Tony). 2004-05-06 10:39 jlous * source/menu.c (1.104): Changed "Tabs..." to "Tab Stops..." in menus. 2004-05-04 16:19 edg * README (1.33), doc/help.etx (1.65), doc/nc.pod (1.3), doc/nedit.pod (1.4), source/help_data.h (1.60), source/help_topic.h (1.52): Added TK to the list of authors. 2004-05-04 09:41 edg * Xlt/BubbleButton.c (1.5): Added declaration of _XmStringCreateExternal (SF bug #923924). 2004-05-03 14:08 edg * ChangeLog (1.37): Regenerated (cvs2cl.pl -b -r -t --accum --gmt). 2004-05-03 13:59 edg * source/window.c (1.156): Bug fix: File->Close in the original window was disabled after calling calling the detach_document() macro subroutine. 2004-05-03 09:26 edg * util/check_lin_tif.c (1.8): Classified OM 2.2.3 (the real one, not the 2.2.2 version claiming to be 2.2.3) as being UNTESTED iso. KNOWN BAD. If no show-stoppers are found, we can classify it as a supported version. 2004-05-03 08:54 edg * Xlt/BubbleButton.c (1.4): Fixed inconsistent linkage declaration for _XmExportLabelString. 2004-05-03 08:53 edg * util/misc.c (1.63): Disabled the sticky radiobutton workaround for OM 2.2.3 and above. The bug appears to be fixed in 2.2.3. 2004-04-30 15:27 edg * source/interpret.c (1.38): Added some comments to the new string allocation routines. 2004-04-30 14:35 edg * source/: interpret.c (1.37), interpret.h (1.15), macro.c (1.85), smartIndent.c (1.33): Speed boost for macro string searching: keep string length together with the string to avoid excessive amount of strlen() calls in some cases. 2004-04-30 11:53 edg * source/window.c (1.155): Bug fix: closing a tab via a macro called from another tab resulted in a crash or an endless loop in GetTopDocument(). 2004-04-30 04:06 tksoh * source/: nedit.c (1.73), window.c (1.154): Some GUI changes on statsAreaForm: removed the separator below the tab-bar; removed some hardcoded visual resources on tab and tab-bar; statsline's text widget to inherit colors from it's immediate parent form, to ease customization. 2004-04-29 02:34 tksoh * source/: menu.c (1.103), nedit.c (1.72), text.c (1.46): Removed tab navigation items from the Window menu, and handle them with text widget's translation table. 2004-04-28 01:54 tksoh * doc/help.etx (1.64), source/help_data.h (1.59), source/help_topic.h (1.51), source/menu.c (1.102), source/nedit.c (1.71), source/nedit.h (1.55), source/window.c (1.153), source/window.h (1.23): Renamed "Split Window" to "Split Pane", and split_window() is now split_pane(). 2004-04-27 01:35 tksoh * source/: file.c (1.81), menu.c (1.101), nedit.h (1.54), preferences.c (1.119), window.c (1.152): Second (and hopefully final) phase of Buffers-to-Documents conversion; Also added brief description to struct WindowInfo on tabbed mode. 2004-04-26 03:01 tksoh * source/window.c (1.151): Fix for SF bug #941888: Window shrinks when switching between tabs on some window managers such as metacity. 2004-04-24 04:53 tksoh * source/window.c (1.150): Preserve document opening chain (WindowList) when documents are detached or moved, so that macro functions such focus_window("last") will traverse the documents correctly. 2004-04-24 03:48 tksoh * source/window.c (1.149): Honor pref setting of "Hide Tab Bar When Only One Document is Open"; covering SF bug #939712: unexpected tab bar on startup. 2004-04-24 03:12 tksoh * source/window.c (1.148): Fixed coredump when closing top document. 2004-04-23 16:35 tringali * source/window.c (1.147): Fix for bug 940844 - flashing isearch bar on startup 2004-04-23 00:43 tksoh * source/window.c (1.146): Fixed bold-face on label of inactive tabs. 2004-04-19 15:46 tringali * source/: window.c (1.145), nedit.c (1.70): - Changed accelerators for next/prev window to Ctrl+Pg Up (for Mozilla compat.) - Bold-face the active tab for visibility, implemented with fontlist tags. 2004-04-17 10:32 tksoh * source/: nedit.c (1.69), window.c (1.144), window.h (1.22): Fixed WM session management (WM_SAVE_YOURSELF) support for tabbed mode. 2004-04-17 03:51 n8gray * doc/help.etx (1.63), source/help_data.h (1.58), source/help_topic.h (1.50): Updated documentation for the auto-scroll feature. The resource for setting the number of lines of padding has changed to nedit.autoScrollVPadding. 2004-04-16 08:15 edg * source/calltips.c (1.6): Fix for SF bug #925951: nedit 5.4 crashes when dragging a calltip. It appears to be a bug in SUN's Motif. Dragging is now disabled. 2004-04-15 22:32 n8gray * source/: menu.c (1.100), nedit.h (1.53), preferences.c (1.118), preferences.h (1.41), window.c (1.143), window.h (1.21): Committing the auto-scroll patch. For now 4 seems like a reasonable default. 2004-04-14 20:33 n8gray * source/: help_data.h (1.57), help_topic.h (1.49), window.c (1.142): Applied TK's patch for putting the * on the correct side of the tab's filename based on text alignment (with a minor change). I still don't understand why it didn't work for me before, but what the heck. Also it looks like I regenerated the help files. No changes there other than the dates at the top. 2004-04-14 15:12 edg * source/window.c (1.141): Warning fix (Andrew Stanaski). 2004-04-14 09:44 edg * source/: nedit.c (1.68), server.c (1.28): Additional fixes for potential crashes due to -do macro commands closing windows. 2004-04-14 05:45 tksoh * source/: nedit.c (1.67), server.c (1.27): Fixed coredump when running -do closed() or detach_document() with nc or nedit, or when files fail to open. Also corrected the behavior on VMS so that -do will only apply onto the first file globbed from the wildcard specified. 2004-04-14 00:49 n8gray * source/: nedit.c (1.66), window.c (1.140): Changed so that alignment of the filenames in tabs isn't hardwired. I edit lots of files that have the same prefix, e.g. mmc_ext_XXX.ml, and if too many tabs get opened then I end up with 25 identical tabs. This is much less of a problem if the text is right-aligned, since the .ml suffixes take up less space. You can try this out by setting the resource "*tab.alignment: XmALIGNMENT_END". One improvement would be to also put the "*" that indicates a file is modified on the right if the titles are right-aligned. I tried to implement that but for some reason couldn't read the setting of the alignment resource successfully. 2004-04-14 00:14 n8gray * source/window.c (1.139): Fixed the code to get the next tab on tab close/detach so that the correct tab is chosen when tabs are sorted. 2004-04-01 12:48 tksoh * source/window.c (1.138): Re-enabled window auto-resizing on (un)display of line numbers for multi-tab windows. Disabling auto-resize on font change alone would be enough to fix the growing-window bug. 2004-04-01 10:29 tksoh * source/window.c (1.137): Fixed BadMatch error when linking to various releases of Lesstif version 1.2 (no problem with v2.x), if we use XCreateBitmapFromData() to created bitmaps for buttons. 2004-04-01 02:50 tksoh * source/textDisp.c (1.56): Fixed BadWindow error when opening help window, introduced by the recent window auto-resize patch. 2004-04-01 01:38 tksoh * source/window.c (1.136): Fixed bug where the detached document would get an incorrect number of rows, when the document contain highlighting fonts with sizes differ from the primary font. For now there'd be some flickers due to the resizing of the detached window by syntax highlighting, etc - something that we are to address later - but the rows will at least be correct. 2004-03-31 15:02 tksoh * source/: highlight.c (1.46), textDisp.c (1.55), window.c (1.135): Disabled window auto-resizing, triggered by font change or (un)display of line numbers, for multi-tab windows. 2004-03-31 12:31 tksoh * source/: nedit.h (1.52), search.c (1.67), window.c (1.134): Applied SF patch #891884: Add Find and Clear buttons to i-search 2004-03-29 14:42 tksoh * source/userCmds.c (1.45): Fixed coredump when invoking BG menu on lower split-panes. 2004-03-28 12:15 yooden * .cvsignore (1.3), doc/.cvsignore (1.5), source/.cvsignore (1.5), util/.cvsignore (1.4): Moves *.bck to global ignore file. 2004-03-25 17:37 tksoh * source/: menu.c (1.99), window.c (1.133): Removed unused functions. 2004-03-25 07:12 n8gray * .cvsignore (1.2), doc/.cvsignore (1.4), doc/help.etx (1.62), source/.cvsignore (1.4), source/help_data.h (1.56), source/help_topic.h (1.48), source/textDrag.c (1.9), util/.cvsignore (1.3): Updated the help files to document action routines for all menu items. Also added *.bck to .cvsignore files. 2004-03-25 04:27 tksoh * source/: file.c (1.80), file.h (1.13), macro.c (1.84), menu.c (1.98), nedit.c (1.65), preferences.c (1.117), selection.c (1.28), server.c (1.26), tags.c (1.56), window.c (1.132), window.h (1.20): Speed up opening of multiple files, by opening the files in background and deferring the syntax highlighting (SH) process. SH may be triggered later when a document is raised, or accessed by macro functions. 2004-03-21 14:25 tksoh * source/: Makefile.common (1.17), window.c (1.131): Bugfix for persistent tooltip of tabs, when dragged with middle button. 2004-03-19 15:17 tringali * util/system.h (1.14): Fix bogus IA64 defintion; detect Intel when masquerading as gcc; guess when compiling HP C. 2004-03-19 09:53 tksoh * source/window.c (1.130): Make next/prev document actions independent of tab sorting policy. 2004-03-11 12:42 edg * source/: nedit.h (1.51), userCmds.c (1.44): Bug fixes for user menu cache (Uwe Lehnert). 2004-03-06 22:44 n8gray * source/: menu.c (1.97), nedit.h (1.50), preferences.c (1.116): Added "Sort Tabs Alphabetically" menu item. 2004-03-06 02:24 n8gray * source/window.c (1.129): Fixed SortTabBar -- it wasn't updating the "next" pointers, which broke the next/previous tab actions. 2004-03-05 08:10 tksoh * source/: menu.c (1.96), menu.h (1.11), userCmds.c (1.43), window.c (1.128): Hide the BG tearoffs when switching doc, and restore them when switched back later. 2004-03-04 09:44 tksoh * source/: menu.c (1.95), menu.h (1.10), nedit.h (1.49), preferences.c (1.115), userCmds.c (1.42), userCmds.h (1.6), window.c (1.127): Applied SF patch #891126: user menu cache. 2004-03-04 00:49 tksoh * source/: file.c (1.79), preferences.c (1.114), preferences.h (1.40), window.c (1.126), window.h (1.19): If 'nedit.sortTab' is True, sort the tabs on the tab bar by filenames alphabetically. Sorting is disabled by default. 2004-03-03 13:28 edg * source/textBuf.c (1.31): Bug fix in BufCountDispChars: don't count terminating \0 of text buffer. 2004-03-03 07:06 tksoh * source/: menu.c (1.94), window.h (1.18): Cleaned up residue of "Attach Tab". 2004-03-02 12:47 tksoh * source/undo.c (1.16): Removed flickers on text area that occured when undoing/redoing with selection and 'nedit.undoModifiesSelection' set to false. 2004-03-02 08:15 tksoh * source/: menu.c (1.93), nedit.h (1.48), window.c (1.125), window.h (1.17): Changed Menu "Attach Tab..." to "Move Tab To...". The corresponding AP attach_document_dialog() is changed to move_document_dialog() too; Also revised preference menus under "Tabbed Editing". 2004-02-27 00:53 tksoh * source/window.c (1.124): Bugfix for shrunken upper split panes when documents are detached or attached. 2004-02-26 09:54 edg * source/window.c (1.123): Clone tab distance & emulation settings when cloning a document. 2004-02-25 02:47 tksoh * source/: menu.c (1.92), window.c (1.122): Made line number display a shell-level item, like the i-search and stats lines. Also fixed few associated bugs. 2004-02-23 02:51 n8gray * source/textBuf.c (1.30): Eliminated unnecessary #include. 2004-02-21 14:25 yooden * doc/help.etx (1.61), source/help_data.h (1.55), source/help_topic.h (1.47): Fiyes typos in help, adds args[] doc (Tony Balinski), changes mailing list information (Joor Loohuis). 2004-02-21 05:45 tksoh * source/: file.c (1.78), macro.c (1.83), menu.c (1.91), preferences.c (1.113), search.c (1.66), shell.c (1.30), smartIndent.c (1.32), tags.c (1.55), undo.c (1.15), userCmds.c (1.41), window.c (1.121), window.h (1.16): Update button state or sensitivity of the main menus only if the document being worked on is on top. This prevent the macro operation from updating the menu buttons incorrectly, when acting on documents currently not on top. 2004-02-20 09:27 tksoh * source/menu.c (1.90): Corrected mnemonic of 'Last Viewed Tab' menu. 2004-02-19 06:33 tksoh * source/nedit.c (1.64): Added missing -group option in nedit command line help message. 2004-02-19 06:23 tksoh * doc/help.etx (1.60), source/help_data.h (1.54), source/help_topic.h (1.46), source/nc.c (1.39), source/nedit.c (1.63): Added option -group to nc and nedit, to allow opening of group of files as tabs in a new window. 2004-02-17 01:01 tksoh * source/window.c (1.120): Fixed coredump when loading tag files, caused by dangling pointer of mode messages. 2004-02-16 01:02 tksoh * doc/help.etx (1.59), source/file.c (1.77), source/file.h (1.12), source/help_data.h (1.53), source/help_topic.h (1.45), source/macro.c (1.82), source/menu.c (1.89), source/nc.c (1.38), source/nedit.c (1.62), source/nedit.h (1.47), source/preferences.c (1.112), source/preferences.h (1.39), source/search.c (1.65), source/selection.c (1.27), source/server.c (1.25), source/tags.c (1.54), source/window.c (1.119): Applied SF patch #893177: modeless tabbed windows. 2004-02-14 02:22 tksoh * source/window.c (1.118): Bugfix: top BG menu tearoffs were not closed before switching tabbed document. 2004-02-13 12:32 tksoh * source/window.c (1.117): Close all BG menu tearoffs before switching tabbed document. BG menu is local to each document, so should not stay up when its parent doc isn't. 2004-02-13 07:53 tksoh * source/window.c (1.116): Bugfix: banner not cleared after loading tag files, etc. 2004-02-10 22:29 yooden * Microline/XmL/Folder.c (1.3), source/file.c (1.76), source/window.c (1.115): Removes some warnings. 2004-02-10 14:25 tringali * source/nedit.c (1.61): Fix reversed tab accelerators in LessTif 2004-02-10 02:00 tringali * source/nedit.c (1.60): Fix for tab accelerators in LessTif; avoid trapping Alt+Shift+arrow too. 2004-02-09 11:02 edg * source/window.c (1.114): Added missing shell/macroMenuValid initializations. 2004-02-09 09:45 tksoh * source/: rangeset.c (1.10), rangeset.h (1.5), window.c (1.113): Bugfix for: 1) coredump when detaching/attaching document containing destroyed rangeset; 2) after being detached/attached, colors of subsequently added rangesets were not refreshed immediately. 2004-02-09 04:16 tksoh * source/window.c (1.112): Applied workaround for partially (bottom) obscured text area of new tabs on OM-2.1.30, and perhaps other Motifs also? 2004-02-08 02:49 tksoh * source/window.c (1.111): Applied workaround for coredump when closing tabs in the middle of keystrokes learning, by clicking on the close-tab button. See comment of closeTabCB() for detail. 2004-02-08 01:46 tksoh * source/window.c (1.110): Bugfix: stats or i-search line might come up concealed on new windows, if the tab bar was set to be always displayed. 2004-02-07 15:44 tringali * source/: menu.c (1.88), menu.h (1.9), nedit.h (1.46), window.c (1.109): Tab context menu via TK Soh, from SF patch 891679 2004-02-07 02:20 tringali * source/nedit.c (1.59): - Visual for inactive tabs: use a lighter grey foreground. Ideally we'd make the active tab boldface, but that requires mucking about with fonts. - Non-emacs accelerators for tab navigation: Alt-Left,Alt-Right,Alt-Home 2004-02-05 07:29 tksoh * source/window.c (1.108): Bugfix for missing BG menus in second and subsequent tabbed docs. 2004-02-04 08:44 tksoh * source/: file.c (1.75), menu.c (1.87), nedit.h (1.45), window.c (1.107), window.h (1.15): Create tabbed document in background, to avoid unnecessary updates on the user menus. This reduces the flickers on the tearoffs of the user menus. It also speeds up the process of opening multiple files, particularly those of the same language modes. 2004-02-03 14:26 edg * source/preferences.c (1.111): Fix for SF bug #887581: /* Uncomment */ macro problem. 2004-02-03 08:25 edg * ChangeLog (1.36): Regenerated (cvs2cl.pl -b -r -t --accum --gmt). 2004-02-03 08:18 edg * source/macro.c (1.81): Fix for SF bug #889444: rangeset_add(rs1, rs2) fails if rs1, rs2 is empty. 2004-02-03 07:27 tksoh * source/preferences.c (1.110): Bugfix: nedit.tabbedMode was not saved to nedit.rc file. 2004-02-03 07:27 tksoh * source/preferences.c (1.110): Bugfix: nedit.tabbedMode was not saved to nedit.rc file. 2004-01-29 11:03 tksoh * source/smartIndent.c (1.31): Applied workaround for Motif crash-with-tearoffs bug to Smart Indent dialog. Any more? 2004-01-29 10:53 tksoh * source/highlightData.c (1.61), source/window.c (1.106), util/misc.c (1.62), util/misc.h (1.22): Applied workaround for Motif crash-with-tearoffs bug to Syntax Highlighting Patterns dialog. 2004-01-28 01:50 tksoh * doc/help.etx (1.58), source/help_data.h (1.52), source/help_topic.h (1.44), source/preferences.c (1.109): A sort of fix for SF Bug #883894: removed normal non-whitespace text characters from the default backlighting list, so that those characters will be displayed with the background color as defined by the nedit.textBgColor resource - unless overridden by syntax highlighting. 2004-01-27 18:02 tksoh * source/: userCmds.c (1.40), window.c (1.105): When switching tabs, only update Macro/Shell/BG menus only if the language mode has changed, to reduce flickers on the tearoffs. 2004-01-27 17:44 tksoh * source/preferences.c (1.108): Fix for SF bug #884862: typo in class names of preference resources. 2004-01-26 09:23 tksoh * source/: macro.c (1.80), macro.h (1.6), nedit.h (1.44), shell.c (1.29), shell.h (1.7), window.c (1.104): Mode message display was not handled properly as we switch between documents. 2004-01-20 03:31 tksoh * source/window.c (1.103): fixed compiling warning on use of undeclared function. 2004-01-20 02:48 tksoh * source/: rangeset.c (1.9), rangeset.h (1.4), window.c (1.102): Transfer rangeset info when attaching/detaching tabs (Uwe Lehnert) 2004-01-16 11:49 edg * source/file.c (1.74): Fix for SF bug #878183: File deleted. Don't delete incremental backup files when incremental backups are off. 2004-01-16 09:18 edg * source/highlightData.c (1.60), source/preferences.c (1.107), source/search.c (1.64), source/userCmds.c (1.39), util/misc.c (1.61), util/misc.h (1.21): Applied the "OpenMotif sticky radio button" workaround to all radio buttons. 2004-01-16 02:59 tksoh * doc/help.etx (1.57), source/file.c (1.73), source/help_data.h (1.51), source/help_topic.h (1.43), source/macro.c (1.79), source/menu.c (1.86), source/nedit.c (1.58), source/nedit.h (1.43), source/preferences.c (1.106), source/preferences.h (1.38), source/search.c (1.63), source/server.c (1.24), source/userCmds.c (1.38), source/window.c (1.101), source/window.h (1.14): Phase one of Buffers-to-Documents conversion. 2004-01-15 07:59 tksoh * source/window.c (1.100): Bugfix: always update Macro & Shell menus when raising a buffer, so that the keyboard shortcuts are refreshed properly. We'll worry about the visual optimization later. 2004-01-13 15:49 edg * source/window.c (1.99): Prevent some (harmless) uninitialized variable accesses when creating a geometry string. 2004-01-13 14:46 tringali * source/window.c (1.98): Workaround for bug in OpenMotif 2.1 and 2.2. If you have an active tear-off menu from a TopLevelShell that is a child of an ApplicationShell, and then close the parent window, Motif crashes. The problem doesn't happen if you close the tear-offs first, so, we programatically close them before destroying the shell widget. 2004-01-13 02:45 tksoh * source/preferences.c (1.105): Fixed coredump when changing language mode via 'Language Mode' tearoff menu. 2004-01-12 17:31 edg * makefiles/Makefile.cygwin (1.8): Added check_tif_rule for Cygwin. 2004-01-12 17:09 edg * source/highlight.c (1.45): Bug fix for crash in highlighting dialog, reported by Joerg Fischer. Error pattern of color-only patterns was copied erroneously. 2004-01-10 06:12 tksoh * source/userCmds.c (1.37): Fixed coredump when invoking Macro/Shell/Background commands from tear-offs. 2004-01-09 05:56 tksoh * source/userCmds.c (1.36): Bugfix: when invoked by keyboard shoft-cuts, macro and shell commands were always executed in the first buffer created, or coredumped if the first buffer had been closed. 2004-01-08 06:19 tksoh * source/: macro.c (1.78), macro.h (1.5), shell.c (1.28), shell.h (1.6), window.c (1.97): Bugfix: cursor and statsline now reflect if macro/shell commands are in progress in each individual buffer. 2004-01-06 06:25 n8gray * source/macro.c (1.77): Patch monkey see, patch monkey do. Tony says fix rangeset bug, patch monkey fix rangeset bug. Ook. Fixes SF bug #871209 2004-01-06 02:38 tksoh * source/: menu.c (1.85), userCmds.c (1.35), window.c (1.96): Improved handling of tear-off (Macro, Shell and Windows) menus: i) fixed shrink-expand bugs; ii) tear-offs stay up when buffers are closed. 2004-01-02 10:32 tksoh * source/window.c (1.95): window manager's size hints should follow the top buffer. 2003-12-31 02:25 tksoh * source/window.c (1.94): Bugfix: bookmarks were lost when detaching/attaching buffers. (Uwe Lehnert) 2003-12-31 01:22 tksoh * source/window.c (1.93): Bugfix for crash when navigating through buffers. 2003-12-30 15:32 tringali * source/nedit.c (1.57): Also put back XmLFolder resources. 2003-12-30 15:19 tringali * source/nedit.c (1.56): Revert to fallback resources. The merging didn't work as I expected. 2003-12-29 10:58 tksoh * source/window.c (1.92): Applied temporary workaround for disappearing-text-window bug when linking to Lesstif (ver 0.93.18 & 0.93.46 tested) 2003-12-28 17:30 tringali * source/nedit.c (1.55): New default resource scheme. We enter resources directly via Xrm calls, instead of fallback resources. This should avoid version skew problems when an app-defaults file has been installed against our wishes. In particular, when there is an app-defaults file out there, we should now merge all the built-in and external resources. Fallback resources would simply discard the built-in resources in favor of the ones in the file, and this frequently would cause missing resources if the file was out of date. 2003-12-28 17:25 yooden * source/: highlightData.c (1.59), preferences.c (1.104): Changes LaTeX patterns (Jörg Fischer) and adds comment macro (Sergei Haller). 2003-12-28 17:25 tringali * source/window.c (1.91): Remove hardcoded visual resources for tab widget, in favor of resources that can be overridden. 2003-12-28 16:26 yooden * source/: help_data.h (1.50), help_topic.h (1.42), highlightData.c (1.58): Adds $args[] to the NEdit Macro pattern. 2003-12-26 10:14 tksoh * source/window.c (1.90): bugfix: text colors not correctly set for new tabs. 2003-12-25 07:09 tksoh * Makefile (1.13): Committed patch #569287: tabbed buffers mode. 2003-12-25 06:55 tksoh * Microline/XmL/Folder.c (1.2), Microline/XmL/FolderP.h (1.2), Microline/XmL/Makefile.common (1.1), Microline/XmL/Makefile.dependencies (1.1), Microline/XmL/XmL.h (1.2), Xlt/BubbleButton.c (1.3), Xlt/BubbleButton.h (1.2), Xlt/BubbleButtonP.h (1.2), Xlt/Makefile.common (1.1), Xlt/Makefile.dependencies (1.1), Xlt/SlideC.c (1.2), doc/help.etx (1.56), source/Makefile.common (1.16), source/file.c (1.72), source/file.h (1.11), source/highlight.c (1.44), source/highlight.h (1.12), source/interpret.c (1.36), source/macro.c (1.76), source/menu.c (1.84), source/menu.h (1.8), source/nc.c (1.37), source/nedit.c (1.54), source/nedit.h (1.42), source/preferences.c (1.103), source/preferences.h (1.37), source/search.c (1.62), source/search.h (1.21), source/selection.c (1.26), source/server.c (1.23), source/shell.c (1.27), source/smartIndent.c (1.30), source/tags.c (1.53), source/text.h (1.18), source/userCmds.c (1.34), source/window.c (1.89), source/window.h (1.13): Committed patch #569287: tabbed buffers mode. 2003-12-24 07:41 tksoh * Xlt/BubbleButton.c (1.2): Bugfix: XltNbubbleString could not be changed after an XltBubbleButton widget has been created. 2003-12-23 21:54 slobasso * doc/help.etx (1.55): docs for new $args[] array and removed 9 arg limit for macros 2003-12-23 10:53 yooden * source/file.c (1.71): Adds a warning to root if he wants to write read-only files. 2003-12-23 08:34 tksoh * Xlt/: BubbleButton.c (1.1), BubbleButton.h (1.1), BubbleButtonP.h (1.1), SlideC.c (1.1), SlideC.h (1.1), SlideCP.h (1.1): Importing the original code for XltBubbleButton from the Xlt Widget Set version 9.2.9 (http://xlt.soureforge.net). 2003-12-21 01:43 tksoh * Microline/: Makefile (1.1), Makefile.in (1.1), XmL/Folder.c (1.1), XmL/Folder.h (1.1), XmL/FolderP.h (1.1), XmL/Grid.c (1.1), XmL/Grid.h (1.1), XmL/GridP.h (1.1), XmL/GridUtil.c (1.1), XmL/Makefile (1.1), XmL/Makefile.in (1.1), XmL/Progress.c (1.1), XmL/Progress.h (1.1), XmL/ProgressP.h (1.1), XmL/Tree.c (1.1), XmL/Tree.h (1.1), XmL/TreeP.h (1.1), XmL/XmL.c (1.1), XmL/XmL.h (1.1), XmL/XmL.uih (1.1), examples/Makefile (1.1), examples/Makefile.in (1.1), examples/demo.c (1.1), examples/folder1.c (1.1), examples/folder2.c (1.1), examples/folder3.c (1.1), examples/folder4.c (1.1), examples/grid1.c (1.1), examples/grid2.c (1.1), examples/grid3.c (1.1), examples/grid4.c (1.1), examples/grid5.c (1.1), examples/grid6.c (1.1), examples/prog1.c (1.1), examples/prog2.c (1.1), examples/prog3.c (1.1), examples/tree1.c (1.1), examples/tree2.c (1.1), examples/tree3.c (1.1), examples/tree4.c (1.1), examples/tree5.c (1.1), examples/uil1.c (1.1), examples/uil1.uil (1.1), examples/util1.c (1.1), man/XmLArrayAdd.3x (1.1), man/XmLArrayDel.3x (1.1), man/XmLArrayFree.3x (1.1), man/XmLArrayGet.3x (1.1), man/XmLArrayGetCount.3x (1.1), man/XmLArrayMove.3x (1.1), man/XmLArrayNew.3x (1.1), man/XmLArrayReorder.3x (1.1), man/XmLArraySet.3x (1.1), man/XmLArraySort.3x (1.1), man/XmLCreateFolder.3x (1.1), man/XmLCreateGrid.3x (1.1), man/XmLCreateProgress.3x (1.1), man/XmLCreateTree.3x (1.1), man/XmLCvtStringToUChar.3x (1.1), man/XmLDateDaysInMonth.3x (1.1), man/XmLDateWeekDay.3x (1.1), man/XmLDrawnButtonSetType.3x (1.1), man/XmLFolder.3x (1.1), man/XmLFolderAddBitmapTab.3x (1.1), man/XmLFolderAddBitmapTabForm.3x (1.1), man/XmLFolderAddTab.3x (1.1), man/XmLFolderAddTabForm.3x (1.1), man/XmLFolderSetActiveTab.3x (1.1), man/XmLFontListCopyDefault.3x (1.1), man/XmLFontListGetDimensions.3x (1.1), man/XmLGrid.3x (1.1), man/XmLGridAddColumns.3x (1.1), man/XmLGridAddRows.3x (1.1), man/XmLGridColumnIsVisible.3x (1.1), man/XmLGridCopyPos.3x (1.1), man/XmLGridCopySelected.3x (1.1), man/XmLGridDeleteAllColumns.3x (1.1), man/XmLGridDeleteAllRows.3x (1.1), man/XmLGridDeleteColumns.3x (1.1), man/XmLGridDeleteRows.3x (1.1), man/XmLGridDeselectAllCells.3x (1.1), man/XmLGridDeselectAllColumns.3x (1.1), man/XmLGridDeselectAllRows.3x (1.1), man/XmLGridDeselectCell.3x (1.1), man/XmLGridDeselectColumn.3x (1.1), man/XmLGridDeselectRow.3x (1.1), man/XmLGridEditBegin.3x (1.1), man/XmLGridEditCancel.3x (1.1), man/XmLGridEditComplete.3x (1.1), man/XmLGridGetColumn.3x (1.1), man/XmLGridGetFocus.3x (1.1), man/XmLGridGetRow.3x (1.1), man/XmLGridGetSelectedCellCount.3x (1.1), man/XmLGridGetSelectedCells.3x (1.1), man/XmLGridGetSelectedColumnCount.3x (1.1), man/XmLGridGetSelectedColumns.3x (1.1), man/XmLGridGetSelectedRow.3x (1.1), man/XmLGridGetSelectedRowCount.3x (1.1), man/XmLGridGetSelectedRows.3x (1.1), man/XmLGridMoveColumns.3x (1.1), man/XmLGridMoveRows.3x (1.1), man/XmLGridPaste.3x (1.1), man/XmLGridPastePos.3x (1.1), man/XmLGridRead.3x (1.1), man/XmLGridReadPos.3x (1.1), man/XmLGridRedrawAll.3x (1.1), man/XmLGridRedrawCell.3x (1.1), man/XmLGridRedrawColumn.3x (1.1), man/XmLGridRedrawRow.3x (1.1), man/XmLGridReorderColumns.3x (1.1), man/XmLGridReorderRows.3x (1.1), man/XmLGridRowColumnToXY.3x (1.1), man/XmLGridRowIsVisible.3x (1.1), man/XmLGridSelectAllCells.3x (1.1), man/XmLGridSelectAllColumns.3x (1.1), man/XmLGridSelectAllRows.3x (1.1), man/XmLGridSelectCell.3x (1.1), man/XmLGridSelectColumn.3x (1.1), man/XmLGridSelectRow.3x (1.1), man/XmLGridSetFocus.3x (1.1), man/XmLGridSetStrings.3x (1.1), man/XmLGridSetStringsPos.3x (1.1), man/XmLGridWrite.3x (1.1), man/XmLGridWritePos.3x (1.1), man/XmLGridXYToRowColumn.3x (1.1), man/XmLMessageBox.3x (1.1), man/XmLPixmapDraw.3x (1.1), man/XmLProgress.3x (1.1), man/XmLRectIntersect.3x (1.1), man/XmLShellOfWidget.3x (1.1), man/XmLSort.3x (1.1), man/XmLStringDraw.3x (1.1), man/XmLStringDrawDirection.3x (1.1), man/XmLTree.3x (1.1), man/XmLTreeAddRow.3x (1.1), man/XmLTreeAddRows.3x (1.1), man/XmLWarning.3x (1.1): Importing Mozilla's Microline3.0 (XmL) library on the MozillaSourceClassic_19981026_BRANCH branch, which has been recently relicensed as MPL 1.1/GPL 2.0/LGPL 2.1. The original source tree for Microline3.0 can be obtained here: % cvs -d:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot \ co -r MozillaSourceClassic_19981026_BRANCH \ mozilla/cmd/xfe/Microline3.0/ 2003-12-19 23:23 slobasso * source/: interpret.c (1.35), interpret.h (1.14), macro.c (1.75), parse.y (1.27), parse_noyacc.c (1.8): added new $args[] array and removed 9 arg limit for macros 2003-12-13 18:16 yooden * util/prefFile.c (1.22): Removes unneeded variable. 2003-12-09 17:55 slobasso * doc/: .cvsignore (1.3), help.etx (1.54), nedit.pod (1.3): docs for -svrname change 2003-12-09 12:57 edg * source/nedit.c (1.53): Adapted the nedit.helpForm.* resource spec to the changed widget hierarchy (now nedit.help.helpForm.*) to make mouse navigation in help windows operational again. 2003-12-07 22:48 yooden * source/: highlightData.c (1.57), preferences.c (1.102): Adds a 'recursion level' to shell pattern set (see SF bug #770855). 2003-12-07 15:56 yooden * util/prefFile.c (1.21): Removes double file access to verify pref file read. 2003-12-05 00:05 slobasso * source/nedit.c (1.52): default to server if server name is supplied 2003-12-05 00:01 slobasso * source/nc.c (1.36): add missing trailing newline to usage 2003-12-04 19:07 slobasso * source/menu.c (1.83): first pass at neditdb corruption cleanup 2003-12-04 09:52 edg * source/window.c (1.88): Renamed the window shell from "text" to "textShell" to avoid resource matching ambiguities with the real text widget. 2003-11-26 21:58 yooden * doc/help.etx (1.53): Added documentation for nedit.undoModifiesSelection 2003-11-24 17:41 edg * doc/Makefile (1.6): Remove generated man pages when cleaning. 2003-11-22 13:03 edg * ChangeLog (1.35), Makefile (1.12), README (1.32), ReleaseNotes (1.23), doc/Makefile (1.5), doc/NEdit.ad (1.4), doc/help.etx (1.52), doc/nc.pod (1.2), doc/nedit.pod (1.2), doc/setext (1.11), makefiles/Makefile.bsdi (1.6), makefiles/Makefile.ccur (1.6), makefiles/Makefile.freebsd (1.6), makefiles/Makefile.generic (1.11), makefiles/Makefile.macosx (1.5), makefiles/Makefile.netbsd (1.6), makefiles/Makefile.openbsd (1.4), makefiles/Makefile.solaris (1.10), source/file.c (1.70), source/help_data.h (1.49), source/help_topic.h (1.41), source/highlight.c (1.43), source/highlight.h (1.11), source/highlightData.c (1.56), source/interpret.c (1.34), source/macro.c (1.74), source/menu.c (1.82), source/nc.c (1.35), source/nedit.c (1.51), source/nedit.h (1.41), source/preferences.c (1.101), source/rangeset.c (1.8), source/rangeset.h (1.3), source/search.c (1.61), source/search.h (1.20), source/server.c (1.22), source/tags.c (1.52), source/text.c (1.45), source/textBuf.c (1.29), source/textBuf.h (1.15), source/textDisp.c (1.54), source/textDisp.h (1.24), source/window.c (1.87), util/check_lin_tif.c (1.7), util/getfiles.c (1.27), util/misc.c (1.60), util/prefFile.c (1.20), util/system.h (1.13): Merged 5.4 release branch with main trunk. 2003-11-20 18:37 edg * ReleaseNotes, source/nc.c, source/server.c (BETA-5-4.[6,5,3]) (utags: REL-5-4): Fix for nc -lm and -geometry command line options being dropped in some cases. 2003-11-19 17:22 edg * Makefile (tags: REL-5-4) (BETA-5-4.5): 5.4RC2 -> 5.4. 2003-11-19 13:50 edg * ChangeLog (tags: REL-5-4) (BETA-5-4.3): Regenerated (cvs2cl.pl -b -r -t --accum --gmt). 2003-11-19 13:44 edg * README (tags: REL-5-4), ReleaseNotes, source/help_data.h (tags: REL-5-4), source/help_topic.h (tags: REL-5-4) (BETA-5-4.[7,5,9,6]): Bumped version number to 5.4. 2003-11-18 15:11 edg * source/menu.c (1.81): Fix for SF bug #844395: SGI_CUSTOM overtype crash. 2003-11-18 12:16 edg * util/fileUtils.c (1.31): Decreased the threshold for MAC file format detection to 1 carriage return instead of 2. 2003-11-17 10:13 edg * util/prefFile.c (BETA-5-4.1): Fix for nc crash on VMS (Michael Smith). 2003-11-16 13:50 yooden * doc/help.etx (1.51): Fixed wrong documentation of $sub_sep, pointed out by Jörg Fischer. 2003-11-14 23:46 yooden * source/: file.c (1.69), smartIndent.c (1.29): Fixes two small bugs: Wrong block and wrong argc. 2003-11-14 00:19 n8gray * README, makefiles/Makefile.macosx (BETA-5-4.[6,2]): Reworked the OS X makefile and added a note about building on OS X to the README. 2003-11-13 07:09 n8gray * util/check_lin_tif.c (BETA-5-4.7): Changed error/warning messages to be non-Linux-centric. 2003-11-08 00:15 yooden * source/file.c (1.68): Changes typo in resource name. 2003-11-07 17:27 edg * doc/help.etx, source/help_data.h, source/macro.c (BETA-5-4.[9,8,4]): Removed the bogus rgb values from the array returned by get_pattern_by_name(). Prevented the special "top" pattern from showing up in the array returned by get_style_at_pos(). Various minor code cleanups and comment fixes. (Mostly contributed by Tony Balinski). 2003-11-03 16:31 edg * doc/help.etx, source/help_data.h, source/highlight.c, source/highlight.h, source/macro.c (BETA-5-4.[8,7,1,1,3]): Changed the "extension" field returned by get_pattern_at_pos() to "extent" and added an "extent" field to the return value of get_style_at_pos(). 2003-10-24 15:29 edg * doc/help.etx (BETA-5-4.7): Typo fix (Yury). 2003-10-24 10:51 edg * doc/help.etx (1.50), source/help_data.h (1.48), source/text.c (1.44): Extended scroll_down() and scroll_up() such that one can specify a scroll unit (lines or pages, default: lines) and corrected the behaviour for CTRL + mouse wheel (scrolling no longer moves the cursor nor destroys the selection). 2003-10-22 20:05 tringali * source/help.c (1.96), source/highlightData.c (1.55), source/nedit.c (1.50), source/nedit.h (1.40), source/preferences.c (1.100), source/smartIndent.c (1.28), source/textSel.c (1.13), source/userCmds.c (1.33), source/window.c (1.86), util/check_lin_tif.c (1.6), util/misc.c (1.59), util/misc.h (1.20): Changed widget hierarchy so we have a single (hidden) top-level application shell. All the top-level windows (editors, syntax, macros, etc.) are now TopLevelShell children of the application shell. This is the standard way of structuring multiple-window applications, and we've been standing on our heads trying to work around problems the old approach causes (no visual propogation to children, no way to address types of top-level windows by name in resources, session management bugs, etc). Some advanced X resource customizations may need to change, but for the better, I think. 2003-10-20 16:38 tringali * source/interpret.c (tags: BETA-5-4-RC2) (BETA-5-4.1): Change #define to be in column 0; some compilers will not accept this indented. 2003-10-20 13:59 edg * ChangeLog (tags: BETA-5-4-RC2) (BETA-5-4.2): Regenerated (cvs2cl.pl -b -r -t --accum --gmt). 2003-10-20 08:29 edg * doc/nc.man, doc/nedit.man, source/help_data.h, source/help_topic.h (BETA-5-4.[2,2,6,5]) (utags: BETA-5-4-RC2): Regenerated for 5.4RC2. 2003-10-20 08:25 edg * doc/Makefile (tags: BETA-5-4-RC2) (BETA-5-4.2): Use double suffix rule for man page generation iso. GNU make extension. 2003-10-15 23:08 yooden * doc/help.etx, source/help_data.h, source/help_topic.h, source/nc.c (BETA-5-4.[6,5,4,4]): New documentation for nc. 2003-10-14 10:56 edg * doc/: nc.man, nedit.man (BETA-5-4.[1,1]): Regenerated. 2003-10-14 10:54 edg * doc/nedit.pod (1.1): file nedit.pod was initially added on branch BETA-5-4. 2003-10-14 10:54 edg * doc/nc.pod (1.1): file nc.pod was initially added on branch BETA-5-4. 2003-10-14 10:54 edg * doc/: Makefile, nc.pod, nedit.pod (BETA-5-4.[1,1,1]): Added man pages in pod format and automatic pod to man page translation. 2003-10-09 15:29 tringali * util/system.h (BETA-5-4.1): Recognize ia64, cygwin, x86-64, win32, unixware. 2003-10-09 09:23 edg * source/nc.c (BETA-5-4.3): Fix for SF #820491: nc -ask hangs when the user cancels the server startup. 2003-10-02 07:27 edg * doc/setext (BETA-5-4.2): More HTML generation improvements (Steven Haehn). 2003-10-01 11:34 edg * doc/setext (BETA-5-4.1): Bug fixes in HTML generation (Andrew Hood). 2003-09-28 15:05 edg * Makefile, README, ReleaseNotes (BETA-5-4.[4,5,4]): 5.4RC2 updates. 2003-09-28 15:03 edg * doc/NEdit.ad (BETA-5-4.2): Removed trailing whitespace. 2003-09-28 15:03 edg * makefiles/: Makefile.bsdi, Makefile.freebsd, Makefile.netbsd, Makefile.openbsd (BETA-5-4.[1,1,1,1]): Added Motif/Lesstif version check. 2003-09-28 14:18 edg * makefiles/Makefile.ccur, makefiles/Makefile.generic, makefiles/Makefile.solaris, source/file.c (BETA-5-4.[1,1,1,4]): Made USE_ACCESS the default (there's no security risk in the way we use access()). See also SF #782518. 2003-09-28 14:11 edg * doc/NEdit.ad (BETA-5-4.1): Updated resources to 5.4. 2003-09-28 14:10 edg * source/nc.c (BETA-5-4.2): Typo fix: noAsk -> noask. 2003-09-26 19:45 yooden * source/menu.c (BETA-5-4.3): Removes some references to the old NEdit file history file name. 2003-09-12 18:24 tringali * README (BETA-5-4.4): Updates for 5.4 2003-09-08 17:08 edg * ChangeLog (BETA-5-4.1): Regenerated (cvs2cl.pl -b -r -t --accum --gmt). 2003-09-08 17:03 edg * source/rangeset.c (BETA-5-4.5): Fixed integer overflow that caused infinite loops. 2003-08-26 09:59 edg * source/rangeset.c (BETA-5-4.4): Crash fix: rangeset name field not initialized. Other: rangeset table list field not initialized (unpredictable first label). 2003-08-24 20:07 yooden * source/highlightData.c (1.54): Fixed small bug in Shell pattern set. 2003-08-24 19:02 yooden * source/highlightData.c (BETA-5-4.3): Changed macro pattern from accomodate new highlighting information functions. 2003-08-22 16:24 edg * source/file.c (BETA-5-4.3): Fix for SF bug #792447: "modified by external..." and directories. 2003-08-21 10:50 edg * source/file.c (BETA-5-4.2): Moved some statements to avoid polluting errno before displaying an error dialog. 2003-08-21 06:41 n8gray * doc/help.etx, source/help_data.h, source/help_topic.h (BETA-5-4.[5,4,3]): Fixed help lines WRT -foreground and -background command-line options. Also noticed that help text for new rangeset API was never generated. 2003-08-15 21:58 n8gray * source/preferences.c (BETA-5-4.5): Also migrate old colors if there's no config file. 2003-08-14 22:06 slobasso * source/menu.c, util/check_lin_tif.c (BETA-5-4.[2,6]): fix warnings 2003-08-13 23:34 slobasso * source/nedit.h (BETA-5-4.1): adjust constant for more menu items 2003-08-13 16:22 edg * source/text.c (BETA-5-4.2): Make KP_Enter behave as Enter (Execute Command Line used to be bound to KP_Enter but is now bound to Ctrl+KP_Enter). (I tried to abort my previous commit when I realized there was a potential problem, but I failed. Sorry.) 2003-08-13 16:03 edg * source/text.c (BETA-5-4.1): [no log message] 2003-08-13 16:01 edg * source/file.c (BETA-5-4.1): Fix for SF bugs #782513: Clicking in text area requires save and #784442: NEdit thinks unchanged windows need save. Additionally: drop read-only attribute when file goes missing. 2003-08-12 11:47 edg * source/server.c (BETA-5-4.2): Last commit was a fix for SF bug #785738: "nc -do ..." creates extra window. 2003-08-12 11:43 edg * source/server.c (BETA-5-4.1): Avoid creating extra windows when using "nc -do ..." (Arne). 2003-08-08 16:24 slobasso * source/rangeset.c (BETA-5-4.3): Only text changes where the text is actually changed result in ranges being adjusted. This includes changing hardware tab size. 2003-08-08 16:20 slobasso * source/window.c (1.85): marks no longer get deleted when hardware tab size is changed. 2003-08-07 04:42 slobasso * doc/help.etx, source/macro.c (BETA-5-4.[4,2]): split get_pattern() and get_style() into get_pattern_by_name(), get_pattern_at_pos(), get_style_by_name(), and get_style_at_pos() 2003-08-04 22:32 slobasso * doc/help.etx (BETA-5-4.3): Fix mistake with rangeset_get_by_name() parameter list. 2003-08-03 17:38 yooden * source/highlightData.c (1.53), source/menu.c (1.80), source/preferences.c (1.99), source/preferences.h (1.36), util/managedList.c (1.13): Removes some unsused functions, function parameters and fixes a typo. 2003-08-02 21:03 yooden * source/highlightData.c (BETA-5-4.2): Adds new functions rangeset_get_by_name() and rangeset_set_name() to the NEdit Macro syntax highlighting pattern set. 2003-08-01 01:26 n8gray * source/: textDisp.c, textDisp.h, window.c (BETA-5-4.[1,1,1]): This should fix the problem where new panes didn't get the correct colors. It feels to me like there should be a better way to do this. 2003-07-31 22:35 n8gray * source/tags.c (BETA-5-4.1): Fixed error parsing alias blocks in calltips files. 2003-07-29 17:54 slobasso * doc/help.etx, source/macro.c, source/rangeset.c, source/rangeset.h (BETA-5-4.[2,1,2,1]): add name to rangesets and fix several int/string implicit conversions 2003-07-27 21:37 edg * util/getfiles.c (BETA-5-4.1): Workaround for Lesstif's "frozen windows" bug (new windows opened via File->Open dialog are left without grabs). 2003-07-27 10:03 edg * source/macro.c (1.73): Another Lesstif Escape key workaround (list dialog) by Oliver Schmidt. 2003-07-25 14:12 tringali * source/preferences.c (BETA-5-4.4): Don't save undoModifiesSelection 2003-07-25 06:50 tksoh * source/file.c (1.67), util/getfiles.c (1.26), util/misc.c (1.58): make file-selection dialog modeless when linking to Lesstif, as workaround for Lesstif bug #566315 - window opened with open-file dialog ingores all input. 2003-07-24 06:07 n8gray * source/preferences.c (BETA-5-4.3): Added separator in Colors dialog and changed buttons so they resize as expected. 2003-07-24 00:21 tringali * source/nc.c (BETA-5-4.1): update version to 5.4 2003-07-18 15:14 edg * source/macro.c (1.72), source/shell.c (1.26), util/DialogF.c (1.28): Applied SF patch #771878: Escape cancels all dialogs. 2003-07-17 11:24 edg * source/search.c (1.60): Minor Lesstif keyboard focus problem workaround (Oliver Schmidt). 2003-07-11 10:39 edg * source/highlightData.c (tags: BETA-5-4-RC1) (BETA-5-4.1): Thorsten's latest revision of the NEdit Macro patterns (I'm only acting as an SF proxy). 2003-07-10 18:21 n8gray * util/check_lin_tif.c (tags: BETA-5-4-RC1) (BETA-5-4.5): Added OM 2.2.3 and LT 0.93.44 to known-bad versions. 2003-06-27 19:55 n8gray * util/check_lin_tif.c (BETA-5-4.4): Removed the Motif 1.2 vs Motif 2.1 detection in lesstif. Also changed message that gets printed when non-lesstif motif is detected to include possibility of OSF Motif. 2003-06-27 17:49 tringali * source/nedit.c (tags: BETA-5-4-RC1) (BETA-5-4.1): Stronger locale checking: handle setting of UTF8 by LC_CTYPE, LC_ALL, LANG and/or the language via the -xnllanguage switch. 2003-06-27 07:24 edg * util/misc.c (tags: BETA-5-4-RC1) (BETA-5-4.1): Crash fix for OpenMotif radio button bug workaround. 2003-06-23 19:44 n8gray * util/check_lin_tif.c (BETA-5-4.3): Adding all versions of Lesstif from 0.93.25 to 0.93.41 to known-bad list. 2003-06-23 05:30 n8gray * util/check_lin_tif.c (BETA-5-4.2): Adding Lesstif 0.93.{36,40} to the known-bad versions list. 2003-06-22 00:42 n8gray * doc/help.etx, source/help_data.h, source/help_topic.h (BETA-5-4.[1,3,2]) (utags: BETA-5-4-RC1): Put my name in the Written By credits. 2003-06-21 03:02 tringali * README, ReleaseNotes (BETA-5-4.[3,3]) (utags: BETA-5-4-RC1): Closed out a pile of bugs. 2003-06-20 21:43 slobasso * source/: menu.c, search.c, search.h (BETA-5-4.[1,1,1]) (utags: BETA-5-4-RC1): fixed bug introduced when patch #734202 was merged 2003-06-18 09:54 edg * source/: rangeset.c, textBuf.c, textBuf.h (BETA-5-4.[1,1,1]) (utags: BETA-5-4-RC1): Fix for rangeset display update bug. 2003-06-16 09:38 edg * Makefile (tags: BETA-5-4-RC1) (BETA-5-4.3): Renegerating nedit.doc and nedit.html was a bad idea. Better put them in the source tarball. 2003-06-16 09:12 edg * README, ReleaseNotes, source/help_data.h (BETA-5-4.[2,2,2]): 5.4beta -> 5.4BETA 2003-06-16 08:57 edg * Makefile (BETA-5-4.2): Make sure that nedit.doc and nedit.html are up-to-date for the dist-bin target. 2003-06-16 08:56 edg * source/preferences.c (tags: BETA-5-4-RC1) (BETA-5-4.2): Made the 5.4 preference migration conditional. 2003-06-16 08:38 edg * README, ReleaseNotes (BETA-5-4.[1,1]): Updated time stamps. 2003-06-16 08:38 edg * source/: help_data.h, help_topic.h (BETA-5-4.[1,1]): Regenerated to get proper time stamps and 5.4beta label. 2003-06-16 08:36 edg * Makefile (BETA-5-4.1): Make the build stop when the verify_config test fails. 2003-06-16 08:35 edg * util/check_lin_tif.c (BETA-5-4.1): Warning fixes. 2003-06-12 17:35 edg * makefiles/Makefile.macosx (tags: BETA-5-4-RC1) (BETA-5-4.1): Added an alternative set of CFLAGS and LIBS for building with Fink (disabled by default) and added the check_tif rule (Joerg). 2003-06-11 02:45 tksoh * source/preferences.c (BETA-5-4.1): fixed title in Save Preferences dialog. 2003-06-08 21:05 edg * ChangeLog (1.34, BETA-5-4-RC1): Regenerated (cvs2cl.pl -b -r -t --accum --gmt). 2003-06-06 18:04 edg * source/: rangeset.c (1.7), textBuf.c (1.28): Fixed a rangeset implementation flaw that caused all kinds of memory leaks in different places. Buffers should not have rangeset modification callbacks when there are no rangesets attached. 2003-06-06 17:13 edg * util/misc.c (1.57): Window group hints leak fixes. 2003-06-06 17:07 edg * source/nedit.c (1.49): Use proper resource class name to avoid uninitialized memory read. 2003-06-06 17:06 edg * util/misc.h (1.19), ReleaseNotes (1.22), source/search.c (1.59), util/misc.c (1.56): Workaround for OpenMotif radio button bug (SF #678198). (Tested with 6 different Motif flavours/versions). 2003-06-05 22:01 n8gray * doc/help.etx (1.49), source/help_data.h (1.47), source/help_topic.h (1.40), source/macro.c (1.71): Changed calltip() so that "tipKey", "tagKey", and "tipText" are position-independent optional arguments. . WARNING: This WILL break any existing calltip calls with more than one argument!!! A call like calltip(foo, "tipText", pos, bar, ...) needs to be changed to calltip(foo, pos, "tipText", bar, ...) and calltip(foo, "tipText") needs to be changed to calltip(foo, -1, "tipText"). 2003-06-04 15:34 slobasso * source/: preferences.c (1.98), window.c (1.84): remove unused variables 2003-06-02 15:18 edg * source/menu.c (1.79): Fixed wrong title in Exit dialog. 2003-05-29 21:07 tringali * util/fontsel.h (1.9): Match function declaration to definition 2003-05-28 08:26 edg * source/preferences.c (1.97): Added an automatic upgrade routine for the changed "wc" shell command. 2003-05-27 22:32 yooden * source/preferences.c (1.96): Replaces csh-specific scriptlet with awklet. 2003-05-27 21:31 tringali * source/window.c (1.83): Propogate colors to new windows on opening (744294) 2003-05-27 15:55 edg * source/preferences.c (1.95): Automatically add Identifier2 text drawing style when upgrading to 5.4. 2003-05-26 09:10 edg * ChangeLog (1.33): Regenerated (cvs2cl.pl -b -r -t --accum --gmt). 2003-05-26 09:07 edg * ReleaseNotes (1.21): Added bugs #559902, 561659, 526981, and 582469. 2003-05-26 08:16 edg * source/search.c (1.58): Committed SF patch #559902: Show Matching Range Bugfix (Tom Heathcote). 2003-05-25 15:55 edg * doc/help.etx (1.48), source/help_data.h (1.46), source/help_topic.h (1.39), source/highlightData.c (1.52), source/macro.c (1.70), source/menu.c (1.78), source/preferences.c (1.94), source/preferences.h (1.35): Removed and disabled some of the backlighting functionality and marked it as being experimental (for the 5.4 release). 2003-05-24 19:15 tringali * source/: menu.c (1.77), nedit.h (1.39), preferences.c (1.93), preferences.h (1.34), window.c (1.82): Simplified the color dialog box so that all colors are global. Plug some leaks when parsing color names. Table-drive color settings to reduce duplicate code. 2003-05-24 18:36 tringali * util/check_lin_tif.c (1.5): Allow Motif 2.1.x instead of just update level 30. We've delivered NEdit with these configurations and they work fine. 2003-05-24 13:11 yooden * source/highlightData.c (1.51): Fixed missing escape in NEdit Macro highlighting pattern. 2003-05-23 14:27 tringali * source/nedit.c (1.48): Avoid a crash when trying to drag widgets (not text) in non-default visual. This appears to be a OSF Motif bug so we just disable dragging entirely. Not a great solution. 2003-05-23 10:58 edg * ReleaseNotes (1.20): Added bug #715767. 2003-05-23 07:48 edg * source/preferences.c (1.92): Removed autoload.nm from NEdit macro recognition patterns again (covered by .nm) and made the upgrade routines also work for people who already upgraded to the post-5.3 preference format. 2003-05-22 22:12 yooden * source/: preferences.c (1.91), highlightData.c (1.50): New version of NEdit Macro syntax highlighting patterns. 2003-05-22 22:00 edg * source/highlightData.c (1.49): Small update to the Python highlighting patterns (due to changed delimiters). 2003-05-22 21:56 edg * source/preferences.c (1.90): Defined a non-default set of delimiters for Python mode. Added autoload.nm to the recognition patterns for NEdit Macro mode. Added nedit.rc to the recognition patterns for X Resources mode. Added a 5.3 to 5.4 upgrade routine for the 3 changes above. 2003-05-20 05:41 n8gray * source/macro.c (1.69): Committing Tom Heathcote's minor rangeset patch. If it breaks everything blame him. :-) 2003-05-20 00:27 n8gray * Makefile (1.11), makefiles/Makefile.aix (1.7), makefiles/Makefile.bsdi (1.5), makefiles/Makefile.ccur (1.5), makefiles/Makefile.convex (1.5), makefiles/Makefile.cygwin (1.7), makefiles/Makefile.dcosx (1.5), makefiles/Makefile.dec (1.6), makefiles/Makefile.depend (1.5), makefiles/Makefile.freebsd (1.5), makefiles/Makefile.generic (1.10), makefiles/Makefile.hpux (1.5), makefiles/Makefile.linux (1.11), makefiles/Makefile.lynx (1.6), makefiles/Makefile.m88k.svr4 (1.5), makefiles/Makefile.macosx (1.4), makefiles/Makefile.netbsd (1.5), makefiles/Makefile.openbsd (1.3), makefiles/Makefile.os2 (1.14), makefiles/Makefile.osf (1.6), makefiles/Makefile.qnx (1.3), makefiles/Makefile.reliant (1.5), makefiles/Makefile.sco (1.6), makefiles/Makefile.sgi (1.5), makefiles/Makefile.solaris (1.9), makefiles/Makefile.sunos (1.5), makefiles/Makefile.superux (1.5), makefiles/Makefile.uhc (1.5), makefiles/Makefile.ultrix (1.5), makefiles/Makefile.unicos (1.7), makefiles/Makefile.unixware (1.6), util/Makefile.common (1.8), util/check_lin_tif.c (1.4): Added verify_config target to all Makefiles. On most platforms it does nothing, but on Linux it triggers a check of the *tif version. This should also probably be enabled on openbsd, freebsd, and any other platform where OpenMotif/Lesstif use is common, but I'll leave that to people more familiar with those platforms. 2003-05-19 21:55 slobasso * source/highlightData.c (1.48): Adjusted Nedit Macro Language highlighting: removed delete from actions and added to keywords and added the following items Variables: calltip_ID Macro Routines: calltip, kill_calltip Actions: focus_pane, unload_tags_file, goto_matching, select_to_matching, set_auto_indent, set_em_tab_dist, set_fonts, set_highlight_syntax, set_incremental_backup, set_incremental_search_line, set_locked, set_make_backup_copy, set_overtype_mode, set_show_line_numbers, set_show_matching, set_match_syntax_based, set_statistics_line, set_tab_dist, set_use_tabs, set_wrap_margin, set_wrap_text 2003-05-19 08:03 edg * doc/help.etx (1.47), source/help_data.h (1.45), source/help_topic.h (1.38): Added missing replace_all() documentation (Tom Heathcote) and removed the "experimental" classification for smart indent. 2003-05-18 20:05 edg * source/: nedit.c (1.47), nedit.h (1.38): Workaround for KDE's FONTLIST bug (and for the various BACKGROUND and FOREGROUND resource values). 2003-05-16 17:15 n8gray * util/check_lin_tif.c (1.3): Added 92.32 to known-good LessTif. Feel free to do this yourselves! :-) It's pretty easy to do. 2003-05-16 16:58 edg * source/highlightData.c (1.47): Updated Python patterns (no updated delimiters yet). 2003-05-16 16:51 slobasso * util/.cvsignore (1.2): added check_lin_tif 2003-05-16 16:50 slobasso * source/nedit.c (1.46): removed unused variable warning 2003-05-16 16:47 slobasso * source/: text.c (1.43), text.h (1.17), textDisp.c (1.53), textDisp.h (1.23): re-commit graphics expose code and added window obscurred hack back in that was erroneously removed. This should put us back where we were without reintroducing a bug that was fixed. 2003-05-16 15:11 tringali * source/: text.c (1.42), text.h (1.16), textDisp.c (1.52), textDisp.h (1.22): Removed explicit handling of GraphicsExpose events that was causing incomplete redraws, reverting to older algorithm. (I've extracted the code into a patch and will post it back on SF to address the problem it was trying to fix.) 2003-05-16 13:47 tringali * util/misc.c (1.55): Fix for missing icons (via C. Rasmussen) 2003-05-16 05:23 tksoh * source/window.c (1.81): Fix for SF bug #715767: remaining panes resized incorrectly after closing a splitpane. 2003-05-15 19:47 n8gray * util/check_lin_tif.c (1.2): Modified copyright notice to be more consistent with the rest of NEdit. 2003-05-15 19:42 n8gray * Makefile (1.10), makefiles/Makefile.linux (1.10), source/Makefile.common (1.15), source/help.c (1.95), util/Makefile.common (1.7), util/check_lin_tif.c (1.1): Added code to detect the version of Motif/Lesstif being built against and complain if it's known-bad or unknown. There's probably room for improvement in both the build and detection portions of this code. 2003-05-15 07:36 edg * ChangeLog (1.32): Regenerated (please only update with cvs2cl.pl -b -r -t --accum --gmt). 2003-05-15 07:33 edg * source/parse_noyacc.c (1.7): Copied the recent modifications of parse.y. 2003-05-14 19:12 n8gray * ChangeLog (1.31): Isn't there a way to generate or update this automatically with CVS? 2003-05-14 19:08 n8gray * source/parse.y (1.26): Comments don't eat backslash-escaped newlines, so this is legal: t_print("Hello " # This is a common greeting \ "world" # This is the recipient of the greeting \ "\n") # This is a newline character 2003-05-04 23:54 yooden * source/macro.c (1.67): Removed some second level leftovers from the old Highlighting API. 2003-05-04 13:20 yooden * doc/help.etx (1.46), source/file.c (1.64), source/help_data.h (1.43), source/help_topic.h (1.36), source/menu.c (1.75): Fixes SF #617840: Append Line Feed on Save The buffer now reflects that a line is added on save. 2003-05-03 22:45 yooden * doc/help.etx (1.45), source/help_data.h (1.42), source/help_topic.h (1.35), source/macro.c (1.66): Removes old Highlighting Information API; fixes some inconsistencies in the Highlighting Information API; adds deprecated section to macro section in online help. 2003-05-03 09:15 edg * util/misc.c (1.54): Made translation table for mouse wheel static, as suggested by Scott. 2003-05-02 19:19 edg * source/highlightData.c (1.45), source/nedit.c (1.45), source/search.c (1.56), source/shell.c (1.25), source/smartIndent.c (1.26), source/userCmds.c (1.32), util/fontsel.c (1.25), util/getfiles.c (1.25), util/managedList.c (1.12), util/misc.c (1.53), util/misc.h (1.18): Committed SF #715941: File dialog wheel support (generalized to all scrolled widgets, except main text area, which already had support). 2003-05-02 18:25 edg * source/rangeset_fn.h (1.4): Obsolete due to new rangeset API. 2003-05-02 18:18 edg * doc/help.etx (1.44), makefiles/Makefile.depend (1.4), source/Makefile.dependencies (1.21), source/help_data.h (1.41), source/help_topic.h (1.34), source/highlightData.c (1.44), source/macro.c (1.65), source/rangeset.c (1.4), source/rangeset.h (1.2), source/rangeset_fn.h (1.3), source/textBuf.c (1.27), source/textBuf.h (1.14), source/textDisp.c (1.50), util/Makefile.dependencies (1.7): Committed patch #628933: New rangeset API. (Including the fix of SF #728988: rangeset_add of empty range works - bad!) Users of range sets will have to update their macros. 2003-04-24 17:20 edg * source/menu.c (1.74): Crash fix: setting NEDIT_HOME to /dev/null caused a coredump because the PrevOpen array never got initialized in that case. 2003-04-24 11:47 edg * source/nedit.c (1.44), util/DialogF.c (1.27), util/DialogF.h (1.9), util/fileUtils.c (1.30): Various fixes related to SF #488412: doOpen() flaws. 2003-04-24 08:57 edg * source/highlightData.c (1.43): Updated LaTeX highlight patterns provided by Joerg (SF #607072: Syntax highlight failure in LaTeX). 2003-04-24 08:26 edg * source/menu.c (1.73): Fix for SF #726325: goto_line_number only accepts 1 arg 2003-04-18 01:07 n8gray * source/calltips.c (1.5), source/calltips.h (1.2), source/help_data.h (1.40), source/help_topic.h (1.33), source/text.c (1.40), source/text.h (1.15), source/textDisp.c (1.49), source/textDisp.h (1.21), source/textP.h (1.8), doc/help.etx (1.43): Setting "nedit*background: blue" should not change the background of calltips. This change makes calltips get their colors from nedit*calltipForeground and nedit*calltipBackground. 2003-04-17 21:46 n8gray * source/: nedit.c (1.43), nedit.h (1.37), preferences.c (1.88), text.c (1.39): Applied color migration patch. IMPORTANT: Remember to move the call to migrateColorResources into the "convert to 5.4" area before releasing 5.4!!! 2003-04-17 09:03 edg * source/: macro.c (1.64), smartIndent.c (1.25): Fix for SF #602336: Wrong Initialization Order and SF #628552: Startup sequence. Macro file is now loaded before smart indent macros are processed. 2003-04-15 23:03 yooden * source/help.c (1.92): Whitespace only. 2003-04-15 20:00 yooden * doc/help.etx (1.42), source/help_data.h (1.39), source/help_topic.h (1.32): Small documentation fixes. 2003-04-10 20:28 edg * source/calltips.c (1.4), util/misc.c (1.52), util/misc.h (1.17): Fix for SF #602260: Calltips crashes. Calltip popup shells now inherit the proper visual and color depth. 2003-04-10 20:08 tringali * source/help.c (1.91): Help text was allocating colors incorrectly, making help text invisible when running with a non-default Visual. Don't assume "black" is help text color! 2003-04-10 18:47 tringali * source/: text.c (1.38), text.h (1.14), textP.h (1.7), window.c (1.80): Fix upside-down GetPrefTypingHidesPointer dependency -- the window code should be setting into the text widget, instead of the text widget getting it directly from preferences. 2003-04-10 18:39 tringali * source/parse.y (1.24): #include to avoid warnings on some systems about no malloc proto. 2003-04-10 18:37 tringali * util/utils.c (1.20): Don't quit if getpwuid() fails. It can fail if some nameservices are not responding through no fault of the user. 2003-04-10 17:58 edg * source/Makefile.dependencies (1.20): Updated dependencies. 2003-04-10 17:37 edg * util/DialogF.c (1.26): Warning fix. 2003-04-10 09:39 edg * source/file.c (1.63): Added some missing fclose() calls in IncludeFile(). 2003-04-09 14:56 edg * source/file.c (1.62): Aaargh. Another few missing commas. 2003-04-09 14:53 edg * source/file.c (1.61): Added another few missing commas in DialogF calls. 2003-04-09 13:52 edg * source/file.c (1.60): Added missing comma in DialogF call. 2003-04-08 23:47 yooden * source/help.c (1.90): Added one missing DialogF() title. 2003-04-08 08:54 edg * source/: highlight.c (1.41), menu.c (1.72), preferences.c (1.87), smartIndent.c (1.24): Fixed indentation inconsistencies and dialog title typos. 2003-04-07 22:51 yooden * source/file.c (1.59), source/highlight.c (1.40), source/highlightData.c (1.42), source/macro.c (1.63), source/menu.c (1.71), source/preferences.c (1.86), source/search.c (1.55), source/selection.c (1.24), source/shell.c (1.24), source/shift.c (1.14), source/smartIndent.c (1.23), source/tags.c (1.49), source/userCmds.c (1.31), util/DialogF.c (1.25), util/DialogF.h (1.8), util/fileUtils.c (1.29), util/fontsel.c (1.24), util/misc.c (1.51), util/printUtils.c (1.22): The Sore Hands Patch: Added dialog title to DialogF(). 2003-04-06 00:46 yooden * source/highlightData.c (1.41), source/macro.c (1.62), source/menu.c (1.70), source/preferences.c (1.85), source/smartIndent.c (1.22), source/userCmds.c (1.30), util/printUtils.c (1.21): Some changed dialog titles, error messages and general code beautification. 2003-04-03 19:05 jlous * source/file.c (1.58), source/macro.c (1.61), source/nedit.h (1.36), source/preferences.c (1.84), source/window.c (1.79), util/fileUtils.c (1.28), util/fileUtils.h (1.10), util/prefFile.c (1.19): Committing patch 621211, accepting foreign linebreaks in prefs- and macro files. 2003-04-03 15:45 edg * source/window.c (1.78): Fix for SF #713780: flickers during macro execution. (Uwe Lehnert) 2003-03-26 16:36 edg * source/textDisp.c (1.48): Reverted some of the unnecessary (and seemingly invalid) changes related to the cursor GC introduced in version 1.46. (SF #710124). 2003-03-26 10:40 edg * source/textDisp.c (1.47): Yesterday's clipping changes were not ok: the gutter between the line numbers and the text area could be filled with character fragments. Clipping ranges are now adjusted when line numbers are drawn. 2003-03-25 18:31 n8gray * source/: textDisp.c (1.46), textDisp.h (1.20): Committing edg's patch to fix usage of shared GCs. 2003-03-25 01:33 n8gray * source/textDisp.c (1.45): Fixed line number color problems. Stupid cut & paste error... 2003-03-24 23:56 yooden * source/nedit.c (1.42): Paranoid protection against pathological language settings. 2003-03-24 17:05 edg * source/: menu.c (1.69), nedit.h (1.35), window.c (1.77): Fix for SF bug #564782: Show Path in Windows Menu 2003-03-24 16:20 tringali * source/nedit.c (1.41): Account for LANG being unset. 2003-03-21 18:51 n8gray * source/: textDisp.c (1.44), window.c (1.76): Fixing 2 color problems. 1: Changing line number GC properties affected *all* buffers. 2: New panes used default text area colors instead of their window's. 2003-03-21 18:31 tringali * source/: nedit.c (1.40), help.c (1.89): Avoid crash when running under a UTF-8 locale, and display locale in help. 2003-03-21 18:22 edg * source/: preferences.c (1.83), smartIndent.c (1.21), smartIndent.h (1.6): Fix for SF bug #439867: Language mode renaming bug. 2003-03-20 13:23 edg * makefiles/Makefile.sco (1.5): Typo fix (SF #689808: SCO makefile error). 2003-03-20 13:05 edg * util/fontsel.c (1.23): Removed some unused variables (gcc warnings). 2003-03-20 13:02 edg * source/: help.c (1.88), highlight.c (1.39), highlight.h (1.10), textDisp.c (1.43): Fix for SF #700823: Nedit crash after highlight Perl-Syntax on OS/390. Made the syntax highlighting style information independent of the character coding (ASCII or EBCDIC). 2003-03-18 10:58 edg * util/managedList.c (1.11): Fix for SF #705495: Crash while Copying Pattern. 2003-03-14 22:27 n8gray * doc/help.etx (1.41), source/help_data.h (1.38), source/help_topic.h (1.31), source/preferences.c (1.82): Added a warning label to the color dialog and changed help text to make it more clear that foreground colors only apply when syntax highlighting is disabled. 2003-03-13 09:11 n8gray * util/fontsel.c (1.22): Hide the sample when the "Show Proportional Fonts" toggle is toggled and the font selection is cleared. Also added a prototype for enableSample(). 2003-03-12 18:33 n8gray * util/fontsel.c (1.21): Tabs -> Spaces If you want a shock, turn on backlighting, set tabs to a slightly off-background color, and edit just about any file in the NEdit project. 2003-03-12 18:03 n8gray * util/fontsel.c (1.20): Fixed clearing of sample field when "show proportional fonts" was toggled. Hide sample text when font selection is invalid. 2003-03-07 19:52 n8gray * source/preferences.c (1.81): Made helper function addColorGroup() static. 2003-03-07 19:46 n8gray * source/preferences.c (1.80): Using XtSetMappedWhenManaged to show/hide the error labels in the color dialog. Thanks Scott! 2003-03-07 01:50 n8gray * doc/help.etx (1.40), source/help_data.h (1.37), source/help_topic.h (1.30), source/preferences.c (1.79): Duh. Forgot to save before the last commit. Also changed docs to reflect new labels in color dialog. 2003-03-07 01:34 n8gray * source/preferences.c (1.78): Minor labelsmithing on color dialog. 2003-03-07 01:07 n8gray * source/preferences.c (1.77): Using a more reliable hack for showing/hiding the (Invalid!) labels in the color dialog. To hide it I set its fg color to its bg color. To unhide it I restore the fg color from its parent. This way the label's width doesn't change, solving the potential visual bug mentioned in my previous commit. I tried changing the label from a gadget to a widget but the XtMap/UnmapWidget functions still failed. Oh well, this works ok. 2003-03-05 23:50 n8gray * doc/help.etx (1.39), source/help_data.h (1.36), source/help_topic.h (1.29), source/menu.c (1.68), source/nedit.h (1.34), source/preferences.c (1.76), source/preferences.h (1.32), source/textDisp.c (1.42), source/textDisp.h (1.19), source/window.c (1.75), source/window.h (1.12), util/fontsel.c (1.19), util/fontsel.h (1.8): Adding the color dialog and documentation. Also adds a colored, editable text field to the font browser dialog. There's a potential minor visual bug depending on the user's fonts. I've tried to fix it but can't seem to figure it out. Search for XXX in preferences.c for details. 2003-02-20 17:30 arnef * source/: file.c (1.57), nc.c (1.33), server.c (1.21): Fixed problem with processing of nc command line. 2003-02-18 20:17 tringali * util/misc.c (1.50): Set group hint so that recent versions of Sawfish will group windows together. 2003-02-17 01:51 n8gray * source/Makefile.common (1.14): Added parse.c target so that build falls back to parse_noyacc.c if neither bison nor yacc can be found. See: http://www.nedit.org/archives/develop/2002-Apr/0512.html for a discussion of this issue. 2003-02-15 02:33 yooden * source/file.c (1.56), util/getfiles.c (1.24), util/misc.c (1.49), util/getfiles.h (1.6): Removed GetNewFilename() 2003-02-15 01:06 yooden * source/preferences.h (1.31): Removed double function declarations. 2003-01-14 22:36 n8gray * source/tags.c (1.48): Added a private lineEmpty function for use when loading calltips files. Also fixed bug where calltip position modifiers weren't reset when tips were posted by means other than the calltip macro subroutine. 2003-01-14 09:50 edg * source/regularExp.c (1.21): Fix for \S, \W, \L, and \D erroneously matching on \0. 2003-01-10 15:33 tringali * source/: window.c (1.74), nedit.c (1.39), text.c (1.37): Apply the "frame around text area" patch and associated geometry fixes. Looks right when the background is light-colored (default), less so if you use a dark background. Can be disabled with resources if you don't like it. 2003-01-10 15:32 tringali * source/file.c (1.55): Fix to prevent file dialog from growing wider than the screen. This is needed for window managers that do not respect XmNmaxWidth (sawfish, twm, fvwm). 2003-01-10 15:29 tringali * util/: getfiles.c (1.23), misc.c (1.48): Prevent the file dialog from getting bigger than screen. This fix is for window managers that do not respect XmNmaxWidth (sawfish, twm, fvwm). 2003-01-07 22:37 tringali * doc/: nedit.doc (1.37), nedit.html (1.31): Remove autogenerated files from CVS to reduce conflicts. They are now automatically generated by the cron script for the website snapshot. 2003-01-06 15:36 edg * source/smartIndent.c (1.20): Bug fix: garbage collection could be triggered during smart indent newline macro (very old copy & paste error). 2003-01-02 02:02 yooden * doc/nedit.doc (1.36), doc/nedit.html (1.30), source/help_data.h (1.35), source/help_topic.h (1.28): Updated reference to regex book part two. 2003-01-02 01:48 yooden * doc/help.etx (1.38): Updated Reference to Regex book. 2003-01-01 15:57 edg * source/smartIndent.c (1.19): Fix for crash bug reported @develop: newline macro inserting a string caused a recursive loop when triggered through smart indent. 2002-12-13 17:23 edg * doc/Makefile (1.4): Added targets to regenerate the FAQ and build the FAQ distribution. 2002-12-13 17:20 edg * doc/: faq.txt (1.4), faq.xml (1.5): Added a Q&A about the changed binding of KP Enter (execute command line). 2002-12-12 17:26 slobasso * source/text.h (1.13): Remove warnings on hpux 10.20 compiler. 2002-12-12 17:26 slobasso * source/selection.c (1.23): Cleanup string to int conversion. 2002-12-12 17:26 slobasso * source/: search.c (1.54), search.h (1.18): Centralize string to enum conversions for search_type. 2002-12-12 17:26 slobasso * source/parse_noyacc.c (1.5): Match changes in parse.y 2002-12-12 17:25 slobasso * source/parse.y (1.23): Move string constant code into function InstallStringConstSymbol. 2002-12-12 17:25 slobasso * source/nedit.h (1.33): New macro TYPE_INT_STR_SIZE to determine a safe string size for integer-like types. 2002-12-12 17:25 slobasso * source/macro.c (1.60): More macro failure macros and new macro call valid_number. Use of new macro TYPE_INT_STR_SIZE and PERM_ALLOC_STR. Add optional index to rangeset_defined. 2002-12-12 17:25 slobasso * source/interpret.h (1.12): New macro PERM_ALLOC_STR for static strings that look allocated and move StringToNum global for verification code. New call InstallStringConstSymbol and move DataValue.tag to an enum. 2002-12-12 17:25 slobasso * source/interpret.c (1.32): Use of new macro PERM_ALLOC_STR for static strings that look allocated and move StringToNum global for verification code. New call InstallStringConstSymbol cleanup of macro debug code with new stack dump. Rewrite SwapCode without allocations. Use of TYPE_INT_STR_SIZE for int string size. Fixes to grabage collection to allow for PERM_ALLOC_STR and catch mod by 0 errors. 2002-12-12 17:25 slobasso * source/highlightData.c (1.40): New nedit macro call valid_number. 2002-12-12 17:25 slobasso * doc/help.etx (1.37), doc/nedit.doc (1.35), doc/nedit.html (1.29), source/help_data.h (1.34): Add optional index to rangeset_defined and new function valid_number. 2002-12-11 18:24 tringali * util/misc.c (1.47): Avoid a 5-second hang when posting a dialog with certain window managers (Sawfish) 2002-12-10 13:16 edg * source/nc.c (1.32): Dropped support for reading preferences from a .nc file. It was entirely undocumented and probably never used by anyone (and it didn't work anymore since the introduction of the NEDIT_HOME patch). 2002-12-10 12:29 edg * source/nc.c (1.31): Fixed a bug in yesterday's bug fix: macro commands could be executed twice when a new server was started. 2002-12-09 17:55 edg * source/nedit.c (1.38): Fix for SF #649442: Dangerous shell command. Changed the shortcut for "Execute Command Line" from "KP Enter" to "Ctrl+KP Enter" to avoid accidental execution of arbitrary commands. 2002-12-09 17:18 edg * source/nc.c (1.30): Fixed various command line argument passing bugs introduced by the nc -wait patch (-icon, -geometry, -lm, ... were dropped when a new file was opened and/or a new server was started). 2002-12-08 09:29 yooden * source/: highlight.c (1.38), highlightData.c (1.39), macro.c (1.59), rangeset.c (1.3), search.c (1.53): Some code cleanup and removal of development artefacts. 2002-12-04 12:30 edg * source/macro.c (1.58): Added boundary checks to searchStringMS() to avoid illegal memory accesses when passing a too large or negative starting position to the search_string() macro. 2002-12-02 15:59 tringali * Makefile (1.9): Removed "doc" from default target so users without Perl can build. (We need a "developer only" target or mode to do this right.) 2002-11-28 23:22 yooden * source/macro.c (1.57), source/menu.c (1.67), source/preferences.c (1.75), util/prefFile.c (1.18), util/utils.c (1.19), util/utils.h (1.11): Fixes the bug in the preference file name algorithm reported by Scott in develop@. 2002-11-22 18:18 tringali * util/misc.c (1.46): Constrain maximum size of dialogs so they aren't bigger than the screen. (Slightly modified from Eddy's original version.) 2002-11-22 17:51 edg * source/window.c (1.73): Minor improvement in the virtual key binding parsing: ignore comment lines. 2002-11-19 18:05 edg * source/: highlight.c (1.37), regularExp.c (1.20), search.c (1.52), textBuf.c (1.26), textBuf.h (1.13): Fixes for SF bugs #515120 (changed behaviour of search?) and #429110 (RegEx search bugs at end of buffer) and a cleanup of the SearchWindow function. 2002-11-15 12:21 edg * doc/setext (1.10): Minor backward compatibility fix for older Perl version (5.004). 2002-11-13 21:59 tringali * source/: help_data.h (1.33), help_topic.h (1.27): - Change help version to 5.4DEV 2002-11-13 21:58 tringali * source/: calltips.c (1.3), text.h (1.12), textDisp.c (1.41): Don't #include "textP.h" where we can get away with it. 2002-11-13 21:58 tringali * source/help.c (1.87): Clean up #ifdef of HAVE__XMVERSIONSTRING and reorder visual info 2002-11-13 21:58 tringali * source/highlightData.c (1.38): - Fix indentation, labels, and mnemonics in highlightData.c 2002-11-13 21:57 tringali * source/: nedit.c (1.37), preferences.c (1.74): - Fix defaults fonts to specify iso8859-1, for RH7.3. 2002-11-13 17:56 edg * source/: highlightData.c (1.37), regularExp.c (1.19): Implemented the more conventional word boundary semantics for regular expressions and adapted the built-in highlight patterns to the changed semantics (the latter is largely automated). 2002-11-12 10:04 ajhood * doc/help.etx (1.36), doc/nedit.doc (1.34), doc/nedit.html (1.28), source/help.c (1.86), source/help_data.h (1.32), source/help_topic.h (1.26): Document default value of nedit.backlightCharTypes Stop *backlightCharTypes in .Xdefaults etc. affecting Help 2002-11-08 20:22 edg * source/: comnedit.com (1.9), highlight.c (1.36), highlight.h (1.9), lnknedit.com (1.7), macro.c (1.56), menu.c (1.66), nedit.h (1.32), preferences.c (1.73), preferences.h (1.30), rangeset.c (1.2), rangeset_fn.h (1.2), server_common.c (1.3), text.h (1.11), textDisp.h (1.18): VMS compilation and linking fixes (Michael Smith). 2002-11-08 16:53 slobasso * source/macro.c (1.55): Removed unused variables and fixed error macro. 2002-10-31 16:08 edg * doc/help.etx (1.35), doc/nc.man (1.6), doc/nedit.doc (1.33), doc/nedit.html (1.27), source/help_data.h (1.31), source/help_topic.h (1.25), source/nc.c (1.29): Fix for invalid atom usage after time-out. Made the nc time-out configurable (-timeout command line option and nc.timeOut X resource) + documentation updates. 2002-10-30 11:44 edg * ChangeLog (1.29): Minor correction. 2002-10-30 11:42 edg * ChangeLog (1.28): Removed lots of duplicate entries and added lots of missing entries. (Apparently, a merge has gone wrong a few months ago). 2002-10-30 11:11 edg * ChangeLog (1.27): Update. 2002-10-29 15:49 edg * source/server.c (1.20): Fix for crash when sending a macro command to the server through nc, while another command is still running. New commands for a window are now rejected when it is already running a macro (beeps). 2002-10-26 00:06 yooden * util/: utils.c (1.18), utils.h (1.10): Fixes wrong declaration and documentation, adds missing Copyright line. 2002-10-16 17:28 n8gray * source/: preferences.c (1.72), preferences.h (1.29), window.c (1.72): Don't switch to PLAIN mode before closing a window just to force unloading of calltips files -- it's slow! Also fixed a potentially erroneous error message in reapplyLanguageMode. 2002-10-15 11:00 ajhood * doc/help.etx (1.34), doc/nedit.doc (1.32), doc/nedit.html (1.26), source/help_data.h (1.30), source/help_topic.h (1.24), source/highlight.c (1.35), source/highlight.h (1.8), source/highlightData.c (1.36), source/highlightData.h (1.10), source/interpret.c (1.31), source/interpret.h (1.11), source/macro.c (1.54), source/preferences.c (1.71), source/preferences.h (1.28), source/textDisp.c (1.40), source/textDisp.h (1.17): Tony's backlight/highlight and SF bug 619234 fixes 2002-10-14 18:41 n8gray * source/: text.c (1.36), textBuf.c (1.25), textBuf.h (1.12), textDisp.c (1.39), textSel.c (1.11): Committing patch for keyboard-based rectangular selection. 2002-10-13 15:53 yooden * doc/help.etx (1.33), doc/nedit.doc (1.31), doc/nedit.html (1.25), source/help_data.h (1.29), source/help_topic.h (1.23): Another tiny doc patch. (Thanks Yury) 2002-10-12 13:33 yooden * doc/help.etx (1.32), doc/nedit.doc (1.30), doc/nedit.html (1.24), source/help_data.h (1.28), source/help_topic.h (1.22): Fixes small documentation bug. 2002-10-10 22:04 slobasso * source/macro.c (1.53): fix comment typo 2002-10-07 19:39 arnef * source/nc.c (1.28): Fix for bug 619231 - nc hangs after crash/kill Generate a property change event to break a deadlock. 2002-10-07 16:19 edg * source/search.c (1.51): Fix for crash bug when search string is too long in search and replace dialogs (triggered when nedit.findReplaceUsesSelection was True and a long selection was made), reported through the discuss list. 2002-10-04 23:21 slobasso * source/: macro.c (1.52), tags.c (1.47): remove compiler warnings 2002-10-01 23:45 n8gray * doc/help.etx (1.31), doc/nedit.doc (1.29), doc/nedit.html (1.23), source/help_data.h (1.27), source/help_topic.h (1.21): Added documentation for column argument to goto_line_number and the goto line dialog. 2002-09-27 12:19 ajhood * source/preferences.c (1.70): set default value for nedit.backlightCharTypes 2002-09-26 12:37 ajhood * doc/NEdit.ad (1.3), doc/README.FAQ (1.3), doc/faq-txt-pass2.xsl (1.3), doc/faq-txt.awk (1.3), doc/faq-txt.dtd (1.3), doc/faq-txt.xsl (1.3), doc/faq.dtd (1.3), doc/faq.txt (1.3), doc/faq.xml (1.4), doc/faq.xsl (1.3), doc/help.etx (1.30), doc/nedit.doc (1.28), doc/nedit.html (1.22), doc/setext (1.9), doc/setext-info.txt (1.3), makefiles/Makefile.depend (1.3), source/Makefile.common (1.13), source/help.c (1.85), source/help_data.h (1.26), source/help_topic.h (1.20), source/highlight.c (1.34), source/highlight.h (1.7), source/highlightData.c (1.35), source/highlightData.h (1.9), source/macro.c (1.51), source/menu.c (1.65), source/nedit.h (1.31), source/parse.y (1.22), source/preferences.c (1.69), source/preferences.h (1.27), source/smartIndent.c (1.18), source/tags.c (1.46), source/text.c (1.35), source/text.h (1.10), source/textBuf.c (1.24), source/textBuf.h (1.11), source/textDisp.c (1.38), source/textDisp.h (1.16), source/textP.h (1.6), source/window.c (1.71), source/window.h (1.11), source/windowTitle.c (1.9), util/fileUtils.c (1.27), util/misc.c (1.45), util/printUtils.c (1.20): backlight/rangeset patch from Josef Maier and Tony Balinski, ported to CVS by Andy Hood. 2002-09-26 12:04 ajhood * Makefile (1.8): auto-rebuild help.doc, help.html and help_*.h If someone can explain how CVS didn't accept the previous commit tell me. 2002-09-26 11:45 ajhood * source/: rangeset.c (1.1), rangeset.h (1.1), rangeset_fn.h (1.1): New files for backlight/rangeset. 2002-09-26 10:24 ajhood * doc/Makefile (1.3): auto-rebuild help.doc, help.html and help_*.h if any of the prerequisites change 2002-09-26 10:22 ajhood * README (1.30): Add comments on -DHAVE__XMVERSIONSTRING compile option. 2002-09-26 10:01 ajhood * makefiles/: Makefile.aix (1.6), Makefile.bsdi (1.4), Makefile.ccur (1.4), Makefile.convex (1.4), Makefile.cygwin (1.5), Makefile.dcosx (1.4), Makefile.dec (1.5), Makefile.freebsd (1.4), Makefile.generic (1.9), Makefile.hpux (1.4), Makefile.linux (1.9), Makefile.lynx (1.5), Makefile.m88k.svr4 (1.4), Makefile.macosx (1.3), Makefile.netbsd (1.4), Makefile.openbsd (1.2), Makefile.os2 (1.13), Makefile.osf (1.5), Makefile.qnx (1.2), Makefile.reliant (1.4), Makefile.sco (1.4), Makefile.sgi (1.4), Makefile.solaris (1.8), Makefile.sunos (1.4), Makefile.superux (1.4), Makefile.uhc (1.4), Makefile.ultrix (1.4), Makefile.unicos (1.6), Makefile.unixware (1.5): Add comments on -DHAVE__XMVERSIONSTRING compile option. 2002-09-25 10:56 edg * doc/help.etx (1.29), source/file.c (1.54), source/help_data.h (1.25), source/help_topic.h (1.19), source/menu.c (1.64), source/nedit.h (1.30), source/preferences.c (1.68), source/preferences.h (1.26), source/textBuf.c (1.23), source/textBuf.h (1.10), source/window.c (1.70): Committed SF patch #602426: Check for real changes of ext. mod files. The additional check is on by default, and a mode message appears if comparison takes more than 1 second. 2002-09-23 12:06 edg * source/userCmds.c (1.29), util/misc.c (1.44), util/misc.h (1.16): Fix for SF #612558: Macro shortcuts still NumLock sensitive. Lock and NumLock are now ignored when entering an accelerator. 2002-09-23 11:16 edg * util/getfiles.c (1.22): Fix for SF bug #613092: Open file browsing works incorrect. Keystroke history is now reset after each list refresh. 2002-09-18 20:17 arnef * source/search.c (1.50): Fixing error in initial commit of 'nc -wait' patch. Removing a XtDispatchEvent() that shouldn't have been there. 2002-09-17 09:01 edg * source/server_common.c (1.2): Fix for SF bug #610438: Committing patch 403647 causes link fail. Replaced XGetAtomNames() by a loop using XGetAtomName(). 2002-09-13 08:28 edg * source/preferences.c (1.67): Fix for SF bug #608693: coredump with -tabs option. The tab distance is now clipped within its valid range. 2002-09-11 18:59 arnef * source/Makefile.common (1.12), source/Makefile.dependencies (1.19), source/file.c (1.53), source/macro.c (1.50), source/nc.c (1.27), source/nedit.h (1.29), source/preferences.c (1.66), source/search.c (1.49), source/selection.c (1.22), source/server.c (1.19), source/server.h (1.5), source/server_common.c (1.1), source/server_common.h (1.1), source/window.c (1.69), util/Makefile.dependencies (1.6): Committing the 'nc -wait' patch (SF #403647). 2002-09-10 12:17 ajhood * doc/nedit.doc (1.27), doc/nedit.html (1.21), source/help_data.h (1.24), source/help_topic.h (1.18): I too can forget to do commit the generated files. 2002-09-10 12:10 ajhood * doc/help.etx (1.28), source/help.c (1.84): Adds visual info to version [eg Visual: Id 0x23 TrueColor 24 bit (Default)] Allows use of _XmVersionString. Add -DHAVE__XMVERSIONSTRING compile option, and if it doesn't link, you don't have it. (This may be exported by Motif but there is no header to tell you if it is there or not.) 2002-09-06 19:21 n8gray * source/calltips.c (1.2): Changing calltip label widget name from "calltipW" back to "calltip" so that resources work as advertised. 2002-09-06 19:13 n8gray * doc/help.etx (1.27), doc/nedit.doc (1.26), doc/nedit.html (1.20), source/Makefile.common (1.11), source/Makefile.dependencies (1.18), source/calltips.c (1.1), source/calltips.h (1.1), source/help_data.h (1.23), source/help_topic.h (1.17), source/macro.c (1.49), source/tags.c (1.45), source/tags.h (1.13), source/text.c (1.34), source/textDisp.c (1.37), source/textDisp.h (1.15): New features: Positioning of calltips can be controlled more precisely using optional arguments to calltip(). These include "center", "right", "above", and "strict". Non-strict, non-anchored calltips will always show up *somewhere* on-screen even if the cursor is not on-screen. Modifications: Refactored calltip UI code into calltips.c/.h. Updated help files, makefiles, and dependencies. Cleaned up tags.c/.h somewhat. 2002-09-05 23:17 slobasso * source/: interpret.c (1.30), parse.y (1.21), parse_noyacc.c (1.4): made the following work when arrayaExpression is anything that returns an array as the result: for (x in arrayaExpression) { } 2002-09-05 23:15 slobasso * source/nedit.c (1.36): fixed Cardinal vs int compare warning. 2002-09-05 17:48 tringali * doc/help.etx (1.26), source/nedit.c (1.35), util/misc.c (1.43), util/misc.h (1.15): Acquire default colors and fonts from the environment if using the default visual. 2002-09-04 08:40 n8gray * source/: tags.c (1.44), textDisp.c (1.36): Minor cleanup of tags.c (it could use a lot more). Also improved calltips so that they try not to go off the edges of the screen. Thanks to TK, from whom I stole much code. Since he stole his tooltip code from me, the circle is complete. :^) 2002-09-04 05:58 n8gray * source/: textDisp.c (1.35), textDisp.h (1.14): Calltips should finally update on any vertical cursor movement! Plus, non- anchored calltips maintain their X positions on redrawing. Also, I found out that textD->cursorX/cursorY are *not* a reliable way to get the X/Y positions of the insertion point, so other potential calltips bugs might be fixed. This is one of those nice commits where I've removed almost as many lines as I've added. :^) 2002-09-03 01:10 n8gray * source/: file.c (1.52), nedit.h (1.28), window.c (1.68): This should fix the worst of the problems in file.c. There are still potential problems if you lose read permission on a file as you're editing it, but I wanted to commit what's done so far. 2002-09-02 23:18 n8gray * source/textDisp.c (1.34): Fixing problem where scroll-wheel-down on empty files caused erroneous scrolling. It was a problem with mixing Cardinal (unsigned) and signed values. I took the approach of casting cursorVPadding to int before using it, since it's nice to have Xt reject negative values automatically. 2002-09-02 08:55 edg * source/textDisp.c (1.33): Fix for crash bug reported through develop@: regex bug using ^.* BufCopyFromBuf() could be called with invalid paramaters in continous wrapping mode. 2002-08-31 15:14 yooden * doc/help.etx (1.25), doc/nedit.doc (1.25), doc/nedit.html (1.19), doc/setext (1.8), doc/setext-info.txt (1.2), source/help_data.h (1.22): Another help update, some setext documentation and a minor setext change. 2002-08-31 08:48 yooden * source/: help_data.h (1.21), help_topic.h (1.16): Corrected Help, second batch. 2002-08-31 08:46 yooden * doc/: help.etx (1.24), nedit.doc (1.24), nedit.html (1.18): Slight correction in help.etx. 2002-08-31 07:24 n8gray * doc/help.etx (1.23), doc/nedit.doc (1.23), doc/nedit.html (1.17), source/help_data.h (1.20), source/help_topic.h (1.15), source/text.c (1.33), source/text.h (1.9), source/textDisp.c (1.32), source/textP.h (1.5): Committing the edge-phobic cursor patch, with documentation and without tab-space mixing. (The new resource is nedit*text.cursorVPadding by the way.) 2002-08-31 00:52 slobasso * source/: interpret.c (1.29), interpret.h (1.10), parse.y (1.20): Lots of array code cleanup including fixes for the following formats: x[9][8] = 6 delete x[4][2][] ++x[4] x[3]-- x[4][5] += 7 ... and many more. Also fixed some cases in which array aliasing could occur. Arrays are supposed to have VALUE semantics. 2002-08-28 14:14 tringali * source/preferences.c (1.65): Revive upgrade message to 5.4 file format 2002-08-27 08:05 edg * source/textDisp.c (1.31): Fixes for SF #600175: Coredump when dismissing resized window Array bounds read & write fixes in calcLineStarts() when number of visible lines becomes zero (only possible in help windows). Avoid scrollbar slider size < 1 warning (which was harmless but annoying). 2002-08-27 05:39 n8gray * source/: file.c (1.51), undo.c (1.14), undo.h (1.6): Committing the file deletion notification patch. I used a specialized message for ENOACCES but used strerror output along with a suggested cause (deletion or relocation by another program) in the other cases, since there are several possible causes of stat() failure. I'm committing the patch despite the minor controversy over the message text because it's better to have some message than none at all. There is still much bogosity in file.c, including another place where stat() failure causes no warning. 2002-08-23 07:52 n8gray * source/textBuf.c (1.22): Fixed a miscalculation in overlayRectInLine that could cause extra letters to be deleted during rectangular drags over tabs. See SF bug #557225 "rect. selection drag buglet" for a description of the problem. 2002-08-23 00:52 slobasso * source/interpret.c (1.28): Fixed bug that didn't allow built in array variables to be iterated with a for loop. 2002-08-22 23:52 slobasso * source/window.c (1.67): Remove unused variables. 2002-08-22 18:43 slobasso * source/userCmds.c (1.28): Fix size calculation and escape characters in menu item names. 2002-08-22 08:40 n8gray * source/undo.c (1.13): Fixed SF bug #578551 "Scrolling to searched/altered selection" by adding MakeSelectionVisible() calls to Undo and Redo. 2002-08-22 08:10 n8gray * source/window.c (1.66): Nuking trailing whitespace from my last commit. 2002-08-22 08:05 n8gray * source/window.c (1.65): MakeSelectionVisible in window.c was not paying attention to wrapped lines. To see the problem in an older version: 1. Open a large file and scroll to the center somewhere 2. Enable continuous wrapping and resize window so lots of lines wrap 3. Select a word and make a mark with Alt+M,a 4. Page Up or Down for several screens 5. Go to the mark with Alt+G,a If there are enough wrapped lines between your position and the mark then the selection and the cursor will be completely offscreen. Also restructured the function so that horizontal scrolling is not bypassed prematurely. 2002-08-21 13:21 tringali * source/help.c (1.83): Remove duplicate widgets caused by a bum merge. 2002-08-21 07:19 n8gray * source/file.c (1.50): Fixed bug where clicking on the WM's close button in an unsaved and untitled buffer, answering yes to the "Save before closing" dialog, then aborting the Save-As dialog led to the window being closed and the changes being lost. The function CloseFileAndWindow wasn't returning FALSE when the Save-As failed. 2002-08-19 21:41 tringali * source/preferences.c (1.64): Remove "alpha" versioning - it wasn't forwards compatabile, and there were no auto-upgrades done despite the message printed. 2002-08-19 07:22 n8gray * source/textDisp.c (1.30): Calltips are now redrawn on TextDMoveUp and TextDMoveDown. This should help those who end up with cursors behind calltips when entering multi-line function calls. 2002-08-17 14:28 yooden * source/window.c (1.64): Removed unused variables. 2002-08-16 14:43 tringali * source/file.c (1.49): Fix hang caused by posting the "reload" dialog box on a hidden window (during multi-file replace validation). 2002-08-15 19:03 n8gray * source/: file.c (1.48), window.c (1.63): Fixed the flickering stats line problem (SF bugs 595106, 594838). Also fixed "save-as doesn't update the stats line" bug. 2002-08-14 19:20 n8gray * source/textDisp.c (1.29): Fixed off-by-one error in expandAllTabs. Also added check for NULL on its return value in TextDShowCalltip. 2002-08-14 08:42 n8gray * source/textDisp.c (1.28): Removed debugging cruft from TextDShowCalltip. 2002-08-13 22:12 n8gray * doc/help.etx (1.22), doc/nedit.doc (1.22), doc/nedit.html (1.16), source/help_data.h (1.19), source/help_topic.h (1.14), source/text.c (1.32), source/textDisp.c (1.27), source/textDisp.h (1.13): Added "absolute" argument to line-oriented action routines, and "wrap" argument to delete_to_start_of_line. 2002-08-12 21:21 tringali * source/tags.c (1.43), source/window.c (1.62), source/window.h (1.10), util/misc.c (1.42), util/misc.h (1.14): Post watch cursor keep screen drawn while loading large tags files. 2002-08-12 15:37 tringali * source/window.c (1.61): Reimplement I-search button focus management, so it doesn't have an ugly flash 2002-08-10 23:59 tringali * source/undo.c (1.12): Added preference for disbling selection modification during Undo. 2002-08-10 23:58 tringali * source/text.c (1.31): - Fix bad hardware tab of 4 spaces. Please set hardware tabs to 8 for NEdit! - Explicitly remove modifiers on some virtual bindings to account for system that map different modified keys to different bindings (e.g., Ctrl-PgUp = osfPageLeft, PgUp = osfPageUp) - Use unions in favor of casts in XEvents. 2002-08-10 23:54 tringali * source/highlightData.c (1.34): Use non-capturing parenthesis in C and C++ patterns where appropriate. 2002-08-10 23:53 tringali * source/preferences.h (1.25): Added preference to disable modifying selection on Undo. 2002-08-10 23:52 tringali * source/preferences.c (1.63): Added preference to disable changing the selection to match Undo. 2002-08-10 23:51 tringali * source/server.c (1.18): Use union for XEvents instead of casts. 2002-08-10 23:48 tringali * source/: interpret.c (1.27), interpret.h (1.9), macro.c (1.48): Use unions in place of nonportable casts to avoid warnings 2002-08-10 23:45 tringali * source/help_data.h (1.18): Regenerated from help.etx update (fix X resource names) 2002-08-10 23:43 tringali * source/help.c (1.82): More detail for Motif version, and change button labels on help browser to be more like WinHelp 2002-08-09 20:48 tringali * util/system.h (1.12): Support for Lynx, MacOS; better x86 reporting 2002-08-09 14:08 tringali * doc/: help.etx (1.21), nedit.doc (1.21), nedit.html (1.15): Fix typo in last commit (replace * with @*) 2002-08-09 13:52 tringali * doc/: help.etx (1.20), nedit.doc (1.20), nedit.html (1.14): Update incorrect X resources (nedit*text.foo) and upgrade version. 2002-08-09 13:11 tringali * source/window.c (1.60): Convert // style comment to /* */, so it compiles again. NEdit is C89, not C++ or C99! 2002-08-08 21:00 n8gray * doc/help.etx (1.19), doc/nedit.doc (1.19), doc/nedit.html (1.13), source/help_data.h (1.17), source/help_topic.h (1.13), source/nedit.h (1.27), source/window.c (1.59): Fixing the "ever-growing stats line" bug seen under lesstif. Also, the stats area code is generally much nicer now, IMHO. 2002-08-02 08:36 n8gray * doc/help.etx (1.18), doc/nedit.doc (1.18), doc/nedit.html (1.12), source/help_data.h (1.16), source/help_topic.h (1.12), source/nc.c (1.26): nc.autoStart now defaults to True. I've had to explain that warning message one too many times... If anybody finds this offensive, it's easy to revert. ;^) 2002-08-01 00:53 n8gray * doc/help.etx (1.17), doc/nedit.doc (1.17), doc/nedit.html (1.11), source/help_data.h (1.15), source/help_topic.h (1.11), source/macro.c (1.47): Added optional "copy" argument to replace_in_string to make it return a copy of the input string if no replacements were done. 2002-07-31 23:34 slobasso * source/interpret.c (1.26): made comment more clear 2002-07-31 20:08 edg * source/highlight.c (1.33): Fix for yesterday's "fix" (which wasn't entirely waterproof). 2002-07-30 13:54 edg * source/highlight.c (1.32): Fix for pattern related crash reported by Joor: I've overlooked a special case in the recent speed improvements. 2002-07-29 08:05 n8gray * doc/help.etx (1.16), doc/nedit.doc (1.16), doc/nedit.html (1.10), source/help_data.h (1.14), source/help_topic.h (1.10): Minor change to the documentation for nedit.typingHidesPointer X resource. By the way, the X resources section of the documentation doesn't seem to be in any order whatsoever. Maybe it should be sorted or grouped into functional groups. 2002-07-29 03:51 n8gray * source/macro.c (1.46): Applying TK's autoflushing t_print patch (SF #552760). I'm not adding a call to isatty, but if anybody cares enough about the issue they're welcome to do it. I just want to make sure the patch isn't forgotten. 2002-07-28 19:25 edg * source/preferences.c (1.62): Introduced alpha preference file version numbering (5.4a1, 5.4a2, ...) for development versions. 2002-07-27 08:55 yooden * source/: highlightData.c (1.33), macro.c (1.45), preferences.c (1.61), preferences.h (1.24), smartIndent.c (1.17), userCmds.c (1.27): Removed obsolete function CopyAllocatedString() 2002-07-26 22:19 n8gray * source/window.c (1.58): Fixed flickering under-shadow on stats line. (Thanks to TK Soh for the fix.) Also fixed horrible tab-space mixing. 2002-07-26 21:39 n8gray * ChangeLog (1.26), doc/help.etx (1.15), doc/nedit.doc (1.15), doc/nedit.html (1.9), source/file.c (1.47), source/help_data.h (1.13), source/help_topic.h (1.9), source/macro.c (1.44), source/menu.c (1.63), source/nedit.c (1.34), source/nedit.h (1.26), source/preferences.c (1.60), source/tags.c (1.42), source/tags.h (1.12), source/text.c (1.30), source/textDisp.c (1.26), source/textDisp.h (1.12), source/window.c (1.57): This is the big one. NEdit is now calltips-enabled! :-) 2002-07-20 23:18 yooden * util/fileUtils.c (1.26): Cover different return value of readlink() for Lynx. 2002-07-20 23:15 yooden * makefiles/Makefile.lynx (1.4): Avoid annoying warnings about include files. 2002-07-20 09:37 amai * util/utils.c (1.17): Fix order of #includes 2002-07-17 20:42 slobasso * source/menu.c (1.62): Lesstif was causing problems with accelerators kicking off actions on KeyRelease events rather than KeyPress events. This should fix key accelerated Mark and Goto Mark commands. 2002-07-17 15:14 edg * source/: highlight.c (1.31), highlightData.c (1.32), regularExp.c (1.18), regularExp.h (1.10): Speed improvements in syntax highlighting and regex engines. 2002-07-16 11:39 edg * source/window.c (1.56): Inserted a cast to suppress a warning with certain compilers. 2002-07-15 14:11 edg * source/: help.c (1.81), macro.c (1.43), preferences.c (1.59), regularExp.c (1.17), regularExp.h (1.9), search.c (1.48), search.h (1.17), tags.c (1.41): Lookbehind regex fix: adding missing backward search extent information. 2002-07-12 11:44 edg * source/window.c (1.55), util/misc.c (1.41): Presumed fix for SF #550870: Nedit quietly exits unexpectedly. Missing X atoms were not created, but always used. 2002-07-11 21:18 slobasso * source/file.c (1.46), source/file.h (1.10), source/help.c (1.80), source/help.h (1.10), source/highlight.c (1.30), util/DialogF.h (1.7), util/clearcase.h (1.3), util/fileUtils.h (1.9), util/fontsel.h (1.7), util/getfiles.h (1.5), util/managedList.h (1.5), util/misc.h (1.13), util/prefFile.h (1.6), util/printUtils.h (1.7), util/system.h (1.11), util/utils.c (1.16), util/utils.h (1.9), util/vmsParam.h (1.4), util/vmsUtils.h (1.5), source/highlight.h (1.6), source/highlightData.c (1.31), source/highlightData.h (1.8), source/interpret.c (1.25), source/interpret.h (1.8), source/macro.c (1.42), source/macro.h (1.4), source/menu.c (1.61), source/menu.h (1.7), source/nc.c (1.25), source/nedit.c (1.33), source/nedit.h (1.25), source/parse.h (1.5), source/parse.y (1.19), source/parse_noyacc.c (1.3), source/preferences.c (1.58), source/preferences.h (1.23), source/rbTree.c (1.7), source/rbTree.h (1.3), source/regexConvert.c (1.8), source/regexConvert.h (1.4), source/regularExp.c (1.16), source/regularExp.h (1.8), source/search.c (1.47), source/search.h (1.16), source/selection.c (1.21), source/selection.h (1.5), source/server.c (1.17), source/server.h (1.4), source/shell.c (1.23), source/shell.h (1.5), source/shift.c (1.13), source/shift.h (1.4), source/smartIndent.c (1.16), source/smartIndent.h (1.5), source/tags.c (1.40), source/tags.h (1.11), source/text.c (1.29), source/text.h (1.8), source/textBuf.c (1.21), source/textBuf.h (1.9), source/textDisp.c (1.25), source/textDisp.h (1.11), source/textDrag.c (1.8), source/textDrag.h (1.3), source/textP.h (1.4), source/textSel.c (1.10), source/textSel.h (1.3), source/undo.c (1.11), source/undo.h (1.5), source/userCmds.c (1.26), source/userCmds.h (1.5), source/window.c (1.54), source/window.h (1.9), source/windowTitle.c (1.8), source/windowTitle.h (1.2): more header file cleanup 2002-07-09 14:15 edg * doc/help.etx (1.14), doc/nedit.doc (1.14), doc/nedit.html (1.8), source/help_data.h (1.12), source/help_topic.h (1.8), source/highlight.c (1.29), source/preferences.c (1.57), source/regularExp.c (1.15), source/regularExp.h (1.7), source/search.c (1.46): Committed SF patch #530308: look-behind regular expression matching. 2002-07-05 22:28 uid71894 * doc/help.etx (1.13), source/macro.c (1.41), source/menu.c (1.60), source/preferences.c (1.56), util/prefFile.c (1.17), util/utils.c (1.15), util/utils.h (1.8): Moves NEdit's config files in ~/.nedit/ or $NEDIT_HOME. 2002-06-29 13:56 yooden * source/preferences.c (1.55): Added some comment macros for default language modes. 2002-06-26 23:39 slobasso * util/: DialogF.c (1.24), DialogF.h (1.6), clearcase.c (1.4), clearcase.h (1.2), fileUtils.c (1.25), fileUtils.h (1.8), fontsel.c (1.18), fontsel.h (1.6), getfiles.c (1.21), getfiles.h (1.4), managedList.c (1.10), managedList.h (1.4), misc.c (1.40), misc.h (1.12), prefFile.c (1.16), prefFile.h (1.5), printUtils.c (1.19), printUtils.h (1.6), system.h (1.10), utils.c (1.14), utils.h (1.7), vmsParam.h (1.3), vmsUtils.h (1.4): make .h files include their requirements and move local .h files to top of include list. 2002-06-26 23:37 slobasso * source/: shell.c (1.22), textDisp.c (1.24): warnings cleanup 2002-06-20 21:32 slobasso * source/: text.c (1.28), text.h (1.7), textDisp.c (1.23), textDisp.h (1.10): Added code to handle graphics expose events that can result from calls to XCopyArea(). Also added code to look for these events since they can get backlogged in some circumstances. Removed hack to determine if we were obscured, since this should no longer be needed. 2002-06-10 16:56 slobasso * source/tags.c (1.39): fixed merge conflict. 2002-06-08 13:56 tringali * ChangeLog (1.25), Makefile (1.7), README (1.29), ReleaseNotes (1.16), doc/help.etx (1.12), doc/nedit.doc (1.13), doc/nedit.html (1.7), makefiles/Makefile.macosx (1.2), makefiles/Makefile.os2 (1.12), source/Makefile.dependencies (1.17), source/comnedit.com (1.8), source/file.c (1.45), source/help.c (1.79), source/help.h (1.9), source/help_data.h (1.11), source/help_topic.h (1.7), source/highlight.c (1.28), source/highlightData.c (1.30), source/highlightData.h (1.7), source/lnknedit.com (1.6), source/nc.c (1.24), source/nedit.c (1.32), source/preferences.c (1.54), source/preferences.h (1.22), source/server.c (1.16), source/shell.c (1.21), source/tags.c (1.38), source/window.c (1.53), source/windowTitle.c (1.7), util/DialogF.c (1.23), util/comutil.com (1.4), util/fileUtils.c (1.24), util/fontsel.c (1.17), util/misc.c (1.39), util/prefFile.c (1.15), util/printUtils.c (1.18), util/utils.c (1.13), util/utils.h (1.6): Merge 5.3 release branch fixes back to mainline development. 2002-06-01 15:18 tringali * Makefile (tags: REL-5-3) (BETA-5-3.3): Final changes for 5.3 2002-06-01 13:44 tringali * doc/nedit.doc, doc/nedit.html, source/help_data.h (BETA-5-3.[4,4,4]) (utags: REL-5-3): Update version to 5.3 for final release. 2002-05-16 07:53 edg * source/preferences.c (tags: REL-5-3) (BETA-5-3.5): Fix for SF #555364: 5.3RC1 preferences update not complete (provided by Markus Schwarzenberg). 2002-05-08 16:19 slobasso * source/menu.c (1.59): Removed many calls to HidePointerOnKeyedEvent() that shouldn't have been put there. 2002-05-08 15:30 slobasso * source/menu.c (1.58): verify we have an event before checking the type 2002-05-07 01:13 n8gray * source/preferences.c (1.53): nedit.typingHidesPointer resource is no longer saved in .nedit file, just like other optional X resources. (e.g. nedit.shell, nedit.tagFile, etc.) 2002-05-06 15:52 slobasso * source/menu.c (1.57): Removed a call to HidePointerOnKeyedEvent in unloadTagsFileMenuCB that caused a crash. 2002-05-03 13:36 amai * ChangeLog (tags: REL-5-3) (BETA-5-3.2): Update 2002-05-02 00:01 slobasso * source/shell.c (BETA-5-3.3): Added code to allow substituted command strings to be arbitrarily long. 2002-05-01 06:36 n8gray * source/: nedit.h (1.24), window.c (1.52): Committed separate line/col patch. Commit Haiku: Line and Col on Right Not Customizable Yet Hope There Are No Bugs 2002-04-29 17:16 slobasso * doc/.cvsignore (1.2): added .version 2002-04-29 08:39 edg * util/comutil.com (BETA-5-3.1): VMS "makefile" enhancements (Jack Patteeuw). 2002-04-29 00:35 amai * .cvsignore (1.1), doc/.cvsignore (1.1), source/.cvsignore (1.3), util/.cvsignore (1.1): Add/enhance .cvsignore .cvsignore files 2002-04-29 00:28 amai * source/window.c (1.51): Drop an unused #include 2002-04-26 16:10 slobasso * source/tags.c (1.37): Removed unused variables and double free. 2002-04-26 16:06 slobasso * source/tags.c (1.36): Cleanup FindDefinition and how globals are used. Changes were actually in previous revision, but I accidentally committed without comment. 2002-04-26 16:04 slobasso * source/tags.c (1.35): [no log message] 2002-04-24 20:40 edg * source/: comnedit.com, lnknedit.com (BETA-5-3.[1,1]): VMS compilation and linking fixes (Jack Patteeuw). 2002-04-23 19:52 edg * source/nc.c, source/preferences.c, source/window.c, source/windowTitle.c, util/fileUtils.c (BETA-5-3.[2,4,4,9,1]): Various VMS compilation & linking fixes. 5.3 now compiles and runs at least on Alpha OpenVMS V7.2-1 (confirmed by Jack Patteeuw, who also reported the problems). 2002-04-22 16:37 slobasso * source/text.c (1.27): fix compiler warning. 2002-04-22 15:24 amai * ChangeLog (1.24): Update 2002-04-22 15:22 amai * makefiles/Makefile.macosx (BETA-5-3.2): Fix line endings from "\\" to "\". Correct linking order in alternative set of flags using XFree86 with LessTif 2002-04-19 21:40 slobasso * doc/help.etx (1.11): Added new feature to hide mouse pointer while typing. 2002-04-19 16:22 slobasso * source/: help_data.h (1.10), menu.c (1.56), menu.h (1.6), preferences.c (1.52), preferences.h (1.21), text.c (1.26), text.h (1.6), textDisp.c (1.22), textDisp.h (1.9): Added new feature to hide mouse pointer while typing. 2002-04-16 17:29 edg * source/nc.c, source/server.c, source/windowTitle.c, util/utils.c, util/utils.h (BETA-5-3.[1,1,8,1,1]): Renamed GetHostName() to GetNameOfHost() to avoid linking problems on VMS (the VMS linker is case-insensitive; GetHostName() conflicts with standard gethostname()). 2002-04-15 10:46 edg * source/: file.c, preferences.c, preferences.h (BETA-5-3.[1,3,1]): Fix for linking problem on VMS: function GetPrefAlwaysCheckRelativeTagsSpecs had more than 31 characters. Replaced it by GetPrefAlwaysCheckRelTagsSpecs. 2002-04-13 20:24 edg * source/window.c (BETA-5-3.3): Minor fix: MakeSelectionVisible() did not take into account line numbers. (SF #543178: Line numbers hide CTRL-M matches). 2002-04-12 18:12 edg * doc/help.etx, doc/nedit.doc, doc/nedit.html, source/help_data.h (BETA-5-3.[1,3,3,3]): Documentation fixes (X-resource section). 2002-04-12 18:09 edg * source/help.c (BETA-5-3.7): Backed out previous change because affects default width of help windows. Will consult developers first. 2002-04-12 17:50 edg * source/help.c (BETA-5-3.6): Small fix: nedit.helpFont was ignored when determining initial size of help windows (instead, the value of the now obsolete nedit*helpText.font resource was used implicitly). 2002-04-10 09:41 edg * source/highlight.c (BETA-5-3.4): Crash fix for syntax highlighting pattern sets containing only pass-2 patterns. 2002-03-28 14:21 edg * util/printUtils.c (tags: BETA-5-3-RC1) (BETA-5-3.1): Applied patch submitted with SF bug #536168: printing to KDE print framework. 2002-03-26 22:32 amai * makefiles/Makefile.macosx (tags: BETA-5-3-RC1) (BETA-5-3.1): Add sample linker command using LessTif as posted on discuss@ 2002-03-26 13:43 edg * util/fontsel.c (tags: BETA-5-3-RC1) (BETA-5-3.1): Prevent possible crash when the Font dialog is destroyed while a modal Font Selection dialog is up. 2002-03-25 10:02 edg * source/highlight.c (tags: BETA-5-3-RC1) (BETA-5-3.3): Prevent buffer overflow in DialogF when reporting a RE compilation error for a very large RE. 2002-03-23 17:04 edg * source/shell.c (tags: BETA-5-3-RC1) (BETA-5-3.2): The line counting algorithm for shell command output dialog is still not fullproof (it would require emulating word wrapping). Now a scrollbar is created when there is a risk of underestimating the number of lines, to make sure that no line ever gets obscured. 2002-03-22 15:54 edg * source/shell.c (BETA-5-3.1): Fix for shell command output dialog obscuring final lines under certain conditions (reported at discuss list). 2002-03-21 08:41 edg * source/: window.c, tags.c (BETA-5-3.[2,2]) (utags: BETA-5-3-RC1): Got rid of strdup() call (+related comment in disabled code in tags.c). 2002-03-21 00:19 amai * source/highlightData.c (tags: BETA-5-3-RC1) (BETA-5-3.4): SF Patch [ 531549 ] TCL highlight patterns updated. 2002-03-21 00:15 amai * makefiles/Makefile.os2 (tags: BETA-5-3-RC1) (BETA-5-3.2): Correct linker flags for omf/debuggable build 2002-03-20 18:30 edg * source/highlightData.c (BETA-5-3.3): Double bug fix in X Resources pattern: context distance violation and missing escapes and continuation highlights. 2002-03-19 21:39 edg * source/help.c (tags: BETA-5-3-RC1) (BETA-5-3.5): Replaced (non-ANSI) snprintf() call by equivalent code. 2002-03-19 18:29 edg * source/windowTitle.c (tags: BETA-5-3-RC1) (BETA-5-3.7): The background color copying code for the preview didn't work with all Motif versions (it even crashed). Now copied the color from the form iso. a label. This should work also for Motif 1.2. 2002-03-19 17:42 edg * Makefile (tags: BETA-5-3-RC1) (BETA-5-3.2): Include nedit.html in binary distributions. 2002-03-19 17:39 edg * ChangeLog, doc/nedit.doc, doc/nedit.html, source/help_data.h, source/help_topic.h (BETA-5-3.[1,2,2,2,2]) (utags: BETA-5-3-RC1): Final update for 5.3RC1 (hopefully). 2002-03-19 08:51 edg * source/windowTitle.c (BETA-5-3.6): Changed the preview field's background color to make it clear that it is read-only. 2002-03-18 23:41 edg * source/highlight.c (BETA-5-3.2): Fix for SF #531577: Balance fails before text viewed. Unparsed parens are parsed with pass-2 patterns when necessary. 2002-03-18 23:15 edg * source/: help.c, nedit.c (tags: BETA-5-3-RC1) (BETA-5-3.[4,2]): Committed Markus' latest enhancements (focus related). 2002-03-17 11:21 yooden * source/windowTitle.c, util/prefFile.c (tags: BETA-5-3-RC1) (BETA-5-3.[5,1]): Makes the cursor in the Window Title Dialog's preview field invisible. 2002-03-16 20:40 edg * source/window.c (BETA-5-3.1): Changed 2 free() calls into XFree calls(). 2002-03-15 14:36 amai * source/: Makefile.dependencies (tags: BETA-5-3-RC1) (BETA-5-3.1), Makefile.dependencies (1.16): Update 2002-03-15 08:51 edg * source/: help.c, help.h (tags: BETA-5-3-RC1), nedit.c (BETA-5-3.[3,1,1]): Applied patch 526967: single window help with history (with a minor modification in the mnemonics: P for Previous iso. Print). 2002-03-14 17:41 amai * source/textDisp.c (1.21), source/textDrag.c (1.7), source/textSel.c (1.9), source/undo.c (1.10), source/userCmds.c (1.25), source/window.c (1.50), source/windowTitle.c (1.6), util/DialogF.c (1.22), util/clearcase.c (1.3), util/fileUtils.c (1.23), util/fontsel.c (1.16), util/getfiles.c (1.20), util/managedList.c (1.9), util/misc.c (1.38), util/prefFile.c (1.14), util/printUtils.c (1.17), util/utils.c (1.12): Attempt to complete last commit (add trailing optional #include) 2002-03-14 17:18 amai * source/: rbTree.c (1.6), regexConvert.c (1.7), regularExp.c (1.14), search.c (1.45), selection.c (1.20), server.c (1.15), shell.c (1.20), shift.c (1.12), smartIndent.c (1.15), tags.c (1.34), text.c (1.25), textBuf.c (1.20): Add an optional #include at the end of all #includes in each .c source file. Document that stuff in Makefile.generic 2002-03-14 17:15 amai * makefiles/Makefile.generic (1.8), source/file.c (1.44), source/help.c (1.78), source/highlight.c (1.27), source/highlightData.c (1.29), source/interpret.c (1.24), source/linkdate.c (1.3), source/macro.c (1.40), source/menu.c (1.55), source/nc.c (1.23), source/nedit.c (1.31), source/preferences.c (1.51): Add an optional #include at the end of all #includes in each .c source file. Document that stuff in Makefile.generic 2002-03-14 15:33 edg * source/windowTitle.c (BETA-5-3.4): Removed some toggle button margin height overrides that caused the mnemonic underscores to disappear with certain Motif versions. 2002-03-14 01:25 amai * source/file.c (1.43), source/help.c (1.77), source/highlight.c (1.26), source/highlightData.c (1.28), source/interpret.c (1.23), source/linkdate.c (1.2), source/macro.c (1.39), source/menu.c (1.54), source/nc.c (1.22), source/preferences.c (1.50), source/rbTree.c (1.5), source/regexConvert.c (1.6), source/regularExp.c (1.13), source/search.c (1.44), source/selection.c (1.19), source/server.c (1.14), source/shell.c (1.19), source/shift.c (1.11), source/smartIndent.c (1.14), source/tags.c (1.33), source/text.c (1.24), source/textBuf.c (1.19), source/textDisp.c (1.20), source/textDrag.c (1.6), source/textSel.c (1.8), source/undo.c (1.9), source/userCmds.c (1.24), source/window.c (1.49), source/windowTitle.c (1.5), util/DialogF.c (1.21), util/clearcase.c (1.2), util/fileUtils.c (1.22), util/fontsel.c (1.15), util/getfiles.c (1.19), util/managedList.c (1.8), util/misc.c (1.37), util/prefFile.c (1.13), util/printUtils.c (1.16), util/utils.c (1.11): Optionally #include "../config.h" anywhere at first place in all(?) .c files 2002-03-13 17:15 edg * source/help.c (BETA-5-3.2): Leak fix: style buffers were leaked when help windows were closed or dismissed. 2002-03-13 13:19 edg * source/highlightData.c (BETA-5-3.2): Minor fix in Tcl patterns: newlines are allowed in double quoted strings. 2002-03-13 12:05 edg * source/preferences.c, util/DialogF.c, util/misc.c (BETA-5-3.[2,1,1]) (utags: BETA-5-3-RC1): Various minor leak fixes. 2002-03-13 12:04 edg * source/windowTitle.c (BETA-5-3.3): Made the preview field use a variable width font to avoid obscuring it too easily. 2002-03-12 20:22 edg * source/preferences.c (BETA-5-3.1): Small leak fix in language mode detection. 2002-03-12 20:20 edg * source/: highlight.c, highlightData.c, highlightData.h (tags: BETA-5-3-RC1) (BETA-5-3.[1,1,1]): Revised syntax-based paren matching algorithm: relaxes constraints on highlight patterns. Valid matches should no longer be missed. 2002-03-12 16:59 edg * source/help.c (BETA-5-3.1): Leak fix: text was leaked when printed. 2002-03-12 16:22 edg * source/windowTitle.c (BETA-5-3.2): Removed an XmStringFree() call that was left behind (and caused a crash). 2002-03-12 16:16 amai * makefiles/Makefile.os2 (BETA-5-3.1): Reduce stack size of binaries. 2002-03-12 14:52 edg * Makefile, README (tags: BETA-5-3-RC1), ReleaseNotes (tags: BETA-5-3-RC1), doc/nedit.doc, doc/nedit.html, source/help_data.h, source/help_topic.h (BETA-5-3.[1,2,2,1,1,1,1]): Set version to 5.3RC1. 2002-03-12 09:04 edg * ReleaseNotes, source/tags.c (BETA-5-3.[1,1]): Applied patch #520941: FindDefinition function incorrectly reads the X selection even when an argument has been provided for the find_definition() action routine. 2002-03-12 00:46 amai * README (BETA-5-3.1): Small updates on LessTif info 2002-03-11 23:09 tringali * source/windowTitle.c (BETA-5-3.1): Fix UI so dialog doesn't jump around. Also prevent overflow bug in text field. 2002-03-11 22:41 amai * source/windowTitle.c (1.4): Fix compiler warning 2002-03-11 22:40 amai * README (1.28): Small updates on LessTif info 2002-03-11 22:18 edg * doc/nedit.doc (1.12), doc/nedit.html (1.6), source/help_data.h (1.9), source/help_topic.h (1.6), README (1.27), ReleaseNotes (1.15): Last update before 5.3 branch. 2002-03-11 22:05 edg * doc/help.etx (1.10, BETA-5-3-RC1), source/highlight.c (1.25), source/highlight.h (1.5, BETA-5-3-RC1), source/menu.c (1.53, BETA-5-3-RC1), source/nedit.h (1.23, BETA-5-3-RC1), source/preferences.c (1.49), source/preferences.h (1.20, BETA-5-3-RC1), source/search.c (1.43, BETA-5-3-RC1), source/window.c (1.48): Applied SF patch #513976: Syntax-based parenthesis matching. 2002-03-11 18:17 edg * ChangeLog (1.23), README (1.26), ReleaseNotes (1.14): Update for 5.3. 2002-03-08 10:40 edg * source/window.c (1.47): Fix for #527319: segfault in virtKeyBindingsAreInvalid(). 2002-03-08 08:43 edg * source/tags.c (1.32): Fix for #527222: malloc bugs in tags.c (Nathan Gray). 2002-03-07 20:49 edg * doc/nedit.doc (1.11), doc/nedit.html (1.5), source/help_data.h (1.8), source/help_topic.h (1.5): Regenerated. 2002-03-07 20:36 edg * doc/help.etx (1.9), source/windowTitle.c (1.3): Applied patch #519092: Customizable window title UI redesign 2002-03-07 17:40 edg * source/menu.c (1.52): Removed some (unnecessary) statements that could cause the X server to freeze when the background menu was popped up while any of the lock keys were on. 2002-03-07 16:42 tringali * makefiles/Makefile.linux (1.8, BETA-5-3-RC1): Add -lXp. 2002-03-06 22:04 edg * doc/help.etx (1.8), source/nedit.h (1.22), source/preferences.c (1.48), source/preferences.h (1.19), source/window.c (1.46): Added patch #525903: Workaround for invalid virtual key bindings attached to the root window: invalid bindings are detected and ignored (behavior can be controlled with a new X-resource). 2002-03-06 14:42 tringali * makefiles/Makefile.linux (1.7): Force Motif to be pulled in statically by default. Linux users tend to upgrade frequently or move binaries across systems, causing library version skew. 2002-03-04 20:10 amai * source/tags.c (1.31): Remove unused statements/code lines as pointed out on develop@ 2002-03-02 17:02 yooden * doc/help.etx (1.7), source/file.c (1.42, BETA-5-3-RC1), source/menu.c (1.51), source/nedit.h (1.21), source/preferences.c (1.47), source/preferences.h (1.18): Makes the line feed NEdit appends on save optional. (SF Bug #495009) 2002-03-01 22:44 slobasso * source/interpret.c (1.22, BETA-5-3-RC1): properly round pow() results 2002-03-01 17:13 amai * ChangeLog (1.22), README (1.25): Update timestamp and ChangeLog 2002-03-01 17:12 amai * util/fileUtils.c (1.21, BETA-5-3-RC1): Add a UNICOS-specific call to readlink() 2002-03-01 17:04 amai * util/fontsel.c (1.14): Replace rint(x) by floor(x+0.5) 2002-03-01 16:04 amai * makefiles/Makefile.unicos (1.5, BETA-5-3-RC1): Patch from Paolo Palazzi to compile on UNICOS 10.0.1.0 2002-02-27 14:44 edg * source/window.c (1.45): Setfont: fixed a bug with the window getting the wrong width when changing the font size under fvwm (or any other ICCCM2 compliant window manager). Fix provided by Dominik Vogt of fvwm. 2002-02-27 11:26 edg * source/text.c (1.23, BETA-5-3-RC1): Replaced the "None" modifiers by "~Alt ~Shift ~Ctrl ~Meta", because "None" also excludes lock keys and prevents PageUp/PageDown from responding when, for instance, the NumLock key is on (so I didn't mix up my binaries after all :-). 2002-02-25 17:28 edg * source/text.c (1.22): Reverted the last change. I've probably mixed up my NEdit binaries. 2002-02-25 14:29 edg * source/text.c (1.21): Removed the recently introduced None modifiers in default key bindings. They don't seem to be recognized by all Motif versions, causing the PageUp/PageDown keys to stop working. 2002-02-25 10:32 edg * source/textDisp.c (1.19, BETA-5-3-RC1): Fix for SF #522263: segfault fix (Nathaniel Gray). 2002-02-24 21:16 edg * source/: textBuf.c (1.18), textBuf.h (1.8) (utags: BETA-5-3-RC1): Fix for #522038: Internal error when splitting window. Allowed more than one pre-delete callback per window (I originally thought that only one was necessary). 2002-02-23 20:01 edg * source/window.c (1.44): Avoid temporarily invalid WM size hints. They seem to amplify the effects of a bug in fvwm2 (SF #496526: Very wide nedit window with fvwm). 2002-02-21 18:53 tringali * source/text.c (1.20): Fix broken PageUp and PageDown keys on systems that bind osfPageLeft to Ctrl-PageUp. 2002-02-20 13:03 amai * source/help.c (1.76): Make getBuildInfo() to return a static string. 2002-02-16 14:39 edg * source/help_data.h (1.7): Regenerated with fixed setext (fixes some style problems). 2002-02-16 14:37 edg * doc/setext (1.7, BETA-5-3-RC1): Style transition fixes by Steven Haehn. 2002-02-15 09:41 edg * doc/nedit.html (1.4), source/help_data.h (1.6), source/help_topic.h (1.4): Regenerated with fixed setext. 2002-02-15 09:37 edg * doc/setext (1.6): Applied bug fixes in help and html generation (provided by Steven Haehn). 2002-02-14 21:08 edg * source/preferences.c (1.46): Bumped .nedit file version to 5.3. 2002-02-14 21:04 edg * README (1.24): Synchronized author list with help.etx. 2002-02-14 20:24 amai * README (1.23), ReleaseNotes (1.13): Re-arrange some text 2002-02-14 14:28 tringali * source/preferences.c (1.45): Oops, helvetica fonts aren't italic, they're oblique. 2002-02-13 23:10 edg * README (1.22), ReleaseNotes (1.12): Preparation of 5.3 release. 2002-02-13 23:07 edg * source/nc.c (1.21, BETA-5-3-RC1): Preparation of 5.3 release. 2002-02-13 20:47 tringali * source/preferences.c (1.44): Change help fonts to be like the defaults we have in nedit.c to reduce the likelihood of them being missing or defective. 2002-02-13 20:00 tringali * util/misc.c (1.36): Fix for [ #478234 ] nedit crash with Xwindows on 2nd screen 2002-02-13 18:03 edg * ChangeLog (1.21): Update. 2002-02-13 14:14 edg * source/textDisp.c (1.18): Fix for SF bug #516920: line numbering in continuous wrap mode. 2002-02-13 12:30 edg * doc/nedit.doc (1.10), doc/nedit.html (1.3), source/help_data.h (1.5), source/help_topic.h (1.3): Regenerated documentation. 2002-02-13 12:27 edg * doc/setext-info.txt (1.1, BETA-5-3-RC1): Added setext format documentation provided by Steven Haehn. 2002-02-13 12:12 edg * doc/help.etx (1.6): Minor fixes. 2002-02-11 21:23 arnef * source/windowTitle.c (1.2): Fixed reason for crash when window is destroyed. Removing leading dashes and spaces Checking for array out of bounds when creating title. 2002-02-11 10:45 edg * source/highlightData.c (1.27): Upgraded X Resources highlight patterns to improve highlighting performance. SF bug #481290; patterns provided by Markus Schwarzenberg. 2002-02-08 23:26 tringali * source/nedit.c (1.30): Yet another attempted fix for 434383: menus showing up as blocks. 2002-02-07 10:23 edg * doc/help.etx (1.5): Updates for SF bug #489601: misprint in help.c. 2002-02-07 10:00 edg * doc/help.etx (1.4): Fix for SF bug #432203: Error in regex help for \l and \L. 2002-02-07 09:28 edg * doc/setext (1.5): Comment on #! interpreter line is not allowed for every shell. 2002-02-05 22:01 edg * source/highlight.c (1.24): Fix for SF bug #512961: NEdit LOCKS UP, and also for a similar bug reported at the discuss mailing list (Philippe Poilbarbe: Infinite Loop). Yet another char/unsigned char mixup problem. 2002-02-05 20:55 edg * source/regularExp.c (1.12, BETA-5-3-RC1): Fixed a char/unsigned char comparison problem that caused crashes when patterns contained characters with ASCII code >= 128. 2002-02-05 18:16 edg * source/: textBuf.c (1.17), textDisp.c (1.17), textDisp.h (1.8, BETA-5-3-RC1), window.c (1.43): Bug fix for SF bug #510631: 5.2 segmentation fault on Linux/i386. Modifying tab distance in continous wrap mode brought the text display widget in an illegal state. 2002-02-05 13:15 edg * source/highlight.c (1.23): Bugfix in color allocation (Thomas Schuetzkowski). 2002-02-03 16:41 edg * source/: textBuf.c (1.16), textBuf.h (1.7), textDisp.c (1.16), textDisp.h (1.7): Patches for SF bug #485415: Continuous wrap updating bugs. Continuous wrap mode combined with variable font sizes resulted in wrong text display calculations. 2002-02-01 15:03 edg * source/textDisp.c (1.15): Patch for SF bug #510765: Help>Version scrollbar can get corrupted. The text display widget used wrong style information for wrapping calculations when using variable width fonts. 2002-01-28 10:43 amai * ChangeLog (1.20), source/help.c (1.75), source/nedit.c (1.29), source/server.c (1.13, BETA-5-3-RC1), source/tags.c (1.30), source/textDisp.c (1.14), source/textDrag.c (1.5, BETA-5-3-RC1), source/undo.c (1.8, BETA-5-3-RC1): Add some explicit #include 2002-01-23 16:54 tringali * source/help.c (1.74): Change parenthesis style to match the rest of nedit source code. 2002-01-23 16:53 tringali * source/textSel.c (1.7, BETA-5-3-RC1): Accept COMPOUND_TEXT selection requests for compatability with recent versions of gnome-terminal. 2002-01-17 01:34 amai * makefiles/Makefile.os2 (1.11): Some small fixes/enhancements 2002-01-15 17:05 tringali * source/: menu.c (1.50), window.c (1.42): Lower case, Upper case, and Find Def do not require an NEdit selection. LC/UC can operate on the cursor, and Find Def can use an external selection. 2002-01-13 16:01 yooden * source/: menu.c (1.49), window.c (1.41): Removed four XtSetSensitive calls that prevent use of 'Open Selected' and 'Find Selection' on selections that are not NEdit's. 2002-01-12 00:59 amai * makefiles/Makefile.os2 (1.10), source/nc.c (1.20): Makefile.os2: update/correct some linker options nc.c: I think I previously messed up the commandline for EMX&VMS case. Perhaps not a good idea to mess around in code which I can't test... 2002-01-11 18:21 amai * source/nc.c (1.19): Fix for server startup command line on OS/2: missing flag for START command and fix memory leak. 2002-01-11 13:10 amai * doc/setext (1.4), source/help_data.h (1.4): Patch from Steven Haehn to add some static/const to setext output 2002-01-10 12:49 amai * source/help.c (1.73): Make some funcs/vars static 2002-01-08 16:06 amai * README (1.21): New timestamp ... (a test whether the commit messages get a different subject now) 2002-01-08 14:33 amai * ChangeLog (1.19), source/menu.c (1.48), source/nedit.h (1.20), source/window.c (1.40): Make more menu Items sensitive WRT an existing selection: Cut, Upper, Lower 2002-01-07 10:15 amai * source/tags.c (1.29): Jump to tags only referenced by line number. Fix by M. Schwarzenberg. 2002-01-05 16:52 amai * source/search.c (1.42): Only set *again menu Items on the first search ever (not on each) 2002-01-05 16:45 amai * source/: Makefile.dependencies (1.15), menu.c (1.47), nedit.h (1.19), search.c (1.41), search.h (1.15, BETA-5-3-RC1), window.c (1.39): Toggle Menu Item sensitivity, including those from SF Bug [ #486072 ] Selection commands sensitivity incorrect 2002-01-05 02:19 edel * source/: help_data.h (1.3), help_topic.h (1.2): Regenerated help_topic.h and help_data.h for change in help.ext 2002-01-05 02:09 edel * makefiles/Makefile.solaris (1.7, BETA-5-3-RC1): Reverting to 1.5 (I accidentally committed my private mods, sorry). 2002-01-05 01:48 edel * doc/help.etx (1.3), doc/setext (1.3), makefiles/Makefile.solaris (1.6), source/help.c (1.72), source/preferences.c (1.43), source/preferences.h (1.17): Help updates from Steve. Remove unused title font resources, add back some missing help text. 2002-01-04 16:39 amai * ChangeLog (1.18), source/textDisp.c (1.13): Fix ("wrong") compiler (gcc) warning about two uninitialized variables 2001-12-31 14:34 amai * source/nc.c (1.18): Fix a problem with calling nedit from nc on OS/2 which I introduced recently. Enlarge Preferences.serverCmd array. 2001-12-24 11:50 amai * source/macro.c (1.38, BETA-5-3-RC1): Fix by Gilles J. Seguin for SF Bug [ #480966 ] Composed characters in learned sequence 2001-12-24 09:46 amai * source/file.c (1.41), source/highlight.c (1.22), source/menu.c (1.46), util/getfiles.c (1.18, BETA-5-3-RC1): Fix for SF Bug [ #480960 ] No titles in some dialog boxes as sent to develop@ from T. Haude 2001-12-24 09:26 amai * ChangeLog (1.17), source/parse_noyacc.c (1.2, BETA-5-3-RC1), source/window.c (1.38): Update ChangeLog, parse_noyacc.c. Typo in window.c 2001-12-24 09:18 amai * source/: interpret.c (1.21), interpret.h (1.7, BETA-5-3-RC1), parse.y (1.18, BETA-5-3-RC1): Apply SF Patch [ #496413 ] preliminary patch for #495293 from A. Hood which in turn fixes SF Bug [ #495293 ] continue outside of loop causes segfault 2001-12-20 15:38 amai * source/: comnedit.com (1.7, BETA-5-3-RC1), parse.c_noyacc (1.8), parse_noyacc.c (1.1): Rename our fallback version of the parse.c code to have a reasonable file extension. Update VMS command file accordingly 2001-12-19 17:08 tringali * source/help.c (1.71): Fix incorrect array size that crashes on platforms where sizeof(char*) != sizeof(int) 2001-12-19 14:51 tringali * source/: window.c (1.37), nedit.c (1.28): Back out frame around text patch; doesn't work well with LessTif 2001-12-18 18:53 tringali * source/: nedit.c (1.27), window.c (1.36): Put frame around text widget, for consistent look with XmScrolledText Patch courtesy of C. Rasmussen (If you don't like it, disable it with *pane*XmFrame.shadowThickness: 0) 2001-12-17 16:28 amai * source/selection.c (1.18, BETA-5-3-RC1): Fix compilation problem 2001-12-16 04:31 ajhood * source/selection.c (1.17): Modified Files: selection.c replacing sprintf lost the path name when opening files 2001-12-14 14:35 edel * source/help_topic.h (1.1): Separated auto-generated part of help.h into different file, help_topic.h. 2001-12-14 05:14 edel * doc/: Makefile (1.2, BETA-5-3-RC1), help.etx (1.2), nedit.doc (1.9), nedit.html (1.2), setext (1.2): Rearranged styles to put fixed fonts first, for sizing help text widget. 2001-12-14 05:12 edel * source/: Makefile.dependencies (1.14), help.c (1.70), help.h (1.8), help_data.h (1.2): Rearanged help fonts so window is sized to match fixed-width formatting. Fixed underlined fonts not working. 2001-12-13 15:44 amai * source/tags.c (1.28): Drop // comments from last check-in 2001-12-13 13:31 amai * ChangeLog (1.16), source/help.h (1.7): Add prototype to help.h to fix build warning 2001-12-13 13:27 amai * source/tags.c (1.27), source/tags.h (1.10, BETA-5-3-RC1), util/fileUtils.c (1.20), util/utils.c (1.10, BETA-5-3-RC1), util/utils.h (1.5, BETA-5-3-RC1): Apply SF Patch [ #491109 ] recognize etags TAGS files added from M. Schwarzenberg 2001-12-13 13:14 amai * source/interpret.c (1.20), source/macro.c (1.37), source/menu.c (1.45), source/parse.y (1.17), source/preferences.c (1.42), source/search.c (1.40), source/selection.c (1.16), source/tags.c (1.26), source/userCmds.c (1.23, BETA-5-3-RC1), util/printUtils.c (1.15): Fix for SF Bug [ #491943 ] missing (unsigned char) casts from M. Schwarzenberg 2001-12-12 17:07 edel * source/help.c (1.69): Fixed hyperlink after search crash, search memory leak, cleaned up code, added more comments. 2001-12-10 05:11 edel * source/help_data.h (1.1): Help data generated from ../doc/help.etx 2001-12-10 05:07 edel * doc/nedit.html (1.1): Copy of html documentation generated by new help system 2001-12-10 05:03 edel * doc/: Makefile (1.1), help.etx (1.1), nedit.doc (1.8), setext (1.1): New help system! 2001-12-10 04:57 edel * source/: Makefile.dependencies (1.13), help.c (1.68), help.h (1.6), highlight.c (1.21), highlight.h (1.4), menu.c (1.44), preferences.c (1.41), preferences.h (1.16), textDisp.c (1.12): New help system! 2001-12-07 10:50 amai * source/file.c (1.40): Close file handle upon various error conditions to leave the routine w/o success. Also reject block devices in addition to directories. 2001-12-05 10:16 amai * source/: nc.c (1.17), nedit.c (1.26): nc: don't use XtWarning when report invalid commanline argument. nedit: react properly if file name on commandline is too long. Now starts up GUI. 2001-12-04 18:03 amai * ChangeLog (1.15), source/server.c (1.12), util/getfiles.c (1.17): More checks for ParseFilename()'s return value 2001-12-04 17:50 amai * source/file.c (1.39), source/menu.c (1.43), source/nc.c (1.16), source/nedit.c (1.25), source/selection.c (1.15), source/tags.c (1.25), util/DialogF.c (1.20), util/fileUtils.c (1.19): ParseFilename() often gets called w/o the caller to ensure that the arguments are proper. Let it do some checks and have an useful return value. 2001-12-04 11:14 amai * makefiles/Makefile.macosx (1.1): Add Makefile for MacOS X, as found on our website 2001-12-03 22:21 amai * source/: help.c (1.67), nedit.c (1.24): Update source timestamp and add -V to commandline help 2001-12-03 22:18 amai * source/nc.c (1.15): Resolve a mess of #ifdefs in handling commandline args. Implement -V|-version for nc 2001-12-03 16:46 tringali * source/: Makefile.common (1.10, BETA-5-3-RC1), help.c (1.66), linkdate.c (1.1, BETA-5-3-RC1): Make build date more accurate by updating on actual link, not when help.c was last compiled. 2001-12-02 17:58 edg * source/: textBuf.c (1.15), textSel.c (1.6): Applied SF patch #487945: Fix for rectangular overstrike paste. 2001-11-30 15:41 tringali * source/: nedit.c (1.23), window.c (1.35): [487153] Let user override font of statistics line 2001-11-27 22:53 edg * source/search.c (1.39): Enhancement to the (multi-file) replacement dialog: all files are first checked for changes to set correct sensitivity for the multi-file button and to generate an up-to-date list of writable files in the multi-file dialog. 2001-11-27 10:47 amai * source/: help.c (1.65), menu.c (1.42), shell.c (1.18): Patch from A. Riese SF Patch [ #434451 ] line numbers in shell commands 2001-11-27 09:09 amai * source/file.c (1.38), source/menu.c (1.41), util/prefFile.c (1.12), util/utils.c (1.9), util/utils.h (1.4): Introduce PrependHome() to create all paths of type $HOME/file without overflow. Fixes some leaks, other remain ... 2001-11-26 21:40 amai * util/: fileUtils.c (1.18), utils.c (1.8): Quit if a "safe" getpw*() call fails. GetUserName() returns a safe, cached result 2001-11-26 17:17 amai * ChangeLog (1.14), README (1.20), source/help.c (1.64), source/nc.c (1.14), source/nedit.c (1.22): Apply Patch from M. Schwarzenberg: SF Patch [ #485610 ] -- open filenames starting with a dash 2001-11-26 14:54 amai * util/fileUtils.c (1.17): Try to fix a potential memory (security?!?) leak in ExpandTile() 2001-11-26 14:17 amai * util/utils.c (1.7): Cache return value of GetHomeDir() and return a private reference. Earlier we did return a string that could be invalided before it was used!? 2001-11-25 23:03 edg * source/file.c (1.37): Crash fix: avoid closing windows twice when user destroys the window of a file that could not be opened instead of closing the error dialog. 2001-11-25 22:05 edg * source/textBuf.c (1.14): Small fix: tighter buffer boundary check when accessing characters. 2001-11-24 11:57 amai * source/file.c (1.36): Patch from Thorsten Haude for SF Bug [ #484870 ] Double Mnemonic 2001-11-24 11:41 amai * makefiles/Makefile.qnx (1.1, BETA-5-3-RC1): Add Makefile for QNX as posted on develop@ mailinglist 2001-11-22 21:01 amai * source/interpret.c (1.19), source/preferences.c (1.40), source/textBuf.c (1.13), source/textBuf.h (1.6), util/printUtils.c (1.14), util/printUtils.h (1.5, BETA-5-3-RC1): Another small const patch 2001-11-21 16:36 amai * util/misc.c (1.35): Patch SF [#483505 ] Fix warning on DEC Not literally, I extended the comment a bit. 2001-11-20 15:53 amai * README (1.19): Sorry, another "dummy" commit, to check for the commit messages :-) 2001-11-20 15:36 amai * ReleaseNotes (1.11): Switch to "5.2+" ... 2001-11-20 15:31 amai * README (1.18): Start list of 5.2+ features/changes 2001-11-20 13:25 amai * source/selection.c (1.14), util/system.h (1.9, BETA-5-3-RC1): Add Intel's icc/ecc to our list of known compilers (and fix a compiler warning) 2001-11-18 19:53 amai * ChangeLog (1.13): Update 2001-11-18 19:02 arnef * source/Makefile.common (1.9), source/Makefile.dependencies (1.12), source/help.c (1.63), source/help.h (1.5), source/menu.c (1.40), source/nc.c (1.13), source/preferences.c (1.39), source/preferences.h (1.15), source/server.c (1.11), source/window.c (1.34), source/window.h (1.8, BETA-5-3-RC1), source/windowTitle.c (1.1), source/windowTitle.h (1.1, BETA-5-3-RC1), util/Makefile.common (1.6, BETA-5-3-RC1), util/Makefile.dependencies (1.5, BETA-5-3-RC1), util/clearcase.c (1.1, BETA-5-3-RC1), util/clearcase.h (1.1, BETA-5-3-RC1), util/fileUtils.c (1.16), util/fileUtils.h (1.7, BETA-5-3-RC1), util/utils.c (1.6), util/utils.h (1.3): Added Customise Window Title patch Ref. http://sourceforge.net/tracker/?func=detail&atid=311005&aid=477875& group_id=11005 2001-11-16 16:06 tringali * util/misc.c (1.34): 482504: Bad CapsLock grab on certain keyboard configurations 2001-11-16 12:47 amai * source/userCmds.c (1.22): "const patch" 2001-11-16 11:13 amai * source/: selection.c (1.13), shift.c (1.10, BETA-5-3-RC1): Add two missing #includes 2001-11-16 11:02 amai * source/: help.c (1.62), shell.c (1.17), userCmds.c (1.21): Apply patch SF [ #434451 ] line numbers in shell commands from Axel Riese. 2001-11-16 10:06 amai * source/: help.c (1.61), menu.c (1.39), selection.c (1.12), selection.h (1.4, BETA-5-3-RC1), text.c (1.19), text.h (1.5, BETA-5-3-RC1), textDisp.c (1.11), textDisp.h (1.6): Apply patch for SF [ #403435 ] Go to column in "Goto Line Number" dialog (added some 'consts', missing #include, etc.) 2001-11-16 09:39 amai * source/: tags.c (1.24), tags.h (1.9), textBuf.c (1.12), textBuf.h (1.5), userCmds.c (1.20): Another "const patch" 2001-11-15 14:28 amai * makefiles/Makefile.openbsd (1.1, BETA-5-3-RC1): In principle the same as Makefile.netbsd, but I arbitrarily chose a Motif 2.1 setup and added -lXp already 2001-11-13 21:07 amai * makefiles/Makefile.os2 (1.9): For now we don't have/use readlink(2) on OS/2 2001-11-13 11:10 amai * source/: search.c (1.38), search.h (1.14): Add some more 'const's to public search routines 2001-11-12 14:04 amai * util/: DialogF.c (1.19), DialogF.h (1.5, BETA-5-3-RC1), misc.c (1.33), misc.h (1.11, BETA-5-3-RC1): Another small 'const patch' 2001-11-12 13:46 amai * makefiles/Makefile.generic (1.7, BETA-5-3-RC1), source/tags.c (1.23), util/fileUtils.c (1.15), util/fileUtils.h (1.6): Revised version of Patch from Markus Schwarzenberg: SF [ #479589 ] path for tags files should be resolved I added a catch for systems without links/readlink(2) 2001-11-10 00:00 slobasso * source/help.c (1.60): fixed bad eol in string 2001-11-09 23:58 slobasso * source/highlightData.c (1.26): added in to NEdit macro language keywords 2001-11-08 16:05 amai * makefiles/Makefile.generic (1.6), makefiles/Makefile.os2 (1.8), source/file.c (1.35): Drop WRITES_DOS_TEXT catch finally! 2001-11-08 13:49 amai * ChangeLog (1.12): Update 2001-11-08 13:47 amai * README (1.17), source/help.c (1.59): Add timestamp again to version info. The build date is not necessarily an indicator for the date of the underlying sources ... 2001-11-08 12:55 edg * source/search.c (1.37): Fixed a bug for replacements in rectangular selections: false matches could hide valid ones. 2001-11-07 22:54 edg * source/preferences.c (1.38): Added a patch for the last remaining issue of SF bug #230912 (Postscript language mode definition on VMS), and added a post-5.2 preferences upgrading routine, to be extended when other preferences are upgraded. 2001-11-05 15:17 tringali * source/highlightData.c (1.25): Update C/C++ preprocessor patterns with specific keywords (#include, #define, etc.) 2001-11-02 12:17 edg * source/file.c (1.34): Changed misleading "Create" button label in dialogs to "New File" (Thorsten Haude, SF bug #449765). 2001-11-02 12:13 edg * README (1.16), doc/nedit.doc (1.7), source/help.c (1.58): Minor documentation updates (Thorsten Haude). 2001-11-01 20:22 edg * util/fontsel.c (1.13): Removed a debug print statement that was left behind accidentally. 2001-10-31 17:25 edg * util/getfiles.c (1.16): Added a VMS-specific check for a Motif 2.x bug workaround (one was added earlier, but it should have been done at two places). 2001-10-31 16:36 edg * source/: nedit.c (1.21), preferences.c (1.37): Changed default font sizes from 12 pixels to 12 points. This should improve portability. 2001-10-30 21:47 tringali * source/preferences.c (1.36): Merge post-RC1 changes to mainline 2001-10-27 20:19 edg * source/: menu.c (1.38), userCmds.c (1.19): Added extra checks to prevent macro/background menu commands from being executed by the user while another command is already running (to prevent a crash). Also added beeps to notify the user in those cases that the commands are rejected. 2001-10-26 20:17 amai * makefiles/: Makefile.generic (1.5), Makefile.os2 (1.7): Document -DWRITES_DOS_TEXT - at least it's used on OS/2! 2001-10-25 15:51 tringali * source/preferences.c (tags: REL-5-2) (BETA-5-2.6): Compare file versions as integers to avoid bad float comparisonsCompare file versions as integers to avoid bad float comparisonsCompare file versions as integers to avoid bad float comparisonsCompare file versions as integers to avoid bad float comparisons 2001-10-22 08:50 amai * source/: tags.c (1.22), tags.h (1.8): Patch for SF [ #473602 ] no mult. tags selection on 1st find def from Markus Schwarzenberg 2001-10-21 15:13 tringali * README (1.15), ReleaseNotes (1.10), doc/faq-txt.awk (1.2, BETA-5-3-RC1), doc/faq-txt.dtd (1.2, BETA-5-3-RC1), doc/faq-txt.xsl (1.2, BETA-5-3-RC1), doc/faq.dtd (1.2, BETA-5-3-RC1), doc/faq.xml (1.3, BETA-5-3-RC1), doc/faq.xsl (1.2, BETA-5-3-RC1), doc/nc.man (1.5, BETA-5-3-RC1), doc/nedit.doc (1.6), doc/nedit.man (1.6, BETA-5-3-RC1), source/file.c (1.33), source/help.c (1.57), source/highlight.c (1.20), source/highlightData.c (1.24), source/nedit.c (1.20), source/preferences.c (1.35), source/search.c (1.36), source/shell.c (1.16), util/fontsel.c (1.12), util/fontsel.h (1.5, BETA-5-3-RC1), util/prefFile.c (1.11), util/system.h (1.8): Merge post-5.2RC1 changes into mainline 2001-10-21 15:09 tringali * doc/NEdit.ad (1.2, BETA-5-3-RC1), doc/README.FAQ (1.2, BETA-5-3-RC1), doc/faq-txt-pass2.xsl (1.2, BETA-5-3-RC1), doc/faq.txt (1.2, BETA-5-3-RC1), makefiles/Makefile.depend (1.2, BETA-5-3-RC1), makefiles/Makefile.linux (1.6), makefiles/Makefile.os2 (1.6), makefiles/Makefile.solaris (1.5), makefiles/Makefile.unixware (1.4, BETA-5-3-RC1): Merge post-5.2RC1 changes into mainline 2001-10-16 14:41 edg * ChangeLog (tags: REL-5-2) (BETA-5-2.6): Final update for 5.2 release. 2001-10-15 20:10 amai * source/tags.c (1.21): Latest patch for SF [ #466742 ] Tag not found 2001-10-15 17:33 slobasso * source/nc.c (1.12): Patch to allow for multi-line macros to be passed on nc command line when a nedit server is not already running. 2001-10-15 17:28 slobasso * source/: file.c (1.32), file.h (1.9, BETA-5-3-RC1), nedit.c (1.19), nedit.h (1.18), server.c (1.10): Changed -read behavior to mimic the Read Only menu option. 2001-10-15 17:24 slobasso * source/text.c (1.18): Fixes problem where triple clicking to select a word wrapped line was inconsistent with the subsequent dragging to extend the selection. The behavior now matches. 2001-10-12 19:34 tringali * Makefile, source/help.c (BETA-5-2.[1,9]) (utags: REL-5-2): Prep work for final 5.2 release 2001-10-12 11:54 edg * README (tags: REL-5-2) (BETA-5-2.5): Minor updates. 2001-10-12 10:36 edg * README, ReleaseNotes (tags: REL-5-2) (BETA-5-2.[4,2]): Updates in preparation of the 5.2 release. 2001-10-11 13:19 edg * source/preferences.c (BETA-5-2.5): Fixed a bug in the 5.2 preferences upgrading routine: new language modes were added, but the corresponding highlight patterns were not enabled. 2001-10-10 18:32 edg * source/shell.c (tags: REL-5-2) (BETA-5-2.1): Fixed a bug that could cause NEdit to crash or garble a file when the user modifies the buffer while the output of an external command is being inserted. 2001-10-08 07:29 amai * ChangeLog (BETA-5-2.5), ChangeLog (1.11): Update 2001-10-06 13:09 amai * ReleaseNotes (BETA-5-2.1): Some very minor changes towards the release 2001-10-06 11:42 amai * README, source/help.c (BETA-5-2.[3,8]): "lame attempt" to enfore a release: drop "RC" and update timestamps! 2001-10-04 11:02 amai * makefiles/Makefile.solaris (tags: REL-5-2) (BETA-5-2.2): Use CC=cc. After all it's the most - since only - standard conforming setting 2001-10-04 10:16 amai * source/tags.c (1.20): Patch for SF Bug [ #466742 ] Tag not found. This is tags-semicolon2.diff as submitted by Markus Schwarzenberg. 2001-10-04 09:44 amai * README (1.14), source/help.c (1.56): Update timestamps 2001-10-02 17:06 amai * source/help.c (BETA-5-2.7): Get PrintVersion() work again and update timestamp 2001-10-02 07:16 amai * doc/README.FAQ (1.1): file README.FAQ was initially added on branch BETA-5-2. 2001-10-02 07:16 amai * doc/faq-txt-pass2.xsl (1.1): file faq-txt-pass2.xsl was initially added on branch BETA-5-2. 2001-10-02 07:16 amai * doc/: README.FAQ, faq-txt-pass2.xsl, faq.dtd, faq.txt, faq.xml (BETA-5-2.[1,1,1,3,5]) (utags: REL-5-2): FAQ updates from Florian Xhumari (20011001) 2001-10-01 13:34 amai * source/highlightData.c (tags: REL-5-2) (BETA-5-2.1): minor pattern fix, bug 455877 2001-10-01 12:42 edg * source/preferences.c (BETA-5-2.4): Changed the order in which new 5.2 language modes were added to the list during upgrading (they are now simply appended instead of inserted). 2001-10-01 08:30 edg * util/prefFile.c (tags: REL-5-2) (BETA-5-2.1): Fixed a bug in the preferences restoration mechanism (prefFileRead is now properly set, even if already present in the resource file). 2001-09-30 19:49 edg * source/preferences.c (BETA-5-2.3): Added a 5.1 to 5.2 preferences upgrading routine (language modes and highlight styles). 2001-09-27 12:41 edg * source/file.c (tags: REL-5-2) (BETA-5-2.1): Added comment about use of tmpnam (Thorsten Haude). 2001-09-26 21:05 amai * makefiles/Makefile.unixware (tags: REL-5-2) (BETA-5-2.1): Add -lSM -lICE to libs as reported on the list as for UnixWare 7.1.1 2001-09-21 09:58 amai * source/: tags.c (1.19), tags.h (1.7): 'const' patch + fix small memory leak + protect against memory overflow in Add*TagFile 2001-09-20 19:30 tringali * doc/nedit.doc (tags: REL-5-2), source/help.c (BETA-5-2.[3,6]): - Merge slobasso 5.2 doc fixes erronously applies to mainline here 2001-09-20 14:24 tringali * source/nedit.c (tags: REL-5-2) (BETA-5-2.1): Remove "iso8859" as some servers do not have this encoding installed. 2001-09-20 11:14 amai * ChangeLog (1.10): Update 2001-09-20 11:13 amai * ChangeLog (BETA-5-2.4): Update. Remove info about recent main trunk 2001-09-19 12:11 amai * makefiles/: Makefile.linux, Makefile.os2 (BETA-5-2.[1,1]) (utags: REL-5-2): Document -lXp flag (required when linking against a Motif 2.1 compatible libXm) 2001-09-17 14:06 amai * source/file.c (1.31), source/regularExp.c (1.11), source/search.h (1.13), util/printUtils.c (1.13): Still minor cleanup. Make compiler/lint even more happy 2001-09-14 15:59 edg * source/highlight.c (tags: REL-5-2) (BETA-5-2.1): Fixes for SF bugs #459965 and #460859 (they are related), including patch #460229. 2001-09-13 14:11 tringali * source/preferences.c (BETA-5-2.2): #458807: Automatically add 5.2 styles if .nedit file is pre-5.2 2001-09-12 20:14 amai * doc/: faq-txt.awk (tags: REL-5-2), faq-txt.dtd (tags: REL-5-2), faq-txt.xsl (tags: REL-5-2), faq.txt, faq.xml, faq.xsl (tags: REL-5-2) (BETA-5-2.[1,1,1,2,4,1]): Update as sent from Florian Xhumari 2001-09-12 09:45 amai * ChangeLog (BETA-5-2.3): I forgot to update this file in this beta branch ... 2001-09-12 09:18 amai * makefiles/Makefile.depend (tags: REL-5-2) (BETA-5-2.1): Add CVS info line to output. Makes life even more simple 2001-09-11 11:24 amai * doc/faq.xml (BETA-5-2.3): Add a non-visible CVS stamp and update version/time stamp 2001-09-11 10:17 edg * source/search.c (tags: REL-5-2) (BETA-5-2.1): Fixed a minor button sensitivity bug (Multiple Files... button was grayed out after canceling multi-file replace dialog and modifying search text). 2001-09-10 15:28 amai * util/system.h (tags: REL-5-2) (BETA-5-2.2): Update/add/fix compiler info 2001-09-10 13:42 amai * source/help.c (BETA-5-2.5): Update timestamp 2001-09-10 13:41 amai * doc/faq.xml (BETA-5-2.2): Some updates WRT LessTif, mostly cosmetics. 2001-09-07 14:16 amai * doc/NEdit.ad (1.1): file NEdit.ad was initially added on branch BETA-5-2. 2001-09-07 14:16 amai * doc/NEdit.ad (tags: REL-5-2) (BETA-5-2.1): Add a 5.1 app defaults file - needs to be updated probably. This contains only outcommented entries! 2001-09-07 07:46 amai * doc/nc.man (tags: REL-5-2), doc/nedit.doc, source/help.c (BETA-5-2.[1,2,4]): Fix typos as reported on the list 2001-09-07 07:39 amai * source/help.c (BETA-5-2.3): Don't call XmRegisterConverters() for Motif 2.1, add declaration for 2.0 and add a "helpful" comment on all that 2001-09-06 09:39 amai * ChangeLog (1.9), source/help.c (1.55): ChangeLog update and a new timestamp 2001-09-06 09:37 amai * source/: Makefile.dependencies (1.11), file.c (1.30), tags.c (1.18), tags.h (1.6): Add missing #include and add some 'const'. Update dependencies 2001-09-05 11:44 amai * source/: file.c (1.29), help.c (1.54), preferences.c (1.34), preferences.h (1.14), tags.c (1.17), tags.h (1.5): Patch for SF bug [ #451997 ] bugs in tags.c/normalizePathname from Markus Schwarzenberg 2001-09-04 17:55 amai * doc/nedit.doc, source/help.c (BETA-5-2.[1,2]): Fix typo reported on the mailinglist 2001-08-31 22:16 amai * doc/: faq.txt, faq.xml (BETA-5-2.[1,1]): Update FAQ as sent from Florian Xhumari. Add plain text version of FAQ 2001-08-31 22:16 amai * doc/faq.txt (1.1): file faq.txt was initially added on branch BETA-5-2. 2001-08-30 21:04 tringali * util/system.h (BETA-5-2.1): Fix for Solaris x86 "unknown" 2001-08-30 20:19 amai * ChangeLog (BETA-5-2.2): Update 2001-08-30 20:17 amai * source/preferences.c (BETA-5-2.1): /bin/csh doesn't make sense on OS/2 - even as a default value only 2001-08-29 15:56 slobasso * source/help.c (1.53): fixed mispellings 2001-08-29 13:56 amai * source/regularExp.c (1.10): Fix lint warning: octal constants shouldn't carry a suffix like 'L'!? 2001-08-29 08:27 amai * util/: misc.c (1.32), misc.h (1.10): Second attempt to fix a specific compiler warning and a 'const' addition 2001-08-29 00:01 slobasso * source/file.c (1.28): moved braces so nedit goto matching works 2001-08-28 23:18 slobasso * doc/nedit.doc (1.5), source/help.c (1.52): documentation cleanup 2001-08-28 22:24 slobasso * source/help.c (1.51): Array documentation cleanup. 2001-08-28 11:41 amai * source/tags.c (1.16): 'const' patch 2001-08-28 11:29 amai * source/file.c (1.27), source/highlight.c (1.19), source/interpret.c (1.18), source/macro.c (1.36), source/menu.c (1.37), source/preferences.c (1.33), source/preferences.h (1.13), source/tags.c (1.15), source/text.c (1.17), util/misc.c (1.31): Fix some more lclint warnings: type casts, make some things static (no, not all unused ones, 'some'), etc. 2001-08-27 18:45 slobasso * source/macro.c (1.35): fixed static linkage of actionToString to match declaration 2001-08-27 09:08 amai * source/nc.c (1.11): startServer() changes: has a return type now; re-shuffle some code Also make another global var static and replace a printf() by puts() 2001-08-26 02:28 slobasso * source/macro.c (1.34): removed unused variable 2001-08-25 15:58 amai * source/: file.c (1.26), highlightData.c (1.23), highlightData.h (1.6), preferences.c (1.32), preferences.h (1.12), regexConvert.c (1.5, BETA-5-3-RC1), regexConvert.h (1.3, BETA-5-3-RC1), server.h (1.3, BETA-5-3-RC1), shell.c (1.15), shell.h (1.4, BETA-5-3-RC1), undo.c (1.7), undo.h (1.4, BETA-5-3-RC1): Another 'const' patch 2001-08-25 15:24 amai * source/: file.c (1.25), file.h (1.8), highlightData.c (1.22), highlightData.h (1.5), macro.c (1.33), macro.h (1.3, BETA-5-3-RC1), regularExp.c (1.9), regularExp.h (1.6, BETA-5-3-RC1), search.c (1.35), search.h (1.12): Another 'const' patch 2001-08-25 12:16 amai * util/printUtils.c (1.12): The very last signed vs. unsigned warning on my system ... 2001-08-25 12:09 amai * source/: highlightData.c (1.21), menu.c (1.36), preferences.c (1.31), regularExp.c (1.8), shell.c (1.14), userCmds.c (1.18): Fix a couple of "unsigned vs. int" compiler warnings. Using gcc on OS/2 this warning is now completly wiped out! 2001-08-25 11:55 amai * util/: DialogF.c (1.18), misc.c (1.30), prefFile.c (1.10): Fix compiler warnings. Mostly unsigned vs. signed int issues 2001-08-25 11:49 amai * README (BETA-5-2.2): A couple of fixes, enhancements (see report on mailinglist) 2001-08-24 18:34 amai * makefiles/Makefile.solaris (BETA-5-2.1): No debug build by default. Patch from Thorsten Haude 2001-08-24 08:33 amai * util/: fontsel.c, fontsel.h, misc.c (BETA-5-2.[2,2,2]) (utags: REL-5-2): Undo some changes which I erroneously checked in ... 2001-08-24 08:28 amai * ChangeLog, util/fontsel.c, util/fontsel.h, util/misc.c (BETA-5-2.[1,1,1,1]): Updated Changelog. Includes whole history, including new beta branch. New options of cvs2cl used, listing contains now revision/branch info, timestamps are in GMT, etc. 2001-08-24 08:19 amai * source/macro.c (1.32): Fix warnings, add 'const's, make func static 2001-08-23 17:57 amai * source/selection.c (1.11): Try to fix two lint/compiler warnings 2001-08-23 17:42 amai * source/search.c (1.34): Fix wrong return type in function (in a "dead" branch) 2001-08-23 14:59 amai * source/: highlightData.c (1.20), interpret.c (1.17), shift.c (1.9), smartIndent.c (1.13, BETA-5-3-RC1): Make some more functions static 2001-08-23 14:39 amai * util/: misc.c (1.29), misc.h (1.9): Drop 'wrong' prototype for standard function. Fix a function signature to avoid warnings 2001-08-23 14:11 amai * util/: fontsel.c (1.11), fontsel.h (1.4): Fix lint warning about float to integer assignment and add some more 'const's 2001-08-23 13:57 amai * util/misc.c (1.28): Drop unused #include 2001-08-22 15:41 amai * README, source/help.c (BETA-5-2.[1,1]): First updates for "RC1" 2001-08-22 15:39 amai * doc/nedit.man (tags: REL-5-2) (BETA-5-2.1): Update from Joor Loohuis. 2001-08-21 14:29 tringali * source/: userCmds.c (1.17), window.c (1.33) (utags: REL-5-2): #449569: Ensure shell/macro accelerators also have accelerator fix 2001-08-20 20:36 tringali * source/window.c (1.32): #449569: Avoid startup failure when window manager grabs the same key as an accelerator 2001-08-18 12:35 amai * source/Makefile.dependencies (1.10, REL-5-2): Update 2001-08-18 12:24 amai * source/: help.c (1.50), help.h (1.4, REL-5-2), nedit.c (1.18): Add a PrintVersion() call to nedit. Some more 'const' patches :-) 2001-08-18 11:48 jlous * README (1.13), doc/nedit.man (1.5), source/help.c (1.49): Moved Thorsten Haude credits from pattern contributor to developer. 2001-08-17 23:02 edg * README (1.12), makefiles/Makefile.aix (1.5, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.bsdi (1.3, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.ccur (1.3, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.convex (1.3, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.cygwin (1.4, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.dcosx (1.3, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.dec (1.4, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.freebsd (1.3, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.generic (1.4, REL-5-2), makefiles/Makefile.hpux (1.3, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.linux (1.5), makefiles/Makefile.lynx (1.3, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.m88k.svr4 (1.3, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.netbsd (1.3, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.os2 (1.5), makefiles/Makefile.osf (1.4, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.reliant (1.3, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.sco (1.3, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.sgi (1.3, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.solaris (1.4), makefiles/Makefile.sunos (1.3, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.superux (1.3, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.uhc (1.3, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.ultrix (1.3, BETA-5-3-RC1, REL-5-2), makefiles/Makefile.unicos (1.4, REL-5-2), makefiles/Makefile.unixware (1.3), source/help.c (1.48), source/preferences.c (1.30): Made the REPLACE_SCOPE compilation option more visible and changed the default replace scope selection preference to "Smart". 2001-08-17 21:54 edg * source/highlight.c (1.18): Added a fix for SF bug #449828. 2001-08-17 14:09 tringali * source/tags.c (1.14, REL-5-2): Fix for crash in shared tag allocation on Solaris (compiler bug?) 2001-08-17 11:01 amai * source/: window.c (1.31), window.h (1.7, REL-5-2): Another 'const' patch 2001-08-17 10:56 amai * util/: fileUtils.c (1.14), fileUtils.h (1.5) (utags: REL-5-2): Export two more interfaces. Fix for CompressPathname() to avoid multiple slashes in path. (Markus Schwarzenberg) 2001-08-16 18:33 slobasso * source/highlightData.c (1.19): Fixed NEdit macro language patterns to contain previously added items. 2001-08-16 17:24 amai * source/highlight.c (1.17): Fix for [ nedit-Bugs-435384 ] circular patterns reference hangs NEdit 2001-08-16 09:49 amai * source/highlightData.c (1.18): Patch [ #451485 ] updated Sh Ksh Bash patterns submitted from Joor Loohuis 2001-08-15 09:16 amai * source/: Makefile.dependencies (1.9), regexConvert.c (1.4, REL-5-2): Another source was missing to #include it's own header for consistency checking! 2001-08-15 09:08 amai * ChangeLog (1.8): Update (ok, not even a week has passed, but it's a nice overview ...) 2001-08-15 09:00 amai * source/preferences.h (1.11, REL-5-2), util/misc.c (1.27), util/misc.h (1.8, REL-5-2): Have unique value for MAX_ACCEL_LEN 2001-08-15 08:56 amai * source/Makefile.dependencies (1.8): Update 2001-08-15 08:56 amai * source/: userCmds.c (1.16), userCmds.h (1.4, BETA-5-3-RC1, REL-5-2): Source should include it's own headers for consistency checking. Add some const to signatures, drop an unused arg from a static interface. 2001-08-14 15:05 slobasso * source/rbTree.c (1.4, BETA-5-3-RC1, REL-5-2): fixed comment spacing 2001-08-14 14:40 slobasso * source/rbTree.c (1.3): added gnu license 2001-08-14 08:50 jlous * README (1.11): README credits updated to reflect version dialog 2001-08-14 08:37 jlous * source/file.c (1.24), source/help.c (1.47), source/highlight.c (1.16), source/highlightData.c (1.17), source/interpret.c (1.16, REL-5-2), source/macro.c (1.31, REL-5-2), source/menu.c (1.35, REL-5-2), source/nc.c (1.10, REL-5-2), source/nedit.c (1.17), source/preferences.c (1.29), source/search.c (1.33), source/selection.c (1.10, REL-5-2), source/server.c (1.9, REL-5-2), source/shell.c (1.13), source/shift.c (1.8, REL-5-2), source/smartIndent.c (1.12, REL-5-2), source/tags.c (1.13), source/text.c (1.16, REL-5-2), source/textBuf.c (1.11, REL-5-2), source/textDisp.c (1.10, REL-5-2), source/textDrag.c (1.4, REL-5-2), source/textSel.c (1.5, REL-5-2), source/undo.c (1.6, REL-5-2), source/userCmds.c (1.15), source/window.c (1.30), util/DialogF.c (1.17, REL-5-2), util/fileUtils.c (1.13), util/fontsel.c (1.10), util/getfiles.c (1.15, REL-5-2), util/managedList.c (1.7, BETA-5-3-RC1, REL-5-2), util/misc.c (1.26), util/prefFile.c (1.9), util/printUtils.c (1.11, REL-5-2), util/system.h (1.7), util/utils.c (1.5, REL-5-2), util/vmsUtils.c (1.5, BETA-5-3-RC1, REL-5-2): Fixed license statements to pure GPL 2001-08-13 13:48 tringali * doc/: nc.man (1.4), nedit.man (1.4): manpage updates from Joor. 2001-08-13 09:55 amai * doc/nedit.doc (1.4), source/help.c (1.46): Doc patch from Thorsten Haude posted on Fri Aug 10 2001 2001-08-13 09:51 amai * doc/nedit.doc (1.3), source/help.c (1.45): Patch from Thorsten Haude: Document Arrays within nedit.doc and typo fix in help.c 2001-08-12 15:45 amai * makefiles/Makefile.generic (1.3), source/comnedit.com (1.6, REL-5-2): Drop last references to NO_FCHMOD #define 2001-08-11 19:51 edg * source/search.c (1.32): Fixed SF bug #448006: three beeps; one to many. 2001-08-10 20:36 amai * source/highlightData.c (1.16): TeX pattern patch from Joerg Fischer 2001-08-10 14:35 amai * source/Makefile.dependencies (1.7): Update dependency list 2001-08-09 20:58 tringali * source/nedit.c (1.16): Fix for wrong menu font [#434383] 2001-08-09 18:47 amai * util/system.h (1.6): Correct a comment :-) 2001-08-09 18:46 amai * makefiles/Makefile.os2 (1.4): Drop -DNO_FCHMOD flag 2001-08-09 18:41 slobasso * source/Makefile.common (1.8, REL-5-2): added parse.c to cleaned files for make clean 2001-08-09 18:39 slobasso * source/userCmds.c (1.14): removed attachment possibly causing window manager loop 2001-08-09 18:03 slobasso * source/: smartIndent.c (1.11), smartIndent.h (1.4, BETA-5-3-RC1, REL-5-2), macro.c (1.30): We now keep track if we are in smart indent macros so garbage collection won't remove things from under a macro. 2001-08-09 13:34 amai * source/highlight.c (1.15), source/highlightData.c (1.15), source/interpret.c (1.15), source/search.c (1.31), source/selection.c (1.9), source/shell.c (1.12), source/smartIndent.c (1.10), source/textBuf.c (1.10), source/textSel.c (1.4), source/userCmds.c (1.13), source/window.c (1.29), util/managedList.c (1.6): Add lots of missing #include 2001-08-09 08:37 amai * source/help.c (1.44): Add hardcoded timestamp (month) again 2001-08-09 07:37 amai * source/.cvsignore (1.2, BETA-5-3-RC1, REL-5-2): Add entry 2001-08-08 22:31 slobasso * source/file.c (1.23): remove fchmod calls except when under VMS 2001-08-08 18:29 amai * makefiles/Makefile.os2 (1.3): Update from my private working copy 2001-08-08 08:39 amai * ChangeLog (1.7): Update (should be done weekly perhaps and could even be done automatically?) 2001-08-08 08:37 amai * source/parse.c_noyacc (1.7, REL-5-2): Re-generate from parse.y. BTW, yacc from Digital Unix 4.0x is being used 2001-08-08 08:34 amai * source/parse.y (1.16, REL-5-2): Add an #include (there was no error/warning; somehow we already got this probably) 2001-08-07 23:46 slobasso * source/Makefile.common (1.7): changed highlightData.c to be compiled with BIGGER_STRINGS 2001-08-07 01:53 tringali * ReleaseNotes (1.9), source/highlightData.c (1.14), source/preferences.c (1.28): #448420: Pattern updates from Joor 2001-08-07 01:12 tringali * source/nedit.c (1.15): Fix for #448402: nedit quits if unable to resolve X locale 2001-08-06 21:24 amai * README (1.10): correction to "Requirements" section 2001-08-06 21:21 amai * README (1.9): Add "Requirements for building NEdit" section 2001-08-06 20:38 tringali * doc/nedit.doc (1.2), source/help.c (1.43): Sync help with doc. (Updates from Thorsten Haude) 2001-08-04 20:49 tringali * source/file.c (1.22), source/menu.c (1.34), source/nc.c (1.9), source/nedit.c (1.14), source/server.c (1.8), source/shell.c (1.11), source/window.c (1.28), util/misc.c (1.25): Ensure exit returns a meaningful (succes/fail) status to the user 2001-08-04 20:23 tringali * util/system.h (1.5): Add info for lots more compilers. 2001-08-03 12:16 amai * ReleaseNotes (1.8): Small updates 2001-08-02 23:45 tringali * util/system.h (1.4): Add definitions for MSVC, Sun Workshop, etc. 2001-08-02 22:59 slobasso * source/macro.c (1.29): Fixed problem where error message is written if empty learned macro is executed. Also disallowed replay from executing if a macro is already in progress. This caused a crash by overflowing the interpreter stack. 2001-08-02 22:54 slobasso * source/file.c (1.21): added symlink security patch and added mode parameter to open calls with O_CREAT 2001-08-02 17:26 amai * source/interpret.c (1.14): Avoid crash when calling "self_insert()" from macro menu: fill in missing entries from our fakes key event 2001-08-01 07:41 amai * ChangeLog (1.6): Update 2001-08-01 07:40 amai * source/help.c (1.42): Again hardcode a string about the development version "August 2001". Build time may be misleading ... 2001-07-31 23:16 slobasso * source/macro.c (1.28): fixed problem where closing window while learning would make it impossible to finish or cancel learing. 2001-07-31 11:58 amai * source/text.c (1.15): Fix minor warnings 2001-07-31 07:46 amai * util/managedList.c (1.5): Don't name variables 'index', may be an interface in BSD-like libc 2001-07-31 07:43 amai * util/getfiles.c (1.14): Fix lint warning: "getfiles.c", line 716: warning: args redefinition hides earlier one 2001-07-31 07:40 amai * util/fontsel.c (1.9): Don't use 'index' as name for variable; may be a call in a BSD-like libc 2001-07-29 17:51 amai * source/highlight.c (1.14): Experimental patch to fix "mismatched" memory handling calls as indicated by "purify". Probably not complete and should be checked again with purify _now_! 2001-07-28 19:53 tringali * Makefile (1.6): #442517: add explanatory text how to use make 2001-07-25 18:37 tringali * source/help.c (1.41): Add more detailed info about Motif (runtime version number) 2001-07-25 18:36 tringali * util/system.h (1.3): Use "Digital/Tru64 Unix" in place of OSF/1 2001-07-25 18:36 tringali * doc/: nc.man (1.3), nedit.man (1.3): Update authors for 5.2 2001-07-25 18:05 slobasso * util/misc.c (1.24): made changes so that Num_Lock's mod mask is found rather than assuming Mod3 2001-07-25 14:36 amai * source/textBuf.c (1.9): Attempt to fix memory leak reported by Thorsten Haude 2001-07-25 13:03 amai * util/misc.c (1.23): Try to fix small memory leak reported by Thorsten Haude 2001-07-25 07:49 amai * util/system.h (1.2): Add "EMX=OS/2" 2001-07-25 07:39 amai * source/Makefile.dependencies (1.6), util/Makefile.dependencies (1.4, REL-5-2): Update dependency lists 2001-07-24 21:55 tringali * util/system.h (1.1): Add host compliation information to help 2001-07-24 21:54 tringali * source/: help.c (1.40), tags.c (1.12), tags.h (1.4, REL-5-2): - Use shared strings for lower memory use with large tags files. - Add compilation host information to help, update authors 2001-07-24 19:27 slobasso * util/misc.c (1.22): Fix array size define to match actual array size. Incorrect size could result in infinite loop. 2001-07-18 13:01 amai * ChangeLog (1.5): Update 2001-07-18 13:00 amai * source/: search.c (1.30), search.h (1.11, REL-5-2), window.c (1.27): Shrink two function names to 31 characters length and below (seems to be a limit on some VMS systems) 2001-07-17 08:19 amai * doc/faq.xml (1.2): Updated version from Florian Xhumari as of http://galleries.free.fr/nedit-faq-01-07-16.tar.gz 2001-07-17 07:31 amai * source/preferences.c (1.27), util/getfiles.c (1.13), util/vmsUtils.c (1.4): VMS patches from Blair Phillips : avoid rint() re-definition, fix for non-unix file root, case-insensitive match on filename extensions. 2001-07-16 20:41 amai * source/lnknedit.com (1.5, BETA-5-3-RC1, REL-5-2): VMS patch from mark.geary@qwest.com 2001-07-16 14:48 amai * doc/: nc.man (1.2), nedit.man (1.2): Man page updates from Joor Loohuis 2001-07-16 11:49 amai * doc/: faq-txt.awk (1.1), faq-txt.dtd (1.1), faq-txt.xsl (1.1), faq.dtd (1.1), faq.xml (1.1), faq.xsl (1.1): faq*: add FAQ files found on our website 2001-07-11 21:35 amai * source/: parse.c_noyacc (1.6), parse.h (1.4, BETA-5-3-RC1, REL-5-2), parse.y (1.15): Back out "const" patch for ParseMacro(). Was incomplete, therefore broken 2001-07-11 15:21 amai * source/: comnedit.com (1.5), file.c (1.20), lnknedit.com (1.4): VMS patches from (not literally as for file.c) 2001-07-11 08:06 amai * source/parse.c_noyacc (1.5): Update from current parse.y 2001-07-11 08:04 amai * source/: parse.h (1.3), parse.y (1.14): Add some 'const' to ParseMacro() signature 2001-07-11 07:55 amai * util/: comutil.com (1.3, BETA-5-3-RC1, REL-5-2), utils.c (1.4): VMS patches from Mark.Geary@qwest.com 2001-07-07 09:55 amai * ChangeLog (1.4): Update 2001-07-07 09:54 amai * COPYRIGHT (1.1, BETA-5-3-RC1, REL-5-2), README (1.8): Have an external file for the license terms. README refers to it 2001-07-07 09:48 amai * nc.man (1.4), nedit.doc (1.6), nedit.man (1.4), doc/nc.man (1.1), doc/nedit.doc (1.1), doc/nedit.man (1.1): Move doc files to separate subdirectory 2001-07-04 09:42 uid30962 * README (1.7): Update some references to LessTif 2001-07-04 09:29 uid30962 * ReleaseNotes (1.7): ReleaseNotes: Upddate 2001-07-03 12:53 amai * source/Makefile.dependencies (1.5): Makefile.dependencies: update depedency list 2001-07-03 12:13 amai * source/help.c (1.39): help.c: A new month has come ... 2001-06-23 09:31 amai * ChangeLog (1.3): ChangeLog: update 2001-06-22 18:27 tringali * source/: nedit.c (1.13), window.c (1.26): Allow stats line background color to be set by user [#431891] 2001-06-22 18:25 tringali * source/macro.c (1.27): Incremental reading from files via J. Lous [Patch #434465] 2001-06-22 14:32 amai * source/file.c (1.19): file.c: fail when trying to read in a directory as a file 2001-06-21 14:54 edel * source/shell.c (1.10): Fixed shell dialog BadMatch crash on Solaris 2.5 2001-06-20 15:48 amai * source/macro.c (1.26): macro.c: replace snprintf() by sprintf(). Add #include 2001-06-20 08:24 amai * ChangeLog (1.2): ChangeLog: update 2001-06-19 20:00 slobasso * source/macro.c (1.25): Added Thorsten's code to put correct key codes in status bar during recording and macro running. 2001-06-09 18:48 amai * makefiles/: Makefile.dec (1.3), Makefile.osf (1.3), Makefile.superux (1.2): Makefile.superux: add CVS Id Makefile.dec Makefile.osf: briefly comment on the os versions they are supposed to work with 2001-06-08 08:14 amai * source/help.c (1.38): help.c: update timestamp to "June, 2001" 2001-06-07 19:52 amai * ChangeLog (1.1): ChangeLog: finally add the output of "cvs2cl". Needs to be updated regularly ... 2001-06-06 19:24 tringali * makefiles/Makefile.linux (1.4): Remove -DEDITRES, this causes link failure. 2001-06-06 10:00 amai * util/: DialogF.c (1.16), fontsel.c (1.8), getfiles.c (1.12), misc.c (1.21), prefFile.c (1.8): *.c: add some explicit #include . Previously it was done implicitly ... 2001-06-05 12:52 amai * makefiles/Makefile.linux (1.3): Makefile.linux: drop -I/-L/usr/lesstif/* flags and add a suitable comment instead 2001-06-05 08:01 amai * source/file.c (1.18): file.c: security fix for WriteBackupFile() 2001-06-01 20:09 edel * makefiles/: Makefile.solaris (1.3), Makefile.superux (1.1): From: Ian Johnston" 2001-05-31 08:49 amai * source/nedit.h (1.17, REL-5-2): nedit.h: add 'extern' to variable declaration in header (to avoid problem with multiple definitions) 2001-05-29 18:21 arnef * source/menu.c (1.33): Add separator in Preferences/Default Settings/Customize Menus 2001-05-19 16:09 tringali * util/misc.c (1.20): Fix bug in mnemonic building- don't build mnemonics for XK_VoidSymbol. Fixes various problems with XFree86 servers. 2001-05-17 11:42 arnef * source/: menu.c (1.32), nedit.h (1.16), preferences.c (1.26), preferences.h (1.10), window.c (1.25): Adding path to windows menu file entries 2001-05-15 20:04 amai * makefiles/Makefile.depend (1.1): Makefile.depend: Makefile used to generate (internal) the dependency list. This file does not build anything! 2001-05-12 00:48 tringali * ReleaseNotes (1.6), source/text.c (1.14): - Add support for mouse wheel scrolling in the main text area. 2001-05-11 19:56 amai * util/fileUtils.c (1.12): fileUtils.c: really tiny patch for OS/2 only (drive letters ;-) 2001-05-11 08:05 amai * source/file.c (1.17): file.c: Corrected(!) version of SuSe security patch for temporary file security problem within PrintString(). Tested once for compile/runtime ... 2001-05-05 18:01 arnef * source/menu.c (1.31): Changing default for sortOpenPrevDefCB should invalidate all open window's OpenPrev menu 2001-05-04 18:33 arnef * source/: nedit.h (1.15), search.c (1.29), search.h (1.10), window.c (1.24): Make the buttons in Find and Replace dialogs sensitive on the state of 'Search for' field. 2001-05-03 09:42 amai * source/help.c (1.37): help.c: update timestamp to "May, 2001" 2001-04-25 21:37 edg * util/DialogF.c (1.15): Added a fix to handle unexpected destruction of dialogs gracefully. 2001-04-25 19:03 amai * nedit.doc (1.5): nedit.doc: fix some typos, convert some "nedit" to "NEdit", drop some comment about pre 1.2 Motif 2001-04-25 17:01 amai * util/fileUtils.c (1.11): fileUtils.c: forgot one special case where the "//" patch might to a crash. Next time I should probably first, later 2001-04-25 16:48 amai * util/fileUtils.c (1.10): fileUtils.c: fix typo in my "double-slash patch" from today 2001-04-25 07:52 amai * util/fileUtils.c (1.9): fileUtils.c: avoid double "//" in path strings as this may not work out on non-un*x systems 2001-04-24 21:10 tringali * util/misc.c (1.19): Fix crash bug in OpenMotif, where asking for the the Display/Window of a gadget produces a NULL pointer. 2001-04-18 19:12 slobasso * source/window.c (1.23): needed to save/restore horizontal and vertical scroll positions when changing hw tab size. 2001-04-18 19:08 slobasso * util/DialogF.c (1.14): fixed use of int where Cardinal should be 2001-04-18 17:10 slobasso * source/: help.c (1.36), macro.c (1.24): new $server_name variable. 2001-04-18 17:02 slobasso * source/: file.c (1.16), file.h (1.7, REL-5-2), help.c (1.35), menu.c (1.30), window.c (1.22): added optional parameter to close() action for save option. 2001-04-18 16:51 slobasso * util/DialogF.c (1.13): fixed a mistake I introduced while debugging 2001-04-18 16:12 slobasso * util/DialogF.c (1.12): cleaned up createMnemonics in an effort to fix a crash bug. Bug still not fixed. 2001-04-17 23:40 slobasso * source/help.c (1.34): cleaned up formatting and moved Windows Menu items into correct area 2001-04-17 20:13 slobasso * source/window.c (1.21): save and restore insert positions when hw tab sizes are changed 2001-04-17 18:47 slobasso * source/macro.c (1.23): cleaned up RedundantActions, adding some missing items 2001-04-16 23:49 slobasso * source/: file.c (1.15), nedit.h (1.14): added bit to distinguish between too much binary data and -read 2001-04-16 23:20 slobasso * source/: file.c (1.14), file.h (1.6), macro.c (1.22), menu.c (1.29), nedit.h (1.13), search.c (1.28), selection.c (1.8), window.c (1.20): readOnly vs lockWrite access fix, now handles the many other locked possibilities 2001-04-16 16:36 edg * source/: help.c (1.33), window.c (1.19): Added workarounds for openmotif bugs [SF bug 231876]. 2001-04-16 14:04 amai * source/textBuf.c (1.8): texBuf.c: try to fix a bug introduced by a "const" patch. Pointed out by 2001-04-14 09:51 amai * makefiles/Makefile.unicos (1.3), source/preferences.c (1.25), source/text.c (1.13), source/userCmds.c (1.12): *: applied re-vised version of patches for UNICOS from Bill Matson 2001-04-13 22:58 slobasso * util/DialogF.c (1.11): fix build problem introduced in previous change UCHAR_MAX is in limits.h 2001-04-13 17:50 tringali * ReleaseNotes (1.5), source/file.c (1.13), source/help.c (1.32), source/highlightData.c (1.13), source/macro.c (1.21), source/preferences.c (1.24), source/search.c (1.27), source/smartIndent.c (1.9), source/userCmds.c (1.11), util/DialogF.c (1.10), util/fontsel.c (1.7), util/getfiles.c (1.11), util/misc.c (1.18), util/misc.h (1.7), util/printUtils.c (1.10): - Updated release notes - Added unmodified mnemonics to confirmation dialogs. - Fix bug in mnemonics where there could be two of the same menmonics on one dialog. 2001-04-13 15:02 slobasso * source/search.c (1.26): fixed regex search backwards bug if wrap turned off. 2001-04-12 22:02 edg * source/: help.c (1.31), macro.c (1.20), menu.c (1.28), nedit.h (1.12), preferences.c (1.23), search.c (1.25), window.c (1.18), window.h (1.6): Extended the Show Matching (..) functionality: Off, Delimiter, and Range. Original patch was submitted by Thorsten Haude. 2001-04-12 15:09 amai * source/menu.c (1.27): menu.c: allow to specify control codes in hex/dec/oct format also improve checking of input 2001-04-09 22:12 amai * util/: misc.c (1.17), misc.h (1.6): misc.c misc.h: another "const" patch 2001-04-09 21:43 edg * source/help.c (1.30): Added information about new search extensions and related stuff. 2001-04-09 21:38 edg * source/: nedit.h (1.11), search.c (1.24): Minor fixes and improvements in isearch + beep on search wrap combination. 2001-04-09 18:46 edg * util/misc.c (1.16): Typo fix in recent accelerator fix. 2001-04-06 13:09 amai * source/: preferences.c (1.22), preferences.h (1.9): preferences.*: even more "const" additions 2001-04-06 13:03 amai * source/: interpret.c (1.13), interpret.h (1.6, REL-5-2): interpret.*: another "const" patch 2001-04-06 09:49 amai * source/file.c (1.12), source/file.h (1.5), source/help.c (1.29), source/highlightData.c (1.12), source/highlightData.h (1.4, REL-5-2), source/preferences.c (1.21), source/preferences.h (1.8), source/regularExp.c (1.7, REL-5-2), source/regularExp.h (1.5, REL-5-2), source/search.c (1.23), source/search.h (1.9), source/textBuf.c (1.7), source/textBuf.h (1.4, REL-5-2), util/fileUtils.c (1.8), util/fileUtils.h (1.4), util/printUtils.c (1.9), util/printUtils.h (1.4, REL-5-2): *.c *.h: big "const" patch. Except in textBuf.c it's only a couple of const additions. In textBuf.c I had to change a coupl of lines to get this done - should be on the safe side of life ... 2001-04-04 19:38 edg * source/: preferences.c (1.20), search.c (1.22): Minor bug fixes in search extensions related code. 2001-04-03 22:59 edg * source/: menu.c (1.26), nedit.h (1.10), preferences.c (1.19), preferences.h (1.7), search.c (1.21), search.h (1.8): Added "smart" replace scope behaviour to the replace dialog radio button alternative, and made it configurable through a preference. 2001-04-03 08:06 amai * source/help.c (1.28): help.c: the "April" patch ... 2001-04-03 01:42 tringali * util/misc.c (1.15): Don't allow traversal to insensitive widgets. 2001-04-02 20:52 edg * source/: highlight.c (1.13), macro.c (1.19), menu.c (1.25), nedit.h (1.9), preferences.c (1.18), preferences.h (1.6), regularExp.c (1.6), regularExp.h (1.4), search.c (1.20), search.h (1.7), window.c (1.17): Introduced additional search modes [Markus Schwarzenberg]. Added beep on search wrap option [Markus Schwarzenberg]. Added sticky case sensitivity search preference [Markus Schwarzenberg]. Replace and find dialog and incremental search bar layout changes (currently two layout alternatives for replace dialog, for evaluation purposes). 2001-03-30 17:54 slobasso * source/highlightData.c (1.11): new global in nedit macro language $empty_array 2001-03-30 17:48 slobasso * source/: help.c (1.27), macro.c (1.18): added a new empty array global 2001-03-27 23:00 slobasso * source/help.c (1.26): minor formatting fix 2001-03-27 15:37 tringali * makefiles/Makefile.aix (1.4): Add FUNCPROTO=15 for the IBM X headers, which require a bitmask in this #define in order to control function prototypes. 2001-03-26 15:46 slobasso * source/: interpret.c (1.12), interpret.h (1.5), macro.c (1.17): minor array code cleanup 2001-03-25 08:42 arnef * source/tags.c (1.11): Fixed bug #217022 2001-03-23 23:11 slobasso * source/highlightData.c (1.10): added missing variables to NEdit macro highlighting data 2001-03-23 14:41 slobasso * source/undo.c (1.5): undo/redo sets the selection to the changed text 2001-03-21 21:25 edg * source/search.c (1.19): Changed the initial default selection for multi-file replacement dialog to all files instead of none. Multi-file replacement dialog now makes sure that at least the first selected item is visible when displayed. Removed the #ifdefs for conditional multi-file replacement functionality. Minor layout change for the replace dialog. 2001-03-21 21:20 edg * source/window.c (1.16): Removed #ifdef for conditional multi-file replacement functionality. 2001-03-19 16:30 slobasso * source/: highlight.c (1.12), regexConvert.c (1.3), regularExp.c (1.5), search.c (1.18), text.c (1.12), textBuf.c (1.6), textDisp.c (1.9): removing warnings for RH7 linux compiler 2001-03-19 14:43 tringali * source/: text.c (1.11), nedit.c (1.12): Move toggle overstrike accelerator to Motif standard "Insert", free up Ctrl+B for other uses. 2001-03-17 06:44 arnef * source/search.c (1.17): Fixed bug related to XtGetSelectionValue() and variables going out of scope. Added mnemonic to Replace& Find Button. 2001-03-16 22:24 slobasso * source/menu.c (1.24): fixed menu argument to set_wrap_text 2001-03-16 20:28 amai * source/: nc.c (1.8), nedit.c (1.11): nc.c nedit.c: wildcard expansion for non-sh shells on OS/2 (EMX) 2001-03-13 16:48 slobasso * source/help.c (1.25), source/macro.c (1.16), source/search.c (1.16), source/selection.c (1.7), source/shell.c (1.9), source/shift.c (1.7), source/textDisp.c (1.8), util/DialogF.c (1.9), util/fontsel.c (1.6), util/printUtils.c (1.8): cleanup warnings under linux compiler 2001-03-12 15:24 slobasso * source/help.c (1.24): fixed a few minor mistakes. 2001-03-12 15:15 slobasso * source/: help.c (1.23), macro.c (1.15), menu.c (1.23), preferences.c (1.17), window.c (1.15), window.h (1.5): added final window settable prefs through actions and verified all should be macro recordable. 2001-03-11 02:31 slobasso * source/: help.c (1.22), menu.c (1.22), nedit.h (1.8): new macro access to many window settings 2001-03-10 15:36 arnef * source/: help.c (1.21), menu.c (1.21), nedit.c (1.10), nedit.h (1.7), preferences.c (1.16), preferences.h (1.5), search.c (1.15), search.h (1.6): Implemented replace/find functionality, patch no 403934 2001-03-09 22:30 slobasso * source/help.c (1.20): changed delete() to delete_selection() in docs 2001-03-09 22:27 slobasso * source/menu.c (1.20): changed Delete menu item to use delete_selection action 2001-03-09 22:21 slobasso * source/parse.y (1.13): added lex hack for delete array[key] vs delete() abiguity 2001-03-09 16:58 slobasso * source/: help.c (1.19), macro.c (1.14), menu.c (1.19), text.c (1.10), text.h (1.4, REL-5-2), textDisp.c (1.7), textDisp.h (1.5, REL-5-2), window.c (1.14), window.h (1.4): adding new variables for font width and pane index and size and focus_pane action 2001-03-06 19:49 slobasso * source/: interpret.c (1.11), rbTree.c (1.2), rbTree.h (1.2, BETA-5-3-RC1, REL-5-2): added comments, cleaned up a few minor bugs and added cvs id's to new files 2001-03-06 15:02 slobasso * source/macro.c (1.13): add comments 2001-03-06 01:00 slobasso * source/: interpret.c (1.10), parse.y (1.12): code cleanup 2001-03-05 21:39 slobasso * source/highlightData.c (1.9): bring syntax hilighting up to latest changes in nedit macro language 2001-03-05 19:26 slobasso * source/: interpret.c (1.9), macro.c (1.12), parse.y (1.11): fixed a few warnings and made splitMS compatible with array sub-scripts end cases, which is what is was designed for 2001-03-05 16:20 amai * source/: help.c (1.18), parse.y (1.10): help.c: It's "March" now ... parse.y: add two yy*() prototypes to make compiler happy 2001-03-05 15:00 slobasso * source/: Makefile.common (1.6), Makefile.dependencies (1.4), help.c (1.17), interpret.c (1.8), interpret.h (1.4), macro.c (1.11), menu.c (1.18), nedit.c (1.9), parse.y (1.9), rbTree.c (1.1), rbTree.h (1.1), shell.c (1.8), smartIndent.c (1.8), userCmds.c (1.10): array macro feature 2001-02-26 23:38 edg * Makefile (1.5), README (1.6), ReleaseNotes (1.4), nc.man (1.3), nedit.doc (1.4), nedit.man (1.3), makefiles/Makefile.aix (1.3), makefiles/Makefile.bsdi (1.2), makefiles/Makefile.ccur (1.2), makefiles/Makefile.convex (1.2), makefiles/Makefile.cygwin (1.3), makefiles/Makefile.dcosx (1.2), makefiles/Makefile.dec (1.2), makefiles/Makefile.freebsd (1.2), makefiles/Makefile.generic (1.2), makefiles/Makefile.hpux (1.2), makefiles/Makefile.linux (1.2), makefiles/Makefile.lynx (1.2), makefiles/Makefile.m88k.svr4 (1.2), makefiles/Makefile.netbsd (1.2), makefiles/Makefile.os2 (1.2), makefiles/Makefile.osf (1.2), makefiles/Makefile.reliant (1.2), makefiles/Makefile.sco (1.2), makefiles/Makefile.sgi (1.2), makefiles/Makefile.solaris (1.2), makefiles/Makefile.sunos (1.2), makefiles/Makefile.uhc (1.2), makefiles/Makefile.ultrix (1.2), makefiles/Makefile.unicos (1.2), makefiles/Makefile.unixware (1.2), source/Makefile.common (1.5), source/Makefile.dependencies (1.3), source/comnedit.com (1.4), source/file.c (1.11), source/file.h (1.4), source/help.c (1.16), source/help.h (1.3), source/highlight.c (1.11), source/highlight.h (1.3, REL-5-2), source/highlightData.c (1.8), source/highlightData.h (1.3), source/interpret.c (1.7), source/interpret.h (1.3), source/lnknedit.com (1.3), source/macro.c (1.10), source/macro.h (1.2, REL-5-2), source/menu.c (1.17), source/menu.h (1.5, BETA-5-3-RC1, REL-5-2), source/n.bm (1.2, BETA-5-3-RC1, REL-5-2), source/nc.c (1.7), source/nedit.bm (1.2, BETA-5-3-RC1, REL-5-2), source/nedit.c (1.8), source/nedit.h (1.6), source/nedit_options_file.opt (1.2, BETA-5-3-RC1, REL-5-2), source/parse.c_noyacc (1.4), source/parse.h (1.2), source/parse.y (1.8), source/preferences.c (1.15), source/preferences.h (1.4), source/regexConvert.c (1.2), source/regexConvert.h (1.2, REL-5-2), source/regularExp.c (1.4), source/regularExp.h (1.3), source/search.c (1.14), source/search.h (1.5), source/selection.c (1.6), source/selection.h (1.3, REL-5-2), source/server.c (1.7), source/server.h (1.2, REL-5-2), source/shell.c (1.7), source/shell.h (1.3, REL-5-2), source/shift.c (1.6), source/shift.h (1.3, BETA-5-3-RC1, REL-5-2), source/smartIndent.c (1.7), source/smartIndent.h (1.3), source/tags.c (1.10), source/tags.h (1.3), source/text.c (1.9), source/text.h (1.3), source/textBuf.c (1.5), source/textBuf.h (1.3), source/textDisp.c (1.6), source/textDisp.h (1.4), source/textDrag.c (1.3), source/textDrag.h (1.2, BETA-5-3-RC1, REL-5-2), source/textP.h (1.3, BETA-5-3-RC1, REL-5-2), source/textSel.c (1.3), source/textSel.h (1.2, BETA-5-3-RC1, REL-5-2), source/undo.c (1.4), source/undo.h (1.3, REL-5-2), source/userCmds.c (1.9), source/userCmds.h (1.3), source/window.c (1.13), source/window.h (1.3), util/DialogF.c (1.8), util/DialogF.h (1.4, REL-5-2), util/Makefile.common (1.5, REL-5-2), util/Makefile.dependencies (1.3), util/comutil.com (1.2), util/fileUtils.c (1.7), util/fileUtils.h (1.3), util/fontsel.c (1.5), util/fontsel.h (1.3), util/getfiles.c (1.10), util/getfiles.h (1.3, BETA-5-3-RC1, REL-5-2), util/managedList.c (1.4), util/managedList.h (1.3, BETA-5-3-RC1, REL-5-2), util/misc.c (1.14), util/misc.h (1.5), util/prefFile.c (1.7), util/prefFile.h (1.4, BETA-5-3-RC1, REL-5-2), util/printUtils.c (1.7), util/printUtils.h (1.3), util/utils.c (1.3), util/utils.h (1.2, REL-5-2), util/vmsParam.h (1.2, BETA-5-3-RC1, REL-5-2), util/vmsUtils.c (1.3), util/vmsUtils.h (1.3, BETA-5-3-RC1, REL-5-2): Added CVS Ids. 2001-02-25 02:13 edel * source/parse.y (1.7): Fix conflicts in yacc grammar! 2001-02-22 20:27 edel * source/highlight.c (1.10): My previous highlighting patch didn't take in to account styles which fail lookup in the pass1pattern list (like pass 2 patterns). 2001-02-21 21:39 tringali * source/highlight.c (1.9): [Patch #101473] Use nearest-color match when colormap exhausted. 2001-02-21 16:49 edel * source/highlight.c (1.8): Abutting styles could fool incremental highlighting into using an unparsable pattern with parseString. 2001-02-20 23:54 slobasso * source/: help.c (1.15), macro.c (1.9): new preference global variables added 2001-02-20 15:37 slobasso * source/menu.c (1.16): fixed bug where forgot to deref nArgs pointer 2001-02-20 09:58 amai * Makefile (1.4), README (1.5): README: change a couple of "nedit" to "NEdit" Makefile: slightly change comment text (fix typo, etc.) 2001-02-19 16:39 slobasso * source/: help.c (1.14), macro.c (1.8), menu.c (1.15): added a new macro command string_compare() and an action raise_window() 2001-02-19 16:30 slobasso * source/file.c (1.10): fix issue where reused untitled window is not given focus when raised. 2001-02-19 10:03 amai * source/help.c (1.13): help.c: fix some typos and change a couple of "nedit" to "NEdit". Actually it is not always straightforward to see whether a "nedit" refers to the whole product called "NEdit" or to the "nedit" executable ... 2001-02-19 02:02 slobasso * source/text.c (1.8): fix warnings 2001-02-17 14:03 amai * source/Makefile.dependencies (1.2), util/Makefile.dependencies (1.2): */Makefile.dependencies: update WRT new utils.* 2001-02-17 13:59 amai * source/file.c (1.9), util/utils.c (1.2): file.c utils.c: add missing #includes 2001-02-17 13:56 amai * util/: utils.c (1.1), utils.h (1.1): utils.*: new sources for general purpose, non-GUI stuff like GetHomeDir() 2001-02-17 13:53 amai * source/file.c (1.8), source/macro.c (1.7), source/menu.c (1.14), source/nc.c (1.6), source/server.c (1.6), source/tags.c (1.9), util/Makefile.common (1.4), util/fileUtils.c (1.6), util/prefFile.c (1.6): nc.c server.c: move #include before other Makefile.common: prepare for util/utils.c to be checked in file.c macro.c menu.c tags.c fileUtils.c prefFile.c: use new GetCurDir(), GetHomeDir() calls 2001-02-17 01:47 edel * source/: highlight.c (1.7), parse.y (1.6): Empty code blocks are rejected by the macro language. 2001-02-17 00:09 slobasso * source/interpret.c (1.6): when strings are converted to numbers and the conversion fails, use 0 rather than junk 2001-02-16 14:58 amai * ReleaseNotes (1.3), source/tags.c (1.8), util/fileUtils.c (1.5): ReleaseNotes: add some bugs being addressed *.c: supply fallback if getcwd() fails (in one case we used uninitialized memory earlier!) 2001-02-16 14:25 amai * source/: Makefile.common (1.4), help.c (1.12): Makefile.common: nc depends on libNUtil.a! help.c: switch to "February 2001" ... 2001-02-15 16:08 tringali * ReleaseNotes (1.2): Add info about 5.2 features and bugfixes. 2001-02-15 16:07 tringali * util/misc.c (1.13): Fix simulateButtonPress() so it works for gadgets. (Needed for DialogF mnemonics.) 2001-02-15 16:06 tringali * util/DialogF.h (1.3): Change dialog_type parameter to int to avoid warnings. 2001-02-15 16:06 tringali * util/DialogF.c (1.7): Automatically create mnemonics for dialog buttons. Change dialog_type parameter to int to avoid warnings (comparing unsingned int for negative isn't exactly useful). 2001-02-15 16:04 tringali * source/preferences.c (1.14): Default syntax highlighting to on. 2001-02-15 16:04 tringali * source/nc.c (1.5): - Remove warnings for 64-bit systems. Extend strlen results to long and use %ld as a format specifier. strlen returns a size_t which is typically an unsigned long on 64-bit systems. 2001-02-14 00:34 slobasso * source/: help.c (1.11), text.c (1.7), textDisp.c (1.5), textDisp.h (1.3): added extra options to many of the macro actions 2001-02-12 22:37 amai * source/preferences.c (1.13): preferences.c: patch from Thorsten Haude to issue a warning if -import can not find the specified file 2001-02-12 21:08 slobasso * source/: help.c (1.10), menu.c (1.13), nedit.h (1.5), preferences.c (1.12), preferences.h (1.3), search.c (1.13), search.h (1.4): Added a search wrap option to prefs and made some more options available to macro actions. 2001-02-09 22:35 tringali * source/help.c (1.9): Remove obsolete reference to Caps-Lock bug. 2001-02-09 22:34 slobasso * source/: interpret.c (1.5), interpret.h (1.2), parse.c_noyacc (1.3), parse.y (1.5): fixed a leak with static strings in the macro interpreter. 2001-02-09 22:19 slobasso * source/: menu.c (1.12), text.c (1.6): fixed strCaseCmp() bug where partial strings would match. 2001-02-09 21:07 amai * source/userCmds.c (1.8): userCmds.c: try to fix compiler warnings 2001-02-09 09:08 amai * source/: menu.c (1.11), menu.h (1.4): menu.*: fix a 'pointer vs. integer constant' problem, by adding a cast to the constants #definition 2001-02-08 09:08 amai * source/Makefile.common (1.3), source/Makefile.dependencies (1.1), util/Makefile.common (1.3), util/Makefile.dependencies (1.1): */Makefile.common: include new */Makefile.dependencies: simple files containing the dependencies for all objects (i.e. *.o) 2001-02-08 08:52 amai * source/: menu.c (1.10), menu.h (1.3): menu.c menu.h: - correct my previous patch: XmNuserData requires XtPointer* arg - add some more 'const's 2001-02-06 16:04 amai * source/search.c (1.12), util/DialogF.c (1.6), util/getfiles.c (1.9): search.c DialogF.c getfiles.c: Drop #ifdef MOTIF10 sections. 2001-02-06 12:07 amai * source/menu.c (1.9): menu.c: Fix a 'major' 64bit bug: we were passing a pointer to int instead of pointer to pointer. This fixes the crash with NEdit/LessTif on alpha when selecting the Window menu item!! 2001-02-06 10:19 amai * source/preferences.c (1.11): preferences.c: drop unused #include 2001-02-06 10:03 amai * source/interpret.c (1.4), util/prefFile.c (1.5), util/prefFile.h (1.3): interpret.c prefFile.*: add 'const' to some more functions' signature 2001-02-06 10:02 amai * source/: nc.c (1.4), server.c (1.5): server.c nc.c: add checks whether some system calls succeed (e.g. uname()) changed signature of getHostName() and getUserName 2001-02-05 19:45 amai * util/: DialogF.c (1.5), misc.c (1.12), prefFile.c (1.4), printUtils.c (1.6): DialogF.c misc.c prefFile.c printUtils.c: add 'const' to some functions' signatures 2001-02-05 17:13 amai * source/: file.c (1.7), help.c (1.8), highlight.c (1.6), highlightData.c (1.7): file.c help.c highlight.c highlightData.c: Replace improper <0> as last argument in XtVa*() interface calls by 2001-02-02 18:10 tringali * source/highlight.c (1.5): Replace debugging code of divide by 0 with a more proper assert. Dividing by zero generated warnings on lots of compilers. 2001-02-02 14:47 amai * source/window.c (1.12): window.c: drop declaration of _XEditResCheckMessages(); should be in according header Fix compiler warning about boolean expression 2001-02-02 14:00 amai * Makefile (1.3), README (1.4): Makefile: do not list CVS/ subdir when running 'make' without argument README: cosmetics (re-formatting) add pointer to makefiles/Makefile.generic which explains our current -D compiler options 2001-02-02 13:12 amai * util/getfiles.c (1.8): getfiles.c: - add 'cont' add some places (as I realized we are already using it, so we don't discuss systems w/o here) - drop */errno.h #includes (I couldn't see any usage of it currently) 2001-02-01 23:16 tringali * makefiles/Makefile.aix (1.2): Fix for bug 130164: force X headers to include full prototype information. 2001-01-26 22:42 amai * source/: help.c (1.7), window.c (1.11): help.c: switch to "January, 2001" window.c: ad cast; should fix SF [Bug #130164 ] Compiler warning on AIX4.3.2 in window.c 2001-01-24 15:54 amai * util/misc.c (1.11), source/highlightData.c (1.6), source/menu.c (1.8), source/preferences.c (1.10), source/userCmds.c (1.7): *.c: The XmNnumChildren resource if of type 'Cardinal', not 'int' 2001-01-10 10:42 amai * source/textBuf.c (1.4): textBuf.c: fix for SF [Bug #115195 ] textBuf.c:862 warning: '/*' within comment 2001-01-05 21:18 amai * source/shell.c (1.6): shell.c: change some "Nedit" strings to "NEdit". properly end an execl() parameter list by (char *)0 2000-12-20 14:05 amai * source/help.c (1.6), source/nedit.c (1.7), source/search.c (1.11), source/window.c (1.10), util/getfiles.c (1.7): Replace "Lesstif" by "LessTif" ... Update timestamp in version info to "december, 2000" 2000-12-20 13:56 amai * README (1.3), source/.cvsignore (1.1), source/tags.c (1.7), util/misc.c (1.10): Add two missing #includes Add a .cvsignore for the two binaries beign built Update the docs WRT LessTif issues 2000-12-19 21:08 tringali * nedit.doc (1.3): Removed obsolete references to fnal.gov FTP server. 2000-12-19 21:06 edg * source/selection.c (1.5): Added a fix for SF bug 126285: segfault with goto line. 2000-12-15 20:57 edg * source/text.c (1.5): Fixed a selection highlighting bug (removed an earlier bogus patch). 2000-12-10 19:35 edg * source/search.c (1.10): Fixed some (harmless) compiler warnings. Added an extra check in the multi-file replacement code to make sure that the user didn't invalidate the replacement strings when the dialog isn't modal (bug in several Lesstif versions). 2000-11-30 21:33 edg * util/getfiles.c (1.6): Implemented a workaround for a Motif 2.x file selection box bug. 2000-11-30 21:31 edg * makefiles/Makefile.cygwin (1.2): Minor changes requested by Christian Denat. 2000-11-23 23:23 edg * source/: search.c (1.9), search.h (1.3), window.c (1.9): Fixed a critical bug in the multi-file replace functionality. Closing windows while a multi-file replace dialog was up could result in a crash. The lists are now updated when a window closes. 2000-11-22 23:08 edg * source/: nedit.h (1.4), search.c (1.8), window.c (1.8): Added multi-file replace-all functionality. 2000-11-22 21:50 edg * source/: preferences.c (1.9), search.c (1.7): Added a missing #include . 2000-11-07 14:03 edel * util/misc.c (1.9): Fix glitches in Caps/Num Lock patch 2000-11-06 21:52 edel * source/: macro.c (1.6), preferences.c (1.8), shift.c (1.5), text.c (1.4), userCmds.c (1.6), window.c (1.7): Patch for Caps/Num Lock bug + a few other minor fixes 2000-11-06 21:50 edel * util/: misc.c (1.8), misc.h (1.4): Patch for Caps/Num Lock Motif bug 2000-10-06 21:23 edel * util/misc.c (1.7): Bug fix: BG menu not working with new best visual code 2000-10-04 03:09 edel * util/: DialogF.c (1.4), fontsel.c (1.4), getfiles.c (1.5), managedList.c (1.3), misc.c (1.6), printUtils.c (1.5): For IA-64, XtVa argument lists must be terminated with NULL rather than 0 2000-10-04 03:07 edel * source/: macro.c (1.5), menu.c (1.7), preferences.c (1.7), search.c (1.6), selection.c (1.4), shell.c (1.5), shift.c (1.4), smartIndent.c (1.6), tags.c (1.6), textDisp.c (1.4), userCmds.c (1.5), window.c (1.6): For IA-64, XtVa calls must be terminated w/NULL, rather than 0 2000-09-29 15:48 edel * util/: fileUtils.c (1.4), misc.c (1.5): Support ClearCase version extended pathnames (and fix some compiler warns) 2000-09-29 15:38 edel * source/: file.c (1.6), file.h (1.3), menu.c (1.6), nedit.c (1.6), preferences.c (1.6), server.c (1.4), shell.c (1.4): Updates from Max (via Arne), and Arne Førlie: ClearCase version extended paths, Untitled windows inherit parent path, and avoid reuse of Untitled windows which are currently running a macro. 2000-09-26 20:28 edel * source/: file.c (1.5), help.c (1.5), highlightData.c (1.5), macro.c (1.4), menu.c (1.5), nedit.c (1.5), preferences.c (1.5), search.c (1.5), smartIndent.c (1.5), tags.c (1.5), userCmds.c (1.4), window.c (1.5): Allow nedit to use non-default visuals 2000-09-26 20:25 edel * util/: DialogF.c (1.3), fontsel.c (1.3), getfiles.c (1.4), misc.c (1.4), misc.h (1.3), printUtils.c (1.4): Allow NEdit to use non-default visual 2000-09-22 19:41 edel * util/: fileUtils.c (1.3), getfiles.c (1.3), misc.c (1.3), prefFile.c (1.3), printUtils.c (1.3): Changes since last posted development release 2000-09-22 19:34 edel * source/: file.c (1.4), help.c (1.4), highlight.c (1.4), highlightData.c (1.4), interpret.c (1.3), macro.c (1.3), menu.c (1.4), nc.c (1.3), nedit.c (1.4), parse.y (1.4), preferences.c (1.4), regularExp.c (1.3), search.c (1.4), selection.c (1.3), server.c (1.3), shell.c (1.3), shift.c (1.3), smartIndent.c (1.4), tags.c (1.4), text.c (1.3), textBuf.c (1.3), undo.c (1.3), userCmds.c (1.3), window.c (1.4): Changes since last posted development release 2000-09-10 18:15 tringali * makefiles/: Makefile.aix (1.1), Makefile.bsdi (1.1), Makefile.ccur (1.1), Makefile.convex (1.1), Makefile.cygwin (1.1), Makefile.dcosx (1.1), Makefile.dec (1.1), Makefile.freebsd (1.1), Makefile.generic (1.1), Makefile.hpux (1.1), Makefile.linux (1.1), Makefile.lynx (1.1), Makefile.m88k.svr4 (1.1), Makefile.netbsd (1.1), Makefile.os2 (1.1), Makefile.osf (1.1), Makefile.reliant (1.1), Makefile.sco (1.1), Makefile.sgi (1.1), Makefile.solaris (1.1), Makefile.sunos (1.1), Makefile.uhc (1.1), Makefile.ultrix (1.1), Makefile.unicos (1.1), Makefile.unixware (1.1) (utags: REL-5-1-1): 5.1.1 baseline 2000-09-09 22:22 tringali * source/: comnedit.com (1.3), file.c (1.3), help.c (1.3), highlight.c (1.3), highlightData.c (1.3), menu.c (1.3), nedit.c (1.3), nedit.h (1.3), parse.c_noyacc (1.2), parse.y (1.3), preferences.c (1.3), search.c (1.3), smartIndent.c (1.3), tags.c (1.3), textDisp.c (1.3), window.c (1.3): 5.2 Development snapshot as of 5/29/2000 2000-09-09 22:18 tringali * Makefile (1.2, REL-5-1-1), README (1.2, REL-5-1-1), ReleaseNotes (1.1, REL-5-1-1), nc.man (1.2, REL-5-1-1), nedit.doc (1.2, REL-5-1-1), nedit.man (1.2, REL-5-1-1), source/Makefile.common (1.2, REL-5-1-1), source/Makefile.dec (1.2), source/Makefile.hp (1.2), source/Makefile.ibm (1.2), source/Makefile.linux (1.2), source/Makefile.osf (1.2), source/Makefile.sgi (1.2), source/Makefile.solaris (1.2), source/Makefile.sunos (1.2), source/Makefile.ultrix (1.2), source/comnedit.com (1.2, REL-5-1-1), source/file.c (1.2, REL-5-1-1), source/file.h (1.2, REL-5-1-1), source/help.c (1.2, REL-5-1-1), source/help.h (1.2, REL-5-1-1), source/highlight.c (1.2, REL-5-1-1), source/highlight.h (1.2, REL-5-1-1), source/highlightData.c (1.2, REL-5-1-1), source/highlightData.h (1.2, REL-5-1-1), source/interpret.c (1.2, REL-5-1-1), source/lnknedit.com (1.2, REL-5-1-1), source/macro.c (1.2, REL-5-1-1), source/menu.c (1.2, REL-5-1-1), source/menu.h (1.2, REL-5-1-1), source/nc.c (1.2, REL-5-1-1), source/nedit.c (1.2, REL-5-1-1), source/nedit.h (1.2, REL-5-1-1), source/parse.y (1.2, REL-5-1-1), source/preferences.c (1.2, REL-5-1-1), source/preferences.h (1.2, REL-5-1-1), source/regexConvert.c (1.1, REL-5-1-1), source/regexConvert.h (1.1, REL-5-1-1), source/regularExp.c (1.2, REL-5-1-1), source/regularExp.h (1.2, REL-5-1-1), source/search.c (1.2, REL-5-1-1), source/search.h (1.2, REL-5-1-1), source/selection.c (1.2, REL-5-1-1), source/selection.h (1.2, REL-5-1-1), source/server.c (1.2, REL-5-1-1), source/shell.c (1.2, REL-5-1-1), source/shell.h (1.2, REL-5-1-1), source/shift.c (1.2, REL-5-1-1), source/shift.h (1.2, REL-5-1-1), source/smartIndent.c (1.2, REL-5-1-1), source/smartIndent.h (1.2, REL-5-1-1), source/tags.c (1.2, REL-5-1-1), source/tags.h (1.2, REL-5-1-1), source/text.c (1.2, REL-5-1-1), source/text.h (1.2, REL-5-1-1), source/textBuf.c (1.2, REL-5-1-1), source/textBuf.h (1.2, REL-5-1-1), source/textDisp.c (1.2, REL-5-1-1), source/textDisp.h (1.2, REL-5-1-1), source/textDrag.c (1.2, REL-5-1-1), source/textP.h (1.2, REL-5-1-1), source/textSel.c (1.2, REL-5-1-1), source/undo.c (1.2, REL-5-1-1), source/undo.h (1.2, REL-5-1-1), source/userCmds.c (1.2, REL-5-1-1), source/userCmds.h (1.2, REL-5-1-1), source/window.c (1.2, REL-5-1-1), source/window.h (1.2, REL-5-1-1), util/DialogF.c (1.2, REL-5-1-1), util/DialogF.h (1.2, REL-5-1-1), util/Makefile.common (1.2, REL-5-1-1), util/Makefile.dec (1.2), util/Makefile.hp (1.2), util/Makefile.ibm (1.2), util/Makefile.linux (1.2), util/Makefile.sgi (1.2), util/Makefile.solaris (1.2), util/Makefile.sunos (1.2), util/Makefile.ultrix (1.2), util/fileUtils.c (1.2, REL-5-1-1), util/fileUtils.h (1.2, REL-5-1-1), util/fontsel.c (1.2, REL-5-1-1), util/fontsel.h (1.2, REL-5-1-1), util/getfiles.c (1.2, REL-5-1-1), util/getfiles.h (1.2, REL-5-1-1), util/managedList.c (1.2, REL-5-1-1), util/managedList.h (1.2, REL-5-1-1), util/misc.c (1.2, REL-5-1-1), util/misc.h (1.2, REL-5-1-1), util/prefFile.c (1.2, REL-5-1-1), util/prefFile.h (1.2, REL-5-1-1), util/printUtils.c (1.2, REL-5-1-1), util/printUtils.h (1.2, REL-5-1-1), util/vmsUtils.c (1.2, REL-5-1-1), util/vmsUtils.h (1.2, REL-5-1-1): 5.1.1 baseline 2000-09-09 22:12 tringali * Makefile (1.1), README (1.1), nc.man (1.1), nedit.doc (1.1), nedit.man (1.1), source/Makefile.common (1.1), source/Makefile.dec (1.1), source/Makefile.hp (1.1), source/Makefile.ibm (1.1), source/Makefile.linux (1.1), source/Makefile.osf (1.1), source/Makefile.sgi (1.1), source/Makefile.solaris (1.1), source/Makefile.sunos (1.1), source/Makefile.ultrix (1.1), source/comnedit.com (1.1), source/file.c (1.1), source/file.h (1.1), source/help.c (1.1), source/help.h (1.1), source/highlight.c (1.1), source/highlight.h (1.1), source/highlightData.c (1.1), source/highlightData.h (1.1), source/interpret.c (1.1), source/interpret.h (1.1, REL-5-1-1), source/lnknedit.com (1.1), source/macro.c (1.1), source/macro.h (1.1, REL-5-1-1), source/menu.c (1.1), source/menu.h (1.1), source/n.bm (1.1, REL-5-1-1), source/nc.c (1.1), source/nedit.bm (1.1, REL-5-1-1), source/nedit.c (1.1), source/nedit.h (1.1), source/nedit_options_file.opt (1.1, REL-5-1-1), source/parse.c_noyacc (1.1, REL-5-1-1), source/parse.h (1.1, REL-5-1-1), source/parse.y (1.1), source/preferences.c (1.1), source/preferences.h (1.1), source/regularExp.c (1.1), source/regularExp.h (1.1), source/search.c (1.1), source/search.h (1.1), source/selection.c (1.1), source/selection.h (1.1), source/server.c (1.1), source/server.h (1.1, REL-5-1-1), source/shell.c (1.1), source/shell.h (1.1), source/shift.c (1.1), source/shift.h (1.1), source/smartIndent.c (1.1), source/smartIndent.h (1.1), source/tags.c (1.1), source/tags.h (1.1), source/text.c (1.1), source/text.h (1.1), source/textBuf.c (1.1), source/textBuf.h (1.1), source/textDisp.c (1.1), source/textDisp.h (1.1), source/textDrag.c (1.1), source/textDrag.h (1.1, REL-5-1-1), source/textP.h (1.1), source/textSel.c (1.1), source/textSel.h (1.1, REL-5-1-1), source/undo.c (1.1), source/undo.h (1.1), source/userCmds.c (1.1), source/userCmds.h (1.1), source/window.c (1.1), source/window.h (1.1), util/DialogF.c (1.1), util/DialogF.h (1.1), util/Makefile.common (1.1), util/Makefile.dec (1.1), util/Makefile.hp (1.1), util/Makefile.ibm (1.1), util/Makefile.linux (1.1), util/Makefile.sgi (1.1), util/Makefile.solaris (1.1), util/Makefile.sunos (1.1), util/Makefile.ultrix (1.1), util/comutil.com (1.1, REL-5-1-1), util/fileUtils.c (1.1), util/fileUtils.h (1.1), util/fontsel.c (1.1), util/fontsel.h (1.1), util/getfiles.c (1.1), util/getfiles.h (1.1), util/managedList.c (1.1), util/managedList.h (1.1), util/misc.c (1.1), util/misc.h (1.1), util/prefFile.c (1.1), util/prefFile.h (1.1), util/printUtils.c (1.1), util/printUtils.h (1.1), util/vmsParam.h (1.1, REL-5-1-1), util/vmsUtils.c (1.1), util/vmsUtils.h (1.1) (utags: REL-5-0-2): 5.0.2 baseline nedit-5.6.orig/Makefile0000644000175000017500000000475310127070671013564 0ustar paulpaul# $Id: Makefile,v 1.19 2004/09/30 20:51:05 n8gray Exp $ SHELL=/bin/sh # # Makefile for NEdit text editor # # Targets are the suffixes of the system-specific makefiles in # the makefiles/ directory. # For example, to build NEdit for Solaris, give the command # # make solaris # # This builds an intermediate library in the util/ directory, # then builds the nedit and nc executables in the source/ directory. # all: @echo "Please specify target:" @echo "(For example, type \"make linux\" for a Linux system.)" @(cd makefiles && ls -C Makefile* | sed -e 's/Makefile.//g') .DEFAULT: @- (cd Microline/XmL; if [ -f ../../makefiles/Makefile.$@ -a ! -f ./Makefile.$@ ];\ then ln -s ../../makefiles/Makefile.$@ .; fi) @- (cd Xlt; if [ -f ../makefiles/Makefile.$@ -a ! -f ./Makefile.$@ ];\ then ln -s ../makefiles/Makefile.$@ .; fi) @- (cd util; if [ -f ../makefiles/Makefile.$@ -a ! -f ./Makefile.$@ ];\ then ln -s ../makefiles/Makefile.$@ .; fi) @- (cd source; if [ -f ../makefiles/Makefile.$@ -a ! -f ./Makefile.$@ ];\ then ln -s ../makefiles/Makefile.$@ .; fi) (cd util; \ $(MAKE) -f Makefile.$@ verify_config && \ $(MAKE) -f Makefile.$@ libNUtil.a) (cd Xlt; $(MAKE) -f Makefile.$@ libXlt.a) (cd Microline/XmL; $(MAKE) -f Makefile.$@ libXmL.a) (cd source; $(MAKE) -f Makefile.$@ nedit nc) # This should not be in the default build, as users may not have Perl # installed. This is only interesting to developers. docs: (cd doc; $(MAKE) all) # We need a "dev-all" target that builds the docs plus binaries, but # that doesn't work since we require the user to specify the target. More # thought is needed clean: (cd util; $(MAKE) -f Makefile.common clean) (cd Xlt; $(MAKE) -f Makefile.common clean) (cd Microline/XmL; $(MAKE) -f Makefile.common clean) (cd source; $(MAKE) -f Makefile.common clean) realclean: clean (cd doc; $(MAKE) clean) # # The following is for creating binary packages of NEdit. # RELEASE=nedit-5.5-`uname -s`-`uname -m` BINDIST-FILES=source/nedit source/nc README COPYRIGHT ReleaseNotes doc/nedit.doc doc/nedit.html doc/nedit.man doc/nc.man doc/faq.txt dist-bin: $(BINDIST-FILES) rm -rf $(RELEASE) mkdir -p $(RELEASE) cp $(BINDIST-FILES) $(RELEASE)/ strip $(RELEASE)/nedit $(RELEASE)/nc chmod 555 $(RELEASE)/nedit $(RELEASE)/nc tar cf $(RELEASE).tar $(RELEASE) compress -c $(RELEASE).tar > $(RELEASE).tar.Z -gzip -9 -c $(RELEASE).tar > $(RELEASE).tar.gz -bzip2 -9 -c $(RELEASE).tar > $(RELEASE).tar.bz2 rm -rf $(RELEASE) $(RELEASE).tar nedit-5.6.orig/README0000644000175000017500000006635711110456077013015 0ustar paulpaul NEdit Version 5.6, October 2008 $Id: README,v 1.49.2.1 2008/10/08 14:16:59 tringali Exp $ NEdit is a multi-purpose text editor for the X Window System, which combines a standard, easy to use, graphical user interface with the thorough functionality and stability required by users who edit text eight hours a day. It provides intensive support for development in a wide variety of languages, text processors, and other tools, but at the same time can be used productively by just about anyone who needs to edit text. As of version 5.1, NEdit may be freely distributed under the terms of the GNU General Public License: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. In addition, as a special exception to the GNU GPL, the copyright holders give permission to link the code of this program with the Motif and Open Motif libraries (or with modified versions of these that use the same license), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than linking with Motif/Open Motif. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License in the file COPYRIGHT as part of this distribution; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. NEdit sources, executables, additional documentation, and contributed software are available from the NEdit web site at http://nedit.org. AUTHORS NEdit was written by Mark Edel, Joy Kyriakopulos, Christopher Conrad, Jim Clark, Arnulfo Zepeda-Navratil, Suresh Ravoor, Tony Balinski, Max Vohlken, Yunliang Yu, Donna Reid, Arne Førlie, Eddy De Greef, Steve LoBasso, Alexander Mai, Scott Tringali, Thorsten Haude, Steve Haehn, Andrew Hood, Nathaniel Gray, and TK Soh. The regular expression matching routines used in NEdit are adapted (with permission) from original code written by Henry Spencer at the University of Toronto. The Microline widgets are inherited from the Mozilla project. Syntax highlighting patterns and smart indent macros were contributed by: Simon T. MacDonald, Maurice Leysens, Matt Majka, Alfred Smeenk, Alain Fargues, Christopher Conrad, Scott Markinson, Konrad Bernloehr, Ivan Herman, Patrice Venant, Christian Denat, Philippe Couton, Max Vohlken, Markus Schwarzenberg, Himanshu Gohel, Steven C. Kapp, Michael Turomsha, John Fieber, Chris Ross, Nathaniel Gray, Joachim Lous, Mike Duigou, Seak Teng-Fong, Joor Loohuis, Mark Jones, and Niek van den Berg. VERSION 5.6 Version 5.6 is a maintenance release. See the ReleaseNotes file for a more detailed description of these new features and a list of bugs fixed in this version. BUILDING NEDIT Pre-built executables will be available for many operating systems, including most major Unix and VMS systems. Check out the NEdit web page at http://nedit.org If you have downloaded a pre-built executable you can skip ahead to the section called INSTALLATION. Otherwise, the requirements to build NEdit from the sources are: - ANSI C89 system (compiler, headers, libraries) - make utility (eg, GNU make) - X11R5 development stuff (headers, libraries), or newer - Motif 1.2 or above (Motif 1.1 might work, but is no longer supported) This GUI library is a standard part on most systems which have an X11 installation. Most commercial Unix systems feature this, others may require a separate installation. A "free" (LGPL'ed) alternative to Motif, called LessTif, is available. See the LessTif section under PLATFORM SPECIFIC ISSUES for details. Optionally one may use: - yacc (or GNU bison) The two directories called 'source' and 'util' contain the sources for NEdit. 'util' should be built first, followed by 'source'. The makefile in NEdit's root directory can be used to build both in sequence if your system is one of the supported machines and no modifications are necessary to the makefiles. To build NEdit from the root directory, issue the command: 'make '; where is one of suffixes of a makefile in the directory 'makefiles'. For example, to build the Silicon Graphics version, type: make sgi If everything works properly, this will produce two executables called 'nedit' and 'nc' in the directory called 'source'. The Source Directories Since executables are already available for the supported systems, you are probably not just rebuilding an existing configuration, and need to know more about how the directories are organized. The util directory builds a library file called libNUtil.a, which is later linked with the code in the source directory to create the nedit executable. The makefiles in both source directories consist of two parts, a machine dependent part and a machine independent part. The machine dependent makefiles can be found in the directory called 'makefiles', and contain machine specific header information. They invoke a common machine independent part called Makefile.common (which in turn includes also Makefile.dependencies). To compile the files in either of these directories, copy or link one of the system-specific makefiles from the directory 'makefiles' into the directory, and issue the command: make -f Makefile. (where is the makefile suffix). Alternatively, you can name the file 'Makefile' and simply type "make". If no makefile exists for your system, you should start from Makefile.generic, which is extensively commented. Contact the developer at develop@nedit.org for help. Building NEdit on VMS Systems A command file is provided for compiling and linking files from all source directories. To build on OpenVMS change directory into [.makefiles] and run 'buildvms.com'. Additional Settings Some C preprocessor macros may be used to en/disable certain parts of the code. Usually this correponds to some non-important features being selected or certain workarounds for platform-specifc problems. Those which might be useful on more than one platform are documented in makefiles/Makefile.generic. Note that a special compilation flag, namely REPLACE_SCOPE, is currently available. Its purpose is to allow the evaluation of two alternative (but functionally equivalent) Replace/Find dialog box layouts. By default, NEdit is built with a Replace/Find dialog containing 2 rows of push buttons. Compiling with the REPLACE_SCOPE flag enables an alternative layout with a row of radio buttons for selecting the scope of the replace operations. Eventually, one of these alternatives will probably disappear, but up to now, the NEdit developers have not been able to decide which one to drop. Please give them both a try and let us know which one you prefer (via the discuss mailing list, for instance). Another compilation flag, HAVE__XMVERSIONSTRING, adds additional information about the Motif version in the menu item "Help->Version" or the command line option "-version". Whether this is available on your system depends on the Motif implementation. It is known to work with OpenMotif 2.1.30, and Motif on Solaris 2.6 and AIX 4.3.3. INSTALLATION NEdit consists of a single, stand-alone executable file which does not require any special installation. To install NEdit on Unix systems, simply put the nedit executable in your path. To use NEdit in client/server mode (which is the recommended way of using it), you also need the nedit client program, nc, which, again, needs no special installation. On some systems, the name nc may conflict with the 'netcat' program. In that case, choose a different name for the executable and simply rename it. The recommend alternative is 'ncl'. Don't forget to put the man-pages for nedit and nc into a place where your man command is able to find them (e.g. /usr/man/man1/nedit.1), and don't forget to rename nc.man to ncl.man if you've renamed nc to ncl. On VMS systems, nedit and nc must be defined as a foreign commands so that they can process command line arguments. For example, if nedit.exe were in the directory mydir on the disk called mydev, adding the following line to your login.com file would define the nedit command: $ ned*it :== $mydev:[mydir]nedit.exe RUNNING NEDIT To run NEdit, simply type 'nedit', optionally followed by the name of a file or files to edit. On-line help is available from the pulldown menu on the far right of the menu bar. For more information on the syntax of the nedit command line, look under the heading of "NEdit Command Line". The recommended way to use NEdit, though, is in client/server mode, invoked by the nc executable. It allows you to edit multiple files within the same instance of NEdit (but still in multiple windows). This saves memory (only one process keeps running), and enables additional functionality (such as find & replace accross multiple windows). See "Server Mode and nc" in the help menu for more information. If you are accessing a host Unix system from a remote workstation or X terminal, you need to set the Unix environment variable for your display: csh: % setenv DISPLAY devicename:0 sh, ksh, bash, zsh: % export DISPLAY=devicename:0 where devicename is the network node name (hostname) of the workstation or X terminal where you are typing. On VMS systems, the equivalent command is: $ set display/create/node=devicename PLATFORM SPECIFIC ISSUES Systems with LessTif, rather than Motif libraries As of Lesstif 0.93.18, NEdit is very stable with Lesstif. You can get the latest LessTif version from http://www.lesstif.org. If you are having trouble building or running NEdit with LessTif, remember there are pre-compiled statically linked executables available from our website. Known bugs which might show off in NEdit linked with LessTif include: 1) Some dialogs which are intended to be modal (prevent other activity while up) are not, and doing other actions while these dialogs are up can cause trouble (.89.9+) 2) Switching to continuous wrap mode, sometimes the horizontal scroll remains partially drawn after the change, rather than disappearing completely as it should. (.89.9+) 3) Secondary selection operations are not yet supported in text fields. 4) Status bar is blank after usage of Incremental Search field (0.93.18+-) Linux Systems Red Hat Linux, as of version 8.0, no longer automatically reads X resources out of the ~/.Xdefaults file. Instead, it reads a file named ~/.Xresources. Any customizations stored in ~/.Xdefaults will not be honored, for all X applications. To fix this, copy the resources into ~/.Xdefaults, or link the files together. The default key bindings for arrow keys in fvwm interfere with some of the arrow key bindings in NEdit, particularly, Ctrl+Arrow and Alt+Arrow. You may want to re-bind them either in NEdit (see Customizing -> Key Binding in the Help menu) or in fvwm in your .fvwmrc file. Some older Linux distributions are missing the /usr/X11R6/lib/X11/XKeysymDB file, which is necessary for running Motif programs. When XKeysymDB is missing, NEdit will spew screenfulls of messages about translation table syntax errors, and many keys won't work. You can obtain a copy of the XKeysymDB file from the contrib sub-directory of the NEdit distribution directory. Linux binaries were built statically by default before NEdit 5.6. This has changed with 5.6 to make better use of distribution-specific features. The call 'make linux' will now create binaries dynamically linked to Motif or Lesstif; calling 'make linux-static' will create static binaries. Mac OS X Systems NEdit is an X Window application and thus requires an X Window server, such as Apple's X11.app or XFree86.org's XDarwin, to be running. If you are building NEdit yourself, you will probably need to edit makefiles/Makefile.macosx to select the correct version of Motif. There are comments in the makefile to help you do this correctly. Note that the developers use the OpenMotif 2.1.30 package available (at the time of writing) at: http://msg.ucsf.edu:8100/~eric/ SGI Systems Beginning with IRIX 6.3, SGI is distributing a customized version of NEdit along with their operating system releases. Their installation uses an app-defaults file (/usr/lib/X11/app-defaults/NEdit) which overrides the default settings in any new nedit version that you install, and may result in missing accelerator keys or cosmetic appearance glitches. If you are re-installing NEdit for the entire system, just remove the existing app- defaults file. If you want to run a newer copy individually, get a copy of the app-defaults file for this version the contrib sub-directory of the distribution directory for this version on ftp.nedit.org (/pub// contrib/nedit.app-defaults), and install it in your home directory or set the environment variables XAPPLRESDIR or XUSERFILESEARCHPATH to point to a directory and install it there. In all cases, the file should be named simply 'NEdit'. No additional installation or resource settings are necessary on IRIX systems before 6.3 HP-UX Systems If you are using HPVUE and have trouble setting colors, for example part of the menu bar stubornly remains at whatever HPVUE's default is, try setting: nedit*useColorObj: False IBM AIX Systems Due to an optimizer bug in IBM's C compiler, the file, textDisp.c, must be compiled without optimization on some AIX systems. Solaris (SunOS 5.3 and beyond) Systems The nedit_solaris executable may require the environment variable OPENWINHOME to be set to the directory where Open Windows is installed. If this is not set properly, NEdit will spew screenfulls of messages about translation table syntax errors. Solaris 2.4 -- Add -DDONT_HAVE_GLOB to the CFLAGS line in Makefile.solaris. Solaris 2.5 -- Solaris 2.5 systems were shipped with a bad shared Motif library, in which the file selection dialog (Open, Save, Save As, Include, etc.) shows long path names in the file list, but no horizontal scroll bar, and no way to read the actual file names. Depending on your system, the patch is one of ID# 103461-07, # 102226-19, or # 103186-21. It affects all Motif based programs which use the library. If you can't patch your system, you might want to just try the nedit_sunos executable (from ftp.nedit.org /pub/), which is statically linked with a good Motif. You can also set the X resource: nedit.stdOpenDialog to True, which at least gives you a text field where you can enter file names by hand. Solaris 2.6 -- If you're experiencing performance problems (windows come up slowly), the patch for Sun's shared Motif library is ID# 105284-04. Installing the patch alone will improve nedit's performance dramatically. The patch also enables a resource, *XmMenuReduceGrabs. Setting this to True will eliminate the delay completely. SunOS 4.x Systems On some SunOS systems, NEdit will also complain about translation table syntax errors. This happens when Motif can't access the keysym database, usually located in the file /usr/lib/X11/XKeysymDB. If this file exists on your system, but NEdit fails to locate it properly, you can set the environment variable XKEYSYMDB to point to the file. If you can't find the file, or if some of the errors persist despite setting XKEYSYMDB, there is a XKeysymDB which you can use to update or replace your /usr/lib/X11/XKeysymDB file available in the contrib sub-directory of the NEdit distribution directory. If you don't want to change your existing XKeysymDB file, make a local copy and set XKEYSYMDB to point to it. If you find that some of the labeled keys on your keyboard are not properly bound to the corresponding action in NEdit, try the following: 1) Get a copy of motifbind.sun (for Sun standard keyboards), or motifbind.sun_at (for Sun PC style keyboards) from the NEdit contrib directory on ftp.nedit.org:/pub//contrib. 2) Copy it to a file called .motifbind in your home directory. 3) Shutdown and restart your X server. COMPATIBILITY WITH PREVIOUS VERSIONS Existing .nedit Files As of version 5.1, NEdit employs a built-in upgrade mechanism which will automatically detects .nedit files of older versions. In general, NEdit will try to convert and insert entries to match the latest version. However, in certain cases where the user has customized the default entries, NEdit will leave them untouched (except for possible syntactic conversions). As a result, the latest syntax highlighting patterns for certain languages may not get activated, for instance, if the user has customized the entries. The latest default patterns can always be activated through the Preferences->Syntax Highlighting->Recognition Patterns menu, though. Next, some version specific upgrading issues are listed. Note that non-incremental upgrading (eg., from 5.0 to 5.2) is supported too. * Upgrading from 5.4 to 5.5 - Changes in the widget hierarchy, possibly effecting resource settings In NEdit 5.4 and below, the widget hierarchy consisted of a separate widget tree for each window. This was rather unconventional and caused certain problems. In 5.5, the hierarchy was changed such that all widgets belong to a single tree with a single root widget. For instance, with 5.4, the top of the widget hierarchy for a 2-window NEdit session looks as follows: NEdit nedit +-- XmMainWindow main NEdit nedit +-- XmMainWindow main In 5.5, the same session results in the following tree: NEdit nedit +-- TopLevelShell textShell | +-- XmMainWindow main +-- TopLevelShell textShell +-- XmMainWindow main Users with advanced X-resource settings may be affected by this change and may have to adapt their resource specifications. - Minor change to the regular expression word boundary semantics In 5.4, the semantics for word boundary regular expressions ('<', '>', and '\B') were changed to behave in a more intuitive way (see Upgrading from 5.3 to 5.4 below). However, this introduced an inconsistency between the regular expressions and several other places in NEdit where word boundaries were taken into account. Therefore, the changes were partially reverted to restore consistency, but without giving up the benefits of the more intuitive word boundary definition. More in particular, a boundary between two characters is now considered to be a word boundary only if exactly one of the characters is a delimiter. This change will have little or no consequences for most users. * Upgrading from 5.3 to 5.4 - Resource syntax Basic colors, like the text foreground and background, are now true preferences. A new dialog (Preferences > Default Settings > Colors) is provided to change them, previously only changeable from X resources. Upon starting, NEdit will migrate any custom colors you have set from the old X resources. Most users will not need to do anything. However, if you used X resources to dynamically change the colors on different invocations, you will need to use the new application-level resources instead. See the .nedit file for details. In 5.3, color resources needed to be qualified by "nedit*" in order to prevent problems when the deepest color visual was not the default. This is no longer necessary, and the qualification may be removed. - New location of configuration files The default location and name of NEdit's resource files has been changed. The most important change is the fact that they can now be stored in a custom directory, defined by the NEDIT_HOME environment variable. If the variable is not set, the directory defaults to ~/.nedit. The files have been renamed as follows: ~/.nedit -> $NEDIT_HOME/nedit.rc ~/.neditmacro -> $NEDIT_HOME/autoload.nm ~/.neditdb -> $NEDIT_HOME/nedit.history For backward compatibility reasons, NEdit continues to use the old convention when these files are already present. No attempt is made to force the user to adopt the new convention. Users that would like to migrate to the new setup can do so manually by moving and renaming the files. - Changed regular expression word boundary semantics and its effect on the syntax highlighting patterns. During the 5.4 development cycle, it was noted that the implementation of NEdit's regular expression word boundary matching was rather unconventional. More in particular, the '<', '>', and '\B' patterns interpreted the boundary between any two characters of which at least one was not a word character as a word boundary. A striking effect of this was that the boundary between two spaces was considered to be a word boundary, which is obviously rather unintuitive. This has been corrected in 5.4: the boundary between two characters is a word boundary, only if exactly one of them is a word character. Several of the built-in syntax highlighting patterns (implicitly) relied on the old word boundary interpretation and they have been corrected too. However, if the user has customized some of these buggy built-in highlighting patterns, the automatic upgrading routines will NOT upgrade them in order not to loose any customizations. It is left up to the user to correct his/her customized patterns manually (using the corrected built-in patterns as a guideline). The following is a list of all language modes and patterns that have been corrected: Ada: Based Numeric Literals Awk: Numeric constant C++: numeric constant C: numeric constant CSS: property, selector pseudo class Java: decimal const, case numeric const JavaScript: Numeric Lex: numeric constant, markers Matlab: Numeric const NEdit Macro: Built-in Vars, Numeric Const Pascal: TP Numeric Values: Perl: dq string, sq string, bq string, subroutine call, numerics, re match PostScript: Number, Operator1 Python: Number SQL: data types, keywords2 Sh Ksh Bash: keywords, built ins Tcl: Keywords VHDL: Numeric Literals Verilog: Reserved WordsA, Numeric Literals, Delay Word, Pins Declaration XML: element declaration keyword Yacc: numeric constant, percent keyword, markers So, if the user has customized the highlighting definitions for any of these language modes (not restricted to the listed patterns), (s)he is strongly advised to restore the default patterns in the syntax highlighting dialog and to re-apply his/her customizations. Moreover, it is advised to check any custom language modes for potential boundary matching problems as described above. * Upgrading from 5.2 to 5.3 There are no major changes in the format of the .nedit file for version 5.2. Users that have customized the X Resources syntax highlighting pattern may consider restoring the default patterns, as they resolve a performance issue when editing the .nedit file itself, for instance. * Upgrading from 5.1 to 5.2 There are no major changes in the format of the .nedit file for version 5.2. NEdit will try to insert additional entries for the newly supported language modes and syntax highlighting patterns (CSS, Regex, and XML) and highlight styles (Pointer, Regex, Warning). Moreover, the formerly boolean 'showMatching' option will silently be converted to a tri-state value. Users that have customized some of the syntax highlighting patterns may consider restoring the default patterns, as many of them have been improved considerably. * Upgrading from 5.0 to 5.1 NEdit 5.1 makes significant changes to the syntax of regular expressions. Mostly, these are upward compatible, but two changes; introducing the brace operator, and changing the meaning of \0; are not. Brace characters must now be escaped with backslash, and & must be used in place of \0 in substitutions. NEdit 5.1 employs a built-in upgrade mechanism which will automatically detect pre-5.1 .nedit files and fix regular expressions which appear in user-defined highlight patterns. The automatic upgrade mechanism, however, can not fix regular expression problems within user-defined macros. If you have a macro which is failing under NEdit 5.1, you will have to fix it by hand. * Upgrading from pre-5.0 If you are upgrading from a pre-5.0 version of NEdit, there are significant changes to the macro language, and you are best off simply editing out the nedit.macroCommands section of your .nedit file, generating a new .nedit file, and then re-introducing your user-written commands into the new file. Most macros written for previous versions will function properly under the new macro language. The most common problems with old macros is lack of a terminating newline on the last line of the macro, and the addition of "<", ">", and now "{" to the regular expression syntax. These characters must now be escaped with \ (backslash). Also, if you have been using a font other than the default for the text portion of your NEdit windows, be sure to check the Preferences -> Default Settings -> Text Font dialog, and select highlighting fonts which match your primary font in size. Matching in height is desirable, but not essential, and sometimes impossible to achive on some systems. When fonts don't match in height, turning on syntax highlighting will cause the window size to change slightly. NEdit can handle unmatched font sizes (width), but leaving them unmatched means sometimes columns and indentation don't line up (as with proportional fonts). FURTHER INFORMATION More information is available in the file nedit.doc in this kit, from NEdit's on-line help system, the man-pages and from the enclosed FAQ file. There is also a web page for NEdit at: http://nedit.org. For discussion with other NEdit users, or to receive notification of new releases you can subscribe to one or more of the NEdit mailing lists, announce@nedit.org, discuss@nedit.org or develop@nedit.org. The NEdit on-line help has information on subscribing under Help -> Mailing Lists. REPORTING BUGS The preferred way to report bugs is to submit an entry on our web-based bug tracker at: http://sourceforge.net/projects/nedit/ The NEdit developers subscribe to both discuss@nedit.org and develop@nedit.org, either of which may be used for reporting bugs. If you're not sure, or you think the report might be of interest to the general NEdit user community, send the report to discuss@nedit.org. If it's something obvious and boring, like we misspelled "anemometer" in the on-line help, send it to develop. If you don't want to subscribe to these lists, please add a note to your mail about cc'ing you on responses. nedit-5.6.orig/ReleaseNotes0000644000175000017500000007505711110456077014446 0ustar paulpaul Release Notes for NEdit Version 5.6, October 2008 $Id: ReleaseNotes,v 1.63.2.3 2008/11/05 09:17:20 lebert Exp $ This file contains last minute notes to users about the release, which are not included in the documentation or README files included with the distribution kits. It also contains change information, for users who are interested in what bugs have been fixed, and what features have been added in the current version. If you are upgrading NEdit from a version prior to 5.0, please see the notes in the README file which came with the (source or executable) distribution kit, about updating macros and font settings in your .nedit file. New Features in 5.6 - The macro variable $VERSION returns NEdit's version number. - The new macro function filename_dialog() can be used to query a file name from the user by using the usual file selection dialog. Bugs fixed in 5.6 - Fix for SF bug #2222159: File was not reload when type was changed externaly - Fix for SF bug #2149312: parse error with zero menu entries. - Force a terminating \n on macro file load time, to prevent syntax errors with statements on the last line. (util/fileUtils.c:ReadMacroFile()) (SF bug #2038921) - Fix multiple memory leaks in interpret.c:PromoteToGlobal() (SF bug #1894726) - Fix for SF bug #1908890: window title not updated. - Fix for SF bug #1730611: $match_syntax_based is not set. - Crash on window close when a "File modified externally" dialog was up (SF bug #1578869). - Crashes and artifacts when using ARGB visuals (SF bugs #1579544, #1030467, #1030192, and #1458006). - The text insertion cursor does no longer blink while typing (SF bug #906878). - The status bar reflects a changed keybinding in the shell command banner. - There is now a pattern for highlighting nested command substitution in shell scripts (SF patch #1010742). - Duplicate display bugs SF#464967 and SF#1041077 are fixed. - A typo in Ada's syntax highlighting patterns is fixed (SF bug #858874). - The shell used to run programs from the shell_command() macro function and from the Shell menu is now part of NEdit's normal settings, and no longer in the X server's settings. It also defaults to the user's login shell, not /bin/csh. This fixes SF#403738 and SF#880607. - File history is now consistent across multiple sessions (SF bug #557032). - If a macro file contains function definitions mixed with code segments the code segments were excuted in the wrong order in certain cases. This is fixed (SF bug #622291). - The current file name is (again) displayed in the Save As dialog text field. (SF bug #1451337) - A crash caused by highlighting patterns with complex regular expressions has been fixed. (SF bug #1536002) - Crashes when the maximum number of patterns in a hightlighting pattern set was exceeded, have been fixed. (SF bug #1536451) - Files are now optionally opened without format changes (SF bug #1003241). - Replace operation where the result exceeded a fixed length silently clipped the result. The limit has been increased and the behaviour on failure is now configurable. (SF bug #1015499) - NEdit can now optionally detect and avoid symlinks (SF bug #1027788). - A minor visual glitch has been fixed (SF bug #1055649). - NEdit asks the user with a dialog if it detects that a document's file is no longer accessible on disk. This dialog is changed to better match expected usage pattern (SF bug #1066144). - Various documentation bugs are fixed (SF bugs #1066765, #1078397, #1110024, #1471868) - Some minor usability bugs have been fixed (SF bugs #1371896, #1508608, #1515134, #1066692). - New highlighting pattern are now used immediately (SF bug #1117848). - Changes in case no longer modifiy the text if no change is actually performed (SF bug #1333103). - Some Linux distros ship with XKEYSYMDB set to a bogus filename which breaks all Motif applications. NEdit ignores that, and let X fall back on the default which is far more likely to work (SF bug #1564907). - Fixed a problem in the macro language on 64-bit systems (SF bug #1625283). - Long macro function names could cause a buffer overflow (SF bug #1640304). - The built-in macro "Make C prototypes" choked on some comments (SF bug #1574071). - Fixed a small bug while inserting special characters (SF bug #682004). - Fixed a translation bug which crashed NEdit on pressing osfInsert in the help window (SF bug #1772468). - Fixed bad exception handling of default macros (SF bug #1731384). New features in 5.5 - The most important new feature is the introduction of window tabs (SF patches #569287 and #893177). - More efficient string search operations for the macro language. - Auto-scrolling is now (partly) configurable through the preference menu. - Find and Clear buttons for i-search bar (SF patch #891884). - Faster user-defined menu creation (SF patch #891126). - Open documents on current desktop (SF patch #963120) - Superuser receives a warning when trying to overwrite a read-only file. - Simplified global font resources. - Macro language: added new $args[] array and removed 9 arguments limit for macros - Improved Latex & Python syntax highlighting patterns Bugs fixed in 5.5 - If underscore (_) is among the word delimiters for a language mode then word boundary regexes will work as expected. (SF bug #1008656) - Problem with writing history file on VMS (SF bug #933146). - Race condition fix for running NEdit in -sync mode (SF bug #978104). - Removed obsolete special window title treatment on SGI (SF bug #779454). - Forbid the deletion of the "Plain" Text Drawing Style (SF patch #970491). - File descriptor handling fix that allows shell commands to be invoked asynchronously. - Crash on Solaris when dragging a calltip (SF bug #925951). - Preference resource name mistakes (SF bug #884862). - Don't delete incremental backup files when incremental backups are off (SF bug #878183). - Allow zero-length ranges to be added to range sets (SF bug #871209). - Improved shell syntax highlighting patterns (SF bug #770855). - Regular expression crash fix (SF bug #987102). Changes since 5.5RC1 - Using exit() in macro no longer causes hang (SF bug #999021). - Updated rangeset documentation (SF bug #1005442). - Minor changes to the regular expression word boundary semantics (SF bug #1008656). - Tabs keep reasonable sizes when things get crowded (SF bug #1005064). - Many unnecessary file status checks are avoided. - Warn On Exit also affects closing of window with multiple tabs (SF bug #1006830) - "File Modified Externally" dialogs are only allowed for top tabs. - Broken virtual key bindings workaround was restored (problems with page-up and page-down). - Preference file number was bumped. - Dialogs' OK button layout fixes. - Fix for SF bug #999820: spaces in dialog button mnemonics. - Fix for SF bug #996786: problems with overtype mode Changes since 5.5RC2 - Less confusing menu wording (SF bug #1023089). - Shell command output is now sent to a new window or a new tab, depending on the tabbed editing preference settings. - Detaching/Moving non-top tab should not change top tab (SF bug #1020035). - Opening new window from a tabbed window no longer diminishes size (SF bug #1011233). New Features in 5.4 - Calltips (SF patch #495286) - Rangesets (SF patch #529298, #628933) - Backlighting (SF patch #529298) - Highlighting information macros (SF patch #529298) - Full mouse wheel support for XFree86 (SF patch #715941) - Look-behind matching for regular expressions (SF patch #530308) - Regular expression and syntax highlighting speed-ups - Flexible resource file location (SF patch #484674) See the section "Upgrading from 5.3 to 5.4" of the README file for more information. - Color dialog (SF patch #595330) - Option to auto-hide mouse pointer while typing - Option to keep cursor away from top and bottom of the screen - Check for real changes of externally modified files (SF patch #602426) - Synchronized interaction between nc and nedit (SF patch #403647) - Several smaller improvements on usability and speed - Several smaller improvements to the macro language (SF patch #552760, ...) Bugs Fixed in 5.4 - Unconvential word boundary semantics for regular expressions have been corrected (including affected syntax highlighting patterns). See the section "Upgrading from 5.3 to 5.4" of the README file for important information. - Config files didn't accept non-Unix file format (SF bug #411092) - Removed regex search bugs (SF bug #429110, #515120) - Smart-indent macros were unaffected by language mode renames (SF bug #439867) - All dialogs have titles now (SF bug #480960) - Giving long filenames at startup caused buffer overflows (SF bug #488412) - Made sure that dialogs don't get wider than screen (SF bug #488593, #489614, #713999) - Workaround for Motif drag icon bug (SF bug #526981: Crash using btn2 on help window buttons and SF bug #582469: 5.3 crash when selecting stats line text). - Dragging a rectangular selection could delete characters (SF bug #557225) - Show Matching Range bug (SF bug #559902) - Keyboard-based rectangular selections were forgotten if the selection ever became zero-width. - Workaround for KDE's FONTLIST bug (SF bug #561659) - Paths were still shown in current's window Windows menu after global option was changed (SF bug #564782) - Scrolling to searched or undone/redone section stopped short (SF bug #578551) - Removed flicker in stats line due to bug prevention (SF bug #594838) - Crash while dismissing a resized help window (SF bug #600175) - Macro functions were evaluated in a wrong order (SF bug #602336, #628552) - Syntax highlighting failures in LaTeX (SF bug #607072) - Crash with wrong values for -tabs option (SF bug #608693) - Macro shortcuts were sensitive to Lock and NumLock (SF bug #612558) - Appending the terminating line break was not reflected in the buffer (SF bug #617840) - A new nc(1) hanged after a server was killed or crashed (SF bug #619231) - Adds (short) list of deprecated macro functions (SF bug #619236) - Removed hazardous command shortcut (SF bug #649442) - Workaround for OpenMotif radio button bug (SF bug #678198: bug in Replace in multiple files). - Typo in SCO makefile (SF bug #689808) - Syntax highlighting routines assumed ASCII encoding (SF bug #700823) - Crash when starting up in a UTF-8 locale (SF bug #703246, 621972) - Crash while manipulating highlighting pattern (SF bug #705495) - Removed flicker in stats line during macro execution (SF bug #713780) - Close pane resize bug (SF bug #715767) - Macro function goto_line_number() only accepted one argument (SF bug #726325) - Newline macro inserting a string caused a crash when triggered through smart indent - Help text foreground was hard-coded to black (SF bug #723096) - System default colors from CDE Style Manager were ignored (SF bug #544053) Changes since 5.4RC1 - Panes didn't inherit the right colors (SF bug #780267) - Fixed Rangeset API usability issues and bugs. - Plain KP Enter now inserts a newline, not (SF bug #779439). - Enabled Motif version checking for xBSD. - SGI: compilation problem (SF bug #780841) - File modification issues (SF bug #782513, SF bug #784442) - Documentation updates. - Color dialog button resize problem. - undoModifiesSelection is no longer saved in .nedit/nedit.rc - Workaround for Lesstif's 'frozen windows' bug. - Fixed calltip parsing problem (SF bug #779681) - Macro language HL pattern updates. - nc -do ... no longer creates unwanted windows (SF bug #785738). - Improved color resource migration. - File accessibility is now determined with access() (SF bug #782518) Changes since 5.4RC2 - Nc crash fix on VMS. - Fixes in highlighting information inspection macros. - Nc -lm command line option fix. New Features in 5.3 This is mainly a bug fix release. The list of new features is therefore limited: - The built-in Help system was revamped. Most notably, a hyperlink mechanism was added for following cross-references. - Enhanced Exuberant ctags support (SF #491109). - Line numbers are available in shell commands (SF #434451). - Goto Line also accepts column numbers (SF #403435). - Automatic line-feed termination when saving is now optional (SF #503073). - A customizable window title (SF #477875/#519092). - Optional syntax based parenthesis matching (iso. purely character based) (SF #513976). Bugs Fixed in 5.3 - Find Definition incorrectly reads the X selection when not needed (SF #520941). - Background popup menu could lock up X-server when used with any of the lock keys on. - Very wide windows when starting NEdit under fvwm (SF #496526). - Workaround for illegal key bindings installed by other Motif applications, causing PageUp/PageDown and arrow keys to stop responding in NEdit (SF #493421/#525903). This is not an NEdit bug, it just looks like one. - Fix for PageUp/PageDown keys not responding (SF #508961). - Crash when running X on 2nd screen (SF #478234, #500353). - Line number display updating in continous wrap mode (SF #516920). - Performance problem with X Resources highlight patterns (SF #481290). - Menu fonts showing up as blocks (SF #434383) - Lockup's in syntax highlighting (especially Perl) (SF #512961). - Crash when using characters with ASCII code >= 128 in syntax highlighting patterns. - Crash when modifying tab distance in continous wrap mode (SF #510631). - Crash when running NEdit in low-depth color modes. - Continous wrap mode + variable width font display bugs. - Potential scroll bar corruption in continuous wrap mode (SF #510765). - Workaround for selection copy/paste problems with recent versions of gnome-terminal. - Jump to tags only referenced by line number. - Composed characters in learned sequence (SF #480966). - Missing titles in some dialogs (SF #480960). - Macro language: continue statement outside loop crash (SF #495293). - Rectangular overstrike past fixes (SF #487945). - Hard-coded statistics line font (SF #487153). - Open filenames starting with a dash (SF #485610). - Crash when closing window of non-existing file while error dialog is up. - Bad CapsLock grab on certain keyboard configurations (SF #482504). - Replacements in rectangular selections could sometimes fail. - Various buffer overflow fixes. - Multiple selection dialog does not pop up on first find (SF #473602). - Tag not found (SF #466742). - Files opened with -read command line option could not be unlocked. New Features in 5.2 - Added built-in patterns for CSS, XML, and regular expressions (Regex). Many other pattern updates. - Support for high- and true-color systems. NEdit now will automatically select the best visual from your X server. This reduces the chance of running out of colors. - New features in the Find and Replace dialogs: o Replacement across multiple windows in a session. o Case sensitivity may be set independently of regular expressions. o Add "Replace and Find" command, which saves keystrokes when doing a large-scale find & replace. - ClearCase version-extended pathnames. - Many new macro subroutines and variables. - Array support in macros. - Range highlighting of matching delimiters. - Undo and Redo highlights the text that has changed, when visible. - Support for wheel mouse scrolling on servers that support it (XFree86). - Improved accelerator key handling. - Insert Control Code dialog accepts value in any valid C notation - Optional beeping when search operations wrap. - Additional default search styles. - Optional displaying of path names in the window list menu. Bug Fixes in 5.2 - Fix a crash when entering an invalid line number in "Goto Line". - Ignore the Caps-Lock key when invoking accelerators. - Fix problems when running NEdit on 64-bit platforms like Alpha - NEdit failed to open files if some directories above were not "readable" - Fix potential crashes if some system calls fail - When no colors are left, attempt to reuse the closest matching color. This allows NEdit's syntax highlighting to better coexist with Netscape, which unfortuntely takes all available colors. - "Overtype" mode is now bound to the Insert key, to be consistent with Motif text fields. - Accelerators now available in confirmation dialogs, and may be invoked without the Alt key. - Don't even try to open a directory for editing - Fix a couple of memory corruption problems New Features in 5.1 - Significant extensions to the regular expression syntax. See details below. - Incremental search, and optional search bar. - New ctags code with full support for Exuberant Ctags, better handling of tag collisions, multiple tag file support, on-demand loading of tag files, and automatic reload of modified tag files. - Optional display of line numbers along the left side of the text. - NEdit can now read and write MS DOS format files. - New built-in syntax highlighting patterns for Lex, PostScript, SQL, Many syntax highlighting pattern improvements. - Improved international character set input - New macro subroutines: list_dialog, getenv, set_language_mode. - Optional warnings about external modifications to files - Clearcase awareness - Session manager restart capability - Default language mode "*" for user-defined menu items, allows per-language variations on a common base - Allow additional modifiers like Sun diamond key in user defined accelerators - Option to sort open previous menu. - -geometry and -iconic command line arguments act per-window, and can be specified via nc - -geometry now specified in characters, rather than pixels - -lm (language mode) command line option - Save As dialog defaults to same file name - Better default fonts for Linux systems - .nedit file version mechanism to make future upgrades easier Bug Fixes in 5.1 - Crash on large amounts of data fed to shell command which does not take input - Delayed secondary windows when executable statements specified in users .neditmacro file - Many corrections to online help - Many highlight patterns corrections - Using window close box in file open/save dialogs leaves nedit server unresponsive - escape in macro dialogs can cause macro hang - Lesstif-specific fixes: attachment warnings in font selector, Work around replace dialog focus bug. - NEdit no longer maintains original protection settings on files. It allows them to be changed externally. Details of Regular Expression Changes in 5.1 Bug Fixes o Fixed bug that caused character classes with a character range not to work properly if one of the range characters was an escaped character. Improvements In Existing Features o Increased maximum number of capturing parentheses from 40 to 50. o Removed optimization that uses `must match' strings (it didn't work and caused more problems than it solved.) o Improved error messages. o Improved Start-Of-Line and End-Of-Line detection by the `^', `$', and the new `\B' (see below) anchors. The Start-Of-Word and End-Of-Word anchors `<' and `>' where not enhanced due to syntax color highlighting pattern compatibility issues. o Changed code to use "unsigned char" in most cases instead of "signed char". Also, use of ANSI character functions (e.g. isdigit(), isspace()) were added wherever possible. These changes should improve support for locales other than "C", for example character sets with accented characters. o Added character escapes for: - \e ASCII escape character (for environments that use the EBCDIC character set, set the EBCDIC_CHARSET compiler symbol to get the EBCDIC equivalent escape character.) - \- minus sign - \{ left brace - \} right brace o Removed the `\"' escape since `"' is not a meta character. o In order to support numeric escapes, use of `\0' as a synonym for `&' in replacement strings was removed. `\0' now signals the start of a numeric (octal) escape sequence (see below.) o Minor tweaks for improved performance. Enhancements o Octal and Hexadecimal Escapes Octal and hexadecimal escapes begin with \0 and \x (or \X) respectively. For example, \052 and \X2A both specify the `*' character. Escapes for null (\00 or \x0) are not valid and will generate an error message. o Shortcut Escapes for Common Character Classes \d digits 0-9 \l letters a-z and A-Z \s whitespace \t, \r, \v, \f, and space \w word characters a-z, A-Z, 0-9, and underscore, `_' `\D', `\L', `\S', and `\W' are the same as the lowercase versions except that the resulting character class is negated. o Anchors The `\B' non-word boundary anchor has been added as the logical opposite of `<' and `>' collectively. This anchor ensures that the left and right characters are either both delimiter characters or both non-delimiter characters. o Word Delimiter Escape Sequences \y Word delimiter character \Y Not a word delimiter character The `\y' token matches any single character that is one of the characters that NEdit recognizes as a word delimiter character, while the `\Y' token matches any character that is NOT a word delimiter character. Note: these are not anchors and DO consume one character of input. o Quantifiers + Minimal (lazy) Matching Quantifiers *? Match zero or more +? Match one at least one ?? Match zero or one These quantifiers match only what is absolutely necessary to achieve a match. + Counting (or Brace) Quantifier {min,max} Match from `min' to `max' times the previous regular expression atom. If `min' is omitted, it is assumed to be zero. If `max' is omitted, it is assumed to be infinity. Whether specified or assumed, `min' must be less than or equal to `max'. If both are omitted, then the construct is the same as `*'. Note that `{,}' and `{}' are both valid brace constructs. A single number appearing without a comma, e.g. `{3}' is short for the `{min,min}' construct, or to match exactly `min' number of times. o Non-Capturing Parentheses Non-Capturing Parentheses are of the form `(?:)' and facilitate grouping only and do not incur the overhead of normal capturing parentheses. o Positive Look-Ahead Positive look-ahead constructs are of the form `(?=)' and implement a zero width assertion of the enclosed regular expression. In other words, a match of the regular expression contained in the positive look-ahead construct is attempted. If it succeeds, control is passed to the next regular expression atom, but the text that was consumed by the positive look-ahead is first unmatched (backtracked) to the place in the text where the positive look-ahead was first encountered. o Negative Look-Ahead Negative look-ahead takes the form `(?!)' and is exactly the same as positive look-ahead except that the enclosed regular expression must NOT match. o Case Sensitivity (?i) Case insensitive; `AbcD' and `aBCd' are equivalent. (?I) Case sensitive; `AbcD' and `aBCd' are different. Regular expressions are case sensitive by default, i.e `(?I)' is assumed. All regular expression meta characters respond appropriately to case insensitivity including character classes and back-references. o Matching Newlines (?n) `.', `[^...]', `\s', `\S' will match newlines (?N) `.', `[^...]', `\s', `\S' do not match newlines `(?N)' is the default behavior. o Comments Comments are of the form `(?#)' and can be inserted anywhere and have no effect on the execution of the regular expression. o Notes on New Parenthetical Constructs Except for plain parentheses, none of the parenthetical constructs capture text. If that is desired, the construct must be wrapped with capturing parentheses, e.g. `((?i Repeat crashes on some systems. - Mouse state can get "stuck" on Alpha-based systems. - Combination of auto-wrap, auto-indent, and unbreakable lines extending the width of the window, caused nedit to unnecessarily insert blank lines. - Incorrect case-insensitive comparison in character sets > 128 bits. - in by-word drag-selection (double click then drag) when begun in the middle of a whitespace selection, anchor would revert to original cursor position rather than maintaining the entire whitespace block. - Language mode names containing spaces could not be used in language sensitive user-defined menu items. - New windows did not always see existing learn/replay sequence, recorded before the window was created. - Possible crash in search_string and search_window macros, when used with long search strings. - Possible crash in get_selection("any") macro. - Under Solaris, crashes on window opening, file dialog, and language mode selection, when user-defined sub-menus were used. - Filenames containing spaces could cause the .neditdb file to become unreadable. - Escape key could not be used to cancel file-selection dialogs when the file list had keyboard focus (which it almost always does). New Features in 5.0.1: - Repeat-over-range, and repeat-to-end capability for repeating last command and learn/replay sequence. - Import capability for loading macro/shell menu commands, highlight patterns, and style sets created by other users. - New macro language routines: string_to_clipboard, clipboard_to_string, toupper, tolower, variables: $em_tab_dist. - Additional default highlight patterns for sh and X resources. - Sorted Open Previous menu. - Numerous improvements to default highlighting patterns and smart indent macros. Bug Fixes in 5.0.1: - Various crashes on Motif 2.0 (Linux and FreeBSD) systems, usually associated with opening files and changing language modes. Usually, but not necessarily, following changes to user-defined menu items. - Background menu activation during drag operation could leave drag unfinished, cause undo to malfunction, and eventually lead to a crash (which was easy to trigger accidentally when the middle button is emulated with mouse-chords on a two button mouse). - X11R6 clients talking to X11R5 servers could crash on font dialog. - Rapid repetition of long macros (such as binding to key and using keyboard repeat) could cause crash. - Several commands which put up dialogs were vulnerable to timing windows where repeating the command could cause a crash. - Calling macro close() routine could cause crash if used to close the window in which the macro was executing. - Using load_macro_file() as an "include" statement in macro files could cause hang. - Artifacts when using non-matching highlight fonts, and making certain types of changes which change the fonts used to display other (not the line being modified) lines in the file. - Auto-newline wrap in overtype mode could duplicate part of wrapped text. - Lower panes in split window mode allowed modification to read-only windows. - Several minor dialog and window focus related problems for explicit (click to focus) users. - Paste Column ignored existing selection. - After copying and re-naming language mode information, highlight patterns and smart indent macros remained attached to the re-named pattern instead of the original. - Trailing newlines should not have been prohibited in Open Selected. - Help for creating smart indent macros was missing. New Features in 5.0 - Completed macro extension language (Simple C/awk-like syntax, safe, fully interruptable) - Syntax highlighting. Built-in patterns for C, C++, Java, Fortran, Pascal, Ada, Perl, Python, Tcl, Awk, Csh, HTML, LaTeX, VHDL, Verilog, and more. - Programmable Smart indent. (Experimentally, at least. There are only macros for C and C++, and they may not fit everyone's programming style.) - Language-sensitive preferences - Continuous wrap mode (long line wrapping), in addition to existing automatic-newline wrapping - User-defined menus can be hierarchical and language-sensitive. - Configurable right-button pop up menu - Pan-scrolling - Searchable on-line help - Word boundary matching (<>) in regular expressions - Repeat command - More dialogs have up-arrow recall - White-space selection via double-click Bug Fixes and Enhancements to Existing Features in 5.0 - No more limits on editing files containing ascii nul characters - Fill Paragraph command handles leading indents - Select to mark - Better directory defaulting in Open Selected and shell commands - Open Selected processes tilde (~) and wildcards - Goto Mark centers scroll position better - Multiple shell commands can be run simultaneously - Shell command execution doesn't block server command processing - Emulated-tab deletion treats auto-indent as emulated tabs - Auto-wrapping of pasted text is optional (off by default) - Notice that default preferences have changed and ask about saving on exit - Selections remain selected after shell command and filter execution - Wrap margin and emulated tab distance preferences are properly transferred to new panes in split window mode nedit-5.6.orig/Xlt/0000755000175000017500000000000011107644406012664 5ustar paulpaulnedit-5.6.orig/Xlt/BubbleButton.c0000644000175000017500000003631610343604517015430 0ustar paulpaul/** * * $Id: BubbleButton.c,v 1.9 2005/12/01 14:31:43 tringali Exp $ * * Copyright (C) 1996 Free Software Foundation, Inc. * Copyright © 1999-2001 by the LessTif developers. * * This file is part of the GNU LessTif Extension Library. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * **/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include "BubbleButtonP.h" #include "SlideC.h" #include "../util/misc.h" #ifdef WITH_DMALLOC #include #endif static const char rcsid[] = "$Id: BubbleButton.c,v 1.9 2005/12/01 14:31:43 tringali Exp $"; /* Widget methods, forward declarations */ static void class_initialize(void); static void class_part_initialize(WidgetClass widget_class); static void initialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args); static void destroy(Widget w); static Boolean set_values(Widget old, Widget request, Widget new_w, ArgList args, Cardinal *num_args); static void _XmExportLabelString(Widget w, int offset, XtArgVal *value); /* Helper functions, forward declarations */ /* Widget default resources */ #define Offset(field) XtOffsetOf(XltBubbleButtonRec, bubble_button.field) static XtResource resources[] = { { XltNbubbleString, XltCBubbleString, XmRXmString, sizeof(XmString), Offset(BubbleString), XmRImmediate, (XtPointer)NULL }, { XltNshowBubble, XltCShowBubble, XmRBoolean, sizeof(Boolean), Offset(show_bubble), XmRImmediate, (XtPointer)True }, { XltNdelay, XltCDelay, XtRInt, sizeof(int), Offset(Delay), XtRImmediate, (XtPointer)1000 }, { XltNmouseOverString, XltCMouseOverString, XmRXmString, sizeof(XmString), Offset(MouseOverString), XtRImmediate, (XtPointer)NULL }, { XltNmouseOverPixmap, XltCMouseOverPixmap, XmRPrimForegroundPixmap, sizeof(Pixmap), Offset(MouseOverPixmap), XtRImmediate, (XtPointer)None }, { XltNbubbleDuration, XltCBubbleDuration, XtRInt, sizeof(int), Offset(Duration), XtRImmediate, (XtPointer)0 }, { XltNslidingBubble, XltCslidingBubble, XmRBoolean, sizeof(Boolean), Offset(slidingBubble), XmRImmediate, (XtPointer)True }, { XltNautoParkBubble, XltCautoParkBubble, XmRBoolean, sizeof(Boolean), Offset(autoParkBubble), XmRImmediate, (XtPointer)False }, }; static XmSyntheticResource syn_resources[] = { { XltNbubbleString, sizeof(XmString), Offset(BubbleString), _XmExportLabelString, NULL } }; #undef Offset /* Widget class record */ static void EnterWindow(Widget w, XEvent *event, String *params, Cardinal *num_params); static void LeaveWindow(Widget w, XEvent *event, String *params, Cardinal *num_params); static XtActionsRec actions[] = { {"Enter", EnterWindow}, {"Leave", LeaveWindow}, }; /* *INDENT-OFF* */ XltBubbleButtonClassRec xrwsBubbleButtonClassRec = { /* Core class part */ { /* superclass */ (WidgetClass) &xmPushButtonClassRec, /* class_name */ "XltBubbleButton", /* widget_size */ sizeof(XltBubbleButtonRec), /* class_initialize */ class_initialize, /* class_part_initialize */ class_part_initialize, /* class_inited */ False, /* initialize */ initialize, /* initialize_hook */ NULL, /* realize */ XtInheritRealize, /* actions */ actions, /* num_actions */ XtNumber(actions), /* resources */ resources, /* num_resources */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ True, /* compress_exposure */ XtExposeCompressMaximal, /* compress_enterleave */ True, /* visible_interest */ False, /* destroy */ destroy, /* resize */ XtInheritResize, /* expose */ XtInheritExpose, /* set_values */ set_values, /* set_values_hook */ NULL, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ NULL, /* accept_focus */ NULL, /* version */ XtVersion, /* callback offsets */ NULL, /* tm_table */ NULL, /* query_geometry */ XtInheritQueryGeometry, /* display_accelerator */ NULL, /* extension */ (XtPointer)NULL }, /* Primitive Class part */ { /* border_highlight */ XmInheritBorderHighlight, /* border_unhighlight */ XmInheritBorderUnhighlight, /* translations */ XtInheritTranslations, /* arm_and_activate_proc */ XmInheritArmAndActivate, /* synthetic resources */ syn_resources, /* num syn res */ XtNumber(syn_resources), /* extension */ (XtPointer)NULL }, /* Label Class part */ { /* setOverrideCallback */ XmInheritSetOverrideCallback, /* menuProcs */ XmInheritMenuProc, /* translations */ XtInheritTranslations, /* extension */ NULL }, /* PushButton Class part */ { /* extension */ NULL }, /* BubbleButton Class part */ { /* leave_time */ 0, /* extension */ NULL } }; /* *INDENT-ON* */ WidgetClass xrwsBubbleButtonWidgetClass = (WidgetClass)&xrwsBubbleButtonClassRec; /* Helper routines */ /* Widget methods */ static void class_initialize(void) { xrwsBubbleButtonClassRec.bubble_button_class.leave_time = 0; } static void class_part_initialize(WidgetClass widget_class) { } static void initialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args) { Widget Shell; Arg arg[10]; int argcnt = 0; BubbleButton_Timer(new_w) = (XtIntervalId)NULL; BubbleButton_DurationTimer(new_w) = (XtIntervalId)NULL; BubbleButton_Swapped(new_w) = False; BubbleButton_Slider(new_w) = NULL; Shell = CreatePopupShellWithBestVis("BubbleShell", transientShellWidgetClass, new_w, arg, argcnt); XtVaSetValues(Shell, XmNoverrideRedirect, True, NULL); if (BubbleButton_MouseOverString(new_w) != NULL) { BubbleButton_MouseOverString(new_w) = XmStringCopy(BubbleButton_MouseOverString(new_w)); } if (BubbleButton_BubbleString(new_w) == NULL) { XmString xmstring; #if XmVERSION >= 2 xmstring = XmeGetLocalizedString((char *)NULL, new_w, XmNlabelString, XtName(new_w)); #else xmstring = _XmOSGetLocalizedString((char *)NULL, new_w, XmNlabelString, XtName(new_w)); #endif BubbleButton_BubbleString(new_w) = xmstring; } else { BubbleButton_BubbleString(new_w) = XmStringCopy(BubbleButton_BubbleString(new_w)); } BubbleButton_Label(new_w) = XmCreateLabel(Shell, "BubbleLabel", NULL, 0); XtVaSetValues(BubbleButton_Label(new_w), XmNlabelString, BubbleButton_BubbleString(new_w), XmNforeground, ((XltBubbleButtonWidget)new_w)->core.background_pixel, XmNbackground, ((XltBubbleButtonWidget)new_w)->primitive.foreground, NULL); XtManageChild(BubbleButton_Label(new_w)); } static void destroy(Widget w) { if (BubbleButton_MouseOverString(w)) { XmStringFree(BubbleButton_MouseOverString(w)); } if (BubbleButton_Timer(w)) { XtRemoveTimeOut(BubbleButton_Timer(w)); } if (BubbleButton_DurationTimer(w)) { XtRemoveTimeOut(BubbleButton_DurationTimer(w)); } } static Boolean set_values(Widget old, Widget request, Widget new_w, ArgList args, Cardinal *num_args) { if (BubbleButton_MouseOverString(new_w) != BubbleButton_MouseOverString(old)) { XmStringFree(BubbleButton_MouseOverString(old)); BubbleButton_MouseOverString(new_w) = XmStringCopy(BubbleButton_MouseOverString(new_w)); } if (BubbleButton_BubbleString(new_w) != BubbleButton_BubbleString(old)) { XmStringFree(BubbleButton_BubbleString(old)); BubbleButton_BubbleString(new_w) = XmStringCopy(BubbleButton_BubbleString(new_w)); XtVaSetValues(BubbleButton_Label(new_w), XmNlabelString, BubbleButton_BubbleString(new_w), NULL); } if (XtIsSensitive(old) != XtIsSensitive(new_w)) { if (!XtIsSensitive(new_w)) { Cardinal num_params = 0; LeaveWindow(new_w, NULL, NULL, &num_params); } } return (False); } /* * Short-term solution. Doesn't belong here. See SF bug #923924. */ extern XmString _XmStringCreateExternal(XmFontList fontlist, _XmString cs); static void _XmExportLabelString(Widget w, int offset, XtArgVal *value) { _XmString str; XmString ret; str = *(_XmString *)(((char *)w) + offset); if (str) { if (XmIsLabel(w)) { ret = _XmStringCreateExternal(Lab_Font(w), str); } else { ret = NULL; } } else { ret = NULL; } *value = (XtArgVal)ret; } static void fadeOutFinish(Widget slide, Widget w, XtPointer call_data) { BubbleButton_Slider(w) = NULL; XtPopdown(XtParent(BubbleButton_Label(w))); } static void UnpostIt(Widget w) { BubbleButton_DurationTimer(w) = (XtIntervalId)NULL; if (BubbleButton_SlidingBubble(w)) { BubbleButton_Slider(w) = XtVaCreateWidget("Slide", xltSlideContextWidgetClass, XmGetXmDisplay(XtDisplay(w)), XltNslideWidget, XtParent(BubbleButton_Label(w)), XltNslideDestHeight, 1, NULL); XtAddCallback(BubbleButton_Slider(w), XltNslideFinishCallback, (XtCallbackProc)fadeOutFinish, w); } else { XtPopdown(XtParent(BubbleButton_Label(w))); } } static void fadeInFinish(Widget slide, Widget w, XtPointer call_data) { BubbleButton_Slider(w) = NULL; if (BubbleButton_Duration(w) > 0) { BubbleButton_DurationTimer(w) = XtAppAddTimeOut(XtWidgetToApplicationContext(w), BubbleButton_Duration(w), (XtTimerCallbackProc)UnpostIt, w); } } #define TOOLTIP_EDGE_GUARD 5 static void PostIt(Widget w) { int rx, ry, x, y; unsigned int key; Window root, child; Dimension xPos, yPos; XWindowAttributes screenAttr; BubbleButton_Timer(w) = (XtIntervalId)NULL; XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child, &rx, &ry, &x, &y, &key); if (BubbleButton_DurationTimer(w) != (XtIntervalId)NULL) { XtRemoveTimeOut(BubbleButton_DurationTimer(w)); BubbleButton_DurationTimer(w) = (XtIntervalId)NULL; } { XtWidgetGeometry geo; XtQueryGeometry(BubbleButton_Label(w), NULL, &geo); xPos = rx - x + XtWidth(w) / 2 ; yPos = ry - y + XtHeight(w); if (BubbleButton_AutoParkBubble(w)) { xPos = rx + 3; yPos = ry + 15; /* keep tooltip within screen */ XGetWindowAttributes(XtDisplay(w), RootWindowOfScreen(XtScreen(w)), &screenAttr); if (xPos + geo.width >= screenAttr.width - TOOLTIP_EDGE_GUARD) xPos = screenAttr.width - geo.width - TOOLTIP_EDGE_GUARD; if (yPos + geo.height >= screenAttr.height - TOOLTIP_EDGE_GUARD) yPos = ry - 15 - geo.height; } if (BubbleButton_SlidingBubble(w)) { int xAdjust, yAdjust; /* FIXME: slider must avoid pointer */ xAdjust = rx < xPos? 1 : -1; yAdjust = ry < yPos? 1 : - geo.height/2; XtVaSetValues(XtParent(BubbleButton_Label(w)), XmNx, rx + xAdjust /*- x + XtWidth(w) / 2*/, XmNy, ry + yAdjust /*- y + XtHeight(w)*/, XmNheight, 1, XmNwidth, 1 /*geo.width*/, NULL); XtPopup(XtParent(BubbleButton_Label(w)), XtGrabNone); BubbleButton_Slider(w) = XtVaCreateWidget("Slide", xltSlideContextWidgetClass, XmGetXmDisplay(XtDisplay(w)), XltNslideWidget, XtParent(BubbleButton_Label(w)), XltNslideDestX, xPos, XltNslideDestY, yPos, XltNslideDestWidth, geo.width, XltNslideDestHeight, geo.height, NULL); XtAddCallback(BubbleButton_Slider(w), XltNslideFinishCallback, (XtCallbackProc)fadeInFinish, w); } else { XtVaSetValues(XtParent(BubbleButton_Label(w)), XmNx, xPos /*- x + XtWidth(w) / 2*/, XmNy, yPos /*- y + XtHeight(w)*/, XmNheight, geo.height, XmNwidth, geo.width /*geo.width*/, NULL); XtPopup(XtParent(BubbleButton_Label(w)), XtGrabNone); if (BubbleButton_Duration(w) > 0) { BubbleButton_DurationTimer(w) = XtAppAddTimeOut(XtWidgetToApplicationContext(w), BubbleButton_Duration(w), (XtTimerCallbackProc)UnpostIt, w); } } } } static void SwapLabels(Widget w) { XmString tmp = NULL; if (BubbleButton_MouseOverString(w)) { XtVaGetValues(w, XmNlabelString, &tmp, NULL); XtVaSetValues(w, XmNlabelString, BubbleButton_MouseOverString(w), NULL); XmStringFree(BubbleButton_MouseOverString(w)); BubbleButton_MouseOverString(w) = tmp; } } static void SwapPixmaps(Widget w) { Pixmap tmp; if (BubbleButton_MouseOverPixmap(w)) { XtVaGetValues(w, XmNlabelPixmap, &tmp, NULL); XtVaSetValues(w, XmNlabelPixmap, BubbleButton_MouseOverPixmap(w), NULL); BubbleButton_MouseOverPixmap(w) = tmp; } } static void Swap(Widget w) { if (Lab_IsText(w)) { SwapLabels(w); } else { SwapPixmaps(w); } BubbleButton_Swapped(w) = BubbleButton_Swapped(w) ? False : True; } static void EnterWindow(Widget w, XEvent *event, String *params, Cardinal *num_params) { if (BubbleButton_ShowBubble(w) && !BubbleButton_Timer(w)) { unsigned long delay; if (event && (event->xcrossing.time - BubbleButtonClass_LeaveTime(w) < BubbleButton_Delay(w))) { delay = 0; } else { delay = BubbleButton_Delay(w); } BubbleButton_Timer(w) = XtAppAddTimeOut(XtWidgetToApplicationContext(w), delay, (XtTimerCallbackProc)PostIt, w); } if (!BubbleButton_Swapped(w)) { Swap(w); } } static void LeaveWindow(Widget w, XEvent *event, String *params, Cardinal *num_params) { if (BubbleButton_Timer(w)) { XtRemoveTimeOut(BubbleButton_Timer(w)); BubbleButton_Timer(w) = (XtIntervalId)NULL; } else { if (BubbleButton_Slider(w) != NULL) { XtDestroyWidget(BubbleButton_Slider(w)); BubbleButton_Slider(w) = NULL; } XtPopdown(XtParent(BubbleButton_Label(w))); if (event) { if (BubbleButton_DurationTimer(w) || BubbleButton_Duration(w) == 0) { BubbleButtonClass_LeaveTime(w) = event->xcrossing.time; } } } if (BubbleButton_DurationTimer(w)) { XtRemoveTimeOut(BubbleButton_DurationTimer(w)); BubbleButton_DurationTimer(w) = (XtIntervalId)NULL; } if (BubbleButton_Swapped(w)) { Swap(w); } } /* Public functions */ Widget XltCreateBubbleButton(Widget parent, char *name, Arg *arglist, Cardinal argCount) { return XtCreateWidget(name, xrwsBubbleButtonWidgetClass, parent, arglist, argCount); } nedit-5.6.orig/Xlt/BubbleButton.h0000644000175000017500000000533007772504713015436 0ustar paulpaul/** * * $Id: BubbleButton.h,v 1.2 2003/12/25 06:55:07 tksoh Exp $ * * Copyright (C) 1996 Free Software Foundation, Inc. * Copyright © 1999-2001 by the LessTif developers. * * This file is part of the GNU LessTif Extension Library. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * **/ #ifndef _BUBBLEBUTTON_H #define _BUBBLEBUTTON_H #include #ifdef __cplusplus extern "C" { #endif #ifndef XltNfadeRate #define XltNfadeRate "fadeRate" #endif #ifndef XltCFadeRate #define XltCFadeRate "FadeRate" #endif #ifndef XltNdelay #define XltNdelay "delay" #endif #ifndef XltCDelay #define XltCDelay "Delay" #endif #define XltNbubbleString "bubbleString" #define XltCBubbleString "BubbleString" #define XltNshowBubble "showBubble" #define XltCShowBubble "ShowBubble" #ifndef XltNmouseOverPixmap #define XltNmouseOverPixmap "mouseOverPixmap" #define XltCMouseOverPixmap "MouseOverPixmap" #endif #ifndef XltNmouseOverString #define XltNmouseOverString "mouseOverString" #define XltCMouseOverString "MouseOverString" #endif #ifndef XltNbubbleDuration #define XltNbubbleDuration "bubbleDuration" #endif #ifndef XltCBubbleDuration #define XltCBubbleDuration "BubbleDuration" #endif #ifndef XltNslidingBubble #define XltNslidingBubble "slidingBubble" #endif #ifndef XltCslidingBubble #define XltCslidingBubble "SlidingBubble" #endif #ifndef XltNautoParkBubble #define XltNautoParkBubble "autoParkBubble" #endif #ifndef XltCautoParkBubble #define XltCautoParkBubble "AutoParkBubble" #endif extern WidgetClass xrwsBubbleButtonWidgetClass; typedef struct _XltBubbleButtonRec *XltBubbleButtonWidget; typedef struct _XltBubbleButtonClassRec *XltBubbleButtonWidgetClass; #if 0 typedef struct { int reason; char *data; int len; } XltHostCallbackStruct, _XltHostCallbackStruct; #endif #define XltIsBubbleButton(w) XtIsSubclass((w), xrwsBubbleButtonWidgetClass) extern Widget XltCreateBubbleButton(Widget parent, char *name, Arg *arglist, Cardinal argCount); #ifdef __cplusplus } /* Close scope of 'extern "C"' declaration which encloses file. */ #endif #endif nedit-5.6.orig/Xlt/BubbleButtonP.h0000644000175000017500000000631710343604517015553 0ustar paulpaul/** * * $Id: BubbleButtonP.h,v 1.5 2005/12/01 14:31:43 tringali Exp $ * * Copyright (C) 1996 Free Software Foundation, Inc. * Copyright © 1999-2001 by the LessTif developers. * * This file is part of the GNU LessTif Extension Library. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * **/ #ifndef _BUBBLEBUTTONP_H #define _BUBBLEBUTTONP_H #include "BubbleButton.h" #include typedef struct { XtIntervalId Timer; int Delay; Widget BubbleLabel; XmString BubbleString; Boolean show_bubble; XmString MouseOverString; Pixmap MouseOverPixmap; XtIntervalId DurationTimer; int Duration; Boolean Swapped; Widget slider; Boolean slidingBubble; Boolean autoParkBubble; } XltBubbleButtonPart; #define BubbleButton_Timer(w) (((XltBubbleButtonWidget)w)->bubble_button.Timer) #define BubbleButton_Delay(w) (((XltBubbleButtonWidget)w)->bubble_button.Delay) #define BubbleButton_Label(w) (((XltBubbleButtonWidget)w)->bubble_button.BubbleLabel) #define BubbleButton_BubbleString(w) (((XltBubbleButtonWidget)w)->bubble_button.BubbleString) #define BubbleButton_ShowBubble(w) (((XltBubbleButtonWidget)w)->bubble_button.show_bubble) #define BubbleButton_MouseOverString(w) (((XltBubbleButtonWidget)w)->bubble_button.MouseOverString) #define BubbleButton_MouseOverPixmap(w) (((XltBubbleButtonWidget)w)->bubble_button.MouseOverPixmap) #define BubbleButton_DurationTimer(w) (((XltBubbleButtonWidget)w)->bubble_button.DurationTimer) #define BubbleButton_Duration(w) (((XltBubbleButtonWidget)w)->bubble_button.Duration) #define BubbleButton_Swapped(w) (((XltBubbleButtonWidget)w)->bubble_button.Swapped) #define BubbleButton_Slider(w) (((XltBubbleButtonWidget)w)->bubble_button.slider) #define BubbleButton_SlidingBubble(w) (((XltBubbleButtonWidget)w)->bubble_button.slidingBubble) #define BubbleButton_AutoParkBubble(w) (((XltBubbleButtonWidget)w)->bubble_button.autoParkBubble) #define BubbleButtonClass_LeaveTime(w) (((XltBubbleButtonWidgetClass)XtClass(w))->bubble_button_class.leave_time) typedef struct _XltBubbleButtonRec { CorePart core; XmPrimitivePart primitive; XmLabelPart label; XmPushButtonPart pushbutton; XltBubbleButtonPart bubble_button; } XltBubbleButtonRec; typedef struct { Time leave_time; XtPointer extension; } XltBubbleButtonClassPart; typedef struct _XltBubbleButtonClassRec { CoreClassPart core_class; XmPrimitiveClassPart primitive_class; XmLabelClassPart label_class; XmPushButtonClassPart pushbutton_class; XltBubbleButtonClassPart bubble_button_class; } XltBubbleButtonClassRec; extern XltBubbleButtonClassRec xrwsBubbleButtonClassRec; #endif nedit-5.6.orig/Xlt/Makefile0000644000175000017500000000142010220261124014304 0ustar paulpaul# $Id: Makefile,v 1.1 2005/03/23 12:34:28 edg Exp $ SHELL=/bin/sh # # Makefile for NEdit text editor # # Targets are the suffixes of the system-specific makefiles in # the makefiles/ directory. # For example, to build NEdit for Solaris, give the command # # make solaris # # This builds an intermediate library in the util/ directory, # then builds the nedit and nc executables in the source/ directory. # all: @echo "Please specify target:" @echo "(For example, type \"make linux\" for a Linux system.)" @(cd ../makefiles && ls -C Makefile* | sed -e 's/Makefile.//g') .DEFAULT: @- if [ -f ../makefiles/Makefile.$@ -a ! -f ./Makefile.$@ ];\ then ln -s ../makefiles/Makefile.$@ .; fi @- $(MAKE) -f Makefile.$@ libXlt.a clean: @- $(MAKE) -f Makefile.common clean nedit-5.6.orig/Xlt/Makefile.common0000644000175000017500000000067007772504713015627 0ustar paulpaul# $Id: Makefile.common,v 1.1 2003/12/25 06:55:07 tksoh Exp $ # # Platform independent part of make procedure for Nirvana utilities directory, # included by machine specific makefiles. # .c.o: $(CC) -c -I../Xlt $(CFLAGS) -o $@ $< OBJS = BubbleButton.o SlideC.o all: libXlt.a libXlt.a: $(OBJS) $(AR) $(ARFLAGS) libXlt.a $(OBJS) clean: rm -f $(OBJS) libXlt.a # Get the dependencies for all objects include Makefile.dependencies nedit-5.6.orig/Xlt/Makefile.dependencies0000644000175000017500000000014407772504713016761 0ustar paulpaulBubbleButton.o: BubbleButton.c BubbleButton.h BubbleButtonP.h SlideC.o: SlideC.c SlideC.h SlideCP.h nedit-5.6.orig/Xlt/SlideC.c0000644000175000017500000002133110343604517014173 0ustar paulpaul/** * * $Id: SlideC.c,v 1.5 2005/12/01 14:31:43 tringali Exp $ * * Copyright (C) 1996 Free Software Foundation, Inc. * Copyright © 1999-2001 by the LessTif developers. * * This file is part of the GNU LessTif Extension Library. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * **/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include #include "SlideCP.h" #ifdef WITH_DMALLOC #include #endif /* Widget methods, forward declarations */ static void class_initialize(void); static void class_part_initialize(WidgetClass widget_class); static void initialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args); static void destroy(Widget w); static Boolean set_values(Widget old, Widget request, Widget new_w, ArgList args, Cardinal *num_args); static void get_values_hook(Widget w, ArgList args, Cardinal *num_args); static void _XltSlideProc(Widget w); static void targetDestroy(Widget target, Widget w); /* Widget default resources */ #define Offset(field) XtOffsetOf(XltSlideContextRec, slide.field) static XtResource resources[] = { { XltNslideFinishCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), Offset(slideFinishCallback), XtRCallback, NULL }, { XltNslideMotionCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), Offset(slideMotionCallback), XtRCallback, NULL }, { XltNslideWidget, XltCSlideWidget, XtRWidget, sizeof(Widget), Offset(slide_widget), XtRImmediate, NULL }, { XltNslideInterval, XltCSlideInterval, XtRInt, sizeof(int), Offset(interval), XtRImmediate, (XtPointer)5 }, { XltNslideDestWidth, XltCSlideDestWidth, XtRDimension, sizeof(Dimension), Offset(dest_width), XtRImmediate, (XtPointer)XmUNSPECIFIED }, { XltNslideDestHeight, XltCSlideDestHeight, XtRDimension, sizeof(Dimension), Offset(dest_height), XtRImmediate, (XtPointer)XmUNSPECIFIED }, { XltNslideDestX, XltCSlideDestX, XtRPosition, sizeof(Position), Offset(dest_x), XtRImmediate, (XtPointer)XmUNSPECIFIED_POSITION }, { XltNslideDestY, XltCSlideDestY, XtRPosition, sizeof(Position), Offset(dest_y), XtRImmediate, (XtPointer)XmUNSPECIFIED_POSITION }, }; #undef Offset /* Widget class record */ XltSlideContextClassRec xltSlideContextClassRec = { /* Object Class Part */ { /* pointer to superclass ClassRec WidgetClass */ (WidgetClass) &objectClassRec, /* widget resource class name String */ "XltSlideContext", /* size in bytes of widget record Cardinal */ sizeof(XltSlideContextRec), /* class initialization proc XtProc */ class_initialize, /* dynamic initialization XtWidgetClassProc */ class_part_initialize, /* has class been initialized? XtEnum */ False, /* initialize subclass fields XtInitProc */ initialize, /* notify that initialize called XtArgsProc */ NULL, /* NULL XtProc */ NULL, /* NULL XtPointer */ NULL, /* NULL Cardinal */ (Cardinal)NULL, /* resources for subclass fields XtResourceList */ resources, /* number of entries in resources Cardinal */ XtNumber(resources), /* resource class quarkified XrmClass */ NULLQUARK, /* NULL Boolean */ (Boolean)NULL, /* NULL XtEnum */ (XtEnum)NULL, /* NULL Boolean */ (Boolean)NULL, /* NULL Boolean */ (Boolean)NULL, /* free data for subclass pointers XtWidgetProc */ destroy, /* NULL XtProc */ NULL, /* NULL XtProc */ NULL, /* set subclass resource values XtSetValuesFunc */ set_values, /* notify that set_values called XtArgsFunc */ NULL, /* NULL XtProc */ NULL, /* notify that get_values called XtArgsProc */ get_values_hook, /* NULL XtProc */ NULL, /* version of intrinsics used XtVersionType */ XtVersion, /* list of callback offsets XtPointer */ NULL, /* NULL String */ NULL, /* NULL XtProc */ NULL, /* NULL XtProc */ NULL, /* pointer to extension record XtPointer */ NULL }, /* SlideContext Class Part */ { NULL } }; WidgetClass xltSlideContextWidgetClass = (WidgetClass)&xltSlideContextClassRec; static void class_initialize(void) { } static void class_part_initialize(WidgetClass widget_class) { } static void initialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args) { /* printf("%s:%s(%d) - %s %li\n", __FILE__, __FUNCTION__, __LINE__, XtName(new_w), Slide_Interval(new_w)); */ if (Slide_DestWidth(new_w) == (Dimension)XmUNSPECIFIED) { Slide_DestWidth(new_w) = XtWidth(Slide_Widget(new_w)); } if (Slide_DestHeight(new_w) == (Dimension)XmUNSPECIFIED) { Slide_DestHeight(new_w) = XtHeight(Slide_Widget(new_w)); } if (Slide_DestX(new_w) == XmUNSPECIFIED_POSITION) { Slide_DestX(new_w) = XtX(Slide_Widget(new_w)); } if (Slide_DestY(new_w) == XmUNSPECIFIED_POSITION) { Slide_DestY(new_w) = XtY(Slide_Widget(new_w)); } Slide_Id(new_w) = XtAppAddTimeOut(XtWidgetToApplicationContext(new_w), Slide_Interval(new_w), (XtTimerCallbackProc)_XltSlideProc, new_w); XtAddCallback(Slide_Widget(new_w), XmNdestroyCallback, (XtCallbackProc)targetDestroy, new_w); } static void destroy(Widget w) { if (Slide_Id(w) != (XtIntervalId)NULL) { XtRemoveTimeOut(Slide_Id(w)); Slide_Id(w) = (XtIntervalId)NULL; } XtRemoveCallback(Slide_Widget(w), XmNdestroyCallback, (XtCallbackProc)targetDestroy, w); } static Boolean set_values(Widget old, Widget request, Widget new_w, ArgList args, Cardinal *num_args) { if (Slide_Widget(old) != Slide_Widget(new_w)) { XtRemoveCallback(Slide_Widget(old), XmNdestroyCallback, (XtCallbackProc)targetDestroy, old); XtAddCallback(Slide_Widget(new_w), XmNdestroyCallback, (XtCallbackProc)targetDestroy, new_w); } return(False); } static void get_values_hook(Widget w, ArgList args, Cardinal *num_args) { } static void targetDestroy(Widget target, Widget w) { XtDestroyWidget(w); } static void _XltSlideProc(Widget w) { Dimension width, height; Position x, y; /* printf("%s:%s(%d) - %s %li\n", __FILE__, __FUNCTION__, __LINE__, XtName(w), Slide_Interval(w)); */ width = XtWidth(Slide_Widget(w)); height = XtHeight(Slide_Widget(w)); x = XtX(Slide_Widget(w)); y = XtY(Slide_Widget(w)); { height = height - (((height - Slide_DestHeight(w)) * 10) / 100); if (height < Slide_DestHeight(w)) { height++; } if (height > Slide_DestHeight(w)) { height--; } width = width - (((width - Slide_DestWidth(w)) * 10) / 100); if (width < Slide_DestWidth(w)) { width++; } if (width > Slide_DestWidth(w)) { width--; } } { y = y - ((((y - Slide_DestY(w)) * 10) / 100) + 0); if (y < Slide_DestY(w)) { y++; } if (y > Slide_DestY(w)) { y--; } x = x - ((((x - Slide_DestX(w)) * 10) / 100) + 0); if (x < Slide_DestX(w)) { x++; } if (x > Slide_DestX(w)) { x--; } } /* XtCallCallbackList(w, Slide_MotionCallback(w), NULL); */ XtVaSetValues(Slide_Widget(w), XmNx, x, XmNy, y, XmNwidth, width, XmNheight, height, NULL); if (Slide_DestX(w) == XtX(Slide_Widget(w)) && Slide_DestY(w) == XtY(Slide_Widget(w)) && Slide_DestWidth(w) == XtWidth(Slide_Widget(w)) && Slide_DestHeight(w) == XtHeight(Slide_Widget(w))) { XtCallCallbackList(w, Slide_FinishCallback(w), NULL); XtRemoveCallback(Slide_Widget(w), XmNdestroyCallback, (XtCallbackProc)targetDestroy, w); XtDestroyWidget(w); } else { Slide_Id(w) = XtAppAddTimeOut(XtWidgetToApplicationContext(w), Slide_Interval(w), (XtTimerCallbackProc)_XltSlideProc, w); } } nedit-5.6.orig/Xlt/SlideC.h0000644000175000017500000000536707771777034014233 0ustar paulpaul/** * * $Id: SlideC.h,v 1.1 2003/12/23 08:34:36 tksoh Exp $ * * Copyright (C) 1996 Free Software Foundation, Inc. * Copyright © 1999-2001 by the LessTif developers. * * This file is part of the GNU LessTif Extension Library. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * **/ #ifndef _SLIDEC_H #define _SLIDEC_H #include #ifdef __cplusplus extern "C" { #endif #ifndef XltIsSlideContext #define XltIsSlideContext(w) XtIsSubclass(w,xltSlideContextClass) #endif #ifndef XltNslideFinishCallback #define XltNslideFinishCallback "slideFinishCallback" #endif #ifndef XltCSlideFinishCallback #define XltCSlideFinishCallback "SlideFinishCallback" #endif #ifndef XltNslideMotionCallback #define XltNslideMotionCallback "slideMotionCallback" #endif #ifndef XltCSlideMotionCallback #define XltCSlideMotionCallback "SlideMotionCallback" #endif #ifndef XltNslideWidget #define XltNslideWidget "slideWidget" #endif #ifndef XltCSlideWidget #define XltCSlideWidget "SlideWidget" #endif #ifndef XltNslideInterval #define XltNslideInterval "slideInterval" #endif #ifndef XltCSlideInterval #define XltCSlideInterval "SlideInterval" #endif #ifndef XltNslideDestWidth #define XltNslideDestWidth "slideDestWidth" #endif #ifndef XltCSlideDestWidth #define XltCSlideDestWidth "SlideDestWidth" #endif #ifndef XltNslideDestHeight #define XltNslideDestHeight "slideDestHeight" #endif #ifndef XltCSlideDestHeight #define XltCSlideDestHeight "SlideDestHeight" #endif #ifndef XltNslideDestX #define XltNslideDestX "slideDestX" #endif #ifndef XltCSlideDestX #define XltCSlideDestX "SlideDestX" #endif #ifndef XltNslideDestY #define XltNslideDestY "slideDestY" #endif #ifndef XltCSlideDestY #define XltCSlideDestY "SlideDestY" #endif extern WidgetClass xltSlideContextWidgetClass; typedef struct _XltSlideContextRec *XltSlideContextWidget; typedef struct _XltSlideContextClassRec *XmSlideContextWidgetClass; typedef struct _XltSlideStruct { Widget w; XtWidgetGeometry dest; unsigned long interval; XtIntervalId id; } XltSlideStruct, *XltSlidePtr; void XltSlide(XltSlidePtr slide_info); #ifdef __cplusplus } #endif #endif nedit-5.6.orig/Xlt/SlideCP.h0000644000175000017500000000514210343604517014322 0ustar paulpaul/** * * $Id: SlideCP.h,v 1.4 2005/12/01 14:31:43 tringali Exp $ * * Copyright (C) 1996 Free Software Foundation, Inc. * Copyright © 1999-2001 by the LessTif developers. * * This file is part of the GNU LessTif Extension Library. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * **/ #ifndef _SLIDECP_H #define _SLIDECP_H #include #include #include #include "SlideC.h" #ifdef __cplusplus extern "C" { #endif #ifndef XmUNSPECIFIED #define XmUNSPECIFIED (~0) #endif #ifndef XmUNSPECIFIED_POSITION #define XmUNSPECIFIED_POSITION (-1) #endif typedef struct { XtPointer extension; } XltSlideContextClassPart; typedef struct _XltSlideContextClassRec { ObjectClassPart object_class; XltSlideContextClassPart slide_class; } XltSlideContextClassRec; extern XltSlideContextClassRec xltSlideContextClassRec; typedef struct _XmSlideContextPart { XtIntervalId id; XtCallbackList slideFinishCallback; XtCallbackList slideMotionCallback; Widget slide_widget; unsigned long interval; Dimension dest_width; Dimension dest_height; Position dest_x; Position dest_y; } XltSlideContextPart; typedef struct _XltSlideContextRec { ObjectPart object; XltSlideContextPart slide; } XltSlideContextRec; #define Slide_Id(w) (((XltSlideContextWidget)w)->slide.id) #define Slide_Widget(w) (((XltSlideContextWidget)w)->slide.slide_widget) #define Slide_Interval(w) (((XltSlideContextWidget)w)->slide.interval) #define Slide_DestWidth(w) (((XltSlideContextWidget)w)->slide.dest_width) #define Slide_DestHeight(w) (((XltSlideContextWidget)w)->slide.dest_height) #define Slide_DestX(w) (((XltSlideContextWidget)w)->slide.dest_x) #define Slide_DestY(w) (((XltSlideContextWidget)w)->slide.dest_y) #define Slide_FinishCallback(w) (((XltSlideContextWidget)w)->slide.slideFinishCallback) #define Slide_MotionCallback(w) (((XltSlideContextWidget)w)->slide.slideMotionCallback) #ifdef __cplusplus } #endif #endif /* ifndef _SLIDECP_H */ nedit-5.6.orig/doc/0000755000175000017500000000000011107644412012657 5ustar paulpaulnedit-5.6.orig/doc/Makefile0000644000175000017500000001201107760441316014322 0ustar paulpaul# Makefile for NEdit text editor documentation # # $Id: Makefile,v 1.6 2003/11/24 17:41:34 edg Exp $ # # NEdit help documentation and internal help code using one common # source, help.etx, a Structure Enhanced TEXT document. # .SUFFIXES: .man .pod instructions: @ echo "" @ echo "This make file is intended for NEdit developers only." @ echo "" @ echo "It uses a perl program (setext) to extract the various forms" @ echo "of the NEdit help documentation and internal help code using" @ echo "one common source, help.etx, a Structure Enhanced TEXT document." @ echo "" @ echo "Additionally, it generates the nedit and nc man pages." @ echo "To generate those you need to have perl and pod2man installed." @ echo "" @ echo "The following are the main targets which generate files for" @ echo "NEdit development. They are:" @ echo "" @ echo " help - generates NEdit help code (help_topic.h, help_data.h)" @ echo " doc - generates various forms of NEdit documentation" @ echo " man - generates the nedit and nc man pages" @ echo " all - generates all the files" @ echo "" @ echo "Remember to specify the VERSION macro on the make command" @ echo "or as an environment variable so that the NEdit version" @ echo "gets placed appropriately. For example, the following" @ echo "command creates all the files for NEdit version 5.3" @ echo "" @ echo " make VERSION='NEdit 5.3' all" @ echo "" @ echo "When the version is not specified, the default value will" @ echo "be 'NEdit release of '" @ echo "" .version: @ if [ "$(VERSION)" = "" ]; then \ echo "NEdit release of `date +'%b %e, %Y'`" > .version; \ else \ echo "$(VERSION)" > .version; \ fi help: ../source/help_topic.h ../source/help_data.h setext ../source/help_topic.h ../source/help_data.h: .version help.etx setext @ echo "Creating NEdit help code `cat .version`" @ ./setext -m -v version="`cat .version`" help.etx @ mv -f help_topic.h ../source @ mv -f help_data.h ../source nedit.html: .version help.etx setext @ echo "Creating NEdit HTML documentation..." @ ./setext -v version="`cat .version`" help.etx nedit.html html/nedit.html: .version help.etx setext @ echo "Creating NEdit HTML website documentation..." @ if [ ! -d html ]; then mkdir html; fi @ if [ -d html ]; then \ cd html; \ ../setext -S -v version="`cat ../.version`" ../help.etx nedit.html; \ else \ echo "** Unable to create html directory to hold NEdit documentation"; \ fi nedit.doc: .version help.etx setext @ echo "Creating NEdit plain text documenation..." @ ./setext -c NEDITDOC -v version="`cat .version`" help.etx nedit.doc nc.man: .version nedit.man: .version .pod.man: @ echo "Creating $* man page..." @ which pod2man > /dev/null 2>&1 || ( echo "Sorry, you need pod2man." && exit 1 ) @ pod2man --release="`cat .version`" --center="NEdit documentation" $*.pod > $@ doc: .version nedit.doc nedit.html html/nedit.html man: .version nedit.man nc.man all: help doc man clean: @ echo "Removing generated NEdit documentation..." @ rm -rf help nedit.html html nedit.doc .version nedit.man nc.man # # FAQ targets. Requires an XSLT parser and processor, such as Java with the # XP and XT packages (http://www.jclark.com/xml/) # Override the XSLT variable at the command line as follows: # # make XSLT= faq # # Example: make XSLT="java -classpath xp.jar:xt.jar com.jclark.xsl.sax.Driver" faq # XSLT=undefined faq: check_xsl faq.txt html/faq/index.shtml faq.txt: faq.xml faq-txt.xsl faq-txt-pass2.xsl faq-txt.awk @ echo Building FAQ - text version @ rm -f faq-txt.html faq-txt-tmp.txt faq.txt @ ${XSLT} faq.xml faq-txt.xsl faq-txt.html @ ${XSLT} faq-txt.html faq-txt-pass2.xsl faq-txt-tmp.txt @ awk -f faq-txt.awk < faq-txt-tmp.txt > faq.txt @ rm -f faq-txt-tmp.txt html/faq/index.shtml: faq.xml faq-txt.xsl @ echo Building FAQ - HTML version @ rm -f html/faq/*.shtml @ if [ ! -d html ]; then mkdir html; fi @ if [ ! -d html/faq ]; then mkdir html/faq; fi @ ${XSLT} faq.xml faq.xsl html/faq/index.shtml check_xsl: @ if [ "x${XSLT}" = "xundefined" ]; \ then\ echo "To rebuild the FAQ, an XSLT parser and processer are required.";\ echo "For instance, a Java runtime environment and the XT and XP";\ echo "packages (http://www.jclark.com/xml/) can be used.";\ echo "Then type:";\ echo "";\ echo " make XSLT= faq";\ echo "";\ echo "For instance:";\ echo "";\ echo " make XSLT=\"java -classpath xp.jar:xt.jar com.jclark.xsl.sax.Driver\" faq";\ echo "";\ exit 1;\ fi FAQFILES = faq-txt.html faq-txt.xsl faq-txt-pass2.xsl faq-txt.awk\ faq-txt.dtd README.FAQ faq.txt Makefile faq.xml faq.xsl\ faq.dtd faq-dist: @ echo "Building faq.tar.gz";\ rm -f faq.tar.gz;\ DISTFILES="${FAQFILES} `ls html/faq/*.shtml`";\ tar cv $${DISTFILES} | gzip -c > faq.tar.gz;\ echo "Building faq.zip";\ rm -f faq.zip;\ zip faq.zip $${DISTFILES};\ nedit-5.6.orig/doc/NEdit.ad0000644000175000017500000002140507757657252014220 0ustar paulpaul! $Id: NEdit.ad,v 1.4 2003/11/22 13:03:38 edg Exp $ ! NEDIT IS NOT DESIGNED TO BE USED WITH AN APP-DEFAULTS FILE, and ! installing this will only cause you grief. This is provided for ! documentation, and as recourse when you have no way of removing ! a system app-defaults file which is preventing you from upgrading ! your nedit version. ! ! Application defaults for NEdit 5.4 ! ! !*FontList: -*-helvetica-medium-r-normal-*-*-120-*-*-*-iso8859-1 !*XmText.FontList: -*-courier-medium-r-normal-*-*-120-*-*-*-iso8859-1 !*XmTextField.FontList: -*-courier-medium-r-normal-*-*-120-*-*-*-iso8859-1 !*XmList.FontList: -*-courier-medium-r-normal-*-*-120-*-*-*-iso8859-1 !*XmFileSelectionBox*XmList.FontList: -*-courier-medium-r-normal-*-*-120-*-*-*-iso8859-1 !*background: #b3b3b3 !*foreground: black !*XmText.foreground: black !*XmText.background: rgb:e5/e5/e5 !*XmList.foreground: black !*XmList.background: rgb:e5/e5/e5 !*XmTextField.foreground: black !*XmTextField.background: rgb:e5/e5/e5 !*XmText.translations: #override\n ! Ctrl~Alt~Metav: paste-clipboard()\n ! Ctrl~Alt~Metac: copy-clipboard()\n ! Ctrl~Alt~Metax: cut-clipboard()\n ! Ctrl~Alt~Metau: delete-to-start-of-line()\n !*XmTextField.translations: #override\n ! Ctrl~Alt~Metav: paste-clipboard()\n ! Ctrl~Alt~Metac: copy-clipboard()\n ! Ctrl~Alt~Metax: cut-clipboard()\n ! Ctrl~Alt~Metau: delete-to-start-of-line()\n !*XmFileSelectionBox.resizePolicy: XmRESIZE_NONE !*XmFileSelectionBox.textAccelerators: !*text.lineNumForeground: black !*text.background: rgb:e5/e5/e5 !*text.foreground: black !*text.highlightForeground: white !*text.highlightBackground: red !*textFrame.shadowThickness: 1 !*menuBar.marginHeight: 0 !*menuBar.shadowThickness: 1 !*pane.sashHeight: 11 !*pane.sashWidth: 11 !*pane.marginWidth: 0 !*pane.marginHeight: 0 !*scrolledW*spacing: 0 !*text.selectionArrayCount: 3 !*helpText.background: rgb:cc/cc/cc !*helpText.foreground: black !*helpText.selectBackground: #b3b3b3 !*statsLine.background: #b3b3b3 !*statsLine.FontList: -*-helvetica-medium-r-normal-*-*-120-*-*-*-iso8859-1 !*helpText.font: -*-courier-medium-r-normal-*-*-120-*-*-*-iso8859-1 !*calltip.background: LemonChiffon1 !*calltip.foreground: black !*iSearchForm*highlightThickness: 1 !*fileMenu.tearOffModel: XmTEAR_OFF_ENABLED !*editMenu.tearOffModel: XmTEAR_OFF_ENABLED !*searchMenu.tearOffModel: XmTEAR_OFF_ENABLED !*preferencesMenu.tearOffModel: XmTEAR_OFF_ENABLED !*windowsMenu.tearOffModel: XmTEAR_OFF_ENABLED !*shellMenu.tearOffModel: XmTEAR_OFF_ENABLED !*macroMenu.tearOffModel: XmTEAR_OFF_ENABLED !*helpMenu.tearOffModel: XmTEAR_OFF_ENABLED !*fileMenu.mnemonic: F !*fileMenu.new.accelerator: Ctrln !*fileMenu.new.acceleratorText: Ctrl+N !*fileMenu.open.accelerator: Ctrlo !*fileMenu.open.acceleratorText: Ctrl+O !*fileMenu.openSelected.accelerator: Ctrly !*fileMenu.openSelected.acceleratorText: Ctrl+Y !*fileMenu.close.accelerator: Ctrlw !*fileMenu.close.acceleratorText: Ctrl+W !*fileMenu.save.accelerator: Ctrls !*fileMenu.save.acceleratorText: Ctrl+S !*fileMenu.includeFile.accelerator: Alti !*fileMenu.includeFile.acceleratorText: Alt+I !*fileMenu.print.accelerator: Ctrlp !*fileMenu.print.acceleratorText: Ctrl+P !*fileMenu.exit.accelerator: Ctrlq !*fileMenu.exit.acceleratorText: Ctrl+Q !*editMenu.mnemonic: E !*editMenu.undo.accelerator: Ctrlz !*editMenu.undo.acceleratorText: Ctrl+Z !*editMenu.redo.accelerator: Shift Ctrlz !*editMenu.redo.acceleratorText: Shift+Ctrl+Z !*editMenu.cut.accelerator: Ctrlx !*editMenu.cut.acceleratorText: Ctrl+X !*editMenu.copy.accelerator: Ctrlc !*editMenu.copy.acceleratorText: Ctrl+C !*editMenu.paste.accelerator: Ctrlv !*editMenu.paste.acceleratorText: Ctrl+V !*editMenu.pasteColumn.accelerator: Shift Ctrlv !*editMenu.pasteColumn.acceleratorText: Ctrl+Shift+V !*editMenu.delete.acceleratorText: Del !*editMenu.selectAll.accelerator: Ctrla !*editMenu.selectAll.acceleratorText: Ctrl+A !*editMenu.shiftLeft.accelerator: Ctrl9 !*editMenu.shiftLeft.acceleratorText: [Shift]Ctrl+9 !*editMenu.shiftLeftShift.accelerator: Shift Ctrl9 !*editMenu.shiftRight.accelerator: Ctrl0 !*editMenu.shiftRight.acceleratorText: [Shift]Ctrl+0 !*editMenu.shiftRightShift.accelerator: Shift Ctrl0 !*editMenu.upperCase.accelerator: Ctrl6 !*editMenu.upperCase.acceleratorText: Ctrl+6 !*editMenu.lowerCase.accelerator: Shift Ctrl6 !*editMenu.lowerCase.acceleratorText: Shift+Ctrl+6 !*editMenu.fillParagraph.accelerator: Ctrlj !*editMenu.fillParagraph.acceleratorText: Ctrl+J !*editMenu.insertFormFeed.accelerator: Alt Ctrll !*editMenu.insertFormFeed.acceleratorText: Alt+Ctrl+L !*editMenu.insertCtrlCode.accelerator: Alt Ctrli !*editMenu.insertCtrlCode.acceleratorText: Alt+Ctrl+I !*searchMenu.mnemonic: S !*searchMenu.find.accelerator: Ctrlf !*searchMenu.find.acceleratorText: [Shift]Ctrl+F !*searchMenu.findShift.accelerator: Shift Ctrlf !*searchMenu.findAgain.accelerator: Ctrlg !*searchMenu.findAgain.acceleratorText: [Shift]Ctrl+G !*searchMenu.findAgainShift.accelerator: Shift Ctrlg !*searchMenu.findSelection.accelerator: Ctrlh !*searchMenu.findSelection.acceleratorText: [Shift]Ctrl+H !*searchMenu.findSelectionShift.accelerator: Shift Ctrlh !*searchMenu.findIncremental.accelerator: Ctrli !*searchMenu.findIncrementalShift.accelerator: Shift Ctrli !*searchMenu.findIncremental.acceleratorText: [Shift]Ctrl+I !*searchMenu.replace.accelerator: Ctrlr !*searchMenu.replace.acceleratorText: [Shift]Ctrl+R !*searchMenu.replaceShift.accelerator: Shift Ctrlr !*searchMenu.findReplace.accelerator: Ctrlr !*searchMenu.findReplace.acceleratorText: [Shift]Ctrl+R !*searchMenu.findReplaceShift.accelerator: Shift Ctrlr !*searchMenu.replaceFindAgain.accelerator: Ctrlt !*searchMenu.replaceFindAgain.acceleratorText: [Shift]Ctrl+T !*searchMenu.replaceFindAgainShift.accelerator: Shift Ctrlt !*searchMenu.replaceAgain.accelerator: Altt !*searchMenu.replaceAgain.acceleratorText: [Shift]Alt+T !*searchMenu.replaceAgainShift.accelerator: Shift Altt !*searchMenu.gotoLineNumber.accelerator: Ctrll !*searchMenu.gotoLineNumber.acceleratorText: Ctrl+L !*searchMenu.gotoSelected.accelerator: Ctrle !*searchMenu.gotoSelected.acceleratorText: Ctrl+E !*searchMenu.mark.accelerator: Altm !*searchMenu.mark.acceleratorText: Alt+M a-z !*searchMenu.gotoMark.accelerator: Altg !*searchMenu.gotoMark.acceleratorText: [Shift]Alt+G a-z !*searchMenu.gotoMarkShift.accelerator: Shift Altg !*searchMenu.gotoMatching.accelerator: Ctrlm !*searchMenu.gotoMatching.acceleratorText: [Shift]Ctrl+M !*searchMenu.gotoMatchingShift.accelerator: Shift Ctrlm !*searchMenu.findDefinition.accelerator: Ctrld !*searchMenu.findDefinition.acceleratorText: Ctrl+D !*searchMenu.showCalltip.accelerator: Ctrlapostrophe !*searchMenu.showCalltip.acceleratorText: Ctrl+' !*preferencesMenu.mnemonic: P !*preferencesMenu.statisticsLine.accelerator: Alta !*preferencesMenu.statisticsLine.acceleratorText: Alt+A !*preferencesMenu.overtype.acceleratorText: Insert !*shellMenu.mnemonic: l !*shellMenu.filterSelection.accelerator: Altr !*shellMenu.filterSelection.acceleratorText: Alt+R !*shellMenu.executeCommand.accelerator: Altx !*shellMenu.executeCommand.acceleratorText: Alt+X !*shellMenu.executeCommandLine.accelerator: CtrlKP_Enter !*shellMenu.executeCommandLine.acceleratorText: Ctrl+KP Enter !*shellMenu.cancelShellCommand.accelerator: Ctrlperiod !*shellMenu.cancelShellCommand.acceleratorText: Ctrl+. !*macroMenu.mnemonic: c !*macroMenu.learnKeystrokes.accelerator: Altk !*macroMenu.learnKeystrokes.acceleratorText: Alt+K !*macroMenu.finishLearn.accelerator: Altk !*macroMenu.finishLearn.acceleratorText: Alt+K !*macroMenu.cancelLearn.accelerator: Ctrlperiod !*macroMenu.cancelLearn.acceleratorText: Ctrl+. !*macroMenu.replayKeystrokes.accelerator: Ctrlk !*macroMenu.replayKeystrokes.acceleratorText: Ctrl+K !*macroMenu.repeat.accelerator: Ctrlcomma !*macroMenu.repeat.acceleratorText: Ctrl+, !*windowsMenu.mnemonic: W !*windowsMenu.splitWindow.accelerator: Ctrl2 !*windowsMenu.splitWindow.acceleratorText: Ctrl+2 !*windowsMenu.closePane.accelerator: Ctrl1 !*windowsMenu.closePane.acceleratorText: Ctrl+1 !*helpMenu.mnemonic: H !*helpForm.sw.helpText*translations: #override\ ! Tab: help-focus-buttons()\n\ ! Return: help-button-action("dismiss")\n\ ! osfCancel: help-button-action("dismiss")\n\ ! ~Meta~Ctrl~Shift: grab-focus() help-hyperlink()\n\ ! ~Meta~Ctrl~Shift: help-hyperlink("current", "process-cancel", "extend-end")\n\ ! ~Meta~Ctrl~Shift: process-bdrag() help-hyperlink()\n\ ! ~Meta~Ctrl~Shift: help-hyperlink(\"new", "process-cancel", "copy-to") nedit-5.6.orig/doc/README.FAQ0000644000175000017500000001147207544577621014173 0ustar paulpaul Contents -------- * Building the FAQ * File List * A quick note on the syntax of faq.xml Building the FAQ ---------------- This FAQ is written in XML and translated to HTML using an XSL stylesheet. The XML source is processed using James Clark's (http://www.jclark.com/) XSLT processor XT and XML parser XP. The XSL stylesheet used to generate the HTML version is here (faq.xsl). The text version is generated in three steps: first, an XSL stylesheet (faq-txt.xsl) is used to generate a simple HTML. Then, a second XSL stylesheet (faq-txt-pass2.xsl) transforms the HTML into plain text. An awk script (faq-txt.awk) then performs the word wrapping. File list --------- README.FAQ This file faq.xml The source of the FAQ faq.dtd The DTD to which conforms faq.xml faq.xsl Stylesheet to convert faq.xml into HTML files faq-txt.xsl Generation of faq.txt, first pass Stylesheet to convert faq.xml into faq-txt.html faq-txt.dtd The DTD to which conforms faq-txt.html faq-txt-pass2.xsl Generation of faq.txt, second pass Stylesheet to convert faq-txt-html into faq-txt-tmp.txt faq-txt.awk Generation of faq.txt, third pass An AWK program for performing word wrapping Makefile Used to generate the FAQ via 'make' Other files are generated ones : *.shtml The faq in HTML format faq-txt.html Generated by pass 1 during generation of faq.txt faq-txt-tmp.txt Generated by pass 2 during generation of faq.txt faq.txt The faq in text version A quick note on the syntax of faq.xml ------------------------------------- This XML file is based on the DTD specified in "faq.dtd". See "faq.dtd" for a rigourous definition; a simple overview is given here, to help in making quick additions and modifications. The FAQ is composed of two parts : a and a . The contains the title (in our case, "NEdit Frequently Asked Questions"), the list of , a which gets displayed ahead of all questions, a section showing how to download the FAQ () and other, less important stuff. The part is composed of many FAQ
s. A section has a title and groups several FAQ entries. A particular section exists, called , which contains the description of the FAQ itself. A section is generally composed of several "Question 'N' Answer" entries (). A contains a question () and the answer to that question (). An identifier must be given to each , via the attribute "id". A longer version of the question may be specified via as another element of ; in this case, the is displayed in a table of questions, while the longer and more complete version, , is displayed along with the answer. The and elements contain text paragraphs. The doesn't contain paragraphs and behaves like a single paragraph itself. A text paragraph is indicated by one of the elements

,

,
    ,
      and
       (which, in the DTD, are collectively referred to as
      %paragraph-styles;).
      
         The 

      denotes a basic paragraph and contains text. The

      indicates an indent, and it contains other paragraphs inside. A nested
      will indent relative to the previous one. The
        and
          indicate respectively an unnumbered and a numbered list. Both
            and
              contain one or many
            1. elements. A
            2. element contains text. The
               indicates a preformatted piece of text, which will be output
                 with no further modifications.
              
              Paragraphs of type 

              and

            3. , as well as and a few other elements of the , contain text. Text is composed of free text and style elements. The style elements are the following : indicates an e-mail address. indicates an image. It has a required attribute "src" which must be a URL referring to the image, and a "alt" attribute containing alternate text, used for non-image-capable formats. indicates a web site. The text between and must be a URL. indicates a HTTP hyperlink. Its required attribute "href" must be the URL to link to. An attribute "alt" may contain alternate text. stands for emphasized text. stands for strong text. is used for terminal output and for the contents of configuration files. is used for command names, when included inline within text. Generally,
               paragraphs are used for several lines of code.
              
              The distinction between  and  and furthermore 
               is not so
              clear. A clearer and better definition is needed.
              
              $Id: README.FAQ,v 1.3 2002/09/26 12:37:37 ajhood Exp $
              nedit-5.6.orig/doc/faq-txt-pass2.xsl0000644000175000017500000000427307544577621016050 0ustar  paulpaul
              
              
              
              
              
              
              
              
              
              	
              	
              PREFIXED
              	
              		
              	
              	NOT_PREFIXED
              
              
              
              
              
              	
              	
              		
              	
              
              
              
              
              
              	
              
              
              	
              		
              	
              
              
              
              
              
              
              
              	
              
              
              	
              		
              	
              
              
              
              
              
              
              
              
              
              
              
              
              	
              	
              	
              	
              
              
              	
              
              
              
              
              
              
              
              
              	
              PRE
              	
              		
              	
              	NOT_PRE
              
              
              
              
              
              
              
              
              	
              	
              	
              
              
              
              
              
              nedit-5.6.orig/doc/faq-txt.awk0000644000175000017500000000173307544577621014774 0ustar  paulpaul# $Id: faq-txt.awk,v 1.3 2002/09/26 12:37:37 ajhood Exp $
              
              function wrap(line, prefix)
              {
              
              	wrapMargin = 75;
              
              	if (length(line) < wrapMargin) {
              		print prefix line;
              	} else {
              
              		count = split(line, words);
              
              		indent = match(line, /[^ ]/)
              
              		indentStr = substr( \
              			"                                                              ", \
              			1, indent - 1);
              
              		result = "";
              		for (w = 1; w <= count; w++) {
              			if (length(result) + length(words[w]) > wrapMargin - indent) {
              				# print a new line
              				print prefix indentStr result;
              				result = words[w];
              			} else {
              				if (w == 1)
              					result = words[w]
              				else
              					result = result " " words[w];
              			}
              		}
              		print prefix indentStr result;
              	}
              }
              
              
              
              
              BEGIN { prefixed = 0; pre = 0 }
              /^PREFIXED$/  {prefixed = 1; next }
              /^NOT_PREFIXED$/  {prefixed = 0; next }
              /^PRE$/  {pre = 1; next }
              /^NOT_PRE$/  {pre = 0; next }
              {
              	if (pre) {
              		if (prefixed) print "> " $0;
              		else print $0;
              	} else {
              		if (prefixed) wrap($0, "> ");
              		else wrap($0, "")
              	}
              }
              nedit-5.6.orig/doc/faq-txt.dtd0000644000175000017500000000106707544577621014765 0ustar  paulpaul
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              nedit-5.6.orig/doc/faq-txt.xsl0000644000175000017500000000732007544577621015016 0ustar  paulpaul
              
              
              
              
              /
              
              
              
              
              	
              		
              	
              
              
              
              
              
              
              	
              	
              	
              	
              
              
              
              	

              Version

              FAQ Maintainers:

              ()

                *
              [] ( ) ' ' ' '
              nedit-5.6.orig/doc/faq.dtd0000644000175000017500000000561007544577621014146 0ustar paulpaul nedit-5.6.orig/doc/faq.txt0000644000175000017500000014334107576413317014212 0ustar paulpaul NEDIT FREQUENTLY ASKED QUESTIONS -------------------------------- Version 2001/10/01 NEdit is a popular GUI-style text editor for Unix and VMS systems. These are answers to the most frequently asked questions to discuss@nedit.org. This information is also available from: ftp://ftp.nedit.org/pub//FAQ, and from the NEdit web page at: http://nedit.org. FAQ Maintainers: Florian Xhumari (Florian.Xhumari@free.fr) ABOUT THE NEDIT FAQ ------------------- This FAQ is written in XML and translated to HTML using an XSL stylesheet. The XML source is processed using James Clark's (http://www.jclark.com/) XSLT processor XT (http://www.jclark.com/xml/xt.html) and XML parser XP (http://www.jclark.com/xml/xp). The XSL stylesheet used to generate the HTML version is here (faq.xsl). The text version is generated in three steps: first, an XSL stylesheet (faq-txt.xsl) is used to generate a simple HTML. Then, a second XSL stylesheet (faq-txt-pass2.xsl) transforms the HTML into plain text. An awk script (faq-txt.awk) then performs the word wrapping. For any questions about or contributions to the FAQ, please send a mail to the maintainers (mailto:Florian.Xhumari@free.fr). WHERE TO GET INFORMATION ------------------------ > Where can I get information about NEdit? The NEdit web page is at: http://nedit.org and it is mirrored in Australia at: http://www.au.nedit.org/ The primary ftp site for NEdit is: ftp://ftp.nedit.org/pub which has a mirror in The Netherlands: ftp://ftp.nl.nedit.org/pub/mirror/NEdit The NEdit ftp site has executables for most Unix and VMS systems, sources, documentation, and contributed software. The first and easiest place to look for help with NEdit is the NEdit Help menu. The bottom item in the menu (Problems/Bugs) has answers to the most commonly asked questions about NEdit, which are not duplicated here. Also check the platform specific information in the README file packaged in the NEdit distribution kits. If you have a problem that you really can't figure out, send mail to discuss@nedit.org, and see if anyone else might be having the same trouble. The nedit developers also subscribe to this list, and hopefully someone will be able to answer your question. If you are a Silicon Graphics user and NEdit came bundled on your system, you can also contact SGI's technical support. > Are there any mailing lists for NEdit users? There are two separate mailing lists for nedit users, and one for developers. Users may post to the developer mailing list to report bugs and communicate with the nedit developers. The lists are: * discuss@nedit.org: general discussion, questions and answers among nedit users and developers. * develop@nedit.org: communication among and with nedit developers. Developers should also subscribe to the discuss list. * announce@nedit.org: a low-volume mailing list for announcing new versions. Please note that only subscribers can send mail to the list. The nedit developers subscribe to both discuss@nedit.org and develop@nedit.org, either of which may be used for reporting bugs. If you're not sure, or you think the report might be of interest to the general nedit user community, send the report to discuss@nedit.org. If it's something obvious and boring, like we misspelled "anemometer" in the on-line help, send it to develop@nedit.org. Please do not cross post to both lists! In order to subscribe to a list, send mail to majordomo@nedit.org with one or more of the following in the body of the message: subscribe announce subscribe discuss subscribe develop To unsubscribe do the same with the keyword unsubscribe. unsubscribe announce unsubscribe discuss unsubscribe develop After subscribing, you will receive copies of all of the email submitted to the lists. You may submit mail to the discussion list by sending it to the appropriate list: discuss@nedit.org, develop@nedit.org or announce@nedit.org. The archives of the old mailing lists (nedit_discuss@fnal_gov and nedit_announce@fnal.gov) can be found on egroups.com: * http://www.egroups.com/group/nedit_discuss/ * http://www.egroups.com/group/nedit_announce/ For more information about the mailing lists, refer to the mailing lists section (http://nedit.org/community/mailing.shtml) in the NEdit site. > Where can I get binaries / executables for machines other than those > available at NEdit site? In past versions, we separated "supported" and "unsupported" executables and divided them between the binary and contrib directories. With more supported systems, you're less likely to find executables in the contrib directory, but it's worth a peek, anyhow. If you can't find anything appropriate, you can try asking in a usenet news group appropriate to your system. Other places to try are, the discuss@nedit.org mailing list, or news:comp.windows.x.apps or news:comp.editors. > What can I contribute? If you use and enjoy NEdit, and feel like giving something back to the NEdit user community, contact develop@nedit.org. If you have ported NEdit to a new machine, written a useful set of macros, or would like to contribute to an ongoing development project, we'd love to hear from you. DIAGNOSING AND REPORTING PROBLEMS --------------------------------- > How do I report problems I've encountered using NEdit ? If you have a problem which is not covered in the on-line help, in this FAQ, or in the README file specific to your system, you can report it to discuss@nedit.org (usage questions) or, develop@nedit.org (error reports). Note that these lists only allow members to post, and if you are not a member, your post will probably de delayed in reaching the list. Alternatively you can use the bug tracker on Sourceforge (http://sourceforge.net/projects/nedit/) to report bugs and make feature requests. Below are some suggestions for information you can provide to help in diagnosing your problem. Because NEdit runs on a large number of different platforms and environments, many problems are platform-specific. It's always helpful to know what kind of system it's being run on. Sometimes, strange behavior can also be traced to the X server software or window manager, so you may want to include information on these as well. The origin of the NEdit executable is often important, particularly, whether it came from the NEdit site (http://www.nedit.org), was built locally, or came from some other ftp server or freeware distribution CD. Despite the fact that Motif appears on almost all Unix platforms, the Motif libraries still vary from one machine to another. Be sure to mention whether you're using Lesstif or Motif. As of version 5.2 a summary with build information is present under 'Version' in the Help menu. If you are having configuration or appearance problems, you should probably look at the output from the command: appres NEdit nedit The 'appres' command will show you the resources that NEdit actually sees when it runs, including "stray" resources intended for other programs but not properly qualified by the program name. It will also give you a final objective check as to whether resource settings that you have made are actually readable by NEdit. BUILDING -------- > When I build NEdit on my SunOS system, I get the fillowing undefined > symbols: > > ld: Undefined symbol > _memmove > _atexit > _strerror > *** Error code 1 > make: Fatal error: Command failed for target `nedit' Older versions of the gcc C runtime library were missing these functions. You can either upgrade gcc, or get sources for these functions from ftp://ftp.nedit.org/pub/contrib/misc (which someone else with your very same problem kindly contributed). > I'd like to build NEdit, but my system seems to be missing the Xm... > include files and libXm.a Xm means Motif, which is an important part of NEdit's GUI interface. Motif is standard on commercial Unix workstations, but not on free Unix platforms like Linux and FreeBSD. On these systems, you can now use LessTif, the GPL clone of Motif, or purchase a copy of Motif, which is usually relatively inexpensive, but not free. You can find a list of companies selling Motif for Linux at: http://www.cen.com/mw3/#providers As of this writing LessTif is very close to being a fully reliable and complete replacement for Motif, so it's definitely worth trying before shelling out any money for a commercial copy. Also remember that in most cases, you don't really need Motif libraries to use NEdit. There are plenty of versions available pre-built with the Motif libraries linked in statically. If you can't find one for your system, ask around, and you may find that someone else has already built one for you. Motif licensing allows free distribution of statically linked binaries. Executables for NEdit are available from ftp://ftp.nedit.org/pub//executables. > When I build NEdit, I get the yacc error: > > conflicts: 36 shift/reduce That's normal. NEdit's macro language has a very conflicted grammar, but the conflicts all resolve themselves correctly. The conflicts stem from allowing awk-style no-operator concatenation of strings. > I built NEdit on my Linux system, and it's full of bugs. What a horrible > editor! Several of the Linux distributions began including LessTif (a free version of the Motif GUI library) before it was really ready for general use (particularly for something which needs to be as reliable as a text editor). If you have a version of Lesstif prior to 0.92.26, you have to upgrade it, before it will support NEdit reliably. To get the newest version, go to http://lesstif.org. Alternatively, you can get pre-built, statically linked, executables from ftp://ftp.nedit.org/pub//executables. > While compiling NEdit on Linux, I get the following warning: > > file.o: In function `PrintString': > file.o(.text+0x17b7): the use of `tmpnam' is dangerous, better use `mkstemp' > > Is NEdit insecure? Not if you are using the glibc. The algorithm of mkstemp(3) consists of two parts: the first part is the one used in tmpnam(3) -- this is what NEdit accomplishes by calling tmpnam(3); the second part is done directly in NEdit. > NEdit fails to build on Linux, with messages > > undefined reference to `XpGetDocumentData' > undefined reference to `XpGetPageDimensions' > ... Edit makefiles/Makefile.Linux, and add '-lXp' to the line starting with 'LIB', right before '-lXext'. At this time we are not sure whether libXp (the X print library) is installed on all Linux systems. CUSTOMIZATION ------------- > I can't get the delete key to remap to a forward delete. I have re-bound it > in my .Xdefaults file, and that doesn't help. In your .Xdefaults file, add: nedit.remapDeleteKey: False This is now the default, so you likely have an old resource file sitting around somewhere with this setting. When remapDeleteKey is True), NEdit forcibly maps the delete to backspace. This can be used when the X server and the client machine have different expectations about whether the key in the backspace position on the keyboard is a backspace key or a delete key. It also saves users in very heterogeneous environments from having to re-map keys on nearly every system they use just to be able to backspace. > My X resource settings don't work. It's harder to explain how to specify X resources than you might expect, since how they are set is often configured by your local system manager. They are either automatically attached to the server (your screen) by an X startup or login script, or they are left unspecified, and read from the .Xdefaults file whenever you run an X application. If they are attached to the server, you should find out the "normal" method for setting them on your system. If it's not the .Xdefaults file, then it is usually a file called .Xresources (also in your home directory). To make a change, you have to either run xrdb, or re-invoke the startup script that originally attached them, usually by exiting and re-starting X, or logging out and back in to your X session. Since setting resources is tricky, it's usually better to start with something simple, like: nedit*foreground:green Then, once you have that working, try the more subtle or difficult ones. You can also use the appres command to find out what resources nedit actually sees ('appres NEdit nedit'). > I am setting some X defaults in my $HOME/.nedit file but some of them don't > work. The .nedit file holds the NEdit Preferences menu options and is automatically overwritten whenever you select "Save Defaults". You really shouldn't put X resource settings there. Also, as you may have discovered, resources other than Preferences resources don't always work from there. How you set X resources depends on local system conventions. You usually put them in the .Xdefaults or .Xresources file in your home directory. You may also need to run xrdb to install them in the server. It depends on how your local system has been configured, so it's best to talk to the person who configured your system. If you're not sure whether your resources are set up correctly, the command: appres NEdit nedit will tell you what settings NEdit will see when it runs. > If I install an "app-defaults" file for NEdit (empty too), all default > shortcuts are reset (only "Alt+B" and "Alt+Z" works). Without that file all > works fine. Now, how can I customize nedit with this problem ? Or, how can > I get a copy of all default shortcuts to add on my NEdit "app-defaults" > file ? NEdit uses the X fallback resources mechanism to provide default values for user-settable resources. When you provide a system-wide app- defaults file, it overrides the entire contents of the fallback resources, meaning all of the program defaults are lost, except for those which are also represented in the app-defaults file. To use an app-defaults file, therefore, you need to start from a complete one which provides all of the necessary default values. There is a complete app-defaults file in: ftp://ftp.nedit.org/pub/contrib/misc/nedit.app-defaults We strongly discourage users from using system-wide app-defaults because once you install the file, you have to keep it up to date with every new release of the software. If you don't update it, users might not even notice the difference, but things will be increasingly wrong with each new release. > Where can I get the complete list of nedit resources? The way X is designed, there are a LOT of user settable resources in NEdit, most of them quite useless. You can see them all using the editres tool, which is available on most Unix systems. A more useful subset are the application default resources, which you can look at either in the source code (near the beginning of nedit.c, in the variable called fallbackResources) or in the app-defaults file in: ftp://ftp.nedit.org/pub/contrib/misc/nedit.app-defaults > Can I use 'ispell' with NEdit instead of the less capable Unix 'spell' > command? 'ispell' is actually the default spell checker for NEdit on Linux systems where 'spell' is not available. On other systems, enter the following in the Shell Commands dialog: Command Input: Either Command Output: Same Window Output Replaces Input: ON Shell Command: cat>spellTmp; xterm -e ispell -x spellTmp; cat spellTmp; rm spellTmp If you want to get fancy, the following puts the temporary file in the /tmp directory, and uses $$ (the process ID of the shell) in the file name so you don't have to worry about clashes between simultaneous ispell sessions: cat > /tmp/ispell.$$; xterm -title "Spell Check" -e ispell -S /tmp/ispell.$$; cat /tmp/ispell.$$; rm /tmp/ispell.$$ > How can the display of hidden (eg .login) files in dialog boxes be > suppressed? We use nedit with for teaching programming with very naive and > inexperienced students. The display of these in dialogs such as the "Save > as..." one encourages them to screw up important login stuff, state files > etc. It depends on the system you are running how easy this is to do. Under Motif 2.0, which I think is still only found on Linux and Free-BSD systems, it's a simple resource setting: nedit*XmFileSelectionBox.fileFilterStyle: FILTER_HIDDEN_FILES On other systems, unfortunately, it's a rather difficult source code change, involving creating a replacement file searching procedure to be spliced in to the file selection box widget. > Most Motif applications allow you to type in the file name in a separate > text field (as in the 'open file' dialog). Why doesn't NEdit? Can I make it > do that? Set the X resource nedit.stdOpenDialog to True. The field is disabled by default to get new users accustomed to typing the file name directly in to the list widget, which is not standard Motif behavior. > I would like to change NEdit's cursor from a bar to a block. I seem to lose > it sometimes in my text. The block cursor in NEdit is used to indicate overstrike mode, but you can turn on a resource to make the cursor thicker: nedit*text.heavyCursor: true The only way to get a permanent block cursor, though is to hack the source code. This shouldn't be too difficult, since the code for drawing a block cursor is already there. > I'd like to see more than 8 files in the file selection dialogs (Open, Save > As, Include, etc.). I've tried to set the X-resources like > nedit*XmList.visibleItemCount: 20, but this did not work. The only effective way I've found to control the number of items in the highly temperamental Motif FileSelectionBox widget is through the height resource: nedit*FileSelect.height: 900 The X resource line above will make the file selection box 900 pixels tall. > I am trying to do key bindings such that, for example, Find is Alt+F rather > than Ctrl+F. However, this clashes with the find menu mnemonic. I realize > that the menu mnemonics can be changed to any letter, but they are always > bound to Alt-letter. I would like to just remove all menu mneumonics. Is > there any way to do this in an .Xdefaults file? You can turn mnemonics off by setting them to the ascii null character, for example: nedit*fileMenu.mnemonic: \0 > I have a PC-style 2-button mouse. Can I switch the 2nd and 3rd mouse > buttons so the more important functions like secondary selection are on the > right button instead of the middle (which is emulated by pressing 1+3 > buttons simultaneously under Linux), like they were in version 4? It's somewhat involved and hard to figure out from the documentation, but yes you can. You have to reverse the translation table bindings for mouse buttons 2 and 3, AND reset the bgMenuButton resource. The translation table bindings can either be found in the source file source/text.c, or by adding and activating a temporary translation to the text widget for dumping the translation table itself (XtDisplayTranslations()). What it boils down to, though, is just add the following lines to your X resource file (.Xdefaults or .Xresources depending on your system): NEdit*text.Translations: #override \n\ : secondary_or_drag_start()\n\ Shift Ctrl Button3: \ secondary_or_drag_adjust("rect", "copy", "overlay")\n\ Shift Button3: secondary_or_drag_adjust("copy")\n\ Ctrl Button3: secondary_or_drag_adjust("rect", "overlay")\n\ Button3: secondary_or_drag_adjust()\n\ Shift Ctrl: move_to_or_end_drag("copy", "overlay")\n\ Shift : move_to_or_end_drag("copy")\n\ Alt: exchange()\n\ Meta: exchange()\n\ Ctrl: copy_to_or_end_drag("overlay")\n\ : copy_to_or_end_drag()\n\ Ctrl~Meta~Alt: mouse_pan()\n\ Ctrl~Meta~Alt Button2: mouse_pan()\n\ : end_drag() nedit.bgMenuButton: ~Shift~Ctrl~Meta~Alt > I'd like to send mail directly from my nedit window, but there's no good > way to make a shell command prompt me for input (for entering the recipient > and subject). Use a macro command instead to do the prompting: to = string_dialog("Send mail to: (enter name below, along with any\n" \ "additional Unix Mail command parameters, -s for subject)", \ "Send", "Cancel") if ($string_dialog_button == 2 || $string_dialog_button == 0) return if ($selection_start == -1) body = get_range(0, $text_length) else body = get_selection() cmdOutput = shell_command("Mail " to, body) if ($shell_cmd_status != 0) dialog("mail command returned failed exit status\n" cmdOutput) else if (cmdOutput != "") dialog(cmdOutput) > How I can set the foreground color for selected text to be always say grey1 > even when syntax highlighting is applied? There's no equivalent to the nedit*text.selectForeground resource when you turn on syntax highlighting. You just have to choose a selection color that is compatible with all of your highlighting colors. FEATURES -------- > I'm a little confused about what happend to drag and drop. I thought > drag-N-drop was supported by the Motif library. NEdit no longer uses the Motif text widget, so all of the functionality had to be duplicated in the new widget. Drag and drop between windows got left off due to time pressure of getting out the new release, but it will be back some day. > Why don't you integrate Max Vohlken's / Yunliang Yu's versions into the > official release of NEdit Many of their changes will eventually find their way in to the "official" version, but some will not. Max has really done quite a lot of stuff. I appreciate it, and I think it's kind of neat to have a "bleeding edge" version of NEdit around to try out new features. I can't just apply Max's patches to our version and release it. Some of them break the VMS version, some interfere with existing commands that are important to other users, and some are just customizations that I don't particularly agree with. Mostly, I want to do a lot of testing to make sure the changes are safe on all platforms, and I just don't have time right now. (Mark Edel) Update as of NEdit version 5.2RC1: The forthcoming NEdit version 5.2 contains several functionalities of Max's patches. > I really like nedit and it would be nice to use on windows 95 or NT instead > of word or notepad. Is this possible? There is an NT version of NEdit, available at http://nedit.org/download/win32.shtml. A mini-FAQ is also available. > A feature which is found in in some Macintosh and PC programs, which I > like, is to provide pre-entered default values in text fields. For example, > the find and replace dialogs could show the last search/replace string, or > the currently selected text. These programs select the text, so simply > typing in the field automatically replaces the default without any extra > work from the user. X has a strict convention that there can be only one selection at a time on the whole display. This means that some of the tricks used in PC and Macintosh programs don't work in X. On PCs and Macs, programs can fill in default values in text fields, and select the text that they have inserted such that If the user types over the selection, it will automatically be erased. Under X, there is a price to pay for making an automatic selection. The selection must be "stolen" from some other window, maybe some other program. If the user's intent was to paste a selection that existed before the dialog popped up, once the automatic selection is made, they are out of luck. If NEdit automatically transferred the selection to the Find or Replace dialog, it would either have to steal the selection, or users would have to click or drag the mouse over the text to delete it before they could type anything different. Instead, NEdit has a "Find Selection" command, as well as various methods of pasting and copying the selection into dialog fields. It also allows you to recall of previous search strings in the Find and Replace dialogs via the up-arrow and down-arrow keys. > I would like to use (multiple fonts, special symbols) in my file, but NEdit > seems to allow just one single font. NEdit is a plain text editor, not a word processor. Plain text files have no font or formatting information contained in them, they are just a string of ascii characters. While you might find a font with limited symbols and greek letters, your troubles would just be beginning. You'd still have trouble getting the printer to agree and print out the characters as they appeared in NEdit. For anything involving font changes or special symbols, you need a word processor, such as Microsoft Word, or a text formatting program like LaTEX. > Auto-wrap doesn't work very well. When I type in the middle of a line, I > can push the end of the line beyond the right margin, and when I delete, It > doesn't keep the right edge of the text lined up. You probably want continuous wrap mode (Preferences -> Wrap -> Continuous). Because NEdit is not a word processor, it is stuck with the limits of the plain text format. In the default, auto-newline, wrapping mode, nedit does wrapping by inserting newline characters. Because there is only one newline character, NEdit can't distinguish a newline which can be "unwrapped" from one which the user intended to be permanent. While it might be possible for NEdit to temporarily make that distinction, for example while the cursor is on a particular line that the user is typing, ultimately, NEdit will have to forget this information, because there is no way to save it in the file. Users who work in auto-newline wrap mode tend to make liberal use of the Fill paragraph command. In continuous wrapping mode, you can intentionally leave out the newlines within paragraphs, and lines will be wrapped as needed to fit within the page. When you edit in the middle of a paragraph, the text will be continuously adjusted. However, continuous wrap mode has it's limitations too. All paragraphs must be lined up against the right margin to take advantage of continuous wrapping, and Unix systems have limited support for files of that format. You may have trouble printing and viewing the files outside of NEdit. > NEdit scrolls too fast when I extend a selection by dragging the mouse > outside of the window. NEdit features proportional auto-scrolling, where the speed is controlled by how far your mouse is beyond the edge of the window. If you want it to scroll slower, bring the mouse back closer to the text. > Is there a special symbol (as % for filename in the shell commands) that > can be used to represent the text that is selected, which can then be used > as an argument to a command? For instance, I want to feed the selection to > a script so that it can be used as the expression to a 'grep' command. Is > there any other way that I can accomplish this goal? Below is an example from the NEdit discussion list (from David L. Paterline) of a "Find All" command implemented by using the selection as an argument to the grep command: I set up a command to list all lines in a file which contain the highlighted selection as follows, using the Preferences -> Shell Commands menu: Menu Entry: all Command Input: selection Command Output: new window Save file before: yes Shell Command: grep -n -- "`cat -`" % The 'cat -' portion of the command echoes the selected text to the 'grep -n' command, which lists the lines containing the selection with line numbers. The output of the command appears in a new window; I can then highlight a line number in the new window and use the Search -> Goto Selected menu in the original window to jump to the line in the original file. > How can I print highlighted text on my printer as it appears in NEdit. In the current version, that's not possible, but there are external tools for highlighting, which are specifically designed for printing, including a2ps, enscript, and genscript. SERVER MODE AND NC ------------------ > I use a mailer which can invoke an external editor, but if I use nc, the > mailer process continues and assumes the editor has finished, when in fact > it hasn't. nc is actually finished communicating with the NEdit server when it returns. It's possible to create a shell command that invokes nc and then goes to sleep, and a second script to be run from the NEdit Shell menu, which looks for the sleeping process with a matching file name and kills it. Try the shell scripts in: ftp://ftp.nedit.org/pub/contrib/misc/nc_and_wait.tar > I started nedit (via 'nc') as root, and then later tried to edit a file as > myself with 'nc'. I was very suprised to see that a new nedit wasn't > started--rather, I was given the old nedit window, with root permissions. > Isn't this a security hole? Actually, NEdit does check who the user is. When you use the su command, however, several Unix variants return the original user name in response to the standard C library calls for getting a user name, rather than the name to which you have su'd. Starting with version 5.1, a different mechanism is used for getting this information, so you shouldn't see this problem any more. In your case, my guess is that you used su to become root, then started an nedit server as root. On a system which returns the original user name, both the new server and the nc client program think the user name is your original user name, so the server accepts requests from both you as root and you as you. The security of an nedit session, depends upon the security of your X server. Only those with access to your screen can send commands to an nedit server, but they can also send keystrokes to any nedit, or a shell window, etc... Anyhow, just upgrade to the latest NEdit version. EDITING TECHNIQUES ------------------ > I'd like to select a large expanse of text without dragging all the way > through it with the mouse. Using the shift key with the left mouse button, you can select all of the text between the cursor (or an existing selection) and the mouse. * Position the cursor at one end of the desired selection * Use the scroll bar to make the other end visible * Shift+Click with the left mouse button to select the text between the cursor and the mouse Alternatively, using only keyboard navigation: * Position the cursor at one end of the desired selection * Type Alt-m and a letter to mark the position * Use the keyboard to go to the other end of the desired selection * Type Shift-Alt-g and the letter you used to mark the first end of the selection > How can I select the text between two marks? * Go to the first mark (Goto Mark). * Hold the shift key while selecting Goto Mark or Alt+Shift+G to select the text. BUGS ---- > The keyboard shortcuts (accelerator keys) are not working when 'Caps' or > 'Num Lock' are switched on. Have I overlooked something obvious? You haven't overlooked anything, it's a Motif design flaw. Netscape painfully works around this and the Alt/Meta key reversal on Sun workstations by internally re-implementing the Motif menu accelerator mechanism. NEdit will likely follow suit with the release of version 5.2. Another possibility (writes Peter Daifuku of SGI): There's another answer which unfortunately isn't widespread as yet. For an X11R6.3 X server supporting the XKB extension, there is a mechanism to ignore the NumLock and CapsLock key as modifiers. The file /usr/lib/X11/xkb/X0-config.keyboard should contain the string IgnoreLockMods=NumLock+Lock . For systems with multiple displays, display 1 would be controlled by the file X1-config.keyboard, etc. On SGI systems, this mechanism is support on IRIX 6.2 with X server patch 1574 or later, on IRIX 6.3 and IRIX 6.4 and all later releases. > Sometimes NEdit inserts instead of saving the file when I type ^S. > Other keyboard shortcuts (accelerator keys) don't work either. You have probably NumLock or CapsLock ON. See the answer to this (#N900) question. > I use the numeric keypad really often, so I keep NumLock on. But NEdit > shortcuts don't work when NumLock is on. The bug is not in NEdit, but in Motif. This is fixed as of NEdit 5.2, but that might not help you much. Older versions have the same problem. Here's how you tell X to interpret the keypad keys as numbers without turning NumLock on. Create a file .Xmodmap in your home directory, and put the following lines in it: keycode 79 = KP_7 keycode 80 = KP_8 keycode 81 = KP_9 keycode 83 = KP_4 keycode 84 = KP_5 keycode 85 = KP_6 keycode 87 = KP_1 keycode 88 = KP_2 keycode 89 = KP_3 keycode 90 = KP_0 keycode 91 = KP_Decimal Then make sure the script that starts your X session parses this file with the command: xmodmap -merge ~/.Xmodmap This script can be ~/.xinitrc (called by startx) or something like Xsession if you use xdm/kdm/gdm. Then again, it might be an entirely different script on some systems. Then turn off numlock, and just continue using the keypad. The only thing is, you loose the alternate set of functions (cursor/home/pgdown/etc). > NEdit crashes I try to paste text in to a text field in a dialog (like Find > or Replace) on my SunOS system. On many SunOS systems, you have to set up an nls directory before various inter-client communication features of Motif will function properly. Before NEdit 4.0 this wasn't much of a problem, because users couldn't cut and paste at all, and Motif would sometimes print a warning about not finding an nls directory, so most users figured it out right away. But with 4.0, everything seems to be working fine, except when someone tries to move text in or out of a dialog field, then blamo. There are instructions in README.sun in ftp://ftp.nedit.org/pub/ NEdit crashes frequently, particularly on window closing. There is an obsolete resource in Motif called defaultFontList, which does nothing but cause random crashing. I don't know why NEdit users keep popping up with this resource set, maybe it looks enticing when you look at widget resources with editres. Anyhow, setting it to anything, whether it be a valid font or just garbage, causes random crashing in both Motif 1.2 and 2.0, so just don't set it. > NEdit sometimes crashes when I execute a shell command menu item I just > added. Check the "Command Input" setting, in the Preferences->Shell Commands dialog for that menu item. If the shell command being executed does not take input, but "Command Input" is set to "selection" or "window", NEdit tries to write the input anyhow, and fails. Set "Command Input" to "none" to prevent this possibility. This is fixed in version 5.1 and later. > When NEdit starts up, I get errors: > > Cannot allocate colormap entry for "#b3b3b3" > Cannot allocate colormap entry for "#e5e5e5" Most X displays are set up to operate in a mode which allocates 8 bits of video memory per-pixel, and requires a color mapping table to translate pixel values to screen colors. With just 8 bits there are only 256 possible colors, and programs must either allocate and share these pixel values, or swap in their own colormap and make all other windows flash to strange colors while their window is focused. Some programs, Netscape in particular, are bad neighbors in this environment and snarf up every free entry in the shared colormap, such that every program that runs after them gets the errors you're asking about. The solution is either to start Netscape last, after all other applications that you might want to run, or better, tell Netscape how many colors it is allowed to allocate. Fortunately, you can do this with a resource setting: Netscape*maxImageColors: 80 > Sometimes when I use regular expression replacement inside of a rectangular > selection, NEdit fails to match text which does legally match the > expression. The problem with REs and rectangular selections is that matching is bounded by the rectangular selection, but text outside of the selection is still fed to the matching routines, so ^, $, don't refer to the edges of the selection, they still refer to the beginning and ending of the line, and some legal matches are excluded because they continue outside of the selection are thereby excluded, or are shadowed by matches which begin or end outside of the selection. > When ever I execute an nedit shell command (such as spell or wc) I get > (extra junk, error messages, complaints from stty) inserted into my text, > or an Information dialog with (extra junk, error messages, complaints from > stty). You probably have printing commands in your shell startup file (.cshrc, or equivalent). These should either be skipped in non-interactive mode, or moved to your .login file. You can often see the problem outside of nedit by typing: csh -c ls Error messages from stty are a result of it being executed from a process which isn't attached to a terminal. You can safely move stty statements and most other interactive commands to your .login file (calling stty from a .cshrc file is redundant because the terminal device doesn't change for each sub-shell). If you can't remove interactive commands, you should skip around them in non-interactive shells, I think the usual method is to put them at the end, preceded by something like: if ($?prompt == 0) exit The manual entry on csh has more information on this. > On a Solaris system, when trying to open a file within nedit, you get the > listing of available file names. However, the sub-window (on the right) > containing the file names (not directory names) sometimes is too narrow so > that you can't see the filename part (i.e. > /usr/people/rainer/sometextfile.txt shows up as /usr/people/rain or so). > When resizing the dialog box, the filenames sub-window on the right doesn't > become larger. I know I can use nedit.stdOpenDialog to type a filename, but > that's annoying. It's a bug in the shared Motif library. Depending on your system, the patch is one of ID# 103461-07, # 102226-19, or # 103186-21. If you can't patch your system, you can set the resource: nedit*XmFileSelectionBox.pathMode: XmPATH_MODE_RELATIVE This will stop the dialog from displaying the path component of file names. Another possible workaround is to use the nedit_sunos executable (from ftp://ftp.nedit.org/pub/), which is statically linked with a good Motif. > When I try to open a file from the "Open" dialog nothing appears in the > "Filter" textfield. Instead, I get repeated message like: > > Name: Text > Class: XmTextField > Character '/' not supported in font. Discarded. In some versions of S.u.S.E. Linux, there's apparently something wrong with their builds of NEdit and other Motif apps. I've been told you can make nedit work by seting the environment variable LD_PRELOAD to /lib/libBrokenLocale.so.1 before launching it. You can also use the statically linked version of NEdit for Linux from ftp://ftp.nedit.org/pub/ > NEdit seems to be running very slowly on my Solaris 2.6 system. If you're running NEdit on a Solaris 2.6 system and experiencing performance problems (windows come up slowly), the patch for Sun's shared Motif library is ID# 105284-04. Installing the patch alone will improve the performance dramatically. The patch also enables a resource, *XmMenuReduceGrabs. Setting this to True will eliminate the delay completely. > I can't seem to enter accented characters on my system. This should be working properly on most systems as of NEdit 5.1 or later. If it's not, try re-building NEdit with -DNO_XMIM. If it still doesn't work, send mail to develop@nedit.org > When I try to use nc to start an nedit server, for instance using > > nc (filename) > > I receive the following error message: > > (filename): forward host lookup failed: > Host name lookup failure: Connection refused There is another program called 'nc' which is installed on some systems. In this case, 'nc' is for 'netcat', some kind of network diagnostic tool. You can safely rename NEdit's 'nc' to something else (we recommend ncl), or put it first in your path before 'netcat'. > Whenever I try to open existing files by using menu, nedit crashes, and > sometimes I get the following error message: > > X Error of failed request: BadAlloc (insufficient resources for operation) > Major opcode of failed request: 53 (X_CreatePixmap) > > But if I type 'nedit filename' command, it works. So how can I open file by > using menu bar? Several users have reported this problem. Most of them were using S.u.S.E. Linux . A few others had different distributions, but always European. The problem appears to be related to how Motif searches for named pixmaps and bitmaps. My guess is that on some systems, this search encounters a match with a bad pixmap file, or tries to load something which is not a pixmap at all. One solution was to set the environment variable XBMLANGPATH to a random directory. For example: XBMLANGPATH=. export XBMLANGPATH The solution on S.u.S.E Linux systems was to remove an unnecessary line in the global /etc/profile (provided by S.u.S.E.): export XAPPLRESDIR= "$XAPPLRESDIR:/var/X11R6/app-defaults:/usr/X11R6/lib/X11/app-defaults" Another user who had the problem reported that the root cause appeared to be insufficient read permissions on some xm_* (e.g. xm_warning) pixmaps in "/usr/X11R6/include/X11/bitmaps". (Could someone else confirm this?) > I want to be able to spawn a command from NEdit. By this I mean that I want > to NEdit to launch another program without waiting for the program to > return. At the moment I'd like to be able to launch 'mctags', but I also > have a variety of other things I'd like to do. The shell command: 'mctags > &' continues to wait for mctags to finish, despite the "&". Is there any > way to do what I want? It's a bug/feature of NEdit that it considers a shell command process alive as long as any of it's file descriptors remain open. Forked processes generally copy and keep open the stdout and stderr descriptors from their parent process, so you have to add '>& /dev/null' to your shell command, so it reads: mctags >& /dev/null & > NEdit flashes or matches the wrong parenthesis, bracket, or brace if there > is an intervening paren/bracket/brace quoted in between. Until version 5.0, NEdit had no way of even knowing what language you were operating in when making the flash/match decision, so it simply counted opening and closing instances, disregarding language syntax context (strings, comments, etc.) completely. Now that the feature is more possible to implement, it may be included in a future version, but I'm not entirely sure how best to do it yet. > I'd like to edit a file which is about 50 Megabytes long. Whenever I try to > read this file, there was always a message as following: > > Error: Cannot perform realloc How large a file you can edit with NEdit depends on how much swap space + RAM you have, since it loads your file into virtual memory and occasionally does a full copy of that memory space. NEdit can handle a 100MB file reasonably well if you increase your swap space, but I don't know how far beyond that it can go. To work with a 100MB file, you must have at least 200MB of virtual memory available. Many Unix systems can be set up to temporarily increase swap space by creating a temporary swap file. > We installed NEdit Version 5.0 recently, and the accelerators Ctrl-G (Find > again) and Ctrl-L (Goto Line Number) are now missing You have an out-of-date app-defaults file. We strongly recommend not using such files for this exact reason. When you use an app-defaults file, it replaces ALL of the program defaults. If you do install an app-defaults file, it is your responsibility to keep it up to date with each new release of the executable. Otherwise, as you have observed, certain features will degrade with each release, as the app-defaults file and the executable get further and further out of sync with eachother. > On our PCs we have Windows 3.1 and we run XVision as X-Server. The problem > that we have is, that we cannot mark with the mouse within NEdit. > > When you click and hold the left mouse button and then move the mouse, you > can see the mark-area flickering during the movement of the mouse. When > stopping the movement nothing is highlighted and nothing is marked. XVision is grabbing the selection immediately, as soon as it is made, not allowing applications to own it. This behavior is completely wrong, and I have no idea what they might have been thinking when they implemented it. It may be possible to turn it off, ask their technical support people if they're not already out of business. > My regular expression replacement got truncated! I wrote a regular > expression to nest additional braces around blocks of code (replace > {([^{}]|\n)*} with {\0}), which works for small blocks of text, but it > fails on large ones, truncating the replacement at around 512 bytes. A remnant of pre-regular-expression, pre-macro-language NEdit, is that replacement strings are limited to 511 bytes. This is high on the list to fix in a future upgrade. > NEdit is slow and pages continuously on my 8MB Linux system On most Unix workstations, 8MB of RAM is actually insufficient to run X and Motif properly. Some Linux users get by with it and Linux itself seems to be quite memory efficient, but you really should have 12 or 16 if you're going to be using X much. NEdit would not be my first choice in editors on an 8MB system. > Some of the special keys on my keyboard don't do what I expect. X systems are rife with this kind of problem because are just too many levels of re-settable bindings between the keyboard and the application program that reads it. Sun systems are the worst offenders, combining poor Motif support with a variety of strange keyboard arrangements. To diagnose these problems, you have to look at all three levels of key binding that affect Motif programs. At the bottom level are the modifier map and keymap table, where hardware key codes are bound to X keysyms. You can see the bindings on this level with the xmodmap program (see man xmodmap). A useful tool in debugging the xmodmap level is a program like xev, which can show you the keysyms it receives. The next level up from that is the motif virtual binding level (see man VirtualBindings). You can (usually) view the bindings at this level by looking at the value of the root window property: _MOTIF_DEFAULT_BINDINGS, using the xprop -root command, however what you see is not necessarily what you'll get. The defaults for these bindings are determined by an unbelievably complicated process involving not just the application in question, but Motif applications which have run before it attached to the same server. This process is described in detail in the VirtualBindings manual page (which is often not available on systems where the bindings are messed up). While it's usually better to attack system configuration problems at the source, this one is so contorted that you're better off with a patch. Luckily, the default Motif virtual bindings can be overridden by an application resource called defaultVirtualBindings. If you think the problem is at the Motif virtual binding level, define a defaultVirtualBindings resource in your .Xresources or .Xdefaults file, using the example below as a template, replacing the keysym names (to the right of the colon) with the keysyms shown by xev when you press the desired key: ! ! Motif Virtual Key Bindings ! nedit*defaultVirtualBindings: \ osfActivate : KP_Enter\n\ osfCancel : Escape\n\ osfHelp : Help\n\ osfMenu : F4\n\ osfMenuBar : F10\n\ osfLeft : Left\n\ osfUp : Up\n\ osfRight : Right\n\ osfDown : Down\n\ osfBeginLine : Home\n\ osfEndLine : End\n\ osfPageUp : Prior\n\ osfPageDown : Next\n\ osfBackSpace : BackSpace\n\ osfDelete : Delete\n\ osfInsert : Insert\n\ osfUndo : F14\n\ osfAddMode :Shift F8\n\ osfCopy : F16\n\ osfCut : F20\n\ osfPaste : F18\n If NEdit is having binding problems, chances are that other Motif-based programs are also having trouble. Removing the "nedit" from the resource name above (just *defaultVirtualBindings), will apply it to the other Motif programs that you run as well. The top level bindings in the key binding hierarchy, are the X toolkit translation tables (see the NEdit Help section called X Resources). To show the translations in use, you can add a binding which dumps the table itself: nedit*text.Translations: #override \ Altt: XtDisplayTranslations()\n Typing Alt+T will then display the contents of the translation table to stdout (the terminal from which you started NEdit). If you have the NEdit source, you can also look at the default bindings in the module text.c. Sometimes, even if you don't understand the problem, you can patch around it by supplying translations for the keysyms that NEdit actually sees, binding them to the action routines that you want activated when you press that key. > KP Enter does no longer executes the current line or selected text as a > shell command. How can I get this behavior back? It was considered dangerous to have a commonly used key potentially execute arbitrary shell commands unintentionally (think rm -Rf). Therefore the shortcut was changed to Ctrl+KP Enter. In case you want the old binding back, you can add the following lines to your .Xdefaults or .Xresources file: nedit*shellMenu.executeCommandLine.accelerator: KP_Enter", nedit*shellMenu.executeCommandLine.acceleratorText: KP Enter", nedit-5.6.orig/doc/faq.xml0000644000175000017500000017712607576413331014177 0ustar paulpaul NEdit Frequently Asked Questions 2001/10/01 Florian Xhumari Florian.Xhumari@free.fr NEdit FAQ

              NEdit is a popular GUI-style text editor for Unix and VMS systems. These are answers to the most frequently asked questions to discuss@nedit.org. This information is also available from:

              ftp://ftp.nedit.org/pub/<current>/FAQ,

              and from the NEdit web page at:

              http://nedit.org.

              The FAQ is available for download in a variety of formats.

              • HTML pages: faq.tar.gz or faq.zip.
              • Plain text: faq.txt.
              • XML source: faq.xml as well as its DTD faq.dtd.
              About the NEdit FAQ

              This FAQ is written in XML and translated to HTML using an XSL stylesheet. The XML source is processed using James Clark's XSLT processor XT and XML parser XP.

              The XSL stylesheet used to generate the HTML version is here.

              The text version is generated in three steps: first, an XSL stylesheet is used to generate a simple HTML. Then, a second XSL stylesheet transforms the HTML into plain text. An awk script then performs the word wrapping.

              For any questions about or contributions to the FAQ, please send a mail to the maintainers.

              Where to get information Where can I get information about NEdit?

              The NEdit web page is at:

              http://nedit.org

              and it is mirrored in Australia at:

              http://www.au.nedit.org/

              The primary ftp site for NEdit is:

              ftp://ftp.nedit.org/pub

              which has a mirror in The Netherlands:

              ftp://ftp.nl.nedit.org/pub/mirror/NEdit

              The NEdit ftp site has executables for most Unix and VMS systems, sources, documentation, and contributed software.

              The first and easiest place to look for help with NEdit is the NEdit Help menu. The bottom item in the menu (Problems/Bugs) has answers to the most commonly asked questions about NEdit, which are not duplicated here. Also check the platform specific information in the README file packaged in the NEdit distribution kits.

              If you have a problem that you really can't figure out, send mail to discuss@nedit.org, and see if anyone else might be having the same trouble. The nedit developers also subscribe to this list, and hopefully someone will be able to answer your question. If you are a Silicon Graphics user and NEdit came bundled on your system, you can also contact SGI's technical support.

              Are there any mailing lists for NEdit users?

              There are two separate mailing lists for nedit users, and one for developers. Users may post to the developer mailing list to report bugs and communicate with the nedit developers.

              The lists are:

              • discuss@nedit.org: general discussion, questions and answers among nedit users and developers.
              • develop@nedit.org: communication among and with nedit developers. Developers should also subscribe to the discuss list.
              • announce@nedit.org: a low-volume mailing list for announcing new versions.

              Please note that only subscribers can send mail to the list.

              The nedit developers subscribe to both discuss@nedit.org and develop@nedit.org, either of which may be used for reporting bugs. If you're not sure, or you think the report might be of interest to the general nedit user community, send the report to discuss@nedit.org. If it's something obvious and boring, like we misspelled "anemometer" in the on-line help, send it to develop@nedit.org.

              Please do not cross post to both lists!

              In order to subscribe to a list, send mail to majordomo@nedit.org with one or more of the following in the body of the message:

                  subscribe announce
                  subscribe discuss
                  subscribe develop
              

              To unsubscribe do the same with the keyword unsubscribe.

                  unsubscribe announce
                  unsubscribe discuss
                  unsubscribe develop
              

              After subscribing, you will receive copies of all of the email submitted to the lists. You may submit mail to the discussion list by sending it to the appropriate list: discuss@nedit.org, develop@nedit.org or announce@nedit.org.

              The archives of the old mailing lists (nedit_discuss@fnal_gov and nedit_announce@fnal.gov) can be found on egroups.com:

              • http://www.egroups.com/group/nedit_discuss/
              • http://www.egroups.com/group/nedit_announce/

              For more information about the mailing lists, refer to the mailing lists section in the NEdit site.

              Where can I get binaries / executables for machines other than those available at NEdit site?

              In past versions, we separated "supported" and "unsupported" executables and divided them between the binary and contrib directories. With more supported systems, you're less likely to find executables in the contrib directory, but it's worth a peek, anyhow. If you can't find anything appropriate, you can try asking in a usenet news group appropriate to your system. Other places to try are, the discuss@nedit.org mailing list, or news:comp.windows.x.apps or news:comp.editors.

              What can I contribute?

              If you use and enjoy NEdit, and feel like giving something back to the NEdit user community, contact develop@nedit.org. If you have ported NEdit to a new machine, written a useful set of macros, or would like to contribute to an ongoing development project, we'd love to hear from you.

              Diagnosing and reporting problems How do I report problems I've encountered using NEdit ?

              If you have a problem which is not covered in the on-line help, in this FAQ, or in the README file specific to your system, you can report it to discuss@nedit.org (usage questions) or, develop@nedit.org (error reports). Note that these lists only allow members to post, and if you are not a member, your post will probably de delayed in reaching the list. Alternatively you can use the bug tracker on Sourceforge (http://sourceforge.net/projects/nedit/) to report bugs and make feature requests. Below are some suggestions for information you can provide to help in diagnosing your problem.

              Because NEdit runs on a large number of different platforms and environments, many problems are platform-specific. It's always helpful to know what kind of system it's being run on. Sometimes, strange behavior can also be traced to the X server software or window manager, so you may want to include information on these as well.

              The origin of the NEdit executable is often important, particularly, whether it came from the NEdit site (http://www.nedit.org), was built locally, or came from some other ftp server or freeware distribution CD. Despite the fact that Motif appears on almost all Unix platforms, the Motif libraries still vary from one machine to another. Be sure to mention whether you're using Lesstif or Motif. As of version 5.2 a summary with build information is present under 'Version' in the Help menu.

              If you are having configuration or appearance problems, you should probably look at the output from the command:

                 appres NEdit nedit
              

              The appres command will show you the resources that NEdit actually sees when it runs, including "stray" resources intended for other programs but not properly qualified by the program name. It will also give you a final objective check as to whether resource settings that you have made are actually readable by NEdit.

              Building When I build NEdit on my SunOS system, I get undefined symbols: _memmove, _atexit, _strerror.

              When I build NEdit on my SunOS system, I get the fillowing undefined symbols:

              ld: Undefined symbol
                 _memmove
                 _atexit
                 _strerror
              *** Error code 1
              make: Fatal error: Command failed for target `nedit'
              

              Older versions of the gcc C runtime library were missing these functions. You can either upgrade gcc, or get sources for these functions from ftp://ftp.nedit.org/pub/contrib/misc (which someone else with your very same problem kindly contributed).

              I'd like to build NEdit, but my system seems to be missing the Xm... include files and libXm.a

              Xm means Motif, which is an important part of NEdit's GUI interface. Motif is standard on commercial Unix workstations, but not on free Unix platforms like Linux and FreeBSD. On these systems, you can now use LessTif, the GPL clone of Motif, or purchase a copy of Motif, which is usually relatively inexpensive, but not free. You can find a list of companies selling Motif for Linux at:

              http://www.cen.com/mw3/#providers

              As of this writing LessTif is very close to being a fully reliable and complete replacement for Motif, so it's definitely worth trying before shelling out any money for a commercial copy. Also remember that in most cases, you don't really need Motif libraries to use NEdit. There are plenty of versions available pre-built with the Motif libraries linked in statically. If you can't find one for your system, ask around, and you may find that someone else has already built one for you. Motif licensing allows free distribution of statically linked binaries. Executables for NEdit are available from ftp://ftp.nedit.org/pub/<current-version>/executables.

              When I build NEdit, I get the yacc error: conflicts: 36 shift/reduce

              When I build NEdit, I get the yacc error:

                conflicts: 36 shift/reduce
              

              That's normal. NEdit's macro language has a very conflicted grammar, but the conflicts all resolve themselves correctly. The conflicts stem from allowing awk-style no-operator concatenation of strings.

              I built NEdit on my Linux system, and it's full of bugs. What a horrible editor!

              Several of the Linux distributions began including LessTif (a free version of the Motif GUI library) before it was really ready for general use (particularly for something which needs to be as reliable as a text editor). If you have a version of Lesstif prior to 0.92.26, you have to upgrade it, before it will support NEdit reliably. To get the newest version, go to http://lesstif.org. Alternatively, you can get pre-built, statically linked, executables from ftp://ftp.nedit.org/pub/<current-version>/executables.

              Thorsten Haude While compiling NEdit on Linux, I get a warning about tmpnam being dangerous.

              While compiling NEdit on Linux, I get the following warning:

                  file.o: In function `PrintString':
                  file.o(.text+0x17b7): the use of `tmpnam' is dangerous, better use `mkstemp'
              

              Is NEdit insecure?

              Not if you are using the glibc. The algorithm of mkstemp(3) consists of two parts: the first part is the one used in tmpnam(3) -- this is what NEdit accomplishes by calling tmpnam(3); the second part is done directly in NEdit.

              Joor Loohuis NEdit fails to build on Linux, with messages about `XpGetDocumentData'

              NEdit fails to build on Linux, with messages

                 undefined reference to `XpGetDocumentData'
                 undefined reference to `XpGetPageDimensions'
                 ...
              

              Edit makefiles/Makefile.Linux, and add '-lXp' to the line starting with 'LIB', right before '-lXext'. At this time we are not sure whether libXp (the X print library) is installed on all Linux systems.

              Customization I can't get the delete key to remap to a forward delete

              I can't get the delete key to remap to a forward delete. I have re-bound it in my .Xdefaults file, and that doesn't help.

              In your .Xdefaults file, add:

              nedit.remapDeleteKey: False

              This is now the default, so you likely have an old resource file sitting around somewhere with this setting. When remapDeleteKey is True), NEdit forcibly maps the delete to backspace. This can be used when the X server and the client machine have different expectations about whether the key in the backspace position on the keyboard is a backspace key or a delete key. It also saves users in very heterogeneous environments from having to re-map keys on nearly every system they use just to be able to backspace.

              My X resource settings don't work.

              It's harder to explain how to specify X resources than you might expect, since how they are set is often configured by your local system manager. They are either automatically attached to the server (your screen) by an X startup or login script, or they are left unspecified, and read from the .Xdefaults file whenever you run an X application. If they are attached to the server, you should find out the "normal" method for setting them on your system. If it's not the .Xdefaults file, then it is usually a file called .Xresources (also in your home directory). To make a change, you have to either run xrdb, or re-invoke the startup script that originally attached them, usually by exiting and re-starting X, or logging out and back in to your X session.

              Since setting resources is tricky, it's usually better to start with something simple, like:

              nedit*foreground:green

              Then, once you have that working, try the more subtle or difficult ones. You can also use the appres command to find out what resources nedit actually sees (appres NEdit nedit).

              I am setting some X defaults in my $HOME/.nedit file but some of them don't work.

              The .nedit file holds the NEdit Preferences menu options and is automatically overwritten whenever you select "Save Defaults". You really shouldn't put X resource settings there. Also, as you may have discovered, resources other than Preferences resources don't always work from there.

              How you set X resources depends on local system conventions. You usually put them in the .Xdefaults or .Xresources file in your home directory. You may also need to run xrdb to install them in the server. It depends on how your local system has been configured, so it's best to talk to the person who configured your system. If you're not sure whether your resources are set up correctly, the command:

                  appres NEdit nedit
              

              will tell you what settings NEdit will see when it runs.

              If I install an "app-defaults" file for NEdit (empty too), all default shortcuts are reset

              If I install an "app-defaults" file for NEdit (empty too), all default shortcuts are reset (only "Alt+B" and "Alt+Z" works). Without that file all works fine. Now, how can I customize nedit with this problem ? Or, how can I get a copy of all default shortcuts to add on my NEdit "app-defaults" file ?

              NEdit uses the X fallback resources mechanism to provide default values for user-settable resources. When you provide a system-wide app- defaults file, it overrides the entire contents of the fallback resources, meaning all of the program defaults are lost, except for those which are also represented in the app-defaults file. To use an app-defaults file, therefore, you need to start from a complete one which provides all of the necessary default values. There is a complete app-defaults file in:

              ftp://ftp.nedit.org/pub/contrib/misc/nedit.app-defaults

              We strongly discourage users from using system-wide app-defaults because once you install the file, you have to keep it up to date with every new release of the software. If you don't update it, users might not even notice the difference, but things will be increasingly wrong with each new release.

              Where can I get the complete list of nedit resources?

              The way X is designed, there are a LOT of user settable resources in NEdit, most of them quite useless. You can see them all using the editres tool, which is available on most Unix systems. A more useful subset are the application default resources, which you can look at either in the source code (near the beginning of nedit.c, in the variable called fallbackResources) or in the app-defaults file in:

              ftp://ftp.nedit.org/pub/contrib/misc/nedit.app-defaults

              Can I use ispell with NEdit instead of the less capable Unix spell command?

              ispell is actually the default spell checker for NEdit on Linux systems where spell is not available. On other systems, enter the following in the Shell Commands dialog:

                Command Input: Either
                Command Output: Same Window
                Output Replaces Input: ON
                Shell Command: cat>spellTmp; xterm -e ispell -x spellTmp; cat spellTmp; rm spellTmp
              

              If you want to get fancy, the following puts the temporary file in the /tmp directory, and uses $$ (the process ID of the shell) in the file name so you don't have to worry about clashes between simultaneous ispell sessions:

                cat > /tmp/ispell.$$; xterm -title "Spell Check" -e
                ispell -S /tmp/ispell.$$; cat /tmp/ispell.$$; rm /tmp/ispell.$$
              
              How can the display of hidden (eg .login) files in dialog boxes be suppressed

              How can the display of hidden (eg .login) files in dialog boxes be suppressed? We use nedit with for teaching programming with very naive and inexperienced students. The display of these in dialogs such as the "Save as..." one encourages them to screw up important login stuff, state files etc.

              It depends on the system you are running how easy this is to do. Under Motif 2.0, which I think is still only found on Linux and Free-BSD systems, it's a simple resource setting:

              nedit*XmFileSelectionBox.fileFilterStyle: FILTER_HIDDEN_FILES

              On other systems, unfortunately, it's a rather difficult source code change, involving creating a replacement file searching procedure to be spliced in to the file selection box widget.

              Why, in the 'open file' dialog, there is no text field where to type in the file name?

              Most Motif applications allow you to type in the file name in a separate text field (as in the 'open file' dialog). Why doesn't NEdit? Can I make it do that?

              Set the X resource nedit.stdOpenDialog to True. The field is disabled by default to get new users accustomed to typing the file name directly in to the list widget, which is not standard Motif behavior.

              I would like to change NEdit's cursor from a bar to a block

              I would like to change NEdit's cursor from a bar to a block. I seem to lose it sometimes in my text.

              The block cursor in NEdit is used to indicate overstrike mode, but you can turn on a resource to make the cursor thicker:

              nedit*text.heavyCursor: true

              The only way to get a permanent block cursor, though is to hack the source code. This shouldn't be too difficult, since the code for drawing a block cursor is already there.

              I'd like to see more than 8 files in the file selection dialogs (Open, Save As, etc.)

              I'd like to see more than 8 files in the file selection dialogs (Open, Save As, Include, etc.). I've tried to set the X-resources like nedit*XmList.visibleItemCount: 20, but this did not work.

              The only effective way I've found to control the number of items in the highly temperamental Motif FileSelectionBox widget is through the height resource:

              nedit*FileSelect.height: 900

              The X resource line above will make the file selection box 900 pixels tall.

              I am trying to do key bindings such that, for example, Find is Alt+F rather than Ctrl+F, but this clashes with the find menu mnemonic

              I am trying to do key bindings such that, for example, Find is Alt+F rather than Ctrl+F. However, this clashes with the find menu mnemonic. I realize that the menu mnemonics can be changed to any letter, but they are always bound to Alt-letter. I would like to just remove all menu mneumonics. Is there any way to do this in an .Xdefaults file?

              You can turn mnemonics off by setting them to the ascii null character, for example:

              nedit*fileMenu.mnemonic: \0

              I have a PC-style 2-button mouse and I would like to switch the 2nd and 3rd (emulated) mouse buttons

              I have a PC-style 2-button mouse. Can I switch the 2nd and 3rd mouse buttons so the more important functions like secondary selection are on the right button instead of the middle (which is emulated by pressing 1+3 buttons simultaneously under Linux), like they were in version 4?

              It's somewhat involved and hard to figure out from the documentation, but yes you can. You have to reverse the translation table bindings for mouse buttons 2 and 3, AND reset the bgMenuButton resource. The translation table bindings can either be found in the source file source/text.c, or by adding and activating a temporary translation to the text widget for dumping the translation table itself (XtDisplayTranslations()).

              What it boils down to, though, is just add the following lines to your X resource file (.Xdefaults or .Xresources depending on your system):

                NEdit*text.Translations: #override \n\
                   <Btn3Down>: secondary_or_drag_start()\n\
                   Shift Ctrl Button3<MotionNotify>: \
                       secondary_or_drag_adjust("rect", "copy", "overlay")\n\
                   Shift Button3<MotionNotify>: secondary_or_drag_adjust("copy")\n\
                   Ctrl Button3<MotionNotify>: secondary_or_drag_adjust("rect", "overlay")\n\
                   Button3<MotionNotify>: secondary_or_drag_adjust()\n\
                   Shift Ctrl<Btn3Up>: move_to_or_end_drag("copy", "overlay")\n\
                   Shift <Btn3Up>: move_to_or_end_drag("copy")\n\
                   Alt<Btn3Up>: exchange()\n\
                   Meta<Btn3Up>: exchange()\n\
                   Ctrl<Btn3Up>: copy_to_or_end_drag("overlay")\n\
                   <Btn3Up>: copy_to_or_end_drag()\n\
                   Ctrl~Meta~Alt<Btn2Down>: mouse_pan()\n\
                   Ctrl~Meta~Alt Button2<MotionNotify>: mouse_pan()\n\
                   <Btn2Up>: end_drag()
                nedit.bgMenuButton: ~Shift~Ctrl~Meta~Alt<Btn2Down>
              
              How can I make a shell command prompt me for input?

              I'd like to send mail directly from my nedit window, but there's no good way to make a shell command prompt me for input (for entering the recipient and subject).

              Use a macro command instead to do the prompting:

                to = string_dialog("Send mail to: (enter name below, along with any\n" \
                    "additional Unix Mail command parameters, -s for subject)", \
                    "Send", "Cancel")
                if ($string_dialog_button == 2 || $string_dialog_button == 0)
                    return
                if ($selection_start == -1)
                    body = get_range(0, $text_length)
                else
                    body = get_selection()
                cmdOutput = shell_command("Mail " to, body)
                if ($shell_cmd_status != 0)
                    dialog("mail command returned failed exit status\n" cmdOutput)
                else if (cmdOutput != "")
                    dialog(cmdOutput)
              
              How I can set the foreground color for selected text when syntax highlighting is applied?

              How I can set the foreground color for selected text to be always say grey1 even when syntax highlighting is applied?

              There's no equivalent to the nedit*text.selectForeground resource when you turn on syntax highlighting. You just have to choose a selection color that is compatible with all of your highlighting colors.

              Features Why NEdit does not support drag and drop?

              I'm a little confused about what happend to drag and drop. I thought drag-N-drop was supported by the Motif library.

              NEdit no longer uses the Motif text widget, so all of the functionality had to be duplicated in the new widget. Drag and drop between windows got left off due to time pressure of getting out the new release, but it will be back some day.

              Why don't you integrate Max Vohlken's / Yunliang Yu's versions into the official release of NEdit

              Many of their changes will eventually find their way in to the "official" version, but some will not. Max has really done quite a lot of stuff. I appreciate it, and I think it's kind of neat to have a "bleeding edge" version of NEdit around to try out new features.

              I can't just apply Max's patches to our version and release it. Some of them break the VMS version, some interfere with existing commands that are important to other users, and some are just customizations that I don't particularly agree with. Mostly, I want to do a lot of testing to make sure the changes are safe on all platforms, and I just don't have time right now. (Mark Edel)

              Update as of NEdit version 5.2RC1: The forthcoming NEdit version 5.2 contains several functionalities of Max's patches.

              Is it possible to use NEdit on windows 95 or NT?

              I really like nedit and it would be nice to use on windows 95 or NT instead of word or notepad. Is this possible?

              There is an NT version of NEdit, available at http://nedit.org/download/win32.shtml. A mini-FAQ is also available.

              Why aren't there pre-entered default values in text fields of dialogs?

              A feature which is found in in some Macintosh and PC programs, which I like, is to provide pre-entered default values in text fields. For example, the find and replace dialogs could show the last search/replace string, or the currently selected text. These programs select the text, so simply typing in the field automatically replaces the default without any extra work from the user.

              X has a strict convention that there can be only one selection at a time on the whole display. This means that some of the tricks used in PC and Macintosh programs don't work in X. On PCs and Macs, programs can fill in default values in text fields, and select the text that they have inserted such that If the user types over the selection, it will automatically be erased. Under X, there is a price to pay for making an automatic selection. The selection must be "stolen" from some other window, maybe some other program. If the user's intent was to paste a selection that existed before the dialog popped up, once the automatic selection is made, they are out of luck.

              If NEdit automatically transferred the selection to the Find or Replace dialog, it would either have to steal the selection, or users would have to click or drag the mouse over the text to delete it before they could type anything different. Instead, NEdit has a "Find Selection" command, as well as various methods of pasting and copying the selection into dialog fields. It also allows you to recall of previous search strings in the Find and Replace dialogs via the up-arrow and down-arrow keys.

              I would like to use (multiple fonts, special symbols) in my file, but NEdit seems to allow just one single font.

              NEdit is a plain text editor, not a word processor. Plain text files have no font or formatting information contained in them, they are just a string of ascii characters. While you might find a font with limited symbols and greek letters, your troubles would just be beginning. You'd still have trouble getting the printer to agree and print out the characters as they appeared in NEdit. For anything involving font changes or special symbols, you need a word processor, such as Microsoft Word, or a text formatting program like LaTEX.

              Auto-wrap doesn't work well

              Auto-wrap doesn't work very well. When I type in the middle of a line, I can push the end of the line beyond the right margin, and when I delete, It doesn't keep the right edge of the text lined up.

              You probably want continuous wrap mode (Preferences -> Wrap -> Continuous).

              Because NEdit is not a word processor, it is stuck with the limits of the plain text format. In the default, auto-newline, wrapping mode, nedit does wrapping by inserting newline characters. Because there is only one newline character, NEdit can't distinguish a newline which can be "unwrapped" from one which the user intended to be permanent. While it might be possible for NEdit to temporarily make that distinction, for example while the cursor is on a particular line that the user is typing, ultimately, NEdit will have to forget this information, because there is no way to save it in the file. Users who work in auto-newline wrap mode tend to make liberal use of the Fill paragraph command.

              In continuous wrapping mode, you can intentionally leave out the newlines within paragraphs, and lines will be wrapped as needed to fit within the page. When you edit in the middle of a paragraph, the text will be continuously adjusted. However, continuous wrap mode has it's limitations too. All paragraphs must be lined up against the right margin to take advantage of continuous wrapping, and Unix systems have limited support for files of that format. You may have trouble printing and viewing the files outside of NEdit.

              NEdit scrolls too fast when I extend a selection by dragging the mouse outside of the window.

              NEdit features proportional auto-scrolling, where the speed is controlled by how far your mouse is beyond the edge of the window. If you want it to scroll slower, bring the mouse back closer to the text.

              Is there a special symbol that represents the selected text, usable in shell commands?

              Is there a special symbol (as % for filename in the shell commands) that can be used to represent the text that is selected, which can then be used as an argument to a command? For instance, I want to feed the selection to a script so that it can be used as the expression to a 'grep' command. Is there any other way that I can accomplish this goal?

              Below is an example from the NEdit discussion list (from David L. Paterline) of a "Find All" command implemented by using the selection as an argument to the grep command:

              I set up a command to list all lines in a file which contain the highlighted selection as follows, using the Preferences -> Shell Commands menu:

                      Menu Entry:           all <selection>
                      Command Input:        selection
                      Command Output:       new window
                      Save file before:     yes
                      Shell Command:        grep -n -- "`cat -`" %
              

              The cat - portion of the command echoes the selected text to the grep -n command, which lists the lines containing the selection with line numbers. The output of the command appears in a new window; I can then highlight a line number in the new window and use the Search -> Goto Selected menu in the original window to jump to the line in the original file.

              How can I print highlighted text on my printer as it appears in NEdit.

              In the current version, that's not possible, but there are external tools for highlighting, which are specifically designed for printing, including a2ps, enscript, and genscript.

              Server mode and nc I want to use nc as an external editor from my mailer, but my mailer doesn't wait for the editor to finish

              I use a mailer which can invoke an external editor, but if I use nc, the mailer process continues and assumes the editor has finished, when in fact it hasn't.

              nc is actually finished communicating with the NEdit server when it returns. It's possible to create a shell command that invokes nc and then goes to sleep, and a second script to be run from the NEdit Shell menu, which looks for the sleeping process with a matching file name and kills it. Try the shell scripts in:

              ftp://ftp.nedit.org/pub/contrib/misc/nc_and_wait.tar

              I started nedit as root, then tried later to edit a file as myself with nc; the file was opened in the root's nedit

              I started nedit (via nc) as root, and then later tried to edit a file as myself with nc. I was very suprised to see that a new nedit wasn't started--rather, I was given the old nedit window, with root permissions. Isn't this a security hole?

              Actually, NEdit does check who the user is. When you use the su command, however, several Unix variants return the original user name in response to the standard C library calls for getting a user name, rather than the name to which you have su'd. Starting with version 5.1, a different mechanism is used for getting this information, so you shouldn't see this problem any more.

              In your case, my guess is that you used su to become root, then started an nedit server as root. On a system which returns the original user name, both the new server and the nc client program think the user name is your original user name, so the server accepts requests from both you as root and you as you.

              The security of an nedit session, depends upon the security of your X server. Only those with access to your screen can send commands to an nedit server, but they can also send keystrokes to any nedit, or a shell window, etc... Anyhow, just upgrade to the latest NEdit version.

              Editing techniques I'd like to select a large expanse of text without dragging all the way through it with the mouse.

              Using the shift key with the left mouse button, you can select all of the text between the cursor (or an existing selection) and the mouse.

              • Position the cursor at one end of the desired selection
              • Use the scroll bar to make the other end visible
              • Shift+Click with the left mouse button to select the text between the cursor and the mouse

              Alternatively, using only keyboard navigation:

              • Position the cursor at one end of the desired selection
              • Type Alt-m and a letter to mark the position
              • Use the keyboard to go to the other end of the desired selection
              • Type Shift-Alt-g and the letter you used to mark the first end of the selection
              How can I select the text between two marks?
              • Go to the first mark (Goto Mark).
              • Hold the shift key while selecting Goto Mark or Alt+Shift+G to select the text.
              Bugs The keyboard shortcuts (accelerator keys) are not working when 'Caps' or 'Num Lock' are switched on.

              The keyboard shortcuts (accelerator keys) are not working when 'Caps' or 'Num Lock' are switched on. Have I overlooked something obvious?

              You haven't overlooked anything, it's a Motif design flaw. Netscape painfully works around this and the Alt/Meta key reversal on Sun workstations by internally re-implementing the Motif menu accelerator mechanism. NEdit will likely follow suit with the release of version 5.2.

              Another possibility (writes Peter Daifuku of SGI):

              There's another answer which unfortunately isn't widespread as yet. For an X11R6.3 X server supporting the XKB extension, there is a mechanism to ignore the NumLock and CapsLock key as modifiers. The file /usr/lib/X11/xkb/X0-config.keyboard should contain the string IgnoreLockMods=NumLock+Lock . For systems with multiple displays, display 1 would be controlled by the file X1-config.keyboard, etc.

              On SGI systems, this mechanism is support on IRIX 6.2 with X server patch 1574 or later, on IRIX 6.3 and IRIX 6.4 and all later releases.

              Sometimes NEdit inserts <dc3> instead of saving the file when I type ^S

              Sometimes NEdit inserts <dc3> instead of saving the file when I type ^S. Other keyboard shortcuts (accelerator keys) don't work either.

              You have probably NumLock or CapsLock ON. See the answer to this question.
              Joor Loohuis I use the numeric keypad really often, so I keep NumLock on. But NEdit shortcuts don't work when NumLock is on.

              The bug is not in NEdit, but in Motif. This is fixed as of NEdit 5.2, but that might not help you much. Older versions have the same problem.

              Here's how you tell X to interpret the keypad keys as numbers without turning NumLock on. Create a file .Xmodmap in your home directory, and put the following lines in it:

                keycode  79 = KP_7
                keycode  80 = KP_8
                keycode  81 = KP_9
                keycode  83 = KP_4
                keycode  84 = KP_5
                keycode  85 = KP_6
                keycode  87 = KP_1
                keycode  88 = KP_2
                keycode  89 = KP_3
                keycode  90 = KP_0
                keycode  91 = KP_Decimal
              

              Then make sure the script that starts your X session parses this file with the command:

                xmodmap -merge ~/.Xmodmap
              

              This script can be ~/.xinitrc (called by startx) or something like Xsession if you use xdm/kdm/gdm. Then again, it might be an entirely different script on some systems.

              Then turn off numlock, and just continue using the keypad. The only thing is, you loose the alternate set of functions (cursor/home/pgdown/etc).

              NEdit crashes I try to paste text in to a text field in a dialog (like Find or Replace) on my SunOS system.

              On many SunOS systems, you have to set up an nls directory before various inter-client communication features of Motif will function properly. Before NEdit 4.0 this wasn't much of a problem, because users couldn't cut and paste at all, and Motif would sometimes print a warning about not finding an nls directory, so most users figured it out right away. But with 4.0, everything seems to be working fine, except when someone tries to move text in or out of a dialog field, then blamo.

              There are instructions in README.sun in ftp://ftp.nedit.org/pub/<current-version<, as well as a tar file containg a complete nls directory: ftp://ftp.nedit.org/pub/<current-version</individual/README.sun

              It contains directions for setting up an nls directory, which is required by Motif for handling copy and paste to Motif text fields.

              NEdit crashes frequently, particularly on window closing.

              There is an obsolete resource in Motif called defaultFontList, which does nothing but cause random crashing. I don't know why NEdit users keep popping up with this resource set, maybe it looks enticing when you look at widget resources with editres. Anyhow, setting it to anything, whether it be a valid font or just garbage, causes random crashing in both Motif 1.2 and 2.0, so just don't set it.

              NEdit sometimes crashes when I execute a shell command menu item I just added.

              Check the "Command Input" setting, in the Preferences->Shell Commands dialog for that menu item. If the shell command being executed does not take input, but "Command Input" is set to "selection" or "window", NEdit tries to write the input anyhow, and fails. Set "Command Input" to "none" to prevent this possibility. This is fixed in version 5.1 and later.

              When NEdit starts up, I get errors like: Cannot allocate colormap entry for "#b3b3b3".

              When NEdit starts up, I get errors:

                 Cannot allocate colormap entry for "#b3b3b3"
                 Cannot allocate colormap entry for "#e5e5e5"
              

              Most X displays are set up to operate in a mode which allocates 8 bits of video memory per-pixel, and requires a color mapping table to translate pixel values to screen colors. With just 8 bits there are only 256 possible colors, and programs must either allocate and share these pixel values, or swap in their own colormap and make all other windows flash to strange colors while their window is focused. Some programs, Netscape in particular, are bad neighbors in this environment and snarf up every free entry in the shared colormap, such that every program that runs after them gets the errors you're asking about.

              The solution is either to start Netscape last, after all other applications that you might want to run, or better, tell Netscape how many colors it is allowed to allocate. Fortunately, you can do this with a resource setting:

              Netscape*maxImageColors: 80

              Sometimes when I use regular expression replacement inside of a rectangular selection, NEdit fails to match text.

              Sometimes when I use regular expression replacement inside of a rectangular selection, NEdit fails to match text which does legally match the expression.

              The problem with REs and rectangular selections is that matching is bounded by the rectangular selection, but text outside of the selection is still fed to the matching routines, so ^, $, don't refer to the edges of the selection, they still refer to the beginning and ending of the line, and some legal matches are excluded because they continue outside of the selection are thereby excluded, or are shadowed by matches which begin or end outside of the selection.

              When ever I execute a nedit shell command (such as spell or wc) I get extra junk.

              When ever I execute an nedit shell command (such as spell or wc) I get (extra junk, error messages, complaints from stty) inserted into my text, or an Information dialog with (extra junk, error messages, complaints from stty).

              You probably have printing commands in your shell startup file (.cshrc, or equivalent). These should either be skipped in non-interactive mode, or moved to your .login file. You can often see the problem outside of nedit by typing:

                  csh -c ls
              

              Error messages from stty are a result of it being executed from a process which isn't attached to a terminal. You can safely move stty statements and most other interactive commands to your .login file (calling stty from a .cshrc file is redundant because the terminal device doesn't change for each sub-shell). If you can't remove interactive commands, you should skip around them in non-interactive shells, I think the usual method is to put them at the end, preceded by something like:

                  if ($?prompt == 0) exit
              

              The manual entry on csh has more information on this.

              On a Solaris system, the right part of the 'file open' dialog is too narrow, I can't see the complete file names.

              On a Solaris system, when trying to open a file within nedit, you get the listing of available file names. However, the sub-window (on the right) containing the file names (not directory names) sometimes is too narrow so that you can't see the filename part (i.e. /usr/people/rainer/sometextfile.txt shows up as /usr/people/rain or so). When resizing the dialog box, the filenames sub-window on the right doesn't become larger. I know I can use nedit.stdOpenDialog to type a filename, but that's annoying.

              It's a bug in the shared Motif library. Depending on your system, the patch is one of ID# 103461-07, # 102226-19, or # 103186-21. If you can't patch your system, you can set the resource:

                  nedit*XmFileSelectionBox.pathMode:  XmPATH_MODE_RELATIVE
              

              This will stop the dialog from displaying the path component of file names. Another possible workaround is to use the nedit_sunos executable (from ftp://ftp.nedit.org/pub/), which is statically linked with a good Motif.

              When I try to open a file from the "Open" dialog nothing appears in the "Filter" textfield

              When I try to open a file from the "Open" dialog nothing appears in the "Filter" textfield. Instead, I get repeated message like:

                  Name: Text
                  Class: XmTextField
                  Character '/' not supported in font.  Discarded.
              

              In some versions of S.u.S.E. Linux, there's apparently something wrong with their builds of NEdit and other Motif apps. I've been told you can make nedit work by seting the environment variable LD_PRELOAD to /lib/libBrokenLocale.so.1 before launching it. You can also use the statically linked version of NEdit for Linux from ftp://ftp.nedit.org/pub/

              NEdit seems to be running very slowly on my Solaris 2.6 system.

              If you're running NEdit on a Solaris 2.6 system and experiencing performance problems (windows come up slowly), the patch for Sun's shared Motif library is ID# 105284-04. Installing the patch alone will improve the performance dramatically. The patch also enables a resource, *XmMenuReduceGrabs. Setting this to True will eliminate the delay completely.

              I can't seem to enter accented characters on my system.

              This should be working properly on most systems as of NEdit 5.1 or later. If it's not, try re-building NEdit with -DNO_XMIM. If it still doesn't work, send mail to develop@nedit.org

              When I try to use nc to start an nedit server, I receive a message (filename): forward host lookup failed: ...

              When I try to use nc to start an nedit server, for instance using

                  nc (filename)
              

              I receive the following error message:

                 (filename): forward host lookup failed:
                             Host name lookup failure: Connection refused
              

              There is another program called nc which is installed on some systems. In this case, nc is for netcat, some kind of network diagnostic tool. You can safely rename NEdit's nc to something else (we recommend ncl), or put it first in your path before netcat.

              Whenever I try to open existing files by using menu, nedit crashes; but if I type nedit filename command, it works.

              Whenever I try to open existing files by using menu, nedit crashes, and sometimes I get the following error message:

                 X Error of failed request:  BadAlloc (insufficient resources for operation)
                 Major opcode of failed request:  53 (X_CreatePixmap)
              

              But if I type nedit filename command, it works. So how can I open file by using menu bar?

              Several users have reported this problem. Most of them were using S.u.S.E. Linux . A few others had different distributions, but always European. The problem appears to be related to how Motif searches for named pixmaps and bitmaps. My guess is that on some systems, this search encounters a match with a bad pixmap file, or tries to load something which is not a pixmap at all. One solution was to set the environment variable XBMLANGPATH to a random directory. For example:

                XBMLANGPATH=.
                export XBMLANGPATH
              

              The solution on S.u.S.E Linux systems was to remove an unnecessary line in the global /etc/profile (provided by S.u.S.E.):

                export XAPPLRESDIR=
                    "$XAPPLRESDIR:/var/X11R6/app-defaults:/usr/X11R6/lib/X11/app-defaults"
              

              Another user who had the problem reported that the root cause appeared to be insufficient read permissions on some xm_* (e.g. xm_warning) pixmaps in "/usr/X11R6/include/X11/bitmaps". (Could someone else confirm this?)

              I want to be able to spawn a command from NEdit.

              I want to be able to spawn a command from NEdit. By this I mean that I want to NEdit to launch another program without waiting for the program to return. At the moment I'd like to be able to launch mctags, but I also have a variety of other things I'd like to do. The shell command: mctags & continues to wait for mctags to finish, despite the "&". Is there any way to do what I want?

              It's a bug/feature of NEdit that it considers a shell command process alive as long as any of it's file descriptors remain open. Forked processes generally copy and keep open the stdout and stderr descriptors from their parent process, so you have to add >& /dev/null to your shell command, so it reads:

                  mctags >& /dev/null &
              
              NEdit flashes or matches the wrong parenthesis, bracket, or brace if there is an intervening paren/bracket/brace quoted in between.

              Until version 5.0, NEdit had no way of even knowing what language you were operating in when making the flash/match decision, so it simply counted opening and closing instances, disregarding language syntax context (strings, comments, etc.) completely. Now that the feature is more possible to implement, it may be included in a future version, but I'm not entirely sure how best to do it yet.

              I'd like to edit a file which is about 50 Megabytes long, but I get errors.

              I'd like to edit a file which is about 50 Megabytes long. Whenever I try to read this file, there was always a message as following:

                  Error: Cannot perform realloc
              

              How large a file you can edit with NEdit depends on how much swap space + RAM you have, since it loads your file into virtual memory and occasionally does a full copy of that memory space. NEdit can handle a 100MB file reasonably well if you increase your swap space, but I don't know how far beyond that it can go. To work with a 100MB file, you must have at least 200MB of virtual memory available. Many Unix systems can be set up to temporarily increase swap space by creating a temporary swap file.

              We installed NEdit Version 5.0 recently, and the accelerators Ctrl-G (Find again) and Ctrl-L (Goto Line Number) are now missing

              You have an out-of-date app-defaults file. We strongly recommend not using such files for this exact reason. When you use an app-defaults file, it replaces ALL of the program defaults. If you do install an app-defaults file, it is your responsibility to keep it up to date with each new release of the executable. Otherwise, as you have observed, certain features will degrade with each release, as the app-defaults file and the executable get further and further out of sync with eachother.

              On our PCs we have Windows 3.1 and we run XVision as X-Server and we cannot mark with the mouse within NEdit.

              On our PCs we have Windows 3.1 and we run XVision as X-Server. The problem that we have is, that we cannot mark with the mouse within NEdit.

              When you click and hold the left mouse button and then move the mouse, you can see the mark-area flickering during the movement of the mouse. When stopping the movement nothing is highlighted and nothing is marked.

              XVision is grabbing the selection immediately, as soon as it is made, not allowing applications to own it. This behavior is completely wrong, and I have no idea what they might have been thinking when they implemented it. It may be possible to turn it off, ask their technical support people if they're not already out of business.

              My regular expression replacement got truncated!

              My regular expression replacement got truncated! I wrote a regular expression to nest additional braces around blocks of code (replace {([^{}]|\n)*} with {\0}), which works for small blocks of text, but it fails on large ones, truncating the replacement at around 512 bytes.

              A remnant of pre-regular-expression, pre-macro-language NEdit, is that replacement strings are limited to 511 bytes. This is high on the list to fix in a future upgrade.

              NEdit is slow and pages continuously on my 8MB Linux system

              On most Unix workstations, 8MB of RAM is actually insufficient to run X and Motif properly. Some Linux users get by with it and Linux itself seems to be quite memory efficient, but you really should have 12 or 16 if you're going to be using X much. NEdit would not be my first choice in editors on an 8MB system.

              Some of the special keys on my keyboard don't do what I expect.

              X systems are rife with this kind of problem because are just too many levels of re-settable bindings between the keyboard and the application program that reads it. Sun systems are the worst offenders, combining poor Motif support with a variety of strange keyboard arrangements.

              To diagnose these problems, you have to look at all three levels of key binding that affect Motif programs.

              At the bottom level are the modifier map and keymap table, where hardware key codes are bound to X keysyms. You can see the bindings on this level with the xmodmap program (see man xmodmap). A useful tool in debugging the xmodmap level is a program like xev, which can show you the keysyms it receives.

              The next level up from that is the motif virtual binding level (see man VirtualBindings). You can (usually) view the bindings at this level by looking at the value of the root window property: _MOTIF_DEFAULT_BINDINGS, using the xprop -root command, however what you see is not necessarily what you'll get. The defaults for these bindings are determined by an unbelievably complicated process involving not just the application in question, but Motif applications which have run before it attached to the same server. This process is described in detail in the VirtualBindings manual page (which is often not available on systems where the bindings are messed up). While it's usually better to attack system configuration problems at the source, this one is so contorted that you're better off with a patch. Luckily, the default Motif virtual bindings can be overridden by an application resource called defaultVirtualBindings. If you think the problem is at the Motif virtual binding level, define a defaultVirtualBindings resource in your .Xresources or .Xdefaults file, using the example below as a template, replacing the keysym names (to the right of the colon) with the keysyms shown by xev when you press the desired key:

                 !
                 ! Motif Virtual Key Bindings
                 !
                 nedit*defaultVirtualBindings: \
                      osfActivate     :               <Key>KP_Enter\n\
                      osfCancel       :               <Key>Escape\n\
                      osfHelp         :               <Key>Help\n\
                      osfMenu         :               <Key>F4\n\
                      osfMenuBar      :               <Key>F10\n\
                      osfLeft         :               <Key>Left\n\
                      osfUp           :               <Key>Up\n\
                      osfRight        :               <Key>Right\n\
                      osfDown         :               <Key>Down\n\
                      osfBeginLine    :               <Key>Home\n\
                      osfEndLine      :               <Key>End\n\
                      osfPageUp       :               <Key>Prior\n\
                      osfPageDown     :               <Key>Next\n\
                      osfBackSpace    :               <Key>BackSpace\n\
                      osfDelete       :               <Key>Delete\n\
                      osfInsert       :               <Key>Insert\n\
                      osfUndo         :               <Key>F14\n\
                      osfAddMode      :Shift          <Key>F8\n\
                      osfCopy         :               <Key>F16\n\
                      osfCut          :               <Key>F20\n\
                      osfPaste        :               <Key>F18\n
              

              If NEdit is having binding problems, chances are that other Motif-based programs are also having trouble. Removing the "nedit" from the resource name above (just *defaultVirtualBindings), will apply it to the other Motif programs that you run as well.

              The top level bindings in the key binding hierarchy, are the X toolkit translation tables (see the NEdit Help section called X Resources). To show the translations in use, you can add a binding which dumps the table itself:

                  nedit*text.Translations: #override \
                      Alt<Key>t: XtDisplayTranslations()\n
              

              Typing Alt+T will then display the contents of the translation table to stdout (the terminal from which you started NEdit). If you have the NEdit source, you can also look at the default bindings in the module text.c.

              Sometimes, even if you don't understand the problem, you can patch around it by supplying translations for the keysyms that NEdit actually sees, binding them to the action routines that you want activated when you press that key.

              KP Enter does no longer executes the current line or selected text as a shell command. How can I get this behavior back?

              It was considered dangerous to have a commonly used key potentially execute arbitrary shell commands unintentionally (think rm -Rf). Therefore the shortcut was changed to Ctrl+KP Enter. In case you want the old binding back, you can add the following lines to your .Xdefaults or .Xresources file:

                 nedit*shellMenu.executeCommandLine.accelerator: <Key>KP_Enter",
                 nedit*shellMenu.executeCommandLine.acceleratorText: KP Enter",
              
              nedit-5.6.orig/doc/faq.xsl0000644000175000017500000001462407544577621014206 0ustar paulpaul t /skin/style.css <!-- --> <xsl:value-of select="title"/> <xsl:value-of select="version" />


              Table of Contents


              Download the FAQ

              Overview

            4. [NEdit] FAQ: <xsl:value-of select="title"/>


              [ ] [FAQ Contents] [ ]
            5. . true true
              FAQ FAQ
            6. nedit-5.6.orig/doc/help.etx0000644000175000017500000100510010756654327014345 0ustar paulpaul.. $Id: help.etx,v 1.111 2008/02/19 22:31:51 ajbj Exp $ .. NOTE: Remember to supply 'version' variable on setext command line. .. For example, setext -m -v "version=NEdit Version 6.0". .. .. The following are variable definitions for the various titles below .. ---------------------------------------------------------------------------- .. |>title=Nirvana Editor (NEdit) Help Documentation<| .. |>ttlMk==========================================<| .. ---------------------------------------------------------------------------- .. ? NEDITDOC~ |>ttlMk<| |>title<| |>ttlMk<| |>version<| |>Date<| .. ~ NEDITDOC .. ! NEDITDOC~ |>title<| |>ttlMk<| .. ? html~ .. .. .. This table of contents is only for the HTML version of this document. .. Table of Contents ----------------- Getting_Started_ Basic Operation Macro/Shell Extensions Selecting_Text_ Shell_Commands_and_Filters_ Finding_and_Replacing_Text_ Learn/Replay_ Cut_and_Paste_ Macro_Language_ Using_the_Mouse_ Macro_Subroutines_ Keyboard_Shortcuts_ Highlighting_Information_ Shifting_and_Filling_ Range_Sets_ Tabbed_Editing_ Action_Routines_ File_Format_ Customizing Features for Programming Customizing_NEdit_ Programming_with_NEdit_ Preferences_ Tabs/Emulated_Tabs_ X_Resources_ Auto/Smart_Indent_ Key_Binding_ Syntax_Highlighting_ Highlighting_Patterns_ Finding_Declarations_(ctags)_ Smart_Indent_Macros_ Calltips_ Regular Expressions NEdit_Command_Line_ Basic_Regular_Expression_Syntax_ Client/Server_Mode_ Metacharacters_ Crash_Recovery_ Parenthetical_Constructs_ Version_ Advanced_Topics_ GNU_General_Public_License_ Example_Regular_Expressions_ Mailing_Lists_ Problems/Defects_ .. ~ html Getting Started --------------- Welcome to NEdit! .. ~ NEDITDOC .. .. What appears below will always print whether or not NEDITDOC is defined. .. NEdit is a standard GUI (Graphical User Interface) style text editor for programs and plain-text files. Users of Macintosh and MS Windows based text editors should find NEdit a familiar and comfortable environment. NEdit provides all of the standard menu, dialog, editing, and mouse support, as well as all of the standard shortcuts to which the users of modern GUI based environments are accustomed. For users of older style Unix editors, welcome to the world of mouse-based editing! .. ? NEDITDOC~ .. NEdit is freely distributed under the terms of the Gnu General Public .. License. .. .. This stuff will always be invisible, unless NEDITDOC is defined .. .. Installing NEdit .. ---------------- .. .. NEdit is a single stand-alone executable file which can be installed by simply .. copying the appropriate executable "nedit" for your system. Both sources and .. executables are available from http://www.nedit.org. The optional "nc" (NEdit .. Client) program is also available for users who want to run nedit in .. client/server mode. .. .. Getting Started .. --------------- .. ~ NEDITDOC Help sections of interest to new users are listed under the "Basic Operation" heading in the top-level Help menu: Selecting_Text_ Finding_and_Replacing_Text_ Cut_and_Paste_ Using_the_Mouse_ Keyboard_Shortcuts_ Shifting_and_Filling_ Programmers should also read the introductory section under the "Features for Programming" section: Programming_with_NEdit_ If you get into trouble, the Undo command in the Edit menu can reverse any modifications that you make. NEdit does not change the file you are editing until you tell it to Save. 3>Editing an Existing File To open an existing file, choose Open... from the file menu. Select the file that you want to open in the pop-up dialog that appears and click on OK. You may open any number of files at the same time. Depending on your settings (cf. "Tabbed_Editing_") each file can appear in its own editor window, or it can appear under a tab in the same editor window. Using Open... rather than re-typing the NEdit command and running additional copies of NEdit, will give you quick access to all of the files you have open via the Windows menu, and ensure that you don't accidentally open the same file twice. NEdit has no "main" window. It remains running as long as at least one editor window is open. 3>Creating a New File If you already have an empty (Untitled) window displayed, just begin typing in the window. To create a new Untitled window, choose New Window or New Tab from the File menu. To give the file a name and save its contents to the disk, choose Save or Save As... from the File menu. 3>Backup Files NEdit maintains periodic backups of the file you are editing so that you can recover the file in the event of a problem such as a system crash, network failure, or X server crash. These files are saved under the name `~filename` (on Unix) or `_filename` (on VMS), where filename is the name of the file you were editing. If an NEdit process is killed, some of these backup files may remain in your directory. (To remove one of these files on Unix, you may have to prefix the `~' (tilde) character with a (backslash) to prevent the shell from interpreting it as a special character.) 3>Shortcuts As you become more familiar with NEdit, substitute the control and function keys shown on the right side of the menus for pulling down menus with the mouse. Dialogs are also streamlined so you can enter information quickly and without using the mouse*. To move the keyboard focus around a dialog, use the tab and arrow keys. One of the buttons in a dialog is usually drawn with a thick, indented, outline. This button can be activated by pressing Return or Enter. The Cancel or Dismiss button can be activated by pressing escape. For example, to replace the string "thing" with "things" type: thingthings To open a file named "whole_earth.c", type: who (how much of the filename you need to type depends on the other files in the directory). See the section called "Keyboard_Shortcuts_" for more details. * Users who have set their keyboard focus mode to "pointer" should set "Popups Under Pointer" in the Default Settings menu to avoid the additional step of moving the mouse into the dialog. ---------------------------------------------------------------------- Basic Operation =============== Selecting Text -------------- NEdit has two general types of selections, primary (highlighted text), and secondary (underlined text). Selections can cover either a simple range of text between two points in the file, or they can cover a rectangular area of the file. Rectangular selections are only useful with non-proportional (fixed spacing) fonts. To select text for copying, deleting, or replacing, press the left mouse button with the pointer at one end of the text you want to select, and drag it to the other end. The text will become highlighted. To select a whole word, double click (click twice quickly in succession). Double clicking and then dragging the mouse will select a number of words. Similarly, you can select a whole line or a number of lines by triple clicking or triple clicking and dragging. Quadruple clicking selects the whole file. After releasing the mouse button, you can still adjust a selection by holding down the shift key and dragging on either end of the selection. To delete the selected text, press delete or backspace. To replace it, begin typing. To select a rectangle or column of text, hold the Ctrl key while dragging the mouse. Rectangular selections can be used in any context that normal selections can be used, including cutting and pasting, filling, shifting, dragging, and searching. Operations on rectangular selections automatically fill in tabs and spaces to maintain alignment of text within and to the right of the selection. Note that the interpretation of rectangular selections by Fill Paragraph is slightly different from that of other commands, the section titled "Shifting_and_Filling_" has details. The middle mouse button can be used to make an additional selection (called the secondary selection). As soon as the button is released, the contents of this selection will be copied to the insert position of the window where the mouse was last clicked (the destination window). This position is marked by a caret shaped cursor when the mouse is outside of the destination window. If there is a (primary) selection, adjacent to the cursor in the window, the new text will replace the selected text. Holding the shift key while making the secondary selection will move the text, deleting it at the site of the secondary selection, rather than copying it. Selected text can also be dragged to a new location in the file using the middle mouse button. Holding the shift key while dragging the text will copy the selected text, leaving the original text in place. Holding the control key will drag the text in overlay mode. Normally, dragging moves text by removing it from the selected position at the start of the drag, and inserting it at a new position relative to the mouse. Dragging a block of text over existing characters, displaces the characters to the end of the selection. In overlay mode, characters which are occluded by blocks of text being dragged are simply removed. When dragging non-rectangular selections, overlay mode also converts the selection to rectangular form, allowing it to be dragged outside of the bounds of the existing text. The section "Using_the_Mouse_" summarizes the mouse commands for making primary and secondary selections. Primary selections can also be made via keyboard commands, see "Keyboard_Shortcuts_". ---------------------------------------------------------------------- Finding and Replacing Text -------------------------- The Search menu contains a number of commands for finding and replacing text. The Find... and Replace... commands present dialogs for entering text for searching and replacing. These dialogs also allow you to choose whether you want the search to be sensitive to upper and lower case, or whether to use the standard Unix pattern matching characters (regular expressions). Searches begin at the current text insertion position. Find Again and Replace Again repeat the last find or replace command without prompting for search strings. To selectively replace text, use the two commands in combination: Find Again, then Replace Again if the highlighted string should be replaced, or Find Again again to go to the next string. Find Selection searches for the text contained in the current primary selection (see Selecting_Text_). The selected text does not have to be in the current editor window, it may even be in another program. For example, if the word dog appears somewhere in a window on your screen, and you want to find it in the file you are editing, select the word dog by dragging the mouse across it, switch to your NEdit window and choose Find Selection from the Search menu. Find Incremental, which opens the interactive search bar, is yet another variation on searching, where every character typed triggers a new search. After you've completed the search string, the next occurrence in the buffer is found by hitting the Return key, or by clicking on the icon to the left (magnifying glass). Holding a Shift key down finds the previous occurrences. To the right there is a clear button with an icon resembling "|<". Clicking on it empties the search text widget without disturbing selections. A middle click on the clear button copies the content of any existing selection into the search text widget and triggers a new search. 3>Searching Backwards Holding down the shift key while choosing any of the search or replace commands from the menu (or using the keyboard shortcut), will search in the reverse direction. Users who have set the search direction using the buttons in the search dialog, may find it a bit confusing that Find Again and Replace Again don't continue in the same direction as the original search (for experienced users, consistency of the direction implied by the shift key is more important). 3>Selective Replacement To replace only some occurrences of a string within a file, choose Replace... from the Search menu, enter the string to search for and the string to substitute, and finish by pressing the Find button. When the first occurrence is highlighted, use either Replace Again (^T) to replace it, or Find Again (^G) to move to the next occurrence without replacing it, and continue in such a manner through all occurrences of interest. To replace all occurrences of a string within some range of text, select the range (see Selecting_Text_), choose Replace... from the Search menu, type the string to search for and the string to substitute, and press the "R. in Selection" button in the dialog. Note that selecting text in the Replace... dialog will unselect the text in the window. 3>Replacement in Multiple Documents You can do the same replacement in more than one document at the same time. To do that, enter the search and replacement string in the replacement dialog as usual, then press the 'Multiple Documents...' button. NEdit will open another dialog where you can pick any document in which the replacement should take place. Then press 'Replace' in this dialog to do the replacement. All attributes (Regular Expression, Case, etc.) are used as selected in the main dialog. ---------------------------------------------------------------------- Cut and Paste ------------- The easiest way to copy and move text around in your file or between windows, is to use the clipboard, an imaginary area that temporarily stores text and data. The Cut command removes the selected text (see Selecting_Text_) from your file and places it in the clipboard. Once text is in the clipboard, the Paste command will copy it to the insert position in the current window. For example, to move some text from one place to another, select it by dragging the mouse over it, choose Cut to remove it, click the pointer to move the insert point where you want the text inserted, then choose Paste to insert it. Copy copies text to the clipboard without deleting it from your file. You can also use the clipboard to transfer text to and from other Motif programs and X programs which make proper use of the clipboard. There are many other methods for copying and moving text within NEdit windows and between NEdit and other programs. The most common such method is clicking the middle mouse button to copy the primary selection (to the clicked position). Copying the selection by clicking the middle mouse button in many cases is the only way to transfer data to and from many X programs. Holding the Shift key while clicking the middle mouse button moves the text, deleting it from its original position, rather than copying it. Other methods for transferring text include secondary selections, primary selection dragging, keyboard-based selection copying, and drag and drop. These are described in detail in the sections: "Selecting_Text_", "Using_the_Mouse_", and "Keyboard_Shortcuts_". ---------------------------------------------------------------------- Using the Mouse --------------- Mouse-based editing is what NEdit is all about, and learning to use the more advanced features like secondary selections and primary selection dragging will be well worth your while. If you don't have time to learn everything, you can get by adequately with just the left mouse button: Clicking the left button moves the cursor. Dragging with the left button makes a selection. Holding the shift key while clicking extends the existing selection, or begins a selection between the cursor and the mouse. Double or triple clicking selects a whole word or a whole line. This section will make more sense if you also read the section called, "Selecting_Text_", which explains the terminology of selections, that is, what is meant by primary, secondary, rectangular, etc. 3>Button and Modifier Key Summary General meaning of mouse buttons and modifier keys: 4> Buttons Button 1 (left) Cursor position and primary selection Button 2 (middle) Secondary selections, and dragging and copying the primary selection Button 3 (right) Quick-access programmable menu and pan scrolling 4> Modifier keys Shift On primary selections, (left mouse button): Extends selection to the mouse pointer On secondary and copy operations, (middle): Toggles between move and copy Ctrl Makes selection rectangular or insertion columnar Alt* (on release) Exchange primary and secondary selections. 3>Left Mouse Button The left mouse button is used to position the cursor and to make primary selections. Click Moves the cursor Double Click Selects a whole word Triple Click Selects a whole line Quad Click Selects the whole file Shift Click Adjusts (extends or shrinks) the selection, or if there is no existing selection, begins a new selection between the cursor and the mouse. Ctrl+Shift+ Adjusts (extends or shrinks) the Click selection rectangularly. Drag Selects text between where the mouse was pressed and where it was released. Ctrl+Drag Selects rectangle between where the mouse was pressed and where it was released. 3>Right Mouse Button The right mouse button posts a programmable menu for frequently used commands. Click/Drag Pops up the background menu (programmed from Preferences -> Default Settings -> Customize Menus -> Window Background). Ctrl+Drag Pan scrolling. Scrolls the window both vertically and horizontally, as if you had grabbed it with your mouse. 3>Middle Mouse Button The middle mouse button is for making secondary selections, and copying and dragging the primary selection. Click Copies the primary selection to the clicked position. Shift+Click Moves the primary selection to the clicked position, deleting it from its original position. Drag 1) Outside of the primary selection: Begins a secondary selection. 2) Inside of the primary selection: Moves the selection by dragging. Ctrl+Drag 1) Outside of the primary selection: Begins a rectangular secondary selection. 2) Inside of the primary selection: Drags the selection in overlay mode (see below). When the mouse button is released after creating a secondary selection: No Modifiers If there is a primary selection, replaces it with the secondary selection. Otherwise, inserts the secondary selection at the cursor position. Shift Move the secondary selection, deleting it from its original position. If there is a primary selection, the move will replace the primary selection with the secondary selection. Otherwise, moves the secondary selection to the cursor position. Alt* Exchange the primary and secondary selections. While moving the primary selection by dragging with the middle mouse button: Shift Leaves a copy of the original selection in place rather than removing it or blanking the area. Ctrl Changes from insert mode to overlay mode (see below). Escape Cancels drag in progress. Overlay Mode: Normally, dragging moves text by removing it from the selected position at the start of the drag, and inserting it at a new position relative to the mouse. When you drag a block of text over existing characters, the existing characters are displaced to the end of the selection. In overlay mode, characters which are occluded by blocks of text being dragged are simply removed. When dragging non-rectangular selections, overlay mode also converts the selection to rectangular form, allowing it to be dragged outside of the bounds of the existing text. Mouse buttons 4 and 5 are usually represented by a mouse wheel nowadays. They are used to scroll up or down in the text window. * The Alt key may be labeled Meta or Compose-Character on some keyboards. Some window managers, including default configurations of mwm, bind combinations of the Alt key and mouse buttons to window manager operations. In NEdit, Alt is only used on button release, so regardless of the window manager bindings for Alt-modified mouse buttons, you can still do the corresponding NEdit operation by using the Alt key AFTER the initial mouse press, so that Alt is held while you release the mouse button. If you find this difficult or annoying, you can re-configure most window managers to skip this binding, or you can re-configure NEdit to use a different key combination. ---------------------------------------------------------------------- Keyboard Shortcuts ------------------ Most of the keyboard shortcuts in NEdit are shown on the right hand sides of the pull-down menus. However, there are more which are not as obvious. These include; dialog button shortcuts; menu and dialog mnemonics; labeled keyboard keys, such as the arrows, page-up, page-down, and home; and optional Shift modifiers on accelerator keys, like [Shift]Ctrl+F. 3>Menu Accelerators Pressing the key combinations shown on the right of the menu items is a shortcut for selecting the menu item with the mouse. Some items have the shift key enclosed in brackets, such as [Shift]Ctrl+F. This indicates that the shift key is optional. In search commands, including the shift key reverses the direction of the search. In Shift commands, it makes the command shift the selected text by a whole tab stop rather than by single characters. 3>Menu Mnemonics Pressing the Alt key in combination with one of the underlined characters in the menu bar pulls down that menu. Once the menu is pulled down, typing the underlined characters in a menu item (without the Alt key) activates that item. With a menu pulled down, you can also use the arrow keys to select menu items, and the Space or Enter keys to activate them. 3>Keyboard Shortcuts within Dialogs One button in a dialog is usually marked with a thick indented outline. Pressing the Return or Enter key activates this button. All dialogs have either a Cancel or Dismiss button. This button can be activated by pressing the Escape (or Esc) key. Pressing the tab key moves the keyboard focus to the next item in a dialog. Within an associated group of buttons, the arrow keys move the focus among the buttons. Shift+Tab moves backward through the items. Most items in dialogs have an underline under one character in their name. Pressing the Alt key along with this character, activates a button as if you had pressed it with the mouse, or moves the keyboard focus to the associated text field or list. You can select items from a list by using the arrow keys to move the selection and space to select. In file selection dialogs, you can type the beginning characters of the file name or directory in the list to select files 3>Labeled Function Keys The labeled function keys on standard workstation and PC keyboards, like the arrows, and page-up and page-down, are active in NEdit, though not shown in the pull-down menus. Holding down the control key while pressing a named key extends the scope of the action that it performs. For example, Home normally moves the insert cursor the beginning of a line. Ctrl+Home moves it to the beginning of the file. Backspace deletes one character, Ctrl+Backspace deletes one word. Holding down the shift key while pressing a named key begins or extends a selection. Combining the shift and control keys combines their actions. For example, to select a word without using the mouse, position the cursor at the beginning of the word and press Ctrl+Shift+RightArrow. The Alt key modifies selection commands to make the selection rectangular. Under X and Motif, there are several levels of translation between keyboard keys and the actions they perform in a program. The "Customizing_NEdit_", and "X_Resources_" sections of the Help menu have more information on this subject. Because of all of this configurability, and since keyboards and standards for the meaning of some keys vary from machine to machine, the mappings may be changed from the defaults listed below. 3>Modifier Keys (in general) Ctrl Extends the scope of the action that the key would otherwise perform. For example, Home normally moves the insert cursor to the beginning of a line. Ctrl+Home moves it to the beginning of the file. Backspace deletes one character, Ctrl+ Backspace deletes one word. Shift Extends the selection to the cursor position. If there's no selection, begins one between the old and new cursor positions. Alt When modifying a selection, makes the selection rectangular. (For the effects of modifier keys on mouse button presses, see the section titled "Using_the_Mouse_") 3>All Keyboards Escape Cancels operation in progress: menu selection, drag, selection, etc. Also equivalent to cancel button in dialogs. Backspace Delete the character before the cursor Ctrl+BS Delete the word before the cursor Arrows -- Left Move the cursor to the left one character Ctrl+Left Move the cursor backward one word (Word delimiters are settable, see "Customizing_NEdit_", and "X_Resources_") Right Move the cursor to the right one character Ctrl+Right Move the cursor forward one word Up Move the cursor up one line Ctrl+Up Move the cursor up one paragraph. (Paragraphs are delimited by blank lines) Down Move the cursor down one line. Ctrl+Down Move the cursor down one paragraph. Ctrl+Return Return with automatic indent, regardless of the setting of Auto Indent. Shift+Return Return without automatic indent, regardless of the setting of Auto Indent. Ctrl+Tab Insert an ASCII tab character, without processing emulated tabs. Alt+Ctrl+ Insert the control-code equivalent of a key Ctrl+/ Select everything (same as Select All menu item or ^A) Ctrl+\ Unselect Ctrl+U Delete to start of line 3>PC Standard Keyboard Ctrl+Insert Copy the primary selection to the clipboard (same as Copy menu item or ^C) for compatibility with Motif standard key binding Shift+Ctrl+ Insert Copy the primary selection to the cursor location. Delete Delete the character before the cursor. (Can be configured to delete the character after the cursor, see "Customizing_NEdit_", and "X_Resources_") Ctrl+Delete Delete to end of line. Shift+Delete Cut, remove the currently selected text and place it in the clipboard. (same as Cut menu item or ^X) for compatibility with Motif standard key binding Shift+Ctrl+ Delete Cut the primary selection to the cursor location. Home Move the cursor to the beginning of the line Ctrl+Home Move the cursor to the beginning of the file End Move the cursor to the end of the line Ctrl+End Move the cursor to the end of the file PageUp Scroll and move the cursor up by one page. PageDown Scroll and move the cursor down by one page. F10 Make the menu bar active for keyboard input (Arrow Keys, Return, Escape, and the Space Bar) Alt+Home Switch to the previously active document. Ctrl+PageUp Switch to the previous document. Ctrl+PageDown Switch to the next document. 3>Specialty Keyboards On machines with different styles of keyboards, generally, text editing actions are properly matched to the labeled keys, such as Remove, Next-screen, etc.. If you prefer different key bindings, see the section titled "Key_Binding_" under the Customizing heading in the Help menu. ---------------------------------------------------------------------- Shifting and Filling -------------------- 3>Shift Left, Shift Right While shifting blocks of text is most important for programmers (See Features for Programming), it is also useful for other tasks, such as creating indented paragraphs. To shift a block of text one tab stop to the right, select the text, then choose Shift Right from the Edit menu. Note that the accelerator keys for these menu items are Ctrl+9 and Ctrl+0, which correspond to the right and left parenthesis on most keyboards. Remember them as adjusting the text in the direction pointed to by the parenthesis character. Holding the Shift key while selecting either Shift Left or Shift Right will shift the text by one character. It is also possible to shift blocks of text by selecting the text rectangularly, and dragging it left or right (and up or down as well). Using a rectangular selection also causes tabs within the selection to be recalculated and substituted, such that the non-whitespace characters remain stationary with respect to the selection. 3>Filling Text filling using the Fill Paragraph command in the Edit menu is one of the most important concepts in NEdit. And it will be well worth your while to understand how to use it properly. In plain text files, unlike word-processor files, there is no way to tell which lines are continuations of other lines, and which lines are meant to be separate, because there is no distinction in meaning between newline characters which separate lines in a paragraph, and ones which separate paragraphs from other text. This makes it impossible for a text editor like NEdit to tell parts of the text which belong together as a paragraph from carefully arranged individual lines. In continuous wrap mode (Preferences -> Wrap -> Continuous), lines automatically wrap and unwrap themselves to line up properly at the right margin. In this mode, you simply omit the newlines within paragraphs and let NEdit make the line breaks as needed. Unfortunately, continuous wrap mode is not appropriate in the majority of situations, because files with extremely long lines are not common under Unix and may not be compatible with all tools, and because you can't achieve effects like indented sections, columns, or program comments, and still take advantage of the automatic wrapping. Without continuous wrapping, paragraph filling is not entirely automatic. Auto-Newline wrapping keeps paragraphs lined up as you type, but once entered, NEdit can no longer distinguish newlines which join wrapped text, and newlines which must be preserved. Therefore, editing in the middle of a paragraph will often leave the right margin messy and uneven. Since NEdit can't act automatically to keep your text lined up, you need to tell it explicitly where to operate, and that is what Fill Paragraph is for. It arranges lines to fill the space between two margins, wrapping the lines neatly at word boundaries. Normally, the left margin for filling is inferred from the text being filled. The first line of each paragraph is considered special, and its left indentation is maintained separately from the remaining lines (for leading indents, bullet points, numbered paragraphs, etc.). Otherwise, the left margin is determined by the furthest left non-whitespace character. The right margin is either the Wrap Margin, set in the preferences menu (by default, the right edge of the window), or can also be chosen on the fly by using a rectangular selection (see below). There are three ways to use Fill Paragraph. The simplest is, while you are typing text, and there is no selection, simply select Fill Paragraph (or type Ctrl+J), and NEdit will arrange the text in the paragraph adjacent to the cursor. A paragraph, in this case, means an area of text delimited by blank lines. The second way to use Fill Paragraph is with a selection. If you select a range of text and then chose Fill Paragraph, all of the text in the selection will be filled. Again, continuous text between blank lines is interpreted as paragraphs and filled individually, respecting leading indents and blank lines. The third, and most versatile, way to use Fill Paragraph is with a rectangular selection. Fill Paragraph treats rectangular selections differently from other commands. Instead of simply filling the text inside the rectangular selection, NEdit interprets the right edge of the selection as the requested wrap margin. Text to the left of the selection is not disturbed (the usual interpretation of a rectangular selection), but text to the right of the selection is included in the operation and is pulled in to the selected region. This method enables you to fill text to an arbitrary right margin, without going back and forth to the wrap-margin dialog, as well as to exclude text to the left of the selection such as comment bars or other text columns. ---------------------------------------------------------------------- Tabbed Editing ---------------- NEdit is able to display files in distinct editor windows, or to display files under tabs in the same editor window. The Options for controlling the tabbed interface are found under Preferences -> Default Settings -> Tabbed Editing (cf. "Preferences_", also "NEdit_Command_Line_"). Notice that you can re-group tabs at any time by detaching and attaching them, or moving them, to other windows. This can be done using the Windows menu, or using the context menu, which pops up when right clicking on a tab. You can switch to a tab by simply clicking on it, or you can use the keyboard. The default keybindings to switch tabs (which are Ctrl+PageUp/-Down and Alt+Home, see "Keyboard_Shortcuts_") can be changed using the actions previous_document(), next_document() and last_document(). ---------------------------------------------------------------------- File Format ----------- While plain-text is probably the simplest and most interchangeable file format in the computer world, there is still variation in what plain-text means from system to system. Plain-text files can differ in character set, line termination, and wrapping. While character set differences are the most obvious and pose the most challenge to portability, they affect NEdit only indirectly via the same font and localization mechanisms common to all X applications. If your system is set up properly, you will probably never see character-set related problems in NEdit. NEdit cannot display Unicode text files, nor any multi-byte character set. The primary difference between an MS DOS format file and a Unix format file, is how the lines are terminated. Unix uses a single newline character. MS DOS uses a carriage-return and a newline. NEdit can read and write both file formats, but internally, it uses the single character Unix standard. NEdit auto-detects MS DOS format files based on the line termination at the start of the file. Files are judged to be DOS format if all of the first five line terminators, within a maximum range, are DOS-style. To change the format in which NEdit writes a file from DOS to Unix or visa versa, use the Save As... command and check or un-check the MS DOS Format button. Wrapping within text files can vary among individual users, as well as from system to system. Both Windows and MacOS make frequent use of plain text files with no implicit right margin. In these files, wrapping is determined by the tool which displays them. Files of this style also exist on Unix systems, despite the fact that they are not supported by all Unix utilities. To display this kind of file properly in NEdit, you have to select the wrap style called Continuous. Wrapping modes are discussed in the sections: Customizing -> Preferences, and Basic Operation -> Shifting and Filling. The last and most minute of format differences is the terminating newline. Some Unix compilers and utilities require a final terminating newline on all files they read and fail in various ways on files which do not have it. Vi and approximately half of Unix editors enforce the terminating newline on all files that they write; Emacs does not enforce this rule. Users are divided on which is best. NEdit makes the final terminating newline optional (Preferences -> Default Settings -> Terminate with Line Break on Save). ---------------------------------------------------------------------- Features for Programming ======================== Programming with NEdit ---------------------- Though general in appearance, NEdit has many features intended specifically for programmers. Major programming-related topics are listed in separate sections under the heading: "Features for Programming": Syntax_Highlighting_, Tabs/Emulated_Tabs_, Finding_Declarations_(ctags)_, Calltips_, and Auto/Smart_Indent_. Minor topics related to programming are discussed below: 3>Language Modes When NEdit initially reads a file, it attempts to determine whether the file is in one of the computer languages that it knows about. Knowing what language a file is written in allows NEdit to assign highlight patterns and smart indent macros, and to set language specific preferences like word delimiters, tab emulation, and auto-indent. Language mode can be recognized from both the file name and from the first 200 characters of content. Language mode recognition and language-specific preferences are configured in: Preferences -> Default Settings -> Language Modes.... You can set the language mode manually for a window, by selecting it from the menu: Preferences -> Language Modes. 3>Backlighting [EXPERIMENTAL] NEdit can be made to set the background color of particular classes of characters to allow easy identification of those characters. This is particularly useful if you need to be able to distinguish between tabs and spaces in a file where the difference is important. The colors used for backlighting are specified by a resource, "nedit*backlightCharTypes". You can turn backlighting on and off through the Preferences -> Apply Backlighting menu entry. If you prefer to have backlighting turned on for all new windows, use the Preferences -> Default Settings -> Apply Backlighting menu entry. This settings can be saved along with other preferences using Preferences -> Save Defaults. **Important:** In future versions of NEdit, the backlighting feature will be extended and reworked such that it becomes easier to configure. The current way of controlling it through a resource is generally considered to be below NEdit's usability standards. These future changes are likely to be incompatible with the current format of the "nedit*backlightCharTypes" resource, though. Therefore, it is expected that there will be no automatic migration path for users who customize the resource. 3>Line Numbers To find a particular line in a source file by line number, choose Goto Line #... from the Search menu. You can also directly select the line number text in the compiler message in the terminal emulator window (xterm, decterm, winterm, etc.) where you ran the compiler, and choose Goto Selected from the Search menu. To find out the line number of a particular line in your file, turn on Statistics Line in the Preferences menu and position the insertion point anywhere on the line. The statistics line continuously updates the line number of the line containing the cursor. To go to a specific column on a given line, choose Goto Line #... from the Search menu and enter a line number and a column number separated by a comma. (e.g. Enter "100,12" for line 100 column 12.) If you want to go to a column on the current line just leave out the line number. (e.g. Enter ",45" to go the column 45 on the current line.) 3>Matching Parentheses To help you inspect nested parentheses, brackets, braces, quotes, and other characters, NEdit has both an automatic parenthesis matching mode, and a Goto Matching command. Automatic parenthesis matching is activated when you type, or move the insertion cursor after a parenthesis, bracket, or brace. It momentarily highlights either the opposite character ('Delimiter') or the entire expression ('Range') when the opposite character is visible in the window. To find a matching character anywhere in the file, select it or position the cursor after it, and choose Goto Matching from the Search menu. If the character matches itself, such as a quote or slash, select the first character of the pair. NEdit will match {, (, [, <, ", ', `, /, and \. Holding the Shift key while typing the accelerator key (Shift+Ctrl+M, by default), will select all of the text between the matching characters. When syntax highlighting is enabled, the matching routines can optionally make use of the syntax information for improved accuracy. In that case, a brace inside a highlighted string will not match a brace inside a comment, for instance. 3>Opening Included Files The Open Selected command in the File menu understands the C preprocessor's #include syntax, so selecting an #include line and invoking Open Selected will generally find the file referred to, unless doing so depends on the settings of compiler switches or other information not available to NEdit. 3>Interface to Programming Tools Integrated software development environments such as SGI's CaseVision and Centerline Software's Code Center, can be interfaced directly with NEdit via the client server interface. These tools allow you to click directly on compiler and runtime error messages and request NEdit to open files, and select lines of interest. The easiest method is usually to use the tool's interface for character-based editors like vi, to invoke nc, but programmatic interfaces can also be derived using the source code for nc. There are also some simple compile/review, grep, ctree, and ctags browsers available in the NEdit contrib directory on ftp.nedit.org. ---------------------------------------------------------------------- Tabs/Emulated Tabs ------------------ 3>Changing the Tab Distance Tabs are important for programming in languages which use indentation to show nesting, as short-hand for producing white-space for leading indents. As a programmer, you have to decide how to use indentation, and how or whether tab characters map to your indentation scheme. Ideally, tab characters map directly to the amount of indent that you use to distinguish nesting levels in your code. Unfortunately, the Unix standard for interpretation of tab characters is eight characters (probably dating back to mechanical capabilities of the original teletype), which is usually too coarse for a single indent. Most text editors, NEdit included, allow you to change the interpretation of the tab character, and many programmers take advantage of this, and set their tabs to 3 or 4 characters to match their programming style. In NEdit you set the hardware tab distance in Preferences -> Tabs... for the current window, or Preferences -> Default Settings -> Tabs... (general), or Preferences -> Default Settings -> Language Modes... (language-specific) to change the defaults for future windows. Changing the meaning of the tab character makes programming much easier while you're in the editor, but can cause you headaches outside of the editor, because there is no way to pass along the tab setting as part of a plain-text file. All of the other tools which display, print, and otherwise process your source code have to be made aware of how the tabs are set, and must be able to handle the change. Non-standard tabs can also confuse other programmers, or make editing your code difficult for them if their text editors don't support changes in tab distance. 3>Emulated Tabs An alternative to changing the interpretation of the tab character is tab emulation. In the Tabs... dialog(s), turning on Emulated Tabs causes the Tab key to insert the correct number of spaces and/or tabs to bring the cursor the next emulated tab stop, as if tabs were set at the emulated tab distance rather than the hardware tab distance. Backspacing immediately after entering an emulated tab will delete the fictitious tab as a unit, but as soon as you move the cursor away from the spot, NEdit will forget that the collection of spaces and tabs is a tab, and will treat it as separate characters. To enter a real tab character with "Emulate Tabs" turned on, use Ctrl+Tab. It is also possible to tell NEdit not to insert ANY tab characters at all in the course of processing emulated tabs, and in shifting and rectangular insertion/deletion operations, for programmers who worry about the misinterpretation of tab characters on other systems. ---------------------------------------------------------------------- .. ** NOTE ** .. .. The following Tabs Dialog and Customize Window Title Dialog sections .. should only appear in the online documentation, and not in any of .. the other possible forms. The rationale is that they are not directly .. obtained from the Help menu, but are buried in preference dialogs. .. .. ? help~ .. Tabs Dialog .. ----------- .. .. The Tabs dialog controls both the operation of the Tab key, and .. the interpretation of tab characters within a file. .. .. The first field, Tab Spacing, controls how NEdit responds to .. tab characters in a file. On most Unix and VMS systems the .. conventional interpretation of a tab character is to advance the .. text position to the nearest multiple of eight characters (a tab .. spacing of 8). However, many programmers of C and other .. structured languages, when given the choice, prefer a tab .. spacing of 3 or 4 characters. Setting a three or four character .. hardware tab spacing is useful and convenient as long as your .. other software tools support it. Unfortunately, on Unix and VMS .. systems, system utilities, such as more, and printing software .. can't always properly display files with other than eight .. character tabs. .. .. Selecting "Emulate Tabs" will cause the Tab key to insert the .. correct number of spaces or tabs to reach the next tab stop, as .. if the tab spacing were set at the value in the "Emulated tab .. spacing" field. Backspacing immediately after entering an .. emulated tab will delete it as a unit, but as soon as you move .. the cursor away from the spot, NEdit will forget that the .. collection of spaces and tabs is a tab, and will treat it as .. separate characters. To enter a real tab character with .. "Emulate Tabs" turned on, use Ctrl+Tab. .. .. In generating emulated tabs, and in Shift Left, Paste Column, .. and some rectangular selection operations, NEdit inserts blank .. characters (spaces or tabs) to preserve the alignment of .. non-blank characters. The bottom toggle button in the Tabs .. dialog instructs NEdit whether to insert tab characters as .. padding in such situations. Turning this off, will keep NEdit .. from automatically inserting tabs. Some software developers .. prefer to keep their source code free of tabs to avoid its .. misinterpretation on systems with different tab character .. conventions. .. ---------------------------------------------------------------------- .. .. Customize Window Title Dialog .. ----------------------------- .. .. The Customize Window Title dialog allows you to customize .. and test the way information will be displayed in each window's .. title field. .. .. **Definition of the title** .. .. The upper half of the dialog can be used to select the various .. components that should be displayed in the title. The layout can be .. fine-tuned by editing the printf() like format string below the .. component buttons: additional characters can be entered, or the .. order can be changed. .. .. The following sequences are interpreted in the format string: .. .. %c ClearCase view tag (only relevant when NEdit is .. used together with ClearCase) .. %[n]d directory, with one optional numeric digit n .. specifying the maximum number of trailing directory .. components to display. Skipped components are .. replaced by an ellipsis (...). .. %f file name, without the path name .. %h host name .. %s NEdit server name (server mode only) .. %[*]S file status, either verbose (%S) or brief (%*S). .. In verbose mode the file status is spelled out: .. read-only, locked, and modified. In brief mode, .. abbreviations and an asterisk are used for the .. respective states: RO, LO, *. .. %u user name .. .. The format string and the component buttons are continously synchronized. .. .. The default format is: .. .. {%c} [%s] %f (%S) - %d .. .. The resulting title will only contain elements with .. a value. Hence, the title is compressed as follows: .. .. * Elements with no value are removed. .. * Empty parenthesis pairs i.e. (), [] or {}, or parenthesis pairs containing only space(s), are removed. .. * Sequences of spaces are replaced with one space. .. * Leading spaces and dashes are removed. .. * Trailing spaces and dashes are removed. .. .. If the server name and the ClearCase view tag are identical, only .. the first one specified in the format string will be displayed. .. .. **Previewing the settings** .. .. The lower part of the dialog can be used to test the selected title .. under various conditions. For some of the components that are selected .. for display, various states can be enforced on the preview. .. .. For instance, components that are not always active (such the .. NEdit server name) can be turned on or off in the preview. .. .. ~ help Auto/Smart Indent ----------------- Programmers who use structured languages usually require some form of automatic indent, so that they don't have to continually re-type the sequences of tabs and/or spaces needed to maintain lengthy running indents. NEdit therefore offers "smart" indent, in addition to the traditional automatic indent which simply lines up the cursor position with the previous line. 3>Smart Indent Smart indent macros are only available by default for C and C++, and while these can easily be configured for different default indentation distances, they may not conform to everyone's exact C programming style. Smart indent is programmed in terms of macros in the NEdit macro language which can be entered in: Preferences -> Default Settings -> Indent -> Program Smart Indent. Hooks are provided for intervening at the point that a newline is entered, either via the user pressing the Enter key, or through auto-wrapping; and for arbitrary type-in to act on specific characters typed. To type a newline character without invoking smart-indent when operating in smart-indent mode, hold the Shift key while pressing the Return or Enter key. 3>Auto-Indent With Indent set to Auto (the default), NEdit keeps a running indent. When you press the Return or Enter key, spaces and tabs are inserted to line up the insert point under the start of the previous line. Regardless of indent-mode, Ctrl+Return always does the automatic indent; Shift+Return always does a return without indent. 3>Block Indentation Adjustment The Shift Left and Shift Right commands as well as rectangular dragging can be used to adjust the indentation for several lines at once. To shift a block of text one character to the right, select the text, then choose Shift Right from the Edit menu. Note that the accelerator keys for these menu items are Ctrl+9 and Ctrl+0, which correspond to the right and left parenthesis on most keyboards. Remember them as adjusting the text in the direction pointed to by the parenthesis character. Holding the Shift key while selecting either Shift Left or Shift Right will shift the text by one tab stop (or by one emulated tab stop if tab emulation is turned on). The help section "Shifting and Filling" under "Basic Operation" has details. ---------------------------------------------------------------------- Syntax Highlighting ------------------- Syntax Highlighting means using colors and fonts to help distinguish language elements in programming languages and other types of structured files. Programmers use syntax highlighting to understand code faster and better, and to spot many kinds of syntax errors more quickly. To use syntax highlighting in NEdit, select Highlight Syntax in the Preferences menu. If NEdit recognizes the computer language that you are using, and highlighting rules (patterns) are available for that language, it will highlight your text, and maintain the highlighting, automatically, as you type. If NEdit doesn't correctly recognize the type of the file you are editing, you can manually select a language mode from Language Modes in the Preferences menu. You can also program the method that NEdit uses to recognize language modes in Preferences -> Default Settings -> Language Modes.... If no highlighting patterns are available for the language that you want to use, you can create new patterns relatively quickly. The Help section "Highlighting_Patterns_" under "Customizing", has details. If you are satisfied with what NEdit is highlighting, but would like it to use different colors or fonts, you can change these by selecting Preferences -> Default Settings -> Syntax Highlighting -> Text Drawing Styles. Highlighting patterns are connected with font and color information through a common set of styles so that colorings defined for one language will be similar across others, and patterns within the same language which are meant to appear identical can be changed in the same place. To understand which styles are used to highlight the language you are interested in, you may need to look at "Highlighting_Patterns_" section, as well. Syntax highlighting is CPU intensive, and under some circumstances can affect NEdit's responsiveness. If you have a particularly slow system, or work with very large files, you may not want to use it all of the time. Syntax highlighting introduces two kinds of delays. The first is an initial parsing delay, proportional to the size of the file. This delay is also incurred when pasting large sections of text, filtering text through shell commands, and other circumstances involving changes to large amounts of text. The second kind of delay happens when text which has not previously been visible is scrolled in to view. Depending on your system, and the highlight patterns you are using, this may or may not be noticeable. A typing delay is also possible, but unlikely if you are only using the built-in patterns. ---------------------------------------------------------------------- Finding Declarations (ctags) ---------------------------- NEdit can process tags files generated using the Unix _ctags command or the Exuberant Ctags program. Ctags creates index files correlating names of functions and declarations with their locations in C, Fortran, or Pascal source code files. (See the ctags manual page for more information). Ctags produces a file called "tags" which can be loaded by NEdit. NEdit can manage any number of tags files simultaneously. Tag collisions are handled with a popup menu to let the user decide which tag to use. In 'Smart' mode NEdit will automatically choose the desired tag based on the scope of the file or module. Once loaded, the information in the tags file enables NEdit to go directly to the declaration of a highlighted function or data structure name with a single command. To load a tags file, select "Load Tags File" from the File menu and choose a tags file to load, or specify the name of the tags file on the NEdit command line: nedit -tags tags NEdit can also be set to load a tags file automatically when it starts up. Setting the X resource nedit.tagFile to the name of a tag file tells NEdit to look for that file at startup time (see "Customizing_NEdit_"). The file name can be either a complete path name, in which case NEdit will always load the same tags file, or a file name without a path or with a relative path, in which case NEdit will load it starting from the current directory. The second option allows you to have different tags files for different projects, each automatically loaded depending on the directory you're in when you start NEdit. Setting the name to "tags" is an obvious choice since this is the name that ctags uses. NEdit normally evaluates relative path tag file specifications every time a file is opened. All accessible tag files are loaded at this time. To disable the automatic loading of tag files specified as relative paths, set the X resource nedit.alwaysCheckRelativeTagsSpecs to False. To unload a tags file, select "Un-load Tags File" from the File menu and choose from the list of tags files. NEdit will keep track of tags file updates by checking the timestamp on the files, and automatically update the tags cache. To find the definition of a function or data structure once a tags file is loaded, select the name anywhere it appears in your program (see "Selecting_Text_") and choose "Find Definition" from the Search menu. ---------------------------------------------------------------------- Calltips -------- Calltips are little yellow boxes that pop up to remind you what the arguments and return type of a function are. More generally, they're a UI mechanism to present a small amount of crucial information in a prominent location. To display a calltip, select some text and choose "Show Calltip" from the Search menu. To kill a displayed calltip, hit Esc. Calltips get their information from one of two places -- either a tags file (see "Finding_Declarations_(ctags)_") or a calltips file. First, any loaded calltips files are searched for a definition, and if nothing is found then the tags database is searched. If a tag is found that matches the highlighted text then a calltip is displayed with the first few lines of the definition -- usually enough to show you what the arguments of a function are. You can load a calltips file by using choosing "Load Calltips File" from the File menu. You can unload a calltips file by selecting it from the "Unload Calltips File" submenu of the File menu. You can also choose one or more default calltips files to be loaded for each language mode using the "Default calltips file(s)" field of the Language Modes dialog. The calltips file format is very simple. calltips files are organized in blocks separated by blank lines. The first line of the block is the key, which is the word that is matched when a calltip is requested. The rest of the block is displayed as the calltip. Almost any text at all can appear in a calltip key or a calltip. There are no special characters that need to be escaped. The only issues to note are that trailing whitespace is ignored, and you cannot have a blank line inside a calltip. (Use a single period instead -- it'll be nearly invisible.) You should also avoid calltip keys that begin and end with '@*' characters, since those are used to mark special blocks. There are five special block types--comment, include, language, alias, and version--which are distinguished by their first lines, "@* comment @*", "@* include @*", "@* language @*", "@* alias @*", and "@* version @*" respectively (without quotes). Comment blocks are ignored when reading calltips files. Include blocks specify additional calltips files to load, one per line. The ~ character can be used for your $HOME directory, but other shell shortcuts like @* and ? can't be used. Include blocks allow you to make a calltips file for your project that includes, say, the calltips files for C, Motif, and Xt. Language blocks specify which language mode the calltips should be used with. When a calltip is requested it won't match tips from languages other than the current language mode. Language blocks only affect the tips listed after the block. Alias blocks allow a calltip to have multiple keys. The first line of the block is the key for the calltip to be displayed, and the rest of the lines are additional keys, one per line, that should also show the calltip. Version blocks are ignored for the time being. You can use calltips in your own macros using the calltip() and kill_calltip() macro subroutines and the $calltip_ID macro variable. See the Macro_Subroutines_ section for details. ---------------------------------------------------------------------- Regular Expressions =================== Basic Regular Expression Syntax ------------------------------- Regular expressions (regex's) are useful as a way to match inexact sequences of characters. They can be used in the `Find...' and `Replace...' search dialogs and are at the core of Color Syntax Highlighting patterns. To specify a regular expression in a search dialog, simply click on the `Regular Expression' radio button in the dialog. A regex is a specification of a pattern to be matched in the searched text. This pattern consists of a sequence of tokens, each being able to match a single character or a sequence of characters in the text, or assert that a specific position within the text has been reached (the latter is called an anchor.) Tokens (also called atoms) can be modified by adding one of a number of special quantifier tokens immediately after the token. A quantifier token specifies how many times the previous token must be matched (see below.) Tokens can be grouped together using one of a number of grouping constructs, the most common being plain parentheses. Tokens that are grouped in this way are also collectively considered to be a regex atom, since this new larger atom may also be modified by a quantifier. A regex can also be organized into a list of alternatives by separating each alternative with pipe characters, `|'. This is called alternation. A match will be attempted for each alternative listed, in the order specified, until a match results or the list of alternatives is exhausted (see Alternation_ section below.) 3>The 'Any' Character If a dot (`.') appears in a regex, it means to match any character exactly once. By default, dot will not match a newline character, but this behavior can be changed (see help topic Parenthetical_Constructs_, under the heading, Matching Newlines). 3>Character Classes A character class, or range, matches exactly one character of text, but the candidates for matching are limited to those specified by the class. Classes come in two flavors as described below: [...] Regular class, match only characters listed. [^...] Negated class, match only characters ~not~ listed. As with the dot token, by default negated character classes do not match newline, but can be made to do so. The characters that are considered special within a class specification are different than the rest of regex syntax as follows. If the first character in a class is the `]' character (second character if the first character is `^') it is a literal character and part of the class character set. This also applies if the first or last character is `-'. Outside of these rules, two characters separated by `-' form a character range which includes all the characters between the two characters as well. For example, `[^f-j]' is the same as `[^fghij]' and means to match any character that is not `f', `g', `h', `i', or `j'. 3>Anchors Anchors are assertions that you are at a very specific position within the search text. NEdit regular expressions support the following anchor tokens: ^ Beginning of line $ End of line < Left word boundary > Right word boundary \B Not a word boundary Note that the \B token ensures that neither the left nor the right character are delimiters, **or** that both left and right characters are delimiters. The left word anchor checks whether the previous character is a delimiter and the next character is not. The right word anchor works in a similar way. Note that word delimiters are user-settable, and defined by the X resource wordDelimiters, cf. X_Resources_. 3>Quantifiers Quantifiers specify how many times the previous regular expression atom may be matched in the search text. Some quantifiers can produce a large performance penalty, and can in some instances completely lock up NEdit. To prevent this, avoid nested quantifiers, especially those of the maximal matching type (see below.) The following quantifiers are maximal matching, or "greedy", in that they match as much text as possible (but don't exclude shorter matches if that is necessary to achieve an overall match). * Match zero or more + Match one or more ? Match zero or one The following quantifiers are minimal matching, or "lazy", in that they match as little text as possible (but don't exclude longer matches if that is necessary to achieve an overall match). *? Match zero or more +? Match one or more ?? Match zero or one One final quantifier is the counting quantifier, or brace quantifier. It takes the following basic form: {min,max} Match from `min' to `max' times the previous regular expression atom. If `min' is omitted, it is assumed to be zero. If `max' is omitted, it is assumed to be infinity. Whether specified or assumed, `min' must be less than or equal to `max'. Note that both `min' and `max' are limited to 65535. If both are omitted, then the construct is the same as `*'. Note that `{,}' and `{}' are both valid brace constructs. A single number appearing without a comma, e.g. `{3}' is short for the `{min,min}' construct, or to match exactly `min' number of times. The quantifiers `{1}' and `{1,1}' are accepted by the syntax, but are optimized away since they mean to match exactly once, which is redundant information. Also, for efficiency, certain combinations of `min' and `max' are converted to either `*', `+', or `?' as follows: {} {,} {0,} * {1,} + {,1} {0,1} ? Note that {0} and {0,0} are meaningless and will generate an error message at regular expression compile time. Brace quantifiers can also be "lazy". For example {2,5}? would try to match 2 times if possible, and will only match 3, 4, or 5 times if that is what is necessary to achieve an overall match. 3>Alternation A series of alternative patterns to match can be specified by separating them with vertical pipes, `|'. An example of _alternation would be `a|be|sea'. This will match `a', or `be', or `sea'. Each alternative can be an arbitrarily complex regular expression. The alternatives are attempted in the order specified. An empty alternative can be specified if desired, e.g. `a|b|'. Since an empty alternative can match nothingness (the empty string), this guarantees that the expression will match. 3>Comments Comments are of the form `(?#)' and can be inserted anywhere and have no effect on the execution of the regular expression. They can be handy for documenting very complex regular expressions. Note that a comment begins with `(?#' and ends at the first occurrence of an ending parenthesis, or the end of the regular expression... period. Comments do not recognize any escape sequences. ---------------------------------------------------------------------- Metacharacters -------------- 3>Escaping Metacharacters In a regular expression (regex), most ordinary characters match themselves. For example, `ab%' would match anywhere `a' followed by `b' followed by `%' appeared in the text. Other characters don't match themselves, but are metacharacters. For example, backslash is a special metacharacter which 'escapes' or changes the meaning of the character following it. Thus, to match a literal backslash would require a regular expression to have two backslashes in sequence. NEdit provides the following escape sequences so that metacharacters that are used by the regex syntax can be specified as ordinary characters. \( \) \- \[ \] \< \> \{ \} \. \| \^ \$ \* \+ \? \& \\ 3>Special Control Characters There are some special characters that are difficult or impossible to type. Many of these characters can be constructed as a sort of metacharacter or sequence by preceding a literal character with a backslash. NEdit recognizes the following special character sequences: \a alert (bell) \b backspace \e ASCII escape character (***) \f form feed (new page) \n newline \r carriage return \t horizontal tab \v vertical tab *** For environments that use the EBCDIC character set, when compiling NEdit set the EBCDIC_CHARSET compiler symbol to get the EBCDIC equivalent escape character.) 3>Octal and Hex Escape Sequences Any ASCII (or EBCDIC) character, except null, can be specified by using either an octal escape or a hexadecimal escape, each beginning with \0 or \x (or \X), respectively. For example, \052 and \X2A both specify the `*' character. Escapes for null (\00 or \x0) are not valid and will generate an error message. Also, any escape that exceeds \0377 or \xFF will either cause an error or have any additional character(s) interpreted literally. For example, \0777 will be interpreted as \077 (a `?' character) followed by `7' since \0777 is greater than \0377. An invalid digit will also end an octal or hexadecimal escape. For example, \091 will cause an error since `9' is not within an octal escape's range of allowable digits (0-7) and truncation before the `9' yields \0 which is invalid. 3>Shortcut Escape Sequences NEdit defines some escape sequences that are handy shortcuts for commonly used character classes. \d digits 0-9 \l letters a-z, A-Z, and locale dependent letters \s whitespace \t, \r, \v, \f, and space \w word characters letters, digits, and underscore, `_' \D, \L, \S, and \W are the same as the lowercase versions except that the resulting character class is negated. For example, \d is equivalent to `[0-9]', while \D is equivalent to `[^0-9]'. These escape sequences can also be used within a character class. For example, `[\l_]' is the same as `[a-zA-Z@_]', extended with possible locale dependent letters. The escape sequences for special characters, and octal and hexadecimal escapes are also valid within a class. 3>Word Delimiter Tokens Although not strictly a character class, the following escape sequences behave similarly to character classes: \y Word delimiter character \Y Not a word delimiter character The `\y' token matches any single character that is one of the characters that NEdit recognizes as a word delimiter character, while the `\Y' token matches any character that is ~not~ a word delimiter character. Word delimiter characters are dynamic in nature, meaning that the user can change them through preference settings. For this reason, they must be handled differently by the regular expression engine. As a consequence of this, `\y' and `\Y' cannot be used within a character class specification. ---------------------------------------------------------------------- Parenthetical Constructs ------------------------ 3>Capturing Parentheses Capturing Parentheses are of the form `()' and can be used to group arbitrarily complex regular expressions. Parentheses can be nested, but the total number of parentheses, nested or otherwise, is limited to 50 pairs. The text that is matched by the regular expression between a matched set of parentheses is captured and available for text substitutions and backreferences (see below.) Capturing parentheses carry a fairly high overhead both in terms of memory used and execution speed, especially if quantified by `*' or `+'. 3>Non-Capturing Parentheses Non-Capturing Parentheses are of the form `(?:)' and facilitate grouping only and do not incur the overhead of normal capturing parentheses. They should not be counted when determining numbers for capturing parentheses which are used with backreferences and substitutions. Because of the limit on the number of capturing parentheses allowed in a regex, it is advisable to use non-capturing parentheses when possible. 3>Positive Look-Ahead Positive look-ahead constructs are of the form `(?=)' and implement a zero width assertion of the enclosed regular expression. In other words, a match of the regular expression contained in the positive look-ahead construct is attempted. If it succeeds, control is passed to the next regular expression atom, but the text that was consumed by the positive look-ahead is first unmatched (backtracked) to the place in the text where the positive look-ahead was first encountered. One application of positive look-ahead is the manual implementation of a first character discrimination optimization. You can include a positive look-ahead that contains a character class which lists every character that the following (potentially complex) regular expression could possibly start with. This will quickly filter out match attempts that cannot possibly succeed. 3>Negative Look-Ahead Negative look-ahead takes the form `(?!)' and is exactly the same as positive look-ahead except that the enclosed regular expression must NOT match. This can be particularly useful when you have an expression that is general, and you want to exclude some special cases. Simply precede the general expression with a negative look-ahead that covers the special cases that need to be filtered out. 3>Positive Look-Behind Positive look-behind constructs are of the form `(?<=)' and implement a zero width assertion of the enclosed regular expression in front of the current matching position. It is similar to a positive look-ahead assertion, except for the fact that the match is attempted on the text preceding the current position, possibly even in front of the start of the matching range of the entire regular expression. A restriction on look-behind expressions is the fact that the expression must match a string of a bounded size. In other words, `*', `+', and `{n,}' quantifiers are not allowed inside the look-behind expression. Moreover, matching performance is sensitive to the difference between the upper and lower bound on the matching size. The smaller the difference, the better the performance. This is especially important for regular expressions used in highlight patterns. Positive look-behind has similar applications as positive look-ahead. 3>Negative Look-Behind Negative look-behind takes the form `(?)' and is exactly the same as positive look-behind except that the enclosed regular expression must ~not~ match. The same restrictions apply. Note however, that performance is even more sensitive to the distance between the size boundaries: a negative look-behind must not match for **any** possible size, so the matching engine must check **every** size. 3>Case Sensitivity There are two parenthetical constructs that control case sensitivity: (?i) Case insensitive; `AbcD' and `aBCd' are equivalent. (?I) Case sensitive; `AbcD' and `aBCd' are different. Regular expressions are case sensitive by default, that is, `(?I)' is assumed. All regular expression token types respond appropriately to case insensitivity including character classes and backreferences. There is some extra overhead involved when case insensitivity is in effect, but only to the extent of converting each character compared to lower case. 3>Matching Newlines NEdit regular expressions by default handle the matching of newlines in a way that should seem natural for most editing tasks. There are situations, however, that require finer control over how newlines are matched by some regular expression tokens. By default, NEdit regular expressions will ~not~ match a newline character for the following regex tokens: dot (`.'); a negated character class (`[^...]'); and the following shortcuts for character classes: `\d', `\D', `\l', `\L', `\s', `\S', `\w', `\W', `\Y' The matching of newlines can be controlled for the `.' token, negated character classes, and the `\s' and `\S' shortcuts by using one of the following parenthetical constructs: (?n) `.', `[^...]', `\s', `\S' match newlines (?N) `.', `[^...]', `\s', `\S' don't match newlines `(?N)' is the default behavior. 3>Notes on New Parenthetical Constructs Except for plain parentheses, none of the parenthetical constructs capture text. If that is desired, the construct must be wrapped with capturing parentheses, e.g. `((?iBack References Backreferences allow you to match text captured by a set of capturing parenthesis at some later position in your regular expression. A backreference is specified using a single backslash followed by a single digit from 1 to 9 (example: \3). Backreferences have similar syntax to substitutions (see below), but are different from substitutions in that they appear within the regular expression, not the substitution string. The number specified with a backreference identifies which set of text capturing parentheses the backreference is associated with. The text that was most recently captured by these parentheses is used by the backreference to attempt a match. As with substitutions, open parentheses are counted from left to right beginning with 1. So the backreference `\3' will try to match another occurrence of the text most recently matched by the third set of capturing parentheses. As an example, the regular expression `(\d)\1' could match `22', `33', or `00', but wouldn't match `19' or `01'. A backreference must be associated with a parenthetical expression that is complete. The expression `(\w(\1))' contains an invalid backreference since the first set of parentheses are not complete at the point where the backreference appears. 3>Substitution Substitution strings are used to replace text matched by a set of capturing parentheses. The substitution string is mostly interpreted as ordinary text except as follows. The escape sequences described above for special characters, and octal and hexadecimal escapes are treated the same way by a substitution string. When the substitution string contains the `&' character, NEdit will substitute the entire string that was matched by the `Find...' operation. Any of the first nine sub-expressions of the match string can also be inserted into the replacement string. This is done by inserting a `\' followed by a digit from 1 to 9 that represents the string matched by a parenthesized expression within the regular expression. These expressions are numbered left-to-right in order of their opening parentheses. The capitalization of text inserted by `&' or `\1', `\2', ... `\9' can be altered by preceding them with `\U', `\u', `\L', or `\l'. `\u' and `\l' change only the first character of the inserted entity, while `\U' and `\L' change the entire entity to upper or lower case, respectively. ---------------------------------------------------------------------- Advanced Topics --------------- 3>Substitutions Regular expression substitution can be used to program automatic editing operations. For example, the following are search and replace strings to find occurrences of the `C' language subroutine `get_x', reverse the first and second parameters, add a third parameter of NULL, and change the name to `new_get_x': Search string: `get_x *\( *([^ ,]*), *([^\)]*)\)' Replace string: `new_get_x(\2, \1, NULL)' 3>Ambiguity If a regular expression could match two different parts of the text, it will match the one which begins earliest. If both begin in the same place but match different lengths, or match the same length in different ways, life gets messier, as follows. In general, the possibilities in a list of alternatives are considered in left-to-right order. The possibilities for `*', `+', and `?' are considered longest-first, nested constructs are considered from the outermost in, and concatenated constructs are considered leftmost-first. The match that will be chosen is the one that uses the earliest possibility in the first choice that has to be made. If there is more than one choice, the next will be made in the same manner (earliest possibility) subject to the decision on the first choice. And so forth. For example, `(ab|a)b*c' could match `abc' in one of two ways. The first choice is between `ab' and `a'; since `ab' is earlier, and does lead to a successful overall match, it is chosen. Since the `b' is already spoken for, the `b*' must match its last possibility, the empty string, since it must respect the earlier choice. In the particular case where no `|'s are present and there is only one `*', `+', or `?', the net effect is that the longest possible match will be chosen. So `ab*', presented with `xabbbby', will match `abbbb'. Note that if `ab*' is tried against `xabyabbbz', it will match `ab' just after `x', due to the begins-earliest rule. (In effect, the decision on where to start the match is the first choice to be made, hence subsequent choices must respect it even if this leads them to less-preferred alternatives.) 3>References An excellent book on the care and feeding of regular expressions is Mastering Regular Expressions, 3rd Edition Jeffrey E. F. Friedl August 2006, O'Reilly & Associates ISBN 0-596-52812-4 The first end second editions of this book are still useful for basic introduction to regexes and contain many useful tips and tricks. ---------------------------------------------------------------------- Example Regular Expressions --------------------------- The following are regular expression examples which will match: * An entire line. ! ^.*$ * Blank lines. ! ^$ * Whitespace on a line. ! \s+ * Whitespace across lines. ! (?n\s+) * Whitespace that spans at least two lines. Note minimal matching `*?' quantifier. ! (?n\s*?\n\s*) * IP address (not robust). ! (?:\d{1,3}(?:\.\d{1,3}){3}) * Two character US Postal state abbreviations (includes territories). ! [ACDF-IK-PR-W][A-Z] * Web addresses. ! (?:http://)?www\.\S+ * Case insensitive double words across line breaks. ! (?i(?n<(\S+)\s+\1>)) * Upper case words with possible punctuation. ! <[A-Z][^a-z\s]*> ---------------------------------------------------------------------- Macro/Shell Extensions ====================== Shell Commands and Filters -------------------------- The Shell menu (Unix versions only) allows you to execute Unix shell commands from within NEdit. You can add items to the menu to extend NEdit's command set or to incorporate custom automatic editing features using shell commands or editing languages like awk and sed. To add items to the menu, select Preferences -> Default Settings Customize Menus -> Shell Menu. NEdit comes pre-configured with a few useful Unix commands like spell and sort, but we encourage you to add your own custom extensions. Filter Selection... prompts you for a Unix command to use to process the currently selected text. The output from this command replaces the contents of the selection. Execute Command... prompts you for a Unix command and replaces the current selection with the output of the command. If there is no selection, it deposits the output at the current insertion point. In the Shell Command field, the % character expands to the name (including directory path), and the # character expands to the current line number of the file in the window. To include a % or # character in the command, use %% or ##, respectively. Execute Command Line uses the position of the cursor in the window to indicate a line to execute as a shell command line. The cursor may be positioned anywhere on the line. This command allows you to use an NEdit window as an editable command window for saving output and saving commands for re-execution. Note that the same character expansions described above in Execute Command also occur with this command. The X resource called nedit.shell (See "Customizing_NEdit_") determines which Unix shell is used to execute commands. The default value for this resource is the user's login shell. ---------------------------------------------------------------------- Learn/Replay ------------ Selecting Learn Keystrokes from the Macro menu puts NEdit in learn mode. In learn mode, keystrokes and menu commands are recorded, to be played back later, using the Replay Keystrokes command, or pasted into a macro in the Macro Commands dialog of the Default Settings menu in Preferences. Note that only keyboard and menu commands are recorded, not mouse clicks or mouse movements since these have no absolute point of reference, such as cursor or selection position. When you do a mouse-based operation in learn mode, NEdit will beep (repeatedly) to remind you that the operation was not recorded. Learn mode is also the quickest and easiest method for writing macros. The dialog for creating macro commands contains a button labeled "Paste Learn / Replay Macro", which will deposit the last sequence learned into the body of the macro. 3>Repeating Actions and Learn/Replay Sequences You can repeat the last (keyboard-based) command, or learn/replay sequence with the Repeat... command in the Macro menu. To repeat an action, first do the action (that is, insert a character, do a search, move the cursor), then select Repeat..., decide how or how many times you want it repeated, and click OK. For example, to move down 30 lines through a file, you could type: Ctrl+, 29 . To repeat a learn/replay sequence, first learn it, then select Repeat..., click on Learn/Replay and how you want it repeated, then click OK. If the commands you are repeating advance the cursor through the file, you can also repeat them within a range of characters, or from the current cursor position to the end of the file. To iterate over a range of characters, use the primary selection (drag the left mouse button over the text) to mark the range you want to operate on, and select "In Selection" in the Repeat dialog. When using In "Selection" or "To End" with a learned sequence, try to do cursor movement as the last step in the sequence, since testing of the cursor position is only done at the end of the sequence execution. If you do cursor movement first, for example searching for a particular word then doing a modification, the position of the cursor won't be checked until the sequence has potentially gone far beyond the end of your desired range. It's easy for a repeated command to get out of hand, and you can easily generate an infinite loop by using range iteration on a command which doesn't progress. To cancel a repeating command in progress, type Ctrl+. (period), or select Cancel Macro from the Macro menu. ---------------------------------------------------------------------- Macro Language -------------- Macros can be called from Macro menu commands, window background menu commands, within the smart-indent framework, from the autoload macro file, cf. Preferences_, and from the command line. Macro menu and window background menu commands are defined under Preferences -> Default Settings -> Customize Menus. Help on creating items in these menus can be found in the section Preferences_. NEdit's macro language is a simple interpreter with integer arithmetic, dynamic strings, and C-style looping constructs (very similar to the procedural portion of the Unix awk program). From the macro language, you can call the same action routines which are bound to keyboard keys and menu items, as well additional subroutines for accessing and manipulating editor data, which are specific to the macro language (these are listed in the sections titled "Macro_Subroutines_", and "Action_Routines_"). 3>Syntax An NEdit macro language program consists of a list of statements, each terminated by a newline. Groups of statements which are executed together conditionally, such as the body of a loop, are surrounded by curly braces "{}". Blank lines and comments are also allowed. Comments begin with a "#" and end with a newline, and can appear either on a line by themselves, or at the end of a statement. Statements which are too long to fit on a single line may be split across several lines, by placing a backslash "\" character at the end of each line to be continued. 3>Data Types The NEdit macro language recognizes only three data types, dynamic character strings, integer values and associative arrays. In general strings and integers can be used interchangeably. If a string represents an integer value, it can be used as an integer. Integers can be compared and concatenated with strings. Arrays may contain integers, strings, or arrays. Arrays are stored key/value pairs. Keys are always stored as strings. 4>Integer Constants Integers are non-fractional numbers in the range of -2147483647 to 2147483647. Integer constants must be in decimal. For example: a = -1 b = 1000 4>Character String Constants Character string constants are enclosed in double quotes. For example: a = "a string" dialog("Hi there!", "OK") Strings may also include C-language style escape sequences: \\ Backslash \t Tab \f Form feed \" Double quote \b Backspace \a Alert \n Newline \r Carriage return \v Vertical tab Also allowed is the escape control character sequence: \e Escape (ASCII or EBCDIC, depending on NEdit compilation settings) For example, to send output to the terminal from which NEdit was started, a newline character is necessary because, like printf, t_print requires explicit newlines, and also buffers its output on a per-line basis: t_print("a = " a "\n") Other characters can be expressed as backslash-escape sequences in macro strings. The format is the same as for regular expressions, described in the paragraphs headed "Octal and Hex Escape Sequences" of the section "Metacharacters_", except that an octal escape sequence can start with any octal digit, not just 0, so the single character string "\0033" is the same as "\33", "\x1B" and "\e" (for an ASCII version of NEdit). Note that if you want to define a regular expression in a macro string, you need to "double-up" the backslashes for the metacharacters with special meaning in regular expressions. For example, the expression (?N(\s|/\*(?n(?:(?!\*/).)*)\*/|//.*\n|\n)+) which matches whitespace or C/C++/Java-style comments, should be written as a macro string as "(?N(\\s|/\\*(?n(?:(?!\\*/).)*)\\*/|//.*\n|\n)+)" (The "\n"s towards the end add literal newline characters to the string. The regular expression interpretation treats the newlines as themselves. It can also interpret the sequence "\\n" as a newline, although the macro string here would then contain a literal backslash followed by a lowercase `N'.) 3>Variables Variable names must begin either with a letter (local variables), or a $ (global variables). Beyond the first character, variables may also contain numbers and underscores `_'. Variables are called in to existence just by setting them (no explicit declarations are necessary). Local variables are limited in scope to the subroutine (or menu item definition) in which they appear. Global variables are accessible from all routines, and their values persist beyond the call which created them, until reset. 4>Built-in Variables NEdit has a number of permanently defined variables, which are used to access global editor information and information about the window in which the macro is executing. These are listed along with the built in functions in the section titled "Macro_Subroutines_". 3>Functions and Subroutines The syntax of a function or subroutine call is: function_name(arg1, arg2, ...) where arg1, arg2, etc. represent the argument values which are passed to the routine being called. A function or subroutine call can be on a line by itself, as above, or if it returns a value, can be invoked within a character or numeric expression: a = fn1(b, c) + fn2(d) dialog("fn3 says: " fn3()) Arguments are passed by value. This means that you cannot return values via the argument list, only through the function value or indirectly through agreed-upon global variables. 4>Built-in Functions NEdit has a wide range of built in functions which can be called from the macro language. These routines are divided into two classes, macro-language functions, and editor action routines. Editor action routines are more flexible, in that they may be called either from the macro language, or bound directly to keys via translation tables. They are also limited, however, in that they cannot return values. Macro language routines can return values, but cannot be bound to keys in translation tables. Nearly all of the built-in subroutines operate on an implied window, which is initially the window from which the macro was started. To manipulate the contents of other windows, use the focus_window subroutine to change the focus to the ones you wish to modify. focus_window can also be used to iterate over all of the currently open windows, using the special keyword names, "last" and "next". For backwards compatibility, hyphenated action routine names are allowed, and most of the existing action routines names which contain underscores have an equivalent version containing hyphens ('-') instead of underscores. Use of these names is discouraged. The macro parser resolves the ambiguity between '-' as the subtraction/negation operator, and - as part of an action routine name by assuming subtraction unless the symbol specifically matches an action routine name. 4>User Defined Functions Users can define their own macro subroutines, using the define keyword: define subroutine_name { < body of subroutine > } Subroutine definitions cannot appear within other definitions, nor within macro menu item definitions. They can only appear in (macro) files, such as the autoload macro file, cf. Preferences_. Macro files can be loaded with File -> Load Macro File or with the load_macro_file() action. The arguments with which a user-defined subroutine or function was invoked, are presented as $1, $2, ... , $9 or $args[expr], where expr can be evaluated to an integer from 1 to the number of arguments. The number of arguments can be read from $n_args or $args[]. The array $args[expr] is the only way to access arguments beyond the first 9. To return a value from a subroutine, and/or to exit from the subroutine before the end of the subroutine body, use the return statement: return 3>Operators and Expressions Operators have the same meaning and precedence that they do in C, except for ^, which raises a number to a power (y^x means y to the x power), rather than bitwise exclusive OR. The table below lists operators in decreasing order of precedence. Operators Associativity () ^ right to left - ! ++ -- (unary) * / % left to right + - left to right > >= < <= == != left to right & left to right | left to right && left to right || left to right (concatenation) left to right = += -= *= /= %=, &= |= right to left The order in which operands are evaluated in an expression is undefined, except for && and ||, which like C, evaluate operands left to right, but stop when further evaluation would no longer change the result. 4>Numerical Operators The numeric operators supported by the NEdit macro language are listed below: + addition - subtraction or negation * multiplication / division % modulo ^ power & bitwise and | bitwise or Increment (++) and decrement (--) operators can also be appended or prepended to variables within an expression. Prepended increment/decrement operators act before the variable is evaluated. Appended increment/decrement operators act after the variable is evaluated. 4>Logical and Comparison Operators Logical operations produce a result of 0 (for false) or 1 (for true). In a logical operation, any non-zero value is recognized to mean true. The logical and comparison operators allowed in the NEdit macro language are listed below: && logical and || logical or ! not > greater < less >= greater or equal <= less or equal == equal (integers and/or strings) != not equal (integers and/or strings) 4>Character String Operators The "operator" for concatenating two strings is the absence of an operator. Adjoining character strings with no operator in between means concatenation: d = a b "string" c t_print("the value of a is: " a) Comparison between character strings is done with the == and != operators, (as with integers). There are a number of useful built-in routines for working with character strings, which are listed in the section called "Macro_Subroutines_". 4>Arrays and Array Operators Arrays may contain either strings, integers, or other arrays. Arrays are associative, which means that they relate two pieces of information, the key and the value. The key is always a string; if you use an integer it is converted to a string. To determine if a given key is in an array, use the 'in' keyword. if ("6" in x) If the left side of the in keyword is an array, the result is true if every key in the left array is in the right array. Array values are not compared. To iterate through all the keys of an array use the 'for' looping construct. Keys are not guaranteed in any particular order: for (aKey in x) Elements can be removed from an array using the delete command: delete x[3] # deletes element with key 3 delete x[] # deletes all elements The number of elements in an array can be determined by referencing the array with no indices: dialog("array x has " x[] " elements", "OK") Arrays can be combined with some operators. All the following operators only compare the keys of the arrays. result = x + y (Merge arrays) The 'result' is a new array containing keys from both x and y. If duplicates are present values from y are used. result = x - y (Remove keys) The 'result' is a new array containing all keys from x that are not in y. result = x & y (Common keys) The 'result' is a new array containing all keys which are in both x and y. The values from y are used. result = x | y (Unique keys) The 'result' is a new array containing keys which exist in either x or y, but not both. When duplicate keys are encountered using the + and & operators, the values from the array on the right side of the operators are used for the result. All of the above operators are array only, meaning both the left and right sides of the operator must be arrays. The results are also arrays. Array keys can also contain multiple dimensions: x[1, 1, 1] = "string" These are used in the expected way, e.g.: for (i = 1; i < 3; i++) { for (j = 1; j < 3; j++) { x[i, j] = k++ } } gives the following array: x[1, 1] = 0 x[1, 2] = 1 x[2, 1] = 2 x[2, 2] = 3 Internally all indices are part of one string, separated by the string $sub_sep (ASCII 0x1c, 'FS'). The first key in the above example is in fact: ["1" $sub_sep "1"] If you need to extract one of the keys, you can use split(), using $sub_sep as the separator. You can also check for the existence of multi-dimensional array by looking for $sub_sep in the key. Last, you need $sub_sep if you want to use the 'in' keyword. if ((1,2) in myArray) {..} doesn't work, but if (("1" $sub_sep "2") in myArray) {..} does work. 3>Looping and Conditionals NEdit supports looping constructs: for and while, and conditional statements: if and else, with essentially the same syntax as C: for (, ...; ; , ...) while () if () if () else , as in C, can be a single statement, or a list of statements enclosed in curly braces ({}). is an expression which must evaluate to true for the statements in to be executed. for loops may also contain initialization statements, , executed once at the beginning of the loop, and increment/decrement statements (or any arbitrary statement), which are executed at the end of the loop, before the condition is evaluated again. Examples: for (i=0; i<100; i++) j = i * 2 for (i=0, j=20; i<20; i++, j--) { k = i * j t_print(i, j, k) } while (k > 0) { k = k - 1 t_print(k) } for (;;) { if (i-- < 1) break } Loops may contain break and continue statements. A **break** statement causes an exit from the innermost loop, a **continue** statement transfers control to the end of the loop. ---------------------------------------------------------------------- Macro Subroutines ----------------- 3>Built in Variables These variables are read-only and cannot be changed by direct assignment. **$1**, **$2**, **$3**, **$4**, **$5**, **$6**, **$7**, **$8**, **$9** **$args**[~expr~] **$n_args** Argument information. The first 9 arguments (if there are that many) can be referenced as read-only values using the shorthand form. All arguments can be accessed as values in the **$args** array, using a numeric index starting at 1. The total number of arguments received by a function is given by **$n_args** or **$args[]**. **$active_pane** Index of the current pane. **$auto_indent** Contains the current preference for auto indent. Can be "off", "on", or "smart". **$calltip_ID** Equals the ID of the currently displayed calltip, or 0 if no calltip is being displayed. **$cursor** Position of the cursor in the current window. **$column** Column number of the cursor position in the current window. **$display_width** Width of the current pane in pixels. **$em_tab_dist** If tab emulation is turned on in the Tabs... dialog of the Preferences menu, the value is the distance between emulated tab stops. If tab emulation is turned off, the value is 0. **$empty_array** An array with no elements. This can be used to initialize an array to an empty state. **$file_format** Current newline format that the file will be saved with. Can be "unix", "dos" or "macintosh". **$file_name** Name of the file being edited in the current window, stripped of directory component. **$file_path** Directory component of file being edited in the current window. **$font_name** Contains the current plain text font name. **$font_name_bold** Contains the current bold text font name. **$font_name_bold_italic** Contains the current bold-italic text font name. **$font_name_italic** Contains the current italic text font name. **$highlight_syntax** Whether syntax highlighting is turned on. **$incremental_backup** Contains 1 if incremental auto saving is on, otherwise 0. **$incremental_search_line** Has a value of 1 if the preference is selected to always show the incremental search line, otherwise 0. **$language_mode** Name of language mode set in the current window. **$line** Line number of the cursor position in the current window. **$locked** True if the file has been locked by the user. **$make_backup_copy** Has a value of 1 if original file is kept in a backup file on save, otherwise 0. **$max_font_width** The maximum font width of all the active styles. Syntax highlighting styles are only considered if syntax highlighting is turned on. **$min_font_width** The minimum font width of all the active styles. Syntax highlighting styles are only considered if syntax highlighting is turned on. **$modified** True if the file in the current window has been modified and the modifications have not yet been saved. **$VERSION** Returns NEdit's version number ('5006' for NEdit 5.6). **$n_display_lines** The number of lines visible in the currently active pane. **$n_panes** The number of panes in the current window. **$overtype_mode** True if in Overtype mode. **$read_only** True if the file is read only. **$selection_start, $selection_end** Beginning and ending positions of the primary selection in the current window, or -1 if there is no text selected in the current window. **$selection_left, $selection_right** Left and right character offsets of the rectangular (primary) selection in the current window, or -1 if there is no selection or it is not rectangular. **$server_name** Name of the current NEdit server. **$show_line_numbers** Whether line numbers are shown next to the text. **$show_matching** Contains the current preference for showing matching pairs, such as "[]" and "{}" pairs. Can be "off", "delimiter", or "range". **$match_syntax_based** Whether pair matching should use syntax information, if available. **$statistics_line** Has a value of 1 if the statistics line is shown, otherwise 0. **$sub_sep** Contains the value of the array sub-script separation string. **$tab_dist** The distance between tab stops for a hardware tab character, as set in the Tabs... dialog of the Preferences menu. **$text_length** The length of the text in the current document. **$top_line** The line number of the top line of the currently active pane. **$use_tabs** Whether the user is allowing the NEdit to insert tab characters to maintain spacing in tab emulation and rectangular dragging operations. (The setting of the "Use tab characters in padding and emulated tabs" button in the Tabs... dialog of the Preferences menu.) **$wrap_margin** The right margin in the current window for text wrapping and filling. **$wrap_text** The current wrap text mode. Values are "none", "auto" or "continuous". ..Disabled for 5.4 release. ..**$backlight_string** .. The current value of the window's backlighting specification. This is empty .. if backlighting is turned off. It can be changed through calls to the .. built-in macro function set_backlight_string(). 3>Built-in Subroutines **append_file( string, filename )** Appends a string to a named file. Returns 1 on successful write, or 0 if unsuccessful. **beep()** Ring the bell. **calltip( "text_or_key" [, pos [, mode or position_modifier, ...]] )** Pops up a calltip. is an optional position in the buffer where the tip will be displayed. Passing -1 for is equivalent to not specifying a position, and it guarantees that the tip will appear on-screen somewhere even if the cursor is not. The upper-left corner of the calltip will appear below where the cursor would appear if it were at this position. is one of "tipText" (default), "tipKey", or "tagKey". "tipText" displays the text as-is, "tagKey" uses it as the key to look up a tag, then converts the tag to a calltip, and "tipKey" uses it as the key to look up a calltip, then falls back to "tagKey" behavior if that fails. You'll usually use "tipKey" or "tipText". Finally, you can modify the placement of the calltip relative to the cursor position (or ) with one or more of these optional position modifiers: "center" aligns the center of the calltip with the position. "right" aligns the right edge of the calltip with the position. ("center" and "right" may not both be used.) "above" places the calltip above the position. "strict" does not allow the calltip to move from its position in order to avoid going off-screen or obscuring the cursor. Returns the ID of the calltip if it was found and/or displayed correctly, 0 otherwise. **clipboard_to_string()** Returns the contents of the clipboard as a macro string. Returns empty string on error. **dialog( message, btn_1_label, btn_2_label, ... )** Pop up a dialog for querying and presenting information to the user. First argument is a string to show in the message area of the dialog. Additional optional arguments represent labels for buttons to appear along the bottom of the dialog. Returns the number of the button pressed (the first button is number 1), or 0 if the user closed the dialog via the window close box. **filename_dialog( [title[, mode[, defaultPath[, filter[, defaultName]]]]] )** Presents a file selection dialog with the given title to the user that prompts for a new or existing file. Options are: ~title~ will be the title of the dialog, defaults to "Choose file". If ~mode~ is set to "exist" (default), the "New File Name"TextField of the FSB will be unmanaged. If "new", the TextField will be managed. ~defaultPath~ is the default path to use. Default (or "") will use the active document's directory. ~filter~ is the file glob which determines which files to display. Is set to "*" if filter is "" and by default. ~defaultName~ is the default filename that is filled in automatically. (**Note** that the default_filename argument does not work on all Motif implementations.) Returns "" if the user cancelled the dialog, otherwise returns the fully-qualified path, including the filename. **focus_window( window_name )** Sets the window on which subsequent macro commands operate. window_name can be either a fully qualified file name, or a relative filename (which will be completed from NEdit's working directory) or one of "last" for the last window created, or "next" for the next window in the chain from the currently focused window (the first window being the one returned from calling focus_window("last"). Returns the name of the newly-focused window, or an empty string if the requested window was not found. **get_character( position )** Returns the single character at the position indicated by the first argument to the routine from the current window. **get_range( start, end )** Returns the text between a starting and ending position from the current window. **get_selection()** Returns a string containing the text currently selected by the primary selection either from the current window (no keyword), or from anywhere on the screen (keyword "any"). **getenv( name )** Gets the value of an environment variable. **kill_calltip( [calltip_ID] )** Kills any calltip that is being displayed in the window in which the macro is running. If there is no displayed calltip this does nothing. If a calltip ID is supplied then the calltip is killed only if its ID is calltip_ID. **length( string )** Returns the length of a string **list_dialog( message, text, btn_1_label, btn_2_label, ... )** Pop up a dialog for prompting the user to choose a line from the given text string. The first argument is a message string to be used as a title for the fixed text describing the list. The second string provides the list data: this is a text string in which list entries are separated by newline characters. Additional optional arguments represent labels for buttons to appear along the bottom of the dialog. Returns the line of text selected by the user as the function value (without any newline separator) or the empty string if none was selected, and number of the button pressed (the first button is number 1), in $list_dialog_button. If the user closes the dialog via the window close box, the function returns the empty string, and $list_dialog_button returns 0. **max( n1, n2, ... )** Returns the maximum value of all of its arguments **min( n1, n2, ... )** Returns the minimum value of all of its arguments **read_file( filename )** Reads the contents of a text file into a string. On success, returns 1 in $read_status, and the contents of the file as a string in the subroutine return value. On failure, returns the empty string "" and an 0 $read_status. **replace_in_string( string, search_for, replace_with [, type, "copy"] )** Replaces all occurrences of a search string in a string with a replacement string. Arguments are 1: string to search in, 2: string to search for, 3: replacement string. There are two optional arguments. One is a search type, either "literal", "case", "word", "caseWord", "regex", or "regexNoCase". The default search type is "literal". If the optional "copy" argument is specified, a copy of the input string is returned when no replacements were performed. By default an empty string ("") will be returned in this case. Returns a new string with all of the replacements done. **replace_range( start, end, string )** Replaces all the text between two positions in the current window. If the cursor position is between start and end it will be set to start. **replace_selection( string )** Replaces the primary-selection selected text in the current window. **replace_substring( string, start, end, replace_with )** Replacing a substring between two positions in a string within another string. **revert_to_saved()** Reloads the file, discarding all changes done to the document by the user since the last save. **search( search_for, start [, search_type, wrap, direction] )** Searches silently in a window without dialogs, beeps, or changes to the selection. Arguments are: 1: string to search for, 2: starting position. Optional arguments may include the strings: "wrap" to make the search wrap around the beginning or end of the string, "backward" or "forward" to change the search direction ("forward" is the default), "literal", "case", "word", "caseWord", "regex", or "regexNoCase" to change the search type (default is "literal"). Returns the starting position of the match, or -1 if nothing matched. Also returns the ending position of the match in $search_end. **search_string( string, search_for, start [, search_type, direction] )** Built-in macro subroutine for searching a string. Arguments are 1: string to search in, 2: string to search for, 3: starting position. Optional arguments may include the strings: "wrap" to make the search wrap around the beginning or end of the string, "backward" or "forward" to change the search direction ("forward" is the default), "literal", "case", "word", "caseWord", "regex", or "regexNoCase" to change the search type (default is "literal"). Returns the starting position of the match, or -1 if nothing matched. Also returns the ending position of the match in $search_end. **select( start, end )** Selects (with the primary selection) text in the current buffer between a starting and ending position. **select_rectangle( start, end, left, right )** Selects a rectangular area of text between a starting and ending position, and confined horizontally to characters displayed between positions "left", and "right". ..Disabled for 5.4 release. ..**set_backlight_string( [string] )** .. Applies the given string, which should be in the format of the .. nedit*backlightCharTypes X resource, to the current text window, turning on .. backlighting. If the value of the string passed is "default", or if no .. parameter is passed, the nedit.backlightCharTypes X resource's own value will .. be used. If the empty string, "", is passed, backlighting will be turned .. off. **set_cursor_pos( position )** Set the cursor position for the current window. **shell_command( command, input_string )** Executes a shell command, feeding it input from input_string. On completion, output from the command is returned as the function value, and the command's exit status is returned in the global variable $shell_cmd_status. **split(string, separation_string [, search_type])** Splits a string using the separator specified. Optionally the search_type argument can specify how the separation_string is interpreted. The default is "literal". The returned value is an array with keys beginning at 0. **string_dialog( message, btn_1_label, btn_2_label, ... )** Pops up a dialog prompting the user to enter information. The first argument is a string to show in the message area of the dialog. Additional optional arguments represent labels for buttons to appear along the bottom of the dialog. Returns the string entered by the user as the function value, and number of the button pressed (the first button is number 1), in $string_dialog_button. If the user closes the dialog via the window close box, the function returns the empty string, and $string_dialog_button returns 0. **string_compare(string1, string2 [, consider-case])** Compare two strings and return 0 if they are equal, -1 if string1 is less than string2 or 1 if string1 is greater than string2. The values for the optional consider-case argument is either "case" or "nocase". The default is to do a case sensitive comparison. **string_to_clipboard( string )** Copy the contents of a macro string to the clipboard. **substring( string, start [, end] )** Returns the portion of a string between a start and end position (with the position of the beginning of the string being 0). If end is missing, the position of the end of the string is used. If either of the positions are negative, they are treated as relative to the end of the string. A position specified either before the start of the string or after the end of the string is repositioned to the nearest valid string position. If the start position is beyond the end position, the empty string is returned. **t_print( string1, string2, ... )** Writes strings to the terminal (stdout) from which NEdit was started. **tolower( string )** Return an all lower-case version of string. **toupper( string )** Return an all upper-case version of string. **valid_number( string )** Returns 1 if the string can be converted to a number without error following the same rules that the implicit conversion would. Otherwise 0. **write_file( string, filename )** Writes a string (parameter 1) to a file named in parameter 2. Returns 1 on successful write, or 0 if unsuccessful. 3>Deprecated Functions Some functions are included only for supporting legacy macros. You should not use any of these functions in any new macro you write. Among these are all action routines with hyphens in their names; use underscores instead ('find-dialog' -> 'find_dialog'). **match()** **DEPRECATED** Use select_to_matching() instead. ---------------------------------------------------------------------- Rangesets ---------- Rangesets are a tool of the macro language to tag parts, or ranges, of the text, which shall be viewed as a group. A range is merely a contiguous range of characters between a start and an end position in the document, and a set of ranges belonging together is called a rangeset. So, a rangeset is nothing but an in general non-contiguous part of the text. Rangesets can be assigned a background color to make them visible: characters within all ranges of a rangeset will have the background color of the rangeset. (If more than one rangeset includes a given character, its background color will be that of the most recently created rangeset which has a color defined.) Applications of rangesets are for example: * Showing differences between two versions of a file. Then, one rangeset would be those parts of the current file that are not in the prior version. * Highlighting all occurrences of a particular pattern, e.g. showing all the strings 'foobar' in the file. * Highlighting spelling mistakes found by a spell-checker. Rangesets are manipulated only through macro routines. Rangesets must be created first using the rangeset_create() function, which will return an identifier for the newly-created (empty) rangeset. This identifier is then passed to the other rangeset functions to manipulate the rangeset. For example, ranges are added to a rangeset with the rangeset_add() function. Notice that the ranges inside a rangeset do not have a particular identity. Only, they are given a (dynamically changing) numeric index, counting from 1, in the order of appearance in the text buffer. The ranges are adjusted when modifications are made to the text buffer: they shift around when characters are added or deleted staying with the original strings of characters. However, ranges within a set will coalesce if the characters between them are removed, or a new range is added to the set which bridges or overlaps others. For more on this, see "How rangesets change with modifications". There is a limit to the number of rangesets which can exist at any time - currently up to 63 in each document. Care should be taken to destroy any rangesets which are no longer needed, by using the rangeset_destroy() function, if this limit is attained. Rangesets can be named: this is useful for macros which need a fixed identification for rangesets which are used for the same purpose in different documents. Although a new rangeset's number is arbitrary, its name can be fixed. This is done using the rangeset_set_name() function. Note that rangeset names within a particular document may not be unique. For this reason, the rangeset_get_by_name() function returns an array of identifiers, which will be empty if the name has not been associated with a rangeset. 4>How rangesets change with modifications When changes are made to the document text, ranges within each set are altered with it, according to their behavioral mode. If changes are made outside of the ranges in a rangeset, each range simply maintains its size and adjusts its position to match the changes. When text within a range is deleted, the range's length is reduced by the same amount. When changes involving new text are made within a range of the set, or to one of the extremities of a range, different behaviours may be desirable. The rangeset_set_mode() function allows these modes to be chosen. Note that the precise behaviour of these modes may change in future versions of NEdit. The available modes are: **maintain** or **ins_del** - Both these modes have the same behaviour. New text added at the front of a range in a set is not added to the range; new text added within the range or at the end extends the range. Replacement overlapping an extremity of the set acts as if the new text were added first, then the old text deleted. This causes curtailment at the front of the range, extension at the end. Replacement of the full text of the range removes the range from the set. The default behaviour for a newly created rangeset is **maintain**. **del_ins** - New text added at the front or end of a range in a set is not added to the range; new text added within the range extends the range. Replacement overlapping an extremity of the set acts as if the old text were deleted first, then the new text added. This causes curtailment at either end. Replacement of the full text of the range removes the range from the set. **include** - New text added at the front or end of a range in a set extends the range, as does new text added within the range. Replacement overlapping an extremity of the set acts as if the new text were added first, then the old text deleted. This causes curtailment at the front of the range, extension at the end. Replacement of the full text of the range adds the new text to the range if the start position of the replacement is at the range's start point. **exclude** - New text added at the front or end of a range in a set does not extend the range; new text added within the range extends the range. Replacement overlapping an extremity causes curtailment of the range. Replacement of the full text of the range removes the range from the set. **break** - New text added at the front or end of a range in a set does not extend the range; new text added within the range will split the range. Replacement overlapping an extremity causes curtailment of the range. Replacement of the full text of the range removes the range from the set. 4>Notes A rangeset is manipulated ~only~ through macro routines. Rangesets can easily become very large, and may exceed the capacity of the running process. Coloring relies on proper color names or specifications (such as the "#rrggbb" hexadecimal digit strings), and appropriate hardware support. If an invalid color name is given, the default background color is used instead. Behaviours set using rangeset_set_mode() are subject to change in future versions. 3>Rangeset read-only variables **$rangeset_list** array of active rangeset identifiers, with integer keys starting at 0, in the order the rangesets were defined. 3>Rangeset functions **rangeset_create()** **rangeset_create( n )** Creates one or more new rangesets. The first form creates a single range set and returns its identifier; if there are no rangesets available it returns 0. The second form creates n new rangesets, and returns an array of the rangeset identifiers with keys beginning at 0. If the requested number of rangesets is not available it returns an empty array. **rangeset_destroy( r )** **rangeset_destroy( array )** Deletes all information about a rangeset or a number of rangesets. The first form destroys the rangeset identified by r. The second form should be passed an array of rangeset identifiers with keys beginning at 0 (i.e. the same form of array returned by rangeset_create(n); it destroys all the rangesets appearing in the array. If any of the rangesets do not exist, the function continues without errors. Does not return a value. **rangeset_add( r )** **rangeset_add( r, start, end )** **rangeset_add( r, r0 )** Adds to the rangeset r. The first form adds the range identified by the current primary selection to the rangeset, unless the selection is rectangular. The second form adds the range defined by the start and end positions given. The third form adds all ranges in the rangeset r0 to the rangeset r, and returns 0. Returns the index of the newly-added range within the rangeset. **rangeset_subtract( r, [start, end] )** **rangeset_subtract( r, r0 )** Removes from the rangeset r. The first form removes the range identified by the current primary selection from the rangeset, unless start and end are defined, in which case the range they define is removed. The second form removes all ranges in the rangeset r0 from the rangeset r. Does not return a value. **rangeset_invert( r )** Changes the rangeset r so that it contains all ranges not in r. Does not return a value. **rangeset_get_by_name( name )** Returns an array of active rangeset identifiers, with integer keys starting at 0, whose name matches name. **rangeset_info( r )** Returns an array containing information about the rangeset r. The array has the following keys: **defined** (whether a rangeset with identifier r is defined), **count** (the number of ranges in the rangeset), **color** (the current background color of the rangeset, an empty string if the rangeset has no color), **name** (the user supplied name of the rangeset, an empty string if the rangeset has no name), and **mode** (the name of the modify-response mode of the rangeset). **rangeset_range( r, [index] )** Returns details of a specific range in the rangeset r. The range is specified by index, which should be between 1 and n (inclusive), where n is the number of ranges in the rangeset. The return value is an array containing the keys **start** (the start position of the range) and **end** (the end position of the range). If index is not supplied, the region returned is the span of the entire rangeset (the region starting at the start of the first range and ending at the end of the last). If index is outside the correct range of values, the function returns an empty array. **rangeset_includes( r, pos )** Returns the index of the range in rangeset r which includes pos; returns 0 if pos is not contained in any of the ranges of r. This can also be used as a simple true/false function which returns true if pos is contained in the rangeset. **rangeset_set_color( r, color )** Attempts to apply the color as a background color to the ranges of r. If color is at empty string, removes the coloring of r. No check is made regarding the validity of color: if the color is invalid (a bad name, or not supported by the hardware) this has unpredictable effects. **rangeset_set_name( r, name )** Apply the name to the rangeset r. **rangeset_set_mode( r, type )** Changes the behaviour of the rangeset r when modifications to the text buffer occur. type can be one of the following: "maintain" (the default), "break", "include", "exclude", "ins_del" or "del_ins". (These modes are described above.) Highlighting Information ------------------------ The user can interrogate the current window to determine the color highlighting used on a particular piece of text. The following functions provide information on the highlighting pattern against which text at a particular position has been matched, its style, color and font attributes (whether the font is supposed to be bold and/or italic). These macro functions permit macro writers to generate formatted output which allows NEdit highlighting to be reproduced. This is suitable for the generation of HTML or Postscript output, for example. Note that if any of the functions is used while in Plain mode or while syntax highlighting is off, the behaviour is undefined. **get_pattern_by_name( pattern_name )** Returns an array containing the pattern attributes for pattern 'pattern_name'. The elements in this array are: * **style** -- Highlight style name If 'pattern_name' is invalid, an empty array is returned. **get_pattern_at_pos( pos )** Returns an array containing the pattern attributes of the character at position 'pos'. The elements in this array are: * **pattern** -- Highlight pattern name * **style** -- Highlight style name * **extent** -- The length in the text which uses the same highlighting pattern The 'extent' value is measured from position 'pos' going right/down (forward in the file) only. If 'pos' is invalid, an empty array is returned. **get_style_by_name( style_name )** Returns an array containing the style attributes for style 'style_name'. The elements in this array are: * **bold** -- '1' if style is bold, '0' otherwise * **italic** -- '1' if style is italic, '0' otherwise * **color** -- Name of the style's color * **background** -- Name of the background color, if any The colors use the names specified in the color definitions for the style. These will either be names matching those the X server recognises, or RGB (red/green/blue) specifications. If 'style_name' is invalid, an empty array is returned. **get_style_at_pos( pos )** Returns an array containing the style attributes of the character at position 'pos'. The elements in this array are: * **style** -- Name of the highlight style * **bold** -- '1' if style is bold, '0' otherwise * **italic** -- '1' if style is italic, '0' otherwise * **color** -- Name of the style's color * **rgb** -- Color's RGB values ('#rrggbb') * **background** -- Name of the background color, if any * **back_rgb** -- Background color's RGB values ('#rrggbb') * **extent** -- The length in the text which uses the same highlight style The colors use the names specified in the color definitions for the style. These will either be names matching those the X server recognises, or RGB specifications. The values for 'rgb' and 'back_rgb' contain the actual color values allocated by the X server for the window. If the X server cannot allocate the specified (named) color exactly, the RGB values in these entries may not match the specified ones. The 'extent' value is measured from position 'pos' going right/down (forward in the file) only. If 'pos' is invalid, an empty array is returned. ---------------------------------------------------------------------- Action Routines --------------- All of the editing capabilities of NEdit are represented as a special type of subroutine, called an action routine, which can be invoked from both macros and translation table entries (see "Key_Binding_" in the Customizing section of the Help menu). 3>Actions Representing Menu Commands File Menu Search Menu ----------------------- ------------------------- new() find() open() find_dialog() open_dialog() find_again() open_selected() find_selection() close() replace() save() replace_dialog() save_as() replace_all() save_as_dialog() replace_in_selection() revert_to_saved_dialog() replace_again() include_file() goto_line_number() include_file_dialog() goto_line_number_dialog() load_macro_file() goto_selected() load_macro_file_dialog() mark() load_tags_file() mark_dialog() load_tags_file_dialog() goto_mark() unload_tags_file() goto_mark_dialog() load_tips_file() goto_matching() load_tips_file_dialog() select_to_matching() unload_tips_file() find_definition() print() show_tip() print_selection() exit() Shell Menu ------------------------- Edit Menu filter_selection_dialog() ----------------------- filter_selection() undo() execute_command() redo() execute_command_dialog() delete() execute_command_line() select_all() shell_menu_command() shift_left() shift_left_by_tab() Macro Menu shift_right() ------------------------- shift_right_by_tab() macro_menu_command() uppercase() repeat_macro() lowercase() repeat_dialog() fill_paragraph() control_code_dialog() Windows Menu ------------------------- split_pane() close_pane() detach_document() move_document_dialog() An action representing a menu command is usually named the same as its corresponding menu item except that all punctuation is removed, all letters are changed to lower case, and spaces are replaced with underscores. To present a dialog to ask the user for input, use the actions with the `_dialog` suffix. Actions without the `_dialog` suffix take the information from the routine's arguments (see below). 3>Menu Action Routine Arguments Arguments are text strings enclosed in quotes. Below are the menu action routines which take arguments. Optional arguments are enclosed in []. **new**( ["tab" | "window" | "prefs" | "opposite"] ) **close**( ["prompt" | "save" | "nosave"] ) **execute_command**( shell-command ) **filter_selection**( shell-command ) **find**( search-string [, ~search-direction~] [, ~search-type~] [, ~search-wrap~] ) **find_again**( [~search-direction~] [, ~search-wrap~] ) **find_definition**( [tag-name] ) **find_dialog**( [~search-direction~] [, ~search-type~] [, ~keep-dialog~] ) **find_selection**( [~search-direction~] [, ~search-wrap~] [, ~non-regex-search-type~] ) **goto_line_number**( [~line-number~] [, ~column-number~] ) **goto_mark**( ~mark-letter~ ) **include_file**( ~filename~ ) **load_tags_file**( ~filename~ ) **macro_menu_command**( ~macro-menu-item-name~ ) **mark**( ~mark-letter~ ) **open**( ~filename~ ) **replace**( search-string, replace-string, [, ~search-direction~] [, ~search-type~] [, ~search-wrap~] ) **replace_again**( [~search-direction~] [, ~search-wrap~] ) **replace_all**( search-string, replace-string [, ~search-type~] ) **replace_dialog**( [~search-direction~] [, ~search-type~] [, ~keep-dialog~] ) **replace_in_selection**( search-string, replace-string [, ~search-type~] ) **save_as**( ~filename~ ) **shell_menu_command**( ~shell-menu-item-name~ ) **unload_tags_file**( ~filename~ ) **----------- Some notes on argument types above -----------** ~Arguments to new()~ "tab": Open a new tab "window": Open a new window "prefs": Follow the user's tab/window preference "opposite": Opposite of user's tab/window preference Default behaviour is "prefs". ~filename~ Path names are relative to the directory from which NEdit was started. Shell interpreted wildcards and `~' are not expanded. ~keep-dialog~ Either "keep" or "nokeep". ~mark-letter~ The mark command limits users to single letters. Inside of macros, single digits are allowed as marks. These won't interfere with marks set by the user. ~macro-menu-item-name~ Name of the command exactly as specified in the Macro Menu dialogs. ~non-regex-search-type~ Either "literal", "case", "word", or "caseWord". ~search-direction~ Either "forward" or "backward". ~search-type~ Either "literal", "case", "word", "caseWord", "regex", or "regexNoCase". ~search-wrap~ Either "wrap" or "nowrap". ~shell-menu-item-name~ Name of the command exactly as specified in the Shell Menu dialogs. 3>Window Preferences Actions **set_auto_indent( "off" | "on" | "smart" )** Set auto indent mode for the current window. **set_em_tab_dist( em-tab-distance )** Set the emulated tab size. An em-tab-distance value of 0 or less translates to no emulated tabs. Em-tab-distance must be smaller than 1000. **set_fonts( font-name, italic-font-name, bold-font-name, bold-italic-font-name )** Set all the fonts used for the current window. **set_highlight_syntax( [0 | 1] )** Set syntax highlighting mode for the current window. A value of 0 turns it off and a value of 1 turns it on. If no parameters are supplied the option is toggled. **set_incremental_backup( [0 | 1] )** Set incremental backup mode for the current window. A value of 0 turns it off and a value of 1 turns it on. If no parameters are supplied the option is toggled. **set_incremental_search_line( [0 | 1] )** Show or hide the incremental search line for the current window. A value of 0 turns it off and a value of 1 turns it on. If no parameters are supplied the option is toggled. **set_language_mode( language-mode )** Set the language mode for the current window. If the language mode is "" or unrecognized, it will be set to Plain. **set_locked( [0 | 1] )** This only affects the locked status of a file, not its read-only status. Permissions are ~not~ changed. A value of 0 turns it off and a value of 1 turns it on. If no parameters are supplied the option is toggled. **set_make_backup_copy( [0 | 1] )** Set whether backup copies are made during saves for the current window. A value of 0 turns it off and a value of 1 turns it on. If no parameters are supplied the option is toggled. **set_overtype_mode( [0 | 1] )** Set overtype mode for the current window. A value of 0 turns it off and a value of 1 turns it on. If no parameters are supplied the option is toggled. **set_show_line_numbers( [0 | 1] )** Show or hide line numbers for the current window. A value of 0 turns it off and a value of 1 turns it on. If no parameters are supplied the option is toggled. **set_show_matching( "off" | "delimiter" | "range" )** Set show matching (...) mode for the current window. **set_match_syntax_based( [0 | 1] )** Set whether matching should be syntax based for the current window. **set_statistics_line( [0 | 1] )** Show or hide the statistics line for the current window. A value of 0 turns it off and a value of 1 turns it on. If no parameters are supplied the option is toggled. **set_tab_dist( tab-distance )** Set the size of hardware tab spacing. Tab-distance must be a value greater than 0 and no greater than 20. **set_use_tabs( [0 | 1] )** Set whether tab characters are used for the current window. A value of 0 turns it off (using space characters instead) and a value of 1 turns it on. If no parameters are supplied the option is toggled. **set_wrap_margin( wrap-width )** Set the wrap width for text wrapping of the current window. A value of 0 means to wrap at window width. **set_wrap_text( "none" | "auto" | "continuous" )** Set wrap text mode for the current window. 3>Keyboard-Only Actions In addition to the arguments listed in the call descriptions below, any routine involving cursor movement can take the argument "extend", meaning, adjust the primary selection to the new cursor position. Routines which take the "extend" argument as well as mouse dragging operations for both primary and secondary selections can take the optional keyword "rect", meaning, make the selection rectangular. Any routine that accepts the "scrollbar" argument will move the display but not the cursor or selection. Routines that accept the "nobell" argument will fail silently without beeping, when that argument is supplied. **backward_character( ["nobell"] )** Moves the cursor one character to the left. **backward_paragraph(["nobell"] )** Moves the cursor to the beginning of the paragraph, or if the cursor is already at the beginning of a paragraph, moves the cursor to the beginning of the previous paragraph. Paragraphs are defined as regions of text delimited by one or more blank lines. **backward_word( ["nobell"] )** Moves the cursor to the beginning of a word, or, if the cursor is already at the beginning of a word, moves the cursor to the beginning of the previous word. Word delimiters are user-settable, and defined by the X resource wordDelimiters. **beginning_of_file( ["scrollbar"] )** Moves the cursor to the beginning of the file. **beginning_of_line( ["absolute"] )** Moves the cursor to the beginning of the line. If "absolute" is given, always moves to the absolute beginning of line, regardless of the text wrapping mode. **beginning_of_selection()** Moves the cursor to the beginning of the selection without disturbing the selection. **copy_clipboard()** Copies the current selection to the clipboard. **copy_primary()** Copies the primary selection to the cursor. **copy_to()** If a secondary selection exists, copies the secondary selection to the cursor. If no secondary selection exists, copies the primary selection to the pointer location. **copy_to_or_end_drag()** Completes either a secondary selection operation, or a primary drag. If the user is dragging the mouse to adjust a secondary selection, the selection is copied and either inserted at the cursor location, or, if pending-delete is on and a primary selection exists in the window, replaces the primary selection. If the user is dragging a block of text (primary selection), completes the drag operation and leaves the text at its current location. **cut_clipboard()** Deletes the text in the primary selection and places it in the clipboard. **cut_primary()** Copies the primary selection to the cursor and deletes it at its original location. **delete_selection()** Deletes the contents of the primary selection. **delete_next_character( ["nobell"] )** If a primary selection exists, deletes its contents. Otherwise, deletes the character following the cursor. **delete_previous_character( ["nobell"] )** If a primary selection exists, deletes its contents. Otherwise, deletes the character before the cursor. **delete_next_word( ["nobell"] )** If a primary selection exists, deletes its contents. Otherwise, deletes the word following the cursor. **delete_previous_word( ["nobell"] )** If a primary selection exists, deletes its contents. Otherwise, deletes the word before the cursor. **delete_to_start_of_line( ["nobell", "wrap"] )** If a primary selection exists, deletes its contents. Otherwise, deletes the characters between the cursor and the start of the line. If "wrap" is given, deletes to the previous wrap point or beginning of line, whichever is closest. **delete_to_end_of_line( ["nobell", "absolute"] )** If a primary selection exists, deletes its contents. Otherwise, deletes the characters between the cursor and the end of the line. If "absolute" is given, always deletes to the absolute end of line, regardless of the text wrapping mode. **deselect_all()** De-selects the primary selection. **end_of_file( ["scrollbar"] )** Moves the cursor to the end of the file. **end_of_line( ["absolute"] )** Moves the cursor to the end of the line. If "absolute" is given, always moves to the absolute end of line, regardless of the text wrapping mode. **end_of_selection()** Moves the cursor to the end of the selection without disturbing the selection. **exchange( ["nobell"] )** Exchange the primary and secondary selections. **extend_adjust()** Attached mouse-movement events to begin a selection between the cursor and the mouse, or extend the primary selection to the mouse position. **extend_end()** Completes a primary drag-selection operation. **extend_start()** Begins a selection between the cursor and the mouse. A drag-selection operation can be started with either extend_start or grab_focus. **focus_pane( [relative-pane] | [positive-index] | [negative-index] )** Move the focus to the requested pane. Arguments can be specified in the form of a relative-pane ("first", "last", "next", "previous"), a positive-index (numbers greater than 0, 1 is the same as "first") or a negative-index (numbers less than 0, -1 is the same as "last"). **forward_character()** Moves the cursor one character to the right. **forward_paragraph( ["nobell"] )** Moves the cursor to the beginning of the next paragraph. Paragraphs are defined as regions of text delimited by one or more blank lines. **forward_word( ["tail"] ["nobell"] )** Moves the cursor to the beginning of the next word. Word delimiters are user-settable, and defined by the X resource wordDelimiters. If the "tail" argument is supplied the cursor will be moved to the end of the current word or the end of the next word, if the cursor is between words. **grab_focus()** Moves the cursor to the mouse pointer location, and prepares for a possible drag-selection operation (bound to extend_adjust), or multi-click operation (a further grab_focus action). If a second invocation of grab focus follows immediately, it selects a whole word, or a third, a whole line. **insert_string( "string" )** If pending delete is on and the cursor is inside the selection, replaces the selection with "string". Otherwise, inserts "string" at the cursor location. **key_select( "direction" [,"nobell"] )** Moves the cursor one character in "direction" ("left", "right", "up", or "down") and extends the selection. Same as forward/backward-character("extend"), or process-up/down("extend"), for compatibility with previous versions. **move-destination()** Moves the cursor to the pointer location without disturbing the selection. (This is an unusual way of working. We left it in for compatibility with previous versions, but if you actually use this capability, please send us some mail, otherwise it is likely to disappear in the future. **move_to()** If a secondary selection exists, deletes the contents of the secondary selection and inserts it at the cursor, or if pending-delete is on and there is a primary selection, replaces the primary selection. If no secondary selection exists, moves the primary selection to the pointer location, deleting it from its original position. **move_to_or_end_drag()** Completes either a secondary selection operation, or a primary drag. If the user is dragging the mouse to adjust a secondary selection, the selection is deleted and either inserted at the cursor location, or, if pending-delete is on and a primary selection exists in the window, replaces the primary selection. If the user is dragging a block of text (primary selection), completes the drag operation and deletes the text from its current location. **newline()** Inserts a newline character. If Auto Indent is on, lines up the indentation of the cursor with the current line. **newline_and_indent()** Inserts a newline character and lines up the indentation of the cursor with the current line, regardless of the setting of Auto Indent. **newline_no_indent()** Inserts a newline character, without automatic indentation, regardless of the setting of Auto Indent. **next_page( ["stutter"] ["column"] ["scrollbar"] ["nobell"] )** Moves the cursor and scroll forward one page. The parameter "stutter" moves the cursor to the bottom of the display, unless it is already there, otherwise it will page down. The parameter "column" will maintain the preferred column while moving the cursor. **page_left( ["scrollbar"] ["nobell"] )** Move the cursor and scroll left one page. **page_right( ["scrollbar"] ["nobell"] )** Move the cursor and scroll right one page. **paste_clipboard()** Insert the contents of the clipboard at the cursor, or if pending delete is on, replace the primary selection with the contents of the clipboard. **previous_page( ["stutter"] ["column"] ["scrollbar"] ["nobell"] )** Moves the cursor and scroll backward one page. The parameter "stutter" moves the cursor to the top of the display, unless it is already there, otherwise it will page up. The parameter "column" will maintain the preferred column while moving the cursor. **process_bdrag()** Same as secondary_or_drag_start for compatibility with previous versions. **process_cancel()** Cancels the current extend_adjust, secondary_adjust, or secondary_or_drag_adjust in progress. **process_down( ["nobell", "absolute"] )** Moves the cursor down one line. If "absolute" is given, always moves to the next line in the text buffer, regardless of wrapping. **process_return()** Same as newline for compatibility with previous versions. **process_shift_down( ["nobell", "absolute"] )** Same as process_down("extend") for compatibility with previous versions. **process_shift_up( ["nobell", "absolute"] )** Same as process_up("extend") for compatibility with previous versions. **process_tab()** If tab emulation is turned on, inserts an emulated tab, otherwise inserts a tab character. **process_up( ["nobell", "absolute"] )** Moves the cursor up one line. If "absolute" is given, always moves to the previous line in the text buffer, regardless of wrapping. **raise_window([relative-window] | [positive-index] | [negative-index] [, "focus" | "nofocus"])** Raise the current focused window to the front if no argument is supplied. Arguments can be specified in the form of a relative-window ("first", "last", "next", "previous"), a positive-index (numbers greater than 0, 1 is the same as "last") or a negative-index (numbers less than 0, -1 is the same as "first"). Moreover, it can be specified whether or not the raised window should request the X input focus. By default, it depends on the setting of the nedit.focusOnRaise resource (see the section "X_Resources_") whether or not the input focus is requested. **scroll_down( nUnits, ["lines" | "pages"] )** Scroll the display down (towards the end of the file) by a given number of units, units being lines or pages. Default units are lines. **scroll_left( nPixels )** Scroll the display left by nPixels. **scroll_right( nPixels )** Scroll the display right by nPixels. **scroll_up( nUnits, ["lines" | "pages"] )** Scroll the display up (towards the beginning of the file) by a given number of units, units being lines or pages. Default units are lines. **scroll_to_line( lineNum )** Scroll to position line number lineNum at the top of the pane. The first line of a file is line 1. **secondary_adjust()** Attached mouse-movement events to extend the secondary selection to the mouse position. **secondary_or_drag_adjust()** Attached mouse-movement events to extend the secondary selection, or reposition the primary text being dragged. Takes two optional arguments, "copy", and "overlay". "copy" leaves a copy of the dragged text at the site at which the drag began. "overlay" does the drag in overlay mode, meaning the dragged text is laid on top of the existing text, obscuring and ultimately deleting it when the drag is complete. **secondary_or_drag_start()** To be attached to a mouse down event. Begins drag selecting a secondary selection, or dragging the contents of the primary selection, depending on whether the mouse is pressed inside of an existing primary selection. **secondary_start()** To be attached to a mouse down event. Begin drag selecting a secondary selection. **select_all()** Select the entire file. **self_insert()** To be attached to a key-press event, inserts the character equivalent of the key pressed. ---------------------------------------------------------------------- Customizing =========== Customizing NEdit ----------------- NEdit can be customized in many different ways. The most important user-settable options are presented in the Preferences menu, including all options that users might need to change during an editing session. Options set in the Default Settings sub-menu of the Preferences menu can be preserved between sessions by selecting Save Defaults, which writes the changes to the preferences file. See the section titled "Preferences_" for more details. User defined commands can be added to NEdit's Shell, Macro, and window background menus. Dialogs for creating items in these menus can be found under Customize Menus in the Default Settings sub menu of the Preferences menu. For users who depend on NEdit every day and want to tune every excruciating detail, there are also X resources for tuning a vast number of such details, down to the color of each individual button. See the section "X_Resources_" for more information, as well as a list of selected resources. The most common reason for customizing your X resources for NEdit, however, is key binding. While limited key binding can be done through Preferences settings (Preferences -> Default Settings -> Customize Menus), you can really only add keys this way, and each key must have a corresponding menu item. Any significant changes to key binding should be made via the Translations resource and menu accelerator resources. The sections titled "Key_Binding_" and "X_Resources_" have more information. ---------------------------------------------------------------------- Preferences ----------- The Preferences menu allows you to set options for both the current editing window, and default values for newly created windows and future NEdit sessions. Options in the Preferences menu itself (not in the Default Settings sub-menu) take effect immediately and refer to the current window only. Options in the Default Settings sub-menu provide initial settings for future windows created using the New or Open commands; options affecting all windows are also set here. Preferences set in the Default Settings sub-menu are saved in a file that NEdit reads at startup time, cf. Autoload_Files_, by selecting Save Defaults. 3>Preferences Menu **Default Settings** Menu of initial settings for future windows. Generally the same as the options in the main part of the menu, but apply as defaults for future windows created during this NEdit session. These settings can be saved using the Save Defaults command below, to be loaded automatically each time NEdit is started. **Save Defaults** Save the default options as set under Default Settings for future NEdit sessions. **Statistics Line** Show the full file name, line number, and length of the file being edited. **Incremental Search Line** Keep the incremental search bar (Search -> Find Incremental) permanently displayed at the top of the window. **Show Line Numbers** Display line numbers to the right of the text. **Language Mode** Tells NEdit what language (if any) to assume, for selecting language-specific features such as highlight patterns and smart indent macros, and setting language specific preferences like word delimiters, tab emulation, and auto-indent. See Programming_with_NEdit_ for more information. **Auto Indent** Setting Auto Indent "on" maintains a running indent (pressing the Return key will line up the cursor with the indent level of the previous line). If smart indent macros are available for the current language mode, smart indent can be selected and NEdit will attempt to guess proper language indentation for each new line, cf. Auto/Smart_Indent_. **Wrap** Choose between two styles of automatic wrapping or none. Auto Newline wrap, wraps text at word boundaries when the cursor reaches the right margin, by replacing the space or tab at the last word boundary with a newline character. Continuous Wrap wraps long lines which extend past the right margin. Continuous Wrap mode is typically used to produce files where newlines are omitted within paragraphs, to make text filling automatic (a kind of poor-man's word processor). Text of this style is common on Macs and PCs but is not necessarily supported very well under Unix (except in programs which deal with e-mail, for which it is often the format of choice). **Wrap Margin** Set margin for Auto Newline Wrap, Continuous Wrap, and Fill Paragraph. Lines may, be wrapped at the right margin of the window, or the margin can be set at a specific column. **Tab Stops** Set the tab distance (number of characters between tab stops) for tab characters, and control tab emulation and use of tab characters in padding and emulated tabs. **Text Font...** Change the font(s) used to display text (fonts for menus and dialogs must be set using X resources for the text area of the window). See below for more information. **Highlight Syntax** If NEdit recognizes the language being edited, and highlighting patterns are available for that language, use fonts and colors to enhance viewing of the file. (See Syntax_Highlighting_ for more information.) **Make Backup Copy** On Save, write a backup copy of the file as it existed before the Save command with the extension .bck (Unix only). **Incremental Backup** Periodically make a backup copy of the file being edited under the name `~filename` on Unix or `_filename` on VMS (see Crash_Recovery_). **Show Matching (..)** Momentarily highlight matching parenthesis, brackets, and braces, or the range between them, when one of these characters is typed, or when the insertion cursor is positioned after it. Delimiter only highlights the matching delimiter, while Range highlights the whole range of text between the matching delimiters. Optionally, the matching can make use of syntax information if syntax highlighting is enabled. Alternatively, the matching is purely character based. In general, syntax based matching results in fewer false matches. **Overtype** In overtype mode, new characters entered replace the characters in front of the insertion cursor, rather than being inserted before them. **Read Only** Lock the file against accidental modification. This temporarily prevents the file from being modified in this NEdit session. Note that this is different from setting the file protection. 3>Preferences -> Default Settings Menu Options in the Preferences -> Default Settings menu have the same meaning as those in the top-level Preferences menu, except that they apply to future NEdit windows and future NEdit sessions if saved with the Save Defaults command. Additional options which appear in this menu are: **Language Modes** Define language recognition information (for determining language mode from file name or content) and set language specific preferences. **Tag Collisions** How to react to multiple tags for the same name. Tags are described in the section: Finding_Declarations_(ctags)_. In Show All mode, all matching tags are displayed in a dialog. In Smart mode, if one of the matching tags is in the current window, that tag is chosen, without displaying the dialog. **Command Shell...** Set the shell used to run programs from the shell_command() macro function and from the Shell menu. This defaults to the user's login shell. **Colors...** Change the colors used to display text. The "Matching (..)" fields change the colors that matching parens, brackets and braces are flashed when the "Show Matching (..)" option is enabled. Note that the foreground colors for plain text, selected text, and matching paren flashing only apply when syntax highlighting is disabled. When syntax highlighting is enabled, text (even text that appears plain) will always be colored according to its highlighting style. (For information on changing syntax highlighting styles and matching patterns use see Syntax_Highlighting_.) **Customize Menus** Add/remove items from the Shell, Macro, and window background menus (see below). **Customize Window Title** Opens a dialog where the information to be displayed in the window's title field can be defined and tested. The dialog contains a Help button, providing further information about the options available. **Searching** Options for controlling the behavior of Find and Replace commands: ~Verbose~ - Presents search results in dialog form, asks before wrapping a search back around the beginning (or end) of the file (unless Beep On Search Wrap is turned on). ~Wrap Around~ - Search and Replace operations wrap around the beginning (or end) of the file. ~Beep On Search Wrap~ - Beep when Search and Replace operations wrap around the beginning (or end) of the file (only if Wrap Around is turned on). ~Keep Dialogs Up~ - Don't pop down Replace and Find boxes after searching. ~Default Search Style~ - Initial setting for search type in Find and Replace dialogs. ~Default Replace Scope~ - [THIS OPTION IS ONLY PRESENT WHEN NEDIT WAS COMPILED WITH THE -DREPLACE_SCOPE FLAG TO SELECT AN ALTERNATIVE REPLACE DIALOG LAYOUT.] Initial setting for the scope in the Replace/Find dialog, when a selection exists. It can be either "In Window", "In Selection", or "Smart". "Smart" results in "In Window" if the size of the selection is smaller than 1 line, and to "In Selection" otherwise. **Syntax Highlighting** Program and configure enhanced text display for new or supported languages. (See Syntax_Highlighting_.) **Tabbed Editing** Options for controlling the tabbed interface: ~Open File in New Tab~ - Open files in new tabs, else open files in new windows. ~Show Tab Bar~ - Show/Hide the tab bar. ~Hide Tab Bar when only one Document is open~ ~Next/Prev Tabs Across Windows~ - Suppose there are two windows with three tabs in the first window and two tabs in the second window. Enabling this option, if you are on the third tab in the first window, hitting Ctrl+PageDown would switch to the first tab in the second window (instead of switching to the first tab in the first window). ~Sort Tabs Alphabetically~ **Show Tooltips** Show file name and path in a tooltip when moving the mouse pointer over a tab. (See Tabbed_Editing_.) **Terminate with Line Break on Save** Some UNIX tools expect that files end with a line feed. If this option is activated, NEdit will append one if required. **Sort Open Prev. Menu** Option to order the File -> Open Previous menu alphabetically, versus in order of last access. **Popups Under Pointer** Display pop-up dialogs centered on the current mouse position, as opposed to centered on the parent window. This generally speeds interaction, and is essential for users who set their window managers so keyboard focus follows the mouse. **Auto-Scroll Near Window Top/Bottom** When this option is enabled the window will automatically scroll when the cursor comes 4 lines from the top or bottom of the window (except at the beginning of the file). The number of lines can be customized with the nedit.autoScrollVPadding resource. **Warnings** Options for controlling the popping up of warning dialogs: ~File Modified Externally~ - Pop up a warning dialog when files get changed external to NEdit. ~Check Modified File Contents~ - If external file modification warnings are requested, also check the file contents iso. only the modification date. ~On Exit~ - Ask before exiting when two or more files are open in an NEdit session or before closing a window with two or more tabs. **Initial Window Size** Default size for new windows. 3>Changing Font(s) The font used to display text in NEdit is set under Preferences -> Text Font (for the current window), or Preferences -> Default Settings Text Font (for future windows). These dialogs also allow you to set fonts for syntax highlighting. If you don't intend to use syntax highlighting, you can ignore most of the dialog, and just set the field labeled Primary Font. Unless you are absolutely certain about the types of files that you will be editing with NEdit, you should choose a fixed-spacing font. Many, if not most, plain-text files are written expecting to be viewed with fixed character spacing, and will look wrong with proportional spacing. NEdit's filling, wrapping, and rectangular operations will also work strangely if you choose a proportional font. Note that in the font browser (the dialog brought up by the Browse... button), the subset of fonts which are shown is narrowed depending on the characteristics already selected. It is therefore important to know that you can unselect characteristics from the lists by clicking on the selected items a second time. Fonts for syntax highlighting should ideally match the primary font in both height and spacing. A mismatch in spacing will result in similar distortions as choosing a proportional font: column alignment will sometimes look wrong, and rectangular operations, wrapping, and filling will behave strangely. A mismatch in height will cause windows to re-size themselves slightly when syntax highlighting is turned on or off, and increase the inter-line spacing of the text. Unfortunately, on some systems it is hard to find sets of fonts which match exactly in height. 3>Customizing Menus You can add or change items in the Shell, Macro, and window background menus under Preferences -> Default Settings -> Customize Menus. When you choose one of these, you will see a dialog with a list of the current user-configurable items from the menu on the left. To change an existing item, select it from the list, and its properties will appear in the remaining fields of the dialog, where you may change them. Selecting the item "New" from the list allows you to enter new items in the menu. Hopefully most of the characteristics are self explanatory, but here are a few things to note: Accelerator keys are keyboard shortcuts which appear on the right hand side of the menus, and allow you avoid pulling down the menu and activate the command with a single keystroke. Enter accelerators by typing the keys exactly as you would to activate the command. Mnemonics are a single letter which should be part of the menu item name, which allow users to traverse and activate menu items by typing keys when the menu is pulled down. In the Shell Command field of the Shell Commands dialog, the % character expands to the name (including directory path) of the file in the window. To include a % character in the command, use %%. The Menu Entry field can contain special characters for constructing hierarchical sub-menus, and for making items which appear only in certain language modes. The right angle bracket character ">" creates a sub-menu. The name of the item itself should be the last element of the path formed from successive sub-menu names joined with ">". Menu panes are called in to existence simply by naming them as part of a Menu Entry name. To put several items in the same sub-menu, repeat the same hierarchical sequence for each. For example, in the Macro Commands dialog, two items with menu entries: a>b>c and a>b>d would create a single sub menu under the macro menu called "a", which would contain a single sub-menu, b, holding the actual items, c and d: +---++---++---+ |a >||b >||c | +---++---+|d | +---+ To qualify a menu entry with a language mode, simply add an at-sign "@@" at the end of the menu command, followed (no space) by a language mode name. To make a menu item which appears in several language modes, append additional @@s and language mode names. For example, an item with the menu entry: Make C Prototypes@@C@@C++ would appear only in C and C++ language modes, and: Make Class Template@@C++ would appear only in C++ mode. Menu items with no qualification appear in all language modes. If a menu item is followed by the single language qualification "@@*", that item will appear only if there are no applicable language-specific items of the same name in the same submenu. For example, if you have the following three entries in the same menu: Make Prototypes@@C@@C++ Make Prototypes@@Java Make Prototypes@@* The first will be available when the language mode is C or C++, the second when the language mode is Java, and for all other language modes (including the "Plain" non-language mode). If the entry: Make Prototypes also exists, this will always appear, meaning that the menu will always have two "Make Prototypes" entries, whatever the language mode. 3>The NEdit Autoload Files At startup time, NEdit _automatically reads the preferences file `nedit.rc', the autoload macro file `autoload.nm', and the history data base `nedit.history'. The preferences file contains saved preferences (menu settings) in the format of an X resource file. The autoload macro file is a macro file containing macro commands and definitions that NEdit will execute at startup. (NEdit doesn't create this file automatically.) Moreover, NEdit saves a list of the recently opened files, which appear under the Open Previous menu, in the history data base. By default the location of these files is '$HOME/.nedit/'. A different directory can be given by letting the environment variable NEDIT_HOME point to it. Notice that NEdit still supports the older names for these files, which are `$HOME/.nedit', `$HOME/.neditmacro', and `$HOME/.neditdb', respectively. This old naming scheme will be used if NEdit detects that `$HOME/.nedit' is a regular file and NEDIT_HOME isn't set. (For VMS, the location of these files is '$NEDIT_HOME/' if NEDIT_HOME is set, and 'SYS$LOGIN:' otherwise.) The contents of the preferences file can be moved into another X resource file (see X_Resources_). One reason for doing so would be to attach server specific preferences, such as a default font, to a particular X server. Another reason for moving preferences into an X resource file would be to keep preferences menu options and X resource settable options together in one place. Though the files are the same format, additional resources should not be added to the preferences file, since NEdit modifies that file by overwriting it completely. Note also that the contents of the preferences file takes precedence over the values in an X resource file. Using Save Defaults after moving the contents of your preferences file to your .Xdefaults file will re-create the preferences file, interfering with the options that you have moved. 3>Sharing Customizations with Other NEdit Users If you have written macro or shell menu commands, highlight patterns, or smart-indent macros that you want to share with other NEdit users, you can make a file which they can load into their NEdit environment. To load such a file, start NEdit with the command: nedit -import In the new NEdit session, verify that the imported patterns or macros do what you want, then select Preferences -> Save Defaults. Saving incorporates the changes into the NEdit preferences file, so the next time you run NEdit, you will not have to import the distribution file. Loading a customization file is automated, but creating one is not. To produce a file to be imported by other users, you must make a copy of your own preferences file, and edit it, by hand, to remove everything but the few items of interest to the recipient. Leave only the individual resource(s), and within those resources, only the particular macro, pattern, style, etc, that you wish to exchange. For example, to share a highlighting pattern set, you would include the patterns, any new styles you added, and language mode information only if the patterns are intended to support a new language rather than updating an existing one. For example: nedit.highlightPatterns:\ My Language:1:0{\n\ Comment:"#":"$"::Comment::\n\ Loop Header:"^[ \\t]*loop:":::Loop::\n\ } nedit.languageModes: My Language:.my:::::: nedit.styles: Loop:blue:Bold Resources are in the format of X resource files, but the format of text within multiple-item resources like highlight patterns, language modes, macros, styles, etc., are private to NEdit. Each resource is a string which ends at the first newline character not escaped with \, so you must be careful about how you treat ends of lines. While you can generally just cut and paste indented sections, if something which was originally in the middle of a resource string is now at the end, you must remove the \ line continuation character(s) so it will not join the next line into the resource. Conversely, if something which was originally at the end of a resource is now in the middle, you'll have to add continuation character(s) to make sure that the resource string is properly continued from beginning to end, and possibly newline character(s) (\n) to make sure that it is properly separated from the next item. ---------------------------------------------------------------------- X Resources ----------- NEdit has additional options to those provided in the Preferences menu which are set using X resources. Like most other X programs, NEdit can be customized to vastly unnecessary proportions, from initial window positions down to the font and shadow colors of each individual button (A complete discussion of how to do this is left to books on the X Window System). Key binding (see "Key_Binding_" is one of the most useful of these resource settable options. X resources are usually specified in a file called .Xdefaults or .Xresources in your home directory (on VMS this is sys$login:decw$xdefaults.dat). On some systems, this file is read and its information attached to the X server (your screen) when you start X. On other systems, the .Xdefaults file is read each time you run an X program. When X resource values are attached to the X server, changes to the resource file are not available to application programs until you either run the xrdb program with the appropriate file as input, or re-start the X server. 3>Selected X Resource Names The following are selected NEdit resource names and default values for NEdit options not settable via the Preferences menu (for preference resource names, see your NEdit preference file): **nedit.tagFile**: (not defined) This can be the name of a file, or multiple files separated by a colon (:) character, of the type produced by Exuberant Ctags or the Unix ctags command, which NEdit will load at startup time (see ctags_support_). The tag file provides a database from which NEdit can automatically open files containing the definition of a particular subroutine or data type. **nedit.alwaysCheckRelativeTagsSpecs: True** When this resource is set to True, and there are tag files specified (with the nedit.tagFile resource, see above) as relative paths, NEdit will evaluate these tag value paths whenever a file is opened. All accessible tag files will be loaded at this time. When this resource value is False, relative path tag specifications will only be evaluated at NEdit startup time. **nedit.wordDelimiters**: .,/\\`'!@@#%^&*()-=+{}[]":;<>? The set of characters which mark the boundaries between words. In addition to these, spaces, tabs, and newlines are always word boundaries. These boundaries take effect for the move-by-word (Ctrl+Arrow) and select-word (double click) commands, and for doing regex searches using the \B, < and > tokens. Note that this default value may be overridden by the setting in Preferences -> Default Settings -> Language Modes.... **nedit.remapDeleteKey**: False Setting this resource to True forcibly maps the delete key to backspace. This can be helpful on systems where the bindings have become tangled, and in environments which mix systems with PC style keyboards and systems with DEC and Macintosh keyboards. Theoretically, these bindings should be made using the standard X/Motif mechanisms, outside of NEdit. In practice, some environments where users access several different systems remotely, can be very hard to configure. If you've given up and are using a backspace key halfway off the keyboard because you can't figure out the bindings, set this to True. **nedit.typingHidesPointer**: False Setting this resource to True causes the mouse pointer to be hidden when you type in the text area. As soon as the mouse pointer is moved, it will reappear. This is useful to stop the mouse pointer from obscuring text. **nedit.overrideDefaultVirtualKeyBindings**: Auto Motif uses a virtual key binding mechanism that shares the bindings between different Motif applications. When a first Motif application is started, it installs some default virtual key bindings and any other Motif application that runs afterwards, simply reuses them. Obviously, if the first application installs an invalid set, all others applications may have problems. In the past, NEdit has been the victim of invalid bindings installed by other applications several times. Through this resource, NEdit can be instructed to ignore the bindings installed by other applications, and use its own private bindings. By default, NEdit tries to detect invalid bindings and ignore them automatically (Auto). Optionally, NEdit can be told to always keep the installed bindings (Never), or to always override them (Always). **nedit.stdOpenDialog**: False Setting this resource to True restores the standard Motif style of Open dialog. NEdit file open dialogs are missing a text field at the bottom of the dialog, where the file name can be entered as a string. The field is removed in NEdit to encourage users to type file names in the list, a non-standard, but much faster method for finding files. **nedit.bgMenuButton**: @~Shift@~Ctrl@~Meta@~Alt Specification for mouse button / key combination to post the background menu (in the form of an X translation table event specification). The event specification should be as specific as possible, since it will override less specific translation table entries. **nedit.maxPrevOpenFiles**: 30 Number of files listed in the Open Previous sub-menu of the File menu. Setting this to zero disables the Open Previous menu item and maintenance of the NEdit file history file. **nedit.printCommand**: (system specific) Command used by the print dialog to print a file, such as, lp, lpr, etc.. The command must be capable of accepting input via stdin (standard input). **nedit.printCopiesOption**: (system specific) Option name used to specify multiple copies to the print command. If the option should be separated from its argument by a space, leave a trailing space. If blank, no "Number of Copies" item will appear in the print dialog. **nedit.printQueueOption**: (system specific) Option name used to specify a print queue to the print command. If the option should be separated from its argument by a space, leave a trailing space. If blank, no "Queue" item will appear in the print dialog. **nedit.printNameOption**: (system specific) Option name used to specify a job name to the print command. If the option should be separated from its argument by a space, leave a trailing space. If blank, no job or file name will be attached to the print job or banner page. **nedit.printHostOption**: (system specific) Option name used to specify a host name to the print command. If the option should be separated from its argument by a space, leave a trailing space. If blank, no "Host" item will appear in the print dialog. **nedit.printDefaultQueue**: (system specific) The name of the default print queue. Used only to display in the print dialog, and has no effect on printing. **nedit.printDefaultHost**: (system specific) The node name of the default print host. Used only to display in the print dialog, and has no effect on printing. **nedit.visualID**: Best If your screen supports multiple visuals (color mapping models), this resource allows you to manually choose among them. The default value of "Best" chooses the deepest (most colors) visual available. Since NEdit does not depend on the specific characteristics of any given color model, Best probably IS the best choice for everyone, and the only reason for setting this resource would be to patch around some kind of X server problem. The resource may also be set to "Default", which chooses the screen's default visual (often a color-mapped, PseudoColor, visual for compatibility with older X applications). It may also be set to a numeric visual-id value (use xdpyinfo to see the list of visuals supported by your display), or a visual class name: PseudoColor, DirectColor, TrueColor, etc.. If you are running under a themed environment (like KDE or CDE) that places its colors in a shallow visual, and you'd rather have that color scheme instead of more colors available, then you may need set the visual to "Default" so that NEdit doesn't choose one with more colors. (The reason for this is: if the "best" visual is not the server's default, then NEdit cannot use the colors provided by your environment. NEdit will fall back to its own default color scheme.) **nedit.installColormap**: False Force the installation of a private colormap. If you have a humble 8-bit color display, and netscape is hogging all of the color cells, you may want to try turning this on. On most systems, this will result in colors flashing wildly when you switch between NEdit and other applications. But a few systems (SGI) have hardware support for multiple simultaneous colormaps, and applications with installed colormaps are well behaved. **nedit.findReplaceUsesSelection**: False Controls if the Find and Replace dialogs are automatically loaded with the contents of the primary selection. **nedit.stickyCaseSenseButton**: True Controls if the "Case Sensitive" buttons in the Find and Replace dialogs and the incremental search bar maintain a separate state for literal and regular expression searches. Moreover, when set to True, by default literal searches are case insensitive and regular expression searches are case sensitive. When set to False, the "Case Sensitive" buttons are independent of the "Regular Expression" toggle. **nedit.multiClickTime**: (system specific) Maximum time in milliseconds allowed between mouse clicks within double and triple click actions. **nedit.undoModifiesSelection**: True By default, NEdit selects any text inserted or changed through a undo/redo action. Set this resource to False if you don't want your selection to be touched. **nedit@*scrollBarPlacement**: BOTTOM_RIGHT How scroll bars are placed in NEdit windows, as well as various lists and text fields in the program. Other choices are: BOTTOM_LEFT, TOP_LEFT, or TOP_RIGHT. **nedit@*text.autoWrapPastedText**: False When Auto Newline Wrap is turned on, apply automatic wrapping (which normally only applies to typed text) to pasted text as well. **nedit@*text.heavyCursor**: False For monitors with poor resolution or users who have difficulty seeing the cursor, makes the cursor in the text editing area of the window heavier and darker. **nedit.autoScrollVPadding**: 4 Number of lines to keep the cursor away from the top or bottom line of the window when the "Auto-Scroll Near Window Top/Bottom" feature is enabled. Keyboard operations that would cause the cursor to get closer than this distance cause the window to scroll up or down instead, except at the beginning of the file. Mouse operations are not affected. **nedit@*text.blinkRate**: 500 Blink rate of the text insertion cursor in milliseconds. Set to zero to stop blinking. **nedit@*text.Translations**: Modifies key bindings (see "Key_Binding_"). **nedit@*foreground**: black Default foreground color for menus, dialogs, scroll bars, etc.. **nedit@*background**: #b3b3b3 Default background color for menus, dialogs, scroll bars, etc.. **nedit@*calltipForeground**: black Foreground color for calltips **nedit@*calltipBackground**: LemonChiffon1 Background color for calltips **nedit@*XmLFolder.inactiveForeground**: #666 Foreground color for inactive tabs. **nedit@*fontList**: helvetica medium 12 points Default font for menus, dialogs, scroll bars, etc.. **nedit.helpFont**: helvetica medium 12 points Font used for displaying online help. **nedit.boldHelpFont**: helvetica bold 12 points Bold font for online help. **nedit.italicHelpFont**: helvetica italic 12 points Italic font for online help. **nedit.fixedHelpFont**: courier medium 12 points Fixed font for online help. **nedit.boldFixedHelpFont**: courier bold 12 points Fixed bold for online help. **nedit.italicFixedHelpFont**: courier italic 12 points Fixed italic font for online help. **nedit.h1HelpFont**: helvetica bold 14 points Font for level-1 titles in help text. **nedit.h2HelpFont**: helvetica bold italic 12 points Font for level-2 titles in help text. **nedit.h3HelpFont**: courier bold 12 points Font for level-3 titles in help text. **nedit.helpLinkFont**: helvetica medium 12 points Font for hyperlinks in the help text **nedit.helpLinkColor**: #009900 Color for hyperlinks in the help text **nedit.backlightCharTypes**: 0-8,10-31,127:red;9:#dedede;32,160-255:#f0f0f0;128-159:orange **NOTE: backlighting is ~experimental~** (see "Programming_with_NEdit_"). A string specifying character classes as ranges of ASCII values followed by the color to be used as their background colors. The format is: low[-high]{,low[-high]}:color{;low-high{,low[-high]}:color} where low and high are ASCII values. For example: 32-255:#f0f0f0;1-31,127:red;128-159:orange;9-13:#e5e5e5 .. DISABLED for 5.4 .. The macro built-in function set_backlight_string() allows these strings to be .. set for a particular window. **nedit.focusOnRaise**: False This resource determines whether new text windows and text windows that are raised, should also request the input focus. Conventionally, it is the task of the window manager to decide on which window gets the input focus. Therefore, NEdit's default behaviour is not to request the input focus explicitly. **nedit.forceOSConversion**: True By default, NEdit converts texts in DOS or Mac format to an internal format using simple newlines as line dividers. This is sometimes not wanted by the user and can be prevented by setting this resource to False. Note: Setting this to False would supress newlines in Mac files entirely, leaving the control character where every line feed would be. Mac OS X uses Unix files and is not affected. Note: Setting this to False while the option 'Terminate with Line Break on Save' is active could lead to file corruption. **nedit.truncSubstitution**: Fail NEdit has a fixed limit on substitution result string length. This resource modifies the behaviour if this limit is exceeded. Possible values are ~Silent~ (will silently fail the operation), ~Fail~ (will fail the operation and pop up a dialog informing the user), ~Warn~ (pops up a dialog warning the user, offering to cancel the operation) and ~Ignore~ (will silently conclude the operation). **WARNING**: Setting this to 'Ignore' will destroy data without warning! **nedit.honorSymlinks**: True If set to True, NEdit will open a requested file on disk even if it is a symlink pointing to a file already opened in another window. If set to false, NEdit will try to detect these cases and just pop up the already opened document. **nc.autoStart**: True Whether the nc program should automatically start an NEdit server (without prompting the user) if an appropriate server is not found. **nc.serverCommand**: nedit -server Command used by the nc program to start an NEdit server. **nc.timeOut**: 10 Basic time-out period used in communication with an NEdit server (seconds). ---------------------------------------------------------------------- ~The following are Selected widget names (to which you may append~ ~.background, .foreground, .fontList, etc., to change colors, fonts~ ~ and other characteristics):~ **nedit@*statsAreaForm** Statistics line and incremental search bar. To get consistent results across the entire stats line and the incremental search bar, use '*' rather than '.' to separate the resource name. For example, to set the foreground color of both components use: nedit*statsAreaForm*foreground instead of: nedit*statsAreaForm.foreground **nedit@*menuBar** Top-of-window menu-bar. **nedit@*textHorScrollBar** Horizontal scroll bar. **nedit@*textVertScrollBar** Vertical scroll bar. ---------------------------------------------------------------------- Key Binding ----------- There are several ways to change key bindings in NEdit. The easiest way to add a new key binding in NEdit is to define a macro in Preferences -> Default Settings -> Customize Menus -> Macro Menu. However, if you want to change existing bindings or add a significant number of new key bindings you will need to do so via X resources. Before reading this section, you must understand how to set X resources (see the help section "X_Resources_"). Since setting X resources is tricky, it is also helpful when working on key-binding, to set some easier-to-verify resource at the same time, as a simple check that the NEdit program is actually seeing your changes. The appres program is also very helpful in checking that the resource settings that you make, actually reach the program for which they are intended in the correct form. 3>Key Binding in General Keyboard commands are associated with editor action routines through two separate mechanisms in NEdit. Commands which appear in pull-down menus have individual resources designating a keyboard equivalent to the menu command, called an accelerator key. Commands which do not have an associated menu item are bound to keys via the X toolkit translation mechanism. The methods for changing these two kinds of bindings are quite different. 3>Key Binding Via Translations The most general way to bind actions to keys in NEdit is to use the translation table associated with the text widget. To add a binding to Alt+Y to insert the string "Hi!", for example, add lines similar to the following to your X resource file: NEdit*text.Translations: #override \n\ Alty: insert_string("Hi!") \n The Help topic "Action_Routines_" lists the actions available to be bound. Translation tables map key and mouse presses, window operations, and other kinds of events, to actions. The syntax for translation tables is simplified here, so you may need to refer to a book on the X window system for more detailed information. Note that accelerator resources (discussed below) override translations, and that most Ctrl+letter and Alt+letter combinations are already bound to an accelerator key. To use one of these combinations from a translation table, therefore, you must first un-bind the original menu accelerator. A resource for changing a translation table consists of a keyword; #override, #augment, or #replace; followed by lines (separated by newline characters) pairing events with actions. Events begin with modifiers, like Ctrl, Shift, or Alt, followed by the event type in <>. BtnDown, Btn1Down, Btn2Down, Btn1Up, Key, KeyUp are valid event types. For key presses, the event type is followed by the name of the key. You can specify a combination of events, such as a sequence of key presses, by separating them with commas. The other half of the event/action pair is a set of actions. These are separated from the event specification by a colon and from each other by spaces. Actions are names followed by parentheses, optionally containing one or more parameters separated by comas. 3>Changing Menu Accelerator Keys The menu shortcut keys shown at the right of NEdit menu items can also be changed via X resources. Each menu item has two resources associated with it, accelerator, the event to trigger the menu item; and acceleratorText, the string shown in the menu. The form of the accelerator resource is the same as events for translation table entries discussed above, though multiple keys and other subtleties are not allowed. The resource name for a menu is the title in lower case, followed by "Menu", the resource name of menu item is the name in lower case, run together, with words separated by caps, and all punctuation removed. For example, to change Cut to Ctrl+X, you would add the following to your .Xdefaults file: nedit*editMenu.cut.accelerator: Ctrlx nedit*editMenu.cut.acceleratorText: Ctrl+X Accelerator keys with optional shift key modifiers, like Find..., have an additional accelerator resource with Shift appended to the name. For example: nedit*searchMenu.find.acceleratorText: [Shift]Alt+F nedit*searchMenu.find.accelerator: Altf nedit*searchMenu.findShift.accelerator: Shift Altf ---------------------------------------------------------------------- Highlighting Patterns --------------------- 3>Writing Syntax Highlighting Patterns Patterns are the mechanism by which language syntax highlighting is implemented in NEdit (see Syntax_Highlighting_ under the heading of Features for Programming). To create syntax highlighting patterns for a new language, or to modify existing patterns, select "Recognition Patterns" from "Syntax Highlighting" sub-section of the "Default Settings" sub-menu of the "Preferences" menu. First, a word of caution. As with regular expression matching in general, it is quite possible to write patterns which are so inefficient that they essentially lock up the editor as they recursively re-examine the entire contents of the file thousands of times. With the multiplicity of patterns, the possibility of a lock-up is significantly increased in syntax highlighting. When working on highlighting patterns, be sure to save your work frequently. NEdit's syntax highlighting is unusual in that it works in real-time (as you type), and yet is completely programmable using standard regular expression notation. Other syntax highlighting editors usually fall either into the category of fully programmable but unable to keep up in real-time, or real-time but limited programmability. The additional burden that NEdit places on pattern writers in order to achieve this speed/flexibility mix, is to force them to state self-imposed limitations on the amount of context that patterns may examine when re-parsing after a change. While the "Pattern Context Requirements" heading is near the end of this section, it is not optional, and must be understood before making any serious effort at pattern writing. In its simplest form, a highlight pattern consists of a regular expression to match, along with a style representing the font an color for displaying any text which matches that expression. To bold the word, "highlight", wherever it appears the text, the regular expression simply would be the word "highlight". The style (selected from the menu under the heading of "Highlight Style") determines how the text will be drawn. To bold the text, either select an existing style, such as "Keyword", which bolds text, or create a new style and select it under Highlight Style. The full range of regular expression capabilities can be applied in such a pattern, with the single caveat that the expression must conclusively match or not match, within the pre-defined context distance (as discussed below under Pattern Context Requirements). To match longer ranges of text, particularly any constructs which exceed the requested context, you must use a pattern which highlights text between a starting and ending regular expression match. To do so, select "Highlight text between starting and ending REs" under "Matching", and enter both a starting and ending regular expression. For example, to highlight everything between double quotes, you would enter a double quote character in both the starting and ending regular expression fields. Patterns with both a beginning and ending expression span all characters between the two expressions, including newlines. Again, the limitation for automatic parsing to operate properly is that both expressions must match within the context distance stated for the pattern set. With the ability to span large distances, comes the responsibility to recover when things go wrong. Remember that syntax highlighting is called upon to parse incorrect or incomplete syntax as often as correct syntax. To stop a pattern short of matching its end expression, you can specify an error expression, which stops the pattern from gobbling up more than it should. For example, if the text between double quotes shouldn't contain newlines, the error expression might be "$". As with both starting and ending expressions, error expressions must also match within the requested context distance. 4>Coloring Sub-Expressions It is also possible to color areas of text within a regular expression match. A pattern of this type associates a style with sub-expressions references of the parent pattern (as used in regular expression substitution patterns, see the NEdit Help menu item on Regular_Expressions_). Sub-expressions of both the starting and ending patterns may be colored. For example, if the parent pattern has a starting expression "\<", and end expression "\>", (for highlighting all of the text contained within angle brackets), a sub-pattern using "&" in both the starting and ending expression fields could color the brackets differently from the intervening text. A quick shortcut to typing in pattern names in the Parent Pattern field is to use the middle mouse button to drag them from the Patterns list. In some cases, there can be interference between coloring sub-patterns and hierarchical sub-patterns (discussed next). How this is resolved, is explained below. 4>Hierarchical Patterns A hierarchical sub-pattern, is identical to a top level pattern, but is invoked only between the starting and ending expression matches of its parent pattern or, in case the parent pattern consists of a single expression, inside the text area matching that expression. Like the sub-expression coloring patterns discussed above, it is associated with a parent pattern using the Parent Pattern field in the pattern specification. Pattern names can be dragged from the pattern list with the middle mouse button to the Parent Pattern field. The matching behaviour for sub-patterns is slightly different, depending on whether the parent pattern consists of a single expression or has both a starting and an ending expression. In case the parent pattern consists of a single expression, and the syntax highlighting parser finds a match for that expression, sub-patterns are matched between the start and the end of the parent match. Sub-patterns cannot extend beyond the boundaries of the parent's match nor can they affect those boundaries (the latter can happen for starting/ending parent patterns, see below). Note that sub-patterns can ~peek~ beyond the parent's matching boundaries by means of look-ahead or look-behind expressions. In case the parent pattern is a starting/ending style pattern, after the start expression of the parent pattern matches, the syntax highlighting parser searches for either the parent's end pattern or a matching sub-pattern. When a sub-pattern matches, control is not returned to the parent pattern until the entire sub-pattern has been parsed, regardless of whether the parent's end pattern appears in the text matched by the sub-pattern. In this way, matching of the parent's ending pattern can be postponed, in contrast to the case where the parent pattern consists of a single expression. Note that, in this case, parsing of sub-patterns starts **after** the match of the parent pattern's starting expression, also in contrast to the single-expression case. The most common use for this capability is for coloring sub-structure of language constructs (smaller patterns embedded in larger patterns). Hierarchical patterns can also simplify parsing by having sub-patterns "hide" special syntax from parent patterns, such as special escape sequences or internal comments. There is no depth limit in nesting hierarchical sub-patterns, but beyond the third level of nesting, automatic re-parsing will sometimes have to re-parse more than the requested context distance to guarantee a correct parse (which can slow down the maximum rate at which the user can type if large sections of text are matched only by deeply nested patterns). While this is obviously not a complete hierarchical language parser it is still useful in many text coloring situations. As a pattern writer, your goal is not to completely cover the language syntax, but to generate colorings that are useful to the programmer. Simpler patterns are usually more efficient and also more robust when applied to incorrect code. Note that in case of a single-expression parent pattern, there is a potential for conflicts between coloring-only sub-patterns and hierarchical sub-patterns (which cannot happen for starting/ending type of patterns, because sub-patterns are matched **between** the starting and ending pattern (not included)). Due to the different nature of these two kinds of sub-patterns, it is technically infeasible to follow the standard matching precedence rules, where a sub-pattern has precedence over the sub-patterns following it. Instead, coloring-only sub-patterns are always colored last, ie., they may override the coloring for overlapping sibling sub-patterns in the overlapping parts of the matches. 4>Deferred (Pass-2) Parsing NEdit does pattern matching for syntax highlighting in two passes. The first pass is applied to the entire file when syntax highlighting is first turned on, and to new ranges of text when they are initially read or pasted in. The second pass is applied only as needed when text is exposed (scrolled in to view). If you have a particularly complex set of patterns, and parsing is beginning to add a noticeable delay to opening files or operations which change large regions of text, you can defer some of that parsing from startup time, to when it is actually needed for viewing the text. Deferred parsing can only be used with single expression patterns, or begin/end patterns which match entirely within the requested context distance. To defer the parsing of a pattern to when the text is exposed, click on the Pass-2 pattern type button in the highlight patterns dialog. Sometimes a pattern can't be deferred, not because of context requirements, but because it must run concurrently with pass-1 (non-deferred) patterns. If they didn't run concurrently, a pass-1 pattern might incorrectly match some of the characters which would normally be hidden inside of a sequence matched by the deferred pattern. For example, C has character constants enclosed in single quotes. These typically do not cross line boundaries, meaning they can be parsed entirely within the context distance of the C pattern set and should be good candidates for deferred parsing. However, they can't be deferred because they can contain sequences of characters which can trigger pass-one patterns. Specifically, the sequence, '\"', contains a double quote character, which would be matched by the string pattern and interpreted as introducing a string. 4>Pattern Context Requirements The context requirements of a pattern set state how much additional text around any change must be examined to guarantee that the patterns will match what they are intended to match. Context requirements are a promise by NEdit to the pattern writer, that the regular expressions in his/her patterns will be matched against at least lines and characters, around any modified text. Combining line and character requirements guarantee that both will be met. Automatic re-parsing happens on EVERY KEYSTROKE, so the amount of context which must be examined is very critical to typing efficiency. The more complicated your patterns, the more critical the context becomes. To cover all of the keywords in a typical language, without affecting the maximum rate at which users can enter text, you may be limited to just a few lines and/or a few hundred characters of context. The default context distance is 1 line, with no minimum character requirement. There are several benefits to sticking with this default. One is simply that it is easy to understand and to comply with. Regular expression notation is designed around single line matching. To span lines in a regular expression, you must explicitly mention the newline character "\n", and matches which are restricted to a single line are virtually immune to lock-ups. Also, if you can code your patterns to work within a single line of context, without an additional character-range context requirement, the parser can take advantage the fact that patterns don't cross line boundaries, and nearly double its efficiency over a one-line and 1-character context requirement. (In a single line context, you are allowed to match newlines, but only as the first and/or last character.) ---------------------------------------------------------------------- Smart Indent Macros ------------------- Smart indent macros can be written for any language, but are usually more difficult to write than highlighting patterns. A good place to start, of course, is to look at the existing macros for C and C++. Smart indent macros for a language mode consist of standard NEdit macro language code attached to any or all of the following three activation conditions: 1) When smart indent is first turned on for a text window containing code of the language, 2) When a newline is typed and smart indent is expected, 3) after any character is typed. To attach macro code to any of these code "hooks", enter it in the appropriate section in the Preferences -> Default Settings -> Auto Indent -> Program Smart Indent dialog. Typically most of the code should go in the initialization section, because that is the appropriate place for subroutine definitions, and smart indent macros are complicated enough that you are not likely to want to write them as one monolithic run of code. You may also put code in the Common/Shared Initialization section (accessible through the button in the upper left corner of the dialog). Unfortunately, since the C/C++ macros also reside in the common/shared section, when you add code there, you run some risk of missing out on future upgrades to these macros, because your changes will override the built-in defaults. The newline macro is invoked after the user types a newline, but before the newline is entered in the buffer. It takes a single argument ($1) which is the position at which the newline will be inserted. It must return the number of characters of indentation the line should have, or -1. A return value of -1 means to do a standard auto-indent. You must supply a newline macro, but the code: "return -1" (auto-indent), or "return 0" (no indent) is sufficient. The type-in macro takes two arguments. $1 is the insert position, and $2 is the character just typed, and does not return a value. It also is invoked before the character is inserted into the buffer. You can do just about anything here, but keep in mind that this macro is executed for every keystroke typed, so if you try to get too fancy, you may degrade performance. ---------------------------------------------------------------------- NEdit Command Line ------------------ .. ? help !!#ifndef VMS **nedit** [-**read**] [-**create**] [-**line** n | +n] [-**server**] [-**do** command] [-**tags** file] [-**tabs** n] [-**wrap**] [-**nowrap**] [-**autowrap**] [-**autoindent**] [-**noautoindent**] [-**autosave**] [-**noautosave**] [-**rows** n] [-**columns** n] [-**font** font] [-**lm** languagemode] [-**geometry** geometry] [-**iconic**] [-**noiconic**] [-**display** [host]:server[.screen] [-**xrm** resourcestring] [-**svrname** name] [-**import** file] [-**background** color] [-**foreground** color] [-**h**|-**help**] [-**tabbed**] [-**untabbed**] [-**group**] [-**V**|-**version**] [--] [file...] **-read** Open the file Read Only regardless of the actual file protection. **-create** Don't warn about file creation when a file doesn't exist. **-line n (or +n)** Go to line number n **-server** Designate this session as an NEdit server, for processing commands from the nc program. nc can be used to interface NEdit to code development environments, mailers, etc., or just as a quick way to open files from the shell command line without starting a new NEdit session. **-do command** Execute an NEdit macro or action on the file following the -do argument on the command line. -do is particularly useful from the nc program, where nc -do can remotely execute commands in an NEdit -server session. **-tags file** Load a file of directions for finding definitions of program subroutines and data objects. The file must be of the format generated by Exuberant Ctags, or the standard Unix ctags command. **-tabs n** Set tab stops every n characters. **-wrap, -nowrap** Wrap long lines at the right edge of the window rather than continuing them past it. (Continuous Wrap mode) **-autowrap, -noautowrap** Wrap long lines when the cursor reaches the right edge of the window by inserting newlines at word boundaries. (Auto Newline Wrap mode) **-autoindent, -noautoindent** Maintain a running indent. **-autosave, -noautosave** Maintain a backup copy of the file being edited under the name '~filename'. **-rows n** Default height in characters for an editing window. **-columns n** Default width in characters for an editing window. **-font font (or -fn font)** Font for text being edited (Font for menus and dialogs can be set with -xrm "*fontList:font"). **-lm languagemode** Initial language mode used for editing succeeding files. **-geometry geometry (or -g geometry)** The initial size and/or location of editor windows. The argument geometry has the form: [x][+|-][[+|-]] where and are the desired width and height of the window, and and are the distance from the edge of the screen to the window, + for top or left, - for bottom or right. -geometry can be specified for individual files on the command line. **-iconic, -noiconic** Initial window state for succeeding files. **-display [host]:server[.screen]** The name of the X server to use. host specifies the machine, server specifies the display server number, and screen specifies the screen number. host or screen can be omitted and default to the local machine, and screen 0. **-background color (or -bg color)** User interface background color. (Background color for text can be set separately with -xrm "nedit.textBgColor: color" or using the Preferences -> Colors dialog). **-foreground color (or -fg color)** User interface foreground color. (Foreground color for text can be set separately with -xrm "nedit.textFgColor: color" or using the Preferences -> Colors dialog). **-tabbed** Open all subsequent files in new tabs. Resets -group option. **-untabbed** Open all subsequent files in new windows. Resets -group option. Note that this only works on subsequent files in this command and does not put NEdit in tab-less mode; for that you can use the command nedit -xrm "nedit.openInTab: False" -xrm "nedit.tabBarHideOne: True" This will affect your default settings for the session, and will be saved if Preferences->Save Defaults... is used, which may not be desired. **-group** Open all subsequent files as tabs in a new window. **-xrm resourcestring** Set the value of an X resource to override a default value (see "Customizing_NEdit_"). **-svrname name** When starting NEdit in server mode, name the server, such that it responds to requests only when nc is given a corresponding -svrname argument. By naming servers, you can run several simultaneously, and direct files and commands specifically to any one. Specifying a non-empty name automatically designates this session as an NEdit server, as though -server were specified. **-import file** Loads an additional preferences file on top of the existing defaults saved in your preferences file. To incorporate macros, language modes, and highlight patterns and styles written by other users, run NEdit with -import , then re-save your preferences file with Preferences -> Save Defaults. **-version** Prints out the NEdit version information. The -V option is synonymous. **-help** Prints out the NEdit command line help. The -h option is synonymous. **--** Treats all subsequent arguments as file names, even if they start with a dash. This is so NEdit can access files that begin with the dash character. .. ? help~ !!#else .. .. This documentation for VMS NEdit usage should only appear in the .. generated help code, not in any of the printed documentation. .. Reasoning is that VMS usage is diminishing and there is a desire .. to not clutter up the printed documentation here. .. NEDIT [filespec[,...]] The following qualifiers are accepted: **/read** Open the file Read Only regardless of the actual file protection. **/create** Don't warn about file creation when a file doesn't exist. **/line=n** Go to line #n **/server** Designate this session as an NEdit server for processing commands from the nc program. The nc program can be used to interface NEdit to code development environments, mailers, etc., or just as a quick way to open files from the shell command line without starting a new NEdit session. **/do=command** Execute an NEdit action routine. on each file following the /do argument on the command line. /do is particularly useful from the nc program, where nc /do can remotely execute commands in an nedit /server session. **/tags=file** Load a file of directions for finding definitions of program subroutines and data objects. The file must be of the format generated by the Unix ctags command. **/wrap, /nowrap** Wrap long lines at the right edge of the window rather than continuing them past it. (Continuous Wrap mode) **/autowrap, /noautowrap** Wrap long lines when the cursor reaches the right edge of the window by inserting newlines at word boundaries. (Auto Newline Wrap mode) **/autoindent, /noautoindent** Maintain a running indent. **/autosave, /noautosave** Maintain a backup copy of the file being edited under the name '_filename'. **/rows=n** Default width in characters for an editing window. **/columns=n** Default height in characters for an editing window. **/font=font (or /fn=font)** Font for text being edited (Font for menus and dialogs can be set with /xrm="*fontList:font"). **/display [host]:server[.screen]** The name of the X server to use. host specifies the machine, server specifies the display server number, and screen specifies the screen number. host or screen can be omitted and default to the local machine, and screen 0. **/geometry=geometry (or /g=geometry)** The initial size and/or location of editor windows. The argument geometry has the form: [x][+|-][[+|-]] where and are the desired width and height of the window, and and are the distance from the edge of the screen to the window, + for top or left, - for bottom or right. **/background=color (or /bg=color)** Background color. (background color for text can be set separately with /xrm="nedit:textBgColor color" or using the Preferences -> Colors dialog). **/foreground=color (or /fg=color)** Foreground color. (foreground color for text can be set separately with /xrm="nedit:textFgColor color" or using the Preferences -> Colors dialog). **/tabbed** Open all subsequent files in new tabs. Resets /group option. **/untabbed** Open all subsequent files in new windows. Resets /group option. **/group** Open all subsequent files as tabs in a new window. **/xrm=resourcestring** Set the value of an X resource to override a default value (see Customizing NEdit). **/svrname=name** When starting nedit in server mode, name the server, such that it responds to requests only when nc is given a corresponding -svrname argument. By naming servers, you can run several simultaneously, and direct files and commands specifically to any one. **/import=file** Loads an additional preferences file on top of the existing defaults saved in your .nedit file. To incorporate macros, language modes, and highlight patterns and styles written by other users, run nedit with /import=, then re-save your .nedit file with Preferences -> Save Defaults. Unix-style command lines (but not file names) are also acceptable: nedit -rows 20 -wrap file1.c file2.c is equivalent to: nedit /rows=20/wrap file1.c, file2.c", !!#endif /* VMS */ .. ~ help ---------------------------------------------------------------------- Client/Server Mode ------------------ NEdit can be operated on its own, or as a two-part client/server application. Client/server mode is useful for integrating NEdit with software development environments, mailers, and other programs; or just as a quick way to open files from the shell command line without starting a new NEdit session. To run NEdit in server mode, type: nedit -server NEdit can also be started in server mode via the NEdit Client program (**nc**) when no servers are available. The nc program, which is distributed along with NEdit, sends commands to an NEdit server to open files or execute editor actions. It can also be used on files that are already opened. Listing a file on the nc command line means: Open it if it is not already open and bring the window to the front. nc supports the following command line options: **nc** [**-read**] [**-create**] [**-line** n | **+**n] [**-do** command] [**-lm** languagemode] [**-svrname** name] [**-svrcmd** command] [**-ask**] [**-noask**] [**-timeout** seconds] [**-geometry** geometry | **-g** geometry] [**-icon** | **-iconic**] [-**tabbed**] [-**untabbed**] [-**group**] [**-wait**] [**-V** | **-version**] [**-xrm** resourcestring] [**-display** [host]:server[.screen]] [**-**-] [file...] **-read** Open the file read-only regardless of its actual permissions. There is no effect if the file is already open. **-create** Don't warn about file creation when a file doesn't exist. **-line** n, **+**n Go to line number n. This will also affect files which are already open. **-do** command Execute an NEdit macro or action on the file following the -do argument on the command line. If you use this command without a filename, nc would randomly choose one window to focus and execute the macro in. **-lm** languagemode Initial language mode used. **-svrname** name Explicitly instructs nc which server to connect to, an instance of nedit(1) with a corresponding -svrname argument. By naming servers, you can run several simultaneously, and direct files and commands specifically to any one. **-svrcmd** command The command which nc uses to start an NEdit server. It is also settable via the X resource `nc.serverCommand' (see X_Resources_). Defaults to "nedit -server". **-ask**, **-noask** Instructs nc to automatically start a server if one is not available. This overrides the X resource `nc.autoStart' (see X_Resources_). **-timeout** seconds Basic time-out period used in communication with an NEdit server. The default is 10 seconds. Also settable via the X resource `nc.timeOut'. Under rare conditions (such as a slow connection), it may be necessary to increase the time-out period. In most cases, the default is fine. **-geometry** geometry, **-g** geometry The initial size and/or location of editor windows. See NEdit_Command_Line_ for details. **-icon**, **-iconic** Initial window state. **-tabbed** Open all subsequent files in new tabs. Resets -group option. **-untabbed** Open all subsequent files in new windows. Resets -group option. **-group** Open all subsequent files as tabs in a new window. **-wait** Instructs nc not to return to the shell until all files given are closed. Normally, nc returns once the files given in its command line are opened by the server. When this option is given, nc returns only after the last file given in this call is closed. Note that this option affects all files in the command line, not only the ones following this option. Note that nc will wait for all files given in the command line, even if the files were already opened. **-version**, **-V** Prints nc's version and build information. **-xrm** resourcestring Contains the resourcestring passed to a newly started server. This option has no effect if the server is already started. **-display** []:[.] The name of the X server to use. See NEdit_Command_Line_ for details. 4>Command Line Arguments In typical Unix style, arguments affect the files which follow them on the command line, for example: incorrect: nc file.c -line 25 correct: nc -line 25 file.c -read, -create, and -line affect all of the files which follow them on the command line. The -do macro is executed only once, on the next file on the line. -do without a file following it on the command line, executes the macro on the first available window (presumably when you give a -do command without a corresponding file or window, you intend it to do something independent of the window in which it happens to execute). The -wait option affects all files named in the command line. 4>Multiple Servers Sometimes it is useful to have more than one NEdit server running, for example to keep mail and programming work separate. The option, -svrname, to both nedit and nc, allows you to start, and communicate with, separate named servers. A named server responds only to requests with the corresponding -svrname argument. If you use ClearCase and are within a ClearCase view, the server name will default to the name of the view (based on the value of the CLEARCASE_ROOT environment variable). 4>Communication Communication between nc and nedit is done through the X display. So as long as the X Window System is set up and working properly, nc will work properly as well. nc uses the DISPLAY environment variable, the machine name and your user name to find the appropriate server, meaning, if you have several machines sharing a common file system, nc will not be able to find a server that is running on a machine with a different host name, even though it may be perfectly appropriate for editing a given file. The command which nc uses to start an nedit server is settable via the X resource nc.serverCommand, by default, "nedit -server". ---------------------------------------------------------------------- Crash Recovery -------------- If a system crash, network failure, X server crash, or program error should happen while you are editing a file, you can still recover most of your work. NEdit maintains a backup file which it updates periodically (every 8 editing operations or 80 characters typed). This file has the same name as the file that you are editing, but with the character `~' (tilde) on Unix or `_' (underscore) on VMS prefixed to the name. To recover a file after a crash, simply rename the file to remove the tilde or underscore character, replacing the older version of the file. (Because several of the Unix shells consider the tilde to be a special character, you may have to prefix the character with a `\' (backslash) when you move or delete an NEdit backup file.) Example, to recover the file called "help.c" on Unix type the command: mv \~help.c help.c A minor caveat, is that if the file you were editing was in MS DOS format, the backup file will be in Unix format, and you will need to open the backup file in NEdit and change the file format back to MS DOS via the Save As... dialog (or use the Unix unix2dos command outside of NEdit). ---------------------------------------------------------------------- Version ------- .. ! help~ |>version<| |>date<| .. ~ help .. .. There is build time versioning information that is handled specially .. inside help.c for this section. It needs to have a '%s' string .. made available for it to appear in the on-line help. .. .. ? help %s .. .. ====================================================================== .. The policy for credit so far is this: .. .. You get "written by" credit if you have CVS commit privileges, and you .. participated in the current release. .. .. You will be "retired" once we realize you haven't been around for a .. while... please come back someday and be active again! .. .. The order is alphabetical, not political or time-ordered. The list .. of patch authors is too large to include here, and we probably won't .. get it right unless they are diligent about adding credits to the .. contributed files. .. .. You get a syntax/indent credit if your pattern is compiled into the .. binary. .. ====================================================================== Active developers: Tony Balinski, Arne Førlie, Nathaniel Gray, Eddy De Greef, Thorsten Haude, Andrew Hood, Scott Tringali, and TK Soh. Retired developers: Mark Edel, Joy Kyriakopulos, Christopher Conrad, Jim Clark, Arnulfo Zepeda-Navratil, Suresh Ravoor, Max Vohlken, Yunliang Yu, Donna Reid, Steve Haehn, Steve LoBasso, and Alexander Mai. The regular expression matching routines used in NEdit are adapted (with permission) from original code written by Henry Spencer at the University of Toronto. The Microline widgets are inherited from the Mozilla project. Syntax highlighting patterns and smart indent macros were contributed by: Simon T. MacDonald, Maurice Leysens, Matt Majka, Alfred Smeenk, Alain Fargues, Christopher Conrad, Scott Markinson, Konrad Bernloehr, Ivan Herman, Patrice Venant, Christian Denat, Philippe Couton, Max Vohlken, Markus Schwarzenberg, Himanshu Gohel, Steven C. Kapp, Michael Turomsha, John Fieber, Chris Ross, Nathaniel Gray, Joachim Lous, Mike Duigou, Seak Teng-Fong, Joor Loohuis, Mark Jones, and Niek van den Berg. NEdit sources, executables, additional documentation, and contributed software are available from the NEdit web site at http://www.nedit.org_. This program is free software; you can redistribute it and/or modify it under the terms of the GNU_General_Public_License_ as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. In addition, as a special exception to the GNU GPL, the copyright holders give permission to link the code of this program with the Motif and Open Motif libraries (or with modified versions of these that use the same license), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than linking with Motif/Open Motif. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the section on the GNU_General_Public_License_ for more details. ---------------------------------------------------------------------- GNU General Public License ------------------- GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. **NO WARRANTY** 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS ---------------------------------------------------------------------- Mailing Lists ------------- There are two separate mailing lists for nedit users, and one for developers. Users may post to the developer mailing list to report defects and communicate with the nedit developers. Remember that nedit is entirely a volunteer effort, so please ask questions first to the discussion list, and do your share to answer other users questions as well. discuss@@nedit.org_ General discussion, questions and answers among NEdit users and developers. announce@@nedit.org_ A low-volume mailing list for announcing new versions. develop@@nedit.org_ Communication among and with NEdit developers. Developers should also subscribe to the discuss list. To subscribe, send mail to one of the following addresses: announce-request@@nedit.org_ discuss-request@@nedit.org_ develop-request@@nedit.org_ with the body consisting of the single word subscribe ---------------------------------------------------------------------- Problems/Defects ---------------- 3>Solutions to Common Problems For a much more comprehensive list of common problems and solutions, see the NEdit FAQ. The latest version of the FAQ can always be found on the NEdit web site at: http://www.nedit.org_. **P: No files are shown in the "Files" list in the Open... dialog.** S: When you use the "Filter" field, include the file specification or a complete directory specification, including the trailing "/" on Unix. (See Help in the Open... dialog). **P: Find Again and Replace Again don't continue in the same direction as the original Find or Replace.** S: Find Again and Replace Again don't use the direction of the original search. The Shift key controls the direction: Ctrl+G means forward, Shift+Ctrl+G means backward. **P: Preferences specified in the Preferences menu don't seem to get saved when I select Save Defaults.** S: NEdit has two kinds of preferences: 1) per-window preferences, in the Preferences menu, and 2) default settings for preferences in newly created windows, in the Default Settings sub-menu of the Preferences menu. Per-window preferences are not saved by Save Defaults, only Default Settings. **P: Columns and indentation don't line up.** S: NEdit is using a proportional width font. Set the font to a fixed style (see Preferences menu). **P: NEdit performs poorly on very large files.** S: Turn off Incremental Backup. With Incremental Backup on, NEdit periodically writes a full copy of the file to disk. **P: Commands added to the Shell Commands menu (Unix only) don't output anything until they are finished executing.** S: If the command output is directed to a dialog, or the input is from a selection, output is collected together and held until the command completes. De-select both of the options and the output will be shown incrementally as the command executes. **P: Dialogs don't automatically get keyboard focus when they pop up.** S: Most X Window managers allow you to choose between two categories of keyboard focus models: pointer focus, and explicit focus. Pointer focus means that as you move the mouse around the screen, the window under the mouse automatically gets the keyboard focus. NEdit users who use this focus model should set "Popups Under Pointer" in the Default Settings sub menu of the preferences menu in NEdit. Users with the explicit focus model, in some cases, may have problems with certain dialogs, such as Find and Replace. In MWM this is caused by the mwm resource startupKeyFocus being set to False (generally a bad choice for explicit focus users). NCDwm users should use the focus model "click" instead of "explicit", again, unless you have set it that way to correct specific problems, this is the appropriate setting for most explicit focus users. **P: The Backspace key doesn't work, or deletes forward rather than backward.** S: While this is an X/Motif binding problem, and should be solved outside of NEdit in the Motif virtual binding layer (or possibly xmodmap or translations), NEdit provides an out. If you set the resource: nedit.remapDeleteKey to True, NEdit will forcibly map the delete key to backspace. The default setting of this resource recently changed, so users who have been depending on this remapping will now have to set it explicitly (or fix their bindings). **P: NEdit crashes when I try to paste text in to a text field in a dialog (like Find or Replace) on my SunOS system.** S: On many SunOS systems, you have to set up an nls directory before various inter-client communication features of Motif will function properly. There are instructions in README.sun in /pub/v5_0_2/individual/README.sun on ftp.nedit.org, as well as a tar file containing a complete nls directory: ftp://ftp.nedit.org/pub/v5_0_2/nls.tar. README.sun contains directions for setting up an nls directory, which is required by Motif for handling copy and paste to Motif text fields. 3>Known Defects Below is the list of known defects which affect NEdit. The defects your copy of NEdit will exhibit depend on which system you are running and with which Motif libraries it was built. Note that there are now Motif 1.2 and/or 2.0 libraries available on ALL supported platforms, and as you can see below there are far fewer defects in Motif 1.2, so it is in your best interest to upgrade your system. 4>All Versions **DEFECT** Operations between rectangular selections on overlapping lines do nothing. ~Work Around~ None. These operations are very complicated and rarely used. **DEFECT** Cut and Paste menu items fail, or possibly crash, for very large (multi-megabyte) selections. ~Work Around~ Use selection copy (middle mouse button click) for transferring larger quantities of data. Cut and Paste save the copied text in server memory, which is usually limited. 3>Reporting Defects Submit bugs through the web at: http://sf.net/tracker/?func=add&group_id=11005&atid=111005 Please include the first few lines from Help > Version, which identifies NEdit's version and other system attributes important for diagnosing your problem. The NEdit developers subscribe to both discuss@@nedit.org and develop@@nedit.org, either of which may be used for reporting defects. If you're not sure, or you think the report might be of interest to the general NEdit user community, send the report to discuss@@nedit.org_. If it's something obvious and boring, like we misspelled "anemometer" in the on-line help, send it to develop@@nedit.org_. If you don't want to subscribe to the Mailing_Lists_, please add a note to your mail about cc'ing you on responses. $$ .. Hyperlinks for this document ============================================== .. _discuss@@nedit.org mailto:discuss@@nedit.org .. _announce@@nedit.org mailto:announce@@nedit.org .. _develop@@nedit.org mailto:develop@@nedit.org .. _discuss-request@@nedit.org mailto:discuss-request@@nedit.org .. _announce-request@@nedit.org mailto:announce-request@@nedit.org .. _develop-request@@nedit.org mailto:develop-request@@nedit.org .. _http://www.nedit.org http://www.nedit.org .. _ctags_support #ctags .. _Alternation #alternation .. _Autoload_Files #automatically .. ============================================================================= .. Below is what is used to guide the generation of 'C'-Motif menus. .. Indentation is SIGNIFICANT in the "Menu" directive lines below. It .. is used to determine under which menu element another item will belong. .. The number of spaces indented is not significant, but items to be placed .. in the same menu panel MUST line up at the same indent level. .. ALL nodes of this menu "tree" should have help name qualifiers. .. These are used to produce the internal lists used by NEdit help code. .. By default, the first character of the menu element will be used as a .. menu mneumonic key. To use another character in the menu element for this .. purpose, surround the character with underscores (eg. I w_a_nt 'a'). .. The menu title MUST match the one found in the actual help text (sans .. special mneumonic key character marking). The help text title may include .. underlines (for spaces) when it is a hyperlink target. .. The Help-name is used to generate various data structure names. For .. instance, the 'start' help name will be used to generate the HelpTopic .. enumeration value HELP_START and the character array htxt_start which .. holds the actual help text used in the menu dialogs. Consequently, these .. names need to be unique and contain only the characters that a 'C' .. compiler can digest. .. Menu separator lines use a dash (-) character for the Menu Title. They .. should also have a unique Help-name. .. A numerical value following the Help-name (separated from the name by .. a comma and/or spaces) is part of a menu element hiding scheme implemented .. in buildHelpMenu (found in 'menu.c'). When the number matches the hideIt .. value found in the procedure, that element will effectively become invisible. .. This mechanism was created for particular menu features that are not .. available to all incarnations of NEdit (in this case, the VMS version). .. A "Help" directive is used for all other text used as NEdit help, but .. does not show up in the Help menu. .. Menu Title # Help-name .. ------------------------------------------------------------ .. Menu: Getting Started # start .. Menu: Basic Operation # basicOp .. Menu: Selecting Text # select .. Menu: Finding and Replacing Text # search .. Menu: Cut and Paste # clipboard .. Menu: Using the Mouse # mouse .. Menu: Keyboard Shortcuts # keyboard .. Menu: S_h_ifting and Filling # fill .. Menu: Tabbed Editing # interface .. Menu: F_i_le Format # format .. Menu: Features for Programming # features .. Menu: Programming with NEdit # programmer .. Menu: Tabs/Emulated Tabs # tabs .. Menu: Auto/Smart Indent # indent .. Menu: Syntax Highlighting # syntax .. Menu: Finding Declarations (ctags) # tags .. Menu: Calltips # calltips .. Menu: Regular Expressions # regex .. Menu: Basic Regular Expression Syntax # basicSyntax .. Menu: Metacharacters # escapeSequences .. Menu: Parenthetical Constructs # parenConstructs .. Menu: Advanced Topics # advancedTopics .. Menu: Example Regular Expressions # examples .. Menu: Macro/Shell Extensions # extensions .. Menu: Shell Commands and Filters # shell, 1 .. Menu: Learn/Replay # learn .. Menu: Macro Language # macro_lang .. Menu: M_a_cro Subroutines # macro_subrs .. Menu: Rangesets # rangeset .. Menu: Highlighting Information # hiliteInfo .. Menu: Action Routines # actions .. Menu: Customizing # customizing .. Menu: Customizing NEdit # customize .. Menu: Preferences # preferences .. Menu: X Resources # resources .. Menu: Key Binding # binding .. Menu: Highlighting Patterns # patterns .. Menu: Smart Indent Macros # smart_indent .. Menu: NEdit Command Line # command_line .. Menu: Client/Server Mode # server .. Menu: Cr_a_sh Recovery # recovery .. Menu: ---------------------------------- # separator1 .. Menu: Version # version .. Menu: GNU General Public License # distribution .. Menu: Mailing _L_ists # mailing_list .. Menu: Problems/Defects # defects .. ------------------------------------------------------------ .. Help: Tabs Dialog # tabs_dialog .. Help: Customize Window Title Dialog # custom_title_dialog nedit-5.6.orig/doc/nc.pod0000644000175000017500000001565410211622001013757 0ustar paulpaul# $Id: nc.pod,v 1.7 2005/03/03 14:49:37 edg Exp $ =pod =head1 NAME nc - Client program for NEdit text editor =head1 SYNOPSYS nc [B<-read>] [B<-create>] [B<-line> I | B<+>I] [B<-do> I] [B<-ask>] [B<-noask>] [B<-svrname> I] [B<-svrcmd> I] [B<-lm> I] [B<-geometry> I | B<-g> I] [B<-icon> | B<-iconic>] [B<-display> I<[host]:server[.screen]>] [B<-timeout> I] [B<-wait>] [B<-xrm> I] [B<-tabbed>] [B<-untabbed>] [B<-group>] [B<-V> | B<-version>] [B<-h> | B<-help>] [B<-->] [file...] =head1 DESCRIPTION B is the client interface to the NEdit text editor. A server can be started explicitly by running NEdit in server mode: nedit -server If no server is running, B will start one unless configured otherwise. Client/server mode is useful for integrating NEdit with software development environments, mailers, and other programs; or just as a quick way to open files from the shell command line without starting a new NEdit session. =head1 OPTIONS =over =item B<-read> Open the file read-only regardless of the actual file protection. =item B<-create> Don't warn about file creation when a file doesn't exist. =item B<-line> I, B<+>I Go to line number I. =item B<-do> I Execute an NEdit macro or action on the file following the -do argument on the command line. If you use this command without a filename, B would randomly choose one window to focus and execute the macro in. =item B<-ask>, B<-noask> Instructs B whether to automatically start a server if one is not available. This overrides the X resource `nc.autoStart'. =item B<-svrname> I Explicitly instructs B which server to connect to, an instance of L with a corresponding B<-svrname> argument. By naming servers, you can run several simultaneously, and direct files and commands specifically to any one. =item B<-svrcmd> I The command which B uses to start an NEdit server. It is also settable via the X resource `nc.serverCommand', by default, I<"nedit -server">. =item B<-lm> I Initial language mode used for editing succeeding files. =item B<-geometry> I, B<-g> I The initial size and/or location of editor windows. The argument geometry has the form: [x][+|-][[+|-]] where `' and `' are the desired width and height of the window, and `' and `' are the distance from the edge of the screen to the window, + for top or left, - for bottom or right. B<-geometry> can be specified for individual files on the command line. =item B<-icon>, B<-iconic> Initial window state for succeeding files. =item B<-display> I<[host]:server[.screen]> The name of the X server to use. host specifies the machine, server specifies the display server number, and screen specifies the screen number. host or screen can be omitted and default to the local machine, and screen 0. =item B<-timeout> I Basic time-out period (in seconds) used in communication with an NEdit server. Default: 10 seconds. Also settable via the X resource `nc.timeOut'. Under rare conditions (such as a slow connection), it may be necessary to increase the time-out period. In most cases, the default is fine. =item B<-wait> Instructs B not to return to the shell until all files given are closed. Normally, B returns once the files given in its command line are opened by the server. When this option is given, nc returns only after the last file given in this call is closed. Note that this option affects all files, not only the ones following this option in the command line. =item B<-xrm> I Set the value of an X resource to override a default value. =item B<-tabbed> Open all subsequent files in new tabs. Resets B<-group> option. =item B<-untabbed> Open all subsequent files in new windows. Resets B<-group> option. =item B<-group> Open all subsequent files as tabs in a new window. =item B<-V>, B<-version> Prints version and build information, to be mentioned when reporting bugs and problems. =item B<-h>, B<-help> Prints the command line help and then exits. =item B<--> Treats all subsequent arguments as file names, even if they start with a dash. This is so NEdit can access files that begin with the dash character. =back =head1 ENVIRONMENT =over =item DISPLAY NEdit requires an X-based workstation or X-Terminal. If you have used B or B to access the host Unix system, set the Unix environment variable for your display: % setenv DISPLAY devicename:0 =back =head1 NOTES Communication between L and L is through the X display. So as long as X windows is set up and working properly, B will work properly as well. B uses the `DISPLAY' environment variable, the machine name and your user name to find the appropriate server, meaning, if you have several machines sharing a common file system, B will not be able to find a server that is running on a machine with a different host name, even though it may be perfectly appropriate for editing a given file. In typical Unix style, arguments affect the files which follow them on the command line, for example: =over =item incorrect: nc file.c -line 25 =item correct: nc -line 25 file.c =back For more information see NEdit's online help, or I in the NEdit distribution kit. =head1 SEE ALSO nedit(1), X(1), mwm(1), ctags(1), etags(1) =head1 AUTHORS NEdit was written by Mark Edel, Joy Kyriakopulos, Christopher Conrad, Jim Clark, Arnulfo Zepeda-Navratil, Suresh Ravoor, Tony Balinski, Max Vohlken, Yunliang Yu, Donna Reid, Arne Forlie, Eddy De Greef, Steve LoBasso, Alexander Mai, Scott Tringali, Thorsten Haude, Steve Haehn, Andrew Hood, Nathaniel Gray, and TK Soh. =head1 COPYRIGHT This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. In addition, as a special exception to the GNU GPL, the copyright holders give permission to link the code of this program with the Motif and Open Motif libraries (or with modified versions of these that use the same license), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than linking with Motif/Open Motif. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License in the Help section "Distribution Policy" for more details. =cut nedit-5.6.orig/doc/nedit.pod0000644000175000017500000002354710255520165014502 0ustar paulpaul# $Id: nedit.pod,v 1.9 2005/06/20 10:54:45 edg Exp $ =pod =head1 NAME NEdit - Text Editor =head1 SYNOPSYS nedit [B<-read>] [B<-create>] [B<-line> I | B<+>I] [B<-server>] [B<-do> I] [B<-tags> I] [B<-tabs> I] [B<-wrap>] [B<-nowrap>] [B<-autowrap>] [B<-autoindent>] [B<-noautoindent>] [B<-autosave>] [B<-noautosave>] [B<-lm> I] [B<-rows> n] [B<-columns> I] [B<-font> I] [B<-geometry>|B<-g> I] [B<-iconic>] [B<-noiconic>] [B<-display> I<[host]:server[.screen]>] [B<-xrm> I] [B<-svrname> I] [B<-import> I] [B<-background>|B<-bg> I] [B<-foreground>|B<-fg> I] [B<-tabbed>] [B<-untabbed>] [B<-group>] [B<-V|-version>] [B<-h|-help>] [B<-->] [file...] =head1 DESCRIPTION NEdit is a standard GUI (Graphical User Interface) style text editor for programs and plain-text files. It provides mouse based editing and a streamlined editing style, based on popular Macintosh and MS Windows editors, for users of X workstations and X terminals. =head1 OPTIONS =over =item B<-read> Open the file read-only regardless of the actual file protection. =item B<-create> Don't warn about file creation when a file doesn't exist. =item B<-line> I, B<+>I Go to line number I. =item B<-server> Designate this session as an NEdit server, for processing commands from the L program. L can be used to interface NEdit to code development environments, mailers, etc., or just as a quick way to open files from the shell command line without starting a new NEdit session. =item B<-do> I Execute an NEdit macro or action on the file following the -do argument on the command line. B<-do> is particularly useful from the L program, where `nc -do' can remotely execute commands in an nedit B<-server> session. =item B<-tags> I Load a file of directions for finding definitions of program subroutines and data objects. The file must be of the format generated by Exuberant Ctags, or the standard Unix L command. =item B<-tabs> I Set tab stops every I characters. =item B<-wrap>, B<-nowrap> Wrap long lines at the right edge of the window rather than continuing them past it. (Continuous Wrap mode) =item B<-autowrap>, B<-noautowrap> Wrap long lines when the cursor reaches the right edge of the window by inserting newlines at word boundaries. (Auto Newline Wrap mode) =item B<-autoindent>, B<-noautoindent> Maintain a running indent. =item B<-autosave>, B<-noautosave> Maintain a backup copy of the file being edited under the name I<~filename> (on Unix) or I<_filename> (on VMS). =item B<-lm> I Initial language mode used for editing succeeding files. =item B<-rows> I Default height in characters for an editing window. =item B<-columns> I Default width in characters for an editing window. =item B<-font> I, B<-fn> I Font for text being edited. Font for menus and dialogs can be set with B<-xrm> I<"*fontList:font">. =item B<-geometry> I, B<-g> I The initial size and/or location of editor windows. The argument geometry has the form: [x][+|-][[+|-]] where C`' and C<< >> are the desired width and height of the window, and and C`' are the distance from the edge of the screen to the window, + for top or left, - for bottom or right. B<-geometry> can be specified for individual files on the command line. =item B<-iconic>, B<-noiconic> Initial window state for succeeding files. =item B<-display> I<[host]:server[.screen]> The name of the X server to use. I specifies the machine, I specifies the display server number, and I specifies the screen number. I or I can be omitted and default to the local machine, and screen 0. =item B<-background> I, B<-bg> I Background color. The background color for text can be set separately with B<-xrm> I<"nedit*text.background: color">. =item B<-foreground> I, B<-fg> I Foreground color. The foreground color for text can be set separately with B<-xrm> I<"nedit*text.foreground: color">. =item B<-xrm> I Set the value of an X resource to override a default value. =item B<-svrname> I When starting nedit in server mode, name the server, such that it responds to requests only when L is given a corresponding B<-svrname> argument. By naming servers, you can run several simultaneously, and direct files and commands specifically to any one. Specifying a non-empty name automatically designates this session as an NEdit server, as though B<-server> were specified. =item B<-import> I Loads an additional preferences file on top of the existing defaults saved in your I file. To incorporate macros, language modes, and highlight patterns and styles written by other users, run nedit with B<-import> I<>, then re-save your I file with Preferences->Save Defaults. =item B<-tabbed> Open all subsequent files in new tabs. Resets B<-group> option. =item B<-untabbed> Open all subsequent files in new windows. Resets B<-group> option. =item B<-group> Open all subsequent files as tabs in a new window. =item B<-V>, B<-version> Prints version and build information, to be mentioned when reporting bugs and problems. =item B<-h>, B<-help> Prints the command line help and then exits. =item B<--> Treats all subsequent arguments as file names, even if they start with a dash. This is so NEdit can access files that begin with the dash character. =back =head1 ENVIRONMENT =over =item DISPLAY NEdit requires an X-based workstation or X-Terminal. If you have used B or B to access the host Unix system, set the Unix environment variable for your display: csh-type shells: % setenv DISPLAY devicename:0 sh-type shells: % DISPLAY=devicename:0 && export DISPLAY =item NEDIT_HOME This environment variable can be set to the name of a directory. This directory will then be used instead of `$HOME/.nedit' as the base directory for NEdit's special files (see section FILES, below). This variable is new to NEdit 5.4. =back =head1 FILES From version 5.4 on, NEdit creates a directory in which NEdit's special files reside. This directory is named '.nedit' by default. =over =item I This is an X resource file which contains most user settings for NEdit. It is read at startup and written by selecting the item 'Save Defaults...' in the Preferences menu. Do not edit this file by hand, all settings can be reached via the 'Default Settings' menu. =item I The list of recently opened files. Do not edit this file by hand. =item I A file that can contain a number of NEdit Macro Language statements and subroutine definitions. The statements will be executed when an NEdit server starts, the subroutines will be loaded for later reference. This file will not be created or modified by NEdit (unless you load it and edit it of course). =back Note that NEdit still supports the older names for these files, which were used by version 5.3 and below. These file names are `$HOME/.nedit', `$HOME/.neditdb' and `$HOME/.neditmacro', respectively. The old naming scheme will be used if NEdit detects that `$HOME/.nedit' is a regular file and NEDIT_HOME isn't set. See also the entry for NEDIT_HOME under ENVIRONMENT, above. =head1 NOTES For more information see NEdit's online help, or nedit.doc in the NEdit distribution kit. NEdit sources, executables, additional documentation, and contributed software are available from the NEdit web site at http://nedit.org. =head1 SEE ALSO nc(1), X(1), mwm(1), ctags(1), etags(1) =head1 AUTHORS NEdit was written by Mark Edel, Joy Kyriakopulos, Christopher Conrad, Jim Clark, Arnulfo Zepeda-Navratil, Suresh Ravoor, Tony Balinski, Max Vohlken, Yunliang Yu, Donna Reid, Arne Forlie, Eddy De Greef, Steve LoBasso, Alexander Mai, Scott Tringali, Thorsten Haude, Steve Haehn, Andrew Hood, Nathaniel Gray, and TK Soh. The regular expression matching routines used in NEdit are adapted (with permission) from original code written by Henry Spencer at the University of Toronto. Syntax highlighting patterns and smart indent macros were contributed by: Simon T. MacDonald, Maurice Leysens, Matt Majka, Alfred Smeenk, Alain Fargues, Christopher Conrad, Scott Markinson, Konrad Bernloehr, Ivan Herman, Patrice Venant, Christian Denat, Philippe Couton, Max Vohlken, Markus Schwarzenberg, Himanshu Gohel, Steven C. Kapp, Michael Turomsha, John Fieber, Chris Ross, Nathaniel Gray, Joachim Lous, Mike Duigou, Seak Teng-Fong, Joor Loohuis, Mark Jones, and Niek van den Berg. =head1 COPYRIGHT This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. In addition, as a special exception to the GNU GPL, the copyright holders give permission to link the code of this program with the Motif and Open Motif libraries (or with modified versions of these that use the same license), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than linking with Motif/Open Motif. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License in the Help section "Distribution Policy" for more details. =cut nedit-5.6.orig/doc/setext0000755000175000017500000034767110742275742014155 0ustar paulpauleval 'exec perl -S $0 ${1+"$@"}' if $running_under_some_shell; #----------------------------------------------------------------------------- # # setext.pl -- Structure Enhanced Text Converter (to HTML or simple text) # # $Id: setext,v 1.14 2008/01/13 02:48:02 yooden Exp $ # # Copyright (c) 2000 Steven Haehn # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # In addition, as a special exception to the GNU GPL, the copyright holders # give permission to link the code of this program with the Motif and Open # Motif libraries (or with modified versions of these that use the same # license), and distribute linked combinations including the two. You must # obey the GNU General Public License in all respects for all of the code used # other than linking with Motif/Open Motif. If you modify this file, you may # extend this exception to your version of the file, but you are not obligated # to do so. If you do not wish to do so, delete this exception statement from # your version. # # This software is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # # You should have received a copy of the GNU General Public License along with # software; if not, write to the Free Software Foundation, Inc., 59 Temple # Place, Suite 330, Boston, MA 02111-1307 USA # #----------------------------------------------------------------------------- # # The concept of setext documents is the brain child of Ian Feldman. # Some typotag terms used herein were originally implemented in a perl script # by Tony Sanders, which is the inspirational source for this work. # This perl script understands the original typotags, plus extras needed for # hypertext links, conditional text, and variables. # # Samples of setext documents are regularly provided to those folks which # receive the TidBITS publication from www.tidbits.com in their e-mail. # # This program is really two programs crammed into one file. The two separate # pieces share lots of code. Instead of having 3 separate files, one of # them being a perl library with the shared code, there was a desire to keep # everything rolled up in one suitcase. # #----------------------------------------------------------------------------- # # GENERAL TRANSLATOR ROUTINES NEDIT HELP SOURCE CODE GENERATION ROUTINES # # check_target_reference collect_internal_hypertext_references # count emit_copyright # date emit_helpText # emit_paragraph emit_helpTitles # emit_setext_definition emit_help_header # extract_fields emit_help_label # extract_menu_info emit_help_menu # extract_menu_init emit_help_menu_text # get_menu_item emit_help_topic # get_setext get_menu_text # is_member get_newline # parse_setext get_style # preserve_html get_style_name # recover_extractions is_known_link # replace_underlines locate_menu_text # show_usage make_NEdit_menu_code # to_state print_menu # translate_setext # # # TYPOTAG TRANSLATION ROUTINES # # help_bold_tt text_bold_tt html_bold_tt # help_bullet_tt text_bullet_tt html_bullet_tt # help_emit_line text_emit_line html_emit_line # help_final text_final html_final # help_finishing text_finishing html_finishing # help_hot_tt text_hot_tt html_hot_tt # help_indent text_indent html_indent # help_init text_init html_init, html_init_title # help_italic_tt text_italic_tt html_italic_tt # help_line_break text_line_break html_line_break # help_list_tt text_list_tt html_list_tt # help_line_tt text_line_tt html_line_tt # help_quote_tt text_quote_tt html_quote_tt # help_section_tt text_section_tt html_section_tt # help_target_tt text_target_tt html_target_tt # help_title text_title html_title # help_underline_tt text_underline_tt html_underline_tt # # help_fixed_styles html_enter_list, html_leave_list # help_proportional_styles html_enter_pre, html_leave_pre # fix_target_tt html_enter_quote, html_leave_quote # html_emit_header, html_emit_footer # getHtmlAttributes # #----------------------------------------------------------------------------- use Getopt::Long; # for parsing the program command line (GetOptions) use File::Basename; # for trimming off directory names from files (basename) use English; #------------------------------------------------------------------------------- sub emit_version { my $version = "1.9"; my $date = "Oct 01, 2003"; print "$pgm: Version $version, $date.\n"; exit 0; } #------------------------------------------------------------------------------- sub show_usage { print "\n"; print "Usage: $pgm [ -dhtTVw ][-D directory][-H [hfile]][-S [htmlExt]] \\\n"; print " [-c conditional][-v name=value][setext_file [converted_file]]\n"; print "\n"; print " $pgm {-mp} [-c conditional][-M menuSuffix][-v name=value] setext_file\n"; print "\n"; print " The first form of $pgm is used to convert Structure Enhanced TEXT\n"; print " documents into HTML or simple text documents.\n"; print " The second form is specific to generating NEdit help menu code\n"; print " from a setext document with Menu and Help directives.\n"; print "\n"; print " -c conditional text definitions, separated by commas.\n"; print " -d do not automatically make titles hypertext references (HTML only)\n"; print " -D specify destination directory for separate HTML files. This also sets\n"; print " the value for the variable HTML_DIR.\n"; print " -h show this usage clause.\n"; print " -H convert setext_file to HyperText Markup Language (HTML).\n"; print " Optional file parameter specifies file containing HTML header\n"; print " and footer definition overrides. The current defaults are:\n"; print " \$htmlHeader = \n"; print " \$HTML_TITLE\n"; print " \n"; print " \n"; print " \$htmlFooter = \n"; print " \n"; print " where \$HTML_TITLE is replaced with an appropriate title.\n\n"; print " -m generate NEdit help menu code files.\n"; print " -M name NEdit help code files with this suffix.\n"; print " -p do option -m and print out NEdit help elements.\n"; print " -S convert setext_file into separate HTML files.\n"; print " (the default name extension is '$htmlExt', but it can be\n"; print " changed by specifying it as an argument to this option)\n"; print " -t convert setext_file to simple text (default).\n"; print " -T emit setext typotag definitions in use.\n"; print " -v defines variable name and assigns it the given value.\n"; print " (more than one occurrence of -v can be made) The variables\n"; print " are made available for use within the setext document parsing.\n"; print " -V display the version of this setext script.\n"; print " -w do not emit warnings about missing variables.\n"; print "\n"; print " When the converted_file argument is missing, STDOUT is used.\n"; print " When the setext_file argument is missing, STDIN is used.\n"; print "\n"; print " To get conditional text within a setext document to be displayed,\n"; print " supply a definition tag through the -c option. For example,\n"; print "\n"; print " $pgm -c NEDITDOC help.etx nedit.doc\n"; print "\n"; print " would generate a plain text document, nedit.doc, from the source\n"; print " help.etx, including/excluding text marked with 'NEDITDOC'\n"; print " conditional text markers, also known as 'maybe' typotags.\n"; print "\n"; exit 0; } #--------------------------------------------------------------------------- # This is a GetOptions call back function for gleaning variables from # the command line so that they can be available to the setext parsing # without having to appear in the setext document. The expected form # on the command line is: -v variableName=value. For example, -v version=5.2 #--------------------------------------------------------------------------- sub declare_variable { my $optionName = shift; my $optionValue = shift; my ( $varName, $varValue ) = split( "=", $optionValue ); $varValue or do { print STDERR "Missing value for variable '$varName'\n"; $Getopt::Long::error++; return }; #----------------------------------------------------- # By trimming off leading and trailing spaces allows # data entry like this: "version = 5.2 of Oct. 2001". #----------------------------------------------------- $varName =~ s/$trim_spaces/$2/o; $varValue =~ s/$trim_spaces/$2/o; $variables{ $varName } = $varValue; } #------------------------------------------------------------------------------- sub emit_setext_definition { print < typotags.etx $pgm -w typotags.etx ============ =================== ================== ! name of setext form acted upon or ! the typotag of typotag displayed as !============ =================== ================== ! title-tt "Title a title ! =====" in chosen style !------------ ------------------- ------------------ ! subhead-tt "Subhead a subhead ! -------" in chosen style !------------ ------------------- ------------------ ! section-tt ^#> section-text a section heading ! with '#' from 1..9 ! in chosen style !------------ ------------------- ------------------ ! indent-tt ^ lines indented lines undented ! ^ by 2 spaces and unfolded !------------ ------------------- ------------------ ! bold-tt **[multi]word** 1+ bold word(s) ! italic-tt ~multi word~ 1+ italic word(s) !underline-tt [_multi]_word_ underlined text ! hot-tt [multi_]word_ 1+ hot word(s) ! quote-tt ^>[space][text] > [mono-spaced] ! bullet-tt ^*[space][text] [bullet] [text] ! untouch-tt `_quoted typotag!_` `_left alone!_` ! notouch-tt ^!followed by text text-left-alone ! field-tt |>name[=value]<| value of name ! line-tt ^ --- horizontal rule !------------ ------------------- ------------------ ! list-tt .([space]list start multiple line list ! element ends with ! empty line ! endlist-tt .) denotes list end !------------ ------------------- ------------------ ! href-tt ^.. \@_word URL jump to address ! note-tt ^.. \@_word Note:("*") ("cause error") ! target-tt \@_[multi_]word [multi ]word !------------ ------------------- ------------------ ! twobuck-tt \$\$ [last on a line] [parse another] ! suppress-tt ^..[space][not dot] [line hidden] ! twodot-tt ^..[alone on a line] [taken note of] !------------ ------------------- ------------------ ! maybe-tt ^.. ? name[~] text show text when ! name defined ! maybenot-tt ^.. ! name[~] text show text when ! name NOT defined ! endmaybe-tt ^.. ~ name end of a multi- ! line maybe[not]-tt !------------ ------------------- ------------------ ! passthru-tt ^!![text] text emitted ! without processing !------------ ------------------- ------------------ ! escape-tt @\@x where 'x' is x is what remains ! escaped character @@@@ needed for 1 @@ ============ =================== ================== Only one instance of the element subhead-tt (or, in its absence, title-tt) is absolutely _required_ for a text to be considered a valid setext. All the elements, but subhead-tt, are in effect optional, that is, not necessary for a setext to be declared as such. The target-tt element allows the hypertext link definition of href-tt to be within the same setext. The actual reference (href-tt) of the target would look like: .. _word #reference_within_document !Multiple line maybe[not]-tt (conditional text regions) !are introduced as ".. ? name~" or ".. ! name~" and are !terminated with ".. ~ name", on a separate line. Single !line maybe[not]-tt do not use the '~' character and are !terminated with the end of the line. The special !conditional text region named "html" allows a mixture of !setext and HTML tags. Nesting of these typotags is !allowed. For instance, if there are three conditional !regions, A, B, and C, C can be nested inside B, which can !be nested inside A (eg. A-B-C...C-B-A). Note that a !surrounding region cannot end before one of its inner !regions is terminated (eg. of illegal nesting !A-B-C...C-A-B, where A terminated prior to B. Multiple line list-tt are introduced as ".(". Each line belongs to the current list element until an empty line is encountered. Once a list-tt is encountered, line separated paragraphs constitute list elements. A list-tt is terminated by endlist-tt. The list-tt/endlist-tt typotags are allowed to be nested (unlike the bullet-tt). These typo-tags do not have to start in the first column of a line, but must have leading whitespace if they are indented at all. Field typotags are used to define and reference values. Field definitions can only occur within a suppress-tt. For example: ".. `|>author=Steven Haehn<|`" Field references (eg. |>author<|) can occur in any printable text. If there is no known value for the field, it will remain unchanged and appear as written in the setext. END_OF_DEFINITION_TEXT #--------------------------------------------------------------- # Emit any predefined variables so user knows what is available. #--------------------------------------------------------------- if( %variables ) { print "\n"; print " The following are predefined for use in a field-tt\n"; print " for any setext document translated by this utility.\n"; print "\n"; foreach $key ( sort keys %variables ) { print " $key = $variables{$key}\n"; } } print "\n \$\$\n"; exit 0; } #------------------------------------------------------------------------------- $pgm = basename( $PROGRAM_NAME ); #========================== # Global shared definitions #========================== $um = "\375"; # untouchable marker $vm = "\374"; # variable marker $escMrk = "\33"; # internal escape marker $trim_spaces = '(\s*)(.*?)(\s*)$'; $list_level = 0; $listIndent = 2; @bullet_list = qw( * * o + * o + * o + ); %variables = ( date => &date(), Date => &date("D"), year => &date("y") ); @cond_text_definitions = (); $make_title_href = 1; #--------------------------------------- # Variables needed for HTML conversions. #--------------------------------------- $lt = "\376"; # "<" marker $gt = "\377"; # ">" marker $amp = "\373"; # "&" marker $htmlExt = "html"; # default HTML file name extension $htmlHeader = "\n\n" . "\$HTML_TITLE\n" . "\n" . "\n"; $htmlFooter = "\n\n"; #--------------------------------------------------------- # Look for following options, complain about unknown ones. #--------------------------------------------------------- Getopt::Long::config( "noignorecase" ); GetOptions( 'c=s', # conditional text definitions, separated by commas 'd', # do not make titles hypertext references (HTML only) 'D=s', # specify destination directory for separate HTML files 'h', \&show_usage, 'H:s', # create HTML from setext input 'm', # create NEdit help menu code from setext input 'M=s', # name NEdit help code files with this suffix 'p', # same as 'm' but with debug printout 'S:s', # generate separate HTML files for each subsection 't', # create text from setext input 'T', # emit setext typo-tag document 'v=s', \&declare_variable, 'V', # emit setext script version information 'w' # do not emit warning messages. ) || &show_usage; #----------------------------------- # Glean only those options specified #----------------------------------- $opt_c && (@cond_text_definitions = split( ",", $opt_c )); $opt_d && ($make_title_href=0); $opt_D && do { $variables{HTML_DIR}=$opt_D; $outputDirectory="$opt_D/" }; $opt_h && show_usage(); defined $opt_H && do { $convert_to = "html"; getHtmlAttributes( $opt_H ) }; $opt_m && do { $make_menu = 1; $convert_to = "help" }; $opt_M && ($helpSuffix = $opt_M ); $opt_p && do { $make_menu = 1; $convert_to = "help"; $print_menu = 1 }; defined $opt_S && do { $convert_to = "html"; $htmlExt = $opt_S if $opt_S; # user can specify file extension $separate_html_files=1; $make_title_href=1 }; $opt_t && ($convert_to = "text"); $opt_T && emit_setext_definition(); $opt_V && (emit_version()); $opt_w && ($noWarn = 1); #-------------------------------------------------------------- # Setext Parser states. # # The names are used to construct "enter_" & "leave_" elements # in the state_change hash table required to be initialized # by language specific initialization routines (see html_init). #-------------------------------------------------------------- $FMT = "fmt"; $LIST = "list"; $PRE_FMT = "pre"; $QUOTE = "quote"; #---------------------------- # Typotag Pattern Definitions #---------------------------- $bold_tt = '\*\*([^\*]+)\*\*([^\*]|$)'; $bullet_tt = '^\* ([^ ])'; $empty_line = '^\s*$'; $fld_left = '\|>'; $fld_right = '<\|'; $field_tt = "(${fld_left}.+?$fld_right)"; $field_content = "${fld_left}(.+?)$fld_right"; #$field_tt = "(${fld_left}[^<]+$fld_right)"; #$field_content = "${fld_left}([^<]+)$fld_right"; $hot_tt = '\b([\S]*)_\b'; $href_tt = '^\.\.\s+_([\S]*)\s+(.*)\s*'; $indent_tt = '^ ([^ ])'; $intHrefMrk = "#"; $internal_href = "^$intHrefMrk(.*)\$"; $italic_tt = '~([^~]*)~'; $line_tt = '^ ---*$'; $list_tt = '^\s*\.([()])'; $notouch_tt = '^!'; $passthru_tt = '^!!'; $quote_tt = '^> '; $section_tt = '^([1-6])>'; $subtitle_tt = '^---'; $suppress_tt = '^\.\.'; $target_tt = '(?!(^|\s)_[\S]+_(\s|\W|$))(^|\s)_([\S]+)'; # not underline, then target $title_tt = '^==='; $twobuck_tt = '^\s*\$\$\s*$'; $underline_tt = '\b_([\S]*)_\b'; $untouch_tt = "\\s*(`[^`]+[`'])(?=\\s|\\W|\$)"; $variable_def = '\s*(\w+)\s*([^=]*(=(.*)))?'; # $1 = name, $4 = value $escape_tt = "@"; # the character escape symbol (need @@ to escape @) $needEscaping = "$escape_tt(.)"; $escapedFound = "$escMrk(\\d+)$escMrk"; if( $make_menu ) { $setext_file = $ARGV[0]; open SETEXT, "<$setext_file" or die "Can't access $setext_file, $OS_ERROR"; make_NEdit_menu_code(); } else # Global elements for parsing setext { #------------------------- # Program option defaults. #------------------------- $setext_file = "-"; # STDIN, allows program to be used as a filter $converted_file = "-"; # STDOUT $convert_to = "text" if $convert_to eq ""; #-------------------------------------- # Begin processing file specifications. #-------------------------------------- $setext_file = $ARGV[0] if $ARGV[0] ne ""; open SETEXT, "<$setext_file" or die "Can't access $setext_file, $OS_ERROR"; if( $ARGV[1] ne "" ) { $converted_file = $ARGV[1]; $convert_to = "html" if $converted_file =~ /\.$htmlExt$/; # in case -H forgotten if( $converted_file eq basename( $converted_file ) ) { if( $outputDirectory ) { $converted_file = "$outputDirectory/$converted_file"; } } } open CONVERT, ">$converted_file" or die "Can't create $converted_file, $OS_ERROR"; translate_setext(); } #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- sub translate_setext { #-------------------------------------- # Adding conversion type to conditional # text definitions for convenience. #-------------------------------------- push @cond_text_definitions, $convert_to; get_setext( SETEXT, \@cond_text_definitions, \@data ); extract_menu_info( \@data ) if( $convert_to eq "html" && $separate_html_files ); chomp @data; # remove the newline character from each line. register_tt_translationFunctions( $convert_to ); parse_setext( \@data ); } #------------------------------------------------------------------------------- sub make_NEdit_menu_code { #-------------------------------- # Supply a default NEdit version. #-------------------------------- $neditDefaultMarker = "NEdit release of "; $variables{ version } = $neditDefaultMarker . date() if (not exists $variables{ version } or $variables{ version } eq "default"); #-------------------------------------- # Adding conversion type to conditional # text definitions for convenience. #-------------------------------------- push @cond_text_definitions, $convert_to; get_setext( SETEXT, \@cond_text_definitions, \@data ); extract_menu_info( \@data ); register_tt_translationFunctions( $convert_to ); } #------------------------------------------------------------------------------- sub parse_setext { my $setextData = shift; local($crnt_state, $fold, $a, $i, $unt, $lineNo); $crnt_state = $FMT; $lineNo = -1; @untouchable = (); $fold = 0; foreach (@$setextData) { $lineNo++; # current location in data array #-------------------------- # process title information #-------------------------- (/$title_tt/i or /$subtitle_tt/i) && do { &$do_title(); $fold = 0; next; }; /$section_tt/o && do { &$do_section_tt($1); $fold = 0; next; }; /$passthru_tt/ && do { &$do_emit_line(); next; }; next if ( /$suppress_tt/ or /$twobuck_tt/ ); $list_level = 0 if $list_level < 0; # paranoia protection #-------------------------------------------------- # handle line breaks, only one empty line gets out. #-------------------------------------------------- if ( /$empty_line/o ) { to_state( $FMT ); if( $list_level and not $fold ) { &$do_list_tt(); $fold = 1; } else { $fold = &$do_line_break( $fold ); } next; } $fold = 0; # no more empty lines /$line_tt/ && do { &$do_line_tt(); next; }; #----------------------------------- # No change to current state allowed # during list processing. #----------------------------------- if( $list_level == 0 ) { #------------------ # State transitions #------------------ if ( /$quote_tt/o ) { &to_state( $QUOTE ) } elsif ( /$bullet_tt/o ) { &to_state( $LIST ) } elsif ( /$indent_tt/o ) { &to_state( $FMT ) } elsif ( /$list_tt/o ) { &to_state( $FMT ) } else { &to_state( $PRE_FMT ) } } if( /$notouch_tt/o ) { s/$notouch_tt/ /o; } else { #-------------------------------------------- # Handle the untouchables first. # Mark their locations for later replacement. # (see recover_extractions) #-------------------------------------------- for( $i = scalar( @untouchable ); /$untouch_tt/o; $i++ ) { $unt = $1; $unlen = length( $unt ); $unloc = index( $_, $unt ); $untouchable[ $i ] = $unt; $front = substr( $_, 0, $unloc ); $back = substr( $_, $unloc+$unlen ); $_ = $front . $um . $back; } &$do_list_tt(); &$do_bullet_tt(); &$do_quote_tt(); &$do_bold_tt(); &$do_italic_tt(); &$do_underline_tt(); &$do_target_tt(); &$do_hot_tt(); &$do_indent_tt(); } &$do_emit_line(); } &$do_final(); } #------------------------------------------------------------------------------- sub register_tt_translationFunctions { my $conversion_type = shift; #---------------------------------------------------- # Register call-back functions for typotag processing #---------------------------------------------------- $do_bold_tt = "${conversion_type}_bold_tt"; $do_bullet_tt = "${conversion_type}_bullet_tt"; $do_emit_line = "${conversion_type}_emit_line"; $do_final = "${conversion_type}_final"; $do_hot_tt = "${conversion_type}_hot_tt"; $do_indent_tt = "${conversion_type}_indent"; $do_initialize = "${conversion_type}_init"; $do_italic_tt = "${conversion_type}_italic_tt"; $do_line_break = "${conversion_type}_line_break"; $do_line_tt = "${conversion_type}_line_tt"; $do_list_tt = "${conversion_type}_list_tt"; $do_quote_tt = "${conversion_type}_quote_tt"; $do_section_tt = "${conversion_type}_section_tt"; $do_target_tt = "${conversion_type}_target_tt"; $do_title = "${conversion_type}_title"; $do_underline_tt = "${conversion_type}_underline_tt"; &$do_initialize; # do any necessary initialization } #------------------------------------------------------------------------------- sub date { $format = $_[0]; ( $sec,$min,$hour,$mday,$mon,$year,@ignore ) = localtime( time ); $month = (January,February,March,April,May,June,July, August,September,October,November,December)[$mon]; $year = $year + 1900; return $year if $format eq "y"; return "$month $mday, $year" if $format eq "D"; return substr($month,0,3) . " $mday, $year"; } #------------------------------------------------------------------------------- sub to_state { my $given_state = shift; if ( $crnt_state ne $given_state ) { if( exists $state_change{ "leave_$crnt_state" } ) { $doStateChange = $state_change{ "leave_$crnt_state" }; &$doStateChange(); } if( exists $state_change{ "enter_$given_state" } ) { $doStateChange = $state_change{ "enter_$given_state" }; &$doStateChange(); } $crnt_state = $given_state; } } #------------------------------------------------------------------------------- sub count { my $whatToCount = shift; my $line = shift; my $howMany = 0; $howMany++ while( $line =~ /$whatToCount/g ); return $howMany; } #------------------------------------------------------------------------------- sub extract_fields { local $_ = shift; local $cond_text_region = shift; my ( $field, $variable, $flen, $floc, $front, $back, $v_name, $v_value ); my @variable_list = (); #------------------------------------------ # Mark all the escaped character sequences. #------------------------------------------ while( /$needEscaping/o ) { $subChar = ord( $1 ); s/$needEscaping/$escMrk$subChar$escMrk/o; } #----------------------------------------------------- # Collect any field typotags found for later expansion. #----------------------------------------------------- while( /$field_tt/o ) { $field = $1; $field =~ /$field_content/ && ( $variable = $1 ); if( $variable =~ /$variable_def/ ) { $v_name = $1; #---------------------------------------------- # When fields 2 and 3 contain identical strings # then a valid field has been encountered. #---------------------------------------------- if( $2 eq $3 ) { $v_value = $4; } else { #----------------------------------- # This is NOT a variable definition. # Have to recover original string. #----------------------------------- $v_name = "_A_${v_name}_Z_"; #internal name $v_value = $variable; } #---------------------------------------- # Is this only a reference to a variable? #---------------------------------------- if ( ! defined $v_value ) { #------------------------------------------------ # Only put definitions in the list when it is not # part of a comment. (comments are not emitted) #------------------------------------------------ push @variable_list, $v_name unless /$suppress_tt/o; } else { #------------------------------------------------ # setting the variable ( |>varName = value<| ) # (here $v_value is the value assignment portion) #------------------------------------------------ if( /$suppress_tt/o ) { $variables{ $v_name } = preserve_html( $v_value, $cond_text_region ); } else { push @variable_list, $variable; } } } #-------------------------------------- # Remove field and replace with marker. #-------------------------------------- $flen = length( $field ); $floc = index( $_, $field ); $front = substr( $_, 0, $floc ); $back = substr( $_, $floc+$flen ); $_ = $front . $vm . $back; } #---------------------------- # Fill in any variables found #---------------------------- foreach $element ( @variable_list ) { if( exists $variables{ $element } ) { $value = $variables{ $element } } else { $value = "|>$element<|"; print STDERR "$pgm: Undefined variable '$element' used in $setext_file.\n" unless $noWarn; } s/$vm/$value/; } $_ = preserve_html( $_, $cond_text_region ); return $_; } #------------------------------------------------------------------------------- sub preserve_html { my $text = shift; my $cond_text_region = shift; #-------------------------------------------------------- # When in a conditional text region that only applies to # HTML translation, change the angle brackets to internal # definitions that will be fixed later. This should allow # for a mixture of setext and HTML language together. #-------------------------------------------------------- if ( $cond_text_region eq "html" ) { $text =~ s//${gt}/go; $text =~ s/\&/${amp}/go; } return $text; } #=================================================================== # Import setext data from given data stream and pay attention to # conditional text considerations, as described below. # # ^.. ? name Conditional text when 'name' is defined. # ^.. ! name Conditional text when 'name' is NOT defined. # # ^.. ? name~ # Multiple line conditional text when 'name' is defined. # (without suppress-tt, will always appear in translated # document going through non-conditional setext conversion) # ^.. ~ name # # ^.. ! name~ # Multiple line conditional text when 'name' is NOT defined. # (without suppress-tt, will always appear in translated # document going through non-conditional setext conversion) # ^.. ~ name # # This procedure also extracts and applies variable definitions # to the text to be emitted. #=================================================================== sub get_setext { my $stream = shift; my $cond_text_definitions = shift; my $data = shift; my $conditional_text_marker = '^\.\. ([\?!~])\s*(\S+)\s?(.*)$'; my $lineNbr = 0; my $i = 0; my $element = ""; my ($tense,$def_nm,$text,$multi_line,$crnt_def); my @cond_text_stack = (); while( $_ = <$stream> ) { $lineNbr++; if( /$conditional_text_marker/o ) { $tense = $1; # positive, negative, or end-of conditional text $def_nm = $2; $text = $3; $multi_line = $def_nm =~ s/~//o; #--------------------------------------------- # Reach end of multiple line conditional text? #--------------------------------------------- if( $tense eq "~" ) { $crnt_def = substr( pop @cond_text_stack, 1 ); if( $crnt_def ne $def_nm ) { print STDERR "Incorrectly nested conditinal text sections near line $lineNbr.\n"; print STDERR "Expected end of '$crnt_def', but saw end of '$def_nm'\n"; exit 1; } } else { #----------------------------------------- # Entering multiple line conditional text? #----------------------------------------- if( $multi_line ) { push @cond_text_stack, "$tense$def_nm"; } #------------------------------------------ # This will also catch any non-space # text found on multiple line conditionals. #------------------------------------------ if( $text =~ /\S/o ) { $$data[$i++] = extract_fields( "$text\n", $def_nm ) if ($tense eq "?") and is_member( $def_nm, $cond_text_definitions ); $$data[$i++] = extract_fields( "$text\n", $def_nm ) if ($tense eq "!") and not is_member( $def_nm, $cond_text_definitions ); } } } elsif( scalar( @cond_text_stack ) == 0 ) { $$data[$i++] = extract_fields( $_, "" ); } else { #-------------------------------------------------------------------- # The top element of the conditional text stack is the current # conditional text area. See if it exists in the definitions list. # When present, we want this line of text, depending on 'tense'. #-------------------------------------------------------------------- $element = $cond_text_stack[-1]; $tense = substr( $element, 0, 1 ); $def_nm = substr( $element, 1 ); if( $tense eq "?") { if( is_member( $def_nm, $cond_text_definitions ) ) { s/$suppress_tt //o; $$data[$i++] = extract_fields( $_, $def_nm ); } } elsif( ! is_member( $def_nm, $cond_text_definitions ) ) { s/$suppress_tt //o; $$data[$i++] = extract_fields( $_, $def_nm ); } } } } #------------------------------------------------------------------------------- sub extract_menu_init { %MenuNames = (); @helpMenu = (); @menuStack = \@helpMenu; $crntMenu = \@helpMenu; @indentStack = ( 0 ); $menuLevel = 0; $comment_ind = "^\\.\\."; # setext comment indicator ("..") $menu_element = "${comment_ind} Menu: "; $help_element = "${comment_ind} Help: "; $drop_marker = "_(.)_"; $separator = "-"; $help_code = 9; # special hide-it code indicating not part of help menu $name_length = 0; # determines padding alignment in HelpMenu data emission $crntIndent = 0; $subMenuIndicator = "\377"; } #------------------------------------------------------------------------------- sub extract_menu_info { my $thisData = shift; my $dataIndex = 0; extract_menu_init(); #---------------------------------------------------------------------- # For each and every menu item found in the original data (*.etx) file. #---------------------------------------------------------------------- while( $_ = get_menu_item( $thisData, \$dataIndex ) ) { #---------------------------------------------------------------------- # Here we want to extract the menu title, help name, optional hideIt # numerical indicator, and optional menu association name. # # Expecting: MenuTitle # HelpName [[,]HideItIndicator] [# Association] #---------------------------------------------------------------------- if( /^([^#]+)#\s*(\w*)(\s*,\s*)?(\d+)?(\s*#\s*)?(\w+)?/o ) { $menuTitle = $1; $helpName = $2; $hideItInd = ($4 eq "") ? "0" : $4; $assocName = ($6 eq "") ? $helpName : $6; $helpName =~ s/$trim_spaces/$2/; $assocName =~ s/$trim_spaces/$2/; #------------------------------------------------ # Determine to which menu this menu item belongs # using leading whitespace indentation. # Extract menu character mneumonic. #------------------------------------------------ $menuTitle =~ /^(\s*)/ && ($nextMenu = length($1)-$crntIndent); $menuTitle =~ s/$trim_spaces/$2/o; $mneumonic = (/$drop_marker/) ? $1 : substr( $menuTitle, 0, 1 ); #-------------------------------------------------- # Identation greater than previous menu element # indicates that this element is part of a submenu. #-------------------------------------------------- if( $nextMenu > 0 ) { @$crntMenu[ $end ] .= $subMenuIndicator; # mark previous element ($menu = $previousTitle) =~ s/ /_/g; @$menu = (); push @menuStack, \@$menu; push @indentStack, $nextMenu; $menuLevel++; } #-------------------------------------- # Indentation less than previous menu # element indicates leaving a submenu. #-------------------------------------- elsif( $nextMenu < 0 ) { $indentLevel = $indentStack[$menuLevel] + $nextMenu; do { pop @menuStack; pop @indentStack; $menuLevel--; } while( $indentLevel < $indentStack[$menuLevel] ); } $crntIndent += $nextMenu; $crntMenu = $menuStack[ $#menuStack ]; $end = scalar( @$crntMenu ); @$crntMenu[ $end ] = "$mneumonic,$menuTitle,$helpName,$hideItInd"; $thisTitle = $menuTitle; $thisTitle =~ s/$drop_marker/$1/; $thisTitle =~ s/ /_/go; $MenuNames{ $thisTitle } = "$menuLevel$assocName"; $previousTitle = $menuTitle; #--------------------------------- # update data for padding purposes #--------------------------------- if( $mneumonic ne $separator and $name_length < length( $helpName ) ) { $name_length = length( $helpName ); } } } } #------------------------------------------------------------------------------- sub get_menu_item { my $setext = shift; my $line = shift; #------------------------------------------- # Search each and every data line for either # a '# Menu: ' line or a '# Help: ' line and # return remainder of the line. #------------------------------------------- while( $$line < scalar( @$setext ) ) { $_ = $$setext[ $$line++ ]; return $_ if s/$menu_element//o; return "$_, $help_code" if s/$help_element//o; } return ""; } #------------------------------------------------------------------------------- sub check_target_reference { local($_) = @_; my $index; my $target = ""; if( /$target_tt/ ){ $target = $4; } #----------------------------------- # Are all titles automatically being # made into hypertext references? #----------------------------------- elsif( $make_title_href ) { /$title_tt/ && ( $target = $2 ); $target =~ s/$trim_spaces/$2/o; $target =~ s/ /_/go; } if( $target ) { print CONVERT "\n"; # only one target-tt reference of this kind allowed per file. ($index = is_member( $target, \@nm_ref )) && do{ splice( @nm_ref, $index-1, 1 ); }; } } #------------------------------------------------------------------------------- sub is_member { $item = shift; $this_list = shift; my $index = 1; foreach $member ( @$this_list ) { if( $item eq $member ) { return $index; } $index++; } return 0; } #------------------------------------------------------------------------------- sub replace_underlines { my $pattern = shift; s#$pattern#($text = $1) =~ s,_, ,go; $text; #eg; } #------------------------------------------------------------------------------- sub reclaim_escapes { #----------------------------------------- # Put back any escaped characters in text. #----------------------------------------- while( /$escapedFound/ ) { $subChar = chr( $1 ); s/$escapedFound/$escape_tt$subChar/; } } #------------------------------------------------------------------------------- sub recover_extractions { my $element; #------------------------------------ # Replace escaped characters in text. #------------------------------------ while( /$escapedFound/ ) { $subChar = chr( $1 ); s/$escapedFound/$subChar/; } foreach $element ( @untouchable ) { s/$um/$element/; } @untouchable = (); } #------------------------------------------------------------------------------- sub emit_paragraph { my $paragraph = shift; my $line = $left_margin; @words = split ' ', $paragraph; #------------------------------------------------------------- # Flow words onto a line up until the right margin is reached. #------------------------------------------------------------- foreach $word ( @words ) { if( length( $line ) + length( $word ) + 1 <= $right_margin ) { $line = "$line$word "; } else { print CONVERT "$line\n"; $line = "$left_margin$word "; } } #-------------------- # emit any remainder. #-------------------- print CONVERT "$line\n" if( length( $line ) > length( $left_margin ) ); } #------------------------------------------------------------------------------- # This routine is used to override program defaults for HTML settings. # Two variables are expected to be defined; $htmlHeader and $htmlFooter sub getHtmlAttributes { my $attrFile = shift; if( $attrFile ) { unless( $return = do $attrFile ) { warn "Could not parse $attrFile: $@" if $@; warn "Could not do $attrFile: $!" unless defined $return; warn "Could not run $attrFile" unless $return; exit 1; } } } #------------------------------------------------------------------------------- # setext to text conversion call-back routines. # ( in alphabetical order ) #------------------------------------------------------------------------------- sub text_bold_tt { s/$bold_tt/$1$2/g } #------------------------------------------------------------------------------- sub text_bullet_tt { # don't do anything if this is no bulleted line. if (/$bullet_tt/) { # remove lead-in from paragraph and put the rest in an array my $paragraph = $_; $paragraph =~ s/$bullet_tt/$1/; @words = split ' ', $paragraph; $paragraph = ""; # start with text mode bullet character my $line = ' * '; foreach $word (@words) { if (length($line) + length($word) + 1 <= $right_margin) { # put every word in a line if there's still room $line = "$line$word "; } else { # append line to paragraph if full and start a new line $paragraph = "$paragraph$line\n"; $line = " $word "; } } # get last line $paragraph = "$paragraph$line"; # remove trailing white space $paragraph =~ s/\s$//; $_ = $paragraph; } } #------------------------------------------------------------------------------- sub text_emit_line { if( /$passthru_tt/ ) { s/$passthru_tt//o; # remove typotag and pass line out as is. reclaim_escapes(); print CONVERT "$_\n"; } else { #----------------------------- # Handling nested lists first. #----------------------------- if( $list_level ) { my $pad = " " x ($list_level * $listIndent); my $bullet = ($atListStart) ? "$bullet_list[$list_level] " : " "; s/^\s*/ $pad$bullet/; $atListStart = 0; } elsif( $crnt_state ne $FMT && $text_unfolded_line ne "" ) { emit_paragraph( &text_finishing($text_unfolded_line) ); $text_unfolded_line = ""; } #------------------------------------------- # This keeps extra newlines from popping out # when a list has been terminated. #------------------------------------------- unless( $terminatedList ) { print CONVERT &text_finishing( $_ ), "\n" unless $_ eq $indentingMode; } else { $terminatedList = 0; } } } #------------------------------------------------------------------------------- sub text_final { emit_paragraph( &text_finishing($text_unfolded_line) ) } #------------------------------------------------------------------------------- sub text_finishing { local($_) = @_; recover_extractions(); $_; } #------------------------------------------------------------------------------- sub text_hot_tt { if ( /$hot_tt/ ) { #--------------------------------------------------------- # The heuristic to prevent Internet addresses from having # underlines removed, is to check for an '@' character. #--------------------------------------------------------- if (($text = $1) !~ /\@/ ) { $text =~ s/_/ /g; } s/$hot_tt/$text/; } } #------------------------------------------------------------------------------- sub text_indent { s/$indent_tt/$1/o && do { $text_unfolded_line = "$text_unfolded_line$_ "; $_ = $indentingMode; }; } #------------------------------------------------------------------------------- sub text_init { %state_change = (); $text_unfolded_line = ""; # to be used by text_indent & text_emit_line $left_margin = " "; # for emit_paragraph $right_margin = 79; # for emit_paragraph $indentingMode = "?#."; # hopefully unique string not normally found #---------------------------------------------------------------- # Take all the titles, capitalize and remove title indicator. #---------------------------------------------------------------- for ($i = 0; $i <= $#data; $i++) { $_ = $data[$i]; # $_ is default for searches (/$title_tt/ or /$subtitle_tt/) && do { $titleType = ( /$title_tt/ ) ? "=" : "-"; $data[$i--] = ".."; # suppress title indicator ( --- or === ) $data[$i] =~ s/^\s*//o; # get rid of any leading space. $this_title = $data[$i]; # Have to fix title if it also happens to be a target-tt. $this_title =~ /$target_tt/ && do { ($tmp = $4) =~ s,_, ,go; $this_title = $tmp }; $data[$i] = "..$titleType \U$this_title"; }; } #---------------------------------------------------- # NOTE: changing original subtitle-tt search pattern # to match what was done above. #---------------------------------------------------- $subtitle_tt = "^\\.\\.- (.*)"; $title_tt = "^\\.\\.= (.*)"; } #------------------------------------------------------------------------------- sub text_italic_tt { s/$italic_tt/$1/g } #------------------------------------------------------------------------------- sub text_line_break { my $fold = shift; emit_paragraph( &text_finishing($text_unfolded_line) ); $text_unfolded_line = ""; print CONVERT "\n" unless $fold++; return $fold; } #------------------------------------------------------------------------------- sub text_line_tt { } #------------------------------------------------------------------------------- sub text_list_tt { if( /$list_tt/o ) { if ( $1 eq '(' ) { $list_level++; s/$list_tt\s*//; $atListStart = 1; } else { $list_level--; s/$list_tt//; $terminatedList = 1; } } #----------------------------------------------------- # An empty line terminates a multiple line list entry. #----------------------------------------------------- elsif( /$empty_line/o ) { print CONVERT "\n"; #text_line_break( 0 ); $atListStart = 1 if $list_level; } } #------------------------------------------------------------------------------- sub text_quote_tt { } #------------------------------------------------------------------------------- sub text_section_tt { my $hdr_level = shift; s/$section_tt//; print CONVERT "\n \U$_\n" if $hdr_level <= 3; # converted to uppercase print CONVERT "\n $_\n" if $hdr_level > 3; # left alone } #------------------------------------------------------------------------------- sub text_target_tt { s#$target_tt#($text = $4) =~ s,_, ,go; " $text"; #eg; } #------------------------------------------------------------------------------- sub text_title { my $size; my $line = ""; my $lc = substr( $_, 2, 1 ); #----------------------------------------------------------------- # Incoming text looks like ..= or ..- <subtitle text> #----------------------------------------------------------------- to_state( $FMT ); $_ = substr( $_, 4 ); text_target_tt(); $size = length( $_ ); #------------------------------------------------- # Going to wrap titles with lines as long as title #------------------------------------------------- for( $size = length( $_ ); $size > 0; $size-- ) { $line="$line$lc"; } print CONVERT "$line\n$_\n$line\n"; } sub text_underline_tt { replace_underlines( $underline_tt ) } #------------------------------------------------------------------------------- # setext to HTML conversion call-back routines. # ( in alphabetical order ) #------------------------------------------------------------------------------- sub html_bold_tt { #--------------------------------------- # Turn all "**text**" into "<B>text</B>" #--------------------------------------- s#$bold_tt#${lt}B${gt}$1${lt}/B${gt}$2#g; } #------------------------------------------------------------------------------- sub html_bullet_tt { s/$bullet_tt(.*)/ ${lt}li${gt}$1$2${lt}\/li${gt}/; } #------------------------------------------------------------------------------- sub html_emit_footer { print CONVERT "</P>\n$htmlFooter"; $closePgf = ""; } #------------------------------------------------------------------------------- sub html_emit_header { my $htitle = shift; my $header = $htmlHeader; $header =~ s/\$HTML_TITLE/$htitle/o; print CONVERT $header; } #------------------------------------------------------------------------------- sub html_emit_line { print CONVERT "<LI>" if $atListStart == 1 and not /${lt}LI${gt}/o; $atListStart = 0; if( /$passthru_tt/ ) { s/$passthru_tt//o; # remove typotag and pass line out as is. reclaim_escapes(); print CONVERT "$_\n" } else { print CONVERT &html_finishing( $_ ), "\n"; } } #------------------------------------------------------------------------------- sub html_enter_list { print CONVERT "<UL>\n" } # state change activities sub html_leave_list { print CONVERT "</UL>\n" } sub html_enter_pre { print CONVERT "<PRE>\n"; $insideNoFormatArea = 1 } sub html_leave_pre { print CONVERT "</PRE>\n"; $insideNoFormatArea = 0 } sub html_enter_quote { print CONVERT "<BLOCKQUOTE><PRE>\n"; $insideNoFormatArea = 1 } sub html_leave_quote { print CONVERT "</PRE></BLOCKQUOTE>\n"; $insideNoFormatArea = 0 } #------------------------------------------------------------------------------- sub html_final { &to_state( $FMT ); html_emit_footer(); #---------------------------------------------------- # Report on all internal name references not used up. #---------------------------------------------------- if( scalar( @nm_ref ) > 0 ) { print STDERR "\nMissing reference (target-tt) to the following:\n\n"; for( $i=0; $i < scalar( @nm_ref ); $i++ ) { print STDERR " $nm_ref[ $i ]\n"; } } } #------------------------------------------------------------------------------- sub html_finishing { local($_) = @_; my $unt; s/\&/\&\#38\;/go; s/\</\&\#60\;/go; s/\>/\&\#62\;/go; s/$lt/</go; s/$gt/>/go; s/$amp/\&/go; # convert markers to real symbols #----------------------------------------------- # This fixes the case where an untouchable # string includes these special html characters. #----------------------------------------------- foreach $element ( @untouchable ) { $element =~ s/\&/\&\#38\;/go; $element =~ s/\</\&\#60\;/go; $element =~ s/\>/\&\#62\;/go; } recover_extractions(); $_; } #------------------------------------------------------------------------------- sub html_hot_tt { #---------------------------------------------------- # After finding a hot-tt, substitute all underlines # with spaces and check to see if the hot-tt had # a corresponding hypertext reference. Flag it in # bright, bold red when no hypertext record found. # Allow user to define the variable HTML_DIR as the # destination directory for the HTML code. # Note, the files may have to actually be placed # in such directory by hand after they are generated. #---------------------------------------------------- s#$hot_tt# $h = $href{$1}; ($text = $1) =~ s,_, ,go; $h ? qq'${lt}A HREF="$variables{HTML_DIR}$h"${gt}$text${lt}/A${gt}' : "${lt}B${gt}${lt}font color=red${gt}--> $text <-- NO HREF!!${lt}/font${gt}${lt}/B${gt}"; #eg; } #------------------------------------------------------------------------------- sub html_indent { s/$indent_tt/$1/ } # get rid of indent-tt characters #------------------------------------------------------------------------------- sub html_init { local $title, $aTitle; my $target; %state_change = ( enter_list => "html_enter_list", leave_list => "html_leave_list", enter_pre => "html_enter_pre", leave_pre => "html_leave_pre", enter_quote => "html_enter_quote", leave_quote => "html_leave_quote", ); $veryFirstTime = 1; # used to force table of content header out #------------------------------------------ # Make a first pass over the data, looking # for hypertext linking information. #------------------------------------------ for ($i = 0; $i <= $#data; $i++) { $_ = $data[$i]; # $_ is default for searches #--------------------------------------------------------- # This will pick out targets found in the setext not # hidden by a suppress-tt, that is, the href-tt below. # With this check, it is unnecessary to have to include # the href-tt which uses identical text for internal # document references. External references need href-tt. # Have to make sure the match does not pick up elements # inside a notouch-tt ( eg. `_do_not_want_this_as_target`) #--------------------------------------------------------- if( /$target_tt/ && substr($`,length($`)-1,1) ne "`" && (not /$suppress_tt/) ) { $href{ $4 } = "$intHrefMrk$4"; push @nm_ref, $4; } #------------------------------------------------- # Locate HREF's and save. When no target is given, # assume the target is internal, with same name. #------------------------------------------------- if( /$href_tt/ ) { $hrefID = $1; $target = ($2) ? $2 : "$intHrefMrk$hrefID"; # assume internal href. $href{$hrefID} = $2; #------------------------------ # Remember internal HREF's not # already seen for target-tt. #------------------------------ if( $target =~ /$internal_href/ ) { if( not is_member( substr( $target, 1), \@nm_ref ) ) { push @nm_ref, $1; } } next; } #--------------------------------------------------------- # The first title-tt or subhead-tt gets <TITLE>... #--------------------------------------------------------- /$title_tt/ && do { $htmlTitle = html_init_title("H1", $i); next; }; /$subtitle_tt/ && do { $htmlTitle = html_init_title("H2", $i); next; }; } html_emit_header( $htmlTitle ); #---------------------------------------------------- # NOTE: changing original title-tt search pattern # to match what was done in html_init_title. #---------------------------------------------------- $title_tt = "^\\.\\.\\s+()(.*)(<\\/H.>)"; } #------------------------------------------------------------------------------- sub html_init_title { local($head, $i) = @_; my $hyper_ref; $data[$i--] = ".."; # suppress title indicator ( --- or === ) $data[$i] =~ s/^\s*//; # get rid of any leading space in actual title $this_title = $data[$i]; # Have to fix title if it also happens to be a target-tt. $this_title =~ /$target_tt/ && do { ($tmp = $4) =~ s,_, ,go; $this_title = $tmp }; #--------------------------------------------------- # Are all titles automatically considered target-tt? #--------------------------------------------------- if( $make_title_href ) { $hyper_ref = $this_title; $hyper_ref =~ s/ /_/go; $externalReference = ($separate_html_files) ? substr("$MenuNames{ $hyper_ref }.$htmlExt", 1) : ""; $href{ $hyper_ref } ="$externalReference$intHrefMrk$hyper_ref"; #------------------------------ # Remember internal HREF's not # already seen for target-tt. #------------------------------ if( not is_member( $hyper_ref, \@nm_ref ) ) { push @nm_ref, $hyper_ref; } } #----------------------------------------------------------------- # Put out the HTML title and then suppress it for later processing #----------------------------------------------------------------- $aTitle = "$this_title" unless $title++; $data[$i] = ".. <$head> " . $data[$i] . " "; return $aTitle; } #------------------------------------------------------------------------------- sub html_italic_tt { #--------------------------------------- # Turn all "~text~" into "text" #--------------------------------------- s#$italic_tt#${lt}I${gt}$1${lt}/I${gt}#g; } #------------------------------------------------------------------------------- sub html_line_break { my $fold = shift; print CONVERT "$closePgf

              \n" unless $fold++; $closePgf = "

              "; return $fold; } #------------------------------------------------------------------------------- sub html_line_tt { if( not $insideNoFormatArea ) { s/$line_tt/${lt}P${gt}${lt}HR${gt}/; print CONVERT html_finishing( $_ ), "\n"; } } #------------------------------------------------------------------------------- sub html_list_tt { if( /$list_tt/o ) { if ( $1 eq '(' ) # open list level { $list_level++; s/$list_tt/${lt}UL${gt}${lt}LI${gt}/; } else # close list level { $list_level--; s,$list_tt,${lt}/LI${gt}${lt}/UL${gt},; $atListStart = 2 if $list_level; $terminatedList = 1; } } #----------------------------------------------------- # An empty line terminates a multiple line list entry. #----------------------------------------------------- elsif( /$empty_line/o ) { print CONVERT "
            7. \n" unless $terminatedList; print CONVERT "

              \n"; $atListStart = 1 if $list_level; $terminatedList = 0; } } #------------------------------------------------------------------------------- sub html_quote_tt { s/$quote_tt\s*//; } #------------------------------------------------------------------------------- sub html_section_tt { my $hdr_level = shift; print CONVERT "\n"; } #------------------------------------------------------------------------------- sub html_target_tt { check_target_reference( $_ ); /$target_tt/ && do { ($a = $4) =~ s,_, ,go; s/$target_tt/ $a/; }; } #------------------------------------------------------------------------------- sub html_title { my $titleHolder = $_; to_state( $FMT ); /$target_tt/ && do { ($a = $4) =~ s,_, ,go; s/$target_tt/$a/; }; if( /$title_tt/i ) # this is the new title-tt from html_init { $frontMrk = $1; $thisTitle = $2; $backMrk = $3; if( not $separate_html_files or $veryFirstTime ) { check_target_reference( $titleHolder ); print CONVERT $frontMrk, &html_finishing($thisTitle), $backMrk, "\n"; $veryFirstTime = 0; } elsif( $frontMrk eq "

              " ) { $savedTitle = $thisTitle; $savedTitleHolder = $titleHolder; } else { #-------------------------- # Create another HTML file? #-------------------------- $hyper_ref = $thisTitle; $hyper_ref =~ s/$trim_spaces/$2/o; $hyper_ref =~ s/ /_/go; $association = $MenuNames{ $hyper_ref }; if( $association ne "" ) { $assocLevel = substr( $association, 0, 1 ); $association = substr( $association, 1 ); $newFile = "$outputDirectory$association.$htmlExt"; if( $converted_file ne $newFile ) { #----------------------------- # Finish off the current file. #----------------------------- html_emit_footer(); close CONVERT; #----------------------------------------------------- # This realigns title after nested sublevels complete. #----------------------------------------------------- if ( $assocLevel == 0 ) { $savedTitle = $thisTitle; } $converted_file = $newFile; open CONVERT, ">$converted_file" or die "Can't create $converted_file, $OS_ERROR"; html_emit_header( $savedTitle ); #-------------------------------------------- # This puts target reference in correct file. #-------------------------------------------- if( $savedTitleHolder ) { check_target_reference( $savedTitleHolder ); if( $savedTitleHolder =~ /$title_tt/i ) { print CONVERT $1, &html_finishing($2), $3, "\n"; } $savedTitleHolder = ""; } } } check_target_reference( $titleHolder ); print CONVERT $frontMrk, &html_finishing($thisTitle), $backMrk, "\n"; } } } #------------------------------------------------------------------------------- sub html_underline_tt { #-------------------------------------------- # Turn all "_text_" into "text" # Remembering to substitute intervening # underlines with spaces. #-------------------------------------------- s#$underline_tt# ($text = $1) =~ s,_, ,go; "${lt}I${gt}${lt}U${gt}$text${lt}/U${gt}${lt}/I${gt}"; #eg; } #------------------------------------------------------------------------------- # setext to NEdit HELP conversion call-back routines. # ( in alphabetical order ) #------------------------------------------------------------------------------- sub help_bold_tt { #---------------------------------------------------- # Turn all "**text**" into "text" #---------------------------------------------------- s#$bold_tt#${stlMrk}$TKN_BOLD$1${stlMrk}$TKN_BOLD$2#g; } #------------------------------------------------------------------------------- sub help_bullet_tt { s/$bullet_tt/ * $1/ } #------------------------------------------------------------------------------- sub help_emit_line { #------------------------------------------------------ # The following is here to help us generate conditional # compilation elements for the 'C' compiler. #------------------------------------------------------ if( /$passthru_tt/ ) { s/$passthru_tt//o; # remove typotag and pass line out as is. reclaim_escapes(); print HELP "$_\n" } else { #------------------------------------------------- # This seems to be the only good place to take # care of style changes that have occurred between # usage of proportional and fixed font styles. #------------------------------------------------- if( $styleChanged ) { $_ = $styleMark . get_style_name( $crntStyle ) . $_; $styleChanged = ""; } my $finishedLine = help_finishing( $_ ); print HELP "\"", $finishedLine, "\",\n"; #---------------------------------------------------------------- # To minimize newline output for the empty line elements, # the algorithm remembers if its last line had a newline emitted. #---------------------------------------------------------------- $newLinePresentInLastLine = $finishedLine =~ /\\n$/; } } #------------------------------------------------------------------------------- sub help_final {} #------------------------------------------------------------------------------- sub help_finishing { local($_) = @_; #---------------------------- # When finishing a heading... #---------------------------- if( $headingLevel ) { #-------------------------------------------------- # ... destroy any styles inadvertantly placed there #-------------------------------------------------- if( /$stlMrk/o ) { my @line = split $stlMrk; $_ = join '', @line; } #------------------------------------ # ... because only one style allowed. #------------------------------------ $stlFront = $styleMark . get_style_name( "" ); $headingLevel = 0; $stlEnd = $styleMark . get_style_name( $initialStyle ); $stlFront = "" if /^$styleToken/ ; # remove redundancy when present $_ = $stlFront . $_ .$stlEnd; } #--------------------------------------------- # Any style markers found in the current line? #--------------------------------------------- elsif( /$stlMrk/ ) { #---------------------------------------- # Break line up into style word elements. #---------------------------------------- my $line = ""; my @line = split $stlMrk; foreach $element ( @line ) { #-------------------------------------------------- # Extract word emphasis token and associated words. # Embed style marker into text line. #-------------------------------------------------- $element =~ /^($aStyleToken)?(.*)$/o && do { $token = ($1) ? $1 : $TKN_TEXT; # $TKN_xxx $words = $2; my $nextStyle = get_style( $crntStyle, $token ); if( $crntStyle eq $nextStyle ) { $line .= $words; } else { $stlNm = get_style_name( $nextStyle ); $line .= "$styleMark$stlNm$words"; $crntStyle = $nextStyle; } }; } $_ = $line; } recover_extractions(); fix_target_tt(); #------------------------------------------- # Apply any initial style change introduced. #------------------------------------------- $_ = $newLeadStyle . $_; $newLeadStyle = ""; #---------------------------------------------------------------- # Add newline element to all lines which are not being currently # formatted into a flowing paragraph. It is done here because the # character also has to get included in the character counts. #---------------------------------------------------------------- $_ .= get_newline( 1 ) if $crnt_state ne $FMT; #---------------------------------------------------------------------- # Since 2 characters (\ and n) are occupying the space of one newline, # we need to subract out the number of new lines from the total offset. #---------------------------------------------------------------------- my $styleCount = count( $styleToken, $_ ); my $newLineCount = count( "\\\\n", $_ ); my $quoteCount = count( '"', $_ ); my $backslashCount = count( "\\\\", $_ ) - $styleCount - $newLineCount - $quoteCount; my $adjustment = ($styleCount * $styleTokenSize) + ($backslashCount / 2) + $newLineCount + $quoteCount; #----------------------------------------------------------- # Now keep a running total of how many characters to emit. # (Keep 2 forms, total number for compiler string length # considerations, and another for target-tt section offsets. #----------------------------------------------------------- $sectionCharacterCnt += length( $_ ); $targetOffset += length( $_ ) - $adjustment; $_; } #------------------------------------------------------------------------------- sub help_fixed_styles { #---------------------------------------------------------------- # All proportional styles in the style state transition table # begin with the "_" character. If we are already in the # proportional styles arena, a link, or header, no change occurs. #---------------------------------------------------------------- if( $crntStyle =~ /^_/ ) { $crntStyle =~ s/^_//o; $styleChanged = $crntStyle unless $styleChanged; } } #------------------------------------------------------------------------------- sub help_hot_tt { my ( $text, $stlNm, $h ); #-------------------------------------------------- # After finding a hot-tt, substitute all underlines # with spaces and check to see if the hot-tt had # a corresponding hypertext reference. Make it # unadorned text when no reference found. #-------------------------------------------------- s#$hot_tt# ($text = $1) =~ s,_, ,go; $h = is_known_link( $text ); $stlNm = get_style_name( $crntStyle ); $h ? "$stlMrk$TKN_LINK$text$stlMrk$TKN_LINK" : $text; #eg; } #------------------------------------------------------------------------------- sub help_indent { if( /$indent_tt/ ) { s/$indent_tt/$1/; # get rid of indent-tt characters /\S$/ && do { $_ .= ' ' }; # make sure space available for remaining } # text in this kind of paragraph } #------------------------------------------------------------------------------- sub help_init { %state_change = ( enter_pre => "help_fixed_styles", leave_pre => "help_proportional_styles", enter_quote => "help_fixed_styles", leave_quote => "help_proportional_styles", ); #-------------------------------------------- # Global elements needed for making menu code #-------------------------------------------- %href = (); $copy_right_holder = "Mark Edel"; $hlptxt = "help_data$helpSuffix.h"; # name of file holding help data structures $hlphdr = "help_topic$helpSuffix.h"; # name of file holding help definitions $stlMrk = "\01"; # this is the character code $styleMark = '\01'; # this is the text string $styleToken = "\\$styleMark"; # this for splitting strings on styleMark $styleTokenSize = length( $styleToken ); # accounts for '\01A' $illegal_help = "HELP_none"; $menu_record = "(.),(.*),(.*),(\\d)"; $tgtIndx = 0; # target-tt index for hypertext reference array (@href) #------------------------------------------------------------------- # The following data is used to embed style data into the help text. #------------------------------------------------------------------- # TOKENS => text bold italic underline %styles_stt = ( # fixed font styles plain => { style => "A", states => [ "plain", "bold", "italic", "u_plain" ] }, bold => { style => "B", states => [ "bold", "plain", "b_ital", "u_bold" ] }, italic => { style => "C", states => [ "italic", "b_ital", "plain", "u_italic" ] }, b_ital => { style => "D", states => [ "b_ital", "italic", "bold", "u_b_ital" ] }, u_plain => { style => "E", states => [ "u_plain", "u_bold", "u_italic", "plain" ] }, u_bold => { style => "F", states => [ "u_bold", "u_plain", "u_b_ital", "bold" ] }, u_italic => { style => "G", states => [ "u_italic", "u_b_ital", "u_plain", "italic" ] }, u_b_ital => { style => "H", states => [ "u_b_ital", "u_italic", "u_bold", "bold_ital" ] }, # proportional font styles _plain => { style => "I", states => [ "_plain", "_bold", "_italic", "_u_plain" ] }, _bold => { style => "J", states => [ "_bold", "_plain", "_b_ital", "_u_bold" ] }, _italic => { style => "K", states => [ "_italic", "_b_ital", "_plain", "_u_italic" ] }, _b_ital => { style => "L", states => [ "_b_ital", "_italic", "_bold", "_u_b_ital" ] }, _u_plain => { style => "M", states => [ "_u_plain", "_u_bold", "_u_italic", "_plain" ] }, _u_bold => { style => "N", states => [ "_u_bold", "_u_plain", "_u_b_ital", "_bold" ] }, _u_italic => { style => "O", states => [ "_u_italic", "_u_b_ital", "_u_plain", "_italic" ] }, _u_b_ital => { style => "P", states => [ "_u_b_ital", "_u_italic", "_u_bold", "_bold_ital" ] }, # hyperLink style => "Q", # header1 style => "R", -- # header2 style => "S", |_ MAX_HEADER # header3 style => "T", -- ); #----------------------------------------------------------- # The link index is the position in a font style table # where the linking font will reside. It appears immediately # after the styles from the table above. #----------------------------------------------------------- $linkIndex = scalar( keys %styles_stt ); $maxTokens = scalar( @{ $styles_stt{plain}{states} } ); $STYLE_PLAIN = $styles_stt{plain}{style}; $STYLE_LINK = "Q"; # link style marker, a continuation from style table $STYLE_HDR = "R"; # beginning of header style markers $MAX_HEADER = 3; # the maximum number of header styles in use $TKN_TEXT = 0; # used in style state transition, order important $TKN_BOLD = 1; # used in style state transition, order important $TKN_ITALIC = 2; # used in style state transition, order important $TKN_ULINE = 3; # used in style state transition, order important $TKN_LINK = 4; $aStyleToken = "[$TKN_TEXT$TKN_BOLD$TKN_ITALIC$TKN_ULINE$TKN_LINK]"; $initialStyle = "_plain"; # the initial style for help text. $crntStyle = $initialStyle; $headingLevel = 0; print_menu( $crntMenu, "" ) if $print_menu; # sort of debug info #---------------------------------- # Create help header (help_topic.h) #---------------------------------- open HLPHDR, ">$hlphdr" or die "Can't create $hlphdr, $OS_ERROR"; emit_help_header( HLPHDR, $crntMenu ); close HLPHDR; #------------------------------------------- # Create help text data header (help_data.h) #------------------------------------------- open HELP, ">$hlptxt" or die "Can't create $hlptxt, $OS_ERROR"; emit_helpTitles( HELP, $crntMenu ); collect_internal_hypertext_references( \@data ); $whence = 0; emit_helpText( HELP, $crntMenu, \@data ); } #------------------------------------------------------------------------------- sub help_italic_tt { s/$italic_tt/${stlMrk}$TKN_ITALIC$1${stlMrk}$TKN_ITALIC/g } #------------------------------------------------------------------------------- sub help_line_break { my $fold = shift; $_ .= get_newline( 2 ); help_emit_line() unless $fold++; return $fold; } #------------------------------------------------------------------------------- sub help_line_tt {} sub help_list_tt { text_list_tt() } sub help_quote_tt {} #------------------------------------------------------------------------------- sub help_proportional_styles { #---------------------------------------------------------------- # All proportional styles in the style state transition table # begin with the "_" character. If we are already in the # proportional styles arena, a link, or header, no change occurs. #---------------------------------------------------------------- unless( $crntStyle =~ /^_/ or $crntStyle eq "link" or $crntStyle eq "header" ) { $crntStyle = "_$crntStyle"; $newLeadStyle = $styleMark . get_style_name( $crntStyle ); } } #------------------------------------------------------------------------------- sub help_section_tt { $headingLevel = shift; #---------------------------------------------------------- # Heading levels for sectioning are being required to start # at level 3 (considered the first level). This keeps the # X-resources down inside NEdit. So here is the mapping. # 1> level-1 # 2> level-1 # 3> level-1 # 4> level-2 # 5> level-3 #---------------------------------------------------------- $headingLevel = ($headingLevel > 2 ) ? $headingLevel - 2 : 1; $headingLevel = $MAX_HEADER if $headingLevel > $MAX_HEADER; # s/$section_tt//; &help_emit_line; $crntStyle = $initialStyle; } #------------------------------------------------------------------------------- sub help_target_tt { } # cannot process target-tt at this time because # calculation of the hypertext offset requires # a fully expanded text line (see help_finishing). sub fix_target_tt { if( /$target_tt/ and exists $href{ $4 } ) { my ( $text, $tgtOffset, $originalLine ); #--------------------------------------------------- # Have to compute target's offset into help section. # Need actual text sans styling information. Assuming # all other text replacement has already occurred. #--------------------------------------------------- $originalLine = $_; s/$styleToken.//g; # remove all styling markers #-------------------------------------------------------- # Inside this special substitution, a computation of the # target's offset from the beginning of the section is # being computed and applied to the hyper-reference array # element which will be emitted after all text sections # have been processed. #-------------------------------------------------------- s#$target_tt# ($text = $4) =~ s,_, ,go; $tgtOffset = index( $_, $text ) + $targetOffset -1; $tgtOffset = sprintf( "%6d", $tgtOffset ); $href[ $tgtIndx++ ] =~ s /^0/$tgtOffset/o; " $text"; #eg; #------------------------------------------------------- # Now fix hyper-references in actual line to be emitted. #------------------------------------------------------- $_ = $originalLine; s#$target_tt# ($text = $4) =~ s,_, ,go; " $text"; #eg; } } #------------------------------------------------------------------------------- sub help_title {&help_emit_line} #------------------------------------------------------------------------------- sub help_underline_tt { #-------------------------------------------------- # Turn all "_text_" into "text" # Remembering to substitute intervening # underlines with spaces. #-------------------------------------------------- s#$underline_tt# ($text = $1) =~ s,_, ,go; "${stlMrk}$TKN_ULINE$text${stlMrk}$TKN_ULINE"; #eg; } #------------------------------------------------------------------------------- sub get_newline { $howMany = shift; $howMany-- if $newLinePresentInLastLine && $howMany > 1; return '\n' x $howMany; } #------------------------------------------------------------------------------- sub is_known_link { my $linkName = shift; for( $index = 0; $index < scalar( @hot_tt_links ); $index++ ) { $element = $hot_tt_links[ $index ]; return 1 if( $hot_tt_links[ $index ] eq $linkName ); } return 0; } #------------------------------------------------------------------------------- sub get_style { my $crntStyle = shift; # plain, bold, italic, etc. my $token = shift; # $TKN_xxx my $style = "header"; # assume working on header if( $headingLevel == 0 ) { if( $token == $TKN_LINK ) { if( $crntStyle eq "link" ) { $style = $prevStyle; } else { $prevStyle = $crntStyle; $style = "link"; } } else { @transitions = @{ $styles_stt{$crntStyle}{states} }; $style = $transitions[ $token ]; } } return $style; } #------------------------------------------------------------------------------- sub get_style_name { my $crntStyle = shift; # plain, bold, italic, etc. my $styleName; if( $headingLevel ) { $styleName = chr(ord( $STYLE_HDR )+$headingLevel-1); } elsif( $crntStyle eq "link" ) { $styleName = $STYLE_LINK; } else { $styleName = $styles_stt{$crntStyle}{style}; } return $styleName; } #------------------------------------------------------------------------------- sub get_menu_item { my $setext = shift; my $line = shift; while( $$line < scalar( @$setext ) ) { $_ = $$setext[ $$line++ ]; return $_ if s/$menu_element//o; return "$_, $help_code" if s/$help_element//o; } return ""; } #------------------------------------------------------------------------------- sub print_menu { my $crnt_menu = shift; my $indent = shift; my ( $menuTitle, $mneumonic, $helpName, $hideit, $type ); foreach $menuItem ( @$crnt_menu ) { if ( $menuItem =~ /$menu_record/o ) { $mneumonic=$1; $menuTitle=$2; $helpName=$3; $hideit=($4) ? $4 : "" } if( $hideit eq $help_code ) { $hideit = ""; $type = "Help" } else { $hideit = ", ($hideit)" if $hideit; $type = "Menu" } print "$type: $indent$mneumonic, $menuTitle [$helpName]$hideit\n"; if( $menuItem =~ /$subMenuIndicator/o ) { ($menu = $menuTitle) =~ s/ /_/og; print_menu( \@$menu, "$indent " ); } } } #------------------------------------------------------------------------------- sub collect_internal_hypertext_references { my $setext = shift; my $line = 0; my ($source, $destination ); while( $line < scalar( @$setext ) ) { $_ = $$setext[ $line++ ]; if( /$href_tt/o ) { $source = $1; $destination = $2; if( $destination =~ /$internal_href/ ) { $href{ $1 } = $source; } } } } #------------------------------------------------------------------------------- sub emit_helpText { my $stream = shift; my $crnt_menu = shift; my $setext = shift; my $line = 0; my $index = 1; $helpNameList = ""; emit_help_menu_text( $setext, $stream, $crnt_menu, \$line ); print $stream "static char **HelpText[] = {\n$helpNameList\n};\n\n"; print $stream "HelpMenu H_M [] =\n{\n"; emit_help_menu( $stream, $crnt_menu, 0, 1 ); print $stream "\n};\n"; #------------------------------------ # Emit internal hypertext references. #------------------------------------ print $stream "\nHref H_R [] =\n{\n"; $sep = ""; for ($index = 0; $index < scalar(@href); $index++) { $element = $href[$index]; $nextone = ($index == $#href) ? "NULL, " : "&H_R[%2d],"; printf $stream "$sep {$nextone$element}", $index+1; $sep = ",\n" } print $stream "\n};\n"; #----------------------------- # Emit program version string. #----------------------------- $pgmVersion = $variables{ version }; $pgmVersion .= '\n' . date() if $pgmVersion !~ /$neditDefaultMarker/; print $stream "\nstatic const char * NEditVersion = \"$pgmVersion\\n\";\n"; } #------------------------------------------------------------------------------- sub emit_help_menu_text { my $setext = shift; my $stream = shift; my $crnt_menu = shift; my $line = shift; my ( $menuTitle, $mneumonic, $helpName, $prevLine ); #---------------------------------------- # For every node of the menu tree... #---------------------------------------- foreach $menuItem ( @$crnt_menu ) { if ( $menuItem =~ /$menu_record/ ) { $mneumonic=$1; $helpName=$3; ($menuTitle=$2) =~ s/_//; } #--------------------------------- # ... recursively expand sub-menus #--------------------------------- if( $menuItem =~ /$subMenuIndicator/ ) { ($menu = $menuTitle) =~ s/ /_/g; emit_help_menu_text( $setext, $stream, \@$menu, $line ); } elsif( $mneumonic ne $separator ) # ... and not a menu separator { locate_menu_text( $setext, $menuTitle, $line ) or die "Unable to find \"$menuTitle\" text!"; $remainder = ""; my @section = (); my $lineNbr = 0; $s_e_p = ($helpNameList) ? ",\n" : ""; $helpNameList .= $s_e_p . " htxt_$helpName"; $sectionCharacterCnt = 0; $targetOffset = 0; #------------------------ # ... emit help menu text #------------------------ while( 1 ) { ($_,$remainder) = get_menu_text( $setext, $remainder, $line ); last if $_ eq ""; $lineNbr++; next if /$empty_line/ and $lineNbr == 1; chomp; #-------------------------------------------------- # Save all hypertext targets found in current topic #-------------------------------------------------- if( /$target_tt/ and exists $href{ $4 } ) { $target = $4; $href = $href{$target}; $href =~ s/_/ /go; $target =~ s/_/ /go; $topic = "HELP_\U$helpName,"; $nl1 = $name_length; # for HELP_ and comma push @href, sprintf("0, %-${nl1}.${nl1}s \"$href\"", $topic); push @hot_tt_links, $href; # collect for later verification. } s/\\/\\\\/go; # escape backslash any where in text s/"/\\"/go; # escape embedded double quotes s/^\s*$//; # redefine whitespace as empty line push @section, $_ ; } print $stream "static char * htxt_$helpName [] = {\n"; $styleChanged = $initialStyle; # This forces initial style out $crntStyle = $initialStyle; parse_setext( \@section ); print $stream "NULL\n};\n\n"; } } } #------------------------------------------------------------------------------- sub locate_menu_text { my $setext = shift; my $menuTitle = shift; my $line = shift; $menuTitle =~ s/_//go; # removing drop key character markers $menuTitle =~ s/ /./go; # spaces could be underlines in titles $menuTitle =~ s/\(/./go; # parens are special in regex searches... $menuTitle =~ s/\)/./go; # ... here they should be ignored #----------------------------------------------------- # When the whence value is set to zero, the search # for the text that belongs with the given menu title # is started at the beginning of the file. This allows # the menu text to be in an order other than that # specified by the menu itself. This gives freedom # to the writer; inefficiency to the text processing. #----------------------------------------------------- $$line = 0 if ( $whence != 1 ); while( $$line < scalar( @$setext ) ) { if( $$setext[ $$line++ ] =~ /$menuTitle/ ) { if ( $$setext[ $$line ] =~ /$subtitle_tt/ or $$setext[ $$line ] =~ /$title_tt/ ) { $$line++; return 1; # the first line after the setext title marker } } } return 0; } #------------------------------------------------------------------------------- sub get_menu_text { my $setext = shift; my $crnt_line = shift; my $line = shift; #------------------------------------- # Skip any setext comment lines found. #------------------------------------- while( $$setext[ $$line ] =~ /$suppress_tt/ ) { $$line ++ }; $crnt_line = $$setext[ $$line++ ] if $crnt_line eq ""; if( $crnt_line =~ /$twobuck_tt/ ) # end of setext document? { return ("", ""); } else { #-------------------------------------------- # Have to read ahead by one line to catch the # title of the next section, or the end of # the setext document.(Eat horizontal rulers) #-------------------------------------------- do { $_ = $$setext[ $$line++ ] } until not /^ --/; #-------------------------------- # Look ahead again, so that an # empty last line is not emitted. #-------------------------------- if( $crnt_line =~ /^\s*$/ and ($$setext[ $$line ] =~ /$subtitle_tt/o or $$setext[ $$line ] =~ /$title_tt/o or $$setext[ $$line ] =~ /$twobuck_tt/o)) { return ("", ""); } if( /$subtitle_tt/o or /$twobuck_tt/o ) { $$line = $$line - 2; return ("", ""); } } return ( $crnt_line, $_ ); } #------------------------------------------------------------------------------- sub emit_help_menu { my $stream = shift; my $crnt_menu = shift; my $level = shift; my $index = shift; my ( $menuTitle, $mneumonic, $helpName, $hideIt ); if( $level == 0 ) { $sep = ""; $end_index = scalar( @$crnt_menu ); } $level++; $nl1 = $name_length+6; # for HELP_ and comma $nl2 = $name_length+3; # for 2 double quotes and comma #---------------------------------------- # For every node of the menu tree... #---------------------------------------- foreach $menuItem ( @$crnt_menu ) { if ( $menuItem =~ /$menu_record/ ) { $mneumonic = $1; $helpName = $3; $hideIt = $4; ($menuTitle=$2) =~ s/_//; } #--------------------------------- # ... recursively expand sub-menus #--------------------------------- if( $menuItem =~ /$subMenuIndicator/ ) { ($menu = $menuTitle) =~ s/ /_/g; printf $stream "$sep { &H_M[%2d], $level, %-${nl1}.${nl1}s %-${nl2}.${nl2}s $hideIt, '$mneumonic', \"$menuTitle\" }", $index, "$illegal_help,", "\"$helpName\","; $index = emit_help_menu( $stream, \@$menu, $level, $index+1 ); } else { $topic = ( $mneumonic eq $separator ) ? "$illegal_help," : "HELP_\U$helpName,"; $helpName = "\"$helpName\","; $nptr = ( $end_index == 1 && $level == 1 ) ? "NULL" : "&H_M[%2d]"; #--------------------------- # are we at end of the menu? #--------------------------- if( $end_index == 1 && $level == 1 ) { print $stream "$sep { NULL, "; } else { printf $stream "$sep { &H_M[%2d], ", $index; } printf $stream "$level, %-${nl1}.${nl1}s %-${nl2}.${nl2}s $hideIt, '$mneumonic', NULL }", $topic, $helpName; $sep = ",\n"; $index++; } $end_index-- if $level == 1; } return $index; } #------------------------------------------------------------------------------- sub emit_helpTitles { my $stream = shift; my $crnt_menu = shift; emit_copyright( $stream, "$hlptxt -- Nirvana Editor help module data" ); print $stream "char *HelpTitles[] = {\n"; emit_help_label( $stream, $crnt_menu ); print $stream " NULL\n};\n\n"; } #------------------------------------------------------------------------------- sub emit_help_label { my $stream = shift; my $crnt_menu = shift; my ( $menuTitle, $mneumonic, $helpName ); #----------------------------------------------------------------- # Emit help title/labels for only the leaf nodes of the menu tree. #----------------------------------------------------------------- foreach $menuItem ( @$crnt_menu ) { if ( $menuItem =~ /$menu_record/ ) { $mneumonic = $1; $helpName = $3; ($menuTitle = $2) =~ s/_//go; } if( $menuItem =~ /$subMenuIndicator/ ) { ($menu = $menuTitle) =~ s/ /_/go; emit_help_label( $stream, \@$menu ); } elsif( $mneumonic ne $separator ) # ... and not a menu separator { print $stream " \"$menuTitle\",\n"; push @hot_tt_links, $menuTitle; # collect for later verification. } } } #------------------------------------------------------------------------------- sub emit_help_header # populates NEdit's help_topic.h { my $stream = shift; my $crnt_menu = shift; emit_copyright( $stream, "$hlphdr -- Nirvana Editor help display" ); print $stream "#define MAX_HEADING $MAX_HEADER\n"; print $stream "#define STL_HD $linkIndex+1\n"; print $stream "#define STL_LINK $linkIndex\n"; print $stream "#define STL_NM_HEADER '$STYLE_HDR'\n"; print $stream "#define STL_NM_LINK '$STYLE_LINK'\n"; print $stream "#define STYLE_MARKER '$styleMark'\n"; print $stream "#define STYLE_PLAIN '$STYLE_PLAIN'\n"; print $stream "#define TKN_LIST_SIZE $maxTokens\n"; print $stream "\n"; print $stream "enum HelpTopic {\n"; emit_help_topic( $stream, $crnt_menu ); print $stream " HELP_LAST_ENTRY,\n"; print $stream " $illegal_help = 0x7fffffff /* Illegal topic */ \n"; print $stream "};\n"; print $stream "\n"; print $stream "#define NUM_TOPICS HELP_LAST_ENTRY\n"; print $stream "\n"; } #------------------------------------------------------------------------------- sub emit_help_topic { my $stream = shift; my $crnt_menu = shift; my ( $menuTitle, $mneumonic, $helpName ); #----------------------------------------------------------------- # Emit help topic name for only the leaf nodes of the menu tree. #----------------------------------------------------------------- foreach $menuItem ( @$crnt_menu ) { if ( $menuItem =~ /$menu_record/ ) { $mneumonic = $1; $helpName = $3; ($menuTitle = $2) =~ s/_//go; } if( $menuItem =~ /$subMenuIndicator/ ) { ($menu = $menuTitle) =~ s/ /_/go; emit_help_topic( $stream, \@$menu ); } elsif( $mneumonic ne $separator ) # ... and not a menu separator { print $stream " HELP_\U$helpName,\n"; } } } #------------------------------------------------------------------------------- sub emit_copyright { my $stream = shift; my $filename = shift; my $year = date("y"); my $padlen1 = 76 - length( $filename ); my $padlen2 = 52 - length( $copy_right_holder ); my $blanks = " "; my $pad1 = substr( $blanks, 0, $padlen1 ); my $pad2 = substr( $blanks, 0, $padlen2 ); print $stream "/*******************************************************************************\n"; print $stream "* *\n"; print $stream "* $filename$pad1 *\n"; print $stream "* *\n"; print $stream " Generated on " . date() . " (Do NOT edit!)\n"; print $stream " Source of content from file $setext_file\n"; print $stream "* *\n"; print $stream "* Copyright (c) 1999-$year $copy_right_holder$pad2 *\n"; print $stream "* *\n"; print $stream "* This is free software; you can redistribute it and/or modify it under the *\n"; print $stream "* terms of the GNU General Public License as published by the Free Software *\n"; print $stream "* Foundation; either version 2 of the License, or (at your option) any later *\n"; print $stream "* version. *\n"; print $stream "* *\n"; print $stream "* This software is distributed in the hope that it will be useful, but WITHOUT *\n"; print $stream "* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *\n"; print $stream "* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *\n"; print $stream "* for more details. *\n"; print $stream "* *\n"; print $stream "* In addition, as a special exception to the GNU GPL, the copyright holders *\n"; print $stream "* give permission to link the code of this program with the Motif and Open *\n"; print $stream "* Motif libraries (or with modified versions of these that use the same *\n"; print $stream "* license), and distribute linked combinations including the two. You must *\n"; print $stream "* obey the GNU General Public License in all respects for all of the code used *\n"; print $stream "* other than linking with Motif/Open Motif. If you modify this file, you may *\n"; print $stream "* extend this exception to your version of the file, but you are not obligated *\n"; print $stream "* to do so. If you do not wish to do so, delete this exception statement from *\n"; print $stream "* your version. *\n"; print $stream "* *\n"; print $stream "* You should have received a copy of the GNU General Public License along with *\n"; print $stream "* software; if not, write to the Free Software Foundation, Inc., 59 Temple *\n"; print $stream "* Place, Suite 330, Boston, MA 02111-1307 USA *\n"; print $stream "* *\n"; print $stream "* Nirvana Text Editor *\n"; print $stream "* September 10, 1991 *\n"; print $stream "* *\n"; print $stream "* Written by $copy_right_holder *\n"; print $stream "* *\n"; print $stream "*******************************************************************************/\n"; print $stream "\n"; } #------------------------------------------------------------------------------- __END__ =head1 NAME Setext - convert Structured Enhanced TEXT into HTML or plain text. =head1 SYNOPSIS Usage: setext [ -dhtTVw ][-D directory][-H [hfile]][-S [htmlExt]] \ [-c conditional][-v name=value][setext_file [converted_file]] setext {-mp} [-c conditional][-M menuSuffix][-v name=value] setext_file The first form of setext is used to convert Structure Enhanced TEXT documents into HTML or simple text documents. The second form is specific to generating NEdit help menu code from a setext document with Menu and Help directives. -c conditional text definitions, separated by commas. -d do not automatically make titles hypertext references (HTML only) -D specify destination directory for separate HTML files. This also sets the value for the variable HTML_DIR. -h show this usage clause. -H convert setext_file to HyperText Markup Language (HTML). Optional file parameter specifies file containing HTML header and footer definition overrides. The current defaults are: $htmlHeader = $HTML_TITLE $htmlFooter = where $HTML_TITLE is replaced with an appropriate title. -m generate NEdit help menu code files. -M name NEdit help code files with this suffix. -p do option -m and print out NEdit help elements. -S convert setext_file into separate HTML files. (the default name extension is 'html', but it can be changed by specifying it as an argument to this option) -t convert setext_file to simple text (default). -T emit setext typotag definitions in use. -v defines variable name and assigns it the given value. (more than one occurrence of -v can be made) The variables are made available for use within the setext document parsing. -V display the version of this setext script. -w do not emit warnings about missing variables. When the converted_file argument is missing, STDOUT is used. When the setext_file argument is missing, STDIN is used. To get conditional text within a setext document to be displayed, supply a definition tag through the -c option. For example, setext -c NEDITDOC help.etx nedit.doc would generate a plain text document, nedit.doc, from the source help.etx, including/excluding text marked with 'NEDITDOC' conditional text markers, also known as 'maybe' typotags. =head1 DESCRIPTION This Structured Enhanced TEXT converter produces either HTML or plain text files from a given setext source. The HTML files produced can include hypertext references to within itself, or to external destinations. The setext converter also has the capability of providing different content in the resulting output files through a conditional text mechanism, and variable data definitions. All this allows a publisher to maintain a single, very readable, source while producing varying content for different output formats and audiences. When the converted_file argument is missing, STDOUT is used. When the setext_file argument is missing, STDIN is used. This gives setext the capability of being a filter to other programs. To get conditional text within a setext document to be displayed, supply a definition tag through the -c option. For example, setext -c NEDITDOC help.etx nedit.doc would generate a plain text document, nedit.doc, from the source help.etx, including/excluding text marked with 'NEDITDOC' conditional text markers, also known as 'maybe' typotags. Use the -T option to see the set of typotags supported by this converter. Further explanations of typotags occurs there. =head2 HTML Generation Examples The simplest form of HTML generation is: setext help.etx nedit.html setext -H help.etx nedit.html The results will be stored in the current directory in the nedit.html file. When the user wants to break up the resulting html file into multiple files, with cross references between the files, the -S option should be used. setext -S help.etx nedit.html The resulting files are broken up according to titled sections and are placed into the current directory, along with the nedit.html file. To change the destination of the resulting files, two options are supplied, the -D and -S options. For instance, setext -S shtml -D help/nedit help.etx nedit.shtml The -S option allows the name of the file extension to be altered. The -D option specifies where the resulting files are going to be stored. Thus, in the example, all the files will be placed in the help/nedit directory (relative to the current directory) and will have ".shtml" as the file extension. A final nuance has been added to help server side HTML capabilities. The -H option can be used to specify a file which contains the definitions of $htmlHeader and $htmlFooter. This will be used to override that which is supplied by the setext script. For example, setext -S shtml -H NEdit.ssd help.etx nedit.html tells setext to use the file NEdit.ssd (server side definition) to override the HTML header and footer generation. An example of the contents of this file follows. $htmlHeader = '' . "\n" . '' . "\n"; $htmlFooter = '' . "\n"; =head2 NEdit Help Menu When generating the NEdit help menu code, two files will be produced, help_data.h and help_topic.h (when the -M option is not used). These two files contain all the programmatic data needed to implement hypertext menus within the NEdit program. The following is an example of a setext invocation which assumes that the variable 'version' is being used within the help.etx file. setext -m -v "version=6.0" help.etx If the -M option is used, its value is appended to the root portion of the two generated files. For example, setext -m -c VMS -M _VMS help.etx will generate the files help_topic_VMS.h and help_data_VMS.h. The conditional portion of the help menu specifically designated for VMS will be extracted from the help.etx source. Below is what is used to guide the generation of 'C'-Motif menus. Indentation is SIGNIFICANT in the "Menu" directive lines below. It is used to determine under which menu element another item will belong. The number of spaces indented is not significant, but items to be placed in the same menu panel MUST line up at the same indent level. ALL nodes of this menu "tree" should have help name qualifiers. These are used to produce the internal lists used by NEdit help code. By default, the first character of the menu element will be used as a menu mneumonic key. To use another character in the menu element for this purpose, surround the character with underscores (eg. I w_a_nt 'a'). The menu title MUST match the one found in the actual help text (sans special mneumonic key character marking). The help text title may include underlines (for spaces) when it is a hyperlink target. The Help-name is used to generate various data structure names. For instance, the 'start' help name will be used to generate the HelpTopic enumeration value HELP_START and the character array htxt_start which holds the actual help text used in the menu dialogs. Consequently, these names need to be unique and contain only the characters that a 'C' compiler can digest. Menu separator lines use a dash (-) character for the Menu Title. They should also have a unique Help-name. A numerical value following the Help-name (separated from the name by a comma and/or spaces) is part of a menu element hiding scheme implemented in buildHelpMenu (found in 'menu.c'). When the number matches the hideIt value found in the procedure, that element will effectively become invisible. This mechanism was created for particular menu features that are not available to all incarnations of NEdit (in this case, the VMS version). A "Help" directive is used for all other text used as NEdit help, but does not show up in the Help menu. The following is a sample of Menu and Help directives. .. Menu Title # Help-name .. ------------------------------------------------------------ .. Menu: Getting Started # start .. Menu: Basic Operation # basicOp .. Menu: Selecting Text # select .. Menu: Finding and Replacing Text # search .. Menu: Cut and Paste # clipboard .. Menu: Using the Mouse # mouse .. Menu: Keyboard Shortcuts # keyboard .. Menu: S_h_ifting and Filling # fill .. Menu: F_i_le Format # format .. Menu: Features for Programming # features .. Menu: Programming with NEdit # programmer .. Menu: Tabs/Emulated Tabs # tabs .. Menu: Auto/Smart Indent # indent .. Menu: Syntax Highlighting # syntax .. Menu: Finding Declarations (ctags) # tags .. Menu: Regular Expressions # regex .. Menu: Basic Syntax # basicSyntax .. Menu: Metacharacters # escapeSequences .. Menu: Parenthetical Constructs # parenConstructs .. Menu: Advanced Topics # advancedTopics .. Menu: Examples # examples .. Menu: Macro/Shell Extensions # extensions .. Menu: Shell Commands and Filters # shell, 1 .. Menu: Learn/Replay # learn .. Menu: Macro Language # macro_lang .. Menu: M_a_cro Subroutines # macro_subrs .. Menu: Action Routines # actions .. Menu: Customizing # customizing .. Menu: Customizing NEdit # customize .. Menu: Preferences # preferences .. Menu: X Resources # resources .. Menu: Key Binding # binding .. Menu: Highlighting Patterns # patterns .. Menu: Smart Indent Macros # smart_indent .. Menu: NEdit Command Line # command_line .. Menu: Client/Server Mode # server .. Menu: Cr_a_sh Recovery # recovery .. Menu: ---------------------------------- # separator1 .. Menu: Version # version .. Menu: Distribution Policy # distribution .. Menu: Mailing _L_ists # mailing_list .. Menu: Problems/Defects # defects .. ------------------------------------------------------------ .. Help: Tabs Dialog # tabs_dialog =cut nedit-5.6.orig/doc/setext-info.txt0000644000175000017500000004424107544577622015714 0ustar paulpaul What is setext ---------------- The following is extracted from text written by Ian Feldman. As originally explained in TidBITS#100 and mentioned there from now on, that publication now comes "wrapped as a setext." The noun itself stands for both a method to wrap (format) texts according to specific layout rules and for a single _structure_enhanced_ text. The latter is a text which has been formatted in such a fashion that it contains clues as to the typographical and logical structure of its source (word-processed) document(s), if any. Those clues, which are called "typotags," facilitate later automatic detection of that structure so it can be validated, extracted, processed, transformed, enhanced as needed, if needed. It follows that setexts, being nothing but pure text (albeit with a special layout), are eminently readable using ANY editor or word processor in existence today or tommorrow, on any computer with a computer program that is capable of opening and reading text files. By default all properly setext-ized files will have an ".etx" or ".ETX" suffix. This stands for an "emailable/ enhanced text", the ExtraTerrestrial overtones nothwistanding ;-)) Unlike other forms of text encoding that use explicit, visible tag elements such as and <\that>, the setext format relies solely on the presence of _implicit_ typotags, carefully chosen to be as visually unobtrusive as possible. The underlined word above is one such instance of the defacto "invisible" coding. Inserted typotags will at worst appear as mere "typos" in the text. [Extensions made to the original set of typotags have muddied this clarity a little bit, but they were necessary for NEdit development.] Similarly, just to give an example, here is a short description of the four types of word emphasis typotags that setexts MAY contain, limited to one emphasis type ONLY per word or word group: ------------------- ---------------------------- -------------- ! **aBoldWord** **multiple bold words** ; bold-tt !_anUnderlinedWord_ _multiple_underlined_words_ ; underline-tt ! ~anItalicWord~ ~multiple italicized words~ ; italic-tt ! aHotWord_ multiple_hot_words_ ; hot-tt ----------------------------------------------------------------- What makes a setext? --------------------- Before any decoding can take place a text has first to be verified whether it is a setext and not some arbitrarily-wrapped stream of characters. Although there are more ways than one to achieve that goal there is one _primary_ test that has to be passed with colors or else the text being tested cannot be a setext. Chief among the typotags are two that signal presence of setext titles and subheads inside the text. A setext document can be formatted more or less properly, may contain or lack any other of its "native" elements but it has to have at least one proper subhead or a title in order to be declared as "a certified setext." Column 1 of text line | V Here are a few demo setext subheads: ------------------------------------ _ _ _ _ Which Share Just One _ _ _ _ ------------------------------------ ----------> UnifyinG FeaturE ------------------------------------ of EQUAL RIGHTMOST VISIBLE character ------------------------------------ length as that of its subhead-tt's ------------------------------------ [this line is called subhead-string] ------------------------------------ [the one below is called subhead-tt] ------------------------------------ [together they make a valid subhead] ------------------------------------ (!) and of course, subheads do not have to be of the same length ;-) ----------------------------------------------------------------------- (nor have to begin in column 1) --------------------------------- although it is recommended that they stay below 40 characters -------------------------------------------------------------- Second Setext In This File ============================== ((end of examples)) ------------------- ((_not_ a subhead)) ^ | Column 1 of text line Note, the last 3 lines of the examples do not constitute a valid subhead because they do not start in column 1. Chief among the reasons why one should first look for presence of subheads rather than titles is that it is fully conceivable that a setext might have been created without an explicit title-tt in order to allow decoder programs to distinguish between part one and any subsequent ones in a possible multi-part mailing. This absence of a title-tt could be enough of a signal to start looking for possible "part x of y" message in either the subject line, filename or anywhere "above" the first detected subhead of the current text. Therefore, here's a formal definition of what makes a setext: +-------------------------------------------------------------+ | a text that contains at least one verified setext subhead | | or setext title | +-------------------------------------------------------------+ Other considerations --------------------- A possibility arises to keep the paragraph text unwrapped, rather than folded uniformly at say the 66th character mark. After all, if the setext is primarily to be displayed inside an editor, rather than on an 80 character terminal screen, then there is not much sense in prior folding of the lines to a specific guaranteed-to-fit-on-a-TTY-screen length. The editor/word processor program will fit the unwrapped text to the available display area, and might actually prefer to have to deal with whole unwrapped paragraphs rather than with otherwise relatively short lines. Most text-processing programs with native word-wrap capabilities actually consider return-terminated lines to be paragraphs in their own right. Thus, if a setext is not to travel via email anyway (because of it being distributed differently or making use of accented characters) then it might as well arrive in unfolded state so that no extra time need be spent on making the paragraphs "whole again." [This is not the choice that is taken with NEdit help because it is easier to visualize the final text for those who do not use text wrapping.] Observe that it is not the state of the paragraph text that makes or breaks a setext. No, the sole criterion of whether a text is a setext is the presence of at least one verified subhead, as described above. Thus even texts with unfolded paragraphs are setexts if they contain at least one subhead-tt. The sole mechanism used in setext to encode which of such lines are in reality paragraphs (as opposed to those that shouldn't be folded mechanically) is the character indent. In fact, after the subhead-tt the second most important typotag is the indent-tt, made up of exactly two space characters, which denotes any such indented lines as ready-candidates for reflowing by so inclined front-ends (either on their own or as part of like-indented lines above and below it). So any potentially long line of a setext that has been indent-tted will be understood (by any validated setext front-end) as to be ready for wrapping-to-length if so required. .. All the following document by Steven Haehn Typotags Available ------------------ The following table contains typotags recognized by the setext utility. The "setext form" column in the table is formatted such that the left most character of the column represents the first character in a line of setext. The circumflex character (^) means that the characters of the typotag are significant only when they are anchored to the front of the setext line. Typotags marked with an asterisk (*) are extensions added for NEdit help generation. !! ============ =================== ================== !! name of setext form acted upon or !! the typotag of typotag displayed as !! ============ =================== ================== !! title-tt "Title a title !! =====" in chosen style !! ------------ ------------------- ------------------ !! subhead-tt "Subhead a subhead !! -------" in chosen style !! ------------ ------------------- ------------------ !! section-tt ^#> section-text a section heading !! with '#' from 1..9 !! in chosen style !! ------------ ------------------- ------------------ !! indent-tt ^ lines indented lines undented !! ^ by 2 spaces and unfolded !! ------------ ------------------- ------------------ !! bold-tt **[multi]word** 1+ bold word(s) !! italic-tt ~multi word~ 1+ italic word(s) !! underline-tt [_multi]_word_ underlined text !! hot-tt [multi_]word_ 1+ hot word(s) !! quote-tt ^>[space][text] > [mono-spaced] !! bullet-tt ^*[space][text] [bullet] [text] !! untouch-tt `_quoted typotag!_` `_left alone!_` !! notouch-tt* ^!followed by text text-left-alone !! field-tt* |>name[=value]<| value of name !! line-tt* ^ --- horizontal rule !! ------------ ------------------- ------------------ !! href-tt* ^.. _word URL jump to address !! note-tt ^.. _word Note:("*") ("cause error") !! target-tt* _[multi_]word [multi ]word !! ------------ ------------------- ------------------ !! twobuck-tt $$ [last on a line] [parse another] !! suppress-tt ^..[space][not dot] [line hidden] !! twodot-tt ^..[alone on a line] [taken note of] !! ------------ ------------------- ------------------ !! maybe-tt* ^.. ? name[~] text show text when !! name defined !! maybenot-tt* ^.. ! name[~] text show text when !! name NOT defined !! endmaybe-tt* ^.. ~ name end of a multi- !! line maybe[not]-tt !! ------------ ------------------- ------------------ !! passthru-tt* ^!![text] text emitted !! without processing !! ------------ ------------------- ------------------ !! escape-tt* @x where 'x' is x is what remains !! escaped character @@ needed for 1 @ !! ============ =================== ================== !! The title-tt, subhead-tt and indent-tt have already been discussed in length in the previous sections. All typotag elements, but the subhead-tt, are optional, that is, not necessary for a setext to be declared as such. The simple character marking typotags, bold-tt, italic-tt, and underline-tt have been used throughout the document and are used to mark text with their obvious meanings. 3>Section-tt (document divisions) The section-tt allows subdividing of the setext into further subsections for greater nesting capability. Typical usage starts the numbering level at 3 because the title-tt and subhead-tt basically represent sections 1 and 2, respectively. 3>Bullet-tt (list marker) The bullet-tt typotag is use to create a list of items. Note that it can only be used to create single line entries, like the following: Column 1 of text line | V * This is the first bullet. * This is the second bullet. Remember that you have to insert empty lines immediately before and after the bullet list. 3>Untouch-tt, Notouch-tt, Passthru-tt, Escape-tt (quoting text) Each one of these leave-my-text-alone typotags offer varying degrees of operation. The untouch-tt surrounds the text that is not to be interpreted. The accent grave (`) character is used to start and finish the untouchable text. (An extension to this has been allowed in the setext utility. An untouch-tt may be terminated by an apostrophe (').) The following are all valid untouch-tt typotags. `this is the _original_ version of the untouch-tt` `this is the _extended_ form of the untouch-tt' `This couldn't _be_ a problem could it?' Note that the third example has used the contraction "couldn't" which did not terminate the untouch-tt because the apostrophe was not followed by whitespace or punctuation. The notouch-tt typotag is used to take care of entire lines of text. The difference between this and the untouch-tt is that there is no visual residual typotag mark left in the output. It is replaced by a space. For example, Column 1 of text line | V ! This line of text will look like this sans the ! in column 1. becomes, This line of text will look like this sans the ! in column 1. The difference between the passthru-tt and the notouch-tt is the subtle difference of not replacing the markers with space, but totally removing them. (The original usage was to try to emit special 'C' compiler directives directly into the help code product). Thus, Column 1 of text line | V !!#ifdef VMS would turn into #ifdef VMS The escape-tt (@) is used to escape the special markers of the other typotags and itself. Here is an example of escaping itself. develop@@nedit.org This will become "develop@nedit.org" in resulting documents. 3>Suppress-tt, Twodot-tt (author annotations or comments) The suppress-tt typotag allows an author to place annotations in a setext document which will not appear in a generated product. Most of the extensions to the original setext definition were placed inside this form of typotag. Column 1 of text line | V .. This is a document comment that would normally disappear .. from generated text, html, or the like. These lines are .. what constitute a suppress-tt. The following line is the .. twodot-tt. .. 3>Hot-tt, Href-tt, Target-tt (hyperlinking text) These three typotags are used in conjunction to create hypertext reference mechanism used int HTML and NEdit help code generation. The hot-tt is an original typotag which needed the additional two tags to be able create actual hyperlinks to other sections of the document, or to external references that could be exploited. These tags are ignored (stripped) when generating simple text documents. The hot-tt typotag is used to mark the text which would be used as the doorway to accessing other parts of the document. It either references a title or subhead string directly, or an href-tt. An href-tt (hypertext reference typotag) is used as an intermediary for the hyperlink destination. Its value either specifies an external document reference, or an internal document reference. The target-tt is used to mark the internal document references mentioned in a href-tt. Now for some examples. All the marked text will be inside parenthesis so it will stand out as to what explicitly is being marked. This hot-tt directly references the (Typotags_Available_) subheading above. Whereas, the following hot-tt (references_) the href-tt marked by this target-tt (_typotag). Here is what the href-tt would look like: Column 1 of text line | V ! .. _references #typotsg .. The following line is the actual hypertext reference in this .. document. This annotation is an example of supress-tt usage. .. _references #typotag 3>Maybe[not]-tt, Endmaybe-tt (conditional text regions) Multiple line maybe-tt or maybenot-tt (conditional text regions) are introduced as follows: Column 1 of text line | V .. ? name~ (this is the maybe-tt) .. ! name~ (this is the maybenot-tt) Both are terminated with an endmaybe-tt on a separate line. Column 1 of text line | V .. ~ name The name* of the conditional region is left up to the text author. Single line maybe[not]-tt typotags do not use the '~' character at the end of the name and are terminated at the end of the line. Column 1 of text line | V .. ? oneLine (This is a one line maybe-tt) .. ! oneLine (This is a one line maybenot-tt) * There are some predefined conditional region names that are already known to the setext parser: html, text, and (NEdit) help. The special conditional text region named "html" allows a mixture of setext and HTML tags. Nesting of conditional text regions is allowed. For instance, if there are three conditional regions, A, B, and C, C can be nested inside B, which can be nested inside A. For example, A-B-C...C-B-A. Column 1 of text line | V .. ? A~ Example of legally nested conditional text regions .. ? B~ .. ? C~ .. ~ C .. ~ B .. ~ A Note that a surrounding region cannot end before one of its inner regions is terminated (eg. of illegal nesting A-B-C...C-A-B, where A terminated prior to B). 3>Field-tt (variable definition and substitution) Field-tt typotags are used to define variables and reference their values. Field definitions can only occur within a suppress-tt. For example, to define the variable 'author' and fill it with the value "Steven Haehn": Column 1 of text line | V .. |>author=Steven Haehn<| To use the value of the defined variable, place the field-tt, |>author<|, in any printable text region. If there is no known value for the field, it will remain unchanged and appear as written in the setext. The following are predefined for use in a field-tt for any setext document translated by the setext utility. Date = (eg. December 6, 2001) date = (eg. Dec 6, 2001) year = (eg. 2001) 3>Line-tt (horizontal rule demarcation) This typotag is used to place horizontal markers into generated text documents. Like the following. Column 4 of text line | V ------------------------------------------------------------- 3>Twobuck-tt (setext termination marker) This typotag is used to mark the end of document parsing. $$ $Id: setext-info.txt,v 1.3 2002/09/26 12:37:38 ajhood Exp $ nedit-5.6.orig/makefiles/0000755000175000017500000000000011107644412014052 5ustar paulpaulnedit-5.6.orig/makefiles/Makefile.aix0000644000175000017500000000215107662273213016301 0ustar paulpaul# $Id: Makefile.aix,v 1.7 2003/05/20 00:27:55 n8gray Exp $ CC=cc AR=ar # Note that -O is conspicuously absent from CFLAGS below due to an IBM # optimizer bug (which affects only textDisp.c). For improved # performance you can optimize all of the other files by specifically # modifying Makefile.common. # # For editres, add -DEDITRES to CFLAGS and -lXmu to LIBS # # -DFUNCPROTO=15 is necessary for some AIX compilers (including xlC) # that do not #define __STDC__ when in ANSI mode. This causes the X # headers to skip function prototypes and use char* in place of void*. # This causes a lot of unnecessary casts to avoid warnings. See bug # #130164 at: # # http://sourceforge.net/bugs/?func=detailbug&bug_id=130164&group_id=11005 # # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-DIBM -DIBM_FWRITE_BUG -DUSE_DIRENT -DFUNCPROTO=15 ARFLAGS=-urs LIBS= -lm -lXm -lXt -lX11 -lPW include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.bsdi0000644000175000017500000000121707757657253016462 0ustar paulpaul# $Id: Makefile.bsdi,v 1.6 2003/11/22 13:03:39 edg Exp $ # # Makefile for BSD/386 # # Thanks to Eric Johnson and Kurt Knochner CC=gcc2 AR=ar # For editres, add -DEDITRES to CFLAGS and -lXmu to LIBS # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O2 -m486 -DUSE_LPR_PRINT_CMD -I/usr/X11/include # LIBS=-lXm -lXt -lX11 LIBS= -L/usr/X11/lib -lXm -lXt -lXext -lX11 -lSM -lICE -lipc ARFLAGS=-ur include Makefile.common verify_config: check_tif_rule nedit-5.6.orig/makefiles/Makefile.ccur0000644000175000017500000000141207757657253016472 0ustar paulpaul# $Id: Makefile.ccur,v 1.6 2003/11/22 13:03:39 edg Exp $ # Makefile for Concurrent SVR4 using PowerMax OS 4.2 or later # # Provided by Robert Yunk of the Boeing Company CC=cc AR=ar # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -DUSE_DIRENT -DEDITRES ARFLAGS=-urs LIBS=-lm -lXm -lXmu -lXt -lX11 -lnsl -lsocket -lXp -lSM -lICE -lXext include Makefile.common # Installation Notes: # Remember to delete or update the old version of the app-defaults # file(s) or you will have accelerator keys missing and File Open # and File Save As errors. verify_config: nedit-5.6.orig/makefiles/Makefile.convex0000644000175000017500000000103307662273213017020 0ustar paulpaul# $Id: Makefile.convex,v 1.5 2003/05/20 00:27:55 n8gray Exp $ # Makefile for Convex # # Thanks to Stephane Bortzmeyer, Conservatoire National des Arts et Metiers CC=/bin/cc AR=/bin/ar ARFLAGS = ur # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS= -O3 -nv LIBS= -L/usr/lib/X11 -lXm -lXt -lX11 include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.cygwin0000644000175000017500000000114310000554766017013 0ustar paulpaul# $Id: Makefile.cygwin,v 1.8 2004/01/12 17:31:34 edg Exp $ CC=gcc AR=ar # For editres, add -DEDITRES to CFLAGS and -lXmu to LIBS # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -I/usr/X11R6/include -DDONT_HAVE_GLOB -DCYGWIN -DUSE_DIRENT -DUSE_LPR_PRINT_CMD -DNO_XMIM ARFLAGS=-urs LIBS= -L/usr/X11R6/lib -lXm -lXpm -lXext -lXt -lSM -lICE -lX11 include Makefile.common verify_config: check_tif_rule nedit-5.6.orig/makefiles/Makefile.dcosx0000644000175000017500000000073507662273213016646 0ustar paulpaul# $Id: Makefile.dcosx,v 1.5 2003/05/20 00:27:55 n8gray Exp $ # Makefile for Pyramid # # Thanks to Koen D'Hondt and patrick@wombat.logica.co.uk CC=cc AR=ar # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O LIBS= -lXm -lXt -lX11 include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.dec0000644000175000017500000000103607662273213016254 0ustar paulpaul# $Id: Makefile.dec,v 1.6 2003/05/20 00:27:55 n8gray Exp $ # # Makefile for old versions of OSF. # Use Makefile.dec for Digital Unix 4.0 and above # CC=cc AR=ar # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -DUSE_DIRENT ARFLAGS=-urs BIGGER_STRINGS= -Wf,-XNl8192 LIBS= -lXm -lXt -lX11 -lm include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.depend0000644000175000017500000000312207662273213016756 0ustar paulpaul# $Id: Makefile.depend,v 1.5 2003/05/20 00:27:55 n8gray Exp $ # # This is a _generic_ Makefile to generate a dependency file # using GNUmake and gcc. # Advantage of this method (as compared to "makedepend(1)") # is that one can easily filter out dependencies on # non-application (i.e. system) headers using the -MM flag # of gcc. The reason to demand GNUMake is basically to have a nice, # simple rule for $(SRCS) as done below (and for the variable # transformations). # So one doesn't have to modify this file and manually add/update # the source file list! # # To use it just you probably just have to edit the # variables in the *CONFIG section* as you see fit. # ***************** CONFIG section ***************** GCC=gcc DEFINES= CPPFLAGS=-I$(HOME)/include DEPENDFILE=dependencies SHELL=/bin/sh # Headers are required to determine _all_ files # on which the dependency file itself may depend SRCS=$(wildcard *.c) HDRS=$(wildcard ../source/*.h) $(wildcard ../util/*.h) # *************** End CONFIG section ************ # ************** Now the generic part *********** .SUFFIXES: .c .o. deps .PHONY: all default deps new DEPS=$(SRCS:.c=.deps) default: all # This is the more conservative approach full: clean new deps # And this a more sophisticated one all: $(DEPENDFILE) # Remove old file, create new one and add CVS info line at top new: /bin/rm -f $(DEPENDFILE) echo '# $$''Id''$$' >$(DEPENDFILE) $(DEPENDFILE): new $(SRCS) $(HDRS) $(GCC) $(CPPFLAGS) $(DEFINES) -MM $(SRCS) >>$(DEPENDFILE) deps: $(DEPS) %.deps: %.c $(GCC) $(CPPFLAGS) $(DEFINES) -MM $< >>$(DEPENDFILE) verify_config: nedit-5.6.orig/makefiles/Makefile.freebsd0000644000175000017500000000110607757657253017150 0ustar paulpaul# $Id: Makefile.freebsd,v 1.6 2003/11/22 13:03:39 edg Exp $ CC=cc AR=ar # For editres, add -DEDITRES to CFLAGS and -lXmu to LIBS # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -I${PREFIX}/include -DUSE_DIRENT -DUSE_LPR_PRINT_CMD -DUSE_XMIM LIBS= ${MOTIFLIB} -L${PREFIX}/lib -lm -lXpm -lXext -lXt -lSM -lICE -lX11 include Makefile.common verify_config: check_tif_rule nedit-5.6.orig/makefiles/Makefile.generic0000644000175000017500000001534207757657253017161 0ustar paulpaul# $Id: Makefile.generic,v 1.11 2003/11/22 13:03:39 edg Exp $ # # Prototype System-Specific Makefile for NEdit # # NEdit does not use any kind of automated configuration like the popular GNU # configure utility, or Imake. Instead, it has a set of hand-generated # system-specific Makefiles. The Makefiles serve two purposes. The obvious # purpose is to build NEdit. The less obvious purpose is to document on which # systems effort has been put into verifying that NEdit actually works properly. # If your system is not represented here, check the nedit web site at: # http://nedit.org for more contributed Makefiles. # # NEdit has few dependencies, and sticks to Posix and ANSI C standards wherever # possible. The only problems people generally run in to in porting NEdit are # related to the Motif GUI library. If you're having trouble building NEdit, # usually the best way to get it to work is to look at any other Motif, or at # least X example which builds and runs successfully, and copy the compiler # flags and libraries that it uses. # # C Compiler used to build all of the C sources. This must be an # ANSI standard C compiler. CC=cc # Library (archive) tool used to combine groups of object files into # a single file. AR=ar # Arguments to be passed to the C compiler. # # Below are compiler flags which may be of use if you are porting NEdit to a # new system: # # DONT_HAVE_GLOB Some older systems don't have the glob subroutine for # USE_MOTIF_GLOB expanding file names. If the linker complains about not # finding "glob" and "globfree", first try adding: # -DUSE_MOTIF_GLOB, which will use a private Motif routine # in place of "glob". Being a private routine, it is not # available in all Motif implementations, and you may have # to resort to -DDONT_HAVE_GLOB, and NEdit will not be able # to expand wildcards in the "Open Selected" command (which # is no huge loss). # # USE_DIRENT Some Unix systems call the structure used by the readdir # subroutine dirent, rather than direct. Add -DUSE_DIRENT # to CFLAGS if your C compiler complains about the line: # # struct direct *DirEntryPtr; # # USE_LPR_PRINT_CMD NEdit considers the standard Unix print command to be "lp" # unless told otherwise. If the standard command on your # system type is "lpr", define this. (This is just the last # resort default. You can redefine the print command to be # whatever you like via X resource settings). # # DONT_USE_ACCESS NEdit used to determine the accessibility of a file by # trying to open it. However, one of the more popular # commercial configuration management tools, ClearCase, # considers opening a file in read/write mode to be a # modification, even if no writing is ever done. This lead # to users having trouble with ClearCase thinking their # files had been modified when they hadn't. NEdit now uses # access() to determine whether a file is writable (in a # safe way). The old behavior can be restored by defining # DONT_USE_ACCESS. # # ROWCOLPATCH Patches around a problem in several versions the Solaris # Motif library which can cause crashes when a wiget is # destroyed. See comments in window.c for details. # # IBM_FWRITE_BUG Killer AIX system bug with fwrite system call. Only # affects one release of AIX, but can cause data corruption. # IBM actually denies that this bug ever existed, but it # was pretty widespread. # # EDITRES If you have the Xmu library, define this to give NEdit # the capability of being probed by editres to display its # widget tree. Editres is useful in customizing details # of X applications which their developers have deemed too # minute to document. If you define this, you must also add # -lXmu to LIBS # # NO_XMIM Don't use the Motif version of the international character # set input routines in the nedit text widget. Turn this on # if you see crashes in routines beginning with XmIm. Such # bugs exist in IRIX 6.5 and some older Motif versions. # # REPLACE_SCOPE Currently, two alternative (but functionally equivalent) # Replace/Find dialog box layouts are available. By default, # a layout with 2 rows of push buttons is built. Compiling # with the REPLACE_SCOPE flag enables an alternative layout # with a row of radio buttons for selecting the scope of the # replace operations. Eventually, one of these alternatives # will probably disappear. Please let us know which one you # prefer (via the discuss mailing list, for instance). # # HAVE__XMVERSIONSTRING If the Motif library exports the runtime version this # will display both strings in the version info to help # confirm the compile time and run time versions are # compatible. # # NO_READLINK Define if your system doesn't have the UNIX interface # readlink(2) - or just no symlinks at all. # # HAVE_CONFIG_H Include config.h from toplevel directory in front # of all other headers in each .c source file. # Only useful for developers so far. # # HAVE_DEBUG_H Include debug.h from toplevel directory after # all other headers in each .c source file. # Only useful for developers. # # Some compilers need to be told to operate in ansi-standard mode, some have # different levels of optimization that you can select (optimization improves # syntax highlighting performance. You will also often need to add locations # of X and/or Motif include files if they are not in the compiler's standard # search path. CFLAGS=-O # Flags for the library (archive) tool. These are pretty much standard # across all Unix systems, but if your system is having trouble building or # rebuilding the nedit library (libNUtil.a), you can try tweaking these. ARFLAGS=-urs # A few C compilers have limits on the size of string constants, which NEdit's # built-in help may exceed. Paradoxically, when you compile the code with one # of these mutants, it usually tells you how to bump up the limit, so all you # have to do is enter that information here. BIGGER_STRINGS= # Flags for the linker. On some systems, you have to specify the locations # for the X and/or Motif libraries. There may also be additional prerequisite # libraries which are required by the X and Motif libraries. These vary from # system to system, and it helps to have a working Motif program (or at least # an X program) as an example. LIBS= -lXm -lXt -lX11 -lm # System independent part include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.hpux0000644000175000017500000000124707662273214016512 0ustar paulpaul# $Id: Makefile.hpux,v 1.5 2003/05/20 00:27:56 n8gray Exp $ CC=cc AR=ar # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # # CFLAGS=-O -Ae -I/usr/include/X11R6 -I/usr/include/Motif1.2_R6 CFLAGS=-O -Aa -I/usr/include/X11R5 -I/usr/include/Motif1.2 -D_HPUX_SOURCE ARFLAGS=-urs # LIBS=-Wl,-L /usr/lib/X11R6 -L /usr/lib/Motif1.2_R6 -lm -lXm -lXt -lX11 LIBS=-L /usr/lib/X11R5 -L /usr/lib/Motif1.2 -lm -lXm -lXt -lX11 BIGGER_STRINGS = -Wp,-H20000 include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.linux0000644000175000017500000000156610520015540016650 0ustar paulpaul# $Id: Makefile.linux,v 1.14 2006/10/26 02:20:16 tringali Exp $ CC=cc AR=ar # For editres, add -DEDITRES to CFLAGS and -lXmu to LIBS # If using a Motif 2.1 compatible library (LessTif, OM) add # a '-lXp' in front of the -lXext in LIBS. You also drop the # -lXpm from that list. # Ensure that the Motif/LessTif headers and libs are found! # e.g. you may have to add something like # -I/usr/lesstif/include to CFLAGS and # -L/usr/lesstif/lib to LIBS # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -I/usr/X11R6/include -DUSE_DIRENT -DUSE_LPR_PRINT_CMD ARFLAGS=-urs LIBS=-L/usr/X11R6/lib -lXm -lXt -lX11 -lm include Makefile.common verify_config: check_tif_rule nedit-5.6.orig/makefiles/Makefile.linux-static0000644000175000017500000000166510520015540020135 0ustar paulpaul# $Id: Makefile.linux-static,v 1.1 2006/10/26 02:20:16 tringali Exp $ CC=cc AR=ar # For editres, add -DEDITRES to CFLAGS and -lXmu to LIBS # If using a Motif 2.1 compatible library (LessTif, OM) add # a '-lXp' in front of the -lXext in LIBS. You also drop the # -lXpm from that list. # Ensure that the Motif/LessTif headers and libs are found! # e.g. you may have to add something like # -I/usr/lesstif/include to CFLAGS and # -L/usr/lesstif/lib to LIBS # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -I/usr/X11R6/include -DUSE_DIRENT -DUSE_LPR_PRINT_CMD ARFLAGS=-urs LIBS=-L/usr/X11R6/lib -Wl,-Bstatic -lXm -Wl,-Bdynamic -lXp -lXpm -lXext -lXt -lSM -lICE -lX11 -lm include Makefile.common verify_config: check_tif_rule nedit-5.6.orig/makefiles/Makefile.lynx0000644000175000017500000000112607662273214016514 0ustar paulpaul# $Id: Makefile.lynx,v 1.6 2003/05/20 00:27:56 n8gray Exp $ CC=cc AR=ar # For editres, add -DEDITRES to CFLAGS and -lXmu to LIBS # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -I/usr/X11R6/include -DUSE_DIRENT -DUSE_LPR_PRINT_CMD -DDONT_HAVE_GLOB -Dlinux -D__NO_INCLUDE_WARN__ LIBS= -L/usr/lib -lm -lXm -lXpm -lXext -lXt -lSM -lICE -lX11 -lbsd include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.m88k.svr40000644000175000017500000000102007662273214017177 0ustar paulpaul# $Id: Makefile.m88k.svr4,v 1.5 2003/05/20 00:27:56 n8gray Exp $ # Makefile for Motorola SVR4 m88k # # Thanks to Mark Scott, Motorola Computer Group CC=cc AR=ar # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -s -DUSE_DIRENT -DSVR4 -DMOTOROLA LIBS= -lm -lXm -lXt -lX11 -lgen include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.macosx0000644000175000017500000000331210075307005016777 0ustar paulpaul# $Id: Makefile.macosx,v 1.7 2004/07/14 19:48:21 n8gray Exp $ # Makefile for MacOS X # Based on a contribution from hopperj@macconnect.com # Maintained by n8gray@caltech.edu # # Note that there will probably be warnings about prebinding and/or # duplicate symbol definitions, but the executable will work fine. # Change this line to point at the location your Motif libraries/headers are # installed. (e.g. /usr/local or /sw) Use "locate libXm." to find the # libraries, then remove the /lib suffix. MOTIFDIR=/usr/local # Use the first line if you're using OpenMotif, use the second if you're using # LessTif from Fink. EXTRALINKFLAGS=-bind_at_load # EXTRALINKFLAGS=-force_flat_namespace # Use the first line to link to Motif statically (highly recommended) or the # second line to link dynamically. With Fink you'll probably have to use # dynamic linking, since they don't normally distribute the static libraries. MOTIFLINK=${MOTIFDIR}/lib/libXm.a #MOTIFLINK=-L${MOTIFDIR}/lib -lXm.2 ############### You shouldn't need to edit anything below here ############## CC=cc AR=libtool ARFLAGS=-static -o # For editres, add -DEDITRES to CFLAGS and -lXmu to LIBS\\ # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -no-cpp-precomp -mdynamic-no-pic -DNO_XMIM -I/usr/X11R6/include \ -I${MOTIFDIR}/include -DUSE_DIRENT -DUSE_LPR_PRINT_CMD LIBS= ${EXTRALINKFLAGS} -L/usr/X11R6/lib ${MOTIFLINK} -lXp \ -lXpm -lXext -lXt -lSM -lICE -lX11 # # generic part # include Makefile.common verify_config: check_tif_rule nedit-5.6.orig/makefiles/Makefile.netbsd0000644000175000017500000000110107757657253017010 0ustar paulpaul# $Id: Makefile.netbsd,v 1.6 2003/11/22 13:03:39 edg Exp $ CC=cc AR=ar # For editres, add -DEDITRES to CFLAGS and -lXmu to LIBS # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -I/usr/X11R6/include -DUSE_DIRENT -DUSE_LPR_PRINT_CMD ARFLAGS=-ur LIBS= -L/usr/X11R6/lib -lm -lXm -lXpm -lXext -lXt -lSM -lICE -lX11 include Makefile.common verify_config: check_tif_rule nedit-5.6.orig/makefiles/Makefile.openbsd0000644000175000017500000000110707757657253017171 0ustar paulpaul# $Id: Makefile.openbsd,v 1.4 2003/11/22 13:03:39 edg Exp $ CC=cc AR=ar # For editres, add -DEDITRES to CFLAGS and -lXmu to LIBS # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -I/usr/X11R6/include -DUSE_DIRENT -DUSE_LPR_PRINT_CMD ARFLAGS=-ur LIBS= -L/usr/X11R6/lib -lXm -lXpm -lXp -lXext -lXt -lSM -lICE -lX11 -lm include Makefile.common verify_config: check_tif_rule nedit-5.6.orig/makefiles/Makefile.os20000644000175000017500000000437707662273214016240 0ustar paulpaul# $Id: Makefile.os2,v 1.14 2003/05/20 00:27:56 n8gray Exp $ # # Makefile for NEdit with XFree86 OS/2 # # From the toplevel directory just call # make -f makefiles/Makefile.os2 # .PHONY: init default clean # toplevel default target default: init build init: util/Makefile.os2 source/Makefile.os2 util/Makefile.os2 source/Makefile.os2: makefiles/Makefile.os2 cp $< $@ build: cd util && $(MAKE) -f Makefile.os2 all BUILD=1 cd source && $(MAKE) -f Makefile.os2 all BUILD=1 clean-all: cd util && $(MAKE) -f Makefile.os2 clean-local cd source && $(MAKE) -f Makefile.os2 clean-local doclean: init cd util && $(MAKE) -f Makefile.os2 clean-local cd source && $(MAKE) -f Makefile.os2 clean-local CC=gcc AR=ar # For editres, add -DEDITRES to CFLAGS and -lXmu to LIBS # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # DEFINES = -DUSE_DIRENT -DUSE_LPR_PRINT_CMD -DEDITRES -DNO_READLINK CFLAGS = -g -Zmt -O5 -mpentium -Wall -Wno-unused -W \ -I$(X11ROOT)/XFree86/include $(DEFINES) ARFLAGS=-urs # Using LessTif's libXm LIBS= -s -Zmtd -Zexe -Zbsd-signals -Zstack 0x4000 \ -L$(X11ROOT)/XFree86/lib -lXm -lXext -lXt -lXmu -lSM -lICE -lX11 ifeq ($(BUILD),1) include Makefile.common endif # # An alternative method to build the executables with OMF objects. # Those can be debugged using sd386, and can benefit from link386 # features like executable compression. # Usage: cd to source/ and type # make -f Makefile.os2 BUILD=1 nedit.exe # OBJS2=$(OBJS:.o=.obj) linkdate.obj CFLAGS2=$(CFLAGS) LIBS2= -g -Zmt -Zcrtdll -Zbsd-signals -Zstack 0x4000 \ -Zlinker /PM:VIO -Zlinker /E:2 -Zlinker /DEBUG -Zmap -Zlinker /M \ -L$(X11ROOT)/XFree86/lib -lXm -lXext -lXt -lXmu -lSM -lICE -lX11 nedit.exe: $(OBJS2) ..\util\libNUtil.lib del nedit $(CC) -o $@ $^ $(LIBS2) -Zomf nc.exe: nc.obj ..\util\libNUtil.lib del nc $(CC) -o $@ $^ $(LIBS2) -Zomf libNUtil.lib: ..\util\libNUtil.a emxomf $< %.obj: %.o emxomf $< %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< %.obj: %.c $(CC) -Zomf $(CFLAGS2) -c -o $@ $< clean-local: rm -f *.o *.a *.lib rm -f *.exe core verify_config: nedit-5.6.orig/makefiles/Makefile.osf0000644000175000017500000000111307662273214016305 0ustar paulpaul# $Id: Makefile.osf,v 1.6 2003/05/20 00:27:56 n8gray Exp $ # # Makefile for nirvana utilities # OSF/1 version: Digital Unix >=4.0, Tru64 # CC=cc # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=$(DEBUG) -DUSE_DIRENT -DFUNCPROTO -DXTFUNCPROTO LIBS= -lXm -lXt -lX11 -lm NLIBDIR = ../osf_lib NBINDIR = ../osf_bin MAKEDEPEND=makedepend -Y include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.qnx0000644000175000017500000000104507662273214016330 0ustar paulpaul# $Id: Makefile.qnx,v 1.3 2003/05/20 00:27:56 n8gray Exp $ # # Makefile for QNX # (reference: NEdit develop mailinglist) # CC=cc AR=ar # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O0 -I/usr/X11R6/include -DNO_XMIM ARFLAGS=-urs LIBS=-L/x86/usr/X11R6/lib -lm -lsocket -lXm -lXt -lICE -lSM -lX11 include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.reliant0000644000175000017500000000104007662273214017153 0ustar paulpaul# $Id: Makefile.reliant,v 1.5 2003/05/20 00:27:56 n8gray Exp $ #Makefile for ReliantUNIX-N Version 5.44 (SINIX) CC=cc AR=ar # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -DUSE_DIRENT LIBS=-L/usr/lib/netlib -lm -lXm -lXpm -lXext -lXt -lSM -lICE -lX11 -lsocket -lns l -ltcpip -lstraddr -lnsl include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.sco0000644000175000017500000000160207662273214016305 0ustar paulpaul# $Id: Makefile.sco,v 1.6 2003/05/20 00:27:56 n8gray Exp $ # Makefile for SCO Unix # # Thanks to Koen D'Hondt and patrick@wombat.logica.co.uk, and Andras Porjesz CC=cc AR=ar # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # #CFLAGS=-O -I/usr/include -Dsco -DSYSV -DUSG -DMALLOC_0_RETURNS_NULL -DUSE_DIRENT #CFLAGS=-O -Dsco -DSYSV -DUSG -DXTFUNCPROTO -DUSE_DIRENT -DMOTIF12 CFLAGS=-O -I/usr/X11R6/include -DUSE_DIRENT -DUSE_LPR_PRINT_CMD -DMAXPATHLEN=256 #LIBS= -lXm -lXt -lXext -lX11 -lc -lx -lsocket -lmalloc -lPW -lintl #LIBS=-lXtXm_s -lX11_s -lXmu -lXext -lsocket -lmalloc -lPW -lintl LIBS=-L/usr/X11R6/lib -L/usr/lib -lm -lXm -lXext -lXt -lX11 -lsocket include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.sgi0000644000175000017500000000205707662273214016310 0ustar paulpaul# $Id: Makefile.sgi,v 1.5 2003/05/20 00:27:56 n8gray Exp $ CC=cc AR=ar # For editres, add -DEDITRES to CFLAGS and -lXmu to LIBS # For systems older than IRIX 6.0, add -DUSE_MOTIF_GLOB to CFLAGS # # The flag NO_XMIM means that nedit will be using Motif composed-character # input routines in Motif text fields, and the basic X ones in the nedit # text widget. This is not optimal because it leaves more room for user # configuration problems. It's set this way because of a bug in the IRIX # 6.5 Motif XMIM routines which causes a crash on window closing. As far # as I know, other versions of IRIX are ok, and this can safely be removed. # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -DSGI -DNO_XMIM ARFLAGS=-urs # For systems older than IRIX 6.0, add: BIGGER_STRINGS= -Wf,-XNl10000 LIBS= -lm -lXm -lXt -lX11 -lPW include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.solaris0000644000175000017500000000220110371442002017151 0ustar paulpaul# $Id: Makefile.solaris,v 1.11 2006/02/05 18:29:22 yooden Exp $ # # You may have to select the ANSI C compiler here #CC=gcc #CC=/opt/SUNWspro/bin/cc CC=cc AR=ar # For editres, add -DEDITRES to CFLAGS and -lXmu to LIBS # For Solaris 2.4, add -DDONT_USE_GLOB # On older Solaris systems, Motif may be in /opt/SUNWmotif or even in # /usr/local. Some Solaris versions require explicit -I/usr/include # as the first include directory. # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # #CFLAGS=-g -I/usr/openwin/include -I/usr/dt/include \ # -DUSE_DIRENT -DROWCOLPATCH -DNO_XMIM CFLAGS=-O -I/usr/openwin/include -I/opt/SUNWmotif/include -DUSE_DIRENT -DNO_XMIM ARFLAGS=-urs LIBS= -L/usr/lib -L/usr/openwin/lib -L/usr/dt/lib -lm -lXm -lXt -lX11 \ -lsocket -lnsl -R /usr/openwin/lib -R /usr/dt/lib -R /usr/ucblib #LIBS= -L/usr/openwin/lib -L/opt/SUNWmotif/lib -lm -lXm \ # -lXt -lX11 -lgen -R /usr/openwin/lib include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.solarisx860000644000175000017500000000122610075362744017544 0ustar paulpaul# $Id: Makefile.solarisx86,v 1.1 2004/07/15 02:03:16 yooden Exp $ # # Solaris x86 makefile # CC=gcc AR=ar # For editres, add -DEDITRES to CFLAGS and -lXmu to LIBS # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -I/usr/openwin/include -I/usr/dt/include -DUSE_DIRENT ARFLAGS=-urs LIBS= -L/usr/lib -L/usr/openwin/lib -L/usr/dt/lib -lm -lXm -lXt -lX11 \ -lsocket -lnsl -R /usr/openwin/lib -R /usr/dt/lib include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.sunos0000644000175000017500000000104007662273214016664 0ustar paulpaul# $Id: Makefile.sunos,v 1.5 2003/05/20 00:27:56 n8gray Exp $ CC=/usr/lang/acc AR=/usr/5bin/ar # For editres, add -DEDITRES to CFLAGS and -lXmu to LIBS # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -DSUNOS -DUSE_LPR_PRINT_CMD -DUSE_MOTIF_GLOB ARFLAGS=-urs LIBS= -lm -Bstatic -lXm -lXt -lX11 include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.superux0000644000175000017500000000121707662273214017236 0ustar paulpaul# # $Id: Makefile.superux,v 1.5 2003/05/20 00:27:56 n8gray Exp $ # NEdit Makefile for NEC SUPER-UX # # CC=/bin/cc # CC=/usr/bin/cc CC=cc AR=ar # # The -hansi flag forces ANSI compilation, even # though ANSI should be the compiler default anyway # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -hansi -DUSE_DIRENT -DUSE_MOTIF_GLOB ARFLAGS=-urs BIGGER_STRINGS= LIBS=-lm -lXm -lXt -lX11 -lSM -lICE -lgen include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.uhc0000644000175000017500000000072607662273214016306 0ustar paulpaul# $Id: Makefile.uhc,v 1.5 2003/05/20 00:27:56 n8gray Exp $ # Makefile for UHC Unix # # Thanks to peter@stella.nmti.co CC=/usr/ucb/cc AR=ar # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O LIBS=-lm -lXm -lXt -lX11 -lgen include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.ultrix0000644000175000017500000000071207662273214017051 0ustar paulpaul# $Id: Makefile.ultrix,v 1.5 2003/05/20 00:27:56 n8gray Exp $ CC=cc AR=ar # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -DUSE_MOTIF_GLOB ARFLAGS=-urs BIGGER_STRINGS= -Wf,-XNl8192 LIBS=-lm -lXm -lXt -lX11 include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.unicos0000644000175000017500000000101207662273214017014 0ustar paulpaul# $Id: Makefile.unicos,v 1.7 2003/05/20 00:27:56 n8gray Exp $ # Makefile for Cray Unicos # # Thanks to Osman Buyukisik CC=cc AR=ar # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-DUSE_DIRENT -DUNICOS -DMAXPATHLEN=1023 BIGGER_STRINGS= LIBS= -lXm -lXt -lX11 -lSM -lICE -lm include Makefile.common verify_config: nedit-5.6.orig/makefiles/Makefile.unixware0000644000175000017500000000105107662273214017361 0ustar paulpaul# $Id: Makefile.unixware,v 1.6 2003/05/20 00:27:56 n8gray Exp $ CC=/usr/ccs/bin/cc AR=ar # For editres, add -DEDITRES to CFLAGS and -lXmu to LIBS # # To evaluate an alternative layout for the Replace/Find dialog, add # -DREPLACE_SCOPE to the CFLAGS. See the README file for more information. # # To test if the Motif library exports the runtime version # add -DHAVE__XMVERSIONSTRING to CFLAGS # CFLAGS=-O -I/usr/X/include -DUSE_DIRENT -DROWCOLPATCH LIBS= -L/usr/X/lib -lXm -lXt -lX11 -lSM -lICE -lgen -lnsl -lm include Makefile.common verify_config: nedit-5.6.orig/makefiles/buildvms.com0000644000175000017500000003653010506462720016410 0ustar paulpaul$! $Id: buildvms.com,v 1.2 2006/09/27 11:51:44 michaelsmith Exp $ $! $! VMS procedure to compile and link modules for NEdit $! $! $! In case of problems with the install you might contact me at $! zinser@zinser.no-ip.info(preferred) or $! zinser@sysdev.deutsche-boerse.com (work) $! $! Make procedure history for NEdit $! $!------------------------------------------------------------------------------ $! Version history $! 0.01 20040229 First version to receive a number $! 0.02 20041109 Init s_case for case sensitive shareable images $! 0.03 20041229 Some more config info (tconfig, conf_check_string) $! 0.04 20050105 Add check for MMS/MMK, does not hurt even for pure DCL build $! 0.05 20060105 Merge in improvements by Michael Smith from NEdit CVS $! $ ON ERROR THEN GOTO err_exit $ true = 1 $ false = 0 $ tmpnam = "temp_" + f$getjpi("","pid") $ tt = tmpnam + ".txt" $ tc = tmpnam + ".c" $ th = tmpnam + ".h" $ define tconfig 'th' $ its_decc = false $ its_vaxc = false $ its_gnuc = false $ s_case = False $ ver_no = "" $! $! Setup variables holding "config" information $! $ Make = "" $ ccopt = "" $ lopts = "" $ dnsrl = "" $ aconf_in_file = "config.hin" $ conf_check_string = "" $ name = "NEdit" $! $ gosub find_ver $! $ whoami = f$parse(f$enviornment("Procedure"),,,,"NO_CONCEAL") $ mydef = F$parse(whoami,,,"DEVICE") $ mydir = f$parse(whoami,,,"DIRECTORY") - "][" $ myproc = f$parse(whoami,,,"Name") + f$parse(whoami,,,"type") $ xmldir = mydef + mydir - ".MAKEFILES]" + ".MICROLINE.XML]" $ startdir = mydef + mydir - ".MAKEFILES]" +"]" $ target = "" $! $! Check for MMK/MMS $! $ If F$Search ("Sys$System:MMS.EXE") .nes. "" Then Make = "MMS" $ If F$Type (MMK) .eqs. "STRING" Then Make = "MMK" $! $ gosub check_opts $! $! Default is to build NEdit. $! If requested do cleanup, create dist, then exit $! $ if (target .nes. "") $ then $ gosub 'target' $ exit $ endif $ gosub check_compiler $! $ if (its_decc) then ccopt = ccopt + "/prefix=all" $ if f$length(make) .gt. 0 $ then $ gosub crea_mms $ set def [.util] $ 'make' $ set def [-.microline.xml] $ 'make' $ set def [--.xlt] $ 'make' $ set def [-.source] $ 'make' $ set def [-] $ else $ DEFINE SYS DECC$LIBRARY_INCLUDE $ DEFINE XM DECW$INCLUDE $ DEFINE X11 DECW$INCLUDE $ DEFINE XML 'xmldir' $ set def [.util] $ if f$search("LIBNUTIL.OLB") .eqs. "" then library/create/object libNUtil.olb $ if f$search("VMSUTILS.OLB") .eqs. "" then library/create/object vmsutils.olb $ cflags = ccopt $ call COMPILE CLEARCASE libNUtil $ call COMPILE DIALOGF libNUtil $ call COMPILE FILEUTILS libNUtil $ call COMPILE GETFILES libNUtil $ call COMPILE MISC libNUtil $ call COMPILE PREFFILE libNUtil $ call COMPILE PRINTUTILS libNUtil $ call COMPILE FONTSEL libNUtil $ call COMPILE MANAGEDLIST libNUtil $ call COMPILE MOTIF libNUtil $ call COMPILE UTILS libNUtil $ call COMPILE VMSUTILS vmsutils $ set def [-.microline.xml] $ if f$search("libXmL.OLB") .eqs. "" then library/create/object libXmL.olb $ call COMPILE Folder libXmL $ call COMPILE Grid libXmL $ call COMPILE GridUtil libXmL $ call COMPILE Progress libXmL $ call COMPILE Tree libXmL $ call COMPILE XmL libXmL $ set def [--.xlt] $ cflags = ccopt + "/include=[]" $ if f$search("libXlt.OLB") .eqs. "" then library/create/object libXlt.olb $ call COMPILE BubbleButton libXlt $ call COMPILE SlideC libXlt $ set def [-.source] $ cflags = ccopt + "/DEFINE=(USE_ACCESS)/include=[-.xlt]" $ call COMPILE SELECTION $ call COMPILE FILE $ call COMPILE HELP $ call COMPILE MENU $ call COMPILE NEDIT $ call COMPILE PREFERENCES $ call COMPILE REGULAREXP $ call COMPILE SEARCH $ call COMPILE SHIFT $ call COMPILE TAGS $ call COMPILE UNDO $ call COMPILE WINDOW $ call COMPILE USERCMDS $ call COMPILE MACRO $ call COMPILE TEXT $ call COMPILE TEXTSEL $ call COMPILE TEXTDISP $ call COMPILE TEXTBUF $ call COMPILE TEXTDRAG $ call COMPILE SERVER $ call COMPILE HIGHLIGHT $ call COMPILE HIGHLIGHTDATA $ call COMPILE INTERPRET $ call COMPILE SMARTINDENT $ call COMPILE REGEXCONVERT $ call COMPILE RBTREE $ call COMPILE WINDOWTITLE $ call COMPILE LINKDATE $ call COMPILE CALLTIPS $ call COMPILE RANGESET $ call COMPILE SERVER_COMMON $ ! $ if f$search("PARSE.C") .nes. "" then DELETE PARSE.C;* $ COPY PARSE_NOYACC.C PARSE.C $ call COMPILE PARSE $ ! $ call COMPILE NC $ OBJS := nedit, file, menu, window, selection, search, undo, shift, - help, preferences, tags, userCmds, regularExp, macro, text, - textSel, textDisp, textBuf, textDrag, server, highlight, - highlightData, interpret, parse, smartIndent, regexconvert, - rbTree, windowtitle, linkdate, calltips, rangeset, server_common $ LINK 'lopts' 'OBJS', NEDIT_OPTIONS_FILE/OPT, - [-.microline.xml]libxml/lib, [-.xlt]libXlt/lib, - [-.util]vmsUtils/lib, libNUtil/lib $ LINK 'lopts' nc, server_common.obj, NEDIT_OPTIONS_FILE/OPT, - [-.util]vmsUtils/lib, libNUtil/lib $ set def 'startdir' $ endif $ if f$type(dnrsl) .eqs. "STRING" then - define decc$no_rooted_search_lists 'dnrsl' $ exit $CC_ERR: $ write sys$output "C compiler required to build ''name'" $ goto err_exit $ERR_EXIT: $ if f$type(dnrsl) .eqs. "STRING" then - define decc$no_rooted_search_lists 'dnrsl' $ close/nolog ver_h $ write sys$output "Error building ''name'. Exiting..." $ exit 2 $!------------------------------------------------------------------------------ $! $! If MMS/MMK are available dump out the descrip.mms if required $! $CREA_MMS: $ write sys$output "Creating [.util]descrip.mms..." $ create [.util]descrip.mms $ open/append out [.util]descrip.mms $ write out "CFLAGS=", ccopt $ copy sys$input: out $ deck CC=cc AR=lib .FIRST DEFINE SYS DECC$LIBRARY_INCLUDE DEFINE XM DECW$INCLUDE DEFINE X11 DECW$INCLUDE OBJS = clearcase.obj, DialogF.obj, getfiles.obj, printUtils.obj, misc.obj,\ fileUtils.obj, prefFile.obj, fontsel.obj, managedlist.obj, utils.obj,\ motif.obj all : libNUtil.olb VMSUTILS.olb sh def libNUtil.olb : $(OBJS) $(AR) /CREATE/OBJ libNUtil.olb $(OBJS) VMSUTILS.olb : VMSUTILS.obj $(AR) /CREATE/OBJ VMSUTILS VMSUTILS $ eod $ close out $ write sys$output "Creating [.microline.xml]descrip.mms..." $ create [.microline.xml]descrip.mms $ open/append out [.microline.xml]descrip.mms $ write out "CFLAGS=", ccopt $ copy sys$input: out $ deck CC=cc AR=lib .FIRST DEFINE SYS DECC$LIBRARY_INCLUDE DEFINE XM DECW$INCLUDE DEFINE X11 DECW$INCLUDE $ eod $ write out " DEFINE XML ", xmldir $ copy sys$input: out $ deck OBJS = Folder.obj, Grid.obj, GridUtil.obj, Progress.obj, Tree.obj, XmL.obj all : libXmL.olb sh def libXmL.olb : $(OBJS) $(AR) /CREATE/OBJ libXmL.olb $(OBJS) $ eod $ close out $ write sys$output "Creating [.xlt]descrip.mms..." $ create [.xlt]descrip.mms $ open/append out [.xlt]descrip.mms $ write out "CFLAGS=", ccopt, "/include=[]" $ copy sys$input: out $ deck CC=cc AR=lib .FIRST DEFINE SYS DECC$LIBRARY_INCLUDE DEFINE XM DECW$INCLUDE DEFINE X11 DECW$INCLUDE OBJS = BubbleButton.obj, SlideC.obj all : libXlt.olb sh def libXlt.olb : $(OBJS) $(AR) /CREATE/OBJ libXlt.olb $(OBJS) $ eod $ close out $ write sys$output "Creating [.source]descrip.mms..." $ create [.source]descrip.mms $ open/append out [.source]descrip.mms $ write out "CFLAGS=", ccopt, "/define=(USE_ACCESS)/include=[-.xlt]" $ write out "LFLAGS=", lopts $ copy sys$input: out $ deck # # Makefile for VMS/MMS # CC=cc .FIRST DEFINE SYS DECC$LIBRARY_INCLUDE DEFINE XM DECW$INCLUDE DEFINE X11 DECW$INCLUDE $ eod $ write out " DEFINE XML ", xmldir $ copy sys$input: out $ deck copy parse_noyacc.c parse.c SRCS = nedit.c selection.c file.c help.c menu.c preferences.c regularExp.c\ search.c shift.c tags.c undo.c window.c userCmds.c macro.c text.c\ textSel.c textDisp.c textBuf.c textDrag.c server.c highlight.c\ highlightData.c interpret.c smartIndent.c parse.c nc.c regexconvert.c\ rbtree.c linkdate.c windowTitle.c calltips.c\ rangeset.c, server_common.c OBJS = selection.obj, file.obj, help.obj, menu.obj, preferences.obj, \ regularExp.obj, search.obj, shift.obj, tags.obj, undo.obj, window.obj,\ userCmds.obj, macro.obj, text.obj, textSel.obj, textDisp.obj,\ textBuf.obj, textDrag.obj, server.obj, highlight.obj,\ highlightData.obj, interpret.obj, smartIndent.obj, parse.obj,\ regexconvert.obj, rbtree.obj, linkdate.obj, windowTitle.obj, \ calltips.obj, rangeset.obj, server_common.obj NEOBJS = nedit.obj NCOBJS = nc.obj all : nedit.exe nc.exe @ write sys$output "Nedit build completed" nedit.exe : $(NEOBJS) $(OBJS) link/exe=nedit.exe $(NEOBJS),$(OBJS), NEDIT_OPTIONS_FILE/OPT, - [-.microline.xml]libxml/lib, [-.xlt]libXlt/lib, - [-.util]vmsUtils/lib, libNUtil.olb/lib nc.exe : $(NCOBJS) LINK $(NCOBJS), NEDIT_OPTIONS_FILE/OPT, - [-.util]vmsUtils/lib,libNUtil.olb/lib $ eod $ close out $ return $!------------------------------------------------------------------------------ $! $! Check command line options and set symbols accordingly $! $!------------------------------------------------------------------------------ $! Version history $! 0.01 20041206 First version to receive a number $ CHECK_OPTS: $ i = 1 $ OPT_LOOP: $ if i .lt. 9 $ then $ cparm = f$edit(p'i',"upcase") $! $! Check if parameter actually contains something $! $ if f$edit(cparm,"trim") .nes. "" $ then $ if cparm .eqs. "DEBUG" $ then $ ccopt = ccopt + "/noopt/deb" $ lopts = lopts + "/deb" $ endif $ if f$locate("CCOPT=",cparm) .lt. f$length(cparm) $ then $ start = f$locate("=",cparm) + 1 $ len = f$length(cparm) - start $ ccopt = ccopt + f$extract(start,len,cparm) $ if f$locate("AS_IS",f$edit(ccopt,"UPCASE")) .lt. f$length(ccopt) - then s_case = true $ endif $ if cparm .eqs. "LINK" then linkonly = true $ if f$locate("LOPTS=",cparm) .lt. f$length(cparm) $ then $ start = f$locate("=",cparm) + 1 $ len = f$length(cparm) - start $ lopts = lopts + f$extract(start,len,cparm) $ endif $ if f$locate("CC=",cparm) .lt. f$length(cparm) $ then $ start = f$locate("=",cparm) + 1 $ len = f$length(cparm) - start $ cc_com = f$extract(start,len,cparm) if (cc_com .nes. "DECC") .and. - (cc_com .nes. "VAXC") .and. - (cc_com .nes. "GNUC") $ then $ write sys$output "Unsupported compiler choice ''cc_com' ignored" $ write sys$output "Use DECC, VAXC, or GNUC instead" $ else $ if cc_com .eqs. "DECC" then its_decc = true $ if cc_com .eqs. "VAXC" then its_vaxc = true $ if cc_com .eqs. "GNUC" then its_gnuc = true $ endif $ endif $ if f$locate("MAKE=",cparm) .lt. f$length(cparm) $ then $ start = f$locate("=",cparm) + 1 $ len = f$length(cparm) - start $ mmks = f$extract(start,len,cparm) $ if (mmks .eqs. "MMK") .or. (mmks .eqs. "MMS") $ then $ make = mmks $ else $ write sys$output "Unsupported make choice ''mmks' ignored" $ write sys$output "Use MMK or MMS instead" $ endif $ endif $ if cparm .eqs. "CLEAN" then target = "CLEAN" $ if cparm .eqs. "DISTBIN" then target = "DISTBIN" $ endif $ i = i + 1 $ goto opt_loop $ endif $ return $!------------------------------------------------------------------------------ $! $! Look for the compiler used $! $! Version history $! 0.01 20040223 First version to receive a number $! 0.02 20040229 Save/set value of decc$no_rooted_search_lists $CHECK_COMPILER: $ if (.not. (its_decc .or. its_vaxc .or. its_gnuc)) $ then $ its_decc = (f$search("SYS$SYSTEM:DECC$COMPILER.EXE") .nes. "") $ its_vaxc = .not. its_decc .and. (F$Search("SYS$System:VAXC.Exe") .nes. "") $ its_gnuc = .not. (its_decc .or. its_vaxc) .and. (f$trnlnm("gnu_cc") .nes. "") $ endif $! $! Exit if no compiler available $! $ if (.not. (its_decc .or. its_vaxc .or. its_gnuc)) $ then goto CC_ERR $ else $ if its_decc $ then $ write sys$output "CC compiler check ... Compaq C" $ if f$trnlnm("decc$no_rooted_search_lists") .nes. "" $ then $ dnrsl = f$trnlnm("decc$no_rooted_search_lists") $ endif $ define decc$no_rooted_search_lists 1 $ else $ if its_vaxc then write sys$output "CC compiler check ... VAX C" $ if its_gnuc then write sys$output "CC compiler check ... GNU C" $ if f$trnlnm(topt) then write topt "sys$share:vaxcrtl.exe/share" $ if f$trnlnm(optf) then write optf "sys$share:vaxcrtl.exe/share" $ endif $ endif $ return $!------------------------------------------------------------------------------ $! $! Cleanup files created during compilation $! $CLEAN: $ delete/noconfirm/log [.util]*.obj;*,[.util]*.olb;*,[.util]*.mms;* $ delete/noconfirm/log [.Xlt]*.obj;*,[.Xlt]*.olb;*,[.Xlt]*.mms;* $ delete/noconfirm/log [.Microline.XmL]*.obj;*,[.Microline.XmL]*.olb;*,- [.Microline.XmL]*.mms;* $ delete/noconfirm/log [.source]*.obj;*,[.source]*.exe;*,[.source]*.mms;* $ return $!------------------------------------------------------------------------------ $! $! Create backup saveset with binaries and other files needed to run NEdit $! $DISTBIN: $ on error then continue $ arch = f$getsyi("arch_name") $ name_ver = - f$fao("!AS!AS_!AS",name,f$element(0,".",ver_no),f$element(0,".",ver_no)) $ purge/log [...] $ delete 'name_ver'-vms-'arch'.bck;* $ create/directory [.'name_ver'] $ set protection=w:rwed [-.'name_ver'...]*.*;* $ delete [.'name_ver'...]*.*;* $ delete [.'name_ver'...]*.*;* $ delete [.'name_ver'...]*.*;* $ delete [.'name_ver'...]*.*;* $ delete [.'name_ver'...]*.*;* $ delete [.'name_ver']*.*;* $ create/directory [.'name_ver'] $ copy [.source]nedit.exe [.'name_ver'] $ copy [.source]nc.exe [.'name_ver'] $ copy README [.'name_ver'] $ copy COPYRIGHT [.'name_ver'] $ copy ReleaseNotes [.'name_ver'] $ copy [.doc]NEDIT.DOC [.'name_ver'] $ copy [.doc]NEDIT.HTML [.'name_ver'] $ copy [.doc]NEDIT.MAN [.'name_ver'] $ copy [.doc]NC.MAN [.'name_ver'] $ copy [.doc]FAQ.TXT [.'name_ver'] $ backup/log [.'name_ver'...] 'name_ver'-vms-'arch'.bck/save_set $ return $!------------------------------------------------------------------------------ $! $! Check and find version of NEdit $! $FIND_VER: $ open/read ver_h [.source]help_data.h $FVLOOP: $ read/end=end_fvloop ver_h line $ if f$locate("NEditVersion",line) .nes. f$length(line) $ then $ ver_no = f$element(0,"\",f$element(1," ",f$element(1,"""",line))) $ goto end_fvloop $ endif $ goto fvloop $END_FVLOOP: $ close ver_h $ return $!------------------------------------------------------------------------------ $! $! Subroutine to compile a source file $! $compile: subroutine $ crdt = F$CVTIME(F$FILE_ATTRIBUTES("''p1'.c","RDT")) $ ordt = "" $ if f$search("''p1'.obj") .nes. "" then - ordt = F$CVTIME(F$FILE_ATTRIBUTES("''p1'.obj","RDT")) $ if "''crdt'" .gts. "''ordt'" $ then $ write sys$output "Compiling ", p1 $ cc 'cflags' /object='p1' 'p1'.c $ if p2 .nes."" then library/replace/object 'p2'.olb 'p1'.obj $ endif $ exit $ endsubroutine $!------------------------------------------------------------------------------ nedit-5.6.orig/source/0000755000175000017500000000000011110456100013377 5ustar paulpaulnedit-5.6.orig/source/Makefile.common0000644000175000017500000000336210027322764016350 0ustar paulpaul# $Id: Makefile.common,v 1.17 2004/03/21 14:25:56 tksoh Exp $ # Platform independent part of make procedure for NEdit directory, # included by machine specific makefiles. # OBJS = nedit.o file.o menu.o window.o selection.o search.o undo.o shift.o \ help.o preferences.o tags.o userCmds.o shell.o regularExp.o macro.o \ text.o textSel.o textDisp.o textBuf.o textDrag.o server.o highlight.o \ highlightData.o interpret.o parse.o smartIndent.o regexConvert.o \ rbTree.o windowTitle.o calltips.o server_common.o rangeset.o XLTLIB = ../Xlt/libXlt.a XMLLIB = ../Microline/XmL/libXmL.a .c.o: $(CC) -c -I../Microline -I../Xlt $(CFLAGS) -o $@ $< all: nedit nc # Note there is no depedency for linkdate.c/o. This is intentional, # we only want natural rebuilds to regenerate the link date. nedit: $(OBJS) ../util/libNUtil.a $(XMLLIB) $(XLTLIB) $(CC) $(CFLAGS) -c linkdate.c $(CC) $(CFLAGS) $(OBJS) linkdate.o $(XMLLIB) \ $(XLTLIB) ../util/libNUtil.a $(LIBS) -o $@ # Note LIBS isn't quite right here; it links unnecessarily against Motif nc: nc.o server_common.o ../util/libNUtil.a $(CC) $(CFLAGS) nc.o server_common.o ../util/libNUtil.a $(LIBS) -o $@ help.o: help.c $(CC) $(CFLAGS) $(BIGGER_STRINGS) -c help.c -o $@ smartIndent.o: smartIndent.c $(CC) $(CFLAGS) $(BIGGER_STRINGS) -c smartIndent.c -o $@ highlightData.o: highlightData.c $(CC) $(CFLAGS) $(BIGGER_STRINGS) -c highlightData.c -o $@ clean: rm -f $(OBJS) nedit nc nc.o parse.c linkdate.o parse.c: parse.y @echo "NOTE: Don't worry about 'command not found' errors here" @echo " unless you have changed the parse.y file." bison -o parse.c parse.y || ( yacc parse.y && mv y.tab.c parse.c ) || \ cp parse_noyacc.c parse.c # Get the dependencies for all objects include Makefile.dependencies nedit-5.6.orig/source/Makefile.dependencies0000644000175000017500000001176607654533201017517 0ustar paulpaul# $Id: Makefile.dependencies,v 1.21 2003/05/02 18:18:41 edg Exp $ calltips.o: calltips.c text.h textBuf.h textP.h textDisp.h calltips.h \ nedit.h ../util/misc.h file.o: file.c file.h nedit.h textBuf.h text.h window.h preferences.h \ undo.h menu.h tags.h server.h ../util/misc.h ../util/DialogF.h \ ../util/fileUtils.h ../util/getfiles.h ../util/printUtils.h \ ../util/utils.h help.o: help.c help.h help_topic.h textBuf.h text.h textP.h textDisp.h \ textSel.h nedit.h search.h window.h preferences.h help_data.h file.h \ highlight.h ../util/misc.h ../util/DialogF.h ../util/system.h highlight.o: highlight.c highlight.h nedit.h textBuf.h textDisp.h text.h \ textP.h regularExp.h highlightData.h preferences.h window.h \ ../util/misc.h ../util/DialogF.h highlightData.o: highlightData.c highlightData.h nedit.h textBuf.h \ highlight.h regularExp.h preferences.h help.h help_topic.h window.h \ regexConvert.h ../util/misc.h ../util/DialogF.h ../util/managedList.h interpret.o: interpret.c interpret.h nedit.h textBuf.h rbTree.h menu.h \ text.h linkdate.o: linkdate.c macro.o: macro.c macro.h nedit.h textBuf.h text.h window.h preferences.h \ interpret.h rbTree.h parse.h search.h server.h shell.h smartIndent.h \ userCmds.h selection.h tags.h calltips.h textDisp.h ../util/DialogF.h \ ../util/misc.h ../util/fileUtils.h ../util/utils.h highlight.h \ highlightData.h rangeset.h menu.o: menu.c menu.h nedit.h textBuf.h text.h file.h window.h search.h \ selection.h undo.h shift.h help.h help_topic.h preferences.h tags.h \ userCmds.h shell.h macro.h highlight.h highlightData.h interpret.h \ rbTree.h smartIndent.h windowTitle.h ../util/getfiles.h \ ../util/DialogF.h ../util/misc.h ../util/fileUtils.h ../util/utils.h nc.o: nc.c server_common.h ../util/fileUtils.h ../util/utils.h \ ../util/prefFile.h ../util/system.h ../util/clearcase.h nedit.o: nedit.c nedit.h textBuf.h file.h preferences.h regularExp.h \ selection.h tags.h menu.h macro.h server.h window.h interpret.h \ rbTree.h parse.h help.h help_topic.h ../util/misc.h \ ../util/printUtils.h ../util/fileUtils.h ../util/getfiles.h parse_noyacc.o: parse_noyacc.c parse.h interpret.h nedit.h textBuf.h \ rbTree.h preferences.o: preferences.c preferences.h nedit.h textBuf.h text.h \ search.h window.h userCmds.h highlight.h highlightData.h help.h \ help_topic.h regularExp.h smartIndent.h windowTitle.h server.h tags.h \ ../util/prefFile.h ../util/misc.h ../util/DialogF.h \ ../util/managedList.h ../util/fontsel.h ../util/fileUtils.h \ ../util/utils.h ../util/clearcase.h rangeset.o: rangeset.c textBuf.h textDisp.h rangeset.h rbTree.o: rbTree.c rbTree.h regexConvert.o: regexConvert.c regexConvert.h regularExp.o: regularExp.c regularExp.h search.o: search.c search.h nedit.h textBuf.h regularExp.h text.h \ server.h window.h preferences.h file.h highlight.h ../util/DialogF.h \ ../util/misc.h selection.o: selection.c selection.h nedit.h textBuf.h text.h file.h \ window.h menu.h server.h ../util/DialogF.h ../util/fileUtils.h server.o: server.c server.h window.h nedit.h textBuf.h file.h selection.h \ macro.h menu.h preferences.h server_common.h ../util/fileUtils.h \ ../util/utils.h server_common.o: server_common.c textBuf.h nedit.h server_common.h \ ../util/utils.h shell.o: shell.c shell.h nedit.h textBuf.h text.h window.h preferences.h \ file.h macro.h interpret.h rbTree.h ../util/DialogF.h ../util/misc.h shift.o: shift.c shift.h nedit.h textBuf.h text.h window.h smartIndent.o: smartIndent.c smartIndent.h nedit.h textBuf.h text.h \ preferences.h interpret.h rbTree.h macro.h window.h parse.h shift.h \ help.h help_topic.h ../util/DialogF.h ../util/misc.h tags.o: tags.c tags.h nedit.h textBuf.h text.h window.h file.h \ preferences.h search.h selection.h calltips.h textDisp.h \ ../util/DialogF.h ../util/fileUtils.h ../util/misc.h ../util/utils.h text.o: text.c text.h textBuf.h textP.h textDisp.h textSel.h textDrag.h \ nedit.h calltips.h textBuf.o: textBuf.c textBuf.h rangeset.h textDisp.o: textDisp.c textDisp.h textBuf.h text.h textP.h nedit.h \ calltips.h highlight.h rangeset.h textDrag.o: textDrag.c textDrag.h text.h textBuf.h textDisp.h textP.h textSel.o: textSel.c textSel.h textP.h textBuf.h textDisp.h text.h undo.o: undo.c undo.h nedit.h textBuf.h text.h search.h window.h file.h \ userCmds.h preferences.h userCmds.o: userCmds.c userCmds.h nedit.h textBuf.h text.h preferences.h \ window.h menu.h shell.h macro.h file.h interpret.h rbTree.h parse.h \ ../util/DialogF.h ../util/misc.h ../util/managedList.h window.o: window.c window.h nedit.h textBuf.h textSel.h text.h textDisp.h \ textP.h menu.h file.h search.h undo.h preferences.h selection.h \ server.h shell.h macro.h highlight.h smartIndent.h userCmds.h nedit.bm \ n.bm windowTitle.h ../util/clearcase.h ../util/misc.h \ ../util/fileUtils.h ../util/utils.h windowTitle.o: windowTitle.c windowTitle.h nedit.h textBuf.h \ preferences.h help.h help_topic.h ../util/prefFile.h ../util/misc.h \ ../util/DialogF.h ../util/utils.h ../util/fileUtils.h \ ../util/clearcase.h nedit-5.6.orig/source/calltips.c0000644000175000017500000002672710737527366015427 0ustar paulpaul/******************************************************************************* * * * calltips.c -- Calltip UI functions (calltip *file* functions are in tags.c) * * * * Copyright (C) 2002 Nathaniel Gray * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * April, 1997 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "text.h" #include "textP.h" #include "calltips.h" #include "../util/misc.h" #include #include #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif static char *expandAllTabs( char *text, int tab_width ); /* ** Pop-down a calltip if one exists, else do nothing */ void KillCalltip(WindowInfo *window, int calltipID) { textDisp *textD = ((TextWidget)window->lastFocus)->text.textD; TextDKillCalltip( textD, calltipID ); } void TextDKillCalltip(textDisp *textD, int calltipID) { if( textD->calltip.ID == 0 ) return; if( calltipID == 0 || calltipID == textD->calltip.ID ) { XtPopdown( textD->calltipShell ); textD->calltip.ID = 0; } } /* ** Is a calltip displayed? Returns the calltip ID of the currently displayed ** calltip, or 0 if there is no calltip displayed. If called with ** calltipID != 0, returns 0 unless there is a calltip being ** displayed with that calltipID. */ int GetCalltipID(WindowInfo *window, int calltipID) { textDisp *textD = ((TextWidget)window->lastFocus)->text.textD; if( calltipID == 0 ) return textD->calltip.ID; else { if( calltipID == textD->calltip.ID) return calltipID; else return 0; } } #define CALLTIP_EDGE_GUARD 5 static Boolean offscreenV(XWindowAttributes *screenAttr, int top, int height) { return (top < CALLTIP_EDGE_GUARD || top + height >= screenAttr->height - CALLTIP_EDGE_GUARD); } /* ** Update the position of the current calltip if one exists, else do nothing */ void TextDRedrawCalltip(textDisp *textD, int calltipID) { int lineHeight = textD->ascent + textD->descent; Position txtX, txtY, borderWidth, abs_x, abs_y, tipWidth, tipHeight; XWindowAttributes screenAttr; int rel_x, rel_y, flip_delta; if( textD->calltip.ID == 0 ) return; if( calltipID != 0 && calltipID != textD->calltip.ID ) return; /* Get the location/dimensions of the text area */ XtVaGetValues(textD->w, XmNx, &txtX, XmNy, &txtY, NULL); if( textD->calltip.anchored ) { /* Put it at the anchor position */ if (!TextDPositionToXY(textD, textD->calltip.pos, &rel_x, &rel_y)) { if (textD->calltip.alignMode == TIP_STRICT) TextDKillCalltip(textD, textD->calltip.ID); return; } } else { if (textD->calltip.pos < 0) { /* First display of tip with cursor offscreen (detected in ShowCalltip) */ textD->calltip.pos = textD->width/2; textD->calltip.hAlign = TIP_CENTER; rel_y = textD->height/3; } else if (!TextDPositionToXY(textD, textD->cursorPos, &rel_x, &rel_y)){ /* Window has scrolled and tip is now offscreen */ if (textD->calltip.alignMode == TIP_STRICT) TextDKillCalltip(textD, textD->calltip.ID); return; } rel_x = textD->calltip.pos; } XtVaGetValues(textD->calltipShell, XmNwidth, &tipWidth, XmNheight, &tipHeight, XmNborderWidth, &borderWidth, NULL); rel_x += borderWidth; rel_y += lineHeight/2 + borderWidth; /* Adjust rel_x for horizontal alignment modes */ if (textD->calltip.hAlign == TIP_CENTER) rel_x -= tipWidth/2; else if (textD->calltip.hAlign == TIP_RIGHT) rel_x -= tipWidth; /* Adjust rel_y for vertical alignment modes */ if (textD->calltip.vAlign == TIP_ABOVE) { flip_delta = tipHeight + lineHeight + 2*borderWidth; rel_y -= flip_delta; } else flip_delta = -(tipHeight + lineHeight + 2*borderWidth); XtTranslateCoords(textD->w, rel_x, rel_y, &abs_x, &abs_y); /* If we're not in strict mode try to keep the tip on-screen */ if (textD->calltip.alignMode == TIP_SLOPPY) { XGetWindowAttributes(XtDisplay(textD->w), RootWindowOfScreen(XtScreen(textD->w)), &screenAttr); /* make sure tip doesn't run off right or left side of screen */ if (abs_x + tipWidth >= screenAttr.width - CALLTIP_EDGE_GUARD) abs_x = screenAttr.width - tipWidth - CALLTIP_EDGE_GUARD; if (abs_x < CALLTIP_EDGE_GUARD) abs_x = CALLTIP_EDGE_GUARD; /* Try to keep the tip onscreen vertically if possible */ if (screenAttr.height > tipHeight && offscreenV(&screenAttr, abs_y, tipHeight)) { /* Maybe flipping from below to above (or vice-versa) will help */ if (!offscreenV(&screenAttr, abs_y + flip_delta, tipHeight)) abs_y += flip_delta; /* Make sure the tip doesn't end up *totally* offscreen */ else if (abs_y + tipHeight < 0) abs_y = CALLTIP_EDGE_GUARD; else if (abs_y >= screenAttr.height) abs_y = screenAttr.height - tipHeight - CALLTIP_EDGE_GUARD; /* If no case applied, just go with the default placement. */ } } XtVaSetValues( textD->calltipShell, XmNx, abs_x, XmNy, abs_y, NULL ); } /* ** Returns a new string with each \t replaced with tab_width spaces or ** a pointer to text if there were no tabs. Returns NULL on malloc failure. ** Note that this is dumb replacement, not smart tab-like behavior! The goal ** is to prevent tabs from turning into squares in calltips, not to get the ** formatting just right. */ static char *expandAllTabs( char *text, int tab_width ) { int i, nTabs=0; size_t len; char *c, *cCpy, *textCpy; /* First count 'em */ for( c = text; *c; ++c ) if( *c == '\t' ) ++nTabs; if( nTabs == 0 ) return text; /* Allocate the new string */ len = strlen( text ) + ( tab_width - 1 )*nTabs; textCpy = (char*)malloc( len + 1 ); if( !textCpy ) { fprintf(stderr, "nedit: Out of heap memory in expandAllTabs!\n"); return NULL; } /* Now replace 'em */ for( c = text, cCpy = textCpy; *c; ++c, ++cCpy) { if( *c == '\t' ) { for( i = 0; i < tab_width; ++i, ++cCpy ) *cCpy = ' '; --cCpy; /* Will be incremented in outer for loop */ } else *cCpy = *c; } *cCpy = '\0'; return textCpy; } /* ** Pop-up a calltip. ** If a calltip is already being displayed it is destroyed and replaced with ** the new calltip. Returns the ID of the calltip or 0 on failure. */ int ShowCalltip(WindowInfo *window, char *text, Boolean anchored, int pos, int hAlign, int vAlign, int alignMode) { static int StaticCalltipID = 1; textDisp *textD = ((TextWidget)window->lastFocus)->text.textD; int rel_x, rel_y; Position txtX, txtY; char *textCpy; XmString str; /* Destroy any previous calltip */ TextDKillCalltip( textD, 0 ); /* Make sure the text isn't NULL */ if (text == NULL) return 0; /* Expand any tabs in the calltip and make it an XmString */ textCpy = expandAllTabs( text, BufGetTabDistance(textD->buffer) ); if( textCpy == NULL ) return 0; /* Out of memory */ str = XmStringCreateLtoR(textCpy, XmFONTLIST_DEFAULT_TAG); if( textCpy != text ) free( textCpy ); /* Get the location/dimensions of the text area */ XtVaGetValues(textD->w, XmNx, &txtX, XmNy, &txtY, NULL); /* Create the calltip widget on first request */ if (textD->calltipW == NULL) { Arg args[10]; int argcnt = 0; XtSetArg(args[argcnt], XmNsaveUnder, True); argcnt++; XtSetArg(args[argcnt], XmNallowShellResize, True); argcnt++; textD->calltipShell = CreatePopupShellWithBestVis("calltipshell", overrideShellWidgetClass, textD->w, args, argcnt); /* Might want to make this a read-only XmText eventually so that users can copy from it */ textD->calltipW = XtVaCreateManagedWidget( "calltip", xmLabelWidgetClass, textD->calltipShell, XmNborderWidth, 1, /* Thin borders */ XmNhighlightThickness, 0, XmNalignment, XmALIGNMENT_BEGINNING, XmNforeground, textD->calltipFGPixel, XmNbackground, textD->calltipBGPixel, NULL ); } /* Set the text on the label */ XtVaSetValues( textD->calltipW, XmNlabelString, str, NULL ); XmStringFree( str ); /* Figure out where to put the tip */ if (anchored) { /* Put it at the specified position */ /* If position is not displayed, return 0 */ if (pos < textD->firstChar || pos > textD->lastChar ) { XBell(TheDisplay, 0); return 0; } textD->calltip.pos = pos; } else { /* Put it next to the cursor, or in the center of the window if the cursor is offscreen and mode != strict */ if (!TextDPositionToXY(textD, textD->cursorPos, &rel_x, &rel_y)) { if (alignMode == TIP_STRICT) { XBell(TheDisplay, 0); return 0; } textD->calltip.pos = -1; } else /* Store the x-offset for use when redrawing */ textD->calltip.pos = rel_x; } /* Should really bounds-check these enumerations... */ textD->calltip.ID = StaticCalltipID; textD->calltip.anchored = anchored; textD->calltip.hAlign = hAlign; textD->calltip.vAlign = vAlign; textD->calltip.alignMode = alignMode; /* Increment the static calltip ID. Macro variables can only be int, not unsigned, so have to work to keep it > 0 on overflow */ if(++StaticCalltipID <= 0) StaticCalltipID = 1; /* Realize the calltip's shell so that its width & height are known */ XtRealizeWidget( textD->calltipShell ); /* Move the calltip and pop it up */ TextDRedrawCalltip(textD, 0); XtPopup( textD->calltipShell, XtGrabNone ); return textD->calltip.ID; } nedit-5.6.orig/source/calltips.h0000644000175000017500000000547010737527367015425 0ustar paulpaul/* $Id: calltips.h,v 1.5 2008/01/04 22:11:03 yooden Exp $ */ /******************************************************************************* * * * calltips.h -- Nirvana Editor Calltips Header File * * * * Copyright 2004 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_CALLTIPS_H_INCLUDED #define NEDIT_CALLTIPS_H_INCLUDED #include "nedit.h" /* For WindowInfo */ #include "textDisp.h" /* for textDisp */ #define NEDIT_DEFAULT_CALLTIP_FG "black" #define NEDIT_DEFAULT_CALLTIP_BG "LemonChiffon1" enum TipHAlignMode {TIP_LEFT, TIP_CENTER, TIP_RIGHT}; enum TipVAlignMode {TIP_ABOVE, TIP_BELOW}; enum TipAlignStrict {TIP_SLOPPY, TIP_STRICT}; int ShowCalltip(WindowInfo *window, char *text, Boolean anchored, int pos, int hAlign, int vAlign, int alignMode); void KillCalltip(WindowInfo *window, int calltipID); void TextDKillCalltip(textDisp *textD, int calltipID); int GetCalltipID(WindowInfo *window, int calltipID); void TextDRedrawCalltip(textDisp *textD, int calltipID); #endif /* ifndef NEDIT_CALLTIPS_H_INCLUDED */ nedit-5.6.orig/source/file.c0000644000175000017500000021027711110456077014510 0ustar paulpaulstatic const char CVSID[] = "$Id: file.c,v 1.118.2.1 2008/11/05 09:17:20 lebert Exp $"; /******************************************************************************* * * * file.c -- Nirvana Editor file i/o * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * May 10, 1991 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "file.h" #include "textBuf.h" #include "text.h" #include "window.h" #include "preferences.h" #include "undo.h" #include "menu.h" #include "tags.h" #include "server.h" #include "interpret.h" #include "../util/misc.h" #include "../util/DialogF.h" #include "../util/fileUtils.h" #include "../util/getfiles.h" #include "../util/printUtils.h" #include "../util/utils.h" #include #include #include #include #include #include #ifdef VMS #include "../util/VMSparam.h" #include #include #include #else #include #include #ifndef __MVS__ #include #endif #include #endif /*VMS*/ #include #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif /* Maximum frequency in miliseconds of checking for external modifications. The periodic check is only performed on buffer modification, and the check interval is only to prevent checking on every keystroke in case of a file system which is slow to process stat requests (which I'm not sure exists) */ #define MOD_CHECK_INTERVAL 3000 static int doSave(WindowInfo *window); static void safeClose(WindowInfo *window); static int doOpen(WindowInfo *window, const char *name, const char *path, int flags); static void backupFileName(WindowInfo *window, char *name, size_t len); static int writeBckVersion(WindowInfo *window); static int bckError(WindowInfo *window, const char *errString, const char *file); static int fileWasModifiedExternally(WindowInfo *window); static const char *errorString(void); static void addWrapNewlines(WindowInfo *window); static void setFormatCB(Widget w, XtPointer clientData, XtPointer callData); static void addWrapCB(Widget w, XtPointer clientData, XtPointer callData); static int cmpWinAgainstFile(WindowInfo *window, const char *fileName); static int min(int i1, int i2); static void modifiedWindowDestroyedCB(Widget w, XtPointer clientData, XtPointer callData); static void forceShowLineNumbers(WindowInfo *window); #ifdef VMS void removeVersionNumber(char *fileName); #endif /*VMS*/ WindowInfo *EditNewFile(WindowInfo *inWindow, char *geometry, int iconic, const char *languageMode, const char *defaultPath) { char name[MAXPATHLEN]; WindowInfo *window; size_t pathlen; char *path; /*... test for creatability? */ /* Find a (relatively) unique name for the new file */ UniqueUntitledName(name); /* create new window/document */ if (inWindow) window = CreateDocument(inWindow, name); else window = CreateWindow(name, geometry, iconic); path = window->path; strcpy(window->filename, name); strcpy(path, (defaultPath && *defaultPath) ? defaultPath : GetCurrentDir()); pathlen = strlen(window->path); #ifndef VMS /* do we have a "/" at the end? if not, add one */ if (0 < pathlen && path[pathlen - 1] != '/' && pathlen < MAXPATHLEN - 1) { strcpy(&path[pathlen], "/"); } #else /* VMS */ /* A logical name should be followed by a colon so that the filename can be added to it to make a full file specification; otherwise a directory path had the form device_or_logicalname:[dir.dir.dir] this requires no separator before the file name. */ if (0 < pathlen && strchr(":]", path[pathlen - 1]) == NULL) { strcpy(&path[pathlen], ":"); /* could not find a separator at end */ } /* TODO: is this enough for VMS? what of posix emulation? */ /* TODO: what about other platforms? */ #endif /* VMS */ SetWindowModified(window, FALSE); CLEAR_ALL_LOCKS(window->lockReasons); UpdateWindowReadOnly(window); UpdateStatsLine(window); UpdateWindowTitle(window); RefreshTabState(window); if (languageMode == NULL) DetermineLanguageMode(window, True); else SetLanguageMode(window, FindLanguageMode(languageMode), True); ShowTabBar(window, GetShowTabBar(window)); if (iconic && IsIconic(window)) RaiseDocument(window); else RaiseDocumentWindow(window); SortTabBar(window); return window; } /* ** Open an existing file specified by name and path. Use the window inWindow ** unless inWindow is NULL or points to a window which is already in use ** (displays a file other than Untitled, or is Untitled but modified). Flags ** can be any of: ** ** CREATE: If file is not found, (optionally) prompt the ** user whether to create ** SUPPRESS_CREATE_WARN When creating a file, don't ask the user ** PREF_READ_ONLY Make the file read-only regardless ** ** If languageMode is passed as NULL, it will be determined automatically ** from the file extension or file contents. ** ** If bgOpen is True, then the file will be open in background. This ** works in association with the SetLanguageMode() function that has ** the syntax highlighting deferred, in order to speed up the file- ** opening operation when multiple files are being opened in succession. */ WindowInfo *EditExistingFile(WindowInfo *inWindow, const char *name, const char *path, int flags, char *geometry, int iconic, const char *languageMode, int tabbed, int bgOpen) { WindowInfo *window; char fullname[MAXPATHLEN]; /* first look to see if file is already displayed in a window */ window = FindWindowWithFile(name, path); if (window != NULL) { if (!bgOpen) { if (iconic) RaiseDocument(window); else RaiseDocumentWindow(window); } return window; } /* If an existing window isn't specified; or the window is already in use (not Untitled or Untitled and modified), or is currently busy running a macro; create the window */ if (inWindow == NULL) { window = CreateWindow(name, geometry, iconic); } else if (inWindow->filenameSet || inWindow->fileChanged || inWindow->macroCmdData != NULL) { if (tabbed) { window = CreateDocument(inWindow, name); } else { window = CreateWindow(name, geometry, iconic); } } else { /* open file in untitled document */ window = inWindow; strcpy(window->path, path); strcpy(window->filename, name); if (!iconic && !bgOpen) { RaiseDocumentWindow(window); } } /* Open the file */ if (!doOpen(window, name, path, flags)) { /* The user may have destroyed the window instead of closing the warning dialog; don't close it twice */ safeClose(window); return NULL; } forceShowLineNumbers(window); /* Decide what language mode to use, trigger language specific actions */ if (languageMode == NULL) DetermineLanguageMode(window, True); else SetLanguageMode(window, FindLanguageMode(languageMode), True); /* update tab label and tooltip */ RefreshTabState(window); SortTabBar(window); ShowTabBar(window, GetShowTabBar(window)); if (!bgOpen) RaiseDocument(window); /* Bring the title bar and statistics line up to date, doOpen does not necessarily set the window title or read-only status */ UpdateWindowTitle(window); UpdateWindowReadOnly(window); UpdateStatsLine(window); /* Add the name to the convenience menu of previously opened files */ strcpy(fullname, path); strcat(fullname, name); if(GetPrefAlwaysCheckRelTagsSpecs()) AddRelTagsFile(GetPrefTagFile(), path, TAG); AddToPrevOpenMenu(fullname); return window; } void RevertToSaved(WindowInfo *window) { char name[MAXPATHLEN], path[MAXPATHLEN]; int i; int insertPositions[MAX_PANES], topLines[MAX_PANES]; int horizOffsets[MAX_PANES]; int openFlags = 0; Widget text; /* Can't revert untitled windows */ if (!window->filenameSet) { DialogF(DF_WARN, window->shell, 1, "Error", "Window '%s' was never saved, can't re-read", "OK", window->filename); return; } /* save insert & scroll positions of all of the panes to restore later */ for (i=0; i<=window->nPanes; i++) { text = i==0 ? window->textArea : window->textPanes[i-1]; insertPositions[i] = TextGetCursorPos(text); TextGetScroll(text, &topLines[i], &horizOffsets[i]); } /* re-read the file, update the window title if new file is different */ strcpy(name, window->filename); strcpy(path, window->path); RemoveBackupFile(window); ClearUndoList(window); openFlags |= IS_USER_LOCKED(window->lockReasons) ? PREF_READ_ONLY : 0; if (!doOpen(window, name, path, openFlags)) { /* This is a bit sketchy. The only error in doOpen that irreperably damages the window is "too much binary data". It should be pretty rare to be reverting something that was fine only to find that now it has too much binary data. */ if (!window->fileMissing) safeClose(window); else { /* Treat it like an externally modified file */ window->lastModTime=0; window->fileMissing=FALSE; } return; } forceShowLineNumbers(window); UpdateWindowTitle(window); UpdateWindowReadOnly(window); /* restore the insert and scroll positions of each pane */ for (i=0; i<=window->nPanes; i++) { text = i==0 ? window->textArea : window->textPanes[i-1]; TextSetCursorPos(text, insertPositions[i]); TextSetScroll(text, topLines[i], horizOffsets[i]); } } /* ** Checks whether a window is still alive, and closes it only if so. ** Intended to be used when the file could not be opened for some reason. ** Normally the window is still alive, but the user may have closed the ** window instead of the error dialog. In that case, we shouldn't close the ** window a second time. */ static void safeClose(WindowInfo *window) { WindowInfo* p = WindowList; while(p) { if (p == window) { CloseWindow(window); return; } p = p->next; } } static int doOpen(WindowInfo *window, const char *name, const char *path, int flags) { char fullname[MAXPATHLEN]; struct stat statbuf; int fileLen, readLen; char *fileString, *c; FILE *fp = NULL; int fd; int resp; /* initialize lock reasons */ CLEAR_ALL_LOCKS(window->lockReasons); /* Update the window data structure */ strcpy(window->filename, name); strcpy(window->path, path); window->filenameSet = TRUE; window->fileMissing = TRUE; /* Get the full name of the file */ strcpy(fullname, path); strcat(fullname, name); /* Open the file */ #ifndef DONT_USE_ACCESS /* The only advantage of this is if you use clearcase, which messes up the mtime of files opened with r+, even if they're never actually written. To avoid requiring special builds for clearcase users, this is now the default. */ { if ((fp = fopen(fullname, "r")) != NULL) { if(access(fullname, W_OK) != 0) SET_PERM_LOCKED(window->lockReasons, TRUE); #else fp = fopen(fullname, "rb+"); if (fp == NULL) { /* Error opening file or file is not writeable */ fp = fopen(fullname, "rb"); if (fp != NULL) { /* File is read only */ SET_PERM_LOCKED(window->lockReasons, TRUE); #endif } else if (flags & CREATE && errno == ENOENT) { /* Give option to create (or to exit if this is the only window) */ if (!(flags & SUPPRESS_CREATE_WARN)) { /* on Solaris 2.6, and possibly other OSes, dialog won't show if parent window is iconized. */ RaiseShellWindow(window->shell, False); /* ask user for next action if file not found */ if (WindowList == window && window->next == NULL) { resp = DialogF(DF_WARN, window->shell, 3, "New File", "Can't open %s:\n%s", "New File", "Cancel", "Exit NEdit", fullname, errorString()); } else { resp = DialogF(DF_WARN, window->shell, 2, "New File", "Can't open %s:\n%s", "New File", "Cancel", fullname, errorString()); } if (resp == 2) { return FALSE; } else if (resp == 3) { exit(EXIT_SUCCESS); } } /* Test if new file can be created */ if ((fd = creat(fullname, 0666)) == -1) { DialogF(DF_ERR, window->shell, 1, "Error creating File", "Can't create %s:\n%s", "OK", fullname, errorString()); return FALSE; } else { #ifdef VMS /* get correct version number and close before removing */ getname(fd, fullname); #endif close(fd); remove(fullname); } SetWindowModified(window, FALSE); if ((flags & PREF_READ_ONLY) != 0) { SET_USER_LOCKED(window->lockReasons, TRUE); } UpdateWindowReadOnly(window); return TRUE; } else { /* A true error */ DialogF(DF_ERR, window->shell, 1, "Error opening File", "Could not open %s%s:\n%s", "OK", path, name, errorString()); return FALSE; } } /* Get the length of the file, the protection mode, and the time of the last modification to the file */ if (fstat(fileno(fp), &statbuf) != 0) { fclose(fp); window->filenameSet = FALSE; /* Temp. prevent check for changes. */ DialogF(DF_ERR, window->shell, 1, "Error opening File", "Error opening %s", "OK", name); window->filenameSet = TRUE; return FALSE; } if (S_ISDIR(statbuf.st_mode)) { fclose(fp); window->filenameSet = FALSE; /* Temp. prevent check for changes. */ DialogF(DF_ERR, window->shell, 1, "Error opening File", "Can't open directory %s", "OK", name); window->filenameSet = TRUE; return FALSE; } #ifdef S_ISBLK if (S_ISBLK(statbuf.st_mode)) { fclose(fp); window->filenameSet = FALSE; /* Temp. prevent check for changes. */ DialogF(DF_ERR, window->shell, 1, "Error opening File", "Can't open block device %s", "OK", name); window->filenameSet = TRUE; return FALSE; } #endif fileLen = statbuf.st_size; /* Allocate space for the whole contents of the file (unfortunately) */ fileString = (char *)malloc(fileLen+1); /* +1 = space for null */ if (fileString == NULL) { fclose(fp); window->filenameSet = FALSE; /* Temp. prevent check for changes. */ DialogF(DF_ERR, window->shell, 1, "Error while opening File", "File is too large to edit", "OK"); window->filenameSet = TRUE; return FALSE; } /* Read the file into fileString and terminate with a null */ readLen = fread(fileString, sizeof(char), fileLen, fp); if (ferror(fp)) { fclose(fp); window->filenameSet = FALSE; /* Temp. prevent check for changes. */ DialogF(DF_ERR, window->shell, 1, "Error while opening File", "Error reading %s:\n%s", "OK", name, errorString()); window->filenameSet = TRUE; free(fileString); return FALSE; } fileString[readLen] = 0; /* Close the file */ if (fclose(fp) != 0) { /* unlikely error */ DialogF(DF_WARN, window->shell, 1, "Error while opening File", "Unable to close file", "OK"); /* we read it successfully, so continue */ } /* Any errors that happen after this point leave the window in a "broken" state, and thus RevertToSaved will abandon the window if window->fileMissing is FALSE and doOpen fails. */ window->fileMode = statbuf.st_mode; window->fileUid = statbuf.st_uid; window->fileGid = statbuf.st_gid; window->lastModTime = statbuf.st_mtime; window->device = statbuf.st_dev; window->inode = statbuf.st_ino; window->fileMissing = FALSE; /* Detect and convert DOS and Macintosh format files */ if (GetPrefForceOSConversion()) { window->fileFormat = FormatOfFile(fileString); if (window->fileFormat == DOS_FILE_FORMAT) { ConvertFromDosFileString(fileString, &readLen, NULL); } else if (window->fileFormat == MAC_FILE_FORMAT) { ConvertFromMacFileString(fileString, readLen); } } /* Display the file contents in the text widget */ window->ignoreModify = True; BufSetAll(window->buffer, fileString); window->ignoreModify = False; /* Check that the length that the buffer thinks it has is the same as what we gave it. If not, there were probably nuls in the file. Substitute them with another character. If that is impossible, warn the user, make the file read-only, and force a substitution */ if (window->buffer->length != readLen) { if (!BufSubstituteNullChars(fileString, readLen, window->buffer)) { resp = DialogF(DF_ERR, window->shell, 2, "Error while opening File", "Too much binary data in file. You may view\n" "it, but not modify or re-save its contents.", "View", "Cancel"); if (resp == 2) { return FALSE; } SET_TMBD_LOCKED(window->lockReasons, TRUE); for (c = fileString; c < &fileString[readLen]; c++) { if (*c == '\0') { *c = (char) 0xfe; } } window->buffer->nullSubsChar = (char) 0xfe; } window->ignoreModify = True; BufSetAll(window->buffer, fileString); window->ignoreModify = False; } /* Release the memory that holds fileString */ free(fileString); /* Set window title and file changed flag */ if ((flags & PREF_READ_ONLY) != 0) { SET_USER_LOCKED(window->lockReasons, TRUE); } if (IS_PERM_LOCKED(window->lockReasons)) { window->fileChanged = FALSE; UpdateWindowTitle(window); } else { SetWindowModified(window, FALSE); if (IS_ANY_LOCKED(window->lockReasons)) { UpdateWindowTitle(window); } } UpdateWindowReadOnly(window); return TRUE; } int IncludeFile(WindowInfo *window, const char *name) { struct stat statbuf; int fileLen, readLen; char *fileString; FILE *fp = NULL; /* Open the file */ fp = fopen(name, "rb"); if (fp == NULL) { DialogF(DF_ERR, window->shell, 1, "Error opening File", "Could not open %s:\n%s", "OK", name, errorString()); return FALSE; } /* Get the length of the file */ if (fstat(fileno(fp), &statbuf) != 0) { DialogF(DF_ERR, window->shell, 1, "Error opening File", "Error opening %s", "OK", name); fclose(fp); return FALSE; } if (S_ISDIR(statbuf.st_mode)) { DialogF(DF_ERR, window->shell, 1, "Error opening File", "Can't open directory %s", "OK", name); fclose(fp); return FALSE; } fileLen = statbuf.st_size; /* allocate space for the whole contents of the file */ fileString = (char *)malloc(fileLen+1); /* +1 = space for null */ if (fileString == NULL) { DialogF(DF_ERR, window->shell, 1, "Error opening File", "File is too large to include", "OK"); fclose(fp); return FALSE; } /* read the file into fileString and terminate with a null */ readLen = fread(fileString, sizeof(char), fileLen, fp); if (ferror(fp)) { DialogF(DF_ERR, window->shell, 1, "Error opening File", "Error reading %s:\n%s", "OK", name, errorString()); fclose(fp); free(fileString); return FALSE; } fileString[readLen] = 0; /* Detect and convert DOS and Macintosh format files */ switch (FormatOfFile(fileString)) { case DOS_FILE_FORMAT: ConvertFromDosFileString(fileString, &readLen, NULL); break; case MAC_FILE_FORMAT: ConvertFromMacFileString(fileString, readLen); break; default: /* Default is Unix, no conversion necessary. */ break; } /* If the file contained ascii nulls, re-map them */ if (!BufSubstituteNullChars(fileString, readLen, window->buffer)) { DialogF(DF_ERR, window->shell, 1, "Error opening File", "Too much binary data in file", "OK"); } /* close the file */ if (fclose(fp) != 0) { /* unlikely error */ DialogF(DF_WARN, window->shell, 1, "Error opening File", "Unable to close file", "OK"); /* we read it successfully, so continue */ } /* insert the contents of the file in the selection or at the insert position in the window if no selection exists */ if (window->buffer->primary.selected) BufReplaceSelected(window->buffer, fileString); else BufInsert(window->buffer, TextGetCursorPos(window->lastFocus), fileString); /* release the memory that holds fileString */ free(fileString); return TRUE; } /* ** Close all files and windows, leaving one untitled window */ int CloseAllFilesAndWindows(void) { while (WindowList->next != NULL || WindowList->filenameSet || WindowList->fileChanged) { /* * When we're exiting through a macro, the document running the * macro does not disappear from the list, so we could get stuck * in an endless loop if we try to close it. Therefore, we close * other documents first. (Note that the document running the macro * may get closed because it is in the same window as another * document that gets closed, but it won't disappear; it becomes * Untitled.) */ if (WindowList == MacroRunWindow() && WindowList->next != NULL) { if (!CloseAllDocumentInWindow(WindowList->next)) { return False; } } else { if (!CloseAllDocumentInWindow(WindowList)) { return False; } } } return TRUE; } int CloseFileAndWindow(WindowInfo *window, int preResponse) { int response, stat; /* Make sure that the window is not in iconified state */ if (window->fileChanged) RaiseDocumentWindow(window); /* If the window is a normal & unmodified file or an empty new file, or if the user wants to ignore external modifications then just close it. Otherwise ask for confirmation first. */ if (!window->fileChanged && /* Normal File */ ((!window->fileMissing && window->lastModTime > 0) || /* New File*/ (window->fileMissing && window->lastModTime == 0) || /* File deleted/modified externally, ignored by user. */ !GetPrefWarnFileMods())) { CloseWindow(window); /* up-to-date windows don't have outstanding backup files to close */ } else { if (preResponse == PROMPT_SBC_DIALOG_RESPONSE) { response = DialogF(DF_WARN, window->shell, 3, "Save File", "Save %s before closing?", "Yes", "No", "Cancel", window->filename); } else { response = preResponse; } if (response == YES_SBC_DIALOG_RESPONSE) { /* Save */ stat = SaveWindow(window); if (stat) { CloseWindow(window); } else { return FALSE; } } else if (response == NO_SBC_DIALOG_RESPONSE) { /* Don't Save */ RemoveBackupFile(window); CloseWindow(window); } else /* 3 == Cancel */ { return FALSE; } } return TRUE; } int SaveWindow(WindowInfo *window) { int stat; /* Try to ensure our information is up-to-date */ CheckForChangesToFile(window); /* Return success if the file is normal & unchanged or is a read-only file. */ if ( (!window->fileChanged && !window->fileMissing && window->lastModTime > 0) || IS_ANY_LOCKED_IGNORING_PERM(window->lockReasons)) return TRUE; /* Prompt for a filename if this is an Untitled window */ if (!window->filenameSet) return SaveWindowAs(window, NULL, False); /* Check for external modifications and warn the user */ if (GetPrefWarnFileMods() && fileWasModifiedExternally(window)) { stat = DialogF(DF_WARN, window->shell, 2, "Save File", "%s has been modified by another program.\n\n" "Continuing this operation will overwrite any external\n" "modifications to the file since it was opened in NEdit,\n" "and your work or someone else's may potentially be lost.\n\n" "To preserve the modified file, cancel this operation and\n" "use Save As... to save this file under a different name,\n" "or Revert to Saved to revert to the modified version.", "Continue", "Cancel", window->filename); if (stat == 2) { /* Cancel and mark file as externally modified */ window->lastModTime = 0; window->fileMissing = FALSE; return FALSE; } } #ifdef VMS RemoveBackupFile(window); stat = doSave(window); #else if (writeBckVersion(window)) return FALSE; stat = doSave(window); if (stat) RemoveBackupFile(window); #endif /*VMS*/ return stat; } int SaveWindowAs(WindowInfo *window, const char *newName, int addWrap) { int response, retVal, fileFormat; char fullname[MAXPATHLEN], filename[MAXPATHLEN], pathname[MAXPATHLEN]; WindowInfo *otherWindow; /* Get the new name for the file */ if (newName == NULL) { response = PromptForNewFile(window, "Save File As", fullname, &fileFormat, &addWrap); if (response != GFN_OK) return FALSE; window->fileFormat = fileFormat; } else { strcpy(fullname, newName); } if (1 == NormalizePathname(fullname)) { return False; } /* Add newlines if requested */ if (addWrap) addWrapNewlines(window); if (ParseFilename(fullname, filename, pathname) != 0) { return FALSE; } /* If the requested file is this file, just save it and return */ if (!strcmp(window->filename, filename) && !strcmp(window->path, pathname)) { if (writeBckVersion(window)) return FALSE; return doSave(window); } /* If the file is open in another window, make user close it. Note that it is possible for user to close the window by hand while the dialog is still up, because the dialog is not application modal, so after doing the dialog, check again whether the window still exists. */ otherWindow = FindWindowWithFile(filename, pathname); if (otherWindow != NULL) { response = DialogF(DF_WARN, window->shell, 2, "File open", "%s is open in another NEdit window", "Cancel", "Close Other Window", filename); if (response == 1) { return FALSE; } if (otherWindow == FindWindowWithFile(filename, pathname)) { if (!CloseFileAndWindow(otherWindow, PROMPT_SBC_DIALOG_RESPONSE)) { return FALSE; } } } /* Destroy the file closed property for the original file */ DeleteFileClosedProperty(window); /* Change the name of the file and save it under the new name */ RemoveBackupFile(window); strcpy(window->filename, filename); strcpy(window->path, pathname); window->fileMode = 0; window->fileUid = 0; window->fileGid = 0; CLEAR_ALL_LOCKS(window->lockReasons); retVal = doSave(window); UpdateWindowReadOnly(window); RefreshTabState(window); /* Add the name to the convenience menu of previously opened files */ AddToPrevOpenMenu(fullname); /* If name has changed, language mode may have changed as well, unless it's an Untitled window for which the user already set a language mode; it's probably the right one. */ if (PLAIN_LANGUAGE_MODE == window->languageMode || window->filenameSet) { DetermineLanguageMode(window, False); } window->filenameSet = True; /* Update the stats line and window title with the new filename */ UpdateWindowTitle(window); UpdateStatsLine(window); SortTabBar(window); return retVal; } static int doSave(WindowInfo *window) { char *fileString = NULL; char fullname[MAXPATHLEN]; struct stat statbuf; FILE *fp; int fileLen, result; /* Get the full name of the file */ strcpy(fullname, window->path); strcat(fullname, window->filename); /* Check for root and warn him if he wants to write to a file with none of the write bits set. */ if ((0 == getuid()) && (0 == stat(fullname, &statbuf)) && !(statbuf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) { result = DialogF(DF_WARN, window->shell, 2, "Writing Read-only File", "File '%s' is marked as read-only.\n" "Do you want to save anyway?", "Save", "Cancel", window->filename); if (1 != result) { return True; } } #ifdef VMS /* strip the version number from the file so VMS will begin a new one */ removeVersionNumber(fullname); #endif /* add a terminating newline if the file doesn't already have one for Unix utilities which get confused otherwise NOTE: this must be done _before_ we create/open the file, because the (potential) buffer modification can trigger a check for file changes. If the file is created for the first time, it has zero size on disk, and the check would falsely conclude that the file has changed on disk, and would pop up a warning dialog */ if (BufGetCharacter(window->buffer, window->buffer->length - 1) != '\n' && window->buffer->length != 0 && GetPrefAppendLF()) { BufInsert(window->buffer, window->buffer->length, "\n"); } /* open the file */ #ifdef VMS fp = fopen(fullname, "w", "rfm = stmlf"); #else fp = fopen(fullname, "wb"); #endif /* VMS */ if (fp == NULL) { result = DialogF(DF_WARN, window->shell, 2, "Error saving File", "Unable to save %s:\n%s\n\nSave as a new file?", "Save As...", "Cancel", window->filename, errorString()); if (result == 1) { return SaveWindowAs(window, NULL, 0); } return FALSE; } #ifdef VMS /* get the complete name of the file including the new version number */ fgetname(fp, fullname); #endif /* get the text buffer contents and its length */ fileString = BufGetAll(window->buffer); fileLen = window->buffer->length; /* If null characters are substituted for, put them back */ BufUnsubstituteNullChars(fileString, window->buffer); /* If the file is to be saved in DOS or Macintosh format, reconvert */ if (window->fileFormat == DOS_FILE_FORMAT) { if (!ConvertToDosFileString(&fileString, &fileLen)) { DialogF(DF_ERR, window->shell, 1, "Out of Memory", "Out of memory! Try\nsaving in Unix format", "OK"); return FALSE; } } else if (window->fileFormat == MAC_FILE_FORMAT) { ConvertToMacFileString(fileString, fileLen); } /* write to the file */ #ifdef IBM_FWRITE_BUG write(fileno(fp), fileString, fileLen); #else fwrite(fileString, sizeof(char), fileLen, fp); #endif if (ferror(fp)) { DialogF(DF_ERR, window->shell, 1, "Error saving File", "%s not saved:\n%s", "OK", window->filename, errorString()); fclose(fp); remove(fullname); XtFree(fileString); return FALSE; } /* close the file */ if (fclose(fp) != 0) { DialogF(DF_ERR, window->shell, 1, "Error closing File", "Error closing file:\n%s", "OK", errorString()); XtFree(fileString); return FALSE; } /* free the text buffer copy returned from XmTextGetString */ XtFree(fileString); #ifdef VMS /* reflect the fact that NEdit is now editing a new version of the file */ ParseFilename(fullname, window->filename, window->path); #endif /*VMS*/ /* success, file was written */ SetWindowModified(window, FALSE); /* update the modification time */ if (stat(fullname, &statbuf) == 0) { window->lastModTime = statbuf.st_mtime; window->fileMissing = FALSE; window->device = statbuf.st_dev; window->inode = statbuf.st_ino; } else { /* This needs to produce an error message -- the file can't be accessed! */ window->lastModTime = 0; window->fileMissing = TRUE; window->device = 0; window->inode = 0; } return TRUE; } /* ** Create a backup file for the current window. The name for the backup file ** is generated using the name and path stored in the window and adding a ** tilde (~) on UNIX and underscore (_) on VMS to the beginning of the name. */ int WriteBackupFile(WindowInfo *window) { char *fileString = NULL; char name[MAXPATHLEN]; FILE *fp; int fd, fileLen; /* Generate a name for the autoSave file */ backupFileName(window, name, sizeof(name)); /* remove the old backup file. Well, this might fail - we'll notice later however. */ remove(name); /* open the file, set more restrictive permissions (using default permissions was somewhat of a security hole, because permissions were independent of those of the original file being edited */ #ifdef VMS if ((fp = fopen(name, "w", "rfm = stmlf")) == NULL) #else if ((fd = open(name, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR | S_IWUSR)) < 0 || (fp = fdopen(fd, "w")) == NULL) #endif /* VMS */ { DialogF(DF_WARN, window->shell, 1, "Error writing Backup", "Unable to save backup for %s:\n%s\n" "Automatic backup is now off", "OK", window->filename, errorString()); window->autoSave = FALSE; SetToggleButtonState(window, window->autoSaveItem, FALSE, FALSE); return FALSE; } /* Set VMS permissions */ #ifdef VMS chmod(name, S_IRUSR | S_IWUSR); #endif /* get the text buffer contents and its length */ fileString = BufGetAll(window->buffer); fileLen = window->buffer->length; /* If null characters are substituted for, put them back */ BufUnsubstituteNullChars(fileString, window->buffer); /* add a terminating newline if the file doesn't already have one */ if (fileLen != 0 && fileString[fileLen-1] != '\n') fileString[fileLen++] = '\n'; /* null terminator no longer needed */ /* write out the file */ #ifdef IBM_FWRITE_BUG write(fileno(fp), fileString, fileLen); #else fwrite(fileString, sizeof(char), fileLen, fp); #endif if (ferror(fp)) { DialogF(DF_ERR, window->shell, 1, "Error saving Backup", "Error while saving backup for %s:\n%s\n" "Automatic backup is now off", "OK", window->filename, errorString()); fclose(fp); remove(name); XtFree(fileString); window->autoSave = FALSE; return FALSE; } /* close the backup file */ if (fclose(fp) != 0) { XtFree(fileString); return FALSE; } /* Free the text buffer copy returned from XmTextGetString */ XtFree(fileString); return TRUE; } /* ** Remove the backup file associated with this window */ void RemoveBackupFile(WindowInfo *window) { char name[MAXPATHLEN]; /* Don't delete backup files when backups aren't activated. */ if (window->autoSave == FALSE) return; backupFileName(window, name, sizeof(name)); remove(name); } /* ** Generate the name of the backup file for this window from the filename ** and path in the window data structure & write into name */ static void backupFileName(WindowInfo *window, char *name, size_t len) { char bckname[MAXPATHLEN]; #ifdef VMS if (window->filenameSet) sprintf(name, "%s_%s", window->path, window->filename); else sprintf(name, "%s_%s", "SYS$LOGIN:", window->filename); #else if (window->filenameSet) { sprintf(name, "%s~%s", window->path, window->filename); } else { strcpy(bckname, "~"); strncat(bckname, window->filename, MAXPATHLEN - 1); PrependHome(bckname, name, len); } #endif /*VMS*/ } /* ** If saveOldVersion is on, copies the existing version of the file to ** .bck in anticipation of a new version being saved. Returns ** True if backup fails and user requests that the new file not be written. */ static int writeBckVersion(WindowInfo *window) { #ifndef VMS char fullname[MAXPATHLEN], bckname[MAXPATHLEN]; struct stat statbuf; int in_fd, out_fd; char *io_buffer; #define IO_BUFFER_SIZE ((size_t)(1024*1024)) /* Do only if version backups are turned on */ if (!window->saveOldVersion) { return False; } /* Get the full name of the file */ strcpy(fullname, window->path); strcat(fullname, window->filename); /* Generate name for old version */ if ((strlen(fullname) + 5) > (size_t) MAXPATHLEN) { return bckError(window, "file name too long", window->filename); } sprintf(bckname, "%s.bck", fullname); /* Delete the old backup file */ /* Errors are ignored; we'll notice them later. */ remove(bckname); /* open the file being edited. If there are problems with the old file, don't bother the user, just skip the backup */ in_fd = open(fullname, O_RDONLY); if (in_fd<0) { return FALSE; } /* Get permissions of the file. We preserve the normal permissions but not ownership, extended attributes, et cetera. */ if (fstat(in_fd, &statbuf) != 0) { return FALSE; } /* open the destination file exclusive and with restrictive permissions. */ out_fd = open(bckname, O_CREAT|O_EXCL|O_TRUNC|O_WRONLY, S_IRUSR | S_IWUSR); if (out_fd < 0) { return bckError(window, "Error open backup file", bckname); } /* Set permissions on new file */ if (fchmod(out_fd, statbuf.st_mode) != 0) { close(in_fd); close(out_fd); remove(bckname); return bckError(window, "fchmod() failed", bckname); } /* Allocate I/O buffer */ io_buffer = (char*) malloc(IO_BUFFER_SIZE); if (NULL == io_buffer) { close(in_fd); close(out_fd); remove(bckname); return bckError(window, "out of memory", bckname); } /* copy loop */ for(;;) { ssize_t bytes_read; ssize_t bytes_written; bytes_read = read(in_fd, io_buffer, IO_BUFFER_SIZE); if (bytes_read < 0) { close(in_fd); close(out_fd); remove(bckname); free(io_buffer); return bckError(window, "read() error", window->filename); } if (0 == bytes_read) { break; /* EOF */ } /* write to the file */ bytes_written = write(out_fd, io_buffer, (size_t) bytes_read); if (bytes_written != bytes_read) { close(in_fd); close(out_fd); remove(bckname); free(io_buffer); return bckError(window, errorString(), bckname); } } /* close the input and output files */ close(in_fd); close(out_fd); free(io_buffer); #endif /* VMS */ return FALSE; } /* ** Error processing for writeBckVersion, gives the user option to cancel ** the subsequent save, or continue and optionally turn off versioning */ static int bckError(WindowInfo *window, const char *errString, const char *file) { int resp; resp = DialogF(DF_ERR, window->shell, 3, "Error writing Backup", "Couldn't write .bck (last version) file.\n%s: %s", "Cancel Save", "Turn off Backups", "Continue", file, errString); if (resp == 1) return TRUE; if (resp == 2) { window->saveOldVersion = FALSE; #ifndef VMS SetToggleButtonState(window, window->saveLastItem, FALSE, FALSE); #endif } return FALSE; } void PrintWindow(WindowInfo *window, int selectedOnly) { textBuffer *buf = window->buffer; selection *sel = &buf->primary; char *fileString = NULL; int fileLen; /* get the contents of the text buffer from the text area widget. Add wrapping newlines if necessary to make it match the displayed text */ if (selectedOnly) { if (!sel->selected) { XBell(TheDisplay, 0); return; } if (sel->rectangular) { fileString = BufGetSelectionText(buf); fileLen = strlen(fileString); } else fileString = TextGetWrapped(window->textArea, sel->start, sel->end, &fileLen); } else fileString = TextGetWrapped(window->textArea, 0, buf->length, &fileLen); /* If null characters are substituted for, put them back */ BufUnsubstituteNullChars(fileString, buf); /* add a terminating newline if the file doesn't already have one */ if (fileLen != 0 && fileString[fileLen-1] != '\n') fileString[fileLen++] = '\n'; /* null terminator no longer needed */ /* Print the string */ PrintString(fileString, fileLen, window->shell, window->filename); /* Free the text buffer copy returned from XmTextGetString */ XtFree(fileString); } /* ** Print a string (length is required). parent is the dialog parent, for ** error dialogs, and jobName is the print title. */ void PrintString(const char *string, int length, Widget parent, const char *jobName) { char tmpFileName[L_tmpnam]; /* L_tmpnam defined in stdio.h */ FILE *fp; int fd; /* Generate a temporary file name */ /* If the glibc is used, the linker issues a warning at this point. This is very thoughtful of him, but does not apply to NEdit. The recommended replacement mkstemp(3) uses the same algorithm as NEdit, namely 1. Create a filename 2. Open the file with the O_CREAT|O_EXCL flags So all an attacker can do is a DoS on the print function. */ tmpnam(tmpFileName); /* open the temporary file */ #ifdef VMS if ((fp = fopen(tmpFileName, "w", "rfm = stmlf")) == NULL) #else if ((fd = open(tmpFileName, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR | S_IWUSR)) < 0 || (fp = fdopen(fd, "w")) == NULL) #endif /* VMS */ { DialogF(DF_WARN, parent, 1, "Error while Printing", "Unable to write file for printing:\n%s", "OK", errorString()); return; } #ifdef VMS chmod(tmpFileName, S_IRUSR | S_IWUSR); #endif /* write to the file */ #ifdef IBM_FWRITE_BUG write(fileno(fp), string, length); #else fwrite(string, sizeof(char), length, fp); #endif if (ferror(fp)) { DialogF(DF_ERR, parent, 1, "Error while Printing", "%s not printed:\n%s", "OK", jobName, errorString()); fclose(fp); /* should call close(fd) in turn! */ remove(tmpFileName); return; } /* close the temporary file */ if (fclose(fp) != 0) { DialogF(DF_ERR, parent, 1, "Error while Printing", "Error closing temp. print file:\n%s", "OK", errorString()); remove(tmpFileName); return; } /* Print the temporary file, then delete it and return success */ #ifdef VMS strcat(tmpFileName, "."); PrintFile(parent, tmpFileName, jobName, True); #else PrintFile(parent, tmpFileName, jobName); remove(tmpFileName); #endif /*VMS*/ return; } /* ** Wrapper for GetExistingFilename which uses the current window's path ** (if set) as the default directory. */ int PromptForExistingFile(WindowInfo *window, char *prompt, char *fullname) { char *savedDefaultDir; int retVal; /* Temporarily set default directory to window->path, prompt for file, then, if the call was unsuccessful, restore the original default directory */ savedDefaultDir = GetFileDialogDefaultDirectory(); if (*window->path != '\0') SetFileDialogDefaultDirectory(window->path); retVal = GetExistingFilename(window->shell, prompt, fullname); if (retVal != GFN_OK) SetFileDialogDefaultDirectory(savedDefaultDir); XtFree(savedDefaultDir); return retVal; } /* ** Wrapper for HandleCustomNewFileSB which uses the current window's path ** (if set) as the default directory, and asks about embedding newlines ** to make wrapping permanent. */ int PromptForNewFile(WindowInfo *window, char *prompt, char *fullname, int *fileFormat, int *addWrap) { int n, retVal; Arg args[20]; XmString s1, s2; Widget fileSB, wrapToggle; Widget formatForm, formatBtns, unixFormat, dosFormat, macFormat; char *savedDefaultDir; *fileFormat = window->fileFormat; /* Temporarily set default directory to window->path, prompt for file, then, if the call was unsuccessful, restore the original default directory */ savedDefaultDir = GetFileDialogDefaultDirectory(); if (*window->path != '\0') SetFileDialogDefaultDirectory(window->path); /* Present a file selection dialog with an added field for requesting long line wrapping to become permanent via inserted newlines */ n = 0; XtSetArg(args[n], XmNselectionLabelString, s1 = XmStringCreateLocalized("New File Name:")); n++; XtSetArg(args[n], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); n++; XtSetArg(args[n], XmNdialogTitle, s2 = XmStringCreateSimple(prompt)); n++; fileSB = CreateFileSelectionDialog(window->shell,"FileSelect",args,n); XmStringFree(s1); XmStringFree(s2); formatForm = XtVaCreateManagedWidget("formatForm", xmFormWidgetClass, fileSB, NULL); formatBtns = XtVaCreateManagedWidget("formatBtns", xmRowColumnWidgetClass, formatForm, XmNradioBehavior, XmONE_OF_MANY, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_TIGHT, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, NULL); XtVaCreateManagedWidget("formatBtns", xmLabelWidgetClass, formatBtns, XmNlabelString, s1=XmStringCreateSimple("Format:"), NULL); XmStringFree(s1); unixFormat = XtVaCreateManagedWidget("unixFormat", xmToggleButtonWidgetClass, formatBtns, XmNlabelString, s1 = XmStringCreateSimple("Unix"), XmNset, *fileFormat == UNIX_FILE_FORMAT, XmNuserData, (XtPointer)UNIX_FILE_FORMAT, XmNmarginHeight, 0, XmNalignment, XmALIGNMENT_BEGINNING, XmNmnemonic, 'U', NULL); XmStringFree(s1); XtAddCallback(unixFormat, XmNvalueChangedCallback, setFormatCB, fileFormat); dosFormat = XtVaCreateManagedWidget("dosFormat", xmToggleButtonWidgetClass, formatBtns, XmNlabelString, s1 = XmStringCreateSimple("DOS"), XmNset, *fileFormat == DOS_FILE_FORMAT, XmNuserData, (XtPointer)DOS_FILE_FORMAT, XmNmarginHeight, 0, XmNalignment, XmALIGNMENT_BEGINNING, XmNmnemonic, 'O', NULL); XmStringFree(s1); XtAddCallback(dosFormat, XmNvalueChangedCallback, setFormatCB, fileFormat); macFormat = XtVaCreateManagedWidget("macFormat", xmToggleButtonWidgetClass, formatBtns, XmNlabelString, s1 = XmStringCreateSimple("Macintosh"), XmNset, *fileFormat == MAC_FILE_FORMAT, XmNuserData, (XtPointer)MAC_FILE_FORMAT, XmNmarginHeight, 0, XmNalignment, XmALIGNMENT_BEGINNING, XmNmnemonic, 'M', NULL); XmStringFree(s1); XtAddCallback(macFormat, XmNvalueChangedCallback, setFormatCB, fileFormat); if (window->wrapMode == CONTINUOUS_WRAP) { wrapToggle = XtVaCreateManagedWidget("addWrap", xmToggleButtonWidgetClass, formatForm, XmNlabelString, s1 = XmStringCreateSimple("Add line breaks where wrapped"), XmNalignment, XmALIGNMENT_BEGINNING, XmNmnemonic, 'A', XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, formatBtns, XmNleftAttachment, XmATTACH_FORM, NULL); XtAddCallback(wrapToggle, XmNvalueChangedCallback, addWrapCB, addWrap); XmStringFree(s1); } *addWrap = False; XtVaSetValues(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_FILTER_LABEL), XmNmnemonic, 'l', XmNuserData, XmFileSelectionBoxGetChild(fileSB, XmDIALOG_FILTER_TEXT), NULL); XtVaSetValues(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_DIR_LIST_LABEL), XmNmnemonic, 'D', XmNuserData, XmFileSelectionBoxGetChild(fileSB, XmDIALOG_DIR_LIST), NULL); XtVaSetValues(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_LIST_LABEL), XmNmnemonic, 'F', XmNuserData, XmFileSelectionBoxGetChild(fileSB, XmDIALOG_LIST), NULL); XtVaSetValues(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_SELECTION_LABEL), XmNmnemonic, prompt[strspn(prompt, "lFD")], XmNuserData, XmFileSelectionBoxGetChild(fileSB, XmDIALOG_TEXT), NULL); AddDialogMnemonicHandler(fileSB, FALSE); RemapDeleteKey(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_FILTER_TEXT)); RemapDeleteKey(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_TEXT)); retVal = HandleCustomNewFileSB(fileSB, fullname, window->filenameSet ? window->filename : NULL); if (retVal != GFN_OK) SetFileDialogDefaultDirectory(savedDefaultDir); XtFree(savedDefaultDir); return retVal; } /* ** Find a name for an untitled file, unique in the name space of in the opened ** files in this session, i.e. Untitled or Untitled_nn, and write it into ** the string "name". */ void UniqueUntitledName(char *name) { WindowInfo *w; int i; for (i=0; inext) if (!strcmp(w->filename, name)) break; if (w == NULL) break; } } /* ** Callback that guards us from trying to access a window after it has ** been destroyed while a modal dialog is up. */ static void modifiedWindowDestroyedCB(Widget w, XtPointer clientData, XtPointer callData) { *(Bool*)clientData = TRUE; } /* ** Check if the file in the window was changed by an external source. ** and put up a warning dialog if it has. */ void CheckForChangesToFile(WindowInfo *window) { static WindowInfo* lastCheckWindow = NULL; static Time lastCheckTime = 0; char fullname[MAXPATHLEN]; struct stat statbuf; Time timestamp; FILE *fp; int resp, silent = 0; XWindowAttributes winAttr; Boolean windowIsDestroyed = False; if(!window->filenameSet) return; /* If last check was very recent, don't impact performance */ timestamp = XtLastTimestampProcessed(XtDisplay(window->shell)); if (window == lastCheckWindow && timestamp - lastCheckTime < MOD_CHECK_INTERVAL) return; lastCheckWindow = window; lastCheckTime = timestamp; /* Update the status, but don't pop up a dialog if we're called from a place where the window might be iconic (e.g., from the replace dialog) or on another desktop. This works, but I bet it costs a round-trip to the server. Might be better to capture MapNotify/Unmap events instead. For tabs that are not on top, we don't want the dialog either, and we don't even need to contact the server to find out. By performing this check first, we avoid a server round-trip for most files in practice. */ if (!IsTopDocument(window)) silent = 1; else { XGetWindowAttributes(XtDisplay(window->shell), XtWindow(window->shell), &winAttr); if (winAttr.map_state != IsViewable) silent = 1; } /* Get the file mode and modification time */ strcpy(fullname, window->path); strcat(fullname, window->filename); if (stat(fullname, &statbuf) != 0) { /* Return if we've already warned the user or we can't warn him now */ if (window->fileMissing || silent) { return; } /* Can't stat the file -- maybe it's been deleted. The filename is now invalid */ window->fileMissing = TRUE; window->lastModTime = 1; window->device = 0; window->inode = 0; /* Warn the user, if they like to be warned (Maybe this should be its own preference setting: GetPrefWarnFileDeleted()) */ if (GetPrefWarnFileMods()) { char* title; char* body; /* See note below about pop-up timing and XUngrabPointer */ XUngrabPointer(XtDisplay(window->shell), timestamp); /* If the window (and the dialog) are destroyed while the dialog is up (typically closed via the window manager), we should avoid accessing the window afterwards. */ XtAddCallback(window->shell, XmNdestroyCallback, modifiedWindowDestroyedCB, &windowIsDestroyed); /* Set title, message body and button to match stat()'s error. */ switch (errno) { case ENOENT: /* A component of the path file_name does not exist. */ title = "File not Found"; body = "File '%s' (or directory in its path)\n" "no longer exists.\n" "Another program may have deleted or moved it."; resp = DialogF(DF_ERR, window->shell, 2, title, body, "Save", "Cancel", window->filename); break; case EACCES: /* Search permission denied for a path component. We add one to the response because Re-Save wouldn't really make sense here. */ title = "Permission Denied"; body = "You no longer have access to file '%s'.\n" "Another program may have changed the permissions of\n" "one of its parent directories."; resp = 1 + DialogF(DF_ERR, window->shell, 1, title, body, "Cancel", window->filename); break; default: /* Everything else. This hints at an internal error (eg. ENOTDIR) or at some bad state at the host. */ title = "File not Accessible"; body = "Error while checking the status of file '%s':\n" " '%s'\n" "Please make sure that no data is lost before closing\n" "this window."; resp = DialogF(DF_ERR, window->shell, 2, title, body, "Save", "Cancel", window->filename, errorString()); break; } if (!windowIsDestroyed) { XtRemoveCallback(window->shell, XmNdestroyCallback, modifiedWindowDestroyedCB, &windowIsDestroyed); } switch (resp) { case 1: SaveWindow(window); break; /* Good idea, but this leads to frequent crashes, see SF#1578869. Reinsert this if circumstances change by uncommenting this part and inserting a "Close" button before each Cancel button above. case 2: CloseWindow(window); return; */ } } /* A missing or (re-)saved file can't be read-only. */ /* TODO: A document without a file can be locked though. */ /* Make sure that the window was not destroyed behind our back! */ if (!windowIsDestroyed) { SET_PERM_LOCKED(window->lockReasons, False); UpdateWindowTitle(window); UpdateWindowReadOnly(window); } return; } /* Check that the file's read-only status is still correct (but only if the file can still be opened successfully in read mode) */ if (window->fileMode != statbuf.st_mode || window->fileUid != statbuf.st_uid || window->fileGid != statbuf.st_gid) { window->fileMode = statbuf.st_mode; window->fileUid = statbuf.st_uid; window->fileGid = statbuf.st_gid; if ((fp = fopen(fullname, "r")) != NULL) { int readOnly; fclose(fp); #ifndef DONT_USE_ACCESS readOnly = access(fullname, W_OK) != 0; #else if (((fp = fopen(fullname, "r+")) != NULL)) { readOnly = FALSE; fclose(fp); } else readOnly = TRUE; #endif if (IS_PERM_LOCKED(window->lockReasons) != readOnly) { SET_PERM_LOCKED(window->lockReasons, readOnly); UpdateWindowTitle(window); UpdateWindowReadOnly(window); } } } /* Warn the user if the file has been modified, unless checking is turned off or the user has already been warned. Popping up a dialog from a focus callback (which is how this routine is usually called) seems to catch Motif off guard, and if the timing is just right, the dialog can be left with a still active pointer grab from a Motif menu which is still in the process of popping down. The workaround, below, of calling XUngrabPointer is inelegant but seems to fix the problem. */ if (!silent && ((window->lastModTime != 0 && window->lastModTime != statbuf.st_mtime) || window->fileMissing) ){ window->lastModTime = 0; /* Inhibit further warnings */ window->fileMissing = FALSE; if (!GetPrefWarnFileMods()) return; if (GetPrefWarnRealFileMods() && !cmpWinAgainstFile(window, fullname)) { /* Contents hasn't changed. Update the modification time. */ window->lastModTime = statbuf.st_mtime; return; } XUngrabPointer(XtDisplay(window->shell), timestamp); if (window->fileChanged) resp = DialogF(DF_WARN, window->shell, 2, "File modified externally", "%s has been modified by another program. Reload?\n\n" "WARNING: Reloading will discard changes made in this\n" "editing session!", "Reload", "Cancel", window->filename); else resp = DialogF(DF_WARN, window->shell, 2, "File modified externally", "%s has been modified by another\nprogram. Reload?", "Reload", "Cancel", window->filename); if (resp == 1) RevertToSaved(window); } } /* ** Return true if the file displayed in window has been modified externally ** to nedit. This should return FALSE if the file has been deleted or is ** unavailable. */ static int fileWasModifiedExternally(WindowInfo *window) { char fullname[MAXPATHLEN]; struct stat statbuf; if(!window->filenameSet) return FALSE; /* if (window->lastModTime == 0) return FALSE; */ strcpy(fullname, window->path); strcat(fullname, window->filename); if (stat(fullname, &statbuf) != 0) return FALSE; if (window->lastModTime == statbuf.st_mtime) return FALSE; if (GetPrefWarnRealFileMods() && !cmpWinAgainstFile(window, fullname)) { return FALSE; } return TRUE; } /* ** Check the read-only or locked status of the window and beep and return ** false if the window should not be written in. */ int CheckReadOnly(WindowInfo *window) { if (IS_ANY_LOCKED(window->lockReasons)) { XBell(TheDisplay, 0); return True; } return False; } /* ** Wrapper for strerror so all the calls don't have to be ifdef'd for VMS. */ static const char *errorString(void) { #ifdef VMS return strerror(errno, vaxc$errno); #else return strerror(errno); #endif } #ifdef VMS /* ** Removing the VMS version number from a file name (if has one). */ void removeVersionNumber(char *fileName) { char *versionStart; versionStart = strrchr(fileName, ';'); if (versionStart != NULL) *versionStart = '\0'; } #endif /*VMS*/ /* ** Callback procedure for File Format toggle buttons. Format is stored ** in userData field of widget button */ static void setFormatCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(w)) { XtPointer userData; XtVaGetValues(w, XmNuserData, &userData, NULL); *(int*) clientData = (int) userData; } } /* ** Callback procedure for toggle button requesting newlines to be inserted ** to emulate continuous wrapping. */ static void addWrapCB(Widget w, XtPointer clientData, XtPointer callData) { int resp; int *addWrap = (int *)clientData; if (XmToggleButtonGetState(w)) { resp = DialogF(DF_WARN, w, 2, "Add Wrap", "This operation adds permanent line breaks to\n" "match the automatic wrapping done by the\n" "Continuous Wrap mode Preferences Option.\n\n" "*** This Option is Irreversable ***\n\n" "Once newlines are inserted, continuous wrapping\n" "will no longer work automatically on these lines", "OK", "Cancel"); if (resp == 2) { XmToggleButtonSetState(w, False, False); *addWrap = False; } else { *addWrap = True; } } else { *addWrap = False; } } /* ** Change a window created in NEdit's continuous wrap mode to the more ** conventional Unix format of embedded newlines. Indicate to the user ** by turning off Continuous Wrap mode. */ static void addWrapNewlines(WindowInfo *window) { int fileLen, i, insertPositions[MAX_PANES], topLines[MAX_PANES]; int horizOffset; Widget text; char *fileString; /* save the insert and scroll positions of each pane */ for (i=0; i<=window->nPanes; i++) { text = i==0 ? window->textArea : window->textPanes[i-1]; insertPositions[i] = TextGetCursorPos(text); TextGetScroll(text, &topLines[i], &horizOffset); } /* Modify the buffer to add wrapping */ fileString = TextGetWrapped(window->textArea, 0, window->buffer->length, &fileLen); BufSetAll(window->buffer, fileString); XtFree(fileString); /* restore the insert and scroll positions of each pane */ for (i=0; i<=window->nPanes; i++) { text = i==0 ? window->textArea : window->textPanes[i-1]; TextSetCursorPos(text, insertPositions[i]); TextSetScroll(text, topLines[i], 0); } /* Show the user that something has happened by turning off Continuous Wrap mode */ SetToggleButtonState(window, window->continuousWrapItem, False, True); } /* * Number of bytes read at once by cmpWinAgainstFile */ #define PREFERRED_CMPBUF_LEN 32768 /* * Check if the contens of the textBuffer *buf is equal * the contens of the file named fileName. The format of * the file (UNIX/DOS/MAC) is handled properly. * * Return values * 0: no difference found * !0: difference found or could not compare contents. */ static int cmpWinAgainstFile(WindowInfo *window, const char *fileName) { char fileString[PREFERRED_CMPBUF_LEN + 2]; struct stat statbuf; int fileLen, restLen, nRead, bufPos, rv, offset, filePos; char pendingCR = 0; int fileFormat = window->fileFormat; char message[MAXPATHLEN+50]; textBuffer *buf = window->buffer; FILE *fp; fp = fopen(fileName, "r"); if (!fp) return (1); if (fstat(fileno(fp), &statbuf) != 0) { fclose(fp); return (1); } fileLen = statbuf.st_size; /* For DOS files, we can't simply check the length */ if (fileFormat != DOS_FILE_FORMAT) { if (fileLen != buf->length) { fclose(fp); return (1); } } else { /* If a DOS file is smaller on disk, it's certainly different */ if (fileLen < buf->length) { fclose(fp); return (1); } } /* For large files, the comparison can take a while. If it takes too long, the user should be given a clue about what is happening. */ sprintf(message, "Comparing externally modified %s ...", window->filename); restLen = min(PREFERRED_CMPBUF_LEN, fileLen); bufPos = 0; filePos = 0; while (restLen > 0) { AllWindowsBusy(message); if (pendingCR) { fileString[0] = pendingCR; offset = 1; } else { offset = 0; } nRead = fread(fileString+offset, sizeof(char), restLen, fp); if (nRead != restLen) { fclose(fp); AllWindowsUnbusy(); return (1); } filePos += nRead; nRead += offset; /* check for on-disk file format changes, but only for the first hunk */ if (bufPos == 0 && fileFormat != FormatOfFile(fileString)) { fclose(fp); AllWindowsUnbusy(); return (1); } if (fileFormat == MAC_FILE_FORMAT) ConvertFromMacFileString(fileString, nRead); else if (fileFormat == DOS_FILE_FORMAT) ConvertFromDosFileString(fileString, &nRead, &pendingCR); /* Beware of 0 chars ! */ BufSubstituteNullChars(fileString, nRead, buf); rv = BufCmp(buf, bufPos, nRead, fileString); if (rv) { fclose(fp); AllWindowsUnbusy(); return (rv); } bufPos += nRead; restLen = min(fileLen - filePos, PREFERRED_CMPBUF_LEN); } AllWindowsUnbusy(); fclose(fp); if (pendingCR) { rv = BufCmp(buf, bufPos, 1, &pendingCR); if (rv) { return (rv); } bufPos += 1; } if (bufPos != buf->length) { return (1); } return (0); } /* ** Force ShowLineNumbers() to re-evaluate line counts for the window if line ** counts are required. */ static void forceShowLineNumbers(WindowInfo *window) { Boolean showLineNum = window->showLineNumbers; if (showLineNum) { window->showLineNumbers = False; ShowLineNumbers(window, showLineNum); } } static int min(int i1, int i2) { return i1 <= i2 ? i1 : i2; } nedit-5.6.orig/source/file.h0000644000175000017500000000701310144236624014505 0ustar paulpaul/* $Id: file.h,v 1.15 2004/11/09 21:58:44 yooden Exp $ */ /******************************************************************************* * * * file.h -- Nirvana Editor File Header File * * * * Copyright 2004 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_FILE_H_INCLUDED #define NEDIT_FILE_H_INCLUDED #include "nedit.h" #include /* flags for EditExistingFile */ #define CREATE 1 #define SUPPRESS_CREATE_WARN 2 #define PREF_READ_ONLY 4 #define PROMPT_SBC_DIALOG_RESPONSE 0 #define YES_SBC_DIALOG_RESPONSE 1 #define NO_SBC_DIALOG_RESPONSE 2 WindowInfo *EditNewFile(WindowInfo *inWindow, char *geometry, int iconic, const char *languageMode, const char *defaultPath); WindowInfo *EditExistingFile(WindowInfo *inWindow, const char *name, const char *path, int flags, char *geometry, int iconic, const char *languageMode, int tabbed, int bgOpen); void RevertToSaved(WindowInfo *window); int SaveWindow(WindowInfo *window); int SaveWindowAs(WindowInfo *window, const char *newName, int addWrap); int CloseAllFilesAndWindows(void); int CloseFileAndWindow(WindowInfo *window, int preResponse); void PrintWindow(WindowInfo *window, int selectedOnly); void PrintString(const char *string, int length, Widget parent, const char *jobName); int WriteBackupFile(WindowInfo *window); int IncludeFile(WindowInfo *window, const char *name); int PromptForExistingFile(WindowInfo *window, char *prompt, char *fullname); int PromptForNewFile(WindowInfo *window, char *prompt, char *fullname, int *fileFormat, int *addWrap); int CheckReadOnly(WindowInfo *window); void RemoveBackupFile(WindowInfo *window); void UniqueUntitledName(char *name); void CheckForChangesToFile(WindowInfo *window); #endif /* NEDIT_FILE_H_INCLUDED */ nedit-5.6.orig/source/help.c0000644000175000017500000013346011052644051014513 0ustar paulpaulstatic const char CVSID[] = "$Id: help.c,v 1.107 2008/08/19 22:24:41 ajbj Exp $"; /******************************************************************************* * * * help.c -- Nirvana Editor help display * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * September 10, 1991 * * * * Written by Mark Edel, mostly rewritten by Steve Haehn for new help system, * * December, 2001 * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "help.h" #include "textBuf.h" #include "text.h" #include "textP.h" #include "textDisp.h" #include "textSel.h" #include "nedit.h" #include "search.h" #include "window.h" #include "preferences.h" #include "help_data.h" #include "file.h" #include "highlight.h" #include "../util/motif.h" #include "../util/misc.h" #include "../util/DialogF.h" #include "../util/system.h" #include #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #include #include /* These are for applying style info to help text */ #include #include #include #include #include #ifdef EDITRES #include /* extern void _XEditResCheckMessages(); */ #endif /* EDITRES */ #ifdef HAVE_DEBUG_H #include "../debug.h" #endif /*============================================================================*/ /* SYMBOL DEFINITIONS */ /*============================================================================*/ #define EOS '\0' /* end-of-string character */ #define CLICK_THRESHOLD 5 /* number of pixels mouse may move from its */ /* pressed location for mouse-up to be */ /* considered a valid click (as opposed to */ /* a drag or mouse-pick error) */ /*============================================================================*/ /* VARIABLE DECLARATIONS */ /*============================================================================*/ static Widget HelpWindows[NUM_TOPICS] = {NULL}; static Widget HelpTextPanes[NUM_TOPICS] = {NULL}; static textBuffer *HelpStyleBuffers[NUM_TOPICS] = {NULL}; static int navHistForw[NUM_TOPICS]; static int navHistBack[NUM_TOPICS]; /* Information on the last search for search-again */ static char LastSearchString[DF_MAX_PROMPT_LENGTH] = ""; static int LastSearchTopic = -1; static int LastSearchPos = 0; static int LastSearchWasAllTopics = False; /* Fonts for each help text style generated by the help generator (setext). The NEdit text widget uses the first help style, 'A', to calculate window width, so making 'A' a fixed font will yield window widths calibrated to match width-dependent fixed font layouts in the help text. */ static enum helpFonts StyleFonts[] = { /* Fixed fonts, styles: 'A', 'B', 'C', 'D' */ FIXED_HELP_FONT, BOLD_FIXED_HELP_FONT, ITALIC_FIXED_HELP_FONT, BOLD_ITALIC_FIXED_HELP_FONT, /* Underlined fixed fonts, styles: 'E', 'F', 'G', 'H' */ FIXED_HELP_FONT, BOLD_FIXED_HELP_FONT, ITALIC_FIXED_HELP_FONT, BOLD_ITALIC_FIXED_HELP_FONT, /* Normal (proportional) fonts, styles: 'I', 'J', 'K', 'L' */ HELP_FONT, BOLD_HELP_FONT, ITALIC_HELP_FONT, BOLD_ITALIC_HELP_FONT, /* Underlined fonts, styles: 'M', 'N', 'O', 'P' */ HELP_FONT, BOLD_HELP_FONT, ITALIC_HELP_FONT, BOLD_ITALIC_HELP_FONT, /* Link font, style: 'Q' */ HELP_FONT, /* Heading fonts, styles: 'R', 'S', 'T' */ H1_HELP_FONT, H2_HELP_FONT, H3_HELP_FONT }; static int StyleUnderlines[] = { /* Fixed fonts, styles: 'A', 'B', 'C', 'D' */ False, False, False, False, /* Underlined fixed fonts, styles: 'E', 'F', 'G', 'H' */ True, True, True, True, /* Normal (proportional) fonts, styles: 'I', 'J', 'K', 'L' */ False, False, False, False, /* Underlined fonts, styles: 'M', 'N', 'O', 'P' */ True, True, True, True, /* Link font, style: 'Q' */ True, /* Heading fonts, styles: 'R', 'S', 'T' */ False, False, False }; #define N_STYLES (XtNumber(StyleFonts)) static styleTableEntry HelpStyleInfo[ N_STYLES ]; /* Translation table for style codes (A, B, C, ...) to their ASCII codes. For systems using ASCII, this is just a one-to-one mapping, but the table makes it possible to use the style codes also on an EBCDIC system. */ static unsigned char AlphabetToAsciiTable[256]; /* Macro that calculates the zero-based index for a given style, taking into account that the character set may not use ASCII coding, but EBCDIC. The "style" argument must be one of the characters A - Z. In ASCII, this comes down to "style - STYLE_PLAIN". */ #define STYLE_INDEX(style) \ (AlphabetToAsciiTable[(unsigned char)style] - \ AlphabetToAsciiTable[(unsigned char)STYLE_PLAIN]) /*============================================================================*/ /* PROGRAM PROTOTYPES */ /*============================================================================*/ static Widget createHelpPanel(enum HelpTopic topic); static void closeCB(Widget w, XtPointer clientData, XtPointer callData); static void prevTopicCB(Widget w, XtPointer clientData, XtPointer callData); static void nextTopicCB(Widget w, XtPointer clientData, XtPointer callData); static void bwHistoryCB(Widget w, XtPointer clientData, XtPointer callData); static void fwHistoryCB(Widget w, XtPointer clientData, XtPointer callData); static void searchHelpCB(Widget w, XtPointer clientData, XtPointer callData); static void searchHelpAgainCB(Widget w, XtPointer clientData, XtPointer callData); static void printCB(Widget w, XtPointer clientData, XtPointer callData); static char *stitch(Widget parent, char **string_list,char **styleMap); static void searchHelpText(Widget parent, int parentTopic, const char *searchFor, int allSections, int startPos, int startTopic); static void changeWindowTopic(int existingTopic, enum HelpTopic newTopic); static int findTopicFromShellWidget(Widget shellWidget); static void loadFontsAndColors(Widget parent, int style); static void initNavigationHistory(void); #ifdef HAVE__XMVERSIONSTRING extern char _XmVersionString[]; #else static char _XmVersionString[] = "unknown"; #endif /*============================================================================*/ /*================================= PROGRAMS =================================*/ /*============================================================================*/ /* ** Create a string containing information on the build environment. Returned ** string must NOT be freed by caller. */ static char *bldInfoString = NULL; static void freeBuildInfo(void) { /* This keeps memory leak detectors happy */ XtFree(bldInfoString); } static const char *const warning = "\nThis NEdit was built with a known-bad version of Motif. Please " "do not report any bugs you encounter unless you can reproduce " "them with a known-good binary from the www.nedit.org website. " "If this binary was supplied with your Linux distribution please " "file a bug report with them asking them to build NEdit with a " "known-good version of Motif.\n"; static const char *getBuildInfo(void) { static const char *bldFormat = "%s\n" " Built on: %s, %s, %s\n" " Built at: %s, %s\n" " With Motif: %s%d.%d.%d [%s]\n" "Running Motif: %d.%d [%s]\n" " Server: %s %d\n" " Visual: %s\n" " Locale: %s\n" ; static const char *visualClass[] = {"StaticGray", "GrayScale", "StaticColor", "PseudoColor", "TrueColor", "DirectColor"}; static const char *const stabilities[] = {"", "(Untested) ", "(Known Bad) "}; if (bldInfoString == NULL) { const char *locale; char visualStr[500] = ""; const enum MotifStability stab = GetMotifStability(); if (TheDisplay) { Visual *visual; int depth; Colormap map; Boolean usingDefaultVisual = FindBestVisual(TheDisplay, APP_NAME, APP_CLASS, &visual, &depth, &map); sprintf(visualStr,"%d-bit %s (ID %#lx%s)", depth, visualClass[visual->class], visual->visualid, usingDefaultVisual ? ", Default" : ""); } bldInfoString = XtMalloc(strlen(bldFormat) + strlen(warning) + 1024); locale = setlocale(LC_MESSAGES, ""); sprintf(bldInfoString, bldFormat, NEditVersion, COMPILE_OS, COMPILE_MACHINE, COMPILE_COMPILER, linkdate, linktime, stabilities[stab], XmVERSION, XmREVISION, XmUPDATE_LEVEL, XmVERSION_STRING, xmUseVersion/1000, xmUseVersion%1000, _XmVersionString, (NULL == TheDisplay ? "" : ServerVendor(TheDisplay)), (NULL == TheDisplay ? 0 : VendorRelease(TheDisplay)), visualStr, locale ? locale : "None"); if (stab == MotifKnownBad) strcat(bldInfoString, warning); atexit(freeBuildInfo); } return bldInfoString; } /* ** Initialization for help system data, needs to be done only once. */ static void initHelpStyles (Widget parent) { static int styleTableInitialized = False; if (! styleTableInitialized) { Pixel fg; int styleIndex; char ** line; XtVaGetValues(parent, XtNforeground, &fg, NULL); for (styleIndex = 0; styleIndex < STL_HD + MAX_HEADING; styleIndex++) { HelpStyleInfo[ styleIndex ].color = fg; HelpStyleInfo[ styleIndex ].underline = StyleUnderlines[styleIndex]; HelpStyleInfo[ styleIndex ].font = NULL; } styleTableInitialized = True; /*------------------------------------------------------- * Only attempt to add build information to version text * when string formatting symbols are present in the text. * This special case is needed to incorporate this * dynamically created information into the static help. *-------------------------------------------------------*/ for (line = HelpText[ HELP_VERSION ]; *line != NULL; line++) { /*-------------------------------------------------- * If and when this printf format is found in the * version help text, replace that line with the * build information. Then stitching the help text * will have the final count of characters to use. *--------------------------------------------------*/ if (strstr (*line, "%s") != NULL) { const char * bldInfo = getBuildInfo(); char * text = XtMalloc (strlen (*line) + strlen (bldInfo)); sprintf (text, *line, bldInfo); *line = text; break; } } /*--------------------------------------------------------- * Also initialize the alphabet-to-ASCII-code table (to * make the style mapping also work on EBCDIC). * DON'T use 'A' to initialize the table! 'A' != 65 in EBCDIC. *--------------------------------------------------------*/ AlphabetToAsciiTable[(unsigned char)'A'] = ASCII_A + 0; AlphabetToAsciiTable[(unsigned char)'B'] = ASCII_A + 1; AlphabetToAsciiTable[(unsigned char)'C'] = ASCII_A + 2; AlphabetToAsciiTable[(unsigned char)'D'] = ASCII_A + 3; AlphabetToAsciiTable[(unsigned char)'E'] = ASCII_A + 4; AlphabetToAsciiTable[(unsigned char)'F'] = ASCII_A + 5; AlphabetToAsciiTable[(unsigned char)'G'] = ASCII_A + 6; AlphabetToAsciiTable[(unsigned char)'H'] = ASCII_A + 7; AlphabetToAsciiTable[(unsigned char)'I'] = ASCII_A + 8; AlphabetToAsciiTable[(unsigned char)'J'] = ASCII_A + 9; AlphabetToAsciiTable[(unsigned char)'K'] = ASCII_A + 10; AlphabetToAsciiTable[(unsigned char)'L'] = ASCII_A + 11; AlphabetToAsciiTable[(unsigned char)'M'] = ASCII_A + 12; AlphabetToAsciiTable[(unsigned char)'N'] = ASCII_A + 13; AlphabetToAsciiTable[(unsigned char)'O'] = ASCII_A + 14; AlphabetToAsciiTable[(unsigned char)'P'] = ASCII_A + 15; AlphabetToAsciiTable[(unsigned char)'Q'] = ASCII_A + 16; AlphabetToAsciiTable[(unsigned char)'R'] = ASCII_A + 17; AlphabetToAsciiTable[(unsigned char)'S'] = ASCII_A + 18; AlphabetToAsciiTable[(unsigned char)'T'] = ASCII_A + 19; AlphabetToAsciiTable[(unsigned char)'U'] = ASCII_A + 20; AlphabetToAsciiTable[(unsigned char)'V'] = ASCII_A + 21; AlphabetToAsciiTable[(unsigned char)'W'] = ASCII_A + 22; AlphabetToAsciiTable[(unsigned char)'X'] = ASCII_A + 23; AlphabetToAsciiTable[(unsigned char)'Y'] = ASCII_A + 24; AlphabetToAsciiTable[(unsigned char)'Z'] = ASCII_A + 25; } } /* ** Help fonts are not loaded until they're actually needed. This function ** checks if the style's font is loaded, and loads it if it's not. */ static void loadFontsAndColors(Widget parent, int style) { XFontStruct *font; int r,g,b; if (HelpStyleInfo[STYLE_INDEX(style)].font == NULL) { font = XLoadQueryFont(XtDisplay(parent), GetPrefHelpFontName(StyleFonts[STYLE_INDEX(style)])); if (font == NULL) { fprintf(stderr, "NEdit: help font, %s, not available\n", GetPrefHelpFontName(StyleFonts[STYLE_INDEX(style)])); font = XLoadQueryFont(XtDisplay(parent), "fixed"); if (font == NULL) { fprintf(stderr, "NEdit: fallback help font, \"fixed\", not " "available, cannot continue\n"); exit(EXIT_FAILURE); } } HelpStyleInfo[STYLE_INDEX(style)].font = font; if (style == STL_NM_LINK) HelpStyleInfo[STYLE_INDEX(style)].color = AllocColor(parent, GetPrefHelpLinkColor(), &r, &g, &b); } } static void adaptNavigationButtons(int topic) { Widget btn; if(HelpWindows[topic] == NULL) return; /* Shouldn't happen */ btn=XtNameToWidget(HelpWindows[topic], "helpForm.prevTopic"); if(btn) { if(topic > 0) XtSetSensitive(btn, True); else XtSetSensitive(btn, False); } btn=XtNameToWidget(HelpWindows[topic], "helpForm.nextTopic"); if(btn) { if(topic < (NUM_TOPICS - 1)) XtSetSensitive(btn, True); else XtSetSensitive(btn, False); } btn=XtNameToWidget(HelpWindows[topic], "helpForm.histBack"); if(btn) { if(navHistBack[topic] != -1) XtSetSensitive(btn, True); else XtSetSensitive(btn, False); } btn=XtNameToWidget(HelpWindows[topic], "helpForm.histForw"); if(btn) { if(navHistForw[topic] != -1) XtSetSensitive(btn, True); else XtSetSensitive(btn, False); } } /* ** Put together stored help strings to create the text and optionally the style ** information for a given help topic. */ static char * stitch ( Widget parent, /* used for dynamic font/color allocation */ char ** string_list, /* given help strings to stitch together */ char ** styleMap /* NULL, or a place to store help styles */ ) { char * cp; char * section, * sp; /* resulting help text section */ char * styleData, * sdp; /* resulting style data for text */ char style = STYLE_PLAIN; /* start off each section with this style */ int total_size = 0; /* help text section size */ char ** crnt_line; /*---------------------------------------------------- * How many characters are there going to be displayed? *----------------------------------------------------*/ for (crnt_line = string_list; *crnt_line != NULL; crnt_line++) { for (cp = *crnt_line; *cp != EOS; cp++) { /*--------------------------------------------- * The help text has embedded style information * consisting of the style marker and a single * character style, for a total of 2 characters. * This style information is not to be included * in the character counting below. *---------------------------------------------*/ if (*cp != STYLE_MARKER) { total_size++; } else { cp++; /* skipping style marker, loop will handle style */ } } } /*-------------------------------------------------------- * Get the needed space, one area for the help text being * stitched together, another for the styles to be applied. *--------------------------------------------------------*/ sp = section = XtMalloc (total_size +1); sdp = styleData = (styleMap) ? XtMalloc (total_size +1) : NULL; *sp = EOS; /*-------------------------------------------- * Fill in the newly acquired contiguous space * with help text and style information. *--------------------------------------------*/ for (crnt_line = string_list; *crnt_line != NULL; crnt_line++) { for (cp = *crnt_line; *cp != EOS; cp++) { if (*cp == STYLE_MARKER) { style = *(++cp); loadFontsAndColors(parent, style); } else { *(sp++) = *cp; /* Beware of possible EBCDIC coding! Use the mapping table. */ if (styleMap) *(sdp++) = AlphabetToAsciiTable[(unsigned char)style]; } } } *sp = EOS; /*----------------------------------------- * Only deal with style map, when available. *-----------------------------------------*/ if (styleMap) { *styleMap = styleData; *sdp = EOS; } return section; } /* ** Display help for subject "topic". "parent" is a widget over which the help ** dialog may be posted. Help dialogs are preserved when popped down by the ** user, and may appear posted over a previous parent, regardless of the parent ** argument. */ void Help(enum HelpTopic topic) { if (HelpWindows[topic] != NULL) RaiseShellWindow(HelpWindows[topic], True); else HelpWindows[topic] = createHelpPanel(topic); adaptNavigationButtons(topic); } /* Setup Window/Icon title for the help window. */ static void setHelpWinTitle(Widget win, enum HelpTopic topic) { char * buf, *topStr=HelpTitles[topic]; buf=malloc(strlen(topStr) + 24); topic++; sprintf(buf, "NEdit Help (%d)", (int)topic); XtVaSetValues(win, XmNiconName, buf, NULL); sprintf(buf, "NEdit Help: %s (%d)", topStr, (int)topic); XtVaSetValues(win, XmNtitle, buf, NULL); free(buf); } /* ** Create a new help window displaying a given subject, "topic" ** ** Important hint: If this widget is restructured or the name of the text ** subwidget is changed don't forget to adapt the default translations of the ** help text. They are located in nedit.c, look for ** static char *fallbackResources ** (currently: nedit.helpForm.sw.helpText*translations...) */ static Widget createHelpPanel(enum HelpTopic topic) { Arg al[50]; int ac; Widget appShell, btn, closeBtn, form, btnFW; Widget sw, hScrollBar, vScrollBar; XmString st1; char * helpText = NULL; char * styleData = NULL; ac = 0; XtSetArg(al[ac], XmNdeleteResponse, XmDO_NOTHING); ac++; appShell = CreateWidget(TheAppShell, "help", topLevelShellWidgetClass, al, ac); AddSmallIcon(appShell); /* With openmotif 2.1.30, a crash may occur when the text widget of the help window is (slowly) resized to a zero width. By imposing a minimum _window_ width, we can work around this problem. The minimum width should be larger than the width of the scrollbar. 50 is probably a safe value; this leaves room for a few characters */ XtVaSetValues(appShell, XtNminWidth, 50, NULL); form = XtVaCreateManagedWidget("helpForm", xmFormWidgetClass, appShell, NULL); XtVaSetValues(form, XmNshadowThickness, 0, NULL); /* Create the bottom row of buttons */ btn = XtVaCreateManagedWidget("find", xmPushButtonWidgetClass, form, XmNlabelString, st1=XmStringCreateSimple("Find..."), XmNmnemonic, 'F', XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 25, NULL); XtAddCallback(btn, XmNactivateCallback, searchHelpCB, appShell); XmStringFree(st1); btn = XtVaCreateManagedWidget("findAgain", xmPushButtonWidgetClass, form, XmNlabelString, st1=XmStringCreateSimple("Find Again"), XmNmnemonic, 'A', XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 27, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 49, NULL); XtAddCallback(btn, XmNactivateCallback, searchHelpAgainCB, appShell); XmStringFree(st1); btn = XtVaCreateManagedWidget("print", xmPushButtonWidgetClass, form, XmNlabelString, st1=XmStringCreateSimple("Print..."), XmNmnemonic, 'P', XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 51, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 73, NULL); XtAddCallback(btn, XmNactivateCallback, printCB, appShell); XmStringFree(st1); closeBtn = XtVaCreateManagedWidget("close", xmPushButtonWidgetClass, form, XmNlabelString, st1=XmStringCreateSimple("Close"), XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 75, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 97, NULL); XtAddCallback(closeBtn, XmNactivateCallback, closeCB, appShell); XmStringFree(st1); /* Create the next row of buttons (for navigation) */ btn = XtVaCreateManagedWidget("prevTopic", xmPushButtonWidgetClass, form, XmNlabelString, st1=XmStringCreateSimple("<< Browse"), XmNmnemonic, 'o', XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, closeBtn, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 51, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 73, NULL); XtAddCallback(btn, XmNactivateCallback, prevTopicCB, appShell); XmStringFree(st1); btn = XtVaCreateManagedWidget("nextTopic", xmPushButtonWidgetClass, form, XmNlabelString, st1=XmStringCreateSimple("Browse >>"), XmNmnemonic, 'e', XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, closeBtn, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 75, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 97, NULL); XtAddCallback(btn, XmNactivateCallback, nextTopicCB, appShell); XmStringFree(st1); btn = XtVaCreateManagedWidget("histBack", xmPushButtonWidgetClass, form, XmNlabelString, st1=XmStringCreateSimple("Back"), XmNmnemonic, 'B', XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, closeBtn, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 25, NULL); XtAddCallback(btn, XmNactivateCallback, bwHistoryCB, appShell); XmStringFree(st1); btnFW = XtVaCreateManagedWidget("histForw", xmPushButtonWidgetClass, form, XmNlabelString, st1=XmStringCreateSimple("Forward"), XmNmnemonic, 'w', XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, closeBtn, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 27, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 49, NULL); XtAddCallback(btnFW, XmNactivateCallback, fwHistoryCB, appShell); XmStringFree(st1); /* Create a text widget inside of a scrolled window widget */ sw = XtVaCreateManagedWidget("sw", xmScrolledWindowWidgetClass, form, XmNshadowThickness, 2, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, btnFW, NULL); hScrollBar = XtVaCreateManagedWidget("hScrollBar", xmScrollBarWidgetClass, sw, XmNorientation, XmHORIZONTAL, XmNrepeatDelay, 10, NULL); vScrollBar = XtVaCreateManagedWidget("vScrollBar", xmScrollBarWidgetClass, sw, XmNorientation, XmVERTICAL, XmNrepeatDelay, 10, NULL); /* Make sure the fixed size help font is loaded, such that we can base our text widget size calculation on it. */ loadFontsAndColors(sw, 'A'); HelpTextPanes[topic] = XtVaCreateManagedWidget("helpText", textWidgetClass, sw, textNfont, HelpStyleInfo[0].font, /* MUST correspond to 'A' above */ textNrows, 30, textNcolumns, 65, textNbacklightCharTypes, NULL, textNhScrollBar, hScrollBar, textNvScrollBar, vScrollBar, textNreadOnly, True, textNcontinuousWrap, True, textNautoShowInsertPos, True, NULL); XtVaSetValues(sw, XmNworkWindow, HelpTextPanes[topic], XmNhorizontalScrollBar, hScrollBar, XmNverticalScrollBar, vScrollBar, NULL); /* Initialize help style information, if it hasn't already been init'd */ initHelpStyles (HelpTextPanes[topic]); /* Put together the text to display and separate it into parallel text and style data for display by the widget */ helpText = stitch (HelpTextPanes[topic], HelpText[topic], &styleData); /* Stuff the text into the widget's text buffer */ BufSetAll (TextGetBuffer (HelpTextPanes[topic]) , helpText); XtFree (helpText); /* Create a style buffer for the text widget and fill it with the style data which was generated along with the text content */ HelpStyleBuffers[topic] = BufCreate(); BufSetAll(HelpStyleBuffers[topic], styleData); XtFree (styleData); TextDAttachHighlightData(((TextWidget)HelpTextPanes[topic])->text.textD, HelpStyleBuffers[topic], HelpStyleInfo, N_STYLES, '\0', NULL, NULL); /* This shouldn't be necessary (what's wrong in text.c?) */ HandleXSelections(HelpTextPanes[topic]); /* Process dialog mnemonic keys */ AddDialogMnemonicHandler(form, FALSE); /* Set the default button */ XtVaSetValues(form, XmNdefaultButton, closeBtn, NULL); XtVaSetValues(form, XmNcancelButton, closeBtn, NULL); /* realize all of the widgets in the new window */ RealizeWithoutForcingPosition(appShell); /* Give the text pane the initial focus */ XmProcessTraversal(HelpTextPanes[topic], XmTRAVERSE_CURRENT); /* Make close command in window menu gracefully prompt for close */ AddMotifCloseCallback(appShell, (XtCallbackProc)closeCB, appShell); /* Initialize navigation information, if it hasn't already been init'd */ initNavigationHistory(); /* Set the window title */ setHelpWinTitle(appShell, topic); #ifdef EDITRES XtAddEventHandler (appShell, (EventMask)0, True, (XtEventHandler)_XEditResCheckMessages, NULL); #endif /* EDITRES */ return appShell; } static void changeTopicOrRaise(int existingTopic, int newTopic) { if(HelpWindows[newTopic] == NULL) { changeWindowTopic(existingTopic, (enum HelpTopic) newTopic); adaptNavigationButtons(newTopic); } else { RaiseShellWindow(HelpWindows[newTopic], True); adaptNavigationButtons(existingTopic); adaptNavigationButtons(newTopic); } } /* ** Callbacks for window controls */ static void closeCB(Widget w, XtPointer clientData, XtPointer callData) { int topic; if ((topic = findTopicFromShellWidget((Widget)clientData)) == -1) return; /* I don't understand the mechanism by which this can be called with HelpWindows[topic] as NULL, but it has happened */ XtDestroyWidget(HelpWindows[topic]); HelpWindows[topic] = NULL; if (HelpStyleBuffers[topic] != NULL) { BufFree(HelpStyleBuffers[topic]); HelpStyleBuffers[topic] = NULL; } } static void prevTopicCB(Widget w, XtPointer clientData, XtPointer callData) { int topic; if ((topic = findTopicFromShellWidget((Widget)clientData)) == -1) return; /* shouldn't happen */ topic--; if(topic >= 0) changeTopicOrRaise(topic+1, topic); } static void nextTopicCB(Widget w, XtPointer clientData, XtPointer callData) { int topic; if ((topic = findTopicFromShellWidget((Widget)clientData)) == -1) return; /* shouldn't happen */ topic++; if(topic < NUM_TOPICS) changeTopicOrRaise(topic-1, topic); } static void bwHistoryCB(Widget w, XtPointer clientData, XtPointer callData) { int topic, goTo; if ((topic = findTopicFromShellWidget((Widget)clientData)) == -1) return; /* shouldn't happen */ goTo=navHistBack[topic]; if(goTo >= 0 && goTo < NUM_TOPICS) { navHistForw[goTo]=topic; changeTopicOrRaise(topic, goTo); } } static void fwHistoryCB(Widget w, XtPointer clientData, XtPointer callData) { int topic, goTo; if ((topic = findTopicFromShellWidget((Widget)clientData)) == -1) return; /* shouldn't happen */ goTo=navHistForw[topic]; if(goTo >= 0 && goTo < NUM_TOPICS) { navHistBack[goTo]=topic; changeTopicOrRaise(topic, goTo); } } static void searchHelpCB(Widget w, XtPointer clientData, XtPointer callData) { char promptText[DF_MAX_PROMPT_LENGTH]; int response, topic; static char **searchHistory = NULL; static int nHistoryStrings = 0; if ((topic = findTopicFromShellWidget((Widget)clientData)) == -1) return; /* shouldn't happen */ SetDialogFPromptHistory(searchHistory, nHistoryStrings); response = DialogF(DF_PROMPT, HelpWindows[topic], 3, "Find", "Search for: (use up arrow key to recall previous)", promptText, "This Section", "All Sections", "Cancel"); if (response == 3) return; AddToHistoryList(promptText, &searchHistory, &nHistoryStrings); searchHelpText(HelpWindows[topic], topic, promptText, response == 2, 0, 0); } static void searchHelpAgainCB(Widget w, XtPointer clientData, XtPointer callData) { int topic; if ((topic = findTopicFromShellWidget((Widget)clientData)) == -1) return; /* shouldn't happen */ searchHelpText(HelpWindows[topic], topic, LastSearchString, LastSearchWasAllTopics, LastSearchPos, LastSearchTopic); } static void printCB(Widget w, XtPointer clientData, XtPointer callData) { int topic, helpStringLen; char *helpString; if ((topic = findTopicFromShellWidget((Widget)clientData)) == -1) return; /* shouldn't happen */ helpString = TextGetWrapped(HelpTextPanes[topic], 0, TextGetBuffer(HelpTextPanes[topic])->length, &helpStringLen); PrintString(helpString, helpStringLen, HelpWindows[topic], HelpTitles[topic]); XtFree(helpString); } /* ** Find the topic and text position within that topic targeted by a hyperlink ** with name "link_name". Returns true if the link was successfully interpreted. */ static int is_known_link(char *link_name, int *topic, int *textPosition) { Href * hypertext; /*------------------------------ * Direct topic links found here. *------------------------------*/ for (*topic=0; HelpTitles[*topic] != NULL; (*topic)++) { if (strcmp (link_name, HelpTitles[*topic]) == 0) { *textPosition = 0; return 1; } } /*------------------------------------ * Links internal to topics found here. *------------------------------------*/ for (hypertext = &H_R[0]; hypertext != NULL; hypertext = hypertext->next) { if (strcmp (link_name, hypertext->source) == 0) { *topic = hypertext->topic; *textPosition = hypertext->location; return 1; } } return 0; } /* ** Find the text of a hyperlink from a clicked character position somewhere ** within the hyperlink text, and display the help that it links to. */ static void followHyperlink(int topic, int charPosition, int newWindow) { textDisp *textD = ((TextWidget)HelpTextPanes[topic])->text.textD; char * link_text; int link_topic; int link_pos; int end = charPosition; int begin = charPosition; char whatStyle = BufGetCharacter(textD->styleBuffer, end); /*-------------------------------------------------- * Locate beginning and ending of current text style. *--------------------------------------------------*/ while (whatStyle == BufGetCharacter(textD->styleBuffer, ++end)); while (whatStyle == BufGetCharacter(textD->styleBuffer, begin-1)) begin--; link_text = BufGetRange (textD->buffer, begin, end); if (is_known_link (link_text, &link_topic, &link_pos) ) { if (HelpWindows[link_topic] != NULL) { RaiseShellWindow(HelpWindows[link_topic], True); } else { if (newWindow) { HelpWindows[link_topic] = createHelpPanel((enum HelpTopic) link_topic); } else { changeWindowTopic(topic, (enum HelpTopic) link_topic); } } navHistBack[link_topic] = topic; navHistForw[topic] = link_topic; TextSetCursorPos(HelpTextPanes[link_topic], link_pos); adaptNavigationButtons(link_topic); adaptNavigationButtons(topic); } XtFree (link_text); } static void helpFocusButtonsAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XmProcessTraversal(w, XmTRAVERSE_NEXT_TAB_GROUP); } /* * handler for help-button-action() * Calls the activate callback for the named button widget of the help text win. */ static void helpButtonActionAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { char buf[80]; int topic; Widget btn; if(*nArgs != 1) { fprintf(stderr, "help-button-action: requires exactly one argument.\n"); return; } /* Find the topic being displayed by this widget */ for (topic = 0; topic < NUM_TOPICS; topic++) if (HelpTextPanes[topic] == w) break; if(topic == NUM_TOPICS || HelpWindows[topic] == NULL) return; /* Shouldn't happen */ /* Compose the button widget name */ strcpy(&buf[0], "helpForm."); if (strlen(args[0]) <= 70) { strcat(&buf[0], args[0]); } else { fprintf(stderr, "help-button-action: argument too long"); return; } btn=XtNameToWidget(HelpWindows[topic], buf); if (btn) { XtCallCallbacks(btn, XmNactivateCallback, HelpWindows[topic]); } else { fprintf(stderr, "help-button-action: invalid argument: %s\n", args[0]); } } /* * Handler for action help-hyperlink() * Arguments: none - init: record event position * "current": if clicked on a link, follow link in same window * "new": if clicked on a link, follow link in new window * * With the 1st argument "current" or "new" this action can have two additional * arguments. These arguments must be valid names of XmText actions. * In this case, the action named in argument #2 is called if the action * help-hyperlink is about to follow the hyperlink. The Action in argument #3 * is called if no hyperlink has been recognized at the current event position. */ static void helpHyperlinkAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XButtonEvent *e = (XButtonEvent *)event; int topic; textDisp *textD = ((TextWidget)w)->text.textD; int clickedPos, newWin; static int pressX=0, pressY=0; /* called without arguments we just record coordinates */ if (*nArgs == 0) { pressX = e->x; pressY = e->y; return; } newWin = !strcmp(args[0], "new"); if(!newWin && strcmp(args[0], "current")) { fprintf(stderr, "help-hyperlink: Unrecognized argument %s\n", args[0]); return; } /* * If for any reason (pointer moved - drag!, no hyperlink found) * this action can't follow a hyperlink then execute the the action * named in arg #3 (if provided) */ if (abs(pressX - e->x) > CLICK_THRESHOLD || abs(pressY - e->y) > CLICK_THRESHOLD) { if (*nArgs == 3) XtCallActionProc(w, args[2], event, NULL, 0); return; } clickedPos = TextDXYToCharPos(textD, e->x, e->y); /* Beware of possible EBCDIC coding! Use the mapping table. */ if (BufGetCharacter(textD->styleBuffer, clickedPos) != (char)AlphabetToAsciiTable[(unsigned char)STL_NM_LINK]) { if (*nArgs == 3) XtCallActionProc(w, args[2], event, NULL, 0); return; } /* Find the topic being displayed by this widget */ for (topic = 0; topic < NUM_TOPICS; topic++) if (HelpTextPanes[topic] == w) break; if (topic == NUM_TOPICS) { /* If we get here someone must have bound help-hyperlink to a non-help * text widget (!) Or some other really strange thing happened. */ if (*nArgs == 3) XtCallActionProc(w, args[2], event, NULL, 0); return; } /* If the action help-hyperlink had 3 arguments execute the action * named in arg #2 before really following the link. */ if (*nArgs == 3) XtCallActionProc(w, args[1], event, NULL, 0); followHyperlink(topic, clickedPos, newWin); } /* ** Install the action for following hyperlinks in the help window */ void InstallHelpLinkActions(XtAppContext context) { static XtActionsRec Actions[] = { {"help-hyperlink", helpHyperlinkAP}, {"help-focus-buttons", helpFocusButtonsAP}, {"help-button-action", helpButtonActionAP} }; XtAppAddActions(context, Actions, XtNumber(Actions)); } /* ** Search the help text. If allSections is true, searches all of the help ** text, otherwise searches only in parentTopic. */ static void searchHelpText(Widget parent, int parentTopic, const char *searchFor, int allSections, int startPos, int startTopic) { int topic, beginMatch, endMatch; int found = False; char * helpText = NULL; /* Search for the string */ for (topic=startTopic; topictext.textD, NULL, NULL, 0, '\0', NULL, NULL); BufSetAll(TextGetBuffer(HelpTextPanes[newTopic]), helpText); XtFree(helpText); BufSetAll(HelpStyleBuffers[newTopic], styleData); XtFree(styleData); TextDAttachHighlightData(((TextWidget)HelpTextPanes[newTopic])->text.textD, HelpStyleBuffers[newTopic], HelpStyleInfo, N_STYLES, '\0', NULL, NULL); } static int findTopicFromShellWidget(Widget shellWidget) { int i; for (i=0; i in Motif 1.2 only. As for Motif 2.1 we don't need this call anymore. This also holds for the Motif 2.1 version of LessTif releases > 0.93.0. */ extern void XmRegisterConverters(void); #endif /* Print version info to stdout */ void PrintVersion(void) { const char *text; #if XmVersion < 2001 XmRegisterConverters(); /* see comment above */ #endif text = getBuildInfo(); puts (text); } nedit-5.6.orig/source/help.h0000644000175000017500000001012510737527367014533 0ustar paulpaul/* $Id: help.h,v 1.13 2008/01/04 22:11:03 yooden Exp $ */ /******************************************************************************* * * * help.h -- Nirvana Editor Help Display * * * * Copyright (c) 1999-2001 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * September 10, 1991 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifndef NEDIT_HELP_H_INCLUDED #define NEDIT_HELP_H_INCLUDED #include "help_topic.h" #include /*============================================================================*/ /* VARIABLE TYPE DEFINITIONS */ /*============================================================================*/ typedef struct HelpMenu /* Maintains help menu structure */ { struct HelpMenu * next; int level; /* menu level, submenu > 1 */ enum HelpTopic topic; /* HELP_none for submenu & separator */ char * wgtName; int hideIt; /* value which determines displayability */ char mnemonic; /* '-' for separator */ char * subTitle; /* title for sub menu, or NULL */ } HelpMenu; typedef struct Href /* Source to topic internal hyperlinks */ { struct Href * next; int location; /* position to link in topic */ enum HelpTopic topic; /* target of link in this topic */ char * source; /* hypertext link characters */ } Href; /*============================================================================*/ /* VARIABLE DECLARATIONS */ /*============================================================================*/ extern HelpMenu H_M[]; extern char *HelpTitles[]; extern const char linkdate[]; extern const char linktime[]; /*============================================================================*/ /* PROGRAM PROTOTYPES */ /*============================================================================*/ void Help(enum HelpTopic topic); void PrintVersion(void); void InstallHelpLinkActions(XtAppContext context); #endif /* NEDIT_HELP_H_INCLUDED */ nedit-5.6.orig/source/help_data.h0000644000175000017500000105325010737527367015533 0ustar paulpaul/******************************************************************************* * * * help_data.h -- Nirvana Editor help module data * * * Generated on Apr 10, 2006 (Do NOT edit!) Source of content from file help.etx * * * Copyright (c) 1999-2006 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * In addition, as a special exception to the GNU GPL, the copyright holders * * give permission to link the code of this program with the Motif and Open * * Motif libraries (or with modified versions of these that use the same * * license), and distribute linked combinations including the two. You must * * obey the GNU General Public License in all respects for all of the code used * * other than linking with Motif/Open Motif. If you modify this file, you may * * extend this exception to your version of the file, but you are not obligated * * to do so. If you do not wish to do so, delete this exception statement from * * your version. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * September 10, 1991 * * * * Written by Mark Edel * * * *******************************************************************************/ char *HelpTitles[] = { "Getting Started", "Selecting Text", "Finding and Replacing Text", "Cut and Paste", "Using the Mouse", "Keyboard Shortcuts", "Shifting and Filling", "Tabbed Editing", "File Format", "Programming with NEdit", "Tabs/Emulated Tabs", "Auto/Smart Indent", "Syntax Highlighting", "Finding Declarations (ctags)", "Calltips", "Basic Regular Expression Syntax", "Metacharacters", "Parenthetical Constructs", "Advanced Topics", "Example Regular Expressions", "Shell Commands and Filters", "Learn/Replay", "Macro Language", "Macro Subroutines", "Range Sets", "Highlighting Information", "Action Routines", "Customizing NEdit", "Preferences", "X Resources", "Key Binding", "Highlighting Patterns", "Smart Indent Macros", "NEdit Command Line", "Client/Server Mode", "Crash Recovery", "Version", "GNU General Public License", "Mailing Lists", "Problems/Defects", "Tabs Dialog", "Customize Window Title Dialog", NULL }; static char * htxt_start [] = { "\01IWelcome to NEdit! ", "\n\n", "NEdit is a standard GUI (Graphical User Interface) style text editor for ", "programs and plain-text files. Users of Macintosh and MS Windows based text ", "editors should find NEdit a familiar and comfortable environment. NEdit ", "provides all of the standard menu, dialog, editing, and mouse support, as ", "well as all of the standard shortcuts to which the users of modern GUI based ", "environments are accustomed. For users of older style Unix editors, welcome ", "to the world of mouse-based editing! ", "\n\n", "Help sections of interest to new users are listed under the \"Basic Operation\" ", "heading in the top-level Help menu: ", "\n\n", "\01A \01QSelecting Text\01A\n", " \01QFinding and Replacing Text\01A\n", " \01QCut and Paste\01A\n", " \01QUsing the Mouse\01A\n", " \01QKeyboard Shortcuts\01A\n", " \01QShifting and Filling\01A\n", "\01I\n", "Programmers should also read the introductory section under the \"Features for ", "Programming\" section: ", "\n\n", "\01A \01QProgramming with NEdit\01A\n", "\01I\n", "If you get into trouble, the Undo command in the Edit menu can reverse any ", "modifications that you make. NEdit does not change the file you are editing ", "until you tell it to Save. ", "\n\n", "\01REditing an Existing File\01I", "\n\n", "To open an existing file, choose Open... from the file menu. Select the file ", "that you want to open in the pop-up dialog that appears and click on OK. You ", "may open any number of files at the same time. Depending on your settings ", "(cf. \"\01QTabbed Editing\01I\") each file can appear in its own editor window, or it ", "can appear under a tab in the same editor window. Using Open... rather than ", "re-typing the NEdit command and running additional copies of NEdit, will give ", "you quick access to all of the files you have open via the Windows menu, and ", "ensure that you don't accidentally open the same file twice. NEdit has no ", "\"main\" window. It remains running as long as at least one editor window is ", "open. ", "\n\n", "\01RCreating a New File\01I", "\n\n", "If you already have an empty (Untitled) window displayed, just begin typing ", "in the window. To create a new Untitled window, choose New Window or New Tab ", "from the File menu. To give the file a name and save its contents to the ", "disk, choose Save or Save As... from the File menu. ", "\n\n", "\01RBackup Files\01I", "\n\n", "NEdit maintains periodic backups of the file you are editing so that you can ", "recover the file in the event of a problem such as a system crash, network ", "failure, or X server crash. These files are saved under the name `~filename` ", "(on Unix) or `_filename` (on VMS), where filename is the name of the file you ", "were editing. If an NEdit process is killed, some of these backup files may ", "remain in your directory. (To remove one of these files on Unix, you may ", "have to prefix the `~' (tilde) character with a (backslash) to prevent the ", "shell from interpreting it as a special character.) ", "\n\n", "\01RShortcuts\01I", "\n\n", "As you become more familiar with NEdit, substitute the control and function ", "keys shown on the right side of the menus for pulling down menus with the ", "mouse. ", "\n\n", "Dialogs are also streamlined so you can enter information quickly and without ", "using the mouse*. To move the keyboard focus around a dialog, use the tab ", "and arrow keys. One of the buttons in a dialog is usually drawn with a ", "thick, indented, outline. This button can be activated by pressing Return or ", "Enter. The Cancel or Dismiss button can be activated by pressing escape. ", "For example, to replace the string \"thing\" with \"things\" type: ", "\n\n", "\01A thingthings\n", "\01I\n", "To open a file named \"whole_earth.c\", type: ", "\n\n", "\01A who\n", "\01I\n", "(how much of the filename you need to type depends on the other files in the ", "directory). See the section called \"\01QKeyboard Shortcuts\01I\" for more details. ", "\n\n", "* Users who have set their keyboard focus mode to \"pointer\" should set ", "\"Popups Under Pointer\" in the Default Settings menu to avoid the additional ", "step of moving the mouse into the dialog. ", NULL }; static char * htxt_select [] = { "\01INEdit has two general types of selections, primary (highlighted text), and ", "secondary (underlined text). Selections can cover either a simple range of ", "text between two points in the file, or they can cover a rectangular area of ", "the file. Rectangular selections are only useful with non-proportional (fixed ", "spacing) fonts. ", "\n\n", "To select text for copying, deleting, or replacing, press the left mouse ", "button with the pointer at one end of the text you want to select, and drag ", "it to the other end. The text will become highlighted. To select a whole ", "word, double click (click twice quickly in succession). Double clicking and ", "then dragging the mouse will select a number of words. Similarly, you can ", "select a whole line or a number of lines by triple clicking or triple ", "clicking and dragging. Quadruple clicking selects the whole file. After ", "releasing the mouse button, you can still adjust a selection by holding down ", "the shift key and dragging on either end of the selection. To delete the ", "selected text, press delete or backspace. To replace it, begin typing. ", "\n\n", "To select a rectangle or column of text, hold the Ctrl key while dragging the ", "mouse. Rectangular selections can be used in any context that normal ", "selections can be used, including cutting and pasting, filling, shifting, ", "dragging, and searching. Operations on rectangular selections automatically ", "fill in tabs and spaces to maintain alignment of text within and to the right ", "of the selection. Note that the interpretation of rectangular selections by ", "Fill Paragraph is slightly different from that of other commands, the section ", "titled \"\01QShifting and Filling\01I\" has details. ", "\n\n", "The middle mouse button can be used to make an additional selection (called ", "the secondary selection). As soon as the button is released, the contents of ", "this selection will be copied to the insert position of the window where the ", "mouse was last clicked (the destination window). This position is marked by a ", "caret shaped cursor when the mouse is outside of the destination window. If ", "there is a (primary) selection, adjacent to the cursor in the window, the new ", "text will replace the selected text. Holding the shift key while making the ", "secondary selection will move the text, deleting it at the site of the ", "secondary selection, rather than copying it. ", "\n\n", "Selected text can also be dragged to a new location in the file using the ", "middle mouse button. Holding the shift key while dragging the text will copy ", "the selected text, leaving the original text in place. Holding the control ", "key will drag the text in overlay mode. ", "\n\n", "Normally, dragging moves text by removing it from the selected position at ", "the start of the drag, and inserting it at a new position relative to the ", "mouse. Dragging a block of text over existing characters, displaces the ", "characters to the end of the selection. In overlay mode, characters which are ", "occluded by blocks of text being dragged are simply removed. When dragging ", "non-rectangular selections, overlay mode also converts the selection to ", "rectangular form, allowing it to be dragged outside of the bounds of the ", "existing text. ", "\n\n", "The section \"\01QUsing the Mouse\01I\" summarizes the mouse commands for making primary ", "and secondary selections. Primary selections can also be made via keyboard ", "commands, see \"\01QKeyboard Shortcuts\01I\". ", NULL }; static char * htxt_search [] = { "\01IThe Search menu contains a number of commands for finding and replacing text. ", "\n\n", "The Find... and Replace... commands present dialogs for entering text for ", "searching and replacing. These dialogs also allow you to choose whether you ", "want the search to be sensitive to upper and lower case, or whether to use ", "the standard Unix pattern matching characters (regular expressions). ", "Searches begin at the current text insertion position. ", "\n\n", "Find Again and Replace Again repeat the last find or replace command without ", "prompting for search strings. To selectively replace text, use the two ", "commands in combination: Find Again, then Replace Again if the highlighted ", "string should be replaced, or Find Again again to go to the next string. ", "\n\n", "Find Selection searches for the text contained in the current primary ", "selection (see \01QSelecting Text\01I). The selected text does not have to be in the ", "current editor window, it may even be in another program. For example, if ", "the word dog appears somewhere in a window on your screen, and you want to ", "find it in the file you are editing, select the word dog by dragging the ", "mouse across it, switch to your NEdit window and choose Find Selection from ", "the Search menu. ", "\n\n", "Find Incremental, which opens the interactive search bar, is yet another variation ", "on searching, where every character typed triggers a new search. After you've ", "completed the search string, the next occurrence in the buffer is found by hitting ", "the Return key, or by clicking on the icon to the left (magnifying glass). Holding ", "a Shift key down finds the previous occurrences. To the right there is a clear ", "button with an icon resembling \"|<\". Clicking on it empties the search text widget ", "without disturbing selections. A middle click on the clear button copies the ", "content of any existing selection into the search text widget and triggers a new ", "search. ", "\n\n", "\01RSearching Backwards\01I", "\n\n", "Holding down the shift key while choosing any of the search or replace ", "commands from the menu (or using the keyboard shortcut), will search in the ", "reverse direction. Users who have set the search direction using the buttons ", "in the search dialog, may find it a bit confusing that Find Again and Replace ", "Again don't continue in the same direction as the original search (for ", "experienced users, consistency of the direction implied by the shift key is ", "more important). ", "\n\n", "\01RSelective Replacement\01I", "\n\n", "To replace only some occurrences of a string within a file, choose Replace... ", "from the Search menu, enter the string to search for and the string to ", "substitute, and finish by pressing the Find button. When the first ", "occurrence is highlighted, use either Replace Again (^T) to replace it, or ", "Find Again (^G) to move to the next occurrence without replacing it, and ", "continue in such a manner through all occurrences of interest. ", "\n\n", "To replace all occurrences of a string within some range of text, select the ", "range (see \01QSelecting Text\01I), choose Replace... from the Search menu, type the ", "string to search for and the string to substitute, and press the \"R. in ", "Selection\" button in the dialog. Note that selecting text in the Replace... ", "dialog will unselect the text in the window. ", NULL }; static char * htxt_clipboard [] = { "\01IThe easiest way to copy and move text around in your file or between windows, ", "is to use the clipboard, an imaginary area that temporarily stores text and ", "data. The Cut command removes the selected text (see \01QSelecting Text\01I) from ", "your file and places it in the clipboard. Once text is in the clipboard, the ", "Paste command will copy it to the insert position in the current window. For ", "example, to move some text from one place to another, select it by dragging ", "the mouse over it, choose Cut to remove it, click the pointer to move the ", "insert point where you want the text inserted, then choose Paste to insert ", "it. Copy copies text to the clipboard without deleting it from your file. ", "You can also use the clipboard to transfer text to and from other Motif ", "programs and X programs which make proper use of the clipboard. ", "\n\n", "There are many other methods for copying and moving text within NEdit windows ", "and between NEdit and other programs. The most common such method is ", "clicking the middle mouse button to copy the primary selection (to the ", "clicked position). Copying the selection by clicking the middle mouse button ", "in many cases is the only way to transfer data to and from many X programs. ", "Holding the Shift key while clicking the middle mouse button moves the text, ", "deleting it from its original position, rather than copying it. Other ", "methods for transferring text include secondary selections, primary selection ", "dragging, keyboard-based selection copying, and drag and drop. These are ", "described in detail in the sections: \"\01QSelecting Text\01I\", \"\01QUsing the Mouse\01I\", ", "and \"\01QKeyboard Shortcuts\01I\". ", NULL }; static char * htxt_mouse [] = { "\01IMouse-based editing is what NEdit is all about, and learning to use the more ", "advanced features like secondary selections and primary selection dragging ", "will be well worth your while. ", "\n\n", "If you don't have time to learn everything, you can get by adequately with ", "just the left mouse button: Clicking the left button moves the cursor. ", "Dragging with the left button makes a selection. Holding the shift key while ", "clicking extends the existing selection, or begins a selection between the ", "cursor and the mouse. Double or triple clicking selects a whole word or a ", "whole line. ", "\n\n", "This section will make more sense if you also read the section called, ", "\"\01QSelecting Text\01I\", which explains the terminology of selections, that is, ", "what is meant by primary, secondary, rectangular, etc. ", "\n\n", "\01RButton and Modifier Key Summary\01I", "\n\n", "General meaning of mouse buttons and modifier keys: ", "\n\n", "\01S Buttons\01I", "\n\n", "\01A Button 1 (left) Cursor position and primary selection\n", "\01I\n", "\01A Button 2 (middle) Secondary selections, and dragging and\n", " copying the primary selection\n", "\01I\n", "\01A Button 3 (right) Quick-access programmable menu and pan\n", " scrolling\n", "\01I\n", "\01S Modifier keys\01I", "\n\n", "\01A Shift On primary selections, (left mouse button):\n", " Extends selection to the mouse pointer\n", " On secondary and copy operations, (middle):\n", " Toggles between move and copy\n", "\01I\n", "\01A Ctrl Makes selection rectangular or insertion\n", " columnar\n", "\01I\n", "\01A Alt* (on release) Exchange primary and secondary\n", " selections.\n", "\01I\n", "\01RLeft Mouse Button\01I", "\n\n", "The left mouse button is used to position the cursor and to make primary ", "selections. ", "\n\n", "\01A Click Moves the cursor\n", "\01I\n", "\01A Double Click Selects a whole word\n", "\01I\n", "\01A Triple Click Selects a whole line\n", "\01I\n", "\01A Quad Click Selects the whole file\n", "\01I\n", "\01A Shift Click Adjusts (extends or shrinks) the\n", " selection, or if there is no existing\n", " selection, begins a new selection\n", " between the cursor and the mouse.\n", "\01I\n", "\01A Ctrl+Shift+ Adjusts (extends or shrinks) the\n", " Click selection rectangularly.\n", "\01I\n", "\01A Drag Selects text between where the mouse\n", " was pressed and where it was released.\n", "\01I\n", "\01A Ctrl+Drag Selects rectangle between where the\n", " mouse was pressed and where it was\n", " released.\n", "\01I\n", "\01RRight Mouse Button\01I", "\n\n", "The right mouse button posts a programmable menu for frequently used commands. ", "\n\n", "\01A Click/Drag Pops up the background menu (programmed\n", " from Preferences -> Default Settings ->\n", " Customize Menus -> Window Background).\n", "\01I\n", "\01A Ctrl+Drag Pan scrolling. Scrolls the window\n", " both vertically and horizontally, as if\n", " you had grabbed it with your mouse.\n", "\01I\n", "\01RMiddle Mouse Button\01I", "\n\n", "The middle mouse button is for making secondary selections, and copying and ", "dragging the primary selection. ", "\n\n", "\01A Click Copies the primary selection to the\n", " clicked position.\n", "\01I\n", "\01A Shift+Click Moves the primary selection to the\n", " clicked position, deleting it from its\n", " original position.\n", "\01I\n", "\01A Drag 1) Outside of the primary selection:\n", " Begins a secondary selection.\n", " 2) Inside of the primary selection:\n", " Moves the selection by dragging.\n", "\01I\n", "\01A Ctrl+Drag 1) Outside of the primary selection:\n", " Begins a rectangular secondary\n", " selection.\n", " 2) Inside of the primary selection:\n", " Drags the selection in overlay\n", " mode (see below).\n", "\01I\n", "When the mouse button is released after creating a secondary selection: ", "\n\n", "\01A No Modifiers If there is a primary selection,\n", " replaces it with the secondary\n", " selection. Otherwise, inserts the\n", " secondary selection at the cursor\n", " position.\n", "\01I\n", "\01A Shift Move the secondary selection, deleting\n", " it from its original position. If\n", " there is a primary selection, the move\n", " will replace the primary selection\n", " with the secondary selection.\n", " Otherwise, moves the secondary\n", " selection to the cursor position.\n", "\01I\n", "\01A Alt* Exchange the primary and secondary\n", " selections.\n", "\01I\n", "While moving the primary selection by dragging with the middle mouse button: ", "\n\n", "\01A Shift Leaves a copy of the original\n", " selection in place rather than\n", " removing it or blanking the area.\n", "\01I\n", "\01A Ctrl Changes from insert mode to overlay\n", " mode (see below).\n", "\01I\n", "\01A Escape Cancels drag in progress.\n", "\01I\n", "Overlay Mode: Normally, dragging moves text by removing it from the selected ", "position at the start of the drag, and inserting it at a new position ", "relative to the mouse. When you drag a block of text over existing ", "characters, the existing characters are displaced to the end of the ", "selection. In overlay mode, characters which are occluded by blocks of text ", "being dragged are simply removed. When dragging non-rectangular selections, ", "overlay mode also converts the selection to rectangular form, allowing it to ", "be dragged outside of the bounds of the existing text. ", "\n\n", "Mouse buttons 4 and 5 are usually represented by a mouse wheel nowadays. ", "They are used to scroll up or down in the text window. ", "\n\n", "* The Alt key may be labeled Meta or Compose-Character on some keyboards. ", "Some window managers, including default configurations of mwm, bind ", "combinations of the Alt key and mouse buttons to window manager operations. ", "In NEdit, Alt is only used on button release, so regardless of the window ", "manager bindings for Alt-modified mouse buttons, you can still do the ", "corresponding NEdit operation by using the Alt key AFTER the initial mouse ", "press, so that Alt is held while you release the mouse button. If you find ", "this difficult or annoying, you can re-configure most window managers to skip ", "this binding, or you can re-configure NEdit to use a different key ", "combination. ", NULL }; static char * htxt_keyboard [] = { "\01IMost of the keyboard shortcuts in NEdit are shown on the right hand sides of ", "the pull-down menus. However, there are more which are not as obvious. These ", "include; dialog button shortcuts; menu and dialog mnemonics; labeled keyboard ", "keys, such as the arrows, page-up, page-down, and home; and optional Shift ", "modifiers on accelerator keys, like [Shift]Ctrl+F. ", "\n\n", "\01RMenu Accelerators\01I", "\n\n", "Pressing the key combinations shown on the right of the menu items is a ", "shortcut for selecting the menu item with the mouse. Some items have the shift ", "key enclosed in brackets, such as [Shift]Ctrl+F. This indicates that the shift ", "key is optional. In search commands, including the shift key reverses the ", "direction of the search. In Shift commands, it makes the command shift the ", "selected text by a whole tab stop rather than by single characters. ", "\n\n", "\01RMenu Mnemonics\01I", "\n\n", "Pressing the Alt key in combination with one of the underlined characters in ", "the menu bar pulls down that menu. Once the menu is pulled down, typing the ", "underlined characters in a menu item (without the Alt key) activates that ", "item. With a menu pulled down, you can also use the arrow keys to select menu ", "items, and the Space or Enter keys to activate them. ", "\n\n", "\01RKeyboard Shortcuts within Dialogs\01I", "\n\n", "One button in a dialog is usually marked with a thick indented outline. ", "Pressing the Return or Enter key activates this button. ", "\n\n", "All dialogs have either a Cancel or Dismiss button. This button can be ", "activated by pressing the Escape (or Esc) key. ", "\n\n", "Pressing the tab key moves the keyboard focus to the next item in a dialog. ", "Within an associated group of buttons, the arrow keys move the focus among the ", "buttons. Shift+Tab moves backward through the items. ", "\n\n", "Most items in dialogs have an underline under one character in their name. ", "Pressing the Alt key along with this character, activates a button as if you ", "had pressed it with the mouse, or moves the keyboard focus to the associated ", "text field or list. ", "\n\n", "You can select items from a list by using the arrow keys to move the ", "selection and space to select. ", "\n\n", "In file selection dialogs, you can type the beginning characters of the file ", "name or directory in the list to select files ", "\n\n", "\01RLabeled Function Keys\01I", "\n\n", "The labeled function keys on standard workstation and PC keyboards, like the ", "arrows, and page-up and page-down, are active in NEdit, though not shown in the ", "pull-down menus. ", "\n\n", "Holding down the control key while pressing a named key extends the scope of ", "the action that it performs. For example, Home normally moves the insert ", "cursor the beginning of a line. Ctrl+Home moves it to the beginning of the ", "file. Backspace deletes one character, Ctrl+Backspace deletes one word. ", "\n\n", "Holding down the shift key while pressing a named key begins or extends a ", "selection. Combining the shift and control keys combines their actions. For ", "example, to select a word without using the mouse, position the cursor at the ", "beginning of the word and press Ctrl+Shift+RightArrow. The Alt key modifies ", "selection commands to make the selection rectangular. ", "\n\n", "Under X and Motif, there are several levels of translation between keyboard ", "keys and the actions they perform in a program. The \"\01QCustomizing NEdit\01I\", and ", "\"\01QX Resources\01I\" sections of the Help menu have more information on this subject. ", "Because of all of this configurability, and since keyboards and standards for ", "the meaning of some keys vary from machine to machine, the mappings may be ", "changed from the defaults listed below. ", "\n\n", "\01RModifier Keys (in general)\01I", "\n\n", "\01A Ctrl Extends the scope of the action that the key\n", " would otherwise perform. For example, Home\n", " normally moves the insert cursor to the beginning\n", " of a line. Ctrl+Home moves it to the beginning of\n", " the file. Backspace deletes one character, Ctrl+\n", " Backspace deletes one word.\n", "\01I\n", "\01A Shift Extends the selection to the cursor position. If\n", " there's no selection, begins one between the old\n", " and new cursor positions.\n", "\01I\n", "\01A Alt When modifying a selection, makes the selection\n", " rectangular.\n", "\01I\n", "(For the effects of modifier keys on mouse button presses, see the section ", "titled \"\01QUsing the Mouse\01I\") ", "\n\n", "\01RAll Keyboards\01I", "\n\n", "\01A Escape Cancels operation in progress: menu\n", " selection, drag, selection, etc. Also\n", " equivalent to cancel button in dialogs.\n", "\01I\n", "\01A Backspace Delete the character before the cursor\n", "\01I\n", "\01A Ctrl+BS Delete the word before the cursor\n", "\01I\n", "\01A Arrows --\n", "\01I\n", "\01A Left Move the cursor to the left one character\n", "\01I\n", "\01A Ctrl+Left Move the cursor backward one word\n", " (Word delimiters are settable, see\n", " \"\01QCustomizing NEdit\01A\", and \"\01QX Resources\01A\")\n", "\01I\n", "\01A Right Move the cursor to the right one character\n", "\01I\n", "\01A Ctrl+Right Move the cursor forward one word\n", "\01I\n", "\01A Up Move the cursor up one line\n", "\01I\n", "\01A Ctrl+Up Move the cursor up one paragraph.\n", " (Paragraphs are delimited by blank lines)\n", "\01I\n", "\01A Down Move the cursor down one line.\n", "\01I\n", "\01A Ctrl+Down Move the cursor down one paragraph.\n", "\01I\n", "\01A Ctrl+Return Return with automatic indent, regardless\n", " of the setting of Auto Indent.\n", "\01I\n", "\01A Shift+Return Return without automatic indent,\n", " regardless of the setting of Auto Indent.\n", "\01I\n", "\01A Ctrl+Tab Insert an ASCII tab character, without\n", " processing emulated tabs.\n", "\01I\n", "\01A Alt+Ctrl+ Insert the control-code equivalent of\n", " a key \n", "\01I\n", "\01A Ctrl+/ Select everything (same as Select\n", " All menu item or ^A)\n", "\01I\n", "\01A Ctrl+\\ Unselect\n", "\01I\n", "\01A Ctrl+U Delete to start of line\n", "\01I\n", "\01RPC Standard Keyboard\01I", "\n\n", "\01A Ctrl+Insert Copy the primary selection to the\n", " clipboard (same as Copy menu item or ^C)\n", " for compatibility with Motif standard key\n", " binding\n", " Shift+Ctrl+\n", " Insert Copy the primary selection to the cursor\n", " location.\n", "\01I\n", "\01A Delete Delete the character before the cursor.\n", " (Can be configured to delete the character\n", " after the cursor, see \"\01QCustomizing NEdit\01A\",\n", " and \"\01QX Resources\01A\")\n", "\01I\n", "\01A Ctrl+Delete Delete to end of line.\n", "\01I\n", "\01A Shift+Delete Cut, remove the currently selected text\n", " and place it in the clipboard. (same as\n", " Cut menu item or ^X) for compatibility\n", " with Motif standard key binding\n", " Shift+Ctrl+\n", " Delete Cut the primary selection to the cursor\n", " location.\n", "\01I\n", "\01A Home Move the cursor to the beginning of the\n", " line\n", "\01I\n", "\01A Ctrl+Home Move the cursor to the beginning of the\n", " file\n", "\01I\n", "\01A End Move the cursor to the end of the line\n", "\01I\n", "\01A Ctrl+End Move the cursor to the end of the file\n", "\01I\n", "\01A PageUp Scroll and move the cursor up by one page.\n", "\01I\n", "\01A PageDown Scroll and move the cursor down by one\n", " page.\n", "\01I\n", "\01A F10 Make the menu bar active for keyboard\n", " input (Arrow Keys, Return, Escape,\n", " and the Space Bar)\n", "\01I\n", "\01A Alt+Home Switch to the previously active document.\n", "\01I\n", "\01A Ctrl+PageUp Switch to the previous document.\n", "\01I\n", "\01A Ctrl+PageDown Switch to the next document.\n", "\01I\n", "\01RSpecialty Keyboards \01I", "\n\n", "On machines with different styles of keyboards, generally, text editing ", "actions are properly matched to the labeled keys, such as Remove, ", "Next-screen, etc.. If you prefer different key bindings, see the section ", "titled \"\01QKey Binding\01I\" under the Customizing heading in the Help menu. ", NULL }; static char * htxt_fill [] = { "\01RShift Left, Shift Right\01I", "\n\n", "While shifting blocks of text is most important for programmers (See Features ", "for Programming), it is also useful for other tasks, such as creating ", "indented paragraphs. ", "\n\n", "To shift a block of text one tab stop to the right, select the text, then ", "choose Shift Right from the Edit menu. Note that the accelerator keys for ", "these menu items are Ctrl+9 and Ctrl+0, which correspond to the right and ", "left parenthesis on most keyboards. Remember them as adjusting the text in ", "the direction pointed to by the parenthesis character. Holding the Shift key ", "while selecting either Shift Left or Shift Right will shift the text by one ", "character. ", "\n\n", "It is also possible to shift blocks of text by selecting the text ", "rectangularly, and dragging it left or right (and up or down as well). Using ", "a rectangular selection also causes tabs within the selection to be ", "recalculated and substituted, such that the non-whitespace characters remain ", "stationary with respect to the selection. ", "\n\n", "\01RFilling \01I", "\n\n", "Text filling using the Fill Paragraph command in the Edit menu is one of the ", "most important concepts in NEdit. And it will be well worth your while to ", "understand how to use it properly. ", "\n\n", "In plain text files, unlike word-processor files, there is no way to tell ", "which lines are continuations of other lines, and which lines are meant to be ", "separate, because there is no distinction in meaning between newline ", "characters which separate lines in a paragraph, and ones which separate ", "paragraphs from other text. This makes it impossible for a text editor like ", "NEdit to tell parts of the text which belong together as a paragraph from ", "carefully arranged individual lines. ", "\n\n", "In continuous wrap mode (Preferences -> Wrap -> Continuous), lines ", "automatically wrap and unwrap themselves to line up properly at the right ", "margin. In this mode, you simply omit the newlines within paragraphs and let ", "NEdit make the line breaks as needed. Unfortunately, continuous wrap mode is ", "not appropriate in the majority of situations, because files with extremely ", "long lines are not common under Unix and may not be compatible with all ", "tools, and because you can't achieve effects like indented sections, columns, ", "or program comments, and still take advantage of the automatic wrapping. ", "\n\n", "Without continuous wrapping, paragraph filling is not entirely automatic. ", "Auto-Newline wrapping keeps paragraphs lined up as you type, but once ", "entered, NEdit can no longer distinguish newlines which join wrapped text, ", "and newlines which must be preserved. Therefore, editing in the middle of a ", "paragraph will often leave the right margin messy and uneven. ", "\n\n", "Since NEdit can't act automatically to keep your text lined up, you need to ", "tell it explicitly where to operate, and that is what Fill Paragraph is for. ", "It arranges lines to fill the space between two margins, wrapping the lines ", "neatly at word boundaries. Normally, the left margin for filling is inferred ", "from the text being filled. The first line of each paragraph is considered ", "special, and its left indentation is maintained separately from the remaining ", "lines (for leading indents, bullet points, numbered paragraphs, etc.). ", "Otherwise, the left margin is determined by the furthest left non-whitespace ", "character. The right margin is either the Wrap Margin, set in the ", "preferences menu (by default, the right edge of the window), or can also be ", "chosen on the fly by using a rectangular selection (see below). ", "\n\n", "There are three ways to use Fill Paragraph. The simplest is, while you are ", "typing text, and there is no selection, simply select Fill Paragraph (or type ", "Ctrl+J), and NEdit will arrange the text in the paragraph adjacent to the ", "cursor. A paragraph, in this case, means an area of text delimited by blank ", "lines. ", "\n\n", "The second way to use Fill Paragraph is with a selection. If you select a ", "range of text and then chose Fill Paragraph, all of the text in the selection ", "will be filled. Again, continuous text between blank lines is interpreted as ", "paragraphs and filled individually, respecting leading indents and blank ", "lines. ", "\n\n", "The third, and most versatile, way to use Fill Paragraph is with a ", "rectangular selection. Fill Paragraph treats rectangular selections ", "differently from other commands. Instead of simply filling the text inside ", "the rectangular selection, NEdit interprets the right edge of the selection ", "as the requested wrap margin. Text to the left of the selection is not ", "disturbed (the usual interpretation of a rectangular selection), but text to ", "the right of the selection is included in the operation and is pulled in to ", "the selected region. This method enables you to fill text to an arbitrary ", "right margin, without going back and forth to the wrap-margin dialog, as well ", "as to exclude text to the left of the selection such as comment bars or other ", "text columns. ", NULL }; static char * htxt_interface [] = { "\01INEdit is able to display files in distinct editor windows, or to display files ", "under tabs in the same editor window. The Options for controlling the tabbed ", "interface are found under Preferences -> Default Settings -> Tabbed Editing ", "(cf. \"\01QPreferences\01I\", also \"\01QNEdit Command Line\01I\"). ", "\n\n", "Notice that you can re-group tabs at any time by detaching and attaching them, ", "or moving them, to other windows. This can be done using the Windows menu, or ", "using the context menu, which pops up when right clicking on a tab. ", "\n\n", "You can switch to a tab by simply clicking on it, or you can use the keyboard. ", "The default keybindings to switch tabs (which are Ctrl+PageUp/-Down and Alt+Home, ", "see \"\01QKeyboard Shortcuts\01I\") can be changed using the actions previous_document(), ", "next_document() and last_document(). ", "\n\n", NULL }; static char * htxt_format [] = { "\01IWhile plain-text is probably the simplest and most interchangeable file ", "format in the computer world, there is still variation in what plain-text ", "means from system to system. Plain-text files can differ in character set, ", "line termination, and wrapping. ", "\n\n", "While character set differences are the most obvious and pose the most ", "challenge to portability, they affect NEdit only indirectly via the same font ", "and localization mechanisms common to all X applications. If your system is ", "set up properly, you will probably never see character-set related problems ", "in NEdit. NEdit can not display Unicode text files, or any multi-byte ", "character set. ", "\n\n", "The primary difference between an MS DOS format file and a Unix format file, ", "is how the lines are terminated. Unix uses a single newline character. MS ", "DOS uses a carriage-return and a newline. NEdit can read and write both file ", "formats, but internally, it uses the single character Unix standard. NEdit ", "auto-detects MS DOS format files based on the line termination at the start ", "of the file. Files are judged to be DOS format if all of the first five line ", "terminators, within a maximum range, are DOS-style. To change the format in ", "which NEdit writes a file from DOS to Unix or visa versa, use the Save As... ", "command and check or un-check the MS DOS Format button. ", "\n\n", "Wrapping within text files can vary among individual users, as well as from ", "system to system. Both Windows and MacOS make frequent use of plain text ", "files with no implicit right margin. In these files, wrapping is determined ", "by the tool which displays them. Files of this style also exist on Unix ", "systems, despite the fact that they are not supported by all Unix utilities. ", "To display this kind of file properly in NEdit, you have to select the wrap ", "style called Continuous. Wrapping modes are discussed in the sections: ", "Customizing -> Preferences, and Basic Operation -> Shifting and Filling. ", "\n\n", "The last and most minute of format differences is the terminating newline. ", "Some Unix compilers and utilities require a final terminating newline on all ", "files they read and fail in various ways on files which do not have it. Vi ", "and approximately half of Unix editors enforce the terminating newline on all ", "files that they write; Emacs does not enforce this rule. Users are divided ", "on which is best. NEdit makes the final terminating newline optional ", "(Preferences -> Default Settings -> Terminate with Line Break on Save). ", NULL }; static char * htxt_programmer [] = { "\01IThough general in appearance, NEdit has many features intended specifically ", "for programmers. Major programming-related topics are listed in separate ", "sections under the heading: \"Features for Programming\": \01QSyntax Highlighting\01I, ", "\01QTabs/Emulated Tabs\01I, \01QFinding Declarations (ctags)\01I, \01QCalltips\01I, and ", "\01QAuto/Smart Indent\01I. Minor topics related to programming are discussed below: ", "\n\n", "\01RLanguage Modes\01I", "\n\n", "When NEdit initially reads a file, it attempts to determine whether the file ", "is in one of the computer languages that it knows about. Knowing what language ", "a file is written in allows NEdit to assign highlight patterns and smart indent ", "macros, and to set language specific preferences like word delimiters, tab ", "emulation, and auto-indent. Language mode can be recognized from both the file ", "name and from the first 200 characters of content. Language mode recognition ", "and language-specific preferences are configured in: Preferences -> Default ", "Settings -> Language Modes.... ", "\n\n", "You can set the language mode manually for a window, by selecting it from the ", "menu: Preferences -> Language Modes. ", "\n\n", "\01RBacklighting [EXPERIMENTAL]\01I", "\n\n", "NEdit can be made to set the background color of particular classes of ", "characters to allow easy identification of those characters. This is ", "particularly useful if you need to be able to distinguish between tabs ", "and spaces in a file where the difference is important. The colors used ", "for backlighting are specified by a resource, \"nedit*backlightCharTypes\". ", "You can turn backlighting on and off through the ", "Preferences -> Apply Backlighting menu entry. ", "\n\n", "If you prefer to have backlighting turned on for all new windows, use ", "the Preferences -> Default Settings -> Apply Backlighting menu entry. ", "This settings can be saved along with other preferences using ", "Preferences -> Save Defaults. ", "\n\n", "\01JImportant:\01I In future versions of NEdit, the backlighting feature will be ", "extended and reworked such that it becomes easier to configure. The current ", "way of controlling it through a resource is generally considered to be below ", "NEdit's usability standards. These future changes are likely to be ", "incompatible with the current format of the \"nedit*backlightCharTypes\" ", "resource, though. Therefore, it is expected that there will be no automatic ", "migration path for users who customize the resource. ", "\n\n", "\01RLine Numbers\01I", "\n\n", "To find a particular line in a source file by line number, choose Goto Line ", "#... from the Search menu. You can also directly select the line number text ", "in the compiler message in the terminal emulator window (xterm, decterm, ", "winterm, etc.) where you ran the compiler, and choose Goto Selected from the ", "Search menu. ", "\n\n", "To find out the line number of a particular line in your file, turn on ", "Statistics Line in the Preferences menu and position the insertion point ", "anywhere on the line. The statistics line continuously updates the line number ", "of the line containing the cursor. ", "\n\n", "To go to a specific column on a given line, choose Goto Line #... from the ", "Search menu and enter a line number and a column number separated by a ", "comma. (e.g. Enter \"100,12\" for line 100 column 12.) If you want to go to ", "a column on the current line just leave out the line number. (e.g. Enter ", "\",45\" to go the column 45 on the current line.) ", "\n\n", "\01RMatching Parentheses\01I", "\n\n", "To help you inspect nested parentheses, brackets, braces, quotes, and other ", "characters, NEdit has both an automatic parenthesis matching mode, and a Goto ", "Matching command. Automatic parenthesis matching is activated when you type, ", "or move the insertion cursor after a parenthesis, bracket, or brace. It ", "momentarily highlights either the opposite character ('Delimiter') or the ", "entire expression ('Range') when the opposite character is visible in the ", "window. To find a matching character anywhere in the file, select it or ", "position the cursor after it, and choose Goto Matching from the Search menu. ", "If the character matches itself, such as a quote or slash, select the first ", "character of the pair. NEdit will match {, (, [, <, \", ', `, /, and \\. ", "Holding the Shift key while typing the accelerator key (Shift+Ctrl+M, by ", "default), will select all of the text between the matching characters. ", "\n\n", "When syntax highlighting is enabled, the matching routines can optionally ", "make use of the syntax information for improved accuracy. In that case, ", "a brace inside a highlighted string will not match a brace inside a comment, ", "for instance. ", "\n\n", "\01ROpening Included Files\01I", "\n\n", "The Open Selected command in the File menu understands the C preprocessor's ", "#include syntax, so selecting an #include line and invoking Open Selected will ", "generally find the file referred to, unless doing so depends on the settings of ", "compiler switches or other information not available to NEdit. ", "\n\n", "\01RInterface to Programming Tools\01I", "\n\n", "Integrated software development environments such as SGI's CaseVision and ", "Centerline Software's Code Center, can be interfaced directly with NEdit via ", "the client server interface. These tools allow you to click directly on ", "compiler and runtime error messages and request NEdit to open files, and select ", "lines of interest. The easiest method is usually to use the tool's interface ", "for character-based editors like vi, to invoke nc, but programmatic interfaces ", "can also be derived using the source code for nc. ", "\n\n", "There are also some simple compile/review, grep, ctree, and ctags browsers ", "available in the NEdit contrib directory on ftp.nedit.org. ", NULL }; static char * htxt_tabs [] = { "\01RChanging the Tab Distance\01I", "\n\n", "Tabs are important for programming in languages which use indentation to show ", "nesting, as short-hand for producing white-space for leading indents. As a ", "programmer, you have to decide how to use indentation, and how or whether tab ", "characters map to your indentation scheme. ", "\n\n", "Ideally, tab characters map directly to the amount of indent that you use to ", "distinguish nesting levels in your code. Unfortunately, the Unix standard ", "for interpretation of tab characters is eight characters (probably dating ", "back to mechanical capabilities of the original teletype), which is usually ", "too coarse for a single indent. ", "\n\n", "Most text editors, NEdit included, allow you to change the interpretation of ", "the tab character, and many programmers take advantage of this, and set their ", "tabs to 3 or 4 characters to match their programming style. In NEdit you set ", "the hardware tab distance in Preferences -> Tabs... for the current window, ", "or Preferences -> Default Settings -> Tabs... (general), or Preferences -> ", "Default Settings -> Language Modes... (language-specific) to change the ", "defaults for future windows. ", "\n\n", "Changing the meaning of the tab character makes programming much easier while ", "you're in the editor, but can cause you headaches outside of the editor, ", "because there is no way to pass along the tab setting as part of a plain-text ", "file. All of the other tools which display, print, and otherwise process ", "your source code have to be made aware of how the tabs are set, and must be ", "able to handle the change. Non-standard tabs can also confuse other ", "programmers, or make editing your code difficult for them if their text ", "editors don't support changes in tab distance. ", "\n\n", "\01REmulated Tabs\01I", "\n\n", "An alternative to changing the interpretation of the tab character is tab ", "emulation. In the Tabs... dialog(s), turning on Emulated Tabs causes the Tab ", "key to insert the correct number of spaces and/or tabs to bring the cursor ", "the next emulated tab stop, as if tabs were set at the emulated tab distance ", "rather than the hardware tab distance. Backspacing immediately after entering ", "an emulated tab will delete the fictitious tab as a unit, but as soon as you ", "move the cursor away from the spot, NEdit will forget that the collection of ", "spaces and tabs is a tab, and will treat it as separate characters. To enter ", "a real tab character with \"Emulate Tabs\" turned on, use Ctrl+Tab. ", "\n\n", "It is also possible to tell NEdit not to insert ANY tab characters at all in ", "the course of processing emulated tabs, and in shifting and rectangular ", "insertion/deletion operations, for programmers who worry about the ", "misinterpretation of tab characters on other systems. ", NULL }; static char * htxt_indent [] = { "\01IProgrammers who use structured languages usually require some form of ", "automatic indent, so that they don't have to continually re-type the ", "sequences of tabs and/or spaces needed to maintain lengthy running indents. ", "NEdit therefore offers \"smart\" indent, in addition to the traditional ", "automatic indent which simply lines up the cursor position with the previous ", "line. ", "\n\n", "\01RSmart Indent\01I", "\n\n", "Smart indent macros are only available by default for C and C++, and while ", "these can easily be configured for different default indentation distances, ", "they may not conform to everyone's exact C programming style. Smart indent ", "is programmed in terms of macros in the NEdit macro language which can be ", "entered in: Preferences -> Default Settings -> Indent -> Program Smart ", "Indent. Hooks are provided for intervening at the point that a newline is ", "entered, either via the user pressing the Enter key, or through ", "auto-wrapping; and for arbitrary type-in to act on specific characters typed. ", "\n\n", "To type a newline character without invoking smart-indent when operating in ", "smart-indent mode, hold the Shift key while pressing the Return or Enter key. ", "\n\n", "\01RAuto-Indent\01I", "\n\n", "With Indent set to Auto (the default), NEdit keeps a running indent. When ", "you press the Return or Enter key, spaces and tabs are inserted to line up ", "the insert point under the start of the previous line. ", "\n\n", "Regardless of indent-mode, Ctrl+Return always does the automatic indent; ", "Shift+Return always does a return without indent. ", "\n\n", "\01RBlock Indentation Adjustment\01I", "\n\n", "The Shift Left and Shift Right commands as well as rectangular dragging can ", "be used to adjust the indentation for several lines at once. To shift a ", "block of text one character to the right, select the text, then choose Shift ", "Right from the Edit menu. Note that the accelerator keys for these menu ", "items are Ctrl+9 and Ctrl+0, which correspond to the right and left ", "parenthesis on most keyboards. Remember them as adjusting the text in the ", "direction pointed to by the parenthesis character. Holding the Shift key ", "while selecting either Shift Left or Shift Right will shift the text by one ", "tab stop (or by one emulated tab stop if tab emulation is turned on). The ", "help section \"Shifting and Filling\" under \"Basic Operation\" has details. ", NULL }; static char * htxt_syntax [] = { "\01ISyntax Highlighting means using colors and fonts to help distinguish language ", "elements in programming languages and other types of structured files. ", "Programmers use syntax highlighting to understand code faster and better, and ", "to spot many kinds of syntax errors more quickly. ", "\n\n", "To use syntax highlighting in NEdit, select Highlight Syntax in the ", "Preferences menu. If NEdit recognizes the computer language that you are ", "using, and highlighting rules (patterns) are available for that language, it ", "will highlight your text, and maintain the highlighting, automatically, as ", "you type. ", "\n\n", "If NEdit doesn't correctly recognize the type of the file you are editing, ", "you can manually select a language mode from Language Modes in the ", "Preferences menu. You can also program the method that NEdit uses to ", "recognize language modes in Preferences -> Default Settings -> Language ", "Modes.... ", "\n\n", "If no highlighting patterns are available for the language that you want to ", "use, you can create new patterns relatively quickly. The Help section ", "\"\01QHighlighting Patterns\01I\" under \"Customizing\", has details. ", "\n\n", "If you are satisfied with what NEdit is highlighting, but would like it to ", "use different colors or fonts, you can change these by selecting Preferences ", "-> Default Settings -> Syntax Highlighting -> Text Drawing Styles. ", "Highlighting patterns are connected with font and color information through a ", "common set of styles so that colorings defined for one language will be ", "similar across others, and patterns within the same language which are meant ", "to appear identical can be changed in the same place. To understand which ", "styles are used to highlight the language you are interested in, you may need ", "to look at \"\01QHighlighting Patterns\01I\" section, as well. ", "\n\n", "Syntax highlighting is CPU intensive, and under some circumstances can affect ", "NEdit's responsiveness. If you have a particularly slow system, or work with ", "very large files, you may not want to use it all of the time. Syntax ", "highlighting introduces two kinds of delays. The first is an initial parsing ", "delay, proportional to the size of the file. This delay is also incurred ", "when pasting large sections of text, filtering text through shell commands, ", "and other circumstances involving changes to large amounts of text. The ", "second kind of delay happens when text which has not previously been visible ", "is scrolled in to view. Depending on your system, and the highlight patterns ", "you are using, this may or may not be noticeable. A typing delay is also ", "possible, but unlikely if you are only using the built-in patterns. ", NULL }; static char * htxt_tags [] = { "\01INEdit can process tags files generated using the Unix ctags command or the ", "Exuberant Ctags program. Ctags creates index files correlating names of ", "functions and declarations with their locations in C, Fortran, or Pascal source ", "code files. (See the ctags manual page for more information). Ctags produces a ", "file called \"tags\" which can be loaded by NEdit. NEdit can manage any number ", "of tags files simultaneously. Tag collisions are handled with a popup menu to ", "let the user decide which tag to use. In 'Smart' mode NEdit will automatically ", "choose the desired tag based on the scope of the file or module. Once loaded, ", "the information in the tags file enables NEdit to go directly to the ", "declaration of a highlighted function or data structure name with a single ", "command. To load a tags file, select \"Load Tags File\" from the File menu and ", "choose a tags file to load, or specify the name of the tags file on the NEdit ", "command line: ", "\n\n", "\01A nedit -tags tags\n", "\01I\n", "NEdit can also be set to load a tags file automatically when it starts up. ", "Setting the X resource nedit.tagFile to the name of a tag file tells NEdit to ", "look for that file at startup time (see \"\01QCustomizing NEdit\01I\"). The file name ", "can be either a complete path name, in which case NEdit will always load the ", "same tags file, or a file name without a path or with a relative path, in ", "which case NEdit will load it starting from the current directory. The ", "second option allows you to have different tags files for different projects, ", "each automatically loaded depending on the directory you're in when you start ", "NEdit. Setting the name to \"tags\" is an obvious choice since this is the ", "name that ctags uses. NEdit normally evaluates relative path tag file ", "specifications every time a file is opened. All accessible tag files are ", "loaded at this time. To disable the automatic loading of tag files specified ", "as relative paths, set the X resource nedit.alwaysCheckRelativeTagsSpecs to ", "False. ", "\n\n", "To unload a tags file, select \"Un-load Tags File\" from the File menu and ", "choose from the list of tags files. NEdit will keep track of tags file updates ", "by checking the timestamp on the files, and automatically update the tags ", "cache. ", "\n\n", "To find the definition of a function or data structure once a tags file is ", "loaded, select the name anywhere it appears in your program (see ", "\"\01QSelecting Text\01I\") and choose \"Find Definition\" from the Search menu. ", NULL }; static char * htxt_calltips [] = { "\01ICalltips are little yellow boxes that pop up to remind you what the arguments ", "and return type of a function are. More generally, they're a UI mechanism to ", "present a small amount of crucial information in a prominent location. To ", "display a calltip, select some text and choose \"Show Calltip\" from the Search ", "menu. To kill a displayed calltip, hit Esc. ", "\n\n", "Calltips get their information from one of two places -- either a tags file (see ", "\"\01QFinding Declarations (ctags)\01I\") or a calltips file. First, any loaded calltips ", "files are searched for a definition, and if nothing is found then the tags ", "database is searched. If a tag is found that matches the highlighted text then ", "a calltip is displayed with the first few lines of the definition -- usually ", "enough to show you what the arguments of a function are. ", "\n\n", "You can load a calltips file by using choosing \"Load Calltips File\" from the ", "File menu. You can unload a calltips file by selecting it from the ", "\"Unload Calltips File\" submenu of the File menu. You can also choose one or ", "more default calltips files to be loaded for each language mode using the ", "\"Default calltips file(s)\" field of the Language Modes dialog. ", "\n\n", "The calltips file format is very simple. calltips files are organized in blocks ", "separated by blank lines. The first line of the block is the key, which is the ", "word that is matched when a calltip is requested. The rest of the block is ", "displayed as the calltip. ", "\n\n", "Almost any text at all can appear in a calltip key or a calltip. There are no ", "special characters that need to be escaped. The only issues to note are that ", "trailing whitespace is ignored, and you cannot have a blank line inside a ", "calltip. (Use a single period instead -- it'll be nearly invisible.) You should ", "also avoid calltip keys that begin and end with '*' characters, since those are ", "used to mark special blocks. ", "\n\n", "There are five special block types--comment, include, language, alias, and ", "version--which are distinguished by their first lines, \"* comment *\", ", "\"* include *\", \"* language *\", \"* alias *\", and \"* version *\" respectively ", "(without quotes). ", "\n\n", "Comment blocks are ignored when reading calltips files. ", "\n\n", "Include blocks specify additional calltips files to load, one per line. The ~ ", "character can be used for your $HOME directory, but other shell shortcuts like ", "* and ? can't be used. Include blocks allow you to make a calltips file for your ", "project that includes, say, the calltips files for C, Motif, and Xt. ", "\n\n", "Language blocks specify which language mode the calltips should be used with. ", "When a calltip is requested it won't match tips from languages other than the ", "current language mode. Language blocks only affect the tips listed after the ", "block. ", "\n\n", "Alias blocks allow a calltip to have multiple keys. The first line of the block ", "is the key for the calltip to be displayed, and the rest of the lines are ", "additional keys, one per line, that should also show the calltip. ", "\n\n", "Version blocks are ignored for the time being. ", "\n\n", "You can use calltips in your own macros using the calltip() and kill_calltip() ", "macro subroutines and the $calltip_ID macro variable. See the ", "\01QMacro Subroutines\01I section for details. ", NULL }; static char * htxt_basicSyntax [] = { "\01IRegular expressions (regex's) are useful as a way to match inexact sequences ", "of characters. They can be used in the `Find...' and `Replace...' search ", "dialogs and are at the core of Color Syntax Highlighting patterns. To specify ", "a regular expression in a search dialog, simply click on the `Regular ", "Expression' radio button in the dialog. ", "\n\n", "A regex is a specification of a pattern to be matched in the searched text. ", "This pattern consists of a sequence of tokens, each being able to match a ", "single character or a sequence of characters in the text, or assert that a ", "specific position within the text has been reached (the latter is called an ", "anchor.) Tokens (also called atoms) can be modified by adding one of a number ", "of special quantifier tokens immediately after the token. A quantifier token ", "specifies how many times the previous token must be matched (see below.) ", "\n\n", "Tokens can be grouped together using one of a number of grouping constructs, ", "the most common being plain parentheses. Tokens that are grouped in this way ", "are also collectively considered to be a regex atom, since this new larger ", "atom may also be modified by a quantifier. ", "\n\n", "A regex can also be organized into a list of alternatives by separating each ", "alternative with pipe characters, `|'. This is called alternation. A match ", "will be attempted for each alternative listed, in the order specified, until a ", "match results or the list of alternatives is exhausted (see \01QAlternation\01I ", "section below.) ", "\n\n", "\01RThe 'Any' Character\01I", "\n\n", "If a dot (`.') appears in a regex, it means to match any character exactly ", "once. By default, dot will not match a newline character, but this behavior ", "can be changed (see help topic \01QParenthetical Constructs\01I, under the ", "heading, Matching Newlines). ", "\n\n", "\01RCharacter Classes\01I", "\n\n", "A character class, or range, matches exactly one character of text, but the ", "candidates for matching are limited to those specified by the class. Classes ", "come in two flavors as described below: ", "\n\n", "\01A [...] Regular class, match only characters listed.\n", " [^...] Negated class, match only characters NOT listed.\n", "\01I\n", "As with the dot token, by default negated character classes do not match ", "newline, but can be made to do so. ", "\n\n", "The characters that are considered special within a class specification are ", "different than the rest of regex syntax as follows. If the first character in ", "a class is the `]' character (second character if the first character is `^') ", "it is a literal character and part of the class character set. This also ", "applies if the first or last character is `-'. Outside of these rules, two ", "characters separated by `-' form a character range which includes all the ", "characters between the two characters as well. For example, `[^f-j]' is the ", "same as `[^fghij]' and means to match any character that is not `f', `g', ", "`h', `i', or `j'. ", "\n\n", "\01RAnchors\01I", "\n\n", "Anchors are assertions that you are at a very specific position within the ", "search text. NEdit regular expressions support the following anchor tokens: ", "\n\n", "\01A ^ Beginning of line\n", " $ End of line\n", " < Left word boundary\n", " > Right word boundary\n", " \\B Not a word boundary\n", "\01I\n", "Note that the \\B token ensures that neither the left nor the right ", "character are delimiters, or that both left and right characters are ", "delimiters. The left word anchor checks whether the previous character ", "is a delimiter and the next character is not. The right word anchor ", "works in a similar way. ", "\n\n", "\01RQuantifiers\01I", "\n\n", "Quantifiers specify how many times the previous regular expression atom may ", "be matched in the search text. Some quantifiers can produce a large ", "performance penalty, and can in some instances completely lock up NEdit. To ", "prevent this, avoid nested quantifiers, especially those of the maximal ", "matching type (see below.) ", "\n\n", "The following quantifiers are maximal matching, or \"greedy\", in that they ", "match as much text as possible (but don't exclude shorter matches if that ", "is necessary to achieve an overall match). ", "\n\n", "\01A * Match zero or more\n", " + Match one or more\n", " ? Match zero or one\n", "\01I\n", "The following quantifiers are minimal matching, or \"lazy\", in that they match ", "as little text as possible (but don't exclude longer matches if that is ", "necessary to achieve an overall match). ", "\n\n", "\01A *? Match zero or more\n", " +? Match one or more\n", " ?? Match zero or one\n", "\01I\n", "One final quantifier is the counting quantifier, or brace quantifier. It ", "takes the following basic form: ", "\n\n", "\01A {min,max} Match from `min' to `max' times the\n", " previous regular expression atom.\n", "\01I\n", "If `min' is omitted, it is assumed to be zero. If `max' is omitted, it is ", "assumed to be infinity. Whether specified or assumed, `min' must be less ", "than or equal to `max'. Note that both `min' and `max' are limited to ", "65535. If both are omitted, then the construct is the same as `*'. Note ", "that `{,}' and `{}' are both valid brace constructs. A single number ", "appearing without a comma, e.g. `{3}' is short for the `{min,min}' construct, ", "or to match exactly `min' number of times. ", "\n\n", "The quantifiers `{1}' and `{1,1}' are accepted by the syntax, but are ", "optimized away since they mean to match exactly once, which is redundant ", "information. Also, for efficiency, certain combinations of `min' and `max' ", "are converted to either `*', `+', or `?' as follows: ", "\n\n", "\01A {} {,} {0,} *\n", " {1,} +\n", " {,1} {0,1} ?\n", "\01I\n", "Note that {0} and {0,0} are meaningless and will generate an error message at ", "regular expression compile time. ", "\n\n", "Brace quantifiers can also be \"lazy\". For example {2,5}? would try to match ", "2 times if possible, and will only match 3, 4, or 5 times if that is what is ", "necessary to achieve an overall match. ", "\n\n", "\01RAlternation\01I", "\n\n", "A series of alternative patterns to match can be specified by separating them ", "with vertical pipes, `|'. An example of alternation would be `a|be|sea'. ", "This will match `a', or `be', or `sea'. Each alternative can be an ", "arbitrarily complex regular expression. The alternatives are attempted in ", "the order specified. An empty alternative can be specified if desired, e.g. ", "`a|b|'. Since an empty alternative can match nothingness (the empty string), ", "this guarantees that the expression will match. ", "\n\n", "\01RComments\01I", "\n\n", "Comments are of the form `(?#)' and can be inserted anywhere ", "and have no effect on the execution of the regular expression. They can be ", "handy for documenting very complex regular expressions. Note that a comment ", "begins with `(?#' and ends at the first occurrence of an ending parenthesis, ", "or the end of the regular expression... period. Comments do not recognize ", "any escape sequences. ", NULL }; static char * htxt_escapeSequences [] = { "\01REscaping Metacharacters\01I", "\n\n", "In a regular expression (regex), most ordinary characters match themselves. ", "For example, `ab%' would match anywhere `a' followed by `b' followed by `%' ", "appeared in the text. Other characters don't match themselves, but are ", "metacharacters. For example, backslash is a special metacharacter which ", "'escapes' or changes the meaning of the character following it. Thus, to ", "match a literal backslash would require a regular expression to have two ", "backslashes in sequence. NEdit provides the following escape sequences so ", "that metacharacters that are used by the regex syntax can be specified as ", "ordinary characters. ", "\n\n", "\01A \\( \\) \\- \\[ \\] \\< \\> \\{ \\}\n", " \\. \\| \\^ \\$ \\* \\+ \\? \\& \\\\\n", "\01I\n", "\01RSpecial Control Characters\01I", "\n\n", "There are some special characters that are difficult or impossible to type. ", "Many of these characters can be constructed as a sort of metacharacter or ", "sequence by preceding a literal character with a backslash. NEdit recognizes ", "the following special character sequences: ", "\n\n", "\01A \\a alert (bell)\n", " \\b backspace\n", " \\e ASCII escape character (***)\n", " \\f form feed (new page)\n", " \\n newline\n", " \\r carriage return\n", " \\t horizontal tab\n", " \\v vertical tab\n", "\01I\n", "\01A *** For environments that use the EBCDIC character set,\n", " when compiling NEdit set the EBCDIC_CHARSET compiler\n", " symbol to get the EBCDIC equivalent escape\n", " character.)\n", "\01I\n", "\01ROctal and Hex Escape Sequences\01I", "\n\n", "Any ASCII (or EBCDIC) character, except null, can be specified by using ", "either an octal escape or a hexadecimal escape, each beginning with \\0 or \\x ", "(or \\X), respectively. For example, \\052 and \\X2A both specify the `*' ", "character. Escapes for null (\\00 or \\x0) are not valid and will generate an ", "error message. Also, any escape that exceeds \\0377 or \\xFF will either cause ", "an error or have any additional character(s) interpreted literally. For ", "example, \\0777 will be interpreted as \\077 (a `?' character) followed by `7' ", "since \\0777 is greater than \\0377. ", "\n\n", "An invalid digit will also end an octal or hexadecimal escape. For example, ", "\\091 will cause an error since `9' is not within an octal escape's range of ", "allowable digits (0-7) and truncation before the `9' yields \\0 which is ", "invalid. ", "\n\n", "\01RShortcut Escape Sequences\01I", "\n\n", "NEdit defines some escape sequences that are handy shortcuts for commonly ", "used character classes. ", "\n\n", "\01A \\d digits 0-9\n", " \\l letters a-z, A-Z, and locale dependent letters\n", " \\s whitespace \\t, \\r, \\v, \\f, and space\n", " \\w word characters letters, digits, and underscore, `_'\n", "\01I\n", "\\D, \\L, \\S, and \\W are the same as the lowercase versions except that the ", "resulting character class is negated. For example, \\d is equivalent to ", "`[0-9]', while \\D is equivalent to `[^0-9]'. ", "\n\n", "These escape sequences can also be used within a character class. For ", "example, `[\\l_]' is the same as `[a-zA-Z_]', extended with possible locale ", "dependent letters. The escape sequences for special characters, and octal ", "and hexadecimal escapes are also valid within a class. ", "\n\n", "\01RWord Delimiter Tokens\01I", "\n\n", "Although not strictly a character class, the following escape sequences ", "behave similarly to character classes: ", "\n\n", "\01A \\y Word delimiter character\n", " \\Y Not a word delimiter character\n", "\01I\n", "The `\\y' token matches any single character that is one of the characters ", "that NEdit recognizes as a word delimiter character, while the `\\Y' token ", "matches any character that is NOT a word delimiter character. Word delimiter ", "characters are dynamic in nature, meaning that the user can change them through ", "preference settings. For this reason, they must be handled differently by the ", "regular expression engine. As a consequence of this, `\\y' and `\\Y' can not be ", "used within a character class specification. ", NULL }; static char * htxt_parenConstructs [] = { "\01RCapturing Parentheses\01I", "\n\n", "Capturing Parentheses are of the form `()' and can be used to group ", "arbitrarily complex regular expressions. Parentheses can be nested, but the ", "total number of parentheses, nested or otherwise, is limited to 50 pairs. ", "The text that is matched by the regular expression between a matched set of ", "parentheses is captured and available for text substitutions and ", "backreferences (see below.) Capturing parentheses carry a fairly high ", "overhead both in terms of memory used and execution speed, especially if ", "quantified by `*' or `+'. ", "\n\n", "\01RNon-Capturing Parentheses\01I", "\n\n", "Non-Capturing Parentheses are of the form `(?:)' and facilitate ", "grouping only and do not incur the overhead of normal capturing parentheses. ", "They should not be counted when determining numbers for capturing parentheses ", "which are used with backreferences and substitutions. Because of the limit ", "on the number of capturing parentheses allowed in a regex, it is advisable to ", "use non-capturing parentheses when possible. ", "\n\n", "\01RPositive Look-Ahead\01I", "\n\n", "Positive look-ahead constructs are of the form `(?=)' and implement a ", "zero width assertion of the enclosed regular expression. In other words, a ", "match of the regular expression contained in the positive look-ahead ", "construct is attempted. If it succeeds, control is passed to the next ", "regular expression atom, but the text that was consumed by the positive ", "look-ahead is first unmatched (backtracked) to the place in the text where ", "the positive look-ahead was first encountered. ", "\n\n", "One application of positive look-ahead is the manual implementation of a ", "first character discrimination optimization. You can include a positive ", "look-ahead that contains a character class which lists every character that ", "the following (potentially complex) regular expression could possibly start ", "with. This will quickly filter out match attempts that can not possibly ", "succeed. ", "\n\n", "\01RNegative Look-Ahead\01I", "\n\n", "Negative look-ahead takes the form `(?!)' and is exactly the same as ", "positive look-ahead except that the enclosed regular expression must NOT ", "match. This can be particularly useful when you have an expression that is ", "general, and you want to exclude some special cases. Simply precede the ", "general expression with a negative look-ahead that covers the special cases ", "that need to be filtered out. ", "\n\n", "\01RPositive Look-Behind\01I", "\n\n", "Positive look-behind constructs are of the form `(?<=)' and implement ", "a zero width assertion of the enclosed regular expression in front of the ", "current matching position. It is similar to a positive look-ahead assertion, ", "except for the fact that the match is attempted on the text preceding the ", "current position, possibly even in front of the start of the matching range ", "of the entire regular expression. ", "\n\n", "A restriction on look-behind expressions is the fact that the expression ", "must match a string of a bounded size. In other words, `*', `+', and `{n,}' ", "quantifiers are not allowed inside the look-behind expression. Moreover, ", "matching performance is sensitive to the difference between the upper and ", "lower bound on the matching size. The smaller the difference, the better the ", "performance. This is especially important for regular expressions used in ", "highlight patterns. ", "\n\n", "Positive look-behind has similar applications as positive look-ahead. ", "\n\n", "\01RNegative Look-Behind\01I", "\n\n", "Negative look-behind takes the form `(?)' and is exactly the same as ", "positive look-behind except that the enclosed regular expression must ", "NOT match. The same restrictions apply. ", "\n\n", "Note however, that performance is even more sensitive to the distance ", "between the size boundaries: a negative look-behind must not match for ", "\01Jany\01I possible size, so the matching engine must check \01Jevery\01I size. ", "\n\n", "\01RCase Sensitivity\01I", "\n\n", "There are two parenthetical constructs that control case sensitivity: ", "\n\n", "\01A (?i) Case insensitive; `AbcD' and `aBCd' are\n", " equivalent.\n", "\01I\n", "\01A (?I) Case sensitive; `AbcD' and `aBCd' are\n", " different.\n", "\01I\n", "Regular expressions are case sensitive by default, that is, `(?I)' is ", "assumed. All regular expression token types respond appropriately to case ", "insensitivity including character classes and backreferences. There is some ", "extra overhead involved when case insensitivity is in effect, but only to the ", "extent of converting each character compared to lower case. ", "\n\n", "\01RMatching Newlines\01I", "\n\n", "NEdit regular expressions by default handle the matching of newlines in a way ", "that should seem natural for most editing tasks. There are situations, ", "however, that require finer control over how newlines are matched by some ", "regular expression tokens. ", "\n\n", "By default, NEdit regular expressions will NOT match a newline character for ", "the following regex tokens: dot (`.'); a negated character class (`[^...]'); ", "and the following shortcuts for character classes: ", "\n\n", "\01A `\\d', `\\D', `\\l', `\\L', `\\s', `\\S', `\\w', `\\W', `\\Y'\n", "\01I\n", "The matching of newlines can be controlled for the `.' token, negated ", "character classes, and the `\\s' and `\\S' shortcuts by using one of the ", "following parenthetical constructs: ", "\n\n", "\01A (?n) `.', `[^...]', `\\s', `\\S' match newlines\n", "\01I\n", "\01A (?N) `.', `[^...]', `\\s', `\\S' don't match\n", " newlines\n", "\01I\n", "`(?N)' is the default behavior. ", "\n\n", "\01RNotes on New Parenthetical Constructs\01I", "\n\n", "Except for plain parentheses, none of the parenthetical constructs capture ", "text. If that is desired, the construct must be wrapped with capturing ", "parentheses, e.g. `((?i))\n", "\01I\n", " * Upper case words with possible punctuation.\n", "\01A <[A-Z][^a-z\\s]*>\n", "\01I\n", NULL }; static char * htxt_shell [] = { "\01IThe Shell menu (Unix versions only) allows you to execute Unix shell commands ", "from within NEdit. You can add items to the menu to extend NEdit's command ", "set or to incorporate custom automatic editing features using shell commands ", "or editing languages like awk and sed. To add items to the menu, select ", "Preferences -> Default Settings Customize Menus -> Shell Menu. NEdit comes ", "pre-configured with a few useful Unix commands like spell and sort, but we ", "encourage you to add your own custom extensions. ", "\n\n", "Filter Selection... prompts you for a Unix command to use to process the ", "currently selected text. The output from this command replaces the contents ", "of the selection. ", "\n\n", "Execute Command... prompts you for a Unix command and replaces the current ", "selection with the output of the command. If there is no selection, it ", "deposits the output at the current insertion point. In the Shell Command ", "field, the % character expands to the name (including directory path), and ", "the # character expands to the current line number of the file in the window. ", "To include a % or # character in the command, use %% or ##, respectively. ", "\n\n", "Execute Command Line uses the position of the cursor in the window to ", "indicate a line to execute as a shell command line. The cursor may be ", "positioned anywhere on the line. This command allows you to use an NEdit ", "window as an editable command window for saving output and saving commands ", "for re-execution. Note that the same character expansions described above ", "in Execute Command also occur with this command. ", "\n\n", "The X resource called nedit.shell (See \"\01QCustomizing NEdit\01I\") determines which ", "Unix shell is used to execute commands. The default value for this resource ", "is /bin/csh. ", NULL }; static char * htxt_learn [] = { "\01ISelecting Learn Keystrokes from the Macro menu puts NEdit in learn mode. In ", "learn mode, keystrokes and menu commands are recorded, to be played back ", "later, using the Replay Keystrokes command, or pasted into a macro in the ", "Macro Commands dialog of the Default Settings menu in Preferences. ", "\n\n", "Note that only keyboard and menu commands are recorded, not mouse clicks or ", "mouse movements since these have no absolute point of reference, such as ", "cursor or selection position. When you do a mouse-based operation in learn ", "mode, NEdit will beep (repeatedly) to remind you that the operation was not ", "recorded. ", "\n\n", "Learn mode is also the quickest and easiest method for writing macros. The ", "dialog for creating macro commands contains a button labeled \"Paste Learn / ", "Replay Macro\", which will deposit the last sequence learned into the body of ", "the macro. ", "\n\n", "\01RRepeating Actions and Learn/Replay Sequences\01I", "\n\n", "You can repeat the last (keyboard-based) command, or learn/replay sequence ", "with the Repeat... command in the Macro menu. To repeat an action, first do ", "the action (that is, insert a character, do a search, move the cursor), then ", "select Repeat..., decide how or how many times you want it repeated, and ", "click OK. For example, to move down 30 lines through a file, you could type: ", " Ctrl+, 29 . To repeat a learn/replay sequence, first ", "learn it, then select Repeat..., click on Learn/Replay and how you want it ", "repeated, then click OK. ", "\n\n", "If the commands you are repeating advance the cursor through the file, you ", "can also repeat them within a range of characters, or from the current cursor ", "position to the end of the file. To iterate over a range of characters, use ", "the primary selection (drag the left mouse button over the text) to mark the ", "range you want to operate on, and select \"In Selection\" in the Repeat dialog. ", "\n\n", "When using In \"Selection\" or \"To End\" with a learned sequence, try to do ", "cursor movement as the last step in the sequence, since testing of the cursor ", "position is only done at the end of the sequence execution. If you do cursor ", "movement first, for example searching for a particular word then doing a ", "modification, the position of the cursor won't be checked until the sequence ", "has potentially gone far beyond the end of your desired range. ", "\n\n", "It's easy for a repeated command to get out of hand, and you can easily ", "generate an infinite loop by using range iteration on a command which doesn't ", "progress. To cancel a repeating command in progress, type Ctrl+. (period), ", "or select Cancel Macro from the Macro menu. ", NULL }; static char * htxt_macro_lang [] = { "\01IMacros can be called from Macro menu commands, window background menu ", "commands, within the smart-indent framework, from the autoload macro file, ", "cf. \01QPreferences\01I, and from the command line. ", "Macro menu and window background menu commands are defined under Preferences ", "-> Default Settings -> Customize Menus. Help on creating items in these ", "menus can be found in the section \01QPreferences\01I. ", "\n\n", "NEdit's macro language is a simple interpreter with integer arithmetic, ", "dynamic strings, and C-style looping constructs (very similar to the ", "procedural portion of the Unix awk program). From the macro language, you ", "can call the same action routines which are bound to keyboard keys and menu ", "items, as well additional subroutines for accessing and manipulating editor ", "data, which are specific to the macro language (these are listed in the ", "sections titled \"\01QMacro Subroutines\01I\", and \"\01QAction Routines\01I\"). ", "\n\n", "\01RSyntax\01I", "\n\n", "An NEdit macro language program consists of a list of statements, each ", "terminated by a newline. Groups of statements which are executed together ", "conditionally, such as the body of a loop, are surrounded by curly braces ", "\"{}\". ", "\n\n", "Blank lines and comments are also allowed. Comments begin with a \"#\" and end ", "with a newline, and can appear either on a line by themselves, or at the end ", "of a statement. ", "\n\n", "Statements which are too long to fit on a single line may be split across ", "several lines, by placing a backslash \"\\\" character at the end of each line ", "to be continued. ", "\n\n", "\01RData Types\01I", "\n\n", "The NEdit macro language recognizes only three data types, dynamic character ", "strings, integer values and associative arrays. In general strings and ", "integers can be used interchangeably. If a string represents an integer ", "value, it can be used as an integer. Integers can be compared and ", "concatenated with strings. Arrays may contain integers, strings, or arrays. ", "Arrays are stored key/value pairs. Keys are always stored as strings. ", "\n\n", "\01SInteger Constants\01I", "\n\n", "Integers are non-fractional numbers in the range of -2147483647 to ", "2147483647. Integer constants must be in decimal. For example: ", "\n\n", "\01A a = -1\n", " b = 1000\n", "\01I\n", "\01SCharacter String Constants\01I", "\n\n", "Character string constants are enclosed in double quotes. For example: ", "\n\n", "\01A a = \"a string\"\n", " dialog(\"Hi there!\", \"OK\")\n", "\01I\n", "Strings may also include C-language style escape sequences: ", "\n\n", "\01A \\\\ Backslash \\t Tab \\f Form feed\n", " \\\" Double quote \\b Backspace \\a Alert\n", " \\n Newline \\r Carriage return \\v Vertical tab\n", "\01I\n", "Also allowed is the escape control character sequence: ", "\n\n", "\01A \\e Escape (ASCII or EBCDIC,\n", " depending on NEdit compilation settings)\n", "\01I\n", "For example, to send output to the terminal from which NEdit was started, a ", "newline character is necessary because, like printf, t_print requires ", "explicit newlines, and also buffers its output on a per-line basis: ", "\n\n", "\01A t_print(\"a = \" a \"\\n\")\n", "\01I\n", "Other characters can be expressed as backslash-escape sequences in macro ", "strings. The format is the same as for regular expressions, described in the ", "paragraphs headed \"Octal and Hex Escape Sequences\" of the section ", "\"\01QMetacharacters\01I\", except that an octal escape sequence can start with any ", "octal digit, not just 0, so the single character string \"\\0033\" is the same ", "as \"\\33\", \"\\x1B\" and \"\\e\" (for an ASCII version of NEdit). ", "\n\n", "Note that if you want to define a regular expression in a macro string, ", "you need to \"double-up\" the backslashes for the metacharacters with ", "special meaning in regular expressions. For example, the expression ", "\n\n", "\01A (?N(\\s|/\\*(?n(?:(?!\\*/).)*)\\*/|//.*\\n|\\n)+)\n", "\01I\n", "which matches whitespace or C/C++/Java-style comments, should be written as ", "a macro string as ", "\n\n", "\01A \"(?N(\\\\s|/\\\\*(?n(?:(?!\\\\*/).)*)\\\\*/|//.*\\n|\\n)+)\"\n", "\01I\n", "(The \"\\n\"s towards the end add literal newline characters to the string. The ", "regular expression interpretation treats the newlines as themselves. It can ", "also interpret the sequence \"\\\\n\" as a newline, although the macro string here ", "would then contain a literal backslash followed by a lowercase `N'.) ", "\n\n", "\01RVariables\01I", "\n\n", "Variable names must begin either with a letter (local variables), or a $ ", "(global variables). Beyond the first character, variables may also contain ", "numbers and underscores `_'. Variables are called in to existence just by ", "setting them (no explicit declarations are necessary). ", "\n\n", "Local variables are limited in scope to the subroutine (or menu item ", "definition) in which they appear. Global variables are accessible from all ", "routines, and their values persist beyond the call which created them, until ", "reset. ", "\n\n", "\01SBuilt-in Variables\01I", "\n\n", "NEdit has a number of permanently defined variables, which are used to access ", "global editor information and information about the window in which the ", "macro is executing. These are listed along with the built in functions in ", "the section titled \"\01QMacro Subroutines\01I\". ", "\n\n", "\01RFunctions and Subroutines\01I", "\n\n", "The syntax of a function or subroutine call is: ", "\n\n", "\01A function_name(arg1, arg2, ...)\n", "\01I\n", "where arg1, arg2, etc. represent the argument values which are passed to ", "the routine being called. A function or subroutine call can be on a line by ", "itself, as above, or if it returns a value, can be invoked within a character ", "or numeric expression: ", "\n\n", "\01A a = fn1(b, c) + fn2(d)\n", " dialog(\"fn3 says: \" fn3())\n", "\01I\n", "Arguments are passed by value. This means that you can not return values via ", "the argument list, only through the function value or indirectly through ", "agreed-upon global variables. ", "\n\n", "\01SBuilt-in Functions\01I", "\n\n", "NEdit has a wide range of built in functions which can be called from the ", "macro language. These routines are divided into two classes, macro-language ", "functions, and editor action routines. Editor action routines are more ", "flexible, in that they may be called either from the macro language, or bound ", "directly to keys via translation tables. They are also limited, however, in ", "that they can not return values. Macro language routines can return values, ", "but can not be bound to keys in translation tables. ", "\n\n", "Nearly all of the built-in subroutines operate on an implied window, which is ", "initially the window from which the macro was started. To manipulate the ", "contents of other windows, use the focus_window subroutine to change the ", "focus to the ones you wish to modify. focus_window can also be used to ", "iterate over all of the currently open windows, using the special keyword ", "names, \"last\" and \"next\". ", "\n\n", "For backwards compatibility, hyphenated action routine names are allowed, and ", "most of the existing action routines names which contain underscores have an ", "equivalent version containing hyphens ('-') instead of underscores. Use of ", "these names is discouraged. The macro parser resolves the ambiguity between ", "'-' as the subtraction/negation operator, and - as part of an action routine ", "name by assuming subtraction unless the symbol specifically matches an action ", "routine name. ", "\n\n", "\01SUser Defined Functions\01I", "\n\n", "Users can define their own macro subroutines, using the define keyword: ", "\n\n", "\01A define subroutine_name {\n", " < body of subroutine >\n", " }\n", "\01I\n", "Subroutine definitions can not appear within other definitions, or within ", "macro menu item definitions. They can only appear in (macro) files, such as ", "the autoload macro file, cf. \01QPreferences\01I. Macro files can be loaded with ", "File -> Load Macro File or with the load_macro_file() action. ", "\n\n", "The arguments with which a user-defined subroutine or function was invoked, ", "are presented as $1, $2, ... , $9 or $args[expr], where expr can be evaluated ", "to an integer from 1 to the number of arguments. The number of arguments can ", "be read from $n_args or $args[]. The array $args[expr] is the only way to ", "access arguments beyond the first 9. ", "\n\n", "To return a value from a subroutine, and/or to exit from the subroutine ", "before the end of the subroutine body, use the return statement: ", "\n\n", "\01A return \n", "\01I\n", "\01ROperators and Expressions\01I", "\n\n", "Operators have the same meaning and precedence that they do in C, except for ", "^, which raises a number to a power (y^x means y to the x power), rather than ", "bitwise exclusive OR. The table below lists operators in decreasing order of ", "precedence. ", "\n\n", "\01A Operators Associativity\n", " ()\n", " ^ right to left\n", " - ! ++ -- (unary)\n", " * / % left to right\n", " + - left to right\n", " > >= < <= == != left to right\n", " & left to right\n", " | left to right\n", " && left to right\n", " || left to right\n", " (concatenation) left to right\n", " = += -= *= /= %=, &= |= right to left\n", "\01I\n", "The order in which operands are evaluated in an expression is undefined, ", "except for && and ||, which like C, evaluate operands left to right, but stop ", "when further evaluation would no longer change the result. ", "\n\n", "\01SNumerical Operators\01I", "\n\n", "The numeric operators supported by the NEdit macro language are listed below: ", "\n\n", "\01A + addition\n", " - subtraction or negation\n", " * multiplication\n", " / division\n", " % modulo\n", " ^ power\n", " & bitwise and\n", " | bitwise or\n", "\01I\n", "Increment (++) and decrement (--) operators can also be appended or prepended ", "to variables within an expression. Prepended increment/decrement operators ", "act before the variable is evaluated. Appended increment/decrement operators ", "act after the variable is evaluated. ", "\n\n", "\01SLogical and Comparison Operators\01I", "\n\n", "Logical operations produce a result of 0 (for false) or 1 (for true). In a ", "logical operation, any non-zero value is recognized to mean true. The ", "logical and comparison operators allowed in the NEdit macro language are ", "listed below: ", "\n\n", "\01A && logical and\n", " || logical or\n", " ! not\n", " > greater\n", " < less\n", " >= greater or equal\n", " <= less or equal\n", " == equal (integers and/or strings)\n", " != not equal (integers and/or strings)\n", "\01I\n", "\01SCharacter String Operators\01I", "\n\n", "The \"operator\" for concatenating two strings is the absence of an operator. ", "Adjoining character strings with no operator in between means concatenation: ", "\n\n", "\01A d = a b \"string\" c\n", " t_print(\"the value of a is: \" a)\n", "\01I\n", "Comparison between character strings is done with the == and != operators, ", "(as with integers). There are a number of useful built-in routines for ", "working with character strings, which are listed in the section called ", "\"\01QMacro Subroutines\01I\". ", "\n\n", "\01SArrays and Array Operators\01I", "\n\n", "Arrays may contain either strings, integers, or other arrays. Arrays are ", "associative, which means that they relate two pieces of information, the key ", "and the value. The key is always a string; if you use an integer it is ", "converted to a string. ", "\n\n", "To determine if a given key is in an array, use the 'in' keyword. ", "\n\n", "\01A if (\"6\" in x)\n", " \n", "\01I\n", "If the left side of the in keyword is an array, the result is true if every ", "key in the left array is in the right array. Array values are not compared. ", "\n\n", "To iterate through all the keys of an array use the 'for' looping construct. ", "Keys are not guaranteed in any particular order: ", "\n\n", "\01A for (aKey in x)\n", " \n", "\01I\n", "Elements can be removed from an array using the delete command: ", "\n\n", "\01A delete x[3] # deletes element with key 3\n", " delete x[] # deletes all elements\n", "\01I\n", "The number of elements in an array can be determined by referencing the ", "array with no indices: ", "\n\n", "\01A dialog(\"array x has \" x[] \" elements\", \"OK\")\n", "\01I\n", "Arrays can be combined with some operators. All the following operators only ", "compare the keys of the arrays. ", "\n\n", "\01A result = x + y (Merge arrays)\n", "\01I\n", "The 'result' is a new array containing keys from both x and y. If ", "duplicates are present values from y are used. ", "\n\n", "\01A result = x - y (Remove keys)\n", "\01I\n", "The 'result' is a new array containing all keys from x that are not in y. ", "\n\n", "\01A result = x & y (Common keys)\n", "\01I\n", "The 'result' is a new array containing all keys which are in both x and y. ", "The values from y are used. ", "\n\n", "\01A result = x | y (Unique keys)\n", "\01I\n", "The 'result' is a new array containing keys which exist in either x or y, ", "but not both. ", "\n\n", "When duplicate keys are encountered using the + and & operators, the values ", "from the array on the right side of the operators are used for the result. ", "All of the above operators are array only, meaning both the left and right ", "sides of the operator must be arrays. The results are also arrays. ", "\n\n", "Array keys can also contain multiple dimensions: ", "\n\n", "\01A x[1, 1, 1] = \"string\"\n", "\01I\n", "These are used in the expected way, e.g.: ", "\n\n", "\01A for (i = 1; i < 3; i++)\n", " {\n", " for (j = 1; j < 3; j++)\n", " {\n", " x[i, j] = k++\n", " }\n", " }\n", "\01I\n", "gives the following array: ", "\n\n", "\01A x[1, 1] = 0\n", " x[1, 2] = 1\n", " x[2, 1] = 2\n", " x[2, 2] = 3\n", "\01I\n", "Internally all indices are part of one string, separated by the string ", "$sub_sep (ASCII 0x1c, 'FS'). The first key in the above example is in ", "fact: ", "\n\n", "\01A [\"1\" $sub_sep \"1\"]\n", "\01I\n", "If you need to extract one of the keys, you can use split(), using ", "$sub_sep as the separator. ", "\n\n", "You can also check for the existence of multi-dimensional array by ", "looking for $sub_sep in the key. ", "\n\n", "Last, you need $sub_sep if you want to use the 'in' keyword. ", "\n\n", "\01A if ((1,2) in myArray)\n", " {..}\n", "\01I\n", "doesn't work, but ", "\n\n", "\01A if ((\"1\" $sub_sep \"2\") in myArray)\n", " {..}\n", "\01I\n", "does work. ", "\n\n", "\01RLooping and Conditionals\01I", "\n\n", "NEdit supports looping constructs: for and while, and conditional statements: ", "if and else, with essentially the same syntax as C: ", "\n\n", "\01A for (, ...; ; , ...) \n", "\01I\n", "\01A while () \n", "\01I\n", "\01A if () \n", "\01I\n", "\01A if () else \n", "\01I\n", ", as in C, can be a single statement, or a list of statements enclosed ", "in curly braces ({}). is an expression which must evaluate to ", "true for the statements in to be executed. for loops may also contain ", "initialization statements, , executed once at the beginning of the ", "loop, and increment/decrement statements (or any arbitrary statement), which ", "are executed at the end of the loop, before the condition is evaluated again. ", "\n\n", "Examples: ", "\n\n", "\01A for (i=0; i<100; i++)\n", " j = i * 2\n", "\01I\n", "\01A for (i=0, j=20; i<20; i++, j--) {\n", " k = i * j\n", " t_print(i, j, k)\n", " }\n", "\01I\n", "\01A while (k > 0)\n", " {\n", " k = k - 1\n", " t_print(k)\n", " }\n", "\01I\n", "\01A for (;;) {\n", " if (i-- < 1)\n", " break\n", " }\n", "\01I\n", "Loops may contain break and continue statements. A break statement causes an ", "exit from the innermost loop, a continue statement transfers control to the ", "end of the loop. ", NULL }; static char * htxt_macro_subrs [] = { "\01RBuilt in Variables\01I", "\n\n", "These variables are read-only and can not be changed. ", "\n\n", "\01A\01B$1\01A, \01B$2\01A, \01B$3\01A, \01B$4\01A, \01B$5\01A, \01B$6\01A, \01B$7\01A, \01B$8\01A, \01B$9\01A\n", "\01B$args\01A[\01Cexpr\01A]\n", "\01B$n_args\01A\n", "\01IArgument information. The first 9 arguments (if there are that many) can ", "be referenced as read-only values using the shorthand form. All arguments ", "can be accessed as values in the \01J$args\01I array, using a numeric index ", "starting at 1. The total number of arguments received by a function is ", "given by \01J$n_args\01I or \01J$args[]\01I. ", "\n\n", "\01A\01B$active_pane\01A\n", "\01IIndex of the current pane. ", "\n\n", "\01A\01B$auto_indent\01A\n", "\01IContains the current preference for auto indent. ", "Can be \"off\", \"on\", or \"smart\". ", "\n\n", "\01A\01B$calltip_ID\01A\n", "\01IEquals the ID of the currently displayed calltip, or 0 if no calltip is ", "being displayed. ", "\n\n", "\01A\01B$cursor\01A\n", "\01IPosition of the cursor in the current window. ", "\n\n", "\01A\01B$column\01A\n", "\01IColumn number of the cursor position in the current window. ", "\n\n", "\01A\01B$display_width\01A\n", "\01IWidth of the current pane in pixels. ", "\n\n", "\01A\01B$em_tab_dist\01A\n", "\01IIf tab emulation is turned on in the Tabs... ", "dialog of the Preferences menu, value is the ", "distance between emulated tab stops. If tab ", "emulation is turned off, value is -1. ", "\n\n", "\01A\01B$empty_array\01A\n", "\01IAn array with no elements. This can be used to initialize ", "an array to an empty state. ", "\n\n", "\01A\01B$file_format\01A\n", "\01ICurrent newline format that the file will be saved with. Can ", "be \"unix\", \"dos\" or \"macintosh\". ", "\n\n", "\01A\01B$file_name\01A\n", "\01IName of the file being edited in the current ", "window, stripped of directory component. ", "\n\n", "\01A\01B$file_path\01A\n", "\01IDirectory component of file being edited in the current window. ", "\n\n", "\01A\01B$font_name\01A\n", "\01IContains the current plain text font name. ", "\n\n", "\01A\01B$font_name_bold\01A\n", "\01IContains the current bold text font name. ", "\n\n", "\01A\01B$font_name_bold_italic\01A\n", "\01IContains the current bold-italic text font name. ", "\n\n", "\01A\01B$font_name_italic\01A\n", "\01IContains the current italic text font name. ", "\n\n", "\01A\01B$highlight_syntax\01A\n", "\01IWhether syntax highlighting is turned on. ", "\n\n", "\01A\01B$incremental_backup\01A\n", "\01IContains 1 if incremental auto saving is on, otherwise 0. ", "\n\n", "\01A\01B$incremental_search_line\01A\n", "\01IHas a value of 1 if the preference is ", "selected to always show the incremental search line, otherwise 0. ", "\n\n", "\01A\01B$language_mode\01A\n", "\01IName of language mode set in the current window. ", "\n\n", "\01A\01B$line\01A\n", "\01ILine number of the cursor position in the current window. ", "\n\n", "\01A\01B$locked\01A\n", "\01ITrue if the file has been locked by the user. ", "\n\n", "\01A\01B$make_backup_copy\01A\n", "\01IHas a value of 1 if original file is kept in a ", "backup file on save, otherwise 0. ", "\n\n", "\01A\01B$max_font_width\01A\n", "\01IThe maximum font width of all the active styles. ", "Syntax highlighting styles are only considered if syntax highlighting ", "is turned on. ", "\n\n", "\01A\01B$min_font_width\01A\n", "\01IThe minimum font width of all the active styles. ", "Syntax highlighting styles are only considered if syntax highlighting ", "is turned on. ", "\n\n", "\01A\01B$modified\01A\n", "\01ITrue if the file in the current window has ", "been modified and the modifications have not ", "yet been saved. ", "\n\n", "\01A\01B$n_display_lines\01A\n", "\01IThe number of lines visible in the currently active pane. ", "\n\n", "\01A\01B$n_panes\01A\n", "\01IThe number of panes in the current window. ", "\n\n", "\01A\01B$overtype_mode\01A\n", "\01ITrue if in Overtype mode. ", "\n\n", "\01A\01B$read_only\01A\n", "\01ITrue if the file is read only. ", "\n\n", "\01A\01B$selection_start, $selection_end\01A \n", "\01IBeginning and ending positions of the ", "primary selection in the current window, or ", "-1 if there is no text selected in the current window. ", "\n\n", "\01A\01B$selection_left, $selection_right\01A \n", "\01ILeft and right character offsets of the rectangular (primary) selection in ", "the current window, or -1 if there is no selection or it is not rectangular. ", "\n\n", "\01A\01B$server_name\01A\n", "\01IName of the current NEdit server. ", "\n\n", "\01A\01B$show_line_numbers\01A\n", "\01IWhether line numbers are shown next to the text. ", "\n\n", "\01A\01B$show_matching\01A\n", "\01IContains the current preference for showing matching pairs, ", "such as \"[]\" and \"{}\" pairs. Can be \"off\", \"delimiter\", or \"range\". ", "\n\n", "\01A\01B$match_syntax_based\01A\n", "\01IWhether pair matching should use syntax information, if available. ", "\n\n", "\01A\01B$statistics_line\01A\n", "\01IHas a value of 1 if the statistics line is shown, otherwise 0. ", "\n\n", "\01A\01B$sub_sep\01A\n", "\01IContains the value of the array sub-script separation string. ", "\n\n", "\01A\01B$tab_dist\01A\n", "\01IThe distance between tab stops for a ", "hardware tab character, as set in the ", "Tabs... dialog of the Preferences menu. ", "\n\n", "\01A\01B$text_length\01A\n", "\01IThe length of the text in the current window. ", "\n\n", "\01A\01B$top_line\01A\n", "\01IThe line number of the top line of the currently active pane. ", "\n\n", "\01A\01B$use_tabs\01A\n", "\01IWhether the user is allowing the NEdit to insert tab characters to maintain ", "spacing in tab emulation and rectangular dragging operations. (The setting of ", "the \"Use tab characters in padding and emulated tabs\" button in the Tabs... ", "dialog of the Preferences menu.) ", "\n\n", "\01A\01B$wrap_margin\01A\n", "\01IThe right margin in the current window for text wrapping and filling. ", "\n\n", "\01A\01B$wrap_text\01A\n", "\01IThe current wrap text mode. Values are \"none\", \"auto\" or \"continuous\". ", "\n\n", "\01RBuilt-in Subroutines\01I", "\n\n", "\01A\01Bappend_file( string, filename )\01A\n", "\01IAppends a string to a named file. Returns 1 on successful write, or 0 if ", "unsuccessful. ", "\n\n", "\01A\01Bbeep()\01A\n", "\01IRing the bell. ", "\n\n", "\01A\01Bcalltip( \"text_or_key\" [, pos [, mode or position_modifier, ...]] )\01A\n", "\01IPops up a calltip. is an optional position in the buffer where the tip ", "will be displayed. Passing -1 for is equivalent to not specifying a ", "position, and it guarantees that the tip will appear on-screen somewhere even ", "if the cursor is not. The upper-left corner of the calltip will appear below ", "where the cursor would appear if it were at this position. ", "\n\n", " is one of \"tipText\" (default), \"tipKey\", or \"tagKey\". \"tipText\" ", "displays the text as-is, \"tagKey\" uses it as the key to look up a tag, then ", "converts the tag to a calltip, and \"tipKey\" uses it as the key to look up a ", "calltip, then falls back to \"tagKey\" behavior if that fails. You'll usually ", "use \"tipKey\" or \"tipText\". ", "\n\n", "Finally, you can modify the placement of the calltip relative to the cursor ", "position (or ) with one or more of these optional position modifiers: ", "\"center\" aligns the center of the calltip with the position. \"right\" aligns ", "the right edge of the calltip with the position. (\"center\" and \"right\" may ", "not both be used.) \"above\" places the calltip above the position. \"strict\" ", "does not allow the calltip to move from its position in order to avoid going ", "off-screen or obscuring the cursor. ", "\n\n", "Returns the ID of the calltip if it was found and/or displayed correctly, ", "0 otherwise. ", "\n\n", "\01A\01Bclipboard_to_string()\01A \n", "\01IReturns the contents of the clipboard as a macro string. Returns empty ", "string on error. ", "\n\n", "\01A\01Bdialog( message, btn_1_label, btn_2_label, ... )\01A \n", "\01IPop up a dialog for querying and presenting information to the user. First ", "argument is a string to show in the message area of the dialog. ", "Additional optional arguments represent labels for buttons to appear along ", "the bottom of the dialog. Returns the number of the button pressed (the ", "first button is number 1), or 0 if the user closed the dialog via the window ", "close box. ", "\n\n", "\01A\01Bexist_filename_dialog( title[, default_path[, filter]] )\01A\n", "\01IPresents a file selection dialog with the given title to the user that ", "prompts for an existing file. A default path and a filter (e.g. \"*.c\") can be ", "optionally specified. To specify a filter without a default path, specify \"\" ", "as the default path. Returns \"\" if the user cancelled the dialog, otherwise ", "returns the fully-qualified path, including the filename. See also ", "\01Jnew_filename_dialog( ... )\01I. ", "\n\n", "\01A\01Bfocus_window( window_name )\01A \n", "\01ISets the window on which subsequent macro commands operate. window_name can ", "be either a fully qualified file name, or a relative filename (which will ", "be completed from NEdit's working directory) or one of \"last\" for the last ", "window created, or \"next\" for the next window in the chain from the currently ", "focused window (the first window being the one returned from calling ", "focus_window(\"last\"). Returns the name of the newly-focused window, or an ", "empty string if the requested window was not found. ", "\n\n", "\01A\01Bget_character( position )\01A \n", "\01IReturns the single character at the position ", "indicated by the first argument to the routine from the current window. ", "\n\n", "\01A\01Bget_range( start, end )\01A \n", "\01IReturns the text between a starting and ending position from the current ", "window. ", "\n\n", "\01A\01Bget_selection()\01A \n", "\01IReturns a string containing the text currently selected by the primary ", "selection either from the current window (no keyword), or from anywhere on ", "the screen (keyword \"any\"). ", "\n\n", "\01A\01Bgetenv( name )\01A\n", "\01IGets the value of an environment variable. ", "\n\n", "\01A\01Bkill_calltip( [calltip_ID] )\01A\n", "\01IKills any calltip that is being displayed in the window in which the macro is ", "running. If there is no displayed calltip this does nothing. If a calltip ", "ID is supplied then the calltip is killed only if its ID is calltip_ID. ", "\n\n", "\01A\01Blength( string )\01A\n", "\01IReturns the length of a string ", "\n\n", "\01A\01Blist_dialog( message, text, btn_1_label, btn_2_label, ... )\01A \n", "\01IPop up a dialog for prompting the user to choose a line from the given text ", "string. The first argument is a message string to be used as a title for the ", "fixed text describing the list. The second string provides the list data: ", "this is a text string in which list entries are separated by newline ", "characters. Additional optional arguments represent labels for ", "buttons to appear along the bottom of the dialog. Returns the line of text ", "selected by the user as the function value (without any newline separator) or ", "the empty string if none was selected, and number of the button pressed (the ", "first button is number 1), in $list_dialog_button. If the user closes the ", "dialog via the window close box, the function returns the empty string, and ", "$list_dialog_button returns 0. ", "\n\n", "\01A\01Bmax( n1, n2, ... )\01A\n", "\01IReturns the maximum value of all of its arguments ", "\n\n", "\01A\01Bmin( n1, n2, ... )\01A\n", "\01IReturns the minimum value of all of its arguments ", "\n\n", "\01A\01Bnew_filename_dialog( title[, default_path[, default_filename]] )\01A\n", "\01IPresents a file selection dialog with the given title to the user that ", "prompts for a new or existing file. A default path and filename can be ", "optionally specified. To specify a default filename without a default path, ", "specify \"\" as the default path. Returns \"\" if the user cancelled the dialog, ", "otherwise returns the fully-qualified path, including the filename. Note that ", "the default_filename argument does not work on all Motif implementations. ", "See also \01Jexist_filename_dialog( ... )\01I. ", "\n\n", "\01A\01Bread_file( filename )\01A \n", "\01IReads the contents of a text file into a string. On success, returns 1 in ", "$read_status, and the contents of the file as a string in the subroutine ", "return value. On failure, returns the empty string \"\" and an 0 $read_status. ", "\n\n", "\01A\01Breplace_in_string( string, search_for, replace_with [, type, \"copy\"] )\01A \n", "\01IReplaces all occurrences of a search string in a string with a replacement ", "string. Arguments are 1: string to search in, 2: string to search for, 3: ", "replacement string. There are two optional arguments. One is a search type, ", "either \"literal\", \"case\", \"word\", \"caseWord\", \"regex\", or \"regexNoCase\". ", "The default search type is \"literal\". If the optional \"copy\" argument is ", "specified, a copy of the input string is returned when no replacements were ", "performed. By default an empty string (\"\") will be returned in this case. ", "Returns a new string with all of the replacements done. ", "\n\n", "\01A\01Breplace_range( start, end, string )\01A \n", "\01IReplaces all the text between two positions in the current window. If the ", "cursor position is between start and end it will be set to start. ", "\n\n", "\01A\01Breplace_selection( string )\01A \n", "\01IReplaces the primary-selection selected text in the current window. ", "\n\n", "\01A\01Breplace_substring( string, start, end, replace_with )\01A \n", "\01IReplacing a substring between two positions in a string within another string. ", "\n\n", "\01A\01Bsearch( search_for, start [, search_type, wrap, direction] )\01A \n", "\01ISearches silently in a window without dialogs, beeps, or changes to the ", "selection. Arguments are: 1: string to search for, 2: starting position. ", "Optional arguments may include the strings: \"wrap\" to make the search wrap ", "around the beginning or end of the string, \"backward\" or \"forward\" to change ", "the search direction (\"forward\" is the default), \"literal\", \"case\", \"word\", ", "\"caseWord\", \"regex\", or \"regexNoCase\" to change the search type (default is ", "\"literal\"). Returns the starting position of the match, or -1 if nothing ", "matched. Also returns the ending position of the match in $search_end. ", "\n\n", "\01A\01Bsearch_string( string, search_for, start [, search_type, direction] )\01A \n", "\01I\n", "Built-in macro subroutine for searching a string. Arguments are 1: string to ", "search in, 2: string to search for, 3: starting position. Optional arguments ", "may include the strings: \"wrap\" to make the search wrap around the beginning ", "or end of the string, \"backward\" or \"forward\" to change the search direction ", "(\"forward\" is the default), \"literal\", \"case\", \"word\", \"caseWord\", \"regex\", ", "or \"regexNoCase\" to change the search type (default is \"literal\"). Returns ", "the starting position of the match, or -1 if nothing matched. Also returns ", "the ending position of the match in $search_end. ", "\n\n", "\01A\01Bselect( start, end )\01A \n", "\01ISelects (with the primary selection) text in the current buffer between a ", "starting and ending position. ", "\n\n", "\01A\01Bselect_rectangle( start, end, left, right )\01A \n", "\01ISelects a rectangular area of text between a starting and ending position, ", "and confined horizontally to characters displayed between positions \"left\", ", "and \"right\". ", "\n\n", "\01A\01Bset_cursor_pos( position )\01A\n", "\01ISet the cursor position for the current window. ", "\n\n", "\01A\01Bshell_command( command, input_string )\01A \n", "\01IExecutes a shell command, feeding it input from input_string. On completion, ", "output from the command is returned as the function value, and the command's ", "exit status is returned in the global variable $shell_cmd_status. ", "\n\n", "\01A\01Bsplit(string, separation_string [, search_type])\01A\n", "\01ISplits a string using the separator specified. Optionally the search_type ", "argument can specify how the separation_string is interpreted. The default ", "is \"literal\". The returned value is an array with keys beginning at 0. ", "\n\n", "\01A\01Bstring_dialog( message, btn_1_label, btn_2_label, ... )\01A \n", "\01IPops up a dialog prompting the user to enter information. The first argument ", "is a string to show in the message area of the dialog. Additional ", "optional arguments represent labels for buttons to appear along the bottom of ", "the dialog. Returns the string entered by the user as the function value, ", "and number of the button pressed (the first button is number 1), in ", "$string_dialog_button. If the user closes the dialog via the window close ", "box, the function returns the empty string, and $string_dialog_button returns ", "0. ", "\n\n", "\01A\01Bstring_compare(string1, string2 [, consider-case])\01A\n", "\01ICompare two strings and return 0 if they are equal, -1 if string1 is less ", "than string2 or 1 if string1 is greater than string2. The values for the ", "optional consider-case argument is either \"case\" or \"nocase\". The default ", "is to do a case sensitive comparison. ", "\n\n", "\01A\01Bstring_to_clipboard( string )\01A \n", "\01ICopy the contents of a macro string to the clipboard. ", "\n\n", "\01A\01Bsubstring( string, start [, end] )\01A \n", "\01IReturns the portion of a string between a start and end position (with the ", "position of the beginning of the string being 0). If end is missing, the ", "position of the end of the string is used. If either of the positions are ", "negative, they are treated as relative to the end of the string. A position ", "specified either before the start of the string or after the end of the string ", "is repositioned to the nearest valid string position. If the start position ", "is beyond the end position, the empty string is returned. ", "\n\n", "\01A\01Bt_print( string1, string2, ... )\01A \n", "\01IWrites strings to the terminal (stdout) from which NEdit was started. ", "\n\n", "\01A\01Btolower( string )\01A\n", "\01IReturn an all lower-case version of string. ", "\n\n", "\01A\01Btoupper( string )\01A\n", "\01IReturn an all upper-case version of string. ", "\n\n", "\01A\01Bvalid_number( string )\01A\n", "\01IReturns 1 if the string can be converted to a number without error ", "following the same rules that the implicit conversion would. Otherwise 0. ", "\n\n", "\01A\01Bwrite_file( string, filename )\01A \n", "\01IWrites a string (parameter 1) to a file named in parameter 2. Returns 1 on ", "successful write, or 0 if unsuccessful. ", "\n\n", "\01RDeprecated Functions\01I", "\n\n", "Some functions are included only for supporting legacy macros. You should not ", "use any of these functions in any new macro you write. Among these are all ", "action routines with hyphens in their names; use underscores instead ", "('find-dialog' -> 'find_dialog'). ", "\n\n", "\01A\01Bmatch()\01A\n", "\01I\01JDEPRECATED\01I Use select_to_matching() instead. ", "\n\n", NULL }; static char * htxt_rangeset [] = { "\01IA rangeset is a set of ranges. A range is a contiguous range of characters ", "defined by its start and end position in the document. The user can ", "create rangesets, identified by arbitrary integers (chosen by the editor when ", "the rangesets are created), and each range within a rangeset is identified by ", "a numeric index, counting from 1, in the order of appearance in the text ", "buffer. The ranges are adjusted when modifications are made to the text ", "buffer: they shuffle around when characters are added or deleted. However, ", "ranges within a set will coalesce if the characters between them are removed, ", "or a new range is added to the set which bridges or overlaps others. ", "\n\n", "Using rangesets allows non-contiguous bits of the text to be identified as a ", "group. ", "\n\n", "Rangesets can be assigned a background color: characters within a range of a ", "rangeset will have the background color of the rangeset. If more than one ", "rangeset includes a given character, its background color will be that of the ", "most recently created rangeset which has a color defined. ", "\n\n", "Rangesets must be created using the rangeset_create() function, which ", "will return an identifier for the newly-created rangeset. This identifier ", "is then passed to the other rangeset functions to manipulate the rangeset. ", "\n\n", "There is a limit to the number of rangesets which can exist at any time - ", "currently up to 63 in each document. Care should be taken to destroy ", "any rangesets which are no longer needed, by using the rangeset_destroy() ", "function, if this limit is attained. ", "\n\n", "Rangesets can be named: this is useful for macros which need a fixed ", "identification for rangesets which are used for the same purpose in ", "different documents. Although a new rangeset's number is arbitrary, its ", "name can be fixed. This is done using the rangeset_set_name() function. ", "Note that rangeset names within a particular document may not be unique. ", "For this reason, the rangeset_get_by_name() function returns an array of ", "identifiers, which will be empty if the name has not been associated with ", "a rangeset. ", "\n\n", "\01SHow rangesets change with modifications\01I", "\n\n", "When changes are made to the document text, ranges within each set are altered ", "with it, according to their behavioral mode. If changes are made outside of ", "the ranges in a rangeset, each range simply maintains its size and adjusts its ", "position to match the changes. When text within a range is deleted, the ", "range's length is reduced by the same amount. When changes involving new text ", "are made within a range of the set, or to one of the extremities of a range, ", "different behaviours may be desirable. The rangeset_set_mode() function allows ", "these modes to be chosen. ", "\n\n", "Note that the precise behaviour of these modes may change in future versions ", "of NEdit. ", "\n\n", "The available modes are: ", "\n\n", "\01Jmaintain\01I or \01Jins_del\01I - ", "Both these modes have the same behaviour. New text added at the front of a ", "range in a set is not added to the range; new text added within the range or ", "at the end extends the range. Replacement overlapping an extremity of the ", "set acts as if the new text were added first, then the old text deleted. ", "This causes curtailment at the front of the range, extension at the end. ", "Replacement of the full text of the range removes the range from the set. ", "The default behaviour for a newly created rangeset is \01Jmaintain\01I. ", "\n\n", "\01Jdel_ins\01I - ", "New text added at the front or end of a range in a set is not added to the ", "range; new text added within the range extends the range. Replacement ", "overlapping an extremity of the set acts as if the old text were deleted ", "first, then the new text added. This causes curtailment at either end. ", "Replacement of the full text of the range removes the range from the set. ", "\n\n", "\01Jinclude\01I - ", "New text added at the front or end of a range in a set extends the range, as ", "does new text added within the range. Replacement overlapping an extremity ", "of the set acts as if the new text were added first, then the old text ", "deleted. This causes curtailment at the front of the range, extension at ", "the end. Replacement of the full text of the range adds the new text to the ", "range if the start position of the replacement is at the range's start ", "point. ", "\n\n", "\01Jexclude\01I - ", "New text added at the front or end of a range in a set does not extend the ", "range; new text added within the range extends the range. Replacement ", "overlapping an extremity causes curtailment of the range. Replacement of ", "the full text of the range removes the range from the set. ", "\n\n", "\01Jbreak\01I - ", "New text added at the front or end of a range in a set does not extend the ", "range; new text added within the range will split the range. Replacement ", "overlapping an extremity causes curtailment of the range. Replacement of ", "the full text of the range removes the range from the set. ", "\n\n", "\01SNotes\01I", "\n\n", "A rangeset is manipulated \01Konly\01I through macro routines. Rangesets ", "can easily become very large, and may exceed the capacity of the running ", "process. Coloring relies on proper color names or specifications (such as ", "the \"#rrggbb\" hexadecimal digit strings), and appropriate hardware support. If ", "an invalid color name is given, the default background color is used instead. ", "Behaviours set using rangeset_set_mode() are subject to change in future ", "versions. ", "\n\n", "\01RRangeset read-only variables\01I", "\n\n", "\01A\01B$rangeset_list\01A\n", "\01Iarray of active rangeset identifiers, with integer keys starting at 0, ", "in the order the rangesets were defined. ", "\n\n", "\01RRangeset functions\01I", "\n\n", "\01A\01Brangeset_create()\01A\n", "\01Brangeset_create( n )\01A\n", "\01ICreates one or more new rangesets. The first form creates a single range ", "set and returns its identifier; if there are no rangesets available it ", "returns 0. The second form creates n new rangesets, and returns an array ", "of the rangeset identifiers with keys beginning at 0. If the requested ", "number of rangesets is not available it returns an empty array. ", "\n\n", "\01A\01Brangeset_destroy( r )\01A\n", "\01Brangeset_destroy( array )\01A\n", "\01IDeletes all information about a rangeset or a number of rangesets. The ", "first form destroys the rangeset identified by r. The second form should ", "be passed an array of rangeset identifiers with keys beginning at 0 (i.e. ", "the same form of array returned by rangeset_create(n); it destroys all the ", "rangesets appearing in the array. If any of the rangesets do not exist, ", "the function continues without errors. Does not return a value. ", "\n\n", "\01A\01Brangeset_add( r, [start, end] )\01A\n", "\01Brangeset_add( r, r0 )\01A\n", "\01IAdds to the rangeset r. The first form adds the range identified by the ", "current primary selection to the rangeset, unless start and end are defined, ", "in which case the range they define is added. Returns the index of the ", "newly-added range within the rangeset. The second form adds all ranges in ", "the rangeset r0 to the rangeset r, and returns 0. ", "\n\n", "\01A\01Brangeset_subtract( r, [start, end] )\01A\n", "\01Brangeset_subtract( r, r0 )\01A\n", "\01IRemoves from the rangeset r. The first form removes the range identified by ", "the current primary selection from the rangeset, unless start and end are ", "defined, in which case the range they define is removed. The second form ", "removes all ranges in the rangeset r0 from the rangeset r. Does not return ", "a value. ", "\n\n", "\01A\01Brangeset_invert( r )\01A\n", "\01IChanges the rangeset r so that it contains all ranges not in r. Does not ", "return a value. ", "\n\n", "\01A\01Brangeset_get_by_name( name )\01A\n", "\01IReturns an array of active rangeset identifiers, with integer keys starting at 0, ", "whose name matches name. ", "\n\n", "\01A\01Brangeset_info( r )\01A\n", "\01IReturns an array containing information about the rangeset r. The array ", "has the following keys: \01Jdefined\01I (whether a rangeset with identifier ", "r is defined), \01Jcount\01I (the number of ranges in the rangeset), \01Jcolor\01I ", "(the current background color of the rangeset, an empty string if the ", "rangeset has no color), \01Jname\01I (the user supplied name of the rangeset, ", "an empty string if the rangeset has no name), and \01Jmode\01I (the name of the ", "modify-response mode of the rangeset). ", "\n\n", "\01A\01Brangeset_range( r, [index] )\01A\n", "\01IReturns details of a specific range in the rangeset r. The range is ", "specified by index, which should be between 1 and n (inclusive), where ", "n is the number of ranges in the rangeset. The return value is an array ", "containing the keys \01Jstart\01I (the start position of the range) and \01Jend\01I ", "(the end position of the range). If index is not supplied, the region ", "returned is the span of the entire rangeset (the region starting at the ", "start of the first range and ending at the end of the last). If index ", "is outside the correct range of values, the function returns an empty array. ", "\n\n", "\01A\01Brangeset_includes( r, pos )\01A\n", "\01IReturns the index of the range in rangeset r which includes pos; returns ", "0 if pos is not contained in any of the ranges of r. This can also be used ", "as a simple true/false function which returns true if pos is contained in ", "the rangeset. ", "\n\n", "\01A\01Brangeset_set_color( r, color )\01A\n", "\01IAttempts to apply the color as a background color to the ranges of r. If ", "color is at empty string, removes the coloring of r. No check is made ", "regarding the validity of color: if the color is invalid (a bad name, ", "or not supported by the hardware) this has unpredictable effects. ", "\n\n", "\01A\01Brangeset_set_name( r, name )\01A\n", "\01IApply the name to the rangeset r. ", "\n\n", "\01A\01Brangeset_set_mode( r, type )\01A\n", "\01IChanges the behaviour of the rangeset r when modifications to the text ", "buffer occur. type can be one of the following: \"maintain\" (the default), ", "\"break\", \"include\", \"exclude\", \"ins_del\" or \"del_ins\". (These modes are ", "described above.) ", "\n\n", NULL }; static char * htxt_hiliteInfo [] = { "\01IThe user can interrogate the current window to determine the color ", "highlighting used on a particular piece of text. The following functions ", "provide information on the highlighting pattern against which text at a ", "particular position has been matched, its style, color and font attributes ", "(whether the font is supposed to be bold and/or italic). ", "\n\n", "These macro functions permit macro writers to generate formatted output which ", "allows NEdit highlighting to be reproduced. This is suitable for the ", "generation of HTML or Postscript output, for example. ", "\n\n", "Note that if any of the functions is used while in Plain mode or while syntax ", "highlighting is off, the behaviour is undefined. ", "\n\n", "\01A\01Bget_pattern_by_name( pattern_name )\01A\n", "\01IReturns an array containing the pattern attributes for pattern 'pattern_name'. ", "The elements in this array are: ", "\n\n", " * \01Jstyle\01I -- Highlight style name\n", "\n", "If 'pattern_name' is invalid, an empty array is returned. ", "\n\n", "\01A\01Bget_pattern_at_pos( pos )\01A\n", "\01IReturns an array containing the pattern attributes of the character at ", "position 'pos'. The elements in this array are: ", "\n\n", " * \01Jpattern\01I -- Highlight pattern name\n", " * \01Jstyle\01I -- Highlight style name\n", " * \01Jextent\01I -- The length in the text which uses the same highlighting pattern\n", "\n", "The 'extent' value is measured from position 'pos' going right/down (forward ", "in the file) only. ", "\n\n", "If 'pos' is invalid, an empty array is returned. ", "\n\n", "\01A\01Bget_style_by_name( style_name )\01A\n", "\01IReturns an array containing the style attributes for style 'style_name'. ", "The elements in this array are: ", "\n\n", " * \01Jbold\01I -- '1' if style is bold, '0' otherwise\n", " * \01Jitalic\01I -- '1' if style is italic, '0' otherwise\n", " * \01Jcolor\01I -- Name of the style's color\n", " * \01Jbackground\01I -- Name of the background color, if any\n", "\n", "The colors use the names specified in the color definitions for the style. ", "These will either be names matching those the X server recognises, or RGB ", "(red/green/blue) specifications. ", "\n\n", "If 'style_name' is invalid, an empty array is returned. ", "\n\n", "\01A\01Bget_style_at_pos( pos )\01A\n", "\01IReturns an array containing the style attributes of the character at ", "position 'pos'. The elements in this array are: ", "\n\n", " * \01Jstyle\01I -- Name of the highlight style\n", " * \01Jbold\01I -- '1' if style is bold, '0' otherwise\n", " * \01Jitalic\01I -- '1' if style is italic, '0' otherwise\n", " * \01Jcolor\01I -- Name of the style's color\n", " * \01Jrgb\01I -- Color's RGB values ('#rrggbb')\n", " * \01Jbackground\01I -- Name of the background color, if any\n", " * \01Jback_rgb\01I -- Background color's RGB values ('#rrggbb')\n", " * \01Jextent\01I -- The length in the text which uses the same highlight style\n", "\n", "The colors use the names specified in the color definitions for the style. ", "These will either be names matching those the X server recognises, or RGB ", "specifications. The values for 'rgb' and 'back_rgb' contain the actual color ", "values allocated by the X server for the window. If the X server cannot ", "allocate the specified (named) color exactly, the RGB values in these ", "entries may not match the specified ones. ", "\n\n", "The 'extent' value is measured from position 'pos' going right/down (forward ", "in the file) only. ", "\n\n", "If 'pos' is invalid, an empty array is returned. ", "\n\n", NULL }; static char * htxt_actions [] = { "\01IAll of the editing capabilities of NEdit are represented as a special type of ", "subroutine, called an action routine, which can be invoked from both macros ", "and translation table entries (see \"\01QKey Binding\01I\" in the ", "Customizing section of the Help menu). ", "\n\n", "\01RActions Representing Menu Commands\01I", "\n\n", "\01A File Menu Search Menu\n", " ----------------------- -------------------------\n", " new() find()\n", " open() find_dialog()\n", " open_dialog() find_again()\n", " open_selected() find_selection()\n", " close() replace()\n", " save() replace_dialog()\n", " save_as() replace_all()\n", " save_as_dialog() replace_in_selection()\n", " revert_to_saved() replace_again()\n", " include_file() goto_line_number()\n", " include_file_dialog() goto_line_number_dialog()\n", " load_macro_file() goto_selected()\n", " load_macro_file_dialog() mark()\n", " load_tags_file() mark_dialog()\n", " load_tags_file_dialog() goto_mark()\n", " unload_tags_file() goto_mark_dialog()\n", " load_tips_file() goto_matching()\n", " load_tips_file_dialog() select_to_matching()\n", " unload_tips_file() find_definition()\n", " print() show_tip()\n", " print_selection() \n", " exit() Shell Menu\n", " -------------------------\n", " Edit Menu filter_selection_dialog()\n", " ----------------------- filter_selection()\n", " undo() execute_command()\n", " redo() execute_command_dialog()\n", " delete() execute_command_line()\n", " select_all() shell_menu_command()\n", " shift_left() \n", " shift_left_by_tab() Macro Menu\n", " shift_right() -------------------------\n", " shift_right_by_tab() macro_menu_command()\n", " uppercase() repeat_macro()\n", " lowercase() repeat_dialog()\n", " fill_paragraph() \n", " control_code_dialog() Windows Menu\n", " -------------------------\n", " split_pane()\n", " close_pane()\n", " detach_document()\n", " move_document_dialog()\n", "\01I\n", "An action representing a menu command is usually named the same as its ", "corresponding menu item except that all punctuation is removed, all letters ", "are changed to lower case, and spaces are replaced with underscores. To ", "present a dialog to ask the user for input, use the actions with the ", "`_dialog` suffix. Actions without the `_dialog` suffix take the information ", "from the routine's arguments (see below). ", "\n\n", "\01RMenu Action Routine Arguments\01I", "\n\n", "Arguments are text strings enclosed in quotes. Below are the menu action ", "routines which take arguments. Optional arguments are enclosed in []. ", "\n\n", "\01A \01Bnew\01A( [\"tab\" | \"window\" | \"prefs\" | \"opposite\"] )\n", "\01I\n", "\01A \01Bclose\01A( [\"prompt\" | \"save\" | \"nosave\"] )\n", "\01I\n", "\01A \01Bexecute_command\01A( shell-command )\n", "\01I\n", "\01A \01Bfilter_selection\01A( shell-command )\n", "\01I\n", "\01A \01Bfind\01A( search-string [, \01Csearch-direction\01A] [, \01Csearch-type\01A] \n", " [, \01Csearch-wrap\01A] )\n", "\01I\n", "\01A \01Bfind_again\01A( [\01Csearch-direction\01A] [, \01Csearch-wrap\01A] )\n", "\01I\n", "\01A \01Bfind_definition\01A( [tag-name] )\n", "\01I\n", "\01A \01Bfind_dialog\01A( [\01Csearch-direction\01A] [, \01Csearch-type\01A] \n", " [, \01Ckeep-dialog\01A] )\n", "\01I\n", "\01A \01Bfind_selection\01A( [\01Csearch-direction\01A] [, \01Csearch-wrap\01A] \n", " [, \01Cnon-regex-search-type\01A] )\n", "\01I\n", "\01A \01Bgoto_line_number\01A( [\01Cline-number\01A] [, \01Ccolumn-number\01A] )\n", "\01I\n", "\01A \01Bgoto_mark\01A( \01Cmark-letter\01A )\n", "\01I\n", "\01A \01Binclude_file\01A( \01Cfilename\01A )\n", "\01I\n", "\01A \01Bload_tags_file\01A( \01Cfilename\01A )\n", "\01I\n", "\01A \01Bmacro_menu_command\01A( \01Cmacro-menu-item-name\01A )\n", "\01I\n", "\01A \01Bmark\01A( \01Cmark-letter\01A )\n", "\01I\n", "\01A \01Bopen\01A( \01Cfilename\01A )\n", "\01I\n", "\01A \01Breplace\01A( search-string, replace-string, \n", " [, \01Csearch-direction\01A] [, \01Csearch-type\01A] [, \01Csearch-wrap\01A] )\n", "\01I\n", "\01A \01Breplace_again\01A( [\01Csearch-direction\01A] [, \01Csearch-wrap\01A] )\n", "\01I\n", "\01A \01Breplace_all\01A( search-string, replace-string [, \01Csearch-type\01A] )\n", "\01I\n", "\01A \01Breplace_dialog\01A( [\01Csearch-direction\01A] [, \01Csearch-type\01A]\n", " [, \01Ckeep-dialog\01A] )\n", "\01I\n", "\01A \01Breplace_in_selection\01A( search-string, \n", " replace-string [, \01Csearch-type\01A] )\n", "\01I\n", "\01A \01Bsave_as\01A( \01Cfilename\01A )\n", "\01I\n", "\01A \01Bshell_menu_command\01A( \01Cshell-menu-item-name\01A )\n", "\01I\n", "\01A \01Bunload_tags_file\01A( \01Cfilename\01A )\n", "\01I\n", "\01A \01B----------- Some notes on argument types above -----------\01A\n", "\01I\n", "\01A \01CArguments to new()\01A\n", " \"tab\": Open a new tab\n", " \"window\": Open a new window\n", " \"prefs\": Follow the user's tab/window \n", " preference\n", " \"opposite\": Opposite of user's tab/window \n", " preference\n", " Default behaviour is \"prefs\".\n", "\01I\n", "\01A \01Cfilename\01A Path names are relative to the directory from\n", " which NEdit was started. Shell interpreted \n", " wildcards and `~' are not expanded.\n", "\01I\n", "\01A \01Ckeep-dialog\01A Either \"keep\" or \"nokeep\".\n", "\01I\n", "\01A \01Cmark-letter\01A The mark command limits users to single \n", " letters. Inside of macros, numeric marks are\n", " allowed, which won't interfere with marks set\n", " by the user.\n", "\01I\n", "\01A \01Cmacro-menu-item-name\01A\n", " Name of the command exactly as specified in \n", " the Macro Menu dialogs.\n", "\01I\n", "\01A \01Cnon-regex-search-type\01A \n", " Either \"literal\", \"case\", \"word\", or \n", " \"caseWord\".\n", "\01I\n", "\01A \01Csearch-direction\01A\n", " Either \"forward\" or \"backward\".\n", "\01I\n", "\01A \01Csearch-type\01A Either \"literal\", \"case\", \"word\", \n", " \"caseWord\", \"regex\", or \"regexNoCase\".\n", "\01I\n", "\01A \01Csearch-wrap\01A Either \"wrap\" or \"nowrap\".\n", "\01I\n", "\01A \01Cshell-menu-item-name\01A\n", " Name of the command exactly as specified in \n", " the Shell Menu dialogs.\n", "\01I\n", "\01RWindow Preferences Actions\01I", "\n\n", "\01A\01Bset_auto_indent( \"off\" | \"on\" | \"smart\" )\01A\n", "\01ISet auto indent mode for the current window. ", "\n\n", "\01A\01Bset_em_tab_dist( em-tab-distance )\01A\n", "\01ISet the emulated tab size. An em-tab-distance value of ", "0 or -1 translates to no emulated tabs. Em-tab-distance must ", "be smaller than 1000. ", "\n\n", "\01A\01Bset_fonts( font-name, italic-font-name, bold-font-name, bold-italic-font-name )\01A\n", "\01ISet all the fonts used for the current window. ", "\n\n", "\01A\01Bset_highlight_syntax( [0 | 1] )\01A\n", "\01ISet syntax highlighting mode for the current window. ", "A value of 0 turns it off and a value of 1 turns it on. ", "If no parameters are supplied the option is toggled. ", "\n\n", "\01A\01Bset_incremental_backup( [0 | 1] )\01A\n", "\01ISet incremental backup mode for the current window. ", "A value of 0 turns it off and a value of 1 turns it on. ", "If no parameters are supplied the option is toggled. ", "\n\n", "\01A\01Bset_incremental_search_line( [0 | 1] )\01A\n", "\01IShow or hide the incremental search line for the current window. ", "A value of 0 turns it off and a value of 1 turns it on. ", "If no parameters are supplied the option is toggled. ", "\n\n", "\01A\01Bset_language_mode( language-mode )\01A\n", "\01ISet the language mode for the current window. If the language mode is ", "\"\" or unrecognized, it will be set to Plain. ", "\n\n", "\01A\01Bset_locked( [0 | 1] )\01A\n", "\01IThis only affects the locked status of a file, not it's read-only ", "status. Permissions are NOT changed. ", "A value of 0 turns it off and a value of 1 turns it on. ", "If no parameters are supplied the option is toggled. ", "\n\n", "\01A\01Bset_make_backup_copy( [0 | 1] )\01A\n", "\01ISet whether backup copies are made during saves for the current window. ", "A value of 0 turns it off and a value of 1 turns it on. ", "If no parameters are supplied the option is toggled. ", "\n\n", "\01A\01Bset_overtype_mode( [0 | 1] )\01A\n", "\01ISet overtype mode for the current window. ", "A value of 0 turns it off and a value of 1 turns it on. ", "If no parameters are supplied the option is toggled. ", "\n\n", "\01A\01Bset_show_line_numbers( [0 | 1] )\01A\n", "\01IShow or hide line numbers for the current window. ", "A value of 0 turns it off and a value of 1 turns it on. ", "If no parameters are supplied the option is toggled. ", "\n\n", "\01A\01Bset_show_matching( \"off\" | \"delimiter\" | \"range\" )\01A\n", "\01ISet show matching (...) mode for the current window. ", "\n\n", "\01A\01Bset_match_syntax_based( [0 | 1] )\01A\n", "\01ISet whether matching should be syntax based for the current window. ", "\n\n", "\01A\01Bset_statistics_line( [0 | 1] )\01A\n", "\01IShow or hide the statistics line for the current window. ", "A value of 0 turns it off and a value of 1 turns it on. ", "If no parameters are supplied the option is toggled. ", "\n\n", "\01A\01Bset_tab_dist( tab-distance )\01A\n", "\01ISet the size of hardware tab spacing. Tab-distance must ", "be a value greater than 0 and no greater than 20. ", "\n\n", "\01A\01Bset_use_tabs( [0 | 1] )\01A\n", "\01ISet whether tabs are used for the current window. ", "A value of 0 turns it off and a value of 1 turns it on. ", "If no parameters are supplied the option is toggled. ", "\n\n", "\01A\01Bset_wrap_margin( wrap-width )\01A\n", "\01ISet the wrap width for text wrapping of the current window. A value ", "of 0 means to wrap at window width. ", "\n\n", "\01A\01Bset_wrap_text( \"none\" | \"auto\" | \"continuous\" )\01A\n", "\01ISet wrap text mode for the current window. ", "\n\n", "\01RKeyboard-Only Actions\01I", "\n\n", "In addition to the arguments listed in the call descriptions below, any ", "routine involving cursor movement can take the argument \"extend\", meaning, ", "adjust the primary selection to the new cursor position. Routines which take ", "the \"extend\" argument as well as mouse dragging operations for both primary ", "and secondary selections can take the optional keyword \"rect\", meaning, make ", "the selection rectangular. Any routine that accepts the \"scrollbar\" argument ", "will move the display but not the cursor or selection. Routines that accept ", "the \"nobell\" argument will fail silently without beeping, when that argument ", "is supplied. ", "\n\n", "\01A\01Bbackward_character( [\"nobell\"] )\01A\n", "\01IMoves the cursor one character to the left. ", "\n\n", "\01A\01Bbackward_paragraph([\"nobell\"] )\01A\n", "\01IMoves the cursor to the beginning of the paragraph, or ", "if the cursor is already at the beginning of a paragraph, moves the cursor to ", "the beginning of the previous paragraph. Paragraphs are defined as regions ", "of text delimited by one or more blank lines. ", "\n\n", "\01A\01Bbackward_word( [\"nobell\"] )\01A\n", "\01IMoves the cursor to the beginning of a word, or, if the ", "cursor is already at the beginning of a word, moves the cursor to the ", "beginning of the previous word. Word delimiters are user-settable, and ", "defined by the X resource wordDelimiters. ", "\n\n", "\01A\01Bbeginning_of_file( [\"scrollbar\"] )\01A\n", "\01IMoves the cursor to the beginning of the file. ", "\n\n", "\01A\01Bbeginning_of_line( [\"absolute\"] )\01A \n", "\01IMoves the cursor to the beginning of the line. If ", "\"absolute\" is given, always moves to the absolute beginning of line, ", "regardless of the text wrapping mode. ", "\n\n", "\01A\01Bbeginning_of_selection()\01A\n", "\01IMoves the cursor to the beginning of the selection ", "without disturbing the selection. ", "\n\n", "\01A\01Bcopy_clipboard()\01A\n", "\01ICopies the current selection to the clipboard. ", "\n\n", "\01A\01Bcopy_primary()\01A\n", "\01ICopies the primary selection to the cursor. ", "\n\n", "\01A\01Bcopy_to()\01A\n", "\01IIf a secondary selection exists, copies the secondary selection to ", "the cursor. If no secondary selection exists, copies the primary selection ", "to the pointer location. ", "\n\n", "\01A\01Bcopy_to_or_end_drag()\01A\n", "\01ICompletes either a secondary selection operation, or a ", "primary drag. If the user is dragging the mouse to adjust a secondary ", "selection, the selection is copied and either inserted at the cursor ", "location, or, if pending-delete is on and a primary selection exists in the ", "window, replaces the primary selection. If the user is dragging a block of ", "text (primary selection), completes the drag operation and leaves the text at ", "it's current location. ", "\n\n", "\01A\01Bcut_clipboard()\01A\n", "\01IDeletes the text in the primary selection and places it in ", "the clipboard. ", "\n\n", "\01A\01Bcut_primary()\01A\n", "\01ICopies the primary selection to the cursor and deletes it at ", "its original location. ", "\n\n", "\01A\01Bdelete_selection()\01A\n", "\01IDeletes the contents of the primary selection. ", "\n\n", "\01A\01Bdelete_next_character( [\"nobell\"] )\01A\n", "\01IIf a primary selection exists, deletes its contents. ", "Otherwise, deletes the character following the cursor. ", "\n\n", "\01A\01Bdelete_previous_character( [\"nobell\"] )\01A\n", "\01IIf a primary selection exists, deletes its ", "contents. Otherwise, deletes the character before the cursor. ", "\n\n", "\01A\01Bdelete_next_word( [\"nobell\"] )\01A\n", "\01IIf a primary selection exists, deletes its contents. ", "Otherwise, deletes the word following the cursor. ", "\n\n", "\01A\01Bdelete_previous_word( [\"nobell\"] )\01A\n", "\01IIf a primary selection exists, deletes its contents. ", "Otherwise, deletes the word before the cursor. ", "\n\n", "\01A\01Bdelete_to_start_of_line( [\"nobell\", \"wrap\"] )\01A\n", "\01IIf a primary selection exists, deletes its contents. Otherwise, deletes the ", "characters between the cursor and the start of the line. If \"wrap\" is ", "given, deletes to the previous wrap point or beginning of line, whichever ", "is closest. ", "\n\n", "\01A\01Bdelete_to_end_of_line( [\"nobell\", \"absolute\"] )\01A\n", "\01IIf a primary selection exists, deletes its contents. ", "Otherwise, deletes the characters between the cursor and the end of the line. ", "If \"absolute\" is given, always deletes to the absolute end of line, regardless ", "of the text wrapping mode. ", "\n\n", "\01A\01Bdeselect_all()\01A\n", "\01IDe-selects the primary selection. ", "\n\n", "\01A\01Bend_of_file( [\"scrollbar\"] )\01A\n", "\01IMoves the cursor to the end of the file. ", "\n\n", "\01A\01Bend_of_line( [\"absolute\"] )\01A \n", "\01IMoves the cursor to the end of the line. If ", "\"absolute\" is given, always moves to the absolute end of line, regardless ", "of the text wrapping mode. ", "\n\n", "\01A\01Bend_of_selection()\01A\n", "\01IMoves the cursor to the end of the selection without ", "disturbing the selection. ", "\n\n", "\01A\01Bexchange( [\"nobell\"] )\01A\n", "\01IExchange the primary and secondary selections. ", "\n\n", "\01A\01Bextend_adjust()\01A\n", "\01IAttached mouse-movement events to begin a selection between ", "the cursor and the mouse, or extend the primary selection to the mouse ", "position. ", "\n\n", "\01A\01Bextend_end()\01A\n", "\01ICompletes a primary drag-selection operation. ", "\n\n", "\01A\01Bextend_start()\01A\n", "\01IBegins a selection between the cursor and the mouse. A ", "drag-selection operation can be started with either extend_start or ", "grab_focus. ", "\n\n", "\01A\01Bfocus_pane( [relative-pane] | [positive-index] | [negative-index] )\01A\n", "\01IMove the focus to the requested pane. ", "Arguments can be specified in the form of a relative-pane ", "(\"first\", \"last\", \"next\", \"previous\"), a positive-index ", "(numbers greater than 0, 1 is the same as \"first\") or a ", "negative-index (numbers less than 0, -1 is the same as \"last\"). ", "\n\n", "\01A\01Bforward_character()\01A\n", "\01IMoves the cursor one character to the right. ", "\n\n", "\01A\01Bforward_paragraph( [\"nobell\"] )\01A\n", "\01IMoves the cursor to the beginning of the next paragraph. ", "Paragraphs are defined as regions of text delimited by one or more blank ", "lines. ", "\n\n", "\01A\01Bforward_word( [\"tail\"] [\"nobell\"] )\01A\n", "\01IMoves the cursor to the beginning of the next word. Word ", "delimiters are user-settable, and defined by the X resource wordDelimiters. ", "If the \"tail\" argument is supplied the cursor will be moved to ", "the end of the current word or the end of the next word, if the ", "cursor is between words. ", "\n\n", "\01A\01Bgrab_focus()\01A\n", "\01IMoves the cursor to the mouse pointer location, and prepares for ", "a possible drag-selection operation (bound to extend_adjust), or multi-click ", "operation (a further grab_focus action). If a second invocation of grab ", "focus follows immediately, it selects a whole word, or a third, a whole line. ", "\n\n", "\01A\01Binsert_string( \"string\" )\01A\n", "\01IIf pending delete is on and the cursor is inside the ", "selection, replaces the selection with \"string\". Otherwise, inserts \"string\" ", "at the cursor location. ", "\n\n", "\01A\01Bkey_select( \"direction\" [,\"nobell\"] )\01A\n", "\01IMoves the cursor one character in \"direction\" ", "(\"left\", \"right\", \"up\", or \"down\") and extends the selection. Same as ", "forward/backward-character(\"extend\"), or process-up/down(\"extend\"), for ", "compatibility with previous versions. ", "\n\n", "\01A\01Bmove-destination()\01A\n", "\01IMoves the cursor to the pointer location without ", "disturbing the selection. (This is an unusual way of working. We left it in ", "for compatibility with previous versions, but if you actually use this ", "capability, please send us some mail, otherwise it is likely to disappear in ", "the future. ", "\n\n", "\01A\01Bmove_to()\01A\n", "\01IIf a secondary selection exists, deletes the contents of the ", "secondary selection and inserts it at the cursor, or if pending-delete is on ", "and there is a primary selection, replaces the primary selection. If no ", "secondary selection exists, moves the primary selection to the pointer ", "location, deleting it from its original position. ", "\n\n", "\01A\01Bmove_to_or_end_drag()\01A\n", "\01ICompletes either a secondary selection operation, or a ", "primary drag. If the user is dragging the mouse to adjust a secondary ", "selection, the selection is deleted and either inserted at the cursor ", "location, or, if pending-delete is on and a primary selection exists in the ", "window, replaces the primary selection. If the user is dragging a block of ", "text (primary selection), completes the drag operation and deletes the text ", "from it's current location. ", "\n\n", "\01A\01Bnewline()\01A\n", "\01IInserts a newline character. If Auto Indent is on, lines up the ", "indentation of the cursor with the current line. ", "\n\n", "\01A\01Bnewline_and_indent()\01A\n", "\01IInserts a newline character and lines up the indentation ", "of the cursor with the current line, regardless of the setting of Auto ", "Indent. ", "\n\n", "\01A\01Bnewline_no_indent()\01A\n", "\01IInserts a newline character, without automatic ", "indentation, regardless of the setting of Auto Indent. ", "\n\n", "\01A\01Bnext_page( [\"stutter\"] [\"column\"] [\"scrollbar\"] [\"nobell\"] )\01A\n", "\01IMoves the cursor and scroll forward one page. ", "The parameter \"stutter\" moves the cursor to the bottom of the display, ", "unless it is already there, otherwise it will page down. ", "The parameter \"column\" will maintain the preferred column while ", "moving the cursor. ", "\n\n", "\01A\01Bpage_left( [\"scrollbar\"] [\"nobell\"] )\01A\n", "\01IMove the cursor and scroll left one page. ", "\n\n", "\01A\01Bpage_right( [\"scrollbar\"] [\"nobell\"] )\01A\n", "\01IMove the cursor and scroll right one page. ", "\n\n", "\01A\01Bpaste_clipboard()\01A\n", "\01IInsert the contents of the clipboard at the cursor, or if ", "pending delete is on, replace the primary selection with the contents of the ", "clipboard. ", "\n\n", "\01A\01Bprevious_page( [\"stutter\"] [\"column\"] [\"scrollbar\"] [\"nobell\"] )\01A\n", "\01IMoves the cursor and scroll backward one page. ", "The parameter \"stutter\" moves the cursor to the top of the display, ", "unless it is already there, otherwise it will page up. ", "The parameter \"column\" will maintain the preferred column while ", "moving the cursor. ", "\n\n", "\01A\01Bprocess_bdrag()\01A\n", "\01ISame as secondary_or_drag_start for compatibility with previous versions. ", "\n\n", "\01A\01Bprocess_cancel()\01A\n", "\01ICancels the current extend_adjust, secondary_adjust, or ", "secondary_or_drag_adjust in progress. ", "\n\n", "\01A\01Bprocess_down( [\"nobell\", \"absolute\"] )\01A\n", "\01IMoves the cursor down one line. If \"absolute\" is given, always moves to the ", "next line in the text buffer, regardless of wrapping. ", "\n\n", "\01A\01Bprocess_return()\01A\n", "\01ISame as newline for compatibility with previous versions. ", "\n\n", "\01A\01Bprocess_shift_down( [\"nobell\", \"absolute\"] )\01A\n", "\01ISame as process_down(\"extend\") for compatibility with previous versions. ", "\n\n", "\01A\01Bprocess_shift_up( [\"nobell\", \"absolute\"] )\01A\n", "\01ISame as process_up(\"extend\") for compatibility with previous versions. ", "\n\n", "\01A\01Bprocess_tab()\01A\n", "\01IIf tab emulation is turned on, inserts an emulated tab, ", "otherwise inserts a tab character. ", "\n\n", "\01A\01Bprocess_up( [\"nobell\", \"absolute\"] )\01A\n", "\01IMoves the cursor up one line. If \"absolute\" is given, always moves to the ", "previous line in the text buffer, regardless of wrapping. ", "\n\n", "\01A\01Braise_window([relative-window] | [positive-index] | [negative-index] [, \"focus\" | \"nofocus\"])\01A\n", "\01IRaise the current focused window to the front if no argument is supplied. ", "Arguments can be specified in the form of a relative-window ", "(\"first\", \"last\", \"next\", \"previous\"), a positive-index ", "(numbers greater than 0, 1 is the same as \"last\") or a ", "negative-index (numbers less than 0, -1 is the same as \"first\"). ", "\n\n", "Moreover, it can be specified whether or not the raised window should ", "request the X input focus. By default, it depends on the setting of the ", "nedit.focusOnRaise resource (see the section \"\01QX Resources\01I\") whether or not ", "the input focus is requested. ", "\n\n", "\01A\01Bscroll_down( nUnits, [\"lines\" | \"pages\"] )\01A\n", "\01IScroll the display down (towards the end of the file) by a given ", "number of units, units being lines or pages. Default units are lines. ", "\n\n", "\01A\01Bscroll_left( nPixels )\01A\n", "\01IScroll the display left by nPixels. ", "\n\n", "\01A\01Bscroll_right( nPixels )\01A\n", "\01IScroll the display right by nPixels. ", "\n\n", "\01A\01Bscroll_up( nUnits, [\"lines\" | \"pages\"] )\01A\n", "\01IScroll the display up (towards the beginning of the file) by a given ", "number of units, units being lines or pages. Default units are lines. ", "\n\n", "\01A\01Bscroll_to_line( lineNum )\01A\n", "\01IScroll to position line number lineNum at the top of ", "the pane. The first line of a file is line 1. ", "\n\n", "\01A\01Bsecondary_adjust()\01A\n", "\01IAttached mouse-movement events to extend the secondary ", "selection to the mouse position. ", "\n\n", "\01A\01Bsecondary_or_drag_adjust()\01A\n", "\01IAttached mouse-movement events to extend the ", "secondary selection, or reposition the primary text being dragged. Takes two ", "optional arguments, \"copy\", and \"overlay\". \"copy\" leaves a copy of the ", "dragged text at the site at which the drag began. \"overlay\" does the drag in ", "overlay mode, meaning the dragged text is laid on top of the existing text, ", "obscuring and ultimately deleting it when the drag is complete. ", "\n\n", "\01A\01Bsecondary_or_drag_start()\01A\n", "\01ITo be attached to a mouse down event. Begins drag ", "selecting a secondary selection, or dragging the contents of the primary ", "selection, depending on whether the mouse is pressed inside of an existing ", "primary selection. ", "\n\n", "\01A\01Bsecondary_start()\01A\n", "\01ITo be attached to a mouse down event. Begin drag selecting ", "a secondary selection. ", "\n\n", "\01A\01Bselect_all()\01A\n", "\01ISelect the entire file. ", "\n\n", "\01A\01Bself_insert()\01A\n", "\01ITo be attached to a key-press event, inserts the character ", "equivalent of the key pressed. ", "\n\n", NULL }; static char * htxt_customize [] = { "\01INEdit can be customized in many different ways. The most important ", "user-settable options are presented in the Preferences menu, including all ", "options that users might need to change during an editing session. Options ", "set in the Default Settings sub-menu of the Preferences menu can be preserved ", "between sessions by selecting Save Defaults, which writes the changes to the ", "preferences file. See the section titled \"\01QPreferences\01I\" for more details. ", "\n\n", "User defined commands can be added to NEdit's Shell, Macro, and window ", "background menus. Dialogs for creating items in these menus can be found ", "under Customize Menus in the Default Settings sub menu of the Preferences ", "menu. ", "\n\n", "For users who depend on NEdit every day and want to tune every excruciating ", "detail, there are also X resources for tuning a vast number of such details, ", "down to the color of each individual button. See the section \"\01QX Resources\01I\" ", "for more information, as well as a list of selected resources. ", "\n\n", "The most common reason for customizing your X resources for NEdit, however, is ", "key binding. While limited key binding can be done through Preferences ", "settings (Preferences -> Default Settings -> Customize Menus), you can really ", "only add keys this way, and each key must have a corresponding menu item. ", "Any significant changes to key binding should be made via the Translations ", "resource and menu accelerator resources. The sections titled \"\01QKey Binding\01I\" ", "and \"\01QX Resources\01I\" have more information. ", NULL }; static char * htxt_preferences [] = { "\01IThe Preferences menu allows you to set options for both the current editing ", "window, and default values for newly created windows and future NEdit ", "sessions. Options in the Preferences menu itself (not in the Default ", "Settings sub-menu) take effect immediately and refer to the current window ", "only. Options in the Default Settings sub-menu provide initial settings for ", "future windows created using the New or Open commands; options affecting all ", "windows are also set here. ", "\n\n", "Preferences set in the Default Settings sub-menu are saved in a file that ", "NEdit reads at startup time, cf. \01QAutoload Files\01I, by selecting Save Defaults. ", "\n\n", "\01RPreferences Menu\01I", "\n\n", "\01A\01BDefault Settings\01A\n", "\01IMenu of initial settings for future windows. Generally the same as the ", "options in the main part of the menu, but apply as defaults for future ", "windows created during this NEdit session. These settings can be saved using ", "the Save Defaults command below, to be loaded automatically each time NEdit ", "is started. ", "\n\n", "\01A\01BSave Defaults\01A\n", "\01ISave the default options as set under Default Settings for future NEdit ", "sessions. ", "\n\n", "\01A\01BStatistics Line\01A\n", "\01IShow the full file name, line number, and length of the file being edited. ", "\n\n", "\01A\01BIncremental Search Line\01A\n", "\01IKeep the incremental search bar (Search -> Find Incremental) permanently ", "displayed at the top of the window. ", "\n\n", "\01A\01BShow Line Numbers\01A\n", "\01IDisplay line numbers to the right of the text. ", "\n\n", "\01A\01BLanguage Mode\01A\n", "\01ITells NEdit what language (if any) to assume, for selecting language-specific ", "features such as highlight patterns and smart indent macros, and setting ", "language specific preferences like word delimiters, tab emulation, and ", "auto-indent. See \01QProgramming with NEdit\01I for more information. ", "\n\n", "\01A\01BAuto Indent\01A\n", "\01ISetting Auto Indent \"on\" maintains a running indent (pressing the Return key ", "will line up the cursor with the indent level of the previous line). If ", "smart indent macros are available for the current language mode, smart indent ", "can be selected and NEdit will attempt to guess proper language indentation ", "for each new line, cf. \01QAuto/Smart Indent\01I. ", "\n\n", "\01A\01BWrap\01A\n", "\01IChoose between two styles of automatic wrapping or none. Auto Newline wrap, ", "wraps text at word boundaries when the cursor reaches the right margin, by ", "replacing the space or tab at the last word boundary with a newline ", "character. Continuous Wrap wraps long lines which extend past the right ", "margin. Continuous Wrap mode is typically used to produce files where ", "newlines are omitted within paragraphs, to make text filling automatic (a ", "kind of poor-man's word processor). Text of this style is common on Macs and ", "PCs but is not necessarily supported very well under Unix (except in programs ", "which deal with e-mail, for which it is often the format of choice). ", "\n\n", "\01A\01BWrap Margin\01A\n", "\01ISet margin for Auto Newline Wrap, Continuous Wrap, and Fill Paragraph. Lines ", "may, be wrapped at the right margin of the window, or the margin can be set ", "at a specific column. ", "\n\n", "\01A\01BTab Stops\01A\n", "\01ISet the tab distance (number of characters between tab stops) for tab ", "characters, and control tab emulation and use of tab characters in padding ", "and emulated tabs. ", "\n\n", "\01A\01BText Font...\01A\n", "\01IChange the font(s) used to display text (fonts for menus and dialogs must be ", "set using X resources for the text area of the window). See below for more ", "information. ", "\n\n", "\01A\01BHighlight Syntax\01A\n", "\01IIf NEdit recognizes the language being edited, and highlighting patterns are ", "available for that language, use fonts and colors to enhance viewing of the ", "file. (See \01QSyntax Highlighting\01I for more information.) ", "\n\n", "\01A\01BMake Backup Copy\01A\n", "\01IOn Save, write a backup copy of the file as it existed before the Save ", "command with the extension .bck (Unix only). ", "\n\n", "\01A\01BIncremental Backup\01A\n", "\01IPeriodically make a backup copy of the file being edited under the name ", "`~filename` on Unix or `_filename` on VMS (see \01QCrash Recovery\01I). ", "\n\n", "\01A\01BShow Matching (..)\01A\n", "\01IMomentarily highlight matching parenthesis, brackets, and braces, or the ", "range between them, when one of these characters is typed, or when the ", "insertion cursor is positioned after it. Delimiter only highlights the ", "matching delimiter, while Range highlights the whole range of text between ", "the matching delimiters. ", "\n\n", "Optionally, the matching can make use of syntax information if syntax ", "highlighting is enabled. Alternatively, the matching is purely character ", "based. In general, syntax based matching results in fewer false matches. ", "\n\n", "\01A\01BOvertype\01A\n", "\01IIn overtype mode, new characters entered replace the characters in front of ", "the insertion cursor, rather than being inserted before them. ", "\n\n", "\01A\01BRead Only\01A\n", "\01ILock the file against accidental modification. This temporarily prevents the ", "file from being modified in this NEdit session. Note that this is different ", "from setting the file protection. ", "\n\n", "\01RPreferences -> Default Settings Menu\01I", "\n\n", "Options in the Preferences -> Default Settings menu have the same meaning as ", "those in the top-level Preferences menu, except that they apply to future ", "NEdit windows and future NEdit sessions if saved with the Save Defaults ", "command. Additional options which appear in this menu are: ", "\n\n", "\01A\01BLanguage Modes\01A\n", "\01IDefine language recognition information (for determining language mode from ", "file name or content) and set language specific preferences. ", "\n\n", "\01A\01BTag Collisions\01A\n", "\01IHow to react to multiple tags for the same name. Tags are described in the ", "section: \01QFinding Declarations (ctags)\01I. In Show All mode, all matching tags ", "are displayed in a dialog. In Smart mode, if one of the matching tags is in ", "the current window, that tag is chosen, without displaying the dialog. ", "\n\n", "\01A\01BSelect Shell...\01A\n", "\01ISet the shell used to run programs from the shell_command() macro function ", "and from the Shell menu. This defaults to the user's login shell. ", "\n\n", "\01A\01BColors...\01A\n", "\01IChange the colors used to display text. The \"Matching (..)\" fields change the ", "colors that matching parens, brackets and braces are flashed when the \"Show ", "Matching (..)\" option is enabled. Note that the foreground colors for plain ", "text, selected text, and matching paren flashing only apply when syntax ", "highlighting is disabled. When syntax highlighting is enabled, text (even ", "text that appears plain) will always be colored according to its highlighting ", "style. (For information on changing syntax highlighting styles and matching ", "patterns use see \01QSyntax Highlighting\01I.) ", "\n\n", "\01A\01BCustomize Menus\01A\n", "\01IAdd/remove items from the Shell, Macro, and window background menus (see ", "below). ", "\n\n", "\01A\01BCustomize Window Title\01A\n", "\01IOpens a dialog where the information to be displayed in the window's title ", "field can be defined and tested. The dialog contains a Help button, providing ", "further information about the options available. ", "\n\n", "\01A\01BSearching\01A\n", "\01IOptions for controlling the behavior of Find and Replace commands: ", "\n\n", "\01KVerbose\01I - ", "Presents search results in dialog form, asks before wrapping a ", "search back around the beginning (or end) of the file ", "(unless Beep On Search Wrap is turned on). ", "\n\n", "\01KWrap Around\01I - ", "Search and Replace operations wrap around the beginning (or end) of the file. ", "\n\n", "\01KBeep On Search Wrap\01I - ", "Beep when Search and Replace operations wrap around the beginning (or end) of ", "the file (only if Wrap Around is turned on). ", "\n\n", "\01KKeep Dialogs Up\01I - ", "Don't pop down Replace and Find boxes after searching. ", "\n\n", "\01KDefault Search Style\01I - ", "Initial setting for search type in Find and Replace dialogs. ", "\n\n", "\01KDefault Replace Scope\01I - ", "[THIS OPTION IS ONLY PRESENT WHEN NEDIT WAS COMPILED WITH THE ", "\01A -DREPLACE_SCOPE FLAG TO SELECT AN ALTERNATIVE REPLACE DIALOG LAYOUT.]\n", "\01I\n", "Initial setting for the scope in the Replace/Find dialog, when a selection ", "exists. It can be either \"In Window\", \"In Selection\", or \"Smart\". \"Smart\" ", "results in \"In Window\" if the size of the selection is smaller than 1 line, ", "and to \"In Selection\" otherwise. ", "\n\n", "\01A\01BSyntax Highlighting\01A\n", "\01IProgram and configure enhanced text display for new or supported languages. ", "(See \01QSyntax Highlighting\01I.) ", "\n\n", "\01A\01BTabbed Editing\01A\n", "\01IOptions for controlling the tabbed interface: ", "\n\n", "\01KOpen File in New Tab\01I - ", "Open files in new tabs, else open files in new windows. ", "\n\n", "\01KShow Tab Bar\01I - ", "Show/Hide the tab bar. ", "\n\n", "\01KHide Tab Bar when only one Document is open\01I ", "\n\n", "\01KNext/Prev Tabs Across Windows\01I - ", "Suppose there are two windows with three tabs in the first window and two tabs in ", "the second window. Enabling this option, if you are on the third tab in the ", "first window, hitting Ctrl+PageDown would switch to the first tab in the second ", "window (instead of switching to the first tab in the first window). ", "\n\n", "\01KSort Tabs Alphabetically\01I ", "\n\n", "\01A\01BShow Tooltips\01A\n", "\01IShow file name and path in a tooltip when moving the mouse pointer over a tab. ", "(See \01QTabbed Editing\01I.) ", "\n\n", "\01A\01BTerminate with Line Break on Save\01A\n", "\01ISome UNIX tools expect that files end with a line feed. If this option is ", "activated, NEdit will append one if required. ", "\n\n", "\01A\01BSort Open Prev. Menu\01A\n", "\01IOption to order the File -> Open Previous menu alphabetically, versus in ", "order of last access. ", "\n\n", "\01A\01BPopups Under Pointer\01A\n", "\01IDisplay pop-up dialogs centered on the current mouse position, as opposed to ", "centered on the parent window. This generally speeds interaction, and is ", "essential for users who set their window managers so keyboard focus ", "follows the mouse. ", "\n\n", "\01A\01BAuto-Scroll Near Window Top/Bottom\01A\n", "\01IWhen this option is enabled the window will automatically scroll when the ", "cursor comes 4 lines from the top or bottom of the window (except at the ", "beginning of the file). The number of lines can be customized with the ", "nedit.autoScrollVPadding resource. ", "\n\n", "\01A\01BWarnings\01A\n", "\01IOptions for controlling the popping up of warning dialogs: ", "\n\n", "\01KFile Modified Externally\01I - ", "Pop up a warning dialog when files get changed external to NEdit. ", "\n\n", "\01KCheck Modified File Contents\01I - ", "If external file modification warnings are requested, also check the file ", "contents iso. only the modification date. ", "\n\n", "\01KOn Exit\01I - ", "Ask before exiting when two or more files are open in an NEdit session ", "or before closing a window with two or more tabs. ", "\n\n", "\01A\01BInitial Window Size\01A\n", "\01IDefault size for new windows. ", "\n\n", "\01RChanging Font(s)\01I", "\n\n", "The font used to display text in NEdit is set under Preferences -> Text Font ", "(for the current window), or Preferences -> Default Settings Text Font (for ", "future windows). These dialogs also allow you to set fonts for syntax ", "highlighting. If you don't intend to use syntax highlighting, you can ignore ", "most of the dialog, and just set the field labeled Primary Font. ", "\n\n", "Unless you are absolutely certain about the types of files that you will be ", "editing with NEdit, you should choose a fixed-spacing font. Many, if not ", "most, plain-text files are written expecting to be viewed with fixed ", "character spacing, and will look wrong with proportional spacing. NEdit's ", "filling, wrapping, and rectangular operations will also work strangely if you ", "choose a proportional font. ", "\n\n", "Note that in the font browser (the dialog brought up by the Browse... ", "button), the subset of fonts which are shown is narrowed depending on the ", "characteristics already selected. It is therefore important to know that you ", "can unselect characteristics from the lists by clicking on the selected items ", "a second time. ", "\n\n", "Fonts for syntax highlighting should ideally match the primary font in both ", "height and spacing. A mismatch in spacing will result in similar distortions ", "as choosing a proportional font: column alignment will sometimes look wrong, ", "and rectangular operations, wrapping, and filling will behave strangely. A ", "mismatch in height will cause windows to re-size themselves slightly when ", "syntax highlighting is turned on or off, and increase the inter- line spacing ", "of the text. Unfortunately, on some systems it is hard to find sets of fonts ", "which match exactly in height. ", "\n\n", "\01RCustomizing Menus\01I", "\n\n", "You can add or change items in the Shell, Macro, and window background menus ", "under Preferences -> Default Settings -> Customize Menus. When you choose ", "one of these, you will see a dialog with a list of the current ", "user-configurable items from the menu on the left. To change an existing ", "item, select it from the list, and its properties will appear in the ", "remaining fields of the dialog, where you may change them. Selecting the ", "item \"New\" from the list allows you to enter new items in the menu. ", "\n\n", "Hopefully most of the characteristics are self explanatory, but here are a ", "few things to note: ", "\n\n", "Accelerator keys are keyboard shortcuts which appear on the right hand side ", "of the menus, and allow you avoid pulling down the menu and activate the ", "command with a single keystroke. Enter accelerators by typing the keys ", "exactly as you would to activate the command. ", "\n\n", "Mnemonics are a single letter which should be part of the menu item name, ", "which allow users to traverse and activate menu items by typing keys when the ", "menu is pulled down. ", "\n\n", "In the Shell Command field of the Shell Commands dialog, the % character ", "expands to the name (including directory path) of the file in the window. To ", "include a % character in the command, use %%. ", "\n\n", "The Menu Entry field can contain special characters for constructing ", "hierarchical sub-menus, and for making items which appear only in certain ", "language modes. The right angle bracket character \">\" creates a sub-menu. ", "The name of the item itself should be the last element of the path formed ", "from successive sub-menu names joined with \">\". Menu panes are called in to ", "existence simply by naming them as part of a Menu Entry name. To put several ", "items in the same sub-menu, repeat the same hierarchical sequence for each. ", "For example, in the Macro Commands dialog, two items with menu entries: a>b>c ", "and a>b>d would create a single sub menu under the macro menu called \"a\", ", "which would contain a single sub-menu, b, holding the actual items, c and d: ", "\n\n", "\01A +---++---++---+\n", " |a >||b >||c |\n", " +---++---+|d |\n", " +---+\n", "\01I\n", "To qualify a menu entry with a language mode, simply add an at-sign \"@\" at ", "the end of the menu command, followed (no space) by a language mode name. To ", "make a menu item which appears in several language modes, append additional ", "@s and language mode names. For example, an item with the menu entry: ", "\n\n", "\01A Make C Prototypes@C@C++\n", "\01I\n", "would appear only in C and C++ language modes, and: ", "\n\n", "\01A Make Class Template@C++\n", "\01I\n", "would appear only in C++ mode. ", "\n\n", "Menu items with no qualification appear in all language modes. ", "\n\n", "If a menu item is followed by the single language qualification \"@*\", that ", "item will appear only if there are no applicable language-specific items of ", "the same name in the same submenu. For example, if you have the following ", "three entries in the same menu: ", "\n\n", "\01A Make Prototypes@C@C++\n", " Make Prototypes@Java\n", " Make Prototypes@*\n", "\01I\n", "The first will be available when the language mode is C or C++, the second ", "when the language mode is Java, and for all other language modes (including ", "the \"Plain\" non-language mode). If the entry: ", "\n\n", "\01A Make Prototypes\n", "\01I\n", "also exists, this will always appear, meaning that the menu will always have ", "two \"Make Prototypes\" entries, whatever the language mode. ", "\n\n", "\01RThe NEdit Autoload Files\01I", "\n\n", "At startup time, NEdit automatically reads the preferences file ", "`nedit.rc', the autoload macro file `autoload.nm', and the history data base ", "`nedit.history'. The preferences file contains saved preferences (menu ", "settings) in the format of an X resource file. The autoload macro file is a ", "macro file containing macro commands and definitions that NEdit will ", "execute at startup. (NEdit doesn't create this file automatically.) ", "Moreover, NEdit saves a list of the recently opened files, which appear under ", "the Open Previous menu, in the history data base. ", "\n\n", "By default the location of these files is '$HOME/.nedit/'. A different ", "directory can be given by letting the environment variable NEDIT_HOME ", "point to it. ", "\n\n", "Notice that NEdit still supports the older names for these files, which are ", "`$HOME/.nedit', `$HOME/.neditmacro', and `$HOME/.neditdb', respectively. This ", "old naming scheme will be used if NEdit detects that `$HOME/.nedit' is a ", "regular file and NEDIT_HOME isn't set. ", "\n\n", "(For VMS, the location of these files is '$NEDIT_HOME/' if NEDIT_HOME is set, ", "and 'SYS$LOGIN:' otherwise.) ", "\n\n", "The contents of the preferences file can be moved into another X resource ", "file (see \01QX Resources\01I). One reason for doing so would be to attach server ", "specific preferences, such as a default font, to a particular X server. ", "Another reason for moving preferences into an X resource file would be to ", "keep preferences menu options and X resource settable options together in ", "one place. Though the files are the same format, additional resources ", "should not be added to the preferences file, since NEdit modifies that file ", "by overwriting it completely. Note also that the contents of the ", "preferences file takes precedence over the values in an X resource file. ", "Using Save Defaults after moving the contents of your preferences file to ", "your .Xdefaults file will re-create the preferences file, interfering with ", "the options that you have moved. ", "\n\n", "\01RSharing Customizations with Other NEdit Users\01I", "\n\n", "If you have written macro or shell menu commands, highlight patterns, or ", "smart-indent macros that you want to share with other NEdit users, you can ", "make a file which they can load into their NEdit environment. ", "\n\n", "To load such a file, start NEdit with the command: ", "\n\n", "\01A nedit -import \n", "\01I\n", "In the new NEdit session, verify that the imported patterns or macros do what ", "you want, then select Preferences -> Save Defaults. Saving incorporates the ", "changes into the NEdit preferences file, so the next time you run NEdit, you ", "will not have to import the distribution file. ", "\n\n", "Loading a customization file is automated, but creating one is not. To ", "produce a file to be imported by other users, you must make a copy of your own ", "preferences file, and edit it, by hand, to remove everything but the ", "few items of interest to the recipient. Leave only the individual ", "resource(s), and within those resources, only the particular macro, pattern, ", "style, etc, that you wish to exchange. ", "\n\n", "For example, to share a highlighting pattern set, you would include the ", "patterns, any new styles you added, and language mode information only if the ", "patterns are intended to support a new language rather than updating an ", "existing one. For example: ", "\n\n", "\01A nedit.highlightPatterns:\\\n", " My Language:1:0{\\n\\\n", " Comment:\"#\":\"$\"::Comment::\\n\\\n", " Loop Header:\"^[ \\\\t]*loop:\":::Loop::\\n\\\n", " }\n", " nedit.languageModes: My Language:.my::::::\n", " nedit.styles: Loop:blue:Bold\n", "\01I\n", "Resources are in the format of X resource files, but the format of text ", "within multiple-item resources like highlight patterns, language modes, ", "macros, styles, etc., are private to NEdit. Each resource is a string which ", "ends at the first newline character not escaped with \\, so you must be ", "careful about how you treat ends of lines. While you can generally just cut ", "and paste indented sections, if something which was originally in the middle ", "of a resource string is now at the end, you must remove the \\ line ", "continuation character(s) so it will not join the next line into the ", "resource. Conversely, if something which was originally at the end of a ", "resource is now in the middle, you'll have to add continuation character(s) ", "to make sure that the resource string is properly continued from beginning to ", "end, and possibly newline character(s) (\\n) to make sure that it is properly ", "separated from the next item. ", NULL }; static char * htxt_resources [] = { "\01INEdit has additional options to those provided in the Preferences menu which ", "are set using X resources. Like most other X programs, NEdit can be ", "customized to vastly unnecessary proportions, from initial window positions ", "down to the font and shadow colors of each individual button (A complete ", "discussion of how to do this is left to books on the X Window System). Key ", "binding (see \"\01QKey Binding\01I\" is one of the most useful of these resource ", "settable options. ", "\n\n", "X resources are usually specified in a file called .Xdefaults or .Xresources ", "in your home directory (on VMS this is sys$login:decw$xdefaults.dat). On ", "some systems, this file is read and its information attached to the X server ", "(your screen) when you start X. On other systems, the .Xdefaults file is ", "read each time you run an X program. When X resource values are attached to ", "the X server, changes to the resource file are not available to application ", "programs until you either run the xrdb program with the appropriate file as ", "input, or re-start the X server. ", "\n\n", "\01RSelected X Resource Names\01I", "\n\n", "The following are selected NEdit resource names and default values for NEdit ", "options not settable via the Preferences menu (for preference resource names, ", "see your NEdit preference file): ", "\n\n", "\01A\01Bnedit.tagFile\01A: (not defined) \n", "\01I\n", "This can be the name of a file, or multiple files separated by a colon (:) ", "character, of the type produced by Exuberant Ctags or the Unix ctags ", "command, which NEdit will load at startup time (see \01Qctag support\01I ). The tag ", "file provides a database from which NEdit can automatically open files ", "containing the definition of a particular subroutine or data type. ", "\n\n", "\01A\01Bnedit.alwaysCheckRelativeTagsSpecs: True\01A\n", "\01I\n", "When this resource is set to True, and there are tag files specified (with ", "the nedit.tagFile resource, see above) as relative paths, NEdit will evaluate ", "these tag value paths whenever a file is opened. All accessible tag files ", "will be loaded at this time. When this resource value is False, relative path ", "tag specifications will only be evaluated at NEdit startup time. ", "\n\n", "\01A\01Bnedit.wordDelimiters\01A: .,/\\\\`'!@#%^&*()-=+{}[]\":;<>?\n", "\01I\n", "The characters, in addition to blanks and tabs, which mark the boundaries ", "between words for the move-by-word (Ctrl+Arrow) and select-word (double ", "click) commands. Note that this default value may be overridden by the ", "setting in Preferences -> Default Settings -> Language Modes.... ", "\n\n", "\01A\01Bnedit.remapDeleteKey\01A: False\n", "\01I\n", "Setting this resource to True forcibly maps the delete key to backspace. This ", "can be helpful on systems where the bindings have become tangled, and in ", "environments which mix systems with PC style keyboards and systems with DEC ", "and Macintosh keyboards. Theoretically, these bindings should be made using ", "the standard X/Motif mechanisms, outside of NEdit. In practice, some ", "environments where users access several different systems remotely, can be ", "very hard to configure. If you've given up and are using a backspace key ", "halfway off the keyboard because you can't figure out the bindings, set this ", "to True. ", "\n\n", "\01A\01Bnedit.typingHidesPointer\01A: False\n", "\01I\n", "Setting this resource to True causes the mouse pointer to be hidden when you ", "type in the text area. As soon as the mouse pointer is moved, it will ", "reappear. This is useful to stop the mouse pointer from obscuring text. ", "\n\n", "\01A\01Bnedit.overrideDefaultVirtualKeyBindings\01A: Auto\n", "\01I\n", "Motif uses a virtual key binding mechanism that shares the bindings between ", "different Motif applications. When a first Motif application is started, it ", "installs some default virtual key bindings and any other Motif application ", "that runs afterwards, simply reuses them. Obviously, if the first ", "application installs an invalid set, all others applications may have ", "problems. ", "\n\n", "In the past, NEdit has been the victim of invalid bindings installed by other ", "applications several times. Through this resource, NEdit can be instructed ", "to ignore the bindings installed by other applications, and use its own ", "private bindings. By default, NEdit tries to detect invalid bindings ", "and ignore them automatically (Auto). Optionally, NEdit can be told to ", "always keep the installed bindings (Never), or to always override them ", "(Always). ", "\n\n", "\01A\01Bnedit.stdOpenDialog\01A: False\n", "\01I\n", "Setting this resource to True restores the standard Motif style of Open ", "dialog. NEdit file open dialogs are missing a text field at the bottom of ", "the dialog, where the file name can be entered as a string. The field is ", "removed in NEdit to encourage users to type file names in the list, a ", "non-standard, but much faster method for finding files. ", "\n\n", "\01A\01Bnedit.bgMenuButton\01A: ~Shift~Ctrl~Meta~Alt\n", "\01I\n", "Specification for mouse button / key combination to post the background menu ", "(in the form of an X translation table event specification). The event ", "specification should be as specific as possible, since it will override less ", "specific translation table entries. ", "\n\n", "\01A\01Bnedit.maxPrevOpenFiles\01A: 30\n", "\01I\n", "Number of files listed in the Open Previous sub-menu of the File menu. ", "Setting this to zero disables the Open Previous menu item and maintenance of ", "the NEdit file history file. ", "\n\n", "\01A\01Bnedit.printCommand\01A: (system specific)\n", "\01I\n", "Command used by the print dialog to print a file, such as, lp, lpr, etc.. ", "The command must be capable of accepting input via stdin (standard input). ", "\n\n", "\01A\01Bnedit.printCopiesOption\01A: (system specific)\n", "\01I\n", "Option name used to specify multiple copies to the print command. If the ", "option should be separated from its argument by a space, leave a trailing ", "space. If blank, no \"Number of Copies\" item will appear in the print dialog. ", "\n\n", "\01A\01Bnedit.printQueueOption\01A: (system specific)\n", "\01I\n", "Option name used to specify a print queue to the print command. If the ", "option should be separated from its argument by a space, leave a trailing ", "space. If blank, no \"Queue\" item will appear in the print dialog. ", "\n\n", "\01A\01Bnedit.printNameOption\01A: (system specific)\n", "\01I\n", "Option name used to specify a job name to the print command. If the option ", "should be separated from its argument by a space, leave a trailing space. If ", "blank, no job or file name will be attached to the print job or banner page. ", "\n\n", "\01A\01Bnedit.printHostOption\01A: (system specific)\n", "\01I\n", "Option name used to specify a host name to the print command. If the option ", "should be separated from its argument by a space, leave a trailing space. If ", "blank, no \"Host\" item will appear in the print dialog. ", "\n\n", "\01A\01Bnedit.printDefaultQueue\01A: (system specific)\n", "\01I\n", "The name of the default print queue. Used only to display in the print ", "dialog, and has no effect on printing. ", "\n\n", "\01A\01Bnedit.printDefaultHost\01A: (system specific)\n", "\01I\n", "The node name of the default print host. Used only to display in the print ", "dialog, and has no effect on printing. ", "\n\n", "\01A\01Bnedit.visualID\01A: Best\n", "\01I\n", "If your screen supports multiple visuals (color mapping models), this ", "resource allows you to manually choose among them. The default value of ", "\"Best\" chooses the deepest (most colors) visual available. Since NEdit does ", "not depend on the specific characteristics of any given color model, Best ", "probably IS the best choice for everyone, and the only reason for setting ", "this resource would be to patch around some kind of X server problem. The ", "resource may also be set to \"Default\", which chooses the screen's default ", "visual (often a color-mapped, PseudoColor, visual for compatibility with ", "older X applications). It may also be set to a numeric visual-id value (use ", "xdpyinfo to see the list of visuals supported by your display), or a visual ", "class name: PseudoColor, DirectColor, TrueColor, etc.. ", "\n\n", "If you are running under a themed environment (like KDE or CDE) that places ", "its colors in a shallow visual, and you'd rather have that color scheme ", "instead of more colors available, then you may need set the visual to ", "\"Default\" so that NEdit doesn't choose one with more colors. (The reason ", "for this is: if the \"best\" visual is not the server's default, then NEdit ", "cannot use the colors provided by your environment. NEdit will fall back to ", "its own default color scheme.) ", "\n\n", "\01A\01Bnedit.installColormap\01A: False\n", "\01I\n", "Force the installation of a private colormap. If you have a humble 8-bit ", "color display, and netscape is hogging all of the color cells, you may want ", "to try turning this on. On most systems, this will result in colors flashing ", "wildly when you switch between NEdit and other applications. But a few ", "systems (SGI) have hardware support for multiple simultaneous colormaps, and ", "applications with installed colormaps are well behaved. ", "\n\n", "\01A\01Bnedit.findReplaceUsesSelection\01A: False\n", "\01I\n", "Controls if the Find and Replace dialogs are automatically loaded with the ", "contents of the primary selection. ", "\n\n", "\01A\01Bnedit.stickyCaseSenseButton\01A: True\n", "\01I\n", "Controls if the \"Case Sensitive\" buttons in the Find and Replace dialogs and ", "the incremental search bar maintain a separate state for literal and regular ", "expression searches. Moreover, when set to True, by default literal searches ", "are case insensitive and regular expression searches are case sensitive. When ", "set to False, the \"Case Sensitive\" buttons are independent of the \"Regular ", "Expression\" toggle. ", "\n\n", "\01A\01Bnedit.multiClickTime\01A: (system specific)\n", "\01I\n", "Maximum time in milliseconds allowed between mouse clicks within double and ", "triple click actions. ", "\n\n", "\01A\01Bnedit.undoModifiesSelection\01A: True\n", "\01I\n", "By default, NEdit selects any text inserted or changed through a undo/redo ", "action. Set this resource to False if you don't want your selection to be ", "touched. ", "\n\n", "\01A\01Bnedit*scrollBarPlacement\01A: BOTTOM_RIGHT\n", "\01I\n", "How scroll bars are placed in NEdit windows, as well as various lists and ", "text fields in the program. Other choices are: BOTTOM_LEFT, TOP_LEFT, or ", "TOP_RIGHT. ", "\n\n", "\01A\01Bnedit*text.autoWrapPastedText\01A: False\n", "\01I\n", "When Auto Newline Wrap is turned on, apply automatic wrapping (which ", "normally only applies to typed text) to pasted text as well. ", "\n\n", "\01A\01Bnedit*text.heavyCursor\01A: False\n", "\01I\n", "For monitors with poor resolution or users who have difficulty seeing the ", "cursor, makes the cursor in the text editing area of the window heavier and ", "darker. ", "\n\n", "\01A\01Bnedit.autoScrollVPadding\01A: 4\n", "\01I\n", "Number of lines to keep the cursor away from the top or bottom line of the ", "window when the \"Auto-Scroll Near Window Top/Bottom\" feature is enabled. ", "Keyboard operations that would cause the cursor to get closer than ", "this distance cause the window to scroll up or down instead, except at the ", "beginning of the file. Mouse operations are not affected. ", "\n\n", "\01A\01Bnedit*text.blinkRate\01A: 500\n", "\01I\n", "Blink rate of the text insertion cursor in milliseconds. Set to zero to stop ", "blinking. ", "\n\n", "\01A\01Bnedit*text.Translations\01A:\n", "\01I\n", "Modifies key bindings (see \"\01QKey Binding\01I\"). ", "\n\n", "\01A\01Bnedit*foreground\01A: black\n", "\01I\n", "Default foreground color for menus, dialogs, scroll bars, etc.. ", "\n\n", "\01A\01Bnedit*background\01A: #b3b3b3\n", "\01I\n", "Default background color for menus, dialogs, scroll bars, etc.. ", "\n\n", "\01A\01Bnedit*calltipForeground\01A: black\n", "\01I\n", "Foreground color for calltips ", "\n\n", "\01A\01Bnedit*calltipBackground\01A: LemonChiffon1\n", "\01I\n", "Background color for calltips ", "\n\n", "\01A\01Bnedit*XmLFolder.inactiveForeground\01A: #666\n", "\01I\n", "Foreground color for inactive tabs. ", "\n\n", "\01A\01Bnedit*fontList\01A: helvetica medium 12 points\n", "\01I\n", "Default font for menus, dialogs, scroll bars, etc.. ", "\n\n", "\01A\01Bnedit.helpFont\01A: helvetica medium 12 points\n", "\01I\n", "Font used for displaying online help. ", "\n\n", "\01A\01Bnedit.boldHelpFont\01A: helvetica bold 12 points\n", "\01I\n", "Bold font for online help. ", "\n\n", "\01A\01Bnedit.italicHelpFont\01A: helvetica italic 12 points\n", "\01I\n", "Italic font for online help. ", "\n\n", "\01A\01Bnedit.fixedHelpFont\01A: courier medium 12 points\n", "\01I\n", "Fixed font for online help. ", "\n\n", "\01A\01Bnedit.boldFixedHelpFont\01A: courier bold 12 points\n", "\01I\n", "Fixed bold for online help. ", "\n\n", "\01A\01Bnedit.italicFixedHelpFont\01A: courier italic 12 points\n", "\01I\n", "Fixed italic font for online help. ", "\n\n", "\01A\01Bnedit.h1HelpFont\01A: helvetica bold 14 points\n", "\01I\n", "Font for level-1 titles in help text. ", "\n\n", "\01A\01Bnedit.h2HelpFont\01A: helvetica bold italic 12 points\n", "\01I\n", "Font for level-2 titles in help text. ", "\n\n", "\01A\01Bnedit.h3HelpFont\01A: courier bold 12 points\n", "\01I\n", "Font for level-3 titles in help text. ", "\n\n", "\01A\01Bnedit.helpLinkFont\01A: helvetica medium 12 points\n", "\01I\n", "Font for hyperlinks in the help text ", "\n\n", "\01A\01Bnedit.helpLinkColor\01A: #009900\n", "\01I\n", "Color for hyperlinks in the help text ", "\n\n", "\01A\01Bnedit.backlightCharTypes\01A: 0-8,10-31,127:red;9:#dedede;32,160-255:#f0f0f0;128-159:orange\n", "\01I\n", "\01JNOTE: backlighting is \01Lexperimental\01J\01I (see \"\01QProgramming with NEdit\01I\"). ", "\n\n", "A string specifying character classes as ranges of ASCII values followed by ", "the color to be used as their background colors. The format is: ", "\n\n", "low[-high]{,low[-high]}:color{;low-high{,low[-high]}:color} ", "\n\n", "where low and high are ASCII values. ", "\n\n", "For example: ", "\01A 32-255:#f0f0f0;1-31,127:red;128-159:orange;9-13:#e5e5e5\n", "\01I\n", "\01A\01Bnedit.focusOnRaise\01A: False\n", "\01I\n", "This resource determines whether new text windows and text windows that are ", "raised, should also request the input focus. Conventionally, it is the task ", "of the window manager to decide on which window gets the input focus. ", "Therefore, NEdit's default behaviour is not to request the input focus ", "explicitly. ", "\n\n", "\01A\01Bnc.autoStart\01A: True \n", "\01I\n", "Whether the nc program should automatically start an NEdit server (without ", "prompting the user) if an appropriate server is not found. ", "\n\n", "\01A\01Bnc.serverCommand\01A: nedit -server\n", "\01I\n", "Command used by the nc program to start an NEdit server. ", "\n\n", "\01A\01Bnc.timeOut\01A: 10\n", "\01I\n", "Basic time-out period used in communication with an NEdit server (seconds). ", "\n\n", "\01KThe following are Selected widget names (to which you may append\01I ", "\01K.background, .foreground, .fontList, etc., to change colors, fonts\01I ", "\01K and other characteristics):\01I ", "\n\n", "\01A\01Bnedit*statsAreaForm\01A\n", "\01I\n", "Statistics line and incremental search bar. To get consistent results across ", "the entire stats line and the incremental search bar, use '*' rather than '.' ", "to separate the resource name. For example, to set the foreground color of ", "both components use: ", "\01A nedit*statsAreaForm*foreground\n", "\01Iinstead of: ", "\01A nedit*statsAreaForm.foreground\n", "\01I\n", "\01A\01Bnedit*menuBar\01A\n", "\01I\n", "Top-of-window menu-bar. ", "\n\n", "\01A\01Bnedit*textHorScrollBar\01A\n", "\01I\n", "Horizontal scroll bar. ", "\n\n", "\01A\01Bnedit*textVertScrollBar\01A\n", "\01I\n", "Vertical scroll bar. ", NULL }; static char * htxt_binding [] = { "\01IThere are several ways to change key bindings in NEdit. The easiest way to ", "add a new key binding in NEdit is to define a macro in Preferences -> Default ", "Settings -> Customize Menus -> Macro Menu. However, if you want to change ", "existing bindings or add a significant number of new key bindings you will ", "need to do so via X resources. ", "\n\n", "Before reading this section, you must understand how to set X resources (see ", "the help section \"\01QX Resources\01I\"). Since setting X resources is tricky, it is ", "also helpful when working on key-binding, to set some easier-to-verify ", "resource at the same time, as a simple check that the NEdit program is ", "actually seeing your changes. The appres program is also very helpful in ", "checking that the resource settings that you make, actually reach the program ", "for which they are intended in the correct form. ", "\n\n", "\01RKey Binding in General\01I", "\n\n", "Keyboard commands are associated with editor action routines through two ", "separate mechanisms in NEdit. Commands which appear in pull-down menus have ", "individual resources designating a keyboard equivalent to the menu command, ", "called an accelerator key. Commands which do not have an associated menu ", "item are bound to keys via the X toolkit translation mechanism. The methods ", "for changing these two kinds of bindings are quite different. ", "\n\n", "\01RKey Binding Via Translations\01I", "\n\n", "The most general way to bind actions to keys in NEdit is to use the ", "translation table associated with the text widget. To add a binding to Alt+Y ", "to insert the string \"Hi!\", for example, add lines similar to the following ", "to your X resource file: ", "\n\n", "\01A NEdit*text.Translations: #override \\n\\\n", " Alty: insert_string(\"Hi!\") \\n\n", "\01I\n", "The Help topic \"\01QAction Routines\01I\" lists the actions available to be bound. ", "\n\n", "Translation tables map key and mouse presses, window operations, and other ", "kinds of events, to actions. The syntax for translation tables is ", "simplified here, so you may need to refer to a book on the X window system ", "for more detailed information. ", "\n\n", "Note that accelerator resources (discussed below) override translations, and ", "that most Ctrl+letter and Alt+letter combinations are already bound to an ", "accelerator key. To use one of these combinations from a translation table, ", "therefore, you must first un-bind the original menu accelerator. ", "\n\n", "A resource for changing a translation table consists of a keyword; #override, ", "#augment, or #replace; followed by lines (separated by newline characters) ", "pairing events with actions. Events begin with modifiers, like Ctrl, Shift, ", "or Alt, followed by the event type in <>. BtnDown, Btn1Down, Btn2Down, ", "Btn1Up, Key, KeyUp are valid event types. For key presses, the event type is ", "followed by the name of the key. You can specify a combination of events, ", "such as a sequence of key presses, by separating them with commas. The other ", "half of the event/action pair is a set of actions. These are separated from ", "the event specification by a colon and from each other by spaces. Actions ", "are names followed by parentheses, optionally containing one or more ", "parameters separated by comas. ", "\n\n", "\01RChanging Menu Accelerator Keys\01I", "\n\n", "The menu shortcut keys shown at the right of NEdit menu items can also be ", "changed via X resources. Each menu item has two resources associated with ", "it, accelerator, the event to trigger the menu item; and acceleratorText, the ", "string shown in the menu. The form of the accelerator resource is the same ", "as events for translation table entries discussed above, though multiple keys ", "and other subtleties are not allowed. The resource name for a menu is the ", "title in lower case, followed by \"Menu\", the resource name of menu item is ", "the name in lower case, run together, with words separated by caps, and all ", "punctuation removed. For example, to change Cut to Ctrl+X, you would add the ", "following to your .Xdefaults file: ", "\n\n", "\01A nedit*editMenu.cut.accelerator: Ctrlx\n", " nedit*editMenu.cut.acceleratorText: Ctrl+X\n", "\01I\n", "Accelerator keys with optional shift key modifiers, like Find..., have an ", "additional accelerator resource with Shift appended to the name. For ", "example: ", "\n\n", "\01A nedit*searchMenu.find.acceleratorText: [Shift]Alt+F\n", " nedit*searchMenu.find.accelerator: Altf\n", " nedit*searchMenu.findShift.accelerator: Shift Altf\n", NULL }; static char * htxt_patterns [] = { "\01RWriting Syntax Highlighting Patterns\01I", "\n\n", "Patterns are the mechanism by which language syntax highlighting is ", "implemented in NEdit (see \01QSyntax Highlighting\01I under the heading of Features ", "for Programming). To create syntax highlighting patterns for a new ", "language, or to modify existing patterns, select \"Recognition Patterns\" from ", "\"Syntax Highlighting\" sub-section of the \"Default Settings\" sub-menu of the ", "\"Preferences\" menu. ", "\n\n", "First, a word of caution. As with regular expression matching in general, it ", "is quite possible to write patterns which are so inefficient that they ", "essentially lock up the editor as they recursively re-examine the entire ", "contents of the file thousands of times. With the multiplicity of patterns, ", "the possibility of a lock-up is significantly increased in syntax ", "highlighting. When working on highlighting patterns, be sure to save your ", "work frequently. ", "\n\n", "NEdit's syntax highlighting is unusual in that it works in real-time (as you ", "type), and yet is completely programmable using standard regular expression ", "notation. Other syntax highlighting editors usually fall either into the ", "category of fully programmable but unable to keep up in real-time, or ", "real-time but limited programmability. The additional burden that NEdit ", "places on pattern writers in order to achieve this speed/flexibility mix, is ", "to force them to state self-imposed limitations on the amount of context that ", "patterns may examine when re-parsing after a change. While the \"Pattern ", "Context Requirements\" heading is near the end of this section, it is not ", "optional, and must be understood before making any serious effort at ", "pattern writing. ", "\n\n", "In its simplest form, a highlight pattern consists of a regular expression to ", "match, along with a style representing the font an color for displaying any ", "text which matches that expression. To bold the word, \"highlight\", wherever ", "it appears the text, the regular expression simply would be the word ", "\"highlight\". The style (selected from the menu under the heading of ", "\"Highlight Style\") determines how the text will be drawn. To bold the text, ", "either select an existing style, such as \"Keyword\", which bolds text, or ", "create a new style and select it under Highlight Style. ", "\n\n", "The full range of regular expression capabilities can be applied in such a ", "pattern, with the single caveat that the expression must conclusively match ", "or not match, within the pre-defined context distance (as discussed below ", "under Pattern Context Requirements). ", "\n\n", "To match longer ranges of text, particularly any constructs which exceed the ", "requested context, you must use a pattern which highlights text between a ", "starting and ending regular expression match. To do so, select \"Highlight ", "text between starting and ending REs\" under \"Matching\", and enter both a ", "starting and ending regular expression. For example, to highlight everything ", "between double quotes, you would enter a double quote character in both the ", "starting and ending regular expression fields. Patterns with both a ", "beginning and ending expression span all characters between the two ", "expressions, including newlines. ", "\n\n", "Again, the limitation for automatic parsing to operate properly is that both ", "expressions must match within the context distance stated for the pattern ", "set. ", "\n\n", "With the ability to span large distances, comes the responsibility to recover ", "when things go wrong. Remember that syntax highlighting is called upon to ", "parse incorrect or incomplete syntax as often as correct syntax. To stop a ", "pattern short of matching its end expression, you can specify an error ", "expression, which stops the pattern from gobbling up more than it should. ", "For example, if the text between double quotes shouldn't contain newlines, ", "the error expression might be \"$\". As with both starting and ending ", "expressions, error expressions must also match within the requested context ", "distance. ", "\n\n", "\01SColoring Sub-Expressions\01I", "\n\n", "It is also possible to color areas of text within a regular expression ", "match. A pattern of this type associates a style with sub-expressions ", "references of the parent pattern (as used in regular expression substitution ", "patterns, see the NEdit Help menu item on Regular Expressions). ", "Sub-expressions of both the starting and ending patterns may be colored. For ", "example, if the parent pattern has a starting expression \"\\<\", and end ", "expression \"\\>\", (for highlighting all of the text contained within angle ", "brackets), a sub-pattern using \"&\" in both the starting and ending expression ", "fields could color the brackets differently from the intervening text. A ", "quick shortcut to typing in pattern names in the Parent Pattern field is to ", "use the middle mouse button to drag them from the Patterns list. ", "\n\n", "In some cases, there can be interference between coloring sub-patterns and ", "hierarchical sub-patterns (discussed next). How this is resolved, is ", "explained below. ", "\n\n", "\01SHierarchical Patterns\01I", "\n\n", "A hierarchical sub-pattern, is identical to a top level pattern, but is ", "invoked only between the starting and ending expression matches of its ", "parent pattern or, in case the parent pattern consists of a single ", "expression, inside the text area matching that expression. Like the ", "sub-expression coloring patterns discussed above, it is associated with a ", "parent pattern using the Parent Pattern field in the pattern specification. ", "Pattern names can be dragged from the pattern list with the middle mouse ", "button to the Parent Pattern field. ", "\n\n", "The matching behaviour for sub-patterns is slightly different, depending on ", "whether the parent pattern consists of a single expression or has both a ", "starting and an ending expression. ", "\n\n", "In case the parent pattern consists of a single expression, and the syntax ", "highlighting parser finds a match for that expression, sub-patterns are ", "matched between the start and the end of the parent match. Sub-patterns ", "cannot extend beyond the boundaries of the parent's match nor can they ", "affect those boundaries (the latter can happen for starting/ending parent ", "patterns, see below). Note that sub-patterns can \01Kpeek\01I beyond the ", "parent's matching boundaries by means of look-ahead or look-behind ", "expressions. ", "\n\n", "In case the parent pattern is a starting/ending style pattern, after the ", "start expression of the parent pattern matches, the syntax highlighting ", "parser searches for either the parent's end pattern or a matching ", "sub-pattern. When a sub-pattern matches, control is not returned to the ", "parent pattern until the entire sub-pattern has been parsed, regardless of ", "whether the parent's end pattern appears in the text matched by the ", "sub-pattern. In this way, matching of the parent's ending pattern can be ", "postponed, in contrast to the case where the parent pattern consists of a ", "single expression. Note that, in this case, parsing of sub-patterns starts ", "\01Jafter\01I the match of the parent pattern's starting expression, also in ", "contrast to the single-expression case. ", "\n\n", "The most common use for this capability is for coloring sub-structure of ", "language constructs (smaller patterns embedded in larger patterns). ", "Hierarchical patterns can also simplify parsing by having sub-patterns \"hide\" ", "special syntax from parent patterns, such as special escape sequences or ", "internal comments. ", "\n\n", "There is no depth limit in nesting hierarchical sub-patterns, but beyond the ", "third level of nesting, automatic re-parsing will sometimes have to re-parse ", "more than the requested context distance to guarantee a correct parse (which ", "can slow down the maximum rate at which the user can type if large sections ", "of text are matched only by deeply nested patterns). ", "\n\n", "While this is obviously not a complete hierarchical language parser it is ", "still useful in many text coloring situations. As a pattern writer, your ", "goal is not to completely cover the language syntax, but to generate ", "colorings that are useful to the programmer. Simpler patterns are usually ", "more efficient and also more robust when applied to incorrect code. ", "\n\n", "Note that in case of a single-expression parent pattern, there is a ", "potential for conflicts between coloring-only sub-patterns and hierarchical ", "sub-patterns (which cannot happen for starting/ending type of patterns, ", "because sub-patterns are matched \01Jbetween\01I the starting and ending pattern ", "(not included)). Due to the different nature of these two kinds of ", "sub-patterns, it is technically infeasible to follow the standard matching ", "precedence rules, where a sub-pattern has precedence over the sub-patterns ", "following it. Instead, coloring-only sub-patterns are always colored last, ", "ie., they may override the coloring for overlapping sibling sub-patterns in ", "the overlapping parts of the matches. ", "\n\n", "\01SDeferred (Pass-2) Parsing\01I", "\n\n", "NEdit does pattern matching for syntax highlighting in two passes. The first ", "pass is applied to the entire file when syntax highlighting is first turned ", "on, and to new ranges of text when they are initially read or pasted in. The ", "second pass is applied only as needed when text is exposed (scrolled in to ", "view). ", "\n\n", "If you have a particularly complex set of patterns, and parsing is beginning ", "to add a noticeable delay to opening files or operations which change large ", "regions of text, you can defer some of that parsing from startup time, to ", "when it is actually needed for viewing the text. Deferred parsing can only ", "be used with single expression patterns, or begin/end patterns which match ", "entirely within the requested context distance. To defer the parsing of a ", "pattern to when the text is exposed, click on the Pass-2 pattern type button ", "in the highlight patterns dialog. ", "\n\n", "Sometimes a pattern can't be deferred, not because of context requirements, ", "but because it must run concurrently with pass-1 (non-deferred) patterns. If ", "they didn't run concurrently, a pass-1 pattern might incorrectly match some ", "of the characters which would normally be hidden inside of a sequence matched ", "by the deferred pattern. For example, C has character constants enclosed in ", "single quotes. These typically do not cross line boundaries, meaning they ", "can be parsed entirely within the context distance of the C pattern set and ", "should be good candidates for deferred parsing. However, they can't be ", "deferred because they can contain sequences of characters which can trigger ", "pass-one patterns. Specifically, the sequence, '\\\"', contains a double quote ", "character, which would be matched by the string pattern and interpreted as ", "introducing a string. ", "\n\n", "\01SPattern Context Requirements\01I", "\n\n", "The context requirements of a pattern set state how much additional text ", "around any change must be examined to guarantee that the patterns will match ", "what they are intended to match. Context requirements are a promise by NEdit ", "to the pattern writer, that the regular expressions in his/her patterns will ", "be matched against at least lines and ", "characters, around any modified text. Combining line and character ", "requirements guarantee that both will be met. ", "\n\n", "Automatic re-parsing happens on EVERY KEYSTROKE, so the amount of context ", "which must be examined is very critical to typing efficiency. The more ", "complicated your patterns, the more critical the context becomes. To cover ", "all of the keywords in a typical language, without affecting the maximum rate ", "at which users can enter text, you may be limited to just a few lines and/or ", "a few hundred characters of context. ", "\n\n", "The default context distance is 1 line, with no minimum character ", "requirement. There are several benefits to sticking with this default. One ", "is simply that it is easy to understand and to comply with. Regular ", "expression notation is designed around single line matching. To span lines ", "in a regular expression, you must explicitly mention the newline character ", "\"\\n\", and matches which are restricted to a single line are virtually immune ", "to lock-ups. Also, if you can code your patterns to work within a single ", "line of context, without an additional character-range context requirement, ", "the parser can take advantage the fact that patterns don't cross line ", "boundaries, and nearly double its efficiency over a one-line and 1-character ", "context requirement. (In a single line context, you are allowed to match ", "newlines, but only as the first and/or last character.) ", NULL }; static char * htxt_smart_indent [] = { "\01ISmart indent macros can be written for any language, but are usually more ", "difficult to write than highlighting patterns. A good place to start, of ", "course, is to look at the existing macros for C and C++. ", "\n\n", "Smart indent macros for a language mode consist of standard NEdit macro ", "language code attached to any or all of the following three activation ", "conditions: 1) When smart indent is first turned on for a text window ", "containing code of the language, 2) When a newline is typed and smart indent ", "is expected, 3) after any character is typed. To attach macro code to any of ", "these code \"hooks\", enter it in the appropriate section in the Preferences -> ", "Default Settings -> Auto Indent -> Program Smart Indent dialog. ", "\n\n", "Typically most of the code should go in the initialization section, because ", "that is the appropriate place for subroutine definitions, and smart indent ", "macros are complicated enough that you are not likely to want to write them ", "as one monolithic run of code. You may also put code in the Common/Shared ", "Initialization section (accessible through the button in the upper left ", "corner of the dialog). Unfortunately, since the C/C++ macros also reside in ", "the common/shared section, when you add code there, you run some risk of ", "missing out on future upgrades to these macros, because your changes will ", "override the built-in defaults. ", "\n\n", "The newline macro is invoked after the user types a newline, but before the ", "newline is entered in the buffer. It takes a single argument ($1) which is ", "the position at which the newline will be inserted. It must return the ", "number of characters of indentation the line should have, or -1. A return ", "value of -1 means to do a standard auto-indent. You must supply a newline ", "macro, but the code: \"return -1\" (auto-indent), or \"return 0\" (no indent) is ", "sufficient. ", "\n\n", "The type-in macro takes two arguments. $1 is the insert position, and $2 is ", "the character just inserted, and does not return a value. You can do just ", "about anything here, but keep in mind that this macro is executed for every ", "keystroke typed, so if you try to get too fancy, you may degrade performance. ", NULL }; static char * htxt_command_line [] = { #ifndef VMS "\01A \01Bnedit\01A [-\01Bread\01A] [-\01Bcreate\01A] [-\01Bline\01A n | +n] [-\01Bserver\01A]\n", " [-\01Bdo\01A command] [-\01Btags\01A file] [-\01Btabs\01A n] [-\01Bwrap\01A]\n", " [-\01Bnowrap\01A] [-\01Bautowrap\01A] [-\01Bautoindent\01A] [-\01Bnoautoindent\01A]\n", " [-\01Bautosave\01A] [-\01Bnoautosave\01A] [-\01Brows\01A n] [-\01Bcolumns\01A n]\n", " [-\01Bfont\01A font] [-\01Blm\01A languagemode] [-\01Bgeometry\01A geometry]\n", " [-\01Biconic\01A] [-\01Bnoiconic\01A] [-\01Bdisplay\01A [host]:server[.screen]\n", " [-\01Bxrm\01A resourcestring] [-\01Bsvrname\01A name] [-\01Bimport\01A file]\n", " [-\01Bbackground\01A color] [-\01Bforeground\01A color] [-\01Bh\01A|-\01Bhelp\01A]\n", " [-\01Btabbed\01A] [-\01Buntabbed\01A] [-\01Bgroup\01A] [-\01BV\01A|-\01Bversion\01A]\n", " [--] [file...]\n", "\01I\n", "\01A\01B-read\01A\n", "\01IOpen the file Read Only regardless of the actual file protection. ", "\n\n", "\01A\01B-create\01A\n", "\01IDon't warn about file creation when a file doesn't exist. ", "\n\n", "\01A\01B-line n (or +n)\01A\n", "\01IGo to line number n ", "\n\n", "\01A\01B-server\01A\n", "\01IDesignate this session as an NEdit server, for processing commands from the ", "nc program. nc can be used to interface NEdit to code development ", "environments, mailers, etc., or just as a quick way to open files from the ", "shell command line without starting a new NEdit session. ", "\n\n", "\01A\01B-do command\01A\n", "\01IExecute an NEdit macro or action on the file following the -do argument on ", "the command line. -do is particularly useful from the nc program, where ", "nc -do can remotely execute commands in an NEdit -server session. ", "\n\n", "\01A\01B-tags file\01A\n", "\01ILoad a file of directions for finding definitions of program subroutines and ", "data objects. The file must be of the format generated by Exuberant Ctags, ", "or the standard Unix ctags command. ", "\n\n", "\01A\01B-tabs n\01A\n", "\01ISet tab stops every n characters. ", "\n\n", "\01A\01B-wrap, -nowrap\01A\n", "\01IWrap long lines at the right edge of the window rather than continuing them ", "past it. (Continuous Wrap mode) ", "\n\n", "\01A\01B-autowrap, -noautowrap\01A\n", "\01IWrap long lines when the cursor reaches the right edge of the window by ", "inserting newlines at word boundaries. (Auto Newline Wrap mode) ", "\n\n", "\01A\01B-autoindent, -noautoindent\01A\n", "\01IMaintain a running indent. ", "\n\n", "\01A\01B-autosave, -noautosave\01A\n", "\01IMaintain a backup copy of the file being edited under the name '~filename'. ", "\n\n", "\01A\01B-rows n\01A\n", "\01IDefault height in characters for an editing window. ", "\n\n", "\01A\01B-columns n\01A\n", "\01IDefault width in characters for an editing window. ", "\n\n", "\01A\01B-font font (or -fn font)\01A\n", "\01IFont for text being edited (Font for menus and dialogs can be set with -xrm ", "\"*fontList:font\"). ", "\n\n", "\01A\01B-lm languagemode\01A\n", "\01IInitial language mode used for editing succeeding files. ", "\n\n", "\01A\01B-geometry geometry (or -g geometry)\01A\n", "\01IThe initial size and/or location of editor windows. The argument geometry ", "has the form: ", "\n\n", "\01A [x][+|-][[+|-]]\n", "\01I\n", "where and are the desired width and height of the window, ", "and and are the distance from the edge of the screen to ", "the window, + for top or left, - for bottom or right. -geometry can be ", "specified for individual files on the command line. ", "\n\n", "\01A\01B-iconic, -noiconic\01A\n", "\01IInitial window state for succeeding files. ", "\n\n", "\01A\01B-display [host]:server[.screen]\01A\n", "\01IThe name of the X server to use. host specifies the machine, server ", "specifies the display server number, and screen specifies the screen number. ", "host or screen can be omitted and default to the local machine, and screen 0. ", "\n\n", "\01A\01B-background color (or -bg color)\01A\n", "\01IUser interface background color. (Background color for text can be set ", "separately with -xrm \"nedit.textBgColor: color\" or using the Preferences -> ", "Colors dialog). ", "\n\n", "\01A\01B-foreground color (or -fg color)\01A\n", "\01IUser interface foreground color. (Foreground color for text can be set ", "separately with -xrm \"nedit.textFgColor: color\" or using the Preferences ", "-> Colors dialog). ", "\n\n", "\01A\01B-tabbed\01A\n", "\01IOpen all subsequent files in new tabs. Resets -group option. ", "\n\n", "\01A\01B-untabbed\01A\n", "\01IOpen all subsequent files in new windows. Resets -group option. ", "\n\n", "\01A\01B-group\01A\n", "\01IOpen all subsequent files as tabs in a new window. ", "\n\n", "\01A\01B-xrm resourcestring\01A \n", "\01ISet the value of an X resource to override a default ", "value (see \"\01QCustomizing NEdit\01I\"). ", "\n\n", "\01A\01B-svrname name\01A\n", "\01IWhen starting NEdit in server mode, name the server, such that it responds to ", "requests only when nc is given a corresponding -svrname argument. By naming ", "servers, you can run several simultaneously, and direct files and commands ", "specifically to any one. Specifying a non-empty name automatically designates ", "this session as an NEdit server, as though -server were specified. ", "\n\n", "\01A\01B-import file\01A\n", "\01ILoads an additional preferences file on top of the existing defaults saved in ", "your preferences file. To incorporate macros, language modes, and highlight ", "patterns and styles written by other users, run NEdit with -import , ", "then re-save your preferences file with Preferences -> Save Defaults. ", "\n\n", "\01A\01B-version\01A\n", "\01IPrints out the NEdit version information. The -V option is synonymous. ", "\n\n", "\01A\01B-help\01A\n", "\01IPrints out the NEdit command line help. The -h option is synonymous. ", "\n\n", "\01A\01B--\01A\n", "\01ITreats all subsequent arguments as file names, even if they start with a ", "dash. This is so NEdit can access files that begin with the dash character. ", "\n\n", #else "This documentation for VMS NEdit usage should only appear in the ", "generated help code, not in any of the printed documentation. ", "Reasoning is that VMS usage is diminishing and there is a desire ", "to not clutter up the printed documentation here. ", "NEDIT [filespec[,...]] ", "\n\n", "The following qualifiers are accepted: ", "\n\n", "\01A\01B/read\01A\n", "\01IOpen the file Read Only regardless of the actual file protection. ", "\n\n", "\01A\01B/create\01A\n", "\01IDon't warn about file creation when a file doesn't exist. ", "\n\n", "\01A\01B/line=n\01A\n", "\01IGo to line #n ", "\n\n", "\01A\01B/server\01A \n", "\01IDesignate this session as an NEdit server for processing commands from the nc ", "program. The nc program can be used to interface NEdit to code development ", "environments, mailers, etc., or just as a quick way to open files from the ", "shell command line without starting a new NEdit session. ", "\n\n", "\01A\01B/do=command\01A\n", "\01IExecute an NEdit action routine. on each file following the /do argument on ", "the command line. /do is particularly useful from the nc program, where nc ", "/do can remotely execute commands in an nedit /server session. ", "\n\n", "\01A\01B/tags=file\01A\n", "\01ILoad a file of directions for finding definitions of program subroutines and ", "data objects. The file must be of the format generated by the Unix ctags ", "command. ", "\n\n", "\01A\01B/wrap, /nowrap\01A\n", "\01IWrap long lines at the right edge of the window rather than continuing them ", "past it. (Continuous Wrap mode) ", "\n\n", "\01A\01B/autowrap, /noautowrap\01A\n", "\01IWrap long lines when the cursor reaches the right edge of the window by ", "inserting newlines at word boundaries. (Auto Newline Wrap mode) ", "\n\n", "\01A\01B/autoindent, /noautoindent\01A\n", "\01IMaintain a running indent. ", "\n\n", "\01A\01B/autosave, /noautosave\01A\n", "\01IMaintain a backup copy of the file being edited under the name '_filename'. ", "\n\n", "\01A\01B/rows=n\01A\n", "\01IDefault width in characters for an editing window. ", "\n\n", "\01A\01B/columns=n\01A\n", "\01IDefault height in characters for an editing window. ", "\n\n", "\01A\01B/font=font (or /fn=font)\01A\n", "\01IFont for text being edited (Font for menus and dialogs can be set with ", "/xrm=\"*fontList:font\"). ", "\n\n", "\01A\01B/display [host]:server[.screen]\01A\n", "\01IThe name of the X server to use. host specifies the machine, server ", "specifies the display server number, and screen specifies the screen number. ", "host or screen can be omitted and default to the local machine, and screen 0. ", "\n\n", "\01A\01B/geometry=geometry (or /g=geometry)\01A\n", "\01IThe initial size and/or location of editor windows. The argument geometry ", "has the form: ", "\n\n", "\01A [x][+|-][[+|-]]\n", "\01I\n", "where and are the desired width and height of the window, ", "and and are the distance from the edge of the screen to ", "the window, + for top or left, - for bottom or right. ", "\n\n", "\01A\01B/background=color (or /bg=color)\01A\n", "\01I\n", "Background color. (background color for text can be set separately with ", "/xrm=\"nedit:textBgColor color\" or using the Preferences -> ", "Colors dialog). ", "\n\n", "\01A\01B/foreground=color (or /fg=color)\01A\n", "\01IForeground color. (foreground color for text can be set separately with ", "/xrm=\"nedit:textFgColor color\" or using the Preferences -> ", "Colors dialog). ", "\n\n", "\01A\01B/tabbed\01A\n", "\01IOpen all subsequent files in new tabs. Resets /group option. ", "\n\n", "\01A\01B/untabbed\01A\n", "\01IOpen all subsequent files in new windows. Resets /group option. ", "\n\n", "\01A\01B/group\01A\n", "\01IOpen all subsequent files as tabs in a new window. ", "\n\n", "\01A\01B/xrm=resourcestring\01A\n", "\01ISet the value of an X resource to override a default value ", "(see Customizing NEdit). ", "\n\n", "\01A\01B/svrname=name\01A\n", "\01IWhen starting nedit in server mode, name the server, such that it responds to ", "requests only when nc is given a corresponding -svrname argument. By naming ", "servers, you can run several simultaneously, and direct files and commands ", "specifically to any one. ", "\n\n", "\01A\01B/import=file\01A\n", "\01ILoads an additional preferences file on top of the existing defaults saved in ", "your .nedit file. To incorporate macros, language modes, and highlight ", "patterns and styles written by other users, run nedit with /import=, ", "then re-save your .nedit file with Preferences -> Save Defaults. ", "\n\n", "Unix-style command lines (but not file names) are also acceptable: ", "\n\n", "\01A nedit -rows 20 -wrap file1.c file2.c\n", "\01I\n", "is equivalent to: ", "\n\n", "\01A nedit /rows=20/wrap file1.c, file2.c\",\n", #endif /* VMS */ NULL }; static char * htxt_server [] = { "\01INEdit can be operated on its own, or as a two-part client/server ", "application. Client/server mode is useful for integrating NEdit with ", "software development environments, mailers, and other programs; or just as a ", "quick way to open files from the shell command line without starting a new ", "NEdit session. ", "\n\n", "To run NEdit in server mode, type: ", "\n\n", "\01A nedit -server\n", "\01I\n", "NEdit can also be started in server mode via the NEdit Client program ", "(\01Jnc\01I) when no servers are available. ", "\n\n", "The nc program, which is distributed along with NEdit, sends commands to ", "an NEdit server to open files or execute editor actions. It can also be ", "used on files that are already opened. ", "\n\n", "Listing a file on the nc command line means: Open it if it is not already ", "open and bring the window to the front. ", "\n\n", "nc supports the following command line options: ", "\n\n", "\01A \01Bnc\01A [\01B-read\01A] [\01B-create\01A]\n", " [\01B-line\01A n | \01B+\01An] [\01B-do\01A command] [\01B-lm\01A languagemode]\n", " [\01B-svrname\01A name] [\01B-svrcmd\01A command]\n", " [\01B-ask\01A] [\01B-noask\01A] [\01B-timeout\01A seconds]\n", " [\01B-geometry\01A geometry | \01B-g\01A geometry] [\01B-icon\01A | \01B-iconic\01A]\n", " [-\01Btabbed\01A] [-\01Buntabbed\01A] [-\01Bgroup\01A] [\01B-wait\01A]\n", " [\01B-V\01A | \01B-version\01A]\n", " [\01B-xrm\01A resourcestring] [\01B-display\01A [host]:server[.screen]]\n", " [\01B-\01A-] [file...]\n", "\01I\n", "\01A\01B-read\01A\n", "\01IOpen the file read-only regardless of its actual permissions. There is no ", "effect if the file is already open. ", "\n\n", "\01A\01B-create\01A\n", "\01IDon't warn about file creation when a file doesn't exist. ", "\n\n", "\01A\01B-line\01A n, \01B+\01An\n", "\01IGo to line number n. This will also affect files which are already open. ", "\n\n", "\01A\01B-do\01A command\n", "\01IExecute an NEdit macro or action on the file following the -do argument ", "on the command line. ", "\n\n", "If you use this command without a filename, nc would randomly choose one ", "window to focus and execute the macro in. ", "\n\n", "\01A\01B-ask\01A, \01B-noask\01A\n", "\01IInstructs nc to automatically start a server if one is not available. This ", "overrides the X resource `nc.autoStart' (see \01QX Resources\01I). ", "\n\n", "\01A\01B-svrname\01A name\n", "\01IExplicitly instructs nc which server to connect to, an instance of ", "nedit(1) with a corresponding -svrname argument. By naming servers, you ", "can run several simultaneously, and direct files and commands ", "specifically to any one. ", "\n\n", "\01A\01B-svrcmd\01A command\n", "\01IThe command which nc uses to start an NEdit server. It is also settable ", "via the X resource `nc.serverCommand' (see \01QX Resources\01I). Defaults to ", "\"nedit -server\". ", "\n\n", "\01A\01B-lm\01A languagemode\n", "\01IInitial language mode used. ", "\n\n", "\01A\01B-geometry\01A geometry, \01B-g\01A geometry\n", "\01IThe initial size and/or location of editor windows. See ", "\01QNEdit Command Line\01I for details. ", "\n\n", "\01A\01B-icon\01A, \01B-iconic\01A\n", "\01IInitial window state. ", "\n\n", "\01A\01B-display\01A []:[.]\n", "\01IThe name of the X server to use. See \01QNEdit Command Line\01I for details. ", "\n\n", "\01A\01B-timeout\01A seconds\n", "\01IBasic time-out period used in communication with an NEdit server. The ", "default is 10 seconds. Also settable via the X resource `nc.timeOut'. ", "\n\n", "Under rare conditions (such as a slow connection), it may be necessary to ", "increase the time-out period. In most cases, the default is fine. ", "\n\n", "\01A\01B-tabbed\01A\n", "\01IOpen all subsequent files in new tabs. Resets -group option. ", "\n\n", "\01A\01B-untabbed\01A\n", "\01IOpen all subsequent files in new windows. Resets -group option. ", "\n\n", "\01A\01B-group\01A\n", "\01IOpen all subsequent files as tabs in a new window. ", "\n\n", "\01A\01B-wait\01A\n", "\01IInstructs nc not to return to the shell until all files given are closed. ", "\n\n", "Normally, nc returns once the files given in its command line are opened ", "by the server. When this option is given, nc returns only after the last ", "file given in this call is closed. ", "\n\n", "Note that this option affects all files in the command line, not only the ", "ones following this option. ", "\n\n", "Note that nc will wait for all files given in the command line, even if ", "the files were already opened. ", "\n\n", "\01SCommand Line Arguments\01I", "\n\n", "In typical Unix style, arguments affect the files which follow them on the ", "command line, for example: ", "\n\n", "\01A incorrect: nc file.c -line 25\n", " correct: nc -line 25 file.c\n", "\01I\n", "-read, -create, and -line affect all of the files which follow them on the ", "command line. ", "\n\n", "The -do macro is executed only once, on the next file on the line. -do ", "without a file following it on the command line, executes the macro on the ", "first available window (presumably when you give a -do command without a ", "corresponding file or window, you intend it to do something independent of ", "the window in which it happens to execute). ", "\n\n", "The -wait option affects all files named in the command line. ", "\n\n", "\01SMultiple Servers\01I", "\n\n", "Sometimes it is useful to have more than one NEdit server running, for ", "example to keep mail and programming work separate. The option, -svrname, to ", "both nedit and nc, allows you to start, and communicate with, separate named ", "servers. A named server responds only to requests with the corresponding ", "-svrname argument. If you use ClearCase and are within a ClearCase view, the ", "server name will default to the name of the view (based on the value of the ", "CLEARCASE_ROOT environment variable). ", "\n\n", "\01SCommunication\01I", "\n\n", "Communication between nc and nedit is done through the X display. So as long ", "as the X Window System is set up and working properly, nc will work properly ", "as well. nc uses the DISPLAY environment variable, the machine name and your ", "user name to find the appropriate server, meaning, if you have several ", "machines sharing a common file system, nc will not be able to find a server ", "that is running on a machine with a different host name, even though it may ", "be perfectly appropriate for editing a given file. ", "\n\n", "The command which nc uses to start an nedit server is settable via the X ", "resource nc.serverCommand, by default, \"nedit -server\". ", NULL }; static char * htxt_recovery [] = { "\01IIf a system crash, network failure, X server crash, or program error should ", "happen while you are editing a file, you can still recover most of your ", "work. NEdit maintains a backup file which it updates periodically (every 8 ", "editing operations or 80 characters typed). This file has the same name ", "as the file that you are editing, but with the character `~' (tilde) on Unix ", "or `_' (underscore) on VMS prefixed to the name. To recover a file after a ", "crash, simply rename the file to remove the tilde or underscore character, ", "replacing the older version of the file. (Because several of the Unix shells ", "consider the tilde to be a special character, you may have to prefix the ", "character with a `\\' (backslash) when you move or delete an NEdit backup ", "file.) ", "\n\n", "Example, to recover the file called \"help.c\" on Unix type the command: ", "\n\n", "\01A mv \\~help.c help.c\n", "\01I\n", "A minor caveat, is that if the file you were editing was in MS DOS format, ", "the backup file will be in Unix format, and you will need to open the backup ", "file in NEdit and change the file format back to MS DOS via the Save As... ", "dialog (or use the Unix unix2dos command outside of NEdit). ", NULL }; static char * htxt_version [] = { "\01A%s\n", "\01I\n", "NEdit was written by Mark Edel, Joy Kyriakopulos, Christopher Conrad, ", "Jim Clark, Arnulfo Zepeda-Navratil, Suresh Ravoor, Tony Balinski, Max ", "Vohlken, Yunliang Yu, Donna Reid, Arne Førlie, Eddy De Greef, Steve ", "LoBasso, Alexander Mai, Scott Tringali, Thorsten Haude, Steve Haehn, ", "Andrew Hood, Nathaniel Gray, and TK Soh. ", "\n\n", "The regular expression matching routines used in NEdit are adapted (with ", "permission) from original code written by Henry Spencer at the ", "University of Toronto. ", "\n\n", "The Microline widgets are inherited from the Mozilla project. ", "\n\n", "Syntax highlighting patterns and smart indent macros were contributed by: ", "Simon T. MacDonald, Maurice Leysens, Matt Majka, Alfred Smeenk, ", "Alain Fargues, Christopher Conrad, Scott Markinson, Konrad Bernloehr, ", "Ivan Herman, Patrice Venant, Christian Denat, Philippe Couton, ", "Max Vohlken, Markus Schwarzenberg, Himanshu Gohel, Steven C. Kapp, ", "Michael Turomsha, John Fieber, Chris Ross, Nathaniel Gray, Joachim Lous, ", "Mike Duigou, Seak Teng-Fong, Joor Loohuis, Mark Jones, ", "and Niek van den Berg. ", "\n\n", "NEdit sources, executables, additional documentation, and contributed ", "software are available from the NEdit web site at http://www.nedit.org. ", "\n\n", "This program is free software; you can redistribute it and/or ", "modify it under the terms of the \01QGNU General Public License\01I ", "as published by the Free Software Foundation; either version 2 ", "of the License, or (at your option) any later version. ", "\n\n", "In addition, as a special exception to the GNU GPL, the copyright holders ", "give permission to link the code of this program with the Motif and Open ", "Motif libraries (or with modified versions of these that use the same ", "license), and distribute linked combinations including the two. You must ", "obey the GNU General Public License in all respects for all of the code ", "used other than linking with Motif/Open Motif. If you modify this file, ", "you may extend this exception to your version of the file, but you are ", "not obligated to do so. If you do not wish to do so, delete this ", "exception statement from your version. ", "\n\n", "This program is distributed in the hope that it will be useful, ", "but WITHOUT ANY WARRANTY; without even the implied warranty of ", "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ", "section on the \01QGNU General Public License\01I for more details. ", NULL }; static char * htxt_distribution [] = { "\01IGNU GENERAL PUBLIC LICENSE ", "\n\n", "Version 2, June 1991 ", "\n\n", "Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, ", "Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute ", "verbatim copies of this license document, but changing it is not allowed. ", "\n\n", "Preamble ", "\n\n", "The licenses for most software are designed to take away your freedom to ", "share and change it. By contrast, the GNU General Public License is intended ", "to guarantee your freedom to share and change free software--to make sure the ", "software is free for all its users. This General Public License applies to ", "most of the Free Software Foundation's software and to any other program ", "whose authors commit to using it. (Some other Free Software Foundation ", "software is covered by the GNU Library General Public License instead.) You ", "can apply it to your programs, too. ", "\n\n", "When we speak of free software, we are referring to freedom, not price. Our ", "General Public Licenses are designed to make sure that you have the freedom ", "to distribute copies of free software (and charge for this service if you ", "wish), that you receive source code or can get it if you want it, that you ", "can change the software or use pieces of it in new free programs; and that ", "you know you can do these things. ", "\n\n", "To protect your rights, we need to make restrictions that forbid anyone to ", "deny you these rights or to ask you to surrender the rights. These ", "restrictions translate to certain responsibilities for you if you distribute ", "copies of the software, or if you modify it. ", "\n\n", "For example, if you distribute copies of such a program, whether gratis or ", "for a fee, you must give the recipients all the rights that you have. You ", "must make sure that they, too, receive or can get the source code. And you ", "must show them these terms so they know their rights. ", "\n\n", "We protect your rights with two steps: (1) copyright the software, and (2) ", "offer you this license which gives you legal permission to copy, distribute ", "and/or modify the software. ", "\n\n", "Also, for each author's protection and ours, we want to make certain that ", "everyone understands that there is no warranty for this free software. If the ", "software is modified by someone else and passed on, we want its recipients to ", "know that what they have is not the original, so that any problems introduced ", "by others will not reflect on the original authors' reputations. ", "\n\n", "Finally, any free program is threatened constantly by software patents. We ", "wish to avoid the danger that redistributors of a free program will ", "individually obtain patent licenses, in effect making the program ", "proprietary. To prevent this, we have made it clear that any patent must be ", "licensed for everyone's free use or not licensed at all. ", "\n\n", "The precise terms and conditions for copying, distribution and modification ", "follow. ", "\n\n", "GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND ", "MODIFICATION ", "\n\n", "0. This License applies to any program or other work which contains a notice ", "placed by the copyright holder saying it may be distributed under the terms ", "of this General Public License. The \"Program\", below, refers to any such ", "program or work, and a \"work based on the Program\" means either the Program ", "or any derivative work under copyright law: that is to say, a work containing ", "the Program or a portion of it, either verbatim or with modifications and/or ", "translated into another language. (Hereinafter, translation is included ", "without limitation in the term \"modification\".) Each licensee is addressed as ", "\"you\". ", "\n\n", "Activities other than copying, distribution and modification are not covered ", "by this License; they are outside its scope. The act of running the Program ", "is not restricted, and the output from the Program is covered only if its ", "contents constitute a work based on the Program (independent of having been ", "made by running the Program). Whether that is true depends on what the ", "Program does. ", "\n\n", "1. You may copy and distribute verbatim copies of the Program's source code ", "as you receive it, in any medium, provided that you conspicuously and ", "appropriately publish on each copy an appropriate copyright notice and ", "disclaimer of warranty; keep intact all the notices that refer to this ", "License and to the absence of any warranty; and give any other recipients of ", "the Program a copy of this License along with the Program. ", "\n\n", "You may charge a fee for the physical act of transferring a copy, and you may ", "at your option offer warranty protection in exchange for a fee. ", "\n\n", "2. You may modify your copy or copies of the Program or any portion of it, ", "thus forming a work based on the Program, and copy and distribute such ", "modifications or work under the terms of Section 1 above, provided that you ", "also meet all of these conditions: ", "\n\n", "a) You must cause the modified files to carry prominent notices stating ", "that you changed the files and the date of any change. ", "\n\n", "b) You must cause any work that you distribute or publish, that in whole or ", "in part contains or is derived from the Program or any part thereof, to be ", "licensed as a whole at no charge to all third parties under the terms of ", "this License. ", "\n\n", "c) If the modified program normally reads commands interactively when run, ", "you must cause it, when started running for such interactive use in the ", "most ordinary way, to print or display an announcement including an ", "appropriate copyright notice and a notice that there is no warranty (or ", "else, saying that you provide a warranty) and that users may redistribute ", "the program under these conditions, and telling the user how to view a copy ", "of this License. (Exception: if the Program itself is interactive but does ", "not normally print such an announcement, your work based on the Program is ", "not required to print an announcement.) ", "\n\n", "These requirements apply to the modified work as a whole. If identifiable ", "sections of that work are not derived from the Program, and can be reasonably ", "considered independent and separate works in themselves, then this License, ", "and its terms, do not apply to those sections when you distribute them as ", "separate works. But when you distribute the same sections as part of a whole ", "which is a work based on the Program, the distribution of the whole must be ", "on the terms of this License, whose permissions for other licensees extend to ", "the entire whole, and thus to each and every part regardless of who wrote it. ", "\n\n", "Thus, it is not the intent of this section to claim rights or contest your ", "rights to work written entirely by you; rather, the intent is to exercise the ", "right to control the distribution of derivative or collective works based on ", "the Program. ", "\n\n", "In addition, mere aggregation of another work not based on the Program with ", "the Program (or with a work based on the Program) on a volume of a storage or ", "distribution medium does not bring the other work under the scope of this ", "License. ", "\n\n", "3. You may copy and distribute the Program (or a work based on it, under ", "Section 2) in object code or executable form under the terms of Sections 1 ", "and 2 above provided that you also do one of the following: ", "\n\n", "a) Accompany it with the complete corresponding machine-readable source ", "code, which must be distributed under the terms of Sections 1 and 2 above ", "on a medium customarily used for software interchange; or, ", "\n\n", "b) Accompany it with a written offer, valid for at least three years, to ", "give any third party, for a charge no more than your cost of physically ", "performing source distribution, a complete machine-readable copy of the ", "corresponding source code, to be distributed under the terms of Sections 1 ", "and 2 above on a medium customarily used for software interchange; or, ", "\n\n", "c) Accompany it with the information you received as to the offer to ", "distribute corresponding source code. (This alternative is allowed only for ", "noncommercial distribution and only if you received the program in object ", "code or executable form with such an offer, in accord with Subsection b ", "above.) ", "\n\n", "The source code for a work means the preferred form of the work for making ", "modifications to it. For an executable work, complete source code means all ", "the source code for all modules it contains, plus any associated interface ", "definition files, plus the scripts used to control compilation and ", "installation of the executable. However, as a special exception, the source ", "code distributed need not include anything that is normally distributed (in ", "either source or binary form) with the major components (compiler, kernel, ", "and so on) of the operating system on which the executable runs, unless that ", "component itself accompanies the executable. ", "\n\n", "If distribution of executable or object code is made by offering access to ", "copy from a designated place, then offering equivalent access to copy the ", "source code from the same place counts as distribution of the source code, ", "even though third parties are not compelled to copy the source along with the ", "object code. ", "\n\n", "4. You may not copy, modify, sublicense, or distribute the Program except as ", "expressly provided under this License. Any attempt otherwise to copy, modify, ", "sublicense or distribute the Program is void, and will automatically ", "terminate your rights under this License. However, parties who have received ", "copies, or rights, from you under this License will not have their licenses ", "terminated so long as such parties remain in full compliance. ", "\n\n", "5. You are not required to accept this License, since you have not signed it. ", "However, nothing else grants you permission to modify or distribute the ", "Program or its derivative works. These actions are prohibited by law if you ", "do not accept this License. Therefore, by modifying or distributing the ", "Program (or any work based on the Program), you indicate your acceptance of ", "this License to do so, and all its terms and conditions for copying, ", "distributing or modifying the Program or works based on it. ", "\n\n", "6. Each time you redistribute the Program (or any work based on the Program), ", "the recipient automatically receives a license from the original licensor to ", "copy, distribute or modify the Program subject to these terms and conditions. ", "You may not impose any further restrictions on the recipients' exercise of ", "the rights granted herein. You are not responsible for enforcing compliance ", "by third parties to this License. ", "\n\n", "7. If, as a consequence of a court judgment or allegation of patent ", "infringement or for any other reason (not limited to patent issues), ", "conditions are imposed on you (whether by court order, agreement or ", "otherwise) that contradict the conditions of this License, they do not excuse ", "you from the conditions of this License. If you cannot distribute so as to ", "satisfy simultaneously your obligations under this License and any other ", "pertinent obligations, then as a consequence you may not distribute the ", "Program at all. For example, if a patent license would not permit ", "royalty-free redistribution of the Program by all those who receive copies ", "directly or indirectly through you, then the only way you could satisfy both ", "it and this License would be to refrain entirely from distribution of the ", "Program. ", "\n\n", "If any portion of this section is held invalid or unenforceable under any ", "particular circumstance, the balance of the section is intended to apply and ", "the section as a whole is intended to apply in other circumstances. ", "\n\n", "It is not the purpose of this section to induce you to infringe any patents ", "or other property right claims or to contest validity of any such claims; ", "this section has the sole purpose of protecting the integrity of the free ", "software distribution system, which is implemented by public license ", "practices. Many people have made generous contributions to the wide range of ", "software distributed through that system in reliance on consistent ", "application of that system; it is up to the author/donor to decide if he or ", "she is willing to distribute software through any other system and a licensee ", "cannot impose that choice. ", "\n\n", "This section is intended to make thoroughly clear what is believed to be a ", "consequence of the rest of this License. ", "\n\n", "8. If the distribution and/or use of the Program is restricted in certain ", "countries either by patents or by copyrighted interfaces, the original ", "copyright holder who places the Program under this License may add an ", "explicit geographical distribution limitation excluding those countries, so ", "that distribution is permitted only in or among countries not thus excluded. ", "In such case, this License incorporates the limitation as if written in the ", "body of this License. ", "\n\n", "9. The Free Software Foundation may publish revised and/or new versions of ", "the General Public License from time to time. Such new versions will be ", "similar in spirit to the present version, but may differ in detail to address ", "new problems or concerns. ", "\n\n", "Each version is given a distinguishing version number. If the Program ", "specifies a version number of this License which applies to it and \"any later ", "version\", you have the option of following the terms and conditions either of ", "that version or of any later version published by the Free Software ", "Foundation. If the Program does not specify a version number of this License, ", "you may choose any version ever published by the Free Software Foundation. ", "\n\n", "10. If you wish to incorporate parts of the Program into other free programs ", "whose distribution conditions are different, write to the author to ask for ", "permission. For software which is copyrighted by the Free Software ", "Foundation, write to the Free Software Foundation; we sometimes make ", "exceptions for this. Our decision will be guided by the two goals of ", "preserving the free status of all derivatives of our free software and of ", "promoting the sharing and reuse of software generally. ", "\n\n", "\01JNO WARRANTY\01I ", "\n\n", "11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR ", "THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE ", "STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE ", "PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, ", "INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND ", "FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND ", "PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, ", "YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. ", "\n\n", "12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING ", "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR ", "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, ", "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING ", "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO ", "LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR ", "THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER ", "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE ", "POSSIBILITY OF SUCH DAMAGES. ", "\n\n", "END OF TERMS AND CONDITIONS ", NULL }; static char * htxt_mailing_list [] = { "\01IThere are two separate mailing lists for nedit users, and one for developers. ", "Users may post to the developer mailing list to report defects and communicate ", "with the nedit developers. Remember that nedit is entirely a volunteer ", "effort, so please ask questions first to the discussion list, and do your ", "share to answer other users questions as well. ", "\n\n", "\01A discuss@nedit.org\n", "\01I\n", "General discussion, questions and answers among NEdit users and developers. ", "\n\n", "\01A announce@nedit.org\n", "\01I\n", "A low-volume mailing list for announcing new versions. ", "\n\n", "\01A develop@nedit.org\n", "\01I\n", "Communication among and with NEdit developers. ", "Developers should also subscribe to the discuss list. ", "\n\n", "To subscribe, send mail to one of the following addresses: ", "\n\n", "\01A announce-request@nedit.org\n", " discuss-request@nedit.org\n", " develop-request@nedit.org\n", "\01I\n", "with the body consisting of the single word ", "\n\n", "\01A subscribe\n", NULL }; static char * htxt_defects [] = { "\01RSolutions to Common Problems\01I", "\n\n", "For a much more comprehensive list of common problems and solutions, see the ", "NEdit FAQ. The latest version of the FAQ can always be found on the NEdit ", "web site at: ", "\n\n", "\01A http://www.nedit.org.\n", "\01I\n", "\01JP: No files are shown in the \"Files\" list in the Open... dialog.\01I ", "\n\n", "S: When you use the \"Filter\" field, include the file specification or a ", "complete directory specification, including the trailing \"/\" on Unix. ", "(See Help in the Open... dialog). ", "\n\n", "\01JP: Find Again and Replace Again don't continue in the same direction as the original Find or Replace.\01I ", "\n\n", "S: Find Again and Replace Again don't use the direction of the original ", "search. The Shift key controls the direction: Ctrl+G means forward, ", "Shift+Ctrl+G means backward. ", "\n\n", "\01JP: Preferences specified in the Preferences menu don't seem to get saved when I select Save Defaults.\01I ", "\n\n", "S: NEdit has two kinds of preferences: 1) per-window preferences, in the ", "Preferences menu, and 2) default settings for preferences in newly created ", "windows, in the Default Settings sub-menu of the Preferences menu. ", "Per-window preferences are not saved by Save Defaults, only Default ", "Settings. ", "\n\n", "\01JP: Columns and indentation don't line up.\01I ", "\n\n", "S: NEdit is using a proportional width font. Set the font to a fixed style ", "(see Preferences menu). ", "\n\n", "\01JP: NEdit performs poorly on very large files.\01I ", "\n\n", "S: Turn off Incremental Backup. With Incremental Backup on, NEdit ", "periodically writes a full copy of the file to disk. ", "\n\n", "\01JP: Commands added to the Shell Commands menu (Unix only) don't output anything until they are finished executing.\01I ", "\n\n", "S: If the command output is directed to a dialog, or the input is from a ", "selection, output is collected together and held until the command ", "completes. De-select both of the options and the output will be shown ", "incrementally as the command executes. ", "\n\n", "\01JP: Dialogs don't automatically get keyboard focus when they pop up.\01I ", "\n\n", "S: Most X Window managers allow you to choose between two categories of ", "keyboard focus models: pointer focus, and explicit focus. Pointer focus ", "means that as you move the mouse around the screen, the window under the ", "mouse automatically gets the keyboard focus. NEdit users who use this ", "focus model should set \"Popups Under Pointer\" in the Default Settings sub ", "menu of the preferences menu in NEdit. Users with the explicit focus ", "model, in some cases, may have problems with certain dialogs, such as Find ", "and Replace. In MWM this is caused by the mwm resource startupKeyFocus ", "being set to False (generally a bad choice for explicit focus users). ", "NCDwm users should use the focus model \"click\" instead of \"explicit\", ", "again, unless you have set it that way to correct specific problems, this ", "is the appropriate setting for most explicit focus users. ", "\n\n", "\01JP: The Backspace key doesn't work, or deletes forward rather than backward.\01I ", "\n\n", "S: While this is an X/Motif binding problem, and should be solved outside of ", "NEdit in the Motif virtual binding layer (or possibly xmodmap or ", "translations), NEdit provides an out. If you set the resource: ", "nedit.remapDeleteKey to True, NEdit will forcibly map the delete key to ", "backspace. The default setting of this resource recently changed, so ", "users who have been depending on this remapping will now have to set it ", "explicitly (or fix their bindings). ", "\n\n", "\01JP: NEdit crashes when I try to paste text in to a text field in a dialog (like Find or Replace) on my SunOS system.\01I ", "\n\n", "S: On many SunOS systems, you have to set up an nls directory before various ", "inter-client communication features of Motif will function properly. ", "There are instructions in README.sun in /pub/v5_0_2/individual/README.sun on ", "ftp.nedit.org, as well as a tar file containing a complete nls ", "directory: ftp://ftp.nedit.org/pub/v5_0_2/nls.tar. ", "README.sun contains directions for setting up an nls directory, which ", "is required by Motif for handling copy and paste to Motif text fields. ", "\n\n", "\01RKnown Defects\01I", "\n\n", "Below is the list of known defects which affect NEdit. The defects your copy ", "of NEdit will exhibit depend on which system you are running and with which ", "Motif libraries it was built. Note that there are now Motif 1.2 and/or 2.0 ", "libraries available on ALL supported platforms, and as you can see below ", "there are far fewer defects in Motif 1.2, so it is in your best interest to ", "upgrade your system. ", "\n\n", "\01SAll Versions\01I", "\n\n", "\01A\01BDEFECT\01A\n", "\01IOperations between rectangular selections on overlapping lines do nothing. ", "\n\n", "\01A\01CWork Around\01A\n", "\01INone. These operations are very complicated and rarely used. ", "\n\n", "\01A\01BDEFECT\01A\n", "\01ICut and Paste menu items fail, or possibly crash, ", "for very large (multi-megabyte) selections. ", "\n\n", "\01A\01CWork Around\01A\n", "\01IUse selection copy (middle mouse button click) ", "for transferring larger quantities of data. ", "Cut and Paste save the copied text in server ", "memory, which is usually limited. ", "\n\n", "\01RReporting Defects\01I", "\n\n", "Submit bugs through the web at: ", "\n\n", "\01A http://sf.net/tracker/?func=add&group_id=11005&atid=111005\n", "\01I\n", "Please include the first few lines from Help > Version, which identifies ", "NEdit's version and other system attributes important for diagnosing your ", "problem. ", "\n\n", "The NEdit developers subscribe to both discuss@nedit.org and ", "develop@nedit.org, either of which may be used for reporting defects. If ", "you're not sure, or you think the report might be of interest to the general ", "NEdit user community, send the report to discuss@nedit.org. If it's ", "something obvious and boring, like we misspelled \"anemometer\" in the on-line ", "help, send it to develop@nedit.org. If you don't want to subscribe to the ", "\01QMailing Lists\01I, please add a note to your mail about cc'ing you on responses. ", NULL }; static char * htxt_tabs_dialog [] = { "\01IThe Tabs dialog controls both the operation of the Tab key, and ", "the interpretation of tab characters within a file. ", "\n\n", "The first field, Tab Spacing, controls how NEdit responds to ", "tab characters in a file. On most Unix and VMS systems the ", "conventional interpretation of a tab character is to advance the ", "text position to the nearest multiple of eight characters (a tab ", "spacing of 8). However, many programmers of C and other ", "structured languages, when given the choice, prefer a tab ", "spacing of 3 or 4 characters. Setting a three or four character ", "hardware tab spacing is useful and convenient as long as your ", "other software tools support it. Unfortunately, on Unix and VMS ", "systems, system utilities, such as more, and printing software ", "can't always properly display files with other than eight ", "character tabs. ", "\n\n", "Selecting \"Emulate Tabs\" will cause the Tab key to insert the ", "correct number of spaces or tabs to reach the next tab stop, as ", "if the tab spacing were set at the value in the \"Emulated tab ", "spacing\" field. Backspacing immediately after entering an ", "emulated tab will delete it as a unit, but as soon as you move ", "the cursor away from the spot, NEdit will forget that the ", "collection of spaces and tabs is a tab, and will treat it as ", "separate characters. To enter a real tab character with ", "\"Emulate Tabs\" turned on, use Ctrl+Tab. ", "\n\n", "In generating emulated tabs, and in Shift Left, Paste Column, ", "and some rectangular selection operations, NEdit inserts blank ", "characters (spaces or tabs) to preserve the alignment of ", "non-blank characters. The bottom toggle button in the Tabs ", "dialog instructs NEdit whether to insert tab characters as ", "padding in such situations. Turning this off, will keep NEdit ", "from automatically inserting tabs. Some software developers ", "prefer to keep their source code free of tabs to avoid its ", "misinterpretation on systems with different tab character ", "conventions. ", NULL }; static char * htxt_custom_title_dialog [] = { "\01IThe Customize Window Title dialog allows you to customize ", "and test the way information will be displayed in each window's ", "title field. ", "\n\n", "\01JDefinition of the title\01I ", "\n\n", "The upper half of the dialog can be used to select the various ", "components that should be displayed in the title. The layout can be ", "fine-tuned by editing the printf() like format string below the ", "component buttons: additional characters can be entered, or the ", "order can be changed. ", "\n\n", "The following sequences are interpreted in the format string: ", "\n\n", "\01A %c ClearCase view tag (only relevant when NEdit is \n", " used together with ClearCase)\n", " %[n]d directory, with one optional numeric digit n \n", " specifying the maximum number of trailing directory \n", " components to display. Skipped components are \n", " replaced by an ellipsis (...).\n", " %f file name, without the path name\n", " %h host name\n", " %s NEdit server name (server mode only)\n", " %[*]S file status, either verbose (%S) or brief (%*S).\n", " In verbose mode the file status is spelled out: \n", " read-only, locked, and modified. In brief mode, \n", " abbreviations and an asterisk are used for the \n", " respective states: RO, LO, *.\n", " %u user name\n", "\01I\n", "The format string and the component buttons are continously synchronized. ", "\n\n", "The default format is: ", "\n\n", "\01A {%c} [%s] %f (%S) - %d\n", "\01I\n", "The resulting title will only contain elements with ", "a value. Hence, the title is compressed as follows: ", "\n\n", "\01A * Elements with no value are removed. \n", "\01I\n", "\01A * Empty parenthesis pairs i.e. (), [] or {}, or parenthesis\n", " pairs containing only space(s), are removed.\n", "\01I\n", "\01A * Sequences of spaces are replaced with one space.\n", "\01I\n", "\01A * Leading spaces and dashes are removed. \n", "\01I\n", "\01A * Trailing spaces and dashes are removed. \n", "\01I\n", "If the server name and the ClearCase view tag are identical, only ", "the first one specified in the format string will be displayed. ", "\n\n", "\01JPreviewing the settings\01I ", "\n\n", "The lower part of the dialog can be used to test the selected title ", "under various conditions. For some of the components that are selected ", "for display, various states can be enforced on the preview. ", "\n\n", "For instance, components that are not always active (such the ", "NEdit server name) can be turned on or off in the preview. ", "\n\n", NULL }; static char **HelpText[] = { htxt_start, htxt_select, htxt_search, htxt_clipboard, htxt_mouse, htxt_keyboard, htxt_fill, htxt_interface, htxt_format, htxt_programmer, htxt_tabs, htxt_indent, htxt_syntax, htxt_tags, htxt_calltips, htxt_basicSyntax, htxt_escapeSequences, htxt_parenConstructs, htxt_advancedTopics, htxt_examples, htxt_shell, htxt_learn, htxt_macro_lang, htxt_macro_subrs, htxt_rangeset, htxt_hiliteInfo, htxt_actions, htxt_customize, htxt_preferences, htxt_resources, htxt_binding, htxt_patterns, htxt_smart_indent, htxt_command_line, htxt_server, htxt_recovery, htxt_version, htxt_distribution, htxt_mailing_list, htxt_defects, htxt_tabs_dialog, htxt_custom_title_dialog }; HelpMenu H_M [] = { { &H_M[ 1], 1, HELP_START, "start", 0, 'G', NULL }, { &H_M[ 2], 1, HELP_none, "basicOp", 0, 'B', "Basic Operation" }, { &H_M[ 3], 2, HELP_SELECT, "select", 0, 'S', NULL }, { &H_M[ 4], 2, HELP_SEARCH, "search", 0, 'F', NULL }, { &H_M[ 5], 2, HELP_CLIPBOARD, "clipboard", 0, 'C', NULL }, { &H_M[ 6], 2, HELP_MOUSE, "mouse", 0, 'U', NULL }, { &H_M[ 7], 2, HELP_KEYBOARD, "keyboard", 0, 'K', NULL }, { &H_M[ 8], 2, HELP_FILL, "fill", 0, 'h', NULL }, { &H_M[ 9], 2, HELP_INTERFACE, "interface", 0, 'T', NULL }, { &H_M[10], 2, HELP_FORMAT, "format", 0, 'i', NULL }, { &H_M[11], 1, HELP_none, "features", 0, 'F', "Features for Programming" }, { &H_M[12], 2, HELP_PROGRAMMER, "programmer", 0, 'P', NULL }, { &H_M[13], 2, HELP_TABS, "tabs", 0, 'T', NULL }, { &H_M[14], 2, HELP_INDENT, "indent", 0, 'A', NULL }, { &H_M[15], 2, HELP_SYNTAX, "syntax", 0, 'S', NULL }, { &H_M[16], 2, HELP_TAGS, "tags", 0, 'F', NULL }, { &H_M[17], 2, HELP_CALLTIPS, "calltips", 0, 'C', NULL }, { &H_M[18], 1, HELP_none, "regex", 0, 'R', "Regular Expressions" }, { &H_M[19], 2, HELP_BASICSYNTAX, "basicSyntax", 0, 'B', NULL }, { &H_M[20], 2, HELP_ESCAPESEQUENCES, "escapeSequences", 0, 'M', NULL }, { &H_M[21], 2, HELP_PARENCONSTRUCTS, "parenConstructs", 0, 'P', NULL }, { &H_M[22], 2, HELP_ADVANCEDTOPICS, "advancedTopics", 0, 'A', NULL }, { &H_M[23], 2, HELP_EXAMPLES, "examples", 0, 'E', NULL }, { &H_M[24], 1, HELP_none, "extensions", 0, 'M', "Macro/Shell Extensions" }, { &H_M[25], 2, HELP_SHELL, "shell", 1, 'S', NULL }, { &H_M[26], 2, HELP_LEARN, "learn", 0, 'L', NULL }, { &H_M[27], 2, HELP_MACRO_LANG, "macro_lang", 0, 'M', NULL }, { &H_M[28], 2, HELP_MACRO_SUBRS, "macro_subrs", 0, 'a', NULL }, { &H_M[29], 2, HELP_RANGESET, "rangeset", 0, 'R', NULL }, { &H_M[30], 2, HELP_HILITEINFO, "hiliteInfo", 0, 'H', NULL }, { &H_M[31], 2, HELP_ACTIONS, "actions", 0, 'A', NULL }, { &H_M[32], 1, HELP_none, "customizing", 0, 'C', "Customizing" }, { &H_M[33], 2, HELP_CUSTOMIZE, "customize", 0, 'C', NULL }, { &H_M[34], 2, HELP_PREFERENCES, "preferences", 0, 'P', NULL }, { &H_M[35], 2, HELP_RESOURCES, "resources", 0, 'X', NULL }, { &H_M[36], 2, HELP_BINDING, "binding", 0, 'K', NULL }, { &H_M[37], 2, HELP_PATTERNS, "patterns", 0, 'H', NULL }, { &H_M[38], 2, HELP_SMART_INDENT, "smart_indent", 0, 'S', NULL }, { &H_M[39], 1, HELP_COMMAND_LINE, "command_line", 0, 'N', NULL }, { &H_M[40], 1, HELP_SERVER, "server", 0, 'C', NULL }, { &H_M[41], 1, HELP_RECOVERY, "recovery", 0, 'a', NULL }, { &H_M[42], 1, HELP_none, "separator1", 0, '-', NULL }, { &H_M[43], 1, HELP_VERSION, "version", 0, 'V', NULL }, { &H_M[44], 1, HELP_DISTRIBUTION, "distribution", 0, 'G', NULL }, { &H_M[45], 1, HELP_MAILING_LIST, "mailing_list", 0, 'L', NULL }, { &H_M[46], 1, HELP_DEFECTS, "defects", 0, 'P', NULL }, { &H_M[47], 1, HELP_TABS_DIALOG, "tabs_dialog", 9, 'T', NULL }, { NULL, 1, HELP_CUSTOM_TITLE_DIALOG, "custom_title_dialog", 9, 'C', NULL } }; Href H_R [] = { {&H_R[1], 54, HELP_TAGS, "ctag support"}, {&H_R[2], 5794, HELP_BASICSYNTAX, "Alternation"}, {NULL, 14799, HELP_PREFERENCES, "Autoload Files"} }; static const char * NEditVersion = "NEdit release of Aug 20, 2004\n"; nedit-5.6.orig/source/help_topic.h0000644000175000017500000001025710416601363015716 0ustar paulpaul/******************************************************************************* * * * help_topic.h -- Nirvana Editor help display * * * Generated on Apr 10, 2006 (Do NOT edit!) Source of content from file help.etx * * * Copyright (c) 1999-2006 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * In addition, as a special exception to the GNU GPL, the copyright holders * * give permission to link the code of this program with the Motif and Open * * Motif libraries (or with modified versions of these that use the same * * license), and distribute linked combinations including the two. You must * * obey the GNU General Public License in all respects for all of the code used * * other than linking with Motif/Open Motif. If you modify this file, you may * * extend this exception to your version of the file, but you are not obligated * * to do so. If you do not wish to do so, delete this exception statement from * * your version. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * September 10, 1991 * * * * Written by Mark Edel * * * *******************************************************************************/ #define MAX_HEADING 3 #define STL_HD 16+1 #define STL_LINK 16 #define STL_NM_HEADER 'R' #define STL_NM_LINK 'Q' #define STYLE_MARKER '\01' #define STYLE_PLAIN 'A' #define TKN_LIST_SIZE 4 enum HelpTopic { HELP_START, HELP_SELECT, HELP_SEARCH, HELP_CLIPBOARD, HELP_MOUSE, HELP_KEYBOARD, HELP_FILL, HELP_INTERFACE, HELP_FORMAT, HELP_PROGRAMMER, HELP_TABS, HELP_INDENT, HELP_SYNTAX, HELP_TAGS, HELP_CALLTIPS, HELP_BASICSYNTAX, HELP_ESCAPESEQUENCES, HELP_PARENCONSTRUCTS, HELP_ADVANCEDTOPICS, HELP_EXAMPLES, HELP_SHELL, HELP_LEARN, HELP_MACRO_LANG, HELP_MACRO_SUBRS, HELP_RANGESET, HELP_HILITEINFO, HELP_ACTIONS, HELP_CUSTOMIZE, HELP_PREFERENCES, HELP_RESOURCES, HELP_BINDING, HELP_PATTERNS, HELP_SMART_INDENT, HELP_COMMAND_LINE, HELP_SERVER, HELP_RECOVERY, HELP_VERSION, HELP_DISTRIBUTION, HELP_MAILING_LIST, HELP_DEFECTS, HELP_TABS_DIALOG, HELP_CUSTOM_TITLE_DIALOG, HELP_LAST_ENTRY, HELP_none = 0x7fffffff /* Illegal topic */ }; #define NUM_TOPICS HELP_LAST_ENTRY nedit-5.6.orig/source/highlight.c0000644000175000017500000026513310737527367015560 0ustar paulpaulstatic const char CVSID[] = "$Id: highlight.c,v 1.56 2008/01/04 22:11:03 yooden Exp $"; /******************************************************************************* * * * highlight.c -- Nirvana Editor syntax highlighting (text coloring and font * * selected by file content * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * June 24, 1996 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "highlight.h" #include "textBuf.h" #include "textDisp.h" #include "text.h" #include "textP.h" #include "nedit.h" #include "regularExp.h" #include "highlightData.h" #include "preferences.h" #include "window.h" #include "../util/misc.h" #include "../util/DialogF.h" #include #include #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #include #include #if XmVersion >= 1002 #include #endif #ifdef HAVE_DEBUG_H #include "../debug.h" #endif /* How much re-parsing to do when an unfinished style is encountered */ #define PASS_2_REPARSE_CHUNK_SIZE 1000 /* Initial forward expansion of parsing region in incremental reparsing, when style changes propagate forward beyond the original modification. This distance is increased by a factor of two for each subsequent step. */ #define REPARSE_CHUNK_SIZE 80 /* Meanings of style buffer characters (styles). Don't use plain 'A' or 'B'; it causes problems with EBCDIC coding (possibly negative offsets when subtracting 'A'). */ #define UNFINISHED_STYLE ASCII_A #define PLAIN_STYLE (ASCII_A+1) #define IS_PLAIN(style) (style == PLAIN_STYLE || style == UNFINISHED_STYLE) #define IS_STYLED(style) (style != PLAIN_STYLE && style != UNFINISHED_STYLE) /* Compare two styles where one of the styles may not yet have been processed with pass2 patterns */ #define EQUIVALENT_STYLE(style1, style2, firstPass2Style) (style1 == style2 || \ (style1 == UNFINISHED_STYLE && \ (style2 == PLAIN_STYLE || (unsigned char)style2 >= firstPass2Style)) || \ (style2 == UNFINISHED_STYLE && \ (style1 == PLAIN_STYLE || (unsigned char)style1 >= firstPass2Style))) /* Scanning context can be reduced (with big efficiency gains) if we know that patterns can't cross line boundaries, which is implied by a context requirement of 1 line and 0 characters */ #define CAN_CROSS_LINE_BOUNDARIES(contextRequirements) \ (contextRequirements->nLines != 1 || contextRequirements->nChars != 0) /* "Compiled" version of pattern specification */ typedef struct _highlightDataRec { regexp *startRE; regexp *endRE; regexp *errorRE; regexp *subPatternRE; char style; int colorOnly; signed char startSubexprs[NSUBEXP+1]; signed char endSubexprs[NSUBEXP+1]; int flags; int nSubPatterns; int nSubBranches; /* Number of top-level branches of subPatternRE */ int userStyleIndex; struct _highlightDataRec **subPatterns; } highlightDataRec; /* Context requirements for incremental reparsing of a pattern set */ typedef struct { int nLines; int nChars; } reparseContext; /* Data structure attached to window to hold all syntax highlighting information (for both drawing and incremental reparsing) */ typedef struct { highlightDataRec *pass1Patterns; highlightDataRec *pass2Patterns; char *parentStyles; reparseContext contextRequirements; styleTableEntry *styleTable; int nStyles; textBuffer *styleBuffer; patternSet *patternSetForWindow; } windowHighlightData; static windowHighlightData *createHighlightData(WindowInfo *window, patternSet *patSet); static void freeHighlightData(windowHighlightData *hd); static patternSet *findPatternsForWindow(WindowInfo *window, int warn); static highlightDataRec *compilePatterns(Widget dialogParent, highlightPattern *patternSrc, int nPatterns); static void freePatterns(highlightDataRec *patterns); static void handleUnparsedRegion(const WindowInfo* win, textBuffer* styleBuf, const int pos); static void handleUnparsedRegionCB(const textDisp* textD, const int pos, const void* cbArg); static void incrementalReparse(windowHighlightData *highlightData, textBuffer *buf, int pos, int nInserted, const char *delimiters); static int parseBufferRange(highlightDataRec *pass1Patterns, highlightDataRec *pass2Patterns, textBuffer *buf, textBuffer *styleBuf, reparseContext *contextRequirements, int beginParse, int endParse, const char *delimiters); static int parseString(highlightDataRec *pattern, const char **string, char **styleString, int length, char *prevChar, int anchored, const char *delimiters, const char* lookBehindTo, const char* match_till); static void passTwoParseString(highlightDataRec *pattern, char *string, char *styleString, int length, char *prevChar, const char *delimiters, const char* lookBehindTo, const char* match_till); static void fillStyleString(const char **stringPtr, char **stylePtr, const char *toPtr, char style, char *prevChar); static void modifyStyleBuf(textBuffer *styleBuf, char *styleString, int startPos, int endPos, int firstPass2Style); static int lastModified(textBuffer *styleBuf); static int max(int i1, int i2); static int min(int i1, int i2); static char getPrevChar(textBuffer *buf, int pos); static regexp *compileREAndWarn(Widget parent, const char *re); static int parentStyleOf(const char *parentStyles, int style); static int isParentStyle(const char *parentStyles, int style1, int style2); static int findSafeParseRestartPos(textBuffer *buf, windowHighlightData *highlightData, int *pos); static int backwardOneContext(textBuffer *buf, reparseContext *context, int fromPos); static int forwardOneContext(textBuffer *buf, reparseContext *context, int fromPos); static void recolorSubexpr(regexp *re, int subexpr, int style, const char *string, char *styleString); static int indexOfNamedPattern(highlightPattern *patList, int nPats, const char *patName); static int findTopLevelParentIndex(highlightPattern *patList, int nPats, int index); static highlightDataRec *patternOfStyle(highlightDataRec *patterns, int style); static void updateWindowHeight(WindowInfo *window, int oldFontHeight); static int getFontHeight(WindowInfo *window); static styleTableEntry *styleTableEntryOfCode(WindowInfo *window, int hCode); /* ** Buffer modification callback for triggering re-parsing of modified ** text and keeping the style buffer synchronized with the text buffer. ** This must be attached to the the text buffer BEFORE any widget text ** display callbacks, so it can get the style buffer ready to be used ** by the text display routines. ** ** Update the style buffer for changes to the text, and mark any style ** changes by selecting the region in the style buffer. This strange ** protocol of informing the text display to redraw style changes by ** making selections in the style buffer is used because this routine ** is intended to be called BEFORE the text display callback paints the ** text (to minimize redraws and, most importantly, to synchronize the ** style buffer with the text buffer). If we redraw now, the text ** display hasn't yet processed the modification, redrawing later is ** not only complicated, it will double-draw almost everything typed. ** ** Note: This routine must be kept efficient. It is called for every ** character typed. */ void SyntaxHighlightModifyCB(int pos, int nInserted, int nDeleted, int nRestyled, const char *deletedText, void *cbArg) { WindowInfo *window = (WindowInfo *)cbArg; windowHighlightData *highlightData = (windowHighlightData *)window->highlightData; if (highlightData == NULL) return; /* Restyling-only modifications (usually a primary or secondary selection) don't require any processing, but clear out the style buffer selection so the widget doesn't think it has to keep redrawing the old area */ if (nInserted == 0 && nDeleted == 0) { BufUnselect(highlightData->styleBuffer); return; } /* First and foremost, the style buffer must track the text buffer accurately and correctly */ if (nInserted > 0) { char *insStyle; int i; insStyle = XtMalloc(sizeof(char) * (nInserted + 1)); for (i=0; istyleBuffer, pos, pos+nDeleted, insStyle); XtFree(insStyle); } else { BufRemove(highlightData->styleBuffer, pos, pos+nDeleted); } /* Mark the changed region in the style buffer as requiring redraw. This is not necessary for getting it redrawn, it will be redrawn anyhow by the text display callback, but it clears the previous selection and saves the modifyStyleBuf routine from unnecessary work in tracking changes that are already scheduled for redraw */ BufSelect(highlightData->styleBuffer, pos, pos+nInserted); /* Re-parse around the changed region */ if (highlightData->pass1Patterns) incrementalReparse(highlightData, window->buffer, pos, nInserted, GetWindowDelimiters(window)); } /* ** Turn on syntax highlighting. If "warn" is true, warn the user when it ** can't be done, otherwise, just return. */ void StartHighlighting(WindowInfo *window, int warn) { patternSet *patterns; windowHighlightData *highlightData; char *stylePtr, *styleString; const char *stringPtr, *bufString; char prevChar = '\0'; int i, oldFontHeight; /* Find the pattern set matching the window's current language mode, tell the user if it can't be done */ patterns = findPatternsForWindow(window, warn); if (patterns == NULL) return; /* Compile the patterns */ highlightData = createHighlightData(window, patterns); if (highlightData == NULL) return; /* Prepare for a long delay, refresh display and put up a watch cursor */ BeginWait(window->shell); XmUpdateDisplay(window->shell); /* Parse the buffer with pass 1 patterns. If there are none, initialize the style buffer to all UNFINISHED_STYLE to trigger parsing later */ stylePtr = styleString = XtMalloc(window->buffer->length + 1); if (highlightData->pass1Patterns == NULL) { for (i=0; ibuffer->length; i++) *stylePtr++ = UNFINISHED_STYLE; } else { stringPtr = bufString = BufAsString(window->buffer); parseString(highlightData->pass1Patterns, &stringPtr, &stylePtr, window->buffer->length, &prevChar, False, GetWindowDelimiters(window), bufString, NULL); } *stylePtr = '\0'; BufSetAll(highlightData->styleBuffer, styleString); XtFree(styleString); /* install highlight pattern data in the window data structure */ window->highlightData = highlightData; /* Get the height of the current font in the window, to be used after highlighting is turned on to resize the window to make room for additional highlight fonts which may be sized differently */ oldFontHeight = getFontHeight(window); /* Attach highlight information to text widgets in each pane */ AttachHighlightToWidget(window->textArea, window); for (i=0; inPanes; i++) AttachHighlightToWidget(window->textPanes[i], window); /* Re-size the window to fit the highlight fonts properly & tell the window manager about the potential line-height change as well */ updateWindowHeight(window, oldFontHeight); UpdateWMSizeHints(window); UpdateMinPaneHeights(window); /* Make sure that if the window has grown, the additional area gets repainted. Otherwise, it is possible that the area gets moved before a repaint event is received and the area doesn't get repainted at all (eg. because of a -line command line argument that moves the text). */ XmUpdateDisplay(window->shell); EndWait(window->shell); } /* ** Turn off syntax highlighting and free style buffer, compiled patterns, and ** related data. */ void StopHighlighting(WindowInfo *window) { int i, oldFontHeight; if (window->highlightData==NULL) return; /* Get the line height being used by the highlight fonts in the window, to be used after highlighting is turned off to resize the window back to the line height of the primary font */ oldFontHeight = getFontHeight(window); /* Free and remove the highlight data from the window */ freeHighlightData((windowHighlightData *)window->highlightData); window->highlightData = NULL; /* Remove and detach style buffer and style table from all text display(s) of window, and redisplay without highlighting */ RemoveWidgetHighlight(window->textArea); for (i=0; inPanes; i++) RemoveWidgetHighlight(window->textPanes[i]); /* Re-size the window to fit the primary font properly & tell the window manager about the potential line-height change as well */ updateWindowHeight(window, oldFontHeight); UpdateWMSizeHints(window); UpdateMinPaneHeights(window); } /* ** Free highlighting data from a window destined for destruction, without ** redisplaying. */ void FreeHighlightingData(WindowInfo *window) { int i; if (window->highlightData == NULL) return; /* Free and remove the highlight data from the window */ freeHighlightData((windowHighlightData *)window->highlightData); window->highlightData = NULL; /* The text display may make a last desperate attempt to access highlight information when it is destroyed, which would be a disaster. */ ((TextWidget)window->textArea)->text.textD->styleBuffer = NULL; for (i=0; inPanes; i++) ((TextWidget)window->textPanes[i])->text.textD->styleBuffer = NULL; } /* ** Attach style information from a window's highlight data to a ** text widget and redisplay. */ void AttachHighlightToWidget(Widget widget, WindowInfo *window) { windowHighlightData *highlightData = (windowHighlightData *)window->highlightData; TextDAttachHighlightData(((TextWidget)widget)->text.textD, highlightData->styleBuffer, highlightData->styleTable, highlightData->nStyles, UNFINISHED_STYLE, handleUnparsedRegionCB, window); } /* ** Remove style information from a text widget and redisplay it. */ void RemoveWidgetHighlight(Widget widget) { TextDAttachHighlightData(((TextWidget)widget)->text.textD, NULL, NULL, 0, UNFINISHED_STYLE, NULL, NULL); } /* ** Change highlight fonts and/or styles in a highlighted window, without ** re-parsing. */ void UpdateHighlightStyles(WindowInfo *window) { patternSet *patterns; windowHighlightData *highlightData; windowHighlightData *oldHighlightData = (windowHighlightData *)window->highlightData; textBuffer *styleBuffer; int i; /* Do nothing if window not highlighted */ if (window->highlightData == NULL) return; /* Find the pattern set for the window's current language mode */ patterns = findPatternsForWindow(window, False); if (patterns == NULL) { StopHighlighting(window); return; } /* Build new patterns */ highlightData = createHighlightData(window, patterns); if (highlightData == NULL) { StopHighlighting(window); return; } /* Update highlight pattern data in the window data structure, but preserve all of the effort that went in to parsing the buffer by swapping it with the empty one in highlightData (which is then freed in freeHighlightData) */ styleBuffer = oldHighlightData->styleBuffer; oldHighlightData->styleBuffer = highlightData->styleBuffer; freeHighlightData(oldHighlightData); highlightData->styleBuffer = styleBuffer; window->highlightData = highlightData; /* Attach new highlight information to text widgets in each pane (and redraw) */ AttachHighlightToWidget(window->textArea, window); for (i=0; inPanes; i++) AttachHighlightToWidget(window->textPanes[i], window); } /* ** Do a test compile of patterns in "patSet" and report problems to the ** user via dialog. Returns True if patterns are ok. ** ** This is somewhat kludgy in that it uses createHighlightData, which ** requires a window to find the fonts to use, and just uses a random ** window from the window list. Since the window is used to get the ** dialog parent as well, in non-popups-under-pointer mode, these dialogs ** will appear in odd places on the screen. */ int TestHighlightPatterns(patternSet *patSet) { windowHighlightData *highlightData; /* Compile the patterns (passing a random window as a source for fonts, and parent for dialogs, since we really don't care what fonts are used) */ highlightData = createHighlightData(WindowList, patSet); if (highlightData == NULL) return False; freeHighlightData(highlightData); return True; } /* ** Returns the highlight style of the character at a given position of a ** window. To avoid breaking encapsulation, the highlight style is converted ** to a void* pointer (no other module has to know that characters are used ** to represent highlight styles; that would complicate future extensions). ** Returns NULL if the window has highlighting turned off. ** The only guarantee that this function offers, is that when the same ** pointer is returned for two positions, the corresponding characters have ** the same highlight style. **/ void* GetHighlightInfo(WindowInfo *window, int pos) { int style; highlightDataRec *pattern = NULL; windowHighlightData *highlightData = (windowHighlightData *)window->highlightData; if (!highlightData) return NULL; /* Be careful with signed/unsigned conversions. NO conversion here! */ style = (int)BufGetCharacter(highlightData->styleBuffer, pos); /* Beware of unparsed regions. */ if (style == UNFINISHED_STYLE) { handleUnparsedRegion(window, highlightData->styleBuffer, pos); style = (int)BufGetCharacter(highlightData->styleBuffer, pos); } if (highlightData->pass1Patterns) { pattern = patternOfStyle(highlightData->pass1Patterns, style); } if (!pattern && highlightData->pass2Patterns) { pattern = patternOfStyle(highlightData->pass2Patterns, style); } if (!pattern) { return NULL; } return (void*)pattern->userStyleIndex; } /* ** Free allocated memory associated with highlight data, including compiled ** regular expressions, style buffer and style table. Note: be sure to ** NULL out the widget references to the objects in this structure before ** calling this. Because of the slow, multi-phase destruction of ** widgets, this data can be referenced even AFTER destroying the widget. */ static void freeHighlightData(windowHighlightData *hd) { if (hd == NULL) return; if (hd->pass1Patterns != NULL) freePatterns(hd->pass1Patterns); if (hd->pass2Patterns != NULL) freePatterns(hd->pass2Patterns); XtFree(hd->parentStyles); BufFree(hd->styleBuffer); XtFree((char *)hd->styleTable); XtFree((char *)hd); } /* ** Find the pattern set matching the window's current language mode, or ** tell the user if it can't be done (if warn is True) and return NULL. */ static patternSet *findPatternsForWindow(WindowInfo *window, int warn) { patternSet *patterns; char *modeName; /* Find the window's language mode. If none is set, warn user */ modeName = LanguageModeName(window->languageMode); if (modeName == NULL) { if (warn) DialogF(DF_WARN, window->shell, 1, "Language Mode", "No language-specific mode has been set for this file.\n\n" "To use syntax highlighting in this window, please select a\n" "language from the Preferences -> Language Modes menu.\n\n" "New language modes and syntax highlighting patterns can be\n" "added via Preferences -> Default Settings -> Language Modes,\n" "and Preferences -> Default Settings -> Syntax Highlighting.", "OK"); return NULL; } /* Look up the appropriate pattern for the language */ patterns = FindPatternSet(modeName); if (patterns == NULL) { if (warn) { DialogF(DF_WARN, window->shell, 1, "Language Mode", "Syntax highlighting is not available in language\n" "mode %s.\n\n" "You can create new syntax highlight patterns in the\n" "Preferences -> Default Settings -> Syntax Highlighting\n" "dialog, or choose a different language mode from:\n" "Preferences -> Language Mode.", "OK", modeName); return NULL; } } return patterns; } /* ** Create complete syntax highlighting information from "patternSrc", using ** highlighting fonts from "window", includes pattern compilation. If errors ** are encountered, warns user with a dialog and returns NULL. To free the ** allocated components of the returned data structure, use freeHighlightData. */ static windowHighlightData *createHighlightData(WindowInfo *window, patternSet *patSet) { highlightPattern *patternSrc = patSet->patterns; int nPatterns = patSet->nPatterns; int contextLines = patSet->lineContext; int contextChars = patSet->charContext; int i, nPass1Patterns, nPass2Patterns; int noPass1, noPass2; char *parentStyles, *parentStylesPtr, *parentName; highlightPattern *pass1PatternSrc, *pass2PatternSrc, *p1Ptr, *p2Ptr; styleTableEntry *styleTable, *styleTablePtr; textBuffer *styleBuf; highlightDataRec *pass1Pats, *pass2Pats; windowHighlightData *highlightData; /* The highlighting code can't handle empty pattern sets, quietly say no */ if (nPatterns == 0) { return NULL; } /* Check that the styles and parent pattern names actually exist */ if (!NamedStyleExists("Plain")) { DialogF(DF_WARN, window->shell, 1, "Highlight Style", "Highlight style \"Plain\" is missing", "OK"); return NULL; } for (i=0; ishell, 1, "Parent Pattern", "Parent field \"%s\" in pattern \"%s\"\n" "does not match any highlight patterns in this set", "OK", patternSrc[i].subPatternOf, patternSrc[i].name); return NULL; } } for (i=0; ishell, 1, "Highlight Style", "Style \"%s\" named in pattern \"%s\"\n" "does not match any existing style", "OK", patternSrc[i].style, patternSrc[i].name); return NULL; } } /* Make DEFER_PARSING flags agree with top level patterns (originally, individual flags had to be correct and were checked here, but dialog now shows this setting only on top patterns which is much less confusing) */ for (i = 0; i < nPatterns; i++) { if (patternSrc[i].subPatternOf != NULL) { int parentindex; parentindex=findTopLevelParentIndex(patternSrc, nPatterns, i); if (parentindex==-1) { DialogF(DF_WARN, window->shell, 1, "Parent Pattern", "Pattern \"%s\" does not have valid parent", "OK", patternSrc[i].name); return NULL; } if (patternSrc[parentindex].flags & DEFER_PARSING) { patternSrc[i].flags |= DEFER_PARSING; } else { patternSrc[i].flags &= ~DEFER_PARSING; } } } /* Sort patterns into those to be used in pass 1 parsing, and those to be used in pass 2, and add default pattern (0) to each list */ nPass1Patterns = 1; nPass2Patterns = 1; for (i=0; iname = p2Ptr->name = ""; p1Ptr->startRE = p2Ptr->startRE = NULL; p1Ptr->endRE = p2Ptr->endRE = NULL; p1Ptr->errorRE = p2Ptr->errorRE = NULL; p1Ptr->style = p2Ptr->style = "Plain"; p1Ptr->subPatternOf = p2Ptr->subPatternOf = NULL; p1Ptr->flags = p2Ptr->flags = 0; p1Ptr++; p2Ptr++; for (i=0; ishell, pass1PatternSrc, nPass1Patterns); if (pass1Pats == NULL) return NULL; } if (nPass2Patterns == 0) pass2Pats = NULL; else { pass2Pats = compilePatterns(window->shell, pass2PatternSrc, nPass2Patterns); if (pass2Pats == NULL) return NULL; } /* Set pattern styles. If there are pass 2 patterns, pass 1 pattern 0 should have a default style of UNFINISHED_STYLE. With no pass 2 patterns, unstyled areas of pass 1 patterns should be PLAIN_STYLE to avoid triggering re-parsing every time they are encountered */ noPass1 = nPass1Patterns == 0; noPass2 = nPass2Patterns == 0; if (noPass2) pass1Pats[0].style = PLAIN_STYLE; else if (noPass1) pass2Pats[0].style = PLAIN_STYLE; else { pass1Pats[0].style = UNFINISHED_STYLE; pass2Pats[0].style = PLAIN_STYLE; } for (i=1; ihighlightName = pat->name; \ p->styleName = pat->style; \ p->colorName = ColorOfNamedStyle(pat->style); \ p->bgColorName = BgColorOfNamedStyle(pat->style); \ p->isBold = FontOfNamedStyleIsBold(pat->style); \ p->isItalic = FontOfNamedStyleIsItalic(pat->style); \ /* And now for the more physical stuff */ \ p->color = AllocColor(window->textArea, p->colorName, &r, &g, &b); \ p->red = r; \ p->green = g; \ p->blue = b; \ if (p->bgColorName) { \ p->bgColor = AllocColor(window->textArea, p->bgColorName, &r, &g, &b); \ p->bgRed = r; \ p->bgGreen = g; \ p->bgBlue = b; \ } \ else { \ p->bgColor = p->color; \ p->bgRed = r; \ p->bgGreen = g; \ p->bgBlue = b; \ } \ p->font = FontOfNamedStyle(window, pat->style); \ } while (0) /* PLAIN_STYLE (pass 1) */ styleTablePtr->underline = FALSE; setStyleTablePtr(styleTablePtr++, noPass1 ? &pass2PatternSrc[0] : &pass1PatternSrc[0]); /* PLAIN_STYLE (pass 2) */ styleTablePtr->underline = FALSE; setStyleTablePtr(styleTablePtr++, noPass2 ? &pass1PatternSrc[0] : &pass2PatternSrc[0]); /* explicit styles (pass 1) */ for (i=1; iunderline = FALSE; setStyleTablePtr(styleTablePtr++, &pass1PatternSrc[i]); } /* explicit styles (pass 2) */ for (i=1; iunderline = FALSE; setStyleTablePtr(styleTablePtr++, &pass2PatternSrc[i]); } /* Free the temporary sorted pattern source list */ XtFree((char *)pass1PatternSrc); XtFree((char *)pass2PatternSrc); /* Create the style buffer */ styleBuf = BufCreate(); /* Collect all of the highlighting information in a single structure */ highlightData =(windowHighlightData *)XtMalloc(sizeof(windowHighlightData)); highlightData->pass1Patterns = pass1Pats; highlightData->pass2Patterns = pass2Pats; highlightData->parentStyles = parentStyles; highlightData->styleTable = styleTable; highlightData->nStyles = styleTablePtr - styleTable; highlightData->styleBuffer = styleBuf; highlightData->contextRequirements.nLines = contextLines; highlightData->contextRequirements.nChars = contextChars; highlightData->patternSetForWindow = patSet; return highlightData; } /* ** Transform pattern sources into the compiled highlight information ** actually used by the code. Output is a tree of highlightDataRec structures ** containing compiled regular expressions and style information. */ static highlightDataRec *compilePatterns(Widget dialogParent, highlightPattern *patternSrc, int nPatterns) { int i, nSubExprs, patternNum, length, subPatIndex, subExprNum, charsRead; int parentIndex; char *ptr, *bigPattern, *compileMsg; highlightDataRec *compiledPats; /* Allocate memory for the compiled patterns. The list is terminated by a record with style == 0. */ compiledPats = (highlightDataRec *)XtMalloc(sizeof(highlightDataRec) * (nPatterns + 1)); compiledPats[nPatterns].style = 0; /* Build the tree of parse expressions */ for (i=0; ihighlightData; patternSet *set; int i; if (hData && (set = hData->patternSetForWindow)) { for (i = 0; i < set->nPatterns; i++) if (strcmp(set->patterns[i].name, name) == 0) return &set->patterns[i]; } return NULL; } /* ** Picks up the entry in the style buffer for the position (if any). Rather ** like styleOfPos() in textDisp.c. Returns the style code or zero. */ int HighlightCodeOfPos(WindowInfo *window, int pos) { windowHighlightData *highlightData = (windowHighlightData *)window->highlightData; textBuffer *styleBuf = highlightData ? highlightData->styleBuffer : NULL; int hCode = 0; if (styleBuf != NULL) { hCode = (unsigned char)BufGetCharacter(styleBuf, pos); if (hCode == UNFINISHED_STYLE) { /* encountered "unfinished" style, trigger parsing */ handleUnparsedRegion(window, highlightData->styleBuffer, pos); hCode = (unsigned char)BufGetCharacter(styleBuf, pos); } } return hCode; } /* ** Returns the length over which a particular highlight code applies, starting ** at pos. If the initial code value *checkCode is zero, the highlight code of ** pos is used. */ /* YOO: This is called form only one other function, which uses a constant for checkCode and never evaluates it after the call. */ int HighlightLengthOfCodeFromPos(WindowInfo *window, int pos, int *checkCode) { windowHighlightData *highlightData = (windowHighlightData *)window->highlightData; textBuffer *styleBuf = highlightData ? highlightData->styleBuffer : NULL; int hCode = 0; int oldPos = pos; if (styleBuf != NULL) { hCode = (unsigned char)BufGetCharacter(styleBuf, pos); if (!hCode) return 0; if (hCode == UNFINISHED_STYLE) { /* encountered "unfinished" style, trigger parsing */ handleUnparsedRegion(window, highlightData->styleBuffer, pos); hCode = (unsigned char)BufGetCharacter(styleBuf, pos); } if (*checkCode == 0) *checkCode = hCode; while (hCode == *checkCode || hCode == UNFINISHED_STYLE) { if (hCode == UNFINISHED_STYLE) { /* encountered "unfinished" style, trigger parsing, then loop */ handleUnparsedRegion(window, highlightData->styleBuffer, pos); hCode = (unsigned char)BufGetCharacter(styleBuf, pos); } else { /* advance the position and get the new code */ hCode = (unsigned char)BufGetCharacter(styleBuf, ++pos); } } } return pos - oldPos; } /* ** Returns the length over which a particular style applies, starting at pos. ** If the initial code value *checkCode is zero, the highlight code of pos ** is used. */ int StyleLengthOfCodeFromPos(WindowInfo *window, int pos, const char **checkStyleName) { windowHighlightData *highlightData = (windowHighlightData *)window->highlightData; textBuffer *styleBuf = highlightData ? highlightData->styleBuffer : NULL; int hCode = 0; int oldPos = pos; styleTableEntry *entry; if (styleBuf != NULL) { hCode = (unsigned char)BufGetCharacter(styleBuf, pos); if (!hCode) return 0; if (hCode == UNFINISHED_STYLE) { /* encountered "unfinished" style, trigger parsing */ handleUnparsedRegion(window, highlightData->styleBuffer, pos); hCode = (unsigned char)BufGetCharacter(styleBuf, pos); } entry = styleTableEntryOfCode(window, hCode); if (entry == NULL) return 0; if ((*checkStyleName) == NULL) (*checkStyleName) = entry->styleName; while (hCode == UNFINISHED_STYLE || ((entry = styleTableEntryOfCode(window, hCode)) && strcmp(entry->styleName, (*checkStyleName)) == 0)) { if (hCode == UNFINISHED_STYLE) { /* encountered "unfinished" style, trigger parsing, then loop */ handleUnparsedRegion(window, highlightData->styleBuffer, pos); hCode = (unsigned char)BufGetCharacter(styleBuf, pos); } else { /* advance the position and get the new code */ hCode = (unsigned char)BufGetCharacter(styleBuf, ++pos); } } } return pos - oldPos; } /* ** Returns a pointer to the entry in the style table for the entry of code ** hCode (if any). */ static styleTableEntry *styleTableEntryOfCode(WindowInfo *window, int hCode) { windowHighlightData *highlightData = (windowHighlightData *)window->highlightData; hCode -= UNFINISHED_STYLE; /* get the correct index value */ if (!highlightData || hCode < 0 || hCode >= highlightData->nStyles) return NULL; return &highlightData->styleTable[hCode]; } /* ** Functions to return style information from the highlighting style table. */ char *HighlightNameOfCode(WindowInfo *window, int hCode) { styleTableEntry *entry = styleTableEntryOfCode(window, hCode); return entry ? entry->highlightName : ""; } char *HighlightStyleOfCode(WindowInfo *window, int hCode) { styleTableEntry *entry = styleTableEntryOfCode(window, hCode); return entry ? entry->styleName : ""; } Pixel HighlightColorValueOfCode(WindowInfo *window, int hCode, int *r, int *g, int *b) { styleTableEntry *entry = styleTableEntryOfCode(window, hCode); if (entry) { *r = entry->red; *g = entry->green; *b = entry->blue; return entry->color; } else { /* pick up foreground color of the (first) text widget of the window */ XColor colorDef; Colormap cMap; Display *display = XtDisplay(window->textArea); *r = *g = *b = 0; XtVaGetValues(window->textArea, XtNcolormap, &cMap, XtNforeground, &colorDef.pixel, NULL); if (XQueryColor(display, cMap, &colorDef)) { *r = colorDef.red; *g = colorDef.green; *b = colorDef.blue; } return colorDef.pixel; } } Pixel GetHighlightBGColorOfCode(WindowInfo *window, int hCode, int *r, int *g, int *b) { styleTableEntry *entry = styleTableEntryOfCode(window, hCode); if (entry && entry->bgColorName) { *r = entry->bgRed; *g = entry->bgGreen; *b = entry->bgBlue; return entry->bgColor; } else { /* pick up background color of the (first) text widget of the window */ XColor colorDef; Colormap cMap; Display *display = XtDisplay(window->textArea); *r = *g = *b = 0; XtVaGetValues(window->textArea, XtNcolormap, &cMap, XtNbackground, &colorDef.pixel, NULL); if (XQueryColor(display, cMap, &colorDef)) { *r = colorDef.red; *g = colorDef.green; *b = colorDef.blue; } return colorDef.pixel; } } /* ** Callback to parse an "unfinished" region of the buffer. "unfinished" means ** that the buffer has been parsed with pass 1 patterns, but this section has ** not yet been exposed, and thus never had pass 2 patterns applied. This ** callback is invoked when the text widget's display routines encounter one ** of these unfinished regions. "pos" is the first position encountered which ** needs re-parsing. This routine applies pass 2 patterns to a chunk of ** the buffer of size PASS_2_REPARSE_CHUNK_SIZE beyond pos. */ static void handleUnparsedRegion(const WindowInfo* window, textBuffer* styleBuf, const int pos) { textBuffer *buf = window->buffer; int beginParse, endParse, beginSafety, endSafety, p; windowHighlightData *highlightData = (windowHighlightData *)window->highlightData; reparseContext *context = &highlightData->contextRequirements; highlightDataRec *pass2Patterns = highlightData->pass2Patterns; char *string, *styleString, *stylePtr, c, prevChar; const char *stringPtr; int firstPass2Style = (unsigned char)pass2Patterns[1].style; /* If there are no pass 2 patterns to process, do nothing (but this should never be triggered) */ if (pass2Patterns == NULL) return; /* Find the point at which to begin parsing to ensure that the character at pos is parsed correctly (beginSafety), at most one context distance back from pos, unless there is a pass 1 section from which to start */ beginParse = pos; beginSafety = backwardOneContext(buf, context, beginParse); for (p=beginParse; p>=beginSafety; p--) { c = BufGetCharacter(styleBuf, p); if (c != UNFINISHED_STYLE && c != PLAIN_STYLE && (unsigned char)c < firstPass2Style) { beginSafety = p + 1; break; } } /* Decide where to stop (endParse), and the extra distance (endSafety) necessary to ensure that the changes at endParse are correct. Stop at the end of the unfinished region, or a max. of PASS_2_REPARSE_CHUNK_SIZE characters forward from the requested position */ endParse = min(buf->length, pos + PASS_2_REPARSE_CHUNK_SIZE); endSafety = forwardOneContext(buf, context, endParse); for (p=pos; pstyleBuffer, pos); } /* ** Re-parse the smallest region possible around a modification to buffer "buf" ** to gurantee that the promised context lines and characters have ** been presented to the patterns. Changes the style buffer in "highlightData" ** with the parsing result. */ static void incrementalReparse(windowHighlightData *highlightData, textBuffer *buf, int pos, int nInserted, const char *delimiters) { int beginParse, endParse, endAt, lastMod, parseInStyle, nPasses; textBuffer *styleBuf = highlightData->styleBuffer; highlightDataRec *pass1Patterns = highlightData->pass1Patterns; highlightDataRec *pass2Patterns = highlightData->pass2Patterns; highlightDataRec *startPattern; reparseContext *context = &highlightData->contextRequirements; char *parentStyles = highlightData->parentStyles; /* Find the position "beginParse" at which to begin reparsing. This is far enough back in the buffer such that the guranteed number of lines and characters of context are examined. */ beginParse = pos; parseInStyle = findSafeParseRestartPos(buf, highlightData, &beginParse); /* Find the position "endParse" at which point it is safe to stop parsing, unless styles are getting changed beyond the last modification */ lastMod = pos + nInserted; endParse = forwardOneContext(buf, context, lastMod); /* ** Parse the buffer from beginParse, until styles compare ** with originals for one full context distance. Distance increases ** by powers of two until nothing changes from previous step. If ** parsing ends before endParse, start again one level up in the ** pattern hierarchy */ for (nPasses=0; ; nPasses++) { /* Parse forward from beginParse to one context beyond the end of the last modification */ startPattern = patternOfStyle(pass1Patterns, parseInStyle); /* If there is no pattern matching the style, it must be a pass-2 style. It that case, it is (probably) safe to start parsing with the root pass-1 pattern again. Anyway, passing a NULL-pointer to the parse routine would result in a crash; restarting with pass-1 patterns is certainly preferable, even if there is a slight chance of a faulty coloring. */ if (!startPattern) { startPattern = pass1Patterns; } endAt = parseBufferRange(startPattern, pass2Patterns, buf, styleBuf, context, beginParse, endParse, delimiters); /* If parse completed at this level, move one style up in the hierarchy and start again from where the previous parse left off. */ if (endAt < endParse) { beginParse = endAt; endParse = forwardOneContext(buf, context, max(endAt, max(lastModified(styleBuf), lastMod))); if (IS_PLAIN(parseInStyle)) { fprintf(stderr, "NEdit internal error: incr. reparse fell short\n"); return; } parseInStyle = parentStyleOf(parentStyles, parseInStyle); /* One context distance beyond last style changed means we're done */ } else if (lastModified(styleBuf) <= lastMod) { return; /* Styles are changing beyond the modification, continue extending the end of the parse range by powers of 2 * REPARSE_CHUNK_SIZE and reparse until nothing changes */ } else { lastMod = lastModified(styleBuf); endParse = min(buf->length, forwardOneContext(buf, context, lastMod) + (REPARSE_CHUNK_SIZE << nPasses)); } } } /* ** Parse text in buffer "buf" between positions "beginParse" and "endParse" ** using pass 1 patterns over the entire range and pass 2 patterns where needed ** to determine whether re-parsed areas have changed and need to be redrawn. ** Deposits style information in "styleBuf" and expands the selection in ** styleBuf to show the additional areas which have changed and need ** redrawing. beginParse must be a position from which pass 1 parsing may ** safely be started using the pass1Patterns given. Internally, adds a ** "takeoff" safety region before beginParse, so that pass 2 patterns will be ** allowed to match properly if they begin before beginParse, and a "landing" ** safety region beyond endparse so that endParse is guranteed to be parsed ** correctly in both passes. Returns the buffer position at which parsing ** finished (this will normally be endParse, unless the pass1Patterns is a ** pattern which does end and the end is reached). */ static int parseBufferRange(highlightDataRec *pass1Patterns, highlightDataRec *pass2Patterns, textBuffer *buf, textBuffer *styleBuf, reparseContext *contextRequirements, int beginParse, int endParse, const char *delimiters) { char *string, *styleString, *stylePtr, *temp, prevChar; const char *stringPtr; int endSafety, endPass2Safety, startPass2Safety, tempLen; int modStart, modEnd, beginSafety, beginStyle, p, style; int firstPass2Style = pass2Patterns == NULL ? INT_MAX : (unsigned char)pass2Patterns[1].style; /* Begin parsing one context distance back (or to the last style change) */ beginStyle = pass1Patterns->style; if (CAN_CROSS_LINE_BOUNDARIES(contextRequirements)) { beginSafety = backwardOneContext(buf, contextRequirements, beginParse); for (p=beginParse; p>=beginSafety; p--) { style = BufGetCharacter(styleBuf, p-1); if (!EQUIVALENT_STYLE(style, beginStyle, firstPass2Style)) { beginSafety = p; break; } } } else { for (beginSafety=max(0,beginParse-1); beginSafety>0; beginSafety--) { style = BufGetCharacter(styleBuf, beginSafety); if (!EQUIVALENT_STYLE(style, beginStyle, firstPass2Style) || BufGetCharacter(buf, beginSafety) == '\n') { beginSafety++; break; } } } /* Parse one parse context beyond requested end to gurantee that parsing at endParse is complete, unless patterns can't cross line boundaries, in which case the end of the line is fine */ if (endParse == 0) return 0; if (CAN_CROSS_LINE_BOUNDARIES(contextRequirements)) endSafety = forwardOneContext(buf, contextRequirements, endParse); else if (endParse>=buf->length || (BufGetCharacter(buf,endParse-1)=='\n')) endSafety = endParse; else endSafety = min(buf->length, BufEndOfLine(buf, endParse) + 1); /* copy the buffer range into a string */ string = BufGetRange(buf, beginSafety, endSafety); styleString = BufGetRange(styleBuf, beginSafety, endSafety); /* Parse it with pass 1 patterns */ /* printf("parsing from %d thru %d\n", beginSafety, endSafety); */ prevChar = getPrevChar(buf, beginParse); stringPtr = &string[beginParse-beginSafety]; stylePtr = &styleString[beginParse-beginSafety]; parseString(pass1Patterns, &stringPtr, &stylePtr, endParse-beginParse, &prevChar, False, delimiters, string, NULL); /* On non top-level patterns, parsing can end early */ endParse = min(endParse, stringPtr-string + beginSafety); /* If there are no pass 2 patterns, we're done */ if (pass2Patterns == NULL) goto parseDone; /* Parsing of pass 2 patterns is done only as necessary for determining where styles have changed. Find the area to avoid, which is already marked as changed (all inserted text and previously modified areas) */ if (styleBuf->primary.selected) { modStart = styleBuf->primary.start; modEnd = styleBuf->primary.end; } else modStart = modEnd = 0; /* Re-parse the areas before the modification with pass 2 patterns, from beginSafety to far enough beyond modStart to gurantee that parsing at modStart is correct (pass 2 patterns must match entirely within one context distance, and only on the top level). If the parse region ends entirely before the modification or at or beyond modEnd, parse the whole thing and take advantage of the safety region which will be thrown away below. Otherwise save the contents of the safety region temporarily, and restore it after the parse. */ if (beginSafety < modStart) { if (endSafety > modStart) { endPass2Safety = forwardOneContext(buf, contextRequirements, modStart); if (endPass2Safety + PASS_2_REPARSE_CHUNK_SIZE >= modEnd) endPass2Safety = endSafety; } else endPass2Safety = endSafety; prevChar = getPrevChar(buf, beginSafety); if (endPass2Safety == endSafety) { passTwoParseString(pass2Patterns, string, styleString, endParse - beginSafety, &prevChar, delimiters, string, NULL); goto parseDone; } else { tempLen = endPass2Safety - modStart; temp = XtMalloc(tempLen); strncpy(temp, &styleString[modStart-beginSafety], tempLen); passTwoParseString(pass2Patterns, string, styleString, modStart - beginSafety, &prevChar, delimiters, string, NULL); strncpy(&styleString[modStart-beginSafety], temp, tempLen); XtFree(temp); } } /* Re-parse the areas after the modification with pass 2 patterns, from modEnd to endSafety, with an additional safety region before modEnd to ensure that parsing at modEnd is correct. */ if (endParse > modEnd) { if (beginSafety > modEnd) { prevChar = getPrevChar(buf, beginSafety); passTwoParseString(pass2Patterns, string, styleString, endParse - beginSafety, &prevChar, delimiters, string, NULL); } else { startPass2Safety = max(beginSafety, backwardOneContext(buf, contextRequirements, modEnd)); tempLen = modEnd - startPass2Safety; temp = XtMalloc(tempLen); strncpy(temp, &styleString[startPass2Safety-beginSafety], tempLen); prevChar = getPrevChar(buf, startPass2Safety); passTwoParseString(pass2Patterns, &string[startPass2Safety-beginSafety], &styleString[startPass2Safety-beginSafety], endParse-startPass2Safety, &prevChar, delimiters, string, NULL); strncpy(&styleString[startPass2Safety-beginSafety], temp, tempLen); XtFree(temp); } } parseDone: /* Update the style buffer with the new style information, but only through endParse. Skip the safety region at the end */ styleString[endParse-beginSafety] = '\0'; modifyStyleBuf(styleBuf, &styleString[beginParse-beginSafety], beginParse, endParse, firstPass2Style); XtFree(styleString); XtFree(string); return endParse; } /* ** Parses "string" according to compiled regular expressions in "pattern" ** until endRE is or errorRE are matched, or end of string is reached. ** Advances "string", "styleString" pointers to the next character past ** the end of the parsed section, and updates "prevChar" to reflect ** the new character before "string". ** If "anchored" is true, just scan the sub-pattern starting at the beginning ** of the string. "length" is how much of the string must be parsed, but ** "string" must still be null terminated, the termination indicating how ** far the string should be searched, and "length" the part which is actually ** required (the string may or may not be parsed beyond "length"). ** ** "lookBehindTo" indicates the boundary till where look-behind patterns may ** look back. If NULL, the start of the string is assumed to be the boundary. ** ** "match_till" indicates the boundary till where matches may extend. If NULL, ** it is assumed that the terminating \0 indicates the boundary. Note that ** look-ahead patterns can peek beyond the boundary, if supplied. ** ** Returns True if parsing was done and the parse succeeded. Returns False if ** the error pattern matched, if the end of the string was reached without ** matching the end expression, or in the unlikely event of an internal error. */ static int parseString(highlightDataRec *pattern, const char **string, char **styleString, int length, char *prevChar, int anchored, const char *delimiters, const char* lookBehindTo, const char* match_till) { int i, subExecuted, subIndex; char *stylePtr; const char *stringPtr, *savedStartPtr, *startingStringPtr; signed char *subExpr; char savedPrevChar; char succChar = match_till ? (*match_till) : '\0'; highlightDataRec *subPat = NULL, *subSubPat; if (length <= 0) return False; stringPtr = *string; stylePtr = *styleString; while (ExecRE(pattern->subPatternRE, stringPtr, anchored ? *string+1 : *string+length+1, False, *prevChar, succChar, delimiters, lookBehindTo, match_till)) { /* Beware of the case where only one real branch exists, but that branch has sub-branches itself. In that case the top_branch refers to the matching sub-branch and must be ignored. */ subIndex = (pattern->nSubBranches > 1) ? pattern->subPatternRE->top_branch : 0; /* Combination of all sub-patterns and end pattern matched */ /* printf("combined patterns RE matched at %d\n", pattern->subPatternRE->startp[0] - *string); */ startingStringPtr = stringPtr; /* Fill in the pattern style for the text that was skipped over before the match, and advance the pointers to the start of the pattern */ fillStyleString(&stringPtr, &stylePtr, pattern->subPatternRE->startp[0], pattern->style, prevChar); /* If the combined pattern matched this pattern's end pattern, we're done. Fill in the style string, update the pointers, color the end expression if there were coloring sub-patterns, and return */ savedStartPtr = stringPtr; savedPrevChar = *prevChar; if (pattern->endRE != NULL) { if (subIndex == 0) { fillStyleString(&stringPtr, &stylePtr, pattern->subPatternRE->endp[0], pattern->style, prevChar); subExecuted = False; for (i=0;inSubPatterns; i++) { subPat = pattern->subPatterns[i]; if (subPat->colorOnly) { if (!subExecuted) { if (!ExecRE(pattern->endRE, savedStartPtr, savedStartPtr+1, False, savedPrevChar, succChar, delimiters, lookBehindTo, match_till)) { fprintf(stderr, "Internal error, failed to " "recover end match in parseString\n"); return False; } subExecuted = True; } for (subExpr=subPat->endSubexprs; *subExpr!=-1; subExpr++) recolorSubexpr(pattern->endRE, *subExpr, subPat->style, *string, *styleString); } } *string = stringPtr; *styleString = stylePtr; return True; } --subIndex; } /* If the combined pattern matched this pattern's error pattern, we're done. Fill in the style string, update the pointers, and return */ if (pattern->errorRE != NULL) { if (subIndex == 0) { fillStyleString(&stringPtr, &stylePtr, pattern->subPatternRE->startp[0], pattern->style, prevChar); *string = stringPtr; *styleString = stylePtr; return False; } --subIndex; } /* Figure out which sub-pattern matched */ for (i=0; inSubPatterns; i++) { subPat = pattern->subPatterns[i]; if (subPat->colorOnly) ++subIndex; else if (i == subIndex) break; } if (i == pattern->nSubPatterns) { fprintf(stderr, "Internal error, failed to match in parseString\n"); return False; } /* the sub-pattern is a simple match, just color it */ if (subPat->subPatternRE == NULL) { fillStyleString(&stringPtr, &stylePtr, pattern->subPatternRE->endp[0], /* subPat->startRE->endp[0],*/ subPat->style, prevChar); /* Parse the remainder of the sub-pattern */ } else if (subPat->endRE != NULL) { /* The pattern is a starting/ending type of pattern, proceed with the regular hierarchical parsing. */ /* If parsing should start after the start pattern, advance to that point (this is currently always the case) */ if (!(subPat->flags & PARSE_SUBPATS_FROM_START)) fillStyleString(&stringPtr, &stylePtr, pattern->subPatternRE->endp[0], /* subPat->startRE->endp[0],*/ subPat->style, prevChar); /* Parse to the end of the subPattern */ parseString(subPat, &stringPtr, &stylePtr, length - (stringPtr - *string), prevChar, False, delimiters, lookBehindTo, match_till); } else { /* If the parent pattern is not a start/end pattern, the sub-pattern can between the boundaries of the parent's match. Note that we must limit the recursive matches such that they do not exceed the parent's ending boundary. Without that restriction, matching becomes unstable. */ /* Parse to the end of the subPattern */ parseString(subPat, &stringPtr, &stylePtr, pattern->subPatternRE->endp[0]-stringPtr, prevChar, False, delimiters, lookBehindTo, pattern->subPatternRE->endp[0]); } /* If the sub-pattern has color-only sub-sub-patterns, add color based on the coloring sub-expression references */ subExecuted = False; for (i=0; inSubPatterns; i++) { subSubPat = subPat->subPatterns[i]; if (subSubPat->colorOnly) { if (!subExecuted) { if (!ExecRE(subPat->startRE, savedStartPtr, savedStartPtr+1, False, savedPrevChar, succChar, delimiters, lookBehindTo, match_till)) { fprintf(stderr, "Internal error, failed to recover " "start match in parseString\n"); return False; } subExecuted = True; } for (subExpr=subSubPat->startSubexprs; *subExpr!=-1; subExpr++) recolorSubexpr(subPat->startRE, *subExpr, subSubPat->style, *string, *styleString); } } /* Make sure parsing progresses. If patterns match the empty string, they can get stuck and hang the process */ if (stringPtr == startingStringPtr) { /* Avoid stepping over the end of the string (possible for zero-length matches at end of the string) */ if (*stringPtr == '\0') break; fillStyleString(&stringPtr, &stylePtr, stringPtr+1, pattern->style, prevChar); } } /* If this is an anchored match (must match on first character), and nothing matched, return False */ if (anchored && stringPtr == *string) return False; /* Reached end of string, fill in the remaining text with pattern style (unless this was an anchored match) */ if (!anchored) fillStyleString(&stringPtr, &stylePtr, *string+length, pattern->style, prevChar); /* Advance the string and style pointers to the end of the parsed text */ *string = stringPtr; *styleString = stylePtr; return pattern->endRE == NULL; } /* ** Takes a string which has already been parsed through pass1 parsing and ** re-parses the areas where pass two patterns are applicable. Parameters ** have the same meaning as in parseString, except that strings aren't doubly ** indirect and string pointers are not updated. */ static void passTwoParseString(highlightDataRec *pattern, char *string, char *styleString, int length, char *prevChar, const char *delimiters, const char *lookBehindTo, const char *match_till) { int inParseRegion = False; char *stylePtr, temp, *parseStart = NULL, *parseEnd, *s, *c; const char *stringPtr; int firstPass2Style = (unsigned char)pattern[1].style; for (c = string, s = styleString; ; c++, s++) { if (!inParseRegion && *c != '\0' && (*s == UNFINISHED_STYLE || *s == PLAIN_STYLE || (unsigned char)*s >= firstPass2Style)) { parseStart = c; inParseRegion = True; } if (inParseRegion && (*c == '\0' || !(*s == UNFINISHED_STYLE || *s == PLAIN_STYLE || (unsigned char)*s >= firstPass2Style))) { parseEnd = c; if (parseStart != string) *prevChar = *(parseStart-1); stringPtr = parseStart; stylePtr = &styleString[parseStart - string]; temp = *parseEnd; *parseEnd = '\0'; /* printf("pass2 parsing %d chars\n", strlen(stringPtr)); */ parseString(pattern, &stringPtr, &stylePtr, min(parseEnd - parseStart, length - (parseStart - string)), prevChar, False, delimiters, lookBehindTo, match_till); *parseEnd = temp; inParseRegion = False; } if (*c == '\0' || (!inParseRegion && c - string >= length)) break; } } /* ** Advance "stringPtr" and "stylePtr" until "stringPtr" == "toPtr", filling ** "stylePtr" with style "style". Can also optionally update the pre-string ** character, prevChar, which is fed to regular the expression matching ** routines for determining word and line boundaries at the start of the string. */ static void fillStyleString(const char **stringPtr, char **stylePtr, const char *toPtr, char style, char *prevChar) { int i, len = toPtr-*stringPtr; if (*stringPtr >= toPtr) return; for (i=0; iprimary; /* Skip the range already marked for redraw */ if (sel->selected) { modStart = sel->start; modEnd = sel->end; } else modStart = modEnd = startPos; /* Compare the original style buffer (outside of the modified range) with the new string with which it will be updated, to find the extent of the modifications. Unfinished styles in the original match any pass 2 style */ for (c=styleString, pos=startPos; pos= firstPass2Style))) { if (pos < minPos) minPos = pos; if (pos > maxPos) maxPos = pos; } } for (c=&styleString[max(0, modEnd-startPos)], pos=max(modEnd, startPos); pos= firstPass2Style))) { if (pos < minPos) minPos = pos; if (pos+1 > maxPos) maxPos = pos+1; } } /* Make the modification */ BufReplace(styleBuf, startPos, endPos, styleString); /* Mark or extend the range that needs to be redrawn. Even if no change was made, it's important to re-establish the selection, because it can get damaged by the BufReplace above */ BufSelect(styleBuf, min(modStart, minPos), max(modEnd, maxPos)); } /* ** Return the last modified position in styleBuf (as marked by modifyStyleBuf ** by the convention used for conveying modification information to the ** text widget, which is selecting the text) */ static int lastModified(textBuffer *styleBuf) { if (styleBuf->primary.selected) return max(0, styleBuf->primary.end); return 0; } /* ** Compute the distance between two colors. */ static double colorDistance(const XColor *c1, const XColor *c2) { /* This is done in RGB space, which is close, but not optimal. It's probably better to do it in HSV or YIQ space, however, that means a whole lot of extra conversions. This would allow us to weight the coordinates differently, e.g, prefer to match hue over brightness. */ static const double scale = 65535; double tred = c1->red / scale - c2->red / scale; double tgreen = c1->green / scale - c2->green / scale; double tblue = c1->blue / scale - c2->blue / scale; /* use square Euclidian distance */ return tred * tred + tgreen * tgreen + tblue * tblue; } /* ** use this canned function to call AllocColor() when ** the r, g & b components is not needed, thus saving ** the little hassle of creating the dummy variable. */ Pixel AllocateColor(Widget w, const char *colorName) { int dummy; return AllocColor(w, colorName, &dummy, &dummy, &dummy); } /* ** Allocate a read-only (shareable) colormap cell for a named color, from the ** the default colormap of the screen on which the widget (w) is displayed. If ** the colormap is full and there's no suitable substitute, print an error on ** stderr, and return the widget's foreground color as a backup. */ Pixel AllocColor(Widget w, const char *colorName, int *r, int *g, int *b) { XColor colorDef; XColor *allColorDefs; Display *display = XtDisplay(w); Colormap cMap; Pixel foreground, bestPixel; double small = 1.0e9; int depth; unsigned int ncolors; unsigned long i, best = 0; /* pixel value */ /* Get the correct colormap for compatability with the "best" visual feature in 5.2. Default visual of screen is no good here. */ XtVaGetValues(w, XtNcolormap, &cMap, XtNdepth, &depth, XtNforeground, &foreground, NULL); bestPixel = foreground; /* Our last fallback */ /* First, check for valid syntax */ if (! XParseColor(display, cMap, colorName, &colorDef)) { fprintf(stderr, "NEdit: Color name %s not in database\n", colorName); colorDef.pixel = foreground; if (XQueryColor(display, cMap, &colorDef)) { *r = colorDef.red; *g = colorDef.green; *b = colorDef.blue; } return foreground; } /* Attempt allocation of the exact color. */ if (XAllocColor(display, cMap, &colorDef)) { *r = colorDef.red; *g = colorDef.green; *b = colorDef.blue; return colorDef.pixel; } /* ---------- Allocation failed, the colormap may be full. ---------- */ #if 0 printf("Couldn't allocate %d %d %d\n", colorDef.red, colorDef.green, colorDef.blue); #endif /* We can't do the nearest-match on other than 8 bit visuals because it just takes too long. */ if (depth > 8) { /* Oh no! */ colorDef.pixel = foreground; if (XQueryColor(display, cMap, &colorDef)) { *r = colorDef.red; *g = colorDef.green; *b = colorDef.blue; } return foreground; } /* Get the entire colormap so we can find the closest one. */ ncolors = (1 << depth); allColorDefs = malloc(ncolors * sizeof(XColor)); memset(allColorDefs, 0, ncolors * sizeof(XColor)); for (i = 0; i < ncolors; i++) allColorDefs[i].pixel = i; XQueryColors(display, cMap, allColorDefs, ncolors); /* Scan through each color, looking for the closest one. */ for (i = 0; i < ncolors; i++) { double dist = colorDistance(&allColorDefs[i], &colorDef); if (dist < small) { best = i; small = dist; } } /* Legally try to acquire the shared color- we should loop through the shortest distances here. We could sort the map in order of decreasing distances and loop through it until one works. */ if (XAllocColor(display, cMap, &allColorDefs[best])) bestPixel = allColorDefs[best].pixel; #if 0 printf("Got %d %d %d, ", allColorDefs[best].red, allColorDefs[best].green, allColorDefs[best].blue); printf("That's %f off\n", small); #endif *r = allColorDefs[best].red; *g = allColorDefs[best].green; *b = allColorDefs[best].blue; free(allColorDefs); return bestPixel; } /* ** Get the character before position "pos" in buffer "buf" */ static char getPrevChar(textBuffer *buf, int pos) { return pos == 0 ? '\0' : BufGetCharacter(buf, pos-1); } /* ** compile a regular expression and present a user friendly dialog on failure. */ static regexp *compileREAndWarn(Widget parent, const char *re) { regexp *compiledRE; char *compileMsg; compiledRE = CompileRE(re, &compileMsg, REDFLT_STANDARD); if (compiledRE == NULL) { char *boundedRe = XtNewString(re); size_t maxLength = DF_MAX_MSG_LENGTH - strlen(compileMsg) - 60; /* Prevent buffer overflow in DialogF. If the re is too long, truncate it and append ... */ if (strlen(boundedRe) > maxLength) { strcpy(&boundedRe[maxLength-3], "..."); } DialogF(DF_WARN, parent, 1, "Error in Regex", "Error in syntax highlighting regular expression:\n%s\n%s", "OK", boundedRe, compileMsg); XtFree(boundedRe); return NULL; } return compiledRE; } static int parentStyleOf(const char *parentStyles, int style) { return parentStyles[(unsigned char)style-UNFINISHED_STYLE]; } static int isParentStyle(const char *parentStyles, int style1, int style2) { int p; for (p = parentStyleOf(parentStyles, style2); p != '\0'; p = parentStyleOf(parentStyles, p)) if (style1 == p) return TRUE; return FALSE; } /* ** Discriminates patterns which can be used with parseString from those which ** can't. Leaf patterns are not suitable for parsing, because patterns ** contain the expressions used for parsing within the context of their own ** operation, i.e. the parent pattern initiates, and leaf patterns merely ** confirm and color. Returns TRUE if the pattern is suitable for parsing. */ static int patternIsParsable(highlightDataRec *pattern) { return pattern != NULL && pattern->subPatternRE != NULL; } /* ** Back up position pointed to by "pos" enough that parsing from that point ** on will satisfy context gurantees for pattern matching for modifications ** at pos. Returns the style with which to begin parsing. The caller is ** guranteed that parsing may safely BEGIN with that style, but not that it ** will continue at that level. ** ** This routine can be fooled if a continuous style run of more than one ** context distance in length is produced by multiple pattern matches which ** abut, rather than by a single continuous match. In this case the ** position returned by this routine may be a bad starting point which will ** result in an incorrect re-parse. However this will happen very rarely, ** and, if it does, is unlikely to result in incorrect highlighting. */ static int findSafeParseRestartPos(textBuffer *buf, windowHighlightData *highlightData, int *pos) { int style, startStyle, runningStyle, checkBackTo, safeParseStart, i; char *parentStyles = highlightData->parentStyles; highlightDataRec *pass1Patterns = highlightData->pass1Patterns; reparseContext *context = &highlightData->contextRequirements; /* We must begin at least one context distance back from the change */ *pos = backwardOneContext(buf, context, *pos); /* If the new position is outside of any styles or at the beginning of the buffer, this is a safe place to begin parsing, and we're done */ if (*pos == 0) return PLAIN_STYLE; startStyle = BufGetCharacter(highlightData->styleBuffer, *pos); if (IS_PLAIN(startStyle)) return PLAIN_STYLE; /* ** The new position is inside of a styled region, meaning, its pattern ** could potentially be affected by the modification. ** ** Follow the style back by enough context to ensure that if we don't find ** its beginning, at least we've found a safe place to begin parsing ** within the styled region. ** ** A safe starting position within a style is either at a style ** boundary, or far enough from the beginning and end of the style run ** to ensure that it's not within the start or end expression match ** (unfortunately, abutting styles can produce false runs so we're not ** really ensuring it, just making it likely). */ if (patternIsParsable(patternOfStyle(pass1Patterns, startStyle))) { safeParseStart = backwardOneContext(buf, context, *pos); checkBackTo = backwardOneContext(buf, context, safeParseStart); } else { safeParseStart = 0; checkBackTo = 0; } runningStyle = startStyle; for (i = *pos-1; ; i--) { /* The start of the buffer is certainly a safe place to parse from */ if (i == 0) { *pos = 0; return PLAIN_STYLE; } /* If the style is preceded by a parent style, it's safe to parse with the parent style, provided that the parent is parsable. */ style = BufGetCharacter(highlightData->styleBuffer, i); if (isParentStyle(parentStyles, style, runningStyle)) { if (patternIsParsable(patternOfStyle(pass1Patterns, style))) { *pos = i + 1; return style; } else { /* The parent is not parsable, so well have to continue searching. The parent now becomes the running style. */ runningStyle = style; } } /* If the style is preceded by a child style, it's safe to resume parsing with the running style, provided that the running style is parsable. */ else if (isParentStyle(parentStyles, runningStyle, style)) { if (patternIsParsable (patternOfStyle(pass1Patterns, runningStyle))) { *pos = i + 1; return runningStyle; } /* Else: keep searching; it's no use switching to the child style because even the running one is not parsable. */ } /* If the style is preceded by a sibling style, it's safe to resume parsing with the common ancestor style, provided that the ancestor is parsable. Checking for siblings is very hard; checking whether the style has the same parent will probably catch 99% of the cases in practice. */ else if (runningStyle != style && isParentStyle(parentStyles, parentStyleOf(parentStyles, runningStyle), style)) { int parentStyle = parentStyleOf(parentStyles, runningStyle); if (patternIsParsable(patternOfStyle(pass1Patterns, parentStyle))) { *pos = i + 1; return parentStyle; } else { /* Switch to the new style */ runningStyle = style; } } /* If the style is preceded by an unrelated style, it's safe to resume parsing with PLAIN_STYLE. (Actually, it isn't, because we didn't really check for all possible sibling relations; but it will be ok in practice.) */ else if (runningStyle != style) { *pos = i + 1; return PLAIN_STYLE; } /* If the style is parsable and didn't change for one whole context distance on either side of safeParseStart, safeParseStart is a reasonable guess at a place to start parsing. Note: No 'else' here! We may come from one of the 'fall-through cases' above. */ if (i == checkBackTo) { *pos = safeParseStart; /* We should never return a non-parsable style, because it will result in an internal error. If the current style is not parsable, the pattern set most probably contains a context distance violation. In that case we can only avoid internal errors (by climbing the pattern hierarchy till we find a parsable ancestor) and hope that the highlighting errors are minor. */ while (!patternIsParsable (patternOfStyle(pass1Patterns, runningStyle))) runningStyle = parentStyleOf(parentStyles, runningStyle); return runningStyle; } } } /* ** Return a position far enough back in "buf" from "fromPos" to give patterns ** their guranteed amount of context for matching (from "context"). If ** backing up by lines yields the greater distance, the returned position will ** be to the newline character before the start of the line, rather than to ** the first character of the line. (I did this because earlier prototypes of ** the syntax highlighting code, which were based on single-line context, used ** this to ensure that line-spanning expressions would be detected. I think ** it may reduce some 2 line context requirements to one line, at a cost of ** only one extra character, but I'm not sure, and my brain hurts from ** thinking about it). */ static int backwardOneContext(textBuffer *buf, reparseContext *context, int fromPos) { if (context->nLines == 0) return max(0, fromPos - context->nChars); else if (context->nChars == 0) return max(0, BufCountBackwardNLines(buf, fromPos, context->nLines-1) - 1); else return max(0, min(max(0, BufCountBackwardNLines(buf, fromPos, context->nLines-1) -1), fromPos - context->nChars)); } /* ** Return a position far enough forward in "buf" from "fromPos" to ensure ** that patterns are given their required amount of context for matching ** (from "context"). If moving forward by lines yields the greater ** distance, the returned position will be the first character of of the ** next line, rather than the newline character at the end (see notes in ** backwardOneContext). */ static int forwardOneContext(textBuffer *buf, reparseContext *context, int fromPos) { if (context->nLines == 0) return min(buf->length, fromPos + context->nChars); else if (context->nChars == 0) return min(buf->length, BufCountForwardNLines(buf, fromPos, context->nLines)); else return min(buf->length, max(BufCountForwardNLines(buf, fromPos, context->nLines), fromPos + context->nChars)); } /* ** Change styles in the portion of "styleString" to "style" where a particular ** sub-expression, "subExpr", of regular expression "re" applies to the ** corresponding portion of "string". */ static void recolorSubexpr(regexp *re, int subexpr, int style, const char *string, char *styleString) { const char *stringPtr; char *stylePtr; stringPtr = re->startp[subexpr]; stylePtr = &styleString[stringPtr - string]; fillStyleString(&stringPtr, &stylePtr, re->endp[subexpr], style, NULL); } /* ** Search for a pattern in pattern list "patterns" with style "style" */ static highlightDataRec *patternOfStyle(highlightDataRec *patterns, int style) { int i; for (i=0; patterns[i].style!=0; i++) if (patterns[i].style == style) return &patterns[i]; if (style == PLAIN_STYLE || style == UNFINISHED_STYLE) return &patterns[0]; return NULL; } static int max(int i1, int i2) { return i1 >= i2 ? i1 : i2; } static int min(int i1, int i2) { return i1 <= i2 ? i1 : i2; } static int indexOfNamedPattern(highlightPattern *patList, int nPats, const char *patName) { int i; if (patName == NULL) return -1; for (i=0; i 1) return; /* Decompose the window height into the part devoted to displaying text (textHeight) and the non-text part (boderHeight) */ XtVaGetValues(window->shell, XmNheight, &windowHeight, NULL); XtVaGetValues(window->textArea, XmNheight, &textAreaHeight, textNmarginHeight, &marginHeight, NULL); textHeight = textAreaHeight - 2*marginHeight; for (i=0; inPanes; i++) { XtVaGetValues(window->textPanes[i], XmNheight, &textAreaHeight, NULL); textHeight += textAreaHeight - 2*marginHeight; } borderHeight = windowHeight - textHeight; /* Calculate a new window height appropriate for the new font */ newWindowHeight = (textHeight*getFontHeight(window)) / oldFontHeight + borderHeight; /* Many window managers enforce window size increments even on client resize requests. Our height increment is probably wrong because it is still set for the previous font. Set the new height in advance, before attempting to resize. */ XtVaSetValues(window->shell, XmNheightInc, getFontHeight(window), NULL); /* Re-size the window */ XtVaSetValues(window->shell, XmNheight, newWindowHeight, NULL); } /* ** Find the height currently being used to display text, which is ** a composite of all of the active highlighting fonts as determined by the ** text display component */ static int getFontHeight(WindowInfo *window) { textDisp *textD = ((TextWidget)window->textArea)->text.textD; return textD->ascent + textD->descent; } nedit-5.6.orig/source/highlight.h0000644000175000017500000001015010737527367015550 0ustar paulpaul/* $Id: highlight.h,v 1.16 2008/01/04 22:11:03 yooden Exp $ */ /******************************************************************************* * * * highlight.h -- Nirvana Editor Syntax Highlighting Header File * * * * Copyright 2003 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_HIGHLIGHT_H_INCLUDED #define NEDIT_HIGHLIGHT_H_INCLUDED #include "nedit.h" #include /* Pattern flags for modifying pattern matching behavior */ #define PARSE_SUBPATS_FROM_START 1 #define DEFER_PARSING 2 #define COLOR_ONLY 4 /* Don't use plain 'A' or 'B' for style indices, it causes problems with EBCDIC coding (possibly negative offsets when subtracting 'A'). */ #define ASCII_A ((char)65) /* Pattern specification structure */ typedef struct { char *name; char *startRE; char *endRE; char *errorRE; char *style; char *subPatternOf; int flags; } highlightPattern; /* Header for a set of patterns */ typedef struct { char *languageMode; int lineContext; int charContext; int nPatterns; highlightPattern *patterns; } patternSet; void SyntaxHighlightModifyCB(int pos, int nInserted, int nDeleted, int nRestyled, const char *deletedText, void *cbArg); void StartHighlighting(WindowInfo *window, int warn); void StopHighlighting(WindowInfo *window); void AttachHighlightToWidget(Widget widget, WindowInfo *window); void FreeHighlightingData(WindowInfo *window); void RemoveWidgetHighlight(Widget widget); void UpdateHighlightStyles(WindowInfo *window); int TestHighlightPatterns(patternSet *patSet); Pixel AllocateColor(Widget w, const char *colorName); Pixel AllocColor(Widget w, const char *colorName, int *r, int *g, int *b); void* GetHighlightInfo(WindowInfo *window, int pos); highlightPattern *FindPatternOfWindow(WindowInfo *window, char *name); int HighlightCodeOfPos(WindowInfo *window, int pos); int HighlightLengthOfCodeFromPos(WindowInfo *window, int pos, int *checkCode); int StyleLengthOfCodeFromPos(WindowInfo *window, int pos, const char **checkStyleName); char *HighlightNameOfCode(WindowInfo *window, int hCode); char *HighlightStyleOfCode(WindowInfo *window, int hCode); Pixel HighlightColorValueOfCode(WindowInfo *window, int hCode, int *r, int *g, int *b); Pixel GetHighlightBGColorOfCode(WindowInfo *window, int hCode, int *r, int *g, int *b); #endif /* NEDIT_HIGHLIGHT_H_INCLUDED */ nedit-5.6.orig/source/highlightData.c0000644000175000017500000060265110737527367016352 0ustar paulpaulstatic const char CVSID[] = "$Id: highlightData.c,v 1.80 2008/01/04 22:11:03 yooden Exp $"; /******************************************************************************* * * * highlightData.c -- Maintain, and allow user to edit, highlight pattern list * * used for syntax highlighting * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * April, 1997 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "highlightData.h" #include "textBuf.h" #include "nedit.h" #include "highlight.h" #include "regularExp.h" #include "preferences.h" #include "help.h" #include "window.h" #include "regexConvert.h" #include "../util/misc.h" #include "../util/DialogF.h" #include "../util/managedList.h" #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #include #include #include #include #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif /* Maximum allowed number of styles (also limited by representation of styles as a byte - 'b') */ #define MAX_HIGHLIGHT_STYLES 128 /* Maximum number of patterns allowed in a pattern set (regular expression limitations are probably much more restrictive). */ #define MAX_PATTERNS 127 /* Names for the fonts that can be used for syntax highlighting */ #define N_FONT_TYPES 4 enum fontTypes {PLAIN_FONT, ITALIC_FONT, BOLD_FONT, BOLD_ITALIC_FONT}; static const char *FontTypeNames[N_FONT_TYPES] = {"Plain", "Italic", "Bold", "Bold Italic"}; typedef struct { char *name; char *color; char *bgColor; int font; } highlightStyleRec; static int styleError(const char *stringStart, const char *stoppedAt, const char *message); #if 0 static int lookupNamedPattern(patternSet *p, char *patternName); #endif static int lookupNamedStyle(const char *styleName); static highlightPattern *readHighlightPatterns(char **inPtr, int withBraces, char **errMsg, int *nPatterns); static int readHighlightPattern(char **inPtr, char **errMsg, highlightPattern *pattern); static patternSet *readDefaultPatternSet(const char *langModeName); static int isDefaultPatternSet(patternSet *patSet); static patternSet *readPatternSet(char **inPtr, int convertOld); static patternSet *highlightError(char *stringStart, char *stoppedAt, const char *message); static char *intToStr(int i); static char *createPatternsString(patternSet *patSet, char *indentStr); static void setStyleByName(const char *style); static void hsDestroyCB(Widget w, XtPointer clientData, XtPointer callData); static void hsOkCB(Widget w, XtPointer clientData, XtPointer callData); static void hsApplyCB(Widget w, XtPointer clientData, XtPointer callData); static void hsCloseCB(Widget w, XtPointer clientData, XtPointer callData); static highlightStyleRec *copyHighlightStyleRec(highlightStyleRec *hs); static void *hsGetDisplayedCB(void *oldItem, int explicitRequest, int *abort, void *cbArg); static void hsSetDisplayedCB(void *item, void *cbArg); static highlightStyleRec *readHSDialogFields(int silent); static void hsFreeItemCB(void *item); static void freeHighlightStyleRec(highlightStyleRec *hs); static int hsDialogEmpty(void); static int updateHSList(void); static void updateHighlightStyleMenu(void); static void convertOldPatternSet(patternSet *patSet); static void convertPatternExpr(char **patternRE, char *patSetName, char *patName, int isSubsExpr); static Widget createHighlightStylesMenu(Widget parent); static void destroyCB(Widget w, XtPointer clientData, XtPointer callData); static void langModeCB(Widget w, XtPointer clientData, XtPointer callData); static void lmDialogCB(Widget w, XtPointer clientData, XtPointer callData); static void styleDialogCB(Widget w, XtPointer clientData, XtPointer callData); static void patTypeCB(Widget w, XtPointer clientData, XtPointer callData); static void matchTypeCB(Widget w, XtPointer clientData, XtPointer callData); static int checkHighlightDialogData(void); static void updateLabels(void); static void okCB(Widget w, XtPointer clientData, XtPointer callData); static void applyCB(Widget w, XtPointer clientData, XtPointer callData); static void checkCB(Widget w, XtPointer clientData, XtPointer callData); static void restoreCB(Widget w, XtPointer clientData, XtPointer callData); static void deleteCB(Widget w, XtPointer clientData, XtPointer callData); static void closeCB(Widget w, XtPointer clientData, XtPointer callData); static void helpCB(Widget w, XtPointer clientData, XtPointer callData); static void *getDisplayedCB(void *oldItem, int explicitRequest, int *abort, void *cbArg); static void setDisplayedCB(void *item, void *cbArg); static void setStyleMenu(const char *styleName); static highlightPattern *readDialogFields(int silent); static int dialogEmpty(void); static int updatePatternSet(void); static patternSet *getDialogPatternSet(void); static int patternSetsDiffer(patternSet *patSet1, patternSet *patSet2); static highlightPattern *copyPatternSrc(highlightPattern *pat, highlightPattern *copyTo); static void freeItemCB(void *item); static void freePatternSrc(highlightPattern *pat, int freeStruct); static void freePatternSet(patternSet *p); /* list of available highlight styles */ static int NHighlightStyles = 0; static highlightStyleRec *HighlightStyles[MAX_HIGHLIGHT_STYLES]; /* Highlight styles dialog information */ static struct { Widget shell; Widget nameW; Widget colorW; Widget bgColorW; Widget plainW, boldW, italicW, boldItalicW; Widget managedListW; highlightStyleRec **highlightStyleList; int nHighlightStyles; } HSDialog = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0}; /* Highlight dialog information */ static struct { Widget shell; Widget lmOptMenu; Widget lmPulldown; Widget styleOptMenu; Widget stylePulldown; Widget nameW; Widget topLevelW; Widget deferredW; Widget subPatW; Widget colorPatW; Widget simpleW; Widget rangeW; Widget parentW; Widget startW; Widget endW; Widget errorW; Widget lineContextW; Widget charContextW; Widget managedListW; Widget parentLbl; Widget startLbl; Widget endLbl; Widget errorLbl; Widget matchLbl; char *langModeName; int nPatterns; highlightPattern **patterns; } HighlightDialog = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL }; /* Pattern sources loaded from the .nedit file or set by the user */ static int NPatternSets = 0; static patternSet *PatternSets[MAX_LANGUAGE_MODES]; static char *DefaultPatternSets[] = { "Ada:1:0{\n\ Comments:\"--\":\"$\"::Comment::\n\ String Literals:\"\"\"\":\"\"\"\":\"\\n\":String::\n\ Character Literals:\"'(?:[^\\\\]|\\\\.)'\":::Character Const::\n\ Ada Attributes:\"(?i'size\\s+(use)>)|'\\l[\\l\\d]*(?:_[\\l\\d]+)*\":::Ada Attributes::\n\ Size Attribute:\"\\1\":\"\"::Keyword:Ada Attributes:C\n\ Based Numeric Literals:\"<(?:\\d+(?:_\\d+)*)#(?:[\\da-fA-F]+(?:_[\\da-fA-F]+)*)(?:\\.[\\da-fA-F]+(?:_[\\da-fA-F]+)*)?#(?iE[+\\-]?(?:\\d+(?:_\\d+)*))?(?!\\Y)\":::Numeric Const::\n\ Numeric Literals:\"<(?:\\d+(?:_\\d+)*)(?:\\.\\d+(?:_\\d+)*)?(?iE[+\\-]?(?:\\d+(?:_\\d+)*))?>\":::Numeric Const::\n\ Pragma:\"(?n(?ipragma)\\s+\\l[\\l\\d]*(?:_\\l[\\l\\d]*)*\\s*\\([^)]*\\)\\s*;)\":::Preprocessor::\n\ Withs Use:\"(?#Make \\s work across newlines)(?n(?iwith|use)(?#Leading W/S)\\s+(?#First package name)(?:\\l[\\l\\d]*(?:(_|\\.\\l)[\\l\\d]*)*)(?#Additional package names [optional])(?:\\s*,\\s*(?:\\l[\\l\\d]*(?:(_|\\.\\l)[\\l\\d]+)*))*(?#Trailing W/S)\\s*;)+\":::Preprocessor::\n\ Predefined Types:\"(?i(?=[bcdfilps]))<(?iboolean|character|count|duration|float|integer|long_float|long_integer|priority|short_float|short_integer|string)>\":::Storage Type::D\n\ Predefined Subtypes:\"(?i(?=[fnp]))<(?ifield|natural|number_base|positive|priority)>\":::Storage Type::D\n\ Reserved Words:\"(?i(?=[a-gil-pr-uwx]))<(?iabort|abs|accept|access|and|array|at|begin|body|case|constant|declare|delay|delta|digits|do|else|elsif|end|entry|exception|exit|for|function|generic|goto|if|in|is|limited|loop|mod|new|not|null|of|or|others|out|package|pragma|private|procedure|raise|range|record|rem|renames|return|reverse|select|separate|subtype|task|terminate|then|type|use|when|while|with|xor)>\":::Keyword::D\n\ Dot All:\"\\.(?iall)>\":::Storage Type::\n\ Ada 95 Only:\"(?i(?=[aprtu]))<(?iabstract|tagged|all|protected|aliased|requeue|until)>\":::Keyword::\n\ Labels Parent:\"<(\\l[\\l\\d]*(?:_[\\l\\d]+)*)(?n\\s*:\\s*)(?ifor|while|loop|declare|begin)>\":::Keyword::D\n\ Labels subpattern:\"\\1\":\"\"::Label:Labels Parent:DC\n\ Endloop labels:\"<(?nend\\s+loop\\s+(\\l[\\l\\d]*(?:_[\\l\\d]+)*\\s*));\":::Keyword::\n\ Endloop labels subpattern:\"\\1\":\"\"::Label:Endloop labels:C\n\ Goto labels:\"\\<\\<\\l[\\l\\d]*(?:_[\\l\\d]+)*\\>\\>\":::Flag::\n\ Exit parent:\"((?iexit))\\s+(\\l\\w*)(?i\\s+when>)?\":::Keyword::\n\ Exit subpattern:\"\\2\":\"\"::Label:Exit parent:C\n\ Identifiers:\"<(?:\\l[\\l\\d]*(?:_[\\l\\d]+)*)>\":::Identifier::D}", "Awk:2:0{\n\ Comment:\"#\":\"$\"::Comment::\n\ Pattern:\"/(\\\\.|([[][]]?[^]]+[]])|[^/])+/\":::Preprocessor::\n\ Keyword:\"<(return|print|printf|if|else|while|for|in|do|break|continue|next|exit|close|system|getline)>\":::Keyword::D\n\ String:\"\"\"\":\"\"\"\":\"\\n\":String1::\n\ String escape:\"\\\\(.|\\n)\":::String1:String:\n\ Builtin functions:\"<(atan2|cos|exp|int|log|rand|sin|sqrt|srand|gsub|index|length|match|split|sprintf|sub|substr)>\":::Keyword::D\n\ Gawk builtin functions:\"<(fflush|gensub|tolower|toupper|systime|strftime)>\":::Text Key1::D\n\ Builtin variables:\"<(ARGC|ARGV|FILENAME|FNR|FS|NF|NR|OFMT|OFS|ORS|RLENGTH|RS|RSTART|SUBSEP)>\":::Storage Type::D\n\ Gawk builtin variables:\"\"\"<(ARGIND|ERRNO|RT|IGNORECASE|FIELDWIDTHS)>\"\"\":::Storage Type::D\n\ Field:\"\\$[0-9a-zA-Z_]+|\\$[ \\t]*\\([^,;]*\\)\":::Storage Type::D\n\ BeginEnd:\"<(BEGIN|END)>\":::Preprocessor1::D\n\ Numeric constant:\"(?\":\"$\"::Preprocessor::\n\ string escape chars:\"\\\\(?:.|\\n)\":::String1:string:\n\ preprocessor esc chars:\"\\\\(?:.|\\n)\":::Preprocessor1:preprocessor line:\n\ preprocessor comment:\"/\\*\":\"\\*/\"::Comment:preprocessor line:\n\ preproc cplus comment:\"//\":\"$\"::Comment:preprocessor line:\n\ preprocessor string:\"L?\"\"\":\"\"\"\":\"\\n\":Preprocessor1:preprocessor line:\n\ prepr string esc chars:\"\\\\(?:.|\\n)\":::String1:preprocessor string:\n\ preprocessor keywords:\"<__(?:LINE|FILE|DATE|TIME|STDC)__>\":::Preprocessor::\n\ character constant:\"L?'\":\"'\":\"[^\\\\][^']\":Character Const::\n\ numeric constant:\"(?\":::Storage Type::D\n\ keyword:\"<(?:new|delete|this|return|goto|if|else|case|default|switch|break|continue|while|do|for|try|catch|throw|sizeof|true|false|namespace|using|dynamic_cast|static_cast|reinterpret_cast|const_cast)>\":::Keyword::D\n\ braces:\"[{}]\":::Keyword::D}", "C:1:0 {\n\ comment:\"/\\*\":\"\\*/\"::Comment::\n\ string:\"L?\"\"\":\"\"\"\":\"\\n\":String::\n\ preprocessor line:\"^\\s*#\\s*(?:include|define|if|ifn?def|line|error|else|endif|elif|undef|pragma)>\":\"$\"::Preprocessor::\n\ string escape chars:\"\\\\(?:.|\\n)\":::String1:string:\n\ preprocessor esc chars:\"\\\\(?:.|\\n)\":::Preprocessor1:preprocessor line:\n\ preprocessor comment:\"/\\*\":\"\\*/\"::Comment:preprocessor line:\n\ preprocessor string:\"L?\"\"\":\"\"\"\":\"\\n\":Preprocessor1:preprocessor line:\n\ prepr string esc chars:\"\\\\(?:.|\\n)\":::String1:preprocessor string:\n\ preprocessor keywords:\"<__(?:LINE|FILE|DATE|TIME|STDC)__>\":::Preprocessor::\n\ character constant:\"L?'\":\"'\":\"[^\\\\][^']\":Character Const::\n\ numeric constant:\"(?\":::Storage Type::D\n\ keyword:\"<(?:return|goto|if|else|case|default|switch|break|continue|while|do|for|sizeof)>\":::Keyword::D\n\ braces:\"[{}]\":::Keyword::D}", "CSS:1:0{\n\ comment:\"/\\*\":\"\\*/\"::Comment::\n\ import rule:\"@import\\s+(url\\([^)]+\\))\\s*\":\";\"::Warning::\n\ import delim:\"&\":\"&\"::Preprocessor:import rule:C\n\ import url:\"\\1\":::Subroutine1:import rule:C\n\ import media:\"(all|screen|print|projection|aural|braille|embossed|handheld|tty|tv|,)\":::Preprocessor1:import rule:\n\ media rule:\"(@media)\\s+\":\"(?=\\{)\"::Warning::\n\ media delim:\"&\":\"&\"::Preprocessor:media rule:C\n\ media type:\"(all|screen|print|projection|aural|braille|embossed|handheld|tty|tv|,)\":::Preprocessor1:media rule:\n\ charset rule:\"@charset\\s+(\"\"[^\"\"]+\"\")\\s*;\":::Preprocessor::\n\ charset name:\"\\1\":::String:charset rule:C\n\ font-face rule:\"@font-face\":::Preprocessor::\n\ page rule:\"@page\":\"(?=\\{)\"::Preprocessor1::\n\ page delim:\"&\":\"&\"::Preprocessor:page rule:C\n\ page pseudo class:\":(first|left|right)\":::Storage Type:page rule:\n\ declaration:\"\\{\":\"\\}\"::Warning::\n\ declaration delims:\"&\":\"&\"::Keyword:declaration:C\n\ declaration comment:\"/\\*\":\"\\*/\"::Comment:declaration:\n\ property:\"<(azimuth|background(-(attachment|color|image|position|repeat))?|border(-(bottom(-(color|style|width))?|-(color|style|width)|collapse|color|left(-(color|style|width))?|right(-(color|style|width))?|spacing|style|top(-(color|style|width))?|width))?|bottom|caption-side|clear|clip|color|content|counter-(increment|reset)|cue(-(after|before))?|cursor|direction|display|elevation|empty-cells|float|font(-(family|size|size-adjust|stretch|style|variant|weight))?|height|left|letter-spacing|line-height|list-style(-(image|position|type))?|margin(-(bottom|left|right|top))?|marker-offset|marks|max-(height|width)|min-(height|width)|orphans|outline(-(color|style|width))?|overflow|padding(-(bottom|left|right|top))?|page(-break-(after|before|inside))?|pause(-(after|before))?|pitch(-range)?|play-during|position|quotes|richness|right|size|speak(-(header|numeral|punctuation))?|speech-rate|stress|table-layout|text(-(align|decoration|indent|shadow|transform))|top|unicode-bidi|vertical-align|visibility|voice-family|volume|white-space|widows|width|word-spacing|z-index)>\":::Identifier1:declaration:\n\ value:\":\":\";\":\"\\}\":Warning:declaration:\n\ value delims:\"&\":\"&\"::Keyword:value:C\n\ value modifier:\"!important|inherit\":::Keyword:value:\n\ uri value:\")?\\)|)?\\)\":::Subroutine:value:\n\ color value:\"(#[A-Fa-f\\d]{6}>|#[A-Fa-f\\d]{3}>|rgb\\(([+-]?\\d+(\\.\\d*)?)\\s*,\\s*([+-]?\\d+(\\.\\d*)?)\\s*,\\s*([+-]?\\d+(\\.\\d*)?)\\)|rgb\\(([+-]?\\d+(\\.\\d*)?%)\\s*,\\s*([+-]?\\d+(\\.\\d*)?%)\\s*,\\s*([+-]?\\d+(\\.\\d*)?%)\\)|<(?iaqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow)>|)\":::Text Arg2:value:\n\ dimension value:\"[+-]?(\\d*\\.\\d+|\\d+)(in|cm|mm|pt|pc|em|ex|px|deg|grad|rad|s|ms|hz|khz)>\":::Numeric Const:value:\n\ percentage value:\"[+-]?(\\d*\\.\\d+|\\d+)%\":::Numeric Const:value:\n\ named value:\"<(100|200|300|400|500|600|700|800|900|above|absolute|always|armenian|auto|avoid|baseline|behind|below|bidi-override|blink|block|bold|bolder|both|bottom|capitalize|caption|center(?:-left|-right)?|child|circle|cjk-ideographic|close-quote|code|collapse|compact|condensed|continuous|crop|cross(?:hair)?|cursive|dashed|decimal(?:-leading-zero)?|default|digits|disc|dotted|double|e-resize|embed|expanded|extra(?:-condensed|-expanded)|fantasy|far(?:-left|-right)|fast(?:er)?|female|fixed|georgian|groove|hebrew|help|hidden|hide|high(?:er)?|hiragana(?:-iroha)?|icon|inherit|inline(?:-table)?|inset|inside|italic|justify|katakana(?:-iroha)?|landscape|larger?|left(?:-side|wards)?|level|lighter|line-through|list-item|loud|low(?:er(?:-alpha|-greek|-latin|-roman|case)?)?|ltr|male|marker|medium|menu|message-box|middle|mix|monospace|move|n-resize|narrower|ne-resize|no(?:-close-quote|-open-quote|-repeat)|none|normal|nowrap|nw-resize|oblique|once|open-quote|out(?:set|side)|overline|pointer|portrait|pre|relative|repeat(?:-x|-y)?|ridge|right(?:-side|wards)?|rtl|run-in|s-resize|sans-serif|scroll|se-resize|semi(?:-condensed|-expanded)|separate|serif|show|silent|slow(?:er)?|small(?:-caps|-caption|er)?|soft|solid|spell-out|square|static|status-bar|sub|super|sw-resize|table(?:-caption|-cell|-column(?:-group)?|-footer-group|-header-group|-row(?:-group)?)?|text(?:-bottom|-top)?|thick|thin|top|ultra(?:-condensed|-expanded)|underline|upper(?:-alpha|-latin|-roman|case)|visible|w-resize|wait|wider|x-(?:fast|high|large|loud|low|slow|small|soft)|xx-(large|small))>\":::Text Arg2:value:\n\ integer value:\"<\\d+>\":::Numeric Const:value:\n\ font family:\"(?iarial|courier|impact|helvetica|lucida|symbol|times|verdana)\":::String:value:\n\ dq string value:\"\"\"\":\"\"\"\":\"\\n\":String:value:\n\ dq string escape:\"\\\\([ -~\\0200-\\0377]|[\\l\\d]{1,6}\\s?)\":::Text Escape:dq string value:\n\ dq string continuation:\"\\\\\\n\":::Text Escape:dq string value:\n\ sq string value:\"'\":\"'\":\"\\n\":String:value:\n\ sq string escape:\"\\\\([ -~\\0200-\\0377]|[\\l\\d]{1,6}\\s?)\":::Text Escape:sq string value:\n\ sq string continuation:\"\\\\\\n\":::Text Escape:sq string value:\n\ operators:\"[,/]\":::Keyword:value:\n\ selector id:\"#[-\\w]+>\":::Pointer::\n\ selector class:\"\\.[-\\w]+>\":::Storage Type::\n\ selector pseudo class:\":(first-child|link|visited|hover|active|focus|lang(\\([\\-\\w]+\\))?)(?!\\Y)\":::Text Arg1::\n\ selector attribute:\"\\[[^\\]]+\\]\":::Ada Attributes::\n\ selector operators:\"[,>*+]\":::Keyword::\n\ selector pseudo element:\":(first-letter|first-line|before|after)>\":::Text Arg::\n\ type selector:\"<[\\l_][-\\w]*>\":::Plain::\n\ free text:\".\":::Warning::\n\ info:\"(?# version 1.31; author/maintainer: Joor Loohuis, joor@loohuis-consulting.nl)\":::Plain::D}", "Csh:1:0{\n\ Comment:\"#\":\"$\"::Comment::\n\ Single Quote String:\"'\":\"([^\\\\]'|^')\":\"\\n\":String::\n\ SQ String Esc Char:\"\\\\([bcfnrt$\\n\\\\]|[0-9][0-9]?[0-9]?)\":::String1:Single Quote String:\n\ Double Quote String:\"\"\"\":\"\"\"\":\"\\n\":String::\n\ DQ String Esc Char:\"\\\\([bcfnrt\\n\\\\]|[0-9][0-9]?[0-9]?)\":::String1:Double Quote String:\n\ Keywords:\"(^|[`;()])[ ]*(return|if|endif|then|else|switch|endsw|while|end|foreach|do|done)>\":::Keyword::D\n\ Variable Ref:\"\\$([<$0-9\\*]|[#a-zA-Z_?][0-9a-zA-Z_[\\]]*(:([ehqrtx]|gh|gt|gr))?|\\{[#0-9a-zA-Z_?][a-zA-Z0-9_[\\]]*(:([ehqrtx]|gh|gt|gr))?})\":::Identifier1::\n\ Variable in String:\"\\$([<$0-9\\*]|[#a-zA-Z_?][0-9a-zA-Z_[\\]]*(:([ehqrtx]|gh|gt|gr))?|\\{[#0-9a-zA-Z_?][a-zA-Z0-9_[\\]]*(:([ehqrtx]|gh|gt|gr))?})\":::Identifier1:Double Quote String:\n\ Naked Variable Cmds:\"<(unset|set|setenv|shift)[ \\t]+[0-9a-zA-Z_]*(\\[.+\\])?\":::Identifier1::\n\ Recolor Naked Cmd:\"\\1\":::Keyword:Naked Variable Cmds:C\n\ Built In Cmds:\"(^|\\|&|[\\|`;()])[ ]*(alias|bg|break|breaksw|case|cd|chdir|continue|default|echo|eval|exec|exit|fg|goto|glob|hashstat|history|jobs|kill|limit|login|logout|nohup|notify|nice|onintr|popd|pushd|printenv|read|rehash|repeat|set|setenv|shift|source|suspend|time|umask|unalias|unhash|unlimit|unset|unsetenv|wait)>\":::Keyword::D\n\ Tcsh Built In Cmds:\"(^|\\|&|[\\|`;()])[ ]*(alloc|bindkey|builtins|complete|echotc|filetest|hup|log|sched|settc|setty|stop|telltc|uncomplete|where|which|dirs|ls-F)>\":::Keyword::D\n\ Special Chars:\"([-{};.,<>&~=!|^%[\\]\\+\\*\\|()])\":::Keyword::D}", "Fortran:2:0{\n\ Comment:\"^[Cc*!]\":\"$\"::Comment::\n\ Bang Comment:\"!\":\"$\"::Comment::\n\ Debug Line:\"^D\":\"$\"::Preprocessor::\n\ String:\"'\":\"'\":\"\\n([^ \\t]| [^ \\t]| [^ \\t]| [^ \\t]| [^ \\t]| [ \\t0]| *\\t[^1-9])\":String::\n\ Keywords:\"<(?iaccept|automatic|backspace|block|call|close|common|continue|data|decode|delete|dimension|do|else|elseif|encode|enddo|end *file|endif|end|entry|equivalence|exit|external|format|function|go *to|if|implicit|include|inquire|intrinsic|logical|map|none|on|open|parameter|pause|pointer|print|program|read|record|return|rewind|save|static|stop|structure|subroutine|system|then|type|union|unlock|virtual|volatile|while|write)>\":::Keyword::D\n\ Data Types:\"<(?ibyte|character|complex|double *complex|double *precision|double|integer|real)(\\*[0-9]+)?>\":::Keyword::D\n\ F90 Keywords:\"<(?iallocatable|allocate|case|case|cycle|deallocate|elsewhere|namelist|recursive|rewrite|select|where|intent|optional)>\":::Keyword::D\n\ Continuation:\"^( [^ \\t0]|( | | | )?\\t[1-9])\":::Flag::\n\ Continuation in String:\"\\n( [^ \\t0]|( | | | )?\\t[1-9])\":::Flag:String:}", "Java:3:0{\n\ README:\"Java highlighting patterns for NEdit 5.1. Version 1.5 Author/maintainer: Joachim Lous - jlous at users.sourceforge.net\":::Flag::D\n\ doccomment:\"/\\*\\*\":\"\\*/\"::Text Comment::\n\ doccomment tag:\"@\\l*\":::Text Key1:doccomment:\n\ comment:\"/\\*\":\"\\*/\"::Comment::\n\ cplus comment:\"//\":\"$\"::Comment::\n\ string:\"\"\"\":\"\"\"\":\"\\n\":String::\n\ string escape:\"(?:\\\\u[\\dA-Faf]{4}|\\\\[0-7]{1,3}|\\\\[btnfr'\"\"\\\\])\":::String1:string:\n\ single quoted:\"'\":\"'\":\"\\n\":String::\n\ single quoted escape:\"(?:\\\\u[\\dA-Faf]{4}|\\\\[0-7]{1,3}|\\\\[btnfr'\"\"\\\\])(?=')\":::String1:single quoted:\n\ single quoted char:\".(?=')\":::String:single quoted:\n\ single quoted error:\".\":::Flag:single quoted:\n\ hex const:\"<(?i0[X][\\dA-F]+)>\":::Numeric Const::\n\ long const:\"<(?i[\\d]+L)>\":::Numeric Const::\n\ decimal const:\"(?\":\";\":\"\\n\":Preprocessor::\n\ classdef:\"<(?:class|interface)>\\s*\\n?\\s*([\\l_]\\w*)\":::Keyword::\n\ classdef name:\"\\1\":\"\"::Storage Type:classdef:C\n\ extends:\"<(?:extends)>\":\"(?=(?:|[{;]))\"::Keyword::\n\ extends argument:\"<[\\l_][\\w\\.]*(?=\\s*(?:/\\*.*\\*/)?(?://.*)?\\n?\\s*(?:[,;{]|))\":::Storage Type:extends:\n\ extends comma:\",\":::Keyword:extends:\n\ extends comment:\"/\\*\":\"\\*/\"::Comment:extends:\n\ extends cpluscomment:\"//\":\"$\"::Comment:extends:\n\ extends error:\".\":::Flag:extends:\n\ impl_throw:\"<(?:implements|throws)>\":\"(?=[{;])\"::Keyword::\n\ impl_throw argument:\"<[\\l_][\\w\\.]*(?=\\s*(?:/\\*.*\\*/)?(?://.*)?\\n?\\s*[,;{])\":::Storage Type:impl_throw:\n\ impl_throw comma:\",\":::Keyword:impl_throw:\n\ impl_throw comment:\"/\\*\":\"\\*/\"::Comment:impl_throw:\n\ impl_throw cpluscomment:\"//\":\"$\"::Comment:impl_throw:\n\ impl_throw error:\".\":::Flag:impl_throw:\n\ case:\"\":\":\"::Label::\n\ case single quoted:\"'\\\\?[^']'\":::Character Const:case:\n\ case numeric const:\"(?^&|%()]\":::Keyword:case:\n\ case error:\".\":::Flag:case:\n\ label:\"([;{}:])\":\"[\\l_]\\w*\\s*:\":\"[^\\s\\n]\":Label::\n\ label qualifier:\"\\1\":\"\"::Keyword:label:C\n\ labelref:\"<(?:break|continue)>\\s*\\n?\\s*([\\l_]\\w*)?(?=\\s*\\n?\\s*;)\":::Keyword::\n\ labelref name:\"\\1\":\"\"::Label:labelref:C\n\ instanceof:\"\\s*\\n?\\s*([\\l_][\\w.]*)\":::Keyword::\n\ instanceof class:\"\\1\":\"\"::Storage Type:instanceof:C\n\ newarray:\"new\\s*[\\n\\s]\\s*([\\l_][\\w\\.]*)\\s*\\n?\\s*(?=\\[)\":::Keyword::\n\ newarray type:\"\\1\":\"\"::Storage Type:newarray:C\n\ constructor def:\"<(abstract|final|native|private|protected|public|static|synchronized)\\s*[\\n|\\s]\\s*[\\l_]\\w*\\s*\\n?\\s*(?=\\()\":::Subroutine::\n\ constructor def modifier:\"\\1\":\"\"::Keyword:constructor def:C\n\ keyword - modifiers:\"<(?:abstract|final|native|private|protected|public|static|transient|synchronized|volatile)>\":::Keyword::\n\ keyword - control flow:\"<(?:catch|do|else|finally|for|if|return|switch|throw|try|while)>\":::Keyword::\n\ keyword - calc value:\"<(?:new|super|this)>\":::Keyword::\n\ keyword - literal value:\"<(?:false|null|true)>\":::Numeric Const::\n\ function def:\"<([\\l_][\\w\\.]*)>((?:\\s*\\[\\s*\\])*)\\s*[\\n|\\s]\\s*<[\\l_]\\w*>\\s*\\n?\\s*(?=\\()\":::Plain::\n\ function def type:\"\\1\":\"\"::Storage Type:function def:C\n\ function def type brackets:\"\\2\":\"\"::Keyword:function def:C\n\ function call:\"<[\\l_]\\w*>\\s*\\n?\\s*(?=\\()\":::Plain::\n\ cast:\"[^\\w\\s]\\s*\\n?\\s*\\(\\s*([\\l_][\\w\\.]*)\\s*\\)\":::Keyword::\n\ cast type:\"\\1\":\"\"::Storage Type:cast:C\n\ declaration:\"<[\\l_][\\w\\.]*>((:?\\s*\\[\\s*\\]\\s*)*)(?=\\s*\\n?\\s*(?!instanceof)[\\l_]\\w*)\":::Storage Type::\n\ declaration brackets:\"\\1\":\"\"::Keyword:declaration:C\n\ variable:\"<[\\l_]\\w*>\":::Identifier1::D\n\ braces and parens:\"[(){}[\\]]\":::Keyword::D\n\ signs:\"[-+*/%=,.;:<>!|&^?]\":::Keyword::D\n\ error:\".\":::Flag::D}", #ifndef VMS /* The VAX C compiler cannot compile this definition */ "JavaScript:1:0{\n\ DSComment:\"//\":\"$\"::Comment::\n\ MLComment:\"/\\*\":\"\\*/\"::Comment::\n\ DQColors:\"aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dodgerblue|firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|gray|green|greenyellow|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgreen|lightgrey|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightsteelblue|lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|purple|red|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|snow|springgreen|steelblue|tan|teal|thistle|tomato|turquoise|violet|wheat|white|whitesmoke|yellow|yellowgreen|#[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]\":::Text Arg1:DQStrings:\n\ SQColors:\"aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dodgerblue|firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|gray|green|greenyellow|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgreen|lightgrey|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightsteelblue|lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|purple|red|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|snow|springgreen|steelblue|tan|teal|thistle|tomato|turquoise|violet|wheat|white|whitesmoke|yellow|yellowgreen|(#)[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-F-af0-9]\":::Text Arg1:SQStrings:\n\ Numeric:\"(?\":::Keyword::\n\ Braces:\"[{}]\":::Keyword::\n\ Statements:\"<(break|continue|else|for|if|in|new|return|this|typeof|var|while|with)>\":::Keyword::\n\ Function:\"function[\\t ]+([a-zA-Z0-9_]+)[\\t \\(]+\":\"[\\n{]\"::Keyword::\n\ FunctionName:\"\\1\":\"\"::Storage Type:Function:C\n\ FunctionArgs:\"\\(\":\"\\)\"::Text Arg:Function:\n\ Parentheses:\"[\\(\\)]\":::Plain::\n\ BuiltInObjectType:\"<(anchor|Applet|Area|Array|button|checkbox|Date|document|elements|FileUpload|form|frame|Function|hidden|history|Image|link|location|Math|navigator|Option|password|Plugin|radio|reset|select|string|submit|text|textarea|window)>\":::Storage Type::\n\ SQStrings:\"'\":\"'\":\"\\n\":String::\n\ DQStrings:\"\"\"\":\"\"\"\":\"\\n\":String::\n\ EventCapturing:\"captureEvents|releaseEvents|routeEvent|handleEvent\":\"\\)\":\"\\n\":Keyword::\n\ PredefinedMethods:\"<(abs|acos|alert|anchor|asin|atan|atan2|back|big|blink|blur|bold|ceil|charAt|clear|clearTimeout|click|close|confirm|cos|escape|eval|exp|fixed|floor|focus|fontcolor|fontsize|forward|getDate|getDay|getHours|getMinutes|getMonth|getSeconds|getTime|getTimezoneOffset|getYear|go|indexOf|isNaN|italics|javaEnabled|join|lastIndexOf|link|log|max|min|open|parse|parseFloat|parseInt|pow|prompt|random|reload|replace|reset|reverse|round|scroll|select|setDate|setHours|setMinutes|setMonth|setSeconds|setTimeout|setTime|setYear|sin|small|sort|split|sqrt|strike|sub|submit|substring|sup|taint|tan|toGMTString|toLocaleString|toLowerCase|toString|toUpperCase|unescape|untaint|UTC|write|writeln)>\":::Keyword::\n\ Properties:\"<(action|alinkColor|anchors|appCodeName|appName|appVersion|bgColor|border|checked|complete|cookie|defaultChecked|defaultSelected|defaultStatus|defaultValue|description|E|elements|enabledPlugin|encoding|fgColor|filename|forms|frames|hash|height|host|hostname|href|hspace|index|lastModified|length|linkColor|links|LN2|LN10|LOG2E|LOG10E|lowsrc|method|name|opener|options|parent|pathname|PI|port|protocol|prototype|referrer|search|selected|selectedIndex|self|SQRT1_2|SQRT2|src|status|target|text|title|top|type|URL|userAgent|value|vlinkColor|vspace|width|window)>\":::Storage Type::\n\ Operators:\"[= ; ->]|[/]|&|\\|\":::Preprocessor::}", #endif /*VMS*/ "LaTeX:1:0{\n\ Comment:\"%\":\"$\"::Text Comment::\n\ Parameter:\"#[0-9]*\":::Text Arg::\n\ Special Chars:\"[{}&]\":::Keyword::\n\ Escape Chars:\"\\\\[$&%#_{}]\":::Text Escape::\n\ Super Sub 1 Char:\"(?:\\^|_)(?:\\\\\\l+|#\\d|[^{\\\\])\":::Text Arg2::\n\ Verbatim Begin End:\"\\\\begin\\{verbatim\\*?}\":\"\\\\end\\{verbatim\\*?}\"::Plain::\n\ Verbatim BG Color:\"&\":\"&\"::Keyword:Verbatim Begin End:C\n\ Verbatim:\"(\\\\verb\\*?)([^\\l\\s\\*]).*?(\\2)\":::Plain::\n\ Verbatim Color:\"\\1\\2\\3\":\"\"::Keyword:Verbatim:C\n\ Inline Math:\"(?/~.,\\\\ ])\":\"nevermatch\":\"[^{[(]\":Text Key::\n\ Cmd Brace Args:\"\\{\":\"}\":\"(?<=^%)|\\\\]|\\$\\$|\\\\end\\{equation\\}\":Text Arg2:Command:\n\ Brace Color:\"&\":\"&\"::Text Arg:Cmd Brace Args:C\n\ Cmd Paren Args:\"\\(\":\"\\)\":\"$\":Text Arg2:Command:\n\ Paren Color:\"&\":\"&\"::Text Arg:Cmd Paren Args:C\n\ Cmd Bracket Args:\"\\[\":\"\\]\":\"$|\\\\\\]\":Text Arg2:Command:\n\ Bracket Color:\"&\":\"&\"::Text Arg:Cmd Bracket Args:C\n\ Sub Cmd Bracket Args Esc:\"\\\\\\}\":::Plain:Sub Cmd Bracket Args:\n\ Sub Cmd Bracket Args:\"\\{\":\"\\}\":\"$|\\\\\\]\":Preprocessor1:Cmd Bracket Args:\n\ Sub Command:\"(?:[_^]|(?:[\\\\@](?:[A-Za-z]+\\*?|[^A-Za-z$&%#{}~\\\\ \\t])))\":::Text Key1:Cmd Brace Args:\n\ Sub Brace:\"\\{\":\"}\"::Text Arg2:Cmd Brace Args:\n\ Sub Sub Brace:\"\\{\":\"}\"::Text Arg2:Sub Brace:\n\ Sub Sub Sub Brace:\"\\{\":\"}\"::Text Arg2:Sub Sub Brace:\n\ Sub Sub Sub Sub Brace:\"\\{\":\"}\"::Text Arg2:Sub Sub Sub Brace:\n\ Sub Paren:\"\\(\":\"\\)\":\"$\":Text Arg2:Cmd Paren Args:\n\ Sub Sub Paren:\"\\(\":\"\\)\":\"$\":Text Arg2:Sub Paren:\n\ Sub Sub Sub Paren:\"\\(\":\"\\)\":\"$\":Text Arg2:Sub Sub Paren:\n\ Sub Parameter:\"#[0-9]*\":::Text Arg:Cmd Brace Args:\n\ Sub Spec Chars:\"[{}$&]\":::Text Arg:Cmd Brace Args:\n\ Sub Esc Chars:\"\\\\[$&%#_{}~^\\\\]\":::Text Arg1:Cmd Brace Args:}", "Lex:1:0{\n\ comment:\"/\\*\":\"\\*/\"::Comment::\n\ string:\"L?\"\"\":\"\"\"\":\"\\n\":String::\n\ meta string:\"\\\\\"\".*\\\\\"\"\":::String::\n\ preprocessor line:\"^\\s*#\\s*(include|define|if|ifn?def|line|error|else|endif|elif|undef|pragma)>\":\"$\"::Preprocessor::\n\ string escape chars:\"\\\\(.|\\n)\":::String1:string:\n\ preprocessor esc chars:\"\\\\(.|\\n)\":::Preprocessor1:preprocessor line:\n\ preprocessor comment:\"/\\*\":\"\\*/\"::Comment:preprocessor line:\n\ preprocessor string:\"L?\"\"\":\"\"\"\":\"\\n\":Preprocessor1:preprocessor line:\n\ prepr string esc chars:\"\\\\(?:.|\\n)\":::String1:preprocessor string:\n\ character constant:\"'\":\"'\":\"[^\\\\][^']\":Character Const::\n\ numeric constant:\"(?\":::Storage Type::D\n\ keyword:\"<(return|goto|if|else|case|default|switch|break|continue|while|do|for|sizeof)>\":::Keyword::D\n\ lex keyword:\"<(yylval|yytext|input|unput|output|lex_input|lex_output|yylex|yymore|yyless|yyin|yyout|yyleng|yywtext|yywleng|yyterminate|REJECT|ECHO|BEGIN|YY_NEW_FILE|yy_create_buffer|yy_switch_to_buffer|yy_delete_buffer|YY_CURRENT_BUFFER|YY_BUFFER_STATE|YY_DECL|YY_INPUT|yywrap|YY_USER_ACTION|YY_USER_INIT|YY_BREAK)>\":::Text Arg::D\n\ stdlib:\"<(BUFSIZ|CHAR_BIT|CHAR_MAX|CHAR_MIN|CLOCKS_PER_SEC|DBL_DIG|DBL_EPSILON|DBL_MANT_DIG|DBL_MAX|DBL_MAX_10_EXP|DBL_MAX_EXP|DBL_MIN|DBL_MIN_10_EXP|DBL_MIN_EXP|EDOM|EOF|ERANGE|EXIT_FAILURE|EXIT_SUCCESS|FILE|FILENAME_MAX|FLT_DIG|FLT_EPSILON|FLT_MANT_DIG|FLT_MAX|FLT_MAX_10_EXP|FLT_MAX_EXP|FLT_MIN|FLT_MIN_10_EXP|FLT_MIN_EXP|FLT_RADIX|FLT_ROUNDS|FOPEN_MAX|HUGE_VAL|INT_MAX|INT_MIN|LC_ALL|LC_COLLATE|LC_CTYPE|LC_MONETARY|LC_NUMERIC|LC_TIME|LDBL_DIG|LDBL_EPSILON|LDBL_MANT_DIG|LDBL_MAX|LDBL_MAX_10_EXP|LDBL_MAX_EXP|LDBL_MIN|LDBL_MIN_10_EXP|LDBL_MIN_EXP|LONG_MAX|LONG_MIN|L_tmpnam|MB_CUR_MAX|MB_LEN_MAX|NULL|RAND_MAX|SCHAR_MAX|SCHAR_MIN|SEEK_CUR|SEEK_END|SEEK_SET|SHRT_MAX|SHRT_MIN|SIGABRT|SIGFPE|SIGILL|SIGINT|SIGSEGV|SIGTERM|SIG_DFL|SIG_ERR|SIG_IGN|TMP_MAX|UCHAR_MAX|UINT_MAX|ULONG_MAX|USHRT_MAX|WCHAR_MAX|WCHAR_MIN|WEOF|_IOFBF|_IOLBF|_IONBF|abort|abs|acos|asctime|asin|assert|atan|atan2|atexit|atof|atoi|atol|bsearch|btowc|calloc|ceil|clearerr|clock|clock_t|cos|cosh|ctime|difftime|div|div_t|errno|exit|exp|fabs|fclose|feof|ferror|fflush|fgetc|fgetpos|fgets|fgetwc|fgetws|floor|fmod|fopen|fpos_t|fprintf|fputc|fputs|fputwc|fputws|fread|free|freopen|frexp|fscanf|fseek|fsetpos|ftell|fwide|fwprintf|fwrite|fwscanf|getc|getchar|getenv|gets|getwc|getwchar|gmtime|isalnum|isalpha|iscntrl|isdigit|isgraph|islower|isprint|ispunct|isspace|isupper|iswalnum|iswalpha|iswcntrl|iswctype|iswdigit|iswgraph|iswlower|iswprint|iswpunct|iswspace|iswupper|iswxdigit|isxdigit|jmp_buf|labs|lconv|ldexp|ldiv|ldiv_t|localeconv|localtime|log|log10|longjmp|malloc|mblen|mbrlen|mbrtowc|mbsinit|mbsrtowcs|mbstate_t|mbstowcs|mbtowc|memchr|memcmp|memcpy|memmove|memset|mktime|modf|offsetof|perror|pow|printf|ptrdiff_t|putc|puts|putwc|putwchar|qsort|raise|rand|realloc|remove|rename|rewind|scanf|setbuf|setjmp|setlocale|setvbuf|sig_atomic_t|signal|sin|sinh|size_t|sprintf|sqrt|srand|sscanf|stderr|stdin|stdout|strcat|strchr|strcmp|strcoll|strcpy|strcspn|strerror|strftime|strlen|strncat|strncmp|strncpy|stroul|strpbrk|strrchr|strspn|strstr|strtod|strtok|strtol|strxfrm|swprintf|swscanf|system|tan|tanh|time|time_t|tm|tmpfile|tmpnam|tolower|toupper|towctrans|towlower|towupper|ungetc|ungetwc|va_arg|va_end|va_list|va_start|vfwprintf|vprintf|vsprintf|vswprintf|vwprintf|wint_t|wmemchr|wmemcmp|wmemcpy|wmemmove|wmemset|wprintf|wscanf)>\":::Subroutine::D\n\ label:\"|(^[ \\t]*[A-Za-z_][A-Za-z0-9_]*[ \\t]*:)\":::Flag::D\n\ braces:\"[{}]\":::Keyword::D\n\ markers:\"(?[ \\t]\":\"$\"::Keyword::\n\ Exports var:\".[A-Za-z0-9_+]*\":\"$\"::Keyword:Exports:\n\ Conditionals:\"^( *| [ \\t]*)[ \\t]\":::Keyword::D\n\ Conditionals ifdefs:\"^( *| [ \\t]*)[ \\t]\":\"$\"::Keyword::D\n\ Conditionals ifdefs var:\".[A-Za-z0-9_+]*\":\"$\"::Preprocessor:Conditionals ifdefs:D\n\ Conditional Ends:\"^( *| [ \\t]*)\":::Keyword::D\n\ vpath:\"^( *| [ \\t]*)[ \\t]\":::Keyword::D\n\ define:\"^( *| [ \\t]*)[ \\t]\":\"$\"::Keyword::D\n\ define var:\".[A-Za-z0-9_+]*\":\"$\"::Preprocessor:define:D\n\ define Ends:\"^( *| [ \\t]*)\":::Keyword::D}", "Matlab:1:0{\n\ Comment:\"%\":\"$\"::Comment::\n\ Comment in Octave:\"#\":\"$\"::Comment::\n\ Keyword:\"<(break|clear|else|elseif|for|function|global|if|return|then|while|end(if|for|while|function))>\":::Keyword::\n\ Transpose:\"[\\w.]('+)\":::Plain::\n\ Paren transposed:\"\\)('+)\":::Keyword::\n\ Paren transp close:\"\\1\":\"\"::Plain:Paren transposed:C\n\ Parentheses:\"[\\(\\)]\":::Keyword::\n\ Brackets transposed:\"\\]('+)\":::Text Key1::\n\ Brack transp close:\"\\1\":\"\"::Plain:Brackets transposed:C\n\ Brackets:\"[\\[\\]]\":::Text Key1::\n\ Braces transposed:\"\\}('+)\":::Text Arg::\n\ Braces transp close:\"\\1\":\"\"::Plain:Braces transposed:C\n\ Braces:\"[\\{\\}]\":::Text Arg::\n\ String:\"'\":\"'\"::String::\n\ Numeric const:\"(?=|\\<|\\>\":::Text Arg1::\n\ Wrong logical ops:\"&&|\\|\\|\":::Plain::\n\ Logical operators:\"~|&|\\|\":::Text Arg2::}", "NEdit Macro:2:0{\n\ README:\"NEdit Macro syntax highlighting patterns, version 2.6, maintainer Thorsten Haude, nedit at thorstenhau.de\":::Flag::D\n\ Comment:\"#\":\"$\"::Comment::\n\ Built-in Misc Vars:\"(?\":::Identifier::\n\ Built-in Pref Vars:\"(?\":::Identifier2::\n\ Built-in Special Vars:\"(?\":::String1::\n\ Built-in Subrs:\"<(?:append_file|beep|calltip|clipboard_to_string|dialog|focus_window|get_character|get_pattern_(by_name|at_pos)|get_range|get_selection|get_style_(by_name|at_pos)|getenv|kill_calltip|length|list_dialog|max|min|rangeset_(?:add|create|destroy|get_by_name|includes|info|invert|range|set_color|set_mode|set_name|subtract)|read_file|replace_in_string|replace_range|replace_selection|replace_substring|search|search_string|select|select_rectangle|set_cursor_pos|set_language_mode|set_locked|shell_command|split|string_compare|string_dialog|string_to_clipboard|substring|t_print|tolower|toupper|valid_number|write_file)>\":::Subroutine::\n\ Menu Actions:\"<(?:new|open|open-dialog|open_dialog|open-selected|open_selected|close|save|save-as|save_as|save-as-dialog|save_as_dialog|revert-to-saved|revert_to_saved|revert_to_saved_dialog|include-file|include_file|include-file-dialog|include_file_dialog|load-macro-file|load_macro_file|load-macro-file-dialog|load_macro_file_dialog|load-tags-file|load_tags_file|load-tags-file-dialog|load_tags_file_dialog|unload_tags_file|load_tips_file|load_tips_file_dialog|unload_tips_file|print|print-selection|print_selection|exit|undo|redo|delete|select-all|select_all|shift-left|shift_left|shift-left-by-tab|shift_left_by_tab|shift-right|shift_right|shift-right-by-tab|shift_right_by_tab|find|find-dialog|find_dialog|find-again|find_again|find-selection|find_selection|find_incremental|start_incremental_find|replace|replace-dialog|replace_dialog|replace-all|replace_all|replace-in-selection|replace_in_selection|replace-again|replace_again|replace_find|replace_find_same|replace_find_again|goto-line-number|goto_line_number|goto-line-number-dialog|goto_line_number_dialog|goto-selected|goto_selected|mark|mark-dialog|mark_dialog|goto-mark|goto_mark|goto-mark-dialog|goto_mark_dialog|match|select_to_matching|goto_matching|find-definition|find_definition|show_tip|split-window|split_window|close-pane|close_pane|uppercase|lowercase|fill-paragraph|fill_paragraph|control-code-dialog|control_code_dialog|filter-selection-dialog|filter_selection_dialog|filter-selection|filter_selection|execute-command|execute_command|execute-command-dialog|execute_command_dialog|execute-command-line|execute_command_line|shell-menu-command|shell_menu_command|macro-menu-command|macro_menu_command|bg_menu_command|post_window_bg_menu|beginning-of-selection|beginning_of_selection|end-of-selection|end_of_selection|repeat_macro|repeat_dialog|raise_window|focus_pane|set_statistics_line|set_incremental_search_line|set_show_line_numbers|set_auto_indent|set_wrap_text|set_wrap_margin|set_highlight_syntax|set_make_backup_copy|set_incremental_backup|set_show_matching|set_match_syntax_based|set_overtype_mode|set_locked|set_tab_dist|set_em_tab_dist|set_use_tabs|set_fonts|set_language_mode)(?=\\s*\\()\":::Subroutine::\n\ Text Actions:\"<(?:self-insert|self_insert|grab-focus|grab_focus|extend-adjust|extend_adjust|extend-start|extend_start|extend-end|extend_end|secondary-adjust|secondary_adjust|secondary-or-drag-adjust|secondary_or_drag_adjust|secondary-start|secondary_start|secondary-or-drag-start|secondary_or_drag_start|process-bdrag|process_bdrag|move-destination|move_destination|move-to|move_to|move-to-or-end-drag|move_to_or_end_drag|end_drag|copy-to|copy_to|copy-to-or-end-drag|copy_to_or_end_drag|exchange|process-cancel|process_cancel|paste-clipboard|paste_clipboard|copy-clipboard|copy_clipboard|cut-clipboard|cut_clipboard|copy-primary|copy_primary|cut-primary|cut_primary|newline|newline-and-indent|newline_and_indent|newline-no-indent|newline_no_indent|delete-selection|delete_selection|delete-previous-character|delete_previous_character|delete-next-character|delete_next_character|delete-previous-word|delete_previous_word|delete-next-word|delete_next_word|delete-to-start-of-line|delete_to_start_of_line|delete-to-end-of-line|delete_to_end_of_line|forward-character|forward_character|backward-character|backward_character|key-select|key_select|process-up|process_up|process-down|process_down|process-shift-up|process_shift_up|process-shift-down|process_shift_down|process-home|process_home|forward-word|forward_word|backward-word|backward_word|forward-paragraph|forward_paragraph|backward-paragraph|backward_paragraph|beginning-of-line|beginning_of_line|end-of-line|end_of_line|beginning-of-file|beginning_of_file|end-of-file|end_of_file|next-page|next_page|previous-page|previous_page|page-left|page_left|page-right|page_right|toggle-overstrike|toggle_overstrike|scroll-up|scroll_up|scroll-down|scroll_down|scroll_left|scroll_right|scroll-to-line|scroll_to_line|select-all|select_all|deselect-all|deselect_all|focusIn|focusOut|process-return|process_return|process-tab|process_tab|insert-string|insert_string|mouse_pan)>\":::Subroutine::\n\ Keyword:\"<(?:break|continue|define|delete|else|for|if|in|return|while)>\":::Keyword::\n\ Braces:\"[{}\\[\\]]\":::Keyword::\n\ Global Variable:\"\\$[A-Za-z0-9_]+\":::Identifier1::\n\ String:\"\"\"\":\"\"\"\":\"\\n\":String::\n\ String Escape Char:\"\\\\(?:.|\\n)\":::Text Escape:String:\n\ Numeric Const:\"(?\":::Numeric Const::\n\ Macro Definition:\"(?<=define)\\s+\\w+\":::Subroutine1::\n\ Custom Macro:\"\\w+(?=\\s*(?:\\\\\\n)?\\s*[\\(])\":::Subroutine1::\n\ Variables:\"\\w+\":::Identifier1::D}", "Pascal:1:0{\n\ TP Directives:\"\\{\\$\":\"\\}\"::Comment::\n\ Comment:\"\\(\\*|\\{\":\"\\*\\)|\\}\"::Comment::\n\ String:\"'\":\"'\":\"\\n\":String::D\n\ Array delimitors:\"\\(\\.|\\.\\)|\\[|\\]\":::Character Const::D\n\ Parentheses:\"\\(|\\)\":::Keyword::D\n\ X Numeric Values:\"<([2-9]|[12]\\d|3[0-6])#[\\d\\l]+>\":::Text Key::D\n\ TP Numeric Values:\"(?\":::Text Key1::D\n\ Numeric Values:\"<\\d+(\\.\\d+)?((e|E)(\\+|-)?\\d+)?>\":::Numeric Const::D\n\ Reserved Words 1:\"<(?iBegin|Const|End|Program|Record|Type|Var)>\":::Keyword::D\n\ Reserved Words 2:\"<(?iForward|Goto|Label|Of|Packed|With)>\":::Identifier::D\n\ X Reserved Words:\"<(?iBindable|Export|Implementation|Import|Interface|Module|Only|Otherwise|Protected|Qualified|Restricted|Value)>\":::Identifier1::D\n\ TP Reserved Words:\"<(?iAbsolute|Assembler|Exit|External|Far|Inline|Interrupt|Near|Private|Unit|Uses)>\":::Text Comment::D\n\ Data Types:\"<(?iArray|Boolean|Char|File|Integer|Real|Set|Text)>\":::Storage Type::D\n\ X Data Types:\"<(?iBindingType|Complex|String|TimeStamp)>\":::Text Arg1::D\n\ TP Data Types:\"<(?iByte|Comp|Double|Extended|LongInt|ShortInt|Single|Word)>\":::Text Arg2::D\n\ Predefined Consts:\"<(?iFalse|Input|MaxInt|Nil|Output|True)>\":::String1::D\n\ X Predefined Consts:\"<(?iEpsReal|MaxChar|MaxReal|MinReal|StandardInput|StandardOutput)>\":::String2::D\n\ Conditionals:\"<(?iCase|Do|DownTo|Else|For|If|Repeat|Then|To|Until|While)>\":::Ada Attributes::D\n\ Proc declaration:\"<(?iProcedure)>\":::Character Const::D\n\ Predefined Proc:\"<(?iDispose|Get|New|Pack|Page|Put|Read|ReadLn|Reset|Rewrite|Unpack|Write|WriteLn)>\":::Subroutine::D\n\ X Predefined Proc:\"<(?iBind|Extend|GetTimeStamp|Halt|ReadStr|SeekRead|SeekUpdate|SeekWrite|Unbind|Update|WriteStr)>\":::Subroutine1::D\n\ Func declaration:\"<(?iFunction)>\":::Identifier::D\n\ Predefined Func:\"<(?iAbs|Arctan|Chr|Cos|Eof|Eoln|Exp|Ln|Odd|Ord|Pred|Round|Sin|Sqr|Sqrt|Succ|Trunc)>\":::Preprocessor::D\n\ X Predefined Func:\"<(?iArg|Binding|Card|Cmplx|Date|Empty|Eq|Ge|Gt|Im|Index|LastPosition|Le|Length|Lt|Ne|Polar|Position|Re|SubStr|Time|Trim)>\":::Preprocessor1::D\n\ X Operators:\"(\\>\\<|\\*\\*)|<(?iAnd_Then|Or_Else|Pow)>\":::Text Arg1::D\n\ Assignment:\":=\":::Plain::D\n\ Operators:\"(\\<|\\>|=|\\^|@)|<(?iAnd|Div|In|Mod|Not|Or)>\":::Text Arg::D\n\ TP Operators:\"<(?iShl|Shr|Xor)>\":::Text Arg2::D}", "Perl:2:0{\n\ dq here doc:\"(\\<\\<(\"\"?))EOF(\\2.*)$\":\"^EOF>\"::Label::\n\ dq here doc delims:\"\\1\\3\":::Keyword:dq here doc:C\n\ dq here doc esc chars:\"\\\\([nrtfbaeulULQE@%\\$\\\\]|0[0-7]+|x[0-9a-fA-F]+|c\\l)\":::Text Escape:dq here doc:\n\ dq here doc variables:\"\\$([-_./,\"\"\\\\*?#;!@$<>(%=~^|&`'+[\\]]|:(?!:)|\\^[ADEFHILMOPSTWX]|ARGV|\\d{1,2})|(@|\\$#)(ARGV|EXPORT|EXPORT_OK|F|INC|ISA|_)>|%(ENV|EXPORT_TAGS|INC|SIG)>|(\\$#?|@|%)(::)?[\\l_](\\w|::(?=\\w))*|(\\$#?|@|%)\\{(::)?[\\l_](\\w|::(?=\\w))*\\}|(\\$|@|%)(?=\\{)\":::Identifier1:dq here doc:\n\ dq here doc content:\".\":::String:dq here doc:\n\ dq string:\"(?(%=~^|&`'+[\\]]|:(?!:)|\\^[ADEFHILMOPSTWX]|ARGV|\\d{1,2})|(@|\\$#)(ARGV|EXPORT|EXPORT_OK|F|INC|ISA|_)>|%(ENV|EXPORT_TAGS|INC|SIG)>|(\\$#?|@|%)(::)?[\\l_](\\w|::(?=\\w))*|(\\$#?|@|%)\\{(::)?[\\l_](\\w|::(?=\\w))*\\}|(\\$|@|%)(?=\\{)\":::Identifier1:dq string:\n\ gen dq string:\"(%=~^|&`'+[\\]]|:(?!:)|\\^[ADEFHILMOPSTWX]|ARGV|\\d{1,2})|(@|\\$#)(ARGV|EXPORT|EXPORT_OK|F|INC|ISA|_)>|%(ENV|EXPORT_TAGS|INC|SIG)>|(\\$#?|@|%)(::)?[\\l_](\\w|::(?=\\w))*|(\\$#?|@|%)\\{(::)?[\\l_](\\w|::(?=\\w))*\\}|(\\$|@|%)(?=\\{)\":::Identifier1:gen dq string:\n\ sq here doc:\"(\\<\\<')EOF('.*)$\":\"^EOF>\"::Label::\n\ sq here doc delims:\"\\1\\2\":::Keyword:sq here doc:C\n\ sq here doc esc chars:\"\\\\\\\\\":::Text Escape:sq here doc:\n\ sq here doc content:\".\":::String1:sq here doc:\n\ sq string:\"(?)|(\\{)[-\\w]+(\\})\":::String1::\n\ implicit sq delims:\"\\1\\2\":::Keyword:implicit sq:C\n\ word list:\"\"::Label::\n\ bq here doc delims:\"\\1\\2\":::Keyword:bq here doc:C\n\ bq here doc comment:\"#\":\"$\"::Comment:bq here doc:\n\ bq here doc variables:\"\\$([-_./,\"\"\\\\*?#;!@$<>(%=~^|&`'+[\\]]|:(?!:)|\\^[ADEFHILMOPSTWX]|ARGV|\\d{1,2})|(@|\\$#)(ARGV|EXPORT|EXPORT_OK|F|INC|ISA|_)>|%(ENV|EXPORT_TAGS|INC|SIG)>|(\\$#?|@|%)(::)?[\\l_](\\w|::(?=\\w))*|(\\$#?|@|%)\\{(::)?[\\l_](\\w|::(?=\\w))*\\}|(\\$|@|%)(?=\\{)\":::Identifier1:bq here doc:\n\ bq here doc content:\".\":::String1:bq here doc:\n\ bq string:\"(?(%=~^|&`'+[\\]]|:(?!:)|\\^[ADEFHILMOPSTWX]|ARGV|\\d{1,2})|(@|\\$#)(ARGV|EXPORT|EXPORT_OK|F|INC|ISA|_)>|%(ENV|EXPORT_TAGS|INC|SIG)>|(\\$#?|@|%)(::)?[\\l_](\\w|::(?=\\w))*|(\\$#?|@|%)\\{(::)?[\\l_](\\w|::(?=\\w))*\\}|(\\$|@|%)(?=\\{)\":::Identifier1:bq string:\n\ gen bq string:\"(%=~^|&`'+[\\]]|:(?!:)|\\^[ADEFHILMOPSTWX]|ARGV|\\d{1,2})|(@|\\$#)(ARGV|EXPORT|EXPORT_OK|F|INC|ISA|_)>|%(ENV|EXPORT_TAGS|INC|SIG)>|(\\$#?|@|%)(::)?[\\l_](\\w|::(?=\\w))*|(\\$#?|@|%)\\{(::)?[\\l_](\\w|::(?=\\w))*\\}|(\\$|@|%)(?=\\{)\":::Identifier1:gen bq string:\n\ gen bq string esc chars:\"\\\\/\":::Text Escape:gen bq string:\n\ transliteration:\"<((y|tr)/)(\\\\/|[^/])+(/)(\\\\/|[^/])*(/[cds]*)\":::String::D\n\ transliteration delims:\"\\1\\4\\6\":::Keyword:transliteration:DC\n\ last array index:\"\\$#([\\l_](\\w|::(?=\\w))*)?\":::Identifier1::\n\ comment:\"#\":\"$\"::Comment::\n\ label:\"((?:^|;)\\s*<([A-Z_]+)>\\s*:(?=(?:[^:]|\\n)))|(goto|last|next|redo)\\s+(<((if|unless)|[A-Z_]+)>|)\":::Plain::\n\ label identifier:\"\\2\\5\":::Label:label:C\n\ label keyword:\"\\3\\6\":::Keyword:label:C\n\ handle:\"(\\<)[A-Z_]+(\\>)|(bind|binmode|close(?:dir)?|connect|eof|fcntl|fileno|flock|getc|getpeername|getsockname|getsockopt|ioctl|listen|open(?:dir)?|recv|read(?:dir)?|rewinddir|seek(?:dir)?|send|setsockopt|shutdown|socket|sysopen|sysread|sysseek|syswrite|tell(?:dir)?|write)>\\s*(\\(?)\\s*[A-Z_]+>|<(accept|pipe|socketpair)>\\s*(\\(?)\\s*[A-Z_]+\\s*(,)\\s*[A-Z_]+>|(print|printf|select)>\\s*(\\(?)\\s*[A-Z_]+>(?!\\s*,)\":::Storage Type::\n\ handle delims:\"\\1\\2\\4\\6\\7\\9\":::Keyword:handle:C\n\ handle functions:\"\\3\\5\\8\":::Subroutine:handle:C\n\ statements:\"<(if|until|while|elsif|else|unless|for(each)?|continue|last|goto|next|redo|do(?=\\s*\\{)|BEGIN|END)>\":::Keyword::D\n\ packages and modules:\"<(bless|caller|import|no|package|prototype|require|return|INIT|CHECK|BEGIN|END|use|new)>\":::Keyword::D\n\ pragm modules:\"<(attrs|autouse|base|blib|constant|diagnostics|fields|integer|less|lib|locale|ops|overload|re|sigtrap|strict|subs|vars|vmsish)>\":::Keyword::D\n\ standard methods:\"<(can|isa|VERSION)>\":::Keyword::D\n\ file tests:\"-[rwxRWXoOezsfdlSpbcugktTBMAC]>\":::Subroutine::D\n\ subr header:\"\":\"(?:\\{|;)\"::Keyword::D\n\ subr header coloring:\"\\1\":::Plain:subr header:DC\n\ subr prototype:\"\\(\":\"\\)\"::Flag:subr header:D\n\ subr prototype delims:\"&\":\"&\"::Keyword:subr prototype:DC\n\ subr prototype chars:\"\\\\?[@$%&*]|;\":::Identifier1:subr prototype:D\n\ references:\"\\\\(\\$|@|%|&)(::)?[\\l_](\\w|::(?=\\w))*|\\\\(\\$?|@|%|&)\\{(::)?[\\l_](\\w|::(?=\\w))*\\}|\\\\(\\$|@|%|&)(?=\\{)\":::Identifier1::\n\ variables:\"\\$([-_./,\"\"\\\\*?#;!@$<>(%=~^|&`'+[\\]]|:(?!:)|\\^[ADEFHILMOPSTWX]|ARGV|\\d{1,2})|(@|\\$#)(ARGV|EXPORT|EXPORT_OK|F|INC|ISA|_)>|%(ENV|EXPORT_TAGS|INC|SIG)>|(\\$#?|@|%)(::)?[\\l_](\\w|::(?=\\w))*|(\\$#?|@|%)\\{(::)?[\\l_](\\w|::(?=\\w))*\\}|(\\$|@|%)(?=\\{)\":::Identifier1::\n\ named operators:\"<(lt|gt|le|ge|eq|ne|cmp|not|and|or|xor|sub|x)>\":::Keyword::D\n\ library functions:\"<((?# arithmetic functions)abs|atan2|cos|exp|int|log|rand|sin|sqrt|srand|time|(?# conversion functions)chr|gmtime|hex|localtime|oct|ord|vec|(?# structure conversion)pack|unpack|(?# string functions)chomp|chop|crypt|eval(?=\\s*[^{])|index|lc|lcfirst|length|quotemeta|rindex|substr|uc|ucfirst|(?# array and hash functions)delete|each|exists|grep|join|keys|map|pop|push|reverse|scalar|shift|sort|splice|split|unshift|values|(?# search and replace functions)pos|study|(?# file operations)chmod|chown|link|lstat|mkdir|readlink|rename|rmdir|stat|symlink|truncate|unlink|utime|(?# input/output)binmode|close|eof|fcntl|fileno|flock|getc|ioctl|open|pipe|print|printf|read|readline|readpipe|seek|select|sprintf|sysopen|sysread|sysseek|syswrite|tell|(?# formats)formline|write|(?# tying variables)tie|tied|untie|(?# directory reading routines)closedir|opendir|readdir|rewinddir|seekdir|telldir|(?# system interaction)alarm|chdir|chroot|die|exec|exit|fork|getlogin|getpgrp|getppid|getpriority|glob|kill|setpgrp|setpriority|sleep|syscall|system|times|umask|wait|waitpid|warn|(?# networking)accept|bind|connect|getpeername|getsockname|getsockopt|listen|recv|send|setsockopt|shutdown|socket|socketpair|(?# system V ipc)msgctl|msgget|msgrcv|msgsnd|semctl|semget|semop|shmctl|shmget|shmread|shmwrite|(?# miscellaneous)defined|do|dump|eval(?=\\s*\\{)|local|my|ref|reset|undef|(?# informations from system databases)endpwent|getpwent|getpwnam|getpwuid|setpwent|endgrent|getgrent|getgrgid|getgrnam|setgrent|endnetent|getnetbyaddr|getnetbyname|getnetent|setnetent|endhostend|gethostbyaddr|gethostbyname|gethostent|sethostent|endservent|getservbyname|getservbyport|getservent|setservent|endprotoent|getprotobyname|getprotobynumber|getprotoent|setprotoent)>\":::Subroutine::\n\ subroutine call:\"(&|-\\>)\\w(\\w|::)*(?!\\Y)|<\\w(\\w|::)*(?=\\s*\\()\":::Subroutine1::D\n\ symbolic operators:\">[-<>+.*/\\\\?!~=%^&:]<\":::Keyword::D\n\ braces and parens:\"[\\[\\]{}\\(\\)\\<\\>]\":::Keyword::D\n\ numerics:\"(?(%=~^|&`'+[\\]]|:(?!:)|\\^[ADEFHILMOPSTWX]|ARGV|\\d{1,2})|(@|\\$#)(ARGV|EXPORT|EXPORT_OK|F|INC|ISA|_)>|%(ENV|EXPORT_TAGS|INC|SIG)>|(\\$#?|@|%)(::)?[\\l_](\\w|::(?=\\w))*|(\\$#?|@|%)\\{(::)?[\\l_](\\w|::(?=\\w))*\\}|(\\$|@|%)(?=\\{)\":::Identifier1:re match:\n\ re match comment:\"\\(\\?#[^)]*\\)\":::Comment:re match:\n\ re match syms:\"[.^$[\\])|)]|\\{\\d+(,\\d*)?\\}\\??|\\((\\?([:=!>imsx]|\\<[=!]))?|[?+*]\\??\":::Regex:re match:\n\ re match refs:\"\\\\[1-9]\\d?\":::Identifier1:re match:\n\ re sub:\"<(s/)\":\"(/)((?:\\\\/|\\\\[1-9]\\d?|[^/])*)(/[egimosx]*)\"::Plain::\n\ re sub delims:\"\\1\":\"\\1\\3\"::Keyword:re sub:C\n\ re sub subst:\"\\2\":\"\\2\"::String:re sub:C\n\ re sub esc chars:\"\\\\([/abdeflnrstuwzABDEGLQSUWZ+?.*$^(){}[\\]|\\\\]|0[0-7]{2}|x[0-9a-fA-F]{2})\":::Text Escape:re sub:\n\ re sub class:\"\\[\\^?\":\"\\]\"::Plain:re sub:\n\ re sub class delims:\"&\":\"&\"::Regex:re sub class:C\n\ re sub class esc chars:\"\\\\([abdeflnrstuwzABDEGLQSUWZ^\\]\\\\-]|0[0-7]{2}|x[0-9a-fA-F]{2})\":::Text Escape:re sub class:\n\ re sub variables:\"\\$([-_.,\"\"\\\\*?#;!@$<>(%=~^|&`'+[\\]]|:(?!:)|\\^[ADEFHILMOPSTWX]|ARGV|\\d{1,2})|(@|\\$#)(ARGV|EXPORT|EXPORT_OK|F|INC|ISA|_)>|%(ENV|EXPORT_TAGS|INC|SIG)>|(\\$#?|@|%)(::)?[\\l_](\\w|::(?=\\w))*|(\\$#?|@|%)\\{(::)?[\\l_](\\w|::(?=\\w))*\\}|(\\$|@|%)(?=\\{)\":::Identifier1:re sub:\n\ re sub comment:\"\\(\\?#[^)]*\\)\":::Comment:re sub:\n\ re sub syms:\"[.^$[\\])|)]|\\{\\d+(,\\d*)?\\}\\??|\\((\\?([:=!>imsx]|\\<[=!]))?|[?+*]\\??\":::Regex:re sub:\n\ re sub refs:\"\\\\[1-9]\\d?\":::Identifier1:re sub:\n\ info:\"version: 2.02p1; author/maintainer: Joor Loohuis, joor@loohuis-consulting.nl\":::Plain::}", "PostScript:1:0{\n\ DSCcomment:\"^%[%|!]\":\"$\"::Preprocessor::\n\ Comment:\"%\":\"$\"::Comment::\n\ string:\"\\(\":\"\\)\"::String::\n\ string esc chars:\"\\\\(n|r|t|b|f|\\\\|\\(|\\)|[0-9][0-9]?[0-9]?)?\":::String2:string:\n\ string2:\"\\(\":\"\\)\"::String:string:\n\ string2 esc chars:\"\\\\(n|r|t|b|f|\\\\|\\(|\\)|[0-9][0-9]?[0-9]?)?\":::String2:string2:\n\ string3:\"\\(\":\"\\)\"::String:string2:\n\ string3 esc chars:\"\\\\(n|r|t|b|f|\\\\|\\(|\\)|[0-9][0-9]?[0-9]?)?\":::String2:string3:\n\ ASCII 85 string:\"\\<~\":\"~\\>\":\"[^!-uz]\":String1::\n\ Dictionary:\"(\\<\\<|\\>\\>)\":::Storage Type::\n\ hex string:\"\\<\":\"\\>\":\"[^0-9a-fA-F> \\t]\":String1::\n\ Literal:\"/[^/%{}\\(\\)\\<\\>\\[\\]\\f\\n\\r\\t ]*\":::Text Key::\n\ Number:\"(?\":::Keyword::D\n\ Operator3:\"<(GetHalftoneName|GetPageDeviceName|GetSubstituteCRD|StartData|addglyph|beginbfchar|beginbfrange|begincidchar|begincidrange|begincmap|begincodespacerange|beginnotdefchar|beginnotdefrange|beginrearrangedfont|beginusematrix|cliprestore|clipsave|composefont|currentsmoothness|currenttrapparams|endbfchar|endbfrange|endcidchar|endcidrange|endcmap|endcodespacerange|endnotdefchar|endnotdefrange|endrearrangedfont|endusematrix|findcolorrendering|removeall|removeglyphs|setsmoothness|settrapparams|settrapzone|shfill|usecmap|usefont)>\":::Keyword::D\n\ Old operator:\"<(condition|currentcontext|currenthalftonephase|defineusername|detach|deviceinfo|eoviewclip|fork|initviewclip|join|lock|monitor|notify|rectviewclip|sethalftonephase|viewclip|viewclippath|wait|wtranslation|yield)>\":::Keyword::D}", "Python:2:0{\n\ Comment:\"#\":\"$\"::Comment::\n\ String3s:\"[uU]?[rR]?'{3}\":\"'{3}\"::String::\n\ String3d:\"[uU]?[rR]?\"\"{3}\":\"\"\"{3}\"::String::\n\ String1s:\"[uU]?[rR]?'\":\"'\":\"$\":String::\n\ String1d:\"[uU]?[rR]?\"\"\":\"\"\"\":\"$\":String::\n\ String escape chars 3s:\"\\\\(?:\\n|\\\\|'|\"\"|a|b|f|n|r|t|v|[0-7]{1,3}|x[\\da-fA-F]{2}|u[\\da-fA-F]{4}|U[\\da-fA-F]{8})\":::String1:String3s:\n\ String escape chars 3d:\"\\\\(?:\\n|\\\\|'|\"\"|a|b|f|n|r|t|v|[0-7]{1,3}|x[\\da-fA-F]{2}|u[\\da-fA-F]{4}|U[\\da-fA-F]{8})\":::String1:String3d:\n\ String escape chars 1s:\"\\\\(?:\\n|\\\\|'|\"\"|a|b|f|n|r|t|v|[0-7]{1,3}|x[\\da-fA-F]{2}|u[\\da-fA-F]{4}|U[\\da-fA-F]{8})\":::String1:String1s:\n\ String escape chars 1d:\"\\\\(?:\\n|\\\\|'|\"\"|a|b|f|n|r|t|v|[0-7]{1,3}|x[\\da-fA-F]{2}|u[\\da-fA-F]{4}|U[\\da-fA-F]{8})\":::String1:String1d:\n\ Representation:\"`\":\"`\":\"$\":String2::\n\ Representation cont:\"\\\\\\n\":::String2:Representation:\n\ Number:\"(?.*?\\(\":\"\\)\"::Preprocessor::\n\ Multiline import comment:\"#\":\"$\"::Comment:Multiline import:\n\ Import:\"<(?:import|from)>\":\";|$\":\"#\":Preprocessor::\n\ Import continuation:\"\\\\\\n\":::Preprocessor:Import:\n\ Member definition:\"<(def)\\s+(?:(__(?:abs|add|and|call|cmp|coerce|complex|contains|del|delattr|delitem|div|divmod|enter|eq|exit|float|floordiv|ge|getattr|getitem|gt|hash|hex|iadd|iand|idiv|ilshift|imod|imul|index|init|int|invert|ior|ipow|irshift|isub|iter|ixor|le|len|long|lshift|lt|mod|mul|ne|neg|nonzero|oct|or|pos|pow|radd|rand|rdiv|rdivmod|repr|rlshift|rmod|rmul|ror|rpow|rrshift|rshift|rsub|rxor|setattr|setitem|str|sub|truediv|xor)__)|((__(?:bases|class|dict)__)|(__(?:delslice|getslice|setslice)__)|(__(?:members|methods)__))|(and|as|assert|break|continue|def|del|elif|else|except|exec|finally|for|from|if|import|in|is|not|or|pass|print|raise|return|try|while|with|yield|class|global|lambda)|([\\l_]\\w*))(?=(?:\\s*(?:\\\\\\n\\s*)?\\(\\s*|\\s*\\(\\s*(?:\\\\?\\n\\s*)?)self>)\":::Plain::\n\ Member def color:\"\\1\":::Keyword:Member definition:C\n\ Member def special:\"\\2\":::Subroutine:Member definition:C\n\ Member def deprecated:\"\\3\":::Warning:Member definition:C\n\ Member def error:\"\\7\":::Flag:Member definition:C\n\ Static method definition:\"<(def)\\s+(__(?:new)__)\":::Plain::\n\ Static def color:\"\\1\":::Keyword:Static method definition:C\n\ Static def special:\"\\2\":::Subroutine:Static method definition:C\n\ Function definition:\"<(def)\\s+(?:(ArithmeticError|AssertionError|AttributeError|BaseException|DeprecationWarning|EOFError|Ellipsis|EnvironmentError|Exception|False|FloatingPointError|FutureWarning|GeneratorExit|IOError|ImportError|ImportWarning|IndentationError|IndexError|KeyError|KeyboardInterrupt|LookupError|MemoryError|NameError|None|NotImplemented|NotImplementedError|OSError|OverflowError|PendingDeprecationWarning|ReferenceError|RuntimeError|RuntimeWarning|StandardError|StopIteration|SyntaxError|SyntaxWarning|SystemError|SystemExit|TabError|True|TypeError|UnboundLocalError|UnicodeDecodeError|UnicodeEncodeError|UnicodeError|UnicodeTranslateError|UnicodeWarning|UserWarning|ValueError|Warning|WindowsError|ZeroDivisionError|__builtins__|__debug__|__doc__|__import__|__name__|abs|all|any|apply|basestring|bool|buffer|callable|chr|classmethod|cmp|coerce|compile|complex|copyright|credits|delattr|dict|dir|divmod|enumerate|eval|execfile|exit|file|filter|float|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|license|list|locals|long|map|max|min|object|oct|open|ord|pow|property|quit|range|raw_input|reduce|reload|repr|reversed|round|self|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)|(and|as|assert|break|continue|def|del|elif|else|except|exec|finally|for|from|if|import|in|is|not|or|pass|print|raise|return|try|while|with|yield|class|global|lambda)|([\\l_]\\w*))>\":::Plain::\n\ Function def color:\"\\1\":::Keyword:Function definition:C\n\ Function def deprecated:\"\\2\":::Warning:Function definition:C\n\ Function def error:\"\\3\":::Flag:Function definition:C\n\ Class definition:\"<(class)\\s+(?:(ArithmeticError|AssertionError|AttributeError|BaseException|DeprecationWarning|EOFError|Ellipsis|EnvironmentError|Exception|False|FloatingPointError|FutureWarning|GeneratorExit|IOError|ImportError|ImportWarning|IndentationError|IndexError|KeyError|KeyboardInterrupt|LookupError|MemoryError|NameError|None|NotImplemented|NotImplementedError|OSError|OverflowError|PendingDeprecationWarning|ReferenceError|RuntimeError|RuntimeWarning|StandardError|StopIteration|SyntaxError|SyntaxWarning|SystemError|SystemExit|TabError|True|TypeError|UnboundLocalError|UnicodeDecodeError|UnicodeEncodeError|UnicodeError|UnicodeTranslateError|UnicodeWarning|UserWarning|ValueError|Warning|WindowsError|ZeroDivisionError|__builtins__|__debug__|__doc__|__import__|__name__|abs|all|any|apply|basestring|bool|buffer|callable|chr|classmethod|cmp|coerce|compile|complex|copyright|credits|delattr|dict|dir|divmod|enumerate|eval|execfile|exit|file|filter|float|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|license|list|locals|long|map|max|min|object|oct|open|ord|pow|property|quit|range|raw_input|reduce|reload|repr|reversed|round|self|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)|(and|as|assert|break|continue|def|del|elif|else|except|exec|finally|for|from|if|import|in|is|not|or|pass|print|raise|return|try|while|with|yield|class|global|lambda)|([\\l_]\\w*))>\":::Plain::\n\ Class def color:\"\\1\":::Storage Type:Class definition:C\n\ Class def deprecated:\"\\2\":::Warning:Class definition:C\n\ Class def error:\"\\3\":::Flag:Class definition:C\n\ Member reference:\"\\.\\s*(?:\\\\?\\n\\s*)?(?:((__(?:abs|add|and|call|cmp|coerce|complex|contains|del|delattr|delitem|div|divmod|enter|eq|exit|float|floordiv|ge|getattr|getitem|gt|hash|hex|iadd|iand|idiv|ilshift|imod|imul|index|init|int|invert|ior|ipow|irshift|isub|iter|ixor|le|len|long|lshift|lt|mod|mul|ne|neg|nonzero|oct|or|pos|pow|radd|rand|rdiv|rdivmod|repr|rlshift|rmod|rmul|ror|rpow|rrshift|rshift|rsub|rxor|setattr|setitem|str|sub|truediv|xor)__)|(__(?:new)__))|((__(?:delslice|getslice|setslice)__)|(__(?:members|methods)__))|(__(?:bases|class|dict)__)|(and|as|assert|break|continue|def|del|elif|else|except|exec|finally|for|from|if|import|in|is|not|or|pass|print|raise|return|try|while|with|yield|class|global|lambda)|([\\l_]\\w*))>\":::Plain::\n\ Member special method:\"\\1\":::Subroutine:Member reference:C\n\ Member deprecated:\"\\4\":::Warning:Member reference:C\n\ Member special attrib:\"\\7\":::Identifier1:Member reference:C\n\ Member ref error:\"\\8\":::Flag:Member reference:C\n\ Storage keyword:\"<(?:class|global|lambda)>\":::Storage Type::\n\ Keyword:\"<(?:and|as|assert|break|continue|def|del|elif|else|except|exec|finally|for|from|if|import|in|is|not|or|pass|print|raise|return|try|while|with|yield)>\":::Keyword::\n\ Built-in function:\"<(?:__import__|abs|all|any|basestring|bool|callable|chr|classmethod|cmp|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|exit|file|filter|float|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|isinstance|issubclass|iter|len|list|locals|long|map|max|min|object|oct|open|ord|pow|property|quit|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)>\":::Subroutine::\n\ Built-in name:\"<(?:Ellipsis|False|None|NotImplemented|True|__builtins__|__debug__|__doc__|__name__|copyright|credits|license|self)>\":::Identifier1::\n\ Built-in exceptions:\"<(?:ArithmeticError|AssertionError|AttributeError|BaseException|EOFError|EnvironmentError|Exception|FloatingPointError|GeneratorExit|IOError|ImportError|IndentationError|IndexError|KeyError|KeyboardInterrupt|LookupError|MemoryError|NameError|NotImplementedError|OSError|OverflowError|ReferenceError|RuntimeError|StandardError|StopIteration|SyntaxError|SystemError|SystemExit|TabError|TypeError|UnboundLocalError|UnicodeDecodeError|UnicodeEncodeError|UnicodeError|UnicodeTranslateError|ValueError|WindowsError|ZeroDivisionError)>\":::Identifier1::\n\ Built-in warnings:\"<(?:DeprecationWarning|FutureWarning|ImportWarning|PendingDeprecationWarning|RuntimeWarning|SyntaxWarning|UnicodeWarning|UserWarning|Warning)>\":::Identifier1::\n\ Deprecated function:\"<(?:apply|buffer|coerce|intern)>\":::Warning::\n\ Braces and parens:\"[[{()}\\]]\":::Keyword::D\n\ Decorator:\"(@)\":\"$\":\"#\":Preprocessor1::\n\ Decorator continuation:\"\\\\\\n\":::Preprocessor1:Decorator:\n\ Decorator marker:\"\\1\":::Storage Type:Decorator:C}", "Regex:1:0{\n\ Comments:\"(?#This is a comment!)\\(\\?#[^)]*(?:\\)|$)\":::Comment::\n\ Literal Escape:\"(?#Special chars that need escapes)\\\\[abefnrtv()\\[\\]<>{}.|^$*+?&\\\\]\":::Preprocessor::\n\ Shortcut Escapes:\"(?#Shortcuts for common char classes)\\\\[dDlLsSwW]\":::Character Const::\n\ Backreferences:\"(?#Internal regex backreferences)\\\\[1-9]\":::Storage Type::\n\ Word Delimiter:\"(?#Special token to match NEdit [non]word-delimiters)\\\\[yY]\":::Subroutine::\n\ Numeric Escape:\"(?#Negative lookahead is to exclude \\x0 and \\00)(?!\\\\[xX0]0*(?:[^\\da-fA-F]|$))\\\\(?:[xX]0*[1-9a-fA-F][\\da-fA-F]?|0*[1-3]?[0-7]?[0-7])\":::Numeric Const::\n\ Quantifiers:\"(?#Matches greedy and lazy quantifiers)[*+?]\\??\":::Flag::\n\ Counting Quantifiers:\"(?#Properly limits range numbers to 0-65535)\\{(?:[0-5]?\\d?\\d?\\d?\\d|6[0-4]\\d\\d\\d|65[0-4]\\d\\d|655[0-2]\\d|6553[0-5])?(?:,(?:[0-5]?\\d?\\d?\\d?\\d|6[0-4]\\d\\d\\d|65[0-4]\\d\\d|655[0-2]\\d|6553[0-5])?)?\\}\\??\":::Numeric Const::\n\ Character Class:\"(?#Handles escapes, char ranges, ^-] at beginning and - at end)\\[\\^?[-\\]]?(?:(?:\\\\(?:[abdeflnrstvwDLSW\\-()\\[\\]<>{}.|^$*+?&\\\\]|[xX0][\\da-fA-F]+)|[^\\\\\\]])(?:-(?:\\\\(?:[abdeflnrstvwDLSW\\-()\\[\\]<>{}.|^$*+?&\\\\]|[xX0][\\da-fA-F]+)|[^\\\\\\]]))?)*\\-?]\":::Character Const::\n\ Anchors:\"(?#\\B is the \"\"not a word boundary\"\" anchor)[$^<>]|\\\\B\":::Flag::\n\ Parens and Alternation:\"\\(?:\\?(?:[:=!iInN])|[()|]\":::Keyword::\n\ Match Themselves:\"(?#Highlight chars left over which just match themselves).\":::Text Comment::D}", "SGML HTML:6:0{\n\ markup declaration:\"\\\"::Plain::\n\ mdo-mdc:\"&\":\"&\"::Storage Type:markup declaration:C\n\ markup declaration dq string:\"\"\"\":\"\"\"\"::String1:markup declaration:\n\ markup declaration sq string:\"'\":\"'\"::String1:markup declaration:\n\ entity declaration:\"((?ientity))[ \\t\\n][ \\t]*\\n?[ \\t]*(%[ \\t\\n][ \\t]*\\n?[ \\t]*)?(\\l[\\l\\d\\-\\.]*|#((?idefault)))[ \\t\\n][ \\t]*\\n?[ \\t]*((?i[cs]data|pi|starttag|endtag|m[ds]))?\":::Preprocessor:markup declaration:\n\ ed name:\"\\2\":\"\"::String2:element declaration:C\n\ ed type:\"\\4\":\"\"::Storage Type:entity declaration:C\n\ doctype declaration:\"((?idoctype))[ \\t\\n][ \\t]*\\n?[ \\t]*(\\l[\\l\\d\\-\\.]*)\":::Preprocessor:markup declaration:\n\ dt name:\"\\2\":\"\"::String2:doctype declaration:C\n\ element declaration:\"((?ielement))[ \\t\\n][ \\t]*\\n?[ \\t]*(\\l[\\l\\d\\-\\.]*)\":::Preprocessor:markup declaration:\n\ attribute declaration:\"((?iattlist))[ \\t\\n][ \\t]*\\n?[ \\t]*(\\l[\\l\\d\\-\\.]*)\":::Preprocessor:markup declaration:\n\ ad name:\"\\2\":\"\"::String2:attribute declaration:C\n\ notation declaration:\"((?inotation))[ \\t\\n][ \\t]*\\n?[ \\t]*(\\l[\\l\\d\\-\\.]*)\":::Preprocessor:markup declaration:\n\ nd name:\"\\2\":\"\"::String2:notation declaration:C\n\ shortref declaration:\"((?ishortref))[ \\t\\n][ \\t]*\\n?[ \\t]*(\\l[\\l\\d\\-\\.]*)\":::Preprocessor:markup declaration:\n\ sd name:\"\\2\":\"\"::String2:shortref declaration:C\n\ comment:\"\\-\\-\":\"\\-\\-\"::Comment:markup declaration:\n\ pi:\"\\<\\?[^\\>]*\\??\\>\":::Flag::\n\ stag:\"(\\<)(\\(\\l[\\w\\-\\.:]*\\))?\\l[\\w\\-\\.:]*\":\"/?\\>\"::Text Key1::\n\ stago-tagc:\"\\1\":\"&\"::Text Arg:stag:C\n\ Attribute:\"([\\l\\-]+)[ \\t\\v]*\\n?[ \\t\\v]*=[ \\t\\v]*\\n?[ \\t\\v]*(\"\"([^\"\"]*\\n){,4}[^\"\"]*\"\"|'([^']*\\n){,4}[^']*'|\\&([^;]*\\n){,4}[^;]*;|[\\w\\-\\.:]+)\":::Plain:stag:\n\ Attribute name:\"\\1\":\"\"::Text Arg2:Attribute:C\n\ Attribute value:\"\\2\":\"\"::String:Attribute:C\n\ Boolean Attribute:\"([\\l\\-]+)\":::Text Arg1:stag:\n\ etag:\"(\\)\":::Text Key1::\n\ etago-tagc:\"\\1\\4\":\"\"::Text Arg:etag:C\n\ Character reference:\"\\&((\\(\\l[\\l\\d\\-\\.]*\\))?\\l[\\l\\d]*|#\\d+|#[xX][a-fA-F\\d]+);?\":::Text Escape::\n\ parameter entity:\"%(\\(\\l[\\l\\d\\-\\.]*\\))?\\l[\\l\\d\\-\\.]*;?\":::Text Escape::\n\ md parameter entity:\"%(\\(\\l[\\l\\d\\-\\.]*\\))?\\l[\\l\\d\\-\\.]*;?\":::Text Escape:markup declaration:\n\ system-public id:\"<(?isystem|public|cdata)>\":::Storage Type:markup declaration:}", "SQL:1:0{\n\ keywords:\",|%|\\<|\\>|:=|=|<(SELECT|ON|FROM|ORDER BY|DESC|WHERE|AND|OR|NOT|NULL|TRUE|FALSE)>\":::Keyword::\n\ comment:\"--\":\"$\"::Comment::\n\ data types:\"<(CHAR|VARCHAR2\\([0-9]*\\)|INT[0-9]*|POINT|BOX|TEXT|BOOLEAN|VARCHAR2|VARCHAR|NUMBER\\([0-9]*\\)|NUMBER)(?!\\Y)\":::Storage Type::\n\ string:\"'\":\"'\"::String::\n\ keywords2:\"END IF;|(?\":::Preprocessor1::\n\ comment2:\"/\\*\":\"\\*/\"::Comment::}", "Sh Ksh Bash:1:0{\n\ README:\"Shell syntax highlighting patterns, version 2.2, maintainer Thorsten Haude, nedit at thorstenhau.de\":::Flag::D\n\ escaped special characters:\"\\\\[\\\\\"\"$`']\":::Keyword::\n\ single quoted string:\"'\":\"'\"::String1::\n\ double quoted string:\"\"\"\":\"\"\"\"::String::\n\ double quoted escape:\"\\\\[\\\\\"\"$`]\":::String2:double quoted string:\n\ dq command sub:\"`\":\"`\":\"\"\"\":Subroutine:double quoted string:\n\ dq arithmetic expansion:\"\\$\\(\\(\":\"\\)\\)\":\"\"\"\":String:double quoted string:\n\ dq new command sub:\"\\$\\(\":\"\\)\":\"\"\"\":Subroutine:double quoted string:\n\ dqncs single quoted string:\"'\":\"'\"::String1:dq new command sub:\n\ dq variables:\"\\$([-*@#?$!0-9]|[a-zA-Z_][0-9a-zA-Z_]*)\":::Identifier1:double quoted string:\n\ dq variables2:\"\\$\\{\":\"}\":\"\\n\":Identifier1:double quoted string:\n\ arithmetic expansion:\"\\$\\(\\(\":\"\\)\\)\"::String::\n\ ae escapes:\"\\\\[\\\\$`\"\"']\":::String2:arithmetic expansion:\n\ ae single quoted string:\"'\":\"'\":\"\\)\\)\":String1:arithmetic expansion:\n\ ae command sub:\"`\":\"`\":\"\\)\\)\":Subroutine:arithmetic expansion:\n\ ae arithmetic expansion:\"\\$\\(\\(\":\"\\)\\)\"::String:arithmetic expansion:\n\ ae new command sub:\"\\$\\(\":\"\\)\":\"\\)\\)\":Subroutine:arithmetic expansion:\n\ ae variables:\"\\$([-*@#?$!0-9]|[a-zA-Z_][0-9a-zA-Z_]*)\":::Identifier1:arithmetic expansion:\n\ ae variables2:\"\\$\\{\":\"}\":\"\\)\\)\":Identifier1:arithmetic expansion:\n\ comments:\"^[ \\t]*#\":\"$\"::Comment::\n\ command substitution:\"`\":\"`\"::Subroutine::\n\ cs escapes:\"\\\\[\\\\$`\"\"']\":::Subroutine1:command substitution:\n\ cs single quoted string:\"'\":\"'\":\"`\":String1:command substitution:\n\ cs variables:\"\\$([-*@#?$!0-9]|[a-zA-Z_][0-9a-zA-Z_]*)\":::Identifier1:command substitution:\n\ cs variables2:\"\\$\\{\":\"}\":\"`\":Identifier1:command substitution:\n\ new command substitution:\"\\$\\(\":\"\\)\"::Subroutine::\n\ ncs new command substitution:\"\\$\\(\":\"\\)\"::Subroutine:new command substitution:\n\ ncs escapes:\"\\\\[\\\\$`\"\"']\":::Subroutine1:new command substitution:\n\ ncs single quoted string:\"'\":\"'\"::String1:new command substitution:\n\ ncs variables:\"\\$([-*@#?$!0-9]|[a-zA-Z_][0-9a-zA-Z_]*)\":::Identifier1:new command substitution:\n\ ncs variables2:\"\\$\\{\":\"}\":\"\\)\":Identifier1:new command substitution:\n\ assignment:\"[a-zA-Z_][0-9a-zA-Z_]*=\":::Identifier1::\n\ variables:\"\\$([-*@#?$!0-9_]|[a-zA-Z_][0-9a-zA-Z_]*)\":::Identifier1::\n\ variables2:\"\\$\\{\":\"}\"::Identifier1::\n\ internal var:\"\\$\\{\":\"}\"::Identifier1:variables2:\n\ comments in line:\"#\":\"$\"::Comment::\n\ numbers:\"<(?i0x[\\da-f]+)|((\\d*\\.)?\\d+([eE][-+]?\\d+)?(?iul?|l|f)?)>\":::Numeric Const::D\n\ keywords:\"(??]+\":::Identifier::\n\ delimiters:\"[{};<>&~=!|^%[\\]+*|]\":::Text Key::D\n\ built ins:\"(?\":::Identifier::\n\ Braces and Brackets:\"[\\[\\]{}]\":::Keyword::D\n\ DQ String Esc Chars:\"\\\\(.|\\n)\":::String1:Double Quote String:\n\ SQ String Esc Chars:\"\\\\(.|\\n)\":::String1:Single Quote String:\n\ Variable in String:\"\\$\\w+|\\$\\{[^}]*}|\\$\":::Identifier1:Double Quote String:\n\ Storage:\"<(public|private|protected)>\":::Storage Type::\n\ Namespace:\"\\w+::\":::Keyword::}", "VHDL:1:0{\n\ Comments:\"--\":\"$\"::Comment::\n\ String Literals:\"\"\"\":\"\"\"\":\"\\n\":String::\n\ Vhdl Attributes:\"'[a-zA-Z][a-zA-Z_]+\":::Ada Attributes::\n\ Character Literals:\"'\":\"'\":\"[^\\\\][^']\":Character Const::\n\ Numeric Literals:\"(?\":::Storage Type::D\n\ Predefined SubTypes:\"<(?istd_logic|std_logic_vector|std_ulogic|std_ulogic_vector|bit|bit_vector)>\":::Storage Type::D\n\ Reserved Words:\"<(?iabs|access|after|all|and|architecture|array|assert|attribute|begin|block|body|buffer|bus|case|component|configuration|disconnect|downto|else|elsif|end|entity|error|exit|failure|file|for|function|generate|generic|guarded|if|in|inout|is|label|library|linkage|loop|map|mod|nand|new|next|nor|not|note|null|of|on|open|or|others|out|package|port|procedure|process|range|record|register|rem|report|return|select|severity|then|to|transport|units|until|use|wait|warning|when|while|with|xor|group|impure|inertial|literal|postponed|pure|reject|rol|ror|shared|sla|sll|sra|srl|unaffected|xnor)>\":::Keyword::D\n\ Identifiers:\"<([a-zA-Z][a-zA-Z0-9_]*)>\":::Plain::D\n\ Flag Special Comments:\"--\\<[^a-zA-Z0-9]+\\>\":::Flag:Comments:\n\ Instantiation:\"([a-zA-Z][a-zA-Z0-9_]*)([ \\t]+):([ \\t]+)([a-zA-Z][a-zA-Z0-9_]*)([ \\t]+)(port|generic|map)\":::Keyword::\n\ Instance Name:\"\\1\":\"\"::Identifier1:Instantiation:C\n\ Component Name:\"\\4\":\"\"::Identifier:Instantiation:C\n\ Syntax Character:\"(\\<=|=\\>|:|=|:=|;|,|\\(|\\))\":::Keyword::}", "Verilog:1:0{\n\ Comment:\"/\\*\":\"\\*/\"::Comment::\n\ cplus comment:\"//\":\"$\"::Comment::\n\ String Literals:\"\"\"\":\"\"\"\":\"\\n\":String::\n\ preprocessor line:\"^[ ]*`\":\"$\"::Preprocessor::\n\ Reserved WordsA:\"(?\":::Storage Type::D\n\ System Functions:\"\\$[a-z_]+\":::Subroutine::D\n\ Numeric Literals:\"(?\":::Storage Type1::\n\ Special Chars:\"(\\{|\\}|,|;|=|\\.)\":::Keyword::}", "XML:1:0{\n\ comment:\"\\\n"); for (i = 0; i < n + extra; i++) { char *pos = ""; DataValue *dv = &StackP[-i - 1]; if (dv < TheStack) { printf("--------------Stack base--------------\n"); break; } offset = dv - FrameP; printf("%4.4s", i < n ? ">>>>" : ""); printf("%8p ", dv); switch (offset) { case 0: pos = "FrameP"; break; /* first local symbol value */ case FP_ARG_ARRAY_CACHE_INDEX: pos = "args"; break; /* arguments array */ case FP_ARG_COUNT_INDEX: pos = "NArgs"; break; /* number of arguments */ case FP_OLD_FP_INDEX: pos = "OldFP"; break; case FP_RET_PC_INDEX: pos = "RetPC"; break; default: if (offset < -FP_TO_ARGS_DIST && offset >= -FP_TO_ARGS_DIST - nArgs) { sprintf(pos = buffer, STACK_DUMP_ARG_PREFIX "%d", offset + FP_TO_ARGS_DIST + nArgs + 1); } break; } printf("%-6s ", pos); dumpVal(*dv); printf("\n"); } } #endif /* ifdef DEBUG_STACK */ nedit-5.6.orig/source/interpret.h0000644000175000017500000001631411071426617015611 0ustar paulpaul/* $Id: interpret.h,v 1.22 2008/10/03 14:34:55 lebert Exp $ */ /******************************************************************************* * * * interpret.h -- Nirvana Editor Interpreter Header File * * * * Copyright 2004 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_INTERPRET_H_INCLUDED #define NEDIT_INTERPRET_H_INCLUDED #include "nedit.h" #include "rbTree.h" #define STACK_SIZE 1024 /* Maximum stack size */ #define MAX_SYM_LEN 100 /* Max. symbol name length */ #define MACRO_EVENT_MARKER 2 /* Special value for the send_event field of events passed to action routines. Tells them that they were called from a macro */ enum symTypes {CONST_SYM, GLOBAL_SYM, LOCAL_SYM, ARG_SYM, PROC_VALUE_SYM, C_FUNCTION_SYM, MACRO_FUNCTION_SYM, ACTION_ROUTINE_SYM}; #define N_OPS 43 enum operations {OP_RETURN_NO_VAL, OP_RETURN, OP_PUSH_SYM, OP_DUP, OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_NEGATE, OP_INCR, OP_DECR, OP_GT, OP_LT, OP_GE, OP_LE, OP_EQ, OP_NE, OP_BIT_AND, OP_BIT_OR, OP_AND, OP_OR, OP_NOT, OP_POWER, OP_CONCAT, OP_ASSIGN, OP_SUBR_CALL, OP_FETCH_RET_VAL, OP_BRANCH, OP_BRANCH_TRUE, OP_BRANCH_FALSE, OP_BRANCH_NEVER, OP_ARRAY_REF, OP_ARRAY_ASSIGN, OP_BEGIN_ARRAY_ITER, OP_ARRAY_ITER, OP_IN_ARRAY, OP_ARRAY_DELETE, OP_PUSH_ARRAY_SYM, OP_ARRAY_REF_ASSIGN_SETUP, OP_PUSH_ARG, OP_PUSH_ARG_COUNT, OP_PUSH_ARG_ARRAY}; enum typeTags {NO_TAG, INT_TAG, STRING_TAG, ARRAY_TAG}; enum execReturnCodes {MACRO_TIME_LIMIT, MACRO_PREEMPT, MACRO_DONE, MACRO_ERROR}; #define ARRAY_DIM_SEP "\034" struct DataValueTag; struct SparseArrayEntryTag; struct ProgramTag; struct SymbolRec; typedef union InstTag { int (*func)(void); int value; struct SymbolRec *sym; } Inst; typedef int (*BuiltInSubr)(WindowInfo *window, struct DataValueTag *argList, int nArgs, struct DataValueTag *result, char **errMsg); typedef struct NStringTag { char *rep; size_t len; } NString; typedef struct DataValueTag { enum typeTags tag; union { int n; struct NStringTag str; BuiltInSubr subr; struct ProgramTag* prog; XtActionProc xtproc; Inst* inst; struct DataValueTag* dataval; struct SparseArrayEntryTag *arrayPtr; } val; } DataValue; typedef struct SparseArrayEntryTag { rbTreeNode nodePtrs; /* MUST BE FIRST ENTRY */ char *key; DataValue value; } SparseArrayEntry; /* symbol table entry */ typedef struct SymbolRec { char *name; enum symTypes type; DataValue value; struct SymbolRec *next; /* to link to another */ } Symbol; typedef struct ProgramTag { Symbol *localSymList; Inst *code; } Program; /* Information needed to re-start a preempted macro */ typedef struct { DataValue *stack; DataValue *stackP; DataValue *frameP; Inst *pc; WindowInfo *runWindow; WindowInfo *focusWindow; } RestartData; void InitMacroGlobals(void); SparseArrayEntry *arrayIterateFirst(DataValue *theArray); SparseArrayEntry *arrayIterateNext(SparseArrayEntry *iterator); SparseArrayEntry *ArrayNew(void); Boolean ArrayInsert(DataValue* theArray, char* keyStr, DataValue* theValue); void ArrayDelete(DataValue *theArray, char *keyStr); void ArrayDeleteAll(DataValue *theArray); unsigned ArraySize(DataValue *theArray); Boolean ArrayGet(DataValue* theArray, char* keyStr, DataValue* theValue); int ArrayCopy(DataValue *dstArray, DataValue *srcArray); /* Routines for creating a program, (accumulated beginning with BeginCreatingProgram and returned via FinishCreatingProgram) */ void BeginCreatingProgram(void); int AddOp(int op, char **msg); int AddSym(Symbol *sym, char **msg); int AddImmediate(int value, char **msg); int AddBranchOffset(Inst *to, char **msg); Inst *GetPC(void); Symbol *InstallIteratorSymbol(void); Symbol *LookupStringConstSymbol(const char *value); Symbol *InstallStringConstSymbol(const char *str); Symbol *LookupSymbol(const char *name); Symbol *InstallSymbol(const char *name, enum symTypes type, DataValue value); Program *FinishCreatingProgram(void); void SwapCode(Inst *start, Inst *boundary, Inst *end); void StartLoopAddrList(void); int AddBreakAddr(Inst *addr); int AddContinueAddr(Inst *addr); void FillLoopAddrs(Inst *breakAddr, Inst *continueAddr); /* create a permanently allocated static string (only for use with static strings) */ #define PERM_ALLOC_STR(xStr) (((char *)("\001" xStr)) + 1) /* Routines for executing programs */ int ExecuteMacro(WindowInfo *window, Program *prog, int nArgs, DataValue *args, DataValue *result, RestartData **continuation, char **msg); int ContinueMacro(RestartData *continuation, DataValue *result, char **msg); void RunMacroAsSubrCall(Program *prog); void PreemptMacro(void); char *AllocString(int length); char *AllocStringNCpy(const char *s, int length); char *AllocStringCpy(const char *s); int AllocNString(NString *string, int length); int AllocNStringNCpy(NString *string, const char *s, int length); int AllocNStringCpy(NString *string, const char *s); void GarbageCollectStrings(void); void FreeRestartData(RestartData *context); Symbol *PromoteToGlobal(Symbol *sym); void FreeProgram(Program *prog); void ModifyReturnedValue(RestartData *context, DataValue dv); WindowInfo *MacroRunWindow(void); WindowInfo *MacroFocusWindow(void); void SetMacroFocusWindow(WindowInfo *window); /* function used for implicit conversion from string to number */ int StringToNum(const char *string, int *number); #endif /* NEDIT_INTERPRET_H_INCLUDED */ nedit-5.6.orig/source/linkdate.c0000644000175000017500000000456310077452065015367 0ustar paulpaul/* $Id: linkdate.c,v 1.4 2004/07/21 11:32:05 yooden Exp $ */ /******************************************************************************* * * * linkdate.c -- Compile time configuration * * * * Copyright (C) 2001 Scott Tringali * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * Noveber 30, 2001 * * * * Written by Scott Tringali, http://www.tringali.org * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #ifdef HAVE_DEBUG_H #include "../debug.h" #endif const char linkdate[] = __DATE__; const char linktime[] = __TIME__; nedit-5.6.orig/source/macro.c0000644000175000017500000057534611053030337014676 0ustar paulpaulstatic const char CVSID[] = "$Id: macro.c,v 1.116 2008/08/20 14:57:35 lebert Exp $"; /******************************************************************************* * * * macro.c -- Macro file processing, learn/replay, and built-in macro * * subroutines * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * April, 1997 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "macro.h" #include "textBuf.h" #include "text.h" #include "nedit.h" #include "window.h" #include "preferences.h" #include "interpret.h" #include "parse.h" #include "search.h" #include "server.h" #include "shell.h" #include "smartIndent.h" #include "userCmds.h" #include "selection.h" #include "rbTree.h" #include "tags.h" #include "calltips.h" #include "../util/DialogF.h" #include "../util/misc.h" #include "../util/fileUtils.h" #include "../util/utils.h" #include "../util/getfiles.h" #include "highlight.h" #include "highlightData.h" #include "rangeset.h" #include #include #include #include #include #ifdef VMS #include #include "../util/VMSparam.h" #include #include #include #else #include #include #ifndef __MVS__ #include #endif #include #endif /*VMS*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif /* Maximum number of actions in a macro and args in an action (to simplify the reader) */ #define MAX_MACRO_ACTIONS 1024 #define MAX_ACTION_ARGS 40 /* How long to wait (msec) before putting up Macro Command banner */ #define BANNER_WAIT_TIME 6000 /* The following definitions cause an exit from the macro with a message */ /* added if (1) to remove compiler warnings on solaris */ #define M_FAILURE(s) do { *errMsg = s; if (1) return False; } while (0) #define M_STR_ALLOC_ASSERT(xDV) do { if (xDV.tag == STRING_TAG && !xDV.val.str.rep) { *errMsg = "Failed to allocate value: %s"; return(False); } } while (0) #define M_ARRAY_INSERT_FAILURE() M_FAILURE("array element failed to insert: %s") /* Data attached to window during shell command execution with information for controling and communicating with the process */ typedef struct { XtIntervalId bannerTimeoutID; XtWorkProcId continueWorkProcID; char bannerIsUp; char closeOnCompletion; Program *program; RestartData *context; Widget dialog; } macroCmdInfo; /* Widgets and global data for Repeat dialog */ typedef struct { WindowInfo *forWindow; char *lastCommand; Widget shell, repeatText, lastCmdToggle; Widget inSelToggle, toEndToggle; } repeatDialog; static void cancelLearn(void); static void runMacro(WindowInfo *window, Program *prog); static void finishMacroCmdExecution(WindowInfo *window); static void repeatOKCB(Widget w, XtPointer clientData, XtPointer callData); static void repeatApplyCB(Widget w, XtPointer clientData, XtPointer callData); static int doRepeatDialogAction(repeatDialog *rd, XEvent *event); static void repeatCancelCB(Widget w, XtPointer clientData, XtPointer callData); static void repeatDestroyCB(Widget w, XtPointer clientData, XtPointer callData); static void learnActionHook(Widget w, XtPointer clientData, String actionName, XEvent *event, String *params, Cardinal *numParams); static void lastActionHook(Widget w, XtPointer clientData, String actionName, XEvent *event, String *params, Cardinal *numParams); static char *actionToString(Widget w, char *actionName, XEvent *event, String *params, Cardinal numParams); static int isMouseAction(const char *action); static int isRedundantAction(const char *action); static int isIgnoredAction(const char *action); static int readCheckMacroString(Widget dialogParent, char *string, WindowInfo *runWindow, const char *errIn, char **errPos); static void bannerTimeoutProc(XtPointer clientData, XtIntervalId *id); static Boolean continueWorkProc(XtPointer clientData); static int escapeStringChars(char *fromString, char *toString); static int escapedStringLength(char *string); static int lengthMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int minMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int maxMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int focusWindowMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int getRangeMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int getCharacterMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int replaceRangeMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int replaceSelectionMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int getSelectionMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int validNumberMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int replaceInStringMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int replaceSubstringMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int readFileMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int writeFileMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int appendFileMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int writeOrAppendFile(int append, WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int substringMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int toupperMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int tolowerMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int stringToClipboardMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int clipboardToStringMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int searchMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int searchStringMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int setCursorPosMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int beepMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int selectMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int selectRectangleMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int tPrintMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int getenvMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int shellCmdMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int dialogMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static void dialogBtnCB(Widget w, XtPointer clientData, XtPointer callData); static void dialogCloseCB(Widget w, XtPointer clientData, XtPointer callData); #ifdef LESSTIF_VERSION static void dialogEscCB(Widget w, XtPointer clientData, XEvent *event, Boolean *cont); #endif /* LESSTIF_VERSION */ static int stringDialogMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static void stringDialogBtnCB(Widget w, XtPointer clientData, XtPointer callData); static void stringDialogCloseCB(Widget w, XtPointer clientData, XtPointer callData); #ifdef LESSTIF_VERSION static void stringDialogEscCB(Widget w, XtPointer clientData, XEvent *event, Boolean *cont); #endif /* LESSTIF_VERSION */ static int calltipMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int killCalltipMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); /* T Balinski */ static int listDialogMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static void listDialogBtnCB(Widget w, XtPointer clientData, XtPointer callData); static void listDialogCloseCB(Widget w, XtPointer clientData, XtPointer callData); /* T Balinski End */ #ifdef LESSTIF_VERSION static void listDialogEscCB(Widget w, XtPointer clientData, XEvent *event, Boolean *cont); #endif /* LESSTIF_VERSION */ static int stringCompareMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int splitMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); /* DISASBLED for 5.4 static int setBacklightStringMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); */ static int cursorMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int lineMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int columnMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int fileNameMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int filePathMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int lengthMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int selectionStartMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int selectionEndMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int selectionLeftMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int selectionRightMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int statisticsLineMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int incSearchLineMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int showLineNumbersMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int autoIndentMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int wrapTextMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int highlightSyntaxMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int makeBackupCopyMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int incBackupMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int showMatchingMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int matchSyntaxBasedMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int overTypeModeMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int readOnlyMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int lockedMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int fileFormatMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int fontNameMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int fontNameItalicMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int fontNameBoldMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int fontNameBoldItalicMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int subscriptSepMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int minFontWidthMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int maxFontWidthMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int wrapMarginMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int topLineMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int numDisplayLinesMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int displayWidthMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int activePaneMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int nPanesMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int emptyArrayMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int serverNameMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int tabDistMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int emTabDistMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int useTabsMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int modifiedMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int languageModeMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int calltipIDMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int readSearchArgs(DataValue *argList, int nArgs, int*searchDirection, int *searchType, int *wrap, char **errMsg); static int wrongNArgsErr(char **errMsg); static int tooFewArgsErr(char **errMsg); static int strCaseCmp(char *str1, char *str2); static int readIntArg(DataValue dv, int *result, char **errMsg); static int readStringArg(DataValue dv, char **result, char *stringStorage, char **errMsg); /* DISABLED FOR 5.4 static int backlightStringMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); */ static int rangesetListMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int versionMV(WindowInfo* window, DataValue* argList, int nArgs, DataValue* result, char** errMsg); static int rangesetCreateMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int rangesetDestroyMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int rangesetGetByNameMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int rangesetAddMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int rangesetSubtractMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int rangesetInvertMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int rangesetInfoMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int rangesetRangeMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int rangesetIncludesPosMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int rangesetSetColorMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int rangesetSetNameMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int rangesetSetModeMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int fillPatternResult(DataValue *result, char **errMsg, WindowInfo *window, char *patternName, Boolean preallocatedPatternName, Boolean includeName, char *styleName, int bufferPos); static int getPatternByNameMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int getPatternAtPosMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int fillStyleResult(DataValue *result, char **errMsg, WindowInfo *window, char *styleName, Boolean preallocatedStyleName, Boolean includeName, int patCode, int bufferPos); static int getStyleByNameMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int getStyleAtPosMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg); static int filenameDialogMS(WindowInfo* window, DataValue* argList, int nArgs, DataValue* result, char** errMsg); /* Built-in subroutines and variables for the macro language */ static BuiltInSubr MacroSubrs[] = {lengthMS, getRangeMS, tPrintMS, dialogMS, stringDialogMS, replaceRangeMS, replaceSelectionMS, setCursorPosMS, getCharacterMS, minMS, maxMS, searchMS, searchStringMS, substringMS, replaceSubstringMS, readFileMS, writeFileMS, appendFileMS, beepMS, getSelectionMS, validNumberMS, replaceInStringMS, selectMS, selectRectangleMS, focusWindowMS, shellCmdMS, stringToClipboardMS, clipboardToStringMS, toupperMS, tolowerMS, listDialogMS, getenvMS, stringCompareMS, splitMS, calltipMS, killCalltipMS, /* DISABLED for 5.4 setBacklightStringMS,*/ rangesetCreateMS, rangesetDestroyMS, rangesetAddMS, rangesetSubtractMS, rangesetInvertMS, rangesetInfoMS, rangesetRangeMS, rangesetIncludesPosMS, rangesetSetColorMS, rangesetSetNameMS, rangesetSetModeMS, rangesetGetByNameMS, getPatternByNameMS, getPatternAtPosMS, getStyleByNameMS, getStyleAtPosMS, filenameDialogMS }; #define N_MACRO_SUBRS (sizeof MacroSubrs/sizeof *MacroSubrs) static const char *MacroSubrNames[N_MACRO_SUBRS] = {"length", "get_range", "t_print", "dialog", "string_dialog", "replace_range", "replace_selection", "set_cursor_pos", "get_character", "min", "max", "search", "search_string", "substring", "replace_substring", "read_file", "write_file", "append_file", "beep", "get_selection", "valid_number", "replace_in_string", "select", "select_rectangle", "focus_window", "shell_command", "string_to_clipboard", "clipboard_to_string", "toupper", "tolower", "list_dialog", "getenv", "string_compare", "split", "calltip", "kill_calltip", /* DISABLED for 5.4 "set_backlight_string", */ "rangeset_create", "rangeset_destroy", "rangeset_add", "rangeset_subtract", "rangeset_invert", "rangeset_info", "rangeset_range", "rangeset_includes", "rangeset_set_color", "rangeset_set_name", "rangeset_set_mode", "rangeset_get_by_name", "get_pattern_by_name", "get_pattern_at_pos", "get_style_by_name", "get_style_at_pos", "filename_dialog" }; static BuiltInSubr SpecialVars[] = {cursorMV, lineMV, columnMV, fileNameMV, filePathMV, lengthMV, selectionStartMV, selectionEndMV, selectionLeftMV, selectionRightMV, wrapMarginMV, tabDistMV, emTabDistMV, useTabsMV, languageModeMV, modifiedMV, statisticsLineMV, incSearchLineMV, showLineNumbersMV, autoIndentMV, wrapTextMV, highlightSyntaxMV, makeBackupCopyMV, incBackupMV, showMatchingMV, matchSyntaxBasedMV, overTypeModeMV, readOnlyMV, lockedMV, fileFormatMV, fontNameMV, fontNameItalicMV, fontNameBoldMV, fontNameBoldItalicMV, subscriptSepMV, minFontWidthMV, maxFontWidthMV, topLineMV, numDisplayLinesMV, displayWidthMV, activePaneMV, nPanesMV, emptyArrayMV, serverNameMV, calltipIDMV, /* DISABLED for 5.4 backlightStringMV, */ rangesetListMV, versionMV }; #define N_SPECIAL_VARS (sizeof SpecialVars/sizeof *SpecialVars) static const char *SpecialVarNames[N_SPECIAL_VARS] = {"$cursor", "$line", "$column", "$file_name", "$file_path", "$text_length", "$selection_start", "$selection_end", "$selection_left", "$selection_right", "$wrap_margin", "$tab_dist", "$em_tab_dist", "$use_tabs", "$language_mode", "$modified", "$statistics_line", "$incremental_search_line", "$show_line_numbers", "$auto_indent", "$wrap_text", "$highlight_syntax", "$make_backup_copy", "$incremental_backup", "$show_matching", "$match_syntax_based", "$overtype_mode", "$read_only", "$locked", "$file_format", "$font_name", "$font_name_italic", "$font_name_bold", "$font_name_bold_italic", "$sub_sep", "$min_font_width", "$max_font_width", "$top_line", "$n_display_lines", "$display_width", "$active_pane", "$n_panes", "$empty_array", "$server_name", "$calltip_ID", /* DISABLED for 5.4 "$backlight_string", */ "$rangeset_list", "$VERSION" }; /* Global symbols for returning values from built-in functions */ #define N_RETURN_GLOBALS 5 enum retGlobalSyms {STRING_DIALOG_BUTTON, SEARCH_END, READ_STATUS, SHELL_CMD_STATUS, LIST_DIALOG_BUTTON}; static const char *ReturnGlobalNames[N_RETURN_GLOBALS] = {"$string_dialog_button", "$search_end", "$read_status", "$shell_cmd_status", "$list_dialog_button"}; static Symbol *ReturnGlobals[N_RETURN_GLOBALS]; /* List of actions not useful when learning a macro sequence (also see below) */ static char* IgnoredActions[] = {"focusIn", "focusOut"}; /* List of actions intended to be attached to mouse buttons, which the user must be warned can't be recorded in a learn/replay sequence */ static const char* MouseActions[] = {"grab_focus", "extend_adjust", "extend_start", "extend_end", "secondary_or_drag_adjust", "secondary_adjust", "secondary_or_drag_start", "secondary_start", "move_destination", "move_to", "move_to_or_end_drag", "copy_to", "copy_to_or_end_drag", "exchange", "process_bdrag", "mouse_pan"}; /* List of actions to not record because they generate further actions, more suitable for recording */ static const char* RedundantActions[] = {"open_dialog", "save_as_dialog", "revert_to_saved_dialog", "include_file_dialog", "load_macro_file_dialog", "load_tags_file_dialog", "find_dialog", "replace_dialog", "goto_line_number_dialog", "mark_dialog", "goto_mark_dialog", "control_code_dialog", "filter_selection_dialog", "execute_command_dialog", "repeat_dialog", "start_incremental_find"}; /* The last command executed (used by the Repeat command) */ static char *LastCommand = NULL; /* The current macro to execute on Replay command */ static char *ReplayMacro = NULL; /* Buffer where macro commands are recorded in Learn mode */ static textBuffer *MacroRecordBuf = NULL; /* Action Hook id for recording actions for Learn mode */ static XtActionHookId MacroRecordActionHook = 0; /* Window where macro recording is taking place */ static WindowInfo *MacroRecordWindow = NULL; /* Arrays for translating escape characters in escapeStringChars */ static char ReplaceChars[] = "\\\"ntbrfav"; static char EscapeChars[] = "\\\"\n\t\b\r\f\a\v"; /* ** Install built-in macro subroutines and special variables for accessing ** editor information */ void RegisterMacroSubroutines(void) { static DataValue subrPtr = {NO_TAG, {0}}, noValue = {NO_TAG, {0}}; unsigned i; /* Install symbols for built-in routines and variables, with pointers to the appropriate c routines to do the work */ for (i=0; inext) { if (!IsTopDocument(win)) continue; XtSetSensitive(win->learnItem, False); } SetSensitive(window, window->finishLearnItem, True); XtVaSetValues(window->cancelMacroItem, XmNlabelString, s=XmStringCreateSimple("Cancel Learn"), NULL); XmStringFree(s); SetSensitive(window, window->cancelMacroItem, True); /* Mark the window where learn mode is happening */ MacroRecordWindow = window; /* Allocate a text buffer for accumulating the macro strings */ MacroRecordBuf = BufCreate(); /* Add the action hook for recording the actions */ MacroRecordActionHook = XtAppAddActionHook(XtWidgetToApplicationContext(window->shell), learnActionHook, window); /* Extract accelerator texts from menu PushButtons */ XtVaGetValues(window->finishLearnItem, XmNacceleratorText, &xmFinish, NULL); XtVaGetValues(window->cancelMacroItem, XmNacceleratorText, &xmCancel, NULL); /* Translate Motif strings to char* */ cFinish = GetXmStringText(xmFinish); cCancel = GetXmStringText(xmCancel); /* Free Motif Strings */ XmStringFree(xmFinish); XmStringFree(xmCancel); /* Create message */ if (cFinish[0] == '\0') { if (cCancel[0] == '\0') { strncpy(message, "Learn Mode -- Use menu to finish or cancel", MAX_LEARN_MSG_LEN); message[MAX_LEARN_MSG_LEN - 1] = '\0'; } else { sprintf(message, "Learn Mode -- Use menu to finish, press %s to cancel", cCancel); } } else { if (cCancel[0] == '\0') { sprintf(message, "Learn Mode -- Press %s to finish, use menu to cancel", cFinish); } else { sprintf(message, "Learn Mode -- Press %s to finish, %s to cancel", cFinish, cCancel); } } /* Free C-strings */ XtFree(cFinish); XtFree(cCancel); /* Put up the learn-mode banner */ SetModeMessage(window, message); } void AddLastCommandActionHook(XtAppContext context) { XtAppAddActionHook(context, lastActionHook, NULL); } void FinishLearn(void) { WindowInfo *win; /* If we're not in learn mode, return */ if (MacroRecordActionHook == 0) return; /* Remove the action hook */ XtRemoveActionHook(MacroRecordActionHook); MacroRecordActionHook = 0; /* Free the old learn/replay sequence */ XtFree(ReplayMacro); /* Store the finished action for the replay menu item */ ReplayMacro = BufGetAll(MacroRecordBuf); /* Free the buffer used to accumulate the macro sequence */ BufFree(MacroRecordBuf); /* Undim the menu items dimmed during learn */ for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XtSetSensitive(win->learnItem, True); } if (IsTopDocument(MacroRecordWindow)) { XtSetSensitive(MacroRecordWindow->finishLearnItem, False); XtSetSensitive(MacroRecordWindow->cancelMacroItem, False); } /* Undim the replay and paste-macro buttons */ for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XtSetSensitive(win->replayItem, True); } DimPasteReplayBtns(True); /* Clear learn-mode banner */ ClearModeMessage(MacroRecordWindow); } /* ** Cancel Learn mode, or macro execution (they're bound to the same menu item) */ void CancelMacroOrLearn(WindowInfo *window) { if (MacroRecordActionHook != 0) cancelLearn(); else if (window->macroCmdData != NULL) AbortMacroCommand(window); } static void cancelLearn(void) { WindowInfo *win; /* If we're not in learn mode, return */ if (MacroRecordActionHook == 0) return; /* Remove the action hook */ XtRemoveActionHook(MacroRecordActionHook); MacroRecordActionHook = 0; /* Free the macro under construction */ BufFree(MacroRecordBuf); /* Undim the menu items dimmed during learn */ for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XtSetSensitive(win->learnItem, True); } if (IsTopDocument(MacroRecordWindow)) { XtSetSensitive(MacroRecordWindow->finishLearnItem, False); XtSetSensitive(MacroRecordWindow->cancelMacroItem, False); } /* Clear learn-mode banner */ ClearModeMessage(MacroRecordWindow); } /* ** Execute the learn/replay sequence stored in "window" */ void Replay(WindowInfo *window) { Program *prog; char *errMsg, *stoppedAt; /* Verify that a replay macro exists and it's not empty and that */ /* we're not already running a macro */ if (ReplayMacro != NULL && ReplayMacro[0] != 0 && window->macroCmdData == NULL) { /* Parse the replay macro (it's stored in text form) and compile it into an executable program "prog" */ prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt); if (prog == NULL) { fprintf(stderr, "NEdit internal error, learn/replay macro syntax error: %s\n", errMsg); return; } /* run the executable program */ runMacro(window, prog); } } /* ** Read the initial NEdit macro file if one exists. */ void ReadMacroInitFile(WindowInfo *window) { const char* autoloadName = GetRCFileName(AUTOLOAD_NM); static int initFileLoaded = False; /* GetRCFileName() might return NULL if an error occurs during creation of the preference file directory. */ if (autoloadName != NULL && !initFileLoaded) { ReadMacroFile(window, autoloadName, False); initFileLoaded = True; } } /* ** Read an NEdit macro file. Extends the syntax of the macro parser with ** define keyword, and allows intermixing of defines with immediate actions. */ int ReadMacroFile(WindowInfo *window, const char *fileName, int warnNotExist) { int result; char *fileString; /* read-in macro file and force a terminating \n, to prevent syntax ** errors with statements on the last line */ fileString = ReadAnyTextFile(fileName, True); if (fileString == NULL){ if (errno != ENOENT || warnNotExist) { DialogF(DF_ERR, window->shell, 1, "Read Macro", "Error reading macro file %s: %s", "OK", fileName, #ifdef VMS strerror(errno, vaxc$errno)); #else strerror(errno)); #endif } return False; } /* Parse fileString */ result = readCheckMacroString(window->shell, fileString, window, fileName, NULL); XtFree(fileString); return result; } /* ** Parse and execute a macro string including macro definitions. Report ** parsing errors in a dialog posted over window->shell. */ int ReadMacroString(WindowInfo *window, char *string, const char *errIn) { return readCheckMacroString(window->shell, string, window, errIn, NULL); } /* ** Check a macro string containing definitions for errors. Returns True ** if macro compiled successfully. Returns False and puts up ** a dialog explaining if macro did not compile successfully. */ int CheckMacroString(Widget dialogParent, char *string, const char *errIn, char **errPos) { return readCheckMacroString(dialogParent, string, NULL, errIn, errPos); } /* ** Parse and optionally execute a macro string including macro definitions. ** Report parsing errors in a dialog posted over dialogParent, using the ** string errIn to identify the entity being parsed (filename, macro string, ** etc.). If runWindow is specified, runs the macro against the window. If ** runWindow is passed as NULL, does parse only. If errPos is non-null, ** returns a pointer to the error location in the string. */ static int readCheckMacroString(Widget dialogParent, char *string, WindowInfo *runWindow, const char *errIn, char **errPos) { char *stoppedAt, *inPtr, *namePtr, *errMsg; char subrName[MAX_SYM_LEN]; Program *prog; Symbol *sym; DataValue subrPtr; Stack* progStack = (Stack*) XtMalloc(sizeof(Stack)); progStack->top = NULL; progStack->size = 0; inPtr = string; while (*inPtr != '\0') { /* skip over white space and comments */ while (*inPtr==' ' || *inPtr=='\t' || *inPtr=='\n'|| *inPtr=='#') { if (*inPtr == '#') while (*inPtr != '\n' && *inPtr != '\0') inPtr++; else inPtr++; } if (*inPtr == '\0') break; /* look for define keyword, and compile and store defined routines */ if (!strncmp(inPtr, "define", 6) && (inPtr[6]==' ' || inPtr[6]=='\t')) { inPtr += 6; inPtr += strspn(inPtr, " \t\n"); namePtr = subrName; while ((namePtr < &subrName[MAX_SYM_LEN - 1]) && (isalnum((unsigned char)*inPtr) || *inPtr == '_')) { *namePtr++ = *inPtr++; } *namePtr = '\0'; if (isalnum((unsigned char)*inPtr) || *inPtr == '_') { return ParseError(dialogParent, string, inPtr, errIn, "subroutine name too long"); } inPtr += strspn(inPtr, " \t\n"); if (*inPtr != '{') { if (errPos != NULL) *errPos = stoppedAt; return ParseError(dialogParent, string, inPtr, errIn, "expected '{'"); } prog = ParseMacro(inPtr, &errMsg, &stoppedAt); if (prog == NULL) { if (errPos != NULL) *errPos = stoppedAt; return ParseError(dialogParent, string, stoppedAt, errIn, errMsg); } if (runWindow != NULL) { sym = LookupSymbol(subrName); if (sym == NULL) { subrPtr.val.prog = prog; subrPtr.tag = NO_TAG; sym = InstallSymbol(subrName, MACRO_FUNCTION_SYM, subrPtr); } else { if (sym->type == MACRO_FUNCTION_SYM) FreeProgram(sym->value.val.prog); else sym->type = MACRO_FUNCTION_SYM; sym->value.val.prog = prog; } } inPtr = stoppedAt; /* Parse and execute immediate (outside of any define) macro commands and WAIT for them to finish executing before proceeding. Note that the code below is not perfect. If you interleave code blocks with definitions in a file which is loaded from another macro file, it will probably run the code blocks in reverse order! */ } else { prog = ParseMacro(inPtr, &errMsg, &stoppedAt); if (prog == NULL) { if (errPos != NULL) { *errPos = stoppedAt; } return ParseError(dialogParent, string, stoppedAt, errIn, errMsg); } if (runWindow != NULL) { XEvent nextEvent; if (runWindow->macroCmdData == NULL) { runMacro(runWindow, prog); while (runWindow->macroCmdData != NULL) { XtAppNextEvent(XtWidgetToApplicationContext( runWindow->shell), &nextEvent); ServerDispatchEvent(&nextEvent); } } else { /* If we come here this means that the string was parsed from within another macro via load_macro_file(). In this case, plain code segments outside of define blocks are rolled into one Program each and put on the stack. At the end, the stack is unrolled, so the plain Programs would be executed in the wrong order. So we don't hand the Programs over to the interpreter just yet (via RunMacroAsSubrCall()), but put it on a stack of our own, reversing order once again. */ Push(progStack, (void*) prog); } } inPtr = stoppedAt; } } /* Unroll reversal stack for macros loaded from macros. */ while (NULL != (prog = (Program*) Pop(progStack))) { RunMacroAsSubrCall(prog); } /* This stack is empty, so just free it without checking the members. */ XtFree((char*) progStack); return True; } /* ** Run a pre-compiled macro, changing the interface state to reflect that ** a macro is running, and handling preemption, resumption, and cancellation. ** frees prog when macro execution is complete; */ static void runMacro(WindowInfo *window, Program *prog) { DataValue result; char *errMsg; int stat; macroCmdInfo *cmdData; XmString s; /* If a macro is already running, just call the program as a subroutine, instead of starting a new one, so we don't have to keep a separate context, and the macros will serialize themselves automatically */ if (window->macroCmdData != NULL) { RunMacroAsSubrCall(prog); return; } /* put up a watch cursor over the waiting window */ BeginWait(window->shell); /* enable the cancel menu item */ XtVaSetValues(window->cancelMacroItem, XmNlabelString, s=XmStringCreateSimple("Cancel Macro"), NULL); XmStringFree(s); SetSensitive(window, window->cancelMacroItem, True); /* Create a data structure for passing macro execution information around amongst the callback routines which will process i/o and completion */ cmdData = (macroCmdInfo *)XtMalloc(sizeof(macroCmdInfo)); window->macroCmdData = cmdData; cmdData->bannerIsUp = False; cmdData->closeOnCompletion = False; cmdData->program = prog; cmdData->context = NULL; cmdData->continueWorkProcID = 0; cmdData->dialog = NULL; /* Set up timer proc for putting up banner when macro takes too long */ cmdData->bannerTimeoutID = XtAppAddTimeOut( XtWidgetToApplicationContext(window->shell), BANNER_WAIT_TIME, bannerTimeoutProc, window); /* Begin macro execution */ stat = ExecuteMacro(window, prog, 0, NULL, &result, &cmdData->context, &errMsg); if (stat == MACRO_ERROR) { finishMacroCmdExecution(window); DialogF(DF_ERR, window->shell, 1, "Macro Error", "Error executing macro: %s", "OK", errMsg); return; } if (stat == MACRO_DONE) { finishMacroCmdExecution(window); return; } if (stat == MACRO_TIME_LIMIT) { ResumeMacroExecution(window); return; } /* (stat == MACRO_PREEMPT) Macro was preempted */ } /* ** Continue with macro execution after preemption. Called by the routines ** whose actions cause preemption when they have completed their lengthy tasks. ** Re-establishes macro execution work proc. Window must be the window in ** which the macro is executing (the window to which macroCmdData is attached), ** and not the window to which operations are focused. */ void ResumeMacroExecution(WindowInfo *window) { macroCmdInfo *cmdData = (macroCmdInfo *)window->macroCmdData; if (cmdData != NULL) cmdData->continueWorkProcID = XtAppAddWorkProc( XtWidgetToApplicationContext(window->shell), continueWorkProc, window); } /* ** Cancel the macro command in progress (user cancellation via GUI) */ void AbortMacroCommand(WindowInfo *window) { if (window->macroCmdData == NULL) return; /* If there's both a macro and a shell command executing, the shell command must have been called from the macro. When called from a macro, shell commands don't put up cancellation controls of their own, but rely instead on the macro cancellation mechanism (here) */ #ifndef VMS if (window->shellCmdData != NULL) AbortShellCommand(window); #endif /* Free the continuation */ FreeRestartData(((macroCmdInfo *)window->macroCmdData)->context); /* Kill the macro command */ finishMacroCmdExecution(window); } /* ** Call this before closing a window, to clean up macro references to the ** window, stop any macro which might be running from it, free associated ** memory, and check that a macro is not attempting to close the window from ** which it is run. If this is being called from a macro, and the window ** this routine is examining is the window from which the macro was run, this ** routine will return False, and the caller must NOT CLOSE THE WINDOW. ** Instead, empty it and make it Untitled, and let the macro completion ** process close the window when the macro is finished executing. */ int MacroWindowCloseActions(WindowInfo *window) { macroCmdInfo *mcd, *cmdData = window->macroCmdData; WindowInfo *w; if (MacroRecordActionHook != 0 && MacroRecordWindow == window) { FinishLearn(); } /* If no macro is executing in the window, allow the close, but check if macros executing in other windows have it as focus. If so, set their focus back to the window from which they were originally run */ if (cmdData == NULL) { for (w=WindowList; w!=NULL; w=w->next) { mcd = (macroCmdInfo *)w->macroCmdData; if (w == MacroRunWindow() && MacroFocusWindow() == window) SetMacroFocusWindow(MacroRunWindow()); else if (mcd != NULL && mcd->context->focusWindow == window) mcd->context->focusWindow = mcd->context->runWindow; } return True; } /* If the macro currently running (and therefore calling us, because execution must otherwise return to the main loop to execute any commands), is running in this window, tell the caller not to close, and schedule window close on completion of macro */ if (window == MacroRunWindow()) { cmdData->closeOnCompletion = True; return False; } /* Free the continuation */ FreeRestartData(cmdData->context); /* Kill the macro command */ finishMacroCmdExecution(window); return True; } /* ** Clean up after the execution of a macro command: free memory, and restore ** the user interface state. */ static void finishMacroCmdExecution(WindowInfo *window) { macroCmdInfo *cmdData = window->macroCmdData; int closeOnCompletion = cmdData->closeOnCompletion; XmString s; XClientMessageEvent event; /* Cancel pending timeout and work proc */ if (cmdData->bannerTimeoutID != 0) XtRemoveTimeOut(cmdData->bannerTimeoutID); if (cmdData->continueWorkProcID != 0) XtRemoveWorkProc(cmdData->continueWorkProcID); /* Clean up waiting-for-macro-command-to-complete mode */ EndWait(window->shell); XtVaSetValues(window->cancelMacroItem, XmNlabelString, s=XmStringCreateSimple("Cancel Learn"), NULL); XmStringFree(s); SetSensitive(window, window->cancelMacroItem, False); if (cmdData->bannerIsUp) ClearModeMessage(window); /* If a dialog was up, get rid of it */ if (cmdData->dialog != NULL) XtDestroyWidget(XtParent(cmdData->dialog)); /* Free execution information */ FreeProgram(cmdData->program); XtFree((char *)cmdData); window->macroCmdData = NULL; /* If macro closed its own window, window was made empty and untitled, but close was deferred until completion. This is completion, so if the window is still empty, do the close */ if (closeOnCompletion && !window->filenameSet && !window->fileChanged) { CloseWindow(window); window = NULL; } /* If no other macros are executing, do garbage collection */ SafeGC(); /* In processing the .neditmacro file (and possibly elsewhere), there is an event loop which waits for macro completion. Send an event to wake up that loop, otherwise execution will stall until the user does something to the window. */ if (!closeOnCompletion) { event.format = 8; event.type = ClientMessage; XSendEvent(XtDisplay(window->shell), XtWindow(window->shell), False, NoEventMask, (XEvent *)&event); } } /* ** Do garbage collection of strings if there are no macros currently ** executing. NEdit's macro language GC strategy is to call this routine ** whenever a macro completes. If other macros are still running (preempted ** or waiting for a shell command or dialog), this does nothing and therefore ** defers GC to the completion of the last macro out. */ void SafeGC(void) { WindowInfo *win; for (win=WindowList; win!=NULL; win=win->next) if (win->macroCmdData != NULL || InSmartIndentMacros(win)) return; GarbageCollectStrings(); } /* ** Executes macro string "macro" using the lastFocus pane in "window". ** Reports errors via a dialog posted over "window", integrating the name ** "errInName" into the message to help identify the source of the error. */ void DoMacro(WindowInfo *window, const char *macro, const char *errInName) { Program *prog; char *errMsg, *stoppedAt, *tMacro; int macroLen; /* Add a terminating newline (which command line users are likely to omit since they are typically invoking a single routine) */ macroLen = strlen(macro); tMacro = XtMalloc(strlen(macro)+2); strncpy(tMacro, macro, macroLen); tMacro[macroLen] = '\n'; tMacro[macroLen+1] = '\0'; /* Parse the macro and report errors if it fails */ prog = ParseMacro(tMacro, &errMsg, &stoppedAt); if (prog == NULL) { ParseError(window->shell, tMacro, stoppedAt, errInName, errMsg); XtFree(tMacro); return; } XtFree(tMacro); /* run the executable program (prog is freed upon completion) */ runMacro(window, prog); } /* ** Get the current Learn/Replay macro in text form. Returned string is a ** pointer to the stored macro and should not be freed by the caller (and ** will cease to exist when the next replay macro is installed) */ char *GetReplayMacro(void) { return ReplayMacro; } /* ** Present the user a dialog for "Repeat" command */ void RepeatDialog(WindowInfo *window) { Widget form, selBox, radioBox, timesForm; repeatDialog *rd; Arg selBoxArgs[1]; char *lastCmdLabel, *parenChar; XmString s1; int cmdNameLen; if (LastCommand == NULL) { DialogF(DF_WARN, window->shell, 1, "Repeat Macro", "No previous commands or learn/\nreplay sequences to repeat", "OK"); return; } /* Remeber the last command, since the user is allowed to work in the window while the dialog is up */ rd = (repeatDialog *)XtMalloc(sizeof(repeatDialog)); rd->lastCommand = XtNewString(LastCommand); /* make a label for the Last command item of the dialog, which includes the last executed action name */ parenChar = strchr(LastCommand, '('); if (parenChar == NULL) return; cmdNameLen = parenChar-LastCommand; lastCmdLabel = XtMalloc(16 + cmdNameLen); strcpy(lastCmdLabel, "Last Command ("); strncpy(&lastCmdLabel[14], LastCommand, cmdNameLen); strcpy(&lastCmdLabel[14 + cmdNameLen], ")"); XtSetArg(selBoxArgs[0], XmNautoUnmanage, False); selBox = CreatePromptDialog(window->shell, "repeat", selBoxArgs, 1); rd->shell = XtParent(selBox); XtAddCallback(rd->shell, XmNdestroyCallback, repeatDestroyCB, rd); XtAddCallback(selBox, XmNokCallback, repeatOKCB, rd); XtAddCallback(selBox, XmNapplyCallback, repeatApplyCB, rd); XtAddCallback(selBox, XmNcancelCallback, repeatCancelCB, rd); XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_TEXT)); XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_SELECTION_LABEL)); XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_HELP_BUTTON)); XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_APPLY_BUTTON)); XtVaSetValues(XtParent(selBox), XmNtitle, "Repeat Macro", NULL); AddMotifCloseCallback(XtParent(selBox), repeatCancelCB, rd); form = XtVaCreateManagedWidget("form", xmFormWidgetClass, selBox, NULL); radioBox = XtVaCreateManagedWidget("cmdSrc", xmRowColumnWidgetClass, form, XmNradioBehavior, True, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_TIGHT, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, NULL); rd->lastCmdToggle = XtVaCreateManagedWidget("lastCmdToggle", xmToggleButtonWidgetClass, radioBox, XmNset, True, XmNlabelString, s1=XmStringCreateSimple(lastCmdLabel), XmNmnemonic, 'C', NULL); XmStringFree(s1); XtFree(lastCmdLabel); XtVaCreateManagedWidget("learnReplayToggle", xmToggleButtonWidgetClass, radioBox, XmNset, False, XmNlabelString, s1=XmStringCreateSimple("Learn/Replay"), XmNmnemonic, 'L', XmNsensitive, ReplayMacro != NULL, NULL); XmStringFree(s1); timesForm = XtVaCreateManagedWidget("form", xmFormWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, radioBox, XmNtopOffset, 10, XmNleftAttachment, XmATTACH_FORM, NULL); radioBox = XtVaCreateManagedWidget("method", xmRowColumnWidgetClass, timesForm, XmNradioBehavior, True, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_TIGHT, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, NULL); rd->inSelToggle = XtVaCreateManagedWidget("inSelToggle", xmToggleButtonWidgetClass, radioBox, XmNset, False, XmNlabelString, s1=XmStringCreateSimple("In Selection"), XmNmnemonic, 'I', NULL); XmStringFree(s1); rd->toEndToggle = XtVaCreateManagedWidget("toEndToggle", xmToggleButtonWidgetClass, radioBox, XmNset, False, XmNlabelString, s1=XmStringCreateSimple("To End"), XmNmnemonic, 'T', NULL); XmStringFree(s1); XtVaCreateManagedWidget("nTimesToggle", xmToggleButtonWidgetClass, radioBox, XmNset, True, XmNlabelString, s1=XmStringCreateSimple("N Times"), XmNmnemonic, 'N', XmNset, True, NULL); XmStringFree(s1); rd->repeatText = XtVaCreateManagedWidget("repeatText", xmTextWidgetClass, timesForm, XmNcolumns, 5, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, radioBox, NULL); RemapDeleteKey(rd->repeatText); /* Handle mnemonic selection of buttons and focus to dialog */ AddDialogMnemonicHandler(form, FALSE); /* Set initial focus */ #if XmVersion >= 1002 XtVaSetValues(form, XmNinitialFocus, timesForm, NULL); XtVaSetValues(timesForm, XmNinitialFocus, rd->repeatText, NULL); #endif /* put up dialog */ rd->forWindow = window; ManageDialogCenteredOnPointer(selBox); } static void repeatOKCB(Widget w, XtPointer clientData, XtPointer callData) { repeatDialog *rd = (repeatDialog *)clientData; if (doRepeatDialogAction(rd, ((XmAnyCallbackStruct *)callData)->event)) XtDestroyWidget(rd->shell); } /* Note that the apply button is not managed in the repeat dialog. The dialog itself is capable of non-modal operation, but to be complete, it needs to dynamically update last command, dimming of learn/replay, possibly a stop button for the macro, and possibly in-selection with selection */ static void repeatApplyCB(Widget w, XtPointer clientData, XtPointer callData) { doRepeatDialogAction((repeatDialog *)clientData, ((XmAnyCallbackStruct *)callData)->event); } static int doRepeatDialogAction(repeatDialog *rd, XEvent *event) { int nTimes; char nTimesStr[TYPE_INT_STR_SIZE(int)]; char *params[2]; /* Find out from the dialog how to repeat the command */ if (XmToggleButtonGetState(rd->inSelToggle)) { if (!rd->forWindow->buffer->primary.selected) { DialogF(DF_WARN, rd->shell, 1, "Repeat Macro", "No selection in window to repeat within", "OK"); XmProcessTraversal(rd->inSelToggle, XmTRAVERSE_CURRENT); return False; } params[0] = "in_selection"; } else if (XmToggleButtonGetState(rd->toEndToggle)) { params[0] = "to_end"; } else { if (GetIntTextWarn(rd->repeatText, &nTimes, "number of times", True) != TEXT_READ_OK) { XmProcessTraversal(rd->repeatText, XmTRAVERSE_CURRENT); return False; } sprintf(nTimesStr, "%d", nTimes); params[0] = nTimesStr; } /* Figure out which command user wants to repeat */ if (XmToggleButtonGetState(rd->lastCmdToggle)) params[1] = XtNewString(rd->lastCommand); else { if (ReplayMacro == NULL) return False; params[1] = XtNewString(ReplayMacro); } /* call the action routine repeat_macro to do the work */ XtCallActionProc(rd->forWindow->lastFocus, "repeat_macro", event, params,2); XtFree(params[1]); return True; } static void repeatCancelCB(Widget w, XtPointer clientData, XtPointer callData) { repeatDialog *rd = (repeatDialog *)clientData; XtDestroyWidget(rd->shell); } static void repeatDestroyCB(Widget w, XtPointer clientData, XtPointer callData) { repeatDialog *rd = (repeatDialog *)clientData; XtFree(rd->lastCommand); XtFree((char *)rd); } /* ** Dispatches a macro to which repeats macro command in "command", either ** an integer number of times ("how" == positive integer), or within a ** selected range ("how" == REPEAT_IN_SEL), or to the end of the window ** ("how == REPEAT_TO_END). ** ** Note that as with most macro routines, this returns BEFORE the macro is ** finished executing */ void RepeatMacro(WindowInfo *window, const char *command, int how) { Program *prog; char *errMsg, *stoppedAt, *loopMacro, *loopedCmd; if (command == NULL) return; /* Wrap a for loop and counter/tests around the command */ if (how == REPEAT_TO_END) loopMacro = "lastCursor=-1\nstartPos=$cursor\n\ while($cursor>=startPos&&$cursor!=lastCursor){\nlastCursor=$cursor\n%s\n}\n"; else if (how == REPEAT_IN_SEL) loopMacro = "selStart = $selection_start\nif (selStart == -1)\nreturn\n\ selEnd = $selection_end\nset_cursor_pos(selStart)\nselect(0,0)\n\ boundText = get_range(selEnd, selEnd+10)\n\ while($cursor >= selStart && $cursor < selEnd && \\\n\ get_range(selEnd, selEnd+10) == boundText) {\n\ startLength = $text_length\n%s\n\ selEnd += $text_length - startLength\n}\n"; else loopMacro = "for(i=0;i<%d;i++){\n%s\n}\n"; loopedCmd = XtMalloc(strlen(command) + strlen(loopMacro) + 25); if (how == REPEAT_TO_END || how == REPEAT_IN_SEL) sprintf(loopedCmd, loopMacro, command); else sprintf(loopedCmd, loopMacro, how, command); /* Parse the resulting macro into an executable program "prog" */ prog = ParseMacro(loopedCmd, &errMsg, &stoppedAt); if (prog == NULL) { fprintf(stderr, "NEdit internal error, repeat macro syntax wrong: %s\n", errMsg); return; } XtFree(loopedCmd); /* run the executable program */ runMacro(window, prog); } /* ** Macro recording action hook for Learn/Replay, added temporarily during ** learn. */ static void learnActionHook(Widget w, XtPointer clientData, String actionName, XEvent *event, String *params, Cardinal *numParams) { WindowInfo *window; int i; char *actionString; /* Select only actions in text panes in the window for which this action hook is recording macros (from clientData). */ for (window=WindowList; window!=NULL; window=window->next) { if (window->textArea == w) break; for (i=0; inPanes; i++) { if (window->textPanes[i] == w) break; } if (i < window->nPanes) break; } if (window == NULL || window != (WindowInfo *)clientData) return; /* beep on un-recordable operations which require a mouse position, to remind the user that the action was not recorded */ if (isMouseAction(actionName)) { XBell(XtDisplay(w), 0); return; } /* Record the action and its parameters */ actionString = actionToString(w, actionName, event, params, *numParams); if (actionString != NULL) { BufInsert(MacroRecordBuf, MacroRecordBuf->length, actionString); XtFree(actionString); } } /* ** Permanent action hook for remembering last action for possible replay */ static void lastActionHook(Widget w, XtPointer clientData, String actionName, XEvent *event, String *params, Cardinal *numParams) { WindowInfo *window; int i; char *actionString; /* Find the window to which this action belongs */ for (window=WindowList; window!=NULL; window=window->next) { if (window->textArea == w) break; for (i=0; inPanes; i++) { if (window->textPanes[i] == w) break; } if (i < window->nPanes) break; } if (window == NULL) return; /* The last action is recorded for the benefit of repeating the last action. Don't record repeat_macro and wipe out the real action */ if (!strcmp(actionName, "repeat_macro")) return; /* Record the action and its parameters */ actionString = actionToString(w, actionName, event, params, *numParams); if (actionString != NULL) { XtFree(LastCommand); LastCommand = actionString; } } /* ** Create a macro string to represent an invocation of an action routine. ** Returns NULL for non-operational or un-recordable actions. */ static char *actionToString(Widget w, char *actionName, XEvent *event, String *params, Cardinal numParams) { char chars[20], *charList[1], *outStr, *outPtr; KeySym keysym; int i, nChars, nParams, length, nameLength; #ifndef NO_XMIM int status; #endif if (isIgnoredAction(actionName) || isRedundantAction(actionName) || isMouseAction(actionName)) return NULL; /* Convert self_insert actions, to insert_string */ if (!strcmp(actionName, "self_insert") || !strcmp(actionName, "self-insert")) { actionName = "insert_string"; #ifdef NO_XMIM nChars = XLookupString((XKeyEvent *)event, chars, 19, &keysym, NULL); if (nChars == 0) return NULL; #else nChars = XmImMbLookupString(w, (XKeyEvent *)event, chars, 19, &keysym, &status); if (nChars == 0 || status == XLookupNone || status == XLookupKeySym || status == XBufferOverflow) return NULL; #endif chars[nChars] = '\0'; charList[0] = chars; params = charList; nParams = 1; } else nParams = numParams; /* Figure out the length of string required */ nameLength = strlen(actionName); length = nameLength + 3; for (i=0; imacroCmdData; XmString xmCancel; char *cCancel = "\0"; char message[MAX_TIMEOUT_MSG_LEN]; cmdData->bannerIsUp = True; /* Extract accelerator text from menu PushButtons */ XtVaGetValues(window->cancelMacroItem, XmNacceleratorText, &xmCancel, NULL); if (!XmStringEmpty(xmCancel)) { /* Translate Motif string to char* */ cCancel = GetXmStringText(xmCancel); /* Free Motif String */ XmStringFree(xmCancel); } /* Create message */ if (cCancel[0] == '\0') { strncpy(message, "Macro Command in Progress", MAX_TIMEOUT_MSG_LEN); message[MAX_TIMEOUT_MSG_LEN - 1] = '\0'; } else { sprintf(message, "Macro Command in Progress -- Press %s to Cancel", cCancel); } /* Free C-string */ XtFree(cCancel); SetModeMessage(window, message); cmdData->bannerTimeoutID = 0; } /* ** Work proc for continuing execution of a preempted macro. ** ** Xt WorkProcs are designed to run first-in first-out, which makes them ** very bad at sharing time between competing tasks. For this reason, it's ** usually bad to use work procs anywhere where their execution is likely to ** overlap. Using a work proc instead of a timer proc (which I usually ** prefer) here means macros will probably share time badly, but we're more ** interested in making the macros cancelable, and in continuing other work ** than having users run a bunch of them at once together. */ static Boolean continueWorkProc(XtPointer clientData) { WindowInfo *window = (WindowInfo *)clientData; macroCmdInfo *cmdData = window->macroCmdData; char *errMsg; int stat; DataValue result; stat = ContinueMacro(cmdData->context, &result, &errMsg); if (stat == MACRO_ERROR) { finishMacroCmdExecution(window); DialogF(DF_ERR, window->shell, 1, "Macro Error", "Error executing macro: %s", "OK", errMsg); return True; } else if (stat == MACRO_DONE) { finishMacroCmdExecution(window); return True; } else if (stat == MACRO_PREEMPT) { cmdData->continueWorkProcID = 0; return True; } /* Macro exceeded time slice, re-schedule it */ if (stat != MACRO_TIME_LIMIT) return True; /* shouldn't happen */ return False; } /* ** Copy fromString to toString replacing special characters in strings, such ** that they can be read back by the macro parser's string reader. i.e. double ** quotes are replaced by \", backslashes are replaced with \\, C-std control ** characters like \n are replaced with their backslash counterparts. This ** routine should be kept reasonably in sync with yylex in parse.y. Companion ** routine escapedStringLength predicts the length needed to write the string ** when it is expanded with the additional characters. Returns the number ** of characters to which the string expanded. */ static int escapeStringChars(char *fromString, char *toString) { char *e, *c, *outPtr = toString; /* substitute escape sequences */ for (c=fromString; *c!='\0'; c++) { for (e=EscapeChars; *e!='\0'; e++) { if (*c == *e) { *outPtr++ = '\\'; *outPtr++ = ReplaceChars[e-EscapeChars]; break; } } if (*e == '\0') *outPtr++ = *c; } *outPtr = '\0'; return outPtr - toString; } /* ** Predict the length of a string needed to hold a copy of "string" with ** special characters replaced with escape sequences by escapeStringChars. */ static int escapedStringLength(char *string) { char *c, *e; int length = 0; /* calculate length and allocate returned string */ for (c=string; *c!='\0'; c++) { for (e=EscapeChars; *e!='\0'; e++) { if (*c == *e) { length++; break; } } length++; } return length; } /* ** Built-in macro subroutine for getting the length of a string */ static int lengthMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char *string, stringStorage[TYPE_INT_STR_SIZE(int)]; if (nArgs != 1) return wrongNArgsErr(errMsg); if (!readStringArg(argList[0], &string, stringStorage, errMsg)) return False; result->tag = INT_TAG; result->val.n = strlen(string); return True; } /* ** Built-in macro subroutines for min and max */ static int minMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int minVal, value, i; if (nArgs == 1) return tooFewArgsErr(errMsg); if (!readIntArg(argList[0], &minVal, errMsg)) return False; for (i=0; itag = INT_TAG; result->val.n = minVal; return True; } static int maxMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int maxVal, value, i; if (nArgs == 1) return tooFewArgsErr(errMsg); if (!readIntArg(argList[0], &maxVal, errMsg)) return False; for (i=0; i maxVal ? value : maxVal; } result->tag = INT_TAG; result->val.n = maxVal; return True; } static int focusWindowMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char stringStorage[TYPE_INT_STR_SIZE(int)], *string; WindowInfo *w; char fullname[MAXPATHLEN]; char normalizedString[MAXPATHLEN]; /* Read the argument representing the window to focus to, and translate it into a pointer to a real WindowInfo */ if (nArgs != 1) return wrongNArgsErr(errMsg); if (!readStringArg(argList[0], &string, stringStorage, errMsg)) { return False; } else if (!strcmp(string, "last")) { w = WindowList; } else if (!strcmp(string, "next")) { w = window->next; } else if (strlen(string) >= MAXPATHLEN) { *errMsg = "Pathname too long in focus_window()"; return False; } else { /* just use the plain name as supplied */ for (w=WindowList; w != NULL; w = w->next) { sprintf(fullname, "%s%s", w->path, w->filename); if (!strcmp(string, fullname)) { break; } } /* didn't work? try normalizing the string passed in */ if (w == NULL) { strncpy(normalizedString, string, MAXPATHLEN); normalizedString[MAXPATHLEN-1] = '\0'; if (1 == NormalizePathname(normalizedString)) { /* Something is broken with the input pathname. */ *errMsg = "Pathname too long in focus_window()"; return False; } for (w=WindowList; w != NULL; w = w->next) { sprintf(fullname, "%s%s", w->path, w->filename); if (!strcmp(normalizedString, fullname)) break; } } } /* If no matching window was found, return empty string and do nothing */ if (w == NULL) { result->tag = STRING_TAG; result->val.str.rep = PERM_ALLOC_STR(""); result->val.str.len = 0; return True; } /* Change the focused window to the requested one */ SetMacroFocusWindow(w); /* turn on syntax highlight that might have been deferred */ if (w->highlightSyntax && w->highlightData==NULL) StartHighlighting(w, False); /* Return the name of the window */ result->tag = STRING_TAG; AllocNString(&result->val.str, strlen(w->path)+strlen(w->filename)+1); sprintf(result->val.str.rep, "%s%s", w->path, w->filename); return True; } /* ** Built-in macro subroutine for getting text from the current window's text ** buffer */ static int getRangeMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int from, to; textBuffer *buf = window->buffer; char *rangeText; /* Validate arguments and convert to int */ if (nArgs != 2) return wrongNArgsErr(errMsg); if (!readIntArg(argList[0], &from, errMsg)) return False; if (!readIntArg(argList[1], &to, errMsg)) return False; if (from < 0) from = 0; if (from > buf->length) from = buf->length; if (to < 0) to = 0; if (to > buf->length) to = buf->length; if (from > to) {int temp = from; from = to; to = temp;} /* Copy text from buffer (this extra copy could be avoided if textBuf.c provided a routine for writing into a pre-allocated string) */ result->tag = STRING_TAG; AllocNString(&result->val.str, to - from + 1); rangeText = BufGetRange(buf, from, to); BufUnsubstituteNullChars(rangeText, buf); strcpy(result->val.str.rep, rangeText); /* Note: after the un-substitution, it is possible that strlen() != len, but that's because strlen() can't deal with 0-characters. */ XtFree(rangeText); return True; } /* ** Built-in macro subroutine for getting a single character at the position ** given, from the current window */ static int getCharacterMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int pos; textBuffer *buf = window->buffer; /* Validate argument and convert it to int */ if (nArgs != 1) return wrongNArgsErr(errMsg); if (!readIntArg(argList[0], &pos, errMsg)) return False; if (pos < 0) pos = 0; if (pos > buf->length) pos = buf->length; /* Return the character in a pre-allocated string) */ result->tag = STRING_TAG; AllocNString(&result->val.str, 2); result->val.str.rep[0] = BufGetCharacter(buf, pos); BufUnsubstituteNullChars(result->val.str.rep, buf); /* Note: after the un-substitution, it is possible that strlen() != len, but that's because strlen() can't deal with 0-characters. */ return True; } /* ** Built-in macro subroutine for replacing text in the current window's text ** buffer */ static int replaceRangeMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int from, to; char stringStorage[TYPE_INT_STR_SIZE(int)], *string; textBuffer *buf = window->buffer; /* Validate arguments and convert to int */ if (nArgs != 3) return wrongNArgsErr(errMsg); if (!readIntArg(argList[0], &from, errMsg)) return False; if (!readIntArg(argList[1], &to, errMsg)) return False; if (!readStringArg(argList[2], &string, stringStorage, errMsg)) return False; if (from < 0) from = 0; if (from > buf->length) from = buf->length; if (to < 0) to = 0; if (to > buf->length) to = buf->length; if (from > to) {int temp = from; from = to; to = temp;} /* Don't allow modifications if the window is read-only */ if (IS_ANY_LOCKED(window->lockReasons)) { XBell(XtDisplay(window->shell), 0); result->tag = NO_TAG; return True; } /* There are no null characters in the string (because macro strings still have null termination), but if the string contains the character used by the buffer for null substitution, it could theoretically become a null. In the highly unlikely event that all of the possible substitution characters in the buffer are used up, stop the macro and tell the user of the failure */ if (!BufSubstituteNullChars(string, strlen(string), window->buffer)) { *errMsg = "Too much binary data in file"; return False; } /* Do the replace */ BufReplace(buf, from, to, string); result->tag = NO_TAG; return True; } /* ** Built-in macro subroutine for replacing the primary-selection selected ** text in the current window's text buffer */ static int replaceSelectionMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char stringStorage[TYPE_INT_STR_SIZE(int)], *string; /* Validate argument and convert to string */ if (nArgs != 1) return wrongNArgsErr(errMsg); if (!readStringArg(argList[0], &string, stringStorage, errMsg)) return False; /* Don't allow modifications if the window is read-only */ if (IS_ANY_LOCKED(window->lockReasons)) { XBell(XtDisplay(window->shell), 0); result->tag = NO_TAG; return True; } /* There are no null characters in the string (because macro strings still have null termination), but if the string contains the character used by the buffer for null substitution, it could theoretically become a null. In the highly unlikely event that all of the possible substitution characters in the buffer are used up, stop the macro and tell the user of the failure */ if (!BufSubstituteNullChars(string, strlen(string), window->buffer)) { *errMsg = "Too much binary data in file"; return False; } /* Do the replace */ BufReplaceSelected(window->buffer, string); result->tag = NO_TAG; return True; } /* ** Built-in macro subroutine for getting the text currently selected by ** the primary selection in the current window's text buffer, or in any ** part of screen if "any" argument is given */ static int getSelectionMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char *selText; /* Read argument list to check for "any" keyword, and get the appropriate selection */ if (nArgs != 0 && nArgs != 1) return wrongNArgsErr(errMsg); if (nArgs == 1) { if (argList[0].tag != STRING_TAG || strcmp(argList[0].val.str.rep, "any")) { *errMsg = "Unrecognized argument to %s"; return False; } selText = GetAnySelection(window); if (selText == NULL) selText = XtNewString(""); } else { selText = BufGetSelectionText(window->buffer); BufUnsubstituteNullChars(selText, window->buffer); } /* Return the text as an allocated string */ result->tag = STRING_TAG; AllocNStringCpy(&result->val.str, selText); XtFree(selText); return True; } /* ** Built-in macro subroutine for determining if implicit conversion of ** a string to number will succeed or fail */ static int validNumberMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char *string, stringStorage[TYPE_INT_STR_SIZE(int)]; if (nArgs != 1) { return wrongNArgsErr(errMsg); } if (!readStringArg(argList[0], &string, stringStorage, errMsg)) { return False; } result->tag = INT_TAG; result->val.n = StringToNum(string, NULL); return True; } /* ** Built-in macro subroutine for replacing a substring within another string */ static int replaceSubstringMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int from, to, length, replaceLen, outLen; char stringStorage[2][TYPE_INT_STR_SIZE(int)], *string, *replStr; /* Validate arguments and convert to int */ if (nArgs != 4) return wrongNArgsErr(errMsg); if (!readStringArg(argList[0], &string, stringStorage[1], errMsg)) return False; if (!readIntArg(argList[1], &from, errMsg)) return False; if (!readIntArg(argList[2], &to, errMsg)) return False; if (!readStringArg(argList[3], &replStr, stringStorage[1], errMsg)) return False; length = strlen(string); if (from < 0) from = 0; if (from > length) from = length; if (to < 0) to = 0; if (to > length) to = length; if (from > to) {int temp = from; from = to; to = temp;} /* Allocate a new string and do the replacement */ replaceLen = strlen(replStr); outLen = length - (to - from) + replaceLen; result->tag = STRING_TAG; AllocNString(&result->val.str, outLen+1); strncpy(result->val.str.rep, string, from); strncpy(&result->val.str.rep[from], replStr, replaceLen); strncpy(&result->val.str.rep[from + replaceLen], &string[to], length - to); return True; } /* ** Built-in macro subroutine for getting a substring of a string. ** Called as substring(string, from [, to]) */ static int substringMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int from, to, length; char stringStorage[TYPE_INT_STR_SIZE(int)], *string; /* Validate arguments and convert to int */ if (nArgs != 2 && nArgs != 3) return wrongNArgsErr(errMsg); if (!readStringArg(argList[0], &string, stringStorage, errMsg)) return False; if (!readIntArg(argList[1], &from, errMsg)) return False; length = to = strlen(string); if (nArgs == 3) if (!readIntArg(argList[2], &to, errMsg)) return False; if (from < 0) from += length; if (from < 0) from = 0; if (from > length) from = length; if (to < 0) to += length; if (to < 0) to = 0; if (to > length) to = length; if (from > to) to = from; /* Allocate a new string and copy the sub-string into it */ result->tag = STRING_TAG; AllocNStringNCpy(&result->val.str, &string[from], to - from); return True; } static int toupperMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int i, length; char stringStorage[TYPE_INT_STR_SIZE(int)], *string; /* Validate arguments and convert to int */ if (nArgs != 1) return wrongNArgsErr(errMsg); if (!readStringArg(argList[0], &string, stringStorage, errMsg)) return False; length = strlen(string); /* Allocate a new string and copy an uppercased version of the string it */ result->tag = STRING_TAG; AllocNString(&result->val.str, length + 1); for (i=0; ival.str.rep[i] = toupper((unsigned char)string[i]); return True; } static int tolowerMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int i, length; char stringStorage[TYPE_INT_STR_SIZE(int)], *string; /* Validate arguments and convert to int */ if (nArgs != 1) return wrongNArgsErr(errMsg); if (!readStringArg(argList[0], &string, stringStorage, errMsg)) return False; length = strlen(string); /* Allocate a new string and copy an lowercased version of the string it */ result->tag = STRING_TAG; AllocNString(&result->val.str, length + 1); for (i=0; ival.str.rep[i] = tolower((unsigned char)string[i]); return True; } static int stringToClipboardMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { long itemID = 0; XmString s; int stat; char stringStorage[TYPE_INT_STR_SIZE(int)], *string; /* Get the string argument */ if (nArgs != 1) return wrongNArgsErr(errMsg); if (!readStringArg(argList[0], &string, stringStorage, errMsg)) return False; /* Use the XmClipboard routines to copy the text to the clipboard. If errors occur, just give up. */ result->tag = NO_TAG; stat = SpinClipboardStartCopy(TheDisplay, XtWindow(window->textArea), s=XmStringCreateSimple("NEdit"), XtLastTimestampProcessed(TheDisplay), window->textArea, NULL, &itemID); XmStringFree(s); if (stat != ClipboardSuccess) return True; if (SpinClipboardCopy(TheDisplay, XtWindow(window->textArea), itemID, "STRING", string, strlen(string), 0, NULL) != ClipboardSuccess) { SpinClipboardEndCopy(TheDisplay, XtWindow(window->textArea), itemID); return True; } SpinClipboardEndCopy(TheDisplay, XtWindow(window->textArea), itemID); return True; } static int clipboardToStringMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { unsigned long length, retLength; long id = 0; /* Should have no arguments */ if (nArgs != 0) return wrongNArgsErr(errMsg); /* Ask if there's a string in the clipboard, and get its length */ if (SpinClipboardInquireLength(TheDisplay, XtWindow(window->shell), "STRING", &length) != ClipboardSuccess) { result->tag = STRING_TAG; result->val.str.rep = PERM_ALLOC_STR(""); result->val.str.len = 0; /* * Possibly, the clipboard can remain in a locked state after * a failure, so we try to remove the lock, just to be sure. */ SpinClipboardUnlock(TheDisplay, XtWindow(window->shell)); return True; } /* Allocate a new string to hold the data */ result->tag = STRING_TAG; AllocNString(&result->val.str, (int)length + 1); /* Copy the clipboard contents to the string */ if (SpinClipboardRetrieve(TheDisplay, XtWindow(window->shell), "STRING", result->val.str.rep, length, &retLength, &id) != ClipboardSuccess) { retLength = 0; /* * Possibly, the clipboard can remain in a locked state after * a failure, so we try to remove the lock, just to be sure. */ SpinClipboardUnlock(TheDisplay, XtWindow(window->shell)); } result->val.str.rep[retLength] = '\0'; result->val.str.len = retLength; return True; } /* ** Built-in macro subroutine for reading the contents of a text file into ** a string. On success, returns 1 in $readStatus, and the contents of the ** file as a string in the subroutine return value. On failure, returns ** the empty string "" and an 0 $readStatus. */ static int readFileMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char stringStorage[TYPE_INT_STR_SIZE(int)], *name; struct stat statbuf; FILE *fp; int readLen; /* Validate arguments and convert to int */ if (nArgs != 1) return wrongNArgsErr(errMsg); if (!readStringArg(argList[0], &name, stringStorage, errMsg)) return False; /* Read the whole file into an allocated string */ if ((fp = fopen(name, "r")) == NULL) goto errorNoClose; if (fstat(fileno(fp), &statbuf) != 0) goto error; result->tag = STRING_TAG; AllocNString(&result->val.str, statbuf.st_size+1); readLen = fread(result->val.str.rep, sizeof(char), statbuf.st_size+1, fp); if (ferror(fp)) goto error; if(!feof(fp)){ /* Couldn't trust file size. Use slower but more general method */ int chunkSize = 1024; char *buffer; buffer = XtMalloc(readLen * sizeof(char)); memcpy(buffer, result->val.str.rep, readLen * sizeof(char)); while (!feof(fp)){ buffer = XtRealloc(buffer, (readLen+chunkSize)*sizeof(char)); readLen += fread(&buffer[readLen], sizeof(char), chunkSize, fp); if (ferror(fp)){ XtFree(buffer); goto error; } } AllocNString(&result->val.str, readLen + 1); memcpy(result->val.str.rep, buffer, readLen * sizeof(char)); XtFree(buffer); } fclose(fp); /* Return the results */ ReturnGlobals[READ_STATUS]->value.tag = INT_TAG; ReturnGlobals[READ_STATUS]->value.val.n = True; return True; error: fclose(fp); errorNoClose: ReturnGlobals[READ_STATUS]->value.tag = INT_TAG; ReturnGlobals[READ_STATUS]->value.val.n = False; result->tag = STRING_TAG; result->val.str.rep = PERM_ALLOC_STR(""); result->val.str.len = 0; return True; } /* ** Built-in macro subroutines for writing or appending a string (parameter $1) ** to a file named in parameter $2. Returns 1 on successful write, or 0 if ** unsuccessful. */ static int writeFileMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { return writeOrAppendFile(False, window, argList, nArgs, result, errMsg); } static int appendFileMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { return writeOrAppendFile(True, window, argList, nArgs, result, errMsg); } static int writeOrAppendFile(int append, WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char stringStorage[2][TYPE_INT_STR_SIZE(int)], *name, *string; FILE *fp; /* Validate argument */ if (nArgs != 2) return wrongNArgsErr(errMsg); if (!readStringArg(argList[0], &string, stringStorage[1], errMsg)) return False; if (!readStringArg(argList[1], &name, stringStorage[0], errMsg)) return False; /* open the file */ if ((fp = fopen(name, append ? "a" : "w")) == NULL) { result->tag = INT_TAG; result->val.n = False; return True; } /* write the string to the file */ fwrite(string, sizeof(char), strlen(string), fp); if (ferror(fp)) { fclose(fp); result->tag = INT_TAG; result->val.n = False; return True; } fclose(fp); /* return the status */ result->tag = INT_TAG; result->val.n = True; return True; } /* ** Built-in macro subroutine for searching silently in a window without ** dialogs, beeps, or changes to the selection. Arguments are: $1: string to ** search for, $2: starting position. Optional arguments may include the ** strings: "wrap" to make the search wrap around the beginning or end of the ** string, "backward" or "forward" to change the search direction ("forward" is ** the default), "literal", "case" or "regex" to change the search type ** (default is "literal"). ** ** Returns the starting position of the match, or -1 if nothing matched. ** also returns the ending position of the match in $searchEndPos */ static int searchMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { DataValue newArgList[9]; /* Use the search string routine, by adding the buffer contents as the string argument */ if (nArgs > 8) return wrongNArgsErr(errMsg); /* we remove constness from BufAsString() result since we know searchStringMS will not modify the result */ newArgList[0].tag = STRING_TAG; newArgList[0].val.str.rep = (char *)BufAsString(window->buffer); newArgList[0].val.str.len = window->buffer->length; /* copy other arguments to the new argument list */ memcpy(&newArgList[1], argList, nArgs * sizeof(DataValue)); return searchStringMS(window, newArgList, nArgs+1, result, errMsg); } /* ** Built-in macro subroutine for searching a string. Arguments are $1: ** string to search in, $2: string to search for, $3: starting position. ** Optional arguments may include the strings: "wrap" to make the search ** wrap around the beginning or end of the string, "backward" or "forward" ** to change the search direction ("forward" is the default), "literal", ** "case" or "regex" to change the search type (default is "literal"). ** ** Returns the starting position of the match, or -1 if nothing matched. ** also returns the ending position of the match in $searchEndPos */ static int searchStringMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int beginPos, wrap, direction, found = False, foundStart, foundEnd, type; int skipSearch = False, len; char stringStorage[2][TYPE_INT_STR_SIZE(int)], *string, *searchStr; /* Validate arguments and convert to proper types */ if (nArgs < 3) return tooFewArgsErr(errMsg); if (!readStringArg(argList[0], &string, stringStorage[0], errMsg)) return False; if (!readStringArg(argList[1], &searchStr, stringStorage[1], errMsg)) return False; if (!readIntArg(argList[2], &beginPos, errMsg)) return False; if (!readSearchArgs(&argList[3], nArgs-3, &direction, &type, &wrap, errMsg)) return False; len = argList[0].val.str.len; if (beginPos > len) { if (direction == SEARCH_FORWARD) { if (wrap) { beginPos = 0; /* Wrap immediately */ } else { found = False; skipSearch = True; } } else { beginPos = len; } } else if (beginPos < 0) { if (direction == SEARCH_BACKWARD) { if (wrap) { beginPos = len; /* Wrap immediately */ } else { found = False; skipSearch = True; } } else { beginPos = 0; } } if (!skipSearch) found = SearchString(string, searchStr, direction, type, wrap, beginPos, &foundStart, &foundEnd, NULL, NULL, GetWindowDelimiters(window)); /* Return the results */ ReturnGlobals[SEARCH_END]->value.tag = INT_TAG; ReturnGlobals[SEARCH_END]->value.val.n = found ? foundEnd : 0; result->tag = INT_TAG; result->val.n = found ? foundStart : -1; return True; } /* ** Built-in macro subroutine for replacing all occurences of a search string in ** a string with a replacement string. Arguments are $1: string to search in, ** $2: string to search for, $3: replacement string. Also takes an optional ** search type: one of "literal", "case" or "regex" (default is "literal"), and ** an optional "copy" argument. ** ** Returns a new string with all of the replacements done. If no replacements ** were performed and "copy" was specified, returns a copy of the original ** string. Otherwise returns an empty string (""). */ static int replaceInStringMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char stringStorage[3][TYPE_INT_STR_SIZE(int)], *string, *searchStr, *replaceStr; char *argStr, *replacedStr; int searchType = SEARCH_LITERAL, copyStart, copyEnd; int replacedLen, replaceEnd, force=False, i; /* Validate arguments and convert to proper types */ if (nArgs < 3 || nArgs > 5) return wrongNArgsErr(errMsg); if (!readStringArg(argList[0], &string, stringStorage[0], errMsg)) return False; if (!readStringArg(argList[1], &searchStr, stringStorage[1], errMsg)) return False; if (!readStringArg(argList[2], &replaceStr, stringStorage[2], errMsg)) return False; for (i = 3; i < nArgs; i++) { /* Read the optional search type and force arguments */ if (!readStringArg(argList[i], &argStr, stringStorage[2], errMsg)) return False; if (!StringToSearchType(argStr, &searchType)) { /* It's not a search type. is it "copy"? */ if (!strcmp(argStr, "copy")) { force = True; } else { *errMsg = "unrecognized argument to %s"; return False; } } } /* Do the replace */ replacedStr = ReplaceAllInString(string, searchStr, replaceStr, searchType, ©Start, ©End, &replacedLen, GetWindowDelimiters(window)); /* Return the results */ result->tag = STRING_TAG; if (replacedStr == NULL) { if (force) { /* Just copy the original DataValue */ if (argList[0].tag == STRING_TAG) { result->val.str.rep = argList[0].val.str.rep; result->val.str.len = argList[0].val.str.len; } else { AllocNStringCpy(&result->val.str, string); } } else { result->val.str.rep = PERM_ALLOC_STR(""); result->val.str.len = 0; } } else { size_t remainder = strlen(&string[copyEnd]); replaceEnd = copyStart + replacedLen; AllocNString(&result->val.str, replaceEnd + remainder + 1); strncpy(result->val.str.rep, string, copyStart); strcpy(&result->val.str.rep[copyStart], replacedStr); strcpy(&result->val.str.rep[replaceEnd], &string[copyEnd]); XtFree(replacedStr); } return True; } static int readSearchArgs(DataValue *argList, int nArgs, int *searchDirection, int *searchType, int *wrap, char **errMsg) { int i; char *argStr, stringStorage[TYPE_INT_STR_SIZE(int)]; *wrap = False; *searchDirection = SEARCH_FORWARD; *searchType = SEARCH_LITERAL; for (i=0; ilastFocus, pos); result->tag = NO_TAG; return True; } static int selectMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int start, end, startTmp; /* Get arguments and convert to int */ if (nArgs != 2) return wrongNArgsErr(errMsg); if (!readIntArg(argList[0], &start, errMsg)) return False; if (!readIntArg(argList[1], &end, errMsg)) return False; /* Verify integrity of arguments */ if (start > end) { startTmp = start; start = end; end = startTmp; } if (start < 0) start = 0; if (start > window->buffer->length) start = window->buffer->length; if (end < 0) end = 0; if (end > window->buffer->length) end = window->buffer->length; /* Make the selection */ BufSelect(window->buffer, start, end); result->tag = NO_TAG; return True; } static int selectRectangleMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int start, end, left, right; /* Get arguments and convert to int */ if (nArgs != 4) return wrongNArgsErr(errMsg); if (!readIntArg(argList[0], &start, errMsg)) return False; if (!readIntArg(argList[1], &end, errMsg)) return False; if (!readIntArg(argList[2], &left, errMsg)) return False; if (!readIntArg(argList[3], &right, errMsg)) return False; /* Make the selection */ BufRectSelect(window->buffer, start, end, left, right); result->tag = NO_TAG; return True; } /* ** Macro subroutine to ring the bell */ static int beepMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { if (nArgs != 0) return wrongNArgsErr(errMsg); XBell(XtDisplay(window->shell), 0); result->tag = NO_TAG; return True; } static int tPrintMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char stringStorage[TYPE_INT_STR_SIZE(int)], *string; int i; if (nArgs == 0) return tooFewArgsErr(errMsg); for (i=0; itag = NO_TAG; return True; } /* ** Built-in macro subroutine for getting the value of an environment variable */ static int getenvMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char stringStorage[1][TYPE_INT_STR_SIZE(int)]; char *name; char *value; /* Get name of variable to get */ if (nArgs != 1) return wrongNArgsErr(errMsg); if (!readStringArg(argList[0], &name, stringStorage[0], errMsg)) { *errMsg = "argument to %s must be a string"; return False; } value = getenv(name); if (value == NULL) value = ""; /* Return the text as an allocated string */ result->tag = STRING_TAG; AllocNStringCpy(&result->val.str, value); return True; } static int shellCmdMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char stringStorage[2][TYPE_INT_STR_SIZE(int)], *cmdString, *inputString; if (nArgs != 2) return wrongNArgsErr(errMsg); if (!readStringArg(argList[0], &cmdString, stringStorage[0], errMsg)) return False; if (!readStringArg(argList[1], &inputString, stringStorage[1], errMsg)) return False; /* Shell command execution requires that the macro be suspended, so this subroutine can't be run if macro execution can't be interrupted */ if (MacroRunWindow()->macroCmdData == NULL) { *errMsg = "%s can't be called from non-suspendable context"; return False; } #ifdef VMS *errMsg = "Shell commands not supported under VMS"; return False; #else ShellCmdToMacroString(window, cmdString, inputString); result->tag = INT_TAG; result->val.n = 0; return True; #endif /*VMS*/ } /* ** Method used by ShellCmdToMacroString (called by shellCmdMS), for returning ** macro string and exit status after the execution of a shell command is ** complete. (Sorry about the poor modularity here, it's just not worth ** teaching other modules about macro return globals, since other than this, ** they're not used outside of macro.c) */ void ReturnShellCommandOutput(WindowInfo *window, const char *outText, int status) { DataValue retVal; macroCmdInfo *cmdData = window->macroCmdData; if (cmdData == NULL) return; retVal.tag = STRING_TAG; AllocNStringCpy(&retVal.val.str, outText); ModifyReturnedValue(cmdData->context, retVal); ReturnGlobals[SHELL_CMD_STATUS]->value.tag = INT_TAG; ReturnGlobals[SHELL_CMD_STATUS]->value.val.n = status; } static int dialogMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { macroCmdInfo *cmdData; char stringStorage[TYPE_INT_STR_SIZE(int)]; char btnStorage[TYPE_INT_STR_SIZE(int)]; char *btnLabel; char *message; Arg al[20]; int ac; Widget dialog, btn; int i, nBtns; XmString s1, s2; /* Ignore the focused window passed as the function argument and put the dialog up over the window which is executing the macro */ window = MacroRunWindow(); cmdData = window->macroCmdData; /* Dialogs require macro to be suspended and interleaved with other macros. This subroutine can't be run if macro execution can't be interrupted */ if (!cmdData) { *errMsg = "%s can't be called from non-suspendable context"; return False; } /* Read and check the arguments. The first being the dialog message, and the rest being the button labels */ if (nArgs == 0) { *errMsg = "%s subroutine called with no arguments"; return False; } if (!readStringArg(argList[0], &message, stringStorage, errMsg)) { return False; } /* check that all button labels can be read */ for (i=1; ishell, "macroDialog", al, ac); if (1 == nArgs) { /* Only set margin width for the default OK button */ XtVaSetValues(XmMessageBoxGetChild(dialog, XmDIALOG_OK_BUTTON), XmNmarginWidth, BUTTON_WIDTH_MARGIN, NULL); } XmStringFree(s1); XmStringFree(s2); AddMotifCloseCallback(XtParent(dialog), dialogCloseCB, window); XtAddCallback(dialog, XmNokCallback, dialogBtnCB, window); XtVaSetValues(XmMessageBoxGetChild(dialog, XmDIALOG_OK_BUTTON), XmNuserData, (XtPointer)1, NULL); cmdData->dialog = dialog; /* Unmanage default buttons, except for "OK" */ XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON)); XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON)); /* Make callback for the unmanaged cancel button (which can still get executed via the esc key) activate close box action */ XtAddCallback(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON), XmNactivateCallback, dialogCloseCB, window); /* Add user specified buttons (1st is already done) */ for (i=1; itag = INT_TAG; result->val.n = 0; return True; } static void dialogBtnCB(Widget w, XtPointer clientData, XtPointer callData) { WindowInfo *window = (WindowInfo *)clientData; macroCmdInfo *cmdData = window->macroCmdData; XtPointer userData; DataValue retVal; /* Return the index of the button which was pressed (stored in the userData field of the button widget). The 1st button, being a gadget, is not returned in w. */ if (cmdData == NULL) return; /* shouldn't happen */ if (XtClass(w) == xmPushButtonWidgetClass) { XtVaGetValues(w, XmNuserData, &userData, NULL); retVal.val.n = (int)userData; } else retVal.val.n = 1; retVal.tag = INT_TAG; ModifyReturnedValue(cmdData->context, retVal); /* Pop down the dialog */ XtDestroyWidget(XtParent(cmdData->dialog)); cmdData->dialog = NULL; /* Continue preempted macro execution */ ResumeMacroExecution(window); } static void dialogCloseCB(Widget w, XtPointer clientData, XtPointer callData) { WindowInfo *window = (WindowInfo *)clientData; macroCmdInfo *cmdData = window->macroCmdData; DataValue retVal; /* Return 0 to show that the dialog was closed via the window close box */ retVal.val.n = 0; retVal.tag = INT_TAG; ModifyReturnedValue(cmdData->context, retVal); /* Pop down the dialog */ XtDestroyWidget(XtParent(cmdData->dialog)); cmdData->dialog = NULL; /* Continue preempted macro execution */ ResumeMacroExecution(window); } #ifdef LESSTIF_VERSION static void dialogEscCB(Widget w, XtPointer clientData, XEvent *event, Boolean *cont) { if (event->xkey.keycode != XKeysymToKeycode(XtDisplay(w), XK_Escape)) return; if (clientData != NULL) { dialogCloseCB(w, (WindowInfo *)clientData, NULL); } *cont = False; } #endif /* LESSTIF_VERSION */ static int stringDialogMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { macroCmdInfo *cmdData; char stringStorage[TYPE_INT_STR_SIZE(int)]; char btnStorage[TYPE_INT_STR_SIZE(int)]; char *btnLabel; char *message; Widget dialog, btn; int i, nBtns; XmString s1, s2; Arg al[20]; int ac; /* Ignore the focused window passed as the function argument and put the dialog up over the window which is executing the macro */ window = MacroRunWindow(); cmdData = window->macroCmdData; /* Dialogs require macro to be suspended and interleaved with other macros. This subroutine can't be run if macro execution can't be interrupted */ if (!cmdData) { *errMsg = "%s can't be called from non-suspendable context"; return False; } /* Read and check the arguments. The first being the dialog message, and the rest being the button labels */ if (nArgs == 0) { *errMsg = "%s subroutine called with no arguments"; return False; } if (!readStringArg(argList[0], &message, stringStorage, errMsg)) { return False; } /* check that all button labels can be read */ for (i=1; ishell, "macroStringDialog", al, ac); if (1 == nArgs) { /* Only set margin width for the default OK button */ XtVaSetValues(XmSelectionBoxGetChild(dialog, XmDIALOG_OK_BUTTON), XmNmarginWidth, BUTTON_WIDTH_MARGIN, NULL); } XmStringFree(s1); XmStringFree(s2); AddMotifCloseCallback(XtParent(dialog), stringDialogCloseCB, window); XtAddCallback(dialog, XmNokCallback, stringDialogBtnCB, window); XtVaSetValues(XmSelectionBoxGetChild(dialog, XmDIALOG_OK_BUTTON), XmNuserData, (XtPointer)1, NULL); cmdData->dialog = dialog; /* Unmanage unneded widgets */ XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON)); XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON)); /* Make callback for the unmanaged cancel button (which can still get executed via the esc key) activate close box action */ XtAddCallback(XmSelectionBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON), XmNactivateCallback, stringDialogCloseCB, window); /* Add user specified buttons (1st is already done). Selection box requires a place-holder widget to be added before buttons can be added, that's what the separator below is for */ XtVaCreateWidget("x", xmSeparatorWidgetClass, dialog, NULL); for (i=1; itag = INT_TAG; result->val.n = 0; return True; } static void stringDialogBtnCB(Widget w, XtPointer clientData, XtPointer callData) { WindowInfo *window = (WindowInfo *)clientData; macroCmdInfo *cmdData = window->macroCmdData; XtPointer userData; DataValue retVal; char *text; int btnNum; /* shouldn't happen, but would crash if it did */ if (cmdData == NULL) return; /* Return the string entered in the selection text area */ text = XmTextGetString(XmSelectionBoxGetChild(cmdData->dialog, XmDIALOG_TEXT)); retVal.tag = STRING_TAG; AllocNStringCpy(&retVal.val.str, text); XtFree(text); ModifyReturnedValue(cmdData->context, retVal); /* Find the index of the button which was pressed (stored in the userData field of the button widget). The 1st button, being a gadget, is not returned in w. */ if (XtClass(w) == xmPushButtonWidgetClass) { XtVaGetValues(w, XmNuserData, &userData, NULL); btnNum = (int)userData; } else btnNum = 1; /* Return the button number in the global variable $string_dialog_button */ ReturnGlobals[STRING_DIALOG_BUTTON]->value.tag = INT_TAG; ReturnGlobals[STRING_DIALOG_BUTTON]->value.val.n = btnNum; /* Pop down the dialog */ XtDestroyWidget(XtParent(cmdData->dialog)); cmdData->dialog = NULL; /* Continue preempted macro execution */ ResumeMacroExecution(window); } static void stringDialogCloseCB(Widget w, XtPointer clientData, XtPointer callData) { WindowInfo *window = (WindowInfo *)clientData; macroCmdInfo *cmdData = window->macroCmdData; DataValue retVal; /* shouldn't happen, but would crash if it did */ if (cmdData == NULL) return; /* Return an empty string */ retVal.tag = STRING_TAG; retVal.val.str.rep = PERM_ALLOC_STR(""); retVal.val.str.len = 0; ModifyReturnedValue(cmdData->context, retVal); /* Return button number 0 in the global variable $string_dialog_button */ ReturnGlobals[STRING_DIALOG_BUTTON]->value.tag = INT_TAG; ReturnGlobals[STRING_DIALOG_BUTTON]->value.val.n = 0; /* Pop down the dialog */ XtDestroyWidget(XtParent(cmdData->dialog)); cmdData->dialog = NULL; /* Continue preempted macro execution */ ResumeMacroExecution(window); } #ifdef LESSTIF_VERSION static void stringDialogEscCB(Widget w, XtPointer clientData, XEvent *event, Boolean *cont) { if (event->xkey.keycode != XKeysymToKeycode(XtDisplay(w), XK_Escape)) return; if (clientData != NULL) { stringDialogCloseCB(w, (WindowInfo *)clientData, NULL); } *cont = False; } #endif /* LESSTIF_VERSION */ /* ** A subroutine to put up a calltip ** First arg is either text to be displayed or a key for tip/tag lookup. ** Optional second arg is the buffer position beneath which to display the ** upper-left corner of the tip. Default (or -1) puts it under the cursor. ** Additional optional arguments: ** "tipText": (default) Indicates first arg is text to be displayed in tip. ** "tipKey": Indicates first arg is key in calltips database. If key ** is not found in tip database then the tags database is also ** searched. ** "tagKey": Indicates first arg is key in tags database. (Skips ** search in calltips database.) ** "center": Horizontally center the calltip at the position ** "right": Put the right edge of the calltip at the position ** "center" and "right" cannot both be specified. ** "above": Place the calltip above the position ** "strict": Don't move the calltip to keep it on-screen and away ** from the cursor's line. ** ** Returns the new calltip's ID on success, 0 on failure. ** ** Does this need to go on IgnoredActions? I don't think so, since ** showing a calltip may be part of the action you want to learn. */ static int calltipMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char stringStorage[TYPE_INT_STR_SIZE(int)], *tipText, *txtArg; Boolean anchored = False, lookup = True; int mode = -1, i; int anchorPos, hAlign = TIP_LEFT, vAlign = TIP_BELOW, alignMode = TIP_SLOPPY; /* Read and check the string */ if (nArgs < 1) { *errMsg = "%s subroutine called with too few arguments"; return False; } if (nArgs > 6) { *errMsg = "%s subroutine called with too many arguments"; return False; } /* Read the tip text or key */ if (!readStringArg(argList[0], &tipText, stringStorage, errMsg)) return False; /* Read the anchor position (-1 for unanchored) */ if (nArgs > 1) { if (!readIntArg(argList[1], &anchorPos, errMsg)) return False; } else { anchorPos = -1; } if (anchorPos >= 0) anchored = True; /* Any further args are directives for relative positioning */ for (i = 2; i < nArgs; ++i) { if (!readStringArg(argList[i], &txtArg, stringStorage, errMsg)){ return False; } switch( txtArg[0] ) { case 'c': if (strcmp(txtArg, "center")) goto bad_arg; hAlign = TIP_CENTER; break; case 'r': if (strcmp(txtArg, "right")) goto bad_arg; hAlign = TIP_RIGHT; break; case 'a': if (strcmp(txtArg, "above")) goto bad_arg; vAlign = TIP_ABOVE; break; case 's': if (strcmp(txtArg, "strict")) goto bad_arg; alignMode = TIP_STRICT; break; case 't': if (!strcmp(txtArg, "tipText")) mode = -1; else if (!strcmp(txtArg, "tipKey")) mode = TIP; else if (!strcmp(txtArg, "tagKey")) mode = TIP_FROM_TAG; else goto bad_arg; break; default: goto bad_arg; } } result->tag = INT_TAG; if (mode < 0) lookup = False; /* Look up (maybe) a calltip and display it */ result->val.n = ShowTipString( window, tipText, anchored, anchorPos, lookup, mode, hAlign, vAlign, alignMode ); return True; bad_arg: /* This is how the (more informative) global var. version would work, assuming there was a global buffer called msg. */ /* sprintf(msg, "unrecognized argument to %%s: \"%s\"", txtArg); *errMsg = msg; */ *errMsg = "unrecognized argument to %s"; return False; } /* ** A subroutine to kill the current calltip */ static int killCalltipMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int calltipID = 0; if (nArgs > 1) { *errMsg = "%s subroutine called with too many arguments"; return False; } if (nArgs > 0) { if (!readIntArg(argList[0], &calltipID, errMsg)) return False; } KillCalltip( window, calltipID ); result->tag = NO_TAG; return True; } /* * A subroutine to get the ID of the current calltip, or 0 if there is none. */ static int calltipIDMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = GetCalltipID(window, 0); return True; } /* ** filename_dialog([title[, mode[, defaultPath[, filter[, defaultName]]]]]) ** ** Presents a FileSelectionDialog to the user prompting for a new file. ** ** Options are: ** title - will be the title of the dialog, defaults to "Choose file". ** mode - if set to "exist" (default), the "New File Name" TextField ** of the FSB will be unmanaged. If "new", the TextField will ** be managed. ** defaultPath - is the default path to use. Default (or "") will use the ** active document's directory. ** filter - the file glob which determines which files to display. ** Is set to "*" if filter is "" and by default. ** defaultName - is the default filename that is filled in automatically. ** ** Returns "" if the user cancelled the dialog, otherwise returns the path to ** the file that was selected ** ** Note that defaultName doesn't work on all *tifs. :-( */ static int filenameDialogMS(WindowInfo* window, DataValue* argList, int nArgs, DataValue* result, char** errMsg) { char stringStorage[5][TYPE_INT_STR_SIZE(int)]; char filename[MAXPATHLEN + 1]; char* title = "Choose Filename"; char* mode = "exist"; char* defaultPath = ""; char* filter = ""; char* defaultName = ""; char* orgDefaultPath; char* orgFilter; int gfnResult; /* Ignore the focused window passed as the function argument and put the dialog up over the window which is executing the macro */ window = MacroRunWindow(); /* Dialogs require macro to be suspended and interleaved with other macros. This subroutine can't be run if macro execution can't be interrupted */ if (NULL == window->macroCmdData) { M_FAILURE("%s can't be called from non-suspendable context"); } /* Get the argument list. */ if (nArgs > 0 && !readStringArg(argList[0], &title, stringStorage[0], errMsg)) { return False; } if (nArgs > 1 && !readStringArg(argList[1], &mode, stringStorage[1], errMsg)) { return False; } if (0 != strcmp(mode, "exist") && 0 != strcmp(mode, "new")) { M_FAILURE("Invalid value for mode in %s"); } if (nArgs > 2 && !readStringArg(argList[2], &defaultPath, stringStorage[2], errMsg)) { return False; } if (nArgs > 3 && !readStringArg(argList[3], &filter, stringStorage[3], errMsg)) { return False; } if (nArgs > 4 && !readStringArg(argList[4], &defaultName, stringStorage[4], errMsg)) { return False; } if (nArgs > 5) { M_FAILURE("%s called with too many arguments. Expects at most 5 arguments."); } /* Set default directory (saving original for later) */ orgDefaultPath = GetFileDialogDefaultDirectory(); if ('\0' != defaultPath[0]) { SetFileDialogDefaultDirectory(defaultPath); } else { SetFileDialogDefaultDirectory(window->path); } /* Set filter (saving original for later) */ orgFilter = GetFileDialogDefaultPattern(); if ('\0' != filter[0]) { SetFileDialogDefaultPattern(filter); } /* Fork to one of the worker methods from util/getfiles.c. (This should obviously be refactored.) */ if (0 == strcmp(mode, "exist")) { gfnResult = GetExistingFilename(window->shell, title, filename); } else { gfnResult = GetNewFilename(window->shell, title, filename, defaultName); } /* Invalid values are weeded out above. */ /* Reset original values and free temps */ SetFileDialogDefaultDirectory(orgDefaultPath); SetFileDialogDefaultPattern(orgFilter); XtFree(orgDefaultPath); XtFree(orgFilter); result->tag = STRING_TAG; if (GFN_OK == gfnResult) { /* Got a string, copy it to the result */ if (!AllocNStringNCpy(&result->val.str, filename, MAXPATHLEN)) { M_FAILURE("failed to allocate return value: %s"); } } else { /* User cancelled. Return "" */ result->val.str.rep = PERM_ALLOC_STR(""); result->val.str.len = 0; } return True; } /* T Balinski */ static int listDialogMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { macroCmdInfo *cmdData; char stringStorage[TYPE_INT_STR_SIZE(int)]; char textStorage[TYPE_INT_STR_SIZE(int)]; char btnStorage[TYPE_INT_STR_SIZE(int)]; char *btnLabel; char *message, *text; Widget dialog, btn; int i, nBtns; XmString s1, s2; long nlines = 0; char *p, *old_p, **text_lines, *tmp; int tmp_len; int n, is_last; XmString *test_strings; int tabDist; Arg al[20]; int ac; /* Ignore the focused window passed as the function argument and put the dialog up over the window which is executing the macro */ window = MacroRunWindow(); cmdData = window->macroCmdData; /* Dialogs require macro to be suspended and interleaved with other macros. This subroutine can't be run if macro execution can't be interrupted */ if (!cmdData) { *errMsg = "%s can't be called from non-suspendable context"; return False; } /* Read and check the arguments. The first being the dialog message, and the rest being the button labels */ if (nArgs < 2) { *errMsg = "%s subroutine called with no message, string or arguments"; return False; } if (!readStringArg(argList[0], &message, stringStorage, errMsg)) return False; if (!readStringArg(argList[1], &text, textStorage, errMsg)) return False; if (!text || text[0] == '\0') { *errMsg = "%s subroutine called with empty list data"; return False; } /* check that all button labels can be read */ for (i=2; ibuffer->tabDist; /* load the table */ n = 0; is_last = 0; p = old_p = text; tmp_len = 0; /* current allocated size of temporary buffer tmp */ tmp = malloc(1); /* temporary buffer into which to expand tabs */ do { is_last = (*p == '\0'); if (*p == '\n' || is_last) { *p = '\0'; if (strlen(old_p) > 0) { /* only include non-empty lines */ char *s, *t; int l; /* save the actual text line in text_lines[n] */ text_lines[n] = (char *)XtMalloc(strlen(old_p) + 1); strcpy(text_lines[n], old_p); /* work out the tabs expanded length */ for (s = old_p, l = 0; *s; s++) l += (*s == '\t') ? tabDist - (l % tabDist) : 1; /* verify tmp is big enough then tab-expand old_p into tmp */ if (l > tmp_len) tmp = realloc(tmp, (tmp_len = l) + 1); for (s = old_p, t = tmp, l = 0; *s; s++) { if (*s == '\t') { for (i = tabDist - (l % tabDist); i--; l++) *t++ = ' '; } else { *t++ = *s; l++; } } *t = '\0'; /* that's it: tmp is the tab-expanded version of old_p */ test_strings[n] = MKSTRING(tmp); n++; } old_p = p + 1; if (!is_last) *p = '\n'; /* put back our newline */ } p++; } while (!is_last); free(tmp); /* don't need this anymore */ nlines = n; if (nlines == 0) { test_strings[0] = MKSTRING(""); nlines = 1; } /* Create the selection box dialog widget and its dialog shell parent */ ac = 0; XtSetArg(al[ac], XmNtitle, " "); ac++; XtSetArg(al[ac], XmNlistLabelString, s1=MKSTRING(message)); ac++; XtSetArg(al[ac], XmNlistItems, test_strings); ac++; XtSetArg(al[ac], XmNlistItemCount, nlines); ac++; XtSetArg(al[ac], XmNlistVisibleItemCount, (nlines > 10) ? 10 : nlines); ac++; XtSetArg(al[ac], XmNokLabelString, s2=XmStringCreateSimple(btnLabel)); ac++; dialog = CreateSelectionDialog(window->shell, "macroListDialog", al, ac); if (2 == nArgs) { /* Only set margin width for the default OK button */ XtVaSetValues(XmSelectionBoxGetChild(dialog, XmDIALOG_OK_BUTTON), XmNmarginWidth, BUTTON_WIDTH_MARGIN, NULL); } AddMotifCloseCallback(XtParent(dialog), listDialogCloseCB, window); XtAddCallback(dialog, XmNokCallback, listDialogBtnCB, window); XtVaSetValues(XmSelectionBoxGetChild(dialog, XmDIALOG_OK_BUTTON), XmNuserData, (XtPointer)1, NULL); XmStringFree(s1); XmStringFree(s2); cmdData->dialog = dialog; /* forget lines stored in list */ while (n--) XmStringFree(test_strings[n]); XtFree((char *)test_strings); /* modify the list */ XtVaSetValues(XmSelectionBoxGetChild(dialog, XmDIALOG_LIST), XmNselectionPolicy, XmSINGLE_SELECT, XmNuserData, (XtPointer)text_lines, NULL); /* Unmanage unneeded widgets */ XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_APPLY_BUTTON)); XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON)); XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON)); XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT)); XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_SELECTION_LABEL)); /* Make callback for the unmanaged cancel button (which can still get executed via the esc key) activate close box action */ XtAddCallback(XmSelectionBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON), XmNactivateCallback, listDialogCloseCB, window); /* Add user specified buttons (1st is already done). Selection box requires a place-holder widget to be added before buttons can be added, that's what the separator below is for */ XtVaCreateWidget("x", xmSeparatorWidgetClass, dialog, NULL); for (i=1; itag = INT_TAG; result->val.n = 0; return True; } static void listDialogBtnCB(Widget w, XtPointer clientData, XtPointer callData) { WindowInfo *window = (WindowInfo *)clientData; macroCmdInfo *cmdData = window->macroCmdData; XtPointer userData; DataValue retVal; char *text; char **text_lines; int btnNum; int n_sel, *seltable, sel_index = 0; Widget theList; size_t length; /* shouldn't happen, but would crash if it did */ if (cmdData == NULL) return; theList = XmSelectionBoxGetChild(cmdData->dialog, XmDIALOG_LIST); /* Return the string selected in the selection list area */ XtVaGetValues(theList, XmNuserData, &text_lines, NULL); if (!XmListGetSelectedPos(theList, &seltable, &n_sel)) { n_sel = 0; } else { sel_index = seltable[0] - 1; XtFree((XtPointer)seltable); } if (!n_sel) { text = PERM_ALLOC_STR(""); length = 0; } else { length = strlen((char *)text_lines[sel_index]); text = AllocString(length + 1); strcpy(text, text_lines[sel_index]); } /* don't need text_lines anymore: free it */ for (sel_index = 0; text_lines[sel_index]; sel_index++) XtFree((XtPointer)text_lines[sel_index]); XtFree((XtPointer)text_lines); retVal.tag = STRING_TAG; retVal.val.str.rep = text; retVal.val.str.len = length; ModifyReturnedValue(cmdData->context, retVal); /* Find the index of the button which was pressed (stored in the userData field of the button widget). The 1st button, being a gadget, is not returned in w. */ if (XtClass(w) == xmPushButtonWidgetClass) { XtVaGetValues(w, XmNuserData, &userData, NULL); btnNum = (int)userData; } else btnNum = 1; /* Return the button number in the global variable $list_dialog_button */ ReturnGlobals[LIST_DIALOG_BUTTON]->value.tag = INT_TAG; ReturnGlobals[LIST_DIALOG_BUTTON]->value.val.n = btnNum; /* Pop down the dialog */ XtDestroyWidget(XtParent(cmdData->dialog)); cmdData->dialog = NULL; /* Continue preempted macro execution */ ResumeMacroExecution(window); } static void listDialogCloseCB(Widget w, XtPointer clientData, XtPointer callData) { WindowInfo *window = (WindowInfo *)clientData; macroCmdInfo *cmdData = window->macroCmdData; DataValue retVal; char **text_lines; int sel_index; Widget theList; /* shouldn't happen, but would crash if it did */ if (cmdData == NULL) return; /* don't need text_lines anymore: retrieve it then free it */ theList = XmSelectionBoxGetChild(cmdData->dialog, XmDIALOG_LIST); XtVaGetValues(theList, XmNuserData, &text_lines, NULL); for (sel_index = 0; text_lines[sel_index]; sel_index++) XtFree((XtPointer)text_lines[sel_index]); XtFree((XtPointer)text_lines); /* Return an empty string */ retVal.tag = STRING_TAG; retVal.val.str.rep = PERM_ALLOC_STR(""); retVal.val.str.len = 0; ModifyReturnedValue(cmdData->context, retVal); /* Return button number 0 in the global variable $list_dialog_button */ ReturnGlobals[LIST_DIALOG_BUTTON]->value.tag = INT_TAG; ReturnGlobals[LIST_DIALOG_BUTTON]->value.val.n = 0; /* Pop down the dialog */ XtDestroyWidget(XtParent(cmdData->dialog)); cmdData->dialog = NULL; /* Continue preempted macro execution */ ResumeMacroExecution(window); } /* T Balinski End */ #ifdef LESSTIF_VERSION static void listDialogEscCB(Widget w, XtPointer clientData, XEvent *event, Boolean *cont) { if (event->xkey.keycode != XKeysymToKeycode(XtDisplay(w), XK_Escape)) return; if (clientData != NULL) { listDialogCloseCB(w, (WindowInfo *)clientData, NULL); } *cont = False; } #endif /* LESSTIF_VERSION */ static int stringCompareMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char stringStorage[3][TYPE_INT_STR_SIZE(int)]; char *leftStr, *rightStr, *argStr; int considerCase = True; int i; int compareResult; if (nArgs < 2) { return(wrongNArgsErr(errMsg)); } if (!readStringArg(argList[0], &leftStr, stringStorage[0], errMsg)) return False; if (!readStringArg(argList[1], &rightStr, stringStorage[1], errMsg)) return False; for (i = 2; i < nArgs; ++i) { if (!readStringArg(argList[i], &argStr, stringStorage[2], errMsg)) return False; else if (!strcmp(argStr, "case")) considerCase = True; else if (!strcmp(argStr, "nocase")) considerCase = False; else { *errMsg = "Unrecognized argument to %s"; return False; } } if (considerCase) { compareResult = strcmp(leftStr, rightStr); compareResult = (compareResult > 0) ? 1 : ((compareResult < 0) ? -1 : 0); } else { compareResult = strCaseCmp(leftStr, rightStr); } result->tag = INT_TAG; result->val.n = compareResult; return True; } /* ** This function is intended to split strings into an array of substrings ** Importatnt note: It should always return at least one entry with key 0 ** split("", ",") result[0] = "" ** split("1,2", ",") result[0] = "1" result[1] = "2" ** split("1,2,", ",") result[0] = "1" result[1] = "2" result[2] = "" ** ** This behavior is specifically important when used to break up ** array sub-scripts */ static int splitMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char stringStorage[3][TYPE_INT_STR_SIZE(int)]; char *sourceStr, *splitStr, *typeSplitStr; int searchType, beginPos, foundStart, foundEnd, strLength, lastEnd; int found, elementEnd, indexNum; char indexStr[TYPE_INT_STR_SIZE(int)], *allocIndexStr; DataValue element; int elementLen; if (nArgs < 2) { return(wrongNArgsErr(errMsg)); } if (!readStringArg(argList[0], &sourceStr, stringStorage[0], errMsg)) { *errMsg = "first argument must be a string: %s"; return(False); } if (!readStringArg(argList[1], &splitStr, stringStorage[1], errMsg)) { splitStr = NULL; } else { if (splitStr[0] == 0) { splitStr = NULL; } } if (splitStr == NULL) { *errMsg = "second argument must be a non-empty string: %s"; return(False); } if (nArgs > 2 && readStringArg(argList[2], &typeSplitStr, stringStorage[2], errMsg)) { if (!StringToSearchType(typeSplitStr, &searchType)) { *errMsg = "unrecognized argument to %s"; return(False); } } else { searchType = SEARCH_LITERAL; } result->tag = ARRAY_TAG; result->val.arrayPtr = ArrayNew(); beginPos = 0; lastEnd = 0; indexNum = 0; strLength = strlen(sourceStr); found = 1; while (found && beginPos < strLength) { sprintf(indexStr, "%d", indexNum); allocIndexStr = AllocString(strlen(indexStr) + 1); if (!allocIndexStr) { *errMsg = "array element failed to allocate key: %s"; return(False); } strcpy(allocIndexStr, indexStr); found = SearchString(sourceStr, splitStr, SEARCH_FORWARD, searchType, False, beginPos, &foundStart, &foundEnd, NULL, NULL, GetWindowDelimiters(window)); elementEnd = found ? foundStart : strLength; elementLen = elementEnd - lastEnd; element.tag = STRING_TAG; if (!AllocNStringNCpy(&element.val.str, &sourceStr[lastEnd], elementLen)) { *errMsg = "failed to allocate element value: %s"; return(False); } if (!ArrayInsert(result, allocIndexStr, &element)) { M_ARRAY_INSERT_FAILURE(); } if (found) { if (foundStart == foundEnd) { beginPos = foundEnd + 1; /* Avoid endless loop for 0-width match */ } else { beginPos = foundEnd; } } else { beginPos = strLength; /* Break the loop */ } lastEnd = foundEnd; ++indexNum; } if (found) { sprintf(indexStr, "%d", indexNum); allocIndexStr = AllocString(strlen(indexStr) + 1); if (!allocIndexStr) { *errMsg = "array element failed to allocate key: %s"; return(False); } strcpy(allocIndexStr, indexStr); element.tag = STRING_TAG; if (lastEnd == strLength) { /* The pattern mathed the end of the string. Add an empty chunk. */ element.val.str.rep = PERM_ALLOC_STR(""); element.val.str.len = 0; if (!ArrayInsert(result, allocIndexStr, &element)) { M_ARRAY_INSERT_FAILURE(); } } else { /* We skipped the last character to prevent an endless loop. Add it to the list. */ elementLen = strLength - lastEnd; if (!AllocNStringNCpy(&element.val.str, &sourceStr[lastEnd], elementLen)) { *errMsg = "failed to allocate element value: %s"; return(False); } if (!ArrayInsert(result, allocIndexStr, &element)) { M_ARRAY_INSERT_FAILURE(); } /* If the pattern can match zero-length strings, we may have to add a final empty chunk. For instance: split("abc\n", "$", "regex") -> matches before \n and at end of string -> expected output: "abc", "\n", "" The '\n' gets added in the lines above, but we still have to verify whether the pattern also matches the end of the string, and add an empty chunk in case it does. */ found = SearchString(sourceStr, splitStr, SEARCH_FORWARD, searchType, False, strLength, &foundStart, &foundEnd, NULL, NULL, GetWindowDelimiters(window)); if (found) { ++indexNum; sprintf(indexStr, "%d", indexNum); allocIndexStr = AllocString(strlen(indexStr) + 1); if (!allocIndexStr) { *errMsg = "array element failed to allocate key: %s"; return(False); } strcpy(allocIndexStr, indexStr); element.tag = STRING_TAG; element.val.str.rep = PERM_ALLOC_STR(""); element.val.str.len = 0; if (!ArrayInsert(result, allocIndexStr, &element)) { M_ARRAY_INSERT_FAILURE(); } } } } return(True); } /* ** Set the backlighting string resource for the current window. If no parameter ** is passed or the value "default" is passed, it attempts to set the preference ** value of the resource. If the empty string is passed, the backlighting string ** will be cleared, turning off backlighting. */ /* DISABLED for 5.4 static int setBacklightStringMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char *backlightString; if (nArgs == 0) { backlightString = GetPrefBacklightCharTypes(); } else if (nArgs == 1) { if (argList[0].tag != STRING_TAG) { *errMsg = "%s not called with a string parameter"; return False; } backlightString = argList[0].val.str.rep; } else return wrongNArgsErr(errMsg); if (strcmp(backlightString, "default") == 0) backlightString = GetPrefBacklightCharTypes(); if (backlightString && *backlightString == '\0') / * empty string param * / backlightString = NULL; / * turns of backlighting * / SetBacklightChars(window, backlightString); return True; } */ static int cursorMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = TextGetCursorPos(window->lastFocus); return True; } static int lineMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int line, cursorPos, colNum; result->tag = INT_TAG; cursorPos = TextGetCursorPos(window->lastFocus); if (!TextPosToLineAndCol(window->lastFocus, cursorPos, &line, &colNum)) line = BufCountLines(window->buffer, 0, cursorPos) + 1; result->val.n = line; return True; } static int columnMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { textBuffer *buf = window->buffer; int cursorPos; result->tag = INT_TAG; cursorPos = TextGetCursorPos(window->lastFocus); result->val.n = BufCountDispChars(buf, BufStartOfLine(buf, cursorPos), cursorPos); return True; } static int fileNameMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = STRING_TAG; AllocNStringCpy(&result->val.str, window->filename); return True; } static int filePathMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = STRING_TAG; AllocNStringCpy(&result->val.str, window->path); return True; } static int lengthMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = window->buffer->length; return True; } static int selectionStartMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = window->buffer->primary.selected ? window->buffer->primary.start : -1; return True; } static int selectionEndMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = window->buffer->primary.selected ? window->buffer->primary.end : -1; return True; } static int selectionLeftMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { selection *sel = &window->buffer->primary; result->tag = INT_TAG; result->val.n = sel->selected && sel->rectangular ? sel->rectStart : -1; return True; } static int selectionRightMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { selection *sel = &window->buffer->primary; result->tag = INT_TAG; result->val.n = sel->selected && sel->rectangular ? sel->rectEnd : -1; return True; } static int wrapMarginMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int margin, nCols; XtVaGetValues(window->textArea, textNcolumns, &nCols, textNwrapMargin, &margin, NULL); result->tag = INT_TAG; result->val.n = margin == 0 ? nCols : margin; return True; } static int statisticsLineMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = window->showStats ? 1 : 0; return True; } static int incSearchLineMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = window->showISearchLine ? 1 : 0; return True; } static int showLineNumbersMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = window->showLineNumbers ? 1 : 0; return True; } static int autoIndentMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char *res = NULL; switch (window->indentStyle) { case NO_AUTO_INDENT: res = PERM_ALLOC_STR("off"); break; case AUTO_INDENT: res = PERM_ALLOC_STR("on"); break; case SMART_INDENT: res = PERM_ALLOC_STR("smart"); break; default: *errMsg = "Invalid indent style value encountered in %s"; return False; break; } result->tag = STRING_TAG; result->val.str.rep = res; result->val.str.len = strlen(res); return True; } static int wrapTextMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char *res = NULL; switch (window->wrapMode) { case NO_WRAP: res = PERM_ALLOC_STR("none"); break; case NEWLINE_WRAP: res = PERM_ALLOC_STR("auto"); break; case CONTINUOUS_WRAP: res = PERM_ALLOC_STR("continuous"); break; default: *errMsg = "Invalid wrap style value encountered in %s"; return False; break; } result->tag = STRING_TAG; result->val.str.rep = res; result->val.str.len = strlen(res); return True; } static int highlightSyntaxMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = window->highlightSyntax ? 1 : 0; return True; } static int makeBackupCopyMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = window->saveOldVersion ? 1 : 0; return True; } static int incBackupMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = window->autoSave ? 1 : 0; return True; } static int showMatchingMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char *res = NULL; switch (window->showMatchingStyle) { case NO_FLASH: res = PERM_ALLOC_STR(NO_FLASH_STRING); break; case FLASH_DELIMIT: res = PERM_ALLOC_STR(FLASH_DELIMIT_STRING); break; case FLASH_RANGE: res = PERM_ALLOC_STR(FLASH_RANGE_STRING); break; default: *errMsg = "Invalid match flashing style value encountered in %s"; return False; break; } result->tag = STRING_TAG; result->val.str.rep = res; result->val.str.len = strlen(res); return True; } static int matchSyntaxBasedMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = window->matchSyntaxBased ? 1 : 0; return True; } static int overTypeModeMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = window->overstrike ? 1 : 0; return True; } static int readOnlyMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = (IS_ANY_LOCKED(window->lockReasons)) ? 1 : 0; return True; } static int lockedMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = (IS_USER_LOCKED(window->lockReasons)) ? 1 : 0; return True; } static int fileFormatMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char *res = NULL; switch (window->fileFormat) { case UNIX_FILE_FORMAT: res = PERM_ALLOC_STR("unix"); break; case DOS_FILE_FORMAT: res = PERM_ALLOC_STR("dos"); break; case MAC_FILE_FORMAT: res = PERM_ALLOC_STR("macintosh"); break; default: *errMsg = "Invalid linefeed style value encountered in %s"; return False; } result->tag = STRING_TAG; result->val.str.rep = res; result->val.str.len = strlen(res); return True; } static int fontNameMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = STRING_TAG; AllocNStringCpy(&result->val.str, window->fontName); return True; } static int fontNameItalicMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = STRING_TAG; AllocNStringCpy(&result->val.str, window->italicFontName); return True; } static int fontNameBoldMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = STRING_TAG; AllocNStringCpy(&result->val.str, window->boldFontName); return True; } static int fontNameBoldItalicMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = STRING_TAG; AllocNStringCpy(&result->val.str, window->boldItalicFontName); return True; } static int subscriptSepMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = STRING_TAG; result->val.str.rep = PERM_ALLOC_STR(ARRAY_DIM_SEP); result->val.str.len = strlen(result->val.str.rep); return True; } static int minFontWidthMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = TextGetMinFontWidth(window->textArea, window->highlightSyntax); return True; } static int maxFontWidthMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = TextGetMaxFontWidth(window->textArea, window->highlightSyntax); return True; } static int topLineMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = TextFirstVisibleLine(window->lastFocus); return True; } static int numDisplayLinesMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = TextNumVisibleLines(window->lastFocus); return True; } static int displayWidthMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = TextVisibleWidth(window->lastFocus); return True; } static int activePaneMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = WidgetToPaneIndex(window, window->lastFocus) + 1; return True; } static int nPanesMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = window->nPanes + 1; return True; } static int emptyArrayMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = ARRAY_TAG; result->val.arrayPtr = NULL; return True; } static int serverNameMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = STRING_TAG; AllocNStringCpy(&result->val.str, GetPrefServerName()); return True; } static int tabDistMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = window->buffer->tabDist; return True; } static int emTabDistMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int dist; XtVaGetValues(window->textArea, textNemulateTabs, &dist, NULL); result->tag = INT_TAG; result->val.n = dist; return True; } static int useTabsMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = window->buffer->useTabs; return True; } static int modifiedMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { result->tag = INT_TAG; result->val.n = window->fileChanged; return True; } static int languageModeMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char *lmName = LanguageModeName(window->languageMode); if (lmName == NULL) lmName = "Plain"; result->tag = STRING_TAG; AllocNStringCpy(&result->val.str, lmName); return True; } /* DISABLED for 5.4 static int backlightStringMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char *backlightString = window->backlightCharTypes; result->tag = STRING_TAG; if (!backlightString || !window->backlightChars) backlightString = ""; AllocNStringCpy(&result->val.str, backlightString); return True; } */ /* -------------------------------------------------------------------------- */ /* ** Range set macro variables and functions */ static int rangesetListMV(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { RangesetTable *rangesetTable = window->buffer->rangesetTable; unsigned char *rangesetList; char *allocIndexStr; char indexStr[TYPE_INT_STR_SIZE(int)] ; int nRangesets, i; DataValue element; result->tag = ARRAY_TAG; result->val.arrayPtr = ArrayNew(); if (rangesetTable == NULL) { return True; } rangesetList = RangesetGetList(rangesetTable); nRangesets = strlen((char*)rangesetList); for(i = 0; i < nRangesets; i++) { element.tag = INT_TAG; element.val.n = rangesetList[i]; sprintf(indexStr, "%d", nRangesets - i - 1); allocIndexStr = AllocString(strlen(indexStr) + 1); if (allocIndexStr == NULL) M_FAILURE("Failed to allocate array key in %s"); strcpy(allocIndexStr, indexStr); if (!ArrayInsert(result, allocIndexStr, &element)) M_FAILURE("Failed to insert array element in %s"); } return True; } /* ** Returns the version number of the current macro language implementation. ** For releases, this is the same number as NEdit's major.minor version ** number to keep things simple. For developer versions this could really ** be anything. ** ** Note that the current way to build $VERSION builds the same value for ** different point revisions. This is done because the macro interface ** does not change for the same version. */ static int versionMV(WindowInfo* window, DataValue* argList, int nArgs, DataValue* result, char** errMsg) { static unsigned version = NEDIT_VERSION * 1000 + NEDIT_REVISION; result->tag = INT_TAG; result->val.n = version; return True; } /* ** Built-in macro subroutine to create a new rangeset or rangesets. ** If called with one argument: $1 is the number of rangesets required and ** return value is an array indexed 0 to n, with the rangeset labels as values; ** (or an empty array if the requested number of rangesets are not available). ** If called with no arguments, returns a single rangeset label (not an array), ** or an empty string if there are no rangesets available. */ static int rangesetCreateMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int label; int i, nRangesetsRequired; DataValue element; char indexStr[TYPE_INT_STR_SIZE(int)], *allocIndexStr; RangesetTable *rangesetTable = window->buffer->rangesetTable; if (nArgs > 1) return wrongNArgsErr(errMsg); if (rangesetTable == NULL) { window->buffer->rangesetTable = rangesetTable = RangesetTableAlloc(window->buffer); } if (nArgs == 0) { label = RangesetCreate(rangesetTable); result->tag = INT_TAG; result->val.n = label; return True; } else { if (!readIntArg(argList[0], &nRangesetsRequired, errMsg)) return False; result->tag = ARRAY_TAG; result->val.arrayPtr = ArrayNew(); if (nRangesetsRequired > nRangesetsAvailable(rangesetTable)) return True; for (i = 0; i < nRangesetsRequired; i++) { element.tag = INT_TAG; element.val.n = RangesetCreate(rangesetTable); sprintf(indexStr, "%d", i); allocIndexStr = AllocString(strlen(indexStr) + 1); if (!allocIndexStr) { *errMsg = "Array element failed to allocate key: %s"; return(False); } strcpy(allocIndexStr, indexStr); ArrayInsert(result, allocIndexStr, &element); } return True; } } /* ** Built-in macro subroutine for forgetting a range set. */ static int rangesetDestroyMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { RangesetTable *rangesetTable = window->buffer->rangesetTable; DataValue *array; DataValue element; char keyString[TYPE_INT_STR_SIZE(int)]; int deleteLabels[N_RANGESETS]; int i, arraySize; int label = 0; if (nArgs != 1) { return wrongNArgsErr(errMsg); } if (argList[0].tag == ARRAY_TAG) { array = &argList[0]; arraySize = ArraySize(array); if (arraySize > N_RANGESETS) { M_FAILURE("Too many elements in array in %s"); } for (i = 0; i < arraySize; i++) { sprintf(keyString, "%d", i); if (!ArrayGet(array, keyString, &element)) { M_FAILURE("Invalid key in array in %s"); } if (!readIntArg(element, &label, errMsg) || !RangesetLabelOK(label)) { M_FAILURE("Invalid rangeset label in array in %s"); } deleteLabels[i] = label; } for (i = 0; i < arraySize; i++) { RangesetForget(rangesetTable, deleteLabels[i]); } } else { if (!readIntArg(argList[0], &label, errMsg) || !RangesetLabelOK(label)) { M_FAILURE("Invalid rangeset label in %s"); } if(rangesetTable != NULL) { RangesetForget(rangesetTable, label); } } /* set up result */ result->tag = NO_TAG; return True; } /* ** Built-in macro subroutine for getting all range sets with a specfic name. ** Arguments are $1: range set name. ** return value is an array indexed 0 to n, with the rangeset labels as values; */ static int rangesetGetByNameMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char stringStorage[1][TYPE_INT_STR_SIZE(int)]; Rangeset *rangeset; int label; char *name, *rangeset_name; RangesetTable *rangesetTable = window->buffer->rangesetTable; unsigned char *rangesetList; char *allocIndexStr; char indexStr[TYPE_INT_STR_SIZE(int)] ; int nRangesets, i, insertIndex = 0; DataValue element; if (nArgs != 1) { return wrongNArgsErr(errMsg); } if (!readStringArg(argList[0], &name, stringStorage[0], errMsg)) { M_FAILURE("First parameter is not a name string in %s"); } result->tag = ARRAY_TAG; result->val.arrayPtr = ArrayNew(); if (rangesetTable == NULL) { return True; } rangesetList = RangesetGetList(rangesetTable); nRangesets = strlen((char *)rangesetList); for (i = 0; i < nRangesets; ++i) { label = rangesetList[i]; rangeset = RangesetFetch(rangesetTable, label); if (rangeset) { rangeset_name = RangesetGetName(rangeset); if (strcmp(name, rangeset_name ? rangeset_name : "") == 0) { element.tag = INT_TAG; element.val.n = label; sprintf(indexStr, "%d", insertIndex); allocIndexStr = AllocString(strlen(indexStr) + 1); if (allocIndexStr == NULL) M_FAILURE("Failed to allocate array key in %s"); strcpy(allocIndexStr, indexStr); if (!ArrayInsert(result, allocIndexStr, &element)) M_FAILURE("Failed to insert array element in %s"); ++insertIndex; } } } return True; } /* ** Built-in macro subroutine for adding to a range set. Arguments are $1: range ** set label (one integer), then either (a) $2: source range set label, ** (b) $2: int start-range, $3: int end-range, (c) nothing (use selection ** if any to specify range to add - must not be rectangular). Returns the ** index of the newly added range (cases b and c), or 0 (case a). */ static int rangesetAddMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { textBuffer *buffer = window->buffer; RangesetTable *rangesetTable = buffer->rangesetTable; Rangeset *targetRangeset, *sourceRangeset; int start, end, isRect, rectStart, rectEnd, maxpos, index; int label = 0; if (nArgs < 1 || nArgs > 3) return wrongNArgsErr(errMsg); if (!readIntArg(argList[0], &label, errMsg) || !RangesetLabelOK(label)) { M_FAILURE("First parameter is an invalid rangeset label in %s"); } if (rangesetTable == NULL) { M_FAILURE("Rangeset does not exist in %s"); } targetRangeset = RangesetFetch(rangesetTable, label); if (targetRangeset == NULL) { M_FAILURE("Rangeset does not exist in %s"); } start = end = -1; if (nArgs == 1) { /* pick up current selection in this window */ if (!BufGetSelectionPos(buffer, &start, &end, &isRect, &rectStart, &rectEnd) || isRect) { M_FAILURE("Selection missing or rectangular in call to %s"); } if (!RangesetAddBetween(targetRangeset, start, end)) { M_FAILURE("Failure to add selection in %s"); } } if (nArgs == 2) { /* add ranges taken from a second set */ if (!readIntArg(argList[1], &label, errMsg) || !RangesetLabelOK(label)) { M_FAILURE("Second parameter is an invalid rangeset label in %s"); } sourceRangeset = RangesetFetch(rangesetTable, label); if (sourceRangeset == NULL) { M_FAILURE("Second rangeset does not exist in %s"); } RangesetAdd(targetRangeset, sourceRangeset); } if (nArgs == 3) { /* add a range bounded by the start and end positions in $2, $3 */ if (!readIntArg(argList[1], &start, errMsg)) { return False; } if (!readIntArg(argList[2], &end, errMsg)) { return False; } /* make sure range is in order and fits buffer size */ maxpos = buffer->length; if (start < 0) start = 0; if (start > maxpos) start = maxpos; if (end < 0) end = 0; if (end > maxpos) end = maxpos; if (start > end) {int temp = start; start = end; end = temp;} if ((start != end) && !RangesetAddBetween(targetRangeset, start, end)) { M_FAILURE("Failed to add range in %s"); } } /* (to) which range did we just add? */ if (nArgs != 2 && start >= 0) { start = (start + end) / 2; /* "middle" of added range */ index = 1 + RangesetFindRangeOfPos(targetRangeset, start, False); } else { index = 0; } /* set up result */ result->tag = INT_TAG; result->val.n = index; return True; } /* ** Built-in macro subroutine for removing from a range set. Almost identical to ** rangesetAddMS() - only changes are from RangesetAdd()/RangesetAddBetween() ** to RangesetSubtract()/RangesetSubtractBetween(), the handling of an ** undefined destination range, and that it returns no value. */ static int rangesetSubtractMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { textBuffer *buffer = window->buffer; RangesetTable *rangesetTable = buffer->rangesetTable; Rangeset *targetRangeset, *sourceRangeset; int start, end, isRect, rectStart, rectEnd, maxpos; int label = 0; if (nArgs < 1 || nArgs > 3) { return wrongNArgsErr(errMsg); } if (!readIntArg(argList[0], &label, errMsg) || !RangesetLabelOK(label)) { M_FAILURE("First parameter is an invalid rangeset label in %s"); } if (rangesetTable == NULL) { M_FAILURE("Rangeset does not exist in %s"); } targetRangeset = RangesetFetch(rangesetTable, label); if (targetRangeset == NULL) { M_FAILURE("Rangeset does not exist in %s"); } if (nArgs == 1) { /* remove current selection in this window */ if (!BufGetSelectionPos(buffer, &start, &end, &isRect, &rectStart, &rectEnd) || isRect) { M_FAILURE("Selection missing or rectangular in call to %s"); } RangesetRemoveBetween(targetRangeset, start, end); } if (nArgs == 2) { /* remove ranges taken from a second set */ if (!readIntArg(argList[1], &label, errMsg) || !RangesetLabelOK(label)) { M_FAILURE("Second parameter is an invalid rangeset label in %s"); } sourceRangeset = RangesetFetch(rangesetTable, label); if (sourceRangeset == NULL) { M_FAILURE("Second rangeset does not exist in %s"); } RangesetRemove(targetRangeset, sourceRangeset); } if (nArgs == 3) { /* remove a range bounded by the start and end positions in $2, $3 */ if (!readIntArg(argList[1], &start, errMsg)) return False; if (!readIntArg(argList[2], &end, errMsg)) return False; /* make sure range is in order and fits buffer size */ maxpos = buffer->length; if (start < 0) start = 0; if (start > maxpos) start = maxpos; if (end < 0) end = 0; if (end > maxpos) end = maxpos; if (start > end) {int temp = start; start = end; end = temp;} RangesetRemoveBetween(targetRangeset, start, end); } /* set up result */ result->tag = NO_TAG; return True; } /* ** Built-in macro subroutine to invert a range set. Argument is $1: range set ** label (one alphabetic character). Returns nothing. Fails if range set ** undefined. */ static int rangesetInvertMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { RangesetTable *rangesetTable = window->buffer->rangesetTable; Rangeset *rangeset; int label = 0; if (nArgs != 1) return wrongNArgsErr(errMsg); if (!readIntArg(argList[0], &label, errMsg) || !RangesetLabelOK(label)) { M_FAILURE("First parameter is an invalid rangeset label in %s"); } if (rangesetTable == NULL) { M_FAILURE("Rangeset does not exist in %s"); } rangeset = RangesetFetch(rangesetTable, label); if (rangeset == NULL) { M_FAILURE("Rangeset does not exist in %s"); } if (RangesetInverse(rangeset) < 0) { M_FAILURE("Problem inverting rangeset in %s"); } /* set up result */ result->tag = NO_TAG; return True; } /* ** Built-in macro subroutine for finding out info about a rangeset. Takes one ** argument of a rangeset label. Returns an array with the following keys: ** defined, count, color, mode. */ static int rangesetInfoMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { RangesetTable *rangesetTable = window->buffer->rangesetTable; Rangeset *rangeset = NULL; int count, defined; char *color, *name, *mode; DataValue element; int label = 0; if (nArgs != 1) return wrongNArgsErr(errMsg); if (!readIntArg(argList[0], &label, errMsg) || !RangesetLabelOK(label)) { M_FAILURE("First parameter is an invalid rangeset label in %s"); } if (rangesetTable != NULL) { rangeset = RangesetFetch(rangesetTable, label); } RangesetGetInfo(rangeset, &defined, &label, &count, &color, &name, &mode); /* set up result */ result->tag = ARRAY_TAG; result->val.arrayPtr = ArrayNew(); element.tag = INT_TAG; element.val.n = defined; if (!ArrayInsert(result, PERM_ALLOC_STR("defined"), &element)) M_FAILURE("Failed to insert array element \"defined\" in %s"); element.tag = INT_TAG; element.val.n = count; if (!ArrayInsert(result, PERM_ALLOC_STR("count"), &element)) M_FAILURE("Failed to insert array element \"count\" in %s"); element.tag = STRING_TAG; if (!AllocNStringCpy(&element.val.str, color)) M_FAILURE("Failed to allocate array value \"color\" in %s"); if (!ArrayInsert(result, PERM_ALLOC_STR("color"), &element)) M_FAILURE("Failed to insert array element \"color\" in %s"); element.tag = STRING_TAG; if (!AllocNStringCpy(&element.val.str, name)) M_FAILURE("Failed to allocate array value \"name\" in %s"); if (!ArrayInsert(result, PERM_ALLOC_STR("name"), &element)) { M_FAILURE("Failed to insert array element \"name\" in %s"); } element.tag = STRING_TAG; if (!AllocNStringCpy(&element.val.str, mode)) M_FAILURE("Failed to allocate array value \"mode\" in %s"); if (!ArrayInsert(result, PERM_ALLOC_STR("mode"), &element)) M_FAILURE("Failed to insert array element \"mode\" in %s"); return True; } /* ** Built-in macro subroutine for finding the extent of a range in a set. ** If only one parameter is supplied, use the spanning range of all ** ranges, otherwise select the individual range specified. Returns ** an array with the keys "start" and "end" and values */ static int rangesetRangeMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { textBuffer *buffer = window->buffer; RangesetTable *rangesetTable = buffer->rangesetTable; Rangeset *rangeset; int start, end, dummy, rangeIndex, ok; DataValue element; int label = 0; if (nArgs < 1 || nArgs > 2) { return wrongNArgsErr(errMsg); } if (!readIntArg(argList[0], &label, errMsg) || !RangesetLabelOK(label)) { M_FAILURE("First parameter is an invalid rangeset label in %s"); } if (rangesetTable == NULL) { M_FAILURE("Rangeset does not exist in %s"); } ok = False; rangeset = RangesetFetch(rangesetTable, label); if (rangeset != NULL) { if (nArgs == 1) { rangeIndex = RangesetGetNRanges(rangeset) - 1; ok = RangesetFindRangeNo(rangeset, 0, &start, &dummy); ok &= RangesetFindRangeNo(rangeset, rangeIndex, &dummy, &end); rangeIndex = -1; } else if (nArgs == 2) { if (!readIntArg(argList[1], &rangeIndex, errMsg)) { return False; } ok = RangesetFindRangeNo(rangeset, rangeIndex-1, &start, &end); } } /* set up result */ result->tag = ARRAY_TAG; result->val.arrayPtr = ArrayNew(); if (!ok) return True; element.tag = INT_TAG; element.val.n = start; if (!ArrayInsert(result, PERM_ALLOC_STR("start"), &element)) M_FAILURE("Failed to insert array element \"start\" in %s"); element.tag = INT_TAG; element.val.n = end; if (!ArrayInsert(result, PERM_ALLOC_STR("end"), &element)) M_FAILURE("Failed to insert array element \"end\" in %s"); return True; } /* ** Built-in macro subroutine for checking a position against a range. If only ** one parameter is supplied, the current cursor position is used. Returns ** false (zero) if not in a range, range index (1-based) if in a range; ** fails if parameters were bad. */ static int rangesetIncludesPosMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { textBuffer *buffer = window->buffer; RangesetTable *rangesetTable = buffer->rangesetTable; Rangeset *rangeset; int pos, rangeIndex, maxpos; int label = 0; if (nArgs < 1 || nArgs > 2) { return wrongNArgsErr(errMsg); } if (!readIntArg(argList[0], &label, errMsg) || !RangesetLabelOK(label)) { M_FAILURE("First parameter is an invalid rangeset label in %s"); } if (rangesetTable == NULL) { M_FAILURE("Rangeset does not exist in %s"); } rangeset = RangesetFetch(rangesetTable, label); if (rangeset == NULL) { M_FAILURE("Rangeset does not exist in %s"); } if (nArgs == 1) { pos = TextGetCursorPos(window->lastFocus); } else if (nArgs == 2) { if (!readIntArg(argList[1], &pos, errMsg)) return False; } maxpos = buffer->length; if (pos < 0 || pos > maxpos) { rangeIndex = 0; } else { rangeIndex = RangesetFindRangeOfPos(rangeset, pos, False) + 1; } /* set up result */ result->tag = INT_TAG; result->val.n = rangeIndex; return True; } /* ** Set the color of a range set's ranges. it is ignored if the color cannot be ** found/applied. If no color is applied, any current color is removed. Returns ** true if the rangeset is valid. */ static int rangesetSetColorMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char stringStorage[1][TYPE_INT_STR_SIZE(int)]; textBuffer *buffer = window->buffer; RangesetTable *rangesetTable = buffer->rangesetTable; Rangeset *rangeset; char *color_name; int label = 0; if (nArgs != 2) { return wrongNArgsErr(errMsg); } if (!readIntArg(argList[0], &label, errMsg) || !RangesetLabelOK(label)) { M_FAILURE("First parameter is an invalid rangeset label in %s"); } if (rangesetTable == NULL) { M_FAILURE("Rangeset does not exist in %s"); } rangeset = RangesetFetch(rangesetTable, label); if (rangeset == NULL) { M_FAILURE("Rangeset does not exist in %s"); } color_name = ""; if (rangeset != NULL) { if (!readStringArg(argList[1], &color_name, stringStorage[0], errMsg)) { M_FAILURE("Second parameter is not a color name string in %s"); } } RangesetAssignColorName(rangeset, color_name); /* set up result */ result->tag = NO_TAG; return True; } /* ** Set the name of a range set's ranges. Returns ** true if the rangeset is valid. */ static int rangesetSetNameMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char stringStorage[1][TYPE_INT_STR_SIZE(int)]; textBuffer *buffer = window->buffer; RangesetTable *rangesetTable = buffer->rangesetTable; Rangeset *rangeset; char *name; int label = 0; if (nArgs != 2) { return wrongNArgsErr(errMsg); } if (!readIntArg(argList[0], &label, errMsg) || !RangesetLabelOK(label)) { M_FAILURE("First parameter is an invalid rangeset label in %s"); } if (rangesetTable == NULL) { M_FAILURE("Rangeset does not exist in %s"); } rangeset = RangesetFetch(rangesetTable, label); if (rangeset == NULL) { M_FAILURE("Rangeset does not exist in %s"); } name = ""; if (rangeset != NULL) { if (!readStringArg(argList[1], &name, stringStorage[0], errMsg)) { M_FAILURE("Second parameter is not a valid name string in %s"); } } RangesetAssignName(rangeset, name); /* set up result */ result->tag = NO_TAG; return True; } /* ** Change a range's modification response. Returns true if the rangeset is ** valid and the response type name is valid. */ static int rangesetSetModeMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char stringStorage[1][TYPE_INT_STR_SIZE(int)]; textBuffer *buffer = window->buffer; RangesetTable *rangesetTable = buffer->rangesetTable; Rangeset *rangeset; char *update_fn_name; int ok; int label = 0; if (nArgs < 1 || nArgs > 2) { return wrongNArgsErr(errMsg); } if (!readIntArg(argList[0], &label, errMsg) || !RangesetLabelOK(label)) { M_FAILURE("First parameter is an invalid rangeset label in %s"); } if (rangesetTable == NULL) { M_FAILURE("Rangeset does not exist in %s"); } rangeset = RangesetFetch(rangesetTable, label); if (rangeset == NULL) { M_FAILURE("Rangeset does not exist in %s"); } update_fn_name = ""; if (rangeset != NULL) { if (nArgs == 2) { if (!readStringArg(argList[1], &update_fn_name, stringStorage[0], errMsg)) { M_FAILURE("Second parameter is not a string in %s"); } } } ok = RangesetChangeModifyResponse(rangeset, update_fn_name); if (!ok) { M_FAILURE("Second parameter is not a valid mode in %s"); } /* set up result */ result->tag = NO_TAG; return True; } /* -------------------------------------------------------------------------- */ /* ** Routines to get details directly from the window. */ /* ** Sets up an array containing information about a style given its name or ** a buffer position (bufferPos >= 0) and its highlighting pattern code ** (patCode >= 0). ** From the name we obtain: ** ["color"] Foreground color name of style ** ["background"] Background color name of style if specified ** ["bold"] '1' if style is bold, '0' otherwise ** ["italic"] '1' if style is italic, '0' otherwise ** Given position and pattern code we obtain: ** ["rgb"] RGB representation of foreground color of style ** ["back_rgb"] RGB representation of background color of style ** ["extent"] Forward distance from position over which style applies ** We only supply the style name if the includeName parameter is set: ** ["style"] Name of style ** */ static int fillStyleResult(DataValue *result, char **errMsg, WindowInfo *window, char *styleName, Boolean preallocatedStyleName, Boolean includeName, int patCode, int bufferPos) { DataValue DV; char colorValue[20]; int r, g, b; /* initialize array */ result->tag = ARRAY_TAG; result->val.arrayPtr = ArrayNew(); /* the following array entries will be strings */ DV.tag = STRING_TAG; if (includeName) { /* insert style name */ if (preallocatedStyleName) { DV.val.str.rep = styleName; DV.val.str.len = strlen(styleName); } else { AllocNStringCpy(&DV.val.str, styleName); } M_STR_ALLOC_ASSERT(DV); if (!ArrayInsert(result, PERM_ALLOC_STR("style"), &DV)) { M_ARRAY_INSERT_FAILURE(); } } /* insert color name */ AllocNStringCpy(&DV.val.str, ColorOfNamedStyle(styleName)); M_STR_ALLOC_ASSERT(DV); if (!ArrayInsert(result, PERM_ALLOC_STR("color"), &DV)) { M_ARRAY_INSERT_FAILURE(); } /* Prepare array element for color value (only possible if we pass through the dynamic highlight pattern tables in other words, only if we have a pattern code) */ if (patCode) { HighlightColorValueOfCode(window, patCode, &r, &g, &b); sprintf(colorValue, "#%02x%02x%02x", r/256, g/256, b/256); AllocNStringCpy(&DV.val.str, colorValue); M_STR_ALLOC_ASSERT(DV); if (!ArrayInsert(result, PERM_ALLOC_STR("rgb"), &DV)) { M_ARRAY_INSERT_FAILURE(); } } /* Prepare array element for background color name */ AllocNStringCpy(&DV.val.str, BgColorOfNamedStyle(styleName)); M_STR_ALLOC_ASSERT(DV); if (!ArrayInsert(result, PERM_ALLOC_STR("background"), &DV)) { M_ARRAY_INSERT_FAILURE(); } /* Prepare array element for background color value (only possible if we pass through the dynamic highlight pattern tables in other words, only if we have a pattern code) */ if (patCode) { GetHighlightBGColorOfCode(window, patCode, &r, &g, &b); sprintf(colorValue, "#%02x%02x%02x", r/256, g/256, b/256); AllocNStringCpy(&DV.val.str, colorValue); M_STR_ALLOC_ASSERT(DV); if (!ArrayInsert(result, PERM_ALLOC_STR("back_rgb"), &DV)) { M_ARRAY_INSERT_FAILURE(); } } /* the following array entries will be integers */ DV.tag = INT_TAG; /* Put boldness value in array */ DV.val.n = FontOfNamedStyleIsBold(styleName); if (!ArrayInsert(result, PERM_ALLOC_STR("bold"), &DV)) { M_ARRAY_INSERT_FAILURE(); } /* Put italicity value in array */ DV.val.n = FontOfNamedStyleIsItalic(styleName); if (!ArrayInsert(result, PERM_ALLOC_STR("italic"), &DV)) { M_ARRAY_INSERT_FAILURE(); } if (bufferPos >= 0) { /* insert extent */ const char *styleNameNotUsed = NULL; DV.val.n = StyleLengthOfCodeFromPos(window, bufferPos, &styleNameNotUsed); if (!ArrayInsert(result, PERM_ALLOC_STR("extent"), &DV)) { M_ARRAY_INSERT_FAILURE(); } } return True; } /* ** Returns an array containing information about the style of name $1 ** ["color"] Foreground color name of style ** ["background"] Background color name of style if specified ** ["bold"] '1' if style is bold, '0' otherwise ** ["italic"] '1' if style is italic, '0' otherwise ** */ static int getStyleByNameMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char stringStorage[1][TYPE_INT_STR_SIZE(int)]; char *styleName; /* Validate number of arguments */ if (nArgs != 1) { return wrongNArgsErr(errMsg); } /* Prepare result */ result->tag = ARRAY_TAG; result->val.arrayPtr = NULL; if (!readStringArg(argList[0], &styleName, stringStorage[0], errMsg)) { M_FAILURE("First parameter is not a string in %s"); } if (!NamedStyleExists(styleName)) { /* if the given name is invalid we just return an empty array. */ return True; } return fillStyleResult(result, errMsg, window, styleName, (argList[0].tag == STRING_TAG), False, 0, -1); } /* ** Returns an array containing information about the style of position $1 ** ["style"] Name of style ** ["color"] Foreground color name of style ** ["background"] Background color name of style if specified ** ["bold"] '1' if style is bold, '0' otherwise ** ["italic"] '1' if style is italic, '0' otherwise ** ["rgb"] RGB representation of foreground color of style ** ["back_rgb"] RGB representation of background color of style ** ["extent"] Forward distance from position over which style applies ** */ static int getStyleAtPosMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int patCode; int bufferPos; textBuffer *buf = window->buffer; /* Validate number of arguments */ if (nArgs != 1) { return wrongNArgsErr(errMsg); } /* Prepare result */ result->tag = ARRAY_TAG; result->val.arrayPtr = NULL; if (!readIntArg(argList[0], &bufferPos, errMsg)) { return False; } /* Verify sane buffer position */ if ((bufferPos < 0) || (bufferPos >= buf->length)) { /* If the position is not legal, we cannot guess anything about the style, so we return an empty array. */ return True; } /* Determine pattern code */ patCode = HighlightCodeOfPos(window, bufferPos); if (patCode == 0) { /* if there is no pattern we just return an empty array. */ return True; } return fillStyleResult(result, errMsg, window, HighlightStyleOfCode(window, patCode), False, True, patCode, bufferPos); } /* ** Sets up an array containing information about a pattern given its name or ** a buffer position (bufferPos >= 0). ** From the name we obtain: ** ["style"] Name of style ** ["extent"] Forward distance from position over which style applies ** We only supply the pattern name if the includeName parameter is set: ** ["pattern"] Name of pattern ** */ static int fillPatternResult(DataValue *result, char **errMsg, WindowInfo *window, char *patternName, Boolean preallocatedPatternName, Boolean includeName, char* styleName, int bufferPos) { DataValue DV; /* initialize array */ result->tag = ARRAY_TAG; result->val.arrayPtr = ArrayNew(); /* the following array entries will be strings */ DV.tag = STRING_TAG; if (includeName) { /* insert pattern name */ if (preallocatedPatternName) { DV.val.str.rep = patternName; DV.val.str.len = strlen(patternName); } else { AllocNStringCpy(&DV.val.str, patternName); } M_STR_ALLOC_ASSERT(DV); if (!ArrayInsert(result, PERM_ALLOC_STR("pattern"), &DV)) { M_ARRAY_INSERT_FAILURE(); } } /* insert style name */ AllocNStringCpy(&DV.val.str, styleName); M_STR_ALLOC_ASSERT(DV); if (!ArrayInsert(result, PERM_ALLOC_STR("style"), &DV)) { M_ARRAY_INSERT_FAILURE(); } /* the following array entries will be integers */ DV.tag = INT_TAG; if (bufferPos >= 0) { /* insert extent */ int checkCode = 0; DV.val.n = HighlightLengthOfCodeFromPos(window, bufferPos, &checkCode); if (!ArrayInsert(result, PERM_ALLOC_STR("extent"), &DV)) { M_ARRAY_INSERT_FAILURE(); } } return True; } /* ** Returns an array containing information about a highlighting pattern. The ** single parameter contains the pattern name for which this information is ** requested. ** The returned array looks like this: ** ["style"] Name of style */ static int getPatternByNameMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { char stringStorage[1][TYPE_INT_STR_SIZE(int)]; char *patternName = NULL; highlightPattern *pattern; /* Begin of building the result. */ result->tag = ARRAY_TAG; result->val.arrayPtr = NULL; /* Validate number of arguments */ if (nArgs != 1) { return wrongNArgsErr(errMsg); } if (!readStringArg(argList[0], &patternName, stringStorage[0], errMsg)) { M_FAILURE("First parameter is not a string in %s"); } pattern = FindPatternOfWindow(window, patternName); if (pattern == NULL) { /* The pattern's name is unknown. */ return True; } return fillPatternResult(result, errMsg, window, patternName, (argList[0].tag == STRING_TAG), False, pattern->style, -1); } /* ** Returns an array containing information about the highlighting pattern ** applied at a given position, passed as the only parameter. ** The returned array looks like this: ** ["pattern"] Name of pattern ** ["style"] Name of style ** ["extent"] Distance from position over which this pattern applies */ static int getPatternAtPosMS(WindowInfo *window, DataValue *argList, int nArgs, DataValue *result, char **errMsg) { int bufferPos = -1; textBuffer *buffer = window->buffer; int patCode = 0; /* Begin of building the result. */ result->tag = ARRAY_TAG; result->val.arrayPtr = NULL; /* Validate number of arguments */ if (nArgs != 1) { return wrongNArgsErr(errMsg); } /* The most straightforward case: Get a pattern, style and extent for a buffer position. */ if (!readIntArg(argList[0], &bufferPos, errMsg)) { return False; } /* Verify sane buffer position * You would expect that buffer->length would be among the sane * positions, but we have n characters and n+1 buffer positions. */ if ((bufferPos < 0) || (bufferPos >= buffer->length)) { /* If the position is not legal, we cannot guess anything about the highlighting pattern, so we return an empty array. */ return True; } /* Determine the highlighting pattern used */ patCode = HighlightCodeOfPos(window, bufferPos); if (patCode == 0) { /* if there is no highlighting pattern we just return an empty array. */ return True; } return fillPatternResult(result, errMsg, window, HighlightNameOfCode(window, patCode), False, True, HighlightStyleOfCode(window, patCode), bufferPos); } static int wrongNArgsErr(char **errMsg) { *errMsg = "Wrong number of arguments to function %s"; return False; } static int tooFewArgsErr(char **errMsg) { *errMsg = "Too few arguments to function %s"; return False; } /* ** strCaseCmp compares its arguments and returns 0 if the two strings ** are equal IGNORING case differences. Otherwise returns 1 or -1 ** depending on relative comparison. */ static int strCaseCmp(char *str1, char *str2) { char *c1, *c2; for (c1 = str1, c2 = str2; (*c1 != '\0' && *c2 != '\0') && toupper((unsigned char)*c1) == toupper((unsigned char)*c2); ++c1, ++c2) { } if (((unsigned char)toupper((unsigned char)*c1)) > ((unsigned char)toupper((unsigned char)*c2))) { return(1); } else if (((unsigned char)toupper((unsigned char)*c1)) < ((unsigned char)toupper((unsigned char)*c2))) { return(-1); } else { return(0); } } /* ** Get an integer value from a tagged DataValue structure. Return True ** if conversion succeeded, and store result in *result, otherwise ** return False with an error message in *errMsg. */ static int readIntArg(DataValue dv, int *result, char **errMsg) { char *c; if (dv.tag == INT_TAG) { *result = dv.val.n; return True; } else if (dv.tag == STRING_TAG) { for (c=dv.val.str.rep; *c != '\0'; c++) { if (!(isdigit((unsigned char)*c) || *c == ' ' || *c == '\t')) { goto typeError; } } sscanf(dv.val.str.rep, "%d", result); return True; } typeError: *errMsg = "%s called with non-integer argument"; return False; } /* ** Get an string value from a tagged DataValue structure. Return True ** if conversion succeeded, and store result in *result, otherwise ** return False with an error message in *errMsg. If an integer value ** is converted, write the string in the space provided by "stringStorage", ** which must be large enough to handle ints of the maximum size. */ static int readStringArg(DataValue dv, char **result, char *stringStorage, char **errMsg) { if (dv.tag == STRING_TAG) { *result = dv.val.str.rep; return True; } else if (dv.tag == INT_TAG) { sprintf(stringStorage, "%d", dv.val.n); *result = stringStorage; return True; } *errMsg = "%s called with unknown object"; return False; } nedit-5.6.orig/source/macro.h0000644000175000017500000000627010144236624014673 0ustar paulpaul/* $Id: macro.h,v 1.8 2004/11/09 21:58:44 yooden Exp $ */ /******************************************************************************* * * * macro.h -- Nirvana Editor Macro Header File * * * * Copyright 2004 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_MACRO_H_INCLUDED #define NEDIT_MACRO_H_INCLUDED #include "nedit.h" #include #define REPEAT_TO_END -1 #define REPEAT_IN_SEL -2 void RegisterMacroSubroutines(void); void AddLastCommandActionHook(XtAppContext context); void BeginLearn(WindowInfo *window); void FinishLearn(void); void CancelMacroOrLearn(WindowInfo *window); void Replay(WindowInfo *window); void SafeGC(void); void DoMacro(WindowInfo *window, const char *macro, const char *errInName); void ResumeMacroExecution(WindowInfo *window); void AbortMacroCommand(WindowInfo *window); int MacroWindowCloseActions(WindowInfo *window); void RepeatDialog(WindowInfo *window); void RepeatMacro(WindowInfo *window, const char *command, int how); int ReadMacroFile(WindowInfo *window, const char *fileName, int warnNotExist); int ReadMacroString(WindowInfo *window, char *string, const char *errIn); int CheckMacroString(Widget dialogParent, char *string, const char *errIn, char **errPos); char *GetReplayMacro(void); void ReadMacroInitFile(WindowInfo *window); void ReturnShellCommandOutput(WindowInfo *window, const char *outText, int status); #endif /* NEDIT_MACRO_H_INCLUDED */ nedit-5.6.orig/source/menu.c0000644000175000017500000060652410737527367014560 0ustar paulpaulstatic const char CVSID[] = "$Id: menu.c,v 1.143 2008/01/04 22:11:03 yooden Exp $"; /******************************************************************************* * * * menu.c -- Nirvana Editor menus * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * May 10, 1991 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "menu.h" #include "textBuf.h" #include "text.h" #include "nedit.h" #include "file.h" #include "window.h" #include "search.h" #include "selection.h" #include "undo.h" #include "shift.h" #include "help.h" #include "preferences.h" #include "tags.h" #include "userCmds.h" #include "shell.h" #include "macro.h" #include "highlight.h" #include "highlightData.h" #include "interpret.h" #include "smartIndent.h" #include "windowTitle.h" #include "../util/getfiles.h" #include "../util/DialogF.h" #include "../util/misc.h" #include "../util/fileUtils.h" #include "../util/utils.h" #include "../Xlt/BubbleButton.h" #include #include #include #include #include #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #include #include #include #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #if XmVersion >= 1002 #define MENU_WIDGET(w) (XmGetPostedFromWidget(XtParent(w))) #else #define MENU_WIDGET(w) (w) #endif /* Menu modes for SGI_CUSTOM short-menus feature */ enum menuModes {FULL, SHORT}; typedef void (*menuCallbackProc)(); extern void _XmDismissTearOff(Widget, XtPointer, XtPointer); static void doActionCB(Widget w, XtPointer clientData, XtPointer callData); static void doTabActionCB(Widget w, XtPointer clientData, XtPointer callData); static void pasteColCB(Widget w, XtPointer clientData, XtPointer callData); static void shiftLeftCB(Widget w, XtPointer clientData, XtPointer callData); static void shiftRightCB(Widget w, XtPointer clientData, XtPointer callData); static void findCB(Widget w, XtPointer clientData, XtPointer callData); static void findSameCB(Widget w, XtPointer clientData, XtPointer callData); static void findSelCB(Widget w, XtPointer clientData, XtPointer callData); static void findIncrCB(Widget w, XtPointer clientData, XtPointer callData); static void replaceCB(Widget w, XtPointer clientData, XtPointer callData); static void replaceSameCB(Widget w, XtPointer clientData, XtPointer callData); static void replaceFindSameCB(Widget w, XtPointer clientData, XtPointer callData); static void markCB(Widget w, XtPointer clientData, XtPointer callData); static void gotoMarkCB(Widget w, XtPointer clientData, XtPointer callData); static void gotoMatchingCB(Widget w, XtPointer clientData, XtPointer callData); static void autoIndentOffCB(Widget w, WindowInfo *window, caddr_t callData); static void autoIndentCB(Widget w, WindowInfo *window, caddr_t callData); static void smartIndentCB(Widget w, WindowInfo *window, caddr_t callData); static void preserveCB(Widget w, WindowInfo *window, caddr_t callData); static void autoSaveCB(Widget w, WindowInfo *window, caddr_t callData); static void newlineWrapCB(Widget w, WindowInfo *window, caddr_t callData); static void noWrapCB(Widget w, WindowInfo *window, caddr_t callData); static void continuousWrapCB(Widget w, WindowInfo *window, caddr_t callData); static void wrapMarginCB(Widget w, WindowInfo *window, caddr_t callData); static void fontCB(Widget w, WindowInfo *window, caddr_t callData); static void tabsCB(Widget w, WindowInfo *window, caddr_t callData); static void backlightCharsCB(Widget w, WindowInfo *window, caddr_t callData); static void showMatchingOffCB(Widget w, WindowInfo *window, caddr_t callData); static void showMatchingDelimitCB(Widget w, WindowInfo *window, caddr_t callData); static void showMatchingRangeCB(Widget w, WindowInfo *window, caddr_t callData); static void matchSyntaxBasedCB(Widget w, WindowInfo *window, caddr_t callData); static void statsCB(Widget w, WindowInfo *window, caddr_t callData); static void autoIndentOffDefCB(Widget w, WindowInfo *window, caddr_t callData); static void autoIndentDefCB(Widget w, WindowInfo *window, caddr_t callData); static void smartIndentDefCB(Widget w, WindowInfo *window, caddr_t callData); static void autoSaveDefCB(Widget w, WindowInfo *window, caddr_t callData); static void preserveDefCB(Widget w, WindowInfo *window, caddr_t callData); static void noWrapDefCB(Widget w, WindowInfo *window, caddr_t callData); static void newlineWrapDefCB(Widget w, WindowInfo *window, caddr_t callData); static void contWrapDefCB(Widget w, WindowInfo *window, caddr_t callData); static void wrapMarginDefCB(Widget w, WindowInfo *window, caddr_t callData); static void shellSelDefCB(Widget widget, WindowInfo* window, caddr_t callData); static void openInTabDefCB(Widget w, WindowInfo *window, caddr_t callData); static void tabBarDefCB(Widget w, WindowInfo *window, caddr_t callData); static void tabBarHideDefCB(Widget w, WindowInfo *window, caddr_t callData); static void tabSortDefCB(Widget w, WindowInfo *window, caddr_t callData); static void toolTipsDefCB(Widget w, WindowInfo *window, caddr_t callData); static void tabNavigateDefCB(Widget w, WindowInfo *window, caddr_t callData); static void statsLineDefCB(Widget w, WindowInfo *window, caddr_t callData); static void iSearchLineDefCB(Widget w, WindowInfo *window, caddr_t callData); static void lineNumsDefCB(Widget w, WindowInfo *window, caddr_t callData); static void pathInWindowsMenuDefCB(Widget w, WindowInfo *window, caddr_t callData); static void customizeTitleDefCB(Widget w, WindowInfo *window, caddr_t callData); static void tabsDefCB(Widget w, WindowInfo *window, caddr_t callData); static void showMatchingOffDefCB(Widget w, WindowInfo *window, caddr_t callData); static void showMatchingDelimitDefCB(Widget w, WindowInfo *window, caddr_t callData); static void showMatchingRangeDefCB(Widget w, WindowInfo *window, caddr_t callData); static void matchSyntaxBasedDefCB(Widget w, WindowInfo *window, caddr_t callData); static void highlightOffDefCB(Widget w, WindowInfo *window, caddr_t callData); static void highlightDefCB(Widget w, WindowInfo *window, caddr_t callData); static void backlightCharsDefCB(Widget w, WindowInfo *window, caddr_t callData); static void fontDefCB(Widget w, WindowInfo *window, caddr_t callData); static void colorDefCB(Widget w, WindowInfo *window, caddr_t callData); static void smartTagsDefCB(Widget parent, XtPointer client_data, XtPointer call_data); static void showAllTagsDefCB(Widget parent, XtPointer client_data, XtPointer call_data); static void languageDefCB(Widget w, WindowInfo *window, caddr_t callData); static void highlightingDefCB(Widget w, WindowInfo *window, caddr_t callData); static void smartMacrosDefCB(Widget w, WindowInfo *window, caddr_t callData); static void stylesDefCB(Widget w, WindowInfo *window, caddr_t callData); static void shellDefCB(Widget w, WindowInfo *window, caddr_t callData); static void macroDefCB(Widget w, WindowInfo *window, caddr_t callData); static void bgMenuDefCB(Widget w, WindowInfo *window, caddr_t callData); static void searchDlogsDefCB(Widget w, WindowInfo *window, caddr_t callData); static void beepOnSearchWrapDefCB(Widget w, WindowInfo *window, caddr_t callData); static void keepSearchDlogsDefCB(Widget w, WindowInfo *window, caddr_t callData); static void searchWrapsDefCB(Widget w, WindowInfo *window, caddr_t callData); static void appendLFCB(Widget w, WindowInfo* window, caddr_t callData); static void sortOpenPrevDefCB(Widget w, WindowInfo *window, caddr_t callData); static void reposDlogsDefCB(Widget w, WindowInfo *window, caddr_t callData); static void autoScrollDefCB(Widget w, WindowInfo *window, caddr_t callData); static void modWarnDefCB(Widget w, WindowInfo *window, caddr_t callData); static void modWarnRealDefCB(Widget w, WindowInfo *window, caddr_t callData); static void exitWarnDefCB(Widget w, WindowInfo *window, caddr_t callData); static void searchLiteralCB(Widget w, WindowInfo *window, caddr_t callData); static void searchCaseSenseCB(Widget w, WindowInfo *window, caddr_t callData); static void searchLiteralWordCB(Widget w, WindowInfo *window, caddr_t callData); static void searchCaseSenseWordCB(Widget w, WindowInfo *window, caddr_t callData); static void searchRegexNoCaseCB(Widget w, WindowInfo *window, caddr_t callData); static void searchRegexCB(Widget w, WindowInfo *window, caddr_t callData); #ifdef REPLACE_SCOPE static void replaceScopeWindowCB(Widget w, WindowInfo *window, caddr_t callData); static void replaceScopeSelectionCB(Widget w, WindowInfo *window, caddr_t callData); static void replaceScopeSmartCB(Widget w, WindowInfo *window, caddr_t callData); #endif static void size24x80CB(Widget w, WindowInfo *window, caddr_t callData); static void size40x80CB(Widget w, WindowInfo *window, caddr_t callData); static void size60x80CB(Widget w, WindowInfo *window, caddr_t callData); static void size80x80CB(Widget w, WindowInfo *window, caddr_t callData); static void sizeCustomCB(Widget w, WindowInfo *window, caddr_t callData); static void savePrefCB(Widget w, WindowInfo *window, caddr_t callData); static void formFeedCB(Widget w, XtPointer clientData, XtPointer callData); static void cancelShellCB(Widget w, WindowInfo *window, XtPointer callData); static void learnCB(Widget w, WindowInfo *window, caddr_t callData); static void finishLearnCB(Widget w, WindowInfo *window, caddr_t callData); static void cancelLearnCB(Widget w, WindowInfo *window, caddr_t callData); static void replayCB(Widget w, WindowInfo *window, caddr_t callData); static void windowMenuCB(Widget w, WindowInfo *window, caddr_t callData); static void prevOpenMenuCB(Widget w, WindowInfo *window, caddr_t callData); static void unloadTagsFileMenuCB(Widget w, WindowInfo *window, caddr_t callData); static void unloadTipsFileMenuCB(Widget w, WindowInfo *window, caddr_t callData); static void newAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void newOppositeAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void newTabAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void openDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void openAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void openSelectedAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void closeAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void saveAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void saveAsDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void saveAsAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void revertDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void revertAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void includeDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void includeAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void loadMacroDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) ; static void loadMacroAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void loadTagsDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void loadTagsAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void unloadTagsAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void loadTipsDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void loadTipsAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void unloadTipsAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void printAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void printSelAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void exitAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void undoAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void redoAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void clearAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void selAllAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void shiftLeftAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void shiftLeftTabAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void shiftRightAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void shiftRightTabAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void findDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void findAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void findSameAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void findSelAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void findIncrAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void startIncrFindAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void replaceDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void replaceAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void replaceAllAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void replaceInSelAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void replaceSameAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void replaceFindAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void replaceFindSameAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void gotoAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void gotoDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void gotoSelectedAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void repeatDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void repeatMacroAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void markAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void markDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void gotoMarkAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void gotoMarkDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void selectToMatchingAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void gotoMatchingAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void findDefAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void showTipAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void splitPaneAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void detachDocumentDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void detachDocumentAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void moveDocumentDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void nextDocumentAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void prevDocumentAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void lastDocumentAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void closePaneAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void capitalizeAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void lowercaseAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void fillAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void controlDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); #ifndef VMS static void filterDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void shellFilterAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void execDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void execAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void execLineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void shellMenuAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); #endif static void macroMenuAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void bgMenuAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void beginningOfSelectionAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void endOfSelectionAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static Widget createMenu(Widget parent, char *name, char *label, char mnemonic, Widget *cascadeBtn, int mode); static Widget createMenuItem(Widget parent, char *name, char *label, char mnemonic, menuCallbackProc callback, void *cbArg, int mode); static Widget createFakeMenuItem(Widget parent, char *name, menuCallbackProc callback, void *cbArg); static Widget createMenuToggle(Widget parent, char *name, char *label, char mnemonic, menuCallbackProc callback, void *cbArg, int set, int mode); static Widget createMenuRadioToggle(Widget parent, char *name, char *label, char mnemonic, menuCallbackProc callback, void *cbArg, int set, int mode); static Widget createMenuSeparator(Widget parent, char *name, int mode); static void invalidatePrevOpenMenus(void); static void updateWindowMenu(const WindowInfo *window); static void updatePrevOpenMenu(WindowInfo *window); static void updateTagsFileMenu(WindowInfo *window); static void updateTipsFileMenu(WindowInfo *window); static int searchDirection(int ignoreArgs, String *args, Cardinal *nArgs); static int searchWrap(int ignoreArgs, String *args, Cardinal *nArgs); static int searchKeepDialogs(int ignoreArgs, String *args, Cardinal *nArgs); static int searchType(int ignoreArgs, String *args, Cardinal *nArgs); static char **shiftKeyToDir(XtPointer callData); static void raiseCB(Widget w, WindowInfo *window, caddr_t callData); static void openPrevCB(Widget w, char *name, caddr_t callData); static void unloadTagsFileCB(Widget w, char *name, caddr_t callData); static void unloadTipsFileCB(Widget w, char *name, caddr_t callData); static int cmpStrPtr(const void *strA, const void *strB); static void setWindowSizeDefault(int rows, int cols); static void updateWindowSizeMenus(void); static void updateWindowSizeMenu(WindowInfo *win); static int strCaseCmp(const char *str1, const char *str2); static int compareWindowNames(const void *windowA, const void *windowB); static void bgMenuPostAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void tabMenuPostAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void raiseWindowAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void focusPaneAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setStatisticsLineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setIncrementalSearchLineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setShowLineNumbersAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setAutoIndentAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setWrapTextAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setWrapMarginAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setHighlightSyntaxAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setMakeBackupCopyAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setIncrementalBackupAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setShowMatchingAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setMatchSyntaxBasedAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setOvertypeModeAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setLockedAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setUseTabsAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setEmTabDistAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setTabDistAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setFontsAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void setLanguageModeAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); #ifdef SGI_CUSTOM static void shortMenusCB(Widget w, WindowInfo *window, caddr_t callData); static void addToToggleShortList(Widget w); static int shortPrefAskDefault(Widget parent, Widget w, const char *settingName); #endif static HelpMenu * buildHelpMenu( Widget pane, HelpMenu * menu, WindowInfo * window); /* Application action table */ static XtActionsRec Actions[] = { {"new", newAP}, {"new_opposite", newOppositeAP}, {"new_tab", newTabAP}, {"open", openAP}, {"open-dialog", openDialogAP}, {"open_dialog", openDialogAP}, {"open-selected", openSelectedAP}, {"open_selected", openSelectedAP}, {"close", closeAP}, {"save", saveAP}, {"save-as", saveAsAP}, {"save_as", saveAsAP}, {"save-as-dialog", saveAsDialogAP}, {"save_as_dialog", saveAsDialogAP}, {"revert-to-saved", revertAP}, {"revert_to_saved", revertAP}, {"revert_to_saved_dialog", revertDialogAP}, {"include-file", includeAP}, {"include_file", includeAP}, {"include-file-dialog", includeDialogAP}, {"include_file_dialog", includeDialogAP}, {"load-macro-file", loadMacroAP}, {"load_macro_file", loadMacroAP}, {"load-macro-file-dialog", loadMacroDialogAP}, {"load_macro_file_dialog", loadMacroDialogAP}, {"load-tags-file", loadTagsAP}, {"load_tags_file", loadTagsAP}, {"load-tags-file-dialog", loadTagsDialogAP}, {"load_tags_file_dialog", loadTagsDialogAP}, {"unload_tags_file", unloadTagsAP}, {"load_tips_file", loadTipsAP}, {"load_tips_file_dialog", loadTipsDialogAP}, {"unload_tips_file", unloadTipsAP}, {"print", printAP}, {"print-selection", printSelAP}, {"print_selection", printSelAP}, {"exit", exitAP}, {"undo", undoAP}, {"redo", redoAP}, {"delete", clearAP}, {"select-all", selAllAP}, {"select_all", selAllAP}, {"shift-left", shiftLeftAP}, {"shift_left", shiftLeftAP}, {"shift-left-by-tab", shiftLeftTabAP}, {"shift_left_by_tab", shiftLeftTabAP}, {"shift-right", shiftRightAP}, {"shift_right", shiftRightAP}, {"shift-right-by-tab", shiftRightTabAP}, {"shift_right_by_tab", shiftRightTabAP}, {"find", findAP}, {"find-dialog", findDialogAP}, {"find_dialog", findDialogAP}, {"find-again", findSameAP}, {"find_again", findSameAP}, {"find-selection", findSelAP}, {"find_selection", findSelAP}, {"find_incremental", findIncrAP}, {"start_incremental_find", startIncrFindAP}, {"replace", replaceAP}, {"replace-dialog", replaceDialogAP}, {"replace_dialog", replaceDialogAP}, {"replace-all", replaceAllAP}, {"replace_all", replaceAllAP}, {"replace-in-selection", replaceInSelAP}, {"replace_in_selection", replaceInSelAP}, {"replace-again", replaceSameAP}, {"replace_again", replaceSameAP}, {"replace_find", replaceFindAP}, {"replace_find_same", replaceFindSameAP}, {"replace_find_again", replaceFindSameAP}, {"goto-line-number", gotoAP}, {"goto_line_number", gotoAP}, {"goto-line-number-dialog", gotoDialogAP}, {"goto_line_number_dialog", gotoDialogAP}, {"goto-selected", gotoSelectedAP}, {"goto_selected", gotoSelectedAP}, {"mark", markAP}, {"mark-dialog", markDialogAP}, {"mark_dialog", markDialogAP}, {"goto-mark", gotoMarkAP}, {"goto_mark", gotoMarkAP}, {"goto-mark-dialog", gotoMarkDialogAP}, {"goto_mark_dialog", gotoMarkDialogAP}, {"match", selectToMatchingAP}, {"select_to_matching", selectToMatchingAP}, {"goto_matching", gotoMatchingAP}, {"find-definition", findDefAP}, {"find_definition", findDefAP}, {"show_tip", showTipAP}, {"split-pane", splitPaneAP}, {"split_pane", splitPaneAP}, {"close-pane", closePaneAP}, {"close_pane", closePaneAP}, {"detach_document", detachDocumentAP}, {"detach_document_dialog", detachDocumentDialogAP}, {"move_document_dialog", moveDocumentDialogAP}, {"next_document", nextDocumentAP}, {"previous_document", prevDocumentAP}, {"last_document", lastDocumentAP}, {"uppercase", capitalizeAP}, {"lowercase", lowercaseAP}, {"fill-paragraph", fillAP}, {"fill_paragraph", fillAP}, {"control-code-dialog", controlDialogAP}, {"control_code_dialog", controlDialogAP}, #ifndef VMS {"filter-selection-dialog", filterDialogAP}, {"filter_selection_dialog", filterDialogAP}, {"filter-selection", shellFilterAP}, {"filter_selection", shellFilterAP}, {"execute-command", execAP}, {"execute_command", execAP}, {"execute-command-dialog", execDialogAP}, {"execute_command_dialog", execDialogAP}, {"execute-command-line", execLineAP}, {"execute_command_line", execLineAP}, {"shell-menu-command", shellMenuAP}, {"shell_menu_command", shellMenuAP}, #endif /*VMS*/ {"macro-menu-command", macroMenuAP}, {"macro_menu_command", macroMenuAP}, {"bg_menu_command", bgMenuAP}, {"post_window_bg_menu", bgMenuPostAP}, {"post_tab_context_menu", tabMenuPostAP}, {"beginning-of-selection", beginningOfSelectionAP}, {"beginning_of_selection", beginningOfSelectionAP}, {"end-of-selection", endOfSelectionAP}, {"end_of_selection", endOfSelectionAP}, {"repeat_macro", repeatMacroAP}, {"repeat_dialog", repeatDialogAP}, {"raise_window", raiseWindowAP}, {"focus_pane", focusPaneAP}, {"set_statistics_line", setStatisticsLineAP}, {"set_incremental_search_line", setIncrementalSearchLineAP}, {"set_show_line_numbers", setShowLineNumbersAP}, {"set_auto_indent", setAutoIndentAP}, {"set_wrap_text", setWrapTextAP}, {"set_wrap_margin", setWrapMarginAP}, {"set_highlight_syntax", setHighlightSyntaxAP}, #ifndef VMS {"set_make_backup_copy", setMakeBackupCopyAP}, #endif {"set_incremental_backup", setIncrementalBackupAP}, {"set_show_matching", setShowMatchingAP}, {"set_match_syntax_based", setMatchSyntaxBasedAP}, {"set_overtype_mode", setOvertypeModeAP}, {"set_locked", setLockedAP}, {"set_tab_dist", setTabDistAP}, {"set_em_tab_dist", setEmTabDistAP}, {"set_use_tabs", setUseTabsAP}, {"set_fonts", setFontsAP}, {"set_language_mode", setLanguageModeAP} }; /* List of previously opened files for File menu */ static int NPrevOpen = 0; static char** PrevOpen = NULL; #ifdef SGI_CUSTOM /* Window to receive items to be toggled on and off in short menus mode */ static WindowInfo *ShortMenuWindow; #endif void HidePointerOnKeyedEvent(Widget w, XEvent *event) { if (event && (event->type == KeyPress || event->type == KeyRelease)) { ShowHidePointer((TextWidget)w, True); } } /* ** Install actions for use in translation tables and macro recording, relating ** to menu item commands */ void InstallMenuActions(XtAppContext context) { XtAppAddActions(context, Actions, XtNumber(Actions)); } /* ** Return the (statically allocated) action table for menu item actions. */ XtActionsRec *GetMenuActions(int *nActions) { *nActions = XtNumber(Actions); return Actions; } /* ** Create the menu bar */ Widget CreateMenuBar(Widget parent, WindowInfo *window) { Widget menuBar, menuPane, btn, subPane, subSubPane, subSubSubPane, cascade; /* ** cache user menus: ** allocate user menu cache */ window->userMenuCache = CreateUserMenuCache(); /* ** Create the menu bar (row column) widget */ menuBar = XmCreateMenuBar(parent, "menuBar", NULL, 0); #ifdef SGI_CUSTOM /* ** Short menu mode is a special feature for the SGI system distribution ** version of NEdit. ** ** To make toggling short-menus mode faster (re-creating the menus was ** too slow), a list is kept in the window data structure of items to ** be turned on and off. Initialize that list and give the menu creation ** routines a pointer to the window on which this list is kept. This is ** (unfortunately) a global variable to keep the interface simple for ** the mainstream case. */ ShortMenuWindow = window; window->nToggleShortItems = 0; #endif /* ** "File" pull down menu. */ menuPane = createMenu(menuBar, "fileMenu", "File", 0, NULL, SHORT); createMenuItem(menuPane, "new", "New", 'N', doActionCB, "new", SHORT); if ( GetPrefOpenInTab() ) window->newOppositeItem = createMenuItem(menuPane, "newOpposite", "New Window", 'W', doActionCB, "new_opposite", SHORT); else window->newOppositeItem = createMenuItem(menuPane, "newOpposite", "New Tab", 'T', doActionCB, "new_opposite", SHORT); createMenuItem(menuPane, "open", "Open...", 'O', doActionCB, "open_dialog", SHORT); window->openSelItem=createMenuItem(menuPane, "openSelected", "Open Selected", 'd', doActionCB, "open_selected", FULL); if (GetPrefMaxPrevOpenFiles() > 0) { window->prevOpenMenuPane = createMenu(menuPane, "openPrevious", "Open Previous", 'v', &window->prevOpenMenuItem, SHORT); XtSetSensitive(window->prevOpenMenuItem, NPrevOpen != 0); XtAddCallback(window->prevOpenMenuItem, XmNcascadingCallback, (XtCallbackProc)prevOpenMenuCB, window); } createMenuSeparator(menuPane, "sep1", SHORT); window->closeItem = createMenuItem(menuPane, "close", "Close", 'C', doActionCB, "close", SHORT); createMenuItem(menuPane, "save", "Save", 'S', doActionCB, "save", SHORT); createMenuItem(menuPane, "saveAs", "Save As...", 'A', doActionCB, "save_as_dialog", SHORT); createMenuItem(menuPane, "revertToSaved", "Revert to Saved", 'R', doActionCB, "revert_to_saved_dialog", SHORT); createMenuSeparator(menuPane, "sep2", SHORT); createMenuItem(menuPane, "includeFile", "Include File...", 'I', doActionCB, "include_file_dialog", SHORT); createMenuItem(menuPane, "loadMacroFile", "Load Macro File...", 'M', doActionCB, "load_macro_file_dialog", FULL); createMenuItem(menuPane, "loadTagsFile", "Load Tags File...", 'g', doActionCB, "load_tags_file_dialog", FULL); window->unloadTagsMenuPane = createMenu(menuPane, "unloadTagsFiles", "Unload Tags File", 'U', &window->unloadTagsMenuItem, FULL); XtSetSensitive(window->unloadTagsMenuItem, TagsFileList != NULL); XtAddCallback(window->unloadTagsMenuItem, XmNcascadingCallback, (XtCallbackProc)unloadTagsFileMenuCB, window); createMenuItem(menuPane, "loadTipsFile", "Load Calltips File...", 'F', doActionCB, "load_tips_file_dialog", FULL); window->unloadTipsMenuPane = createMenu(menuPane, "unloadTipsFiles", "Unload Calltips File", 'e', &window->unloadTipsMenuItem, FULL); XtSetSensitive(window->unloadTipsMenuItem, TipsFileList != NULL); XtAddCallback(window->unloadTipsMenuItem, XmNcascadingCallback, (XtCallbackProc)unloadTipsFileMenuCB, window); createMenuSeparator(menuPane, "sep3", SHORT); createMenuItem(menuPane, "print", "Print...", 'P', doActionCB, "print", SHORT); window->printSelItem = createMenuItem(menuPane, "printSelection", "Print Selection...", 'l', doActionCB, "print_selection", SHORT); XtSetSensitive(window->printSelItem, window->wasSelected); createMenuSeparator(menuPane, "sep4", SHORT); createMenuItem(menuPane, "exit", "Exit", 'x', doActionCB, "exit", SHORT); CheckCloseDim(); /* ** "Edit" pull down menu. */ menuPane = createMenu(menuBar, "editMenu", "Edit", 0, NULL, SHORT); window->undoItem = createMenuItem(menuPane, "undo", "Undo", 'U', doActionCB, "undo", SHORT); XtSetSensitive(window->undoItem, False); window->redoItem = createMenuItem(menuPane, "redo", "Redo", 'R', doActionCB, "redo", SHORT); XtSetSensitive(window->redoItem, False); createMenuSeparator(menuPane, "sep1", SHORT); window->cutItem = createMenuItem(menuPane, "cut", "Cut", 't', doActionCB, "cut_clipboard", SHORT); XtSetSensitive(window->cutItem, window->wasSelected); window->copyItem = createMenuItem(menuPane, "copy", "Copy", 'C', doActionCB, "copy_clipboard", SHORT); XtSetSensitive(window->copyItem, window->wasSelected); createMenuItem(menuPane, "paste", "Paste", 'P', doActionCB, "paste_clipboard", SHORT); createMenuItem(menuPane, "pasteColumn", "Paste Column", 's', pasteColCB, window, SHORT); window->delItem=createMenuItem(menuPane, "delete", "Delete", 'D', doActionCB, "delete_selection", SHORT); XtSetSensitive(window->delItem, window->wasSelected); createMenuItem(menuPane, "selectAll", "Select All", 'A', doActionCB, "select_all", SHORT); createMenuSeparator(menuPane, "sep2", SHORT); createMenuItem(menuPane, "shiftLeft", "Shift Left", 'L', shiftLeftCB, window, SHORT); createFakeMenuItem(menuPane, "shiftLeftShift", shiftLeftCB, window); createMenuItem(menuPane, "shiftRight", "Shift Right", 'g', shiftRightCB, window, SHORT); createFakeMenuItem(menuPane, "shiftRightShift", shiftRightCB, window); window->lowerItem=createMenuItem(menuPane, "lowerCase", "Lower-case", 'w', doActionCB, "lowercase", SHORT); window->upperItem=createMenuItem(menuPane, "upperCase", "Upper-case", 'e', doActionCB, "uppercase", SHORT); createMenuItem(menuPane, "fillParagraph", "Fill Paragraph", 'F', doActionCB, "fill_paragraph", SHORT); createMenuSeparator(menuPane, "sep3", FULL); createMenuItem(menuPane, "insertFormFeed", "Insert Form Feed", 'I', formFeedCB, window, FULL); createMenuItem(menuPane, "insertCtrlCode", "Insert Ctrl Code...", 'n', doActionCB, "control_code_dialog", FULL); #ifdef SGI_CUSTOM createMenuSeparator(menuPane, "sep4", SHORT); window->overtypeModeItem = createMenuToggle(menuPane, "overtype", "Overtype", 'O', doActionCB, "set_overtype_mode", False, SHORT); window->readOnlyItem = createMenuToggle(menuPane, "readOnly", "Read Only", 'y', doActionCB, "set_locked", IS_USER_LOCKED(window->lockReasons), FULL); #endif /* ** "Search" pull down menu. */ menuPane = createMenu(menuBar, "searchMenu", "Search", 0, NULL, SHORT); createMenuItem(menuPane, "find", "Find...", 'F', findCB, window, SHORT); createFakeMenuItem(menuPane, "findShift", findCB, window); window->findAgainItem=createMenuItem(menuPane, "findAgain", "Find Again", 'i', findSameCB, window, SHORT); XtSetSensitive(window->findAgainItem, NHist); createFakeMenuItem(menuPane, "findAgainShift", findSameCB, window); window->findSelItem=createMenuItem(menuPane, "findSelection", "Find Selection", 'S', findSelCB, window, SHORT); createFakeMenuItem(menuPane, "findSelectionShift", findSelCB, window); createMenuItem(menuPane, "findIncremental", "Find Incremental", 'n', findIncrCB, window, SHORT); createFakeMenuItem(menuPane, "findIncrementalShift", findIncrCB, window); createMenuItem(menuPane, "replace", "Replace...", 'R', replaceCB, window, SHORT); createFakeMenuItem(menuPane, "replaceShift", replaceCB, window); window->replaceFindAgainItem=createMenuItem(menuPane, "replaceFindAgain", "Replace Find Again", 'A', replaceFindSameCB, window, SHORT); XtSetSensitive(window->replaceFindAgainItem, NHist); createFakeMenuItem(menuPane, "replaceFindAgainShift", replaceFindSameCB, window); window->replaceAgainItem=createMenuItem(menuPane, "replaceAgain", "Replace Again", 'p', replaceSameCB, window, SHORT); XtSetSensitive(window->replaceAgainItem, NHist); createFakeMenuItem(menuPane, "replaceAgainShift", replaceSameCB, window); createMenuSeparator(menuPane, "sep1", FULL); createMenuItem(menuPane, "gotoLineNumber", "Goto Line Number...", 'L', doActionCB, "goto_line_number_dialog", FULL); window->gotoSelItem=createMenuItem(menuPane, "gotoSelected", "Goto Selected", 'G', doActionCB, "goto_selected", FULL); createMenuSeparator(menuPane, "sep2", FULL); createMenuItem(menuPane, "mark", "Mark", 'k', markCB, window, FULL); createMenuItem(menuPane, "gotoMark", "Goto Mark", 'o', gotoMarkCB, window, FULL); createFakeMenuItem(menuPane, "gotoMarkShift", gotoMarkCB, window); createMenuSeparator(menuPane, "sep3", FULL); createMenuItem(menuPane, "gotoMatching", "Goto Matching (..)", 'M', gotoMatchingCB, window, FULL); createFakeMenuItem(menuPane, "gotoMatchingShift", gotoMatchingCB, window); window->findDefItem = createMenuItem(menuPane, "findDefinition", "Find Definition", 'D', doActionCB, "find_definition", FULL); XtSetSensitive(window->findDefItem, TagsFileList != NULL); window->showTipItem = createMenuItem(menuPane, "showCalltip", "Show Calltip", 'C', doActionCB, "show_tip", FULL); XtSetSensitive(window->showTipItem, (TagsFileList != NULL || TipsFileList != NULL) ); /* ** Preferences menu, Default Settings sub menu */ menuPane = createMenu(menuBar, "preferencesMenu", "Preferences", 0, NULL, SHORT); subPane = createMenu(menuPane, "defaultSettings", "Default Settings", 'D', NULL, FULL); createMenuItem(subPane, "languageModes", "Language Modes...", 'L', languageDefCB, window, FULL); /* Auto Indent sub menu */ subSubPane = createMenu(subPane, "autoIndent", "Auto Indent", 'A', NULL, FULL); window->autoIndentOffDefItem = createMenuRadioToggle(subSubPane, "off", "Off", 'O', autoIndentOffDefCB, window, GetPrefAutoIndent(PLAIN_LANGUAGE_MODE) == NO_AUTO_INDENT, SHORT); window->autoIndentDefItem = createMenuRadioToggle(subSubPane, "on", "On", 'n', autoIndentDefCB, window, GetPrefAutoIndent(PLAIN_LANGUAGE_MODE) == AUTO_INDENT, SHORT); window->smartIndentDefItem = createMenuRadioToggle(subSubPane, "smart", "Smart", 'S', smartIndentDefCB, window, GetPrefAutoIndent(PLAIN_LANGUAGE_MODE) == SMART_INDENT, SHORT); createMenuSeparator(subSubPane, "sep1", SHORT); createMenuItem(subSubPane, "ProgramSmartIndent", "Program Smart Indent...", 'P', smartMacrosDefCB, window, FULL); /* Wrap sub menu */ subSubPane = createMenu(subPane, "wrap", "Wrap", 'W', NULL, FULL); window->noWrapDefItem = createMenuRadioToggle(subSubPane, "none", "None", 'N', noWrapDefCB, window, GetPrefWrap(PLAIN_LANGUAGE_MODE) == NO_WRAP, SHORT); window->newlineWrapDefItem = createMenuRadioToggle(subSubPane, "autoNewline", "Auto Newline", 'A', newlineWrapDefCB, window, GetPrefWrap(PLAIN_LANGUAGE_MODE) == NEWLINE_WRAP, SHORT); window->contWrapDefItem = createMenuRadioToggle(subSubPane, "continuous", "Continuous", 'C', contWrapDefCB, window, GetPrefWrap(PLAIN_LANGUAGE_MODE) == CONTINUOUS_WRAP, SHORT); createMenuSeparator(subSubPane, "sep1", SHORT); createMenuItem(subSubPane, "wrapMargin", "Wrap Margin...", 'W', wrapMarginDefCB, window, SHORT); /* Smart Tags sub menu */ subSubPane = createMenu(subPane, "smartTags", "Tag Collisions", 'l', NULL, FULL); window->allTagsDefItem = createMenuRadioToggle(subSubPane, "showall", "Show All", 'A', showAllTagsDefCB, window, !GetPrefSmartTags(), FULL); window->smartTagsDefItem = createMenuRadioToggle(subSubPane, "smart", "Smart", 'S', smartTagsDefCB, window, GetPrefSmartTags(), FULL); createMenuItem(subPane, "shellSel", "Command Shell...", 's', shellSelDefCB, window, SHORT); createMenuItem(subPane, "tabDistance", "Tab Stops...", 'T', tabsDefCB, window, SHORT); createMenuItem(subPane, "textFont", "Text Fonts...", 'F', fontDefCB, window, FULL); createMenuItem(subPane, "colors", "Colors...", 'C', colorDefCB, window, FULL); /* Customize Menus sub menu */ subSubPane = createMenu(subPane, "customizeMenus", "Customize Menus", 'u', NULL, FULL); #ifndef VMS createMenuItem(subSubPane, "shellMenu", "Shell Menu...", 'S', shellDefCB, window, FULL); #endif createMenuItem(subSubPane, "macroMenu", "Macro Menu...", 'M', macroDefCB, window, FULL); createMenuItem(subSubPane, "windowBackgroundMenu", "Window Background Menu...", 'W', bgMenuDefCB, window, FULL); createMenuSeparator(subSubPane, "sep1", SHORT); window->sortOpenPrevDefItem = createMenuToggle(subSubPane, "sortOpenPrevMenu", "Sort Open Prev. Menu", 'o', sortOpenPrevDefCB, window, GetPrefSortOpenPrevMenu(), FULL); window->pathInWindowsMenuDefItem = createMenuToggle(subSubPane, "pathInWindowsMenu", "Show Path In Windows Menu", 'P', pathInWindowsMenuDefCB, window, GetPrefShowPathInWindowsMenu(), SHORT); createMenuItem(subPane, "custimizeTitle", "Customize Window Title...", 'd', customizeTitleDefCB, window, FULL); /* Search sub menu */ subSubPane = createMenu(subPane, "searching", "Searching", 'g', NULL, FULL); window->searchDlogsDefItem = createMenuToggle(subSubPane, "verbose", "Verbose", 'V', searchDlogsDefCB, window, GetPrefSearchDlogs(), SHORT); window->searchWrapsDefItem = createMenuToggle(subSubPane, "wrapAround", "Wrap Around", 'W', searchWrapsDefCB, window, GetPrefSearchWraps(), SHORT); window->beepOnSearchWrapDefItem = createMenuToggle(subSubPane, "beepOnSearchWrap", "Beep On Search Wrap", 'B', beepOnSearchWrapDefCB, window, GetPrefBeepOnSearchWrap(), SHORT); window->keepSearchDlogsDefItem = createMenuToggle(subSubPane, "keepDialogsUp", "Keep Dialogs Up", 'K', keepSearchDlogsDefCB, window, GetPrefKeepSearchDlogs(), SHORT); subSubSubPane = createMenu(subSubPane, "defaultSearchStyle", "Default Search Style", 'D', NULL, FULL); XtVaSetValues(subSubSubPane, XmNradioBehavior, True, NULL); window->searchLiteralDefItem = createMenuToggle(subSubSubPane, "literal", "Literal", 'L', searchLiteralCB, window, GetPrefSearch() == SEARCH_LITERAL, FULL); window->searchCaseSenseDefItem = createMenuToggle(subSubSubPane, "caseSensitive", "Literal, Case Sensitive", 'C', searchCaseSenseCB, window, GetPrefSearch() == SEARCH_CASE_SENSE, FULL); window->searchLiteralWordDefItem = createMenuToggle(subSubSubPane, "literalWord", "Literal, Whole Word", 'W', searchLiteralWordCB, window, GetPrefSearch() == SEARCH_LITERAL_WORD, FULL); window->searchCaseSenseWordDefItem = createMenuToggle(subSubSubPane, "caseSensitiveWord", "Literal, Case Sensitive, Whole Word", 't', searchCaseSenseWordCB, window, GetPrefSearch() == SEARCH_CASE_SENSE_WORD, FULL); window->searchRegexDefItem = createMenuToggle(subSubSubPane, "regularExpression", "Regular Expression", 'R', searchRegexCB, window, GetPrefSearch() == SEARCH_REGEX, FULL); window->searchRegexNoCaseDefItem = createMenuToggle(subSubSubPane, "regularExpressionNoCase", "Regular Expression, Case Insensitive", 'I', searchRegexNoCaseCB, window, GetPrefSearch() == SEARCH_REGEX_NOCASE, FULL); #ifdef REPLACE_SCOPE subSubSubPane = createMenu(subSubPane, "defaultReplaceScope", "Default Replace Scope", 'R', NULL, FULL); XtVaSetValues(subSubSubPane, XmNradioBehavior, True, NULL); window->replScopeWinDefItem = createMenuToggle(subSubSubPane, "window", "In Window", 'W', replaceScopeWindowCB, window, GetPrefReplaceDefScope() == REPL_DEF_SCOPE_WINDOW, FULL); window->replScopeSelDefItem = createMenuToggle(subSubSubPane, "selection", "In Selection", 'S', replaceScopeSelectionCB, window, GetPrefReplaceDefScope() == REPL_DEF_SCOPE_SELECTION, FULL); window->replScopeSmartDefItem = createMenuToggle(subSubSubPane, "window", "Smart", 'm', replaceScopeSmartCB, window, GetPrefReplaceDefScope() == REPL_DEF_SCOPE_SMART, FULL); #endif /* Syntax Highlighting sub menu */ subSubPane = createMenu(subPane, "syntaxHighlighting","Syntax Highlighting", 'H', NULL, FULL); window->highlightOffDefItem = createMenuRadioToggle(subSubPane, "off","Off", 'O', highlightOffDefCB, window, !GetPrefHighlightSyntax(), FULL); window->highlightDefItem = createMenuRadioToggle(subSubPane, "on", "On", 'n', highlightDefCB, window, GetPrefHighlightSyntax(), FULL); createMenuSeparator(subSubPane, "sep1", SHORT); createMenuItem(subSubPane, "recognitionPatterns", "Recognition Patterns...", 'R', highlightingDefCB, window, FULL); createMenuItem(subSubPane, "textDrawingStyles", "Text Drawing Styles...", 'T', stylesDefCB, window, FULL); window->backlightCharsDefItem = createMenuToggle(subPane, "backlightChars", "Apply Backlighting", 'g', backlightCharsDefCB, window, GetPrefBacklightChars(), FULL); /* tabbed editing sub menu */ subSubPane = createMenu(subPane, "tabbedEditMenu", "Tabbed Editing", 0, &cascade, SHORT); window->openInTabDefItem = createMenuToggle(subSubPane, "openAsTab", "Open File In New Tab", 'T', openInTabDefCB, window, GetPrefOpenInTab(), FULL); window->tabBarDefItem = createMenuToggle(subSubPane, "showTabBar", "Show Tab Bar", 'B', tabBarDefCB, window, GetPrefTabBar(), FULL); window->tabBarHideDefItem = createMenuToggle(subSubPane, "hideTabBar", "Hide Tab Bar When Only One Document is Open", 'H', tabBarHideDefCB, window, GetPrefTabBarHideOne(), FULL); window->tabNavigateDefItem = createMenuToggle(subSubPane, "tabNavigateDef", "Next/Prev Tabs Across Windows", 'W', tabNavigateDefCB, window, GetPrefGlobalTabNavigate(), FULL); window->tabSortDefItem = createMenuToggle(subSubPane, "tabSortDef", "Sort Tabs Alphabetically", 'S', tabSortDefCB, window, GetPrefSortTabs(), FULL); window->toolTipsDefItem = createMenuToggle(subPane, "showTooltips", "Show Tooltips", 0, toolTipsDefCB, window, GetPrefToolTips(), FULL); window->statsLineDefItem = createMenuToggle(subPane, "statisticsLine", "Statistics Line", 'S', statsLineDefCB, window, GetPrefStatsLine(), SHORT); window->iSearchLineDefItem = createMenuToggle(subPane, "incrementalSearchLine", "Incremental Search Line", 'i', iSearchLineDefCB, window, GetPrefISearchLine(), FULL); window->lineNumsDefItem = createMenuToggle(subPane, "showLineNumbers", "Show Line Numbers", 'N', lineNumsDefCB, window, GetPrefLineNums(), SHORT); window->saveLastDefItem = createMenuToggle(subPane, "preserveLastVersion", "Make Backup Copy (*.bck)", 'e', preserveDefCB, window, GetPrefSaveOldVersion(), SHORT); window->autoSaveDefItem = createMenuToggle(subPane, "incrementalBackup", "Incremental Backup", 'B', autoSaveDefCB, window, GetPrefAutoSave(), SHORT); /* Show Matching sub menu */ subSubPane = createMenu(subPane, "showMatching", "Show Matching (..)", 'M', NULL, FULL); window->showMatchingOffDefItem = createMenuRadioToggle(subSubPane, "off", "Off", 'O', showMatchingOffDefCB, window, GetPrefShowMatching() == NO_FLASH, SHORT); window->showMatchingDelimitDefItem = createMenuRadioToggle(subSubPane, "delimiter", "Delimiter", 'D', showMatchingDelimitDefCB, window, GetPrefShowMatching() == FLASH_DELIMIT, SHORT); window->showMatchingRangeDefItem = createMenuRadioToggle(subSubPane, "range", "Range", 'R', showMatchingRangeDefCB, window, GetPrefShowMatching() == FLASH_RANGE, SHORT); createMenuSeparator(subSubPane, "sep", SHORT); window->matchSyntaxBasedDefItem = createMenuToggle(subSubPane, "matchSyntax", "Syntax Based", 'S', matchSyntaxBasedDefCB, window, GetPrefMatchSyntaxBased(), SHORT); /* Append LF at end of files on save */ window->appendLFItem = createMenuToggle(subPane, "appendLFItem", "Terminate with Line Break on Save", 'v', appendLFCB, NULL, GetPrefAppendLF(), FULL); window->reposDlogsDefItem = createMenuToggle(subPane, "popupsUnderPointer", "Popups Under Pointer", 'P', reposDlogsDefCB, window, GetPrefRepositionDialogs(), FULL); window->autoScrollDefItem = createMenuToggle(subPane, "autoScroll", "Auto Scroll Near Window Top/Bottom", 0, autoScrollDefCB, window, GetPrefAutoScroll(), FULL); subSubPane = createMenu(subPane, "warnings", "Warnings", 'r', NULL, FULL); window->modWarnDefItem = createMenuToggle(subSubPane, "filesModifiedExternally", "Files Modified Externally", 'F', modWarnDefCB, window, GetPrefWarnFileMods(), FULL); window->modWarnRealDefItem = createMenuToggle(subSubPane, "checkModifiedFileContents", "Check Modified File Contents", 'C', modWarnRealDefCB, window, GetPrefWarnRealFileMods(), FULL); XtSetSensitive(window->modWarnRealDefItem, GetPrefWarnFileMods()); window->exitWarnDefItem = createMenuToggle(subSubPane, "onExit", "On Exit", 'O', exitWarnDefCB, window, GetPrefWarnExit(), FULL); /* Initial Window Size sub menu (simulates radioBehavior) */ subSubPane = createMenu(subPane, "initialwindowSize", "Initial Window Size", 'z', NULL, FULL); /* XtVaSetValues(subSubPane, XmNradioBehavior, True, NULL); */ window->size24x80DefItem = btn = createMenuToggle(subSubPane, "24X80", "24 x 80", '2', size24x80CB, window, False, SHORT); XtVaSetValues(btn, XmNindicatorType, XmONE_OF_MANY, NULL); window->size40x80DefItem = btn = createMenuToggle(subSubPane, "40X80", "40 x 80", '4', size40x80CB, window, False, SHORT); XtVaSetValues(btn, XmNindicatorType, XmONE_OF_MANY, NULL); window->size60x80DefItem = btn = createMenuToggle(subSubPane, "60X80", "60 x 80", '6', size60x80CB, window, False, SHORT); XtVaSetValues(btn, XmNindicatorType, XmONE_OF_MANY, NULL); window->size80x80DefItem = btn = createMenuToggle(subSubPane, "80X80", "80 x 80", '8', size80x80CB, window, False, SHORT); XtVaSetValues(btn, XmNindicatorType, XmONE_OF_MANY, NULL); window->sizeCustomDefItem = btn = createMenuToggle(subSubPane, "custom", "Custom...", 'C', sizeCustomCB, window, False, SHORT); XtVaSetValues(btn, XmNindicatorType, XmONE_OF_MANY, NULL); updateWindowSizeMenu(window); /* ** Remainder of Preferences menu */ createMenuItem(menuPane, "saveDefaults", "Save Defaults...", 'v', savePrefCB, window, FULL); #ifdef SGI_CUSTOM window->shortMenusDefItem = createMenuToggle(menuPane, "shortMenus", "Short Menus", 'h', shortMenusCB, window, GetPrefShortMenus(), SHORT); #endif createMenuSeparator(menuPane, "sep1", SHORT); window->statsLineItem = createMenuToggle(menuPane, "statisticsLine", "Statistics Line", 'S', statsCB, window, GetPrefStatsLine(), SHORT); window->iSearchLineItem = createMenuToggle(menuPane, "incrementalSearchLine","Incremental Search Line", 'I', doActionCB, "set_incremental_search_line", GetPrefISearchLine(), FULL); window->lineNumsItem = createMenuToggle(menuPane, "lineNumbers", "Show Line Numbers", 'N', doActionCB, "set_show_line_numbers", GetPrefLineNums(), SHORT); CreateLanguageModeSubMenu(window, menuPane, "languageMode", "Language Mode", 'L'); subPane = createMenu(menuPane, "autoIndent", "Auto Indent", 'A', NULL, FULL); window->autoIndentOffItem = createMenuRadioToggle(subPane, "off", "Off", 'O', autoIndentOffCB, window, window->indentStyle == NO_AUTO_INDENT, SHORT); window->autoIndentItem = createMenuRadioToggle(subPane, "on", "On", 'n', autoIndentCB, window, window->indentStyle == AUTO_INDENT, SHORT); window->smartIndentItem = createMenuRadioToggle(subPane, "smart", "Smart", 'S', smartIndentCB, window, window->indentStyle == SMART_INDENT, SHORT); subPane = createMenu(menuPane, "wrap", "Wrap", 'W', NULL, FULL); window->noWrapItem = createMenuRadioToggle(subPane, "none", "None", 'N', noWrapCB, window, window->wrapMode==NO_WRAP, SHORT); window->newlineWrapItem = createMenuRadioToggle(subPane, "autoNewlineWrap", "Auto Newline", 'A', newlineWrapCB, window, window->wrapMode==NEWLINE_WRAP, SHORT); window->continuousWrapItem = createMenuRadioToggle(subPane, "continuousWrap", "Continuous", 'C', continuousWrapCB, window, window->wrapMode==CONTINUOUS_WRAP, SHORT); createMenuSeparator(subPane, "sep1", SHORT); createMenuItem(subPane, "wrapMargin", "Wrap Margin...", 'W', wrapMarginCB, window, SHORT); createMenuItem(menuPane, "tabs", "Tab Stops...", 'T', tabsCB, window, SHORT); createMenuItem(menuPane, "textFont", "Text Fonts...", 'F', fontCB, window, FULL); window->highlightItem = createMenuToggle(menuPane, "highlightSyntax", "Highlight Syntax", 'H', doActionCB, "set_highlight_syntax", GetPrefHighlightSyntax(), SHORT); window->backlightCharsItem = createMenuToggle(menuPane, "backlightChars", "Apply Backlighting", 'g', backlightCharsCB, window, window->backlightChars, FULL); #ifndef VMS window->saveLastItem = createMenuToggle(menuPane, "makeBackupCopy", "Make Backup Copy (*.bck)", 'e', preserveCB, window, window->saveOldVersion, SHORT); #endif window->autoSaveItem = createMenuToggle(menuPane, "incrementalBackup", "Incremental Backup", 'B', autoSaveCB, window, window->autoSave, SHORT); subPane = createMenu(menuPane, "showMatching", "Show Matching (..)", 'M', NULL, FULL); window->showMatchingOffItem = createMenuRadioToggle(subPane, "off", "Off", 'O', showMatchingOffCB, window, window->showMatchingStyle == NO_FLASH, SHORT); window->showMatchingDelimitItem = createMenuRadioToggle(subPane, "delimiter", "Delimiter", 'D', showMatchingDelimitCB, window, window->showMatchingStyle == FLASH_DELIMIT, SHORT); window->showMatchingRangeItem = createMenuRadioToggle(subPane, "range", "Range", 'R', showMatchingRangeCB, window, window->showMatchingStyle == FLASH_RANGE, SHORT); createMenuSeparator(subPane, "sep", SHORT); window->matchSyntaxBasedItem = createMenuToggle(subPane, "matchSyntax", "Syntax Based", 'S', matchSyntaxBasedCB, window, window->matchSyntaxBased, SHORT); #ifndef SGI_CUSTOM createMenuSeparator(menuPane, "sep2", SHORT); window->overtypeModeItem = createMenuToggle(menuPane, "overtype", "Overtype", 'O', doActionCB, "set_overtype_mode", False, SHORT); window->readOnlyItem = createMenuToggle(menuPane, "readOnly", "Read Only", 'y', doActionCB, "set_locked", IS_USER_LOCKED(window->lockReasons), FULL); #endif #ifndef VMS /* ** Create the Shell menu */ menuPane = window->shellMenuPane = createMenu(menuBar, "shellMenu", "Shell", 0, &cascade, FULL); btn = createMenuItem(menuPane, "executeCommand", "Execute Command...", 'E', doActionCB, "execute_command_dialog", SHORT); XtVaSetValues(btn, XmNuserData, PERMANENT_MENU_ITEM, NULL); btn = createMenuItem(menuPane, "executeCommandLine", "Execute Command Line", 'x', doActionCB, "execute_command_line", SHORT); XtVaSetValues(btn, XmNuserData, PERMANENT_MENU_ITEM, NULL); window->filterItem = createMenuItem(menuPane, "filterSelection", "Filter Selection...", 'F', doActionCB, "filter_selection_dialog", SHORT); XtVaSetValues(window->filterItem, XmNuserData, PERMANENT_MENU_ITEM, XmNsensitive, window->wasSelected, NULL); window->cancelShellItem = createMenuItem(menuPane, "cancelShellCommand", "Cancel Shell Command", 'C', cancelShellCB, window, SHORT); XtVaSetValues(window->cancelShellItem, XmNuserData, PERMANENT_MENU_ITEM, XmNsensitive, False, NULL); btn = createMenuSeparator(menuPane, "sep1", SHORT); XtVaSetValues(btn, XmNuserData, PERMANENT_MENU_ITEM, NULL); #endif /* ** Create the Macro menu */ menuPane = window->macroMenuPane = createMenu(menuBar, "macroMenu", "Macro", 0, &cascade, FULL); window->learnItem = createMenuItem(menuPane, "learnKeystrokes", "Learn Keystrokes", 'L', learnCB, window, SHORT); XtVaSetValues(window->learnItem , XmNuserData, PERMANENT_MENU_ITEM, NULL); window->finishLearnItem = createMenuItem(menuPane, "finishLearn", "Finish Learn", 'F', finishLearnCB, window, SHORT); XtVaSetValues(window->finishLearnItem , XmNuserData, PERMANENT_MENU_ITEM, XmNsensitive, False, NULL); window->cancelMacroItem = createMenuItem(menuPane, "cancelLearn", "Cancel Learn", 'C', cancelLearnCB, window, SHORT); XtVaSetValues(window->cancelMacroItem, XmNuserData, PERMANENT_MENU_ITEM, XmNsensitive, False, NULL); window->replayItem = createMenuItem(menuPane, "replayKeystrokes", "Replay Keystrokes", 'K', replayCB, window, SHORT); XtVaSetValues(window->replayItem, XmNuserData, PERMANENT_MENU_ITEM, XmNsensitive, GetReplayMacro() != NULL, NULL); window->repeatItem = createMenuItem(menuPane, "repeat", "Repeat...", 'R', doActionCB, "repeat_dialog", SHORT); XtVaSetValues(window->repeatItem, XmNuserData, PERMANENT_MENU_ITEM, NULL); btn = createMenuSeparator(menuPane, "sep1", SHORT); XtVaSetValues(btn, XmNuserData, PERMANENT_MENU_ITEM, NULL); /* ** Create the Windows menu */ menuPane = window->windowMenuPane = createMenu(menuBar, "windowsMenu", "Windows", 0, &cascade, FULL); XtAddCallback(cascade, XmNcascadingCallback, (XtCallbackProc)windowMenuCB, window); window->splitPaneItem = createMenuItem(menuPane, "splitPane", "Split Pane", 'S', doActionCB, "split_pane", SHORT); XtVaSetValues(window->splitPaneItem, XmNuserData, PERMANENT_MENU_ITEM, NULL); window->closePaneItem = createMenuItem(menuPane, "closePane", "Close Pane", 'C', doActionCB, "close_pane", SHORT); XtVaSetValues(window->closePaneItem, XmNuserData, PERMANENT_MENU_ITEM,NULL); XtSetSensitive(window->closePaneItem, False); btn = createMenuSeparator(menuPane, "sep01", SHORT); XtVaSetValues(btn, XmNuserData, PERMANENT_MENU_ITEM, NULL); window->detachDocumentItem = createMenuItem(menuPane, "detachBuffer", "Detach Tab", 'D', doActionCB, "detach_document", SHORT); XtSetSensitive(window->detachDocumentItem, False); window->moveDocumentItem = createMenuItem(menuPane, "moveDocument", "Move Tab To...", 'M', doActionCB, "move_document_dialog", SHORT); XtSetSensitive(window->moveDocumentItem, False); btn = createMenuSeparator(menuPane, "sep1", SHORT); XtVaSetValues(btn, XmNuserData, PERMANENT_MENU_ITEM, NULL); /* ** Create "Help" pull down menu. */ menuPane = createMenu(menuBar, "helpMenu", "Help", 0, &cascade, SHORT); XtVaSetValues(menuBar, XmNmenuHelpWidget, cascade, NULL); buildHelpMenu( menuPane, &H_M[0], window ); return menuBar; } /*----------------------------------------------------------------------------*/ static Widget makeHelpMenuItem( Widget parent, char *name, /* to be assigned to the child widget */ char *label, /* text to be displayed in menu */ char mnemonic, /* letter in label to be underlined */ menuCallbackProc callback, /* activated when menu item selected */ void *cbArg, /* passed to activated call back */ int mode, /* SGI_CUSTOM menu option */ enum HelpTopic topic /* associated with this menu item */ ) { Widget menuItem = createMenuItem( parent, name, label, mnemonic, callback, cbArg, mode ); XtVaSetValues( menuItem, XmNuserData, (XtPointer)topic, NULL ); return menuItem; } /*----------------------------------------------------------------------------*/ static void helpCB( Widget menuItem, XtPointer clientData, XtPointer callData ) { enum HelpTopic topic; XtPointer userData; HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(menuItem))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtVaGetValues( menuItem, XmNuserData, &userData, NULL ); topic = (enum HelpTopic)userData; Help(topic); } /*----------------------------------------------------------------------------*/ #define NON_MENU_HELP 9 static HelpMenu * buildHelpMenu( Widget pane, /* Menu pane on which to place new menu items */ HelpMenu * menu, /* Data to drive building the help menu */ WindowInfo * window /* Main NEdit window information */ ) { #ifdef VMS int hideIt = 1; /* All menu items matching this will be inaccessible */ #else int hideIt = -1; /* This value should make all menu items accessible */ #endif if( menu != NULL ) { int crntLevel = menu->level; /*------------------------- * For each menu element ... *-------------------------*/ while( menu != NULL && menu->level == crntLevel ) { /*---------------------------------------------- * ... see if dealing with a separator or submenu *----------------------------------------------*/ if( menu->topic == HELP_none ) { if( menu->mnemonic == '-' ) { createMenuSeparator(pane, menu->wgtName, SHORT); menu = menu->next; } else { /*------------------------------------------------------- * Do not show any of the submenu when it is to be hidden. *-------------------------------------------------------*/ if( menu->hideIt == hideIt || menu->hideIt == NON_MENU_HELP ) { do { menu = menu->next; } while( menu != NULL && menu->level > crntLevel ); } else { Widget subPane = createMenu( pane, menu->wgtName, menu->subTitle, menu->mnemonic, NULL, FULL); menu = buildHelpMenu( subPane, menu->next, window ); } } } else { /*--------------------------------------- * Show menu item if not going to hide it. * This is the easy way out of hiding * menu items. When entire submenus want * to be hidden, either the entire branch * will have to be marked, or this algorithm * will have to become a lot smarter. *---------------------------------------*/ if( menu->hideIt != hideIt && menu->hideIt != NON_MENU_HELP ) makeHelpMenuItem( pane, menu->wgtName, HelpTitles[menu->topic], menu->mnemonic, helpCB, window, SHORT, menu->topic ); menu = menu->next; } } } return menu; } /*----------------------------------------------------------------------------*/ /* ** handle actions called from the context menus of tabs. */ static void doTabActionCB(Widget w, XtPointer clientData, XtPointer callData) { Widget menu = MENU_WIDGET(w); WindowInfo *win, *window = WidgetToWindow(menu); /* extract the window to be acted upon, see comment in tabMenuPostAP() for detail */ XtVaGetValues(window->tabMenuPane, XmNuserData, &win, NULL); HidePointerOnKeyedEvent(win->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(win->lastFocus, (char *)clientData, ((XmAnyCallbackStruct *)callData)->event, NULL, 0); } static void doActionCB(Widget w, XtPointer clientData, XtPointer callData) { Widget menu = MENU_WIDGET(w); Widget widget = WidgetToWindow(menu)->lastFocus; String action = (String) clientData; XEvent* event = ((XmAnyCallbackStruct*) callData)->event; HidePointerOnKeyedEvent(widget, event); XtCallActionProc(widget, action, event, NULL, 0); } static void pasteColCB(Widget w, XtPointer clientData, XtPointer callData) { static char *params[1] = {"rect"}; HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(MENU_WIDGET(w))->lastFocus, "paste_clipboard", ((XmAnyCallbackStruct *)callData)->event, params, 1); } static void shiftLeftCB(Widget w, XtPointer clientData, XtPointer callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event->xbutton.state & ShiftMask ? "shift_left_by_tab" : "shift_left", ((XmAnyCallbackStruct *)callData)->event, NULL, 0); } static void shiftRightCB(Widget w, XtPointer clientData, XtPointer callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event->xbutton.state & ShiftMask ? "shift_right_by_tab" : "shift_right", ((XmAnyCallbackStruct *)callData)->event, NULL, 0); } static void findCB(Widget w, XtPointer clientData, XtPointer callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(MENU_WIDGET(w))->lastFocus, "find_dialog", ((XmAnyCallbackStruct *)callData)->event, shiftKeyToDir(callData), 1); } static void findSameCB(Widget w, XtPointer clientData, XtPointer callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(MENU_WIDGET(w))->lastFocus, "find_again", ((XmAnyCallbackStruct *)callData)->event, shiftKeyToDir(callData), 1); } static void findSelCB(Widget w, XtPointer clientData, XtPointer callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(MENU_WIDGET(w))->lastFocus, "find_selection", ((XmAnyCallbackStruct *)callData)->event, shiftKeyToDir(callData), 1); } static void findIncrCB(Widget w, XtPointer clientData, XtPointer callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(MENU_WIDGET(w))->lastFocus, "start_incremental_find", ((XmAnyCallbackStruct *)callData)->event, shiftKeyToDir(callData), 1); } static void replaceCB(Widget w, XtPointer clientData, XtPointer callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(MENU_WIDGET(w))->lastFocus, "replace_dialog", ((XmAnyCallbackStruct *)callData)->event, shiftKeyToDir(callData), 1); } static void replaceSameCB(Widget w, XtPointer clientData, XtPointer callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(MENU_WIDGET(w))->lastFocus, "replace_again", ((XmAnyCallbackStruct *)callData)->event, shiftKeyToDir(callData), 1); } static void replaceFindSameCB(Widget w, XtPointer clientData, XtPointer callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(MENU_WIDGET(w))->lastFocus, "replace_find_same", ((XmAnyCallbackStruct *)callData)->event, shiftKeyToDir(callData), 1); } static void markCB(Widget w, XtPointer clientData, XtPointer callData) { XEvent *event = ((XmAnyCallbackStruct *)callData)->event; WindowInfo *window = WidgetToWindow(MENU_WIDGET(w)); HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); if (event->type == KeyPress || event->type == KeyRelease) BeginMarkCommand(window); else XtCallActionProc(window->lastFocus, "mark_dialog", event, NULL, 0); } static void gotoMarkCB(Widget w, XtPointer clientData, XtPointer callData) { XEvent *event = ((XmAnyCallbackStruct *)callData)->event; WindowInfo *window = WidgetToWindow(MENU_WIDGET(w)); int extend = event->xbutton.state & ShiftMask; static char *params[1] = {"extend"}; HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); if (event->type == KeyPress || event->type == KeyRelease) BeginGotoMarkCommand(window, extend); else XtCallActionProc(window->lastFocus, "goto_mark_dialog", event, params, extend ? 1 : 0); } static void gotoMatchingCB(Widget w, XtPointer clientData, XtPointer callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event->xbutton.state & ShiftMask ? "select_to_matching" : "goto_matching", ((XmAnyCallbackStruct *)callData)->event, NULL, 0); } static void autoIndentOffCB(Widget w, WindowInfo *window, caddr_t callData) { static char *params[1] = {"off"}; Widget menu = MENU_WIDGET(w); window = WidgetToWindow(menu); #ifdef SGI_CUSTOM if (shortPrefAskDefault(window->shell, w, "Auto Indent Off")) { autoIndentOffDefCB(w, window, callData); SaveNEditPrefs(window->shell, GetPrefShortMenus()); } #endif HidePointerOnKeyedEvent(WidgetToWindow(menu)->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(menu)->lastFocus, "set_auto_indent", ((XmAnyCallbackStruct *)callData)->event, params, 1); } static void autoIndentCB(Widget w, WindowInfo *window, caddr_t callData) { static char *params[1] = {"on"}; Widget menu = MENU_WIDGET(w); window = WidgetToWindow(menu); #ifdef SGI_CUSTOM if (shortPrefAskDefault(window->shell, w, "Auto Indent")) { autoIndentDefCB(w, window, callData); SaveNEditPrefs(window->shell, GetPrefShortMenus()); } #endif HidePointerOnKeyedEvent(WidgetToWindow(menu)->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(menu)->lastFocus, "set_auto_indent", ((XmAnyCallbackStruct *)callData)->event, params, 1); } static void smartIndentCB(Widget w, WindowInfo *window, caddr_t callData) { static char *params[1] = {"smart"}; Widget menu = MENU_WIDGET(w); window = WidgetToWindow(menu); #ifdef SGI_CUSTOM if (shortPrefAskDefault(window->shell, w, "Smart Indent")) { smartIndentDefCB(w, window, callData); SaveNEditPrefs(window->shell, GetPrefShortMenus()); } #endif HidePointerOnKeyedEvent(WidgetToWindow(menu)->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(menu)->lastFocus, "set_auto_indent", ((XmAnyCallbackStruct *)callData)->event, params, 1); } static void autoSaveCB(Widget w, WindowInfo *window, caddr_t callData) { Widget menu = MENU_WIDGET(w); window = WidgetToWindow(menu); #ifdef SGI_CUSTOM if (shortPrefAskDefault(window->shell, w, "Incremental Backup")) { autoSaveDefCB(w, window, callData); SaveNEditPrefs(window->shell, GetPrefShortMenus()); } #endif HidePointerOnKeyedEvent(WidgetToWindow(menu)->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(menu)->lastFocus, "set_incremental_backup", ((XmAnyCallbackStruct *)callData)->event, NULL, 0); } static void preserveCB(Widget w, WindowInfo *window, caddr_t callData) { Widget menu = MENU_WIDGET(w); window = WidgetToWindow(menu); #ifdef SGI_CUSTOM if (shortPrefAskDefault(window->shell, w, "Make Backup Copy")) { preserveDefCB(w, window, callData); SaveNEditPrefs(window->shell, GetPrefShortMenus()); } #endif HidePointerOnKeyedEvent(WidgetToWindow(menu)->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(menu)->lastFocus, "set_make_backup_copy", ((XmAnyCallbackStruct *)callData)->event, NULL, 0); } static void showMatchingOffCB(Widget w, WindowInfo *window, caddr_t callData) { static char *params[1] = {NO_FLASH_STRING}; Widget menu = MENU_WIDGET(w); window = WidgetToWindow(menu); #ifdef SGI_CUSTOM if (shortPrefAskDefault(window->shell, w, "Show Matching Off")) { showMatchingOffDefCB(w, window, callData); SaveNEditPrefs(window->shell, GetPrefShortMenus()); } #endif HidePointerOnKeyedEvent(WidgetToWindow(menu)->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(menu)->lastFocus, "set_show_matching", ((XmAnyCallbackStruct *)callData)->event, params, 1); } static void showMatchingDelimitCB(Widget w, WindowInfo *window, caddr_t callData) { static char *params[1] = {FLASH_DELIMIT_STRING}; Widget menu = MENU_WIDGET(w); window = WidgetToWindow(menu); #ifdef SGI_CUSTOM if (shortPrefAskDefault(window->shell, w, "Show Matching Delimiter")) { showMatchingDelimitDefCB(w, window, callData); SaveNEditPrefs(window->shell, GetPrefShortMenus()); } #endif HidePointerOnKeyedEvent(WidgetToWindow(menu)->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(menu)->lastFocus, "set_show_matching", ((XmAnyCallbackStruct *)callData)->event, params, 1); } static void showMatchingRangeCB(Widget w, WindowInfo *window, caddr_t callData) { static char *params[1] = {FLASH_RANGE_STRING}; Widget menu = MENU_WIDGET(w); window = WidgetToWindow(menu); #ifdef SGI_CUSTOM if (shortPrefAskDefault(window->shell, w, "Show Matching Range")) { showMatchingRangeDefCB(w, window, callData); SaveNEditPrefs(window->shell, GetPrefShortMenus()); } #endif HidePointerOnKeyedEvent(WidgetToWindow(menu)->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(menu)->lastFocus, "set_show_matching", ((XmAnyCallbackStruct *)callData)->event, params, 1); } static void matchSyntaxBasedCB(Widget w, WindowInfo *window, caddr_t callData) { Widget menu = MENU_WIDGET(w); window = WidgetToWindow(menu); #ifdef SGI_CUSTOM if (shortPrefAskDefault(window->shell, w, "Match Syntax Based")) { matchSyntaxBasedDefCB(w, window, callData); SaveNEditPrefs(window->shell, GetPrefShortMenus()); } #endif HidePointerOnKeyedEvent(WidgetToWindow(menu)->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(menu)->lastFocus, "set_match_syntax_based", ((XmAnyCallbackStruct *)callData)->event, NULL, 0); } static void fontCB(Widget w, WindowInfo *window, caddr_t callData) { ChooseFonts(WidgetToWindow(MENU_WIDGET(w)), True); } static void noWrapCB(Widget w, WindowInfo *window, caddr_t callData) { static char *params[1] = {"none"}; Widget menu = MENU_WIDGET(w); window = WidgetToWindow(menu); #ifdef SGI_CUSTOM if (shortPrefAskDefault(window->shell, w, "No Wrap")) { noWrapDefCB(w, window, callData); SaveNEditPrefs(window->shell, GetPrefShortMenus()); } #endif HidePointerOnKeyedEvent(WidgetToWindow(menu)->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(menu)->lastFocus, "set_wrap_text", ((XmAnyCallbackStruct *)callData)->event, params, 1); } static void newlineWrapCB(Widget w, WindowInfo *window, caddr_t callData) { static char *params[1] = {"auto"}; Widget menu = MENU_WIDGET(w); window = WidgetToWindow(menu); #ifdef SGI_CUSTOM if (shortPrefAskDefault(window->shell, w, "Auto Newline Wrap")) { newlineWrapDefCB(w, window, callData); SaveNEditPrefs(window->shell, GetPrefShortMenus()); } #endif HidePointerOnKeyedEvent(WidgetToWindow(menu)->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(menu)->lastFocus, "set_wrap_text", ((XmAnyCallbackStruct *)callData)->event, params, 1); } static void continuousWrapCB(Widget w, WindowInfo *window, caddr_t callData) { static char *params[1] = {"continuous"}; Widget menu = MENU_WIDGET(w); window = WidgetToWindow(menu); #ifdef SGI_CUSTOM if (shortPrefAskDefault(window->shell, w, "Continuous Wrap")) { contWrapDefCB(w, window, callData); SaveNEditPrefs(window->shell, GetPrefShortMenus()); } #endif HidePointerOnKeyedEvent(WidgetToWindow(menu)->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(menu)->lastFocus, "set_wrap_text", ((XmAnyCallbackStruct *)callData)->event, params, 1); } static void wrapMarginCB(Widget w, WindowInfo *window, caddr_t callData) { window = WidgetToWindow(MENU_WIDGET(w)); HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); WrapMarginDialog(window->shell, window); } static void backlightCharsCB(Widget w, WindowInfo *window, caddr_t callData) { int applyBacklight = XmToggleButtonGetState(w); window = WidgetToWindow(MENU_WIDGET(w)); SetBacklightChars(window, applyBacklight?GetPrefBacklightCharTypes():NULL); } static void tabsCB(Widget w, WindowInfo *window, caddr_t callData) { window = WidgetToWindow(MENU_WIDGET(w)); HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); TabsPrefDialog(window->shell, window); } static void statsCB(Widget w, WindowInfo *window, caddr_t callData) { Widget menu = MENU_WIDGET(w); window = WidgetToWindow(menu); #ifdef SGI_CUSTOM if (shortPrefAskDefault(window->shell, w, "Statistics Line")) { statsLineDefCB(w, window, callData); SaveNEditPrefs(window->shell, GetPrefShortMenus()); } #endif HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(menu)->lastFocus, "set_statistics_line", ((XmAnyCallbackStruct *)callData)->event, NULL, 0); } static void autoIndentOffDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ SetPrefAutoIndent(NO_AUTO_INDENT); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->autoIndentOffDefItem, True, False); XmToggleButtonSetState(win->autoIndentDefItem, False, False); XmToggleButtonSetState(win->smartIndentDefItem, False, False); } } static void autoIndentDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ SetPrefAutoIndent(AUTO_INDENT); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->autoIndentDefItem, True, False); XmToggleButtonSetState(win->autoIndentOffDefItem, False, False); XmToggleButtonSetState(win->smartIndentDefItem, False, False); } } static void smartIndentDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ SetPrefAutoIndent(SMART_INDENT); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->smartIndentDefItem, True, False); XmToggleButtonSetState(win->autoIndentOffDefItem, False, False); XmToggleButtonSetState(win->autoIndentDefItem, False, False); } } static void autoSaveDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefAutoSave(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->autoSaveDefItem, state, False); } } static void preserveDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefSaveOldVersion(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->saveLastDefItem, state, False); } } static void fontDefCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); ChooseFonts(WidgetToWindow(MENU_WIDGET(w)), False); } static void colorDefCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); ChooseColors(WidgetToWindow(MENU_WIDGET(w))); } static void noWrapDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ SetPrefWrap(NO_WRAP); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->noWrapDefItem, True, False); XmToggleButtonSetState(win->newlineWrapDefItem, False, False); XmToggleButtonSetState(win->contWrapDefItem, False, False); } } static void newlineWrapDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ SetPrefWrap(NEWLINE_WRAP); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->newlineWrapDefItem, True, False); XmToggleButtonSetState(win->contWrapDefItem, False, False); XmToggleButtonSetState(win->noWrapDefItem, False, False); } } static void contWrapDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ SetPrefWrap(CONTINUOUS_WRAP); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->contWrapDefItem, True, False); XmToggleButtonSetState(win->newlineWrapDefItem, False, False); XmToggleButtonSetState(win->noWrapDefItem, False, False); } } static void wrapMarginDefCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); WrapMarginDialog(WidgetToWindow(MENU_WIDGET(w))->shell, NULL); } static void smartTagsDefCB(Widget w, XtPointer client_data, XtPointer callData) { WindowInfo *win; SetPrefSmartTags(True); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->smartTagsDefItem, True, False); XmToggleButtonSetState(win->allTagsDefItem, False, False); } } static void showAllTagsDefCB(Widget w, XtPointer client_data, XtPointer callData) { WindowInfo *win; SetPrefSmartTags(False); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->smartTagsDefItem, False, False); XmToggleButtonSetState(win->allTagsDefItem, True, False); } } static void shellSelDefCB(Widget widget, WindowInfo* window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(widget))->lastFocus, ((XmAnyCallbackStruct*) callData)->event); SelectShellDialog(WidgetToWindow(MENU_WIDGET(widget))->shell, NULL); } static void tabsDefCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); TabsPrefDialog(WidgetToWindow(MENU_WIDGET(w))->shell, NULL); } static void showMatchingOffDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ SetPrefShowMatching(NO_FLASH); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->showMatchingOffDefItem, True, False); XmToggleButtonSetState(win->showMatchingDelimitDefItem, False, False); XmToggleButtonSetState(win->showMatchingRangeDefItem, False, False); } } static void showMatchingDelimitDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ SetPrefShowMatching(FLASH_DELIMIT); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->showMatchingOffDefItem, False, False); XmToggleButtonSetState(win->showMatchingDelimitDefItem, True, False); XmToggleButtonSetState(win->showMatchingRangeDefItem, False, False); } } static void showMatchingRangeDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ SetPrefShowMatching(FLASH_RANGE); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->showMatchingOffDefItem, False, False); XmToggleButtonSetState(win->showMatchingDelimitDefItem, False, False); XmToggleButtonSetState(win->showMatchingRangeDefItem, True, False); } } static void matchSyntaxBasedDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefMatchSyntaxBased(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->matchSyntaxBasedDefItem, state, False); } } static void backlightCharsDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefBacklightChars(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->backlightCharsDefItem, state, False); } } static void highlightOffDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ SetPrefHighlightSyntax(False); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->highlightOffDefItem, True, False); XmToggleButtonSetState(win->highlightDefItem, False, False); } } static void highlightDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ SetPrefHighlightSyntax(True); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->highlightOffDefItem, False, False); XmToggleButtonSetState(win->highlightDefItem, True, False); } } static void highlightingDefCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); EditHighlightPatterns(WidgetToWindow(MENU_WIDGET(w))); } static void smartMacrosDefCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); EditSmartIndentMacros(WidgetToWindow(MENU_WIDGET(w))); } static void stylesDefCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); EditHighlightStyles(NULL); } static void languageDefCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); EditLanguageModes(); } #ifndef VMS static void shellDefCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); EditShellMenu(WidgetToWindow(MENU_WIDGET(w))); } #endif /* VMS */ static void macroDefCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); EditMacroMenu(WidgetToWindow(MENU_WIDGET(w))); } static void bgMenuDefCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); EditBGMenu(WidgetToWindow(MENU_WIDGET(w))); } static void customizeTitleDefCB(Widget w, WindowInfo *window, caddr_t callData) { window = WidgetToWindow(MENU_WIDGET(w)); HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); EditCustomTitleFormat(window); } static void searchDlogsDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefSearchDlogs(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->searchDlogsDefItem, state, False); } } static void beepOnSearchWrapDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefBeepOnSearchWrap(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->beepOnSearchWrapDefItem, state, False); } } static void keepSearchDlogsDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefKeepSearchDlogs(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->keepSearchDlogsDefItem, state, False); } } static void searchWrapsDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefSearchWraps(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->searchWrapsDefItem, state, False); } } static void appendLFCB(Widget w, WindowInfo* window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); SetPrefAppendLF(state); for (win = WindowList; win != NULL; win = win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->appendLFItem, state, False); } } static void sortOpenPrevDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference, make the other windows' menus agree, and invalidate their Open Previous menus */ SetPrefSortOpenPrevMenu(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->sortOpenPrevDefItem, state, False); } } static void reposDlogsDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefRepositionDialogs(state); SetPointerCenteredDialogs(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->reposDlogsDefItem, state, False); } } static void autoScrollDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefAutoScroll(state); /* XXX: Should we ensure auto-scroll now if needed? */ for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->autoScrollDefItem, state, False); } } static void modWarnDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefWarnFileMods(state); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->modWarnDefItem, state, False); XtSetSensitive(win->modWarnRealDefItem, state); } } static void modWarnRealDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefWarnRealFileMods(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->modWarnRealDefItem, state, False); } } static void exitWarnDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefWarnExit(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->exitWarnDefItem, state, False); } } static void openInTabDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefOpenInTab(state); for (win=WindowList; win!=NULL; win=win->next) XmToggleButtonSetState(win->openInTabDefItem, state, False); } static void tabBarDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefTabBar(state); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->tabBarDefItem, state, False); ShowWindowTabBar(win); } } static void tabBarHideDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefTabBarHideOne(state); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->tabBarHideDefItem, state, False); ShowWindowTabBar(win); } } static void toolTipsDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefToolTips(state); for (win=WindowList; win!=NULL; win=win->next) { XtVaSetValues(win->tab, XltNshowBubble, GetPrefToolTips(), NULL); if (IsTopDocument(win)) XmToggleButtonSetState(win->toolTipsDefItem, state, False); } } static void tabNavigateDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefGlobalTabNavigate(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->tabNavigateDefItem, state, False); } } static void tabSortDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefSortTabs(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->tabSortDefItem, state, False); } /* If we just enabled sorting, sort all tabs. Note that this reorders the next pointers underneath us, which is scary, but SortTabBar never touches windows that are earlier in the WindowList so it's ok. */ if (state) { Widget shell=(Widget)0; for (win=WindowList; win!=NULL; win=win->next) { if ( win->shell != shell ) { SortTabBar(win); shell = win->shell; } } } } static void statsLineDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefStatsLine(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->statsLineDefItem, state, False); } } static void iSearchLineDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefISearchLine(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->iSearchLineDefItem, state, False); } } static void lineNumsDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefLineNums(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->lineNumsDefItem, state, False); } } static void pathInWindowsMenuDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int state = XmToggleButtonGetState(w); /* Set the preference and make the other windows' menus agree */ SetPrefShowPathInWindowsMenu(state); for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win)) XmToggleButtonSetState(win->pathInWindowsMenuDefItem, state, False); } InvalidateWindowMenus(); } static void searchLiteralCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ if (XmToggleButtonGetState(w)) { SetPrefSearch(SEARCH_LITERAL); for (win=WindowList; win!=NULL; win=win->next){ if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->searchLiteralDefItem, True, False); XmToggleButtonSetState(win->searchCaseSenseDefItem, False, False); XmToggleButtonSetState(win->searchLiteralWordDefItem, False, False); XmToggleButtonSetState(win->searchCaseSenseWordDefItem, False, False); XmToggleButtonSetState(win->searchRegexDefItem, False, False); XmToggleButtonSetState(win->searchRegexNoCaseDefItem, False, False); } } } static void searchCaseSenseCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ if (XmToggleButtonGetState(w)) { SetPrefSearch(SEARCH_CASE_SENSE); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->searchLiteralDefItem, False, False); XmToggleButtonSetState(win->searchCaseSenseDefItem, True, False); XmToggleButtonSetState(win->searchLiteralWordDefItem, False, False); XmToggleButtonSetState(win->searchCaseSenseWordDefItem, False, False); XmToggleButtonSetState(win->searchRegexDefItem, False, False); XmToggleButtonSetState(win->searchRegexNoCaseDefItem, False, False); } } } static void searchLiteralWordCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ if (XmToggleButtonGetState(w)) { SetPrefSearch(SEARCH_LITERAL_WORD); for (win=WindowList; win!=NULL; win=win->next){ if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->searchLiteralDefItem, False, False); XmToggleButtonSetState(win->searchCaseSenseDefItem, False, False); XmToggleButtonSetState(win->searchLiteralWordDefItem, True, False); XmToggleButtonSetState(win->searchCaseSenseWordDefItem, False, False); XmToggleButtonSetState(win->searchRegexDefItem, False, False); XmToggleButtonSetState(win->searchRegexNoCaseDefItem, False, False); } } } static void searchCaseSenseWordCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ if (XmToggleButtonGetState(w)) { SetPrefSearch(SEARCH_CASE_SENSE_WORD); for (win=WindowList; win!=NULL; win=win->next) { if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->searchLiteralDefItem, False, False); XmToggleButtonSetState(win->searchCaseSenseDefItem, False, False); XmToggleButtonSetState(win->searchLiteralWordDefItem, False, False); XmToggleButtonSetState(win->searchCaseSenseWordDefItem, True, False); XmToggleButtonSetState(win->searchRegexDefItem, False, False); XmToggleButtonSetState(win->searchRegexNoCaseDefItem, False, False); } } } static void searchRegexCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ if (XmToggleButtonGetState(w)) { SetPrefSearch(SEARCH_REGEX); for (win=WindowList; win!=NULL; win=win->next){ if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->searchLiteralDefItem, False, False); XmToggleButtonSetState(win->searchCaseSenseDefItem, False, False); XmToggleButtonSetState(win->searchLiteralWordDefItem, False, False); XmToggleButtonSetState(win->searchCaseSenseWordDefItem, False, False); XmToggleButtonSetState(win->searchRegexDefItem, True, False); XmToggleButtonSetState(win->searchRegexNoCaseDefItem, False, False); } } } static void searchRegexNoCaseCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ if (XmToggleButtonGetState(w)) { SetPrefSearch(SEARCH_REGEX_NOCASE); for (win=WindowList; win!=NULL; win=win->next){ if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->searchLiteralDefItem, False, False); XmToggleButtonSetState(win->searchCaseSenseDefItem, False, False); XmToggleButtonSetState(win->searchLiteralWordDefItem, False, False); XmToggleButtonSetState(win->searchCaseSenseWordDefItem, False, False); XmToggleButtonSetState(win->searchRegexDefItem, False, False); XmToggleButtonSetState(win->searchRegexNoCaseDefItem, True, False); } } } #ifdef REPLACE_SCOPE static void replaceScopeWindowCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ if (XmToggleButtonGetState(w)) { SetPrefReplaceDefScope(REPL_DEF_SCOPE_WINDOW); for (win=WindowList; win!=NULL; win=win->next){ if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->replScopeWinDefItem, True, False); XmToggleButtonSetState(win->replScopeSelDefItem, False, False); XmToggleButtonSetState(win->replScopeSmartDefItem, False, False); } } } static void replaceScopeSelectionCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ if (XmToggleButtonGetState(w)) { SetPrefReplaceDefScope(REPL_DEF_SCOPE_SELECTION); for (win=WindowList; win!=NULL; win=win->next){ if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->replScopeWinDefItem, False, False); XmToggleButtonSetState(win->replScopeSelDefItem, True, False); XmToggleButtonSetState(win->replScopeSmartDefItem, False, False); } } } static void replaceScopeSmartCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; /* Set the preference and make the other windows' menus agree */ if (XmToggleButtonGetState(w)) { SetPrefReplaceDefScope(REPL_DEF_SCOPE_SMART); for (win=WindowList; win!=NULL; win=win->next){ if (!IsTopDocument(win)) continue; XmToggleButtonSetState(win->replScopeWinDefItem, False, False); XmToggleButtonSetState(win->replScopeSelDefItem, False, False); XmToggleButtonSetState(win->replScopeSmartDefItem, True, False); } } } #endif static void size24x80CB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); setWindowSizeDefault(24, 80); } static void size40x80CB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); setWindowSizeDefault(40, 80); } static void size60x80CB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); setWindowSizeDefault(60, 80); } static void size80x80CB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); setWindowSizeDefault(80, 80); } static void sizeCustomCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); RowColumnPrefDialog(WidgetToWindow(MENU_WIDGET(w))->shell); updateWindowSizeMenus(); } static void savePrefCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); SaveNEditPrefs(WidgetToWindow(MENU_WIDGET(w))->shell, False); } static void formFeedCB(Widget w, XtPointer clientData, XtPointer callData) { static char *params[1] = {"\f"}; HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); XtCallActionProc(WidgetToWindow(MENU_WIDGET(w))->lastFocus, "insert_string", ((XmAnyCallbackStruct *)callData)->event, params, 1); } static void cancelShellCB(Widget w, WindowInfo *window, XtPointer callData) { #ifndef VMS HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); AbortShellCommand(WidgetToWindow(MENU_WIDGET(w))); #endif } static void learnCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); BeginLearn(WidgetToWindow(MENU_WIDGET(w))); } static void finishLearnCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); FinishLearn(); } static void cancelLearnCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); CancelMacroOrLearn(WidgetToWindow(MENU_WIDGET(w))); } static void replayCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); Replay(WidgetToWindow(MENU_WIDGET(w))); } static void windowMenuCB(Widget w, WindowInfo *window, caddr_t callData) { window = WidgetToWindow(MENU_WIDGET(w)); if (!window->windowMenuValid) { updateWindowMenu(window); window->windowMenuValid = True; } } static void prevOpenMenuCB(Widget w, WindowInfo *window, caddr_t callData) { window = WidgetToWindow(MENU_WIDGET(w)); updatePrevOpenMenu(window); } static void unloadTagsFileMenuCB(Widget w, WindowInfo *window, caddr_t callData) { updateTagsFileMenu(WidgetToWindow(MENU_WIDGET(w))); } static void unloadTipsFileMenuCB(Widget w, WindowInfo *window, caddr_t callData) { updateTipsFileMenu(WidgetToWindow(MENU_WIDGET(w))); } /* ** open a new tab or window. */ static void newAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); int openInTab = GetPrefOpenInTab(); if (*nArgs > 0) { if (strcmp(args[0], "prefs") == 0) { /* accept default */; } else if (strcmp(args[0], "tab") == 0) { openInTab = 1; } else if (strcmp(args[0], "window") == 0) { openInTab = 0; } else if (strcmp(args[0], "opposite") == 0) { openInTab = !openInTab; } else { fprintf(stderr, "nedit: Unknown argument to action procedure \"new\": %s\n", args[0]); } } EditNewFile(openInTab? window : NULL, NULL, False, NULL, window->path); CheckCloseDim(); } /* ** These are just here because our techniques make it hard to bind a menu item ** to an action procedure that takes arguments. The user doesn't need to know ** about them -- they can use new( "opposite" ) or new( "tab" ). */ static void newOppositeAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); EditNewFile(GetPrefOpenInTab()? NULL : window, NULL, False, NULL, window->path); CheckCloseDim(); } static void newTabAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); EditNewFile(window, NULL, False, NULL, window->path); CheckCloseDim(); } static void openDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); char fullname[MAXPATHLEN], *params[2]; int response; int n=1; response = PromptForExistingFile(window, "Open File", fullname); if (response != GFN_OK) return; params[0] = fullname; if (*nArgs>0 && !strcmp(args[0], "1")) params[n++] = "1"; XtCallActionProc(window->lastFocus, "open", event, params, n); CheckCloseDim(); } static void openAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); char filename[MAXPATHLEN], pathname[MAXPATHLEN]; if (*nArgs == 0) { fprintf(stderr, "nedit: open action requires file argument\n"); return; } if (0 != ParseFilename(args[0], filename, pathname) || strlen(filename) + strlen(pathname) > MAXPATHLEN - 1) { fprintf(stderr, "nedit: invalid file name for open action: %s\n", args[0]); return; } EditExistingFile(window, filename, pathname, 0, NULL, False, NULL, GetPrefOpenInTab(), False); CheckCloseDim(); } static void openSelectedAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { OpenSelectedFile(WidgetToWindow(w), event->xbutton.time); CheckCloseDim(); } static void closeAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { int preResponse = PROMPT_SBC_DIALOG_RESPONSE; if (*nArgs > 0) { if (strcmp(args[0], "prompt") == 0) { preResponse = PROMPT_SBC_DIALOG_RESPONSE; } else if (strcmp(args[0], "save") == 0) { preResponse = YES_SBC_DIALOG_RESPONSE; } else if (strcmp(args[0], "nosave") == 0) { preResponse = NO_SBC_DIALOG_RESPONSE; } } CloseFileAndWindow(WidgetToWindow(w), preResponse); CheckCloseDim(); } static void saveAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; SaveWindow(window); } static void saveAsDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); int response, addWrap, fileFormat; char fullname[MAXPATHLEN], *params[2]; response = PromptForNewFile(window, "Save File As", fullname, &fileFormat, &addWrap); if (response != GFN_OK) return; window->fileFormat = fileFormat; params[0] = fullname; params[1] = "wrapped"; XtCallActionProc(window->lastFocus, "save_as", event, params, addWrap?2:1); } static void saveAsAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { if (*nArgs == 0) { fprintf(stderr, "nedit: save_as action requires file argument\n"); return; } SaveWindowAs(WidgetToWindow(w), args[0], *nArgs == 2 && !strCaseCmp(args[1], "wrapped")); } static void revertDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); int b; /* re-reading file is irreversible, prompt the user first */ if (window->fileChanged) { b = DialogF(DF_QUES, window->shell, 2, "Discard Changes", "Discard changes to\n%s%s?", "OK", "Cancel", window->path, window->filename); } else { b = DialogF(DF_QUES, window->shell, 2, "Reload File", "Re-load file\n%s%s?", "Re-read", "Cancel", window->path, window->filename); } if (b != 1) { return; } XtCallActionProc(window->lastFocus, "revert_to_saved", event, NULL, 0); } static void revertAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { RevertToSaved(WidgetToWindow(w)); } static void includeDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); char filename[MAXPATHLEN], *params[1]; int response; if (CheckReadOnly(window)) return; response = PromptForExistingFile(window, "Include File", filename); if (response != GFN_OK) return; params[0] = filename; XtCallActionProc(window->lastFocus, "include_file", event, params, 1); } static void includeAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; if (*nArgs == 0) { fprintf(stderr, "nedit: include action requires file argument\n"); return; } IncludeFile(WidgetToWindow(w), args[0]); } static void loadMacroDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); char filename[MAXPATHLEN], *params[1]; int response; response = PromptForExistingFile(window, "Load Macro File", filename); if (response != GFN_OK) return; params[0] = filename; XtCallActionProc(window->lastFocus, "load_macro_file", event, params, 1); } static void loadMacroAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { if (*nArgs == 0) { fprintf(stderr,"nedit: load_macro_file action requires file argument\n"); return; } ReadMacroFile(WidgetToWindow(w), args[0], True); } static void loadTagsDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); char filename[MAXPATHLEN], *params[1]; int response; response = PromptForExistingFile(window, "Load Tags File", filename); if (response != GFN_OK) return; params[0] = filename; XtCallActionProc(window->lastFocus, "load_tags_file", event, params, 1); } static void loadTagsAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { if (*nArgs == 0) { fprintf(stderr,"nedit: load_tags_file action requires file argument\n"); return; } if (!AddTagsFile(args[0], TAG)) { DialogF(DF_WARN, WidgetToWindow(w)->shell, 1, "Error Reading File", "Error reading ctags file:\n'%s'\ntags not loaded", "OK", args[0]); } } static void unloadTagsAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { if (*nArgs == 0) { fprintf(stderr, "nedit: unload_tags_file action requires file argument\n"); return; } if (DeleteTagsFile(args[0], TAG, True)) { WindowInfo *win; /* refresh the "Unload Tags File" tear-offs after unloading, or close the tear-offs if all tags files have been unloaded */ for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win) && !XmIsMenuShell(XtParent(win->unloadTagsMenuPane))) { if (XtIsSensitive(win->unloadTagsMenuItem)) updateTagsFileMenu(win); else _XmDismissTearOff(XtParent(win->unloadTagsMenuPane), NULL, NULL); } } } } static void loadTipsDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); char filename[MAXPATHLEN], *params[1]; int response; response = PromptForExistingFile(window, "Load Calltips File", filename); if (response != GFN_OK) return; params[0] = filename; XtCallActionProc(window->lastFocus, "load_tips_file", event, params, 1); } static void loadTipsAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { if (*nArgs == 0) { fprintf(stderr,"nedit: load_tips_file action requires file argument\n"); return; } if (!AddTagsFile(args[0], TIP)) { DialogF(DF_WARN, WidgetToWindow(w)->shell, 1, "Error Reading File", "Error reading tips file:\n'%s'\ntips not loaded", "OK", args[0]); } } static void unloadTipsAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { if (*nArgs == 0) { fprintf(stderr, "nedit: unload_tips_file action requires file argument\n"); return; } /* refresh the "Unload Calltips File" tear-offs after unloading, or close the tear-offs if all tips files have been unloaded */ if (DeleteTagsFile(args[0], TIP, True)) { WindowInfo *win; for (win=WindowList; win!=NULL; win=win->next) { if (IsTopDocument(win) && !XmIsMenuShell(XtParent(win->unloadTipsMenuPane))) { if (XtIsSensitive(win->unloadTipsMenuItem)) updateTipsFileMenu(win); else _XmDismissTearOff(XtParent(win->unloadTipsMenuPane), NULL, NULL); } } } } static void printAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { PrintWindow(WidgetToWindow(w), False); } static void printSelAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { PrintWindow(WidgetToWindow(w), True); } static void exitAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (!CheckPrefsChangesSaved(window->shell)) return; /* If this is not the last window (more than one window is open), confirm with the user before exiting. */ if (GetPrefWarnExit() && !(window == WindowList && window->next == NULL)) { int resp, titleLen, lineLen; char exitMsg[DF_MAX_MSG_LENGTH], *ptr, *title; char filename[MAXPATHLEN]; WindowInfo *win; /* List the windows being edited and make sure the user really wants to exit */ ptr = exitMsg; lineLen = 0; strcpy(ptr, "Editing: "); ptr += 9; lineLen += 9; for (win=WindowList; win!=NULL; win=win->next) { sprintf(filename, "%s%s", win->filename, win->fileChanged? "*": ""); title = filename; titleLen = strlen(title); if (ptr - exitMsg + titleLen + 30 >= DF_MAX_MSG_LENGTH) { strcpy(ptr, "..."); ptr += 3; break; } if (lineLen + titleLen + (win->next==NULL?5:2) > 50) { *ptr++ = '\n'; lineLen = 0; } if (win->next == NULL) { sprintf(ptr, "and %s.", title); ptr += 5 + titleLen; lineLen += 5 + titleLen; } else { sprintf(ptr, "%s, ", title); ptr += 2 + titleLen; lineLen += 2 + titleLen; } } sprintf(ptr, "\n\nExit NEdit?"); resp = DialogF(DF_QUES, window->shell, 2, "Exit", "%s", "Exit", "Cancel", exitMsg); if (resp == 2) return; } /* Close all files and exit when the last one is closed */ if (CloseAllFilesAndWindows()) exit(EXIT_SUCCESS); } static void undoAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; Undo(window); } static void redoAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; Redo(window); } static void clearAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; BufRemoveSelected(window->buffer); } static void selAllAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); BufSelect(window->buffer, 0, window->buffer->length); } static void shiftLeftAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; ShiftSelection(window, SHIFT_LEFT, False); } static void shiftLeftTabAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; ShiftSelection(window, SHIFT_LEFT, True); } static void shiftRightAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; ShiftSelection(window, SHIFT_RIGHT, False); } static void shiftRightTabAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; ShiftSelection(window, SHIFT_RIGHT, True); } static void findDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { DoFindDlog(WidgetToWindow(w), searchDirection(0, args, nArgs), searchKeepDialogs(0, args, nArgs), searchType(0, args, nArgs), event->xbutton.time); } static void findAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { if (*nArgs == 0) { fprintf(stderr, "nedit: find action requires search string argument\n"); return; } SearchAndSelect(WidgetToWindow(w), searchDirection(1, args, nArgs), args[0], searchType(1, args, nArgs), searchWrap(1, args, nArgs)); } static void findSameAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { SearchAndSelectSame(WidgetToWindow(w), searchDirection(0, args, nArgs), searchWrap(0, args, nArgs)); } static void findSelAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { SearchForSelected(WidgetToWindow(w), searchDirection(0, args, nArgs), searchType(0, args, nArgs), searchWrap(0, args, nArgs), event->xbutton.time); } static void startIncrFindAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { BeginISearch(WidgetToWindow(w), searchDirection(0, args, nArgs)); } static void findIncrAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { int i, continued = FALSE; if (*nArgs == 0) { fprintf(stderr, "nedit: find action requires search string argument\n"); return; } for (i=1; i<(int)*nArgs; i++) if (!strCaseCmp(args[i], "continued")) continued = TRUE; SearchAndSelectIncremental(WidgetToWindow(w), searchDirection(1, args, nArgs), args[0], searchType(1, args, nArgs), searchWrap(1, args, nArgs), continued); } static void replaceDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; DoFindReplaceDlog(window, searchDirection(0, args, nArgs), searchKeepDialogs(0, args, nArgs), searchType(0, args, nArgs), event->xbutton.time); } static void replaceAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; if (*nArgs < 2) { fprintf(stderr, "nedit: replace action requires search and replace string arguments\n"); return; } SearchAndReplace(window, searchDirection(2, args, nArgs), args[0], args[1], searchType(2, args, nArgs), searchWrap(2, args, nArgs)); } static void replaceAllAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; if (*nArgs < 2) { fprintf(stderr, "nedit: replace_all action requires search and replace string arguments\n"); return; } ReplaceAll(window, args[0], args[1], searchType(2, args, nArgs)); } static void replaceInSelAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; if (*nArgs < 2) { fprintf(stderr, "nedit: replace_in_selection requires search and replace string arguments\n"); return; } ReplaceInSelection(window, args[0], args[1], searchType(2, args, nArgs)); } static void replaceSameAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; ReplaceSame(window, searchDirection(0, args, nArgs), searchWrap(0, args, nArgs)); } static void replaceFindAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) { return; } if (*nArgs < 2) { DialogF(DF_WARN, window->shell, 1, "Error in replace_find", "replace_find action requires search and replace string arguments", "OK"); return; } ReplaceAndSearch(window, searchDirection(2, args, nArgs), args[0], args[1], searchType(2, args, nArgs), searchWrap(0, args, nArgs)); } static void replaceFindSameAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; ReplaceFindSame(window, searchDirection(0, args, nArgs), searchWrap(0, args, nArgs)); } static void gotoAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { int lineNum, column, position, curCol; /* Accept various formats: [line]:[column] (menu action) line (macro call) line, column (macro call) */ if (*nArgs == 0 || *nArgs > 2 || (*nArgs == 1 && StringToLineAndCol(args[0], &lineNum, &column ) == -1) || (*nArgs == 2 && (!StringToNum(args[0], &lineNum) || !StringToNum(args[1], &column)))) { fprintf(stderr,"nedit: goto_line_number action requires line and/or column number\n"); return; } /* User specified column, but not line number */ if (lineNum == -1) { position = TextGetCursorPos(w); if (TextPosToLineAndCol(w, position, &lineNum, &curCol) == False) { return; } } else if ( column == -1 ) { /* User didn't specify a column */ SelectNumberedLine(WidgetToWindow(w), lineNum); return; } position = TextLineAndColToPos(w, lineNum, column ); if ( position == -1 ) { return; } TextSetCursorPos(w, position); return; } static void gotoDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { GotoLineNumber(WidgetToWindow(w)); } static void gotoSelectedAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { GotoSelectedLineNumber(WidgetToWindow(w), event->xbutton.time); } static void repeatDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { RepeatDialog(WidgetToWindow(w)); } static void repeatMacroAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { int how; if (*nArgs != 2) { fprintf(stderr, "nedit: repeat_macro requires two arguments\n"); return; } if (!strcmp(args[0], "in_selection")) how = REPEAT_IN_SEL; else if (!strcmp(args[0], "to_end")) how = REPEAT_TO_END; else if (sscanf(args[0], "%d", &how) != 1) { fprintf(stderr, "nedit: repeat_macro requires method/count\n"); return; } RepeatMacro(WidgetToWindow(w), args[1], how); } static void markAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { if (*nArgs == 0 || strlen(args[0]) != 1 || !isalnum((unsigned char)args[0][0])) { fprintf(stderr,"nedit: mark action requires a single-letter label\n"); return; } AddMark(WidgetToWindow(w), w, args[0][0]); } static void markDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { MarkDialog(WidgetToWindow(w)); } static void gotoMarkAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { if (*nArgs == 0 || strlen(args[0]) != 1 || !isalnum((unsigned char)args[0][0])) { fprintf(stderr, "nedit: goto_mark action requires a single-letter label\n"); return; } GotoMark(WidgetToWindow(w), w, args[0][0], *nArgs > 1 && !strcmp(args[1], "extend")); } static void gotoMarkDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { GotoMarkDialog(WidgetToWindow(w), *nArgs!=0 && !strcmp(args[0], "extend")); } static void selectToMatchingAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { SelectToMatchingCharacter(WidgetToWindow(w)); } static void gotoMatchingAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { GotoMatchingCharacter(WidgetToWindow(w)); } static void findDefAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { FindDefinition(WidgetToWindow(w), event->xbutton.time, *nArgs == 0 ? NULL : args[0]); } static void showTipAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { FindDefCalltip(WidgetToWindow(w), event->xbutton.time, *nArgs == 0 ? NULL : args[0]); } static void splitPaneAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); SplitPane(window); if (IsTopDocument(window)) { XtSetSensitive(window->splitPaneItem, window->nPanes < MAX_PANES); XtSetSensitive(window->closePaneItem, window->nPanes > 0); } } static void closePaneAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); ClosePane(window); if (IsTopDocument(window)) { XtSetSensitive(window->splitPaneItem, window->nPanes < MAX_PANES); XtSetSensitive(window->closePaneItem, window->nPanes > 0); } } static void detachDocumentDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); int resp; if (NDocuments(window) < 2) return; resp = DialogF(DF_QUES, window->shell, 2, "Detach %s?", "Detach", "Cancel", window->filename); if (resp == 1) DetachDocument(window); } static void detachDocumentAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (NDocuments(window) < 2) return; DetachDocument(window); } static void moveDocumentDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { MoveDocumentDialog(WidgetToWindow(w)); } static void nextDocumentAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { NextDocument(WidgetToWindow(w)); } static void prevDocumentAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { PreviousDocument(WidgetToWindow(w)); } static void lastDocumentAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { LastDocument(WidgetToWindow(w)); } static void capitalizeAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; UpcaseSelection(window); } static void lowercaseAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; DowncaseSelection(window); } static void fillAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; FillSelection(window); } static void controlDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); unsigned char charCodeString[2]; char charCodeText[DF_MAX_PROMPT_LENGTH], dummy[DF_MAX_PROMPT_LENGTH]; char *params[1]; int charCode, nRead, response; if (CheckReadOnly(window)) return; response = DialogF(DF_PROMPT, window->shell, 2, "Insert Ctrl Code", "ASCII Character Code:", charCodeText, "OK", "Cancel"); if (response == 2) return; /* If we don't scan for a trailing string invalid input would be accepted sometimes. */ nRead = sscanf(charCodeText, "%i%s", &charCode, dummy); if (nRead != 1 || charCode < 0 || charCode > 255) { XBell(TheDisplay, 0); return; } charCodeString[0] = (unsigned char)charCode; charCodeString[1] = '\0'; params[0] = (char *)charCodeString; if (!BufSubstituteNullChars((char *)charCodeString, 1, window->buffer)) { DialogF(DF_ERR, window->shell, 1, "Error", "Too much binary data", "OK"); return; } XtCallActionProc(w, "insert_string", event, params, 1); } #ifndef VMS static void filterDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); char *params[1], cmdText[DF_MAX_PROMPT_LENGTH]; int resp; static char **cmdHistory = NULL; static int nHistoryCmds = 0; if (CheckReadOnly(window)) return; if (!window->buffer->primary.selected) { XBell(TheDisplay, 0); return; } SetDialogFPromptHistory(cmdHistory, nHistoryCmds); resp = DialogF(DF_PROMPT, window->shell, 2, "Filter Selection", "Shell command: (use up arrow key to recall previous)", cmdText, "OK", "Cancel"); if (resp == 2) return; AddToHistoryList(cmdText, &cmdHistory, &nHistoryCmds); params[0] = cmdText; XtCallActionProc(w, "filter_selection", event, params, 1); } static void shellFilterAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; if (*nArgs == 0) { fprintf(stderr, "nedit: filter_selection requires shell command argument\n"); return; } FilterSelection(window, args[0], event->xany.send_event == MACRO_EVENT_MARKER); } static void execDialogAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); char *params[1], cmdText[DF_MAX_PROMPT_LENGTH]; int resp; static char **cmdHistory = NULL; static int nHistoryCmds = 0; if (CheckReadOnly(window)) return; SetDialogFPromptHistory(cmdHistory, nHistoryCmds); resp = DialogF(DF_PROMPT, window->shell, 2, "Execute Command", "Shell command: (use up arrow key to recall previous;\n" "%% expands to current filename, # to line number)", cmdText, "OK", "Cancel"); if (resp == 2) return; AddToHistoryList(cmdText, &cmdHistory, &nHistoryCmds); params[0] = cmdText; XtCallActionProc(w, "execute_command", event, params, 1);; } static void execAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; if (*nArgs == 0) { fprintf(stderr, "nedit: execute_command requires shell command argument\n"); return; } ExecShellCommand(window, args[0], event->xany.send_event == MACRO_EVENT_MARKER); } static void execLineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (CheckReadOnly(window)) return; ExecCursorLine(window, event->xany.send_event == MACRO_EVENT_MARKER); } static void shellMenuAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { if (*nArgs == 0) { fprintf(stderr, "nedit: shell_menu_command requires item-name argument\n"); return; } HidePointerOnKeyedEvent(w, event); DoNamedShellMenuCmd(WidgetToWindow(w), args[0], event->xany.send_event == MACRO_EVENT_MARKER); } #endif static void macroMenuAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { if (*nArgs == 0) { fprintf(stderr, "nedit: macro_menu_command requires item-name argument\n"); return; } /* Don't allow users to execute a macro command from the menu (or accel) if there's already a macro command executing, UNLESS the macro is directly called from another one. NEdit can't handle running multiple, independent uncoordinated, macros in the same window. Macros may invoke macro menu commands recursively via the macro_menu_command action proc, which is important for being able to repeat any operation, and to embed macros within eachother at any level, however, a call here with a macro running means that THE USER is explicitly invoking another macro via the menu or an accelerator, UNLESS the macro event marker is set */ if (event->xany.send_event != MACRO_EVENT_MARKER) { if (WidgetToWindow(w)->macroCmdData != NULL) { XBell(TheDisplay, 0); return; } } HidePointerOnKeyedEvent(w, event); DoNamedMacroMenuCmd(WidgetToWindow(w), args[0]); } static void bgMenuAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { if (*nArgs == 0) { fprintf(stderr, "nedit: bg_menu_command requires item-name argument\n"); return; } /* Same remark as for macro menu commands (see above). */ if (event->xany.send_event != MACRO_EVENT_MARKER) { if (WidgetToWindow(w)->macroCmdData != NULL) { XBell(TheDisplay, 0); return; } } HidePointerOnKeyedEvent(w, event); DoNamedBGMenuCmd(WidgetToWindow(w), args[0]); } static void beginningOfSelectionAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textBuffer *buf = TextGetBuffer(w); int start, end, isRect, rectStart, rectEnd; if (!BufGetSelectionPos(buf, &start, &end, &isRect, &rectStart, &rectEnd)) return; if (!isRect) TextSetCursorPos(w, start); else TextSetCursorPos(w, BufCountForwardDispChars(buf, BufStartOfLine(buf, start), rectStart)); } static void endOfSelectionAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textBuffer *buf = TextGetBuffer(w); int start, end, isRect, rectStart, rectEnd; if (!BufGetSelectionPos(buf, &start, &end, &isRect, &rectStart, &rectEnd)) return; if (!isRect) TextSetCursorPos(w, end); else TextSetCursorPos(w, BufCountForwardDispChars(buf, BufStartOfLine(buf, end), rectEnd)); } static void raiseWindowAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); WindowInfo *nextWindow; WindowInfo *tmpWindow; int windowIndex; Boolean focus = GetPrefFocusOnRaise(); if (*nArgs > 0) { if (strcmp(args[0], "last") == 0) { window = WindowList; } else if (strcmp(args[0], "first") == 0) { window = WindowList; if (window != NULL) { nextWindow = window->next; while (nextWindow != NULL) { window = nextWindow; nextWindow = nextWindow->next; } } } else if (strcmp(args[0], "previous") == 0) { tmpWindow = window; window = WindowList; if (window != NULL) { nextWindow = window->next; while (nextWindow != NULL && nextWindow != tmpWindow) { window = nextWindow; nextWindow = nextWindow->next; } if (nextWindow == NULL && tmpWindow != WindowList) { window = NULL; } } } else if (strcmp(args[0], "next") == 0) { if (window != NULL) { window = window->next; if (window == NULL) { window = WindowList; } } } else { if (sscanf(args[0], "%d", &windowIndex) == 1) { if (windowIndex > 0) { for (window = WindowList; window != NULL && windowIndex > 1; --windowIndex) { window = window->next; } } else if (windowIndex < 0) { for (window = WindowList; window != NULL; window = window->next) { ++windowIndex; } if (windowIndex >= 0) { for (window = WindowList; window != NULL && windowIndex > 0; window = window->next) { --windowIndex; } } else { window = NULL; } } else { window = NULL; } } else { window = NULL; } } if (*nArgs > 1) { if (strcmp(args[1], "focus") == 0) { focus = True; } else if (strcmp(args[1], "nofocus") == 0) { focus = False; } } } if (window != NULL) { RaiseFocusDocumentWindow(window, focus); } else { XBell(TheDisplay, 0); } } static void focusPaneAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); Widget newFocusPane = NULL; int paneIndex; if (*nArgs > 0) { if (strcmp(args[0], "first") == 0) { paneIndex = 0; } else if (strcmp(args[0], "last") == 0) { paneIndex = window->nPanes; } else if (strcmp(args[0], "next") == 0) { paneIndex = WidgetToPaneIndex(window, window->lastFocus) + 1; if (paneIndex > window->nPanes) { paneIndex = 0; } } else if (strcmp(args[0], "previous") == 0) { paneIndex = WidgetToPaneIndex(window, window->lastFocus) - 1; if (paneIndex < 0) { paneIndex = window->nPanes; } } else { if (sscanf(args[0], "%d", &paneIndex) == 1) { if (paneIndex > 0) { paneIndex = paneIndex - 1; } else if (paneIndex < 0) { paneIndex = window->nPanes + (paneIndex + 1); } else { paneIndex = -1; } } } if (paneIndex >= 0 && paneIndex <= window->nPanes) { newFocusPane = GetPaneByIndex(window, paneIndex); } if (newFocusPane != NULL) { window->lastFocus = newFocusPane; XmProcessTraversal(window->lastFocus, XmTRAVERSE_CURRENT); } else { XBell(TheDisplay, 0); } } else { fprintf(stderr, "nedit: focus_pane requires argument\n"); } } #define ACTION_BOOL_PARAM_OR_TOGGLE(newState, numArgs, argvVal, oValue, actionName) \ if ((numArgs) > 0) { \ int intState; \ \ if (sscanf(argvVal[0], "%d", &intState) == 1) { \ (newState) = (intState != 0); \ } \ else { \ fprintf(stderr, "nedit: %s requires 0 or 1 argument\n", actionName); \ return; \ } \ } \ else { \ (newState) = !(oValue); \ } static void setStatisticsLineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); Boolean newState; /* stats line is a shell-level item, so we toggle the button state regardless of it's 'topness' */ ACTION_BOOL_PARAM_OR_TOGGLE(newState, *nArgs, args, window->showStats, "set_statistics_line"); XmToggleButtonSetState(window->statsLineItem, newState, False); ShowStatsLine(window, newState); } static void setIncrementalSearchLineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); Boolean newState; /* i-search line is a shell-level item, so we toggle the button state regardless of it's 'topness' */ ACTION_BOOL_PARAM_OR_TOGGLE(newState, *nArgs, args, window->showISearchLine, "set_incremental_search_line"); XmToggleButtonSetState(window->iSearchLineItem, newState, False); ShowISearchLine(window, newState); } static void setShowLineNumbersAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); Boolean newState; /* line numbers panel is a shell-level item, so we toggle the button state regardless of it's 'topness' */ ACTION_BOOL_PARAM_OR_TOGGLE(newState, *nArgs, args, window->showLineNumbers, "set_show_line_numbers"); XmToggleButtonSetState(window->lineNumsItem, newState, False); ShowLineNumbers(window, newState); } static void setAutoIndentAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (*nArgs > 0) { if (strcmp(args[0], "off") == 0) { SetAutoIndent(window, NO_AUTO_INDENT); } else if (strcmp(args[0], "on") == 0) { SetAutoIndent(window, AUTO_INDENT); } else if (strcmp(args[0], "smart") == 0) { SetAutoIndent(window, SMART_INDENT); } else { fprintf(stderr, "nedit: set_auto_indent invalid argument\n"); } } else { fprintf(stderr, "nedit: set_auto_indent requires argument\n"); } } static void setWrapTextAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (*nArgs > 0) { if (strcmp(args[0], "none") == 0) { SetAutoWrap(window, NO_WRAP); } else if (strcmp(args[0], "auto") == 0) { SetAutoWrap(window, NEWLINE_WRAP); } else if (strcmp(args[0], "continuous") == 0) { SetAutoWrap(window, CONTINUOUS_WRAP); } else { fprintf(stderr, "nedit: set_wrap_text invalid argument\n"); } } else { fprintf(stderr, "nedit: set_wrap_text requires argument\n"); } } static void setWrapMarginAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (*nArgs > 0) { int newMargin = 0; if (sscanf(args[0], "%d", &newMargin) == 1 && newMargin >= 0 && newMargin < 1000) { int i; XtVaSetValues(window->textArea, textNwrapMargin, newMargin, NULL); for (i = 0; i < window->nPanes; ++i) { XtVaSetValues(window->textPanes[i], textNwrapMargin, newMargin, NULL); } } else { fprintf(stderr, "nedit: set_wrap_margin requires integer argument >= 0 and < 1000\n"); } } else { fprintf(stderr, "nedit: set_wrap_margin requires argument\n"); } } static void setHighlightSyntaxAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); Boolean newState; ACTION_BOOL_PARAM_OR_TOGGLE(newState, *nArgs, args, window->highlightSyntax, "set_highlight_syntax"); if (IsTopDocument(window)) XmToggleButtonSetState(window->highlightItem, newState, False); window->highlightSyntax = newState; if (window->highlightSyntax) { StartHighlighting(window, True); } else { StopHighlighting(window); } } static void setMakeBackupCopyAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); Boolean newState; ACTION_BOOL_PARAM_OR_TOGGLE(newState, *nArgs, args, window->saveOldVersion, "set_make_backup_copy"); #ifndef VMS if (IsTopDocument(window)) XmToggleButtonSetState(window->saveLastItem, newState, False); #endif window->saveOldVersion = newState; } static void setIncrementalBackupAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); Boolean newState; ACTION_BOOL_PARAM_OR_TOGGLE(newState, *nArgs, args, window->autoSave, "set_incremental_backup"); if (IsTopDocument(window)) XmToggleButtonSetState(window->autoSaveItem, newState, False); window->autoSave = newState; } static void setShowMatchingAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (*nArgs > 0) { if (strcmp(args[0], NO_FLASH_STRING) == 0) { SetShowMatching(window, NO_FLASH); } else if (strcmp(args[0], FLASH_DELIMIT_STRING) == 0) { SetShowMatching(window, FLASH_DELIMIT); } else if (strcmp(args[0], FLASH_RANGE_STRING) == 0) { SetShowMatching(window, FLASH_RANGE); } /* For backward compatibility with pre-5.2 versions, we also accept 0 and 1 as aliases for NO_FLASH and FLASH_DELIMIT. It is quite unlikely, though, that anyone ever used this action procedure via the macro language or a key binding, so this can probably be left out safely. */ else if (strcmp(args[0], "0") == 0) { SetShowMatching(window, NO_FLASH); } else if (strcmp(args[0], "1") == 0) { SetShowMatching(window, FLASH_DELIMIT); } else { fprintf(stderr, "nedit: Invalid argument for set_show_matching\n"); } } else { fprintf(stderr, "nedit: set_show_matching requires argument\n"); } } static void setMatchSyntaxBasedAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); Boolean newState; ACTION_BOOL_PARAM_OR_TOGGLE(newState, *nArgs, args, window->matchSyntaxBased, "set_match_syntax_based"); if (IsTopDocument(window)) XmToggleButtonSetState(window->matchSyntaxBasedItem, newState, False); window->matchSyntaxBased = newState; } static void setOvertypeModeAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); Boolean newState; if (window == NULL) return; ACTION_BOOL_PARAM_OR_TOGGLE(newState, *nArgs, args, window->overstrike, "set_overtype_mode"); if (IsTopDocument(window)) XmToggleButtonSetState(window->overtypeModeItem, newState, False); SetOverstrike(window, newState); } static void setLockedAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); Boolean newState; ACTION_BOOL_PARAM_OR_TOGGLE(newState, *nArgs, args, IS_USER_LOCKED(window->lockReasons), "set_locked"); SET_USER_LOCKED(window->lockReasons, newState); if (IsTopDocument(window)) XmToggleButtonSetState(window->readOnlyItem, IS_ANY_LOCKED(window->lockReasons), False); UpdateWindowTitle(window); UpdateWindowReadOnly(window); } static void setTabDistAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (*nArgs > 0) { int newTabDist = 0; if (sscanf(args[0], "%d", &newTabDist) == 1 && newTabDist > 0 && newTabDist <= MAX_EXP_CHAR_LEN) { SetTabDist(window, newTabDist); } else { fprintf(stderr, "nedit: set_tab_dist requires integer argument > 0 and <= %d\n", MAX_EXP_CHAR_LEN); } } else { fprintf(stderr, "nedit: set_tab_dist requires argument\n"); } } static void setEmTabDistAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (*nArgs > 0) { int newEmTabDist = 0; if (sscanf(args[0], "%d", &newEmTabDist) == 1 && newEmTabDist < 1000) { if (newEmTabDist < 0) { newEmTabDist = 0; } SetEmTabDist(window, newEmTabDist); } else { fprintf(stderr, "nedit: set_em_tab_dist requires integer argument >= -1 and < 1000\n"); } } else { fprintf(stderr, "nedit: set_em_tab_dist requires integer argument\n"); } } static void setUseTabsAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); Boolean newState; ACTION_BOOL_PARAM_OR_TOGGLE(newState, *nArgs, args, window->buffer->useTabs, "set_use_tabs"); window->buffer->useTabs = newState; } static void setFontsAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (*nArgs >= 4) { SetFonts(window, args[0], args[1], args[2], args[3]); } else { fprintf(stderr, "nedit: set_fonts requires 4 arguments\n"); } } static void setLanguageModeAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); if (*nArgs > 0) { SetLanguageMode(window, FindLanguageMode(args[0]), FALSE); } else { fprintf(stderr, "nedit: set_language_mode requires argument\n"); } } /* ** Same as AddSubMenu from libNUtil.a but 1) mnemonic is optional (NEdit ** users like to be able to re-arrange the mnemonics so they can set Alt ** key combinations as accelerators), 2) supports the short/full option ** of SGI_CUSTOM mode, 3) optionally returns the cascade button widget ** in "cascadeBtn" if "cascadeBtn" is non-NULL. */ static Widget createMenu(Widget parent, char *name, char *label, char mnemonic, Widget *cascadeBtn, int mode) { Widget menu, cascade; XmString st1; menu = CreatePulldownMenu(parent, name, NULL, 0); cascade = XtVaCreateWidget(name, xmCascadeButtonWidgetClass, parent, XmNlabelString, st1=XmStringCreateSimple(label), XmNsubMenuId, menu, NULL); XmStringFree(st1); if (mnemonic != 0) XtVaSetValues(cascade, XmNmnemonic, mnemonic, NULL); #ifdef SGI_CUSTOM if (mode == SHORT || !GetPrefShortMenus()) XtManageChild(cascade); if (mode == FULL) addToToggleShortList(cascade); #else XtManageChild(cascade); #endif if (cascadeBtn != NULL) *cascadeBtn = cascade; return menu; } /* ** Same as AddMenuItem from libNUtil.a without setting the accelerator ** (these are set in the fallback app-defaults so users can change them), ** and with the short/full option required in SGI_CUSTOM mode. */ static Widget createMenuItem(Widget parent, char *name, char *label, char mnemonic, menuCallbackProc callback, void *cbArg, int mode) { Widget button; XmString st1; button = XtVaCreateWidget(name, xmPushButtonWidgetClass, parent, XmNlabelString, st1=XmStringCreateSimple(label), XmNmnemonic, mnemonic, NULL); XtAddCallback(button, XmNactivateCallback, (XtCallbackProc)callback, cbArg); XmStringFree(st1); #ifdef SGI_CUSTOM if (mode == SHORT || !GetPrefShortMenus()) XtManageChild(button); if (mode == FULL) addToToggleShortList(button); XtVaSetValues(button, XmNuserData, PERMANENT_MENU_ITEM, NULL); #else XtManageChild(button); #endif return button; } /* ** "fake" menu items allow accelerators to be attached, but don't show up ** in the menu. They are necessary to process the shifted menu items because ** Motif does not properly process the event descriptions in accelerator ** resources, and you can't specify "shift key is optional" */ static Widget createFakeMenuItem(Widget parent, char *name, menuCallbackProc callback, void *cbArg) { Widget button; XmString st1; button = XtVaCreateManagedWidget(name, xmPushButtonWidgetClass, parent, XmNlabelString, st1=XmStringCreateSimple(""), XmNshadowThickness, 0, XmNmarginHeight, 0, XmNheight, 0, NULL); XtAddCallback(button, XmNactivateCallback, (XtCallbackProc)callback, cbArg); XmStringFree(st1); XtVaSetValues(button, XmNtraversalOn, False, NULL); return button; } /* ** Add a toggle button item to an already established pull-down or pop-up ** menu, including mnemonics, accelerators and callbacks. */ static Widget createMenuToggle(Widget parent, char *name, char *label, char mnemonic, menuCallbackProc callback, void *cbArg, int set, int mode) { Widget button; XmString st1; button = XtVaCreateWidget(name, xmToggleButtonWidgetClass, parent, XmNlabelString, st1=XmStringCreateSimple(label), XmNmnemonic, mnemonic, XmNset, set, NULL); XtAddCallback(button, XmNvalueChangedCallback, (XtCallbackProc)callback, cbArg); XmStringFree(st1); #ifdef SGI_CUSTOM if (mode == SHORT || !GetPrefShortMenus()) XtManageChild(button); if (mode == FULL) addToToggleShortList(button); XtVaSetValues(button, XmNuserData, PERMANENT_MENU_ITEM, NULL); #else XtManageChild(button); #endif return button; } /* ** Create a toggle button with a diamond (radio-style) appearance */ static Widget createMenuRadioToggle(Widget parent, char *name, char *label, char mnemonic, menuCallbackProc callback, void *cbArg, int set, int mode) { Widget button; button = createMenuToggle(parent, name, label, mnemonic, callback, cbArg, set, mode); XtVaSetValues(button, XmNindicatorType, XmONE_OF_MANY, NULL); return button; } static Widget createMenuSeparator(Widget parent, char *name, int mode) { Widget button; button = XmCreateSeparator(parent, name, NULL, 0); #ifdef SGI_CUSTOM if (mode == SHORT || !GetPrefShortMenus()) XtManageChild(button); if (mode == FULL) addToToggleShortList(button); XtVaSetValues(button, XmNuserData, PERMANENT_MENU_ITEM, NULL); #else XtManageChild(button); #endif return button; } /* ** Make sure the close menu item is dimmed appropriately for the current ** set of windows. It should be dim only for the last Untitled, unmodified, ** editor window, and sensitive otherwise. */ void CheckCloseDim(void) { WindowInfo *window; if (WindowList == NULL) return; if (WindowList->next==NULL && !WindowList->filenameSet && !WindowList->fileChanged) { XtSetSensitive(WindowList->closeItem, FALSE); return; } for (window=WindowList; window!=NULL; window=window->next) { if (!IsTopDocument(window)) continue; XtSetSensitive(window->closeItem, True); } } /* ** Invalidate the Window menus of all NEdit windows to but don't change ** the menus until they're needed (Originally, this was "UpdateWindowMenus", ** but creating and destroying manu items for every window every time a ** new window was created or something changed, made things move very ** slowly with more than 10 or so windows). */ void InvalidateWindowMenus(void) { WindowInfo *w; /* Mark the window menus invalid (to be updated when the user pulls one down), unless the menu is torn off, meaning it is visible to the user and should be updated immediately */ for (w=WindowList; w!=NULL; w=w->next) { if (!XmIsMenuShell(XtParent(w->windowMenuPane))) updateWindowMenu(w); else w->windowMenuValid = False; } } /* ** Mark the Previously Opened Files menus of all NEdit windows as invalid. ** Since actually changing the menus is slow, they're just marked and updated ** when the user pulls one down. */ static void invalidatePrevOpenMenus(void) { WindowInfo *w; /* Mark the menus invalid (to be updated when the user pulls one down), unless the menu is torn off, meaning it is visible to the user and should be updated immediately */ for (w=WindowList; w!=NULL; w=w->next) { if (!XmIsMenuShell(XtParent(w->prevOpenMenuPane))) updatePrevOpenMenu(w); } } /* ** Add a file to the list of previously opened files for display in the ** File menu. */ void AddToPrevOpenMenu(const char *filename) { int i; char *nameCopy; WindowInfo *w; /* If the Open Previous command is disabled, just return */ if (GetPrefMaxPrevOpenFiles() < 1) { return; } /* Refresh list of previously opened files to avoid Big Race Condition, where two sessions overwrite each other's changes in NEdit's history file. Of course there is still Little Race Condition, which occurs if a Session A reads the list, then Session B reads the list and writes it before Session A gets a chance to write. */ ReadNEditDB(); /* If the name is already in the list, move it to the start */ for (i=0; i= GetPrefMaxPrevOpenFiles()) { /* This is only safe if GetPrefMaxPrevOpenFiles() > 0. */ XtFree(PrevOpen[--NPrevOpen]); } /* Add it to the list */ nameCopy = XtMalloc(strlen(filename) + 1); strcpy(nameCopy, filename); memmove(&PrevOpen[1], &PrevOpen[0], sizeof(char *) * NPrevOpen); PrevOpen[0] = nameCopy; NPrevOpen++; /* Mark the Previously Opened Files menu as invalid in all windows */ invalidatePrevOpenMenus(); /* Undim the menu in all windows if it was previously empty */ if (NPrevOpen > 0) { for (w=WindowList; w!=NULL; w=w->next) { if (!IsTopDocument(w)) continue; XtSetSensitive(w->prevOpenMenuItem, True); } } /* Write the menu contents to disk to restore in later sessions */ WriteNEditDB(); } static char* getWindowsMenuEntry(const WindowInfo* window) { static char fullTitle[MAXPATHLEN * 2 + 3+ 1]; sprintf(fullTitle, "%s%s", window->filename, window->fileChanged? "*" : ""); if (GetPrefShowPathInWindowsMenu() && window->filenameSet) { strcat(fullTitle, " - "); strcat(fullTitle, window->path); } return(fullTitle); } /* ** Update the Window menu of a single window to reflect the current state of ** all NEdit windows as determined by the global WindowList. */ static void updateWindowMenu(const WindowInfo *window) { WindowInfo *w; WidgetList items; Cardinal nItems; int i, n, nWindows, windowIndex; WindowInfo **windows; if (!IsTopDocument(window)) return; /* Make a sorted list of windows */ for (w=WindowList, nWindows=0; w!=NULL; w=w->next, nWindows++); windows = (WindowInfo **)XtMalloc(sizeof(WindowInfo *) * nWindows); for (w=WindowList, i=0; w!=NULL; w=w->next, i++) windows[i] = w; qsort(windows, nWindows, sizeof(WindowInfo *), compareWindowNames); /* if the menu is torn off, unmanage the menu pane before updating it to prevent the tear-off menu from shrinking/expanding as the menu entries are added */ if (!XmIsMenuShell(XtParent(window->windowMenuPane))) XtUnmanageChild(window->windowMenuPane); /* While it is not possible on some systems (ibm at least) to substitute a new menu pane, it is possible to substitute menu items, as long as at least one remains in the menu at all times. This routine assumes that the menu contains permanent items marked with the value PERMANENT_MENU_ITEM in the userData resource, and adds and removes items which it marks with the value TEMPORARY_MENU_ITEM */ /* Go thru all of the items in the menu and rename them to match the window list. Delete any extras */ XtVaGetValues(window->windowMenuPane, XmNchildren, &items, XmNnumChildren, &nItems, NULL); windowIndex = 0; nWindows = NWindows(); for (n=0; n<(int)nItems; n++) { XtPointer userData; XtVaGetValues(items[n], XmNuserData, &userData, NULL); if (userData == TEMPORARY_MENU_ITEM) { if (windowIndex >= nWindows) { /* unmanaging before destroying stops parent from displaying */ XtUnmanageChild(items[n]); XtDestroyWidget(items[n]); } else { XmString st1; char* title = getWindowsMenuEntry(windows[windowIndex]); XtVaSetValues(items[n], XmNlabelString, st1=XmStringCreateSimple(title), NULL); XtRemoveAllCallbacks(items[n], XmNactivateCallback); XtAddCallback(items[n], XmNactivateCallback, (XtCallbackProc)raiseCB, windows[windowIndex]); XmStringFree(st1); windowIndex++; } } } /* Add new items for the titles of the remaining windows to the menu */ for (; windowIndexwindowMenuPane, XmNlabelString, st1=XmStringCreateSimple(title), XmNmarginHeight, 0, XmNuserData, TEMPORARY_MENU_ITEM, NULL); XtAddCallback(btn, XmNactivateCallback, (XtCallbackProc)raiseCB, windows[windowIndex]); XmStringFree(st1); } XtFree((char *)windows); /* if the menu is torn off, we need to manually adjust the dimension of the menuShell _before_ re-managing the menu pane, to either expose the hidden menu entries or remove the empty space */ if (!XmIsMenuShell(XtParent(window->windowMenuPane))) { Dimension width, height; XtVaGetValues(window->windowMenuPane, XmNwidth, &width, XmNheight, &height, NULL); XtVaSetValues(XtParent(window->windowMenuPane), XmNwidth, width, XmNheight, height, NULL); XtManageChild(window->windowMenuPane); } } /* ** Update the Previously Opened Files menu of a single window to reflect the ** current state of the list as retrieved from FIXME. ** Thanks to Markus Schwarzenberg for the sorting part. */ static void updatePrevOpenMenu(WindowInfo *window) { Widget btn; WidgetList items; Cardinal nItems; int n, index; XmString st1; char **prevOpenSorted; /* Read history file to get entries written by other sessions. */ ReadNEditDB(); /* Sort the previously opened file list if requested */ prevOpenSorted = (char **)XtMalloc(NPrevOpen * sizeof(char*)); memcpy(prevOpenSorted, PrevOpen, NPrevOpen * sizeof(char*)); if (GetPrefSortOpenPrevMenu()) qsort(prevOpenSorted, NPrevOpen, sizeof(char*), cmpStrPtr); /* Go thru all of the items in the menu and rename them to match the file list. In older Motifs (particularly ibm), it was dangerous to replace a whole menu pane, which would be much simpler. However, since the code was already written for the Windows menu and is well tested, I'll stick with this weird method of re-naming the items */ XtVaGetValues(window->prevOpenMenuPane, XmNchildren, &items, XmNnumChildren, &nItems, NULL); index = 0; for (n=0; n<(int)nItems; n++) { if (index >= NPrevOpen) { /* unmanaging before destroying stops parent from displaying */ XtUnmanageChild(items[n]); XtDestroyWidget(items[n]); } else { XtVaSetValues(items[n], XmNlabelString, st1=XmStringCreateSimple(prevOpenSorted[index]), NULL); XtRemoveAllCallbacks(items[n], XmNactivateCallback); XtAddCallback(items[n], XmNactivateCallback, (XtCallbackProc)openPrevCB, prevOpenSorted[index]); XmStringFree(st1); index++; } } /* Add new items for the remaining file names to the menu */ for (; indexprevOpenMenuPane, XmNlabelString, st1=XmStringCreateSimple(prevOpenSorted[index]), XmNmarginHeight, 0, XmNuserData, TEMPORARY_MENU_ITEM, NULL); XtAddCallback(btn, XmNactivateCallback, (XtCallbackProc)openPrevCB, prevOpenSorted[index]); XmStringFree(st1); } XtFree((char*)prevOpenSorted); } /* ** This function manages the display of the Tags File Menu, which is displayed ** when the user selects Un-load Tags File. */ static void updateTagsFileMenu(WindowInfo *window) { tagFile *tf; Widget btn; WidgetList items; Cardinal nItems; int n; XmString st1; /* Go thru all of the items in the menu and rename them to match the file list. In older Motifs (particularly ibm), it was dangerous to replace a whole menu pane, which would be much simpler. However, since the code was already written for the Windows menu and is well tested, I'll stick with this weird method of re-naming the items */ XtVaGetValues(window->unloadTagsMenuPane, XmNchildren, &items, XmNnumChildren, &nItems, NULL); tf = TagsFileList; for (n=0; n<(int)nItems; n++) { if (!tf) { /* unmanaging before destroying stops parent from displaying */ XtUnmanageChild(items[n]); XtDestroyWidget(items[n]); } else { XtVaSetValues(items[n], XmNlabelString, st1=XmStringCreateSimple(tf->filename), NULL); XtRemoveAllCallbacks(items[n], XmNactivateCallback); XtAddCallback(items[n], XmNactivateCallback, (XtCallbackProc)unloadTagsFileCB, tf->filename); XmStringFree(st1); tf = tf->next; } } /* Add new items for the remaining file names to the menu */ while (tf) { btn = XtVaCreateManagedWidget("win", xmPushButtonWidgetClass, window->unloadTagsMenuPane, XmNlabelString, st1=XmStringCreateSimple(tf->filename),XmNmarginHeight, 0, XmNuserData, TEMPORARY_MENU_ITEM, NULL); XtAddCallback(btn, XmNactivateCallback, (XtCallbackProc)unloadTagsFileCB, tf->filename); XmStringFree(st1); tf = tf->next; } } /* ** This function manages the display of the Tips File Menu, which is displayed ** when the user selects Un-load Calltips File. */ static void updateTipsFileMenu(WindowInfo *window) { tagFile *tf; Widget btn; WidgetList items; Cardinal nItems; int n; XmString st1; /* Go thru all of the items in the menu and rename them to match the file list. In older Motifs (particularly ibm), it was dangerous to replace a whole menu pane, which would be much simpler. However, since the code was already written for the Windows menu and is well tested, I'll stick with this weird method of re-naming the items */ XtVaGetValues(window->unloadTipsMenuPane, XmNchildren, &items, XmNnumChildren, &nItems, NULL); tf = TipsFileList; for (n=0; n<(int)nItems; n++) { if (!tf) { /* unmanaging before destroying stops parent from displaying */ XtUnmanageChild(items[n]); XtDestroyWidget(items[n]); } else { XtVaSetValues(items[n], XmNlabelString, st1=XmStringCreateSimple(tf->filename), NULL); XtRemoveAllCallbacks(items[n], XmNactivateCallback); XtAddCallback(items[n], XmNactivateCallback, (XtCallbackProc)unloadTipsFileCB, tf->filename); XmStringFree(st1); tf = tf->next; } } /* Add new items for the remaining file names to the menu */ while (tf) { btn = XtVaCreateManagedWidget("win", xmPushButtonWidgetClass, window->unloadTipsMenuPane, XmNlabelString, st1=XmStringCreateSimple(tf->filename),XmNmarginHeight, 0, XmNuserData, TEMPORARY_MENU_ITEM, NULL); XtAddCallback(btn, XmNactivateCallback, (XtCallbackProc)unloadTipsFileCB, tf->filename); XmStringFree(st1); tf = tf->next; } } /* ** Comparison function for sorting file names for the Open Previous submenu */ static int cmpStrPtr(const void *strA, const void *strB) { return strcmp(*((char**)strA), *((char**)strB)); } #ifdef VMS static char neditDBBadFilenameChars[] = "\n\t*?(){}!@#%&' "; #else static char neditDBBadFilenameChars[] = "\n"; #endif /* ** Write dynamic database of file names for "Open Previous". Eventually, ** this may hold window positions, and possibly file marks, in which case, ** it should be moved to a different module, but for now it's just a list ** of previously opened files. */ void WriteNEditDB(void) { const char* fullName = GetRCFileName(NEDIT_HISTORY); FILE *fp; int i; static char fileHeader[] = "# File name database for NEdit Open Previous command\n"; if (fullName == NULL) { /* GetRCFileName() might return NULL if an error occurs during creation of the preference file directory. */ return; } /* If the Open Previous command is disabled, just return */ if (GetPrefMaxPrevOpenFiles() < 1) { return; } /* open the file */ if ((fp = fopen(fullName, "w")) == NULL) { #ifdef VMS /* When the version number, ";1" is specified as part of the file name, fopen(fullName, "w"), will only open for writing if the file does not exist. Using, fopen(fullName, "r+"), opens an existing file for "update" - read/write pointer is placed at the beginning of file. By calling ftruncate(), we discard the old contents and avoid trailing garbage in the file if the new contents is shorter. */ if ((fp = fopen(fullName, "r+")) == NULL) { return; } if (ftruncate(fileno(fp), 0) != 0) { fclose(fp); return; } #else return; #endif } /* write the file header text to the file */ fprintf(fp, "%s", fileHeader); /* Write the list of file names */ for (i = 0; i < NPrevOpen; ++i) { size_t lineLen = strlen(PrevOpen[i]); if (lineLen > 0 && PrevOpen[i][0] != '#' && strcspn(PrevOpen[i], neditDBBadFilenameChars) == lineLen) { fprintf(fp, "%s\n", PrevOpen[i]); } } fclose(fp); } /* ** Read database of file names for 'Open Previous' submenu. ** ** Eventually, this may hold window positions, and possibly file marks (in ** which case it should be moved to a different module) but for now it's ** just a list of previously opened files. ** ** This list is read once at startup and potentially refreshed before a ** new entry is about to be written to the file or before the menu is ** displayed. If the file is modified since the last read (or not read ** before), it is read in, otherwise nothing is done. */ void ReadNEditDB(void) { const char *fullName = GetRCFileName(NEDIT_HISTORY); char line[MAXPATHLEN + 2]; char *nameCopy; struct stat attribute; FILE *fp; size_t lineLen; static time_t lastNeditdbModTime = 0; /* If the Open Previous command is disabled or the user set the resource to an (invalid) negative value, just return. */ if (GetPrefMaxPrevOpenFiles() < 1) { return; } /* Initialize the files list and allocate a (permanent) block memory of the size prescribed by the maxPrevOpenFiles resource */ if (!PrevOpen) { PrevOpen = (char**) XtMalloc(sizeof(char*) * GetPrefMaxPrevOpenFiles()); NPrevOpen = 0; } /* Don't move this check ahead of the previous statements. PrevOpen must be initialized at all times. */ if (fullName == NULL) { /* GetRCFileName() might return NULL if an error occurs during creation of the preference file directory. */ return; } /* Stat history file to see whether someone touched it after this session last changed it. */ if (0 == stat(fullName, &attribute)) { if (lastNeditdbModTime >= attribute.st_mtime) { /* Do nothing, history file is unchanged. */ return; } else { /* Memorize modtime to compare to next time. */ lastNeditdbModTime = attribute.st_mtime; } } else { /* stat() failed, probably for non-exiting history database. */ if (ENOENT != errno) { perror("nedit: Error reading history database"); } return; } /* open the file */ if ((fp = fopen(fullName, "r")) == NULL) { return; } /* Clear previous list. */ while (0 != NPrevOpen) { XtFree(PrevOpen[--NPrevOpen]); } /* read lines of the file, lines beginning with # are considered to be comments and are thrown away. Lines are subject to cursory checking, then just copied to the Open Previous file menu list */ while (True) { if (fgets(line, sizeof(line), fp) == NULL) { /* end of file */ fclose(fp); return; } if (line[0] == '#') { /* comment */ continue; } lineLen = strlen(line); if (lineLen == 0) { /* blank line */ continue; } if (line[lineLen - 1] != '\n') { /* no newline, probably truncated */ fprintf(stderr, "nedit: Line too long in history file\n"); while (fgets(line, sizeof(line), fp) != NULL) { lineLen = strlen(line); if (lineLen > 0 && line[lineLen - 1] == '\n') { break; } } continue; } line[--lineLen] = '\0'; if (strcspn(line, neditDBBadFilenameChars) != lineLen) { /* non-filename characters */ fprintf(stderr, "nedit: History file may be corrupted\n"); continue; } nameCopy = XtMalloc(lineLen + 1); strcpy(nameCopy, line); PrevOpen[NPrevOpen++] = nameCopy; if (NPrevOpen >= GetPrefMaxPrevOpenFiles()) { /* too many entries */ fclose(fp); return; } } } static void setWindowSizeDefault(int rows, int cols) { SetPrefRows(rows); SetPrefCols(cols); updateWindowSizeMenus(); } static void updateWindowSizeMenus(void) { WindowInfo *win; for (win=WindowList; win!=NULL; win=win->next) updateWindowSizeMenu(win); } static void updateWindowSizeMenu(WindowInfo *win) { int rows = GetPrefRows(), cols = GetPrefCols(); char title[50]; XmString st1; if (!IsTopDocument(win)) return; XmToggleButtonSetState(win->size24x80DefItem, rows==24&&cols==80,False); XmToggleButtonSetState(win->size40x80DefItem, rows==40&&cols==80,False); XmToggleButtonSetState(win->size60x80DefItem, rows==60&&cols==80,False); XmToggleButtonSetState(win->size80x80DefItem, rows==80&&cols==80,False); if ((rows!=24 && rows!=40 && rows!=60 && rows!=80) || cols!=80) { XmToggleButtonSetState(win->sizeCustomDefItem, True, False); sprintf(title, "Custom... (%d x %d)", rows, cols); XtVaSetValues(win->sizeCustomDefItem, XmNlabelString, st1=XmStringCreateSimple(title), NULL); XmStringFree(st1); } else { XmToggleButtonSetState(win->sizeCustomDefItem, False, False); XtVaSetValues(win->sizeCustomDefItem, XmNlabelString, st1=XmStringCreateSimple("Custom..."), NULL); XmStringFree(st1); } } /* ** Scans action argument list for arguments "forward" or "backward" to ** determine search direction for search and replace actions. "ignoreArgs" ** tells the routine how many required arguments there are to ignore before ** looking for keywords */ static int searchDirection(int ignoreArgs, String *args, Cardinal *nArgs) { int i; for (i=ignoreArgs; i<(int)*nArgs; i++) { if (!strCaseCmp(args[i], "forward")) return SEARCH_FORWARD; if (!strCaseCmp(args[i], "backward")) return SEARCH_BACKWARD; } return SEARCH_FORWARD; } /* ** Scans action argument list for arguments "keep" or "nokeep" to ** determine whether to keep dialogs up for search and replace. "ignoreArgs" ** tells the routine how many required arguments there are to ignore before ** looking for keywords */ static int searchKeepDialogs(int ignoreArgs, String *args, Cardinal *nArgs) { int i; for (i=ignoreArgs; i<(int)*nArgs; i++) { if (!strCaseCmp(args[i], "keep")) return TRUE; if (!strCaseCmp(args[i], "nokeep")) return FALSE; } return GetPrefKeepSearchDlogs(); } /* ** Scans action argument list for arguments "wrap" or "nowrap" to ** determine search direction for search and replace actions. "ignoreArgs" ** tells the routine how many required arguments there are to ignore before ** looking for keywords */ static int searchWrap(int ignoreArgs, String *args, Cardinal *nArgs) { int i; for (i=ignoreArgs; i<(int)*nArgs; i++) { if (!strCaseCmp(args[i], "wrap")) return(TRUE); if (!strCaseCmp(args[i], "nowrap")) return(FALSE); } return GetPrefSearchWraps(); } /* ** Scans action argument list for arguments "literal", "case" or "regex" to ** determine search type for search and replace actions. "ignoreArgs" ** tells the routine how many required arguments there are to ignore before ** looking for keywords */ static int searchType(int ignoreArgs, String *args, Cardinal *nArgs) { int i, tmpSearchType; for (i=ignoreArgs; i<(int)*nArgs; i++) { if (StringToSearchType(args[i], &tmpSearchType)) return tmpSearchType; } return GetPrefSearch(); } /* ** Return a pointer to the string describing search direction for search action ** routine parameters given a callback XmAnyCallbackStruct pointed to by ** "callData", by checking if the shift key is pressed (for search callbacks). */ static char **shiftKeyToDir(XtPointer callData) { static char *backwardParam[1] = {"backward"}; static char *forwardParam[1] = {"forward"}; if (((XmAnyCallbackStruct *)callData)->event->xbutton.state & ShiftMask) return backwardParam; return forwardParam; } static void raiseCB(Widget w, WindowInfo *window, caddr_t callData) { HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); RaiseFocusDocumentWindow(window, True /* always focus */); } static void openPrevCB(Widget w, char *name, caddr_t callData) { char *params[1]; Widget menu = MENU_WIDGET(w); HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); params[0] = name; XtCallActionProc(WidgetToWindow(menu)->lastFocus, "open", ((XmAnyCallbackStruct *)callData)->event, params, 1); CheckCloseDim(); } static void unloadTagsFileCB(Widget w, char *name, caddr_t callData) { char *params[1]; Widget menu = MENU_WIDGET(w); HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); params[0] = name; XtCallActionProc(WidgetToWindow(menu)->lastFocus, "unload_tags_file", ((XmAnyCallbackStruct *)callData)->event, params, 1); } static void unloadTipsFileCB(Widget w, char *name, caddr_t callData) { char *params[1]; #if XmVersion >= 1002 Widget menu = XmGetPostedFromWidget(XtParent(w)); /* If menu is torn off */ #else Widget menu = w; #endif params[0] = name; XtCallActionProc(WidgetToWindow(menu)->lastFocus, "unload_tips_file", ((XmAnyCallbackStruct *)callData)->event, params, 1); } /* ** strCaseCmp compares its arguments and returns 0 if the two strings ** are equal IGNORING case differences. Otherwise returns 1. */ static int strCaseCmp(const char *str1, const char *str2) { const char *c1, *c2; for (c1=str1, c2=str2; *c1!='\0' && *c2!='\0'; c1++, c2++) if (toupper((unsigned char)*c1) != toupper((unsigned char)*c2)) return 1; if (*c1 == *c2) { return(0); } else { return(1); } } /* ** Comparison function for sorting windows by title for the window menu. ** Windows are sorted by Untitled and then alphabetically by filename and ** then alphabetically by path. */ static int compareWindowNames(const void *windowA, const void *windowB) { int rc; const WindowInfo *a = *((WindowInfo**)windowA); const WindowInfo *b = *((WindowInfo**)windowB); /* Untitled first */ rc = a->filenameSet == b->filenameSet ? 0 : a->filenameSet && !b->filenameSet ? 1 : -1; if (rc != 0) return rc; rc = strcmp(a->filename, b->filename); if (rc != 0) return rc; rc = strcmp(a->path, b->path); return rc; } /* ** Create popup for right button programmable menu */ Widget CreateBGMenu(WindowInfo *window) { Arg args[1]; /* There is still some mystery here. It's important to get the XmNmenuPost resource set to the correct menu button, or the menu will not post properly, but there's also some danger that it will take over the entire button and interfere with text widget translations which use the button with modifiers. I don't entirely understand why it works properly now when it failed often in development, and certainly ignores the ~ syntax in translation event specifications. */ XtSetArg(args[0], XmNmenuPost, GetPrefBGMenuBtn()); return CreatePopupMenu(window->textArea, "bgMenu", args, 1); } /* ** Create context popup menu for tabs & tab bar */ Widget CreateTabContextMenu(Widget parent, WindowInfo *window) { Widget menu; Arg args[8]; int n; n = 0; XtSetArg(args[n], XmNtearOffModel, XmTEAR_OFF_DISABLED); n++; menu = CreatePopupMenu(parent, "tabContext", args, n); createMenuItem(menu, "new", "New Tab", 0, doTabActionCB, "new_tab", SHORT); createMenuItem(menu, "close", "Close Tab", 0, doTabActionCB, "close", SHORT); createMenuSeparator(menu, "sep1", SHORT); window->contextDetachDocumentItem = createMenuItem(menu, "detach", "Detach Tab", 0, doTabActionCB, "detach_document", SHORT); XtSetSensitive(window->contextDetachDocumentItem, False); window->contextMoveDocumentItem = createMenuItem(menu, "attach", "Move Tab To...", 0, doTabActionCB, "move_document_dialog", SHORT); return menu; } /* ** Add a translation to the text widget to trigger the background menu using ** the mouse-button + modifier combination specified in the resource: ** nedit.bgMenuBtn. */ void AddBGMenuAction(Widget widget) { static XtTranslations table = NULL; if (table == NULL) { char translations[MAX_ACCEL_LEN + 25]; sprintf(translations, "%s: post_window_bg_menu()\n",GetPrefBGMenuBtn()); table = XtParseTranslationTable(translations); } XtOverrideTranslations(widget, table); } static void bgMenuPostAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window = WidgetToWindow(w); /* The Motif popup handling code BLOCKS events while the menu is posted, including the matching btn-up events which complete various dragging operations which it may interrupt. Cancel to head off problems */ XtCallActionProc(window->lastFocus, "process_cancel", event, NULL, 0); /* Pop up the menu */ XmMenuPosition(window->bgMenuPane, (XButtonPressedEvent *)event); XtManageChild(window->bgMenuPane); /* These statements have been here for a very long time, but seem unnecessary and are even dangerous: when any of the lock keys are on, Motif thinks it shouldn't display the background menu, but this callback is called anyway. When we then grab the focus and force the menu to be drawn, bad things can happen (like a total lockup of the X server). XtPopup(XtParent(window->bgMenuPane), XtGrabNonexclusive); XtMapWidget(XtParent(window->bgMenuPane)); XtMapWidget(window->bgMenuPane); */ } void AddTabContextMenuAction(Widget widget) { static XtTranslations table = NULL; if (table == NULL) { char *translations = ": post_tab_context_menu()\n"; table = XtParseTranslationTable(translations); } XtOverrideTranslations(widget, table); } /* ** action procedure for posting context menu of tabs */ static void tabMenuPostAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo *window; XButtonPressedEvent *xbutton = (XButtonPressedEvent *)event; Widget wgt; /* Determine if the context menu was called from tabs or gutter, then stored the corresponding window info as userData of the popup menu pane, which will later be extracted by doTabActionCB() to act upon. When the context menu was called from the gutter, the active doc is assumed. Lesstif requires the action [to pupop the menu] to also be to the tabs, else nothing happed when right-click on tabs. Even so, the action procedure sometime appear to be called from the gutter even if users did right-click on the tabs. Here we try to cater for the uncertainty. */ if (XtClass(w) == xrwsBubbleButtonWidgetClass) window = TabToWindow(w); else if (xbutton->subwindow) { wgt = XtWindowToWidget(XtDisplay(w), xbutton->subwindow); window = TabToWindow(wgt); } else { window = WidgetToWindow(w); } XtVaSetValues(window->tabMenuPane, XmNuserData, (XtPointer)window, NULL); /* The Motif popup handling code BLOCKS events while the menu is posted, including the matching btn-up events which complete various dragging operations which it may interrupt. Cancel to head off problems */ XtCallActionProc(window->lastFocus, "process_cancel", event, NULL, 0); /* Pop up the menu */ XmMenuPosition(window->tabMenuPane, (XButtonPressedEvent *)event); XtManageChild(window->tabMenuPane); } /* ** Event handler for restoring the input hint of menu tearoffs ** previously disabled in ShowHiddenTearOff() */ static void tearoffMappedCB(Widget w, XtPointer clientData, XUnmapEvent *event) { Widget shell = (Widget)clientData; XWMHints *wmHints; if (event->type != MapNotify) return; /* restore the input hint previously disabled in ShowHiddenTearOff() */ wmHints = XGetWMHints(TheDisplay, XtWindow(shell)); wmHints->input = True; wmHints->flags |= InputHint; XSetWMHints(TheDisplay, XtWindow(shell), wmHints); XFree(wmHints); /* we only need to do this only */ XtRemoveEventHandler(shell, StructureNotifyMask, False, (XtEventHandler)tearoffMappedCB, shell); } /* ** Redisplay (map) a hidden tearoff */ void ShowHiddenTearOff(Widget menuPane) { Widget shell; if (!menuPane) return; shell = XtParent(menuPane); if (!XmIsMenuShell(shell)) { XWindowAttributes winAttr; XGetWindowAttributes(XtDisplay(shell), XtWindow(shell), &winAttr); if (winAttr.map_state == IsUnmapped) { XWMHints *wmHints; /* to workaround a problem where the remapped tearoffs always receive the input focus insteads of the text editing window, we disable the input hint of the tearoff shell temporarily. */ wmHints = XGetWMHints(XtDisplay(shell), XtWindow(shell)); wmHints->input = False; wmHints->flags |= InputHint; XSetWMHints(XtDisplay(shell), XtWindow(shell), wmHints); XFree(wmHints); /* show the tearoff */ XtMapWidget(shell); /* the input hint will be restored when the tearoff is mapped */ XtAddEventHandler(shell, StructureNotifyMask, False, (XtEventHandler)tearoffMappedCB, shell); } } } #ifdef SGI_CUSTOM static void shortMenusCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; int i, state = XmToggleButtonGetState(w); Widget parent; window = WidgetToWindow(w); HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus, ((XmAnyCallbackStruct *)callData)->event); /* Set the preference */ SetPrefShortMenus(state); /* Re-create the menus for all windows */ for (win=WindowList; win!=NULL; win=win->next) { for (i=0; inToggleShortItems; i++) { if (state) XtUnmanageChild(win->toggleShortItems[i]); else XtManageChild(win->toggleShortItems[i]); } } if (GetPrefShortMenus()) SaveNEditPrefs(window->shell, True); } static void addToToggleShortList(Widget w) { if (ShortMenuWindow->nToggleShortItems >= MAX_SHORTENED_ITEMS) { fprintf(stderr,"nedit, internal error: increase MAX_SHORTENED_ITEMS\n"); return; } ShortMenuWindow->toggleShortItems[ShortMenuWindow->nToggleShortItems++] = w; } /* ** Present the user a dialog for specifying whether or not a short ** menu mode preference should be applied toward the default setting. ** Return True if user requested to reset and save the default value. ** If operation was canceled, will return toggle widget "w" to it's ** original (opposite) state. */ static int shortPrefAskDefault(Widget parent, Widget w, const char *settingName) { char msg[100] = ""; if (!GetPrefShortMenus()) { return False; } sprintf(msg, "%s: %s\nSave as default for future windows as well?", settingName, XmToggleButtonGetState(w) ? "On" : "Off"); switch (DialogF (DF_QUES, parent, 3, "Save Default", msg, "Yes", "No", "Cancel")) { case 1: /* yes */ return True; case 2: /* no */ return False; case 3: /* cancel */ XmToggleButtonSetState(w, !XmToggleButtonGetState(w), False); return False; } return False; /* not reached */ } #endif nedit-5.6.orig/source/menu.h0000644000175000017500000000555110737527367014556 0ustar paulpaul/* $Id: menu.h,v 1.14 2008/01/04 22:11:03 yooden Exp $ */ /******************************************************************************* * * * menu.h -- Nirvana Editor Menu Header File * * * * Copyright 2004 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_MENU_H_INCLUDED #define NEDIT_MENU_H_INCLUDED #include "nedit.h" #include #include #define PERMANENT_MENU_ITEM (XtPointer)1 #define TEMPORARY_MENU_ITEM (XtPointer)2 Widget CreateMenuBar(Widget parent, WindowInfo *window); void InstallMenuActions(XtAppContext context); XtActionsRec *GetMenuActions(int *nActions); void InvalidateWindowMenus(void); void CheckCloseDim(void); void AddToPrevOpenMenu(const char *filename); void WriteNEditDB(void); void ReadNEditDB(void); Widget CreateBGMenu(WindowInfo *window); void AddBGMenuAction(Widget widget); void HidePointerOnKeyedEvent(Widget w, XEvent *event); Widget CreateTabContextMenu(Widget parent, WindowInfo *window); void AddTabContextMenuAction(Widget widget); void ShowHiddenTearOff(Widget menuPane); #endif /* NEDIT_MENU_H_INCLUDED */ nedit-5.6.orig/source/n.bm0000644000175000017500000000204607246564333014205 0ustar paulpaul/* $Id: n.bm,v 1.2 2001/02/26 23:38:03 edg Exp $ */ #define n_width 24 #define n_height 24 static unsigned char n_bits[] = { 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x14, 0xc0, 0x5a, 0xab, 0xf5, 0xb4, 0x56, 0xfb, 0x4a, 0xad, 0xbc, 0x94, 0x52, 0xd9, 0x4a, 0xad, 0xbc, 0x94, 0x5a, 0xd9, 0xca, 0xb5, 0xbc, 0x94, 0x69, 0xd9, 0xca, 0xd7, 0xbc, 0x94, 0xad, 0xd9, 0xca, 0xd3, 0xbc, 0x94, 0xad, 0xd9, 0xca, 0x5b, 0xbd, 0x94, 0xb5, 0xda, 0xca, 0x6b, 0xbd, 0x94, 0xd5, 0xda, 0x4a, 0x6b, 0xb5, 0xa4, 0x56, 0xea, 0xfa, 0xab, 0xbf, 0x54, 0x55, 0xd5, 0xff, 0xff, 0xff}; static unsigned char n_mask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; nedit-5.6.orig/source/nc.c0000644000175000017500000010557610723635310014174 0ustar paulpaulstatic const char CVSID[] = "$Id: nc.c,v 1.48 2007/11/29 22:18:48 tringali Exp $"; /******************************************************************************* * * * nc.c -- Nirvana Editor client program for nedit server processes * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * November, 1995 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "server_common.h" #include "../util/fileUtils.h" #include "../util/utils.h" #include "../util/prefFile.h" #include "../util/system.h" #include #include #include #include #ifdef VMS #include #include descrip #include ssdef #include syidef #include "../util/VMSparam.h" #include "../util/VMSutils.h" #else #ifndef __MVS__ #include #endif #include #include #include #include #include "../util/clearcase.h" #endif /* VMS */ #ifdef __EMX__ #include #endif #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #define APP_NAME "nc" #define APP_CLASS "NEditClient" #define PROPERTY_CHANGE_TIMEOUT (Preferences.timeOut * 1000) /* milliseconds */ #define SERVER_START_TIMEOUT (Preferences.timeOut * 3000) /* milliseconds */ #define REQUEST_TIMEOUT (Preferences.timeOut * 1000) /* milliseconds */ #define FILE_OPEN_TIMEOUT (Preferences.timeOut * 3000) /* milliseconds */ typedef struct { char* shell; char* serverRequest; } CommandLine; static void timeOutProc(Boolean *timeOutReturn, XtIntervalId *id); static int startServer(const char *message, const char *commandLine); static CommandLine processCommandLine(int argc, char** argv); static void parseCommandLine(int argc, char **arg, CommandLine *cmdLine); static void nextArg(int argc, char **argv, int *argIndex); static void copyCommandLineArg(CommandLine *cmdLine, const char *arg); static void printNcVersion(void); static Boolean findExistingServer(XtAppContext context, Window rootWindow, Atom serverExistsAtom); static void startNewServer(XtAppContext context, Window rootWindow, char* commandLine, Atom serverExistsAtom); static void waitUntilRequestProcessed(XtAppContext context, Window rootWindow, char* commandString, Atom serverRequestAtom); static void waitUntilFilesOpenedOrClosed(XtAppContext context, Window rootWindow); Display *TheDisplay; XtAppContext AppContext; static Atom currentWaitForAtom; static Atom noAtom = (Atom)(-1); static const char cmdLineHelp[] = #ifdef VMS "[Sorry, no on-line help available.]\n"; /* Why is that ? */ #else "Usage: nc [-read] [-create]\n" " [-line n | +n] [-do command] [-lm languagemode]\n" " [-svrname name] [-svrcmd command]\n" " [-ask] [-noask] [-timeout seconds]\n" " [-geometry geometry | -g geometry] [-icon | -iconic]\n" " [-tabbed] [-untabbed] [-group] [-wait]\n" " [-V | -version] [-h|-help]\n" " [-xrm resourcestring] [-display [host]:server[.screen]]\n" " [--] [file...]\n"; #endif /*VMS*/ /* Structure to hold X Resource values */ static struct { int autoStart; char serverCmd[2*MAXPATHLEN]; /* holds executable name + flags */ char serverName[MAXPATHLEN]; int waitForClose; int timeOut; } Preferences; /* Application resources */ static PrefDescripRec PrefDescrip[] = { {"autoStart", "AutoStart", PREF_BOOLEAN, "True", &Preferences.autoStart, NULL, True}, {"serverCommand", "ServerCommand", PREF_STRING, "nedit -server", Preferences.serverCmd, (void *)sizeof(Preferences.serverCmd), False}, {"serverName", "serverName", PREF_STRING, "", Preferences.serverName, (void *)sizeof(Preferences.serverName), False}, {"waitForClose", "WaitForClose", PREF_BOOLEAN, "False", &Preferences.waitForClose, NULL, False}, {"timeOut", "TimeOut", PREF_INT, "10", &Preferences.timeOut, NULL, False} }; /* Resource related command line options */ static XrmOptionDescRec OpTable[] = { {"-ask", ".autoStart", XrmoptionNoArg, (caddr_t)"False"}, {"-noask", ".autoStart", XrmoptionNoArg, (caddr_t)"True"}, {"-svrname", ".serverName", XrmoptionSepArg, (caddr_t)NULL}, {"-svrcmd", ".serverCommand", XrmoptionSepArg, (caddr_t)NULL}, {"-wait", ".waitForClose", XrmoptionNoArg, (caddr_t)"True"}, {"-timeout", ".timeOut", XrmoptionSepArg, (caddr_t)NULL} }; /* Struct to hold info about files being opened and edited. */ typedef struct _FileListEntry { Atom waitForFileOpenAtom; Atom waitForFileClosedAtom; char* path; struct _FileListEntry *next; } FileListEntry; typedef struct { int waitForOpenCount; int waitForCloseCount; FileListEntry* fileList; } FileListHead; static FileListHead fileListHead; static void setPropertyValue(Atom atom) { XChangeProperty(TheDisplay, RootWindow(TheDisplay, DefaultScreen(TheDisplay)), atom, XA_STRING, 8, PropModeReplace, (unsigned char *)"True", 4); } /* Add another entry to the file entry list, if it doesn't exist yet. */ static void addToFileList(const char *path) { FileListEntry *item; /* see if the file already exists in the list */ for (item = fileListHead.fileList; item; item = item->next) { if (!strcmp(item->path, path)) break; } /* Add the atom to the head of the file list if it wasn't found. */ if (item == 0) { item = malloc(sizeof(item[0])); item->waitForFileOpenAtom = None; item->waitForFileClosedAtom = None; item->path = (char*)malloc(strlen(path)+1); strcpy(item->path, path); item->next = fileListHead.fileList; fileListHead.fileList = item; } } /* Creates the properties for the various paths */ static void createWaitProperties(void) { FileListEntry *item; for (item = fileListHead.fileList; item; item = item->next) { fileListHead.waitForOpenCount++; item->waitForFileOpenAtom = CreateServerFileOpenAtom(Preferences.serverName, item->path); setPropertyValue(item->waitForFileOpenAtom); if (Preferences.waitForClose == True) { fileListHead.waitForCloseCount++; item->waitForFileClosedAtom = CreateServerFileClosedAtom(Preferences.serverName, item->path, False); setPropertyValue(item->waitForFileClosedAtom); } } } int main(int argc, char **argv) { XtAppContext context; Window rootWindow; CommandLine commandLine; Atom serverExistsAtom, serverRequestAtom; XrmDatabase prefDB; Boolean serverExists; /* Initialize toolkit and get an application context */ XtToolkitInitialize(); AppContext = context = XtCreateApplicationContext(); #ifdef VMS /* Convert the command line to Unix style */ ConvertVMSCommandLine(&argc, &argv); #endif /*VMS*/ #ifdef __EMX__ /* expand wildcards if necessary */ _wildcard(&argc, &argv); #endif /* Read the preferences command line into a database (note that we don't support the .nc file anymore) */ prefDB = CreatePreferencesDatabase(NULL, APP_CLASS, OpTable, XtNumber(OpTable), (unsigned *)&argc, argv); /* Process the command line before calling XtOpenDisplay, because the latter consumes certain command line arguments that we still need (-icon, -geometry ...) */ commandLine = processCommandLine(argc, argv); /* Open the display and find the root window */ TheDisplay = XtOpenDisplay (context, NULL, APP_NAME, APP_CLASS, NULL, 0, &argc, argv); if (!TheDisplay) { XtWarning ("nc: Can't open display\n"); exit(EXIT_FAILURE); } rootWindow = RootWindow(TheDisplay, DefaultScreen(TheDisplay)); /* Read the application resources into the Preferences data structure */ RestorePreferences(prefDB, XtDatabase(TheDisplay), APP_NAME, APP_CLASS, PrefDescrip, XtNumber(PrefDescrip)); /* Make sure that the time out unit is at least 1 second and not too large either (overflow!). */ if (Preferences.timeOut < 1) { Preferences.timeOut = 1; } else if (Preferences.timeOut > 1000) { Preferences.timeOut = 1000; } #ifndef VMS /* For Clearcase users who have not set a server name, use the clearcase view name. Clearcase views make files with the same absolute path names but different contents (and therefore can't be edited in the same nedit session). This should have no bad side-effects for non-clearcase users */ if (Preferences.serverName[0] == '\0') { const char* viewTag = GetClearCaseViewTag(); if (viewTag != NULL && strlen(viewTag) < MAXPATHLEN) { strcpy(Preferences.serverName, viewTag); } } #endif /* VMS */ /* Create the wait properties for the various files. */ createWaitProperties(); /* Monitor the properties on the root window */ XSelectInput(TheDisplay, rootWindow, PropertyChangeMask); /* Create the server property atoms on the current DISPLAY. */ CreateServerPropertyAtoms(Preferences.serverName, &serverExistsAtom, &serverRequestAtom); serverExists = findExistingServer(context, rootWindow, serverExistsAtom); if (serverExists == False) startNewServer(context, rootWindow, commandLine.shell, serverExistsAtom); waitUntilRequestProcessed(context, rootWindow, commandLine.serverRequest, serverRequestAtom); waitUntilFilesOpenedOrClosed(context, rootWindow); XtCloseDisplay(TheDisplay); XtFree(commandLine.shell); XtFree(commandLine.serverRequest); return 0; } /* ** Xt timer procedure for timeouts on NEdit server requests */ static void timeOutProc(Boolean *timeOutReturn, XtIntervalId *id) { /* NOTE: XtAppNextEvent() does call this routine but ** doesn't return unless there are more events. ** Hence, we generate this (synthetic) event to break the deadlock */ Window rootWindow = RootWindow(TheDisplay, DefaultScreen(TheDisplay)); if (currentWaitForAtom != noAtom) { XChangeProperty(TheDisplay, rootWindow, currentWaitForAtom, XA_STRING, 8, PropModeReplace, (unsigned char *)"", strlen("")); } /* Flag that the timeout has occurred. */ *timeOutReturn = True; } static Boolean findExistingServer(XtAppContext context, Window rootWindow, Atom serverExistsAtom) { Boolean serverExists = True; unsigned char *propValue; int getFmt; Atom dummyAtom; unsigned long dummyULong, nItems; /* See if there might be a server (not a guaranty), by translating the root window property NEDIT_SERVER_EXISTS__ */ if (XGetWindowProperty(TheDisplay, rootWindow, serverExistsAtom, 0, INT_MAX, False, XA_STRING, &dummyAtom, &getFmt, &nItems, &dummyULong, &propValue) != Success || nItems == 0) { serverExists = False; } else { Boolean timeOut = False; XtIntervalId timerId; XFree(propValue); /* Remove the server exists property to make sure the server is ** running. If it is running it will get recreated. */ XDeleteProperty(TheDisplay, rootWindow, serverExistsAtom); XSync(TheDisplay, False); timerId = XtAppAddTimeOut(context, PROPERTY_CHANGE_TIMEOUT, (XtTimerCallbackProc)timeOutProc, &timeOut); currentWaitForAtom = serverExistsAtom; while (!timeOut) { /* NOTE: XtAppNextEvent() does call the timeout routine but ** doesn't return unless there are more events. */ XEvent event; const XPropertyEvent *e = (const XPropertyEvent *)&event; XtAppNextEvent(context, &event); /* We will get a PropertyNewValue when the server recreates ** the server exists atom. */ if (e->type == PropertyNotify && e->window == rootWindow && e->atom == serverExistsAtom) { if (e->state == PropertyNewValue) { break; } } XtDispatchEvent(&event); } /* Start a new server if the timeout expired. The server exists ** property was not recreated. */ if (timeOut) { serverExists = False; } else { XtRemoveTimeOut(timerId); } } return(serverExists); } static void startNewServer(XtAppContext context, Window rootWindow, char* commandLine, Atom serverExistsAtom) { Boolean timeOut = False; XtIntervalId timerId; /* Add back the server name resource from the command line or resource database to the command line for starting the server. If -svrcmd appeared on the original command line, it was removed by CreatePreferencesDatabase before the command line was recorded in commandLine.shell. Moreover, if no server name was specified, it may have defaulted to the ClearCase view tag. */ if (Preferences.serverName[0] != '\0') { strcat(commandLine, " -svrname "); strcat(commandLine, Preferences.serverName); } switch (startServer("No servers available, start one? (y|n) [y]: ", commandLine)) { case -1: /* Start failed */ XtCloseDisplay(TheDisplay); exit(EXIT_FAILURE); break; case -2: /* Start canceled by user */ XtCloseDisplay(TheDisplay); exit(EXIT_SUCCESS); break; } /* Set up a timeout proc in case the server is dead. The standard selection timeout is probably a good guess at how long to wait for this style of inter-client communication as well */ timerId = XtAppAddTimeOut(context, SERVER_START_TIMEOUT, (XtTimerCallbackProc)timeOutProc, &timeOut); currentWaitForAtom = serverExistsAtom; /* Wait for the server to start */ while (!timeOut) { XEvent event; const XPropertyEvent *e = (const XPropertyEvent *)&event; /* NOTE: XtAppNextEvent() does call the timeout routine but ** doesn't return unless there are more events. */ XtAppNextEvent(context, &event); /* We will get a PropertyNewValue when the server updates ** the server exists atom. If the property is deleted the ** the server must have died. */ if (e->type == PropertyNotify && e->window == rootWindow && e->atom == serverExistsAtom) { if (e->state == PropertyNewValue) { break; } else if (e->state == PropertyDelete) { fprintf(stderr, "%s: The server failed to start.\n", APP_NAME); XtCloseDisplay(TheDisplay); exit(EXIT_FAILURE); } } XtDispatchEvent(&event); } /* Exit if the timeout expired. */ if (timeOut) { fprintf(stderr, "%s: The server failed to start (time-out).\n", APP_NAME); XtCloseDisplay(TheDisplay); exit(EXIT_FAILURE); } else { XtRemoveTimeOut(timerId); } } /* ** Prompt the user about starting a server, with "message", then start server */ static int startServer(const char *message, const char *commandLineArgs) { char c, *commandLine; #ifdef VMS int spawnFlags = 1 /* + 1<<3 */; /* NOWAIT, NOKEYPAD */ int spawn_sts; struct dsc$descriptor_s *cmdDesc; char *nulDev = "NL:"; struct dsc$descriptor_s *nulDevDesc; #else int sysrc; #endif /* !VMS */ /* prompt user whether to start server */ if (!Preferences.autoStart) { printf(message); do { c = getc(stdin); } while (c == ' ' || c == '\t'); if (c != 'Y' && c != 'y' && c != '\n') return (-2); } /* start the server */ #ifdef VMS commandLine = XtMalloc(strlen(Preferences.serverCmd) + strlen(commandLineArgs) + 3); sprintf(commandLine, "%s %s", Preferences.serverCmd, commandLineArgs); cmdDesc = NulStrToDesc(commandLine); /* build command descriptor */ nulDevDesc = NulStrToDesc(nulDev); /* build "NL:" descriptor */ spawn_sts = lib$spawn(cmdDesc, nulDevDesc, 0, &spawnFlags, 0,0,0,0,0,0,0,0); XtFree(commandLine); if (spawn_sts != SS$_NORMAL) { fprintf(stderr, "Error return from lib$spawn: %d\n", spawn_sts); fprintf(stderr, "Nedit server not started.\n"); return (-1); } else { FreeStrDesc(cmdDesc); return 0; } #else #if defined(__EMX__) /* OS/2 */ /* Unfortunately system() calls a shell determined by the environment variables COMSPEC and EMXSHELL. We have to figure out which one. */ { char *sh_spec, *sh, *base; char *CMD_EXE="cmd.exe"; commandLine = XtMalloc(strlen(Preferences.serverCmd) + strlen(commandLineArgs) + 15); sh = getenv ("EMXSHELL"); if (sh == NULL) sh = getenv ("COMSPEC"); if (sh == NULL) sh = CMD_EXE; sh_spec=XtNewString(sh); base=_getname(sh_spec); _remext(base); if (stricmp (base, "cmd") == 0 || stricmp (base, "4os2") == 0) { sprintf(commandLine, "start /C /MIN %s %s", Preferences.serverCmd, commandLineArgs); } else { sprintf(commandLine, "%s %s &", Preferences.serverCmd, commandLineArgs); } XtFree(sh_spec); } #else /* Unix */ commandLine = XtMalloc(strlen(Preferences.serverCmd) + strlen(commandLineArgs) + 3); sprintf(commandLine, "%s %s&", Preferences.serverCmd, commandLineArgs); #endif sysrc=system(commandLine); XtFree(commandLine); if (sysrc==0) return 0; else return (-1); #endif /* !VMS */ } /* Reconstruct the command line in string commandLine in case we have to * start a server (nc command line args parallel nedit's). Include * -svrname if nc wants a named server, so nedit will match. Special * characters are protected from the shell by escaping EVERYTHING with \ */ static CommandLine processCommandLine(int argc, char** argv) { CommandLine commandLine; int i; int length = 0; for (i=1; iserverRequest = NULL; return; } strcat(path, name); /* determine if file is to be openned in new tab, by factoring the options -group, -tabbed & -untabbed */ if (group == 2) { isTabbed = 0; /* start a new window for new group */ group = 1; /* next file will be within group */ } else if (group == 1) { isTabbed = 1; /* new tab for file in group */ } else { isTabbed = tabbed; /* not in group */ } /* See below for casts */ sprintf(outPtr, "%d %d %d %d %d %ld %ld %ld %ld\n%s\n%s\n%s\n%s\n%n", lineNum, read, create, iconic, tabbed, (long) strlen(path), (long) strlen(toDoCommand), (long) strlen(langMode), (long) strlen(geometry), path, toDoCommand, langMode, geometry, &charsWritten); outPtr += charsWritten; free(nameList[j]); /* Create the file open atoms for the paths supplied */ addToFileList(path); fileCount++; } if (nameList != NULL) free(nameList); #else if (ParseFilename(argv[i], name, path) != 0) { /* An Error, most likely too long paths/strings given */ commandLine->serverRequest = NULL; return; } strcat(path, name); /* determine if file is to be openned in new tab, by factoring the options -group, -tabbed & -untabbed */ if (group == 2) { isTabbed = 0; /* start a new window for new group */ group = 1; /* next file will be within group */ } else if (group == 1) { isTabbed = 1; /* new tab for file in group */ } else { isTabbed = tabbed; /* not in group */ } /* SunOS 4 acc or acc and/or its runtime library has a bug such that %n fails (segv) if it follows a string in a printf or sprintf. The silly code below avoids this. The "long" cast on strlen() is necessary because size_t is 64 bit on Alphas, and 32-bit on most others. There is no printf format specifier for "size_t", thanx, ANSI. */ sprintf(outPtr, "%d %d %d %d %d %ld %ld %ld %ld\n%n", lineNum, read, create, iconic, isTabbed, (long) strlen(path), (long) strlen(toDoCommand), (long) strlen(langMode), (long) strlen(geometry), &charsWritten); outPtr += charsWritten; strcpy(outPtr, path); outPtr += strlen(path); *outPtr++ = '\n'; strcpy(outPtr, toDoCommand); outPtr += strlen(toDoCommand); *outPtr++ = '\n'; strcpy(outPtr, langMode); outPtr += strlen(langMode); *outPtr++ = '\n'; strcpy(outPtr, geometry); outPtr += strlen(geometry); *outPtr++ = '\n'; toDoCommand = ""; /* Create the file open atoms for the paths supplied */ addToFileList(path); fileCount++; #endif /* VMS */ } } #ifdef VMS VMSFileScanDone(); #endif /*VMS*/ /* If there's an un-written -do command, or we are to open a new window, * or user has requested iconic state, but not provided a file name, * create a server request with an empty file name and requested * iconic state (and optional language mode and geometry). */ if (toDoCommand[0] != '\0' || fileCount == 0) { sprintf(outPtr, "0 0 0 %d %d 0 %ld %ld %ld\n\n%n", iconic, tabbed, (long) strlen(toDoCommand), (long) strlen(langMode), (long) strlen(geometry), &charsWritten); outPtr += charsWritten; strcpy(outPtr, toDoCommand); outPtr += strlen(toDoCommand); *outPtr++ = '\n'; strcpy(outPtr, langMode); outPtr += strlen(langMode); *outPtr++ = '\n'; strcpy(outPtr, geometry); outPtr += strlen(geometry); *outPtr++ = '\n'; } *outPtr = '\0'; commandLine->serverRequest = commandString; } static void waitUntilRequestProcessed(XtAppContext context, Window rootWindow, char* commandString, Atom serverRequestAtom) { XtIntervalId timerId; Boolean timeOut = False; /* Set the NEDIT_SERVER_REQUEST__ property on the root window to activate the server */ XChangeProperty(TheDisplay, rootWindow, serverRequestAtom, XA_STRING, 8, PropModeReplace, (unsigned char *)commandString, strlen(commandString)); /* Set up a timeout proc in case the server is dead. The standard selection timeout is probably a good guess at how long to wait for this style of inter-client communication as well */ timerId = XtAppAddTimeOut(context, REQUEST_TIMEOUT, (XtTimerCallbackProc)timeOutProc, &timeOut); currentWaitForAtom = serverRequestAtom; /* Wait for the property to be deleted to know the request was processed */ while (!timeOut) { XEvent event; const XPropertyEvent *e = (const XPropertyEvent *)&event; XtAppNextEvent(context, &event); if (e->window == rootWindow && e->atom == serverRequestAtom && e->state == PropertyDelete) break; XtDispatchEvent(&event); } /* Exit if the timeout expired. */ if (timeOut) { fprintf(stderr, "%s: The server did not respond to the request.\n", APP_NAME); XtCloseDisplay(TheDisplay); exit(EXIT_FAILURE); } else { XtRemoveTimeOut(timerId); } } static void waitUntilFilesOpenedOrClosed(XtAppContext context, Window rootWindow) { XtIntervalId timerId; Boolean timeOut = False; /* Set up a timeout proc so we don't wait forever if the server is dead. The standard selection timeout is probably a good guess at how long to wait for this style of inter-client communication as well */ timerId = XtAppAddTimeOut(context, FILE_OPEN_TIMEOUT, (XtTimerCallbackProc)timeOutProc, &timeOut); currentWaitForAtom = noAtom; /* Wait for all of the windows to be opened by server, * and closed if -wait was supplied */ while (fileListHead.fileList) { XEvent event; const XPropertyEvent *e = (const XPropertyEvent *)&event; XtAppNextEvent(context, &event); /* Update the fileList and check if all files have been closed. */ if (e->type == PropertyNotify && e->window == rootWindow) { FileListEntry *item; if (e->state == PropertyDelete) { for (item = fileListHead.fileList; item; item = item->next) { if (e->atom == item->waitForFileOpenAtom) { /* The 'waitForFileOpen' property is deleted when the file is opened */ fileListHead.waitForOpenCount--; item->waitForFileOpenAtom = None; /* Reset the timer while we wait for all files to be opened. */ XtRemoveTimeOut(timerId); timerId = XtAppAddTimeOut(context, FILE_OPEN_TIMEOUT, (XtTimerCallbackProc)timeOutProc, &timeOut); } else if (e->atom == item->waitForFileClosedAtom) { /* When file is opened in -wait mode the property * is deleted when the file is closed. */ fileListHead.waitForCloseCount--; item->waitForFileClosedAtom = None; } } if (fileListHead.waitForOpenCount == 0 && !timeOut) { XtRemoveTimeOut(timerId); } if (fileListHead.waitForOpenCount == 0 && fileListHead.waitForCloseCount == 0) { break; } } } /* We are finished if we are only waiting for files to open and ** the file open timeout has expired. */ if (!Preferences.waitForClose && timeOut) { break; } XtDispatchEvent(&event); } } static void nextArg(int argc, char **argv, int *argIndex) { if (*argIndex + 1 >= argc) { #ifdef VMS *argv[*argIndex] = '/'; #endif /*VMS*/ fprintf(stderr, "nc: %s requires an argument\n%s", argv[*argIndex], cmdLineHelp); exit(EXIT_FAILURE); } (*argIndex)++; } /* Copies a given nc command line argument to the server startup command ** line (-icon, -geometry, -xrm, ...) Special characters are protected from ** the shell by escaping EVERYTHING with \ ** Note that the .shell string in the command line structure is large enough ** to hold the escaped characters. */ static void copyCommandLineArg(CommandLine *commandLine, const char *arg) { const char *c; char *outPtr = commandLine->shell + strlen(commandLine->shell); #if defined(VMS) || defined(__EMX__) /* Non-Unix shells don't want/need esc */ for (c=arg; *c!='\0'; c++) { *outPtr++ = *c; } *outPtr++ = ' '; *outPtr = '\0'; #else *outPtr++ = '\''; for (c=arg; *c!='\0'; c++) { if (*c == '\'') { *outPtr++ = '\''; *outPtr++ = '\\'; } *outPtr++ = *c; if (*c == '\'') { *outPtr++ = '\''; } } *outPtr++ = '\''; *outPtr++ = ' '; *outPtr = '\0'; #endif /* VMS */ } /* Print version of 'nc' */ static void printNcVersion(void ) { static const char *const ncHelpText = \ "nc (NEdit) Version 5.5 (October 2004)\n\n\ Built on: %s, %s, %s\n\ Built at: %s, %s\n"; fprintf(stdout, ncHelpText, COMPILE_OS, COMPILE_MACHINE, COMPILE_COMPILER, __DATE__, __TIME__); } nedit-5.6.orig/source/nedit.bm0000644000175000017500000001072607246564333015057 0ustar paulpaul/* $Id: nedit.bm,v 1.2 2001/02/26 23:38:03 edg Exp $ */ #define iconBitmapWidth 50 #define iconBitmapHeight 50 static unsigned char iconBits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x03, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x02, 0x00, 0x15, 0x40, 0x55, 0x55, 0x55, 0x03, 0x5a, 0xab, 0xf5, 0xaa, 0xaa, 0xaa, 0x02, 0xb4, 0x56, 0x7b, 0x55, 0x55, 0x55, 0x03, 0x4a, 0xad, 0xbc, 0xaa, 0xaa, 0xaa, 0x02, 0x94, 0x5a, 0x59, 0x55, 0x55, 0x55, 0x03, 0x4a, 0xb5, 0xbc, 0xaa, 0xaa, 0xaa, 0x02, 0x94, 0x4a, 0x59, 0x55, 0x55, 0x55, 0x03, 0xca, 0xb5, 0xbc, 0xaa, 0xaa, 0xaa, 0x02, 0x94, 0x69, 0x59, 0x55, 0x55, 0x55, 0x03, 0xca, 0xd7, 0xbc, 0xaa, 0xaa, 0xaa, 0x02, 0x94, 0xa5, 0x59, 0x55, 0x55, 0x55, 0x03, 0xca, 0x5b, 0xbd, 0xaa, 0xaa, 0xaa, 0x02, 0x94, 0xb5, 0x5a, 0x55, 0x55, 0x55, 0x03, 0xca, 0x03, 0x00, 0x00, 0x00, 0x80, 0x02, 0x94, 0xa9, 0xaa, 0xaa, 0xaa, 0x6a, 0x03, 0xca, 0x53, 0x55, 0x55, 0x55, 0xd5, 0x02, 0xa4, 0x29, 0x08, 0x02, 0xaa, 0x60, 0x03, 0x42, 0x13, 0x04, 0x01, 0x55, 0xd0, 0x02, 0xa4, 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, 0x03, 0xfa, 0xf3, 0xff, 0xff, 0xff, 0xff, 0x02, 0x54, 0x19, 0x00, 0x00, 0x00, 0x68, 0x03, 0xaa, 0x12, 0xff, 0x1f, 0x00, 0xc8, 0x02, 0x54, 0x19, 0x00, 0x00, 0x00, 0x68, 0x03, 0xaa, 0x12, 0xff, 0x03, 0x00, 0xc8, 0x02, 0x54, 0x19, 0x00, 0x00, 0x00, 0x68, 0x03, 0xaa, 0x12, 0xfc, 0x0f, 0x0f, 0xc8, 0x02, 0x54, 0x19, 0x00, 0x00, 0x00, 0x68, 0x03, 0xaa, 0x12, 0xc0, 0x03, 0x00, 0xc8, 0x02, 0x54, 0x19, 0x00, 0x00, 0x00, 0x68, 0x03, 0xaa, 0x12, 0xc0, 0x03, 0x00, 0xc8, 0x02, 0x54, 0x19, 0x00, 0x00, 0x00, 0x68, 0x03, 0xaa, 0x12, 0xc0, 0x3f, 0x00, 0xc8, 0x02, 0x54, 0x19, 0x00, 0x00, 0x00, 0x68, 0x03, 0xaa, 0x12, 0x7c, 0x00, 0x00, 0xc8, 0x02, 0x54, 0x19, 0x00, 0x00, 0x00, 0x68, 0x03, 0xaa, 0x12, 0xff, 0x03, 0x00, 0xc8, 0x02, 0x54, 0x19, 0x00, 0x00, 0x00, 0x68, 0x03, 0xaa, 0xf2, 0xff, 0xff, 0xff, 0xdf, 0x02, 0x54, 0x19, 0x00, 0x00, 0x00, 0x68, 0x03, 0xaa, 0x52, 0x55, 0x55, 0x55, 0xd5, 0x02, 0x54, 0xfd, 0xff, 0xff, 0xff, 0x7f, 0x03, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x02, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x03, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x02, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x03, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x02, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03}; static unsigned char maskBits[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; nedit-5.6.orig/source/nedit.c0000644000175000017500000014271310723635241014674 0ustar paulpaulstatic const char CVSID[] = "$Id: nedit.c,v 1.100 2007/11/29 22:18:09 tringali Exp $"; /******************************************************************************* * * * nedit.c -- Nirvana Editor main program * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * May 10, 1991 * * * * Written by Mark Edel * * * * Modifications: * * * * 8/18/93 - Mark Edel & Joy Kyriakopulos - Ported to VMS * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "nedit.h" /* #include "textBuf.h" */ #include "file.h" #include "preferences.h" #include "regularExp.h" #include "selection.h" #include "tags.h" #include "menu.h" #include "macro.h" #include "server.h" #include "interpret.h" #include "parse.h" #include "help.h" #include "../util/misc.h" #include "../util/printUtils.h" #include "../util/fileUtils.h" #include "../util/getfiles.h" #include "../util/motif.h" #include #include #include #include #include #include #ifndef NO_XMIM #include #else #include #endif #include #include #include #if XmVersion >= 1002 #include #endif #ifdef VMS #include #include "../util/VMSparam.h" #include "../util/VMSUtils.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #ifdef HAVE_DEBUG_H #include "../debug.h" #endif static void nextArg(int argc, char **argv, int *argIndex); static int checkDoMacroArg(const char *macro); static String neditLanguageProc(Display *dpy, String xnl, XtPointer closure); static void maskArgvKeywords(int argc, char **argv, const char **maskArgs); static void unmaskArgvKeywords(int argc, char **argv, const char **maskArgs); static void fixupBrokenXKeysymDB(void); static void patchResourcesForVisual(void); static void patchResourcesForKDEbug(void); static void patchLocaleForMotif(void); static unsigned char* sanitizeVirtualKeyBindings(void); static int sortAlphabetical(const void* k1, const void* k2); static int virtKeyBindingsAreInvalid(const unsigned char* bindings); static void restoreInsaneVirtualKeyBindings(unsigned char* bindings); static void noWarningFilter(String); static void showWarningFilter(String); WindowInfo *WindowList = NULL; Display *TheDisplay = NULL; char *ArgV0 = NULL; Boolean IsServer = False; Widget TheAppShell; /* Reasons for choice of default font qualifications: iso8859 appears to be necessary for newer versions of XFree86 that default to Unicode encoding, which doesn't quite work with Motif. Otherwise Motif puts up garbage (square blocks). (This of course, is a stupid default because there are far more iso8859 apps than Unicode apps. But the X folks insist it's a client bug. Hah.) RedHat 7.3 won't default to '-1' for an encoding, if left with a *, and so reverts to "fixed". Yech. */ #define NEDIT_DEFAULT_FONT "-*-helvetica-medium-r-normal-*-*-120-*-*-*-*-iso8859-1," \ "-*-helvetica-bold-r-normal-*-*-120-*-*-*-*-iso8859-1=BOLD," \ "-*-helvetica-medium-o-normal-*-*-120-*-*-*-*-iso8859-1=ITALIC" #define NEDIT_FIXED_FONT "-*-courier-medium-r-normal-*-*-120-*-*-*-*-iso8859-1," \ "-*-courier-bold-r-normal-*-*-120-*-*-*-*-iso8859-1=BOLD," \ "-*-courier-medium-o-normal-*-*-120-*-*-*-*-iso8859-1=ITALIC" #define NEDIT_DEFAULT_BG "#b3b3b3" #define NEDIT_TEXT_TRANSLATIONS "#override\\n" \ "Ctrl~Alt~Metav: paste-clipboard()\\n" \ "Ctrl~Alt~Metac: copy-clipboard()\\n" \ "Ctrl~Alt~Metax: cut-clipboard()\\n" \ "Ctrl~Alt~Metau: delete-to-start-of-line()\\n" static char *fallbackResources[] = { /* Try to avoid Motif's horrificly ugly default colors and fonts, if the user's environment provides no usable defaults. We try to choose a Windows-y default color setting here. Editable text fields are forced to a fixed-pitch font for usability. By using the VendorShell fontList resources, Motif automatically groups the fonts into the right classes. It's then easier for the user or environment to override this sensibly: nedit -xrm '*textFontList: myfont' This is broken in recent versions of LessTif. */ #ifdef LESSTIF_VERSION "*FontList: " NEDIT_DEFAULT_FONT, "*XmText.FontList: " NEDIT_FIXED_FONT, "*XmTextField.FontList: " NEDIT_FIXED_FONT, "*XmList.FontList: " NEDIT_FIXED_FONT, "*XmFileSelectionBox*XmList.FontList: " NEDIT_FIXED_FONT, #else "*buttonFontList: " NEDIT_DEFAULT_FONT, "*labelFontList: " NEDIT_DEFAULT_FONT, "*textFontList: " NEDIT_FIXED_FONT, #endif "*background: " NEDIT_DEFAULT_BG, "*foreground: " NEDIT_DEFAULT_FG, "*XmText.foreground: " NEDIT_DEFAULT_FG, "*XmText.background: " NEDIT_DEFAULT_TEXT_BG, "*XmList.foreground: " NEDIT_DEFAULT_FG, "*XmList.background: " NEDIT_DEFAULT_TEXT_BG, "*XmTextField.foreground: " NEDIT_DEFAULT_FG, "*XmTextField.background: " NEDIT_DEFAULT_TEXT_BG, /* Use baseTranslations as per Xt Programmer's Manual, 10.2.12 */ "*XmText.baseTranslations: " NEDIT_TEXT_TRANSLATIONS, "*XmTextField.baseTranslations: " NEDIT_TEXT_TRANSLATIONS, "*XmLFolder.highlightThickness: 0", "*XmLFolder.shadowThickness: 1", "*XmLFolder.maxTabWidth: 150", "*XmLFolder.traversalOn: False", "*XmLFolder.inactiveForeground: #666" , "*tab.alignment: XmALIGNMENT_BEGINNING", "*tab.marginWidth: 0", "*tab.marginHeight: 1", /* Prevent the file selection box from acting stupid. */ "*XmFileSelectionBox.resizePolicy: XmRESIZE_NONE", "*XmFileSelectionBox.textAccelerators:", "*XmFileSelectionBox.pathMode: XmPATH_MODE_RELATIVE", "*XmFileSelectionBox.width: 500", "*XmFileSelectionBox.height: 400", /* NEdit-specific widgets. Theses things should probably be manually jammed into the database, rather than fallbacks. We really want the accelerators to be there even if someone creates an app-defaults file against our wishes. */ "*text.lineNumForeground: " NEDIT_DEFAULT_LINENO_FG, "*text.background: " NEDIT_DEFAULT_TEXT_BG, "*text.foreground: " NEDIT_DEFAULT_FG, "*text.highlightForeground: " NEDIT_DEFAULT_HI_FG, "*text.highlightBackground: " NEDIT_DEFAULT_HI_BG, "*textFrame.shadowThickness: 1", "*menuBar.marginHeight: 0", "*menuBar.shadowThickness: 1", "*pane.sashHeight: 11", "*pane.sashWidth: 11", "*pane.marginWidth: 0", "*pane.marginHeight: 0", "*scrolledW*spacing: 0", "*text.selectionArrayCount: 3", "*helpText.background: " NEDIT_DEFAULT_HELP_BG, "*helpText.foreground: " NEDIT_DEFAULT_HELP_FG, "*helpText.selectBackground: " NEDIT_DEFAULT_BG, "*statsLine.background: " NEDIT_DEFAULT_BG, "*statsLine.FontList: " NEDIT_DEFAULT_FONT, "*calltip.background: LemonChiffon1", "*calltip.foreground: black", "*iSearchForm*highlightThickness: 1", "*fileMenu.tearOffModel: XmTEAR_OFF_ENABLED", "*editMenu.tearOffModel: XmTEAR_OFF_ENABLED", "*searchMenu.tearOffModel: XmTEAR_OFF_ENABLED", "*preferencesMenu.tearOffModel: XmTEAR_OFF_ENABLED", "*windowsMenu.tearOffModel: XmTEAR_OFF_ENABLED", "*shellMenu.tearOffModel: XmTEAR_OFF_ENABLED", "*macroMenu.tearOffModel: XmTEAR_OFF_ENABLED", "*helpMenu.tearOffModel: XmTEAR_OFF_ENABLED", "*fileMenu.mnemonic: F", "*fileMenu.new.accelerator: Ctrln", "*fileMenu.new.acceleratorText: Ctrl+N", "*fileMenu.newOpposite.accelerator: Shift Ctrln", "*fileMenu.newOpposite.acceleratorText: Shift+Ctrl+N", "*fileMenu.open.accelerator: Ctrlo", "*fileMenu.open.acceleratorText: Ctrl+O", "*fileMenu.openSelected.accelerator: Ctrly", "*fileMenu.openSelected.acceleratorText: Ctrl+Y", "*fileMenu.close.accelerator: Ctrlw", "*fileMenu.close.acceleratorText: Ctrl+W", "*fileMenu.save.accelerator: Ctrls", "*fileMenu.save.acceleratorText: Ctrl+S", "*fileMenu.includeFile.accelerator: Alti", "*fileMenu.includeFile.acceleratorText: Alt+I", "*fileMenu.print.accelerator: Ctrlp", "*fileMenu.print.acceleratorText: Ctrl+P", "*fileMenu.exit.accelerator: Ctrlq", "*fileMenu.exit.acceleratorText: Ctrl+Q", "*editMenu.mnemonic: E", "*editMenu.undo.accelerator: Ctrlz", "*editMenu.undo.acceleratorText: Ctrl+Z", "*editMenu.redo.accelerator: Shift Ctrlz", "*editMenu.redo.acceleratorText: Shift+Ctrl+Z", /* Clipboard accelerators prevent the use of the clipboard in iSearch's XmText, so they are left out. Their job is done by translations in the main text widget, so the acceleratorText is still kept. */ "*editMenu.cut.acceleratorText: Ctrl+X", "*editMenu.copy.acceleratorText: Ctrl+C", "*editMenu.paste.acceleratorText: Ctrl+V", "*editMenu.pasteColumn.accelerator: Shift Ctrlv", "*editMenu.pasteColumn.acceleratorText: Ctrl+Shift+V", "*editMenu.delete.acceleratorText: Del", "*editMenu.selectAll.accelerator: Ctrla", "*editMenu.selectAll.acceleratorText: Ctrl+A", "*editMenu.shiftLeft.accelerator: Ctrl9", "*editMenu.shiftLeft.acceleratorText: [Shift]Ctrl+9", "*editMenu.shiftLeftShift.accelerator: Shift Ctrl9", "*editMenu.shiftRight.accelerator: Ctrl0", "*editMenu.shiftRight.acceleratorText: [Shift]Ctrl+0", "*editMenu.shiftRightShift.accelerator: Shift Ctrl0", "*editMenu.upperCase.accelerator: Ctrl6", "*editMenu.upperCase.acceleratorText: Ctrl+6", "*editMenu.lowerCase.accelerator: Shift Ctrl6", "*editMenu.lowerCase.acceleratorText: Shift+Ctrl+6", "*editMenu.fillParagraph.accelerator: Ctrlj", "*editMenu.fillParagraph.acceleratorText: Ctrl+J", "*editMenu.insertFormFeed.accelerator: Alt Ctrll", "*editMenu.insertFormFeed.acceleratorText: Alt+Ctrl+L", "*editMenu.insertCtrlCode.accelerator: Alt Ctrli", "*editMenu.insertCtrlCode.acceleratorText: Alt+Ctrl+I", "*searchMenu.mnemonic: S", "*searchMenu.find.accelerator: Ctrlf", "*searchMenu.find.acceleratorText: [Shift]Ctrl+F", "*searchMenu.findShift.accelerator: Shift Ctrlf", "*searchMenu.findAgain.accelerator: Ctrlg", "*searchMenu.findAgain.acceleratorText: [Shift]Ctrl+G", "*searchMenu.findAgainShift.accelerator: Shift Ctrlg", "*searchMenu.findSelection.accelerator: Ctrlh", "*searchMenu.findSelection.acceleratorText: [Shift]Ctrl+H", "*searchMenu.findSelectionShift.accelerator: Shift Ctrlh", "*searchMenu.findIncremental.accelerator: Ctrli", "*searchMenu.findIncrementalShift.accelerator: Shift Ctrli", "*searchMenu.findIncremental.acceleratorText: [Shift]Ctrl+I", "*searchMenu.replace.accelerator: Ctrlr", "*searchMenu.replace.acceleratorText: [Shift]Ctrl+R", "*searchMenu.replaceShift.accelerator: Shift Ctrlr", "*searchMenu.findReplace.accelerator: Ctrlr", "*searchMenu.findReplace.acceleratorText: [Shift]Ctrl+R", "*searchMenu.findReplaceShift.accelerator: Shift Ctrlr", "*searchMenu.replaceFindAgain.accelerator: Ctrlt", "*searchMenu.replaceFindAgain.acceleratorText: [Shift]Ctrl+T", "*searchMenu.replaceFindAgainShift.accelerator: Shift Ctrlt", "*searchMenu.replaceAgain.accelerator: Altt", "*searchMenu.replaceAgain.acceleratorText: [Shift]Alt+T", "*searchMenu.replaceAgainShift.accelerator: Shift Altt", "*searchMenu.gotoLineNumber.accelerator: Ctrll", "*searchMenu.gotoLineNumber.acceleratorText: Ctrl+L", "*searchMenu.gotoSelected.accelerator: Ctrle", "*searchMenu.gotoSelected.acceleratorText: Ctrl+E", "*searchMenu.mark.accelerator: Altm", "*searchMenu.mark.acceleratorText: Alt+M a-z", "*searchMenu.gotoMark.accelerator: Altg", "*searchMenu.gotoMark.acceleratorText: [Shift]Alt+G a-z", "*searchMenu.gotoMarkShift.accelerator: Shift Altg", "*searchMenu.gotoMatching.accelerator: Ctrlm", "*searchMenu.gotoMatching.acceleratorText: [Shift]Ctrl+M", "*searchMenu.gotoMatchingShift.accelerator: Shift Ctrlm", "*searchMenu.findDefinition.accelerator: Ctrld", "*searchMenu.findDefinition.acceleratorText: Ctrl+D", "*searchMenu.showCalltip.accelerator: Ctrlapostrophe", "*searchMenu.showCalltip.acceleratorText: Ctrl+'", "*preferencesMenu.mnemonic: P", "*preferencesMenu.statisticsLine.accelerator: Alta", "*preferencesMenu.statisticsLine.acceleratorText: Alt+A", "*preferencesMenu.overtype.acceleratorText: Insert", "*shellMenu.mnemonic: l", "*shellMenu.filterSelection.accelerator: Altr", "*shellMenu.filterSelection.acceleratorText: Alt+R", "*shellMenu.executeCommand.accelerator: Altx", "*shellMenu.executeCommand.acceleratorText: Alt+X", "*shellMenu.executeCommandLine.accelerator: CtrlKP_Enter", "*shellMenu.executeCommandLine.acceleratorText: Ctrl+KP Enter", "*shellMenu.cancelShellCommand.accelerator: Ctrlperiod", "*shellMenu.cancelShellCommand.acceleratorText: Ctrl+.", "*macroMenu.mnemonic: c", "*macroMenu.learnKeystrokes.accelerator: Altk", "*macroMenu.learnKeystrokes.acceleratorText: Alt+K", "*macroMenu.finishLearn.accelerator: Altk", "*macroMenu.finishLearn.acceleratorText: Alt+K", "*macroMenu.cancelLearn.accelerator: Ctrlperiod", "*macroMenu.cancelLearn.acceleratorText: Ctrl+.", "*macroMenu.replayKeystrokes.accelerator: Ctrlk", "*macroMenu.replayKeystrokes.acceleratorText: Ctrl+K", "*macroMenu.repeat.accelerator: Ctrlcomma", "*macroMenu.repeat.acceleratorText: Ctrl+,", "*windowsMenu.mnemonic: W", "*windowsMenu.splitPane.accelerator: Ctrl2", "*windowsMenu.splitPane.acceleratorText: Ctrl+2", "*windowsMenu.closePane.accelerator: Ctrl1", "*windowsMenu.closePane.acceleratorText: Ctrl+1", "*helpMenu.mnemonic: H", "nedit.help.helpForm.sw.helpText*baseTranslations: #override\ Tab:help-focus-buttons()\\n\ Return:help-button-action(\"close\")\\n\ CtrlF:help-button-action(\"find\")\\n\ CtrlG:help-button-action(\"findAgain\")\\n\ osfCancel:help-button-action(\"close\")\\n\ ~Meta~Ctrl~Shift:\ grab-focus() help-hyperlink()\\n\ ~Meta~Ctrl~Shift:\ help-hyperlink(\"current\", \"process-cancel\", \"extend-end\")\\n\ ~Meta~Ctrl~Shift:\ process-bdrag() help-hyperlink()\\n\ ~Meta~Ctrl~Shift:\ help-hyperlink(\"new\", \"process-cancel\", \"copy-to\")", NULL }; static const char cmdLineHelp[] = #ifndef VMS "Usage: nedit [-read] [-create] [-line n | +n] [-server] [-do command]\n\ [-tags file] [-tabs n] [-wrap] [-nowrap] [-autowrap]\n\ [-autoindent] [-noautoindent] [-autosave] [-noautosave]\n\ [-lm languagemode] [-rows n] [-columns n] [-font font]\n\ [-geometry geometry] [-iconic] [-noiconic] [-svrname name]\n\ [-display [host]:server[.screen] [-xrm resourcestring]\n\ [-import file] [-background color] [-foreground color]\n\ [-tabbed] [-untabbed] [-group] [-V|-version] [-h|-help]\n\ [--] [file...]\n"; #else "[Sorry, no on-line help available.]\n"; /* Why is that ? */ #endif /*VMS*/ int main(int argc, char **argv) { int i, lineNum, nRead, fileSpecified = FALSE, editFlags = CREATE; int gotoLine = False, macroFileRead = False, opts = True; int iconic=False, tabbed = -1, group = 0, isTabbed; char *toDoCommand = NULL, *geometry = NULL, *langMode = NULL; char filename[MAXPATHLEN], pathname[MAXPATHLEN]; XtAppContext context; XrmDatabase prefDB; WindowInfo *window = NULL, *lastFile = NULL; static const char *protectedKeywords[] = {"-iconic", "-icon", "-geometry", "-g", "-rv", "-reverse", "-bd", "-bordercolor", "-borderwidth", "-bw", "-title", NULL}; unsigned char* invalidBindings = NULL; /* Warn user if this has been compiled wrong. */ enum MotifStability stability = GetMotifStability(); if (stability == MotifKnownBad) { fputs("nedit: WARNING: This version of NEdit is built incorrectly, and will be unstable.\n" "nedit: Please get a stable version of NEdit from http://www.nedit.org.\n", stderr); } /* Save the command which was used to invoke nedit for restart command */ ArgV0 = argv[0]; /* Set locale for C library, X, and Motif input functions. Reverts to "C" if requested locale not available. */ XtSetLanguageProc(NULL, neditLanguageProc, NULL); /* Initialize X toolkit (does not open display yet) */ XtToolkitInitialize(); context = XtCreateApplicationContext(); /* Set up a warning handler to trap obnoxious Xt grab warnings */ SuppressPassiveGrabWarnings(); /* Set up a handler to suppress X warning messages by default */ XtAppSetWarningHandler(context, noWarningFilter); /* Set up default resources if no app-defaults file is found */ XtAppSetFallbackResources(context, fallbackResources); #if XmVersion >= 1002 /* Allow users to change tear off menus with X resources */ XmRepTypeInstallTearOffModelConverter(); #endif #ifdef VMS /* Convert the command line to Unix style (This is not an ideal solution) */ ConvertVMSCommandLine(&argc, &argv); #endif /*VMS*/ #ifdef __EMX__ /* expand wildcards if necessary */ _wildcard(&argc, &argv); #endif /* Read the preferences file and command line into a database */ prefDB = CreateNEditPrefDB(&argc, argv); /* Open the display and read X database and remaining command line args. XtOpenDisplay must be allowed to process some of the resource arguments with its inaccessible internal option table, but others, like -geometry and -iconic are per-window and it should not be allowed to consume them, so we temporarily masked them out. */ maskArgvKeywords(argc, argv, protectedKeywords); /* X.Org 6.8 and above add support for ARGB visuals (with alpha-channel), typically with a 32-bit color depth. By default, NEdit uses the visual with the largest color depth. However, both OpenMotif and Lesstif cannot handle ARGB visuals (crashes, weird display effects, ...), so NEdit should avoid selecting such a visual. Unfortunatly, there appears to be no reliable way to identify ARGB visuals that doesn't require some of the recent X.Org extensions. Luckily, the X.Org developers have provided a mechanism that can hide these problematic visuals from the application. This can be achieved by setting the XLIB_SKIP_ARGB_VISUALS environment variable. Users can set this variable before starting NEdit, but it is much more convenient that NEdit takes care of this. This must be done before the display is opened (empirically verified). */ putenv("XLIB_SKIP_ARGB_VISUALS=1"); TheDisplay = XtOpenDisplay (context, NULL, APP_NAME, APP_CLASS, NULL, 0, &argc, argv); unmaskArgvKeywords(argc, argv, protectedKeywords); if (!TheDisplay) { /* Respond to -V or -version even if there is no display */ for (i = 1; i < argc && strcmp(argv[i], "--"); i++) { if (0 == strcmp(argv[i], "-V") || 0 == strcmp(argv[i], "-version")) { PrintVersion(); exit(EXIT_SUCCESS); } } fputs ("NEdit: Can't open display\n", stderr); exit(EXIT_FAILURE); } /* Must be done before creating widgets */ fixupBrokenXKeysymDB(); patchResourcesForVisual(); patchResourcesForKDEbug(); /* Initialize global symbols and subroutines used in the macro language */ InitMacroGlobals(); RegisterMacroSubroutines(); /* Store preferences from the command line and .nedit file, and set the appropriate preferences */ RestoreNEditPrefs(prefDB, XtDatabase(TheDisplay)); /* Intercept syntactically invalid virtual key bindings BEFORE we create any shells. */ invalidBindings = sanitizeVirtualKeyBindings(); /* Create a hidden application shell that is the parent of all the main editor windows. Realize it so it the window can act as group leader. */ TheAppShell = CreateShellWithBestVis(APP_NAME, APP_CLASS, applicationShellWidgetClass, TheDisplay, NULL, 0); /* Restore the original bindings ASAP such that other apps are not affected. */ restoreInsaneVirtualKeyBindings(invalidBindings); XtSetMappedWhenManaged(TheAppShell, False); XtRealizeWidget(TheAppShell); #ifndef NO_SESSION_RESTART AttachSessionMgrHandler(TheAppShell); #endif /* More preference stuff */ LoadPrintPreferences(XtDatabase(TheDisplay), APP_NAME, APP_CLASS, True); SetDeleteRemap(GetPrefMapDelete()); SetPointerCenteredDialogs(GetPrefRepositionDialogs()); SetGetEFTextFieldRemoval(!GetPrefStdOpenDialog()); /* Set up action procedures for menu item commands */ InstallMenuActions(context); /* Add Actions for following hyperlinks in the help window */ InstallHelpLinkActions(context); /* Add actions for mouse wheel support in scrolled windows (except text area) */ InstallMouseWheelActions(context); /* Install word delimiters for regular expression matching */ SetREDefaultWordDelimiters(GetPrefDelimiters()); /* Read the nedit dynamic database of files for the Open Previous command (and eventually other information as well) */ ReadNEditDB(); /* Process -import command line argument before others which might open windows (loading preferences doesn't update menu settings, which would then be out of sync with the real preference settings) */ for (i=1; i, -line, -server, and files to edit) not already processed by RestoreNEditPrefs. */ fileSpecified = FALSE; for (i=1; ishell != lastFile->shell) { CleanUpTabBarExposeQueue(lastFile); RaiseDocument(lastFile); } if (!macroFileRead) { ReadMacroInitFile(WindowList); macroFileRead = True; } if (gotoLine) SelectNumberedLine(window, lineNum); if (toDoCommand != NULL) { DoMacro(window, toDoCommand, "-do macro"); toDoCommand = NULL; if (!IsValidWindow(window)) window = NULL; /* window closed by macro */ if (lastFile && !IsValidWindow(lastFile)) lastFile = NULL; /* window closed by macro */ } } /* register last opened file for later use */ if (window) lastFile = window; } else { fprintf(stderr, "nedit: file name too long: %s\n", nameList[j]); } free(nameList[j]); } if (nameList != NULL) free(nameList); #else if (ParseFilename(argv[i], filename, pathname) == 0 ) { /* determine if file is to be openned in new tab, by factoring the options -group, -tabbed & -untabbed */ if (group == 2) { isTabbed = 0; /* start a new window for new group */ group = 1; /* next file will be within group */ } else if (group == 1) { isTabbed = 1; /* new tab for file in group */ } else { /* not in group */ isTabbed = tabbed==-1? GetPrefOpenInTab() : tabbed; } /* Files are opened in background to improve opening speed by defering certain time consuiming task such as syntax highlighting. At the end of the file-opening loop, the last file opened will be raised to restore those deferred items. The current file may also be raised if there're macros to execute on. */ window = EditExistingFile(WindowList, filename, pathname, editFlags, geometry, iconic, langMode, isTabbed, True); fileSpecified = TRUE; if (window) { CleanUpTabBarExposeQueue(window); /* raise the last tab of previous window */ if (lastFile && window->shell != lastFile->shell) { CleanUpTabBarExposeQueue(lastFile); RaiseDocument(lastFile); } if (!macroFileRead) { ReadMacroInitFile(WindowList); macroFileRead = True; } if (gotoLine) SelectNumberedLine(window, lineNum); if (toDoCommand != NULL) { DoMacro(window, toDoCommand, "-do macro"); toDoCommand = NULL; if (!IsValidWindow(window)) window = NULL; /* window closed by macro */ if (lastFile && !IsValidWindow(lastFile)) lastFile = NULL; /* window closed by macro */ } } /* register last opened file for later use */ if (window) lastFile = window; } else { fprintf(stderr, "nedit: file name too long: %s\n", argv[i]); } #endif /*VMS*/ } } #ifdef VMS VMSFileScanDone(); #endif /*VMS*/ /* Raise the last file opened */ if (lastFile) { CleanUpTabBarExposeQueue(lastFile); RaiseDocument(lastFile); } CheckCloseDim(); /* If no file to edit was specified, open a window to edit "Untitled" */ if (!fileSpecified) { EditNewFile(NULL, geometry, iconic, langMode, NULL); ReadMacroInitFile(WindowList); CheckCloseDim(); if (toDoCommand != NULL) DoMacro(WindowList, toDoCommand, "-do macro"); } /* Begin remembering last command invoked for "Repeat" menu item */ AddLastCommandActionHook(context); /* Set up communication port and write ~/.nedit_server_process file */ if (IsServer) InitServerCommunication(); /* Process events. */ if (IsServer) ServerMainLoop(context); else XtAppMainLoop(context); /* Not reached but this keeps some picky compilers happy */ return EXIT_SUCCESS; } static void nextArg(int argc, char **argv, int *argIndex) { if (*argIndex + 1 >= argc) { #ifdef VMS *argv[*argIndex] = '/'; #endif /*VMS*/ fprintf(stderr, "NEdit: %s requires an argument\n%s", argv[*argIndex], cmdLineHelp); exit(EXIT_FAILURE); } (*argIndex)++; } /* ** Return True if -do macro is valid, otherwise write an error on stderr */ static int checkDoMacroArg(const char *macro) { Program *prog; char *errMsg, *stoppedAt, *tMacro; int macroLen; /* Add a terminating newline (which command line users are likely to omit since they are typically invoking a single routine) */ macroLen = strlen(macro); tMacro = XtMalloc(strlen(macro)+2); strncpy(tMacro, macro, macroLen); tMacro[macroLen] = '\n'; tMacro[macroLen+1] = '\0'; /* Do a test parse */ prog = ParseMacro(tMacro, &errMsg, &stoppedAt); XtFree(tMacro); if (prog == NULL) { ParseError(NULL, tMacro, stoppedAt, "argument to -do", errMsg); return False; } FreeProgram(prog); return True; } /* ** maskArgvKeywords and unmaskArgvKeywords mangle selected keywords by ** replacing the '-' with a space, for the purpose of hiding them from ** XtOpenDisplay's option processing. Why this silly scheme? XtOpenDisplay ** really needs to see command line arguments, particularly -display, but ** there's no way to change the option processing table it uses, to keep ** it from consuming arguments which are meant to apply per-window, like ** -geometry and -iconic. */ static void maskArgvKeywords(int argc, char **argv, const char **maskArgs) { int i, k; for (i=1; i= 2003) const char *ctype; char ctypebuf[1024]; char *utf_start; /* We have to check LC_CTYPE specifically here, because the system might specify different locales for different categories (why anyone would want to do this is beyond me). As far as I can tell, only LC_CTYPE causes OSF Motif to crash. If it turns out others do, we'll have to iterate over a list of locale cateogries and patch every one of them. */ ctype = setlocale(LC_CTYPE, NULL); if (!ctype) return; strncpy(ctypebuf, ctype, sizeof ctypebuf); if ((utf_start = strstr(ctypebuf, ".utf8")) || (utf_start = strstr(ctypebuf, ".UTF-8"))) { *utf_start = '\0'; /* Samurai chop */ setlocale(LC_CTYPE, ctypebuf); } #endif } /* ** Same as the default X language procedure, except we check if Motif can ** handle the locale as well. */ static String neditLanguageProc(Display *dpy, String xnl, XtPointer closure) { /* "xnl" will be set if the user passes in a new language via the "-xnllanguage" flag. If it's empty, then setlocale will get the default locale by some system-dependent means (usually, reading some environment variables). */ if (! setlocale(LC_ALL, xnl)) { XtWarning("locale not supported by C library, locale unchanged"); } patchLocaleForMotif(); if (! XSupportsLocale()) { XtWarning("locale not supported by Xlib, locale set to C"); setlocale(LC_ALL, "C"); } if (! XSetLocaleModifiers("")) XtWarning("X locale modifiers not supported, using default"); return setlocale(LC_ALL, NULL); /* re-query in case overwritten */ } static int sortAlphabetical(const void* k1, const void* k2) { const char* key1 = *(const char**)k1; const char* key2 = *(const char**)k2; return strcmp(key1, key2); } /* * Checks whether a given virtual key binding string is invalid. * A binding is considered invalid if there are duplicate key entries. */ static int virtKeyBindingsAreInvalid(const unsigned char* bindings) { int maxCount = 1, i, count; const char *pos = (const char*)bindings; char *copy; char *pos2, *pos3; char **keys; /* First count the number of bindings; bindings are separated by \n strings. The number of bindings equals the number of \n + 1. Beware of leading and trailing \n; the number is actually an upper bound on the number of entries. */ while ((pos = strstr(pos, "\n"))) { ++pos; ++maxCount; } if (maxCount == 1) return False; /* One binding is always ok */ keys = (char**)malloc(maxCount*sizeof(char*)); copy = XtNewString((const char*)bindings); i = 0; pos2 = copy; count = 0; while (i #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #define NEDIT_VERSION 5 #define NEDIT_REVISION 5 /* Some default colors */ #define NEDIT_DEFAULT_FG "black" #define NEDIT_DEFAULT_TEXT_BG "rgb:e5/e5/e5" #define NEDIT_DEFAULT_SEL_FG "black" #define NEDIT_DEFAULT_SEL_BG "rgb:cc/cc/cc" #define NEDIT_DEFAULT_HI_FG "white" /* These are colors for flashing */ #define NEDIT_DEFAULT_HI_BG "red" /* matching parens. */ #define NEDIT_DEFAULT_LINENO_FG "black" #define NEDIT_DEFAULT_CURSOR_FG "black" #define NEDIT_DEFAULT_HELP_FG "black" #define NEDIT_DEFAULT_HELP_BG "rgb:cc/cc/cc" /* Tuning parameters */ #define SEARCHMAX 5119 /* Maximum length of search/replace strings */ #define MAX_SEARCH_HISTORY 100 /* Maximum length of search string history */ #define MAX_PANES 6 /* Max # of ADDITIONAL text editing panes that can be added to a window */ #ifndef VMS #define AUTOSAVE_CHAR_LIMIT 30 /* number of characters user can type before NEdit generates a new backup file */ #else #define AUTOSAVE_CHAR_LIMIT 80 /* set higher on VMS becaus saving is slower */ #endif /*VMS*/ #define AUTOSAVE_OP_LIMIT 8 /* number of distinct editing operations user can do before NEdit gens. new backup file */ #define MAX_FONT_LEN 100 /* maximum length for a font name */ #define MAX_COLOR_LEN 30 /* maximum length for a color name */ #define MAX_MARKS 36 /* max. # of bookmarks (one per letter & #) */ #define MIN_LINE_NUM_COLS 4 /* Min. # of columns in line number display */ #define APP_NAME "nedit" /* application name for loading resources */ #define APP_CLASS "NEdit" /* application class for loading resources */ /* The accumulated list of undo operations can potentially consume huge amounts of memory. These tuning parameters determine how much undo infor- mation is retained. Normally, the list is kept between UNDO_OP_LIMIT and UNDO_OP_TRIMTO in length (when the list reaches UNDO_OP_LIMIT, it is trimmed to UNDO_OP_TRIMTO then allowed to grow back to UNDO_OP_LIMIT). When there are very large amounts of saved text held in the list, UNDO_WORRY_LIMIT and UNDO_PURGE_LIMIT take over and cause the list to be trimmed back further to keep its size down. */ #define UNDO_PURGE_LIMIT 15000000 /* If undo list gets this large (in bytes), trim it to length of UNDO_PURGE_TRIMTO */ #define UNDO_PURGE_TRIMTO 1 /* Amount to trim the undo list in a purge */ #define UNDO_WORRY_LIMIT 2000000 /* If undo list gets this large (in bytes), trim it to length of UNDO_WORRY_TRIMTO */ #define UNDO_WORRY_TRIMTO 5 /* Amount to trim the undo list when memory use begins to get serious */ #define UNDO_OP_LIMIT 400 /* normal limit for length of undo list */ #define UNDO_OP_TRIMTO 200 /* size undo list is normally trimmed to when it exceeds UNDO_OP_TRIMTO in length */ #ifdef SGI_CUSTOM #define MAX_SHORTENED_ITEMS 100 /* max. number of items excluded in short- */ #endif /* menus mode */ enum indentStyle {NO_AUTO_INDENT, AUTO_INDENT, SMART_INDENT}; enum wrapStyle {NO_WRAP, NEWLINE_WRAP, CONTINUOUS_WRAP}; enum showMatchingStyle {NO_FLASH, FLASH_DELIMIT, FLASH_RANGE}; enum virtKeyOverride { VIRT_KEY_OVERRIDE_NEVER, VIRT_KEY_OVERRIDE_AUTO, VIRT_KEY_OVERRIDE_ALWAYS }; /* This enum must be kept in parallel to the array TruncSubstitutionModes[] in preferences.c */ enum truncSubstitution {TRUNCSUBST_SILENT, TRUNCSUBST_FAIL, TRUNCSUBST_WARN, TRUNCSUBST_IGNORE}; #define NO_FLASH_STRING "off" #define FLASH_DELIMIT_STRING "delimiter" #define FLASH_RANGE_STRING "range" #define CHARSET (XmStringCharSet)XmSTRING_DEFAULT_CHARSET #define MKSTRING(string) \ XmStringCreateLtoR(string, XmSTRING_DEFAULT_CHARSET) #define SET_ONE_RSRC(widget, name, newValue) \ { \ static Arg args[1] = {{name, (XtArgVal)0}}; \ args[0].value = (XtArgVal)newValue; \ XtSetValues(widget, args, 1); \ } #define GET_ONE_RSRC(widget, name, valueAddr) \ { \ static Arg args[1] = {{name, (XtArgVal)0}}; \ args[0].value = (XtArgVal)valueAddr; \ XtGetValues(widget, args, 1); \ } /* This handles all the different reasons files can be locked */ #define USER_LOCKED_BIT 0 #define PERM_LOCKED_BIT 1 #define TOO_MUCH_BINARY_DATA_LOCKED_BIT 2 #define LOCKED_BIT_TO_MASK(bitNum) (1 << (bitNum)) #define SET_LOCKED_BY_REASON(reasons, onOrOff, reasonBit) ((onOrOff) ? \ ((reasons) |= LOCKED_BIT_TO_MASK(reasonBit)) : \ ((reasons) &= ~LOCKED_BIT_TO_MASK(reasonBit))) #define IS_USER_LOCKED(reasons) (((reasons) & LOCKED_BIT_TO_MASK(USER_LOCKED_BIT)) != 0) #define SET_USER_LOCKED(reasons, onOrOff) SET_LOCKED_BY_REASON(reasons, onOrOff, USER_LOCKED_BIT) #define IS_PERM_LOCKED(reasons) (((reasons) & LOCKED_BIT_TO_MASK(PERM_LOCKED_BIT)) != 0) #define SET_PERM_LOCKED(reasons, onOrOff) SET_LOCKED_BY_REASON(reasons, onOrOff, PERM_LOCKED_BIT) #define IS_TMBD_LOCKED(reasons) (((reasons) & LOCKED_BIT_TO_MASK(TOO_MUCH_BINARY_DATA_LOCKED_BIT)) != 0) #define SET_TMBD_LOCKED(reasons, onOrOff) SET_LOCKED_BY_REASON(reasons, onOrOff, TOO_MUCH_BINARY_DATA_LOCKED_BIT) #define IS_ANY_LOCKED_IGNORING_USER(reasons) (((reasons) & ~LOCKED_BIT_TO_MASK(USER_LOCKED_BIT)) != 0) #define IS_ANY_LOCKED_IGNORING_PERM(reasons) (((reasons) & ~LOCKED_BIT_TO_MASK(PERM_LOCKED_BIT)) != 0) #define IS_ANY_LOCKED(reasons) ((reasons) != 0) #define CLEAR_ALL_LOCKS(reasons) ((reasons) = 0) /* determine a safe size for a string to hold an integer-like number contained in xType */ #define TYPE_INT_STR_SIZE(xType) ((sizeof(xType) * 3) + 2) /* Record on undo list */ typedef struct _UndoInfo { struct _UndoInfo *next; /* pointer to the next undo record */ int type; int startPos; int endPos; int oldLen; char *oldText; char inUndo; /* flag to indicate undo command on this record in progress. Redirects SaveUndoInfo to save the next mod- ifications on the redo list instead of the undo list. */ char restoresToSaved; /* flag to indicate undoing this operation will restore file to last saved (unmodified) state */ } UndoInfo; /* Element in bookmark table */ typedef struct { char label; int cursorPos; selection sel; } Bookmark; /* Identifiers for the different colors that can be adjusted. */ enum colorTypes { TEXT_FG_COLOR, TEXT_BG_COLOR, SELECT_FG_COLOR, SELECT_BG_COLOR, HILITE_FG_COLOR, HILITE_BG_COLOR, LINENO_FG_COLOR, CURSOR_FG_COLOR, NUM_COLORS }; /* cache user menus: manage mode of user menu list element */ typedef enum { UMMM_UNMANAGE, /* user menu item is unmanaged */ UMMM_UNMANAGE_ALL, /* user menu item is a sub menu and is completely unmanaged (including nested sub menus) */ UMMM_MANAGE, /* user menu item is managed; menu items of potential sub menu are (un)managed individually */ UMMM_MANAGE_ALL /* user menu item is a sub menu and is completely managed */ } UserMenuManageMode; /* structure representing one user menu item */ typedef struct _UserMenuListElement { UserMenuManageMode umleManageMode; /* current manage mode */ UserMenuManageMode umlePrevManageMode; /* previous manage mode */ char *umleAccKeys; /* accelerator keys of item */ Boolean umleAccLockPatchApplied; /* indicates, if accelerator lock patch is applied */ Widget umleMenuItem; /* menu item represented by this element */ Widget umleSubMenuPane; /* holds menu pane, if item represents a sub menu */ struct _UserMenuList *umleSubMenuList; /* elements of sub menu, if item represents a sub menu */ } UserMenuListElement; /* structure holding a list of user menu items */ typedef struct _UserMenuList { int umlNbrItems; UserMenuListElement **umlItems; } UserMenuList; /* structure holding cache info about Shell and Macro menus, which are shared over all "tabbed" documents (needed to manage/unmanage this user definable menus when language mode changes) */ typedef struct _UserMenuCache { int umcLanguageMode; /* language mode applied for shared user menus */ Boolean umcShellMenuCreated; /* indicating, if all shell menu items were created */ Boolean umcMacroMenuCreated; /* indicating, if all macro menu items were created */ UserMenuList umcShellMenuList; /* list of all shell menu items */ UserMenuList umcMacroMenuList; /* list of all macro menu items */ } UserMenuCache; /* structure holding cache info about Background menu, which is owned by each document individually (needed to manage/unmanage this user definable menu when language mode changes) */ typedef struct _UserBGMenuCache { int ubmcLanguageMode; /* language mode applied for background user menu */ Boolean ubmcMenuCreated; /* indicating, if all background menu items were created */ UserMenuList ubmcMenuList; /* list of all background menu items */ } UserBGMenuCache; /* The WindowInfo structure holds the information on a Document. A number of 'tabbed' documents may reside within a shell window, hence some of its members are of 'shell-level'; namely the find/replace dialogs, the menu bar & its associated members, the components on the stats area (i-search line, statsline and tab bar), plus probably a few others. See CreateWindow() and CreateDocument() for more info. Each document actually 'lives' within its splitPane widget member, which can be raised to become the 'top' (visible) document by function RaiseDocument(). The non-top documents may still be accessed through macros, or the context menu on the tab bar. Prior to the introduction of tabbed mode, each window may house only one document, making it effectively an 'editor window', hence the name WindowInfo. This struct name has been preserved to ease the transition when tabbed mode was introduced after NEdit 5.4. */ typedef struct _WindowInfo { struct _WindowInfo *next; Widget shell; /* application shell of window */ Widget mainWin; /* main window of shell */ Widget splitPane; /* paned win. for splitting text area */ Widget textArea; /* the first text editing area widget */ Widget textPanes[MAX_PANES]; /* additional ones created on demand */ Widget lastFocus; /* the last pane to have kbd. focus */ Widget statsLine; /* file stats information display */ Widget statsLineForm; Widget statsLineColNo; /* Line/Column information display */ Widget iSearchForm; /* incremental search line widgets */ Widget iSearchFindButton; Widget iSearchText; Widget iSearchClearButton; Widget iSearchRegexToggle; Widget iSearchCaseToggle; Widget iSearchRevToggle; Widget menuBar; /* the main menu bar */ Widget tabBar; /* tab bar for tabbed window */ Widget tab; /* tab for this document */ Widget replaceDlog; /* replace dialog */ Widget replaceText; /* replace dialog settable widgets... */ Widget replaceWithText; Widget replaceCaseToggle; Widget replaceWordToggle; Widget replaceRegexToggle; Widget replaceRevToggle; Widget replaceKeepBtn; Widget replaceBtns; Widget replaceBtn; Widget replaceAllBtn; #ifndef REPLACE_SCOPE Widget replaceInWinBtn; Widget replaceInSelBtn; #endif Widget replaceSearchTypeBox; Widget replaceFindBtn; Widget replaceAndFindBtn; Widget findDlog; /* find dialog */ Widget findText; /* find dialog settable widgets... */ Widget findCaseToggle; Widget findWordToggle; Widget findRegexToggle; Widget findRevToggle; Widget findKeepBtn; Widget findBtns; Widget findBtn; Widget findSearchTypeBox; Widget replaceMultiFileDlog; /* Replace in multiple files */ Widget replaceMultiFileList; Widget replaceMultiFilePathBtn; Widget fontDialog; /* NULL, unless font dialog is up */ Widget colorDialog; /* NULL, unless color dialog is up */ Widget readOnlyItem; /* menu bar settable widgets... */ Widget autoSaveItem; Widget saveLastItem; Widget openSelItem; Widget newOppositeItem; Widget closeItem; Widget printSelItem; Widget undoItem; Widget redoItem; Widget cutItem; Widget delItem; Widget copyItem; Widget lowerItem; Widget upperItem; Widget findSelItem; Widget findAgainItem; Widget replaceFindAgainItem; Widget replaceAgainItem; Widget gotoSelItem; Widget langModeCascade; Widget findDefItem; Widget showTipItem; Widget autoIndentOffItem; Widget autoIndentItem; Widget smartIndentItem; Widget noWrapItem; Widget newlineWrapItem; Widget continuousWrapItem; Widget statsLineItem; Widget iSearchLineItem; Widget lineNumsItem; Widget showMatchingOffItem; Widget showMatchingDelimitItem; Widget showMatchingRangeItem; Widget matchSyntaxBasedItem; Widget overtypeModeItem; Widget highlightItem; Widget windowMenuPane; Widget shellMenuPane; Widget macroMenuPane; Widget bgMenuPane; Widget tabMenuPane; Widget prevOpenMenuPane; Widget prevOpenMenuItem; Widget unloadTagsMenuPane; Widget unloadTagsMenuItem; Widget unloadTipsMenuPane; Widget unloadTipsMenuItem; Widget filterItem; Widget autoIndentOffDefItem; Widget autoIndentDefItem; Widget smartIndentDefItem; Widget autoSaveDefItem; Widget saveLastDefItem; Widget noWrapDefItem; Widget newlineWrapDefItem; Widget contWrapDefItem; Widget showMatchingOffDefItem; Widget showMatchingDelimitDefItem; Widget showMatchingRangeDefItem; Widget matchSyntaxBasedDefItem; Widget highlightOffDefItem; Widget highlightDefItem; Widget backlightCharsItem; Widget backlightCharsDefItem; Widget searchDlogsDefItem; Widget beepOnSearchWrapDefItem; Widget keepSearchDlogsDefItem; Widget searchWrapsDefItem; Widget appendLFItem; Widget sortOpenPrevDefItem; Widget allTagsDefItem; Widget smartTagsDefItem; Widget reposDlogsDefItem; Widget autoScrollDefItem; Widget openInTabDefItem; Widget tabBarDefItem; Widget tabBarHideDefItem; Widget toolTipsDefItem; Widget tabNavigateDefItem; Widget tabSortDefItem; Widget statsLineDefItem; Widget iSearchLineDefItem; Widget lineNumsDefItem; Widget pathInWindowsMenuDefItem; Widget modWarnDefItem; Widget modWarnRealDefItem; Widget exitWarnDefItem; Widget searchLiteralDefItem; Widget searchCaseSenseDefItem; Widget searchLiteralWordDefItem; Widget searchCaseSenseWordDefItem; Widget searchRegexNoCaseDefItem; Widget searchRegexDefItem; #ifdef REPLACE_SCOPE Widget replScopeWinDefItem; Widget replScopeSelDefItem; Widget replScopeSmartDefItem; #endif Widget size24x80DefItem; Widget size40x80DefItem; Widget size60x80DefItem; Widget size80x80DefItem; Widget sizeCustomDefItem; Widget cancelShellItem; Widget learnItem; Widget finishLearnItem; Widget cancelMacroItem; Widget replayItem; Widget repeatItem; Widget splitPaneItem; Widget closePaneItem; Widget detachDocumentItem; Widget moveDocumentItem; Widget contextMoveDocumentItem; Widget contextDetachDocumentItem; Widget bgMenuUndoItem; Widget bgMenuRedoItem; #ifdef SGI_CUSTOM Widget shortMenusDefItem; Widget toggleShortItems[MAX_SHORTENED_ITEMS]; /* Menu items to be managed and unmanaged to toggle short menus on and off */ int nToggleShortItems; #endif char filename[MAXPATHLEN]; /* name component of file being edited*/ char path[MAXPATHLEN]; /* path component of file being edited*/ unsigned fileMode; /* permissions of file being edited */ uid_t fileUid; /* last recorded user id of the file */ gid_t fileGid; /* last recorded group id of the file */ int fileFormat; /* whether to save the file straight (Unix format), or convert it to MS DOS style with \r\n line breaks */ time_t lastModTime; /* time of last modification to file */ dev_t device; /* device where the file resides */ ino_t inode; /* file's inode */ UndoInfo *undo; /* info for undoing last operation */ UndoInfo *redo; /* info for redoing last undone op */ textBuffer *buffer; /* holds the text being edited */ int nPanes; /* number of additional text editing areas, created by splitWindow */ int autoSaveCharCount; /* count of single characters typed since last backup file generated */ int autoSaveOpCount; /* count of editing operations "" */ int undoOpCount; /* count of stored undo operations */ int undoMemUsed; /* amount of memory (in bytes) dedicated to the undo list */ char fontName[MAX_FONT_LEN]; /* names of the text fonts in use */ char italicFontName[MAX_FONT_LEN]; char boldFontName[MAX_FONT_LEN]; char boldItalicFontName[MAX_FONT_LEN]; XmFontList fontList; /* fontList for the primary font */ XFontStruct *italicFontStruct; /* fontStructs for highlighting fonts */ XFontStruct *boldFontStruct; XFontStruct *boldItalicFontStruct; XtIntervalId flashTimeoutID; /* timer procedure id for getting rid of highlighted matching paren. Non- zero val. means highlight is drawn */ int flashPos; /* position saved for erasing matching paren highlight (if one is drawn) */ int wasSelected; /* last selection state (for dim/undim of selection related menu items */ Boolean filenameSet; /* is the window still "Untitled"? */ Boolean fileChanged; /* has window been modified? */ Boolean fileMissing; /* is the window's file gone? */ int lockReasons; /* all ways a file can be locked */ Boolean autoSave; /* is autosave turned on? */ Boolean saveOldVersion; /* keep old version in filename.bck */ char indentStyle; /* whether/how to auto indent */ char wrapMode; /* line wrap style: NO_WRAP, NEWLINE_WRAP or CONTINUOUS_WRAP */ Boolean overstrike; /* is overstrike mode turned on ? */ char showMatchingStyle; /* How to show matching parens: NO_FLASH, FLASH_DELIMIT, or FLASH_RANGE */ char matchSyntaxBased; /* Use syntax info to show matching */ Boolean showStats; /* is stats line supposed to be shown */ Boolean showISearchLine; /* is incr. search line to be shown */ Boolean showLineNumbers; /* is the line number display shown */ Boolean highlightSyntax; /* is syntax highlighting turned on? */ Boolean backlightChars; /* is char backlighting turned on? */ char *backlightCharTypes; /* what backlighting to use */ Boolean modeMessageDisplayed; /* special stats line banner for learn and shell command executing modes */ char *modeMessage; /* stats line banner content for learn and shell command executing modes */ Boolean ignoreModify; /* ignore modifications to text area */ Boolean windowMenuValid; /* is window menu up to date? */ int rHistIndex, fHistIndex; /* history placeholders for */ int iSearchHistIndex; /* find and replace dialogs */ int iSearchStartPos; /* start pos. of current incr. search */ int iSearchLastBeginPos; /* beg. pos. last match of current i.s.*/ int nMarks; /* number of active bookmarks */ XtIntervalId markTimeoutID; /* backup timer for mark event handler*/ Bookmark markTable[MAX_MARKS]; /* marked locations in window */ void *highlightData; /* info for syntax highlighting */ void *shellCmdData; /* when a shell command is executing, info. about it, otherwise, NULL */ void *macroCmdData; /* same for macro commands */ void *smartIndentData; /* compiled macros for smart indent */ Atom fileClosedAtom; /* Atom used to tell nc that the file is closed */ int languageMode; /* identifies language mode currently selected in the window */ Boolean multiFileReplSelected; /* selected during last multi-window replacement operation (history) */ struct _WindowInfo** /* temporary list of writable windows */ writableWindows; /* used during multi-file replacements */ int nWritableWindows; /* number of elements in the list */ Bool multiFileBusy; /* suppresses multiple beeps/dialogs during multi-file replacements */ Bool replaceFailed; /* flags replacements failures during multi-file replacements */ Bool replaceLastRegexCase; /* last state of the case sense button in regex mode for replace dialog */ Bool replaceLastLiteralCase; /* idem, for literal mode */ Bool iSearchLastRegexCase; /* idem, for regex mode in incremental search bar */ Bool iSearchLastLiteralCase; /* idem, for literal mode */ Bool findLastRegexCase; /* idem, for regex mode in find dialog */ Bool findLastLiteralCase; /* idem, for literal mode */ #ifdef REPLACE_SCOPE int replaceScope; /* Current scope for replace dialog */ Widget replaceScopeWinToggle; /* Scope for replace = window */ Widget replaceScopeSelToggle; /* Scope for replace = selection */ Widget replaceScopeMultiToggle;/* Scope for replace = multiple files */ #endif UserMenuCache *userMenuCache; /* cache user menus: */ UserBGMenuCache userBGMenuCache; /* shell & macro menu are shared over all "tabbed" documents, while each document has its own background menu. */ } WindowInfo; extern WindowInfo *WindowList; extern Display *TheDisplay; extern Widget TheAppShell; extern char *ArgV0; extern Boolean IsServer; #endif /* NEDIT_NEDIT_H_INCLUDED */ nedit-5.6.orig/source/nedit_options_file.opt0000644000175000017500000000033507246564333020030 0ustar paulpaul! $Id: nedit_options_file.opt,v 1.2 2001/02/26 23:38:03 edg Exp $ SYS$SHARE:DECC$SHR.EXE/SHARE sys$share:decw$xlibshr/share SYS$SHARE:DECW$XTLIBSHRR5/SHARE SYS$SHARE:DECW$XMLIBSHR12/SHARE SYS$SHARE:DECW$DXMLIBSHR12/SHARE nedit-5.6.orig/source/parse.h0000644000175000017500000000433710144236624014706 0ustar paulpaul/* $Id: parse.h,v 1.7 2004/11/09 21:58:44 yooden Exp $ */ /******************************************************************************* * * * parse.h -- Nirvana Editor Macro Parsing Header File * * * * Copyright 2002 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_PARSE_H_INCLUDED #define NEDIT_PARSE_H_INCLUDED #include "interpret.h" Program *ParseMacro(char *expr, char **msg, char **stoppedAt); #endif /* NEDIT_PARSE_H_INCLUDED */ nedit-5.6.orig/source/parse.y0000644000175000017500000006364310551732246014737 0ustar paulpaul/* $Id: parse.y,v 1.29 2007/01/12 16:17:42 tringali Exp $ */ %{ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "parse.h" #include "textBuf.h" #include "nedit.h" #include "rbTree.h" #include "interpret.h" #include #include #include #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #ifdef HAVE_DEBUG_H #include "../debug.h" #endif /* Macros to add error processing to AddOp and AddSym calls */ #define ADD_OP(op) if (!AddOp(op, &ErrMsg)) return 1 #define ADD_SYM(sym) if (!AddSym(sym, &ErrMsg)) return 1 #define ADD_IMMED(val) if (!AddImmediate(val, &ErrMsg)) return 1 #define ADD_BR_OFF(to) if (!AddBranchOffset(to, &ErrMsg)) return 1 #define SET_BR_OFF(from, to) ((from)->value) = ((Inst *)(to)) - ((Inst *)(from)) /* Max. length for a string constant (... there shouldn't be a maximum) */ #define MAX_STRING_CONST_LEN 5000 static const char CVSID[] = "$Id: parse.y,v 1.29 2007/01/12 16:17:42 tringali Exp $"; static int yyerror(char *s); static int yylex(void); int yyparse(void); static int follow(char expect, int yes, int no); static int follow2(char expect1, int yes1, char expect2, int yes2, int no); static int follow_non_whitespace(char expect, int yes, int no); static Symbol *matchesActionRoutine(char **inPtr); static char *ErrMsg; static char *InPtr; extern Inst *LoopStack[]; /* addresses of break, cont stmts */ extern Inst **LoopStackPtr; /* to fill at the end of a loop */ %} %union { Symbol *sym; Inst *inst; int nArgs; } %token NUMBER STRING SYMBOL %token DELETE ARG_LOOKUP %token IF WHILE ELSE FOR BREAK CONTINUE RETURN %type arglist %type cond comastmts for while else and or arrayexpr %type evalsym %nonassoc IF_NO_ELSE %nonassoc ELSE %nonassoc SYMBOL ARG_LOOKUP %right '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ ANDEQ OREQ %left CONCAT %left OR %left AND %left '|' %left '&' %left GT GE LT LE EQ NE IN %left '+' '-' %left '*' '/' '%' %nonassoc UNARY_MINUS NOT %nonassoc DELETE %nonassoc INCR DECR %right POW %nonassoc '[' %nonassoc '(' %% /* Rules */ program: blank stmts { ADD_OP(OP_RETURN_NO_VAL); return 0; } | blank '{' blank stmts '}' { ADD_OP(OP_RETURN_NO_VAL); return 0; } | blank '{' blank '}' { ADD_OP(OP_RETURN_NO_VAL); return 0; } | error { return 1; } ; block: '{' blank stmts '}' blank | '{' blank '}' blank | stmt ; stmts: stmt | stmts stmt ; stmt: simpstmt '\n' blank | IF '(' cond ')' blank block %prec IF_NO_ELSE { SET_BR_OFF($3, GetPC()); } | IF '(' cond ')' blank block else blank block %prec ELSE { SET_BR_OFF($3, ($7+1)); SET_BR_OFF($7, GetPC()); } | while '(' cond ')' blank block { ADD_OP(OP_BRANCH); ADD_BR_OFF($1); SET_BR_OFF($3, GetPC()); FillLoopAddrs(GetPC(), $1); } | for '(' comastmts ';' cond ';' comastmts ')' blank block { FillLoopAddrs(GetPC()+2+($7-($5+1)), GetPC()); SwapCode($5+1, $7, GetPC()); ADD_OP(OP_BRANCH); ADD_BR_OFF($3); SET_BR_OFF($5, GetPC()); } | for '(' SYMBOL IN arrayexpr ')' { Symbol *iterSym = InstallIteratorSymbol(); ADD_OP(OP_BEGIN_ARRAY_ITER); ADD_SYM(iterSym); ADD_OP(OP_ARRAY_ITER); ADD_SYM($3); ADD_SYM(iterSym); ADD_BR_OFF(0); } blank block { ADD_OP(OP_BRANCH); ADD_BR_OFF($5+2); SET_BR_OFF($5+5, GetPC()); FillLoopAddrs(GetPC(), $5+2); } | BREAK '\n' blank { ADD_OP(OP_BRANCH); ADD_BR_OFF(0); if (AddBreakAddr(GetPC()-1)) { yyerror("break outside loop"); YYERROR; } } | CONTINUE '\n' blank { ADD_OP(OP_BRANCH); ADD_BR_OFF(0); if (AddContinueAddr(GetPC()-1)) { yyerror("continue outside loop"); YYERROR; } } | RETURN expr '\n' blank { ADD_OP(OP_RETURN); } | RETURN '\n' blank { ADD_OP(OP_RETURN_NO_VAL); } ; simpstmt: SYMBOL '=' expr { ADD_OP(OP_ASSIGN); ADD_SYM($1); } | evalsym ADDEQ expr { ADD_OP(OP_ADD); ADD_OP(OP_ASSIGN); ADD_SYM($1); } | evalsym SUBEQ expr { ADD_OP(OP_SUB); ADD_OP(OP_ASSIGN); ADD_SYM($1); } | evalsym MULEQ expr { ADD_OP(OP_MUL); ADD_OP(OP_ASSIGN); ADD_SYM($1); } | evalsym DIVEQ expr { ADD_OP(OP_DIV); ADD_OP(OP_ASSIGN); ADD_SYM($1); } | evalsym MODEQ expr { ADD_OP(OP_MOD); ADD_OP(OP_ASSIGN); ADD_SYM($1); } | evalsym ANDEQ expr { ADD_OP(OP_BIT_AND); ADD_OP(OP_ASSIGN); ADD_SYM($1); } | evalsym OREQ expr { ADD_OP(OP_BIT_OR); ADD_OP(OP_ASSIGN); ADD_SYM($1); } | DELETE arraylv '[' arglist ']' { ADD_OP(OP_ARRAY_DELETE); ADD_IMMED($4); } | initarraylv '[' arglist ']' '=' expr { ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED($3); } | initarraylv '[' arglist ']' ADDEQ expr { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(1); ADD_IMMED($3); ADD_OP(OP_ADD); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED($3); } | initarraylv '[' arglist ']' SUBEQ expr { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(1); ADD_IMMED($3); ADD_OP(OP_SUB); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED($3); } | initarraylv '[' arglist ']' MULEQ expr { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(1); ADD_IMMED($3); ADD_OP(OP_MUL); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED($3); } | initarraylv '[' arglist ']' DIVEQ expr { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(1); ADD_IMMED($3); ADD_OP(OP_DIV); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED($3); } | initarraylv '[' arglist ']' MODEQ expr { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(1); ADD_IMMED($3); ADD_OP(OP_MOD); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED($3); } | initarraylv '[' arglist ']' ANDEQ expr { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(1); ADD_IMMED($3); ADD_OP(OP_BIT_AND); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED($3); } | initarraylv '[' arglist ']' OREQ expr { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(1); ADD_IMMED($3); ADD_OP(OP_BIT_OR); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED($3); } | initarraylv '[' arglist ']' INCR { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(0); ADD_IMMED($3); ADD_OP(OP_INCR); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED($3); } | initarraylv '[' arglist ']' DECR { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(0); ADD_IMMED($3); ADD_OP(OP_DECR); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED($3); } | INCR initarraylv '[' arglist ']' { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(0); ADD_IMMED($4); ADD_OP(OP_INCR); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED($4); } | DECR initarraylv '[' arglist ']' { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(0); ADD_IMMED($4); ADD_OP(OP_DECR); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED($4); } | SYMBOL '(' arglist ')' { ADD_OP(OP_SUBR_CALL); ADD_SYM(PromoteToGlobal($1)); ADD_IMMED($3); } | INCR SYMBOL { ADD_OP(OP_PUSH_SYM); ADD_SYM($2); ADD_OP(OP_INCR); ADD_OP(OP_ASSIGN); ADD_SYM($2); } | SYMBOL INCR { ADD_OP(OP_PUSH_SYM); ADD_SYM($1); ADD_OP(OP_INCR); ADD_OP(OP_ASSIGN); ADD_SYM($1); } | DECR SYMBOL { ADD_OP(OP_PUSH_SYM); ADD_SYM($2); ADD_OP(OP_DECR); ADD_OP(OP_ASSIGN); ADD_SYM($2); } | SYMBOL DECR { ADD_OP(OP_PUSH_SYM); ADD_SYM($1); ADD_OP(OP_DECR); ADD_OP(OP_ASSIGN); ADD_SYM($1); } ; evalsym: SYMBOL { $$ = $1; ADD_OP(OP_PUSH_SYM); ADD_SYM($1); } ; comastmts: /* nothing */ { $$ = GetPC(); } | simpstmt { $$ = GetPC(); } | comastmts ',' simpstmt { $$ = GetPC(); } ; arglist: /* nothing */ { $$ = 0; } | expr { $$ = 1; } | arglist ',' expr { $$ = $1 + 1; } ; expr: numexpr %prec CONCAT | expr numexpr %prec CONCAT { ADD_OP(OP_CONCAT); } ; initarraylv: SYMBOL { ADD_OP(OP_PUSH_ARRAY_SYM); ADD_SYM($1); ADD_IMMED(1); } | initarraylv '[' arglist ']' { ADD_OP(OP_ARRAY_REF); ADD_IMMED($3); } ; arraylv: SYMBOL { ADD_OP(OP_PUSH_ARRAY_SYM); ADD_SYM($1); ADD_IMMED(0); } | arraylv '[' arglist ']' { ADD_OP(OP_ARRAY_REF); ADD_IMMED($3); } ; arrayexpr: numexpr { $$ = GetPC(); } ; numexpr: NUMBER { ADD_OP(OP_PUSH_SYM); ADD_SYM($1); } | STRING { ADD_OP(OP_PUSH_SYM); ADD_SYM($1); } | SYMBOL { ADD_OP(OP_PUSH_SYM); ADD_SYM($1); } | SYMBOL '(' arglist ')' { ADD_OP(OP_SUBR_CALL); ADD_SYM(PromoteToGlobal($1)); ADD_IMMED($3); ADD_OP(OP_FETCH_RET_VAL); } | '(' expr ')' | ARG_LOOKUP '[' numexpr ']' { ADD_OP(OP_PUSH_ARG); } | ARG_LOOKUP '[' ']' { ADD_OP(OP_PUSH_ARG_COUNT); } | ARG_LOOKUP { ADD_OP(OP_PUSH_ARG_ARRAY); } | numexpr '[' arglist ']' { ADD_OP(OP_ARRAY_REF); ADD_IMMED($3); } | numexpr '+' numexpr { ADD_OP(OP_ADD); } | numexpr '-' numexpr { ADD_OP(OP_SUB); } | numexpr '*' numexpr { ADD_OP(OP_MUL); } | numexpr '/' numexpr { ADD_OP(OP_DIV); } | numexpr '%' numexpr { ADD_OP(OP_MOD); } | numexpr POW numexpr { ADD_OP(OP_POWER); } | '-' numexpr %prec UNARY_MINUS { ADD_OP(OP_NEGATE); } | numexpr GT numexpr { ADD_OP(OP_GT); } | numexpr GE numexpr { ADD_OP(OP_GE); } | numexpr LT numexpr { ADD_OP(OP_LT); } | numexpr LE numexpr { ADD_OP(OP_LE); } | numexpr EQ numexpr { ADD_OP(OP_EQ); } | numexpr NE numexpr { ADD_OP(OP_NE); } | numexpr '&' numexpr { ADD_OP(OP_BIT_AND); } | numexpr '|' numexpr { ADD_OP(OP_BIT_OR); } | numexpr and numexpr %prec AND { ADD_OP(OP_AND); SET_BR_OFF($2, GetPC()); } | numexpr or numexpr %prec OR { ADD_OP(OP_OR); SET_BR_OFF($2, GetPC()); } | NOT numexpr { ADD_OP(OP_NOT); } | INCR SYMBOL { ADD_OP(OP_PUSH_SYM); ADD_SYM($2); ADD_OP(OP_INCR); ADD_OP(OP_DUP); ADD_OP(OP_ASSIGN); ADD_SYM($2); } | SYMBOL INCR { ADD_OP(OP_PUSH_SYM); ADD_SYM($1); ADD_OP(OP_DUP); ADD_OP(OP_INCR); ADD_OP(OP_ASSIGN); ADD_SYM($1); } | DECR SYMBOL { ADD_OP(OP_PUSH_SYM); ADD_SYM($2); ADD_OP(OP_DECR); ADD_OP(OP_DUP); ADD_OP(OP_ASSIGN); ADD_SYM($2); } | SYMBOL DECR { ADD_OP(OP_PUSH_SYM); ADD_SYM($1); ADD_OP(OP_DUP); ADD_OP(OP_DECR); ADD_OP(OP_ASSIGN); ADD_SYM($1); } | numexpr IN numexpr { ADD_OP(OP_IN_ARRAY); } ; while: WHILE { $$ = GetPC(); StartLoopAddrList(); } ; for: FOR { StartLoopAddrList(); $$ = GetPC(); } ; else: ELSE { ADD_OP(OP_BRANCH); $$ = GetPC(); ADD_BR_OFF(0); } ; cond: /* nothing */ { ADD_OP(OP_BRANCH_NEVER); $$ = GetPC(); ADD_BR_OFF(0); } | numexpr { ADD_OP(OP_BRANCH_FALSE); $$ = GetPC(); ADD_BR_OFF(0); } ; and: AND { ADD_OP(OP_DUP); ADD_OP(OP_BRANCH_FALSE); $$ = GetPC(); ADD_BR_OFF(0); } ; or: OR { ADD_OP(OP_DUP); ADD_OP(OP_BRANCH_TRUE); $$ = GetPC(); ADD_BR_OFF(0); } ; blank: /* nothing */ | blank '\n' ; %% /* User Subroutines Section */ /* ** Parse a null terminated string and create a program from it (this is the ** parser entry point). The program created by this routine can be ** executed using ExecuteProgram. Returns program on success, or NULL ** on failure. If the command failed, the error message is returned ** as a pointer to a static string in msg, and the length of the string up ** to where parsing failed in stoppedAt. */ Program *ParseMacro(char *expr, char **msg, char **stoppedAt) { Program *prog; BeginCreatingProgram(); /* call yyparse to parse the string and check for success. If the parse failed, return the error message and string index (the grammar aborts parsing at the first error) */ InPtr = expr; if (yyparse()) { *msg = ErrMsg; *stoppedAt = InPtr; FreeProgram(FinishCreatingProgram()); return NULL; } /* get the newly created program */ prog = FinishCreatingProgram(); /* parse succeeded */ *msg = ""; *stoppedAt = InPtr; return prog; } static int yylex(void) { int i, len; Symbol *s; static DataValue value = {NO_TAG, {0}}; static char escape[] = "\\\"ntbrfave"; #ifdef EBCDIC_CHARSET static char replace[] = "\\\"\n\t\b\r\f\a\v\x27"; /* EBCDIC escape */ #else static char replace[] = "\\\"\n\t\b\r\f\a\v\x1B"; /* ASCII escape */ #endif /* skip whitespace, backslash-newline combinations, and comments, which are all considered whitespace */ for (;;) { if (*InPtr == '\\' && *(InPtr + 1) == '\n') InPtr += 2; else if (*InPtr == ' ' || *InPtr == '\t') InPtr++; else if (*InPtr == '#') while (*InPtr != '\n' && *InPtr != '\0') { /* Comments stop at escaped newlines */ if (*InPtr == '\\' && *(InPtr + 1) == '\n') { InPtr += 2; break; } InPtr++; } else break; } /* return end of input at the end of the string */ if (*InPtr == '\0') { return 0; } /* process number tokens */ if (isdigit((unsigned char)*InPtr)) { /* number */ char name[28]; sscanf(InPtr, "%d%n", &value.val.n, &len); sprintf(name, "const %d", value.val.n); InPtr += len; value.tag = INT_TAG; if ((yylval.sym=LookupSymbol(name)) == NULL) yylval.sym = InstallSymbol(name, CONST_SYM, value); return NUMBER; } /* process symbol tokens. "define" is a special case not handled by this parser, considered end of input. Another special case is action routine names which are allowed to contain '-' despite the ambiguity, handled in matchesActionRoutine. */ if (isalpha((unsigned char)*InPtr) || *InPtr == '$') { if ((s=matchesActionRoutine(&InPtr)) == NULL) { char symName[MAX_SYM_LEN+1], *p = symName; *p++ = *InPtr++; while (isalnum((unsigned char)*InPtr) || *InPtr=='_') { if (p >= symName + MAX_SYM_LEN) InPtr++; else *p++ = *InPtr++; } *p = '\0'; if (!strcmp(symName, "while")) return WHILE; if (!strcmp(symName, "if")) return IF; if (!strcmp(symName, "else")) return ELSE; if (!strcmp(symName, "for")) return FOR; if (!strcmp(symName, "break")) return BREAK; if (!strcmp(symName, "continue")) return CONTINUE; if (!strcmp(symName, "return")) return RETURN; if (!strcmp(symName, "in")) return IN; if (!strcmp(symName, "$args")) return ARG_LOOKUP; if (!strcmp(symName, "delete") && follow_non_whitespace('(', SYMBOL, DELETE) == DELETE) return DELETE; if (!strcmp(symName, "define")) { InPtr -= 6; return 0; } if ((s=LookupSymbol(symName)) == NULL) { s = InstallSymbol(symName, symName[0]=='$' ? (((symName[1] > '0' && symName[1] <= '9') && symName[2] == 0) ? ARG_SYM : GLOBAL_SYM) : LOCAL_SYM, value); s->value.tag = NO_TAG; } } yylval.sym = s; return SYMBOL; } /* Process quoted strings with embedded escape sequences: For backslashes we recognise hexadecimal values with initial 'x' such as "\x1B"; octal value (upto 3 oct digits with a possible leading zero) such as "\33", "\033" or "\0033", and the C escapes: \", \', \n, \t, \b, \r, \f, \a, \v, and the added \e for the escape character, as for REs. Disallow hex/octal zero values (NUL): instead ignore the introductory backslash, eg "\x0xyz" becomes "x0xyz" and "\0000hello" becomes "0000hello". */ if (*InPtr == '\"') { char string[MAX_STRING_CONST_LEN], *p = string; char *backslash; InPtr++; while (*InPtr != '\0' && *InPtr != '\"' && *InPtr != '\n') { if (p >= string + MAX_STRING_CONST_LEN) { InPtr++; continue; } if (*InPtr == '\\') { backslash = InPtr; InPtr++; if (*InPtr == '\n') { InPtr++; continue; } if (*InPtr == 'x') { /* a hex introducer */ int hexValue = 0; const char *hexDigits = "0123456789abcdef"; const char *hexD; InPtr++; if (*InPtr == '\0' || (hexD = strchr(hexDigits, tolower(*InPtr))) == NULL) { *p++ = 'x'; } else { hexValue = hexD - hexDigits; InPtr++; /* now do we have another digit? only accept one more */ if (*InPtr != '\0' && (hexD = strchr(hexDigits,tolower(*InPtr))) != NULL){ hexValue = hexD - hexDigits + (hexValue << 4); InPtr++; } if (hexValue != 0) { *p++ = (char)hexValue; } else { InPtr = backslash + 1; /* just skip the backslash */ } } continue; } /* the RE documentation requires \0 as the octal introducer; here you can start with any octal digit, but you are only allowed up to three (or four if the first is '0'). */ if ('0' <= *InPtr && *InPtr <= '7') { if (*InPtr == '0') { InPtr++; /* octal introducer: don't count this digit */ } if ('0' <= *InPtr && *InPtr <= '7') { /* treat as octal - first digit */ char octD = *InPtr++; int octValue = octD - '0'; if ('0' <= *InPtr && *InPtr <= '7') { /* second digit */ octD = *InPtr++; octValue = (octValue << 3) + octD - '0'; /* now do we have another digit? can we add it? if value is going to be too big for char (greater than 0377), stop converting now before adding the third digit */ if ('0' <= *InPtr && *InPtr <= '7' && octValue <= 037) { /* third digit is acceptable */ octD = *InPtr++; octValue = (octValue << 3) + octD - '0'; } } if (octValue != 0) { *p++ = (char)octValue; } else { InPtr = backslash + 1; /* just skip the backslash */ } } else { /* \0 followed by non-digits: go back to 0 */ InPtr = backslash + 1; /* just skip the backslash */ } continue; } for (i=0; escape[i]!='\0'; i++) { if (escape[i] == *InPtr) { *p++ = replace[i]; InPtr++; break; } } /* if we get here, we didn't recognise the character after the backslash: just copy it next time round the loop */ } else { *p++= *InPtr++; } } *p = '\0'; InPtr++; yylval.sym = InstallStringConstSymbol(string); return STRING; } /* process remaining two character tokens or return single char as token */ switch(*InPtr++) { case '>': return follow('=', GE, GT); case '<': return follow('=', LE, LT); case '=': return follow('=', EQ, '='); case '!': return follow('=', NE, NOT); case '+': return follow2('+', INCR, '=', ADDEQ, '+'); case '-': return follow2('-', DECR, '=', SUBEQ, '-'); case '|': return follow2('|', OR, '=', OREQ, '|'); case '&': return follow2('&', AND, '=', ANDEQ, '&'); case '*': return follow2('*', POW, '=', MULEQ, '*'); case '/': return follow('=', DIVEQ, '/'); case '%': return follow('=', MODEQ, '%'); case '^': return POW; default: return *(InPtr-1); } } /* ** look ahead for >=, etc. */ static int follow(char expect, int yes, int no) { if (*InPtr++ == expect) return yes; InPtr--; return no; } static int follow2(char expect1, int yes1, char expect2, int yes2, int no) { char next = *InPtr++; if (next == expect1) return yes1; if (next == expect2) return yes2; InPtr--; return no; } static int follow_non_whitespace(char expect, int yes, int no) { char *localInPtr = InPtr; while (1) { if (*localInPtr == ' ' || *localInPtr == '\t') { ++localInPtr; } else if (*localInPtr == '\\' && *(localInPtr + 1) == '\n') { localInPtr += 2; } else if (*localInPtr == expect) { return(yes); } else { return(no); } } } /* ** Look (way) ahead for hyphenated routine names which begin at inPtr. A ** hyphenated name is allowed if it is pre-defined in the global symbol ** table. If a matching name exists, returns the symbol, and update "inPtr". ** ** I know this is horrible language design, but existing nedit action routine ** names contain hyphens. Handling them here in the lexical analysis process ** is much easier than trying to deal with it in the parser itself. (sorry) */ static Symbol *matchesActionRoutine(char **inPtr) { char *c, *symPtr; int hasDash = False; char symbolName[MAX_SYM_LEN+1]; Symbol *s; symPtr = symbolName; for (c = *inPtr; isalnum((unsigned char)*c) || *c=='_' || ( *c=='-' && isalnum((unsigned char)(*(c+1)))); c++) { if (*c == '-') hasDash = True; *symPtr++ = *c; } if (!hasDash) return NULL; *symPtr = '\0'; s = LookupSymbol(symbolName); if (s != NULL) *inPtr = c; return s; } /* ** Called by yacc to report errors (just stores for returning when ** parsing is aborted. The error token action is to immediate abort ** parsing, so this message is immediately reported to the caller ** of ParseExpr) */ static int yyerror(char *s) { ErrMsg = s; return 0; } nedit-5.6.orig/source/parse_noyacc.c0000644000175000017500000020301310551732427016231 0ustar paulpaul#ifndef lint static char const yyrcsid[] = "$FreeBSD: src/usr.bin/yacc/skeleton.c,v 1.28 2000/01/17 02:04:06 bde Exp $"; #endif #include #define YYBYACC 1 #define YYMAJOR 1 #define YYMINOR 9 #define YYLEX yylex() #define YYEMPTY -1 #define yyclearin (yychar=(YYEMPTY)) #define yyerrok (yyerrflag=0) #define YYRECOVERING() (yyerrflag!=0) static int yygrowstack(); #define YYPREFIX "yy" #line 3 "parse.y" #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "parse.h" #include "textBuf.h" #include "nedit.h" #include "rbTree.h" #include "interpret.h" #include #include #include #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #ifdef HAVE_DEBUG_H #include "../debug.h" #endif /* Macros to add error processing to AddOp and AddSym calls */ #define ADD_OP(op) if (!AddOp(op, &ErrMsg)) return 1 #define ADD_SYM(sym) if (!AddSym(sym, &ErrMsg)) return 1 #define ADD_IMMED(val) if (!AddImmediate(val, &ErrMsg)) return 1 #define ADD_BR_OFF(to) if (!AddBranchOffset(to, &ErrMsg)) return 1 #define SET_BR_OFF(from, to) ((from)->value) = ((Inst *)(to)) - ((Inst *)(from)) /* Max. length for a string constant (... there shouldn't be a maximum) */ #define MAX_STRING_CONST_LEN 5000 static const char CVSID[] = "$Id: parse_noyacc.c,v 1.10 2007/01/12 16:19:35 tringali Exp $"; static int yyerror(char *s); static int yylex(void); int yyparse(void); static int follow(char expect, int yes, int no); static int follow2(char expect1, int yes1, char expect2, int yes2, int no); static int follow_non_whitespace(char expect, int yes, int no); static Symbol *matchesActionRoutine(char **inPtr); static char *ErrMsg; static char *InPtr; extern Inst *LoopStack[]; /* addresses of break, cont stmts */ extern Inst **LoopStackPtr; /* to fill at the end of a loop */ #line 57 "parse.y" typedef union { Symbol *sym; Inst *inst; int nArgs; } YYSTYPE; #line 76 "y.tab.c" #define YYERRCODE 256 #define NUMBER 257 #define STRING 258 #define SYMBOL 259 #define DELETE 260 #define ARG_LOOKUP 261 #define IF 262 #define WHILE 263 #define ELSE 264 #define FOR 265 #define BREAK 266 #define CONTINUE 267 #define RETURN 268 #define IF_NO_ELSE 269 #define ADDEQ 270 #define SUBEQ 271 #define MULEQ 272 #define DIVEQ 273 #define MODEQ 274 #define ANDEQ 275 #define OREQ 276 #define CONCAT 277 #define OR 278 #define AND 279 #define GT 280 #define GE 281 #define LT 282 #define LE 283 #define EQ 284 #define NE 285 #define IN 286 #define UNARY_MINUS 287 #define NOT 288 #define INCR 289 #define DECR 290 #define POW 291 const short yylhs[] = { -1, 0, 0, 0, 0, 13, 13, 13, 12, 12, 14, 14, 14, 14, 14, 16, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 10, 3, 3, 3, 1, 1, 1, 17, 17, 19, 19, 18, 18, 9, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 5, 4, 6, 2, 2, 7, 8, 11, 11, }; const short yylen[] = { 2, 2, 5, 4, 1, 5, 4, 1, 1, 2, 3, 6, 9, 6, 10, 0, 9, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 4, 2, 2, 2, 2, 1, 0, 1, 3, 0, 1, 3, 1, 2, 1, 4, 1, 4, 1, 1, 1, 1, 4, 3, 4, 3, 1, 4, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 3, 1, 1, 1, 0, 1, 1, 1, 0, 2, }; const short yydefred[] = { 0, 4, 0, 0, 0, 0, 0, 93, 94, 0, 0, 0, 0, 0, 100, 101, 0, 0, 0, 0, 8, 0, 0, 0, 44, 46, 0, 58, 0, 0, 100, 100, 61, 62, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 91, 0, 0, 0, 0, 88, 90, 0, 0, 100, 0, 99, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 100, 0, 67, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 100, 0, 0, 0, 0, 64, 66, 69, 0, 0, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 100, 0, 7, 15, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 100, 100, 0, 100, 0, 0, 0, 100, 0, 100, 12, 16, 0, 0, 14, }; const short yydgoto[] = { 2, 62, 65, 106, 16, 17, 192, 99, 100, 161, 18, 3, 19, 177, 178, 21, 193, 63, 28, 22, 43, }; const short yysindex[] = { -242, 0, 0, 221, 6, -243, -15, 0, 0, 32, 42, 603, -209, -204, 0, 0, 54, 58, 768, 1179, 0, 77, 22, 843, 0, 0, 843, 0, 38, 843, 0, 0, 0, 0, 8, 44, 843, 843, -150, -142, 843, 0, 747, 1368, 0, 46, 0, 49, 369, 101, 843, 843, 843, 843, 843, 843, 843, 843, 0, 0, 843, 843, -26, 843, 843, 82, 1368, 121, 121, 0, 0, 843, 975, -87, -87, 0, 0, 837, 121, 0, 1368, 0, 0, 843, 843, 843, 843, 843, 843, 843, 843, 843, 843, 843, 843, 843, 843, 843, 843, 843, 843, 843, 843, 0, 328, -31, -27, 0, 104, 843, 843, 843, 843, 843, 843, 843, 121, -22, 0, 843, -21, 0, -17, 0, -35, 0, 121, 65, 163, -9, -9, -9, -9, -9, -9, -9, 2, 2, -87, -87, -87, -87, -7, 23, 1250, 39, 40, 0, 843, 843, 504, 0, 624, 843, 0, 292, 0, 0, 0, 0, 0, 110, 1368, 94, 0, 292, 843, 843, 843, 843, 843, 843, 843, 843, 0, 0, 0, -110, 0, 0, 504, 0, 843, 843, 843, 843, 843, 843, 843, 843, 665, 0, 0, 0, 55, 0, 464, 292, 292, 0, 121, 0, 0, 0, 292, 121, 0, }; const short yyrindex[] = { 700, 0, 0, 0, -91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 0, 0, 0, 0, 0, 0, 56, 0, 0, 116, 0, 0, 0, 0, 383, 128, 0, 0, 0, 0, 0, 0, 0, 179, 10, 0, 108, 0, 0, -18, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 47, 0, -1, 51, 0, -28, 1, 11, 0, 0, 56, 0, 419, 455, 0, 0, 0, 21, 0, 431, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 51, 51, 0, 0, -91, 0, 0, 0, 75, 80, 117, 481, 503, 568, 611, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 1342, 1337, 899, 934, 969, 1197, 1232, 1267, 1302, 827, 863, 491, 527, 563, 791, 0, 1377, 877, 0, 0, 0, 0, 127, 0, 0, 69, 18, 118, 0, 0, 0, 0, 391, 539, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 0, 0, 81, 0, 613, 755, 815, 875, 932, 936, 940, 942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 0, 0, 0, 0, 105, 0, }; const short yygindex[] = { 0, 444, -45, -16, 0, 0, 0, 0, 0, 0, 0, 1272, -42, 37, 26, -30, 0, 24, 0, 129, 1632, }; #define YYTABLESIZE 1821 const short yytable[] = { 56, 17, 96, 84, 98, 108, 104, 94, 92, 26, 93, 18, 95, 97, 1, 118, 27, 150, 119, 107, 43, 20, 119, 119, 156, 29, 48, 119, 96, 20, 23, 97, 149, 94, 92, 42, 93, 119, 95, 96, 52, 48, 30, 52, 94, 58, 26, 61, 71, 95, 44, 43, 31, 10, 43, 46, 98, 21, 157, 53, 96, 84, 53, 19, 77, 94, 92, 23, 93, 43, 95, 152, 154, 6, 20, 109, 110, 111, 112, 113, 114, 115, 98, 119, 119, 22, 158, 59, 21, 83, 23, 21, 52, 98, 49, 51, 199, 51, 50, 150, 51, 56, 96, 84, 163, 5, 21, 94, 92, 75, 93, 53, 95, 60, 98, 11, 22, 76, 45, 22, 164, 23, 48, 121, 23, 48, 17, 24, 29, 64, 58, 15, 159, 160, 22, 72, 18, 101, 68, 23, 102, 45, 47, 153, 51, 151, 20, 83, 196, 45, 107, 179, 45, 180, 191, 1, 98, 96, 24, 29, 57, 24, 29, 60, 194, 68, 68, 45, 68, 68, 68, 68, 68, 68, 0, 68, 24, 29, 10, 47, 47, 47, 47, 47, 47, 47, 96, 68, 19, 54, 182, 183, 184, 185, 186, 187, 188, 189, 6, 56, 96, 0, 181, 0, 97, 94, 92, 0, 93, 59, 95, 0, 0, 0, 0, 0, 20, 0, 0, 54, 54, 68, 58, 54, 0, 0, 0, 0, 0, 0, 5, 15, 0, 0, 202, 203, 0, 0, 54, 0, 11, 206, 0, 81, 82, 85, 86, 87, 88, 89, 90, 91, 68, 0, 98, 148, 97, 0, 24, 25, 17, 17, 0, 17, 17, 17, 17, 17, 17, 17, 18, 18, 54, 18, 18, 18, 18, 18, 18, 18, 20, 20, 97, 20, 20, 20, 20, 20, 20, 20, 17, 17, 0, 97, 0, 24, 25, 69, 70, 0, 18, 18, 15, 85, 86, 87, 88, 89, 90, 91, 20, 20, 10, 10, 97, 10, 10, 10, 10, 10, 10, 10, 19, 19, 0, 19, 19, 19, 19, 19, 19, 19, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 10, 10, 14, 85, 86, 87, 88, 89, 90, 91, 19, 19, 0, 0, 97, 0, 0, 0, 105, 5, 6, 6, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 11, 11, 0, 11, 11, 15, 11, 11, 11, 11, 0, 68, 68, 68, 0, 68, 12, 13, 0, 63, 5, 5, 0, 0, 0, 0, 0, 40, 0, 0, 11, 11, 68, 68, 68, 68, 68, 68, 68, 68, 68, 176, 68, 68, 68, 68, 63, 63, 0, 0, 63, 63, 63, 63, 63, 76, 63, 0, 40, 0, 0, 40, 54, 54, 54, 0, 54, 55, 63, 85, 86, 87, 88, 89, 90, 91, 40, 0, 0, 147, 97, 0, 76, 76, 0, 76, 76, 76, 76, 76, 76, 87, 76, 54, 54, 54, 0, 55, 55, 0, 63, 55, 63, 0, 76, 0, 4, 5, 57, 6, 7, 0, 8, 9, 10, 11, 55, 25, 87, 87, 103, 87, 87, 87, 87, 87, 87, 72, 87, 0, 117, 0, 0, 63, 120, 0, 12, 13, 76, 26, 87, 122, 0, 0, 0, 0, 0, 0, 25, 0, 55, 25, 0, 0, 72, 72, 0, 72, 72, 72, 72, 72, 72, 73, 72, 0, 25, 0, 142, 76, 26, 145, 146, 26, 87, 41, 72, 4, 5, 0, 6, 7, 0, 8, 9, 10, 11, 0, 26, 0, 73, 73, 0, 73, 73, 73, 73, 73, 73, 74, 73, 0, 0, 0, 27, 87, 41, 12, 13, 41, 72, 0, 73, 4, 5, 201, 6, 7, 0, 8, 9, 10, 11, 0, 41, 0, 74, 74, 0, 74, 74, 74, 74, 74, 74, 27, 74, 0, 27, 41, 0, 72, 0, 12, 13, 0, 73, 28, 74, 30, 0, 0, 0, 27, 4, 5, 57, 6, 7, 0, 8, 9, 10, 11, 0, 0, 63, 63, 63, 40, 63, 0, 0, 0, 36, 0, 0, 73, 28, 0, 30, 28, 74, 30, 12, 13, 0, 63, 63, 63, 63, 63, 63, 63, 63, 63, 28, 63, 30, 0, 63, 15, 76, 76, 76, 0, 76, 0, 0, 0, 0, 166, 0, 74, 55, 55, 55, 0, 55, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76, 76, 0, 76, 76, 76, 100, 0, 87, 87, 87, 0, 87, 0, 0, 55, 55, 55, 0, 4, 5, 0, 6, 7, 0, 8, 9, 10, 11, 87, 87, 87, 87, 87, 87, 87, 87, 87, 0, 87, 87, 87, 0, 0, 72, 72, 72, 0, 72, 12, 13, 0, 0, 79, 0, 0, 0, 0, 0, 4, 5, 31, 0, 0, 0, 72, 72, 72, 72, 72, 72, 72, 72, 72, 0, 72, 72, 72, 0, 0, 73, 73, 73, 40, 73, 0, 195, 0, 36, 12, 13, 0, 31, 0, 0, 31, 0, 75, 0, 0, 0, 73, 73, 73, 73, 73, 73, 73, 73, 73, 31, 73, 73, 73, 0, 0, 74, 74, 74, 100, 74, 32, 0, 0, 75, 75, 0, 75, 75, 75, 75, 75, 75, 70, 75, 0, 0, 74, 74, 74, 74, 74, 74, 74, 74, 74, 75, 74, 74, 74, 0, 0, 32, 0, 0, 32, 32, 33, 34, 0, 35, 70, 0, 70, 70, 0, 70, 70, 70, 71, 32, 0, 0, 40, 125, 0, 0, 0, 36, 40, 75, 33, 70, 86, 36, 0, 0, 37, 38, 39, 167, 168, 169, 170, 171, 172, 173, 71, 0, 71, 71, 0, 71, 71, 71, 77, 0, 0, 0, 174, 175, 75, 33, 86, 86, 33, 70, 86, 71, 0, 4, 5, 0, 6, 7, 0, 8, 9, 10, 11, 33, 0, 86, 77, 0, 77, 77, 0, 34, 77, 78, 0, 35, 0, 0, 0, 36, 70, 37, 0, 12, 13, 71, 0, 77, 100, 100, 0, 100, 100, 0, 100, 100, 100, 100, 0, 86, 0, 78, 34, 78, 78, 34, 35, 78, 79, 35, 36, 0, 37, 36, 0, 37, 71, 0, 100, 100, 34, 77, 78, 0, 35, 0, 0, 0, 36, 0, 37, 0, 0, 32, 33, 34, 79, 35, 79, 79, 0, 0, 79, 0, 40, 0, 0, 0, 0, 36, 0, 0, 77, 0, 0, 0, 78, 79, 0, 0, 0, 0, 0, 0, 37, 38, 39, 51, 52, 53, 54, 55, 56, 57, 0, 0, 0, 75, 75, 75, 0, 75, 0, 0, 0, 0, 0, 78, 0, 0, 0, 79, 0, 0, 0, 0, 0, 123, 75, 75, 75, 75, 75, 75, 75, 75, 75, 0, 75, 75, 75, 0, 0, 70, 70, 70, 0, 70, 0, 0, 0, 0, 79, 32, 33, 34, 0, 35, 0, 32, 33, 34, 0, 35, 70, 70, 70, 70, 70, 70, 70, 70, 70, 0, 70, 70, 70, 0, 0, 71, 71, 71, 0, 71, 37, 38, 39, 0, 0, 0, 37, 38, 39, 86, 86, 86, 0, 86, 0, 0, 71, 71, 71, 71, 71, 71, 71, 71, 71, 0, 71, 71, 71, 0, 86, 77, 77, 77, 0, 77, 0, 0, 0, 0, 86, 86, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 77, 0, 77, 77, 77, 0, 78, 78, 78, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 78, 78, 78, 78, 78, 78, 78, 78, 78, 0, 78, 78, 78, 0, 79, 79, 79, 0, 79, 0, 32, 33, 34, 80, 35, 80, 80, 0, 0, 80, 81, 0, 0, 0, 0, 79, 79, 79, 79, 79, 79, 79, 79, 79, 80, 79, 79, 79, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0, 81, 0, 81, 81, 0, 0, 81, 82, 0, 0, 0, 0, 0, 0, 0, 0, 48, 96, 84, 0, 80, 81, 94, 92, 0, 93, 0, 95, 0, 0, 0, 0, 67, 68, 0, 82, 0, 82, 82, 0, 0, 82, 92, 78, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 81, 82, 0, 0, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 92, 98, 92, 92, 0, 0, 92, 83, 0, 0, 0, 126, 84, 0, 0, 0, 81, 0, 0, 0, 82, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 83, 0, 83, 83, 0, 0, 83, 84, 84, 0, 0, 84, 85, 0, 0, 0, 82, 0, 155, 0, 92, 83, 0, 0, 0, 0, 84, 0, 0, 0, 96, 84, 0, 0, 0, 94, 92, 0, 93, 0, 95, 0, 85, 85, 0, 0, 85, 0, 165, 0, 0, 92, 0, 0, 0, 83, 0, 0, 0, 0, 84, 85, 0, 4, 5, 0, 6, 7, 0, 8, 9, 10, 11, 190, 0, 0, 0, 0, 0, 80, 80, 80, 0, 80, 98, 0, 83, 0, 0, 197, 198, 84, 200, 12, 13, 85, 204, 0, 205, 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 0, 80, 80, 80, 0, 81, 81, 81, 83, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 81, 81, 81, 81, 81, 81, 81, 81, 0, 81, 81, 81, 0, 82, 82, 82, 0, 82, 82, 85, 86, 87, 88, 89, 90, 91, 0, 0, 0, 0, 97, 0, 0, 0, 82, 82, 82, 82, 82, 82, 82, 82, 82, 0, 82, 82, 82, 0, 92, 92, 92, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 92, 92, 92, 92, 92, 92, 92, 92, 0, 92, 92, 92, 0, 83, 83, 83, 0, 83, 84, 84, 84, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 83, 0, 0, 0, 84, 84, 0, 0, 0, 83, 83, 83, 0, 0, 84, 84, 84, 0, 85, 85, 85, 0, 85, 0, 0, 0, 0, 0, 0, 0, 81, 82, 85, 86, 87, 88, 89, 90, 91, 85, 85, 0, 0, 97, 0, 66, 0, 0, 0, 85, 85, 85, 73, 74, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 124, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 0, 143, 144, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 80, 80, 80, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 66, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 80, 80, 80, 80, 80, }; const short yycheck[] = { 91, 0, 37, 38, 91, 50, 48, 42, 43, 40, 45, 0, 47, 41, 256, 41, 259, 44, 44, 49, 10, 0, 44, 44, 41, 40, 44, 44, 37, 3, 61, 59, 59, 42, 43, 11, 45, 44, 47, 37, 41, 59, 10, 44, 42, 19, 40, 23, 40, 47, 259, 41, 10, 0, 44, 259, 91, 10, 93, 41, 37, 38, 44, 0, 40, 42, 43, 61, 45, 59, 47, 93, 93, 0, 48, 51, 52, 53, 54, 55, 56, 57, 91, 44, 44, 10, 93, 10, 41, 124, 10, 44, 93, 91, 40, 44, 41, 41, 40, 44, 44, 91, 37, 38, 149, 0, 59, 42, 43, 259, 45, 93, 47, 91, 91, 0, 41, 259, 10, 44, 150, 41, 41, 41, 44, 44, 125, 10, 10, 91, 104, 10, 93, 93, 59, 91, 125, 91, 10, 59, 91, 12, 13, 119, 93, 41, 125, 124, 190, 41, 180, 41, 44, 59, 264, 0, 91, 41, 41, 41, 91, 44, 44, 41, 180, 37, 38, 59, 40, 41, 42, 43, 44, 45, -1, 47, 59, 59, 125, 270, 271, 272, 273, 274, 275, 276, 59, 59, 125, 10, 166, 167, 168, 169, 170, 171, 172, 173, 125, 91, 37, -1, 165, -1, 291, 42, 43, -1, 45, 91, 47, -1, -1, -1, -1, -1, 190, -1, -1, 40, 41, 93, 196, 44, -1, -1, -1, -1, -1, -1, 125, 10, -1, -1, 197, 198, -1, -1, 59, -1, 125, 204, -1, 278, 279, 280, 281, 282, 283, 284, 285, 286, 124, -1, 91, 286, 291, -1, 289, 290, 259, 260, -1, 262, 263, 264, 265, 266, 267, 268, 259, 260, 93, 262, 263, 264, 265, 266, 267, 268, 259, 260, 291, 262, 263, 264, 265, 266, 267, 268, 289, 290, -1, 291, -1, 289, 290, 289, 290, -1, 289, 290, 10, 280, 281, 282, 283, 284, 285, 286, 289, 290, 259, 260, 291, 262, 263, 264, 265, 266, 267, 268, 259, 260, -1, 262, 263, 264, 265, 266, 267, 268, 259, 260, -1, 262, 263, 264, 265, 266, 267, 268, 289, 290, 123, 280, 281, 282, 283, 284, 285, 286, 289, 290, -1, -1, 291, -1, -1, -1, 259, 260, 289, 290, 259, 260, -1, 262, 263, 264, 265, 266, 267, 268, 259, 260, -1, 262, 263, 10, 265, 266, 267, 268, -1, 257, 258, 259, -1, 261, 289, 290, -1, 10, 289, 290, -1, -1, -1, -1, -1, 10, -1, -1, 289, 290, 278, 279, 280, 281, 282, 283, 284, 285, 286, 123, 288, 289, 290, 291, 37, 38, -1, -1, 41, 42, 43, 44, 45, 10, 47, -1, 41, -1, -1, 44, 257, 258, 259, -1, 261, 10, 59, 280, 281, 282, 283, 284, 285, 286, 59, -1, -1, 125, 291, -1, 37, 38, -1, 40, 41, 42, 43, 44, 45, 10, 47, 288, 289, 290, -1, 40, 41, -1, 91, 44, 93, -1, 59, -1, 259, 260, 91, 262, 263, -1, 265, 266, 267, 268, 59, 10, 37, 38, 125, 40, 41, 42, 43, 44, 45, 10, 47, -1, 60, -1, -1, 124, 64, -1, 289, 290, 93, 10, 59, 71, -1, -1, -1, -1, -1, -1, 41, -1, 93, 44, -1, -1, 37, 38, -1, 40, 41, 42, 43, 44, 45, 10, 47, -1, 59, -1, 98, 124, 41, 101, 102, 44, 93, 10, 59, 259, 260, -1, 262, 263, -1, 265, 266, 267, 268, -1, 59, -1, 37, 38, -1, 40, 41, 42, 43, 44, 45, 10, 47, -1, -1, -1, 10, 124, 41, 289, 290, 44, 93, -1, 59, 259, 260, 125, 262, 263, -1, 265, 266, 267, 268, -1, 59, -1, 37, 38, -1, 40, 41, 42, 43, 44, 45, 41, 47, -1, 44, 10, -1, 124, -1, 289, 290, -1, 93, 10, 59, 10, -1, -1, -1, 59, 259, 260, 91, 262, 263, -1, 265, 266, 267, 268, -1, -1, 257, 258, 259, 40, 261, -1, -1, -1, 45, -1, -1, 124, 41, -1, 41, 44, 93, 44, 289, 290, -1, 278, 279, 280, 281, 282, 283, 284, 285, 286, 59, 288, 59, -1, 291, 10, 257, 258, 259, -1, 261, -1, -1, -1, -1, 61, -1, 124, 257, 258, 259, -1, 261, -1, -1, -1, -1, 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, 290, 10, -1, 257, 258, 259, -1, 261, -1, -1, 288, 289, 290, -1, 259, 260, -1, 262, 263, -1, 265, 266, 267, 268, 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, 290, -1, -1, 257, 258, 259, -1, 261, 289, 290, -1, -1, 10, -1, -1, -1, -1, -1, 259, 260, 10, -1, -1, -1, 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, 290, -1, -1, 257, 258, 259, 40, 261, -1, 125, -1, 45, 289, 290, -1, 41, -1, -1, 44, -1, 10, -1, -1, -1, 278, 279, 280, 281, 282, 283, 284, 285, 286, 59, 288, 289, 290, -1, -1, 257, 258, 259, 123, 261, 10, -1, -1, 37, 38, -1, 40, 41, 42, 43, 44, 45, 10, 47, -1, -1, 278, 279, 280, 281, 282, 283, 284, 285, 286, 59, 288, 289, 290, -1, -1, 41, -1, -1, 44, 257, 258, 259, -1, 261, 38, -1, 40, 41, -1, 43, 44, 45, 10, 59, -1, -1, 40, 41, -1, -1, -1, 45, 40, 93, 10, 59, 10, 45, -1, -1, 288, 289, 290, 270, 271, 272, 273, 274, 275, 276, 38, -1, 40, 41, -1, 43, 44, 45, 10, -1, -1, -1, 289, 290, 124, 41, 40, 41, 44, 93, 44, 59, -1, 259, 260, -1, 262, 263, -1, 265, 266, 267, 268, 59, -1, 59, 38, -1, 40, 41, -1, 10, 44, 10, -1, 10, -1, -1, -1, 10, 124, 10, -1, 289, 290, 93, -1, 59, 259, 260, -1, 262, 263, -1, 265, 266, 267, 268, -1, 93, -1, 38, 41, 40, 41, 44, 41, 44, 10, 44, 41, -1, 41, 44, -1, 44, 124, -1, 289, 290, 59, 93, 59, -1, 59, -1, -1, -1, 59, -1, 59, -1, -1, 257, 258, 259, 38, 261, 40, 41, -1, -1, 44, -1, 40, -1, -1, -1, -1, 45, -1, -1, 124, -1, -1, -1, 93, 59, -1, -1, -1, -1, -1, -1, 288, 289, 290, 270, 271, 272, 273, 274, 275, 276, -1, -1, -1, 257, 258, 259, -1, 261, -1, -1, -1, -1, -1, 124, -1, -1, -1, 93, -1, -1, -1, -1, -1, 93, 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, 290, -1, -1, 257, 258, 259, -1, 261, -1, -1, -1, -1, 124, 257, 258, 259, -1, 261, -1, 257, 258, 259, -1, 261, 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, 290, -1, -1, 257, 258, 259, -1, 261, 288, 289, 290, -1, -1, -1, 288, 289, 290, 257, 258, 259, -1, 261, -1, -1, 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, 290, -1, 278, 257, 258, 259, -1, 261, -1, -1, -1, -1, 288, 289, 290, -1, -1, -1, -1, -1, -1, -1, -1, -1, 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, 290, -1, 257, 258, 259, -1, 261, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, -1, -1, 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, 290, -1, 257, 258, 259, -1, 261, -1, 257, 258, 259, 38, 261, 40, 41, -1, -1, 44, 10, -1, -1, -1, -1, 278, 279, 280, 281, 282, 283, 284, 285, 286, 59, 288, 289, 290, -1, -1, -1, 288, 289, 290, -1, -1, -1, -1, 38, -1, 40, 41, -1, -1, 44, 10, -1, -1, -1, -1, -1, -1, -1, -1, 14, 37, 38, -1, 93, 59, 42, 43, -1, 45, -1, 47, -1, -1, -1, -1, 30, 31, -1, 38, -1, 40, 41, -1, -1, 44, 10, 41, -1, -1, -1, -1, -1, -1, -1, 124, -1, -1, -1, 93, 59, -1, -1, -1, -1, 59, -1, -1, -1, -1, -1, -1, -1, -1, 38, 91, 40, 41, -1, -1, 44, 10, -1, -1, -1, 79, 10, -1, -1, -1, 124, -1, -1, -1, 93, 59, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 124, 38, -1, 40, 41, -1, -1, 44, 40, 41, -1, -1, 44, 10, -1, -1, -1, 124, -1, 121, -1, 93, 59, -1, -1, -1, -1, 59, -1, -1, -1, 37, 38, -1, -1, -1, 42, 43, -1, 45, -1, 47, -1, 40, 41, -1, -1, 44, -1, 151, -1, -1, 124, -1, -1, -1, 93, -1, -1, -1, -1, 93, 59, -1, 259, 260, -1, 262, 263, -1, 265, 266, 267, 268, 176, -1, -1, -1, -1, -1, 257, 258, 259, -1, 261, 91, -1, 124, -1, -1, 192, 193, 124, 195, 289, 290, 93, 199, -1, 201, -1, 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, 290, -1, 257, 258, 259, 124, 261, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, 290, -1, 257, 258, 259, -1, 261, 279, 280, 281, 282, 283, 284, 285, 286, -1, -1, -1, -1, 291, -1, -1, -1, 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, 290, -1, 257, 258, 259, -1, 261, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, 290, -1, 257, 258, 259, -1, 261, 257, 258, 259, -1, 261, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 278, 279, -1, -1, -1, 278, 279, -1, -1, -1, 288, 289, 290, -1, -1, 288, 289, 290, -1, 257, 258, 259, -1, 261, -1, -1, -1, -1, -1, -1, -1, 278, 279, 280, 281, 282, 283, 284, 285, 286, 278, 279, -1, -1, 291, -1, 29, -1, -1, -1, 288, 289, 290, 36, 37, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, 50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 61, -1, 63, -1, -1, -1, -1, -1, -1, -1, -1, 72, -1, -1, -1, -1, 77, -1, -1, -1, -1, -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, -1, 99, 100, -1, -1, -1, -1, -1, -1, -1, -1, 109, 110, 111, 112, 113, 114, 115, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 148, 149, -1, -1, -1, 153, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 182, 183, 184, 185, 186, 187, 188, 189, }; #define YYFINAL 2 #ifndef YYDEBUG #define YYDEBUG 0 #endif #define YYMAXTOKEN 291 #if YYDEBUG const char * const yyname[] = { "end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,"'%'","'&'",0,"'('","')'","'*'","'+'","','","'-'",0,"'/'",0,0,0,0,0, 0,0,0,0,0,0,"';'",0,"'='",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,"'['",0,"']'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, "'{'","'|'","'}'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"NUMBER","STRING","SYMBOL","DELETE", "ARG_LOOKUP","IF","WHILE","ELSE","FOR","BREAK","CONTINUE","RETURN","IF_NO_ELSE", "ADDEQ","SUBEQ","MULEQ","DIVEQ","MODEQ","ANDEQ","OREQ","CONCAT","OR","AND","GT", "GE","LT","LE","EQ","NE","IN","UNARY_MINUS","NOT","INCR","DECR","POW", }; const char * const yyrule[] = { "$accept : program", "program : blank stmts", "program : blank '{' blank stmts '}'", "program : blank '{' blank '}'", "program : error", "block : '{' blank stmts '}' blank", "block : '{' blank '}' blank", "block : stmt", "stmts : stmt", "stmts : stmts stmt", "stmt : simpstmt '\\n' blank", "stmt : IF '(' cond ')' blank block", "stmt : IF '(' cond ')' blank block else blank block", "stmt : while '(' cond ')' blank block", "stmt : for '(' comastmts ';' cond ';' comastmts ')' blank block", "$$1 :", "stmt : for '(' SYMBOL IN arrayexpr ')' $$1 blank block", "stmt : BREAK '\\n' blank", "stmt : CONTINUE '\\n' blank", "stmt : RETURN expr '\\n' blank", "stmt : RETURN '\\n' blank", "simpstmt : SYMBOL '=' expr", "simpstmt : evalsym ADDEQ expr", "simpstmt : evalsym SUBEQ expr", "simpstmt : evalsym MULEQ expr", "simpstmt : evalsym DIVEQ expr", "simpstmt : evalsym MODEQ expr", "simpstmt : evalsym ANDEQ expr", "simpstmt : evalsym OREQ expr", "simpstmt : DELETE arraylv '[' arglist ']'", "simpstmt : initarraylv '[' arglist ']' '=' expr", "simpstmt : initarraylv '[' arglist ']' ADDEQ expr", "simpstmt : initarraylv '[' arglist ']' SUBEQ expr", "simpstmt : initarraylv '[' arglist ']' MULEQ expr", "simpstmt : initarraylv '[' arglist ']' DIVEQ expr", "simpstmt : initarraylv '[' arglist ']' MODEQ expr", "simpstmt : initarraylv '[' arglist ']' ANDEQ expr", "simpstmt : initarraylv '[' arglist ']' OREQ expr", "simpstmt : initarraylv '[' arglist ']' INCR", "simpstmt : initarraylv '[' arglist ']' DECR", "simpstmt : INCR initarraylv '[' arglist ']'", "simpstmt : DECR initarraylv '[' arglist ']'", "simpstmt : SYMBOL '(' arglist ')'", "simpstmt : INCR SYMBOL", "simpstmt : SYMBOL INCR", "simpstmt : DECR SYMBOL", "simpstmt : SYMBOL DECR", "evalsym : SYMBOL", "comastmts :", "comastmts : simpstmt", "comastmts : comastmts ',' simpstmt", "arglist :", "arglist : expr", "arglist : arglist ',' expr", "expr : numexpr", "expr : expr numexpr", "initarraylv : SYMBOL", "initarraylv : initarraylv '[' arglist ']'", "arraylv : SYMBOL", "arraylv : arraylv '[' arglist ']'", "arrayexpr : numexpr", "numexpr : NUMBER", "numexpr : STRING", "numexpr : SYMBOL", "numexpr : SYMBOL '(' arglist ')'", "numexpr : '(' expr ')'", "numexpr : ARG_LOOKUP '[' numexpr ']'", "numexpr : ARG_LOOKUP '[' ']'", "numexpr : ARG_LOOKUP", "numexpr : numexpr '[' arglist ']'", "numexpr : numexpr '+' numexpr", "numexpr : numexpr '-' numexpr", "numexpr : numexpr '*' numexpr", "numexpr : numexpr '/' numexpr", "numexpr : numexpr '%' numexpr", "numexpr : numexpr POW numexpr", "numexpr : '-' numexpr", "numexpr : numexpr GT numexpr", "numexpr : numexpr GE numexpr", "numexpr : numexpr LT numexpr", "numexpr : numexpr LE numexpr", "numexpr : numexpr EQ numexpr", "numexpr : numexpr NE numexpr", "numexpr : numexpr '&' numexpr", "numexpr : numexpr '|' numexpr", "numexpr : numexpr and numexpr", "numexpr : numexpr or numexpr", "numexpr : NOT numexpr", "numexpr : INCR SYMBOL", "numexpr : SYMBOL INCR", "numexpr : DECR SYMBOL", "numexpr : SYMBOL DECR", "numexpr : numexpr IN numexpr", "while : WHILE", "for : FOR", "else : ELSE", "cond :", "cond : numexpr", "and : AND", "or : OR", "blank :", "blank : blank '\\n'", }; #endif #if YYDEBUG #include #endif #ifdef YYSTACKSIZE #undef YYMAXDEPTH #define YYMAXDEPTH YYSTACKSIZE #else #ifdef YYMAXDEPTH #define YYSTACKSIZE YYMAXDEPTH #else #define YYSTACKSIZE 10000 #define YYMAXDEPTH 10000 #endif #endif #define YYINITSTACKSIZE 200 int yydebug; int yynerrs; int yyerrflag; int yychar; short *yyssp; YYSTYPE *yyvsp; YYSTYPE yyval; YYSTYPE yylval; short *yyss; short *yysslim; YYSTYPE *yyvs; int yystacksize; #line 443 "parse.y" /* User Subroutines Section */ /* ** Parse a null terminated string and create a program from it (this is the ** parser entry point). The program created by this routine can be ** executed using ExecuteProgram. Returns program on success, or NULL ** on failure. If the command failed, the error message is returned ** as a pointer to a static string in msg, and the length of the string up ** to where parsing failed in stoppedAt. */ Program *ParseMacro(char *expr, char **msg, char **stoppedAt) { Program *prog; BeginCreatingProgram(); /* call yyparse to parse the string and check for success. If the parse failed, return the error message and string index (the grammar aborts parsing at the first error) */ InPtr = expr; if (yyparse()) { *msg = ErrMsg; *stoppedAt = InPtr; FreeProgram(FinishCreatingProgram()); return NULL; } /* get the newly created program */ prog = FinishCreatingProgram(); /* parse succeeded */ *msg = ""; *stoppedAt = InPtr; return prog; } static int yylex(void) { int i, len; Symbol *s; static DataValue value = {NO_TAG, {0}}; static char escape[] = "\\\"ntbrfave"; #ifdef EBCDIC_CHARSET static char replace[] = "\\\"\n\t\b\r\f\a\v\x27"; /* EBCDIC escape */ #else static char replace[] = "\\\"\n\t\b\r\f\a\v\x1B"; /* ASCII escape */ #endif /* skip whitespace, backslash-newline combinations, and comments, which are all considered whitespace */ for (;;) { if (*InPtr == '\\' && *(InPtr + 1) == '\n') InPtr += 2; else if (*InPtr == ' ' || *InPtr == '\t') InPtr++; else if (*InPtr == '#') while (*InPtr != '\n' && *InPtr != '\0') { /* Comments stop at escaped newlines */ if (*InPtr == '\\' && *(InPtr + 1) == '\n') { InPtr += 2; break; } InPtr++; } else break; } /* return end of input at the end of the string */ if (*InPtr == '\0') { return 0; } /* process number tokens */ if (isdigit((unsigned char)*InPtr)) { /* number */ char name[28]; sscanf(InPtr, "%d%n", &value.val.n, &len); sprintf(name, "const %d", value.val.n); InPtr += len; value.tag = INT_TAG; if ((yylval.sym=LookupSymbol(name)) == NULL) yylval.sym = InstallSymbol(name, CONST_SYM, value); return NUMBER; } /* process symbol tokens. "define" is a special case not handled by this parser, considered end of input. Another special case is action routine names which are allowed to contain '-' despite the ambiguity, handled in matchesActionRoutine. */ if (isalpha((unsigned char)*InPtr) || *InPtr == '$') { if ((s=matchesActionRoutine(&InPtr)) == NULL) { char symName[MAX_SYM_LEN+1], *p = symName; *p++ = *InPtr++; while (isalnum((unsigned char)*InPtr) || *InPtr=='_') { if (p >= symName + MAX_SYM_LEN) InPtr++; else *p++ = *InPtr++; } *p = '\0'; if (!strcmp(symName, "while")) return WHILE; if (!strcmp(symName, "if")) return IF; if (!strcmp(symName, "else")) return ELSE; if (!strcmp(symName, "for")) return FOR; if (!strcmp(symName, "break")) return BREAK; if (!strcmp(symName, "continue")) return CONTINUE; if (!strcmp(symName, "return")) return RETURN; if (!strcmp(symName, "in")) return IN; if (!strcmp(symName, "$args")) return ARG_LOOKUP; if (!strcmp(symName, "delete") && follow_non_whitespace('(', SYMBOL, DELETE) == DELETE) return DELETE; if (!strcmp(symName, "define")) { InPtr -= 6; return 0; } if ((s=LookupSymbol(symName)) == NULL) { s = InstallSymbol(symName, symName[0]=='$' ? (((symName[1] > '0' && symName[1] <= '9') && symName[2] == 0) ? ARG_SYM : GLOBAL_SYM) : LOCAL_SYM, value); s->value.tag = NO_TAG; } } yylval.sym = s; return SYMBOL; } /* Process quoted strings with embedded escape sequences: For backslashes we recognise hexadecimal values with initial 'x' such as "\x1B"; octal value (upto 3 oct digits with a possible leading zero) such as "\33", "\033" or "\0033", and the C escapes: \", \', \n, \t, \b, \r, \f, \a, \v, and the added \e for the escape character, as for REs. Disallow hex/octal zero values (NUL): instead ignore the introductory backslash, eg "\x0xyz" becomes "x0xyz" and "\0000hello" becomes "0000hello". */ if (*InPtr == '\"') { char string[MAX_STRING_CONST_LEN], *p = string; char *backslash; InPtr++; while (*InPtr != '\0' && *InPtr != '\"' && *InPtr != '\n') { if (p >= string + MAX_STRING_CONST_LEN) { InPtr++; continue; } if (*InPtr == '\\') { backslash = InPtr; InPtr++; if (*InPtr == '\n') { InPtr++; continue; } if (*InPtr == 'x') { /* a hex introducer */ int hexValue = 0; const char *hexDigits = "0123456789abcdef"; const char *hexD; InPtr++; if (*InPtr == '\0' || (hexD = strchr(hexDigits, tolower(*InPtr))) == NULL) { *p++ = 'x'; } else { hexValue = hexD - hexDigits; InPtr++; /* now do we have another digit? only accept one more */ if (*InPtr != '\0' && (hexD = strchr(hexDigits,tolower(*InPtr))) != NULL){ hexValue = hexD - hexDigits + (hexValue << 4); InPtr++; } if (hexValue != 0) { *p++ = (char)hexValue; } else { InPtr = backslash + 1; /* just skip the backslash */ } } continue; } /* the RE documentation requires \0 as the octal introducer; here you can start with any octal digit, but you are only allowed up to three (or four if the first is '0'). */ if ('0' <= *InPtr && *InPtr <= '7') { if (*InPtr == '0') { InPtr++; /* octal introducer: don't count this digit */ } if ('0' <= *InPtr && *InPtr <= '7') { /* treat as octal - first digit */ char octD = *InPtr++; int octValue = octD - '0'; if ('0' <= *InPtr && *InPtr <= '7') { /* second digit */ octD = *InPtr++; octValue = (octValue << 3) + octD - '0'; /* now do we have another digit? can we add it? if value is going to be too big for char (greater than 0377), stop converting now before adding the third digit */ if ('0' <= *InPtr && *InPtr <= '7' && octValue <= 037) { /* third digit is acceptable */ octD = *InPtr++; octValue = (octValue << 3) + octD - '0'; } } if (octValue != 0) { *p++ = (char)octValue; } else { InPtr = backslash + 1; /* just skip the backslash */ } } else { /* \0 followed by non-digits: go back to 0 */ InPtr = backslash + 1; /* just skip the backslash */ } continue; } for (i=0; escape[i]!='\0'; i++) { if (escape[i] == *InPtr) { *p++ = replace[i]; InPtr++; break; } } /* if we get here, we didn't recognise the character after the backslash: just copy it next time round the loop */ } else { *p++= *InPtr++; } } *p = '\0'; InPtr++; yylval.sym = InstallStringConstSymbol(string); return STRING; } /* process remaining two character tokens or return single char as token */ switch(*InPtr++) { case '>': return follow('=', GE, GT); case '<': return follow('=', LE, LT); case '=': return follow('=', EQ, '='); case '!': return follow('=', NE, NOT); case '+': return follow2('+', INCR, '=', ADDEQ, '+'); case '-': return follow2('-', DECR, '=', SUBEQ, '-'); case '|': return follow2('|', OR, '=', OREQ, '|'); case '&': return follow2('&', AND, '=', ANDEQ, '&'); case '*': return follow2('*', POW, '=', MULEQ, '*'); case '/': return follow('=', DIVEQ, '/'); case '%': return follow('=', MODEQ, '%'); case '^': return POW; default: return *(InPtr-1); } } /* ** look ahead for >=, etc. */ static int follow(char expect, int yes, int no) { if (*InPtr++ == expect) return yes; InPtr--; return no; } static int follow2(char expect1, int yes1, char expect2, int yes2, int no) { char next = *InPtr++; if (next == expect1) return yes1; if (next == expect2) return yes2; InPtr--; return no; } static int follow_non_whitespace(char expect, int yes, int no) { char *localInPtr = InPtr; while (1) { if (*localInPtr == ' ' || *localInPtr == '\t') { ++localInPtr; } else if (*localInPtr == '\\' && *(localInPtr + 1) == '\n') { localInPtr += 2; } else if (*localInPtr == expect) { return(yes); } else { return(no); } } } /* ** Look (way) ahead for hyphenated routine names which begin at inPtr. A ** hyphenated name is allowed if it is pre-defined in the global symbol ** table. If a matching name exists, returns the symbol, and update "inPtr". ** ** I know this is horrible language design, but existing nedit action routine ** names contain hyphens. Handling them here in the lexical analysis process ** is much easier than trying to deal with it in the parser itself. (sorry) */ static Symbol *matchesActionRoutine(char **inPtr) { char *c, *symPtr; int hasDash = False; char symbolName[MAX_SYM_LEN+1]; Symbol *s; symPtr = symbolName; for (c = *inPtr; isalnum((unsigned char)*c) || *c=='_' || ( *c=='-' && isalnum((unsigned char)(*(c+1)))); c++) { if (*c == '-') hasDash = True; *symPtr++ = *c; } if (!hasDash) return NULL; *symPtr = '\0'; s = LookupSymbol(symbolName); if (s != NULL) *inPtr = c; return s; } /* ** Called by yacc to report errors (just stores for returning when ** parsing is aborted. The error token action is to immediate abort ** parsing, so this message is immediately reported to the caller ** of ParseExpr) */ static int yyerror(char *s) { ErrMsg = s; return 0; } #line 1079 "y.tab.c" /* allocate initial stack or double stack size, up to YYMAXDEPTH */ static int yygrowstack() { int newsize, i; short *newss; YYSTYPE *newvs; if ((newsize = yystacksize) == 0) newsize = YYINITSTACKSIZE; else if (newsize >= YYMAXDEPTH) return -1; else if ((newsize *= 2) > YYMAXDEPTH) newsize = YYMAXDEPTH; i = yyssp - yyss; newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) : (short *)malloc(newsize * sizeof *newss); if (newss == NULL) return -1; yyss = newss; yyssp = newss + i; newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) : (YYSTYPE *)malloc(newsize * sizeof *newvs); if (newvs == NULL) return -1; yyvs = newvs; yyvsp = newvs + i; yystacksize = newsize; yysslim = yyss + newsize - 1; return 0; } #define YYABORT goto yyabort #define YYREJECT goto yyabort #define YYACCEPT goto yyaccept #define YYERROR goto yyerrlab #ifndef YYPARSE_PARAM #if defined(__cplusplus) || __STDC__ #define YYPARSE_PARAM_ARG void #define YYPARSE_PARAM_DECL #else /* ! ANSI-C/C++ */ #define YYPARSE_PARAM_ARG #define YYPARSE_PARAM_DECL #endif /* ANSI-C/C++ */ #else /* YYPARSE_PARAM */ #ifndef YYPARSE_PARAM_TYPE #define YYPARSE_PARAM_TYPE void * #endif #if defined(__cplusplus) || __STDC__ #define YYPARSE_PARAM_ARG YYPARSE_PARAM_TYPE YYPARSE_PARAM #define YYPARSE_PARAM_DECL #else /* ! ANSI-C/C++ */ #define YYPARSE_PARAM_ARG YYPARSE_PARAM #define YYPARSE_PARAM_DECL YYPARSE_PARAM_TYPE YYPARSE_PARAM; #endif /* ANSI-C/C++ */ #endif /* ! YYPARSE_PARAM */ int yyparse (YYPARSE_PARAM_ARG) YYPARSE_PARAM_DECL { register int yym, yyn, yystate; #if YYDEBUG register const char *yys; if ((yys = getenv("YYDEBUG"))) { yyn = *yys; if (yyn >= '0' && yyn <= '9') yydebug = yyn - '0'; } #endif yynerrs = 0; yyerrflag = 0; yychar = (-1); if (yyss == NULL && yygrowstack()) goto yyoverflow; yyssp = yyss; yyvsp = yyvs; *yyssp = yystate = 0; yyloop: if ((yyn = yydefred[yystate])) goto yyreduce; if (yychar < 0) { if ((yychar = yylex()) < 0) yychar = 0; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, reading %d (%s)\n", YYPREFIX, yystate, yychar, yys); } #endif } if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yychar) { #if YYDEBUG if (yydebug) printf("%sdebug: state %d, shifting to state %d\n", YYPREFIX, yystate, yytable[yyn]); #endif if (yyssp >= yysslim && yygrowstack()) { goto yyoverflow; } *++yyssp = yystate = yytable[yyn]; *++yyvsp = yylval; yychar = (-1); if (yyerrflag > 0) --yyerrflag; goto yyloop; } if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yychar) { yyn = yytable[yyn]; goto yyreduce; } if (yyerrflag) goto yyinrecovery; #if defined(lint) || defined(__GNUC__) goto yynewerror; #endif yynewerror: yyerror("syntax error"); #if defined(lint) || defined(__GNUC__) goto yyerrlab; #endif yyerrlab: ++yynerrs; yyinrecovery: if (yyerrflag < 3) { yyerrflag = 3; for (;;) { if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) { #if YYDEBUG if (yydebug) printf("%sdebug: state %d, error recovery shifting\ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); #endif if (yyssp >= yysslim && yygrowstack()) { goto yyoverflow; } *++yyssp = yystate = yytable[yyn]; *++yyvsp = yylval; goto yyloop; } else { #if YYDEBUG if (yydebug) printf("%sdebug: error recovery discarding state %d\n", YYPREFIX, *yyssp); #endif if (yyssp <= yyss) goto yyabort; --yyssp; --yyvsp; } } } else { if (yychar == 0) goto yyabort; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, error recovery discards token %d (%s)\n", YYPREFIX, yystate, yychar, yys); } #endif yychar = (-1); goto yyloop; } yyreduce: #if YYDEBUG if (yydebug) printf("%sdebug: state %d, reducing by rule %d (%s)\n", YYPREFIX, yystate, yyn, yyrule[yyn]); #endif yym = yylen[yyn]; yyval = yyvsp[1-yym]; switch (yyn) { case 1: #line 91 "parse.y" { ADD_OP(OP_RETURN_NO_VAL); return 0; } break; case 2: #line 94 "parse.y" { ADD_OP(OP_RETURN_NO_VAL); return 0; } break; case 3: #line 97 "parse.y" { ADD_OP(OP_RETURN_NO_VAL); return 0; } break; case 4: #line 100 "parse.y" { return 1; } break; case 11: #line 112 "parse.y" { SET_BR_OFF(yyvsp[-3].inst, GetPC()); } break; case 12: #line 115 "parse.y" { SET_BR_OFF(yyvsp[-6].inst, (yyvsp[-2].inst+1)); SET_BR_OFF(yyvsp[-2].inst, GetPC()); } break; case 13: #line 118 "parse.y" { ADD_OP(OP_BRANCH); ADD_BR_OFF(yyvsp[-5].inst); SET_BR_OFF(yyvsp[-3].inst, GetPC()); FillLoopAddrs(GetPC(), yyvsp[-5].inst); } break; case 14: #line 122 "parse.y" { FillLoopAddrs(GetPC()+2+(yyvsp[-3].inst-(yyvsp[-5].inst+1)), GetPC()); SwapCode(yyvsp[-5].inst+1, yyvsp[-3].inst, GetPC()); ADD_OP(OP_BRANCH); ADD_BR_OFF(yyvsp[-7].inst); SET_BR_OFF(yyvsp[-5].inst, GetPC()); } break; case 15: #line 127 "parse.y" { Symbol *iterSym = InstallIteratorSymbol(); ADD_OP(OP_BEGIN_ARRAY_ITER); ADD_SYM(iterSym); ADD_OP(OP_ARRAY_ITER); ADD_SYM(yyvsp[-3].sym); ADD_SYM(iterSym); ADD_BR_OFF(0); } break; case 16: #line 132 "parse.y" { ADD_OP(OP_BRANCH); ADD_BR_OFF(yyvsp[-4].inst+2); SET_BR_OFF(yyvsp[-4].inst+5, GetPC()); FillLoopAddrs(GetPC(), yyvsp[-4].inst+2); } break; case 17: #line 137 "parse.y" { ADD_OP(OP_BRANCH); ADD_BR_OFF(0); if (AddBreakAddr(GetPC()-1)) { yyerror("break outside loop"); YYERROR; } } break; case 18: #line 143 "parse.y" { ADD_OP(OP_BRANCH); ADD_BR_OFF(0); if (AddContinueAddr(GetPC()-1)) { yyerror("continue outside loop"); YYERROR; } } break; case 19: #line 149 "parse.y" { ADD_OP(OP_RETURN); } break; case 20: #line 152 "parse.y" { ADD_OP(OP_RETURN_NO_VAL); } break; case 21: #line 156 "parse.y" { ADD_OP(OP_ASSIGN); ADD_SYM(yyvsp[-2].sym); } break; case 22: #line 159 "parse.y" { ADD_OP(OP_ADD); ADD_OP(OP_ASSIGN); ADD_SYM(yyvsp[-2].sym); } break; case 23: #line 162 "parse.y" { ADD_OP(OP_SUB); ADD_OP(OP_ASSIGN); ADD_SYM(yyvsp[-2].sym); } break; case 24: #line 165 "parse.y" { ADD_OP(OP_MUL); ADD_OP(OP_ASSIGN); ADD_SYM(yyvsp[-2].sym); } break; case 25: #line 168 "parse.y" { ADD_OP(OP_DIV); ADD_OP(OP_ASSIGN); ADD_SYM(yyvsp[-2].sym); } break; case 26: #line 171 "parse.y" { ADD_OP(OP_MOD); ADD_OP(OP_ASSIGN); ADD_SYM(yyvsp[-2].sym); } break; case 27: #line 174 "parse.y" { ADD_OP(OP_BIT_AND); ADD_OP(OP_ASSIGN); ADD_SYM(yyvsp[-2].sym); } break; case 28: #line 177 "parse.y" { ADD_OP(OP_BIT_OR); ADD_OP(OP_ASSIGN); ADD_SYM(yyvsp[-2].sym); } break; case 29: #line 180 "parse.y" { ADD_OP(OP_ARRAY_DELETE); ADD_IMMED(yyvsp[-1].nArgs); } break; case 30: #line 183 "parse.y" { ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED(yyvsp[-3].nArgs); } break; case 31: #line 186 "parse.y" { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(1); ADD_IMMED(yyvsp[-3].nArgs); ADD_OP(OP_ADD); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED(yyvsp[-3].nArgs); } break; case 32: #line 191 "parse.y" { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(1); ADD_IMMED(yyvsp[-3].nArgs); ADD_OP(OP_SUB); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED(yyvsp[-3].nArgs); } break; case 33: #line 196 "parse.y" { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(1); ADD_IMMED(yyvsp[-3].nArgs); ADD_OP(OP_MUL); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED(yyvsp[-3].nArgs); } break; case 34: #line 201 "parse.y" { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(1); ADD_IMMED(yyvsp[-3].nArgs); ADD_OP(OP_DIV); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED(yyvsp[-3].nArgs); } break; case 35: #line 206 "parse.y" { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(1); ADD_IMMED(yyvsp[-3].nArgs); ADD_OP(OP_MOD); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED(yyvsp[-3].nArgs); } break; case 36: #line 211 "parse.y" { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(1); ADD_IMMED(yyvsp[-3].nArgs); ADD_OP(OP_BIT_AND); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED(yyvsp[-3].nArgs); } break; case 37: #line 216 "parse.y" { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(1); ADD_IMMED(yyvsp[-3].nArgs); ADD_OP(OP_BIT_OR); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED(yyvsp[-3].nArgs); } break; case 38: #line 221 "parse.y" { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(0); ADD_IMMED(yyvsp[-2].nArgs); ADD_OP(OP_INCR); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED(yyvsp[-2].nArgs); } break; case 39: #line 226 "parse.y" { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(0); ADD_IMMED(yyvsp[-2].nArgs); ADD_OP(OP_DECR); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED(yyvsp[-2].nArgs); } break; case 40: #line 231 "parse.y" { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(0); ADD_IMMED(yyvsp[-1].nArgs); ADD_OP(OP_INCR); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED(yyvsp[-1].nArgs); } break; case 41: #line 236 "parse.y" { ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(0); ADD_IMMED(yyvsp[-1].nArgs); ADD_OP(OP_DECR); ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED(yyvsp[-1].nArgs); } break; case 42: #line 241 "parse.y" { ADD_OP(OP_SUBR_CALL); ADD_SYM(PromoteToGlobal(yyvsp[-3].sym)); ADD_IMMED(yyvsp[-1].nArgs); } break; case 43: #line 245 "parse.y" { ADD_OP(OP_PUSH_SYM); ADD_SYM(yyvsp[0].sym); ADD_OP(OP_INCR); ADD_OP(OP_ASSIGN); ADD_SYM(yyvsp[0].sym); } break; case 44: #line 249 "parse.y" { ADD_OP(OP_PUSH_SYM); ADD_SYM(yyvsp[-1].sym); ADD_OP(OP_INCR); ADD_OP(OP_ASSIGN); ADD_SYM(yyvsp[-1].sym); } break; case 45: #line 253 "parse.y" { ADD_OP(OP_PUSH_SYM); ADD_SYM(yyvsp[0].sym); ADD_OP(OP_DECR); ADD_OP(OP_ASSIGN); ADD_SYM(yyvsp[0].sym); } break; case 46: #line 257 "parse.y" { ADD_OP(OP_PUSH_SYM); ADD_SYM(yyvsp[-1].sym); ADD_OP(OP_DECR); ADD_OP(OP_ASSIGN); ADD_SYM(yyvsp[-1].sym); } break; case 47: #line 262 "parse.y" { yyval.sym = yyvsp[0].sym; ADD_OP(OP_PUSH_SYM); ADD_SYM(yyvsp[0].sym); } break; case 48: #line 266 "parse.y" { yyval.inst = GetPC(); } break; case 49: #line 269 "parse.y" { yyval.inst = GetPC(); } break; case 50: #line 272 "parse.y" { yyval.inst = GetPC(); } break; case 51: #line 276 "parse.y" { yyval.nArgs = 0; } break; case 52: #line 279 "parse.y" { yyval.nArgs = 1; } break; case 53: #line 282 "parse.y" { yyval.nArgs = yyvsp[-2].nArgs + 1; } break; case 55: #line 287 "parse.y" { ADD_OP(OP_CONCAT); } break; case 56: #line 291 "parse.y" { ADD_OP(OP_PUSH_ARRAY_SYM); ADD_SYM(yyvsp[0].sym); ADD_IMMED(1); } break; case 57: #line 294 "parse.y" { ADD_OP(OP_ARRAY_REF); ADD_IMMED(yyvsp[-1].nArgs); } break; case 58: #line 298 "parse.y" { ADD_OP(OP_PUSH_ARRAY_SYM); ADD_SYM(yyvsp[0].sym); ADD_IMMED(0); } break; case 59: #line 301 "parse.y" { ADD_OP(OP_ARRAY_REF); ADD_IMMED(yyvsp[-1].nArgs); } break; case 60: #line 305 "parse.y" { yyval.inst = GetPC(); } break; case 61: #line 309 "parse.y" { ADD_OP(OP_PUSH_SYM); ADD_SYM(yyvsp[0].sym); } break; case 62: #line 312 "parse.y" { ADD_OP(OP_PUSH_SYM); ADD_SYM(yyvsp[0].sym); } break; case 63: #line 315 "parse.y" { ADD_OP(OP_PUSH_SYM); ADD_SYM(yyvsp[0].sym); } break; case 64: #line 318 "parse.y" { ADD_OP(OP_SUBR_CALL); ADD_SYM(PromoteToGlobal(yyvsp[-3].sym)); ADD_IMMED(yyvsp[-1].nArgs); ADD_OP(OP_FETCH_RET_VAL); } break; case 66: #line 324 "parse.y" { ADD_OP(OP_PUSH_ARG); } break; case 67: #line 327 "parse.y" { ADD_OP(OP_PUSH_ARG_COUNT); } break; case 68: #line 330 "parse.y" { ADD_OP(OP_PUSH_ARG_ARRAY); } break; case 69: #line 333 "parse.y" { ADD_OP(OP_ARRAY_REF); ADD_IMMED(yyvsp[-1].nArgs); } break; case 70: #line 336 "parse.y" { ADD_OP(OP_ADD); } break; case 71: #line 339 "parse.y" { ADD_OP(OP_SUB); } break; case 72: #line 342 "parse.y" { ADD_OP(OP_MUL); } break; case 73: #line 345 "parse.y" { ADD_OP(OP_DIV); } break; case 74: #line 348 "parse.y" { ADD_OP(OP_MOD); } break; case 75: #line 351 "parse.y" { ADD_OP(OP_POWER); } break; case 76: #line 354 "parse.y" { ADD_OP(OP_NEGATE); } break; case 77: #line 357 "parse.y" { ADD_OP(OP_GT); } break; case 78: #line 360 "parse.y" { ADD_OP(OP_GE); } break; case 79: #line 363 "parse.y" { ADD_OP(OP_LT); } break; case 80: #line 366 "parse.y" { ADD_OP(OP_LE); } break; case 81: #line 369 "parse.y" { ADD_OP(OP_EQ); } break; case 82: #line 372 "parse.y" { ADD_OP(OP_NE); } break; case 83: #line 375 "parse.y" { ADD_OP(OP_BIT_AND); } break; case 84: #line 378 "parse.y" { ADD_OP(OP_BIT_OR); } break; case 85: #line 381 "parse.y" { ADD_OP(OP_AND); SET_BR_OFF(yyvsp[-1].inst, GetPC()); } break; case 86: #line 384 "parse.y" { ADD_OP(OP_OR); SET_BR_OFF(yyvsp[-1].inst, GetPC()); } break; case 87: #line 387 "parse.y" { ADD_OP(OP_NOT); } break; case 88: #line 390 "parse.y" { ADD_OP(OP_PUSH_SYM); ADD_SYM(yyvsp[0].sym); ADD_OP(OP_INCR); ADD_OP(OP_DUP); ADD_OP(OP_ASSIGN); ADD_SYM(yyvsp[0].sym); } break; case 89: #line 394 "parse.y" { ADD_OP(OP_PUSH_SYM); ADD_SYM(yyvsp[-1].sym); ADD_OP(OP_DUP); ADD_OP(OP_INCR); ADD_OP(OP_ASSIGN); ADD_SYM(yyvsp[-1].sym); } break; case 90: #line 398 "parse.y" { ADD_OP(OP_PUSH_SYM); ADD_SYM(yyvsp[0].sym); ADD_OP(OP_DECR); ADD_OP(OP_DUP); ADD_OP(OP_ASSIGN); ADD_SYM(yyvsp[0].sym); } break; case 91: #line 402 "parse.y" { ADD_OP(OP_PUSH_SYM); ADD_SYM(yyvsp[-1].sym); ADD_OP(OP_DUP); ADD_OP(OP_DECR); ADD_OP(OP_ASSIGN); ADD_SYM(yyvsp[-1].sym); } break; case 92: #line 406 "parse.y" { ADD_OP(OP_IN_ARRAY); } break; case 93: #line 410 "parse.y" { yyval.inst = GetPC(); StartLoopAddrList(); } break; case 94: #line 414 "parse.y" { StartLoopAddrList(); yyval.inst = GetPC(); } break; case 95: #line 418 "parse.y" { ADD_OP(OP_BRANCH); yyval.inst = GetPC(); ADD_BR_OFF(0); } break; case 96: #line 422 "parse.y" { ADD_OP(OP_BRANCH_NEVER); yyval.inst = GetPC(); ADD_BR_OFF(0); } break; case 97: #line 425 "parse.y" { ADD_OP(OP_BRANCH_FALSE); yyval.inst = GetPC(); ADD_BR_OFF(0); } break; case 98: #line 429 "parse.y" { ADD_OP(OP_DUP); ADD_OP(OP_BRANCH_FALSE); yyval.inst = GetPC(); ADD_BR_OFF(0); } break; case 99: #line 434 "parse.y" { ADD_OP(OP_DUP); ADD_OP(OP_BRANCH_TRUE); yyval.inst = GetPC(); ADD_BR_OFF(0); } break; #line 1868 "y.tab.c" } yyssp -= yym; yystate = *yyssp; yyvsp -= yym; yym = yylhs[yyn]; if (yystate == 0 && yym == 0) { #if YYDEBUG if (yydebug) printf("%sdebug: after reduction, shifting from state 0 to\ state %d\n", YYPREFIX, YYFINAL); #endif yystate = YYFINAL; *++yyssp = YYFINAL; *++yyvsp = yyval; if (yychar < 0) { if ((yychar = yylex()) < 0) yychar = 0; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, reading %d (%s)\n", YYPREFIX, YYFINAL, yychar, yys); } #endif } if (yychar == 0) goto yyaccept; goto yyloop; } if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yystate) yystate = yytable[yyn]; else yystate = yydgoto[yym]; #if YYDEBUG if (yydebug) printf("%sdebug: after reduction, shifting from state %d \ to state %d\n", YYPREFIX, *yyssp, yystate); #endif if (yyssp >= yysslim && yygrowstack()) { goto yyoverflow; } *++yyssp = yystate; *++yyvsp = yyval; goto yyloop; yyoverflow: yyerror("yacc stack overflow"); yyabort: return (1); yyaccept: return (0); } nedit-5.6.orig/source/preferences.c0000644000175000017500000070435511110456077016077 0ustar paulpaulstatic const char CVSID[] = "$Id: preferences.c,v 1.159 2008/08/20 14:57:35 lebert Exp $"; /******************************************************************************* * * * preferences.c -- Nirvana Editor preferences processing * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * April 20, 1993 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "preferences.h" #include "textBuf.h" #include "nedit.h" #include "menu.h" #include "text.h" #include "search.h" #include "window.h" #include "userCmds.h" #include "highlight.h" #include "highlightData.h" #include "help.h" #include "regularExp.h" #include "smartIndent.h" #include "windowTitle.h" #include "server.h" #include "tags.h" #include "../util/prefFile.h" #include "../util/misc.h" #include "../util/DialogF.h" #include "../util/managedList.h" #include "../util/fontsel.h" #include "../util/fileUtils.h" #include "../util/utils.h" #include #include #include #include #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #include "../util/clearcase.h" #endif /*VMS*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #if XmVersion >= 1002 #define MENU_WIDGET(w) (XmGetPostedFromWidget(XtParent(w))) #else #define MENU_WIDGET(w) (w) #endif #define PREF_FILE_VERSION "5.6" /* New styles added in 5.2 for auto-upgrade */ #define ADD_5_2_STYLES " Pointer:#660000:Bold\nRegex:#009944:Bold\nWarning:brown2:Italic" /* maximum number of word delimiters allowed (256 allows whole character set) */ #define MAX_WORD_DELIMITERS 256 /* maximum number of file extensions allowed in a language mode */ #define MAX_FILE_EXTENSIONS 20 /* Return values for checkFontStatus */ enum fontStatus {GOOD_FONT, BAD_PRIMARY, BAD_FONT, BAD_SIZE, BAD_SPACING}; /* enumerated type preference strings ** The order of the elements in this array must be exactly the same ** as the order of the corresponding integers of the enum SearchType ** defined in search.h (!!) */ static char *SearchMethodStrings[] = { "Literal", "CaseSense", "RegExp", "LiteralWord", "CaseSenseWord", "RegExpNoCase", NULL }; #ifdef REPLACE_SCOPE /* enumerated default scope for replace dialog if a selection exists when ** the dialog is popped up. */ static char *ReplaceDefScopeStrings[] = { "Window", "Selection", "Smart", NULL }; #endif #define N_WRAP_STYLES 3 static char *AutoWrapTypes[N_WRAP_STYLES+3] = {"None", "Newline", "Continuous", "True", "False", NULL}; #define N_INDENT_STYLES 3 static char *AutoIndentTypes[N_INDENT_STYLES+3] = {"None", "Auto", "Smart", "True", "False", NULL}; #define N_VIRTKEY_OVERRIDE_MODES 3 static char *VirtKeyOverrideModes[N_VIRTKEY_OVERRIDE_MODES+1] = { "Never", "Auto", "Always", NULL}; #define N_SHOW_MATCHING_STYLES 3 /* For backward compatibility, "False" and "True" are still accepted. They are internally converted to "Off" and "Delimiter" respectively. NOTE: N_SHOW_MATCHING_STYLES must correspond to the number of _real_ matching styles, not counting False & True. False and True should also be the last ones in the list. */ static char *ShowMatchingTypes[] = {"Off", "Delimiter", "Range", "False", "True", NULL}; /* This array must be kept in parallel to the enum truncSubstitution in nedit.h */ static char* TruncSubstitutionModes[] = {"Silent", "Fail", "Warn", "Ignore", NULL}; /* suplement wrap and indent styles w/ a value meaning "use default" for the override fields in the language modes dialog */ #define DEFAULT_WRAP -1 #define DEFAULT_INDENT -1 #define DEFAULT_TAB_DIST -1 #define DEFAULT_EM_TAB_DIST -1 /* list of available language modes and language specific preferences */ static int NLanguageModes = 0; typedef struct { char *name; int nExtensions; char **extensions; char *recognitionExpr; char *defTipsFile; char *delimiters; int wrapStyle; int indentStyle; int tabDist; int emTabDist; } languageModeRec; static languageModeRec *LanguageModes[MAX_LANGUAGE_MODES]; /* Language mode dialog information */ static struct { Widget shell; Widget nameW; Widget extW; Widget recogW; Widget defTipsW; Widget delimitW; Widget managedListW; Widget tabW; Widget emTabW; Widget defaultIndentW; Widget noIndentW; Widget autoIndentW; Widget smartIndentW; Widget defaultWrapW; Widget noWrapW; Widget newlineWrapW; Widget contWrapW; languageModeRec **languageModeList; int nLanguageModes; } LMDialog = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0}; /* Font dialog information */ typedef struct { Widget shell; Widget primaryW; Widget fillW; Widget italicW; Widget italicErrW; Widget boldW; Widget boldErrW; Widget boldItalicW; Widget boldItalicErrW; WindowInfo *window; int forWindow; } fontDialog; /* Color dialog information */ typedef struct { Widget shell; Widget textFgW; Widget textFgErrW; Widget textBgW; Widget textBgErrW; Widget selectFgW; Widget selectFgErrW; Widget selectBgW; Widget selectBgErrW; Widget hiliteFgW; Widget hiliteFgErrW; Widget hiliteBgW; Widget hiliteBgErrW; Widget lineNoFgW; Widget lineNoFgErrW; Widget cursorFgW; Widget cursorFgErrW; WindowInfo *window; } colorDialog; /* Repository for simple preferences settings */ static struct prefData { int openInTab; /* open files in new tabs */ int wrapStyle; /* what kind of wrapping to do */ int wrapMargin; /* 0=wrap at window width, other=wrap margin */ int autoIndent; /* style for auto-indent */ int autoSave; /* whether automatic backup feature is on */ int saveOldVersion; /* whether to preserve a copy of last version */ int searchDlogs; /* whether to show explanatory search dialogs */ int searchWrapBeep; /* 1=beep when search restarts at begin/end */ int keepSearchDlogs; /* whether to retain find and replace dialogs */ int searchWraps; /* whether to attempt search again if reach bof or eof */ int statsLine; /* whether to show the statistics line */ int iSearchLine; /* whether to show the incremental search line*/ int tabBar; /* whether to show the tab bar */ int tabBarHideOne; /* hide tab bar if only one document in window */ int globalTabNavigate; /* prev/next document across windows */ int toolTips; /* whether to show the tooltips */ int lineNums; /* whether to show line numbers */ int pathInWindowsMenu; /* whether to show path in windows menu */ int warnFileMods; /* warn user if files externally modified */ int warnRealFileMods; /* only warn if file contents modified */ int warnExit; /* whether to warn on exit */ int searchMethod; /* initial search method as a text string */ #ifdef REPLACE_SCOPE int replaceDefScope; /* default replace scope if selection exists */ #endif int textRows; /* initial window height in characters */ int textCols; /* initial window width in characters */ int tabDist; /* number of characters between tab stops */ int emTabDist; /* non-zero tab dist. if emulated tabs are on */ int insertTabs; /* whether to use tabs for padding */ int showMatchingStyle; /* how to flash matching parenthesis */ int matchSyntaxBased; /* use syntax info to match parenthesis */ int highlightSyntax; /* whether to highlight syntax by default */ int smartTags; /* look for tag in current window first */ int alwaysCheckRelativeTagsSpecs; /* for every new opened file of session */ int stickyCaseSenseBtn; /* whether Case Word Btn is sticky to Regex Btn */ int prefFileRead; /* detects whether a .nedit existed */ int backlightChars; /* whether to apply character "backlighting" */ char *backlightCharTypes; /* the backlighting color definitions */ #ifdef SGI_CUSTOM int shortMenus; /* short menu mode */ #endif char fontString[MAX_FONT_LEN]; /* names of fonts for text widget */ char boldFontString[MAX_FONT_LEN]; char italicFontString[MAX_FONT_LEN]; char boldItalicFontString[MAX_FONT_LEN]; XmFontList fontList; /* XmFontLists corresp. to above named fonts */ XFontStruct *boldFontStruct; XFontStruct *italicFontStruct; XFontStruct *boldItalicFontStruct; int sortTabs; /* sort tabs alphabetically */ int repositionDialogs; /* w. to reposition dialogs under the pointer */ int autoScroll; /* w. to autoscroll near top/bottom of screen */ int autoScrollVPadding; /* how close to get before autoscrolling */ int sortOpenPrevMenu; /* whether to sort the "Open Previous" menu */ int appendLF; /* Whether to append LF at the end of each file */ int mapDelete; /* whether to map delete to backspace */ int stdOpenDialog; /* w. to retain redundant text field in Open */ char tagFile[MAXPATHLEN]; /* name of tags file to look for at startup */ int maxPrevOpenFiles; /* limit to size of Open Previous menu */ int typingHidesPointer; /* hide mouse pointer when typing */ char delimiters[MAX_WORD_DELIMITERS]; /* punctuation characters */ char shell[MAXPATHLEN + 1]; /* shell to use for executing commands */ char geometry[MAX_GEOM_STRING_LEN]; /* per-application geometry string, only for the clueless */ char serverName[MAXPATHLEN];/* server name for multiple servers per disp. */ char bgMenuBtn[MAX_ACCEL_LEN]; /* X event description for triggering posting of background menu */ char fileVersion[6]; /* Version of nedit which wrote the .nedit file we're reading */ int findReplaceUsesSelection; /* whether the find replace dialog is automatically loaded with the primary selection */ int virtKeyOverride; /* Override Motif default virtual key bindings never, if invalid, or always */ char titleFormat[MAX_TITLE_FORMAT_LEN]; char helpFontNames[NUM_HELP_FONTS][MAX_FONT_LEN];/* fonts for help system */ char helpLinkColor[MAX_COLOR_LEN]; /* Color for hyperlinks in the help system */ char colorNames[NUM_COLORS][MAX_COLOR_LEN]; char tooltipBgColor[MAX_COLOR_LEN]; int undoModifiesSelection; int focusOnRaise; Boolean honorSymlinks; int truncSubstitution; Boolean forceOSConversion; } PrefData; /* Temporary storage for preferences strings which are discarded after being read */ static struct { char *shellCmds; char *macroCmds; char *bgMenuCmds; char *highlight; char *language; char *styles; char *smartIndent; char *smartIndentCommon; char *shell; } TempStringPrefs; /* preference descriptions for SavePreferences and RestorePreferences. */ static PrefDescripRec PrefDescrip[] = { {"fileVersion", "FileVersion" , PREF_STRING, "", PrefData.fileVersion, (void *)sizeof(PrefData.fileVersion), True}, #ifndef VMS #ifdef linux {"shellCommands", "ShellCommands", PREF_ALLOC_STRING, "spell:Alt+B:s:EX:\n\ cat>spellTmp; xterm -e ispell -x spellTmp; cat spellTmp; rm spellTmp\n\ wc::w:ED:\nwc | awk '{print $1 \" lines, \" $2 \" words, \" $3 \" characters\"}'\n\ sort::o:EX:\nsort\nnumber lines::n:AW:\nnl -ba\nmake:Alt+Z:m:W:\nmake\n\ expand::p:EX:\nexpand\nunexpand::u:EX:\nunexpand\n", &TempStringPrefs.shellCmds, NULL, True}, #elif __FreeBSD__ {"shellCommands", "ShellCommands", PREF_ALLOC_STRING, "spell:Alt+B:s:EX:\n\ cat>spellTmp; xterm -e ispell -x spellTmp; cat spellTmp; rm spellTmp\n\ wc::w:ED:\nwc | awk '{print $2 \" lines, \" $1 \" words, \" $3 \" characters\"}'\n\ sort::o:EX:\nsort\nnumber lines::n:AW:\npr -tn\nmake:Alt+Z:m:W:\nmake\n\ expand::p:EX:\nexpand\nunexpand::u:EX:\nunexpand\n", &TempStringPrefs.shellCmds, NULL, True}, #else {"shellCommands", "ShellCommands", PREF_ALLOC_STRING, "spell:Alt+B:s:ED:\n\ (cat;echo \"\") | spell\nwc::w:ED:\nwc | awk '{print $1 \" lines, \" $2 \" words, \" $3 \" characters\"}'\n\ \nsort::o:EX:\nsort\nnumber lines::n:AW:\nnl -ba\nmake:Alt+Z:m:W:\nmake\n\ expand::p:EX:\nexpand\nunexpand::u:EX:\nunexpand\n", &TempStringPrefs.shellCmds, NULL, True}, #endif /* linux, __FreeBSD__ */ #endif /* VMS */ {"macroCommands", "MacroCommands", PREF_ALLOC_STRING, "Complete Word:Alt+D::: {\n\ # This macro attempts to complete the current word by\n\ # finding another word in the same document that has\n\ # the same prefix; repeated invocations of the macro\n\ # (by repeated typing of its accelerator, say) cycles\n\ # through the alternatives found.\n\ # \n\ # Make sure $compWord contains something (a dummy index)\n\ $compWord[\"\"] = \"\"\n\ \n\ # Test whether the rest of $compWord has been initialized:\n\ # this avoids having to initialize the global variable\n\ # $compWord in an external macro file\n\ if (!(\"wordEnd\" in $compWord)) {\n\ # we need to initialize it\n\ $compWord[\"wordEnd\"] = 0\n\ $compWord[\"repeat\"] = 0\n\ $compWord[\"init\"] = 0\n\ $compWord[\"wordStart\"] = 0\n\ }\n\ \n\ if ($compWord[\"wordEnd\"] == $cursor) {\n\ $compWord[\"repeat\"] += 1\n\ }\n\ else {\n\ $compWord[\"repeat\"] = 1\n\ $compWord[\"init\"] = $cursor\n\ \n\ # search back to a word boundary to find the word to complete\n\ # (we use \\w here to allow for programming \"words\" that can include\n\ # digits and underscores; use \\l for letters only)\n\ $compWord[\"wordStart\"] = search(\"<\\\\w+\", $cursor, \"backward\", \"regex\", \"wrap\")\n\ \n\ if ($compWord[\"wordStart\"] == -1)\n\ return\n\ \n\ if ($search_end == $cursor)\n\ $compWord[\"word\"] = get_range($compWord[\"wordStart\"], $cursor)\n\ else\n\ return\n\ }\n\ s = $cursor\n\ for (i=0; i <= $compWord[\"repeat\"]; i++)\n\ s = search($compWord[\"word\"], s - 1, \"backward\", \"regex\", \"wrap\")\n\ \n\ if (s == $compWord[\"wordStart\"]) {\n\ beep()\n\ $compWord[\"repeat\"] = 0\n\ s = $compWord[\"wordStart\"]\n\ se = $compWord[\"init\"]\n\ }\n\ else\n\ se = search(\">\", s, \"regex\")\n\ \n\ replace_range($compWord[\"wordStart\"], $cursor, get_range(s, se))\n\ \n\ $compWord[\"wordEnd\"] = $cursor\n\ }\n\ Fill Sel. w/Char:::R: {\n\ # This macro replaces each character position in\n\ # the selection with the string typed into the dialog\n\ # it displays.\n\ if ($selection_start == -1) {\n\ beep()\n\ return\n\ }\n\ \n\ # Ask the user what character to fill with\n\ fillChar = string_dialog(\"Fill selection with what character?\", \\\n\ \"OK\", \"Cancel\")\n\ if ($string_dialog_button == 2 || $string_dialog_button == 0)\n\ return\n\ \n\ # Count the number of lines (NL characters) in the selection\n\ # (by removing all non-NLs in selection and counting the remainder)\n\ nLines = length(replace_in_string(get_selection(), \\\n\ \"^.*$\", \"\", \"regex\"))\n\ \n\ rectangular = $selection_left != -1\n\ \n\ # work out the pieces of required of the replacement text\n\ # this will be top mid bot where top is empty or ends in NL,\n\ # mid is 0 or more lines of repeats ending with NL, and\n\ # bot is 0 or more repeats of the fillChar\n\ \n\ toplen = -1 # top piece by default empty (no NL)\n\ midlen = 0\n\ botlen = 0\n\ \n\ if (rectangular) {\n\ # just fill the rectangle: mid\\n \\ nLines\n\ # mid\\n /\n\ # bot - last line with no nl\n\ midlen = $selection_right - $selection_left\n\ botlen = $selection_right - $selection_left\n\ } else {\n\ # |col[0]\n\ # .........toptoptop\\n |col[0]\n\ # either midmidmidmidmidmid\\n \\ nLines - 1 or ...botbot...\n\ # midmidmidmidmidmid\\n / |col[1]\n\ # botbot... |\n\ # |col[1] |wrap margin\n\ # we need column positions col[0], col[1] of selection start and\n\ # end (use a loop and arrays to do the two positions)\n\ sel[0] = $selection_start\n\ sel[1] = $selection_end\n\ \n\ # col[0] = pos_to_column($selection_start)\n\ # col[1] = pos_to_column($selection_end)\n\ \n\ for (i = 0; i < 2; ++i) {\n\ end = sel[i]\n\ pos = search(\"^\", end, \"regex\", \"backward\")\n\ thisCol = 0\n\ while (pos < end) {\n\ nexttab = search(\"\\t\", pos)\n\ if (nexttab < 0 || nexttab >= end) {\n\ thisCol += end - pos # count remaining non-tabs\n\ nexttab = end\n\ } else {\n\ thisCol += nexttab - pos + $tab_dist\n\ thisCol -= (thisCol % $tab_dist)\n\ }\n\ pos = nexttab + 1 # skip past the tab or end\n\ }\n\ col[i] = thisCol\n\ }\n\ toplen = max($wrap_margin - col[0], 0)\n\ botlen = min(col[1], $wrap_margin)\n\ \n\ if (nLines == 0) {\n\ toplen = -1\n\ botlen = max(botlen - col[0], 0)\n\ } else {\n\ midlen = $wrap_margin\n\ if (toplen < 0)\n\ toplen = 0\n\ nLines-- # top piece will end in a NL\n\ }\n\ }\n\ \n\ # Create the fill text\n\ # which is the longest piece? make a line of that length\n\ # (use string doubling - this allows the piece to be\n\ # appended to double in size at each iteration)\n\ \n\ len = max(toplen, midlen, botlen)\n\ charlen = length(fillChar) # maybe more than one char given!\n\ \n\ line = \"\"\n\ while (len > 0) {\n\ if (len % 2)\n\ line = line fillChar\n\ len /= 2\n\ if (len > 0)\n\ fillChar = fillChar fillChar\n\ }\n\ # assemble our pieces\n\ toppiece = \"\"\n\ midpiece = \"\"\n\ botpiece = \"\"\n\ if (toplen >= 0)\n\ toppiece = substring(line, 0, toplen * charlen) \"\\n\"\n\ if (botlen > 0)\n\ botpiece = substring(line, 0, botlen * charlen)\n\ \n\ # assemble midpiece (use doubling again)\n\ line = substring(line, 0, midlen * charlen) \"\\n\"\n\ while (nLines > 0) {\n\ if (nLines % 2)\n\ midpiece = midpiece line\n\ nLines /= 2\n\ if (nLines > 0)\n\ line = line line\n\ }\n\ # Replace the selection with the complete fill text\n\ replace_selection(toppiece midpiece botpiece)\n\ }\n\ Quote Mail Reply:::: {\n\ if ($selection_start == -1)\n\ replace_all(\"^.*$\", \"\\\\> &\", \"regex\")\n\ else\n\ replace_in_selection(\"^.*$\", \"\\\\> &\", \"regex\")\n\ }\n\ Unquote Mail Reply:::: {\n\ if ($selection_start == -1)\n\ replace_all(\"(^\\\\> )(.*)$\", \"\\\\2\", \"regex\")\n\ else\n\ replace_in_selection(\"(^\\\\> )(.*)$\", \"\\\\2\", \"regex\")\n\ }\n\ Comments>/* Comment */@C@C++@Java@CSS@JavaScript@Lex:::R: {\n\ selStart = $selection_start\n\ selEnd = $selection_end\n\ replace_range(selStart, selEnd, \"/* \" get_selection() \" */\")\n\ select(selStart, selEnd + 6)\n\ }\n\ Comments>/* Uncomment */@C@C++@Java@CSS@JavaScript@Lex:::R: {\n\ pos = search(\"(?n\\\\s*/\\\\*\\\\s*)\", $selection_start, \"regex\")\n\ start = $search_end\n\ end = search(\"(?n\\\\*/\\\\s*)\", $selection_end, \"regex\", \"backward\")\n\ if (pos != $selection_start || end == -1 )\n\ return\n\ replace_selection(get_range(start, end))\n\ select(pos, $cursor)\n\ }\n\ Comments>// Comment@C@C++@Java@JavaScript:::R: {\n\ replace_in_selection(\"^.*$\", \"// &\", \"regex\")\n\ }\n\ Comments>// Uncomment@C@C++@Java@JavaScript:::R: {\n\ replace_in_selection(\"(^[ \\\\t]*// ?)(.*)$\", \"\\\\2\", \"regex\")\n\ }\n\ Comments># Comment@Perl@Sh Ksh Bash@NEdit Macro@Makefile@Awk@Csh@Python@Tcl:::R: {\n\ replace_in_selection(\"^.*$\", \"#&\", \"regex\")\n\ }\n\ Comments># Uncomment@Perl@Sh Ksh Bash@NEdit Macro@Makefile@Awk@Csh@Python@Tcl:::R: {\n\ replace_in_selection(\"(^[ \\\\t]*#)(.*)$\", \"\\\\2\", \"regex\")\n\ }\n\ Comments>-- Comment@SQL:::R: {\n\ replace_in_selection(\"^.*$\", \"--&\", \"regex\")\n\ }\n\ Comments>-- Uncomment@SQL:::R: {\n\ replace_in_selection(\"(^[ \\\\t]*--)(.*)$\", \"\\\\2\", \"regex\")\n\ }\n\ Comments>! Comment@X Resources:::R: {\n\ replace_in_selection(\"^.*$\", \"!&\", \"regex\")\n\ }\n\ Comments>! Uncomment@X Resources:::R: {\n\ replace_in_selection(\"(^[ \\\\t]*!)(.*)$\", \"\\\\2\", \"regex\")\n\ }\n\ Comments>% Comment@LaTeX:::R: {\n\ replace_in_selection(\"^.*$\", \"%&\", \"regex\")\n\ }\n\ Comments>% Uncomment@LaTeX:::R: {\n\ replace_in_selection(\"(^[ \\\\t]*%)(.*)$\", \"\\\\2\", \"regex\")\n\ }\n\ Comments>Bar Comment@C:::R: {\n\ if ($selection_left != -1) {\n\ dialog(\"Selection must not be rectangular\")\n\ return\n\ }\n\ start = $selection_start\n\ end = $selection_end-1\n\ origText = get_range($selection_start, $selection_end-1)\n\ newText = \"/*\\n\" replace_in_string(get_range(start, end), \\\n\ \"^\", \" * \", \"regex\") \"\\n */\\n\"\n\ replace_selection(newText)\n\ select(start, start + length(newText))\n\ }\n\ Comments>Bar Uncomment@C:::R: {\n\ selStart = $selection_start\n\ selEnd = $selection_end\n\ pos = search(\"/\\\\*\\\\s*\\\\n\", selStart, \"regex\")\n\ if (pos != selStart) return\n\ start = $search_end\n\ end = search(\"\\\\n\\\\s*\\\\*/\\\\s*\\\\n?\", selEnd, \"regex\", \"backward\")\n\ if (end == -1 || $search_end < selEnd) return\n\ newText = get_range(start, end)\n\ newText = replace_in_string(newText,\"^ *\\\\* ?\", \"\", \"regex\", \"copy\")\n\ if (get_range(selEnd, selEnd - 1) == \"\\n\") selEnd -= 1\n\ replace_range(selStart, selEnd, newText)\n\ select(selStart, selStart + length(newText))\n\ }\n\ Make C Prototypes@C@C++:::: {\n\ # simplistic extraction of C function prototypes, usually good enough\n\ if ($selection_start == -1) {\n\ start = 0\n\ end = $text_length\n\ } else {\n\ start = $selection_start\n\ end = $selection_end\n\ }\n\ string = get_range(start, end)\n\ # remove all C++ and C comments, then all blank lines in the extracted range\n\ string = replace_in_string(string, \"//.*$\", \"\", \"regex\", \"copy\")\n\ string = replace_in_string(string, \"(?n/\\\\*.*?\\\\*/)\", \"\", \"regex\", \"copy\")\n\ string = replace_in_string(string, \"^\\\\s*\\n\", \"\", \"regex\", \"copy\")\n\ nDefs = 0\n\ searchPos = 0\n\ prototypes = \"\"\n\ staticPrototypes = \"\"\n\ for (;;) {\n\ headerStart = search_string(string, \\\n\ \"^[a-zA-Z]([^;#\\\"'{}=>?~\":\n\ C:.C .H::::::\".,/\\`'!|@#%^&*()-=+{}[]\"\":;<>?~\":\n\ CSS:CSS::Auto:None:::\".,/\\`'!|@#%^&*()=+{}[]\"\":;<>?~\":\n\ Csh:.CSH .CSHRC .TCSHRC .LOGIN .LOGOUT:\"^[ \\t]*#[ \\t]*![ \\t]*/bin/t?csh\"::::::\n\ Fortran:.F .F77 .FOR:::::::\n\ Java:.JAVA:::::::\n\ LaTeX:.TEX .STY .CLS .LTX .INS .CLO .FD:::::::\n\ Lex:.LEX:::::::\n\ Makefile:MAKEFILE:::None:8:8::\n\ Matlab:.M .OCT .SCI:::::::\n\ NEdit Macro:.NM .NEDITMACRO:::::::\n\ Pascal:.PAS .P .INT:::::::\n\ Perl:.PL .PM .P5:\"^[ \\t]*#[ \\t]*!.*perl\":Auto:None:::\".,/\\\\`'!$@#%^&*()-=+{}[]\"\":;<>?~|\":\n\ PostScript:.ps .PS .eps .EPS .epsf .epsi:\"^%!\":::::\"/%(){}[]<>\":\n\ Python:.PY:\"^#!.*python\":Auto:None:::\"!\"\"#$%&'()*+,-./:;<=>?@[\\\\]^`{|}~\":\n\ Regex:.REG .REGEX:\"\\(\\?[:#=!iInN].+\\)\":None:Continuous::::\n\ SGML HTML:.SGML .SGM .HTML .HTM:\"\\<[Hh][Tt][Mm][Ll]\\>\"::::::\n\ SQL:.SQL:::::::\n\ Sh Ksh Bash:.SH .BASH .KSH .PROFILE .BASHRC .BASH_LOGOUT .BASH_LOGIN .BASH_PROFILE:\"^[ \\t]*#[ \\t]*![ \\t]*/.*bin/(bash|ksh|sh|zsh)\"::::::\n\ Tcl:.TCL::Smart:None::::\n\ VHDL:.VHD .VHDL .VDL:::::::\n\ Verilog:.V:::::::\n\ XML:.XML .XSL .DTD:\"\\<(?i\\?xml|!doctype)\"::None:::\"<>/=\"\"'()+*?|\":\n\ X Resources:.XRESOURCES .XDEFAULTS .NEDIT .PATS NEDIT.RC:\"^[!#].*([Aa]pp|[Xx]).*[Dd]efaults\"::::::\n\ Yacc:.Y::::::\".,/\\`'!|@#%^&*()-=+{}[]\"\":;<>?~\":", #else "Ada:.ada .ad .ads .adb .a:::::::\n\ Awk:.awk:::::::\n\ C++:.cc .hh .C .H .i .cxx .hxx .cpp .c++::::::\".,/\\`'!|@#%^&*()-=+{}[]\"\":;<>?~\":\n\ C:.c .h::::::\".,/\\`'!|@#%^&*()-=+{}[]\"\":;<>?~\":\n\ CSS:css::Auto:None:::\".,/\\`'!|@#%^&*()=+{}[]\"\":;<>?~\":\n\ Csh:.csh .cshrc .tcshrc .login .logout:\"^[ \\t]*#[ \\t]*![ \\t]*/bin/t?csh\"::::::\n\ Fortran:.f .f77 .for:::::::\n\ Java:.java:::::::\n\ JavaScript:.js:::::::\n\ LaTeX:.tex .sty .cls .ltx .ins .clo .fd:::::::\n\ Lex:.lex:::::::\n\ Makefile:Makefile makefile .gmk:::None:8:8::\n\ Matlab:.m .oct .sci:::::::\n\ NEdit Macro:.nm .neditmacro:::::::\n\ Pascal:.pas .p .int:::::::\n\ Perl:.pl .pm .p5 .PL:\"^[ \\t]*#[ \\t]*!.*perl\":Auto:None:::\".,/\\\\`'!$@#%^&*()-=+{}[]\"\":;<>?~|\":\n\ PostScript:.ps .eps .epsf .epsi:\"^%!\":::::\"/%(){}[]<>\":\n\ Python:.py:\"^#!.*python\":Auto:None:::\"!\"\"#$%&'()*+,-./:;<=>?@[\\\\]^`{|}~\":\n\ Regex:.reg .regex:\"\\(\\?[:#=!iInN].+\\)\":None:Continuous::::\n\ SGML HTML:.sgml .sgm .html .htm:\"\\<[Hh][Tt][Mm][Ll]\\>\"::::::\n\ SQL:.sql:::::::\n\ Sh Ksh Bash:.sh .bash .ksh .profile .bashrc .bash_logout .bash_login .bash_profile:\"^[ \\t]*#[ \\t]*![ \\t]*/.*bin/(bash|ksh|sh|zsh)\"::::::\n\ Tcl:.tcl .tk .itcl .itk::Smart:None::::\n\ VHDL:.vhd .vhdl .vdl:::::::\n\ Verilog:.v:::::::\n\ XML:.xml .xsl .dtd:\"\\<(?i\\?xml|!doctype)\"::None:::\"<>/=\"\"'()+*?|\":\n\ X Resources:.Xresources .Xdefaults .nedit .pats nedit.rc:\"^[!#].*([Aa]pp|[Xx]).*[Dd]efaults\"::::::\n\ Yacc:.y::::::\".,/\\`'!|@#%^&*()-=+{}[]\"\":;<>?~\":", #endif &TempStringPrefs.language, NULL, True}, {"styles", "Styles", PREF_ALLOC_STRING, "Plain:black:Plain\n\ Comment:gray20:Italic\n\ Keyword:black:Bold\n\ Operator:dark blue:Bold\n\ Bracket:dark blue:Bold\n\ Storage Type:brown:Bold\n\ Storage Type1:saddle brown:Bold\n\ String:darkGreen:Plain\n\ String1:SeaGreen:Plain\n\ String2:darkGreen:Bold\n\ Preprocessor:RoyalBlue4:Plain\n\ Preprocessor1:blue:Plain\n\ Character Const:darkGreen:Plain\n\ Numeric Const:darkGreen:Plain\n\ Identifier:brown:Plain\n\ Identifier1:RoyalBlue4:Plain\n\ Identifier2:SteelBlue:Plain\n\ Subroutine:brown:Plain\n\ Subroutine1:chocolate:Plain\n\ Ada Attributes:plum:Bold\n\ Label:red:Italic\n\ Flag:red:Bold\n\ Text Comment:SteelBlue4:Italic\n\ Text Key:VioletRed4:Bold\n\ Text Key1:VioletRed4:Plain\n\ Text Arg:RoyalBlue4:Bold\n\ Text Arg1:SteelBlue4:Bold\n\ Text Arg2:RoyalBlue4:Plain\n\ Text Escape:gray30:Bold\n\ LaTeX Math:darkGreen:Plain\n" ADD_5_2_STYLES, &TempStringPrefs.styles, NULL, True}, {"smartIndentInit", "SmartIndentInit", PREF_ALLOC_STRING, "C:Default\n\ C++:Default\n\ Python:Default\n\ Matlab:Default", &TempStringPrefs.smartIndent, NULL, True}, {"smartIndentInitCommon", "SmartIndentInitCommon", PREF_ALLOC_STRING, "Default", &TempStringPrefs.smartIndentCommon, NULL, True}, {"autoWrap", "AutoWrap", PREF_ENUM, "Continuous", &PrefData.wrapStyle, AutoWrapTypes, True}, {"wrapMargin", "WrapMargin", PREF_INT, "0", &PrefData.wrapMargin, NULL, True}, {"autoIndent", "AutoIndent", PREF_ENUM, "Auto", &PrefData.autoIndent, AutoIndentTypes, True}, {"autoSave", "AutoSave", PREF_BOOLEAN, "True", &PrefData.autoSave, NULL, True}, {"openInTab", "OpenInTab", PREF_BOOLEAN, "True", &PrefData.openInTab, NULL, True}, {"saveOldVersion", "SaveOldVersion", PREF_BOOLEAN, "False", &PrefData.saveOldVersion, NULL, True}, {"showMatching", "ShowMatching", PREF_ENUM, "Delimiter", &PrefData.showMatchingStyle, ShowMatchingTypes, True}, {"matchSyntaxBased", "MatchSyntaxBased", PREF_BOOLEAN, "True", &PrefData.matchSyntaxBased, NULL, True}, {"highlightSyntax", "HighlightSyntax", PREF_BOOLEAN, "True", &PrefData.highlightSyntax, NULL, True}, {"backlightChars", "BacklightChars", PREF_BOOLEAN, "False", &PrefData.backlightChars, NULL, True}, {"backlightCharTypes", "BacklightCharTypes", PREF_ALLOC_STRING, "0-8,10-31,127:red;9:#dedede;32,160-255:#f0f0f0;128-159:orange", /* gray87 gray94 */ &PrefData.backlightCharTypes, NULL, False}, {"searchDialogs", "SearchDialogs", PREF_BOOLEAN, "False", &PrefData.searchDlogs, NULL, True}, {"beepOnSearchWrap", "BeepOnSearchWrap", PREF_BOOLEAN, "False", &PrefData.searchWrapBeep, NULL, True}, {"retainSearchDialogs", "RetainSearchDialogs", PREF_BOOLEAN, "False", &PrefData.keepSearchDlogs, NULL, True}, {"searchWraps", "SearchWraps", PREF_BOOLEAN, "True", &PrefData.searchWraps, NULL, True}, {"stickyCaseSenseButton", "StickyCaseSenseButton", PREF_BOOLEAN, "True", &PrefData.stickyCaseSenseBtn, NULL, True}, #if XmVersion < 1002 /* Flashing is annoying in 1.1 versions */ {"repositionDialogs", "RepositionDialogs", PREF_BOOLEAN, "False", &PrefData.repositionDialogs, NULL, True}, #else {"repositionDialogs", "RepositionDialogs", PREF_BOOLEAN, "True", &PrefData.repositionDialogs, NULL, True}, #endif {"autoScroll", "AutoScroll", PREF_BOOLEAN, "False", &PrefData.autoScroll, NULL, True}, {"autoScrollVPadding", "AutoScrollVPadding", PREF_INT, "4", &PrefData.autoScrollVPadding, NULL, False}, {"appendLF", "AppendLF", PREF_BOOLEAN, "True", &PrefData.appendLF, NULL, True}, {"sortOpenPrevMenu", "SortOpenPrevMenu", PREF_BOOLEAN, "True", &PrefData.sortOpenPrevMenu, NULL, True}, {"statisticsLine", "StatisticsLine", PREF_BOOLEAN, "False", &PrefData.statsLine, NULL, True}, {"iSearchLine", "ISearchLine", PREF_BOOLEAN, "False", &PrefData.iSearchLine, NULL, True}, {"sortTabs", "SortTabs", PREF_BOOLEAN, "False", &PrefData.sortTabs, NULL, True}, {"tabBar", "TabBar", PREF_BOOLEAN, "True", &PrefData.tabBar, NULL, True}, {"tabBarHideOne", "TabBarHideOne", PREF_BOOLEAN, "True", &PrefData.tabBarHideOne, NULL, True}, {"toolTips", "ToolTips", PREF_BOOLEAN, "True", &PrefData.toolTips, NULL, True}, {"globalTabNavigate", "GlobalTabNavigate", PREF_BOOLEAN, "False", &PrefData.globalTabNavigate, NULL, True}, {"lineNumbers", "LineNumbers", PREF_BOOLEAN, "False", &PrefData.lineNums, NULL, True}, {"pathInWindowsMenu", "PathInWindowsMenu", PREF_BOOLEAN, "True", &PrefData.pathInWindowsMenu, NULL, True}, {"warnFileMods", "WarnFileMods", PREF_BOOLEAN, "True", &PrefData.warnFileMods, NULL, True}, {"warnRealFileMods", "WarnRealFileMods", PREF_BOOLEAN, "True", &PrefData.warnRealFileMods, NULL, True}, {"warnExit", "WarnExit", PREF_BOOLEAN, "True", &PrefData.warnExit, NULL, True}, {"searchMethod", "SearchMethod", PREF_ENUM, "Literal", &PrefData.searchMethod, SearchMethodStrings, True}, #ifdef REPLACE_SCOPE {"replaceDefaultScope", "ReplaceDefaultScope", PREF_ENUM, "Smart", &PrefData.replaceDefScope, ReplaceDefScopeStrings, True}, #endif {"textRows", "TextRows", PREF_INT, "24", &PrefData.textRows, NULL, True}, {"textCols", "TextCols", PREF_INT, "80", &PrefData.textCols, NULL, True}, {"tabDistance", "TabDistance", PREF_INT, "8", &PrefData.tabDist, NULL, True}, {"emulateTabs", "EmulateTabs", PREF_INT, "0", &PrefData.emTabDist, NULL, True}, {"insertTabs", "InsertTabs", PREF_BOOLEAN, "True", &PrefData.insertTabs, NULL, True}, {"textFont", "TextFont", PREF_STRING, "-*-courier-medium-r-normal--*-120-*-*-*-iso8859-1", PrefData.fontString, (void *)sizeof(PrefData.fontString), True}, {"boldHighlightFont", "BoldHighlightFont", PREF_STRING, "-*-courier-bold-r-normal--*-120-*-*-*-iso8859-1", PrefData.boldFontString, (void *)sizeof(PrefData.boldFontString), True}, {"italicHighlightFont", "ItalicHighlightFont", PREF_STRING, "-*-courier-medium-o-normal--*-120-*-*-*-iso8859-1", PrefData.italicFontString, (void *)sizeof(PrefData.italicFontString), True}, {"boldItalicHighlightFont", "BoldItalicHighlightFont", PREF_STRING, "-*-courier-bold-o-normal--*-120-*-*-*-iso8859-1", PrefData.boldItalicFontString, (void *)sizeof(PrefData.boldItalicFontString), True}, {"helpFont", "HelpFont", PREF_STRING, "-*-helvetica-medium-r-normal--*-120-*-*-*-iso8859-1", PrefData.helpFontNames[HELP_FONT], (void *)sizeof(PrefData.helpFontNames[HELP_FONT]), False}, {"boldHelpFont", "BoldHelpFont", PREF_STRING, "-*-helvetica-bold-r-normal--*-120-*-*-*-iso8859-1", PrefData.helpFontNames[BOLD_HELP_FONT], (void *)sizeof(PrefData.helpFontNames[BOLD_HELP_FONT]), False}, {"italicHelpFont", "ItalicHelpFont", PREF_STRING, "-*-helvetica-medium-o-normal--*-120-*-*-*-iso8859-1", PrefData.helpFontNames[ITALIC_HELP_FONT], (void *)sizeof(PrefData.helpFontNames[ITALIC_HELP_FONT]), False}, {"boldItalicHelpFont", "BoldItalicHelpFont", PREF_STRING, "-*-helvetica-bold-o-normal--*-120-*-*-*-iso8859-1", PrefData.helpFontNames[BOLD_ITALIC_HELP_FONT], (void *)sizeof(PrefData.helpFontNames[BOLD_ITALIC_HELP_FONT]), False}, {"fixedHelpFont", "FixedHelpFont", PREF_STRING, "-*-courier-medium-r-normal--*-120-*-*-*-iso8859-1", PrefData.helpFontNames[FIXED_HELP_FONT], (void *)sizeof(PrefData.helpFontNames[FIXED_HELP_FONT]), False}, {"boldFixedHelpFont", "BoldFixedHelpFont", PREF_STRING, "-*-courier-bold-r-normal--*-120-*-*-*-iso8859-1", PrefData.helpFontNames[BOLD_FIXED_HELP_FONT], (void *)sizeof(PrefData.helpFontNames[BOLD_FIXED_HELP_FONT]), False}, {"italicFixedHelpFont", "ItalicFixedHelpFont", PREF_STRING, "-*-courier-medium-o-normal--*-120-*-*-*-iso8859-1", PrefData.helpFontNames[ITALIC_FIXED_HELP_FONT], (void *)sizeof(PrefData.helpFontNames[ITALIC_FIXED_HELP_FONT]), False}, {"boldItalicFixedHelpFont", "BoldItalicFixedHelpFont", PREF_STRING, "-*-courier-bold-o-normal--*-120-*-*-*-iso8859-1", PrefData.helpFontNames[BOLD_ITALIC_FIXED_HELP_FONT], (void *)sizeof(PrefData.helpFontNames[BOLD_ITALIC_FIXED_HELP_FONT]), False}, {"helpLinkFont", "HelpLinkFont", PREF_STRING, "-*-helvetica-medium-r-normal--*-120-*-*-*-iso8859-1", PrefData.helpFontNames[HELP_LINK_FONT], (void *)sizeof(PrefData.helpFontNames[HELP_LINK_FONT]), False}, {"h1HelpFont", "H1HelpFont", PREF_STRING, "-*-helvetica-bold-r-normal--*-140-*-*-*-iso8859-1", PrefData.helpFontNames[H1_HELP_FONT], (void *)sizeof(PrefData.helpFontNames[H1_HELP_FONT]), False}, {"h2HelpFont", "H2HelpFont", PREF_STRING, "-*-helvetica-bold-o-normal--*-120-*-*-*-iso8859-1", PrefData.helpFontNames[H2_HELP_FONT], (void *)sizeof(PrefData.helpFontNames[H2_HELP_FONT]), False}, {"h3HelpFont", "H3HelpFont", PREF_STRING, "-*-courier-bold-r-normal--*-120-*-*-*-iso8859-1", PrefData.helpFontNames[H3_HELP_FONT], (void *)sizeof(PrefData.helpFontNames[H3_HELP_FONT]), False}, {"helpLinkColor", "HelpLinkColor", PREF_STRING, "#009900", PrefData.helpLinkColor, (void *)sizeof(PrefData.helpLinkColor), False}, {"textFgColor", "TextFgColor", PREF_STRING, NEDIT_DEFAULT_FG, PrefData.colorNames[TEXT_FG_COLOR], (void *)sizeof(PrefData.colorNames[TEXT_FG_COLOR]), True}, {"textBgColor", "TextBgColor", PREF_STRING, NEDIT_DEFAULT_TEXT_BG, PrefData.colorNames[TEXT_BG_COLOR], (void *)sizeof(PrefData.colorNames[TEXT_BG_COLOR]), True}, {"selectFgColor", "SelectFgColor", PREF_STRING, NEDIT_DEFAULT_SEL_FG, PrefData.colorNames[SELECT_FG_COLOR], (void *)sizeof(PrefData.colorNames[SELECT_FG_COLOR]), True}, {"selectBgColor", "SelectBgColor", PREF_STRING, NEDIT_DEFAULT_SEL_BG, PrefData.colorNames[SELECT_BG_COLOR], (void *)sizeof(PrefData.colorNames[SELECT_BG_COLOR]), True}, {"hiliteFgColor", "HiliteFgColor", PREF_STRING, NEDIT_DEFAULT_HI_FG, PrefData.colorNames[HILITE_FG_COLOR], (void *)sizeof(PrefData.colorNames[HILITE_FG_COLOR]), True}, {"hiliteBgColor", "HiliteBgColor", PREF_STRING, NEDIT_DEFAULT_HI_BG, PrefData.colorNames[HILITE_BG_COLOR], (void *)sizeof(PrefData.colorNames[HILITE_BG_COLOR]), True}, {"lineNoFgColor", "LineNoFgColor", PREF_STRING, NEDIT_DEFAULT_LINENO_FG, PrefData.colorNames[LINENO_FG_COLOR], (void *)sizeof(PrefData.colorNames[LINENO_FG_COLOR]), True}, {"cursorFgColor", "CursorFgColor", PREF_STRING, NEDIT_DEFAULT_CURSOR_FG, PrefData.colorNames[CURSOR_FG_COLOR], (void *)sizeof(PrefData.colorNames[CURSOR_FG_COLOR]), True}, {"tooltipBgColor", "TooltipBgColor", PREF_STRING, "LemonChiffon1", PrefData.tooltipBgColor, (void *)sizeof(PrefData.tooltipBgColor), False}, {"shell", "Shell", PREF_STRING, "DEFAULT", PrefData.shell, (void*) sizeof(PrefData.shell), True}, {"geometry", "Geometry", PREF_STRING, "", PrefData.geometry, (void *)sizeof(PrefData.geometry), False}, {"remapDeleteKey", "RemapDeleteKey", PREF_BOOLEAN, "False", &PrefData.mapDelete, NULL, False}, {"stdOpenDialog", "StdOpenDialog", PREF_BOOLEAN, "False", &PrefData.stdOpenDialog, NULL, False}, {"tagFile", "TagFile", PREF_STRING, "", PrefData.tagFile, (void *)sizeof(PrefData.tagFile), False}, {"wordDelimiters", "WordDelimiters", PREF_STRING, ".,/\\`'!|@#%^&*()-=+{}[]\":;<>?", PrefData.delimiters, (void *)sizeof(PrefData.delimiters), False}, {"serverName", "ServerName", PREF_STRING, "", PrefData.serverName, (void *)sizeof(PrefData.serverName), False}, {"maxPrevOpenFiles", "MaxPrevOpenFiles", PREF_INT, "30", &PrefData.maxPrevOpenFiles, NULL, False}, {"bgMenuButton", "BGMenuButton" , PREF_STRING, "~Shift~Ctrl~Meta~Alt", PrefData.bgMenuBtn, (void *)sizeof(PrefData.bgMenuBtn), False}, {"smartTags", "SmartTags", PREF_BOOLEAN, "True", &PrefData.smartTags, NULL, True}, {"typingHidesPointer", "TypingHidesPointer", PREF_BOOLEAN, "False", &PrefData.typingHidesPointer, NULL, False}, {"alwaysCheckRelativeTagsSpecs", "AlwaysCheckRelativeTagsSpecs", PREF_BOOLEAN, "True", &PrefData.alwaysCheckRelativeTagsSpecs, NULL, False}, {"prefFileRead", "PrefFileRead", PREF_BOOLEAN, "False", &PrefData.prefFileRead, NULL, True}, #ifdef SGI_CUSTOM {"shortMenus", "ShortMenus", PREF_BOOLEAN, "False", &PrefData.shortMenus, NULL, True}, #endif {"findReplaceUsesSelection", "FindReplaceUsesSelection", PREF_BOOLEAN, "False", &PrefData.findReplaceUsesSelection, NULL, False}, {"overrideDefaultVirtualKeyBindings", "OverrideDefaultVirtualKeyBindings", PREF_ENUM, "Auto", &PrefData.virtKeyOverride, VirtKeyOverrideModes, False}, {"titleFormat", "TitleFormat", PREF_STRING, "{%c} [%s] %f (%S) - %d", PrefData.titleFormat, (void *)sizeof(PrefData.titleFormat), True}, {"undoModifiesSelection", "UndoModifiesSelection", PREF_BOOLEAN, "True", &PrefData.undoModifiesSelection, NULL, False}, {"focusOnRaise", "FocusOnRaise", PREF_BOOLEAN, "False", &PrefData.focusOnRaise, NULL, False}, {"forceOSConversion", "ForceOSConversion", PREF_BOOLEAN, "True", &PrefData.forceOSConversion, NULL, False}, {"truncSubstitution", "TruncSubstitution", PREF_ENUM, "Fail", &PrefData.truncSubstitution, TruncSubstitutionModes, False}, {"honorSymlinks", "HonorSymlinks", PREF_BOOLEAN, "True", &PrefData.honorSymlinks, NULL, False} }; static XrmOptionDescRec OpTable[] = { {"-wrap", ".autoWrap", XrmoptionNoArg, (caddr_t)"Continuous"}, {"-nowrap", ".autoWrap", XrmoptionNoArg, (caddr_t)"None"}, {"-autowrap", ".autoWrap", XrmoptionNoArg, (caddr_t)"Newline"}, {"-noautowrap", ".autoWrap", XrmoptionNoArg, (caddr_t)"None"}, {"-autoindent", ".autoIndent", XrmoptionNoArg, (caddr_t)"Auto"}, {"-noautoindent", ".autoIndent", XrmoptionNoArg, (caddr_t)"False"}, {"-autosave", ".autoSave", XrmoptionNoArg, (caddr_t)"True"}, {"-noautosave", ".autoSave", XrmoptionNoArg, (caddr_t)"False"}, {"-rows", ".textRows", XrmoptionSepArg, (caddr_t)NULL}, {"-columns", ".textCols", XrmoptionSepArg, (caddr_t)NULL}, {"-tabs", ".tabDistance", XrmoptionSepArg, (caddr_t)NULL}, {"-font", ".textFont", XrmoptionSepArg, (caddr_t)NULL}, {"-fn", ".textFont", XrmoptionSepArg, (caddr_t)NULL}, {"-svrname", ".serverName", XrmoptionSepArg, (caddr_t)NULL}, }; static const char HeaderText[] = "\ ! Preferences file for NEdit\n\ ! (User settings in X \"application defaults\" format)\n\ !\n\ ! This file is overwritten by the \"Save Defaults...\" command in NEdit\n\ ! and serves only the interactively settable options presented in the NEdit\n\ ! \"Preferences\" menu. To modify other options, such as key bindings, use\n\ ! the .Xdefaults file in your home directory (or the X resource\n\ ! specification method appropriate to your system). The contents of this\n\ ! file can be moved into an X resource file, but since resources in this file\n\ ! override their corresponding X resources, either this file should be \n\ ! deleted or individual resource lines in the file should be deleted for the\n\ ! moved lines to take effect.\n"; /* Module-global variable set when any preference changes (for asking the user about re-saving on exit) */ static int PrefsHaveChanged = False; /* Module-global variable set when user uses -import to load additional preferences on top of the defaults. Contains name of file loaded */ static char *ImportedFile = NULL; /* Module-global variables to support Initial Window Size... dialog */ static int DoneWithSizeDialog; static Widget RowText, ColText; /* Module-global variables for Tabs dialog */ static int DoneWithTabsDialog; static WindowInfo *TabsDialogForWindow; static Widget TabDistText, EmTabText, EmTabToggle, UseTabsToggle, EmTabLabel; /* Module-global variables for Wrap Margin dialog */ static int DoneWithWrapDialog; static WindowInfo *WrapDialogForWindow; static Widget WrapText, WrapTextLabel, WrapWindowToggle; /* Module-global variables for shell selection dialog */ static int DoneWithShellSelDialog = False; static void translatePrefFormats(int convertOld, int fileVer); static void setIntPref(int *prefDataField, int newValue); static void setStringPref(char *prefDataField, const char *newValue); static void sizeOKCB(Widget w, XtPointer clientData, XtPointer callData); static void setStringAllocPref(char **pprefDataField, char *newValue); static void sizeCancelCB(Widget w, XtPointer clientData, XtPointer callData); static void tabsOKCB(Widget w, XtPointer clientData, XtPointer callData); static void tabsCancelCB(Widget w, XtPointer clientData, XtPointer callData); static void tabsHelpCB(Widget w, XtPointer clientData, XtPointer callData); static void emTabsCB(Widget w, XtPointer clientData, XtPointer callData); static void wrapOKCB(Widget w, XtPointer clientData, XtPointer callData); static void wrapCancelCB(Widget w, XtPointer clientData, XtPointer callData); static void wrapWindowCB(Widget w, XtPointer clientData, XtPointer callData); static void shellSelOKCB(Widget widget, XtPointer clientData, XtPointer callData); static void shellSelCancelCB(Widget widgget, XtPointer clientData, XtPointer callData); static void reapplyLanguageMode(WindowInfo *window, int mode,int forceDefaults); static void fillFromPrimaryCB(Widget w, XtPointer clientData, XtPointer callData); static int checkFontStatus(fontDialog *fd, Widget fontTextFieldW); static int showFontStatus(fontDialog *fd, Widget fontTextFieldW, Widget errorLabelW); static void primaryModifiedCB(Widget w, XtPointer clientData, XtPointer callData); static void italicModifiedCB(Widget w, XtPointer clientData, XtPointer callData); static void boldModifiedCB(Widget w, XtPointer clientData, XtPointer callData); static void boldItalicModifiedCB(Widget w, XtPointer clientData, XtPointer callData); static void primaryBrowseCB(Widget w, XtPointer clientData, XtPointer callData); static void italicBrowseCB(Widget w, XtPointer clientData, XtPointer callData); static void boldBrowseCB(Widget w, XtPointer clientData, XtPointer callData); static void boldItalicBrowseCB(Widget w, XtPointer clientData, XtPointer callData); static void browseFont(Widget parent, Widget fontTextW); static void fontDestroyCB(Widget w, XtPointer clientData, XtPointer callData); static void fontOkCB(Widget w, XtPointer clientData, XtPointer callData); static void fontApplyCB(Widget w, XtPointer clientData, XtPointer callData); static void fontCancelCB(Widget w, XtPointer clientData, XtPointer callData); static void updateFonts(fontDialog *fd); static Boolean checkColorStatus(colorDialog *cd, Widget colorFieldW); static int verifyAllColors (colorDialog *cd); static void showColorStatus (colorDialog *cd, Widget colorFieldW, Widget errorLabelW); static void updateColors(colorDialog *cd); static void colorDestroyCB(Widget w, XtPointer clientData, XtPointer callData); static void colorOkCB (Widget w, XtPointer clientData, XtPointer callData); static void colorApplyCB (Widget w, XtPointer clientData, XtPointer callData); static void colorCloseCB(Widget w, XtPointer clientData, XtPointer callData); static void textFgModifiedCB (Widget w, XtPointer clientData, XtPointer callData); static void textBgModifiedCB (Widget w, XtPointer clientData, XtPointer callData); static void selectFgModifiedCB(Widget w, XtPointer clientData, XtPointer callData); static void selectBgModifiedCB(Widget w, XtPointer clientData, XtPointer callData); static void hiliteFgModifiedCB(Widget w, XtPointer clientData, XtPointer callData); static void hiliteBgModifiedCB(Widget w, XtPointer clientData, XtPointer callData); static void lineNoFgModifiedCB(Widget w, XtPointer clientData, XtPointer callData); static void cursorFgModifiedCB(Widget w, XtPointer clientData, XtPointer callData); static int matchLanguageMode(WindowInfo *window); static int loadLanguageModesString(char *inString, int fileVer); static char *writeLanguageModesString(void); static char *createExtString(char **extensions, int nExtensions); static char **readExtensionList(char **inPtr, int *nExtensions); static void updateLanguageModeSubmenu(WindowInfo *window); static void setLangModeCB(Widget w, XtPointer clientData, XtPointer callData); static int modeError(languageModeRec *lm, const char *stringStart, const char *stoppedAt, const char *message); static void lmDestroyCB(Widget w, XtPointer clientData, XtPointer callData); static void lmOkCB(Widget w, XtPointer clientData, XtPointer callData); static void lmApplyCB(Widget w, XtPointer clientData, XtPointer callData); static void lmCloseCB(Widget w, XtPointer clientData, XtPointer callData); static int lmDeleteConfirmCB(int itemIndex, void *cbArg); static int updateLMList(void); static languageModeRec *copyLanguageModeRec(languageModeRec *lm); static void *lmGetDisplayedCB(void *oldItem, int explicitRequest, int *abort, void *cbArg); static void lmSetDisplayedCB(void *item, void *cbArg); static languageModeRec *readLMDialogFields(int silent); static void lmFreeItemCB(void *item); static void freeLanguageModeRec(languageModeRec *lm); static int lmDialogEmpty(void); static void updatePatternsTo5dot1(void); static void updatePatternsTo5dot2(void); static void updatePatternsTo5dot3(void); static void updatePatternsTo5dot4(void); static void updateShellCmdsTo5dot3(void); static void updateShellCmdsTo5dot4(void); static void updateMacroCmdsTo5dot5(void); static void updatePatternsTo5dot6(void); static void updateMacroCmdsTo5dot6(void); static void migrateColorResources(XrmDatabase prefDB, XrmDatabase appDB); static void spliceString(char **intoString, const char *insertString, const char *atExpr); static int regexFind(const char *inString, const char *expr); static int regexReplace(char **inString, const char *expr, const char *replaceWith); static int caseFind(const char *inString, const char *expr); static int caseReplace(char **inString, const char *expr, const char *replaceWith, int replaceLen); static int stringReplace(char **inString, const char *expr, const char *replaceWith, int searchType, int replaceLen); static int replaceMacroIfUnchanged(const char* oldText, const char* newStart, const char* newEnd); static const char* getDefaultShell(void); #ifdef SGI_CUSTOM static int shortPrefToDefault(Widget parent, const char *settingName, int *setDefault); #endif XrmDatabase CreateNEditPrefDB(int *argcInOut, char **argvInOut) { return CreatePreferencesDatabase(GetRCFileName(NEDIT_RC), APP_NAME, OpTable, XtNumber(OpTable), (unsigned int *)argcInOut, argvInOut); } void RestoreNEditPrefs(XrmDatabase prefDB, XrmDatabase appDB) { int requiresConversion; int major; /* The integral part of version number */ int minor; /* fractional part of version number */ int fileVer = 0; /* Both combined into an integer */ int nparsed; /* Load preferences */ RestorePreferences(prefDB, appDB, APP_NAME, APP_CLASS, PrefDescrip, XtNumber(PrefDescrip)); /* If the preferences file was written by an older version of NEdit, warn the user that it will be converted. */ requiresConversion = PrefData.prefFileRead && PrefData.fileVersion[0] == '\0'; if (requiresConversion) { updatePatternsTo5dot1(); } if (PrefData.prefFileRead) { if (PrefData.fileVersion[0] == '\0') { fileVer = 0; /* Pre-5.1 */ } else { /* Note: do not change the format of this. Older executables need to read this field for forward compatability. */ nparsed = sscanf(PrefData.fileVersion, "%d.%d", &major, &minor); if (nparsed >= 2) { /* Use OSF-style numbering scheme */ fileVer = major * 1000 + minor; } } } if (PrefData.prefFileRead && fileVer < 5002) { updatePatternsTo5dot2(); } if (PrefData.prefFileRead && fileVer < 5003) { updateShellCmdsTo5dot3(); updatePatternsTo5dot3(); } /* Note that we don't care about unreleased file versions. Anyone who is running a CVS or alpha version of NEdit is resposnbile for managing the preferences file themselves. Otherwise, it gets impossible to track the number of "in-between" file formats. We only do auto-upgrading for a real release. */ if (PrefData.prefFileRead && (fileVer < 5004)) { migrateColorResources(prefDB, appDB); updateShellCmdsTo5dot4(); updatePatternsTo5dot4(); } if (PrefData.prefFileRead && (fileVer < 5005)) { updateMacroCmdsTo5dot5(); } if (PrefData.prefFileRead && (fileVer < 5006)) { fprintf(stderr, "NEdit: Converting .nedit file to 5.6 version.\n" " To keep, use Preferences -> Save Defaults\n"); updateMacroCmdsTo5dot6(); updatePatternsTo5dot6(); } /* Migrate colors if there's no config file yet */ if (!PrefData.prefFileRead) { migrateColorResources(prefDB, appDB); } /* Do further parsing on resource types which RestorePreferences does not understand and reads as strings, to put them in the final form in which nedit stores and uses. If the preferences file was written by an older version of NEdit, update regular expressions in highlight patterns to quote braces and use & instead of \0 */ translatePrefFormats(requiresConversion, fileVer); } /* ** Many of of NEdit's preferences are much more complicated than just simple ** integers or strings. These are read as strings, but must be parsed and ** translated into something meaningful. This routine does the translation, ** and, in most cases, frees the original string, which is no longer useful. ** ** In addition this function covers settings that, while simple, require ** additional steps before they can be published. ** ** The argument convertOld attempts a conversion from pre 5.1 format .nedit ** files (which means patterns and macros may contain regular expressions ** which are of the older syntax where braces were not quoted, and \0 was a ** legal substitution character). Macros, so far can not be automatically ** converted, unfortunately. */ static void translatePrefFormats(int convertOld, int fileVer) { XFontStruct *font; /* Parse the strings which represent types which are not decoded by the standard resource manager routines */ #ifndef VMS if (TempStringPrefs.shellCmds != NULL) { LoadShellCmdsString(TempStringPrefs.shellCmds); XtFree(TempStringPrefs.shellCmds); TempStringPrefs.shellCmds = NULL; } #endif /* VMS */ if (TempStringPrefs.macroCmds != NULL) { LoadMacroCmdsString(TempStringPrefs.macroCmds); XtFree(TempStringPrefs.macroCmds); TempStringPrefs.macroCmds = NULL; } if (TempStringPrefs.bgMenuCmds != NULL) { LoadBGMenuCmdsString(TempStringPrefs.bgMenuCmds); XtFree(TempStringPrefs.bgMenuCmds); TempStringPrefs.bgMenuCmds = NULL; } if (TempStringPrefs.highlight != NULL) { LoadHighlightString(TempStringPrefs.highlight, convertOld); XtFree(TempStringPrefs.highlight); TempStringPrefs.highlight = NULL; } if (TempStringPrefs.styles != NULL) { LoadStylesString(TempStringPrefs.styles); XtFree(TempStringPrefs.styles); TempStringPrefs.styles = NULL; } if (TempStringPrefs.language != NULL) { loadLanguageModesString(TempStringPrefs.language, fileVer); XtFree(TempStringPrefs.language); TempStringPrefs.language = NULL; } if (TempStringPrefs.smartIndent != NULL) { LoadSmartIndentString(TempStringPrefs.smartIndent); XtFree(TempStringPrefs.smartIndent); TempStringPrefs.smartIndent = NULL; } if (TempStringPrefs.smartIndentCommon != NULL) { LoadSmartIndentCommonString(TempStringPrefs.smartIndentCommon); XtFree(TempStringPrefs.smartIndentCommon); TempStringPrefs.smartIndentCommon = NULL; } /* translate the font names into fontLists suitable for the text widget */ font = XLoadQueryFont(TheDisplay, PrefData.fontString); PrefData.fontList = font==NULL ? NULL : XmFontListCreate(font, XmSTRING_DEFAULT_CHARSET); PrefData.boldFontStruct = XLoadQueryFont(TheDisplay, PrefData.boldFontString); PrefData.italicFontStruct = XLoadQueryFont(TheDisplay, PrefData.italicFontString); PrefData.boldItalicFontStruct = XLoadQueryFont(TheDisplay, PrefData.boldItalicFontString); /* ** The default set for the comand shell in PrefDescrip ("DEFAULT") is ** only a place-holder, the actual default is the user's login shell ** (or whatever is implemented in getDefaultShell()). We put the login ** shell's name in PrefData here. */ if (0 == strcmp(PrefData.shell, "DEFAULT")) { strncpy(PrefData.shell, getDefaultShell(), MAXPATHLEN); PrefData.shell[MAXPATHLEN] = '\0'; } /* For compatability with older (4.0.3 and before) versions, the autoWrap and autoIndent resources can accept values of True and False. Translate them into acceptable wrap and indent styles */ if (PrefData.wrapStyle == 3) PrefData.wrapStyle = CONTINUOUS_WRAP; if (PrefData.wrapStyle == 4) PrefData.wrapStyle = NO_WRAP; if (PrefData.autoIndent == 3) PrefData.autoIndent = AUTO_INDENT; if (PrefData.autoIndent == 4) PrefData.autoIndent = NO_AUTO_INDENT; /* setup language mode dependent info of user menus (to increase performance when switching between documents of different language modes) */ SetupUserMenuInfo(); } void SaveNEditPrefs(Widget parent, int quietly) { const char* prefFileName = GetRCFileName(NEDIT_RC); if (prefFileName == NULL) { /* GetRCFileName() might return NULL if an error occurs during creation of the preference file directory. */ DialogF(DF_WARN, parent, 1, "Error saving Preferences", "Unable to save preferences: Cannot determine filename.", "OK"); return; } if (!quietly) { if (DialogF(DF_INF, parent, 2, "Save Preferences", ImportedFile == NULL ? "Default preferences will be saved in the file:\n" "%s\n" "NEdit automatically loads this file\n" "each time it is started." : "Default preferences will be saved in the file:\n" "%s\n" "SAVING WILL INCORPORATE SETTINGS\n" "FROM FILE: %s", "OK", "Cancel", prefFileName, ImportedFile) == 2) { return; } } /* Write the more dynamic settings into TempStringPrefs. These locations are set in PrefDescrip, so this is where SavePreferences() will look for them. */ #ifndef VMS TempStringPrefs.shellCmds = WriteShellCmdsString(); #endif /* VMS */ TempStringPrefs.macroCmds = WriteMacroCmdsString(); TempStringPrefs.bgMenuCmds = WriteBGMenuCmdsString(); TempStringPrefs.highlight = WriteHighlightString(); TempStringPrefs.language = writeLanguageModesString(); TempStringPrefs.styles = WriteStylesString(); TempStringPrefs.smartIndent = WriteSmartIndentString(); TempStringPrefs.smartIndentCommon = WriteSmartIndentCommonString(); strcpy(PrefData.fileVersion, PREF_FILE_VERSION); if (!SavePreferences(XtDisplay(parent), prefFileName, HeaderText, PrefDescrip, XtNumber(PrefDescrip))) { DialogF(DF_WARN, parent, 1, "Save Preferences", "Unable to save preferences in %s", "OK", prefFileName); } #ifndef VMS XtFree(TempStringPrefs.shellCmds); #endif /* VMS */ XtFree(TempStringPrefs.macroCmds); XtFree(TempStringPrefs.bgMenuCmds); XtFree(TempStringPrefs.highlight); XtFree(TempStringPrefs.language); XtFree(TempStringPrefs.styles); XtFree(TempStringPrefs.smartIndent); XtFree(TempStringPrefs.smartIndentCommon); PrefsHaveChanged = False; } /* ** Load an additional preferences file on top of the existing preferences ** derived from defaults, the .nedit file, and X resources. */ void ImportPrefFile(const char *filename, int convertOld) { XrmDatabase db; char *fileString; fileString = ReadAnyTextFile(filename, False); if (fileString != NULL){ db = XrmGetStringDatabase(fileString); XtFree(fileString); OverlayPreferences(db, APP_NAME, APP_CLASS, PrefDescrip, XtNumber(PrefDescrip)); translatePrefFormats(convertOld, -1); ImportedFile = XtNewString(filename); } else { fprintf(stderr, "Could not read additional preferences file: "); fprintf(stderr, filename); fprintf(stderr, "\n"); } } void SetPrefOpenInTab(int state) { WindowInfo *w = WindowList; setIntPref(&PrefData.openInTab, state); for(; w != NULL; w = w->next) UpdateNewOppositeMenu(w, state); } int GetPrefOpenInTab(void) { return PrefData.openInTab; } void SetPrefWrap(int state) { setIntPref(&PrefData.wrapStyle, state); } int GetPrefWrap(int langMode) { if (langMode == PLAIN_LANGUAGE_MODE || LanguageModes[langMode]->wrapStyle == DEFAULT_WRAP) return PrefData.wrapStyle; return LanguageModes[langMode]->wrapStyle; } void SetPrefWrapMargin(int margin) { setIntPref(&PrefData.wrapMargin, margin); } int GetPrefWrapMargin(void) { return PrefData.wrapMargin; } void SetPrefSearch(int searchType) { setIntPref(&PrefData.searchMethod, searchType); } int GetPrefSearch(void) { return PrefData.searchMethod; } #ifdef REPLACE_SCOPE void SetPrefReplaceDefScope(int scope) { setIntPref(&PrefData.replaceDefScope, scope); } int GetPrefReplaceDefScope(void) { return PrefData.replaceDefScope; } #endif void SetPrefAutoIndent(int state) { setIntPref(&PrefData.autoIndent, state); } int GetPrefAutoIndent(int langMode) { if (langMode == PLAIN_LANGUAGE_MODE || LanguageModes[langMode]->indentStyle == DEFAULT_INDENT) return PrefData.autoIndent; return LanguageModes[langMode]->indentStyle; } void SetPrefAutoSave(int state) { setIntPref(&PrefData.autoSave, state); } int GetPrefAutoSave(void) { return PrefData.autoSave; } void SetPrefSaveOldVersion(int state) { setIntPref(&PrefData.saveOldVersion, state); } int GetPrefSaveOldVersion(void) { return PrefData.saveOldVersion; } void SetPrefSearchDlogs(int state) { setIntPref(&PrefData.searchDlogs, state); } int GetPrefSearchDlogs(void) { return PrefData.searchDlogs; } void SetPrefBeepOnSearchWrap(int state) { setIntPref(&PrefData.searchWrapBeep, state); } int GetPrefBeepOnSearchWrap(void) { return PrefData.searchWrapBeep; } void SetPrefKeepSearchDlogs(int state) { setIntPref(&PrefData.keepSearchDlogs, state); } int GetPrefKeepSearchDlogs(void) { return PrefData.keepSearchDlogs; } void SetPrefSearchWraps(int state) { setIntPref(&PrefData.searchWraps, state); } int GetPrefStickyCaseSenseBtn(void) { return PrefData.stickyCaseSenseBtn; } int GetPrefSearchWraps(void) { return PrefData.searchWraps; } void SetPrefStatsLine(int state) { setIntPref(&PrefData.statsLine, state); } int GetPrefStatsLine(void) { return PrefData.statsLine; } void SetPrefISearchLine(int state) { setIntPref(&PrefData.iSearchLine, state); } int GetPrefISearchLine(void) { return PrefData.iSearchLine; } void SetPrefSortTabs(int state) { setIntPref(&PrefData.sortTabs, state); } int GetPrefSortTabs(void) { return PrefData.sortTabs; } void SetPrefTabBar(int state) { setIntPref(&PrefData.tabBar, state); } int GetPrefTabBar(void) { return PrefData.tabBar; } void SetPrefTabBarHideOne(int state) { setIntPref(&PrefData.tabBarHideOne, state); } int GetPrefTabBarHideOne(void) { return PrefData.tabBarHideOne; } void SetPrefGlobalTabNavigate(int state) { setIntPref(&PrefData.globalTabNavigate, state); } int GetPrefGlobalTabNavigate(void) { return PrefData.globalTabNavigate; } void SetPrefToolTips(int state) { setIntPref(&PrefData.toolTips, state); } int GetPrefToolTips(void) { return PrefData.toolTips; } void SetPrefLineNums(int state) { setIntPref(&PrefData.lineNums, state); } int GetPrefLineNums(void) { return PrefData.lineNums; } void SetPrefShowPathInWindowsMenu(int state) { setIntPref(&PrefData.pathInWindowsMenu, state); } int GetPrefShowPathInWindowsMenu(void) { return PrefData.pathInWindowsMenu; } void SetPrefWarnFileMods(int state) { setIntPref(&PrefData.warnFileMods, state); } int GetPrefWarnFileMods(void) { return PrefData.warnFileMods; } void SetPrefWarnRealFileMods(int state) { setIntPref(&PrefData.warnRealFileMods, state); } int GetPrefWarnRealFileMods(void) { return PrefData.warnRealFileMods; } void SetPrefWarnExit(int state) { setIntPref(&PrefData.warnExit, state); } int GetPrefWarnExit(void) { return PrefData.warnExit; } void SetPrefv(int state) { setIntPref(&PrefData.findReplaceUsesSelection, state); } int GetPrefFindReplaceUsesSelection(void) { return PrefData.findReplaceUsesSelection; } int GetPrefMapDelete(void) { return PrefData.mapDelete; } int GetPrefStdOpenDialog(void) { return PrefData.stdOpenDialog; } void SetPrefRows(int nRows) { setIntPref(&PrefData.textRows, nRows); } int GetPrefRows(void) { return PrefData.textRows; } void SetPrefCols(int nCols) { setIntPref(&PrefData.textCols, nCols); } int GetPrefCols(void) { return PrefData.textCols; } void SetPrefTabDist(int tabDist) { setIntPref(&PrefData.tabDist, tabDist); } int GetPrefTabDist(int langMode) { int tabDist; if (langMode == PLAIN_LANGUAGE_MODE || LanguageModes[langMode]->tabDist == DEFAULT_TAB_DIST) { tabDist = PrefData.tabDist; } else { tabDist = LanguageModes[langMode]->tabDist; } /* Make sure that the tab distance is in range (garbage may have been entered via the command line or the X resources, causing errors later on, like division by zero). */ if (tabDist <= 0) return 1; if (tabDist > MAX_EXP_CHAR_LEN) return MAX_EXP_CHAR_LEN; return tabDist; } void SetPrefEmTabDist(int tabDist) { setIntPref(&PrefData.emTabDist, tabDist); } int GetPrefEmTabDist(int langMode) { if (langMode == PLAIN_LANGUAGE_MODE || LanguageModes[langMode]->emTabDist == DEFAULT_EM_TAB_DIST) return PrefData.emTabDist; return LanguageModes[langMode]->emTabDist; } void SetPrefInsertTabs(int state) { setIntPref(&PrefData.insertTabs, state); } int GetPrefInsertTabs(void) { return PrefData.insertTabs; } void SetPrefShowMatching(int state) { setIntPref(&PrefData.showMatchingStyle, state); } int GetPrefShowMatching(void) { /* * For backwards compatibility with pre-5.2 versions, the boolean * False/True matching behavior is converted to NO_FLASH/FLASH_DELIMIT. */ if (PrefData.showMatchingStyle >= N_SHOW_MATCHING_STYLES) PrefData.showMatchingStyle -= N_SHOW_MATCHING_STYLES; return PrefData.showMatchingStyle; } void SetPrefMatchSyntaxBased(int state) { setIntPref(&PrefData.matchSyntaxBased, state); } int GetPrefMatchSyntaxBased(void) { return PrefData.matchSyntaxBased; } void SetPrefHighlightSyntax(Boolean state) { setIntPref(&PrefData.highlightSyntax, state); } Boolean GetPrefHighlightSyntax(void) { return PrefData.highlightSyntax; } void SetPrefBacklightChars(int state) { setIntPref(&PrefData.backlightChars, state); } int GetPrefBacklightChars(void) { return PrefData.backlightChars; } void SetPrefBacklightCharTypes(char *types) { setStringAllocPref(&PrefData.backlightCharTypes, types); } char *GetPrefBacklightCharTypes(void) { return PrefData.backlightCharTypes; } void SetPrefRepositionDialogs(int state) { setIntPref(&PrefData.repositionDialogs, state); } int GetPrefRepositionDialogs(void) { return PrefData.repositionDialogs; } void SetPrefAutoScroll(int state) { WindowInfo *w = WindowList; int margin = state ? PrefData.autoScrollVPadding : 0; setIntPref(&PrefData.autoScroll, state); for(w = WindowList; w != NULL; w = w->next) SetAutoScroll(w, margin); } int GetPrefAutoScroll(void) { return PrefData.autoScroll; } int GetVerticalAutoScroll(void) { return PrefData.autoScroll ? PrefData.autoScrollVPadding : 0; } void SetPrefAppendLF(int state) { setIntPref(&PrefData.appendLF, state); } int GetPrefAppendLF(void) { return PrefData.appendLF; } void SetPrefSortOpenPrevMenu(int state) { setIntPref(&PrefData.sortOpenPrevMenu, state); } int GetPrefSortOpenPrevMenu(void) { return PrefData.sortOpenPrevMenu; } char *GetPrefTagFile(void) { return PrefData.tagFile; } void SetPrefSmartTags(int state) { setIntPref(&PrefData.smartTags, state); } int GetPrefSmartTags(void) { return PrefData.smartTags; } int GetPrefAlwaysCheckRelTagsSpecs(void) { return PrefData.alwaysCheckRelativeTagsSpecs; } char *GetPrefDelimiters(void) { return PrefData.delimiters; } char *GetPrefColorName(int index) { return PrefData.colorNames[index]; } void SetPrefColorName(int index, const char *name) { setStringPref(PrefData.colorNames[index], name); } /* ** Set the font preferences using the font name (the fontList is generated ** in this call). Note that this leaks memory and server resources each ** time the default font is re-set. See note on SetFontByName in window.c ** for more information. */ void SetPrefFont(char *fontName) { XFontStruct *font; setStringPref(PrefData.fontString, fontName); font = XLoadQueryFont(TheDisplay, fontName); PrefData.fontList = font==NULL ? NULL : XmFontListCreate(font, XmSTRING_DEFAULT_CHARSET); } void SetPrefBoldFont(char *fontName) { setStringPref(PrefData.boldFontString, fontName); PrefData.boldFontStruct = XLoadQueryFont(TheDisplay, fontName); } void SetPrefItalicFont(char *fontName) { setStringPref(PrefData.italicFontString, fontName); PrefData.italicFontStruct = XLoadQueryFont(TheDisplay, fontName); } void SetPrefBoldItalicFont(char *fontName) { setStringPref(PrefData.boldItalicFontString, fontName); PrefData.boldItalicFontStruct = XLoadQueryFont(TheDisplay, fontName); } char *GetPrefFontName(void) { return PrefData.fontString; } char *GetPrefBoldFontName(void) { return PrefData.boldFontString; } char *GetPrefItalicFontName(void) { return PrefData.italicFontString; } char *GetPrefBoldItalicFontName(void) { return PrefData.boldItalicFontString; } XmFontList GetPrefFontList(void) { return PrefData.fontList; } XFontStruct *GetPrefBoldFont(void) { return PrefData.boldFontStruct; } XFontStruct *GetPrefItalicFont(void) { return PrefData.italicFontStruct; } XFontStruct *GetPrefBoldItalicFont(void) { return PrefData.boldItalicFontStruct; } char *GetPrefHelpFontName(int index) { return PrefData.helpFontNames[index]; } char *GetPrefHelpLinkColor(void) { return PrefData.helpLinkColor; } char *GetPrefTooltipBgColor(void) { return PrefData.tooltipBgColor; } void SetPrefShell(const char *shell) { setStringPref(PrefData.shell, shell); } const char* GetPrefShell(void) { return PrefData.shell; } char *GetPrefGeometry(void) { return PrefData.geometry; } char *GetPrefServerName(void) { return PrefData.serverName; } char *GetPrefBGMenuBtn(void) { return PrefData.bgMenuBtn; } int GetPrefMaxPrevOpenFiles(void) { return PrefData.maxPrevOpenFiles; } int GetPrefTypingHidesPointer(void) { return(PrefData.typingHidesPointer); } #ifdef SGI_CUSTOM void SetPrefShortMenus(int state) { setIntPref(&PrefData.shortMenus, state); } int GetPrefShortMenus(void) { return PrefData.shortMenus; } #endif void SetPrefTitleFormat(const char* format) { const WindowInfo* window; setStringPref(PrefData.titleFormat, format); /* update all windows */ for (window=WindowList; window!=NULL; window=window->next) { UpdateWindowTitle(window); } } const char* GetPrefTitleFormat(void) { return PrefData.titleFormat; } Boolean GetPrefUndoModifiesSelection(void) { return (Boolean)PrefData.undoModifiesSelection; } Boolean GetPrefFocusOnRaise(void) { return (Boolean)PrefData.focusOnRaise; } Boolean GetPrefForceOSConversion(void) { return (Boolean) PrefData.forceOSConversion; } Boolean GetPrefHonorSymlinks(void) { return PrefData.honorSymlinks; } int GetPrefOverrideVirtKeyBindings(void) { return PrefData.virtKeyOverride; } int GetPrefTruncSubstitution(void) { return PrefData.truncSubstitution; } /* ** If preferences don't get saved, ask the user on exit whether to save */ void MarkPrefsChanged(void) { PrefsHaveChanged = True; } /* ** Check if preferences have changed, and if so, ask the user if he wants ** to re-save. Returns False if user requests cancelation of Exit (or whatever ** operation triggered this call to be made). */ int CheckPrefsChangesSaved(Widget dialogParent) { int resp; if (!PrefsHaveChanged) return True; resp = DialogF(DF_WARN, dialogParent, 3, "Default Preferences", ImportedFile == NULL ? "Default Preferences have changed.\n" "Save changes to NEdit preference file?" : "Default Preferences have changed. SAVING \n" "CHANGES WILL INCORPORATE ADDITIONAL\nSETTINGS FROM FILE: %s", "Save", "Don't Save", "Cancel", ImportedFile); if (resp == 2) return True; if (resp == 3) return False; SaveNEditPrefs(dialogParent, True); return True; } /* ** set *prefDataField to newValue, but first check if they're different ** and update PrefsHaveChanged if a preference setting has now changed. */ static void setIntPref(int *prefDataField, int newValue) { if (newValue != *prefDataField) PrefsHaveChanged = True; *prefDataField = newValue; } static void setStringPref(char *prefDataField, const char *newValue) { if (strcmp(prefDataField, newValue)) PrefsHaveChanged = True; strcpy(prefDataField, newValue); } static void setStringAllocPref(char **pprefDataField, char *newValue) { char *p_newField; /* treat empty strings as nulls */ if (newValue && *newValue == '\0') newValue = NULL; if (*pprefDataField && **pprefDataField == '\0') *pprefDataField = NULL; /* assume statically alloc'ed "" */ /* check changes */ if (!*pprefDataField && !newValue) return; else if (!*pprefDataField && newValue) PrefsHaveChanged = True; else if (*pprefDataField && !newValue) PrefsHaveChanged = True; else if (strcmp(*pprefDataField, newValue)) PrefsHaveChanged = True; /* get rid of old preference */ XtFree(*pprefDataField); /* store new preference */ if (newValue) { p_newField = XtMalloc(strlen(newValue) + 1); strcpy(p_newField, newValue); } *pprefDataField = newValue; } /* ** Set the language mode for the window, update the menu and trigger language ** mode specific actions (turn on/off highlighting). If forceNewDefaults is ** true, re-establish default settings for language-specific preferences ** regardless of whether they were previously set by the user. */ void SetLanguageMode(WindowInfo *window, int mode, int forceNewDefaults) { Widget menu; WidgetList items; int n; Cardinal nItems; void *userData; /* Do mode-specific actions */ reapplyLanguageMode(window, mode, forceNewDefaults); /* Select the correct language mode in the sub-menu */ if (IsTopDocument(window)) { XtVaGetValues(window->langModeCascade, XmNsubMenuId, &menu, NULL); XtVaGetValues(menu, XmNchildren, &items, XmNnumChildren, &nItems, NULL); for (n=0; n<(int)nItems; n++) { XtVaGetValues(items[n], XmNuserData, &userData, NULL); XmToggleButtonSetState(items[n], (int)userData == mode, False); } } } /* ** Lookup a language mode by name, returning the index of the language ** mode or PLAIN_LANGUAGE_MODE if the name is not found */ int FindLanguageMode(const char *languageName) { int i; /* Compare each language mode to the one we were presented */ for (i=0; iname)) return i; return PLAIN_LANGUAGE_MODE; } /* ** Apply language mode matching criteria and set window->languageMode to ** the appropriate mode for the current file, trigger language mode ** specific actions (turn on/off highlighting), and update the language ** mode menu item. If forceNewDefaults is true, re-establish default ** settings for language-specific preferences regardless of whether ** they were previously set by the user. */ void DetermineLanguageMode(WindowInfo *window, int forceNewDefaults) { SetLanguageMode(window, matchLanguageMode(window), forceNewDefaults); } /* ** Return the name of the current language mode set in "window", or NULL ** if the current mode is "Plain". */ char *LanguageModeName(int mode) { if (mode == PLAIN_LANGUAGE_MODE) return NULL; else return LanguageModes[mode]->name; } /* ** Get the set of word delimiters for the language mode set in the current ** window. Returns NULL when no language mode is set (it would be easy to ** return the default delimiter set when the current language mode is "Plain", ** or the mode doesn't have its own delimiters, but this is usually used ** to supply delimiters for RE searching, and ExecRE can skip compiling a ** delimiter table when delimiters is NULL). */ char *GetWindowDelimiters(const WindowInfo *window) { if (window->languageMode == PLAIN_LANGUAGE_MODE) return NULL; else return LanguageModes[window->languageMode]->delimiters; } /* ** Put up a dialog for selecting a custom initial window size */ void RowColumnPrefDialog(Widget parent) { Widget form, selBox, topLabel; Arg selBoxArgs[2]; XmString s1; XtSetArg(selBoxArgs[0], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); XtSetArg(selBoxArgs[1], XmNautoUnmanage, False); selBox = CreatePromptDialog(parent, "customSize", selBoxArgs, 2); XtAddCallback(selBox, XmNokCallback, (XtCallbackProc)sizeOKCB, NULL); XtAddCallback(selBox, XmNcancelCallback, (XtCallbackProc)sizeCancelCB,NULL); XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_TEXT)); XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_SELECTION_LABEL)); XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_HELP_BUTTON)); XtVaSetValues(XtParent(selBox), XmNtitle, "Initial Window Size", NULL); form = XtVaCreateManagedWidget("form", xmFormWidgetClass, selBox, NULL); topLabel = XtVaCreateManagedWidget("topLabel", xmLabelGadgetClass, form, XmNlabelString, s1=MKSTRING( "Enter desired size in rows\nand columns of characters:"), NULL); XmStringFree(s1); RowText = XtVaCreateManagedWidget("rows", xmTextWidgetClass, form, XmNcolumns, 3, XmNtopAttachment, XmATTACH_WIDGET, XmNleftAttachment, XmATTACH_POSITION, XmNrightAttachment, XmATTACH_POSITION, XmNtopWidget, topLabel, XmNleftPosition, 5, XmNrightPosition, 45, NULL); RemapDeleteKey(RowText); XtVaCreateManagedWidget("xLabel", xmLabelGadgetClass, form, XmNlabelString, s1=MKSTRING("x"), XmNtopAttachment, XmATTACH_WIDGET, XmNleftAttachment, XmATTACH_POSITION, XmNrightAttachment, XmATTACH_POSITION, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNtopWidget, topLabel, XmNbottomWidget, RowText, XmNleftPosition, 45, XmNrightPosition, 55, NULL); XmStringFree(s1); ColText = XtVaCreateManagedWidget("cols", xmTextWidgetClass, form, XmNcolumns, 3, XmNtopAttachment, XmATTACH_WIDGET, XmNleftAttachment, XmATTACH_POSITION, XmNrightAttachment, XmATTACH_POSITION, XmNtopWidget, topLabel, XmNleftPosition, 55, XmNrightPosition, 95, NULL); RemapDeleteKey(ColText); /* put up dialog and wait for user to press ok or cancel */ DoneWithSizeDialog = False; ManageDialogCenteredOnPointer(selBox); while (!DoneWithSizeDialog) { XEvent event; XtAppNextEvent(XtWidgetToApplicationContext(parent), &event); ServerDispatchEvent(&event); } XtDestroyWidget(selBox); } static void sizeOKCB(Widget w, XtPointer clientData, XtPointer callData) { int rowValue, colValue, stat; /* get the values that the user entered and make sure they're ok */ stat = GetIntTextWarn(RowText, &rowValue, "number of rows", True); if (stat != TEXT_READ_OK) return; stat = GetIntTextWarn(ColText, &colValue, "number of columns", True); if (stat != TEXT_READ_OK) return; /* set the corresponding preferences and dismiss the dialog */ SetPrefRows(rowValue); SetPrefCols(colValue); DoneWithSizeDialog = True; } static void sizeCancelCB(Widget w, XtPointer clientData, XtPointer callData) { DoneWithSizeDialog = True; } /* ** Present the user a dialog for setting tab related preferences, either as ** defaults, or for a specific window (pass "forWindow" as NULL to set default ** preference, or a window to set preferences for the specific window. */ void TabsPrefDialog(Widget parent, WindowInfo *forWindow) { Widget form, selBox; Arg selBoxArgs[2]; XmString s1; int emulate, emTabDist, useTabs, tabDist; XtSetArg(selBoxArgs[0], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); XtSetArg(selBoxArgs[1], XmNautoUnmanage, False); selBox = CreatePromptDialog(parent, "customSize", selBoxArgs, 2); XtAddCallback(selBox, XmNokCallback, (XtCallbackProc)tabsOKCB, NULL); XtAddCallback(selBox, XmNcancelCallback, (XtCallbackProc)tabsCancelCB,NULL); XtAddCallback(selBox, XmNhelpCallback, (XtCallbackProc)tabsHelpCB,NULL); XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_TEXT)); XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_SELECTION_LABEL)); XtVaSetValues(XtParent(selBox), XmNtitle, "Tabs", NULL); form = XtVaCreateManagedWidget("form", xmFormWidgetClass, selBox, NULL); TabDistText = XtVaCreateManagedWidget("tabDistText", xmTextWidgetClass, form, XmNcolumns, 7, XmNtopAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); RemapDeleteKey(TabDistText); XtVaCreateManagedWidget("tabDistLabel", xmLabelGadgetClass, form, XmNlabelString, s1=XmStringCreateSimple( "Tab spacing (for hardware tab characters)"), XmNmnemonic, 'T', XmNuserData, TabDistText, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, TabDistText, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomWidget, TabDistText, NULL); XmStringFree(s1); EmTabText = XtVaCreateManagedWidget("emTabText", xmTextWidgetClass, form, XmNcolumns, 7, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, TabDistText, XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET, XmNrightWidget, TabDistText, NULL); RemapDeleteKey(EmTabText); EmTabLabel = XtVaCreateManagedWidget("emTabLabel", xmLabelGadgetClass, form, XmNlabelString, s1=XmStringCreateSimple("Emulated tab spacing"), XmNmnemonic, 's', XmNuserData, EmTabText, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, TabDistText, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, EmTabText, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomWidget, EmTabText, NULL); XmStringFree(s1); EmTabToggle = XtVaCreateManagedWidget("emTabToggle", xmToggleButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("Emulate tabs"), XmNmnemonic, 'E', XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, TabDistText, XmNleftAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomWidget, EmTabText, NULL); XmStringFree(s1); XtAddCallback(EmTabToggle, XmNvalueChangedCallback, emTabsCB, NULL); UseTabsToggle = XtVaCreateManagedWidget("useTabsToggle", xmToggleButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple( "Use tab characters in padding and emulated tabs"), XmNmnemonic, 'U', XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, EmTabText, XmNtopOffset, 5, XmNleftAttachment, XmATTACH_FORM, NULL); XmStringFree(s1); /* Set default values */ if (forWindow == NULL) { emTabDist = GetPrefEmTabDist(PLAIN_LANGUAGE_MODE); useTabs = GetPrefInsertTabs(); tabDist = GetPrefTabDist(PLAIN_LANGUAGE_MODE); } else { XtVaGetValues(forWindow->textArea, textNemulateTabs, &emTabDist, NULL); useTabs = forWindow->buffer->useTabs; tabDist = BufGetTabDistance(forWindow->buffer); } emulate = emTabDist != 0; SetIntText(TabDistText, tabDist); XmToggleButtonSetState(EmTabToggle, emulate, True); if (emulate) SetIntText(EmTabText, emTabDist); XmToggleButtonSetState(UseTabsToggle, useTabs, False); XtSetSensitive(EmTabText, emulate); XtSetSensitive(EmTabLabel, emulate); /* Handle mnemonic selection of buttons and focus to dialog */ AddDialogMnemonicHandler(form, FALSE); /* Set the widget to get focus */ #if XmVersion >= 1002 XtVaSetValues(form, XmNinitialFocus, TabDistText, NULL); #endif /* put up dialog and wait for user to press ok or cancel */ TabsDialogForWindow = forWindow; DoneWithTabsDialog = False; ManageDialogCenteredOnPointer(selBox); while (!DoneWithTabsDialog) { XEvent event; XtAppNextEvent(XtWidgetToApplicationContext(parent), &event); ServerDispatchEvent(&event); } XtDestroyWidget(selBox); } static void tabsOKCB(Widget w, XtPointer clientData, XtPointer callData) { int emulate, useTabs, stat, tabDist, emTabDist; WindowInfo *window = TabsDialogForWindow; /* get the values that the user entered and make sure they're ok */ emulate = XmToggleButtonGetState(EmTabToggle); useTabs = XmToggleButtonGetState(UseTabsToggle); stat = GetIntTextWarn(TabDistText, &tabDist, "tab spacing", True); if (stat != TEXT_READ_OK) return; if (tabDist <= 0 || tabDist > MAX_EXP_CHAR_LEN) { DialogF(DF_WARN, TabDistText, 1, "Tab Spacing", "Tab spacing out of range", "OK"); return; } if (emulate) { stat = GetIntTextWarn(EmTabText, &emTabDist, "emulated tab spacing",True); if (stat != TEXT_READ_OK) return; if (emTabDist <= 0 || tabDist >= 1000) { DialogF(DF_WARN, EmTabText, 1, "Tab Spacing", "Emulated tab spacing out of range", "OK"); return; } } else emTabDist = 0; #ifdef SGI_CUSTOM /* Ask the user about saving as a default preference */ if (TabsDialogForWindow != NULL) { int setDefault; if (!shortPrefToDefault(window->shell, "Tab Settings", &setDefault)) { DoneWithTabsDialog = True; return; } if (setDefault) { SetPrefTabDist(tabDist); SetPrefEmTabDist(emTabDist); SetPrefInsertTabs(useTabs); SaveNEditPrefs(window->shell, GetPrefShortMenus()); } } #endif /* Set the value in either the requested window or default preferences */ if (TabsDialogForWindow == NULL) { SetPrefTabDist(tabDist); SetPrefEmTabDist(emTabDist); SetPrefInsertTabs(useTabs); } else { char *params[1]; char numStr[25]; params[0] = numStr; sprintf(numStr, "%d", tabDist); XtCallActionProc(window->textArea, "set_tab_dist", NULL, params, 1); params[0] = numStr; sprintf(numStr, "%d", emTabDist); XtCallActionProc(window->textArea, "set_em_tab_dist", NULL, params, 1); params[0] = numStr; sprintf(numStr, "%d", useTabs); XtCallActionProc(window->textArea, "set_use_tabs", NULL, params, 1); /* setTabDist(window, tabDist); setEmTabDist(window, emTabDist); window->buffer->useTabs = useTabs; */ } DoneWithTabsDialog = True; } static void tabsCancelCB(Widget w, XtPointer clientData, XtPointer callData) { DoneWithTabsDialog = True; } static void tabsHelpCB(Widget w, XtPointer clientData, XtPointer callData) { Help(HELP_TABS_DIALOG); } static void emTabsCB(Widget w, XtPointer clientData, XtPointer callData) { int state = XmToggleButtonGetState(w); XtSetSensitive(EmTabLabel, state); XtSetSensitive(EmTabText, state); } /* ** Present the user a dialog for setting wrap margin. */ void WrapMarginDialog(Widget parent, WindowInfo *forWindow) { Widget form, selBox; Arg selBoxArgs[2]; XmString s1; int margin; XtSetArg(selBoxArgs[0], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); XtSetArg(selBoxArgs[1], XmNautoUnmanage, False); selBox = CreatePromptDialog(parent, "wrapMargin", selBoxArgs, 2); XtAddCallback(selBox, XmNokCallback, (XtCallbackProc)wrapOKCB, NULL); XtAddCallback(selBox, XmNcancelCallback, (XtCallbackProc)wrapCancelCB,NULL); XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_TEXT)); XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_SELECTION_LABEL)); XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_HELP_BUTTON)); XtVaSetValues(XtParent(selBox), XmNtitle, "Wrap Margin", NULL); form = XtVaCreateManagedWidget("form", xmFormWidgetClass, selBox, NULL); WrapWindowToggle = XtVaCreateManagedWidget("wrapWindowToggle", xmToggleButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("Wrap and Fill at width of window"), XmNmnemonic, 'W', XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, NULL); XmStringFree(s1); XtAddCallback(WrapWindowToggle, XmNvalueChangedCallback, wrapWindowCB,NULL); WrapText = XtVaCreateManagedWidget("wrapText", xmTextWidgetClass, form, XmNcolumns, 5, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, WrapWindowToggle, XmNrightAttachment, XmATTACH_FORM, NULL); RemapDeleteKey(WrapText); WrapTextLabel = XtVaCreateManagedWidget("wrapMarginLabel", xmLabelGadgetClass, form, XmNlabelString, s1=XmStringCreateSimple( "Margin for Wrap and Fill"), XmNmnemonic, 'M', XmNuserData, WrapText, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, WrapWindowToggle, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, WrapText, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomWidget, WrapText, NULL); XmStringFree(s1); /* Set default value */ if (forWindow == NULL) margin = GetPrefWrapMargin(); else XtVaGetValues(forWindow->textArea, textNwrapMargin, &margin, NULL); XmToggleButtonSetState(WrapWindowToggle, margin==0, True); if (margin != 0) SetIntText(WrapText, margin); XtSetSensitive(WrapText, margin!=0); XtSetSensitive(WrapTextLabel, margin!=0); /* Handle mnemonic selection of buttons and focus to dialog */ AddDialogMnemonicHandler(form, FALSE); /* put up dialog and wait for user to press ok or cancel */ WrapDialogForWindow = forWindow; DoneWithWrapDialog = False; ManageDialogCenteredOnPointer(selBox); while (!DoneWithWrapDialog) { XEvent event; XtAppNextEvent(XtWidgetToApplicationContext(parent), &event); ServerDispatchEvent(&event); } XtDestroyWidget(selBox); } static void wrapOKCB(Widget w, XtPointer clientData, XtPointer callData) { int wrapAtWindow, margin, stat; WindowInfo *window = WrapDialogForWindow; /* get the values that the user entered and make sure they're ok */ wrapAtWindow = XmToggleButtonGetState(WrapWindowToggle); if (wrapAtWindow) margin = 0; else { stat = GetIntTextWarn(WrapText, &margin, "wrap Margin", True); if (stat != TEXT_READ_OK) return; if (margin <= 0 || margin >= 1000) { DialogF(DF_WARN, WrapText, 1, "Wrap Margin", "Wrap margin out of range", "OK"); return; } } #ifdef SGI_CUSTOM /* Ask the user about saving as a default preference */ if (WrapDialogForWindow != NULL) { int setDefault; if (!shortPrefToDefault(window->shell, "Wrap Margin Settings", &setDefault)) { DoneWithWrapDialog = True; return; } if (setDefault) { SetPrefWrapMargin(margin); SaveNEditPrefs(window->shell, GetPrefShortMenus()); } } #endif /* Set the value in either the requested window or default preferences */ if (WrapDialogForWindow == NULL) SetPrefWrapMargin(margin); else { char *params[1]; char marginStr[25]; sprintf(marginStr, "%d", margin); params[0] = marginStr; XtCallActionProc(window->textArea, "set_wrap_margin", NULL, params, 1); } DoneWithWrapDialog = True; } static void wrapCancelCB(Widget w, XtPointer clientData, XtPointer callData) { DoneWithWrapDialog = True; } static void wrapWindowCB(Widget w, XtPointer clientData, XtPointer callData) { int wrapAtWindow = XmToggleButtonGetState(w); XtSetSensitive(WrapTextLabel, !wrapAtWindow); XtSetSensitive(WrapText, !wrapAtWindow); } /* ** Create and show a dialog for selecting the shell */ void SelectShellDialog(Widget parent, WindowInfo* forWindow) { Widget shellSelDialog; Arg shellSelDialogArgs[2]; XmString label; /* Set up the dialog. */ XtSetArg(shellSelDialogArgs[0], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); XtSetArg(shellSelDialogArgs[1], XmNautoUnmanage, False); shellSelDialog = CreatePromptDialog(parent, "shellSelDialog", shellSelDialogArgs, 2); /* Fix dialog to our liking. */ XtVaSetValues(XtParent(shellSelDialog), XmNtitle, "Command Shell", NULL); XtAddCallback(shellSelDialog, XmNokCallback, (XtCallbackProc) shellSelOKCB, shellSelDialog); XtAddCallback(shellSelDialog, XmNcancelCallback, (XtCallbackProc) shellSelCancelCB, NULL); XtUnmanageChild(XmSelectionBoxGetChild(shellSelDialog, XmDIALOG_HELP_BUTTON)); label = XmStringCreateLocalized("Enter shell path:"); XtVaSetValues(shellSelDialog, XmNselectionLabelString, label, NULL); XmStringFree(label); /* Set dialog's text to the current setting. */ XmTextSetString(XmSelectionBoxGetChild(shellSelDialog, XmDIALOG_TEXT), (char*) GetPrefShell()); DoneWithShellSelDialog = False; /* Show dialog and wait until the user made her choice. */ ManageDialogCenteredOnPointer(shellSelDialog); while (!DoneWithShellSelDialog) { XEvent event; XtAppNextEvent(XtWidgetToApplicationContext(parent), &event); ServerDispatchEvent(&event); } XtDestroyWidget(shellSelDialog); } static void shellSelOKCB(Widget widget, XtPointer clientData, XtPointer callData) { Widget shellSelDialog = (Widget) clientData; String shellName = XtMalloc(MAXPATHLEN); struct stat attribute; unsigned dlgResult; /* Leave with a warning if the dialog is not up. */ if (!XtIsRealized(shellSelDialog)) { fprintf(stderr, "nedit: Callback shellSelOKCB() illegally called.\n"); return; } /* Get the string that the user entered and make sure it's ok. */ shellName = XmTextGetString(XmSelectionBoxGetChild(shellSelDialog, XmDIALOG_TEXT)); if (-1 == stat(shellName, &attribute)) { dlgResult = DialogF(DF_WARN, shellSelDialog, 2, "Command Shell", "The selected shell is not available.\nDo you want to use it anyway?", "OK", "Cancel"); if (1 != dlgResult) { return; } } SetPrefShell(shellName); XtFree(shellName); DoneWithShellSelDialog = True; } static void shellSelCancelCB(Widget widgget, XtPointer clientData, XtPointer callData) { DoneWithShellSelDialog = True; } /* ** Present a dialog for editing language mode information */ void EditLanguageModes(void) { #define LIST_RIGHT 40 #define LEFT_MARGIN_POS 1 #define RIGHT_MARGIN_POS 99 #define H_MARGIN 5 Widget form, nameLbl, topLbl, extLbl, recogLbl, delimitLbl, defTipsLbl; Widget okBtn, applyBtn, closeBtn; Widget overrideFrame, overrideForm, delimitForm; Widget tabForm, tabLbl, indentBox, wrapBox; XmString s1; int i, ac; Arg args[20]; /* if the dialog is already displayed, just pop it to the top and return */ if (LMDialog.shell != NULL) { RaiseDialogWindow(LMDialog.shell); return; } LMDialog.languageModeList = (languageModeRec **)XtMalloc( sizeof(languageModeRec *) * MAX_LANGUAGE_MODES); for (i=0; iname, LMDialog.languageModeList[itemIndex]->name)) return True; /* don't allow deletion if data will be lost */ if (LMHasHighlightPatterns(LMDialog.languageModeList[itemIndex]->name)) { DialogF(DF_WARN, LMDialog.shell, 1, "Patterns exist", "This language mode has syntax highlighting\n" "patterns defined. Please delete the patterns\n" "first, in Preferences -> Default Settings ->\n" "Syntax Highlighting, before proceeding here.", "OK"); return False; } /* don't allow deletion if data will be lost */ if (LMHasSmartIndentMacros(LMDialog.languageModeList[itemIndex]->name)) { DialogF(DF_WARN, LMDialog.shell, 1, "Smart Indent Macros exist", "This language mode has smart indent macros\n" "defined. Please delete the macros first,\n" "in Preferences -> Default Settings ->\n" "Auto Indent -> Program Smart Indent,\n" "before proceeding here.", "OK"); return False; } return True; } /* ** Apply the changes that the user has made in the language modes dialog to the ** stored language mode information for this NEdit session (the data array ** LanguageModes) */ static int updateLMList(void) { WindowInfo *window; int oldLanguageMode; char *oldModeName, *newDelimiters; int i, j; /* Get the current contents of the dialog fields */ if (!UpdateManagedList(LMDialog.managedListW, True)) return False; /* Fix up language mode indices in all open windows (which may change if the currently selected mode is deleted or has changed position), and update word delimiters */ for (window=WindowList; window!=NULL; window=window->next) { if (window->languageMode != PLAIN_LANGUAGE_MODE) { oldLanguageMode = window->languageMode; oldModeName = LanguageModes[window->languageMode]->name; window->languageMode = PLAIN_LANGUAGE_MODE; for (i=0; iname)) { newDelimiters = LMDialog.languageModeList[i]->delimiters; if (newDelimiters == NULL) newDelimiters = GetPrefDelimiters(); XtVaSetValues(window->textArea, textNwordDelimiters, newDelimiters, NULL); for (j=0; jnPanes; j++) XtVaSetValues(window->textPanes[j], textNwordDelimiters, newDelimiters, NULL); /* don't forget to adapt the LM stored within the user menu cache */ if (window->userMenuCache->umcLanguageMode == oldLanguageMode) window->userMenuCache->umcLanguageMode = i; if (window->userBGMenuCache.ubmcLanguageMode == oldLanguageMode) window->userBGMenuCache.ubmcLanguageMode = i; /* update the language mode of this window (document) */ window->languageMode = i; break; } } } } /* If there were any name changes, re-name dependent highlight patterns and smart-indent macros and fix up the weird rename-format names */ for (i=0; iname, ':') != NULL) { char *newName = strrchr(LMDialog.languageModeList[i]->name, ':')+1; *strchr(LMDialog.languageModeList[i]->name, ':') = '\0'; RenameHighlightPattern(LMDialog.languageModeList[i]->name, newName); RenameSmartIndentMacros(LMDialog.languageModeList[i]->name, newName); memmove(LMDialog.languageModeList[i]->name, newName, strlen(newName) + 1); ChangeManagedListData(LMDialog.managedListW); } } /* Replace the old language mode list with the new one from the dialog */ for (i=0; inext) { updateLanguageModeSubmenu(window); if (window->languageMode != PLAIN_LANGUAGE_MODE && LanguageModes[window->languageMode]->defTipsFile != NULL) AddTagsFile(LanguageModes[window->languageMode]->defTipsFile, TIP); /* cache user menus: Rebuild all user menus of this window */ RebuildAllMenus(window); } /* If a syntax highlighting dialog is up, update its menu */ UpdateLanguageModeMenu(); /* The same for the smart indent macro dialog */ UpdateLangModeMenuSmartIndent(); /* Note that preferences have been changed */ MarkPrefsChanged(); return True; } static void *lmGetDisplayedCB(void *oldItem, int explicitRequest, int *abort, void *cbArg) { languageModeRec *lm, *oldLM = (languageModeRec *)oldItem; char *tempName; int i, nCopies, oldLen; /* If the dialog is currently displaying the "new" entry and the fields are empty, that's just fine */ if (oldItem == NULL && lmDialogEmpty()) return NULL; /* Read the data the user has entered in the dialog fields */ lm = readLMDialogFields(True); /* If there was a name change of a non-duplicate language mode, modify the name to the weird format of: ":old name:new name". This signals that a name change is necessary in lm dependent data such as highlight patterns. Duplicate language modes may be re-named at will, since no data will be lost due to the name change. */ if (lm != NULL && oldLM != NULL && strcmp(oldLM->name, lm->name)) { nCopies = 0; for (i=0; iname, LMDialog.languageModeList[i]->name)) nCopies++; if (nCopies <= 1) { oldLen = strchr(oldLM->name, ':') == NULL ? strlen(oldLM->name) : strchr(oldLM->name, ':') - oldLM->name; tempName = XtMalloc(oldLen + strlen(lm->name) + 2); strncpy(tempName, oldLM->name, oldLen); sprintf(&tempName[oldLen], ":%s", lm->name); XtFree(lm->name); lm->name = tempName; } } /* If there are no problems reading the data, just return it */ if (lm != NULL) return (void *)lm; /* If there are problems, and the user didn't ask for the fields to be read, give more warning */ if (!explicitRequest) { if (DialogF(DF_WARN, LMDialog.shell, 2, "Discard Language Mode", "Discard incomplete entry\nfor current language mode?", "Keep", "Discard") == 2) { return oldItem == NULL ? NULL : (void *)copyLanguageModeRec((languageModeRec *)oldItem); } } /* Do readLMDialogFields again without "silent" mode to display warning */ lm = readLMDialogFields(False); *abort = True; return NULL; } static void lmSetDisplayedCB(void *item, void *cbArg) { languageModeRec *lm = (languageModeRec *)item; char *extStr; if (item == NULL) { XmTextSetString(LMDialog.nameW, ""); XmTextSetString(LMDialog.extW, ""); XmTextSetString(LMDialog.recogW, ""); XmTextSetString(LMDialog.defTipsW, ""); XmTextSetString(LMDialog.delimitW, ""); XmTextSetString(LMDialog.tabW, ""); XmTextSetString(LMDialog.emTabW, ""); RadioButtonChangeState(LMDialog.defaultIndentW, True, True); RadioButtonChangeState(LMDialog.defaultWrapW, True, True); } else { XmTextSetString(LMDialog.nameW, strchr(lm->name, ':') == NULL ? lm->name : strchr(lm->name, ':')+1); extStr = createExtString(lm->extensions, lm->nExtensions); XmTextSetString(LMDialog.extW, extStr); XtFree(extStr); XmTextSetString(LMDialog.recogW, lm->recognitionExpr); XmTextSetString(LMDialog.defTipsW, lm->defTipsFile); XmTextSetString(LMDialog.delimitW, lm->delimiters); if (lm->tabDist == DEFAULT_TAB_DIST) XmTextSetString(LMDialog.tabW, ""); else SetIntText(LMDialog.tabW, lm->tabDist); if (lm->emTabDist == DEFAULT_EM_TAB_DIST) XmTextSetString(LMDialog.emTabW, ""); else SetIntText(LMDialog.emTabW, lm->emTabDist); RadioButtonChangeState(LMDialog.defaultIndentW, lm->indentStyle == DEFAULT_INDENT, False); RadioButtonChangeState(LMDialog.noIndentW, lm->indentStyle == NO_AUTO_INDENT, False); RadioButtonChangeState(LMDialog.autoIndentW, lm->indentStyle == AUTO_INDENT, False); RadioButtonChangeState(LMDialog.smartIndentW, lm->indentStyle == SMART_INDENT, False); RadioButtonChangeState(LMDialog.defaultWrapW, lm->wrapStyle == DEFAULT_WRAP, False); RadioButtonChangeState(LMDialog.noWrapW, lm->wrapStyle == NO_WRAP, False); RadioButtonChangeState(LMDialog.newlineWrapW, lm->wrapStyle == NEWLINE_WRAP, False); RadioButtonChangeState(LMDialog.contWrapW, lm->wrapStyle == CONTINUOUS_WRAP, False); } } static void lmFreeItemCB(void *item) { freeLanguageModeRec((languageModeRec *)item); } static void freeLanguageModeRec(languageModeRec *lm) { int i; XtFree(lm->name); XtFree(lm->recognitionExpr); XtFree(lm->defTipsFile); XtFree(lm->delimiters); for (i=0; inExtensions; i++) XtFree(lm->extensions[i]); XtFree((char*) lm->extensions); XtFree((char *)lm); } /* ** Copy a languageModeRec data structure and all of the allocated data it contains */ static languageModeRec *copyLanguageModeRec(languageModeRec *lm) { languageModeRec *newLM; int i; newLM = (languageModeRec *)XtMalloc(sizeof(languageModeRec)); newLM->name = XtMalloc(strlen(lm->name)+1); strcpy(newLM->name, lm->name); newLM->nExtensions = lm->nExtensions; newLM->extensions = (char **)XtMalloc(sizeof(char *) * lm->nExtensions); for (i=0; inExtensions; i++) { newLM->extensions[i] = XtMalloc(strlen(lm->extensions[i]) + 1); strcpy(newLM->extensions[i], lm->extensions[i]); } if (lm->recognitionExpr == NULL) newLM->recognitionExpr = NULL; else { newLM->recognitionExpr = XtMalloc(strlen(lm->recognitionExpr)+1); strcpy(newLM->recognitionExpr, lm->recognitionExpr); } if (lm->defTipsFile == NULL) newLM->defTipsFile = NULL; else { newLM->defTipsFile = XtMalloc(strlen(lm->defTipsFile)+1); strcpy(newLM->defTipsFile, lm->defTipsFile); } if (lm->delimiters == NULL) newLM->delimiters = NULL; else { newLM->delimiters = XtMalloc(strlen(lm->delimiters)+1); strcpy(newLM->delimiters, lm->delimiters); } newLM->wrapStyle = lm->wrapStyle; newLM->indentStyle = lm->indentStyle; newLM->tabDist = lm->tabDist; newLM->emTabDist = lm->emTabDist; return newLM; } /* ** Read the fields in the language modes dialog and create a languageModeRec data ** structure reflecting the current state of the selected language mode in the dialog. ** If any of the information is incorrect or missing, display a warning dialog and ** return NULL. Passing "silent" as True, suppresses the warning dialogs. */ static languageModeRec *readLMDialogFields(int silent) { languageModeRec *lm; regexp *compiledRE; char *compileMsg, *extStr, *extPtr; /* Allocate a language mode structure to return, set unread fields to empty so everything can be freed on errors by freeLanguageModeRec */ lm = (languageModeRec *)XtMalloc(sizeof(languageModeRec)); lm->nExtensions = 0; lm->recognitionExpr = NULL; lm->defTipsFile = NULL; lm->delimiters = NULL; /* read the name field */ lm->name = ReadSymbolicFieldTextWidget(LMDialog.nameW, "language mode name", silent); if (lm->name == NULL) { XtFree((char *)lm); return NULL; } if (*lm->name == '\0') { if (!silent) { DialogF(DF_WARN, LMDialog.shell, 1, "Language Mode Name", "Please specify a name\nfor the language mode", "OK"); XmProcessTraversal(LMDialog.nameW, XmTRAVERSE_CURRENT); } freeLanguageModeRec(lm); return NULL; } /* read the extension list field */ extStr = extPtr = XmTextGetString(LMDialog.extW); lm->extensions = readExtensionList(&extPtr, &lm->nExtensions); XtFree(extStr); /* read recognition expression */ lm->recognitionExpr = XmTextGetString(LMDialog.recogW); if (*lm->recognitionExpr == '\0') { XtFree(lm->recognitionExpr); lm->recognitionExpr = NULL; } else { compiledRE = CompileRE(lm->recognitionExpr, &compileMsg, REDFLT_STANDARD); if (compiledRE == NULL) { if (!silent) { DialogF(DF_WARN, LMDialog.shell, 1, "Regex", "Recognition expression:\n%s", "OK", compileMsg); XmProcessTraversal(LMDialog.recogW, XmTRAVERSE_CURRENT); } XtFree((char *)compiledRE); freeLanguageModeRec(lm); return NULL; } XtFree((char *)compiledRE); } /* Read the default calltips file for the language mode */ lm->defTipsFile = XmTextGetString(LMDialog.defTipsW); if (*lm->defTipsFile == '\0') { /* Empty string */ XtFree(lm->defTipsFile); lm->defTipsFile = NULL; } else { /* Ensure that AddTagsFile will work */ if (AddTagsFile(lm->defTipsFile, TIP) == FALSE) { if (!silent) { DialogF(DF_WARN, LMDialog.shell, 1, "Error reading Calltips", "Can't read default calltips file(s):\n \"%s\"\n", "OK", lm->defTipsFile); XmProcessTraversal(LMDialog.recogW, XmTRAVERSE_CURRENT); } freeLanguageModeRec(lm); return NULL; } else if (DeleteTagsFile(lm->defTipsFile, TIP, False) == FALSE) fprintf(stderr, "nedit: Internal error: Trouble deleting " "calltips file(s):\n \"%s\"\n", lm->defTipsFile); } /* read tab spacing field */ if (TextWidgetIsBlank(LMDialog.tabW)) lm->tabDist = DEFAULT_TAB_DIST; else { if (GetIntTextWarn(LMDialog.tabW, &lm->tabDist, "tab spacing", False) != TEXT_READ_OK) { freeLanguageModeRec(lm); return NULL; } if (lm->tabDist <= 0 || lm->tabDist > 100) { if (!silent) { DialogF(DF_WARN, LMDialog.shell, 1, "Invalid Tab Spacing", "Invalid tab spacing: %d", "OK", lm->tabDist); XmProcessTraversal(LMDialog.tabW, XmTRAVERSE_CURRENT); } freeLanguageModeRec(lm); return NULL; } } /* read emulated tab field */ if (TextWidgetIsBlank(LMDialog.emTabW)) { lm->emTabDist = DEFAULT_EM_TAB_DIST; } else { if (GetIntTextWarn(LMDialog.emTabW, &lm->emTabDist, "emulated tab spacing", False) != TEXT_READ_OK) { freeLanguageModeRec(lm); return NULL; } if (lm->emTabDist < 0 || lm->emTabDist > 100) { if (!silent) { DialogF(DF_WARN, LMDialog.shell, 1, "Invalid Tab Spacing", "Invalid emulated tab spacing: %d", "OK", lm->emTabDist); XmProcessTraversal(LMDialog.emTabW, XmTRAVERSE_CURRENT); } freeLanguageModeRec(lm); return NULL; } } /* read delimiters string */ lm->delimiters = XmTextGetString(LMDialog.delimitW); if (*lm->delimiters == '\0') { XtFree(lm->delimiters); lm->delimiters = NULL; } /* read indent style */ if (XmToggleButtonGetState(LMDialog.noIndentW)) lm->indentStyle = NO_AUTO_INDENT; else if (XmToggleButtonGetState(LMDialog.autoIndentW)) lm->indentStyle = AUTO_INDENT; else if (XmToggleButtonGetState(LMDialog.smartIndentW)) lm->indentStyle = SMART_INDENT; else lm->indentStyle = DEFAULT_INDENT; /* read wrap style */ if (XmToggleButtonGetState(LMDialog.noWrapW)) lm->wrapStyle = NO_WRAP; else if (XmToggleButtonGetState(LMDialog.newlineWrapW)) lm->wrapStyle = NEWLINE_WRAP; else if (XmToggleButtonGetState(LMDialog.contWrapW)) lm->wrapStyle = CONTINUOUS_WRAP; else lm->wrapStyle = DEFAULT_WRAP; return lm; } /* ** Return True if the language mode dialog fields are blank (unchanged from the "New" ** language mode state). */ static int lmDialogEmpty(void) { return TextWidgetIsBlank(LMDialog.nameW) && TextWidgetIsBlank(LMDialog.extW) && TextWidgetIsBlank(LMDialog.recogW) && TextWidgetIsBlank(LMDialog.delimitW) && TextWidgetIsBlank(LMDialog.tabW) && TextWidgetIsBlank(LMDialog.emTabW) && XmToggleButtonGetState(LMDialog.defaultIndentW) && XmToggleButtonGetState(LMDialog.defaultWrapW); } /* ** Present a dialog for changing fonts (primary, and for highlighting). */ void ChooseFonts(WindowInfo *window, int forWindow) { #define MARGIN_SPACING 10 #define BTN_TEXT_OFFSET 3 Widget form, primaryLbl, primaryBtn, italicLbl, italicBtn; Widget boldLbl, boldBtn, boldItalicLbl, boldItalicBtn; Widget primaryFrame, primaryForm, highlightFrame, highlightForm; Widget okBtn, applyBtn, cancelBtn; fontDialog *fd; XmString s1; int ac; Arg args[20]; /* if the dialog is already displayed, just pop it to the top and return */ if (window->fontDialog != NULL) { RaiseDialogWindow(((fontDialog *)window->fontDialog)->shell); return; } /* Create a structure for keeping track of dialog state */ fd = (fontDialog *)XtMalloc(sizeof(fontDialog)); fd->window = window; fd->forWindow = forWindow; window->fontDialog = (void*)fd; /* Create a form widget in a dialog shell */ ac = 0; XtSetArg(args[ac], XmNautoUnmanage, False); ac++; XtSetArg(args[ac], XmNresizePolicy, XmRESIZE_NONE); ac++; form = CreateFormDialog(window->shell, "choose Fonts", args, ac); XtVaSetValues(form, XmNshadowThickness, 0, NULL); fd->shell = XtParent(form); XtVaSetValues(fd->shell, XmNtitle, "Text Fonts", NULL); AddMotifCloseCallback(XtParent(form), fontCancelCB, fd); XtAddCallback(form, XmNdestroyCallback, fontDestroyCB, fd); primaryFrame = XtVaCreateManagedWidget("primaryFrame", xmFrameWidgetClass, form, XmNmarginHeight, 3, XmNtopAttachment, XmATTACH_POSITION, XmNtopPosition, 2, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 99, NULL); primaryForm = XtVaCreateManagedWidget("primaryForm", xmFormWidgetClass, primaryFrame, NULL); primaryLbl = XtVaCreateManagedWidget("primaryFont", xmLabelGadgetClass, primaryFrame, XmNlabelString, s1=XmStringCreateSimple("Primary Font"), XmNmnemonic, 'P', XmNchildType, XmFRAME_TITLE_CHILD, XmNchildHorizontalAlignment, XmALIGNMENT_CENTER, NULL); XmStringFree(s1); primaryBtn = XtVaCreateManagedWidget("primaryBtn", xmPushButtonWidgetClass, primaryForm, XmNlabelString, s1=XmStringCreateSimple("Browse..."), XmNmnemonic, 'r', XmNtopAttachment, XmATTACH_POSITION, XmNtopPosition, 2, XmNtopOffset, BTN_TEXT_OFFSET, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, NULL); XmStringFree(s1); XtAddCallback(primaryBtn, XmNactivateCallback, primaryBrowseCB, fd); fd->primaryW = XtVaCreateManagedWidget("primary", xmTextWidgetClass, primaryForm, XmNcolumns, 70, XmNmaxLength, MAX_FONT_LEN, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, primaryBtn, XmNtopAttachment, XmATTACH_POSITION, XmNtopPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 99, NULL); RemapDeleteKey(fd->primaryW); XtAddCallback(fd->primaryW, XmNvalueChangedCallback, primaryModifiedCB, fd); XtVaSetValues(primaryLbl, XmNuserData, fd->primaryW, NULL); highlightFrame = XtVaCreateManagedWidget("highlightFrame", xmFrameWidgetClass, form, XmNmarginHeight, 3, XmNnavigationType, XmTAB_GROUP, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, primaryFrame, XmNtopOffset, 20, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 99, NULL); highlightForm = XtVaCreateManagedWidget("highlightForm", xmFormWidgetClass, highlightFrame, NULL); XtVaCreateManagedWidget("highlightFonts", xmLabelGadgetClass, highlightFrame, XmNlabelString, s1=XmStringCreateSimple("Fonts for Syntax Highlighting"), XmNchildType, XmFRAME_TITLE_CHILD, XmNchildHorizontalAlignment, XmALIGNMENT_CENTER, NULL); XmStringFree(s1); fd->fillW = XtVaCreateManagedWidget("fillBtn", xmPushButtonWidgetClass, highlightForm, XmNlabelString, s1=XmStringCreateSimple("Fill Highlight Fonts from Primary"), XmNmnemonic, 'F', XmNtopAttachment, XmATTACH_POSITION, XmNtopPosition, 2, XmNtopOffset, BTN_TEXT_OFFSET, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, NULL); XmStringFree(s1); XtAddCallback(fd->fillW, XmNactivateCallback, fillFromPrimaryCB, fd); italicLbl = XtVaCreateManagedWidget("italicLbl", xmLabelGadgetClass, highlightForm, XmNlabelString, s1=XmStringCreateSimple("Italic Font"), XmNmnemonic, 'I', XmNalignment, XmALIGNMENT_BEGINNING, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, fd->fillW, XmNtopOffset, MARGIN_SPACING, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, NULL); XmStringFree(s1); fd->italicErrW = XtVaCreateManagedWidget("italicErrLbl", xmLabelGadgetClass, highlightForm, XmNlabelString, s1=XmStringCreateSimple( "(vvv spacing is inconsistent with primary font vvv)"), XmNalignment, XmALIGNMENT_END, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, fd->fillW, XmNtopOffset, MARGIN_SPACING, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, italicLbl, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 99, NULL); XmStringFree(s1); italicBtn = XtVaCreateManagedWidget("italicBtn", xmPushButtonWidgetClass, highlightForm, XmNlabelString, s1=XmStringCreateSimple("Browse..."), XmNmnemonic, 'o', XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, italicLbl, XmNtopOffset, BTN_TEXT_OFFSET, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, NULL); XmStringFree(s1); XtAddCallback(italicBtn, XmNactivateCallback, italicBrowseCB, fd); fd->italicW = XtVaCreateManagedWidget("italic", xmTextWidgetClass, highlightForm, XmNmaxLength, MAX_FONT_LEN, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, italicBtn, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, italicLbl, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 99, NULL); RemapDeleteKey(fd->italicW); XtAddCallback(fd->italicW, XmNvalueChangedCallback, italicModifiedCB, fd); XtVaSetValues(italicLbl, XmNuserData, fd->italicW, NULL); boldLbl = XtVaCreateManagedWidget("boldLbl", xmLabelGadgetClass, highlightForm, XmNlabelString, s1=XmStringCreateSimple("Bold Font"), XmNmnemonic, 'B', XmNalignment, XmALIGNMENT_BEGINNING, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, italicBtn, XmNtopOffset, MARGIN_SPACING, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, NULL); XmStringFree(s1); fd->boldErrW = XtVaCreateManagedWidget("boldErrLbl", xmLabelGadgetClass, highlightForm, XmNlabelString, s1=XmStringCreateSimple(""), XmNalignment, XmALIGNMENT_END, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, italicBtn, XmNtopOffset, MARGIN_SPACING, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, boldLbl, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 99, NULL); XmStringFree(s1); boldBtn = XtVaCreateManagedWidget("boldBtn", xmPushButtonWidgetClass, highlightForm, XmNlabelString, s1=XmStringCreateSimple("Browse..."), XmNmnemonic, 'w', XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, boldLbl, XmNtopOffset, BTN_TEXT_OFFSET, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, NULL); XmStringFree(s1); XtAddCallback(boldBtn, XmNactivateCallback, boldBrowseCB, fd); fd->boldW = XtVaCreateManagedWidget("bold", xmTextWidgetClass, highlightForm, XmNmaxLength, MAX_FONT_LEN, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, boldBtn, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, boldLbl, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 99, NULL); RemapDeleteKey(fd->boldW); XtAddCallback(fd->boldW, XmNvalueChangedCallback, boldModifiedCB, fd); XtVaSetValues(boldLbl, XmNuserData, fd->boldW, NULL); boldItalicLbl = XtVaCreateManagedWidget("boldItalicLbl", xmLabelGadgetClass, highlightForm, XmNlabelString, s1=XmStringCreateSimple("Bold Italic Font"), XmNmnemonic, 'l', XmNalignment, XmALIGNMENT_BEGINNING, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, boldBtn, XmNtopOffset, MARGIN_SPACING, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, NULL); XmStringFree(s1); fd->boldItalicErrW = XtVaCreateManagedWidget("boldItalicErrLbl", xmLabelGadgetClass, highlightForm, XmNlabelString, s1=XmStringCreateSimple(""), XmNalignment, XmALIGNMENT_END, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, boldBtn, XmNtopOffset, MARGIN_SPACING, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, boldItalicLbl, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 99, NULL); XmStringFree(s1); boldItalicBtn = XtVaCreateManagedWidget("boldItalicBtn", xmPushButtonWidgetClass, highlightForm, XmNlabelString, s1=XmStringCreateSimple("Browse..."), XmNmnemonic, 's', XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, boldItalicLbl, XmNtopOffset, BTN_TEXT_OFFSET, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, NULL); XmStringFree(s1); XtAddCallback(boldItalicBtn, XmNactivateCallback, boldItalicBrowseCB, fd); fd->boldItalicW = XtVaCreateManagedWidget("boldItalic", xmTextWidgetClass, highlightForm, XmNmaxLength, MAX_FONT_LEN, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, boldItalicBtn, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, boldItalicLbl, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 99, NULL); RemapDeleteKey(fd->boldItalicW); XtAddCallback(fd->boldItalicW, XmNvalueChangedCallback, boldItalicModifiedCB, fd); XtVaSetValues(boldItalicLbl, XmNuserData, fd->boldItalicW, NULL); okBtn = XtVaCreateManagedWidget("ok", xmPushButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("OK"), XmNmarginWidth, BUTTON_WIDTH_MARGIN, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, highlightFrame, XmNtopOffset, MARGIN_SPACING, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, forWindow ? 13 : 26, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, forWindow ? 27 : 40, NULL); XtAddCallback(okBtn, XmNactivateCallback, fontOkCB, fd); XmStringFree(s1); if (forWindow) { applyBtn = XtVaCreateManagedWidget("apply",xmPushButtonWidgetClass,form, XmNlabelString, s1=XmStringCreateSimple("Apply"), XmNmnemonic, 'A', XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, highlightFrame, XmNtopOffset, MARGIN_SPACING, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 43, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 57, NULL); XtAddCallback(applyBtn, XmNactivateCallback, fontApplyCB, fd); XmStringFree(s1); } cancelBtn = XtVaCreateManagedWidget("cancel", xmPushButtonWidgetClass, form, XmNlabelString, s1 = XmStringCreateSimple(forWindow ? "Close" : "Cancel"), XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, highlightFrame, XmNtopOffset, MARGIN_SPACING, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, forWindow ? 73 : 59, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, forWindow ? 87 : 73, NULL); XtAddCallback(cancelBtn, XmNactivateCallback, fontCancelCB, fd); XmStringFree(s1); /* Set initial default button */ XtVaSetValues(form, XmNdefaultButton, okBtn, NULL); XtVaSetValues(form, XmNcancelButton, cancelBtn, NULL); /* Set initial values */ if (forWindow) { XmTextSetString(fd->primaryW, window->fontName); XmTextSetString(fd->boldW, window->boldFontName); XmTextSetString(fd->italicW, window->italicFontName); XmTextSetString(fd->boldItalicW, window->boldItalicFontName); } else { XmTextSetString(fd->primaryW, GetPrefFontName()); XmTextSetString(fd->boldW, GetPrefBoldFontName()); XmTextSetString(fd->italicW, GetPrefItalicFontName()); XmTextSetString(fd->boldItalicW, GetPrefBoldItalicFontName()); } /* Handle mnemonic selection of buttons and focus to dialog */ AddDialogMnemonicHandler(form, FALSE); /* put up dialog */ ManageDialogCenteredOnPointer(form); } static void fillFromPrimaryCB(Widget w, XtPointer clientData, XtPointer callData) { fontDialog *fd = (fontDialog *)clientData; char *primaryName, *errMsg; char modifiedFontName[MAX_FONT_LEN]; char *searchString = "(-[^-]*-[^-]*)-([^-]*)-([^-]*)-(.*)"; char *italicReplaceString = "\\1-\\2-o-\\4"; char *boldReplaceString = "\\1-bold-\\3-\\4"; char *boldItalicReplaceString = "\\1-bold-o-\\4"; regexp *compiledRE; /* Match the primary font agains RE pattern for font names. If it doesn't match, we can't generate highlight font names, so return */ compiledRE = CompileRE(searchString, &errMsg, REDFLT_STANDARD); primaryName = XmTextGetString(fd->primaryW); if (!ExecRE(compiledRE, primaryName, NULL, False, '\0', '\0', NULL, NULL, NULL)) { XBell(XtDisplay(fd->shell), 0); free(compiledRE); XtFree(primaryName); return; } /* Make up names for new fonts based on RE replace patterns */ SubstituteRE(compiledRE, italicReplaceString, modifiedFontName, MAX_FONT_LEN); XmTextSetString(fd->italicW, modifiedFontName); SubstituteRE(compiledRE, boldReplaceString, modifiedFontName, MAX_FONT_LEN); XmTextSetString(fd->boldW, modifiedFontName); SubstituteRE(compiledRE, boldItalicReplaceString, modifiedFontName, MAX_FONT_LEN); XmTextSetString(fd->boldItalicW, modifiedFontName); XtFree(primaryName); free(compiledRE); } static void primaryModifiedCB(Widget w, XtPointer clientData, XtPointer callData) { fontDialog *fd = (fontDialog *)clientData; showFontStatus(fd, fd->italicW, fd->italicErrW); showFontStatus(fd, fd->boldW, fd->boldErrW); showFontStatus(fd, fd->boldItalicW, fd->boldItalicErrW); } static void italicModifiedCB(Widget w, XtPointer clientData, XtPointer callData) { fontDialog *fd = (fontDialog *)clientData; showFontStatus(fd, fd->italicW, fd->italicErrW); } static void boldModifiedCB(Widget w, XtPointer clientData, XtPointer callData) { fontDialog *fd = (fontDialog *)clientData; showFontStatus(fd, fd->boldW, fd->boldErrW); } static void boldItalicModifiedCB(Widget w, XtPointer clientData, XtPointer callData) { fontDialog *fd = (fontDialog *)clientData; showFontStatus(fd, fd->boldItalicW, fd->boldItalicErrW); } static void primaryBrowseCB(Widget w, XtPointer clientData, XtPointer callData) { fontDialog *fd = (fontDialog *)clientData; browseFont(fd->shell, fd->primaryW); } static void italicBrowseCB(Widget w, XtPointer clientData, XtPointer callData) { fontDialog *fd = (fontDialog *)clientData; browseFont(fd->shell, fd->italicW); } static void boldBrowseCB(Widget w, XtPointer clientData, XtPointer callData) { fontDialog *fd = (fontDialog *)clientData; browseFont(fd->shell, fd->boldW); } static void boldItalicBrowseCB(Widget w, XtPointer clientData, XtPointer callData) { fontDialog *fd = (fontDialog *)clientData; browseFont(fd->shell, fd->boldItalicW); } static void fontDestroyCB(Widget w, XtPointer clientData, XtPointer callData) { fontDialog *fd = (fontDialog *)clientData; fd->window->fontDialog = NULL; XtFree((char *)fd); } static void fontOkCB(Widget w, XtPointer clientData, XtPointer callData) { fontDialog *fd = (fontDialog *)clientData; updateFonts(fd); /* pop down and destroy the dialog */ XtDestroyWidget(fd->shell); } static void fontApplyCB(Widget w, XtPointer clientData, XtPointer callData) { fontDialog *fd = (fontDialog *)clientData; updateFonts(fd); } static void fontCancelCB(Widget w, XtPointer clientData, XtPointer callData) { fontDialog *fd = (fontDialog *)clientData; /* pop down and destroy the dialog */ XtDestroyWidget(fd->shell); } /* ** Check over a font name in a text field to make sure it agrees with the ** primary font in height and spacing. */ static int checkFontStatus(fontDialog *fd, Widget fontTextFieldW) { char *primaryName, *testName; XFontStruct *primaryFont, *testFont; Display *display = XtDisplay(fontTextFieldW); int primaryWidth, primaryHeight, testWidth, testHeight; /* Get width and height of the font to check. Note the test for empty name: X11R6 clients freak out X11R5 servers if they ask them to load an empty font name, and kill the whole application! */ testName = XmTextGetString(fontTextFieldW); if (testName[0] == '\0') { XtFree(testName); return BAD_FONT; } testFont = XLoadQueryFont(display, testName); if (testFont == NULL) { XtFree(testName); return BAD_FONT; } XtFree(testName); testWidth = testFont->min_bounds.width; testHeight = testFont->ascent + testFont->descent; XFreeFont(display, testFont); /* Get width and height of the primary font */ primaryName = XmTextGetString(fd->primaryW); if (primaryName[0] == '\0') { XtFree(primaryName); return BAD_FONT; } primaryFont = XLoadQueryFont(display, primaryName); if (primaryFont == NULL) { XtFree(primaryName); return BAD_PRIMARY; } XtFree(primaryName); primaryWidth = primaryFont->min_bounds.width; primaryHeight = primaryFont->ascent + primaryFont->descent; XFreeFont(display, primaryFont); /* Compare font information */ if (testWidth != primaryWidth) return BAD_SPACING; if (testHeight != primaryHeight) return BAD_SIZE; return GOOD_FONT; } /* ** Update the error label for a font text field to reflect its validity and degree ** of agreement with the currently selected primary font */ static int showFontStatus(fontDialog *fd, Widget fontTextFieldW, Widget errorLabelW) { int status; XmString s; char *msg; status = checkFontStatus(fd, fontTextFieldW); if (status == BAD_PRIMARY) msg = "(font below may not match primary font)"; else if (status == BAD_FONT) msg = "(xxx font below is invalid xxx)"; else if (status == BAD_SIZE) msg = "(height of font below does not match primary)"; else if (status == BAD_SPACING) msg = "(spacing of font below does not match primary)"; else msg = ""; XtVaSetValues(errorLabelW, XmNlabelString, s=XmStringCreateSimple(msg), NULL); XmStringFree(s); return status; } /* ** Put up a font selector panel to set the font name in the text widget "fontTextW" */ static void browseFont(Widget parent, Widget fontTextW) { char *origFontName, *newFontName; Pixel fgPixel, bgPixel; int dummy; origFontName = XmTextGetString(fontTextW); /* Get the values from the defaults */ fgPixel = AllocColor(parent, GetPrefColorName(TEXT_FG_COLOR), &dummy, &dummy, &dummy); bgPixel = AllocColor(parent, GetPrefColorName(TEXT_BG_COLOR), &dummy, &dummy, &dummy); newFontName = FontSel(parent, PREF_FIXED, origFontName, fgPixel, bgPixel); XtFree(origFontName); if (newFontName == NULL) return; XmTextSetString(fontTextW, newFontName); XtFree(newFontName); } /* ** Accept the changes in the dialog and set the fonts regardless of errors */ static void updateFonts(fontDialog *fd) { char *fontName, *italicName, *boldName, *boldItalicName; fontName = XmTextGetString(fd->primaryW); italicName = XmTextGetString(fd->italicW); boldName = XmTextGetString(fd->boldW); boldItalicName = XmTextGetString(fd->boldItalicW); if (fd->forWindow) { char *params[4]; params[0] = fontName; params[1] = italicName; params[2] = boldName; params[3] = boldItalicName; XtCallActionProc(fd->window->textArea, "set_fonts", NULL, params, 4); /* SetFonts(fd->window, fontName, italicName, boldName, boldItalicName); */ } else { SetPrefFont(fontName); SetPrefItalicFont(italicName); SetPrefBoldFont(boldName); SetPrefBoldItalicFont(boldItalicName); } XtFree(fontName); XtFree(italicName); XtFree(boldName); XtFree(boldItalicName); } /* ** Change the language mode to the one indexed by "mode", reseting word ** delimiters, syntax highlighting and other mode specific parameters */ static void reapplyLanguageMode(WindowInfo *window, int mode, int forceDefaults) { char *delimiters; int i, wrapMode, indentStyle, tabDist, emTabDist, highlight, oldEmTabDist; int wrapModeIsDef, tabDistIsDef, emTabDistIsDef, indentStyleIsDef; int highlightIsDef, haveHighlightPatterns, haveSmartIndentMacros; int oldMode = window->languageMode; /* If the mode is the same, and changes aren't being forced (as might happen with Save As...), don't mess with already correct settings */ if (window->languageMode == mode && !forceDefaults) return; /* Change the mode name stored in the window */ window->languageMode = mode; /* Decref oldMode's default calltips file if needed */ if (oldMode != PLAIN_LANGUAGE_MODE && LanguageModes[oldMode]->defTipsFile) { DeleteTagsFile( LanguageModes[oldMode]->defTipsFile, TIP, False ); } /* Set delimiters for all text widgets */ if (mode == PLAIN_LANGUAGE_MODE || LanguageModes[mode]->delimiters == NULL) delimiters = GetPrefDelimiters(); else delimiters = LanguageModes[mode]->delimiters; XtVaSetValues(window->textArea, textNwordDelimiters, delimiters, NULL); for (i=0; inPanes; i++) XtVaSetValues(window->textPanes[i], textNautoIndent, delimiters, NULL); /* Decide on desired values for language-specific parameters. If a parameter was set to its default value, set it to the new default, otherwise, leave it alone */ wrapModeIsDef = window->wrapMode == GetPrefWrap(oldMode); tabDistIsDef = BufGetTabDistance(window->buffer) == GetPrefTabDist(oldMode); XtVaGetValues(window->textArea, textNemulateTabs, &oldEmTabDist, NULL); emTabDistIsDef = oldEmTabDist == GetPrefEmTabDist(oldMode); indentStyleIsDef = window->indentStyle == GetPrefAutoIndent(oldMode) || (GetPrefAutoIndent(oldMode) == SMART_INDENT && window->indentStyle == AUTO_INDENT && !SmartIndentMacrosAvailable(LanguageModeName(oldMode))); highlightIsDef = window->highlightSyntax == GetPrefHighlightSyntax() || (GetPrefHighlightSyntax() && FindPatternSet(LanguageModeName(oldMode)) == NULL); wrapMode = wrapModeIsDef || forceDefaults ? GetPrefWrap(mode) : window->wrapMode; tabDist = tabDistIsDef || forceDefaults ? GetPrefTabDist(mode) : BufGetTabDistance(window->buffer); emTabDist = emTabDistIsDef || forceDefaults ? GetPrefEmTabDist(mode) : oldEmTabDist; indentStyle = indentStyleIsDef || forceDefaults ? GetPrefAutoIndent(mode) : window->indentStyle; highlight = highlightIsDef || forceDefaults ? GetPrefHighlightSyntax() : window->highlightSyntax; /* Dim/undim smart-indent and highlighting menu items depending on whether patterns/macros are available */ haveHighlightPatterns = FindPatternSet(LanguageModeName(mode)) != NULL; haveSmartIndentMacros = SmartIndentMacrosAvailable(LanguageModeName(mode)); if (IsTopDocument(window)) { XtSetSensitive(window->highlightItem, haveHighlightPatterns); XtSetSensitive(window->smartIndentItem, haveSmartIndentMacros); } /* Turn off requested options which are not available */ highlight = haveHighlightPatterns && highlight; if (indentStyle == SMART_INDENT && !haveSmartIndentMacros) indentStyle = AUTO_INDENT; /* Change highlighting */ window->highlightSyntax = highlight; SetToggleButtonState(window, window->highlightItem, highlight, False); StopHighlighting(window); /* we defer highlighting to RaiseDocument() if doc is hidden */ if (IsTopDocument(window) && highlight) StartHighlighting(window, False); /* Force a change of smart indent macros (SetAutoIndent will re-start) */ if (window->indentStyle == SMART_INDENT) { EndSmartIndent(window); window->indentStyle = AUTO_INDENT; } /* set requested wrap, indent, and tabs */ SetAutoWrap(window, wrapMode); SetAutoIndent(window, indentStyle); SetTabDist(window, tabDist); SetEmTabDist(window, emTabDist); /* Load calltips files for new mode */ if (mode != PLAIN_LANGUAGE_MODE && LanguageModes[mode]->defTipsFile) { AddTagsFile( LanguageModes[mode]->defTipsFile, TIP ); } /* Add/remove language specific menu items */ UpdateUserMenus(window); } /* ** Find and return the name of the appropriate languange mode for ** the file in "window". Returns a pointer to a string, which will ** remain valid until a change is made to the language modes list. */ static int matchLanguageMode(WindowInfo *window) { char *ext, *first200; int i, j, fileNameLen, extLen, beginPos, endPos, start; const char *versionExtendedPath; /*... look for an explicit mode statement first */ /* Do a regular expression search on for recognition pattern */ first200 = BufGetRange(window->buffer, 0, 200); for (i=0; irecognitionExpr != NULL) { if (SearchString(first200, LanguageModes[i]->recognitionExpr, SEARCH_FORWARD, SEARCH_REGEX, False, 0, &beginPos, &endPos, NULL, NULL, NULL)) { XtFree(first200); return i; } } } XtFree(first200); /* Look at file extension ("@@/" starts a ClearCase version extended path, which gets appended after the file extension, and therefore must be stripped off to recognize the extension to make ClearCase users happy) */ fileNameLen = strlen(window->filename); #ifdef VMS if (strchr(window->filename, ';') != NULL) fileNameLen = strchr(window->filename, ';') - window->filename; #else if ((versionExtendedPath = GetClearCaseVersionExtendedPath(window->filename)) != NULL) fileNameLen = versionExtendedPath - window->filename; #endif for (i=0; inExtensions; j++) { ext = LanguageModes[i]->extensions[j]; extLen = strlen(ext); start = fileNameLen - extLen; #if defined(__VMS) && (__VMS_VER >= 70200000) /* VMS v7.2 has case-preserving filenames */ if (start >= 0 && !strncasecmp(&window->filename[start], ext, extLen)) return i; #else if (start >= 0 && !strncmp(&window->filename[start], ext, extLen)) return i; #endif } } /* no appropriate mode was found */ return PLAIN_LANGUAGE_MODE; } static int loadLanguageModesString(char *inString, int fileVer) { char *errMsg, *styleName, *inPtr = inString; languageModeRec *lm; int i; for (;;) { /* skip over blank space */ inPtr += strspn(inPtr, " \t\n"); /* Allocate a language mode structure to return, set unread fields to empty so everything can be freed on errors by freeLanguageModeRec */ lm = (languageModeRec *)XtMalloc(sizeof(languageModeRec)); lm->nExtensions = 0; lm->recognitionExpr = NULL; lm->defTipsFile = NULL; lm->delimiters = NULL; /* read language mode name */ lm->name = ReadSymbolicField(&inPtr); if (lm->name == NULL) { XtFree((char *)lm); return modeError(NULL,inString,inPtr,"language mode name required"); } if (!SkipDelimiter(&inPtr, &errMsg)) return modeError(lm, inString, inPtr, errMsg); /* read list of extensions */ lm->extensions = readExtensionList(&inPtr, &lm->nExtensions); if (!SkipDelimiter(&inPtr, &errMsg)) return modeError(lm, inString, inPtr, errMsg); /* read the recognition regular expression */ if (*inPtr == '\n' || *inPtr == '\0' || *inPtr == ':') lm->recognitionExpr = NULL; else if (!ReadQuotedString(&inPtr, &errMsg, &lm->recognitionExpr)) return modeError(lm, inString,inPtr, errMsg); if (!SkipDelimiter(&inPtr, &errMsg)) return modeError(lm, inString, inPtr, errMsg); /* read the indent style */ styleName = ReadSymbolicField(&inPtr); if (styleName == NULL) lm->indentStyle = DEFAULT_INDENT; else { for (i=0; iindentStyle = i; break; } } XtFree(styleName); if (i == N_INDENT_STYLES) return modeError(lm,inString,inPtr,"unrecognized indent style"); } if (!SkipDelimiter(&inPtr, &errMsg)) return modeError(lm, inString, inPtr, errMsg); /* read the wrap style */ styleName = ReadSymbolicField(&inPtr); if (styleName == NULL) lm->wrapStyle = DEFAULT_WRAP; else { for (i=0; iwrapStyle = i; break; } } XtFree(styleName); if (i == N_WRAP_STYLES) return modeError(lm, inString, inPtr,"unrecognized wrap style"); } if (!SkipDelimiter(&inPtr, &errMsg)) return modeError(lm, inString, inPtr, errMsg); /* read the tab distance */ if (*inPtr == '\n' || *inPtr == '\0' || *inPtr == ':') lm->tabDist = DEFAULT_TAB_DIST; else if (!ReadNumericField(&inPtr, &lm->tabDist)) return modeError(lm, inString, inPtr, "bad tab spacing"); if (!SkipDelimiter(&inPtr, &errMsg)) return modeError(lm, inString, inPtr, errMsg); /* read emulated tab distance */ if (*inPtr == '\n' || *inPtr == '\0' || *inPtr == ':') lm->emTabDist = DEFAULT_EM_TAB_DIST; else if (!ReadNumericField(&inPtr, &lm->emTabDist)) return modeError(lm, inString, inPtr, "bad emulated tab spacing"); if (!SkipDelimiter(&inPtr, &errMsg)) return modeError(lm, inString, inPtr, errMsg); /* read the delimiters string */ if (*inPtr == '\n' || *inPtr == '\0' || *inPtr == ':') lm->delimiters = NULL; else if (!ReadQuotedString(&inPtr, &errMsg, &lm->delimiters)) return modeError(lm, inString, inPtr, errMsg); /* After 5.3 all language modes need a default tips file field */ if (!SkipDelimiter(&inPtr, &errMsg)) if (fileVer > 5003) return modeError(lm, inString, inPtr, errMsg); /* read the default tips file */ if (*inPtr == '\n' || *inPtr == '\0') lm->defTipsFile = NULL; else if (!ReadQuotedString(&inPtr, &errMsg, &lm->defTipsFile)) return modeError(lm, inString, inPtr, errMsg); /* pattern set was read correctly, add/replace it in the list */ for (i=0; iname, lm->name)) { freeLanguageModeRec(LanguageModes[i]); LanguageModes[i] = lm; break; } } if (i == NLanguageModes) { LanguageModes[NLanguageModes++] = lm; if (NLanguageModes > MAX_LANGUAGE_MODES) return modeError(NULL, inString, inPtr, "maximum allowable number of language modes exceeded"); } /* if the string ends here, we're done */ inPtr += strspn(inPtr, " \t\n"); if (*inPtr == '\0') return True; } /* End for(;;) */ } static char *writeLanguageModesString(void) { int i; char *outStr, *escapedStr, *str, numBuf[25]; textBuffer *outBuf; outBuf = BufCreate(); for (i=0; ilength, "\t"); BufInsert(outBuf, outBuf->length, LanguageModes[i]->name); BufInsert(outBuf, outBuf->length, ":"); BufInsert(outBuf, outBuf->length, str = createExtString( LanguageModes[i]->extensions, LanguageModes[i]->nExtensions)); XtFree(str); BufInsert(outBuf, outBuf->length, ":"); if (LanguageModes[i]->recognitionExpr != NULL) { BufInsert(outBuf, outBuf->length, str=MakeQuotedString(LanguageModes[i]->recognitionExpr)); XtFree(str); } BufInsert(outBuf, outBuf->length, ":"); if (LanguageModes[i]->indentStyle != DEFAULT_INDENT) BufInsert(outBuf, outBuf->length, AutoIndentTypes[LanguageModes[i]->indentStyle]); BufInsert(outBuf, outBuf->length, ":"); if (LanguageModes[i]->wrapStyle != DEFAULT_WRAP) BufInsert(outBuf, outBuf->length, AutoWrapTypes[LanguageModes[i]->wrapStyle]); BufInsert(outBuf, outBuf->length, ":"); if (LanguageModes[i]->tabDist != DEFAULT_TAB_DIST) { sprintf(numBuf, "%d", LanguageModes[i]->tabDist); BufInsert(outBuf, outBuf->length, numBuf); } BufInsert(outBuf, outBuf->length, ":"); if (LanguageModes[i]->emTabDist != DEFAULT_EM_TAB_DIST) { sprintf(numBuf, "%d", LanguageModes[i]->emTabDist); BufInsert(outBuf, outBuf->length, numBuf); } BufInsert(outBuf, outBuf->length, ":"); if (LanguageModes[i]->delimiters != NULL) { BufInsert(outBuf, outBuf->length, str=MakeQuotedString(LanguageModes[i]->delimiters)); XtFree(str); } BufInsert(outBuf, outBuf->length, ":"); if (LanguageModes[i]->defTipsFile != NULL) { BufInsert(outBuf, outBuf->length, str=MakeQuotedString(LanguageModes[i]->defTipsFile)); XtFree(str); } BufInsert(outBuf, outBuf->length, "\n"); } /* Get the output, and lop off the trailing newline */ outStr = BufGetRange(outBuf, 0, outBuf->length - 1); BufFree(outBuf); escapedStr = EscapeSensitiveChars(outStr); XtFree(outStr); return escapedStr; } static char *createExtString(char **extensions, int nExtensions) { int e, length = 1; char *outStr, *outPtr; for (e=0; e outStr && *(outPtr-1) == ' ') outPtr--; if (outPtr == outStr) { XtFree(outStr); return NULL; } *outPtr = '\0'; return outStr; } /* ** parse an individual quoted string. Anything between ** double quotes is acceptable, quote characters can be escaped by "". ** Returns allocated string "string" containing ** argument minus quotes. If not successful, returns False with ** (statically allocated) message in "errMsg". */ int ReadQuotedString(char **inPtr, char **errMsg, char **string) { char *outPtr, *c; /* skip over blank space */ *inPtr += strspn(*inPtr, " \t"); /* look for initial quote */ if (**inPtr != '\"') { *errMsg = "expecting quoted string"; return False; } (*inPtr)++; /* calculate max length and allocate returned string */ for (c= *inPtr; ; c++) { if (*c == '\0') { *errMsg = "string not terminated"; return False; } else if (*c == '\"') { if (*(c+1) == '\"') c++; else break; } } /* copy string up to end quote, transforming escaped quotes into quotes */ *string = XtMalloc(c - *inPtr + 1); outPtr = *string; while (True) { if (**inPtr == '\"') { if (*(*inPtr+1) == '\"') (*inPtr)++; else break; } *outPtr++ = *(*inPtr)++; } *outPtr = '\0'; /* skip end quote */ (*inPtr)++; return True; } /* ** Replace characters which the X resource file reader considers control ** characters, such that a string will read back as it appears in "string". ** (So far, newline characters are replaced with with \n\ and ** backslashes with \\. This has not been tested exhaustively, and ** probably should be. It would certainly be more asthetic if other ** control characters were replaced as well). ** ** Returns an allocated string which must be freed by the caller with XtFree. */ char *EscapeSensitiveChars(const char *string) { const char *c; char *outStr, *outPtr; int length = 0; /* calculate length and allocate returned string */ for (c=string; *c!='\0'; c++) { if (*c == '\\') length++; else if (*c == '\n') length += 3; length++; } outStr = XtMalloc(length + 1); outPtr = outStr; /* add backslashes */ for (c=string; *c!='\0'; c++) { if (*c == '\\') *outPtr++ = '\\'; else if (*c == '\n') { *outPtr++ = '\\'; *outPtr++ = 'n'; *outPtr++ = '\\'; } *outPtr++ = *c; } *outPtr = '\0'; return outStr; } /* ** Adds double quotes around a string and escape existing double quote ** characters with two double quotes. Enables the string to be read back ** by ReadQuotedString. */ char *MakeQuotedString(const char *string) { const char *c; char *outStr, *outPtr; int length = 0; /* calculate length and allocate returned string */ for (c=string; *c!='\0'; c++) { if (*c == '\"') length++; length++; } outStr = XtMalloc(length + 3); outPtr = outStr; /* add starting quote */ *outPtr++ = '\"'; /* copy string, escaping quotes with "" */ for (c=string; *c!='\0'; c++) { if (*c == '\"') *outPtr++ = '\"'; *outPtr++ = *c; } /* add ending quote */ *outPtr++ = '\"'; /* terminate string and return */ *outPtr = '\0'; return outStr; } /* ** Read a dialog text field containing a symbolic name (language mode names, ** style names, highlight pattern names, colors, and fonts), clean the ** entered text of leading and trailing whitespace, compress all ** internal whitespace to one space character, and check it over for ** colons, which interfere with the preferences file reader/writer syntax. ** Returns NULL on error, and puts up a dialog if silent is False. Returns ** an empty string if the text field is blank. */ char *ReadSymbolicFieldTextWidget(Widget textW, const char *fieldName, int silent) { char *string, *stringPtr, *parsedString; /* read from the text widget */ string = stringPtr = XmTextGetString(textW); /* parse it with the same routine used to read symbolic fields from files. If the string is not read entirely, there are invalid characters, so warn the user if not in silent mode. */ parsedString = ReadSymbolicField(&stringPtr); if (*stringPtr != '\0') { if (!silent) { *(stringPtr + 1) = '\0'; DialogF(DF_WARN, textW, 1, "Invalid Character", "Invalid character \"%s\" in %s", "OK", stringPtr, fieldName); XmProcessTraversal(textW, XmTRAVERSE_CURRENT); } XtFree(string); XtFree(parsedString); return NULL; } XtFree(string); if (parsedString == NULL) { parsedString = XtMalloc(1); *parsedString = '\0'; } return parsedString; } /* ** Create a pulldown menu pane with the names of the current language modes. ** XmNuserData for each item contains the language mode name. */ Widget CreateLanguageModeMenu(Widget parent, XtCallbackProc cbProc, void *cbArg) { Widget menu, btn; int i; XmString s1; menu = CreatePulldownMenu(parent, "languageModes", NULL, 0); for (i=0; iname), XmNmarginHeight, 0, XmNuserData, (void *)LanguageModes[i]->name, NULL); XmStringFree(s1); XtAddCallback(btn, XmNactivateCallback, cbProc, cbArg); } return menu; } /* ** Set the language mode menu in option menu "optMenu" to ** show a particular language mode */ void SetLangModeMenu(Widget optMenu, const char *modeName) { int i; Cardinal nItems; WidgetList items; Widget pulldown, selectedItem; char *itemName; XtVaGetValues(optMenu, XmNsubMenuId, &pulldown, NULL); XtVaGetValues(pulldown, XmNchildren, &items, XmNnumChildren, &nItems, NULL); if (nItems == 0) return; selectedItem = items[0]; for (i=0; i<(int)nItems; i++) { XtVaGetValues(items[i], XmNuserData, &itemName, NULL); if (!strcmp(itemName, modeName)) { selectedItem = items[i]; break; } } XtVaSetValues(optMenu, XmNmenuHistory, selectedItem,NULL); } /* ** Create a submenu for chosing language mode for the current window. */ void CreateLanguageModeSubMenu(WindowInfo* window, const Widget parent, const char* name, const char* label, const char mnemonic) { XmString string = XmStringCreateSimple((char*) label); window->langModeCascade = XtVaCreateManagedWidget(name, xmCascadeButtonGadgetClass, parent, XmNlabelString, string, XmNmnemonic, mnemonic, XmNsubMenuId, NULL, NULL); XmStringFree(string); updateLanguageModeSubmenu(window); } /* ** Re-build the language mode sub-menu using the current data stored ** in the master list: LanguageModes. */ static void updateLanguageModeSubmenu(WindowInfo *window) { int i; XmString s1; Widget menu, btn; Arg args[1] = {{XmNradioBehavior, (XtArgVal)True}}; /* Destroy and re-create the menu pane */ XtVaGetValues(window->langModeCascade, XmNsubMenuId, &menu, NULL); if (menu != NULL) XtDestroyWidget(menu); menu = CreatePulldownMenu(XtParent(window->langModeCascade), "languageModes", args, 1); btn = XtVaCreateManagedWidget("languageMode", xmToggleButtonGadgetClass, menu, XmNlabelString, s1=XmStringCreateSimple("Plain"), XmNuserData, (void *)PLAIN_LANGUAGE_MODE, XmNset, window->languageMode==PLAIN_LANGUAGE_MODE, NULL); XmStringFree(s1); XtAddCallback(btn, XmNvalueChangedCallback, setLangModeCB, window); for (i=0; iname), XmNmarginHeight, 0, XmNuserData, (void *)i, XmNset, window->languageMode==i, NULL); XmStringFree(s1); XtAddCallback(btn, XmNvalueChangedCallback, setLangModeCB, window); } XtVaSetValues(window->langModeCascade, XmNsubMenuId, menu, NULL); } static void setLangModeCB(Widget w, XtPointer clientData, XtPointer callData) { WindowInfo *window = WidgetToWindow(MENU_WIDGET(w)); char *params[1]; void *mode; if (!XmToggleButtonGetState(w)) return; /* get name of language mode stored in userData field of menu item */ XtVaGetValues(w, XmNuserData, &mode, NULL); /* If the mode didn't change, do nothing */ if (window->languageMode == (int)mode) return; /* redo syntax highlighting word delimiters, etc. */ /* reapplyLanguageMode(window, (int)mode, False); */ params[0] = (((int)mode) == PLAIN_LANGUAGE_MODE) ? "" : LanguageModes[(int)mode]->name; XtCallActionProc(window->textArea, "set_language_mode", NULL, params, 1); } /* ** Skip a delimiter and it's surrounding whitespace */ int SkipDelimiter(char **inPtr, char **errMsg) { *inPtr += strspn(*inPtr, " \t"); if (**inPtr != ':') { *errMsg = "syntax error"; return False; } (*inPtr)++; *inPtr += strspn(*inPtr, " \t"); return True; } /* ** Skip an optional separator and its surrounding whitespace ** return true if delimiter found */ int SkipOptSeparator(char separator, char **inPtr) { *inPtr += strspn(*inPtr, " \t"); if (**inPtr != separator) { return False; } (*inPtr)++; *inPtr += strspn(*inPtr, " \t"); return True; } /* ** Short-hand error processing for language mode parsing errors, frees ** lm (if non-null), prints a formatted message explaining where the ** error is, and returns False; */ static int modeError(languageModeRec *lm, const char *stringStart, const char *stoppedAt, const char *message) { if (lm != NULL) freeLanguageModeRec(lm); return ParseError(NULL, stringStart, stoppedAt, "language mode specification", message); } /* ** Report parsing errors in resource strings or macros, formatted nicely so ** the user can tell where things became botched. Errors can be sent either ** to stderr, or displayed in a dialog. For stderr, pass toDialog as NULL. ** For a dialog, pass the dialog parent in toDialog. */ int ParseError(Widget toDialog, const char *stringStart, const char *stoppedAt, const char *errorIn, const char *message) { int len, nNonWhite = 0; const char *c; char *errorLine; for (c=stoppedAt; c>=stringStart; c--) { if (c == stringStart) break; else if (*c == '\n' && nNonWhite >= 5) break; else if (*c != ' ' && *c != '\t') nNonWhite++; } len = stoppedAt - c + (*stoppedAt == '\0' ? 0 : 1); errorLine = XtMalloc(len+4); strncpy(errorLine, c, len); errorLine[len++] = '<'; errorLine[len++] = '='; errorLine[len++] = '='; errorLine[len] = '\0'; if (toDialog == NULL) { fprintf(stderr, "NEdit: %s in %s:\n%s\n", message, errorIn, errorLine); } else { DialogF(DF_WARN, toDialog, 1, "Parse Error", "%s in %s:\n%s", "OK", message, errorIn, errorLine); } XtFree(errorLine); return False; } /* ** Compare two strings which may be NULL */ int AllocatedStringsDiffer(const char *s1, const char *s2) { if (s1 == NULL && s2 == NULL) return False; if (s1 == NULL || s2 == NULL) return True; return strcmp(s1, s2); } static void updatePatternsTo5dot1(void) { const char *htmlDefaultExpr = "^[ \t]*HTML[ \t]*:[ \t]*Default[ \t]*$"; const char *vhdlAnchorExpr = "^[ \t]*VHDL:"; /* Add new patterns if there aren't already existing patterns with the same name. If possible, insert before VHDL in language mode list. If not, just add to end */ if (!regexFind(TempStringPrefs.highlight, "^[ \t]*PostScript:")) spliceString(&TempStringPrefs.highlight, "PostScript:Default", vhdlAnchorExpr); if (!regexFind(TempStringPrefs.language, "^[ \t]*PostScript:")) spliceString(&TempStringPrefs.language, "PostScript:.ps .PS .eps .EPS .epsf .epsi::::::", vhdlAnchorExpr); if (!regexFind(TempStringPrefs.highlight, "^[ \t]*Lex:")) spliceString(&TempStringPrefs.highlight, "Lex:Default", vhdlAnchorExpr); if (!regexFind(TempStringPrefs.language, "^[ \t]*Lex:")) spliceString(&TempStringPrefs.language, "Lex:.lex::::::", vhdlAnchorExpr); if (!regexFind(TempStringPrefs.highlight, "^[ \t]*SQL:")) spliceString(&TempStringPrefs.highlight, "SQL:Default", vhdlAnchorExpr); if (!regexFind(TempStringPrefs.language, "^[ \t]*SQL:")) spliceString(&TempStringPrefs.language, "SQL:.sql::::::", vhdlAnchorExpr); if (!regexFind(TempStringPrefs.highlight, "^[ \t]*Matlab:")) spliceString(&TempStringPrefs.highlight, "Matlab:Default", vhdlAnchorExpr); if (!regexFind(TempStringPrefs.language, "^[ \t]*Matlab:")) spliceString(&TempStringPrefs.language, "Matlab:..m .oct .sci::::::", vhdlAnchorExpr); if (!regexFind(TempStringPrefs.smartIndent, "^[ \t]*Matlab:")) spliceString(&TempStringPrefs.smartIndent, "Matlab:Default", NULL); if (!regexFind(TempStringPrefs.styles, "^[ \t]*Label:")) spliceString(&TempStringPrefs.styles, "Label:red:Italic", "^[ \t]*Flag:"); if (!regexFind(TempStringPrefs.styles, "^[ \t]*Storage Type1:")) spliceString(&TempStringPrefs.styles, "Storage Type1:saddle brown:Bold", "^[ \t]*String:"); /* Replace html pattern with sgml html pattern, as long as there isn't an existing html pattern which will be overwritten */ if (regexFind(TempStringPrefs.highlight, htmlDefaultExpr)) { regexReplace(&TempStringPrefs.highlight, htmlDefaultExpr, "SGML HTML:Default"); if (!regexReplace(&TempStringPrefs.language, "^[ \t]*HTML:.*$", "SGML HTML:.sgml .sgm .html .htm:\"\\<(?ihtml)\\>\":::::\n")) { spliceString(&TempStringPrefs.language, "SGML HTML:.sgml .sgm .html .htm:\"\\<(?ihtml)\\>\":::::\n", vhdlAnchorExpr); } } } static void updatePatternsTo5dot2(void) { #ifdef VMS const char *cppLm5dot1 = "^[ \t]*C\\+\\+:\\.CC \\.HH \\.I::::::\"\\.,/\\\\`'!\\|@#%\\^&\\*\\(\\)-=\\+\\{\\}\\[\\]\"\":;\\<\\>\\?~\""; const char *perlLm5dot1 = "^[ \t]*Perl:\\.PL \\.PM \\.P5:\"\\^\\[ \\\\t\\]\\*#\\[ \\\\t\\]\\*!\\.\\*perl\":::::"; const char *psLm5dot1 = "^[ \t]*PostScript:\\.ps \\.PS \\.eps \\.EPS \\.epsf \\.epsi:\"\\^%!\":::::\"/%\\(\\)\\{\\}\\[\\]\\<\\>\""; const char *tclLm5dot1 = "^[ \t]*Tcl:\\.TCL::::::"; const char *cppLm5dot2 = "C++:.CC .HH .C .H .I .CXX .HXX .CPP::::::\".,/\\`'!|@#%^&*()-=+{}[]\"\":;<>?~\""; const char *perlLm5dot2 = "Perl:.PL .PM .P5:\"^[ \\t]*#[ \\t]*!.*perl\":Auto:None:::\".,/\\\\`'!$@#%^&*()-=+{}[]\"\":;<>?~|\""; const char *psLm5dot2 = "PostScript:.ps .PS .eps .EPS .epsf .epsi:\"^%!\":::::\"/%(){}[]<>\""; const char *tclLm5dot2 = "Tcl:.TCL::Smart:None:::"; #else const char *cppLm5dot1 = "^[ \t]*C\\+\\+:\\.cc \\.hh \\.C \\.H \\.i \\.cxx \\.hxx::::::\"\\.,/\\\\`'!\\|@#%\\^&\\*\\(\\)-=\\+\\{\\}\\[\\]\"\":;\\<\\>\\?~\""; const char *perlLm5dot1 = "^[ \t]*Perl:\\.pl \\.pm \\.p5:\"\\^\\[ \\\\t\\]\\*#\\[ \\\\t\\]\\*!\\.\\*perl\":::::"; const char *psLm5dot1 = "^[ \t]*PostScript:\\.ps \\.PS \\.eps \\.EPS \\.epsf \\.epsi:\"\\^%!\":::::\"/%\\(\\)\\{\\}\\[\\]\\<\\>\""; const char *shLm5dot1 = "^[ \t]*Sh Ksh Bash:\\.sh \\.bash \\.ksh \\.profile:\"\\^\\[ \\\\t\\]\\*#\\[ \\\\t\\]\\*!\\[ \\\\t\\]\\*/bin/\\(sh\\|ksh\\|bash\\)\":::::"; const char *tclLm5dot1 = "^[ \t]*Tcl:\\.tcl::::::"; const char *cppLm5dot2 = "C++:.cc .hh .C .H .i .cxx .hxx .cpp::::::\".,/\\`'!|@#%^&*()-=+{}[]\"\":;<>?~\""; const char *perlLm5dot2 = "Perl:.pl .pm .p5 .PL:\"^[ \\t]*#[ \\t]*!.*perl\":Auto:None:::\".,/\\\\`'!$@#%^&*()-=+{}[]\"\":;<>?~|\""; const char *psLm5dot2 = "PostScript:.ps .eps .epsf .epsi:\"^%!\":::::\"/%(){}[]<>\""; const char *shLm5dot2 = "Sh Ksh Bash:.sh .bash .ksh .profile .bashrc .bash_logout .bash_login .bash_profile:\"^[ \\t]*#[ \\t]*![ \\t]*/.*bin/(sh|ksh|bash)\":::::"; const char *tclLm5dot2 = "Tcl:.tcl .tk .itcl .itk::Smart:None:::"; #endif /* VMS */ const char *cssLm5dot2 = "CSS:css::Auto:None:::\".,/\\`'!|@#%^&*()=+{}[]\"\":;<>?~\""; const char *reLm5dot2 = "Regex:.reg .regex:\"\\(\\?[:#=!iInN].+\\)\":None:Continuous:::"; const char *xmlLm5dot2 = "XML:.xml .xsl .dtd:\"\\<(?i\\?xml|!doctype)\"::None:::\"<>/=\"\"'()+*?|\""; const char *cssHl5dot2 = "CSS:Default"; const char *reHl5dot2 = "Regex:Default"; const char *xmlHl5dot2 = "XML:Default"; const char *ptrStyle = "Pointer:#660000:Bold"; const char *reStyle = "Regex:#009944:Bold"; const char *wrnStyle = "Warning:brown2:Italic"; /* First upgrade modified language modes, only if the user hasn't altered the default 5.1 definitions. */ if (regexFind(TempStringPrefs.language, cppLm5dot1)) regexReplace(&TempStringPrefs.language, cppLm5dot1, cppLm5dot2); if (regexFind(TempStringPrefs.language, perlLm5dot1)) regexReplace(&TempStringPrefs.language, perlLm5dot1, perlLm5dot2); if (regexFind(TempStringPrefs.language, psLm5dot1)) regexReplace(&TempStringPrefs.language, psLm5dot1, psLm5dot2); #ifndef VMS if (regexFind(TempStringPrefs.language, shLm5dot1)) regexReplace(&TempStringPrefs.language, shLm5dot1, shLm5dot2); #endif if (regexFind(TempStringPrefs.language, tclLm5dot1)) regexReplace(&TempStringPrefs.language, tclLm5dot1, tclLm5dot2); /* Then append the new modes (trying to keep them in alphabetical order makes no sense, since 5.1 didn't use alphabetical order). */ if (!regexFind(TempStringPrefs.language, "^[ \t]*CSS:")) spliceString(&TempStringPrefs.language, cssLm5dot2, NULL); if (!regexFind(TempStringPrefs.language, "^[ \t]*Regex:")) spliceString(&TempStringPrefs.language, reLm5dot2, NULL); if (!regexFind(TempStringPrefs.language, "^[ \t]*XML:")) spliceString(&TempStringPrefs.language, xmlLm5dot2, NULL); /* Enable default highlighting patterns for these modes, unless already present */ if (!regexFind(TempStringPrefs.highlight, "^[ \t]*CSS:")) spliceString(&TempStringPrefs.highlight, cssHl5dot2, NULL); if (!regexFind(TempStringPrefs.highlight, "^[ \t]*Regex:")) spliceString(&TempStringPrefs.highlight, reHl5dot2, NULL); if (!regexFind(TempStringPrefs.highlight, "^[ \t]*XML:")) spliceString(&TempStringPrefs.highlight, xmlHl5dot2, NULL); /* Finally, append the new highlight styles */ if (!regexFind(TempStringPrefs.styles, "^[ \t]*Warning:")) spliceString(&TempStringPrefs.styles, wrnStyle, NULL); if (!regexFind(TempStringPrefs.styles, "^[ \t]*Regex:")) spliceString(&TempStringPrefs.styles, reStyle, "^[ \t]*Warning:"); if (!regexFind(TempStringPrefs.styles, "^[ \t]*Pointer:")) spliceString(&TempStringPrefs.styles, ptrStyle, "^[ \t]*Regex:"); } static void updatePatternsTo5dot3(void) { /* This is a bogus function on non-VMS */ #ifdef VMS const char *psLm5dot2 = "^[ \t]*PostScript:\\.ps \\.PS \\.eps \\.EPS \\.epsf \\.epsi:\"\\^%!\":::::\"/%\\(\\)\\{\\}\\[\\]\\<\\>\""; const char *psLm5dot3 = "PostScript:.ps .PS .eps .EPS .epsf .EPSF .epsi .EPSI:\"^%!\":::::\"/%(){}[]<>\""; /* Upgrade modified language modes, only if the user hasn't altered the default 5.2 definitions. */ if (regexFind(TempStringPrefs.language, psLm5dot2)) regexReplace(&TempStringPrefs.language, psLm5dot2, psLm5dot3); #endif } static void updatePatternsTo5dot4(void) { #ifdef VMS const char *pyLm5dot3 = "Python:\\.PY:\"\\^#!\\.\\*python\":Auto:None::::?\n"; const char *xrLm5dot3 = "X Resources:\\.XRESOURCES \\.XDEFAULTS \\.NEDIT:\"\\^\\[!#\\]\\.\\*\\(\\[Aa\\]pp\\|\\[Xx\\]\\)\\.\\*\\[Dd\\]efaults\"::::::?\n"; const char *pyLm5dot4 = "Python:.PY:\"^#!.*python\":Auto:None:::\"!\"\"#$%&'()*+,-./:;<=>?@[\\\\]^`{|}~\":\n"; const char *xrLm5dot4 = "X Resources:.XRESOURCES .XDEFAULTS .NEDIT NEDIT.RC:\"^[!#].*([Aa]pp|[Xx]).*[Dd]efaults\"::::::\n"; #else const char *pyLm5dot3 = "Python:\\.py:\"\\^#!\\.\\*python\":Auto:None::::?\n"; const char *xrLm5dot3 = "X Resources:\\.Xresources \\.Xdefaults \\.nedit:\"\\^\\[!#\\]\\.\\*\\(\\[Aa\\]pp\\|\\[Xx\\]\\)\\.\\*\\[Dd\\]efaults\"::::::?\n"; const char *pyLm5dot4 = "Python:.py:\"^#!.*python\":Auto:None:::\"!\"\"#$%&'()*+,-./:;<=>?@[\\\\]^`{|}~\":\n"; const char *xrLm5dot4 = "X Resources:.Xresources .Xdefaults .nedit nedit.rc:\"^[!#].*([Aa]pp|[Xx]).*[Dd]efaults\"::::::\n"; #endif /* Upgrade modified language modes, only if the user hasn't altered the default 5.3 definitions. */ if (regexFind(TempStringPrefs.language, pyLm5dot3)) regexReplace(&TempStringPrefs.language, pyLm5dot3, pyLm5dot4); if (regexFind(TempStringPrefs.language, xrLm5dot3)) regexReplace(&TempStringPrefs.language, xrLm5dot3, xrLm5dot4); /* Add new styles */ if (!regexFind(TempStringPrefs.styles, "^[ \t]*Identifier2:")) spliceString(&TempStringPrefs.styles, "Identifier2:SteelBlue:Plain", "^[ \t]*Subroutine:"); } static void updatePatternsTo5dot6(void) { const char *pats[] = { #ifndef VMS "Csh:\\.csh \\.cshrc \\.login \\.logout:\"\\^\\[ \\\\t\\]\\*#\\[ \\\\t\\]\\*!\\[ \\\\t\\]\\*/bin/csh\"::::::\\n", "Csh:.csh .cshrc .tcshrc .login .logout:\"^[ \\t]*#[ \\t]*![ \\t]*/bin/t?csh\"::::::\n", "LaTeX:\\.tex \\.sty \\.cls \\.ltx \\.ins:::::::\\n", "LaTeX:.tex .sty .cls .ltx .ins .clo .fd:::::::\n", "X Resources:\\.Xresources \\.Xdefaults \\.nedit:\"\\^\\[!#\\]\\.\\*\\(\\[Aa\\]pp\\|\\[Xx\\]\\)\\.\\*\\[Dd\\]efaults\"::::::\\n", "X Resources:.Xresources .Xdefaults .nedit .pats nedit.rc:\"^[!#].*([Aa]pp|[Xx]).*[Dd]efaults\"::::::\n", #else "Csh:\\.csh \\.cshrc \\.login \\.logout:\"\\^\\[ \\\\t\\]\\*#\\[ \\\\t\\]\\*!\\[ \\\\t\\]\\*/bin/csh\"::::::\\n", "Csh:.CSH .CSHRC .TCSHRC .LOGIN .LOGOUT:\"^[ \\t]*#[ \\t]*![ \\t]*/bin/t?csh\"::::::\n", "LaTeX:\\.TEX \\.STY \\.CLS \\.LTX \\.INS:::::::\\n", "LaTeX:.TEX .STY .CLS .LTX .INS .CLO .FD:::::::\n", "Lex:\\.lex:::::::\\n", "Lex:.LEX:::::::\n", "Matlab:\\.m \\.oct \\.sci:::::::\\n", "Matlab:.M .OCT .SCI:::::::\n", "Regex:\\.reg \\.regex:\"\\\\\\(\\\\\\?\\[:#=!iInN\\]\\.\\+\\\\\\\)\":None:Continuous::::\\n", "Regex:.REG .REGEX:\"\\(\\?[:#=!iInN].+\\)\":None:Continuous::::\n", "SGML HTML:\\.sgml \\.sgm \\.html \\.htm:\"\\\\\\<\\[Hh\\]\\[Tt\\]\\[Mm\\]\\[Ll\\]\\\\\\>\"::::::\\n", "SGML HTML:.SGML .SGM .HTML .HTM:\"\\<[Hh][Tt][Mm][Ll]\\>\"::::::\n", "SQL:\\.sql:::::::\\n", "SQL:.SQL:::::::\n", "Sh Ksh Bash:\\.sh \\.bash \\.ksh \\.profile \\.bashrc \\.bash_logout \\.bash_login \\.bash_profile:\"\\^\\[ \\\\t\\]\\*#\\[ \\\\t\\]\\*!\\[ \\\\t\\]\\*/\\.\\*bin/\\(bash\\|ksh\\|sh\\|zsh\\)\"::::::\\n", "Sh Ksh Bash:.SH .BASH .KSH .PROFILE .BASHRC .BASH_LOGOUT .BASH_LOGIN .BASH_PROFILE:\"^[ \\t]*#[ \\t]*![ \\t]*/.*bin/(bash|ksh|sh|zsh)\"::::::\n", "XML:\\.xml \\.xsl \\.dtd:\"\\\\\\<\\(\\?i\\\\\\?xml\\|!doctype\\)\"::None:::\"\\<\\>/=\"\"'\\(\\)\\+\\*\\?\\|\":\\n", "XML:.XML .XSL .DTD:\"\\<(?i\\?xml|!doctype)\"::None:::\"<>/=\"\"'()+*?|\":\n", "X Resources:\\.XRESOURCES \\.XDEFAULTS \\.NEDIT:\"\\^\\[!#\\]\\.\\*\\(\\[Aa\\]pp\\|\\[Xx\\]\\)\\.\\*\\[Dd\\]efaults\"::::::\\n", "X Resources:.XRESOURCES .XDEFAULTS .NEDIT .PATS NEDIT.RC:\"^[!#].*([Aa]pp|[Xx]).*[Dd]efaults\"::::::\n", #endif NULL }; /* Upgrade modified language modes, only if the user hasn't altered the default 5.5 definitions. */ int i; for (i = 0; pats[i]; i+=2) { if (regexFind(TempStringPrefs.language, pats[i])) regexReplace(&TempStringPrefs.language, pats[i], pats[i+1]); } /* Add new styles */ if (!regexFind(TempStringPrefs.styles, "^[ \t]*Bracket:")) spliceString(&TempStringPrefs.styles, "Bracket:dark blue:Bold", "^[ \t]*Storage Type:"); if (!regexFind(TempStringPrefs.styles, "^[ \t]*Operator:")) spliceString(&TempStringPrefs.styles, "Operator:dark blue:Bold", "^[ \t]*Bracket:"); } /* * We migrate a color from the X resources to the prefs if: * 1. The prefs entry is equal to the default entry * 2. The X resource is not equal to the default entry */ static void migrateColor(XrmDatabase prefDB, XrmDatabase appDB, char *class, char *name, int color_index, char *default_val) { char *type, *valueString; XrmValue rsrcValue; /* If this color has been customized in the color dialog then use that value */ if ( strcmp(default_val, PrefData.colorNames[color_index]) ) return; /* Retrieve the value of the resource from the DB */ if (XrmGetResource(prefDB, name, class, &type, &rsrcValue)) { if (strcmp(type, XmRString)) { fprintf(stderr,"Internal Error: Unexpected resource type, %s\n", type); return; } valueString = rsrcValue.addr; } else if (XrmGetResource(appDB, name, class, &type, &rsrcValue)) { if (strcmp(type, XmRString)) { fprintf(stderr,"Internal Error: Unexpected resource type, %s\n", type); return; } valueString = rsrcValue.addr; } else /* No resources set */ return; /* An X resource is set. If it's non-default, update the prefs. */ if ( strcmp(valueString, default_val) ) { strncpy(PrefData.colorNames[color_index], valueString, MAX_COLOR_LEN); } } /* * In 5.4 we moved color preferences from X resources to a color dialog, * meaning they're in the normal prefs system. Users who have customized * their colors with X resources would probably prefer not to have to redo * the customization in the dialog, so we migrate them to the prefs for them. */ static void migrateColorResources(XrmDatabase prefDB, XrmDatabase appDB) { migrateColor(prefDB, appDB, APP_CLASS ".Text.Foreground", APP_NAME ".text.foreground", TEXT_FG_COLOR, NEDIT_DEFAULT_FG); migrateColor(prefDB, appDB, APP_CLASS ".Text.Background", APP_NAME ".text.background", TEXT_BG_COLOR, NEDIT_DEFAULT_TEXT_BG); migrateColor(prefDB, appDB, APP_CLASS ".Text.SelectForeground", APP_NAME ".text.selectForeground", SELECT_FG_COLOR, NEDIT_DEFAULT_SEL_FG); migrateColor(prefDB, appDB, APP_CLASS ".Text.SelectBackground", APP_NAME ".text.selectBackground", SELECT_BG_COLOR, NEDIT_DEFAULT_SEL_BG); migrateColor(prefDB, appDB, APP_CLASS ".Text.HighlightForeground", APP_NAME ".text.highlightForeground", HILITE_FG_COLOR, NEDIT_DEFAULT_HI_FG); migrateColor(prefDB, appDB, APP_CLASS ".Text.HighlightBackground", APP_NAME ".text.highlightBackground", HILITE_BG_COLOR, NEDIT_DEFAULT_HI_BG); migrateColor(prefDB, appDB, APP_CLASS ".Text.LineNumForeground", APP_NAME ".text.lineNumForeground", LINENO_FG_COLOR, NEDIT_DEFAULT_LINENO_FG); migrateColor(prefDB, appDB, APP_CLASS ".Text.CursorForeground", APP_NAME ".text.cursorForeground", CURSOR_FG_COLOR, NEDIT_DEFAULT_CURSOR_FG); } /* ** Inserts a string into intoString, reallocating it with XtMalloc. If ** regular expression atExpr is found, inserts the string before atExpr ** followed by a newline. If atExpr is not found, inserts insertString ** at the end, PRECEDED by a newline. */ static void spliceString(char **intoString, const char *insertString, const char *atExpr) { int beginPos, endPos; int intoLen = strlen(*intoString); int insertLen = strlen(insertString); char *newString = XtMalloc(intoLen + insertLen + 2); if (atExpr != NULL && SearchString(*intoString, atExpr, SEARCH_FORWARD, SEARCH_REGEX, False, 0, &beginPos, &endPos, NULL, NULL, NULL)) { strncpy(newString, *intoString, beginPos); strncpy(&newString[beginPos], insertString, insertLen); newString[beginPos+insertLen] = '\n'; strncpy(&newString[beginPos+insertLen+1], &((*intoString)[beginPos]), intoLen - beginPos); } else { strncpy(newString, *intoString, intoLen); newString[intoLen] = '\n'; strncpy(&newString[intoLen+1], insertString, insertLen); } newString[intoLen + insertLen + 1] = '\0'; XtFree(*intoString); *intoString = newString; } /* ** Simplified regular expression search routine which just returns true ** or false depending on whether inString matches expr */ static int regexFind(const char *inString, const char *expr) { int beginPos, endPos; return SearchString(inString, expr, SEARCH_FORWARD, SEARCH_REGEX, False, 0, &beginPos, &endPos, NULL, NULL, NULL); } /* ** Simplified case-sensisitive string search routine which just ** returns true or false depending on whether inString matches expr */ static int caseFind(const char *inString, const char *expr) { int beginPos, endPos; return SearchString(inString, expr, SEARCH_FORWARD, SEARCH_CASE_SENSE, False, 0, &beginPos, &endPos, NULL, NULL, NULL); } /* ** Common implementation for simplified string replacement routines. */ static int stringReplace(char **inString, const char *expr, const char *replaceWith, int searchType, int replaceLen) { int beginPos, endPos, newLen; char *newString; int inLen = strlen(*inString); if (0 >= replaceLen) replaceLen = strlen(replaceWith); if (!SearchString(*inString, expr, SEARCH_FORWARD, searchType, False, 0, &beginPos, &endPos, NULL, NULL, NULL)) return FALSE; newLen = inLen + replaceLen - (endPos-beginPos); newString = XtMalloc(newLen + 1); strncpy(newString, *inString, beginPos); strncpy(&newString[beginPos], replaceWith, replaceLen); strncpy(&newString[beginPos+replaceLen], &((*inString)[endPos]), inLen - endPos); newString[newLen] = '\0'; XtFree(*inString); *inString = newString; return TRUE; } /* ** Simplified regular expression replacement routine which replaces the ** first occurence of expr in inString with replaceWith, reallocating ** inString with XtMalloc. If expr is not found, does nothing and ** returns false. */ static int regexReplace(char **inString, const char *expr, const char *replaceWith) { return stringReplace(inString, expr, replaceWith, SEARCH_REGEX, -1); } /* ** Simplified case-sensisitive string replacement routine which ** replaces the first occurence of expr in inString with replaceWith, ** reallocating inString with XtMalloc. If expr is not found, does nothing ** and returns false. */ static int caseReplace(char **inString, const char *expr, const char *replaceWith, int replaceLen) { return stringReplace(inString, expr, replaceWith, SEARCH_CASE_SENSE, replaceLen); } /* ** Looks for a (case-sensitive literal) match of an old macro text in a ** temporary macro commands buffer. If the text is found, it is replaced by ** a substring of the default macros, bounded by a given start and end pattern ** (inclusive). Returns the length of the replacement. */ static int replaceMacroIfUnchanged(const char* oldText, const char* newStart, const char* newEnd) { if (caseFind(TempStringPrefs.macroCmds, oldText)) { #ifdef VMS const char *start = strstr(PrefDescrip[1].defaultString, newStart); #else const char *start = strstr(PrefDescrip[2].defaultString, newStart); #endif if (start) { const char *end = strstr(start, newEnd); if (end) { int length = (int)(end-start) + strlen(newEnd); caseReplace(&TempStringPrefs.macroCmds, oldText, start, length); return length; } } } return 0; } #ifndef VMS /* ** Replace all '#' characters in shell commands by '##' to keep commands ** containing those working. '#' is a line number placeholder in 5.3 and ** had no special meaning before. */ static void updateShellCmdsTo5dot3(void) { char *cOld, *cNew, *pCol, *pNL; int nHash, isCmd; char *newString; if(!TempStringPrefs.shellCmds) return; /* Count number of '#'. If there are '#' characters in the non-command ** part of the definition we count too much and later allocate too much ** memory for the new string, but this doesn't hurt. */ for(cOld=TempStringPrefs.shellCmds, nHash=0; *cOld; cOld++) if(*cOld == '#') nHash++; /* No '#' -> no conversion necessary. */ if(!nHash) return; newString=XtMalloc(strlen(TempStringPrefs.shellCmds) + 1 + nHash); cOld = TempStringPrefs.shellCmds; cNew = newString; isCmd = 0; pCol = NULL; pNL = NULL; /* Copy all characters from TempStringPrefs.shellCmds into newString ** and duplicate '#' in command parts. A simple check for really beeing ** inside a command part (starting with '\n', between the the two last ** '\n' a colon ':' must have been found) is preformed. */ while(*cOld) { /* actually every 2nd line is a command. We additionally ** check if there is a colon ':' in the previous line. */ if(*cOld=='\n') { if((pCol > pNL) && !isCmd) isCmd=1; else isCmd=0; pNL=cOld; } if(!isCmd && *cOld ==':') pCol = cOld; /* Duplicate hashes if we're in a command part */ if(isCmd && *cOld=='#') *cNew++ = '#'; /* Copy every character */ *cNew++ = *cOld++; } /* Terminate new preferences string */ *cNew = 0; /* free the old memory */ XtFree(TempStringPrefs.shellCmds); /* exchange the string */ TempStringPrefs.shellCmds = newString; } #else static void updateShellCmdsTo5dot3(void) { /* No shell commands in VMS ! */ return; } #endif static void updateShellCmdsTo5dot4(void) { #ifndef VMS /* No shell commands on VMS */ #ifdef __FreeBSD__ const char* wc5dot3 = "^(\\s*)set wc=`wc`; echo \\$wc\\[1\\] \"words,\" \\$wc\\[2\\] \"lines,\" \\$wc\\[3\\] \"characters\"\\n"; const char* wc5dot4 = "wc | awk '{print $2 \" lines, \" $1 \" words, \" $3 \" characters\"}'\n"; #else const char* wc5dot3 = "^(\\s*)set wc=`wc`; echo \\$wc\\[1\\] \"lines,\" \\$wc\\[2\\] \"words,\" \\$wc\\[3\\] \"characters\"\\n"; const char* wc5dot4 = "wc | awk '{print $1 \" lines, \" $2 \" words, \" $3 \" characters\"}'\n"; #endif /* __FreeBSD__ */ if (regexFind(TempStringPrefs.shellCmds, wc5dot3)) regexReplace(&TempStringPrefs.shellCmds, wc5dot3, wc5dot4); #endif /* VMS */ return; } static void updateMacroCmdsTo5dot5(void) { const char* uc5dot4 = "^(\\s*)if \\(substring\\(sel, keepEnd - 1, keepEnd == \" \"\\)\\)\\n"; const char* uc5dot5 = " if (substring(sel, keepEnd - 1, keepEnd) == \" \")\n"; if (regexFind(TempStringPrefs.macroCmds, uc5dot4)) regexReplace(&TempStringPrefs.macroCmds, uc5dot4, uc5dot5); return; } static void updateMacroCmdsTo5dot6(void) { /* This is ridiculous. Macros don't belong in the default preferences string. This code is also likely to break when the macro commands are upgraded again in a next release, because it looks for patterns in the default macro string (which may change). Using a "Default" mechanism, like we do for highlighting patterns would simplify upgrading A LOT in the future, but changing the way default macros are stored, is a lot of work too, unfortunately. */ const char *pats[] = { "Complete Word:Alt+D::: {\n\ # Tuning parameters\n\ ScanDistance = 200\n\ \n\ # Search back to a word boundary to find the word to complete\n\ startScan = max(0, $cursor - ScanDistance)\n\ endScan = min($text_length, $cursor + ScanDistance)\n\ scanString = get_range(startScan, endScan)\n\ keyEnd = $cursor-startScan\n\ keyStart = search_string(scanString, \"<\", keyEnd, \"backward\", \"regex\")\n\ if (keyStart == -1)\n\ return\n\ keyString = \"<\" substring(scanString, keyStart, keyEnd)\n\ \n\ # search both forward and backward from the cursor position. Note that\n\ # using a regex search can lead to incorrect results if any of the special\n\ # regex characters is encountered, which is not considered a delimiter\n\ backwardSearchResult = search_string(scanString, keyString, keyStart-1, \\\n\ \"backward\", \"regex\")\n\ forwardSearchResult = search_string(scanString, keyString, keyEnd, \"regex\")\n\ if (backwardSearchResult == -1 && forwardSearchResult == -1) {\n\ beep()\n\ return\n\ }\n\ \n\ # if only one direction matched, use that, otherwise use the nearest\n\ if (backwardSearchResult == -1)\n\ matchStart = forwardSearchResult\n\ else if (forwardSearchResult == -1)\n\ matchStart = backwardSearchResult\n\ else {\n\ if (keyStart - backwardSearchResult <= forwardSearchResult - keyEnd)\n\ matchStart = backwardSearchResult\n\ else\n\ matchStart = forwardSearchResult\n\ }\n\ \n\ # find the complete word\n\ matchEnd = search_string(scanString, \">\", matchStart, \"regex\")\n\ completedWord = substring(scanString, matchStart, matchEnd)\n\ \n\ # replace it in the window\n\ replace_range(startScan + keyStart, $cursor, completedWord)\n\ }", "Complete Word:", "\n\t}", "Fill Sel. w/Char:::R: {\n\ if ($selection_start == -1) {\n\ beep()\n\ return\n\ }\n\ \n\ # Ask the user what character to fill with\n\ fillChar = string_dialog(\"Fill selection with what character?\", \"OK\", \"Cancel\")\n\ if ($string_dialog_button == 2 || $string_dialog_button == 0)\n\ return\n\ \n\ # Count the number of lines in the selection\n\ nLines = 0\n\ for (i=$selection_start; i<$selection_end; i++)\n\ if (get_character(i) == \"\\n\")\n\ nLines++\n\ \n\ # Create the fill text\n\ rectangular = $selection_left != -1\n\ line = \"\"\n\ fillText = \"\"\n\ if (rectangular) {\n\ for (i=0; i<$selection_right-$selection_left; i++)\n\ line = line fillChar\n\ for (i=0; i=0 && get_character(i)!=\"\\n\"; i--)\n\ startIndent++\n\ for (i=0; i<$wrap_margin-startIndent; i++)\n\ fillText = fillText fillChar\n\ fillText = fillText \"\\n\"\n\ for (i=0; i<$wrap_margin; i++)\n\ line = line fillChar\n\ for (i=0; i=$selection_start && get_character(i)!=\"\\n\"; \\\n\ i--)\n\ fillText = fillText fillChar\n\ }\n\ }\n\ \n\ # Replace the selection with the fill text\n\ replace_selection(fillText)\n\ }", "Fill Sel. w/Char:", "\n\t}", "Comments>/* Uncomment */@C@C++@Java@CSS@JavaScript@Lex:::R: {\n\ sel = get_selection()\n\ selStart = $selection_start\n\ selEnd = $selection_end\n\ commentStart = search_string(sel, \"/*\", 0)\n\ if (substring(sel, commentStart + 2, commentStart + 3) == \" \")\n\ keepStart = commentStart + 3\n\ else\n\ keepStart = commentStart + 2\n\ keepEnd = search_string(sel, \"*/\", length(sel), \"backward\")\n\ commentEnd = keepEnd + 2\n\ if (substring(sel, keepEnd - 1, keepEnd) == \" \")\n\ keepEnd = keepEnd - 1\n\ replace_range(selStart + commentStart, selStart + commentEnd, \\\n\ substring(sel, keepStart, keepEnd))\n\ select(selStart, selEnd - (keepStart-commentStart) - \\\n\ (commentEnd - keepEnd))\n\ }", "Comments>/* Uncomment */", "\n\t}", "Comments>Bar Uncomment@C:::R: {\n\ selStart = $selection_start\n\ selEnd = $selection_end\n\ newText = get_range(selStart+3, selEnd-4)\n\ newText = replace_in_string(newText, \"^ \\\\* \", \"\", \"regex\")\n\ replace_range(selStart, selEnd, newText)\n\ select(selStart, selStart + length(newText))\n\ }","Comments>Bar Uncomment@C:", "\n\t}", "Make C Prototypes@C@C++:::: {\n\ if ($selection_start == -1) {\n\ start = 0\n\ end = $text_length\n\ } else {\n\ start = $selection_start\n\ end = $selection_end\n\ }\n\ string = get_range(start, end)\n\ nDefs = 0", "Make C Prototypes@C@C++:", "\t\tnDefs = 0", NULL }; int i; for (i = 0; pats[i]; i+=3) replaceMacroIfUnchanged(pats[i], pats[i+1], pats[i+2]); return; } #ifdef SGI_CUSTOM /* ** Present the user a dialog for specifying whether or not a short ** menu mode preference should be applied toward the default setting. ** Return False (function value) if operation was canceled, return True ** in setDefault if requested to reset the default value. */ static int shortPrefToDefault(Widget parent, const char *settingName, int *setDefault) { char msg[100] = ""; if (!GetPrefShortMenus()) { *setDefault = False; return True; } sprintf(msg, "%s\nSave as default for future windows as well?", settingName); switch (DialogF (DF_QUES, parent, 3, "Save Default", msg, "Yes", "No", "Cancel")) { case 1: /* yes */ *setDefault = True; return True; case 2: /* no */ *setDefault = False; return True; case 3: /* cancel */ return False; } return False; /* not reached */ } #endif /* Decref the default calltips file(s) for this window */ void UnloadLanguageModeTipsFile(WindowInfo *window) { int mode; mode = window->languageMode; if (mode != PLAIN_LANGUAGE_MODE && LanguageModes[mode]->defTipsFile) { DeleteTagsFile( LanguageModes[mode]->defTipsFile, TIP, False ); } } /****************************************************************************** * The Color selection dialog ******************************************************************************/ /* There are 8 colors: And 8 indices: textFg TEXT_FG_COLOR textBg TEXT_BG_COLOR selectFg SELECT_FG_COLOR selectBg SELECT_BG_COLOR hiliteFg HILITE_FG_COLOR hiliteBg HILITE_BG_COLOR lineNoFg LINENO_FG_COLOR cursorFg CURSOR_FG_COLOR */ #define MARGIN_SPACING 10 /* * Callbacks for field modifications */ static void textFgModifiedCB(Widget w, XtPointer clientData, XtPointer callData) { colorDialog *cd = (colorDialog *)clientData; showColorStatus(cd, cd->textFgW, cd->textFgErrW); } static void textBgModifiedCB(Widget w, XtPointer clientData, XtPointer callData) { colorDialog *cd = (colorDialog *)clientData; showColorStatus(cd, cd->textBgW, cd->textBgErrW); } static void selectFgModifiedCB(Widget w, XtPointer clientData, XtPointer callData) { colorDialog *cd = (colorDialog *)clientData; showColorStatus(cd, cd->selectFgW, cd->selectFgErrW); } static void selectBgModifiedCB(Widget w, XtPointer clientData, XtPointer callData) { colorDialog *cd = (colorDialog *)clientData; showColorStatus(cd, cd->selectBgW, cd->selectBgErrW); } static void hiliteFgModifiedCB(Widget w, XtPointer clientData, XtPointer callData) { colorDialog *cd = (colorDialog *)clientData; showColorStatus(cd, cd->hiliteFgW, cd->hiliteFgErrW); } static void hiliteBgModifiedCB(Widget w, XtPointer clientData, XtPointer callData) { colorDialog *cd = (colorDialog *)clientData; showColorStatus(cd, cd->hiliteBgW, cd->hiliteBgErrW); } static void lineNoFgModifiedCB(Widget w, XtPointer clientData, XtPointer callData) { colorDialog *cd = (colorDialog *)clientData; showColorStatus(cd, cd->lineNoFgW, cd->lineNoFgErrW); } static void cursorFgModifiedCB(Widget w, XtPointer clientData, XtPointer callData) { colorDialog *cd = (colorDialog *)clientData; showColorStatus(cd, cd->cursorFgW, cd->cursorFgErrW); } /* * Helper functions for validating colors */ static int verifyAllColors(colorDialog *cd) { /* Maybe just check for empty strings in error widgets instead? */ return (checkColorStatus(cd, cd->textFgW) && checkColorStatus(cd, cd->textBgW) && checkColorStatus(cd, cd->selectFgW) && checkColorStatus(cd, cd->selectBgW) && checkColorStatus(cd, cd->hiliteFgW) && checkColorStatus(cd, cd->hiliteBgW) && checkColorStatus(cd, cd->lineNoFgW) && checkColorStatus(cd, cd->cursorFgW) ); } /* Returns True if the color is valid, False if it's not */ static Boolean checkColorStatus(colorDialog *cd, Widget colorFieldW) { Colormap cMap; XColor colorDef; Status status; Display *display = XtDisplay(cd->shell); char *text = XmTextGetString(colorFieldW); XtVaGetValues(cd->shell, XtNcolormap, &cMap, NULL); status = XParseColor(display, cMap, text, &colorDef); XtFree(text); return (status != 0); } /* Show or hide errorLabelW depending on whether or not colorFieldW contains a valid color name. */ static void showColorStatus(colorDialog *cd, Widget colorFieldW, Widget errorLabelW) { /* Should set the OK/Apply button sensitivity here, instead of leaving is sensitive and then complaining if an error. */ XtSetMappedWhenManaged( errorLabelW, !checkColorStatus(cd, colorFieldW) ); } /* Update the colors in the window or in the preferences */ static void updateColors(colorDialog *cd) { WindowInfo *window; char *textFg = XmTextGetString(cd->textFgW), *textBg = XmTextGetString(cd->textBgW), *selectFg = XmTextGetString(cd->selectFgW), *selectBg = XmTextGetString(cd->selectBgW), *hiliteFg = XmTextGetString(cd->hiliteFgW), *hiliteBg = XmTextGetString(cd->hiliteBgW), *lineNoFg = XmTextGetString(cd->lineNoFgW), *cursorFg = XmTextGetString(cd->cursorFgW); for (window = WindowList; window != NULL; window = window->next) { SetColors(window, textFg, textBg, selectFg, selectBg, hiliteFg, hiliteBg, lineNoFg, cursorFg); } SetPrefColorName(TEXT_FG_COLOR , textFg ); SetPrefColorName(TEXT_BG_COLOR , textBg ); SetPrefColorName(SELECT_FG_COLOR, selectFg); SetPrefColorName(SELECT_BG_COLOR, selectBg); SetPrefColorName(HILITE_FG_COLOR, hiliteFg); SetPrefColorName(HILITE_BG_COLOR, hiliteBg); SetPrefColorName(LINENO_FG_COLOR, lineNoFg); SetPrefColorName(CURSOR_FG_COLOR, cursorFg); XtFree(textFg); XtFree(textBg); XtFree(selectFg); XtFree(selectBg); XtFree(hiliteFg); XtFree(hiliteBg); XtFree(lineNoFg); XtFree(cursorFg); } /* * Dialog button callbacks */ static void colorDestroyCB(Widget w, XtPointer clientData, XtPointer callData) { colorDialog *cd = (colorDialog *)clientData; cd->window->colorDialog = NULL; XtFree((char *)cd); } static void colorOkCB(Widget w, XtPointer clientData, XtPointer callData) { colorDialog *cd = (colorDialog *)clientData; if(!verifyAllColors(cd)) { DialogF(DF_ERR, w, 1, "Invalid Colors", "All colors must be valid to proceed.", "OK"); return; } updateColors(cd); /* pop down and destroy the dialog */ XtDestroyWidget(cd->shell); } static void colorApplyCB(Widget w, XtPointer clientData, XtPointer callData) { colorDialog *cd = (colorDialog *)clientData; if(!verifyAllColors(cd)) { DialogF(DF_ERR, w, 1, "Invalid Colors", "All colors must be valid to be applied.", "OK"); return; } updateColors(cd); } static void colorCloseCB(Widget w, XtPointer clientData, XtPointer callData) { colorDialog *cd = (colorDialog *)clientData; /* pop down and destroy the dialog */ XtDestroyWidget(cd->shell); } /* Add a label, error label, and text entry label with a validation callback */ static Widget addColorGroup( Widget parent, const char *name, char mnemonic, char *label, Widget *fieldW, Widget *errW, Widget topWidget, int leftPos, int rightPos, XtCallbackProc modCallback, colorDialog *cd ) { Widget lblW; char *longerName; XmString s1; int nameLen = strlen(name); /* The label widget */ longerName = XtMalloc(nameLen+7); strcpy(longerName, name); strcat(longerName, "Lbl"); lblW = XtVaCreateManagedWidget(longerName, xmLabelGadgetClass, parent, XmNlabelString, s1=XmStringCreateSimple( label ), XmNmnemonic, mnemonic, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, topWidget, XmNtopOffset, MARGIN_SPACING, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, leftPos, NULL); XmStringFree(s1); /* The error label widget */ strcpy(&(longerName[nameLen]), "ErrLbl"); *errW = XtVaCreateManagedWidget(longerName, xmLabelWidgetClass, parent, XmNlabelString, s1=XmStringCreateSimple("(Invalid!)"), XmNalignment, XmALIGNMENT_END, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, topWidget, XmNtopOffset, MARGIN_SPACING, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, lblW, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, rightPos, NULL); XmStringFree(s1); /* The text field entry widget */ *fieldW = XtVaCreateManagedWidget(name, xmTextWidgetClass, parent, XmNcolumns, MAX_COLOR_LEN-1, XmNmaxLength, MAX_COLOR_LEN-1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, leftPos, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, rightPos, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, lblW, NULL); RemapDeleteKey(*fieldW); XtAddCallback(*fieldW, XmNvalueChangedCallback, modCallback, cd); XtVaSetValues(lblW, XmNuserData, *fieldW, NULL); XtFree(longerName); return *fieldW; } /* * Code for the dialog itself */ void ChooseColors(WindowInfo *window) { Widget form, tmpW, topW, infoLbl; Widget okBtn, applyBtn, closeBtn; colorDialog *cd; XmString s1; int ac; Arg args[20]; /* if the dialog is already displayed, just pop it to the top and return */ if (window->colorDialog != NULL) { RaiseDialogWindow(((colorDialog *)window->colorDialog)->shell); return; } /* Create a structure for keeping track of dialog state */ cd = XtNew(colorDialog); window->colorDialog = (void*)cd; /* Create a form widget in a dialog shell */ ac = 0; XtSetArg(args[ac], XmNautoUnmanage, False); ac++; XtSetArg(args[ac], XmNresizePolicy, XmRESIZE_NONE); ac++; form = CreateFormDialog(window->shell, "choose colors", args, ac); XtVaSetValues(form, XmNshadowThickness, 0, NULL); cd->shell = XtParent(form); cd->window = window; XtVaSetValues(cd->shell, XmNtitle, "Colors", NULL); AddMotifCloseCallback(XtParent(form), colorCloseCB, cd); XtAddCallback(form, XmNdestroyCallback, colorDestroyCB, cd); /* Information label */ infoLbl = XtVaCreateManagedWidget("infoLbl", xmLabelGadgetClass, form, XmNtopAttachment, XmATTACH_POSITION, XmNtopPosition, 2, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 99, XmNalignment, XmALIGNMENT_CENTER, XmNlabelString, s1 = XmStringCreateLtoR( "Colors can be entered as names (e.g. red, blue) or " "as RGB triples\nin the format #RRGGBB, where each digit " "is in the range 0-f.", XmFONTLIST_DEFAULT_TAG), NULL); XmStringFree(s1); topW = infoLbl; /* The left column (foregrounds) of color entry groups */ tmpW = addColorGroup( form, "textFg", 'P', "Plain Text Foreground", &(cd->textFgW), &(cd->textFgErrW), topW, 1, 49, textFgModifiedCB, cd ); tmpW = addColorGroup( form, "selectFg", 'S', "Selection Foreground", &(cd->selectFgW), &(cd->selectFgErrW), tmpW, 1, 49, selectFgModifiedCB, cd ); tmpW = addColorGroup( form, "hiliteFg", 'M', "Matching (..) Foreground", &(cd->hiliteFgW), &(cd->hiliteFgErrW), tmpW, 1, 49, hiliteFgModifiedCB, cd ); tmpW = addColorGroup( form, "lineNoFg", 'L', "Line Numbers", &(cd->lineNoFgW), &(cd->lineNoFgErrW), tmpW, 1, 49, lineNoFgModifiedCB, cd ); /* The right column (backgrounds) */ tmpW = addColorGroup( form, "textBg", 'T', "Text Area Background", &(cd->textBgW), &(cd->textBgErrW), topW, 51, 99, textBgModifiedCB, cd ); tmpW = addColorGroup( form, "selectBg", 'B', "Selection Background", &(cd->selectBgW), &(cd->selectBgErrW), tmpW, 51, 99, selectBgModifiedCB, cd ); tmpW = addColorGroup( form, "hiliteBg", 'h', "Matching (..) Background", &(cd->hiliteBgW), &(cd->hiliteBgErrW), tmpW, 51, 99, hiliteBgModifiedCB, cd ); tmpW = addColorGroup( form, "cursorFg", 'C', "Cursor Color", &(cd->cursorFgW), &(cd->cursorFgErrW), tmpW, 51, 99, cursorFgModifiedCB, cd ); tmpW = XtVaCreateManagedWidget("infoLbl", xmLabelGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, tmpW, XmNtopOffset, MARGIN_SPACING, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 99, XmNalignment, XmALIGNMENT_CENTER, XmNlabelString, s1 = XmStringCreateLtoR( "NOTE: Foreground colors only apply when syntax highlighting " "is DISABLED.\n", XmFONTLIST_DEFAULT_TAG), NULL); XmStringFree(s1); tmpW = XtVaCreateManagedWidget("sep", xmSeparatorGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, tmpW, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); /* The OK, Apply, and Cancel buttons */ okBtn = XtVaCreateManagedWidget("ok", xmPushButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("OK"), XmNmarginWidth, BUTTON_WIDTH_MARGIN, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, tmpW, XmNtopOffset, MARGIN_SPACING, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 30, NULL); XtAddCallback(okBtn, XmNactivateCallback, colorOkCB, cd); XmStringFree(s1); applyBtn = XtVaCreateManagedWidget( "apply", xmPushButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("Apply"), XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, tmpW, XmNtopOffset, MARGIN_SPACING, XmNmnemonic, 'A', XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 40, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 60, NULL); XtAddCallback(applyBtn, XmNactivateCallback, colorApplyCB, cd); XmStringFree(s1); closeBtn = XtVaCreateManagedWidget("close", xmPushButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("Close"), XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, tmpW, XmNtopOffset, MARGIN_SPACING, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 70, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 90, NULL); XtAddCallback(closeBtn, XmNactivateCallback, colorCloseCB, cd); XmStringFree(s1); /* Set initial default button */ XtVaSetValues(form, XmNdefaultButton, okBtn, NULL); XtVaSetValues(form, XmNcancelButton, closeBtn, NULL); /* Set initial values */ XmTextSetString(cd->textFgW, GetPrefColorName(TEXT_FG_COLOR )); XmTextSetString(cd->textBgW, GetPrefColorName(TEXT_BG_COLOR )); XmTextSetString(cd->selectFgW, GetPrefColorName(SELECT_FG_COLOR)); XmTextSetString(cd->selectBgW, GetPrefColorName(SELECT_BG_COLOR)); XmTextSetString(cd->hiliteFgW, GetPrefColorName(HILITE_FG_COLOR)); XmTextSetString(cd->hiliteBgW, GetPrefColorName(HILITE_BG_COLOR)); XmTextSetString(cd->lineNoFgW, GetPrefColorName(LINENO_FG_COLOR)); XmTextSetString(cd->cursorFgW, GetPrefColorName(CURSOR_FG_COLOR)); /* Handle mnemonic selection of buttons and focus to dialog */ AddDialogMnemonicHandler(form, FALSE); /* put up dialog */ ManageDialogCenteredOnPointer(form); } /* ** This function passes up a pointer to the static name of the default ** shell, currently defined as the user's login shell. ** In case of errors, the fallback of "sh" will be returned. */ static const char* getDefaultShell(void) { struct passwd* passwdEntry = NULL; static char shellBuffer[MAXPATHLEN + 1] = "sh"; passwdEntry = getpwuid(getuid()); /* getuid() never fails. */ if (NULL == passwdEntry) { /* Something bad happened! Do something, quick! */ perror("nedit: Failed to get passwd entry (falling back to 'sh')"); return "sh"; } /* *passwdEntry may be overwritten */ /* TODO: To make this and other function calling getpwuid() more robust, passwdEntry should be kept in a central position (Core->sysinfo?). That way, local code would always get a current copy of passwdEntry, but could still be kept lean. The obvious alternative of a central facility within NEdit to access passwdEntry would increase coupling and would have to cover a lot of assumptions. */ strncpy(shellBuffer, passwdEntry->pw_shell, MAXPATHLEN); shellBuffer[MAXPATHLEN] = '\0'; return shellBuffer; } nedit-5.6.orig/source/preferences.h0000644000175000017500000002151410737527367016110 0ustar paulpaul/* $Id: preferences.h,v 1.57 2008/01/04 22:11:03 yooden Exp $ */ /******************************************************************************* * * * preference.h -- Nirvana Editor Preferences Header File * * * * Copyright 2004 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_PREFERENCES_H_INCLUDED #define NEDIT_PREFERENCES_H_INCLUDED #include "nedit.h" #include #include #include #include #define PLAIN_LANGUAGE_MODE -1 /* maximum number of language modes allowed */ #define MAX_LANGUAGE_MODES 127 #define MAX_TITLE_FORMAT_LEN 50 /* Identifiers for individual fonts in the help fonts list */ enum helpFonts {HELP_FONT, BOLD_HELP_FONT, ITALIC_HELP_FONT, BOLD_ITALIC_HELP_FONT, FIXED_HELP_FONT, BOLD_FIXED_HELP_FONT, ITALIC_FIXED_HELP_FONT, BOLD_ITALIC_FIXED_HELP_FONT, HELP_LINK_FONT, H1_HELP_FONT, H2_HELP_FONT, H3_HELP_FONT, NUM_HELP_FONTS }; XrmDatabase CreateNEditPrefDB(int *argcInOut, char **argvInOut); void RestoreNEditPrefs(XrmDatabase prefDB, XrmDatabase appDB); void SaveNEditPrefs(Widget parent, int quietly); void ImportPrefFile(const char *filename, int convertOld); void MarkPrefsChanged(void); int CheckPrefsChangesSaved(Widget dialogParent); void SetPrefWrap(int state); int GetPrefWrap(int langMode); void SetPrefWrapMargin(int margin); int GetPrefWrapMargin(void); void SetPrefSearchDlogs(int state); int GetPrefSearchDlogs(void); void SetPrefKeepSearchDlogs(int state); int GetPrefKeepSearchDlogs(void); void SetPrefSearchWraps(int state); int GetPrefSearchWraps(void); void SetPrefStatsLine(int state); int GetPrefStatsLine(void); void SetPrefISearchLine(int state); int GetPrefISearchLine(void); void SetPrefTabBar(int state); int GetPrefTabBar(void); void SetPrefSortTabs(int state); int GetPrefSortTabs(void); void SetPrefTabBarHideOne(int state); int GetPrefTabBarHideOne(void); void SetPrefGlobalTabNavigate(int state); int GetPrefGlobalTabNavigate(void); void SetPrefToolTips(int state); int GetPrefToolTips(void); void SetPrefLineNums(int state); int GetPrefLineNums(void); void SetPrefShowPathInWindowsMenu(int state); int GetPrefShowPathInWindowsMenu(void); void SetPrefWarnFileMods(int state); int GetPrefWarnFileMods(void); void SetPrefWarnRealFileMods(int state); int GetPrefWarnRealFileMods(void); void SetPrefWarnExit(int state); int GetPrefWarnExit(void); void SetPrefSearch(int searchType); int GetPrefSearch(void); void SetPrefAutoIndent(int state); int GetPrefAutoIndent(int langMode); void SetPrefAutoSave(int state); int GetPrefAutoSave(void); void SetPrefSaveOldVersion(int state); int GetPrefSaveOldVersion(void); void SetPrefRows(int nRows); int GetPrefRows(void); void SetPrefCols(int nCols); int GetPrefCols(void); void SetPrefTabDist(int tabDist); int GetPrefTabDist(int langMode); void SetPrefEmTabDist(int tabDist); int GetPrefEmTabDist(int langMode); void SetPrefInsertTabs(int state); int GetPrefInsertTabs(void); void SetPrefShowMatching(int state); int GetPrefShowMatching(void); void SetPrefMatchSyntaxBased(int state); int GetPrefMatchSyntaxBased(void); void SetPrefHighlightSyntax(Boolean state); Boolean GetPrefHighlightSyntax(void); void SetPrefBacklightChars(int state); int GetPrefBacklightChars(void); void SetPrefBacklightCharTypes(char *types); char *GetPrefBacklightCharTypes(void); void SetPrefRepositionDialogs(int state); int GetPrefRepositionDialogs(void); void SetPrefAutoScroll(int state); int GetPrefAutoScroll(void); int GetVerticalAutoScroll(void); void SetPrefAppendLF(int state); int GetPrefAppendLF(void); void SetPrefSortOpenPrevMenu(int state); int GetPrefSortOpenPrevMenu(void); char *GetPrefTagFile(void); int GetPrefSmartTags(void); void SetPrefSmartTags(int state); int GetPrefAlwaysCheckRelTagsSpecs(void); void SetPrefFont(char *fontName); void SetPrefBoldFont(char *fontName); void SetPrefItalicFont(char *fontName); void SetPrefBoldItalicFont(char *fontName); char *GetPrefFontName(void); char *GetPrefBoldFontName(void); char *GetPrefItalicFontName(void); char *GetPrefBoldItalicFontName(void); XmFontList GetPrefFontList(void); XFontStruct *GetPrefBoldFont(void); XFontStruct *GetPrefItalicFont(void); XFontStruct *GetPrefBoldItalicFont(void); char *GetPrefTooltipBgColor(void); char *GetPrefHelpFontName(int index); char *GetPrefHelpLinkColor(void); char *GetPrefColorName(int colorIndex); void SetPrefColorName(int colorIndex, const char *color); void SetPrefShell(const char *shell); const char* GetPrefShell(void); char *GetPrefGeometry(void); char *GetPrefServerName(void); char *GetPrefBGMenuBtn(void); void RowColumnPrefDialog(Widget parent); void TabsPrefDialog(Widget parent, WindowInfo *forWindow); void WrapMarginDialog(Widget parent, WindowInfo *forWindow); int GetPrefMapDelete(void); int GetPrefStdOpenDialog(void); char *GetPrefDelimiters(void); int GetPrefMaxPrevOpenFiles(void); int GetPrefTypingHidesPointer(void); #ifdef SGI_CUSTOM void SetPrefShortMenus(int state); int GetPrefShortMenus(void); #endif void SelectShellDialog(Widget parent, WindowInfo* forWindow); void EditLanguageModes(void); void ChooseFonts(WindowInfo *window, int forWindow); void ChooseColors(WindowInfo *window); char *LanguageModeName(int mode); char *GetWindowDelimiters(const WindowInfo *window); int ReadNumericField(char **inPtr, int *value); char *ReadSymbolicField(char **inPtr); char *ReadSymbolicFieldTextWidget(Widget textW, const char *fieldName, int silent); int ReadQuotedString(char **inPtr, char **errMsg, char **string); char *MakeQuotedString(const char *string); char *EscapeSensitiveChars(const char *string); int SkipDelimiter(char **inPtr, char **errMsg); int SkipOptSeparator(char separator, char **inPtr); int ParseError(Widget toDialog, const char *stringStart, const char *stoppedAt, const char *errorIn, const char *message); int AllocatedStringsDiffer(const char *s1, const char *s2); void SetLanguageMode(WindowInfo *window, int mode, int forceNewDefaults); int FindLanguageMode(const char *languageName); void UnloadLanguageModeTipsFile(WindowInfo *window); void DetermineLanguageMode(WindowInfo *window, int forceNewDefaults); Widget CreateLanguageModeMenu(Widget parent, XtCallbackProc cbProc, void *cbArg); void SetLangModeMenu(Widget optMenu, const char *modeName); void CreateLanguageModeSubMenu(WindowInfo* window, const Widget parent, const char* name, const char* label, const char mnemonic); void SetPrefFindReplaceUsesSelection(int state); int GetPrefFindReplaceUsesSelection(void); int GetPrefStickyCaseSenseBtn(void); void SetPrefBeepOnSearchWrap(int state); int GetPrefBeepOnSearchWrap(void); #ifdef REPLACE_SCOPE void SetPrefReplaceDefScope(int scope); int GetPrefReplaceDefScope(void); #endif void SetPrefTitleFormat(const char* format); const char* GetPrefTitleFormat(void); int GetPrefOverrideVirtKeyBindings(void); int GetPrefTruncSubstitution(void); int GetPrefOpenInTab(void); void SetPrefUndoModifiesSelection(Boolean); void SetPrefOpenInTab(int state); Boolean GetPrefUndoModifiesSelection(void); Boolean GetPrefFocusOnRaise(void); Boolean GetPrefHonorSymlinks(void); Boolean GetPrefForceOSConversion(void); void SetPrefFocusOnRaise(Boolean); #endif /* NEDIT_PREFERENCES_H_INCLUDED */ nedit-5.6.orig/source/rangeset.c0000644000175000017500000014654410754123435015410 0ustar paulpaul/* $Id: rangeset.c,v 1.21 2008/02/11 19:50:53 ajbj Exp $ */ /******************************************************************************* * * * rangeset.c -- Nirvana Editor rangest functions * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * Sep 26, 2002 * * * * Written by Tony Balinski with contributions from Andrew Hood * * * * Modifications: * * * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "textBuf.h" #include "textDisp.h" #include "rangeset.h" #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif /* -------------------------------------------------------------------------- */ struct _Range { int start, end; /* range from [start-]end */ }; typedef Rangeset *RangesetUpdateFn(Rangeset *p, int pos, int ins, int del); struct _Rangeset { RangesetUpdateFn *update_fn; /* modification update function */ char *update_name; /* update function name */ int maxpos; /* text buffer maxpos */ int last_index; /* a place to start looking */ int n_ranges; /* how many ranges in ranges */ Range *ranges; /* the ranges table */ unsigned char label; /* a number 1-63 */ signed char color_set; /* 0: unset; 1: set; -1: invalid */ char *color_name; /* the name of an assigned color */ Pixel color; /* the value of a particular color */ textBuffer *buf; /* the text buffer of the rangeset */ char *name; /* name of rangeset */ }; struct _RangesetTable { int n_set; /* how many sets are active */ textBuffer *buf; /* the text buffer of the rangeset */ Rangeset set[N_RANGESETS]; /* the rangeset table */ unsigned char order[N_RANGESETS]; /* inds of set[]s ordered by depth */ unsigned char active[N_RANGESETS]; /* entry true if corresp. set active */ unsigned char depth[N_RANGESETS]; /* depth[i]: pos of set[i] in order[] */ unsigned char list[N_RANGESETS + 1];/* string of labels in depth order */ }; /* -------------------------------------------------------------------------- */ #define SWAPval(T,a,b) { T t; t = *(a); *(a) = *(b); *(b) = t; } static unsigned char rangeset_labels[N_RANGESETS + 1] = { 58, 10, 15, 1, 27, 52, 14, 3, 61, 13, 31, 30, 45, 28, 41, 55, 33, 20, 62, 34, 42, 18, 57, 47, 24, 49, 19, 50, 25, 38, 40, 2, 21, 39, 59, 22, 60, 4, 6, 16, 29, 37, 48, 46, 54, 43, 32, 56, 51, 7, 9, 63, 5, 8, 36, 44, 26, 11, 23, 17, 53, 35, 12, 0 }; /* -------------------------------------------------------------------------- */ static RangesetUpdateFn rangesetInsDelMaintain; static RangesetUpdateFn rangesetInclMaintain; static RangesetUpdateFn rangesetDelInsMaintain; static RangesetUpdateFn rangesetExclMaintain; static RangesetUpdateFn rangesetBreakMaintain; #define DEFAULT_UPDATE_FN_NAME "maintain" static struct { char *name; RangesetUpdateFn *update_fn; } RangesetUpdateMap[] = { {DEFAULT_UPDATE_FN_NAME, rangesetInsDelMaintain}, {"ins_del", rangesetInsDelMaintain}, {"include", rangesetInclMaintain}, {"del_ins", rangesetDelInsMaintain}, {"exclude", rangesetExclMaintain}, {"break", rangesetBreakMaintain}, {(char *)0, (RangesetUpdateFn *)0} }; /* -------------------------------------------------------------------------- */ static Range *RangesNew(int n) { Range *newRanges; if (n != 0) { /* We use a blocked allocation scheme here, with a block size of factor. Only allocations of multiples of factor will be allowed. Be sure to allocate at least one more than we really need, and round up to next higher multiple of factor, ie n = (((n + 1) + factor - 1) / factor) * factor If we choose factor = (1 << factor_bits), we can use shifts instead of multiply/divide, ie n = ((n + (1 << factor_bits)) >> factor_bits) << factor_bits or n = (1 + (n >> factor_bits)) << factor_bits Since the shifts just strip the end 1 bits, we can even get away with n = ((1 << factor_bits) + n) & (~0 << factor_bits); Finally, we decide on factor_bits according to the size of n: if n >= 256, we probably want less reallocation on growth than otherwise; choose some arbitrary values thus: factor_bits = (n >= 256) ? 6 : 4 so n = (n >= 256) ? (n + (1<<6)) & (~0<<6) : (n + (1<<4)) & (~0<<4) or n = (n >= 256) ? ((n + 64) & ~63) : ((n + 16) & ~15) */ n = (n >= 256) ? ((n + 64) & ~63) : ((n + 16) & ~15); newRanges = (Range *)XtMalloc(n * sizeof (Range)); return newRanges; } return NULL; } /* -------------------------------------------------------------------------- */ static Range* RangesRealloc(Range* ranges, int n) { int size; Range* newRanges; if (n > 0) { /* see RangesNew() for comments */ n = (n >= 256) ? ((n + 64) & ~63) : ((n + 16) & ~15); size = n * sizeof (Range); newRanges = (Range*) (ranges != NULL ? XtRealloc((char *)ranges, size) : XtMalloc(size)); return newRanges; } else { XtFree((char*) ranges); } return NULL; } /* -------------------------------------------------------------------------- */ static Range *RangesFree(Range *ranges) { XtFree((char*) ranges); return NULL; } /* -------------------------------------------------------------------------- */ /* ** Refresh the given range on the screen. If the range indicated is null, we ** refresh the screen for the whole file. */ void RangesetRefreshRange(Rangeset *rangeset, int start, int end) { if (rangeset->buf != NULL) BufCheckDisplay(rangeset->buf, start, end); } static void rangesetRefreshAllRanges(Rangeset *rangeset) { int i; for (i = 0; i < rangeset->n_ranges; i++) RangesetRefreshRange(rangeset, rangeset->ranges[i].start, rangeset->ranges[i].end); } /* -------------------------------------------------------------------------- */ /* ** Remove all ranges from a range set. */ void RangesetEmpty(Rangeset *rangeset) { Range *ranges = rangeset->ranges; int start, end; if (rangeset->color_name && rangeset->color_set > 0) { /* this range is colored: we need to clear it */ rangeset->color_set = -1; while (rangeset->n_ranges--) { start = ranges[rangeset->n_ranges].start; end = ranges[rangeset->n_ranges].end; RangesetRefreshRange(rangeset, start, end); } } XtFree(rangeset->color_name); XtFree(rangeset->name); rangeset->color_name = (char *)0; rangeset->name = (char *)0; rangeset->ranges = RangesFree(rangeset->ranges); } /* -------------------------------------------------------------------------- */ /* ** Initialise a new range set. */ void RangesetInit(Rangeset *rangeset, int label, textBuffer *buf) { rangeset->label = (unsigned char)label; /* a letter A-Z */ rangeset->maxpos = 0; /* text buffer maxpos */ rangeset->last_index = 0; /* a place to start looking */ rangeset->n_ranges = 0; /* how many ranges in ranges */ rangeset->ranges = (Range *)0; /* the ranges table */ rangeset->color_name = (char *)0; rangeset->name = (char *)0; rangeset->color_set = 0; rangeset->buf = buf; rangeset->maxpos = buf->length; RangesetChangeModifyResponse(rangeset, DEFAULT_UPDATE_FN_NAME); } /* ** Change a range set's modification behaviour. Returns true (non-zero) ** if the update function name was found, else false. */ int RangesetChangeModifyResponse(Rangeset *rangeset, char *name) { int i; if (name == NULL) name = DEFAULT_UPDATE_FN_NAME; for (i = 0; RangesetUpdateMap[i].name; i++) if (strcmp(RangesetUpdateMap[i].name, name) == 0) { rangeset->update_fn = RangesetUpdateMap[i].update_fn; rangeset->update_name = RangesetUpdateMap[i].name; return 1; } return 0; } /* -------------------------------------------------------------------------- */ /* ** Find the index of the first integer in table greater than or equal to pos. ** Fails with len (the total number of entries). The start index base can be ** chosen appropriately. */ static int at_or_before(int *table, int base, int len, int val) { int lo, mid = 0, hi; if (base >= len) return len; /* not sure what this means! */ lo = base; /* first valid index */ hi = len - 1; /* last valid index */ while (lo <= hi) { mid = (lo + hi) / 2; if (val == table[mid]) return mid; if (val < table[mid]) hi = mid - 1; else lo = mid + 1; } /* if we get here, we didn't find val itself */ if (val > table[mid]) mid++; return mid; } static int weighted_at_or_before(int *table, int base, int len, int val) { int lo, mid = 0, hi; int min, max; if (base >= len) return len; /* not sure what this means! */ lo = base; /* first valid index */ hi = len - 1; /* last valid index */ min = table[lo]; /* establish initial min/max */ max = table[hi]; if (val <= min) /* initial range checks */ return lo; /* needed to avoid out-of-range mid values */ else if (val > max) return len; else if (val == max) return hi; while (lo <= hi) { /* Beware of integer overflow when multiplying large numbers! */ mid = lo + (int)((hi - lo) * (double)(val - min) / (max - min)); /* we won't worry about min == max - values should be unique */ if (val == table[mid]) return mid; if (val < table[mid]) { hi = mid - 1; max = table[mid]; } else { /* val > table[mid] */ lo = mid + 1; min = table[mid]; } } /* if we get here, we didn't find val itself */ if (val > table[mid]) return mid + 1; return mid; } /* -------------------------------------------------------------------------- */ /* ** Find out whether the position pos is included in one of the ranges of ** rangeset. Returns the containing range's index if true, -1 otherwise. ** Note: ranges are indexed from zero. */ int RangesetFindRangeNo(Rangeset *rangeset, int index, int *start, int *end) { if (!rangeset || index < 0 || rangeset->n_ranges <= index || !rangeset->ranges) return 0; *start = rangeset->ranges[index].start; *end = rangeset->ranges[index].end; return 1; } /* ** Find out whether the position pos is included in one of the ranges of ** rangeset. Returns the containing range's index if true, -1 otherwise. ** Note: ranges are indexed from zero. */ int RangesetFindRangeOfPos(Rangeset *rangeset, int pos, int incl_end) { int *ranges; int len, ind; if (!rangeset || !rangeset->n_ranges || !rangeset->ranges) return -1; ranges = (int *)rangeset->ranges; /* { s1,e1, s2,e2, s3,e3,... } */ len = rangeset->n_ranges * 2; ind = at_or_before(ranges, 0, len, pos); if (ind == len) return -1; /* beyond end */ if (ind & 1) { /* ind odd: references an end marker */ if (pos < ranges[ind] || (incl_end && pos == ranges[ind])) return ind / 2; /* return the range index */ } else { /* ind even: references start marker */ if (pos == ranges[ind]) return ind / 2; /* return the range index */ } return -1; /* not in any range */ } /* ** Find out whether the position pos is included in one of the ranges of ** rangeset. Returns the containing range's index if true, -1 otherwise. ** Essentially the same as the RangesetFindRangeOfPos() function, but uses the ** last_index member of the rangeset and weighted_at_or_before() for speedy ** lookup in refresh tasks. The rangeset is assumed to be valid, as is the ** position. We also don't allow checking of the endpoint. ** Returns the including range index, or -1 if not found. */ int RangesetCheckRangeOfPos(Rangeset *rangeset, int pos) { int *ranges; int len, index, last; len = rangeset->n_ranges; if (len == 0) return -1; /* no ranges */ ranges = (int *)rangeset->ranges; /* { s1,e1, s2,e2, s3,e3,... } */ last = rangeset->last_index; /* try to profit from the last lookup by using its index */ if (last >= len || last < 0) { last = (len > 0) ? len - 1 : 0; /* make sure last is in range */ rangeset->last_index = last; } len *= 2; last *= 2; if (pos >= ranges[last]) { /* last even: this is a start */ if (pos < ranges[last + 1]) /* checking an end here */ return last / 2; /* no need to change rangeset->last_index */ else last += 2; /* not in this range: move on */ if (last == len) return -1; /* moved on too far */ /* find the entry in the upper portion of ranges */ index = weighted_at_or_before(ranges, last, len, pos); /* search end only */ } else if (last > 0) { index = weighted_at_or_before(ranges, 0, last, pos); /* search front only */ } else index = 0; rangeset->last_index = index / 2; if (index == len) return -1; /* beyond end */ if (index & 1) { /* index odd: references an end marker */ if (pos < ranges[index]) return index / 2; /* return the range index */ } else { /* index even: references start marker */ if (pos == ranges[index]) return index / 2; /* return the range index */ } return -1; /* not in any range */ } /* -------------------------------------------------------------------------- */ /* ** Merge the ranges in rangeset plusSet into rangeset origSet. */ int RangesetAdd(Rangeset *origSet, Rangeset *plusSet) { Range *origRanges, *plusRanges, *newRanges, *oldRanges; int nOrigRanges, nPlusRanges; int isOld; origRanges = origSet->ranges; nOrigRanges = origSet->n_ranges; plusRanges = plusSet->ranges; nPlusRanges = plusSet->n_ranges; if (nPlusRanges == 0) return nOrigRanges; /* no ranges in plusSet - nothing to do */ newRanges = RangesNew(nOrigRanges + nPlusRanges); if (nOrigRanges == 0) { /* no ranges in destination: just copy the ranges from the other set */ memcpy(newRanges, plusRanges, nPlusRanges * sizeof (Range)); RangesFree(origSet->ranges); origSet->ranges = newRanges; origSet->n_ranges = nPlusRanges; for (nOrigRanges = 0; nOrigRanges < nPlusRanges; nOrigRanges++) { RangesetRefreshRange(origSet, newRanges->start, newRanges->end); newRanges++; } return nPlusRanges; } oldRanges = origRanges; origSet->ranges = newRanges; origSet->n_ranges = 0; /* in the following we merrily swap the pointers/counters of the two input ranges (from origSet and plusSet) - don't worry, they're both consulted read-only - building the merged set in newRanges */ isOld = 1; /* true if origRanges points to a range in oldRanges[] */ while (nOrigRanges > 0 || nPlusRanges > 0) { /* make the range with the lowest start value the origRanges range */ if (nOrigRanges == 0 || (nPlusRanges > 0 && origRanges->start > plusRanges->start)) { SWAPval(Range *, &origRanges, &plusRanges); SWAPval(int, &nOrigRanges, &nPlusRanges); isOld = !isOld; } origSet->n_ranges++; /* we're using a new result range */ *newRanges = *origRanges++; nOrigRanges--; if (!isOld) RangesetRefreshRange(origSet, newRanges->start, newRanges->end); /* now we must cycle over plusRanges, merging in the overlapped ranges */ while (nPlusRanges > 0 && newRanges->end >= plusRanges->start) { do { if (newRanges->end < plusRanges->end) { if (isOld) RangesetRefreshRange(origSet, newRanges->end, plusRanges->end); newRanges->end = plusRanges->end; } plusRanges++; nPlusRanges--; } while (nPlusRanges > 0 && newRanges->end >= plusRanges->start); /* by now, newRanges->end may have extended to overlap more ranges in origRanges, so swap and start again */ SWAPval(Range *, &origRanges, &plusRanges); SWAPval(int, &nOrigRanges, &nPlusRanges); isOld = !isOld; } /* OK: now *newRanges holds the result of merging all the first ranges from origRanges and plusRanges - now we have a break in contiguity, so move on to the next newRanges in the result */ newRanges++; } /* finally, forget the old rangeset values, and reallocate the new ones */ RangesFree(oldRanges); origSet->ranges = RangesRealloc(origSet->ranges, origSet->n_ranges); return origSet->n_ranges; } /* -------------------------------------------------------------------------- */ /* ** Subtract the ranges of minusSet from rangeset origSet. */ int RangesetRemove(Rangeset *origSet, Rangeset *minusSet) { Range *origRanges, *minusRanges, *newRanges, *oldRanges; int nOrigRanges, nMinusRanges; origRanges = origSet->ranges; nOrigRanges = origSet->n_ranges; minusRanges = minusSet->ranges; nMinusRanges = minusSet->n_ranges; if (nOrigRanges == 0 || nMinusRanges == 0) return 0; /* no ranges in origSet or minusSet - nothing to do */ /* we must provide more space: each range in minusSet might split a range in origSet */ newRanges = RangesNew(origSet->n_ranges + minusSet->n_ranges); oldRanges = origRanges; origSet->ranges = newRanges; origSet->n_ranges = 0; /* consider each range in origRanges - we do not change any of minusRanges's data, but we may change origRanges's - it will be discarded at the end */ while (nOrigRanges > 0) { do { /* skip all minusRanges ranges strictly in front of *origRanges */ while (nMinusRanges > 0 && minusRanges->end <= origRanges->start) { minusRanges++; /* *minusRanges in front of *origRanges: move onto next *minusRanges */ nMinusRanges--; } if (nMinusRanges > 0) { /* keep all origRanges ranges strictly in front of *minusRanges */ while (nOrigRanges > 0 && origRanges->end <= minusRanges->start) { *newRanges++ = *origRanges++; /* *minusRanges beyond *origRanges: save *origRanges in *newRanges */ nOrigRanges--; origSet->n_ranges++; } } else { /* no more minusRanges ranges to remove - save the rest of origRanges */ while (nOrigRanges > 0) { *newRanges++ = *origRanges++; nOrigRanges--; origSet->n_ranges++; } } } while (nMinusRanges > 0 && minusRanges->end <= origRanges->start); /* any more non-overlaps */ /* when we get here either we're done, or we have overlap */ if (nOrigRanges > 0) { if (minusRanges->start <= origRanges->start) { /* origRanges->start inside *minusRanges */ if (minusRanges->end < origRanges->end) { RangesetRefreshRange(origSet, origRanges->start, minusRanges->end); origRanges->start = minusRanges->end; /* cut off front of original *origRanges */ minusRanges++; /* dealt with this *minusRanges: move on */ nMinusRanges--; } else { /* all *origRanges inside *minusRanges */ RangesetRefreshRange(origSet, origRanges->start, origRanges->end); origRanges++; /* all of *origRanges can be skipped */ nOrigRanges--; } } else { /* minusRanges->start inside *origRanges: save front, adjust or skip rest */ newRanges->start = origRanges->start; /* save front of *origRanges in *newRanges */ newRanges->end = minusRanges->start; newRanges++; origSet->n_ranges++; if (minusRanges->end < origRanges->end) { /* all *minusRanges inside *origRanges */ RangesetRefreshRange(origSet, minusRanges->start, minusRanges->end); origRanges->start = minusRanges->end; /* cut front of *origRanges upto end *minusRanges */ minusRanges++; /* dealt with this *minusRanges: move on */ nMinusRanges--; } else { /* minusRanges->end beyond *origRanges */ RangesetRefreshRange(origSet, minusRanges->start, origRanges->end); origRanges++; /* skip rest of *origRanges */ nOrigRanges--; } } } } /* finally, forget the old rangeset values, and reallocate the new ones */ RangesFree(oldRanges); origSet->ranges = RangesRealloc(origSet->ranges, origSet->n_ranges); return origSet->n_ranges; } /* -------------------------------------------------------------------------- */ /* ** Get number of ranges in rangeset. */ int RangesetGetNRanges(Rangeset *rangeset) { return rangeset ? rangeset->n_ranges : 0; } /* ** Get information about rangeset. */ void RangesetGetInfo(Rangeset *rangeset, int *defined, int *label, int *count, char **color, char **name, char **mode) { if (rangeset == NULL) { *defined = False; *label = 0; *count = 0; *color = ""; *name = ""; *mode = ""; } else { *defined = True; *label = (int)rangeset->label; *count = rangeset->n_ranges; *color = rangeset->color_name ? rangeset->color_name : ""; *name = rangeset->name ? rangeset->name : ""; *mode = rangeset->update_name; } } /* -------------------------------------------------------------------------- */ static Rangeset *rangesetFixMaxpos(Rangeset *rangeset, int ins, int del) { rangeset->maxpos += ins - del; return rangeset; } /* -------------------------------------------------------------------------- */ /* ** Allocate and initialise, or empty and free a ranges set table. */ RangesetTable *RangesetTableAlloc(textBuffer *buffer) { int i; RangesetTable *table = (RangesetTable *)XtMalloc(sizeof (RangesetTable)); if (!table) return table; table->buf = buffer; for (i = 0; i < N_RANGESETS; i++) { RangesetInit(&table->set[i], rangeset_labels[i], buffer); table->order[i] = (unsigned char)i; table->active[i] = 0; table->depth[i] = (unsigned char)i; } table->n_set = 0; table->list[0] = '\0'; /* Range sets must be updated before the text display callbacks are called to avoid highlighted ranges getting out of sync. */ BufAddHighPriorityModifyCB(buffer, RangesetBufModifiedCB, table); return table; } RangesetTable *RangesetTableFree(RangesetTable *table) { int i; if (table) { BufRemoveModifyCB(table->buf, RangesetBufModifiedCB, table); for (i = 0; i < N_RANGESETS; i++) RangesetEmpty(&table->set[i]); XtFree((char *)table); } return (RangesetTable *)0; } /* ** clone a ranges set. */ static void rangesetClone(Rangeset *destRangeset, Rangeset *srcRangeset) { destRangeset->update_fn = srcRangeset->update_fn; destRangeset->update_name = srcRangeset->update_name; destRangeset->maxpos = srcRangeset->maxpos; destRangeset->last_index = srcRangeset->last_index; destRangeset->n_ranges = srcRangeset->n_ranges; destRangeset->color_set = srcRangeset->color_set; destRangeset->color = srcRangeset->color; if (srcRangeset->color_name) { destRangeset->color_name = XtMalloc(strlen(srcRangeset->color_name) +1); strcpy(destRangeset->color_name, srcRangeset->color_name); } if (srcRangeset->name) { destRangeset->name = XtMalloc(strlen(srcRangeset->name) + 1); strcpy(destRangeset->name, srcRangeset->name); } if (srcRangeset->ranges) { destRangeset->ranges = RangesNew(srcRangeset->n_ranges); memcpy(destRangeset->ranges, srcRangeset->ranges, srcRangeset->n_ranges * sizeof(Range)); } } /* ** Create a new rangeset table in the destination buffer ** by cloning it from the source table. ** ** Returns the new table created. */ RangesetTable *RangesetTableClone(RangesetTable *srcTable, textBuffer *destBuffer) { RangesetTable *newTable = NULL; int i; if (srcTable == NULL) return NULL; newTable = RangesetTableAlloc(destBuffer); newTable->n_set = srcTable->n_set; memcpy(newTable->order, srcTable->order, sizeof(unsigned char) *N_RANGESETS); memcpy(newTable->active, srcTable->active, sizeof(unsigned char) *N_RANGESETS); memcpy(newTable->depth, srcTable->depth, sizeof(unsigned char) *N_RANGESETS); memcpy(newTable->list, srcTable->list, sizeof(unsigned char) *(N_RANGESETS + 1)); for (i = 0; i < N_RANGESETS; i++) rangesetClone(&newTable->set[i], &srcTable->set[i]); return newTable; } /* ** Find a range set given its label in the table. */ int RangesetFindIndex(RangesetTable *table, int label, int must_be_active) { int i; unsigned char *p_label; if(label == 0) { return -1; } if (table != NULL) { p_label = (unsigned char*)strchr((char*)rangeset_labels, label); if (p_label) { i = p_label - rangeset_labels; if (!must_be_active || table->active[i]) return i; } } return -1; } /* ** Assign the range set table list. */ static void RangesetTableListSet(RangesetTable *table) { int i; for (i = 0; i < table->n_set; i++) table->list[i] = rangeset_labels[(int)table->order[i]]; table->list[table->n_set] = '\0'; } /* ** Return true if label is a valid identifier for a range set. */ int RangesetLabelOK(int label) { return strchr((char*)rangeset_labels, label) != NULL; } /* ** Helper routines for managing the order and depth tables. */ static int activateRangeset(RangesetTable *table, int active) { int depth, i, j; if (table->active[active]) return 0; /* already active */ depth = table->depth[active]; /* we want to make the "active" set the most recent (lowest depth value): shuffle table->order[0..depth-1] to table->order[1..depth] readjust the entries in table->depth[] accordingly */ for (i = depth; i > 0; i--) { j = table->order[i] = table->order[i - 1]; table->depth[j] = i; } /* insert the new one: first in order, of depth 0 */ table->order[0] = active; table->depth[active] = 0; /* and finally... */ table->active[active] = 1; table->n_set++; RangesetTableListSet(table); return 1; } static int deactivateRangeset(RangesetTable *table, int active) { int depth, n, i, j; if (!table->active[active]) return 0; /* already inactive */ /* we want to start by swapping the deepest entry in order with active shuffle table->order[depth+1..n_set-1] to table->order[depth..n_set-2] readjust the entries in table->depth[] accordingly */ depth = table->depth[active]; n = table->n_set - 1; for (i = depth; i < n; i++) { j = table->order[i] = table->order[i + 1]; table->depth[j] = i; } /* reinsert the old one: at max (active) depth */ table->order[n] = active; table->depth[active] = n; /* and finally... */ table->active[active] = 0; table->n_set--; RangesetTableListSet(table); return 1; } /* ** Return the number of rangesets that are inactive */ int nRangesetsAvailable(RangesetTable *table) { return(N_RANGESETS - table->n_set); } /* ** Create a new empty rangeset */ int RangesetCreate(RangesetTable *table) { int label; int setIndex; size_t firstAvailableIndex = strspn((char*)rangeset_labels, (char*)table->list); if(firstAvailableIndex >= sizeof(rangeset_labels)) return 0; label = rangeset_labels[firstAvailableIndex]; setIndex = RangesetFindIndex(table, label, 0); if (setIndex < 0) return 0; if (table->active[setIndex]) return label; if (activateRangeset(table, setIndex)) RangesetInit(&table->set[setIndex], rangeset_labels[setIndex], table->buf); return label; } /* ** Forget the rangeset identified by label - clears it, renders it inactive. */ Rangeset *RangesetForget(RangesetTable *table, int label) { int set_ind = RangesetFindIndex(table, label, 1); if (set_ind < 0) return (Rangeset *)0; if (deactivateRangeset(table, set_ind)) RangesetEmpty(&table->set[set_ind]); return &table->set[set_ind]; } /* ** Fetch the rangeset identified by label - initialise it if not active and ** make_active is true, and make it the most visible. */ Rangeset *RangesetFetch(RangesetTable *table, int label) { int rangesetIndex = RangesetFindIndex(table, label, 0); if (rangesetIndex < 0) return (Rangeset *)NULL; if (table->active[rangesetIndex]) return &table->set[rangesetIndex]; else return (Rangeset *)NULL; } unsigned char *RangesetGetList(RangesetTable *table) { return table ? table->list : (unsigned char *)""; } /* -------------------------------------------------------------------------- */ void RangesetTableUpdatePos(RangesetTable *table, int pos, int ins, int del) { int i; Rangeset *p; if (!table || (ins == 0 && del == 0)) return; for (i = 0; i < table->n_set; i++) { p = &table->set[(int)table->order[i]]; p->update_fn(p, pos, ins, del); } } void RangesetBufModifiedCB(int pos, int nInserted, int nDeleted, int nRestyled, const char *deletedText, void *cbArg) { RangesetTable *table = (RangesetTable *)cbArg; if ((nInserted != nDeleted) || BufCmp(table->buf, pos, nInserted, deletedText) != 0) { RangesetTableUpdatePos(table, pos, nInserted, nDeleted); } } /* -------------------------------------------------------------------------- */ /* ** Find the index of the first range in depth order which includes the position. ** Returns the index of the rangeset in the rangeset table + 1 if an including ** rangeset was found, 0 otherwise. If needs_color is true, "colorless" ranges ** will be skipped. */ int RangesetIndex1ofPos(RangesetTable *table, int pos, int needs_color) { int i; Rangeset *rangeset; if (!table) return 0; for (i = 0; i < table->n_set; i++) { rangeset = &table->set[(int)table->order[i]]; if (RangesetCheckRangeOfPos(rangeset, pos) >= 0) { if (needs_color && rangeset->color_set >= 0 && rangeset->color_name) return table->order[i] + 1; } } return 0; } /* -------------------------------------------------------------------------- */ /* ** Assign a color name to a rangeset via the rangeset table. */ int RangesetAssignColorName(Rangeset *rangeset, char *color_name) { char *cp; if (color_name && color_name[0] == '\0') color_name = (char *)0; /* "" invalid */ /* store new color name value */ if (color_name) { cp = XtMalloc(strlen(color_name) + 1); strcpy(cp, color_name); } else cp = color_name; /* free old color name value */ XtFree(rangeset->color_name); rangeset->color_name = cp; rangeset->color_set = 0; rangesetRefreshAllRanges(rangeset); return 1; } /* ** Assign a name to a rangeset via the rangeset table. */ int RangesetAssignName(Rangeset *rangeset, char *name) { char *cp; if (name && name[0] == '\0') name = (char *)0; /* store new name value */ if (name) { cp = XtMalloc(strlen(name) + 1); strcpy(cp, name); } else { cp = name; } /* free old name value */ XtFree(rangeset->name); rangeset->name = cp; return 1; } /* ** Assign a color pixel value to a rangeset via the rangeset table. If ok is ** false, the color_set flag is set to an invalid (negative) value. */ int RangesetAssignColorPixel(Rangeset *rangeset, Pixel color, int ok) { rangeset->color_set = ok ? 1 : -1; rangeset->color = color; return 1; } /* ** Return the name, if any. */ char *RangesetGetName(Rangeset *rangeset) { return rangeset->name; } /* ** Return the color validity, if any, and the value in *color. */ int RangesetGetColorValid(Rangeset *rangeset, Pixel *color) { *color = rangeset->color; return rangeset->color_set; } /* ** Return the color name, if any. */ char *RangesetTableGetColorName(RangesetTable *table, int index) { Rangeset *rangeset = &table->set[index]; return rangeset->color_name; } /* ** Return the color color validity, if any, and the value in *color. */ int RangesetTableGetColorValid(RangesetTable *table, int index, Pixel *color) { Rangeset *rangeset = &table->set[index]; *color = rangeset->color; return rangeset->color_set; } /* ** Assign a color pixel value to a rangeset via the rangeset table. If ok is ** false, the color_set flag is set to an invalid (negative) value. */ int RangesetTableAssignColorPixel(RangesetTable *table, int index, Pixel color, int ok) { Rangeset *rangeset = &table->set[index]; rangeset->color_set = ok ? 1 : -1; rangeset->color = color; return 1; } /* -------------------------------------------------------------------------- */ #define is_start(i) !((i) & 1) /* true if i is even */ #define is_end(i) ((i) & 1) /* true if i is odd */ /* ** Find the index of the first entry in the range set's ranges table (viewed as ** an int array) whose value is equal to or greater than pos. As a side effect, ** update the lasi_index value of the range set. Return's the index value. This ** will be twice p->n_ranges if pos is beyond the end. */ static int rangesetWeightedAtOrBefore(Rangeset *rangeset, int pos) { int i, last, n, *rangeTable = (int *)rangeset->ranges; n = rangeset->n_ranges; if (n == 0) return 0; last = rangeset->last_index; if (last >= n || last < 0) last = 0; n *= 2; last *= 2; if (pos >= rangeTable[last]) /* ranges[last_index].start */ i = weighted_at_or_before(rangeTable, last, n, pos); /* search end only */ else i = weighted_at_or_before(rangeTable, 0, last, pos); /* search front only */ rangeset->last_index = i / 2; return i; } /* ** Adjusts values in tab[] by an amount delta, perhaps moving them meanwhile. */ static int rangesetShuffleToFrom(int *rangeTable, int to, int from, int n, int delta) { int end, diff = from - to; if (n <= 0) return 0; if (delta != 0) { if (diff > 0) { /* shuffle entries down */ for (end = to + n; to < end; to++) rangeTable[to] = rangeTable[to + diff] + delta; } else if (diff < 0) { /* shuffle entries up */ for (end = to, to += n; --to >= end;) rangeTable[to] = rangeTable[to + diff] + delta; } else { /* diff == 0: just run through */ for (end = n; end--;) rangeTable[to++] += delta; } } else { if (diff > 0) { /* shuffle entries down */ for (end = to + n; to < end; to++) rangeTable[to] = rangeTable[to + diff]; } else if (diff < 0) { /* shuffle entries up */ for (end = to, to += n; --to >= end;) rangeTable[to] = rangeTable[to + diff]; } /* else diff == 0: nothing to do */ } return n; } /* ** Functions to adjust a rangeset to include new text or remove old. ** *** NOTE: No redisplay: that's outside the responsability of these routines. */ /* "Insert/Delete": if the start point is in or at the end of a range ** (start < pos && pos <= end), any text inserted will extend that range. ** Insertions appear to occur before deletions. This will never add new ranges. */ static Rangeset *rangesetInsDelMaintain(Rangeset *rangeset, int pos, int ins, int del) { int i, j, n, *rangeTable = (int *)rangeset->ranges; int end_del, movement; n = 2 * rangeset->n_ranges; i = rangesetWeightedAtOrBefore(rangeset, pos); if (i == n) return rangesetFixMaxpos(rangeset, ins, del); /* all beyond the end */ end_del = pos + del; movement = ins - del; /* the idea now is to determine the first range not concerned with the movement: its index will be j. For indices j to n-1, we will adjust position by movement only. (They may need shuffling up or down, depending on whether ranges have been deleted or created by the change.) */ j = i; while (j < n && rangeTable[j] <= end_del) /* skip j to first ind beyond changes */ j++; /* if j moved forward, we have deleted over rangeTable[i] - reduce it accordingly, accounting for inserts. */ if (j > i) rangeTable[i] = pos + ins; /* If i and j both index starts or ends, just copy all the rangeTable[] values down by j - i spaces, adjusting on the way. Otherwise, move beyond rangeTable[i] before doing this. */ if (is_start(i) != is_start(j)) i++; rangesetShuffleToFrom(rangeTable, i, j, n - j, movement); n -= j - i; rangeset->n_ranges = n / 2; rangeset->ranges = RangesRealloc(rangeset->ranges, rangeset->n_ranges); /* final adjustments */ return rangesetFixMaxpos(rangeset, ins, del); } /* "Inclusive": if the start point is in, at the start of, or at the end of a ** range (start <= pos && pos <= end), any text inserted will extend that range. ** Insertions appear to occur before deletions. This will never add new ranges. ** (Almost identical to rangesetInsDelMaintain().) */ static Rangeset *rangesetInclMaintain(Rangeset *rangeset, int pos, int ins, int del) { int i, j, n, *rangeTable = (int *)rangeset->ranges; int end_del, movement; n = 2 * rangeset->n_ranges; i = rangesetWeightedAtOrBefore(rangeset, pos); if (i == n) return rangesetFixMaxpos(rangeset, ins, del); /* all beyond the end */ /* if the insert occurs at the start of a range, the following lines will extend the range, leaving the start of the range at pos. */ if (is_start(i) && rangeTable[i] == pos && ins > 0) i++; end_del = pos + del; movement = ins - del; /* the idea now is to determine the first range not concerned with the movement: its index will be j. For indices j to n-1, we will adjust position by movement only. (They may need shuffling up or down, depending on whether ranges have been deleted or created by the change.) */ j = i; while (j < n && rangeTable[j] <= end_del) /* skip j to first ind beyond changes */ j++; /* if j moved forward, we have deleted over rangeTable[i] - reduce it accordingly, accounting for inserts. */ if (j > i) rangeTable[i] = pos + ins; /* If i and j both index starts or ends, just copy all the rangeTable[] values down by j - i spaces, adjusting on the way. Otherwise, move beyond rangeTable[i] before doing this. */ if (is_start(i) != is_start(j)) i++; rangesetShuffleToFrom(rangeTable, i, j, n - j, movement); n -= j - i; rangeset->n_ranges = n / 2; rangeset->ranges = RangesRealloc(rangeset->ranges, rangeset->n_ranges); /* final adjustments */ return rangesetFixMaxpos(rangeset, ins, del); } /* "Delete/Insert": if the start point is in a range (start < pos && ** pos <= end), and the end of deletion is also in a range ** (start <= pos + del && pos + del < end) any text inserted will extend that ** range. Deletions appear to occur before insertions. This will never add new ** ranges. */ static Rangeset *rangesetDelInsMaintain(Rangeset *rangeset, int pos, int ins, int del) { int i, j, n, *rangeTable = (int *)rangeset->ranges; int end_del, movement; n = 2 * rangeset->n_ranges; i = rangesetWeightedAtOrBefore(rangeset, pos); if (i == n) return rangesetFixMaxpos(rangeset, ins, del); /* all beyond the end */ end_del = pos + del; movement = ins - del; /* the idea now is to determine the first range not concerned with the movement: its index will be j. For indices j to n-1, we will adjust position by movement only. (They may need shuffling up or down, depending on whether ranges have been deleted or created by the change.) */ j = i; while (j < n && rangeTable[j] <= end_del) /* skip j to first ind beyond changes */ j++; /* if j moved forward, we have deleted over rangeTable[i] - reduce it accordingly, accounting for inserts. (Note: if rangeTable[j] is an end position, inserted text will belong to the range that rangeTable[j] closes; otherwise inserted text does not belong to a range.) */ if (j > i) rangeTable[i] = (is_end(j)) ? pos + ins : pos; /* If i and j both index starts or ends, just copy all the rangeTable[] values down by j - i spaces, adjusting on the way. Otherwise, move beyond rangeTable[i] before doing this. */ if (is_start(i) != is_start(j)) i++; rangesetShuffleToFrom(rangeTable, i, j, n - j, movement); n -= j - i; rangeset->n_ranges = n / 2; rangeset->ranges = RangesRealloc(rangeset->ranges, rangeset->n_ranges); /* final adjustments */ return rangesetFixMaxpos(rangeset, ins, del); } /* "Exclusive": if the start point is in, but not at the end of, a range ** (start < pos && pos < end), and the end of deletion is also in a range ** (start <= pos + del && pos + del < end) any text inserted will extend that ** range. Deletions appear to occur before insertions. This will never add new ** ranges. (Almost identical to rangesetDelInsMaintain().) */ static Rangeset *rangesetExclMaintain(Rangeset *rangeset, int pos, int ins, int del) { int i, j, n, *rangeTable = (int *)rangeset->ranges; int end_del, movement; n = 2 * rangeset->n_ranges; i = rangesetWeightedAtOrBefore(rangeset, pos); if (i == n) return rangesetFixMaxpos(rangeset, ins, del); /* all beyond the end */ /* if the insert occurs at the end of a range, the following lines will skip the range, leaving the end of the range at pos. */ if (is_end(i) && rangeTable[i] == pos && ins > 0) i++; end_del = pos + del; movement = ins - del; /* the idea now is to determine the first range not concerned with the movement: its index will be j. For indices j to n-1, we will adjust position by movement only. (They may need shuffling up or down, depending on whether ranges have been deleted or created by the change.) */ j = i; while (j < n && rangeTable[j] <= end_del) /* skip j to first ind beyond changes */ j++; /* if j moved forward, we have deleted over rangeTable[i] - reduce it accordingly, accounting for inserts. (Note: if rangeTable[j] is an end position, inserted text will belong to the range that rangeTable[j] closes; otherwise inserted text does not belong to a range.) */ if (j > i) rangeTable[i] = (is_end(j)) ? pos + ins : pos; /* If i and j both index starts or ends, just copy all the rangeTable[] values down by j - i spaces, adjusting on the way. Otherwise, move beyond rangeTable[i] before doing this. */ if (is_start(i) != is_start(j)) i++; rangesetShuffleToFrom(rangeTable, i, j, n - j, movement); n -= j - i; rangeset->n_ranges = n / 2; rangeset->ranges = RangesRealloc(rangeset->ranges, rangeset->n_ranges); /* final adjustments */ return rangesetFixMaxpos(rangeset, ins, del); } /* "Break": if the modification point pos is strictly inside a range, that range ** may be broken in two if the deletion point pos+del does not extend beyond the ** end. Inserted text is never included in the range. */ static Rangeset *rangesetBreakMaintain(Rangeset *rangeset, int pos, int ins, int del) { int i, j, n, *rangeTable = (int *)rangeset->ranges; int end_del, movement, need_gap; n = 2 * rangeset->n_ranges; i = rangesetWeightedAtOrBefore(rangeset, pos); if (i == n) return rangesetFixMaxpos(rangeset, ins, del); /* all beyond the end */ /* if the insert occurs at the end of a range, the following lines will skip the range, leaving the end of the range at pos. */ if (is_end(i) && rangeTable[i] == pos && ins > 0) i++; end_del = pos + del; movement = ins - del; /* the idea now is to determine the first range not concerned with the movement: its index will be j. For indices j to n-1, we will adjust position by movement only. (They may need shuffling up or down, depending on whether ranges have been deleted or created by the change.) */ j = i; while (j < n && rangeTable[j] <= end_del) /* skip j to first ind beyond changes */ j++; if (j > i) rangeTable[i] = pos; /* do we need to insert a gap? yes if pos is in a range and ins > 0 */ /* The logic for the next statement: if i and j are both range ends, range boundaries indicated by index values between i and j (if any) have been "skipped". This means that rangeTable[i-1],rangeTable[j] is the current range. We will be inserting in that range, splitting it. */ need_gap = (is_end(i) && is_end(j) && ins > 0); /* if we've got start-end or end-start, skip rangeTable[i] */ if (is_start(i) != is_start(j)) { /* one is start, other is end */ if (is_start(i)) { if (rangeTable[i] == pos) rangeTable[i] = pos + ins; /* move the range start */ } i++; /* skip to next index */ } /* values rangeTable[j] to rangeTable[n-1] must be adjusted by movement and placed in position. */ if (need_gap) i += 2; /* make space for the break */ /* adjust other position values: shuffle them up or down if necessary */ rangesetShuffleToFrom(rangeTable, i, j, n - j, movement); if (need_gap) { /* add the gap informations */ rangeTable[i - 2] = pos; rangeTable[i - 1] = pos + ins; } n -= j - i; rangeset->n_ranges = n / 2; rangeset->ranges = RangesRealloc(rangeset->ranges, rangeset->n_ranges); /* final adjustments */ return rangesetFixMaxpos(rangeset, ins, del); } /* -------------------------------------------------------------------------- */ /* ** Invert the rangeset (replace it with its complement in the range 0-maxpos). ** Returns the number of ranges if successful, -1 otherwise. Never adds more ** than one range. */ int RangesetInverse(Rangeset *rangeset) { int *rangeTable; int n, has_zero, has_end; if (!rangeset) return -1; rangeTable = (int *)rangeset->ranges; if (rangeset->n_ranges == 0) { if (!rangeTable) { rangeset->ranges = RangesNew(1); rangeTable = (int *)rangeset->ranges; } rangeTable[0] = 0; rangeTable[1] = rangeset->maxpos; n = 2; } else { n = rangeset->n_ranges * 2; /* find out what we have */ has_zero = (rangeTable[0] == 0); has_end = (rangeTable[n - 1] == rangeset->maxpos); /* fill the entry "beyond the end" with the buffer's length */ rangeTable[n + 1] = rangeTable[n] = rangeset->maxpos; if (has_zero) { /* shuffle down by one */ rangesetShuffleToFrom(rangeTable, 0, 1, n, 0); n -= 1; } else { /* shuffle up by one */ rangesetShuffleToFrom(rangeTable, 1, 0, n, 0); rangeTable[0] = 0; n += 1; } if (has_end) n -= 1; else n += 1; } rangeset->n_ranges = n / 2; rangeset->ranges = RangesRealloc((Range *)rangeTable, rangeset->n_ranges); RangesetRefreshRange(rangeset, 0, rangeset->maxpos); return rangeset->n_ranges; } /* -------------------------------------------------------------------------- */ /* ** Add the range indicated by the positions start and end. Returns the ** new number of ranges in the set. */ int RangesetAddBetween(Rangeset *rangeset, int start, int end) { int i, j, n, *rangeTable = (int *)rangeset->ranges; if (start > end) { i = start; /* quietly sort the positions */ start = end; end = i; } else if (start == end) { return rangeset->n_ranges; /* no-op - empty range == no range */ } n = 2 * rangeset->n_ranges; if (n == 0) { /* make sure we have space */ rangeset->ranges = RangesNew(1); rangeTable = (int *)rangeset->ranges; i = 0; } else i = rangesetWeightedAtOrBefore(rangeset, start); if (i == n) { /* beyond last range: just add it */ rangeTable[n] = start; rangeTable[n + 1] = end; rangeset->n_ranges++; rangeset->ranges = RangesRealloc(rangeset->ranges, rangeset->n_ranges); RangesetRefreshRange(rangeset, start, end); return rangeset->n_ranges; } j = i; while (j < n && rangeTable[j] <= end) /* skip j to first ind beyond changes */ j++; if (i == j) { if (is_start(i)) { /* is_start(i): need to make a gap in range rangeTable[i-1], rangeTable[i] */ rangesetShuffleToFrom(rangeTable, i + 2, i, n - i, 0); /* shuffle up */ rangeTable[i] = start; /* load up new range's limits */ rangeTable[i + 1] = end; rangeset->n_ranges++; /* we've just created a new range */ rangeset->ranges = RangesRealloc(rangeset->ranges, rangeset->n_ranges); } else { return rangeset->n_ranges; /* no change */ } } else { /* we'll be shuffling down */ if (is_start(i)) rangeTable[i++] = start; if (is_start(j)) rangeTable[--j] = end; if (i < j) rangesetShuffleToFrom(rangeTable, i, j, n - j, 0); n -= j - i; rangeset->n_ranges = n / 2; rangeset->ranges = RangesRealloc(rangeset->ranges, rangeset->n_ranges); } RangesetRefreshRange(rangeset, start, end); return rangeset->n_ranges; } /* ** Remove the range indicated by the positions start and end. Returns the ** new number of ranges in the set. */ int RangesetRemoveBetween(Rangeset *rangeset, int start, int end) { int i, j, n, *rangeTable = (int *)rangeset->ranges; if (start > end) { i = start; /* quietly sort the positions */ start = end; end = i; } else if (start == end) { return rangeset->n_ranges; /* no-op - empty range == no range */ } n = 2 * rangeset->n_ranges; i = rangesetWeightedAtOrBefore(rangeset, start); if (i == n) return rangeset->n_ranges; /* beyond last range */ j = i; while (j < n && rangeTable[j] <= end) /* skip j to first ind beyond changes */ j++; if (i == j) { /* removal occurs in front of rangeTable[i] */ if (is_start(i)) return rangeset->n_ranges; /* no change */ else { /* is_end(i): need to make a gap in range rangeTable[i-1], rangeTable[i] */ i--; /* start of current range */ rangesetShuffleToFrom(rangeTable, i + 2, i, n - i, 0); /* shuffle up */ rangeTable[i + 1] = start; /* change end of current range */ rangeTable[i + 2] = end; /* change start of new range */ rangeset->n_ranges++; /* we've just created a new range */ rangeset->ranges = RangesRealloc(rangeset->ranges, rangeset->n_ranges); } } else { /* removal occurs in front of rangeTable[j]: we'll be shuffling down */ if (is_end(i)) rangeTable[i++] = start; if (is_end(j)) rangeTable[--j] = end; if (i < j) rangesetShuffleToFrom(rangeTable, i, j, n - j, 0); n -= j - i; rangeset->n_ranges = n / 2; rangeset->ranges = RangesRealloc(rangeset->ranges, rangeset->n_ranges); } RangesetRefreshRange(rangeset, start, end); return rangeset->n_ranges; } /* -------------------------------------------------------------------------- */ nedit-5.6.orig/source/rangeset.h0000644000175000017500000001003710737527370015407 0ustar paulpaul/* $Id: rangeset.h,v 1.8 2008/01/04 22:11:04 yooden Exp $ */ /******************************************************************************* * * * rangeset.h -- Nirvana Editor rangest header * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * Sep 26, 2002 * * * * Written by Tony Balinski with contributions from Andrew Hood * * * * Modifications: * * * * * *******************************************************************************/ #ifndef rangeset_h_DEFINED #define rangeset_h_DEFINED #include #define N_RANGESETS 63 typedef struct _Range Range; typedef struct _Rangeset Rangeset; void RangesetRefreshRange(Rangeset *rangeset, int start, int end); void RangesetEmpty(Rangeset *rangeset); void RangesetInit(Rangeset *rangeset, int label, textBuffer *buf); int RangesetChangeModifyResponse(Rangeset *rangeset, char *name); int RangesetFindRangeNo(Rangeset *rangeset, int index, int *start, int *end); int RangesetFindRangeOfPos(Rangeset *rangeset, int pos, int incl_end); int RangesetCheckRangeOfPos(Rangeset *rangeset, int pos); int RangesetInverse(Rangeset *p); int RangesetAdd(Rangeset *origSet, Rangeset *plusSet); int RangesetAddBetween(Rangeset *rangeset, int start, int end); int RangesetRemove(Rangeset *origSet, Rangeset *minusSet); int RangesetRemoveBetween(Rangeset *rangeset, int start, int end); int RangesetGetNRanges(Rangeset *rangeset); void RangesetGetInfo(Rangeset *rangeset, int *defined, int *label, int *count, char **color, char **name, char **mode); RangesetTable *RangesetTableAlloc(textBuffer *buf); RangesetTable *RangesetTableFree(RangesetTable *table); RangesetTable *RangesetTableClone(RangesetTable *srcTable, textBuffer *destBuffer); int RangesetFindIndex(RangesetTable *table, int label, int must_be_active); int RangesetLabelOK(int label); int RangesetCreate(RangesetTable *table); int nRangesetsAvailable(RangesetTable *table); Rangeset *RangesetForget(RangesetTable *table, int label); Rangeset *RangesetFetch(RangesetTable *table, int label); unsigned char * RangesetGetList(RangesetTable *table); void RangesetTableUpdatePos(RangesetTable *table, int pos, int n_ins, int n_del); void RangesetBufModifiedCB(int pos, int nInserted, int nDeleted, int nRestyled, const char *deletedText, void *cbArg); int RangesetIndex1ofPos(RangesetTable *table, int pos, int needs_color); int RangesetAssignColorName(Rangeset *rangeset, char *color_name); int RangesetAssignColorPixel(Rangeset *rangeset, Pixel color, int ok); char *RangesetGetName(Rangeset *rangeset); int RangesetAssignName(Rangeset *rangeset, char *name); int RangesetGetColorValid(Rangeset *rangeset, Pixel *color); char *RangesetTableGetColorName(RangesetTable *table, int index); int RangesetTableGetColorValid(RangesetTable *table, int index, Pixel *color); int RangesetTableAssignColorPixel(RangesetTable *table, int index, Pixel color, int ok); #endif /* rangeset_h_DEFINED */ nedit-5.6.orig/source/rbTree.c0000644000175000017500000005107007513373022015006 0ustar paulpaulstatic const char CVSID[] = "$Id: rbTree.c,v 1.7 2002/07/11 21:18:10 slobasso Exp $"; /******************************************************************************* * * * rbTree.c -- Nirvana editor red-black balanced binary tree * * * * Copyright (C) 2001 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July, 1993 * * * * Written by Mark Edel * * * *******************************************************************************/ /* ** rbTree is a red-black balanced binary tree ** the base node holds the leftmost, rightmost and root pointers ** and a node count */ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "rbTree.h" #include #include /*#define RBTREE_TEST_CODE*/ #ifdef RBTREE_TEST_CODE #include #endif #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #define rbTreeNodeRed 0 #define rbTreeNodeBlack 1 /* ** rotate a node left */ static void rotateLeft(rbTreeNode *x, rbTreeNode **root) { rbTreeNode *y = x->right; x->right = y->left; if (y->left != NULL) { y->left->parent = x; } y->parent = x->parent; if (x == *root) { *root = y; } else if (x == x->parent->left) { x->parent->left = y; } else { x->parent->right = y; } y->left = x; x->parent = y; } /* ** rotate a node right */ static void rotateRight(rbTreeNode *x, rbTreeNode **root) { rbTreeNode *y = x->left; x->left = y->right; if (y->right != NULL) { y->right->parent = x; } y->parent = x->parent; if (x == *root) { *root = y; } else if (x == x->parent->right) { x->parent->right = y; } else { x->parent->left = y; } y->right = x; x->parent = y; } /* ** balance tree after an insert of node x */ static void insertBalance(rbTreeNode *x, rbTreeNode **root) { x->color = rbTreeNodeRed; while (x != *root && x->parent->color == rbTreeNodeRed) { if (x->parent == x->parent->parent->left) { rbTreeNode *y = x->parent->parent->right; if (y && y->color == rbTreeNodeRed) { x->parent->color = rbTreeNodeBlack; y->color = rbTreeNodeBlack; x->parent->parent->color = rbTreeNodeRed; x = x->parent->parent; } else { if (x == x->parent->right) { x = x->parent; rotateLeft(x, root); } x->parent->color = rbTreeNodeBlack; x->parent->parent->color = rbTreeNodeRed; rotateRight(x->parent->parent, root); } } else { rbTreeNode *y = x->parent->parent->left; if (y && y->color == rbTreeNodeRed) { x->parent->color = rbTreeNodeBlack; y->color = rbTreeNodeBlack; x->parent->parent->color = rbTreeNodeRed; x = x->parent->parent; } else { if (x == x->parent->left) { x = x->parent; rotateRight(x, root); } x->parent->color = rbTreeNodeBlack; x->parent->parent->color = rbTreeNodeRed; rotateLeft(x->parent->parent, root); } } } (*root)->color = rbTreeNodeBlack; } /* ** returns the leftmost node (the beginning of the sorted list) */ rbTreeNode *rbTreeBegin(rbTreeNode *base) { return(base->left); } /* ** returns the rightmost node (the end of the sorted list) */ rbTreeNode *rbTreeReverseBegin(rbTreeNode *base) { return(base->right); } /* ** search for a node and return it's pointer, NULL if not found */ rbTreeNode *rbTreeFind(rbTreeNode *base, rbTreeNode *searchNode, rbTreeCompareNodeCB compareRecords) { rbTreeNode *foundNode = NULL; rbTreeNode *current = base->parent; while(current != NULL) { int compareResult = compareRecords(searchNode, current); if (compareResult < 0) { current = current->left; } else if (compareResult > 0) { current = current->right; } else { foundNode = current; current = NULL; } } return(foundNode); } /* ** insert a node into the tree and rebalance it ** if a duplicate is found copy the new data over it ** returns the new node */ rbTreeNode *rbTreeInsert(rbTreeNode *base, rbTreeNode *searchNode, rbTreeCompareNodeCB compareRecords, rbTreeAllocateNodeCB allocateNode, rbTreeCopyToNodeCB copyToNode) { rbTreeNode *current, *parent, *x; int fromLeft = 0, foundMatch = 0; current = base->parent; parent = NULL; x = NULL; while(current != NULL) { int compareResult = compareRecords(searchNode, current); if (compareResult < 0) { parent = current; current = current->left; fromLeft = 1; } else if (compareResult > 0) { parent = current; current = current->right; fromLeft = 0; } else { x = current; if (!copyToNode(x, searchNode)) { x = NULL; } current = NULL; foundMatch = 1; } } if (!foundMatch) { x = allocateNode(searchNode); if (x) { x->parent = parent; x->left = NULL; x->right = NULL; x->color = rbTreeNodeRed; if (parent) { if (fromLeft) { parent->left = x; } else { parent->right = x; } } else { base->parent = x; } ++(base->color); if (x->parent == base->left && (x->parent == NULL || x->parent->left == x)) { base->left = x; } if (x->parent == base->right && (x->parent == NULL || x->parent->right == x)) { base->right = x; } insertBalance(x, &base->parent); } } return(x); } /* ** unlink a node from the tree and rebalance it. ** returns the removed node pointer */ rbTreeNode *rbTreeUnlinkNode(rbTreeNode *base, rbTreeNode *z) { int swapColor; rbTreeNode *x, *y, *x_parent; y = z; if (y->left == NULL) { x = y->right; if (y == base->left) { base->left = rbTreeNext(y); } } else { if (y->right == NULL) { x = y->left; if (y == base->right) { base->right = rbTreePrevious(y); } } else { y = y->right; while (y->left != NULL) { y = y->left; } x = y->right; } } if (y != z) { z->left->parent = y; y->left = z->left; if (y != z->right) { x_parent = y->parent; if (x != NULL) { x->parent = y->parent; } y->parent->left = x; y->right = z->right; z->right->parent = y; } else { x_parent = y; } if (base->parent == z) { base->parent = y; } else if (z->parent->left == z) { z->parent->left = y; } else { z->parent->right = y; } y->parent = z->parent; swapColor = y->color; y->color = z->color; z->color = swapColor; y = z; } else { x_parent = y->parent; if (x != NULL) { x->parent = y->parent; } if (base->parent == z) { base->parent = x; } else { if (z->parent->left == z) { z->parent->left = x; } else { z->parent->right = x; } } } --(base->color); if (y->color != rbTreeNodeRed) { while (x != base->parent && (x == NULL || x->color == rbTreeNodeBlack)) { if (x == x_parent->left) { rbTreeNode *w = x_parent->right; if (w->color == rbTreeNodeRed) { w->color = rbTreeNodeBlack; x_parent->color = rbTreeNodeRed; rotateLeft(x_parent, &base->parent); w = x_parent->right; } if ((w->left == NULL || w->left->color == rbTreeNodeBlack) && (w->right == NULL || w->right->color == rbTreeNodeBlack)) { w->color = rbTreeNodeRed; x = x_parent; x_parent = x_parent->parent; } else { if (w->right == NULL || w->right->color == rbTreeNodeBlack) { if (w->left) { w->left->color = rbTreeNodeBlack; } w->color = rbTreeNodeRed; rotateRight(w, &base->parent); w = x_parent->right; } w->color = x_parent->color; x_parent->color = rbTreeNodeBlack; if (w->right) { w->right->color = rbTreeNodeBlack; } rotateLeft(x_parent, &base->parent); break; } } else { rbTreeNode *w = x_parent->left; if (w->color == rbTreeNodeRed) { w->color = rbTreeNodeBlack; x_parent->color = rbTreeNodeRed; rotateRight(x_parent, &base->parent); w = x_parent->left; } if ((w->right == NULL || w->right->color == rbTreeNodeBlack) && (w->left == NULL || w->left->color == rbTreeNodeBlack)) { w->color = rbTreeNodeRed; x = x_parent; x_parent = x_parent->parent; } else { if (w->left == NULL || w->left->color == rbTreeNodeBlack) { if (w->right) { w->right->color = rbTreeNodeBlack; } w->color = rbTreeNodeRed; rotateLeft(w, &base->parent); w = x_parent->left; } w->color = x_parent->color; x_parent->color = rbTreeNodeBlack; if (w->left) { w->left->color = rbTreeNodeBlack; } rotateRight(x_parent, &base->parent); break; } } } if (x) { x->color = rbTreeNodeBlack; } } return(y); } /* ** delete an already found node and dispose it */ void rbTreeDeleteNode(rbTreeNode *base, rbTreeNode *foundNode, rbTreeDisposeNodeCB disposeNode) { disposeNode(rbTreeUnlinkNode(base, foundNode)); } /* ** search for a node and remove it from the tree ** disposing the removed node ** returns 1 if a node was found, otherwise 0 */ int rbTreeDelete(rbTreeNode *base, rbTreeNode *searchNode, rbTreeCompareNodeCB compareRecords, rbTreeDisposeNodeCB disposeNode) { int foundNode = 0; rbTreeNode *z; z = rbTreeFind(base, searchNode, compareRecords); if (z != NULL) { rbTreeDeleteNode(base, z, disposeNode); foundNode = 1; } return(foundNode); } /* ** move an iterator foreward one element ** note that a valid pointer must be passed, ** passing NULL will result in unpredictable results */ rbTreeNode *rbTreeNext(rbTreeNode *x) { if (x->right != NULL) { x = x->right; while (x->left != NULL) { x = x->left; } } else { rbTreeNode *fromX; do { fromX = x; x = x->parent; } while (x && fromX == x->right); } return(x); } /* ** move an iterator back one element ** note that a valid pointer must be passed, ** passing NULL will result in unpredictable results */ rbTreeNode *rbTreePrevious(rbTreeNode *x) { if (x->left != NULL) { x = x->left; while (x->right != NULL) { x = x->right; } } else { rbTreeNode *fromX; do { fromX = x; x = x->parent; } while (x && fromX == x->left); } return(x); } /* ** returns the number of real data nodes in the tree, not counting ** the base node since it contains no data */ int rbTreeSize(rbTreeNode *base) { return(base->color); } /* ** Allocate a new red-black tree using an empty node to hold pointers */ rbTreeNode *rbTreeNew(rbTreeAllocateEmptyNodeCB allocateEmptyNode) { rbTreeNode *rootStorage = allocateEmptyNode(); if (rootStorage) { rootStorage->left = NULL; /* leftmost node */ rootStorage->right = NULL; /* rightmost node */ rootStorage->parent = NULL; /* root node */ rootStorage->color = 0; /* node count */ } return(rootStorage); } /* ** iterate through all nodes, unlinking and disposing them ** extra effort is made to maintain all links, the size, and ** leftmost/rightmost pointers, so that the tree can be dumped ** when debugging problems. We could probably ifdef some of this ** since it goes unused most of the time ** the tree is not kept balanced since all nodes will be removed */ void rbTreeDispose(rbTreeNode *base, rbTreeDisposeNodeCB disposeNode) { rbTreeNode *iter = rbTreeBegin(base); while (iter != NULL) { rbTreeNode *nextIter = rbTreeNext(iter); if (iter->parent) { if (iter->parent->left == iter) { iter->parent->left = iter->right; } else { iter->parent->right = iter->right; } } if (iter->right != NULL) { iter->right->parent = iter->parent; } base->left = nextIter; if (base->right == iter) { base->right = NULL; } --(base->color); if (base->parent == iter) { base->parent = nextIter; } disposeNode(iter); iter = nextIter; } disposeNode(base); } #ifdef RBTREE_TEST_CODE /* ================================================================== */ /* ** code to test basic stuff of tree routines */ typedef struct TestNode { rbTreeNode nodePointers; /* MUST BE FIRST MEMBER */ char *str; char *key; } TestNode; static int rbTreeCompareNode_TestNode(rbTreeNode *left, rbTreeNode *right) { return(strcmp(((TestNode *)left)->key, ((TestNode *)right)->key)); } static rbTreeNode *rbTreeAllocateNode_TestNode(rbTreeNode *src) { TestNode *newNode = malloc(sizeof(TestNode)); if (newNode) { newNode->str = malloc(strlen(((TestNode *)src)->str) + 1); if (newNode->str) { strcpy(newNode->str, ((TestNode *)src)->str); newNode->key = malloc(strlen(((TestNode *)src)->key) + 1); if (newNode->key) { strcpy(newNode->key, ((TestNode *)src)->key); } else { free(newNode->str); newNode->str = NULL; free(newNode); newNode = NULL; } } else { free(newNode); newNode = NULL; } } return((rbTreeNode *)newNode); } rbTreeNode *rbTreeAllocateEmptyNodeCB_TestNode(void) { TestNode *newNode = malloc(sizeof(TestNode)); if (newNode) { newNode->str = NULL; newNode->key = NULL; } return((rbTreeNode *)newNode); } static void rbTreeDisposeNode_TestNode(rbTreeNode *src) { if (src) { if (((TestNode *)src)->str) { free(((TestNode *)src)->str); ((TestNode *)src)->str = NULL; } if (((TestNode *)src)->key) { free(((TestNode *)src)->key); ((TestNode *)src)->key = NULL; } src->left = (void *)-1; src->right = (void *)-1; src->parent = (void *)-1; src->color = rbTreeNodeBlack; free(src); } } static int rbTreeCopyToNode_TestNode(rbTreeNode *dst, rbTreeNode *src) { TestNode newValues; int copiedOK = 0; newValues.str = malloc(strlen(((TestNode *)src)->str) + 1); if (newValues.str) { strcpy(newValues.str, ((TestNode *)src)->str); newValues.key = malloc(strlen(((TestNode *)src)->key) + 1); if (newValues.key) { strcpy(newValues.key, ((TestNode *)src)->key); ((TestNode *)dst)->str = newValues.str; ((TestNode *)dst)->key = newValues.key; copiedOK = 1; } else { free(newValues.str); newValues.str = NULL; } } return(copiedOK); } static void DumpTree(rbTreeNode *base) { rbTreeNode *newNode; newNode = rbTreeBegin(base); while (newNode != NULL) { rbTreeNode *nextNode = rbTreeNext(newNode); printf("[%s] = \"%s\"\n", ((TestNode *)newNode)->key, ((TestNode *)newNode)->str); printf("[%x] l[%x] r[%x] p[%x] <%s>\n", (int)newNode, (int)newNode->left, (int)newNode->right, (int)newNode->parent, ((newNode->color == rbTreeNodeBlack)?"Black":"Red")); newNode = nextNode; } } int main(int argc, char **argv) { rbTreeNode *base, *newNode; TestNode searchNode; char tmpkey[20], tmpValue[40]; int i; searchNode.key = tmpkey; searchNode.str = tmpValue; base = rbTreeNew(rbTreeAllocateEmptyNodeCB_TestNode); if (!base) { printf("Failed New!!!\n"); exit(1); } for (i = 0; i < 100; ++i) { sprintf(tmpkey, "%d", i); sprintf(tmpValue, "<%d>", i * i); newNode = rbTreeInsert(base, (rbTreeNode *)&searchNode, rbTreeCompareNode_TestNode, rbTreeAllocateNode_TestNode, rbTreeCopyToNode_TestNode); if (!newNode) { printf("Failed!!!\n"); exit(1); } } newNode = rbTreeBegin(base); while (newNode != NULL) { rbTreeNode *nextNode = rbTreeNext(newNode); printf("[%s] = \"%s\"\n", ((TestNode *)newNode)->key, ((TestNode *)newNode)->str); if (strlen(((TestNode *)newNode)->str) < 7) { int didDelete; printf("Deleting [%s]\n", ((TestNode *)newNode)->key); didDelete = rbTreeDelete(base, newNode, rbTreeCompareNode_TestNode, rbTreeDisposeNode_TestNode); printf("delete result = %d\n", didDelete); } newNode = nextNode; } printf("Tree Size = %d\n", rbTreeSize(base)); printf("\n++++++++++++++++\n"); DumpTree(base); printf("\n++++++++++++++++\n"); rbTreeDispose(base, rbTreeDisposeNode_TestNode); printf("\nDone.\n"); return(0); } #endif nedit-5.6.orig/source/rbTree.h0000644000175000017500000000740510144236624015016 0ustar paulpaul/* $Id: rbTree.h,v 1.5 2004/11/09 21:58:44 yooden Exp $ */ /******************************************************************************* * * * rbTree.h -- Nirvana Editor Red-Black Balanced Binary Tree Header File * * * * Copyright 2002 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_RBTREE_H_INCLUDED #define NEDIT_RBTREE_H_INCLUDED typedef struct rbTreeNode { struct rbTreeNode *left; /* left child */ struct rbTreeNode *right; /* right child */ struct rbTreeNode *parent; /* parent */ int color; /* node color (rbTreeNodeBlack, rbTreeNodeRed) */ } rbTreeNode; typedef int (*rbTreeCompareNodeCB)(rbTreeNode *left, rbTreeNode *right); typedef rbTreeNode *(*rbTreeAllocateNodeCB)(rbTreeNode *src); typedef rbTreeNode *(*rbTreeAllocateEmptyNodeCB)(void); typedef void (*rbTreeDisposeNodeCB)(rbTreeNode *src); typedef int (*rbTreeCopyToNodeCB)(rbTreeNode *dst, rbTreeNode *src); rbTreeNode *rbTreeBegin(rbTreeNode *base); rbTreeNode *rbTreeReverseBegin(rbTreeNode *base); rbTreeNode *rbTreeFind(rbTreeNode *base, rbTreeNode *searchNode, rbTreeCompareNodeCB compareRecords); rbTreeNode *rbTreeInsert(rbTreeNode *base, rbTreeNode *searchNode, rbTreeCompareNodeCB compareRecords, rbTreeAllocateNodeCB allocateNode, rbTreeCopyToNodeCB copyToNode); rbTreeNode *rbTreeUnlinkNode(rbTreeNode *base, rbTreeNode *z); void rbTreeDeleteNode(rbTreeNode *base, rbTreeNode *foundNode, rbTreeDisposeNodeCB disposeNode); int rbTreeDelete(rbTreeNode *base, rbTreeNode *searchNode, rbTreeCompareNodeCB compareRecords, rbTreeDisposeNodeCB disposeNode); rbTreeNode *rbTreeNext(rbTreeNode *x); rbTreeNode *rbTreePrevious(rbTreeNode *x); int rbTreeSize(rbTreeNode *base); rbTreeNode *rbTreeNew(rbTreeAllocateEmptyNodeCB allocateEmptyNode); void rbTreeDispose(rbTreeNode *base, rbTreeDisposeNodeCB disposeNode); #endif /* NEDIT_RBTREE_H_INCLUDED */ nedit-5.6.orig/source/regexConvert.c0000644000175000017500000007752610077452065016260 0ustar paulpaulstatic const char CVSID[] = "$Id: regexConvert.c,v 1.10 2004/07/21 11:32:05 yooden Exp $"; /*------------------------------------------------------------------------* * `CompileRE', `ExecRE', and `ConvertSubstituteRE' -- regular expression parsing * * This is a HIGHLY ALTERED VERSION of Henry Spencer's `regcomp' * code adapted for NEdit. * * .-------------------------------------------------------------------. * | ORIGINAL COPYRIGHT NOTICE: | * | | * | Copyright (c) 1986 by University of Toronto. | * | Written by Henry Spencer. Not derived from licensed software. | * | | * | Permission is granted to anyone to use this software for any | * | purpose on any computer system, and to redistribute it freely, | * | subject to the following restrictions: | * | | * | 1. The author is not responsible for the consequences of use of | * | this software, no matter how awful, even if they arise | * | from defects in it. | * | | * | 2. The origin of this software must not be misrepresented, either | * | by explicit claim or by omission. | * | | * | 3. Altered versions must be plainly marked as such, and must not | * | be misrepresented as being the original software. | * `-------------------------------------------------------------------' * * This is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. In addition, you may distribute version of this program linked to * Motif or Open Motif. See README for details. * * This software is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along with * software; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "regexConvert.h" #include #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif /* Utility definitions. */ #define NSUBEXP 50 #define CONVERT_FAIL(m) {*Error_Ptr = (m); return 0;} #define IS_QUANTIFIER(c) ((c) == '*' || (c) == '+' || (c) == '?') #define U_CHAR_AT(p) ((unsigned int) *(unsigned char *)(p)) /* Flags to be passed up and down via function parameters during compile. */ #define WORST 0 /* Worst case. No assumptions can be made.*/ #define HAS_WIDTH 1 /* Known never to match null string. */ #define SIMPLE 2 /* Simple enough to be STAR/PLUS operand. */ #define NO_PAREN 0 /* Only set by initial call to "chunk". */ #define PAREN 1 /* Used for normal capturing parentheses. */ #define REG_ZERO 0UL #define REG_ONE 1UL /* Global work variables for `ConvertRE'. */ static unsigned char *Reg_Parse; /* Input scan ptr (scans user's regex) */ static int Total_Paren; /* Parentheses, (), counter. */ static unsigned long Convert_Size; /* Address of this used as flag. */ static unsigned char *Code_Emit_Ptr; /* When Code_Emit_Ptr is set to &Compute_Size no code is emitted. Instead, the size of code that WOULD have been generated is accumulated in Convert_Size. Otherwise, Code_Emit_Ptr points to where compiled regex code is to be written. */ static unsigned char Compute_Size; static char **Error_Ptr; /* Place to store error messages so they can be returned by `ConvertRE' */ static char Error_Text [128];/* Sting to build error messages in. */ static unsigned char Meta_Char [] = ".*+?[(|)^<>$"; static unsigned char *Convert_Str; /* Forward declarations for functions used by `ConvertRE'. */ static int alternative (int *flag_param); static int chunk (int paren, int *flag_param); static void emit_convert_byte (unsigned char c); static unsigned char literal_escape (unsigned char c, int); static int atom (int *flag_param); static void reg_error (char *str); static int piece (int *flag_param); /*----------------------------------------------------------------------* * ConvertRE * * Compiles a regular expression into the internal format used by * `ExecRE'. * * Beware that the optimization and preparation code in here knows about * some of the structure of the compiled regexp. *----------------------------------------------------------------------*/ char * ConvertRE (const char *exp, char **errorText) { int flags_local, pass; /* Set up `errorText' to receive failure reports. */ Error_Ptr = errorText; *Error_Ptr = ""; if (exp == NULL) CONVERT_FAIL ("NULL argument to `ConvertRE\'"); Code_Emit_Ptr = &Compute_Size; Convert_Size = 0UL; /* We can't allocate space until we know how big the compiled form will be, but we can't compile it (and thus know how big it is) until we've got a place to put the code. So we cheat: we compile it twice, once with code generation turned off and size counting turned on, and once "for real". This also means that we don't allocate space until we are sure that the thing really will compile successfully, and we never have to move the code and thus invalidate pointers into it. (Note that it has to be in one piece because free() must be able to free it all.) */ for (pass = 1; pass <= 2; pass++) { /*-------------------------------------------* * FIRST PASS: Determine size and legality. * * SECOND PASS: Emit converted code. * *-------------------------------------------*/ Reg_Parse = (unsigned char *) exp; Total_Paren = 1; if (chunk (NO_PAREN, &flags_local) == 0) return (NULL); /* Something went wrong */ emit_convert_byte ('\0'); if (pass == 1) { /* Allocate memory. */ Convert_Str = (unsigned char *) XtMalloc (sizeof (unsigned char) * Convert_Size); if (Convert_Str == NULL) { CONVERT_FAIL ("out of memory in `ConvertRE\'"); } Code_Emit_Ptr = Convert_Str; } } return (char *) Convert_Str; } /*----------------------------------------------------------------------* * chunk * * * * Process main body of regex or process a parenthesized "thing". * * * * Caller must absorb opening parenthesis. *----------------------------------------------------------------------*/ static int chunk (int paren, int *flag_param) { register int this_branch; int flags_local; *flag_param = HAS_WIDTH; /* Tentatively. */ /* Make an OPEN node, if parenthesized. */ if (paren == PAREN) { if (Total_Paren >= NSUBEXP) { sprintf (Error_Text, "number of ()'s > %d", (int) NSUBEXP); CONVERT_FAIL (Error_Text); } Total_Paren++; } /* Pick up the branches, linking them together. */ do { this_branch = alternative (&flags_local); if (this_branch == 0) return 0; /* If any alternative could be zero width, consider the whole parenthisized thing to be zero width. */ if (!(flags_local & HAS_WIDTH)) *flag_param &= ~HAS_WIDTH; /* Are there more alternatives to process? */ if (*Reg_Parse != '|') break; emit_convert_byte ('|'); Reg_Parse++; } while (1); /* Check for proper termination. */ if (paren != NO_PAREN && *Reg_Parse != ')') { CONVERT_FAIL ("missing right parenthesis \')\'"); } else if (paren != NO_PAREN) { emit_convert_byte (')'); Reg_Parse++; } else if (paren == NO_PAREN && *Reg_Parse != '\0') { if (*Reg_Parse == ')') { CONVERT_FAIL ("missing left parenthesis \'(\'"); } else { CONVERT_FAIL ("junk on end"); /* "Can't happen" - NOTREACHED */ } } return 1; } /*----------------------------------------------------------------------* * alternative - Processes one alternative of an '|' operator. *----------------------------------------------------------------------*/ static int alternative (int *flag_param) { int ret_val; int flags_local; *flag_param = WORST; /* Tentatively. */ /* Loop until we hit the start of the next alternative, the end of this set of alternatives (end of parentheses), or the end of the regex. */ while (*Reg_Parse != '|' && *Reg_Parse != ')' && *Reg_Parse != '\0') { ret_val = piece (&flags_local); if (ret_val == 0) return 0; /* Something went wrong. */ *flag_param |= flags_local & HAS_WIDTH; } return 1; } /*----------------------------------------------------------------------* * piece - something followed by possible '*', '+', or '?'. *----------------------------------------------------------------------*/ static int piece (int *flag_param) { register int ret_val; register unsigned char op_code; unsigned long min_val = REG_ZERO; int flags_local; ret_val = atom (&flags_local); if (ret_val == 0) return 0; /* Something went wrong. */ op_code = *Reg_Parse; if (!IS_QUANTIFIER (op_code)) { *flag_param = flags_local; return (ret_val); } Reg_Parse++; if (op_code == '+') min_val = REG_ONE; /* It is dangerous to apply certain quantifiers to a possibly zero width item. */ if (!(flags_local & HAS_WIDTH) && min_val > REG_ZERO) { sprintf (Error_Text, "%c operand could be empty", op_code); CONVERT_FAIL (Error_Text); } *flag_param = (min_val > REG_ZERO) ? (WORST | HAS_WIDTH) : WORST; if ( !((op_code == '*') || (op_code == '+') || (op_code == '?')) ) { /* We get here if the IS_QUANTIFIER macro is not coordinated properly with this function. */ CONVERT_FAIL ("internal error #2, `piece\'"); } if (IS_QUANTIFIER (*Reg_Parse)) { sprintf (Error_Text, "nested quantifiers, %c%c", op_code, *Reg_Parse); CONVERT_FAIL (Error_Text); } emit_convert_byte (op_code); return (ret_val); } /*----------------------------------------------------------------------* * atom - Process one regex item at the lowest level *----------------------------------------------------------------------*/ static int atom (int *flag_param) { int ret_val = 1; unsigned char test; int flags_local; *flag_param = WORST; /* Tentatively. */ switch (*Reg_Parse++) { case '^': emit_convert_byte ('^'); break; case '$': emit_convert_byte ('$'); break; case '<': emit_convert_byte ('<'); break; case '>': emit_convert_byte ('>'); break; case '.': emit_convert_byte ('.'); *flag_param |= (HAS_WIDTH | SIMPLE); break; case '(': emit_convert_byte ('('); ret_val = chunk (PAREN, &flags_local); if (ret_val == 0) return 0; /* Something went wrong. */ /* Add HAS_WIDTH flag if it was set by call to chunk. */ *flag_param |= flags_local & HAS_WIDTH; break; case '\0': case '|': case ')': CONVERT_FAIL ("internal error #3, `atom\'"); /* Supposed to be */ /* caught earlier. */ case '?': case '+': case '*': sprintf (Error_Text, "%c follows nothing", *(Reg_Parse - 1)); CONVERT_FAIL (Error_Text); case '{': emit_convert_byte ('\\'); /* Quote braces. */ emit_convert_byte ('{'); break; case '[': { register unsigned int last_value; unsigned char last_emit = 0; unsigned char buffer [500]; int head = 0; int negated = 0; int do_brackets = 1; int a_z_flag = 0; int A_Z_flag = 0; int zero_nine = 0; int u_score_flag = 0; buffer [0] = '\0'; /* Handle characters that can only occur at the start of a class. */ if (*Reg_Parse == '^') { /* Complement of range. */ negated = 1; Reg_Parse++; } if (*Reg_Parse == ']' || *Reg_Parse == '-') { /* If '-' or ']' is the first character in a class, it is a literal character in the class. */ last_emit = *Reg_Parse; if (head >= 498) { CONVERT_FAIL ("too much data in [] to convert."); } buffer [head++] = '\\'; /* Escape `]' and '-' for clarity. */ buffer [head++] = *Reg_Parse; Reg_Parse++; } /* Handle the rest of the class characters. */ while (*Reg_Parse != '\0' && *Reg_Parse != ']') { if (*Reg_Parse == '-') { /* Process a range, e.g [a-z]. */ Reg_Parse++; if (*Reg_Parse == ']' || *Reg_Parse == '\0') { /* If '-' is the last character in a class it is a literal character. If `Reg_Parse' points to the end of the regex string, an error will be generated later. */ last_emit = '-'; if (head >= 498) { CONVERT_FAIL ("too much data in [] to convert."); } buffer [head++] = '\\'; /* Escape '-' for clarity. */ buffer [head++] = '-'; } else { if (*Reg_Parse == '\\') { /* Handle escaped characters within a class range. */ Reg_Parse++; if ((test = literal_escape (*Reg_Parse, 0))) { buffer [head++] = '-'; if (*Reg_Parse != '\"') { emit_convert_byte ('\\'); } buffer [head++] = *Reg_Parse; last_value = (unsigned int) test; } else { sprintf ( Error_Text, "\\%c is an invalid escape sequence(3)", *Reg_Parse); CONVERT_FAIL (Error_Text); } } else { last_value = U_CHAR_AT (Reg_Parse); if (last_emit == '0' && last_value == '9') { zero_nine = 1; head--; } else if (last_emit == 'a' && last_value == 'z') { a_z_flag = 1; head--; } else if (last_emit == 'A' && last_value == 'Z') { A_Z_flag = 1; head--; } else { buffer [head++] = '-'; if ((test = literal_escape (*Reg_Parse, 1))) { /* Ordinary character matches an escape sequence; convert it to the escape sequence. */ if (head >= 495) { CONVERT_FAIL ( "too much data in [] to convert."); } buffer [head++] = '\\'; if (test == '0') { /* Make octal escape. */ test = *Reg_Parse; buffer [head++] = '0'; buffer [head++] = ('0' + (test / 64)); test -= (test / 64) * 64; buffer [head++] = ('0' + (test / 8)); test -= (test / 8) * 8; buffer [head++] = ('0' + test); } else { buffer [head++] = test; } } else { buffer [head++] = last_value; } } } if (last_emit > last_value) { CONVERT_FAIL ("invalid [] range"); } last_emit = (unsigned char) last_value; Reg_Parse++; } /* End class character range code. */ } else if (*Reg_Parse == '\\') { Reg_Parse++; if ((test = literal_escape (*Reg_Parse, 0)) != '\0') { last_emit = test; if (head >= 498) { CONVERT_FAIL ("too much data in [] to convert."); } if (*Reg_Parse != '\"') { buffer [head++] = '\\'; } buffer [head++] = *Reg_Parse; } else { sprintf (Error_Text, "\\%c is an invalid escape sequence(1)", *Reg_Parse); CONVERT_FAIL (Error_Text); } Reg_Parse++; /* End of class escaped sequence code */ } else { last_emit = *Reg_Parse; if (*Reg_Parse == '_') { u_score_flag = 1; /* Emit later if we can't do `\w'. */ } else if ((test = literal_escape (*Reg_Parse, 1))) { /* Ordinary character matches an escape sequence; convert it to the escape sequence. */ if (head >= 495) { CONVERT_FAIL ("too much data in [] to convert."); } buffer [head++] = '\\'; if (test == '0') { /* Make octal escape. */ test = *Reg_Parse; buffer [head++] = '0'; buffer [head++] = ('0' + (test / 64)); test -= (test / 64) * 64; buffer [head++] = ('0' + (test / 8)); test -= (test / 8) * 8; buffer [head++] = ('0' + test); } else { if (head >= 499) { CONVERT_FAIL ("too much data in [] to convert."); } buffer [head++] = test; } } else { if (head >= 499) { CONVERT_FAIL ("too much data in [] to convert."); } buffer [head++] = *Reg_Parse; } Reg_Parse++; } } /* End of while (*Reg_Parse != '\0' && *Reg_Parse != ']') */ if (*Reg_Parse != ']') CONVERT_FAIL ("missing right \']\'"); buffer [head] = '\0'; /* NOTE: it is impossible to specify an empty class. This is because [] would be interpreted as "begin character class" followed by a literal ']' character and no "end character class" delimiter (']'). Because of this, it is always safe to assume that a class HAS_WIDTH. */ Reg_Parse++; *flag_param |= HAS_WIDTH | SIMPLE; if (head == 0) { if (( a_z_flag && A_Z_flag && zero_nine && u_score_flag) || ( a_z_flag && A_Z_flag && !zero_nine && !u_score_flag) || (!a_z_flag && !A_Z_flag && zero_nine && !u_score_flag)) { do_brackets = 0; } } if (do_brackets) { emit_convert_byte ('['); if (negated) emit_convert_byte ('^'); } /* Output any shortcut escapes if we can. */ while (a_z_flag || A_Z_flag || zero_nine || u_score_flag) { if (a_z_flag && A_Z_flag && zero_nine && u_score_flag) { emit_convert_byte ('\\'); if (negated && !do_brackets) { emit_convert_byte ('W'); } else { emit_convert_byte ('w'); } a_z_flag = A_Z_flag = zero_nine = u_score_flag = 0; } else if (a_z_flag && A_Z_flag) { emit_convert_byte ('\\'); if (negated && !do_brackets) { emit_convert_byte ('L'); } else { emit_convert_byte ('l'); } a_z_flag = A_Z_flag = 0; } else if (zero_nine) { emit_convert_byte ('\\'); if (negated && !do_brackets) { emit_convert_byte ('D'); } else { emit_convert_byte ('d'); } zero_nine = 0; } else if (a_z_flag) { emit_convert_byte ('a'); emit_convert_byte ('-'); emit_convert_byte ('z'); a_z_flag = 0; } else if (A_Z_flag) { emit_convert_byte ('A'); emit_convert_byte ('-'); emit_convert_byte ('Z'); A_Z_flag = 0; } else if (u_score_flag) { emit_convert_byte ('_'); u_score_flag = 0; } } /* Output our buffered class characters. */ for (head = 0; buffer [head] != '\0'; head++) { emit_convert_byte (buffer [head]); } if (do_brackets) { emit_convert_byte (']'); } } break; /* End of character class code. */ /* Fall through to Default case to handle literal escapes. */ default: Reg_Parse--; /* If we fell through from the above code, we are now pointing at the back slash (\) character. */ { unsigned char *parse_save, *emit_save; int emit_diff, len = 0; /* Loop until we find a meta character or end of regex string. */ for (; *Reg_Parse != '\0' && !strchr ((char *) Meta_Char, (int) *Reg_Parse); len++) { /* Save where we are in case we have to back this character out. */ parse_save = Reg_Parse; emit_save = Code_Emit_Ptr; if (*Reg_Parse == '\\') { if ((test = literal_escape (*(Reg_Parse + 1), 0))) { if (*(Reg_Parse + 1) != '\"') { emit_convert_byte ('\\'); } Reg_Parse++; /* Point to escaped character */ emit_convert_byte (*Reg_Parse); } else { sprintf (Error_Text, "\\%c is an invalid escape sequence(2)", *(Reg_Parse + 1)); CONVERT_FAIL (Error_Text); } Reg_Parse++; } else { /* Ordinary character */ if ((test = literal_escape (*Reg_Parse, 1))) { /* Ordinary character matches an escape sequence; convert it to the escape sequence. */ emit_convert_byte ('\\'); if (test == '0') { test = *Reg_Parse; emit_convert_byte ('0'); emit_convert_byte ('0' + (test / 64)); test -= (test / 64) * 64; emit_convert_byte ('0' + (test / 8)); test -= (test / 8) * 8; emit_convert_byte ('0' + test); } else { emit_convert_byte (test); } } else { emit_convert_byte (*Reg_Parse); } Reg_Parse++; } /* If next regex token is a quantifier (?, +. *, or {m,n}) and our EXACTLY node so far is more than one character, leave the last character to be made into an EXACTLY node one character wide for the multiplier to act on. For example 'abcd* would have an EXACTLY node with an 'abc' operand followed by a STAR node followed by another EXACTLY node with a 'd' operand. */ if (IS_QUANTIFIER (*Reg_Parse) && len > 0) { Reg_Parse = parse_save; /* Point to previous regex token. */ emit_diff = (Code_Emit_Ptr - emit_save); if (Code_Emit_Ptr == &Compute_Size) { Convert_Size -= emit_diff; } else { /* Write over previously emitted byte. */ Code_Emit_Ptr = emit_save; } break; } } if (len <= 0) CONVERT_FAIL ("internal error #4, `atom\'"); *flag_param |= HAS_WIDTH; if (len == 1) *flag_param |= SIMPLE; } } /* END switch (*Reg_Parse++) */ return (ret_val); } /*----------------------------------------------------------------------* * emit_convert_byte * * Emit (if appropriate) a byte of converted code. *----------------------------------------------------------------------*/ static void emit_convert_byte (unsigned char c) { if (Code_Emit_Ptr == &Compute_Size) { Convert_Size++; } else { *Code_Emit_Ptr++ = c; } } /*--------------------------------------------------------------------* * literal_escape * * Recognize escaped literal characters (prefixed with backslash), * and translate them into the corresponding character. * * Returns the proper character value or NULL if not a valid literal * escape. *--------------------------------------------------------------------*/ static unsigned char literal_escape (unsigned char c, int action) { static unsigned char control_escape [] = { 'a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\0' }; static unsigned char control_actual [] = { '\a', '\b', #ifdef EBCDIC_CHARSET 0x27, /* Escape character in IBM's EBCDIC character set. */ #else 0x1B, /* Escape character in ASCII character set. */ #endif '\f', '\n', '\r', '\t', '\v', '\0' }; static unsigned char valid_escape [] = { 'a', 'b', 'f', 'n', 'r', 't', 'v', '(', ')', '[', ']', '<', '>', '.', '\\', '|', '^', '$', '*', '+', '?', '&', '\"', '\0' }; static unsigned char value [] = { '\a', '\b', '\f', '\n', '\r', '\t', '\v', '(', ')', '[', ']', '<', '>', '.', '\\', '|', '^', '$', '*', '+', '?', '&', '\"', '\0' }; int i; if (action == 0) { for (i = 0; valid_escape [i] != '\0'; i++) { if (c == valid_escape [i]) return value [i]; } } else if (action == 1) { for (i = 0; control_actual [i] != '\0'; i++) { if (c == control_actual [i]) { return control_escape [i]; } } } if (action == 1) { if (!isprint (c)) { /* Signal to generate an numeric (octal) escape. */ return '0'; } } return 0; } /*----------------------------------------------------------------------* * ConvertSubstituteRE - Perform substitutions after a `regexp' match. *----------------------------------------------------------------------*/ void ConvertSubstituteRE ( const char *source, char *dest, int max) { register unsigned char *src; register unsigned char *dst; register unsigned char c; register unsigned char test; if (source == NULL || dest == NULL) { reg_error ("NULL parm to `ConvertSubstituteRE\'"); return; } src = (unsigned char *) source; dst = (unsigned char *) dest; while ((c = *src++) != '\0') { if (c == '\\') { /* Process any case altering tokens, i.e \u, \U, \l, \L. */ if (*src == 'u' || *src == 'U' || *src == 'l' || *src == 'L') { *dst++ = '\\'; c = *src++; *dst++ = c; if (c == '\0') { break; } else { c = *src++; } } } if (c == '&') { *dst++ = '&'; } else if (c == '\\') { if (*src == '0') { /* Convert `\0' to `&' */ *dst++ = '&'; src++; } else if ('1' <= *src && *src <= '9') { *dst++ = '\\'; *dst++ = *src++; } else if ((test = literal_escape (*src, 0)) != '\0') { *dst++ = '\\'; *dst++ = *src++; } else if (*src == '\0') { /* If '\' is the last character of the replacement string, it is interpreted as a literal backslash. */ *dst++ = '\\'; } else { /* Old regex's allowed any escape sequence. Convert these to unescaped characters that replace themselves; i.e. they don't need to be escaped. */ *dst++ = *src++; } } else { /* Ordinary character. */ if (((char *) dst - (char *) dest) >= (max - 1)) { break; } else { if ((test = literal_escape (c, 1))) { /* Ordinary character matches an escape sequence; convert it to the escape sequence. */ *dst++ = '\\'; if (test == '0') { /* Make octal escape. */ test = c; *dst++ = '0'; *dst++ = ('0' + (test / 64)); test -= (test / 64) * 64; *dst++ = ('0' + (test / 8)); test -= (test / 8) * 8; *dst++ = ('0' + test); } else { *dst++ = test; } } else { *dst++ = c; } } } } *dst = '\0'; } /*----------------------------------------------------------------------* * reg_error *----------------------------------------------------------------------*/ static void reg_error (char *str) { fprintf ( stderr, "NEdit: Internal error processing regular expression (%s)\n", str); } nedit-5.6.orig/source/regexConvert.h0000644000175000017500000000443310144236624016244 0ustar paulpaul/* $Id: regexConvert.h,v 1.7 2004/11/09 21:58:44 yooden Exp $ */ /******************************************************************************* * * * regexConvert.h -- Nirvana Editor Regex Conversion Header File * * * * Copyright 2003 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_REGEXCONVERT_H_INCLUDED #define NEDIT_REGEXCONVERT_H_INCLUDED char *ConvertRE(const char *exp, char **errorText); void ConvertSubstituteRE(const char *source, char *dest, int max); #endif /* NEDIT_REGEXCONVERT_H_INCLUDED */ nedit-5.6.orig/source/regularExp.c0000644000175000017500000044424610762110532015707 0ustar paulpaulstatic const char CVSID[] = "$Id: regularExp.c,v 1.33 2008/02/29 23:12:26 lebert Exp $"; /*------------------------------------------------------------------------* * `CompileRE', `ExecRE', and `substituteRE' -- regular expression parsing * * This is a HIGHLY ALTERED VERSION of Henry Spencer's `regcomp' and * `regexec' code adapted for NEdit. * * .-------------------------------------------------------------------. * | ORIGINAL COPYRIGHT NOTICE: | * | | * | Copyright (c) 1986 by University of Toronto. | * | Written by Henry Spencer. Not derived from licensed software. | * | | * | Permission is granted to anyone to use this software for any | * | purpose on any computer system, and to redistribute it freely, | * | subject to the following restrictions: | * | | * | 1. The author is not responsible for the consequences of use of | * | this software, no matter how awful, even if they arise | * | from defects in it. | * | | * | 2. The origin of this software must not be misrepresented, either | * | by explicit claim or by omission. | * | | * | 3. Altered versions must be plainly marked as such, and must not | * | be misrepresented as being the original software. | * `-------------------------------------------------------------------' * * This is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. In addition, you may distribute version of this program linked to * Motif or Open Motif. See README for details. * * This software is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along with * software; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA * * * BEWARE that some of this code is subtly aware of the way operator * precedence is structured in regular expressions. Serious changes in * regular-expression syntax might require a total rethink. * -- Henry Spencer * (Yes, it did!) -- Christopher Conrad, Dec. 1999 * * January, 1994, Mark Edel * Consolidated files, changed names of external functions to avoid * potential conflicts with native regcomp and regexec functions, changed * error reporting to NEdit form, added multi-line and reverse searching, * and added \n \t \u \U \l \L. * * June, 1996, Mark Edel * Bug in NEXT macro, didn't work for expressions which compiled to over * 256 bytes. * * December, 1999, Christopher Conrad * Reformatted code for readability, improved error output, added octal and * hexadecimal escapes, added back-references (\1-\9), added positive look * ahead: (?=...), added negative lookahead: (?!...), added non-capturing * parentheses: (?:...), added case insensitive constructs (?i...) and * (?I...), added newline matching constructs (?n...) and (?N...), added * regex comments: (?#...), added shortcut escapes: \d\D\l\L\s\S\w\W\y\Y. * Added "not a word boundary" anchor \B. * * July, 2002, Eddy De Greef * Added look behind, both positive (?<=...) and negative (? #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif /* The first byte of the regexp internal `program' is a magic number to help gaurd against corrupted data; the compiled regex code really begins in the second byte. */ #define MAGIC 0234 /* The "internal use only" fields in `regexp.h' are present to pass info from * `CompileRE' to `ExecRE' which permits the execute phase to run lots faster on * simple cases. They are: * * match_start Character that must begin a match; '\0' if none obvious. * anchor Is the match anchored (at beginning-of-line only)? * * `match_start' and `anchor' permit very fast decisions on suitable starting * points for a match, considerably reducing the work done by ExecRE. */ /* STRUCTURE FOR A REGULAR EXPRESSION (regex) `PROGRAM'. * * This is essentially a linear encoding of a nondeterministic finite-state * machine or NFA (aka syntax charts or `railroad normal form' in parsing * technology). Each node is an opcode plus a NEXT pointer, possibly * followed by operands. NEXT pointers of all nodes except BRANCH implement * concatenation; a NEXT pointer with a BRANCH on both ends of it is * connecting two alternatives. (Here we have one of the subtle syntax * dependencies: an individual BRANCH (as opposed to a collection of them) is * never concatenated with anything because of operator precedence.) The * operand of some types of nodes is a literal string; for others, it is a node * leading into a sub-FSM. In particular, the operand of a BRANCH node is the * first node of the branch. (NB this is _NOT_ a tree structure: the tail of * the branch connects to the thing following the set of BRANCHes.) * * The opcodes are: */ /* DEFINITION VALUE MEANING */ #define END 1 /* End of program. */ /* Zero width positional assertions. */ #define BOL 2 /* Match position at beginning of line. */ #define EOL 3 /* Match position at end of line. */ #define BOWORD 4 /* Match "" representing word delimiter or BOL */ #define EOWORD 5 /* Match "" representing word delimiter or EOL */ #define NOT_BOUNDARY 6 /* Not word boundary (\B, opposite of < and >) */ /* Op codes with null terminated string operands. */ #define EXACTLY 7 /* Match this string. */ #define SIMILAR 8 /* Match this case insensitive string */ #define ANY_OF 9 /* Match any character in the set. */ #define ANY_BUT 10 /* Match any character not in the set. */ /* Op codes to match any character. */ #define ANY 11 /* Match any one character (implements '.') */ #define EVERY 12 /* Same as ANY but matches newline. */ /* Shortcut escapes, \d, \D, \l, \L, \s, \S, \w, \W, \y, \Y. */ #define DIGIT 13 /* Match any digit, i.e. [0123456789] */ #define NOT_DIGIT 14 /* Match any non-digit, i.e. [^0123456789] */ #define LETTER 15 /* Match any letter character [a-zA-Z] */ #define NOT_LETTER 16 /* Match any non-letter character [^a-zA-Z] */ #define SPACE 17 /* Match any whitespace character EXCEPT \n */ #define SPACE_NL 18 /* Match any whitespace character INCLUDING \n */ #define NOT_SPACE 19 /* Match any non-whitespace character */ #define NOT_SPACE_NL 20 /* Same as NOT_SPACE but matches newline. */ #define WORD_CHAR 21 /* Match any word character [a-zA-Z0-9_] */ #define NOT_WORD_CHAR 22 /* Match any non-word character [^a-zA-Z0-9_] */ #define IS_DELIM 23 /* Match any character that's a word delimiter */ #define NOT_DELIM 24 /* Match any character NOT a word delimiter */ /* Quantifier nodes. (Only applied to SIMPLE nodes. Quantifiers applied to non SIMPLE nodes or larger atoms are implemented using complex constructs.)*/ #define STAR 25 /* Match this (simple) thing 0 or more times. */ #define LAZY_STAR 26 /* Minimal matching STAR */ #define QUESTION 27 /* Match this (simple) thing 0 or 1 times. */ #define LAZY_QUESTION 28 /* Minimal matching QUESTION */ #define PLUS 29 /* Match this (simple) thing 1 or more times. */ #define LAZY_PLUS 30 /* Minimal matching PLUS */ #define BRACE 31 /* Match this (simple) thing m to n times. */ #define LAZY_BRACE 32 /* Minimal matching BRACE */ /* Nodes used to build complex constructs. */ #define NOTHING 33 /* Match empty string (always matches) */ #define BRANCH 34 /* Match this alternative, or the next... */ #define BACK 35 /* Always matches, NEXT ptr points backward. */ #define INIT_COUNT 36 /* Initialize {m,n} counter to zero */ #define INC_COUNT 37 /* Increment {m,n} counter by one */ #define TEST_COUNT 38 /* Test {m,n} counter against operand */ /* Back Reference nodes. */ #define BACK_REF 39 /* Match latest matched parenthesized text */ #define BACK_REF_CI 40 /* Case insensitive version of BACK_REF */ #define X_REGEX_BR 41 /* Cross-Regex Back-Ref for syntax highlighting */ #define X_REGEX_BR_CI 42 /* Case insensitive version of X_REGEX_BR_CI */ /* Various nodes used to implement parenthetical constructs. */ #define POS_AHEAD_OPEN 43 /* Begin positive look ahead */ #define NEG_AHEAD_OPEN 44 /* Begin negative look ahead */ #define LOOK_AHEAD_CLOSE 45 /* End positive or negative look ahead */ #define POS_BEHIND_OPEN 46 /* Begin positive look behind */ #define NEG_BEHIND_OPEN 47 /* Begin negative look behind */ #define LOOK_BEHIND_CLOSE 48 /* Close look behind */ #define OPEN 49 /* Open for capturing parentheses. */ /* OPEN+1 is number 1, etc. */ #define CLOSE (OPEN + NSUBEXP) /* Close for capturing parentheses. */ #define LAST_PAREN (CLOSE + NSUBEXP) #if (LAST_PAREN > UCHAR_MAX) #error "Too many parentheses for storage in an unsigned char (LAST_PAREN too big.)" #endif /* The next_ptr () function can consume up to 30% of the time during matching because it is called an immense number of times (an average of 25 next_ptr() calls per match() call was witnessed for Perl syntax highlighting). Therefore it is well worth removing some of the function call overhead by selectively inlining the next_ptr() calls. Moreover, the inlined code can be simplified for matching because one of the tests, only necessary during compilation, can be left out. The net result of using this inlined version at two critical places is a 25% speedup (again, witnesses on Perl syntax highlighting). */ #define NEXT_PTR(in_ptr, out_ptr)\ next_ptr_offset = GET_OFFSET (in_ptr);\ if (next_ptr_offset == 0)\ out_ptr = NULL;\ else {\ if (GET_OP_CODE (in_ptr) == BACK)\ out_ptr = in_ptr - next_ptr_offset;\ else \ out_ptr = in_ptr + next_ptr_offset;\ } /* OPCODE NOTES: ------------ All nodes consist of an 8 bit op code followed by 2 bytes that make up a 16 bit NEXT pointer. Some nodes have a null terminated character string operand following the NEXT pointer. Other nodes may have an 8 bit index operand. The TEST_COUNT node has an index operand followed by a 16 bit test value. The BRACE and LAZY_BRACE nodes have two 16 bit values for min and max but no index value. SIMILAR Operand(s): null terminated string Implements a case insensitive match of a string. Mostly intended for use in syntax highlighting patterns for keywords of languages like FORTRAN and Ada that are case insensitive. The regex text in this node is converted to lower case during regex compile. DIGIT, NOT_DIGIT, LETTER, NOT_LETTER, SPACE, NOT_SPACE, WORD_CHAR, NOT_WORD_CHAR Operand(s): None Implements shortcut escapes \d, \D, \l, \L, \s, \S, \w, \W. The locale aware ANSI functions isdigit(), isalpha(), isalnun(), and isspace() are used to implement these in the hopes of increasing portability. NOT_BOUNDARY Operand(s): None Implements \B as a zero width assertion that the current character is NOT on a word boundary. Word boundaries are defined to be the position between two characters where one of those characters is one of the dynamically defined word delimiters, and the other character is not. IS_DELIM Operand(s): None Implements \y as any character that is one of the dynamically specified word delimiters. NOT_DELIM Operand(s): None Implements \Y as any character that is NOT one of the dynamically specified word delimiters. STAR, PLUS, QUESTION, and complex '*', '+', and '?' Operand(s): None (Note: NEXT pointer is usually zero. The code that processes this node skips over it.) Complex (parenthesized) versions implemented as circular BRANCH structures using BACK. SIMPLE versions (one character per match) are implemented separately for speed and to minimize recursion. BRACE, LAZY_BRACE Operand(s): minimum value (2 bytes), maximum value (2 bytes) Implements the {m,n} construct for atoms that are SIMPLE. BRANCH Operand(s): None The set of branches constituting a single choice are hooked together with their NEXT pointers, since precedence prevents anything being concatenated to any individual branch. The NEXT pointer of the last BRANCH in a choice points to the thing following the whole choice. This is also where the final NEXT pointer of each individual branch points; each branch starts with the operand node of a BRANCH node. BACK Operand(s): None Normal NEXT pointers all implicitly point forward. Back implicitly points backward. BACK exists to make loop structures possible. INIT_COUNT Operand(s): index (1 byte) Initializes the count array element referenced by the index operand. This node is used to build general (i.e. parenthesized) {m,n} constructs. INC_COUNT Operand(s): index (1 byte) Increments the count array element referenced by the index operand. This node is used to build general (i.e. parenthesized) {m,n} constructs. TEST_COUNT Operand(s): index (1 byte), test value (2 bytes) Tests the current value of the count array element specified by the index operand against the test value. If the current value is less than the test value, control passes to the node after that TEST_COUNT node. Otherwise control passes to the node referenced by the NEXT pointer for the TEST_COUNT node. This node is used to build general (i.e. parenthesized) {m,n} constructs. BACK_REF, BACK_REF_CI Operand(s): index (1 byte, value 1-9) Implements back references. This node will attempt to match whatever text was most recently captured by the index'th set of parentheses. BACK_REF_CI is case insensitive version. X_REGEX_BR, X_REGEX_BR_CI (NOT IMPLEMENTED YET) Operand(s): index (1 byte, value 1-9) Implements back references into a previously matched but separate regular expression. This is used by syntax highlighting patterns. This node will attempt to match whatever text was most captured by the index'th set of parentheses of the separate regex passed to ExecRE. X_REGEX_BR_CI is case insensitive version. POS_AHEAD_OPEN, NEG_AHEAD_OPEN, LOOK_AHEAD_CLOSE Operand(s): None Implements positive and negative look ahead. Look ahead is an assertion that something is either there or not there. Once this is determined the regex engine backtracks to where it was just before the look ahead was encountered, i.e. look ahead is a zero width assertion. POS_BEHIND_OPEN, NEG_BEHIND_OPEN, LOOK_BEHIND_CLOSE Operand(s): 2x2 bytes for OPEN (match boundaries), None for CLOSE Implements positive and negative look behind. Look behind is an assertion that something is either there or not there in front of the current position. Look behind is a zero width assertion, with the additional constraint that it must have a bounded length (for complexity and efficiency reasons; note that most other implementation even impose fixed length). OPEN, CLOSE Operand(s): None OPEN + n = Start of parenthesis 'n', CLOSE + n = Close of parenthesis 'n', and are numbered at compile time. */ /* A node is one char of opcode followed by two chars of NEXT pointer plus * any operands. NEXT pointers are stored as two 8-bit pieces, high order * first. The value is a positive offset from the opcode of the node * containing it. An operand, if any, simply follows the node. (Note that * much of the code generation knows about this implicit relationship.) * * Using two bytes for NEXT_PTR_SIZE is vast overkill for most things, * but allows patterns to get big without disasters. */ #define OP_CODE_SIZE 1 #define NEXT_PTR_SIZE 2 #define INDEX_SIZE 1 #define LENGTH_SIZE 4 #define NODE_SIZE (NEXT_PTR_SIZE + OP_CODE_SIZE) #define GET_OP_CODE(p) (*(unsigned char *)(p)) #define OPERAND(p) ((p) + NODE_SIZE) #define GET_OFFSET(p) ((( *((p) + 1) & 0377) << 8) + (( *((p) + 2)) & 0377)) #define PUT_OFFSET_L(v) (unsigned char)(((v) >> 8) & 0377) #define PUT_OFFSET_R(v) (unsigned char) ((v) & 0377) #define GET_LOWER(p) ((( *((p) + NODE_SIZE) & 0377) << 8) + \ (( *((p) + NODE_SIZE+1)) & 0377)) #define GET_UPPER(p) ((( *((p) + NODE_SIZE+2) & 0377) << 8) + \ (( *((p) + NODE_SIZE+3)) & 0377)) /* Utility definitions. */ #define REG_FAIL(m) {*Error_Ptr = (m); return (NULL);} #define IS_QUANTIFIER(c) ((c) == '*' || (c) == '+' || \ (c) == '?' || (c) == Brace_Char) #define SET_BIT(i,n) ((i) |= (1 << ((n) - 1))) #define TEST_BIT(i,n) ((i) & (1 << ((n) - 1))) #define U_CHAR_AT(p) ((unsigned int) *(unsigned char *)(p)) /* Flags to be passed up and down via function parameters during compile. */ #define WORST 0 /* Worst case. No assumptions can be made.*/ #define HAS_WIDTH 1 /* Known never to match null string. */ #define SIMPLE 2 /* Simple enough to be STAR/PLUS operand. */ #define NO_PAREN 0 /* Only set by initial call to "chunk". */ #define PAREN 1 /* Used for normal capturing parentheses. */ #define NO_CAPTURE 2 /* Non-capturing parentheses (grouping only). */ #define INSENSITIVE 3 /* Case insensitive parenthetical construct */ #define SENSITIVE 4 /* Case sensitive parenthetical construct */ #define NEWLINE 5 /* Construct to match newlines in most cases */ #define NO_NEWLINE 6 /* Construct to match newlines normally */ #define REG_INFINITY 0UL #define REG_ZERO 0UL #define REG_ONE 1UL /* Flags for function shortcut_escape() */ #define CHECK_ESCAPE 0 /* Check an escape sequence for validity only. */ #define CHECK_CLASS_ESCAPE 1 /* Check the validity of an escape within a character class */ #define EMIT_CLASS_BYTES 2 /* Emit equivalent character class bytes, e.g \d=0123456789 */ #define EMIT_NODE 3 /* Emit the appropriate node. */ /* Array sizes for arrays used by function init_ansi_classes. */ #define WHITE_SPACE_SIZE 16 #define ALNUM_CHAR_SIZE 256 /* Number of bytes to offset from the beginning of the regex program to the start of the actual compiled regex code, i.e. skipping over the MAGIC number and the two counters at the front. */ #define REGEX_START_OFFSET 3 #define MAX_COMPILED_SIZE 32767UL /* Largest size a compiled regex can be. Probably could be 65535UL. */ /* Global work variables for `CompileRE'. */ static unsigned char *Reg_Parse; /* Input scan ptr (scans user's regex) */ static int Total_Paren; /* Parentheses, (), counter. */ static int Num_Braces; /* Number of general {m,n} constructs. {m,n} quantifiers of SIMPLE atoms are not included in this count. */ static int Closed_Parens; /* Bit flags indicating () closure. */ static int Paren_Has_Width; /* Bit flags indicating ()'s that are known to not match the empty string */ static unsigned char Compute_Size; /* Address of this used as flag. */ static unsigned char *Code_Emit_Ptr; /* When Code_Emit_Ptr is set to &Compute_Size no code is emitted. Instead, the size of code that WOULD have been generated is accumulated in Reg_Size. Otherwise, Code_Emit_Ptr points to where compiled regex code is to be written. */ static unsigned long Reg_Size; /* Size of compiled regex code. */ static char **Error_Ptr; /* Place to store error messages so they can be returned by `CompileRE' */ static char Error_Text [128];/* Sting to build error messages in. */ static unsigned char White_Space [WHITE_SPACE_SIZE]; /* Arrays used by */ static unsigned char Word_Char [ALNUM_CHAR_SIZE]; /* functions */ static unsigned char Letter_Char [ALNUM_CHAR_SIZE]; /* init_ansi_classes () */ /* and shortcut_escape (). */ static unsigned char ASCII_Digits [] = "0123456789"; /* Same for all */ /* locales. */ static int Is_Case_Insensitive; static int Match_Newline; static int Enable_Counting_Quantifier = 1; static unsigned char Brace_Char; static unsigned char Default_Meta_Char [] = "{.*+?[(|)^<>$"; static unsigned char *Meta_Char; typedef struct { long lower; long upper; } len_range; /* Forward declarations for functions used by `CompileRE'. */ static unsigned char * alternative (int *flag_param, len_range *range_param); static unsigned char * back_ref (unsigned char *c, int *flag_param, int emit); static unsigned char * chunk (int paren, int *flag_param, len_range *range_param); static void emit_byte (unsigned char c); static void emit_class_byte (unsigned char c); static unsigned char * emit_node (int op_code); static unsigned char * emit_special (unsigned char op_code, unsigned long test_val, int index); static unsigned char literal_escape (unsigned char c); static unsigned char numeric_escape (unsigned char c, unsigned char **parse); static unsigned char * atom (int *flag_param, len_range *range_param); static void reg_error (char *str); static unsigned char * insert (unsigned char op, unsigned char *opnd, long min, long max, int index); static unsigned char * next_ptr (unsigned char *ptr); static void offset_tail (unsigned char *ptr, int offset, unsigned char *val); static void branch_tail (unsigned char *ptr, int offset, unsigned char *val); static unsigned char * piece (int *flag_param, len_range *range_param); static void tail (unsigned char *search_from, unsigned char *point_t); static unsigned char * shortcut_escape (unsigned char c, int *flag_param, int emit); static int init_ansi_classes (void); /*----------------------------------------------------------------------* * CompileRE * * Compiles a regular expression into the internal format used by * `ExecRE'. * * The default behaviour wrt. case sensitivity and newline matching can * be controlled through the defaultFlags argument (Markus Schwarzenberg). * Future extensions are possible by using other flag bits. * Note that currently only the case sensitivity flag is effectively used. * * Beware that the optimization and preparation code in here knows about * some of the structure of the compiled regexp. *----------------------------------------------------------------------*/ regexp * CompileRE (const char *exp, char **errorText, int defaultFlags) { register regexp *comp_regex = NULL; register unsigned char *scan; int flags_local, pass; len_range range_local; if (Enable_Counting_Quantifier) { Brace_Char = '{'; Meta_Char = &Default_Meta_Char [0]; } else { Brace_Char = '*'; /* Bypass the '{' in */ Meta_Char = &Default_Meta_Char [1]; /* Default_Meta_Char */ } /* Set up errorText to receive failure reports. */ Error_Ptr = errorText; *Error_Ptr = ""; if (exp == NULL) REG_FAIL ("NULL argument, `CompileRE\'"); /* Initialize arrays used by function `shortcut_escape'. */ if (!init_ansi_classes ()) REG_FAIL ("internal error #1, `CompileRE\'"); Code_Emit_Ptr = &Compute_Size; Reg_Size = 0UL; /* We can't allocate space until we know how big the compiled form will be, but we can't compile it (and thus know how big it is) until we've got a place to put the code. So we cheat: we compile it twice, once with code generation turned off and size counting turned on, and once "for real". This also means that we don't allocate space until we are sure that the thing really will compile successfully, and we never have to move the code and thus invalidate pointers into it. (Note that it has to be in one piece because free() must be able to free it all.) */ for (pass = 1; pass <= 2; pass++) { /*-------------------------------------------* * FIRST PASS: Determine size and legality. * * SECOND PASS: Emit code. * *-------------------------------------------*/ /* Schwarzenberg: * If defaultFlags = 0 use standard defaults: * Is_Case_Insensitive: Case sensitive is the default * Match_Newline: Newlines are NOT matched by default * in character classes */ Is_Case_Insensitive = ((defaultFlags & REDFLT_CASE_INSENSITIVE) ? 1 : 0); Match_Newline = 0; /* ((defaultFlags & REDFLT_MATCH_NEWLINE) ? 1 : 0); Currently not used. Uncomment if needed. */ Reg_Parse = (unsigned char *) exp; Total_Paren = 1; Num_Braces = 0; Closed_Parens = 0; Paren_Has_Width = 0; emit_byte (MAGIC); emit_byte ('%'); /* Placeholder for num of capturing parentheses. */ emit_byte ('%'); /* Placeholder for num of general {m,n} constructs. */ if (chunk (NO_PAREN, &flags_local, &range_local) == NULL) return (NULL); /* Something went wrong */ if (pass == 1) { if (Reg_Size >= MAX_COMPILED_SIZE) { /* Too big for NEXT pointers NEXT_PTR_SIZE bytes long to span. This is a real issue since the first BRANCH node usually points to the end of the compiled regex code. */ sprintf (Error_Text, "regexp > %lu bytes", MAX_COMPILED_SIZE); REG_FAIL (Error_Text); } /* Allocate memory. */ comp_regex = (regexp *) malloc (sizeof (regexp) + Reg_Size); if (comp_regex == NULL) REG_FAIL ("out of memory in `CompileRE\'"); Code_Emit_Ptr = (unsigned char *) comp_regex->program; } } comp_regex->program [1] = (unsigned char) Total_Paren - 1; comp_regex->program [2] = (unsigned char) Num_Braces; /*----------------------------------------* * Dig out information for optimizations. * *----------------------------------------*/ comp_regex->match_start = '\0'; /* Worst-case defaults. */ comp_regex->anchor = 0; /* First BRANCH. */ scan = (unsigned char *) (comp_regex->program + REGEX_START_OFFSET); if (GET_OP_CODE (next_ptr (scan)) == END) { /* Only one top-level choice. */ scan = OPERAND (scan); /* Starting-point info. */ if (GET_OP_CODE (scan) == EXACTLY) { comp_regex->match_start = *OPERAND (scan); } else if (PLUS <= GET_OP_CODE (scan) && GET_OP_CODE (scan) <= LAZY_PLUS) { /* Allow x+ or x+? at the start of the regex to be optimized. */ if (GET_OP_CODE (scan + NODE_SIZE) == EXACTLY) { comp_regex->match_start = *OPERAND (scan + NODE_SIZE); } } else if (GET_OP_CODE (scan) == BOL) { comp_regex->anchor++; } } return (comp_regex); } /*----------------------------------------------------------------------* * chunk * * * * Process main body of regex or process a parenthesized "thing". * * * * Caller must absorb opening parenthesis. * * * * Combining parenthesis handling with the base level of regular * * expression is a trifle forced, but the need to tie the tails of the * * branches to what follows makes it hard to avoid. * *----------------------------------------------------------------------*/ static unsigned char * chunk (int paren, int *flag_param, len_range *range_param) { register unsigned char *ret_val = NULL; register unsigned char *this_branch; register unsigned char *ender = NULL; register int this_paren = 0; int flags_local, first = 1, zero_width, i; int old_sensitive = Is_Case_Insensitive; int old_newline = Match_Newline; len_range range_local; int look_only = 0; unsigned char *emit_look_behind_bounds = NULL; *flag_param = HAS_WIDTH; /* Tentatively. */ range_param->lower = 0; /* Idem */ range_param->upper = 0; /* Make an OPEN node, if parenthesized. */ if (paren == PAREN) { if (Total_Paren >= NSUBEXP) { sprintf (Error_Text, "number of ()'s > %d", (int) NSUBEXP); REG_FAIL (Error_Text); } this_paren = Total_Paren; Total_Paren++; ret_val = emit_node (OPEN + this_paren); } else if (paren == POS_AHEAD_OPEN || paren == NEG_AHEAD_OPEN) { *flag_param = WORST; /* Look ahead is zero width. */ look_only = 1; ret_val = emit_node (paren); } else if (paren == POS_BEHIND_OPEN || paren == NEG_BEHIND_OPEN) { *flag_param = WORST; /* Look behind is zero width. */ look_only = 1; /* We'll overwrite the zero length later on, so we save the ptr */ ret_val = emit_special (paren, 0, 0); emit_look_behind_bounds = ret_val + NODE_SIZE; } else if (paren == INSENSITIVE) { Is_Case_Insensitive = 1; } else if (paren == SENSITIVE) { Is_Case_Insensitive = 0; } else if (paren == NEWLINE) { Match_Newline = 1; } else if (paren == NO_NEWLINE) { Match_Newline = 0; } /* Pick up the branches, linking them together. */ do { this_branch = alternative (&flags_local, &range_local); if (this_branch == NULL) return (NULL); if (first) { first = 0; *range_param = range_local; if (ret_val == NULL) ret_val = this_branch; } else if (range_param->lower >= 0) { if (range_local.lower >= 0) { if (range_local.lower < range_param->lower) range_param->lower = range_local.lower; if (range_local.upper > range_param->upper) range_param->upper = range_local.upper; } else { range_param->lower = -1; /* Branches have different lengths */ range_param->upper = -1; } } tail (ret_val, this_branch); /* Connect BRANCH -> BRANCH. */ /* If any alternative could be zero width, consider the whole parenthisized thing to be zero width. */ if (!(flags_local & HAS_WIDTH)) *flag_param &= ~HAS_WIDTH; /* Are there more alternatives to process? */ if (*Reg_Parse != '|') break; Reg_Parse++; } while (1); /* Make a closing node, and hook it on the end. */ if (paren == PAREN) { ender = emit_node (CLOSE + this_paren); } else if (paren == NO_PAREN) { ender = emit_node (END); } else if (paren == POS_AHEAD_OPEN || paren == NEG_AHEAD_OPEN) { ender = emit_node (LOOK_AHEAD_CLOSE); } else if (paren == POS_BEHIND_OPEN || paren == NEG_BEHIND_OPEN) { ender = emit_node (LOOK_BEHIND_CLOSE); } else { ender = emit_node (NOTHING); } tail (ret_val, ender); /* Hook the tails of the branch alternatives to the closing node. */ for (this_branch = ret_val; this_branch != NULL; ) { branch_tail (this_branch, NODE_SIZE, ender); this_branch = next_ptr (this_branch); } /* Check for proper termination. */ if (paren != NO_PAREN && *Reg_Parse++ != ')') { REG_FAIL ("missing right parenthesis \')\'"); } else if (paren == NO_PAREN && *Reg_Parse != '\0') { if (*Reg_Parse == ')') { REG_FAIL ("missing left parenthesis \'(\'"); } else { REG_FAIL ("junk on end"); /* "Can't happen" - NOTREACHED */ } } /* Check whether look behind has a fixed size */ if (emit_look_behind_bounds) { if (range_param->lower < 0) { REG_FAIL ("look-behind does not have a bounded size"); } if (range_param->upper > 65535L) { REG_FAIL ("max. look-behind size is too large (>65535)") } if (Code_Emit_Ptr != &Compute_Size) { *emit_look_behind_bounds++ = PUT_OFFSET_L (range_param->lower); *emit_look_behind_bounds++ = PUT_OFFSET_R (range_param->lower); *emit_look_behind_bounds++ = PUT_OFFSET_L (range_param->upper); *emit_look_behind_bounds = PUT_OFFSET_R (range_param->upper); } } /* For look ahead/behind, the length must be set to zero again */ if (look_only) { range_param->lower = 0; range_param->upper = 0; } zero_width = 0; /* Set a bit in Closed_Parens to let future calls to function `back_ref' know that we have closed this set of parentheses. */ if (paren == PAREN && this_paren <= (int)sizeof (Closed_Parens) * CHAR_BIT) { SET_BIT (Closed_Parens, this_paren); /* Determine if a parenthesized expression is modified by a quantifier that can have zero width. */ if (*(Reg_Parse) == '?' || *(Reg_Parse) == '*') { zero_width++; } else if (*(Reg_Parse) == '{' && Brace_Char == '{') { if (*(Reg_Parse + 1) == ',' || *(Reg_Parse + 1) == '}') { zero_width++; } else if (*(Reg_Parse + 1) == '0') { i = 2; while (*(Reg_Parse + i) == '0') i++; if (*(Reg_Parse + i) == ',') zero_width++; } } } /* If this set of parentheses is known to never match the empty string, set a bit in Paren_Has_Width to let future calls to function back_ref know that this set of parentheses has non-zero width. This will allow star (*) or question (?) quantifiers to be aplied to a back-reference that refers to this set of parentheses. */ if ((*flag_param & HAS_WIDTH) && paren == PAREN && !zero_width && this_paren <= (int)(sizeof (Paren_Has_Width) * CHAR_BIT)) { SET_BIT (Paren_Has_Width, this_paren); } Is_Case_Insensitive = old_sensitive; Match_Newline = old_newline; return (ret_val); } /*----------------------------------------------------------------------* * alternative * * Processes one alternative of an '|' operator. Connects the NEXT * pointers of each regex atom together sequentialy. *----------------------------------------------------------------------*/ static unsigned char * alternative (int *flag_param, len_range *range_param) { register unsigned char *ret_val; register unsigned char *chain; register unsigned char *latest; int flags_local; len_range range_local; *flag_param = WORST; /* Tentatively. */ range_param->lower = 0; /* Idem */ range_param->upper = 0; ret_val = emit_node (BRANCH); chain = NULL; /* Loop until we hit the start of the next alternative, the end of this set of alternatives (end of parentheses), or the end of the regex. */ while (*Reg_Parse != '|' && *Reg_Parse != ')' && *Reg_Parse != '\0') { latest = piece (&flags_local, &range_local); if (latest == NULL) return (NULL); /* Something went wrong. */ *flag_param |= flags_local & HAS_WIDTH; if (range_local.lower < 0) { /* Not a fixed length */ range_param->lower = -1; range_param->upper = -1; } else if (range_param->lower >= 0) { range_param->lower += range_local.lower; range_param->upper += range_local.upper; } if (chain != NULL) { /* Connect the regex atoms together sequentialy. */ tail (chain, latest); } chain = latest; } if (chain == NULL) { /* Loop ran zero times. */ (void) emit_node (NOTHING); } return (ret_val); } /*----------------------------------------------------------------------* * piece - something followed by possible '*', '+', '?', or "{m,n}" * * Note that the branching code sequences used for the general cases of * *, +. ?, and {m,n} are somewhat optimized: they use the same * NOTHING node as both the endmarker for their branch list and the * body of the last branch. It might seem that this node could be * dispensed with entirely, but the endmarker role is not redundant. *----------------------------------------------------------------------*/ static unsigned char * piece (int *flag_param, len_range *range_param) { register unsigned char *ret_val; register unsigned char *next; register unsigned char op_code; unsigned long min_max [2] = {REG_ZERO, REG_INFINITY}; int flags_local, i, brace_present = 0; int lazy = 0, comma_present = 0; int digit_present [2] = {0,0}; len_range range_local; ret_val = atom (&flags_local, &range_local); if (ret_val == NULL) return (NULL); /* Something went wrong. */ op_code = *Reg_Parse; if (!IS_QUANTIFIER (op_code)) { *flag_param = flags_local; *range_param = range_local; return (ret_val); } else if (op_code == '{') { /* {n,m} quantifier present */ brace_present++; Reg_Parse++; /* This code will allow specifying a counting range in any of the following forms: {m,n} between m and n. {,n} same as {0,n} or between 0 and infinity. {m,} same as {m,0} or between m and infinity. {m} same as {m,m} or exactly m. {,} same as {0,0} or between 0 and infinity or just '*'. {} same as {0,0} or between 0 and infinity or just '*'. Note that specifying a max of zero, {m,0} is not allowed in the regex itself, but it is implemented internally that way to support '*', '+', and {min,} constructs and signals an unlimited number. */ for (i = 0; i < 2; i++) { /* Look for digits of number and convert as we go. The numeric maximum value for max and min of 65,535 is due to using 2 bytes to store each value in the compiled regex code. */ while (isdigit (*Reg_Parse)) { /* (6553 * 10 + 6) > 65535 (16 bit max) */ if ((min_max [i] == 6553UL && (*Reg_Parse - '0') <= 5) || (min_max [i] <= 6552UL)) { min_max [i] = (min_max [i] * 10UL) + (unsigned long) (*Reg_Parse - '0'); Reg_Parse++; digit_present [i]++; } else { if (i == 0) { sprintf (Error_Text, "min operand of {%lu%c,???} > 65535", min_max [0], *Reg_Parse); } else { sprintf (Error_Text, "max operand of {%lu,%lu%c} > 65535", min_max [0], min_max [1], *Reg_Parse); } REG_FAIL (Error_Text); } } if (!comma_present && *Reg_Parse == ',') { comma_present++; Reg_Parse++; } } /* A max of zero can not be specified directly in the regex since it would signal a max of infinity. This code specifically disallows `{0,0}', `{,0}', and `{0}' which really means nothing to humans but would be interpreted as `{0,infinity}' or `*' if we didn't make this check. */ if (digit_present [0] && (min_max [0] == REG_ZERO) && !comma_present) { REG_FAIL ("{0} is an invalid range"); } else if (digit_present [0] && (min_max [0] == REG_ZERO) && digit_present [1] && (min_max [1] == REG_ZERO)) { REG_FAIL ("{0,0} is an invalid range"); } else if (digit_present [1] && (min_max [1] == REG_ZERO)) { if (digit_present [0]) { sprintf (Error_Text, "{%lu,0} is an invalid range", min_max [0]); REG_FAIL (Error_Text); } else { REG_FAIL ("{,0} is an invalid range"); } } if (!comma_present) min_max [1] = min_max [0]; /* {x} means {x,x} */ if (*Reg_Parse != '}') { REG_FAIL ("{m,n} specification missing right \'}\'"); } else if (min_max [1] != REG_INFINITY && min_max [0] > min_max [1]) { /* Disallow a backward range. */ sprintf (Error_Text, "{%lu,%lu} is an invalid range", min_max [0], min_max [1]); REG_FAIL (Error_Text); } } Reg_Parse++; /* Check for a minimal matching (non-greedy or "lazy") specification. */ if (*Reg_Parse == '?') { lazy = 1; Reg_Parse++; } /* Avoid overhead of counting if possible */ if (op_code == '{') { if (min_max [0] == REG_ZERO && min_max [1] == REG_INFINITY) { op_code = '*'; } else if (min_max [0] == REG_ONE && min_max [1] == REG_INFINITY) { op_code = '+'; } else if (min_max [0] == REG_ZERO && min_max [1] == REG_ONE) { op_code = '?'; } else if (min_max [0] == REG_ONE && min_max [1] == REG_ONE) { /* "x{1,1}" is the same as "x". No need to pollute the compiled regex with such nonsense. */ *flag_param = flags_local; *range_param = range_local; return (ret_val); } else if (Num_Braces > (int)UCHAR_MAX) { sprintf (Error_Text, "number of {m,n} constructs > %d", UCHAR_MAX); REG_FAIL (Error_Text); } } if (op_code == '+') min_max [0] = REG_ONE; if (op_code == '?') min_max [1] = REG_ONE; /* It is dangerous to apply certain quantifiers to a possibly zero width item. */ if (!(flags_local & HAS_WIDTH)) { if (brace_present) { sprintf (Error_Text, "{%lu,%lu} operand could be empty", min_max [0], min_max [1]); } else { sprintf (Error_Text, "%c operand could be empty", op_code); } REG_FAIL (Error_Text); } *flag_param = (min_max [0] > REG_ZERO) ? (WORST | HAS_WIDTH) : WORST; if (range_local.lower >= 0) { if (min_max[1] != REG_INFINITY) { range_param->lower = range_local.lower * min_max[0]; range_param->upper = range_local.upper * min_max[1]; } else { range_param->lower = -1; /* Not a fixed-size length */ range_param->upper = -1; } } else { range_param->lower = -1; /* Not a fixed-size length */ range_param->upper = -1; } /*---------------------------------------------------------------------* * Symbol Legend For Node Structure Diagrams *---------------------------------------------------------------------* * (...) = general grouped thing * B = (B)ranch, K = bac(K), N = (N)othing * I = (I)nitialize count, C = Increment (C)ount * T~m = (T)est against mini(m)um- go to NEXT pointer if >= operand * T~x = (T)est against ma(x)imum- go to NEXT pointer if >= operand * '~' = NEXT pointer, \___| = forward pointer, |___/ = Backward pointer *---------------------------------------------------------------------*/ if (op_code == '*' && (flags_local & SIMPLE)) { insert ((lazy ? LAZY_STAR : STAR), ret_val, 0UL, 0UL, 0); } else if (op_code == '+' && (flags_local & SIMPLE)) { insert (lazy ? LAZY_PLUS : PLUS, ret_val, 0UL, 0UL, 0); } else if (op_code == '?' && (flags_local & SIMPLE)) { insert (lazy ? LAZY_QUESTION : QUESTION, ret_val, 0UL, 0UL, 0); } else if (op_code == '{' && (flags_local & SIMPLE)) { insert (lazy ? LAZY_BRACE : BRACE, ret_val, min_max [0], min_max [1], 0); } else if ((op_code == '*' || op_code == '+') && lazy) { /* Node structure for (x)*? Node structure for (x)+? construct. * construct. (Same as (x)*? except for initial * forward jump into parenthesis.) * * ___6____ * _______5_______ /________|______ * | _4__ 1_\ /| ____ | _\ * |/ | / |\ / |/ | | / |\ * B~ N~ B~ (...)~ K~ N~ N~ B~ N~ B~ (...)~ K~ N~ * \ \___2_______| \ \___________| * \_____3_______| \_____________| * */ tail (ret_val, emit_node (BACK)); /* 1 */ (void) insert (BRANCH, ret_val, 0UL, 0UL, 0); /* 2,4 */ (void) insert (NOTHING, ret_val, 0UL, 0UL, 0); /* 3 */ next = emit_node (NOTHING); /* 2,3 */ offset_tail (ret_val, NODE_SIZE, next); /* 2 */ tail (ret_val, next); /* 3 */ insert (BRANCH, ret_val, 0UL, 0UL, 0); /* 4,5 */ tail (ret_val, ret_val + (2 * NODE_SIZE)); /* 4 */ offset_tail (ret_val, 3 * NODE_SIZE, ret_val); /* 5 */ if (op_code == '+') { insert (NOTHING, ret_val, 0UL, 0UL, 0); /* 6 */ tail (ret_val, ret_val + (4 * NODE_SIZE)); /* 6 */ } } else if (op_code == '*') { /* Node structure for (x)* construct. * ____1_____ * | \ * B~ (...)~ K~ B~ N~ * \ \_|2 |\_| * \__3_______| 4 */ insert (BRANCH, ret_val, 0UL, 0UL, 0); /* 1,3 */ offset_tail (ret_val, NODE_SIZE, emit_node (BACK)); /* 2 */ offset_tail (ret_val, NODE_SIZE, ret_val); /* 1 */ tail (ret_val, emit_node (BRANCH)); /* 3 */ tail (ret_val, emit_node (NOTHING)); /* 4 */ } else if (op_code == '+') { /* Node structure for (x)+ construct. * * ____2_____ * | \ * (...)~ B~ K~ B~ N~ * \_|\____|\_| * 1 3 4 */ next = emit_node (BRANCH); /* 1 */ tail (ret_val, next); /* 1 */ tail (emit_node (BACK), ret_val); /* 2 */ tail (next, emit_node (BRANCH)); /* 3 */ tail (ret_val, emit_node (NOTHING)); /* 4 */ } else if (op_code == '?' && lazy) { /* Node structure for (x)?? construct. * _4__ 1_ * / | / | * B~ N~ B~ (...)~ N~ * \ \___2____| * \_____3____| */ (void) insert (BRANCH, ret_val, 0UL, 0UL, 0); /* 2,4 */ (void) insert (NOTHING, ret_val, 0UL, 0UL, 0); /* 3 */ next = emit_node (NOTHING); /* 1,2,3 */ offset_tail (ret_val, 2 * NODE_SIZE, next); /* 1 */ offset_tail (ret_val, NODE_SIZE, next); /* 2 */ tail (ret_val, next); /* 3 */ insert (BRANCH, ret_val, 0UL, 0UL, 0); /* 4 */ tail (ret_val, (ret_val + (2 * NODE_SIZE))); /* 4 */ } else if (op_code == '?') { /* Node structure for (x)? construct. * ___1____ _2 * / |/ | * B~ (...)~ B~ N~ * \__3_| */ insert (BRANCH, ret_val, 0UL, 0UL, 0); /* 1 */ tail (ret_val, emit_node (BRANCH)); /* 1 */ next = emit_node (NOTHING); /* 2,3 */ tail (ret_val, next); /* 2 */ offset_tail (ret_val, NODE_SIZE, next); /* 3 */ } else if (op_code == '{' && min_max [0] == min_max [1]) { /* Node structure for (x){m}, (x){m}?, (x){m,m}, or (x){m,m}? constructs. * Note that minimal and maximal matching mean the same thing when we * specify the minimum and maximum to be the same value. * _______3_____ * | 1_ _2 \ * | / |/ | \ * I~ (...)~ C~ T~m K~ N~ * \_| \_____| * 5 4 */ tail (ret_val, emit_special (INC_COUNT, 0UL, Num_Braces)); /* 1 */ tail (ret_val, emit_special (TEST_COUNT, min_max [0], Num_Braces));/* 2 */ tail (emit_node (BACK), ret_val); /* 3 */ tail (ret_val, emit_node (NOTHING)); /* 4 */ next = insert (INIT_COUNT, ret_val, 0UL, 0UL, Num_Braces); /* 5 */ tail (ret_val, next); /* 5 */ Num_Braces++; } else if (op_code == '{' && lazy) { if (min_max [0] == REG_ZERO && min_max [1] != REG_INFINITY) { /* Node structure for (x){0,n}? or {,n}? construct. * _________3____________ * 8_| _4__ 1_ _2 \ * / |/ | / |/ | \ * I~ B~ N~ B~ (...)~ C~ T~x K~ N~ * \ \ \__7__| * \ \_________6_______| * \______5____________| */ tail (ret_val, emit_special (INC_COUNT, 0UL, Num_Braces)); /* 1 */ next = emit_special (TEST_COUNT, min_max [0], Num_Braces); /* 2,7 */ tail (ret_val, next); /* 2 */ (void) insert (BRANCH, ret_val, 0UL, 0UL, Num_Braces); /* 4,6 */ (void) insert (NOTHING, ret_val, 0UL, 0UL, Num_Braces); /* 5 */ (void) insert (BRANCH, ret_val, 0UL, 0UL, Num_Braces); /* 3,4,8 */ tail (emit_node (BACK), ret_val); /* 3 */ tail (ret_val, ret_val + (2 * NODE_SIZE)); /* 4 */ next = emit_node (NOTHING); /* 5,6,7 */ offset_tail (ret_val, NODE_SIZE, next); /* 5 */ offset_tail (ret_val, 2 * NODE_SIZE, next); /* 6 */ offset_tail (ret_val, 3 * NODE_SIZE, next); /* 7 */ next = insert (INIT_COUNT, ret_val, 0UL, 0UL, Num_Braces); /* 8 */ tail (ret_val, next); /* 8 */ } else if (min_max [0] > REG_ZERO && min_max [1] == REG_INFINITY) { /* Node structure for (x){m,}? construct. * ______8_________________ * | _______3_____ \ * | _7__ | 1_ _2 \ \ * |/ | | / |/ | \ \ * I~ B~ N~ B~ (...)~ C~ T~m K~ K~ N~ * \_____\__\_| \_4___| | * 9 \ \_________5__________| * \_______6______________| */ tail (ret_val, emit_special (INC_COUNT, 0UL, Num_Braces)); /* 1 */ next = emit_special (TEST_COUNT, min_max [0], Num_Braces); /* 2,4 */ tail (ret_val, next); /* 2 */ tail (emit_node (BACK), ret_val); /* 3 */ tail (ret_val, emit_node (BACK)); /* 4 */ (void) insert (BRANCH, ret_val, 0UL, 0UL, 0); /* 5,7 */ (void) insert (NOTHING, ret_val, 0UL, 0UL, 0); /* 6 */ next = emit_node (NOTHING); /* 5,6 */ offset_tail (ret_val, NODE_SIZE, next); /* 5 */ tail (ret_val, next); /* 6 */ (void) insert (BRANCH, ret_val, 0UL, 0UL, 0); /* 7,8 */ tail (ret_val, ret_val + (2 * NODE_SIZE)); /* 7 */ offset_tail (ret_val, 3 * NODE_SIZE, ret_val); /* 8 */ (void) insert (INIT_COUNT, ret_val, 0UL, 0UL, Num_Braces); /* 9 */ tail (ret_val, ret_val + INDEX_SIZE + (4 * NODE_SIZE)); /* 9 */ } else { /* Node structure for (x){m,n}? construct. * ______9_____________________ * | _____________3___ \ * | __8_ | 1_ _2 \ \ * |/ | | / |/ | \ \ * I~ B~ N~ B~ (...)~ C~ T~x T~m K~ K~ N~ * \_____\__\_| \ \__4__| | * 10 \ \ \_7_________| * \ \_________6_____________| * \_______5_________________| */ tail (ret_val, emit_special (INC_COUNT, 0UL, Num_Braces)); /* 1 */ next = emit_special (TEST_COUNT, min_max [1], Num_Braces); /* 2,7 */ tail (ret_val, next); /* 2 */ next = emit_special (TEST_COUNT, min_max [0], Num_Braces); /* 4 */ tail (emit_node (BACK), ret_val); /* 3 */ tail (next, emit_node (BACK)); /* 4 */ (void) insert (BRANCH, ret_val, 0UL, 0UL, 0); /* 6,8 */ (void) insert (NOTHING, ret_val, 0UL, 0UL, 0); /* 5 */ (void) insert (BRANCH, ret_val, 0UL, 0UL, 0); /* 8,9 */ next = emit_node (NOTHING); /* 5,6,7 */ offset_tail (ret_val, NODE_SIZE, next); /* 5 */ offset_tail (ret_val, 2 * NODE_SIZE, next); /* 6 */ offset_tail (ret_val, 3 * NODE_SIZE, next); /* 7 */ tail (ret_val, ret_val + (2 * NODE_SIZE)); /* 8 */ offset_tail (next, -NODE_SIZE, ret_val); /* 9 */ insert (INIT_COUNT, ret_val, 0UL, 0UL, Num_Braces); /* 10 */ tail (ret_val, ret_val + INDEX_SIZE + (4 * NODE_SIZE)); /* 10 */ } Num_Braces++; } else if (op_code == '{') { if (min_max [0] == REG_ZERO && min_max [1] != REG_INFINITY) { /* Node structure for (x){0,n} or (x){,n} construct. * * ___3____________ * | 1_ _2 \ 5_ * | / |/ | \ / | * I~ B~ (...)~ C~ T~x K~ B~ N~ * \_|\ \_6___|__| * 7 \________4________| */ tail (ret_val, emit_special (INC_COUNT, 0UL, Num_Braces)); /* 1 */ next = emit_special (TEST_COUNT, min_max [1], Num_Braces); /* 2,6 */ tail (ret_val, next); /* 2 */ (void) insert (BRANCH, ret_val, 0UL, 0UL, 0); /* 3,4,7 */ tail (emit_node (BACK), ret_val); /* 3 */ next = emit_node (BRANCH); /* 4,5 */ tail (ret_val, next); /* 4 */ tail (next, emit_node (NOTHING)); /* 5,6 */ offset_tail (ret_val, NODE_SIZE, next); /* 6 */ next = insert (INIT_COUNT, ret_val, 0UL, 0UL, Num_Braces); /* 7 */ tail (ret_val, next); /* 7 */ } else if (min_max [0] > REG_ZERO && min_max [1] == REG_INFINITY) { /* Node structure for (x){m,} construct. * __________4________ * | __3__________ \ * _|___| 1_ _2 \ \ _7 * / | 8 | / |/ | \ \ / | * I~ B~ (...)~ C~ T~m K~ K~ B~ N~ * \ \_5___| | * \__________6__________| */ tail (ret_val, emit_special (INC_COUNT, 0UL, Num_Braces)); /* 1 */ next = emit_special (TEST_COUNT, min_max [0], Num_Braces); /* 2 */ tail (ret_val, next); /* 2 */ tail (emit_node (BACK), ret_val); /* 3 */ (void) insert (BRANCH, ret_val, 0UL, 0UL, 0); /* 4,6 */ next = emit_node (BACK); /* 4 */ tail (next, ret_val); /* 4 */ offset_tail (ret_val, NODE_SIZE, next); /* 5 */ tail (ret_val, emit_node (BRANCH)); /* 6 */ tail (ret_val, emit_node (NOTHING)); /* 7 */ insert (INIT_COUNT, ret_val, 0UL, 0UL, Num_Braces); /* 8 */ tail (ret_val, ret_val + INDEX_SIZE + (2 * NODE_SIZE)); /* 8 */ } else { /* Node structure for (x){m,n} construct. * _____6________________ * | _____________3___ \ * 9_|__| 1_ _2 \ \ _8 * / | | / |/ | \ \ / | * I~ B~ (...)~ C~ T~x T~m K~ K~ B~ N~ * \ \ \__4__| | | * \ \_7_________|__| * \_________5_____________| */ tail (ret_val, emit_special (INC_COUNT, 0UL, Num_Braces)); /* 1 */ next = emit_special (TEST_COUNT, min_max [1], Num_Braces); /* 2,4 */ tail (ret_val, next); /* 2 */ next = emit_special (TEST_COUNT, min_max [0], Num_Braces); /* 4 */ tail (emit_node (BACK), ret_val); /* 3 */ tail (next, emit_node (BACK)); /* 4 */ (void) insert (BRANCH, ret_val, 0UL, 0UL, 0); /* 5,6 */ next = emit_node (BRANCH); /* 5,8 */ tail (ret_val, next); /* 5 */ offset_tail (next, -NODE_SIZE, ret_val); /* 6 */ next = emit_node (NOTHING); /* 7,8 */ offset_tail (ret_val, NODE_SIZE, next); /* 7 */ offset_tail (next, -NODE_SIZE, next); /* 8 */ (void) insert (INIT_COUNT, ret_val, 0UL, 0UL, Num_Braces); /* 9 */ tail (ret_val, ret_val + INDEX_SIZE + (2 * NODE_SIZE)); /* 9 */ } Num_Braces++; } else { /* We get here if the IS_QUANTIFIER macro is not coordinated properly with this function. */ REG_FAIL ("internal error #2, `piece\'"); } if (IS_QUANTIFIER (*Reg_Parse)) { if (op_code == '{') { sprintf (Error_Text, "nested quantifiers, {m,n}%c", *Reg_Parse); } else { sprintf (Error_Text, "nested quantifiers, %c%c", op_code, *Reg_Parse); } REG_FAIL (Error_Text); } return (ret_val); } /*----------------------------------------------------------------------* * atom * * Process one regex item at the lowest level * * OPTIMIZATION: Lumps a continuous sequence of ordinary characters * together so that it can turn them into a single EXACTLY node, which * is smaller to store and faster to run. *----------------------------------------------------------------------*/ static unsigned char * atom (int *flag_param, len_range *range_param) { register unsigned char *ret_val; unsigned char test; int flags_local; len_range range_local; *flag_param = WORST; /* Tentatively. */ range_param->lower = 0; /* Idem */ range_param->upper = 0; /* Process any regex comments, e.g. `(?# match next token->)'. The terminating right parenthesis can not be escaped. The comment stops at the first right parenthesis encountered (or the end of the regex string)... period. Handles multiple sequential comments, e.g. `(?# one)(?# two)...' */ while (*Reg_Parse == '(' && *(Reg_Parse + 1) == '?' && *(Reg_Parse + 2) == '#') { Reg_Parse += 3; while (*Reg_Parse != ')' && *Reg_Parse != '\0') { Reg_Parse++; } if (*Reg_Parse == ')') { Reg_Parse++; } if (*Reg_Parse == ')' || *Reg_Parse == '|' || *Reg_Parse == '\0') { /* Hit end of regex string or end of parenthesized regex; have to return "something" (i.e. a NOTHING node) to avoid generating an error. */ ret_val = emit_node (NOTHING); return (ret_val); } } switch (*Reg_Parse++) { case '^': ret_val = emit_node (BOL); break; case '$': ret_val = emit_node (EOL); break; case '<': ret_val = emit_node (BOWORD); break; case '>': ret_val = emit_node (EOWORD); break; case '.': if (Match_Newline) { ret_val = emit_node (EVERY); } else { ret_val = emit_node (ANY); } *flag_param |= (HAS_WIDTH | SIMPLE); range_param->lower = 1; range_param->upper = 1; break; case '(': if (*Reg_Parse == '?') { /* Special parenthetical expression */ Reg_Parse++; range_local.lower = 0; /* Make sure it is always used */ range_local.upper = 0; if (*Reg_Parse == ':') { Reg_Parse++; ret_val = chunk (NO_CAPTURE, &flags_local, &range_local); } else if (*Reg_Parse == '=') { Reg_Parse++; ret_val = chunk (POS_AHEAD_OPEN, &flags_local, &range_local); } else if (*Reg_Parse == '!') { Reg_Parse++; ret_val = chunk (NEG_AHEAD_OPEN, &flags_local, &range_local); } else if (*Reg_Parse == 'i') { Reg_Parse++; ret_val = chunk (INSENSITIVE, &flags_local, &range_local); } else if (*Reg_Parse == 'I') { Reg_Parse++; ret_val = chunk (SENSITIVE, &flags_local, &range_local); } else if (*Reg_Parse == 'n') { Reg_Parse++; ret_val = chunk (NEWLINE, &flags_local, &range_local); } else if (*Reg_Parse == 'N') { Reg_Parse++; ret_val = chunk (NO_NEWLINE, &flags_local, &range_local); } else if (*Reg_Parse == '<') { Reg_Parse++; if (*Reg_Parse == '=') { Reg_Parse++; ret_val = chunk (POS_BEHIND_OPEN, &flags_local, &range_local); } else if (*Reg_Parse == '!') { Reg_Parse++; ret_val = chunk (NEG_BEHIND_OPEN, &flags_local, &range_local); } else { sprintf (Error_Text, "invalid look-behind syntax, \"(?<%c...)\"", *Reg_Parse); REG_FAIL (Error_Text); } } else { sprintf (Error_Text, "invalid grouping syntax, \"(?%c...)\"", *Reg_Parse); REG_FAIL (Error_Text); } } else { /* Normal capturing parentheses */ ret_val = chunk (PAREN, &flags_local, &range_local); } if (ret_val == NULL) return (NULL); /* Something went wrong. */ /* Add HAS_WIDTH flag if it was set by call to chunk. */ *flag_param |= flags_local & HAS_WIDTH; *range_param = range_local; break; case '\0': case '|': case ')': REG_FAIL ("internal error #3, `atom\'"); /* Supposed to be */ /* caught earlier. */ case '?': case '+': case '*': sprintf (Error_Text, "%c follows nothing", *(Reg_Parse - 1)); REG_FAIL (Error_Text); case '{': if (Enable_Counting_Quantifier) { REG_FAIL ("{m,n} follows nothing"); } else { ret_val = emit_node (EXACTLY); /* Treat braces as literals. */ emit_byte ('{'); emit_byte ('\0'); range_param->lower = 1; range_param->upper = 1; } break; case '[': { register unsigned int second_value; register unsigned int last_value; unsigned char last_emit = 0; /* Handle characters that can only occur at the start of a class. */ if (*Reg_Parse == '^') { /* Complement of range. */ ret_val = emit_node (ANY_BUT); Reg_Parse++; /* All negated classes include newline unless escaped with a "(?n)" switch. */ if (!Match_Newline) emit_byte ('\n'); } else { ret_val = emit_node (ANY_OF); } if (*Reg_Parse == ']' || *Reg_Parse == '-') { /* If '-' or ']' is the first character in a class, it is a literal character in the class. */ last_emit = *Reg_Parse; emit_byte (*Reg_Parse); Reg_Parse++; } /* Handle the rest of the class characters. */ while (*Reg_Parse != '\0' && *Reg_Parse != ']') { if (*Reg_Parse == '-') { /* Process a range, e.g [a-z]. */ Reg_Parse++; if (*Reg_Parse == ']' || *Reg_Parse == '\0') { /* If '-' is the last character in a class it is a literal character. If `Reg_Parse' points to the end of the regex string, an error will be generated later. */ emit_byte ('-'); last_emit = '-'; } else { /* We must get the range starting character value from the emitted code since it may have been an escaped character. `second_value' is set one larger than the just emitted character value. This is done since `second_value' is used as the start value for the loop that emits the values in the range. Since we have already emitted the first character of the class, we do not want to emit it again. */ second_value = ((unsigned int) last_emit) + 1; if (*Reg_Parse == '\\') { /* Handle escaped characters within a class range. Specifically disallow shortcut escapes as the end of a class range. To allow this would be ambiguous since shortcut escapes represent a set of characters, and it would not be clear which character of the class should be treated as the "last" character. */ Reg_Parse++; if ((test = numeric_escape (*Reg_Parse, &Reg_Parse))) { last_value = (unsigned int) test; } else if ((test = literal_escape (*Reg_Parse))) { last_value = (unsigned int) test; } else if (shortcut_escape (*Reg_Parse, NULL, CHECK_CLASS_ESCAPE)) { sprintf (Error_Text, "\\%c is not allowed as range operand", *Reg_Parse); REG_FAIL (Error_Text); } else { sprintf ( Error_Text, "\\%c is an invalid char class escape sequence", *Reg_Parse); REG_FAIL (Error_Text); } } else { last_value = U_CHAR_AT (Reg_Parse); } if (Is_Case_Insensitive) { second_value = (unsigned int) tolower ((int) second_value); last_value = (unsigned int) tolower ((int) last_value); } /* For case insensitive, something like [A-_] will generate an error here since ranges are converted to lower case. */ if (second_value - 1 > last_value) { REG_FAIL ("invalid [] range"); } /* If only one character in range (e.g [a-a]) then this loop is not run since the first character of any range was emitted by the previous iteration of while loop. */ for (; second_value <= last_value; second_value++) { emit_class_byte (second_value); } last_emit = (unsigned char) last_value; Reg_Parse++; } /* End class character range code. */ } else if (*Reg_Parse == '\\') { Reg_Parse++; if ((test = numeric_escape (*Reg_Parse, &Reg_Parse)) != '\0') { emit_class_byte (test); last_emit = test; } else if ((test = literal_escape (*Reg_Parse)) != '\0') { emit_byte (test); last_emit = test; } else if (shortcut_escape (*Reg_Parse, NULL, CHECK_CLASS_ESCAPE)) { if (*(Reg_Parse + 1) == '-') { /* Specifically disallow shortcut escapes as the start of a character class range (see comment above.) */ sprintf (Error_Text, "\\%c not allowed as range operand", *Reg_Parse); REG_FAIL (Error_Text); } else { /* Emit the bytes that are part of the shortcut escape sequence's range (e.g. \d = 0123456789) */ shortcut_escape (*Reg_Parse, NULL, EMIT_CLASS_BYTES); } } else { sprintf (Error_Text, "\\%c is an invalid char class escape sequence", *Reg_Parse); REG_FAIL (Error_Text); } Reg_Parse++; /* End of class escaped sequence code */ } else { emit_class_byte (*Reg_Parse); /* Ordinary class character. */ last_emit = *Reg_Parse; Reg_Parse++; } } /* End of while (*Reg_Parse != '\0' && *Reg_Parse != ']') */ if (*Reg_Parse != ']') REG_FAIL ("missing right \']\'"); emit_byte('\0'); /* NOTE: it is impossible to specify an empty class. This is because [] would be interpreted as "begin character class" followed by a literal ']' character and no "end character class" delimiter (']'). Because of this, it is always safe to assume that a class HAS_WIDTH. */ Reg_Parse++; *flag_param |= HAS_WIDTH | SIMPLE; range_param->lower = 1; range_param->upper = 1; } break; /* End of character class code. */ case '\\': /* Force Error_Text to have a length of zero. This way we can tell if either of the calls to shortcut_escape() or back_ref() fill Error_Text with an error message. */ Error_Text [0] = '\0'; if ((ret_val = shortcut_escape (*Reg_Parse, flag_param, EMIT_NODE))) { Reg_Parse++; range_param->lower = 1; range_param->upper = 1; break; } else if ((ret_val = back_ref (Reg_Parse, flag_param, EMIT_NODE))) { /* Can't make any assumptions about a back-reference as to SIMPLE or HAS_WIDTH. For example (^|<) is neither simple nor has width. So we don't flip bits in flag_param here. */ Reg_Parse++; /* Back-references always have an unknown length */ range_param->lower = -1; range_param->upper = -1; break; } if (strlen (Error_Text) > 0) REG_FAIL (Error_Text); /* At this point it is apparent that the escaped character is not a shortcut escape or back-reference. Back up one character to allow the default code to include it as an ordinary character. */ /* Fall through to Default case to handle literal escapes and numeric escapes. */ default: Reg_Parse--; /* If we fell through from the above code, we are now pointing at the back slash (\) character. */ { unsigned char *parse_save; int len = 0; if (Is_Case_Insensitive) { ret_val = emit_node (SIMILAR); } else { ret_val = emit_node (EXACTLY); } /* Loop until we find a meta character, shortcut escape, back reference, or end of regex string. */ for (; *Reg_Parse != '\0' && !strchr ((char *) Meta_Char, (int) *Reg_Parse); len++) { /* Save where we are in case we have to back this character out. */ parse_save = Reg_Parse; if (*Reg_Parse == '\\') { Reg_Parse++; /* Point to escaped character */ Error_Text [0] = '\0'; /* See comment above. */ if ((test = numeric_escape (*Reg_Parse, &Reg_Parse))) { if (Is_Case_Insensitive) { emit_byte (tolower (test)); } else { emit_byte (test); } } else if ((test = literal_escape (*Reg_Parse))) { emit_byte (test); } else if (back_ref (Reg_Parse, NULL, CHECK_ESCAPE)) { /* Leave back reference for next `atom' call */ Reg_Parse--; break; } else if (shortcut_escape (*Reg_Parse, NULL, CHECK_ESCAPE)) { /* Leave shortcut escape for next `atom' call */ Reg_Parse--; break; } else { if (strlen (Error_Text) == 0) { /* None of the above calls generated an error message so generate our own here. */ sprintf (Error_Text, "\\%c is an invalid escape sequence", *Reg_Parse); } REG_FAIL (Error_Text); } Reg_Parse++; } else { /* Ordinary character */ if (Is_Case_Insensitive) { emit_byte (tolower (*Reg_Parse)); } else { emit_byte (*Reg_Parse); } Reg_Parse++; } /* If next regex token is a quantifier (?, +. *, or {m,n}) and our EXACTLY node so far is more than one character, leave the last character to be made into an EXACTLY node one character wide for the multiplier to act on. For example 'abcd* would have an EXACTLY node with an 'abc' operand followed by a STAR node followed by another EXACTLY node with a 'd' operand. */ if (IS_QUANTIFIER (*Reg_Parse) && len > 0) { Reg_Parse = parse_save; /* Point to previous regex token. */ if (Code_Emit_Ptr == &Compute_Size) { Reg_Size--; } else { Code_Emit_Ptr--; /* Write over previously emitted byte. */ } break; } } if (len <= 0) REG_FAIL ("internal error #4, `atom\'"); *flag_param |= HAS_WIDTH; if (len == 1) *flag_param |= SIMPLE; range_param->lower = len; range_param->upper = len; emit_byte ('\0'); } } /* END switch (*Reg_Parse++) */ return (ret_val); } /*----------------------------------------------------------------------* * emit_node * * Emit (if appropriate) the op code for a regex node atom. * * The NEXT pointer is initialized to NULL. * * Returns a pointer to the START of the emitted node. *----------------------------------------------------------------------*/ static unsigned char * emit_node (int op_code) { register unsigned char *ret_val; register unsigned char *ptr; ret_val = Code_Emit_Ptr; /* Return address of start of node */ if (ret_val == &Compute_Size) { Reg_Size += NODE_SIZE; } else { ptr = ret_val; *ptr++ = (unsigned char) op_code; *ptr++ = '\0'; /* Null "NEXT" pointer. */ *ptr++ = '\0'; Code_Emit_Ptr = ptr; } return (ret_val); } /*----------------------------------------------------------------------* * emit_byte * * Emit (if appropriate) a byte of code (usually part of an operand.) *----------------------------------------------------------------------*/ static void emit_byte (unsigned char c) { if (Code_Emit_Ptr == &Compute_Size) { Reg_Size++; } else { *Code_Emit_Ptr++ = c; } } /*----------------------------------------------------------------------* * emit_class_byte * * Emit (if appropriate) a byte of code (usually part of a character * class operand.) *----------------------------------------------------------------------*/ static void emit_class_byte (unsigned char c) { if (Code_Emit_Ptr == &Compute_Size) { Reg_Size++; if (Is_Case_Insensitive && isalpha (c)) Reg_Size++; } else if (Is_Case_Insensitive && isalpha (c)) { /* For case insensitive character classes, emit both upper and lower case versions of alphabetical characters. */ *Code_Emit_Ptr++ = tolower (c); *Code_Emit_Ptr++ = toupper (c); } else { *Code_Emit_Ptr++ = c; } } /*----------------------------------------------------------------------* * emit_special * * Emit nodes that need special processing. *----------------------------------------------------------------------*/ static unsigned char * emit_special ( unsigned char op_code, unsigned long test_val, int index) { register unsigned char *ret_val = &Compute_Size; register unsigned char *ptr; if (Code_Emit_Ptr == &Compute_Size) { switch (op_code) { case POS_BEHIND_OPEN: case NEG_BEHIND_OPEN: Reg_Size += LENGTH_SIZE; /* Length of the look-behind match */ Reg_Size += NODE_SIZE; /* Make room for the node */ break; case TEST_COUNT: Reg_Size += NEXT_PTR_SIZE; /* Make room for a test value. */ case INC_COUNT: Reg_Size += INDEX_SIZE; /* Make room for an index value. */ default: Reg_Size += NODE_SIZE; /* Make room for the node. */ } } else { ret_val = emit_node (op_code); /* Return the address for start of node. */ ptr = Code_Emit_Ptr; if (op_code == INC_COUNT || op_code == TEST_COUNT) { *ptr++ = (unsigned char) index; if (op_code == TEST_COUNT) { *ptr++ = PUT_OFFSET_L (test_val); *ptr++ = PUT_OFFSET_R (test_val); } } else if (op_code == POS_BEHIND_OPEN || op_code == NEG_BEHIND_OPEN) { *ptr++ = PUT_OFFSET_L (test_val); *ptr++ = PUT_OFFSET_R (test_val); *ptr++ = PUT_OFFSET_L (test_val); *ptr++ = PUT_OFFSET_R (test_val); } Code_Emit_Ptr = ptr; } return (ret_val); } /*----------------------------------------------------------------------* * insert * * Insert a node in front of already emitted node(s). Means relocating * the operand. Code_Emit_Ptr points one byte past the just emitted * node and operand. The parameter `insert_pos' points to the location * where the new node is to be inserted. *----------------------------------------------------------------------*/ static unsigned char * insert ( unsigned char op, unsigned char *insert_pos, long min, long max, int index) { register unsigned char *src; register unsigned char *dst; unsigned char *place; int insert_size = NODE_SIZE; if (op == BRACE || op == LAZY_BRACE) { /* Make room for the min and max values. */ insert_size += (2 * NEXT_PTR_SIZE); } else if (op == INIT_COUNT) { /* Make room for an index value . */ insert_size += INDEX_SIZE; } if (Code_Emit_Ptr == &Compute_Size) { Reg_Size += insert_size; return &Compute_Size; } src = Code_Emit_Ptr; Code_Emit_Ptr += insert_size; dst = Code_Emit_Ptr; /* Relocate the existing emitted code to make room for the new node. */ while (src > insert_pos) *--dst = *--src; place = insert_pos; /* Where operand used to be. */ *place++ = op; /* Inserted operand. */ *place++ = '\0'; /* NEXT pointer for inserted operand. */ *place++ = '\0'; if (op == BRACE || op == LAZY_BRACE) { *place++ = PUT_OFFSET_L (min); *place++ = PUT_OFFSET_R (min); *place++ = PUT_OFFSET_L (max); *place++ = PUT_OFFSET_R (max); } else if (op == INIT_COUNT) { *place++ = (unsigned char) index; } return place; /* Return a pointer to the start of the code moved. */ } /*----------------------------------------------------------------------* * tail - Set the next-pointer at the end of a node chain. *----------------------------------------------------------------------*/ static void tail (unsigned char *search_from, unsigned char *point_to) { register unsigned char *scan; register unsigned char *next; register int offset; if (search_from == &Compute_Size) return; /* Find the last node in the chain (node with a null NEXT pointer) */ scan = search_from; for (;;) { next = next_ptr (scan); if (!next) break; scan = next; } if (GET_OP_CODE (scan) == BACK) { offset = scan - point_to; } else { offset = point_to - scan; } /* Set NEXT pointer */ *(scan + 1) = PUT_OFFSET_L (offset); *(scan + 2) = PUT_OFFSET_R (offset); } /*--------------------------------------------------------------------* * offset_tail * * Perform a tail operation on (ptr + offset). *--------------------------------------------------------------------*/ static void offset_tail (unsigned char *ptr, int offset, unsigned char *val) { if (ptr == &Compute_Size || ptr == NULL) return; tail (ptr + offset, val); } /*--------------------------------------------------------------------* * branch_tail * * Perform a tail operation on (ptr + offset) but only if `ptr' is a * BRANCH node. *--------------------------------------------------------------------*/ static void branch_tail (unsigned char *ptr, int offset, unsigned char *val) { if (ptr == &Compute_Size || ptr == NULL ||GET_OP_CODE (ptr) != BRANCH) { return; } tail (ptr + offset, val); } /*--------------------------------------------------------------------* * shortcut_escape * * Implements convenient escape sequences that represent entire * character classes or special location assertions (similar to escapes * supported by Perl) * _ * \d Digits [0-9] | * \D NOT a digit [^0-9] | (Examples * \l Letters [a-zA-Z] | at left * \L NOT a Letter [^a-zA-Z] | are * \s Whitespace [ \t\n\r\f\v] | for * \S NOT Whitespace [^ \t\n\r\f\v] | C * \w "Word" character [a-zA-Z0-9_] | Locale) * \W NOT a "Word" character [^a-zA-Z0-9_] _| * * \B Matches any character that is NOT a word-delimiter * * Codes for the "emit" parameter: * * EMIT_NODE * Emit a shortcut node. Shortcut nodes have an implied set of * class characters. This helps keep the compiled regex string * small. * * EMIT_CLASS_BYTES * Emit just the equivalent characters of the class. This makes * the escape usable from within a class, e.g. [a-fA-F\d]. Only * \d, \D, \s, \S, \w, and \W can be used within a class. * * CHECK_ESCAPE * Only verify that this is a valid shortcut escape. * * CHECK_CLASS_ESCAPE * Same as CHECK_ESCAPE but only allows characters valid within * a class. * *--------------------------------------------------------------------*/ static unsigned char * shortcut_escape ( unsigned char c, int *flag_param, int emit) { register unsigned char *class = NULL; static unsigned char *codes = (unsigned char *) "ByYdDlLsSwW"; unsigned char *ret_val = (unsigned char *) 1; /* Assume success. */ unsigned char *valid_codes; if (emit == EMIT_CLASS_BYTES || emit == CHECK_CLASS_ESCAPE) { valid_codes = codes + 3; /* \B, \y and \Y are not allowed in classes */ } else { valid_codes = codes; } if (!strchr ((char *) valid_codes, (int) c)) { return NULL; /* Not a valid shortcut escape sequence */ } else if (emit == CHECK_ESCAPE || emit == CHECK_CLASS_ESCAPE) { return ret_val; /* Just checking if this is a valid shortcut escape. */ } switch (c) { case 'd': case 'D': if (emit == EMIT_CLASS_BYTES) { class = ASCII_Digits; } else if (emit == EMIT_NODE) { ret_val = (islower (c) ? emit_node (DIGIT) : emit_node (NOT_DIGIT)); } break; case 'l': case 'L': if (emit == EMIT_CLASS_BYTES) { class = Letter_Char; } else if (emit == EMIT_NODE) { ret_val = (islower (c) ? emit_node (LETTER) : emit_node (NOT_LETTER)); } break; case 's': case 'S': if (emit == EMIT_CLASS_BYTES) { if (Match_Newline) emit_byte ('\n'); class = White_Space; } else if (emit == EMIT_NODE) { if (Match_Newline) { ret_val = (islower (c) ? emit_node (SPACE_NL) : emit_node (NOT_SPACE_NL)); } else { ret_val = (islower (c) ? emit_node (SPACE) : emit_node (NOT_SPACE)); } } break; case 'w': case 'W': if (emit == EMIT_CLASS_BYTES) { class = Word_Char; } else if (emit == EMIT_NODE) { ret_val = (islower (c) ? emit_node (WORD_CHAR) : emit_node (NOT_WORD_CHAR)); } break; /* Since the delimiter table is not available at regex compile time \B, \Y and \Y can only generate a node. At run time, the delimiter table will be available for these nodes to use. */ case 'y': if (emit == EMIT_NODE) { ret_val = emit_node (IS_DELIM); } else { REG_FAIL ("internal error #5 `shortcut_escape\'"); } break; case 'Y': if (emit == EMIT_NODE) { ret_val = emit_node (NOT_DELIM); } else { REG_FAIL ("internal error #6 `shortcut_escape\'"); } break; case 'B': if (emit == EMIT_NODE) { ret_val = emit_node (NOT_BOUNDARY); } else { REG_FAIL ("internal error #7 `shortcut_escape\'"); } break; default: /* We get here if there isn't a case for every character in the string "codes" */ REG_FAIL ("internal error #8 `shortcut_escape\'"); } if (emit == EMIT_NODE && c != 'B') { *flag_param |= (HAS_WIDTH | SIMPLE); } if (class) { /* Emit bytes within a character class operand. */ while (*class != '\0') { emit_byte (*class++); } } return ret_val; } /*--------------------------------------------------------------------* * numeric_escape * * Implements hex and octal numeric escape sequence syntax. * * Hexadecimal Escape: \x## Max of two digits Must have leading 'x'. * Octal Escape: \0### Max of three digits and not greater * than 377 octal. Must have leading zero. * * Returns the actual character value or NULL if not a valid hex or * octal escape. REG_FAIL is called if \x0, \x00, \0, \00, \000, or * \0000 is specified. *--------------------------------------------------------------------*/ static unsigned char numeric_escape ( unsigned char c, unsigned char **parse) { static unsigned char digits [] = "fedcbaFEDCBA9876543210"; static unsigned int digit_val [] = { 15, 14, 13, 12, 11, 10, /* Lower case Hex digits */ 15, 14, 13, 12, 11, 10, /* Upper case Hex digits */ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; /* Decimal Digits */ register unsigned char *scan; register unsigned char *pos_ptr; register unsigned char *digit_str; unsigned int value = 0; unsigned int radix = 8; int width = 3; /* Can not be bigger than \0377 */ int pos_delta = 14; int i, pos; switch (c) { case '0': digit_str = digits + pos_delta; /* Only use Octal digits, i.e. 0-7. */ break; case 'x': case 'X': width = 2; /* Can not be bigger than \0377 */ radix = 16; pos_delta = 0; digit_str = digits; /* Use all of the digit characters. */ break; default: return ('\0'); /* Not a numeric escape */ } scan = *parse; scan++; /* Only change *parse on success. */ pos_ptr = (unsigned char *) strchr ((char *) digit_str, (int) *scan); for (i = 0; pos_ptr != NULL && (i < width); i++) { pos = (pos_ptr - digit_str) + pos_delta; value = (value * radix) + digit_val [pos]; /* If this digit makes the value over 255, treat this digit as a literal character instead of part of the numeric escape. For example, \0777 will be processed as \077 (an 'M') and a literal '7' character, NOT 511 decimal which is > 255. */ if (value > 255) { /* Back out calculations for last digit processed. */ value -= digit_val [pos]; value /= radix; break; /* Note that scan will not be incremented and still points to the digit that caused overflow. It will be decremented by the "else" below to point to the last character that is considered to be part of the octal escape. */ } scan++; pos_ptr = (unsigned char *) strchr ((char *) digit_str, (int) *scan); } /* Handle the case of "\0" i.e. trying to specify a NULL character. */ if (value == 0) { if (c == '0') { sprintf (Error_Text, "\\00 is an invalid octal escape"); } else { sprintf (Error_Text, "\\%c0 is an invalid hexadecimal escape", c); } } else { /* Point to the last character of the number on success. */ scan--; *parse = scan; } return (unsigned char) value; } /*--------------------------------------------------------------------* * literal_escape * * Recognize escaped literal characters (prefixed with backslash), * and translate them into the corresponding character. * * Returns the proper character value or NULL if not a valid literal * escape. *--------------------------------------------------------------------*/ static unsigned char literal_escape (unsigned char c) { static unsigned char valid_escape [] = { 'a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '(', ')', '-', '[', ']', '<', '>', '{', '}', '.', '\\', '|', '^', '$', '*', '+', '?', '&', '\0' }; static unsigned char value [] = { '\a', '\b', #ifdef EBCDIC_CHARSET 0x27, /* Escape character in IBM's EBCDIC character set. */ #else 0x1B, /* Escape character in ASCII character set. */ #endif '\f', '\n', '\r', '\t', '\v', '(', ')', '-', '[', ']', '<', '>', '{', '}', '.', '\\', '|', '^', '$', '*', '+', '?', '&', '\0' }; int i; for (i = 0; valid_escape [i] != '\0'; i++) { if (c == valid_escape [i]) return value [i]; } return '\0'; } /*--------------------------------------------------------------------* * back_ref * * Process a request to match a previous parenthesized thing. * Parenthetical entities are numbered beginning at 1 by counting * opening parentheses from left to to right. \0 would represent * whole match, but would confuse numeric_escape as an octal escape, * so it is forbidden. * * Constructs of the form \~1, \~2, etc. are cross-regex back * references and are used in syntax highlighting patterns to match * text previously matched by another regex. *** IMPLEMENT LATER *** *--------------------------------------------------------------------*/ static unsigned char * back_ref ( unsigned char *c, int *flag_param, int emit) { int paren_no, c_offset = 0, is_cross_regex = 0; unsigned char *ret_val; /* Implement cross regex backreferences later. */ /* if (*c == (unsigned char) ('~')) { c_offset++; is_cross_regex++; } */ paren_no = (int) (*(c + c_offset) - (unsigned char) ('0')); if (!isdigit (*(c + c_offset)) || /* Only \1, \2, ... \9 are supported. */ paren_no == 0) { /* Should be caught by numeric_escape. */ return NULL; } /* Make sure parentheses for requested back-reference are complete. */ if (!is_cross_regex && !TEST_BIT (Closed_Parens, paren_no)) { sprintf (Error_Text, "\\%d is an illegal back reference", paren_no); return NULL; } if (emit == EMIT_NODE) { if (is_cross_regex) { Reg_Parse++; /* Skip past the '~' in a cross regex back reference. We only do this if we are emitting code. */ if (Is_Case_Insensitive) { ret_val = emit_node (X_REGEX_BR_CI); } else { ret_val = emit_node (X_REGEX_BR); } } else { if (Is_Case_Insensitive) { ret_val = emit_node (BACK_REF_CI); } else { ret_val = emit_node (BACK_REF); } } emit_byte ((unsigned char) paren_no); if (is_cross_regex || TEST_BIT (Paren_Has_Width, paren_no)) { *flag_param |= HAS_WIDTH; } } else if (emit == CHECK_ESCAPE) { ret_val = (unsigned char *) 1; } else { ret_val = NULL; } return ret_val; } /*======================================================================* * Regex execution related code *======================================================================*/ /* Global work variables for `ExecRE'. */ static unsigned char *Reg_Input; /* String-input pointer. */ static unsigned char *Start_Of_String; /* Beginning of input, for ^ */ /* and < checks. */ static unsigned char *End_Of_String; /* Logical end of input (if supplied, till \0 otherwise) */ static unsigned char *Look_Behind_To; /* Position till were look behind can safely check back */ static unsigned char **Start_Ptr_Ptr; /* Pointer to `startp' array. */ static unsigned char **End_Ptr_Ptr; /* Ditto for `endp'. */ static unsigned char *Extent_Ptr_FW; /* Forward extent pointer */ static unsigned char *Extent_Ptr_BW; /* Backward extent pointer */ static unsigned char *Back_Ref_Start [10]; /* Back_Ref_Start [0] and */ static unsigned char *Back_Ref_End [10]; /* Back_Ref_End [0] are not */ /* used. This simplifies */ /* indexing. */ /* * Measured recursion limits: * Linux: +/- 40 000 (up to 110 000) * Solaris: +/- 85 000 * HP-UX 11: +/- 325 000 * * So 10 000 ought to be safe. */ #define REGEX_RECURSION_LIMIT 10000 static int Recursion_Count; /* Recursion counter */ static int Recursion_Limit_Exceeded; /* Recursion limit exceeded flag */ #define AT_END_OF_STRING(X) (*(X) == (unsigned char)'\0' ||\ (End_Of_String != NULL && (X) >= End_Of_String)) /* static regexp *Cross_Regex_Backref; */ static int Prev_Is_BOL; static int Succ_Is_EOL; static int Prev_Is_Delim; static int Succ_Is_Delim; /* Define a pointer to an array to hold general (...){m,n} counts. */ typedef struct brace_counts { unsigned long count [1]; /* More unwarranted chumminess with compiler. */ } brace_counts; static struct brace_counts *Brace; /* Default table for determining whether a character is a word delimiter. */ static unsigned char Default_Delimiters [UCHAR_MAX] = {0}; static unsigned char *Current_Delimiters; /* Current delimiter table */ /* Forward declarations of functions used by `ExecRE' */ static int attempt (regexp *, unsigned char *); static int match (unsigned char *, int *); static unsigned long greedy (unsigned char *, long); static void adjustcase (unsigned char *, int, unsigned char); static unsigned char * makeDelimiterTable (unsigned char *, unsigned char *); /* * ExecRE - match a `regexp' structure against a string * * If `end' is non-NULL, matches may not BEGIN past end, but may extend past * it. If reverse is true, `end' must be specified, and searching begins at * `end'. "isbol" should be set to true if the beginning of the string is the * actual beginning of a line (since `ExecRE' can't look backwards from the * beginning to find whether there was a newline before). Likewise, "isbow" * asks whether the string is preceded by a word delimiter. End of string is * always treated as a word and line boundary (there may be cases where it * shouldn't be, in which case, this should be changed). "delimit" (if * non-null) specifies a null-terminated string of characters to be considered * word delimiters matching "<" and ">". if "delimit" is NULL, the default * delimiters (as set in SetREDefaultWordDelimiters) are used. * Look_behind_to indicates the position till where it is safe to * perform look-behind matches. If set, it should be smaller than or equal * to the start position of the search (pointed at by string). If it is NULL, * it defaults to the start position. * Finally, match_to indicates the logical end of the string, till where * matches are allowed to extend. Note that look-ahead patterns may look * past that boundary. If match_to is set to NULL, the terminating \0 is * assumed to correspond to the logical boundary. Match_to, if set, must be * larger than or equal to end, if set. */ int ExecRE(regexp *prog, const char* string, const char* end, int reverse, char prev_char, char succ_char, const char* delimiters, const char* look_behind_to, const char* match_to) { register unsigned char *str; unsigned char **s_ptr; unsigned char **e_ptr; int ret_val = 0; unsigned char tempDelimitTable [256]; int i; /* Check for valid parameters. */ if (prog == NULL || string == NULL) { reg_error ("NULL parameter to `ExecRE\'"); goto SINGLE_RETURN; } /* Check validity of program. */ if (U_CHAR_AT (prog->program) != MAGIC) { reg_error ("corrupted program"); goto SINGLE_RETURN; } s_ptr = (unsigned char **) prog->startp; e_ptr = (unsigned char **) prog->endp; /* If caller has supplied delimiters, make a delimiter table */ if (delimiters == NULL) { Current_Delimiters = Default_Delimiters; } else { Current_Delimiters = makeDelimiterTable ( (unsigned char *) delimiters, (unsigned char *) tempDelimitTable); } /* Remember the logical end of the string. */ End_Of_String = (unsigned char *) match_to; if (end == NULL && reverse) { for (end = string; !AT_END_OF_STRING((unsigned char*)end); end++) ; succ_char = '\n'; } else if (end == NULL) { succ_char = '\n'; } /* Initialize arrays used by shortcut_escape. */ if (!init_ansi_classes ()) goto SINGLE_RETURN; /* Remember the beginning of the string for matching BOL */ Start_Of_String = (unsigned char *) string; Look_Behind_To = (unsigned char *) (look_behind_to?look_behind_to:string); Prev_Is_BOL = ((prev_char == '\n') || (prev_char == '\0') ? 1 : 0); Succ_Is_EOL = ((succ_char == '\n') || (succ_char == '\0') ? 1 : 0); Prev_Is_Delim = (Current_Delimiters [(unsigned char)prev_char] ? 1 : 0); Succ_Is_Delim = (Current_Delimiters [(unsigned char)succ_char] ? 1 : 0); Total_Paren = (int) (prog->program [1]); Num_Braces = (int) (prog->program [2]); /* Reset the recursion detection flag */ Recursion_Limit_Exceeded = 0; /* Allocate memory for {m,n} construct counting variables if need be. */ if (Num_Braces > 0) { Brace = (brace_counts *) malloc (sizeof (brace_counts) * (size_t) Num_Braces); if (Brace == NULL) { reg_error ("out of memory in `ExecRE\'"); goto SINGLE_RETURN; } } else { Brace = NULL; } /* Initialize the first nine (9) capturing parentheses start and end pointers to point to the start of the search string. This is to prevent crashes when later trying to reference captured parens that do not exist in the compiled regex. We only need to do the first nine since users can only specify \1, \2, ... \9. */ for (i = 9; i > 0; i--) { *s_ptr++ = (unsigned char *) string; *e_ptr++ = (unsigned char *) string; } if (!reverse) { /* Forward Search */ if (prog->anchor) { /* Search is anchored at BOL */ if (attempt (prog, (unsigned char *) string)) { ret_val = 1; goto SINGLE_RETURN; } for (str = (unsigned char *) string; !AT_END_OF_STRING(str) && str != (unsigned char *) end && !Recursion_Limit_Exceeded; str++) { if (*str == '\n') { if (attempt (prog, str + 1)) { ret_val = 1; break; } } } goto SINGLE_RETURN; } else if (prog->match_start != '\0') { /* We know what char match must start with. */ for (str = (unsigned char *) string; !AT_END_OF_STRING(str) && str != (unsigned char *) end && !Recursion_Limit_Exceeded; str++) { if (*str == (unsigned char)prog->match_start) { if (attempt (prog, str)) { ret_val = 1; break; } } } goto SINGLE_RETURN; } else { /* General case */ for (str = (unsigned char *) string; !AT_END_OF_STRING(str) && str != (unsigned char *) end && !Recursion_Limit_Exceeded; str++) { if (attempt (prog, str)) { ret_val = 1; break; } } /* Beware of a single $ matching \0 */ if (!Recursion_Limit_Exceeded && !ret_val && AT_END_OF_STRING(str) && str != (unsigned char *) end) { if (attempt (prog, str)) { ret_val = 1; } } goto SINGLE_RETURN; } } else { /* Search reverse, same as forward, but loops run backward */ /* Make sure that we don't start matching beyond the logical end */ if (End_Of_String != NULL && (unsigned char*)end > End_Of_String) { end = (const char*)End_Of_String; } if (prog->anchor) { /* Search is anchored at BOL */ for (str = (unsigned char *)(end - 1); str >= (unsigned char *) string && !Recursion_Limit_Exceeded; str--) { if (*str == '\n') { if (attempt (prog, str + 1)) { ret_val = 1; goto SINGLE_RETURN; } } } if (!Recursion_Limit_Exceeded && attempt (prog, (unsigned char *) string)) { ret_val = 1; goto SINGLE_RETURN; } goto SINGLE_RETURN; } else if (prog->match_start != '\0') { /* We know what char match must start with. */ for (str = (unsigned char *) end; str >= (unsigned char *) string && !Recursion_Limit_Exceeded; str--) { if (*str == (unsigned char)prog->match_start) { if (attempt (prog, str)) { ret_val = 1; break; } } } goto SINGLE_RETURN; } else { /* General case */ for (str = (unsigned char *) end; str >= (unsigned char *) string && !Recursion_Limit_Exceeded; str--) { if (attempt (prog, str)) { ret_val = 1; break; } } } } SINGLE_RETURN: if (Brace) free (Brace); if (Recursion_Limit_Exceeded) return (0); return (ret_val); } /*--------------------------------------------------------------------* * init_ansi_classes * * Generate character class sets using locale aware ANSI C functions. * *--------------------------------------------------------------------*/ static int init_ansi_classes (void) { static int initialized = 0; static int underscore = (int) '_'; int i, word_count, letter_count, space_count; if (!initialized) { initialized = 1; /* Only need to generate character sets once. */ word_count = 0; letter_count = 0; space_count = 0; for (i = 1; i < (int)UCHAR_MAX; i++) { if (isalnum (i) || i == underscore) { Word_Char [word_count++] = (unsigned char) i; } if (isalpha (i)) { Letter_Char [letter_count++] = (unsigned char) i; } /* Note: Whether or not newline is considered to be whitespace is handled by switches within the original regex and is thus omitted here. */ if (isspace (i) && (i != (int) '\n')) { White_Space [space_count++] = (unsigned char) i; } /* Make sure arrays are big enough. ("- 2" because of zero array origin and we need to leave room for the NULL terminator.) */ if (word_count > (ALNUM_CHAR_SIZE - 2) || space_count > (WHITE_SPACE_SIZE - 2) || letter_count > (ALNUM_CHAR_SIZE - 2)) { reg_error ("internal error #9 `init_ansi_classes\'"); return (0); } } Word_Char [word_count] = '\0'; Letter_Char [word_count] = '\0'; White_Space [space_count] = '\0'; } return (1); } /*----------------------------------------------------------------------* * attempt - try match at specific point, returns: 0 failure, 1 success *----------------------------------------------------------------------*/ static int attempt (regexp *prog, unsigned char *string) { register int i; register unsigned char **s_ptr; register unsigned char **e_ptr; int branch_index = 0; /* Must be set to zero ! */ Reg_Input = string; Start_Ptr_Ptr = (unsigned char **) prog->startp; End_Ptr_Ptr = (unsigned char **) prog->endp; s_ptr = (unsigned char **) prog->startp; e_ptr = (unsigned char **) prog->endp; /* Reset the recursion counter. */ Recursion_Count = 0; /* Overhead due to capturing parentheses. */ Extent_Ptr_BW = string; Extent_Ptr_FW = NULL; for (i = Total_Paren + 1; i > 0; i--) { *s_ptr++ = NULL; *e_ptr++ = NULL; } if (match ((unsigned char *) (prog->program + REGEX_START_OFFSET), &branch_index)) { prog->startp [0] = (char *) string; prog->endp [0] = (char *) Reg_Input; /* <-- One char AFTER */ prog->extentpBW = (char *) Extent_Ptr_BW; /* matched string! */ prog->extentpFW = (char *) Extent_Ptr_FW; prog->top_branch = branch_index; return (1); } else { return (0); } } /*----------------------------------------------------------------------* * match - main matching routine * * Conceptually the strategy is simple: check to see whether the * current node matches, call self recursively to see whether the rest * matches, and then act accordingly. In practice we make some effort * to avoid recursion, in particular by going through "ordinary" nodes * (that don't need to know whether the rest of the match failed) by a * loop instead of by recursion. Returns 0 failure, 1 success. *----------------------------------------------------------------------*/ #define MATCH_RETURN(X)\ { --Recursion_Count; return (X); } #define CHECK_RECURSION_LIMIT\ if (Recursion_Limit_Exceeded) MATCH_RETURN (0); static int match (unsigned char *prog, int *branch_index_param) { register unsigned char *scan; /* Current node. */ unsigned char *next; /* Next node. */ register int next_ptr_offset; /* Used by the NEXT_PTR () macro */ if (++Recursion_Count > REGEX_RECURSION_LIMIT) { if (!Recursion_Limit_Exceeded) /* Prevent duplicate errors */ reg_error("recursion limit exceeded, please respecify expression"); Recursion_Limit_Exceeded = 1; MATCH_RETURN (0); } scan = prog; while (scan != NULL) { NEXT_PTR (scan, next); switch (GET_OP_CODE (scan)) { case BRANCH: { register unsigned char *save; register int branch_index_local = 0; if (GET_OP_CODE (next) != BRANCH) { /* No choice. */ next = OPERAND (scan); /* Avoid recursion. */ } else { do { save = Reg_Input; if (match (OPERAND (scan), NULL)) { if (branch_index_param) *branch_index_param = branch_index_local; MATCH_RETURN (1); } CHECK_RECURSION_LIMIT ++branch_index_local; Reg_Input = save; /* Backtrack. */ NEXT_PTR (scan, scan); } while (scan != NULL && GET_OP_CODE (scan) == BRANCH); MATCH_RETURN (0); /* NOT REACHED */ } } break; case EXACTLY: { register int len; register unsigned char *opnd; opnd = OPERAND (scan); /* Inline the first character, for speed. */ if (*opnd != *Reg_Input) MATCH_RETURN (0); len = strlen ((char *) opnd); if (End_Of_String != NULL && Reg_Input + len > End_Of_String) { MATCH_RETURN (0); } if (len > 1 && strncmp ((char *) opnd, (char *) Reg_Input, len) != 0) { MATCH_RETURN (0); } Reg_Input += len; } break; case SIMILAR: { register unsigned char *opnd; register unsigned char test; opnd = OPERAND (scan); /* Note: the SIMILAR operand was converted to lower case during regex compile. */ while ((test = *opnd++) != '\0') { if (AT_END_OF_STRING(Reg_Input) || tolower (*Reg_Input++) != test) { MATCH_RETURN (0); } } } break; case BOL: /* `^' (beginning of line anchor) */ if (Reg_Input == Start_Of_String) { if (Prev_Is_BOL) break; } else if (*(Reg_Input - 1) == '\n') { break; } MATCH_RETURN (0); case EOL: /* `$' anchor matches end of line and end of string */ if (*Reg_Input == '\n' || (AT_END_OF_STRING(Reg_Input) && Succ_Is_EOL)) { break; } MATCH_RETURN (0); case BOWORD: /* `<' (beginning of word anchor) */ /* Check to see if the current character is not a delimiter and the preceding character is. */ { int prev_is_delim; if (Reg_Input == Start_Of_String) { prev_is_delim = Prev_Is_Delim; } else { prev_is_delim = Current_Delimiters [ *(Reg_Input - 1) ]; } if (prev_is_delim) { int current_is_delim; if (AT_END_OF_STRING(Reg_Input)) { current_is_delim = Succ_Is_Delim; } else { current_is_delim = Current_Delimiters [ *Reg_Input ]; } if (!current_is_delim) break; } } MATCH_RETURN (0); case EOWORD: /* `>' (end of word anchor) */ /* Check to see if the current character is a delimiter and the preceding character is not. */ { int prev_is_delim; if (Reg_Input == Start_Of_String) { prev_is_delim = Prev_Is_Delim; } else { prev_is_delim = Current_Delimiters [ *(Reg_Input-1) ]; } if (!prev_is_delim) { int current_is_delim; if (AT_END_OF_STRING(Reg_Input)) { current_is_delim = Succ_Is_Delim; } else { current_is_delim = Current_Delimiters [ *Reg_Input ]; } if (current_is_delim) break; } } MATCH_RETURN (0); case NOT_BOUNDARY: /* \B (NOT a word boundary) */ { int prev_is_delim; int current_is_delim; if (Reg_Input == Start_Of_String) { prev_is_delim = Prev_Is_Delim; } else { prev_is_delim = Current_Delimiters [ *(Reg_Input-1) ]; } if (AT_END_OF_STRING(Reg_Input)) { current_is_delim = Succ_Is_Delim; } else { current_is_delim = Current_Delimiters [ *Reg_Input ]; } if (!(prev_is_delim ^ current_is_delim)) break; } MATCH_RETURN (0); case IS_DELIM: /* \y (A word delimiter character.) */ if (Current_Delimiters [ *Reg_Input ] && !AT_END_OF_STRING(Reg_Input)) { Reg_Input++; break; } MATCH_RETURN (0); case NOT_DELIM: /* \Y (NOT a word delimiter character.) */ if (!Current_Delimiters [ *Reg_Input ] && !AT_END_OF_STRING(Reg_Input)) { Reg_Input++; break; } MATCH_RETURN (0); case WORD_CHAR: /* \w (word character; alpha-numeric or underscore) */ if ((isalnum ((int) *Reg_Input) || *Reg_Input == '_') && !AT_END_OF_STRING(Reg_Input)) { Reg_Input++; break; } MATCH_RETURN (0); case NOT_WORD_CHAR:/* \W (NOT a word character) */ if (isalnum ((int) *Reg_Input) || *Reg_Input == '_' || *Reg_Input == '\n' || AT_END_OF_STRING(Reg_Input)) MATCH_RETURN (0); Reg_Input++; break; case ANY: /* `.' (matches any character EXCEPT newline) */ if (AT_END_OF_STRING(Reg_Input) || *Reg_Input == '\n') MATCH_RETURN (0); Reg_Input++; break; case EVERY: /* `.' (matches any character INCLUDING newline) */ if (AT_END_OF_STRING(Reg_Input)) MATCH_RETURN (0); Reg_Input++; break; case DIGIT: /* \d, same as [0123456789] */ if (!isdigit ((int) *Reg_Input) || AT_END_OF_STRING(Reg_Input)) MATCH_RETURN (0); Reg_Input++; break; case NOT_DIGIT: /* \D, same as [^0123456789] */ if (isdigit ((int) *Reg_Input) || *Reg_Input == '\n' || AT_END_OF_STRING(Reg_Input)) MATCH_RETURN (0); Reg_Input++; break; case LETTER: /* \l, same as [a-zA-Z] */ if (!isalpha ((int) *Reg_Input) || AT_END_OF_STRING(Reg_Input)) MATCH_RETURN (0); Reg_Input++; break; case NOT_LETTER: /* \L, same as [^0123456789] */ if (isalpha ((int) *Reg_Input) || *Reg_Input == '\n' || AT_END_OF_STRING(Reg_Input)) MATCH_RETURN (0); Reg_Input++; break; case SPACE: /* \s, same as [ \t\r\f\v] */ if (!isspace ((int) *Reg_Input) || *Reg_Input == '\n' || AT_END_OF_STRING(Reg_Input)) MATCH_RETURN (0); Reg_Input++; break; case SPACE_NL: /* \s, same as [\n \t\r\f\v] */ if (!isspace ((int) *Reg_Input) || AT_END_OF_STRING(Reg_Input)) MATCH_RETURN (0); Reg_Input++; break; case NOT_SPACE: /* \S, same as [^\n \t\r\f\v] */ if (isspace ((int) *Reg_Input) || AT_END_OF_STRING(Reg_Input)) MATCH_RETURN (0); Reg_Input++; break; case NOT_SPACE_NL: /* \S, same as [^ \t\r\f\v] */ if ((isspace ((int) *Reg_Input) && *Reg_Input != '\n') || AT_END_OF_STRING(Reg_Input)) MATCH_RETURN (0); Reg_Input++; break; case ANY_OF: /* [...] character class. */ if (AT_END_OF_STRING(Reg_Input)) MATCH_RETURN (0); /* Needed because strchr () considers \0 as a member of the character set. */ if (strchr ((char *) OPERAND (scan), (int) *Reg_Input) == NULL) { MATCH_RETURN (0); } Reg_Input++; break; case ANY_BUT: /* [^...] Negated character class-- does NOT normally match newline (\n added usually to operand at compile time.) */ if (AT_END_OF_STRING(Reg_Input)) MATCH_RETURN (0); /* See comment for ANY_OF. */ if (strchr ((char *) OPERAND (scan), (int) *Reg_Input) != NULL) { MATCH_RETURN (0); } Reg_Input++; break; case NOTHING: case BACK: break; case STAR: case PLUS: case QUESTION: case BRACE: case LAZY_STAR: case LAZY_PLUS: case LAZY_QUESTION: case LAZY_BRACE: { register unsigned long num_matched = REG_ZERO; register unsigned long min = ULONG_MAX, max = REG_ZERO; register unsigned char *save; register unsigned char next_char; unsigned char *next_op; int lazy = 0; /* Lookahead (when possible) to avoid useless match attempts when we know what character comes next. */ if (GET_OP_CODE (next) == EXACTLY) { next_char = *OPERAND (next); } else { next_char = '\0';/* i.e. Don't know what next character is. */ } next_op = OPERAND (scan); switch (GET_OP_CODE (scan)) { case LAZY_STAR: lazy = 1; case STAR: min = REG_ZERO; max = ULONG_MAX; break; case LAZY_PLUS: lazy = 1; case PLUS: min = REG_ONE; max = ULONG_MAX; break; case LAZY_QUESTION: lazy = 1; case QUESTION: min = REG_ZERO; max = REG_ONE; break; case LAZY_BRACE: lazy = 1; case BRACE: min = (unsigned long) GET_OFFSET (scan + NEXT_PTR_SIZE); max = (unsigned long) GET_OFFSET (scan + (2 * NEXT_PTR_SIZE)); if (max <= REG_INFINITY) max = ULONG_MAX; next_op = OPERAND (scan + (2 * NEXT_PTR_SIZE)); } save = Reg_Input; if (lazy) { if ( min > REG_ZERO) num_matched = greedy (next_op, min); } else { num_matched = greedy (next_op, max); } while (min <= num_matched && num_matched <= max) { if (next_char == '\0' || next_char == *Reg_Input) { if (match (next, NULL)) MATCH_RETURN (1); CHECK_RECURSION_LIMIT } /* Couldn't or didn't match. */ if (lazy) { if (!greedy (next_op, 1)) MATCH_RETURN (0); num_matched++; /* Inch forward. */ } else if (num_matched > REG_ZERO) { num_matched--; /* Back up. */ } else if (min == REG_ZERO && num_matched == REG_ZERO) { break; } Reg_Input = save + num_matched; } MATCH_RETURN (0); } break; case END: if (Extent_Ptr_FW == NULL || (Reg_Input - Extent_Ptr_FW) > 0) { Extent_Ptr_FW = Reg_Input; } MATCH_RETURN (1); /* Success! */ break; case INIT_COUNT: Brace->count [*OPERAND (scan)] = REG_ZERO; break; case INC_COUNT: Brace->count [*OPERAND (scan)]++; break; case TEST_COUNT: if (Brace->count [*OPERAND (scan)] < (unsigned long) GET_OFFSET (scan + NEXT_PTR_SIZE + INDEX_SIZE)) { next = scan + NODE_SIZE + INDEX_SIZE + NEXT_PTR_SIZE; } break; case BACK_REF: case BACK_REF_CI: /* case X_REGEX_BR: */ /* case X_REGEX_BR_CI: *** IMPLEMENT LATER */ { register unsigned char *captured, *finish; int paren_no; paren_no = (int) *OPERAND (scan); /* if (GET_OP_CODE (scan) == X_REGEX_BR || GET_OP_CODE (scan) == X_REGEX_BR_CI) { if (Cross_Regex_Backref == NULL) MATCH_RETURN (0); captured = (unsigned char *) Cross_Regex_Backref->startp [paren_no]; finish = (unsigned char *) Cross_Regex_Backref->endp [paren_no]; } else { */ captured = Back_Ref_Start [paren_no]; finish = Back_Ref_End [paren_no]; /* } */ if ((captured != NULL) && (finish != NULL)) { if (captured > finish) MATCH_RETURN (0); if (GET_OP_CODE (scan) == BACK_REF_CI /* || GET_OP_CODE (scan) == X_REGEX_BR_CI*/ ) { while (captured < finish) { if (AT_END_OF_STRING(Reg_Input) || tolower (*captured++) != tolower (*Reg_Input++)) { MATCH_RETURN (0); } } } else { while (captured < finish) { if (AT_END_OF_STRING(Reg_Input) || *captured++ != *Reg_Input++) MATCH_RETURN (0); } } break; } else { MATCH_RETURN (0); } } case POS_AHEAD_OPEN: case NEG_AHEAD_OPEN: { register unsigned char *save; register unsigned char *saved_end; int answer; save = Reg_Input; /* Temporarily ignore the logical end of the string, to allow lookahead past the end. */ saved_end = End_Of_String; End_Of_String = NULL; answer = match (next, NULL); /* Does the look-ahead regex match? */ CHECK_RECURSION_LIMIT if ((GET_OP_CODE (scan) == POS_AHEAD_OPEN) ? answer : !answer) { /* Remember the last (most to the right) character position that we consume in the input for a successful match. This is info that may be needed should an attempt be made to match the exact same text at the exact same place. Since look-aheads backtrack, a regex with a trailing look-ahead may need more text than it matches to accomplish a re-match. */ if (Extent_Ptr_FW == NULL || (Reg_Input - Extent_Ptr_FW) > 0) { Extent_Ptr_FW = Reg_Input; } Reg_Input = save; /* Backtrack to look-ahead start. */ End_Of_String = saved_end; /* Restore logical end. */ /* Jump to the node just after the (?=...) or (?!...) Construct. */ next = next_ptr (OPERAND (scan)); /* Skip 1st branch */ /* Skip the chain of branches inside the look-ahead */ while(GET_OP_CODE(next) == BRANCH) next = next_ptr (next); next = next_ptr (next); /* Skip the LOOK_AHEAD_CLOSE */ } else { Reg_Input = save; /* Backtrack to look-ahead start. */ End_Of_String = saved_end; /* Restore logical end. */ MATCH_RETURN (0); } } break; case POS_BEHIND_OPEN: case NEG_BEHIND_OPEN: { register unsigned char *save; int answer; register int offset, upper; int lower; int found = 0; unsigned char *saved_end; save = Reg_Input; saved_end = End_Of_String; /* Prevent overshoot (greedy matching could end past the current position) by tightening the matching boundary. Lookahead inside lookbehind can still cross that boundary. */ End_Of_String = Reg_Input; lower = GET_LOWER (scan); upper = GET_UPPER (scan); /* Start with the shortest match first. This is the most efficient direction in general. Note! Negative look behind is _very_ tricky when the length is not constant: we have to make sure the expression doesn't match for _any_ of the starting positions. */ for (offset = lower; offset <= upper; ++offset) { Reg_Input = save - offset; if (Reg_Input < Look_Behind_To) { /* No need to look any further */ break; } answer = match (next, NULL); /* Does the look-behind regex match? */ CHECK_RECURSION_LIMIT /* The match must have ended at the current position; otherwise it is invalid */ if (answer && Reg_Input == save) { /* It matched, exactly far enough */ found = 1; /* Remember the last (most to the left) character position that we consume in the input for a successful match. This is info that may be needed should an attempt be made to match the exact same text at the exact same place. Since look-behind backtracks, a regex with a leading look-behind may need more text than it matches to accomplish a re-match. */ if (Extent_Ptr_BW == NULL || (Extent_Ptr_BW - (save - offset)) > 0) { Extent_Ptr_BW = save - offset; } break; } } /* Always restore the position and the logical string end. */ Reg_Input = save; End_Of_String = saved_end; if ((GET_OP_CODE (scan) == POS_BEHIND_OPEN) ? found : !found) { /* The look-behind matches, so we must jump to the next node. The look-behind node is followed by a chain of branches (contents of the look-behind expression), and terminated by a look-behind-close node. */ next = next_ptr (OPERAND (scan) + LENGTH_SIZE); /* 1st branch */ /* Skip the chained branches inside the look-ahead */ while (GET_OP_CODE (next) == BRANCH) next = next_ptr (next); next = next_ptr (next); /* Skip LOOK_BEHIND_CLOSE */ } else { /* Not a match */ MATCH_RETURN (0); } } break; case LOOK_AHEAD_CLOSE: case LOOK_BEHIND_CLOSE: MATCH_RETURN (1); /* We have reached the end of the look-ahead or look-behind which implies that we matched it, so return TRUE. */ default: if ((GET_OP_CODE (scan) > OPEN) && (GET_OP_CODE (scan) < OPEN + NSUBEXP)) { register int no; register unsigned char *save; no = GET_OP_CODE (scan) - OPEN; save = Reg_Input; if (no < 10) { Back_Ref_Start [no] = save; Back_Ref_End [no] = NULL; } if (match (next, NULL)) { /* Do not set `Start_Ptr_Ptr' if some later invocation (think recursion) of the same parentheses already has. */ if (Start_Ptr_Ptr [no] == NULL) Start_Ptr_Ptr [no] = save; MATCH_RETURN (1); } else { MATCH_RETURN (0); } } else if ((GET_OP_CODE (scan) > CLOSE) && (GET_OP_CODE (scan) < CLOSE + NSUBEXP)) { register int no; register unsigned char *save; no = GET_OP_CODE (scan) - CLOSE; save = Reg_Input; if (no < 10) Back_Ref_End [no] = save; if (match (next, NULL)) { /* Do not set `End_Ptr_Ptr' if some later invocation of the same parentheses already has. */ if (End_Ptr_Ptr [no] == NULL) End_Ptr_Ptr [no] = save; MATCH_RETURN (1); } else { MATCH_RETURN (0); } } else { reg_error ("memory corruption, `match\'"); MATCH_RETURN (0); } break; } scan = next; } /* We get here only if there's trouble -- normally "case END" is the terminating point. */ reg_error ("corrupted pointers, `match\'"); MATCH_RETURN (0); } /*----------------------------------------------------------------------* * greedy * * Repeatedly match something simple up to "max" times. If max <= 0 * then match as much as possible (max = infinity). Uses unsigned long * variables to maximize the amount of text matchable for unbounded * qualifiers like '*' and '+'. This will allow at least 4,294,967,295 * matches (4 Gig!) for an ANSI C compliant compiler. If you are * applying a regex to something bigger than that, you shouldn't be * using NEdit! * * Returns the actual number of matches. *----------------------------------------------------------------------*/ static unsigned long greedy (unsigned char *p, long max) { register unsigned char *input_str; register unsigned char *operand; register unsigned long count = REG_ZERO; register unsigned long max_cmp; input_str = Reg_Input; operand = OPERAND (p); /* Literal char or start of class characters. */ max_cmp = (max > 0) ? (unsigned long) max : ULONG_MAX; switch (GET_OP_CODE (p)) { case ANY: /* Race to the end of the line or string. Dot DOESN'T match newline. */ while (count < max_cmp && *input_str != '\n' && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; case EVERY: /* Race to the end of the line or string. Dot DOES match newline. */ while (count < max_cmp && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; case EXACTLY: /* Count occurrences of single character operand. */ while (count < max_cmp && *operand == *input_str && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; case SIMILAR: /* Case insensitive version of EXACTLY */ while (count < max_cmp && *operand == tolower (*input_str) && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; case ANY_OF: /* [...] character class. */ while (count < max_cmp && strchr ((char *) operand, (int) *input_str) != NULL && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; case ANY_BUT: /* [^...] Negated character class- does NOT normally match newline (\n added usually to operand at compile time.) */ while (count < max_cmp && strchr ((char *) operand, (int) *input_str) == NULL && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; case IS_DELIM: /* \y (not a word delimiter char) NOTE: '\n' and '\0' are always word delimiters. */ while (count < max_cmp && Current_Delimiters [ *input_str ] && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; case NOT_DELIM: /* \Y (not a word delimiter char) NOTE: '\n' and '\0' are always word delimiters. */ while (count < max_cmp && !Current_Delimiters [ *input_str ] && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; case WORD_CHAR: /* \w (word character, alpha-numeric or underscore) */ while (count < max_cmp && (isalnum ((int) *input_str) || *input_str == (unsigned char) '_') && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; case NOT_WORD_CHAR:/* \W (NOT a word character) */ while (count < max_cmp && !isalnum ((int) *input_str) && *input_str != (unsigned char) '_' && *input_str != (unsigned char) '\n' && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; case DIGIT: /* same as [0123456789] */ while (count < max_cmp && isdigit ((int) *input_str) && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; case NOT_DIGIT: /* same as [^0123456789] */ while (count < max_cmp && !isdigit ((int) *input_str) && *input_str != '\n' && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; case SPACE: /* same as [ \t\r\f\v]-- doesn't match newline. */ while (count < max_cmp && isspace ((int) *input_str) && *input_str != '\n' && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; case SPACE_NL: /* same as [\n \t\r\f\v]-- matches newline. */ while (count < max_cmp && isspace ((int) *input_str) && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; case NOT_SPACE: /* same as [^\n \t\r\f\v]-- doesn't match newline. */ while (count < max_cmp && !isspace ((int) *input_str) && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; case NOT_SPACE_NL: /* same as [^ \t\r\f\v]-- matches newline. */ while (count < max_cmp && (!isspace ((int) *input_str) || *input_str == '\n') && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; case LETTER: /* same as [a-zA-Z] */ while (count < max_cmp && isalpha ((int) *input_str) && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; case NOT_LETTER: /* same as [^a-zA-Z] */ while (count < max_cmp && !isalpha ((int) *input_str) && *input_str != '\n' && !AT_END_OF_STRING(input_str)) { count++; input_str++; } break; default: /* Called inappropriately. Only atoms that are SIMPLE should generate a call to greedy. The above cases should cover all the atoms that are SIMPLE. */ reg_error ("internal error #10 `greedy\'"); count = 0U; /* Best we can do. */ } /* Point to character just after last matched character. */ Reg_Input = input_str; return (count); } /*----------------------------------------------------------------------* * next_ptr - compute the address of a node's "NEXT" pointer. * Note: a simplified inline version is available via the NEXT_PTR() macro, * but that one is only to be used at time-critical places (see the * description of the macro). *----------------------------------------------------------------------*/ static unsigned char * next_ptr (unsigned char *ptr) { register int offset; if (ptr == &Compute_Size) return (NULL); offset = GET_OFFSET (ptr); if (offset == 0) return (NULL); if (GET_OP_CODE (ptr) == BACK) { return (ptr - offset); } else { return (ptr + offset); } } /* ** SubstituteRE - Perform substitutions after a `regexp' match. ** ** This function cleanly shortens results of more than max length to max. ** To give the caller a chance to react to this the function returns False ** on any error. The substitution will still be executed. */ Boolean SubstituteRE(const regexp* prog, const char* source, char* dest, const int max) { register unsigned char *src; unsigned char *src_alias; register unsigned char *dst; register unsigned char c; register unsigned char test; register int paren_no; register int len; register unsigned char chgcase; Boolean anyWarnings = False; if (prog == NULL || source == NULL || dest == NULL) { reg_error ("NULL parm to `SubstituteRE\'"); return False; } if (U_CHAR_AT (prog->program) != MAGIC) { reg_error ("damaged regexp passed to `SubstituteRE\'"); return False; } src = (unsigned char *) source; dst = (unsigned char *) dest; while ((c = *src++) != '\0') { chgcase = '\0'; paren_no = -1; if (c == '\\') { /* Process any case altering tokens, i.e \u, \U, \l, \L. */ if (*src == 'u' || *src == 'U' || *src == 'l' || *src == 'L') { chgcase = *src; src++; c = *src++; if (c == '\0') break; } } if (c == '&') { paren_no = 0; } else if (c == '\\') { /* Can not pass register variable `&src' to function `numeric_escape' so make a non-register copy that we can take the address of. */ src_alias = src; if ('1' <= *src && *src <= '9') { paren_no = (int) *src++ - (int) '0'; } else if ((test = literal_escape (*src)) != '\0') { c = test; src++; } else if ((test = numeric_escape (*src, &src_alias)) != '\0') { c = test; src = src_alias; src++; /* NOTE: if an octal escape for zero is attempted (e.g. \000), it will be treated as a literal string. */ } else if (*src == '\0') { /* If '\' is the last character of the replacement string, it is interpreted as a literal backslash. */ c = '\\'; } else { c = *src++; /* Allow any escape sequence (This is */ } /* INCONSISTENT with the `CompileRE' */ } /* mind set of issuing an error! */ if (paren_no < 0) { /* Ordinary character. */ if (((char *) dst - (char *) dest) >= (max - 1)) { reg_error("replacing expression in `SubstituteRE\' too long; " "truncating"); anyWarnings = True; break; } else { *dst++ = c; } } else if (prog->startp [paren_no] != NULL && prog->endp [paren_no] != NULL) { len = prog->endp [paren_no] - prog->startp [paren_no]; if (((char *) dst + len - (char *) dest) >= max-1) { reg_error("replacing expression in `SubstituteRE\' too long; " "truncating"); anyWarnings = True; len = max - ((char *) dst - (char *) dest) - 1; } (void) strncpy ((char *) dst, (char *) prog->startp [paren_no], len); if (chgcase != '\0') adjustcase (dst, len, chgcase); dst += len; if (len != 0 && *(dst - 1) == '\0') { /* strncpy hit NUL. */ reg_error ("damaged match string in `SubstituteRE\'"); anyWarnings = True; } } } *dst = '\0'; return !anyWarnings; } static void adjustcase (unsigned char *str, int len, unsigned char chgcase) { register unsigned char *string = str; int i; /* The tokens \u and \l only modify the first character while the tokens \U and \L modify the entire string. */ if (islower (chgcase) && len > 0) len = 1; switch (chgcase) { case 'u': case 'U': for (i = 0; i < len; i++) { *(string + i) = toupper ((int) *(string + i)); } break; case 'l': case 'L': for (i = 0; i < len; i++) { *(string + i) = tolower ((int) *(string + i)); } break; } } /*----------------------------------------------------------------------* * reg_error *----------------------------------------------------------------------*/ static void reg_error (char *str) { fprintf ( stderr, "nedit: Internal error processing regular expression (%s)\n", str); } /*----------------------------------------------------------------------* * makeDelimiterTable * * Translate a null-terminated string of delimiters into a 256 byte * lookup table for determining whether a character is a delimiter or * not. * * Table must be allocated by the caller. * * Return value is a pointer to the table. *----------------------------------------------------------------------*/ static unsigned char * makeDelimiterTable ( unsigned char *delimiters, unsigned char *table) { unsigned char *c; memset (table, 0, 256); for (c = (unsigned char *) delimiters; *c != '\0'; c++) { table [*c] = 1; } table [(int) NULL] = 1; /* These */ table [(int) '\t'] = 1; /* characters */ table [(int) '\n'] = 1; /* are always */ table [(int) ' ' ] = 1; /* delimiters. */ return table; } /*----------------------------------------------------------------------* * SetREDefaultWordDelimiters * * Builds a default delimiter table that persists across `ExecRE' calls. *----------------------------------------------------------------------*/ void SetREDefaultWordDelimiters (char *delimiters) { makeDelimiterTable ((unsigned char *) delimiters, Default_Delimiters); } nedit-5.6.orig/source/regularExp.h0000644000175000017500000001251510737527370015720 0ustar paulpaul/* $Id: regularExp.h,v 1.16 2008/01/04 22:11:04 yooden Exp $ */ /******************************************************************************* * * * regularExp.h -- Nirvana Editor Regular Expression Package Header File * * * * Copyright 2002 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #include #ifndef NEDIT_REGULAREXP_H_INCLUDED #define NEDIT_REGULAREXP_H_INCLUDED /* Number of text capturing parentheses allowed. */ #define NSUBEXP 50 /* Structure to contain the compiled form of a regular expression plus pointers to matched text. `program' is the actual compiled regex code. */ typedef struct regexp { char *startp [NSUBEXP]; /* Captured text starting locations. */ char *endp [NSUBEXP]; /* Captured text ending locations. */ char *extentpBW; /* Points to the maximum extent of text scanned by ExecRE in front of the string to achieve a match (needed because of positive look-behind.) */ char *extentpFW; /* Points to the maximum extent of text scanned by ExecRE to achieve a match (needed because of positive look-ahead.) */ int top_branch; /* Zero-based index of the top branch that matches. Used by syntax highlighting only. */ char match_start; /* Internal use only. */ char anchor; /* Internal use only. */ char program [1]; /* Unwarranted chumminess with compiler. */ } regexp; /* Flags for CompileRE default settings (Markus Schwarzenberg) */ typedef enum { REDFLT_STANDARD = 0, REDFLT_CASE_INSENSITIVE = 1 /* REDFLT_MATCH_NEWLINE = 2 Currently not used. */ } RE_DEFAULT_FLAG; /* Compiles a regular expression into the internal format used by `ExecRE'. */ regexp * CompileRE ( const char *exp, /* String containing the regex specification. */ char **errorText, /* Text of any error message produced. */ int defaultFlags); /* Flags for default RE-operation */ /* Match a `regexp' structure against a string. */ int ExecRE ( regexp *prog, /* Compiled regex. */ const char *string, /* Text to search within. */ const char *end, /* Pointer to the end of `string'. If NULL will scan from `string' until '\0' is found. */ int reverse, /* Backward search. */ char prev_char, /* Character immediately prior to `string'. Set to '\n' or '\0' if true beginning of text. */ char succ_char, /* Character immediately after `end'. Set to '\n' or '\0' if true beginning of text. */ const char *delimiters, /* Word delimiters to use (NULL for default) */ const char *look_behind_to,/* Boundary for look-behind; defaults to "string" if NULL */ const char *match_till); /* Boundary to where match can extend. \0 is assumed to be the boundary if not set. Lookahead can cross the boundary. */ /* Perform substitutions after a `regexp' match. */ Boolean SubstituteRE(const regexp* prog, const char* source, char* dest, const int max); /* Builds a default delimiter table that persists across `ExecRE' calls that is identical to `delimiters'. Pass NULL for "default default" set of delimiters. */ void SetREDefaultWordDelimiters ( char *delimiters); #endif /* NEDIT_REGULAREXP_H_INCLUDED */ nedit-5.6.orig/source/search.c0000644000175000017500000056714211110456100015027 0ustar paulpaulstatic const char CVSID[] = "$Id: search.c,v 1.89.2.1 2008/10/06 21:03:05 ajbj Exp $"; /******************************************************************************* * * * search.c -- Nirvana Editor search and replace functions * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * May 10, 1991 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "search.h" #include "regularExp.h" #include "textBuf.h" #include "text.h" #include "nedit.h" #include "server.h" #include "window.h" #include "userCmds.h" #include "preferences.h" #include "file.h" #include "highlight.h" #include "selection.h" #ifdef REPLACE_SCOPE #include "textDisp.h" #include "textP.h" #endif #include "../util/DialogF.h" #include "../util/misc.h" #include #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #include #include #include #include #include #ifdef REPLACE_SCOPE #if XmVersion >= 1002 #include #endif #endif #include #include #include #include #include #include /* for getting selection */ #include #include /* " " */ #ifdef HAVE_DEBUG_H #include "../debug.h" #endif int NHist = 0; typedef struct _SelectionInfo { int done; WindowInfo* window; char* selection; } SelectionInfo; typedef struct { int direction; int searchType; int searchWrap; } SearchSelectedCallData; /* History mechanism for search and replace strings */ static char *SearchHistory[MAX_SEARCH_HISTORY]; static char *ReplaceHistory[MAX_SEARCH_HISTORY]; static int SearchTypeHistory[MAX_SEARCH_HISTORY]; static int HistStart = 0; static int textFieldNonEmpty(Widget w); static void setTextField(WindowInfo* window, Time time, Widget textField); static void getSelectionCB(Widget w, SelectionInfo *selectionInfo, Atom *selection, Atom *type, char *value, int *length, int *format); static void fFocusCB(Widget w, WindowInfo *window, caddr_t *callData); static void rFocusCB(Widget w, WindowInfo *window, caddr_t *callData); static void rKeepCB(Widget w, WindowInfo *window, caddr_t *callData); static void fKeepCB(Widget w, WindowInfo *window, caddr_t *callData); static void replaceCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData); static void replaceAllCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData); static void rInSelCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData); static void rCancelCB(Widget w, WindowInfo *window, caddr_t callData); static void fCancelCB(Widget w, WindowInfo *window, caddr_t callData); static void rFindCB(Widget w,WindowInfo *window,XmAnyCallbackStruct *callData); static void rFindTextValueChangedCB(Widget w, WindowInfo *window, XKeyEvent *event); static void rFindArrowKeyCB(Widget w, WindowInfo *window, XKeyEvent *event); static void rSetActionButtons(WindowInfo* window, int replaceBtn, int replaceFindBtn, int replaceAndFindBtn, #ifndef REPLACE_SCOPE int replaceInWinBtn, int replaceInSelBtn, #endif int replaceAllBtn); #ifdef REPLACE_SCOPE static void rScopeWinCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData); static void rScopeSelCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData); static void rScopeMultiCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData); static void replaceAllScopeCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData); #endif static void replaceArrowKeyCB(Widget w, WindowInfo *window, XKeyEvent *event); static void fUpdateActionButtons(WindowInfo *window); static void findTextValueChangedCB(Widget w, WindowInfo *window, XKeyEvent *event); static void findArrowKeyCB(Widget w, WindowInfo *window, XKeyEvent *event); static void replaceFindCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData); static void findCB(Widget w, WindowInfo *window,XmAnyCallbackStruct *callData); static void replaceMultiFileCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData); static void rMultiFileReplaceCB(Widget w, WindowInfo *window, XmAnyCallbackStruct * callData); static void rMultiFileCancelCB(Widget w, WindowInfo *window, caddr_t callData); static void rMultiFileSelectAllCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData); static void rMultiFileDeselectAllCB(Widget w, WindowInfo *window, XmAnyCallbackStruct * callData); static void rMultiFilePathCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData); static void uploadFileListItems(WindowInfo* window, Bool replace); static int countWindows(void); static int countWritableWindows(void); static void collectWritableWindows(WindowInfo* window); static void freeWritableWindowsCB(Widget w, WindowInfo* window, XmAnyCallbackStruct *callData); static void checkMultiReplaceListForDoomedW(WindowInfo* window, WindowInfo* doomedWindow); static void removeDoomedWindowFromList(WindowInfo* window, int index); static void unmanageReplaceDialogs(const WindowInfo *window); static void flashTimeoutProc(XtPointer clientData, XtIntervalId *id); static void eraseFlash(WindowInfo *window); static int getReplaceDlogInfo(WindowInfo *window, int *direction, char *searchString, char *replaceString, int *searchType); static int getFindDlogInfo(WindowInfo *window, int *direction, char *searchString, int *searchType); static void selectedSearchCB(Widget w, XtPointer callData, Atom *selection, Atom *type, char *value, int *length, int *format); static void iSearchTextClearAndPasteAP(Widget w, XEvent *event, String *args, Cardinal *nArg); static void iSearchTextClearCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData); static void iSearchTextActivateCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData); static void iSearchTextValueChangedCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData); static void iSearchTextKeyEH(Widget w, WindowInfo *window, XKeyEvent *event, Boolean *continueDispatch); static int searchLiteral(const char *string, const char *searchString, int caseSense, int direction, int wrap, int beginPos, int *startPos, int *endPos, int *searchExtentBW, int *searchExtentFW); static int searchLiteralWord(const char *string, const char *searchString, int caseSense, int direction, int wrap, int beginPos, int *startPos, int *endPos, const char * delimiters); static int searchRegex(const char *string, const char *searchString, int direction, int wrap, int beginPos, int *startPos, int *endPos, int *searchExtentBW, int *searchExtentFW, const char *delimiters, int defaultFlags); static int forwardRegexSearch(const char *string, const char *searchString, int wrap, int beginPos, int *startPos, int *endPos, int *searchExtentBW, int *searchExtentFW, const char *delimiters, int defaultFlags); static int backwardRegexSearch(const char *string, const char *searchString, int wrap, int beginPos, int *startPos, int *endPos, int *searchExtentBW, int *searchExtentFW, const char *delimiters, int defaultFlags); static void upCaseString(char *outString, const char *inString); static void downCaseString(char *outString, const char *inString); static void resetFindTabGroup(WindowInfo *window); static void resetReplaceTabGroup(WindowInfo *window); static int searchMatchesSelection(WindowInfo *window, const char *searchString, int searchType, int *left, int *right, int *searchExtentBW, int *searchExtentFW); static int findMatchingChar(WindowInfo *window, char toMatch, void *toMatchStyle, int charPos, int startLimit, int endLimit, int *matchPos); static Boolean replaceUsingRE(const char* searchStr, const char* replaceStr, const char* sourceStr, int beginPos, char* destStr, int maxDestLen, int prevChar, const char* delimiters, int defaultFlags); static void saveSearchHistory(const char *searchString, const char *replaceString, int searchType, int isIncremental); static int historyIndex(int nCycles); static char *searchTypeArg(int searchType); static char *searchWrapArg(int searchWrap); static char *directionArg(int direction); static int isRegexType(int searchType); static int defaultRegexFlags(int searchType); static void findRegExpToggleCB(Widget w, XtPointer clientData, XtPointer callData); static void replaceRegExpToggleCB(Widget w, XtPointer clientData, XtPointer callData); static void iSearchRegExpToggleCB(Widget w, XtPointer clientData, XtPointer callData); static void findCaseToggleCB(Widget w, XtPointer clientData, XtPointer callData); static void replaceCaseToggleCB(Widget w, XtPointer clientData, XtPointer callData); static void iSearchCaseToggleCB(Widget w, XtPointer clientData, XtPointer callData); static void iSearchTryBeepOnWrap(WindowInfo *window, int direction, int beginPos, int startPos); static void iSearchRecordLastBeginPos(WindowInfo *window, int direction, int initPos); static Boolean prefOrUserCancelsSubst(const Widget parent, const Display* display); typedef struct _charMatchTable { char c; char match; char direction; } charMatchTable; #define N_MATCH_CHARS 13 #define N_FLASH_CHARS 6 static charMatchTable MatchingChars[N_MATCH_CHARS] = { {'{', '}', SEARCH_FORWARD}, {'}', '{', SEARCH_BACKWARD}, {'(', ')', SEARCH_FORWARD}, {')', '(', SEARCH_BACKWARD}, {'[', ']', SEARCH_FORWARD}, {']', '[', SEARCH_BACKWARD}, {'<', '>', SEARCH_FORWARD}, {'>', '<', SEARCH_BACKWARD}, {'/', '/', SEARCH_FORWARD}, {'"', '"', SEARCH_FORWARD}, {'\'', '\'', SEARCH_FORWARD}, {'`', '`', SEARCH_FORWARD}, {'\\', '\\', SEARCH_FORWARD}, }; /* ** Definitions for the search method strings, used as arguments for ** macro search subroutines and search action routines */ static char *searchTypeStrings[] = { "literal", /* SEARCH_LITERAL */ "case", /* SEARCH_CASE_SENSE */ "regex", /* SEARCH_REGEX */ "word", /* SEARCH_LITERAL_WORD */ "caseWord", /* SEARCH_CASE_SENSE_WORD */ "regexNoCase", /* SEARCH_REGEX_NOCASE */ NULL }; /* ** Window for which a search dialog callback is currently active. That window ** cannot be safely closed because the callback would access the armed button ** after it got destroyed. ** Note that an attempt to close such a window can only happen if the search ** action triggers a modal dialog and the user tries to close the window via ** the window manager without dismissing the dialog first. It is up to the ** close callback of the window to intercept and reject the request by calling ** the WindowCanBeClosed() function. */ static WindowInfo *windowNotToClose = NULL; Boolean WindowCanBeClosed(WindowInfo *window) { if (windowNotToClose && GetTopDocument(window->shell) == GetTopDocument(windowNotToClose->shell)) { return False; } return True; /* It's safe */ } /* ** Shared routine for replace and find dialogs and i-search bar to initialize ** the state of the regex/case/word toggle buttons, and the sticky case ** sensitivity states. */ static void initToggleButtons(int searchType, Widget regexToggle, Widget caseToggle, Widget* wordToggle, Bool* lastLiteralCase, Bool* lastRegexCase) { /* Set the initial search type and remember the corresponding case sensitivity states in case sticky case sensitivity is required. */ switch (searchType) { case SEARCH_LITERAL: *lastLiteralCase = False; *lastRegexCase = True; XmToggleButtonSetState(regexToggle, False, False); XmToggleButtonSetState(caseToggle, False, False); if (wordToggle) { XmToggleButtonSetState(*wordToggle, False, False); XtSetSensitive(*wordToggle, True); } break; case SEARCH_CASE_SENSE: *lastLiteralCase = True; *lastRegexCase = True; XmToggleButtonSetState(regexToggle, False, False); XmToggleButtonSetState(caseToggle, True, False); if (wordToggle) { XmToggleButtonSetState(*wordToggle, False, False); XtSetSensitive(*wordToggle, True); } break; case SEARCH_LITERAL_WORD: *lastLiteralCase = False; *lastRegexCase = True; XmToggleButtonSetState(regexToggle, False, False); XmToggleButtonSetState(caseToggle, False, False); if (wordToggle) { XmToggleButtonSetState(*wordToggle, True, False); XtSetSensitive(*wordToggle, True); } break; case SEARCH_CASE_SENSE_WORD: *lastLiteralCase = True; *lastRegexCase = True; XmToggleButtonSetState(regexToggle, False, False); XmToggleButtonSetState(caseToggle, True, False); if (wordToggle) { XmToggleButtonSetState(*wordToggle, True, False); XtSetSensitive(*wordToggle, True); } break; case SEARCH_REGEX: *lastLiteralCase = False; *lastRegexCase = True; XmToggleButtonSetState(regexToggle, True, False); XmToggleButtonSetState(caseToggle, True, False); if (wordToggle) { XmToggleButtonSetState(*wordToggle, False, False); XtSetSensitive(*wordToggle, False); } break; case SEARCH_REGEX_NOCASE: *lastLiteralCase = False; *lastRegexCase = False; XmToggleButtonSetState(regexToggle, True, False); XmToggleButtonSetState(caseToggle, False, False); if (wordToggle) { XmToggleButtonSetState(*wordToggle, False, False); XtSetSensitive(*wordToggle, False); } break; } } #ifdef REPLACE_SCOPE /* ** Checks whether a selection spans multiple lines. Used to decide on the ** default scope for replace dialogs. ** This routine introduces a dependency on textDisp.h, which is not so nice, ** but I currently don't have a cleaner solution. */ static int selectionSpansMultipleLines(WindowInfo *window) { int selStart, selEnd, isRect, rectStart, rectEnd, lineStartStart, lineStartEnd; int lineWidth; textDisp *textD; if (!BufGetSelectionPos(window->buffer, &selStart, &selEnd, &isRect, &rectStart, &rectEnd)) return FALSE; /* This is kind of tricky. The perception of a line depends on the line wrap mode being used. So in theory, we should take into account the layout of the text on the screen. However, the routine to calculate a line number for a given character position (TextDPosToLineAndCol) only works for displayed lines, so we cannot use it. Therefore, we use this simple heuristic: - If a newline is found between the start and end of the selection, we obviously have a multi-line selection. - If no newline is found, but the distance between the start and the end of the selection is larger than the number of characters displayed on a line, and we're in continuous wrap mode, we also assume a multi-line selection. */ lineStartStart = BufStartOfLine(window->buffer, selStart); lineStartEnd = BufStartOfLine(window->buffer, selEnd); /* If the line starts differ, we have a "\n" in between. */ if (lineStartStart != lineStartEnd ) return TRUE; if (window->wrapMode != CONTINUOUS_WRAP) return FALSE; /* Same line */ /* Estimate the number of characters on a line */ textD = ((TextWidget)window->textArea)->text.textD; if (textD->fontStruct->max_bounds.width > 0) lineWidth = textD->width / textD->fontStruct->max_bounds.width; else lineWidth = 1; if (lineWidth < 1) lineWidth = 1; /* Just in case */ /* Estimate the numbers of line breaks from the start of the line to the start and ending positions of the selection and compare.*/ if ((selStart-lineStartStart)/lineWidth != (selEnd-lineStartStart)/lineWidth ) return TRUE; /* Spans multiple lines */ return FALSE; /* Small selection; probably doesn't span lines */ } #endif void DoFindReplaceDlog(WindowInfo *window, int direction, int keepDialogs, int searchType, Time time) { /* Create the dialog if it doesn't already exist */ if (window->replaceDlog == NULL) CreateReplaceDlog(window->shell, window); setTextField(window, time, window->replaceText); /* If the window is already up, just pop it to the top */ if (XtIsManaged(window->replaceDlog)) { RaiseDialogWindow(XtParent(window->replaceDlog)); return; } /* Blank the Replace with field */ XmTextSetString(window->replaceWithText, ""); /* Set the initial search type */ initToggleButtons(searchType, window->replaceRegexToggle, window->replaceCaseToggle, &window->replaceWordToggle, &window->replaceLastLiteralCase, &window->replaceLastRegexCase); /* Set the initial direction based on the direction argument */ XmToggleButtonSetState(window->replaceRevToggle, direction == SEARCH_FORWARD ? False: True, True); /* Set the state of the Keep Dialog Up button */ XmToggleButtonSetState(window->replaceKeepBtn, keepDialogs, True); #ifdef REPLACE_SCOPE /* Set the state of the scope radio buttons to "In Window". Notify to make sure that callbacks are called. NOTE: due to an apparent bug in OpenMotif, the radio buttons may get stuck after resetting the scope to "In Window". Therefore we must use RadioButtonChangeState(), which contains a workaround. */ if (window->wasSelected) { /* If a selection exists, the default scope depends on the preference of the user. */ switch(GetPrefReplaceDefScope()) { case REPL_DEF_SCOPE_SELECTION: /* The user prefers selection scope, no matter what the size of the selection is. */ RadioButtonChangeState(window->replaceScopeSelToggle, True, True); break; case REPL_DEF_SCOPE_SMART: if (selectionSpansMultipleLines(window)) { /* If the selection spans multiple lines, the user most likely wants to perform a replacement in the selection */ RadioButtonChangeState(window->replaceScopeSelToggle, True, True); } else { /* It's unlikely that the user wants a replacement in a tiny selection only. */ RadioButtonChangeState(window->replaceScopeWinToggle, True, True); } break; default: /* The user always wants window scope as default. */ RadioButtonChangeState(window->replaceScopeWinToggle, True, True); break; } } else { /* No selection -> always choose "In Window" as default. */ RadioButtonChangeState(window->replaceScopeWinToggle, True, True); } #endif UpdateReplaceActionButtons(window); /* Start the search history mechanism at the current history item */ window->rHistIndex = 0; /* Display the dialog */ ManageDialogCenteredOnPointer(window->replaceDlog); /* Workaround: LessTif (as of version 0.89) needs reminding of who had the focus when the dialog was unmanaged. When re-managed, focus is lost and events fall through to the window below. */ XmProcessTraversal(window->replaceText, XmTRAVERSE_CURRENT); } static void setTextField(WindowInfo *window, Time time, Widget textField) { XEvent nextEvent; char *primary_selection = 0; SelectionInfo *selectionInfo = XtNew(SelectionInfo); if (GetPrefFindReplaceUsesSelection()) { selectionInfo->done = 0; selectionInfo->window = window; selectionInfo->selection = 0; XtGetSelectionValue(window->textArea, XA_PRIMARY, XA_STRING, (XtSelectionCallbackProc)getSelectionCB, selectionInfo, time); while (selectionInfo->done == 0) { XtAppNextEvent(XtWidgetToApplicationContext(window->textArea), &nextEvent); ServerDispatchEvent(&nextEvent); } primary_selection = selectionInfo->selection; } if (primary_selection == 0) { primary_selection = XtNewString(""); } /* Update the field */ XmTextSetString(textField, primary_selection); XtFree(primary_selection); XtFree((char*)selectionInfo); } static void getSelectionCB(Widget w, SelectionInfo *selectionInfo, Atom *selection, Atom *type, char *value, int *length, int *format) { WindowInfo *window = selectionInfo->window; /* return an empty string if we can't get the selection data */ if (*type == XT_CONVERT_FAIL || *type != XA_STRING || value == NULL || *length == 0) { XtFree(value); selectionInfo->selection = 0; selectionInfo->done = 1; return; } /* return an empty string if the data is not of the correct format. */ if (*format != 8) { DialogF(DF_WARN, window->shell, 1, "Invalid Format", "NEdit can't handle non 8-bit text", "OK"); XtFree(value); selectionInfo->selection = 0; selectionInfo->done = 1; return; } selectionInfo->selection = XtMalloc(*length+1); memcpy(selectionInfo->selection, value, *length); selectionInfo->selection[*length] = 0; XtFree(value); selectionInfo->done = 1; } void DoFindDlog(WindowInfo *window, int direction, int keepDialogs, int searchType, Time time) { /* Create the dialog if it doesn't already exist */ if (window->findDlog == NULL) CreateFindDlog(window->shell, window); setTextField(window, time, window->findText); /* If the window is already up, just pop it to the top */ if (XtIsManaged(window->findDlog)) { RaiseDialogWindow(XtParent(window->findDlog)); return; } /* Set the initial search type */ initToggleButtons(searchType, window->findRegexToggle, window->findCaseToggle, &window->findWordToggle, &window->findLastLiteralCase, &window->findLastRegexCase); /* Set the initial direction based on the direction argument */ XmToggleButtonSetState(window->findRevToggle, direction == SEARCH_FORWARD ? False : True, True); /* Set the state of the Keep Dialog Up button */ XmToggleButtonSetState(window->findKeepBtn, keepDialogs, True); /* Set the state of the Find button */ fUpdateActionButtons(window); /* start the search history mechanism at the current history item */ window->fHistIndex = 0; /* Display the dialog */ ManageDialogCenteredOnPointer(window->findDlog); /* Workaround: LessTif (as of version 0.89) needs reminding of who had the focus when the dialog was unmanaged. When re-managed, focus is lost and events fall through to the window below. */ XmProcessTraversal(window->findText, XmTRAVERSE_CURRENT); } void DoReplaceMultiFileDlog(WindowInfo *window) { char searchString[SEARCHMAX], replaceString[SEARCHMAX]; int direction, searchType; /* Validate and fetch the find and replace strings from the dialog */ if (!getReplaceDlogInfo(window, &direction, searchString, replaceString, &searchType)) return; /* Don't let the user select files when no replacement can be made */ if (*searchString == '\0') { /* Set the initial focus of the dialog back to the search string */ resetReplaceTabGroup(window); /* pop down the replace dialog */ if (!XmToggleButtonGetState(window->replaceKeepBtn)) unmanageReplaceDialogs(window); return; } /* Create the dialog if it doesn't already exist */ if (window->replaceMultiFileDlog == NULL) CreateReplaceMultiFileDlog(window); /* Raising the window doesn't make sense. It is modal, so we can't get here unless it is unmanaged */ /* Prepare a list of writable windows */ collectWritableWindows(window); /* Initialize/update the list of files. */ uploadFileListItems(window, False); /* Display the dialog */ ManageDialogCenteredOnPointer(window->replaceMultiFileDlog); } /* ** If a window is closed (possibly via the window manager) while it is on the ** multi-file replace dialog list of any other window (or even the same one), ** we must update those lists or we end up with dangling references. ** Normally, there can be only one of those dialogs at the same time ** (application modal), but Lesstif doesn't (always) honor application ** modalness, so there can be more than one dialog. */ void RemoveFromMultiReplaceDialog(WindowInfo *doomedWindow) { WindowInfo *w; for (w=WindowList; w!=NULL; w=w->next) if (w->writableWindows) /* A multi-file replacement dialog is up for this window */ checkMultiReplaceListForDoomedW(w, doomedWindow); } void CreateReplaceDlog(Widget parent, WindowInfo *window) { Arg args[50]; int argcnt, defaultBtnOffset; XmString st1; Widget form, btnForm; #ifdef REPLACE_SCOPE Widget scopeForm, replaceAllBtn; #else Widget label3, allForm; #endif Widget inWinBtn, inSelBtn, inMultiBtn; Widget searchTypeBox; Widget label2, label1, label, replaceText, findText; Widget findBtn, cancelBtn, replaceBtn; Widget replaceFindBtn; Widget searchDirBox, reverseBtn, keepBtn; char title[MAXPATHLEN + 19]; Dimension shadowThickness; argcnt = 0; XtSetArg(args[argcnt], XmNautoUnmanage, False); argcnt++; form = CreateFormDialog(parent, "replaceDialog", args, argcnt); XtVaSetValues(form, XmNshadowThickness, 0, NULL); if (GetPrefKeepSearchDlogs()) { sprintf(title, "Replace/Find (in %s)", window->filename); XtVaSetValues(XtParent(form), XmNtitle, title, NULL); } else XtVaSetValues(XtParent(form), XmNtitle, "Replace/Find", NULL); argcnt = 0; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 4); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNalignment, XmALIGNMENT_BEGINNING); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("String to Find:")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 't'); argcnt++; label1 = XmCreateLabel(form, "label1", args, argcnt); XmStringFree(st1); XtManageChild(label1); argcnt = 0; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNalignment, XmALIGNMENT_END); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING( "(use up arrow key to recall previous)")); argcnt++; label2 = XmCreateLabel(form, "label2", args, argcnt); XmStringFree(st1); XtManageChild(label2); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, label1); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNmaxLength, SEARCHMAX); argcnt++; findText = XmCreateText(form, "replaceString", args, argcnt); XtAddCallback(findText, XmNfocusCallback, (XtCallbackProc)rFocusCB, window); XtAddCallback(findText, XmNvalueChangedCallback, (XtCallbackProc)rFindTextValueChangedCB, window); XtAddEventHandler(findText, KeyPressMask, False, (XtEventHandler)rFindArrowKeyCB, window); RemapDeleteKey(findText); XtManageChild(findText); XmAddTabGroup(findText); XtVaSetValues(label1, XmNuserData, findText, NULL); /* mnemonic processing */ argcnt = 0; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, findText); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNalignment, XmALIGNMENT_BEGINNING); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Replace With:")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'W'); argcnt++; label = XmCreateLabel(form, "label", args, argcnt); XmStringFree(st1); XtManageChild(label); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, label); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNmaxLength, SEARCHMAX); argcnt++; replaceText = XmCreateText(form, "replaceWithString", args, argcnt); XtAddEventHandler(replaceText, KeyPressMask, False, (XtEventHandler)replaceArrowKeyCB, window); RemapDeleteKey(replaceText); XtManageChild(replaceText); XmAddTabGroup(replaceText); XtVaSetValues(label, XmNuserData, replaceText, NULL); /* mnemonic processing */ argcnt = 0; XtSetArg(args[argcnt], XmNorientation, XmHORIZONTAL); argcnt++; XtSetArg(args[argcnt], XmNpacking, XmPACK_TIGHT); argcnt++; XtSetArg(args[argcnt], XmNmarginHeight, 0); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, replaceText); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 2); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 4); argcnt++; searchTypeBox = XmCreateRowColumn(form, "searchTypeBox", args, argcnt); XtManageChild(searchTypeBox); XmAddTabGroup(searchTypeBox); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Regular Expression")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'R'); argcnt++; window->replaceRegexToggle = XmCreateToggleButton(searchTypeBox, "regExp", args, argcnt); XmStringFree(st1); XtManageChild(window->replaceRegexToggle); XtAddCallback(window->replaceRegexToggle, XmNvalueChangedCallback, (XtCallbackProc) replaceRegExpToggleCB, window); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Case Sensitive")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'C'); argcnt++; window->replaceCaseToggle = XmCreateToggleButton(searchTypeBox, "caseSensitive", args, argcnt); XmStringFree(st1); XtManageChild(window->replaceCaseToggle); XtAddCallback(window->replaceCaseToggle, XmNvalueChangedCallback, (XtCallbackProc) replaceCaseToggleCB, window); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Whole Word")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'h'); argcnt++; window->replaceWordToggle = XmCreateToggleButton(searchTypeBox, "wholeWord", args, argcnt); XmStringFree(st1); XtManageChild(window->replaceWordToggle); argcnt = 0; XtSetArg(args[argcnt], XmNorientation, XmHORIZONTAL); argcnt++; XtSetArg(args[argcnt], XmNpacking, XmPACK_TIGHT); argcnt++; XtSetArg(args[argcnt], XmNmarginHeight, 0); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 0); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, searchTypeBox); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 2); argcnt++; XtSetArg(args[argcnt], XmNradioBehavior, False); argcnt++; searchDirBox = XmCreateRowColumn(form, "searchDirBox", args, argcnt); XtManageChild(searchDirBox); XmAddTabGroup(searchDirBox); argcnt = 0; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Search Backward")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'B'); argcnt++; reverseBtn = XmCreateToggleButton(searchDirBox, "reverse", args, argcnt); XmStringFree(st1); XtManageChild(reverseBtn); argcnt = 0; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Keep Dialog")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'K'); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 0); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, searchTypeBox); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 4); argcnt++; keepBtn = XmCreateToggleButton(form, "keep", args, argcnt); XtAddCallback(keepBtn, XmNvalueChangedCallback, (XtCallbackProc)rKeepCB, window); XmStringFree(st1); XtManageChild(keepBtn); XmAddTabGroup(keepBtn); #ifdef REPLACE_SCOPE argcnt = 0; XtSetArg(args[argcnt], XmNorientation, XmHORIZONTAL); argcnt++; XtSetArg(args[argcnt], XmNpacking, XmPACK_TIGHT); argcnt++; XtSetArg(args[argcnt], XmNmarginHeight, 0); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, searchDirBox); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 2); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNradioBehavior, True); argcnt++; XtSetArg(args[argcnt], XmNradioAlwaysOne, True); argcnt++; scopeForm = XmCreateRowColumn(form, "scope", args, argcnt); XtManageChild(scopeForm); XmAddTabGroup(scopeForm); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("In Window")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'i'); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_NONE); argcnt++; inWinBtn = XmCreateToggleButton(scopeForm, "inWindow", args, argcnt); XtAddCallback(inWinBtn, XmNvalueChangedCallback, (XtCallbackProc)rScopeWinCB, window); XmStringFree(st1); XtManageChild(inWinBtn); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("In Selection")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'S'); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftWidget, inWinBtn); argcnt++; inSelBtn = XmCreateToggleButton(scopeForm, "inSel", args, argcnt); XtAddCallback(inSelBtn, XmNvalueChangedCallback, (XtCallbackProc)rScopeSelCB, window); XmStringFree(st1); XtManageChild(inSelBtn); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("In Multiple Documents")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'M'); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNleftWidget, inSelBtn); argcnt++; inMultiBtn = XmCreateToggleButton(scopeForm, "multiFile", args, argcnt); XtAddCallback(inMultiBtn, XmNvalueChangedCallback, (XtCallbackProc)rScopeMultiCB, window); XmStringFree(st1); XtManageChild(inMultiBtn); #else argcnt = 0; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, searchDirBox); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 6); argcnt++; allForm = XmCreateForm(form, "all", args, argcnt); XtManageChild(allForm); XmAddTabGroup(allForm); argcnt = 0; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 4); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNalignment, XmALIGNMENT_BEGINNING); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Replace all in:")); argcnt++; label3 = XmCreateLabel(allForm, "label3", args, argcnt); XmStringFree(st1); XtManageChild(label3); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Window")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'i'); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftWidget, label3); argcnt++; inWinBtn = XmCreatePushButton(allForm, "inWindow", args, argcnt); XtAddCallback(inWinBtn, XmNactivateCallback, (XtCallbackProc)replaceAllCB, window); XmStringFree(st1); XtManageChild(inWinBtn); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Selection")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'S'); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftWidget, inWinBtn); argcnt++; inSelBtn = XmCreatePushButton(allForm, "inSel", args, argcnt); XtAddCallback(inSelBtn, XmNactivateCallback, (XtCallbackProc)rInSelCB, window); XmStringFree(st1); XtManageChild(inSelBtn); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Multiple Documents...")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'M'); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNleftWidget, inSelBtn); argcnt++; inMultiBtn = XmCreatePushButton(allForm, "multiFile", args, argcnt); XtAddCallback(inMultiBtn, XmNactivateCallback, (XtCallbackProc)replaceMultiFileCB, window); XmStringFree(st1); XtManageChild(inMultiBtn); #endif argcnt = 0; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; #ifdef REPLACE_SCOPE XtSetArg(args[argcnt], XmNtopWidget, scopeForm); argcnt++; #else XtSetArg(args[argcnt], XmNtopWidget, allForm); argcnt++; #endif XtSetArg(args[argcnt], XmNleftOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 6); argcnt++; btnForm = XmCreateForm(form, "buttons", args, argcnt); XtManageChild(btnForm); XmAddTabGroup(btnForm); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Replace")); argcnt++; XtSetArg(args[argcnt], XmNshowAsDefault, (short)1); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_FORM); argcnt++; #ifdef REPLACE_SCOPE XtSetArg(args[argcnt], XmNleftPosition, 0); argcnt++; XtSetArg(args[argcnt], XmNrightPosition, 21); argcnt++; #else XtSetArg(args[argcnt], XmNleftPosition, 0); argcnt++; XtSetArg(args[argcnt], XmNrightPosition, 25); argcnt++; #endif replaceBtn = XmCreatePushButton(btnForm, "replace", args, argcnt); XtAddCallback(replaceBtn, XmNactivateCallback, (XtCallbackProc)replaceCB, window); XmStringFree(st1); XtManageChild(replaceBtn); XtVaGetValues(replaceBtn, XmNshadowThickness, &shadowThickness, NULL); defaultBtnOffset = shadowThickness + 4; argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Find")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'F'); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_POSITION); argcnt++; #ifdef REPLACE_SCOPE XtSetArg(args[argcnt], XmNleftPosition, 21); argcnt++; XtSetArg(args[argcnt], XmNrightPosition, 33); argcnt++; #else XtSetArg(args[argcnt], XmNleftPosition, 25); argcnt++; XtSetArg(args[argcnt], XmNrightPosition, 42); argcnt++; #endif XtSetArg(args[argcnt], XmNtopOffset, defaultBtnOffset); argcnt++; XtSetArg(args[argcnt], XmNbottomOffset, defaultBtnOffset); argcnt++; findBtn = XmCreatePushButton(btnForm, "find", args, argcnt); XtAddCallback(findBtn, XmNactivateCallback, (XtCallbackProc)rFindCB, window); XmStringFree(st1); XtManageChild(findBtn); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Replace & Find")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'n'); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_POSITION); argcnt++; #ifdef REPLACE_SCOPE XtSetArg(args[argcnt], XmNleftPosition, 33); argcnt++; XtSetArg(args[argcnt], XmNrightPosition, 62); argcnt++; #else XtSetArg(args[argcnt], XmNleftPosition, 42); argcnt++; XtSetArg(args[argcnt], XmNrightPosition, 79); argcnt++; #endif XtSetArg(args[argcnt], XmNtopOffset, defaultBtnOffset); argcnt++; XtSetArg(args[argcnt], XmNbottomOffset, defaultBtnOffset); argcnt++; replaceFindBtn = XmCreatePushButton(btnForm, "replacefind", args, argcnt); XtAddCallback(replaceFindBtn, XmNactivateCallback, (XtCallbackProc)replaceFindCB, window); XmStringFree(st1); XtManageChild(replaceFindBtn); #ifdef REPLACE_SCOPE argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Replace All")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'A'); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNleftPosition, 62); argcnt++; XtSetArg(args[argcnt], XmNrightPosition, 85); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, defaultBtnOffset); argcnt++; replaceAllBtn = XmCreatePushButton(btnForm, "all", args, argcnt); XtAddCallback(replaceAllBtn, XmNactivateCallback, (XtCallbackProc)replaceAllScopeCB, window); XmStringFree(st1); XtManageChild(replaceAllBtn); #endif argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Cancel")); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_POSITION); argcnt++; #ifdef REPLACE_SCOPE XtSetArg(args[argcnt], XmNleftPosition, 85); argcnt++; XtSetArg(args[argcnt], XmNrightPosition, 100); argcnt++; #else XtSetArg(args[argcnt], XmNleftPosition, 79); argcnt++; XtSetArg(args[argcnt], XmNrightPosition, 100); argcnt++; #endif XtSetArg(args[argcnt], XmNtopOffset, defaultBtnOffset); argcnt++; XtSetArg(args[argcnt], XmNbottomOffset, defaultBtnOffset); argcnt++; cancelBtn = XmCreatePushButton(btnForm, "cancel", args, argcnt); XmStringFree(st1); XtAddCallback(cancelBtn, XmNactivateCallback, (XtCallbackProc)rCancelCB, window); XtManageChild(cancelBtn); XtVaSetValues(form, XmNcancelButton, cancelBtn, NULL); AddDialogMnemonicHandler(form, FALSE); window->replaceDlog = form; window->replaceText = findText; window->replaceWithText = replaceText; window->replaceRevToggle = reverseBtn; window->replaceKeepBtn = keepBtn; window->replaceBtns = btnForm; window->replaceBtn = replaceBtn; window->replaceAndFindBtn = replaceFindBtn; window->replaceFindBtn = findBtn; window->replaceSearchTypeBox = searchTypeBox; #ifdef REPLACE_SCOPE window->replaceAllBtn = replaceAllBtn; window->replaceScopeWinToggle = inWinBtn; window->replaceScopeSelToggle = inSelBtn; window->replaceScopeMultiToggle = inMultiBtn; #else window->replaceInWinBtn = inWinBtn; window->replaceAllBtn = inMultiBtn; window->replaceInSelBtn = inSelBtn; #endif } void CreateFindDlog(Widget parent, WindowInfo *window) { Arg args[50]; int argcnt, defaultBtnOffset; XmString st1; Widget form, btnForm, searchTypeBox; Widget findText, label1, label2, cancelBtn, findBtn; Widget searchDirBox, reverseBtn, keepBtn; char title[MAXPATHLEN + 11]; Dimension shadowThickness; argcnt = 0; XtSetArg(args[argcnt], XmNautoUnmanage, False); argcnt++; form = CreateFormDialog(parent, "findDialog", args, argcnt); XtVaSetValues(form, XmNshadowThickness, 0, NULL); if (GetPrefKeepSearchDlogs()) { sprintf(title, "Find (in %s)", window->filename); XtVaSetValues(XtParent(form), XmNtitle, title, NULL); } else XtVaSetValues(XtParent(form), XmNtitle, "Find", NULL); argcnt = 0; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNalignment, XmALIGNMENT_BEGINNING); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("String to Find:")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'S'); argcnt++; label1 = XmCreateLabel(form, "label1", args, argcnt); XmStringFree(st1); XtManageChild(label1); argcnt = 0; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNalignment, XmALIGNMENT_END); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING( "(use up arrow key to recall previous)")); argcnt++; label2 = XmCreateLabel(form, "label2", args, argcnt); XmStringFree(st1); XtManageChild(label2); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, label1); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNmaxLength, SEARCHMAX); argcnt++; findText = XmCreateText(form, "searchString", args, argcnt); XtAddCallback(findText, XmNfocusCallback, (XtCallbackProc)fFocusCB, window); XtAddCallback(findText, XmNvalueChangedCallback, (XtCallbackProc)findTextValueChangedCB, window); XtAddEventHandler(findText, KeyPressMask, False, (XtEventHandler)findArrowKeyCB, window); RemapDeleteKey(findText); XtManageChild(findText); XmAddTabGroup(findText); XtVaSetValues(label1, XmNuserData, findText, NULL); /* mnemonic processing */ argcnt = 0; XtSetArg(args[argcnt], XmNorientation, XmHORIZONTAL); argcnt++; XtSetArg(args[argcnt], XmNpacking, XmPACK_TIGHT); argcnt++; XtSetArg(args[argcnt], XmNmarginHeight, 0); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, findText); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 2); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 4); argcnt++; searchTypeBox = XmCreateRowColumn(form, "searchTypeBox", args, argcnt); XtManageChild(searchTypeBox); XmAddTabGroup(searchTypeBox); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Regular Expression")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'R'); argcnt++; window->findRegexToggle = XmCreateToggleButton(searchTypeBox, "regExp", args, argcnt); XmStringFree(st1); XtManageChild(window->findRegexToggle); XtAddCallback(window->findRegexToggle, XmNvalueChangedCallback, (XtCallbackProc) findRegExpToggleCB, window); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Case Sensitive")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'C'); argcnt++; window->findCaseToggle = XmCreateToggleButton(searchTypeBox, "caseSensitive", args, argcnt); XmStringFree(st1); XtManageChild(window->findCaseToggle); XtAddCallback(window->findCaseToggle, XmNvalueChangedCallback, (XtCallbackProc) findCaseToggleCB, window); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Whole Word")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'h'); argcnt++; window->findWordToggle = XmCreateToggleButton(searchTypeBox, "wholeWord", args, argcnt); XmStringFree(st1); XtManageChild(window->findWordToggle); argcnt = 0; XtSetArg(args[argcnt], XmNorientation, XmHORIZONTAL); argcnt++; XtSetArg(args[argcnt], XmNpacking, XmPACK_TIGHT); argcnt++; XtSetArg(args[argcnt], XmNmarginHeight, 0); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 0); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, searchTypeBox); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 2); argcnt++; XtSetArg(args[argcnt], XmNradioBehavior, False); argcnt++; searchDirBox = XmCreateRowColumn(form, "searchDirBox", args, argcnt); XtManageChild(searchDirBox); XmAddTabGroup(searchDirBox); argcnt = 0; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Search Backward")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'B'); argcnt++; reverseBtn = XmCreateToggleButton(searchDirBox, "reverse", args, argcnt); XmStringFree(st1); XtManageChild(reverseBtn); argcnt = 0; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Keep Dialog")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'K'); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 0); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, searchTypeBox); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 4); argcnt++; keepBtn = XmCreateToggleButton(form, "keep", args, argcnt); XtAddCallback(keepBtn, XmNvalueChangedCallback, (XtCallbackProc)fKeepCB, window); XmStringFree(st1); XtManageChild(keepBtn); XmAddTabGroup(keepBtn); argcnt = 0; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, searchDirBox); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 2); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 4); argcnt++; btnForm = XmCreateForm(form, "buttons", args, argcnt); XtManageChild(btnForm); XmAddTabGroup(btnForm); argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Find")); argcnt++; XtSetArg(args[argcnt], XmNshowAsDefault, (short)1); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftPosition, 20); argcnt++; XtSetArg(args[argcnt], XmNbottomOffset, 6); argcnt++; findBtn = XmCreatePushButton(btnForm, "find", args, argcnt); XtAddCallback(findBtn, XmNactivateCallback, (XtCallbackProc)findCB, window); XmStringFree(st1); XtManageChild(findBtn); XtVaGetValues(findBtn, XmNshadowThickness, &shadowThickness, NULL); defaultBtnOffset = shadowThickness + 4; argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Cancel")); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNrightPosition, 80); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, defaultBtnOffset); argcnt++; cancelBtn = XmCreatePushButton(btnForm, "cancel", args, argcnt); XtAddCallback(cancelBtn, XmNactivateCallback, (XtCallbackProc)fCancelCB, window); XmStringFree(st1); XtManageChild(cancelBtn); XtVaSetValues(form, XmNcancelButton, cancelBtn, NULL); AddDialogMnemonicHandler(form, FALSE); window->findDlog = form; window->findText = findText; window->findRevToggle = reverseBtn; window->findKeepBtn = keepBtn; window->findBtns = btnForm; window->findBtn = findBtn; window->findSearchTypeBox = searchTypeBox; } void CreateReplaceMultiFileDlog(WindowInfo *window) { Arg args[50]; int argcnt, defaultBtnOffset; XmString st1; Widget list, label1, form, pathBtn; Widget btnForm, replaceBtn, selectBtn, deselectBtn, cancelBtn; Dimension shadowThickness; argcnt = 0; XtSetArg(args[argcnt], XmNautoUnmanage, False); argcnt++; XtSetArg (args[argcnt], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); argcnt ++; /* Ideally, we should create the multi-file dialog as a child widget of the replace dialog. However, if we do this, the main window can hide the multi-file dialog when raised (I'm not sure why, but it's something that I observed with fvwm). By using the main window as the parent, it is possible that the replace dialog _partially_ covers the multi-file dialog, but this much better than the multi-file dialog being covered completely by the main window */ form = CreateFormDialog(window->shell, "replaceMultiFileDialog", args, argcnt); XtVaSetValues(form, XmNshadowThickness, 0, NULL); XtVaSetValues(XtParent(form), XmNtitle, "Replace All in Multiple Documents", NULL); /* Label at top left. */ argcnt = 0; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_NONE); argcnt++; /* Offset = 6 + (highlightThickness + detailShadowThickness) of the toggle button (see below). Unfortunately, detailShadowThickness is a Motif 2.x property, so we can't measure it. The default is 2 pixels. To make things even more complicated, the SunOS 5.6 / Solaris 2.6 version of Motif 1.2 seems to use a detailShadowThickness of 0 ... So we'll have to live with a slight misalignment on that platform (those Motif libs are known to have many other problems). */ XtSetArg(args[argcnt], XmNtopOffset, 10); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNalignment, XmALIGNMENT_BEGINNING); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Files in which to Replace All:")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'F'); argcnt++; label1 = XmCreateLabel(form, "label1", args, argcnt); XmStringFree(st1); XtManageChild(label1); /* Pathname toggle button at top right (always unset by default) */ argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNset, False); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNalignment, XmALIGNMENT_END); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Show Path Names")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'P'); argcnt++; pathBtn = XmCreateToggleButton(form, "path", args, argcnt); XmStringFree(st1); XtAddCallback(pathBtn, XmNvalueChangedCallback, (XtCallbackProc)rMultiFilePathCB, window); XtManageChild(pathBtn); /* * Buttons at bottom. Place them before the list, such that we can * attach the list to the label and the button box. In that way only * the lists resizes vertically when the dialog is resized; users expect * the list to resize, not the buttons. */ argcnt = 0; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNresizable, (short)0); argcnt++; btnForm = XmCreateForm(form, "buttons", args, argcnt); XtManageChild(btnForm); /* Replace */ argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Replace")); argcnt++; XtSetArg(args[argcnt], XmNshowAsDefault, (short)1); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'R'); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNleftPosition, 0); argcnt++; XtSetArg(args[argcnt], XmNrightPosition, 25); argcnt++; replaceBtn = XmCreatePushButton(btnForm, "replace", args, argcnt); XmStringFree(st1); XtAddCallback(replaceBtn, XmNactivateCallback, (XtCallbackProc)rMultiFileReplaceCB, window); /* * _DON'T_ set the replace button as default (as in other dialogs). * Multi-selection lists have the nasty property of selecting the * current item when is pressed. * In that way, the user could inadvertently select an additional file * (most likely the last one that was deselected). * The user has to activate the replace button explictly (either with * a mouse click or with the shortcut key). * * XtVaSetValues(form, XmNdefaultButton, replaceBtn, NULL); */ XtManageChild(replaceBtn); XtVaGetValues(replaceBtn, XmNshadowThickness, &shadowThickness, NULL); defaultBtnOffset = shadowThickness + 4; /* Select All */ argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Select All")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'S'); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNleftPosition, 25); argcnt++; XtSetArg(args[argcnt], XmNrightPosition, 50); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, defaultBtnOffset); argcnt++; selectBtn = XmCreatePushButton(btnForm, "select", args, argcnt); XmStringFree(st1); XtAddCallback(selectBtn, XmNactivateCallback, (XtCallbackProc)rMultiFileSelectAllCB, window); XtManageChild(selectBtn); /* Deselect All */ argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Deselect All")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'D'); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNleftPosition, 50); argcnt++; XtSetArg(args[argcnt], XmNrightPosition, 75); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, defaultBtnOffset); argcnt++; deselectBtn = XmCreatePushButton(btnForm, "deselect", args, argcnt); XmStringFree(st1); XtAddCallback(deselectBtn, XmNactivateCallback, (XtCallbackProc)rMultiFileDeselectAllCB, window); XtManageChild(deselectBtn); /* Cancel */ argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNhighlightThickness, 2); argcnt++; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Cancel")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'C'); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNleftPosition, 75); argcnt++; XtSetArg(args[argcnt], XmNrightPosition, 100); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, defaultBtnOffset); argcnt++; cancelBtn = XmCreatePushButton(btnForm, "cancel", args, argcnt); XmStringFree(st1); XtAddCallback(cancelBtn, XmNactivateCallback, (XtCallbackProc)rMultiFileCancelCB, window); XtManageChild(cancelBtn); /* The list of files */ argcnt = 0; XtSetArg(args[argcnt], XmNtraversalOn, True); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNbottomWidget, btnForm); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, label1); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 10); argcnt++; XtSetArg(args[argcnt], XmNvisibleItemCount, 10); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNbottomOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 10); argcnt++; /* An alternative is to use the EXTENDED_SELECT, but that one is less suited for keyboard manipulation (moving the selection cursor with the keyboard deselects everything). */ XtSetArg(args[argcnt], XmNselectionPolicy, XmMULTIPLE_SELECT); argcnt++; list = XmCreateScrolledList(form, "list_of_files", args, argcnt); AddMouseWheelSupport(list); XtManageChild(list); /* Traverse: list -> buttons -> path name toggle button */ XmAddTabGroup(list); XmAddTabGroup(btnForm); XmAddTabGroup(pathBtn); XtVaSetValues(label1, XmNuserData, list, NULL); /* mnemonic processing */ /* Cancel/Mnemonic stuff. */ XtVaSetValues(form, XmNcancelButton, cancelBtn, NULL); AddDialogMnemonicHandler(form, FALSE); window->replaceMultiFileDlog = form; window->replaceMultiFileList = list; window->replaceMultiFilePathBtn = pathBtn; /* Install a handler that frees the list of writable windows when the dialog is unmapped. */ XtAddCallback(form, XmNunmapCallback, (XtCallbackProc)freeWritableWindowsCB, window); } /* ** Iterates through the list of writable windows of a window, and removes ** the doomed window if necessary. */ static void checkMultiReplaceListForDoomedW(WindowInfo* window, WindowInfo* doomedWindow) { WindowInfo *w; int i; /* If the window owning the list and the doomed window are one and the same, we just close the multi-file replacement dialog. */ if (window == doomedWindow) { XtUnmanageChild(window->replaceMultiFileDlog); return; } /* Check whether the doomed window is currently listed */ for (i = 0; i < window->nWritableWindows; ++i) { w = window->writableWindows[i]; if (w == doomedWindow) { removeDoomedWindowFromList(window, i); break; } } } /* ** Removes a window that is about to be closed from the list of files in ** which to replace. If the list becomes empty, the dialog is popped down. */ static void removeDoomedWindowFromList(WindowInfo* window, int index) { int entriesToMove; /* If the list would become empty, we remove the dialog */ if (window->nWritableWindows <= 1) { XtUnmanageChild(window->replaceMultiFileDlog); return; } entriesToMove = window->nWritableWindows - index - 1; memmove(&(window->writableWindows[index]), &(window->writableWindows[index+1]), (size_t)(entriesToMove*sizeof(WindowInfo*))); window->nWritableWindows -= 1; XmListDeletePos(window->replaceMultiFileList, index + 1); } /* ** These callbacks fix a Motif 1.1 problem that the default button gets the ** keyboard focus when a dialog is created. We want the first text field ** to get the focus, so we don't set the default button until the text field ** has the focus for sure. I have tried many other ways and this is by far ** the least nasty. */ static void fFocusCB(Widget w, WindowInfo *window, caddr_t *callData) { window = WidgetToWindow(w); SET_ONE_RSRC(window->findDlog, XmNdefaultButton, window->findBtn); } static void rFocusCB(Widget w, WindowInfo *window, caddr_t *callData) { window = WidgetToWindow(w); SET_ONE_RSRC(window->replaceDlog, XmNdefaultButton, window->replaceBtn); } /* when keeping a window up, clue the user what window it's associated with */ static void rKeepCB(Widget w, WindowInfo *window, caddr_t *callData) { char title[MAXPATHLEN + 19]; window = WidgetToWindow(w); if (XmToggleButtonGetState(w)) { sprintf(title, "Replace/Find (in %s)", window->filename); XtVaSetValues(XtParent(window->replaceDlog), XmNtitle, title, NULL); } else XtVaSetValues(XtParent(window->replaceDlog), XmNtitle, "Replace/Find", NULL); } static void fKeepCB(Widget w, WindowInfo *window, caddr_t *callData) { char title[MAXPATHLEN + 11]; window = WidgetToWindow(w); if (XmToggleButtonGetState(w)) { sprintf(title, "Find (in %s)", window->filename); XtVaSetValues(XtParent(window->findDlog), XmNtitle, title, NULL); } else XtVaSetValues(XtParent(window->findDlog), XmNtitle, "Find", NULL); } static void replaceCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { char searchString[SEARCHMAX], replaceString[SEARCHMAX]; int direction, searchType; char *params[5]; window = WidgetToWindow(w); /* Validate and fetch the find and replace strings from the dialog */ if (!getReplaceDlogInfo(window, &direction, searchString, replaceString, &searchType)) return; /* Set the initial focus of the dialog back to the search string */ resetReplaceTabGroup(window); /* Find the text and replace it */ params[0] = searchString; params[1] = replaceString; params[2] = directionArg(direction); params[3] = searchTypeArg(searchType); params[4] = searchWrapArg(GetPrefSearchWraps()); windowNotToClose = window; XtCallActionProc(window->lastFocus, "replace", callData->event, params, 5); windowNotToClose = NULL; /* Pop down the dialog */ if (!XmToggleButtonGetState(window->replaceKeepBtn)) unmanageReplaceDialogs(window); } static void replaceAllCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { char searchString[SEARCHMAX], replaceString[SEARCHMAX]; int direction, searchType; char *params[3]; window = WidgetToWindow(w); /* Validate and fetch the find and replace strings from the dialog */ if (!getReplaceDlogInfo(window, &direction, searchString, replaceString, &searchType)) return; /* Set the initial focus of the dialog back to the search string */ resetReplaceTabGroup(window); /* do replacement */ params[0] = searchString; params[1] = replaceString; params[2] = searchTypeArg(searchType); windowNotToClose = window; XtCallActionProc(window->lastFocus, "replace_all", callData->event, params, 3); windowNotToClose = NULL; /* pop down the dialog */ if (!XmToggleButtonGetState(window->replaceKeepBtn)) unmanageReplaceDialogs(window); } static void replaceMultiFileCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { window = WidgetToWindow(w); DoReplaceMultiFileDlog(window); } /* ** Callback that frees the list of windows the multi-file replace ** dialog is unmapped. **/ static void freeWritableWindowsCB(Widget w, WindowInfo* window, XmAnyCallbackStruct *callData) { window = WidgetToWindow(w); XtFree((XtPointer)window->writableWindows); window->writableWindows = NULL; window->nWritableWindows = 0; } /* ** Comparison function for sorting windows by title for the window menu */ static int compareWindowNames(const void *windowA, const void *windowB) { return strcmp((*((WindowInfo**)windowA))->filename, (*((WindowInfo**)windowB))->filename); } /* ** Count no. of windows */ static int countWindows(void) { int nWindows; const WindowInfo *w; for (w=WindowList, nWindows=0; w!=NULL; w=w->next, ++nWindows); return nWindows; } /* ** Count no. of writable windows, but first update the status of all files. */ static int countWritableWindows(void) { int nWritable, nBefore, nAfter; WindowInfo *w; nBefore = countWindows(); for (w=WindowList, nWritable=0; w!=NULL; w=w->next) { /* We must be very careful! The status check may trigger a pop-up dialog when the file has changed on disk, and the user may destroy arbitrary windows in response. */ CheckForChangesToFile(w); nAfter = countWindows(); if (nAfter != nBefore) { /* The user has destroyed a file; start counting all over again */ nBefore = nAfter; w = WindowList; nWritable = 0; continue; } if (!IS_ANY_LOCKED(w->lockReasons)) ++nWritable; } return nWritable; } /* ** Collects a list of writable windows (sorted by file name). ** The previous list, if any is freed first. **/ static void collectWritableWindows(WindowInfo* window) { int nWritable = countWritableWindows(); int i; WindowInfo *w; WindowInfo **windows; XtFree((char*) window->writableWindows); /* Make a sorted list of writable windows */ windows = (WindowInfo **)XtMalloc(sizeof(WindowInfo *) * nWritable); for (w=WindowList, i=0; w!=NULL; w=w->next) if (!IS_ANY_LOCKED(w->lockReasons)) windows[i++] = w; qsort(windows, nWritable, sizeof(WindowInfo *), compareWindowNames); window->writableWindows = windows; window->nWritableWindows = nWritable; } static void rMultiFileReplaceCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { char searchString[SEARCHMAX], replaceString[SEARCHMAX]; int direction, searchType; char *params[4]; int nSelected, i; WindowInfo *writableWin; Bool replaceFailed, noWritableLeft; window = WidgetToWindow(w); nSelected = 0; for (i=0; inWritableWindows; ++i) if (XmListPosSelected(window->replaceMultiFileList, i+1)) ++nSelected; if (!nSelected) { DialogF(DF_INF, XtParent(window->replaceMultiFileDlog), 1, "No Files", "No files selected!", "OK"); return; /* Give the user another chance */ } /* Set the initial focus of the dialog back to the search string */ resetReplaceTabGroup(window); /* * Protect the user against him/herself; Maybe this is a bit too much? */ if (DialogF(DF_QUES, window->shell, 2, "Multi-File Replacement", "Multi-file replacements are difficult to undo.\n" "Proceed with the replacement ?", "Yes", "Cancel") != 1) { /* pop down the multi-file dialog only */ XtUnmanageChild(window->replaceMultiFileDlog); return; } /* Fetch the find and replace strings from the dialog; they should have been validated already, but since Lesstif may not honor modal dialogs, it is possible that the user modified the strings again, so we should verify them again too. */ if (!getReplaceDlogInfo(window, &direction, searchString, replaceString, &searchType)) return; /* Set the initial focus of the dialog back to the search string */ resetReplaceTabGroup(window); params[0] = searchString; params[1] = replaceString; params[2] = searchTypeArg(searchType); replaceFailed = True; noWritableLeft = True; /* Perform the replacements and mark the selected files (history) */ for (i=0; inWritableWindows; ++i) { writableWin = window->writableWindows[i]; if (XmListPosSelected(window->replaceMultiFileList, i+1)) { /* First check again whether the file is still writable. If the file status has changed or the file was locked in the mean time (possible due to Lesstif modal dialog bug), we just skip the window. */ if (!IS_ANY_LOCKED(writableWin->lockReasons)) { noWritableLeft = False; writableWin->multiFileReplSelected = True; writableWin->multiFileBusy = True; /* Avoid multi-beep/dialog */ writableWin->replaceFailed = False; XtCallActionProc(writableWin->lastFocus, "replace_all", callData->event, params, 3); writableWin->multiFileBusy = False; if (!writableWin->replaceFailed) replaceFailed = False; } } else { writableWin->multiFileReplSelected = False; } } if (!XmToggleButtonGetState(window->replaceKeepBtn)) { /* Pop down both replace dialogs. */ unmanageReplaceDialogs(window); } else { /* pow down only the file selection dialog */ XtUnmanageChild(window->replaceMultiFileDlog); } /* We suppressed multiple beeps/dialogs. If there wasn't any file in which the replacement succeeded, we should still warn the user */ if (replaceFailed) { if (GetPrefSearchDlogs()) { if (noWritableLeft) { DialogF(DF_INF, window->shell, 1, "Read-only Files", "All selected files have become read-only.", "OK"); } else { DialogF(DF_INF, window->shell, 1, "String not found", "String was not found", "OK"); } } else { XBell(TheDisplay, 0); } } } static void rMultiFileCancelCB(Widget w, WindowInfo *window, caddr_t callData) { window = WidgetToWindow(w); /* Set the initial focus of the dialog back to the search string */ resetReplaceTabGroup(window); /* pop down the multi-window replace dialog */ XtUnmanageChild(window->replaceMultiFileDlog); } static void rMultiFileSelectAllCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { int i; char policy; Widget list; window = WidgetToWindow(w); list = window->replaceMultiFileList; /* * If the list is in extended selection mode, we can't select more * than one item (probably because XmListSelectPos is equivalent * to a button1 click; I don't think that there is an equivalent * for CTRL-button1). Therefore, we temporarily put the list into * multiple selection mode. * Note: this is not really necessary if the list is in multiple select * mode all the time (as it currently is). */ XtVaGetValues(list, XmNselectionPolicy, &policy, NULL); XtVaSetValues(list, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL); /* Is there no other way (like "select all") ? */ XmListDeselectAllItems(window->replaceMultiFileList); /* select toggles */ for (i=0; inWritableWindows; ++i) { XmListSelectPos(list, i+1, FALSE); } /* Restore the original policy. */ XtVaSetValues(list, XmNselectionPolicy, policy, NULL); } static void rMultiFileDeselectAllCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { window = WidgetToWindow(w); XmListDeselectAllItems(window->replaceMultiFileList); } static void rMultiFilePathCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { window = WidgetToWindow(w); uploadFileListItems(window, True); /* Replace */ } /* * Uploads the file items to the multi-file replament dialog list. * A boolean argument indicates whether the elements currently in the * list have to be replaced or not. * Depending on the state of the "Show path names" toggle button, either * the file names or the path names are listed. */ static void uploadFileListItems(WindowInfo* window, Bool replace) { XmStringTable names; int nWritable, i, *selected, selectedCount; char buf[MAXPATHLEN+1], policy; Bool usePathNames; WindowInfo *w; Widget list; nWritable = window->nWritableWindows; list = window->replaceMultiFileList; names = (XmStringTable) XtMalloc(nWritable * sizeof(XmString*)); usePathNames = XmToggleButtonGetState(window->replaceMultiFilePathBtn); /* Note: the windows are sorted alphabetically by _file_ name. This order is _not_ changed when we switch to path names. That would be confusing for the user */ for (i = 0; i < nWritable; ++i) { w = window->writableWindows[i]; if (usePathNames && window->filenameSet) { sprintf(buf, "%s%s", w->path, w->filename); } else { sprintf(buf, "%s", w->filename); } names[i] = XmStringCreateSimple(buf); } /* * If the list is in extended selection mode, we can't pre-select * more than one item in (probably because XmListSelectPos is * equivalent to a button1 click; I don't think that there is an * equivalent for CTRL-button1). Therefore, we temporarily put the * list into multiple selection mode. */ XtVaGetValues(list, XmNselectionPolicy, &policy, NULL); XtVaSetValues(list, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL); if (replace) { /* Note: this function is obsolete in Motif 2.x, but it is available for compatibility reasons */ XmListGetSelectedPos(list, &selected, &selectedCount); XmListReplaceItemsPos(list, names, nWritable, 1); /* Maintain the selections */ XmListDeselectAllItems(list); for (i = 0; i < selectedCount; ++i) { XmListSelectPos(list, selected[i], False); } XtFree((char*) selected); } else { Arg args[1]; int nVisible; int firstSelected = 0; /* Remove the old list, if any */ XmListDeleteAllItems(list); /* Initial settings */ XmListAddItems(list, names, nWritable, 1); /* Pre-select the files from the last run. */ selectedCount = 0; for (i = 0; i < nWritable; ++i) { if (window->writableWindows[i]->multiFileReplSelected) { XmListSelectPos(list, i+1, False); ++selectedCount; /* Remember the first selected item */ if (firstSelected == 0) firstSelected = i+1; } } /* If no files are selected, we select them all. Normally this only happens the first time the dialog is used, but it looks "silly" if the dialog pops up with nothing selected. */ if (selectedCount == 0) { for (i = 0; i < nWritable; ++i) { XmListSelectPos(list, i+1, False); } firstSelected = 1; } /* Make sure that the first selected item is visible; otherwise, the user could get the impression that nothing is selected. By visualizing at least the first selected item, the user will more easily be confident that the previous selection is still active. */ XtSetArg(args[0], XmNvisibleItemCount, &nVisible); XtGetValues(list, args, 1); /* Make sure that we don't create blank lines at the bottom by positioning too far. */ if (nWritable <= nVisible) { /* No need to shift the visible position */ firstSelected = 1; } else { int maxFirst = nWritable - nVisible + 1; if (firstSelected > maxFirst) firstSelected = maxFirst; } XmListSetPos(list, firstSelected); } /* Put the list back into its original selection policy. */ XtVaSetValues(list, XmNselectionPolicy, policy, NULL); for (i = 0; i < nWritable; ++i) XmStringFree(names[i]); XtFree((char*) names); } /* ** Unconditionally pops down the replace dialog and the ** replace-in-multiple-files dialog, if it exists. */ static void unmanageReplaceDialogs(const WindowInfo *window) { /* If the replace dialog goes down, the multi-file replace dialog must go down too */ if (window->replaceMultiFileDlog && XtIsManaged(window->replaceMultiFileDlog)) { XtUnmanageChild(window->replaceMultiFileDlog); } if (window->replaceDlog && XtIsManaged(window->replaceDlog)) { XtUnmanageChild(window->replaceDlog); } } static void rInSelCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { char searchString[SEARCHMAX], replaceString[SEARCHMAX]; int direction, searchType; char *params[3]; window = WidgetToWindow(w); /* Validate and fetch the find and replace strings from the dialog */ if (!getReplaceDlogInfo(window, &direction, searchString, replaceString, &searchType)) return; /* Set the initial focus of the dialog back to the search string */ resetReplaceTabGroup(window); /* do replacement */ params[0] = searchString; params[1] = replaceString; params[2] = searchTypeArg(searchType); windowNotToClose = window; XtCallActionProc(window->lastFocus, "replace_in_selection", callData->event, params, 3); windowNotToClose = NULL; /* pop down the dialog */ if (!XmToggleButtonGetState(window->replaceKeepBtn)) unmanageReplaceDialogs(window); } static void rCancelCB(Widget w, WindowInfo *window, caddr_t callData) { window = WidgetToWindow(w); /* Set the initial focus of the dialog back to the search string */ resetReplaceTabGroup(window); /* pop down the dialog */ unmanageReplaceDialogs(window); } static void fCancelCB(Widget w, WindowInfo *window, caddr_t callData) { window = WidgetToWindow(w); /* Set the initial focus of the dialog back to the search string */ resetFindTabGroup(window); /* pop down the dialog */ XtUnmanageChild(window->findDlog); } static void rFindCB(Widget w, WindowInfo *window,XmAnyCallbackStruct *callData) { char searchString[SEARCHMAX], replaceString[SEARCHMAX]; int direction, searchType; char *params[4]; window = WidgetToWindow(w); /* Validate and fetch the find and replace strings from the dialog */ if (!getReplaceDlogInfo(window, &direction, searchString, replaceString, &searchType)) return; /* Set the initial focus of the dialog back to the search string */ resetReplaceTabGroup(window); /* Find the text and mark it */ params[0] = searchString; params[1] = directionArg(direction); params[2] = searchTypeArg(searchType); params[3] = searchWrapArg(GetPrefSearchWraps()); windowNotToClose = window; XtCallActionProc(window->lastFocus, "find", callData->event, params, 4); windowNotToClose = NULL; /* Doctor the search history generated by the action to include the replace string (if any), so the replace string can be used on subsequent replaces, even though no actual replacement was done. */ if (historyIndex(1) != -1 && !strcmp(SearchHistory[historyIndex(1)], searchString)) { XtFree(ReplaceHistory[historyIndex(1)]); ReplaceHistory[historyIndex(1)] = XtNewString(replaceString); } /* Pop down the dialog */ if (!XmToggleButtonGetState(window->replaceKeepBtn)) unmanageReplaceDialogs(window); } static void replaceFindCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { char searchString[SEARCHMAX+1], replaceString[SEARCHMAX+1]; int direction, searchType; char *params[4]; window = WidgetToWindow(w); /* Validate and fetch the find and replace strings from the dialog */ if (!getReplaceDlogInfo(window, &direction, searchString, replaceString, &searchType)) return; /* Set the initial focus of the dialog back to the search string */ resetReplaceTabGroup(window); /* Find the text and replace it */ params[0] = searchString; params[1] = replaceString; params[2] = directionArg(direction); params[3] = searchTypeArg(searchType); windowNotToClose = window; XtCallActionProc(window->lastFocus, "replace_find", callData->event, params, 4); windowNotToClose = NULL; /* Pop down the dialog */ if (!XmToggleButtonGetState(window->replaceKeepBtn)) unmanageReplaceDialogs(window); } static void rSetActionButtons(WindowInfo* window, int replaceBtn, int replaceFindBtn, int replaceAndFindBtn, #ifndef REPLACE_SCOPE int replaceInWinBtn, int replaceInSelBtn, #endif int replaceAllBtn) { XtSetSensitive(window->replaceBtn, replaceBtn); XtSetSensitive(window->replaceFindBtn, replaceFindBtn); XtSetSensitive(window->replaceAndFindBtn, replaceAndFindBtn); #ifndef REPLACE_SCOPE XtSetSensitive(window->replaceInWinBtn, replaceInWinBtn); XtSetSensitive(window->replaceInSelBtn, replaceInSelBtn); #endif XtSetSensitive(window->replaceAllBtn, replaceAllBtn); } void UpdateReplaceActionButtons(WindowInfo* window) { /* Is there any text in the search for field */ int searchText = textFieldNonEmpty(window->replaceText); #ifdef REPLACE_SCOPE switch (window->replaceScope) { case REPL_SCOPE_WIN: /* Enable all buttons, if there is any text in the search field. */ rSetActionButtons(window, searchText, searchText, searchText, searchText); break; case REPL_SCOPE_SEL: /* Only enable Replace All, if a selection exists and text in search field. */ rSetActionButtons(window, False, False, False, searchText && window->wasSelected); break; case REPL_SCOPE_MULTI: /* Only enable Replace All, if text in search field. */ rSetActionButtons(window, False, False, False, searchText); break; } #else rSetActionButtons(window, searchText, searchText, searchText, searchText, searchText && window->wasSelected, searchText && (countWritableWindows() > 1)); #endif } #ifdef REPLACE_SCOPE /* ** The next 3 callback adapt the sensitivity of the replace dialog push ** buttons to the state of the scope radio buttons. */ static void rScopeWinCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { window = WidgetToWindow(w); if (XmToggleButtonGetState(window->replaceScopeWinToggle)) { window->replaceScope = REPL_SCOPE_WIN; UpdateReplaceActionButtons(window); } } static void rScopeSelCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { window = WidgetToWindow(w); if (XmToggleButtonGetState(window->replaceScopeSelToggle)) { window->replaceScope = REPL_SCOPE_SEL; UpdateReplaceActionButtons(window); } } static void rScopeMultiCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { window = WidgetToWindow(w); if (XmToggleButtonGetState(window->replaceScopeMultiToggle)) { window->replaceScope = REPL_SCOPE_MULTI; UpdateReplaceActionButtons(window); } } /* ** This routine dispatches a push on the replace-all button to the appropriate ** callback, depending on the state of the scope radio buttons. */ static void replaceAllScopeCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { window = WidgetToWindow(w); switch(window->replaceScope) { case REPL_SCOPE_WIN: replaceAllCB(w, window, callData); break; case REPL_SCOPE_SEL: rInSelCB(w, window, callData); break; case REPL_SCOPE_MULTI: replaceMultiFileCB(w, window, callData); break; } } #endif static int textFieldNonEmpty(Widget w) { char *str = XmTextGetString(w); int nonEmpty = (str[0] != '\0'); XtFree(str); return(nonEmpty); } static void rFindTextValueChangedCB(Widget w, WindowInfo *window, XKeyEvent *event) { window = WidgetToWindow(w); UpdateReplaceActionButtons(window); } static void rFindArrowKeyCB(Widget w, WindowInfo *window, XKeyEvent *event) { KeySym keysym = XLookupKeysym(event, 0); int index; char *searchStr, *replaceStr; int searchType; window = WidgetToWindow(w); index = window->rHistIndex; /* only process up and down arrow keys */ if (keysym != XK_Up && keysym != XK_Down) return; /* increment or decrement the index depending on which arrow was pressed */ index += (keysym == XK_Up) ? 1 : -1; /* if the index is out of range, beep and return */ if (index != 0 && historyIndex(index) == -1) { XBell(TheDisplay, 0); return; } window = WidgetToWindow(w); /* determine the strings and button settings to use */ if (index == 0) { searchStr = ""; replaceStr = ""; searchType = GetPrefSearch(); } else { searchStr = SearchHistory[historyIndex(index)]; replaceStr = ReplaceHistory[historyIndex(index)]; searchType = SearchTypeHistory[historyIndex(index)]; } /* Set the buttons and fields with the selected search type */ initToggleButtons(searchType, window->replaceRegexToggle, window->replaceCaseToggle, &window->replaceWordToggle, &window->replaceLastLiteralCase, &window->replaceLastRegexCase); XmTextSetString(window->replaceText, searchStr); XmTextSetString(window->replaceWithText, replaceStr); /* Set the state of the Replace, Find ... buttons */ UpdateReplaceActionButtons(window); window->rHistIndex = index; } static void replaceArrowKeyCB(Widget w, WindowInfo *window, XKeyEvent *event) { KeySym keysym = XLookupKeysym(event, 0); int index; window = WidgetToWindow(w); index = window->rHistIndex; /* only process up and down arrow keys */ if (keysym != XK_Up && keysym != XK_Down) return; /* increment or decrement the index depending on which arrow was pressed */ index += (keysym == XK_Up) ? 1 : -1; /* if the index is out of range, beep and return */ if (index != 0 && historyIndex(index) == -1) { XBell(TheDisplay, 0); return; } window = WidgetToWindow(w); /* change only the replace field information */ if (index == 0) XmTextSetString(window->replaceWithText, ""); else XmTextSetString(window->replaceWithText, ReplaceHistory[historyIndex(index)]); window->rHistIndex = index; } static void fUpdateActionButtons(WindowInfo *window) { int buttonState = textFieldNonEmpty(window->findText); XtSetSensitive(window->findBtn, buttonState); } static void findTextValueChangedCB(Widget w, WindowInfo *window, XKeyEvent *event) { window = WidgetToWindow(w); fUpdateActionButtons(window); } static void findArrowKeyCB(Widget w, WindowInfo *window, XKeyEvent *event) { KeySym keysym = XLookupKeysym(event, 0); int index; char *searchStr; int searchType; window = WidgetToWindow(w); index = window->fHistIndex; /* only process up and down arrow keys */ if (keysym != XK_Up && keysym != XK_Down) return; /* increment or decrement the index depending on which arrow was pressed */ index += (keysym == XK_Up) ? 1 : -1; /* if the index is out of range, beep and return */ if (index != 0 && historyIndex(index) == -1) { XBell(TheDisplay, 0); return; } /* determine the strings and button settings to use */ if (index == 0) { searchStr = ""; searchType = GetPrefSearch(); } else { searchStr = SearchHistory[historyIndex(index)]; searchType = SearchTypeHistory[historyIndex(index)]; } /* Set the buttons and fields with the selected search type */ initToggleButtons(searchType, window->findRegexToggle, window->findCaseToggle, &window->findWordToggle, &window->findLastLiteralCase, &window->findLastRegexCase); XmTextSetString(window->findText, searchStr); /* Set the state of the Find ... button */ fUpdateActionButtons(window); window->fHistIndex = index; } static void findCB(Widget w, WindowInfo *window,XmAnyCallbackStruct *callData) { char searchString[SEARCHMAX]; int direction, searchType; char *params[4]; window = WidgetToWindow(w); /* fetch find string, direction and type from the dialog */ if (!getFindDlogInfo(window, &direction, searchString, &searchType)) return; /* Set the initial focus of the dialog back to the search string */ resetFindTabGroup(window); /* find the text and mark it */ params[0] = searchString; params[1] = directionArg(direction); params[2] = searchTypeArg(searchType); params[3] = searchWrapArg(GetPrefSearchWraps()); windowNotToClose = window; XtCallActionProc(window->lastFocus, "find", callData->event, params, 4); windowNotToClose = NULL; /* pop down the dialog */ if (!XmToggleButtonGetState(window->findKeepBtn)) XtUnmanageChild(window->findDlog); } /* ** Fetch and verify (particularly regular expression) search and replace ** strings and search type from the Replace dialog. If the strings are ok, ** save a copy in the search history, copy them in to "searchString", ** "replaceString', which are assumed to be at least SEARCHMAX in length, ** return search type in "searchType", and return TRUE as the function ** value. Otherwise, return FALSE. */ static int getReplaceDlogInfo(WindowInfo *window, int *direction, char *searchString, char *replaceString, int *searchType) { char *replaceText, *replaceWithText; regexp *compiledRE = NULL; char *compileMsg; /* Get the search and replace strings, search type, and direction from the dialog */ replaceText = XmTextGetString(window->replaceText); replaceWithText = XmTextGetString(window->replaceWithText); if(XmToggleButtonGetState(window->replaceRegexToggle)) { int regexDefault; if(XmToggleButtonGetState(window->replaceCaseToggle)) { *searchType = SEARCH_REGEX; regexDefault = REDFLT_STANDARD; } else { *searchType = SEARCH_REGEX_NOCASE; regexDefault = REDFLT_CASE_INSENSITIVE; } /* If the search type is a regular expression, test compile it immediately and present error messages */ compiledRE = CompileRE(replaceText, &compileMsg, regexDefault); if (compiledRE == NULL) { DialogF(DF_WARN, XtParent(window->replaceDlog), 1, "Search String", "Please respecify the search string:\n%s", "OK", compileMsg); XtFree(replaceText); XtFree(replaceWithText); return FALSE; } free((char*)compiledRE); } else { if(XmToggleButtonGetState(window->replaceCaseToggle)) { if(XmToggleButtonGetState(window->replaceWordToggle)) *searchType = SEARCH_CASE_SENSE_WORD; else *searchType = SEARCH_CASE_SENSE; } else { if(XmToggleButtonGetState(window->replaceWordToggle)) *searchType = SEARCH_LITERAL_WORD; else *searchType = SEARCH_LITERAL; } } *direction = XmToggleButtonGetState(window->replaceRevToggle) ? SEARCH_BACKWARD : SEARCH_FORWARD; /* Return strings */ if (strlen(replaceText) >= SEARCHMAX) { DialogF(DF_WARN, XtParent(window->replaceDlog), 1, "String too long", "Search string too long.", "OK"); XtFree(replaceText); XtFree(replaceWithText); return FALSE; } if (strlen(replaceWithText) >= SEARCHMAX) { DialogF(DF_WARN, XtParent(window->replaceDlog), 1, "String too long", "Replace string too long.", "OK"); XtFree(replaceText); XtFree(replaceWithText); return FALSE; } strcpy(searchString, replaceText); strcpy(replaceString, replaceWithText); XtFree(replaceText); XtFree(replaceWithText); return TRUE; } /* ** Fetch and verify (particularly regular expression) search string, ** direction, and search type from the Find dialog. If the search string ** is ok, save a copy in the search history, copy it to "searchString", ** which is assumed to be at least SEARCHMAX in length, return search type ** in "searchType", and return TRUE as the function value. Otherwise, ** return FALSE. */ static int getFindDlogInfo(WindowInfo *window, int *direction, char *searchString, int *searchType) { char *findText; regexp *compiledRE = NULL; char *compileMsg; /* Get the search string, search type, and direction from the dialog */ findText = XmTextGetString(window->findText); if(XmToggleButtonGetState(window->findRegexToggle)) { int regexDefault; if(XmToggleButtonGetState(window->findCaseToggle)) { *searchType = SEARCH_REGEX; regexDefault = REDFLT_STANDARD; } else { *searchType = SEARCH_REGEX_NOCASE; regexDefault = REDFLT_CASE_INSENSITIVE; } /* If the search type is a regular expression, test compile it immediately and present error messages */ compiledRE = CompileRE(findText, &compileMsg, regexDefault); if (compiledRE == NULL) { DialogF(DF_WARN, XtParent(window->findDlog), 1, "Regex Error", "Please respecify the search string:\n%s", "OK", compileMsg); return FALSE; } free((char *)compiledRE); } else { if(XmToggleButtonGetState(window->findCaseToggle)) { if(XmToggleButtonGetState(window->findWordToggle)) *searchType = SEARCH_CASE_SENSE_WORD; else *searchType = SEARCH_CASE_SENSE; } else { if(XmToggleButtonGetState(window->findWordToggle)) *searchType = SEARCH_LITERAL_WORD; else *searchType = SEARCH_LITERAL; } } *direction = XmToggleButtonGetState(window->findRevToggle) ? SEARCH_BACKWARD : SEARCH_FORWARD; if (isRegexType(*searchType)) { } /* Return the search string */ if (strlen(findText) >= SEARCHMAX) { DialogF(DF_WARN, XtParent(window->findDlog), 1, "String too long", "Search string too long.", "OK"); XtFree(findText); return FALSE; } strcpy(searchString, findText); XtFree(findText); return TRUE; } int SearchAndSelectSame(WindowInfo *window, int direction, int searchWrap) { if (NHist < 1) { XBell(TheDisplay, 0); return FALSE; } return SearchAndSelect(window, direction, SearchHistory[historyIndex(1)], SearchTypeHistory[historyIndex(1)], searchWrap); } /* ** Search for "searchString" in "window", and select the matching text in ** the window when found (or beep or put up a dialog if not found). Also ** adds the search string to the global search history. */ int SearchAndSelect(WindowInfo *window, int direction, const char *searchString, int searchType, int searchWrap) { int startPos, endPos; int beginPos, cursorPos, selStart, selEnd; int movedFwd = 0; /* Save a copy of searchString in the search history */ saveSearchHistory(searchString, NULL, searchType, FALSE); /* set the position to start the search so we don't find the same string that was found on the last search */ if (searchMatchesSelection(window, searchString, searchType, &selStart, &selEnd, NULL, NULL)) { /* selection matches search string, start before or after sel. */ if (direction == SEARCH_BACKWARD) { beginPos = selStart - 1; } else { beginPos = selStart + 1; movedFwd = 1; } } else { selStart = -1; selEnd = -1; /* no selection, or no match, search relative cursor */ cursorPos = TextGetCursorPos(window->lastFocus); if (direction == SEARCH_BACKWARD) { /* use the insert position - 1 for backward searches */ beginPos = cursorPos-1; } else { /* use the insert position for forward searches */ beginPos = cursorPos; } } /* when the i-search bar is active and search is repeated there (Return), the action "find" is called (not: "find_incremental"). "find" calls this function SearchAndSelect. To keep track of the iSearchLastBeginPos correctly in the repeated i-search case it is necessary to call the following function here, otherwise there are no beeps on the repeated incremental search wraps. */ iSearchRecordLastBeginPos(window, direction, beginPos); /* do the search. SearchWindow does appropriate dialogs and beeps */ if (!SearchWindow(window, direction, searchString, searchType, searchWrap, beginPos, &startPos, &endPos, NULL, NULL)) return FALSE; /* if the search matched an empty string (possible with regular exps) beginning at the start of the search, go to the next occurrence, otherwise repeated finds will get "stuck" at zero-length matches */ if (direction==SEARCH_FORWARD && beginPos==startPos && beginPos==endPos) { if (!movedFwd && !SearchWindow(window, direction, searchString, searchType, searchWrap, beginPos+1, &startPos, &endPos, NULL, NULL)) return FALSE; } /* if matched text is already selected, just beep */ if (selStart==startPos && selEnd==endPos) { XBell(TheDisplay, 0); return FALSE; } /* select the text found string */ BufSelect(window->buffer, startPos, endPos); MakeSelectionVisible(window, window->lastFocus); TextSetCursorPos(window->lastFocus, endPos); return TRUE; } void SearchForSelected(WindowInfo *window, int direction, int searchType, int searchWrap, Time time) { SearchSelectedCallData *callData = XtNew(SearchSelectedCallData); callData->direction = direction; callData->searchType = searchType; callData->searchWrap = searchWrap; XtGetSelectionValue(window->textArea, XA_PRIMARY, XA_STRING, (XtSelectionCallbackProc)selectedSearchCB, callData, time); } static void selectedSearchCB(Widget w, XtPointer callData, Atom *selection, Atom *type, char *value, int *length, int *format) { WindowInfo *window = WidgetToWindow(w); SearchSelectedCallData *callDataItems = (SearchSelectedCallData *)callData; int searchType; char searchString[SEARCHMAX+1]; window = WidgetToWindow(w); /* skip if we can't get the selection data or it's too long */ if (*type == XT_CONVERT_FAIL || value == NULL) { if (GetPrefSearchDlogs()) DialogF(DF_WARN, window->shell, 1, "Wrong Selection", "Selection not appropriate for searching", "OK"); else XBell(TheDisplay, 0); XtFree(callData); return; } if (*length > SEARCHMAX) { if (GetPrefSearchDlogs()) DialogF(DF_WARN, window->shell, 1, "Selection too long", "Selection too long", "OK"); else XBell(TheDisplay, 0); XtFree(value); XtFree(callData); return; } if (*length == 0) { XBell(TheDisplay, 0); XtFree(value); XtFree(callData); return; } /* should be of type text??? */ if (*format != 8) { fprintf(stderr, "NEdit: can't handle non 8-bit text\n"); XBell(TheDisplay, 0); XtFree(value); XtFree(callData); return; } /* make the selection the current search string */ strncpy(searchString, value, *length); searchString[*length] = '\0'; XtFree(value); /* Use the passed method for searching, unless it is regex, since this kind of search is by definition a literal search */ searchType = callDataItems->searchType; if (searchType == SEARCH_REGEX ) searchType = SEARCH_CASE_SENSE; else if (searchType == SEARCH_REGEX_NOCASE) searchType = SEARCH_LITERAL; /* search for it in the window */ SearchAndSelect(window, callDataItems->direction, searchString, searchType, callDataItems->searchWrap); XtFree(callData); } /* ** Pop up and clear the incremental search line and prepare to search. */ void BeginISearch(WindowInfo *window, int direction) { window->iSearchStartPos = -1; XmTextSetString(window->iSearchText, ""); XmToggleButtonSetState(window->iSearchRevToggle, direction == SEARCH_BACKWARD, FALSE); /* Note: in contrast to the replace and find dialogs, the regex and case toggles are not reset to their default state when the incremental search bar is redisplayed. I'm not sure whether this is the best choice. If not, an initToggleButtons() call should be inserted here. But in that case, it might be appropriate to have different default search modes for i-search and replace/find. */ TempShowISearch(window, TRUE); XmProcessTraversal(window->iSearchText, XmTRAVERSE_CURRENT); } /* ** Incremental searching is anchored at the position where the cursor ** was when the user began typing the search string. Call this routine ** to forget about this original anchor, and if the search bar is not ** permanently up, pop it down. */ void EndISearch(WindowInfo *window) { /* Note: Please maintain this such that it can be freely peppered in mainline code, without callers having to worry about performance or visual glitches. */ /* Forget the starting position used for the current run of searches */ window->iSearchStartPos = -1; /* Mark the end of incremental search history overwriting */ saveSearchHistory("", NULL, 0, FALSE); /* Pop down the search line (if it's not pegged up in Preferences) */ TempShowISearch(window, FALSE); } /* ** Reset window->iSearchLastBeginPos to the resulting initial ** search begin position for incremental searches. */ static void iSearchRecordLastBeginPos(WindowInfo *window, int direction, int initPos) { window->iSearchLastBeginPos = initPos; if (direction == SEARCH_BACKWARD) window->iSearchLastBeginPos--; } /* ** Search for "searchString" in "window", and select the matching text in ** the window when found (or beep or put up a dialog if not found). If ** "continued" is TRUE and a prior incremental search starting position is ** recorded, search from that original position, otherwise, search from the ** current cursor position. */ int SearchAndSelectIncremental(WindowInfo *window, int direction, const char *searchString, int searchType, int searchWrap, int continued) { int beginPos, startPos, endPos; /* If there's a search in progress, start the search from the original starting position, otherwise search from the cursor position. */ if (!continued || window->iSearchStartPos == -1) { window->iSearchStartPos = TextGetCursorPos(window->lastFocus); iSearchRecordLastBeginPos(window, direction, window->iSearchStartPos); } beginPos = window->iSearchStartPos; /* If the search string is empty, beep eventually if text wrapped back to the initial position, re-init iSearchLastBeginPos, clear the selection, set the cursor back to what would be the beginning of the search, and return. */ if(searchString[0] == 0) { int beepBeginPos = (direction == SEARCH_BACKWARD) ? beginPos-1:beginPos; iSearchTryBeepOnWrap(window, direction, beepBeginPos, beepBeginPos); iSearchRecordLastBeginPos(window, direction, window->iSearchStartPos); BufUnselect(window->buffer); TextSetCursorPos(window->lastFocus, beginPos); return TRUE; } /* Save the string in the search history, unless we're cycling thru the search history itself, which can be detected by matching the search string with the search string of the current history index. */ if(!(window->iSearchHistIndex > 1 && !strcmp(searchString, SearchHistory[historyIndex(window->iSearchHistIndex)]))) { saveSearchHistory(searchString, NULL, searchType, TRUE); /* Reset the incremental search history pointer to the beginning */ window->iSearchHistIndex = 1; } /* begin at insert position - 1 for backward searches */ if (direction == SEARCH_BACKWARD) beginPos--; /* do the search. SearchWindow does appropriate dialogs and beeps */ if (!SearchWindow(window, direction, searchString, searchType, searchWrap, beginPos, &startPos, &endPos, NULL, NULL)) return FALSE; window->iSearchLastBeginPos = startPos; /* if the search matched an empty string (possible with regular exps) beginning at the start of the search, go to the next occurrence, otherwise repeated finds will get "stuck" at zero-length matches */ if (direction==SEARCH_FORWARD && beginPos==startPos && beginPos==endPos) if (!SearchWindow(window, direction, searchString, searchType, searchWrap, beginPos+1, &startPos, &endPos, NULL, NULL)) return FALSE; window->iSearchLastBeginPos = startPos; /* select the text found string */ BufSelect(window->buffer, startPos, endPos); MakeSelectionVisible(window, window->lastFocus); TextSetCursorPos(window->lastFocus, endPos); return TRUE; } /* ** Attach callbacks to the incremental search bar widgets. This also fudges ** up the translations on the text widget so Shift+Return will call the ** activate callback (along with Return and Ctrl+Return). It does this ** because incremental search uses the activate callback from the text ** widget to detect when the user has pressed Return to search for the next ** occurrence of the search string, and Shift+Return, which is the natural ** command for a reverse search does not naturally trigger this callback. */ void SetISearchTextCallbacks(WindowInfo *window) { static XtTranslations tableText = NULL; static char *translationsText = "ShiftReturn: activate()\n"; static XtTranslations tableClear = NULL; static char *translationsClear = ":Arm()\n: isearch_clear_and_paste() Disarm()\n"; static XtActionsRec actions[] = { { "isearch_clear_and_paste", iSearchTextClearAndPasteAP } }; if (tableText == NULL) tableText = XtParseTranslationTable(translationsText); XtOverrideTranslations(window->iSearchText, tableText); if (tableClear == NULL) { /* make sure actions are loaded */ XtAppAddActions(XtWidgetToApplicationContext(window->iSearchText), actions, XtNumber(actions)); tableClear = XtParseTranslationTable(translationsClear); } XtOverrideTranslations(window->iSearchClearButton, tableClear); XtAddCallback(window->iSearchText, XmNactivateCallback, (XtCallbackProc)iSearchTextActivateCB, window); XtAddCallback(window->iSearchText, XmNvalueChangedCallback, (XtCallbackProc)iSearchTextValueChangedCB, window); XtAddEventHandler(window->iSearchText, KeyPressMask, False, (XtEventHandler)iSearchTextKeyEH, window); /* Attach callbacks to deal with the optional sticky case sensitivity behaviour. Do this before installing the search callbacks to make sure that the proper search parameters are taken into account. */ XtAddCallback(window->iSearchCaseToggle, XmNvalueChangedCallback, (XtCallbackProc)iSearchCaseToggleCB, window); XtAddCallback(window->iSearchRegexToggle, XmNvalueChangedCallback, (XtCallbackProc)iSearchRegExpToggleCB, window); /* When search parameters (direction or search type), redo the search */ XtAddCallback(window->iSearchCaseToggle, XmNvalueChangedCallback, (XtCallbackProc)iSearchTextValueChangedCB, window); XtAddCallback(window->iSearchRegexToggle, XmNvalueChangedCallback, (XtCallbackProc)iSearchTextValueChangedCB, window); XtAddCallback(window->iSearchRevToggle, XmNvalueChangedCallback, (XtCallbackProc)iSearchTextValueChangedCB, window); /* find button: just like pressing return */ XtAddCallback(window->iSearchFindButton, XmNactivateCallback, (XtCallbackProc)iSearchTextActivateCB, window); /* clear button: empty the search text widget */ XtAddCallback(window->iSearchClearButton, XmNactivateCallback, (XtCallbackProc)iSearchTextClearCB, window); } /* ** Remove callbacks before resetting the incremental search text to avoid any ** cursor movement and/or clearing of selections. */ static void iSearchTextSetString(Widget w, WindowInfo *window, char *str) { /* remove callbacks which would be activated by emptying the text */ XtRemoveAllCallbacks(window->iSearchText, XmNvalueChangedCallback); XtRemoveAllCallbacks(window->iSearchText, XmNactivateCallback); /* empty the text */ XmTextSetString(window->iSearchText, str ? str : ""); /* put back the callbacks */ XtAddCallback(window->iSearchText, XmNactivateCallback, (XtCallbackProc)iSearchTextActivateCB, window); XtAddCallback(window->iSearchText, XmNvalueChangedCallback, (XtCallbackProc)iSearchTextValueChangedCB, window); } /* ** Action routine for Mouse Button 2 on the iSearchClearButton: resets the ** string then calls the activate callback for the text directly. */ static void iSearchTextClearAndPasteAP(Widget w, XEvent *event, String *args, Cardinal *nArg) { WindowInfo *window; char *selText; XmAnyCallbackStruct cbdata; memset(&cbdata, 0, sizeof (cbdata)); cbdata.event = event; window = WidgetToWindow(w); selText = GetAnySelection(window); iSearchTextSetString(w, window, selText); if (selText) { XmTextSetInsertionPosition(window->iSearchText, strlen(selText)); XtFree(selText); } iSearchTextActivateCB(w, window, &cbdata); } /* ** User pressed the clear incremental search bar button. Remove callbacks ** before resetting the text to avoid any cursor movement and/or clearing ** of selections. */ static void iSearchTextClearCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { window = WidgetToWindow(w); iSearchTextSetString(w, window, NULL); } /* ** User pressed return in the incremental search bar. Do a new search with ** the search string displayed. The direction of the search is toggled if ** the Ctrl key or the Shift key is pressed when the text field is activated. */ static void iSearchTextActivateCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { char *params[4]; char *searchString; int searchType, direction; window = WidgetToWindow(w); /* Fetch the string, search type and direction from the incremental search bar widgets at the top of the window */ searchString = XmTextGetString(window->iSearchText); if(XmToggleButtonGetState(window->iSearchCaseToggle)) { if(XmToggleButtonGetState(window->iSearchRegexToggle)) searchType = SEARCH_REGEX; else searchType = SEARCH_CASE_SENSE; } else { if(XmToggleButtonGetState(window->iSearchRegexToggle)) searchType = SEARCH_REGEX_NOCASE; else searchType = SEARCH_LITERAL; } direction = XmToggleButtonGetState(window->iSearchRevToggle) ? SEARCH_BACKWARD : SEARCH_FORWARD; /* Reverse the search direction if the Ctrl or Shift key was pressed */ if (callData->event->xbutton.state & (ShiftMask | ControlMask)) direction = direction == SEARCH_FORWARD ? SEARCH_BACKWARD : SEARCH_FORWARD; /* find the text and mark it */ params[0] = searchString; params[1] = directionArg(direction); params[2] = searchTypeArg(searchType); params[3] = searchWrapArg(GetPrefSearchWraps()); XtCallActionProc(window->lastFocus, "find", callData->event, params, 4); XtFree(searchString); } /* ** Called when user types in the incremental search line. Redoes the ** search for the new search string. */ static void iSearchTextValueChangedCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { char *params[5]; char *searchString; int searchType, direction, nParams; window = WidgetToWindow(w); /* Fetch the string, search type and direction from the incremental search bar widgets at the top of the window */ searchString = XmTextGetString(window->iSearchText); if(XmToggleButtonGetState(window->iSearchCaseToggle)) { if(XmToggleButtonGetState(window->iSearchRegexToggle)) searchType = SEARCH_REGEX; else searchType = SEARCH_CASE_SENSE; } else { if(XmToggleButtonGetState(window->iSearchRegexToggle)) searchType = SEARCH_REGEX_NOCASE; else searchType = SEARCH_LITERAL; } direction = XmToggleButtonGetState(window->iSearchRevToggle) ? SEARCH_BACKWARD : SEARCH_FORWARD; /* If the search type is a regular expression, test compile it. If it fails, silently skip it. (This allows users to compose the expression in peace when they have unfinished syntax, but still get beeps when correct syntax doesn't match) */ if (isRegexType(searchType)) { regexp *compiledRE = NULL; char *compileMsg; compiledRE = CompileRE(searchString, &compileMsg, defaultRegexFlags(searchType)); if (compiledRE == NULL) { XtFree(searchString); return; } free((char *)compiledRE); } /* Call the incremental search action proc to do the searching and selecting (this allows it to be recorded for learn/replay). If there's an incremental search already in progress, mark the operation as "continued" so the search routine knows to re-start the search from the original starting position */ nParams = 0; params[nParams++] = searchString; params[nParams++] = directionArg(direction); params[nParams++] = searchTypeArg(searchType); params[nParams++] = searchWrapArg(GetPrefSearchWraps()); if (window->iSearchStartPos != -1) params[nParams++] = "continued"; XtCallActionProc(window->lastFocus, "find_incremental", callData->event, params, nParams); XtFree(searchString); } /* ** Process arrow keys for history recall, and escape key for leaving ** incremental search bar. */ static void iSearchTextKeyEH(Widget w, WindowInfo *window, XKeyEvent *event, Boolean *continueDispatch) { KeySym keysym = XLookupKeysym(event, 0); int index; char *searchStr; int searchType; /* only process up and down arrow keys */ if (keysym != XK_Up && keysym != XK_Down && keysym != XK_Escape) { *continueDispatch = TRUE; return; } window = WidgetToWindow(w); index = window->iSearchHistIndex; *continueDispatch = FALSE; /* allow escape key to cancel search */ if (keysym == XK_Escape) { XmProcessTraversal(window->lastFocus, XmTRAVERSE_CURRENT); EndISearch(window); return; } /* increment or decrement the index depending on which arrow was pressed */ index += (keysym == XK_Up) ? 1 : -1; /* if the index is out of range, beep and return */ if (index != 0 && historyIndex(index) == -1) { XBell(TheDisplay, 0); return; } /* determine the strings and button settings to use */ if (index == 0) { searchStr = ""; searchType = GetPrefSearch(); } else { searchStr = SearchHistory[historyIndex(index)]; searchType = SearchTypeHistory[historyIndex(index)]; } /* Set the info used in the value changed callback before calling XmTextSetString(). */ window->iSearchHistIndex = index; initToggleButtons(searchType, window->iSearchRegexToggle, window->iSearchCaseToggle, NULL, &window->iSearchLastLiteralCase, &window->iSearchLastRegexCase); /* Beware the value changed callback is processed as part of this call */ XmTextSetString(window->iSearchText, searchStr); XmTextSetInsertionPosition(window->iSearchText, XmTextGetLastPosition(window->iSearchText)); } /* ** Check the character before the insertion cursor of textW and flash ** matching parenthesis, brackets, or braces, by temporarily highlighting ** the matching character (a timer procedure is scheduled for removing the ** highlights) */ void FlashMatching(WindowInfo *window, Widget textW) { char c; void *style; int pos, matchIndex; int startPos, endPos, searchPos, matchPos; int constrain; /* if a marker is already drawn, erase it and cancel the timeout */ if (window->flashTimeoutID != 0) { eraseFlash(window); XtRemoveTimeOut(window->flashTimeoutID); window->flashTimeoutID = 0; } /* no flashing required */ if (window->showMatchingStyle == NO_FLASH) { return; } /* don't flash matching characters if there's a selection */ if (window->buffer->primary.selected) return; /* get the character to match and the position to start from */ pos = TextGetCursorPos(textW) - 1; if (pos < 0) return; c = BufGetCharacter(window->buffer, pos); style = GetHighlightInfo(window, pos); /* is the character one we want to flash? */ for (matchIndex = 0; matchIndexnPanes == 0) && (window->showMatchingStyle == FLASH_DELIMIT)); if (MatchingChars[matchIndex].direction == SEARCH_BACKWARD) { startPos = constrain ? TextFirstVisiblePos(textW) : 0; endPos = pos; searchPos = endPos; } else { startPos = pos; endPos = constrain ? TextLastVisiblePos(textW) : window->buffer->length; searchPos = startPos; } /* do the search */ if (!findMatchingChar(window, c, style, searchPos, startPos, endPos, &matchPos)) return; if (window->showMatchingStyle == FLASH_DELIMIT) { /* Highlight either the matching character ... */ BufHighlight(window->buffer, matchPos, matchPos+1); } else { /* ... or the whole range. */ if (MatchingChars[matchIndex].direction == SEARCH_BACKWARD) { BufHighlight(window->buffer, matchPos, pos+1); } else { BufHighlight(window->buffer, matchPos+1, pos); } } /* Set up a timer to erase the box after 1.5 seconds */ window->flashTimeoutID = XtAppAddTimeOut( XtWidgetToApplicationContext(window->shell), 1500, flashTimeoutProc, window); window->flashPos = matchPos; } void SelectToMatchingCharacter(WindowInfo *window) { int selStart, selEnd; int startPos, endPos, matchPos; textBuffer *buf = window->buffer; /* get the character to match and its position from the selection, or the character before the insert point if nothing is selected. Give up if too many characters are selected */ if (!GetSimpleSelection(buf, &selStart, &selEnd)) { selEnd = TextGetCursorPos(window->lastFocus); if (window->overstrike) selEnd += 1; selStart = selEnd - 1; if (selStart < 0) { XBell(TheDisplay, 0); return; } } if ((selEnd - selStart) != 1) { XBell(TheDisplay, 0); return; } /* Search for it in the buffer */ if (!findMatchingChar(window, BufGetCharacter(buf, selStart), GetHighlightInfo(window, selStart), selStart, 0, buf->length, &matchPos)) { XBell(TheDisplay, 0); return; } startPos = (matchPos > selStart) ? selStart : matchPos; endPos = (matchPos > selStart) ? matchPos : selStart; /* temporarily shut off autoShowInsertPos before setting the cursor position so MakeSelectionVisible gets a chance to place the cursor string at a pleasing position on the screen (otherwise, the cursor would be automatically scrolled on screen and MakeSelectionVisible would do nothing) */ XtVaSetValues(window->lastFocus, textNautoShowInsertPos, False, NULL); /* select the text between the matching characters */ BufSelect(buf, startPos, endPos+1); MakeSelectionVisible(window, window->lastFocus); XtVaSetValues(window->lastFocus, textNautoShowInsertPos, True, NULL); } void GotoMatchingCharacter(WindowInfo *window) { int selStart, selEnd; int matchPos; textBuffer *buf = window->buffer; /* get the character to match and its position from the selection, or the character before the insert point if nothing is selected. Give up if too many characters are selected */ if (!GetSimpleSelection(buf, &selStart, &selEnd)) { selEnd = TextGetCursorPos(window->lastFocus); if (window->overstrike) selEnd += 1; selStart = selEnd - 1; if (selStart < 0) { XBell(TheDisplay, 0); return; } } if ((selEnd - selStart) != 1) { XBell(TheDisplay, 0); return; } /* Search for it in the buffer */ if (!findMatchingChar(window, BufGetCharacter(buf, selStart), GetHighlightInfo(window, selStart), selStart, 0, buf->length, &matchPos)) { XBell(TheDisplay, 0); return; } /* temporarily shut off autoShowInsertPos before setting the cursor position so MakeSelectionVisible gets a chance to place the cursor string at a pleasing position on the screen (otherwise, the cursor would be automatically scrolled on screen and MakeSelectionVisible would do nothing) */ XtVaSetValues(window->lastFocus, textNautoShowInsertPos, False, NULL); TextSetCursorPos(window->lastFocus, matchPos+1); MakeSelectionVisible(window, window->lastFocus); XtVaSetValues(window->lastFocus, textNautoShowInsertPos, True, NULL); } static int findMatchingChar(WindowInfo *window, char toMatch, void* styleToMatch, int charPos, int startLimit, int endLimit, int *matchPos) { int nestDepth, matchIndex, direction, beginPos, pos; char matchChar, c; void *style = NULL; textBuffer *buf = window->buffer; int matchSyntaxBased = window->matchSyntaxBased; /* If we don't match syntax based, fake a matching style. */ if (!matchSyntaxBased) style = styleToMatch; /* Look up the matching character and match direction */ for (matchIndex = 0; matchIndex=startLimit; pos--) { c=BufGetCharacter(buf, pos); if (c == matchChar) { if (matchSyntaxBased) style = GetHighlightInfo(window, pos); if (style == styleToMatch) { nestDepth--; if (nestDepth == 0) { *matchPos = pos; return TRUE; } } } else if (c == toMatch) { if (matchSyntaxBased) style = GetHighlightInfo(window, pos); if (style == styleToMatch) nestDepth++; } } } return FALSE; } /* ** Xt timer procedure for erasing the matching parenthesis marker. */ static void flashTimeoutProc(XtPointer clientData, XtIntervalId *id) { eraseFlash((WindowInfo *)clientData); ((WindowInfo *)clientData)->flashTimeoutID = 0; } /* ** Erase the marker drawn on a matching parenthesis bracket or brace ** character. */ static void eraseFlash(WindowInfo *window) { BufUnhighlight(window->buffer); } /* ** Search and replace using previously entered search strings (from dialog ** or selection). */ int ReplaceSame(WindowInfo *window, int direction, int searchWrap) { if (NHist < 1) { XBell(TheDisplay, 0); return FALSE; } return SearchAndReplace(window, direction, SearchHistory[historyIndex(1)], ReplaceHistory[historyIndex(1)], SearchTypeHistory[historyIndex(1)], searchWrap); } /* ** Search and replace using previously entered search strings (from dialog ** or selection). */ int ReplaceFindSame(WindowInfo *window, int direction, int searchWrap) { if (NHist < 1) { XBell(TheDisplay, 0); return FALSE; } return ReplaceAndSearch(window, direction, SearchHistory[historyIndex(1)], ReplaceHistory[historyIndex(1)], SearchTypeHistory[historyIndex(1)], searchWrap); } /* ** Replace selection with "replaceString" and search for string "searchString" in window "window", ** using algorithm "searchType" and direction "direction" */ int ReplaceAndSearch(WindowInfo *window, int direction, const char *searchString, const char *replaceString, int searchType, int searchWrap) { int startPos = 0, endPos = 0, replaceLen = 0; int searchExtentBW, searchExtentFW; int replaced; /* Save a copy of search and replace strings in the search history */ saveSearchHistory(searchString, replaceString, searchType, FALSE); replaced = 0; /* Replace the selected text only if it matches the search string */ if (searchMatchesSelection(window, searchString, searchType, &startPos, &endPos, &searchExtentBW, &searchExtentFW)) { /* replace the text */ if (isRegexType(searchType)) { char replaceResult[SEARCHMAX+1], *foundString; foundString = BufGetRange(window->buffer, searchExtentBW, searchExtentFW+1); replaceUsingRE(searchString, replaceString, foundString, startPos-searchExtentBW, replaceResult, SEARCHMAX, startPos == 0 ? '\0' : BufGetCharacter(window->buffer, startPos-1), GetWindowDelimiters(window), defaultRegexFlags(searchType)); XtFree(foundString); BufReplace(window->buffer, startPos, endPos, replaceResult); replaceLen = strlen(replaceResult); } else { BufReplace(window->buffer, startPos, endPos, replaceString); replaceLen = strlen(replaceString); } /* Position the cursor so the next search will work correctly based */ /* on the direction of the search */ TextSetCursorPos(window->lastFocus, startPos + ((direction == SEARCH_FORWARD) ? replaceLen : 0)); replaced = 1; } /* do the search; beeps/dialogs are taken care of */ SearchAndSelect(window, direction, searchString, searchType, searchWrap); return replaced; } /* ** Search for string "searchString" in window "window", using algorithm ** "searchType" and direction "direction", and replace it with "replaceString" ** Also adds the search and replace strings to the global search history. */ int SearchAndReplace(WindowInfo *window, int direction, const char *searchString, const char *replaceString, int searchType, int searchWrap) { int startPos, endPos, replaceLen, searchExtentBW, searchExtentFW; int found; int beginPos, cursorPos; /* Save a copy of search and replace strings in the search history */ saveSearchHistory(searchString, replaceString, searchType, FALSE); /* If the text selected in the window matches the search string, */ /* the user is probably using search then replace method, so */ /* replace the selected text regardless of where the cursor is. */ /* Otherwise, search for the string. */ if (!searchMatchesSelection(window, searchString, searchType, &startPos, &endPos, &searchExtentBW, &searchExtentFW)) { /* get the position to start the search */ cursorPos = TextGetCursorPos(window->lastFocus); if (direction == SEARCH_BACKWARD) { /* use the insert position - 1 for backward searches */ beginPos = cursorPos-1; } else { /* use the insert position for forward searches */ beginPos = cursorPos; } /* do the search */ found = SearchWindow(window, direction, searchString, searchType, searchWrap, beginPos, &startPos, &endPos, &searchExtentBW, &searchExtentFW); if (!found) return FALSE; } /* replace the text */ if (isRegexType(searchType)) { char replaceResult[SEARCHMAX], *foundString; foundString = BufGetRange(window->buffer, searchExtentBW, searchExtentFW+1); replaceUsingRE(searchString, replaceString, foundString, startPos - searchExtentBW, replaceResult, SEARCHMAX, startPos == 0 ? '\0' : BufGetCharacter(window->buffer, startPos-1), GetWindowDelimiters(window), defaultRegexFlags(searchType)); XtFree(foundString); BufReplace(window->buffer, startPos, endPos, replaceResult); replaceLen = strlen(replaceResult); } else { BufReplace(window->buffer, startPos, endPos, replaceString); replaceLen = strlen(replaceString); } /* after successfully completing a replace, selected text attracts attention away from the area of the replacement, particularly when the selection represents a previous search. so deselect */ BufUnselect(window->buffer); /* temporarily shut off autoShowInsertPos before setting the cursor position so MakeSelectionVisible gets a chance to place the replaced string at a pleasing position on the screen (otherwise, the cursor would be automatically scrolled on screen and MakeSelectionVisible would do nothing) */ XtVaSetValues(window->lastFocus, textNautoShowInsertPos, False, NULL); TextSetCursorPos(window->lastFocus, startPos + ((direction == SEARCH_FORWARD) ? replaceLen : 0)); MakeSelectionVisible(window, window->lastFocus); XtVaSetValues(window->lastFocus, textNautoShowInsertPos, True, NULL); return TRUE; } /* ** Uses the resource nedit.truncSubstitution to determine how to deal with ** regex failures. This function only knows about the resource (via the usual ** setting getter) and asks or warns the user depending on that. ** ** One could argue that the dialoging should be determined by the setting ** 'searchDlogs'. However, the incomplete substitution is not just a question ** of verbosity, but of data loss. The search is successful, only the ** replacement fails due to an internal limitation of NEdit. ** ** The parameters 'parent' and 'display' are only used to put dialogs and ** beeps at the right place. ** ** The result is either predetermined by the resource or the user's choice. */ static Boolean prefOrUserCancelsSubst(const Widget parent, const Display* display) { Boolean cancel = True; unsigned confirmResult = 0; switch (GetPrefTruncSubstitution()) { case TRUNCSUBST_SILENT: /* silently fail the operation */ cancel = True; break; case TRUNCSUBST_FAIL: /* fail the operation and pop up a dialog informing the user */ XBell((Display*) display, 0); DialogF(DF_INF, parent, 1, "Substitution Failed", "The result length of the substitution exceeded an internal limit.\n" "The substitution is canceled.", "OK"); cancel = True; break; case TRUNCSUBST_WARN: /* pop up dialog and ask for confirmation */ XBell((Display*) display, 0); confirmResult = DialogF(DF_WARN, parent, 2, "Substitution Failed", "The result length of the substitution exceeded an internal limit.\n" "Executing the substitution will result in loss of data.", "Lose Data", "Cancel"); cancel = (1 != confirmResult); break; case TRUNCSUBST_IGNORE: /* silently conclude the operation; THIS WILL DESTROY DATA. */ cancel = False; break; } return cancel; } /* ** Replace all occurences of "searchString" in "window" with "replaceString" ** within the current primary selection in "window". Also adds the search and ** replace strings to the global search history. */ void ReplaceInSelection(const WindowInfo* window, const char* searchString, const char* replaceString, const int searchType) { int selStart, selEnd, beginPos, startPos, endPos, realOffset, replaceLen; int found, isRect, rectStart, rectEnd, lineStart, cursorPos; int extentBW, extentFW; char *fileString; textBuffer *tempBuf; Boolean substSuccess = False; Boolean anyFound = False; Boolean cancelSubst = True; /* save a copy of search and replace strings in the search history */ saveSearchHistory(searchString, replaceString, searchType, FALSE); /* find out where the selection is */ if (!BufGetSelectionPos(window->buffer, &selStart, &selEnd, &isRect, &rectStart, &rectEnd)) return; /* get the selected text */ if (isRect) { selStart = BufStartOfLine(window->buffer, selStart); selEnd = BufEndOfLine(window->buffer, selEnd); fileString = BufGetRange(window->buffer, selStart, selEnd); } else fileString = BufGetSelectionText(window->buffer); /* create a temporary buffer in which to do the replacements to hide the intermediate steps from the display routines, and so everything can be undone in a single operation */ tempBuf = BufCreate(); BufSetAll(tempBuf, fileString); /* search the string and do the replacements in the temporary buffer */ replaceLen = strlen(replaceString); found = TRUE; beginPos = 0; cursorPos = 0; realOffset = 0; while (found) { found = SearchString(fileString, searchString, SEARCH_FORWARD, searchType, FALSE, beginPos, &startPos, &endPos, &extentBW, &extentFW, GetWindowDelimiters(window)); if (!found) break; anyFound = True; /* if the selection is rectangular, verify that the found string is in the rectangle */ if (isRect) { lineStart = BufStartOfLine(window->buffer, selStart+startPos); if (BufCountDispChars(window->buffer, lineStart, selStart+startPos) < rectStart || BufCountDispChars(window->buffer, lineStart, selStart+endPos) > rectEnd) { if (fileString[endPos] == '\0') break; /* If the match starts before the left boundary of the selection, and extends past it, we should not continue search after the end of the (false) match, because we could miss a valid match starting between the left boundary and the end of the false match. */ if (BufCountDispChars(window->buffer, lineStart, selStart+startPos) < rectStart && BufCountDispChars(window->buffer, lineStart, selStart+endPos) > rectStart) beginPos += 1; else beginPos = (startPos == endPos) ? endPos+1 : endPos; continue; } } /* Make sure the match did not start past the end (regular expressions can consider the artificial end of the range as the end of a line, and match a fictional whole line beginning there) */ if (startPos == (selEnd - selStart)) { found = False; break; } /* replace the string and compensate for length change */ if (isRegexType(searchType)) { char replaceResult[SEARCHMAX], *foundString; foundString = BufGetRange(tempBuf, extentBW+realOffset, extentFW+realOffset+1); substSuccess = replaceUsingRE(searchString, replaceString, foundString, startPos - extentBW, replaceResult, SEARCHMAX, 0 == (startPos + realOffset) ? '\0' : BufGetCharacter(tempBuf, startPos + realOffset - 1), GetWindowDelimiters(window), defaultRegexFlags(searchType)); XtFree(foundString); if (!substSuccess) { /* The substitution failed. Primary reason for this would be a result string exceeding SEARCHMAX. */ cancelSubst = prefOrUserCancelsSubst(window->shell, TheDisplay); if (cancelSubst) { /* No point in trying other substitutions. */ break; } } BufReplace(tempBuf, startPos+realOffset, endPos+realOffset, replaceResult); replaceLen = strlen(replaceResult); } else { /* at this point plain substitutions (should) always work */ BufReplace(tempBuf, startPos+realOffset, endPos+realOffset, replaceString); substSuccess = True; } realOffset += replaceLen - (endPos - startPos); /* start again after match unless match was empty, then endPos+1 */ beginPos = (startPos == endPos) ? endPos+1 : endPos; cursorPos = endPos; if (fileString[endPos] == '\0') break; } XtFree(fileString); if (anyFound) { if (substSuccess || !cancelSubst) { /* Either the substitution was successful (the common case) or the user does not care and wants to have a faulty replacement. */ /* replace the selected range in the real buffer */ BufReplace(window->buffer, selStart, selEnd, BufAsString(tempBuf)); /* set the insert point at the end of the last replacement */ TextSetCursorPos(window->lastFocus, selStart + cursorPos + realOffset); /* leave non-rectangular selections selected (rect. ones after replacement are less useful since left/right positions are randomly adjusted) */ if (!isRect) { BufSelect(window->buffer, selStart, selEnd + realOffset); } } } else { /* Nothing found, tell the user about it */ if (GetPrefSearchDlogs()) { /* Avoid bug in Motif 1.1 by putting away search dialog before DialogF */ if (window->findDlog && XtIsManaged(window->findDlog) && !XmToggleButtonGetState(window->findKeepBtn)) XtUnmanageChild(window->findDlog); if (window->replaceDlog && XtIsManaged(window->replaceDlog) && !XmToggleButtonGetState(window->replaceKeepBtn)) unmanageReplaceDialogs(window); DialogF(DF_INF, window->shell, 1, "String not found", "String was not found", "OK"); } else XBell(TheDisplay, 0); } BufFree(tempBuf); return; } /* ** Replace all occurences of "searchString" in "window" with "replaceString". ** Also adds the search and replace strings to the global search history. */ int ReplaceAll(WindowInfo *window, const char *searchString, const char *replaceString, int searchType) { const char *fileString; char *newFileString; int copyStart, copyEnd, replacementLen; /* reject empty string */ if (*searchString == '\0') return FALSE; /* save a copy of search and replace strings in the search history */ saveSearchHistory(searchString, replaceString, searchType, FALSE); /* view the entire text buffer from the text area widget as a string */ fileString = BufAsString(window->buffer); newFileString = ReplaceAllInString(fileString, searchString, replaceString, searchType, ©Start, ©End, &replacementLen, GetWindowDelimiters(window)); if (newFileString == NULL) { if (window->multiFileBusy) { window->replaceFailed = TRUE; /* only needed during multi-file replacements */ } else if (GetPrefSearchDlogs()) { if (window->findDlog && XtIsManaged(window->findDlog) && !XmToggleButtonGetState(window->findKeepBtn)) XtUnmanageChild(window->findDlog); if (window->replaceDlog && XtIsManaged(window->replaceDlog) && !XmToggleButtonGetState(window->replaceKeepBtn)) unmanageReplaceDialogs(window); DialogF(DF_INF, window->shell, 1, "String not found", "String was not found", "OK"); } else XBell(TheDisplay, 0); return FALSE; } /* replace the contents of the text widget with the substituted text */ BufReplace(window->buffer, copyStart, copyEnd, newFileString); /* Move the cursor to the end of the last replacement */ TextSetCursorPos(window->lastFocus, copyStart + replacementLen); XtFree(newFileString); return TRUE; } /* ** Replace all occurences of "searchString" in "inString" with "replaceString" ** and return an allocated string covering the range between the start of the ** first replacement (returned in "copyStart", and the end of the last ** replacement (returned in "copyEnd") */ char *ReplaceAllInString(const char *inString, const char *searchString, const char *replaceString, int searchType, int *copyStart, int *copyEnd, int *replacementLength, const char *delimiters) { int beginPos, startPos, endPos, lastEndPos; int found, nFound, removeLen, replaceLen, copyLen, addLen; char *outString, *fillPtr; int searchExtentBW, searchExtentFW; /* reject empty string */ if (*searchString == '\0') return NULL; /* rehearse the search first to determine the size of the buffer needed to hold the substituted text. No substitution done here yet */ replaceLen = strlen(replaceString); found = TRUE; nFound = 0; removeLen = 0; addLen = 0; beginPos = 0; *copyStart = -1; while (found) { found = SearchString(inString, searchString, SEARCH_FORWARD, searchType, FALSE, beginPos, &startPos, &endPos, &searchExtentBW, &searchExtentFW, delimiters); if (found) { if (*copyStart < 0) *copyStart = startPos; *copyEnd = endPos; /* start next after match unless match was empty, then endPos+1 */ beginPos = (startPos == endPos) ? endPos+1 : endPos; nFound++; removeLen += endPos - startPos; if (isRegexType(searchType)) { char replaceResult[SEARCHMAX]; replaceUsingRE(searchString, replaceString, &inString[searchExtentBW], startPos-searchExtentBW, replaceResult, SEARCHMAX, startPos == 0 ? '\0' : inString[startPos-1], delimiters, defaultRegexFlags(searchType)); addLen += strlen(replaceResult); } else addLen += replaceLen; if (inString[endPos] == '\0') break; } } if (nFound == 0) return NULL; /* Allocate a new buffer to hold all of the new text between the first and last substitutions */ copyLen = *copyEnd - *copyStart; outString = XtMalloc(copyLen - removeLen + addLen + 1); /* Scan through the text buffer again, substituting the replace string and copying the part between replaced text to the new buffer */ found = TRUE; beginPos = 0; lastEndPos = 0; fillPtr = outString; while (found) { found = SearchString(inString, searchString, SEARCH_FORWARD, searchType, FALSE, beginPos, &startPos, &endPos, &searchExtentBW, &searchExtentFW, delimiters); if (found) { if (beginPos != 0) { memcpy(fillPtr, &inString[lastEndPos], startPos - lastEndPos); fillPtr += startPos - lastEndPos; } if (isRegexType(searchType)) { char replaceResult[SEARCHMAX]; replaceUsingRE(searchString, replaceString, &inString[searchExtentBW], startPos-searchExtentBW, replaceResult, SEARCHMAX, startPos == 0 ? '\0' : inString[startPos-1], delimiters, defaultRegexFlags(searchType)); replaceLen = strlen(replaceResult); memcpy(fillPtr, replaceResult, replaceLen); } else { memcpy(fillPtr, replaceString, replaceLen); } fillPtr += replaceLen; lastEndPos = endPos; /* start next after match unless match was empty, then endPos+1 */ beginPos = (startPos == endPos) ? endPos+1 : endPos; if (inString[endPos] == '\0') break; } } *fillPtr = '\0'; *replacementLength = fillPtr - outString; return outString; } /* ** If this is an incremental search and BeepOnSearchWrap is on: ** Emit a beep if the search wrapped over BOF/EOF compared to ** the last startPos of the current incremental search. */ static void iSearchTryBeepOnWrap(WindowInfo *window, int direction, int beginPos, int startPos) { if (GetPrefBeepOnSearchWrap()) { if (direction == SEARCH_FORWARD) { if ((startPos >= beginPos && window->iSearchLastBeginPos < beginPos) ||(startPos < beginPos && window->iSearchLastBeginPos >= beginPos)) { XBell(TheDisplay, 0); } } else { if ((startPos <= beginPos && window->iSearchLastBeginPos > beginPos) ||(startPos > beginPos && window->iSearchLastBeginPos <= beginPos)) { XBell(TheDisplay, 0); } } } } /* ** Search the text in "window", attempting to match "searchString" */ int SearchWindow(WindowInfo *window, int direction, const char *searchString, int searchType, int searchWrap, int beginPos, int *startPos, int *endPos, int *extentBW, int *extentFW) { const char *fileString; int found, resp, fileEnd = window->buffer->length - 1, outsideBounds; /* reject empty string */ if (*searchString == '\0') return FALSE; /* get the entire text buffer from the text area widget */ fileString = BufAsString(window->buffer); /* If we're already outside the boundaries, we must consider wrapping immediately (Note: fileEnd+1 is a valid starting position. Consider searching for $ at the end of a file ending with \n.) */ if ((direction == SEARCH_FORWARD && beginPos > fileEnd + 1) || (direction == SEARCH_BACKWARD && beginPos < 0)) { outsideBounds = TRUE; } else { outsideBounds = FALSE; } /* search the string copied from the text area widget, and present dialogs, or just beep. iSearchStartPos is not a perfect indicator that an incremental search is in progress. A parameter would be better. */ if (window->iSearchStartPos == -1) { /* normal search */ found = !outsideBounds && SearchString(fileString, searchString, direction, searchType, FALSE, beginPos, startPos, endPos, extentBW, extentFW, GetWindowDelimiters(window)); /* Avoid Motif 1.1 bug by putting away search dialog before DialogF */ if (window->findDlog && XtIsManaged(window->findDlog) && !XmToggleButtonGetState(window->findKeepBtn)) XtUnmanageChild(window->findDlog); if (window->replaceDlog && XtIsManaged(window->replaceDlog) && !XmToggleButtonGetState(window->replaceKeepBtn)) unmanageReplaceDialogs(window); if (!found) { if (searchWrap) { if (direction == SEARCH_FORWARD && beginPos != 0) { if(GetPrefBeepOnSearchWrap()) { XBell(TheDisplay, 0); } else if (GetPrefSearchDlogs()) { resp = DialogF(DF_QUES, window->shell, 2, "Wrap Search", "Continue search from\nbeginning of file?", "Continue", "Cancel"); if (resp == 2) { return False; } } found = SearchString(fileString, searchString, direction, searchType, FALSE, 0, startPos, endPos, extentBW, extentFW, GetWindowDelimiters(window)); } else if (direction == SEARCH_BACKWARD && beginPos != fileEnd) { if(GetPrefBeepOnSearchWrap()) { XBell(TheDisplay, 0); } else if (GetPrefSearchDlogs()) { resp = DialogF(DF_QUES, window->shell, 2, "Wrap Search", "Continue search\nfrom end of file?", "Continue", "Cancel"); if (resp == 2) { return False; } } found = SearchString(fileString, searchString, direction, searchType, FALSE, fileEnd + 1, startPos, endPos, extentBW, extentFW, GetWindowDelimiters(window)); } } if (!found) { if (GetPrefSearchDlogs()) { DialogF(DF_INF, window->shell, 1, "String not found", "String was not found","OK"); } else { XBell(TheDisplay, 0); } } } } else { /* incremental search */ if (outsideBounds && searchWrap) { if (direction == SEARCH_FORWARD) beginPos = 0; else beginPos = fileEnd+1; outsideBounds = FALSE; } found = !outsideBounds && SearchString(fileString, searchString, direction, searchType, searchWrap, beginPos, startPos, endPos, extentBW, extentFW, GetWindowDelimiters(window)); if (found) { iSearchTryBeepOnWrap(window, direction, beginPos, *startPos); } else XBell(TheDisplay, 0); } return found; } /* ** Search the null terminated string "string" for "searchString", beginning at ** "beginPos". Returns the boundaries of the match in "startPos" and "endPos". ** searchExtentBW and searchExtentFW return the backwardmost and forwardmost ** positions used to make the match, which are usually startPos and endPos, ** but may extend further if positive lookahead or lookbehind was used in ** a regular expression match. "delimiters" may be used to provide an ** alternative set of word delimiters for regular expression "<" and ">" ** characters, or simply passed as null for the default delimiter set. */ int SearchString(const char *string, const char *searchString, int direction, int searchType, int wrap, int beginPos, int *startPos, int *endPos, int *searchExtentBW, int *searchExtentFW, const char *delimiters) { switch (searchType) { case SEARCH_CASE_SENSE_WORD: return searchLiteralWord(string, searchString, TRUE, direction, wrap, beginPos, startPos, endPos, delimiters); case SEARCH_LITERAL_WORD: return searchLiteralWord(string, searchString, FALSE, direction, wrap, beginPos, startPos, endPos, delimiters); case SEARCH_CASE_SENSE: return searchLiteral(string, searchString, TRUE, direction, wrap, beginPos, startPos, endPos, searchExtentBW, searchExtentFW); case SEARCH_LITERAL: return searchLiteral(string, searchString, FALSE, direction, wrap, beginPos, startPos, endPos, searchExtentBW, searchExtentFW); case SEARCH_REGEX: return searchRegex(string, searchString, direction, wrap, beginPos, startPos, endPos, searchExtentBW, searchExtentFW, delimiters, REDFLT_STANDARD); case SEARCH_REGEX_NOCASE: return searchRegex(string, searchString, direction, wrap, beginPos, startPos, endPos, searchExtentBW, searchExtentFW, delimiters, REDFLT_CASE_INSENSITIVE); } return FALSE; /* never reached, just makes compilers happy */ } /* ** Parses a search type description string. If the string contains a valid ** search type description, returns TRUE and writes the corresponding ** SearchType in searchType. Returns FALSE and leaves searchType untouched ** otherwise. (Originally written by Markus Schwarzenberg; slightly adapted). */ int StringToSearchType(const char * string, int *searchType) { int i; for (i = 0; searchTypeStrings[i]; i++) { if (!strcmp(string, searchTypeStrings[i])) { break; } } if (!searchTypeStrings[i]) { return FALSE; } *searchType = i; return TRUE; } /* ** Searches for whole words (Markus Schwarzenberg). ** ** If the first/last character of `searchString' is a "normal ** word character" (not contained in `delimiters', not a whitespace) ** then limit search to strings, who's next left/next right character ** is contained in `delimiters' or is a whitespace or text begin or end. ** ** If the first/last character of `searchString' itself is contained ** in delimiters or is a white space, then the neighbour character of the ** first/last character will not be checked, just a simple match ** will suffice in that case. ** */ static int searchLiteralWord(const char *string, const char *searchString, int caseSense, int direction, int wrap, int beginPos, int *startPos, int *endPos, const char * delimiters) { /* This is critical code for the speed of searches. */ /* For efficiency, we define the macro DOSEARCH with the guts of the search */ /* routine and repeat it, changing the parameters of the outer loop for the */ /* searching, forwards, backwards, and before and after the begin point */ #define DOSEARCHWORD() \ if (*filePtr == *ucString || *filePtr == *lcString) { \ /* matched first character */ \ ucPtr = ucString; \ lcPtr = lcString; \ tempPtr = filePtr; \ while (*tempPtr == *ucPtr || *tempPtr == *lcPtr) { \ tempPtr++; ucPtr++; lcPtr++; \ if ( *ucPtr == 0 /* matched whole string */ \ && (cignore_R ||\ isspace((unsigned char)*tempPtr) ||\ strchr(delimiters, *tempPtr) ) \ /* next char right delimits word ? */ \ && (cignore_L ||\ filePtr==string || /* border case */ \ isspace((unsigned char)filePtr[-1]) ||\ strchr(delimiters,filePtr[-1]) ))\ /* next char left delimits word ? */ { \ *startPos = filePtr - string; \ *endPos = tempPtr - string; \ return TRUE; \ } \ } \ } register const char *filePtr, *tempPtr, *ucPtr, *lcPtr; char lcString[SEARCHMAX], ucString[SEARCHMAX]; int cignore_L=0, cignore_R=0; /* SEARCHMAX was fine in the original NEdit, but it should be done away with now that searching can be done from macros without limits. Returning search failure here is cheating users. This limit is not documented. */ if (strlen(searchString) >= SEARCHMAX) return FALSE; /* If there is no language mode, we use the default list of delimiters */ if (delimiters==NULL) delimiters = GetPrefDelimiters(); if ( isspace((unsigned char)*searchString) || strchr(delimiters, *searchString)) cignore_L=1; if ( isspace((unsigned char)searchString[strlen(searchString)-1]) || strchr(delimiters, searchString[strlen(searchString)-1]) ) cignore_R=1; if (caseSense) { strcpy(ucString, searchString); strcpy(lcString, searchString); } else { upCaseString(ucString, searchString); downCaseString(lcString, searchString); } if (direction == SEARCH_FORWARD) { /* search from beginPos to end of string */ for (filePtr=string+beginPos; *filePtr!=0; filePtr++) { DOSEARCHWORD() } if (!wrap) return FALSE; /* search from start of file to beginPos */ for (filePtr=string; filePtr<=string+beginPos; filePtr++) { DOSEARCHWORD() } return FALSE; } else { /* SEARCH_BACKWARD */ /* search from beginPos to start of file. A negative begin pos */ /* says begin searching from the far end of the file */ if (beginPos >= 0) { for (filePtr=string+beginPos; filePtr>=string; filePtr--) { DOSEARCHWORD() } } if (!wrap) return FALSE; /* search from end of file to beginPos */ /*... this strlen call is extreme inefficiency, but it's not obvious */ /* how to get the text string length from the text widget (under 1.1)*/ for (filePtr=string+strlen(string); filePtr>=string+beginPos; filePtr--) { DOSEARCHWORD() } return FALSE; } } static int searchLiteral(const char *string, const char *searchString, int caseSense, int direction, int wrap, int beginPos, int *startPos, int *endPos, int *searchExtentBW, int *searchExtentFW) { /* This is critical code for the speed of searches. */ /* For efficiency, we define the macro DOSEARCH with the guts of the search */ /* routine and repeat it, changing the parameters of the outer loop for the */ /* searching, forwards, backwards, and before and after the begin point */ #define DOSEARCH() \ if (*filePtr == *ucString || *filePtr == *lcString) { \ /* matched first character */ \ ucPtr = ucString; \ lcPtr = lcString; \ tempPtr = filePtr; \ while (*tempPtr == *ucPtr || *tempPtr == *lcPtr) { \ tempPtr++; ucPtr++; lcPtr++; \ if (*ucPtr == 0) { \ /* matched whole string */ \ *startPos = filePtr - string; \ *endPos = tempPtr - string; \ if (searchExtentBW != NULL) \ *searchExtentBW = *startPos; \ if (searchExtentFW != NULL) \ *searchExtentFW = *endPos; \ return TRUE; \ } \ } \ } \ register const char *filePtr, *tempPtr, *ucPtr, *lcPtr; char lcString[SEARCHMAX], ucString[SEARCHMAX]; /* SEARCHMAX was fine in the original NEdit, but it should be done away with now that searching can be done from macros without limits. Returning search failure here is cheating users. This limit is not documented. */ if (strlen(searchString) >= SEARCHMAX) return FALSE; if (caseSense) { strcpy(ucString, searchString); strcpy(lcString, searchString); } else { upCaseString(ucString, searchString); downCaseString(lcString, searchString); } if (direction == SEARCH_FORWARD) { /* search from beginPos to end of string */ for (filePtr=string+beginPos; *filePtr!=0; filePtr++) { DOSEARCH() } if (!wrap) return FALSE; /* search from start of file to beginPos */ for (filePtr=string; filePtr<=string+beginPos; filePtr++) { DOSEARCH() } return FALSE; } else { /* SEARCH_BACKWARD */ /* search from beginPos to start of file. A negative begin pos */ /* says begin searching from the far end of the file */ if (beginPos >= 0) { for (filePtr=string+beginPos; filePtr>=string; filePtr--) { DOSEARCH() } } if (!wrap) return FALSE; /* search from end of file to beginPos */ /*... this strlen call is extreme inefficiency, but it's not obvious */ /* how to get the text string length from the text widget (under 1.1)*/ for (filePtr=string+strlen(string); filePtr>=string+beginPos; filePtr--) { DOSEARCH() } return FALSE; } } static int searchRegex(const char *string, const char *searchString, int direction, int wrap, int beginPos, int *startPos, int *endPos, int *searchExtentBW, int *searchExtentFW, const char *delimiters, int defaultFlags) { if (direction == SEARCH_FORWARD) return forwardRegexSearch(string, searchString, wrap, beginPos, startPos, endPos, searchExtentBW, searchExtentFW, delimiters, defaultFlags); else return backwardRegexSearch(string, searchString, wrap, beginPos, startPos, endPos, searchExtentBW, searchExtentFW, delimiters, defaultFlags); } static int forwardRegexSearch(const char *string, const char *searchString, int wrap, int beginPos, int *startPos, int *endPos, int *searchExtentBW, int *searchExtentFW, const char *delimiters, int defaultFlags) { regexp *compiledRE = NULL; char *compileMsg; /* compile the search string for searching with ExecRE. Note that this does not process errors from compiling the expression. It assumes that the expression was checked earlier. */ compiledRE = CompileRE(searchString, &compileMsg, defaultFlags); if (compiledRE == NULL) return FALSE; /* search from beginPos to end of string */ if (ExecRE(compiledRE, string + beginPos, NULL, FALSE, (beginPos == 0) ? '\0' : string[beginPos-1], '\0', delimiters, string, NULL)) { *startPos = compiledRE->startp[0] - string; *endPos = compiledRE->endp[0] - string; if (searchExtentFW != NULL) *searchExtentFW = compiledRE->extentpFW - string; if (searchExtentBW != NULL) *searchExtentBW = compiledRE->extentpBW - string; free((char *)compiledRE); return TRUE; } /* if wrap turned off, we're done */ if (!wrap) { free((char *)compiledRE); return FALSE; } /* search from the beginning of the string to beginPos */ if (ExecRE(compiledRE, string, string + beginPos, FALSE, '\0', string[beginPos], delimiters, string, NULL)) { *startPos = compiledRE->startp[0] - string; *endPos = compiledRE->endp[0] - string; if (searchExtentFW != NULL) *searchExtentFW = compiledRE->extentpFW - string; if (searchExtentBW != NULL) *searchExtentBW = compiledRE->extentpBW - string; free((char *)compiledRE); return TRUE; } free((char *)compiledRE); return FALSE; } static int backwardRegexSearch(const char *string, const char *searchString, int wrap, int beginPos, int *startPos, int *endPos, int *searchExtentBW, int *searchExtentFW, const char *delimiters, int defaultFlags) { regexp *compiledRE = NULL; char *compileMsg; int length; /* compile the search string for searching with ExecRE */ compiledRE = CompileRE(searchString, &compileMsg, defaultFlags); if (compiledRE == NULL) return FALSE; /* search from beginPos to start of file. A negative begin pos */ /* says begin searching from the far end of the file. */ if (beginPos >= 0) { if (ExecRE(compiledRE, string, string + beginPos, TRUE, '\0', '\0', delimiters, string, NULL)) { *startPos = compiledRE->startp[0] - string; *endPos = compiledRE->endp[0] - string; if (searchExtentFW != NULL) *searchExtentFW = compiledRE->extentpFW - string; if (searchExtentBW != NULL) *searchExtentBW = compiledRE->extentpBW - string; free((char *)compiledRE); return TRUE; } } /* if wrap turned off, we're done */ if (!wrap) { free((char *)compiledRE); return FALSE; } /* search from the end of the string to beginPos */ if (beginPos < 0) beginPos = 0; length = strlen(string); /* sadly, this means scanning entire string */ if (ExecRE(compiledRE, string + beginPos, string + length, TRUE, (beginPos == 0) ? '\0' : string[beginPos-1], '\0', delimiters, string, NULL)) { *startPos = compiledRE->startp[0] - string; *endPos = compiledRE->endp[0] - string; if (searchExtentFW != NULL) *searchExtentFW = compiledRE->extentpFW - string; if (searchExtentBW != NULL) *searchExtentBW = compiledRE->extentpBW - string; free((char *)compiledRE); return TRUE; } free((char *)compiledRE); return FALSE; } static void upCaseString(char *outString, const char *inString) { char *outPtr; const char *inPtr; for (outPtr=outString, inPtr=inString; *inPtr!=0; inPtr++, outPtr++) { *outPtr = toupper((unsigned char)*inPtr); } *outPtr = 0; } static void downCaseString(char *outString, const char *inString) { char *outPtr; const char *inPtr; for (outPtr=outString, inPtr=inString; *inPtr!=0; inPtr++, outPtr++) { *outPtr = tolower((unsigned char)*inPtr); } *outPtr = 0; } /* ** resetFindTabGroup & resetReplaceTabGroup are really gruesome kludges to ** set the keyboard traversal. XmProcessTraversal does not work at ** all on these dialogs. ...It seems to have started working around ** Motif 1.1.2 */ static void resetFindTabGroup(WindowInfo *window) { XmProcessTraversal(window->findText, XmTRAVERSE_CURRENT); } static void resetReplaceTabGroup(WindowInfo *window) { XmProcessTraversal(window->replaceText, XmTRAVERSE_CURRENT); } /* ** Return TRUE if "searchString" exactly matches the text in the window's ** current primary selection using search algorithm "searchType". If true, ** also return the position of the selection in "left" and "right". */ static int searchMatchesSelection(WindowInfo *window, const char *searchString, int searchType, int *left, int *right, int *searchExtentBW, int *searchExtentFW) { int selLen, selStart, selEnd, startPos, endPos, extentBW, extentFW, beginPos; int regexLookContext = isRegexType(searchType) ? 1000 : 0; char *string; int found, isRect, rectStart, rectEnd, lineStart = 0; /* find length of selection, give up on no selection or too long */ if (!BufGetEmptySelectionPos(window->buffer, &selStart, &selEnd, &isRect, &rectStart, &rectEnd)) return FALSE; if (selEnd - selStart > SEARCHMAX) return FALSE; /* if the selection is rectangular, don't match if it spans lines */ if (isRect) { lineStart = BufStartOfLine(window->buffer, selStart); if (lineStart != BufStartOfLine(window->buffer, selEnd)) return FALSE; } /* get the selected text plus some additional context for regular expression lookahead */ if (isRect) { int stringStart = lineStart + rectStart - regexLookContext; if (stringStart < 0) stringStart = 0; string = BufGetRange(window->buffer, stringStart, lineStart + rectEnd + regexLookContext); selLen = rectEnd - rectStart; beginPos = lineStart + rectStart - stringStart; } else { int stringStart = selStart - regexLookContext; if (stringStart < 0) stringStart = 0; string = BufGetRange(window->buffer, stringStart, selEnd + regexLookContext); selLen = selEnd - selStart; beginPos = selStart - stringStart; } if (*string == '\0') { XtFree(string); return FALSE; } /* search for the string in the selection (we are only interested */ /* in an exact match, but the procedure SearchString does important */ /* stuff like applying the correct matching algorithm) */ found = SearchString(string, searchString, SEARCH_FORWARD, searchType, FALSE, beginPos, &startPos, &endPos, &extentBW, &extentFW, GetWindowDelimiters(window)); XtFree(string); /* decide if it is an exact match */ if (!found) return FALSE; if (startPos != beginPos || endPos - beginPos != selLen ) return FALSE; /* return the start and end of the selection */ if (isRect) GetSimpleSelection(window->buffer, left, right); else { *left = selStart; *right = selEnd; } if (searchExtentBW != NULL) *searchExtentBW = *left - (startPos - extentBW); if (searchExtentFW != NULL) *searchExtentFW = *right + extentFW - endPos; return TRUE; } /* ** Substitutes a replace string for a string that was matched using a ** regular expression. This was added later and is rather ineficient ** because instead of using the compiled regular expression that was used ** to make the match in the first place, it re-compiles the expression ** and redoes the search on the already-matched string. This allows the ** code to continue using strings to represent the search and replace ** items. */ static Boolean replaceUsingRE(const char* searchStr, const char* replaceStr, const char* sourceStr, const int beginPos, char* destStr, const int maxDestLen, const int prevChar, const char* delimiters, const int defaultFlags) { regexp *compiledRE; char *compileMsg; Boolean substResult = False; compiledRE = CompileRE(searchStr, &compileMsg, defaultFlags); ExecRE(compiledRE, sourceStr+beginPos, NULL, False, prevChar, '\0', delimiters, sourceStr, NULL); substResult = SubstituteRE(compiledRE, replaceStr, destStr, maxDestLen); free((char *)compiledRE); return substResult; } /* ** Store the search and replace strings, and search type for later recall. ** If replaceString is NULL, duplicate the last replaceString used. ** Contiguous incremental searches share the same history entry (each new ** search modifies the current search string, until a non-incremental search ** is made. To mark the end of an incremental search, call saveSearchHistory ** again with an empty search string and isIncremental==False. */ static void saveSearchHistory(const char *searchString, const char *replaceString, int searchType, int isIncremental) { char *sStr, *rStr; static int currentItemIsIncremental = FALSE; WindowInfo *w; /* Cancel accumulation of contiguous incremental searches (even if the information is not worthy of saving) if search is not incremental */ if (!isIncremental) currentItemIsIncremental = FALSE; /* Don't save empty search strings */ if (searchString[0] == '\0') return; /* If replaceString is NULL, duplicate the last one (if any) */ if (replaceString == NULL) replaceString = NHist >= 1 ? ReplaceHistory[historyIndex(1)] : ""; /* Compare the current search and replace strings against the saved ones. If they are identical, don't bother saving */ if (NHist >= 1 && searchType == SearchTypeHistory[historyIndex(1)] && !strcmp(SearchHistory[historyIndex(1)], searchString) && !strcmp(ReplaceHistory[historyIndex(1)], replaceString)) { return; } /* If the current history item came from an incremental search, and the new one is also incremental, just update the entry */ if (currentItemIsIncremental && isIncremental) { XtFree(SearchHistory[historyIndex(1)]); SearchHistory[historyIndex(1)] = XtNewString(searchString); SearchTypeHistory[historyIndex(1)] = searchType; return; } currentItemIsIncremental = isIncremental; if (NHist==0) { for (w=WindowList; w!=NULL; w=w->next) { if (!IsTopDocument(w)) continue; XtSetSensitive(w->findAgainItem, True); XtSetSensitive(w->replaceFindAgainItem, True); XtSetSensitive(w->replaceAgainItem, True); } } /* If there are more than MAX_SEARCH_HISTORY strings saved, recycle some space, free the entry that's about to be overwritten */ if (NHist == MAX_SEARCH_HISTORY) { XtFree(SearchHistory[HistStart]); XtFree(ReplaceHistory[HistStart]); } else NHist++; /* Allocate and copy the search and replace strings and add them to the circular buffers at HistStart, bump the buffer pointer to next pos. */ sStr = XtMalloc(strlen(searchString) + 1); rStr = XtMalloc(strlen(replaceString) + 1); strcpy(sStr, searchString); strcpy(rStr, replaceString); SearchHistory[HistStart] = sStr; ReplaceHistory[HistStart] = rStr; SearchTypeHistory[HistStart] = searchType; HistStart++; if (HistStart >= MAX_SEARCH_HISTORY) HistStart = 0; } /* ** return an index into the circular buffer arrays of history information ** for search strings, given the number of saveSearchHistory cycles back from ** the current time. */ static int historyIndex(int nCycles) { int index; if (nCycles > NHist || nCycles <= 0) return -1; index = HistStart - nCycles; if (index < 0) index = MAX_SEARCH_HISTORY + index; return index; } /* ** Return a pointer to the string describing search type for search action ** routine parameters (see menu.c for processing of action routines) */ static char *searchTypeArg(int searchType) { if (0 <= searchType && searchType < N_SEARCH_TYPES) { return searchTypeStrings[searchType]; } return searchTypeStrings[SEARCH_LITERAL]; } /* ** Return a pointer to the string describing search wrap for search action ** routine parameters (see menu.c for processing of action routines) */ static char *searchWrapArg(int searchWrap) { if (searchWrap) { return "wrap"; } return "nowrap"; } /* ** Return a pointer to the string describing search direction for search action ** routine parameters (see menu.c for processing of action routines) */ static char *directionArg(int direction) { if (direction == SEARCH_BACKWARD) return "backward"; return "forward"; } /* ** Checks whether a search mode in one of the regular expression modes. */ static int isRegexType(int searchType) { return searchType == SEARCH_REGEX || searchType == SEARCH_REGEX_NOCASE; } /* ** Returns the default flags for regular expression matching, given a ** regular expression search mode. */ static int defaultRegexFlags(int searchType) { switch (searchType) { case SEARCH_REGEX: return REDFLT_STANDARD; case SEARCH_REGEX_NOCASE: return REDFLT_CASE_INSENSITIVE; default: /* We should never get here, but just in case ... */ return REDFLT_STANDARD; } } /* ** The next 4 callbacks handle the states of find/replace toggle ** buttons, which depend on the state of the "Regex" button, and the ** sensitivity of the Whole Word buttons. ** Callbacks are necessary for both "Regex" and "Case Sensitive" ** buttons to make sure the states are saved even after a cancel operation. ** ** If sticky case sensitivity is requested, the behaviour is as follows: ** The first time "Regular expression" is checked, "Match case" gets ** checked too. Thereafter, checking or unchecking "Regular expression" ** restores the "Match case" button to the setting it had the last ** time when literals or REs where used. ** Without sticky behaviour, the state of the Regex button doesn't influence ** the state of the Case Sensitive button. ** ** Independently, the state of the buttons is always restored to the ** default state when a dialog is popped up, and when the user returns ** from stepping through the search history. ** ** NOTE: similar call-backs exist for the incremental search bar; see window.c. */ static void findRegExpToggleCB(Widget w, XtPointer clientData, XtPointer callData) { WindowInfo * window = WidgetToWindow(w); int searchRegex = XmToggleButtonGetState(w); int searchCaseSense = XmToggleButtonGetState(window->findCaseToggle); /* In sticky mode, restore the state of the Case Sensitive button */ if(GetPrefStickyCaseSenseBtn()) { if(searchRegex) { window->findLastLiteralCase = searchCaseSense; XmToggleButtonSetState(window->findCaseToggle, window->findLastRegexCase, False); } else { window->findLastRegexCase = searchCaseSense; XmToggleButtonSetState(window->findCaseToggle, window->findLastLiteralCase, False); } } /* make the Whole Word button insensitive for regex searches */ XtSetSensitive(window->findWordToggle, !searchRegex); } static void replaceRegExpToggleCB(Widget w, XtPointer clientData, XtPointer callData) { WindowInfo * window = WidgetToWindow(w); int searchRegex = XmToggleButtonGetState(w); int searchCaseSense = XmToggleButtonGetState(window->replaceCaseToggle); /* In sticky mode, restore the state of the Case Sensitive button */ if(GetPrefStickyCaseSenseBtn()) { if(searchRegex) { window->replaceLastLiteralCase = searchCaseSense; XmToggleButtonSetState(window->replaceCaseToggle, window->replaceLastRegexCase, False); } else { window->replaceLastRegexCase = searchCaseSense; XmToggleButtonSetState(window->replaceCaseToggle, window->replaceLastLiteralCase, False); } } /* make the Whole Word button insensitive for regex searches */ XtSetSensitive(window->replaceWordToggle, !searchRegex); } static void iSearchRegExpToggleCB(Widget w, XtPointer clientData, XtPointer callData) { WindowInfo * window = WidgetToWindow(w); int searchRegex = XmToggleButtonGetState(w); int searchCaseSense = XmToggleButtonGetState(window->iSearchCaseToggle); /* In sticky mode, restore the state of the Case Sensitive button */ if(GetPrefStickyCaseSenseBtn()) { if(searchRegex) { window->iSearchLastLiteralCase = searchCaseSense; XmToggleButtonSetState(window->iSearchCaseToggle, window->iSearchLastRegexCase, False); } else { window->iSearchLastRegexCase = searchCaseSense; XmToggleButtonSetState(window->iSearchCaseToggle, window->iSearchLastLiteralCase, False); } } /* The iSearch bar has no Whole Word button to enable/disable. */ } static void findCaseToggleCB(Widget w, XtPointer clientData, XtPointer callData) { WindowInfo * window = WidgetToWindow(w); int searchCaseSense = XmToggleButtonGetState(w); /* Save the state of the Case Sensitive button depending on the state of the Regex button*/ if(XmToggleButtonGetState(window->findRegexToggle)) window->findLastRegexCase = searchCaseSense; else window->findLastLiteralCase = searchCaseSense; } static void replaceCaseToggleCB(Widget w, XtPointer clientData, XtPointer callData) { WindowInfo * window = WidgetToWindow(w); int searchCaseSense = XmToggleButtonGetState(w); /* Save the state of the Case Sensitive button depending on the state of the Regex button*/ if(XmToggleButtonGetState(window->replaceRegexToggle)) window->replaceLastRegexCase = searchCaseSense; else window->replaceLastLiteralCase = searchCaseSense; } static void iSearchCaseToggleCB(Widget w, XtPointer clientData, XtPointer callData) { WindowInfo * window = WidgetToWindow(w); int searchCaseSense = XmToggleButtonGetState(w); /* Save the state of the Case Sensitive button depending on the state of the Regex button*/ if(XmToggleButtonGetState(window->iSearchRegexToggle)) window->iSearchLastRegexCase = searchCaseSense; else window->iSearchLastLiteralCase = searchCaseSense; } nedit-5.6.orig/source/search.h0000644000175000017500000001450210513637612015036 0ustar paulpaul/* $Id: search.h,v 1.28 2006/10/13 07:26:02 ajbj Exp $ */ /******************************************************************************* * * * search.h -- Nirvana Editor Search Header File * * * * Copyright 2003 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_SEARCH_H_INCLUDED #define NEDIT_SEARCH_H_INCLUDED #include "nedit.h" #include #include enum SearchDirection {SEARCH_FORWARD, SEARCH_BACKWARD}; void CreateFindDlog(Widget parent, WindowInfo *window); void CreateReplaceDlog(Widget parent, WindowInfo *window); void CreateReplaceMultiFileDlog(WindowInfo *window); void DoFindReplaceDlog(WindowInfo *window, int direction, int keepDialogs, int searchType, Time time); void DoReplaceMultiFileDlog(WindowInfo *window); void UpdateReplaceActionButtons(WindowInfo* window); void DoFindDlog(WindowInfo *window, int direction, int keepDialogs, int searchType, Time time); int SearchAndSelect(WindowInfo *window, int direction, const char *searchString, int searchType, int searchWrap); int SearchAndSelectSame(WindowInfo *window, int direction, int searchWrap); int SearchAndSelectIncremental(WindowInfo *window, int direction, const char *searchString, int searchType, int searchWrap, int continued); void SearchForSelected(WindowInfo *window, int direction, int searchWrap, int searchType, Time time); int SearchAndReplace(WindowInfo *window, int direction, const char *searchString, const char *replaceString, int searchType, int searchWrap); int ReplaceAndSearch(WindowInfo *window, int direction, const char *searchString, const char *replaceString, int searchType, int searchWrap); int ReplaceFindSame(WindowInfo *window, int direction, int searchWrap); int ReplaceSame(WindowInfo *window, int direction, int searchWrap); int ReplaceAll(WindowInfo *window, const char *searchString, const char *replaceString, int searchType); void ReplaceInSelection(const WindowInfo* window, const char* searchString, const char* replaceString, const int searchType); int SearchWindow(WindowInfo *window, int direction, const char *searchString, int searchType, int searchWrap, int beginPos, int *startPos, int *endPos, int *extentBW, int* extentFW); int SearchString(const char *string, const char *searchString, int direction, int searchType, int wrap, int beginPos, int *startPos, int *endPos, int *searchExtentBW, int*searchExtentFW, const char *delimiters); char *ReplaceAllInString(const char *inString, const char *searchString, const char *replaceString, int searchType, int *copyStart, int *copyEnd, int *replacementLength, const char *delimiters); void BeginISearch(WindowInfo *window, int direction); void EndISearch(WindowInfo *window); void SetISearchTextCallbacks(WindowInfo *window); void FlashMatching(WindowInfo *window, Widget textW); void SelectToMatchingCharacter(WindowInfo *window); void GotoMatchingCharacter(WindowInfo *window); void RemoveFromMultiReplaceDialog(WindowInfo *window); Boolean WindowCanBeClosed(WindowInfo *window); /* ** Schwarzenberg: added SEARCH_LITERAL_WORD .. SEARCH_REGEX_NOCASE ** ** The order of the integers in this enumeration must be exactly ** the same as the order of the coressponding strings of the ** array SearchMethodStrings defined in preferences.c (!!) ** */ enum SearchType { SEARCH_LITERAL, SEARCH_CASE_SENSE, SEARCH_REGEX, SEARCH_LITERAL_WORD, SEARCH_CASE_SENSE_WORD, SEARCH_REGEX_NOCASE, N_SEARCH_TYPES /* must be last in enum SearchType */ }; #ifdef REPLACE_SCOPE /* Scope on which the replace operations apply */ enum ReplaceScope { REPL_SCOPE_WIN, REPL_SCOPE_SEL, REPL_SCOPE_MULTI }; /* Default scope if selection exists when replace dialog pops up. "Smart" means "In Selection" if the selection spans more than one line; "In Window" otherwise. */ enum ReplaceAllDefaultScope { REPL_DEF_SCOPE_WINDOW, REPL_DEF_SCOPE_SELECTION, REPL_DEF_SCOPE_SMART }; #endif /* ** Returns a pointer to the string describing the search type for search ** action routine parameters (see menu.c for processing of action routines) ** If searchType is invalid defaultRV is returned. */ const char *SearchTypeArg(int searchType, const char * defaultRV); /* ** Parses a search type description string. If the string contains a valid ** search type description, returns TRUE and writes the corresponding ** SearchType in searchType. Returns FALSE and leaves searchType untouched ** otherwise. */ int StringToSearchType(const char * string, int *searchType); /* ** History of search actions. */ extern int NHist; #endif /* NEDIT_SEARCH_H_INCLUDED */ nedit-5.6.orig/source/selection.c0000644000175000017500000005420310761110373015546 0ustar paulpaulstatic const char CVSID[] = "$Id: selection.c,v 1.34 2008/02/26 22:21:47 ajbj Exp $"; /******************************************************************************* * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * May 10, 1991 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "selection.h" #include "textBuf.h" #include "text.h" #include "nedit.h" #include "file.h" #include "window.h" #include "menu.h" #include "preferences.h" #include "server.h" #include "../util/DialogF.h" #include "../util/fileUtils.h" #include #include #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #if !defined(DONT_HAVE_GLOB) && !defined(USE_MOTIF_GLOB) && !defined(VMS) #include #endif #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif static void gotoCB(Widget widget, WindowInfo *window, Atom *sel, Atom *type, char *value, int *length, int *format); static void fileCB(Widget widget, WindowInfo *window, Atom *sel, Atom *type, char *value, int *length, int *format); static void getAnySelectionCB(Widget widget, char **result, Atom *sel, Atom *type, char *value, int *length, int *format); static void processMarkEvent(Widget w, XtPointer clientData, XEvent *event, Boolean *continueDispatch, char *action, int extend); static void markTimeoutProc(XtPointer clientData, XtIntervalId *id); static void markKeyCB(Widget w, XtPointer clientData, XEvent *event, Boolean *continueDispatch); static void gotoMarkKeyCB(Widget w, XtPointer clientData, XEvent *event, Boolean *continueDispatch); static void gotoMarkExtendKeyCB(Widget w, XtPointer clientData, XEvent *event, Boolean *continueDispatch); static void maintainSelection(selection *sel, int pos, int nInserted, int nDeleted); static void maintainPosition(int *position, int modPos, int nInserted, int nDeleted); /* ** Extract the line and column number from the text string. ** Set the line and/or column number to -1 if not specified, and return -1 if ** both line and column numbers are not specified. */ int StringToLineAndCol(const char *text, int *lineNum, int *column) { char *endptr; long tempNum; int textLen; /* Get line number */ tempNum = strtol( text, &endptr, 10 ); /* If user didn't specify a line number, set lineNum to -1 */ if ( endptr == text ) { *lineNum = -1; } else if ( tempNum >= INT_MAX ) { *lineNum = INT_MAX; } else if ( tempNum < 0 ) { *lineNum = 0; } else { *lineNum = tempNum; } /* Find the next digit */ for ( textLen = strlen(endptr); textLen > 0; endptr++, textLen-- ) { if (isdigit((unsigned char)*endptr) || *endptr == '-' || *endptr == '+') { break; } } /* Get column */ if ( *endptr != '\0' ) { tempNum = strtol( endptr, NULL, 10 ); if ( tempNum >= INT_MAX ) { *column = INT_MAX; } else if ( tempNum < 0 ) { *column = 0; } else { *column = tempNum; } } else { *column = -1; } return *lineNum == -1 && *column == -1 ? -1 : 0; } void GotoLineNumber(WindowInfo *window) { char lineNumText[DF_MAX_PROMPT_LENGTH], *params[1]; int lineNum, column, response; response = DialogF(DF_PROMPT, window->shell, 2, "Goto Line Number", "Goto Line (and/or Column) Number:", lineNumText, "OK", "Cancel"); if (response == 2) return; if (StringToLineAndCol(lineNumText, &lineNum, &column) == -1) { XBell(TheDisplay, 0); return; } params[0] = lineNumText; XtCallActionProc(window->lastFocus, "goto_line_number", NULL, params, 1); } void GotoSelectedLineNumber(WindowInfo *window, Time time) { XtGetSelectionValue(window->textArea, XA_PRIMARY, XA_STRING, (XtSelectionCallbackProc)gotoCB, window, time); } void OpenSelectedFile(WindowInfo *window, Time time) { XtGetSelectionValue(window->textArea, XA_PRIMARY, XA_STRING, (XtSelectionCallbackProc)fileCB, window, time); } /* ** Getting the current selection by making the request, and then blocking ** (processing events) while waiting for a reply. On failure (timeout or ** bad format) returns NULL, otherwise returns the contents of the selection. */ char *GetAnySelection(WindowInfo *window) { static char waitingMarker[1] = ""; char *selText = waitingMarker; XEvent nextEvent; /* If the selection is in the window's own buffer get it from there, but substitute null characters as if it were an external selection */ if (window->buffer->primary.selected) { selText = BufGetSelectionText(window->buffer); BufUnsubstituteNullChars(selText, window->buffer); return selText; } /* Request the selection value to be delivered to getAnySelectionCB */ XtGetSelectionValue(window->textArea, XA_PRIMARY, XA_STRING, (XtSelectionCallbackProc)getAnySelectionCB, &selText, XtLastTimestampProcessed(XtDisplay(window->textArea))); /* Wait for the value to appear */ while (selText == waitingMarker) { XtAppNextEvent(XtWidgetToApplicationContext(window->textArea), &nextEvent); ServerDispatchEvent(&nextEvent); } return selText; } static void gotoCB(Widget widget, WindowInfo *window, Atom *sel, Atom *type, char *value, int *length, int *format) { /* two integers and some space in between */ char lineText[(TYPE_INT_STR_SIZE(int) * 2) + 5]; int rc, lineNum, column, position, curCol; /* skip if we can't get the selection data, or it's obviously not a number */ if (*type == XT_CONVERT_FAIL || value == NULL) { XBell(TheDisplay, 0); return; } if (((size_t) *length) > sizeof(lineText) - 1) { XBell(TheDisplay, 0); XtFree(value); return; } /* should be of type text??? */ if (*format != 8) { fprintf(stderr, "NEdit: Can't handle non 8-bit text\n"); XBell(TheDisplay, 0); XtFree(value); return; } strncpy(lineText, value, sizeof(lineText)); lineText[sizeof(lineText) - 1] = '\0'; rc = StringToLineAndCol(lineText, &lineNum, &column); XtFree(value); if (rc == -1) { XBell(TheDisplay, 0); return; } /* User specified column, but not line number */ if ( lineNum == -1 ) { position = TextGetCursorPos(widget); if (TextPosToLineAndCol(widget, position, &lineNum, &curCol) == False) { XBell(TheDisplay, 0); return; } } /* User didn't specify a column */ else if ( column == -1 ) { SelectNumberedLine(window, lineNum); return; } position = TextLineAndColToPos(widget, lineNum, column ); if ( position == -1 ) { XBell(TheDisplay, 0); return; } TextSetCursorPos(widget, position); } static void fileCB(Widget widget, WindowInfo *window, Atom *sel, Atom *type, char *value, int *length, int *format) { char nameText[MAXPATHLEN], includeName[MAXPATHLEN]; char filename[MAXPATHLEN], pathname[MAXPATHLEN]; char *inPtr, *outPtr; #ifdef VMS #ifndef __DECC static char includeDir[] = "sys$library:"; #else static char includeDir[] = "decc$library_include:"; #endif #else static char includeDir[] = "/usr/include/"; #endif /* VMS */ /* get the string, or skip if we can't get the selection data, or it's obviously not a file name */ if (*type == XT_CONVERT_FAIL || value == NULL) { XBell(TheDisplay, 0); return; } if (*length > MAXPATHLEN || *length == 0) { XBell(TheDisplay, 0); XtFree(value); return; } /* should be of type text??? */ if (*format != 8) { fprintf(stderr, "NEdit: Can't handle non 8-bit text\n"); XBell(TheDisplay, 0); XtFree(value); return; } strncpy(nameText, value, *length); XtFree(value); nameText[*length] = '\0'; /* extract name from #include syntax */ if (sscanf(nameText, "#include \"%[^\"]\"", includeName) == 1) strcpy(nameText, includeName); else if (sscanf(nameText, "#include <%[^<>]>", includeName) == 1) sprintf(nameText, "%s%s", includeDir, includeName); /* strip whitespace from name */ for (inPtr=nameText, outPtr=nameText; *inPtr!='\0'; inPtr++) if (*inPtr != ' ' && *inPtr != '\t' && *inPtr != '\n') *outPtr++ = *inPtr; *outPtr = '\0'; #ifdef VMS /* If path name is relative, make it refer to current window's directory */ if ((strchr(nameText, ':') == NULL) && (strlen(nameText) > 1) && !((nameText[0] == '[') && (nameText[1] != '-') && (nameText[1] != '.'))) { strcpy(filename, window->path); strcat(filename, nameText); strcpy(nameText, filename); } #else /* Process ~ characters in name */ ExpandTilde(nameText); /* If path name is relative, make it refer to current window's directory */ if (nameText[0] != '/') { strcpy(filename, window->path); strcat(filename, nameText); strcpy(nameText, filename); } #endif /* Expand wildcards in file name. Some older systems don't have the glob subroutine for expanding file names, in these cases, either don't expand names, or try to use the Motif internal parsing routine _XmOSGetDirEntries, which is not guranteed to be available, but in practice is there and does work. */ #if defined(DONT_HAVE_GLOB) || defined(VMS) /* Open the file */ if (ParseFilename(nameText, filename, pathname) != 0) { XBell(TheDisplay, 0); return; } EditExistingFile(window, filename, pathname, 0, NULL, False, NULL, GetPrefOpenInTab(), False); #elif defined(USE_MOTIF_GLOB) { char **nameList = NULL; int i, nFiles = 0, maxFiles = 30; if (ParseFilename(nameText, filename, pathname) != 0) { XBell(TheDisplay, 0); return; } _XmOSGetDirEntries(pathname, filename, XmFILE_ANY_TYPE, False, True, &nameList, &nFiles, &maxFiles); for (i=0; ibuffer->length; i++) { lineStart = lineEnd + 1; lineEnd = BufEndOfLine(window->buffer, lineStart); } /* highlight the line */ if (i>lineNum) { /* Line was found */ if (lineEnd < window->buffer->length) { BufSelect(window->buffer, lineStart, lineEnd+1); } else { /* Don't select past the end of the buffer ! */ BufSelect(window->buffer, lineStart, window->buffer->length); } } else { /* Line was not found -> position the selection & cursor at the end without making a real selection and beep */ lineStart = window->buffer->length; BufSelect(window->buffer, lineStart, lineStart); XBell(TheDisplay, 0); } MakeSelectionVisible(window, window->lastFocus); TextSetCursorPos(window->lastFocus, lineStart); } void MarkDialog(WindowInfo *window) { char letterText[DF_MAX_PROMPT_LENGTH], *params[1]; int response; response = DialogF(DF_PROMPT, window->shell, 2, "Mark", "Enter a single letter label to use for recalling\n" "the current selection and cursor position.\n\n" "(To skip this dialog, use the accelerator key,\n" "followed immediately by a letter key (a-z))", letterText, "OK", "Cancel"); if (response == 2) return; if (strlen(letterText) != 1 || !isalpha((unsigned char)letterText[0])) { XBell(TheDisplay, 0); return; } params[0] = letterText; XtCallActionProc(window->lastFocus, "mark", NULL, params, 1); } void GotoMarkDialog(WindowInfo *window, int extend) { char letterText[DF_MAX_PROMPT_LENGTH], *params[2]; int response; response = DialogF(DF_PROMPT, window->shell, 2, "Goto Mark", "Enter the single letter label used to mark\n" "the selection and/or cursor position.\n\n" "(To skip this dialog, use the accelerator\n" "key, followed immediately by the letter)", letterText, "OK", "Cancel"); if (response == 2) return; if (strlen(letterText) != 1 || !isalpha((unsigned char)letterText[0])) { XBell(TheDisplay, 0); return; } params[0] = letterText; params[1] = "extend"; XtCallActionProc(window->lastFocus, "goto_mark", NULL, params, extend ? 2 : 1); } /* ** Process a command to mark a selection. Expects the user to continue ** the command by typing a label character. Handles both correct user ** behavior (type a character a-z) or bad behavior (do nothing or type ** something else). */ void BeginMarkCommand(WindowInfo *window) { XtInsertEventHandler(window->lastFocus, KeyPressMask, False, markKeyCB, window, XtListHead); window->markTimeoutID = XtAppAddTimeOut( XtWidgetToApplicationContext(window->shell), 4000, markTimeoutProc, window->lastFocus); } /* ** Process a command to go to a marked selection. Expects the user to ** continue the command by typing a label character. Handles both correct ** user behavior (type a character a-z) or bad behavior (do nothing or type ** something else). */ void BeginGotoMarkCommand(WindowInfo *window, int extend) { XtInsertEventHandler(window->lastFocus, KeyPressMask, False, extend ? gotoMarkExtendKeyCB : gotoMarkKeyCB, window, XtListHead); window->markTimeoutID = XtAppAddTimeOut( XtWidgetToApplicationContext(window->shell), 4000, markTimeoutProc, window->lastFocus); } /* ** Xt timer procedure for removing event handler if user failed to type a ** mark character withing the allowed time */ static void markTimeoutProc(XtPointer clientData, XtIntervalId *id) { Widget w = (Widget)clientData; WindowInfo *window = WidgetToWindow(w); XtRemoveEventHandler(w, KeyPressMask, False, markKeyCB, window); XtRemoveEventHandler(w, KeyPressMask, False, gotoMarkKeyCB, window); XtRemoveEventHandler(w, KeyPressMask, False, gotoMarkExtendKeyCB, window); window->markTimeoutID = 0; } /* ** Temporary event handlers for keys pressed after the mark or goto-mark ** commands, If the key is valid, grab the key event and call the action ** procedure to mark (or go to) the selection, otherwise, remove the handler ** and give up. */ static void processMarkEvent(Widget w, XtPointer clientData, XEvent *event, Boolean *continueDispatch, char *action, int extend) { XKeyEvent *e = (XKeyEvent *)event; WindowInfo *window = WidgetToWindow(w); Modifiers modifiers; KeySym keysym; char *params[2], string[2]; XtTranslateKeycode(TheDisplay, e->keycode, e->state, &modifiers, &keysym); if ((keysym >= 'A' && keysym <= 'Z') || (keysym >= 'a' && keysym <= 'z')) { string[0] = toupper(keysym); string[1] = '\0'; params[0] = string; params[1] = "extend"; XtCallActionProc(window->lastFocus, action, event, params, extend ? 2 : 1); *continueDispatch = False; } XtRemoveEventHandler(w, KeyPressMask, False, markKeyCB, window); XtRemoveEventHandler(w, KeyPressMask, False, gotoMarkKeyCB, window); XtRemoveEventHandler(w, KeyPressMask, False, gotoMarkExtendKeyCB, window); XtRemoveTimeOut(window->markTimeoutID); } static void markKeyCB(Widget w, XtPointer clientData, XEvent *event, Boolean *continueDispatch) { processMarkEvent(w, clientData, event, continueDispatch, "mark", False); } static void gotoMarkKeyCB(Widget w, XtPointer clientData, XEvent *event, Boolean *continueDispatch) { processMarkEvent(w, clientData, event, continueDispatch, "goto_mark",False); } static void gotoMarkExtendKeyCB(Widget w, XtPointer clientData, XEvent *event, Boolean *continueDispatch) { processMarkEvent(w, clientData, event, continueDispatch, "goto_mark", True); } void AddMark(WindowInfo *window, Widget widget, char label) { int index; /* look for a matching mark to re-use, or advance nMarks to create a new one */ label = toupper(label); for (index=0; indexnMarks; index++) { if (window->markTable[index].label == label) break; } if (index >= MAX_MARKS) { fprintf(stderr, "no more marks allowed\n"); /* shouldn't happen */ return; } if (index == window->nMarks) window->nMarks++; /* store the cursor location and selection position in the table */ window->markTable[index].label = label; memcpy(&window->markTable[index].sel, &window->buffer->primary, sizeof(selection)); window->markTable[index].cursorPos = TextGetCursorPos(widget); } void GotoMark(WindowInfo *window, Widget w, char label, int extendSel) { int index, oldStart, newStart, oldEnd, newEnd, cursorPos; selection *sel, *oldSel; /* look up the mark in the mark table */ label = toupper(label); for (index=0; indexnMarks; index++) { if (window->markTable[index].label == label) break; } if (index == window->nMarks) { XBell(TheDisplay, 0); return; } /* reselect marked the selection, and move the cursor to the marked pos */ sel = &window->markTable[index].sel; oldSel = &window->buffer->primary; cursorPos = window->markTable[index].cursorPos; if (extendSel) { oldStart = oldSel->selected ? oldSel->start : TextGetCursorPos(w); oldEnd = oldSel->selected ? oldSel->end : TextGetCursorPos(w); newStart = sel->selected ? sel->start : cursorPos; newEnd = sel->selected ? sel->end : cursorPos; BufSelect(window->buffer, oldStart < newStart ? oldStart : newStart, oldEnd > newEnd ? oldEnd : newEnd); } else { if (sel->selected) { if (sel->rectangular) BufRectSelect(window->buffer, sel->start, sel->end, sel->rectStart, sel->rectEnd); else BufSelect(window->buffer, sel->start, sel->end); } else BufUnselect(window->buffer); } /* Move the window into a pleasing position relative to the selection or cursor. MakeSelectionVisible is not great with multi-line selections, and here we will sometimes give it one. And to set the cursor position without first using the less pleasing capability of the widget itself for bringing the cursor in to view, you have to first turn it off, set the position, then turn it back on. */ XtVaSetValues(w, textNautoShowInsertPos, False, NULL); TextSetCursorPos(w, cursorPos); MakeSelectionVisible(window, window->lastFocus); XtVaSetValues(w, textNautoShowInsertPos, True, NULL); } /* ** Keep the marks in the windows book-mark table up to date across ** changes to the underlying buffer */ void UpdateMarkTable(WindowInfo *window, int pos, int nInserted, int nDeleted) { int i; for (i=0; inMarks; i++) { maintainSelection(&window->markTable[i].sel, pos, nInserted, nDeleted); maintainPosition(&window->markTable[i].cursorPos, pos, nInserted, nDeleted); } } /* ** Update a selection across buffer modifications specified by ** "pos", "nDeleted", and "nInserted". */ static void maintainSelection(selection *sel, int pos, int nInserted, int nDeleted) { if (!sel->selected || pos > sel->end) return; maintainPosition(&sel->start, pos, nInserted, nDeleted); maintainPosition(&sel->end, pos, nInserted, nDeleted); if (sel->end <= sel->start) sel->selected = False; } /* ** Update a position across buffer modifications specified by ** "modPos", "nDeleted", and "nInserted". */ static void maintainPosition(int *position, int modPos, int nInserted, int nDeleted) { if (modPos > *position) return; if (modPos+nDeleted <= *position) *position += nInserted - nDeleted; else *position = modPos; } nedit-5.6.orig/source/selection.h0000644000175000017500000000567210144236624015564 0ustar paulpaul/* $Id: selection.h,v 1.7 2004/11/09 21:58:44 yooden Exp $ */ /******************************************************************************* * * * selection.h -- Nirvana Editor Selection Header File * * * * Copyright 2002 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_SELECTION_H_INCLUDED #define NEDIT_SELECTION_H_INCLUDED #include "nedit.h" #include #include int StringToLineAndCol(const char *text, int *lineNum, int *column ); void GotoSelectedLineNumber(WindowInfo *window, Time time); void GotoLineNumber(WindowInfo *window); void SelectNumberedLine(WindowInfo *window, int lineNum); void OpenSelectedFile(WindowInfo *window, Time time); char *GetAnySelection(WindowInfo *window); void BeginMarkCommand(WindowInfo *window); void BeginGotoMarkCommand(WindowInfo *window, int extend); void AddMark(WindowInfo *window, Widget widget, char label); void UpdateMarkTable(WindowInfo *window, int pos, int nInserted, int nDeleted); void GotoMark(WindowInfo *window, Widget w, char label, int extendSel); void MarkDialog(WindowInfo *window); void GotoMarkDialog(WindowInfo *window, int extend); #endif /* NEDIT_SELECTION_H_INCLUDED */ nedit-5.6.orig/source/server.c0000644000175000017500000004221310736147253015076 0ustar paulpaulstatic const char CVSID[] = "$Id: server.c,v 1.34 2007/12/31 11:12:43 yooden Exp $"; /******************************************************************************* * * * server.c -- Nirvana Editor edit-server component * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * November, 1995 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "server.h" #include "textBuf.h" #include "nedit.h" #include "window.h" #include "file.h" #include "selection.h" #include "macro.h" #include "menu.h" #include "preferences.h" #include "server_common.h" #include "../util/fileUtils.h" #include "../util/utils.h" #include "../util/misc.h" #include #include #include #include #ifdef VMS #include #include ssdef #include syidef #include "../util/VMSparam.h" #include "../util/VMSutils.h" #else #include #include #ifndef __MVS__ #include #endif #include #include #endif #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif static void processServerCommand(void); static void cleanUpServerCommunication(void); static void processServerCommandString(char *string); static void getFileClosedProperty(WindowInfo *window); static int isLocatedOnDesktop(WindowInfo *window, long currentDesktop); static WindowInfo *findWindowOnDesktop(int tabbed, long currentDesktop); static Atom ServerRequestAtom = 0; static Atom ServerExistsAtom = 0; /* ** Set up inter-client communication for NEdit server end, expected to be ** called only once at startup time */ void InitServerCommunication(void) { Window rootWindow = RootWindow(TheDisplay, DefaultScreen(TheDisplay)); /* Create the server property atoms on the current DISPLAY. */ CreateServerPropertyAtoms(GetPrefServerName(), &ServerExistsAtom, &ServerRequestAtom); /* Pay attention to PropertyChangeNotify events on the root window. Do this before putting up the server atoms, to avoid a race condition (when nc sees that the server exists, it sends a command, so we must make sure that we already monitor properties). */ XSelectInput(TheDisplay, rootWindow, PropertyChangeMask); /* Create the server-exists property on the root window to tell clients whether to try a request (otherwise clients would always have to try and wait for their timeouts to expire) */ XChangeProperty(TheDisplay, rootWindow, ServerExistsAtom, XA_STRING, 8, PropModeReplace, (unsigned char *)"True", 4); /* Set up exit handler for cleaning up server-exists property */ atexit(cleanUpServerCommunication); } static void deleteProperty(Atom* atom) { if (!IsServer) { *atom = None; return; } if (*atom != None) { XDeleteProperty(TheDisplay, RootWindow(TheDisplay, DefaultScreen(TheDisplay)), *atom); *atom = None; } } /* ** Exit handler. Removes server-exists property on root window */ static void cleanUpServerCommunication(void) { WindowInfo *w; /* Delete any per-file properties that still exist * (and that server knows about) */ for (w = WindowList; w; w = w->next) { DeleteFileClosedProperty(w); } /* Delete any per-file properties that still exist * (but that that server doesn't know about) */ DeleteServerFileAtoms(GetPrefServerName(), RootWindow(TheDisplay, DefaultScreen(TheDisplay))); /* Delete the server-exists property from the root window (if it was assigned) and don't let the process exit until the X server has processed the delete request (otherwise it won't be done) */ deleteProperty(&ServerExistsAtom); XSync(TheDisplay, False); } /* ** Special event loop for NEdit servers. Processes PropertyNotify events on ** the root window (this would not be necessary if it were possible to ** register an Xt event-handler for a window, rather than only a widget). ** Invokes server routines when a server-request property appears, ** re-establishes server-exists property when another server exits and ** this server is still alive to take over. */ void ServerMainLoop(XtAppContext context) { while (TRUE) { XEvent event; XtAppNextEvent(context, &event); ServerDispatchEvent(&event); } } static void processServerCommand(void) { Atom dummyAtom; unsigned long nItems, dummyULong; unsigned char *propValue; int getFmt; /* Get the value of the property, and delete it from the root window */ if (XGetWindowProperty(TheDisplay, RootWindow(TheDisplay, DefaultScreen(TheDisplay)), ServerRequestAtom, 0, INT_MAX, True, XA_STRING, &dummyAtom, &getFmt, &nItems, &dummyULong, &propValue) != Success || getFmt != 8) return; /* Invoke the command line processor on the string to process the request */ processServerCommandString((char *)propValue); XFree(propValue); } Boolean ServerDispatchEvent(XEvent *event) { if (IsServer) { Window rootWindow = RootWindow(TheDisplay, DefaultScreen(TheDisplay)); if (event->xany.window == rootWindow && event->xany.type == PropertyNotify) { const XPropertyEvent* e = &event->xproperty; if (e->type == PropertyNotify && e->window == rootWindow) { if (e->atom == ServerRequestAtom && e->state == PropertyNewValue) processServerCommand(); else if (e->atom == ServerExistsAtom && e->state == PropertyDelete) XChangeProperty(TheDisplay, rootWindow, ServerExistsAtom, XA_STRING, 8, PropModeReplace, (unsigned char *)"True", 4); } } } return XtDispatchEvent(event); } /* Try to find existing 'FileOpen' property atom for path. */ static Atom findFileOpenProperty(const char* filename, const char* pathname) { char path[MAXPATHLEN]; Atom atom; if (!IsServer) return(None); strcpy(path, pathname); strcat(path, filename); atom = CreateServerFileOpenAtom(GetPrefServerName(), path); return(atom); } /* Destroy the 'FileOpen' atom to inform nc that this file has ** been opened. */ static void deleteFileOpenProperty(WindowInfo *window) { if (window->filenameSet) { Atom atom = findFileOpenProperty(window->filename, window->path); deleteProperty(&atom); } } static void deleteFileOpenProperty2(const char* filename, const char* pathname) { Atom atom = findFileOpenProperty(filename, pathname); deleteProperty(&atom); } /* Try to find existing 'FileClosed' property atom for path. */ static Atom findFileClosedProperty(const char* filename, const char* pathname) { char path[MAXPATHLEN]; Atom atom; if (!IsServer) return(None); strcpy(path, pathname); strcat(path, filename); atom = CreateServerFileClosedAtom(GetPrefServerName(), path, True); /* don't create */ return(atom); } /* Get hold of the property to use when closing the file. */ static void getFileClosedProperty(WindowInfo *window) { if (window->filenameSet) { window->fileClosedAtom = findFileClosedProperty(window->filename, window->path); } } /* Delete the 'FileClosed' atom to inform nc that this file has ** been closed. */ void DeleteFileClosedProperty(WindowInfo *window) { if (window->filenameSet) { deleteProperty(&window->fileClosedAtom); } } static void deleteFileClosedProperty2(const char* filename, const char* pathname) { Atom atom = findFileClosedProperty(filename, pathname); deleteProperty(&atom); } static int isLocatedOnDesktop(WindowInfo *window, long currentDesktop) { long windowDesktop; if (currentDesktop == -1) return True; /* No desktop information available */ windowDesktop = QueryDesktop(TheDisplay, window->shell); /* Sticky windows have desktop 0xFFFFFFFF by convention */ if (windowDesktop == currentDesktop || windowDesktop == 0xFFFFFFFFL) return True; /* Desktop matches, or window is sticky */ return False; } static WindowInfo *findWindowOnDesktop(int tabbed, long currentDesktop) { WindowInfo *window; if (tabbed == 0 || (tabbed == -1 && GetPrefOpenInTab() == 0)) { /* A new window is requested, unless we find an untitled unmodified document on the current desktop */ for (window=WindowList; window!=NULL; window=window->next) { if (window->filenameSet || window->fileChanged || window->macroCmdData != NULL) { continue; } /* No check for top document here! */ if (isLocatedOnDesktop(window, currentDesktop)) { return window; } } } else { /* Find a window on the current desktop to hold the new document */ for (window=WindowList; window!=NULL; window=window->next) { /* Avoid unnecessary property access (server round-trip) */ if (!IsTopDocument(window)) { continue; } if (isLocatedOnDesktop(window, currentDesktop)) { return window; } } } return NULL; /* No window found on current desktop -> create new window */ } static void processServerCommandString(char *string) { char *fullname, filename[MAXPATHLEN], pathname[MAXPATHLEN]; char *doCommand, *geometry, *langMode, *inPtr; int editFlags, stringLen = strlen(string); int lineNum, createFlag, readFlag, iconicFlag, lastIconic = 0, tabbed = -1; int fileLen, doLen, lmLen, geomLen, charsRead, itemsRead; WindowInfo *window, *lastFile = NULL; long currentDesktop = QueryCurrentDesktop(TheDisplay, RootWindow(TheDisplay, DefaultScreen(TheDisplay))); /* If the command string is empty, put up an empty, Untitled window (or just pop one up if it already exists) */ if (string[0] == '\0') { for (window=WindowList; window!=NULL; window=window->next) if (!window->filenameSet && !window->fileChanged && isLocatedOnDesktop(window, currentDesktop)) break; if (window == NULL) { EditNewFile(findWindowOnDesktop(tabbed, currentDesktop), NULL, False, NULL, NULL); CheckCloseDim(); } else { RaiseDocument(window); XMapRaised(TheDisplay, XtWindow(window->shell)); } return; } /* ** Loop over all of the files in the command list */ inPtr = string; while (TRUE) { if (*inPtr == '\0') break; /* Read a server command from the input string. Header contains: linenum createFlag fileLen doLen\n, followed by a filename and -do command both followed by newlines. This bit of code reads the header, and converts the newlines following the filename and do command to nulls to terminate the filename and doCommand strings */ itemsRead = sscanf(inPtr, "%d %d %d %d %d %d %d %d %d%n", &lineNum, &readFlag, &createFlag, &iconicFlag, &tabbed, &fileLen, &doLen, &lmLen, &geomLen, &charsRead); if (itemsRead != 9) goto readError; inPtr += charsRead + 1; if (inPtr - string + fileLen > stringLen) goto readError; fullname = inPtr; inPtr += fileLen; *inPtr++ = '\0'; if (inPtr - string + doLen > stringLen) goto readError; doCommand = inPtr; inPtr += doLen; *inPtr++ = '\0'; if (inPtr - string + lmLen > stringLen) goto readError; langMode = inPtr; inPtr += lmLen; *inPtr++ = '\0'; if (inPtr - string + geomLen > stringLen) goto readError; geometry = inPtr; inPtr += geomLen; *inPtr++ = '\0'; /* An empty file name means: * put up an empty, Untitled window, or use an existing one * choose a random window for executing the -do macro upon */ if (fileLen <= 0) { for (window=WindowList; window!=NULL; window=window->next) if (!window->filenameSet && !window->fileChanged && isLocatedOnDesktop(window, currentDesktop)) break; if (*doCommand == '\0') { if (window == NULL) { EditNewFile(findWindowOnDesktop(tabbed, currentDesktop), NULL, iconicFlag, lmLen==0?NULL:langMode, NULL); } else { if (iconicFlag) RaiseDocument(window); else RaiseDocumentWindow(window); } } else { WindowInfo *win = WindowList; /* Starting a new command while another one is still running in the same window is not possible (crashes). */ while (win != NULL && win->macroCmdData != NULL) { win = win->next; } if (!win) { XBell(TheDisplay, 0); } else { /* Raise before -do (macro could close window). */ if (iconicFlag) RaiseDocument(win); else RaiseDocumentWindow(win); DoMacro(win, doCommand, "-do macro"); } } CheckCloseDim(); return; } /* Process the filename by looking for the files in an existing window, or opening if they don't exist */ editFlags = (readFlag ? PREF_READ_ONLY : 0) | CREATE | (createFlag ? SUPPRESS_CREATE_WARN : 0); if (ParseFilename(fullname, filename, pathname) != 0) { fprintf(stderr, "NEdit: invalid file name\n"); deleteFileClosedProperty2(filename, pathname); break; } window = FindWindowWithFile(filename, pathname); if (window == NULL) { /* Files are opened in background to improve opening speed by defering certain time consuiming task such as syntax highlighting. At the end of the file-opening loop, the last file opened will be raised to restore those deferred items. The current file may also be raised if there're macros to execute on. */ window = EditExistingFile(findWindowOnDesktop(tabbed, currentDesktop), filename, pathname, editFlags, geometry, iconicFlag, lmLen == 0 ? NULL : langMode, tabbed == -1? GetPrefOpenInTab() : tabbed, True); if (window) { CleanUpTabBarExposeQueue(window); if (lastFile && window->shell != lastFile->shell) { CleanUpTabBarExposeQueue(lastFile); RaiseDocument(lastFile); } } } /* Do the actions requested (note DoMacro is last, since the do command can do anything, including closing the window!) */ if (window != NULL) { deleteFileOpenProperty(window); getFileClosedProperty(window); if (lineNum > 0) SelectNumberedLine(window, lineNum); if (*doCommand != '\0') { RaiseDocument(window); if (!iconicFlag) XMapRaised(TheDisplay, XtWindow(window->shell)); /* Starting a new command while another one is still running in the same window is not possible (crashes). */ if (window->macroCmdData != NULL) { XBell(TheDisplay, 0); } else { DoMacro(window, doCommand, "-do macro"); /* in case window is closed by macro functions such as close() or detach_document() */ if (!IsValidWindow(window)) window = NULL; if (lastFile && !IsValidWindow(lastFile)) lastFile = NULL; } } /* register the last file opened for later use */ if (window) { lastFile = window; lastIconic = iconicFlag; } } else { deleteFileOpenProperty2(filename, pathname); deleteFileClosedProperty2(filename, pathname); } } /* Raise the last file opened */ if (lastFile) { CleanUpTabBarExposeQueue(lastFile); if (lastIconic) RaiseDocument(lastFile); else RaiseDocumentWindow(lastFile); CheckCloseDim(); } return; readError: fprintf(stderr, "NEdit: error processing server request\n"); return; } nedit-5.6.orig/source/server.h0000644000175000017500000000462010144236624015075 0ustar paulpaul/* $Id: server.h,v 1.7 2004/11/09 21:58:44 yooden Exp $ */ /******************************************************************************* * * * server.h -- Nirvana Editor Server Header File * * * * Copyright 2002 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_SERVER_H_INCLUDED #define NEDIT_SERVER_H_INCLUDED #include "window.h" #define NO_CONNECTION -1 #define COM_OK 1 #define COM_FAILURE 2 void InitServerCommunication(void); void ServerMainLoop(XtAppContext context); Boolean ServerDispatchEvent(XEvent *event); void DeleteFileClosedProperty(WindowInfo *window); #endif /* NEDIT_SERVER_H_INCLUDED */ nedit-5.6.orig/source/server_common.c0000644000175000017500000001245010737527370016451 0ustar paulpaul/******************************************************************************* * * * server_common.c -- Nirvana Editor common server stuff * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * November, 1995 * * * * Written by Mark Edel * * * *******************************************************************************/ #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #include "nedit.h" #include "server_common.h" #include "../util/utils.h" /* * Create the server property atoms for the server with serverName. * Atom names are generated as follows: * * NEDIT_SERVER_EXISTS___ * NEDIT_SERVER_REQUEST___ * * is the name that can be set by the user to allow * for multiple servers to run on the same display. * defaults to "" if not supplied by the user. * * is the user name of the current user. */ void CreateServerPropertyAtoms(const char *serverName, Atom *serverExistsAtomReturn, Atom *serverRequestAtomReturn) { char propName[20+1+MAXNODENAMELEN+1+MAXUSERNAMELEN+1+MAXSERVERNAMELEN]; const char *userName = GetUserName(); const char *hostName = GetNameOfHost(); sprintf(propName, "NEDIT_SERVER_EXISTS_%s_%s_%s", hostName, userName, serverName); *serverExistsAtomReturn = XInternAtom(TheDisplay, propName, False); sprintf(propName, "NEDIT_SERVER_REQUEST_%s_%s_%s", hostName, userName, serverName); *serverRequestAtomReturn = XInternAtom(TheDisplay, propName, False); } /* * Create the individual property atoms for each file being * opened by the server with serverName. This atom is used * by nc to monitor if the file has been closed. * * Atom names are generated as follows: * * NEDIT_FILE____ * * is the name that can be set by the user to allow * for multiple servers to run on the same display. * defaults to "" if not supplied by the user. * * is the user name of the current user. * * is the path of the file being edited. */ Atom CreateServerFileOpenAtom(const char *serverName, const char *path) { char propName[10+1+MAXNODENAMELEN+1+MAXUSERNAMELEN+1+MAXSERVERNAMELEN+1+MAXPATHLEN+1+7]; const char *userName = GetUserName(); const char *hostName = GetNameOfHost(); Atom atom; sprintf(propName, "NEDIT_FILE_%s_%s_%s_%s_WF_OPEN", hostName, userName, serverName, path); atom = XInternAtom(TheDisplay, propName, False); return(atom); } Atom CreateServerFileClosedAtom(const char *serverName, const char *path, Bool only_if_exist) { char propName[10+1+MAXNODENAMELEN+1+MAXUSERNAMELEN+1+MAXSERVERNAMELEN+1+MAXPATHLEN+1+9]; const char *userName = GetUserName(); const char *hostName = GetNameOfHost(); Atom atom; sprintf(propName, "NEDIT_FILE_%s_%s_%s_%s_WF_CLOSED", hostName, userName, serverName, path); atom = XInternAtom(TheDisplay, propName, only_if_exist); return(atom); } /* * Delete all File atoms that belong to this server (as specified by * __). */ void DeleteServerFileAtoms(const char* serverName, Window rootWindow) { char propNamePrefix[10+1+MAXNODENAMELEN+1+MAXUSERNAMELEN+1+MAXSERVERNAMELEN+1]; const char *userName = GetUserName(); const char *hostName = GetNameOfHost(); int length = sprintf(propNamePrefix, "NEDIT_FILE_%s_%s_%s_", hostName, userName, serverName); int nProperties; Atom* atoms = XListProperties(TheDisplay, rootWindow, &nProperties); if (atoms != NULL) { int i; for (i = 0; i < nProperties; i++) { /* XGetAtomNames() is more efficient, but doesn't exist in X11R5. */ char *name = XGetAtomName(TheDisplay, atoms[i]); if (name != NULL && strncmp(propNamePrefix, name, length) == 0) { XDeleteProperty(TheDisplay, rootWindow, atoms[i]); } XFree(name); } XFree((char*)atoms); } } nedit-5.6.orig/source/server_common.h0000644000175000017500000000447510144236624016455 0ustar paulpaul/* $Id: server_common.h,v 1.3 2004/11/09 21:58:44 yooden Exp $ */ /******************************************************************************* * * * server_common.h -- Nirvana Editor common server stuff * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * November, 1995 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifndef NEDIT_SERVER_COMMON_H_INCLUDED #define NEDIT_SERVER_COMMON_H_INCLUDED #include /* Lets limit the unique server name to MAXPATHLEN */ #define MAXSERVERNAMELEN MAXPATHLEN #define DEFAULTSERVERNAME "" void CreateServerPropertyAtoms(const char *serverName, Atom *serverExistsAtomReturn, Atom *serverRequestAtomReturn); Atom CreateServerFileOpenAtom(const char *serverName, const char *path); Atom CreateServerFileClosedAtom(const char *serverName, const char *path, Bool only_if_exists); void DeleteServerFileAtoms(const char* serverName, Window rootWindow); #endif /* NEDIT_SERVER_COMMON_H_INCLUDED */ nedit-5.6.orig/source/shell.c0000644000175000017500000013272210737527370014707 0ustar paulpaulstatic const char CVSID[] = "$Id: shell.c,v 1.44 2008/01/04 22:11:04 yooden Exp $"; /******************************************************************************* * * * shell.c -- Nirvana Editor shell command execution * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * December, 1993 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "shell.h" #include "textBuf.h" #include "text.h" #include "nedit.h" #include "window.h" #include "preferences.h" #include "file.h" #include "macro.h" #include "interpret.h" #include "../util/DialogF.h" #include "../util/misc.h" #include "menu.h" #include #include #include #include #include #ifndef __MVS__ #ifndef VMS #include #endif #endif #include #include #include #include #include #ifdef notdef #ifdef IBM #define NBBY 8 #include #endif #include #endif #ifdef __EMX__ #include #endif #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif /* Tuning parameters */ #define IO_BUF_SIZE 4096 /* size of buffers for collecting cmd output */ #define MAX_OUT_DIALOG_ROWS 30 /* max height of dialog for command output */ #define MAX_OUT_DIALOG_COLS 80 /* max width of dialog for command output */ #define OUTPUT_FLUSH_FREQ 1000 /* how often (msec) to flush output buffers when process is taking too long */ #define BANNER_WAIT_TIME 6000 /* how long to wait (msec) before putting up Shell Command Executing... banner */ /* flags for issueCommand */ #define ACCUMULATE 1 #define ERROR_DIALOGS 2 #define REPLACE_SELECTION 4 #define RELOAD_FILE_AFTER 8 #define OUTPUT_TO_DIALOG 16 #define OUTPUT_TO_STRING 32 /* element of a buffer list for collecting output from shell processes */ typedef struct bufElem { struct bufElem *next; int length; char contents[IO_BUF_SIZE]; } buffer; /* data attached to window during shell command execution with information for controling and communicating with the process */ typedef struct { int flags; int stdinFD, stdoutFD, stderrFD; pid_t childPid; XtInputId stdinInputID, stdoutInputID, stderrInputID; buffer *outBufs, *errBufs; char *input; char *inPtr; Widget textW; int leftPos, rightPos; int inLength; XtIntervalId bannerTimeoutID, flushTimeoutID; char bannerIsUp; char fromMacro; } shellCmdInfo; static void issueCommand(WindowInfo *window, const char *command, char *input, int inputLen, int flags, Widget textW, int replaceLeft, int replaceRight, int fromMacro); static void stdoutReadProc(XtPointer clientData, int *source, XtInputId *id); static void stderrReadProc(XtPointer clientData, int *source, XtInputId *id); static void stdinWriteProc(XtPointer clientData, int *source, XtInputId *id); static void finishCmdExecution(WindowInfo *window, int terminatedOnError); static pid_t forkCommand(Widget parent, const char *command, const char *cmdDir, int *stdinFD, int *stdoutFD, int *stderrFD); static void addOutput(buffer **bufList, buffer *buf); static char *coalesceOutput(buffer **bufList, int *length); static void freeBufList(buffer **bufList); static void removeTrailingNewlines(char *string); static void createOutputDialog(Widget parent, char *text); static void destroyOutDialogCB(Widget w, XtPointer callback, XtPointer closure); static void measureText(char *text, int wrapWidth, int *rows, int *cols, int *wrapped); static void truncateString(char *string, int length); static void bannerTimeoutProc(XtPointer clientData, XtIntervalId *id); static void flushTimeoutProc(XtPointer clientData, XtIntervalId *id); static void safeBufReplace(textBuffer *buf, int *start, int *end, const char *text); static char *shellCommandSubstitutes(const char *inStr, const char *fileStr, const char *lineStr); static int shellSubstituter(char *outStr, const char *inStr, const char *fileStr, const char *lineStr, int outLen, int predictOnly); /* ** Filter the current selection through shell command "command". The selection ** is removed, and replaced by the output from the command execution. Failed ** command status and output to stderr are presented in dialog form. */ void FilterSelection(WindowInfo *window, const char *command, int fromMacro) { int left, right, textLen; char *text; /* Can't do two shell commands at once in the same window */ if (window->shellCmdData != NULL) { XBell(TheDisplay, 0); return; } /* Get the selection and the range in character positions that it occupies. Beep and return if no selection */ text = BufGetSelectionText(window->buffer); if (*text == '\0') { XtFree(text); XBell(TheDisplay, 0); return; } textLen = strlen(text); BufUnsubstituteNullChars(text, window->buffer); left = window->buffer->primary.start; right = window->buffer->primary.end; /* Issue the command and collect its output */ issueCommand(window, command, text, textLen, ACCUMULATE | ERROR_DIALOGS | REPLACE_SELECTION, window->lastFocus, left, right, fromMacro); } /* ** Execute shell command "command", depositing the result at the current ** insert position or in the current selection if the window has a ** selection. */ void ExecShellCommand(WindowInfo *window, const char *command, int fromMacro) { int left, right, flags = 0; char *subsCommand, fullName[MAXPATHLEN]; int pos, line, column; char lineNumber[11]; /* Can't do two shell commands at once in the same window */ if (window->shellCmdData != NULL) { XBell(TheDisplay, 0); return; } /* get the selection or the insert position */ pos = TextGetCursorPos(window->lastFocus); if (GetSimpleSelection(window->buffer, &left, &right)) flags = ACCUMULATE | REPLACE_SELECTION; else left = right = pos; /* Substitute the current file name for % and the current line number for # in the shell command */ strcpy(fullName, window->path); strcat(fullName, window->filename); TextPosToLineAndCol(window->lastFocus, pos, &line, &column); sprintf(lineNumber, "%d", line); subsCommand = shellCommandSubstitutes(command, fullName, lineNumber); if (subsCommand == NULL) { DialogF(DF_ERR, window->shell, 1, "Shell Command", "Shell command is too long due to\n" "filename substitutions with '%%' or\n" "line number substitutions with '#'", "OK"); return; } /* issue the command */ issueCommand(window, subsCommand, NULL, 0, flags, window->lastFocus, left, right, fromMacro); free(subsCommand); } /* ** Execute shell command "command", on input string "input", depositing the ** in a macro string (via a call back to ReturnShellCommandOutput). */ void ShellCmdToMacroString(WindowInfo *window, const char *command, const char *input) { char *inputCopy; /* Make a copy of the input string for issueCommand to hold and free upon completion */ inputCopy = *input == '\0' ? NULL : XtNewString(input); /* fork the command and begin processing input/output */ issueCommand(window, command, inputCopy, strlen(input), ACCUMULATE | OUTPUT_TO_STRING, NULL, 0, 0, True); } /* ** Execute the line of text where the the insertion cursor is positioned ** as a shell command. */ void ExecCursorLine(WindowInfo *window, int fromMacro) { char *cmdText; int left, right, insertPos; char *subsCommand, fullName[MAXPATHLEN]; int pos, line, column; char lineNumber[11]; /* Can't do two shell commands at once in the same window */ if (window->shellCmdData != NULL) { XBell(TheDisplay, 0); return; } /* get all of the text on the line with the insert position */ pos = TextGetCursorPos(window->lastFocus); if (!GetSimpleSelection(window->buffer, &left, &right)) { left = right = pos; left = BufStartOfLine(window->buffer, left); right = BufEndOfLine(window->buffer, right); insertPos = right; } else insertPos = BufEndOfLine(window->buffer, right); cmdText = BufGetRange(window->buffer, left, right); BufUnsubstituteNullChars(cmdText, window->buffer); /* insert a newline after the entire line */ BufInsert(window->buffer, insertPos, "\n"); /* Substitute the current file name for % and the current line number for # in the shell command */ strcpy(fullName, window->path); strcat(fullName, window->filename); TextPosToLineAndCol(window->lastFocus, pos, &line, &column); sprintf(lineNumber, "%d", line); subsCommand = shellCommandSubstitutes(cmdText, fullName, lineNumber); if (subsCommand == NULL) { DialogF(DF_ERR, window->shell, 1, "Shell Command", "Shell command is too long due to\n" "filename substitutions with '%%' or\n" "line number substitutions with '#'", "OK"); return; } /* issue the command */ issueCommand(window, subsCommand, NULL, 0, 0, window->lastFocus, insertPos+1, insertPos+1, fromMacro); free(subsCommand); XtFree(cmdText); } /* ** Do a shell command, with the options allowed to users (input source, ** output destination, save first and load after) in the shell commands ** menu. */ void DoShellMenuCmd(WindowInfo *window, const char *command, int input, int output, int outputReplacesInput, int saveFirst, int loadAfter, int fromMacro) { int flags = 0; char *text; char *subsCommand, fullName[MAXPATHLEN]; int left = 0, right = 0, textLen; int pos, line, column; char lineNumber[11]; WindowInfo *inWindow = window; Widget outWidget; /* Can't do two shell commands at once in the same window */ if (window->shellCmdData != NULL) { XBell(TheDisplay, 0); return; } /* Substitute the current file name for % and the current line number for # in the shell command */ strcpy(fullName, window->path); strcat(fullName, window->filename); pos = TextGetCursorPos(window->lastFocus); TextPosToLineAndCol(window->lastFocus, pos, &line, &column); sprintf(lineNumber, "%d", line); subsCommand = shellCommandSubstitutes(command, fullName, lineNumber); if (subsCommand == NULL) { DialogF(DF_ERR, window->shell, 1, "Shell Command", "Shell command is too long due to\n" "filename substitutions with '%%' or\n" "line number substitutions with '#'", "OK"); return; } /* Get the command input as a text string. If there is input, errors shouldn't be mixed in with output, so set flags to ERROR_DIALOGS */ if (input == FROM_SELECTION) { text = BufGetSelectionText(window->buffer); if (*text == '\0') { XtFree(text); free(subsCommand); XBell(TheDisplay, 0); return; } flags |= ACCUMULATE | ERROR_DIALOGS; } else if (input == FROM_WINDOW) { text = BufGetAll(window->buffer); flags |= ACCUMULATE | ERROR_DIALOGS; } else if (input == FROM_EITHER) { text = BufGetSelectionText(window->buffer); if (*text == '\0') { XtFree(text); text = BufGetAll(window->buffer); } flags |= ACCUMULATE | ERROR_DIALOGS; } else /* FROM_NONE */ text = NULL; /* If the buffer was substituting another character for ascii-nuls, put the nuls back in before exporting the text */ if (text != NULL) { textLen = strlen(text); BufUnsubstituteNullChars(text, window->buffer); } else textLen = 0; /* Assign the output destination. If output is to a new window, create it, and run the command from it instead of the current one, to free the current one from waiting for lengthy execution */ if (output == TO_DIALOG) { outWidget = NULL; flags |= OUTPUT_TO_DIALOG; left = right = 0; } else if (output == TO_NEW_WINDOW) { EditNewFile(GetPrefOpenInTab()?inWindow:NULL, NULL, False, NULL, window->path); outWidget = WindowList->textArea; inWindow = WindowList; left = right = 0; CheckCloseDim(); } else { /* TO_SAME_WINDOW */ outWidget = window->lastFocus; if (outputReplacesInput && input != FROM_NONE) { if (input == FROM_WINDOW) { left = 0; right = window->buffer->length; } else if (input == FROM_SELECTION) { GetSimpleSelection(window->buffer, &left, &right); flags |= ACCUMULATE | REPLACE_SELECTION; } else if (input == FROM_EITHER) { if (GetSimpleSelection(window->buffer, &left, &right)) flags |= ACCUMULATE | REPLACE_SELECTION; else { left = 0; right = window->buffer->length; } } } else { if (GetSimpleSelection(window->buffer, &left, &right)) flags |= ACCUMULATE | REPLACE_SELECTION; else left = right = TextGetCursorPos(window->lastFocus); } } /* If the command requires the file be saved first, save it */ if (saveFirst) { if (!SaveWindow(window)) { if (input != FROM_NONE) XtFree(text); free(subsCommand); return; } } /* If the command requires the file to be reloaded after execution, set a flag for issueCommand to deal with it when execution is complete */ if (loadAfter) flags |= RELOAD_FILE_AFTER; /* issue the command */ issueCommand(inWindow, subsCommand, text, textLen, flags, outWidget, left, right, fromMacro); free(subsCommand); } /* ** Cancel the shell command in progress */ void AbortShellCommand(WindowInfo *window) { shellCmdInfo *cmdData = window->shellCmdData; if (cmdData == NULL) return; kill(- cmdData->childPid, SIGTERM); finishCmdExecution(window, True); } /* ** Issue a shell command and feed it the string "input". Output can be ** directed either to text widget "textW" where it replaces the text between ** the positions "replaceLeft" and "replaceRight", to a separate pop-up dialog ** (OUTPUT_TO_DIALOG), or to a macro-language string (OUTPUT_TO_STRING). If ** "input" is NULL, no input is fed to the process. If an input string is ** provided, it is freed when the command completes. Flags: ** ** ACCUMULATE Causes output from the command to be saved up until ** the command completes. ** ERROR_DIALOGS Presents stderr output separately in popup a dialog, ** and also reports failed exit status as a popup dialog ** including the command output. ** REPLACE_SELECTION Causes output to replace the selection in textW. ** RELOAD_FILE_AFTER Causes the file to be completely reloaded after the ** command completes. ** OUTPUT_TO_DIALOG Send output to a pop-up dialog instead of textW ** OUTPUT_TO_STRING Output to a macro-language string instead of a text ** widget or dialog. ** ** REPLACE_SELECTION, ERROR_DIALOGS, and OUTPUT_TO_STRING can only be used ** along with ACCUMULATE (these operations can't be done incrementally). */ static void issueCommand(WindowInfo *window, const char *command, char *input, int inputLen, int flags, Widget textW, int replaceLeft, int replaceRight, int fromMacro) { int stdinFD, stdoutFD, stderrFD = 0; XtAppContext context = XtWidgetToApplicationContext(window->shell); shellCmdInfo *cmdData; pid_t childPid; /* verify consistency of input parameters */ if ((flags & ERROR_DIALOGS || flags & REPLACE_SELECTION || flags & OUTPUT_TO_STRING) && !(flags & ACCUMULATE)) return; /* a shell command called from a macro must be executed in the same window as the macro, regardless of where the output is directed, so the user can cancel them as a unit */ if (fromMacro) window = MacroRunWindow(); /* put up a watch cursor over the waiting window */ if (!fromMacro) BeginWait(window->shell); /* enable the cancel menu item */ if (!fromMacro) SetSensitive(window, window->cancelShellItem, True); /* fork the subprocess and issue the command */ childPid = forkCommand(window->shell, command, window->path, &stdinFD, &stdoutFD, (flags & ERROR_DIALOGS) ? &stderrFD : NULL); /* set the pipes connected to the process for non-blocking i/o */ if (fcntl(stdinFD, F_SETFL, O_NONBLOCK) < 0) perror("nedit: Internal error (fcntl)"); if (fcntl(stdoutFD, F_SETFL, O_NONBLOCK) < 0) perror("nedit: Internal error (fcntl1)"); if (flags & ERROR_DIALOGS) { if (fcntl(stderrFD, F_SETFL, O_NONBLOCK) < 0) perror("nedit: Internal error (fcntl2)"); } /* if there's nothing to write to the process' stdin, close it now */ if (input == NULL) close(stdinFD); /* Create a data structure for passing process information around amongst the callback routines which will process i/o and completion */ cmdData = (shellCmdInfo *)XtMalloc(sizeof(shellCmdInfo)); window->shellCmdData = cmdData; cmdData->flags = flags; cmdData->stdinFD = stdinFD; cmdData->stdoutFD = stdoutFD; cmdData->stderrFD = stderrFD; cmdData->childPid = childPid; cmdData->outBufs = NULL; cmdData->errBufs = NULL; cmdData->input = input; cmdData->inPtr = input; cmdData->textW = textW; cmdData->bannerIsUp = False; cmdData->fromMacro = fromMacro; cmdData->leftPos = replaceLeft; cmdData->rightPos = replaceRight; cmdData->inLength = inputLen; /* Set up timer proc for putting up banner when process takes too long */ if (fromMacro) cmdData->bannerTimeoutID = 0; else cmdData->bannerTimeoutID = XtAppAddTimeOut(context, BANNER_WAIT_TIME, bannerTimeoutProc, window); /* Set up timer proc for flushing output buffers periodically */ if ((flags & ACCUMULATE) || textW == NULL) cmdData->flushTimeoutID = 0; else cmdData->flushTimeoutID = XtAppAddTimeOut(context, OUTPUT_FLUSH_FREQ, flushTimeoutProc, window); /* set up callbacks for activity on the file descriptors */ cmdData->stdoutInputID = XtAppAddInput(context, stdoutFD, (XtPointer)XtInputReadMask, stdoutReadProc, window); if (input != NULL) cmdData->stdinInputID = XtAppAddInput(context, stdinFD, (XtPointer)XtInputWriteMask, stdinWriteProc, window); else cmdData->stdinInputID = 0; if (flags & ERROR_DIALOGS) cmdData->stderrInputID = XtAppAddInput(context, stderrFD, (XtPointer)XtInputReadMask, stderrReadProc, window); else cmdData->stderrInputID = 0; /* If this was called from a macro, preempt the macro untill shell command completes */ if (fromMacro) PreemptMacro(); } /* ** Called when the shell sub-process stdout stream has data. Reads data into ** the "outBufs" buffer chain in the window->shellCommandData data structure. */ static void stdoutReadProc(XtPointer clientData, int *source, XtInputId *id) { WindowInfo *window = (WindowInfo *)clientData; shellCmdInfo *cmdData = window->shellCmdData; buffer *buf; int nRead; /* read from the process' stdout stream */ buf = (buffer *)XtMalloc(sizeof(buffer)); nRead = read(cmdData->stdoutFD, buf->contents, IO_BUF_SIZE); /* error in read */ if (nRead == -1) { /* error */ if (errno != EWOULDBLOCK && errno != EAGAIN) { perror("nedit: Error reading shell command output"); XtFree((char *)buf); finishCmdExecution(window, True); } return; } /* end of data. If the stderr stream is done too, execution of the shell process is complete, and we can display the results */ if (nRead == 0) { XtFree((char *)buf); XtRemoveInput(cmdData->stdoutInputID); cmdData->stdoutInputID = 0; if (cmdData->stderrInputID == 0) finishCmdExecution(window, False); return; } /* characters were read successfully, add buf to linked list of buffers */ buf->length = nRead; addOutput(&cmdData->outBufs, buf); } /* ** Called when the shell sub-process stderr stream has data. Reads data into ** the "errBufs" buffer chain in the window->shellCommandData data structure. */ static void stderrReadProc(XtPointer clientData, int *source, XtInputId *id) { WindowInfo *window = (WindowInfo *)clientData; shellCmdInfo *cmdData = window->shellCmdData; buffer *buf; int nRead; /* read from the process' stderr stream */ buf = (buffer *)XtMalloc(sizeof(buffer)); nRead = read(cmdData->stderrFD, buf->contents, IO_BUF_SIZE); /* error in read */ if (nRead == -1) { if (errno != EWOULDBLOCK && errno != EAGAIN) { perror("nedit: Error reading shell command error stream"); XtFree((char *)buf); finishCmdExecution(window, True); } return; } /* end of data. If the stdout stream is done too, execution of the shell process is complete, and we can display the results */ if (nRead == 0) { XtFree((char *)buf); XtRemoveInput(cmdData->stderrInputID); cmdData->stderrInputID = 0; if (cmdData->stdoutInputID == 0) finishCmdExecution(window, False); return; } /* characters were read successfully, add buf to linked list of buffers */ buf->length = nRead; addOutput(&cmdData->errBufs, buf); } /* ** Called when the shell sub-process stdin stream is ready for input. Writes ** data from the "input" text string passed to issueCommand. */ static void stdinWriteProc(XtPointer clientData, int *source, XtInputId *id) { WindowInfo *window = (WindowInfo *)clientData; shellCmdInfo *cmdData = window->shellCmdData; int nWritten; nWritten = write(cmdData->stdinFD, cmdData->inPtr, cmdData->inLength); if (nWritten == -1) { if (errno == EPIPE) { /* Just shut off input to broken pipes. User is likely feeding it to a command which does not take input */ XtRemoveInput(cmdData->stdinInputID); cmdData->stdinInputID = 0; close(cmdData->stdinFD); cmdData->inPtr = NULL; } else if (errno != EWOULDBLOCK && errno != EAGAIN) { perror("nedit: Write to shell command failed"); finishCmdExecution(window, True); } } else { cmdData->inPtr += nWritten; cmdData->inLength -= nWritten; if (cmdData->inLength <= 0) { XtRemoveInput(cmdData->stdinInputID); cmdData->stdinInputID = 0; close(cmdData->stdinFD); cmdData->inPtr = NULL; } } } /* ** Timer proc for putting up the "Shell Command in Progress" banner if ** the process is taking too long. */ #define MAX_TIMEOUT_MSG_LEN (MAX_ACCEL_LEN + 60) static void bannerTimeoutProc(XtPointer clientData, XtIntervalId *id) { WindowInfo *window = (WindowInfo *)clientData; shellCmdInfo *cmdData = window->shellCmdData; XmString xmCancel; char* cCancel; char message[MAX_TIMEOUT_MSG_LEN]; cmdData->bannerIsUp = True; /* Extract accelerator text from menu PushButtons */ XtVaGetValues(window->cancelShellItem, XmNacceleratorText, &xmCancel, NULL); /* Translate Motif string to char* */ cCancel = GetXmStringText(xmCancel); /* Free Motif String */ XmStringFree(xmCancel); /* Create message */ if ('\0' == cCancel[0]) { strncpy(message, "Shell Command in Progress", MAX_TIMEOUT_MSG_LEN); message[MAX_TIMEOUT_MSG_LEN - 1] = '\0'; } else { sprintf(message, "Shell Command in Progress -- Press %s to Cancel", cCancel); } /* Free C-string */ XtFree(cCancel); SetModeMessage(window, message); cmdData->bannerTimeoutID = 0; } /* ** Buffer replacement wrapper routine to be used for inserting output from ** a command into the buffer, which takes into account that the buffer may ** have been shrunken by the user (eg, by Undo). If necessary, the starting ** and ending positions (part of the state of the command) are corrected. */ static void safeBufReplace(textBuffer *buf, int *start, int *end, const char *text) { if (*start > buf->length) *start = buf->length; if (*end > buf->length) *end = buf->length; BufReplace(buf, *start, *end, text); } /* ** Timer proc for flushing output buffers periodically when the process ** takes too long. */ static void flushTimeoutProc(XtPointer clientData, XtIntervalId *id) { WindowInfo *window = (WindowInfo *)clientData; shellCmdInfo *cmdData = window->shellCmdData; textBuffer *buf = TextGetBuffer(cmdData->textW); int len; char *outText; /* shouldn't happen, but it would be bad if it did */ if (cmdData->textW == NULL) return; outText = coalesceOutput(&cmdData->outBufs, &len); if (len != 0) { if (BufSubstituteNullChars(outText, len, buf)) { safeBufReplace(buf, &cmdData->leftPos, &cmdData->rightPos, outText); TextSetCursorPos(cmdData->textW, cmdData->leftPos+strlen(outText)); cmdData->leftPos += len; cmdData->rightPos = cmdData->leftPos; } else fprintf(stderr, "nedit: Too much binary data\n"); } XtFree(outText); /* re-establish the timer proc (this routine) to continue processing */ cmdData->flushTimeoutID = XtAppAddTimeOut( XtWidgetToApplicationContext(window->shell), OUTPUT_FLUSH_FREQ, flushTimeoutProc, clientData); } /* ** Clean up after the execution of a shell command sub-process and present ** the output/errors to the user as requested in the initial issueCommand ** call. If "terminatedOnError" is true, don't bother trying to read the ** output, just close the i/o descriptors, free the memory, and restore the ** user interface state. */ static void finishCmdExecution(WindowInfo *window, int terminatedOnError) { shellCmdInfo *cmdData = window->shellCmdData; textBuffer *buf; int status, failure, errorReport, reselectStart, outTextLen, errTextLen; int resp, cancel = False, fromMacro = cmdData->fromMacro; char *outText, *errText = NULL; /* Cancel any pending i/o on the file descriptors */ if (cmdData->stdoutInputID != 0) XtRemoveInput(cmdData->stdoutInputID); if (cmdData->stdinInputID != 0) XtRemoveInput(cmdData->stdinInputID); if (cmdData->stderrInputID != 0) XtRemoveInput(cmdData->stderrInputID); /* Close any file descriptors remaining open */ close(cmdData->stdoutFD); if (cmdData->flags & ERROR_DIALOGS) close(cmdData->stderrFD); if (cmdData->inPtr != NULL) close(cmdData->stdinFD); /* Free the provided input text */ XtFree(cmdData->input); /* Cancel pending timeouts */ if (cmdData->flushTimeoutID != 0) XtRemoveTimeOut(cmdData->flushTimeoutID); if (cmdData->bannerTimeoutID != 0) XtRemoveTimeOut(cmdData->bannerTimeoutID); /* Clean up waiting-for-shell-command-to-complete mode */ if (!cmdData->fromMacro) { EndWait(window->shell); SetSensitive(window, window->cancelShellItem, False); if (cmdData->bannerIsUp) ClearModeMessage(window); } /* If the process was killed or became inaccessable, give up */ if (terminatedOnError) { freeBufList(&cmdData->outBufs); freeBufList(&cmdData->errBufs); waitpid(cmdData->childPid, &status, 0); goto cmdDone; } /* Assemble the output from the process' stderr and stdout streams into null terminated strings, and free the buffer lists used to collect it */ outText = coalesceOutput(&cmdData->outBufs, &outTextLen); if (cmdData->flags & ERROR_DIALOGS) errText = coalesceOutput(&cmdData->errBufs, &errTextLen); /* Wait for the child process to complete and get its return status */ waitpid(cmdData->childPid, &status, 0); /* Present error and stderr-information dialogs. If a command returned error output, or if the process' exit status indicated failure, present the information to the user. */ if (cmdData->flags & ERROR_DIALOGS) { failure = WIFEXITED(status) && WEXITSTATUS(status) != 0; errorReport = *errText != '\0'; if (failure && errorReport) { removeTrailingNewlines(errText); truncateString(errText, DF_MAX_MSG_LENGTH); resp = DialogF(DF_WARN, window->shell, 2, "Warning", "%s", "Cancel", "Proceed", errText); cancel = resp == 1; } else if (failure) { truncateString(outText, DF_MAX_MSG_LENGTH-70); resp = DialogF(DF_WARN, window->shell, 2, "Command Failure", "Command reported failed exit status.\n" "Output from command:\n%s", "Cancel", "Proceed", outText); cancel = resp == 1; } else if (errorReport) { removeTrailingNewlines(errText); truncateString(errText, DF_MAX_MSG_LENGTH); resp = DialogF(DF_INF, window->shell, 2, "Information", "%s", "Proceed", "Cancel", errText); cancel = resp == 2; } XtFree(errText); if (cancel) { XtFree(outText); goto cmdDone; } } /* If output is to a dialog, present the dialog. Otherwise insert the (remaining) output in the text widget as requested, and move the insert point to the end */ if (cmdData->flags & OUTPUT_TO_DIALOG) { removeTrailingNewlines(outText); if (*outText != '\0') createOutputDialog(window->shell, outText); } else if (cmdData->flags & OUTPUT_TO_STRING) { ReturnShellCommandOutput(window,outText, WEXITSTATUS(status)); } else { buf = TextGetBuffer(cmdData->textW); if (!BufSubstituteNullChars(outText, outTextLen, buf)) { fprintf(stderr,"nedit: Too much binary data in shell cmd output\n"); outText[0] = '\0'; } if (cmdData->flags & REPLACE_SELECTION) { reselectStart = buf->primary.rectangular ? -1 : buf->primary.start; BufReplaceSelected(buf, outText); TextSetCursorPos(cmdData->textW, buf->cursorPosHint); if (reselectStart != -1) BufSelect(buf, reselectStart, reselectStart + strlen(outText)); } else { safeBufReplace(buf, &cmdData->leftPos, &cmdData->rightPos, outText); TextSetCursorPos(cmdData->textW, cmdData->leftPos+strlen(outText)); } } /* If the command requires the file to be reloaded afterward, reload it */ if (cmdData->flags & RELOAD_FILE_AFTER) RevertToSaved(window); /* Command is complete, free data structure and continue macro execution */ XtFree(outText); cmdDone: XtFree((char *)cmdData); window->shellCmdData = NULL; if (fromMacro) ResumeMacroExecution(window); } /* ** Fork a subprocess to execute a command, return file descriptors for pipes ** connected to the subprocess' stdin, stdout, and stderr streams. cmdDir ** sets the default directory for the subprocess. If stderrFD is passed as ** NULL, the pipe represented by stdoutFD is connected to both stdin and ** stderr. The function value returns the pid of the new subprocess, or -1 ** if an error occured. */ static pid_t forkCommand(Widget parent, const char *command, const char *cmdDir, int *stdinFD, int *stdoutFD, int *stderrFD) { int childStdoutFD, childStdinFD, childStderrFD, pipeFDs[2]; int dupFD; pid_t childPid; /* Ignore SIGPIPE signals generated when user attempts to provide input for commands which don't take input */ signal(SIGPIPE, SIG_IGN); /* Create pipes to communicate with the sub process. One end of each is returned to the caller, the other half is spliced to stdin, stdout and stderr in the child process */ if (pipe(pipeFDs) != 0) { perror("nedit: Internal error (opening stdout pipe)"); return -1; } *stdoutFD = pipeFDs[0]; childStdoutFD = pipeFDs[1]; if (pipe(pipeFDs) != 0) { perror("nedit: Internal error (opening stdin pipe)"); return -1; } *stdinFD = pipeFDs[1]; childStdinFD = pipeFDs[0]; if (stderrFD == NULL) childStderrFD = childStdoutFD; else { if (pipe(pipeFDs) != 0) { perror("nedit: Internal error (opening stdin pipe)"); return -1; } *stderrFD = pipeFDs[0]; childStderrFD = pipeFDs[1]; } /* Fork the process */ #ifdef VMS childPid = vfork(); #else childPid = fork(); #endif /* ** Child process context (fork returned 0), clean up the ** child ends of the pipes and execute the command */ if (0 == childPid) { /* close the parent end of the pipes in the child process */ close(*stdinFD); close(*stdoutFD); if (stderrFD != NULL) close(*stderrFD); /* close current stdin, stdout, and stderr file descriptors before substituting pipes */ close(fileno(stdin)); close(fileno(stdout)); close(fileno(stderr)); /* duplicate the child ends of the pipes to have the same numbers as stdout & stderr, so it can substitute for stdout & stderr */ dupFD = dup2(childStdinFD, fileno(stdin)); if (dupFD == -1) perror("dup of stdin failed"); dupFD = dup2(childStdoutFD, fileno(stdout)); if (dupFD == -1) perror("dup of stdout failed"); dupFD = dup2(childStderrFD, fileno(stderr)); if (dupFD == -1) perror("dup of stderr failed"); /* now close the original child end of the pipes (we now have the 0, 1 and 2 descriptors in their place) */ close(childStdinFD); close(childStdoutFD); close(childStderrFD); /* make this process the leader of a new process group, so the sub processes can be killed, if necessary, with a killpg call */ #ifndef __EMX__ /* OS/2 doesn't have this */ #ifndef VMS /* VMS doesn't have this */ setsid(); #endif #endif /* change the current working directory to the directory of the current file. */ if (cmdDir[0] != 0) { if (chdir(cmdDir) == -1) { perror("chdir to directory of current file failed"); } } /* execute the command using the shell specified by preferences */ execlp(GetPrefShell(), GetPrefShell(), "-c", command, NULL); /* if we reach here, execlp failed */ fprintf(stderr, "Error starting shell: %s\n", GetPrefShell()); exit(EXIT_FAILURE); } /* Parent process context, check if fork succeeded */ if (childPid == -1) { DialogF(DF_ERR, parent, 1, "Shell Command", "Error starting shell command process\n(fork failed)", "OK"); } /* close the child ends of the pipes */ close(childStdinFD); close(childStdoutFD); if (stderrFD != NULL) close(childStderrFD); return childPid; } /* ** Add a buffer full of output to a buffer list */ static void addOutput(buffer **bufList, buffer *buf) { buf->next = *bufList; *bufList = buf; } /* ** coalesce the contents of a list of buffers into a contiguous memory block, ** freeing the memory occupied by the buffer list. Returns the memory block ** as the function result, and its length as parameter "length". */ static char *coalesceOutput(buffer **bufList, int *outLength) { buffer *buf, *rBufList = NULL; char *outBuf, *outPtr, *p; int i, length = 0; /* find the total length of data read */ for (buf=*bufList; buf!=NULL; buf=buf->next) length += buf->length; /* allocate contiguous memory for returning data */ outBuf = XtMalloc(length+1); /* reverse the buffer list */ while (*bufList != NULL) { buf = *bufList; *bufList = buf->next; buf->next = rBufList; rBufList = buf; } /* copy the buffers into the output buffer */ outPtr = outBuf; for (buf=rBufList; buf!=NULL; buf=buf->next) { p = buf->contents; for (i=0; ilength; i++) *outPtr++ = *p++; } /* terminate with a null */ *outPtr = '\0'; /* free the buffer list */ freeBufList(&rBufList); *outLength = outPtr - outBuf; return outBuf; } static void freeBufList(buffer **bufList) { buffer *buf; while (*bufList != NULL) { buf = *bufList; *bufList = buf->next; XtFree((char *)buf); } } /* ** Remove trailing newlines from a string by substituting nulls */ static void removeTrailingNewlines(char *string) { char *endPtr = &string[strlen(string)-1]; while (endPtr >= string && *endPtr == '\n') *endPtr-- = '\0'; } /* ** Create a dialog for the output of a shell command. The dialog lives until ** the user presses the Dismiss button, and is then destroyed */ static void createOutputDialog(Widget parent, char *text) { Arg al[50]; int ac, rows, cols, hasScrollBar, wrapped; Widget form, textW, button; XmString st1; /* measure the width and height of the text to determine size for dialog */ measureText(text, MAX_OUT_DIALOG_COLS, &rows, &cols, &wrapped); if (rows > MAX_OUT_DIALOG_ROWS) { rows = MAX_OUT_DIALOG_ROWS; hasScrollBar = True; } else hasScrollBar = False; if (cols > MAX_OUT_DIALOG_COLS) cols = MAX_OUT_DIALOG_COLS; if (cols == 0) cols = 1; /* Without completely emulating Motif's wrapping algorithm, we can't be sure that we haven't underestimated the number of lines in case a line has wrapped, so let's assume that some lines could be obscured */ if (wrapped) hasScrollBar = True; ac = 0; form = CreateFormDialog(parent, "shellOutForm", al, ac); ac = 0; XtSetArg(al[ac], XmNlabelString, st1=MKSTRING("OK")); ac++; XtSetArg(al[ac], XmNmarginWidth, BUTTON_WIDTH_MARGIN); ac++; XtSetArg(al[ac], XmNhighlightThickness, 2); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++; button = XmCreatePushButtonGadget(form, "ok", al, ac); XtManageChild(button); XtVaSetValues(form, XmNdefaultButton, button, NULL); XtVaSetValues(form, XmNcancelButton, button, NULL); XmStringFree(st1); XtAddCallback(button, XmNactivateCallback, destroyOutDialogCB, XtParent(form)); ac = 0; XtSetArg(al[ac], XmNrows, rows); ac++; XtSetArg(al[ac], XmNcolumns, cols); ac++; XtSetArg(al[ac], XmNresizeHeight, False); ac++; XtSetArg(al[ac], XmNtraversalOn, True); ac++; XtSetArg(al[ac], XmNwordWrap, True); ac++; XtSetArg(al[ac], XmNscrollHorizontal, False); ac++; XtSetArg(al[ac], XmNscrollVertical, hasScrollBar); ac++; XtSetArg(al[ac], XmNhighlightThickness, 2); ac++; XtSetArg(al[ac], XmNspacing, 0); ac++; XtSetArg(al[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++; XtSetArg(al[ac], XmNeditable, False); ac++; XtSetArg(al[ac], XmNvalue, text); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNbottomWidget, button); ac++; textW = XmCreateScrolledText(form, "outText", al, ac); AddMouseWheelSupport(textW); MakeSingleLineTextW(textW); /* Binds to activate() */ XtManageChild(textW); XtVaSetValues(XtParent(form), XmNtitle, "Output from Command", NULL); ManageDialogCenteredOnPointer(form); #ifdef LESSTIF_VERSION /* * The Lesstif text widget blocks activate() calls in multi-line mode, * so we put the original focus on the Ok button such that the user * can simply hit Return to dismiss the dialog. */ XmProcessTraversal(button, XmTRAVERSE_CURRENT); #else XmProcessTraversal(textW, XmTRAVERSE_CURRENT); #endif } /* ** Dispose of the command output dialog when user presses Dismiss button */ static void destroyOutDialogCB(Widget w, XtPointer callback, XtPointer closure) { XtDestroyWidget((Widget)callback); } /* ** Measure the width and height of a string of text. Assumes 8 character ** tabs. wrapWidth specifies a number of columns at which text wraps. */ static void measureText(char *text, int wrapWidth, int *rows, int *cols, int *wrapped) { int maxCols = 0, line = 1, col = 0, wrapCol; char *c; *wrapped = 0; for (c=text; *c!='\0'; c++) { if (*c=='\n') { line++; col = 0; continue; } if (*c == '\t') { col += 8 - (col % 8); wrapCol = 0; /* Tabs at end of line are not drawn when wrapped */ } else if (*c == ' ') { col++; wrapCol = 0; /* Spaces at end of line are not drawn when wrapped */ } else { col++; wrapCol = 1; } /* Note: there is a small chance that the number of lines is over-estimated when a line ends with a space or a tab (ie, followed by a newline) and that whitespace crosses the boundary, because whitespace at the end of a line does not cause wrapping. Taking this into account is very hard, but an over-estimation is harmless. The worst that can happen is that some extra blank lines are shown at the end of the dialog (in contrast to an under-estimation, which could make the last lines invisible). On the other hand, without emulating Motif's wrapping algorithm completely, we can't be sure that we don't underestimate the number of lines (Motif uses word wrap, and this counting algorithm uses character wrap). Therefore, we remember whether there is a line that has wrapped. In that case we allways install a scroll bar. */ if (col > wrapWidth) { line++; *wrapped = 1; col = wrapCol; } else if (col > maxCols) { maxCols = col; } } *rows = line; *cols = maxCols; } /* ** Truncate a string to a maximum of length characters. If it shortens the ** string, it appends "..." to show that it has been shortened. It assumes ** that the string that it is passed is writeable. */ static void truncateString(char *string, int length) { if ((int)strlen(string) > length) memcpy(&string[length-3], "...", 4); } /* ** Substitute the string fileStr in inStr wherever % appears and ** lineStr in inStr wherever # appears, storing the ** result in outStr. If predictOnly is non-zero, the result string length ** is predicted without creating the string. Returns the length of the result ** string or -1 in case of an error. ** */ static int shellSubstituter(char *outStr, const char *inStr, const char *fileStr, const char *lineStr, int outLen, int predictOnly) { const char *inChar; char *outChar = NULL; int outWritten = 0; int fileLen, lineLen; inChar = inStr; if (!predictOnly) { outChar = outStr; } fileLen = strlen(fileStr); lineLen = strlen(lineStr); while (*inChar != '\0') { if (!predictOnly && outWritten >= outLen) { return(-1); } if (*inChar == '%') { if (*(inChar + 1) == '%') { inChar += 2; if (!predictOnly) { *outChar++ = '%'; } outWritten++; } else { if (!predictOnly) { if (outWritten + fileLen >= outLen) { return(-1); } strncpy(outChar, fileStr, fileLen); outChar += fileLen; } outWritten += fileLen; inChar++; } } else if (*inChar == '#') { if (*(inChar + 1) == '#') { inChar += 2; if (!predictOnly) { *outChar++ = '#'; } outWritten++; } else { if (!predictOnly) { if (outWritten + lineLen >= outLen) { return(-1); } strncpy(outChar, lineStr, lineLen); outChar += lineLen; } outWritten += lineLen; inChar++; } } else { if (!predictOnly) { *outChar++ = *inChar; } inChar++; outWritten++; } } if (!predictOnly) { if (outWritten >= outLen) { return(-1); } *outChar = '\0'; } ++outWritten; return(outWritten); } static char *shellCommandSubstitutes(const char *inStr, const char *fileStr, const char *lineStr) { int cmdLen; char *subsCmdStr = NULL; cmdLen = shellSubstituter(NULL, inStr, fileStr, lineStr, 0, 1); if (cmdLen >= 0) { subsCmdStr = malloc(cmdLen); if (subsCmdStr) { cmdLen = shellSubstituter(subsCmdStr, inStr, fileStr, lineStr, cmdLen, 0); if (cmdLen < 0) { free(subsCmdStr); subsCmdStr = NULL; } } } return(subsCmdStr); } nedit-5.6.orig/source/shell.h0000644000175000017500000000554210144236624014702 0ustar paulpaul/* $Id: shell.h,v 1.9 2004/11/09 21:58:44 yooden Exp $ */ /******************************************************************************* * * * shell.h -- Nirvana Editor Shell Header File * * * * Copyright 2004 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_SHELL_H_INCLUDED #define NEDIT_SHELL_H_INCLUDED #include "nedit.h" /* sources for command input and destinations for command output */ enum inSrcs {FROM_SELECTION, FROM_WINDOW, FROM_EITHER, FROM_NONE}; enum outDests {TO_SAME_WINDOW, TO_NEW_WINDOW, TO_DIALOG}; void FilterSelection(WindowInfo *window, const char *command, int fromMacro); void ExecShellCommand(WindowInfo *window, const char *command, int fromMacro); void ExecCursorLine(WindowInfo *window, int fromMacro); void ShellCmdToMacroString(WindowInfo *window, const char *command, const char *input); void DoShellMenuCmd(WindowInfo *window, const char *command, int input, int output, int outputReplaceInput, int saveFirst, int loadAfter, int fromMacro); void AbortShellCommand(WindowInfo *window); #endif /* NEDIT_SHELL_H_INCLUDED */ nedit-5.6.orig/source/shift.c0000644000175000017500000006035310515126063014701 0ustar paulpaulstatic const char CVSID[] = "$Id: shift.c,v 1.18 2006/10/17 10:10:59 yooden Exp $"; /******************************************************************************* * * * shift.c -- Nirvana Editor built-in filter commands * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * June 18, 1991 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "shift.h" #include "textBuf.h" #include "text.h" #include "nedit.h" #include "window.h" #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif static void shiftRect(WindowInfo *window, int direction, int byTab, int selStart, int selEnd, int rectStart, int rectEnd); static void changeCase(WindowInfo *window, int makeUpper); static char *shiftLineRight(char *line, int lineLen, int tabsAllowed, int tabDist, int nChars); static char *shiftLineLeft(char *line, int lineLen, int tabDist, int nChars); static int findLeftMargin(char *text, int length, int tabDist); static char *fillParagraphs(char *text, int rightMargin, int tabDist, int useTabs, char nullSubsChar, int *filledLen, int alignWithFirst); static char *fillParagraph(char *text, int leftMargin, int firstLineIndent, int rightMargin, int tabDist, int allowTabs, char nullSubsChar, int *filledLen); static char *makeIndentString(int indent, int tabDist, int allowTabs, int *nChars); static int atTabStop(int pos, int tabDist); static int nextTab(int pos, int tabDist); static int countLines(const char *text); static int findParagraphStart(textBuffer *buf, int startPos); static int findParagraphEnd(textBuffer *buf, int startPos); /* ** Shift the selection left or right by a single character, or by one tab stop ** if "byTab" is true. (The length of a tab stop is the size of an emulated ** tab if emulated tabs are turned on, or a hardware tab if not). */ void ShiftSelection(WindowInfo *window, int direction, int byTab) { int selStart, selEnd, isRect, rectStart, rectEnd; int shiftedLen, newEndPos, cursorPos, origLength, emTabDist, shiftDist; char *text, *shiftedText; textBuffer *buf = window->buffer; /* get selection, if no text selected, use current insert position */ if (!BufGetSelectionPos(buf, &selStart, &selEnd, &isRect, &rectStart, &rectEnd)) { cursorPos = TextGetCursorPos(window->lastFocus); selStart = BufStartOfLine(buf, cursorPos); selEnd = BufEndOfLine(buf, cursorPos); if (selEnd < buf->length) selEnd++; BufSelect(buf, selStart, selEnd); isRect = False; text = BufGetRange(buf, selStart, selEnd); } else if (isRect) { cursorPos = TextGetCursorPos(window->lastFocus); origLength = buf->length; shiftRect(window, direction, byTab, selStart, selEnd, rectStart, rectEnd); TextSetCursorPos(window->lastFocus, (cursorPos < (selEnd+selStart)/2) ? selStart : cursorPos + (buf->length - origLength)); return; } else { selStart = BufStartOfLine(buf, selStart); if (selEnd != 0 && BufGetCharacter(buf, selEnd-1) != '\n') { selEnd = BufEndOfLine(buf, selEnd); if (selEnd < buf->length) selEnd++; } BufSelect(buf, selStart, selEnd); text = BufGetRange(buf, selStart, selEnd); } /* shift the text by the appropriate distance */ if (byTab) { XtVaGetValues(window->textArea, textNemulateTabs, &emTabDist, NULL); shiftDist = emTabDist == 0 ? buf->tabDist : emTabDist; } else shiftDist = 1; shiftedText = ShiftText(text, direction, buf->useTabs, buf->tabDist, shiftDist, &shiftedLen); XtFree(text); BufReplaceSelected(buf, shiftedText); XtFree(shiftedText); newEndPos = selStart + shiftedLen; BufSelect(buf, selStart, newEndPos); } static void shiftRect(WindowInfo *window, int direction, int byTab, int selStart, int selEnd, int rectStart, int rectEnd) { int offset, emTabDist; textBuffer *tempBuf, *buf = window->buffer; char *text; /* Make sure selStart and SelEnd refer to whole lines */ selStart = BufStartOfLine(buf, selStart); selEnd = BufEndOfLine(buf, selEnd); /* Calculate the the left/right offset for the new rectangle */ if (byTab) { XtVaGetValues(window->textArea, textNemulateTabs, &emTabDist, NULL); offset = emTabDist == 0 ? buf->tabDist : emTabDist; } else offset = 1; offset *= direction == SHIFT_LEFT ? -1 : 1; if (rectStart + offset < 0) offset = -rectStart; /* Create a temporary buffer for the lines containing the selection, to hide the intermediate steps from the display update routines */ tempBuf = BufCreate(); tempBuf->tabDist = buf->tabDist; tempBuf->useTabs = buf->useTabs; text = BufGetRange(buf, selStart, selEnd); BufSetAll(tempBuf, text); XtFree(text); /* Do the shift in the temporary buffer */ text = BufGetTextInRect(buf, selStart, selEnd, rectStart, rectEnd); BufRemoveRect(tempBuf, 0, selEnd-selStart, rectStart, rectEnd); BufInsertCol(tempBuf, rectStart+offset, 0, text, NULL, NULL); XtFree(text); /* Make the change in the real buffer */ BufReplace(buf, selStart, selEnd, BufAsString(tempBuf)); BufRectSelect(buf, selStart, selStart + tempBuf->length, rectStart+offset, rectEnd+offset); BufFree(tempBuf); } void UpcaseSelection(WindowInfo *window) { changeCase(window, True); } void DowncaseSelection(WindowInfo *window) { changeCase(window, False); } /* ** Capitalize or lowercase the contents of the selection (or of the character ** before the cursor if there is no selection). If "makeUpper" is true, ** change to upper case, otherwise, change to lower case. */ static void changeCase(WindowInfo *window, int makeUpper) { textBuffer *buf = window->buffer; char *text, *c; char oldChar; int cursorPos, start, end, isRect, rectStart, rectEnd; /* Get the selection. Use character before cursor if no selection */ if (!BufGetSelectionPos(buf, &start, &end, &isRect, &rectStart, &rectEnd)) { char bufChar[2] = " "; cursorPos = TextGetCursorPos(window->lastFocus); if (cursorPos == 0) { XBell(TheDisplay, 0); return; } *bufChar = BufGetCharacter(buf, cursorPos-1); *bufChar = makeUpper ? toupper((unsigned char)*bufChar) : tolower((unsigned char)*bufChar); BufReplace(buf, cursorPos-1, cursorPos, bufChar); } else { Boolean modified = False; text = BufGetSelectionText(buf); for (c = text; *c != '\0'; c++) { oldChar = *c; *c = makeUpper ? toupper((unsigned char)*c) : tolower((unsigned char)*c); if (*c != oldChar) { modified = True; } } if (modified) { BufReplaceSelected(buf, text); } XtFree(text); if (isRect) BufRectSelect(buf, start, end, rectStart, rectEnd); else BufSelect(buf, start, end); } } void FillSelection(WindowInfo *window) { textBuffer *buf = window->buffer; char *text, *filledText; int left, right, nCols, len, isRect, rectStart, rectEnd; int rightMargin, wrapMargin; int insertPos = TextGetCursorPos(window->lastFocus); int hasSelection = window->buffer->primary.selected; /* Find the range of characters and get the text to fill. If there is a selection, use it but extend non-rectangular selections to encompass whole lines. If there is no selection, find the paragraph containing the insertion cursor */ if (!BufGetSelectionPos(buf, &left, &right, &isRect, &rectStart, &rectEnd)) { left = findParagraphStart(buf, insertPos); right = findParagraphEnd(buf, insertPos); if (left == right) { XBell(TheDisplay, 0); return; } text = BufGetRange(buf, left, right); } else if (isRect) { left = BufStartOfLine(buf, left); right = BufEndOfLine(buf, right); text = BufGetTextInRect(buf, left, right, rectStart, INT_MAX); } else { left = BufStartOfLine(buf, left); if (right != 0 && BufGetCharacter(buf, right-1) != '\n') { right = BufEndOfLine(buf, right); if (right < buf->length) right++; } BufSelect(buf, left, right); text = BufGetRange(buf, left, right); } /* Find right margin either as specified in the rectangular selection, or by measuring the text and querying the window's wrap margin (or width) */ if (hasSelection && isRect) { rightMargin = rectEnd - rectStart; } else { XtVaGetValues(window->textArea, textNcolumns, &nCols, textNwrapMargin, &wrapMargin, NULL); rightMargin = (wrapMargin == 0 ? nCols : wrapMargin); } /* Fill the text */ filledText = fillParagraphs(text, rightMargin, buf->tabDist, buf->useTabs, buf->nullSubsChar, &len, False); XtFree(text); /* Replace the text in the window */ if (hasSelection && isRect) { BufReplaceRect(buf, left, right, rectStart, INT_MAX, filledText); BufRectSelect(buf, left, BufEndOfLine(buf, BufCountForwardNLines(buf, left, countLines(filledText)-1)), rectStart, rectEnd); } else { BufReplace(buf, left, right, filledText); if (hasSelection) BufSelect(buf, left, left + len); } XtFree(filledText); /* Find a reasonable cursor position. Usually insertPos is best, but if the text was indented, positions can shift */ if (hasSelection && isRect) TextSetCursorPos(window->lastFocus, buf->cursorPosHint); else TextSetCursorPos(window->lastFocus, insertPos < left ? left : (insertPos > left + len ? left + len : insertPos)); } /* ** shift lines left and right in a multi-line text string. Returns the ** shifted text in memory that must be freed by the caller with XtFree. */ char *ShiftText(char *text, int direction, int tabsAllowed, int tabDist, int nChars, int *newLen) { char *shiftedText, *shiftedLine; char *textPtr, *lineStartPtr, *shiftedPtr; int bufLen; /* ** Allocate memory for shifted string. Shift left adds a maximum of ** tabDist-2 characters per line (remove one tab, add tabDist-1 spaces). ** Shift right adds a maximum of nChars character per line. */ if (direction == SHIFT_RIGHT) bufLen = strlen(text) + countLines(text) * nChars; else bufLen = strlen(text) + countLines(text) * tabDist; shiftedText = (char *)XtMalloc(bufLen + 1); /* ** break into lines and call shiftLine(Left/Right) on each */ lineStartPtr = text; textPtr = text; shiftedPtr = shiftedText; while (TRUE) { if (*textPtr=='\n' || *textPtr=='\0') { shiftedLine = (direction == SHIFT_RIGHT) ? shiftLineRight(lineStartPtr, textPtr-lineStartPtr, tabsAllowed, tabDist, nChars) : shiftLineLeft(lineStartPtr, textPtr-lineStartPtr, tabDist, nChars); strcpy(shiftedPtr, shiftedLine); shiftedPtr += strlen(shiftedLine); XtFree(shiftedLine); if (*textPtr == '\0') { /* terminate string & exit loop at end of text */ *shiftedPtr = '\0'; break; } else { /* move the newline from text to shifted text */ *shiftedPtr++ = *textPtr++; } /* start line over */ lineStartPtr = textPtr; } else textPtr++; } *newLen = shiftedPtr - shiftedText; return shiftedText; } static char *shiftLineRight(char *line, int lineLen, int tabsAllowed, int tabDist, int nChars) { char *lineOut; char *lineInPtr, *lineOutPtr; int whiteWidth, i; lineInPtr = line; lineOut = XtMalloc(lineLen + nChars + 1); lineOutPtr = lineOut; whiteWidth = 0; while (TRUE) { if (*lineInPtr == '\0' || (lineInPtr - line) >= lineLen) { /* nothing on line, wipe it out */ *lineOut = '\0'; return lineOut; } else if (*lineInPtr == ' ') { /* white space continues with tab, advance to next tab stop */ whiteWidth++; *lineOutPtr++ = *lineInPtr++; } else if (*lineInPtr == '\t') { /* white space continues with tab, advance to next tab stop */ whiteWidth = nextTab(whiteWidth, tabDist); *lineOutPtr++ = *lineInPtr++; } else { /* end of white space, add nChars of space */ for (i=0; i= lineLen) { /* nothing on line, wipe it out */ *lineOut = '\0'; return lineOut; } else if (*lineInPtr == ' ') { /* white space continues with space, advance one character */ whiteWidth++; *lineOutPtr++ = *lineInPtr++; } else if (*lineInPtr == '\t') { /* white space continues with tab, advance to next tab stop */ /* save the position, though, in case we need to remove the tab */ lastWhiteWidth = whiteWidth; whiteWidth = nextTab(whiteWidth, tabDist); *lineOutPtr++ = *lineInPtr++; } else { /* end of white space, remove nChars characters */ for (i=1; i<=nChars; i++) { if (lineOutPtr > lineOut) { if (*(lineOutPtr-1) == ' ') { /* end of white space is a space, just remove it */ lineOutPtr--; } else { /* end of white space is a tab, remove it and add back spaces */ lineOutPtr--; whiteGoal = whiteWidth - i; whiteWidth = lastWhiteWidth; while (whiteWidth < whiteGoal) { *lineOutPtr++ = ' '; whiteWidth++; } } } } /* move remainder of line */ while (*lineInPtr!='\0' && (lineInPtr - line) < lineLen) *lineOutPtr++ = *lineInPtr++; /* add a null */ *lineOutPtr = '\0'; return lineOut; } } } static int atTabStop(int pos, int tabDist) { return (pos%tabDist == 0); } static int nextTab(int pos, int tabDist) { return (pos/tabDist)*tabDist + tabDist; } static int countLines(const char *text) { int count = 1; while(*text != '\0') { if (*text++ == '\n') { count++; } } return count; } /* ** Find the implied left margin of a text string (the number of columns to the ** first non-whitespace character on any line) up to either the terminating ** null character at the end of the string, or "length" characters, whever ** comes first. */ static int findLeftMargin(char *text, int length, int tabDist) { char *c; int col = 0, leftMargin = INT_MAX; int inMargin = True; for (c=text; *c!='\0' && c-textlength) { ch = BufGetCharacter(buf, paraStart); if (ch != ' ' && ch != '\t' && ch != '\n') break; paraStart++; } if (paraStart >= buf->length) break; paraStart = BufStartOfLine(buf, paraStart); /* Find the end of the paragraph */ paraEnd = findParagraphEnd(buf, paraStart); /* Operate on either the one paragraph, or to make them all identical, do all of them together (fill paragraph can format all the paragraphs it finds with identical specs if it gets passed more than one) */ fillEnd = alignWithFirst ? buf->length : paraEnd; /* Get the paragraph in a text string (or all of the paragraphs if we're making them all the same) */ paraText = BufGetRange(buf, paraStart, fillEnd); /* Find separate left margins for the first and for the first line of the paragraph, and for rest of the remainder of the paragraph */ for (c=paraText ; *c!='\0' && *c!='\n'; c++); firstLineLen = c - paraText; secondLineStart = *c == '\0' ? paraText : c + 1; firstLineIndent = findLeftMargin(paraText, firstLineLen, tabDist); leftMargin = findLeftMargin(secondLineStart, paraEnd - paraStart - (secondLineStart - paraText), tabDist); /* Fill the paragraph */ filledText = fillParagraph(paraText, leftMargin, firstLineIndent, rightMargin, tabDist, useTabs, nullSubsChar, &len); XtFree(paraText); /* Replace it in the buffer */ BufReplace(buf, paraStart, fillEnd, filledText); XtFree(filledText); /* move on to the next paragraph */ paraStart += len; } /* Free the buffer and return its contents */ filledText = BufGetAll(buf); *filledLen = buf->length; BufFree(buf); return filledText; } /* ** Trim leading space, and arrange text to fill between leftMargin and ** rightMargin (except for the first line which fills from firstLineIndent), ** re-creating whitespace to the left of the text using tabs (if allowTabs is ** True) calculated using tabDist, and spaces. Returns a newly allocated ** string as the function result, and the length of the new string in filledLen. */ static char *fillParagraph(char *text, int leftMargin, int firstLineIndent, int rightMargin, int tabDist, int allowTabs, char nullSubsChar, int *filledLen) { char *cleanedText, *outText, *indentString, *leadIndentStr, *outPtr, *c, *b; int col, cleanedLen, indentLen, leadIndentLen, nLines = 1; int inWhitespace, inMargin; /* remove leading spaces, convert newlines to spaces */ cleanedText = XtMalloc(strlen(text)+1); outPtr = cleanedText; inMargin = True; for (c=text; *c!='\0'; c++) { if (*c == '\t' || *c == ' ') { if (!inMargin) *outPtr++ = *c; } else if (*c == '\n') { if (inMargin) { /* a newline before any text separates paragraphs, so leave it in, back up, and convert the previous space back to \n */ if (outPtr > cleanedText && *(outPtr-1) == ' ') *(outPtr-1) = '\n'; *outPtr++ = '\n'; nLines +=2; } else *outPtr++ = ' '; inMargin = True; } else { *outPtr++ = *c; inMargin = False; } } cleanedLen = outPtr - cleanedText; *outPtr = '\0'; /* Put back newlines breaking text at word boundaries within the margins. Algorithm: scan through characters, counting columns, and when the margin width is exceeded, search backward for beginning of the word and convert the last whitespace character into a newline */ col = firstLineIndent; for (c=cleanedText; *c!='\0'; c++) { if (*c == '\n') col = leftMargin; else col += BufCharWidth(*c, col, tabDist, nullSubsChar); if (col-1 > rightMargin) { inWhitespace = True; for (b=c; b>=cleanedText && *b!='\n'; b--) { if (*b == '\t' || *b == ' ') { if (!inWhitespace) { *b = '\n'; c = b; col = leftMargin; nLines++; break; } } else inWhitespace = False; } } } nLines++; /* produce a string to prepend to lines to indent them to the left margin */ leadIndentStr = makeIndentString(firstLineIndent, tabDist, allowTabs, &leadIndentLen); indentString = makeIndentString(leftMargin, tabDist, allowTabs, &indentLen); /* allocate memory for the finished string */ outText = XtMalloc(sizeof(char) * (cleanedLen + leadIndentLen + indentLen * (nLines-1) + 1)); outPtr = outText; /* prepend the indent string to each line of the filled text */ strncpy(outPtr, leadIndentStr, leadIndentLen); outPtr += leadIndentLen; for (c=cleanedText; *c!='\0'; c++) { *outPtr++ = *c; if (*c == '\n') { strncpy(outPtr, indentString, indentLen); outPtr += indentLen; } } /* convert any trailing space to newline. Add terminating null */ if (*(outPtr-1) == ' ') *(outPtr-1) = '\n'; *outPtr = '\0'; /* clean up, return result */ XtFree(cleanedText); XtFree(leadIndentStr); XtFree(indentString); *filledLen = outPtr - outText; return outText; } static char *makeIndentString(int indent, int tabDist, int allowTabs, int *nChars) { char *indentString, *outPtr; int i; outPtr = indentString = XtMalloc(sizeof(char) * indent + 1); if (allowTabs) { for (i=0; ilength) { c = BufGetCharacter(buf, pos); if (c == '\n') break; if (strchr(whiteChars, c) != NULL) pos++; else pos = BufEndOfLine(buf, pos)+1; } return pos < buf->length ? pos : buf->length; } static int findParagraphStart(textBuffer *buf, int startPos) { char c; int pos, parStart; static char whiteChars[] = " \t"; if (startPos == 0) return 0; parStart = BufStartOfLine(buf, startPos); pos = parStart - 2; while (pos > 0) { c = BufGetCharacter(buf, pos); if (c == '\n') break; if (strchr(whiteChars, c) != NULL) pos--; else { parStart = BufStartOfLine(buf, pos); pos = parStart - 2; } } return parStart > 0 ? parStart : 0; } nedit-5.6.orig/source/shift.h0000644000175000017500000000476110144236624014712 0ustar paulpaul/* $Id: shift.h,v 1.6 2004/11/09 21:58:44 yooden Exp $ */ /******************************************************************************* * * * shift.h -- Nirvana Editor Shift Header File * * * * Copyright 2002 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_SHIFT_H_INCLUDED #define NEDIT_SHIFT_H_INCLUDED #include "nedit.h" enum ShiftDirection {SHIFT_LEFT, SHIFT_RIGHT}; void ShiftSelection(WindowInfo *window, int direction, int byTab); void UpcaseSelection(WindowInfo *window); void DowncaseSelection(WindowInfo *window); void FillSelection(WindowInfo *window); char *ShiftText(char *text, int direction, int tabsAllowed, int tabDist, int nChars, int *newLen); #endif /* NEDIT_SHIFT_H_INCLUDED */ nedit-5.6.orig/source/smartIndent.c0000644000175000017500000022203611110456100016040 0ustar paulpaulstatic const char CVSID[] = "$Id: smartIndent.c,v 1.40 2006/12/02 10:27:06 yooden Exp $"; /******************************************************************************* * * * smartIndent.c -- Maintain, and allow user to edit, macros for smart indent * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July, 1997 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "smartIndent.h" #include "textBuf.h" #include "nedit.h" #include "text.h" #include "preferences.h" #include "interpret.h" #include "macro.h" #include "window.h" #include "parse.h" #include "shift.h" #include "help.h" #include "../util/DialogF.h" #include "../util/misc.h" #include #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #include #include #include #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif static char MacroEndBoundary[] = "--End-of-Macro--"; typedef struct { char *lmName; char *initMacro; char *newlineMacro; char *modMacro; } smartIndentRec; typedef struct { Program *newlineMacro; int inNewLineMacro; Program *modMacro; int inModMacro; } windowSmartIndentData; /* Smart indent macros dialog information */ static struct { Widget shell; Widget lmOptMenu; Widget lmPulldown; Widget initMacro; Widget newlineMacro; Widget modMacro; char *langModeName; } SmartIndentDialog = {NULL,NULL,NULL,NULL,NULL,NULL,NULL}; /* Common smart indent macros dialog information */ static struct { Widget shell; Widget text; } CommonDialog = {NULL,NULL}; static int NSmartIndentSpecs = 0; static smartIndentRec *SmartIndentSpecs[MAX_LANGUAGE_MODES]; static char *CommonMacros = NULL; static void executeNewlineMacro(WindowInfo *window,smartIndentCBStruct *cbInfo); static void executeModMacro(WindowInfo *window,smartIndentCBStruct *cbInfo); static void insertShiftedMacro(textBuffer *buf, char *macro); static int isDefaultIndentSpec(smartIndentRec *indentSpec); static smartIndentRec *findIndentSpec(const char *modeName); static char *ensureNewline(char *string); static int loadDefaultIndentSpec(char *lmName); static int siParseError(char *stringStart, char *stoppedAt, char *message); static void destroyCB(Widget w, XtPointer clientData, XtPointer callData); static void langModeCB(Widget w, XtPointer clientData, XtPointer callData); static void commonDialogCB(Widget w, XtPointer clientData, XtPointer callData); static void lmDialogCB(Widget w, XtPointer clientData, XtPointer callData); static void okCB(Widget w, XtPointer clientData, XtPointer callData); static void applyCB(Widget w, XtPointer clientData, XtPointer callData); static void checkCB(Widget w, XtPointer clientData, XtPointer callData); static void restoreCB(Widget w, XtPointer clientData, XtPointer callData); static void deleteCB(Widget w, XtPointer clientData, XtPointer callData); static void closeCB(Widget w, XtPointer clientData, XtPointer callData); static void helpCB(Widget w, XtPointer clientData, XtPointer callData); static int checkSmartIndentDialogData(void); static smartIndentRec *getSmartIndentDialogData(void); static void setSmartIndentDialogData(smartIndentRec *is); static void comDestroyCB(Widget w, XtPointer clientData, XtPointer callData); static void comOKCB(Widget w, XtPointer clientData, XtPointer callData); static void comApplyCB(Widget w, XtPointer clientData, XtPointer callData); static void comCheckCB(Widget w, XtPointer clientData, XtPointer callData); static void comRestoreCB(Widget w, XtPointer clientData, XtPointer callData); static void comCloseCB(Widget w, XtPointer clientData, XtPointer callData); static int updateSmartIndentCommonData(void); static int checkSmartIndentCommonDialogData(void); static int updateSmartIndentData(void); static char *readSIMacro(char **inPtr); static smartIndentRec *copyIndentSpec(smartIndentRec *is); static void freeIndentSpec(smartIndentRec *is); static int indentSpecsDiffer(smartIndentRec *is1, smartIndentRec *is2); #define N_DEFAULT_INDENT_SPECS 4 static smartIndentRec DefaultIndentSpecs[N_DEFAULT_INDENT_SPECS] = { {"C", "# C Macros and tuning parameters are shared with C++, and are declared\n\ # in the common section. Press Common / Shared Initialization above.\n", "return cFindSmartIndentDist($1)\n", "if ($2 == \"}\" || $2 == \"{\" || $2 == \"#\")\n\ cBraceOrPound($1, $2)\n"}, {"C++", "# C++ Macros and tuning parameters are shared with C, and are declared\n\ # in the common section. Press Common / Shared Initialization above.\n", "return cFindSmartIndentDist($1)\n", "if ($2 == \"}\" || $2 == \"{\" || $2 == \"#\")\n\ cBraceOrPound($1, $2)\n"}, {"Python", "# Number of characters in a normal indent level. May be a number, or the\n\ # string \"default\", meaning, guess the value from the current tab settings.\n\ $pyIndentDist = \"default\"\n", "if (get_range($1-1, $1) != \":\")\n\ return -1\n\ return measureIndent($1) + defaultIndent($pyIndentDist)\n", NULL}, {"Matlab", "# Number of spaces to indent \"case\" statements\n\ $caseDepth = 2\n\ define matlabNewlineMacro\n\ {\n\ if ($em_tab_dist == -1)\n\ tabsize = $tab_dist\n\ else\n\ tabsize = $em_tab_dist\n\ startLine = startOfLine($1)\n\ indentLevel = measureIndent($1)\n\ \n\ # If this line is continued on next, return default:\n\ lastLine = get_range(startLine, $1)\n\ if (search_string(lastLine, \"...\", 0) != -1) {\n\ if ($n_args == 2)\n\ return matlabNewlineMacro(startLine - 1, 1)\n\ else {\n\ return -1\n\ }\n\ }\n\ \n\ # Correct the indentLevel if this was a continued line.\n\ while (startLine > 1)\n\ {\n\ endLine = startLine - 1\n\ startLine = startOfLine(endLine)\n\ lastLine = get_range(startLine, endLine)\n\ # No \"...\" means we've found the root\n\ if (search_string(lastLine, \"...\", 0) == -1) {\n\ startLine = endLine + 1\n\ break\n\ }\n\ }\n\ indentLevel = measureIndent(startLine)\n\ \n\ # Get the first word of the indentLevel line\n\ FWend = search(\">|\\n\", startLine + indentLevel, \"regex\")\n\ # This search fails on EOF\n\ if (FWend == -1)\n\ FWend = $1\n\ \n\ firstWord = get_range(startLine + indentLevel, FWend)\n\ \n\ # How shall we change the indent level based on the first word?\n\ if (search_string(firstWord, \\\n\ \"|||||\", 0, \"regex\") == 0) {\n\ return indentLevel + tabsize\n\ }\n\ else if ((firstWord == \"end\") || (search_string(firstWord, \\\n\ \"||||\", 0, \"regex\") == 0)) {\n\ # Get the last indent level \n\ if (startLine > 0) # avoid infinite loop\n\ last_indent = matlabNewlineMacro(startLine - 1, 1)\n\ else\n\ last_indent = indentLevel\n\ \n\ # Re-indent this line\n\ if ($n_args == 1) {\n\ if (firstWord == \"case\" || firstWord == \"otherwise\")\n\ replace_range(startLine, startLine + indentLevel, \\\n\ makeIndentString(last_indent - tabsize + $caseDepth))\n\ else\n\ replace_range(startLine, startLine + indentLevel, \\\n\ makeIndentString(last_indent - tabsize))\n\ }\n\ \n\ if (firstWord == \"end\") {\n\ return max(last_indent - tabsize, 0)\n\ }\n\ else {\n\ return last_indent\n\ }\n\ } \n\ else {\n\ return indentLevel\n\ }\n\ }\n\ ", "return matlabNewlineMacro($1)\n", NULL} }; static char DefaultCommonMacros[] = "#\n\ # C/C++ Style/tuning parameters\n\ #\n\ \n\ # Number of characters in a normal indent level. May be a number, or the\n\ # string \"default\", meaning, guess the value from the current tab settings.\n\ $cIndentDist = \"default\"\n\ \n\ # Number of characters in a line continuation. May be a number or the\n\ # string \"default\", meaning, guess the value from the current tab settings.\n\ $cContinuationIndent = \"default\"\n\ \n\ # How far back from the current position to search for an anchoring position\n\ # on which to base indent. When no reliable indicators of proper indent level\n\ # can be found within the requested distance, reverts to plain auto indent.\n\ $cMaxSearchBackLines = 10\n\ \n\ #\n\ # Find the start of the line containing position $1\n\ #\n\ define startOfLine {\n\ \n\ for (i=$1-1; ; i--) {\n\ if (i <= 0)\n\ return 0\n\ if (get_character(i) == \"\\n\")\n\ return i + 1\n\ }\n\ }\n\ \n\ #\n\ # Find the indent level of the line containing character position $1\n\ #\n\ define measureIndent {\n\ \n\ # measure the indentation to the first non-white character on the line\n\ indent = 0\n\ for (i=startOfLine($1); i < $text_length; i++) {\n\ c = get_character(i)\n\ if (c != \" \" && c != \"\\t\")\n\ break\n\ if (c == \"\\t\")\n\ indent += $tab_dist - (indent % $tab_dist)\n\ else\n\ indent++\n\ }\n\ return indent\n\ }\n\ \n\ #\n\ # Make a string to produce an indent of $1 characters\n\ #\n\ define makeIndentString {\n\ \n\ if ($use_tabs) {\n\ nTabs = $1 / $tab_dist\n\ nSpaces = $1 % $tab_dist\n\ } else {\n\ nTabs = 0\n\ nSpaces = $1\n\ }\n\ indentString = \"\"\n\ for (i=0; i= $2)\n\ return i\n\ if (get_character(i+1) == \"*\") {\n\ for (i=i+1; ; i++) {\n\ if (i+1 >= $2)\n\ return -1\n\ if (get_character(i) == \"*\" && get_character(i+1) == \"/\") {\n\ i++\n\ break\n\ }\n\ }\n\ } else if (get_character(i+1) == \"/\") {\n\ for (i=i+1; i<$2; i++) {\n\ if (get_character(i) == \"\\n\") {\n\ if (!$3)\n\ return i\n\ break\n\ }\n\ }\n\ }\n\ } else if (c == \"#\" && $3) {\n\ for (i=i+1; ; i++) {\n\ if (i >= $2) {\n\ if (get_character(i-1) == \"\\\\\")\n\ return -1\n\ else\n\ break\n\ }\n\ if (get_character(i) == \"\\n\" && get_character(i-1) != \"\\\\\")\n\ break\n\ }\n\ } else if (!(c == \" \" || c == \"\\t\" || ($3 && c==\"\\n\")))\n\ return i\n\ }\n\ return $2\n\ }\n\ \n\ #\n\ # Search backward for an anchor point: a line ending brace, or semicolon\n\ # or case statement, followed (ignoring blank lines and comments) by what we\n\ # assume is a properly indented line, a brace on a line by itself, or a case\n\ # statement. Returns the position of the first non-white, non comment\n\ # character on the line. returns -1 if an anchor position can't be found\n\ # before $cMaxSearchBackLines.\n\ #\n\ define cFindIndentAnchorPoint {\n\ \n\ nLines = 0\n\ anchorPos = $1\n\ for (i=$1-1; i>0; i--) {\n\ c = get_character(i)\n\ if (c == \";\" || c == \"{\" || c == \"}\" || c == \":\") {\n\ \n\ # Verify that it's line ending\n\ lineEnd = cSkipBlankSpace(i+1, $1, 0)\n\ if (lineEnd == -1 || \\\n\ (lineEnd != $text_length && get_character(lineEnd) != \"\\n\"))\n\ continue\n\ \n\ # if it's a colon, it's only meaningful if \"case\" begins the line\n\ if (c == \":\") {\n\ lineStart = startOfLine(i)\n\ caseStart = cSkipBlankSpace(lineStart, lineEnd, 0)\n\ if (get_range(caseStart, caseStart+4) != \"case\")\n\ continue\n\ delim = get_character(caseStart+4)\n\ if (delim!=\" \" && delim!=\"\\t\" && delim!=\"(\" && delim!=\":\")\n\ continue\n\ isCase = 1\n\ } else\n\ isCase = 0\n\ \n\ # Move forward past blank lines and comment lines to find\n\ # non-blank, non-comment line-start\n\ anchorPos = cSkipBlankSpace(lineEnd, $1, 1)\n\ \n\ # Accept if it's before the requested position, otherwise\n\ # continue further back in the file and try again\n\ if (anchorPos != -1 && anchorPos < $1)\n\ break\n\ \n\ # A case statement by itself is an acceptable anchor\n\ if (isCase)\n\ return caseStart\n\ \n\ # A brace on a line by itself is an acceptable anchor, even\n\ # if it doesn't follow a semicolon or another brace\n\ if (c == \"{\" || c == \"}\") {\n\ for (j = i-1; ; j--) {\n\ if (j == 0)\n\ return i\n\ ch = get_character(j)\n\ if (ch == \"\\n\")\n\ return i\n\ if (ch != \"\\t\" && ch != \" \")\n\ break\n\ }\n\ }\n\ \n\ } else if (c == \"\\n\")\n\ if (++nLines > $cMaxSearchBackLines)\n\ return -1\n\ }\n\ if (i <= 0)\n\ return -1\n\ return anchorPos\n\ }\n\ \n\ #\n\ # adjust the indent on a line about to recive either a right or left brace\n\ # or pound (#) character ($2) following position $1\n\ #\n\ define cBraceOrPound {\n\ \n\ # Find start of the line, and make sure there's nothing but white-space\n\ # before the character. If there's anything before it, do nothing\n\ for (i=$1-1; ; i--) {\n\ if (i < 0) {\n\ lineStart = 0\n\ break\n\ }\n\ c = get_character(i)\n\ if (c == \"\\n\") {\n\ lineStart = i + 1\n\ break\n\ }\n\ if (c != \" \" && c != \"\\t\")\n\ return\n\ }\n\ \n\ # If the character was a pound, drag it all the way to the left margin\n\ if ($2 == \"#\") {\n\ replace_range(lineStart, $1, \"\")\n\ return\n\ }\n\ \n\ # Find the position on which to base the indent\n\ indent = cFindSmartIndentDist($1 - 1, \"noContinue\")\n\ if (indent == -1)\n\ return\n\ \n\ # Adjust the indent if it's a right brace (left needs no adjustment)\n\ if ($2 == \"}\") {\n\ indent -= defaultIndent($cIndentDist)\n\ if (indent < 0)\n\ indent = 0\n\ }\n\ \n\ # Replace the current indent with the new indent string\n\ insertStr = makeIndentString(indent)\n\ replace_range(lineStart, $1, insertStr)\n\ }\n\ \n\ #\n\ # Find Smart Indent Distance for a newline character inserted at $1,\n\ # or return -1 to give up. Adding the optional argument \"noContinue\"\n\ # will stop the routine from inserting line continuation indents\n\ #\n\ define cFindSmartIndentDist {\n\ \n\ # Find a known good indent to base the new indent upon\n\ anchorPos = cFindIndentAnchorPoint($1)\n\ if (anchorPos == -1)\n\ return -1\n\ \n\ # Find the indentation of that line\n\ anchorIndent = measureIndent(anchorPos)\n\ \n\ # Look for special keywords which affect indent (for, if, else while, do)\n\ # and modify the continuation indent distance to the normal indent\n\ # distance when a completed statement of this type occupies the line.\n\ if ($n_args >= 2 && $2 == \"noContinue\") {\n\ continueIndent = 0\n\ $allowSemi = 0\n\ } else\n\ continueIndent = cCalcContinueIndent(anchorPos, $1)\n\ \n\ # Move forward from anchor point, ignoring comments and blank lines,\n\ # remembering the last non-white, non-comment character. If $1 is\n\ # in the middle of a comment, give up\n\ lastChar = get_character(anchorPos)\n\ if (anchorPos < $1) {\n\ for (i=anchorPos;;) {\n\ i = cSkipBlankSpace(i, $1, 1)\n\ if (i == -1)\n\ return -1\n\ if (i >= $1)\n\ break\n\ lastChar = get_character(i++)\n\ }\n\ }\n\ \n\ # Return the new indent based on the type of the last character.\n\ # In a for stmt, however, last character may be a semicolon and not\n\ # signal the end of the statement\n\ if (lastChar == \"{\")\n\ return anchorIndent + defaultIndent($cIndentDist)\n\ else if (lastChar == \"}\")\n\ return anchorIndent\n\ else if (lastChar == \";\") {\n\ if ($allowSemi)\n\ return anchorIndent + continueIndent\n\ else\n\ return anchorIndent\n\ } else if (lastChar == \":\" && get_range(anchorPos, anchorPos+4) == \"case\")\n\ return anchorIndent + defaultIndent($cIndentDist)\n\ return anchorIndent + continueIndent\n\ }\n\ \n\ #\n\ # Calculate the continuation indent distance for statements not ending in\n\ # semicolons or braces. This is not necessarily $continueIndent. It may\n\ # be adjusted if the statement contains if, while, for, or else.\n\ #\n\ # As a side effect, also return $allowSemi to help distinguish statements\n\ # which might contain an embedded semicolon, which should not be interpreted\n\ # as an end of statement character.\n\ #\n\ define cCalcContinueIndent {\n\ \n\ anchorPos = $1\n\ maxPos = $2\n\ \n\ # Figure out if the anchor is on a keyword which changes indent. A special\n\ # case is made for elses nested in after braces\n\ anchorIsFor = 0\n\ $allowSemi = 0\n\ if (get_character(anchorPos) == \"}\") {\n\ for (i=anchorPos+1; ilanguageMode); if (modeName == NULL) { if (warn) { DialogF(DF_WARN, window->shell, 1, "Smart Indent", "No language-specific mode has been set for this file.\n\n" "To use smart indent in this window, please select a\n" "language from the Preferences -> Language Modes menu.", "OK"); } return; } /* Look up the appropriate smart-indent macros for the language */ indentMacros = findIndentSpec(modeName); if (indentMacros == NULL) { if (warn) { DialogF(DF_WARN, window->shell, 1, "Smart Indent", "Smart indent is not available in languagemode\n%s.\n\n" "You can create new smart indent macros in the\n" "Preferences -> Default Settings -> Smart Indent\n" "dialog, or choose a different language mode from:\n" "Preferences -> Language Mode.", "OK", modeName); } return; } /* Make sure that the initial macro file is loaded before we execute any of the smart-indent macros. Smart-indent macros may reference routines defined in that file. */ ReadMacroInitFile(window); /* Compile and run the common and language-specific initialization macros (Note that when these return, the immediate commands in the file have not necessarily been executed yet. They are only SCHEDULED for execution) */ if (!initialized) { if (!ReadMacroString(window, CommonMacros, "smart indent common initialization macros")) return; initialized = True; } if (indentMacros->initMacro != NULL) { if (!ReadMacroString(window, indentMacros->initMacro, "smart indent initialization macro")) return; } /* Compile the newline and modify macros and attach them to the window */ winData = (windowSmartIndentData *)XtMalloc(sizeof(windowSmartIndentData)); winData->inNewLineMacro = 0; winData->inModMacro = 0; winData->newlineMacro = ParseMacro(indentMacros->newlineMacro, &errMsg, &stoppedAt); if (winData->newlineMacro == NULL) { ParseError(window->shell, indentMacros->newlineMacro, stoppedAt, "newline macro", errMsg); return; } if (indentMacros->modMacro == NULL) winData->modMacro = NULL; else { winData->modMacro = ParseMacro(indentMacros->modMacro, &errMsg, &stoppedAt); if (winData->modMacro == NULL) { ParseError(window->shell, indentMacros->modMacro, stoppedAt, "smart indent modify macro", errMsg); return; } } window->smartIndentData = (void *)winData; } void EndSmartIndent(WindowInfo *window) { windowSmartIndentData *winData = (windowSmartIndentData *)window->smartIndentData; if (winData == NULL) return; /* Free programs and allocated data */ if (winData->modMacro != NULL) FreeProgram(winData->modMacro); FreeProgram(winData->newlineMacro); XtFree((char *)winData); window->smartIndentData = NULL; } /* ** Returns true if there are smart indent macros for a named language */ int SmartIndentMacrosAvailable(char *languageModeName) { return findIndentSpec(languageModeName) != NULL; } /* ** Attaches to the text widget's smart-indent callback to invoke a user ** defined macro when the text widget requires an indent (not just when the ** user types a newline, but also when the widget does an auto-wrap with ** auto-indent on), or the user types some other character. */ void SmartIndentCB(Widget w, XtPointer clientData, XtPointer callData) { WindowInfo *window = WidgetToWindow(w); smartIndentCBStruct *cbInfo = (smartIndentCBStruct *)callData; if (window->smartIndentData == NULL) return; if (cbInfo->reason == CHAR_TYPED) executeModMacro(window, cbInfo); else if (cbInfo->reason == NEWLINE_INDENT_NEEDED) executeNewlineMacro(window, cbInfo); } /* ** Run the newline macro with information from the smart-indent callback ** structure passed by the widget */ static void executeNewlineMacro(WindowInfo *window, smartIndentCBStruct *cbInfo) { windowSmartIndentData *winData = (windowSmartIndentData *)window->smartIndentData; /* posValue probably shouldn't be static due to re-entrance issues */ static DataValue posValue = {INT_TAG, {0}}; DataValue result; RestartData *continuation; char *errMsg; int stat; /* Beware of recursion: the newline macro may insert a string which triggers the newline macro to be called again and so on. Newline macros shouldn't insert strings, but nedit must not crash either if they do. */ if (winData->inNewLineMacro) return; /* Call newline macro with the position at which to add newline/indent */ posValue.val.n = cbInfo->pos; ++(winData->inNewLineMacro); stat = ExecuteMacro(window, winData->newlineMacro, 1, &posValue, &result, &continuation, &errMsg); /* Don't allow preemption or time limit. Must get return value */ while (stat == MACRO_TIME_LIMIT) stat = ContinueMacro(continuation, &result, &errMsg); --(winData->inNewLineMacro); /* Collect Garbage. Note that the mod macro does not collect garbage, (because collecting per-line is more efficient than per-character) but GC now depends on the newline macro being mandatory */ SafeGC(); /* Process errors in macro execution */ if (stat == MACRO_PREEMPT || stat == MACRO_ERROR) { DialogF(DF_ERR, window->shell, 1, "Smart Indent", "Error in smart indent macro:\n%s", "OK", stat == MACRO_ERROR ? errMsg : "dialogs and shell commands not permitted"); EndSmartIndent(window); return; } /* Validate and return the result */ if (result.tag != INT_TAG || result.val.n < -1 || result.val.n > 1000) { DialogF(DF_ERR, window->shell, 1, "Smart Indent", "Smart indent macros must return\ninteger indent distance", "OK"); EndSmartIndent(window); return; } cbInfo->indentRequest = result.val.n; } Boolean InSmartIndentMacros(WindowInfo *window) { windowSmartIndentData *winData = (windowSmartIndentData *)window->smartIndentData; return((winData && (winData->inModMacro || winData->inNewLineMacro))); } /* ** Run the modification macro with information from the smart-indent callback ** structure passed by the widget */ static void executeModMacro(WindowInfo *window,smartIndentCBStruct *cbInfo) { windowSmartIndentData *winData = (windowSmartIndentData *)window->smartIndentData; /* args probably shouldn't be static due to future re-entrance issues */ static DataValue args[2] = {{INT_TAG, {0}}, {STRING_TAG, {0}}}; /* after 5.2 release remove inModCB and use new winData->inModMacro value */ static int inModCB = False; DataValue result; RestartData *continuation; char *errMsg; int stat; /* Check for inappropriate calls and prevent re-entering if the macro makes a buffer modification */ if (winData == NULL || winData->modMacro == NULL || inModCB) return; /* Call modification macro with the position of the modification, and the character(s) inserted. Don't allow preemption or time limit. Execution must not overlap or re-enter */ args[0].val.n = cbInfo->pos; AllocNStringCpy(&args[1].val.str, cbInfo->charsTyped); inModCB = True; ++(winData->inModMacro); stat = ExecuteMacro(window, winData->modMacro, 2, args, &result, &continuation, &errMsg); while (stat == MACRO_TIME_LIMIT) stat = ContinueMacro(continuation, &result, &errMsg); --(winData->inModMacro); inModCB = False; /* Process errors in macro execution */ if (stat == MACRO_PREEMPT || stat == MACRO_ERROR) { DialogF(DF_ERR, window->shell, 1, "Smart Indent", "Error in smart indent modification macro:\n%s", "OK", stat == MACRO_ERROR ? errMsg : "dialogs and shell commands not permitted"); EndSmartIndent(window); return; } } void EditSmartIndentMacros(WindowInfo *window) { #define BORDER 4 Widget form, lmOptMenu, lmForm, lmBtn; Widget okBtn, applyBtn, checkBtn, deleteBtn, commonBtn; Widget closeBtn, helpBtn, restoreBtn, pane; Widget initForm, newlineForm, modifyForm; Widget initLbl, newlineLbl, modifyLbl; XmString s1; char *lmName; Arg args[20]; int n; /* if the dialog is already displayed, just pop it to the top and return */ if (SmartIndentDialog.shell != NULL) { RaiseDialogWindow(SmartIndentDialog.shell); return; } if (LanguageModeName(0) == NULL) { DialogF(DF_WARN, window->shell, 1, "Language Mode", "No Language Modes defined", "OK"); return; } /* Decide on an initial language mode */ lmName = LanguageModeName(window->languageMode == PLAIN_LANGUAGE_MODE ? 0 : window->languageMode); SmartIndentDialog.langModeName = XtNewString(lmName); /* Create a form widget in an application shell */ n = 0; XtSetArg(args[n], XmNdeleteResponse, XmDO_NOTHING); n++; XtSetArg(args[n], XmNiconName, "NEdit Smart Indent Macros"); n++; XtSetArg(args[n], XmNtitle, "Program Smart Indent Macros"); n++; SmartIndentDialog.shell = CreateWidget(TheAppShell, "smartIndent", topLevelShellWidgetClass, args, n); AddSmallIcon(SmartIndentDialog.shell); form = XtVaCreateManagedWidget("editSmartIndentMacros", xmFormWidgetClass, SmartIndentDialog.shell, XmNautoUnmanage, False, XmNresizePolicy, XmRESIZE_NONE, NULL); XtAddCallback(form, XmNdestroyCallback, destroyCB, NULL); AddMotifCloseCallback(SmartIndentDialog.shell, closeCB, NULL); lmForm = XtVaCreateManagedWidget("lmForm", xmFormWidgetClass, form, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNtopAttachment, XmATTACH_POSITION, XmNtopPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 99, NULL); SmartIndentDialog.lmPulldown = CreateLanguageModeMenu(lmForm, langModeCB, NULL); n = 0; XtSetArg(args[n], XmNspacing, 0); n++; XtSetArg(args[n], XmNmarginWidth, 0); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, 50); n++; XtSetArg(args[n], XmNsubMenuId, SmartIndentDialog.lmPulldown); n++; lmOptMenu = XmCreateOptionMenu(lmForm, "langModeOptMenu", args, n); XtManageChild(lmOptMenu); SmartIndentDialog.lmOptMenu = lmOptMenu; XtVaCreateManagedWidget("lmLbl", xmLabelGadgetClass, lmForm, XmNlabelString, s1=XmStringCreateSimple("Language Mode:"), XmNmnemonic, 'L', XmNuserData, XtParent(SmartIndentDialog.lmOptMenu), XmNalignment, XmALIGNMENT_END, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 50, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomWidget, lmOptMenu, NULL); XmStringFree(s1); lmBtn = XtVaCreateManagedWidget("lmBtn", xmPushButtonWidgetClass, lmForm, XmNlabelString, s1=MKSTRING("Add / Modify\nLanguage Mode..."), XmNmnemonic, 'A', XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL); XtAddCallback(lmBtn, XmNactivateCallback, lmDialogCB, NULL); XmStringFree(s1); commonBtn = XtVaCreateManagedWidget("commonBtn", xmPushButtonWidgetClass, lmForm, XmNlabelString, s1=MKSTRING("Common / Shared\nInitialization..."), XmNmnemonic, 'C', XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL); XtAddCallback(commonBtn, XmNactivateCallback, commonDialogCB, NULL); XmStringFree(s1); okBtn = XtVaCreateManagedWidget("ok", xmPushButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("OK"), XmNmarginWidth, BUTTON_WIDTH_MARGIN, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 13, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, BORDER, NULL); XtAddCallback(okBtn, XmNactivateCallback, okCB, NULL); XmStringFree(s1); applyBtn = XtVaCreateManagedWidget("apply", xmPushButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("Apply"), XmNmnemonic, 'y', XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 13, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 26, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, BORDER, NULL); XtAddCallback(applyBtn, XmNactivateCallback, applyCB, NULL); XmStringFree(s1); checkBtn = XtVaCreateManagedWidget("check", xmPushButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("Check"), XmNmnemonic, 'k', XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 26, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 39, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, BORDER, NULL); XtAddCallback(checkBtn, XmNactivateCallback, checkCB, NULL); XmStringFree(s1); deleteBtn = XtVaCreateManagedWidget("delete", xmPushButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("Delete"), XmNmnemonic, 'D', XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 39, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 52, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, BORDER, NULL); XtAddCallback(deleteBtn, XmNactivateCallback, deleteCB, NULL); XmStringFree(s1); restoreBtn = XtVaCreateManagedWidget("restore", xmPushButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("Restore Defaults"), XmNmnemonic, 'f', XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 52, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 73, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, BORDER, NULL); XtAddCallback(restoreBtn, XmNactivateCallback, restoreCB, NULL); XmStringFree(s1); closeBtn = XtVaCreateManagedWidget("close", xmPushButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("Close"), XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 73, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 86, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, BORDER, NULL); XtAddCallback(closeBtn, XmNactivateCallback, closeCB, NULL); XmStringFree(s1); helpBtn = XtVaCreateManagedWidget("help", xmPushButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("Help"), XmNmnemonic, 'H', XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 86, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 99, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, BORDER, NULL); XtAddCallback(helpBtn, XmNactivateCallback, helpCB, NULL); XmStringFree(s1); pane = XtVaCreateManagedWidget("pane", xmPanedWindowWidgetClass, form, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 99, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, lmForm, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, okBtn, NULL); /* XmNmarginWidth, 0, XmNmarginHeight, 0, XmNseparatorOn, False, XmNspacing, 3, XmNsashIndent, -2, */ initForm = XtVaCreateManagedWidget("initForm", xmFormWidgetClass, pane, NULL); initLbl = XtVaCreateManagedWidget("initLbl", xmLabelGadgetClass, initForm, XmNlabelString, s1=XmStringCreateSimple( "Language Specific Initialization Macro Commands and Definitions"), XmNmnemonic, 'I', NULL); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; XtSetArg(args[n], XmNrows, 5); n++; XtSetArg(args[n], XmNcolumns, 80); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, initLbl); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; SmartIndentDialog.initMacro = XmCreateScrolledText(initForm, "initMacro", args, n); AddMouseWheelSupport(SmartIndentDialog.initMacro); XtManageChild(SmartIndentDialog.initMacro); RemapDeleteKey(SmartIndentDialog.initMacro); XtVaSetValues(initLbl, XmNuserData, SmartIndentDialog.initMacro, NULL); newlineForm = XtVaCreateManagedWidget("newlineForm", xmFormWidgetClass, pane, NULL); newlineLbl = XtVaCreateManagedWidget("newlineLbl", xmLabelGadgetClass, newlineForm, XmNlabelString, s1=XmStringCreateSimple("Newline Macro"), XmNmnemonic, 'N', NULL); XmStringFree(s1); XtVaCreateManagedWidget("newlineArgsLbl", xmLabelGadgetClass, newlineForm, XmNalignment, XmALIGNMENT_END, XmNlabelString, s1=XmStringCreateSimple( "($1 is insert position, return indent request or -1)"), XmNrightAttachment, XmATTACH_FORM, NULL); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; XtSetArg(args[n], XmNrows, 5); n++; XtSetArg(args[n], XmNcolumns, 80); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, newlineLbl); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; SmartIndentDialog.newlineMacro = XmCreateScrolledText(newlineForm, "newlineMacro", args, n); AddMouseWheelSupport(SmartIndentDialog.newlineMacro); XtManageChild(SmartIndentDialog.newlineMacro); RemapDeleteKey(SmartIndentDialog.newlineMacro); XtVaSetValues(newlineLbl, XmNuserData, SmartIndentDialog.newlineMacro,NULL); modifyForm = XtVaCreateManagedWidget("modifyForm", xmFormWidgetClass, pane, NULL); modifyLbl = XtVaCreateManagedWidget("modifyLbl", xmLabelGadgetClass, modifyForm, XmNlabelString,s1=XmStringCreateSimple("Type-in Macro"), XmNmnemonic, 'M', NULL); XmStringFree(s1); XtVaCreateManagedWidget("modifyArgsLbl", xmLabelGadgetClass, modifyForm, XmNalignment, XmALIGNMENT_END, XmNlabelString, s1=XmStringCreateSimple( "($1 is position, $2 is character to be inserted)"), XmNrightAttachment, XmATTACH_FORM, NULL); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; XtSetArg(args[n], XmNrows, 5); n++; XtSetArg(args[n], XmNcolumns, 80); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, modifyLbl); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; SmartIndentDialog.modMacro = XmCreateScrolledText(modifyForm, "modifyMacro", args, n); AddMouseWheelSupport(SmartIndentDialog.modMacro); XtManageChild(SmartIndentDialog.modMacro); RemapDeleteKey(SmartIndentDialog.modMacro); XtVaSetValues(modifyLbl, XmNuserData, SmartIndentDialog.modMacro, NULL); /* Set initial default button */ XtVaSetValues(form, XmNdefaultButton, okBtn, NULL); XtVaSetValues(form, XmNcancelButton, closeBtn, NULL); /* Handle mnemonic selection of buttons and focus to dialog */ AddDialogMnemonicHandler(form, FALSE); /* Fill in the dialog information for the selected language mode */ setSmartIndentDialogData(findIndentSpec(lmName)); SetLangModeMenu(SmartIndentDialog.lmOptMenu,SmartIndentDialog.langModeName); /* Realize all of the widgets in the new dialog */ RealizeWithoutForcingPosition(SmartIndentDialog.shell); } static void destroyCB(Widget w, XtPointer clientData, XtPointer callData) { XtFree(SmartIndentDialog.langModeName); SmartIndentDialog.shell = NULL; } static void langModeCB(Widget w, XtPointer clientData, XtPointer callData) { char *modeName; int i, resp; static smartIndentRec emptyIndentSpec = {NULL, NULL, NULL, NULL}; smartIndentRec *oldMacros, *newMacros; /* Get the newly selected mode name. If it's the same, do nothing */ XtVaGetValues(w, XmNuserData, &modeName, NULL); if (!strcmp(modeName, SmartIndentDialog.langModeName)) return; /* Find the original macros */ for (i=0; ilmName)) break; oldMacros = i == NSmartIndentSpecs ? &emptyIndentSpec : SmartIndentSpecs[i]; /* Check if the macros have changed, if so allow user to apply, discard, or cancel */ newMacros = getSmartIndentDialogData(); if (indentSpecsDiffer(oldMacros, newMacros)) { resp = DialogF(DF_QUES, SmartIndentDialog.shell, 3, "Smart Indent", "Smart indent macros for language mode\n" "%s were changed. Apply changes?", "Apply", "Discard", "Cancel", SmartIndentDialog.langModeName); if (resp == 3) { SetLangModeMenu(SmartIndentDialog.lmOptMenu, SmartIndentDialog.langModeName); return; } else if (resp == 1) { if (checkSmartIndentDialogData()) { if (oldMacros == &emptyIndentSpec) { SmartIndentSpecs[NSmartIndentSpecs++] = copyIndentSpec(newMacros); } else { freeIndentSpec(oldMacros); SmartIndentSpecs[i] = copyIndentSpec(newMacros); } } else { SetLangModeMenu(SmartIndentDialog.lmOptMenu, SmartIndentDialog.langModeName); return; } } } freeIndentSpec(newMacros); /* Fill the dialog with the new language mode information */ SmartIndentDialog.langModeName = XtNewString(modeName); setSmartIndentDialogData(findIndentSpec(modeName)); } static void lmDialogCB(Widget w, XtPointer clientData, XtPointer callData) { EditLanguageModes(); } static void commonDialogCB(Widget w, XtPointer clientData, XtPointer callData) { EditCommonSmartIndentMacro(); } static void okCB(Widget w, XtPointer clientData, XtPointer callData) { /* change the macro */ if (!updateSmartIndentData()) return; /* pop down and destroy the dialog */ CloseAllPopupsFor(SmartIndentDialog.shell); XtDestroyWidget(SmartIndentDialog.shell); } static void applyCB(Widget w, XtPointer clientData, XtPointer callData) { /* change the patterns */ updateSmartIndentData(); } static void checkCB(Widget w, XtPointer clientData, XtPointer callData) { if (checkSmartIndentDialogData()) DialogF(DF_INF, SmartIndentDialog.shell, 1, "Macro compiled", "Macros compiled without error", "OK"); } static void restoreCB(Widget w, XtPointer clientData, XtPointer callData) { int i; smartIndentRec *defaultIS; /* Find the default indent spec */ for (i=0; ilmName)) break; if (i < NSmartIndentSpecs) { freeIndentSpec(SmartIndentSpecs[i]); SmartIndentSpecs[i] = copyIndentSpec(defaultIS); } else SmartIndentSpecs[NSmartIndentSpecs++] = copyIndentSpec(defaultIS); /* Update the dialog */ setSmartIndentDialogData(defaultIS); } static void deleteCB(Widget w, XtPointer clientData, XtPointer callData) { int i; if (DialogF(DF_WARN, SmartIndentDialog.shell, 2, "Delete Macros", "Are you sure you want to delete smart indent\n" "macros for language mode %s?", "Yes, Delete", "Cancel", SmartIndentDialog.langModeName) == 2) { return; } /* if a stored version of the pattern set exists, delete it from the list */ for (i=0; ilmName)) break; if (i < NSmartIndentSpecs) { freeIndentSpec(SmartIndentSpecs[i]); memmove(&SmartIndentSpecs[i], &SmartIndentSpecs[i+1], (NSmartIndentSpecs-1 - i) * sizeof(smartIndentRec *)); NSmartIndentSpecs--; } /* Clear out the dialog */ setSmartIndentDialogData(NULL); } static void closeCB(Widget widget, XtPointer clientData, XtPointer callData) { /* pop down and destroy the dialog */ CloseAllPopupsFor(SmartIndentDialog.shell); XtDestroyWidget(SmartIndentDialog.shell); } static void helpCB(Widget w, XtPointer clientData, XtPointer callData) { Help(HELP_SMART_INDENT); } static int checkSmartIndentDialogData(void) { char *widgetText, *errMsg, *stoppedAt; Program *prog; /* Check the initialization macro */ if (!TextWidgetIsBlank(SmartIndentDialog.initMacro)) { widgetText =ensureNewline(XmTextGetString(SmartIndentDialog.initMacro)); if (!CheckMacroString(SmartIndentDialog.shell, widgetText, "initialization macro", &stoppedAt)) { XmTextSetInsertionPosition(SmartIndentDialog.initMacro, stoppedAt - widgetText); XmProcessTraversal(SmartIndentDialog.initMacro, XmTRAVERSE_CURRENT); XtFree(widgetText); return False; } XtFree(widgetText); } /* Test compile the newline macro */ if (TextWidgetIsBlank(SmartIndentDialog.newlineMacro)) { DialogF(DF_WARN, SmartIndentDialog.shell, 1, "Smart Indent", "Newline macro required", "OK"); return False; } widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.newlineMacro)); prog = ParseMacro(widgetText, &errMsg, &stoppedAt); if (prog == NULL) { ParseError(SmartIndentDialog.shell, widgetText, stoppedAt, "newline macro", errMsg); XmTextSetInsertionPosition(SmartIndentDialog.newlineMacro, stoppedAt - widgetText); XmProcessTraversal(SmartIndentDialog.newlineMacro, XmTRAVERSE_CURRENT); XtFree(widgetText); return False; } XtFree(widgetText); FreeProgram(prog); /* Test compile the modify macro */ if (!TextWidgetIsBlank(SmartIndentDialog.modMacro)) { widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.modMacro)); prog = ParseMacro(widgetText, &errMsg, &stoppedAt); if (prog == NULL) { ParseError(SmartIndentDialog.shell, widgetText, stoppedAt, "modify macro", errMsg); XmTextSetInsertionPosition(SmartIndentDialog.modMacro, stoppedAt - widgetText); XmProcessTraversal(SmartIndentDialog.modMacro, XmTRAVERSE_CURRENT); XtFree(widgetText); return False; } XtFree(widgetText); FreeProgram(prog); } return True; } static smartIndentRec *getSmartIndentDialogData(void) { smartIndentRec *is; is = (smartIndentRec *)XtMalloc(sizeof(smartIndentRec)); is->lmName = XtNewString(SmartIndentDialog.langModeName); is->initMacro = TextWidgetIsBlank(SmartIndentDialog.initMacro) ? NULL : ensureNewline(XmTextGetString(SmartIndentDialog.initMacro)); is->newlineMacro = TextWidgetIsBlank(SmartIndentDialog.newlineMacro) ? NULL: ensureNewline(XmTextGetString(SmartIndentDialog.newlineMacro)); is->modMacro = TextWidgetIsBlank(SmartIndentDialog.modMacro) ? NULL : ensureNewline(XmTextGetString(SmartIndentDialog.modMacro)); return is; } static void setSmartIndentDialogData(smartIndentRec *is) { if (is == NULL) { XmTextSetString(SmartIndentDialog.initMacro, ""); XmTextSetString(SmartIndentDialog.newlineMacro, ""); XmTextSetString(SmartIndentDialog.modMacro, ""); } else { if (is->initMacro == NULL) XmTextSetString(SmartIndentDialog.initMacro, ""); else XmTextSetString(SmartIndentDialog.initMacro, is->initMacro); XmTextSetString(SmartIndentDialog.newlineMacro, is->newlineMacro); if (is->modMacro == NULL) XmTextSetString(SmartIndentDialog.modMacro, ""); else XmTextSetString(SmartIndentDialog.modMacro, is->modMacro); } } void EditCommonSmartIndentMacro(void) { #define VERT_BORDER 4 Widget form, topLbl; Widget okBtn, applyBtn, checkBtn; Widget closeBtn, restoreBtn; XmString s1; Arg args[20]; int n; /* if the dialog is already displayed, just pop it to the top and return */ if (CommonDialog.shell != NULL) { RaiseDialogWindow(CommonDialog.shell); return; } /* Create a form widget in an application shell */ n = 0; XtSetArg(args[n], XmNdeleteResponse, XmDO_NOTHING); n++; XtSetArg(args[n], XmNiconName, "NEdit Common Smart Indent Macros"); n++; XtSetArg(args[n], XmNtitle, "Common Smart Indent Macros"); n++; CommonDialog.shell = CreateWidget(TheAppShell, "smartIndent", topLevelShellWidgetClass, args, n); AddSmallIcon(CommonDialog.shell); form = XtVaCreateManagedWidget("editCommonSIMacros", xmFormWidgetClass, CommonDialog.shell, XmNautoUnmanage, False, XmNresizePolicy, XmRESIZE_NONE, NULL); XtAddCallback(form, XmNdestroyCallback, comDestroyCB, NULL); AddMotifCloseCallback(CommonDialog.shell, comCloseCB, NULL); topLbl = XtVaCreateManagedWidget("topLbl", xmLabelGadgetClass, form, XmNlabelString, s1=XmStringCreateSimple( "Common Definitions for Smart Indent Macros"), XmNmnemonic, 'C', XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, VERT_BORDER, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, NULL); okBtn = XtVaCreateManagedWidget("ok", xmPushButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("OK"), XmNmarginWidth, BUTTON_WIDTH_MARGIN, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 6, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 18, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, VERT_BORDER, NULL); XtAddCallback(okBtn, XmNactivateCallback, comOKCB, NULL); XmStringFree(s1); applyBtn = XtVaCreateManagedWidget("apply", xmPushButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("Apply"), XmNmnemonic, 'y', XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 22, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 35, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, VERT_BORDER, NULL); XtAddCallback(applyBtn, XmNactivateCallback, comApplyCB, NULL); XmStringFree(s1); checkBtn = XtVaCreateManagedWidget("check", xmPushButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("Check"), XmNmnemonic, 'k', XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 39, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 52, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, VERT_BORDER, NULL); XtAddCallback(checkBtn, XmNactivateCallback, comCheckCB, NULL); XmStringFree(s1); restoreBtn = XtVaCreateManagedWidget("restore", xmPushButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("Restore Default"), XmNmnemonic, 'f', XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 56, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 77, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, VERT_BORDER, NULL); XtAddCallback(restoreBtn, XmNactivateCallback, comRestoreCB, NULL); XmStringFree(s1); closeBtn = XtVaCreateManagedWidget("close", xmPushButtonWidgetClass, form, XmNlabelString, s1=XmStringCreateSimple("Close"), XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 81, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 94, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, VERT_BORDER, NULL); XtAddCallback(closeBtn, XmNactivateCallback, comCloseCB, NULL); XmStringFree(s1); n = 0; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; XtSetArg(args[n], XmNrows, 24); n++; XtSetArg(args[n], XmNcolumns, 80); n++; XtSetArg(args[n], XmNvalue, CommonMacros); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, topLbl); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, 1); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 99); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, okBtn); n++; XtSetArg(args[n], XmNbottomOffset, VERT_BORDER); n++; CommonDialog.text = XmCreateScrolledText(form, "commonText", args, n); AddMouseWheelSupport(CommonDialog.text); XtManageChild(CommonDialog.text); RemapDeleteKey(CommonDialog.text); XtVaSetValues(topLbl, XmNuserData, CommonDialog.text, NULL); /* Set initial default button */ XtVaSetValues(form, XmNdefaultButton, okBtn, NULL); XtVaSetValues(form, XmNcancelButton, closeBtn, NULL); /* Handle mnemonic selection of buttons and focus to dialog */ AddDialogMnemonicHandler(form, FALSE); /* Realize all of the widgets in the new dialog */ RealizeWithoutForcingPosition(CommonDialog.shell); } static void comDestroyCB(Widget w, XtPointer clientData, XtPointer callData) { CommonDialog.shell = NULL; } static void comOKCB(Widget w, XtPointer clientData, XtPointer callData) { /* change the macro */ if (!updateSmartIndentCommonData()) return; /* pop down and destroy the dialog */ XtDestroyWidget(CommonDialog.shell); } static void comApplyCB(Widget w, XtPointer clientData, XtPointer callData) { /* change the macro */ updateSmartIndentCommonData(); } static void comCheckCB(Widget w, XtPointer clientData, XtPointer callData) { if (checkSmartIndentCommonDialogData()) { DialogF(DF_INF, CommonDialog.shell, 1, "Macro compiled", "Macros compiled without error", "OK"); } } static void comRestoreCB(Widget w, XtPointer clientData, XtPointer callData) { if (DialogF(DF_WARN, CommonDialog.shell, 2, "Discard Changes", "Are you sure you want to discard all\n" "changes to common smart indent macros", "Discard", "Cancel") == 2) { return; } /* replace common macros with default */ XtFree(CommonMacros); CommonMacros = XtNewString(DefaultCommonMacros); /* Update the dialog */ XmTextSetString(CommonDialog.text, CommonMacros); } static void comCloseCB(Widget w, XtPointer clientData, XtPointer callData) { /* pop down and destroy the dialog */ XtDestroyWidget(CommonDialog.shell); } /* ** Update the smart indent macros being edited in the dialog ** with the information that the dialog is currently displaying, and ** apply changes to any window which is currently using the macros. */ static int updateSmartIndentCommonData(void) { WindowInfo *window; /* Make sure the patterns are valid and compile */ if (!checkSmartIndentCommonDialogData()) return False; /* Get the current data */ CommonMacros = ensureNewline(XmTextGetString(CommonDialog.text)); /* Re-execute initialization macros (macros require a window to function, since user could theoretically execute an action routine, but it probably won't be referenced in a smart indent initialization) */ if (!ReadMacroString(WindowList, CommonMacros, "common macros")) return False; /* Find windows that are currently using smart indent and re-initialize the smart indent macros (in case they have initialization data which depends on common data) */ for (window=WindowList; window!=NULL; window=window->next) { if (window->indentStyle == SMART_INDENT && window->languageMode != PLAIN_LANGUAGE_MODE) { EndSmartIndent(window); BeginSmartIndent(window, False); } } /* Note that preferences have been changed */ MarkPrefsChanged(); return True; } static int checkSmartIndentCommonDialogData(void) { char *widgetText, *stoppedAt; if (!TextWidgetIsBlank(CommonDialog.text)) { widgetText = ensureNewline(XmTextGetString(CommonDialog.text)); if (!CheckMacroString(CommonDialog.shell, widgetText, "macros", &stoppedAt)) { XmTextSetInsertionPosition(CommonDialog.text, stoppedAt-widgetText); XmProcessTraversal(CommonDialog.text, XmTRAVERSE_CURRENT); XtFree(widgetText); return False; } XtFree(widgetText); } return True; } /* ** Update the smart indent macros being edited in the dialog ** with the information that the dialog is currently displaying, and ** apply changes to any window which is currently using the macros. */ static int updateSmartIndentData(void) { smartIndentRec *newMacros; WindowInfo *window; char *lmName; int i; /* Make sure the patterns are valid and compile */ if (!checkSmartIndentDialogData()) return False; /* Get the current data */ newMacros = getSmartIndentDialogData(); /* Find the original macros */ for (i=0; ilmName)) break; /* If it's a new language, add it at the end, otherwise free the existing macros and replace it */ if (i == NSmartIndentSpecs) { SmartIndentSpecs[NSmartIndentSpecs++] = newMacros; } else { freeIndentSpec(SmartIndentSpecs[i]); SmartIndentSpecs[i] = newMacros; } /* Find windows that are currently using this indent specification and re-do the smart indent macros */ for (window=WindowList; window!=NULL; window=window->next) { lmName = LanguageModeName(window->languageMode); if (lmName != NULL && !strcmp(lmName, newMacros->lmName)) { SetSensitive(window, window->smartIndentItem, True); if (window->indentStyle == SMART_INDENT && window->languageMode != PLAIN_LANGUAGE_MODE) { EndSmartIndent(window); BeginSmartIndent(window, False); } } } /* Note that preferences have been changed */ MarkPrefsChanged(); return True; } static int loadDefaultIndentSpec(char *lmName) { int i; for (i=0; ilmName, is.lmName)) { freeIndentSpec(SmartIndentSpecs[i]); SmartIndentSpecs[i] = isCopy; break; } } if (i == NSmartIndentSpecs) SmartIndentSpecs[NSmartIndentSpecs++] = isCopy; } } int LoadSmartIndentCommonString(char *inString) { int shiftedLen; char *inPtr = inString; /* If called from -import, can replace existing ones */ XtFree(CommonMacros); /* skip over blank space */ inPtr += strspn(inPtr, " \t\n"); /* look for "Default" keyword, and if it's there, return the default smart common macro */ if (!strncmp(inPtr, "Default", 7)) { CommonMacros = XtNewString(DefaultCommonMacros); return True; } /* Remove leading tabs added by writer routine */ CommonMacros = ShiftText(inPtr, SHIFT_LEFT, True, 8, 8, &shiftedLen); return True; } /* ** Read a macro (arbitrary text terminated by the macro end boundary string) ** from the position pointed to by *inPtr, trim off added tabs and return an ** allocated copy of the string, and advance *inPtr to the end of the macro. ** Returns NULL if the macro end boundary string is not found. */ static char *readSIMacro(char **inPtr) { char *retStr, *macroStr, *macroEnd; int shiftedLen; /* Strip leading newline */ if (**inPtr == '\n') (*inPtr)++; /* Find the end of the macro */ macroEnd = strstr(*inPtr, MacroEndBoundary); if (macroEnd == NULL) return NULL; /* Copy the macro */ macroStr = XtMalloc(macroEnd - *inPtr + 1); strncpy(macroStr, *inPtr, macroEnd - *inPtr); macroStr[macroEnd - *inPtr] = '\0'; /* Remove leading tabs added by writer routine */ *inPtr = macroEnd + strlen(MacroEndBoundary); retStr = ShiftText(macroStr, SHIFT_LEFT, True, 8, 8, &shiftedLen); XtFree(macroStr); return retStr; } static smartIndentRec *copyIndentSpec(smartIndentRec *is) { smartIndentRec *ris = (smartIndentRec *)XtMalloc(sizeof(smartIndentRec)); ris->lmName = XtNewString(is->lmName); ris->initMacro = XtNewString(is->initMacro); ris->newlineMacro = XtNewString(is->newlineMacro); ris->modMacro = XtNewString(is->modMacro); return ris; } static void freeIndentSpec(smartIndentRec *is) { XtFree(is->lmName); if (is->initMacro != NULL) XtFree(is->initMacro); XtFree(is->newlineMacro); if (is->modMacro != NULL)XtFree(is->modMacro); } static int indentSpecsDiffer(smartIndentRec *is1, smartIndentRec *is2) { return AllocatedStringsDiffer(is1->initMacro, is2->initMacro) || AllocatedStringsDiffer(is1->newlineMacro, is2->newlineMacro) || AllocatedStringsDiffer(is1->modMacro, is2->modMacro); } static int siParseError(char *stringStart, char *stoppedAt, char *message) { return ParseError(NULL, stringStart, stoppedAt, "smart indent specification", message); } char *WriteSmartIndentString(void) { int i; smartIndentRec *sis; textBuffer *outBuf; char *outStr, *escapedStr; outBuf = BufCreate(); for (i=0; ilength, "\t"); BufInsert(outBuf, outBuf->length, sis->lmName); BufInsert(outBuf, outBuf->length, ":"); if (isDefaultIndentSpec(sis)) BufInsert(outBuf, outBuf->length, "Default\n"); else { insertShiftedMacro(outBuf, sis->initMacro); insertShiftedMacro(outBuf, sis->newlineMacro); insertShiftedMacro(outBuf, sis->modMacro); } } /* Get the output string, and lop off the trailing newline */ outStr = BufGetRange(outBuf, 0, outBuf->length > 0 ? outBuf->length-1 : 0); BufFree(outBuf); /* Protect newlines and backslashes from translation by the resource reader */ escapedStr = EscapeSensitiveChars(outStr); XtFree(outStr); return escapedStr; } char *WriteSmartIndentCommonString(void) { int len; char *outStr, *escapedStr; if (!strcmp(CommonMacros, DefaultCommonMacros)) return XtNewString("Default"); if (CommonMacros == NULL) return XtNewString(""); /* Shift the macro over by a tab to keep .nedit file bright and clean */ outStr = ShiftText(CommonMacros, SHIFT_RIGHT, True, 8, 8, &len); /* Protect newlines and backslashes from translation by the resource reader */ escapedStr = EscapeSensitiveChars(outStr); XtFree(outStr); /* If there's a trailing escaped newline, remove it */ len = strlen(escapedStr); if (len > 1 && escapedStr[len-1] == '\n' && escapedStr[len-2] == '\\') escapedStr[len-2] = '\0'; return escapedStr; } /* ** Insert macro text "macro" into buffer "buf" shifted right by 8 characters ** (so it looks nice in the .nedit file), and terminated with a macro-end- ** boundary string. */ static void insertShiftedMacro(textBuffer *buf, char *macro) { char *shiftedMacro; int shiftedLen; if (macro != NULL) { shiftedMacro = ShiftText(macro, SHIFT_RIGHT, True, 8, 8, &shiftedLen); BufInsert(buf, buf->length, shiftedMacro); XtFree(shiftedMacro); } BufInsert(buf, buf->length, "\t"); BufInsert(buf, buf->length, MacroEndBoundary); BufInsert(buf, buf->length, "\n"); } static int isDefaultIndentSpec(smartIndentRec *indentSpec) { int i; for (i=0; ilmName, DefaultIndentSpecs[i].lmName)) return !indentSpecsDiffer(indentSpec, &DefaultIndentSpecs[i]); return False; } static smartIndentRec *findIndentSpec(const char *modeName) { int i; if (modeName == NULL) return NULL; for (i=0; ilmName)) return SmartIndentSpecs[i]; return NULL; } /* ** If "string" is not terminated with a newline character, return a ** reallocated string which does end in a newline (otherwise, just pass on ** string as function value). (The macro language requires newline terminators ** for statements, but the text widget doesn't force it like the NEdit text ** buffer does, so this might avoid some confusion.) */ static char *ensureNewline(char *string) { char *newString; int length; if (string == NULL) return NULL; length = strlen(string); if (length == 0 || string[length-1] == '\n') return string; newString = XtMalloc(length + 2); strcpy(newString, string); newString[length] = '\n'; newString[length+1] = '\0'; XtFree(string); return newString; } /* ** Returns True if there are smart indent macros, or potential macros ** not yet committed in the smart indent dialog for a language mode, */ int LMHasSmartIndentMacros(const char *languageMode) { if (findIndentSpec(languageMode) != NULL) return True; return SmartIndentDialog.shell!=NULL && !strcmp(SmartIndentDialog.langModeName, languageMode); } /* ** Change the language mode name of smart indent macro sets for language ** "oldName" to "newName" in both the stored macro sets, and the pattern set ** currently being edited in the dialog. */ void RenameSmartIndentMacros(const char *oldName, const char *newName) { int i; for (i=0; ilmName)) { XtFree(SmartIndentSpecs[i]->lmName); SmartIndentSpecs[i]->lmName = XtNewString(newName); } } if (SmartIndentDialog.shell != NULL) { if (!strcmp(SmartIndentDialog.langModeName, oldName)) { XtFree(SmartIndentDialog.langModeName); SmartIndentDialog.langModeName = XtNewString(newName); } } } /* ** If a smart indent dialog is up, ask to have the option menu for ** chosing language mode updated (via a call to CreateLanguageModeMenu) */ void UpdateLangModeMenuSmartIndent(void) { Widget oldMenu; if (SmartIndentDialog.shell == NULL) return; oldMenu = SmartIndentDialog.lmPulldown; SmartIndentDialog.lmPulldown = CreateLanguageModeMenu( XtParent(XtParent(oldMenu)), langModeCB, NULL); XtVaSetValues(XmOptionButtonGadget(SmartIndentDialog.lmOptMenu), XmNsubMenuId, SmartIndentDialog.lmPulldown, NULL); SetLangModeMenu(SmartIndentDialog.lmOptMenu, SmartIndentDialog.langModeName); XtDestroyWidget(oldMenu); } nedit-5.6.orig/source/smartIndent.h0000644000175000017500000000560410144236624016062 0ustar paulpaul/* $Id: smartIndent.h,v 1.8 2004/11/09 21:58:44 yooden Exp $ */ /******************************************************************************* * * * smartIndent.h -- Nirvana Editor Smart Indent Header File * * * * Copyright 2003 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_SMARTINDENT_H_INCLUDED #define NEDIT_SMARTINDENT_H_INCLUDED #include "nedit.h" #include void BeginSmartIndent(WindowInfo *window, int warn); void EndSmartIndent(WindowInfo *window); void SmartIndentCB(Widget w, XtPointer clientData, XtPointer callData); int LoadSmartIndentString(char *inString); int LoadSmartIndentCommonString(char *inString); char *WriteSmartIndentString(void); char *WriteSmartIndentCommonString(void); int SmartIndentMacrosAvailable(char *languageMode); void EditSmartIndentMacros(WindowInfo *window); void EditCommonSmartIndentMacro(void); Boolean InSmartIndentMacros(WindowInfo *window); int LMHasSmartIndentMacros(const char *languageMode); void RenameSmartIndentMacros(const char *oldName, const char *newName); void UpdateLangModeMenuSmartIndent(void); #endif /* NEDIT_SMARTINDENT_H_INCLUDED */ nedit-5.6.orig/source/tags.c0000644000175000017500000020665510762353036014537 0ustar paulpaulstatic const char CVSID[] = "$Id: tags.c,v 1.70 2008/03/01 22:18:06 lebert Exp $"; /******************************************************************************* * * * tags.c -- Nirvana editor tag file handling * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July, 1993 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "tags.h" #include "textBuf.h" #include "text.h" #include "nedit.h" #include "window.h" #include "file.h" #include "preferences.h" #include "search.h" #include "selection.h" #include "calltips.h" #include "../util/DialogF.h" #include "../util/fileUtils.h" #include "../util/misc.h" #include "../util/utils.h" #include #include #include #include #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #include /* For Calltips */ #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #define MAXLINE 2048 #define MAX_TAG_LEN 256 #define MAXDUPTAGS 100 #define MAX_TAG_INCLUDE_RECURSION_LEVEL 5 /* Take this many lines when making a tip from a tag. (should probably be a language-dependent option, but...) */ #define TIP_DEFAULT_LINES 4 #define STRSAVE(a) ((a!=NULL)?strcpy(malloc(strlen(a)+1),(a)):strcpy(malloc(1),"")) typedef struct _tag { struct _tag *next; const char *path; const char *name; const char *file; int language; const char *searchString; /* see comment below */ int posInf; /* see comment below */ short index; } tag; /* ** contents of tag->searchString | tag->posInf ** ctags, line num specified: "" | line num ** ctags, search expr specfd: ctags search expr | -1 ** etags (emacs tags) etags search string | search start pos */ enum searchDirection {FORWARD, BACKWARD}; static int loadTagsFile(const char *tagSpec, int index, int recLevel); static void findDefCB(Widget widget, WindowInfo *window, Atom *sel, Atom *type, char *value, int *length, int *format); static void setTag(tag *t, const char *name, const char *file, int language, const char *searchString, int posInf, const char * tag); static int fakeRegExSearch(WindowInfo *window, char *buffer, const char *searchString, int *startPos, int *endPos); static unsigned hashAddr(const char *key); static void updateMenuItems(void); static int addTag(const char *name, const char *file, int lang, const char *search, int posInf, const char *path, int index); static int delTag(const char *name, const char *file, int lang, const char *search, int posInf, int index); static tag *getTag(const char *name, int search_type); static int findDef(WindowInfo *window, const char *value, int search_type); static int findAllMatches(WindowInfo *window, const char *string); static void findAllCB(Widget parent, XtPointer client_data, XtPointer call_data); static Widget createSelectMenu(Widget parent, char *label, int nArgs, char *args[]); static void editTaggedLocation( Widget parent, int i ); static void showMatchingCalltip( Widget parent, int i ); static const char *rcs_strdup(const char *str); static void rcs_free(const char *str); static int searchLine(char *line, const char *regex); static void rstrip( char *dst, const char *src ); static int nextTFBlock(FILE *fp, char *header, char **tiptext, int *lineAt, int *lineNo); static int loadTipsFile(const char *tipsFile, int index, int recLevel); /* Hash table of tags, implemented as an array. Each bin contains a NULL-terminated linked list of parsed tags */ static tag **Tags = NULL; static int DefTagHashSize = 10000; /* list of loaded tags files */ tagFile *TagsFileList = NULL; /* Hash table of calltip tags */ static tag **Tips = NULL; tagFile *TipsFileList = NULL; /* These are all transient global variables -- they don't hold any state between tag/tip lookups */ static int searchMode = TAG; static const char *tagName; static char tagFiles[MAXDUPTAGS][MAXPATHLEN]; static char tagSearch[MAXDUPTAGS][MAXPATHLEN]; static int tagPosInf[MAXDUPTAGS]; static Boolean globAnchored; static int globPos; static int globHAlign; static int globVAlign; static int globAlignMode; /* A wrapper for calling TextDShowCalltip */ static int tagsShowCalltip( WindowInfo *window, char *text ) { if (text) return ShowCalltip( window, text, globAnchored, globPos, globHAlign, globVAlign, globAlignMode); else return 0; } /* Set the head of the proper file list (Tags or Tips) to t */ static tagFile *setFileListHead(tagFile *t, int file_type ) { if (file_type == TAG) TagsFileList = t; else TipsFileList = t; return t; } /* Compute hash address from a string key */ static unsigned hashAddr(const char *key) { unsigned s=strlen(key); unsigned a=0,x=0,i; for (i=0; (i+3)next; } else return NULL; for (;t; t = t->next) if (!strcmp(name,t->name)) return t; return NULL; } /* Add a tag specification to the hash table ** Return Value: 0 ... tag already existing, spec not added ** 1 ... tag spec is new, added. ** (We don't return boolean as the return value is used as counter increment!) ** */ static int addTag(const char *name, const char *file, int lang, const char *search, int posInf, const char *path, int index) { int addr = hashAddr(name) % DefTagHashSize; tag *t; char newfile[MAXPATHLEN]; tag **table; if (searchMode == TIP) { if (Tips == NULL) Tips = (tag **)calloc(DefTagHashSize, sizeof(tag*)); table = Tips; } else { if (Tags == NULL) Tags = (tag **)calloc(DefTagHashSize, sizeof(tag*)); table = Tags; } if (*file == '/') strcpy(newfile,file); else sprintf(newfile,"%s%s", path, file); NormalizePathname(newfile); for (t = table[addr]; t; t = t->next) { if (strcmp(name,t->name)) continue; if (lang != t->language) continue; if (strcmp(search,t->searchString)) continue; if (posInf != t->posInf) continue; if (*t->file == '/' && strcmp(newfile,t->file)) continue; if (*t->file != '/') { char tmpfile[MAXPATHLEN]; sprintf(tmpfile, "%s%s", t->path, t->file); NormalizePathname(tmpfile); if (strcmp(newfile, tmpfile)) continue; } return 0; } t = (tag *) malloc(sizeof(tag)); setTag(t, name, file, lang, search, posInf, path); t->index = index; t->next = table[addr]; table[addr] = t; return 1; } /* Delete a tag from the cache. * Search is limited to valid matches of 'name','file', 'search', posInf, and 'index'. * EX: delete all tags matching index 2 ==> * delTag(tagname,NULL,-2,NULL,-2,2); * (posInf = -2 is an invalid match, posInf range: -1 .. +MAXINT, lang = -2 is also an invalid match) */ static int delTag(const char *name, const char *file, int lang, const char *search, int posInf, int index) { tag *t, *last; int start,finish,i,del=0; tag **table; if (searchMode == TIP) table = Tips; else table = Tags; if (table == NULL) return FALSE; if (name) start = finish = hashAddr(name) % DefTagHashSize; else { start = 0; finish = DefTagHashSize; } for (i = start; inext:table[i]) { if (name && strcmp(name,t->name)) continue; if (index && index != t->index) continue; if (file && strcmp(file,t->file)) continue; if (lang >= PLAIN_LANGUAGE_MODE && lang != t->language) continue; if (search && strcmp(search,t->searchString)) continue; if (posInf == t->posInf) continue; if (last) last->next = t->next; else table[i] = t->next; rcs_free(t->name); rcs_free(t->file); rcs_free(t->searchString); rcs_free(t->path); free(t); t = NULL; del++; } } return del>0; } /* used in AddRelTagsFile and AddTagsFile */ static int tagFileIndex = 0; /* ** AddRelTagsFile(): Rescan tagSpec for relative tag file specs ** (not starting with [/~]) and extend the tag files list if in ** windowPath a tags file matching the relative spec has been found. */ int AddRelTagsFile(const char *tagSpec, const char *windowPath, int file_type) { tagFile *t; int added=0; struct stat statbuf; char *filename; char pathName[MAXPATHLEN]; char *tmptagSpec; tagFile *FileList; searchMode = file_type; if (searchMode == TAG) FileList = TagsFileList; else FileList = TipsFileList; tmptagSpec = (char *) malloc(strlen(tagSpec)+1); strcpy(tmptagSpec, tagSpec); for (filename = strtok(tmptagSpec, ":"); filename; filename = strtok(NULL, ":")){ if (*filename == '/' || *filename == '~') continue; if (windowPath && *windowPath) { strcpy(pathName, windowPath); } else { strcpy(pathName, GetCurrentDir()); } strcat(pathName, "/"); strcat(pathName, filename); NormalizePathname(pathName); for (t = FileList; t && strcmp(t->filename, pathName); t = t->next); if (t) { added=1; continue; } if (stat(pathName, &statbuf) != 0) continue; t = (tagFile *) malloc(sizeof(tagFile)); t->filename = STRSAVE(pathName); t->loaded = 0; t->date = statbuf.st_mtime; t->index = ++tagFileIndex; t->next = FileList; FileList = setFileListHead(t, file_type); added=1; } free(tmptagSpec); updateMenuItems(); if (added) return TRUE; else return FALSE; } /* ** AddTagsFile(): Set up the the list of tag files to manage from a file spec. ** The file spec comes from the X-Resource Nedit.tags: It can list multiple ** tags files, specified by separating them with colons. The .Xdefaults would ** look like this: ** Nedit.tags: : ** Returns True if all files were found in the FileList or loaded successfully, ** FALSE otherwise. */ int AddTagsFile(const char *tagSpec, int file_type) { tagFile *t; int added=1; struct stat statbuf; char *filename; char pathName[MAXPATHLEN]; char *tmptagSpec; tagFile *FileList; /* To prevent any possible segfault */ if (tagSpec == NULL) { fprintf(stderr, "nedit: Internal Error!\n" " Passed NULL pointer to AddTagsFile!\n"); return FALSE; } searchMode = file_type; if (searchMode == TAG) FileList = TagsFileList; else FileList = TipsFileList; tmptagSpec = (char *) malloc(strlen(tagSpec)+1); strcpy(tmptagSpec, tagSpec); for (filename = strtok(tmptagSpec,":"); filename; filename = strtok(NULL,":")) { if (*filename != '/') { strcpy(pathName, GetCurrentDir()); strcat(pathName,"/"); strcat(pathName,filename); } else { strcpy(pathName,filename); } NormalizePathname(pathName); for (t = FileList; t && strcmp(t->filename,pathName); t = t->next); if (t) { /* This file is already in the list. It's easiest to just refcount all tag/tip files even though we only actually care about tip files. */ ++(t->refcount); added=1; continue; } if (stat(pathName,&statbuf) != 0) { /* Problem reading this tags file. Return FALSE */ added = 0; continue; } t = (tagFile *) malloc(sizeof(tagFile)); t->filename = STRSAVE(pathName); t->loaded = 0; t->date = statbuf.st_mtime; t->index = ++tagFileIndex; t->next = FileList; t->refcount = 1; FileList = setFileListHead(t, file_type ); } free(tmptagSpec); updateMenuItems(); if (added) return TRUE; else return FALSE; } /* Un-manage a colon-delimited set of tags files * Return TRUE if all files were found in the FileList and unloaded, FALSE * if any file was not found in the FileList. * "file_type" is either TAG or TIP * If "force_unload" is true, a calltips file will be deleted even if its * refcount is nonzero. */ int DeleteTagsFile(const char *tagSpec, int file_type, Boolean force_unload) { tagFile *t, *last; tagFile *FileList; char pathName[MAXPATHLEN], *tmptagSpec, *filename; int removed; /* To prevent any possible segfault */ if (tagSpec == NULL) { fprintf(stderr, "nedit: Internal Error: Passed NULL pointer to DeleteTagsFile!\n"); return FALSE; } searchMode = file_type; if (searchMode == TAG) FileList = TagsFileList; else FileList = TipsFileList; tmptagSpec = (char *) malloc(strlen(tagSpec)+1); strcpy(tmptagSpec, tagSpec); removed=1; for (filename = strtok(tmptagSpec,":"); filename; filename = strtok(NULL,":")) { if (*filename != '/') { strcpy(pathName, GetCurrentDir()); strcat(pathName,"/"); strcat(pathName,filename); } else { strcpy(pathName,filename); } NormalizePathname(pathName); for (last=NULL,t = FileList; t; last = t,t = t->next) { if (strcmp(t->filename, pathName)) continue; /* Don't unload tips files with nonzero refcounts unless forced */ if (searchMode == TIP && !force_unload && --t->refcount > 0) { break; } if (t->loaded) delTag(NULL,NULL,-2,NULL,-2,t->index); if (last) last->next = t->next; else FileList = setFileListHead(t->next, file_type); free(t->filename); free(t); updateMenuItems(); break; } /* If any file can't be removed, return false */ if (!t) removed = 0; } if (removed) return TRUE; else return FALSE; } /* ** Update the "Find Definition", "Unload Tags File", "Show Calltip", ** and "Unload Calltips File" menu items in the existing windows. */ static void updateMenuItems(void) { WindowInfo *w; Boolean tipStat=FALSE, tagStat=FALSE; if (TipsFileList) tipStat=TRUE; if (TagsFileList) tagStat=TRUE; for (w=WindowList; w!=NULL; w=w->next) { if (!IsTopDocument(w)) continue; XtSetSensitive(w->showTipItem, tipStat || tagStat); XtSetSensitive(w->unloadTipsMenuItem, tipStat); XtSetSensitive(w->findDefItem, tagStat); XtSetSensitive(w->unloadTagsMenuItem, tagStat); } } /* ** Scans one from a ctags tags file () in tagPath. ** Return value: Number of tag specs added. */ static int scanCTagsLine(const char *line, const char *tagPath, int index) { char name[MAXLINE], searchString[MAXLINE]; char file[MAXPATHLEN]; char *posTagREEnd, *posTagRENull; int nRead, pos; nRead = sscanf(line, "%s\t%s\t%[^\n]", name, file, searchString); if (nRead != 3) return 0; if ( *name == '!' ) return 0; /* ** Guess the end of searchString: ** Try to handle original ctags and exuberant ctags format: */ if(searchString[0] == '/' || searchString[0] == '?') { pos=-1; /* "search expr without pos info" */ /* Situations: //\0 ** ??\0 --> original ctags ** //;" ** ??;" --> exuberant ctags */ posTagREEnd = strrchr(searchString, ';'); posTagRENull = strchr(searchString, 0); if(!posTagREEnd || (posTagREEnd[1] != '"') || (posTagRENull[-1] == searchString[0])) { /* -> original ctags format = exuberant ctags format 1 */ posTagREEnd = posTagRENull; } else { /* looks like exuberant ctags format 2 */ *posTagREEnd = 0; } /* ** Hide the last delimiter: ** // becomes / ** ?? becomes ? ** This will save a little work in fakeRegExSearch. */ if(posTagREEnd > (searchString+2)) { posTagREEnd--; if(searchString[0] == *posTagREEnd) *posTagREEnd=0; } } else { pos=atoi(searchString); *searchString=0; } /* No ability to read language mode right now */ return addTag(name, file, PLAIN_LANGUAGE_MODE, searchString, pos, tagPath, index); } /* * Scans one from an etags (emacs) tags file () in tagPath. * recLevel = current recursion level for tags file including * file = destination definition file. possibly modified. len=MAXPATHLEN! * Return value: Number of tag specs added. */ static int scanETagsLine(const char *line, const char * tagPath, int index, char * file, int recLevel) { char name[MAXLINE], searchString[MAXLINE]; char incPath[MAXPATHLEN]; int pos, len; char *posDEL, *posSOH, *posCOM; /* check for destination file separator */ if(line[0]==12) { /* */ *file=0; return 0; } /* check for standard definition line */ posDEL=strchr(line, '\177'); posSOH=strchr(line, '\001'); posCOM=strrchr(line, ','); if(*file && posDEL && (posSOH > posDEL) && (posCOM > posSOH)) { /* exuberant ctags -e style */ len=Min(MAXLINE-1, posDEL - line); strncpy(searchString, line, len); searchString[len]=0; len=Min(MAXLINE-1, (posSOH - posDEL) - 1); strncpy(name, posDEL + 1, len); name[len]=0; pos=atoi(posCOM+1); /* No ability to set language mode for the moment */ return addTag(name, file, PLAIN_LANGUAGE_MODE, searchString, pos, tagPath, index); } if (*file && posDEL && (posCOM > posDEL)) { /* old etags style, part name is missing here! */ len=Min(MAXLINE-1, posDEL - line); strncpy(searchString, line, len); searchString[len]=0; /* guess name: take the last alnum (plus _) part of searchString */ while(--len >= 0) { if( isalnum((unsigned char)searchString[len]) || (searchString[len] == '_')) break; } if(len<0) return 0; pos=len; while (pos >= 0 && (isalnum((unsigned char)searchString[pos]) || (searchString[pos] == '_'))) pos--; strncpy(name, searchString + pos + 1, len - pos); name[len - pos] = 0; /* name ready */ pos=atoi(posCOM+1); return addTag(name, file, PLAIN_LANGUAGE_MODE, searchString, pos, tagPath, index); } /* check for destination file spec */ if(*line && posCOM) { len=Min(MAXPATHLEN-1, posCOM - line); strncpy(file, line, len); file[len]=0; /* check if that's an include file ... */ if(!(strncmp(posCOM+1, "include", 7))) { if(*file != '/') { if((strlen(tagPath) + strlen(file)) >= MAXPATHLEN) { fprintf(stderr, "tags.c: MAXPATHLEN overflow\n"); *file=0; /* invalidate */ return 0; } strcpy(incPath, tagPath); strcat(incPath, file); CompressPathname(incPath); return(loadTagsFile(incPath, index, recLevel+1)); } else { return(loadTagsFile(file, index, recLevel+1)); } } } return 0; } /* Tag File Type */ typedef enum { TFT_CHECK, TFT_ETAGS, TFT_CTAGS } TFT; /* ** Loads tagsFile into the hash table. ** Returns the number of added tag specifications. */ static int loadTagsFile(const char *tagsFile, int index, int recLevel) { FILE *fp = NULL; char line[MAXLINE]; char file[MAXPATHLEN], tagPath[MAXPATHLEN]; char resolvedTagsFile[MAXPATHLEN+1]; int nTagsAdded=0; int tagFileType = TFT_CHECK; if(recLevel > MAX_TAG_INCLUDE_RECURSION_LEVEL) { return 0; } /* the path of the tags file must be resolved to find the right files: * definition source files are (in most cases) specified relatively inside * the tags file to the tags files directory. */ if(!ResolvePath(tagsFile, resolvedTagsFile)) { return 0; } /* Open the file */ if ((fp = fopen(resolvedTagsFile, "r")) == NULL) { return 0; } ParseFilename(resolvedTagsFile, NULL, tagPath); /* Read the file and store its contents */ while (fgets(line, MAXLINE, fp)) { /* This might take a while if you have a huge tags file (like I do).. keep the windows up to date and post a busy cursor so the user doesn't think we died. */ AllWindowsBusy("Loading tags file..."); /* the first character in the file decides if the file is treat as etags or ctags file. */ if(tagFileType==TFT_CHECK) { if(line[0]==12) /* */ tagFileType=TFT_ETAGS; else tagFileType=TFT_CTAGS; } if(tagFileType==TFT_CTAGS) { nTagsAdded += scanCTagsLine(line, tagPath, index); } else { nTagsAdded += scanETagsLine(line, tagPath, index, file, recLevel); } } fclose(fp); AllWindowsUnbusy(); return nTagsAdded; } /* ** Given a tag name, lookup the file and path of the definition ** and the proper search string. Returned strings are pointers ** to internal storage which are valid until the next loadTagsFile call. ** ** Invocation with name != NULL (containing the searched definition) ** --> returns first definition of name ** Successive invocation with name == NULL ** --> returns further definitions (resulting from multiple tags files) ** ** Return Value: TRUE: tag spec found ** FALSE: no (more) definitions found. */ #define TAG_STS_ERR_FMT "NEdit: Error getting status for tag file %s\n" int LookupTag(const char *name, const char **file, int *language, const char **searchString, int * pos, const char **path, int search_type) { tag *t; tagFile *tf; struct stat statbuf; tagFile *FileList; int load_status; searchMode = search_type; if (searchMode == TIP) FileList = TipsFileList; else FileList = TagsFileList; /* ** Go through the list of all tags Files: ** - load them (if not already loaded) ** - check for update of the tags file and reload it in that case ** - save the modification date of the tags file ** ** Do this only as long as name != NULL, not for sucessive calls ** to find multiple tags specs. ** */ for (tf = FileList; tf && name; tf = tf->next) { if (tf->loaded) { if (stat(tf->filename,&statbuf) != 0) { /* */ fprintf(stderr, TAG_STS_ERR_FMT, tf->filename); } else { if (tf->date == statbuf.st_mtime) { /* current tags file tf is already loaded and up to date */ continue; } } /* tags file has been modified, delete it's entries and reload it */ delTag(NULL,NULL,-2,NULL,-2,tf->index); } /* If we get here we have to try to (re-) load the tags file */ if (FileList == TipsFileList) load_status = loadTipsFile(tf->filename, tf->index, 0); else load_status = loadTagsFile(tf->filename, tf->index, 0); if(load_status) { if (stat(tf->filename,&statbuf) != 0) { if(!tf->loaded) { /* if tf->loaded == 1 we already have seen the error msg */ fprintf(stderr, TAG_STS_ERR_FMT, tf->filename); } } else { tf->date = statbuf.st_mtime; } tf->loaded = 1; } else { tf->loaded = 0; } } t = getTag(name, search_type); if (!t) { return FALSE; } else { *file = t->file; *language = t->language; *searchString = t->searchString; *pos = t->posInf; *path = t->path; return TRUE; } } /* ** This code path is followed if the request came from either ** FindDefinition or FindDefCalltip. This should probably be refactored. */ static int findDef(WindowInfo *window, const char *value, int search_type) { static char tagText[MAX_TAG_LEN + 1]; const char *p; char message[MAX_TAG_LEN+40]; int l, ml, status = 0; searchMode = search_type; l = strlen(value); if (l <= MAX_TAG_LEN) { /* should be of type text??? */ for (p = value; *p && isascii(*p); p++) { } if (!(*p)) { ml = ((l < MAX_TAG_LEN) ? (l) : (MAX_TAG_LEN)); strncpy(tagText, value, ml); tagText[ml] = '\0'; /* See if we can find the tip/tag */ status = findAllMatches(window, tagText); /* If we didn't find a requested calltip, see if we can use a tag */ if (status == 0 && search_type == TIP && TagsFileList != NULL) { searchMode = TIP_FROM_TAG; status = findAllMatches(window, tagText); } if (status == 0) { /* Didn't find any matches */ if (searchMode == TIP_FROM_TAG || searchMode == TIP) { sprintf(message, "No match for \"%s\" in calltips or tags.", tagName); tagsShowCalltip( window, message ); } else { DialogF(DF_WARN, window->textArea, 1, "Tags", "\"%s\" not found in tags file%s", "OK", tagName, (TagsFileList && TagsFileList->next) ? "s" : ""); } } } else { fprintf(stderr, "NEdit: Can't handle non 8-bit text\n"); XBell(TheDisplay, 0); } } else { fprintf(stderr, "NEdit: Tag Length too long.\n"); XBell(TheDisplay, 0); } return status; } /* ** Lookup the definition for the current primary selection the currently ** loaded tags file and bring up the file and line that the tags file ** indicates. */ static void findDefinitionHelper(WindowInfo *window, Time time, const char *arg, int search_type) { if(arg) { findDef(window, arg, search_type); } else { searchMode = search_type; XtGetSelectionValue(window->textArea, XA_PRIMARY, XA_STRING, (XtSelectionCallbackProc)findDefCB, window, time); } } /* ** See findDefHelper */ void FindDefinition(WindowInfo *window, Time time, const char *arg) { findDefinitionHelper(window, time, arg, TAG); } /* ** See findDefHelper */ void FindDefCalltip(WindowInfo *window, Time time, const char *arg) { /* Reset calltip parameters to reasonable defaults */ globAnchored = False; globPos = -1; globHAlign = TIP_LEFT; globVAlign = TIP_BELOW; globAlignMode = TIP_SLOPPY; findDefinitionHelper(window, time, arg, TIP); } /* Callback function for FindDefinition */ static void findDefCB(Widget widget, WindowInfo *window, Atom *sel, Atom *type, char *value, int *length, int *format) { /* skip if we can't get the selection data, or it's obviously too long */ if (*type == XT_CONVERT_FAIL || value == NULL) { XBell(TheDisplay, 0); } else { findDef(window, value, searchMode); } XtFree(value); } /* ** Try to display a calltip ** anchored: If true, tip appears at position pos ** lookup: If true, text is considered a key to be searched for in the ** tip and/or tag database depending on search_type ** search_type: Either TIP or TIP_FROM_TAG */ int ShowTipString(WindowInfo *window, char *text, Boolean anchored, int pos, Boolean lookup, int search_type, int hAlign, int vAlign, int alignMode) { if (search_type == TAG) return 0; /* So we don't have to carry all of the calltip alignment info around */ globAnchored = anchored; globPos = pos; globHAlign = hAlign; globVAlign = vAlign; globAlignMode = alignMode; /* If this isn't a lookup request, just display it. */ if (!lookup) return tagsShowCalltip(window, text); else return findDef(window, text, search_type); } /* store all of the info into a pre-allocated tags struct */ static void setTag(tag *t, const char *name, const char *file, int language, const char *searchString, int posInf, const char *path) { t->name = rcs_strdup(name); t->file = rcs_strdup(file); t->language = language; t->searchString = rcs_strdup(searchString); t->posInf = posInf; t->path = rcs_strdup(path); } /* ** ctags search expressions are literal strings with a search direction flag, ** line starting "^" and ending "$" delimiters. This routine translates them ** into NEdit compatible regular expressions and does the search. ** Etags search expressions are plain literals strings, which ** ** If in_buffer is not NULL then it is searched instead of the window buffer. ** In this case in_buffer should be an XtMalloc allocated buffer and the ** caller is responsible for freeing it. */ static int fakeRegExSearch(WindowInfo *window, char *in_buffer, const char *searchString, int *startPos, int *endPos) { int found, searchStartPos, dir, ctagsMode; char searchSubs[3*MAXLINE+3], *outPtr; const char *fileString, *inPtr; if (in_buffer == NULL) { /* get the entire (sigh) text buffer from the text area widget */ fileString = BufAsString(window->buffer); } else { fileString = in_buffer; } /* determine search direction and start position */ if (*startPos != -1) { /* etags mode! */ dir = SEARCH_FORWARD; searchStartPos = *startPos; ctagsMode=0; } else if (searchString[0] == '/') { dir = SEARCH_FORWARD; searchStartPos = 0; ctagsMode=1; } else if (searchString[0] == '?') { dir = SEARCH_BACKWARD; /* searchStartPos = window->buffer->length; */ searchStartPos = strlen(fileString); ctagsMode=1; } else { fprintf(stderr, "NEdit: Error parsing tag file search string"); return FALSE; } /* Build the search regex. */ outPtr=searchSubs; if(ctagsMode) { inPtr=searchString+1; /* searchString[0] is / or ? --> search dir */ if(*inPtr == '^') { /* If the first char is a caret then it's a RE line start delim */ *outPtr++ = *inPtr++; } } else { /* etags mode, no search dir spec, no leading caret */ inPtr=searchString; } while(*inPtr) { if( (*inPtr=='\\' && inPtr[1]=='/') || (*inPtr=='\r' && inPtr[1]=='$' && !inPtr[2]) ) { /* Remove: - escapes (added by standard and exuberant ctags) from slashes - literal CRs generated by standard ctags for DOSified sources */ inPtr++; } else if(strchr("()-[]<>{}.|^*+?&\\", *inPtr) || (*inPtr == '$' && (inPtr[1]||(!ctagsMode)))){ /* Escape RE Meta Characters to match them literally. Don't escape $ if it's the last charcter of the search expr in ctags mode; always escape $ in etags mode. */ *outPtr++ = '\\'; *outPtr++ = *inPtr++; } else if (isspace((unsigned char)*inPtr)) { /* col. multiple spaces */ *outPtr++ = '\\'; *outPtr++ = 's'; *outPtr++ = '+'; do { inPtr++ ; } while(isspace((unsigned char)*inPtr)); } else { /* simply copy all other characters */ *outPtr++ = *inPtr++; } } *outPtr=0; /* Terminate searchSubs */ found = SearchString(fileString, searchSubs, dir, SEARCH_REGEX, False, searchStartPos, startPos, endPos, NULL, NULL, NULL); if(!found && !ctagsMode) { /* position of the target definition could have been drifted before startPos, if nothing has been found by now try searching backward again from startPos. */ found = SearchString(fileString, searchSubs, SEARCH_BACKWARD, SEARCH_REGEX, False, searchStartPos, startPos, endPos, NULL, NULL, NULL); } /* return the result */ if (found) { /* *startPos and *endPos are set in SearchString*/ return TRUE; } else { /* startPos, endPos left untouched by SearchString if search failed. */ XBell(TheDisplay, 0); return FALSE; } } /* Finds all matches and handles tag "collisions". Prompts user with a list of collided tags in the hash table and allows the user to select the correct one. */ static int findAllMatches(WindowInfo *window, const char *string) { Widget dialogParent = window->textArea; char filename[MAXPATHLEN], pathname[MAXPATHLEN]; char temp[32+2*MAXPATHLEN+MAXLINE]; const char *fileToSearch, *searchString, *tagPath; char **dupTagsList; int startPos, i, pathMatch=0, samePath=0, langMode, nMatches=0; /* verify that the string is reasonable as a tag */ if (*string == '\0' || strlen(string) > MAX_TAG_LEN) { XBell(TheDisplay, 0); return -1; } tagName=string; /* First look up all of the matching tags */ while (LookupTag(string, &fileToSearch, &langMode, &searchString, &startPos, &tagPath, searchMode)) { /* Skip this tag if it has a language mode that doesn't match the current language mode, but don't skip anything if the window is in PLAIN_LANGUAGE_MODE. */ if (window->languageMode != PLAIN_LANGUAGE_MODE && GetPrefSmartTags() && langMode != PLAIN_LANGUAGE_MODE && langMode != window->languageMode) { string=NULL; continue; } if (*fileToSearch == '/') strcpy(tagFiles[nMatches], fileToSearch); else sprintf(tagFiles[nMatches],"%s%s",tagPath,fileToSearch); strcpy(tagSearch[nMatches],searchString); tagPosInf[nMatches]=startPos; ParseFilename(tagFiles[nMatches], filename, pathname); /* Is this match in the current file? If so, use it! */ if (GetPrefSmartTags() && !strcmp(window->filename,filename) && !strcmp(window->path,pathname) ) { if (nMatches) { strcpy(tagFiles[0],tagFiles[nMatches]); strcpy(tagSearch[0],tagSearch[nMatches]); tagPosInf[0]=tagPosInf[nMatches]; } nMatches = 1; break; } /* Is this match in the same dir. as the current file? */ if (!strcmp(window->path,pathname)) { samePath++; pathMatch=nMatches; } if (++nMatches >= MAXDUPTAGS) { DialogF(DF_WARN, dialogParent, 1, "Tags", "Too many duplicate tags, first %d shown", "OK", MAXDUPTAGS); break; } /* Tell LookupTag to look for more definitions of the same tag: */ string = NULL; } /* Did we find any matches? */ if (!nMatches) { return 0; } /* Only one of the matches is in the same dir. as this file. Use it. */ if (GetPrefSmartTags() && samePath == 1 && nMatches > 1) { strcpy(tagFiles[0],tagFiles[pathMatch]); strcpy(tagSearch[0],tagSearch[pathMatch]); tagPosInf[0]=tagPosInf[pathMatch]; nMatches = 1; } /* If all of the tag entries are the same file, just use the first. */ if (GetPrefSmartTags()) { for (i=1; i1) { if (!(dupTagsList = (char **) malloc(sizeof(char *) * nMatches))) { fprintf(stderr, "nedit: findAllMatches(): out of heap space!\n"); XBell(TheDisplay, 0); return -1; } for (i=0; i0 && !strcmp(tagFiles[i],tagFiles[i-1]))) { if(*(tagSearch[i]) && (tagPosInf[i] != -1)) { /* etags */ sprintf(temp,"%2d. %s%s %8i %s", i+1, pathname, filename, tagPosInf[i], tagSearch[i]); } else if (*(tagSearch[i])) { /* ctags search expr */ sprintf(temp,"%2d. %s%s %s", i+1, pathname, filename, tagSearch[i]); } else { /* line number only */ sprintf(temp,"%2d. %s%s %8i", i+1, pathname, filename, tagPosInf[i]); } } else { sprintf(temp,"%2d. %s%s",i+1,pathname,filename); } if (NULL == (dupTagsList[i] = (char*) malloc(strlen(temp) + 1))) { int j; fprintf(stderr, "nedit: findAllMatches(): out of heap space!\n"); /* dupTagsList[i] is unallocated, let's free [i - 1] to [0] */ for (j = i - 1; j > -1; j--) { free(dupTagsList[j]); } free(dupTagsList); XBell(TheDisplay, 0); return -1; } strcpy(dupTagsList[i],temp); } createSelectMenu(dialogParent, "Duplicate Tags", nMatches, dupTagsList); for (i=0; ireason == XmCR_NO_MATCH) return; if (cbs->reason == XmCR_CANCEL) { XtDestroyWidget(XtParent(parent)); return; } XmStringGetLtoR(cbs->value,XmFONTLIST_DEFAULT_TAG,&eptr); if ((i = atoi(eptr)-1) < 0) { XBell(TheDisplay, 0); return; } if (searchMode == TAG) editTaggedLocation( parent, i ); /* Open the file with the definition */ else showMatchingCalltip( parent, i ); if (cbs->reason == XmCR_OK) XtDestroyWidget(XtParent(parent)); } /* Window manager close-box callback for tag-collision dialog */ static void findAllCloseCB(Widget parent, XtPointer client_data, XtPointer call_data) { XtDestroyWidget(parent); } /* * Given a \0 terminated string and a position, advance the position * by n lines, where line separators (for now) are \n. If the end of * string is reached before n lines, return the number of lines advanced, * else normally return -1. */ static int moveAheadNLines( char *str, int *pos, int n ) { int i=n; while (str[*pos] != '\0' && n>0) { if (str[*pos] == '\n') --n; ++(*pos); } if (n==0) return -1; else return i-n; } /* ** Show the calltip specified by tagFiles[i], tagSearch[i], tagPosInf[i] ** This reads from either a source code file (if searchMode == TIP_FROM_TAG) ** or a calltips file (if searchMode == TIP). */ static void showMatchingCalltip( Widget parent, int i ) { int startPos=0, fileLen, readLen, tipLen; int endPos=0; char *fileString; FILE *fp; struct stat statbuf; char *message; /* 1. Open the target file */ NormalizePathname(tagFiles[i]); fp = fopen(tagFiles[i], "r"); if (fp == NULL) { DialogF(DF_ERR, parent, 1, "Error opening File", "Error opening %s", "OK", tagFiles[i]); return; } if (fstat(fileno(fp), &statbuf) != 0) { fclose(fp); DialogF(DF_ERR, parent, 1, "Error opening File", "Error opening %s", "OK", tagFiles[i]); return; } /* 2. Read the target file */ /* Allocate space for the whole contents of the file (unfortunately) */ fileLen = statbuf.st_size; fileString = XtMalloc(fileLen+1); /* +1 = space for null */ if (fileString == NULL) { fclose(fp); DialogF(DF_ERR, parent, 1, "File too large", "File is too large to load", "OK"); return; } /* Read the file into fileString and terminate with a null */ readLen = fread(fileString, sizeof(char), fileLen, fp); if (ferror(fp)) { fclose(fp); DialogF(DF_ERR, parent, 1, "Error reading File", "Error reading %s", "OK", tagFiles[i]); XtFree(fileString); return; } fileString[readLen] = 0; /* Close the file */ if (fclose(fp) != 0) { /* unlikely error */ DialogF(DF_WARN, parent, 1, "Error closing File", "Unable to close file", "OK"); /* we read it successfully, so continue */ } /* 3. Search for the tagged location (set startPos) */ if (!*(tagSearch[i])) { /* It's a line number, just go for it */ if ((moveAheadNLines( fileString, &startPos, tagPosInf[i]-1 )) >= 0) { DialogF(DF_ERR, parent, 1, "Tags Error", "%s\n not long enough for definition to be on line %d", "OK", tagFiles[i], tagPosInf[i]); XtFree(fileString); return; } } else { startPos = tagPosInf[i]; if(!fakeRegExSearch(WidgetToWindow(parent), fileString, tagSearch[i], &startPos, &endPos)){ DialogF(DF_WARN, parent, 1, "Tag not found", "Definition for %s\nnot found in %s", "OK", tagName, tagFiles[i]); XtFree(fileString); return; } } if (searchMode == TIP) { int dummy, found; /* 4. Find the end of the calltip (delimited by an empty line) */ endPos = startPos; found = SearchString(fileString, "\\n\\s*\\n", SEARCH_FORWARD, SEARCH_REGEX, False, startPos, &endPos, &dummy, NULL, NULL, NULL); if (!found) { /* Just take 4 lines */ moveAheadNLines( fileString, &endPos, TIP_DEFAULT_LINES ); --endPos; /* Lose the last \n */ } } else { /* Mode = TIP_FROM_TAG */ /* 4. Copy TIP_DEFAULT_LINES lines of text to the calltip string */ endPos = startPos; moveAheadNLines( fileString, &endPos, TIP_DEFAULT_LINES ); /* Make sure not to overrun the fileString with ". . ." */ if (((size_t) endPos) <= (strlen(fileString)-5)) { sprintf( &fileString[endPos], ". . ." ); endPos += 5; } } /* 5. Copy the calltip to a string */ tipLen = endPos - startPos; message = XtMalloc(tipLen+1); /* +1 = space for null */ if (message == NULL) { DialogF(DF_ERR, parent, 1, "Out of Memory", "Can't allocate memory for calltip message", "OK"); XtFree(fileString); return; } strncpy( message, &fileString[startPos], tipLen ); message[tipLen] = 0; /* 6. Display it */ tagsShowCalltip( WidgetToWindow(parent), message ); XtFree(message); XtFree(fileString); } /* Open a new (or existing) editor window to the location specified in tagFiles[i], tagSearch[i], tagPosInf[i] */ static void editTaggedLocation( Widget parent, int i ) { /* Globals: tagSearch, tagPosInf, tagFiles, tagName, textNrows, WindowList */ int startPos, endPos, lineNum, rows; char filename[MAXPATHLEN], pathname[MAXPATHLEN]; WindowInfo *windowToSearch; WindowInfo *parentWindow = WidgetToWindow(parent); ParseFilename(tagFiles[i],filename,pathname); /* open the file containing the definition */ EditExistingFile(parentWindow, filename, pathname, 0, NULL, False, NULL, GetPrefOpenInTab(), False); windowToSearch = FindWindowWithFile(filename, pathname); if (windowToSearch == NULL) { DialogF(DF_WARN, parent, 1, "File not found", "File %s not found", "OK", tagFiles[i]); return; } startPos=tagPosInf[i]; if(!*(tagSearch[i])) { /* if the search string is empty, select the numbered line */ SelectNumberedLine(windowToSearch, startPos); return; } /* search for the tags file search string in the newly opened file */ if(!fakeRegExSearch(windowToSearch, NULL, tagSearch[i], &startPos, &endPos)){ DialogF(DF_WARN, windowToSearch->shell, 1, "Tag Error", "Definition for %s\nnot found in %s", "OK", tagName, tagFiles[i]); return; } /* select the matched string */ BufSelect(windowToSearch->buffer, startPos, endPos); RaiseFocusDocumentWindow(windowToSearch, True); /* Position it nicely in the window, about 1/4 of the way down from the top */ lineNum = BufCountLines(windowToSearch->buffer, 0, startPos); XtVaGetValues(windowToSearch->lastFocus, textNrows, &rows, NULL); TextSetScroll(windowToSearch->lastFocus, lineNum - rows/4, 0); TextSetCursorPos(windowToSearch->lastFocus, endPos); } /* Create a Menu for user to select from the collided tags */ static Widget createSelectMenu(Widget parent, char *label, int nArgs, char *args[]) { int i; char tmpStr[100]; Widget menu; XmStringTable list; XmString popupTitle; int ac; Arg csdargs[20]; list = (XmStringTable) XtMalloc(nArgs * sizeof(XmString *)); for (i=0; inext) { if (!strcmp(str, rp->string)) break; prev = rp; } if (rp) /* It exists, return it and bump ref ct */ { rp->usage++; newstr = rp->string; RcsStats.tshar++; RcsStats.tbyteshared += len; } else /* Doesn't exist, conjure up a new one. */ { struct rcs* newrcs; if (NULL == (newrcs = (struct rcs*) malloc(sizeof(struct rcs)))) { /* Not much to fall back to here. */ fprintf(stderr, "nedit: rcs_strdup(): out of heap space!\n"); XBell(TheDisplay, 0); exit(1); } if (NULL == (newrcs->string = (char*) malloc(len + 1))) { /* Not much to fall back to here. */ fprintf(stderr, "nedit: rcs_strdup(): out of heap space!\n"); XBell(TheDisplay, 0); exit(1); } strcpy(newrcs->string, str); newrcs->usage = 1; newrcs->next = NULL; if (Rcs[bucket]) prev->next = newrcs; else Rcs[bucket] = newrcs; newstr = newrcs->string; } RcsStats.tbytes += len; return newstr; } /* ** Decrease the reference count on a shared string. When the reference ** count reaches zero, free the master string. */ static void rcs_free(const char *rcs_str) { int bucket; struct rcs *rp; struct rcs *prev = NULL; if (rcs_str == NULL) return; bucket = hashAddr(rcs_str) % RCS_SIZE; /* find it in hash */ for (rp = Rcs[bucket]; rp; rp = rp->next) { if (rcs_str == rp->string) break; prev = rp; } if (rp) /* It's a shared string, decrease ref count */ { rp->usage--; if (rp->usage < 0) /* D'OH! */ { fprintf(stderr, "NEdit: internal error deallocating shared string."); return; } if (rp->usage == 0) /* Last one- free the storage */ { free(rp->string); if (prev) prev->next = rp->next; else Rcs[bucket] = rp->next; free(rp); } } else /* Doesn't appear to be a shared string */ { fprintf(stderr, "NEdit: attempt to free a non-shared string."); return; } } /******************************************************************** * Functions for loading Calltips files * ********************************************************************/ enum tftoken_types { TF_EOF, TF_BLOCK, TF_VERSION, TF_INCLUDE, TF_LANGUAGE, TF_ALIAS, TF_ERROR, TF_ERROR_EOF }; /* A wrapper for SearchString */ static int searchLine(char *line, const char *regex) { int dummy1, dummy2; return SearchString(line, regex, SEARCH_FORWARD, SEARCH_REGEX, False, 0, &dummy1, &dummy2, NULL, NULL, NULL); } /* Check if a line has non-ws characters */ static Boolean lineEmpty(const char *line) { while (*line && *line != '\n') { if (*line != ' ' && *line != '\t') return False; ++line; } return True; } /* Remove trailing whitespace from a line */ static void rstrip( char *dst, const char *src ) { int wsStart, dummy2; /* Strip trailing whitespace */ if(SearchString(src, "\\s*\\n", SEARCH_FORWARD, SEARCH_REGEX, False, 0, &wsStart, &dummy2, NULL, NULL, NULL)) { if(dst != src) memcpy(dst, src, wsStart); dst[wsStart] = 0; } else if(dst != src) strcpy(dst, src); } /* ** Get the next block from a tips file. A block is a \n\n+ delimited set of ** lines in a calltips file. All of the parameters except are return ** values, and most have different roles depending on the type of block ** that is found. ** header: Depends on the block type ** body: Depends on the block type. Used to return a new ** dynamically allocated string. ** blkLine: Returns the line number of the first line of the block ** after the "* xxxx *" line. ** currLine: Used to keep track of the current line in the file. */ static int nextTFBlock(FILE *fp, char *header, char **body, int *blkLine, int *currLine) { /* These are the different kinds of tokens */ const char *commenTF_regex = "^\\s*\\* comment \\*\\s*$"; const char *version_regex = "^\\s*\\* version \\*\\s*$"; const char *include_regex = "^\\s*\\* include \\*\\s*$"; const char *language_regex = "^\\s*\\* language \\*\\s*$"; const char *alias_regex = "^\\s*\\* alias \\*\\s*$"; char line[MAXLINE], *status; int dummy1; int code; /* Skip blank lines and comments */ while(1) { /* Skip blank lines */ while((status=fgets(line, MAXLINE, fp))) { ++(*currLine); if(!lineEmpty( line )) break; } /* Check for error or EOF */ if(!status) return TF_EOF; /* We've got a non-blank line -- is it a comment block? */ if( !searchLine(line, commenTF_regex) ) break; /* Skip the comment (non-blank lines) */ while((status=fgets(line, MAXLINE, fp))) { ++(*currLine); if(lineEmpty( line )) break; } if(!status) return TF_EOF; } /* Now we know it's a meaningful block */ dummy1 = searchLine(line, include_regex); if( dummy1 || searchLine(line, alias_regex) ) { /* INCLUDE or ALIAS block */ int incLen, incPos, i, incLines; /* fprintf(stderr, "Starting include/alias at line %i\n", *currLine); */ if(dummy1) code = TF_INCLUDE; else { code = TF_ALIAS; /* Need to read the header line for an alias */ status=fgets(line, MAXLINE, fp); ++(*currLine); if (!status) return TF_ERROR_EOF; if (lineEmpty( line )) { fprintf( stderr, "nedit: Warning: empty '* alias *' " "block in calltips file.\n" ); return TF_ERROR; } rstrip(header, line); } incPos = ftell(fp); *blkLine = *currLine + 1; /* Line of first actual filename/alias */ if (incPos < 0) return TF_ERROR; /* Figure out how long the block is */ while((status=fgets(line, MAXLINE, fp))) { ++(*currLine); if(lineEmpty( line )) break; } incLen = ftell(fp) - incPos; incLines = *currLine - *blkLine; /* Correct currLine for the empty line it read at the end */ --(*currLine); if (incLines == 0) { fprintf( stderr, "nedit: Warning: empty '* include *' or" " '* alias *' block in calltips file.\n" ); return TF_ERROR; } /* Make space for the filenames/alias sources */ *body = (char *)malloc(incLen+1); if (!*body) return TF_ERROR; *body[0]=0; if (fseek(fp, incPos, SEEK_SET) != 0) { free (*body); return TF_ERROR; } /* Read all the lines in the block */ /* fprintf(stderr, "Copying lines\n"); */ for (i=0; idest = (char*)malloc( strlen(dest)+1 ); if(!(alias->dest)) return NULL; strcpy( alias->dest, dest ); alias->sources = sources; return alias; } /* Deallocate a linked-list of aliases */ static void free_alias_list(tf_alias *alias) { tf_alias *tmp_alias; while(alias) { tmp_alias = alias->next; free(alias->dest); free(alias->sources); free(alias); alias = tmp_alias; } } /* ** Load a calltips file and insert all of the entries into the global tips ** database. Each tip is essentially stored as its filename and the line ** at which it appears--the exact same way ctags indexes source-code. That's ** why calltips and tags share so much code. */ static int loadTipsFile(const char *tipsFile, int index, int recLevel) { FILE *fp = NULL; char header[MAXLINE]; char *body, *tipIncFile; char tipPath[MAXPATHLEN]; char resolvedTipsFile[MAXPATHLEN+1]; int nTipsAdded=0, langMode = PLAIN_LANGUAGE_MODE, oldLangMode; int currLine=0, code, blkLine; tf_alias *aliases=NULL, *tmp_alias; if(recLevel > MAX_TAG_INCLUDE_RECURSION_LEVEL) { fprintf(stderr, "nedit: Warning: Reached recursion limit before loading calltips file:\n\t%s\n", tipsFile); return 0; } /* find the tips file */ #ifndef VMS /* Allow ~ in Unix filenames */ strncpy(tipPath, tipsFile, MAXPATHLEN); /* ExpandTilde is destructive */ ExpandTilde(tipPath); if(!ResolvePath(tipPath, resolvedTipsFile)) return 0; #else if(!ResolvePath(tipsFile, resolvedTipsFile)) return 0; #endif /* Get the path to the tips file */ ParseFilename(resolvedTipsFile, NULL, tipPath); /* Open the file */ if ((fp = fopen(resolvedTipsFile, "r")) == NULL) return 0; while( 1 ) { code = nextTFBlock(fp, header, &body, &blkLine, &currLine); if( code == TF_ERROR_EOF ) { fprintf(stderr,"nedit: Warning: unexpected EOF in calltips file.\n"); break; } if( code == TF_EOF ) break; switch (code) { case TF_BLOCK: /* Add the calltip to the global hash table. For the moment I'm just using line numbers because I don't want to have to deal with adding escape characters for regex metacharacters that might appear in the string */ nTipsAdded += addTag(header, resolvedTipsFile, langMode, "", blkLine, tipPath, index); free( body ); break; case TF_INCLUDE: /* nextTFBlock returns a colon-separated list of tips files in body */ for(tipIncFile=strtok(body,":"); tipIncFile; tipIncFile=strtok(NULL,":")) { /* fprintf(stderr, "nedit: DEBUG: including tips file '%s'\n", tipIncFile); */ nTipsAdded += loadTipsFile( tipIncFile, index, recLevel+1); } free( body ); break; case TF_LANGUAGE: /* Switch to the new language mode if it's valid, else ignore it. */ oldLangMode = langMode; langMode = FindLanguageMode( header ); if (langMode == PLAIN_LANGUAGE_MODE && strcmp(header, "Plain")) { fprintf(stderr, "nedit: Error reading calltips file:\n\t%s\n" "Unknown language mode: \"%s\"\n", tipsFile, header); langMode = oldLangMode; } break; case TF_ERROR: fprintf(stderr,"nedit: Warning: Recoverable error while " "reading calltips file:\n \"%s\"\n", resolvedTipsFile); break; case TF_ALIAS: /* Allocate a new alias struct */ tmp_alias = aliases; aliases = new_alias(header, body); if( !aliases ) { fprintf(stderr,"nedit: Can't allocate memory for tipfile " "alias in calltips file:\n \"%s\"\n", resolvedTipsFile); /* Deallocate any allocated aliases */ free_alias_list(tmp_alias); return 0; } /* Add it to the list */ aliases->next = tmp_alias; break; default: ;/* Ignore TF_VERSION for now */ } } /* Now resolve any aliases */ tmp_alias = aliases; while (tmp_alias) { tag *t; char *src; t = getTag(tmp_alias->dest, TIP); if (!t) { fprintf(stderr, "nedit: Can't find destination of alias \"%s\"\n" " in calltips file:\n \"%s\"\n", tmp_alias->dest, resolvedTipsFile); } else { for(src=strtok(tmp_alias->sources,":"); src; src=strtok(NULL,":")) addTag(src, resolvedTipsFile, t->language, "", t->posInf, tipPath, index); } tmp_alias = tmp_alias->next; } free_alias_list(aliases); return nTipsAdded; } nedit-5.6.orig/source/tags.h0000644000175000017500000000724610204245770014533 0ustar paulpaul/* $Id: tags.h,v 1.16 2005/02/15 01:10:16 n8gray Exp $ */ /******************************************************************************* * * * tags.h -- Nirvana Editor Tags Header File * * * * Copyright 2002 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_TAGS_H_INCLUDED #define NEDIT_TAGS_H_INCLUDED #include "nedit.h" #include #include #include typedef struct _tagFile { struct _tagFile *next; char *filename; time_t date; Boolean loaded; short index; short refcount; /* Only tips files are refcounted, not tags files */ } tagFile; extern tagFile *TagsFileList; /* list of loaded tags files */ extern tagFile *TipsFileList; /* list of loaded calltips tag files */ /* file_type and search_type arguments are to select between tips and tags, and should be one of TAG or TIP. TIP_FROM_TAG is for ShowTipString. */ enum mode {TAG, TIP_FROM_TAG, TIP}; int AddRelTagsFile(const char *tagSpec, const char *windowPath, int file_type); /* tagSpec is a colon-delimited list of filenames */ int AddTagsFile(const char *tagSpec, int file_type); int DeleteTagsFile(const char *tagSpec, int file_type, Boolean force_unload); int LookupTag(const char *name, const char **file, int *lang, const char **searchString, int * pos, const char **path, int search_type); /* Routines for handling tags or tips from the current selection */ void FindDefinition(WindowInfo *window, Time time, const char *arg); void FindDefCalltip(WindowInfo *window, Time time, const char *arg); /* Display (possibly finding first) a calltip. Search type can only be TIP or TIP_FROM_TAG here. */ int ShowTipString(WindowInfo *window, char *text, Boolean anchored, int pos, Boolean lookup, int search_type, int hAlign, int vAlign, int alignMode); #endif /* NEDIT_TAGS_H_INCLUDED */ nedit-5.6.orig/source/text.c0000644000175000017500000046115510737527370014571 0ustar paulpaulstatic const char CVSID[] = "$Id: text.c,v 1.57 2008/01/04 22:11:04 yooden Exp $"; /******************************************************************************* * * * text.c - Display text from a text buffer * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * June 15, 1995 * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "text.h" #include "textP.h" #include "textBuf.h" #include "textDisp.h" #include "textSel.h" #include "textDrag.h" #include "nedit.h" #include "calltips.h" #include "../util/DialogF.h" #include "window.h" #include #include #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #include #include #include #include #include #include #include #if XmVersion >= 1002 #include #endif #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #ifdef UNICOS #define XtOffset(p_type,field) ((size_t)__INTADDR__(&(((p_type)0)->field))) #endif /* Number of pixels of motion from the initial (grab-focus) button press required to begin recognizing a mouse drag for the purpose of making a selection */ #define SELECT_THRESHOLD 5 /* Length of delay in milliseconds for vertical autoscrolling */ #define VERTICAL_SCROLL_DELAY 50 static void initialize(TextWidget request, TextWidget new); static void handleHidePointer(Widget w, XtPointer unused, XEvent *event, Boolean *continue_to_dispatch); static void handleShowPointer(Widget w, XtPointer unused, XEvent *event, Boolean *continue_to_dispatch); static void redisplay(TextWidget w, XEvent *event, Region region); static void redisplayGE(TextWidget w, XtPointer client_data, XEvent *event, Boolean *continue_to_dispatch_return); static void destroy(TextWidget w); static void resize(TextWidget w); static Boolean setValues(TextWidget current, TextWidget request, TextWidget new); static void realize(Widget w, XtValueMask *valueMask, XSetWindowAttributes *attributes); static XtGeometryResult queryGeometry(Widget w, XtWidgetGeometry *proposed, XtWidgetGeometry *answer); static void grabFocusAP(Widget w, XEvent *event, String *args, Cardinal *n_args); static void moveDestinationAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void extendAdjustAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void extendStartAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void extendEndAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void processCancelAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void secondaryStartAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void secondaryOrDragStartAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void secondaryAdjustAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void secondaryOrDragAdjustAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void copyToAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void copyToOrEndDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void copyPrimaryAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void cutPrimaryAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void moveToAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void moveToOrEndDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void endDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void exchangeAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void mousePanAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void pasteClipboardAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void copyClipboardAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void cutClipboardAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void insertStringAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void selfInsertAP(Widget w, XEvent *event, String *args, Cardinal *n_args); static void newlineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void newlineAndIndentAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void newlineNoIndentAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void processTabAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void endOfLineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void beginningOfLineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void deleteSelectionAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void deletePreviousCharacterAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void deleteNextCharacterAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void deletePreviousWordAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void deleteNextWordAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void deleteToStartOfLineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void deleteToEndOfLineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void forwardCharacterAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void backwardCharacterAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void forwardWordAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void backwardWordAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void forwardParagraphAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void backwardParagraphAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void keySelectAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void processUpAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void processShiftUpAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void processDownAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void processShiftDownAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void beginningOfFileAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void endOfFileAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void nextPageAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void previousPageAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void pageLeftAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void pageRightAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void toggleOverstrikeAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void scrollUpAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void scrollDownAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void scrollLeftAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void scrollRightAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void scrollToLineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void selectAllAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void deselectAllAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void focusInAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void focusOutAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void checkMoveSelectionChange(Widget w, XEvent *event, int startPos, String *args, Cardinal *nArgs); static void keyMoveExtendSelection(Widget w, XEvent *event, int startPos, int rectangular); static void checkAutoShowInsertPos(Widget w); static int checkReadOnly(Widget w); static void simpleInsertAtCursor(Widget w, char *chars, XEvent *event, int allowPendingDelete); static int pendingSelection(Widget w); static int deletePendingSelection(Widget w, XEvent *event); static int deleteEmulatedTab(Widget w, XEvent *event); static void selectWord(Widget w, int pointerX); static int spanForward(textBuffer *buf, int startPos, char *searchChars, int ignoreSpace, int *foundPos); static int spanBackward(textBuffer *buf, int startPos, char *searchChars, int ignoreSpace, int *foundPos); static void selectLine(Widget w); static int startOfWord(TextWidget w, int pos); static int endOfWord(TextWidget w, int pos); static void checkAutoScroll(TextWidget w, int x, int y); static void endDrag(Widget w); static void cancelDrag(Widget w); static void callCursorMovementCBs(Widget w, XEvent *event); static void adjustSelection(TextWidget tw, int x, int y); static void adjustSecondarySelection(TextWidget tw, int x, int y); static void autoScrollTimerProc(XtPointer clientData, XtIntervalId *id); static char *wrapText(TextWidget tw, char *startLine, char *text, int bufOffset, int wrapMargin, int *breakBefore); static int wrapLine(TextWidget tw, textBuffer *buf, int bufOffset, int lineStartPos, int lineEndPos, int limitPos, int *breakAt, int *charsAdded); static char *createIndentString(TextWidget tw, textBuffer *buf, int bufOffset, int lineStartPos, int lineEndPos, int *length, int *column); static void cursorBlinkTimerProc(XtPointer clientData, XtIntervalId *id); static int hasKey(const char *key, const String *args, const Cardinal *nArgs); static int max(int i1, int i2); static int min(int i1, int i2); static int strCaseCmp(const char *str1, const char *str2); static void ringIfNecessary(Boolean silent, Widget w); static char defaultTranslations[] = /* Home */ "~Shift ~Ctrl AltosfBeginLine: last_document()\n" /* Backspace */ "CtrlosfBackSpace: delete_previous_word()\n" "osfBackSpace: delete_previous_character()\n" /* Delete */ "Alt Shift CtrlosfDelete: cut_primary(\"rect\")\n" "Meta Shift CtrlosfDelete: cut_primary(\"rect\")\n" "Shift CtrlosfDelete: cut_primary()\n" "CtrlosfDelete: delete_to_end_of_line()\n" "ShiftosfDelete: cut_clipboard()\n" "osfDelete: delete_next_character()\n" /* Insert */ "Alt Shift CtrlosfInsert: copy_primary(\"rect\")\n" "Meta Shift CtrlosfInsert: copy_primary(\"rect\")\n" "Shift CtrlosfInsert: copy_primary()\n" "ShiftosfInsert: paste_clipboard()\n" "CtrlosfInsert: copy_clipboard()\n" "~Shift ~CtrlosfInsert: set_overtype_mode()\n" /* Cut/Copy/Paste */ "Shift CtrlosfCut: cut_primary()\n" "osfCut: cut_clipboard()\n" "osfCopy: copy_clipboard()\n" "osfPaste: paste_clipboard()\n" "osfPrimaryPaste: copy_primary()\n" /* BeginLine */ "Alt Shift CtrlosfBeginLine: beginning_of_file(\"extend\", \"rect\")\n" "Meta Shift CtrlosfBeginLine: beginning_of_file(\"extend\" \"rect\")\n" "Alt ShiftosfBeginLine: beginning_of_line(\"extend\", \"rect\")\n" "Meta ShiftosfBeginLine: beginning_of_line(\"extend\", \"rect\")\n" "Shift CtrlosfBeginLine: beginning_of_file(\"extend\")\n" "CtrlosfBeginLine: beginning_of_file()\n" "ShiftosfBeginLine: beginning_of_line(\"extend\")\n" "~Alt~Shift~Ctrl~MetaosfBeginLine: beginning_of_line()\n" /* EndLine */ "Alt Shift CtrlosfEndLine: end_of_file(\"extend\", \"rect\")\n" "Meta Shift CtrlosfEndLine: end_of_file(\"extend\", \"rect\")\n" "Alt ShiftosfEndLine: end_of_line(\"extend\", \"rect\")\n" "Meta ShiftosfEndLine: end_of_line(\"extend\", \"rect\")\n" "Shift CtrlosfEndLine: end_of_file(\"extend\")\n" "CtrlosfEndLine: end_of_file()\n" "ShiftosfEndLine: end_of_line(\"extend\")\n" "~Alt~Shift~Ctrl~MetaosfEndLine: end_of_line()\n" /* Left */ "Alt Shift CtrlosfLeft: backward_word(\"extend\", \"rect\")\n" "Meta Shift CtrlosfLeft: backward_word(\"extend\", \"rect\")\n" "Alt ShiftosfLeft: key_select(\"left\", \"rect\")\n" "Meta ShiftosfLeft: key_select(\"left\", \"rect\")\n" "Shift CtrlosfLeft: backward_word(\"extend\")\n" "CtrlosfLeft: backward_word()\n" "ShiftosfLeft: key_select(\"left\")\n" "~Alt~Shift~Ctrl~MetaosfLeft: backward_character()\n" /* Right */ "Alt Shift CtrlosfRight: forward_word(\"extend\", \"rect\")\n" "Meta Shift CtrlosfRight: forward_word(\"extend\", \"rect\")\n" "Alt ShiftosfRight: key_select(\"right\", \"rect\")\n" "Meta ShiftosfRight: key_select(\"right\", \"rect\")\n" "Shift CtrlosfRight: forward_word(\"extend\")\n" "CtrlosfRight: forward_word()\n" "ShiftosfRight: key_select(\"right\")\n" "~Alt~Shift~Ctrl~MetaosfRight: forward_character()\n" /* Up */ "Alt Shift CtrlosfUp: backward_paragraph(\"extend\", \"rect\")\n" "Meta Shift CtrlosfUp: backward_paragraph(\"extend\", \"rect\")\n" "Alt ShiftosfUp: process_shift_up(\"rect\")\n" "Meta ShiftosfUp: process_shift_up(\"rect\")\n" "Shift CtrlosfUp: backward_paragraph(\"extend\")\n" "CtrlosfUp: backward_paragraph()\n" "ShiftosfUp: process_shift_up()\n" "~Alt~Shift~Ctrl~MetaosfUp: process_up()\n" /* Down */ "Alt Shift CtrlosfDown: forward_paragraph(\"extend\", \"rect\")\n" "Meta Shift CtrlosfDown: forward_paragraph(\"extend\", \"rect\")\n" "Alt ShiftosfDown: process_shift_down(\"rect\")\n" "Meta ShiftosfDown: process_shift_down(\"rect\")\n" "Shift CtrlosfDown: forward_paragraph(\"extend\")\n" "CtrlosfDown: forward_paragraph()\n" "ShiftosfDown: process_shift_down()\n" "~Alt~Shift~Ctrl~MetaosfDown: process_down()\n" /* PageUp */ "Alt Shift CtrlosfPageUp: page_left(\"extend\", \"rect\")\n" "Meta Shift CtrlosfPageUp: page_left(\"extend\", \"rect\")\n" "Alt ShiftosfPageUp: previous_page(\"extend\", \"rect\")\n" "Meta ShiftosfPageUp: previous_page(\"extend\", \"rect\")\n" "Shift CtrlosfPageUp: page_left(\"extend\")\n" "CtrlosfPageUp: previous_document()\n" "ShiftosfPageUp: previous_page(\"extend\")\n" "~Alt ~Shift ~Ctrl ~MetaosfPageUp: previous_page()\n" /* PageDown */ "Alt Shift CtrlosfPageDown: page_right(\"extend\", \"rect\")\n" "Meta Shift CtrlosfPageDown: page_right(\"extend\", \"rect\")\n" "Alt ShiftosfPageDown: next_page(\"extend\", \"rect\")\n" "Meta ShiftosfPageDown: next_page(\"extend\", \"rect\")\n" "Shift CtrlosfPageDown: page_right(\"extend\")\n" "CtrlosfPageDown: next_document()\n" "ShiftosfPageDown: next_page(\"extend\")\n" "~Alt ~Shift ~Ctrl ~MetaosfPageDown: next_page()\n" /* PageLeft and PageRight are placed later than the PageUp/PageDown bindings. Some systems map osfPageLeft to Ctrl-PageUp. Overloading this single key gives problems, and we want to give priority to the normal version. */ /* PageLeft */ "Alt ShiftosfPageLeft: page_left(\"extend\", \"rect\")\n" "Meta ShiftosfPageLeft: page_left(\"extend\", \"rect\")\n" "ShiftosfPageLeft: page_left(\"extend\")\n" "~Alt ~Shift ~Ctrl ~MetaosfPageLeft: page_left()\n" /* PageRight */ "Alt ShiftosfPageRight: page_right(\"extend\", \"rect\")\n" "Meta ShiftosfPageRight: page_right(\"extend\", \"rect\")\n" "ShiftosfPageRight: page_right(\"extend\")\n" "~Alt ~Shift ~Ctrl ~MetaosfPageRight: page_right()\n" "ShiftosfSelect: key_select()\n" "osfCancel: process_cancel()\n" "Ctrl~Alt~Metav: paste_clipboard()\n" "Ctrl~Alt~Metac: copy_clipboard()\n" "Ctrl~Alt~Metax: cut_clipboard()\n" "Ctrl~Alt~Metau: delete_to_start_of_line()\n" "CtrlReturn: newline_and_indent()\n" "ShiftReturn: newline_no_indent()\n" "Return: newline()\n" /* KP_Enter = osfActivate Note: Ctrl+KP_Enter is already bound to Execute Command Line... */ "ShiftosfActivate: newline_no_indent()\n" "osfActivate: newline()\n" "CtrlTab: self_insert()\n" "Tab: process_tab()\n" "Alt Shift Ctrlspace: key_select(\"rect\")\n" "Meta Shift Ctrlspace: key_select(\"rect\")\n" "Shift Ctrl~Meta~Altspace: key_select()\n" "Ctrl~Meta~Altslash: select_all()\n" "Ctrl~Meta~Altbackslash: deselect_all()\n" ": self_insert()\n" "Alt Ctrl: move_destination()\n" "Meta Ctrl: move_destination()\n" "Shift Ctrl: extend_start(\"rect\")\n" "Shift: extend_start()\n" ": grab_focus()\n" "Button1 Ctrl: extend_adjust(\"rect\")\n" "Button1~Ctrl: extend_adjust()\n" ": extend_end()\n" ": secondary_or_drag_start()\n" "Shift Ctrl Button2: secondary_or_drag_adjust(\"rect\", \"copy\", \"overlay\")\n" "Shift Button2: secondary_or_drag_adjust(\"copy\")\n" "Ctrl Button2: secondary_or_drag_adjust(\"rect\", \"overlay\")\n" "Button2: secondary_or_drag_adjust()\n" "Shift Ctrl: move_to_or_end_drag(\"copy\", \"overlay\")\n" "Shift : move_to_or_end_drag(\"copy\")\n" "Alt: exchange()\n" "Meta: exchange()\n" "Ctrl: copy_to_or_end_drag(\"overlay\")\n" ": copy_to_or_end_drag()\n" "Ctrl~Meta~Alt: mouse_pan()\n" "Ctrl~Meta~Alt Button3: mouse_pan()\n" ": end_drag()\n" ": focusIn()\n" ": focusOut()\n" /* Support for mouse wheel in XFree86 */ "Shift,: scroll_up(1)\n" "Shift,: scroll_down(1)\n" "Ctrl,: scroll_up(1, pages)\n" "Ctrl,: scroll_down(1, pages)\n" ",: scroll_up(5)\n" ",: scroll_down(5)\n"; /* some of the translations from the Motif text widget were not picked up: :osfSelect: set-anchor()\n\ :osfActivate: activate()\n\ ~Shift Ctrl~Meta~AltReturn: activate()\n\ ~Shift Ctrl~Meta~Altspace: set-anchor()\n\ :osfClear: clear-selection()\n\ ~Shift~Ctrl~Meta~AltReturn: process-return()\n\ Shift~Meta~AltTab: prev-tab-group()\n\ Ctrl~Meta~AltTab: next-tab-group()\n\ : unmap()\n\ : enter()\n\ : leave()\n */ static XtActionsRec actionsList[] = { {"self-insert", selfInsertAP}, {"self_insert", selfInsertAP}, {"grab-focus", grabFocusAP}, {"grab_focus", grabFocusAP}, {"extend-adjust", extendAdjustAP}, {"extend_adjust", extendAdjustAP}, {"extend-start", extendStartAP}, {"extend_start", extendStartAP}, {"extend-end", extendEndAP}, {"extend_end", extendEndAP}, {"secondary-adjust", secondaryAdjustAP}, {"secondary_adjust", secondaryAdjustAP}, {"secondary-or-drag-adjust", secondaryOrDragAdjustAP}, {"secondary_or_drag_adjust", secondaryOrDragAdjustAP}, {"secondary-start", secondaryStartAP}, {"secondary_start", secondaryStartAP}, {"secondary-or-drag-start", secondaryOrDragStartAP}, {"secondary_or_drag_start", secondaryOrDragStartAP}, {"process-bdrag", secondaryOrDragStartAP}, {"process_bdrag", secondaryOrDragStartAP}, {"move-destination", moveDestinationAP}, {"move_destination", moveDestinationAP}, {"move-to", moveToAP}, {"move_to", moveToAP}, {"move-to-or-end-drag", moveToOrEndDragAP}, {"move_to_or_end_drag", moveToOrEndDragAP}, {"end_drag", endDragAP}, {"copy-to", copyToAP}, {"copy_to", copyToAP}, {"copy-to-or-end-drag", copyToOrEndDragAP}, {"copy_to_or_end_drag", copyToOrEndDragAP}, {"exchange", exchangeAP}, {"process-cancel", processCancelAP}, {"process_cancel", processCancelAP}, {"paste-clipboard", pasteClipboardAP}, {"paste_clipboard", pasteClipboardAP}, {"copy-clipboard", copyClipboardAP}, {"copy_clipboard", copyClipboardAP}, {"cut-clipboard", cutClipboardAP}, {"cut_clipboard", cutClipboardAP}, {"copy-primary", copyPrimaryAP}, {"copy_primary", copyPrimaryAP}, {"cut-primary", cutPrimaryAP}, {"cut_primary", cutPrimaryAP}, {"newline", newlineAP}, {"newline-and-indent", newlineAndIndentAP}, {"newline_and_indent", newlineAndIndentAP}, {"newline-no-indent", newlineNoIndentAP}, {"newline_no_indent", newlineNoIndentAP}, {"delete-selection", deleteSelectionAP}, {"delete_selection", deleteSelectionAP}, {"delete-previous-character", deletePreviousCharacterAP}, {"delete_previous_character", deletePreviousCharacterAP}, {"delete-next-character", deleteNextCharacterAP}, {"delete_next_character", deleteNextCharacterAP}, {"delete-previous-word", deletePreviousWordAP}, {"delete_previous_word", deletePreviousWordAP}, {"delete-next-word", deleteNextWordAP}, {"delete_next_word", deleteNextWordAP}, {"delete-to-start-of-line", deleteToStartOfLineAP}, {"delete_to_start_of_line", deleteToStartOfLineAP}, {"delete-to-end-of-line", deleteToEndOfLineAP}, {"delete_to_end_of_line", deleteToEndOfLineAP}, {"forward-character", forwardCharacterAP}, {"forward_character", forwardCharacterAP}, {"backward-character", backwardCharacterAP}, {"backward_character", backwardCharacterAP}, {"key-select", keySelectAP}, {"key_select", keySelectAP}, {"process-up", processUpAP}, {"process_up", processUpAP}, {"process-down", processDownAP}, {"process_down", processDownAP}, {"process-shift-up", processShiftUpAP}, {"process_shift_up", processShiftUpAP}, {"process-shift-down", processShiftDownAP}, {"process_shift_down", processShiftDownAP}, {"process-home", beginningOfLineAP}, {"process_home", beginningOfLineAP}, {"forward-word", forwardWordAP}, {"forward_word", forwardWordAP}, {"backward-word", backwardWordAP}, {"backward_word", backwardWordAP}, {"forward-paragraph", forwardParagraphAP}, {"forward_paragraph", forwardParagraphAP}, {"backward-paragraph", backwardParagraphAP}, {"backward_paragraph", backwardParagraphAP}, {"beginning-of-line", beginningOfLineAP}, {"beginning_of_line", beginningOfLineAP}, {"end-of-line", endOfLineAP}, {"end_of_line", endOfLineAP}, {"beginning-of-file", beginningOfFileAP}, {"beginning_of_file", beginningOfFileAP}, {"end-of-file", endOfFileAP}, {"end_of_file", endOfFileAP}, {"next-page", nextPageAP}, {"next_page", nextPageAP}, {"previous-page", previousPageAP}, {"previous_page", previousPageAP}, {"page-left", pageLeftAP}, {"page_left", pageLeftAP}, {"page-right", pageRightAP}, {"page_right", pageRightAP}, {"toggle-overstrike", toggleOverstrikeAP}, {"toggle_overstrike", toggleOverstrikeAP}, {"scroll-up", scrollUpAP}, {"scroll_up", scrollUpAP}, {"scroll-down", scrollDownAP}, {"scroll_down", scrollDownAP}, {"scroll_left", scrollLeftAP}, {"scroll_right", scrollRightAP}, {"scroll-to-line", scrollToLineAP}, {"scroll_to_line", scrollToLineAP}, {"select-all", selectAllAP}, {"select_all", selectAllAP}, {"deselect-all", deselectAllAP}, {"deselect_all", deselectAllAP}, {"focusIn", focusInAP}, {"focusOut", focusOutAP}, {"process-return", selfInsertAP}, {"process_return", selfInsertAP}, {"process-tab", processTabAP}, {"process_tab", processTabAP}, {"insert-string", insertStringAP}, {"insert_string", insertStringAP}, {"mouse_pan", mousePanAP}, }; /* The motif text widget defined a bunch of actions which the nedit text widget as-of-yet does not support: Actions which were not bound to keys (for emacs emulation, some of them should probably be supported: kill-next-character() kill-next-word() kill-previous-character() kill-previous-word() kill-selection() kill-to-end-of-line() kill-to-start-of-line() unkill() next-line() newline-and-backup() beep() redraw-display() scroll-one-line-down() scroll-one-line-up() set-insertion-point() Actions which are not particularly useful: set-anchor() activate() clear-selection() -> this is a wierd one do-quick-action() -> don't think this ever worked Help() next-tab-group() select-adjust() select-start() select-end() */ static XtResource resources[] = { {XmNhighlightThickness, XmCHighlightThickness, XmRDimension, sizeof(Dimension), XtOffset(TextWidget, primitive.highlight_thickness), XmRInt, 0}, {XmNshadowThickness, XmCShadowThickness, XmRDimension, sizeof(Dimension), XtOffset(TextWidget, primitive.shadow_thickness), XmRInt, 0}, {textNfont, textCFont, XmRFontStruct, sizeof(XFontStruct *), XtOffset(TextWidget, text.fontStruct), XmRString, "fixed"}, {textNselectForeground, textCSelectForeground, XmRPixel, sizeof(Pixel), XtOffset(TextWidget, text.selectFGPixel), XmRString, NEDIT_DEFAULT_SEL_FG}, {textNselectBackground, textCSelectBackground, XmRPixel, sizeof(Pixel), XtOffset(TextWidget, text.selectBGPixel), XmRString, NEDIT_DEFAULT_SEL_BG}, {textNhighlightForeground, textCHighlightForeground, XmRPixel,sizeof(Pixel), XtOffset(TextWidget, text.highlightFGPixel), XmRString, NEDIT_DEFAULT_HI_FG}, {textNhighlightBackground, textCHighlightBackground, XmRPixel,sizeof(Pixel), XtOffset(TextWidget, text.highlightBGPixel), XmRString, NEDIT_DEFAULT_HI_BG}, {textNlineNumForeground, textCLineNumForeground, XmRPixel,sizeof(Pixel), XtOffset(TextWidget, text.lineNumFGPixel), XmRString, NEDIT_DEFAULT_LINENO_FG}, {textNcursorForeground, textCCursorForeground, XmRPixel,sizeof(Pixel), XtOffset(TextWidget, text.cursorFGPixel), XmRString, NEDIT_DEFAULT_CURSOR_FG}, {textNcalltipForeground, textCcalltipForeground, XmRPixel,sizeof(Pixel), XtOffset(TextWidget, text.calltipFGPixel), XmRString, NEDIT_DEFAULT_CALLTIP_FG}, {textNcalltipBackground, textCcalltipBackground, XmRPixel,sizeof(Pixel), XtOffset(TextWidget, text.calltipBGPixel), XmRString, NEDIT_DEFAULT_CALLTIP_BG}, {textNbacklightCharTypes,textCBacklightCharTypes,XmRString,sizeof(XmString), XtOffset(TextWidget, text.backlightCharTypes), XmRString, NULL}, {textNrows, textCRows, XmRInt,sizeof(int), XtOffset(TextWidget, text.rows), XmRString, "24"}, {textNcolumns, textCColumns, XmRInt, sizeof(int), XtOffset(TextWidget, text.columns), XmRString, "80"}, {textNmarginWidth, textCMarginWidth, XmRInt, sizeof(int), XtOffset(TextWidget, text.marginWidth), XmRString, "5"}, {textNmarginHeight, textCMarginHeight, XmRInt, sizeof(int), XtOffset(TextWidget, text.marginHeight), XmRString, "5"}, {textNpendingDelete, textCPendingDelete, XmRBoolean, sizeof(Boolean), XtOffset(TextWidget, text.pendingDelete), XmRString, "True"}, {textNautoWrap, textCAutoWrap, XmRBoolean, sizeof(Boolean), XtOffset(TextWidget, text.autoWrap), XmRString, "True"}, {textNcontinuousWrap, textCContinuousWrap, XmRBoolean, sizeof(Boolean), XtOffset(TextWidget, text.continuousWrap), XmRString, "True"}, {textNautoIndent, textCAutoIndent, XmRBoolean, sizeof(Boolean), XtOffset(TextWidget, text.autoIndent), XmRString, "True"}, {textNsmartIndent, textCSmartIndent, XmRBoolean, sizeof(Boolean), XtOffset(TextWidget, text.smartIndent), XmRString, "False"}, {textNoverstrike, textCOverstrike, XmRBoolean, sizeof(Boolean), XtOffset(TextWidget, text.overstrike), XmRString, "False"}, {textNheavyCursor, textCHeavyCursor, XmRBoolean, sizeof(Boolean), XtOffset(TextWidget, text.heavyCursor), XmRString, "False"}, {textNreadOnly, textCReadOnly, XmRBoolean, sizeof(Boolean), XtOffset(TextWidget, text.readOnly), XmRString, "False"}, {textNhidePointer, textCHidePointer, XmRBoolean, sizeof(Boolean), XtOffset(TextWidget, text.hidePointer), XmRString, "False"}, {textNwrapMargin, textCWrapMargin, XmRInt, sizeof(int), XtOffset(TextWidget, text.wrapMargin), XmRString, "0"}, {textNhScrollBar, textCHScrollBar, XmRWidget, sizeof(Widget), XtOffset(TextWidget, text.hScrollBar), XmRString, ""}, {textNvScrollBar, textCVScrollBar, XmRWidget, sizeof(Widget), XtOffset(TextWidget, text.vScrollBar), XmRString, ""}, {textNlineNumCols, textCLineNumCols, XmRInt, sizeof(int), XtOffset(TextWidget, text.lineNumCols), XmRString, "0"}, {textNautoShowInsertPos, textCAutoShowInsertPos, XmRBoolean, sizeof(Boolean), XtOffset(TextWidget, text.autoShowInsertPos), XmRString, "True"}, {textNautoWrapPastedText, textCAutoWrapPastedText, XmRBoolean, sizeof(Boolean), XtOffset(TextWidget, text.autoWrapPastedText), XmRString, "False"}, {textNwordDelimiters, textCWordDelimiters, XmRString, sizeof(char *), XtOffset(TextWidget, text.delimiters), XmRString, ".,/\\`'!@#%^&*()-=+{}[]\":;<>?"}, {textNblinkRate, textCBlinkRate, XmRInt, sizeof(int), XtOffset(TextWidget, text.cursorBlinkRate), XmRString, "500"}, {textNemulateTabs, textCEmulateTabs, XmRInt, sizeof(int), XtOffset(TextWidget, text.emulateTabs), XmRString, "0"}, {textNfocusCallback, textCFocusCallback, XmRCallback, sizeof(caddr_t), XtOffset(TextWidget, text.focusInCB), XtRCallback, NULL}, {textNlosingFocusCallback, textCLosingFocusCallback, XmRCallback, sizeof(caddr_t), XtOffset(TextWidget, text.focusOutCB), XtRCallback,NULL}, {textNcursorMovementCallback, textCCursorMovementCallback, XmRCallback, sizeof(caddr_t), XtOffset(TextWidget, text.cursorCB), XtRCallback, NULL}, {textNdragStartCallback, textCDragStartCallback, XmRCallback, sizeof(caddr_t), XtOffset(TextWidget, text.dragStartCB), XtRCallback, NULL}, {textNdragEndCallback, textCDragEndCallback, XmRCallback, sizeof(caddr_t), XtOffset(TextWidget, text.dragEndCB), XtRCallback, NULL}, {textNsmartIndentCallback, textCSmartIndentCallback, XmRCallback, sizeof(caddr_t), XtOffset(TextWidget, text.smartIndentCB), XtRCallback, NULL}, {textNcursorVPadding, textCCursorVPadding, XtRCardinal, sizeof(Cardinal), XtOffset(TextWidget, text.cursorVPadding), XmRString, "0"} }; static TextClassRec textClassRec = { /* CoreClassPart */ { (WidgetClass) &xmPrimitiveClassRec, /* superclass */ "Text", /* class_name */ sizeof(TextRec), /* widget_size */ NULL, /* class_initialize */ NULL, /* class_part_initialize */ FALSE, /* class_inited */ (XtInitProc)initialize, /* initialize */ NULL, /* initialize_hook */ realize, /* realize */ actionsList, /* actions */ XtNumber(actionsList), /* num_actions */ resources, /* resources */ XtNumber(resources), /* num_resources */ NULLQUARK, /* xrm_class */ TRUE, /* compress_motion */ TRUE, /* compress_exposure */ TRUE, /* compress_enterleave */ FALSE, /* visible_interest */ (XtWidgetProc)destroy, /* destroy */ (XtWidgetProc)resize, /* resize */ (XtExposeProc)redisplay, /* expose */ (XtSetValuesFunc)setValues, /* set_values */ NULL, /* set_values_hook */ XtInheritSetValuesAlmost, /* set_values_almost */ NULL, /* get_values_hook */ NULL, /* accept_focus */ XtVersion, /* version */ NULL, /* callback private */ defaultTranslations, /* tm_table */ queryGeometry, /* query_geometry */ NULL, /* display_accelerator */ NULL, /* extension */ }, /* Motif primitive class fields */ { (XtWidgetProc)_XtInherit, /* Primitive border_highlight */ (XtWidgetProc)_XtInherit, /* Primitive border_unhighlight */ NULL, /*XtInheritTranslations,*/ /* translations */ NULL, /* arm_and_activate */ NULL, /* get resources */ 0, /* num get_resources */ NULL, /* extension */ }, /* Text class part */ { 0, /* ignored */ } }; WidgetClass textWidgetClass = (WidgetClass)&textClassRec; #define NEDIT_HIDE_CURSOR_MASK (KeyPressMask) #define NEDIT_SHOW_CURSOR_MASK (FocusChangeMask | PointerMotionMask | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask) static char empty_bits[] = {0x00, 0x00, 0x00, 0x00}; static Cursor empty_cursor = 0; /* ** Widget initialize method */ static void initialize(TextWidget request, TextWidget new) { XFontStruct *fs = new->text.fontStruct; char *delimiters; textBuffer *buf; Pixel white, black; int textLeft; int charWidth = fs->max_bounds.width; int marginWidth = new->text.marginWidth; int lineNumCols = new->text.lineNumCols; /* Set the initial window size based on the rows and columns resources */ if (request->core.width == 0) new->core.width = charWidth * new->text.columns + marginWidth*2 + (lineNumCols == 0 ? 0 : marginWidth + charWidth * lineNumCols); if (request->core.height == 0) new->core.height = (fs->ascent + fs->descent) * new->text.rows + new->text.marginHeight * 2; /* The default colors work for B&W as well as color, except for selectFGPixel and selectBGPixel, where color highlighting looks much better without reverse video, so if we get here, and the selection is totally unreadable because of the bad default colors, swap the colors and make the selection reverse video */ white = WhitePixelOfScreen(XtScreen((Widget)new)); black = BlackPixelOfScreen(XtScreen((Widget)new)); if ( new->text.selectBGPixel == white && new->core.background_pixel == white && new->text.selectFGPixel == black && new->primitive.foreground == black) { new->text.selectBGPixel = black; new->text.selectFGPixel = white; } /* Create the initial text buffer for the widget to display (which can be replaced later with TextSetBuffer) */ buf = BufCreate(); /* Create and initialize the text-display part of the widget */ textLeft = new->text.marginWidth + (lineNumCols == 0 ? 0 : marginWidth + charWidth * lineNumCols); new->text.textD = TextDCreate((Widget)new, new->text.hScrollBar, new->text.vScrollBar, textLeft, new->text.marginHeight, new->core.width - marginWidth - textLeft, new->core.height - new->text.marginHeight * 2, lineNumCols == 0 ? 0 : marginWidth, lineNumCols == 0 ? 0 : lineNumCols * charWidth, buf, new->text.fontStruct, new->core.background_pixel, new->primitive.foreground, new->text.selectFGPixel, new->text.selectBGPixel, new->text.highlightFGPixel, new->text.highlightBGPixel, new->text.cursorFGPixel, new->text.lineNumFGPixel, new->text.continuousWrap, new->text.wrapMargin, new->text.backlightCharTypes, new->text.calltipFGPixel, new->text.calltipBGPixel); /* Add mandatory delimiters blank, tab, and newline to the list of delimiters. The memory use scheme here is that new values are always copied, and can therefore be safely freed on subsequent set-values calls or destroy */ delimiters = XtMalloc(strlen(new->text.delimiters) + 4); sprintf(delimiters, "%s%s", " \t\n", new->text.delimiters); new->text.delimiters = delimiters; /* Start with the cursor blanked (widgets don't have focus on creation, the initial FocusIn event will unblank it and get blinking started) */ new->text.textD->cursorOn = False; /* Initialize the widget variables */ new->text.autoScrollProcID = 0; new->text.cursorBlinkProcID = 0; new->text.dragState = NOT_CLICKED; new->text.multiClickState = NO_CLICKS; new->text.lastBtnDown = 0; new->text.selectionOwner = False; new->text.motifDestOwner = False; new->text.emTabsBeforeCursor = 0; #ifndef NO_XMIM /* Register the widget to the input manager */ XmImRegister((Widget)new, 0); /* In case some Resources for the IC need to be set, add them below */ XmImVaSetValues((Widget)new, NULL); #endif XtAddEventHandler((Widget)new, GraphicsExpose, True, (XtEventHandler)redisplayGE, (Opaque)NULL); if (new->text.hidePointer) { Display *theDisplay; Pixmap empty_pixmap; XColor black_color; /* Set up the empty Cursor */ if (empty_cursor == 0) { theDisplay = XtDisplay((Widget)new); empty_pixmap = XCreateBitmapFromData(theDisplay, RootWindowOfScreen(XtScreen((Widget)new)), empty_bits, 1, 1); XParseColor(theDisplay, DefaultColormapOfScreen(XtScreen((Widget)new)), "black", &black_color); empty_cursor = XCreatePixmapCursor(theDisplay, empty_pixmap, empty_pixmap, &black_color, &black_color, 0, 0); } /* Add event handler to hide the pointer on keypresses */ XtAddEventHandler((Widget)new, NEDIT_HIDE_CURSOR_MASK, False, handleHidePointer, (Opaque)NULL); } } /* Hide the pointer while the user is typing */ static void handleHidePointer(Widget w, XtPointer unused, XEvent *event, Boolean *continue_to_dispatch) { TextWidget tw = (TextWidget) w; ShowHidePointer(tw, True); } /* Restore the pointer if the mouse moves or focus changes */ static void handleShowPointer(Widget w, XtPointer unused, XEvent *event, Boolean *continue_to_dispatch) { TextWidget tw = (TextWidget) w; ShowHidePointer(tw, False); } void ShowHidePointer(TextWidget w, Boolean hidePointer) { if (w->text.hidePointer) { if (hidePointer != w->text.textD->pointerHidden) { if (hidePointer) { /* Don't listen for keypresses any more */ XtRemoveEventHandler((Widget)w, NEDIT_HIDE_CURSOR_MASK, False, handleHidePointer, (Opaque)NULL); /* Switch to empty cursor */ XDefineCursor(XtDisplay(w), XtWindow(w), empty_cursor); w->text.textD->pointerHidden = True; /* Listen to mouse movement, focus change, and button presses */ XtAddEventHandler((Widget)w, NEDIT_SHOW_CURSOR_MASK, False, handleShowPointer, (Opaque)NULL); } else { /* Don't listen to mouse/focus events any more */ XtRemoveEventHandler((Widget)w, NEDIT_SHOW_CURSOR_MASK, False, handleShowPointer, (Opaque)NULL); /* Switch to regular cursor */ XUndefineCursor(XtDisplay(w), XtWindow(w)); w->text.textD->pointerHidden = False; /* Listen for keypresses now */ XtAddEventHandler((Widget)w, NEDIT_HIDE_CURSOR_MASK, False, handleHidePointer, (Opaque)NULL); } } } } /* ** Widget destroy method */ static void destroy(TextWidget w) { textBuffer *buf; /* Free the text display and possibly the attached buffer. The buffer is freed only if after removing all of the modify procs (by calling StopHandlingXSelections and TextDFree) there are no modify procs left */ StopHandlingXSelections((Widget)w); buf = w->text.textD->buffer; TextDFree(w->text.textD); if (buf->nModifyProcs == 0) BufFree(buf); if (w->text.cursorBlinkProcID != 0) XtRemoveTimeOut(w->text.cursorBlinkProcID); XtFree(w->text.delimiters); XtRemoveAllCallbacks((Widget)w, textNfocusCallback); XtRemoveAllCallbacks((Widget)w, textNlosingFocusCallback); XtRemoveAllCallbacks((Widget)w, textNcursorMovementCallback); XtRemoveAllCallbacks((Widget)w, textNdragStartCallback); XtRemoveAllCallbacks((Widget)w, textNdragEndCallback); #ifndef NO_XMIM /* Unregister the widget from the input manager */ XmImUnregister((Widget)w); #endif } /* ** Widget resize method. Called when the size of the widget changes */ static void resize(TextWidget w) { XFontStruct *fs = w->text.fontStruct; int height = w->core.height, width = w->core.width; int marginWidth = w->text.marginWidth, marginHeight = w->text.marginHeight; int lineNumAreaWidth = w->text.lineNumCols == 0 ? 0 : w->text.marginWidth + fs->max_bounds.width * w->text.lineNumCols; w->text.columns = (width - marginWidth*2 - lineNumAreaWidth) / fs->max_bounds.width; w->text.rows = (height - marginHeight*2) / (fs->ascent + fs->descent); /* Reject widths and heights less than a character, which the text display can't tolerate. This is not strictly legal, but I've seen it done in other widgets and it seems to do no serious harm. NEdit prevents panes from getting smaller than one line, but sometimes splitting windows on Linux 2.0 systems (same Motif, why the change in behavior?), causes one or two resize calls with < 1 line of height. Fixing it here is 100x easier than re-designing textDisp.c */ if (w->text.columns < 1) { w->text.columns = 1; w->core.width = width = fs->max_bounds.width + marginWidth*2 + lineNumAreaWidth; } if (w->text.rows < 1) { w->text.rows = 1; w->core.height = height = fs->ascent + fs->descent + marginHeight*2; } /* Resize the text display that the widget uses to render text */ TextDResize(w->text.textD, width - marginWidth*2 - lineNumAreaWidth, height - marginHeight*2); /* if the window became shorter or narrower, there may be text left in the bottom or right margin area, which must be cleaned up */ if (XtIsRealized((Widget)w)) { XClearArea(XtDisplay(w), XtWindow(w), 0, height-marginHeight, width, marginHeight, False); XClearArea(XtDisplay(w), XtWindow(w),width-marginWidth, 0, marginWidth, height, False); } } /* ** Widget redisplay method */ static void redisplay(TextWidget w, XEvent *event, Region region) { XExposeEvent *e = &event->xexpose; TextDRedisplayRect(w->text.textD, e->x, e->y, e->width, e->height); } static Bool findGraphicsExposeOrNoExposeEvent(Display *theDisplay, XEvent *event, XPointer arg) { if ((theDisplay == event->xany.display) && (event->type == GraphicsExpose || event->type == NoExpose) && ((Widget)arg == XtWindowToWidget(event->xany.display, event->xany.window))) { return(True); } else { return(False); } } static void adjustRectForGraphicsExposeOrNoExposeEvent(TextWidget w, XEvent *event, Boolean *first, int *left, int *top, int *width, int *height) { Boolean removeQueueEntry = False; if (event->type == GraphicsExpose) { XGraphicsExposeEvent *e = &event->xgraphicsexpose; int x = e->x, y = e->y; TextDImposeGraphicsExposeTranslation(w->text.textD, &x, &y); if (*first) { *left = x; *top = y; *width = e->width; *height = e->height; *first = False; } else { int prev_left = *left; int prev_top = *top; *left = min(*left, x); *top = min(*top, y); *width = max(prev_left + *width, x + e->width) - *left; *height = max(prev_top + *height, y + e->height) - *top; } if (e->count == 0) { removeQueueEntry = True; } } else if (event->type == NoExpose) { removeQueueEntry = True; } if (removeQueueEntry) { TextDPopGraphicExposeQueueEntry(w->text.textD); } } static void redisplayGE(TextWidget w, XtPointer client_data, XEvent *event, Boolean *continue_to_dispatch_return) { if (event->type == GraphicsExpose || event->type == NoExpose) { HandleAllPendingGraphicsExposeNoExposeEvents(w, event); } } void HandleAllPendingGraphicsExposeNoExposeEvents(TextWidget w, XEvent *event) { XEvent foundEvent; int left; int top; int width; int height; Boolean invalidRect = True; if (event) { adjustRectForGraphicsExposeOrNoExposeEvent(w, event, &invalidRect, &left, &top, &width, &height); } while (XCheckIfEvent(XtDisplay(w), &foundEvent, findGraphicsExposeOrNoExposeEvent, (XPointer)w)) { adjustRectForGraphicsExposeOrNoExposeEvent(w, &foundEvent, &invalidRect, &left, &top, &width, &height); } if (!invalidRect) { TextDRedisplayRect(w->text.textD, left, top, width, height); } } /* ** Widget setValues method */ static Boolean setValues(TextWidget current, TextWidget request, TextWidget new) { Boolean redraw = False, reconfigure = False; if (new->text.overstrike != current->text.overstrike) { if (current->text.textD->cursorStyle == BLOCK_CURSOR) TextDSetCursorStyle(current->text.textD, current->text.heavyCursor ? HEAVY_CURSOR : NORMAL_CURSOR); else if (current->text.textD->cursorStyle == NORMAL_CURSOR || current->text.textD->cursorStyle == HEAVY_CURSOR) TextDSetCursorStyle(current->text.textD, BLOCK_CURSOR); } if (new->text.fontStruct != current->text.fontStruct) { if (new->text.lineNumCols != 0) reconfigure = True; TextDSetFont(current->text.textD, new->text.fontStruct); } if (new->text.wrapMargin != current->text.wrapMargin || new->text.continuousWrap != current->text.continuousWrap) TextDSetWrapMode(current->text.textD, new->text.continuousWrap, new->text.wrapMargin); /* When delimiters are changed, copy the memory, so that the caller doesn't have to manage it, and add mandatory delimiters blank, tab, and newline to the list */ if (new->text.delimiters != current->text.delimiters) { char *delimiters = XtMalloc(strlen(new->text.delimiters) + 4); XtFree(current->text.delimiters); sprintf(delimiters, "%s%s", " \t\n", new->text.delimiters); new->text.delimiters = delimiters; } /* Setting the lineNumCols resource tells the text widget to hide or show, or change the number of columns of the line number display, which requires re-organizing the x coordinates of both the line number display and the main text display */ if (new->text.lineNumCols != current->text.lineNumCols || reconfigure) { int marginWidth = new->text.marginWidth; int charWidth = new->text.fontStruct->max_bounds.width; int lineNumCols = new->text.lineNumCols; if (lineNumCols == 0) { TextDSetLineNumberArea(new->text.textD, 0, 0, marginWidth); new->text.columns = (new->core.width - marginWidth*2) / charWidth; } else { TextDSetLineNumberArea(new->text.textD, marginWidth, charWidth * lineNumCols, 2*marginWidth + charWidth * lineNumCols); new->text.columns = (new->core.width - marginWidth*3 - charWidth * lineNumCols) / charWidth; } } if (new->text.backlightCharTypes != current->text.backlightCharTypes) { TextDSetupBGClasses((Widget)new, new->text.backlightCharTypes, &new->text.textD->bgClassPixel, &new->text.textD->bgClass, new->text.textD->bgPixel); redraw = True; } return redraw; } /* ** Widget realize method */ static void realize(Widget w, XtValueMask *valueMask, XSetWindowAttributes *attributes) { /* Set bit gravity window attribute. This saves a full blank and redraw on window resizing */ *valueMask |= CWBitGravity; attributes->bit_gravity = NorthWestGravity; /* Continue with realize method from superclass */ (xmPrimitiveClassRec.core_class.realize)(w, valueMask, attributes); } /* ** Widget query geometry method ... unless asked to negotiate a different size simply return current size. */ static XtGeometryResult queryGeometry(Widget w, XtWidgetGeometry *proposed, XtWidgetGeometry *answer) { TextWidget tw = (TextWidget)w; int curHeight = tw->core.height; int curWidth = tw->core.width; XFontStruct *fs = tw->text.textD->fontStruct; int fontWidth = fs->max_bounds.width; int fontHeight = fs->ascent + fs->descent; int marginHeight = tw->text.marginHeight; int propWidth = (proposed->request_mode & CWWidth) ? proposed->width : 0; int propHeight = (proposed->request_mode & CWHeight) ? proposed->height : 0; answer->request_mode = CWHeight | CWWidth; if(proposed->request_mode & CWWidth) /* Accept a width no smaller than 10 chars */ answer->width = max(fontWidth * 10, proposed->width); else answer->width = curWidth; if(proposed->request_mode & CWHeight) /* Accept a height no smaller than an exact multiple of the line height and at least one line high */ answer->height = max(1, ((propHeight - 2*marginHeight) / fontHeight)) * fontHeight + 2*marginHeight; else answer->height = curHeight; /*printf("propWidth %d, propHeight %d, ansWidth %d, ansHeight %d\n", propWidth, propHeight, answer->width, answer->height);*/ if (propWidth == answer->width && propHeight == answer->height) return XtGeometryYes; else if (answer->width == curWidth && answer->height == curHeight) return XtGeometryNo; else return XtGeometryAlmost; } /* ** Set the text buffer which this widget will display and interact with. ** The currently attached buffer is automatically freed, ONLY if it has ** no additional modify procs attached (as it would if it were being ** displayed by another text widget). */ void TextSetBuffer(Widget w, textBuffer *buffer) { textBuffer *oldBuf = ((TextWidget)w)->text.textD->buffer; StopHandlingXSelections(w); TextDSetBuffer(((TextWidget)w)->text.textD, buffer); if (oldBuf->nModifyProcs == 0) BufFree(oldBuf); } /* ** Get the buffer associated with this text widget. Note that attaching ** additional modify callbacks to the buffer will prevent it from being ** automatically freed when the widget is destroyed. */ textBuffer *TextGetBuffer(Widget w) { return ((TextWidget)w)->text.textD->buffer; } /* ** Translate a line number and column into a position */ int TextLineAndColToPos(Widget w, int lineNum, int column) { return TextDLineAndColToPos(((TextWidget)w)->text.textD, lineNum, column ); } /* ** Translate a position into a line number (if the position is visible, ** if it's not, return False */ int TextPosToLineAndCol(Widget w, int pos, int *lineNum, int *column) { return TextDPosToLineAndCol(((TextWidget)w)->text.textD, pos, lineNum, column); } /* ** Translate a buffer text position to the XY location where the center ** of the cursor would be positioned to point to that character. Returns ** False if the position is not displayed because it is VERTICALLY out ** of view. If the position is horizontally out of view, returns the ** x coordinate where the position would be if it were visible. */ int TextPosToXY(Widget w, int pos, int *x, int *y) { return TextDPositionToXY(((TextWidget)w)->text.textD, pos, x, y); } /* ** Return the cursor position */ int TextGetCursorPos(Widget w) { return TextDGetInsertPosition(((TextWidget)w)->text.textD); } /* ** Set the cursor position */ void TextSetCursorPos(Widget w, int pos) { TextDSetInsertPosition(((TextWidget)w)->text.textD, pos); checkAutoShowInsertPos(w); callCursorMovementCBs(w, NULL); } /* ** Return the horizontal and vertical scroll positions of the widget */ void TextGetScroll(Widget w, int *topLineNum, int *horizOffset) { TextDGetScroll(((TextWidget)w)->text.textD, topLineNum, horizOffset); } /* ** Set the horizontal and vertical scroll positions of the widget */ void TextSetScroll(Widget w, int topLineNum, int horizOffset) { TextDSetScroll(((TextWidget)w)->text.textD, topLineNum, horizOffset); } int TextGetMinFontWidth(Widget w, Boolean considerStyles) { return(TextDMinFontWidth(((TextWidget)w)->text.textD, considerStyles)); } int TextGetMaxFontWidth(Widget w, Boolean considerStyles) { return(TextDMaxFontWidth(((TextWidget)w)->text.textD, considerStyles)); } /* ** Set this widget to be the owner of selections made in it's attached ** buffer (text buffers may be shared among several text widgets). */ void TextHandleXSelections(Widget w) { HandleXSelections(w); } void TextPasteClipboard(Widget w, Time time) { cancelDrag(w); if (checkReadOnly(w)) return; TakeMotifDestination(w, time); InsertClipboard(w, False); callCursorMovementCBs(w, NULL); } void TextColPasteClipboard(Widget w, Time time) { cancelDrag(w); if (checkReadOnly(w)) return; TakeMotifDestination(w, time); InsertClipboard(w, True); callCursorMovementCBs(w, NULL); } void TextCopyClipboard(Widget w, Time time) { cancelDrag(w); if (!((TextWidget)w)->text.textD->buffer->primary.selected) { XBell(XtDisplay(w), 0); return; } CopyToClipboard(w, time); } void TextCutClipboard(Widget w, Time time) { textDisp *textD = ((TextWidget)w)->text.textD; cancelDrag(w); if (checkReadOnly(w)) return; if (!textD->buffer->primary.selected) { XBell(XtDisplay(w), 0); return; } TakeMotifDestination(w, time); CopyToClipboard (w, time); BufRemoveSelected(textD->buffer); TextDSetInsertPosition(textD, textD->buffer->cursorPosHint); checkAutoShowInsertPos(w); } int TextFirstVisibleLine(Widget w) { return(((TextWidget)w)->text.textD->topLineNum); } int TextNumVisibleLines(Widget w) { return(((TextWidget)w)->text.textD->nVisibleLines); } int TextVisibleWidth(Widget w) { return(((TextWidget)w)->text.textD->width); } int TextFirstVisiblePos(Widget w) { return ((TextWidget)w)->text.textD->firstChar; } int TextLastVisiblePos(Widget w) { return ((TextWidget)w)->text.textD->lastChar; } /* ** Insert text "chars" at the cursor position, respecting pending delete ** selections, overstrike, and handling cursor repositioning as if the text ** had been typed. If autoWrap is on wraps the text to fit within the wrap ** margin, auto-indenting where the line was wrapped (but nowhere else). ** "allowPendingDelete" controls whether primary selections in the widget are ** treated as pending delete selections (True), or ignored (False). "event" ** is optional and is just passed on to the cursor movement callbacks. */ void TextInsertAtCursor(Widget w, char *chars, XEvent *event, int allowPendingDelete, int allowWrap) { int wrapMargin, colNum, lineStartPos, cursorPos; char *c, *lineStartText, *wrappedText; TextWidget tw = (TextWidget)w; textDisp *textD = tw->text.textD; textBuffer *buf = textD->buffer; int fontWidth = textD->fontStruct->max_bounds.width; int replaceSel, singleLine, breakAt = 0; /* Don't wrap if auto-wrap is off or suppressed, or it's just a newline */ if (!allowWrap || !tw->text.autoWrap || (chars[0] == '\n' && chars[1] == '\0')) { simpleInsertAtCursor(w, chars, event, allowPendingDelete); return; } /* If this is going to be a pending delete operation, the real insert position is the start of the selection. This will make rectangular selections wrap strangely, but this routine should rarely be used for them, and even more rarely when they need to be wrapped. */ replaceSel = allowPendingDelete && pendingSelection(w); cursorPos = replaceSel ? buf->primary.start : TextDGetInsertPosition(textD); /* If the text is only one line and doesn't need to be wrapped, just insert it and be done (for efficiency only, this routine is called for each character typed). (Of course, it may not be significantly more efficient than the more general code below it, so it may be a waste of time!) */ wrapMargin = tw->text.wrapMargin != 0 ? tw->text.wrapMargin : textD->width / fontWidth; lineStartPos = BufStartOfLine(buf, cursorPos); colNum = BufCountDispChars(buf, lineStartPos, cursorPos); for (c=chars; *c!='\0' && *c!='\n'; c++) colNum += BufCharWidth(*c, colNum, buf->tabDist, buf->nullSubsChar); singleLine = *c == '\0'; if (colNum < wrapMargin && singleLine) { simpleInsertAtCursor(w, chars, event, True); return; } /* Wrap the text */ lineStartText = BufGetRange(buf, lineStartPos, cursorPos); wrappedText = wrapText(tw, lineStartText, chars, lineStartPos, wrapMargin, replaceSel ? NULL : &breakAt); XtFree(lineStartText); /* Insert the text. Where possible, use TextDInsert which is optimized for less redraw. */ if (replaceSel) { BufReplaceSelected(buf, wrappedText); TextDSetInsertPosition(textD, buf->cursorPosHint); } else if (tw->text.overstrike) { if (breakAt == 0 && singleLine) TextDOverstrike(textD, wrappedText); else { BufReplace(buf, cursorPos-breakAt, cursorPos, wrappedText); TextDSetInsertPosition(textD, buf->cursorPosHint); } } else { if (breakAt == 0) { TextDInsert(textD, wrappedText); } else { BufReplace(buf, cursorPos-breakAt, cursorPos, wrappedText); TextDSetInsertPosition(textD, buf->cursorPosHint); } } XtFree(wrappedText); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } /* ** Fetch text from the widget's buffer, adding wrapping newlines to emulate ** effect acheived by wrapping in the text display in continuous wrap mode. */ char *TextGetWrapped(Widget w, int startPos, int endPos, int *outLen) { textDisp *textD = ((TextWidget)w)->text.textD; textBuffer *buf = textD->buffer; textBuffer *outBuf; int fromPos, toPos, outPos; char c, *outString; if (!((TextWidget)w)->text.continuousWrap || startPos == endPos) { *outLen = endPos - startPos; return BufGetRange(buf, startPos, endPos); } /* Create a text buffer with a good estimate of the size that adding newlines will expand it to. Since it's a text buffer, if we guess wrong, it will fail softly, and simply expand the size */ outBuf = BufCreatePreallocated((endPos-startPos) + (endPos-startPos)/5); outPos = 0; /* Go (displayed) line by line through the buffer, adding newlines where the text is wrapped at some character other than an existing newline */ fromPos = startPos; toPos = TextDCountForwardNLines(textD, startPos, 1, False); while (toPos < endPos) { BufCopyFromBuf(buf, outBuf, fromPos, toPos, outPos); outPos += toPos - fromPos; c = BufGetCharacter(outBuf, outPos-1); if (c == ' ' || c == '\t') BufReplace(outBuf, outPos-1, outPos, "\n"); else if (c != '\n') { BufInsert(outBuf, outPos, "\n"); outPos++; } fromPos = toPos; toPos = TextDCountForwardNLines(textD, fromPos, 1, True); } BufCopyFromBuf(buf, outBuf, fromPos, endPos, outPos); /* return the contents of the output buffer as a string */ outString = BufGetAll(outBuf); *outLen = outBuf->length; BufFree(outBuf); return outString; } /* ** Return the (statically allocated) action table for menu item actions. ** ** Warning: This routine can only be used before the first text widget is ** created! After that, apparently, Xt takes over the table and overwrites ** it with its own version. XtGetActionList is preferable, but is not ** available before X11R5. */ XtActionsRec *TextGetActions(int *nActions) { *nActions = XtNumber(actionsList); return actionsList; } static void grabFocusAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XButtonEvent *e = &event->xbutton; TextWidget tw = (TextWidget)w; textDisp *textD = tw->text.textD; Time lastBtnDown = tw->text.lastBtnDown; int row, column; /* Indicate state for future events, PRIMARY_CLICKED indicates that the proper initialization has been done for primary dragging and/or multi-clicking. Also record the timestamp for multi-click processing */ tw->text.dragState = PRIMARY_CLICKED; tw->text.lastBtnDown = e->time; /* Become owner of the MOTIF_DESTINATION selection, making this widget the designated recipient of secondary quick actions in Motif XmText widgets and in other NEdit text widgets */ TakeMotifDestination(w, e->time); /* Check for possible multi-click sequence in progress */ if (tw->text.multiClickState != NO_CLICKS) { if (e->time < lastBtnDown + XtGetMultiClickTime(XtDisplay(w))) { if (tw->text.multiClickState == ONE_CLICK) { selectWord(w, e->x); callCursorMovementCBs(w, event); return; } else if (tw->text.multiClickState == TWO_CLICKS) { selectLine(w); callCursorMovementCBs(w, event); return; } else if (tw->text.multiClickState == THREE_CLICKS) { BufSelect(textD->buffer, 0, textD->buffer->length); return; } else if (tw->text.multiClickState > THREE_CLICKS) tw->text.multiClickState = NO_CLICKS; } else tw->text.multiClickState = NO_CLICKS; } /* Clear any existing selections */ BufUnselect(textD->buffer); /* Move the cursor to the pointer location */ moveDestinationAP(w, event, args, nArgs); /* Record the site of the initial button press and the initial character position so subsequent motion events and clicking can decide when and where to begin a primary selection */ tw->text.btnDownX = e->x; tw->text.btnDownY = e->y; tw->text.anchor = TextDGetInsertPosition(textD); TextDXYToUnconstrainedPosition(textD, e->x, e->y, &row, &column); column = TextDOffsetWrappedColumn(textD, row, column); tw->text.rectAnchor = column; } static void moveDestinationAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XButtonEvent *e = &event->xbutton; textDisp *textD = ((TextWidget)w)->text.textD; /* Get input focus */ XmProcessTraversal(w, XmTRAVERSE_CURRENT); /* Move the cursor */ TextDSetInsertPosition(textD, TextDXYToPosition(textD, e->x, e->y)); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } static void extendAdjustAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { TextWidget tw = (TextWidget)w; XMotionEvent *e = &event->xmotion; int dragState = tw->text.dragState; int rectDrag = hasKey("rect", args, nArgs); /* Make sure the proper initialization was done on mouse down */ if (dragState != PRIMARY_DRAG && dragState != PRIMARY_CLICKED && dragState != PRIMARY_RECT_DRAG) return; /* If the selection hasn't begun, decide whether the mouse has moved far enough from the initial mouse down to be considered a drag */ if (tw->text.dragState == PRIMARY_CLICKED) { if (abs(e->x - tw->text.btnDownX) > SELECT_THRESHOLD || abs(e->y - tw->text.btnDownY) > SELECT_THRESHOLD) tw->text.dragState = rectDrag ? PRIMARY_RECT_DRAG : PRIMARY_DRAG; else return; } /* If "rect" argument has appeared or disappeared, keep dragState up to date about which type of drag this is */ tw->text.dragState = rectDrag ? PRIMARY_RECT_DRAG : PRIMARY_DRAG; /* Record the new position for the autoscrolling timer routine, and engage or disengage the timer if the mouse is in/out of the window */ checkAutoScroll(tw, e->x, e->y); /* Adjust the selection and move the cursor */ adjustSelection(tw, e->x, e->y); } static void extendStartAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XMotionEvent *e = &event->xmotion; textDisp *textD = ((TextWidget)w)->text.textD; textBuffer *buf = textD->buffer; selection *sel = &buf->primary; int anchor, rectAnchor, anchorLineStart, newPos, row, column; /* Find the new anchor point for the rest of this drag operation */ newPos = TextDXYToPosition(textD, e->x, e->y); TextDXYToUnconstrainedPosition(textD, e->x, e->y, &row, &column); column = TextDOffsetWrappedColumn(textD, row, column); if (sel->selected) { if (sel->rectangular) { rectAnchor = column < (sel->rectEnd + sel->rectStart) / 2 ? sel->rectEnd : sel->rectStart; anchorLineStart = BufStartOfLine(buf, newPos < (sel->end + sel->start) / 2 ? sel->end : sel->start); anchor = BufCountForwardDispChars(buf, anchorLineStart, rectAnchor); } else { if (abs(newPos - sel->start) < abs(newPos - sel->end)) anchor = sel->end; else anchor = sel->start; anchorLineStart = BufStartOfLine(buf, anchor); rectAnchor = BufCountDispChars(buf, anchorLineStart, anchor); } } else { anchor = TextDGetInsertPosition(textD); anchorLineStart = BufStartOfLine(buf, anchor); rectAnchor = BufCountDispChars(buf, anchorLineStart, anchor); } ((TextWidget)w)->text.anchor = anchor; ((TextWidget)w)->text.rectAnchor = rectAnchor; /* Make the new selection */ if (hasKey("rect", args, nArgs)) BufRectSelect(buf, BufStartOfLine(buf, min(anchor, newPos)), BufEndOfLine(buf, max(anchor, newPos)), min(rectAnchor, column), max(rectAnchor, column)); else BufSelect(buf, min(anchor, newPos), max(anchor, newPos)); /* Never mind the motion threshold, go right to dragging since extend-start is unambiguously the start of a selection */ ((TextWidget)w)->text.dragState = PRIMARY_DRAG; /* Don't do by-word or by-line adjustment, just by character */ ((TextWidget)w)->text.multiClickState = NO_CLICKS; /* Move the cursor */ TextDSetInsertPosition(textD, newPos); callCursorMovementCBs(w, event); } static void extendEndAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XButtonEvent *e = &event->xbutton; TextWidget tw = (TextWidget)w; if (tw->text.dragState == PRIMARY_CLICKED && tw->text.lastBtnDown <= e->time + XtGetMultiClickTime(XtDisplay(w))) tw->text.multiClickState++; endDrag(w); } static void processCancelAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { int dragState = ((TextWidget)w)->text.dragState; textBuffer *buf = ((TextWidget)w)->text.textD->buffer; textDisp *textD = ((TextWidget)w)->text.textD; /* If there's a calltip displayed, kill it. */ TextDKillCalltip(textD, 0); if (dragState == PRIMARY_DRAG || dragState == PRIMARY_RECT_DRAG) BufUnselect(buf); cancelDrag(w); } static void secondaryStartAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XMotionEvent *e = &event->xmotion; textDisp *textD = ((TextWidget)w)->text.textD; textBuffer *buf = textD->buffer; selection *sel = &buf->secondary; int anchor, pos, row, column; /* Find the new anchor point and make the new selection */ pos = TextDXYToPosition(textD, e->x, e->y); if (sel->selected) { if (abs(pos - sel->start) < abs(pos - sel->end)) anchor = sel->end; else anchor = sel->start; BufSecondarySelect(buf, anchor, pos); } else anchor = pos; /* Record the site of the initial button press and the initial character position so subsequent motion events can decide when to begin a selection, (and where the selection began) */ ((TextWidget)w)->text.btnDownX = e->x; ((TextWidget)w)->text.btnDownY = e->y; ((TextWidget)w)->text.anchor = pos; TextDXYToUnconstrainedPosition(textD, e->x, e->y, &row, &column); column = TextDOffsetWrappedColumn(textD, row, column); ((TextWidget)w)->text.rectAnchor = column; ((TextWidget)w)->text.dragState = SECONDARY_CLICKED; } static void secondaryOrDragStartAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XMotionEvent *e = &event->xmotion; textDisp *textD = ((TextWidget)w)->text.textD; textBuffer *buf = textD->buffer; /* If the click was outside of the primary selection, this is not a drag, start a secondary selection */ if (!buf->primary.selected || !TextDInSelection(textD, e->x, e->y)) { secondaryStartAP(w, event, args, nArgs); return; } if (checkReadOnly(w)) return; /* Record the site of the initial button press and the initial character position so subsequent motion events can decide when to begin a drag, and where to drag to */ ((TextWidget)w)->text.btnDownX = e->x; ((TextWidget)w)->text.btnDownY = e->y; ((TextWidget)w)->text.dragState = CLICKED_IN_SELECTION; } static void secondaryAdjustAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { TextWidget tw = (TextWidget)w; XMotionEvent *e = &event->xmotion; int dragState = tw->text.dragState; int rectDrag = hasKey("rect", args, nArgs); /* Make sure the proper initialization was done on mouse down */ if (dragState != SECONDARY_DRAG && dragState != SECONDARY_RECT_DRAG && dragState != SECONDARY_CLICKED) return; /* If the selection hasn't begun, decide whether the mouse has moved far enough from the initial mouse down to be considered a drag */ if (tw->text.dragState == SECONDARY_CLICKED) { if (abs(e->x - tw->text.btnDownX) > SELECT_THRESHOLD || abs(e->y - tw->text.btnDownY) > SELECT_THRESHOLD) tw->text.dragState = rectDrag ? SECONDARY_RECT_DRAG: SECONDARY_DRAG; else return; } /* If "rect" argument has appeared or disappeared, keep dragState up to date about which type of drag this is */ tw->text.dragState = rectDrag ? SECONDARY_RECT_DRAG : SECONDARY_DRAG; /* Record the new position for the autoscrolling timer routine, and engage or disengage the timer if the mouse is in/out of the window */ checkAutoScroll(tw, e->x, e->y); /* Adjust the selection */ adjustSecondarySelection(tw, e->x, e->y); } static void secondaryOrDragAdjustAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { TextWidget tw = (TextWidget)w; XMotionEvent *e = &event->xmotion; int dragState = tw->text.dragState; /* Only dragging of blocks of text is handled in this action proc. Otherwise, defer to secondaryAdjust to handle the rest */ if (dragState != CLICKED_IN_SELECTION && dragState != PRIMARY_BLOCK_DRAG) { secondaryAdjustAP(w, event, args, nArgs); return; } /* Decide whether the mouse has moved far enough from the initial mouse down to be considered a drag */ if (tw->text.dragState == CLICKED_IN_SELECTION) { if (abs(e->x - tw->text.btnDownX) > SELECT_THRESHOLD || abs(e->y - tw->text.btnDownY) > SELECT_THRESHOLD) BeginBlockDrag(tw); else return; } /* Record the new position for the autoscrolling timer routine, and engage or disengage the timer if the mouse is in/out of the window */ checkAutoScroll(tw, e->x, e->y); /* Adjust the selection */ BlockDragSelection(tw, e->x, e->y, hasKey("overlay", args, nArgs) ? (hasKey("copy", args, nArgs) ? DRAG_OVERLAY_COPY : DRAG_OVERLAY_MOVE) : (hasKey("copy", args, nArgs) ? DRAG_COPY : DRAG_MOVE)); } static void copyToAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XButtonEvent *e = &event->xbutton; TextWidget tw = (TextWidget)w; textDisp *textD = tw->text.textD; int dragState = tw->text.dragState; textBuffer *buf = textD->buffer; selection *secondary = &buf->secondary, *primary = &buf->primary; int rectangular = secondary->rectangular; char *textToCopy; int insertPos, lineStart, column; endDrag(w); if (!((dragState == SECONDARY_DRAG && secondary->selected) || (dragState == SECONDARY_RECT_DRAG && secondary->selected) || dragState == SECONDARY_CLICKED || dragState == NOT_CLICKED)) return; if (!(secondary->selected && !((TextWidget)w)->text.motifDestOwner)) { if (checkReadOnly(w)) { BufSecondaryUnselect(buf); return; } } if (secondary->selected) { if (tw->text.motifDestOwner) { TextDBlankCursor(textD); textToCopy = BufGetSecSelectText(buf); if (primary->selected && rectangular) { insertPos = TextDGetInsertPosition(textD); BufReplaceSelected(buf, textToCopy); TextDSetInsertPosition(textD, buf->cursorPosHint); } else if (rectangular) { insertPos = TextDGetInsertPosition(textD); lineStart = BufStartOfLine(buf, insertPos); column = BufCountDispChars(buf, lineStart, insertPos); BufInsertCol(buf, column, lineStart, textToCopy, NULL, NULL); TextDSetInsertPosition(textD, buf->cursorPosHint); } else TextInsertAtCursor(w, textToCopy, event, True, tw->text.autoWrapPastedText); XtFree(textToCopy); BufSecondaryUnselect(buf); TextDUnblankCursor(textD); } else SendSecondarySelection(w, e->time, False); } else if (primary->selected) { textToCopy = BufGetSelectionText(buf); TextDSetInsertPosition(textD, TextDXYToPosition(textD, e->x, e->y)); TextInsertAtCursor(w, textToCopy, event, False, tw->text.autoWrapPastedText); XtFree(textToCopy); } else { TextDSetInsertPosition(textD, TextDXYToPosition(textD, e->x, e->y)); InsertPrimarySelection(w, e->time, False); } } static void copyToOrEndDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { int dragState = ((TextWidget)w)->text.dragState; if (dragState != PRIMARY_BLOCK_DRAG) { copyToAP(w, event, args, nArgs); return; } FinishBlockDrag((TextWidget)w); } static void moveToAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XButtonEvent *e = &event->xbutton; textDisp *textD = ((TextWidget)w)->text.textD; int dragState = ((TextWidget)w)->text.dragState; textBuffer *buf = textD->buffer; selection *secondary = &buf->secondary, *primary = &buf->primary; int insertPos, rectangular = secondary->rectangular; int column, lineStart; char *textToCopy; endDrag(w); if (!((dragState == SECONDARY_DRAG && secondary->selected) || (dragState == SECONDARY_RECT_DRAG && secondary->selected) || dragState == SECONDARY_CLICKED || dragState == NOT_CLICKED)) return; if (checkReadOnly(w)) { BufSecondaryUnselect(buf); return; } if (secondary->selected) { if (((TextWidget)w)->text.motifDestOwner) { textToCopy = BufGetSecSelectText(buf); if (primary->selected && rectangular) { insertPos = TextDGetInsertPosition(textD); BufReplaceSelected(buf, textToCopy); TextDSetInsertPosition(textD, buf->cursorPosHint); } else if (rectangular) { insertPos = TextDGetInsertPosition(textD); lineStart = BufStartOfLine(buf, insertPos); column = BufCountDispChars(buf, lineStart, insertPos); BufInsertCol(buf, column, lineStart, textToCopy, NULL, NULL); TextDSetInsertPosition(textD, buf->cursorPosHint); } else TextInsertAtCursor(w, textToCopy, event, True, ((TextWidget)w)->text.autoWrapPastedText); XtFree(textToCopy); BufRemoveSecSelect(buf); BufSecondaryUnselect(buf); } else SendSecondarySelection(w, e->time, True); } else if (primary->selected) { textToCopy = BufGetRange(buf, primary->start, primary->end); TextDSetInsertPosition(textD, TextDXYToPosition(textD, e->x, e->y)); TextInsertAtCursor(w, textToCopy, event, False, ((TextWidget)w)->text.autoWrapPastedText); XtFree(textToCopy); BufRemoveSelected(buf); BufUnselect(buf); } else { TextDSetInsertPosition(textD, TextDXYToPosition(textD, e->x, e->y)); MovePrimarySelection(w, e->time, False); } } static void moveToOrEndDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { int dragState = ((TextWidget)w)->text.dragState; if (dragState != PRIMARY_BLOCK_DRAG) { moveToAP(w, event, args, nArgs); return; } FinishBlockDrag((TextWidget)w); } static void endDragAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { if (((TextWidget)w)->text.dragState == PRIMARY_BLOCK_DRAG) FinishBlockDrag((TextWidget)w); else endDrag(w); } static void exchangeAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XButtonEvent *e = &event->xbutton; textDisp *textD = ((TextWidget)w)->text.textD; textBuffer *buf = textD->buffer; selection *sec = &buf->secondary, *primary = &buf->primary; char *primaryText, *secText; int newPrimaryStart, newPrimaryEnd, secWasRect; int dragState = ((TextWidget)w)->text.dragState; /* save before endDrag */ int silent = hasKey("nobell", args, nArgs); endDrag(w); if (checkReadOnly(w)) return; /* If there's no secondary selection here, or the primary and secondary selection overlap, just beep and return */ if (!sec->selected || (primary->selected && ((primary->start <= sec->start && primary->end > sec->start) || (sec->start <= primary->start && sec->end > primary->start)))) { BufSecondaryUnselect(buf); ringIfNecessary(silent, w); /* If there's no secondary selection, but the primary selection is being dragged, we must not forget to finish the dragging. Otherwise, modifications aren't recorded. */ if (dragState == PRIMARY_BLOCK_DRAG) FinishBlockDrag((TextWidget)w); return; } /* if the primary selection is in another widget, use selection routines */ if (!primary->selected) { ExchangeSelections(w, e->time); return; } /* Both primary and secondary are in this widget, do the exchange here */ primaryText = BufGetSelectionText(buf); secText = BufGetSecSelectText(buf); secWasRect = sec->rectangular; BufReplaceSecSelect(buf, primaryText); newPrimaryStart = primary->start; BufReplaceSelected(buf, secText); newPrimaryEnd = newPrimaryStart + strlen(secText); XtFree(primaryText); XtFree(secText); BufSecondaryUnselect(buf); if (secWasRect) { TextDSetInsertPosition(textD, buf->cursorPosHint); } else { BufSelect(buf, newPrimaryStart, newPrimaryEnd); TextDSetInsertPosition(textD, newPrimaryEnd); } checkAutoShowInsertPos(w); } static void copyPrimaryAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XKeyEvent *e = &event->xkey; TextWidget tw = (TextWidget)w; textDisp *textD = tw->text.textD; textBuffer *buf = textD->buffer; selection *primary = &buf->primary; int rectangular = hasKey("rect", args, nArgs); char *textToCopy; int insertPos, col; cancelDrag(w); if (checkReadOnly(w)) return; if (primary->selected && rectangular) { textToCopy = BufGetSelectionText(buf); insertPos = TextDGetInsertPosition(textD); col = BufCountDispChars(buf, BufStartOfLine(buf, insertPos), insertPos); BufInsertCol(buf, col, insertPos, textToCopy, NULL, NULL); TextDSetInsertPosition(textD, buf->cursorPosHint); XtFree(textToCopy); checkAutoShowInsertPos(w); } else if (primary->selected) { textToCopy = BufGetSelectionText(buf); insertPos = TextDGetInsertPosition(textD); BufInsert(buf, insertPos, textToCopy); TextDSetInsertPosition(textD, insertPos + strlen(textToCopy)); XtFree(textToCopy); checkAutoShowInsertPos(w); } else if (rectangular) { if (!TextDPositionToXY(textD, TextDGetInsertPosition(textD), &tw->text.btnDownX, &tw->text.btnDownY)) return; /* shouldn't happen */ InsertPrimarySelection(w, e->time, True); } else InsertPrimarySelection(w, e->time, False); } static void cutPrimaryAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XKeyEvent *e = &event->xkey; textDisp *textD = ((TextWidget)w)->text.textD; textBuffer *buf = textD->buffer; selection *primary = &buf->primary; char *textToCopy; int rectangular = hasKey("rect", args, nArgs); int insertPos, col; cancelDrag(w); if (checkReadOnly(w)) return; if (primary->selected && rectangular) { textToCopy = BufGetSelectionText(buf); insertPos = TextDGetInsertPosition(textD); col = BufCountDispChars(buf, BufStartOfLine(buf, insertPos), insertPos); BufInsertCol(buf, col, insertPos, textToCopy, NULL, NULL); TextDSetInsertPosition(textD, buf->cursorPosHint); XtFree(textToCopy); BufRemoveSelected(buf); checkAutoShowInsertPos(w); } else if (primary->selected) { textToCopy = BufGetSelectionText(buf); insertPos = TextDGetInsertPosition(textD); BufInsert(buf, insertPos, textToCopy); TextDSetInsertPosition(textD, insertPos + strlen(textToCopy)); XtFree(textToCopy); BufRemoveSelected(buf); checkAutoShowInsertPos(w); } else if (rectangular) { if (!TextDPositionToXY(textD, TextDGetInsertPosition(textD), &((TextWidget)w)->text.btnDownX, &((TextWidget)w)->text.btnDownY)) return; /* shouldn't happen */ MovePrimarySelection(w, e->time, True); } else { MovePrimarySelection(w, e->time, False); } } static void mousePanAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XButtonEvent *e = &event->xbutton; TextWidget tw = (TextWidget)w; textDisp *textD = tw->text.textD; int lineHeight = textD->ascent + textD->descent; int topLineNum, horizOffset; static Cursor panCursor = 0; if (tw->text.dragState == MOUSE_PAN) { TextDSetScroll(textD, (tw->text.btnDownY - e->y + lineHeight/2) / lineHeight, tw->text.btnDownX - e->x); } else if (tw->text.dragState == NOT_CLICKED) { TextDGetScroll(textD, &topLineNum, &horizOffset); tw->text.btnDownX = e->x + horizOffset; tw->text.btnDownY = e->y + topLineNum * lineHeight; tw->text.dragState = MOUSE_PAN; if (!panCursor) panCursor = XCreateFontCursor(XtDisplay(w), XC_fleur); XGrabPointer(XtDisplay(w), XtWindow(w), False, ButtonMotionMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, panCursor, CurrentTime); } else cancelDrag(w); } static void pasteClipboardAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { if (hasKey("rect", args, nArgs)) TextColPasteClipboard(w, event->xkey.time); else TextPasteClipboard(w, event->xkey.time); } static void copyClipboardAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { TextCopyClipboard(w, event->xkey.time); } static void cutClipboardAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { TextCutClipboard(w, event->xkey.time); } static void insertStringAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { smartIndentCBStruct smartIndent; textDisp *textD = ((TextWidget)w)->text.textD; if (*nArgs == 0) return; cancelDrag(w); if (checkReadOnly(w)) return; if (((TextWidget)w)->text.smartIndent) { smartIndent.reason = CHAR_TYPED; smartIndent.pos = TextDGetInsertPosition(textD); smartIndent.indentRequest = 0; smartIndent.charsTyped = args[0]; XtCallCallbacks(w, textNsmartIndentCallback, (XtPointer)&smartIndent); } TextInsertAtCursor(w, args[0], event, True, True); BufUnselect((((TextWidget)w)->text.textD)->buffer); } static void selfInsertAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { WindowInfo* window = WidgetToWindow(w); #ifdef NO_XMIM static XComposeStatus compose = {NULL, 0}; #else int status; #endif XKeyEvent *e = &event->xkey; char chars[20]; KeySym keysym; int nChars; smartIndentCBStruct smartIndent; textDisp *textD = ((TextWidget)w)->text.textD; #ifdef NO_XMIM nChars = XLookupString(&event->xkey, chars, 19, &keysym, &compose); if (nChars == 0) return; #else nChars = XmImMbLookupString(w, &event->xkey, chars, 19, &keysym, &status); if (nChars == 0 || status == XLookupNone || status == XLookupKeySym || status == XBufferOverflow) return; #endif cancelDrag(w); if (checkReadOnly(w)) return; TakeMotifDestination(w, e->time); chars[nChars] = '\0'; if (!BufSubstituteNullChars(chars, nChars, window->buffer)) { DialogF(DF_ERR, window->shell, 1, "Error", "Too much binary data", "OK"); return; } /* If smart indent is on, call the smart indent callback to check the inserted character */ if (((TextWidget)w)->text.smartIndent) { smartIndent.reason = CHAR_TYPED; smartIndent.pos = TextDGetInsertPosition(textD); smartIndent.indentRequest = 0; smartIndent.charsTyped = chars; XtCallCallbacks(w, textNsmartIndentCallback, (XtPointer)&smartIndent); } TextInsertAtCursor(w, chars, event, True, True); BufUnselect(textD->buffer); } static void newlineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { if (((TextWidget)w)->text.autoIndent || ((TextWidget)w)->text.smartIndent) newlineAndIndentAP(w, event, args, nArgs); else newlineNoIndentAP(w, event, args, nArgs); } static void newlineNoIndentAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XKeyEvent *e = &event->xkey; cancelDrag(w); if (checkReadOnly(w)) return; TakeMotifDestination(w, e->time); simpleInsertAtCursor(w, "\n", event, True); BufUnselect((((TextWidget)w)->text.textD)->buffer); } static void newlineAndIndentAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XKeyEvent *e = &event->xkey; TextWidget tw = (TextWidget)w; textDisp *textD = tw->text.textD; textBuffer *buf = textD->buffer; char *indentStr; int cursorPos, lineStartPos, column; if (checkReadOnly(w)) return; cancelDrag(w); TakeMotifDestination(w, e->time); /* Create a string containing a newline followed by auto or smart indent string */ cursorPos = TextDGetInsertPosition(textD); lineStartPos = BufStartOfLine(buf, cursorPos); indentStr = createIndentString(tw, buf, 0, lineStartPos, cursorPos, NULL, &column); /* Insert it at the cursor */ simpleInsertAtCursor(w, indentStr, event, True); XtFree(indentStr); if (tw->text.emulateTabs > 0) { /* If emulated tabs are on, make the inserted indent deletable by tab. Round this up by faking the column a bit to the right to let the user delete half-tabs with one keypress. */ column += tw->text.emulateTabs - 1; tw->text.emTabsBeforeCursor = column / tw->text.emulateTabs; } BufUnselect(buf); } static void processTabAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; textBuffer *buf = textD->buffer; selection *sel = &buf->primary; int emTabDist = ((TextWidget)w)->text.emulateTabs; int emTabsBeforeCursor = ((TextWidget)w)->text.emTabsBeforeCursor; int insertPos, indent, startIndent, toIndent, lineStart, tabWidth; char *outStr, *outPtr; if (checkReadOnly(w)) return; cancelDrag(w); TakeMotifDestination(w, event->xkey.time); /* If emulated tabs are off, just insert a tab */ if (emTabDist <= 0) { TextInsertAtCursor(w, "\t", event, True, True); return; } /* Find the starting and ending indentation. If the tab is to replace an existing selection, use the start of the selection instead of the cursor position as the indent. When replacing rectangular selections, tabs are automatically recalculated as if the inserted text began at the start of the line */ insertPos = pendingSelection(w) ? sel->start : TextDGetInsertPosition(textD); lineStart = BufStartOfLine(buf, insertPos); if (pendingSelection(w) && sel->rectangular) insertPos = BufCountForwardDispChars(buf, lineStart, sel->rectStart); startIndent = BufCountDispChars(buf, lineStart, insertPos); toIndent = startIndent + emTabDist - (startIndent % emTabDist); if (pendingSelection(w) && sel->rectangular) { toIndent -= startIndent; startIndent = 0; } /* Allocate a buffer assuming all the inserted characters will be spaces */ outStr = XtMalloc(toIndent - startIndent + 1); /* Add spaces and tabs to outStr until it reaches toIndent */ outPtr = outStr; indent = startIndent; while (indent < toIndent) { tabWidth = BufCharWidth('\t', indent, buf->tabDist, buf->nullSubsChar); if (buf->useTabs && tabWidth > 1 && indent + tabWidth <= toIndent) { *outPtr++ = '\t'; indent += tabWidth; } else { *outPtr++ = ' '; indent++; } } *outPtr = '\0'; /* Insert the emulated tab */ TextInsertAtCursor(w, outStr, event, True, True); XtFree(outStr); /* Restore and ++ emTabsBeforeCursor cleared by TextInsertAtCursor */ ((TextWidget)w)->text.emTabsBeforeCursor = emTabsBeforeCursor + 1; BufUnselect(buf); } static void deleteSelectionAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XKeyEvent *e = &event->xkey; cancelDrag(w); if (checkReadOnly(w)) return; TakeMotifDestination(w, e->time); deletePendingSelection(w, event); } static void deletePreviousCharacterAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XKeyEvent *e = &event->xkey; textDisp *textD = ((TextWidget)w)->text.textD; int insertPos = TextDGetInsertPosition(textD); char c; int silent = hasKey("nobell", args, nArgs); cancelDrag(w); if (checkReadOnly(w)) return; TakeMotifDestination(w, e->time); if (deletePendingSelection(w, event)) return; if (insertPos == 0) { ringIfNecessary(silent, w); return; } if (deleteEmulatedTab(w, event)) return; if (((TextWidget)w)->text.overstrike) { c = BufGetCharacter(textD->buffer, insertPos - 1); if (c == '\n') BufRemove(textD->buffer, insertPos - 1, insertPos); else if (c != '\t') BufReplace(textD->buffer, insertPos - 1, insertPos, " "); } else { BufRemove(textD->buffer, insertPos - 1, insertPos); } TextDSetInsertPosition(textD, insertPos - 1); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } static void deleteNextCharacterAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XKeyEvent *e = &event->xkey; textDisp *textD = ((TextWidget)w)->text.textD; int insertPos = TextDGetInsertPosition(textD); int silent = hasKey("nobell", args, nArgs); cancelDrag(w); if (checkReadOnly(w)) return; TakeMotifDestination(w, e->time); if (deletePendingSelection(w, event)) return; if (insertPos == textD->buffer->length) { ringIfNecessary(silent, w); return; } BufRemove(textD->buffer, insertPos , insertPos + 1); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } static void deletePreviousWordAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XKeyEvent *e = &event->xkey; textDisp *textD = ((TextWidget)w)->text.textD; int insertPos = TextDGetInsertPosition(textD); int pos, lineStart = BufStartOfLine(textD->buffer, insertPos); char *delimiters = ((TextWidget)w)->text.delimiters; int silent = hasKey("nobell", args, nArgs); cancelDrag(w); if (checkReadOnly(w)) { return; } TakeMotifDestination(w, e->time); if (deletePendingSelection(w, event)) { return; } if (insertPos == lineStart) { ringIfNecessary(silent, w); return; } pos = max(insertPos - 1, 0); while (strchr(delimiters, BufGetCharacter(textD->buffer, pos)) != NULL && pos != lineStart) { pos--; } pos = startOfWord((TextWidget)w, pos); BufRemove(textD->buffer, pos, insertPos); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } static void deleteNextWordAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XKeyEvent *e = &event->xkey; textDisp *textD = ((TextWidget)w)->text.textD; int insertPos = TextDGetInsertPosition(textD); int pos, lineEnd = BufEndOfLine(textD->buffer, insertPos); char *delimiters = ((TextWidget)w)->text.delimiters; int silent = hasKey("nobell", args, nArgs); cancelDrag(w); if (checkReadOnly(w)) { return; } TakeMotifDestination(w, e->time); if (deletePendingSelection(w, event)) { return; } if (insertPos == lineEnd) { ringIfNecessary(silent, w); return; } pos = insertPos; while (strchr(delimiters, BufGetCharacter(textD->buffer, pos)) != NULL && pos != lineEnd) { pos++; } pos = endOfWord((TextWidget)w, pos); BufRemove(textD->buffer, insertPos, pos); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } static void deleteToEndOfLineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XKeyEvent *e = &event->xkey; textDisp *textD = ((TextWidget)w)->text.textD; int insertPos = TextDGetInsertPosition(textD); int endOfLine; int silent = 0; silent = hasKey("nobell", args, nArgs); if (hasKey("absolute", args, nArgs)) endOfLine = BufEndOfLine(textD->buffer, insertPos); else endOfLine = TextDEndOfLine(textD, insertPos, False); cancelDrag(w); if (checkReadOnly(w)) return; TakeMotifDestination(w, e->time); if (deletePendingSelection(w, event)) return; if (insertPos == endOfLine) { ringIfNecessary(silent, w); return; } BufRemove(textD->buffer, insertPos, endOfLine); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } static void deleteToStartOfLineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { XKeyEvent *e = &event->xkey; textDisp *textD = ((TextWidget)w)->text.textD; int insertPos = TextDGetInsertPosition(textD); int startOfLine; int silent = 0; silent = hasKey("nobell", args, nArgs); if (hasKey("wrap", args, nArgs)) startOfLine = TextDStartOfLine(textD, insertPos); else startOfLine = BufStartOfLine(textD->buffer, insertPos); cancelDrag(w); if (checkReadOnly(w)) return; TakeMotifDestination(w, e->time); if (deletePendingSelection(w, event)) return; if (insertPos == startOfLine) { ringIfNecessary(silent, w); return; } BufRemove(textD->buffer, startOfLine, insertPos); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } static void forwardCharacterAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { int insertPos = TextDGetInsertPosition(((TextWidget)w)->text.textD); int silent = hasKey("nobell", args, nArgs); cancelDrag(w); if (!TextDMoveRight(((TextWidget)w)->text.textD)) { ringIfNecessary(silent, w); } checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } static void backwardCharacterAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { int insertPos = TextDGetInsertPosition(((TextWidget)w)->text.textD); int silent = hasKey("nobell", args, nArgs); cancelDrag(w); if (!TextDMoveLeft(((TextWidget)w)->text.textD)) { ringIfNecessary(silent, w); } checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } static void forwardWordAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; textBuffer *buf = textD->buffer; int pos, insertPos = TextDGetInsertPosition(textD); char *delimiters = ((TextWidget)w)->text.delimiters; int silent = hasKey("nobell", args, nArgs); cancelDrag(w); if (insertPos == buf->length) { ringIfNecessary(silent, w); return; } pos = insertPos; if (hasKey("tail", args, nArgs)) { for (; poslength; pos++) { if (NULL == strchr(delimiters, BufGetCharacter(buf, pos))) { break; } } if (NULL == strchr(delimiters, BufGetCharacter(buf, pos))) { pos = endOfWord((TextWidget)w, pos); } } else { if (NULL == strchr(delimiters, BufGetCharacter(buf, pos))) { pos = endOfWord((TextWidget)w, pos); } for (; poslength; pos++) { if (NULL == strchr(delimiters, BufGetCharacter(buf, pos))) { break; } } } TextDSetInsertPosition(textD, pos); checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } static void backwardWordAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; textBuffer *buf = textD->buffer; int pos, insertPos = TextDGetInsertPosition(textD); char *delimiters = ((TextWidget)w)->text.delimiters; int silent = hasKey("nobell", args, nArgs); cancelDrag(w); if (insertPos == 0) { ringIfNecessary(silent, w); return; } pos = max(insertPos - 1, 0); while (strchr(delimiters, BufGetCharacter(buf, pos)) != NULL && pos > 0) pos--; pos = startOfWord((TextWidget)w, pos); TextDSetInsertPosition(textD, pos); checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } static void forwardParagraphAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; int pos, insertPos = TextDGetInsertPosition(textD); textBuffer *buf = textD->buffer; char c; static char whiteChars[] = " \t"; int silent = hasKey("nobell", args, nArgs); cancelDrag(w); if (insertPos == buf->length) { ringIfNecessary(silent, w); return; } pos = min(BufEndOfLine(buf, insertPos)+1, buf->length); while (pos < buf->length) { c = BufGetCharacter(buf, pos); if (c == '\n') break; if (strchr(whiteChars, c) != NULL) pos++; else pos = min(BufEndOfLine(buf, pos)+1, buf->length); } TextDSetInsertPosition(textD, min(pos+1, buf->length)); checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } static void backwardParagraphAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; int parStart, pos, insertPos = TextDGetInsertPosition(textD); textBuffer *buf = textD->buffer; char c; static char whiteChars[] = " \t"; int silent = hasKey("nobell", args, nArgs); cancelDrag(w); if (insertPos == 0) { ringIfNecessary(silent, w); return; } parStart = BufStartOfLine(buf, max(insertPos-1, 0)); pos = max(parStart - 2, 0); while (pos > 0) { c = BufGetCharacter(buf, pos); if (c == '\n') break; if (strchr(whiteChars, c) != NULL) pos--; else { parStart = BufStartOfLine(buf, pos); pos = max(parStart - 2, 0); } } TextDSetInsertPosition(textD, parStart); checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } static void keySelectAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; int stat, insertPos = TextDGetInsertPosition(textD); int silent = hasKey("nobell", args, nArgs); cancelDrag(w); if (hasKey("left", args, nArgs)) stat = TextDMoveLeft(textD); else if (hasKey("right", args, nArgs)) stat = TextDMoveRight(textD); else if (hasKey("up", args, nArgs)) stat = TextDMoveUp(textD, 0); else if (hasKey("down", args, nArgs)) stat = TextDMoveDown(textD, 0); else { keyMoveExtendSelection(w, event, insertPos, hasKey("rect", args,nArgs)); return; } if (!stat) { ringIfNecessary(silent, w); } else { keyMoveExtendSelection(w, event, insertPos, hasKey("rect", args,nArgs)); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } } static void processUpAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { int insertPos = TextDGetInsertPosition(((TextWidget)w)->text.textD); int silent = hasKey("nobell", args, nArgs); int abs = hasKey("absolute", args, nArgs); cancelDrag(w); if (!TextDMoveUp(((TextWidget)w)->text.textD, abs)) ringIfNecessary(silent, w); checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } static void processShiftUpAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { int insertPos = TextDGetInsertPosition(((TextWidget)w)->text.textD); int silent = hasKey("nobell", args, nArgs); int abs = hasKey("absolute", args, nArgs); cancelDrag(w); if (!TextDMoveUp(((TextWidget)w)->text.textD, abs)) ringIfNecessary(silent, w); keyMoveExtendSelection(w, event, insertPos, hasKey("rect", args, nArgs)); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } static void processDownAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { int insertPos = TextDGetInsertPosition(((TextWidget)w)->text.textD); int silent = hasKey("nobell", args, nArgs); int abs = hasKey("absolute", args, nArgs); cancelDrag(w); if (!TextDMoveDown(((TextWidget)w)->text.textD, abs)) ringIfNecessary(silent, w); checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } static void processShiftDownAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { int insertPos = TextDGetInsertPosition(((TextWidget)w)->text.textD); int silent = hasKey("nobell", args, nArgs); int abs = hasKey("absolute", args, nArgs); cancelDrag(w); if (!TextDMoveDown(((TextWidget)w)->text.textD, abs)) ringIfNecessary(silent, w); keyMoveExtendSelection(w, event, insertPos, hasKey("rect", args, nArgs)); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } static void beginningOfLineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; int insertPos = TextDGetInsertPosition(textD); cancelDrag(w); if (hasKey("absolute", args, nArgs)) TextDSetInsertPosition(textD, BufStartOfLine(textD->buffer, insertPos)); else TextDSetInsertPosition(textD, TextDStartOfLine(textD, insertPos)); checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); textD->cursorPreferredCol = 0; } static void endOfLineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; int insertPos = TextDGetInsertPosition(textD); cancelDrag(w); if (hasKey("absolute", args, nArgs)) TextDSetInsertPosition(textD, BufEndOfLine(textD->buffer, insertPos)); else TextDSetInsertPosition(textD, TextDEndOfLine(textD, insertPos, False)); checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); textD->cursorPreferredCol = -1; } static void beginningOfFileAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { int insertPos = TextDGetInsertPosition(((TextWidget)w)->text.textD); textDisp *textD = ((TextWidget)w)->text.textD; cancelDrag(w); if (hasKey("scrollbar", args, nArgs)) { if (textD->topLineNum != 1) { TextDSetScroll(textD, 1, textD->horizOffset); } } else { TextDSetInsertPosition(((TextWidget)w)->text.textD, 0); checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } } static void endOfFileAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; int insertPos = TextDGetInsertPosition(textD); int lastTopLine; cancelDrag(w); if (hasKey("scrollbar", args, nArgs)) { lastTopLine = max(1, textD->nBufferLines - (textD->nVisibleLines - 2) + ((TextWidget)w)->text.cursorVPadding); if (lastTopLine != textD->topLineNum) { TextDSetScroll(textD, lastTopLine, textD->horizOffset); } } else { TextDSetInsertPosition(textD, textD->buffer->length); checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } } static void nextPageAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; textBuffer *buf = textD->buffer; int lastTopLine = max(1, textD->nBufferLines - (textD->nVisibleLines - 2) + ((TextWidget)w)->text.cursorVPadding ); int insertPos = TextDGetInsertPosition(textD); int column = 0, visLineNum, lineStartPos; int pos, targetLine; int pageForwardCount = max(1, textD->nVisibleLines - 1); int maintainColumn = 0; int silent = hasKey("nobell", args, nArgs); maintainColumn = hasKey("column", args, nArgs); cancelDrag(w); if (hasKey("scrollbar", args, nArgs)) { /* scrollbar only */ targetLine = min(textD->topLineNum + pageForwardCount, lastTopLine); if (targetLine == textD->topLineNum) { ringIfNecessary(silent, w); return; } TextDSetScroll(textD, targetLine, textD->horizOffset); } else if (hasKey("stutter", args, nArgs)) { /* Mac style */ /* move to bottom line of visible area */ /* if already there, page down maintaining preferrred column */ targetLine = max(min(textD->nVisibleLines - 1, textD->nBufferLines), 0); column = TextDPreferredColumn(textD, &visLineNum, &lineStartPos); if (lineStartPos == textD->lineStarts[targetLine]) { if (insertPos >= buf->length || textD->topLineNum == lastTopLine) { ringIfNecessary(silent, w); return; } targetLine = min(textD->topLineNum + pageForwardCount, lastTopLine); pos = TextDCountForwardNLines(textD, insertPos, pageForwardCount, False); if (maintainColumn) { pos = TextDPosOfPreferredCol(textD, column, pos); } TextDSetInsertPosition(textD, pos); TextDSetScroll(textD, targetLine, textD->horizOffset); } else { pos = textD->lineStarts[targetLine]; while (targetLine > 0 && pos == -1) { --targetLine; pos = textD->lineStarts[targetLine]; } if (lineStartPos == pos) { ringIfNecessary(silent, w); return; } if (maintainColumn) { pos = TextDPosOfPreferredCol(textD, column, pos); } TextDSetInsertPosition(textD, pos); } checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); if (maintainColumn) { textD->cursorPreferredCol = column; } else { textD->cursorPreferredCol = -1; } } else { /* "standard" */ if (insertPos >= buf->length && textD->topLineNum == lastTopLine) { ringIfNecessary(silent, w); return; } if (maintainColumn) { column = TextDPreferredColumn(textD, &visLineNum, &lineStartPos); } targetLine = textD->topLineNum + textD->nVisibleLines - 1; if (targetLine < 1) targetLine = 1; if (targetLine > lastTopLine) targetLine = lastTopLine; pos = TextDCountForwardNLines(textD, insertPos, textD->nVisibleLines-1, False); if (maintainColumn) { pos = TextDPosOfPreferredCol(textD, column, pos); } TextDSetInsertPosition(textD, pos); TextDSetScroll(textD, targetLine, textD->horizOffset); checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); if (maintainColumn) { textD->cursorPreferredCol = column; } else { textD->cursorPreferredCol = -1; } } } static void previousPageAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; int insertPos = TextDGetInsertPosition(textD); int column = 0, visLineNum, lineStartPos; int pos, targetLine; int pageBackwardCount = max(1, textD->nVisibleLines - 1); int maintainColumn = 0; int silent = hasKey("nobell", args, nArgs); maintainColumn = hasKey("column", args, nArgs); cancelDrag(w); if (hasKey("scrollbar", args, nArgs)) { /* scrollbar only */ targetLine = max(textD->topLineNum - pageBackwardCount, 1); if (targetLine == textD->topLineNum) { ringIfNecessary(silent, w); return; } TextDSetScroll(textD, targetLine, textD->horizOffset); } else if (hasKey("stutter", args, nArgs)) { /* Mac style */ /* move to top line of visible area */ /* if already there, page up maintaining preferrred column if required */ targetLine = 0; column = TextDPreferredColumn(textD, &visLineNum, &lineStartPos); if (lineStartPos == textD->lineStarts[targetLine]) { if (textD->topLineNum == 1 && (maintainColumn || column == 0)) { ringIfNecessary(silent, w); return; } targetLine = max(textD->topLineNum - pageBackwardCount, 1); pos = TextDCountBackwardNLines(textD, insertPos, pageBackwardCount); if (maintainColumn) { pos = TextDPosOfPreferredCol(textD, column, pos); } TextDSetInsertPosition(textD, pos); TextDSetScroll(textD, targetLine, textD->horizOffset); } else { pos = textD->lineStarts[targetLine]; if (maintainColumn) { pos = TextDPosOfPreferredCol(textD, column, pos); } TextDSetInsertPosition(textD, pos); } checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); if (maintainColumn) { textD->cursorPreferredCol = column; } else { textD->cursorPreferredCol = -1; } } else { /* "standard" */ if (insertPos <= 0 && textD->topLineNum == 1) { ringIfNecessary(silent, w); return; } if (maintainColumn) { column = TextDPreferredColumn(textD, &visLineNum, &lineStartPos); } targetLine = textD->topLineNum - (textD->nVisibleLines - 1); if (targetLine < 1) targetLine = 1; pos = TextDCountBackwardNLines(textD, insertPos, textD->nVisibleLines-1); if (maintainColumn) { pos = TextDPosOfPreferredCol(textD, column, pos); } TextDSetInsertPosition(textD, pos); TextDSetScroll(textD, targetLine, textD->horizOffset); checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); if (maintainColumn) { textD->cursorPreferredCol = column; } else { textD->cursorPreferredCol = -1; } } } static void pageLeftAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; textBuffer *buf = textD->buffer; int insertPos = TextDGetInsertPosition(textD); int maxCharWidth = textD->fontStruct->max_bounds.width; int lineStartPos, indent, pos; int horizOffset; int silent = hasKey("nobell", args, nArgs); cancelDrag(w); if (hasKey("scrollbar", args, nArgs)) { if (textD->horizOffset == 0) { ringIfNecessary(silent, w); return; } horizOffset = max(0, textD->horizOffset - textD->width); TextDSetScroll(textD, textD->topLineNum, horizOffset); } else { lineStartPos = BufStartOfLine(buf, insertPos); if (insertPos == lineStartPos && textD->horizOffset == 0) { ringIfNecessary(silent, w); return; } indent = BufCountDispChars(buf, lineStartPos, insertPos); pos = BufCountForwardDispChars(buf, lineStartPos, max(0, indent - textD->width / maxCharWidth)); TextDSetInsertPosition(textD, pos); TextDSetScroll(textD, textD->topLineNum, max(0, textD->horizOffset - textD->width)); checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } } static void pageRightAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; textBuffer *buf = textD->buffer; int insertPos = TextDGetInsertPosition(textD); int maxCharWidth = textD->fontStruct->max_bounds.width; int oldHorizOffset = textD->horizOffset; int lineStartPos, indent, pos; int horizOffset, sliderSize, sliderMax; int silent = hasKey("nobell", args, nArgs); cancelDrag(w); if (hasKey("scrollbar", args, nArgs)) { XtVaGetValues(textD->hScrollBar, XmNmaximum, &sliderMax, XmNsliderSize, &sliderSize, NULL); horizOffset = min(textD->horizOffset + textD->width, sliderMax - sliderSize); if (textD->horizOffset == horizOffset) { ringIfNecessary(silent, w); return; } TextDSetScroll(textD, textD->topLineNum, horizOffset); } else { lineStartPos = BufStartOfLine(buf, insertPos); indent = BufCountDispChars(buf, lineStartPos, insertPos); pos = BufCountForwardDispChars(buf, lineStartPos, indent + textD->width / maxCharWidth); TextDSetInsertPosition(textD, pos); TextDSetScroll(textD, textD->topLineNum, textD->horizOffset + textD->width); if (textD->horizOffset == oldHorizOffset && insertPos == pos) ringIfNecessary(silent, w); checkMoveSelectionChange(w, event, insertPos, args, nArgs); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } } static void toggleOverstrikeAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { TextWidget tw = (TextWidget)w; if (tw->text.overstrike) { tw->text.overstrike = False; TextDSetCursorStyle(tw->text.textD, tw->text.heavyCursor ? HEAVY_CURSOR : NORMAL_CURSOR); } else { tw->text.overstrike = True; if ( tw->text.textD->cursorStyle == NORMAL_CURSOR || tw->text.textD->cursorStyle == HEAVY_CURSOR) TextDSetCursorStyle(tw->text.textD, BLOCK_CURSOR); } } static void scrollUpAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; int topLineNum, horizOffset, nLines; if (*nArgs == 0 || sscanf(args[0], "%d", &nLines) != 1) return; if (*nArgs == 2) { /* Allow both 'page' and 'pages' */ if (strncmp(args[1], "page", 4) == 0) nLines *= textD->nVisibleLines; /* 'line' or 'lines' is the only other valid possibility */ else if (strncmp(args[1], "line", 4) != 0) return; } TextDGetScroll(textD, &topLineNum, &horizOffset); TextDSetScroll(textD, topLineNum-nLines, horizOffset); } static void scrollDownAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; int topLineNum, horizOffset, nLines; if (*nArgs == 0 || sscanf(args[0], "%d", &nLines) != 1) return; if (*nArgs == 2) { /* Allow both 'page' and 'pages' */ if (strncmp(args[1], "page", 4) == 0) nLines *= textD->nVisibleLines; /* 'line' or 'lines' is the only other valid possibility */ else if (strncmp(args[1], "line", 4) != 0) return; } TextDGetScroll(textD, &topLineNum, &horizOffset); TextDSetScroll(textD, topLineNum+nLines, horizOffset); } static void scrollLeftAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; int horizOffset, nPixels; int sliderMax, sliderSize; if (*nArgs == 0 || sscanf(args[0], "%d", &nPixels) != 1) return; XtVaGetValues(textD->hScrollBar, XmNmaximum, &sliderMax, XmNsliderSize, &sliderSize, NULL); horizOffset = min(max(0, textD->horizOffset - nPixels), sliderMax - sliderSize); if (textD->horizOffset != horizOffset) { TextDSetScroll(textD, textD->topLineNum, horizOffset); } } static void scrollRightAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; int horizOffset, nPixels; int sliderMax, sliderSize; if (*nArgs == 0 || sscanf(args[0], "%d", &nPixels) != 1) return; XtVaGetValues(textD->hScrollBar, XmNmaximum, &sliderMax, XmNsliderSize, &sliderSize, NULL); horizOffset = min(max(0, textD->horizOffset + nPixels), sliderMax - sliderSize); if (textD->horizOffset != horizOffset) { TextDSetScroll(textD, textD->topLineNum, horizOffset); } } static void scrollToLineAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; int topLineNum, horizOffset, lineNum; if (*nArgs == 0 || sscanf(args[0], "%d", &lineNum) != 1) return; TextDGetScroll(textD, &topLineNum, &horizOffset); TextDSetScroll(textD, lineNum, horizOffset); } static void selectAllAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textBuffer *buf = ((TextWidget)w)->text.textD->buffer; cancelDrag(w); BufSelect(buf, 0, buf->length); } static void deselectAllAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { cancelDrag(w); BufUnselect(((TextWidget)w)->text.textD->buffer); } /* ** Called on the Intrinsic FocusIn event. ** ** Note that the widget has no internal state about the focus, ie. it does ** not know whether it has the focus or not. */ static void focusInAP(Widget widget, XEvent* event, String* unused1, Cardinal* unused2) { TextWidget textwidget = (TextWidget) widget; textDisp* textD = textwidget->text.textD; /* I don't entirely understand the traversal mechanism in Motif widgets, particularly, what leads to this widget getting a focus-in event when it does not actually have the input focus. The temporary solution is to do the comparison below, and not show the cursor when Motif says we don't have focus, but keep looking for the real answer */ #if XmVersion >= 1002 if (widget != XmGetFocusWidget(widget)) return; #endif /* If the timer is not already started, start it */ if (textwidget->text.cursorBlinkRate != 0 && textwidget->text.cursorBlinkProcID == 0) { textwidget->text.cursorBlinkProcID = XtAppAddTimeOut(XtWidgetToApplicationContext(widget), textwidget->text.cursorBlinkRate, cursorBlinkTimerProc, widget); } /* Change the cursor to active style */ if (textwidget->text.overstrike) TextDSetCursorStyle(textD, BLOCK_CURSOR); else TextDSetCursorStyle(textD, (textwidget->text.heavyCursor ? HEAVY_CURSOR : NORMAL_CURSOR)); TextDUnblankCursor(textD); #ifndef NO_XMIM /* Notify Motif input manager that widget has focus */ XmImVaSetFocusValues(widget, NULL); #endif /* Call any registered focus-in callbacks */ XtCallCallbacks((Widget) widget, textNfocusCallback, (XtPointer) event); } static void focusOutAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { textDisp *textD = ((TextWidget)w)->text.textD; /* Remove the cursor blinking timer procedure */ if (((TextWidget)w)->text.cursorBlinkProcID != 0) XtRemoveTimeOut(((TextWidget)w)->text.cursorBlinkProcID); ((TextWidget)w)->text.cursorBlinkProcID = 0; /* Leave a dim or destination cursor */ TextDSetCursorStyle(textD, ((TextWidget)w)->text.motifDestOwner ? CARET_CURSOR : DIM_CURSOR); TextDUnblankCursor(textD); /* If there's a calltip displayed, kill it. */ TextDKillCalltip(textD, 0); /* Call any registered focus-out callbacks */ XtCallCallbacks((Widget)w, textNlosingFocusCallback, (XtPointer)event); } /* ** For actions involving cursor movement, "extend" keyword means incorporate ** the new cursor position in the selection, and lack of an "extend" keyword ** means cancel the existing selection */ static void checkMoveSelectionChange(Widget w, XEvent *event, int startPos, String *args, Cardinal *nArgs) { if (hasKey("extend", args, nArgs)) keyMoveExtendSelection(w, event, startPos, hasKey("rect", args, nArgs)); else BufUnselect((((TextWidget)w)->text.textD)->buffer); } /* ** If a selection change was requested via a keyboard command for moving ** the insertion cursor (usually with the "extend" keyword), adjust the ** selection to include the new cursor position, or begin a new selection ** between startPos and the new cursor position with anchor at startPos. */ static void keyMoveExtendSelection(Widget w, XEvent *event, int origPos, int rectangular) { XKeyEvent *e = &event->xkey; TextWidget tw = (TextWidget)w; textDisp *textD = tw->text.textD; textBuffer *buf = textD->buffer; selection *sel = &buf->primary; int newPos = TextDGetInsertPosition(textD); int startPos, endPos, startCol, endCol, newCol, origCol; int anchor, rectAnchor, anchorLineStart; /* Moving the cursor does not take the Motif destination, but as soon as the user selects something, grab it (I'm not sure if this distinction actually makes sense, but it's what Motif was doing, back when their secondary selections actually worked correctly) */ TakeMotifDestination(w, e->time); if ((sel->selected || sel->zeroWidth) && sel->rectangular && rectangular) { /* rect -> rect */ newCol = BufCountDispChars(buf, BufStartOfLine(buf, newPos), newPos); startCol = min(tw->text.rectAnchor, newCol); endCol = max(tw->text.rectAnchor, newCol); startPos = BufStartOfLine(buf, min(tw->text.anchor, newPos)); endPos = BufEndOfLine(buf, max(tw->text.anchor, newPos)); BufRectSelect(buf, startPos, endPos, startCol, endCol); } else if (sel->selected && rectangular) { /* plain -> rect */ newCol = BufCountDispChars(buf, BufStartOfLine(buf, newPos), newPos); if (abs(newPos - sel->start) < abs(newPos - sel->end)) anchor = sel->end; else anchor = sel->start; anchorLineStart = BufStartOfLine(buf, anchor); rectAnchor = BufCountDispChars(buf, anchorLineStart, anchor); tw->text.anchor = anchor; tw->text.rectAnchor = rectAnchor; BufRectSelect(buf, BufStartOfLine(buf, min(anchor, newPos)), BufEndOfLine(buf, max(anchor, newPos)), min(rectAnchor, newCol), max(rectAnchor, newCol)); } else if (sel->selected && sel->rectangular) { /* rect -> plain */ startPos = BufCountForwardDispChars(buf, BufStartOfLine(buf, sel->start), sel->rectStart); endPos = BufCountForwardDispChars(buf, BufStartOfLine(buf, sel->end), sel->rectEnd); if (abs(origPos - startPos) < abs(origPos - endPos)) anchor = endPos; else anchor = startPos; BufSelect(buf, anchor, newPos); } else if (sel->selected) { /* plain -> plain */ if (abs(origPos - sel->start) < abs(origPos - sel->end)) anchor = sel->end; else anchor = sel->start; BufSelect(buf, anchor, newPos); } else if (rectangular) { /* no sel -> rect */ origCol = BufCountDispChars(buf, BufStartOfLine(buf, origPos), origPos); newCol = BufCountDispChars(buf, BufStartOfLine(buf, newPos), newPos); startCol = min(newCol, origCol); endCol = max(newCol, origCol); startPos = BufStartOfLine(buf, min(origPos, newPos)); endPos = BufEndOfLine(buf, max(origPos, newPos)); tw->text.anchor = origPos; tw->text.rectAnchor = origCol; BufRectSelect(buf, startPos, endPos, startCol, endCol); } else { /* no sel -> plain */ tw->text.anchor = origPos; tw->text.rectAnchor = BufCountDispChars(buf, BufStartOfLine(buf, origPos), origPos); BufSelect(buf, tw->text.anchor, newPos); } } static void checkAutoShowInsertPos(Widget w) { if (((TextWidget)w)->text.autoShowInsertPos) TextDMakeInsertPosVisible(((TextWidget)w)->text.textD); } static int checkReadOnly(Widget w) { if (((TextWidget)w)->text.readOnly) { XBell(XtDisplay(w), 0); return True; } return False; } /* ** Insert text "chars" at the cursor position, as if the text had been ** typed. Same as TextInsertAtCursor, but without the complicated auto-wrap ** scanning and re-formatting. */ static void simpleInsertAtCursor(Widget w, char *chars, XEvent *event, int allowPendingDelete) { textDisp *textD = ((TextWidget)w)->text.textD; textBuffer *buf = textD->buffer; char *c; if (allowPendingDelete && pendingSelection(w)) { BufReplaceSelected(buf, chars); TextDSetInsertPosition(textD, buf->cursorPosHint); } else if (((TextWidget)w)->text.overstrike) { for (c=chars; *c!='\0' && *c!='\n'; c++); if (*c == '\n') TextDInsert(textD, chars); else TextDOverstrike(textD, chars); } else TextDInsert(textD, chars); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); } /* ** If there's a selection, delete it and position the cursor where the ** selection was deleted. (Called by routines which do deletion to check ** first for and do possible selection delete) */ static int deletePendingSelection(Widget w, XEvent *event) { textDisp *textD = ((TextWidget)w)->text.textD; textBuffer *buf = textD->buffer; if (((TextWidget)w)->text.textD->buffer->primary.selected) { BufRemoveSelected(buf); TextDSetInsertPosition(textD, buf->cursorPosHint); checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); return True; } else return False; } /* ** Return true if pending delete is on and there's a selection contiguous ** with the cursor ready to be deleted. These criteria are used to decide ** if typing a character or inserting something should delete the selection ** first. */ static int pendingSelection(Widget w) { selection *sel = &((TextWidget)w)->text.textD->buffer->primary; int pos = TextDGetInsertPosition(((TextWidget)w)->text.textD); return ((TextWidget)w)->text.pendingDelete && sel->selected && pos >= sel->start && pos <= sel->end; } /* ** Check if tab emulation is on and if there are emulated tabs before the ** cursor, and if so, delete an emulated tab as a unit. Also finishes up ** by calling checkAutoShowInsertPos and callCursorMovementCBs, so the ** calling action proc can just return (this is necessary to preserve ** emTabsBeforeCursor which is otherwise cleared by callCursorMovementCBs). */ static int deleteEmulatedTab(Widget w, XEvent *event) { textDisp *textD = ((TextWidget)w)->text.textD; textBuffer *buf = ((TextWidget)w)->text.textD->buffer; int emTabDist = ((TextWidget)w)->text.emulateTabs; int emTabsBeforeCursor = ((TextWidget)w)->text.emTabsBeforeCursor; int startIndent, toIndent, insertPos, startPos, lineStart; int pos, indent, startPosIndent; char c, *spaceString; if (emTabDist <= 0 || emTabsBeforeCursor <= 0) return False; /* Find the position of the previous tab stop */ insertPos = TextDGetInsertPosition(textD); lineStart = BufStartOfLine(buf, insertPos); startIndent = BufCountDispChars(buf, lineStart, insertPos); toIndent = (startIndent-1) - ((startIndent-1) % emTabDist); /* Find the position at which to begin deleting (stop at non-whitespace characters) */ startPosIndent = indent = 0; startPos = lineStart; for (pos=lineStart; pos < insertPos; pos++) { c = BufGetCharacter(buf, pos); indent += BufCharWidth(c, indent, buf->tabDist, buf->nullSubsChar); if (indent > toIndent) break; startPosIndent = indent; startPos = pos + 1; } /* Just to make sure, check that we're not deleting any non-white chars */ for (pos=insertPos-1; pos>=startPos; pos--) { c = BufGetCharacter(buf, pos); if (c != ' ' && c != '\t') { startPos = pos + 1; break; } } /* Do the text replacement and reposition the cursor. If any spaces need to be inserted to make up for a deleted tab, do a BufReplace, otherwise, do a BufRemove. */ if (startPosIndent < toIndent) { spaceString = XtMalloc(toIndent - startPosIndent + 1); memset(spaceString, ' ', toIndent-startPosIndent); spaceString[toIndent - startPosIndent] = '\0'; BufReplace(buf, startPos, insertPos, spaceString); TextDSetInsertPosition(textD, startPos + toIndent - startPosIndent); XtFree(spaceString); } else { BufRemove(buf, startPos, insertPos); TextDSetInsertPosition(textD, startPos); } /* The normal cursor movement stuff would usually be called by the action routine, but this wraps around it to restore emTabsBeforeCursor */ checkAutoShowInsertPos(w); callCursorMovementCBs(w, event); /* Decrement and restore the marker for consecutive emulated tabs, which would otherwise have been zeroed by callCursorMovementCBs */ ((TextWidget)w)->text.emTabsBeforeCursor = emTabsBeforeCursor - 1; return True; } /* ** Select the word or whitespace adjacent to the cursor, and move the cursor ** to its end. pointerX is used as a tie-breaker, when the cursor is at the ** boundary between a word and some white-space. If the cursor is on the ** left, the word or space on the left is used. If it's on the right, that ** is used instead. */ static void selectWord(Widget w, int pointerX) { TextWidget tw = (TextWidget)w; textBuffer *buf = tw->text.textD->buffer; int x, y, insertPos = TextDGetInsertPosition(tw->text.textD); TextPosToXY(w, insertPos, &x, &y); if (pointerX < x && insertPos > 0 && BufGetCharacter(buf, insertPos-1) != '\n') insertPos--; BufSelect(buf, startOfWord(tw, insertPos), endOfWord(tw, insertPos)); } static int startOfWord(TextWidget w, int pos) { int startPos; textBuffer *buf = w->text.textD->buffer; char *delimiters=w->text.delimiters; char c = BufGetCharacter(buf, pos); if (c == ' ' || c== '\t') { if (!spanBackward(buf, pos, " \t", False, &startPos)) return 0; } else if (strchr(delimiters, c)) { if (!spanBackward(buf, pos, delimiters, True, &startPos)) return 0; } else { if (!BufSearchBackward(buf, pos, delimiters, &startPos)) return 0; } return min(pos, startPos+1); } static int endOfWord(TextWidget w, int pos) { int endPos; textBuffer *buf = w->text.textD->buffer; char *delimiters=w->text.delimiters; char c = BufGetCharacter(buf, pos); if (c == ' ' || c== '\t') { if (!spanForward(buf, pos, " \t", False, &endPos)) return buf->length; } else if (strchr(delimiters, c)) { if (!spanForward(buf, pos, delimiters, True, &endPos)) return buf->length; } else { if (!BufSearchForward(buf, pos, delimiters, &endPos)) return buf->length; } return endPos; } /* ** Search forwards in buffer "buf" for the first character NOT in ** "searchChars", starting with the character "startPos", and returning the ** result in "foundPos" returns True if found, False if not. If ignoreSpace ** is set, then Space, Tab, and Newlines are ignored in searchChars. */ static int spanForward(textBuffer *buf, int startPos, char *searchChars, int ignoreSpace, int *foundPos) { int pos; char *c; pos = startPos; while (pos < buf->length) { for (c=searchChars; *c!='\0'; c++) if(!(ignoreSpace && (*c==' ' || *c=='\t' || *c=='\n'))) if (BufGetCharacter(buf, pos) == *c) break; if(*c == 0) { *foundPos = pos; return True; } pos++; } *foundPos = buf->length; return False; } /* ** Search backwards in buffer "buf" for the first character NOT in ** "searchChars", starting with the character BEFORE "startPos", returning the ** result in "foundPos" returns True if found, False if not. If ignoreSpace is ** set, then Space, Tab, and Newlines are ignored in searchChars. */ static int spanBackward(textBuffer *buf, int startPos, char *searchChars, int ignoreSpace, int *foundPos) { int pos; char *c; if (startPos == 0) { *foundPos = 0; return False; } pos = startPos == 0 ? 0 : startPos - 1; while (pos >= 0) { for (c=searchChars; *c!='\0'; c++) if(!(ignoreSpace && (*c==' ' || *c=='\t' || *c=='\n'))) if (BufGetCharacter(buf, pos) == *c) break; if(*c == 0) { *foundPos = pos; return True; } pos--; } *foundPos = 0; return False; } /* ** Select the line containing the cursor, including the terminating newline, ** and move the cursor to its end. */ static void selectLine(Widget w) { textDisp *textD = ((TextWidget)w)->text.textD; int insertPos = TextDGetInsertPosition(textD); int endPos, startPos; endPos = BufEndOfLine(textD->buffer, insertPos); startPos = BufStartOfLine(textD->buffer, insertPos); BufSelect(textD->buffer, startPos, min(endPos + 1, textD->buffer->length)); TextDSetInsertPosition(textD, endPos); } /* ** Given a new mouse pointer location, pass the position on to the ** autoscroll timer routine, and make sure the timer is on when it's ** needed and off when it's not. */ static void checkAutoScroll(TextWidget w, int x, int y) { int inWindow; /* Is the pointer in or out of the window? */ inWindow = x >= w->text.textD->left && x < w->core.width - w->text.marginWidth && y >= w->text.marginHeight && y < w->core.height - w->text.marginHeight; /* If it's in the window, cancel the timer procedure */ if (inWindow) { if (w->text.autoScrollProcID != 0) XtRemoveTimeOut(w->text.autoScrollProcID);; w->text.autoScrollProcID = 0; return; } /* If the timer is not already started, start it */ if (w->text.autoScrollProcID == 0) { w->text.autoScrollProcID = XtAppAddTimeOut( XtWidgetToApplicationContext((Widget)w), 0, autoScrollTimerProc, w); } /* Pass on the newest mouse location to the autoscroll routine */ w->text.mouseX = x; w->text.mouseY = y; } /* ** Reset drag state and cancel the auto-scroll timer */ static void endDrag(Widget w) { if (((TextWidget)w)->text.autoScrollProcID != 0) XtRemoveTimeOut(((TextWidget)w)->text.autoScrollProcID); ((TextWidget)w)->text.autoScrollProcID = 0; if (((TextWidget)w)->text.dragState == MOUSE_PAN) XUngrabPointer(XtDisplay(w), CurrentTime); ((TextWidget)w)->text.dragState = NOT_CLICKED; } /* ** Cancel any drag operation that might be in progress. Should be included ** in nearly every key event to cleanly end any dragging before edits are made ** which might change the insert position or the content of the buffer during ** a drag operation) */ static void cancelDrag(Widget w) { int dragState = ((TextWidget)w)->text.dragState; if (((TextWidget)w)->text.autoScrollProcID != 0) XtRemoveTimeOut(((TextWidget)w)->text.autoScrollProcID); if (dragState == SECONDARY_DRAG || dragState == SECONDARY_RECT_DRAG) BufSecondaryUnselect(((TextWidget)w)->text.textD->buffer); if (dragState == PRIMARY_BLOCK_DRAG) CancelBlockDrag((TextWidget)w); if (dragState == MOUSE_PAN) XUngrabPointer(XtDisplay(w), CurrentTime); if (dragState != NOT_CLICKED) ((TextWidget)w)->text.dragState = DRAG_CANCELED; } /* ** Do operations triggered by cursor movement: Call cursor movement callback ** procedure(s), and cancel marker indicating that the cursor is after one or ** more just-entered emulated tabs (spaces to be deleted as a unit). */ static void callCursorMovementCBs(Widget w, XEvent *event) { ((TextWidget)w)->text.emTabsBeforeCursor = 0; XtCallCallbacks((Widget)w, textNcursorMovementCallback, (XtPointer)event); } /* ** Adjust the selection as the mouse is dragged to position: (x, y). */ static void adjustSelection(TextWidget tw, int x, int y) { textDisp *textD = tw->text.textD; textBuffer *buf = textD->buffer; int row, col, startCol, endCol, startPos, endPos; int newPos = TextDXYToPosition(textD, x, y); /* Adjust the selection */ if (tw->text.dragState == PRIMARY_RECT_DRAG) { TextDXYToUnconstrainedPosition(textD, x, y, &row, &col); col = TextDOffsetWrappedColumn(textD, row, col); startCol = min(tw->text.rectAnchor, col); endCol = max(tw->text.rectAnchor, col); startPos = BufStartOfLine(buf, min(tw->text.anchor, newPos)); endPos = BufEndOfLine(buf, max(tw->text.anchor, newPos)); BufRectSelect(buf, startPos, endPos, startCol, endCol); } else if (tw->text.multiClickState == ONE_CLICK) { startPos = startOfWord(tw, min(tw->text.anchor, newPos)); endPos = endOfWord(tw, max(tw->text.anchor, newPos)); BufSelect(buf, startPos, endPos); newPos = newPos < tw->text.anchor ? startPos : endPos; } else if (tw->text.multiClickState == TWO_CLICKS) { startPos = BufStartOfLine(buf, min(tw->text.anchor, newPos)); endPos = BufEndOfLine(buf, max(tw->text.anchor, newPos)); BufSelect(buf, startPos, min(endPos+1, buf->length)); newPos = newPos < tw->text.anchor ? startPos : endPos; } else BufSelect(buf, tw->text.anchor, newPos); /* Move the cursor */ TextDSetInsertPosition(textD, newPos); callCursorMovementCBs((Widget)tw, NULL); } static void adjustSecondarySelection(TextWidget tw, int x, int y) { textDisp *textD = tw->text.textD; textBuffer *buf = textD->buffer; int row, col, startCol, endCol, startPos, endPos; int newPos = TextDXYToPosition(textD, x, y); if (tw->text.dragState == SECONDARY_RECT_DRAG) { TextDXYToUnconstrainedPosition(textD, x, y, &row, &col); col = TextDOffsetWrappedColumn(textD, row, col); startCol = min(tw->text.rectAnchor, col); endCol = max(tw->text.rectAnchor, col); startPos = BufStartOfLine(buf, min(tw->text.anchor, newPos)); endPos = BufEndOfLine(buf, max(tw->text.anchor, newPos)); BufSecRectSelect(buf, startPos, endPos, startCol, endCol); } else BufSecondarySelect(textD->buffer, tw->text.anchor, newPos); } /* ** Wrap multi-line text in argument "text" to be inserted at the end of the ** text on line "startLine" and return the result. If "breakBefore" is ** non-NULL, allow wrapping to extend back into "startLine", in which case ** the returned text will include the wrapped part of "startLine", and ** "breakBefore" will return the number of characters at the end of ** "startLine" that were absorbed into the returned string. "breakBefore" ** will return zero if no characters were absorbed into the returned string. ** The buffer offset of text in the widget's text buffer is needed so that ** smart indent (which can be triggered by wrapping) can search back farther ** in the buffer than just the text in startLine. */ static char *wrapText(TextWidget tw, char *startLine, char *text, int bufOffset, int wrapMargin, int *breakBefore) { textBuffer *wrapBuf, *buf = tw->text.textD->buffer; int startLineLen = strlen(startLine); int colNum, pos, lineStartPos, limitPos, breakAt, charsAdded; int firstBreak = -1, tabDist = buf->tabDist; char c, *wrappedText; /* Create a temporary text buffer and load it with the strings */ wrapBuf = BufCreate(); BufInsert(wrapBuf, 0, startLine); BufInsert(wrapBuf, wrapBuf->length, text); /* Scan the buffer for long lines and apply wrapLine when wrapMargin is exceeded. limitPos enforces no breaks in the "startLine" part of the string (if requested), and prevents re-scanning of long unbreakable lines for each character beyond the margin */ colNum = 0; pos = 0; lineStartPos = 0; limitPos = breakBefore == NULL ? startLineLen : 0; while (pos < wrapBuf->length) { c = BufGetCharacter(wrapBuf, pos); if (c == '\n') { lineStartPos = limitPos = pos + 1; colNum = 0; } else { colNum += BufCharWidth(c, colNum, tabDist, buf->nullSubsChar); if (colNum > wrapMargin) { if (!wrapLine(tw, wrapBuf, bufOffset, lineStartPos, pos, limitPos, &breakAt, &charsAdded)) { limitPos = max(pos, limitPos); } else { lineStartPos = limitPos = breakAt+1; pos += charsAdded; colNum = BufCountDispChars(wrapBuf, lineStartPos, pos+1); if (firstBreak == -1) firstBreak = breakAt; } } } pos++; } /* Return the wrapped text, possibly including part of startLine */ if (breakBefore == NULL) wrappedText = BufGetRange(wrapBuf, startLineLen, wrapBuf->length); else { *breakBefore = firstBreak != -1 && firstBreak < startLineLen ? startLineLen - firstBreak : 0; wrappedText = BufGetRange(wrapBuf, startLineLen - *breakBefore, wrapBuf->length); } BufFree(wrapBuf); return wrappedText; } /* ** Wraps the end of a line beginning at lineStartPos and ending at lineEndPos ** in "buf", at the last white-space on the line >= limitPos. (The implicit ** assumption is that just the last character of the line exceeds the wrap ** margin, and anywhere on the line we can wrap is correct). Returns False if ** unable to wrap the line. "breakAt", returns the character position at ** which the line was broken, ** ** Auto-wrapping can also trigger auto-indent. The additional parameter ** bufOffset is needed when auto-indent is set to smart indent and the smart ** indent routines need to scan far back in the buffer. "charsAdded" returns ** the number of characters added to acheive the auto-indent. wrapMargin is ** used to decide whether auto-indent should be skipped because the indent ** string itself would exceed the wrap margin. */ static int wrapLine(TextWidget tw, textBuffer *buf, int bufOffset, int lineStartPos, int lineEndPos, int limitPos, int *breakAt, int *charsAdded) { int p, length, column; char c, *indentStr; /* Scan backward for whitespace or BOL. If BOL, return False, no whitespace in line at which to wrap */ for (p=lineEndPos; ; p--) { if (p < lineStartPos || p < limitPos) return False; c = BufGetCharacter(buf, p); if (c == '\t' || c == ' ') break; } /* Create an auto-indent string to insert to do wrap. If the auto indent string reaches the wrap position, slice the auto-indent back off and return to the left margin */ if (tw->text.autoIndent || tw->text.smartIndent) { indentStr = createIndentString(tw, buf, bufOffset, lineStartPos, lineEndPos, &length, &column); if (column >= p-lineStartPos) indentStr[1] = '\0'; } else { indentStr = "\n"; length = 1; } /* Replace the whitespace character with the auto-indent string and return the stats */ BufReplace(buf, p, p+1, indentStr); if (tw->text.autoIndent || tw->text.smartIndent) XtFree(indentStr); *breakAt = p; *charsAdded = length-1; return True; } /* ** Create and return an auto-indent string to add a newline at lineEndPos to a ** line starting at lineStartPos in buf. "buf" may or may not be the real ** text buffer for the widget. If it is not the widget's text buffer it's ** offset position from the real buffer must be specified in "bufOffset" to ** allow the smart-indent routines to scan back as far as necessary. The ** string length is returned in "length" (or "length" can be passed as NULL, ** and the indent column is returned in "column" (if non NULL). */ static char *createIndentString(TextWidget tw, textBuffer *buf, int bufOffset, int lineStartPos, int lineEndPos, int *length, int *column) { textDisp *textD = tw->text.textD; int pos, indent = -1, tabDist = textD->buffer->tabDist; int i, useTabs = textD->buffer->useTabs; char *indentPtr, *indentStr, c; smartIndentCBStruct smartIndent; /* If smart indent is on, call the smart indent callback. It is not called when multi-line changes are being made (lineStartPos != 0), because smart indent needs to search back an indeterminate distance through the buffer, and reconciling that with wrapping changes made, but not yet committed in the buffer, would make programming smart indent more difficult for users and make everything more complicated */ if (tw->text.smartIndent && (lineStartPos == 0 || buf == textD->buffer)) { smartIndent.reason = NEWLINE_INDENT_NEEDED; smartIndent.pos = lineEndPos + bufOffset; smartIndent.indentRequest = 0; smartIndent.charsTyped = NULL; XtCallCallbacks((Widget)tw, textNsmartIndentCallback, (XtPointer)&smartIndent); indent = smartIndent.indentRequest; } /* If smart indent wasn't used, measure the indent distance of the line */ if (indent == -1) { indent = 0; for (pos=lineStartPos; postext.textD; int topLineNum, horizOffset, newPos, cursorX, y; int fontWidth = textD->fontStruct->max_bounds.width; int fontHeight = textD->fontStruct->ascent + textD->fontStruct->descent; /* For vertical autoscrolling just dragging the mouse outside of the top or bottom of the window is sufficient, for horizontal (non-rectangular) scrolling, see if the position where the CURSOR would go is outside */ newPos = TextDXYToPosition(textD, w->text.mouseX, w->text.mouseY); if (w->text.dragState == PRIMARY_RECT_DRAG) cursorX = w->text.mouseX; else if (!TextDPositionToXY(textD, newPos, &cursorX, &y)) cursorX = w->text.mouseX; /* Scroll away from the pointer, 1 character (horizontal), or 1 character for each fontHeight distance from the mouse to the text (vertical) */ TextDGetScroll(textD, &topLineNum, &horizOffset); if (cursorX >= (int)w->core.width - w->text.marginWidth) horizOffset += fontWidth; else if (w->text.mouseX < textD->left) horizOffset -= fontWidth; if (w->text.mouseY >= (int)w->core.height - w->text.marginHeight) topLineNum += 1 + ((w->text.mouseY - (int)w->core.height - w->text.marginHeight) / fontHeight) + 1; else if (w->text.mouseY < w->text.marginHeight) topLineNum -= 1 + ((w->text.marginHeight-w->text.mouseY) / fontHeight); TextDSetScroll(textD, topLineNum, horizOffset); /* Continue the drag operation in progress. If none is in progress (safety check) don't continue to re-establish the timer proc */ if (w->text.dragState == PRIMARY_DRAG) { adjustSelection(w, w->text.mouseX, w->text.mouseY); } else if (w->text.dragState == PRIMARY_RECT_DRAG) { adjustSelection(w, w->text.mouseX, w->text.mouseY); } else if (w->text.dragState == SECONDARY_DRAG) { adjustSecondarySelection(w, w->text.mouseX, w->text.mouseY); } else if (w->text.dragState == SECONDARY_RECT_DRAG) { adjustSecondarySelection(w, w->text.mouseX, w->text.mouseY); } else if (w->text.dragState == PRIMARY_BLOCK_DRAG) { BlockDragSelection(w, w->text.mouseX, w->text.mouseY, USE_LAST); } else { w->text.autoScrollProcID = 0; return; } /* re-establish the timer proc (this routine) to continue processing */ w->text.autoScrollProcID = XtAppAddTimeOut( XtWidgetToApplicationContext((Widget)w), w->text.mouseY >= w->text.marginHeight && w->text.mouseY < w->core.height - w->text.marginHeight ? (VERTICAL_SCROLL_DELAY*fontWidth) / fontHeight : VERTICAL_SCROLL_DELAY, autoScrollTimerProc, w); } /* ** Xt timer procedure for cursor blinking */ static void cursorBlinkTimerProc(XtPointer clientData, XtIntervalId *id) { TextWidget w = (TextWidget)clientData; textDisp *textD = w->text.textD; /* Blink the cursor */ if (textD->cursorOn) TextDBlankCursor(textD); else TextDUnblankCursor(textD); /* re-establish the timer proc (this routine) to continue processing */ w->text.cursorBlinkProcID = XtAppAddTimeOut( XtWidgetToApplicationContext((Widget)w), w->text.cursorBlinkRate, cursorBlinkTimerProc, w); } /* ** Sets the caret to on or off and restart the caret blink timer. ** This could be used by other modules to modify the caret's blinking. */ void ResetCursorBlink(TextWidget textWidget, Boolean startsBlanked) { if (0 != textWidget->text.cursorBlinkRate) { if (0 != textWidget->text.cursorBlinkProcID) { XtRemoveTimeOut(textWidget->text.cursorBlinkProcID); } if (startsBlanked) { TextDBlankCursor(textWidget->text.textD); } else { TextDUnblankCursor(textWidget->text.textD); } textWidget->text.cursorBlinkProcID = XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) textWidget), textWidget->text.cursorBlinkRate, cursorBlinkTimerProc, textWidget); } } /* ** look at an action procedure's arguments to see if argument "key" has been ** specified in the argument list */ static int hasKey(const char *key, const String *args, const Cardinal *nArgs) { int i; for (i=0; i<(int)*nArgs; i++) if (!strCaseCmp(args[i], key)) return True; return False; } static int max(int i1, int i2) { return i1 >= i2 ? i1 : i2; } static int min(int i1, int i2) { return i1 <= i2 ? i1 : i2; } /* ** strCaseCmp compares its arguments and returns 0 if the two strings ** are equal IGNORING case differences. Otherwise returns 1. */ static int strCaseCmp(const char *str1, const char *str2) { unsigned const char *c1 = (unsigned const char*) str1; unsigned const char *c2 = (unsigned const char*) str2; for (; *c1!='\0' && *c2!='\0'; c1++, c2++) if (toupper(*c1) != toupper(*c2)) return 1; if (*c1 == *c2) { return(0); } else { return(1); } } static void ringIfNecessary(Boolean silent, Widget w) { if (!silent) XBell(XtDisplay(w), 0); } nedit-5.6.orig/source/text.h0000644000175000017500000001705410737527370014571 0ustar paulpaul/* $Id: text.h,v 1.24 2008/01/04 22:11:04 yooden Exp $ */ /******************************************************************************* * * * text.h -- Nirvana Editor Text Widget Header File * * * * Copyright 2003 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_TEXT_H_INCLUDED #define NEDIT_TEXT_H_INCLUDED #include "textBuf.h" #include #include #include /* Resource strings */ #define textNfont "font" #define textCFont "Font" #define textNrows "rows" #define textCRows "Rows" #define textNcolumns "columns" #define textCColumns "Columns" #define textNmarginWidth "marginWidth" #define textCMarginWidth "MarginWidth" #define textNmarginHeight "marginHeight" #define textCMarginHeight "MarginHeight" #define textNselectForeground "selectForeground" #define textCSelectForeground "SelectForeground" #define textNselectBackground "selectBackground" #define textCSelectBackground "SelectBackground" #define textNhighlightForeground "highlightForeground" #define textCHighlightForeground "HighlightForeground" #define textNhighlightBackground "highlightBackground" #define textCHighlightBackground "HighlightBackground" #define textNcursorForeground "cursorForeground" #define textCCursorForeground "CursorForeground" #define textNlineNumForeground "lineNumForeground" #define textCLineNumForeground "LineNumForeground" #define textNcalltipForeground "calltipForeground" #define textCcalltipForeground "CalltipForeground" #define textNcalltipBackground "calltipBackground" #define textCcalltipBackground "CalltipBackground" #define textNpendingDelete "pendingDelete" #define textCPendingDelete "PendingDelete" #define textNhScrollBar "hScrollBar" #define textCHScrollBar "HScrollBar" #define textNvScrollBar "vScrollBar" #define textCVScrollBar "VScrollBar" #define textNlineNumCols "lineNumCols" #define textCLineNumCols "LineNumCols" #define textNautoShowInsertPos "autoShowInsertPos" #define textCAutoShowInsertPos "AutoShowInsertPos" #define textNautoWrapPastedText "autoWrapPastedText" #define textCAutoWrapPastedText "AutoWrapPastedText" #define textNwordDelimiters "wordDelimiters" #define textCWordDelimiters "WordDelimiters" #define textNblinkRate "blinkRate" #define textCBlinkRate "BlinkRate" #define textNfocusCallback "focusCallback" #define textCFocusCallback "FocusCallback" #define textNlosingFocusCallback "losingFocusCallback" #define textCLosingFocusCallback "LosingFocusCallback" #define textNcursorMovementCallback "cursorMovementCallback" #define textCCursorMovementCallback "CursorMovementCallback" #define textNdragStartCallback "dragStartCallback" #define textCDragStartCallback "DragStartCallback" #define textNdragEndCallback "dragEndCallback" #define textCDragEndCallback "DragEndCallback" #define textNsmartIndentCallback "smartIndentCallback" #define textCSmartIndentCallback "SmartIndentCallback" #define textNautoWrap "autoWrap" #define textCAutoWrap "AutoWrap" #define textNcontinuousWrap "continuousWrap" #define textCContinuousWrap "ContinuousWrap" #define textNwrapMargin "wrapMargin" #define textCWrapMargin "WrapMargin" #define textNautoIndent "autoIndent" #define textCAutoIndent "AutoIndent" #define textNsmartIndent "smartIndent" #define textCSmartIndent "SmartIndent" #define textNoverstrike "overstrike" #define textCOverstrike "Overstrike" #define textNheavyCursor "heavyCursor" #define textCHeavyCursor "HeavyCursor" #define textNreadOnly "readOnly" #define textCReadOnly "ReadOnly" #define textNhidePointer "hidePointer" #define textCHidePointer "HidePointer" #define textNemulateTabs "emulateTabs" #define textCEmulateTabs "EmulateTabs" #define textNcursorVPadding "cursorVPadding" #define textCCursorVPadding "CursorVPadding" #define textNbacklightCharTypes "backlightCharTypes" #define textCBacklightCharTypes "BacklightCharTypes" extern WidgetClass textWidgetClass; struct _TextClassRec; struct _TextRec; typedef struct _TextRec *TextWidget; typedef struct { int startPos; int nCharsDeleted; int nCharsInserted; char *deletedText; } dragEndCBStruct; enum smartIndentCallbackReasons {NEWLINE_INDENT_NEEDED, CHAR_TYPED}; typedef struct { int reason; int pos; int indentRequest; char *charsTyped; } smartIndentCBStruct; /* User callable routines */ void TextSetBuffer(Widget w, textBuffer *buffer); textBuffer *TextGetBuffer(Widget w); int TextLineAndColToPos(Widget w, int lineNum, int column); int TextPosToLineAndCol(Widget w, int pos, int *lineNum, int *column); int TextPosToXY(Widget w, int pos, int *x, int *y); int TextGetCursorPos(Widget w); void TextSetCursorPos(Widget w, int pos); void TextGetScroll(Widget w, int *topLineNum, int *horizOffset); void TextSetScroll(Widget w, int topLineNum, int horizOffset); int TextGetMinFontWidth(Widget w, Boolean considerStyles); int TextGetMaxFontWidth(Widget w, Boolean considerStyles); void TextHandleXSelections(Widget w); void TextPasteClipboard(Widget w, Time time); void TextColPasteClipboard(Widget w, Time time); void TextCopyClipboard(Widget w, Time time); void TextCutClipboard(Widget w, Time time); int TextFirstVisibleLine(Widget w); int TextNumVisibleLines(Widget w); int TextVisibleWidth(Widget w); void TextInsertAtCursor(Widget w, char *chars, XEvent *event, int allowPendingDelete, int allowWrap); int TextFirstVisiblePos(Widget w); int TextLastVisiblePos(Widget w); char *TextGetWrapped(Widget w, int startPos, int endPos, int *length); XtActionsRec *TextGetActions(int *nActions); void ShowHidePointer(TextWidget w, Boolean hidePointer); void ResetCursorBlink(TextWidget textWidget, Boolean startsBlanked); #ifdef VMS /* VMS linker doesn't like long names (>31 chars) */ #define HandleAllPendingGraphicsExposeNoExposeEvents HandlePendingExpNoExpEvents #endif /* VMS */ void HandleAllPendingGraphicsExposeNoExposeEvents(TextWidget w, XEvent *event); #endif /* NEDIT_TEXT_H_INCLUDED */ nedit-5.6.orig/source/textBuf.c0000644000175000017500000025067410737527370015230 0ustar paulpaulstatic const char CVSID[] = "$Id: textBuf.c,v 1.37 2008/01/04 22:11:04 yooden Exp $"; /******************************************************************************* * * * textBuf.c - Manage source text for one or more text areas * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * June 15, 1995 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "textBuf.h" #include "rangeset.h" #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #define PREFERRED_GAP_SIZE 80 /* Initial size for the buffer gap (empty space in the buffer where text might be inserted if the user is typing sequential chars) */ static void histogramCharacters(const char *string, int length, char hist[256], int init); static void subsChars(char *string, int length, char fromChar, char toChar); static char chooseNullSubsChar(char hist[256]); static int insert(textBuffer *buf, int pos, const char *text); static void delete(textBuffer *buf, int start, int end); static void deleteRect(textBuffer *buf, int start, int end, int rectStart, int rectEnd, int *replaceLen, int *endPos); static void insertCol(textBuffer *buf, int column, int startPos, const char *insText, int *nDeleted, int *nInserted, int *endPos); static void overlayRect(textBuffer *buf, int startPos, int rectStart, int rectEnd, const char *insText, int *nDeleted, int *nInserted, int *endPos); static void insertColInLine(const char *line, const char *insLine, int column, int insWidth, int tabDist, int useTabs, char nullSubsChar, char *outStr, int *outLen, int *endOffset); static void deleteRectFromLine(const char *line, int rectStart, int rectEnd, int tabDist, int useTabs, char nullSubsChar, char *outStr, int *outLen, int *endOffset); static void overlayRectInLine(const char *line, const char *insLine, int rectStart, int rectEnd, int tabDist, int useTabs, char nullSubsChar, char *outStr, int *outLen, int *endOffset); static void callPreDeleteCBs(textBuffer *buf, int pos, int nDeleted); static void callModifyCBs(textBuffer *buf, int pos, int nDeleted, int nInserted, int nRestyled, const char *deletedText); static void redisplaySelection(textBuffer *buf, selection *oldSelection, selection *newSelection); static void moveGap(textBuffer *buf, int pos); static void reallocateBuf(textBuffer *buf, int newGapStart, int newGapLen); static void setSelection(selection *sel, int start, int end); static void setRectSelect(selection *sel, int start, int end, int rectStart, int rectEnd); static void updateSelections(textBuffer *buf, int pos, int nDeleted, int nInserted); static void updateSelection(selection *sel, int pos, int nDeleted, int nInserted); static int getSelectionPos(selection *sel, int *start, int *end, int *isRect, int *rectStart, int *rectEnd); static char *getSelectionText(textBuffer *buf, selection *sel); static void removeSelected(textBuffer *buf, selection *sel); static void replaceSelected(textBuffer *buf, selection *sel, const char *text); static void addPadding(char *string, int startIndent, int toIndent, int tabDist, int useTabs, char nullSubsChar, int *charsAdded); static int searchForward(textBuffer *buf, int startPos, char searchChar, int *foundPos); static int searchBackward(textBuffer *buf, int startPos, char searchChar, int *foundPos); static char *copyLine(const char *text, int *lineLen); static int countLines(const char *string); static int textWidth(const char *text, int tabDist, char nullSubsChar); static void findRectSelBoundariesForCopy(textBuffer *buf, int lineStartPos, int rectStart, int rectEnd, int *selStart, int *selEnd); static char *realignTabs(const char *text, int origIndent, int newIndent, int tabDist, int useTabs, char nullSubsChar, int *newLength); static char *expandTabs(const char *text, int startIndent, int tabDist, char nullSubsChar, int *newLen); static char *unexpandTabs(const char *text, int startIndent, int tabDist, char nullSubsChar, int *newLen); static int max(int i1, int i2); static int min(int i1, int i2); #ifdef __MVS__ static const char *ControlCodeTable[64] = { "nul", "soh", "stx", "etx", "sel", "ht", "rnl", "del", "ge", "sps", "rpt", "vt", "ff", "cr", "so", "si", "dle", "dc1", "dc2", "dc3", "res", "nl", "bs", "poc", "can", "em", "ubs", "cu1", "ifs", "igs", "irs", "ius", "ds", "sos", "fs", "wus", "byp", "lf", "etb", "esc", "sa", "sfe", "sm", "csp", "mfa", "enq", "ack", "bel", "x30", "x31", "syn", "ir", "pp", "trn", "nbs", "eot", "sbs", "it", "rff", "cu3", "dc4", "nak", "x3e", "sub"}; #else static const char *ControlCodeTable[32] = { "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", "bs", "ht", "nl", "vt", "np", "cr", "so", "si", "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", "can", "em", "sub", "esc", "fs", "gs", "rs", "us"}; #endif /* ** Create an empty text buffer */ textBuffer *BufCreate(void) { textBuffer *buf = BufCreatePreallocated(0); return buf; } /* ** Create an empty text buffer of a pre-determined size (use this to ** avoid unnecessary re-allocation if you know exactly how much the buffer ** will need to hold */ textBuffer *BufCreatePreallocated(int requestedSize) { textBuffer *buf; buf = (textBuffer *)XtMalloc(sizeof(textBuffer)); buf->length = 0; buf->buf = XtMalloc(requestedSize + PREFERRED_GAP_SIZE + 1); buf->buf[requestedSize + PREFERRED_GAP_SIZE] = '\0'; buf->gapStart = 0; buf->gapEnd = PREFERRED_GAP_SIZE; buf->tabDist = 8; buf->useTabs = True; buf->primary.selected = False; buf->primary.zeroWidth = False; buf->primary.rectangular = False; buf->primary.start = buf->primary.end = 0; buf->secondary.selected = False; buf->secondary.zeroWidth = False; buf->secondary.start = buf->secondary.end = 0; buf->secondary.rectangular = False; buf->highlight.selected = False; buf->highlight.zeroWidth = False; buf->highlight.start = buf->highlight.end = 0; buf->highlight.rectangular = False; buf->modifyProcs = NULL; buf->cbArgs = NULL; buf->nModifyProcs = 0; buf->preDeleteProcs = NULL; buf->preDeleteCbArgs = NULL; buf->nPreDeleteProcs = 0; buf->nullSubsChar = '\0'; #ifdef PURIFY {int i; for (i=buf->gapStart; igapEnd; i++) buf->buf[i] = '.';} #endif buf->rangesetTable = NULL; return buf; } /* ** Free a text buffer */ void BufFree(textBuffer *buf) { XtFree(buf->buf); if (buf->nModifyProcs != 0) { XtFree((char *)buf->modifyProcs); XtFree((char *)buf->cbArgs); } if (buf->rangesetTable) RangesetTableFree(buf->rangesetTable); if (buf->nPreDeleteProcs != 0) { XtFree((char *)buf->preDeleteProcs); XtFree((char *)buf->preDeleteCbArgs); } XtFree((char *)buf); } /* ** Get the entire contents of a text buffer. Memory is allocated to contain ** the returned string, which the caller must free. */ char *BufGetAll(textBuffer *buf) { char *text; text = XtMalloc(buf->length+1); memcpy(text, buf->buf, buf->gapStart); memcpy(&text[buf->gapStart], &buf->buf[buf->gapEnd], buf->length - buf->gapStart); text[buf->length] = '\0'; return text; } /* ** Get the entire contents of a text buffer as a single string. The gap is ** moved so that the buffer data can be accessed as a single contiguous ** character array. ** NB DO NOT ALTER THE TEXT THROUGH THE RETURNED POINTER! ** (we make an exception in BufSubstituteNullChars() however) ** This function is intended ONLY to provide a searchable string without copying ** into a temporary buffer. */ const char *BufAsString(textBuffer *buf) { char *text; int bufLen = buf->length; int leftLen = buf->gapStart; int rightLen = bufLen - leftLen; /* find where best to put the gap to minimise memory movement */ if (leftLen != 0 && rightLen != 0) { leftLen = (leftLen < rightLen) ? 0 : bufLen; moveGap(buf, leftLen); } /* get the start position of the actual data */ text = &buf->buf[(leftLen == 0) ? buf->gapEnd : 0]; /* make sure it's null-terminated */ text[bufLen] = 0; return text; } /* ** Replace the entire contents of the text buffer */ void BufSetAll(textBuffer *buf, const char *text) { int length, deletedLength; char *deletedText; length = strlen(text); callPreDeleteCBs(buf, 0, buf->length); /* Save information for redisplay, and get rid of the old buffer */ deletedText = BufGetAll(buf); deletedLength = buf->length; XtFree(buf->buf); /* Start a new buffer with a gap of PREFERRED_GAP_SIZE in the center */ buf->buf = XtMalloc(length + PREFERRED_GAP_SIZE + 1); buf->buf[length + PREFERRED_GAP_SIZE] = '\0'; buf->length = length; buf->gapStart = length/2; buf->gapEnd = buf->gapStart + PREFERRED_GAP_SIZE; memcpy(buf->buf, text, buf->gapStart); memcpy(&buf->buf[buf->gapEnd], &text[buf->gapStart], length-buf->gapStart); #ifdef PURIFY {int i; for (i=buf->gapStart; igapEnd; i++) buf->buf[i] = '.';} #endif /* Zero all of the existing selections */ updateSelections(buf, 0, deletedLength, 0); /* Call the saved display routine(s) to update the screen */ callModifyCBs(buf, 0, deletedLength, length, 0, deletedText); XtFree(deletedText); } /* ** Return a copy of the text between "start" and "end" character positions ** from text buffer "buf". Positions start at 0, and the range does not ** include the character pointed to by "end" */ char* BufGetRange(const textBuffer* buf, int start, int end) { char *text; int length, part1Length; /* Make sure start and end are ok, and allocate memory for returned string. If start is bad, return "", if end is bad, adjust it. */ if (start < 0 || start > buf->length) { text = XtMalloc(1); text[0] = '\0'; return text; } if (end < start) { int temp = start; start = end; end = temp; } if (end > buf->length) end = buf->length; length = end - start; text = XtMalloc(length+1); /* Copy the text from the buffer to the returned string */ if (end <= buf->gapStart) { memcpy(text, &buf->buf[start], length); } else if (start >= buf->gapStart) { memcpy(text, &buf->buf[start+(buf->gapEnd-buf->gapStart)], length); } else { part1Length = buf->gapStart - start; memcpy(text, &buf->buf[start], part1Length); memcpy(&text[part1Length], &buf->buf[buf->gapEnd], length-part1Length); } text[length] = '\0'; return text; } /* ** Return the character at buffer position "pos". Positions start at 0. */ char BufGetCharacter(const textBuffer* buf, const int pos) { if (pos < 0 || pos >= buf->length) return '\0'; if (pos < buf->gapStart) return buf->buf[pos]; else return buf->buf[pos + buf->gapEnd-buf->gapStart]; } /* ** Insert null-terminated string "text" at position "pos" in "buf" */ void BufInsert(textBuffer *buf, int pos, const char *text) { int nInserted; /* if pos is not contiguous to existing text, make it */ if (pos > buf->length) pos = buf->length; if (pos < 0 ) pos = 0; /* Even if nothing is deleted, we must call these callbacks */ callPreDeleteCBs(buf, pos, 0); /* insert and redisplay */ nInserted = insert(buf, pos, text); buf->cursorPosHint = pos + nInserted; callModifyCBs(buf, pos, 0, nInserted, 0, NULL); } /* ** Delete the characters between "start" and "end", and insert the ** null-terminated string "text" in their place in in "buf" */ void BufReplace(textBuffer *buf, int start, int end, const char *text) { char *deletedText; int nInserted = strlen(text); callPreDeleteCBs(buf, start, end-start); deletedText = BufGetRange(buf, start, end); delete(buf, start, end); insert(buf, start, text); buf->cursorPosHint = start + nInserted; callModifyCBs(buf, start, end-start, nInserted, 0, deletedText); XtFree(deletedText); } void BufRemove(textBuffer *buf, int start, int end) { char *deletedText; /* Make sure the arguments make sense */ if (start > end) { int temp = start; start = end; end = temp; } if (start > buf->length) start = buf->length; if (start < 0) start = 0; if (end > buf->length) end = buf->length; if (end < 0) end = 0; callPreDeleteCBs(buf, start, end-start); /* Remove and redisplay */ deletedText = BufGetRange(buf, start, end); delete(buf, start, end); buf->cursorPosHint = start; callModifyCBs(buf, start, end-start, 0, 0, deletedText); XtFree(deletedText); } void BufCopyFromBuf(textBuffer *fromBuf, textBuffer *toBuf, int fromStart, int fromEnd, int toPos) { int length = fromEnd - fromStart; int part1Length; /* Prepare the buffer to receive the new text. If the new text fits in the current buffer, just move the gap (if necessary) to where the text should be inserted. If the new text is too large, reallocate the buffer with a gap large enough to accomodate the new text and a gap of PREFERRED_GAP_SIZE */ if (length > toBuf->gapEnd - toBuf->gapStart) reallocateBuf(toBuf, toPos, length + PREFERRED_GAP_SIZE); else if (toPos != toBuf->gapStart) moveGap(toBuf, toPos); /* Insert the new text (toPos now corresponds to the start of the gap) */ if (fromEnd <= fromBuf->gapStart) { memcpy(&toBuf->buf[toPos], &fromBuf->buf[fromStart], length); } else if (fromStart >= fromBuf->gapStart) { memcpy(&toBuf->buf[toPos], &fromBuf->buf[fromStart+(fromBuf->gapEnd-fromBuf->gapStart)], length); } else { part1Length = fromBuf->gapStart - fromStart; memcpy(&toBuf->buf[toPos], &fromBuf->buf[fromStart], part1Length); memcpy(&toBuf->buf[toPos+part1Length], &fromBuf->buf[fromBuf->gapEnd], length-part1Length); } toBuf->gapStart += length; toBuf->length += length; updateSelections(toBuf, toPos, 0, length); } /* ** Insert "text" columnwise into buffer starting at displayed character ** position "column" on the line beginning at "startPos". Opens a rectangular ** space the width and height of "text", by moving all text to the right of ** "column" right. If charsInserted and charsDeleted are not NULL, the ** number of characters inserted and deleted in the operation (beginning ** at startPos) are returned in these arguments */ void BufInsertCol(textBuffer *buf, int column, int startPos, const char *text, int *charsInserted, int *charsDeleted) { int nLines, lineStartPos, nDeleted, insertDeleted, nInserted; char *deletedText; nLines = countLines(text); lineStartPos = BufStartOfLine(buf, startPos); nDeleted = BufEndOfLine(buf, BufCountForwardNLines(buf, startPos, nLines)) - lineStartPos; callPreDeleteCBs(buf, lineStartPos, nDeleted); deletedText = BufGetRange(buf, lineStartPos, lineStartPos + nDeleted); insertCol(buf, column, lineStartPos, text, &insertDeleted, &nInserted, &buf->cursorPosHint); if (nDeleted != insertDeleted) fprintf(stderr, "NEdit internal consistency check ins1 failed"); callModifyCBs(buf, lineStartPos, nDeleted, nInserted, 0, deletedText); XtFree(deletedText); if (charsInserted != NULL) *charsInserted = nInserted; if (charsDeleted != NULL) *charsDeleted = nDeleted; } /* ** Overlay "text" between displayed character positions "rectStart" and ** "rectEnd" on the line beginning at "startPos". If charsInserted and ** charsDeleted are not NULL, the number of characters inserted and deleted ** in the operation (beginning at startPos) are returned in these arguments. ** If rectEnd equals -1, the width of the inserted text is measured first. */ void BufOverlayRect(textBuffer *buf, int startPos, int rectStart, int rectEnd, const char *text, int *charsInserted, int *charsDeleted) { int nLines, lineStartPos, nDeleted, insertDeleted, nInserted; char *deletedText; nLines = countLines(text); lineStartPos = BufStartOfLine(buf, startPos); if(rectEnd == -1) rectEnd = rectStart + textWidth(text, buf->tabDist, buf->nullSubsChar); lineStartPos = BufStartOfLine(buf, startPos); nDeleted = BufEndOfLine(buf, BufCountForwardNLines(buf, startPos, nLines)) - lineStartPos; callPreDeleteCBs(buf, lineStartPos, nDeleted); deletedText = BufGetRange(buf, lineStartPos, lineStartPos + nDeleted); overlayRect(buf, lineStartPos, rectStart, rectEnd, text, &insertDeleted, &nInserted, &buf->cursorPosHint); if (nDeleted != insertDeleted) fprintf(stderr, "NEdit internal consistency check ovly1 failed"); callModifyCBs(buf, lineStartPos, nDeleted, nInserted, 0, deletedText); XtFree(deletedText); if (charsInserted != NULL) *charsInserted = nInserted; if (charsDeleted != NULL) *charsDeleted = nDeleted; } /* ** Replace a rectangular area in buf, given by "start", "end", "rectStart", ** and "rectEnd", with "text". If "text" is vertically longer than the ** rectangle, add extra lines to make room for it. */ void BufReplaceRect(textBuffer *buf, int start, int end, int rectStart, int rectEnd, const char *text) { char *deletedText; char *insText=NULL; int i, nInsertedLines, nDeletedLines, insLen, hint; int insertDeleted, insertInserted, deleteInserted; int linesPadded = 0; /* Make sure start and end refer to complete lines, since the columnar delete and insert operations will replace whole lines */ start = BufStartOfLine(buf, start); end = BufEndOfLine(buf, end); callPreDeleteCBs(buf, start, end-start); /* If more lines will be deleted than inserted, pad the inserted text with newlines to make it as long as the number of deleted lines. This will indent all of the text to the right of the rectangle to the same column. If more lines will be inserted than deleted, insert extra lines in the buffer at the end of the rectangle to make room for the additional lines in "text" */ nInsertedLines = countLines(text); nDeletedLines = BufCountLines(buf, start, end); if (nInsertedLines < nDeletedLines) { char *insPtr; insLen = strlen(text); insText = XtMalloc(insLen + nDeletedLines - nInsertedLines + 1); strcpy(insText, text); insPtr = insText + insLen; for (i=0; icursorPosHint); XtFree(insText); } else insertCol(buf, rectStart, start, text, &insertDeleted, &insertInserted, &buf->cursorPosHint); /* Figure out how many chars were inserted and call modify callbacks */ if (insertDeleted != deleteInserted + linesPadded) fprintf(stderr, "NEdit: internal consistency check repl1 failed\n"); callModifyCBs(buf, start, end-start, insertInserted, 0, deletedText); XtFree(deletedText); } /* ** Remove a rectangular swath of characters between character positions start ** and end and horizontal displayed-character offsets rectStart and rectEnd. */ void BufRemoveRect(textBuffer *buf, int start, int end, int rectStart, int rectEnd) { char *deletedText; int nInserted; start = BufStartOfLine(buf, start); end = BufEndOfLine(buf, end); callPreDeleteCBs(buf, start, end-start); deletedText = BufGetRange(buf, start, end); deleteRect(buf, start, end, rectStart, rectEnd, &nInserted, &buf->cursorPosHint); callModifyCBs(buf, start, end-start, nInserted, 0, deletedText); XtFree(deletedText); } /* ** Clear a rectangular "hole" out of the buffer between character positions ** start and end and horizontal displayed-character offsets rectStart and ** rectEnd. */ void BufClearRect(textBuffer *buf, int start, int end, int rectStart, int rectEnd) { int i, nLines; char *newlineString; nLines = BufCountLines(buf, start, end); newlineString = XtMalloc(nLines+1); for (i=0; itabDist, buf->useTabs, buf->nullSubsChar, &len); XtFree(textOut); return retabbedStr; } /* ** Get the hardware tab distance used by all displays for this buffer, ** and used in computing offsets for rectangular selection operations. */ int BufGetTabDistance(textBuffer *buf) { return buf->tabDist; } /* ** Set the hardware tab distance used by all displays for this buffer, ** and used in computing offsets for rectangular selection operations. */ void BufSetTabDistance(textBuffer *buf, int tabDist) { const char *deletedText; /* First call the pre-delete callbacks with the previous tab setting still active. */ callPreDeleteCBs(buf, 0, buf->length); /* Change the tab setting */ buf->tabDist = tabDist; /* Force any display routines to redisplay everything */ deletedText = BufAsString(buf); callModifyCBs(buf, 0, buf->length, buf->length, 0, deletedText); } void BufCheckDisplay(textBuffer *buf, int start, int end) { /* just to make sure colors in the selected region are up to date */ callModifyCBs(buf, start, 0, 0, end-start, NULL); } void BufSelect(textBuffer *buf, int start, int end) { selection oldSelection = buf->primary; setSelection(&buf->primary, start, end); redisplaySelection(buf, &oldSelection, &buf->primary); } void BufUnselect(textBuffer *buf) { selection oldSelection = buf->primary; buf->primary.selected = False; buf->primary.zeroWidth = False; redisplaySelection(buf, &oldSelection, &buf->primary); } void BufRectSelect(textBuffer *buf, int start, int end, int rectStart, int rectEnd) { selection oldSelection = buf->primary; setRectSelect(&buf->primary, start, end, rectStart, rectEnd); redisplaySelection(buf, &oldSelection, &buf->primary); } int BufGetSelectionPos(textBuffer *buf, int *start, int *end, int *isRect, int *rectStart, int *rectEnd) { return getSelectionPos(&buf->primary, start, end, isRect, rectStart, rectEnd); } /* Same as above, but also returns TRUE for empty selections */ int BufGetEmptySelectionPos(textBuffer *buf, int *start, int *end, int *isRect, int *rectStart, int *rectEnd) { return getSelectionPos(&buf->primary, start, end, isRect, rectStart, rectEnd) || buf->primary.zeroWidth; } char *BufGetSelectionText(textBuffer *buf) { return getSelectionText(buf, &buf->primary); } void BufRemoveSelected(textBuffer *buf) { removeSelected(buf, &buf->primary); } void BufReplaceSelected(textBuffer *buf, const char *text) { replaceSelected(buf, &buf->primary, text); } void BufSecondarySelect(textBuffer *buf, int start, int end) { selection oldSelection = buf->secondary; setSelection(&buf->secondary, start, end); redisplaySelection(buf, &oldSelection, &buf->secondary); } void BufSecondaryUnselect(textBuffer *buf) { selection oldSelection = buf->secondary; buf->secondary.selected = False; buf->secondary.zeroWidth = False; redisplaySelection(buf, &oldSelection, &buf->secondary); } void BufSecRectSelect(textBuffer *buf, int start, int end, int rectStart, int rectEnd) { selection oldSelection = buf->secondary; setRectSelect(&buf->secondary, start, end, rectStart, rectEnd); redisplaySelection(buf, &oldSelection, &buf->secondary); } int BufGetSecSelectPos(textBuffer *buf, int *start, int *end, int *isRect, int *rectStart, int *rectEnd) { return getSelectionPos(&buf->secondary, start, end, isRect, rectStart, rectEnd); } char *BufGetSecSelectText(textBuffer *buf) { return getSelectionText(buf, &buf->secondary); } void BufRemoveSecSelect(textBuffer *buf) { removeSelected(buf, &buf->secondary); } void BufReplaceSecSelect(textBuffer *buf, const char *text) { replaceSelected(buf, &buf->secondary, text); } void BufHighlight(textBuffer *buf, int start, int end) { selection oldSelection = buf->highlight; setSelection(&buf->highlight, start, end); redisplaySelection(buf, &oldSelection, &buf->highlight); } void BufUnhighlight(textBuffer *buf) { selection oldSelection = buf->highlight; buf->highlight.selected = False; buf->highlight.zeroWidth = False; redisplaySelection(buf, &oldSelection, &buf->highlight); } void BufRectHighlight(textBuffer *buf, int start, int end, int rectStart, int rectEnd) { selection oldSelection = buf->highlight; setRectSelect(&buf->highlight, start, end, rectStart, rectEnd); redisplaySelection(buf, &oldSelection, &buf->highlight); } int BufGetHighlightPos(textBuffer *buf, int *start, int *end, int *isRect, int *rectStart, int *rectEnd) { return getSelectionPos(&buf->highlight, start, end, isRect, rectStart, rectEnd); } /* ** Add a callback routine to be called when the buffer is modified */ void BufAddModifyCB(textBuffer *buf, bufModifyCallbackProc bufModifiedCB, void *cbArg) { bufModifyCallbackProc *newModifyProcs; void **newCBArgs; int i; newModifyProcs = (bufModifyCallbackProc *) XtMalloc(sizeof(bufModifyCallbackProc *) * (buf->nModifyProcs+1)); newCBArgs = (void *)XtMalloc(sizeof(void *) * (buf->nModifyProcs+1)); for (i=0; inModifyProcs; i++) { newModifyProcs[i] = buf->modifyProcs[i]; newCBArgs[i] = buf->cbArgs[i]; } if (buf->nModifyProcs != 0) { XtFree((char *)buf->modifyProcs); XtFree((char *)buf->cbArgs); } newModifyProcs[buf->nModifyProcs] = bufModifiedCB; newCBArgs[buf->nModifyProcs] = cbArg; buf->nModifyProcs++; buf->modifyProcs = newModifyProcs; buf->cbArgs = newCBArgs; } /* ** Similar to the above, but makes sure that the callback is called before ** normal priority callbacks. */ void BufAddHighPriorityModifyCB(textBuffer *buf, bufModifyCallbackProc bufModifiedCB, void *cbArg) { bufModifyCallbackProc *newModifyProcs; void **newCBArgs; int i; newModifyProcs = (bufModifyCallbackProc *) XtMalloc(sizeof(bufModifyCallbackProc *) * (buf->nModifyProcs+1)); newCBArgs = (void *)XtMalloc(sizeof(void *) * (buf->nModifyProcs+1)); for (i=0; inModifyProcs; i++) { newModifyProcs[i+1] = buf->modifyProcs[i]; newCBArgs[i+1] = buf->cbArgs[i]; } if (buf->nModifyProcs != 0) { XtFree((char *)buf->modifyProcs); XtFree((char *)buf->cbArgs); } newModifyProcs[0] = bufModifiedCB; newCBArgs[0] = cbArg; buf->nModifyProcs++; buf->modifyProcs = newModifyProcs; buf->cbArgs = newCBArgs; } void BufRemoveModifyCB(textBuffer *buf, bufModifyCallbackProc bufModifiedCB, void *cbArg) { int i, toRemove = -1; bufModifyCallbackProc *newModifyProcs; void **newCBArgs; /* find the matching callback to remove */ for (i=0; inModifyProcs; i++) { if (buf->modifyProcs[i] == bufModifiedCB && buf->cbArgs[i] == cbArg) { toRemove = i; break; } } if (toRemove == -1) { fprintf(stderr, "NEdit Internal Error: Can't find modify CB to remove\n"); return; } /* Allocate new lists for remaining callback procs and args (if any are left) */ buf->nModifyProcs--; if (buf->nModifyProcs == 0) { buf->nModifyProcs = 0; XtFree((char *)buf->modifyProcs); buf->modifyProcs = NULL; XtFree((char *)buf->cbArgs); buf->cbArgs = NULL; return; } newModifyProcs = (bufModifyCallbackProc *) XtMalloc(sizeof(bufModifyCallbackProc *) * (buf->nModifyProcs)); newCBArgs = (void *)XtMalloc(sizeof(void *) * (buf->nModifyProcs)); /* copy out the remaining members and free the old lists */ for (i=0; imodifyProcs[i]; newCBArgs[i] = buf->cbArgs[i]; } for (; inModifyProcs; i++) { newModifyProcs[i] = buf->modifyProcs[i+1]; newCBArgs[i] = buf->cbArgs[i+1]; } XtFree((char *)buf->modifyProcs); XtFree((char *)buf->cbArgs); buf->modifyProcs = newModifyProcs; buf->cbArgs = newCBArgs; } /* ** Add a callback routine to be called before text is deleted from the buffer. */ void BufAddPreDeleteCB(textBuffer *buf, bufPreDeleteCallbackProc bufPreDeleteCB, void *cbArg) { bufPreDeleteCallbackProc *newPreDeleteProcs; void **newCBArgs; int i; newPreDeleteProcs = (bufPreDeleteCallbackProc *) XtMalloc(sizeof(bufPreDeleteCallbackProc *) * (buf->nPreDeleteProcs+1)); newCBArgs = (void *)XtMalloc(sizeof(void *) * (buf->nPreDeleteProcs+1)); for (i=0; inPreDeleteProcs; i++) { newPreDeleteProcs[i] = buf->preDeleteProcs[i]; newCBArgs[i] = buf->preDeleteCbArgs[i]; } if (buf->nPreDeleteProcs != 0) { XtFree((char *)buf->preDeleteProcs); XtFree((char *)buf->preDeleteCbArgs); } newPreDeleteProcs[buf->nPreDeleteProcs] = bufPreDeleteCB; newCBArgs[buf->nPreDeleteProcs] = cbArg; buf->nPreDeleteProcs++; buf->preDeleteProcs = newPreDeleteProcs; buf->preDeleteCbArgs = newCBArgs; } void BufRemovePreDeleteCB(textBuffer *buf, bufPreDeleteCallbackProc bufPreDeleteCB, void *cbArg) { int i, toRemove = -1; bufPreDeleteCallbackProc *newPreDeleteProcs; void **newCBArgs; /* find the matching callback to remove */ for (i=0; inPreDeleteProcs; i++) { if (buf->preDeleteProcs[i] == bufPreDeleteCB && buf->preDeleteCbArgs[i] == cbArg) { toRemove = i; break; } } if (toRemove == -1) { fprintf(stderr, "NEdit Internal Error: Can't find pre-delete CB to remove\n"); return; } /* Allocate new lists for remaining callback procs and args (if any are left) */ buf->nPreDeleteProcs--; if (buf->nPreDeleteProcs == 0) { buf->nPreDeleteProcs = 0; XtFree((char *)buf->preDeleteProcs); buf->preDeleteProcs = NULL; XtFree((char *)buf->preDeleteCbArgs); buf->preDeleteCbArgs = NULL; return; } newPreDeleteProcs = (bufPreDeleteCallbackProc *) XtMalloc(sizeof(bufPreDeleteCallbackProc *) * (buf->nPreDeleteProcs)); newCBArgs = (void *)XtMalloc(sizeof(void *) * (buf->nPreDeleteProcs)); /* copy out the remaining members and free the old lists */ for (i=0; ipreDeleteProcs[i]; newCBArgs[i] = buf->preDeleteCbArgs[i]; } for (; inPreDeleteProcs; i++) { newPreDeleteProcs[i] = buf->preDeleteProcs[i+1]; newCBArgs[i] = buf->preDeleteCbArgs[i+1]; } XtFree((char *)buf->preDeleteProcs); XtFree((char *)buf->preDeleteCbArgs); buf->preDeleteProcs = newPreDeleteProcs; buf->preDeleteCbArgs = newCBArgs; } /* ** Find the position of the start of the line containing position "pos" */ int BufStartOfLine(textBuffer *buf, int pos) { int startPos; if (!searchBackward(buf, pos, '\n', &startPos)) return 0; return startPos + 1; } /* ** Find the position of the end of the line containing position "pos" ** (which is either a pointer to the newline character ending the line, ** or a pointer to one character beyond the end of the buffer) */ int BufEndOfLine(textBuffer *buf, int pos) { int endPos; if (!searchForward(buf, pos, '\n', &endPos)) endPos = buf->length; return endPos; } /* ** Get a character from the text buffer expanded into it's screen ** representation (which may be several characters for a tab or a ** control code). Returns the number of characters written to "outStr". ** "indent" is the number of characters from the start of the line ** for figuring tabs. Output string is guranteed to be shorter or ** equal in length to MAX_EXP_CHAR_LEN */ int BufGetExpandedChar(const textBuffer* buf, const int pos, const int indent, char* outStr) { return BufExpandCharacter(BufGetCharacter(buf, pos), indent, outStr, buf->tabDist, buf->nullSubsChar); } /* ** Expand a single character from the text buffer into it's screen ** representation (which may be several characters for a tab or a ** control code). Returns the number of characters added to "outStr". ** "indent" is the number of characters from the start of the line ** for figuring tabs. Output string is guranteed to be shorter or ** equal in length to MAX_EXP_CHAR_LEN */ int BufExpandCharacter(const char c, const int indent, char *outStr, const int tabDist, const char nullSubsChar) { int i, nSpaces; /* Convert tabs to spaces */ if (c == '\t') { nSpaces = tabDist - (indent % tabDist); for (i=0; i"); return 5; } #ifdef __MVS__ if (((unsigned char)c) <= 63) { sprintf(outStr, "<%s>", ControlCodeTable[(unsigned char)c]); return strlen(outStr); } #else if (((unsigned char)c) <= 31) { sprintf(outStr, "<%s>", ControlCodeTable[(unsigned char)c]); return strlen(outStr); } else if (c == 127) { sprintf(outStr, ""); return 5; } #endif /* Otherwise, just return the character */ *outStr = c; return 1; } /* ** Return the length in displayed characters of character "c" expanded ** for display (as discussed above in BufGetExpandedChar). If the ** buffer for which the character width is being measured is doing null ** substitution, nullSubsChar should be passed as that character (or nul ** to ignore). */ int BufCharWidth(char c, int indent, int tabDist, char nullSubsChar) { /* Note, this code must parallel that in BufExpandCharacter */ if (c == nullSubsChar) return 5; else if (c == '\t') return tabDist - (indent % tabDist); else if (((unsigned char)c) <= 31) return strlen(ControlCodeTable[(unsigned char)c]) + 2; else if (c == 127) return 5; return 1; } /* ** Count the number of displayed characters between buffer position ** "lineStartPos" and "targetPos". (displayed characters are the characters ** shown on the screen to represent characters in the buffer, where tabs and ** control characters are expanded) */ int BufCountDispChars(const textBuffer* buf, const int lineStartPos, const int targetPos) { int pos, charCount = 0; char expandedChar[MAX_EXP_CHAR_LEN]; pos = lineStartPos; while (pos < targetPos && pos < buf->length) charCount += BufGetExpandedChar(buf, pos++, charCount, expandedChar); return charCount; } /* ** Count forward from buffer position "startPos" in displayed characters ** (displayed characters are the characters shown on the screen to represent ** characters in the buffer, where tabs and control characters are expanded) */ int BufCountForwardDispChars(textBuffer *buf, int lineStartPos, int nChars) { int pos, charCount = 0; char c; pos = lineStartPos; while (charCount < nChars && pos < buf->length) { c = BufGetCharacter(buf, pos); if (c == '\n') return pos; charCount += BufCharWidth(c, charCount, buf->tabDist,buf->nullSubsChar); pos++; } return pos; } /* ** Count the number of newlines between startPos and endPos in buffer "buf". ** The character at position "endPos" is not counted. */ int BufCountLines(textBuffer *buf, int startPos, int endPos) { int pos, gapLen = buf->gapEnd - buf->gapStart; int lineCount = 0; pos = startPos; while (pos < buf->gapStart) { if (pos == endPos) return lineCount; if (buf->buf[pos++] == '\n') lineCount++; } while (pos < buf->length) { if (pos == endPos) return lineCount; if (buf->buf[pos++ + gapLen] == '\n') lineCount++; } return lineCount; } /* ** Find the first character of the line "nLines" forward from "startPos" ** in "buf" and return its position */ int BufCountForwardNLines(const textBuffer* buf, const int startPos, const unsigned nLines) { int pos, gapLen = buf->gapEnd - buf->gapStart; int lineCount = 0; if (nLines == 0) return startPos; pos = startPos; while (pos < buf->gapStart) { if (buf->buf[pos++] == '\n') { lineCount++; if (lineCount == nLines) return pos; } } while (pos < buf->length) { if (buf->buf[pos++ + gapLen] == '\n') { lineCount++; if (lineCount >= nLines) return pos; } } return pos; } /* ** Find the position of the first character of the line "nLines" backwards ** from "startPos" (not counting the character pointed to by "startpos" if ** that is a newline) in "buf". nLines == 0 means find the beginning of ** the line */ int BufCountBackwardNLines(textBuffer *buf, int startPos, int nLines) { int pos, gapLen = buf->gapEnd - buf->gapStart; int lineCount = -1; pos = startPos - 1; if (pos <= 0) return 0; while (pos >= buf->gapStart) { if (buf->buf[pos + gapLen] == '\n') { if (++lineCount >= nLines) return pos + 1; } pos--; } while (pos >= 0) { if (buf->buf[pos] == '\n') { if (++lineCount >= nLines) return pos + 1; } pos--; } return 0; } /* ** Search forwards in buffer "buf" for characters in "searchChars", starting ** with the character "startPos", and returning the result in "foundPos" ** returns True if found, False if not. */ int BufSearchForward(textBuffer *buf, int startPos, const char *searchChars, int *foundPos) { int pos, gapLen = buf->gapEnd - buf->gapStart; const char *c; pos = startPos; while (pos < buf->gapStart) { for (c=searchChars; *c!='\0'; c++) { if (buf->buf[pos] == *c) { *foundPos = pos; return True; } } pos++; } while (pos < buf->length) { for (c=searchChars; *c!='\0'; c++) { if (buf->buf[pos + gapLen] == *c) { *foundPos = pos; return True; } } pos++; } *foundPos = buf->length; return False; } /* ** Search backwards in buffer "buf" for characters in "searchChars", starting ** with the character BEFORE "startPos", returning the result in "foundPos" ** returns True if found, False if not. */ int BufSearchBackward(textBuffer *buf, int startPos, const char *searchChars, int *foundPos) { int pos, gapLen = buf->gapEnd - buf->gapStart; const char *c; if (startPos == 0) { *foundPos = 0; return False; } pos = startPos == 0 ? 0 : startPos - 1; while (pos >= buf->gapStart) { for (c=searchChars; *c!='\0'; c++) { if (buf->buf[pos + gapLen] == *c) { *foundPos = pos; return True; } } pos--; } while (pos >= 0) { for (c=searchChars; *c!='\0'; c++) { if (buf->buf[pos] == *c) { *foundPos = pos; return True; } } pos--; } *foundPos = 0; return False; } /* ** A horrible design flaw in NEdit (from the very start, before we knew that ** NEdit would become so popular), is that it uses C NULL terminated strings ** to hold text. This means editing text containing NUL characters is not ** possible without special consideration. Here is the special consideration. ** The routines below maintain a special substitution-character which stands ** in for a null, and translates strings an buffers back and forth from/to ** the substituted form, figure out what to substitute, and figure out ** when we're in over our heads and no translation is possible. */ /* ** The primary routine for integrating new text into a text buffer with ** substitution of another character for ascii nuls. This substitutes null ** characters in the string in preparation for being copied or replaced ** into the buffer, and if neccessary, adjusts the buffer as well, in the ** event that the string contains the character it is currently using for ** substitution. Returns False, if substitution is no longer possible ** because all non-printable characters are already in use. */ int BufSubstituteNullChars(char *string, int length, textBuffer *buf) { char histogram[256]; /* Find out what characters the string contains */ histogramCharacters(string, length, histogram, True); /* Does the string contain the null-substitute character? If so, re- histogram the buffer text to find a character which is ok in both the string and the buffer, and change the buffer's null-substitution character. If none can be found, give up and return False */ if (histogram[(unsigned char)buf->nullSubsChar] != 0) { char *bufString, newSubsChar; /* here we know we can modify the file buffer directly, so we cast away constness */ bufString = (char *)BufAsString(buf); histogramCharacters(bufString, buf->length, histogram, False); newSubsChar = chooseNullSubsChar(histogram); if (newSubsChar == '\0') { return False; } /* bufString points to the buffer's data, so we substitute in situ */ subsChars(bufString, buf->length, buf->nullSubsChar, newSubsChar); buf->nullSubsChar = newSubsChar; } /* If the string contains null characters, substitute them with the buffer's null substitution character */ if (histogram[0] != 0) subsChars(string, length, '\0', buf->nullSubsChar); return True; } /* ** Convert strings obtained from buffers which contain null characters, which ** have been substituted for by a special substitution character, back to ** a null-containing string. There is no time penalty for calling this ** routine if no substitution has been done. */ void BufUnsubstituteNullChars(char *string, textBuffer *buf) { register char *c, subsChar = buf->nullSubsChar; if (subsChar == '\0') return; for (c=string; *c != '\0'; c++) if (*c == subsChar) *c = '\0'; } /* ** Compares len Bytes contained in buf starting at Position pos with ** the contens of cmpText. Returns 0 if there are no differences, ** != 0 otherwise. ** */ int BufCmp(textBuffer * buf, int pos, int len, const char *cmpText) { int posEnd; int part1Length; int result; posEnd = pos + len; if (posEnd > buf->length) { return (1); } if (pos < 0) { return (-1); } if (posEnd <= buf->gapStart) { return (strncmp(&(buf->buf[pos]), cmpText, len)); } else if (pos >= buf->gapStart) { return (strncmp (&buf->buf[pos + (buf->gapEnd - buf->gapStart)], cmpText, len)); } else { part1Length = buf->gapStart - pos; result = strncmp(&buf->buf[pos], cmpText, part1Length); if (result) { return (result); } return (strncmp(&buf->buf[buf->gapEnd], &cmpText[part1Length], len - part1Length)); } } /* ** Create a pseudo-histogram of the characters in a string (don't actually ** count, because we don't want overflow, just mark the character's presence ** with a 1). If init is true, initialize the histogram before acumulating. ** if not, add the new data to an existing histogram. */ static void histogramCharacters(const char *string, int length, char hist[256], int init) { int i; const char *c; if (init) for (i=0; i<256; i++) hist[i] = 0; for (c=string; c < &string[length]; c++) hist[*((unsigned char *)c)] |= 1; } /* ** Substitute fromChar with toChar in string. */ static void subsChars(char *string, int length, char fromChar, char toChar) { char *c; for (c=string; c < &string[length]; c++) if (*c == fromChar) *c = toChar; } /* ** Search through ascii control characters in histogram in order of least ** likelihood of use, find an unused character to use as a stand-in for a ** null. If the character set is full (no available characters outside of ** the printable set, return the null character. */ static char chooseNullSubsChar(char hist[256]) { #define N_REPLACEMENTS 25 static char replacements[N_REPLACEMENTS] = {1,2,3,4,5,6,14,15,16,17,18,19, 20,21,22,23,24,25,26,28,29,30,31,11,7}; int i; for (i = 0; i < N_REPLACEMENTS; i++) if (hist[(unsigned char)replacements[i]] == 0) return replacements[i]; return '\0'; } /* ** Internal (non-redisplaying) version of BufInsert. Returns the length of ** text inserted (this is just strlen(text), however this calculation can be ** expensive and the length will be required by any caller who will continue ** on to call redisplay). pos must be contiguous with the existing text in ** the buffer (i.e. not past the end). */ static int insert(textBuffer *buf, int pos, const char *text) { int length = strlen(text); /* Prepare the buffer to receive the new text. If the new text fits in the current buffer, just move the gap (if necessary) to where the text should be inserted. If the new text is too large, reallocate the buffer with a gap large enough to accomodate the new text and a gap of PREFERRED_GAP_SIZE */ if (length > buf->gapEnd - buf->gapStart) reallocateBuf(buf, pos, length + PREFERRED_GAP_SIZE); else if (pos != buf->gapStart) moveGap(buf, pos); /* Insert the new text (pos now corresponds to the start of the gap) */ memcpy(&buf->buf[pos], text, length); buf->gapStart += length; buf->length += length; updateSelections(buf, pos, 0, length); return length; } /* ** Internal (non-redisplaying) version of BufRemove. Removes the contents ** of the buffer between start and end (and moves the gap to the site of ** the delete). */ static void delete(textBuffer *buf, int start, int end) { /* if the gap is not contiguous to the area to remove, move it there */ if (start > buf->gapStart) moveGap(buf, start); else if (end < buf->gapStart) moveGap(buf, end); /* expand the gap to encompass the deleted characters */ buf->gapEnd += end - buf->gapStart; buf->gapStart -= buf->gapStart - start; /* update the length */ buf->length -= end - start; /* fix up any selections which might be affected by the change */ updateSelections(buf, start, end-start, 0); } /* ** Insert a column of text without calling the modify callbacks. Note that ** in some pathological cases, inserting can actually decrease the size of ** the buffer because of spaces being coalesced into tabs. "nDeleted" and ** "nInserted" return the number of characters deleted and inserted beginning ** at the start of the line containing "startPos". "endPos" returns buffer ** position of the lower left edge of the inserted column (as a hint for ** routines which need to set a cursor position). */ static void insertCol(textBuffer *buf, int column, int startPos, const char *insText, int *nDeleted, int *nInserted, int *endPos) { int nLines, start, end, insWidth, lineStart, lineEnd; int expReplLen, expInsLen, len, endOffset; char *outStr, *outPtr, *line, *replText, *expText, *insLine; const char *insPtr; if (column < 0) column = 0; /* Allocate a buffer for the replacement string large enough to hold possibly expanded tabs in both the inserted text and the replaced area, as well as per line: 1) an additional 2*MAX_EXP_CHAR_LEN characters for padding where tabs and control characters cross the column of the selection, 2) up to "column" additional spaces per line for padding out to the position of "column", 3) padding up to the width of the inserted text if that must be padded to align the text beyond the inserted column. (Space for additional newlines if the inserted text extends beyond the end of the buffer is counted with the length of insText) */ start = BufStartOfLine(buf, startPos); nLines = countLines(insText) + 1; insWidth = textWidth(insText, buf->tabDist, buf->nullSubsChar); end = BufEndOfLine(buf, BufCountForwardNLines(buf, start, nLines-1)); replText = BufGetRange(buf, start, end); expText = expandTabs(replText, 0, buf->tabDist, buf->nullSubsChar, &expReplLen); XtFree(replText); XtFree(expText); expText = expandTabs(insText, 0, buf->tabDist, buf->nullSubsChar, &expInsLen); XtFree(expText); outStr = XtMalloc(expReplLen + expInsLen + nLines * (column + insWidth + MAX_EXP_CHAR_LEN) + 1); /* Loop over all lines in the buffer between start and end inserting text at column, splitting tabs and adding padding appropriately */ outPtr = outStr; lineStart = start; insPtr = insText; while (True) { lineEnd = BufEndOfLine(buf, lineStart); line = BufGetRange(buf, lineStart, lineEnd); insLine = copyLine(insPtr, &len); insPtr += len; insertColInLine(line, insLine, column, insWidth, buf->tabDist, buf->useTabs, buf->nullSubsChar, outPtr, &len, &endOffset); XtFree(line); XtFree(insLine); #if 0 /* Earlier comments claimed that trailing whitespace could multiply on the ends of lines, but insertColInLine looks like it should never add space unnecessarily, and this trimming interfered with paragraph filling, so lets see if it works without it. MWE */ { char *c; for (c=outPtr+len-1; c>outPtr && (*c == ' ' || *c == '\t'); c--) len--; } #endif outPtr += len; *outPtr++ = '\n'; lineStart = lineEnd < buf->length ? lineEnd + 1 : buf->length; if (*insPtr == '\0') break; insPtr++; } if (outPtr != outStr) outPtr--; /* trim back off extra newline */ *outPtr = '\0'; /* replace the text between start and end with the new stuff */ delete(buf, start, end); insert(buf, start, outStr); *nInserted = outPtr - outStr; *nDeleted = end - start; *endPos = start + (outPtr - outStr) - len + endOffset; XtFree(outStr); } /* ** Delete a rectangle of text without calling the modify callbacks. Returns ** the number of characters replacing those between start and end. Note that ** in some pathological cases, deleting can actually increase the size of ** the buffer because of tab expansions. "endPos" returns the buffer position ** of the point in the last line where the text was removed (as a hint for ** routines which need to position the cursor after a delete operation) */ static void deleteRect(textBuffer *buf, int start, int end, int rectStart, int rectEnd, int *replaceLen, int *endPos) { int nLines, lineStart, lineEnd, len, endOffset; char *outStr, *outPtr, *line, *text, *expText; /* allocate a buffer for the replacement string large enough to hold possibly expanded tabs as well as an additional MAX_EXP_CHAR_LEN * 2 characters per line for padding where tabs and control characters cross the edges of the selection */ start = BufStartOfLine(buf, start); end = BufEndOfLine(buf, end); nLines = BufCountLines(buf, start, end) + 1; text = BufGetRange(buf, start, end); expText = expandTabs(text, 0, buf->tabDist, buf->nullSubsChar, &len); XtFree(text); XtFree(expText); outStr = XtMalloc(len + nLines * MAX_EXP_CHAR_LEN * 2 + 1); /* loop over all lines in the buffer between start and end removing the text between rectStart and rectEnd and padding appropriately */ lineStart = start; outPtr = outStr; while (lineStart <= buf->length && lineStart <= end) { lineEnd = BufEndOfLine(buf, lineStart); line = BufGetRange(buf, lineStart, lineEnd); deleteRectFromLine(line, rectStart, rectEnd, buf->tabDist, buf->useTabs, buf->nullSubsChar, outPtr, &len, &endOffset); XtFree(line); outPtr += len; *outPtr++ = '\n'; lineStart = lineEnd + 1; } if (outPtr != outStr) outPtr--; /* trim back off extra newline */ *outPtr = '\0'; /* replace the text between start and end with the newly created string */ delete(buf, start, end); insert(buf, start, outStr); *replaceLen = outPtr - outStr; *endPos = start + (outPtr - outStr) - len + endOffset; XtFree(outStr); } /* ** Overlay a rectangular area of text without calling the modify callbacks. ** "nDeleted" and "nInserted" return the number of characters deleted and ** inserted beginning at the start of the line containing "startPos". ** "endPos" returns buffer position of the lower left edge of the inserted ** column (as a hint for routines which need to set a cursor position). */ static void overlayRect(textBuffer *buf, int startPos, int rectStart, int rectEnd, const char *insText, int *nDeleted, int *nInserted, int *endPos) { int nLines, start, end, lineStart, lineEnd; int expInsLen, len, endOffset; char *c, *outStr, *outPtr, *line, *expText, *insLine; const char *insPtr; /* Allocate a buffer for the replacement string large enough to hold possibly expanded tabs in the inserted text, as well as per line: 1) an additional 2*MAX_EXP_CHAR_LEN characters for padding where tabs and control characters cross the column of the selection, 2) up to "column" additional spaces per line for padding out to the position of "column", 3) padding up to the width of the inserted text if that must be padded to align the text beyond the inserted column. (Space for additional newlines if the inserted text extends beyond the end of the buffer is counted with the length of insText) */ start = BufStartOfLine(buf, startPos); nLines = countLines(insText) + 1; end = BufEndOfLine(buf, BufCountForwardNLines(buf, start, nLines-1)); expText = expandTabs(insText, 0, buf->tabDist, buf->nullSubsChar, &expInsLen); XtFree(expText); outStr = XtMalloc(end-start + expInsLen + nLines * (rectEnd + MAX_EXP_CHAR_LEN) + 1); /* Loop over all lines in the buffer between start and end overlaying the text between rectStart and rectEnd and padding appropriately. Trim trailing space from line (whitespace at the ends of lines otherwise tends to multiply, since additional padding is added to maintain it */ outPtr = outStr; lineStart = start; insPtr = insText; while (True) { lineEnd = BufEndOfLine(buf, lineStart); line = BufGetRange(buf, lineStart, lineEnd); insLine = copyLine(insPtr, &len); insPtr += len; overlayRectInLine(line, insLine, rectStart, rectEnd, buf->tabDist, buf->useTabs, buf->nullSubsChar, outPtr, &len, &endOffset); XtFree(line); XtFree(insLine); for (c=outPtr+len-1; c>outPtr && (*c == ' ' || *c == '\t'); c--) len--; outPtr += len; *outPtr++ = '\n'; lineStart = lineEnd < buf->length ? lineEnd + 1 : buf->length; if (*insPtr == '\0') break; insPtr++; } if (outPtr != outStr) outPtr--; /* trim back off extra newline */ *outPtr = '\0'; /* replace the text between start and end with the new stuff */ delete(buf, start, end); insert(buf, start, outStr); *nInserted = outPtr - outStr; *nDeleted = end - start; *endPos = start + (outPtr - outStr) - len + endOffset; XtFree(outStr); } /* ** Insert characters from single-line string "insLine" in single-line string ** "line" at "column", leaving "insWidth" space before continuing line. ** "outLen" returns the number of characters written to "outStr", "endOffset" ** returns the number of characters from the beginning of the string to ** the right edge of the inserted text (as a hint for routines which need ** to position the cursor). */ static void insertColInLine(const char *line, const char *insLine, int column, int insWidth, int tabDist, int useTabs, char nullSubsChar, char *outStr, int *outLen, int *endOffset) { char *c, *outPtr, *retabbedStr; const char *linePtr; int indent, toIndent, len, postColIndent; /* copy the line up to "column" */ outPtr = outStr; indent = 0; for (linePtr=line; *linePtr!='\0'; linePtr++) { len = BufCharWidth(*linePtr, indent, tabDist, nullSubsChar); if (indent + len > column) break; indent += len; *outPtr++ = *linePtr; } /* If "column" falls in the middle of a character, and the character is a tab, leave it off and leave the indent short and it will get padded later. If it's a control character, insert it and adjust indent accordingly. */ if (indent < column && *linePtr != '\0') { postColIndent = indent + len; if (*linePtr == '\t') linePtr++; else { *outPtr++ = *linePtr++; indent += len; } } else postColIndent = indent; /* If there's no text after the column and no text to insert, that's all */ if (*insLine == '\0' && *linePtr == '\0') { *outLen = *endOffset = outPtr - outStr; return; } /* pad out to column if text is too short */ if (indent < column) { addPadding(outPtr, indent, column, tabDist, useTabs, nullSubsChar,&len); outPtr += len; indent = column; } /* Copy the text from "insLine" (if any), recalculating the tabs as if the inserted string began at column 0 to its new column destination */ if (*insLine != '\0') { retabbedStr = realignTabs(insLine, 0, indent, tabDist, useTabs, nullSubsChar, &len); for (c=retabbedStr; *c!='\0'; c++) { *outPtr++ = *c; len = BufCharWidth(*c, indent, tabDist, nullSubsChar); indent += len; } XtFree(retabbedStr); } /* If the original line did not extend past "column", that's all */ if (*linePtr == '\0') { *outLen = *endOffset = outPtr - outStr; return; } /* Pad out to column + width of inserted text + (additional original offset due to non-breaking character at column) */ toIndent = column + insWidth + postColIndent-column; addPadding(outPtr, indent, toIndent, tabDist, useTabs, nullSubsChar, &len); outPtr += len; indent = toIndent; /* realign tabs for text beyond "column" and write it out */ retabbedStr = realignTabs(linePtr, postColIndent, indent, tabDist, useTabs, nullSubsChar, &len); strcpy(outPtr, retabbedStr); XtFree(retabbedStr); *endOffset = outPtr - outStr; *outLen = (outPtr - outStr) + len; } /* ** Remove characters in single-line string "line" between displayed positions ** "rectStart" and "rectEnd", and write the result to "outStr", which is ** assumed to be large enough to hold the returned string. Note that in ** certain cases, it is possible for the string to get longer due to ** expansion of tabs. "endOffset" returns the number of characters from ** the beginning of the string to the point where the characters were ** deleted (as a hint for routines which need to position the cursor). */ static void deleteRectFromLine(const char *line, int rectStart, int rectEnd, int tabDist, int useTabs, char nullSubsChar, char *outStr, int *outLen, int *endOffset) { int indent, preRectIndent, postRectIndent, len; const char *c; char *outPtr; char *retabbedStr; /* copy the line up to rectStart */ outPtr = outStr; indent = 0; for (c=line; *c!='\0'; c++) { if (indent > rectStart) break; len = BufCharWidth(*c, indent, tabDist, nullSubsChar); if (indent + len > rectStart && (indent == rectStart || *c == '\t')) break; indent += len; *outPtr++ = *c; } preRectIndent = indent; /* skip the characters between rectStart and rectEnd */ for(; *c!='\0' && indent rectStart) break; inIndent += len; outIndent += len; *outPtr++ = *linePtr; } /* If "rectStart" falls in the middle of a character, and the character is a tab, leave it off and leave the outIndent short and it will get padded later. If it's a control character, insert it and adjust outIndent accordingly. */ if (inIndent < rectStart && *linePtr != '\0') { if (*linePtr == '\t') { /* Skip past the tab */ linePtr++; inIndent += len; } else { *outPtr++ = *linePtr++; outIndent += len; inIndent += len; } } /* skip the characters between rectStart and rectEnd */ for(; *linePtr!='\0' && inIndent < rectEnd; linePtr++) inIndent += BufCharWidth(*linePtr, inIndent, tabDist, nullSubsChar); postRectIndent = inIndent; /* After this inIndent is dead and linePtr is supposed to point at the character just past the last character that will be altered by the overlay, whether that's a \t or otherwise. postRectIndent is the position at which that character is supposed to appear */ /* If there's no text after rectStart and no text to insert, that's all */ if (*insLine == '\0' && *linePtr == '\0') { *outLen = *endOffset = outPtr - outStr; return; } /* pad out to rectStart if text is too short */ if (outIndent < rectStart) { addPadding(outPtr, outIndent, rectStart, tabDist, useTabs, nullSubsChar, &len); outPtr += len; } outIndent = rectStart; /* Copy the text from "insLine" (if any), recalculating the tabs as if the inserted string began at column 0 to its new column destination */ if (*insLine != '\0') { retabbedStr = realignTabs(insLine, 0, rectStart, tabDist, useTabs, nullSubsChar, &len); for (c=retabbedStr; *c!='\0'; c++) { *outPtr++ = *c; len = BufCharWidth(*c, outIndent, tabDist, nullSubsChar); outIndent += len; } XtFree(retabbedStr); } /* If the original line did not extend past "rectStart", that's all */ if (*linePtr == '\0') { *outLen = *endOffset = outPtr - outStr; return; } /* Pad out to rectEnd + (additional original offset due to non-breaking character at right boundary) */ addPadding(outPtr, outIndent, postRectIndent, tabDist, useTabs, nullSubsChar, &len); outPtr += len; outIndent = postRectIndent; /* copy the text beyond "rectEnd" */ strcpy(outPtr, linePtr); *endOffset = outPtr - outStr; *outLen = (outPtr - outStr) + strlen(linePtr); } static void setSelection(selection *sel, int start, int end) { sel->selected = start != end; sel->zeroWidth = (start == end) ? 1 : 0; sel->rectangular = False; sel->start = min(start, end); sel->end = max(start, end); } static void setRectSelect(selection *sel, int start, int end, int rectStart, int rectEnd) { sel->selected = rectStart < rectEnd; sel->zeroWidth = (rectStart == rectEnd) ? 1 : 0; sel->rectangular = True; sel->start = start; sel->end = end; sel->rectStart = rectStart; sel->rectEnd = rectEnd; } static int getSelectionPos(selection *sel, int *start, int *end, int *isRect, int *rectStart, int *rectEnd) { /* Always fill in the parameters (zero-width can be requested too). */ *isRect = sel->rectangular; *start = sel->start; *end = sel->end; if (sel->rectangular) { *rectStart = sel->rectStart; *rectEnd = sel->rectEnd; } return sel->selected; } static char *getSelectionText(textBuffer *buf, selection *sel) { int start, end, isRect, rectStart, rectEnd; char *text; /* If there's no selection, return an allocated empty string */ if (!getSelectionPos(sel, &start, &end, &isRect, &rectStart, &rectEnd)) { text = XtMalloc(1); *text = '\0'; return text; } /* If the selection is not rectangular, return the selected range */ if (isRect) return BufGetTextInRect(buf, start, end, rectStart, rectEnd); else return BufGetRange(buf, start, end); } static void removeSelected(textBuffer *buf, selection *sel) { int start, end; int isRect, rectStart, rectEnd; if (!getSelectionPos(sel, &start, &end, &isRect, &rectStart, &rectEnd)) return; if (isRect) BufRemoveRect(buf, start, end, rectStart, rectEnd); else BufRemove(buf, start, end); } static void replaceSelected(textBuffer *buf, selection *sel, const char *text) { int start, end, isRect, rectStart, rectEnd; selection oldSelection = *sel; /* If there's no selection, return */ if (!getSelectionPos(sel, &start, &end, &isRect, &rectStart, &rectEnd)) return; /* Do the appropriate type of replace */ if (isRect) BufReplaceRect(buf, start, end, rectStart, rectEnd, text); else BufReplace(buf, start, end, text); /* Unselect (happens automatically in BufReplace, but BufReplaceRect can't detect when the contents of a selection goes away) */ sel->selected = False; redisplaySelection(buf, &oldSelection, sel); } static void addPadding(char *string, int startIndent, int toIndent, int tabDist, int useTabs, char nullSubsChar, int *charsAdded) { char *outPtr; int len, indent; indent = startIndent; outPtr = string; if (useTabs) { while (indent < toIndent) { len = BufCharWidth('\t', indent, tabDist, nullSubsChar); if (len > 1 && indent + len <= toIndent) { *outPtr++ = '\t'; indent += len; } else { *outPtr++ = ' '; indent++; } } } else { while (indent < toIndent) { *outPtr++ = ' '; indent++; } } *charsAdded = outPtr - string; } /* ** Call the stored modify callback procedure(s) for this buffer to update the ** changed area(s) on the screen and any other listeners. */ static void callModifyCBs(textBuffer *buf, int pos, int nDeleted, int nInserted, int nRestyled, const char *deletedText) { int i; for (i=0; inModifyProcs; i++) (*buf->modifyProcs[i])(pos, nInserted, nDeleted, nRestyled, deletedText, buf->cbArgs[i]); } /* ** Call the stored pre-delete callback procedure(s) for this buffer to update ** the changed area(s) on the screen and any other listeners. */ static void callPreDeleteCBs(textBuffer *buf, int pos, int nDeleted) { int i; for (i=0; inPreDeleteProcs; i++) (*buf->preDeleteProcs[i])(pos, nDeleted, buf->preDeleteCbArgs[i]); } /* ** Call the stored redisplay procedure(s) for this buffer to update the ** screen for a change in a selection. */ static void redisplaySelection(textBuffer *buf, selection *oldSelection, selection *newSelection) { int oldStart, oldEnd, newStart, newEnd, ch1Start, ch1End, ch2Start, ch2End; /* If either selection is rectangular, add an additional character to the end of the selection to request the redraw routines to wipe out the parts of the selection beyond the end of the line */ oldStart = oldSelection->start; newStart = newSelection->start; oldEnd = oldSelection->end; newEnd = newSelection->end; if (oldSelection->rectangular) oldEnd++; if (newSelection->rectangular) newEnd++; /* If the old or new selection is unselected, just redisplay the single area that is (was) selected and return */ if (!oldSelection->selected && !newSelection->selected) return; if (!oldSelection->selected) { callModifyCBs(buf, newStart, 0, 0, newEnd-newStart, NULL); return; } if (!newSelection->selected) { callModifyCBs(buf, oldStart, 0, 0, oldEnd-oldStart, NULL); return; } /* If the selection changed from normal to rectangular or visa versa, or if a rectangular selection changed boundaries, redisplay everything */ if ((oldSelection->rectangular && !newSelection->rectangular) || (!oldSelection->rectangular && newSelection->rectangular) || (oldSelection->rectangular && ( (oldSelection->rectStart != newSelection->rectStart) || (oldSelection->rectEnd != newSelection->rectEnd)))) { callModifyCBs(buf, min(oldStart, newStart), 0, 0, max(oldEnd, newEnd) - min(oldStart, newStart), NULL); return; } /* If the selections are non-contiguous, do two separate updates and return */ if (oldEnd < newStart || newEnd < oldStart) { callModifyCBs(buf, oldStart, 0, 0, oldEnd-oldStart, NULL); callModifyCBs(buf, newStart, 0, 0, newEnd-newStart, NULL); return; } /* Otherwise, separate into 3 separate regions: ch1, and ch2 (the two changed areas), and the unchanged area of their intersection, and update only the changed area(s) */ ch1Start = min(oldStart, newStart); ch2End = max(oldEnd, newEnd); ch1End = max(oldStart, newStart); ch2Start = min(oldEnd, newEnd); if (ch1Start != ch1End) callModifyCBs(buf, ch1Start, 0, 0, ch1End-ch1Start, NULL); if (ch2Start != ch2End) callModifyCBs(buf, ch2Start, 0, 0, ch2End-ch2Start, NULL); } static void moveGap(textBuffer *buf, int pos) { int gapLen = buf->gapEnd - buf->gapStart; if (pos > buf->gapStart) memmove(&buf->buf[buf->gapStart], &buf->buf[buf->gapEnd], pos - buf->gapStart); else memmove(&buf->buf[pos + gapLen], &buf->buf[pos], buf->gapStart - pos); buf->gapEnd += pos - buf->gapStart; buf->gapStart += pos - buf->gapStart; } /* ** reallocate the text storage in "buf" to have a gap starting at "newGapStart" ** and a gap size of "newGapLen", preserving the buffer's current contents. */ static void reallocateBuf(textBuffer *buf, int newGapStart, int newGapLen) { char *newBuf; int newGapEnd; newBuf = XtMalloc(buf->length + newGapLen + 1); newBuf[buf->length + PREFERRED_GAP_SIZE] = '\0'; newGapEnd = newGapStart + newGapLen; if (newGapStart <= buf->gapStart) { memcpy(newBuf, buf->buf, newGapStart); memcpy(&newBuf[newGapEnd], &buf->buf[newGapStart], buf->gapStart - newGapStart); memcpy(&newBuf[newGapEnd + buf->gapStart - newGapStart], &buf->buf[buf->gapEnd], buf->length - buf->gapStart); } else { /* newGapStart > buf->gapStart */ memcpy(newBuf, buf->buf, buf->gapStart); memcpy(&newBuf[buf->gapStart], &buf->buf[buf->gapEnd], newGapStart - buf->gapStart); memcpy(&newBuf[newGapEnd], &buf->buf[buf->gapEnd + newGapStart - buf->gapStart], buf->length - newGapStart); } XtFree(buf->buf); buf->buf = newBuf; buf->gapStart = newGapStart; buf->gapEnd = newGapEnd; #ifdef PURIFY {int i; for (i=buf->gapStart; igapEnd; i++) buf->buf[i] = '.';} #endif } /* ** Update all of the selections in "buf" for changes in the buffer's text */ static void updateSelections(textBuffer *buf, int pos, int nDeleted, int nInserted) { updateSelection(&buf->primary, pos, nDeleted, nInserted); updateSelection(&buf->secondary, pos, nDeleted, nInserted); updateSelection(&buf->highlight, pos, nDeleted, nInserted); } /* ** Update an individual selection for changes in the corresponding text */ static void updateSelection(selection *sel, int pos, int nDeleted, int nInserted) { if ((!sel->selected && !sel->zeroWidth) || pos > sel->end) return; if (pos+nDeleted <= sel->start) { sel->start += nInserted - nDeleted; sel->end += nInserted - nDeleted; } else if (pos <= sel->start && pos+nDeleted >= sel->end) { sel->start = pos; sel->end = pos; sel->selected = False; sel->zeroWidth = False; } else if (pos <= sel->start && pos+nDeleted < sel->end) { sel->start = pos; sel->end = nInserted + sel->end - nDeleted; } else if (pos < sel->end) { sel->end += nInserted - nDeleted; if (sel->end <= sel->start) sel->selected = False; } } /* ** Search forwards in buffer "buf" for character "searchChar", starting ** with the character "startPos", and returning the result in "foundPos" ** returns True if found, False if not. (The difference between this and ** BufSearchForward is that it's optimized for single characters. The ** overall performance of the text widget is dependent on its ability to ** count lines quickly, hence searching for a single character: newline) */ static int searchForward(textBuffer *buf, int startPos, char searchChar, int *foundPos) { int pos, gapLen = buf->gapEnd - buf->gapStart; pos = startPos; while (pos < buf->gapStart) { if (buf->buf[pos] == searchChar) { *foundPos = pos; return True; } pos++; } while (pos < buf->length) { if (buf->buf[pos + gapLen] == searchChar) { *foundPos = pos; return True; } pos++; } *foundPos = buf->length; return False; } /* ** Search backwards in buffer "buf" for character "searchChar", starting ** with the character BEFORE "startPos", returning the result in "foundPos" ** returns True if found, False if not. (The difference between this and ** BufSearchBackward is that it's optimized for single characters. The ** overall performance of the text widget is dependent on its ability to ** count lines quickly, hence searching for a single character: newline) */ static int searchBackward(textBuffer *buf, int startPos, char searchChar, int *foundPos) { int pos, gapLen = buf->gapEnd - buf->gapStart; if (startPos == 0) { *foundPos = 0; return False; } pos = startPos == 0 ? 0 : startPos - 1; while (pos >= buf->gapStart) { if (buf->buf[pos + gapLen] == searchChar) { *foundPos = pos; return True; } pos--; } while (pos >= 0) { if (buf->buf[pos] == searchChar) { *foundPos = pos; return True; } pos--; } *foundPos = 0; return False; } /* ** Copy from "text" to end up to but not including newline (or end of "text") ** and return the copy as the function value, and the length of the line in ** "lineLen" */ static char *copyLine(const char *text, int *lineLen) { int len = 0; const char *c; char *outStr; for (c=text; *c!='\0' && *c!='\n'; c++) len++; outStr = XtMalloc(len + 1); strncpy(outStr, text, len); outStr[len] = '\0'; *lineLen = len; return outStr; } /* ** Count the number of newlines in a null-terminated text string; */ static int countLines(const char *string) { const char *c; int lineCount = 0; for (c=string; *c!='\0'; c++) if (*c == '\n') lineCount++; return lineCount; } /* ** Measure the width in displayed characters of string "text" */ static int textWidth(const char *text, int tabDist, char nullSubsChar) { int width = 0, maxWidth = 0; const char *c; for (c=text; *c!='\0'; c++) { if (*c == '\n') { if (width > maxWidth) maxWidth = width; width = 0; } else width += BufCharWidth(*c, width, tabDist, nullSubsChar); } if (width > maxWidth) return width; return maxWidth; } /* ** Find the first and last character position in a line withing a rectangular ** selection (for copying). Includes tabs which cross rectStart, but not ** control characters which do so. Leaves off tabs which cross rectEnd. ** ** Technically, the calling routine should convert tab characters which ** cross the right boundary of the selection to spaces which line up with ** the edge of the selection. Unfortunately, the additional memory ** management required in the parent routine to allow for the changes ** in string size is not worth all the extra work just for a couple of ** shifted characters, so if a tab protrudes, just lop it off and hope ** that there are other characters in the selection to establish the right ** margin for subsequent columnar pastes of this data. */ static void findRectSelBoundariesForCopy(textBuffer *buf, int lineStartPos, int rectStart, int rectEnd, int *selStart, int *selEnd) { int pos, width, indent = 0; char c; /* find the start of the selection */ for (pos=lineStartPos; poslength; pos++) { c = BufGetCharacter(buf, pos); if (c == '\n') break; width = BufCharWidth(c, indent, buf->tabDist, buf->nullSubsChar); if (indent + width > rectStart) { if (indent != rectStart && c != '\t') { pos++; indent += width; } break; } indent += width; } *selStart = pos; /* find the end */ for (; poslength; pos++) { c = BufGetCharacter(buf, pos); if (c == '\n') break; width = BufCharWidth(c, indent, buf->tabDist, buf->nullSubsChar); indent += width; if (indent > rectEnd) { if (indent-width != rectEnd && c != '\t') pos++; break; } } *selEnd = pos; } /* ** Adjust the space and tab characters from string "text" so that non-white ** characters remain stationary when the text is shifted from starting at ** "origIndent" to starting at "newIndent". Returns an allocated string ** which must be freed by the caller with XtFree. */ static char *realignTabs(const char *text, int origIndent, int newIndent, int tabDist, int useTabs, char nullSubsChar, int *newLength) { char *expStr, *outStr; int len; /* If the tabs settings are the same, retain original tabs */ if (origIndent % tabDist == newIndent %tabDist) { len = strlen(text); outStr = XtMalloc(len + 1); strcpy(outStr, text); *newLength = len; return outStr; } /* If the tab settings are not the same, brutally convert tabs to spaces, then back to tabs in the new position */ expStr = expandTabs(text, origIndent, tabDist, nullSubsChar, &len); if (!useTabs) { *newLength = len; return expStr; } outStr = unexpandTabs(expStr, newIndent, tabDist, nullSubsChar, newLength); XtFree(expStr); return outStr; } /* ** Expand tabs to spaces for a block of text. The additional parameter ** "startIndent" if nonzero, indicates that the text is a rectangular selection ** beginning at column "startIndent" */ static char *expandTabs(const char *text, int startIndent, int tabDist, char nullSubsChar, int *newLen) { char *outStr, *outPtr; const char *c; int indent, len, outLen = 0; /* rehearse the expansion to figure out length for output string */ indent = startIndent; for (c=text; *c!='\0'; c++) { if (*c == '\t') { len = BufCharWidth(*c, indent, tabDist, nullSubsChar); outLen += len; indent += len; } else if (*c == '\n') { indent = startIndent; outLen++; } else { indent += BufCharWidth(*c, indent, tabDist, nullSubsChar); outLen++; } } /* do the expansion */ outStr = XtMalloc(outLen+1); outPtr = outStr; indent = startIndent; for (c=text; *c!= '\0'; c++) { if (*c == '\t') { len = BufExpandCharacter(*c, indent, outPtr, tabDist, nullSubsChar); outPtr += len; indent += len; } else if (*c == '\n') { indent = startIndent; *outPtr++ = *c; } else { indent += BufCharWidth(*c, indent, tabDist, nullSubsChar); *outPtr++ = *c; } } outStr[outLen] = '\0'; *newLen = outLen; return outStr; } /* ** Convert sequences of spaces into tabs. The threshold for conversion is ** when 3 or more spaces can be converted into a single tab, this avoids ** converting double spaces after a period withing a block of text. */ static char *unexpandTabs(const char *text, int startIndent, int tabDist, char nullSubsChar, int *newLen) { char *outStr, *outPtr, expandedChar[MAX_EXP_CHAR_LEN]; const char *c; int indent, len; outStr = XtMalloc(strlen(text)+1); outPtr = outStr; indent = startIndent; for (c=text; *c!='\0';) { if (*c == ' ') { len = BufExpandCharacter('\t', indent, expandedChar, tabDist, nullSubsChar); if (len >= 3 && !strncmp(c, expandedChar, len)) { c += len; *outPtr++ = '\t'; indent += len; } else { *outPtr++ = *c++; indent++; } } else if (*c == '\n') { indent = startIndent; *outPtr++ = *c++; } else { *outPtr++ = *c++; indent++; } } *outPtr = '\0'; *newLen = outPtr - outStr; return outStr; } static int max(int i1, int i2) { return i1 >= i2 ? i1 : i2; } static int min(int i1, int i2) { return i1 <= i2 ? i1 : i2; } nedit-5.6.orig/source/textBuf.h0000644000175000017500000002253010737527370015221 0ustar paulpaul/* $Id: textBuf.h,v 1.22 2008/01/04 22:11:04 yooden Exp $ */ /******************************************************************************* * * * textBuf.h -- Nirvana Editor Text Buffer Header File * * * * Copyright 2003 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_TEXTBUF_H_INCLUDED #define NEDIT_TEXTBUF_H_INCLUDED /* Maximum length in characters of a tab or control character expansion of a single buffer character */ #define MAX_EXP_CHAR_LEN 20 typedef struct _RangesetTable RangesetTable; typedef struct { char selected; /* True if the selection is active */ char rectangular; /* True if the selection is rectangular */ char zeroWidth; /* Width 0 selections aren't "real" selections, but they can be useful when creating rectangular selections from the keyboard. */ int start; /* Pos. of start of selection, or if rectangular start of line containing it. */ int end; /* Pos. of end of selection, or if rectangular end of line containing it. */ int rectStart; /* Indent of left edge of rect. selection */ int rectEnd; /* Indent of right edge of rect. selection */ } selection; typedef void (*bufModifyCallbackProc)(int pos, int nInserted, int nDeleted, int nRestyled, const char *deletedText, void *cbArg); typedef void (*bufPreDeleteCallbackProc)(int pos, int nDeleted, void *cbArg); typedef struct _textBuffer { int length; /* length of the text in the buffer (the length of the buffer itself must be calculated: gapEnd - gapStart + length) */ char *buf; /* allocated memory where the text is stored */ int gapStart; /* points to the first character of the gap */ int gapEnd; /* points to the first char after the gap */ selection primary; /* highlighted areas */ selection secondary; selection highlight; int tabDist; /* equiv. number of characters in a tab */ int useTabs; /* True if buffer routines are allowed to use tabs for padding in rectangular operations */ int nModifyProcs; /* number of modify-redisplay procs attached */ bufModifyCallbackProc /* procedures to call when buffer is */ *modifyProcs; /* modified to redisplay contents */ void **cbArgs; /* caller arguments for modifyProcs above */ int nPreDeleteProcs; /* number of pre-delete procs attached */ bufPreDeleteCallbackProc /* procedure to call before text is deleted */ *preDeleteProcs; /* from the buffer; at most one is supported. */ void **preDeleteCbArgs; /* caller argument for pre-delete proc above */ int cursorPosHint; /* hint for reasonable cursor position after a buffer modification operation */ char nullSubsChar; /* NEdit is based on C null-terminated strings, so ascii-nul characters must be substituted with something else. This is the else, but of course, things get quite messy when you use it */ RangesetTable *rangesetTable; /* current range sets */ } textBuffer; textBuffer *BufCreate(void); textBuffer *BufCreatePreallocated(int requestedSize); void BufFree(textBuffer *buf); char *BufGetAll(textBuffer *buf); const char *BufAsString(textBuffer *buf); void BufSetAll(textBuffer *buf, const char *text); char* BufGetRange(const textBuffer* buf, int start, int end); char BufGetCharacter(const textBuffer* buf, const int pos); char *BufGetTextInRect(textBuffer *buf, int start, int end, int rectStart, int rectEnd); void BufInsert(textBuffer *buf, int pos, const char *text); void BufRemove(textBuffer *buf, int start, int end); void BufReplace(textBuffer *buf, int start, int end, const char *text); void BufCopyFromBuf(textBuffer *fromBuf, textBuffer *toBuf, int fromStart, int fromEnd, int toPos); void BufInsertCol(textBuffer *buf, int column, int startPos, const char *text, int *charsInserted, int *charsDeleted); void BufReplaceRect(textBuffer *buf, int start, int end, int rectStart, int rectEnd, const char *text); void BufRemoveRect(textBuffer *buf, int start, int end, int rectStart, int rectEnd); void BufOverlayRect(textBuffer *buf, int startPos, int rectStart, int rectEnd, const char *text, int *charsInserted, int *charsDeleted); void BufClearRect(textBuffer *buf, int start, int end, int rectStart, int rectEnd); int BufGetTabDistance(textBuffer *buf); void BufSetTabDistance(textBuffer *buf, int tabDist); void BufCheckDisplay(textBuffer *buf, int start, int end); void BufSelect(textBuffer *buf, int start, int end); void BufUnselect(textBuffer *buf); void BufRectSelect(textBuffer *buf, int start, int end, int rectStart, int rectEnd); int BufGetSelectionPos(textBuffer *buf, int *start, int *end, int *isRect, int *rectStart, int *rectEnd); int BufGetEmptySelectionPos(textBuffer *buf, int *start, int *end, int *isRect, int *rectStart, int *rectEnd); char *BufGetSelectionText(textBuffer *buf); void BufRemoveSelected(textBuffer *buf); void BufReplaceSelected(textBuffer *buf, const char *text); void BufSecondarySelect(textBuffer *buf, int start, int end); void BufSecondaryUnselect(textBuffer *buf); void BufSecRectSelect(textBuffer *buf, int start, int end, int rectStart, int rectEnd); int BufGetSecSelectPos(textBuffer *buf, int *start, int *end, int *isRect, int *rectStart, int *rectEnd); char *BufGetSecSelectText(textBuffer *buf); void BufRemoveSecSelect(textBuffer *buf); void BufReplaceSecSelect(textBuffer *buf, const char *text); void BufHighlight(textBuffer *buf, int start, int end); void BufUnhighlight(textBuffer *buf); void BufRectHighlight(textBuffer *buf, int start, int end, int rectStart, int rectEnd); int BufGetHighlightPos(textBuffer *buf, int *start, int *end, int *isRect, int *rectStart, int *rectEnd); void BufAddModifyCB(textBuffer *buf, bufModifyCallbackProc bufModifiedCB, void *cbArg); void BufAddHighPriorityModifyCB(textBuffer *buf, bufModifyCallbackProc bufModifiedCB, void *cbArg); void BufRemoveModifyCB(textBuffer *buf, bufModifyCallbackProc bufModifiedCB, void *cbArg); void BufAddPreDeleteCB(textBuffer *buf, bufPreDeleteCallbackProc bufPreDeleteCB, void *cbArg); void BufRemovePreDeleteCB(textBuffer *buf, bufPreDeleteCallbackProc bufPreDeleteCB, void *cbArg); int BufStartOfLine(textBuffer *buf, int pos); int BufEndOfLine(textBuffer *buf, int pos); int BufGetExpandedChar(const textBuffer* buf, const int pos, const int indent, char* outStr); int BufExpandCharacter(char c, int indent, char *outStr, int tabDist, char nullSubsChar); int BufCharWidth(char c, int indent, int tabDist, char nullSubsChar); int BufCountDispChars(const textBuffer* buf, const int lineStartPos, const int targetPos); int BufCountForwardDispChars(textBuffer *buf, int lineStartPos, int nChars); int BufCountLines(textBuffer *buf, int startPos, int endPos); int BufCountForwardNLines(const textBuffer* buf, const int startPos, const unsigned nLines); int BufCountBackwardNLines(textBuffer *buf, int startPos, int nLines); int BufSearchForward(textBuffer *buf, int startPos, const char *searchChars, int *foundPos); int BufSearchBackward(textBuffer *buf, int startPos, const char *searchChars, int *foundPos); int BufSubstituteNullChars(char *string, int length, textBuffer *buf); void BufUnsubstituteNullChars(char *string, textBuffer *buf); int BufCmp(textBuffer * buf, int pos, int len, const char *cmpText); #endif /* NEDIT_TEXTBUF_H_INCLUDED */ nedit-5.6.orig/source/textDisp.c0000644000175000017500000043646610737531724015416 0ustar paulpaulstatic const char CVSID[] = "$Id: textDisp.c,v 1.71 2008/01/04 22:31:48 yooden Exp $"; /******************************************************************************* * * * textDisp.c - Display text from a text buffer * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * June 15, 1995 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "textDisp.h" #include "textBuf.h" #include "text.h" #include "textP.h" #include "nedit.h" #include "calltips.h" #include "highlight.h" #include "rangeset.h" #include #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif /* Masks for text drawing methods. These are or'd together to form an integer which describes what drawing calls to use to draw a string */ #define FILL_SHIFT 8 #define SECONDARY_SHIFT 9 #define PRIMARY_SHIFT 10 #define HIGHLIGHT_SHIFT 11 #define STYLE_LOOKUP_SHIFT 0 #define BACKLIGHT_SHIFT 12 #define FILL_MASK (1 << FILL_SHIFT) #define SECONDARY_MASK (1 << SECONDARY_SHIFT) #define PRIMARY_MASK (1 << PRIMARY_SHIFT) #define HIGHLIGHT_MASK (1 << HIGHLIGHT_SHIFT) #define STYLE_LOOKUP_MASK (0xff << STYLE_LOOKUP_SHIFT) #define BACKLIGHT_MASK (0xff << BACKLIGHT_SHIFT) #define RANGESET_SHIFT (20) #define RANGESET_MASK (0x3F << RANGESET_SHIFT) /* If you use both 32-Bit Style mask layout: Bits +----------------+----------------+----------------+----------------+ hex |1F1E1D1C1B1A1918|1716151413121110| F E D C B A 9 8| 7 6 5 4 3 2 1 0| dec |3130292827262524|2322212019181716|151413121110 9 8| 7 6 5 4 3 2 1 0| +----------------+----------------+----------------+----------------+ Type | r r| r r r r b b b b| b b b b H 1 2 F| s s s s s s s s| +----------------+----------------+----------------+----------------+ where: s - style lookup value (8 bits) F - fill (1 bit) 2 - secondary selection (1 bit) 1 - primary selection (1 bit) H - highlight (1 bit) b - backlighting index (8 bits) r - rangeset index (6 bits) This leaves 6 "unused" bits */ /* Maximum displayable line length (how many characters will fit across the widest window). This amount of memory is temporarily allocated from the stack in the redisplayLine routine for drawing strings */ #define MAX_DISP_LINE_LEN 1000 /* Macro for getting the TextPart from a textD */ #define TEXT_OF_TEXTD(t) (((TextWidget)((t)->w))->text) enum positionTypes {CURSOR_POS, CHARACTER_POS}; static void updateLineStarts(textDisp *textD, int pos, int charsInserted, int charsDeleted, int linesInserted, int linesDeleted, int *scrolled); static void offsetLineStarts(textDisp *textD, int newTopLineNum); static void calcLineStarts(textDisp *textD, int startLine, int endLine); static void calcLastChar(textDisp *textD); static int posToVisibleLineNum(textDisp *textD, int pos, int *lineNum); static void redisplayLine(textDisp *textD, int visLineNum, int leftClip, int rightClip, int leftCharIndex, int rightCharIndex); static void drawString(textDisp *textD, int style, int x, int y, int toX, char *string, int nChars); static void clearRect(textDisp *textD, GC gc, int x, int y, int width, int height); static void drawCursor(textDisp *textD, int x, int y); static int styleOfPos(textDisp *textD, int lineStartPos, int lineLen, int lineIndex, int dispIndex, int thisChar); static int stringWidth(const textDisp* textD, const char* string, const int length, const int style); static int inSelection(selection *sel, int pos, int lineStartPos, int dispIndex); static int xyToPos(textDisp *textD, int x, int y, int posType); static void xyToUnconstrainedPos(textDisp *textD, int x, int y, int *row, int *column, int posType); static void bufPreDeleteCB(int pos, int nDeleted, void *cbArg); static void bufModifiedCB(int pos, int nInserted, int nDeleted, int nRestyled, const char *deletedText, void *cbArg); static void setScroll(textDisp *textD, int topLineNum, int horizOffset, int updateVScrollBar, int updateHScrollBar); static void hScrollCB(Widget w, XtPointer clientData, XtPointer callData); static void vScrollCB(Widget w, XtPointer clientData, XtPointer callData); static void visibilityEH(Widget w, XtPointer data, XEvent *event, Boolean *continueDispatch); static void redrawLineNumbers(textDisp *textD, int clearAll); static void updateVScrollBarRange(textDisp *textD); static int updateHScrollBarRange(textDisp *textD); static int max(int i1, int i2); static int min(int i1, int i2); static int countLines(const char *string); static int measureVisLine(textDisp *textD, int visLineNum); static int emptyLinesVisible(textDisp *textD); static void blankCursorProtrusions(textDisp *textD); static void allocateFixedFontGCs(textDisp *textD, XFontStruct *fontStruct, Pixel bgPixel, Pixel fgPixel, Pixel selectFGPixel, Pixel selectBGPixel, Pixel highlightFGPixel, Pixel highlightBGPixel, Pixel lineNumFGPixel); static GC allocateGC(Widget w, unsigned long valueMask, unsigned long foreground, unsigned long background, Font font, unsigned long dynamicMask, unsigned long dontCareMask); static void releaseGC(Widget w, GC gc); static void resetClipRectangles(textDisp *textD); static int visLineLength(textDisp *textD, int visLineNum); static void measureDeletedLines(textDisp *textD, int pos, int nDeleted); static void findWrapRange(textDisp *textD, const char *deletedText, int pos, int nInserted, int nDeleted, int *modRangeStart, int *modRangeEnd, int *linesInserted, int *linesDeleted); static void wrappedLineCounter(const textDisp* textD, const textBuffer* buf, const int startPos, const int maxPos, const int maxLines, const Boolean startPosIsLineStart, const int styleBufOffset, int* retPos, int* retLines, int* retLineStart, int* retLineEnd); static void findLineEnd(textDisp *textD, int startPos, int startPosIsLineStart, int *lineEnd, int *nextLineStart); static int wrapUsesCharacter(textDisp *textD, int lineEndPos); static void hideOrShowHScrollBar(textDisp *textD); static int rangeTouchesRectSel(selection *sel, int rangeStart, int rangeEnd); static void extendRangeForStyleMods(textDisp *textD, int *start, int *end); static int getAbsTopLineNum(textDisp *textD); static void offsetAbsLineNum(textDisp *textD, int oldFirstChar); static int maintainingAbsTopLineNum(textDisp *textD); static void resetAbsLineNum(textDisp *textD); static int measurePropChar(const textDisp* textD, const char c, const int colNum, const int pos); static Pixel allocBGColor(Widget w, char *colorName, int *ok); static Pixel getRangesetColor(textDisp *textD, int ind, Pixel bground); static void textDRedisplayRange(textDisp *textD, int start, int end); textDisp *TextDCreate(Widget widget, Widget hScrollBar, Widget vScrollBar, Position left, Position top, Position width, Position height, Position lineNumLeft, Position lineNumWidth, textBuffer *buffer, XFontStruct *fontStruct, Pixel bgPixel, Pixel fgPixel, Pixel selectFGPixel, Pixel selectBGPixel, Pixel highlightFGPixel, Pixel highlightBGPixel, Pixel cursorFGPixel, Pixel lineNumFGPixel, int continuousWrap, int wrapMargin, XmString bgClassString, Pixel calltipFGPixel, Pixel calltipBGPixel) { textDisp *textD; XGCValues gcValues; int i; textD = (textDisp *)XtMalloc(sizeof(textDisp)); textD->w = widget; textD->top = top; textD->left = left; textD->width = width; textD->height = height; textD->cursorOn = True; textD->cursorPos = 0; textD->cursorX = -100; textD->cursorY = -100; textD->cursorToHint = NO_HINT; textD->cursorStyle = NORMAL_CURSOR; textD->cursorPreferredCol = -1; textD->buffer = buffer; textD->firstChar = 0; textD->lastChar = 0; textD->nBufferLines = 0; textD->topLineNum = 1; textD->absTopLineNum = 1; textD->needAbsTopLineNum = False; textD->horizOffset = 0; textD->visibility = VisibilityUnobscured; textD->hScrollBar = hScrollBar; textD->vScrollBar = vScrollBar; textD->fontStruct = fontStruct; textD->ascent = fontStruct->ascent; textD->descent = fontStruct->descent; textD->fixedFontWidth = fontStruct->min_bounds.width == fontStruct->max_bounds.width ? fontStruct->min_bounds.width : -1; textD->styleBuffer = NULL; textD->styleTable = NULL; textD->nStyles = 0; textD->bgPixel = bgPixel; textD->fgPixel = fgPixel; textD->selectFGPixel = selectFGPixel; textD->highlightFGPixel = highlightFGPixel; textD->selectBGPixel = selectBGPixel; textD->highlightBGPixel = highlightBGPixel; textD->lineNumFGPixel = lineNumFGPixel; textD->cursorFGPixel = cursorFGPixel; textD->wrapMargin = wrapMargin; textD->continuousWrap = continuousWrap; allocateFixedFontGCs(textD, fontStruct, bgPixel, fgPixel, selectFGPixel, selectBGPixel, highlightFGPixel, highlightBGPixel, lineNumFGPixel); textD->styleGC = allocateGC(textD->w, 0, 0, 0, fontStruct->fid, GCClipMask|GCForeground|GCBackground, GCArcMode); textD->lineNumLeft = lineNumLeft; textD->lineNumWidth = lineNumWidth; textD->nVisibleLines = (height - 1) / (textD->ascent + textD->descent) + 1; gcValues.foreground = cursorFGPixel; textD->cursorFGGC = XtGetGC(widget, GCForeground, &gcValues); textD->lineStarts = (int *)XtMalloc(sizeof(int) * textD->nVisibleLines); textD->lineStarts[0] = 0; textD->calltipW = NULL; textD->calltipShell = NULL; textD->calltip.ID = 0; textD->calltipFGPixel = calltipFGPixel; textD->calltipBGPixel = calltipBGPixel; for (i=1; inVisibleLines; i++) textD->lineStarts[i] = -1; textD->bgClassPixel = NULL; textD->bgClass = NULL; TextDSetupBGClasses(widget, bgClassString, &textD->bgClassPixel, &textD->bgClass, bgPixel); textD->suppressResync = 0; textD->nLinesDeleted = 0; textD->modifyingTabDist = 0; textD->pointerHidden = False; textD->graphicsExposeQueue = NULL; /* Attach an event handler to the widget so we can know the visibility (used for choosing the fastest drawing method) */ XtAddEventHandler(widget, VisibilityChangeMask, False, visibilityEH, textD); /* Attach the callback to the text buffer for receiving modification information */ if (buffer != NULL) { BufAddModifyCB(buffer, bufModifiedCB, textD); BufAddPreDeleteCB(buffer, bufPreDeleteCB, textD); } /* Initialize the scroll bars and attach movement callbacks */ if (vScrollBar != NULL) { XtVaSetValues(vScrollBar, XmNminimum, 1, XmNmaximum, 2, XmNsliderSize, 1, XmNrepeatDelay, 10, XmNvalue, 1, NULL); XtAddCallback(vScrollBar, XmNdragCallback, vScrollCB, (XtPointer)textD); XtAddCallback(vScrollBar, XmNvalueChangedCallback, vScrollCB, (XtPointer)textD); } if (hScrollBar != NULL) { XtVaSetValues(hScrollBar, XmNminimum, 0, XmNmaximum, 1, XmNsliderSize, 1, XmNrepeatDelay, 10, XmNvalue, 0, XmNincrement, fontStruct->max_bounds.width, NULL); XtAddCallback(hScrollBar, XmNdragCallback, hScrollCB, (XtPointer)textD); XtAddCallback(hScrollBar, XmNvalueChangedCallback, hScrollCB, (XtPointer)textD); } /* Update the display to reflect the contents of the buffer */ if (buffer != NULL) bufModifiedCB(0, buffer->length, 0, 0, NULL, textD); /* Decide if the horizontal scroll bar needs to be visible */ hideOrShowHScrollBar(textD); return textD; } /* ** Free a text display and release its associated memory. Note, the text ** BUFFER that the text display displays is a separate entity and is not ** freed, nor are the style buffer or style table. */ void TextDFree(textDisp *textD) { BufRemoveModifyCB(textD->buffer, bufModifiedCB, textD); BufRemovePreDeleteCB(textD->buffer, bufPreDeleteCB, textD); releaseGC(textD->w, textD->gc); releaseGC(textD->w, textD->selectGC); releaseGC(textD->w, textD->highlightGC); releaseGC(textD->w, textD->selectBGGC); releaseGC(textD->w, textD->highlightBGGC); releaseGC(textD->w, textD->styleGC); releaseGC(textD->w, textD->lineNumGC); XtFree((char *)textD->lineStarts); while (TextDPopGraphicExposeQueueEntry(textD)) { } XtFree((char *)textD->bgClassPixel); XtFree((char *)textD->bgClass); XtFree((char *)textD); } /* ** Attach a text buffer to display, replacing the current buffer (if any) */ void TextDSetBuffer(textDisp *textD, textBuffer *buffer) { /* If the text display is already displaying a buffer, clear it off of the display and remove our callback from it */ if (textD->buffer != NULL) { bufModifiedCB(0, 0, textD->buffer->length, 0, NULL, textD); BufRemoveModifyCB(textD->buffer, bufModifiedCB, textD); BufRemovePreDeleteCB(textD->buffer, bufPreDeleteCB, textD); } /* Add the buffer to the display, and attach a callback to the buffer for receiving modification information when the buffer contents change */ textD->buffer = buffer; BufAddModifyCB(buffer, bufModifiedCB, textD); BufAddPreDeleteCB(buffer, bufPreDeleteCB, textD); /* Update the display */ bufModifiedCB(0, buffer->length, 0, 0, NULL, textD); } /* ** Attach (or remove) highlight information in text display and redisplay. ** Highlighting information consists of a style buffer which parallels the ** normal text buffer, but codes font and color information for the display; ** a style table which translates style buffer codes (indexed by buffer ** character - 65 (ASCII code for 'A')) into fonts and colors; and a callback ** mechanism for as-needed highlighting, triggered by a style buffer entry of ** "unfinishedStyle". Style buffer can trigger additional redisplay during ** a normal buffer modification if the buffer contains a primary selection ** (see extendRangeForStyleMods for more information on this protocol). ** ** Style buffers, tables and their associated memory are managed by the caller. */ void TextDAttachHighlightData(textDisp *textD, textBuffer *styleBuffer, styleTableEntry *styleTable, int nStyles, char unfinishedStyle, unfinishedStyleCBProc unfinishedHighlightCB, void *cbArg) { textD->styleBuffer = styleBuffer; textD->styleTable = styleTable; textD->nStyles = nStyles; textD->unfinishedStyle = unfinishedStyle; textD->unfinishedHighlightCB = unfinishedHighlightCB; textD->highlightCBArg = cbArg; /* Call TextDSetFont to combine font information from style table and primary font, adjust font-related parameters, and then redisplay */ TextDSetFont(textD, textD->fontStruct); } /* Change the (non syntax-highlit) colors */ void TextDSetColors(textDisp *textD, Pixel textFgP, Pixel textBgP, Pixel selectFgP, Pixel selectBgP, Pixel hiliteFgP, Pixel hiliteBgP, Pixel lineNoFgP, Pixel cursorFgP) { XGCValues values; Display *d = XtDisplay(textD->w); /* Update the stored pixels */ textD->fgPixel = textFgP; textD->bgPixel = textBgP; textD->selectFGPixel = selectFgP; textD->selectBGPixel = selectBgP; textD->highlightFGPixel = hiliteFgP; textD->highlightBGPixel = hiliteBgP; textD->lineNumFGPixel = lineNoFgP; textD->cursorFGPixel = cursorFgP; releaseGC(textD->w, textD->gc); releaseGC(textD->w, textD->selectGC); releaseGC(textD->w, textD->selectBGGC); releaseGC(textD->w, textD->highlightGC); releaseGC(textD->w, textD->highlightBGGC); releaseGC(textD->w, textD->lineNumGC); allocateFixedFontGCs(textD, textD->fontStruct, textBgP, textFgP, selectFgP, selectBgP, hiliteFgP, hiliteBgP, lineNoFgP); /* Change the cursor GC (the cursor GC is not shared). */ values.foreground = cursorFgP; XChangeGC( d, textD->cursorFGGC, GCForeground, &values ); /* Redisplay */ TextDRedisplayRect(textD, textD->left, textD->top, textD->width, textD->height); redrawLineNumbers(textD, True); } /* ** Change the (non highlight) font */ void TextDSetFont(textDisp *textD, XFontStruct *fontStruct) { Display *display = XtDisplay(textD->w); int i, maxAscent = fontStruct->ascent, maxDescent = fontStruct->descent; int width, height, fontWidth; Pixel bgPixel, fgPixel, selectFGPixel, selectBGPixel; Pixel highlightFGPixel, highlightBGPixel, lineNumFGPixel; XGCValues values; XFontStruct *styleFont; /* If font size changes, cursor will be redrawn in a new position */ blankCursorProtrusions(textD); /* If there is a (syntax highlighting) style table in use, find the new maximum font height for this text display */ for (i=0; inStyles; i++) { styleFont = textD->styleTable[i].font; if (styleFont != NULL && styleFont->ascent > maxAscent) maxAscent = styleFont->ascent; if (styleFont != NULL && styleFont->descent > maxDescent) maxDescent = styleFont->descent; } textD->ascent = maxAscent; textD->descent = maxDescent; /* If all of the current fonts are fixed and match in width, compute */ fontWidth = fontStruct->max_bounds.width; if (fontWidth != fontStruct->min_bounds.width) fontWidth = -1; else { for (i=0; inStyles; i++) { styleFont = textD->styleTable[i].font; if (styleFont != NULL && (styleFont->max_bounds.width != fontWidth || styleFont->max_bounds.width != styleFont->min_bounds.width)) fontWidth = -1; } } textD->fixedFontWidth = fontWidth; /* Don't let the height dip below one line, or bad things can happen */ if (textD->height < maxAscent + maxDescent) textD->height = maxAscent + maxDescent; /* Change the font. In most cases, this means re-allocating the affected GCs (they are shared with other widgets, and if the primary font changes, must be re-allocated to change it). Unfortunately, this requres recovering all of the colors from the existing GCs */ textD->fontStruct = fontStruct; XGetGCValues(display, textD->gc, GCForeground|GCBackground, &values); fgPixel = values.foreground; bgPixel = values.background; XGetGCValues(display, textD->selectGC, GCForeground|GCBackground, &values); selectFGPixel = values.foreground; selectBGPixel = values.background; XGetGCValues(display, textD->highlightGC,GCForeground|GCBackground,&values); highlightFGPixel = values.foreground; highlightBGPixel = values.background; XGetGCValues(display, textD->lineNumGC, GCForeground, &values); lineNumFGPixel = values.foreground; releaseGC(textD->w, textD->gc); releaseGC(textD->w, textD->selectGC); releaseGC(textD->w, textD->highlightGC); releaseGC(textD->w, textD->selectBGGC); releaseGC(textD->w, textD->highlightBGGC); releaseGC(textD->w, textD->lineNumGC); allocateFixedFontGCs(textD, fontStruct, bgPixel, fgPixel, selectFGPixel, selectBGPixel, highlightFGPixel, highlightBGPixel, lineNumFGPixel); XSetFont(display, textD->styleGC, fontStruct->fid); /* Do a full resize to force recalculation of font related parameters */ width = textD->width; height = textD->height; textD->width = textD->height = 0; TextDResize(textD, width, height); /* if the shell window doesn't get resized, and the new fonts are of smaller sizes, sometime we get some residual text on the blank space at the bottom part of text area. Clear it here. */ clearRect(textD, textD->gc, textD->left, textD->top + textD->height - maxAscent - maxDescent, textD->width, maxAscent + maxDescent); /* Redisplay */ TextDRedisplayRect(textD, textD->left, textD->top, textD->width, textD->height); /* Clean up line number area in case spacing has changed */ redrawLineNumbers(textD, True); } int TextDMinFontWidth(textDisp *textD, Boolean considerStyles) { int fontWidth = textD->fontStruct->max_bounds.width; int i; if (considerStyles) { for (i = 0; i < textD->nStyles; ++i) { int thisWidth = (textD->styleTable[i].font)->min_bounds.width; if (thisWidth < fontWidth) { fontWidth = thisWidth; } } } return(fontWidth); } int TextDMaxFontWidth(textDisp *textD, Boolean considerStyles) { int fontWidth = textD->fontStruct->max_bounds.width; int i; if (considerStyles) { for (i = 0; i < textD->nStyles; ++i) { int thisWidth = (textD->styleTable[i].font)->max_bounds.width; if (thisWidth > fontWidth) { fontWidth = thisWidth; } } } return(fontWidth); } /* ** Change the size of the displayed text area */ void TextDResize(textDisp *textD, int width, int height) { int oldVisibleLines = textD->nVisibleLines; int canRedraw = XtWindow(textD->w) != 0; int newVisibleLines = height / (textD->ascent + textD->descent); int redrawAll = False; int oldWidth = textD->width; int exactHeight = height - height % (textD->ascent + textD->descent); textD->width = width; textD->height = height; /* In continuous wrap mode, a change in width affects the total number of lines in the buffer, and can leave the top line number incorrect, and the top character no longer pointing at a valid line start */ if (textD->continuousWrap && textD->wrapMargin==0 && width!=oldWidth) { int oldFirstChar = textD->firstChar; textD->nBufferLines = TextDCountLines(textD, 0, textD->buffer->length, True); textD->firstChar = TextDStartOfLine(textD, textD->firstChar); textD->topLineNum = TextDCountLines(textD, 0, textD->firstChar, True)+1; redrawAll = True; offsetAbsLineNum(textD, oldFirstChar); } /* reallocate and update the line starts array, which may have changed size and/or contents. (contents can change in continuous wrap mode when the width changes, even without a change in height) */ if (oldVisibleLines < newVisibleLines) { XtFree((char *)textD->lineStarts); textD->lineStarts = (int *)XtMalloc(sizeof(int) * newVisibleLines); } textD->nVisibleLines = newVisibleLines; calcLineStarts(textD, 0, newVisibleLines); calcLastChar(textD); /* if the window became shorter, there may be partially drawn text left at the bottom edge, which must be cleaned up */ if (canRedraw && oldVisibleLines>newVisibleLines && exactHeight!=height) XClearArea(XtDisplay(textD->w), XtWindow(textD->w), textD->left, textD->top + exactHeight, textD->width, height - exactHeight, False); /* if the window became taller, there may be an opportunity to display more text by scrolling down */ if (canRedraw && oldVisibleLines < newVisibleLines && textD->topLineNum + textD->nVisibleLines > textD->nBufferLines) setScroll(textD, max(1, textD->nBufferLines - textD->nVisibleLines + 2 + TEXT_OF_TEXTD(textD).cursorVPadding), textD->horizOffset, False, False); /* Update the scroll bar page increment size (as well as other scroll bar parameters. If updating the horizontal range caused scrolling, redraw */ updateVScrollBarRange(textD); if (updateHScrollBarRange(textD)) redrawAll = True; /* If a full redraw is needed */ if (redrawAll && canRedraw) TextDRedisplayRect(textD, textD->left, textD->top, textD->width, textD->height); /* Decide if the horizontal scroll bar needs to be visible */ hideOrShowHScrollBar(textD); /* Refresh the line number display to draw more line numbers, or erase extras */ redrawLineNumbers(textD, True); /* Redraw the calltip */ TextDRedrawCalltip(textD, 0); } /* ** Refresh a rectangle of the text display. left and top are in coordinates of ** the text drawing window */ void TextDRedisplayRect(textDisp *textD, int left, int top, int width, int height) { int fontHeight, firstLine, lastLine, line; /* find the line number range of the display */ fontHeight = textD->ascent + textD->descent; firstLine = (top - textD->top - fontHeight + 1) / fontHeight; lastLine = (top + height - textD->top) / fontHeight; /* If the graphics contexts are shared using XtAllocateGC, their clipping rectangles may have changed since the last use */ resetClipRectangles(textD); /* draw the lines of text */ for (line=firstLine; line<=lastLine; line++) redisplayLine(textD, line, left, left+width, 0, INT_MAX); /* draw the line numbers if exposed area includes them */ if (textD->lineNumWidth != 0 && left <= textD->lineNumLeft + textD->lineNumWidth) redrawLineNumbers(textD, False); } /* ** Refresh all of the text between buffer positions "start" and "end" ** not including the character at the position "end". ** If end points beyond the end of the buffer, refresh the whole display ** after pos, including blank lines which are not technically part of ** any range of characters. */ static void textDRedisplayRange(textDisp *textD, int start, int end) { int i, startLine, lastLine, startIndex, endIndex; /* If the range is outside of the displayed text, just return */ if (end < textD->firstChar || (start > textD->lastChar && !emptyLinesVisible(textD))) return; /* Clean up the starting and ending values */ if (start < 0) start = 0; if (start > textD->buffer->length) start = textD->buffer->length; if (end < 0) end = 0; if (end > textD->buffer->length) end = textD->buffer->length; /* Get the starting and ending lines */ if (start < textD->firstChar) { start = textD->firstChar; } if (!posToVisibleLineNum(textD, start, &startLine)) { startLine = textD->nVisibleLines - 1; } if (end >= textD->lastChar) { lastLine = textD->nVisibleLines - 1; } else { if (!posToVisibleLineNum(textD, end, &lastLine)) { /* shouldn't happen */ lastLine = textD->nVisibleLines - 1; } } /* Get the starting and ending positions within the lines */ startIndex = (textD->lineStarts[startLine] == -1) ? 0 : start - textD->lineStarts[startLine]; if (end >= textD->lastChar) { /* Request to redisplay beyond textD->lastChar, so tell redisplayLine() to display everything to infy. */ endIndex = INT_MAX; } else if (textD->lineStarts[lastLine] == -1) { /* Here, lastLine is determined by posToVisibleLineNum() (see if/else above) but deemed to be out of display according to textD->lineStarts. */ endIndex = 0; } else { endIndex = end - textD->lineStarts[lastLine]; } /* Reset the clipping rectangles for the drawing GCs which are shared using XtAllocateGC, and may have changed since the last use */ resetClipRectangles(textD); /* If the starting and ending lines are the same, redisplay the single line between "start" and "end" */ if (startLine == lastLine) { redisplayLine(textD, startLine, 0, INT_MAX, startIndex, endIndex); return; } /* Redisplay the first line from "start" */ redisplayLine(textD, startLine, 0, INT_MAX, startIndex, INT_MAX); /* Redisplay the lines in between at their full width */ for (i=startLine+1; i textD->topLineNum) && (topLineNum > (textD->nBufferLines + 2 - textD->nVisibleLines + vPadding))) topLineNum = max(textD->topLineNum, textD->nBufferLines + 2 - textD->nVisibleLines + vPadding); XtVaGetValues(textD->hScrollBar, XmNmaximum, &sliderMax, XmNsliderSize, &sliderSize, NULL); if (horizOffset < 0) horizOffset = 0; if (horizOffset > sliderMax - sliderSize) horizOffset = sliderMax - sliderSize; setScroll(textD, topLineNum, horizOffset, True, True); } /* ** Get the current scroll position for the text display, in terms of line ** number of the top line and horizontal pixel offset from the left margin */ void TextDGetScroll(textDisp *textD, int *topLineNum, int *horizOffset) { *topLineNum = textD->topLineNum; *horizOffset = textD->horizOffset; } /* ** Set the position of the text insertion cursor for text display "textD" */ void TextDSetInsertPosition(textDisp *textD, int newPos) { /* make sure new position is ok, do nothing if it hasn't changed */ if (newPos == textD->cursorPos) return; if (newPos < 0) newPos = 0; if (newPos > textD->buffer->length) newPos = textD->buffer->length; /* cursor movement cancels vertical cursor motion column */ textD->cursorPreferredCol = -1; /* erase the cursor at it's previous position */ TextDBlankCursor(textD); /* draw it at its new position */ textD->cursorPos = newPos; textD->cursorOn = True; textDRedisplayRange(textD, textD->cursorPos-1, textD->cursorPos + 1); } void TextDBlankCursor(textDisp *textD) { if (!textD->cursorOn) return; blankCursorProtrusions(textD); textD->cursorOn = False; textDRedisplayRange(textD, textD->cursorPos-1, textD->cursorPos+1); } void TextDUnblankCursor(textDisp *textD) { if (!textD->cursorOn) { textD->cursorOn = True; textDRedisplayRange(textD, textD->cursorPos-1, textD->cursorPos+1); } } void TextDSetCursorStyle(textDisp *textD, int style) { textD->cursorStyle = style; blankCursorProtrusions(textD); if (textD->cursorOn) { textDRedisplayRange(textD, textD->cursorPos-1, textD->cursorPos + 1); } } void TextDSetWrapMode(textDisp *textD, int wrap, int wrapMargin) { textD->wrapMargin = wrapMargin; textD->continuousWrap = wrap; /* wrapping can change change the total number of lines, re-count */ textD->nBufferLines = TextDCountLines(textD, 0, textD->buffer->length,True); /* changing wrap margins wrap or changing from wrapped mode to non-wrapped can leave the character at the top no longer at a line start, and/or change the line number */ textD->firstChar = TextDStartOfLine(textD, textD->firstChar); textD->topLineNum = TextDCountLines(textD, 0, textD->firstChar, True) + 1; resetAbsLineNum(textD); /* update the line starts array */ calcLineStarts(textD, 0, textD->nVisibleLines); calcLastChar(textD); /* Update the scroll bar page increment size (as well as other scroll bar parameters) */ updateVScrollBarRange(textD); updateHScrollBarRange(textD); /* Decide if the horizontal scroll bar needs to be visible */ hideOrShowHScrollBar(textD); /* Do a full redraw */ TextDRedisplayRect(textD, 0, textD->top, textD->width + textD->left, textD->height); } int TextDGetInsertPosition(textDisp *textD) { return textD->cursorPos; } /* ** Insert "text" at the current cursor location. This has the same ** effect as inserting the text into the buffer using BufInsert and ** then moving the insert position after the newly inserted text, except ** that it's optimized to do less redrawing. */ void TextDInsert(textDisp *textD, char *text) { int pos = textD->cursorPos; textD->cursorToHint = pos + strlen(text); BufInsert(textD->buffer, pos, text); textD->cursorToHint = NO_HINT; } /* ** Insert "text" (which must not contain newlines), overstriking the current ** cursor location. */ void TextDOverstrike(textDisp *textD, char *text) { int startPos = textD->cursorPos; textBuffer *buf = textD->buffer; int lineStart = BufStartOfLine(buf, startPos); int textLen = strlen(text); int i, p, endPos, indent, startIndent, endIndent; char *c, ch, *paddedText = NULL; /* determine how many displayed character positions are covered */ startIndent = BufCountDispChars(textD->buffer, lineStart, startPos); indent = startIndent; for (c=text; *c!='\0'; c++) indent += BufCharWidth(*c, indent, buf->tabDist, buf->nullSubsChar); endIndent = indent; /* find which characters to remove, and if necessary generate additional padding to make up for removed control characters at the end */ indent=startIndent; for (p=startPos; ; p++) { if (p == buf->length) break; ch = BufGetCharacter(buf, p); if (ch == '\n') break; indent += BufCharWidth(ch, indent, buf->tabDist, buf->nullSubsChar); if (indent == endIndent) { p++; break; } else if (indent > endIndent) { if (ch != '\t') { p++; paddedText = XtMalloc(textLen + MAX_EXP_CHAR_LEN + 1); strcpy(paddedText, text); for (i=0; icursorToHint = startPos + textLen; BufReplace(buf, startPos, endPos, paddedText == NULL ? text : paddedText); textD->cursorToHint = NO_HINT; XtFree(paddedText); } /* ** Translate window coordinates to the nearest text cursor position. */ int TextDXYToPosition(textDisp *textD, int x, int y) { return xyToPos(textD, x, y, CURSOR_POS); } /* ** Translate window coordinates to the nearest character cell. */ int TextDXYToCharPos(textDisp *textD, int x, int y) { return xyToPos(textD, x, y, CHARACTER_POS); } /* ** Translate window coordinates to the nearest row and column number for ** positioning the cursor. This, of course, makes no sense when the font ** is proportional, since there are no absolute columns. */ void TextDXYToUnconstrainedPosition(textDisp *textD, int x, int y, int *row, int *column) { xyToUnconstrainedPos(textD, x, y, row, column, CURSOR_POS); } /* ** Translate line and column to the nearest row and column number for ** positioning the cursor. This, of course, makes no sense when the font ** is proportional, since there are no absolute columns. */ int TextDLineAndColToPos(textDisp *textD, int lineNum, int column) { int i, lineEnd, charIndex, outIndex; int lineStart=0, charLen=0; char *lineStr, expandedChar[MAX_EXP_CHAR_LEN]; /* Count lines */ if (lineNum < 1) lineNum = 1; lineEnd = -1; for (i=1; i<=lineNum && lineEndbuffer->length; i++) { lineStart = lineEnd + 1; lineEnd = BufEndOfLine(textD->buffer, lineStart); } /* If line is beyond end of buffer, position at last character in buffer */ if ( lineNum >= i ) { return lineEnd; } /* Start character index at zero */ charIndex=0; /* Only have to count columns if column isn't zero (or negative) */ if (column > 0) { /* Count columns, expanding each character */ lineStr = BufGetRange(textD->buffer, lineStart, lineEnd); outIndex = 0; for(i=lineStart; ibuffer->tabDist, textD->buffer->nullSubsChar); if ( outIndex+charLen >= column ) break; outIndex+=charLen; } /* If the column is in the middle of an expanded character, put cursor * in front of character if in first half of character, and behind * character if in last half of character */ if (column >= outIndex + ( charLen / 2 )) charIndex++; /* If we are beyond the end of the line, back up one space */ if ((i>=lineEnd)&&(charIndex>0)) charIndex--; } /* Position is the start of the line plus the index into line buffer */ return lineStart + charIndex; } /* ** Translate a buffer text position to the XY location where the center ** of the cursor would be positioned to point to that character. Returns ** False if the position is not displayed because it is VERTICALLY out ** of view. If the position is horizontally out of view, returns the ** x coordinate where the position would be if it were visible. */ int TextDPositionToXY(textDisp *textD, int pos, int *x, int *y) { int charIndex, lineStartPos, fontHeight, lineLen; int visLineNum, charLen, outIndex, xStep, charStyle; char *lineStr, expandedChar[MAX_EXP_CHAR_LEN]; /* If position is not displayed, return false */ if (pos < textD->firstChar || (pos > textD->lastChar && !emptyLinesVisible(textD))) return False; /* Calculate y coordinate */ if (!posToVisibleLineNum(textD, pos, &visLineNum)) return False; fontHeight = textD->ascent + textD->descent; *y = textD->top + visLineNum*fontHeight + fontHeight/2; /* Get the text, length, and buffer position of the line. If the position is beyond the end of the buffer and should be at the first position on the first empty line, don't try to get or scan the text */ lineStartPos = textD->lineStarts[visLineNum]; if (lineStartPos == -1) { *x = textD->left - textD->horizOffset; return True; } lineLen = visLineLength(textD, visLineNum); lineStr = BufGetRange(textD->buffer, lineStartPos, lineStartPos + lineLen); /* Step through character positions from the beginning of the line to "pos" to calculate the x coordinate */ xStep = textD->left - textD->horizOffset; outIndex = 0; for(charIndex=0; charIndexbuffer->tabDist, textD->buffer->nullSubsChar); charStyle = styleOfPos(textD, lineStartPos, lineLen, charIndex, outIndex, lineStr[charIndex]); xStep += stringWidth(textD, expandedChar, charLen, charStyle); outIndex += charLen; } *x = xStep; XtFree(lineStr); return True; } /* ** If the text widget is maintaining a line number count appropriate to "pos" ** return the line and column numbers of pos, otherwise return False. If ** continuous wrap mode is on, returns the absolute line number (as opposed to ** the wrapped line number which is used for scrolling). THIS ROUTINE ONLY ** WORKS FOR DISPLAYED LINES AND, IN CONTINUOUS WRAP MODE, ONLY WHEN THE ** ABSOLUTE LINE NUMBER IS BEING MAINTAINED. Otherwise, it returns False. */ int TextDPosToLineAndCol(textDisp *textD, int pos, int *lineNum, int *column) { textBuffer *buf = textD->buffer; /* In continuous wrap mode, the absolute (non-wrapped) line count is maintained separately, as needed. Only return it if we're actually keeping track of it and pos is in the displayed text */ if (textD->continuousWrap) { if (!maintainingAbsTopLineNum(textD) || pos < textD->firstChar || pos > textD->lastChar) return False; *lineNum = textD->absTopLineNum + BufCountLines(buf, textD->firstChar, pos); *column = BufCountDispChars(buf, BufStartOfLine(buf, pos), pos); return True; } /* Only return the data if pos is within the displayed text */ if (!posToVisibleLineNum(textD, pos, lineNum)) return False; *column = BufCountDispChars(buf, textD->lineStarts[*lineNum], pos); *lineNum += textD->topLineNum; return True; } /* ** Return True if position (x, y) is inside of the primary selection */ int TextDInSelection(textDisp *textD, int x, int y) { int row, column, pos = xyToPos(textD, x, y, CHARACTER_POS); textBuffer *buf = textD->buffer; xyToUnconstrainedPos(textD, x, y, &row, &column, CHARACTER_POS); if (rangeTouchesRectSel(&buf->primary, textD->firstChar, textD->lastChar)) column = TextDOffsetWrappedColumn(textD, row, column); return inSelection(&buf->primary, pos, BufStartOfLine(buf, pos), column); } /* ** Correct a column number based on an unconstrained position (as returned by ** TextDXYToUnconstrainedPosition) to be relative to the last actual newline ** in the buffer before the row and column position given, rather than the ** last line start created by line wrapping. This is an adapter ** for rectangular selections and code written before continuous wrap mode, ** which thinks that the unconstrained column is the number of characters ** from the last newline. Obviously this is time consuming, because it ** invloves character re-counting. */ int TextDOffsetWrappedColumn(textDisp *textD, int row, int column) { int lineStart, dispLineStart; if (!textD->continuousWrap || row < 0 || row > textD->nVisibleLines) return column; dispLineStart = textD->lineStarts[row]; if (dispLineStart == -1) return column; lineStart = BufStartOfLine(textD->buffer, dispLineStart); return column + BufCountDispChars(textD->buffer, lineStart, dispLineStart); } /* ** Correct a row number from an unconstrained position (as returned by ** TextDXYToUnconstrainedPosition) to a straight number of newlines from the ** top line of the display. Because rectangular selections are based on ** newlines, rather than display wrapping, and anywhere a rectangular selection ** needs a row, it needs it in terms of un-wrapped lines. */ int TextDOffsetWrappedRow(textDisp *textD, int row) { if (!textD->continuousWrap || row < 0 || row > textD->nVisibleLines) return row; return BufCountLines(textD->buffer, textD->firstChar, textD->lineStarts[row]); } /* ** Scroll the display to bring insertion cursor into view. ** ** Note: it would be nice to be able to do this without counting lines twice ** (setScroll counts them too) and/or to count from the most efficient ** starting point, but the efficiency of this routine is not as important to ** the overall performance of the text display. */ void TextDMakeInsertPosVisible(textDisp *textD) { int hOffset, topLine, x, y; int cursorPos = textD->cursorPos; int linesFromTop = 0, do_padding = 1; int cursorVPadding = (int)TEXT_OF_TEXTD(textD).cursorVPadding; hOffset = textD->horizOffset; topLine = textD->topLineNum; /* Don't do padding if this is a mouse operation */ do_padding = ((TEXT_OF_TEXTD(textD).dragState == NOT_CLICKED) && (cursorVPadding > 0)); /* Find the new top line number */ if (cursorPos < textD->firstChar) { topLine -= TextDCountLines(textD, cursorPos, textD->firstChar, False); /* linesFromTop = 0; */ } else if (cursorPos > textD->lastChar && !emptyLinesVisible(textD)) { topLine += TextDCountLines(textD, textD->lastChar - (wrapUsesCharacter(textD, textD->lastChar) ? 0 : 1), cursorPos, False); linesFromTop = textD->nVisibleLines-1; } else if (cursorPos == textD->lastChar && !emptyLinesVisible(textD) && !wrapUsesCharacter(textD, textD->lastChar)) { topLine++; linesFromTop = textD->nVisibleLines-1; } else { /* Avoid extra counting if cursorVPadding is disabled */ if (do_padding) linesFromTop = TextDCountLines(textD, textD->firstChar, cursorPos, True); } if (topLine < 1) { fprintf(stderr, "nedit: internal consistency check tl1 failed\n"); topLine = 1; } if (do_padding) { /* Keep the cursor away from the top or bottom of screen. */ if (textD->nVisibleLines <= 2*(int)cursorVPadding) { topLine += (linesFromTop - textD->nVisibleLines/2); topLine = max(topLine, 1); } else if (linesFromTop < (int)cursorVPadding) { topLine -= (cursorVPadding - linesFromTop); topLine = max(topLine, 1); } else if (linesFromTop > textD->nVisibleLines-(int)cursorVPadding-1) { topLine += (linesFromTop - (textD->nVisibleLines-cursorVPadding-1)); } } /* Find the new setting for horizontal offset (this is a bit ungraceful). If the line is visible, just use TextDPositionToXY to get the position to scroll to, otherwise, do the vertical scrolling first, then the horizontal */ if (!TextDPositionToXY(textD, cursorPos, &x, &y)) { setScroll(textD, topLine, hOffset, True, True); if (!TextDPositionToXY(textD, cursorPos, &x, &y)) return; /* Give up, it's not worth it (but why does it fail?) */ } if (x > textD->left + textD->width) hOffset += x - (textD->left + textD->width); else if (x < textD->left) hOffset += x - textD->left; /* Do the scroll */ setScroll(textD, topLine, hOffset, True, True); } /* ** Return the current preferred column along with the current ** visible line index (-1 if not visible) and the lineStartPos ** of the current insert position. */ int TextDPreferredColumn(textDisp *textD, int *visLineNum, int *lineStartPos) { int column; /* Find the position of the start of the line. Use the line starts array if possible, to avoid unbounded line-counting in continuous wrap mode */ if (posToVisibleLineNum(textD, textD->cursorPos, visLineNum)) { *lineStartPos = textD->lineStarts[*visLineNum]; } else { *lineStartPos = TextDStartOfLine(textD, textD->cursorPos); *visLineNum = -1; } /* Decide what column to move to, if there's a preferred column use that */ column = (textD->cursorPreferredCol >= 0) ? textD->cursorPreferredCol : BufCountDispChars(textD->buffer, *lineStartPos, textD->cursorPos); return(column); } /* ** Return the insert position of the requested column given ** the lineStartPos. */ int TextDPosOfPreferredCol(textDisp *textD, int column, int lineStartPos) { int newPos; newPos = BufCountForwardDispChars(textD->buffer, lineStartPos, column); if (textD->continuousWrap) { newPos = min(newPos, TextDEndOfLine(textD, lineStartPos, True)); } return(newPos); } /* ** Cursor movement functions */ int TextDMoveRight(textDisp *textD) { if (textD->cursorPos >= textD->buffer->length) return False; TextDSetInsertPosition(textD, textD->cursorPos + 1); return True; } int TextDMoveLeft(textDisp *textD) { if (textD->cursorPos <= 0) return False; TextDSetInsertPosition(textD, textD->cursorPos - 1); return True; } int TextDMoveUp(textDisp *textD, int absolute) { int lineStartPos, column, prevLineStartPos, newPos, visLineNum; /* Find the position of the start of the line. Use the line starts array if possible, to avoid unbounded line-counting in continuous wrap mode */ if (absolute) { lineStartPos = BufStartOfLine(textD->buffer, textD->cursorPos); visLineNum = -1; } else if (posToVisibleLineNum(textD, textD->cursorPos, &visLineNum)) lineStartPos = textD->lineStarts[visLineNum]; else { lineStartPos = TextDStartOfLine(textD, textD->cursorPos); visLineNum = -1; } if (lineStartPos == 0) return False; /* Decide what column to move to, if there's a preferred column use that */ column = textD->cursorPreferredCol >= 0 ? textD->cursorPreferredCol : BufCountDispChars(textD->buffer, lineStartPos, textD->cursorPos); /* count forward from the start of the previous line to reach the column */ if (absolute) { prevLineStartPos = BufCountBackwardNLines(textD->buffer, lineStartPos, 1); } else if (visLineNum != -1 && visLineNum != 0) { prevLineStartPos = textD->lineStarts[visLineNum-1]; } else { prevLineStartPos = TextDCountBackwardNLines(textD, lineStartPos, 1); } newPos = BufCountForwardDispChars(textD->buffer, prevLineStartPos, column); if (textD->continuousWrap && !absolute) newPos = min(newPos, TextDEndOfLine(textD, prevLineStartPos, True)); /* move the cursor */ TextDSetInsertPosition(textD, newPos); /* if a preferred column wasn't aleady established, establish it */ textD->cursorPreferredCol = column; return True; } int TextDMoveDown(textDisp *textD, int absolute) { int lineStartPos, column, nextLineStartPos, newPos, visLineNum; if (textD->cursorPos == textD->buffer->length) { return False; } if (absolute) { lineStartPos = BufStartOfLine(textD->buffer, textD->cursorPos); visLineNum = -1; } else if (posToVisibleLineNum(textD, textD->cursorPos, &visLineNum)) { lineStartPos = textD->lineStarts[visLineNum]; } else { lineStartPos = TextDStartOfLine(textD, textD->cursorPos); visLineNum = -1; } column = textD->cursorPreferredCol >= 0 ? textD->cursorPreferredCol : BufCountDispChars(textD->buffer, lineStartPos, textD->cursorPos); if (absolute) nextLineStartPos = BufCountForwardNLines(textD->buffer, lineStartPos, 1); else nextLineStartPos = TextDCountForwardNLines(textD, lineStartPos, 1, True); newPos = BufCountForwardDispChars(textD->buffer, nextLineStartPos, column); if (textD->continuousWrap && !absolute) { newPos = min(newPos, TextDEndOfLine(textD, nextLineStartPos, True)); } TextDSetInsertPosition(textD, newPos); textD->cursorPreferredCol = column; return True; } /* ** Same as BufCountLines, but takes in to account wrapping if wrapping is ** turned on. If the caller knows that startPos is at a line start, it ** can pass "startPosIsLineStart" as True to make the call more efficient ** by avoiding the additional step of scanning back to the last newline. */ int TextDCountLines(textDisp *textD, int startPos, int endPos, int startPosIsLineStart) { int retLines, retPos, retLineStart, retLineEnd; /* If we're not wrapping use simple (and more efficient) BufCountLines */ if (!textD->continuousWrap) return BufCountLines(textD->buffer, startPos, endPos); wrappedLineCounter(textD, textD->buffer, startPos, endPos, INT_MAX, startPosIsLineStart, 0, &retPos, &retLines, &retLineStart, &retLineEnd); return retLines; } /* ** Same as BufCountForwardNLines, but takes in to account line breaks when ** wrapping is turned on. If the caller knows that startPos is at a line start, ** it can pass "startPosIsLineStart" as True to make the call more efficient ** by avoiding the additional step of scanning back to the last newline. */ int TextDCountForwardNLines(const textDisp* textD, const int startPos, const unsigned nLines, const Boolean startPosIsLineStart) { int retLines, retPos, retLineStart, retLineEnd; /* if we're not wrapping use more efficient BufCountForwardNLines */ if (!textD->continuousWrap) return BufCountForwardNLines(textD->buffer, startPos, nLines); /* wrappedLineCounter can't handle the 0 lines case */ if (nLines == 0) return startPos; /* use the common line counting routine to count forward */ wrappedLineCounter(textD, textD->buffer, startPos, textD->buffer->length, nLines, startPosIsLineStart, 0, &retPos, &retLines, &retLineStart, &retLineEnd); return retPos; } /* ** Same as BufEndOfLine, but takes in to account line breaks when wrapping ** is turned on. If the caller knows that startPos is at a line start, it ** can pass "startPosIsLineStart" as True to make the call more efficient ** by avoiding the additional step of scanning back to the last newline. ** ** Note that the definition of the end of a line is less clear when continuous ** wrap is on. With continuous wrap off, it's just a pointer to the newline ** that ends the line. When it's on, it's the character beyond the last ** DISPLAYABLE character on the line, where a whitespace character which has ** been "converted" to a newline for wrapping is not considered displayable. ** Also note that, a line can be wrapped at a non-whitespace character if the ** line had no whitespace. In this case, this routine returns a pointer to ** the start of the next line. This is also consistent with the model used by ** visLineLength. */ int TextDEndOfLine(const textDisp* textD, const int pos, const Boolean startPosIsLineStart) { int retLines, retPos, retLineStart, retLineEnd; /* If we're not wrapping use more efficient BufEndOfLine */ if (!textD->continuousWrap) return BufEndOfLine(textD->buffer, pos); if (pos == textD->buffer->length) return pos; wrappedLineCounter(textD, textD->buffer, pos, textD->buffer->length, 1, startPosIsLineStart, 0, &retPos, &retLines, &retLineStart, &retLineEnd); return retLineEnd; } /* ** Same as BufStartOfLine, but returns the character after last wrap point ** rather than the last newline. */ int TextDStartOfLine(const textDisp* textD, const int pos) { int retLines, retPos, retLineStart, retLineEnd; /* If we're not wrapping, use the more efficient BufStartOfLine */ if (!textD->continuousWrap) return BufStartOfLine(textD->buffer, pos); wrappedLineCounter(textD, textD->buffer, BufStartOfLine(textD->buffer, pos), pos, INT_MAX, True, 0, &retPos, &retLines, &retLineStart, &retLineEnd); return retLineStart; } /* ** Same as BufCountBackwardNLines, but takes in to account line breaks when ** wrapping is turned on. */ int TextDCountBackwardNLines(textDisp *textD, int startPos, int nLines) { textBuffer *buf = textD->buffer; int pos, lineStart, retLines, retPos, retLineStart, retLineEnd; /* If we're not wrapping, use the more efficient BufCountBackwardNLines */ if (!textD->continuousWrap) return BufCountBackwardNLines(textD->buffer, startPos, nLines); pos = startPos; while (True) { lineStart = BufStartOfLine(buf, pos); wrappedLineCounter(textD, textD->buffer, lineStart, pos, INT_MAX, True, 0, &retPos, &retLines, &retLineStart, &retLineEnd); if (retLines > nLines) return TextDCountForwardNLines(textD, lineStart, retLines-nLines, True); nLines -= retLines; pos = lineStart - 1; if (pos < 0) return 0; nLines -= 1; } } /* ** Callback attached to the text buffer to receive delete information before ** the modifications are actually made. */ static void bufPreDeleteCB(int pos, int nDeleted, void *cbArg) { textDisp *textD = (textDisp *)cbArg; if (textD->continuousWrap && (textD->fixedFontWidth == -1 || textD->modifyingTabDist)) /* Note: we must perform this measurement, even if there is not a single character deleted; the number of "deleted" lines is the number of visual lines spanned by the real line in which the modification takes place. Also, a modification of the tab distance requires the same kind of calculations in advance, even if the font width is "fixed", because when the width of the tab characters changes, the layout of the text may be completely different. */ measureDeletedLines(textD, pos, nDeleted); else textD->suppressResync = 0; /* Probably not needed, but just in case */ } /* ** Callback attached to the text buffer to receive modification information */ static void bufModifiedCB(int pos, int nInserted, int nDeleted, int nRestyled, const char *deletedText, void *cbArg) { int linesInserted, linesDeleted, startDispPos, endDispPos; textDisp *textD = (textDisp *)cbArg; textBuffer *buf = textD->buffer; int oldFirstChar = textD->firstChar; int scrolled, origCursorPos = textD->cursorPos; int wrapModStart, wrapModEnd; /* buffer modification cancels vertical cursor motion column */ if (nInserted != 0 || nDeleted != 0) textD->cursorPreferredCol = -1; /* Count the number of lines inserted and deleted, and in the case of continuous wrap mode, how much has changed */ if (textD->continuousWrap) { findWrapRange(textD, deletedText, pos, nInserted, nDeleted, &wrapModStart, &wrapModEnd, &linesInserted, &linesDeleted); } else { linesInserted = nInserted == 0 ? 0 : BufCountLines(buf, pos, pos + nInserted); linesDeleted = nDeleted == 0 ? 0 : countLines(deletedText); } /* Update the line starts and topLineNum */ if (nInserted != 0 || nDeleted != 0) { if (textD->continuousWrap) { updateLineStarts(textD, wrapModStart, wrapModEnd-wrapModStart, nDeleted + pos-wrapModStart + (wrapModEnd-(pos+nInserted)), linesInserted, linesDeleted, &scrolled); } else { updateLineStarts(textD, pos, nInserted, nDeleted, linesInserted, linesDeleted, &scrolled); } } else scrolled = False; /* If we're counting non-wrapped lines as well, maintain the absolute (non-wrapped) line number of the text displayed */ if (maintainingAbsTopLineNum(textD) && (nInserted != 0 || nDeleted != 0)) { if (pos + nDeleted < oldFirstChar) textD->absTopLineNum += BufCountLines(buf, pos, pos + nInserted) - countLines(deletedText); else if (pos < oldFirstChar) resetAbsLineNum(textD); } /* Update the line count for the whole buffer */ textD->nBufferLines += linesInserted - linesDeleted; /* Update the scroll bar ranges (and value if the value changed). Note that updating the horizontal scroll bar range requires scanning the entire displayed text, however, it doesn't seem to hurt performance much. Note also, that the horizontal scroll bar update routine is allowed to re-adjust horizOffset if there is blank space to the right of all lines of text. */ updateVScrollBarRange(textD); scrolled |= updateHScrollBarRange(textD); /* Update the cursor position */ if (textD->cursorToHint != NO_HINT) { textD->cursorPos = textD->cursorToHint; textD->cursorToHint = NO_HINT; } else if (textD->cursorPos > pos) { if (textD->cursorPos < pos + nDeleted) textD->cursorPos = pos; else textD->cursorPos += nInserted - nDeleted; } /* If the changes caused scrolling, re-paint everything and we're done. */ if (scrolled) { blankCursorProtrusions(textD); TextDRedisplayRect(textD, 0, textD->top, textD->width + textD->left, textD->height); if (textD->styleBuffer) {/* See comments in extendRangeForStyleMods */ textD->styleBuffer->primary.selected = False; textD->styleBuffer->primary.zeroWidth = False; } return; } /* If the changes didn't cause scrolling, decide the range of characters that need to be re-painted. Also if the cursor position moved, be sure that the redisplay range covers the old cursor position so the old cursor gets erased, and erase the bits of the cursor which extend beyond the left and right edges of the text. */ startDispPos = textD->continuousWrap ? wrapModStart : pos; if (origCursorPos == startDispPos && textD->cursorPos != startDispPos) startDispPos = min(startDispPos, origCursorPos-1); if (linesInserted == linesDeleted) { if (nInserted == 0 && nDeleted == 0) endDispPos = pos + nRestyled; else { endDispPos = textD->continuousWrap ? wrapModEnd : BufEndOfLine(buf, pos + nInserted) + 1; if (origCursorPos >= startDispPos && (origCursorPos <= endDispPos || endDispPos == buf->length)) blankCursorProtrusions(textD); } /* If more than one line is inserted/deleted, a line break may have been inserted or removed in between, and the line numbers may have changed. If only one line is altered, line numbers cannot be affected (the insertion or removal of a line break always results in at least two lines being redrawn). */ if (linesInserted > 1) redrawLineNumbers(textD, False); } else { /* linesInserted != linesDeleted */ endDispPos = textD->lastChar + 1; if (origCursorPos >= pos) blankCursorProtrusions(textD); redrawLineNumbers(textD, False); } /* If there is a style buffer, check if the modification caused additional changes that need to be redisplayed. (Redisplaying separately would cause double-redraw on almost every modification involving styled text). Extend the redraw range to incorporate style changes */ if (textD->styleBuffer) extendRangeForStyleMods(textD, &startDispPos, &endDispPos); /* Redisplay computed range */ textDRedisplayRange(textD, startDispPos, endDispPos); } /* ** In continuous wrap mode, internal line numbers are calculated after ** wrapping. A separate non-wrapped line count is maintained when line ** numbering is turned on. There is some performance cost to maintaining this ** line count, so normally absolute line numbers are not tracked if line ** numbering is off. This routine allows callers to specify that they still ** want this line count maintained (for use via TextDPosToLineAndCol). ** More specifically, this allows the line number reported in the statistics ** line to be calibrated in absolute lines, rather than post-wrapped lines. */ void TextDMaintainAbsLineNum(textDisp *textD, int state) { textD->needAbsTopLineNum = state; resetAbsLineNum(textD); } /* ** Returns the absolute (non-wrapped) line number of the first line displayed. ** Returns 0 if the absolute top line number is not being maintained. */ static int getAbsTopLineNum(textDisp *textD) { if (!textD->continuousWrap) return textD->topLineNum; if (maintainingAbsTopLineNum(textD)) return textD->absTopLineNum; return 0; } /* ** Re-calculate absolute top line number for a change in scroll position. */ static void offsetAbsLineNum(textDisp *textD, int oldFirstChar) { if (maintainingAbsTopLineNum(textD)) { if (textD->firstChar < oldFirstChar) textD->absTopLineNum -= BufCountLines(textD->buffer, textD->firstChar, oldFirstChar); else textD->absTopLineNum += BufCountLines(textD->buffer, oldFirstChar, textD->firstChar); } } /* ** Return true if a separate absolute top line number is being maintained ** (for displaying line numbers or showing in the statistics line). */ static int maintainingAbsTopLineNum(textDisp *textD) { return textD->continuousWrap && (textD->lineNumWidth != 0 || textD->needAbsTopLineNum); } /* ** Count lines from the beginning of the buffer to reestablish the ** absolute (non-wrapped) top line number. If mode is not continuous wrap, ** or the number is not being maintained, does nothing. */ static void resetAbsLineNum(textDisp *textD) { textD->absTopLineNum = 1; offsetAbsLineNum(textD, 0); } /* ** Find the line number of position "pos" relative to the first line of ** displayed text. Returns False if the line is not displayed. */ static int posToVisibleLineNum(textDisp *textD, int pos, int *lineNum) { int i; if (pos < textD->firstChar) return False; if (pos > textD->lastChar) { if (emptyLinesVisible(textD)) { if (textD->lastChar < textD->buffer->length) { if (!posToVisibleLineNum(textD, textD->lastChar, lineNum)) { fprintf(stderr, "nedit: Consistency check ptvl failed\n"); return False; } return ++(*lineNum) <= textD->nVisibleLines-1; } else { posToVisibleLineNum(textD, max(textD->lastChar-1, 0), lineNum); return True; } } return False; } for (i=textD->nVisibleLines-1; i>=0; i--) { if (textD->lineStarts[i] != -1 && pos >= textD->lineStarts[i]) { *lineNum = i; return True; } } return False; } /* ** Redisplay the text on a single line represented by "visLineNum" (the ** number of lines down from the top of the display), limited by ** "leftClip" and "rightClip" window coordinates and "leftCharIndex" and ** "rightCharIndex" character positions (not including the character at ** position "rightCharIndex"). ** ** The cursor is also drawn if it appears on the line. */ static void redisplayLine(textDisp *textD, int visLineNum, int leftClip, int rightClip, int leftCharIndex, int rightCharIndex) { textBuffer *buf = textD->buffer; int i, x, y, startX, charIndex, lineStartPos, lineLen, fontHeight; int stdCharWidth, charWidth, startIndex, charStyle, style; int charLen, outStartIndex, outIndex, cursorX = 0, hasCursor = False; int dispIndexOffset, cursorPos = textD->cursorPos, y_orig; char expandedChar[MAX_EXP_CHAR_LEN], outStr[MAX_DISP_LINE_LEN]; char *lineStr, *outPtr; char baseChar; /* If line is not displayed, skip it */ if (visLineNum < 0 || visLineNum >= textD->nVisibleLines) return; /* Shrink the clipping range to the active display area */ leftClip = max(textD->left, leftClip); rightClip = min(rightClip, textD->left + textD->width); if (leftClip > rightClip) { return; } /* Calculate y coordinate of the string to draw */ fontHeight = textD->ascent + textD->descent; y = textD->top + visLineNum * fontHeight; /* Get the text, length, and buffer position of the line to display */ lineStartPos = textD->lineStarts[visLineNum]; if (lineStartPos == -1) { lineLen = 0; lineStr = NULL; } else { lineLen = visLineLength(textD, visLineNum); lineStr = BufGetRange(buf, lineStartPos, lineStartPos + lineLen); } /* Space beyond the end of the line is still counted in units of characters of a standardized character width (this is done mostly because style changes based on character position can still occur in this region due to rectangular selections). stdCharWidth must be non-zero to prevent a potential infinite loop if x does not advance */ stdCharWidth = textD->fontStruct->max_bounds.width; if (stdCharWidth <= 0) { fprintf(stderr, "nedit: Internal Error, bad font measurement\n"); XtFree(lineStr); return; } /* Rectangular selections are based on "real" line starts (after a newline or start of buffer). Calculate the difference between the last newline position and the line start we're using. Since scanning back to find a newline is expensive, only do so if there's actually a rectangular selection which needs it */ if (textD->continuousWrap && (rangeTouchesRectSel(&buf->primary, lineStartPos, lineStartPos + lineLen) || rangeTouchesRectSel( &buf->secondary, lineStartPos, lineStartPos + lineLen) || rangeTouchesRectSel(&buf->highlight, lineStartPos, lineStartPos + lineLen))) { dispIndexOffset = BufCountDispChars(buf, BufStartOfLine(buf, lineStartPos), lineStartPos); } else dispIndexOffset = 0; /* Step through character positions from the beginning of the line (even if that's off the left edge of the displayed area) to find the first character position that's not clipped, and the x coordinate for drawing that character */ x = textD->left - textD->horizOffset; outIndex = 0; for (charIndex = 0; ; charIndex++) { baseChar = '\0'; charLen = charIndex >= lineLen ? 1 : BufExpandCharacter(baseChar = lineStr[charIndex], outIndex, expandedChar, buf->tabDist, buf->nullSubsChar); style = styleOfPos(textD, lineStartPos, lineLen, charIndex, outIndex + dispIndexOffset, baseChar); charWidth = charIndex >= lineLen ? stdCharWidth : stringWidth(textD, expandedChar, charLen, style); if (x + charWidth >= leftClip && charIndex >= leftCharIndex) { startIndex = charIndex; outStartIndex = outIndex; startX = x; break; } x += charWidth; outIndex += charLen; } /* Scan character positions from the beginning of the clipping range, and draw parts whenever the style changes (also note if the cursor is on this line, and where it should be drawn to take advantage of the x position which we've gone to so much trouble to calculate) */ outPtr = outStr; outIndex = outStartIndex; x = startX; for (charIndex = startIndex; charIndex < rightCharIndex; charIndex++) { if (lineStartPos+charIndex == cursorPos) { if (charIndex < lineLen || (charIndex == lineLen && cursorPos >= buf->length)) { hasCursor = True; cursorX = x - 1; } else if (charIndex == lineLen) { if (wrapUsesCharacter(textD, cursorPos)) { hasCursor = True; cursorX = x - 1; } } } baseChar = '\0'; charLen = charIndex >= lineLen ? 1 : BufExpandCharacter(baseChar = lineStr[charIndex], outIndex, expandedChar, buf->tabDist, buf->nullSubsChar); charStyle = styleOfPos(textD, lineStartPos, lineLen, charIndex, outIndex + dispIndexOffset, baseChar); for (i = 0; i < charLen; i++) { if (i != 0 && charIndex < lineLen && lineStr[charIndex] == '\t') { charStyle = styleOfPos(textD, lineStartPos, lineLen, charIndex, outIndex + dispIndexOffset, '\t'); } if (charStyle != style) { drawString(textD, style, startX, y, x, outStr, outPtr - outStr); outPtr = outStr; startX = x; style = charStyle; } if (charIndex < lineLen) { *outPtr = expandedChar[i]; charWidth = stringWidth(textD, &expandedChar[i], 1, charStyle); } else { charWidth = stdCharWidth; } outPtr++; x += charWidth; outIndex++; } if (outPtr - outStr + MAX_EXP_CHAR_LEN >= MAX_DISP_LINE_LEN || x >= rightClip) { break; } } /* Draw the remaining style segment */ drawString(textD, style, startX, y, x, outStr, outPtr - outStr); /* Draw the cursor if part of it appeared on the redisplayed part of this line. Also check for the cases which are not caught as the line is scanned above: when the cursor appears at the very end of the redisplayed section. */ y_orig = textD->cursorY; if (textD->cursorOn) { if (hasCursor) { drawCursor(textD, cursorX, y); } else if (charIndex < lineLen && (lineStartPos+charIndex+1 == cursorPos) && x == rightClip) { if (cursorPos >= buf->length) { drawCursor(textD, x - 1, y); } else { if (wrapUsesCharacter(textD, cursorPos)) { drawCursor(textD, x - 1, y); } } } else if ((lineStartPos + rightCharIndex) == cursorPos) { drawCursor(textD, x - 1, y); } } /* If the y position of the cursor has changed, redraw the calltip */ if (hasCursor && (y_orig != textD->cursorY || y_orig != y)) TextDRedrawCalltip(textD, 0); XtFree(lineStr); } /* ** Draw a string or blank area according to parameter "style", using the ** appropriate colors and drawing method for that style, with top left ** corner at x, y. If style says to draw text, use "string" as source of ** characters, and draw "nChars", if style is FILL, erase ** rectangle where text would have drawn from x to toX and from y to ** the maximum y extent of the current font(s). */ static void drawString(textDisp *textD, int style, int x, int y, int toX, char *string, int nChars) { GC gc, bgGC; XGCValues gcValues; XFontStruct *fs = textD->fontStruct; Pixel bground = textD->bgPixel; Pixel fground = textD->fgPixel; int underlineStyle = FALSE; /* Don't draw if widget isn't realized */ if (XtWindow(textD->w) == 0) return; /* select a GC */ if (style & (STYLE_LOOKUP_MASK | BACKLIGHT_MASK | RANGESET_MASK)) { gc = bgGC = textD->styleGC; } else if (style & HIGHLIGHT_MASK) { gc = textD->highlightGC; bgGC = textD->highlightBGGC; } else if (style & PRIMARY_MASK) { gc = textD->selectGC; bgGC = textD->selectBGGC; } else { gc = bgGC = textD->gc; } if (gc == textD->styleGC) { /* we have work to do */ styleTableEntry *styleRec; /* Set font, color, and gc depending on style. For normal text, GCs for normal drawing, or drawing within a selection or highlight are pre-allocated and pre-configured. For syntax highlighting, GCs are configured here, on the fly. */ if (style & STYLE_LOOKUP_MASK) { styleRec = &textD->styleTable[(style & STYLE_LOOKUP_MASK) - ASCII_A]; underlineStyle = styleRec->underline; fs = styleRec->font; gcValues.font = fs->fid; fground = styleRec->color; /* here you could pick up specific select and highlight fground */ } else { styleRec = NULL; gcValues.font = fs->fid; fground = textD->fgPixel; } /* Background color priority order is: 1 Primary(Selection), 2 Highlight(Parens), 3 Rangeset, 4 SyntaxHighlightStyle, 5 Backlight (if NOT fill), 6 DefaultBackground */ bground = style & PRIMARY_MASK ? textD->selectBGPixel : style & HIGHLIGHT_MASK ? textD->highlightBGPixel : style & RANGESET_MASK ? getRangesetColor(textD, (style&RANGESET_MASK)>>RANGESET_SHIFT, bground) : styleRec && styleRec->bgColorName ? styleRec->bgColor : (style & BACKLIGHT_MASK) && !(style & FILL_MASK) ? textD->bgClassPixel[(style>>BACKLIGHT_SHIFT) & 0xff] : textD->bgPixel; if (fground == bground) /* B&W kludge */ fground = textD->bgPixel; /* set up gc for clearing using the foreground color entry */ gcValues.foreground = gcValues.background = bground; XChangeGC(XtDisplay(textD->w), gc, GCFont | GCForeground | GCBackground, &gcValues); } /* Draw blank area rather than text, if that was the request */ if (style & FILL_MASK) { /* wipes out to right hand edge of widget */ if (toX >= textD->left) clearRect(textD, bgGC, max(x, textD->left), y, toX - max(x, textD->left), textD->ascent + textD->descent); return; } /* If any space around the character remains unfilled (due to use of different sized fonts for highlighting), fill in above or below to erase previously drawn characters */ if (fs->ascent < textD->ascent) clearRect(textD, bgGC, x, y, toX - x, textD->ascent - fs->ascent); if (fs->descent < textD->descent) clearRect(textD, bgGC, x, y + textD->ascent + fs->descent, toX - x, textD->descent - fs->descent); /* set up gc for writing text (set foreground properly) */ if (bgGC == textD->styleGC) { gcValues.foreground = fground; XChangeGC(XtDisplay(textD->w), gc, GCForeground, &gcValues); } /* Draw the string using gc and font set above */ XDrawImageString(XtDisplay(textD->w), XtWindow(textD->w), gc, x, y + textD->ascent, string, nChars); /* Underline if style is secondary selection */ if (style & SECONDARY_MASK || underlineStyle) { /* restore foreground in GC (was set to background by clearRect()) */ gcValues.foreground = fground; XChangeGC(XtDisplay(textD->w), gc, GCForeground, &gcValues); /* draw underline */ XDrawLine(XtDisplay(textD->w), XtWindow(textD->w), gc, x, y + textD->ascent, toX - 1, y + textD->ascent); } } /* ** Clear a rectangle with the appropriate background color for "style" */ static void clearRect(textDisp *textD, GC gc, int x, int y, int width, int height) { /* A width of zero means "clear to end of window" to XClearArea */ if (width == 0 || XtWindow(textD->w) == 0) return; if (gc == textD->gc) { XClearArea(XtDisplay(textD->w), XtWindow(textD->w), x, y, width, height, False); } else { XFillRectangle(XtDisplay(textD->w), XtWindow(textD->w), gc, x, y, width, height); } } /* ** Draw a cursor with top center at x, y. */ static void drawCursor(textDisp *textD, int x, int y) { XSegment segs[5]; int left, right, cursorWidth, midY; int fontWidth = textD->fontStruct->min_bounds.width, nSegs = 0; int fontHeight = textD->ascent + textD->descent; int bot = y + fontHeight - 1; if (XtWindow(textD->w) == 0 || x < textD->left-1 || x > textD->left + textD->width) return; /* For cursors other than the block, make them around 2/3 of a character width, rounded to an even number of pixels so that X will draw an odd number centered on the stem at x. */ cursorWidth = (fontWidth/3) * 2; left = x - cursorWidth/2; right = left + cursorWidth; /* Create segments and draw cursor */ if (textD->cursorStyle == CARET_CURSOR) { midY = bot - fontHeight/5; segs[0].x1 = left; segs[0].y1 = bot; segs[0].x2 = x; segs[0].y2 = midY; segs[1].x1 = x; segs[1].y1 = midY; segs[1].x2 = right; segs[1].y2 = bot; segs[2].x1 = left; segs[2].y1 = bot; segs[2].x2 = x; segs[2].y2=midY-1; segs[3].x1 = x; segs[3].y1=midY-1; segs[3].x2 = right; segs[3].y2 = bot; nSegs = 4; } else if (textD->cursorStyle == NORMAL_CURSOR) { segs[0].x1 = left; segs[0].y1 = y; segs[0].x2 = right; segs[0].y2 = y; segs[1].x1 = x; segs[1].y1 = y; segs[1].x2 = x; segs[1].y2 = bot; segs[2].x1 = left; segs[2].y1 = bot; segs[2].x2 = right; segs[2].y2=bot; nSegs = 3; } else if (textD->cursorStyle == HEAVY_CURSOR) { segs[0].x1 = x-1; segs[0].y1 = y; segs[0].x2 = x-1; segs[0].y2 = bot; segs[1].x1 = x; segs[1].y1 = y; segs[1].x2 = x; segs[1].y2 = bot; segs[2].x1 = x+1; segs[2].y1 = y; segs[2].x2 = x+1; segs[2].y2 = bot; segs[3].x1 = left; segs[3].y1 = y; segs[3].x2 = right; segs[3].y2 = y; segs[4].x1 = left; segs[4].y1 = bot; segs[4].x2 = right; segs[4].y2=bot; nSegs = 5; } else if (textD->cursorStyle == DIM_CURSOR) { midY = y + fontHeight/2; segs[0].x1 = x; segs[0].y1 = y; segs[0].x2 = x; segs[0].y2 = y; segs[1].x1 = x; segs[1].y1 = midY; segs[1].x2 = x; segs[1].y2 = midY; segs[2].x1 = x; segs[2].y1 = bot; segs[2].x2 = x; segs[2].y2 = bot; nSegs = 3; } else if (textD->cursorStyle == BLOCK_CURSOR) { right = x + fontWidth; segs[0].x1 = x; segs[0].y1 = y; segs[0].x2 = right; segs[0].y2 = y; segs[1].x1 = right; segs[1].y1 = y; segs[1].x2 = right; segs[1].y2=bot; segs[2].x1 = right; segs[2].y1 = bot; segs[2].x2 = x; segs[2].y2 = bot; segs[3].x1 = x; segs[3].y1 = bot; segs[3].x2 = x; segs[3].y2 = y; nSegs = 4; } XDrawSegments(XtDisplay(textD->w), XtWindow(textD->w), textD->cursorFGGC, segs, nSegs); /* Save the last position drawn */ textD->cursorX = x; textD->cursorY = y; } /* ** Determine the drawing method to use to draw a specific character from "buf". ** "lineStartPos" gives the character index where the line begins, "lineIndex", ** the number of characters past the beginning of the line, and "dispIndex", ** the number of displayed characters past the beginning of the line. Passing ** lineStartPos of -1 returns the drawing style for "no text". ** ** Why not just: styleOfPos(textD, pos)? Because style applies to blank areas ** of the window beyond the text boundaries, and because this routine must also ** decide whether a position is inside of a rectangular selection, and do so ** efficiently, without re-counting character positions from the start of the ** line. ** ** Note that style is a somewhat incorrect name, drawing method would ** be more appropriate. */ static int styleOfPos(textDisp *textD, int lineStartPos, int lineLen, int lineIndex, int dispIndex, int thisChar) { textBuffer *buf = textD->buffer; textBuffer *styleBuf = textD->styleBuffer; int pos, style = 0; if (lineStartPos == -1 || buf == NULL) return FILL_MASK; pos = lineStartPos + min(lineIndex, lineLen); if (lineIndex >= lineLen) style = FILL_MASK; else if (styleBuf != NULL) { style = (unsigned char)BufGetCharacter(styleBuf, pos); if (style == textD->unfinishedStyle) { /* encountered "unfinished" style, trigger parsing */ (textD->unfinishedHighlightCB)(textD, pos, textD->highlightCBArg); style = (unsigned char)BufGetCharacter(styleBuf, pos); } } if (inSelection(&buf->primary, pos, lineStartPos, dispIndex)) style |= PRIMARY_MASK; if (inSelection(&buf->highlight, pos, lineStartPos, dispIndex)) style |= HIGHLIGHT_MASK; if (inSelection(&buf->secondary, pos, lineStartPos, dispIndex)) style |= SECONDARY_MASK; /* store in the RANGESET_MASK portion of style the rangeset index for pos */ if (buf->rangesetTable) { int rangesetIndex = RangesetIndex1ofPos(buf->rangesetTable, pos, True); style |= ((rangesetIndex << RANGESET_SHIFT) & RANGESET_MASK); } /* store in the BACKLIGHT_MASK portion of style the background color class of the character thisChar */ if (textD->bgClass) { style |= (textD->bgClass[(unsigned char)thisChar]<styleTable[(style & STYLE_LOOKUP_MASK) - ASCII_A].font; else fs = textD->fontStruct; return XTextWidth(fs, (char*) string, (int) length); } /* ** Return true if position "pos" with indentation "dispIndex" is in ** selection "sel" */ static int inSelection(selection *sel, int pos, int lineStartPos, int dispIndex) { return sel->selected && ((!sel->rectangular && pos >= sel->start && pos < sel->end) || (sel->rectangular && pos >= sel->start && lineStartPos <= sel->end && dispIndex >= sel->rectStart && dispIndex < sel->rectEnd)); } /* ** Translate window coordinates to the nearest (insert cursor or character ** cell) text position. The parameter posType specifies how to interpret the ** position: CURSOR_POS means translate the coordinates to the nearest cursor ** position, and CHARACTER_POS means return the position of the character ** closest to (x, y). */ static int xyToPos(textDisp *textD, int x, int y, int posType) { int charIndex, lineStart, lineLen, fontHeight; int charWidth, charLen, charStyle, visLineNum, xStep, outIndex; char *lineStr, expandedChar[MAX_EXP_CHAR_LEN]; /* Find the visible line number corresponding to the y coordinate */ fontHeight = textD->ascent + textD->descent; visLineNum = (y - textD->top) / fontHeight; if (visLineNum < 0) return textD->firstChar; if (visLineNum >= textD->nVisibleLines) visLineNum = textD->nVisibleLines - 1; /* Find the position at the start of the line */ lineStart = textD->lineStarts[visLineNum]; /* If the line start was empty, return the last position in the buffer */ if (lineStart == -1) return textD->buffer->length; /* Get the line text and its length */ lineLen = visLineLength(textD, visLineNum); lineStr = BufGetRange(textD->buffer, lineStart, lineStart + lineLen); /* Step through character positions from the beginning of the line to find the character position corresponding to the x coordinate */ xStep = textD->left - textD->horizOffset; outIndex = 0; for(charIndex=0; charIndexbuffer->tabDist, textD->buffer->nullSubsChar); charStyle = styleOfPos(textD, lineStart, lineLen, charIndex, outIndex, lineStr[charIndex]); charWidth = stringWidth(textD, expandedChar, charLen, charStyle); if (x < xStep + (posType == CURSOR_POS ? charWidth/2 : charWidth)) { XtFree(lineStr); return lineStart + charIndex; } xStep += charWidth; outIndex += charLen; } /* If the x position was beyond the end of the line, return the position of the newline at the end of the line */ XtFree(lineStr); return lineStart + lineLen; } /* ** Translate window coordinates to the nearest row and column number for ** positioning the cursor. This, of course, makes no sense when the font is ** proportional, since there are no absolute columns. The parameter posType ** specifies how to interpret the position: CURSOR_POS means translate the ** coordinates to the nearest position between characters, and CHARACTER_POS ** means translate the position to the nearest character cell. */ static void xyToUnconstrainedPos(textDisp *textD, int x, int y, int *row, int *column, int posType) { int fontHeight = textD->ascent + textD->descent; int fontWidth = textD->fontStruct->max_bounds.width; /* Find the visible line number corresponding to the y coordinate */ *row = (y - textD->top) / fontHeight; if (*row < 0) *row = 0; if (*row >= textD->nVisibleLines) *row = textD->nVisibleLines - 1; *column = ((x-textD->left) + textD->horizOffset + (posType == CURSOR_POS ? fontWidth/2 : 0)) / fontWidth; if (*column < 0) *column = 0; } /* ** Offset the line starts array, topLineNum, firstChar and lastChar, for a new ** vertical scroll position given by newTopLineNum. If any currently displayed ** lines will still be visible, salvage the line starts values, otherwise, ** count lines from the nearest known line start (start or end of buffer, or ** the closest value in the lineStarts array) */ static void offsetLineStarts(textDisp *textD, int newTopLineNum) { int oldTopLineNum = textD->topLineNum; int oldFirstChar = textD->firstChar; int lineDelta = newTopLineNum - oldTopLineNum; int nVisLines = textD->nVisibleLines; int *lineStarts = textD->lineStarts; int i, lastLineNum; textBuffer *buf = textD->buffer; /* If there was no offset, nothing needs to be changed */ if (lineDelta == 0) return; /* { int i; printf("Scroll, lineDelta %d\n", lineDelta); printf("lineStarts Before: "); for(i=0; ifirstChar = TextDCountForwardNLines(textD, 0, newTopLineNum-1, True); /* printf("counting forward %d lines from start\n", newTopLineNum-1);*/ } else if (newTopLineNum < oldTopLineNum) { textD->firstChar = TextDCountBackwardNLines(textD, textD->firstChar, -lineDelta); /* printf("counting backward %d lines from firstChar\n", -lineDelta);*/ } else if (newTopLineNum < lastLineNum) { textD->firstChar = lineStarts[newTopLineNum - oldTopLineNum]; /* printf("taking new start from lineStarts[%d]\n", newTopLineNum - oldTopLineNum); */ } else if (newTopLineNum-lastLineNum < textD->nBufferLines-newTopLineNum) { textD->firstChar = TextDCountForwardNLines(textD, lineStarts[nVisLines-1], newTopLineNum - lastLineNum, True); /* printf("counting forward %d lines from start of last line\n", newTopLineNum - lastLineNum); */ } else { textD->firstChar = TextDCountBackwardNLines(textD, buf->length, textD->nBufferLines - newTopLineNum + 1); /* printf("counting backward %d lines from end\n", textD->nBufferLines - newTopLineNum + 1); */ } /* Fill in the line starts array */ if (lineDelta < 0 && -lineDelta < nVisLines) { for (i=nVisLines-1; i >= -lineDelta; i--) lineStarts[i] = lineStarts[i+lineDelta]; calcLineStarts(textD, 0, -lineDelta); } else if (lineDelta > 0 && lineDelta < nVisLines) { for (i=0; itopLineNum = newTopLineNum; /* If we're numbering lines or being asked to maintain an absolute line number, re-calculate the absolute line number */ offsetAbsLineNum(textD, oldFirstChar); /* { int i; printf("lineStarts After: "); for(i=0; ilineStarts; int i, lineOfPos, lineOfEnd, nVisLines = textD->nVisibleLines; int charDelta = charsInserted - charsDeleted; int lineDelta = linesInserted - linesDeleted; /* { int i; printf("linesDeleted %d, linesInserted %d, charsInserted %d, charsDeleted %d\n", linesDeleted, linesInserted, charsInserted, charsDeleted); printf("lineStarts Before: "); for(i=0; ifirstChar) { textD->topLineNum += lineDelta; for (i=0; ifirstChar += charDelta; textD->lastChar += charDelta; *scrolled = False; return; } /* The change began before the beginning of the displayed text, but part or all of the displayed text was deleted */ if (pos < textD->firstChar) { /* If some text remains in the window, anchor on that */ if (posToVisibleLineNum(textD, pos + charsDeleted, &lineOfEnd) && ++lineOfEnd < nVisLines && lineStarts[lineOfEnd] != -1) { textD->topLineNum = max(1, textD->topLineNum + lineDelta); textD->firstChar = TextDCountBackwardNLines(textD, lineStarts[lineOfEnd] + charDelta, lineOfEnd); /* Otherwise anchor on original line number and recount everything */ } else { if (textD->topLineNum > textD->nBufferLines + lineDelta) { textD->topLineNum = 1; textD->firstChar = 0; } else textD->firstChar = TextDCountForwardNLines(textD, 0, textD->topLineNum - 1, True); } calcLineStarts(textD, 0, nVisLines-1); /* { int i; printf("lineStarts after delete encroaches: "); for(i=0; ilastChar) { /* find line on which the change began */ posToVisibleLineNum(textD, pos, &lineOfPos); /* salvage line starts after the changed area */ if (lineDelta == 0) { for (i=lineOfPos+1; i 0) { for (i=nVisLines-1; i>=lineOfPos+lineDelta+1; i--) lineStarts[i] = lineStarts[i-lineDelta] + (lineStarts[i-lineDelta] == -1 ? 0 : charDelta); } else /* (lineDelta < 0) */ { for (i=max(0,lineOfPos+1); i= 0) calcLineStarts(textD, lineOfPos + 1, lineOfPos + linesInserted); if (lineDelta < 0) calcLineStarts(textD, nVisLines+lineDelta, nVisLines); /* { int i; printf("lineStarts after recalculation: "); for(i=0; ifirstChar if startLine is 0) is good, and re-counts ** newlines to fill in the requested entries. Out of range values for ** "startLine" and "endLine" are acceptable. */ static void calcLineStarts(textDisp *textD, int startLine, int endLine) { int startPos, bufLen = textD->buffer->length; int line, lineEnd, nextLineStart, nVis = textD->nVisibleLines; int *lineStarts = textD->lineStarts; /* Clean up (possibly) messy input parameters */ if (nVis == 0) return; if (endLine < 0) endLine = 0; if (endLine >= nVis) endLine = nVis - 1; if (startLine < 0) startLine = 0; if (startLine >=nVis) startLine = nVis - 1; if (startLine > endLine) return; /* Find the last known good line number -> position mapping */ if (startLine == 0) { lineStarts[0] = textD->firstChar; startLine = 1; } startPos = lineStarts[startLine-1]; /* If the starting position is already past the end of the text, fill in -1's (means no text on line) and return */ if (startPos == -1) { for (line=startLine; line<=endLine; line++) lineStarts[line] = -1; return; } /* Loop searching for ends of lines and storing the positions of the start of the next line in lineStarts */ for (line=startLine; line<=endLine; line++) { findLineEnd(textD, startPos, True, &lineEnd, &nextLineStart); startPos = nextLineStart; if (startPos >= bufLen) { /* If the buffer ends with a newline or line break, put buf->length in the next line start position (instead of a -1 which is the normal marker for an empty line) to indicate that the cursor may safely be displayed there */ if (line == 0 || (lineStarts[line-1] != bufLen && lineEnd != nextLineStart)) { lineStarts[line] = bufLen; line++; } break; } lineStarts[line] = startPos; } /* Set any entries beyond the end of the text to -1 */ for (; line<=endLine; line++) lineStarts[line] = -1; } /* ** Given a textDisp with a complete, up-to-date lineStarts array, update ** the lastChar entry to point to the last buffer position displayed. */ static void calcLastChar(textDisp *textD) { int i; for (i=textD->nVisibleLines-1; i>0 && textD->lineStarts[i]== -1; i--); textD->lastChar = i < 0 ? 0 : TextDEndOfLine(textD, textD->lineStarts[i], True); } void TextDImposeGraphicsExposeTranslation(textDisp *textD, int *xOffset, int *yOffset) { if (textD->graphicsExposeQueue) { graphicExposeTranslationEntry *thisGEQEntry = textD->graphicsExposeQueue->next; if (thisGEQEntry) { *xOffset += thisGEQEntry->horizontal; *yOffset += thisGEQEntry->vertical; } } } Boolean TextDPopGraphicExposeQueueEntry(textDisp *textD) { graphicExposeTranslationEntry *removedGEQEntry = textD->graphicsExposeQueue; if (removedGEQEntry) { textD->graphicsExposeQueue = removedGEQEntry->next; XtFree((char *)removedGEQEntry); } return(removedGEQEntry?True:False); } void TextDTranlateGraphicExposeQueue(textDisp *textD, int xOffset, int yOffset, Boolean appendEntry) { graphicExposeTranslationEntry *newGEQEntry = NULL; if (appendEntry) { newGEQEntry = (graphicExposeTranslationEntry *)XtMalloc(sizeof(graphicExposeTranslationEntry)); newGEQEntry->next = NULL; newGEQEntry->horizontal = xOffset; newGEQEntry->vertical = yOffset; } if (textD->graphicsExposeQueue) { graphicExposeTranslationEntry *iter = textD->graphicsExposeQueue; while (iter->next) { iter->next->horizontal += xOffset; iter->next->vertical += yOffset; iter = iter->next; } if (appendEntry) { iter->next = (struct graphicExposeTranslationEntry *)newGEQEntry; } } else { if (appendEntry) { textD->graphicsExposeQueue = newGEQEntry; } } } static void setScroll(textDisp *textD, int topLineNum, int horizOffset, int updateVScrollBar, int updateHScrollBar) { int fontHeight = textD->ascent + textD->descent; int origHOffset = textD->horizOffset; int lineDelta = textD->topLineNum - topLineNum; int xOffset, yOffset, srcX, srcY, dstX, dstY, width, height; int exactHeight = textD->height - textD->height % (textD->ascent + textD->descent); /* Do nothing if scroll position hasn't actually changed or there's no window to draw in yet */ if (XtWindow(textD->w) == 0 || (textD->horizOffset == horizOffset && textD->topLineNum == topLineNum)) return; /* If part of the cursor is protruding beyond the text clipping region, clear it off */ blankCursorProtrusions(textD); /* If the vertical scroll position has changed, update the line starts array and related counters in the text display */ offsetLineStarts(textD, topLineNum); /* Just setting textD->horizOffset is enough information for redisplay */ textD->horizOffset = horizOffset; /* Update the scroll bar positions if requested, note: updating the horizontal scroll bars can have the further side-effect of changing the horizontal scroll position, textD->horizOffset */ if (updateVScrollBar && textD->vScrollBar != NULL) { updateVScrollBarRange(textD); } if (updateHScrollBar && textD->hScrollBar != NULL) { updateHScrollBarRange(textD); } /* Redisplay everything if the window is partially obscured (since it's too hard to tell what displayed areas are salvageable) or if there's nothing to recover because the scroll distance is large */ xOffset = origHOffset - textD->horizOffset; yOffset = lineDelta * fontHeight; if (textD->visibility != VisibilityUnobscured || abs(xOffset) > textD->width || abs(yOffset) > exactHeight) { TextDTranlateGraphicExposeQueue(textD, xOffset, yOffset, False); TextDRedisplayRect(textD, textD->left, textD->top, textD->width, textD->height); } else { /* If the window is not obscured, paint most of the window using XCopyArea from existing displayed text, and redraw only what's necessary */ /* Recover the useable window areas by moving to the proper location */ srcX = textD->left + (xOffset >= 0 ? 0 : -xOffset); dstX = textD->left + (xOffset >= 0 ? xOffset : 0); width = textD->width - abs(xOffset); srcY = textD->top + (yOffset >= 0 ? 0 : -yOffset); dstY = textD->top + (yOffset >= 0 ? yOffset : 0); height = exactHeight - abs(yOffset); resetClipRectangles(textD); TextDTranlateGraphicExposeQueue(textD, xOffset, yOffset, True); XCopyArea(XtDisplay(textD->w), XtWindow(textD->w), XtWindow(textD->w), textD->gc, srcX, srcY, width, height, dstX, dstY); /* redraw the un-recoverable parts */ if (yOffset > 0) { TextDRedisplayRect(textD, textD->left, textD->top, textD->width, yOffset); } else if (yOffset < 0) { TextDRedisplayRect(textD, textD->left, textD->top + textD->height + yOffset, textD->width, -yOffset); } if (xOffset > 0) { TextDRedisplayRect(textD, textD->left, textD->top, xOffset, textD->height); } else if (xOffset < 0) { TextDRedisplayRect(textD, textD->left + textD->width + xOffset, textD->top, -xOffset, textD->height); } /* Restore protruding parts of the cursor */ textDRedisplayRange(textD, textD->cursorPos-1, textD->cursorPos+1); } /* Refresh line number/calltip display if its up and we've scrolled vertically */ if (lineDelta != 0) { redrawLineNumbers(textD, False); TextDRedrawCalltip(textD, 0); } HandleAllPendingGraphicsExposeNoExposeEvents((TextWidget)textD->w, NULL); } /* ** Update the minimum, maximum, slider size, page increment, and value ** for vertical scroll bar. */ static void updateVScrollBarRange(textDisp *textD) { int sliderSize, sliderMax, sliderValue; if (textD->vScrollBar == NULL) return; /* The Vert. scroll bar value and slider size directly represent the top line number, and the number of visible lines respectively. The scroll bar maximum value is chosen to generally represent the size of the whole buffer, with minor adjustments to keep the scroll bar widget happy */ sliderSize = max(textD->nVisibleLines, 1); /* Avoid X warning (size < 1) */ sliderValue = textD->topLineNum; sliderMax = max(textD->nBufferLines + 2 + TEXT_OF_TEXTD(textD).cursorVPadding, sliderSize + sliderValue); XtVaSetValues(textD->vScrollBar, XmNmaximum, sliderMax, XmNsliderSize, sliderSize, XmNpageIncrement, max(1, textD->nVisibleLines - 1), XmNvalue, sliderValue, NULL); } /* ** Update the minimum, maximum, slider size, page increment, and value ** for the horizontal scroll bar. If scroll position is such that there ** is blank space to the right of all lines of text, scroll back (adjust ** horizOffset but don't redraw) to take up the slack and position the ** right edge of the text at the right edge of the display. ** ** Note, there is some cost to this routine, since it scans the whole range ** of displayed text, particularly since it's usually called for each typed ** character! */ static int updateHScrollBarRange(textDisp *textD) { int i, maxWidth = 0, sliderMax, sliderWidth; int origHOffset = textD->horizOffset; if (textD->hScrollBar == NULL || !XtIsManaged(textD->hScrollBar)) return False; /* Scan all the displayed lines to find the width of the longest line */ for (i=0; inVisibleLines && textD->lineStarts[i]!= -1; i++) maxWidth = max(measureVisLine(textD, i), maxWidth); /* If the scroll position is beyond what's necessary to keep all lines in view, scroll to the left to bring the end of the longest line to the right margin */ if (maxWidth < textD->width + textD->horizOffset && textD->horizOffset > 0) textD->horizOffset = max(0, maxWidth - textD->width); /* Readjust the scroll bar */ sliderWidth = textD->width; sliderMax = max(maxWidth, sliderWidth + textD->horizOffset); XtVaSetValues(textD->hScrollBar, XmNmaximum, sliderMax, XmNsliderSize, sliderWidth, XmNpageIncrement, max(textD->width - 100, 10), XmNvalue, textD->horizOffset, NULL); /* Return True if scroll position was changed */ return origHOffset != textD->horizOffset; } /* ** Define area for drawing line numbers. A width of 0 disables line ** number drawing. */ void TextDSetLineNumberArea(textDisp *textD, int lineNumLeft, int lineNumWidth, int textLeft) { int newWidth = textD->width + textD->left - textLeft; textD->lineNumLeft = lineNumLeft; textD->lineNumWidth = lineNumWidth; textD->left = textLeft; XClearWindow(XtDisplay(textD->w), XtWindow(textD->w)); resetAbsLineNum(textD); TextDResize(textD, newWidth, textD->height); TextDRedisplayRect(textD, 0, textD->top, INT_MAX, textD->height); } /* ** Refresh the line number area. If clearAll is False, writes only over ** the character cell areas. Setting clearAll to True will clear out any ** stray marks outside of the character cell area, which might have been ** left from before a resize or font change. */ static void redrawLineNumbers(textDisp *textD, int clearAll) { int y, line, visLine, nCols, lineStart; char lineNumString[12]; int lineHeight = textD->ascent + textD->descent; int charWidth = textD->fontStruct->max_bounds.width; XRectangle clipRect; Display *display = XtDisplay(textD->w); /* Don't draw if lineNumWidth == 0 (line numbers are hidden), or widget is not yet realized */ if (textD->lineNumWidth == 0 || XtWindow(textD->w) == 0) return; /* Make sure we reset the clipping range for the line numbers GC, because the GC may be shared (eg, if the line numbers and text have the same color) and therefore the clipping ranges may be invalid. */ clipRect.x = textD->lineNumLeft; clipRect.y = textD->top; clipRect.width = textD->lineNumWidth; clipRect.height = textD->height; XSetClipRectangles(display, textD->lineNumGC, 0, 0, &clipRect, 1, Unsorted); /* Erase the previous contents of the line number area, if requested */ if (clearAll) XClearArea(XtDisplay(textD->w), XtWindow(textD->w), textD->lineNumLeft, textD->top, textD->lineNumWidth, textD->height, False); /* Draw the line numbers, aligned to the text */ nCols = min(11, textD->lineNumWidth / charWidth); y = textD->top; line = getAbsTopLineNum(textD); for (visLine=0; visLine < textD->nVisibleLines; visLine++) { lineStart = textD->lineStarts[visLine]; if (lineStart != -1 && (lineStart==0 || BufGetCharacter(textD->buffer, lineStart-1)=='\n')) { sprintf(lineNumString, "%*d", nCols, line); XDrawImageString(XtDisplay(textD->w), XtWindow(textD->w), textD->lineNumGC, textD->lineNumLeft, y + textD->ascent, lineNumString, strlen(lineNumString)); line++; } else { XClearArea(XtDisplay(textD->w), XtWindow(textD->w), textD->lineNumLeft, y, textD->lineNumWidth, textD->ascent + textD->descent, False); if (visLine == 0) line++; } y += lineHeight; } } /* ** Callbacks for drag or valueChanged on scroll bars */ static void vScrollCB(Widget w, XtPointer clientData, XtPointer callData) { textDisp *textD = (textDisp *)clientData; int newValue = ((XmScrollBarCallbackStruct *)callData)->value; int lineDelta = newValue - textD->topLineNum; if (lineDelta == 0) return; setScroll(textD, newValue, textD->horizOffset, False, True); } static void hScrollCB(Widget w, XtPointer clientData, XtPointer callData) { textDisp *textD = (textDisp *)clientData; int newValue = ((XmScrollBarCallbackStruct *)callData)->value; if (newValue == textD->horizOffset) return; setScroll(textD, textD->topLineNum, newValue, False, False); } static void visibilityEH(Widget w, XtPointer data, XEvent *event, Boolean *continueDispatch) { /* Record whether the window is fully visible or not. This information is used for choosing the scrolling methodology for optimal performance, if the window is partially obscured, XCopyArea may not work */ ((textDisp *)data)->visibility = ((XVisibilityEvent *)event)->state; } static int max(int i1, int i2) { return i1 >= i2 ? i1 : i2; } static int min(int i1, int i2) { return i1 <= i2 ? i1 : i2; } /* ** Count the number of newlines in a null-terminated text string; */ static int countLines(const char *string) { const char *c; int lineCount = 0; if (string == NULL) return 0; for (c=string; *c!='\0'; c++) if (*c == '\n') lineCount++; return lineCount; } /* ** Return the width in pixels of the displayed line pointed to by "visLineNum" */ static int measureVisLine(textDisp *textD, int visLineNum) { int i, width = 0, len, style, lineLen = visLineLength(textD, visLineNum); int charCount = 0, lineStartPos = textD->lineStarts[visLineNum]; char expandedChar[MAX_EXP_CHAR_LEN]; if (textD->styleBuffer == NULL) { for (i=0; ibuffer, lineStartPos + i, charCount, expandedChar); width += XTextWidth(textD->fontStruct, expandedChar, len); charCount += len; } } else { for (i=0; ibuffer, lineStartPos+i, charCount, expandedChar); style = (unsigned char)BufGetCharacter(textD->styleBuffer, lineStartPos+i) - ASCII_A; width += XTextWidth(textD->styleTable[style].font, expandedChar, len); charCount += len; } } return width; } /* ** Return true if there are lines visible with no corresponding buffer text */ static int emptyLinesVisible(textDisp *textD) { return textD->nVisibleLines > 0 && textD->lineStarts[textD->nVisibleLines-1] == -1; } /* ** When the cursor is at the left or right edge of the text, part of it ** sticks off into the clipped region beyond the text. Normal redrawing ** can not overwrite this protruding part of the cursor, so it must be ** erased independently by calling this routine. */ static void blankCursorProtrusions(textDisp *textD) { int x, width, cursorX = textD->cursorX, cursorY = textD->cursorY; int fontWidth = textD->fontStruct->max_bounds.width; int fontHeight = textD->ascent + textD->descent; int cursorWidth, left = textD->left, right = left + textD->width; cursorWidth = (fontWidth/3) * 2; if (cursorX >= left-1 && cursorX <= left + cursorWidth/2 - 1) { x = cursorX - cursorWidth/2; width = left - x; } else if (cursorX >= right - cursorWidth/2 && cursorX <= right) { x = right; width = cursorX + cursorWidth/2 + 2 - right; } else return; XClearArea(XtDisplay(textD->w), XtWindow(textD->w), x, cursorY, width, fontHeight, False); } /* ** Allocate shared graphics contexts used by the widget, which must be ** re-allocated on a font change. */ static void allocateFixedFontGCs(textDisp *textD, XFontStruct *fontStruct, Pixel bgPixel, Pixel fgPixel, Pixel selectFGPixel, Pixel selectBGPixel, Pixel highlightFGPixel, Pixel highlightBGPixel, Pixel lineNumFGPixel) { textD->gc = allocateGC(textD->w, GCFont | GCForeground | GCBackground, fgPixel, bgPixel, fontStruct->fid, GCClipMask, GCArcMode); textD->selectGC = allocateGC(textD->w, GCFont | GCForeground | GCBackground, selectFGPixel, selectBGPixel, fontStruct->fid, GCClipMask, GCArcMode); textD->selectBGGC = allocateGC(textD->w, GCForeground, selectBGPixel, 0, fontStruct->fid, GCClipMask, GCArcMode); textD->highlightGC = allocateGC(textD->w, GCFont|GCForeground|GCBackground, highlightFGPixel, highlightBGPixel, fontStruct->fid, GCClipMask, GCArcMode); textD->highlightBGGC = allocateGC(textD->w, GCForeground, highlightBGPixel, 0, fontStruct->fid, GCClipMask, GCArcMode); textD->lineNumGC = allocateGC(textD->w, GCFont | GCForeground | GCBackground, lineNumFGPixel, bgPixel, fontStruct->fid, GCClipMask, GCArcMode); } /* ** X11R4 does not have the XtAllocateGC function for sharing graphics contexts ** with changeable fields. Unfortunately the R4 call for creating shared ** graphics contexts (XtGetGC) is rarely useful because most widgets need ** to be able to set and change clipping, and that makes the GC unshareable. ** ** This function allocates and returns a gc, using XtAllocateGC if possible, ** or XCreateGC on X11R4 systems where XtAllocateGC is not available. */ static GC allocateGC(Widget w, unsigned long valueMask, unsigned long foreground, unsigned long background, Font font, unsigned long dynamicMask, unsigned long dontCareMask) { XGCValues gcValues; gcValues.font = font; gcValues.background = background; gcValues.foreground = foreground; #if defined(XlibSpecificationRelease) && XlibSpecificationRelease > 4 return XtAllocateGC(w, 0, valueMask, &gcValues, dynamicMask, dontCareMask); #else return XCreateGC(XtDisplay(w), RootWindowOfScreen(XtScreen(w)), valueMask, &gcValues); #endif } /* ** Release a gc allocated with allocateGC above */ static void releaseGC(Widget w, GC gc) { #if defined(XlibSpecificationRelease) && XlibSpecificationRelease > 4 XtReleaseGC(w, gc); #else XFreeGC(XtDisplay(w), gc); #endif } /* ** resetClipRectangles sets the clipping rectangles for GCs which clip ** at the text boundary (as opposed to the window boundary). These GCs ** are shared such that the drawing styles are constant, but the clipping ** rectangles are allowed to change among different users of the GCs (the ** GCs were created with XtAllocGC). This routine resets them so the clipping ** rectangles are correct for this text display. */ static void resetClipRectangles(textDisp *textD) { XRectangle clipRect; Display *display = XtDisplay(textD->w); clipRect.x = textD->left; clipRect.y = textD->top; clipRect.width = textD->width; clipRect.height = textD->height - textD->height % (textD->ascent + textD->descent); XSetClipRectangles(display, textD->gc, 0, 0, &clipRect, 1, Unsorted); XSetClipRectangles(display, textD->selectGC, 0, 0, &clipRect, 1, Unsorted); XSetClipRectangles(display, textD->highlightGC, 0, 0, &clipRect, 1, Unsorted); XSetClipRectangles(display, textD->selectBGGC, 0, 0, &clipRect, 1, Unsorted); XSetClipRectangles(display, textD->highlightBGGC, 0, 0, &clipRect, 1, Unsorted); XSetClipRectangles(display, textD->styleGC, 0, 0, &clipRect, 1, Unsorted); } /* ** Return the length of a line (number of displayable characters) by examining ** entries in the line starts array rather than by scanning for newlines */ static int visLineLength(textDisp *textD, int visLineNum) { int nextLineStart, lineStartPos = textD->lineStarts[visLineNum]; if (lineStartPos == -1) return 0; if (visLineNum+1 >= textD->nVisibleLines) return textD->lastChar - lineStartPos; nextLineStart = textD->lineStarts[visLineNum+1]; if (nextLineStart == -1) return textD->lastChar - lineStartPos; if (wrapUsesCharacter(textD, nextLineStart-1)) return nextLineStart-1 - lineStartPos; return nextLineStart - lineStartPos; } /* ** When continuous wrap is on, and the user inserts or deletes characters, ** wrapping can happen before and beyond the changed position. This routine ** finds the extent of the changes, and counts the deleted and inserted lines ** over that range. It also attempts to minimize the size of the range to ** what has to be counted and re-displayed, so the results can be useful ** both for delimiting where the line starts need to be recalculated, and ** for deciding what part of the text to redisplay. */ static void findWrapRange(textDisp *textD, const char *deletedText, int pos, int nInserted, int nDeleted, int *modRangeStart, int *modRangeEnd, int *linesInserted, int *linesDeleted) { int length, retPos, retLines, retLineStart, retLineEnd; textBuffer *deletedTextBuf, *buf = textD->buffer; int nVisLines = textD->nVisibleLines; int *lineStarts = textD->lineStarts; int countFrom, countTo, lineStart, adjLineStart, i; int visLineNum = 0, nLines = 0; /* ** Determine where to begin searching: either the previous newline, or ** if possible, limit to the start of the (original) previous displayed ** line, using information from the existing line starts array */ if (pos >= textD->firstChar && pos <= textD->lastChar) { for (i=nVisLines-1; i>0; i--) if (lineStarts[i] != -1 && pos >= lineStarts[i]) break; if (i > 0) { countFrom = lineStarts[i-1]; visLineNum = i-1; } else countFrom = BufStartOfLine(buf, pos); } else countFrom = BufStartOfLine(buf, pos); /* ** Move forward through the (new) text one line at a time, counting ** displayed lines, and looking for either a real newline, or for the ** line starts to re-sync with the original line starts array */ lineStart = countFrom; *modRangeStart = countFrom; while (True) { /* advance to the next line. If the line ended in a real newline or the end of the buffer, that's far enough */ wrappedLineCounter(textD, buf, lineStart, buf->length, 1, True, 0, &retPos, &retLines, &retLineStart, &retLineEnd); if (retPos >= buf->length) { countTo = buf->length; *modRangeEnd = countTo; if (retPos != retLineEnd) nLines++; break; } else lineStart = retPos; nLines++; if (lineStart > pos + nInserted && BufGetCharacter(buf, lineStart-1) == '\n') { countTo = lineStart; *modRangeEnd = lineStart; break; } /* Don't try to resync in continuous wrap mode with non-fixed font sizes; it would result in a chicken-and-egg dependency between the calculations for the inserted and the deleted lines. If we're in that mode, the number of deleted lines is calculated in advance, without resynchronization, so we shouldn't resynchronize for the inserted lines either. */ if (textD->suppressResync) continue; /* check for synchronization with the original line starts array before pos, if so, the modified range can begin later */ if (lineStart <= pos) { while (visLineNum pos + nInserted) { adjLineStart = lineStart - nInserted + nDeleted; while (visLineNumsuppressResync) { *linesDeleted = textD->nLinesDeleted; textD->suppressResync = 0; return; } length = (pos-countFrom) + nDeleted +(countTo-(pos+nInserted)); deletedTextBuf = BufCreatePreallocated(length); if (pos > countFrom) BufCopyFromBuf(textD->buffer, deletedTextBuf, countFrom, pos, 0); if (nDeleted != 0) BufInsert(deletedTextBuf, pos-countFrom, deletedText); if (countTo > pos+nInserted) BufCopyFromBuf(textD->buffer, deletedTextBuf, pos+nInserted, countTo, pos-countFrom+nDeleted); /* Note that we need to take into account an offset for the style buffer: the deletedTextBuf can be out of sync with the style buffer. */ wrappedLineCounter(textD, deletedTextBuf, 0, length, INT_MAX, True, countFrom, &retPos, &retLines, &retLineStart, &retLineEnd); BufFree(deletedTextBuf); *linesDeleted = retLines; textD->suppressResync = 0; } /* ** This is a stripped-down version of the findWrapRange() function above, ** intended to be used to calculate the number of "deleted" lines during ** a buffer modification. It is called _before_ the modification takes place. ** ** This function should only be called in continuous wrap mode with a ** non-fixed font width. In that case, it is impossible to calculate ** the number of deleted lines, because the necessary style information ** is no longer available _after_ the modification. In other cases, we ** can still perform the calculation afterwards (possibly even more ** efficiently). */ static void measureDeletedLines(textDisp *textD, int pos, int nDeleted) { int retPos, retLines, retLineStart, retLineEnd; textBuffer *buf = textD->buffer; int nVisLines = textD->nVisibleLines; int *lineStarts = textD->lineStarts; int countFrom, lineStart; int nLines = 0, i; /* ** Determine where to begin searching: either the previous newline, or ** if possible, limit to the start of the (original) previous displayed ** line, using information from the existing line starts array */ if (pos >= textD->firstChar && pos <= textD->lastChar) { for (i=nVisLines-1; i>0; i--) if (lineStarts[i] != -1 && pos >= lineStarts[i]) break; if (i > 0) { countFrom = lineStarts[i-1]; } else countFrom = BufStartOfLine(buf, pos); } else countFrom = BufStartOfLine(buf, pos); /* ** Move forward through the (new) text one line at a time, counting ** displayed lines, and looking for either a real newline, or for the ** line starts to re-sync with the original line starts array */ lineStart = countFrom; while (True) { /* advance to the next line. If the line ended in a real newline or the end of the buffer, that's far enough */ wrappedLineCounter(textD, buf, lineStart, buf->length, 1, True, 0, &retPos, &retLines, &retLineStart, &retLineEnd); if (retPos >= buf->length) { if (retPos != retLineEnd) nLines++; break; } else lineStart = retPos; nLines++; if (lineStart > pos + nDeleted && BufGetCharacter(buf, lineStart-1) == '\n') { break; } /* Unlike in the findWrapRange() function above, we don't try to resync with the line starts, because we don't know the length of the inserted text yet, nor the updated style information. Because of that, we also shouldn't resync with the line starts after the modification either, because we must perform the calculations for the deleted and inserted lines in the same way. This can result in some unnecessary recalculation and redrawing overhead, and therefore we should only use this two-phase mode of calculation when it's really needed (continuous wrap + variable font width). */ } textD->nLinesDeleted = nLines; textD->suppressResync = 1; } /* ** Count forward from startPos to either maxPos or maxLines (whichever is ** reached first), and return all relevant positions and line count. ** The provided textBuffer may differ from the actual text buffer of the ** widget. In that case it must be a (partial) copy of the actual text buffer ** and the styleBufOffset argument must indicate the starting position of the ** copy, to take into account the correct style information. ** ** Returned values: ** ** retPos: Position where counting ended. When counting lines, the ** position returned is the start of the line "maxLines" ** lines beyond "startPos". ** retLines: Number of line breaks counted ** retLineStart: Start of the line where counting ended ** retLineEnd: End position of the last line traversed */ static void wrappedLineCounter(const textDisp* textD, const textBuffer* buf, const int startPos, const int maxPos, const int maxLines, const Boolean startPosIsLineStart, const int styleBufOffset, int* retPos, int* retLines, int* retLineStart, int* retLineEnd) { int lineStart, newLineStart = 0, b, p, colNum, wrapMargin; int maxWidth, width, countPixels, i, foundBreak; int nLines = 0, tabDist = textD->buffer->tabDist; unsigned char c; char nullSubsChar = textD->buffer->nullSubsChar; /* If the font is fixed, or there's a wrap margin set, it's more efficient to measure in columns, than to count pixels. Determine if we can count in columns (countPixels == False) or must count pixels (countPixels == True), and set the wrap target for either pixels or columns */ if (textD->fixedFontWidth != -1 || textD->wrapMargin != 0) { countPixels = False; wrapMargin = textD->wrapMargin != 0 ? textD->wrapMargin : textD->width / textD->fixedFontWidth; maxWidth = INT_MAX; } else { countPixels = True; wrapMargin = INT_MAX; maxWidth = textD->width; } /* Find the start of the line if the start pos is not marked as a line start. */ if (startPosIsLineStart) lineStart = startPos; else lineStart = TextDStartOfLine(textD, startPos); /* ** Loop until position exceeds maxPos or line count exceeds maxLines. ** (actually, contines beyond maxPos to end of line containing maxPos, ** in case later characters cause a word wrap back before maxPos) */ colNum = 0; width = 0; for (p=lineStart; plength; p++) { c = BufGetCharacter(buf, p); /* If the character was a newline, count the line and start over, otherwise, add it to the width and column counts */ if (c == '\n') { if (p >= maxPos) { *retPos = maxPos; *retLines = nLines; *retLineStart = lineStart; *retLineEnd = maxPos; return; } nLines++; if (nLines >= maxLines) { *retPos = p + 1; *retLines = nLines; *retLineStart = p + 1; *retLineEnd = p; return; } lineStart = p + 1; colNum = 0; width = 0; } else { colNum += BufCharWidth(c, colNum, tabDist, nullSubsChar); if (countPixels) width += measurePropChar(textD, c, colNum, p+styleBufOffset); } /* If character exceeded wrap margin, find the break point and wrap there */ if (colNum > wrapMargin || width > maxWidth) { foundBreak = False; for (b=p; b>=lineStart; b--) { c = BufGetCharacter(buf, b); if (c == '\t' || c == ' ') { newLineStart = b + 1; if (countPixels) { colNum = 0; width = 0; for (i=b+1; i= maxPos) { *retPos = maxPos; *retLines = maxPos < newLineStart ? nLines : nLines + 1; *retLineStart = maxPos < newLineStart ? lineStart : newLineStart; *retLineEnd = maxPos; return; } nLines++; if (nLines >= maxLines) { *retPos = foundBreak ? b + 1 : max(p, lineStart+1); *retLines = nLines; *retLineStart = lineStart; *retLineEnd = foundBreak ? b : p; return; } lineStart = newLineStart; } } /* reached end of buffer before reaching pos or line target */ *retPos = buf->length; *retLines = nLines; *retLineStart = lineStart; *retLineEnd = buf->length; } /* ** Measure the width in pixels of a character "c" at a particular column ** "colNum" and buffer position "pos". This is for measuring characters in ** proportional or mixed-width highlighting fonts. ** ** A note about proportional and mixed-width fonts: the mixed width and ** proportional font code in nedit does not get much use in general editing, ** because nedit doesn't allow per-language-mode fonts, and editing programs ** in a proportional font is usually a bad idea, so very few users would ** choose a proportional font as a default. There are still probably mixed- ** width syntax highlighting cases where things don't redraw properly for ** insertion/deletion, though static display and wrapping and resizing ** should now be solid because they are now used for online help display. */ static int measurePropChar(const textDisp* textD, const char c, const int colNum, const int pos) { int charLen, style; char expChar[MAX_EXP_CHAR_LEN]; textBuffer *styleBuf = textD->styleBuffer; charLen = BufExpandCharacter(c, colNum, expChar, textD->buffer->tabDist, textD->buffer->nullSubsChar); if (styleBuf == NULL) { style = 0; } else { style = (unsigned char)BufGetCharacter(styleBuf, pos); if (style == textD->unfinishedStyle) { /* encountered "unfinished" style, trigger parsing */ (textD->unfinishedHighlightCB)(textD, pos, textD->highlightCBArg); style = (unsigned char)BufGetCharacter(styleBuf, pos); } } return stringWidth(textD, expChar, charLen, style); } /* ** Finds both the end of the current line and the start of the next line. Why? ** In continuous wrap mode, if you need to know both, figuring out one from the ** other can be expensive or error prone. The problem comes when there's a ** trailing space or tab just before the end of the buffer. To translate an ** end of line value to or from the next lines start value, you need to know ** whether the trailing space or tab is being used as a line break or just a ** normal character, and to find that out would otherwise require counting all ** the way back to the beginning of the line. */ static void findLineEnd(textDisp *textD, int startPos, int startPosIsLineStart, int *lineEnd, int *nextLineStart) { int retLines, retLineStart; /* if we're not wrapping use more efficient BufEndOfLine */ if (!textD->continuousWrap) { *lineEnd = BufEndOfLine(textD->buffer, startPos); *nextLineStart = min(textD->buffer->length, *lineEnd + 1); return; } /* use the wrapped line counter routine to count forward one line */ wrappedLineCounter(textD, textD->buffer, startPos, textD->buffer->length, 1, startPosIsLineStart, 0, nextLineStart, &retLines, &retLineStart, lineEnd); return; } /* ** Line breaks in continuous wrap mode usually happen at newlines or ** whitespace. This line-terminating character is not included in line ** width measurements and has a special status as a non-visible character. ** However, lines with no whitespace are wrapped without the benefit of a ** line terminating character, and this distinction causes endless trouble ** with all of the text display code which was originally written without ** continuous wrap mode and always expects to wrap at a newline character. ** ** Given the position of the end of the line, as returned by TextDEndOfLine ** or BufEndOfLine, this returns true if there is a line terminating ** character, and false if there's not. On the last character in the ** buffer, this function can't tell for certain whether a trailing space was ** used as a wrap point, and just guesses that it wasn't. So if an exact ** accounting is necessary, don't use this function. */ static int wrapUsesCharacter(textDisp *textD, int lineEndPos) { char c; if (!textD->continuousWrap || lineEndPos == textD->buffer->length) return True; c = BufGetCharacter(textD->buffer, lineEndPos); return c == '\n' || ((c == '\t' || c == ' ') && lineEndPos + 1 != textD->buffer->length); } /* ** Decide whether the user needs (or may need) a horizontal scroll bar, ** and manage or unmanage the scroll bar widget accordingly. The H. ** scroll bar is only hidden in continuous wrap mode when it's absolutely ** certain that the user will not need it: when wrapping is set ** to the window edge, or when the wrap margin is strictly less than ** the longest possible line. */ static void hideOrShowHScrollBar(textDisp *textD) { if (textD->continuousWrap && (textD->wrapMargin == 0 || textD->wrapMargin * textD->fontStruct->max_bounds.width < textD->width)) XtUnmanageChild(textD->hScrollBar); else XtManageChild(textD->hScrollBar); } /* ** Return true if the selection "sel" is rectangular, and touches a ** buffer position withing "rangeStart" to "rangeEnd" */ static int rangeTouchesRectSel(selection *sel, int rangeStart, int rangeEnd) { return sel->selected && sel->rectangular && sel->end >= rangeStart && sel->start <= rangeEnd; } /* ** Extend the range of a redraw request (from *start to *end) with additional ** redraw requests resulting from changes to the attached style buffer (which ** contains auxiliary information for coloring or styling text). */ static void extendRangeForStyleMods(textDisp *textD, int *start, int *end) { selection *sel = &textD->styleBuffer->primary; int extended = False; /* The peculiar protocol used here is that modifications to the style buffer are marked by selecting them with the buffer's primary selection. The style buffer is usually modified in response to a modify callback on the text buffer BEFORE textDisp.c's modify callback, so that it can keep the style buffer in step with the text buffer. The style-update callback can't just call for a redraw, because textDisp hasn't processed the original text changes yet. Anyhow, to minimize redrawing and to avoid the complexity of scheduling redraws later, this simple protocol tells the text display's buffer modify callback to extend it's redraw range to show the text color/and font changes as well. */ if (sel->selected) { if (sel->start < *start) { *start = sel->start; extended = True; } if (sel->end > *end) { *end = sel->end; extended = True; } } /* If the selection was extended due to a style change, and some of the fonts don't match in spacing, extend redraw area to end of line to redraw characters exposed by possible font size changes */ if (textD->fixedFontWidth == -1 && extended) *end = BufEndOfLine(textD->buffer, *end) + 1; } /********************** Backlight Functions ******************************/ /* ** Allocate a read-only (shareable) colormap cell for a named color, from the ** the default colormap of the screen on which the widget (w) is displayed. If ** the colormap is full and there's no suitable substitute, print an error on ** stderr, and return the widget's background color as a backup. */ static Pixel allocBGColor(Widget w, char *colorName, int *ok) { int r,g,b; *ok = 1; return AllocColor(w, colorName, &r, &g, &b); } static Pixel getRangesetColor(textDisp *textD, int ind, Pixel bground) { textBuffer *buf; RangesetTable *tab; Pixel color; char *color_name; int valid; if (ind > 0) { ind--; buf = textD->buffer; tab = buf->rangesetTable; valid = RangesetTableGetColorValid(tab, ind, &color); if (valid == 0) { color_name = RangesetTableGetColorName(tab, ind); if (color_name) color = allocBGColor(textD->w, color_name, &valid); RangesetTableAssignColorPixel(tab, ind, color, valid); } if (valid > 0) { return color; } } return bground; } /* ** Read the background color class specification string in str, allocating the ** necessary colors, and allocating and setting up the character->class_no and ** class_no->pixel map arrays, returned via *pp_bgClass and *pp_bgClassPixel ** respectively. ** Note: the allocation of class numbers could be more intelligent: there can ** never be more than 256 of these (one per character); but I don't think ** there'll be a pressing need. I suppose the scanning of the specification ** could be better too, but then, who cares! */ void TextDSetupBGClasses(Widget w, XmString str, Pixel **pp_bgClassPixel, unsigned char **pp_bgClass, Pixel bgPixelDefault) { unsigned char bgClass[256]; Pixel bgClassPixel[256]; int class_no = 0; char *semicol; char *s = (char *)str; size_t was_semicol; int lo, hi, dummy; char *pos; Boolean is_good = True; XtFree((char *)*pp_bgClass); XtFree((char *)*pp_bgClassPixel); *pp_bgClassPixel = NULL; *pp_bgClass = NULL; if (!s) return; /* default for all chars is class number zero, for standard background */ memset(bgClassPixel, 0, sizeof bgClassPixel); memset(bgClass, 0, sizeof bgClass); bgClassPixel[0] = bgPixelDefault; /* since class no == 0 in a "style" has no set bits in BACKLIGHT_MASK (see styleOfPos()), when drawString() is called for text with a backlight class no of zero, bgClassPixel[0] is never consulted, and the default background color is chosen. */ /* The format of the class string s is: low[-high]{,low[-high]}:color{;low-high{,low[-high]}:color} eg 32-255:#f0f0f0;1-31,127:red;128-159:orange;9-13:#e5e5e5 where low and high represent a character range between ordinal ASCII values. Using strtol() allows automatic octal, dec and hex reading of low and high. The example format sets backgrounds as follows: char 1 - 8 colored red (control characters) char 9 - 13 colored #e5e5e5 (isspace() control characters) char 14 - 31 colored red (control characters) char 32 - 126 colored #f0f0f0 char 127 colored red (delete character) char 128 - 159 colored orange ("shifted" control characters) char 160 - 255 colored #f0f0f0 Notice that some of the later ranges overwrite the class values defined for earlier ones (eg the first clause, 32-255:#f0f0f0 sets the DEL character background color to #f0f0f0; it is then set to red by the clause 1-31,127:red). */ while (s && class_no < 255) { class_no++; /* simple class alloc scheme */ was_semicol = 0; is_good = True; if ((semicol = (char *)strchr(s, ';'))) { *semicol = '\0'; /* null-terminate low[-high]:color clause */ was_semicol = 1; } /* loop over ranges before the color spec, assigning the characters in the ranges to the current class number */ for (lo = hi = strtol(s, &pos, 0); is_good; lo = hi = strtol(pos + 1, &pos, 0)) { if (pos && *pos == '-') hi = strtol(pos + 1, &pos, 0); /* get end of range */ is_good = (pos && 0 <= lo && lo <= hi && hi <= 255); if (is_good) while (lo <= hi) bgClass[lo++] = (unsigned char)class_no; if (*pos != ',') break; } if ((is_good = (is_good && *pos == ':'))) { is_good = (*pos++ != '\0'); /* pos now points to color */ bgClassPixel[class_no] = allocBGColor(w, pos, &dummy); } if (!is_good) { /* complain? this class spec clause (in string s) was faulty */ } /* end of loop iterator clauses */ if (was_semicol) *semicol = ';'; /* un-null-terminate low[-high]:color clause */ s = semicol + was_semicol; } /* when we get here, we've set up our class table and class-to-pixel table in local variables: now put them into the "real thing" */ class_no++; /* bigger than all valid class_nos */ *pp_bgClass = (unsigned char *)XtMalloc(256); *pp_bgClassPixel = (Pixel *)XtMalloc(class_no * sizeof (Pixel)); if (!*pp_bgClass || !*pp_bgClassPixel) { XtFree((char *)*pp_bgClass); XtFree((char *)*pp_bgClassPixel); return; } memcpy(*pp_bgClass, bgClass, 256); memcpy(*pp_bgClassPixel, bgClassPixel, class_no * sizeof (Pixel)); } nedit-5.6.orig/source/textDisp.h0000644000175000017500000003005410737527370015404 0ustar paulpaul/* $Id: textDisp.h,v 1.31 2008/01/04 22:11:04 yooden Exp $ */ /******************************************************************************* * * * textDisp.h -- Nirvana Editor Text Diplay Header File * * * * Copyright 2003 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_TEXTDISP_H_INCLUDED #define NEDIT_TEXTDISP_H_INCLUDED #include "textBuf.h" #include #include #include enum cursorStyles {NORMAL_CURSOR, CARET_CURSOR, DIM_CURSOR, BLOCK_CURSOR, HEAVY_CURSOR}; #define NO_HINT -1 typedef struct { char *highlightName; char *styleName; char *colorName; char isBold; char isItalic; unsigned short red; unsigned short green; unsigned short blue; Pixel color; Boolean underline; XFontStruct *font; char *bgColorName; /* background style coloring (name may be NULL) */ unsigned short bgRed; unsigned short bgGreen; unsigned short bgBlue; Pixel bgColor; } styleTableEntry; typedef struct graphicExposeTranslationEntry { int horizontal; int vertical; struct graphicExposeTranslationEntry *next; } graphicExposeTranslationEntry; typedef void (*unfinishedStyleCBProc)(); typedef struct _calltipStruct { int ID; /* ID of displayed calltip. Equals zero if none is displayed. */ Boolean anchored; /* Is it anchored to a position */ int pos; /* Position tip is anchored to */ int hAlign; /* horizontal alignment */ int vAlign; /* vertical alignment */ int alignMode; /* Strict or sloppy alignment */ } calltipStruct; typedef struct _textDisp { Widget w; int top, left, width, height, lineNumLeft, lineNumWidth; int cursorPos; int cursorOn; int cursorX, cursorY; /* X, Y pos. of last drawn cursor Note: these are used for *drawing* and are not generally reliable for finding the insert position's x/y coordinates! */ int cursorToHint; /* Tells the buffer modified callback where to move the cursor, to reduce the number of redraw calls */ int cursorStyle; /* One of enum cursorStyles above */ int cursorPreferredCol; /* Column for vert. cursor movement */ int nVisibleLines; /* # of visible (displayed) lines */ int nBufferLines; /* # of newlines in the buffer */ textBuffer *buffer; /* Contains text to be displayed */ textBuffer *styleBuffer; /* Optional parallel buffer containing color and font information */ int firstChar, lastChar; /* Buffer positions of first and last displayed character (lastChar points either to a newline or one character beyond the end of the buffer) */ int continuousWrap; /* Wrap long lines when displaying */ int wrapMargin; /* Margin in # of char positions for wrapping in continuousWrap mode */ int *lineStarts; int topLineNum; /* Line number of top displayed line of file (first line of file is 1) */ int absTopLineNum; /* In continuous wrap mode, the line number of the top line if the text were not wrapped (note that this is only maintained as needed). */ int needAbsTopLineNum; /* Externally settable flag to continue maintaining absTopLineNum even if it isn't needed for line # display */ int horizOffset; /* Horizontal scroll pos. in pixels */ int visibility; /* Window visibility (see XVisibility event) */ int nStyles; /* Number of entries in styleTable */ styleTableEntry *styleTable; /* Table of fonts and colors for coloring/syntax-highlighting */ char unfinishedStyle; /* Style buffer entry which triggers on-the-fly reparsing of region */ unfinishedStyleCBProc /* Callback to parse "unfinished" */ unfinishedHighlightCB; /* regions */ void *highlightCBArg; /* Arg to unfinishedHighlightCB */ XFontStruct *fontStruct; /* Font structure for primary font */ int ascent, descent; /* Composite ascent and descent for primary font + all-highlight fonts */ int fixedFontWidth; /* Font width if all current fonts are fixed and match in width, else -1 */ Widget hScrollBar, vScrollBar; GC gc, selectGC, highlightGC; /* GCs for drawing text */ GC selectBGGC, highlightBGGC; /* GCs for erasing text */ GC cursorFGGC; /* GC for drawing the cursor */ GC lineNumGC; /* GC for drawing line numbers */ GC styleGC; /* GC with color and font unspecified for drawing colored/styled text */ Pixel fgPixel, bgPixel; /* Foreground/Background colors */ Pixel selectFGPixel, /* Foreground select color */ selectBGPixel; /* Background select color */ Pixel highlightFGPixel, /* Highlight colors are used when */ highlightBGPixel; /* flashing matching parens */ Pixel lineNumFGPixel; /* Color for drawing line numbers */ Pixel cursorFGPixel; Pixel *bgClassPixel; /* table of colors for each BG class */ unsigned char *bgClass; /* obtains index into bgClassPixel[] */ Widget calltipW; /* The Label widget for the calltip */ Widget calltipShell; /* The Shell that holds the calltip */ calltipStruct calltip; /* The info for the calltip itself */ Pixel calltipFGPixel; Pixel calltipBGPixel; int suppressResync; /* Suppress resynchronization of line starts during buffer updates */ int nLinesDeleted; /* Number of lines deleted during buffer modification (only used when resynchronization is suppressed) */ int modifyingTabDist; /* Whether tab distance is being modified */ Boolean pointerHidden; /* true if the mouse pointer is hidden */ graphicExposeTranslationEntry *graphicsExposeQueue; } textDisp; textDisp *TextDCreate(Widget widget, Widget hScrollBar, Widget vScrollBar, Position left, Position top, Position width, Position height, Position lineNumLeft, Position lineNumWidth, textBuffer *buffer, XFontStruct *fontStruct, Pixel bgPixel, Pixel fgPixel, Pixel selectFGPixel, Pixel selectBGPixel, Pixel highlightFGPixel, Pixel highlightBGPixel, Pixel cursorFGPixel, Pixel lineNumFGPixel, int continuousWrap, int wrapMargin, XmString bgClassString, Pixel calltipFGPixel, Pixel calltipBGPixel); void TextDFree(textDisp *textD); void TextDSetBuffer(textDisp *textD, textBuffer *buffer); void TextDAttachHighlightData(textDisp *textD, textBuffer *styleBuffer, styleTableEntry *styleTable, int nStyles, char unfinishedStyle, unfinishedStyleCBProc unfinishedHighlightCB, void *cbArg); void TextDSetColors(textDisp *textD, Pixel textFgP, Pixel textBgP, Pixel selectFgP, Pixel selectBgP, Pixel hiliteFgP, Pixel hiliteBgP, Pixel lineNoFgP, Pixel cursorFgP); void TextDSetFont(textDisp *textD, XFontStruct *fontStruct); int TextDMinFontWidth(textDisp *textD, Boolean considerStyles); int TextDMaxFontWidth(textDisp *textD, Boolean considerStyles); void TextDResize(textDisp *textD, int width, int height); void TextDRedisplayRect(textDisp *textD, int left, int top, int width, int height); void TextDSetScroll(textDisp *textD, int topLineNum, int horizOffset); void TextDGetScroll(textDisp *textD, int *topLineNum, int *horizOffset); void TextDInsert(textDisp *textD, char *text); void TextDOverstrike(textDisp *textD, char *text); void TextDSetInsertPosition(textDisp *textD, int newPos); int TextDGetInsertPosition(textDisp *textD); int TextDXYToPosition(textDisp *textD, int x, int y); int TextDXYToCharPos(textDisp *textD, int x, int y); void TextDXYToUnconstrainedPosition(textDisp *textD, int x, int y, int *row, int *column); int TextDLineAndColToPos(textDisp *textD, int lineNum, int column); int TextDOffsetWrappedColumn(textDisp *textD, int row, int column); int TextDOffsetWrappedRow(textDisp *textD, int row); int TextDPositionToXY(textDisp *textD, int pos, int *x, int *y); int TextDPosToLineAndCol(textDisp *textD, int pos, int *lineNum, int *column); int TextDInSelection(textDisp *textD, int x, int y); void TextDMakeInsertPosVisible(textDisp *textD); int TextDMoveRight(textDisp *textD); int TextDMoveLeft(textDisp *textD); int TextDMoveUp(textDisp *textD, int absolute); int TextDMoveDown(textDisp *textD, int absolute); void TextDBlankCursor(textDisp *textD); void TextDUnblankCursor(textDisp *textD); void TextDSetCursorStyle(textDisp *textD, int style); void TextDSetWrapMode(textDisp *textD, int wrap, int wrapMargin); int TextDEndOfLine(const textDisp* textD, const int pos, const Boolean startPosIsLineStart); int TextDStartOfLine(const textDisp* textD, const int pos); int TextDCountForwardNLines(const textDisp* textD, const int startPos, const unsigned nLines, const Boolean startPosIsLineStart); int TextDCountBackwardNLines(textDisp *textD, int startPos, int nLines); int TextDCountLines(textDisp *textD, int startPos, int endPos, int startPosIsLineStart); void TextDSetupBGClasses(Widget w, XmString str, Pixel **pp_bgClassPixel, unsigned char **pp_bgClass, Pixel bgPixelDefault); void TextDSetLineNumberArea(textDisp *textD, int lineNumLeft, int lineNumWidth, int textLeft); void TextDMaintainAbsLineNum(textDisp *textD, int state); int TextDPosOfPreferredCol(textDisp *textD, int column, int lineStartPos); int TextDPreferredColumn(textDisp *textD, int *visLineNum, int *lineStartPos); #ifdef VMS /* VMS linker doesn't like long names (>31 chars) */ #define TextDImposeGraphicsExposeTranslation TextDGraphicsExposeTranslation #endif /* VMS */ void TextDImposeGraphicsExposeTranslation(textDisp *textD, int *xOffset, int *yOffset); Boolean TextDPopGraphicExposeQueueEntry(textDisp *textD); void TextDTranlateGraphicExposeQueue(textDisp *textD, int xOffset, int yOffset, Boolean appendEntry); #endif /* NEDIT_TEXTDISP_H_INCLUDED */ nedit-5.6.orig/source/textDrag.c0000644000175000017500000005573410200115063015342 0ustar paulpaulstatic const char CVSID[] = "$Id: textDrag.c,v 1.11 2005/02/02 09:15:31 edg Exp $"; /******************************************************************************* * * * textDrag.c - Text Dragging routines for NEdit text widget * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * Dec. 15, 1995 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "textDrag.h" #include "textBuf.h" #include "textDisp.h" #include "textP.h" #include #include #include #include #include #if XmVersion >= 1002 #include #endif #ifdef HAVE_DEBUG_H #include "../debug.h" #endif static void trackModifyRange(int *rangeStart, int *modRangeEnd, int *unmodRangeEnd, int modPos, int nInserted, int nDeleted); static void findTextMargins(textBuffer *buf, int start, int end, int *leftMargin, int *rightMargin); static int findRelativeLineStart(textBuffer *buf, int referencePos, int referenceLineNum, int newLineNum); static int min3(int i1, int i2, int i3); static int max3(int i1, int i2, int i3); static int max(int i1, int i2); /* ** Start the process of dragging the current primary-selected text across ** the window (move by dragging, as opposed to dragging to create the ** selection) */ void BeginBlockDrag(TextWidget tw) { textDisp *textD = tw->text.textD; textBuffer *buf = textD->buffer; int fontHeight = textD->fontStruct->ascent + textD->fontStruct->descent; int fontWidth = textD->fontStruct->max_bounds.width; selection *sel = &buf->primary; int nLines, mousePos, lineStart; int x, y, lineEnd; char *text; /* Save a copy of the whole text buffer as a backup, and for deriving changes */ tw->text.dragOrigBuf = BufCreate(); BufSetTabDistance(tw->text.dragOrigBuf, buf->tabDist); tw->text.dragOrigBuf->useTabs = buf->useTabs; text = BufGetAll(buf); BufSetAll(tw->text.dragOrigBuf, text); XtFree(text); if (sel->rectangular) BufRectSelect(tw->text.dragOrigBuf, sel->start, sel->end, sel->rectStart, sel->rectEnd); else BufSelect(tw->text.dragOrigBuf, sel->start, sel->end); /* Record the mouse pointer offsets from the top left corner of the selection (the position where text will actually be inserted In dragging non-rectangular selections) */ if (sel->rectangular) { tw->text.dragXOffset = tw->text.btnDownX + textD->horizOffset - textD->left - sel->rectStart * fontWidth; } else { if (!TextDPositionToXY(textD, sel->start, &x, &y)) x = BufCountDispChars(buf, TextDStartOfLine(textD, sel->start), sel->start) * fontWidth + textD->left - textD->horizOffset; tw->text.dragXOffset = tw->text.btnDownX - x; } mousePos = TextDXYToPosition(textD, tw->text.btnDownX, tw->text.btnDownY); nLines = BufCountLines(buf, sel->start, mousePos); tw->text.dragYOffset = nLines * fontHeight + (((tw->text.btnDownY - tw->text.marginHeight) % fontHeight) - fontHeight/2); tw->text.dragNLines = BufCountLines(buf, sel->start, sel->end); /* Record the current drag insert position and the information for undoing the fictional insert of the selection in its new position */ tw->text.dragInsertPos = sel->start; tw->text.dragInserted = sel->end - sel->start; if (sel->rectangular) { textBuffer *testBuf = BufCreate(); char *testText = BufGetRange(buf, sel->start, sel->end); BufSetTabDistance(testBuf, buf->tabDist); testBuf->useTabs = buf->useTabs; BufSetAll(testBuf, testText); XtFree(testText); BufRemoveRect(testBuf, 0, sel->end - sel->start, sel->rectStart, sel->rectEnd); tw->text.dragDeleted = testBuf->length; BufFree(testBuf); tw->text.dragRectStart = sel->rectStart; } else { tw->text.dragDeleted = 0; tw->text.dragRectStart = 0; } tw->text.dragType = DRAG_MOVE; tw->text.dragSourceDeletePos = sel->start; tw->text.dragSourceInserted = tw->text.dragDeleted; tw->text.dragSourceDeleted = tw->text.dragInserted; /* For non-rectangular selections, fill in the rectangular information in the selection for overlay mode drags which are done rectangularly */ if (!sel->rectangular) { lineStart = BufStartOfLine(buf, sel->start); if (tw->text.dragNLines == 0) { tw->text.dragOrigBuf->primary.rectStart = BufCountDispChars(buf, lineStart, sel->start); tw->text.dragOrigBuf->primary.rectEnd = BufCountDispChars(buf, lineStart, sel->end); } else { lineEnd = BufGetCharacter(buf, sel->end - 1) == '\n' ? sel->end - 1 : sel->end; findTextMargins(buf, lineStart, lineEnd, &tw->text.dragOrigBuf->primary.rectStart, &tw->text.dragOrigBuf->primary.rectEnd); } } /* Set the drag state to announce an ongoing block-drag */ tw->text.dragState = PRIMARY_BLOCK_DRAG; /* Call the callback announcing the start of a block drag */ XtCallCallbacks((Widget)tw, textNdragStartCallback, (XtPointer)NULL); } /* ** Reposition the primary-selected text that is being dragged as a block ** for a new mouse position of (x, y) */ void BlockDragSelection(TextWidget tw, int x, int y, int dragType) { textDisp *textD = tw->text.textD; textBuffer *buf = textD->buffer; int fontHeight = textD->fontStruct->ascent + textD->fontStruct->descent; int fontWidth = textD->fontStruct->max_bounds.width; textBuffer *origBuf = tw->text.dragOrigBuf; int dragXOffset = tw->text.dragXOffset; textBuffer *tempBuf; selection *origSel = &origBuf->primary; int rectangular = origSel->rectangular; int overlay, oldDragType = tw->text.dragType; int nLines = tw->text.dragNLines; int insLineNum, insLineStart, insRectStart, insRectEnd, insStart; char *repText, *text, *insText; int modRangeStart = -1, tempModRangeEnd = -1, bufModRangeEnd = -1; int referenceLine, referencePos, tempStart, tempEnd, origSelLen; int insertInserted, insertDeleted, row, column; int origSelLineStart, origSelLineEnd; int sourceInserted, sourceDeleted, sourceDeletePos; if (tw->text.dragState != PRIMARY_BLOCK_DRAG) return; /* The operation of block dragging is simple in theory, but not so simple in practice. There is a backup buffer (tw->text.dragOrigBuf) which holds a copy of the buffer as it existed before the drag. When the user drags the mouse to a new location, this routine is called, and a temporary buffer is created and loaded with the local part of the buffer (from the backup) which might be changed by the drag. The changes are all made to this temporary buffer, and the parts of this buffer which then differ from the real (displayed) buffer are used to replace those parts, thus one replace operation serves as both undo and modify. This double-buffering of the operation prevents excessive redrawing (though there is still plenty of needless redrawing due to re-selection and rectangular operations). The hard part is keeping track of the changes such that a single replace operation will do everyting. This is done using a routine called trackModifyRange which tracks expanding ranges of changes in the two buffers in modRangeStart, tempModRangeEnd, and bufModRangeEnd. */ /* Create a temporary buffer for accumulating changes which will eventually be replaced in the real buffer. Load the buffer with the range of characters which might be modified in this drag step (this could be tighter, but hopefully it's not too slow) */ tempBuf = BufCreate(); tempBuf->tabDist = buf->tabDist; tempBuf->useTabs = buf->useTabs; tempStart = min3(tw->text.dragInsertPos, origSel->start, BufCountBackwardNLines(buf, textD->firstChar, nLines+2)); tempEnd = BufCountForwardNLines(buf, max3(tw->text.dragInsertPos, origSel->start, textD->lastChar), nLines+2) + origSel->end - origSel->start; text = BufGetRange(origBuf, tempStart, tempEnd); BufSetAll(tempBuf, text); XtFree(text); /* If the drag type is USE_LAST, use the last dragType applied */ if (dragType == USE_LAST) dragType = tw->text.dragType; overlay = dragType == DRAG_OVERLAY_MOVE || dragType == DRAG_OVERLAY_COPY; /* Overlay mode uses rectangular selections whether or not the original was rectangular. To use a plain selection as if it were rectangular, the start and end positions need to be moved to the line boundaries and trailing newlines must be excluded */ origSelLineStart = BufStartOfLine(origBuf, origSel->start); if (!rectangular && BufGetCharacter(origBuf, origSel->end - 1) == '\n') origSelLineEnd = origSel->end - 1; else origSelLineEnd = BufEndOfLine(origBuf, origSel->end); if (!rectangular && overlay && nLines != 0) dragXOffset -= fontWidth * (origSel->rectStart - (origSel->start - origSelLineStart)); /* If the drag operation is of a different type than the last one, and the operation is a move, expand the modified-range to include undoing the text-removal at the site from which the text was dragged. */ if (dragType != oldDragType && tw->text.dragSourceDeleted != 0) trackModifyRange(&modRangeStart, &bufModRangeEnd, &tempModRangeEnd, tw->text.dragSourceDeletePos, tw->text.dragSourceInserted, tw->text.dragSourceDeleted); /* Do, or re-do the original text removal at the site where a move began. If this part has not changed from the last call, do it silently to bring the temporary buffer in sync with the real (displayed) buffer. If it's being re-done, track the changes to complete the redo operation begun above */ if (dragType == DRAG_MOVE || dragType == DRAG_OVERLAY_MOVE) { if (rectangular || overlay) { int prevLen = tempBuf->length; origSelLen = origSelLineEnd - origSelLineStart; if (overlay) BufClearRect(tempBuf, origSelLineStart-tempStart, origSelLineEnd-tempStart, origSel->rectStart, origSel->rectEnd); else BufRemoveRect(tempBuf, origSelLineStart-tempStart, origSelLineEnd-tempStart, origSel->rectStart, origSel->rectEnd); sourceDeletePos = origSelLineStart; sourceInserted = origSelLen - prevLen + tempBuf->length; sourceDeleted = origSelLen; } else { BufRemove(tempBuf, origSel->start - tempStart, origSel->end - tempStart); sourceDeletePos = origSel->start; sourceInserted = 0; sourceDeleted = origSel->end - origSel->start; } if (dragType != oldDragType) trackModifyRange(&modRangeStart, &tempModRangeEnd, &bufModRangeEnd, sourceDeletePos, sourceInserted, sourceDeleted); } else { sourceDeletePos = 0; sourceInserted = 0; sourceDeleted = 0; } /* Expand the modified-range to include undoing the insert from the last call. */ trackModifyRange(&modRangeStart, &bufModRangeEnd, &tempModRangeEnd, tw->text.dragInsertPos, tw->text.dragInserted, tw->text.dragDeleted); /* Find the line number and column of the insert position. Note that in continuous wrap mode, these must be calculated as if the text were not wrapped */ TextDXYToUnconstrainedPosition(textD, max(0, x - dragXOffset), max(0, y - (tw->text.dragYOffset % fontHeight)), &row, &column); column = TextDOffsetWrappedColumn(textD, row, column); row = TextDOffsetWrappedRow(textD, row); insLineNum = row + textD->topLineNum - tw->text.dragYOffset / fontHeight; /* find a common point of reference between the two buffers, from which the insert position line number can be translated to a position */ if (textD->firstChar > modRangeStart) { referenceLine = textD->topLineNum - BufCountLines(buf, modRangeStart, textD->firstChar); referencePos = modRangeStart; } else { referencePos = textD->firstChar; referenceLine = textD->topLineNum; } /* find the position associated with the start of the new line in the temporary buffer */ insLineStart = findRelativeLineStart(tempBuf, referencePos - tempStart, referenceLine, insLineNum) + tempStart; if (insLineStart - tempStart == tempBuf->length) insLineStart = BufStartOfLine(tempBuf, insLineStart - tempStart) + tempStart; /* Find the actual insert position */ if (rectangular || overlay) { insStart = insLineStart; insRectStart = column; } else { /* note, this will fail with proportional fonts */ insStart = BufCountForwardDispChars(tempBuf, insLineStart - tempStart, column) + tempStart; insRectStart = 0; } /* If the position is the same as last time, don't bother drawing (it would be nice if this decision could be made earlier) */ if (insStart == tw->text.dragInsertPos && insRectStart == tw->text.dragRectStart && dragType == oldDragType) { BufFree(tempBuf); return; } /* Do the insert in the temporary buffer */ if (rectangular || overlay) { insText = BufGetTextInRect(origBuf, origSelLineStart, origSelLineEnd, origSel->rectStart, origSel->rectEnd); if (overlay) BufOverlayRect(tempBuf, insStart - tempStart, insRectStart, insRectStart + origSel->rectEnd - origSel->rectStart, insText, &insertInserted, &insertDeleted); else BufInsertCol(tempBuf, insRectStart, insStart - tempStart, insText, &insertInserted, &insertDeleted); trackModifyRange(&modRangeStart, &tempModRangeEnd, &bufModRangeEnd, insStart, insertInserted, insertDeleted); XtFree(insText); } else { insText = BufGetSelectionText(origBuf); BufInsert(tempBuf, insStart - tempStart, insText); trackModifyRange(&modRangeStart, &tempModRangeEnd, &bufModRangeEnd, insStart, origSel->end - origSel->start, 0); insertInserted = origSel->end - origSel->start; insertDeleted = 0; XtFree(insText); } /* Make the changes in the real buffer */ repText = BufGetRange(tempBuf, modRangeStart - tempStart, tempModRangeEnd - tempStart); BufFree(tempBuf); TextDBlankCursor(textD); BufReplace(buf, modRangeStart, bufModRangeEnd, repText); XtFree(repText); /* Store the necessary information for undoing this step */ tw->text.dragInsertPos = insStart; tw->text.dragRectStart = insRectStart; tw->text.dragInserted = insertInserted; tw->text.dragDeleted = insertDeleted; tw->text.dragSourceDeletePos = sourceDeletePos; tw->text.dragSourceInserted = sourceInserted; tw->text.dragSourceDeleted = sourceDeleted; tw->text.dragType = dragType; /* Reset the selection and cursor position */ if (rectangular || overlay) { insRectEnd = insRectStart + origSel->rectEnd - origSel->rectStart; BufRectSelect(buf, insStart, insStart + insertInserted, insRectStart, insRectEnd); TextDSetInsertPosition(textD, BufCountForwardDispChars(buf, BufCountForwardNLines(buf, insStart, tw->text.dragNLines), insRectEnd)); } else { BufSelect(buf, insStart, insStart + origSel->end - origSel->start); TextDSetInsertPosition(textD, insStart + origSel->end - origSel->start); } TextDUnblankCursor(textD); XtCallCallbacks((Widget)tw, textNcursorMovementCallback, (XtPointer)NULL); tw->text.emTabsBeforeCursor = 0; } /* ** Complete a block text drag operation */ void FinishBlockDrag(TextWidget tw) { dragEndCBStruct endStruct; int modRangeStart = -1, origModRangeEnd, bufModRangeEnd; char *deletedText; /* Find the changed region of the buffer, covering both the deletion of the selected text at the drag start position, and insertion at the drag destination */ trackModifyRange(&modRangeStart, &bufModRangeEnd, &origModRangeEnd, tw->text.dragSourceDeletePos, tw->text.dragSourceInserted, tw->text.dragSourceDeleted); trackModifyRange(&modRangeStart, &bufModRangeEnd, &origModRangeEnd, tw->text.dragInsertPos, tw->text.dragInserted, tw->text.dragDeleted); /* Get the original (pre-modified) range of text from saved backup buffer */ deletedText = BufGetRange(tw->text.dragOrigBuf, modRangeStart, origModRangeEnd); /* Free the backup buffer */ BufFree(tw->text.dragOrigBuf); /* Return to normal drag state */ tw->text.dragState = NOT_CLICKED; /* Call finish-drag calback */ endStruct.startPos = modRangeStart; endStruct.nCharsDeleted = origModRangeEnd - modRangeStart; endStruct.nCharsInserted = bufModRangeEnd - modRangeStart; endStruct.deletedText = deletedText; XtCallCallbacks((Widget)tw, textNdragEndCallback, (XtPointer)&endStruct); XtFree(deletedText); } /* ** Cancel a block drag operation */ void CancelBlockDrag(TextWidget tw) { textBuffer *buf = tw->text.textD->buffer; textBuffer *origBuf = tw->text.dragOrigBuf; selection *origSel = &origBuf->primary; int modRangeStart = -1, origModRangeEnd, bufModRangeEnd; char *repText; dragEndCBStruct endStruct; /* If the operation was a move, make the modify range reflect the removal of the text from the starting position */ if (tw->text.dragSourceDeleted != 0) trackModifyRange(&modRangeStart, &bufModRangeEnd, &origModRangeEnd, tw->text.dragSourceDeletePos, tw->text.dragSourceInserted, tw->text.dragSourceDeleted); /* Include the insert being undone from the last step in the modified range. */ trackModifyRange(&modRangeStart, &bufModRangeEnd, &origModRangeEnd, tw->text.dragInsertPos, tw->text.dragInserted, tw->text.dragDeleted); /* Make the changes in the buffer */ repText = BufGetRange(origBuf, modRangeStart, origModRangeEnd); BufReplace(buf, modRangeStart, bufModRangeEnd, repText); XtFree(repText); /* Reset the selection and cursor position */ if (origSel->rectangular) BufRectSelect(buf, origSel->start, origSel->end, origSel->rectStart, origSel->rectEnd); else BufSelect(buf, origSel->start, origSel->end); TextDSetInsertPosition(tw->text.textD, buf->cursorPosHint); XtCallCallbacks((Widget)tw, textNcursorMovementCallback, NULL); tw->text.emTabsBeforeCursor = 0; /* Free the backup buffer */ BufFree(origBuf); /* Indicate end of drag */ tw->text.dragState = DRAG_CANCELED; /* Call finish-drag calback */ endStruct.startPos = 0; endStruct.nCharsDeleted = 0; endStruct.nCharsInserted = 0; endStruct.deletedText = NULL; XtCallCallbacks((Widget)tw, textNdragEndCallback, (XtPointer)&endStruct); } /* ** Maintain boundaries of changed region between two buffers which ** start out with identical contents, but diverge through insertion, ** deletion, and replacement, such that the buffers can be reconciled ** by replacing the changed region of either buffer with the changed ** region of the other. ** ** rangeStart is the beginning of the modification region in the shared ** coordinates of both buffers (which are identical up to rangeStart). ** modRangeEnd is the end of the changed region for the buffer being ** modified, unmodRangeEnd is the end of the region for the buffer NOT ** being modified. A value of -1 in rangeStart indicates that there ** have been no modifications so far. */ static void trackModifyRange(int *rangeStart, int *modRangeEnd, int *unmodRangeEnd, int modPos, int nInserted, int nDeleted) { if (*rangeStart == -1) { *rangeStart = modPos; *modRangeEnd = modPos + nInserted; *unmodRangeEnd = modPos + nDeleted; } else { if (modPos < *rangeStart) *rangeStart = modPos; if (modPos + nDeleted > *modRangeEnd) { *unmodRangeEnd += modPos + nDeleted - *modRangeEnd; *modRangeEnd = modPos + nInserted; } else *modRangeEnd += nInserted - nDeleted; } } /* ** Find the left and right margins of text between "start" and "end" in ** buffer "buf". Note that "start is assumed to be at the start of a line. */ static void findTextMargins(textBuffer *buf, int start, int end, int *leftMargin, int *rightMargin) { char c; int pos, width = 0, maxWidth = 0, minWhite = INT_MAX, inWhite = True; for (pos=start; pos maxWidth) maxWidth = width; width = 0; inWhite = True; } else width += BufCharWidth(c, width, buf->tabDist, buf->nullSubsChar); } if (width > maxWidth) maxWidth = width; *leftMargin = minWhite == INT_MAX ? 0 : minWhite; *rightMargin = maxWidth; } /* ** Find a text position in buffer "buf" by counting forward or backward ** from a reference position with known line number */ static int findRelativeLineStart(textBuffer *buf, int referencePos, int referenceLineNum, int newLineNum) { if (newLineNum < referenceLineNum) return BufCountBackwardNLines(buf, referencePos, referenceLineNum - newLineNum); else if (newLineNum > referenceLineNum) return BufCountForwardNLines(buf, referencePos, newLineNum - referenceLineNum); return BufStartOfLine(buf, referencePos); } static int min3(int i1, int i2, int i3) { if (i1 <= i2 && i1 <= i3) return i1; return i2 <= i3 ? i2 : i3; } static int max3(int i1, int i2, int i3) { if (i1 >= i2 && i1 >= i3) return i1; return i2 >= i3 ? i2 : i3; } static int max(int i1, int i2) { return i1 >= i2 ? i1 : i2; } nedit-5.6.orig/source/textDrag.h0000644000175000017500000000467310144236625015362 0ustar paulpaul/* $Id: textDrag.h,v 1.5 2004/11/09 21:58:45 yooden Exp $ */ /******************************************************************************* * * * textDrag.h -- Nirvana Editor Drag/Drop Header File * * * * Copyright 2004 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_TEXTDRAG_H_INCLUDED #define NEDIT_TEXTDRAG_H_INCLUDED #include "text.h" enum blockDragTypes {USE_LAST, DRAG_COPY, DRAG_MOVE, DRAG_OVERLAY_MOVE, DRAG_OVERLAY_COPY}; void BeginBlockDrag(TextWidget tw); void BlockDragSelection(TextWidget tw, int x, int y, int dragType); void FinishBlockDrag(TextWidget tw); void CancelBlockDrag(TextWidget tw); #endif /* NEDIT_TEXTDRAG_H_INCLUDED */ nedit-5.6.orig/source/textP.h0000644000175000017500000001433710144236625014702 0ustar paulpaul/* $Id: textP.h,v 1.12 2004/11/09 21:58:45 yooden Exp $ */ /******************************************************************************* * * * textP.h -- Nirvana Editor Text Editing Widget private include file * * * * Copyright 2003 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_TEXTP_H_INCLUDED #define NEDIT_TEXTP_H_INCLUDED #include "textBuf.h" #include "textDisp.h" #include #include #include #include #include #include enum dragStates {NOT_CLICKED, PRIMARY_CLICKED, SECONDARY_CLICKED, CLICKED_IN_SELECTION, PRIMARY_DRAG, PRIMARY_RECT_DRAG, SECONDARY_DRAG, SECONDARY_RECT_DRAG, PRIMARY_BLOCK_DRAG, DRAG_CANCELED, MOUSE_PAN}; enum multiClickStates {NO_CLICKS, ONE_CLICK, TWO_CLICKS, THREE_CLICKS}; typedef struct _TextClassPart{ int ignore; } TextClassPart; typedef struct _TextClassRec{ CoreClassPart core_class; XmPrimitiveClassPart primitive_class; TextClassPart text_class; } TextClassRec; extern TextClassRec nTextClassRec; typedef struct _TextPart { /* resources */ Pixel selectFGPixel, selectBGPixel, highlightFGPixel, highlightBGPixel; Pixel cursorFGPixel, lineNumFGPixel, calltipFGPixel, calltipBGPixel; XFontStruct *fontStruct; Boolean pendingDelete; Boolean autoShowInsertPos; Boolean autoWrap; Boolean autoWrapPastedText; Boolean continuousWrap; Boolean autoIndent; Boolean smartIndent; Boolean overstrike; Boolean heavyCursor; Boolean readOnly; Boolean hidePointer; int rows, columns; int marginWidth, marginHeight; int cursorBlinkRate; int wrapMargin; int emulateTabs; int lineNumCols; char *delimiters; Cardinal cursorVPadding; Widget hScrollBar, vScrollBar; XtCallbackList focusInCB; XtCallbackList focusOutCB; XtCallbackList cursorCB; XtCallbackList dragStartCB; XtCallbackList dragEndCB; XtCallbackList smartIndentCB; /* private state */ textDisp *textD; /* Pointer to display information */ int anchor, rectAnchor; /* Anchors for drag operations and rectangular drag operations */ int dragState; /* Why is the mouse being dragged and what is being acquired */ int multiClickState; /* How long is this multi-click sequence so far */ int btnDownX, btnDownY; /* Mark the position of last btn down action for deciding when to begin paying attention to motion actions, and where to paste columns */ Time lastBtnDown; /* Timestamp of last button down event for multi-click recognition */ int mouseX, mouseY; /* Last known mouse position in drag operation (for autoscroll) */ int selectionOwner; /* True if widget owns the selection */ int motifDestOwner; /* " " owns the motif destination */ int emTabsBeforeCursor; /* If non-zero, number of consecutive emulated tabs just entered. Saved so chars can be deleted as a unit */ XtIntervalId autoScrollProcID; /* id of Xt timer proc for autoscroll */ XtIntervalId cursorBlinkProcID; /* id of timer proc for cursor blink */ textBuffer *dragOrigBuf; /* backup buffer copy used during block dragging of selections */ int dragXOffset, dragYOffset; /* offsets between cursor location and actual insertion point in drag */ int dragType; /* style of block drag operation */ int dragInsertPos; /* location where text being block dragged was last inserted */ int dragRectStart; /* rect. offset "" */ int dragInserted; /* # of characters inserted at drag destination in last drag position */ int dragDeleted; /* # of characters deleted "" */ int dragSourceDeletePos; /* location from which move source text was removed at start of drag */ int dragSourceInserted; /* # of chars. inserted when move source text was deleted */ int dragSourceDeleted; /* # of chars. deleted "" */ int dragNLines; /* # of newlines in text being drag'd */ XmString backlightCharTypes; /* background class string to parse */ } TextPart; typedef struct _TextRec { CorePart core; XmPrimitivePart primitive; TextPart text; } TextRec; #endif /* NEDIT_TEXTP_H_INCLUDED */ nedit-5.6.orig/source/textSel.c0000644000175000017500000010265410737527371015232 0ustar paulpaulstatic const char CVSID[] = "$Id: textSel.c,v 1.19 2008/01/04 22:11:05 yooden Exp $"; /******************************************************************************* * * * textSel.c - Selection and clipboard routines for NEdit text widget * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * Dec. 15, 1995 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "textSel.h" #include "textP.h" #include "text.h" #include "textDisp.h" #include "textBuf.h" #include "../util/misc.h" #include #include #include #include #include #include #include #if XmVersion >= 1002 #include #endif #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #define N_SELECT_TARGETS 7 #define N_ATOMS 11 enum atomIndex {A_TEXT, A_TARGETS, A_MULTIPLE, A_TIMESTAMP, A_INSERT_SELECTION, A_DELETE, A_CLIPBOARD, A_INSERT_INFO, A_ATOM_PAIR, A_MOTIF_DESTINATION, A_COMPOUND_TEXT}; /* Results passed back to the convert proc processing an INSERT_SELECTION request, by getInsertSelection when the selection to insert has been received and processed */ enum insertResultFlags {INSERT_WAITING, UNSUCCESSFUL_INSERT, SUCCESSFUL_INSERT}; /* Actions for selection notify event handler upon receiving confermation of a successful convert selection request */ enum selectNotifyActions {UNSELECT_SECONDARY, REMOVE_SECONDARY, EXCHANGE_SECONDARY}; /* temporary structure for passing data to the event handler for completing selection requests (the hard way, via xlib calls) */ typedef struct { int action; XtIntervalId timeoutProcID; Time timeStamp; Widget widget; char *actionText; int length; } selectNotifyInfo; static void modifiedCB(int pos, int nInserted, int nDeleted, int nRestyled, const char *deletedText, void *cbArg); static void sendSecondary(Widget w, Time time, Atom sel, int action, char *actionText, int actionTextLen); static void getSelectionCB(Widget w, XtPointer clientData, Atom *selType, Atom *type, XtPointer value, unsigned long *length, int *format); static void getInsertSelectionCB(Widget w, XtPointer clientData,Atom *selType, Atom *type, XtPointer value, unsigned long *length, int *format); static void getExchSelCB(Widget w, XtPointer clientData, Atom *selType, Atom *type, XtPointer value, unsigned long *length, int *format); static Boolean convertSelectionCB(Widget w, Atom *selType, Atom *target, Atom *type, XtPointer *value, unsigned long *length, int *format); static void loseSelectionCB(Widget w, Atom *selType); static Boolean convertSecondaryCB(Widget w, Atom *selType, Atom *target, Atom *type, XtPointer *value, unsigned long *length, int *format); static void loseSecondaryCB(Widget w, Atom *selType); static Boolean convertMotifDestCB(Widget w, Atom *selType, Atom *target, Atom *type, XtPointer *value, unsigned long *length, int *format); static void loseMotifDestCB(Widget w, Atom *selType); static void selectNotifyEH(Widget w, XtPointer data, XEvent *event, Boolean *continueDispatch); static void selectNotifyTimerProc(XtPointer clientData, XtIntervalId *id); static Atom getAtom(Display *display, int atomNum); /* ** Designate text widget "w" to be the selection owner for primary selections ** in its attached buffer (a buffer can be attached to multiple text widgets). */ void HandleXSelections(Widget w) { int i; textBuffer *buf = ((TextWidget)w)->text.textD->buffer; /* Remove any existing selection handlers for other widgets */ for (i=0; inModifyProcs; i++) { if (buf->modifyProcs[i] == modifiedCB) { BufRemoveModifyCB(buf, modifiedCB, buf->cbArgs[i]); break; } } /* Add a handler with this widget as the CB arg (and thus the sel. owner) */ BufAddModifyCB(((TextWidget)w)->text.textD->buffer, modifiedCB, w); } /* ** Discontinue ownership of selections for widget "w"'s attached buffer ** (if "w" was the designated selection owner) */ void StopHandlingXSelections(Widget w) { int i; textBuffer *buf = ((TextWidget)w)->text.textD->buffer; for (i=0; inModifyProcs; i++) { if (buf->modifyProcs[i] == modifiedCB && buf->cbArgs[i] == w) { BufRemoveModifyCB(buf, modifiedCB, buf->cbArgs[i]); return; } } } /* ** Copy the primary selection to the clipboard */ void CopyToClipboard(Widget w, Time time) { char *text; long itemID = 0; XmString s; int stat, length; /* Get the selected text, if there's no selection, do nothing */ text = BufGetSelectionText(((TextWidget)w)->text.textD->buffer); if (*text == '\0') { XtFree(text); return; } /* If the string contained ascii-nul characters, something else was substituted in the buffer. Put the nulls back */ length = strlen(text); BufUnsubstituteNullChars(text, ((TextWidget)w)->text.textD->buffer); /* Shut up LessTif */ if (SpinClipboardLock(XtDisplay(w), XtWindow(w)) != ClipboardSuccess) { XtFree(text); return; } /* Use the XmClipboard routines to copy the text to the clipboard. If errors occur, just give up. */ s = XmStringCreateSimple("NEdit"); stat = SpinClipboardStartCopy(XtDisplay(w), XtWindow(w), s, time, w, NULL, &itemID); XmStringFree(s); if (stat != ClipboardSuccess) { SpinClipboardUnlock(XtDisplay(w), XtWindow(w)); return; } /* Note that we were previously passing length + 1 here, but I suspect that this was inconsistent with the somewhat ambiguous policy of including a terminating null but not mentioning it in the length */ if (SpinClipboardCopy(XtDisplay(w), XtWindow(w), itemID, "STRING", text, length, 0, NULL) != ClipboardSuccess) { XtFree(text); SpinClipboardEndCopy(XtDisplay(w), XtWindow(w), itemID); SpinClipboardUnlock(XtDisplay(w), XtWindow(w)); return; } XtFree(text); SpinClipboardEndCopy(XtDisplay(w), XtWindow(w), itemID); SpinClipboardUnlock(XtDisplay(w), XtWindow(w)); } /* ** Insert the X PRIMARY selection (from whatever window currently owns it) ** at the cursor position. */ void InsertPrimarySelection(Widget w, Time time, int isColumnar) { static int isColFlag; /* Theoretically, strange things could happen if the user managed to get in any events between requesting receiving the selection data, however, getSelectionCB simply inserts the selection at the cursor. Don't bother with further measures until real problems are observed. */ isColFlag = isColumnar; XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, getSelectionCB, &isColFlag, time); } /* ** Insert the secondary selection at the motif destination by initiating ** an INSERT_SELECTION request to the current owner of the MOTIF_DESTINATION ** selection. Upon completion, unselect the secondary selection. If ** "removeAfter" is true, also delete the secondary selection from the ** widget's buffer upon completion. */ void SendSecondarySelection(Widget w, Time time, int removeAfter) { sendSecondary(w, time, getAtom(XtDisplay(w), A_MOTIF_DESTINATION), removeAfter ? REMOVE_SECONDARY : UNSELECT_SECONDARY, NULL, 0); } /* ** Exchange Primary and secondary selections (to be called by the widget ** with the secondary selection) */ void ExchangeSelections(Widget w, Time time) { if (!((TextWidget)w)->text.textD->buffer->secondary.selected) return; /* Initiate an long series of events: 1) get the primary selection, 2) replace the primary selection with this widget's secondary, 3) replace this widget's secondary with the text returned from getting the primary selection. This could be done with a much more efficient MULTIPLE request following ICCCM conventions, but the X toolkit MULTIPLE handling routines can't handle INSERT_SELECTION requests inside of MULTIPLE requests, because they don't allow access to the requested property atom in inside of an XtConvertSelectionProc. It's simply not worth duplicating all of Xt's selection handling routines for a little performance, and this would make the code incompatible with Motif text widgets */ XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, getExchSelCB, NULL, time); } /* ** Insert the contents of the PRIMARY selection at the cursor position in ** widget "w" and delete the contents of the selection in its current owner ** (if the selection owner supports DELETE targets). */ void MovePrimarySelection(Widget w, Time time, int isColumnar) { static Atom targets[2] = {XA_STRING}; static int isColFlag; static XtPointer clientData[2] = {(XtPointer)&isColFlag, (XtPointer)&isColFlag}; targets[1] = getAtom(XtDisplay(w), A_DELETE); isColFlag = isColumnar; /* some strangeness here: the selection callback appears to be getting clientData[1] for targets[0] */ XtGetSelectionValues(w, XA_PRIMARY, targets, 2, getSelectionCB, clientData, time); } /* ** Insert the X CLIPBOARD selection at the cursor position. If isColumnar, ** do an BufInsertCol for a columnar paste instead of BufInsert. */ void InsertClipboard(Widget w, int isColumnar) { unsigned long length, retLength; textDisp *textD = ((TextWidget)w)->text.textD; textBuffer *buf = ((TextWidget)w)->text.textD->buffer; int cursorLineStart, column, cursorPos; char *string; long id = 0; /* Get the clipboard contents. Note: this code originally used the CLIPBOARD selection, rather than the Motif clipboard interface. It was changed because Motif widgets in the same application would hang when users pasted data from nedit text widgets. This happened because the XmClipboard routines used by the widgets do blocking event reads, preventing a response by a selection owner in the same application. While the Motif clipboard routines as they are used below, limit the size of the data that be transferred via the clipboard, and are generally slower and buggier, they do preserve the clipboard across widget destruction and even program termination. */ if (SpinClipboardInquireLength(XtDisplay(w), XtWindow(w), "STRING", &length) != ClipboardSuccess || length == 0) { /* * Possibly, the clipboard can remain in a locked state after * a failure, so we try to remove the lock, just to be sure. */ SpinClipboardUnlock(XtDisplay(w), XtWindow(w)); return; } string = XtMalloc(length+1); if (SpinClipboardRetrieve(XtDisplay(w), XtWindow(w), "STRING", string, length, &retLength, &id) != ClipboardSuccess || retLength == 0) { XtFree(string); /* * Possibly, the clipboard can remain in a locked state after * a failure, so we try to remove the lock, just to be sure. */ SpinClipboardUnlock(XtDisplay(w), XtWindow(w)); return; } string[retLength] = '\0'; /* If the string contains ascii-nul characters, substitute something else, or give up, warn, and refuse */ if (!BufSubstituteNullChars(string, retLength, buf)) { fprintf(stderr, "Too much binary data, text not pasted\n"); XtFree(string); return; } /* Insert it in the text widget */ if (isColumnar && !buf->primary.selected) { cursorPos = TextDGetInsertPosition(textD); cursorLineStart = BufStartOfLine(buf, cursorPos); column = BufCountDispChars(buf, cursorLineStart, cursorPos); if (((TextWidget)w)->text.overstrike) { BufOverlayRect(buf, cursorLineStart, column, -1, string, NULL, NULL); } else { BufInsertCol(buf, column, cursorLineStart, string, NULL, NULL); } TextDSetInsertPosition(textD, BufCountForwardDispChars(buf, cursorLineStart, column)); if (((TextWidget)w)->text.autoShowInsertPos) TextDMakeInsertPosVisible(textD); } else TextInsertAtCursor(w, string, NULL, True, ((TextWidget)w)->text.autoWrapPastedText); XtFree(string); } /* ** Take ownership of the MOTIF_DESTINATION selection. This is Motif's private ** selection type for designating a widget to receive the result of ** secondary quick action requests. The NEdit text widget uses this also ** for compatibility with Motif text widgets. */ void TakeMotifDestination(Widget w, Time time) { if (((TextWidget)w)->text.motifDestOwner || ((TextWidget)w)->text.readOnly) return; /* Take ownership of the MOTIF_DESTINATION selection */ if (!XtOwnSelection(w, getAtom(XtDisplay(w), A_MOTIF_DESTINATION), time, convertMotifDestCB, loseMotifDestCB, NULL)) { return; } ((TextWidget)w)->text.motifDestOwner = True; } /* ** This routine is called every time there is a modification made to the ** buffer to which this callback is attached, with an argument of the text ** widget that has been designated (by HandleXSelections) to handle its ** selections. It checks if the status of the selection in the buffer ** has changed since last time, and owns or disowns the X selection depending ** on the status of the primary selection in the buffer. If it is not allowed ** to take ownership of the selection, it unhighlights the text in the buffer ** (Being in the middle of a modify callback, this has a somewhat complicated ** result, since later callbacks will see the second modifications first). */ static void modifiedCB(int pos, int nInserted, int nDeleted, int nRestyled, const char *deletedText, void *cbArg) { TextWidget w = (TextWidget)cbArg; Time time = XtLastTimestampProcessed(XtDisplay((Widget)w)); int selected = w->text.textD->buffer->primary.selected; int isOwner = w->text.selectionOwner; /* If the widget owns the selection and the buffer text is still selected, or if the widget doesn't own it and there's no selection, do nothing */ if ((isOwner && selected) || (!isOwner && !selected)) return; /* Don't disown the selection here. Another application (namely: klipper) may try to take it when it thinks nobody has the selection. We then lose it, making selection-based macro operations fail. Disowning is really only for when the widget is destroyed to avoid a convert callback from firing at a bad time. */ /* Take ownership of the selection */ if (!XtOwnSelection((Widget)w, XA_PRIMARY, time, convertSelectionCB, loseSelectionCB, NULL)) BufUnselect(w->text.textD->buffer); else w->text.selectionOwner = True; } /* ** Send an INSERT_SELECTION request to "sel". ** Upon completion, do the action specified by "action" (one of enum ** selectNotifyActions) using "actionText" and freeing actionText (if ** not NULL) when done. */ static void sendSecondary(Widget w, Time time, Atom sel, int action, char *actionText, int actionTextLen) { static Atom selInfoProp[2] = {XA_SECONDARY, XA_STRING}; Display *disp = XtDisplay(w); selectNotifyInfo *cbInfo; XtAppContext context = XtWidgetToApplicationContext((Widget)w); /* Take ownership of the secondary selection, give up if we can't */ if (!XtOwnSelection(w, XA_SECONDARY, time, convertSecondaryCB, loseSecondaryCB, NULL)) { BufSecondaryUnselect(((TextWidget)w)->text.textD->buffer); return; } /* Set up a property on this window to pass along with the INSERT_SELECTION request to tell the MOTIF_DESTINATION owner what selection and what target from that selection to insert */ XChangeProperty(disp, XtWindow(w), getAtom(disp, A_INSERT_INFO), getAtom(disp, A_ATOM_PAIR), 32, PropModeReplace, (unsigned char *)selInfoProp, 2 /* 1? */); /* Make INSERT_SELECTION request to the owner of selection "sel" to do the insert. This must be done using XLib calls to specify the property with the information about what to insert. This means it also requires an event handler to see if the request succeeded or not, and a backup timer to clean up if the select notify event is never returned */ XConvertSelection(XtDisplay(w), sel, getAtom(disp, A_INSERT_SELECTION), getAtom(disp, A_INSERT_INFO), XtWindow(w), time); cbInfo = (selectNotifyInfo *)XtMalloc(sizeof(selectNotifyInfo)); cbInfo->action = action; cbInfo->timeStamp = time; cbInfo->widget = (Widget)w; cbInfo->actionText = actionText; cbInfo->length = actionTextLen; XtAddEventHandler(w, 0, True, selectNotifyEH, (XtPointer)cbInfo); cbInfo->timeoutProcID = XtAppAddTimeOut(context, XtAppGetSelectionTimeout(context), selectNotifyTimerProc, (XtPointer)cbInfo); } /* ** Called when data arrives from a request for the PRIMARY selection. If ** everything is in order, it inserts it at the cursor in the requesting ** widget. */ static void getSelectionCB(Widget w, XtPointer clientData, Atom *selType, Atom *type, XtPointer value, unsigned long *length, int *format) { textDisp *textD = ((TextWidget)w)->text.textD; int isColumnar = *(int *)clientData; int cursorLineStart, cursorPos, column, row; char *string; /* Confirm that the returned value is of the correct type */ if (*type != XA_STRING || *format != 8) { XtFree((char*) value); return; } /* Copy the string just to make space for the null character (this may not be necessary, XLib documentation claims a NULL is already added, but the Xt documentation for this routine makes no such claim) */ string = XtMalloc(*length + 1); memcpy(string, (char *)value, *length); string[*length] = '\0'; /* If the string contains ascii-nul characters, substitute something else, or give up, warn, and refuse */ if (!BufSubstituteNullChars(string, *length, textD->buffer)) { fprintf(stderr, "Too much binary data, giving up\n"); XtFree(string); XtFree((char *)value); return; } /* Insert it in the text widget */ if (isColumnar) { cursorPos = TextDGetInsertPosition(textD); cursorLineStart = BufStartOfLine(textD->buffer, cursorPos); TextDXYToUnconstrainedPosition(textD, ((TextWidget)w)->text.btnDownX, ((TextWidget)w)->text.btnDownY, &row, &column); BufInsertCol(textD->buffer, column, cursorLineStart, string, NULL,NULL); TextDSetInsertPosition(textD, textD->buffer->cursorPosHint); } else TextInsertAtCursor(w, string, NULL, False, ((TextWidget)w)->text.autoWrapPastedText); XtFree(string); /* The selection requstor is required to free the memory passed to it via value */ XtFree((char *)value); } /* ** Called when data arrives from request resulting from processing an ** INSERT_SELECTION request. If everything is in order, inserts it at ** the cursor or replaces pending delete selection in widget "w", and sets ** the flag passed in clientData to SUCCESSFUL_INSERT or UNSUCCESSFUL_INSERT ** depending on the success of the operation. */ static void getInsertSelectionCB(Widget w, XtPointer clientData,Atom *selType, Atom *type, XtPointer value, unsigned long *length, int *format) { textBuffer *buf = ((TextWidget)w)->text.textD->buffer; char *string; int *resultFlag = (int *)clientData; /* Confirm that the returned value is of the correct type */ if (*type != XA_STRING || *format != 8 || value == NULL) { XtFree((char*) value); *resultFlag = UNSUCCESSFUL_INSERT; return; } /* Copy the string just to make space for the null character */ string = XtMalloc(*length + 1); memcpy(string, (char *)value, *length); string[*length] = '\0'; /* If the string contains ascii-nul characters, substitute something else, or give up, warn, and refuse */ if (!BufSubstituteNullChars(string, *length, buf)) { fprintf(stderr, "Too much binary data, giving up\n"); XtFree(string); XtFree((char *)value); return; } /* Insert it in the text widget */ TextInsertAtCursor(w, string, NULL, True, ((TextWidget)w)->text.autoWrapPastedText); XtFree(string); *resultFlag = SUCCESSFUL_INSERT; /* This callback is required to free the memory passed to it thru value */ XtFree((char *)value); } /* ** Called when data arrives from an X primary selection request for the ** purpose of exchanging the primary and secondary selections. ** If everything is in order, stores the retrieved text temporarily and ** initiates a request to replace the primary selection with this widget's ** secondary selection. */ static void getExchSelCB(Widget w, XtPointer clientData, Atom *selType, Atom *type, XtPointer value, unsigned long *length, int *format) { /* Confirm that there is a value and it is of the correct type */ if (*length == 0 || value == NULL || *type != XA_STRING || *format != 8) { XtFree((char*) value); XBell(XtDisplay(w), 0); BufSecondaryUnselect(((TextWidget)w)->text.textD->buffer); return; } /* Request the selection owner to replace the primary selection with this widget's secondary selection. When complete, replace this widget's secondary selection with text "value" and free it. */ sendSecondary(w, XtLastTimestampProcessed(XtDisplay(w)), XA_PRIMARY, EXCHANGE_SECONDARY, (char *)value, *length); } /* ** Selection converter procedure used by the widget when it is the selection ** owner to provide data in the format requested by the selection requestor. ** ** Note: Memory left in the *value field is freed by Xt as long as there is no ** done_proc procedure registered in the XtOwnSelection call where this ** procdeure is registered */ static Boolean convertSelectionCB(Widget w, Atom *selType, Atom *target, Atom *type, XtPointer *value, unsigned long *length, int *format) { XSelectionRequestEvent *event = XtGetSelectionRequest(w, *selType, 0); textBuffer *buf = ((TextWidget)w)->text.textD->buffer; Display *display = XtDisplay(w); Atom *targets, dummyAtom; unsigned long nItems, dummyULong; Atom *reqAtoms; int getFmt, result = INSERT_WAITING; XEvent nextEvent; /* target is text, string, or compound text */ if (*target == XA_STRING || *target == getAtom(display, A_TEXT) || *target == getAtom(display, A_COMPOUND_TEXT)) { /* We really don't directly support COMPOUND_TEXT, but recent versions gnome-terminal incorrectly ask for it, even though don't declare that we do. Just reply in string format. */ *type = XA_STRING; *value = (XtPointer)BufGetSelectionText(buf); *length = strlen((char *)*value); *format = 8; BufUnsubstituteNullChars(*value, buf); return True; } /* target is "TARGETS", return a list of targets we can handle */ if (*target == getAtom(display, A_TARGETS)) { targets = (Atom *)XtMalloc(sizeof(Atom) * N_SELECT_TARGETS); targets[0] = XA_STRING; targets[1] = getAtom(display, A_TEXT); targets[2] = getAtom(display, A_TARGETS); targets[3] = getAtom(display, A_MULTIPLE); targets[4] = getAtom(display, A_TIMESTAMP); targets[5] = getAtom(display, A_INSERT_SELECTION); targets[6] = getAtom(display, A_DELETE); *type = XA_ATOM; *value = (XtPointer)targets; *length = N_SELECT_TARGETS; *format = 32; return True; } /* target is "INSERT_SELECTION": 1) get the information about what selection and target to use to get the text to insert, from the property named in the property field of the selection request event. 2) initiate a get value request for the selection and target named in the property, and WAIT until it completes */ if (*target == getAtom(display, A_INSERT_SELECTION)) { if (((TextWidget)w)->text.readOnly) return False; if (XGetWindowProperty(event->display, event->requestor, event->property, 0, 2, False, AnyPropertyType, &dummyAtom, &getFmt, &nItems, &dummyULong, (unsigned char **)&reqAtoms) != Success || getFmt != 32 || nItems != 2) return False; if (reqAtoms[1] != XA_STRING) return False; XtGetSelectionValue(w, reqAtoms[0], reqAtoms[1], getInsertSelectionCB, &result, event->time); XFree((char *)reqAtoms); while (result == INSERT_WAITING) { XtAppNextEvent(XtWidgetToApplicationContext(w), &nextEvent); XtDispatchEvent(&nextEvent); } *type = getAtom(display, A_INSERT_SELECTION); *format = 8; *value = NULL; *length = 0; return result == SUCCESSFUL_INSERT; } /* target is "DELETE": delete primary selection */ if (*target == getAtom(display, A_DELETE)) { BufRemoveSelected(buf); *length = 0; *format = 8; *type = getAtom(display, A_DELETE); *value = NULL; return True; } /* targets TIMESTAMP and MULTIPLE are handled by the toolkit, any others are unrecognized, return False */ return False; } static void loseSelectionCB(Widget w, Atom *selType) { TextWidget tw = (TextWidget)w; selection *sel = &tw->text.textD->buffer->primary; char zeroWidth = sel->rectangular ? sel->zeroWidth : 0; /* For zero width rect. sel. we give up the selection but keep the zero width tag. */ tw->text.selectionOwner = False; BufUnselect(tw->text.textD->buffer); sel->zeroWidth = zeroWidth; } /* ** Selection converter procedure used by the widget to (temporarily) provide ** the secondary selection data to a single requestor who has been asked ** to insert it. */ static Boolean convertSecondaryCB(Widget w, Atom *selType, Atom *target, Atom *type, XtPointer *value, unsigned long *length, int *format) { textBuffer *buf = ((TextWidget)w)->text.textD->buffer; /* target must be string */ if (*target != XA_STRING && *target != getAtom(XtDisplay(w), A_TEXT)) return False; /* Return the contents of the secondary selection. The memory allocated here is freed by the X toolkit */ *type = XA_STRING; *value = (XtPointer)BufGetSecSelectText(buf); *length = strlen((char *)*value); *format = 8; BufUnsubstituteNullChars(*value, buf); return True; } static void loseSecondaryCB(Widget w, Atom *selType) { /* do nothing, secondary selections are transient anyhow, and it will go away on its own */ } /* ** Selection converter procedure used by the widget when it owns the Motif ** destination, to handle INSERT_SELECTION requests. */ static Boolean convertMotifDestCB(Widget w, Atom *selType, Atom *target, Atom *type, XtPointer *value, unsigned long *length, int *format) { XSelectionRequestEvent *event = XtGetSelectionRequest(w, *selType, 0); Display *display = XtDisplay(w); Atom *targets, dummyAtom; unsigned long nItems, dummyULong; Atom *reqAtoms; int getFmt, result = INSERT_WAITING; XEvent nextEvent; /* target is "TARGETS", return a list of targets it can handle */ if (*target == getAtom(display, A_TARGETS)) { targets = (Atom *)XtMalloc(sizeof(Atom) * 3); targets[0] = getAtom(display, A_TARGETS); targets[1] = getAtom(display, A_TIMESTAMP); targets[2] = getAtom(display, A_INSERT_SELECTION); *type = XA_ATOM; *value = (XtPointer)targets; *length = 3; *format = 32; return True; } /* target is "INSERT_SELECTION": 1) get the information about what selection and target to use to get the text to insert, from the property named in the property field of the selection request event. 2) initiate a get value request for the selection and target named in the property, and WAIT until it completes */ if (*target == getAtom(display, A_INSERT_SELECTION)) { if (((TextWidget)w)->text.readOnly) return False; if (XGetWindowProperty(event->display, event->requestor, event->property, 0, 2, False, AnyPropertyType, &dummyAtom, &getFmt, &nItems, &dummyULong, (unsigned char **)&reqAtoms) != Success || getFmt != 32 || nItems != 2) return False; if (reqAtoms[1] != XA_STRING) return False; XtGetSelectionValue(w, reqAtoms[0], reqAtoms[1], getInsertSelectionCB, &result, event->time); XFree((char *)reqAtoms); while (result == INSERT_WAITING) { XtAppNextEvent(XtWidgetToApplicationContext(w), &nextEvent); XtDispatchEvent(&nextEvent); } *type = getAtom(display, A_INSERT_SELECTION); *format = 8; *value = NULL; *length = 0; return result == SUCCESSFUL_INSERT; } /* target TIMESTAMP is handled by the toolkit and not passed here, any others are unrecognized */ return False; } static void loseMotifDestCB(Widget w, Atom *selType) { ((TextWidget)w)->text.motifDestOwner = False; if (((TextWidget)w)->text.textD->cursorStyle == CARET_CURSOR) TextDSetCursorStyle(((TextWidget)w)->text.textD, DIM_CURSOR); } /* ** Event handler for SelectionNotify events, to finish off INSERT_SELECTION ** requests which must be done through the lower ** level (and more complicated) XLib selection mechanism. Matches the ** time stamp in the request against the time stamp stored when the selection ** request was made to find the selectionNotify event that it was installed ** to catch. When it finds the correct event, it does the action it was ** installed to do, and removes itself and its backup timer (which would do ** the clean up if the selectionNotify event never arrived.) */ static void selectNotifyEH(Widget w, XtPointer data, XEvent *event, Boolean *continueDispatch) { textBuffer *buf = ((TextWidget)w)->text.textD->buffer; XSelectionEvent *e = (XSelectionEvent *)event; selectNotifyInfo *cbInfo = (selectNotifyInfo *)data; int selStart, selEnd; char *string; /* Check if this was the selection request for which this handler was set up, if not, do nothing */ if (event->type != SelectionNotify || e->time != cbInfo->timeStamp) return; /* The time stamp matched, remove this event handler and its backup timer procedure */ XtRemoveEventHandler(w, 0, True, selectNotifyEH, data); XtRemoveTimeOut(cbInfo->timeoutProcID); /* Check if the request succeeded, if not, beep, remove any existing secondary selection, and return */ if (e->property == None) { XBell(XtDisplay(w), 0); BufSecondaryUnselect(buf); XtDisownSelection(w, XA_SECONDARY, e->time); XtFree((char*) cbInfo->actionText); XtFree((char *)cbInfo); return; } /* Do the requested action, if the action is exchange, also clean up the properties created for returning the primary selection and making the MULTIPLE target request */ if (cbInfo->action == REMOVE_SECONDARY) { BufRemoveSecSelect(buf); } else if (cbInfo->action == EXCHANGE_SECONDARY) { string = XtMalloc(cbInfo->length + 1); memcpy(string, cbInfo->actionText, cbInfo->length); string[cbInfo->length] = '\0'; selStart = buf->secondary.start; if (BufSubstituteNullChars(string, cbInfo->length, buf)) { BufReplaceSecSelect(buf, string); if (buf->secondary.rectangular) { /*... it would be nice to re-select, but probably impossible */ TextDSetInsertPosition(((TextWidget)w)->text.textD, buf->cursorPosHint); } else { selEnd = selStart + cbInfo->length; BufSelect(buf, selStart, selEnd); TextDSetInsertPosition(((TextWidget)w)->text.textD, selEnd); } } else fprintf(stderr, "Too much binary data\n"); XtFree(string); } BufSecondaryUnselect(buf); XtDisownSelection(w, XA_SECONDARY, e->time); XtFree((char *)cbInfo->actionText); XtFree((char *)cbInfo); } /* ** Xt timer procedure for timeouts on XConvertSelection requests, cleans up ** after a complete failure of the selection mechanism to return a selection ** notify event for a convert selection request */ static void selectNotifyTimerProc(XtPointer clientData, XtIntervalId *id) { selectNotifyInfo *cbInfo = (selectNotifyInfo *)clientData; textBuffer *buf = ((TextWidget)cbInfo->widget)->text.textD->buffer; fprintf(stderr, "NEdit: timeout on selection request\n"); XtRemoveEventHandler(cbInfo->widget, 0, True, selectNotifyEH, cbInfo); BufSecondaryUnselect(buf); XtDisownSelection(cbInfo->widget, XA_SECONDARY, cbInfo->timeStamp); XtFree((char*) cbInfo->actionText); XtFree((char *)cbInfo); } /* ** Maintain a cache of interned atoms. To reference one, use the constant ** from the enum, atomIndex, above. */ static Atom getAtom(Display *display, int atomNum) { static Atom atomList[N_ATOMS] = {0}; static char *atomNames[N_ATOMS] = {"TEXT", "TARGETS", "MULTIPLE", "TIMESTAMP", "INSERT_SELECTION", "DELETE", "CLIPBOARD", "INSERT_INFO", "ATOM_PAIR", "MOTIF_DESTINATION", "COMPOUND_TEXT"}; if (atomList[atomNum] == 0) atomList[atomNum] = XInternAtom(display, atomNames[atomNum], False); return atomList[atomNum]; } nedit-5.6.orig/source/textSel.h0000644000175000017500000000520710144236625015222 0ustar paulpaul/* $Id: textSel.h,v 1.6 2004/11/09 21:58:45 yooden Exp $ */ /******************************************************************************* * * * textSel.h -- Nirvana Editor Selection header file * * * * Copyright 2004 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_TEXTSEL_H_INCLUDED #define NEDIT_TEXTSEL_H_INCLUDED #include #include void HandleXSelections(Widget w); void StopHandlingXSelections(Widget w); void CopyToClipboard(Widget w, Time time); void InsertPrimarySelection(Widget w, Time time, int isColumnar); void MovePrimarySelection(Widget w, Time time, int isColumnar); void SendSecondarySelection(Widget w, Time time, int removeAfter); void ExchangeSelections(Widget w, Time time); void InsertClipboard(Widget w, int isColumnar); void TakeMotifDestination(Widget w, Time time); #endif /* NEDIT_TEXTSEL_H_INCLUDED */ nedit-5.6.orig/source/undo.c0000644000175000017500000003640710737527371014551 0ustar paulpaulstatic const char CVSID[] = "$Id: undo.c,v 1.19 2008/01/04 22:11:05 yooden Exp $"; /******************************************************************************* * * * undo.c -- Nirvana Editor undo command * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * May 10, 1991 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "undo.h" #include "textBuf.h" #include "text.h" #include "nedit.h" #include "search.h" #include "window.h" #include "file.h" #include "userCmds.h" #include "preferences.h" #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #define FORWARD 1 #define REVERSE 2 static void addUndoItem(WindowInfo *window, UndoInfo *undo); static void addRedoItem(WindowInfo *window, UndoInfo *redo); static void removeUndoItem(WindowInfo *window); static void removeRedoItem(WindowInfo *window); static void appendDeletedText(WindowInfo *window, const char *deletedText, int deletedLen, int direction); static void trimUndoList(WindowInfo *window, int maxLength); static int determineUndoType(int nInserted, int nDeleted); static void freeUndoRecord(UndoInfo *undo); void Undo(WindowInfo *window) { UndoInfo *undo = window->undo; int restoredTextLength; /* return if nothing to undo */ if (undo == NULL) return; /* BufReplace will eventually call SaveUndoInformation. This is mostly good because it makes accumulating redo operations easier, however SaveUndoInformation needs to know that it is being called in the context of an undo. The inUndo field in the undo record indicates that this record is in the process of being undone. */ undo->inUndo = True; /* use the saved undo information to reverse changes */ BufReplace(window->buffer, undo->startPos, undo->endPos, (undo->oldText != NULL ? undo->oldText : "")); restoredTextLength = undo->oldText != NULL ? strlen(undo->oldText) : 0; if (!window->buffer->primary.selected || GetPrefUndoModifiesSelection()) { /* position the cursor in the focus pane after the changed text to show the user where the undo was done */ TextSetCursorPos(window->lastFocus, undo->startPos + restoredTextLength); } if (GetPrefUndoModifiesSelection()) { if (restoredTextLength > 0) { BufSelect(window->buffer, undo->startPos, undo->startPos + restoredTextLength); } else { BufUnselect(window->buffer); } } MakeSelectionVisible(window, window->lastFocus); /* restore the file's unmodified status if the file was unmodified when the change being undone was originally made. Also, remove the backup file, since the text in the buffer is now identical to the original file */ if (undo->restoresToSaved) { SetWindowModified(window, False); RemoveBackupFile(window); } /* free the undo record and remove it from the chain */ removeUndoItem(window); } void Redo(WindowInfo *window) { UndoInfo *redo = window->redo; int restoredTextLength; /* return if nothing to redo */ if (window->redo == NULL) return; /* BufReplace will eventually call SaveUndoInformation. To indicate to SaveUndoInformation that this is the context of a redo operation, we set the inUndo indicator in the redo record */ redo->inUndo = True; /* use the saved redo information to reverse changes */ BufReplace(window->buffer, redo->startPos, redo->endPos, (redo->oldText != NULL ? redo->oldText : "")); restoredTextLength = redo->oldText != NULL ? strlen(redo->oldText) : 0; if (!window->buffer->primary.selected || GetPrefUndoModifiesSelection()) { /* position the cursor in the focus pane after the changed text to show the user where the undo was done */ TextSetCursorPos(window->lastFocus, redo->startPos + restoredTextLength); } if (GetPrefUndoModifiesSelection()) { if (restoredTextLength > 0) { BufSelect(window->buffer, redo->startPos, redo->startPos + restoredTextLength); } else { BufUnselect(window->buffer); } } MakeSelectionVisible(window, window->lastFocus); /* restore the file's unmodified status if the file was unmodified when the change being redone was originally made. Also, remove the backup file, since the text in the buffer is now identical to the original file */ if (redo->restoresToSaved) { SetWindowModified(window, False); RemoveBackupFile(window); } /* remove the redo record from the chain and free it */ removeRedoItem(window); } /* ** SaveUndoInformation stores away the changes made to the text buffer. As a ** side effect, it also increments the autoSave operation and character counts ** since it needs to do the classification anyhow. ** ** Note: This routine must be kept efficient. It is called for every ** character typed. */ void SaveUndoInformation(WindowInfo *window, int pos, int nInserted, int nDeleted, const char *deletedText) { int newType, oldType; UndoInfo *u, *undo = window->undo; int isUndo = (undo != NULL && undo->inUndo); int isRedo = (window->redo != NULL && window->redo->inUndo); /* redo operations become invalid once the user begins typing or does other editing. If this is not a redo or undo operation and a redo list still exists, clear it and dim the redo menu item */ if (!(isUndo || isRedo) && window->redo != NULL) ClearRedoList(window); /* figure out what kind of editing operation this is, and recall what the last one was */ newType = determineUndoType(nInserted, nDeleted); if (newType == UNDO_NOOP) return; oldType = (undo == NULL || isUndo) ? UNDO_NOOP : undo->type; /* ** Check for continuations of single character operations. These are ** accumulated so a whole insertion or deletion can be undone, rather ** than just the last character that the user typed. If the window ** is currently in an unmodified state, don't accumulate operations ** across the save, so the user can undo back to the unmodified state. */ if (window->fileChanged) { /* normal sequential character insertion */ if ( ((oldType == ONE_CHAR_INSERT || oldType == ONE_CHAR_REPLACE) && newType == ONE_CHAR_INSERT) && (pos == undo->endPos)) { undo->endPos++; window->autoSaveCharCount++; return; } /* overstrike mode replacement */ if ((oldType == ONE_CHAR_REPLACE && newType == ONE_CHAR_REPLACE) && (pos == undo->endPos)) { appendDeletedText(window, deletedText, nDeleted, FORWARD); undo->endPos++; window->autoSaveCharCount++; return; } /* forward delete */ if ((oldType==ONE_CHAR_DELETE && newType==ONE_CHAR_DELETE) && (pos==undo->startPos)) { appendDeletedText(window, deletedText, nDeleted, FORWARD); return; } /* reverse delete */ if ((oldType==ONE_CHAR_DELETE && newType==ONE_CHAR_DELETE) && (pos == undo->startPos-1)) { appendDeletedText(window, deletedText, nDeleted, REVERSE); undo->startPos--; undo->endPos--; return; } } /* ** The user has started a new operation, create a new undo record ** and save the new undo data. */ undo = (UndoInfo *)XtMalloc(sizeof(UndoInfo)); undo->oldLen = 0; undo->oldText = NULL; undo->type = newType; undo->inUndo = False; undo->restoresToSaved = False; undo->startPos = pos; undo->endPos = pos + nInserted; /* if text was deleted, save it */ if (nDeleted > 0) { undo->oldLen = nDeleted + 1; /* +1 is for null at end */ undo->oldText = XtMalloc(nDeleted + 1); strcpy(undo->oldText, deletedText); } /* increment the operation count for the autosave feature */ window->autoSaveOpCount++; /* if the window is currently unmodified, remove the previous restoresToSaved marker, and set it on this record */ if (!window->fileChanged) { undo->restoresToSaved = True; for (u=window->undo; u!=NULL; u=u->next) u->restoresToSaved = False; for (u=window->redo; u!=NULL; u=u->next) u->restoresToSaved = False; } /* Add the new record to the undo list unless SaveUndoInfo is saving information generated by an Undo operation itself, in which case, add the new record to the redo list. */ if (isUndo) addRedoItem(window, undo); else addUndoItem(window, undo); } /* ** ClearUndoList, ClearRedoList ** ** Functions for clearing all of the information off of the undo or redo ** lists and adjusting the edit menu accordingly */ void ClearUndoList(WindowInfo *window) { while (window->undo != NULL) removeUndoItem(window); } void ClearRedoList(WindowInfo *window) { while (window->redo != NULL) removeRedoItem(window); } /* ** Add an undo record (already allocated by the caller) to the window's undo ** list if the item pushes the undo operation or character counts past the ** limits, trim the undo list to an acceptable length. */ static void addUndoItem(WindowInfo *window, UndoInfo *undo) { /* Make the undo menu item sensitive now that there's something to undo */ if (window->undo == NULL) { SetSensitive(window, window->undoItem, True); SetBGMenuUndoSensitivity(window, True); } /* Add the item to the beginning of the list */ undo->next = window->undo; window->undo = undo; /* Increment the operation and memory counts */ window->undoOpCount++; window->undoMemUsed += undo->oldLen; /* Trim the list if it exceeds any of the limits */ if (window->undoOpCount > UNDO_OP_LIMIT) trimUndoList(window, UNDO_OP_TRIMTO); if (window->undoMemUsed > UNDO_WORRY_LIMIT) trimUndoList(window, UNDO_WORRY_TRIMTO); if (window->undoMemUsed > UNDO_PURGE_LIMIT) trimUndoList(window, UNDO_PURGE_TRIMTO); } /* ** Add an item (already allocated by the caller) to the window's redo list. */ static void addRedoItem(WindowInfo *window, UndoInfo *redo) { /* Make the redo menu item sensitive now that there's something to redo */ if (window->redo == NULL) { SetSensitive(window, window->redoItem, True); SetBGMenuRedoSensitivity(window, True); } /* Add the item to the beginning of the list */ redo->next = window->redo; window->redo = redo; } /* ** Pop (remove and free) the current (front) undo record from the undo list */ static void removeUndoItem(WindowInfo *window) { UndoInfo *undo = window->undo; if (undo == NULL) return; /* Decrement the operation and memory counts */ window->undoOpCount--; window->undoMemUsed -= undo->oldLen; /* Remove and free the item */ window->undo = undo->next; freeUndoRecord(undo); /* if there are no more undo records left, dim the Undo menu item */ if (window->undo == NULL) { SetSensitive(window, window->undoItem, False); SetBGMenuUndoSensitivity(window, False); } } /* ** Pop (remove and free) the current (front) redo record from the redo list */ static void removeRedoItem(WindowInfo *window) { UndoInfo *redo = window->redo; /* Remove and free the item */ window->redo = redo->next; freeUndoRecord(redo); /* if there are no more redo records left, dim the Redo menu item */ if (window->redo == NULL) { SetSensitive(window, window->redoItem, False); SetBGMenuRedoSensitivity(window, False); } } /* ** Add deleted text to the beginning or end ** of the text saved for undoing the last operation. This routine is intended ** for continuing of a string of one character deletes or replaces, but will ** work with more than one character. */ static void appendDeletedText(WindowInfo *window, const char *deletedText, int deletedLen, int direction) { UndoInfo *undo = window->undo; char *comboText; /* re-allocate, adding space for the new character(s) */ comboText = XtMalloc(undo->oldLen + deletedLen); /* copy the new character and the already deleted text to the new memory */ if (direction == FORWARD) { strcpy(comboText, undo->oldText); strcat(comboText, deletedText); } else { strcpy(comboText, deletedText); strcat(comboText, undo->oldText); } /* keep track of the additional memory now used by the undo list */ window->undoMemUsed++; /* free the old saved text and attach the new */ XtFree(undo->oldText); undo->oldText = comboText; undo->oldLen += deletedLen; } /* ** Trim records off of the END of the undo list to reduce it to length ** maxLength */ static void trimUndoList(WindowInfo *window, int maxLength) { int i; UndoInfo *u, *lastRec; if (window->undo == NULL) return; /* Find last item on the list to leave intact */ for (i=1, u=window->undo; inext); if (u == NULL) return; /* Trim off all subsequent entries */ lastRec = u; while (lastRec->next != NULL) { u = lastRec->next; lastRec->next = u->next; window->undoOpCount--; window->undoMemUsed -= u->oldLen; freeUndoRecord(u); } } static int determineUndoType(int nInserted, int nDeleted) { int textDeleted, textInserted; textDeleted = (nDeleted > 0); textInserted = (nInserted > 0); if (textInserted && !textDeleted) { /* Insert */ if (nInserted == 1) return ONE_CHAR_INSERT; else return BLOCK_INSERT; } else if (textInserted && textDeleted) { /* Replace */ if (nInserted == 1) return ONE_CHAR_REPLACE; else return BLOCK_REPLACE; } else if (!textInserted && textDeleted) { /* Delete */ if (nDeleted == 1) return ONE_CHAR_DELETE; else return BLOCK_DELETE; } else { /* Nothing deleted or inserted */ return UNDO_NOOP; } } static void freeUndoRecord(UndoInfo *undo) { if (undo == NULL) return; XtFree(undo->oldText); XtFree((char *)undo); } nedit-5.6.orig/source/undo.h0000644000175000017500000000502210737527371014543 0ustar paulpaul/* $Id: undo.h,v 1.9 2008/01/04 22:11:05 yooden Exp $ */ /******************************************************************************* * * * undo.h -- Nirvana Editor Undo header file * * * * Copyright 2004 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_UNDO_H_INCLUDED #define NEDIT_UNDO_H_INCLUDED #include "nedit.h" enum undoTypes {UNDO_NOOP, ONE_CHAR_INSERT, ONE_CHAR_REPLACE, ONE_CHAR_DELETE, BLOCK_INSERT, BLOCK_REPLACE, BLOCK_DELETE}; void Undo(WindowInfo *window); void Redo(WindowInfo *window); void SaveUndoInformation(WindowInfo *window, int pos, int nInserted, int nDeleted, const char *deletedText); void ClearUndoList(WindowInfo *window); void ClearRedoList(WindowInfo *window); #endif /* NEDIT_UNDO_H_INCLUDED */ nedit-5.6.orig/source/userCmds.c0000644000175000017500000036170411110456100015343 0ustar paulpaulstatic const char CVSID[] = "$Id: userCmds.c,v 1.56.2.1 2008/10/06 11:37:24 lebert Exp $"; /******************************************************************************* * * * userCmds.c -- Nirvana Editor shell and macro command dialogs * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * April, 1997 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "userCmds.h" #include "textBuf.h" #include "text.h" #include "nedit.h" #include "preferences.h" #include "window.h" #include "menu.h" #include "shell.h" #include "macro.h" #include "file.h" #include "interpret.h" #include "parse.h" #include "../util/DialogF.h" #include "../util/misc.h" #include "../util/managedList.h" #include #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #if XmVersion >= 1002 #define MENU_WIDGET(w) (XmGetPostedFromWidget(XtParent(w))) #else #define MENU_WIDGET(w) (w) #endif extern void _XmDismissTearOff(Widget w, XtPointer call, XtPointer x); /* max. number of user programmable menu commands allowed per each of the macro, shell, and background menus */ #define MAX_ITEMS_PER_MENU 400 /* indicates, that an unknown (i.e. not existing) language mode is bound to an user menu item */ #define UNKNOWN_LANGUAGE_MODE -2 /* major divisions (in position units) in User Commands dialogs */ #define LEFT_MARGIN_POS 1 #define RIGHT_MARGIN_POS 99 #define LIST_RIGHT 45 #define SHELL_CMD_TOP 70 #define MACRO_CMD_TOP 40 /* types of current dialog and/or menu */ enum dialogTypes {SHELL_CMDS, MACRO_CMDS, BG_MENU_CMDS}; /* Structure representing a menu item for shell, macro and BG menus*/ typedef struct { char *name; unsigned int modifiers; KeySym keysym; char mnemonic; char input; char output; char repInput; char saveFirst; char loadAfter; char *cmd; } menuItemRec; /* Structure for widgets and flags associated with shell command, macro command and BG command editing dialogs */ typedef struct { int dialogType; WindowInfo *window; Widget nameTextW, accTextW, mneTextW, cmdTextW, saveFirstBtn; Widget loadAfterBtn, selInpBtn, winInpBtn, eitherInpBtn, noInpBtn; Widget repInpBtn, sameOutBtn, dlogOutBtn, winOutBtn, dlogShell; Widget managedList; menuItemRec **menuItemsList; int nMenuItems; } userCmdDialog; /* Structure for keeping track of hierarchical sub-menus during user-menu creation */ typedef struct { char *name; Widget menuPane; } menuTreeItem; /* Structure holding hierarchical info about one sub-menu. Suppose following user menu items: a.) "menuItem1" b.) "subMenuA>menuItemA1" c.) "subMenuA>menuItemA2" d.) "subMenuA>subMenuB>menuItemB1" e.) "subMenuA>subMenuB>menuItemB2" Structure of this user menu is: Main Menu Name Sub-Menu A Name Sub-Menu B Name element nbr. element nbr. element nbr. 0 menuItem1 1 subMenuA --+-> 0 menuItemA1 +-> 1 menuItemA2 +-> 2 subMenuB --+-> 0 menuItemB1 +-> 1 menuItemB2 Above example holds 2 sub-menus: 1.) "subMenuA" (hierarchical ID = {1} means: element nbr. "1" of main menu) 2.) "subMenuA>subMenuB" (hierarchical ID = {1, 2} means: el. nbr. "2" of "subMenuA", which itself is el. nbr. "0" of main menu) */ typedef struct { char *usmiName; /* hierarchical name of sub-menu */ int *usmiId; /* hierarchical ID of sub-menu */ int usmiIdLen; /* length of hierarchical ID */ } userSubMenuInfo; /* Holds info about sub-menu structure of an user menu */ typedef struct { int usmcNbrOfMainMenuItems; /* number of main menu items */ int usmcNbrOfSubMenus; /* number of sub-menus */ userSubMenuInfo *usmcInfo; /* list of sub-menu info */ } userSubMenuCache; /* Structure holding info about a single menu item. According to above example there exist 5 user menu items: a.) "menuItem1" (hierarchical ID = {0} means: element nbr. "0" of main menu) b.) "menuItemA1" (hierarchical ID = {1, 0} means: el. nbr. "0" of "subMenuA", which itself is el. nbr. "1" of main menu) c.) "menuItemA2" (hierarchical ID = {1, 1}) d.) "menuItemB1" (hierarchical ID = {1, 2, 0}) e.) "menuItemB2" (hierarchical ID = {1, 2, 1}) */ typedef struct { char *umiName; /* hierarchical name of menu item (w.o. language mode info) */ int *umiId; /* hierarchical ID of menu item */ int umiIdLen; /* length of hierarchical ID */ Boolean umiIsDefault; /* menu item is default one ("@*") */ int umiNbrOfLanguageModes; /* number of language modes applicable for this menu item */ int *umiLanguageMode; /* list of applicable lang. modes */ int umiDefaultIndex; /* array index of menu item to be used as default, if no lang. mode matches */ Boolean umiToBeManaged; /* indicates, that menu item needs to be managed */ } userMenuInfo; /* Structure holding info about a selected user menu (shell, macro or background) */ typedef struct { int sumType; /* type of menu (shell, macro or background */ Widget sumMenuPane; /* pane of main menu */ int sumNbrOfListItems; /* number of menu items */ menuItemRec **sumItemList; /* list of menu items */ userMenuInfo **sumInfoList; /* list of infos about menu items */ userSubMenuCache *sumSubMenus; /* info about sub-menu structure */ UserMenuList *sumMainMenuList; /* cached info about main menu */ Boolean *sumMenuCreated; /* pointer to "menu created" indicator */ } selectedUserMenu; /* Descriptions of the current user programmed menu items for re-generating menus and processing shell, macro, and background menu selections */ static menuItemRec *ShellMenuItems[MAX_ITEMS_PER_MENU]; static userMenuInfo *ShellMenuInfo[MAX_ITEMS_PER_MENU]; static userSubMenuCache ShellSubMenus; static int NShellMenuItems = 0; static menuItemRec *MacroMenuItems[MAX_ITEMS_PER_MENU]; static userMenuInfo *MacroMenuInfo[MAX_ITEMS_PER_MENU]; static userSubMenuCache MacroSubMenus; static int NMacroMenuItems = 0; static menuItemRec *BGMenuItems[MAX_ITEMS_PER_MENU]; static userMenuInfo *BGMenuInfo[MAX_ITEMS_PER_MENU]; static userSubMenuCache BGSubMenus; static int NBGMenuItems = 0; /* Top level shells of the user-defined menu editing dialogs */ static Widget ShellCmdDialog = NULL; static Widget MacroCmdDialog = NULL; static Widget BGMenuCmdDialog = NULL; /* Paste learn/replay sequence buttons in user defined menu editing dialogs (for dimming and undimming externally when replay macro is available) */ static Widget MacroPasteReplayBtn = NULL; static Widget BGMenuPasteReplayBtn = NULL; static void editMacroOrBGMenu(WindowInfo *window, int dialogType); static void dimSelDepItemsInMenu(Widget menuPane, menuItemRec **menuList, int nMenuItems, int sensitive); static void rebuildMenuOfAllWindows(int menuType); static void rebuildMenu(WindowInfo *window, int menuType); static Widget findInMenuTree(menuTreeItem *menuTree, int nTreeEntries, const char *hierName); static char *copySubstring(const char *string, int length); static Widget createUserMenuItem(Widget menuPane, char *name, menuItemRec *f, int index, XtCallbackProc cbRtn, XtPointer cbArg); static Widget createUserSubMenu(Widget parent, char *label, Widget *menuItem); static void deleteMenuItems(Widget menuPane); static void selectUserMenu(WindowInfo *window, int menuType, selectedUserMenu *menu); static void updateMenu(WindowInfo *window, int menuType); static void manageTearOffMenu(Widget menuPane); static void resetManageMode(UserMenuList *list); static void manageAllSubMenuWidgets(UserMenuListElement *subMenu); static void unmanageAllSubMenuWidgets(UserMenuListElement *subMenu); static void manageMenuWidgets(UserMenuList *list); static void removeAccelFromMenuWidgets(UserMenuList *menuList); static void assignAccelToMenuWidgets(UserMenuList *menuList, WindowInfo *window); static void manageUserMenu(selectedUserMenu *menu, WindowInfo *window); static void createMenuItems(WindowInfo *window, selectedUserMenu *menu); static void okCB(Widget w, XtPointer clientData, XtPointer callData); static void applyCB(Widget w, XtPointer clientData, XtPointer callData); static void checkCB(Widget w, XtPointer clientData, XtPointer callData); static int checkMacro(userCmdDialog *ucd); static int checkMacroText(char *macro, Widget errorParent, Widget errFocus); static int applyDialogChanges(userCmdDialog *ucd); static void closeCB(Widget w, XtPointer clientData, XtPointer callData); static void pasteReplayCB(Widget w, XtPointer clientData, XtPointer callData); static void destroyCB(Widget w, XtPointer clientData, XtPointer callData); static void accKeyCB(Widget w, XtPointer clientData, XKeyEvent *event); static void sameOutCB(Widget w, XtPointer clientData, XtPointer callData); static void shellMenuCB(Widget w, WindowInfo *window, XtPointer callData); static void macroMenuCB(Widget w, WindowInfo *window, XtPointer callData); static void bgMenuCB(Widget w, WindowInfo *window, XtPointer callData) ; static void accFocusCB(Widget w, XtPointer clientData, XtPointer callData); static void accLoseFocusCB(Widget w, XtPointer clientData, XtPointer callData); static void updateDialogFields(menuItemRec *f, userCmdDialog *ucd); static menuItemRec *readDialogFields(userCmdDialog *ucd, int silent); static menuItemRec *copyMenuItemRec(menuItemRec *item); static void freeMenuItemRec(menuItemRec *item); static void *getDialogDataCB(void *oldItem, int explicitRequest, int *abort, void *cbArg); static void setDialogDataCB(void *item, void *cbArg); static void freeItemCB(void *item); static int dialogFieldsAreEmpty(userCmdDialog *ucd); static void disableTextW(Widget textW); static char *writeMenuItemString(menuItemRec **menuItems, int nItems, int listType); static int loadMenuItemString(char *inString, menuItemRec **menuItems, int *nItems, int listType); static void generateAcceleratorString(char *text, unsigned int modifiers, KeySym keysym); static void genAccelEventName(char *text, unsigned int modifiers, KeySym keysym); static int parseAcceleratorString(const char *string, unsigned int *modifiers, KeySym *keysym); static int parseError(const char *message); static char *copyMacroToEnd(char **inPtr); static void addTerminatingNewline(char **string); static void parseMenuItemList(menuItemRec **itemList, int nbrOfItems, userMenuInfo **infoList, userSubMenuCache *subMenus); static int getSubMenuDepth(const char *menuName); static userMenuInfo *parseMenuItemRec(menuItemRec *item); static void parseMenuItemName(char *menuItemName, userMenuInfo *info); static void generateUserMenuId(userMenuInfo *info, userSubMenuCache *subMenus); static userSubMenuInfo *findSubMenuInfo(userSubMenuCache *subMenus, const char *hierName); static char *stripLanguageMode(const char *menuItemName); static void setDefaultIndex(userMenuInfo **infoList, int nbrOfItems, int defaultIdx); static void applyLangModeToUserMenuInfo(userMenuInfo **infoList, int nbrOfItems, int languageMode); static int doesLanguageModeMatch(userMenuInfo *info, int languageMode); static void freeUserMenuInfoList(userMenuInfo **infoList, int nbrOfItems); static void freeUserMenuInfo(userMenuInfo *info); static void allocSubMenuCache(userSubMenuCache *subMenus, int nbrOfItems); static void freeSubMenuCache(userSubMenuCache *subMenus); static void allocUserMenuList(UserMenuList *list, int nbrOfItems); static void freeUserMenuList(UserMenuList *list); static UserMenuListElement *allocUserMenuListElement(Widget menuItem, char *accKeys); static void freeUserMenuListElement(UserMenuListElement *element); static UserMenuList *allocUserSubMenuList(int nbrOfItems); static void freeUserSubMenuList(UserMenuList *list); /* ** Present a dialog for editing the user specified commands in the shell menu */ void EditShellMenu(WindowInfo *window) { Widget form, accLabel, inpLabel, inpBox, outBox, outLabel; Widget nameLabel, cmdLabel, okBtn, applyBtn, closeBtn; userCmdDialog *ucd; XmString s1; int ac, i; Arg args[20]; /* if the dialog is already displayed, just pop it to the top and return */ if (ShellCmdDialog != NULL) { RaiseDialogWindow(ShellCmdDialog); return; } /* Create a structure for keeping track of dialog state */ ucd = (userCmdDialog *)XtMalloc(sizeof(userCmdDialog)); ucd->window = window; /* Set the dialog to operate on the Shell menu */ ucd->menuItemsList = (menuItemRec **)XtMalloc(sizeof(menuItemRec *) * MAX_ITEMS_PER_MENU); for (i=0; imenuItemsList[i] = copyMenuItemRec(ShellMenuItems[i]); ucd->nMenuItems = NShellMenuItems; ucd->dialogType = SHELL_CMDS; ac = 0; XtSetArg(args[ac], XmNdeleteResponse, XmDO_NOTHING); ac++; XtSetArg(args[ac], XmNiconName, "NEdit Shell Menu"); ac++; XtSetArg(args[ac], XmNtitle, "Shell Menu"); ac++; ucd->dlogShell = CreateWidget(TheAppShell, "shellCommands", topLevelShellWidgetClass, args, ac); AddSmallIcon(ucd->dlogShell); form = XtVaCreateManagedWidget("editShellCommands", xmFormWidgetClass, ucd->dlogShell, XmNautoUnmanage, False, XmNresizePolicy, XmRESIZE_NONE, NULL); ShellCmdDialog = ucd->dlogShell; XtAddCallback(form, XmNdestroyCallback, destroyCB, ucd); AddMotifCloseCallback(ucd->dlogShell, closeCB, ucd); ac = 0; XtSetArg(args[ac], XmNtopAttachment, XmATTACH_POSITION); ac++; XtSetArg(args[ac], XmNtopPosition, 2); ac++; XtSetArg(args[ac], XmNleftAttachment, XmATTACH_POSITION); ac++; XtSetArg(args[ac], XmNleftPosition, LEFT_MARGIN_POS); ac++; XtSetArg(args[ac], XmNrightAttachment, XmATTACH_POSITION); ac++; XtSetArg(args[ac], XmNrightPosition, LIST_RIGHT-1); ac++; XtSetArg(args[ac], XmNbottomAttachment, XmATTACH_POSITION); ac++; XtSetArg(args[ac], XmNbottomPosition, SHELL_CMD_TOP); ac++; ucd->managedList = CreateManagedList(form, "list", args, ac, (void **)ucd->menuItemsList, &ucd->nMenuItems, MAX_ITEMS_PER_MENU, 20, getDialogDataCB, ucd, setDialogDataCB, ucd, freeItemCB); ucd->loadAfterBtn = XtVaCreateManagedWidget("loadAfterBtn", xmToggleButtonWidgetClass, form, XmNlabelString, s1=MKSTRING("Re-load file after executing command"), XmNmnemonic, 'R', XmNalignment, XmALIGNMENT_BEGINNING, XmNset, False, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_POSITION, XmNbottomPosition, SHELL_CMD_TOP, NULL); XmStringFree(s1); ucd->saveFirstBtn = XtVaCreateManagedWidget("saveFirstBtn", xmToggleButtonWidgetClass, form, XmNlabelString, s1=MKSTRING("Save file before executing command"), XmNmnemonic, 'f', XmNalignment, XmALIGNMENT_BEGINNING, XmNset, False, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, ucd->loadAfterBtn, NULL); XmStringFree(s1); ucd->repInpBtn = XtVaCreateManagedWidget("repInpBtn", xmToggleButtonWidgetClass, form, XmNlabelString, s1=MKSTRING("Output replaces input"), XmNmnemonic, 'f', XmNalignment, XmALIGNMENT_BEGINNING, XmNset, False, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, ucd->saveFirstBtn, NULL); XmStringFree(s1); outBox = XtVaCreateManagedWidget("outBox", xmRowColumnWidgetClass, form, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNradioBehavior, True, XmNradioAlwaysOne, True, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT + 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, ucd->repInpBtn, XmNbottomOffset, 4, NULL); ucd->sameOutBtn = XtVaCreateManagedWidget("sameOutBtn", xmToggleButtonWidgetClass, outBox, XmNlabelString, s1=MKSTRING("same document"), XmNmnemonic, 'm', XmNalignment, XmALIGNMENT_BEGINNING, XmNmarginHeight, 0, XmNset, True, NULL); XmStringFree(s1); XtAddCallback(ucd->sameOutBtn, XmNvalueChangedCallback, sameOutCB, ucd); ucd->dlogOutBtn = XtVaCreateManagedWidget("dlogOutBtn", xmToggleButtonWidgetClass, outBox, XmNlabelString, s1=MKSTRING("dialog"), XmNmnemonic, 'g', XmNalignment, XmALIGNMENT_BEGINNING, XmNmarginHeight, 0, XmNset, False, NULL); XmStringFree(s1); ucd->winOutBtn = XtVaCreateManagedWidget("winOutBtn", xmToggleButtonWidgetClass, outBox, XmNlabelString, s1=MKSTRING("new document"), XmNmnemonic, 'n', XmNalignment, XmALIGNMENT_BEGINNING, XmNmarginHeight, 0, XmNset, False, NULL); XmStringFree(s1); outLabel = XtVaCreateManagedWidget("outLabel", xmLabelGadgetClass, form, XmNlabelString, s1=MKSTRING("Command Output (stdout/stderr):"), XmNalignment, XmALIGNMENT_BEGINNING, XmNmarginTop, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, outBox, NULL); XmStringFree(s1); inpBox = XtVaCreateManagedWidget("inpBox", xmRowColumnWidgetClass, form, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNradioBehavior, True, XmNradioAlwaysOne, True, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT + 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, outLabel, NULL); ucd->selInpBtn = XtVaCreateManagedWidget("selInpBtn", xmToggleButtonWidgetClass, inpBox, XmNlabelString, s1=MKSTRING("selection"), XmNmnemonic, 's', XmNalignment, XmALIGNMENT_BEGINNING, XmNmarginHeight, 0, XmNset, True, NULL); XmStringFree(s1); ucd->winInpBtn = XtVaCreateManagedWidget("winInpBtn", xmToggleButtonWidgetClass, inpBox, XmNlabelString, s1=MKSTRING("document"), XmNmnemonic, 'w', XmNalignment, XmALIGNMENT_BEGINNING, XmNmarginHeight, 0, XmNset, False, NULL); XmStringFree(s1); ucd->eitherInpBtn = XtVaCreateManagedWidget("eitherInpBtn", xmToggleButtonWidgetClass, inpBox, XmNlabelString, s1=MKSTRING("either"), XmNmnemonic, 't', XmNalignment, XmALIGNMENT_BEGINNING, XmNmarginHeight, 0, XmNset, False, NULL); XmStringFree(s1); ucd->noInpBtn = XtVaCreateManagedWidget("noInpBtn", xmToggleButtonWidgetClass, inpBox, XmNlabelString, s1=MKSTRING("none"), XmNmnemonic, 'o', XmNalignment, XmALIGNMENT_BEGINNING, XmNmarginHeight, 0, XmNset, False, NULL); XmStringFree(s1); inpLabel = XtVaCreateManagedWidget("inpLabel", xmLabelGadgetClass, form, XmNlabelString, s1=MKSTRING("Command Input (stdin):"), XmNalignment, XmALIGNMENT_BEGINNING, XmNmarginTop, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, inpBox, NULL); XmStringFree(s1); ucd->mneTextW = XtVaCreateManagedWidget("mne", xmTextWidgetClass, form, XmNcolumns, 1, XmNmaxLength, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RIGHT_MARGIN_POS-10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, inpLabel, NULL); RemapDeleteKey(ucd->mneTextW); ucd->accTextW = XtVaCreateManagedWidget("acc", xmTextWidgetClass, form, XmNcolumns, 12, XmNmaxLength, MAX_ACCEL_LEN-1, XmNcursorPositionVisible, False, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS-15, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, inpLabel, NULL); XtAddEventHandler(ucd->accTextW, KeyPressMask, False, (XtEventHandler)accKeyCB, ucd); XtAddCallback(ucd->accTextW, XmNfocusCallback, accFocusCB, ucd); XtAddCallback(ucd->accTextW, XmNlosingFocusCallback, accLoseFocusCB, ucd); accLabel = XtVaCreateManagedWidget("accLabel", xmLabelGadgetClass, form, XmNlabelString, s1=MKSTRING("Accelerator"), XmNmnemonic, 'l', XmNuserData, ucd->accTextW, XmNalignment, XmALIGNMENT_BEGINNING, XmNmarginTop, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, LIST_RIGHT + 24, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, ucd->mneTextW, NULL); XmStringFree(s1); XtVaCreateManagedWidget("mneLabel", xmLabelGadgetClass, form, XmNlabelString, s1=MKSTRING("Mnemonic"), XmNmnemonic, 'i', XmNuserData, ucd->mneTextW, XmNalignment, XmALIGNMENT_END, XmNmarginTop, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT + 24, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, ucd->mneTextW, NULL); XmStringFree(s1); ucd->nameTextW = XtVaCreateManagedWidget("name", xmTextWidgetClass, form, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, accLabel, NULL); RemapDeleteKey(ucd->nameTextW); nameLabel = XtVaCreateManagedWidget("nameLabel", xmLabelGadgetClass, form, XmNlabelString, s1=MKSTRING("Menu Entry"), XmNmnemonic, 'y', XmNuserData, ucd->nameTextW, XmNalignment, XmALIGNMENT_BEGINNING, XmNmarginTop, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, ucd->nameTextW, NULL); XmStringFree(s1); XtVaCreateManagedWidget("nameNotes", xmLabelGadgetClass, form, XmNlabelString, s1=MKSTRING("(> for sub-menu, @ language mode)"), XmNalignment, XmALIGNMENT_END, XmNmarginTop, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, nameLabel, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, ucd->nameTextW, NULL); XmStringFree(s1); XtVaCreateManagedWidget("topLabel", xmLabelGadgetClass, form, XmNlabelString, s1=MKSTRING( "Select a shell menu item from the list at left.\n\ Select \"New\" to add a new command to the menu."), XmNtopAttachment, XmATTACH_POSITION, XmNtopPosition, 2, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, nameLabel, NULL); XmStringFree(s1); cmdLabel = XtVaCreateManagedWidget("cmdLabel", xmLabelGadgetClass, form, XmNlabelString, s1=MKSTRING("Shell Command to Execute"), XmNmnemonic, 'x', XmNalignment, XmALIGNMENT_BEGINNING, XmNmarginTop, 5, XmNtopAttachment, XmATTACH_POSITION, XmNtopPosition, SHELL_CMD_TOP, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LEFT_MARGIN_POS, NULL); XmStringFree(s1); XtVaCreateManagedWidget("cmdLabel", xmLabelGadgetClass, form, XmNlabelString, s1=MKSTRING("(% expands to current filename, # to line number)"), XmNalignment, XmALIGNMENT_END, XmNmarginTop, 5, XmNtopAttachment, XmATTACH_POSITION, XmNtopPosition, SHELL_CMD_TOP, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, cmdLabel, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, NULL); XmStringFree(s1); okBtn = XtVaCreateManagedWidget("ok",xmPushButtonWidgetClass,form, XmNlabelString, s1=MKSTRING("OK"), XmNmarginWidth, BUTTON_WIDTH_MARGIN, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 13, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 29, XmNbottomAttachment, XmATTACH_POSITION, XmNbottomPosition, 99, NULL); XtAddCallback(okBtn, XmNactivateCallback, okCB, ucd); XmStringFree(s1); applyBtn = XtVaCreateManagedWidget("apply",xmPushButtonWidgetClass,form, XmNlabelString, s1=MKSTRING("Apply"), XmNmnemonic, 'A', XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 42, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 58, XmNbottomAttachment, XmATTACH_POSITION, XmNbottomPosition, 99, NULL); XtAddCallback(applyBtn, XmNactivateCallback, applyCB, ucd); XmStringFree(s1); closeBtn = XtVaCreateManagedWidget("close", xmPushButtonWidgetClass, form, XmNlabelString, s1=MKSTRING("Close"), XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 71, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 87, XmNbottomAttachment, XmATTACH_POSITION, XmNbottomPosition, 99, NULL); XtAddCallback(closeBtn, XmNactivateCallback, closeCB, ucd); XmStringFree(s1); ac = 0; XtSetArg(args[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++; XtSetArg(args[ac], XmNscrollHorizontal, False); ac++; XtSetArg(args[ac], XmNwordWrap, True); ac++; XtSetArg(args[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(args[ac], XmNtopWidget, cmdLabel); ac++; XtSetArg(args[ac], XmNleftAttachment, XmATTACH_POSITION); ac++; XtSetArg(args[ac], XmNleftPosition, LEFT_MARGIN_POS); ac++; XtSetArg(args[ac], XmNrightAttachment, XmATTACH_POSITION); ac++; XtSetArg(args[ac], XmNrightPosition, RIGHT_MARGIN_POS); ac++; XtSetArg(args[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; XtSetArg(args[ac], XmNbottomWidget, okBtn); ac++; XtSetArg(args[ac], XmNbottomOffset, 5); ac++; ucd->cmdTextW = XmCreateScrolledText(form, "name", args, ac); AddMouseWheelSupport(ucd->cmdTextW); XtManageChild(ucd->cmdTextW); MakeSingleLineTextW(ucd->cmdTextW); RemapDeleteKey(ucd->cmdTextW); XtVaSetValues(cmdLabel, XmNuserData, ucd->cmdTextW, NULL); /* for mnemonic */ /* Disable text input for the accelerator key widget, let the event handler manage it instead */ disableTextW(ucd->accTextW); /* initializs the dialog fields to match "New" list item */ updateDialogFields(NULL, ucd); /* Set initial default button */ XtVaSetValues(form, XmNdefaultButton, okBtn, NULL); XtVaSetValues(form, XmNcancelButton, closeBtn, NULL); /* Handle mnemonic selection of buttons and focus to dialog */ AddDialogMnemonicHandler(form, FALSE); /* realize all of the widgets in the new window */ RealizeWithoutForcingPosition(ucd->dlogShell); } /* ** Present a dialogs for editing the user specified commands in the Macro ** and background menus */ void EditMacroMenu(WindowInfo *window) { editMacroOrBGMenu(window, MACRO_CMDS); } void EditBGMenu(WindowInfo *window) { editMacroOrBGMenu(window, BG_MENU_CMDS); } static void editMacroOrBGMenu(WindowInfo *window, int dialogType) { Widget form, accLabel, pasteReplayBtn; Widget nameLabel, cmdLabel, okBtn, applyBtn, closeBtn; userCmdDialog *ucd; char *title; XmString s1; int ac, i; Arg args[20]; /* if the dialog is already displayed, just pop it to the top and return */ if (dialogType == MACRO_CMDS && MacroCmdDialog != NULL) { RaiseDialogWindow(MacroCmdDialog); return; } if (dialogType == BG_MENU_CMDS && BGMenuCmdDialog != NULL) { RaiseDialogWindow(BGMenuCmdDialog); return; } /* Create a structure for keeping track of dialog state */ ucd = (userCmdDialog *)XtMalloc(sizeof(userCmdDialog)); ucd->window = window; /* Set the dialog to operate on the Macro menu */ ucd->menuItemsList = (menuItemRec **)XtMalloc(sizeof(menuItemRec **) * MAX_ITEMS_PER_MENU); if (dialogType == MACRO_CMDS) { for (i=0; imenuItemsList[i] = copyMenuItemRec(MacroMenuItems[i]); ucd->nMenuItems = NMacroMenuItems; } else { /* BG_MENU_CMDS */ for (i=0; imenuItemsList[i] = copyMenuItemRec(BGMenuItems[i]); ucd->nMenuItems = NBGMenuItems; } ucd->dialogType = dialogType; title = dialogType == MACRO_CMDS ? "Macro Commands" : "Window Background Menu"; ac = 0; XtSetArg(args[ac], XmNdeleteResponse, XmDO_NOTHING); ac++; XtSetArg(args[ac], XmNiconName, title); ac++; XtSetArg(args[ac], XmNtitle, title); ac++; ucd->dlogShell = CreateWidget(TheAppShell, "macros", topLevelShellWidgetClass, args, ac); AddSmallIcon(ucd->dlogShell); form = XtVaCreateManagedWidget("editMacroCommands", xmFormWidgetClass, ucd->dlogShell, XmNautoUnmanage, False, XmNresizePolicy, XmRESIZE_NONE, NULL); XtAddCallback(form, XmNdestroyCallback, destroyCB, ucd); AddMotifCloseCallback(ucd->dlogShell, closeCB, ucd); ac = 0; XtSetArg(args[ac], XmNtopAttachment, XmATTACH_POSITION); ac++; XtSetArg(args[ac], XmNtopPosition, 2); ac++; XtSetArg(args[ac], XmNleftAttachment, XmATTACH_POSITION); ac++; XtSetArg(args[ac], XmNleftPosition, LEFT_MARGIN_POS); ac++; XtSetArg(args[ac], XmNrightAttachment, XmATTACH_POSITION); ac++; XtSetArg(args[ac], XmNrightPosition, LIST_RIGHT-1); ac++; XtSetArg(args[ac], XmNbottomAttachment, XmATTACH_POSITION); ac++; XtSetArg(args[ac], XmNbottomPosition, MACRO_CMD_TOP); ac++; ucd->managedList = CreateManagedList(form, "list", args, ac, (void **)ucd->menuItemsList, &ucd->nMenuItems, MAX_ITEMS_PER_MENU, 20, getDialogDataCB, ucd, setDialogDataCB, ucd, freeItemCB); ucd->selInpBtn = XtVaCreateManagedWidget("selInpBtn", xmToggleButtonWidgetClass, form, XmNlabelString, s1=MKSTRING("Requires Selection"), XmNmnemonic, 'R', XmNalignment, XmALIGNMENT_BEGINNING, XmNmarginHeight, 0, XmNset, False, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT, XmNbottomAttachment, XmATTACH_POSITION, XmNbottomPosition, MACRO_CMD_TOP, NULL); XmStringFree(s1); ucd->mneTextW = XtVaCreateManagedWidget("mne", xmTextWidgetClass, form, XmNcolumns, 1, XmNmaxLength, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RIGHT_MARGIN_POS-21-5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS-21, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, ucd->selInpBtn, XmNbottomOffset, 5, NULL); RemapDeleteKey(ucd->mneTextW); ucd->accTextW = XtVaCreateManagedWidget("acc", xmTextWidgetClass, form, XmNcolumns, 12, XmNmaxLength, MAX_ACCEL_LEN-1, XmNcursorPositionVisible, False, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS-20-10, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, ucd->selInpBtn, XmNbottomOffset, 5, NULL); XtAddEventHandler(ucd->accTextW, KeyPressMask, False, (XtEventHandler)accKeyCB, ucd); XtAddCallback(ucd->accTextW, XmNfocusCallback, accFocusCB, ucd); XtAddCallback(ucd->accTextW, XmNlosingFocusCallback, accLoseFocusCB, ucd); accLabel = XtVaCreateManagedWidget("accLabel", xmLabelGadgetClass, form, XmNlabelString, s1=MKSTRING("Accelerator"), XmNmnemonic, 'l', XmNuserData, ucd->accTextW, XmNalignment, XmALIGNMENT_BEGINNING, XmNmarginTop, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, LIST_RIGHT + 22, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, ucd->mneTextW, NULL); XmStringFree(s1); XtVaCreateManagedWidget("mneLabel", xmLabelGadgetClass, form, XmNlabelString, s1=MKSTRING("Mnemonic"), XmNmnemonic, 'i', XmNuserData, ucd->mneTextW, XmNalignment, XmALIGNMENT_END, XmNmarginTop, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT + 22, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS-21, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, ucd->mneTextW, NULL); XmStringFree(s1); pasteReplayBtn = XtVaCreateManagedWidget("pasteReplay", xmPushButtonWidgetClass, form, XmNlabelString, s1=MKSTRING("Paste Learn/\nReplay Macro"), XmNmnemonic, 'P', XmNsensitive, GetReplayMacro() != NULL, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RIGHT_MARGIN_POS-20, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_POSITION, XmNbottomPosition, MACRO_CMD_TOP, NULL); XtAddCallback(pasteReplayBtn, XmNactivateCallback, pasteReplayCB, ucd); XmStringFree(s1); ucd->nameTextW = XtVaCreateManagedWidget("name", xmTextWidgetClass, form, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, accLabel, NULL); RemapDeleteKey(ucd->nameTextW); nameLabel = XtVaCreateManagedWidget("nameLabel", xmLabelGadgetClass, form, XmNlabelString, s1=MKSTRING("Menu Entry"), XmNmnemonic, 'y', XmNuserData, ucd->nameTextW, XmNalignment, XmALIGNMENT_BEGINNING, XmNmarginTop, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, ucd->nameTextW, NULL); XmStringFree(s1); XtVaCreateManagedWidget("nameNotes", xmLabelGadgetClass, form, XmNlabelString, s1=MKSTRING("(> for sub-menu, @ language mode)"), XmNalignment, XmALIGNMENT_END, XmNmarginTop, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, nameLabel, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, ucd->nameTextW, NULL); XmStringFree(s1); XtVaCreateManagedWidget("topLabel", xmLabelGadgetClass, form, XmNlabelString, s1=MKSTRING( "Select a macro menu item from the list at left.\n\ Select \"New\" to add a new command to the menu."), XmNtopAttachment, XmATTACH_POSITION, XmNtopPosition, 2, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LIST_RIGHT, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, nameLabel, NULL); XmStringFree(s1); cmdLabel = XtVaCreateManagedWidget("cmdLabel", xmLabelGadgetClass, form, XmNlabelString, s1=MKSTRING("Macro Command to Execute"), XmNmnemonic, 'x', XmNalignment, XmALIGNMENT_BEGINNING, XmNmarginTop, 5, XmNtopAttachment, XmATTACH_POSITION, XmNtopPosition, MACRO_CMD_TOP, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LEFT_MARGIN_POS, NULL); XmStringFree(s1); okBtn = XtVaCreateManagedWidget("ok",xmPushButtonWidgetClass,form, XmNlabelString, s1=MKSTRING("OK"), XmNmarginWidth, BUTTON_WIDTH_MARGIN, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 8, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 23, XmNbottomAttachment, XmATTACH_POSITION, XmNbottomPosition, 99, NULL); XtAddCallback(okBtn, XmNactivateCallback, okCB, ucd); XmStringFree(s1); applyBtn = XtVaCreateManagedWidget("apply",xmPushButtonWidgetClass,form, XmNlabelString, s1=MKSTRING("Apply"), XmNmnemonic, 'A', XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 31, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 46, XmNbottomAttachment, XmATTACH_POSITION, XmNbottomPosition, 99, NULL); XtAddCallback(applyBtn, XmNactivateCallback, applyCB, ucd); XmStringFree(s1); applyBtn = XtVaCreateManagedWidget("check",xmPushButtonWidgetClass,form, XmNlabelString, s1=MKSTRING("Check"), XmNmnemonic, 'C', XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 54, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 69, XmNbottomAttachment, XmATTACH_POSITION, XmNbottomPosition, 99, NULL); XtAddCallback(applyBtn, XmNactivateCallback, checkCB, ucd); XmStringFree(s1); closeBtn = XtVaCreateManagedWidget("close", xmPushButtonWidgetClass, form, XmNlabelString, s1=MKSTRING("Close"), XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 77, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 92, XmNbottomAttachment, XmATTACH_POSITION, XmNbottomPosition, 99, NULL); XtAddCallback(closeBtn, XmNactivateCallback, closeCB, ucd); XmStringFree(s1); ac = 0; XtSetArg(args[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++; XtSetArg(args[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(args[ac], XmNtopWidget, cmdLabel); ac++; XtSetArg(args[ac], XmNleftAttachment, XmATTACH_POSITION); ac++; XtSetArg(args[ac], XmNleftPosition, LEFT_MARGIN_POS); ac++; XtSetArg(args[ac], XmNrightAttachment, XmATTACH_POSITION); ac++; XtSetArg(args[ac], XmNrightPosition, RIGHT_MARGIN_POS); ac++; XtSetArg(args[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; XtSetArg(args[ac], XmNbottomWidget, okBtn); ac++; XtSetArg(args[ac], XmNbottomOffset, 5); ac++; ucd->cmdTextW = XmCreateScrolledText(form, "name", args, ac); AddMouseWheelSupport(ucd->cmdTextW); XtManageChild(ucd->cmdTextW); RemapDeleteKey(ucd->cmdTextW); XtVaSetValues(cmdLabel, XmNuserData, ucd->cmdTextW, NULL); /* for mnemonic */ /* Disable text input for the accelerator key widget, let the event handler manage it instead */ disableTextW(ucd->accTextW); /* initializs the dialog fields to match "New" list item */ updateDialogFields(NULL, ucd); /* Set initial default button */ XtVaSetValues(form, XmNdefaultButton, okBtn, NULL); XtVaSetValues(form, XmNcancelButton, closeBtn, NULL); /* Handle mnemonic selection of buttons and focus to dialog */ AddDialogMnemonicHandler(form, FALSE); /* Make widgets for top level shell and paste-replay buttons available to other functions */ if (dialogType == MACRO_CMDS) { MacroCmdDialog = ucd->dlogShell; MacroPasteReplayBtn = pasteReplayBtn; } else { BGMenuCmdDialog = ucd->dlogShell; BGMenuPasteReplayBtn = pasteReplayBtn; } /* Realize all of the widgets in the new dialog */ RealizeWithoutForcingPosition(ucd->dlogShell); } /* ** Update the Shell, Macro, and Window Background menus of window ** "window" from the currently loaded command descriptions. */ void UpdateUserMenus(WindowInfo *window) { if (!IsTopDocument(window)) return; /* update user menus, which are shared over all documents, only if language mode was changed */ if (window->userMenuCache->umcLanguageMode != window->languageMode) { #ifndef VMS updateMenu(window, SHELL_CMDS); #endif updateMenu(window, MACRO_CMDS); /* remember language mode assigned to shared user menus */ window->userMenuCache->umcLanguageMode = window->languageMode; } /* update background menu, which is owned by a single document, only if language mode was changed */ if (window->userBGMenuCache.ubmcLanguageMode != window->languageMode) { updateMenu(window, BG_MENU_CMDS); /* remember language mode assigned to background menu */ window->userBGMenuCache.ubmcLanguageMode = window->languageMode; } } /* ** Dim/undim buttons for pasting replay macros into macro and bg menu dialogs */ void DimPasteReplayBtns(int sensitive) { if (MacroCmdDialog != NULL) XtSetSensitive(MacroPasteReplayBtn, sensitive); if (BGMenuCmdDialog != NULL) XtSetSensitive(BGMenuPasteReplayBtn, sensitive); } /* ** Dim/undim user programmable menu items which depend on there being ** a selection in their associated window. */ void DimSelectionDepUserMenuItems(WindowInfo *window, int sensitive) { if (!IsTopDocument(window)) return; #ifndef VMS dimSelDepItemsInMenu(window->shellMenuPane, ShellMenuItems, NShellMenuItems, sensitive); #endif /*VMS*/ dimSelDepItemsInMenu(window->macroMenuPane, MacroMenuItems, NMacroMenuItems, sensitive); dimSelDepItemsInMenu(window->bgMenuPane, BGMenuItems, NBGMenuItems, sensitive); } static void dimSelDepItemsInMenu(Widget menuPane, menuItemRec **menuList, int nMenuItems, int sensitive) { WidgetList items; Widget subMenu; XtPointer userData; int n, index; Cardinal nItems; XtVaGetValues(menuPane, XmNchildren, &items, XmNnumChildren, &nItems, NULL); for (n=0; n<(int)nItems; n++) { XtVaGetValues(items[n], XmNuserData, &userData, NULL); if (userData != (XtPointer)PERMANENT_MENU_ITEM) { if (XtClass(items[n]) == xmCascadeButtonWidgetClass) { XtVaGetValues(items[n], XmNsubMenuId, &subMenu, NULL); dimSelDepItemsInMenu(subMenu, menuList, nMenuItems, sensitive); } else { index = (int)userData - 10; if (index <0 || index >= nMenuItems) return; if (menuList[index]->input == FROM_SELECTION) XtSetSensitive(items[n], sensitive); } } } } /* ** Harmless kludge for making undo/redo menu items in background menu properly ** sensitive (even though they're programmable) along with real undo item ** in the Edit menu */ void SetBGMenuUndoSensitivity(WindowInfo *window, int sensitive) { if (window->bgMenuUndoItem != NULL) SetSensitive(window, window->bgMenuUndoItem, sensitive); } void SetBGMenuRedoSensitivity(WindowInfo *window, int sensitive) { if (window->bgMenuRedoItem != NULL) SetSensitive(window, window->bgMenuRedoItem, sensitive); } /* ** Generate a text string for the preferences file describing the contents ** of the shell cmd list. This string is not exactly of the form that it ** can be read by LoadShellCmdsString, rather, it is what needs to be written ** to a resource file such that it will read back in that form. */ char *WriteShellCmdsString(void) { return writeMenuItemString(ShellMenuItems, NShellMenuItems, SHELL_CMDS); } /* ** Generate a text string for the preferences file describing the contents of ** the macro menu and background menu commands lists. These strings are not ** exactly of the form that it can be read by LoadMacroCmdsString, rather, it ** is what needs to be written to a resource file such that it will read back ** in that form. */ char *WriteMacroCmdsString(void) { return writeMenuItemString(MacroMenuItems, NMacroMenuItems, MACRO_CMDS); } char *WriteBGMenuCmdsString(void) { return writeMenuItemString(BGMenuItems, NBGMenuItems, BG_MENU_CMDS); } /* ** Read a string representing shell command menu items and add them to the ** internal list used for constructing shell menus */ int LoadShellCmdsString(char *inString) { return loadMenuItemString(inString, ShellMenuItems, &NShellMenuItems, SHELL_CMDS); } /* ** Read strings representing macro menu or background menu command menu items ** and add them to the internal lists used for constructing menus */ int LoadMacroCmdsString(char *inString) { return loadMenuItemString(inString, MacroMenuItems, &NMacroMenuItems, MACRO_CMDS); } int LoadBGMenuCmdsString(char *inString) { return loadMenuItemString(inString, BGMenuItems, &NBGMenuItems, BG_MENU_CMDS); } /* ** Cache user menus: ** Setup user menu info after read of macro, shell and background menu ** string (reason: language mode info from preference string is read *after* ** user menu preference string was read). */ void SetupUserMenuInfo(void) { parseMenuItemList(ShellMenuItems, NShellMenuItems, ShellMenuInfo, &ShellSubMenus); parseMenuItemList(MacroMenuItems, NMacroMenuItems, MacroMenuInfo, &MacroSubMenus); parseMenuItemList(BGMenuItems , NBGMenuItems , BGMenuInfo , &BGSubMenus); } /* ** Cache user menus: ** Update user menu info to take into account e.g. change of language modes ** (i.e. add / move / delete of language modes etc). */ void UpdateUserMenuInfo(void) { freeUserMenuInfoList(ShellMenuInfo, NShellMenuItems); freeSubMenuCache(&ShellSubMenus); parseMenuItemList(ShellMenuItems, NShellMenuItems, ShellMenuInfo, &ShellSubMenus); freeUserMenuInfoList(MacroMenuInfo, NMacroMenuItems); freeSubMenuCache(&MacroSubMenus); parseMenuItemList(MacroMenuItems, NMacroMenuItems, MacroMenuInfo, &MacroSubMenus); freeUserMenuInfoList(BGMenuInfo, NBGMenuItems); freeSubMenuCache(&BGSubMenus); parseMenuItemList(BGMenuItems, NBGMenuItems, BGMenuInfo, &BGSubMenus); } /* ** Search through the shell menu and execute the first command with menu item ** name "itemName". Returns True on successs and False on failure. */ #ifndef VMS int DoNamedShellMenuCmd(WindowInfo *window, const char *itemName, int fromMacro) { int i; for (i=0; iname, itemName)) { if (ShellMenuItems[i]->output == TO_SAME_WINDOW && CheckReadOnly(window)) return False; DoShellMenuCmd(window, ShellMenuItems[i]->cmd, ShellMenuItems[i]->input, ShellMenuItems[i]->output, ShellMenuItems[i]->repInput, ShellMenuItems[i]->saveFirst, ShellMenuItems[i]->loadAfter, fromMacro); return True; } } return False; } #endif /*VMS*/ /* ** Search through the Macro or background menu and execute the first command ** with menu item name "itemName". Returns True on successs and False on ** failure. */ int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName) { int i; for (i=0; iname, itemName)) { DoMacro(window, MacroMenuItems[i]->cmd, "macro menu command"); return True; } } return False; } int DoNamedBGMenuCmd(WindowInfo *window, const char *itemName) { int i; for (i=0; iname, itemName)) { DoMacro(window, BGMenuItems[i]->cmd, "background menu macro"); return True; } } return False; } /* ** Cache user menus: ** Rebuild all of the Shell, Macro, Background menus of given editor window. */ void RebuildAllMenus(WindowInfo *window) { rebuildMenu(window, SHELL_CMDS); rebuildMenu(window, MACRO_CMDS); rebuildMenu(window, BG_MENU_CMDS); } /* ** Cache user menus: ** Rebuild either Shell, Macro or Background menus of all editor windows. */ static void rebuildMenuOfAllWindows(int menuType) { WindowInfo *w; for (w=WindowList; w!=NULL; w=w->next) rebuildMenu(w, menuType); } /* ** Rebuild either the Shell, Macro or Background menu of "window", depending ** on value of "menuType". Rebuild is realized by following main steps: ** - dismiss user (sub) menu tearoff. ** - delete all user defined menu widgets. ** - update user menu including (re)creation of menu widgets. */ static void rebuildMenu(WindowInfo *window, int menuType) { selectedUserMenu menu; /* Background menu is always rebuild (exists once per document). Shell, macro (user) menu cache is rebuild only, if given window is currently displayed on top. */ if (menuType != BG_MENU_CMDS && !IsTopDocument(window)) return; /* Fetch the appropriate menu data */ selectUserMenu(window, menuType, &menu); /* dismiss user menu tearoff, to workaround the quick but noticeable shrink-expand bug, most probably triggered by the rebuild of the user menus. In any case, the submenu tearoffs will later be dismissed too in order to prevent dangling tearoffs, so doing this also for the main user menu tearoffs shouldn't be so bad */ if (!XmIsMenuShell(XtParent(menu.sumMenuPane))) _XmDismissTearOff(XtParent(menu.sumMenuPane), NULL, NULL); /* destroy all widgets related to menu pane */ deleteMenuItems(menu.sumMenuPane); /* remove cached user menu info */ freeUserMenuList(menu.sumMainMenuList); *menu.sumMenuCreated = False; /* re-create & cache user menu items */ updateMenu(window, menuType); } /* ** Fetch the appropriate menu info for given menu type */ static void selectUserMenu(WindowInfo *window, int menuType, selectedUserMenu *menu) { if (menuType == SHELL_CMDS) { menu->sumMenuPane = window->shellMenuPane; menu->sumNbrOfListItems = NShellMenuItems; menu->sumItemList = ShellMenuItems; menu->sumInfoList = ShellMenuInfo; menu->sumSubMenus = &ShellSubMenus; menu->sumMainMenuList = &window->userMenuCache->umcShellMenuList; menu->sumMenuCreated = &window->userMenuCache->umcShellMenuCreated; } else if (menuType == MACRO_CMDS) { menu->sumMenuPane = window->macroMenuPane; menu->sumNbrOfListItems = NMacroMenuItems; menu->sumItemList = MacroMenuItems; menu->sumInfoList = MacroMenuInfo; menu->sumSubMenus = &MacroSubMenus; menu->sumMainMenuList = &window->userMenuCache->umcMacroMenuList; menu->sumMenuCreated = &window->userMenuCache->umcMacroMenuCreated; } else { /* BG_MENU_CMDS */ menu->sumMenuPane = window->bgMenuPane; menu->sumNbrOfListItems = NBGMenuItems; menu->sumItemList = BGMenuItems; menu->sumInfoList = BGMenuInfo; menu->sumSubMenus = &BGSubMenus; menu->sumMainMenuList = &window->userBGMenuCache.ubmcMenuList; menu->sumMenuCreated = &window->userBGMenuCache.ubmcMenuCreated; } menu->sumType = menuType; } /* ** Updates either the Shell, Macro or Background menu of "window", depending ** on value of "menuType". Update is realized by following main steps: ** - set / reset "to be managed" flag of user menu info list items ** according to current selected language mode. ** - create *all* user menu items (widgets etc). related to given ** window & menu type, if not done before. ** - manage / unmanage user menu widgets according to "to be managed" ** indication of user menu info list items. */ static void updateMenu(WindowInfo *window, int menuType) { selectedUserMenu menu; /* Fetch the appropriate menu data */ selectUserMenu(window, menuType, &menu); /* Set / reset "to be managed" flag of all info list items */ applyLangModeToUserMenuInfo(menu.sumInfoList, menu.sumNbrOfListItems, window->languageMode); /* create user menu items, if not done before */ if (!*menu.sumMenuCreated) createMenuItems(window, &menu); /* manage user menu items depending on current language mode */ manageUserMenu(&menu, window); if (menuType == BG_MENU_CMDS) { /* Set the proper sensitivity of items which may be dimmed */ SetBGMenuUndoSensitivity(window, XtIsSensitive(window->undoItem)); SetBGMenuRedoSensitivity(window, XtIsSensitive(window->redoItem)); } DimSelectionDepUserMenuItems(window, window->buffer->primary.selected); } /* ** Manually adjust the dimension of the menuShell _before_ ** re-managing the menu pane, to either expose hidden menu ** entries or remove empty space. */ static void manageTearOffMenu(Widget menuPane) { Dimension width, height, border; /* somehow OM went into a long CPU cycling when we attempt to change the shell window dimension by setting the XmNwidth & XmNheight directly. Using XtResizeWidget() seem to fix it */ XtVaGetValues(XtParent(menuPane), XmNborderWidth, &border, NULL); XtVaGetValues(menuPane, XmNwidth, &width, XmNheight, &height, NULL); XtResizeWidget(XtParent(menuPane), width, height, border); XtManageChild(menuPane); } /* ** Cache user menus: ** Reset manage mode of user menu items in window cache. */ static void resetManageMode(UserMenuList *list) { int i; UserMenuListElement *element; for (i=0; iumlNbrItems; i ++) { element = list->umlItems[i]; /* remember current manage mode before reset it to "unmanaged" */ element->umlePrevManageMode = element->umleManageMode; element->umleManageMode = UMMM_UNMANAGE; /* recursively reset manage mode of sub-menus */ if (element->umleSubMenuList != NULL) resetManageMode(element->umleSubMenuList); } } /* ** Cache user menus: ** Manage all menu widgets of given user sub-menu list. */ static void manageAllSubMenuWidgets(UserMenuListElement *subMenu) { int i; UserMenuList *subMenuList; UserMenuListElement *element; WidgetList widgetList; Cardinal nWidgetListItems; /* if the sub-menu is torn off, unmanage the menu pane before updating it to prevent the tear-off menu from shrinking and expanding as the menu entries are (un)managed */ if (!XmIsMenuShell(XtParent(subMenu->umleSubMenuPane))) { XtUnmanageChild(subMenu->umleSubMenuPane); } /* manage all children of sub-menu pane */ XtVaGetValues(subMenu->umleSubMenuPane, XmNchildren, &widgetList, XmNnumChildren, &nWidgetListItems, NULL); XtManageChildren(widgetList, nWidgetListItems); /* scan, if an menu item of given sub-menu holds a nested sub-menu */ subMenuList = subMenu->umleSubMenuList; for (i=0; iumlNbrItems; i ++) { element = subMenuList->umlItems[i]; if (element->umleSubMenuList != NULL) { /* if element is a sub-menu, then continue managing all items of that sub-menu recursively */ manageAllSubMenuWidgets(element); } } /* manage sub-menu pane widget itself */ XtManageChild(subMenu->umleMenuItem); /* if the sub-menu is torn off, then adjust & manage the menu */ if (!XmIsMenuShell(XtParent(subMenu->umleSubMenuPane))) { manageTearOffMenu(subMenu->umleSubMenuPane); } /* redisplay sub-menu tearoff window, if the sub-menu was torn off before */ ShowHiddenTearOff(subMenu->umleSubMenuPane); } /* ** Cache user menus: ** Unmanage all menu widgets of given user sub-menu list. */ static void unmanageAllSubMenuWidgets(UserMenuListElement *subMenu) { int i; Widget shell; UserMenuList *subMenuList; UserMenuListElement *element; WidgetList widgetList; Cardinal nWidgetListItems; /* if sub-menu is torn-off, then unmap its shell (so tearoff window isn't displayed anymore) */ shell = XtParent(subMenu->umleSubMenuPane); if (!XmIsMenuShell(shell)) { XtUnmapWidget(shell); } /* unmanage all children of sub-menu pane */ XtVaGetValues(subMenu->umleSubMenuPane, XmNchildren, &widgetList, XmNnumChildren, &nWidgetListItems, NULL); XtUnmanageChildren(widgetList, nWidgetListItems); /* scan, if an menu item of given sub-menu holds a nested sub-menu */ subMenuList = subMenu->umleSubMenuList; for (i=0; iumlNbrItems; i ++) { element = subMenuList->umlItems[i]; if (element->umleSubMenuList != NULL) { /* if element is a sub-menu, then continue unmanaging all items of that sub-menu recursively */ unmanageAllSubMenuWidgets(element); } } /* unmanage sub-menu pane widget itself */ XtUnmanageChild(subMenu->umleMenuItem); } /* ** Cache user menus: ** Manage / unmanage menu widgets according to given user menu list. */ static void manageMenuWidgets(UserMenuList *list) { int i; UserMenuListElement *element; /* (un)manage all elements of given user menu list */ for (i=0; iumlNbrItems; i ++) { element = list->umlItems[i]; if (element->umlePrevManageMode != element->umleManageMode || element->umleManageMode == UMMM_MANAGE) { /* previous and current manage mode differ OR current manage mode indicates: element needs to be (un)managed individually */ if (element->umleManageMode == UMMM_MANAGE_ALL) { /* menu item represented by "element" is a sub-menu and needs to be completely managed */ manageAllSubMenuWidgets(element); } else if (element->umleManageMode == UMMM_MANAGE) { if (element->umlePrevManageMode == UMMM_UNMANAGE || element->umlePrevManageMode == UMMM_UNMANAGE_ALL) { /* menu item represented by "element" was unmanaged before and needs to be managed now */ XtManageChild(element->umleMenuItem); } /* if element is a sub-menu, then continue (un)managing single elements of that sub-menu one by one */ if (element->umleSubMenuList != NULL) { /* if the sub-menu is torn off, unmanage the menu pane before updating it to prevent the tear-off menu from shrinking and expanding as the menu entries are (un)managed */ if (!XmIsMenuShell(XtParent(element->umleSubMenuPane))) { XtUnmanageChild(element->umleSubMenuPane); } /* (un)manage menu entries of sub-menu */ manageMenuWidgets(element->umleSubMenuList); /* if the sub-menu is torn off, then adjust & manage the menu */ if (!XmIsMenuShell(XtParent(element->umleSubMenuPane))) { manageTearOffMenu(element->umleSubMenuPane); } /* if the sub-menu was torn off then redisplay it */ ShowHiddenTearOff(element->umleSubMenuPane); } } else if (element->umleManageMode == UMMM_UNMANAGE_ALL){ /* menu item represented by "element" is a sub-menu and needs to be completely unmanaged */ unmanageAllSubMenuWidgets(element); } else { /* current mode is UMMM_UNMANAGE -> menu item represented by "element" is a single menu item and needs to be unmanaged */ XtUnmanageChild(element->umleMenuItem); } } } } /* ** Cache user menus: ** Remove accelerators from all items of given user (sub-)menu list. */ static void removeAccelFromMenuWidgets(UserMenuList *menuList) { int i; UserMenuListElement *element; /* scan all elements of this (sub-)menu */ for (i=0; iumlNbrItems; i ++) { element = menuList->umlItems[i]; if (element->umleSubMenuList != NULL) { /* if element is a sub-menu, then continue removing accelerators from all items of that sub-menu recursively */ removeAccelFromMenuWidgets(element->umleSubMenuList); } else if (element->umleAccKeys != NULL && element->umleManageMode == UMMM_UNMANAGE && element->umlePrevManageMode == UMMM_MANAGE) { /* remove accelerator if one was bound */ XtVaSetValues(element->umleMenuItem, XmNaccelerator, NULL, NULL); } } } /* ** Cache user menus: ** Assign accelerators to all managed items of given user (sub-)menu list. */ static void assignAccelToMenuWidgets(UserMenuList *menuList, WindowInfo *window) { int i; UserMenuListElement *element; /* scan all elements of this (sub-)menu */ for (i=0; iumlNbrItems; i ++) { element = menuList->umlItems[i]; if (element->umleSubMenuList != NULL) { /* if element is a sub-menu, then continue assigning accelerators to all managed items of that sub-menu recursively */ assignAccelToMenuWidgets(element->umleSubMenuList, window); } else if (element->umleAccKeys != NULL && element->umleManageMode == UMMM_MANAGE && element->umlePrevManageMode == UMMM_UNMANAGE) { /* assign accelerator if applicable */ XtVaSetValues(element->umleMenuItem, XmNaccelerator, element->umleAccKeys, NULL); if (!element->umleAccLockPatchApplied) { UpdateAccelLockPatch(window->splitPane, element->umleMenuItem); element->umleAccLockPatchApplied = True; } } } } /* ** Cache user menus: ** (Un)Manage all items of selected user menu. */ static void manageUserMenu(selectedUserMenu *menu, WindowInfo *window) { int n, i; int *id; Boolean currentLEisSubMenu; userMenuInfo *info; UserMenuList *menuList; UserMenuListElement *currentLE; UserMenuManageMode *mode; /* reset manage mode of all items of selected user menu in window cache */ resetManageMode(menu->sumMainMenuList); /* set manage mode of all items of selected user menu in window cache according to the "to be managed" indication of the info list */ for (n=0; nsumNbrOfListItems; n++) { info = menu->sumInfoList[n]; menuList = menu->sumMainMenuList; id = info->umiId; /* select all menu list items belonging to menu record "info" using hierarchical ID of current menu info (e.g. id = {3} means: 4th element of main menu; {0} = 1st element etc.)*/ for (i=0; iumiIdLen; i ++) { currentLE = menuList->umlItems[*id]; mode = ¤tLE->umleManageMode; currentLEisSubMenu = (currentLE->umleSubMenuList != NULL); if (info->umiToBeManaged) { /* menu record needs to be managed: */ if (*mode == UMMM_UNMANAGE) { /* "mode" was not touched after reset ("init. state"): if current list element represents a sub-menu, then probably the complete sub-menu needs to be managed too. If current list element indicates single menu item, then just this item needs to be managed */ if (currentLEisSubMenu) { *mode = UMMM_MANAGE_ALL; } else { *mode = UMMM_MANAGE; } } else if (*mode == UMMM_UNMANAGE_ALL) { /* "mode" was touched after reset: current list element represents a sub-menu and min. one element of the sub-menu needs to be unmanaged -> the sub-menu needs to be (un)managed element by element */ *mode = UMMM_MANAGE; } } else { /* menu record needs to be unmanaged: */ if (*mode == UMMM_UNMANAGE) { /* "mode" was not touched after reset ("init. state"): if current list element represents a sub-menu, then probably the complete sub-menu needs to be unmanaged too. */ if (currentLEisSubMenu) { *mode = UMMM_UNMANAGE_ALL; } } else if (*mode == UMMM_MANAGE_ALL) { /* "mode" was touched after reset: current list element represents a sub-menu and min. one element of the sub-menu needs to be managed -> the sub-menu needs to be (un)managed element by element */ *mode = UMMM_MANAGE; } } menuList = currentLE->umleSubMenuList; id ++; } } /* if the menu is torn off, unmanage the menu pane before updating it to prevent the tear-off menu from shrinking and expanding as the menu entries are managed */ if (!XmIsMenuShell(XtParent(menu->sumMenuPane))) XtUnmanageChild(menu->sumMenuPane); /* manage menu widgets according to current / previous manage mode of user menu window cache */ manageMenuWidgets(menu->sumMainMenuList); /* Note: before new accelerator is assigned it seems to be necessary to remove old accelerator from user menu widgets. Removing same accelerator *after* it was assigned to another user menu widget doesn't work */ removeAccelFromMenuWidgets(menu->sumMainMenuList); assignAccelToMenuWidgets(menu->sumMainMenuList, window); /* if the menu is torn off, then adjust & manage the menu */ if (!XmIsMenuShell(XtParent(menu->sumMenuPane))) manageTearOffMenu(menu->sumMenuPane); } /* ** Create either the variable Shell menu, Macro menu or Background menu ** items of "window" (driven by value of "menuType") */ static void createMenuItems(WindowInfo *window, selectedUserMenu *menu) { Widget btn, subPane, newSubPane; int n; menuItemRec *item; menuTreeItem *menuTree; int i, nTreeEntries, size; char *hierName, *namePtr, *subMenuName, *subSep, *fullName; int menuType = menu->sumType; userMenuInfo *info; userSubMenuCache *subMenus = menu->sumSubMenus; userSubMenuInfo *subMenuInfo; UserMenuList *menuList; UserMenuListElement *currentLE; int subMenuDepth; char accKeysBuf[MAX_ACCEL_LEN+5]; char *accKeys; /* Allocate storage for structures to help find panes of sub-menus */ size = sizeof(menuTreeItem) * menu->sumNbrOfListItems; menuTree = (menuTreeItem *)XtMalloc(size); nTreeEntries = 0; /* Harmless kludge: undo and redo items are marked specially if found in the background menu, and used to dim/undim with edit menu */ window->bgMenuUndoItem = NULL; window->bgMenuRedoItem = NULL; /* ** Add items to the menu pane, creating hierarchical sub-menus as ** necessary */ allocUserMenuList(menu->sumMainMenuList, subMenus->usmcNbrOfMainMenuItems); for (n=0; nsumNbrOfListItems; n++) { item = menu->sumItemList[n]; info = menu->sumInfoList[n]; menuList = menu->sumMainMenuList; subMenuDepth = 0; fullName = info->umiName; /* create/find sub-menus, stripping off '>' until item name is reached, then create the menu item */ namePtr = fullName; subPane = menu->sumMenuPane; for (;;) { subSep = strchr(namePtr, '>'); if (subSep == NULL) { btn = createUserMenuItem(subPane, namePtr, item, n, (XtCallbackProc)(menuType == SHELL_CMDS ? shellMenuCB : (menuType == MACRO_CMDS ? macroMenuCB : bgMenuCB)), (XtPointer)window); if (menuType == BG_MENU_CMDS && !strcmp(item->cmd, "undo()\n")) window->bgMenuUndoItem = btn; else if (menuType == BG_MENU_CMDS && !strcmp(item->cmd,"redo()\n")) window->bgMenuRedoItem = btn; /* generate accelerator keys */ genAccelEventName(accKeysBuf, item->modifiers, item->keysym); accKeys = item->keysym == NoSymbol ? NULL : XtNewString(accKeysBuf); /* create corresponding menu list item */ menuList->umlItems[menuList->umlNbrItems ++] = allocUserMenuListElement(btn, accKeys); break; } hierName = copySubstring(fullName, subSep - fullName); subMenuInfo = findSubMenuInfo(subMenus, hierName); newSubPane = findInMenuTree(menuTree, nTreeEntries, hierName); if (newSubPane == NULL) { subMenuName = copySubstring(namePtr, subSep - namePtr); newSubPane = createUserSubMenu(subPane, subMenuName, &btn); XtFree(subMenuName); menuTree[nTreeEntries].name = hierName; menuTree[nTreeEntries++].menuPane = newSubPane; currentLE = allocUserMenuListElement(btn, NULL); menuList->umlItems[menuList->umlNbrItems ++] = currentLE; currentLE->umleSubMenuPane = newSubPane; currentLE->umleSubMenuList = allocUserSubMenuList(subMenuInfo->usmiId[subMenuInfo->usmiIdLen]); } else { currentLE = menuList->umlItems[subMenuInfo->usmiId[subMenuDepth]]; XtFree(hierName); } subPane = newSubPane; menuList = currentLE->umleSubMenuList; subMenuDepth ++; namePtr = subSep + 1; } } *menu->sumMenuCreated = True; /* Free the structure used to keep track of sub-menus durring creation */ for (i=0; ib>c...) */ static Widget findInMenuTree(menuTreeItem *menuTree, int nTreeEntries, const char *hierName) { int i; for (i=0; imodifiers, f->keysym); st1=XmStringCreateSimple(name); st2=XmStringCreateSimple(accText); btn = XtVaCreateWidget("cmd", xmPushButtonWidgetClass, menuPane, XmNlabelString, st1, XmNacceleratorText, st2, XmNmnemonic, f->mnemonic, XmNuserData, (XtPointer)(index+10), NULL); XtAddCallback(btn, XmNactivateCallback, cbRtn, cbArg); XmStringFree(st1); XmStringFree(st2); return btn; } /* ** Add a user-defined sub-menu to an established pull-down menu, marking ** it's userData field with TEMPORARY_MENU_ITEM so it can be found and ** removed later if the menu is redefined. Returns the menu pane of the ** new sub-menu. */ static Widget createUserSubMenu(Widget parent, char *label, Widget *menuItem) { Widget menuPane; XmString st1; static Arg args[1] = {{XmNuserData, (XtArgVal)TEMPORARY_MENU_ITEM}}; menuPane = CreatePulldownMenu(parent, "userPulldown", args, 1); *menuItem = XtVaCreateWidget("userCascade", xmCascadeButtonWidgetClass, parent, XmNlabelString, st1=XmStringCreateSimple(label), XmNsubMenuId, menuPane, XmNuserData, TEMPORARY_MENU_ITEM, NULL); XmStringFree(st1); return menuPane; } /* ** Cache user menus: ** Delete all variable menu items of given menu pane */ static void deleteMenuItems(Widget menuPane) { WidgetList itemList, items; Cardinal nItems; Widget subMenuID; XtPointer userData; int n; /* Fetch the list of children from the menu pane to delete */ XtVaGetValues(menuPane, XmNchildren, &itemList, XmNnumChildren, &nItems, NULL); /* make a copy because the widget alters the list as you delete widgets */ items = (WidgetList)XtMalloc(sizeof(Widget) * nItems); memcpy(items, itemList, sizeof(Widget) * nItems); /* delete all of the widgets not marked as PERMANENT_MENU_ITEM */ for (n=0; n<(int)nItems; n++) { XtVaGetValues(items[n], XmNuserData, &userData, NULL); if (userData != (XtPointer)PERMANENT_MENU_ITEM) { if (XtClass(items[n]) == xmCascadeButtonWidgetClass) { XtVaGetValues(items[n], XmNsubMenuId, &subMenuID, NULL); /* prevent dangling submenu tearoffs */ if (!XmIsMenuShell(XtParent(subMenuID))) _XmDismissTearOff(XtParent(subMenuID), NULL, NULL); deleteMenuItems(subMenuID); #if XmVersion < 2000 /* Skipping this creates a memory and server resource leak (though both are reclaimed on window closing). In Motif 2.0 (and beyond?) there is a potential crash during phase 2 widget destruction in "SetCascadeField", and in Motif 1.2 there are free-memory reads. I would really like to be able to destroy this. */ XtDestroyWidget(subMenuID); #endif } else { /* remove accel. before destroy or lose it forever */ XtVaSetValues(items[n], XmNaccelerator, NULL, NULL); } XtDestroyWidget(items[n]); } } XtFree((char *)items); } static void closeCB(Widget w, XtPointer clientData, XtPointer callData) { userCmdDialog *ucd = (userCmdDialog *)clientData; /* Mark that there's no longer a (macro, bg, or shell) dialog up */ if (ucd->dialogType == SHELL_CMDS) ShellCmdDialog = NULL; else if (ucd->dialogType == MACRO_CMDS) MacroCmdDialog = NULL; else BGMenuCmdDialog = NULL; /* pop down and destroy the dialog (memory for ucd is freed in the destroy callback) */ XtDestroyWidget(ucd->dlogShell); } static void okCB(Widget w, XtPointer clientData, XtPointer callData) { userCmdDialog *ucd = (userCmdDialog *)clientData; /* Read the dialog fields, and update the menus */ if (!applyDialogChanges(ucd)) return; /* Mark that there's no longer a (macro, bg, or shell) dialog up */ if (ucd->dialogType == SHELL_CMDS) ShellCmdDialog = NULL; else if (ucd->dialogType == MACRO_CMDS) MacroCmdDialog = NULL; else BGMenuCmdDialog = NULL; /* pop down and destroy the dialog (memory for ucd is freed in the destroy callback) */ XtDestroyWidget(ucd->dlogShell); } static void applyCB(Widget w, XtPointer clientData, XtPointer callData) { applyDialogChanges((userCmdDialog *)clientData); } static void checkCB(Widget w, XtPointer clientData, XtPointer callData) { userCmdDialog *ucd = (userCmdDialog *)clientData; if (checkMacro(ucd)) { DialogF(DF_INF, ucd->dlogShell, 1, "Macro", "Macro compiled without error", "OK"); } } static int checkMacro(userCmdDialog *ucd) { menuItemRec *f; f = readDialogFields(ucd, False); if (f == NULL) return False; if (!checkMacroText(f->cmd, ucd->dlogShell, ucd->cmdTextW)) { freeMenuItemRec(f); return False; } return True; } static int checkMacroText(char *macro, Widget errorParent, Widget errFocus) { Program *prog; char *errMsg, *stoppedAt; prog = ParseMacro(macro, &errMsg, &stoppedAt); if (prog == NULL) { if (errorParent != NULL) { ParseError(errorParent, macro, stoppedAt, "macro", errMsg); XmTextSetInsertionPosition(errFocus, stoppedAt - macro); XmProcessTraversal(errFocus, XmTRAVERSE_CURRENT); } return False; } FreeProgram(prog); if (*stoppedAt != '\0') { if (errorParent != NULL) { ParseError(errorParent, macro, stoppedAt,"macro","syntax error"); XmTextSetInsertionPosition(errFocus, stoppedAt - macro); XmProcessTraversal(errFocus, XmTRAVERSE_CURRENT); } return False; } return True; } static int applyDialogChanges(userCmdDialog *ucd) { int i; /* Get the current contents of the dialog fields */ if (!UpdateManagedList(ucd->managedList, True)) return False; /* Test compile the macro */ if (ucd->dialogType == MACRO_CMDS) if (!checkMacro(ucd)) return False; /* Update the menu information */ if (ucd->dialogType == SHELL_CMDS) { for (i=0; inMenuItems; i++) ShellMenuItems[i] = copyMenuItemRec(ucd->menuItemsList[i]); NShellMenuItems = ucd->nMenuItems; parseMenuItemList(ShellMenuItems, NShellMenuItems, ShellMenuInfo, &ShellSubMenus); } else if (ucd->dialogType == MACRO_CMDS) { for (i=0; inMenuItems; i++) MacroMenuItems[i] = copyMenuItemRec(ucd->menuItemsList[i]); NMacroMenuItems = ucd->nMenuItems; parseMenuItemList(MacroMenuItems, NMacroMenuItems, MacroMenuInfo, &MacroSubMenus); } else { /* BG_MENU_CMDS */ for (i=0; inMenuItems; i++) BGMenuItems[i] = copyMenuItemRec(ucd->menuItemsList[i]); NBGMenuItems = ucd->nMenuItems; parseMenuItemList(BGMenuItems, NBGMenuItems, BGMenuInfo, &BGSubMenus); } /* Update the menus themselves in all of the NEdit windows */ rebuildMenuOfAllWindows(ucd->dialogType); /* Note that preferences have been changed */ MarkPrefsChanged(); return True; } static void pasteReplayCB(Widget w, XtPointer clientData, XtPointer callData) { userCmdDialog *ucd = (userCmdDialog *)clientData; if (GetReplayMacro() == NULL) return; XmTextInsert(ucd->cmdTextW, XmTextGetInsertionPosition(ucd->cmdTextW), GetReplayMacro()); } static void destroyCB(Widget w, XtPointer clientData, XtPointer callData) { userCmdDialog *ucd = (userCmdDialog *)clientData; int i; for (i=0; inMenuItems; i++) freeMenuItemRec(ucd->menuItemsList[i]); XtFree((char *)ucd->menuItemsList); XtFree((char *)ucd); } static void accFocusCB(Widget w, XtPointer clientData, XtPointer callData) { userCmdDialog *ucd = (userCmdDialog *)clientData; RemoveDialogMnemonicHandler(XtParent(ucd->accTextW)); } static void accLoseFocusCB(Widget w, XtPointer clientData, XtPointer callData) { userCmdDialog *ucd = (userCmdDialog *)clientData; AddDialogMnemonicHandler(XtParent(ucd->accTextW), FALSE); } static void accKeyCB(Widget w, XtPointer clientData, XKeyEvent *event) { userCmdDialog *ucd = (userCmdDialog *)clientData; KeySym keysym = XLookupKeysym(event, 0); char outStr[MAX_ACCEL_LEN]; /* Accept only real keys, not modifiers alone */ if (IsModifierKey(keysym)) return; /* Tab key means go to the next field, don't enter */ if (keysym == XK_Tab) return; /* Beep and return if the modifiers are buttons or ones we don't support */ if (event->state & ~(ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)) { XBell(TheDisplay, 0); return; } /* Delete or backspace clears field */ if (keysym == XK_Delete || keysym == XK_BackSpace) { XmTextSetString(ucd->accTextW, ""); return; } /* generate the string to use in the dialog field */ generateAcceleratorString(outStr, event->state, keysym); /* Reject single character accelerators (a very simple way to eliminate un-modified letters and numbers) The goal is give users a clue that they're supposed to type the actual keys, not the name. This scheme is not rigorous and still allows accelerators like Comma. */ if (strlen(outStr) == 1) { XBell(TheDisplay, 0); return; } /* fill in the accelerator field in the dialog */ XmTextSetString(ucd->accTextW, outStr); } static void sameOutCB(Widget w, XtPointer clientData, XtPointer callData) { XtSetSensitive(((userCmdDialog *)clientData)->repInpBtn, XmToggleButtonGetState(w)); } static void shellMenuCB(Widget w, WindowInfo *window, XtPointer callData) { XtArgVal userData; int index; char *params[1]; window = WidgetToWindow(MENU_WIDGET(w)); /* get the index of the shell command and verify that it's in range */ XtVaGetValues(w, XmNuserData, &userData, NULL); index = (int)userData - 10; if (index <0 || index >= NShellMenuItems) return; params[0] = ShellMenuItems[index]->name; XtCallActionProc(window->lastFocus, "shell_menu_command", ((XmAnyCallbackStruct *)callData)->event, params, 1); } static void macroMenuCB(Widget w, WindowInfo *window, XtPointer callData) { XtArgVal userData; int index; char *params[1]; window = WidgetToWindow(MENU_WIDGET(w)); /* Don't allow users to execute a macro command from the menu (or accel) if there's already a macro command executing. NEdit can't handle running multiple, independent uncoordinated, macros in the same window. Macros may invoke macro menu commands recursively via the macro_menu_command action proc, which is important for being able to repeat any operation, and to embed macros within eachother at any level, however, a call here with a macro running means that THE USER is explicitly invoking another macro via the menu or an accelerator. */ if (window->macroCmdData != NULL) { XBell(TheDisplay, 0); return; } /* get the index of the macro command and verify that it's in range */ XtVaGetValues(w, XmNuserData, &userData, NULL); index = (int)userData - 10; if (index <0 || index >= NMacroMenuItems) return; params[0] = MacroMenuItems[index]->name; XtCallActionProc(window->lastFocus, "macro_menu_command", ((XmAnyCallbackStruct *)callData)->event, params, 1); } static void bgMenuCB(Widget w, WindowInfo *window, XtPointer callData) { XtArgVal userData; int index; char *params[1]; /* Same remark as for macro menu commands (see above). */ if (window->macroCmdData != NULL) { XBell(TheDisplay, 0); return; } /* get the index of the macro command and verify that it's in range */ XtVaGetValues(w, XmNuserData, &userData, NULL); index = (int)userData - 10; if (index <0 || index >= NBGMenuItems) return; params[0] = BGMenuItems[index]->name; XtCallActionProc(window->lastFocus, "bg_menu_command", ((XmAnyCallbackStruct *)callData)->event, params, 1); } /* ** Update the name, accelerator, mnemonic, and command fields in the shell ** command or macro dialog to agree with the currently selected item in the ** menu item list. */ static void updateDialogFields(menuItemRec *f, userCmdDialog *ucd) { char mneString[2], accString[MAX_ACCEL_LEN]; /* fill in the name, accelerator, mnemonic, and command fields of the dialog for the newly selected item, or blank them if "New" is selected */ if (f == NULL) { XmTextSetString(ucd->nameTextW, ""); XmTextSetString(ucd->cmdTextW, ""); XmTextSetString(ucd->accTextW, ""); XmTextSetString(ucd->mneTextW, ""); if (ucd->dialogType == SHELL_CMDS) { RadioButtonChangeState(ucd->selInpBtn, True, True); RadioButtonChangeState(ucd->sameOutBtn, True, True); RadioButtonChangeState(ucd->repInpBtn, False, False); XtSetSensitive(ucd->repInpBtn, True); RadioButtonChangeState(ucd->saveFirstBtn, False, False); RadioButtonChangeState(ucd->loadAfterBtn, False, False); } } else { mneString[0] = f->mnemonic; mneString[1] = '\0'; generateAcceleratorString(accString, f->modifiers, f->keysym); XmTextSetString(ucd->nameTextW, f->name); XmTextSetString(ucd->cmdTextW, f->cmd); XmTextSetString(ucd->accTextW, accString); XmTextSetString(ucd->mneTextW, mneString); RadioButtonChangeState(ucd->selInpBtn, f->input==FROM_SELECTION, False); if (ucd->dialogType == SHELL_CMDS) { RadioButtonChangeState(ucd->winInpBtn, f->input == FROM_WINDOW, False); RadioButtonChangeState(ucd->eitherInpBtn, f->input == FROM_EITHER, False); RadioButtonChangeState(ucd->noInpBtn, f->input == FROM_NONE, False); RadioButtonChangeState(ucd->sameOutBtn, f->output==TO_SAME_WINDOW, False); RadioButtonChangeState(ucd->winOutBtn, f->output==TO_NEW_WINDOW, False); RadioButtonChangeState(ucd->dlogOutBtn, f->output==TO_DIALOG, False); RadioButtonChangeState(ucd->repInpBtn, f->repInput, False); XtSetSensitive(ucd->repInpBtn, f->output==TO_SAME_WINDOW); RadioButtonChangeState(ucd->saveFirstBtn, f->saveFirst, False); RadioButtonChangeState(ucd->loadAfterBtn, f->loadAfter, False); } } } /* ** Read the name, accelerator, mnemonic, and command fields from the shell or ** macro commands dialog into a newly allocated menuItemRec. Returns a ** pointer to the new menuItemRec structure as the function value, or NULL on ** failure. */ static menuItemRec *readDialogFields(userCmdDialog *ucd, int silent) { char *nameText, *cmdText, *mneText, *accText; menuItemRec *f; nameText = XmTextGetString(ucd->nameTextW); if (*nameText == '\0') { if (!silent) { DialogF(DF_WARN, ucd->dlogShell, 1, "Menu Entry", "Please specify a name\nfor the menu item", "OK"); XmProcessTraversal(ucd->nameTextW, XmTRAVERSE_CURRENT); } XtFree(nameText); return NULL; } if (strchr(nameText, ':')) { if (!silent) { DialogF(DF_WARN, ucd->dlogShell, 1, "Menu Entry", "Menu item names may not\ncontain colon (:) characters", "OK"); XmProcessTraversal(ucd->nameTextW, XmTRAVERSE_CURRENT); } XtFree(nameText); return NULL; } cmdText = XmTextGetString(ucd->cmdTextW); if (cmdText == NULL || *cmdText == '\0') { if (!silent) { DialogF(DF_WARN, ucd->dlogShell, 1, "Command to Execute", "Please specify %s to execute", "OK", ucd->dialogType == SHELL_CMDS ? "shell command" : "macro command(s)"); XmProcessTraversal(ucd->cmdTextW, XmTRAVERSE_CURRENT); } XtFree(nameText); XtFree(cmdText); return NULL; } if (ucd->dialogType == MACRO_CMDS || ucd->dialogType == BG_MENU_CMDS) { addTerminatingNewline(&cmdText); if (!checkMacroText(cmdText, silent ? NULL : ucd->dlogShell, ucd->cmdTextW)) { XtFree(nameText); XtFree(cmdText); return NULL; } } f = (menuItemRec *)XtMalloc(sizeof(menuItemRec)); f->name = nameText; f->cmd = cmdText; if ((mneText = XmTextGetString(ucd->mneTextW)) != NULL) { f->mnemonic = mneText==NULL ? '\0' : mneText[0]; XtFree(mneText); if (f->mnemonic == ':') /* colons mess up string parsing */ f->mnemonic = '\0'; } if ((accText = XmTextGetString(ucd->accTextW)) != NULL) { parseAcceleratorString(accText, &f->modifiers, &f->keysym); XtFree(accText); } if (ucd->dialogType == SHELL_CMDS) { if (XmToggleButtonGetState(ucd->selInpBtn)) f->input = FROM_SELECTION; else if (XmToggleButtonGetState(ucd->winInpBtn)) f->input = FROM_WINDOW; else if (XmToggleButtonGetState(ucd->eitherInpBtn)) f->input = FROM_EITHER; else f->input = FROM_NONE; if (XmToggleButtonGetState(ucd->winOutBtn)) f->output = TO_NEW_WINDOW; else if (XmToggleButtonGetState(ucd->dlogOutBtn)) f->output = TO_DIALOG; else f->output = TO_SAME_WINDOW; f->repInput = XmToggleButtonGetState(ucd->repInpBtn); f->saveFirst = XmToggleButtonGetState(ucd->saveFirstBtn); f->loadAfter = XmToggleButtonGetState(ucd->loadAfterBtn); } else { f->input = XmToggleButtonGetState(ucd->selInpBtn) ? FROM_SELECTION : FROM_NONE; f->output = TO_SAME_WINDOW; f->repInput = False; f->saveFirst = False; f->loadAfter = False; } return f; } /* ** Copy a menu item record, and its associated memory */ static menuItemRec *copyMenuItemRec(menuItemRec *item) { menuItemRec *newItem; newItem = (menuItemRec *)XtMalloc(sizeof(menuItemRec)); *newItem = *item; newItem->name = XtMalloc(strlen(item->name)+1); strcpy(newItem->name, item->name); newItem->cmd = XtMalloc(strlen(item->cmd)+1); strcpy(newItem->cmd, item->cmd); return newItem; } /* ** Free a menu item record, and its associated memory */ static void freeMenuItemRec(menuItemRec *item) { XtFree(item->name); XtFree(item->cmd); XtFree((char *)item); } /* ** Callbacks for managed-list operations */ static void *getDialogDataCB(void *oldItem, int explicitRequest, int *abort, void *cbArg) { userCmdDialog *ucd = (userCmdDialog *)cbArg; menuItemRec *currentFields; /* If the dialog is currently displaying the "new" entry and the fields are empty, that's just fine */ if (oldItem == NULL && dialogFieldsAreEmpty(ucd)) return NULL; /* If there are no problems reading the data, just return it */ currentFields = readDialogFields(ucd, True); if (currentFields != NULL) return (void *)currentFields; /* If user might not be expecting fields to be read, give more warning */ if (!explicitRequest) { if (DialogF(DF_WARN, ucd->dlogShell, 2, "Discard Entry", "Discard incomplete entry\nfor current menu item?", "Keep", "Discard") == 2) { return oldItem == NULL ? NULL : (void *)copyMenuItemRec((menuItemRec *)oldItem); } } /* Do readDialogFields again without "silent" mode to display warning(s) */ readDialogFields(ucd, False); *abort = True; return NULL; } static void setDialogDataCB(void *item, void *cbArg) { updateDialogFields((menuItemRec *)item, (userCmdDialog *)cbArg); } static int dialogFieldsAreEmpty(userCmdDialog *ucd) { return TextWidgetIsBlank(ucd->nameTextW) && TextWidgetIsBlank(ucd->cmdTextW) && TextWidgetIsBlank(ucd->accTextW) && TextWidgetIsBlank(ucd->mneTextW) && (ucd->dialogType != SHELL_CMDS || ( XmToggleButtonGetState(ucd->selInpBtn) && XmToggleButtonGetState(ucd->sameOutBtn) && !XmToggleButtonGetState(ucd->repInpBtn) && !XmToggleButtonGetState(ucd->saveFirstBtn) && !XmToggleButtonGetState(ucd->loadAfterBtn))); } static void freeItemCB(void *item) { freeMenuItemRec((menuItemRec *)item); } /* ** Gut a text widget of it's ability to process input */ static void disableTextW(Widget textW) { static XtTranslations emptyTable = NULL; static char *emptyTranslations = "\ : enter()\n\ : grab-focus()\n\ : extend-adjust()\n\ : extend-end()\n\ ShiftTab: prev-tab-group()\n\ CtrlTab: next-tab-group()\n\ Tab: next-tab-group()\n\ : leave()\n\ : focusIn()\n\ : focusOut()\n\ : unmap()\n"; /* replace the translation table with the slimmed down one above */ if (emptyTable == NULL) emptyTable = XtParseTranslationTable(emptyTranslations); XtVaSetValues(textW, XmNtranslations, emptyTable, NULL); } static char *writeMenuItemString(menuItemRec **menuItems, int nItems, int listType) { char *outStr, *outPtr, *c, accStr[MAX_ACCEL_LEN]; menuItemRec *f; int i, length; /* determine the max. amount of memory needed for the returned string and allocate a buffer for composing the string */ length = 0; for (i=0; imodifiers, f->keysym); length += strlen(f->name) * 2; /* allow for \n & \\ expansions */ length += strlen(accStr); length += strlen(f->cmd) * 6; /* allow for \n & \\ expansions */ length += 21; /* number of characters added below */ } length++; /* terminating null */ outStr = XtMalloc(length); /* write the string */ outPtr = outStr; *outPtr++ = '\\'; *outPtr++ = '\n'; for (i=0; imodifiers, f->keysym); *outPtr++ = '\t'; for (c=f->name; *c!='\0'; ++c) { /* Copy the command name */ if (*c == '\\') { /* changing backslashes to \\ */ *outPtr++ = '\\'; *outPtr++ = '\\'; } else if (*c == '\n') { /* changing newlines to \n */ *outPtr++ = '\\'; *outPtr++ = 'n'; } else { *outPtr++ = *c; } } *outPtr++ = ':'; strcpy(outPtr, accStr); outPtr += strlen(accStr); *outPtr++ = ':'; if (f->mnemonic != '\0') *outPtr++ = f->mnemonic; *outPtr++ = ':'; if (listType == SHELL_CMDS) { if (f->input == FROM_SELECTION) *outPtr++ = 'I'; else if (f->input == FROM_WINDOW) *outPtr++ = 'A'; else if (f->input == FROM_EITHER) *outPtr++ = 'E'; if (f->output == TO_DIALOG) *outPtr++ = 'D'; else if (f->output == TO_NEW_WINDOW) *outPtr++ = 'W'; if (f->repInput) *outPtr++ = 'X'; if (f->saveFirst) *outPtr++ = 'S'; if (f->loadAfter) *outPtr++ = 'L'; *outPtr++ = ':'; } else { if (f->input == FROM_SELECTION) *outPtr++ = 'R'; *outPtr++ = ':'; *outPtr++ = ' '; *outPtr++ = '{'; } *outPtr++ = '\\'; *outPtr++ = 'n'; *outPtr++ = '\\'; *outPtr++ = '\n'; *outPtr++ = '\t'; *outPtr++ = '\t'; for (c=f->cmd; *c!='\0'; c++) { /* Copy the command string, changing */ if (*c == '\\') { /* backslashes to double backslashes */ *outPtr++ = '\\'; /* and newlines to backslash-n's, */ *outPtr++ = '\\'; /* followed by real newlines and tab */ } else if (*c == '\n') { *outPtr++ = '\\'; *outPtr++ = 'n'; *outPtr++ = '\\'; *outPtr++ = '\n'; *outPtr++ = '\t'; *outPtr++ = '\t'; } else *outPtr++ = *c; } if (listType == MACRO_CMDS || listType == BG_MENU_CMDS) { if (*(outPtr-1) == '\t') outPtr--; *outPtr++ = '}'; } *outPtr++ = '\\'; *outPtr++ = 'n'; *outPtr++ = '\\'; *outPtr++ = '\n'; } --outPtr; *--outPtr = '\0'; return outStr; } static int loadMenuItemString(char *inString, menuItemRec **menuItems, int *nItems, int listType) { menuItemRec *f; char *cmdStr; char *inPtr = inString; char *nameStr, accStr[MAX_ACCEL_LEN], mneChar; KeySym keysym; unsigned int modifiers; int i, input, output, saveFirst, loadAfter, repInput; int nameLen, accLen, mneLen, cmdLen; for (;;) { /* remove leading whitespace */ while (*inPtr == ' ' || *inPtr == '\t') inPtr++; /* end of string in proper place */ if (*inPtr == '\0') { return True; } /* read name field */ nameLen = strcspn(inPtr, ":"); if (nameLen == 0) return parseError("no name field"); nameStr = XtMalloc(nameLen+1); strncpy(nameStr, inPtr, nameLen); nameStr[nameLen] = '\0'; inPtr += nameLen; if (*inPtr == '\0') return parseError("end not expected"); inPtr++; /* read accelerator field */ accLen = strcspn(inPtr, ":"); if (accLen >= MAX_ACCEL_LEN) return parseError("accelerator field too long"); strncpy(accStr, inPtr, accLen); accStr[accLen] = '\0'; inPtr += accLen; if (*inPtr == '\0') return parseError("end not expected"); inPtr++; /* read menemonic field */ mneLen = strcspn(inPtr, ":"); if (mneLen > 1) return parseError("mnemonic field too long"); if (mneLen == 1) mneChar = *inPtr++; else mneChar = '\0'; inPtr++; if (*inPtr == '\0') return parseError("end not expected"); /* read flags field */ input = FROM_NONE; output = TO_SAME_WINDOW; repInput = False; saveFirst = False; loadAfter = False; for (; *inPtr != ':'; inPtr++) { if (listType == SHELL_CMDS) { if (*inPtr == 'I') input = FROM_SELECTION; else if (*inPtr == 'A') input = FROM_WINDOW; else if (*inPtr == 'E') input = FROM_EITHER; else if (*inPtr == 'W') output = TO_NEW_WINDOW; else if (*inPtr == 'D') output = TO_DIALOG; else if (*inPtr == 'X') repInput = True; else if (*inPtr == 'S') saveFirst = True; else if (*inPtr == 'L') loadAfter = True; else return parseError("unreadable flag field"); } else { if (*inPtr == 'R') input = FROM_SELECTION; else return parseError("unreadable flag field"); } } inPtr++; /* read command field */ if (listType == SHELL_CMDS) { if (*inPtr++ != '\n') return parseError("command must begin with newline"); while (*inPtr == ' ' || *inPtr == '\t') /* leading whitespace */ inPtr++; cmdLen = strcspn(inPtr, "\n"); if (cmdLen == 0) return parseError("shell command field is empty"); cmdStr = XtMalloc(cmdLen+1); strncpy(cmdStr, inPtr, cmdLen); cmdStr[cmdLen] = '\0'; inPtr += cmdLen; } else { cmdStr = copyMacroToEnd(&inPtr); if (cmdStr == NULL) return False; } while (*inPtr == ' ' || *inPtr == '\t' || *inPtr == '\n') inPtr++; /* skip trailing whitespace & newline */ /* parse the accelerator field */ if (!parseAcceleratorString(accStr, &modifiers, &keysym)) return parseError("couldn't read accelerator field"); /* create a menu item record */ f = (menuItemRec *)XtMalloc(sizeof(menuItemRec)); f->name = nameStr; f->cmd = cmdStr; f->mnemonic = mneChar; f->modifiers = modifiers; f->input = input; f->output = output; f->repInput = repInput; f->saveFirst = saveFirst; f->loadAfter = loadAfter; f->keysym = keysym; /* add/replace menu record in the list */ for (i=0; i < *nItems; i++) { if (!strcmp(menuItems[i]->name, f->name)) { freeMenuItemRec(menuItems[i]); menuItems[i] = f; break; } } if (i == *nItems) menuItems[(*nItems)++] = f; } } static int parseError(const char *message) { fprintf(stderr, "NEdit: Parse error in user defined menu item, %s\n", message); return False; } /* ** Create a text string representing an accelerator for the dialog, ** the shellCommands or macroCommands resource, and for the menu item. */ static void generateAcceleratorString(char *text, unsigned int modifiers, KeySym keysym) { char *shiftStr = "", *ctrlStr = "", *altStr = ""; char *mod2Str = "", *mod3Str = "", *mod4Str = "", *mod5Str = ""; char keyName[20]; Modifiers numLockMask = GetNumLockModMask(TheDisplay); /* if there's no accelerator, generate an empty string */ if (keysym == NoSymbol) { *text = '\0'; return; } /* Translate the modifiers into strings. Lock and NumLock are always ignored (see util/misc.c), so we don't display them either. */ if (modifiers & ShiftMask) shiftStr = "Shift+"; if (modifiers & ControlMask) ctrlStr = "Ctrl+"; if (modifiers & Mod1Mask) altStr = "Alt+"; if ((modifiers & Mod2Mask) && (Mod2Mask != numLockMask)) mod2Str = "Mod2+"; if ((modifiers & Mod3Mask) && (Mod3Mask != numLockMask)) mod3Str = "Mod3+"; if ((modifiers & Mod4Mask) && (Mod4Mask != numLockMask)) mod4Str = "Mod4+"; if ((modifiers & Mod5Mask) && (Mod5Mask != numLockMask)) mod5Str = "Mod5+"; /* for a consistent look to the accelerator names in the menus, capitalize the first letter of the keysym */ strcpy(keyName, XKeysymToString(keysym)); *keyName = toupper(*keyName); /* concatenate the strings together */ sprintf(text, "%s%s%s%s%s%s%s%s", shiftStr, ctrlStr, altStr, mod2Str, mod3Str, mod4Str, mod5Str, keyName); } /* ** Create a translation table event description string for the menu ** XmNaccelerator resource. */ static void genAccelEventName(char *text, unsigned int modifiers, KeySym keysym) { char *shiftStr = "", *lockStr = "", *ctrlStr = "", *altStr = ""; char *mod2Str = "", *mod3Str = "", *mod4Str = "", *mod5Str = ""; /* if there's no accelerator, generate an empty string */ if (keysym == NoSymbol) { *text = '\0'; return; } /* translate the modifiers into strings */ if (modifiers & ShiftMask) shiftStr = "Shift "; if (modifiers & LockMask) lockStr = "Lock "; if (modifiers & ControlMask) ctrlStr = "Ctrl "; if (modifiers & Mod1Mask) altStr = "Alt "; if (modifiers & Mod2Mask) mod2Str = "Mod2 "; if (modifiers & Mod3Mask) mod3Str = "Mod3 "; if (modifiers & Mod4Mask) mod4Str = "Mod4 "; if (modifiers & Mod5Mask) mod5Str = "Mod5 "; /* put the modifiers together with the key name */ sprintf(text, "%s%s%s%s%s%s%s%s%s", shiftStr, lockStr, ctrlStr, altStr, mod2Str, mod3Str, mod4Str, mod5Str, XKeysymToString(keysym)); } /* ** Read an accelerator name and put it into the form of a modifier mask ** and a KeySym code. Returns false if string can't be read ** ... does not handle whitespace in string (look at scanf) */ static int parseAcceleratorString(const char *string, unsigned int *modifiers, KeySym *keysym) { int i, nFields, inputLength = strlen(string); char fields[10][MAX_ACCEL_LEN]; /* a blank field means no accelerator */ if (inputLength == 0) { *modifiers = 0; *keysym = NoSymbol; return True; } /* limit the string length so no field strings will overflow */ if (inputLength > MAX_ACCEL_LEN) return False; /* divide the input into '+' separated fields */ nFields = sscanf(string, "%[^+]+%[^+]+%[^+]+%[^+]+%[^+]+%[^+]+%[^+]+%[^+]+%[^+]+%[^+]", fields[0], fields[1], fields[2], fields[3], fields[4], fields[5], fields[6], fields[7], fields[8], fields[9]); if (nFields == 0) return False; /* get the key name from the last field and translate it to a keysym. If the name is capitalized, try it lowercase as well, since some of the keysyms are "prettied up" by generateAcceleratorString */ *keysym = XStringToKeysym(fields[nFields-1]); if (*keysym == NoSymbol) { *fields[nFields-1] = tolower(*fields[nFields-1]); *keysym = XStringToKeysym(fields[nFields-1]); if (*keysym == NoSymbol) return False; } /* parse the modifier names from the rest of the fields */ *modifiers = 0; for (i=0; iumcLanguageMode = -2; cache->umcShellMenuCreated = False; cache->umcMacroMenuCreated = False; cache->umcShellMenuList.umlNbrItems = 0; cache->umcShellMenuList.umlItems = NULL; cache->umcMacroMenuList.umlNbrItems = 0; cache->umcMacroMenuList.umlItems = NULL; return cache; } void FreeUserMenuCache(UserMenuCache *cache) { freeUserMenuList(&cache->umcShellMenuList); freeUserMenuList(&cache->umcMacroMenuList); XtFree((char *)cache); } /* ** Cache user menus: ** init. a user background menu cache structure */ void InitUserBGMenuCache(UserBGMenuCache *cache) { cache->ubmcLanguageMode = -2; cache->ubmcMenuCreated = False; cache->ubmcMenuList.umlNbrItems = 0; cache->ubmcMenuList.umlItems = NULL; } void FreeUserBGMenuCache(UserBGMenuCache *cache) { freeUserMenuList(&cache->ubmcMenuList); } /* ** Cache user menus: ** Parse given menu item list and setup a user menu info list for ** management of user menu. */ static void parseMenuItemList(menuItemRec **itemList, int nbrOfItems, userMenuInfo **infoList, userSubMenuCache *subMenus) { int i; userMenuInfo *info; /* Allocate storage for structures to keep track of sub-menus */ allocSubMenuCache(subMenus, nbrOfItems); /* 1st pass: setup user menu info: extract language modes, menu name & default indication; build user menu ID */ for (i=0; iumiIsDefault) { setDefaultIndex(infoList, nbrOfItems, i); } } } /* ** Returns the sub-menu depth (i.e. nesting level) of given ** menu name. */ static int getSubMenuDepth(const char *menuName) { const char *subSep; int depth = 0; /* determine sub-menu depth by counting '>' of given "menuName" */ subSep = menuName; while ((subSep = strchr(subSep, '>')) != NULL ) { depth ++; subSep ++; } return depth; } /* ** Cache user menus: ** Parse a singe menu item. Allocate & setup a user menu info element ** holding extracted info. */ static userMenuInfo *parseMenuItemRec(menuItemRec *item) { userMenuInfo *newInfo; int subMenuDepth; int idSize; /* allocate a new user menu info element */ newInfo = (userMenuInfo *)XtMalloc(sizeof(userMenuInfo)); /* determine sub-menu depth and allocate some memory for hierarchical ID; init. ID with {0,.., 0} */ newInfo->umiName = stripLanguageMode(item->name); subMenuDepth = getSubMenuDepth(newInfo->umiName); idSize = sizeof(int)*(subMenuDepth+1); newInfo->umiId = (int *)XtMalloc(idSize); memset(newInfo->umiId,0,idSize); /* init. remaining parts of user menu info element */ newInfo->umiIdLen = 0; newInfo->umiIsDefault = False; newInfo->umiNbrOfLanguageModes = 0; newInfo->umiLanguageMode = NULL; newInfo->umiDefaultIndex = -1; newInfo->umiToBeManaged = False; /* assign language mode info to new user menu info element */ parseMenuItemName(item->name, newInfo); return newInfo; } /* ** Cache user menus: ** Extract language mode related info out of given menu item name string. ** Store this info in given user menu info structure. */ static void parseMenuItemName(char *menuItemName, userMenuInfo *info) { char *atPtr, *firstAtPtr, *endPtr; char c; int languageMode; int langModes[MAX_LANGUAGE_MODES]; int nbrLM = 0; int size; atPtr = firstAtPtr = strchr(menuItemName, '@'); if (atPtr != NULL) { if (!strcmp(atPtr+1, "*")) { /* only language is "*": this is for all but language specific macros */ info->umiIsDefault = True; return; } /* setup a list of all language modes related to given menu item */ while (atPtr != NULL) { /* extract language mode name after "@" sign */ for(endPtr=atPtr+1; isalnum((unsigned char)*endPtr) || *endPtr=='_' || *endPtr=='-' || *endPtr==' ' || *endPtr=='+' || *endPtr=='$' || *endPtr=='#'; endPtr++); /* lookup corresponding language mode index; if PLAIN is returned then this means, that language mode name after "@" is unknown (i.e. not defined) */ c = *endPtr; *endPtr = '\0'; languageMode = FindLanguageMode(atPtr+1); if (languageMode == PLAIN_LANGUAGE_MODE) { langModes[nbrLM] = UNKNOWN_LANGUAGE_MODE; } else { langModes[nbrLM] = languageMode; } nbrLM ++; *endPtr = c; /* look for next "@" */ atPtr = strchr(endPtr, '@'); } if (nbrLM != 0) { info->umiNbrOfLanguageModes = nbrLM; size = sizeof(int)*nbrLM; info->umiLanguageMode = (int *)XtMalloc(size); memcpy(info->umiLanguageMode, langModes, size); } } } /* ** Cache user menus: ** generates an ID (= array of integers) of given user menu info, which ** allows to find the user menu item within the menu tree later on: 1st ** integer of ID indicates position within main menu; 2nd integer indicates ** position within 1st sub-menu etc. */ static void generateUserMenuId(userMenuInfo *info, userSubMenuCache *subMenus) { int idSize; char *hierName, *subSep; int subMenuDepth = 0; int *menuIdx = &subMenus->usmcNbrOfMainMenuItems; userSubMenuInfo *curSubMenu; /* find sub-menus, stripping off '>' until item name is reached */ subSep = info->umiName; while ((subSep = strchr(subSep, '>')) != NULL) { hierName = copySubstring(info->umiName, subSep - info->umiName); curSubMenu = findSubMenuInfo(subMenus, hierName); if (curSubMenu == NULL) { /* sub-menu info not stored before: new sub-menu; remember its hierarchical position */ info->umiId[subMenuDepth] = *menuIdx; (*menuIdx) ++; /* store sub-menu info in list of subMenus; allocate some memory for hierarchical ID of sub-menu & take over current hierarchical ID of current user menu info */ curSubMenu = &subMenus->usmcInfo[subMenus->usmcNbrOfSubMenus]; subMenus->usmcNbrOfSubMenus ++; curSubMenu->usmiName = hierName; idSize = sizeof(int)*(subMenuDepth+2); curSubMenu->usmiId = (int *)XtMalloc(idSize); memcpy(curSubMenu->usmiId, info->umiId, idSize); curSubMenu->usmiIdLen = subMenuDepth+1; } else { /* sub-menu info already stored before: takeover its hierarchical position */ XtFree(hierName); info->umiId[subMenuDepth] = curSubMenu->usmiId[subMenuDepth]; } subMenuDepth ++; menuIdx = &curSubMenu->usmiId[subMenuDepth]; subSep ++; } /* remember position of menu item within final (sub) menu */ info->umiId[subMenuDepth] = *menuIdx; info->umiIdLen = subMenuDepth + 1; (*menuIdx) ++; } /* ** Cache user menus: ** Find info corresponding to a hierarchical menu name (a>b>c...) */ static userSubMenuInfo *findSubMenuInfo(userSubMenuCache *subMenus, const char *hierName) { int i; for (i=0; iusmcNbrOfSubMenus; i++) if (!strcmp(hierName, subMenus->usmcInfo[i].usmiName)) return &subMenus->usmcInfo[i]; return NULL; } /* ** Cache user menus: ** Returns an allocated copy of menuItemName stripped of language mode ** parts (i.e. parts starting with "@"). */ static char *stripLanguageMode(const char *menuItemName) { char *firstAtPtr; firstAtPtr = strchr(menuItemName, '@'); if (firstAtPtr == NULL) return XtNewString(menuItemName); else return copySubstring(menuItemName, firstAtPtr-menuItemName); } static void setDefaultIndex(userMenuInfo **infoList, int nbrOfItems, int defaultIdx) { char *defaultMenuName = infoList[defaultIdx]->umiName; int i; userMenuInfo *info; /* Scan the list for items with the same name and a language mode specified. If one is found, then set the default index to the index of the current default item. */ for (i=0; iumiIsDefault && strcmp(info->umiName, defaultMenuName)==0) { info->umiDefaultIndex = defaultIdx; } } } /* ** Determine the info list menu items, which need to be managed ** for given language mode. Set / reset "to be managed" indication ** of info list items accordingly. */ static void applyLangModeToUserMenuInfo(userMenuInfo **infoList, int nbrOfItems, int languageMode) { int i; userMenuInfo *info; /* 1st pass: mark all items as "to be managed", which are applicable for all language modes or which are indicated as "default" items */ for (i=0; iumiToBeManaged = (info->umiNbrOfLanguageModes == 0 || info->umiIsDefault); } /* 2nd pass: mark language mode specific items matching given language mode as "to be managed". Reset "to be managed" indications of "default" items, if applicable */ for (i=0; iumiNbrOfLanguageModes != 0) { if (doesLanguageModeMatch(info, languageMode)) { info->umiToBeManaged = True; if (info->umiDefaultIndex != -1) infoList[info->umiDefaultIndex]->umiToBeManaged = False; } } } } /* ** Returns true, if given user menu info is applicable for given language mode */ static int doesLanguageModeMatch(userMenuInfo *info, int languageMode) { int i; for (i=0; iumiNbrOfLanguageModes; i++) { if (info->umiLanguageMode[i] == languageMode) return True; } return False; } static void freeUserMenuInfoList(userMenuInfo **infoList, int nbrOfItems) { int i; for (i=0; iumiName); XtFree((char *)info->umiId); if (info->umiNbrOfLanguageModes != 0) XtFree((char *)info->umiLanguageMode); XtFree((char *)info); } /* ** Cache user menus: ** Allocate & init. storage for structures to manage sub-menus */ static void allocSubMenuCache(userSubMenuCache *subMenus, int nbrOfItems) { int size = sizeof(userSubMenuInfo) * nbrOfItems; subMenus->usmcNbrOfMainMenuItems = 0; subMenus->usmcNbrOfSubMenus = 0; subMenus->usmcInfo = (userSubMenuInfo *)XtMalloc(size); } static void freeSubMenuCache(userSubMenuCache *subMenus) { int i; for (i=0; iusmcNbrOfSubMenus; i++) { XtFree(subMenus->usmcInfo[i].usmiName); XtFree((char *)subMenus->usmcInfo[i].usmiId); } XtFree((char *)subMenus->usmcInfo); } static void allocUserMenuList(UserMenuList *list, int nbrOfItems) { int size = sizeof(UserMenuListElement *) * nbrOfItems; list->umlNbrItems = 0; list->umlItems = (UserMenuListElement **)XtMalloc(size); } static void freeUserMenuList(UserMenuList *list) { int i; for (i=0; iumlNbrItems; i++) freeUserMenuListElement(list->umlItems[i]); list->umlNbrItems = 0; XtFree((char*) list->umlItems); list->umlItems = NULL; } static UserMenuListElement *allocUserMenuListElement(Widget menuItem, char *accKeys) { UserMenuListElement *element; element = (UserMenuListElement *)XtMalloc(sizeof(UserMenuListElement)); element->umleManageMode = UMMM_UNMANAGE; element->umlePrevManageMode = UMMM_UNMANAGE; element->umleAccKeys = accKeys; element->umleAccLockPatchApplied = False; element->umleMenuItem = menuItem; element->umleSubMenuPane = NULL; element->umleSubMenuList = NULL; return element; } static void freeUserMenuListElement(UserMenuListElement *element) { if (element->umleSubMenuList != NULL) freeUserSubMenuList(element->umleSubMenuList); XtFree(element->umleAccKeys); XtFree((char *)element); } static UserMenuList *allocUserSubMenuList(int nbrOfItems) { UserMenuList *list; list = (UserMenuList *)XtMalloc(sizeof(UserMenuList)); allocUserMenuList(list, nbrOfItems); return list; } static void freeUserSubMenuList(UserMenuList *list) { freeUserMenuList(list); XtFree((char *)list); } nedit-5.6.orig/source/userCmds.h0000644000175000017500000000642210177440760015362 0ustar paulpaul/* $Id: userCmds.h,v 1.11 2005/01/31 14:34:24 edg Exp $ */ /******************************************************************************* * * * userCmds.h -- Nirvana Editor user commands header file * * * * Copyright 2004 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_USERCMDS_H_INCLUDED #define NEDIT_USERCMDS_H_INCLUDED #include "nedit.h" void EditShellMenu(WindowInfo *window); void EditMacroMenu(WindowInfo *window); void EditBGMenu(WindowInfo *window); void UpdateUserMenus(WindowInfo *window); char *WriteShellCmdsString(void); char *WriteMacroCmdsString(void); char *WriteBGMenuCmdsString(void); int LoadShellCmdsString(char *inString); int LoadMacroCmdsString(char *inString); int LoadBGMenuCmdsString(char *inString); int DoNamedShellMenuCmd(WindowInfo *window, const char *itemName, int fromMacro); int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName); int DoNamedBGMenuCmd(WindowInfo *window, const char *itemName); void RebuildAllMenus(WindowInfo *window); void SetBGMenuUndoSensitivity(WindowInfo *window, int sensitive); void SetBGMenuRedoSensitivity(WindowInfo *window, int sensitive); void DimSelectionDepUserMenuItems(WindowInfo *window, int sensitive); void DimPasteReplayBtns(int sensitive); UserMenuCache *CreateUserMenuCache(void); void FreeUserMenuCache(UserMenuCache *cache); void InitUserBGMenuCache(UserBGMenuCache *cache); void FreeUserBGMenuCache(UserBGMenuCache *cache); void SetupUserMenuInfo(void); void UpdateUserMenuInfo(void); #endif /* NEDIT_USERCMDS_H_INCLUDED */ nedit-5.6.orig/source/window.c0000644000175000017500000051107410763076170015104 0ustar paulpaulstatic const char CVSID[] = "$Id: window.c,v 1.204 2008/03/03 22:32:24 tringali Exp $"; /******************************************************************************* * * * window.c -- Nirvana Editor window creation/deletion * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * May 10, 1991 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "window.h" #include "textBuf.h" #include "textSel.h" #include "text.h" #include "textDisp.h" #include "textP.h" #include "nedit.h" #include "menu.h" #include "file.h" #include "search.h" #include "undo.h" #include "preferences.h" #include "selection.h" #include "server.h" #include "shell.h" #include "macro.h" #include "highlight.h" #include "smartIndent.h" #include "userCmds.h" #include "nedit.bm" #include "n.bm" #include "windowTitle.h" #include "interpret.h" #include "rangeset.h" #include "../util/clearcase.h" #include "../util/misc.h" #include "../util/fileUtils.h" #include "../util/utils.h" #include "../util/fileUtils.h" #include "../util/DialogF.h" #include "../Xlt/BubbleButtonP.h" #include "../Microline/XmL/Folder.h" #include #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #include "../util/clearcase.h" #endif /*VMS*/ #include #include #include #include #ifdef __unix__ #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef EDITRES #include /* extern void _XEditResCheckMessages(); */ #endif /* EDITRES */ #ifdef HAVE_DEBUG_H #include "../debug.h" #endif /* Initial minimum height of a pane. Just a fallback in case setPaneMinHeight (which may break in a future release) is not available */ #define PANE_MIN_HEIGHT 39 /* Thickness of 3D border around statistics and/or incremental search areas below the main menu bar */ #define STAT_SHADOW_THICKNESS 1 /* bitmap data for the close-tab button */ #define close_width 11 #define close_height 11 static unsigned char close_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x8c, 0x01, 0xdc, 0x01, 0xf8, 0x00, 0x70, 0x00, 0xf8, 0x00, 0xdc, 0x01, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00}; /* bitmap data for the isearch-find button */ #define isrcFind_width 11 #define isrcFind_height 11 static unsigned char isrcFind_bits[] = { 0xe0, 0x01, 0x10, 0x02, 0xc8, 0x04, 0x08, 0x04, 0x08, 0x04, 0x00, 0x04, 0x18, 0x02, 0xdc, 0x01, 0x0e, 0x00, 0x07, 0x00, 0x03, 0x00}; /* bitmap data for the isearch-clear button */ #define isrcClear_width 11 #define isrcClear_height 11 static unsigned char isrcClear_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x84, 0x01, 0xc4, 0x00, 0x64, 0x00, 0xc4, 0x00, 0x84, 0x01, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00}; extern void _XmDismissTearOff(Widget, XtPointer, XtPointer); static void hideTooltip(Widget tab); static Pixmap createBitmapWithDepth(Widget w, char *data, unsigned int width, unsigned int height); static WindowInfo *getNextTabWindow(WindowInfo *window, int direction, int crossWin, int wrap); static Widget addTab(Widget folder, const char *string); static int compareWindowNames(const void *windowA, const void *windowB); static int getTabPosition(Widget tab); static Widget manageToolBars(Widget toolBarsForm); static void hideTearOffs(Widget menuPane); static void CloseDocumentWindow(Widget w, WindowInfo *window, XtPointer callData); static void closeTabCB(Widget w, Widget mainWin, caddr_t callData); static void raiseTabCB(Widget w, XtPointer clientData, XtPointer callData); static Widget createTextArea(Widget parent, WindowInfo *window, int rows, int cols, int emTabDist, char *delimiters, int wrapMargin, int lineNumCols); static void showStats(WindowInfo *window, int state); static void showISearch(WindowInfo *window, int state); static void showStatsForm(WindowInfo *window); static void addToWindowList(WindowInfo *window); static void removeFromWindowList(WindowInfo *window); static void focusCB(Widget w, WindowInfo *window, XtPointer callData); static void modifiedCB(int pos, int nInserted, int nDeleted, int nRestyled, const char *deletedText, void *cbArg); static void movedCB(Widget w, WindowInfo *window, XtPointer callData); static void dragStartCB(Widget w, WindowInfo *window, XtPointer callData); static void dragEndCB(Widget w, WindowInfo *window, dragEndCBStruct *callData); static void closeCB(Widget w, WindowInfo *window, XtPointer callData); static void saveYourselfCB(Widget w, Widget appShell, XtPointer callData); static void setPaneDesiredHeight(Widget w, int height); static void setPaneMinHeight(Widget w, int min); static void addWindowIcon(Widget shell); static void wmSizeUpdateProc(XtPointer clientData, XtIntervalId *id); static void getGeometryString(WindowInfo *window, char *geomString); #ifdef ROWCOLPATCH static void patchRowCol(Widget w); static void patchedRemoveChild(Widget child); #endif static void refreshMenuBar(WindowInfo *window); static void cloneDocument(WindowInfo *window, WindowInfo *orgWin); static void cloneTextPanes(WindowInfo *window, WindowInfo *orgWin); static UndoInfo *cloneUndoItems(UndoInfo *orgList); static Widget containingPane(Widget w); static WindowInfo *inFocusDocument = NULL; /* where we are now */ static WindowInfo *lastFocusDocument = NULL; /* where we came from */ static int DoneWithMoveDocumentDialog; static int updateLineNumDisp(WindowInfo* window); static int updateGutterWidth(WindowInfo* window); static void deleteDocument(WindowInfo *window); static void cancelTimeOut(XtIntervalId *timer); /* From Xt, Shell.c, "BIGSIZE" */ static const Dimension XT_IGNORE_PPOSITION = 32767; /* ** Create a new editor window */ WindowInfo *CreateWindow(const char *name, char *geometry, int iconic) { Widget winShell, mainWin, menuBar, pane, text, stats, statsAreaForm; Widget closeTabBtn, tabForm, form; WindowInfo *window; Pixel bgpix, fgpix; Arg al[20]; int ac; XmString s1; XmFontList statsFontList; WindowInfo *win; char newGeometry[MAX_GEOM_STRING_LEN]; unsigned int rows, cols; int x = 0, y = 0, bitmask, showTabBar, state; static Pixmap isrcFind = 0; static Pixmap isrcClear = 0; static Pixmap closeTabPixmap = 0; /* Allocate some memory for the new window data structure */ window = (WindowInfo *)XtMalloc(sizeof(WindowInfo)); /* initialize window structure */ /* + Schwarzenberg: should a memset(window, 0, sizeof(WindowInfo)); be added here ? */ window->replaceDlog = NULL; window->replaceText = NULL; window->replaceWithText = NULL; window->replaceWordToggle = NULL; window->replaceCaseToggle = NULL; window->replaceRegexToggle = NULL; window->findDlog = NULL; window->findText = NULL; window->findWordToggle = NULL; window->findCaseToggle = NULL; window->findRegexToggle = NULL; window->replaceMultiFileDlog = NULL; window->replaceMultiFilePathBtn = NULL; window->replaceMultiFileList = NULL; window->multiFileReplSelected = FALSE; window->multiFileBusy = FALSE; window->writableWindows = NULL; window->nWritableWindows = 0; window->fileChanged = FALSE; window->fileMode = 0; window->fileUid = 0; window->fileGid = 0; window->filenameSet = FALSE; window->fileFormat = UNIX_FILE_FORMAT; window->lastModTime = 0; window->fileMissing = True; strcpy(window->filename, name); window->undo = NULL; window->redo = NULL; window->nPanes = 0; window->autoSaveCharCount = 0; window->autoSaveOpCount = 0; window->undoOpCount = 0; window->undoMemUsed = 0; CLEAR_ALL_LOCKS(window->lockReasons); window->indentStyle = GetPrefAutoIndent(PLAIN_LANGUAGE_MODE); window->autoSave = GetPrefAutoSave(); window->saveOldVersion = GetPrefSaveOldVersion(); window->wrapMode = GetPrefWrap(PLAIN_LANGUAGE_MODE); window->overstrike = False; window->showMatchingStyle = GetPrefShowMatching(); window->matchSyntaxBased = GetPrefMatchSyntaxBased(); window->showStats = GetPrefStatsLine(); window->showISearchLine = GetPrefISearchLine(); window->showLineNumbers = GetPrefLineNums(); window->highlightSyntax = GetPrefHighlightSyntax(); window->backlightCharTypes = NULL; window->backlightChars = GetPrefBacklightChars(); if (window->backlightChars) { char *cTypes = GetPrefBacklightCharTypes(); if (cTypes && window->backlightChars) { if ((window->backlightCharTypes = XtMalloc(strlen(cTypes) + 1))) strcpy(window->backlightCharTypes, cTypes); } } window->modeMessageDisplayed = FALSE; window->modeMessage = NULL; window->ignoreModify = FALSE; window->windowMenuValid = FALSE; window->flashTimeoutID = 0; window->fileClosedAtom = None; window->wasSelected = FALSE; strcpy(window->fontName, GetPrefFontName()); strcpy(window->italicFontName, GetPrefItalicFontName()); strcpy(window->boldFontName, GetPrefBoldFontName()); strcpy(window->boldItalicFontName, GetPrefBoldItalicFontName()); window->colorDialog = NULL; window->fontList = GetPrefFontList(); window->italicFontStruct = GetPrefItalicFont(); window->boldFontStruct = GetPrefBoldFont(); window->boldItalicFontStruct = GetPrefBoldItalicFont(); window->fontDialog = NULL; window->nMarks = 0; window->markTimeoutID = 0; window->highlightData = NULL; window->shellCmdData = NULL; window->macroCmdData = NULL; window->smartIndentData = NULL; window->languageMode = PLAIN_LANGUAGE_MODE; window->iSearchHistIndex = 0; window->iSearchStartPos = -1; window->replaceLastRegexCase = TRUE; window->replaceLastLiteralCase = FALSE; window->iSearchLastRegexCase = TRUE; window->iSearchLastLiteralCase = FALSE; window->findLastRegexCase = TRUE; window->findLastLiteralCase = FALSE; window->tab = NULL; window->device = 0; window->inode = 0; /* If window geometry was specified, split it apart into a window position component and a window size component. Create a new geometry string containing the position component only. Rows and cols are stripped off because we can't easily calculate the size in pixels from them until the whole window is put together. Note that the preference resource is only for clueless users who decide to specify the standard X geometry application resource, which is pretty useless because width and height are the same as the rows and cols preferences, and specifying a window location will force all the windows to pile on top of one another */ if (geometry == NULL || geometry[0] == '\0') geometry = GetPrefGeometry(); if (geometry == NULL || geometry[0] == '\0') { rows = GetPrefRows(); cols = GetPrefCols(); newGeometry[0] = '\0'; } else { bitmask = XParseGeometry(geometry, &x, &y, &cols, &rows); if (bitmask == 0) fprintf(stderr, "Bad window geometry specified: %s\n", geometry); else { if (!(bitmask & WidthValue)) cols = GetPrefCols(); if (!(bitmask & HeightValue)) rows = GetPrefRows(); } CreateGeometryString(newGeometry, x, y, 0, 0, bitmask & ~(WidthValue | HeightValue)); } /* Create a new toplevel shell to hold the window */ ac = 0; XtSetArg(al[ac], XmNtitle, name); ac++; XtSetArg(al[ac], XmNdeleteResponse, XmDO_NOTHING); ac++; #ifdef SGI_CUSTOM if (strncmp(name, "Untitled", 8) == 0) { XtSetArg(al[ac], XmNiconName, APP_NAME); ac++; } else { XtSetArg(al[ac], XmNiconName, name); ac++; } #else XtSetArg(al[ac], XmNiconName, name); ac++; #endif XtSetArg(al[ac], XmNgeometry, newGeometry[0]=='\0'?NULL:newGeometry); ac++; XtSetArg(al[ac], XmNinitialState, iconic ? IconicState : NormalState); ac++; if (newGeometry[0] == '\0') { /* Workaround to make Xt ignore Motif's bad PPosition size changes. Even though we try to remove the PPosition in RealizeWithoutForcingPosition, it is not sufficient. Motif will recompute the size hints some point later and put PPosition back! If the window is mapped after that time, then the window will again wind up at 0, 0. So, XEmacs does this, and now we do. Alternate approach, relying on ShellP.h: ((WMShellWidget)winShell)->shell.client_specified &= ~_XtShellPPositionOK; */ XtSetArg(al[ac], XtNx, XT_IGNORE_PPOSITION); ac++; XtSetArg(al[ac], XtNy, XT_IGNORE_PPOSITION); ac++; } winShell = CreateWidget(TheAppShell, "textShell", topLevelShellWidgetClass, al, ac); window->shell = winShell; #ifdef EDITRES XtAddEventHandler (winShell, (EventMask)0, True, (XtEventHandler)_XEditResCheckMessages, NULL); #endif /* EDITRES */ #ifndef SGI_CUSTOM addWindowIcon(winShell); #endif /* Create a MainWindow to manage the menubar and text area, set the userData resource to be used by WidgetToWindow to recover the window pointer from the widget id of any of the window's widgets */ XtSetArg(al[ac], XmNuserData, window); ac++; mainWin = XmCreateMainWindow(winShell, "main", al, ac); window->mainWin = mainWin; XtManageChild(mainWin); /* The statsAreaForm holds the stats line and the I-Search line. */ statsAreaForm = XtVaCreateWidget("statsAreaForm", xmFormWidgetClass, mainWin, XmNmarginWidth, STAT_SHADOW_THICKNESS, XmNmarginHeight, STAT_SHADOW_THICKNESS, /* XmNautoUnmanage, False, */ NULL); /* NOTE: due to a bug in openmotif 2.1.30, NEdit used to crash when the i-search bar was active, and the i-search text widget was focussed, and the window's width was resized to nearly zero. In theory, it is possible to avoid this by imposing a minimum width constraint on the nedit windows, but that width would have to be at least 30 characters, which is probably unacceptable. Amazingly, adding a top offset of 1 pixel to the toggle buttons of the i-search bar, while keeping the the top offset of the text widget to 0 seems to avoid avoid the crash. */ window->iSearchForm = XtVaCreateWidget("iSearchForm", xmFormWidgetClass, statsAreaForm, XmNshadowThickness, 0, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, STAT_SHADOW_THICKNESS, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, STAT_SHADOW_THICKNESS, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, STAT_SHADOW_THICKNESS, XmNbottomOffset, STAT_SHADOW_THICKNESS, NULL); if(window->showISearchLine) XtManageChild(window->iSearchForm); /* Disable keyboard traversal of the find, clear and toggle buttons. We were doing this previously by forcing the keyboard focus back to the text widget whenever a toggle changed. That causes an ugly focus flash on screen. It's better just not to go there in the first place. Plus, if the user really wants traversal, it's an X resource so it can be enabled without too much pain and suffering. */ if (isrcFind == 0) { isrcFind = createBitmapWithDepth(window->iSearchForm, (char *)isrcFind_bits, isrcFind_width, isrcFind_height); } window->iSearchFindButton = XtVaCreateManagedWidget("iSearchFindButton", xmPushButtonWidgetClass, window->iSearchForm, XmNlabelString, s1=XmStringCreateSimple("Find"), XmNlabelType, XmPIXMAP, XmNlabelPixmap, isrcFind, XmNtraversalOn, False, XmNmarginHeight, 1, XmNmarginWidth, 1, XmNleftAttachment, XmATTACH_FORM, /* XmNleftOffset, 3, */ XmNleftOffset, 0, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 1, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 1, NULL); XmStringFree(s1); window->iSearchCaseToggle = XtVaCreateManagedWidget("iSearchCaseToggle", xmToggleButtonWidgetClass, window->iSearchForm, XmNlabelString, s1=XmStringCreateSimple("Case"), XmNset, GetPrefSearch() == SEARCH_CASE_SENSE || GetPrefSearch() == SEARCH_REGEX || GetPrefSearch() == SEARCH_CASE_SENSE_WORD, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNtopOffset, 1, /* see openmotif note above */ XmNrightAttachment, XmATTACH_FORM, XmNmarginHeight, 0, XmNtraversalOn, False, NULL); XmStringFree(s1); window->iSearchRegexToggle = XtVaCreateManagedWidget("iSearchREToggle", xmToggleButtonWidgetClass, window->iSearchForm, XmNlabelString, s1=XmStringCreateSimple("RegExp"), XmNset, GetPrefSearch() == SEARCH_REGEX_NOCASE || GetPrefSearch() == SEARCH_REGEX, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNtopOffset, 1, /* see openmotif note above */ XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, window->iSearchCaseToggle, XmNmarginHeight, 0, XmNtraversalOn, False, NULL); XmStringFree(s1); window->iSearchRevToggle = XtVaCreateManagedWidget("iSearchRevToggle", xmToggleButtonWidgetClass, window->iSearchForm, XmNlabelString, s1=XmStringCreateSimple("Rev"), XmNset, False, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNtopOffset, 1, /* see openmotif note above */ XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, window->iSearchRegexToggle, XmNmarginHeight, 0, XmNtraversalOn, False, NULL); XmStringFree(s1); if (isrcClear == 0) { isrcClear = createBitmapWithDepth(window->iSearchForm, (char *)isrcClear_bits, isrcClear_width, isrcClear_height); } window->iSearchClearButton = XtVaCreateManagedWidget("iSearchClearButton", xmPushButtonWidgetClass, window->iSearchForm, XmNlabelString, s1=XmStringCreateSimple("iSearchRevToggle, XmNrightOffset, 2, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 1, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 1, NULL); XmStringFree(s1); window->iSearchText = XtVaCreateManagedWidget("iSearchText", xmTextWidgetClass, window->iSearchForm, XmNmarginHeight, 1, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, window->iSearchFindButton, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, window->iSearchClearButton, /* XmNrightOffset, 5, */ XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 0, /* see openmotif note above */ XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 0, NULL); RemapDeleteKey(window->iSearchText); SetISearchTextCallbacks(window); /* create the a form to house the tab bar and close-tab button */ tabForm = XtVaCreateWidget("tabForm", xmFormWidgetClass, statsAreaForm, XmNmarginHeight, 0, XmNmarginWidth, 0, XmNspacing, 0, XmNresizable, False, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNshadowThickness, 0, NULL); /* button to close top document */ if (closeTabPixmap == 0) { closeTabPixmap = createBitmapWithDepth(tabForm, (char *)close_bits, close_width, close_height); } closeTabBtn = XtVaCreateManagedWidget("closeTabBtn", xmPushButtonWidgetClass, tabForm, XmNmarginHeight, 0, XmNmarginWidth, 0, XmNhighlightThickness, 0, XmNlabelType, XmPIXMAP, XmNlabelPixmap, closeTabPixmap, XmNshadowThickness, 1, XmNtraversalOn, False, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 3, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 3, NULL); XtAddCallback(closeTabBtn, XmNactivateCallback, (XtCallbackProc)closeTabCB, mainWin); /* create the tab bar */ window->tabBar = XtVaCreateManagedWidget("tabBar", xmlFolderWidgetClass, tabForm, XmNresizePolicy, XmRESIZE_PACK, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, closeTabBtn, XmNrightOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 0, XmNtopAttachment, XmATTACH_FORM, NULL); window->tabMenuPane = CreateTabContextMenu(window->tabBar, window); AddTabContextMenuAction(window->tabBar); /* create an unmanaged composite widget to get the folder widget to hide the 3D shadow for the manager area. Note: this works only on the patched XmLFolder widget */ form = XtVaCreateWidget("form", xmFormWidgetClass, window->tabBar, XmNheight, 1, XmNresizable, False, NULL); XtAddCallback(window->tabBar, XmNactivateCallback, raiseTabCB, NULL); window->tab = addTab(window->tabBar, name); /* A form to hold the stats line text and line/col widgets */ window->statsLineForm = XtVaCreateWidget("statsLineForm", xmFormWidgetClass, statsAreaForm, XmNshadowThickness, 0, XmNtopAttachment, window->showISearchLine ? XmATTACH_WIDGET : XmATTACH_FORM, XmNtopWidget, window->iSearchForm, XmNrightAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNresizable, False, /* */ NULL); /* A separate display of the line/column number */ window->statsLineColNo = XtVaCreateManagedWidget("statsLineColNo", xmLabelWidgetClass, window->statsLineForm, XmNlabelString, s1=XmStringCreateSimple("L: --- C: ---"), XmNshadowThickness, 0, XmNmarginHeight, 2, XmNtraversalOn, False, XmNtopAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, /* */ NULL); XmStringFree(s1); /* Create file statistics display area. Using a text widget rather than a label solves a layout problem with the main window, which messes up if the label is too long (we would need a resize callback to control the length when the window changed size), and allows users to select file names and line numbers. Colors are copied from parent widget, because many users and some system defaults color text backgrounds differently from other widgets. */ XtVaGetValues(window->statsLineForm, XmNbackground, &bgpix, NULL); XtVaGetValues(window->statsLineForm, XmNforeground, &fgpix, NULL); stats = XtVaCreateManagedWidget("statsLine", xmTextWidgetClass, window->statsLineForm, XmNbackground, bgpix, XmNforeground, fgpix, XmNshadowThickness, 0, XmNhighlightColor, bgpix, XmNhighlightThickness, 0, /* must be zero, for OM (2.1.30) to aligns tatsLineColNo & statsLine */ XmNmarginHeight, 1, /* == statsLineColNo.marginHeight - 1, to align with statsLineColNo */ XmNscrollHorizontal, False, XmNeditMode, XmSINGLE_LINE_EDIT, XmNeditable, False, XmNtraversalOn, False, XmNcursorPositionVisible, False, XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET, /* */ XmNtopWidget, window->statsLineColNo, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, window->statsLineColNo, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, /* */ XmNbottomWidget, window->statsLineColNo, XmNrightOffset, 3, NULL); window->statsLine = stats; /* Give the statsLine the same font as the statsLineColNo */ XtVaGetValues(window->statsLineColNo, XmNfontList, &statsFontList, NULL); XtVaSetValues(window->statsLine, XmNfontList, statsFontList, NULL); /* Manage the statsLineForm */ if(window->showStats) XtManageChild(window->statsLineForm); /* If the fontList was NULL, use the magical default provided by Motif, since it must have worked if we've gotten this far */ if (window->fontList == NULL) XtVaGetValues(stats, XmNfontList, &window->fontList, NULL); /* Create the menu bar */ menuBar = CreateMenuBar(mainWin, window); window->menuBar = menuBar; XtManageChild(menuBar); /* Create paned window to manage split pane behavior */ pane = XtVaCreateManagedWidget("pane", xmPanedWindowWidgetClass, mainWin, XmNseparatorOn, False, XmNspacing, 3, XmNsashIndent, -2, NULL); window->splitPane = pane; XmMainWindowSetAreas(mainWin, menuBar, statsAreaForm, NULL, NULL, pane); /* Store a copy of document/window pointer in text pane to support action procedures. See also WidgetToWindow() for info. */ XtVaSetValues(pane, XmNuserData, window, NULL); /* Patch around Motif's most idiotic "feature", that its menu accelerators recognize Caps Lock and Num Lock as modifiers, and don't trigger if they are engaged */ AccelLockBugPatch(pane, window->menuBar); /* Create the first, and most permanent text area (other panes may be added & removed, but this one will never be removed */ text = createTextArea(pane, window, rows,cols, GetPrefEmTabDist(PLAIN_LANGUAGE_MODE), GetPrefDelimiters(), GetPrefWrapMargin(), window->showLineNumbers?MIN_LINE_NUM_COLS:0); XtManageChild(text); window->textArea = text; window->lastFocus = text; /* Set the initial colors from the globals. */ SetColors(window, GetPrefColorName(TEXT_FG_COLOR ), GetPrefColorName(TEXT_BG_COLOR ), GetPrefColorName(SELECT_FG_COLOR), GetPrefColorName(SELECT_BG_COLOR), GetPrefColorName(HILITE_FG_COLOR), GetPrefColorName(HILITE_BG_COLOR), GetPrefColorName(LINENO_FG_COLOR), GetPrefColorName(CURSOR_FG_COLOR)); /* Create the right button popup menu (note: order is important here, since the translation for popping up this menu was probably already added in createTextArea, but CreateBGMenu requires window->textArea to be set so it can attach the menu to it (because menu shells are finicky about the kinds of widgets they are attached to)) */ window->bgMenuPane = CreateBGMenu(window); /* cache user menus: init. user background menu cache */ InitUserBGMenuCache(&window->userBGMenuCache); /* Create the text buffer rather than using the one created automatically with the text area widget. This is done so the syntax highlighting modify callback can be called to synchronize the style buffer BEFORE the text display's callback is called upon to display a modification */ window->buffer = BufCreate(); BufAddModifyCB(window->buffer, SyntaxHighlightModifyCB, window); /* Attach the buffer to the text widget, and add callbacks for modify */ TextSetBuffer(text, window->buffer); BufAddModifyCB(window->buffer, modifiedCB, window); /* Designate the permanent text area as the owner for selections */ HandleXSelections(text); /* Set the requested hardware tab distance and useTabs in the text buffer */ BufSetTabDistance(window->buffer, GetPrefTabDist(PLAIN_LANGUAGE_MODE)); window->buffer->useTabs = GetPrefInsertTabs(); /* add the window to the global window list, update the Windows menus */ addToWindowList(window); InvalidateWindowMenus(); showTabBar = GetShowTabBar(window); if (showTabBar) XtManageChild(tabForm); manageToolBars(statsAreaForm); if (showTabBar || window->showISearchLine || window->showStats) XtManageChild(statsAreaForm); /* realize all of the widgets in the new window */ RealizeWithoutForcingPosition(winShell); XmProcessTraversal(text, XmTRAVERSE_CURRENT); /* Make close command in window menu gracefully prompt for close */ AddMotifCloseCallback(winShell, (XtCallbackProc)closeCB, window); /* Make window resizing work in nice character heights */ UpdateWMSizeHints(window); /* Set the minimum pane height for the initial text pane */ UpdateMinPaneHeights(window); /* create dialogs shared by all documents in a window */ CreateFindDlog(window->shell, window); CreateReplaceDlog(window->shell, window); CreateReplaceMultiFileDlog(window); /* dim/undim Attach_Tab menu items */ state = NDocuments(window) < NWindows(); for(win=WindowList; win; win=win->next) { if (IsTopDocument(win)) { XtSetSensitive(win->moveDocumentItem, state); XtSetSensitive(win->contextMoveDocumentItem, state); } } return window; } /* ** ButtonPress event handler for tabs. */ static void tabClickEH(Widget w, XtPointer clientData, XEvent *event) { /* hide the tooltip when user clicks with any button. */ if (BubbleButton_Timer(w)) { XtRemoveTimeOut(BubbleButton_Timer(w)); BubbleButton_Timer(w) = (XtIntervalId)NULL; } else { hideTooltip(w); } } /* ** add a tab to the tab bar for the new document. */ static Widget addTab(Widget folder, const char *string) { Widget tooltipLabel, tab; XmString s1; s1 = XmStringCreateSimple((char *)string); tab = XtVaCreateManagedWidget("tab", xrwsBubbleButtonWidgetClass, folder, /* XmNmarginWidth, , */ /* XmNmarginHeight, , */ /* XmNalignment, , */ XmNlabelString, s1, XltNbubbleString, s1, XltNshowBubble, GetPrefToolTips(), XltNautoParkBubble, True, XltNslidingBubble, False, /* XltNdelay, 800,*/ /* XltNbubbleDuration, 8000,*/ NULL); XmStringFree(s1); /* there's things to do as user click on the tab */ XtAddEventHandler(tab, ButtonPressMask, False, (XtEventHandler)tabClickEH, (XtPointer)0); /* BubbleButton simply use reversed video for tooltips, we try to use the 'standard' color */ tooltipLabel = XtNameToWidget(tab, "*BubbleLabel"); XtVaSetValues(tooltipLabel, XmNbackground, AllocateColor(tab, GetPrefTooltipBgColor()), XmNforeground, AllocateColor(tab, NEDIT_DEFAULT_FG), NULL); /* put borders around tooltip. BubbleButton use transientShellWidgetClass as tooltip shell, which came without borders */ XtVaSetValues(XtParent(tooltipLabel), XmNborderWidth, 1, NULL); #ifdef LESSTIF_VERSION /* If we don't do this, no popup when right-click on tabs */ AddTabContextMenuAction(tab); #endif /* LESSTIF_VERSION */ return tab; } /* ** Comparison function for sorting windows by title. ** Windows are sorted by alphabetically by filename and then ** alphabetically by path. */ static int compareWindowNames(const void *windowA, const void *windowB) { int rc; const WindowInfo *a = *((WindowInfo**)windowA); const WindowInfo *b = *((WindowInfo**)windowB); rc = strcmp(a->filename, b->filename); if (rc != 0) return rc; rc = strcmp(a->path, b->path); return rc; } /* ** Sort tabs in the tab bar alphabetically, if demanded so. */ void SortTabBar(WindowInfo *window) { WindowInfo *w; WindowInfo **windows; WidgetList tabList; int i, j, nDoc, tabCount; if (!GetPrefSortTabs()) return; /* need more than one tab to sort */ nDoc = NDocuments(window); if (nDoc < 2) return; /* first sort the documents */ windows = (WindowInfo **)XtMalloc(sizeof(WindowInfo *) * nDoc); for (w=WindowList, i=0; w!=NULL; w=w->next) { if (window->shell == w->shell) windows[i++] = w; } qsort(windows, nDoc, sizeof(WindowInfo *), compareWindowNames); /* assign tabs to documents in sorted order */ XtVaGetValues(window->tabBar, XmNtabWidgetList, &tabList, XmNtabCount, &tabCount, NULL); for (i=0, j=0; icore.being_destroyed) continue; /* set tab as active */ if (IsTopDocument(windows[j])) XmLFolderSetActiveTab(window->tabBar, i, False); windows[j]->tab = tabList[i]; RefreshTabState(windows[j]); j++; } XtFree((char *)windows); } /* ** find which document a tab belongs to */ WindowInfo *TabToWindow(Widget tab) { WindowInfo *win; for (win=WindowList; win; win=win->next) { if (win->tab == tab) return win; } return NULL; } /* ** Close a document, or an editor window */ void CloseWindow(WindowInfo *window) { int keepWindow, state; char name[MAXPATHLEN]; WindowInfo *win, *topBuf = NULL, *nextBuf = NULL; /* Free smart indent macro programs */ EndSmartIndent(window); /* Clean up macro references to the doomed window. If a macro is executing, stop it. If macro is calling this (closing its own window), leave the window alive until the macro completes */ keepWindow = !MacroWindowCloseActions(window); #ifndef VMS /* Kill shell sub-process and free related memory */ AbortShellCommand(window); #endif /*VMS*/ /* Unload the default tips files for this language mode if necessary */ UnloadLanguageModeTipsFile(window); /* If a window is closed while it is on the multi-file replace dialog list of any other window (or even the same one), we must update those lists or we end up with dangling references. Normally, there can be only one of those dialogs at the same time (application modal), but LessTif doesn't even (always) honor application modalness, so there can be more than one dialog. */ RemoveFromMultiReplaceDialog(window); /* Destroy the file closed property for this file */ DeleteFileClosedProperty(window); /* Remove any possibly pending callback which might fire after the widget is gone. */ cancelTimeOut(&window->flashTimeoutID); cancelTimeOut(&window->markTimeoutID); /* if this is the last window, or must be kept alive temporarily because it's running the macro calling us, don't close it, make it Untitled */ if (keepWindow || (WindowList == window && window->next == NULL)) { window->filename[0] = '\0'; UniqueUntitledName(name); CLEAR_ALL_LOCKS(window->lockReasons); window->fileMode = 0; window->fileUid = 0; window->fileGid = 0; strcpy(window->filename, name); strcpy(window->path, ""); window->ignoreModify = TRUE; BufSetAll(window->buffer, ""); window->ignoreModify = FALSE; window->nMarks = 0; window->filenameSet = FALSE; window->fileMissing = TRUE; window->fileChanged = FALSE; window->fileFormat = UNIX_FILE_FORMAT; window->lastModTime = 0; window->device = 0; window->inode = 0; StopHighlighting(window); EndSmartIndent(window); UpdateWindowTitle(window); UpdateWindowReadOnly(window); XtSetSensitive(window->closeItem, FALSE); XtSetSensitive(window->readOnlyItem, TRUE); XmToggleButtonSetState(window->readOnlyItem, FALSE, FALSE); ClearUndoList(window); ClearRedoList(window); XmTextSetString(window->statsLine, ""); /* resets scroll pos of stats line from long file names */ UpdateStatsLine(window); DetermineLanguageMode(window, True); RefreshTabState(window); updateLineNumDisp(window); return; } /* Free syntax highlighting patterns, if any. w/o redisplaying */ FreeHighlightingData(window); /* remove the buffer modification callbacks so the buffer will be deallocated when the last text widget is destroyed */ BufRemoveModifyCB(window->buffer, modifiedCB, window); BufRemoveModifyCB(window->buffer, SyntaxHighlightModifyCB, window); #ifdef ROWCOLPATCH patchRowCol(window->menuBar); #endif /* free the undo and redo lists */ ClearUndoList(window); ClearRedoList(window); /* close the document/window */ if (NDocuments(window) > 1) { if (MacroRunWindow() && MacroRunWindow() != window && MacroRunWindow()->shell == window->shell) { nextBuf = MacroRunWindow(); RaiseDocument(nextBuf); } else if (IsTopDocument(window)) { /* need to find a successor before closing a top document */ nextBuf = getNextTabWindow(window, 1, 0, 0); RaiseDocument(nextBuf); } else { topBuf = GetTopDocument(window->shell); } } /* remove the window from the global window list, update window menus */ removeFromWindowList(window); InvalidateWindowMenus(); CheckCloseDim(); /* Close of window running a macro may have been disabled. */ /* remove the tab of the closing document from tab bar */ XtDestroyWidget(window->tab); /* refresh tab bar after closing a document */ if (nextBuf) { ShowWindowTabBar(nextBuf); updateLineNumDisp(nextBuf); } else if (topBuf) { ShowWindowTabBar(topBuf); updateLineNumDisp(topBuf); } /* dim/undim Detach_Tab menu items */ win = nextBuf? nextBuf : topBuf; if (win) { state = NDocuments(win) > 1; XtSetSensitive(win->detachDocumentItem, state); XtSetSensitive(win->contextDetachDocumentItem, state); } /* dim/undim Attach_Tab menu items */ state = NDocuments(WindowList) < NWindows(); for(win=WindowList; win; win=win->next) { if (IsTopDocument(win)) { XtSetSensitive(win->moveDocumentItem, state); XtSetSensitive(win->contextMoveDocumentItem, state); } } /* free background menu cache for document */ FreeUserBGMenuCache(&window->userBGMenuCache); /* destroy the document's pane, or the window */ if (nextBuf || topBuf) { deleteDocument(window); } else { /* free user menu cache for window */ FreeUserMenuCache(window->userMenuCache); /* remove and deallocate all of the widgets associated with window */ XtFree(window->backlightCharTypes); /* we made a copy earlier on */ CloseAllPopupsFor(window->shell); XtDestroyWidget(window->shell); } /* deallocate the window data structure */ XtFree((char*)window); } /* ** check if tab bar is to be shown on this window */ int GetShowTabBar(WindowInfo *window) { if (!GetPrefTabBar()) return False; else if (NDocuments(window) == 1) return !GetPrefTabBarHideOne(); else return True; } void ShowWindowTabBar(WindowInfo *window) { if (GetPrefTabBar()) { if (GetPrefTabBarHideOne()) ShowTabBar(window, NDocuments(window)>1); else ShowTabBar(window, True); } else ShowTabBar(window, False); } /* ** Check if there is already a window open for a given file */ WindowInfo *FindWindowWithFile(const char *name, const char *path) { WindowInfo* window; /* I don't think this algorithm will work on vms so I am disabling it for now */ #ifndef VMS if (!GetPrefHonorSymlinks()) { char fullname[MAXPATHLEN + 1]; struct stat attribute; strncpy(fullname, path, MAXPATHLEN); strncat(fullname, name, MAXPATHLEN); fullname[MAXPATHLEN] = '\0'; if (0 == stat(fullname, &attribute)) { for (window = WindowList; window != NULL; window = window->next) { if (attribute.st_dev == window->device && attribute.st_ino == window->inode) { return window; } } } /* else: Not an error condition, just a new file. Continue to check whether the filename is already in use for an unsaved document. */ } #endif for (window = WindowList; window != NULL; window = window->next) { if (!strcmp(window->filename, name) && !strcmp(window->path, path)) { return window; } } return NULL; } /* ** Add another independently scrollable pane to the current document, ** splitting the pane which currently has keyboard focus. */ void SplitPane(WindowInfo *window) { short paneHeights[MAX_PANES+1]; int insertPositions[MAX_PANES+1], topLines[MAX_PANES+1]; int horizOffsets[MAX_PANES+1]; int i, focusPane, emTabDist, wrapMargin, lineNumCols, totalHeight=0; char *delimiters; Widget text = NULL; textDisp *textD, *newTextD; /* Don't create new panes if we're already at the limit */ if (window->nPanes >= MAX_PANES) return; /* Record the current heights, scroll positions, and insert positions of the existing panes, keyboard focus */ focusPane = 0; for (i=0; i<=window->nPanes; i++) { text = i==0 ? window->textArea : window->textPanes[i-1]; insertPositions[i] = TextGetCursorPos(text); XtVaGetValues(containingPane(text),XmNheight,&paneHeights[i],NULL); totalHeight += paneHeights[i]; TextGetScroll(text, &topLines[i], &horizOffsets[i]); if (text == window->lastFocus) focusPane = i; } /* Unmanage & remanage the panedWindow so it recalculates pane heights */ XtUnmanageChild(window->splitPane); /* Create a text widget to add to the pane and set its buffer and highlight data to be the same as the other panes in the document */ XtVaGetValues(window->textArea, textNemulateTabs, &emTabDist, textNwordDelimiters, &delimiters, textNwrapMargin, &wrapMargin, textNlineNumCols, &lineNumCols, NULL); text = createTextArea(window->splitPane, window, 1, 1, emTabDist, delimiters, wrapMargin, lineNumCols); TextSetBuffer(text, window->buffer); if (window->highlightData != NULL) AttachHighlightToWidget(text, window); if (window->backlightChars) { XtVaSetValues(text, textNbacklightCharTypes, window->backlightCharTypes, NULL); } XtManageChild(text); window->textPanes[window->nPanes++] = text; /* Fix up the colors */ textD = ((TextWidget)window->textArea)->text.textD; newTextD = ((TextWidget)text)->text.textD; XtVaSetValues(text, XmNforeground, textD->fgPixel, XmNbackground, textD->bgPixel, NULL); TextDSetColors( newTextD, textD->fgPixel, textD->bgPixel, textD->selectFGPixel, textD->selectBGPixel, textD->highlightFGPixel, textD->highlightBGPixel, textD->lineNumFGPixel, textD->cursorFGPixel ); /* Set the minimum pane height in the new pane */ UpdateMinPaneHeights(window); /* adjust the heights, scroll positions, etc., to split the focus pane */ for (i=window->nPanes; i>focusPane; i--) { insertPositions[i] = insertPositions[i-1]; paneHeights[i] = paneHeights[i-1]; topLines[i] = topLines[i-1]; horizOffsets[i] = horizOffsets[i-1]; } paneHeights[focusPane] = paneHeights[focusPane]/2; paneHeights[focusPane+1] = paneHeights[focusPane]; for (i=0; i<=window->nPanes; i++) { text = i==0 ? window->textArea : window->textPanes[i-1]; setPaneDesiredHeight(containingPane(text), paneHeights[i]); } /* Re-manage panedWindow to recalculate pane heights & reset selection */ if (IsTopDocument(window)) XtManageChild(window->splitPane); /* Reset all of the heights, scroll positions, etc. */ for (i=0; i<=window->nPanes; i++) { text = i==0 ? window->textArea : window->textPanes[i-1]; TextSetCursorPos(text, insertPositions[i]); TextSetScroll(text, topLines[i], horizOffsets[i]); setPaneDesiredHeight(containingPane(text), totalHeight/(window->nPanes+1)); } XmProcessTraversal(window->lastFocus, XmTRAVERSE_CURRENT); /* Update the window manager size hints after the sizes of the panes have been set (the widget heights are not yet readable here, but they will be by the time the event loop gets around to running this timer proc) */ XtAppAddTimeOut(XtWidgetToApplicationContext(window->shell), 0, wmSizeUpdateProc, window); } Widget GetPaneByIndex(WindowInfo *window, int paneIndex) { Widget text = NULL; if (paneIndex >= 0 && paneIndex <= window->nPanes) { text = (paneIndex == 0) ? window->textArea : window->textPanes[paneIndex - 1]; } return(text); } int WidgetToPaneIndex(WindowInfo *window, Widget w) { int i; Widget text; int paneIndex = 0; for (i = 0; i <= window->nPanes; ++i) { text = (i == 0) ? window->textArea : window->textPanes[i - 1]; if (text == w) { paneIndex = i; } } return(paneIndex); } /* ** Close the window pane that last had the keyboard focus. (Actually, close ** the bottom pane and make it look like pane which had focus was closed) */ void ClosePane(WindowInfo *window) { short paneHeights[MAX_PANES+1]; int insertPositions[MAX_PANES+1], topLines[MAX_PANES+1]; int horizOffsets[MAX_PANES+1]; int i, focusPane; Widget text; /* Don't delete the last pane */ if (window->nPanes <= 0) return; /* Record the current heights, scroll positions, and insert positions of the existing panes, and the keyboard focus */ focusPane = 0; for (i=0; i<=window->nPanes; i++) { text = i==0 ? window->textArea : window->textPanes[i-1]; insertPositions[i] = TextGetCursorPos(text); XtVaGetValues(containingPane(text), XmNheight, &paneHeights[i], NULL); TextGetScroll(text, &topLines[i], &horizOffsets[i]); if (text == window->lastFocus) focusPane = i; } /* Unmanage & remanage the panedWindow so it recalculates pane heights */ XtUnmanageChild(window->splitPane); /* Destroy last pane, and make sure lastFocus points to an existing pane. Workaround for OM 2.1.30: text widget must be unmanaged for xmPanedWindowWidget to calculate the correct pane heights for the remaining panes, simply detroying it didn't seem enough */ window->nPanes--; XtUnmanageChild(containingPane(window->textPanes[window->nPanes])); XtDestroyWidget(containingPane(window->textPanes[window->nPanes])); if (window->nPanes == 0) window->lastFocus = window->textArea; else if (focusPane > window->nPanes) window->lastFocus = window->textPanes[window->nPanes-1]; /* adjust the heights, scroll positions, etc., to make it look like the pane with the input focus was closed */ for (i=focusPane; i<=window->nPanes; i++) { insertPositions[i] = insertPositions[i+1]; paneHeights[i] = paneHeights[i+1]; topLines[i] = topLines[i+1]; horizOffsets[i] = horizOffsets[i+1]; } /* set the desired heights and re-manage the paned window so it will recalculate pane heights */ for (i=0; i<=window->nPanes; i++) { text = i==0 ? window->textArea : window->textPanes[i-1]; setPaneDesiredHeight(containingPane(text), paneHeights[i]); } if (IsTopDocument(window)) XtManageChild(window->splitPane); /* Reset all of the scroll positions, insert positions, etc. */ for (i=0; i<=window->nPanes; i++) { text = i==0 ? window->textArea : window->textPanes[i-1]; TextSetCursorPos(text, insertPositions[i]); TextSetScroll(text, topLines[i], horizOffsets[i]); } XmProcessTraversal(window->lastFocus, XmTRAVERSE_CURRENT); /* Update the window manager size hints after the sizes of the panes have been set (the widget heights are not yet readable here, but they will be by the time the event loop gets around to running this timer proc) */ XtAppAddTimeOut(XtWidgetToApplicationContext(window->shell), 0, wmSizeUpdateProc, window); } /* ** Turn on and off the display of line numbers */ void ShowLineNumbers(WindowInfo *window, int state) { Widget text; int i, marginWidth; unsigned reqCols = 0; Dimension windowWidth; WindowInfo *win; textDisp *textD = ((TextWidget)window->textArea)->text.textD; if (window->showLineNumbers == state) return; window->showLineNumbers = state; /* Just setting window->showLineNumbers is sufficient to tell updateLineNumDisp() to expand the line number areas and the window size for the number of lines required. To hide the line number display, set the width to zero, and contract the window width. */ if (state) { reqCols = updateLineNumDisp(window); } else { XtVaGetValues(window->shell, XmNwidth, &windowWidth, NULL); XtVaGetValues(window->textArea, textNmarginWidth, &marginWidth, NULL); XtVaSetValues(window->shell, XmNwidth, windowWidth - textD->left + marginWidth, NULL); for (i=0; i<=window->nPanes; i++) { text = i==0 ? window->textArea : window->textPanes[i-1]; XtVaSetValues(text, textNlineNumCols, 0, NULL); } } /* line numbers panel is shell-level, hence other tabbed documents in the window should synch */ for (win=WindowList; win; win=win->next) { if (win->shell != window->shell || win == window) continue; win->showLineNumbers = state; for (i=0; i<=win->nPanes; i++) { text = i==0 ? win->textArea : win->textPanes[i-1]; /* reqCols should really be cast here, but into what? XmRInt? */ XtVaSetValues(text, textNlineNumCols, reqCols, NULL); } } /* Tell WM that the non-expandable part of the window has changed size */ UpdateWMSizeHints(window); } void SetTabDist(WindowInfo *window, int tabDist) { if (window->buffer->tabDist != tabDist) { int saveCursorPositions[MAX_PANES + 1]; int saveVScrollPositions[MAX_PANES + 1]; int saveHScrollPositions[MAX_PANES + 1]; int paneIndex; window->ignoreModify = True; for (paneIndex = 0; paneIndex <= window->nPanes; ++paneIndex) { Widget w = GetPaneByIndex(window, paneIndex); textDisp *textD = ((TextWidget)w)->text.textD; TextGetScroll(w, &saveVScrollPositions[paneIndex], &saveHScrollPositions[paneIndex]); saveCursorPositions[paneIndex] = TextGetCursorPos(w); textD->modifyingTabDist = 1; } BufSetTabDistance(window->buffer, tabDist); for (paneIndex = 0; paneIndex <= window->nPanes; ++paneIndex) { Widget w = GetPaneByIndex(window, paneIndex); textDisp *textD = ((TextWidget)w)->text.textD; textD->modifyingTabDist = 0; TextSetCursorPos(w, saveCursorPositions[paneIndex]); TextSetScroll(w, saveVScrollPositions[paneIndex], saveHScrollPositions[paneIndex]); } window->ignoreModify = False; } } void SetEmTabDist(WindowInfo *window, int emTabDist) { int i; XtVaSetValues(window->textArea, textNemulateTabs, emTabDist, NULL); for (i = 0; i < window->nPanes; ++i) { XtVaSetValues(window->textPanes[i], textNemulateTabs, emTabDist, NULL); } } /* ** Turn on and off the display of the statistics line */ void ShowStatsLine(WindowInfo *window, int state) { WindowInfo *win; Widget text; int i; /* In continuous wrap mode, text widgets must be told to keep track of the top line number in absolute (non-wrapped) lines, because it can be a costly calculation, and is only needed for displaying line numbers, either in the stats line, or along the left margin */ for (i=0; i<=window->nPanes; i++) { text = i==0 ? window->textArea : window->textPanes[i-1]; TextDMaintainAbsLineNum(((TextWidget)text)->text.textD, state); } window->showStats = state; showStats(window, state); /* i-search line is shell-level, hence other tabbed documents in the window should synch */ for (win=WindowList; win; win=win->next) { if (win->shell != window->shell || win == window) continue; win->showStats = state; } } /* ** Displays and undisplays the statistics line (regardless of settings of ** window->showStats or window->modeMessageDisplayed) */ static void showStats(WindowInfo *window, int state) { if (state) { XtManageChild(window->statsLineForm); showStatsForm(window); } else { XtUnmanageChild(window->statsLineForm); showStatsForm(window); } /* Tell WM that the non-expandable part of the window has changed size */ /* Already done in showStatsForm */ /* UpdateWMSizeHints(window); */ } /* */ static void showTabBar(WindowInfo *window, int state) { if (state) { XtManageChild(XtParent(window->tabBar)); showStatsForm(window); } else { XtUnmanageChild(XtParent(window->tabBar)); showStatsForm(window); } } /* */ void ShowTabBar(WindowInfo *window, int state) { if (XtIsManaged(XtParent(window->tabBar)) == state) return; showTabBar(window, state); } /* ** Turn on and off the continuing display of the incremental search line ** (when off, it is popped up and down as needed via TempShowISearch) */ void ShowISearchLine(WindowInfo *window, int state) { WindowInfo *win; if (window->showISearchLine == state) return; window->showISearchLine = state; showISearch(window, state); /* i-search line is shell-level, hence other tabbed documents in the window should synch */ for (win=WindowList; win; win=win->next) { if (win->shell != window->shell || win == window) continue; win->showISearchLine = state; } } /* ** Temporarily show and hide the incremental search line if the line is not ** already up. */ void TempShowISearch(WindowInfo *window, int state) { if (window->showISearchLine) return; if (XtIsManaged(window->iSearchForm) != state) showISearch(window, state); } /* ** Put up or pop-down the incremental search line regardless of settings ** of showISearchLine or TempShowISearch */ static void showISearch(WindowInfo *window, int state) { if (state) { XtManageChild(window->iSearchForm); showStatsForm(window); } else { XtUnmanageChild(window->iSearchForm); showStatsForm(window); } /* Tell WM that the non-expandable part of the window has changed size */ /* This is already done in showStatsForm */ /* UpdateWMSizeHints(window); */ } /* ** Show or hide the extra display area under the main menu bar which ** optionally contains the status line and the incremental search bar */ static void showStatsForm(WindowInfo *window) { Widget statsAreaForm = XtParent(window->statsLineForm); Widget mainW = XtParent(statsAreaForm); /* The very silly use of XmNcommandWindowLocation and XmNshowSeparator below are to kick the main window widget to position and remove the status line when it is managed and unmanaged. At some Motif version level, the showSeparator trick backfires and leaves the separator shown, but fortunately the dynamic behavior is fixed, too so the workaround is no longer necessary, either. (... the version where this occurs may be earlier than 2.1. If the stats line shows double thickness shadows in earlier Motif versions, the #if XmVersion directive should be moved back to that earlier version) */ if (manageToolBars(statsAreaForm)) { XtUnmanageChild(statsAreaForm); /*... will this fix Solaris 7??? */ XtVaSetValues(mainW, XmNcommandWindowLocation, XmCOMMAND_ABOVE_WORKSPACE, NULL); #if XmVersion < 2001 XtVaSetValues(mainW, XmNshowSeparator, True, NULL); #endif XtManageChild(statsAreaForm); XtVaSetValues(mainW, XmNshowSeparator, False, NULL); UpdateStatsLine(window); } else { XtUnmanageChild(statsAreaForm); XtVaSetValues(mainW, XmNcommandWindowLocation, XmCOMMAND_BELOW_WORKSPACE, NULL); } /* Tell WM that the non-expandable part of the window has changed size */ UpdateWMSizeHints(window); } /* ** Display a special message in the stats line (show the stats line if it ** is not currently shown). */ void SetModeMessage(WindowInfo *window, const char *message) { /* this document may be hidden (not on top) or later made hidden, so we save a copy of the mode message, so we can restore the statsline when the document is raised to top again */ window->modeMessageDisplayed = True; XtFree(window->modeMessage); window->modeMessage = XtNewString(message); if (!IsTopDocument(window)) return; XmTextSetString(window->statsLine, (char*)message); /* * Don't invoke the stats line again, if stats line is already displayed. */ if (!window->showStats) showStats(window, True); } /* ** Clear special statistics line message set in SetModeMessage, returns ** the statistics line to its original state as set in window->showStats */ void ClearModeMessage(WindowInfo *window) { if (!window->modeMessageDisplayed) return; window->modeMessageDisplayed = False; XtFree(window->modeMessage); window->modeMessage = NULL; if (!IsTopDocument(window)) return; /* * Remove the stats line only if indicated by it's window state. */ if (!window->showStats) showStats(window, False); UpdateStatsLine(window); } /* ** Count the windows */ int NWindows(void) { WindowInfo *win; int n; for (win=WindowList, n=0; win!=NULL; win=win->next, n++); return n; } /* ** Set autoindent state to one of NO_AUTO_INDENT, AUTO_INDENT, or SMART_INDENT. */ void SetAutoIndent(WindowInfo *window, int state) { int autoIndent = state == AUTO_INDENT, smartIndent = state == SMART_INDENT; int i; if (window->indentStyle == SMART_INDENT && !smartIndent) EndSmartIndent(window); else if (smartIndent && window->indentStyle != SMART_INDENT) BeginSmartIndent(window, True); window->indentStyle = state; XtVaSetValues(window->textArea, textNautoIndent, autoIndent, textNsmartIndent, smartIndent, NULL); for (i=0; inPanes; i++) XtVaSetValues(window->textPanes[i], textNautoIndent, autoIndent, textNsmartIndent, smartIndent, NULL); if (IsTopDocument(window)) { XmToggleButtonSetState(window->smartIndentItem, smartIndent, False); XmToggleButtonSetState(window->autoIndentItem, autoIndent, False); XmToggleButtonSetState(window->autoIndentOffItem, state == NO_AUTO_INDENT, False); } } /* ** Set showMatching state to one of NO_FLASH, FLASH_DELIMIT or FLASH_RANGE. ** Update the menu to reflect the change of state. */ void SetShowMatching(WindowInfo *window, int state) { window->showMatchingStyle = state; if (IsTopDocument(window)) { XmToggleButtonSetState(window->showMatchingOffItem, state == NO_FLASH, False); XmToggleButtonSetState(window->showMatchingDelimitItem, state == FLASH_DELIMIT, False); XmToggleButtonSetState(window->showMatchingRangeItem, state == FLASH_RANGE, False); } } /* ** Update the "New (in X)" menu item to reflect the preferences */ void UpdateNewOppositeMenu(WindowInfo *window, int openInTab) { XmString lbl; if ( openInTab ) XtVaSetValues(window->newOppositeItem, XmNlabelString, lbl=XmStringCreateSimple("New Window"), XmNmnemonic, 'W', NULL); else XtVaSetValues(window->newOppositeItem, XmNlabelString, lbl=XmStringCreateSimple("New Tab"), XmNmnemonic, 'T', NULL); XmStringFree(lbl); } /* ** Set the fonts for "window" from a font name, and updates the display. ** Also updates window->fontList which is used for statistics line. ** ** Note that this leaks memory and server resources. In previous NEdit ** versions, fontLists were carefully tracked and freed, but X and Motif ** have some kind of timing problem when widgets are distroyed, such that ** fonts may not be freed immediately after widget destruction with 100% ** safety. Rather than kludge around this with timerProcs, I have chosen ** to create new fontLists only when the user explicitly changes the font ** (which shouldn't happen much in normal NEdit operation), and skip the ** futile effort of freeing them. */ void SetFonts(WindowInfo *window, const char *fontName, const char *italicName, const char *boldName, const char *boldItalicName) { XFontStruct *font, *oldFont; int i, oldFontWidth, oldFontHeight, fontWidth, fontHeight; int borderWidth, borderHeight, marginWidth, marginHeight; int primaryChanged, highlightChanged = False; Dimension oldWindowWidth, oldWindowHeight, oldTextWidth, oldTextHeight; Dimension textHeight, newWindowWidth, newWindowHeight; textDisp *textD = ((TextWidget)window->textArea)->text.textD; /* Check which fonts have changed */ primaryChanged = strcmp(fontName, window->fontName); if (strcmp(italicName, window->italicFontName)) highlightChanged = True; if (strcmp(boldName, window->boldFontName)) highlightChanged = True; if (strcmp(boldItalicName, window->boldItalicFontName)) highlightChanged = True; if (!primaryChanged && !highlightChanged) return; /* Get information about the current window sizing, to be used to determine the correct window size after the font is changed */ XtVaGetValues(window->shell, XmNwidth, &oldWindowWidth, XmNheight, &oldWindowHeight, NULL); XtVaGetValues(window->textArea, XmNheight, &textHeight, textNmarginHeight, &marginHeight, textNmarginWidth, &marginWidth, textNfont, &oldFont, NULL); oldTextWidth = textD->width + textD->lineNumWidth; oldTextHeight = textHeight - 2*marginHeight; for (i=0; inPanes; i++) { XtVaGetValues(window->textPanes[i], XmNheight, &textHeight, NULL); oldTextHeight += textHeight - 2*marginHeight; } borderWidth = oldWindowWidth - oldTextWidth; borderHeight = oldWindowHeight - oldTextHeight; oldFontWidth = oldFont->max_bounds.width; oldFontHeight = textD->ascent + textD->descent; /* Change the fonts in the window data structure. If the primary font didn't work, use Motif's fallback mechanism by stealing it from the statistics line. Highlight fonts are allowed to be NULL, which is interpreted as "use the primary font" */ if (primaryChanged) { strcpy(window->fontName, fontName); font = XLoadQueryFont(TheDisplay, fontName); if (font == NULL) XtVaGetValues(window->statsLine, XmNfontList, &window->fontList, NULL); else window->fontList = XmFontListCreate(font, XmSTRING_DEFAULT_CHARSET); } if (highlightChanged) { strcpy(window->italicFontName, italicName); window->italicFontStruct = XLoadQueryFont(TheDisplay, italicName); strcpy(window->boldFontName, boldName); window->boldFontStruct = XLoadQueryFont(TheDisplay, boldName); strcpy(window->boldItalicFontName, boldItalicName); window->boldItalicFontStruct = XLoadQueryFont(TheDisplay, boldItalicName); } /* Change the primary font in all the widgets */ if (primaryChanged) { font = GetDefaultFontStruct(window->fontList); XtVaSetValues(window->textArea, textNfont, font, NULL); for (i=0; inPanes; i++) XtVaSetValues(window->textPanes[i], textNfont, font, NULL); } /* Change the highlight fonts, even if they didn't change, because primary font is read through the style table for syntax highlighting */ if (window->highlightData != NULL) UpdateHighlightStyles(window); /* Change the window manager size hints. Note: this has to be done _before_ we set the new sizes. ICCCM2 compliant window managers (such as fvwm2) would otherwise resize the window twice: once because of the new sizes requested, and once because of the new size increments, resulting in an overshoot. */ UpdateWMSizeHints(window); /* Use the information from the old window to re-size the window to a size appropriate for the new font, but only do so if there's only _one_ document in the window, in order to avoid growing-window bug */ if (NDocuments(window) == 1) { fontWidth = GetDefaultFontStruct(window->fontList)->max_bounds.width; fontHeight = textD->ascent + textD->descent; newWindowWidth = (oldTextWidth*fontWidth) / oldFontWidth + borderWidth; newWindowHeight = (oldTextHeight*fontHeight) / oldFontHeight + borderHeight; XtVaSetValues(window->shell, XmNwidth, newWindowWidth, XmNheight, newWindowHeight, NULL); } /* Change the minimum pane height */ UpdateMinPaneHeights(window); } void SetColors(WindowInfo *window, const char *textFg, const char *textBg, const char *selectFg, const char *selectBg, const char *hiliteFg, const char *hiliteBg, const char *lineNoFg, const char *cursorFg) { int i, dummy; Pixel textFgPix = AllocColor( window->textArea, textFg, &dummy, &dummy, &dummy), textBgPix = AllocColor( window->textArea, textBg, &dummy, &dummy, &dummy), selectFgPix = AllocColor( window->textArea, selectFg, &dummy, &dummy, &dummy), selectBgPix = AllocColor( window->textArea, selectBg, &dummy, &dummy, &dummy), hiliteFgPix = AllocColor( window->textArea, hiliteFg, &dummy, &dummy, &dummy), hiliteBgPix = AllocColor( window->textArea, hiliteBg, &dummy, &dummy, &dummy), lineNoFgPix = AllocColor( window->textArea, lineNoFg, &dummy, &dummy, &dummy), cursorFgPix = AllocColor( window->textArea, cursorFg, &dummy, &dummy, &dummy); textDisp *textD; /* Update the main pane */ XtVaSetValues(window->textArea, XmNforeground, textFgPix, XmNbackground, textBgPix, NULL); textD = ((TextWidget)window->textArea)->text.textD; TextDSetColors( textD, textFgPix, textBgPix, selectFgPix, selectBgPix, hiliteFgPix, hiliteBgPix, lineNoFgPix, cursorFgPix ); /* Update any additional panes */ for (i=0; inPanes; i++) { XtVaSetValues(window->textPanes[i], XmNforeground, textFgPix, XmNbackground, textBgPix, NULL); textD = ((TextWidget)window->textPanes[i])->text.textD; TextDSetColors( textD, textFgPix, textBgPix, selectFgPix, selectBgPix, hiliteFgPix, hiliteBgPix, lineNoFgPix, cursorFgPix ); } /* Redo any syntax highlighting */ if (window->highlightData != NULL) UpdateHighlightStyles(window); } /* ** Set insert/overstrike mode */ void SetOverstrike(WindowInfo *window, int overstrike) { int i; XtVaSetValues(window->textArea, textNoverstrike, overstrike, NULL); for (i=0; inPanes; i++) XtVaSetValues(window->textPanes[i], textNoverstrike, overstrike, NULL); window->overstrike = overstrike; } /* ** Select auto-wrap mode, one of NO_WRAP, NEWLINE_WRAP, or CONTINUOUS_WRAP */ void SetAutoWrap(WindowInfo *window, int state) { int i; int autoWrap = state == NEWLINE_WRAP, contWrap = state == CONTINUOUS_WRAP; XtVaSetValues(window->textArea, textNautoWrap, autoWrap, textNcontinuousWrap, contWrap, NULL); for (i=0; inPanes; i++) XtVaSetValues(window->textPanes[i], textNautoWrap, autoWrap, textNcontinuousWrap, contWrap, NULL); window->wrapMode = state; if (IsTopDocument(window)) { XmToggleButtonSetState(window->newlineWrapItem, autoWrap, False); XmToggleButtonSetState(window->continuousWrapItem, contWrap, False); XmToggleButtonSetState(window->noWrapItem, state == NO_WRAP, False); } } /* ** Set the auto-scroll margin */ void SetAutoScroll(WindowInfo *window, int margin) { int i; XtVaSetValues(window->textArea, textNcursorVPadding, margin, NULL); for (i=0; inPanes; i++) XtVaSetValues(window->textPanes[i], textNcursorVPadding, margin, NULL); } /* ** Recover the window pointer from any widget in the window, by searching ** up the widget hierarcy for the top level container widget where the ** window pointer is stored in the userData field. In a tabbed window, ** this is the window pointer of the top (active) document, which is ** returned if w is 'shell-level' widget - menus, find/replace dialogs, etc. ** ** To support action routine in tabbed windows, a copy of the window ** pointer is also store in the splitPane widget. */ WindowInfo *WidgetToWindow(Widget w) { WindowInfo *window = NULL; Widget parent; while (True) { /* return window pointer of document */ if (XtClass(w) == xmPanedWindowWidgetClass) break; if (XtClass(w) == topLevelShellWidgetClass) { WidgetList items; /* there should be only 1 child for the shell - the main window widget */ XtVaGetValues(w, XmNchildren, &items, NULL); w = items[0]; break; } parent = XtParent(w); if (parent == NULL) return NULL; /* make sure it is not a dialog shell */ if (XtClass(parent) == topLevelShellWidgetClass && XmIsMainWindow(w)) break; w = parent; } XtVaGetValues(w, XmNuserData, &window, NULL); return window; } /* ** Change the window appearance and the window data structure to show ** that the file it contains has been modified */ void SetWindowModified(WindowInfo *window, int modified) { if (window->fileChanged == FALSE && modified == TRUE) { SetSensitive(window, window->closeItem, TRUE); window->fileChanged = TRUE; UpdateWindowTitle(window); RefreshTabState(window); } else if (window->fileChanged == TRUE && modified == FALSE) { window->fileChanged = FALSE; UpdateWindowTitle(window); RefreshTabState(window); } } /* ** Update the window title to reflect the filename, read-only, and modified ** status of the window data structure */ void UpdateWindowTitle(const WindowInfo *window) { char *iconTitle, *title; if (!IsTopDocument(window)) return; title = FormatWindowTitle(window->filename, window->path, #ifdef VMS NULL, #else GetClearCaseViewTag(), #endif /* VMS */ GetPrefServerName(), IsServer, window->filenameSet, window->lockReasons, window->fileChanged, GetPrefTitleFormat()); iconTitle = XtMalloc(strlen(window->filename) + 2); /* strlen("*")+1 */ strcpy(iconTitle, window->filename); if (window->fileChanged) strcat(iconTitle, "*"); XtVaSetValues(window->shell, XmNtitle, title, XmNiconName, iconTitle, NULL); /* If there's a find or replace dialog up in "Keep Up" mode, with a file name in the title, update it too */ if (window->findDlog && XmToggleButtonGetState(window->findKeepBtn)) { sprintf(title, "Find (in %s)", window->filename); XtVaSetValues(XtParent(window->findDlog), XmNtitle, title, NULL); } if (window->replaceDlog && XmToggleButtonGetState(window->replaceKeepBtn)) { sprintf(title, "Replace (in %s)", window->filename); XtVaSetValues(XtParent(window->replaceDlog), XmNtitle, title, NULL); } XtFree(iconTitle); /* Update the Windows menus with the new name */ InvalidateWindowMenus(); } /* ** Update the read-only state of the text area(s) in the window, and ** the ReadOnly toggle button in the File menu to agree with the state in ** the window data structure. */ void UpdateWindowReadOnly(WindowInfo *window) { int i, state; if (!IsTopDocument(window)) return; state = IS_ANY_LOCKED(window->lockReasons); XtVaSetValues(window->textArea, textNreadOnly, state, NULL); for (i=0; inPanes; i++) XtVaSetValues(window->textPanes[i], textNreadOnly, state, NULL); XmToggleButtonSetState(window->readOnlyItem, state, FALSE); XtSetSensitive(window->readOnlyItem, !IS_ANY_LOCKED_IGNORING_USER(window->lockReasons)); } /* ** Find the start and end of a single line selection. Hides rectangular ** selection issues for older routines which use selections that won't ** span lines. */ int GetSimpleSelection(textBuffer *buf, int *left, int *right) { int selStart, selEnd, isRect, rectStart, rectEnd, lineStart; /* get the character to match and its position from the selection, or the character before the insert point if nothing is selected. Give up if too many characters are selected */ if (!BufGetSelectionPos(buf, &selStart, &selEnd, &isRect, &rectStart, &rectEnd)) return False; if (isRect) { lineStart = BufStartOfLine(buf, selStart); selStart = BufCountForwardDispChars(buf, lineStart, rectStart); selEnd = BufCountForwardDispChars(buf, lineStart, rectEnd); } *left = selStart; *right = selEnd; return True; } /* ** If the selection (or cursor position if there's no selection) is not ** fully shown, scroll to bring it in to view. Note that as written, ** this won't work well with multi-line selections. Modest re-write ** of the horizontal scrolling part would be quite easy to make it work ** well with rectangular selections. */ void MakeSelectionVisible(WindowInfo *window, Widget textPane) { int left, right, isRect, rectStart, rectEnd, horizOffset; int scrollOffset, leftX, rightX, y, rows, margin; int topLineNum, lastLineNum, rightLineNum, leftLineNum, linesToScroll; textDisp *textD = ((TextWidget)textPane)->text.textD; int topChar = TextFirstVisiblePos(textPane); int lastChar = TextLastVisiblePos(textPane); int targetLineNum; Dimension width; /* find out where the selection is */ if (!BufGetSelectionPos(window->buffer, &left, &right, &isRect, &rectStart, &rectEnd)) { left = right = TextGetCursorPos(textPane); isRect = False; } /* Check vertical positioning unless the selection is already shown or already covers the display. If the end of the selection is below bottom, scroll it in to view until the end selection is scrollOffset lines from the bottom of the display or the start of the selection scrollOffset lines from the top. Calculate a pleasing distance from the top or bottom of the window, to scroll the selection to (if scrolling is necessary), around 1/3 of the height of the window */ if (!((left >= topChar && right <= lastChar) || (left <= topChar && right >= lastChar))) { XtVaGetValues(textPane, textNrows, &rows, NULL); scrollOffset = rows/3; TextGetScroll(textPane, &topLineNum, &horizOffset); if (right > lastChar) { /* End of sel. is below bottom of screen */ leftLineNum = topLineNum + TextDCountLines(textD, topChar, left, False); targetLineNum = topLineNum + scrollOffset; if (leftLineNum >= targetLineNum) { /* Start of sel. is not between top & target */ linesToScroll = TextDCountLines(textD, lastChar, right, False) + scrollOffset; if (leftLineNum - linesToScroll < targetLineNum) linesToScroll = leftLineNum - targetLineNum; /* Scroll start of selection to the target line */ TextSetScroll(textPane, topLineNum+linesToScroll, horizOffset); } } else if (left < topChar) { /* Start of sel. is above top of screen */ lastLineNum = topLineNum + rows; rightLineNum = lastLineNum - TextDCountLines(textD, right, lastChar, False); targetLineNum = lastLineNum - scrollOffset; if (rightLineNum <= targetLineNum) { /* End of sel. is not between bottom & target */ linesToScroll = TextDCountLines(textD, left, topChar, False) + scrollOffset; if (rightLineNum + linesToScroll > targetLineNum) linesToScroll = targetLineNum - rightLineNum; /* Scroll end of selection to the target line */ TextSetScroll(textPane, topLineNum-linesToScroll, horizOffset); } } } /* If either end of the selection off screen horizontally, try to bring it in view, by making sure both end-points are visible. Using only end points of a multi-line selection is not a great idea, and disaster for rectangular selections, so this part of the routine should be re-written if it is to be used much with either. Note also that this is a second scrolling operation, causing the display to jump twice. It's done after vertical scrolling to take advantage of TextPosToXY which requires it's reqested position to be vertically on screen) */ if ( TextPosToXY(textPane, left, &leftX, &y) && TextPosToXY(textPane, right, &rightX, &y) && leftX <= rightX) { TextGetScroll(textPane, &topLineNum, &horizOffset); XtVaGetValues(textPane, XmNwidth, &width, textNmarginWidth, &margin, NULL); if (leftX < margin + textD->lineNumLeft + textD->lineNumWidth) horizOffset -= margin + textD->lineNumLeft + textD->lineNumWidth - leftX; else if (rightX > width - margin) horizOffset += rightX - (width - margin); TextSetScroll(textPane, topLineNum, horizOffset); } /* make sure that the statistics line is up to date */ UpdateStatsLine(window); } static Widget createTextArea(Widget parent, WindowInfo *window, int rows, int cols, int emTabDist, char *delimiters, int wrapMargin, int lineNumCols) { Widget text, sw, hScrollBar, vScrollBar, frame; /* Create a text widget inside of a scrolled window widget */ sw = XtVaCreateManagedWidget("scrolledW", xmScrolledWindowWidgetClass, parent, XmNpaneMaximum, SHRT_MAX, XmNpaneMinimum, PANE_MIN_HEIGHT, XmNhighlightThickness, 0, NULL); hScrollBar = XtVaCreateManagedWidget("textHorScrollBar", xmScrollBarWidgetClass, sw, XmNorientation, XmHORIZONTAL, XmNrepeatDelay, 10, NULL); vScrollBar = XtVaCreateManagedWidget("textVertScrollBar", xmScrollBarWidgetClass, sw, XmNorientation, XmVERTICAL, XmNrepeatDelay, 10, NULL); frame = XtVaCreateManagedWidget("textFrame", xmFrameWidgetClass, sw, XmNshadowType, XmSHADOW_IN, NULL); text = XtVaCreateManagedWidget("text", textWidgetClass, frame, textNbacklightCharTypes, window->backlightCharTypes, textNrows, rows, textNcolumns, cols, textNlineNumCols, lineNumCols, textNemulateTabs, emTabDist, textNfont, GetDefaultFontStruct(window->fontList), textNhScrollBar, hScrollBar, textNvScrollBar, vScrollBar, textNreadOnly, IS_ANY_LOCKED(window->lockReasons), textNwordDelimiters, delimiters, textNwrapMargin, wrapMargin, textNautoIndent, window->indentStyle == AUTO_INDENT, textNsmartIndent, window->indentStyle == SMART_INDENT, textNautoWrap, window->wrapMode == NEWLINE_WRAP, textNcontinuousWrap, window->wrapMode == CONTINUOUS_WRAP, textNoverstrike, window->overstrike, textNhidePointer, (Boolean) GetPrefTypingHidesPointer(), textNcursorVPadding, GetVerticalAutoScroll(), NULL); XtVaSetValues(sw, XmNworkWindow, frame, XmNhorizontalScrollBar, hScrollBar, XmNverticalScrollBar, vScrollBar, NULL); /* add focus, drag, cursor tracking, and smart indent callbacks */ XtAddCallback(text, textNfocusCallback, (XtCallbackProc)focusCB, window); XtAddCallback(text, textNcursorMovementCallback, (XtCallbackProc)movedCB, window); XtAddCallback(text, textNdragStartCallback, (XtCallbackProc)dragStartCB, window); XtAddCallback(text, textNdragEndCallback, (XtCallbackProc)dragEndCB, window); XtAddCallback(text, textNsmartIndentCallback, SmartIndentCB, window); /* This makes sure the text area initially has a the insert point shown ... (check if still true with the nedit text widget, probably not) */ XmAddTabGroup(containingPane(text)); /* compensate for Motif delete/backspace problem */ RemapDeleteKey(text); /* Augment translation table for right button popup menu */ AddBGMenuAction(text); /* If absolute line numbers will be needed for display in the statistics line, tell the widget to maintain them (otherwise, it's a costly operation and performance will be better without it) */ TextDMaintainAbsLineNum(((TextWidget)text)->text.textD, window->showStats); return text; } static void movedCB(Widget w, WindowInfo *window, XtPointer callData) { TextWidget textWidget = (TextWidget) w; if (window->ignoreModify) return; /* update line and column nubers in statistics line */ UpdateStatsLine(window); /* Check the character before the cursor for matchable characters */ FlashMatching(window, w); /* Check for changes to read-only status and/or file modifications */ CheckForChangesToFile(window); /* This callback is not only called for focussed panes, but for newly created panes as well. So make sure that the cursor is left alone for unfocussed panes. TextWidget have no state per se about focus, so we use the related ID for the blink procedure. */ if (0 != textWidget->text.cursorBlinkProcID) { /* Start blinking the caret again. */ ResetCursorBlink(textWidget, False); } } static void modifiedCB(int pos, int nInserted, int nDeleted, int nRestyled, const char *deletedText, void *cbArg) { WindowInfo *window = (WindowInfo *)cbArg; int selected = window->buffer->primary.selected; /* update the table of bookmarks */ if (!window->ignoreModify) { UpdateMarkTable(window, pos, nInserted, nDeleted); } /* Check and dim/undim selection related menu items */ if ((window->wasSelected && !selected) || (!window->wasSelected && selected)) { window->wasSelected = selected; /* do not refresh shell-level items (window, menu-bar etc) when motifying non-top document */ if (IsTopDocument(window)) { XtSetSensitive(window->printSelItem, selected); XtSetSensitive(window->cutItem, selected); XtSetSensitive(window->copyItem, selected); XtSetSensitive(window->delItem, selected); /* Note we don't change the selection for items like "Open Selected" and "Find Selected". That's because it works on selections in external applications. Desensitizing it if there's no NEdit selection disables this feature. */ #ifndef VMS XtSetSensitive(window->filterItem, selected); #endif DimSelectionDepUserMenuItems(window, selected); if (window->replaceDlog != NULL && XtIsManaged(window->replaceDlog)) { UpdateReplaceActionButtons(window); } } } /* When the program needs to make a change to a text area without without recording it for undo or marking file as changed it sets ignoreModify */ if (window->ignoreModify || (nDeleted == 0 && nInserted == 0)) return; /* Make sure line number display is sufficient for new data */ updateLineNumDisp(window); /* Save information for undoing this operation (this call also counts characters and editing operations for triggering autosave */ SaveUndoInformation(window, pos, nInserted, nDeleted, deletedText); /* Trigger automatic backup if operation or character limits reached */ if (window->autoSave && (window->autoSaveCharCount > AUTOSAVE_CHAR_LIMIT || window->autoSaveOpCount > AUTOSAVE_OP_LIMIT)) { WriteBackupFile(window); window->autoSaveCharCount = 0; window->autoSaveOpCount = 0; } /* Indicate that the window has now been modified */ SetWindowModified(window, TRUE); /* Update # of bytes, and line and col statistics */ UpdateStatsLine(window); /* Check if external changes have been made to file and warn user */ CheckForChangesToFile(window); } static void focusCB(Widget w, WindowInfo *window, XtPointer callData) { /* record which window pane last had the keyboard focus */ window->lastFocus = w; /* update line number statistic to reflect current focus pane */ UpdateStatsLine(window); /* finish off the current incremental search */ EndISearch(window); /* Check for changes to read-only status and/or file modifications */ CheckForChangesToFile(window); } static void dragStartCB(Widget w, WindowInfo *window, XtPointer callData) { /* don't record all of the intermediate drag steps for undo */ window->ignoreModify = True; } static void dragEndCB(Widget w, WindowInfo *window, dragEndCBStruct *callData) { /* restore recording of undo information */ window->ignoreModify = False; /* Do nothing if drag operation was canceled */ if (callData->nCharsInserted == 0) return; /* Save information for undoing this operation not saved while undo recording was off */ modifiedCB(callData->startPos, callData->nCharsInserted, callData->nCharsDeleted, 0, callData->deletedText, window); } static void closeCB(Widget w, WindowInfo *window, XtPointer callData) { window = WidgetToWindow(w); if (!WindowCanBeClosed(window)) { return; } CloseDocumentWindow(w, window, callData); } #ifndef NO_SESSION_RESTART static void saveYourselfCB(Widget w, Widget appShell, XtPointer callData) { WindowInfo *win, *topWin, **revWindowList; char geometry[MAX_GEOM_STRING_LEN]; int argc = 0, maxArgc, nWindows, i; char **argv; int wasIconic = False; int n, nItems; WidgetList children; /* Allocate memory for an argument list and for a reversed list of windows. The window list is reversed for IRIX 4DWM and any other window/session manager combination which uses window creation order for re-associating stored geometry information with new windows created by a restored application */ maxArgc = 4; /* nedit -server -svrname name */ nWindows = 0; for (win=WindowList; win!=NULL; win=win->next) { maxArgc += 5; /* -iconic -group -geometry WxH+x+y filename */ nWindows++; } argv = (char **)XtMalloc(maxArgc*sizeof(char *)); revWindowList = (WindowInfo **)XtMalloc(sizeof(WindowInfo *)*nWindows); for (win=WindowList, i=nWindows-1; win!=NULL; win=win->next, i--) revWindowList[i] = win; /* Create command line arguments for restoring each window in the list */ argv[argc++] = XtNewString(ArgV0); if (IsServer) { argv[argc++] = XtNewString("-server"); if (GetPrefServerName()[0] != '\0') { argv[argc++] = XtNewString("-svrname"); argv[argc++] = XtNewString(GetPrefServerName()); } } /* editor windows are popup-shell children of top-level appShell */ XtVaGetValues(appShell, XmNchildren, &children, XmNnumChildren, &nItems, NULL); for (n=nItems-1; n>=0; n--) { WidgetList tabs; int tabCount; if (strcmp(XtName(children[n]), "textShell") || ((topWin = WidgetToWindow(children[n])) == NULL)) continue; /* skip non-editor windows */ /* create a group for each window */ getGeometryString(topWin, geometry); argv[argc++] = XtNewString("-group"); argv[argc++] = XtNewString("-geometry"); argv[argc++] = XtNewString(geometry); if (IsIconic(topWin)) { argv[argc++] = XtNewString("-iconic"); wasIconic = True; } else if (wasIconic) { argv[argc++] = XtNewString("-noiconic"); wasIconic = False; } /* add filename of each tab in window... */ XtVaGetValues(topWin->tabBar, XmNtabWidgetList, &tabs, XmNtabCount, &tabCount, NULL); for (i=0; i< tabCount; i++) { win = TabToWindow(tabs[i]); if (win->filenameSet) { /* add filename */ argv[argc] = XtMalloc(strlen(win->path) + strlen(win->filename) + 1); sprintf(argv[argc++], "%s%s", win->path, win->filename); } } } XtFree((char *)revWindowList); /* Set the window's WM_COMMAND property to the created command line */ XSetCommand(TheDisplay, XtWindow(appShell), argv, argc); for (i=0; ishell), "WM_STATE", False); if (XGetWindowProperty(XtDisplay(window->shell), XtWindow(window->shell), wmStateAtom, 0L, 1L, False, wmStateAtom, &actualType, &actualFormat, &nItems, &leftover, (unsigned char **)&property) != Success || nItems != 1 || property == NULL) return FALSE; result = *property == IconicState; XtFree((char *)property); return result; } /* ** Add a window to the the window list. */ static void addToWindowList(WindowInfo *window) { WindowInfo *temp; temp = WindowList; WindowList = window; window->next = temp; } /* ** Remove a window from the list of windows */ static void removeFromWindowList(WindowInfo *window) { WindowInfo *temp; if (WindowList == window) WindowList = window->next; else { for (temp = WindowList; temp != NULL; temp = temp->next) { if (temp->next == window) { temp->next = window->next; break; } } } } /* ** Set the new gutter width in the window. Sadly, the only way to do this is ** to set it on every single document, so we have to iterate over them. ** ** (Iteration taken from NDocuments(); is there a better way to do it?) */ static int updateGutterWidth(WindowInfo* window) { WindowInfo* document; int reqCols = MIN_LINE_NUM_COLS; int newColsDiff = 0; int maxCols = 0; for (document = WindowList; NULL != document; document = document->next) { if (document->shell == window->shell) { /* We found ourselves a document from this window. */ int lineNumCols, tmpReqCols; textDisp *textD = ((TextWidget) document->textArea)->text.textD; XtVaGetValues(document->textArea, textNlineNumCols, &lineNumCols, NULL); /* Is the width of the line number area sufficient to display all the line numbers in the file? If not, expand line number field, and the window width. */ if (lineNumCols > maxCols) { maxCols = lineNumCols; } tmpReqCols = textD->nBufferLines < 1 ? 1 : (int) log10((double) textD->nBufferLines + 1) + 1; if (tmpReqCols > reqCols) { reqCols = tmpReqCols; } } } if (reqCols != maxCols) { XFontStruct *fs; Dimension windowWidth; short fontWidth; newColsDiff = reqCols - maxCols; XtVaGetValues(window->textArea, textNfont, &fs, NULL); fontWidth = fs->max_bounds.width; XtVaGetValues(window->shell, XmNwidth, &windowWidth, NULL); XtVaSetValues(window->shell, XmNwidth, (Dimension) windowWidth + (newColsDiff * fontWidth), NULL); UpdateWMSizeHints(window); } for (document = WindowList; NULL != document; document = document->next) { if (document->shell == window->shell) { Widget text; int i; int lineNumCols; XtVaGetValues(document->textArea, textNlineNumCols, &lineNumCols, NULL); if (lineNumCols == reqCols) { continue; } /* Update all panes of this document. */ for (i = 0; i <= document->nPanes; i++) { text = 0==i ? document->textArea : document->textPanes[i-1]; XtVaSetValues(text, textNlineNumCols, reqCols, NULL); } } } return reqCols; } /* ** If necessary, enlarges the window and line number display area to make ** room for numbers. */ static int updateLineNumDisp(WindowInfo* window) { if (!window->showLineNumbers) { return 0; } /* Decide how wide the line number field has to be to display all possible line numbers */ return updateGutterWidth(window); } /* ** Update the optional statistics line. */ void UpdateStatsLine(WindowInfo *window) { int line, pos, colNum; char *string, *format, slinecol[32]; Widget statW = window->statsLine; XmString xmslinecol; #ifdef SGI_CUSTOM char *sleft, *smid, *sright; #endif if (!IsTopDocument(window)) return; /* This routine is called for each character typed, so its performance affects overall editor perfomance. Only update if the line is on. */ if (!window->showStats) return; /* Compose the string to display. If line # isn't available, leave it off */ pos = TextGetCursorPos(window->lastFocus); string = XtMalloc(strlen(window->filename) + strlen(window->path) + 45); format = window->fileFormat == DOS_FILE_FORMAT ? " DOS" : (window->fileFormat == MAC_FILE_FORMAT ? " Mac" : ""); if (!TextPosToLineAndCol(window->lastFocus, pos, &line, &colNum)) { sprintf(string, "%s%s%s %d bytes", window->path, window->filename, format, window->buffer->length); sprintf(slinecol, "L: --- C: ---"); } else { sprintf(slinecol, "L: %d C: %d", line, colNum); if (window->showLineNumbers) sprintf(string, "%s%s%s byte %d of %d", window->path, window->filename, format, pos, window->buffer->length); else sprintf(string, "%s%s%s %d bytes", window->path, window->filename, format, window->buffer->length); } /* Update the line/column number */ xmslinecol = XmStringCreateSimple(slinecol); XtVaSetValues( window->statsLineColNo, XmNlabelString, xmslinecol, NULL ); XmStringFree(xmslinecol); /* Don't clobber the line if there's a special message being displayed */ if (!window->modeMessageDisplayed) { /* Change the text in the stats line */ #ifdef SGI_CUSTOM /* don't show full pathname, just dir and filename (+ byte info) */ smid = strchr(string, '/'); if ( smid != NULL ) { sleft = smid; sright = strrchr(string, '/'); while (strcmp(smid, sright)) { sleft = smid; smid = strchr(sleft + 1, '/'); } XmTextReplace(statW, 0, XmTextGetLastPosition(statW), sleft + 1); } else XmTextReplace(statW, 0, XmTextGetLastPosition(statW), string); #else XmTextReplace(statW, 0, XmTextGetLastPosition(statW), string); #endif } XtFree(string); /* Update the line/col display */ xmslinecol = XmStringCreateSimple(slinecol); XtVaSetValues(window->statsLineColNo, XmNlabelString, xmslinecol, NULL); XmStringFree(xmslinecol); } static Boolean currentlyBusy = False; static long busyStartTime = 0; static Boolean modeMessageSet = False; /* * Auxiliary function for measuring elapsed time during busy waits. */ static long getRelTimeInTenthsOfSeconds() { #ifdef __unix__ struct timeval current; gettimeofday(¤t, NULL); return (current.tv_sec*10 + current.tv_usec/100000) & 0xFFFFFFFL; #else time_t current; time(¤t); return (current*10) & 0xFFFFFFFL; #endif } void AllWindowsBusy(const char *message) { WindowInfo *w; if (!currentlyBusy) { busyStartTime = getRelTimeInTenthsOfSeconds(); modeMessageSet = False; for (w=WindowList; w!=NULL; w=w->next) { /* We don't the display message here yet, but defer it for a while. If the wait is short, we don't want to have it flash on and off the screen. However, we can't use a time since in generally we are in a tight loop and only processing exposure events, so it's up to the caller to make sure that this routine is called at regular intervals. */ BeginWait(w->shell); } } else if (!modeMessageSet && message && getRelTimeInTenthsOfSeconds() - busyStartTime > 10) { /* Show the mode message when we've been busy for more than a second */ for (w=WindowList; w!=NULL; w=w->next) { SetModeMessage(w, message); } modeMessageSet = True; } BusyWait(WindowList->shell); currentlyBusy = True; } void AllWindowsUnbusy(void) { WindowInfo *w; for (w=WindowList; w!=NULL; w=w->next) { ClearModeMessage(w); EndWait(w->shell); } currentlyBusy = False; modeMessageSet = False; busyStartTime = 0; } /* ** Paned windows are impossible to adjust after they are created, which makes ** them nearly useless for NEdit (or any application which needs to dynamically ** adjust the panes) unless you tweek some private data to overwrite the ** desired and minimum pane heights which were set at creation time. These ** will probably break in a future release of Motif because of dependence on ** private data. */ static void setPaneDesiredHeight(Widget w, int height) { ((XmPanedWindowConstraintPtr)w->core.constraints)->panedw.dheight = height; } static void setPaneMinHeight(Widget w, int min) { ((XmPanedWindowConstraintPtr)w->core.constraints)->panedw.min = min; } /* ** Update the window manager's size hints. These tell it the increments in ** which it is allowed to resize the window. While this isn't particularly ** important for NEdit (since it can tolerate any window size), setting these ** hints also makes the resize indicator show the window size in characters ** rather than pixels, which is very helpful to users. */ void UpdateWMSizeHints(WindowInfo *window) { Dimension shellWidth, shellHeight, textHeight, hScrollBarHeight; int marginHeight, marginWidth, totalHeight, nCols, nRows; XFontStruct *fs; int i, baseWidth, baseHeight, fontHeight, fontWidth; Widget hScrollBar; textDisp *textD = ((TextWidget)window->textArea)->text.textD; /* Find the dimensions of a single character of the text font */ XtVaGetValues(window->textArea, textNfont, &fs, NULL); fontHeight = textD->ascent + textD->descent; fontWidth = fs->max_bounds.width; /* Find the base (non-expandable) width and height of the editor window. FIXME: To workaround the shrinking-window bug on some WM such as Metacity, which caused the window to shrink as we switch between documents using different font sizes on the documents in the same window, the base width, and similarly the base height, is ajusted such that: shellWidth = baseWidth + cols * textWidth There are two issues with this workaround: 1. the right most characters may appear partially obsure 2. the Col x Row info reported by the WM will be based on the fully display text. */ XtVaGetValues(window->textArea, XmNheight, &textHeight, textNmarginHeight, &marginHeight, textNmarginWidth, &marginWidth, NULL); totalHeight = textHeight - 2*marginHeight; for (i=0; inPanes; i++) { XtVaGetValues(window->textPanes[i], XmNheight, &textHeight, textNhScrollBar, &hScrollBar, NULL); totalHeight += textHeight - 2*marginHeight; if (!XtIsManaged(hScrollBar)) { XtVaGetValues(hScrollBar, XmNheight, &hScrollBarHeight, NULL); totalHeight -= hScrollBarHeight; } } XtVaGetValues(window->shell, XmNwidth, &shellWidth, XmNheight, &shellHeight, NULL); nCols = textD->width / fontWidth; nRows = totalHeight / fontHeight; baseWidth = shellWidth - nCols * fontWidth; baseHeight = shellHeight - nRows * fontHeight; /* Set the size hints in the shell widget */ XtVaSetValues(window->shell, XmNwidthInc, fs->max_bounds.width, XmNheightInc, fontHeight, XmNbaseWidth, baseWidth, XmNbaseHeight, baseHeight, XmNminWidth, baseWidth + fontWidth, XmNminHeight, baseHeight + (1+window->nPanes) * fontHeight, NULL); /* Motif will keep placing this on the shell every time we change it, so it needs to be undone every single time. This only seems to happen on mult-head dispalys on screens 1 and higher. */ RemovePPositionHint(window->shell); } /* ** Update the minimum allowable height for a split pane after a change ** to font or margin height. */ void UpdateMinPaneHeights(WindowInfo *window) { textDisp *textD = ((TextWidget)window->textArea)->text.textD; Dimension hsbHeight, swMarginHeight,frameShadowHeight; int i, marginHeight, minPaneHeight; Widget hScrollBar; /* find the minimum allowable size for a pane */ XtVaGetValues(window->textArea, textNhScrollBar, &hScrollBar, NULL); XtVaGetValues(containingPane(window->textArea), XmNscrolledWindowMarginHeight, &swMarginHeight, NULL); XtVaGetValues(XtParent(window->textArea), XmNshadowThickness, &frameShadowHeight, NULL); XtVaGetValues(window->textArea, textNmarginHeight, &marginHeight, NULL); XtVaGetValues(hScrollBar, XmNheight, &hsbHeight, NULL); minPaneHeight = textD->ascent + textD->descent + marginHeight*2 + swMarginHeight*2 + hsbHeight + 2*frameShadowHeight; /* Set it in all of the widgets in the window */ setPaneMinHeight(containingPane(window->textArea), minPaneHeight); for (i=0; inPanes; i++) setPaneMinHeight(containingPane(window->textPanes[i]), minPaneHeight); } /* Add an icon to an applicaction shell widget. addWindowIcon adds a large ** (primary window) icon, AddSmallIcon adds a small (secondary window) icon. ** ** Note: I would prefer that these were not hardwired, but yhere is something ** weird about the XmNiconPixmap resource that prevents it from being set ** from the defaults in the application resource database. */ static void addWindowIcon(Widget shell) { static Pixmap iconPixmap = 0, maskPixmap = 0; if (iconPixmap == 0) { iconPixmap = XCreateBitmapFromData(TheDisplay, RootWindowOfScreen(XtScreen(shell)), (char *)iconBits, iconBitmapWidth, iconBitmapHeight); maskPixmap = XCreateBitmapFromData(TheDisplay, RootWindowOfScreen(XtScreen(shell)), (char *)maskBits, iconBitmapWidth, iconBitmapHeight); } XtVaSetValues(shell, XmNiconPixmap, iconPixmap, XmNiconMask, maskPixmap, NULL); } void AddSmallIcon(Widget shell) { static Pixmap iconPixmap = 0, maskPixmap = 0; if (iconPixmap == 0) { iconPixmap = XCreateBitmapFromData(TheDisplay, RootWindowOfScreen(XtScreen(shell)), (char *)n_bits, n_width, n_height); maskPixmap = XCreateBitmapFromData(TheDisplay, RootWindowOfScreen(XtScreen(shell)), (char *)n_mask, n_width, n_height); } XtVaSetValues(shell, XmNiconPixmap, iconPixmap, XmNiconMask, maskPixmap, NULL); } /* ** Create pixmap per the widget's color depth setting. ** ** This fixes a BadMatch (X_CopyArea) error due to mismatching of ** color depth between the bitmap (depth of 1) and the screen, ** specifically on when linked to LessTif v1.2 (release 0.93.18 ** & 0.93.94 tested). LessTif v2.x showed no such problem. */ static Pixmap createBitmapWithDepth(Widget w, char *data, unsigned int width, unsigned int height) { Pixmap pixmap; Pixel fg, bg; int depth; XtVaGetValues (w, XmNforeground, &fg, XmNbackground, &bg, XmNdepth, &depth, NULL); pixmap = XCreatePixmapFromBitmapData(XtDisplay(w), RootWindowOfScreen(XtScreen(w)), (char *)data, width, height, fg, bg, depth); return pixmap; } /* ** Save the position and size of a window as an X standard geometry string. ** A string of at least MAX_GEOMETRY_STRING_LEN characters should be ** provided in the argument "geomString" to receive the result. */ static void getGeometryString(WindowInfo *window, char *geomString) { int x, y, fontWidth, fontHeight, baseWidth, baseHeight; unsigned int width, height, dummyW, dummyH, bw, depth, nChild; Window parent, root, *child, w = XtWindow(window->shell); Display *dpy = XtDisplay(window->shell); /* Find the width and height from the window of the shell */ XGetGeometry(dpy, w, &root, &x, &y, &width, &height, &bw, &depth); /* Find the top left corner (x and y) of the window decorations. (This is what's required in the geometry string to restore the window to it's original position, since the window manager re-parents the window to add it's title bar and menus, and moves the requested window down and to the left.) The position is found by traversing the window hier- archy back to the window to the last parent before the root window */ for(;;) { XQueryTree(dpy, w, &root, &parent, &child, &nChild); XFree((char*)child); if (parent == root) break; w = parent; } XGetGeometry(dpy, w, &root, &x, &y, &dummyW, &dummyH, &bw, &depth); /* Use window manager size hints (set by UpdateWMSizeHints) to translate the width and height into characters, as opposed to pixels */ XtVaGetValues(window->shell, XmNwidthInc, &fontWidth, XmNheightInc, &fontHeight, XmNbaseWidth, &baseWidth, XmNbaseHeight, &baseHeight, NULL); width = (width-baseWidth) / fontWidth; height = (height-baseHeight) / fontHeight; /* Write the string */ CreateGeometryString(geomString, x, y, width, height, XValue | YValue | WidthValue | HeightValue); } /* ** Xt timer procedure for updating size hints. The new sizes of objects in ** the window are not ready immediately after adding or removing panes. This ** is a timer routine to be invoked with a timeout of 0 to give the event ** loop a chance to finish processing the size changes before reading them ** out for setting the window manager size hints. */ static void wmSizeUpdateProc(XtPointer clientData, XtIntervalId *id) { UpdateWMSizeHints((WindowInfo *)clientData); } #ifdef ROWCOLPATCH /* ** There is a bad memory reference in the delete_child method of the ** RowColumn widget in some Motif versions (so far, just Solaris with Motif ** 1.2.3) which appears durring the phase 2 destroy of the widget. This ** patch replaces the method with a call to the Composite widget's ** delete_child method. The composite delete_child method handles part, ** but not all of what would have been done by the original method, meaning ** that this is dangerous and should be used sparingly. Note that ** patchRowCol is called only in CloseWindow, before the widget is about to ** be destroyed, and only on systems where the bug has been observed */ static void patchRowCol(Widget w) { ((XmRowColumnClassRec *)XtClass(w))->composite_class.delete_child = patchedRemoveChild; } static void patchedRemoveChild(Widget child) { /* Call composite class method instead of broken row col delete_child method */ (*((CompositeWidgetClass)compositeWidgetClass)->composite_class. delete_child) (child); } #endif /* ROWCOLPATCH */ /* ** Set the backlight character class string */ void SetBacklightChars(WindowInfo *window, char *applyBacklightTypes) { int i; int is_applied = XmToggleButtonGetState(window->backlightCharsItem) ? 1 : 0; int do_apply = applyBacklightTypes ? 1 : 0; window->backlightChars = do_apply; XtFree(window->backlightCharTypes); if (window->backlightChars && (window->backlightCharTypes = XtMalloc(strlen(applyBacklightTypes)+1))) strcpy(window->backlightCharTypes, applyBacklightTypes); else window->backlightCharTypes = NULL; XtVaSetValues(window->textArea, textNbacklightCharTypes, window->backlightCharTypes, NULL); for (i=0; inPanes; i++) XtVaSetValues(window->textPanes[i], textNbacklightCharTypes, window->backlightCharTypes, NULL); if (is_applied != do_apply) SetToggleButtonState(window, window->backlightCharsItem, do_apply, False); } /* ** perform generic management on the children (toolbars) of toolBarsForm, ** a.k.a. statsForm, by setting the form attachment of the managed child ** widgets per their position/order. ** ** You can optionally create separator after a toolbar widget with it's ** widget name set to "TOOLBAR_SEP", which will appear below the toolbar ** widget. These seperators will then be managed automatically by this ** routine along with the toolbars they 'attached' to. ** ** It also takes care of the attachment offset settings of the child ** widgets to keep the border lines of the parent form displayed, so ** you don't have set them before hand. ** ** Note: XtManage/XtUnmange the target child (toolbar) before calling this ** function. ** ** Returns the last toolbar widget managed. ** */ static Widget manageToolBars(Widget toolBarsForm) { Widget topWidget = NULL; WidgetList children; int n, nItems=0; XtVaGetValues(toolBarsForm, XmNchildren, &children, XmNnumChildren, &nItems, NULL); for (n=0; ntextArea)->text.textD; /* width is the same for panes */ XtVaGetValues(window->textArea, textNcolumns, nCols, NULL); /* we have to work out the height, as the text area may have been split */ XtVaGetValues(window->textArea, textNhScrollBar, &hScrollBar, textNmarginHeight, &marginHeight, textNmarginWidth, &marginWidth, NULL); XtVaGetValues(hScrollBar, XmNheight, &hScrollBarHeight, NULL); XtVaGetValues(window->splitPane, XmNheight, &paneHeight, NULL); totalHeight = paneHeight - 2*marginHeight -hScrollBarHeight; fontHeight = textD->ascent + textD->descent; *nRows = totalHeight/fontHeight; } /* ** Create a new document in the shell window. ** Document are created in 'background' so that the user ** menus, ie. the Macro/Shell/BG menus, will not be updated ** unnecessarily; hence speeding up the process of opening ** multiple files. */ WindowInfo* CreateDocument(WindowInfo* shellWindow, const char* name) { Widget pane, text; WindowInfo *window; int nCols, nRows; /* Allocate some memory for the new window data structure */ window = (WindowInfo *)XtMalloc(sizeof(WindowInfo)); /* inherit settings and later reset those required */ memcpy(window, shellWindow, sizeof(WindowInfo)); #if 0 /* share these dialog items with parent shell */ window->replaceDlog = NULL; window->replaceText = NULL; window->replaceWithText = NULL; window->replaceWordToggle = NULL; window->replaceCaseToggle = NULL; window->replaceRegexToggle = NULL; window->findDlog = NULL; window->findText = NULL; window->findWordToggle = NULL; window->findCaseToggle = NULL; window->findRegexToggle = NULL; window->replaceMultiFileDlog = NULL; window->replaceMultiFilePathBtn = NULL; window->replaceMultiFileList = NULL; window->showLineNumbers = GetPrefLineNums(); window->showStats = GetPrefStatsLine(); window->showISearchLine = GetPrefISearchLine(); #endif window->multiFileReplSelected = FALSE; window->multiFileBusy = FALSE; window->writableWindows = NULL; window->nWritableWindows = 0; window->fileChanged = FALSE; window->fileMissing = True; window->fileMode = 0; window->fileUid = 0; window->fileGid = 0; window->filenameSet = FALSE; window->fileFormat = UNIX_FILE_FORMAT; window->lastModTime = 0; strcpy(window->filename, name); window->undo = NULL; window->redo = NULL; window->nPanes = 0; window->autoSaveCharCount = 0; window->autoSaveOpCount = 0; window->undoOpCount = 0; window->undoMemUsed = 0; CLEAR_ALL_LOCKS(window->lockReasons); window->indentStyle = GetPrefAutoIndent(PLAIN_LANGUAGE_MODE); window->autoSave = GetPrefAutoSave(); window->saveOldVersion = GetPrefSaveOldVersion(); window->wrapMode = GetPrefWrap(PLAIN_LANGUAGE_MODE); window->overstrike = False; window->showMatchingStyle = GetPrefShowMatching(); window->matchSyntaxBased = GetPrefMatchSyntaxBased(); window->highlightSyntax = GetPrefHighlightSyntax(); window->backlightCharTypes = NULL; window->backlightChars = GetPrefBacklightChars(); if (window->backlightChars) { char *cTypes = GetPrefBacklightCharTypes(); if (cTypes && window->backlightChars) { if ((window->backlightCharTypes = XtMalloc(strlen(cTypes) + 1))) strcpy(window->backlightCharTypes, cTypes); } } window->modeMessageDisplayed = FALSE; window->modeMessage = NULL; window->ignoreModify = FALSE; window->windowMenuValid = FALSE; window->flashTimeoutID = 0; window->fileClosedAtom = None; window->wasSelected = FALSE; strcpy(window->fontName, GetPrefFontName()); strcpy(window->italicFontName, GetPrefItalicFontName()); strcpy(window->boldFontName, GetPrefBoldFontName()); strcpy(window->boldItalicFontName, GetPrefBoldItalicFontName()); window->colorDialog = NULL; window->fontList = GetPrefFontList(); window->italicFontStruct = GetPrefItalicFont(); window->boldFontStruct = GetPrefBoldFont(); window->boldItalicFontStruct = GetPrefBoldItalicFont(); window->fontDialog = NULL; window->nMarks = 0; window->markTimeoutID = 0; window->highlightData = NULL; window->shellCmdData = NULL; window->macroCmdData = NULL; window->smartIndentData = NULL; window->languageMode = PLAIN_LANGUAGE_MODE; window->iSearchHistIndex = 0; window->iSearchStartPos = -1; window->replaceLastRegexCase = TRUE; window->replaceLastLiteralCase = FALSE; window->iSearchLastRegexCase = TRUE; window->iSearchLastLiteralCase = FALSE; window->findLastRegexCase = TRUE; window->findLastLiteralCase = FALSE; window->tab = NULL; window->bgMenuUndoItem = NULL; window->bgMenuRedoItem = NULL; window->device = 0; window->inode = 0; if (window->fontList == NULL) XtVaGetValues(shellWindow->statsLine, XmNfontList, &window->fontList,NULL); getTextPaneDimension(shellWindow, &nRows, &nCols); /* Create pane that actaully holds the new document. As document is created in 'background', we need to hide it. If we leave it unmanaged without setting it to the XmNworkWindow of the mainWin, due to a unknown bug in Motif where splitpane's scrollWindow child somehow came up with a height taller than the splitpane, the bottom part of the text editing widget is obstructed when later brought up by RaiseDocument(). So we first manage it hidden, then unmanage it and reset XmNworkWindow, then let RaiseDocument() show it later. */ pane = XtVaCreateWidget("pane", xmPanedWindowWidgetClass, window->mainWin, XmNmarginWidth, 0, XmNmarginHeight, 0, XmNseparatorOn, False, XmNspacing, 3, XmNsashIndent, -2, XmNmappedWhenManaged, False, NULL); XtVaSetValues(window->mainWin, XmNworkWindow, pane, NULL); XtManageChild(pane); window->splitPane = pane; /* Store a copy of document/window pointer in text pane to support action procedures. See also WidgetToWindow() for info. */ XtVaSetValues(pane, XmNuserData, window, NULL); /* Patch around Motif's most idiotic "feature", that its menu accelerators recognize Caps Lock and Num Lock as modifiers, and don't trigger if they are engaged */ AccelLockBugPatch(pane, window->menuBar); /* Create the first, and most permanent text area (other panes may be added & removed, but this one will never be removed */ text = createTextArea(pane, window, nRows, nCols, GetPrefEmTabDist(PLAIN_LANGUAGE_MODE), GetPrefDelimiters(), GetPrefWrapMargin(), window->showLineNumbers?MIN_LINE_NUM_COLS:0); XtManageChild(text); window->textArea = text; window->lastFocus = text; /* Set the initial colors from the globals. */ SetColors(window, GetPrefColorName(TEXT_FG_COLOR ), GetPrefColorName(TEXT_BG_COLOR ), GetPrefColorName(SELECT_FG_COLOR), GetPrefColorName(SELECT_BG_COLOR), GetPrefColorName(HILITE_FG_COLOR), GetPrefColorName(HILITE_BG_COLOR), GetPrefColorName(LINENO_FG_COLOR), GetPrefColorName(CURSOR_FG_COLOR)); /* Create the right button popup menu (note: order is important here, since the translation for popping up this menu was probably already added in createTextArea, but CreateBGMenu requires window->textArea to be set so it can attach the menu to it (because menu shells are finicky about the kinds of widgets they are attached to)) */ window->bgMenuPane = CreateBGMenu(window); /* cache user menus: init. user background menu cache */ InitUserBGMenuCache(&window->userBGMenuCache); /* Create the text buffer rather than using the one created automatically with the text area widget. This is done so the syntax highlighting modify callback can be called to synchronize the style buffer BEFORE the text display's callback is called upon to display a modification */ window->buffer = BufCreate(); BufAddModifyCB(window->buffer, SyntaxHighlightModifyCB, window); /* Attach the buffer to the text widget, and add callbacks for modify */ TextSetBuffer(text, window->buffer); BufAddModifyCB(window->buffer, modifiedCB, window); /* Designate the permanent text area as the owner for selections */ HandleXSelections(text); /* Set the requested hardware tab distance and useTabs in the text buffer */ BufSetTabDistance(window->buffer, GetPrefTabDist(PLAIN_LANGUAGE_MODE)); window->buffer->useTabs = GetPrefInsertTabs(); window->tab = addTab(window->tabBar, name); /* add the window to the global window list, update the Windows menus */ InvalidateWindowMenus(); addToWindowList(window); #ifdef LESSTIF_VERSION /* FIXME: Temporary workaround for disappearing-text-window bug when linking to Lesstif. After changes is made to statsAreaForm (parent of statsline, i-search line and tab bar) widget such as enabling/disabling the statsline, the XmForm widget enclosing the text widget somehow refused to resize to fit the text widget. Resizing the shell window or making changes [again] to the statsAreaForm appeared to bring out the text widget, though doesn't fix it for the subsequently added documents. Here we try to do the latter for all new documents created. */ if (XtIsManaged(XtParent(window->statsLineForm))) { XtUnmanageChild(XtParent(window->statsLineForm)); XtManageChild(XtParent(window->statsLineForm)); } #endif /* LESSTIF_VERSION */ /* return the shell ownership to previous tabbed doc */ XtVaSetValues(window->mainWin, XmNworkWindow, shellWindow->splitPane, NULL); XLowerWindow(TheDisplay, XtWindow(window->splitPane)); XtUnmanageChild(window->splitPane); XtVaSetValues(window->splitPane, XmNmappedWhenManaged, True, NULL); return window; } /* ** return the next/previous docment on the tab list. ** ** If is true then the next tab of the rightmost tab will be the ** second tab from the right, and the the previous tab of the leftmost ** tab will be the second from the left. This is useful for getting ** the next tab after a tab detaches/closes and you don't want to wrap around. */ static WindowInfo *getNextTabWindow(WindowInfo *window, int direction, int crossWin, int wrap) { WidgetList tabList, tabs; WindowInfo *win; int tabCount, tabTotalCount; int tabPos, nextPos; int i, n; int nBuf = crossWin? NWindows() : NDocuments(window); if (nBuf <= 1) return NULL; /* get the list of tabs */ tabs = (WidgetList)XtMalloc(sizeof(Widget) * nBuf); tabTotalCount = 0; if (crossWin) { int n, nItems; WidgetList children; XtVaGetValues(TheAppShell, XmNchildren, &children, XmNnumChildren, &nItems, NULL); /* get list of tabs in all windows */ for (n=0; ntabBar, XmNtabWidgetList, &tabList, XmNtabCount, &tabCount, NULL); for (i=0; i< tabCount; i++) { tabs[tabTotalCount++] = tabList[i]; } } } else { /* get list of tabs in this window */ XtVaGetValues(window->tabBar, XmNtabWidgetList, &tabList, XmNtabCount, &tabCount, NULL); for (i=0; i< tabCount; i++) { if (TabToWindow(tabList[i])) /* make sure tab is valid */ tabs[tabTotalCount++] = tabList[i]; } } /* find the position of the tab in the tablist */ tabPos = 0; for (n=0; ntab) { tabPos = n; break; } } /* calculate index position of next tab */ nextPos = tabPos + direction; if (nextPos >= nBuf) { if (wrap) nextPos = 0; else nextPos = nBuf - 2; } else if (nextPos < 0) { if (wrap) nextPos = nBuf - 1; else nextPos = 1; } /* return the document where the next tab belongs to */ win = TabToWindow(tabs[nextPos]); XtFree((char *)tabs); return win; } /* ** return the integer position of a tab in the tabbar it ** belongs to, or -1 if there's an error, somehow. */ static int getTabPosition(Widget tab) { WidgetList tabList; int i, tabCount; Widget tabBar = XtParent(tab); XtVaGetValues(tabBar, XmNtabWidgetList, &tabList, XmNtabCount, &tabCount, NULL); for (i=0; i< tabCount; i++) { if (tab == tabList[i]) return i; } return -1; /* something is wrong! */ } /* ** update the tab label, etc. of a tab, per the states of it's document. */ void RefreshTabState(WindowInfo *win) { XmString s1, tipString; char labelString[MAXPATHLEN]; char *tag = XmFONTLIST_DEFAULT_TAG; unsigned char alignment; /* Set tab label to document's filename. Position of "*" (modified) will change per label alignment setting */ XtVaGetValues(win->tab, XmNalignment, &alignment, NULL); if (alignment != XmALIGNMENT_END) { sprintf(labelString, "%s%s", win->fileChanged? "*" : "", win->filename); } else { sprintf(labelString, "%s%s", win->filename, win->fileChanged? "*" : ""); } /* Make the top document stand out a little more */ if (IsTopDocument(win)) tag = "BOLD"; s1 = XmStringCreateLtoR(labelString, tag); if (GetPrefShowPathInWindowsMenu() && win->filenameSet) { strcat(labelString, " - "); strcat(labelString, win->path); } tipString=XmStringCreateSimple(labelString); XtVaSetValues(win->tab, XltNbubbleString, tipString, XmNlabelString, s1, NULL); XmStringFree(s1); XmStringFree(tipString); } /* ** close all the documents in a window */ int CloseAllDocumentInWindow(WindowInfo *window) { WindowInfo *win; if (NDocuments(window) == 1) { /* only one document in the window */ return CloseFileAndWindow(window, PROMPT_SBC_DIALOG_RESPONSE); } else { Widget winShell = window->shell; WindowInfo *topDocument; /* close all _modified_ documents belong to this window */ for (win = WindowList; win; ) { if (win->shell == winShell && win->fileChanged) { WindowInfo *next = win->next; if (!CloseFileAndWindow(win, PROMPT_SBC_DIALOG_RESPONSE)) return False; win = next; } else win = win->next; } /* see there's still documents left in the window */ for (win = WindowList; win; win=win->next) if (win->shell == winShell) break; if (win) { topDocument = GetTopDocument(winShell); /* close all non-top documents belong to this window */ for (win = WindowList; win; ) { if (win->shell == winShell && win != topDocument) { WindowInfo *next = win->next; if (!CloseFileAndWindow(win, PROMPT_SBC_DIALOG_RESPONSE)) return False; win = next; } else win = win->next; } /* close the last document and its window */ if (!CloseFileAndWindow(topDocument, PROMPT_SBC_DIALOG_RESPONSE)) return False; } } return True; } static void CloseDocumentWindow(Widget w, WindowInfo *window, XtPointer callData) { int nDocuments = NDocuments(window); if (nDocuments == NWindows()) { /* this is only window, then exit */ XtCallActionProc(WindowList->lastFocus, "exit", ((XmAnyCallbackStruct *)callData)->event, NULL, 0); } else { if (nDocuments == 1) { CloseFileAndWindow(window, PROMPT_SBC_DIALOG_RESPONSE); } else { int resp = 1; if (GetPrefWarnExit()) resp = DialogF(DF_QUES, window->shell, 2, "Close Window", "Close ALL documents in this window?", "Close", "Cancel"); if (resp == 1) CloseAllDocumentInWindow(window); } } } /* ** Refresh the menu entries per the settings of the ** top document. */ void RefreshMenuToggleStates(WindowInfo *window) { WindowInfo *win; if (!IsTopDocument(window)) return; /* File menu */ XtSetSensitive(window->printSelItem, window->wasSelected); /* Edit menu */ XtSetSensitive(window->undoItem, window->undo != NULL); XtSetSensitive(window->redoItem, window->redo != NULL); XtSetSensitive(window->printSelItem, window->wasSelected); XtSetSensitive(window->cutItem, window->wasSelected); XtSetSensitive(window->copyItem, window->wasSelected); XtSetSensitive(window->delItem, window->wasSelected); /* Preferences menu */ XmToggleButtonSetState(window->statsLineItem, window->showStats, False); XmToggleButtonSetState(window->iSearchLineItem, window->showISearchLine, False); XmToggleButtonSetState(window->lineNumsItem, window->showLineNumbers, False); XmToggleButtonSetState(window->highlightItem, window->highlightSyntax, False); XtSetSensitive(window->highlightItem, window->languageMode != PLAIN_LANGUAGE_MODE); XmToggleButtonSetState(window->backlightCharsItem, window->backlightChars, False); #ifndef VMS XmToggleButtonSetState(window->saveLastItem, window->saveOldVersion, False); #endif XmToggleButtonSetState(window->autoSaveItem, window->autoSave, False); XmToggleButtonSetState(window->overtypeModeItem, window->overstrike, False); XmToggleButtonSetState(window->matchSyntaxBasedItem, window->matchSyntaxBased, False); XmToggleButtonSetState(window->readOnlyItem, IS_USER_LOCKED(window->lockReasons), False); XtSetSensitive(window->smartIndentItem, SmartIndentMacrosAvailable(LanguageModeName(window->languageMode))); SetAutoIndent(window, window->indentStyle); SetAutoWrap(window, window->wrapMode); SetShowMatching(window, window->showMatchingStyle); SetLanguageMode(window, window->languageMode, FALSE); /* Windows Menu */ XtSetSensitive(window->splitPaneItem, window->nPanes < MAX_PANES); XtSetSensitive(window->closePaneItem, window->nPanes > 0); XtSetSensitive(window->detachDocumentItem, NDocuments(window)>1); XtSetSensitive(window->contextDetachDocumentItem, NDocuments(window)>1); for (win=WindowList; win; win=win->next) if (win->shell != window->shell) break; XtSetSensitive(window->moveDocumentItem, win != NULL); } /* ** Refresh the various settings/state of the shell window per the ** settings of the top document. */ static void refreshMenuBar(WindowInfo *window) { RefreshMenuToggleStates(window); /* Add/remove language specific menu items */ UpdateUserMenus(window); /* refresh selection-sensitive menus */ DimSelectionDepUserMenuItems(window, window->wasSelected); } /* ** remember the last document. */ WindowInfo *MarkLastDocument(WindowInfo *window) { WindowInfo *prev = lastFocusDocument; if (window) lastFocusDocument = window; return prev; } /* ** remember the active (top) document. */ WindowInfo *MarkActiveDocument(WindowInfo *window) { WindowInfo *prev = inFocusDocument; if (window) inFocusDocument = window; return prev; } /* ** Bring up the next window by tab order */ void NextDocument(WindowInfo *window) { WindowInfo *win; if (WindowList->next == NULL) return; win = getNextTabWindow(window, 1, GetPrefGlobalTabNavigate(), 1); if (win == NULL) return; if (window->shell == win->shell) RaiseDocument(win); else RaiseFocusDocumentWindow(win, True); } /* ** Bring up the previous window by tab order */ void PreviousDocument(WindowInfo *window) { WindowInfo *win; if (WindowList->next == NULL) return; win = getNextTabWindow(window, -1, GetPrefGlobalTabNavigate(), 1); if (win == NULL) return; if (window->shell == win->shell) RaiseDocument(win); else RaiseFocusDocumentWindow(win, True); } /* ** Bring up the last active window */ void LastDocument(WindowInfo *window) { WindowInfo *win; for(win = WindowList; win; win=win->next) if (lastFocusDocument == win) break; if (!win) return; if (window->shell == win->shell) RaiseDocument(win); else RaiseFocusDocumentWindow(win, True); } /* ** make sure window is alive is kicking */ int IsValidWindow(WindowInfo *window) { WindowInfo *win; for(win = WindowList; win; win=win->next) if (window == win) return True; return False; } /* ** raise the document and its shell window and focus depending on pref. */ void RaiseDocumentWindow(WindowInfo *window) { if (!window) return; RaiseDocument(window); RaiseShellWindow(window->shell, GetPrefFocusOnRaise()); } /* ** raise the document and its shell window and optionally focus. */ void RaiseFocusDocumentWindow(WindowInfo *window, Boolean focus) { if (!window) return; RaiseDocument(window); RaiseShellWindow(window->shell, focus); } /* ** Redisplay menu tearoffs previously hid by hideTearOffs() */ static void redisplayTearOffs(Widget menuPane) { WidgetList itemList; Widget subMenuID; Cardinal nItems; int n; /* redisplay all submenu tearoffs */ XtVaGetValues(menuPane, XmNchildren, &itemList, XmNnumChildren, &nItems, NULL); for (n=0; n<(int)nItems; n++) { if (XtClass(itemList[n]) == xmCascadeButtonWidgetClass) { XtVaGetValues(itemList[n], XmNsubMenuId, &subMenuID, NULL); redisplayTearOffs(subMenuID); } } /* redisplay tearoff for this menu */ if (!XmIsMenuShell(XtParent(menuPane))) ShowHiddenTearOff(menuPane); } /* ** hide all the tearoffs spawned from this menu. ** It works recursively to close the tearoffs of the submenus */ static void hideTearOffs(Widget menuPane) { WidgetList itemList; Widget subMenuID; Cardinal nItems; int n; /* hide all submenu tearoffs */ XtVaGetValues(menuPane, XmNchildren, &itemList, XmNnumChildren, &nItems, NULL); for (n=0; n<(int)nItems; n++) { if (XtClass(itemList[n]) == xmCascadeButtonWidgetClass) { XtVaGetValues(itemList[n], XmNsubMenuId, &subMenuID, NULL); hideTearOffs(subMenuID); } } /* hide tearoff for this menu */ if (!XmIsMenuShell(XtParent(menuPane))) XtUnmapWidget(XtParent(menuPane)); } /* ** Raise a tabbed document within its shell window. ** ** NB: use RaiseDocumentWindow() to raise the doc and ** its shell window. */ void RaiseDocument(WindowInfo *window) { WindowInfo *win, *lastwin; if (!window || !WindowList) return; lastwin = MarkActiveDocument(window); if (lastwin != window && IsValidWindow(lastwin)) MarkLastDocument(lastwin); /* document already on top? */ XtVaGetValues(window->mainWin, XmNuserData, &win, NULL); if (win == window) return; /* set the document as top document */ XtVaSetValues(window->mainWin, XmNuserData, window, NULL); /* show the new top document */ XtVaSetValues(window->mainWin, XmNworkWindow, window->splitPane, NULL); XtManageChild(window->splitPane); XRaiseWindow(TheDisplay, XtWindow(window->splitPane)); /* Turn on syntax highlight that might have been deferred. NB: this must be done after setting the document as XmNworkWindow and managed, else the parent shell window may shrink on some window-managers such as metacity, due to changes made in UpdateWMSizeHints().*/ if (window->highlightSyntax && window->highlightData==NULL) StartHighlighting(window, False); /* put away the bg menu tearoffs of last active document */ hideTearOffs(win->bgMenuPane); /* restore the bg menu tearoffs of active document */ redisplayTearOffs(window->bgMenuPane); /* set tab as active */ XmLFolderSetActiveTab(window->tabBar, getTabPosition(window->tab), False); /* set keyboard focus. Must be done before unmanaging previous top document, else lastFocus will be reset to textArea */ XmProcessTraversal(window->lastFocus, XmTRAVERSE_CURRENT); /* we only manage the top document, else the next time a document is raised again, it's textpane might not resize properly. Also, somehow (bug?) XtUnmanageChild() doesn't hide the splitPane, which obscure lower part of the statsform when we toggle its components, so we need to put the document at the back */ XLowerWindow(TheDisplay, XtWindow(win->splitPane)); XtUnmanageChild(win->splitPane); RefreshTabState(win); /* now refresh window state/info. RefreshWindowStates() has a lot of work to do, so we update the screen first so the document appears to switch swiftly. */ XmUpdateDisplay(window->splitPane); RefreshWindowStates(window); RefreshTabState(window); /* put away the bg menu tearoffs of last active document */ hideTearOffs(win->bgMenuPane); /* restore the bg menu tearoffs of active document */ redisplayTearOffs(window->bgMenuPane); /* Make sure that the "In Selection" button tracks the presence of a selection and that the window inherits the proper search scope. */ if (window->replaceDlog != NULL && XtIsManaged(window->replaceDlog)) { #ifdef REPLACE_SCOPE window->replaceScope = win->replaceScope; #endif UpdateReplaceActionButtons(window); } UpdateWMSizeHints(window); } WindowInfo* GetTopDocument(Widget w) { WindowInfo *window = WidgetToWindow(w); return WidgetToWindow(window->shell); } Boolean IsTopDocument(const WindowInfo *window) { return window == GetTopDocument(window->shell)? True : False; } static void deleteDocument(WindowInfo *window) { if (NULL == window) { return; } XtDestroyWidget(window->splitPane); } /* ** return the number of documents owned by this shell window */ int NDocuments(WindowInfo *window) { WindowInfo *win; int nDocument = 0; for (win = WindowList; win; win = win->next) { if (win->shell == window->shell) nDocument++; } return nDocument; } /* ** refresh window state for this document */ void RefreshWindowStates(WindowInfo *window) { if (!IsTopDocument(window)) return; if (window->modeMessageDisplayed) XmTextSetString(window->statsLine, window->modeMessage); else UpdateStatsLine(window); UpdateWindowReadOnly(window); UpdateWindowTitle(window); /* show/hide statsline as needed */ if (window->modeMessageDisplayed && !XtIsManaged(window->statsLineForm)) { /* turn on statline to display mode message */ showStats(window, True); } else if (window->showStats && !XtIsManaged(window->statsLineForm)) { /* turn on statsline since it is enabled */ showStats(window, True); } else if (!window->showStats && !window->modeMessageDisplayed && XtIsManaged(window->statsLineForm)) { /* turn off statsline since there's nothing to show */ showStats(window, False); } /* signal if macro/shell is running */ if (window->shellCmdData || window->macroCmdData) BeginWait(window->shell); else EndWait(window->shell); /* we need to force the statsline to reveal itself */ if (XtIsManaged(window->statsLineForm)) { XmTextSetCursorPosition(window->statsLine, 0); /* start of line */ XmTextSetCursorPosition(window->statsLine, 9000); /* end of line */ } XmUpdateDisplay(window->statsLine); refreshMenuBar(window); updateLineNumDisp(window); } static void cloneTextPanes(WindowInfo *window, WindowInfo *orgWin) { short paneHeights[MAX_PANES+1]; int insertPositions[MAX_PANES+1], topLines[MAX_PANES+1]; int horizOffsets[MAX_PANES+1]; int i, focusPane, emTabDist, wrapMargin, lineNumCols, totalHeight=0; char *delimiters; Widget text; selection sel; textDisp *textD, *newTextD; /* transfer the primary selection */ memcpy(&sel, &orgWin->buffer->primary, sizeof(selection)); if (sel.selected) { if (sel.rectangular) BufRectSelect(window->buffer, sel.start, sel.end, sel.rectStart, sel.rectEnd); else BufSelect(window->buffer, sel.start, sel.end); } else BufUnselect(window->buffer); /* Record the current heights, scroll positions, and insert positions of the existing panes, keyboard focus */ focusPane = 0; for (i=0; i<=orgWin->nPanes; i++) { text = i==0 ? orgWin->textArea : orgWin->textPanes[i-1]; insertPositions[i] = TextGetCursorPos(text); XtVaGetValues(containingPane(text), XmNheight, &paneHeights[i], NULL); totalHeight += paneHeights[i]; TextGetScroll(text, &topLines[i], &horizOffsets[i]); if (text == orgWin->lastFocus) focusPane = i; } window->nPanes = orgWin->nPanes; /* Copy some parameters */ XtVaGetValues(orgWin->textArea, textNemulateTabs, &emTabDist, textNwordDelimiters, &delimiters, textNwrapMargin, &wrapMargin, NULL); lineNumCols = orgWin->showLineNumbers ? MIN_LINE_NUM_COLS : 0; XtVaSetValues(window->textArea, textNemulateTabs, emTabDist, textNwordDelimiters, delimiters, textNwrapMargin, wrapMargin, textNlineNumCols, lineNumCols, NULL); /* clone split panes, if any */ textD = ((TextWidget)window->textArea)->text.textD; if (window->nPanes) { /* Unmanage & remanage the panedWindow so it recalculates pane heights */ XtUnmanageChild(window->splitPane); /* Create a text widget to add to the pane and set its buffer and highlight data to be the same as the other panes in the orgWin */ for(i=0; inPanes; i++) { text = createTextArea(window->splitPane, window, 1, 1, emTabDist, delimiters, wrapMargin, lineNumCols); TextSetBuffer(text, window->buffer); if (window->highlightData != NULL) AttachHighlightToWidget(text, window); XtManageChild(text); window->textPanes[i] = text; /* Fix up the colors */ newTextD = ((TextWidget)text)->text.textD; XtVaSetValues(text, XmNforeground, textD->fgPixel, XmNbackground, textD->bgPixel, NULL); TextDSetColors(newTextD, textD->fgPixel, textD->bgPixel, textD->selectFGPixel, textD->selectBGPixel, textD->highlightFGPixel,textD->highlightBGPixel, textD->lineNumFGPixel, textD->cursorFGPixel); } /* Set the minimum pane height in the new pane */ UpdateMinPaneHeights(window); for (i=0; i<=window->nPanes; i++) { text = i==0 ? window->textArea : window->textPanes[i-1]; setPaneDesiredHeight(containingPane(text), paneHeights[i]); } /* Re-manage panedWindow to recalculate pane heights & reset selection */ XtManageChild(window->splitPane); } /* Reset all of the heights, scroll positions, etc. */ for (i=0; i<=window->nPanes; i++) { textDisp *textD; text = i==0 ? window->textArea : window->textPanes[i-1]; TextSetCursorPos(text, insertPositions[i]); TextSetScroll(text, topLines[i], horizOffsets[i]); /* dim the cursor */ textD = ((TextWidget)text)->text.textD; TextDSetCursorStyle(textD, DIM_CURSOR); TextDUnblankCursor(textD); } /* set the focus pane */ for (i=0; i<=window->nPanes; i++) { text = i==0 ? window->textArea : window->textPanes[i-1]; if(i == focusPane) { window->lastFocus = text; XmProcessTraversal(text, XmTRAVERSE_CURRENT); break; } } /* Update the window manager size hints after the sizes of the panes have been set (the widget heights are not yet readable here, but they will be by the time the event loop gets around to running this timer proc) */ XtAppAddTimeOut(XtWidgetToApplicationContext(window->shell), 0, wmSizeUpdateProc, window); } /* ** clone a document's states and settings into the other. */ static void cloneDocument(WindowInfo *window, WindowInfo *orgWin) { const char *orgDocument; char *params[4]; int emTabDist; strcpy(window->path, orgWin->path); strcpy(window->filename, orgWin->filename); ShowLineNumbers(window, orgWin->showLineNumbers); window->ignoreModify = True; /* copy the text buffer */ orgDocument = BufAsString(orgWin->buffer); BufSetAll(window->buffer, orgDocument); /* copy the tab preferences (here!) */ BufSetTabDistance(window->buffer, orgWin->buffer->tabDist); window->buffer->useTabs = orgWin->buffer->useTabs; XtVaGetValues(orgWin->textArea, textNemulateTabs, &emTabDist, NULL); SetEmTabDist(window, emTabDist); window->ignoreModify = False; /* transfer text fonts */ params[0] = orgWin->fontName; params[1] = orgWin->italicFontName; params[2] = orgWin->boldFontName; params[3] = orgWin->boldItalicFontName; XtCallActionProc(window->textArea, "set_fonts", NULL, params, 4); SetBacklightChars(window, orgWin->backlightCharTypes); /* Clone rangeset info. FIXME: Cloning of rangesets must be done before syntax highlighting, else the rangesets do not be highlighted (colored) properly if syntax highlighting is on. */ window->buffer->rangesetTable = RangesetTableClone(orgWin->buffer->rangesetTable, window->buffer); /* Syntax highlighting */ window->languageMode = orgWin->languageMode; window->highlightSyntax = orgWin->highlightSyntax; if (window->highlightSyntax) StartHighlighting(window, False); /* copy states of original document */ window->filenameSet = orgWin->filenameSet; window->fileFormat = orgWin->fileFormat; window->lastModTime = orgWin->lastModTime; window->fileChanged = orgWin->fileChanged; window->fileMissing = orgWin->fileMissing; window->lockReasons = orgWin->lockReasons; window->autoSaveCharCount = orgWin->autoSaveCharCount; window->autoSaveOpCount = orgWin->autoSaveOpCount; window->undoOpCount = orgWin->undoOpCount; window->undoMemUsed = orgWin->undoMemUsed; window->lockReasons = orgWin->lockReasons; window->autoSave = orgWin->autoSave; window->saveOldVersion = orgWin->saveOldVersion; window->wrapMode = orgWin->wrapMode; SetOverstrike(window, orgWin->overstrike); window->showMatchingStyle = orgWin->showMatchingStyle; window->matchSyntaxBased = orgWin->matchSyntaxBased; #if 0 window->showStats = orgWin->showStats; window->showISearchLine = orgWin->showISearchLine; window->showLineNumbers = orgWin->showLineNumbers; window->modeMessageDisplayed = orgWin->modeMessageDisplayed; window->ignoreModify = orgWin->ignoreModify; window->windowMenuValid = orgWin->windowMenuValid; window->flashTimeoutID = orgWin->flashTimeoutID; window->wasSelected = orgWin->wasSelected; strcpy(window->fontName, orgWin->fontName); strcpy(window->italicFontName, orgWin->italicFontName); strcpy(window->boldFontName, orgWin->boldFontName); strcpy(window->boldItalicFontName, orgWin->boldItalicFontName); window->fontList = orgWin->fontList; window->italicFontStruct = orgWin->italicFontStruct; window->boldFontStruct = orgWin->boldFontStruct; window->boldItalicFontStruct = orgWin->boldItalicFontStruct; window->markTimeoutID = orgWin->markTimeoutID; window->highlightData = orgWin->highlightData; window->shellCmdData = orgWin->shellCmdData; window->macroCmdData = orgWin->macroCmdData; window->smartIndentData = orgWin->smartIndentData; #endif window->iSearchHistIndex = orgWin->iSearchHistIndex; window->iSearchStartPos = orgWin->iSearchStartPos; window->replaceLastRegexCase = orgWin->replaceLastRegexCase; window->replaceLastLiteralCase = orgWin->replaceLastLiteralCase; window->iSearchLastRegexCase = orgWin->iSearchLastRegexCase; window->iSearchLastLiteralCase = orgWin->iSearchLastLiteralCase; window->findLastRegexCase = orgWin->findLastRegexCase; window->findLastLiteralCase = orgWin->findLastLiteralCase; window->device = orgWin->device; window->inode = orgWin->inode; window->fileClosedAtom = orgWin->fileClosedAtom; orgWin->fileClosedAtom = None; /* copy the text/split panes settings, cursor pos & selection */ cloneTextPanes(window, orgWin); /* copy undo & redo list */ window->undo = cloneUndoItems(orgWin->undo); window->redo = cloneUndoItems(orgWin->redo); /* copy bookmarks */ window->nMarks = orgWin->nMarks; memcpy(&window->markTable, &orgWin->markTable, sizeof(Bookmark)*window->nMarks); /* kick start the auto-indent engine */ window->indentStyle = NO_AUTO_INDENT; SetAutoIndent(window, orgWin->indentStyle); /* synchronize window state to this document */ RefreshWindowStates(window); } static UndoInfo *cloneUndoItems(UndoInfo *orgList) { UndoInfo *head = NULL, *undo, *clone, *last = NULL; for (undo = orgList; undo; undo = undo->next) { clone = (UndoInfo *)XtMalloc(sizeof(UndoInfo)); memcpy(clone, undo, sizeof(UndoInfo)); if (undo->oldText) { clone->oldText = XtMalloc(strlen(undo->oldText)+1); strcpy(clone->oldText, undo->oldText); } clone->next = NULL; if (last) last->next = clone; else head = clone; last = clone; } return head; } /* ** spin off the document to a new window */ WindowInfo *DetachDocument(WindowInfo *window) { WindowInfo *win = NULL, *cloneWin; if (NDocuments(window) < 2) return NULL; /* raise another document in the same shell window if the window being detached is the top document */ if (IsTopDocument(window)) { win = getNextTabWindow(window, 1, 0, 0); RaiseDocument(win); } /* Create a new window */ cloneWin = CreateWindow(window->filename, NULL, False); /* CreateWindow() simply adds the new window's pointer to the head of WindowList. We need to adjust the detached window's pointer, so that macro functions such as focus_window("last") will travel across the documents per the sequence they're opened. The new doc will appear to replace it's former self as the old doc is closed. */ WindowList = cloneWin->next; cloneWin->next = window->next; window->next = cloneWin; /* these settings should follow the detached document. must be done before cloning window, else the height of split panes may not come out correctly */ ShowISearchLine(cloneWin, window->showISearchLine); ShowStatsLine(cloneWin, window->showStats); /* clone the document & its pref settings */ cloneDocument(cloneWin, window); /* remove the document from the old window */ window->fileChanged = False; CloseFileAndWindow(window, NO_SBC_DIALOG_RESPONSE); /* refresh former host window */ if (win) { RefreshWindowStates(win); } /* this should keep the new document window fresh */ RefreshWindowStates(cloneWin); RefreshTabState(cloneWin); SortTabBar(cloneWin); return cloneWin; } /* ** Move document to an other window. ** ** the moving document will receive certain window settings from ** its new host, i.e. the window size, stats and isearch lines. */ WindowInfo *MoveDocument(WindowInfo *toWindow, WindowInfo *window) { WindowInfo *win = NULL, *cloneWin; /* prepare to move document */ if (NDocuments(window) < 2) { /* hide the window to make it look like we are moving */ XtUnmapWidget(window->shell); } else if (IsTopDocument(window)) { /* raise another document to replace the document being moved */ win = getNextTabWindow(window, 1, 0, 0); RaiseDocument(win); } /* relocate the document to target window */ cloneWin = CreateDocument(toWindow, window->filename); ShowTabBar(cloneWin, GetShowTabBar(cloneWin)); cloneDocument(cloneWin, window); /* CreateDocument() simply adds the new window's pointer to the head of WindowList. We need to adjust the detached window's pointer, so that macro functions such as focus_window("last") will travel across the documents per the sequence they're opened. The new doc will appear to replace it's former self as the old doc is closed. */ WindowList = cloneWin->next; cloneWin->next = window->next; window->next = cloneWin; /* remove the document from the old window */ window->fileChanged = False; CloseFileAndWindow(window, NO_SBC_DIALOG_RESPONSE); /* some menu states might have changed when deleting document */ if (win) RefreshWindowStates(win); /* this should keep the new document window fresh */ RaiseDocumentWindow(cloneWin); RefreshTabState(cloneWin); SortTabBar(cloneWin); return cloneWin; } static void moveDocumentCB(Widget dialog, WindowInfo *window, XtPointer call_data) { XmSelectionBoxCallbackStruct *cbs = (XmSelectionBoxCallbackStruct *) call_data; DoneWithMoveDocumentDialog = cbs->reason; } /* ** present dialog for selecting a target window to move this document ** into. Do nothing if there is only one shell window opened. */ void MoveDocumentDialog(WindowInfo *window) { WindowInfo *win, *targetWin, **shellWinList; int i, nList=0, nWindows=0, ac; char tmpStr[MAXPATHLEN+50]; Widget parent, dialog, listBox, moveAllOption; XmString *list = NULL; XmString popupTitle, s1; Arg csdargs[20]; int *position_list, position_count; /* get the list of available shell windows, not counting the document to be moved */ nWindows = NWindows(); list = (XmStringTable) XtMalloc(nWindows * sizeof(XmString *)); shellWinList = (WindowInfo **) XtMalloc(nWindows * sizeof(WindowInfo *)); for (win=WindowList; win; win=win->next) { if (!IsTopDocument(win) || win->shell == window->shell) continue; sprintf(tmpStr, "%s%s", win->filenameSet? win->path : "", win->filename); list[nList] = XmStringCreateSimple(tmpStr); shellWinList[nList] = win; nList++; } /* stop here if there's no other window to move to */ if (!nList) { XtFree((char *)list); XtFree((char *)shellWinList); return; } /* create the dialog */ parent = window->shell; popupTitle = XmStringCreateSimple("Move Document"); sprintf(tmpStr, "Move %s into window of", window->filename); s1 = XmStringCreateSimple(tmpStr); ac = 0; XtSetArg(csdargs[ac], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); ac++; XtSetArg(csdargs[ac], XmNdialogTitle, popupTitle); ac++; XtSetArg(csdargs[ac], XmNlistLabelString, s1); ac++; XtSetArg(csdargs[ac], XmNlistItems, list); ac++; XtSetArg(csdargs[ac], XmNlistItemCount, nList); ac++; XtSetArg(csdargs[ac], XmNvisibleItemCount, 12); ac++; XtSetArg(csdargs[ac], XmNautoUnmanage, False); ac++; dialog = CreateSelectionDialog(parent,"moveDocument",csdargs,ac); XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT)); XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON)); XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_SELECTION_LABEL)); XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)moveDocumentCB, window); XtAddCallback(dialog, XmNapplyCallback, (XtCallbackProc)moveDocumentCB, window); XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)moveDocumentCB, window); XmStringFree(s1); XmStringFree(popupTitle); /* free the window list */ for (i=0; i1) XtManageChild(moveAllOption); /* disable option if only one document in the window */ XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_APPLY_BUTTON)); s1 = MKSTRING("Move"); XtVaSetValues (dialog, XmNokLabelString, s1, NULL); XmStringFree(s1); /* default to the first window on the list */ listBox = XmSelectionBoxGetChild(dialog, XmDIALOG_LIST); XmListSelectPos(listBox, 1, True); /* show the dialog */ DoneWithMoveDocumentDialog = 0; ManageDialogCenteredOnPointer(dialog); while (!DoneWithMoveDocumentDialog) XtAppProcessEvent(XtWidgetToApplicationContext(parent), XtIMAll); /* get the window to move document into */ XmListGetSelectedPos(listBox, &position_list, &position_count); targetWin = shellWinList[position_list[0]-1]; XtFree((char *)position_list); /* now move document(s) */ if (DoneWithMoveDocumentDialog == XmCR_OK) { /* move top document */ if (XmToggleButtonGetState(moveAllOption)) { /* move all documents */ for (win = WindowList; win; ) { if (win != window && win->shell == window->shell) { WindowInfo *next = win->next; MoveDocument(targetWin, win); win = next; } else win = win->next; } /* invoking document is the last to move */ MoveDocument(targetWin, window); } else { MoveDocument(targetWin, window); } } XtFree((char *)shellWinList); XtDestroyWidget(dialog); } static void hideTooltip(Widget tab) { Widget tooltip = XtNameToWidget(tab, "*BubbleShell"); if (tooltip) XtPopdown(tooltip); } static void closeTabProc(XtPointer clientData, XtIntervalId *id) { CloseFileAndWindow((WindowInfo*)clientData, PROMPT_SBC_DIALOG_RESPONSE); } /* ** callback to close-tab button. */ static void closeTabCB(Widget w, Widget mainWin, caddr_t callData) { /* FIXME: XtRemoveActionHook() related coredump An unknown bug seems to be associated with the XtRemoveActionHook() call in FinishLearn(), which resulted in coredump if a tab was closed, in the middle of keystrokes learning, by clicking on the close-tab button. As evident to our accusation, the coredump may be surpressed by simply commenting out the XtRemoveActionHook() call. The bug was consistent on both Motif and Lesstif on various platforms. Closing the tab through either the "Close" menu or its accel key, however, was without any trouble. While its actual mechanism is not well understood, we somehow managed to workaround the bug by delaying the action of closing the tab. For now. */ XtAppAddTimeOut(XtWidgetToApplicationContext(w), 0, closeTabProc, GetTopDocument(mainWin)); } /* ** callback to clicks on a tab to raise it's document. */ static void raiseTabCB(Widget w, XtPointer clientData, XtPointer callData) { XmLFolderCallbackStruct *cbs = (XmLFolderCallbackStruct *)callData; WidgetList tabList; Widget tab; XtVaGetValues(w, XmNtabWidgetList, &tabList, NULL); tab = tabList[cbs->pos]; RaiseDocument(TabToWindow(tab)); } static Widget containingPane(Widget w) { /* The containing pane used to simply be the first parent, but with the introduction of an XmFrame, it's the grandparent. */ return XtParent(XtParent(w)); } static void cancelTimeOut(XtIntervalId *timer) { if (*timer != 0) { XtRemoveTimeOut(*timer); *timer = 0; } } /* ** set/clear toggle menu state if the calling document is on top. */ void SetToggleButtonState(WindowInfo *window, Widget w, Boolean state, Boolean notify) { if (IsTopDocument(window)) { XmToggleButtonSetState(w, state, notify); } } /* ** set/clear menu sensitivity if the calling document is on top. */ void SetSensitive(WindowInfo *window, Widget w, Boolean sensitive) { if (IsTopDocument(window)) { XtSetSensitive(w, sensitive); } } /* ** Remove redundant expose events on tab bar. */ void CleanUpTabBarExposeQueue(WindowInfo *window) { XEvent event; XExposeEvent ev; int count; if (window == NULL) return; /* remove redundant expose events on tab bar */ count=0; while (XCheckTypedWindowEvent(TheDisplay, XtWindow(window->tabBar), Expose, &event)) count++; /* now we can update tabbar */ if (count) { ev.type = Expose; ev.display = TheDisplay; ev.window = XtWindow(window->tabBar); ev.x = 0; ev.y = 0; ev.width = XtWidth(window->tabBar); ev.height = XtHeight(window->tabBar); ev.count = 0; XSendEvent(TheDisplay, XtWindow(window->tabBar), False, ExposureMask, (XEvent *)&ev); } } nedit-5.6.orig/source/window.h0000644000175000017500000001330410737527371015107 0ustar paulpaul/* $Id: window.h,v 1.33 2008/01/04 22:11:05 yooden Exp $ */ /******************************************************************************* * * * window.h -- Nirvana Editor Window header file * * * * Copyright 2004 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_WINDOW_H_INCLUDED #define NEDIT_WINDOW_H_INCLUDED #include "nedit.h" #include "textBuf.h" #include void AttachSessionMgrHandler(Widget appShell); WindowInfo *CreateWindow(const char *title, char *geometry, int iconic); void CloseWindow(WindowInfo *window); int NWindows(void); void UpdateWindowTitle(const WindowInfo *window); void UpdateWindowReadOnly(WindowInfo *window); void UpdateStatsLine(WindowInfo *window); void UpdateWMSizeHints(WindowInfo *window); void UpdateMinPaneHeights(WindowInfo *window); void UpdateNewOppositeMenu(WindowInfo *window, int openInTab); void SetWindowModified(WindowInfo *window, int modified); void MakeSelectionVisible(WindowInfo *window, Widget textPane); int GetSimpleSelection(textBuffer *buf, int *left, int *right); WindowInfo *FindWindowWithFile(const char *name, const char *path); void SetAutoIndent(WindowInfo *window, int state); void SetShowMatching(WindowInfo *window, int state); void SetFonts(WindowInfo *window, const char *fontName, const char *italicName, const char *boldName, const char *boldItalicName); void SetColors(WindowInfo *window, const char *textFg, const char *textBg, const char *selectFg, const char *selectBg, const char *hiliteFg, const char *hiliteBg, const char *lineNoFg, const char *cursorFg); void SetOverstrike(WindowInfo *window, int overstrike); void SetAutoWrap(WindowInfo *window, int state); void SetAutoScroll(WindowInfo *window, int margin); void SplitPane(WindowInfo *window); Widget GetPaneByIndex(WindowInfo *window, int paneIndex); int WidgetToPaneIndex(WindowInfo *window, Widget w); void ClosePane(WindowInfo *window); int GetShowTabBar(WindowInfo *window); void ShowTabBar(WindowInfo *window, int state); void ShowStatsLine(WindowInfo *window, int state); void ShowISearchLine(WindowInfo *window, int state); void TempShowISearch(WindowInfo *window, int state); void ShowLineNumbers(WindowInfo *window, int state); void SetModeMessage(WindowInfo *window, const char *message); void ClearModeMessage(WindowInfo *window); WindowInfo *WidgetToWindow(Widget w); void AddSmallIcon(Widget shell); void SetTabDist(WindowInfo *window, int tabDist); void SetEmTabDist(WindowInfo *window, int emTabDist); int CloseAllDocumentInWindow(WindowInfo *window); WindowInfo* CreateDocument(WindowInfo* shellWindow, const char* name); WindowInfo *TabToWindow(Widget tab); void RaiseDocument(WindowInfo *window); void RaiseDocumentWindow(WindowInfo *window); void RaiseFocusDocumentWindow(WindowInfo *window, Boolean focus); WindowInfo *MarkLastDocument(WindowInfo *window); WindowInfo *MarkActiveDocument(WindowInfo *window); void NextDocument(WindowInfo *window); void PreviousDocument(WindowInfo *window); void LastDocument(WindowInfo *window); int NDocuments(WindowInfo *window); WindowInfo *MoveDocument(WindowInfo *toWindow, WindowInfo *window); WindowInfo *DetachDocument(WindowInfo *window); void MoveDocumentDialog(WindowInfo *window); WindowInfo* GetTopDocument(Widget w); Boolean IsTopDocument(const WindowInfo *window); int IsIconic(WindowInfo *window); int IsValidWindow(WindowInfo *window); void RefreshTabState(WindowInfo *window); void ShowWindowTabBar(WindowInfo *window); void RefreshMenuToggleStates(WindowInfo *window); void RefreshWindowStates(WindowInfo *window); void AllWindowsBusy(const char* message); void AllWindowsUnbusy(void); void SortTabBar(WindowInfo *window); void SetBacklightChars(WindowInfo *window, char *applyBacklightTypes); void SetToggleButtonState(WindowInfo *window, Widget w, Boolean state, Boolean notify); void SetSensitive(WindowInfo *window, Widget w, Boolean sensitive); void CleanUpTabBarExposeQueue(WindowInfo *window); #endif /* NEDIT_WINDOW_H_INCLUDED */ nedit-5.6.orig/source/windowTitle.c0000644000175000017500000014054210736147254016106 0ustar paulpaulstatic const char CVSID[] = "$Id: windowTitle.c,v 1.16 2007/12/31 11:12:44 yooden Exp $"; /******************************************************************************* * * * windowTitle.c -- Nirvana Editor window title customization * * * * Copyright (C) 2001, Arne Forlie * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * * Written by Arne Forlie, http://arne.forlie.com * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "windowTitle.h" #include "textBuf.h" #include "nedit.h" #include "preferences.h" #include "help.h" #include "../util/prefFile.h" #include "../util/misc.h" #include "../util/DialogF.h" #include "../util/utils.h" #include "../util/fileUtils.h" #include #include #include #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #include "../util/clearcase.h" #endif /*VMS*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #define WINDOWTITLE_MAX_LEN 500 /* Customize window title dialog information */ static struct { Widget form; Widget shell; WindowInfo* window; Widget previewW; Widget formatW; Widget ccW; Widget fileW; Widget hostW; Widget dirW; Widget statusW; Widget shortStatusW; Widget serverW; Widget nameW; Widget mdirW; Widget ndirW; Widget oDirW; Widget oCcViewTagW; Widget oServerNameW; Widget oFileChangedW; Widget oFileLockedW; Widget oFileReadOnlyW; Widget oServerEqualViewW; char filename[MAXPATHLEN]; char path[MAXPATHLEN]; char viewTag[MAXPATHLEN]; char serverName[MAXPATHLEN]; int isServer; int filenameSet; int lockReasons; int fileChanged; int suppressFormatUpdate; } etDialog = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,"","","","",0,0,0,0,0}; static char* removeSequence(char* sourcePtr, char c) { while (*sourcePtr == c) { sourcePtr++; } return(sourcePtr); } /* ** Two functions for performing safe insertions into a finite ** size buffer so that we don't get any memory overruns. */ static char* safeStrCpy(char* dest, char* destEnd, const char* source) { int len = (int)strlen(source); if (len <= (destEnd - dest)) { strcpy(dest, source); return(dest + len); } else { strncpy(dest, source, destEnd - dest); *destEnd = '\0'; return(destEnd); } } static char* safeCharAdd(char* dest, char* destEnd, char c) { if (destEnd - dest > 0) { *dest++ = c; *dest = '\0'; } return(dest); } /* ** Remove empty paranthesis pairs and multiple spaces in a row ** with one space. ** Also remove leading and trailing spaces and dashes. */ static void compressWindowTitle(char *title) { /* Compress the title */ int modified; do { char *sourcePtr = title; char *destPtr = sourcePtr; char c = *sourcePtr++; modified = False; /* Remove leading spaces and dashes */ while (c == ' ' || c == '-') { c= *sourcePtr++; } /* Remove empty constructs */ while (c != '\0') { switch (c) { /* remove sequences */ case ' ': case '-': sourcePtr = removeSequence(sourcePtr, c); *destPtr++ = c; /* leave one */ break; /* remove empty paranthesis pairs */ case '(': if (*sourcePtr == ')') { modified = True; sourcePtr++; } else *destPtr++ = c; sourcePtr = removeSequence(sourcePtr, ' '); break; case '[': if (*sourcePtr == ']') { modified = True; sourcePtr++; } else *destPtr++ = c; sourcePtr = removeSequence(sourcePtr, ' '); break; case '{': if (*sourcePtr == '}') { modified = True; sourcePtr++; } else *destPtr++ = c; sourcePtr = removeSequence(sourcePtr, ' '); break; default: *destPtr++ = c; break; } c = *sourcePtr++; *destPtr = '\0'; } /* Remove trailing spaces and dashes */ while (destPtr-- > title) { if (*destPtr != ' ' && *destPtr != '-') break; *destPtr = '\0'; } } while (modified == True); } /* ** Format the windows title using a printf like formatting string. ** The following flags are recognised: ** %c : ClearCase view tag ** %s : server name ** %[n]d : directory, with one optional digit specifying the max number ** of trailing directory components to display. Skipped components are ** replaced by an ellipsis (...). ** %f : file name ** %h : host name ** %S : file status ** %u : user name ** ** if the ClearCase view tag and server name are identical, only the first one ** specified in the formatting string will be displayed. */ char *FormatWindowTitle(const char* filename, const char* path, const char* clearCaseViewTag, const char* serverName, int isServer, int filenameSet, int lockReasons, int fileChanged, const char* titleFormat) { static char title[WINDOWTITLE_MAX_LEN]; char *titlePtr = title; char* titleEnd = title + WINDOWTITLE_MAX_LEN - 1; /* Flags to supress one of these if both are specified and they are identical */ int serverNameSeen = False; int clearCaseViewTagSeen = False; int fileNamePresent = False; int hostNamePresent = False; int userNamePresent = False; int serverNamePresent = False; int clearCasePresent = False; int fileStatusPresent = False; int dirNamePresent = False; int noOfComponents = -1; int shortStatus = False; *titlePtr = '\0'; /* always start with an empty string */ while (*titleFormat != '\0' && titlePtr < titleEnd) { char c = *titleFormat++; if (c == '%') { c = *titleFormat++; if (c == '\0') { titlePtr = safeCharAdd(titlePtr, titleEnd, '%'); break; } switch (c) { case 'c': /* ClearCase view tag */ clearCasePresent = True; if (clearCaseViewTag != NULL) { if (serverNameSeen == False || strcmp(serverName, clearCaseViewTag) != 0) { titlePtr = safeStrCpy(titlePtr, titleEnd, clearCaseViewTag); clearCaseViewTagSeen = True; } } break; case 's': /* server name */ serverNamePresent = True; if (isServer && serverName[0] != '\0') { /* only applicable for servers */ if (clearCaseViewTagSeen == False || strcmp(serverName, clearCaseViewTag) != 0) { titlePtr = safeStrCpy(titlePtr, titleEnd, serverName); serverNameSeen = True; } } break; case 'd': /* directory without any limit to no. of components */ dirNamePresent = True; if (filenameSet) { titlePtr = safeStrCpy(titlePtr, titleEnd, path); } break; case '0': /* directory with limited no. of components */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (*titleFormat == 'd') { dirNamePresent = True; noOfComponents = c - '0'; titleFormat++; /* delete the argument */ if (filenameSet) { const char* trailingPath = GetTrailingPathComponents(path, noOfComponents); /* prefix with ellipsis if components were skipped */ if (trailingPath > path) { titlePtr = safeStrCpy(titlePtr, titleEnd, "..."); } titlePtr = safeStrCpy(titlePtr, titleEnd, trailingPath); } } break; case 'f': /* file name */ fileNamePresent = True; titlePtr = safeStrCpy(titlePtr, titleEnd, filename); break; case 'h': /* host name */ hostNamePresent = True; titlePtr = safeStrCpy(titlePtr, titleEnd, GetNameOfHost()); break; case 'S': /* file status */ fileStatusPresent = True; if (IS_ANY_LOCKED_IGNORING_USER(lockReasons) && fileChanged) titlePtr = safeStrCpy(titlePtr, titleEnd, "read only, modified"); else if (IS_ANY_LOCKED_IGNORING_USER(lockReasons)) titlePtr = safeStrCpy(titlePtr, titleEnd, "read only"); else if (IS_USER_LOCKED(lockReasons) && fileChanged) titlePtr = safeStrCpy(titlePtr, titleEnd, "locked, modified"); else if (IS_USER_LOCKED(lockReasons)) titlePtr = safeStrCpy(titlePtr, titleEnd, "locked"); else if (fileChanged) titlePtr = safeStrCpy(titlePtr, titleEnd, "modified"); break; case 'u': /* user name */ userNamePresent = True; titlePtr = safeStrCpy(titlePtr, titleEnd, GetUserName()); break; case '%': /* escaped % */ titlePtr = safeCharAdd(titlePtr, titleEnd, '%'); break; case '*': /* short file status ? */ fileStatusPresent = True; if (*titleFormat && *titleFormat == 'S') { ++titleFormat; shortStatus = True; if (IS_ANY_LOCKED_IGNORING_USER(lockReasons) && fileChanged) titlePtr = safeStrCpy(titlePtr, titleEnd, "RO*"); else if (IS_ANY_LOCKED_IGNORING_USER(lockReasons)) titlePtr = safeStrCpy(titlePtr, titleEnd, "RO"); else if (IS_USER_LOCKED(lockReasons) && fileChanged) titlePtr = safeStrCpy(titlePtr, titleEnd, "LO*"); else if (IS_USER_LOCKED(lockReasons)) titlePtr = safeStrCpy(titlePtr, titleEnd, "LO"); else if (fileChanged) titlePtr = safeStrCpy(titlePtr, titleEnd, "*"); break; } /* fall-through */ default: titlePtr = safeCharAdd(titlePtr, titleEnd, c); break; } } else { titlePtr = safeCharAdd(titlePtr, titleEnd, c); } } compressWindowTitle(title); if (title[0] == 0) { sprintf(&title[0], ""); /* For preview purposes only */ } if (etDialog.form) { /* Prevent recursive callback loop */ etDialog.suppressFormatUpdate = True; /* Sync radio buttons with format string (in case the user entered the format manually) */ XmToggleButtonSetState(etDialog.fileW, fileNamePresent, False); XmToggleButtonSetState(etDialog.statusW, fileStatusPresent, False); XmToggleButtonSetState(etDialog.serverW, serverNamePresent, False); #ifndef VMS XmToggleButtonSetState(etDialog.ccW, clearCasePresent, False); #endif /* VMS */ XmToggleButtonSetState(etDialog.dirW, dirNamePresent, False); XmToggleButtonSetState(etDialog.hostW, hostNamePresent, False); XmToggleButtonSetState(etDialog.nameW, userNamePresent, False); XtSetSensitive(etDialog.shortStatusW, fileStatusPresent); if (fileStatusPresent) { XmToggleButtonSetState(etDialog.shortStatusW, shortStatus, False); } /* Directory components are also sensitive to presence of dir */ XtSetSensitive(etDialog.ndirW, dirNamePresent); XtSetSensitive(etDialog.mdirW, dirNamePresent); if (dirNamePresent) /* Avoid erasing number when not active */ { if (noOfComponents >= 0) { char* value = XmTextGetString(etDialog.ndirW); char buf[2]; sprintf(&buf[0], "%d", noOfComponents); if (strcmp(&buf[0], value)) /* Don't overwrite unless diff. */ SetIntText(etDialog.ndirW, noOfComponents); XtFree(value); } else { XmTextSetString(etDialog.ndirW, ""); } } /* Enable/disable test buttons, depending on presence of codes */ XtSetSensitive(etDialog.oFileChangedW, fileStatusPresent); XtSetSensitive(etDialog.oFileReadOnlyW, fileStatusPresent); XtSetSensitive(etDialog.oFileLockedW, fileStatusPresent && !IS_PERM_LOCKED(etDialog.lockReasons)); XtSetSensitive(etDialog.oServerNameW, serverNamePresent); #ifndef VMS XtSetSensitive(etDialog.oCcViewTagW, clearCasePresent); XtSetSensitive(etDialog.oServerEqualViewW, clearCasePresent && serverNamePresent); #endif /* VMS */ XtSetSensitive(etDialog.oDirW, dirNamePresent); etDialog.suppressFormatUpdate = False; } return(title); } /* a utility that sets the values of all toggle buttons */ static void setToggleButtons(void) { XmToggleButtonSetState(etDialog.oDirW, etDialog.filenameSet == True, False); XmToggleButtonSetState(etDialog.oFileChangedW, etDialog.fileChanged == True, False); XmToggleButtonSetState(etDialog.oFileReadOnlyW, IS_PERM_LOCKED(etDialog.lockReasons), False); XmToggleButtonSetState(etDialog.oFileLockedW, IS_USER_LOCKED(etDialog.lockReasons), False); /* Read-only takes precedence on locked */ XtSetSensitive(etDialog.oFileLockedW, !IS_PERM_LOCKED(etDialog.lockReasons)); #ifdef VMS XmToggleButtonSetState(etDialog.oServerNameW, etDialog.isServer, False); #else XmToggleButtonSetState(etDialog.oCcViewTagW, GetClearCaseViewTag() != NULL, False); XmToggleButtonSetState(etDialog.oServerNameW, etDialog.isServer, False); if (GetClearCaseViewTag() != NULL && etDialog.isServer && GetPrefServerName()[0] != '\0' && strcmp(GetClearCaseViewTag(), GetPrefServerName()) == 0) { XmToggleButtonSetState(etDialog.oServerEqualViewW, True, False); } else { XmToggleButtonSetState(etDialog.oServerEqualViewW, False, False); } #endif /* VMS */ } static void formatChangedCB(Widget w, XtPointer clientData, XtPointer callData) { char *format; int filenameSet = XmToggleButtonGetState(etDialog.oDirW); char *title; const char* serverName; if (etDialog.suppressFormatUpdate) { return; /* Prevent recursive feedback */ } format = XmTextGetString(etDialog.formatW); #ifndef VMS if (XmToggleButtonGetState(etDialog.oServerEqualViewW) && XmToggleButtonGetState(etDialog.ccW)) { serverName = etDialog.viewTag; } else #endif /* VMS */ { serverName = XmToggleButtonGetState(etDialog.oServerNameW) ? etDialog.serverName : ""; } title = FormatWindowTitle( etDialog.filename, etDialog.filenameSet == True ? etDialog.path : "/a/very/long/path/used/as/example/", #ifdef VMS NULL, #else XmToggleButtonGetState(etDialog.oCcViewTagW) ? etDialog.viewTag : NULL, #endif /* VMS */ serverName, etDialog.isServer, filenameSet, etDialog.lockReasons, XmToggleButtonGetState(etDialog.oFileChangedW), format); XtFree(format); XmTextFieldSetString(etDialog.previewW, title); } #ifndef VMS static void ccViewTagCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(w) == False) { XmToggleButtonSetState(etDialog.oServerEqualViewW, False, False); } formatChangedCB(w, clientData, callData); } #endif /* VMS */ static void serverNameCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(w) == False) { XmToggleButtonSetState(etDialog.oServerEqualViewW, False, False); } etDialog.isServer = XmToggleButtonGetState(w); formatChangedCB(w, clientData, callData); } static void fileChangedCB(Widget w, XtPointer clientData, XtPointer callData) { etDialog.fileChanged = XmToggleButtonGetState(w); formatChangedCB(w, clientData, callData); } static void fileLockedCB(Widget w, XtPointer clientData, XtPointer callData) { SET_USER_LOCKED(etDialog.lockReasons, XmToggleButtonGetState(w)); formatChangedCB(w, clientData, callData); } static void fileReadOnlyCB(Widget w, XtPointer clientData, XtPointer callData) { SET_PERM_LOCKED(etDialog.lockReasons, XmToggleButtonGetState(w)); formatChangedCB(w, clientData, callData); } #ifndef VMS static void serverEqualViewCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(w) == True) { XmToggleButtonSetState(etDialog.oCcViewTagW, True, False); XmToggleButtonSetState(etDialog.oServerNameW, True, False); etDialog.isServer = True; } formatChangedCB(w, clientData, callData); } #endif /* VMS */ static void applyCB(Widget w, XtPointer clientData, XtPointer callData) { char *format = XmTextGetString(etDialog.formatW); /* pop down the dialog */ /* XtUnmanageChild(etDialog.form); */ if (strcmp(format, GetPrefTitleFormat()) != 0) { SetPrefTitleFormat(format); } XtFree(format); } static void closeCB(Widget w, XtPointer clientData, XtPointer callData) { /* pop down the dialog */ XtUnmanageChild(etDialog.form); } static void restoreCB(Widget w, XtPointer clientData, XtPointer callData) { XmTextSetString(etDialog.formatW, "{%c} [%s] %f (%S) - %d"); } static void helpCB(Widget w, XtPointer clientData, XtPointer callData) { Help(HELP_CUSTOM_TITLE_DIALOG); } static void wtDestroyCB(Widget w, XtPointer clientData, XtPointer callData) { if (w == etDialog.form) /* Prevent disconnecting the replacing dialog */ etDialog.form = NULL; } static void wtUnmapCB(Widget w, XtPointer clientData, XtPointer callData) { if (etDialog.form == w) /* Prevent destroying the replacing dialog */ XtDestroyWidget(etDialog.form); } static void appendToFormat(const char* string) { char *format = XmTextGetString(etDialog.formatW); char *buf = XtMalloc(strlen(string) + strlen(format) + 1); strcpy(buf, format); strcat(buf, string); XmTextSetString(etDialog.formatW, buf); XtFree(format); XtFree(buf); } static void removeFromFormat(const char* string) { char *format = XmTextGetString(etDialog.formatW); char* pos; /* There can be multiple occurences */ while ((pos = strstr(format, string))) { /* If the string is preceded or followed by a brace, include the brace(s) for removal */ char* start = pos; char* end = pos + strlen(string); char post = *end; if (post == '}' || post == ')' || post == ']' || post == '>') { end += 1; post = *end; } if (start > format) { char pre = *(start-1); if (pre == '{' || pre == '(' || pre == '[' || pre == '<') start -= 1; } if (start > format) { char pre = *(start-1); /* If there is a space in front and behind, remove one space (there can be more spaces, but in that case it is likely that the user entered them manually); also remove trailing space */ if (pre == ' ' && post == ' ') { end += 1; } else if (pre == ' ' && post == (char)0) { /* Remove (1) trailing space */ start -= 1; } } /* Contract the string: move end to start */ strcpy(start, end); } /* Remove leading and trailing space */ pos = format; while (*pos == ' ') ++pos; strcpy(format, pos); pos = format + strlen(format) - 1; while (pos >= format && *pos == ' ') { --pos; } *(pos+1) = (char)0; XmTextSetString(etDialog.formatW, format); XtFree(format); } static void toggleFileCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(etDialog.fileW)) appendToFormat(" %f"); else removeFromFormat("%f"); } static void toggleServerCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(etDialog.serverW)) appendToFormat(" [%s]"); else removeFromFormat("%s"); } static void toggleHostCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(etDialog.hostW)) appendToFormat(" [%h]"); else removeFromFormat("%h"); } #ifndef VMS static void toggleClearCaseCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(etDialog.ccW)) appendToFormat(" {%c}"); else removeFromFormat("%c"); } #endif /* VMS */ static void toggleStatusCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(etDialog.statusW)) { if (XmToggleButtonGetState(etDialog.shortStatusW)) appendToFormat(" (%*S)"); else appendToFormat(" (%S)"); } else { removeFromFormat("%S"); removeFromFormat("%*S"); } } static void toggleShortStatusCB(Widget w, XtPointer clientData, XtPointer callData) { char *format, *pos; if (etDialog.suppressFormatUpdate) { return; } format = XmTextGetString(etDialog.formatW); if (XmToggleButtonGetState(etDialog.shortStatusW)) { /* Find all %S occurrences and replace them by %*S */ do { pos = strstr(format, "%S"); if (pos) { char* tmp = (char*)XtMalloc((strlen(format)+2)*sizeof(char)); strncpy(tmp, format, (size_t)(pos-format+1)); tmp[pos-format+1] = 0; strcat(tmp, "*"); strcat(tmp, pos+1); XtFree(format); format = tmp; } } while (pos); } else { /* Replace all %*S occurences by %S */ do { pos = strstr(format, "%*S"); if (pos) { strcpy(pos+1, pos+2); } } while(pos); } XmTextSetString(etDialog.formatW, format); XtFree(format); } static void toggleUserCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(etDialog.nameW)) appendToFormat(" %u"); else removeFromFormat("%u"); } static void toggleDirectoryCB(Widget w, XtPointer clientData, XtPointer callData) { if (XmToggleButtonGetState(etDialog.dirW)) { char buf[20]; int maxComp; char *value = XmTextGetString(etDialog.ndirW); if (*value) { if (sscanf(value, "%d", &maxComp) > 0) { sprintf(&buf[0], " %%%dd ", maxComp); } else { sprintf(&buf[0], " %%d "); /* Should not be necessary */ } } else { sprintf(&buf[0], " %%d "); } XtFree(value); appendToFormat(buf); } else { int i; removeFromFormat("%d"); for (i=0; i<=9; ++i) { char buf[20]; sprintf(&buf[0], "%%%dd", i); removeFromFormat(buf); } } } static void enterMaxDirCB(Widget w, XtPointer clientData, XtPointer callData) { int maxComp = -1; char *format; char *value; if (etDialog.suppressFormatUpdate) { return; } format = XmTextGetString(etDialog.formatW); value = XmTextGetString(etDialog.ndirW); if (*value) { if (sscanf(value, "%d", &maxComp) <= 0) { /* Don't allow non-digits to be entered */ XBell(XtDisplay(w), 0); XmTextSetString(etDialog.ndirW, ""); } } if (maxComp >= 0) { char *pos; int found = False; char insert[2]; insert[0] = (char)('0' + maxComp); insert[1] = (char)0; /* '0' digit and 0 char ! */ /* Find all %d and %nd occurrences and replace them by the new value */ do { int i; found = False; pos = strstr(format, "%d"); if (pos) { char* tmp = (char*)XtMalloc((strlen(format)+2)*sizeof(char)); strncpy(tmp, format, (size_t)(pos-format+1)); tmp[pos-format+1] = 0; strcat(tmp, &insert[0]); strcat(tmp, pos+1); XtFree(format); format = tmp; found = True; } for (i=0; i<=9; ++i) { char buf[20]; sprintf(&buf[0], "%%%dd", i); if (i != maxComp) { pos = strstr(format, &buf[0]); if (pos) { *(pos+1) = insert[0]; found = True; } } } } while (found); } else { int found = True; /* Replace all %nd occurences by %d */ do { int i; found = False; for (i=0; i<=9; ++i) { char buf[20]; char *pos; sprintf(&buf[0], "%%%dd", i); pos = strstr(format, &buf[0]); if (pos) { strcpy(pos+1, pos+2); found = True; } } } while(found); } XmTextSetString(etDialog.formatW, format); XtFree(format); XtFree(value); } static void createEditTitleDialog(Widget parent) { #define LEFT_MARGIN_POS 2 #define RIGHT_MARGIN_POS 98 #define V_MARGIN 5 #define RADIO_INDENT 3 Widget buttonForm, formatLbl, previewFrame; Widget previewForm, previewBox, selectFrame, selectBox, selectForm; Widget testLbl, selectLbl; Widget applyBtn, closeBtn, restoreBtn, helpBtn; XmString s1; XmFontList fontList; Arg args[20]; int defaultBtnOffset; Dimension shadowThickness; Dimension radioHeight, textHeight; Pixel background; int ac = 0; XtSetArg(args[ac], XmNautoUnmanage, False); ac++; XtSetArg(args[ac], XmNtitle, "Customize Window Title"); ac++; etDialog.form = CreateFormDialog(parent, "customizeTitle", args, ac); /* * Destroy the dialog every time it is unmapped (otherwise it 'sticks' * to the window for which it was created originally). */ XtAddCallback(etDialog.form, XmNunmapCallback, wtUnmapCB, NULL); XtAddCallback(etDialog.form, XmNdestroyCallback, wtDestroyCB, NULL); etDialog.shell = XtParent(etDialog.form); /* Definition form */ selectFrame = XtVaCreateManagedWidget("selectionFrame", xmFrameWidgetClass, etDialog.form, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LEFT_MARGIN_POS, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, V_MARGIN, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, NULL); XtVaCreateManagedWidget("titleLabel", xmLabelGadgetClass, selectFrame, XmNlabelString, s1=XmStringCreateSimple("Title definition"), XmNchildType, XmFRAME_TITLE_CHILD, XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING, NULL); XmStringFree(s1); selectForm = XtVaCreateManagedWidget("selectForm", xmFormWidgetClass, selectFrame , XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LEFT_MARGIN_POS, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, V_MARGIN, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, NULL); selectLbl = XtVaCreateManagedWidget("selectLabel", xmLabelGadgetClass, selectForm, XmNlabelString, s1=XmStringCreateSimple("Select title components to include: "), XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LEFT_MARGIN_POS, XmNtopOffset, 5, XmNbottomOffset, 5, XmNtopAttachment, XmATTACH_FORM, NULL); XmStringFree(s1); selectBox = XtVaCreateManagedWidget("selectBox", xmFormWidgetClass, selectForm, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_TIGHT, XmNradioBehavior, False, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, selectLbl, NULL); etDialog.fileW = XtVaCreateManagedWidget("file", xmToggleButtonWidgetClass, selectBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RADIO_INDENT, XmNtopAttachment, XmATTACH_FORM, XmNlabelString, s1=XmStringCreateSimple("File name (%f)"), XmNmnemonic, 'F', NULL); XtAddCallback(etDialog.fileW, XmNvalueChangedCallback, toggleFileCB, NULL); XmStringFree(s1); etDialog.statusW = XtVaCreateManagedWidget("status", xmToggleButtonWidgetClass, selectBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.fileW, XmNlabelString, s1=XmStringCreateSimple("File status (%S) "), XmNmnemonic, 't', NULL); XtAddCallback(etDialog.statusW, XmNvalueChangedCallback, toggleStatusCB, NULL); XmStringFree(s1); etDialog.shortStatusW = XtVaCreateManagedWidget("shortStatus", xmToggleButtonWidgetClass, selectBox, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, etDialog.statusW, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.fileW, XmNlabelString, s1=XmStringCreateSimple("brief"), XmNmnemonic, 'b', NULL); XtAddCallback(etDialog.shortStatusW, XmNvalueChangedCallback, toggleShortStatusCB, NULL); XmStringFree(s1); etDialog.ccW = XtVaCreateManagedWidget("ccView", xmToggleButtonWidgetClass, selectBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.statusW, XmNlabelString, s1=XmStringCreateSimple("ClearCase view tag (%c) "), XmNmnemonic, 'C', NULL); #ifdef VMS XtSetSensitive(etDialog.ccW, False); #else XtAddCallback(etDialog.ccW, XmNvalueChangedCallback, toggleClearCaseCB, NULL); #endif /* VMS */ XmStringFree(s1); etDialog.dirW = XtVaCreateManagedWidget("directory", xmToggleButtonWidgetClass, selectBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.ccW, XmNlabelString, s1=XmStringCreateSimple("Directory (%d),"), XmNmnemonic, 'D', NULL); XtAddCallback(etDialog.dirW, XmNvalueChangedCallback, toggleDirectoryCB, NULL); XmStringFree(s1); XtVaGetValues(etDialog.fileW, XmNheight, &radioHeight, NULL); etDialog.mdirW = XtVaCreateManagedWidget("componentLab", xmLabelGadgetClass, selectBox, XmNheight, radioHeight, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, etDialog.dirW, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.ccW, XmNlabelString, s1=XmStringCreateSimple("max. components: "), XmNmnemonic, 'x', NULL); XmStringFree(s1); etDialog.ndirW = XtVaCreateManagedWidget("dircomp", xmTextWidgetClass, selectBox, XmNcolumns, 1, XmNmaxLength, 1, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, etDialog.mdirW, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.ccW, NULL); XtAddCallback(etDialog.ndirW, XmNvalueChangedCallback, enterMaxDirCB, NULL); RemapDeleteKey(etDialog.ndirW); XtVaSetValues(etDialog.mdirW, XmNuserData, etDialog.ndirW, NULL); /* mnemonic processing */ XtVaGetValues(etDialog.ndirW, XmNheight, &textHeight, NULL); XtVaSetValues(etDialog.dirW, XmNheight, textHeight, NULL); XtVaSetValues(etDialog.mdirW, XmNheight, textHeight, NULL); etDialog.hostW = XtVaCreateManagedWidget("host", xmToggleButtonWidgetClass, selectBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 50 + RADIO_INDENT, XmNtopAttachment, XmATTACH_FORM, XmNlabelString, s1=XmStringCreateSimple("Host name (%h)"), XmNmnemonic, 'H', NULL); XtAddCallback(etDialog.hostW, XmNvalueChangedCallback, toggleHostCB, NULL); XmStringFree(s1); etDialog.nameW = XtVaCreateManagedWidget("name", xmToggleButtonWidgetClass, selectBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 50 + RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.hostW, XmNlabelString, s1=XmStringCreateSimple("User name (%u)"), XmNmnemonic, 'U', NULL); XtAddCallback(etDialog.nameW, XmNvalueChangedCallback, toggleUserCB, NULL); XmStringFree(s1); etDialog.serverW = XtVaCreateManagedWidget("server", xmToggleButtonWidgetClass, selectBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 50 + RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.nameW, XmNlabelString, s1=XmStringCreateSimple("NEdit server name (%s)"), XmNmnemonic, 's', NULL); XtAddCallback(etDialog.serverW, XmNvalueChangedCallback, toggleServerCB, NULL); XmStringFree(s1); formatLbl = XtVaCreateManagedWidget("formatLbl", xmLabelGadgetClass, selectForm, XmNlabelString, s1=XmStringCreateSimple("Format: "), XmNmnemonic, 'r', XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LEFT_MARGIN_POS, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, selectBox, XmNbottomAttachment, XmATTACH_FORM, NULL); XmStringFree(s1); etDialog.formatW = XtVaCreateManagedWidget("format", xmTextWidgetClass, selectForm, XmNmaxLength, WINDOWTITLE_MAX_LEN, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, selectBox, XmNtopOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, formatLbl, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, NULL); RemapDeleteKey(etDialog.formatW); XtVaSetValues(formatLbl, XmNuserData, etDialog.formatW, NULL); XtAddCallback(etDialog.formatW, XmNvalueChangedCallback, formatChangedCB, NULL); XtVaGetValues(etDialog.formatW, XmNheight, &textHeight, NULL); XtVaSetValues(formatLbl, XmNheight, textHeight, NULL); previewFrame = XtVaCreateManagedWidget("previewFrame", xmFrameWidgetClass, etDialog.form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, selectFrame, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LEFT_MARGIN_POS, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, NULL); XtVaCreateManagedWidget("previewLabel", xmLabelGadgetClass, previewFrame, XmNlabelString, s1=XmStringCreateSimple("Preview"), XmNchildType, XmFRAME_TITLE_CHILD, XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING, NULL); XmStringFree(s1); previewForm = XtVaCreateManagedWidget("previewForm", xmFormWidgetClass, previewFrame, XmNleftAttachment, XmATTACH_FORM, XmNleftPosition, LEFT_MARGIN_POS, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, V_MARGIN, XmNrightAttachment, XmATTACH_FORM, XmNrightPosition, RIGHT_MARGIN_POS, NULL); /* Copy a variable width font from one of the labels to use for the preview (no editing is allowed, and with a fixed size font the preview easily gets partially obscured). Also copy the form background color to make it clear that this field is not editable */ XtVaGetValues(formatLbl, XmNfontList, &fontList, NULL); XtVaGetValues(previewForm, XmNbackground, &background, NULL); etDialog.previewW = XtVaCreateManagedWidget("sample", xmTextFieldWidgetClass, previewForm, XmNeditable, False, XmNcursorPositionVisible, False, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, V_MARGIN, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, V_MARGIN, XmNfontList, fontList, XmNbackground, background, NULL); previewBox = XtVaCreateManagedWidget("previewBox", xmFormWidgetClass, previewForm, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_TIGHT, XmNradioBehavior, False, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.previewW, NULL); testLbl = XtVaCreateManagedWidget("testLabel", xmLabelGadgetClass, previewBox, XmNlabelString, s1=XmStringCreateSimple("Test settings: "), XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LEFT_MARGIN_POS, XmNtopOffset, 5, XmNbottomOffset, 5, XmNtopAttachment, XmATTACH_FORM, NULL); XmStringFree(s1); etDialog.oFileChangedW = XtVaCreateManagedWidget("fileChanged", xmToggleButtonWidgetClass, previewBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, testLbl, XmNlabelString, s1=XmStringCreateSimple("File modified"), XmNmnemonic, 'o', NULL); XtAddCallback(etDialog.oFileChangedW, XmNvalueChangedCallback, fileChangedCB, NULL); XmStringFree(s1); etDialog.oFileReadOnlyW = XtVaCreateManagedWidget("fileReadOnly", xmToggleButtonWidgetClass, previewBox, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, etDialog.oFileChangedW, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, testLbl, XmNlabelString, s1=XmStringCreateSimple("File read only"), XmNmnemonic, 'n', NULL); XtAddCallback(etDialog.oFileReadOnlyW, XmNvalueChangedCallback, fileReadOnlyCB, NULL); XmStringFree(s1); etDialog.oFileLockedW = XtVaCreateManagedWidget("fileLocked", xmToggleButtonWidgetClass, previewBox, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, etDialog.oFileReadOnlyW, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, testLbl, XmNlabelString, s1=XmStringCreateSimple("File locked"), XmNmnemonic, 'l', NULL); XtAddCallback(etDialog.oFileLockedW, XmNvalueChangedCallback, fileLockedCB, NULL); XmStringFree(s1); etDialog.oServerNameW = XtVaCreateManagedWidget("servernameSet", xmToggleButtonWidgetClass, previewBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.oFileChangedW, XmNlabelString, s1=XmStringCreateSimple("Server name present"), XmNmnemonic, 'v', NULL); XtAddCallback(etDialog.oServerNameW, XmNvalueChangedCallback, serverNameCB, NULL); XmStringFree(s1); etDialog.oCcViewTagW = XtVaCreateManagedWidget("ccViewTagSet", xmToggleButtonWidgetClass, previewBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.oServerNameW, XmNlabelString, s1=XmStringCreateSimple("CC view tag present"), #ifdef VMS XmNset, False, #else XmNset, GetClearCaseViewTag() != NULL, #endif /* VMS */ XmNmnemonic, 'w', NULL); #ifdef VMS XtSetSensitive(etDialog.oCcViewTagW, False); #else XtAddCallback(etDialog.oCcViewTagW, XmNvalueChangedCallback, ccViewTagCB, NULL); #endif /* VMS */ XmStringFree(s1); etDialog.oServerEqualViewW = XtVaCreateManagedWidget("serverEqualView", xmToggleButtonWidgetClass, previewBox, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, etDialog.oCcViewTagW, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.oServerNameW, XmNlabelString, s1=XmStringCreateSimple("Server name equals CC view tag "), XmNmnemonic, 'q', NULL); #ifdef VMS XtSetSensitive(etDialog.oServerEqualViewW, False); #else XtAddCallback(etDialog.oServerEqualViewW, XmNvalueChangedCallback, serverEqualViewCB, NULL); #endif /* VMS */ XmStringFree(s1); etDialog.oDirW = XtVaCreateManagedWidget("pathSet", xmToggleButtonWidgetClass, previewBox, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, RADIO_INDENT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, etDialog.oCcViewTagW, XmNlabelString, s1=XmStringCreateSimple("Directory present"), XmNmnemonic, 'i', NULL); XtAddCallback(etDialog.oDirW, XmNvalueChangedCallback, formatChangedCB, NULL); XmStringFree(s1); /* Button box */ buttonForm = XtVaCreateManagedWidget("buttonForm", xmFormWidgetClass, etDialog.form, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, LEFT_MARGIN_POS, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, previewFrame, XmNtopOffset, V_MARGIN, XmNbottomOffset, V_MARGIN, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, RIGHT_MARGIN_POS, NULL); applyBtn = XtVaCreateManagedWidget("apply", xmPushButtonWidgetClass, buttonForm, XmNhighlightThickness, 2, XmNlabelString, s1=XmStringCreateSimple("Apply"), XmNshowAsDefault, (short)1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 6, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 25, XmNbottomAttachment, XmATTACH_FORM, NULL); XtAddCallback(applyBtn, XmNactivateCallback, applyCB, NULL); XmStringFree(s1); XtVaGetValues(applyBtn, XmNshadowThickness, &shadowThickness, NULL); defaultBtnOffset = shadowThickness + 4; closeBtn = XtVaCreateManagedWidget("close", xmPushButtonWidgetClass, buttonForm, XmNhighlightThickness, 2, XmNlabelString, s1=XmStringCreateSimple("Close"), XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 52, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 71, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, defaultBtnOffset, NULL); XtAddCallback(closeBtn, XmNactivateCallback, closeCB, NULL); XmStringFree(s1); restoreBtn = XtVaCreateManagedWidget("restore", xmPushButtonWidgetClass, buttonForm, XmNhighlightThickness, 2, XmNlabelString, s1=XmStringCreateSimple("Default"), XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 29, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 48, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, defaultBtnOffset, XmNmnemonic, 'e', NULL); XtAddCallback(restoreBtn, XmNactivateCallback, restoreCB, NULL); XmStringFree(s1); helpBtn = XtVaCreateManagedWidget("help", xmPushButtonWidgetClass, buttonForm, XmNhighlightThickness, 2, XmNlabelString, s1=XmStringCreateSimple("Help"), XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 75, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 94, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, defaultBtnOffset, XmNmnemonic, 'p', NULL); XtAddCallback(helpBtn, XmNactivateCallback, helpCB, NULL); XmStringFree(s1); /* Set initial default button */ XtVaSetValues(etDialog.form, XmNdefaultButton, applyBtn, NULL); XtVaSetValues(etDialog.form, XmNcancelButton, closeBtn, NULL); /* Handle mnemonic selection of buttons and focus to dialog */ AddDialogMnemonicHandler(etDialog.form, FALSE); etDialog.suppressFormatUpdate = FALSE; } void EditCustomTitleFormat(WindowInfo *window) { /* copy attributes from current window so that we can use as many * 'real world' defaults as possible when testing the effect * of different formatting strings. */ strcpy(etDialog.path, window->path); strcpy(etDialog.filename, window->filename); #ifndef VMS strcpy(etDialog.viewTag, GetClearCaseViewTag() != NULL ? GetClearCaseViewTag() : "viewtag"); #endif /* VMS */ strcpy(etDialog.serverName, IsServer ? GetPrefServerName() : "servername"); etDialog.isServer = IsServer; etDialog.filenameSet = window->filenameSet; etDialog.lockReasons = window->lockReasons; etDialog.fileChanged = window->fileChanged; if (etDialog.window != window && etDialog.form) { /* Destroy the dialog owned by the other window. Note: don't rely on the destroy event handler to reset the form. Events are handled asynchronously, so the old dialog may continue to live for a while. */ XtDestroyWidget(etDialog.form); etDialog.form = NULL; } etDialog.window = window; /* Create the dialog if it doesn't already exist */ if (etDialog.form == NULL) { createEditTitleDialog(window->shell); } else { /* If the window is already up, just pop it to the top */ if (XtIsManaged(etDialog.form)) { RaiseDialogWindow(XtParent(etDialog.form)); /* force update of the dialog */ setToggleButtons(); formatChangedCB(0, 0, 0); return; } } /* set initial value of format field */ XmTextSetString(etDialog.formatW, (char *)GetPrefTitleFormat()); /* force update of the dialog */ setToggleButtons(); formatChangedCB(0, 0, 0); /* put up dialog and wait for user to press ok or cancel */ ManageDialogCenteredOnPointer(etDialog.form); } nedit-5.6.orig/source/windowTitle.h0000644000175000017500000000551410144236625016104 0ustar paulpaul/* $Id: windowTitle.h,v 1.5 2004/11/09 21:58:45 yooden Exp $ */ /******************************************************************************* * * * windowTitle.h -- Nirvana Editor window title customization * * * * Copyright (C) 2001, Arne Forlie * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * * Written by Arne Forlie, http://arne.forlie.com * * * *******************************************************************************/ #ifndef NEDIT_WINDOWTITLE_H_INCLUDED #define NEDIT_WINDOWTITLE_H_INCLUDED #include "nedit.h" #include char *FormatWindowTitle(const char* filename, const char* path, const char* clearCaseViewTag, const char* serverName, int isServer, int filenameSet, int lockReasons, int fileChanged, const char* titleFormat); void EditCustomTitleFormat(WindowInfo *window); #endif /* NEDIT_WINDOWTITLE_H_INCLUDED */ nedit-5.6.orig/util/0000755000175000017500000000000011107644430013067 5ustar paulpaulnedit-5.6.orig/util/DialogF.c0000644000175000017500000006364510735251367014567 0ustar paulpaulstatic const char CVSID[] = "$Id: DialogF.c,v 1.32 2007/12/28 19:48:07 yooden Exp $"; /******************************************************************************* * * * DialogF -- modal dialog printf routine * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * April 26, 1991 * * * * Written by Joy Kyriakopulos * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "DialogF.h" #include "misc.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #define NUM_DIALOGS_SUPPORTED 6 #define NUM_BUTTONS_SUPPORTED 3 /* except prompt dialog */ #define NUM_BUTTONS_MAXPROMPT 4 #define MAX_TITLE_LEN 256 enum dialogBtnIndecies {OK_BTN, APPLY_BTN, CANCEL_BTN, HELP_BTN}; struct dfcallbackstruct { unsigned button; /* button pressed by user */ Boolean done_with_dialog; /* set by callbacks; dialog can be destroyed */ unsigned apply_up; /* will = 1 when apply button managed */ Boolean destroyed; /* set when dialog is destroyed unexpectedly */ }; static char **PromptHistory = NULL; static int NPromptHistoryItems = -1; static void apply_callback (Widget w, struct dfcallbackstruct *client_data, caddr_t call_data); static void help_callback (Widget w, struct dfcallbackstruct *client_data, caddr_t call_data); static void cancel_callback (Widget w, struct dfcallbackstruct *client_data, caddr_t call_data); static void ok_callback (Widget w, struct dfcallbackstruct *client_data, caddr_t call_data); static void destroy_callback (Widget w, struct dfcallbackstruct *client_data, caddr_t call_data); static void focusCB(Widget w, Widget dialog, caddr_t call_data); static void addEscapeHandler(Widget dialog, struct dfcallbackstruct *df, int whichBtn); static void escapeHelpCB(Widget w, XtPointer callData, XEvent *event, Boolean *cont); static void escapeApplyCB(Widget w, XtPointer callData, XEvent *event, Boolean *cont); static void createMnemonics(Widget w); /******************************************************************************* * DialogF() * * * * function to put up modal versions of the XmCreateDialog functions * * (where is Error, Information, Prompt, Question, Message, or Warning). * * The purpose of this routine is to allow a printf-style dialog box to be * * invoked in-line without giving control back to the main loop. The message * * string can contain vsprintf specifications. * * DialogF displays the dialog in application-modal style, blocking the * * application and keeping the modal dialog as the top window until the user * * responds. DialogF accepts a variable number of arguments, so the calling * * routine needs to #include . The first button is automatically * * marked as the default button (activated when the user types Return, * * surrounded by a special outline), and any button named either Cancel, or * * Dismiss is marked as the cancel button (activated by the ESC key). Buttons * * marked Dismiss or Cancel are also triggered by close of dialog via the * * window close box. If there's no Cancel or Dismiss button, button 1 is * * invoked when the close box is pressed. * * * * Arguments: * * * * unsigned dialog_type dialog type (e.g. DF_ERR for error dialog, refer to * * DialogF.h for dialog type values) * * Widget parent parent widget ID * * unsigned n # of buttons to display; if set to 0, use defaults in * * XmCreateDialog; value in range 0 to * * NUM_BUTTONS_SUPPORTED (for prompt dialogs: * * NUM_BUTTONS_MAXPROMPT) * * char* title dialog title * * char* msgstr message string (may contain conversion specifications * * for vsprintf) * * char* input_string if dialog type = DF_PROMPT, then: a character string * * array in which to put the string input by the user. Do * * NOT include an input_string argument for other dialog * * types. * * char* but_lbl button label(s) for buttons requested (if n > 0, one * * but_lbl argument per button) * * arguments for vsprintf (if any) * * * * * * Returns: * * * * button selected by user (i.e. 1, 2, or 3. or 4 for prompt) * * * * * * Examples: * * * * but_pressed = DialogF (DF_QUES, toplevel, 3, "Direction?", "up", * * "down", "other"); * * but_pressed = DialogF (DF_ERR, toplevel, 1, "You can't do that!", * * "Acknowledged"); * * but_pressed = DialogF (DF_PROMPT, toplevel, 0, "New %s", * * new_sub_category, categories[i]); * */ unsigned DialogF(int dialog_type, Widget parent, unsigned n, const char* title, const char* msgstr, ...) /* variable # arguments */ { va_list var; Widget dialog, dialog_shell; unsigned dialog_num, prompt; XmString but_lbl_xms[NUM_BUTTONS_MAXPROMPT]; XmString msgstr_xms, input_string_xms, titstr_xms; char msgstr_vsp[DF_MAX_MSG_LENGTH+1]; char *but_lbl, *input_string = NULL, *input_string_ptr; int argcount, num_but_lbls = 0, i, but_index, cancel_index = -1; Arg args[256]; char titleCopy[MAX_TITLE_LEN]; struct dfcallbackstruct df; static int dialog_types[] = { /* Supported dialog types */ XmDIALOG_ERROR, XmDIALOG_INFORMATION, XmDIALOG_MESSAGE, XmDIALOG_QUESTION, XmDIALOG_WARNING, XmDIALOG_PROMPT }; static char *dialog_name[] = { /* Corresponding dialog names */ "Error", "Information", "Message", "Question", "Warning", "Prompt" }; static unsigned char selectionButton_id[] = { XmDIALOG_OK_BUTTON, XmDIALOG_APPLY_BUTTON, XmDIALOG_CANCEL_BUTTON, XmDIALOG_HELP_BUTTON }; Cardinal N_SELECTION_BUTTONS = XtNumber(selectionButton_id); static unsigned char messageButton_id[] = { XmDIALOG_OK_BUTTON, XmDIALOG_CANCEL_BUTTON, XmDIALOG_HELP_BUTTON }; Cardinal N_MESSAGE_BUTTONS = XtNumber(messageButton_id); static char *button_name[] = { /* Motif button names */ XmNokLabelString, XmNapplyLabelString, /* button #2, if managed */ XmNcancelLabelString, XmNhelpLabelString }; /* Validate input parameters */ if ((dialog_type > NUM_DIALOGS_SUPPORTED) || (dialog_type <= 0)) { printf ("\nError calling DialogF - Unsupported dialog type\n"); return (0); } dialog_num = dialog_type - 1; prompt = (dialog_type == DF_PROMPT); if ((!prompt && (n > NUM_BUTTONS_SUPPORTED)) || (prompt && (n > NUM_BUTTONS_MAXPROMPT))) { printf ("\nError calling DialogF - Too many buttons specified\n"); return (0); } df.done_with_dialog = False; df.destroyed = False; va_start (var, msgstr); if (prompt) { /* Get where to put dialog input string */ input_string = va_arg(var, char*); } if (n == NUM_BUTTONS_MAXPROMPT) df.apply_up = 1; /* Apply button will be managed */ else df.apply_up = 0; /* Apply button will not be managed */ for (argcount = 0; argcount < (int)n; ++argcount) { /* Set up button labels */ but_lbl = va_arg(var, char *); but_lbl_xms[num_but_lbls] = XmStringCreateLtoR (but_lbl, XmSTRING_DEFAULT_CHARSET); but_index = df.apply_up ? argcount : ((argcount == 0) ? argcount : argcount+1); XtSetArg (args[argcount], button_name[but_index], but_lbl_xms[num_but_lbls++]); if (!strcmp(but_lbl, "Cancel") || !strcmp(but_lbl, "Dismiss")) cancel_index = but_index; } if (n == 1) cancel_index = 0; /* Get & translate msg string. NOTE: the use of vsprintf is inherently dangerous because there is no way to control the length of the written string. vnsprintf isn't available on all platforms, unfortunately. Therefore we have to make sure that msgstr_vsp is large enough such that it cannot overflow under any circumstances (within the context of any DialogF call). A necessary condition is that it can at least hold one file name (MAXPATHLEN). Therefore, DF_MAX_MSG_LENGTH must be sufficiently larger than MAXPATHLEN. */ vsprintf (msgstr_vsp, msgstr, var); va_end(var); strncpy(&titleCopy[0], title, MAX_TITLE_LEN); titleCopy[MAX_TITLE_LEN-1] = '\0'; msgstr_xms = XmStringCreateLtoR(msgstr_vsp, XmSTRING_DEFAULT_CHARSET); titstr_xms = XmStringCreateLtoR(titleCopy, XmSTRING_DEFAULT_CHARSET); if (prompt) { /* Prompt dialog */ XtSetArg (args[argcount], XmNselectionLabelString, msgstr_xms); argcount++; XtSetArg (args[argcount], XmNdialogTitle, titstr_xms); argcount++; XtSetArg (args[argcount], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); argcount ++; dialog = CreatePromptDialog(parent, dialog_name[dialog_num], args, argcount); XtAddCallback (dialog, XmNokCallback, (XtCallbackProc)ok_callback, (char *)&df); XtAddCallback (dialog, XmNcancelCallback, (XtCallbackProc)cancel_callback, (char *)&df); XtAddCallback (dialog, XmNhelpCallback, (XtCallbackProc)help_callback, (char *)&df); XtAddCallback (dialog, XmNapplyCallback, (XtCallbackProc)apply_callback, (char *)&df); RemapDeleteKey(XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT)); /* Text area in prompt dialog should get focus, not ok button since user enters text first. To fix this, we need to turn off the default button for the dialog, until after keyboard focus has been established */ XtVaSetValues(dialog, XmNdefaultButton, NULL, NULL); XtAddCallback(XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT), XmNfocusCallback, (XtCallbackProc)focusCB, (char *)dialog); /* Limit the length of the text that can be entered in text field */ XtVaSetValues(XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT), XmNmaxLength, DF_MAX_PROMPT_LENGTH-1, NULL); /* Turn on the requested number of buttons in the dialog by managing/unmanaging the button widgets */ switch (n) { /* number of buttons requested */ case 0: case 3: break; /* or default of 3 buttons */ case 1: XtUnmanageChild (XmSelectionBoxGetChild (dialog, XmDIALOG_CANCEL_BUTTON) ); case 2: XtUnmanageChild (XmSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON) ); break; case 4: XtManageChild (XmSelectionBoxGetChild (dialog, XmDIALOG_APPLY_BUTTON) ); df.apply_up = 1; /* apply button managed */ default: break; } /* end switch */ /* Set margin width to managed buttons. */ for (i = 0; (unsigned) i < N_SELECTION_BUTTONS; i++) { Widget button = XmSelectionBoxGetChild(dialog, selectionButton_id[i]); if (XtIsManaged(button)) { XtVaSetValues(button, XmNmarginWidth, BUTTON_WIDTH_MARGIN, NULL); } } /* If the button labeled cancel or dismiss is not the cancel button, or if there is no button labeled cancel or dismiss, redirect escape key events (this is necessary because the XmNcancelButton resource in the bulletin board widget class is blocked from being reset) */ if (cancel_index == -1) addEscapeHandler(dialog, NULL, 0); else if (cancel_index != CANCEL_BTN) addEscapeHandler(dialog, &df, cancel_index); /* Add a callback to the window manager close callback for the dialog */ AddMotifCloseCallback(XtParent(dialog), (XtCallbackProc)(cancel_index == APPLY_BTN ? apply_callback : (cancel_index == CANCEL_BTN ? cancel_callback : (cancel_index == HELP_BTN ? help_callback : ok_callback))), &df); /* Also add a callback to detect unexpected destruction (eg, because the parent window is destroyed) */ XtAddCallback(dialog, XmNdestroyCallback, (XtCallbackProc)destroy_callback, &df); /* A previous call to SetDialogFPromptHistory can request that an up-arrow history-recall mechanism be attached. If so, do it here */ if (NPromptHistoryItems != -1) AddHistoryToTextWidget(XmSelectionBoxGetChild(dialog,XmDIALOG_TEXT), &PromptHistory, &NPromptHistoryItems); /* Pop up the dialog */ ManageDialogCenteredOnPointer(dialog); /* Get the focus to the input string. There is some timing problem within Motif that requires this to be called several times */ for (i=0; i<20; i++) XmProcessTraversal(XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT), XmTRAVERSE_CURRENT); /* Wait for a response to the dialog */ while (!df.done_with_dialog && !df.destroyed) XtAppProcessEvent (XtWidgetToApplicationContext(dialog), XtIMAll); if (!df.destroyed) { argcount = 0; /* Pass back string user entered */ XtSetArg (args[argcount], XmNtextString, &input_string_xms); argcount++; XtGetValues (dialog, args, argcount); XmStringGetLtoR (input_string_xms, XmSTRING_DEFAULT_CHARSET, &input_string_ptr); strcpy (input_string, input_string_ptr); /* This step is necessary */ XmStringFree(input_string_xms ); XtFree(input_string_ptr); /* Important! Only intercept unexpected destroy events. */ XtRemoveCallback(dialog, XmNdestroyCallback, (XtCallbackProc)destroy_callback, &df); XtDestroyWidget(dialog); } PromptHistory = NULL; NPromptHistoryItems = -1; } /* End prompt dialog path */ else { /* MessageBox dialogs */ XtSetArg (args[argcount], XmNmessageString, msgstr_xms); argcount++; XtSetArg (args[argcount], XmNdialogType, dialog_types[dialog_num]); argcount ++; XtSetArg (args[argcount], XmNdialogTitle, titstr_xms); argcount++; XtSetArg (args[argcount], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); argcount ++; dialog_shell = CreateDialogShell (parent, dialog_name[dialog_num], 0, 0); dialog = XmCreateMessageBox (dialog_shell, "msg box", args, argcount); XtAddCallback (dialog, XmNokCallback, (XtCallbackProc)ok_callback, (char *)&df); XtAddCallback (dialog, XmNcancelCallback, (XtCallbackProc)cancel_callback, (char *)&df); XtAddCallback (dialog, XmNhelpCallback, (XtCallbackProc)help_callback, (char *)&df); /* Make extraneous buttons disappear */ switch (n) { /* n = number of buttons requested */ case 0: case 3: break; /* default (0) gets you 3 buttons */ case 1: XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_CANCEL_BUTTON) ); case 2: XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON) ); break; default: break; } /* Set margin width to managed buttons. */ for (i = 0; (unsigned) i < N_MESSAGE_BUTTONS; i++) { Widget button = XmMessageBoxGetChild(dialog, messageButton_id[i]); if (XtIsManaged(button)) { XtVaSetValues(button, XmNmarginWidth, BUTTON_WIDTH_MARGIN, NULL); } } /* Try to create some sensible default mnemonics */ createMnemonics(dialog_shell); AddDialogMnemonicHandler(dialog_shell, TRUE); /* If the button labeled cancel or dismiss is not the cancel button, or if there is no button labeled cancel or dismiss, redirect escape key events (this is necessary because the XmNcancelButton resource in the bulletin board widget class is blocked from being reset) */ if (cancel_index == -1) addEscapeHandler(dialog, NULL, 0); else if (cancel_index != CANCEL_BTN) addEscapeHandler(dialog, &df, cancel_index); /* Add a callback to the window manager close callback for the dialog */ AddMotifCloseCallback(XtParent(dialog), (XtCallbackProc)(cancel_index == APPLY_BTN ? apply_callback : (cancel_index == CANCEL_BTN ? cancel_callback : (cancel_index == HELP_BTN ? help_callback : ok_callback))),&df); /* Also add a callback to detect unexpected destruction (eg, because the parent window is destroyed) */ XtAddCallback(dialog_shell, XmNdestroyCallback, (XtCallbackProc)destroy_callback, &df); /* Pop up the dialog, wait for response*/ ManageDialogCenteredOnPointer(dialog); while (!df.done_with_dialog && !df.destroyed) XtAppProcessEvent (XtWidgetToApplicationContext(dialog), XtIMAll); if (!df.destroyed) { /* Important! Only intercept unexpected destroy events. */ XtRemoveCallback(dialog_shell, XmNdestroyCallback, (XtCallbackProc)destroy_callback, &df); XtDestroyWidget(dialog_shell); } } XmStringFree(msgstr_xms); XmStringFree(titstr_xms); for (i = 0; i < num_but_lbls; ++i) XmStringFree(but_lbl_xms[i]); /* If the dialog was destroyed unexpectedly, the button was not set yet, so we must set the index of the cancel button. */ if (df.destroyed) { df.button = cancel_index == APPLY_BTN ? 2 : (cancel_index == CANCEL_BTN ? 2 + df.apply_up : (cancel_index == HELP_BTN ? 3 + df.apply_up : 1)); } df.apply_up = 0; /* default is apply button unmanaged */ return (df.button); } /* ** Add up-arrow history recall to the next DialogF(DF_PROMPT... call (see ** AddHistoryToTextWidget in misc.c). This must be re-set before each call. ** calling DialogF with a dialog type of DF_PROMPT automatically resets ** this mode back to no-history-recall. */ void SetDialogFPromptHistory(char **historyList, int nItems) { PromptHistory = historyList; NPromptHistoryItems = nItems; } static void ok_callback (Widget w, struct dfcallbackstruct *client_data, caddr_t call_data) { client_data->done_with_dialog = True; client_data->button = 1; /* Return Button number pressed */ } static void cancel_callback (Widget w, struct dfcallbackstruct *client_data, caddr_t call_data) { client_data->done_with_dialog = True; client_data->button = 2 + client_data->apply_up; /* =3 if apply button managed */ } static void help_callback (Widget w, struct dfcallbackstruct *client_data, caddr_t call_data) { client_data->done_with_dialog = True; client_data->button = 3 + client_data->apply_up; /* =4 if apply button managed */ } static void apply_callback (Widget w, struct dfcallbackstruct *client_data, caddr_t call_data) { client_data->done_with_dialog = True; client_data->button = 2; /* Motif puts between OK and cancel */ } static void destroy_callback (Widget w, struct dfcallbackstruct *client_data, caddr_t call_data) { client_data->destroyed = True; } /* ** callback for returning default button status to the ok button once we're ** sure the text area in the prompt dialog has input focus. */ static void focusCB(Widget w, Widget dialog, caddr_t call_data) { XtVaSetValues(dialog, XmNdefaultButton, XmSelectionBoxGetChild(dialog, XmDIALOG_OK_BUTTON), NULL); } /* ** Message and prompt dialogs hardwire the cancel button to the XmNcancelButton ** resource in the bulletin board dialog. Since we rename the buttons, the ** cancel label may not be on the dialog's idea of the Cancel button. The only ** way to make the accelerator for Cancel and Dismiss (the escape key) work ** correctly in this situation is to brutally catch and redirect the event. ** This routine redirects escape key events in the dialog to the callback for ** the button "whichBtn", passing it argument "df". If "df" is NULL, simply ** block the event from reaching the dialog. */ static void addEscapeHandler(Widget dialog, struct dfcallbackstruct *df, int whichBtn) { XtAddEventHandler(dialog, KeyPressMask, False, whichBtn == APPLY_BTN ? escapeApplyCB : escapeHelpCB, (XtPointer)df); XtGrabKey(dialog, XKeysymToKeycode(XtDisplay(dialog), XK_Escape), 0, True, GrabModeAsync, GrabModeAsync); } /* ** Event handler for escape key to redirect the event to the help button. ** Attached when cancel label appears on Help button. */ static void escapeHelpCB(Widget w, XtPointer callData, XEvent *event, Boolean *cont) { if (event->xkey.keycode != XKeysymToKeycode(XtDisplay(w), XK_Escape)) return; if (callData != NULL) help_callback(w, (struct dfcallbackstruct *)callData, NULL); *cont = False; } /* ** Event handler for escape key to redirect event to the apply button. ** Attached when cancel label appears on Apply button. */ static void escapeApplyCB(Widget w, XtPointer callData, XEvent *event, Boolean *cont) { if (event->xkey.keycode != XKeysymToKeycode(XtDisplay(w), XK_Escape)) return; if (callData != NULL) apply_callback(w, (struct dfcallbackstruct *)callData, NULL); *cont = False; } /* ** Only used by createMnemonics(Widget w) */ static void recurseCreateMnemonics(Widget w, Boolean *mnemonicUsed) { WidgetList children; Cardinal numChildren, i; XtVaGetValues(w, XmNchildren, &children, XmNnumChildren, &numChildren, NULL); for (i = 0; i < numChildren; i++) { Widget child = children[i]; if (XtIsComposite(child)) { recurseCreateMnemonics(child, mnemonicUsed); } else if (XtIsSubclass(child, xmPushButtonWidgetClass) || XtIsSubclass(child, xmPushButtonGadgetClass)) { XmString xmslabel; char *label; int c; XtVaGetValues(child, XmNlabelString, &xmslabel, NULL); if (XmStringGetLtoR(xmslabel, XmSTRING_DEFAULT_CHARSET, &label)) { /* Scan through the string to see if the label is already used */ int labelLen = strlen(label); for (c = 0; c < labelLen; c++) { unsigned char lc = tolower((unsigned char)label[c]); if (!mnemonicUsed[lc] && isalnum(lc)) { mnemonicUsed[lc] = TRUE; XtVaSetValues(child, XmNmnemonic, label[c], NULL); break; } } XtFree(label); } XmStringFree(xmslabel); } } } /* ** Automatically create mnemonics for a widget. Traverse all it's ** children. If the child is a push button, snag the first unused letter ** and make that the mnemonic. This is useful for DialogF dialogs which ** can have arbitrary text in the buttons. */ static void createMnemonics(Widget w) { Boolean mnemonicUsed[UCHAR_MAX + 1]; memset(mnemonicUsed, FALSE, sizeof mnemonicUsed / sizeof *mnemonicUsed); recurseCreateMnemonics(w, mnemonicUsed); } nedit-5.6.orig/util/DialogF.h0000644000175000017500000000615510144236625014557 0ustar paulpaul/* $Id: DialogF.h,v 1.11 2004/11/09 21:58:45 yooden Exp $ */ /******************************************************************************* * * * DialogF.h -- Nirvana Editor Dialog Header File * * * * Copyright 2003 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_DIALOGF_H_INCLUDED #define NEDIT_DIALOGF_H_INCLUDED #include #ifdef VMS #include "../util/VMSparam.h" #else #ifndef __MVS__ #include #endif #endif /*VMS*/ #define DF_ERR 1 /* Error Dialog */ #define DF_INF 2 /* Information Dialog */ #define DF_MSG 3 /* Message Dialog */ #define DF_QUES 4 /* Question Dialog */ #define DF_WARN 5 /* Warning Dialog */ #define DF_PROMPT 6 /* Prompt Dialog */ /* longest message length supported. Note that dialogs may contains a file name, which is only limited in length by MAXPATHLEN, so DF_MAX_MSG_LENGTH must be sufficiently larger than MAXPATHLEN. */ #define DF_MAX_MSG_LENGTH (2047 + MAXPATHLEN) #define DF_MAX_PROMPT_LENGTH 255 /* longest prompt string supported */ unsigned DialogF(int dialog_type, Widget parent, unsigned n, const char* title, const char* msgstr, ...); /* variable # arguments */ void SetDialogFPromptHistory(char **historyList, int nItems); #endif /* NEDIT_DIALOGF_H_INCLUDED */ nedit-5.6.orig/util/Makefile.common0000644000175000017500000000204510203260621016007 0ustar paulpaul# $Id: Makefile.common,v 1.9 2005/02/12 01:53:21 tringali Exp $ # # Platform independent part of make procedure for Nirvana utilities directory, # included by machine specific makefiles. # OBJS = DialogF.o getfiles.o printUtils.o misc.o fileUtils.o \ prefFile.o fontsel.o managedList.o utils.o clearcase.o motif.o all: libNUtil.a libNUtil.a: $(OBJS) $(AR) $(ARFLAGS) libNUtil.a $(OBJS) printUtils.o: printUtils.c $(CC) -c $(CFLAGS) $(PRINTFLAGS) printUtils.c # This is for any platform where bogus OpenMotif or LessTif versions might # be found in the wild. The rule needs a different name from the executable # so that the rule continues to fire if the executable exists. Note that we # do not cache the .o file - this is so if the build fails, you can jump # and retry on another system without worrying that it will be different. check_tif_rule: motif.o $(CC) $(CFLAGS) -o check_lin_tif check_lin_tif.c motif.c ./check_lin_tif clean: rm -f $(OBJS) libNUtil.a check_lin_tif # Get the dependencies for all objects include Makefile.dependencies nedit-5.6.orig/util/Makefile.dependencies0000644000175000017500000000103207654533211017156 0ustar paulpaul# $Id: Makefile.dependencies,v 1.7 2003/05/02 18:18:49 edg Exp $ DialogF.o: DialogF.c DialogF.h misc.h clearcase.o: clearcase.c clearcase.h fileUtils.o: fileUtils.c fileUtils.h utils.h fontsel.o: fontsel.c fontsel.h misc.h DialogF.h getfiles.o: getfiles.c getfiles.h fileUtils.h misc.h managedList.o: managedList.c managedList.h misc.h misc.o: misc.c misc.h DialogF.h prefFile.o: prefFile.c prefFile.h fileUtils.h utils.h printUtils.o: printUtils.c printUtils.h DialogF.h misc.h prefFile.h utils.o: utils.c utils.h vmsUtils.o: vmsUtils.c nedit-5.6.orig/util/check_lin_tif.c0000644000175000017500000001500410342675756016033 0ustar paulpaul/******************************************************************************* * * * verifyMotif: A small test program to detect bad versions of LessTif and * * Open Motif. Written on linux but should be portable. * * * * Copyright (C) 2003 Nathaniel Gray * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 28, 1992 * * * * Written by Nathaniel Gray * * * * Modifications by: * * Scott Tringali * * * *******************************************************************************/ #include #include "motif.h" #include #include /* Print out a message listing the known-good versions */ static void showGoodVersions(void) { fputs("\nNEdit is known to work with Motif versions:\n", stderr); fputs(GetMotifStableVersions(), stderr); fputs( "OpenMotif is available from:\n" "\thttp://www.opengroup.org/openmotif/\n" "\thttp://www.ist.co.uk/DOWNLOADS/motif_download.html\n" "\nAlso, unless you need a customized NEdit you should STRONGLY\n" "consider downloading a pre-built binary from http://www.nedit.org,\n" "since these are the most stable versions.\n", stderr); } /* ** Main test driver. Check the stability, and allow overrides if needed. */ int main(int argc, const char *argv[]) { enum MotifStability stability = GetMotifStability(); if (stability == MotifKnownGood) return EXIT_SUCCESS; if (stability == MotifKnownBad) { fprintf(stderr, "ERROR: Bad Motif Version:\n\t%s\n", XmVERSION_STRING); fprintf(stderr, "\nThis version of Motif is known to be broken and is\n" "thus unsupported by the NEdit developers. It will probably\n" "cause NEdit to crash frequently. Check these pages for a more\n" "detailed description of the problems with this version:\n" "\thttp://www.motifdeveloper.com/tips/tip22.html\n" "\thttp://www.motifdeveloper.com/tips/Motif22Review.pdf\n"); #ifdef BUILD_BROKEN_NEDIT { char buf[2]; fprintf(stderr, "\n========================== WARNING ===========================\n" "You have chosen to build NEdit with a known-bad version of Motif,\n" "risking instability and probable data loss. You are very brave!\n" "Please do not report bugs to the NEdit developers unless you can\n" "reproduce them with a known-good NEdit binary downloaded from:\n" "\thttp://www.nedit.org\n" "\nHIT ENTER TO CONTINUE\n"); fgets(buf, 2, stdin); return EXIT_SUCCESS; } #else showGoodVersions(); fprintf(stderr, "\nIf you really want to build a known-bad version of NEdit you\n" "can override this sanity check by adding -DBUILD_BROKEN_NEDIT\n" "to the CFLAGS variable in your platform's Makefile (e.g.\n" "makefiles/Makefile.linux)\n"); #endif } if (stability == MotifUnknown) { /* This version is neither known-good nor known-bad */ fprintf(stderr, "ERROR: Untested Motif Version:\n\t%s\n", XmVERSION_STRING); fprintf(stderr, "You are attempting to build NEdit with a version of Motif that\n" "has not been verified to work well with NEdit. This could be fine,\n" "but it could also lead to crashes and instability. Historically, \n" "older versions of Motif have quite often been more stable\n" "than newer versions when used with NEdit, so don't assume newer\n" "is better.\n"); #ifdef BUILD_UNTESTED_NEDIT { char buf[2]; fprintf(stderr, "\n========================== WARNING ===========================\n" "You have chosen to build NEdit with an untested version of Motif.\n" "Please report your success or failure with this version to:\n" "\tdevelop@nedit.org\n" "\nHIT ENTER TO CONTINUE\n"); fgets(buf, 2, stdin); return EXIT_SUCCESS; } #else showGoodVersions(); fprintf(stderr, "\nIf you really want to build an untested version of NEdit you\n" "can override this sanity check by adding -DBUILD_UNTESTED_NEDIT\n" "to the CFLAGS variable in your platform's Makefile (e.g.\n" "makefiles/Makefile.linux)\n"); #endif } return EXIT_FAILURE; } nedit-5.6.orig/util/clearcase.c0000644000175000017500000000621610144236625015165 0ustar paulpaulstatic const char CVSID[] = "$Id: clearcase.c,v 1.6 2004/11/09 21:58:45 yooden Exp $"; /******************************************************************************* * * * clearcase.c -- Nirvana Editor ClearCase support utilities * * * * Copyright (C) 2001 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * March, 2001 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "clearcase.h" #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif static int ClearCaseViewTagFound = 0; static char *ClearCaseViewRoot = NULL; static const char *ClearCaseViewTag = NULL; const char* GetClearCaseVersionExtendedPath(const char* fullname) { return(strstr(fullname, "@@/")); } /* ** Return a string showing the ClearCase view tag. If ClearCase is not in ** use, or a view is not set, NULL is returned. ** ** If user has ClearCase and is in a view, CLEARCASE_ROOT will be set and ** the view tag can be extracted. This check is safe and efficient enough ** that it doesn't impact non-clearcase users, so it is not conditionally ** compiled. (Thanks to Max Vohlken) */ const char *GetClearCaseViewTag(void) { if (!ClearCaseViewTagFound) { /* Extract the view name from the CLEARCASE_ROOT environment variable */ const char *envPtr = getenv("CLEARCASE_ROOT"); if (envPtr != NULL) { const char *tagPtr; ClearCaseViewRoot = XtMalloc(strlen(envPtr) + 1); strcpy(ClearCaseViewRoot, envPtr); tagPtr = strrchr(ClearCaseViewRoot, '/'); if (tagPtr != NULL) { ClearCaseViewTag = ++tagPtr; } } } /* If we don't find it first time, we will never find it, so may just as * well say that we have found it. */ ClearCaseViewTagFound = 1; return(ClearCaseViewTag); } nedit-5.6.orig/util/clearcase.h0000644000175000017500000000440210144236625015165 0ustar paulpaul/* $Id: clearcase.h,v 1.5 2004/11/09 21:58:45 yooden Exp $ */ /******************************************************************************* * * * clearcase.h -- Nirvana Editor Clearcase Header File * * * * Copyright 2002 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_CLEARCASE_H_INCLUDED #define NEDIT_CLEARCASE_H_INCLUDED const char* GetClearCaseVersionExtendedPath(const char* fullname); const char *GetClearCaseViewTag(void); #endif /* NEDIT_CLEARCASE_H_INCLUDED */ nedit-5.6.orig/util/fileUtils.c0000644000175000017500000004632011053030337015173 0ustar paulpaulstatic const char CVSID[] = "$Id: fileUtils.c,v 1.35 2008/08/20 14:57:35 lebert Exp $"; /******************************************************************************* * * * fileUtils.c -- File utilities for Nirvana applications * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 28, 1992 * * * * Written by Mark Edel * * * * Modified by: DMR - Ported to VMS (1st stage for Histo-Scope) * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "fileUtils.h" #include "utils.h" #include #include #include #include #include #ifdef VAXC #define NULL (void *) 0 #endif /*VAXC*/ #ifdef VMS #include "vmsparam.h" #include #else #include #ifndef __MVS__ #include #endif #include #include #include #endif /*VMS*/ #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #ifndef MAXSYMLINKS /* should be defined in */ #define MAXSYMLINKS 20 #endif #define TRUE 1 #define FALSE 0 /* Parameters to algorithm used to auto-detect DOS format files. NEdit will scan up to the lesser of FORMAT_SAMPLE_LINES lines and FORMAT_SAMPLE_CHARS characters of the beginning of the file, checking that all newlines are paired with carriage returns. If even a single counterexample exists, the file is judged to be in Unix format. */ #define FORMAT_SAMPLE_LINES 5 #define FORMAT_SAMPLE_CHARS 2000 static char *nextSlash(char *ptr); static char *prevSlash(char *ptr); static int compareThruSlash(const char *string1, const char *string2); static void copyThruSlash(char **toString, char **fromString); /* ** Decompose a Unix file name into a file name and a path. ** Return non-zero value if it fails, zero else. ** For now we assume that filename and pathname are at ** least MAXPATHLEN chars long. ** To skip setting filename or pathname pass NULL for that argument. */ int ParseFilename(const char *fullname, char *filename, char *pathname) { int fullLen = strlen(fullname); int i, pathLen, fileLen; #ifdef VMS /* find the last ] or : */ for (i=fullLen-1; i>=0; i--) { if (fullname[i] == ']' || fullname[i] == ':') break; } #else /* UNIX */ char *viewExtendPath; int scanStart; /* For clearcase version extended paths, slash characters after the "@@/" should be considered part of the file name, rather than the path */ if ((viewExtendPath = strstr(fullname, "@@/")) != NULL) scanStart = viewExtendPath - fullname - 1; else scanStart = fullLen - 1; /* find the last slash */ for (i=scanStart; i>=0; i--) { if (fullname[i] == '/') break; } #endif /* move chars before / (or ] or :) into pathname,& after into filename */ pathLen = i + 1; fileLen = fullLen - pathLen; if (pathname) { if (pathLen >= MAXPATHLEN) { return 1; } strncpy(pathname, fullname, pathLen); pathname[pathLen] = 0; } if (filename) { if (fileLen >= MAXPATHLEN) { return 2; } strncpy(filename, &fullname[pathLen], fileLen); filename[fileLen] = 0; } #ifndef VMS /* UNIX specific... Modify at a later date for VMS */ if(pathname) { if (NormalizePathname(pathname)) { return 1; /* pathname too long */ } pathLen = strlen(pathname); } #endif if (filename && pathname && ((pathLen + 1 + fileLen) >= MAXPATHLEN)) { return 1; /* pathname + filename too long */ } return 0; } #ifndef VMS /* ** Expand tilde characters which begin file names as done by the shell ** If it doesn't work just out leave pathname unmodified. ** This implementation is neither fast, nor elegant, nor ... */ int ExpandTilde(char *pathname) { struct passwd *passwdEntry; char username[MAXPATHLEN], temp[MAXPATHLEN]; char *nameEnd; unsigned len_left; if (pathname[0] != '~') return TRUE; nameEnd = strchr(&pathname[1], '/'); if (nameEnd == NULL) { nameEnd = pathname + strlen(pathname); } strncpy(username, &pathname[1], nameEnd - &pathname[1]); username[nameEnd - &pathname[1]] = '\0'; /* We might consider to re-use the GetHomeDir() function, but to keep the code more similar for both cases ... */ if (username[0] == '\0') { passwdEntry = getpwuid(getuid()); if ((passwdEntry == NULL) || (*(passwdEntry->pw_dir)== '\0')) { /* This is really serious, so just exit. */ perror("NEdit/nc: getpwuid() failed "); exit(EXIT_FAILURE); } } else { passwdEntry = getpwnam(username); if ((passwdEntry == NULL) || (*(passwdEntry->pw_dir)== '\0')) { /* username was just an input by the user, this is no indication for some (serious) problems */ return FALSE; } } strcpy(temp, passwdEntry->pw_dir); strcat(temp, "/"); len_left= sizeof(temp)-strlen(temp)-1; if (len_left < strlen(nameEnd)) { /* It won't work out */ return FALSE; } strcat(temp, nameEnd); strcpy(pathname, temp); return TRUE; } /* * Resolve symbolic links (if any) for the absolute path given in pathIn * and place the resolved absolute path in pathResolved. * - pathIn must contain an absolute path spec. * - pathResolved must point to a buffer of minimum size MAXPATHLEN. * * Returns: * TRUE if pathResolved contains a valid resolved path * OR pathIn is not a symlink (pathResolved will have the same * contents like pathIn) * * FALSE an error occured while trying to resolve the symlink, i.e. * pathIn was no absolute path or the link is a loop. */ int ResolvePath(const char * pathIn, char * pathResolved) { char resolveBuf[MAXPATHLEN], pathBuf[MAXPATHLEN]; char *pathEnd; int rlResult, loops; #ifdef NO_READLINK strncpy(pathResolved, pathIn, MAXPATHLEN); /* If there are no links at all, it's a valid "resolved" path */ return TRUE; #else /* !! readlink does NOT recognize loops, i.e. links like file -> ./file */ for (loops=0; loopsMAXPATHLEN)! ** ** FIXME: Documentation ** FIXME: Change return value to False and True. */ int NormalizePathname(char *pathname) { /* if this is a relative pathname, prepend current directory */ #ifdef __EMX__ /* OS/2, ...: welcome to the world of drive letters ... */ if (!_fnisabs(pathname)) { #else if (pathname[0] != '/') { #endif char *oldPathname; size_t len; /* make a copy of pathname to work from */ oldPathname=(char *)malloc(strlen(pathname)+1); strcpy(oldPathname, pathname); /* get the working directory and prepend to the path */ strcpy(pathname, GetCurrentDir()); /* check for trailing slash, or pathname being root dir "/": don't add a second '/' character as this may break things on non-un*x systems */ len = strlen(pathname); /* GetCurrentDir() returns non-NULL value */ /* Apart from the fact that people putting conditional expressions in ifs should be caned: How should len ever become 0 if GetCurrentDir() always returns a useful value? FIXME: Check and document GetCurrentDir() return behaviour. */ if (0 == len ? 1 : pathname[len-1] != '/') { strcat(pathname, "/"); } strcat(pathname, oldPathname); free(oldPathname); } /* compress out .. and . */ return CompressPathname(pathname); } /* ** Return 0 if everything's fine, 1 else. ** ** FIXME: Documentation ** FIXME: Change return value to False and True. */ int CompressPathname(char *pathname) { char *buf, *inPtr, *outPtr; struct stat statbuf; /* (Added by schwarzenberg) ** replace multiple slashes by a single slash ** (added by yooden) ** Except for the first slash. From the Single UNIX Spec: "A pathname ** that begins with two successive slashes may be interpreted in an ** implementation-dependent manner" */ inPtr = pathname; buf = (char*) malloc(strlen(pathname) + 2); outPtr = buf; *outPtr++ = *inPtr++; while (*inPtr) { *outPtr = *inPtr++; if ('/' == *outPtr) { while ('/' == *inPtr) { inPtr++; } } outPtr++; } *outPtr=0; strcpy(pathname, buf); /* compress out . and .. */ inPtr = pathname; outPtr = buf; /* copy initial / */ copyThruSlash(&outPtr, &inPtr); while (inPtr != NULL) { /* if the next component is "../", remove previous component */ if (compareThruSlash(inPtr, "../")) { *outPtr = 0; /* If the ../ is at the beginning, or if the previous component is a symbolic link, preserve the ../. It is not valid to compress ../ when the previous component is a symbolic link because ../ is relative to where the link points. If there's no S_ISLNK macro, assume system does not do symbolic links. */ #ifdef S_ISLNK if(outPtr-1 == buf || (lstat(buf, &statbuf) == 0 && S_ISLNK(statbuf.st_mode))) { copyThruSlash(&outPtr, &inPtr); } else #endif { /* back up outPtr to remove last path name component */ outPtr = prevSlash(outPtr); inPtr = nextSlash(inPtr); } } else if (compareThruSlash(inPtr, "./")) { /* don't copy the component if it's the redundant "./" */ inPtr = nextSlash(inPtr); } else { /* copy the component to outPtr */ copyThruSlash(&outPtr, &inPtr); } } /* updated pathname with the new value */ if (strlen(buf)>MAXPATHLEN) { fprintf(stderr, "nedit: CompressPathname(): file name too long %s\n", pathname); free(buf); return 1; } else { strcpy(pathname, buf); free(buf); return 0; } } static char *nextSlash(char *ptr) { for(; *ptr!='/'; ptr++) { if (*ptr == '\0') return NULL; } return ptr + 1; } static char *prevSlash(char *ptr) { for(ptr -= 2; *ptr!='/'; ptr--); return ptr + 1; } static int compareThruSlash(const char *string1, const char *string2) { while (TRUE) { if (*string1 != *string2) return FALSE; if (*string1 =='\0' || *string1=='/') return TRUE; string1++; string2++; } } static void copyThruSlash(char **toString, char **fromString) { char *to = *toString; char *from = *fromString; while (TRUE) { *to = *from; if (*from =='\0') { *fromString = NULL; return; } if (*from=='/') { *toString = to + 1; *fromString = from + 1; return; } from++; to++; } } #else /* VMS */ /* ** Dummy versions of the public functions for VMS. */ /* ** Return 0 if everything's fine, 1 else. */ int NormalizePathname(char *pathname) { return 0; } /* ** Return 0 if everything's fine, 1 else. */ int CompressPathname(char *pathname) { return 0; } /* * Returns: * TRUE if no error occured * * FALSE if an error occured. */ int ResolvePath(const char * pathIn, char * pathResolved) { if (strlen(pathIn) < MAXPATHLEN) { strcpy(pathResolved, pathIn); return TRUE; } else { return FALSE; } } #endif /* VMS */ /* ** Return the trailing 'n' no. of path components */ const char *GetTrailingPathComponents(const char* path, int noOfComponents) { /* Start from the rear */ const char* ptr = path + strlen(path); int count = 0; while (--ptr > path) { if (*ptr == '/') { if (count++ == noOfComponents) { break; } } } return(ptr); } /* ** Samples up to a maximum of FORMAT_SAMPLE_LINES lines and FORMAT_SAMPLE_CHARS ** characters, to determine whether fileString represents a MS DOS or Macintosh ** format file. If there's ANY ambiguity (a newline in the sample not paired ** with a return in an otherwise DOS looking file, or a newline appearing in ** the sampled portion of a Macintosh looking file), the file is judged to be ** Unix format. */ int FormatOfFile(const char *fileString) { const char *p; int nNewlines = 0, nReturns = 0; for (p=fileString; *p!='\0' && p < fileString + FORMAT_SAMPLE_CHARS; p++) { if (*p == '\n') { nNewlines++; if (p == fileString || *(p-1) != '\r') return UNIX_FILE_FORMAT; if (nNewlines >= FORMAT_SAMPLE_LINES) return DOS_FILE_FORMAT; } else if (*p == '\r') nReturns++; } if (nNewlines > 0) return DOS_FILE_FORMAT; if (nReturns > 0) return MAC_FILE_FORMAT; return UNIX_FILE_FORMAT; } /* ** Converts a string (which may represent the entire contents of the file) ** from DOS or Macintosh format to Unix format. Conversion is done in-place. ** In the DOS case, the length will be shorter, and passed length will be ** modified to reflect the new length. The routine has support for blockwise ** file to string conversion: if the fileString has a trailing '\r' and ** 'pendingCR' is not zero, the '\r' is deposited in there and is not ** converted. If there is no trailing '\r', a 0 is deposited in 'pendingCR' ** It's the caller's responsability to make sure that the pending character, ** if present, is inserted at the beginning of the next block to convert. */ void ConvertFromDosFileString(char *fileString, int *length, char* pendingCR) { char *outPtr = fileString; char *inPtr = fileString; if (pendingCR) *pendingCR = 0; while (inPtr < fileString + *length) { if (*inPtr == '\r') { if (inPtr < fileString + *length - 1) { if (*(inPtr + 1) == '\n') inPtr++; } else { if (pendingCR) { *pendingCR = *inPtr; break; /* Don't copy this trailing '\r' */ } } } *outPtr++ = *inPtr++; } *outPtr = '\0'; *length = outPtr - fileString; } void ConvertFromMacFileString(char *fileString, int length) { char *inPtr = fileString; while (inPtr < fileString + length) { if (*inPtr == '\r' ) *inPtr = '\n'; inPtr++; } } /* ** Converts a string (which may represent the entire contents of the file) from ** Unix to DOS format. String is re-allocated (with malloc), and length is ** modified. If allocation fails, which it may, because this can potentially ** be a huge hunk of memory, returns FALSE and no conversion is done. ** ** This could be done more efficiently by asking doSave to allocate some ** extra memory for this, and only re-allocating if it wasn't enough. If ** anyone cares about the performance or the potential for running out of ** memory on a save, it should probably be redone. */ int ConvertToDosFileString(char **fileString, int *length) { char *outPtr, *outString; char *inPtr = *fileString; int inLength = *length; int outLength = 0; /* How long a string will we need? */ while (inPtr < *fileString + inLength) { if (*inPtr == '\n') outLength++; inPtr++; outLength++; } /* Allocate the new string */ outString = XtMalloc(outLength + 1); if (outString == NULL) return FALSE; /* Do the conversion, free the old string */ inPtr = *fileString; outPtr = outString; while (inPtr < *fileString + inLength) { if (*inPtr == '\n') *outPtr++ = '\r'; *outPtr++ = *inPtr++; } *outPtr = '\0'; XtFree(*fileString); *fileString = outString; *length = outLength; return TRUE; } /* ** Converts a string (which may represent the entire contents of the file) ** from Unix to Macintosh format. */ void ConvertToMacFileString(char *fileString, int length) { char *inPtr = fileString; while (inPtr < fileString + length) { if (*inPtr == '\n' ) *inPtr = '\r'; inPtr++; } } /* ** Reads a text file into a string buffer, converting line breaks to ** unix-style if appropriate. ** ** Force a terminating \n, if this is requested */ char *ReadAnyTextFile(const char *fileName, int forceNL) { struct stat statbuf; FILE *fp; int fileLen, readLen; char *fileString; int format; /* Read the whole file into fileString */ if ((fp = fopen(fileName, "r")) == NULL) { return NULL; } if (fstat(fileno(fp), &statbuf) != 0) { fclose(fp); return NULL; } fileLen = statbuf.st_size; /* +1 = space for null ** +1 = possible additional \n */ fileString = XtMalloc(fileLen + 2); readLen = fread(fileString, sizeof(char), fileLen, fp); if (ferror(fp)) { XtFree(fileString); fclose(fp); return NULL; } fclose(fp); fileString[readLen] = 0; /* Convert linebreaks? */ format = FormatOfFile(fileString); if (format == DOS_FILE_FORMAT){ char pendingCR; ConvertFromDosFileString(fileString, &readLen, &pendingCR); } else if (format == MAC_FILE_FORMAT){ ConvertFromMacFileString(fileString, readLen); } /* now, that the fileString is in Unix format, check for terminating \n */ if (forceNL && fileString[readLen - 1] != '\n') { fileString[readLen] = '\n'; fileString[readLen + 1] = '\0'; } return fileString; } nedit-5.6.orig/util/fileUtils.h0000644000175000017500000000566311053030340015177 0ustar paulpaul/* $Id: fileUtils.h,v 1.13 2008/08/20 14:57:36 lebert Exp $ */ /******************************************************************************* * * * fileUtils.h -- Nirvana Editor File Utilities Header File * * * * Copyright 2003 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_FILEUTILS_H_INCLUDED #define NEDIT_FILEUTILS_H_INCLUDED enum fileFormats {UNIX_FILE_FORMAT, DOS_FILE_FORMAT, MAC_FILE_FORMAT}; int ParseFilename(const char *fullname, char *filename, char *pathname); int ExpandTilde(char *pathname); const char* GetTrailingPathComponents(const char* path, int noOfComponents); int NormalizePathname(char *pathname); int CompressPathname(char *pathname); int ResolvePath(const char * pathIn, char * pathResolved); int FormatOfFile(const char *fileString); void ConvertFromDosFileString(char *inString, int *length, char* pendingCR); void ConvertFromMacFileString(char *fileString, int length); int ConvertToDosFileString(char **fileString, int *length); void ConvertToMacFileString(char *fileString, int length); char *ReadAnyTextFile(const char *fileName, int forceNL); #endif /* NEDIT_FILEUTILS_H_INCLUDED */ nedit-5.6.orig/util/fontsel.c0000644000175000017500000013345110534252372014717 0ustar paulpaulstatic const char CVSID[] = "$Id: fontsel.c,v 1.29 2006/12/02 10:27:06 yooden Exp $"; /******************************************************************************* * * * fontsel.c -- Nirvana Font Selector * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * June 2, 1993 * * * * Written by Suresh Ravoor (assisted by Mark Edel) * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "fontsel.h" #include "misc.h" #include "DialogF.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #define MAX_ARGS 20 #define MAX_NUM_FONTS 32767 #define MAX_FONT_NAME_LEN 256 #define MAX_ENTRIES_IN_LIST 5000 #define MAX_DISPLAY_SIZE 150 #define DELIM '-' #define NUM_COMPONENTS_FONT_NAME 14 #define TEMP_BUF_SIZE 256 #define DISPLAY_HEIGHT 90 enum listSpecifier { NONE, FONT, STYLE, SIZE }; /* local data structures and types */ typedef struct { Widget form; /* widget id */ Widget okButton; /* widget id */ Widget cancelButton; /* widget id */ Widget fontList; /* widget id */ Widget styleList; /* widget id */ Widget sizeList; /* widget id */ Widget fontNameField; /* widget id */ Widget sizeToggle; /* widget id */ Widget propFontToggle; /* widget id */ Widget dispField; /* widget id */ char **fontData; /* font name info */ int numFonts; /* number of fonts */ char *sel1; /* selection from list 1 */ char *sel2; /* selection from list 2 */ char *sel3; /* selection from list 3 */ int showPropFonts; /* toggle state - show prop fonts */ int showSizeInPixels;/* toggle state - size in pixels */ char *fontName; /* current font name */ XFontStruct *oldFont; /* font data structure for dispSample */ XmFontList oldFontList; /* font data structure for dispSample */ int exitFlag; /* used for program exit control */ int destroyedFlag; /* used to prevent double destruction */ Pixel sampleFG; /* Colors for the sample field */ Pixel sampleBG; } xfselControlBlkType; /* local function prototypes */ static void getStringComponent(const char *inStr, int pos, char *outStr); static void setupScrollLists(int dontChange, xfselControlBlkType ctrlBlk); static int notPropFont(const char *font); static int styleMatch(xfselControlBlkType *ctrlBlk, const char *font); static int sizeMatch(xfselControlBlkType *ctrlBlk, const char *font); static int fontMatch(xfselControlBlkType *ctrlBlk, const char *font); static void addItemToList(char **buf, const char *item, int *count); static void getFontPart(const char *font, char *buff1); static void getStylePart(const char *font, char *buff1); static void getSizePart(const char *font, char *buff1, int inPixels); static void propFontToggleAction(Widget widget, xfselControlBlkType *ctrlBlk, XmToggleButtonCallbackStruct *call_data); static void sizeToggleAction(Widget widget, xfselControlBlkType *ctrlBlk, XmToggleButtonCallbackStruct *call_data); static void fontAction(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data); static void styleAction(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data); static void sizeAction(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data); static void choiceMade(xfselControlBlkType *ctrlBlk); static void dispSample(xfselControlBlkType *ctrlBlk); static void destroyCB(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data); static void cancelAction(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data); static void okAction(Widget widget, xfselControlBlkType *ctrlBlk, XmPushButtonCallbackStruct *call_data); static void startupFont(xfselControlBlkType *ctrlBlk, const char *font); static void setFocus(Widget w, xfselControlBlkType *ctrlBlk, XEvent *event, Boolean *continueToDispatch); static void FindBigFont(xfselControlBlkType *ctrlBlk, char *bigFont); static void enableSample(xfselControlBlkType *ctrlBlk, Bool turn_on, XmFontList *fontList); /******************************************************************************* * * * FontSel () * * * * * * Function to put up a modal font selection dialog box. The purpose * * of this routine is to allow the user to interactively view sample * * fonts and to choose a font for current use. * * * * Arguments: * * * * Widget parent - parent widget ID * * * * int showPropFont - ONLY_FIXED : shows only fixed fonts * * doesn't show prop font * * toggle button also. * * PREF_FIXED : can select either fixed * * or proportional fonts; * * but starting option is * * Fixed fonts. * * PREF_PROP : can select either fixed * * or proportional fonts; * * but starting option is * * proportional fonts. * * * * char * currFont - ASCII string that contains the name * * of the currently selected font. * * * * Pixel sampleFG, sampleBG - Foreground/Background colors in * * which to display the sample * * text. * * * * * * Returns: * * * * pointer to an ASCII character string that contains the name of * * the selected font (in X format for naming fonts); it is the users * * responsibility to free the space allocated to this string. * * * * Comments: * * * * The calling function has to call the appropriate routines to set * * the current font to the one represented by the returned string. * * * *******************************************************************************/ char *FontSel(Widget parent, int showPropFonts, const char *currFont, Pixel sampleFG, Pixel sampleBG) { Widget dialog, form, okButton, cancelButton; Widget styleList, sizeList, fontName, fontList; Widget sizeToggle, propFontToggle = NULL, dispField; Widget nameLabel, sampleLabel; Arg args[MAX_ARGS]; int n; XmString tempStr; char bigFont[MAX_FONT_NAME_LEN]; xfselControlBlkType ctrlBlk; Display *theDisplay; ctrlBlk.fontData = XListFonts(XtDisplay(parent), "-*-*-*-*-*-*-*-*-*-*-*-*-*-*", MAX_NUM_FONTS, &ctrlBlk.numFonts); FindBigFont(&ctrlBlk, bigFont); ctrlBlk.oldFont = XLoadQueryFont(XtDisplay(parent), bigFont); ctrlBlk.oldFontList = XmFontListCreate(ctrlBlk.oldFont, XmSTRING_DEFAULT_CHARSET); ctrlBlk.sampleFG = sampleFG; ctrlBlk.sampleBG = sampleBG; dialog = CreateDialogShell(parent, "Font Selector", args, 0); /* Set up window sizes for form widget */ n = 0; XtSetArg(args[n], XmNautoUnmanage, FALSE); n++; XtSetArg(args[n], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); n++; /* Create form popup dialog widget */ form = XtCreateWidget ("Font Selector", xmFormWidgetClass, dialog, args, n); /* Create pushbutton widgets */ n = 0; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNbottomOffset, 4); n++; XtSetArg(args[n], XmNtopOffset, 1); n++; XtSetArg(args[n], XmNrightPosition, 45); n++; XtSetArg(args[n], XmNwidth, 110); n++; XtSetArg(args[n], XmNheight, 28); n++; XtSetArg(args[n], XmNshowAsDefault, TRUE); n++; okButton = XtCreateManagedWidget("OK", xmPushButtonWidgetClass, form, args, n); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, okButton); n++; XtSetArg(args[n], XmNbottomWidget, okButton); n++; XtSetArg(args[n], XmNleftPosition, 55); n++; XtSetArg(args[n], XmNwidth, 110); n++; XtSetArg(args[n], XmNheight, 28); n++; cancelButton = XtCreateManagedWidget("Cancel", xmPushButtonWidgetClass, form, args, n); /* create font name text widget and the corresponding label */ n = 0; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNbottomWidget, okButton); n++; XtSetArg(args[n], XmNleftPosition, 1); n++; XtSetArg(args[n], XmNrightPosition, 99); n++; XtSetArg(args[n], XmNeditable, True); n++; XtSetArg(args[n], XmNeditMode, XmSINGLE_LINE_EDIT); n++; XtSetArg(args[n], XmNmaxLength, MAX_FONT_NAME_LEN); n++; fontName = XtCreateManagedWidget("fontname", xmTextWidgetClass, form, args, n); RemapDeleteKey(fontName); /* kludge to handle delete and BS */ n = 0; tempStr = XmStringCreate("Font Name:", XmSTRING_DEFAULT_CHARSET); XtSetArg(args[n], XmNlabelString, tempStr); n++; XtSetArg(args[n], XmNmnemonic, 'N'); n++; XtSetArg(args[n], XmNuserData, fontName); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, fontName); n++; XtSetArg(args[n], XmNbottomWidget, fontName); n++; XtSetArg(args[n], XmNtopOffset, 1); n++; nameLabel = XtCreateManagedWidget("Font Name:", xmLabelWidgetClass, form, args, n); XmStringFree(tempStr); /* create sample display text field widget */ n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 99); n++; XtSetArg(args[n], XmNbottomWidget, nameLabel); n++; XtSetArg(args[n], XmNleftPosition, 1); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNvalue, "ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789"); n++; XtSetArg(args[n], XmNforeground, sampleFG); n++; XtSetArg(args[n], XmNbackground, sampleBG); n++; dispField = XtCreateManagedWidget(" ", xmTextFieldWidgetClass, form, args, n); n = 0; tempStr = XmStringCreate("Sample:", XmSTRING_DEFAULT_CHARSET); XtSetArg(args[n], XmNlabelString, tempStr); n++; XtSetArg(args[n], XmNmnemonic, 'S'); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, dispField); n++; XtSetArg(args[n], XmNbottomWidget, dispField); n++; XtSetArg(args[n], XmNtopOffset, 1); n++; sampleLabel = XtCreateManagedWidget("Font Name:", xmLabelWidgetClass, form, args, n); XmStringFree(tempStr); /* create toggle buttons */ n = 0; tempStr = XmStringCreate("Show Size in Points", XmSTRING_DEFAULT_CHARSET); XtSetArg(args[n], XmNlabelString, tempStr); n++; XtSetArg(args[n], XmNmnemonic, 'P'); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftPosition, 2); n++; XtSetArg(args[n], XmNtopOffset, 1); n++; XtSetArg(args[n], XmNbottomWidget, sampleLabel); n++; sizeToggle = XtCreateManagedWidget("sizetoggle", xmToggleButtonWidgetClass, form, args, n); XmStringFree(tempStr); if (showPropFonts != ONLY_FIXED) { n = 0; tempStr = XmStringCreate("Show Proportional Width Fonts", XmSTRING_DEFAULT_CHARSET); XtSetArg(args[n], XmNlabelString, tempStr); n++; XtSetArg(args[n], XmNmnemonic, 'W'); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNrightPosition, 98); n++; XtSetArg(args[n], XmNtopWidget, sizeToggle); n++; XtSetArg(args[n], XmNbottomWidget, sizeToggle); n++; XtSetArg(args[n], XmNtopOffset, 1); n++; propFontToggle = XtCreateManagedWidget("propfonttoggle", xmToggleButtonWidgetClass, form, args, n); XmStringFree(tempStr); } /* create scroll list widgets */ /* "Font" list */ n = 0; tempStr = XmStringCreate("Font:", XmSTRING_DEFAULT_CHARSET); XtSetArg(args[n], XmNlabelString, tempStr); n++; XtSetArg(args[n], XmNmnemonic, 'F'); n++; XtSetArg(args[n], XmNtopOffset, 2); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, 1); n++; nameLabel = XtCreateManagedWidget("Font:", xmLabelWidgetClass, form, args, n); XmStringFree(tempStr); n = 0; XtSetArg(args[n], XmNvisibleItemCount, 15); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNbottomWidget, sizeToggle); n++; XtSetArg(args[n], XmNtopWidget, nameLabel); n++; XtSetArg(args[n], XmNleftWidget, nameLabel); n++; XtSetArg(args[n], XmNrightPosition, 52); n++; fontList = XmCreateScrolledList(form, "fontlist", args, n); AddMouseWheelSupport(fontList); XtManageChild(fontList); XtVaSetValues(nameLabel, XmNuserData, fontList, NULL); /* "Style" list */ n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNtopWidget, nameLabel); n++; XtSetArg(args[n], XmNleftOffset, 5); n++; XtSetArg(args[n], XmNleftWidget, XtParent(fontList)); n++; XtSetArg(args[n], XmNbottomWidget, XtParent(fontList)); n++; XtSetArg(args[n], XmNrightPosition, 85); n++; styleList = XmCreateScrolledList(form, "stylelist", args, n); AddMouseWheelSupport(styleList); XtManageChild(styleList); n = 0; tempStr = XmStringCreate("Style:", XmSTRING_DEFAULT_CHARSET); XtSetArg(args[n], XmNmnemonic, 'y'); n++; XtSetArg(args[n], XmNuserData, styleList); n++; XtSetArg(args[n], XmNlabelString, tempStr); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, XtParent(styleList)); n++; XtSetArg(args[n], XmNleftWidget, XtParent(styleList)); n++; XtCreateManagedWidget("Style:", xmLabelWidgetClass, form, args, n); XmStringFree(tempStr); /* "Size" list */ n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, nameLabel); n++; XtSetArg(args[n], XmNleftWidget, XtParent(styleList)); n++; XtSetArg(args[n], XmNbottomWidget, XtParent(fontList)); n++; XtSetArg(args[n], XmNleftOffset, 5); n++; XtSetArg(args[n], XmNrightPosition, 99); n++; sizeList = XmCreateScrolledList(form, "sizelist", args, n); AddMouseWheelSupport(sizeList); XtManageChild(sizeList); n = 0; tempStr = XmStringCreate("Size:", XmSTRING_DEFAULT_CHARSET); XtSetArg(args[n], XmNlabelString, tempStr); n++; XtSetArg(args[n], XmNmnemonic, 'z'); n++; XtSetArg(args[n], XmNuserData, sizeList); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, XtParent(sizeList)); n++; XtSetArg(args[n], XmNleftWidget, XtParent(sizeList)); n++; XtCreateManagedWidget("Size:", xmLabelWidgetClass, form, args, n); XmStringFree(tempStr); /* update form widgets cancel button */ n = 0; XtSetArg(args[n], XmNcancelButton, cancelButton); n++; XtSetValues(form, args, n); /* update application's control block structure */ ctrlBlk.form = form; ctrlBlk.okButton = okButton; ctrlBlk.cancelButton = cancelButton; ctrlBlk.fontList = fontList; ctrlBlk.styleList = styleList; ctrlBlk.sizeList = sizeList; ctrlBlk.fontNameField = fontName; ctrlBlk.sizeToggle = sizeToggle; if (showPropFonts != ONLY_FIXED) ctrlBlk.propFontToggle = propFontToggle; ctrlBlk.dispField = dispField; ctrlBlk.exitFlag = FALSE; ctrlBlk.destroyedFlag = FALSE; ctrlBlk.showPropFonts = showPropFonts; ctrlBlk.showSizeInPixels = TRUE; ctrlBlk.sel1 = NULL; ctrlBlk.sel2 = NULL; ctrlBlk.sel3 = NULL; ctrlBlk.fontName = NULL; setupScrollLists(NONE, ctrlBlk); /* update scroll lists */ if (showPropFonts == PREF_PROP) XmToggleButtonSetState(propFontToggle, TRUE, FALSE); /* Register callback functions */ if (showPropFonts != ONLY_FIXED) XtAddCallback(propFontToggle, XmNvalueChangedCallback, (XtCallbackProc)propFontToggleAction, (char *)&ctrlBlk); XtAddCallback(sizeToggle, XmNvalueChangedCallback, (XtCallbackProc)sizeToggleAction, (char *)&ctrlBlk); XtAddCallback(fontList, XmNbrowseSelectionCallback, (XtCallbackProc)fontAction, (char *)&ctrlBlk); XtAddCallback(styleList, XmNbrowseSelectionCallback, (XtCallbackProc)styleAction, (char *)&ctrlBlk); XtAddCallback(sizeList, XmNbrowseSelectionCallback, (XtCallbackProc)sizeAction, (char *)&ctrlBlk); XtAddCallback(okButton, XmNactivateCallback, (XtCallbackProc)okAction, (char *)&ctrlBlk); XtAddCallback(cancelButton, XmNactivateCallback, (XtCallbackProc)cancelAction, (char *)&ctrlBlk); /* add event handler to setup input focus at start to scroll list */ XtAddEventHandler(fontList, FocusChangeMask, FALSE, (XtEventHandler)setFocus, (char *)&ctrlBlk); XmProcessTraversal(fontList, XmTRAVERSE_CURRENT); /* setup tabgroups */ XmAddTabGroup(fontList); XmAddTabGroup(styleList); XmAddTabGroup(sizeList); XmAddTabGroup(sizeToggle); if (showPropFonts != ONLY_FIXED) XmAddTabGroup(propFontToggle); XmAddTabGroup(fontName); XmAddTabGroup(okButton); XmAddTabGroup(cancelButton); /* Make sure that we don't try to access the dialog if the user destroyed it (possibly indirectly, by destroying the parent). */ XtAddCallback(dialog, XmNdestroyCallback, (XtCallbackProc)destroyCB, (char *)&ctrlBlk); /* Link Motif Close option to cancel action */ AddMotifCloseCallback(dialog, (XtCallbackProc)cancelAction, &ctrlBlk); /* Handle dialog mnemonics */ AddDialogMnemonicHandler(form, FALSE); /* Realize Widgets */ ManageDialogCenteredOnPointer(form); /* set up current font parameters */ if (currFont[0] != '\0') startupFont(&ctrlBlk, currFont); /* Make sure that we can still access the display in case the form gets destroyed */ theDisplay = XtDisplay(form); /* enter event loop */ while (! ctrlBlk.exitFlag && ! ctrlBlk.destroyedFlag) XtAppProcessEvent(XtWidgetToApplicationContext(form), XtIMAll); if (! ctrlBlk.destroyedFlag) { /* Don't let the callback destroy the font name */ XtRemoveCallback(dialog, XmNdestroyCallback, (XtCallbackProc)destroyCB, (char *)&ctrlBlk); XtDestroyWidget(dialog); } if (ctrlBlk.oldFont != NULL) { XFreeFont(theDisplay, ctrlBlk.oldFont); XmFontListFree(ctrlBlk.oldFontList); } return(ctrlBlk.fontName); } /* gets a specific substring from a string */ static void getStringComponent(const char *inStr, int pos, char *outStr) { int i, j; *outStr = '\0'; if (pos > NUM_COMPONENTS_FONT_NAME) { fprintf(stderr, "Warning: getStringComponent being used for "); fprintf(stderr, "pos > %d\nIf such ", NUM_COMPONENTS_FONT_NAME); fprintf(stderr, "use is intended remove these warning lines\n"); } for (i = 0; (pos > 0) && (inStr[i] != '\0'); i++) if (inStr[i] == DELIM) pos--; if (inStr[i] == '\0') return; for (j = 0; (inStr[i] != DELIM) && (inStr[i] != '\0'); i++, j++) outStr[j] = inStr[i]; outStr[j] = '\0'; } /* parse through the fontlist data and set up the three scroll lists */ static void setupScrollLists(int dontChange, xfselControlBlkType ctrlBlk) { char *itemBuf1[MAX_ENTRIES_IN_LIST]; char *itemBuf2[MAX_ENTRIES_IN_LIST]; char *itemBuf3[MAX_ENTRIES_IN_LIST]; int itemCount1, itemCount2, itemCount3; char buff1[TEMP_BUF_SIZE]; XmString items[MAX_ENTRIES_IN_LIST]; int i; itemCount1 = 0; itemCount2 = 0; itemCount3 = 0; for (i = 0; i < ctrlBlk.numFonts && i < MAX_ENTRIES_IN_LIST; i++) { if ((dontChange != FONT) && (styleMatch(&ctrlBlk, ctrlBlk.fontData[i])) && (sizeMatch (&ctrlBlk, ctrlBlk.fontData[i])) && ((ctrlBlk.showPropFonts == PREF_PROP) || (notPropFont(ctrlBlk.fontData[i])))) { getFontPart(ctrlBlk.fontData[i], buff1); addItemToList(itemBuf1, buff1, &itemCount1); } if ((dontChange != STYLE) && (fontMatch(&ctrlBlk, ctrlBlk.fontData[i])) && (sizeMatch (&ctrlBlk, ctrlBlk.fontData[i])) && ((ctrlBlk.showPropFonts == PREF_PROP) || (notPropFont(ctrlBlk.fontData[i])))) { getStylePart(ctrlBlk.fontData[i], buff1); addItemToList(itemBuf2, buff1, &itemCount2); } if ((dontChange != SIZE) && (fontMatch(&ctrlBlk, ctrlBlk.fontData[i])) && (styleMatch (&ctrlBlk, ctrlBlk.fontData[i])) && ((ctrlBlk.showPropFonts == PREF_PROP) || (notPropFont(ctrlBlk.fontData[i])))) { getSizePart(ctrlBlk.fontData[i], buff1, ctrlBlk.showSizeInPixels); addItemToList(itemBuf3, buff1, &itemCount3); } } /* end - for (i = 0; i < ctrlBlk.numFonts; i++) */ /* recreate all three scroll lists where necessary */ if (dontChange != FONT) { for (i = 0; i < itemCount1; i++) { items[i] = XmStringCreate(itemBuf1[i], XmSTRING_DEFAULT_CHARSET); XtFree(itemBuf1[i]); } XmListDeleteAllItems(ctrlBlk.fontList); XmListAddItems(ctrlBlk.fontList, items, itemCount1, 1); if (ctrlBlk.sel1 != NULL) { XmStringFree(items[0]); items[0] = XmStringCreate(ctrlBlk.sel1, XmSTRING_DEFAULT_CHARSET); XmListSelectItem(ctrlBlk.fontList, items[0], FALSE); XmListSetBottomItem(ctrlBlk.fontList, items[0]); } for (i = 0; i < itemCount1; i++) XmStringFree(items[i]); } if (dontChange != STYLE) { for (i = 0; i < itemCount2; i++) { items[i] = XmStringCreate(itemBuf2[i], XmSTRING_DEFAULT_CHARSET); XtFree(itemBuf2[i]); } XmListDeleteAllItems(ctrlBlk.styleList); XmListAddItems(ctrlBlk.styleList, items, itemCount2, 1); if (ctrlBlk.sel2 != NULL) { XmStringFree(items[0]); items[0] = XmStringCreate(ctrlBlk.sel2, XmSTRING_DEFAULT_CHARSET); XmListSelectItem(ctrlBlk.styleList, items[0], FALSE); XmListSetBottomItem(ctrlBlk.styleList, items[0]); } for (i = 0; i < itemCount2; i++) XmStringFree(items[i]); } if (dontChange != SIZE) { for (i = 0; i < itemCount3; i++) { items[i] = XmStringCreate(itemBuf3[i], XmSTRING_DEFAULT_CHARSET); XtFree(itemBuf3[i]); } XmListDeleteAllItems(ctrlBlk.sizeList); XmListAddItems(ctrlBlk.sizeList, items, itemCount3, 1); if (ctrlBlk.sel3 != NULL) { XmStringFree(items[0]); items[0] = XmStringCreate(ctrlBlk.sel3, XmSTRING_DEFAULT_CHARSET); XmListSelectItem(ctrlBlk.sizeList, items[0], FALSE); XmListSetBottomItem(ctrlBlk.sizeList, items[0]); } for (i = 0; i < itemCount3; i++) XmStringFree(items[i]); } } /* returns TRUE if argument is not name of a proportional font */ static int notPropFont(const char *font) { char buff1[TEMP_BUF_SIZE]; getStringComponent(font, 11, buff1); if ((strcmp(buff1, "p") == 0) || (strcmp(buff1, "P") == 0)) return(FALSE); else return(TRUE); } /* returns TRUE if the style portion of the font matches the currently selected style */ static int styleMatch(xfselControlBlkType *ctrlBlk, const char *font) { char buff[TEMP_BUF_SIZE]; if (ctrlBlk->sel2 == NULL) return(TRUE); getStylePart(font, buff); if (strcmp(buff, ctrlBlk->sel2) == 0) return(TRUE); else return(FALSE); } /* returns TRUE if the size portion of the font matches the currently selected size */ static int sizeMatch(xfselControlBlkType *ctrlBlk, const char *font) { char buff[TEMP_BUF_SIZE]; if (ctrlBlk->sel3 == NULL) return(TRUE); getSizePart(font, buff, ctrlBlk->showSizeInPixels); if (strcmp(buff, ctrlBlk->sel3) == 0) return(TRUE); else return(FALSE); } /* returns TRUE if the font portion of the font matches the currently selected font */ static int fontMatch(xfselControlBlkType *ctrlBlk, const char *font) { char buff[TEMP_BUF_SIZE]; if (ctrlBlk->sel1 == NULL) return(TRUE); getFontPart(font, buff); if (strcmp(buff, ctrlBlk->sel1) == 0) return(TRUE); else return(FALSE); } /* inserts a string into correct sorted position in a list */ static void addItemToList(char **buf, const char *item, int *count) { int i, j; if (*count == MAX_ENTRIES_IN_LIST) { fprintf(stderr, "Trying to add more than MAX_ENTRIES_IN_LIST "); fprintf(stderr, "(%d) entries to array\n", MAX_ENTRIES_IN_LIST); return; } for (i = 0; i < *count; i++) { if (strcmp(buf[i], item) == 0) return; if (strcmp(buf[i], item) > 0) break; } for (j = *count; j > i; j--) buf[j] = buf[j-1]; buf[i] = XtMalloc(strlen(item) + 1); strcpy(buf[i], item); (*count)++; } /* given a font name this function returns the part used in the first scroll list */ static void getFontPart(const char *font, char *buff1) { char buff2[TEMP_BUF_SIZE], buff3[TEMP_BUF_SIZE]; char buff4[TEMP_BUF_SIZE]; getStringComponent(font, 2, buff1); getStringComponent(font, 1, buff2); sprintf(buff3, "%s (%s", buff1, buff2); getStringComponent(font, 13, buff1); getStringComponent(font, 14, buff4); if (((strncmp(buff1, "iso8859", 7) == 0) || (strncmp(buff1, "ISO8859", 7) == 0)) && (strcmp(buff4, "1") == 0)) sprintf(buff1, "%s)", buff3); else { sprintf(buff2, "%s, %s,", buff3, buff1); sprintf(buff1, "%s %s)", buff2, buff4); } } /* given a font name this function returns the part used in the second scroll list */ static void getStylePart(const char *font, char *buff1) { char buff2[TEMP_BUF_SIZE], buff3[TEMP_BUF_SIZE]; getStringComponent(font, 3, buff3); getStringComponent(font, 5, buff2); if ((strcmp(buff2, "normal") != 0) && (strcmp(buff2, "Normal") != 0) && (strcmp(buff2, "NORMAL") != 0)) sprintf(buff1, "%s %s", buff3, buff2); else strcpy(buff1, buff3); getStringComponent(font, 6, buff2); if (buff2[0] != '\0') sprintf(buff3, "%s %s", buff1, buff2); else strcpy(buff3, buff1); getStringComponent(font, 4, buff2); if ((strcmp(buff2, "o") == 0) || (strcmp(buff2, "O") == 0)) sprintf(buff1, "%s oblique", buff3); else if ((strcmp(buff2, "i") == 0) || (strcmp(buff2, "I") == 0)) sprintf(buff1, "%s italic", buff3); if (strcmp(buff1, " ") == 0) strcpy(buff1, "-"); } /* given a font name this function returns the part used in the third scroll list */ static void getSizePart(const char *font, char *buff1, int inPixels) { int size; if (inPixels) { getStringComponent(font, 7, buff1); size = atoi(buff1); sprintf(buff1, "%2d", size); } else { double temp; getStringComponent(font, 8, buff1); size = atoi(buff1); temp = (double)size / 10.0; if (buff1[strlen(buff1) - 1] == '0') { size = (int)floor(temp+0.5); sprintf(buff1, "%2d", size); } else sprintf(buff1, "%4.1f", temp); } } /* Call back functions start from here - suffix Action in the function name is for the callback function for the corresponding widget */ static void propFontToggleAction(Widget widget, xfselControlBlkType *ctrlBlk, XmToggleButtonCallbackStruct *call_data) { if (call_data->reason == XmCR_VALUE_CHANGED) { if (ctrlBlk->showPropFonts == PREF_FIXED) ctrlBlk->showPropFonts = PREF_PROP; else ctrlBlk->showPropFonts = PREF_FIXED; XtFree(ctrlBlk->sel1); ctrlBlk->sel1 = NULL; XtFree(ctrlBlk->sel2); ctrlBlk->sel2 = NULL; XtFree(ctrlBlk->sel3); ctrlBlk->sel3 = NULL; setupScrollLists(NONE, *ctrlBlk); XmTextSetString(ctrlBlk->fontNameField, ""); enableSample(ctrlBlk, False, NULL); } } static void sizeToggleAction(Widget widget, xfselControlBlkType *ctrlBlk, XmToggleButtonCallbackStruct *call_data) { int i, makeSelection; char newSize[10]; XmString str; if (call_data->reason == XmCR_VALUE_CHANGED) { makeSelection = (ctrlBlk->sel3 != NULL); for (i = 0; (makeSelection) && (i < ctrlBlk->numFonts); i++) if ((fontMatch(ctrlBlk, ctrlBlk->fontData[i])) && (styleMatch(ctrlBlk, ctrlBlk->fontData[i])) && (sizeMatch(ctrlBlk, ctrlBlk->fontData[i]))) { getSizePart(ctrlBlk->fontData[i], newSize, !ctrlBlk->showSizeInPixels); break; } if (ctrlBlk->showSizeInPixels) ctrlBlk->showSizeInPixels = FALSE; else ctrlBlk->showSizeInPixels = TRUE; XtFree(ctrlBlk->sel3); ctrlBlk->sel3 = NULL; setupScrollLists(NONE, *ctrlBlk); if (makeSelection) { str = XmStringCreate(newSize, XmSTRING_DEFAULT_CHARSET); XmListSelectItem(ctrlBlk->sizeList, str, TRUE); XmListSetBottomItem(ctrlBlk->sizeList, str); XmStringFree(str); } } } static void enableSample(xfselControlBlkType *ctrlBlk, Bool turn_on, XmFontList *fontList) { int n=0; Arg args[4]; XtSetArg(args[n], XmNeditable, turn_on); n++; XtSetArg(args[n], XmNcursorPositionVisible, turn_on); n++; if( turn_on ) { if( !fontList ) { fprintf(stderr, "nedit: Internal error in fontsel.c, line %i\n", \ __LINE__); } else { XtSetArg(args[n], XmNfontList, *fontList); n++; } XtSetArg(args[n], XmNforeground, ctrlBlk->sampleFG); n++; } else { XtSetArg(args[n], XmNforeground, ctrlBlk->sampleBG); n++; } XtSetValues(ctrlBlk->dispField, args, n); /* Make sure the sample area gets resized if the font size changes */ XtUnmanageChild(ctrlBlk->dispField); XtManageChild(ctrlBlk->dispField); } static void fontAction(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data) { char *sel; XmStringGetLtoR(call_data->item, XmSTRING_DEFAULT_CHARSET, &sel); if (ctrlBlk->sel1 == NULL) { ctrlBlk->sel1 = XtMalloc(strlen(sel) + 1); strcpy(ctrlBlk->sel1, sel); } else { if (strcmp(ctrlBlk->sel1, sel) == 0) { /* Unselecting current selection */ XtFree(ctrlBlk->sel1); ctrlBlk->sel1 = NULL; XmListDeselectItem(widget, call_data->item); } else { XtFree(ctrlBlk->sel1); ctrlBlk->sel1 = XtMalloc(strlen(sel) + 1); strcpy(ctrlBlk->sel1, sel); } } XtFree(sel); setupScrollLists(FONT, *ctrlBlk); if ((ctrlBlk->sel1 != NULL) && (ctrlBlk->sel2 != NULL) && (ctrlBlk->sel3 != NULL)) choiceMade(ctrlBlk); else { enableSample(ctrlBlk, False, NULL); XmTextSetString(ctrlBlk->fontNameField, ""); } } static void styleAction(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data) { char *sel; XmStringGetLtoR(call_data->item, XmSTRING_DEFAULT_CHARSET, &sel); if (ctrlBlk->sel2 == NULL) { ctrlBlk->sel2 = XtMalloc(strlen(sel) + 1); strcpy(ctrlBlk->sel2, sel); } else { if (strcmp(ctrlBlk->sel2, sel) == 0) { /* unselecting current selection */ XtFree(ctrlBlk->sel2); ctrlBlk->sel2 = NULL; XmListDeselectItem(widget, call_data->item); } else { XtFree(ctrlBlk->sel2); ctrlBlk->sel2 = XtMalloc(strlen(sel) + 1); strcpy(ctrlBlk->sel2, sel); } } XtFree(sel); setupScrollLists(STYLE, *ctrlBlk); if ((ctrlBlk->sel1 != NULL) && (ctrlBlk->sel2 != NULL) && (ctrlBlk->sel3 != NULL)) choiceMade(ctrlBlk); else { enableSample(ctrlBlk, False, NULL); XmTextSetString(ctrlBlk->fontNameField, ""); } } static void sizeAction(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data) { char *sel; XmStringGetLtoR(call_data->item, XmSTRING_DEFAULT_CHARSET, &sel); if (ctrlBlk->sel3 == NULL) { ctrlBlk->sel3 = XtMalloc(strlen(sel) + 1); strcpy(ctrlBlk->sel3, sel); } else { if (strcmp(ctrlBlk->sel3, sel) == 0) { /* unselecting current selection */ XtFree(ctrlBlk->sel3); ctrlBlk->sel3 = NULL; XmListDeselectItem(widget, call_data->item); } else { XtFree(ctrlBlk->sel3); ctrlBlk->sel3 = XtMalloc(strlen(sel) + 1); strcpy(ctrlBlk->sel3, sel); } } XtFree(sel); setupScrollLists(SIZE, *ctrlBlk); if ((ctrlBlk->sel1 != NULL) && (ctrlBlk->sel2 != NULL) && (ctrlBlk->sel3 != NULL)) choiceMade(ctrlBlk); else { enableSample(ctrlBlk, False, NULL); XmTextSetString(ctrlBlk->fontNameField, ""); } } /* function called when all three choices have been made; sets up font name and displays sample font */ static void choiceMade(xfselControlBlkType *ctrlBlk) { int i; XtFree(ctrlBlk->fontName); ctrlBlk->fontName = NULL; for (i = 0; i < ctrlBlk->numFonts; i++) { if ((fontMatch(ctrlBlk, ctrlBlk->fontData[i])) && (styleMatch(ctrlBlk, ctrlBlk->fontData[i])) && (sizeMatch (ctrlBlk, ctrlBlk->fontData[i]))) { ctrlBlk->fontName = XtMalloc( strlen(ctrlBlk->fontData[i]) + 1); strcpy(ctrlBlk->fontName, ctrlBlk->fontData[i]); break; } } if (ctrlBlk->fontName != NULL) { XmTextSetString(ctrlBlk->fontNameField, ctrlBlk->fontName); dispSample(ctrlBlk); } else { DialogF (DF_ERR, ctrlBlk->form, 1, "Font Specification", "Invalid Font Specification", "OK"); } } /* loads selected font and displays sample text in that font */ static void dispSample(xfselControlBlkType *ctrlBlk) { XFontStruct *font; XmFontList fontList; Display *display; display = XtDisplay(ctrlBlk->form); font = XLoadQueryFont(display, ctrlBlk->fontName); fontList = XmFontListCreate(font, XmSTRING_DEFAULT_CHARSET); enableSample(ctrlBlk, True, &fontList); if (ctrlBlk->oldFont != NULL) { XFreeFont(display, ctrlBlk->oldFont); XmFontListFree(ctrlBlk->oldFontList); } ctrlBlk->oldFont = font; ctrlBlk->oldFontList = fontList; } static void destroyCB(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data) { /* Prevent double destruction of the font selection dialog */ ctrlBlk->destroyedFlag = TRUE; cancelAction(widget, ctrlBlk, call_data); } static void cancelAction(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data) { XtFree(ctrlBlk->sel1); XtFree(ctrlBlk->sel2); XtFree(ctrlBlk->sel3); XtFree(ctrlBlk->fontName); ctrlBlk->fontName = NULL; XFreeFontNames(ctrlBlk->fontData); ctrlBlk->exitFlag = TRUE; } static void okAction(Widget widget, xfselControlBlkType *ctrlBlk, XmPushButtonCallbackStruct *call_data) { char *fontPattern; char **fontName; int i; fontPattern = XmTextGetString(ctrlBlk->fontNameField); fontName = XListFonts(XtDisplay(ctrlBlk->form), fontPattern, 1, &i); XtFree(fontPattern); if (i != 1) { DialogF (DF_ERR, ctrlBlk->okButton, 1, "Font Specification", "Invalid Font Specification", "OK"); XFreeFontNames(fontName); } else { XtFree(ctrlBlk->fontName); ctrlBlk->fontName = XtMalloc(strlen(fontName[0]) + 1); strcpy(ctrlBlk->fontName, fontName[0]); XtFree(ctrlBlk->sel1); XtFree(ctrlBlk->sel2); XtFree(ctrlBlk->sel3); XFreeFontNames(fontName); XFreeFontNames(ctrlBlk->fontData); ctrlBlk->exitFlag = TRUE; } } /* if current font is passed as an argument then this function is invoked and sets up initial entries */ static void startupFont(xfselControlBlkType *ctrlBlk, const char *font) { int i; char **fontName; char part[TEMP_BUF_SIZE]; XmString str; fontName = XListFonts(XtDisplay(ctrlBlk->form), font, 1, &i); if (i == 0) { /* invalid font passed in at startup */ XFreeFontNames(fontName); return; } ctrlBlk->fontName = XtMalloc(strlen(fontName[0]) + 1); strcpy(ctrlBlk->fontName, fontName[0]); getFontPart(fontName[0], part); XFreeFontNames(fontName); str = XmStringCreate(part, XmSTRING_DEFAULT_CHARSET); XmListSetBottomItem(ctrlBlk->fontList, str); XmListSelectItem(ctrlBlk->fontList, str, TRUE); XmListSelectItem(ctrlBlk->fontList, str, TRUE); XmStringFree(str); dispSample(ctrlBlk); XmTextSetString(ctrlBlk->fontNameField, ctrlBlk->fontName); } /* hacked code to move initial input focus to first scroll list and at the same time have the OK button as the default button */ static void setFocus(Widget w, xfselControlBlkType *ctrlBlk, XEvent *event, Boolean *continueToDispatch) { int n; Arg args[2]; *continueToDispatch = TRUE; n = 0; XtSetArg(args[n], XmNdefaultButton, ctrlBlk->okButton); n++; XtSetValues(ctrlBlk->form, args, n); } /* finds the name of the biggest font less than the given limit MAX_DISPLAY_SIZE used to set up the initial height of the display widget */ static void FindBigFont(xfselControlBlkType *ctrlBlk, char *bigFont) { int i, maxSize, ind = -1, size; char sizeStr[10]; for (i = 0, maxSize = 0; i < ctrlBlk->numFonts; i++) { getStringComponent(ctrlBlk->fontData[i], 7, sizeStr); size = atoi(sizeStr); if ((size > maxSize) && (size < MAX_DISPLAY_SIZE)) { ind = i; maxSize = size; } } if (ind >= 0) { strcpy(bigFont, ctrlBlk->fontData[ind]); } else { bigFont[0] = 0; } } nedit-5.6.orig/util/fontsel.h0000644000175000017500000001312510144236625014717 0ustar paulpaul/* $Id: fontsel.h,v 1.11 2004/11/09 21:58:45 yooden Exp $ */ /******************************************************************************* * * * fontsel.h -- Nirvana Editor Font Selector Dialog Header File * * * * Copyright 2003 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_FONTSEL_H_INCLUDED #define NEDIT_FONTSEL_H_INCLUDED #include /******************************************************************************* * * * FontSel () * * * * * * Function to put up a modal font selection dialog box. The purpose * * of this routine is to allow the user to interactively view sample * * fonts and to choose a font for current use. * * * * Arguments: * * * * Widget parent - parent widget ID * * * * int showPropFont - ONLY_FIXED : shows only fixed fonts * * doesn't show prop font * * toggle button also. * * PREF_FIXED : can select either fixed * * or proportional fonts; * * but starting option is * * Fixed fonts. * * PREF_PROP : can select either fixed * * or proportional fonts; * * but starting option is * * proportional fonts. * * * * char * currFont - ASCII string that contains the name * * of the currently selected font. * * * * Returns: * * * * pointer to an ASCII character string that contains the name of * * the selected font (in X format for naming fonts); it is the users * * responsibility to free the space allocated to this string. * * * * Comments: * * * * The calling function has to call the appropriate routines to set * * the current font to the one represented by the returned string. * * * *******************************************************************************/ /* constant values for controlling the proportional font toggle */ #define ONLY_FIXED 0 #define PREF_FIXED 1 #define PREF_PROP 2 /* function prototype */ char *FontSel(Widget parent, int showPropFont, const char *currFont, Pixel sampleFG, Pixel sampleBG); #endif /* NEDIT_FONTSEL_H_INCLUDED */ nedit-5.6.orig/util/getfiles.c0000644000175000017500000013326010762026555015052 0ustar paulpaulstatic const char CVSID[] = "$Id: getfiles.c,v 1.37 2008/02/29 16:06:05 tringali Exp $"; /******************************************************************************* * * * Getfiles.c -- File Interface Routines * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * May 23, 1991 * * * * Written by Donna Reid * * * * modified 11/5/91 by JMK: integrated changes made by M. Edel; updated for * * destroy widget problem (took out ManageModalDialog * * call; added comments. * * 10/1/92 by MWE: Added help dialog and fixed a few bugs * * 4/7/93 by DR: Port to VMS * * 6/1/93 by JMK: Integrate Port and changes by MWE to make * * directories "sticky" and a fix to prevent opening * * a directory when no filename was specified * * 6/24/92 by MWE: Made filename list and directory list typeable, * * set initial focus to filename list * * 6/25/93 by JMK: Fix memory leaks found by Purify. * * * * Included are two routines written using Motif for accessing files: * * * * GetExistingFilename presents a FileSelectionBox dialog where users can * * choose an existing file to open. * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "getfiles.h" #include "fileUtils.h" #include "misc.h" #include #include #include #include #include #ifdef VMS #include #include #include "VMSparam.h" #else #include #include #include #ifndef __MVS__ #include #endif #endif /*VMS*/ #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #define MAX_ARGS 20 /* Maximum number of X arguments */ #define PERMS 0666 /* UNIX file permission, RW for owner, group, world */ #define MAX_LIST_KEYSTROKES 100 /* Max # of keys user can type to a file list */ #define MAX_LIST_KESTROKE_WAIT 2000 /* Allowable delay in milliseconds between characters typed to a list before starting over (throwing out the accumulated characters */ #define SET_ONE_RSRC(widget, name, newValue) \ { \ static Arg tmpargs[1] = {{name, (XtArgVal)0}}; \ tmpargs[0].value = (XtArgVal)newValue; \ XtSetValues(widget, tmpargs, 1); \ } enum yesNoValues {ynNone, ynYes, ynNo}; /* Saved default directory and pattern from last successful call */ static XmString DefaultDirectory = NULL; static XmString DefaultPattern = NULL; /* User settable option for leaving the file name text field in GetExistingFilename dialogs. Off by default so new users will get used to typing in the list rather than in the text field */ static int RemoveRedundantTextField = True; /* Text for help button help display */ /* ... needs variant for VMS */ #ifndef SGI_CUSTOM static const char *HelpExist = "The file open dialog shows a list of directories on the left, and a list \ of files on the right. Double clicking on a file name in the list on the \ right, or selecting it and pressing the OK button, will open that file. \ Double clicking on a directory name, or selecting \ it and pressing \"Filter\", will move into that directory. To move upwards in \ the directory tree, double click on the directory entry ending in \"..\". \ You can also begin typing a file name to select from the file list, or \ directly type in directory and file specifications in the \ field labeled \"Filter\".\n\ \n\ If you use the filter field, remember to include \ either a file name, \"*\" is acceptable, or a trailing \"/\". If \ you don't, the name after the last \"/\" is interpreted as the file name to \ match. When you leave off the file name or trailing \"/\", you won't see \ any files to open in the list \ because the filter specification matched the directory file itself, rather \ than the files in the directory."; static const char *HelpNew = "This dialog allows you to create a new file, or to save the current file \ under a new name. To specify a file \ name in the current directory, complete the name displayed in the \"Save File \ As:\" field near the bottom of the dialog. If you delete or change \ the path shown in the field, the file will be saved using whatever path \ you type, provided that it is a valid Unix file specification.\n\ \n\ To replace an existing file, select it from the Files list \ and press \"OK\", or simply double click on the name.\n\ \n\ To save a file in another directory, use the Directories list \ to move around in the file system hierarchy. Double clicking on \ directory names in the list, or selecting them and pressing the \ \"Filter\" button will select that directory. To move upwards \ in the directory tree, double \ click on the directory entry ending in \"..\". You can also move directly \ to a directory by typing the file specification of the path in the \"Filter\" \ field and pressing the \"Filter\" button."; #else /* SGI_CUSTOM */ static const char *HelpExist = "The \"File to Edit:\" field shows a list of directories and files in the \ current directory.\n\ \n\ Double clicking on a file name in the list, or selecting it and pressing \ the OK button, will open that file.\n\ \n\ Double clicking on a directory name, or selecting it and pressing the OK \ button will move into that directory. To navigate upwards in the file \ system hierarchy you can use the buttons above the \"Selection\" field \ (each of these buttons represent a directory level). \n\ \n\ You can also enter a file or directory name to open in the field \ labeled \"Selection\". Pressing the space bar will complete a partial file \ name, or beep if no files match. The drop pocket to the right of the field \ will accept icons dragged from the desktop, and the button with the circular \ arrows, to the right, of the field recalls previously selected \ directories.\n\ \n\ The \"Filter\" button allows you to narrow down the list of files and \ directories shown in the \"File to Edit:\" field. The default filter of \ \"*\" allows all files to be listed."; static const char *HelpNew = "This dialog allows you to create a new file or to save the current file \ under a new name.\n\ \n\ To specify a file name in the current directory, complete the name displayed \ in the \"Save File As:\" field. If you delete or change the path shown \ in the field, the file will be saved using whatever path you type, provided \ that it is a valid Unix file specification.\n\ \n\ To replace an existing file, select it from the \"Files\" list and press \ \"OK\", or simply double click on the name in the \"Files\" list.\n\ \n\ To save a file in another directory, use the \"Files\" list to move around \ in the file system hierarchy. Double clicking on a directory name, or \ selecting it and pressing the OK button, will move into that directory. \ To navigate upwards in the file system hierarchy you can use the buttons \ above the \"Selection\" field (each of these buttons represent a directory \ level).\n\ \n\ You can also move directly to a directory by typing the file specification \ of the path in the \"Save File As:\" field. Pressing the space bar will \ complete a partial directory or file \ name, or beep if nothing matches. The drop pocket to the right of the field \ will accept icons dragged from the desktop, and the button with the circular \ arrows, to the right, of the field recalls previously selected \ directories.\n\ \n\ The \"Filter\" button allows you to narrow down the list of files and \ directories shown in the \"Files\" field. The default filter of \ \"*\" allows all files to be listed."; #endif /* SGI_CUSTOM */ /* Local Callback Routines and variables */ static void newFileOKCB(Widget w, Boolean *client_data, XmFileSelectionBoxCallbackStruct *call_data); static void newFileCancelCB(Widget w, Boolean *client_data, caddr_t call_data); static void newHelpCB(Widget w, Widget helpPanel, caddr_t call_data); static void createYesNoDialog(Widget parent); static void createErrorDialog(Widget parent); static int doYesNoDialog(const char *msg); static void doErrorDialog(const char *errorString, const char *filename); static void existOkCB(Widget w, Boolean * client_data, XmFileSelectionBoxCallbackStruct *call_data); static void existCancelCB(Widget w, Boolean * client_data, caddr_t call_data); static void existHelpCB(Widget w, Widget helpPanel, caddr_t call_data); static void errorOKCB(Widget w, caddr_t client_data, caddr_t call_data); static void yesNoOKCB(Widget w, caddr_t client_data, caddr_t call_data); static void yesNoCancelCB(Widget w, caddr_t client_data, caddr_t call_data); static Widget createPanelHelp(Widget parent, const char *text, const char *title); static void helpDismissCB(Widget w, Widget helpPanel, caddr_t call_data); static void makeListTypeable(Widget listW); static void listCharEH(Widget w, XtPointer callData, XEvent *event, Boolean *continueDispatch); static void replacementDirSearchProc(Widget w, XtPointer searchData); static void replacementFileSearchProc(Widget w, XtPointer searchData); static void sortWidgetList(Widget listWidget); static int compareXmStrings(const void *string1, const void *string2); static int SelectResult = GFN_CANCEL; /* Initialize results as cancel */ static Widget YesNoDialog; /* "Overwrite?" dialog widget */ static int YesNoResult; /* Result of overwrite dialog */ static Widget ErrorDialog; /* Dialog widget for error msgs */ static int ErrorDone; /* Flag to mark dialog completed */ static void (*OrigDirSearchProc)(); /* Built in Motif directory search */ static void (*OrigFileSearchProc)(); /* Built in Motif file search proc */ /* * Do the hard work of setting up a file selection dialog */ Widget getFilenameHelper(Widget parent, char *promptString, char *filename, int existing) { int n; /* number of arguments */ Arg args[MAX_ARGS]; /* arg list */ Widget fileSB; /* widget file select box */ XmString titleString; /* compound string for dialog title */ n = 0; titleString = XmStringCreateSimple(promptString); XtSetArg(args[n], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); n++; XtSetArg(args[n], XmNdialogTitle, titleString); n++; fileSB = CreateFileSelectionDialog(parent,"FileSelect",args,n); XmStringFree(titleString); #ifndef SGI_CUSTOM if (existing && RemoveRedundantTextField) XtUnmanageChild(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_TEXT)); XtUnmanageChild(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_SELECTION_LABEL)); XtVaSetValues(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_FILTER_LABEL), XmNmnemonic, 'l', XmNuserData, XmFileSelectionBoxGetChild(fileSB, XmDIALOG_FILTER_TEXT), NULL); XtVaSetValues(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_DIR_LIST_LABEL), XmNmnemonic, 'D', XmNuserData, XmFileSelectionBoxGetChild(fileSB, XmDIALOG_DIR_LIST), NULL); XtVaSetValues(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_LIST_LABEL), XmNmnemonic, promptString[strspn(promptString, "lD")], XmNuserData, XmFileSelectionBoxGetChild(fileSB, XmDIALOG_LIST), NULL); AddDialogMnemonicHandler(fileSB, FALSE); RemapDeleteKey(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_FILTER_TEXT)); RemapDeleteKey(XmFileSelectionBoxGetChild(fileSB, XmDIALOG_TEXT)); #endif return fileSB; } /* GetExistingFilename */ /* */ /* This routine will popup a file selection box so that the user can */ /* select an existing file from the scrollable list. The user is */ /* prevented from entering a new filename because the edittable text */ /* area of the file selection box widget is unmanaged. After the user */ /* selects a file, GetExistingFilename returns the selected filename and */ /* GFN_OK, indicating that the OK button was pressed. If the user */ /* pressed the cancel button, the return value is GFN_CANCEL, and the */ /* filename character string supplied in the call is not altered. */ /* */ /* Arguments: */ /* */ /* Widget parent - parent widget id */ /* char * promptString - prompt string */ /* char * filename - a string to receive the selected filename */ /* (this string will not be altered if the */ /* user pressed the cancel button) */ /* */ /* Returns: GFN_OK - file was selected and OK button pressed */ /* GFN_CANCEL - Cancel button pressed and no returned file */ /* */ int GetExistingFilename(Widget parent, char *promptString, char *filename) { Widget existFileSB = getFilenameHelper(parent, promptString, filename, True); return HandleCustomExistFileSB(existFileSB, filename); } /* GetNewFilename * * Same as GetExistingFilename but pick a new file instead of an existing one. * In this case the text area of the FSB is *not* unmanaged, so the user can * enter a new filename. */ int GetNewFilename(Widget parent, char *promptString, char *filename, char *defaultName) { Widget fileSB = getFilenameHelper(parent, promptString, filename, False); return HandleCustomNewFileSB(fileSB, filename, defaultName); } /* ** HandleCustomExistFileSB ** ** Manage a customized file selection box for opening existing files. ** Use this if you want to change the standard file selection dialog ** from the defaults provided in GetExistingFilename, but still ** want take advantage of the button processing, help messages, and ** file checking of GetExistingFilename. ** ** Arguments: ** ** Widget existFileSB - your custom file selection box widget id ** char * filename - a string to receive the selected filename ** (this string will not be altered if the ** user pressed the cancel button) ** ** Returns: GFN_OK - file was selected and OK button pressed ** GFN_CANCEL - Cancel button pressed and no returned file ** */ int HandleCustomExistFileSB(Widget existFileSB, char *filename) { Boolean done_with_dialog=False; /* ok to destroy dialog flag */ char *fileString; /* C string for file selected */ char *dirString; /* C string for dir of file selected */ XmString cFileString; /* compound string for file selected */ XmString cDir; /* compound directory selected */ XmString cPattern; /* compound filter pattern */ Widget help; /* help window form dialog */ #if XmVersion < 1002 int i; #endif XtAddCallback(existFileSB, XmNokCallback, (XtCallbackProc)existOkCB, &done_with_dialog); XtAddCallback(existFileSB, XmNcancelCallback, (XtCallbackProc)existCancelCB, &done_with_dialog); AddMotifCloseCallback(XtParent(existFileSB), (XtCallbackProc)existCancelCB, &done_with_dialog); help = createPanelHelp(existFileSB, HelpExist, "Selecting Files to Open"); createErrorDialog(existFileSB); XtAddCallback(existFileSB, XmNhelpCallback, (XtCallbackProc)existHelpCB, (char *)help); if (DefaultDirectory != NULL || DefaultPattern != NULL) XtVaSetValues(existFileSB, XmNdirectory, DefaultDirectory, XmNpattern, DefaultPattern, NULL); #ifndef SGI_CUSTOM makeListTypeable(XmFileSelectionBoxGetChild(existFileSB,XmDIALOG_LIST)); makeListTypeable(XmFileSelectionBoxGetChild(existFileSB,XmDIALOG_DIR_LIST)); #if XmVersion >= 1002 XtVaSetValues(existFileSB, XmNinitialFocus, XtParent( XmFileSelectionBoxGetChild(existFileSB, XmDIALOG_LIST)), NULL); #endif #endif ManageDialogCenteredOnPointer(existFileSB); #ifndef SGI_CUSTOM /* Typing in the directory list is dependent on the list being in the same form of alphabetical order expected by the character processing routines. As of about 1.2.3, some Motif libraries seem to have a different idea of ordering than is usual for Unix directories. To sort them properly, we have to patch the directory and file searching routines to re-sort the lists when they change */ XtVaGetValues(existFileSB, XmNdirSearchProc, &OrigDirSearchProc, XmNfileSearchProc, &OrigFileSearchProc, NULL); XtVaSetValues(existFileSB, XmNdirSearchProc, replacementDirSearchProc, XmNfileSearchProc, replacementFileSearchProc, NULL); sortWidgetList(XmFileSelectionBoxGetChild(existFileSB, XmDIALOG_DIR_LIST)); sortWidgetList(XmFileSelectionBoxGetChild(existFileSB, XmDIALOG_LIST)); #if XmVersion < 1002 /* To give file list initial focus, revoke default button status for the "OK" button. Dynamic defaulting will restore it as the default button after the keyboard focus is established. Note the voodoo below: calling XmProcess traversal extra times (a recommendation from OSF technical support) somehow succeedes in giving the file list focus */ XtVaSetValues(existFileSB, XmNdefaultButton, NULL, NULL); for (i=1; i<30; i++) XmProcessTraversal(XmFileSelectionBoxGetChild(existFileSB, XmDIALOG_LIST), XmTRAVERSE_CURRENT); #endif #endif /* SGI_CUSTOM */ while (!done_with_dialog) XtAppProcessEvent(XtWidgetToApplicationContext(existFileSB), XtIMAll); if (SelectResult == GFN_OK) { XtVaGetValues(existFileSB, XmNdirSpec, &cFileString, XmNdirectory, &cDir, XmNpattern, &cPattern, NULL); /* Undocumented: file selection box widget allocates copies of these strings on getValues calls. I have risked freeing them to avoid memory leaks, since I assume other developers have made this same realization, therefore OSF can't easily go back and change it */ if (DefaultDirectory != NULL) XmStringFree(DefaultDirectory); if (DefaultPattern != NULL) XmStringFree(DefaultPattern); DefaultDirectory = cDir; DefaultPattern = cPattern; XmStringGetLtoR(cFileString, XmSTRING_DEFAULT_CHARSET, &fileString); /* Motif 2.x seem to contain a bug that causes it to return only the relative name of the file in XmNdirSpec when XmNpathMode is set to XmPATH_MODE_RELATIVE (through X resources), although the man page states that it always returns the full path name. We can easily work around this by checking that the first character of the file name is a `/'. */ #ifdef VMS /* VMS won't return `/' as the 1st character of the full file spec. `:' terminates the device name and is not allowed elsewhere */ if (strchr(fileString, ':') != NULL) { #else if (fileString[0] == '/') { #endif /* VMS */ /* The directory name is already present in the file name or the user entered a full path name. */ strcpy(filename, fileString); } else { /* Concatenate the directory name and the file name */ XmStringGetLtoR(cDir, XmSTRING_DEFAULT_CHARSET, &dirString); strcpy(filename, dirString); strcat(filename, fileString); XtFree(dirString); } XmStringFree(cFileString); XtFree(fileString); } /* Destroy the dialog _shell_ iso. the dialog. Normally, this shouldn't be necessary as the shell is destroyed automatically when the dialog is. However, due to a bug in various Lesstif versions, the latter messes up the grab cascades and leaves new windows without grabs, such that they appear to be frozen. */ XtDestroyWidget(XtParent(existFileSB)); return SelectResult; } /* ** HandleCustomNewFileSB ** ** Manage a customized file selection box for opening new files. ** ** Arguments: ** ** Widget newFileSB - your custom file selection box widget id ** char * filename - a string to receive the selected filename ** (this string will not be altered if the ** user pressed the cancel button) ** char* defaultName - default name to be pre-entered in filename ** text field. ** ** Returns: GFN_OK - file was selected and OK button pressed ** GFN_CANCEL - Cancel button pressed and no returned file ** */ int HandleCustomNewFileSB(Widget newFileSB, char *filename, char *defaultName) { Boolean done_with_dialog=False; /* ok to destroy dialog flag */ Widget help; /* help window form dialog */ XmString cFileString; /* compound string for file selected */ XmString cDir; /* compound directory selected */ XmString cPattern; /* compound filter pattern */ char *fileString; /* C string for file selected */ char *dirString; /* C string for dir of file selected */ #if XmVersion < 1002 int i; #endif XtAddCallback(newFileSB, XmNokCallback, (XtCallbackProc)newFileOKCB, &done_with_dialog); XtAddCallback(newFileSB, XmNcancelCallback, (XtCallbackProc)newFileCancelCB, &done_with_dialog); #ifndef SGI_CUSTOM makeListTypeable(XmFileSelectionBoxGetChild(newFileSB,XmDIALOG_LIST)); makeListTypeable(XmFileSelectionBoxGetChild(newFileSB,XmDIALOG_DIR_LIST)); #endif if (DefaultDirectory != NULL || DefaultPattern != NULL) XtVaSetValues(newFileSB, XmNdirectory, DefaultDirectory, XmNpattern, DefaultPattern, NULL); help = createPanelHelp(newFileSB, HelpNew, "Saving a File"); createYesNoDialog(newFileSB); createErrorDialog(newFileSB); XtAddCallback(newFileSB, XmNhelpCallback, (XtCallbackProc)newHelpCB, (char *)help); #if XmVersion >= 1002 #ifndef SGI_CUSTOM XtVaSetValues(newFileSB, XmNinitialFocus, XmFileSelectionBoxGetChild(newFileSB, XmDIALOG_TEXT), NULL); #else /* SGI_CUSTOM */ { Widget finder = XmFileSelectionBoxGetChild(newFileSB, SgDIALOG_FINDER); if ( finder != NULL ) XtVaSetValues(newFileSB, XmNinitialFocus, finder, NULL); } #endif #endif ManageDialogCenteredOnPointer(newFileSB); #ifndef SGI_CUSTOM #if XmVersion < 1002 /* To give filename text initial focus, revoke default button status for the "OK" button. Dynamic defaulting will restore it as the default button after the keyboard focus is established. Note the voodoo below: calling XmProcess traversal FOUR times (a recommendation from OSF technical support) somehow succeedes in changing the focus */ XtVaSetValues(newFileSB, XmNdefaultButton, NULL, NULL); for (i=1; i<30; i++) XmProcessTraversal(XmFileSelectionBoxGetChild(newFileSB, XmDIALOG_TEXT), XmTRAVERSE_CURRENT); #endif /* Typing in the directory list is dependent on the list being in the same form of alphabetical order expected by the character processing routines. As of about 1.2.3, some Motif libraries seem to have a different idea of ordering than is usual for Unix directories. To sort them properly, we have to patch the directory and file searching routines to re-sort the lists when they change */ XtVaGetValues(newFileSB, XmNdirSearchProc, &OrigDirSearchProc, XmNfileSearchProc, &OrigFileSearchProc, NULL); XtVaSetValues(newFileSB, XmNdirSearchProc, replacementDirSearchProc, XmNfileSearchProc, replacementFileSearchProc, NULL); sortWidgetList(XmFileSelectionBoxGetChild(newFileSB, XmDIALOG_DIR_LIST)); sortWidgetList(XmFileSelectionBoxGetChild(newFileSB, XmDIALOG_LIST)); #endif /* SGI_CUSTOM */ /* Delay the setting of the default name till after the replacement of the search procedures. Otherwise the field is cleared again by certain *tif implementations */ if (defaultName != NULL) { Widget nameField = XmFileSelectionBoxGetChild(newFileSB, XmDIALOG_TEXT); #ifdef LESSTIF_VERSION /* Workaround for Lesstif bug (0.93.94 and possibly other versions): if a proportional font is used for the text field and text is inserted while the dialog is managed, Lesstif crashes because it tries to access a non-existing selection. By creating a temporary dummy selection, the crash is avoided. */ XmTextFieldSetSelection(nameField, 0, 1, CurrentTime); XmTextInsert(nameField, XmTextGetLastPosition(nameField), defaultName); XmTextFieldSetSelection(nameField, 0, 0, CurrentTime); #else XmTextInsert(nameField, XmTextGetLastPosition(nameField), defaultName); #endif } while (!done_with_dialog) XtAppProcessEvent (XtWidgetToApplicationContext(newFileSB), XtIMAll); if (SelectResult == GFN_OK) { /* See note in existing file routines about freeing the values obtained in the following call */ XtVaGetValues(newFileSB, XmNdirSpec, &cFileString, XmNdirectory, &cDir, XmNpattern, &cPattern, NULL); if (DefaultDirectory != NULL) XmStringFree(DefaultDirectory); if (DefaultPattern != NULL) XmStringFree(DefaultPattern); DefaultDirectory = cDir; DefaultPattern = cPattern; XmStringGetLtoR(cFileString, XmSTRING_DEFAULT_CHARSET, &fileString); /* See note in existing file routines about Motif 2.x bug. */ #ifdef VMS /* VMS won't return `/' as the 1st character of the full file spec. `:' terminates the device name and is not allowed elsewhere */ if (strchr(fileString, ':') != NULL) { #else if (fileString[0] == '/') { #endif /* VMS */ /* The directory name is already present in the file name or the user entered a full path name. */ strcpy(filename, fileString); } else { /* Concatenate the directory name and the file name */ XmStringGetLtoR(cDir, XmSTRING_DEFAULT_CHARSET, &dirString); strcpy(filename, dirString); strcat(filename, fileString); XtFree(dirString); } XmStringFree(cFileString); XtFree(fileString); } XtDestroyWidget(newFileSB); return SelectResult; } /* ** Return current default directory used by GetExistingFilename. ** Can return NULL if no default directory has been set (meaning ** use the application's current working directory) String must ** be freed by the caller using XtFree. */ char *GetFileDialogDefaultDirectory(void) { char *string; if (DefaultDirectory == NULL) return NULL; XmStringGetLtoR(DefaultDirectory, XmSTRING_DEFAULT_CHARSET, &string); return string; } /* ** Return current default match pattern used by GetExistingFilename. ** Can return NULL if no default pattern has been set (meaning use ** a pattern matching all files in the directory) String must be ** freed by the caller using XtFree. */ char *GetFileDialogDefaultPattern(void) { char *string; if (DefaultPattern == NULL) return NULL; XmStringGetLtoR(DefaultPattern, XmSTRING_DEFAULT_CHARSET, &string); return string; } /* ** Set the current default directory to be used by GetExistingFilename. ** "dir" can be passed as NULL to clear the current default directory ** and use the application's working directory instead. */ void SetFileDialogDefaultDirectory(char *dir) { if (DefaultDirectory != NULL) XmStringFree(DefaultDirectory); DefaultDirectory = dir==NULL ? NULL : XmStringCreateSimple(dir); } /* ** Set the current default match pattern to be used by GetExistingFilename. ** "pattern" can be passed as NULL as the equivalent a pattern matching ** all files in the directory. */ void SetFileDialogDefaultPattern(char *pattern) { if (DefaultPattern != NULL) XmStringFree(DefaultPattern); DefaultPattern = pattern==NULL ? NULL : XmStringCreateSimple(pattern); } /* ** Turn on or off the text fiend in the GetExistingFilename file selection ** box, where users can enter the filename by typing. This is redundant ** with typing in the list, and leads users who are new to nedit to miss ** the more powerful feature in favor of changing the focus and typing ** in the text field. */ void SetGetEFTextFieldRemoval(int state) { RemoveRedundantTextField = state; } /* ** createYesNoDialog, createErrorDialog, doYesNoDialog, doErrorDialog ** ** Error Messages and question dialogs to be used with the file selection ** box. Due to a crash bug in Motif 1.1.1 thru (at least) 1.1.5 ** getfiles can not use DialogF. According to OSF, there is an error ** in the creation of pushButtonGadgets involving the creation and ** destruction of some sort of temporary object. These routines create ** the dialogs along with the file selection dialog and manage them ** to display messages. This somehow avoids the problem */ static void createYesNoDialog(Widget parent) { XmString buttonString; /* compound string for dialog buttons */ int n; /* number of arguments */ Arg args[MAX_ARGS]; /* arg list */ n = 0; XtSetArg(args[n], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); n++; XtSetArg(args[n], XmNtitle, " "); n++; YesNoDialog = CreateQuestionDialog(parent, "yesNo", args, n); XtAddCallback (YesNoDialog, XmNokCallback, (XtCallbackProc)yesNoOKCB, NULL); XtAddCallback (YesNoDialog, XmNcancelCallback, (XtCallbackProc)yesNoCancelCB, NULL); XtUnmanageChild(XmMessageBoxGetChild (YesNoDialog, XmDIALOG_HELP_BUTTON)); buttonString = XmStringCreateSimple("Yes"); SET_ONE_RSRC(YesNoDialog, XmNokLabelString, buttonString); XmStringFree(buttonString); buttonString = XmStringCreateSimple("No"); SET_ONE_RSRC(YesNoDialog, XmNcancelLabelString, buttonString); XmStringFree(buttonString); } static void createErrorDialog(Widget parent) { XmString buttonString; /* compound string for dialog button */ int n; /* number of arguments */ Arg args[MAX_ARGS]; /* arg list */ n = 0; XtSetArg(args[n], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); n++; XtSetArg(args[n], XmNtitle, " "); n++; ErrorDialog = CreateErrorDialog(parent, "error", args, n); XtAddCallback(ErrorDialog, XmNcancelCallback, (XtCallbackProc)errorOKCB, NULL); XtUnmanageChild(XmMessageBoxGetChild(ErrorDialog, XmDIALOG_OK_BUTTON)); XtUnmanageChild(XmMessageBoxGetChild(ErrorDialog, XmDIALOG_HELP_BUTTON)); buttonString = XmStringCreateLtoR("OK", XmSTRING_DEFAULT_CHARSET); XtVaSetValues(ErrorDialog, XmNcancelLabelString, buttonString, NULL); XtVaSetValues(XmMessageBoxGetChild(ErrorDialog, XmDIALOG_CANCEL_BUTTON), XmNmarginWidth, BUTTON_WIDTH_MARGIN, NULL); XmStringFree(buttonString); } static int doYesNoDialog(const char *filename) { char string[255]; XmString mString; YesNoResult = ynNone; sprintf(string, "File %s already exists,\nOk to overwrite?", filename); mString = XmStringCreateLtoR(string, XmSTRING_DEFAULT_CHARSET); SET_ONE_RSRC(YesNoDialog, XmNmessageString, mString); XmStringFree(mString); ManageDialogCenteredOnPointer(YesNoDialog); while (YesNoResult == ynNone) XtAppProcessEvent(XtWidgetToApplicationContext(YesNoDialog), XtIMAll); XtUnmanageChild(YesNoDialog); /* Nasty motif bug here, patched around by waiting for a ReparentNotify event (with timeout) before allowing file selection dialog to pop down. If this routine returns too quickly, and the file selection dialog (and thereby, this dialog as well) are destroyed while X is still sorting through the events generated by the pop-down, something bad happens and we get a crash */ if (YesNoResult == ynYes) PopDownBugPatch(YesNoDialog); return YesNoResult == ynYes; } static void doErrorDialog(const char *errorString, const char *filename) { char string[255]; XmString mString; ErrorDone = False; sprintf(string, errorString, filename); mString = XmStringCreateLtoR(string, XmSTRING_DEFAULT_CHARSET); SET_ONE_RSRC(ErrorDialog, XmNmessageString, mString); XmStringFree(mString); ManageDialogCenteredOnPointer(ErrorDialog); while (!ErrorDone) XtAppProcessEvent (XtWidgetToApplicationContext(ErrorDialog), XtIMAll); XtUnmanageChild(ErrorDialog); } static void newFileOKCB(Widget w, Boolean *client_data, XmFileSelectionBoxCallbackStruct *call_data) { char *filename; /* name of chosen file */ int fd; /* file descriptor */ int length; /* length of file name */ int response; /* response to dialog */ struct stat buf; /* status from fstat */ XmStringGetLtoR(call_data->value, XmSTRING_DEFAULT_CHARSET, &filename); SelectResult = GFN_OK; length = strlen(filename); if (length == 0 || filename[length-1] == '/') { doErrorDialog("Please supply a name for the file", NULL); XtFree(filename); return; } #ifdef VMS if (strchr(filename,';') && (fd = open(filename, O_RDONLY, 0)) != -1) { #else /* not VMS*/ if ((fd = open(filename, O_RDONLY, 0)) != -1) { /* exists */ #endif /*VMS*/ fstat(fd, &buf); close(fd); if (buf.st_mode & S_IFDIR) { doErrorDialog("Error: %s is a directory", filename); XtFree(filename); return; } response = doYesNoDialog(filename); #ifdef VMS if (response) { if (access(filename, 2) != 0) { /* have write/delete access? */ doErrorDialog("Error: can't overwrite %s ", filename); XtFree(filename); return; } } else { #else if (!response) { #endif /*VMS*/ return; } } else { if ((fd = creat(filename, PERMS)) == -1) { doErrorDialog("Error: can't create %s ", filename); XtFree(filename); return; } else { close(fd); remove(filename); } } XtFree(filename); *client_data = True; /* done with dialog */ } static void newFileCancelCB(Widget w, Boolean *client_data, caddr_t call_data) { SelectResult = GFN_CANCEL; *client_data = True; } static void newHelpCB(Widget w, Widget helpPanel, caddr_t call_data) { ManageDialogCenteredOnPointer(helpPanel); } static void existOkCB(Widget w, Boolean * client_data, XmFileSelectionBoxCallbackStruct *call_data) { char *filename; /* name of chosen file */ int fd; /* file descriptor */ int length; /* length of file name */ XmStringGetLtoR(call_data->value, XmSTRING_DEFAULT_CHARSET, &filename); SelectResult = GFN_OK; length = strlen(filename); if (length == 0 || filename[length-1] == '/') { doErrorDialog("Please select a file to open", NULL); XtFree(filename); return; } else if ((fd = open(filename, O_RDONLY,0)) == -1) { doErrorDialog("Error: can't open %s ", filename); XtFree(filename); return; } else close(fd); XtFree(filename); *client_data = True; /* done with dialog */ } static void existCancelCB(Widget w, Boolean * client_data, caddr_t call_data) { SelectResult = GFN_CANCEL; *client_data = True; /* done with dialog */ } static void yesNoOKCB(Widget w, caddr_t client_data, caddr_t call_data) { YesNoResult = ynYes; } static void existHelpCB(Widget w, Widget helpPanel, caddr_t call_data) { ManageDialogCenteredOnPointer(helpPanel); } static void errorOKCB(Widget w, caddr_t client_data, caddr_t call_data) { ErrorDone = True; } static void yesNoCancelCB(Widget w, caddr_t client_data, caddr_t call_data) { YesNoResult = ynNo; } static Widget createPanelHelp(Widget parent, const char *helpText, const char *title) { Arg al[20]; int ac; Widget form, text, button; XmString st1; ac = 0; form = CreateFormDialog(parent, "helpForm", al, ac); ac = 0; XtSetArg (al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++; XtSetArg (al[ac], XmNtopAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNlabelString, st1=XmStringCreateLtoR ("OK", XmSTRING_DEFAULT_CHARSET)); ac++; XtSetArg (al[ac], XmNmarginWidth, BUTTON_WIDTH_MARGIN); ac++; button = XmCreatePushButtonGadget(form, "ok", al, ac); XtAddCallback(button, XmNactivateCallback, (XtCallbackProc)helpDismissCB, (char *)form); XmStringFree(st1); XtManageChild(button); SET_ONE_RSRC(form, XmNdefaultButton, button); ac = 0; XtSetArg(al[ac], XmNrows, 15); ac++; XtSetArg(al[ac], XmNcolumns, 60); ac++; XtSetArg(al[ac], XmNresizeHeight, False); ac++; XtSetArg(al[ac], XmNtraversalOn, False); ac++; XtSetArg(al[ac], XmNwordWrap, True); ac++; XtSetArg(al[ac], XmNscrollHorizontal, False); ac++; XtSetArg(al[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++; XtSetArg(al[ac], XmNeditable, False); ac++; XtSetArg(al[ac], XmNvalue, helpText); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNbottomWidget, button); ac++; text = XmCreateScrolledText(form, "helpText", al, ac); AddMouseWheelSupport(text); XtManageChild(text); SET_ONE_RSRC(XtParent(form), XmNtitle, title); return form; } static void helpDismissCB(Widget w, Widget helpPanel, caddr_t call_data) { XtUnmanageChild(helpPanel); } /* ** Add ability for user to type filenames to a list widget */ static void makeListTypeable(Widget listW) { XtAddEventHandler(listW, KeyPressMask, False, listCharEH, NULL); } /* ** Action procedure for processing characters typed in a list, finds the ** first item matching the characters typed so far. */ static int nKeystrokes = 0; /* Global key stroke history counter */ static void listCharEH(Widget w, XtPointer callData, XEvent *event, Boolean *continueDispatch) { char charString[5], c, *itemString; int nChars, nItems, i, cmp, selectPos, topPos, nVisible; XmString *items; KeySym kSym; char name[MAXPATHLEN], path[MAXPATHLEN]; static char keystrokes[MAX_LIST_KEYSTROKES]; static Time lastKeyTime = 0; /* Get the ascii character code represented by the event */ nChars = XLookupString((XKeyEvent *)event, charString, sizeof(charString), &kSym, NULL); c = charString[0]; /* Process selected control keys, but otherwise ignore the keystroke if it isn't a single printable ascii character */ *continueDispatch = False; if (kSym==XK_BackSpace || kSym==XK_Delete) { nKeystrokes = nKeystrokes > 0 ? nKeystrokes-1 : 0; return; } else if (kSym==XK_Clear || kSym==XK_Cancel || kSym==XK_Break) { nKeystrokes = 0; return; } else if (nChars!=1 || c<0x021 || c>0x07e) { *continueDispatch = True; return; } /* Throw out keystrokes and start keystroke accumulation over from scratch if user waits more than MAX_LIST_KESTROKE_WAIT milliseconds */ if (((XKeyEvent *)event)->time - lastKeyTime > MAX_LIST_KESTROKE_WAIT) nKeystrokes = 0; lastKeyTime = ((XKeyEvent *)event)->time; /* Accumulate the current keystroke, just beep if there are too many */ if (nKeystrokes >= MAX_LIST_KEYSTROKES) XBell(XtDisplay(w), 0); else #ifdef VMS keystrokes[nKeystrokes++] = toupper(c); #else keystrokes[nKeystrokes++] = c; #endif /* Get the items (filenames) in the list widget */ XtVaGetValues(w, XmNitems, &items, XmNitemCount, &nItems, NULL); /* compare them with the accumulated user keystrokes & decide the appropriate line in the list widget to select */ selectPos = 0; for (i=0; i 0) { selectPos = i; break; } } /* Make the selection, and make sure it will be visible */ XmListSelectPos(w, selectPos, True); if (selectPos == 0) /* XmListSelectPos curiously returns 0 for last item */ selectPos = nItems + 1; XtVaGetValues(w, XmNtopItemPosition, &topPos, XmNvisibleItemCount, &nVisible, NULL); if (selectPos < topPos) XmListSetPos(w, selectPos-2 > 1 ? selectPos-2 : 1); else if (selectPos > topPos+nVisible-1) XmListSetBottomPos(w, selectPos+2 <= nItems ? selectPos+2 : 0); /* For LessTif 0.89.9. Obsolete now? */ XmListSelectPos(w, selectPos, True); } /* ** Replacement directory and file search procedures for the file selection ** box to re-sort the items in a standard order. This is a patch, and not ** a very good one, for the problem that in some Motif versions, the directory ** list is sorted differently, such that typing of filenames fails because ** it expects strcmp alphabetical order, as opposed to strcasecmp. Most ** users prefer the old ordering, which is what this enforces, but if ** ifdefs can be found that will correctly predict the ordering and adjust ** listCharEH above, instead of resorting to re-sorting, it should be done. ** This obviously wastes valuable time as the selection box is popping up ** and should be removed. These routines also leak memory like a seive, ** because Motif's inconsistent treatment of memory in list widgets does ** not allow us to free lists that we pass in, and most Motif versions ** don't clean it up properly. */ static void replacementDirSearchProc(Widget w, XtPointer searchData) { Boolean updated; /* Call the original search procedure to do the actual search */ (*OrigDirSearchProc)(w, searchData); /* Refreshing a list clears the keystroke history, even if no update. */ nKeystrokes = 0; XtVaGetValues(w, XmNlistUpdated, &updated, NULL); if (!updated) return; /* Sort the items in the list */ sortWidgetList(XmFileSelectionBoxGetChild(w, XmDIALOG_DIR_LIST)); } static void replacementFileSearchProc(Widget w, XtPointer searchData) { Boolean updated; /* Call the original search procedure to do the actual search */ (*OrigFileSearchProc)(w, searchData); /* Refreshing a list clears the keystroke history, even if no update. */ nKeystrokes = 0; XtVaGetValues(w, XmNlistUpdated, &updated, NULL); if (!updated) return; /* Sort the items in the list */ sortWidgetList(XmFileSelectionBoxGetChild(w, XmDIALOG_LIST)); } /* ** Sort the items in a list widget "listWidget" */ static void sortWidgetList(Widget listWidget) { XmString *items, *sortedItems; int nItems, i; /* OpenMotif 2.3 will crash if we try to replace the items, when they are selected. This function is only called when we refresh the contents anyway. */ XmListDeselectAllItems(listWidget); XtVaGetValues(listWidget, XmNitems, &items, XmNitemCount, &nItems, NULL); sortedItems = (XmString *)XtMalloc(sizeof(XmString) * nItems); for (i=0; i #define GFN_OK 1 /* Get Filename OK constant */ #define GFN_CANCEL 2 /* Get Filename Cancel constant */ int GetExistingFilename(Widget parent, char *promptString, char *filename); int GetNewFilename(Widget parent, char *promptString, char *filename, char *defaultName); int HandleCustomExistFileSB(Widget existFileSB, char *filename); int HandleCustomNewFileSB(Widget newFileSB, char *filename, char *defaultName); char *GetFileDialogDefaultDirectory(void); char *GetFileDialogDefaultPattern(void); void SetFileDialogDefaultDirectory(char *dir); void SetFileDialogDefaultPattern(char *pattern); void SetGetEFTextFieldRemoval(int state); #endif /* NEDIT_GETFILES_H_INCLUDED */ nedit-5.6.orig/util/managedList.c0000644000175000017500000006333710466067224015506 0ustar paulpaulstatic const char CVSID[] = "$Id: managedList.c,v 1.15 2006/08/08 10:59:32 edg Exp $"; /******************************************************************************* * * * managedList.c -- User interface for reorderable list of records * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * November, 1995 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "managedList.h" #include "misc.h" #include "DialogF.h" #include #include #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif /* Common data between the managed list callback functions */ typedef struct { Widget listW, deleteBtn, copyBtn, moveUpBtn, moveDownBtn; void *(*getDialogDataCB)(void *, int, int *, void *); void *getDialogDataArg; void (*setDialogDataCB)(void *, void *); void *setDialogDataArg; void *(*copyItemCB)(void *); void (*freeItemCB)(void *); int (*deleteConfirmCB)(int, void *); void *deleteConfirmArg; int maxItems; int *nItems; void **itemList; int lastSelection; } managedListData; static void destroyCB(Widget w, XtPointer clientData, XtPointer callData); static void deleteCB(Widget w, XtPointer clientData, XtPointer callData); static void copyCB(Widget w, XtPointer clientData, XtPointer callData); static void moveUpCB(Widget w, XtPointer clientData, XtPointer callData); static void moveDownCB(Widget w, XtPointer clientData, XtPointer callData); static int incorporateDialogData(managedListData *ml, int listPos, int explicit); static void updateDialogFromList(managedListData *ml, int selection); static void updateListWidgetItem(managedListData *ml, int listPos); static void listSelectionCB(Widget w, XtPointer clientData, XtPointer callData); static int selectedListPosition(managedListData *ml); static void selectItem(Widget listW, int itemIndex, int updateDialog); static Widget shellOfWidget(Widget w); /* ** Create a user interface to help manage a list of arbitrary data records ** which users can edit, add, delete, and reorder. ** ** The caller creates the overall dialog for presenting the data to the user, ** but embeds the list and button widgets created here (and list management ** code they activate) to handle the organization of the overall list. ** ** This routine creates a form widget containing the buttons and list widget ** with which the user interacts with the list data. ManageListAndButtons ** can be used alternatively to take advantage of the management code with a ** different arrangement of the widgets (this routine puts buttons in a ** column on the left, list on the right) imposed here. ** ** "args" and "argc" are passed to the form widget creation routine, so that ** attachments can be specified for embedding the form in a dialog. ** ** See ManageListAndButtons for a description of the remaining arguments. */ Widget CreateManagedList(Widget parent, char *name, Arg *args, int argC, void **itemList, int *nItems, int maxItems, int nColumns, void *(*getDialogDataCB)(void *, int, int *, void *), void *getDialogDataArg, void (*setDialogDataCB)(void *, void *), void *setDialogDataArg, void (*freeItemCB)(void *)) { int ac; Arg al[20]; XmString s1; Widget form, rowCol, listW; Widget deleteBtn, copyBtn, moveUpBtn, moveDownBtn; XmString *placeholderTable; char *placeholderStr; form = XmCreateForm(parent, name, args, argC); XtManageChild(form); rowCol = XtVaCreateManagedWidget("mlRowCol", xmRowColumnWidgetClass, form, XmNpacking, XmPACK_COLUMN, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); deleteBtn = XtVaCreateManagedWidget("delete", xmPushButtonWidgetClass, rowCol, XmNlabelString, s1=XmStringCreateSimple("Delete"), NULL); XmStringFree(s1); copyBtn = XtVaCreateManagedWidget("copy", xmPushButtonWidgetClass, rowCol, XmNlabelString, s1=XmStringCreateSimple("Copy"), NULL); XmStringFree(s1); moveUpBtn = XtVaCreateManagedWidget("moveUp", xmPushButtonWidgetClass, rowCol, XmNlabelString, s1=XmStringCreateSimple("Move ^"), NULL); XmStringFree(s1); moveDownBtn = XtVaCreateManagedWidget("moveDown", xmPushButtonWidgetClass, rowCol, XmNlabelString, s1=XmStringCreateSimple("Move v"), NULL); XmStringFree(s1); /* AFAIK the only way to make a list widget n-columns wide is to make up a fake initial string of that width, and create it with that */ placeholderStr = XtMalloc(nColumns+1); memset(placeholderStr, 'm', nColumns); placeholderStr[nColumns] = '\0'; placeholderTable = StringTable(1, placeholderStr); XtFree(placeholderStr); ac = 0; XtSetArg(al[ac], XmNscrollBarDisplayPolicy, XmAS_NEEDED); ac++; XtSetArg(al[ac], XmNlistSizePolicy, XmCONSTANT); ac++; XtSetArg(al[ac], XmNitems, placeholderTable); ac++; XtSetArg(al[ac], XmNitemCount, 1); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNleftWidget, rowCol); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++; listW = XmCreateScrolledList(form, "list", al, ac); AddMouseWheelSupport(listW); XtManageChild(listW); FreeStringTable(placeholderTable); return ManageListAndButtons(listW, deleteBtn, copyBtn, moveUpBtn, moveDownBtn, itemList, nItems, maxItems, getDialogDataCB, getDialogDataArg, setDialogDataCB, setDialogDataArg, freeItemCB); } /* ** Manage a list widget and a set of buttons which represent a list of ** records. The caller provides facilities for editing the records ** individually, and this code handles the organization of the overall list, ** such that the user can modify, add, and delete records, and re-order the ** list. ** ** The format for the list of records managed by this code should be an ** array of size "maxItems" of pointers to record structures. The records ** themselves can be of any format, but the first field of the structure ** must be a pointer to a character string which will be displayed as the ** item name in the list. The list "itemList", and the number of items ** "nItems" are automatically updated by the list management routines as the ** user makes changes. ** ** The caller must provide routines for transferring data to and from the ** dialog fields dedicated to displaying and editing records in the list. ** The callback "setDialogDataCB" must take the contents of the item pointer ** passed to it, and display the data it contains, erasing any previously ** displayed data. The format of the setDialogData callback is: ** ** void setDialogDataCB(void *item, void *cbArg) ** ** item: a pointer to the record to be displayed ** ** cbArg: an arbitrary argument passed on to the callback routine ** ** The callback "setDialogDataCB" must allocate (with XtMalloc) and return a ** new record reflecting the current contents of the dialog fields. It may ** do error checking on the data that the user has entered, and can abort ** whatever operation triggered the request by setting "abort" to True. ** This routine is called in a variety of contexts, such as the user ** clicking on a list item, or requesting that a copy be made of the current ** list item. To aide in communicating errors to the user, the boolean value ** "explicitRequest" distinguishes between the case where the user has ** specifically requested that the fields be read, and the case where he ** may be surprised that errors are being reported, and require further ** explanation. The format of the getDialogData callback is: ** ** void *getDialogDataCB(void *oldItem, int explicitRequest, int *abort, ** void *cbArg) ** ** oldItem: a pointer to the existing record being modified in the ** dialog, or NULL, if the user is modifying the "New" item. ** ** explicitRequest: True if the user directly asked for the records ** to be changed (as with an OK or Apply button). If a less direct ** process resulted in the request, the user might need extra ** explanation and possibly a chance to proceed using the existing ** stored data (to use the data from oldItem, the routine should ** make a new copy). ** ** abort: Can be set to True if the dialog fields contain errors. ** Setting abort to True, stops whetever process made the request ** for updating the data in the list from the displayed data, and ** forces the user to remain focused on the currently displayed ** item until he either gives up or gets it right. ** ** cbArg: arbitrary data, passed on from where the callback was ** established in the list creation routines ** ** The return value should be an allocated ** ** The callback "freeItemCB" should free the item passed to it: ** ** void freeItemCB(void *item, void *cbArg) ** ** item: a pointer to the record to be freed ** ** The difference between ManageListAndButtons and CreateManagedList, is that ** in this routine, the caller creates the list and button widgets and passes ** them here so that they be arranged explicitly, rather than relying on the ** default style imposed by CreateManagedList. ManageListAndButtons simply ** attaches the appropriate callbacks to process mouse and keyboard input from ** the widgets. */ Widget ManageListAndButtons(Widget listW, Widget deleteBtn, Widget copyBtn, Widget moveUpBtn, Widget moveDownBtn, void **itemList, int *nItems, int maxItems, void *(*getDialogDataCB)(void *, int, int *, void *), void *getDialogDataArg, void (*setDialogDataCB)(void *, void *), void *setDialogDataArg, void (*freeItemCB)(void *)) { managedListData *ml; /* Create a managedList data structure to hold information about the widgets, callbacks, and current state of the list */ ml = (managedListData *)XtMalloc(sizeof(managedListData)); ml->listW = listW; ml->deleteBtn = deleteBtn; ml->copyBtn = copyBtn; ml->moveUpBtn = moveUpBtn; ml->moveDownBtn = moveDownBtn; ml->getDialogDataCB = NULL; ml->getDialogDataArg = getDialogDataArg; ml->setDialogDataCB = NULL; ml->setDialogDataArg = setDialogDataArg; ml->freeItemCB = freeItemCB; ml->deleteConfirmCB = NULL; ml->deleteConfirmArg = NULL; ml->nItems = nItems; ml->maxItems = maxItems; ml->itemList = itemList; ml->lastSelection = 1; /* Make the managed list data structure accessible from the list widget pointer, and make sure it gets freed when the list is destroyed */ XtVaSetValues(ml->listW, XmNuserData, ml, NULL); XtAddCallback(ml->listW, XmNdestroyCallback, destroyCB, ml); /* Add callbacks for button and list actions */ XtAddCallback(ml->deleteBtn, XmNactivateCallback, deleteCB, ml); XtAddCallback(ml->copyBtn, XmNactivateCallback, copyCB, ml); XtAddCallback(ml->moveUpBtn, XmNactivateCallback, moveUpCB, ml); XtAddCallback(ml->moveDownBtn, XmNactivateCallback, moveDownCB, ml); XtAddCallback(ml->listW, XmNbrowseSelectionCallback, listSelectionCB, ml); /* Initialize the list and buttons (don't set up the callbacks until this is done, so they won't get called on creation) */ updateDialogFromList(ml, -1); ml->getDialogDataCB = getDialogDataCB; ml->setDialogDataCB = setDialogDataCB; return ml->listW; } /* ** Update the currently selected list item from the dialog fields, using ** the getDialogDataCB callback. "explicitRequest" is a boolean value ** passed to on to the getDialogDataCB callback to help set the tone for ** how error messages are presented (see ManageListAndButtons for more ** information). */ int UpdateManagedList(Widget listW, int explicitRequest) { managedListData *ml; /* Recover the pointer to the managed list structure from the widget's userData pointer */ XtVaGetValues(listW, XmNuserData, &ml, NULL); /* Make the update */ return incorporateDialogData(ml, selectedListPosition(ml), explicitRequest); } /* ** Update the displayed list and data to agree with a data list which has ** been changed externally (not by the ManagedList list manager). */ void ChangeManagedListData(Widget listW) { managedListData *ml; /* Recover the pointer to the managed list structure from the widget's userData pointer */ XtVaGetValues(listW, XmNuserData, &ml, NULL); updateDialogFromList(ml, -1); } /* ** Change the selected item in the managed list given the index into the ** list being managed. */ void SelectManagedListItem(Widget listW, int itemIndex) { selectItem(listW, itemIndex, True); } /* ** Return the index of the item currently selected in the list */ int ManagedListSelectedIndex(Widget listW) { managedListData *ml; XtVaGetValues(listW, XmNuserData, &ml, NULL); return selectedListPosition(ml)-2; } /* ** Add a delete-confirmation callback to a managed list. This will be called ** when the user presses the Delete button on the managed list. The callback ** can put up a dialog, and optionally abort the operation by returning False. */ void AddDeleteConfirmCB(Widget listW, int (*deleteConfirmCB)(int, void *), void *deleteConfirmArg) { managedListData *ml; XtVaGetValues(listW, XmNuserData, &ml, NULL); ml->deleteConfirmCB = deleteConfirmCB; ml->deleteConfirmArg = deleteConfirmArg; } /* ** Called on destruction of the list widget */ static void destroyCB(Widget w, XtPointer clientData, XtPointer callData) { /* Free the managed list data structure */ XtFree((char *)clientData); } /* ** Button callbacks: deleteCB, copyCB, moveUpCB, moveDownCB */ static void deleteCB(Widget w, XtPointer clientData, XtPointer callData) { managedListData *ml = (managedListData *)clientData; int i, ind, listPos; /* get the selected list position and the item to be deleted */ listPos = selectedListPosition(ml); ind = listPos-2; /* if there's a delete confirmation callback, call it first, and allow it to request that the operation be aborted */ if (ml->deleteConfirmCB != NULL) if (!(*ml->deleteConfirmCB)(ind, ml->deleteConfirmArg)) return; /* free the item and remove it from the list */ (*ml->freeItemCB)(ml->itemList[ind]); for (i=ind; i<*ml->nItems-1; i++) ml->itemList[i] = ml->itemList[i+1]; (*ml->nItems)--; /* update the list widget and move the selection to the previous item in the list and display the fields appropriate for that entry */ updateDialogFromList(ml, ind-1); } static void copyCB(Widget w, XtPointer clientData, XtPointer callData) { managedListData *ml = (managedListData *)clientData; int i, listPos, abort = False; void *item; /* get the selected list position and the item to be copied */ listPos = selectedListPosition(ml); if (listPos == 1) return; /* can't copy "new" */ if ((*ml->nItems) == ml->maxItems) { DialogF(DF_ERR, shellOfWidget(ml->listW), 1, "Limits exceeded", "Cannot copy item.\nToo many items in list.", "OK"); return; } /* Bring the entry up to date (could result in operation being canceled) */ item = (*ml->getDialogDataCB)(ml->itemList[listPos-2], False, &abort, ml->getDialogDataArg); if (abort) return; if (item != NULL) { (*ml->freeItemCB)(ml->itemList[listPos-2]); ml->itemList[listPos-2] = item; } /* Make a copy by requesting the data again. In case getDialogDataCB() returned a fallback value, the dialog may not be in sync with the internal list. If we _explicitly_ request the data again, we could get an invalid answer. Therefore, we first update the dialog to make sure that we can copy the right data. */ updateDialogFromList(ml, listPos-2); item = (*ml->getDialogDataCB)(ml->itemList[listPos-2], True, &abort, ml->getDialogDataArg); if (abort) return; /* add the item to the item list */ for (i= *ml->nItems; i>=listPos; i--) ml->itemList[i] = ml->itemList[i-1]; ml->itemList[listPos-1] = item; (*ml->nItems)++; /* redisplay the list widget and select the new item */ updateDialogFromList(ml, listPos-1); } static void moveUpCB(Widget w, XtPointer clientData, XtPointer callData) { managedListData *ml = (managedListData *)clientData; int ind, listPos; void *temp; /* get the item index currently selected in the menu item list */ listPos = selectedListPosition(ml); ind = listPos-2; /* Bring the item up to date with the dialog fields (It would be better if this could be avoided, because user errors will be flagged here, but it's not worth re-writing everything for such a trivial point) */ if (!incorporateDialogData(ml, ml->lastSelection, False)) return; /* shuffle the item up in the menu item list */ temp = ml->itemList[ind]; ml->itemList[ind] = ml->itemList[ind-1]; ml->itemList[ind-1] = temp; /* update the list widget and keep the selection on moved item */ updateDialogFromList(ml, ind-1); } static void moveDownCB(Widget w, XtPointer clientData, XtPointer callData) { managedListData *ml = (managedListData *)clientData; int ind, listPos; void *temp; /* get the item index currently selected in the menu item list */ listPos = selectedListPosition(ml); ind = listPos-2; /* Bring the item up to date with the dialog fields (I wish this could be avoided) */ if (!incorporateDialogData(ml, ml->lastSelection, False)) return; /* shuffle the item down in the menu item list */ temp = ml->itemList[ind]; ml->itemList[ind] = ml->itemList[ind+1]; ml->itemList[ind+1] = temp; /* update the list widget and keep the selection on moved item */ updateDialogFromList(ml, ind+1); } /* ** Called when the user clicks on an item in the list widget */ static void listSelectionCB(Widget w, XtPointer clientData, XtPointer callData) { managedListData *ml = (managedListData *)clientData; int ind, listPos = ((XmListCallbackStruct *)callData)->item_position; /* Save the current dialog fields before overwriting them. If there's an error, force the user to go back to the old selection and fix it before proceeding */ if (ml->getDialogDataCB != NULL && ml->lastSelection != 0) { if (!incorporateDialogData(ml, ml->lastSelection, False)) { XmListDeselectAllItems(ml->listW); XmListSelectPos(ml->listW, ml->lastSelection, False); return; } /* reselect item because incorporateDialogData can alter selection */ selectItem(ml->listW, listPos-2, False); } ml->lastSelection = listPos; /* Dim or un-dim buttons at bottom of dialog based on whether the selected item is a menu entry, or "New" */ if (listPos == 1) { XtSetSensitive(ml->copyBtn, False); XtSetSensitive(ml->deleteBtn, False); XtSetSensitive(ml->moveUpBtn, False); XtSetSensitive(ml->moveDownBtn, False); } else { XtSetSensitive(ml->copyBtn, True); XtSetSensitive(ml->deleteBtn, True); XtSetSensitive(ml->moveUpBtn, listPos != 2); XtSetSensitive(ml->moveDownBtn, listPos != *ml->nItems+1); } /* get the index of the item currently selected in the item list */ ind = listPos - 2; /* tell the caller to show the new item */ if (ml->setDialogDataCB != NULL) (*ml->setDialogDataCB)(listPos==1 ? NULL : ml->itemList[ind], ml->setDialogDataArg); } /* ** Incorporate the current contents of the dialog fields into the list ** being managed, and if necessary change the display in the list widget. ** The data is obtained by calling the getDialogDataCB callback, which ** is allowed to reject whatever request triggered the update. If the ** request is rejected, the return value from this function will be False. */ static int incorporateDialogData(managedListData *ml, int listPos, int explicit) { int abort = False; void *item; /* Get the current contents of the dialog fields. Callback will set abort to True if canceled */ item = (*ml->getDialogDataCB)(listPos == 1 ? NULL : ml->itemList[ listPos-2], explicit, &abort, ml->getDialogDataArg); if (abort) return False; if (item == NULL) /* don't modify if fields are empty */ return True; /* If the item is "new" add a new entry to the list, otherwise, modify the entry with the text fields from the dialog */ if (listPos == 1) { if ((*ml->nItems) == ml->maxItems) { DialogF(DF_ERR, shellOfWidget(ml->listW), 1, "Limits exceeded", "Cannot add new item.\nToo many items in list.", "OK"); return False; } ml->itemList[(*ml->nItems)++] = item; updateDialogFromList(ml, *ml->nItems - 1); } else { (*ml->freeItemCB)(ml->itemList[listPos-2]); ml->itemList[listPos-2] = item; updateListWidgetItem(ml, listPos); } return True; } /* ** Update the list widget to reflect the current contents of the managed item ** list, set the item that should now be highlighted, and call getDisplayed ** on the newly selected item to fill in the dialog fields. */ static void updateDialogFromList(managedListData *ml, int selection) { int i; XmString *stringTable; /* On many systems under Motif 1.1 the list widget can't handle items being changed while anything is selected! */ XmListDeselectAllItems(ml->listW); /* Fill in the list widget with the names from the item list */ stringTable = (XmString *)XtMalloc(sizeof(XmString) * (*ml->nItems+1)); stringTable[0] = XmStringCreateSimple("New"); for (i=0; i < *ml->nItems; i++) stringTable[i+1] = XmStringCreateSimple(*(char **)ml->itemList[i]); XtVaSetValues(ml->listW, XmNitems, stringTable, XmNitemCount, *ml->nItems+1, NULL); for (i=0; i < *ml->nItems+1; i++) XmStringFree(stringTable[i]); XtFree((char *)stringTable); /* Select the requested item (indirectly filling in the dialog fields), but don't trigger an update of the last selected item from the current dialog fields */ ml->lastSelection = 0; selectItem(ml->listW, selection, True); } /* ** Update one item of the managed list widget to reflect the current contents ** of the managed item list. */ static void updateListWidgetItem(managedListData *ml, int listPos) { int savedPos; XmString newString[1]; /* save the current selected position (Motif sometimes does stupid things to the selection when a change is made, like selecting the new item if it matches the name of currently selected one) */ savedPos = selectedListPosition(ml); XmListDeselectAllItems(ml->listW); /* update the list */ newString[0] = XmStringCreateSimple(*(char **)ml->itemList[listPos-2]); XmListReplaceItemsPos(ml->listW, newString, 1, listPos); XmStringFree(newString[0]); /* restore the selected position */ XmListSelectPos(ml->listW, savedPos, False); } /* ** Get the position of the selection in the menu item list widget */ static int selectedListPosition(managedListData *ml) { int listPos; int *posList = NULL, posCount = 0; if (!XmListGetSelectedPos(ml->listW, &posList, &posCount)) { fprintf(stderr, "Internal error (nothing selected)"); return 1; } listPos = *posList; XtFree((char *)posList); if (listPos < 1 || listPos > *ml->nItems+1) { fprintf(stderr, "Internal error (XmList bad value)"); return 1; } return listPos; } /* ** Select an item in the list given the list (array) index value. ** If updateDialog is True, trigger a complete dialog update, which ** could potentially reject the change. */ static void selectItem(Widget listW, int itemIndex, int updateDialog) { int topPos, nVisible, selection = itemIndex+2; /* Select the item */ XmListDeselectAllItems(listW); XmListSelectPos(listW, selection, updateDialog); /* If the selected item is not visible, scroll the list */ XtVaGetValues(listW, XmNtopItemPosition, &topPos, XmNvisibleItemCount, &nVisible, NULL); if (selection < topPos) XmListSetPos(listW, selection); else if (selection >= topPos + nVisible) XmListSetPos(listW, selection - nVisible + 1); } static Widget shellOfWidget(Widget w) { while(1) { if (!w) return 0; if (XtIsSubclass(w, shellWidgetClass)) return w; w = XtParent(w); } } nedit-5.6.orig/util/managedList.h0000644000175000017500000000621010144236625015472 0ustar paulpaul/* $Id: managedList.h,v 1.7 2004/11/09 21:58:45 yooden Exp $ */ /******************************************************************************* * * * managedList.h -- Nirvana Editor Managed List Header File * * * * Copyright 2002 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_MANAGEDLIST_H_INCLUDED #define NEDIT_MANAGEDLIST_H_INCLUDED #include Widget CreateManagedList(Widget parent, char *name, Arg *args, int argC, void **itemList, int *nItems, int maxItems, int nColumns, void *(*getDialogDataCB)(void *, int, int *, void *), void *getDialogDataArg, void (*setDialogDataCB)(void *, void *), void *setDialogDataArg, void (*freeItemCB)(void *)); Widget ManageListAndButtons(Widget listW, Widget deleteBtn, Widget copyBtn, Widget moveUpBtn, Widget moveDownBtn, void **itemList, int *nItems, int maxItems, void *(*getDialogDataCB)(void *, int, int *, void *), void *getDialogDataArg, void (*setDialogDataCB)(void *, void *), void *setDialogDataArg, void (*freeItemCB)(void *)); int UpdateManagedList(Widget listW, int explicitRequest); int ManagedListSelectedIndex(Widget listW); void ChangeManagedListData(Widget listW); void SelectManagedListItem(Widget listW, int itemIndex); void AddDeleteConfirmCB(Widget listW, int (*deleteConfirmCB)(int, void *), void *deleteConfirmArg); #endif /* NEDIT_MANAGEDLIST_H_INCLUDED */ nedit-5.6.orig/util/misc.c0000644000175000017500000023341410737527371014211 0ustar paulpaulstatic const char CVSID[] = "$Id: misc.c,v 1.88 2008/01/04 22:11:05 yooden Exp $"; /******************************************************************************* * * * misc.c -- Miscelaneous Motif convenience functions * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 28, 1992 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "misc.h" #include "DialogF.h" #include #include #include #include #include #include #ifdef __unix__ #include #include #endif #ifdef __APPLE__ #ifdef __MACH__ #include #endif #endif #ifdef VMS #include #include #include #endif /*VMS*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #ifndef LESSTIF_VERSION extern void _XmDismissTearOff(Widget w, XtPointer call, XtPointer x); #endif /* structure for passing history-recall data to callbacks */ typedef struct { char ***list; int *nItems; int index; } histInfo; typedef Widget (*MotifDialogCreationCall)(Widget, String, ArgList, Cardinal); /* Maximum size of a history-recall list. Typically never invoked, since user must first make this many entries in the text field, limited for safety, to the maximum reasonable number of times user can hit up-arrow before carpal tunnel syndrome sets in */ #define HISTORY_LIST_TRIM_TO 1000 #define HISTORY_LIST_MAX 2000 /* flags to enable/disable delete key remapping and pointer centered dialogs */ static int RemapDeleteEnabled = True; static int PointerCenteredDialogsEnabled = False; /* bitmap and mask for waiting (wrist-watch) cursor */ #define watch_x_hot 7 #define watch_y_hot 7 #define watch_width 16 #define watch_height 16 static unsigned char watch_bits[] = { 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07, 0x10, 0x08, 0x08, 0x11, 0x04, 0x21, 0x04, 0x21, 0xe4, 0x21, 0x04, 0x20, 0x08, 0x10, 0x10, 0x08, 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07 }; #define watch_mask_width 16 #define watch_mask_height 16 static unsigned char watch_mask_bits[] = { 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfc, 0x3f, 0xf8, 0x1f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f }; static void addMnemonicGrabs(Widget addTo, Widget w, int unmodified); static void mnemonicCB(Widget w, XtPointer callData, XKeyEvent *event); static void findAndActivateMnemonic(Widget w, unsigned int keycode); static void addAccelGrabs(Widget topWidget, Widget w); static void addAccelGrab(Widget topWidget, Widget w); static int parseAccelString(Display *display, const char *string, KeySym *keysym, unsigned int *modifiers); static void lockCB(Widget w, XtPointer callData, XEvent *event, Boolean *continueDispatch); static int findAndActivateAccel(Widget w, unsigned int keyCode, unsigned int modifiers, XEvent *event); static void removeWhiteSpace(char *string); static int stripCaseCmp(const char *str1, const char *str2); static void warnHandlerCB(String message); static void histDestroyCB(Widget w, XtPointer clientData, XtPointer callData); static void histArrowKeyEH(Widget w, XtPointer callData, XEvent *event, Boolean *continueDispatch); static ArgList addParentVisArgs(Widget parent, ArgList arglist, Cardinal *argcount); static Widget addParentVisArgsAndCall(MotifDialogCreationCall callRoutine, Widget parent, char *name, ArgList arglist, Cardinal argcount); static void scrollDownAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void scrollUpAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void pageDownAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static void pageUpAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); static long queryDesktop(Display *display, Window window, Atom deskTopAtom); static void warning(const char* mesg); static void microsleep(long usecs); /* ** Set up closeCB to be called when the user selects close from the ** window menu. The close menu item usually activates f.kill which ** sends a WM_DELETE_WINDOW protocol request for the window. */ void AddMotifCloseCallback(Widget shell, XtCallbackProc closeCB, void *arg) { static Atom wmpAtom, dwAtom = 0; Display *display = XtDisplay(shell); /* deactivate the built in delete response of killing the application */ XtVaSetValues(shell, XmNdeleteResponse, XmDO_NOTHING, NULL); /* add a delete window protocol callback instead */ if (dwAtom == 0) { wmpAtom = XmInternAtom(display, "WM_PROTOCOLS", FALSE); dwAtom = XmInternAtom(display, "WM_DELETE_WINDOW", FALSE); } XmAddProtocolCallback(shell, wmpAtom, dwAtom, closeCB, arg); } /* ** Motif still generates spurious passive grab warnings on both IBM and SGI ** This routine suppresses them. ** (amai, 20011121:) ** And triggers an annoying message on DEC systems on alpha -> ** See Xt sources, xc/lib/Xt/Error.c:DefaultMsg()): ** actually for some obscure reasons they check for XtError/Warning ** handlers being installed when running as a root process! ** Since this handler doesn't help on non-effected systems we should only ** use it if necessary. */ void SuppressPassiveGrabWarnings(void) { #if !defined(__alpha) && !defined(__EMX__) XtSetWarningHandler(warnHandlerCB); #endif } /* ** This routine kludges around the problem of backspace not being mapped ** correctly when Motif is used between a server with a delete key in ** the traditional typewriter backspace position and a client that ** expects a backspace key in that position. Though there are three ** distinct levels of key re-mapping in effect when a user is running ** a Motif application, none of these is really appropriate or effective ** for eliminating the delete v.s. backspace problem. Our solution is, ** sadly, to eliminate the forward delete functionality of the delete key ** in favor of backwards delete for both keys. So as not to prevent the ** user or the application from applying other translation table re-mapping, ** we apply re-map the key as a post-processing step, applied after widget ** creation. As a result, the re-mapping necessarily becomes embedded ** throughout an application (wherever text widgets are created), and ** within library routines, including the Nirvana utility library. To ** make this remapping optional, the SetDeleteRemap function provides a ** way for an application to turn this functionality on and off. It is ** recommended that applications that use this routine provide an ** application resource called remapDeleteKey so savvy users can get ** their forward delete functionality back. */ void RemapDeleteKey(Widget w) { static XtTranslations table = NULL; static char *translations = "~Shift~Ctrl~Meta~AltosfDelete: delete-previous-character()\n"; if (RemapDeleteEnabled) { if (table == NULL) table = XtParseTranslationTable(translations); XtOverrideTranslations(w, table); } } void SetDeleteRemap(int state) { RemapDeleteEnabled = state; } /* ** The routine adds the passed in top-level Widget's window to our ** window group. On the first call a dummy unmapped window will ** be created to be our leader. This must not be called before the ** Widget has be realized and should be called before the window is ** mapped. */ static void setWindowGroup(Widget shell) { static int firstTime = True; static Window groupLeader; Display *display = XtDisplay(shell); XWMHints *wmHints; if (firstTime) { /* Create a dummy window to be the group leader for our windows */ String name, class; XClassHint *classHint; groupLeader = XCreateSimpleWindow(display, RootWindow(display, DefaultScreen(display)), 1, 1, 1, 1, 0, 0, 0); /* Set it's class hint so it will be identified correctly by the window manager */ XtGetApplicationNameAndClass(display, &name, &class); classHint = XAllocClassHint(); classHint->res_name = name; classHint->res_class = class; XSetClassHint(display, groupLeader, classHint); XFree(classHint); firstTime = False; } /* Set the window group hint for this shell's window */ wmHints = XGetWMHints(display, XtWindow(shell)); wmHints->window_group = groupLeader; wmHints->flags |= WindowGroupHint; XSetWMHints(display, XtWindow(shell), wmHints); XFree(wmHints); } /* ** This routine resolves a window manager protocol incompatibility between ** the X toolkit and several popular window managers. Using this in place ** of XtRealizeWidget will realize the window in a way which allows the ** affected window managers to apply their own placement strategy to the ** window, as opposed to forcing the window to a specific location. ** ** One of the hints in the WM_NORMAL_HINTS protocol, PPlacement, gets set by ** the X toolkit (probably part of the Core or Shell widget) when a shell ** widget is realized to the value stored in the XmNx and XmNy resources of the ** Core widget. While callers can set these values, there is no "unset" value ** for these resources. On systems which are more Motif aware, a PPosition ** hint of 0,0, which is the default for XmNx and XmNy, is interpreted as, ** "place this as if no hints were specified". Unfortunately the fvwm family ** of window managers, which are now some of the most popular, interpret this ** as "place this window at (0,0)". This routine intervenes between the ** realizing and the mapping of the window to remove the inappropriate ** PPlacement hint. */ void RemovePPositionHint(Widget shell) { XSizeHints *hints = XAllocSizeHints(); long suppliedHints; /* Get rid of the incorrect WMNormal hint */ if (XGetWMNormalHints(XtDisplay(shell), XtWindow(shell), hints, &suppliedHints)) { hints->flags &= ~PPosition; XSetWMNormalHints(XtDisplay(shell), XtWindow(shell), hints); } XFree(hints); } void RealizeWithoutForcingPosition(Widget shell) { Boolean mappedWhenManaged; /* Temporarily set value of XmNmappedWhenManaged to stop the window from popping up right away */ XtVaGetValues(shell, XmNmappedWhenManaged, &mappedWhenManaged, NULL); XtVaSetValues(shell, XmNmappedWhenManaged, False, NULL); /* Realize the widget in unmapped state */ XtRealizeWidget(shell); /* Remove the hint */ RemovePPositionHint(shell); /* Set WindowGroupHint so the NEdit icons can be grouped; this seems to be necessary starting with Gnome 2.0 */ setWindowGroup(shell); /* Map the widget */ XtMapWidget(shell); /* Restore the value of XmNmappedWhenManaged */ XtVaSetValues(shell, XmNmappedWhenManaged, mappedWhenManaged, NULL); } /* ** Older X applications and X servers were mostly designed to operate with ** visual class PseudoColor, because older displays were at most 8 bits ** deep. Modern X servers, however, usually support 24 bit depth and other ** color models. Sun (and others?) still sets their default visual to ** 8-bit PseudoColor, because some of their X applications don't work ** properly with the other color models. The problem with PseudoColor, of ** course, is that users run out of colors in the default colormap, and if ** they install additional colormaps for individual applications, colors ** flash and change weirdly when you change your focus from one application ** to another. ** ** In addition to the poor choice of default, a design flaw in Xt makes it ** impossible even for savvy users to specify the XtNvisual resource to ** switch to a deeper visual. The problem is that the colormap resource is ** processed independently of the visual resource, and usually results in a ** colormap for the default visual rather than for the user-selected one. ** ** This routine should be called before creating a shell widget, to ** pre-process the visual, depth, and colormap resources, and return the ** proper values for these three resources to be passed to XtAppCreateShell. ** Applications which actually require a particular color model (i.e. for ** doing color table animation or dynamic color assignment) should not use ** this routine. ** ** Note that a consequence of using the "best" as opposed to the default ** visual is that some color resources are still converted with the default ** visual (particularly *background), and these must be avoided by widgets ** which are allowed to handle any visual. ** ** Returns True if the best visual is the default, False otherwise. */ Boolean FindBestVisual(Display *display, const char *appName, const char *appClass, Visual **visual, int *depth, Colormap *colormap) { char rsrcName[256], rsrcClass[256], *valueString, *type, *endPtr; XrmValue value; int screen = DefaultScreen(display); int reqDepth = -1; long reqID = -1; /* should hold a 'VisualID' and a '-1' ... */ int reqClass = -1; int installColormap = FALSE; int maxDepth, bestClass, bestVisual, nVis, i, j; XVisualInfo visTemplate, *visList = NULL; static Visual *cachedVisual = NULL; static Colormap cachedColormap; static int cachedDepth = 0; int bestClasses[] = {StaticGray, GrayScale, StaticColor, PseudoColor, DirectColor, TrueColor}; /* If results have already been computed, just return them */ if (cachedVisual != NULL) { *visual = cachedVisual; *depth = cachedDepth; *colormap = cachedColormap; return (*visual == DefaultVisual(display, screen)); } /* Read the visualID and installColormap resources for the application. visualID can be specified either as a number (the visual id as shown by xdpyinfo), as a visual class name, or as Best or Default. */ sprintf(rsrcName,"%s.%s", appName, "visualID"); sprintf(rsrcClass, "%s.%s", appClass, "VisualID"); if (XrmGetResource(XtDatabase(display), rsrcName, rsrcClass, &type, &value)) { valueString = value.addr; reqID = (int)strtol(valueString, &endPtr, 0); if (endPtr == valueString) { reqID = -1; if (stripCaseCmp(valueString, "Default")) reqID = DefaultVisual(display, screen)->visualid; else if (stripCaseCmp(valueString, "StaticGray")) reqClass = StaticGray; else if (stripCaseCmp(valueString, "StaticColor")) reqClass = StaticColor; else if (stripCaseCmp(valueString, "TrueColor")) reqClass = TrueColor; else if (stripCaseCmp(valueString, "GrayScale")) reqClass = GrayScale; else if (stripCaseCmp(valueString, "PseudoColor")) reqClass = PseudoColor; else if (stripCaseCmp(valueString, "DirectColor")) reqClass = DirectColor; else if (!stripCaseCmp(valueString, "Best")) fprintf(stderr, "Invalid visualID resource value\n"); } } sprintf(rsrcName,"%s.%s", appName, "installColormap"); sprintf(rsrcClass, "%s.%s", appClass, "InstallColormap"); if (XrmGetResource(XtDatabase(display), rsrcName, rsrcClass, &type, &value)) { if (stripCaseCmp(value.addr, "Yes") || stripCaseCmp(value.addr, "True")) installColormap = TRUE; } visTemplate.screen = screen; /* Generate a list of visuals to consider. (Note, vestigial code for user-requested visual depth is left in, just in case that function might be needed again, but it does nothing). */ if (reqID != -1) { visTemplate.visualid = reqID; visList = XGetVisualInfo(display, VisualScreenMask|VisualIDMask, &visTemplate, &nVis); if (visList == NULL) fprintf(stderr, "VisualID resource value not valid\n"); } if (visList == NULL && reqClass != -1 && reqDepth != -1) { visTemplate.class = reqClass; visTemplate.depth = reqDepth; visList = XGetVisualInfo(display, VisualScreenMask| VisualClassMask | VisualDepthMask, &visTemplate, &nVis); if (visList == NULL) fprintf(stderr, "Visual class/depth combination not available\n"); } if (visList == NULL && reqClass != -1) { visTemplate.class = reqClass; visList = XGetVisualInfo(display, VisualScreenMask|VisualClassMask, &visTemplate, &nVis); if (visList == NULL) fprintf(stderr, "Visual Class from resource \"visualID\" not available\n"); } if (visList == NULL && reqDepth != -1) { visTemplate.depth = reqDepth; visList = XGetVisualInfo(display, VisualScreenMask|VisualDepthMask, &visTemplate, &nVis); if (visList == NULL) fprintf(stderr, "Requested visual depth not available\n"); } if (visList == NULL) { visList = XGetVisualInfo(display, VisualScreenMask, &visTemplate, &nVis); if (visList == NULL) { fprintf(stderr, "Internal Error: no visuals available?\n"); *visual = DefaultVisual(display, screen); *depth = DefaultDepth(display, screen); *colormap = DefaultColormap(display, screen); return True; } } /* Choose among the visuals in the candidate list. Prefer maximum depth first then matching default, then largest value of bestClass (I'm not sure whether we actually care about class) */ maxDepth = 0; bestClass = 0; bestVisual = 0; for (i=0; i < nVis; i++) { /* X.Org 6.8+ 32-bit visuals (with alpha-channel) cause a lot of problems, so we have to skip them. We already try this by setting the environment variable XLIB_SKIP_ARGB_VISUALS at startup (in nedit.c), but that doesn't cover the case where NEdit is running on a host that doesn't use the X.Org X libraries but is displaying remotely on an X.Org server. Therefore, this additional check is added. Note that this check in itself is not sufficient. There have been bug reports that seemed to indicate that non-32-bit visuals with an alpha-channel exist. The combined approach (env. var. + 32-bit check) should cover the vast majority of the cases, though. */ if (visList[i].depth >= 32 && strstr(ServerVendor(display), "X.Org") != 0) { continue; } if (visList[i].depth > maxDepth) { maxDepth = visList[i].depth; bestClass = 0; bestVisual = i; } if (visList[i].depth == maxDepth) { if (visList[i].visual == DefaultVisual(display, screen)) bestVisual = i; if (visList[bestVisual].visual != DefaultVisual(display, screen)) { for (j = 0; j < (int)XtNumber(bestClasses); j++) { if (visList[i].class == bestClasses[j] && j > bestClass) { bestClass = j; bestVisual = i; } } } } } *visual = cachedVisual = visList[bestVisual].visual; *depth = cachedDepth = visList[bestVisual].depth; /* If the chosen visual is not the default, it needs a colormap allocated */ if (*visual == DefaultVisual(display, screen) && !installColormap) *colormap = cachedColormap = DefaultColormap(display, screen); else { *colormap = cachedColormap = XCreateColormap(display, RootWindow(display, screen), cachedVisual, AllocNone); XInstallColormap(display, cachedColormap); } /* printf("Chose visual with depth %d, class %d, colormap %ld, id 0x%x\n", visList[bestVisual].depth, visList[bestVisual].class, *colormap, cachedVisual->visualid); */ /* Fix memory leak */ if (visList != NULL) { XFree(visList); } return (*visual == DefaultVisual(display, screen)); } /* ** If you want to use a non-default visual with Motif, shells all have to be ** created with that visual, depth, and colormap, even if the parent has them ** set up properly. Substituting these routines, will append visual args copied ** from the parent widget (CreatePopupMenu and CreatePulldownMenu), or from the ** best visual, obtained via FindBestVisual above (CreateShellWithBestVis). */ Widget CreateDialogShell(Widget parent, char *name, ArgList arglist, Cardinal argcount) { return addParentVisArgsAndCall(XmCreateDialogShell, parent, name, arglist, argcount); } Widget CreatePopupMenu(Widget parent, char *name, ArgList arglist, Cardinal argcount) { return addParentVisArgsAndCall(XmCreatePopupMenu, parent, name, arglist, argcount); } Widget CreatePulldownMenu(Widget parent, char *name, ArgList arglist, Cardinal argcount) { return addParentVisArgsAndCall(XmCreatePulldownMenu, parent, name, arglist, argcount); } Widget CreatePromptDialog(Widget parent, char *name, ArgList arglist, Cardinal argcount) { return addParentVisArgsAndCall(XmCreatePromptDialog, parent, name, arglist, argcount); } Widget CreateSelectionDialog(Widget parent, char *name, ArgList arglist, Cardinal argcount) { Widget dialog = addParentVisArgsAndCall(XmCreateSelectionDialog, parent, name, arglist, argcount); AddMouseWheelSupport(XmSelectionBoxGetChild(dialog, XmDIALOG_LIST)); return dialog; } Widget CreateFormDialog(Widget parent, char *name, ArgList arglist, Cardinal argcount) { return addParentVisArgsAndCall(XmCreateFormDialog, parent, name, arglist, argcount); } Widget CreateFileSelectionDialog(Widget parent, char *name, ArgList arglist, Cardinal argcount) { Widget dialog = addParentVisArgsAndCall(XmCreateFileSelectionDialog, parent, name, arglist, argcount); AddMouseWheelSupport(XmFileSelectionBoxGetChild(dialog, XmDIALOG_LIST)); AddMouseWheelSupport(XmFileSelectionBoxGetChild(dialog, XmDIALOG_DIR_LIST)); return dialog; } Widget CreateQuestionDialog(Widget parent, char *name, ArgList arglist, Cardinal argcount) { return addParentVisArgsAndCall(XmCreateQuestionDialog, parent, name, arglist, argcount); } Widget CreateMessageDialog(Widget parent, char *name, ArgList arglist, Cardinal argcount) { return addParentVisArgsAndCall(XmCreateMessageDialog, parent, name, arglist, argcount); } Widget CreateErrorDialog(Widget parent, char *name, ArgList arglist, Cardinal argcount) { return addParentVisArgsAndCall(XmCreateErrorDialog, parent, name, arglist, argcount); } Widget CreateWidget(Widget parent, const char *name, WidgetClass class, ArgList arglist, Cardinal argcount) { Widget result; ArgList al = addParentVisArgs(parent, arglist, &argcount); result = XtCreateWidget(name, class, parent, al, argcount); XtFree((char *)al); return result; } Widget CreateShellWithBestVis(String appName, String appClass, WidgetClass class, Display *display, ArgList args, Cardinal nArgs) { Visual *visual; int depth; Colormap colormap; ArgList al; Cardinal ac = nArgs; Widget result; FindBestVisual(display, appName, appClass, &visual, &depth, &colormap); al = (ArgList)XtMalloc(sizeof(Arg) * (nArgs + 3)); if (nArgs != 0) memcpy(al, args, sizeof(Arg) * nArgs); XtSetArg(al[ac], XtNvisual, visual); ac++; XtSetArg(al[ac], XtNdepth, depth); ac++; XtSetArg(al[ac], XtNcolormap, colormap); ac++; result = XtAppCreateShell(appName, appClass, class, display, al, ac); XtFree((char *)al); return result; } Widget CreatePopupShellWithBestVis(String shellName, WidgetClass class, Widget parent, ArgList arglist, Cardinal argcount) { Widget result; ArgList al = addParentVisArgs(parent, arglist, &argcount); result = XtCreatePopupShell(shellName, class, parent, al, argcount); XtFree((char *)al); return result; } /* ** Extends an argument list for widget creation with additional arguments ** for visual, colormap, and depth. The original argument list is not altered ** and it's the caller's responsability to free the returned list. */ static ArgList addParentVisArgs(Widget parent, ArgList arglist, Cardinal *argcount) { Visual *visual; int depth; Colormap colormap; ArgList al; Widget parentShell = parent; /* Find the application/dialog/menu shell at the top of the widget hierarchy, which has the visual resource being used */ while (True) { if (XtIsShell(parentShell)) break; if (parentShell == NULL) { fprintf(stderr, "failed to find shell\n"); exit(EXIT_FAILURE); } parentShell = XtParent(parentShell); } /* Add the visual, depth, and colormap resources to the argument list */ XtVaGetValues(parentShell, XtNvisual, &visual, XtNdepth, &depth, XtNcolormap, &colormap, NULL); al = (ArgList)XtMalloc(sizeof(Arg) * ((*argcount) + 3)); if ((*argcount) != 0) memcpy(al, arglist, sizeof(Arg) * (*argcount)); /* For non-Lesstif versions, the visual, depth, and colormap are now set globally via the resource database. So strictly spoken, it is no longer necessary to set them explicitly for every shell widget. For Lesstif, however, this doesn't work. Luckily, Lesstif handles non-default visuals etc. properly for its own shells and we can take care of things for our shells (eg, call tips) here. */ XtSetArg(al[*argcount], XtNvisual, visual); (*argcount)++; XtSetArg(al[*argcount], XtNdepth, depth); (*argcount)++; XtSetArg(al[*argcount], XtNcolormap, colormap); (*argcount)++; return al; } /* ** Calls one of the Motif widget creation routines, splicing in additional ** arguments for visual, colormap, and depth. */ static Widget addParentVisArgsAndCall(MotifDialogCreationCall createRoutine, Widget parent, char *name, ArgList arglist, Cardinal argcount) { Widget result; ArgList al = addParentVisArgs(parent, arglist, &argcount); result = (*createRoutine)(parent, name, al, argcount); XtFree((char *)al); return result; } /* ** ManageDialogCenteredOnPointer is used in place of XtManageChild for ** popping up a dialog to enable the dialog to be centered under the ** mouse pointer. Whether it pops up the dialog centered under the pointer ** or in its default position centered over the parent widget, depends on ** the value set in the SetPointerCenteredDialogs call. ** Additionally, this function constrains the size of the dialog to the ** screen's size, to avoid insanely wide dialogs with obscured buttons. */ void ManageDialogCenteredOnPointer(Widget dialogChild) { Widget shell = XtParent(dialogChild); Window root, child; unsigned int mask; unsigned int width, height, borderWidth, depth; int x, y, winX, winY, maxX, maxY, maxWidth, maxHeight; Dimension xtWidth, xtHeight; Boolean mappedWhenManaged; static const int slop = 25; /* Temporarily set value of XmNmappedWhenManaged to stop the dialog from popping up right away */ XtVaGetValues(shell, XmNmappedWhenManaged, &mappedWhenManaged, NULL); XtVaSetValues(shell, XmNmappedWhenManaged, False, NULL); /* Ensure that the dialog doesn't get wider/taller than the screen. We use a hard-coded "slop" size because we don't know the border width until it's on screen, and by then it's too late. Putting this before managing the widgets allows it to get the geometry right on the first pass and also prevents the user from accidentally resizing too wide. */ maxWidth = XtScreen(shell)->width - slop; maxHeight = XtScreen(shell)->height - slop; XtVaSetValues(shell, XmNmaxWidth, maxWidth, XmNmaxHeight, maxHeight, NULL); /* Manage the dialog */ XtManageChild(dialogChild); /* Check to see if the window manager doesn't respect XmNmaxWidth and XmNmaxHeight on the first geometry pass (sawfish, twm, fvwm). For this to work XmNresizePolicy must be XmRESIZE_NONE, otherwise the dialog will try to expand anyway. */ XtVaGetValues(shell, XmNwidth, &xtWidth, XmNheight, &xtHeight, NULL); if (xtWidth > maxWidth) XtVaSetValues(shell, XmNwidth, (Dimension) maxWidth, NULL); if (xtHeight > maxHeight) XtVaSetValues(shell, XmNheight, (Dimension) maxHeight, NULL); /* Only set the x/y position if the centering option is enabled. Avoid getting the coordinates if not so, to save a few round-trips to the server. */ if (PointerCenteredDialogsEnabled) { /* Get the pointer position (x, y) */ XQueryPointer(XtDisplay(shell), XtWindow(shell), &root, &child, &x, &y, &winX, &winY, &mask); /* Translate the pointer position (x, y) into a position for the new window that will place the pointer at its center */ XGetGeometry(XtDisplay(shell), XtWindow(shell), &root, &winX, &winY, &width, &height, &borderWidth, &depth); width += 2 * borderWidth; height += 2 * borderWidth; x -= width/2; y -= height/2; /* Ensure that the dialog remains on screen */ maxX = maxWidth - width; maxY = maxHeight - height; if (x > maxX) x = maxX; if (x < 0) x = 0; if (y > maxY) y = maxY; if (y < 0) y = 0; /* Some window managers (Sawfish) don't appear to respond to the geometry set call in synchronous mode. This causes the window to delay XmNwmTimeout (default 5 seconds) before posting, and it is very annoying. See "man VendorShell" for more info. */ XtVaSetValues(shell, XmNuseAsyncGeometry, True, NULL); /* Set desired window position in the DialogShell */ XtVaSetValues(shell, XmNx, x, XmNy, y, NULL); } /* Map the widget */ XtMapWidget(shell); /* Restore the value of XmNmappedWhenManaged */ XtVaSetValues(shell, XmNmappedWhenManaged, mappedWhenManaged, NULL); } /* ** Cause dialogs created by libNUtil.a routines (such as DialogF), ** and dialogs which use ManageDialogCenteredOnPointer to pop up ** over the pointer (state = True), or pop up in their default ** positions (state = False) */ void SetPointerCenteredDialogs(int state) { PointerCenteredDialogsEnabled = state; } /* ** Raise a window to the top and give it the input focus. Setting input focus ** is important on systems which use explict (rather than pointer) focus. ** ** The X alternatives XMapRaised, and XSetInputFocus both have problems. ** XMapRaised only gives the window the focus if it was initially not visible, ** and XSetInputFocus sets the input focus, but crashes if the window is not ** visible. ** ** This routine should also be used in the case where a dialog is popped up and ** subsequent calls to the dialog function use a flag, or the XtIsManaged, to ** decide whether to create a new instance of the dialog, because on slower ** systems, events can intervene while a dialog is still on its way up and its ** window is still invisible, causing a subtle crash potential if ** XSetInputFocus is used. */ void RaiseDialogWindow(Widget shell) { RaiseWindow(XtDisplay(shell), XtWindow(shell), True); } void RaiseShellWindow(Widget shell, Boolean focus) { RaiseWindow(XtDisplay(shell), XtWindow(shell), focus); } void RaiseWindow(Display *display, Window w, Boolean focus) { if (focus) { XWindowAttributes winAttr; XGetWindowAttributes(display, w, &winAttr); if (winAttr.map_state == IsViewable) XSetInputFocus(display, w, RevertToParent, CurrentTime); } XMapRaised(display, w); } /* ** Add a handler for mnemonics in a dialog (Motif currently only handles ** mnemonics in menus) following the example of M.S. Windows. To add ** mnemonics to a dialog, set the XmNmnemonic resource, as you would in ** a menu, on push buttons or toggle buttons, and call this function ** when the dialog is fully constructed. Mnemonics added or changed ** after this call will not be noticed. To add a mnemonic to a text field ** or list, set the XmNmnemonic resource on the appropriate label and set ** the XmNuserData resource of the label to the widget to get the focus ** when the mnemonic is typed. */ void AddDialogMnemonicHandler(Widget dialog, int unmodifiedToo) { XtAddEventHandler(dialog, KeyPressMask, False, (XtEventHandler)mnemonicCB, (XtPointer)0); addMnemonicGrabs(dialog, dialog, unmodifiedToo); } /* ** Removes the event handler and key-grabs added by AddDialogMnemonicHandler */ void RemoveDialogMnemonicHandler(Widget dialog) { XtUngrabKey(dialog, AnyKey, Mod1Mask); XtRemoveEventHandler(dialog, KeyPressMask, False, (XtEventHandler)mnemonicCB, (XtPointer)0); } /* ** Patch around Motif's poor handling of menu accelerator keys. Motif ** does not process menu accelerators when the caps lock or num lock ** keys are engaged. To enable accelerators in these cases, call this ** routine with the completed menu bar widget as "topMenuContainer", and ** the top level shell widget as "topWidget". It will add key grabs for ** all of the accelerators it finds in the topMenuContainer menu tree, and ** an event handler which can process dropped accelerator events by (again) ** traversing the menu tree looking for matching accelerators, and invoking ** the appropriate button actions. Any dynamic additions to the menus ** require a call to UpdateAccelLockPatch to add the additional grabs. ** Unfortunately, these grabs can not be removed. */ void AccelLockBugPatch(Widget topWidget, Widget topMenuContainer) { XtAddEventHandler(topWidget, KeyPressMask, False, lockCB, topMenuContainer); addAccelGrabs(topWidget, topMenuContainer); } /* ** Add additional key grabs for new menu items added to the menus, for ** patching around the Motif Caps/Num Lock problem. "topWidget" must be ** the same widget passed in the original call to AccelLockBugPatch. */ void UpdateAccelLockPatch(Widget topWidget, Widget newButton) { addAccelGrab(topWidget, newButton); } /* ** PopDownBugPatch ** ** Under some circumstances, popping down a dialog and its parent in ** rapid succession causes a crash. This routine delays and ** processs events until receiving a ReparentNotify event. ** (I have no idea why a ReparentNotify event occurs at all, but it does ** mark the point where it is safe to destroy or pop down the parent, and ** it might have something to do with the bug.) There is a failsafe in ** the form of a ~1.5 second timeout in case no ReparentNotify arrives. ** Use this sparingly, only when real crashes are observed, and periodically ** check to make sure that it is still necessary. */ void PopDownBugPatch(Widget w) { time_t stopTime; stopTime = time(NULL) + 1; while (time(NULL) <= stopTime) { XEvent event; XtAppContext context = XtWidgetToApplicationContext(w); XtAppPeekEvent(context, &event); if (event.xany.type == ReparentNotify) return; XtAppProcessEvent(context, XtIMAll); } } /* ** Convert a compound string to a C style null terminated string. ** Returned string must be freed by the caller. */ char *GetXmStringText(XmString fromString) { XmStringContext context; char *text, *toPtr, *toString, *fromPtr; XmStringCharSet charset; XmStringDirection direction; Boolean separator; /* Malloc a buffer large enough to hold the string. XmStringLength should always be slightly longer than necessary, but won't be shorter than the equivalent null-terminated string */ toString = XtMalloc(XmStringLength(fromString)); /* loop over all of the segments in the string, copying each segment into the output string and converting separators into newlines */ XmStringInitContext(&context, fromString); toPtr = toString; while (XmStringGetNextSegment(context, &text, &charset, &direction, &separator)) { for (fromPtr=text; *fromPtr!='\0'; fromPtr++) *toPtr++ = *fromPtr; if (separator) *toPtr++ = '\n'; XtFree(text); XtFree(charset); } /* terminate the string, free the context, and return the string */ *toPtr++ = '\0'; XmStringFreeContext(context); return toString; } /* ** Get the XFontStruct that corresponds to the default (first) font in ** a Motif font list. Since Motif stores this, it saves us from storing ** it or querying it from the X server. */ XFontStruct *GetDefaultFontStruct(XmFontList font) { XFontStruct *fs; XmFontContext context; XmStringCharSet charset; XmFontListInitFontContext(&context, font); XmFontListGetNextFont(context, &charset, &fs); XmFontListFreeFontContext(context); XtFree(charset); return fs; } /* ** Create a string table suitable for passing to XmList widgets */ XmString* StringTable(int count, ... ) { va_list ap; XmString *array; int i; char *str; va_start(ap, count); array = (XmString*)XtMalloc((count+1) * sizeof(XmString)); for(i = 0; i < count; i++ ) { str = va_arg(ap, char *); array[i] = XmStringCreateSimple(str); } array[i] = (XmString)0; va_end(ap); return(array); } void FreeStringTable(XmString *table) { int i; for(i = 0; table[i] != 0; i++) XmStringFree(table[i]); XtFree((char *)table); } /* ** Simulate a button press. The purpose of this routine is show users what ** is happening when they take an action with a non-obvious side effect, ** such as when a user double clicks on a list item. The argument is an ** XmPushButton widget to "press" */ void SimulateButtonPress(Widget widget) { XEvent keyEvent; memset((char *)&keyEvent, 0, sizeof(XKeyPressedEvent)); keyEvent.type = KeyPress; keyEvent.xkey.serial = 1; keyEvent.xkey.send_event = True; if (XtIsSubclass(widget, xmGadgetClass)) { /* On some Motif implementations, asking a gadget for its window will crash, rather than return the window of its parent. */ Widget parent = XtParent(widget); keyEvent.xkey.display = XtDisplay(parent); keyEvent.xkey.window = XtWindow(parent); XtCallActionProc(parent, "ManagerGadgetSelect", &keyEvent, NULL, 0); } else { keyEvent.xkey.display = XtDisplay(widget); keyEvent.xkey.window = XtWindow(widget); XtCallActionProc(widget, "ArmAndActivate", &keyEvent, NULL, 0); } } /* ** Add an item to an already established pull-down or pop-up menu, including ** mnemonics, accelerators and callbacks. */ Widget AddMenuItem(Widget parent, char *name, char *label, char mnemonic, char *acc, char *accText, XtCallbackProc callback, void *cbArg) { Widget button; XmString st1, st2; button = XtVaCreateManagedWidget(name, xmPushButtonWidgetClass, parent, XmNlabelString, st1=XmStringCreateSimple(label), XmNmnemonic, mnemonic, XmNacceleratorText, st2=XmStringCreateSimple(accText), XmNaccelerator, acc, NULL); XtAddCallback(button, XmNactivateCallback, callback, cbArg); XmStringFree(st1); XmStringFree(st2); return button; } /* ** Add a toggle button item to an already established pull-down or pop-up ** menu, including mnemonics, accelerators and callbacks. */ Widget AddMenuToggle(Widget parent, char *name, char *label, char mnemonic, char *acc, char *accText, XtCallbackProc callback, void *cbArg, int set) { Widget button; XmString st1, st2; button = XtVaCreateManagedWidget(name, xmToggleButtonWidgetClass, parent, XmNlabelString, st1=XmStringCreateSimple(label), XmNmnemonic, mnemonic, XmNacceleratorText, st2=XmStringCreateSimple(accText), XmNaccelerator, acc, XmNset, set, NULL); XtAddCallback(button, XmNvalueChangedCallback, callback, cbArg); XmStringFree(st1); XmStringFree(st2); return button; } /* ** Add a sub-menu to an established pull-down or pop-up menu, including ** mnemonics, accelerators and callbacks. Returns the menu pane of the ** new sub menu. */ Widget AddSubMenu(Widget parent, char *name, char *label, char mnemonic) { Widget menu; XmString st1; menu = CreatePulldownMenu(parent, name, NULL, 0); XtVaCreateManagedWidget(name, xmCascadeButtonWidgetClass, parent, XmNlabelString, st1=XmStringCreateSimple(label), XmNmnemonic, mnemonic, XmNsubMenuId, menu, NULL); XmStringFree(st1); return menu; } /* ** SetIntText ** ** Set the text of a motif label to show an integer */ void SetIntText(Widget text, int value) { char labelString[20]; sprintf(labelString, "%d", value); XmTextSetString(text, labelString); } /* ** GetIntText, GetFloatText, GetIntTextWarn, GetFloatTextWarn ** ** Get the text of a motif text widget as an integer or floating point number. ** The functions will return TEXT_READ_OK of the value was read correctly. ** If not, they will return either TEXT_IS_BLANK, or TEXT_NOT_NUMBER. The ** GetIntTextWarn and GetFloatTextWarn will display a dialog warning the ** user that the value could not be read. The argument fieldName is used ** in the dialog to help the user identify where the problem is. Set ** warnBlank to true if a blank field is also considered an error. */ int GetFloatText(Widget text, double *value) { char *strValue, *endPtr; int retVal; strValue = XmTextGetString(text); /* Get Value */ removeWhiteSpace(strValue); /* Remove blanks and tabs */ *value = strtod(strValue, &endPtr); /* Convert string to double */ if (strlen(strValue) == 0) /* String is empty */ retVal = TEXT_IS_BLANK; else if (*endPtr != '\0') /* Whole string not parsed */ retVal = TEXT_NOT_NUMBER; else retVal = TEXT_READ_OK; XtFree(strValue); return retVal; } int GetIntText(Widget text, int *value) { char *strValue, *endPtr; int retVal; strValue = XmTextGetString(text); /* Get Value */ removeWhiteSpace(strValue); /* Remove blanks and tabs */ *value = strtol(strValue, &endPtr, 10); /* Convert string to long */ if (strlen(strValue) == 0) /* String is empty */ retVal = TEXT_IS_BLANK; else if (*endPtr != '\0') /* Whole string not parsed */ retVal = TEXT_NOT_NUMBER; else retVal = TEXT_READ_OK; XtFree(strValue); return retVal; } int GetFloatTextWarn(Widget text, double *value, const char *fieldName, int warnBlank) { int result; char *valueStr; result = GetFloatText(text, value); if (result == TEXT_READ_OK || (result == TEXT_IS_BLANK && !warnBlank)) return result; valueStr = XmTextGetString(text); if (result == TEXT_IS_BLANK) { DialogF(DF_ERR, text, 1, "Warning", "Please supply %s value", "OK", fieldName); } else /* TEXT_NOT_NUMBER */ { DialogF (DF_ERR, text, 1, "Warning", "Can't read %s value: \"%s\"", "OK", fieldName, valueStr); } XtFree(valueStr); return result; } int GetIntTextWarn(Widget text, int *value, const char *fieldName, int warnBlank) { int result; char *valueStr; result = GetIntText(text, value); if (result == TEXT_READ_OK || (result == TEXT_IS_BLANK && !warnBlank)) return result; valueStr = XmTextGetString(text); if (result == TEXT_IS_BLANK) { DialogF (DF_ERR, text, 1, "Warning", "Please supply a value for %s", "OK", fieldName); } else /* TEXT_NOT_NUMBER */ { DialogF (DF_ERR, text, 1, "Warning", "Can't read integer value \"%s\" in %s", "OK", valueStr, fieldName); } XtFree(valueStr); return result; } int TextWidgetIsBlank(Widget textW) { char *str; int retVal; str = XmTextGetString(textW); removeWhiteSpace(str); retVal = *str == '\0'; XtFree(str); return retVal; } /* ** Turn a multi-line editing text widget into a fake single line text area ** by disabling the translation for Return. This is a way to give users ** extra space, by allowing wrapping, but still prohibiting newlines. ** (SINGLE_LINE_EDIT mode can't be used, in this case, because it forces ** the widget to be one line high). */ void MakeSingleLineTextW(Widget textW) { static XtTranslations noReturnTable = NULL; static char *noReturnTranslations = "Return: activate()\n"; if (noReturnTable == NULL) noReturnTable = XtParseTranslationTable(noReturnTranslations); XtOverrideTranslations(textW, noReturnTable); } /* ** Add up-arrow/down-arrow recall to a single line text field. When user ** presses up-arrow, string is cleared and recent entries are presented, ** moving to older ones as each successive up-arrow is pressed. Down-arrow ** moves to more recent ones, final down-arrow clears the field. Associated ** routine, AddToHistoryList, makes maintaining a history list easier. ** ** Arguments are the widget, and pointers to the history list and number of ** items, which are expected to change periodically. */ void AddHistoryToTextWidget(Widget textW, char ***historyList, int *nItems) { histInfo *histData; /* create a data structure for passing history info to the callbacks */ histData = (histInfo *)XtMalloc(sizeof(histInfo)); histData->list = historyList; histData->nItems = nItems; histData->index = -1; /* Add an event handler for handling up/down arrow events */ XtAddEventHandler(textW, KeyPressMask, False, (XtEventHandler)histArrowKeyEH, histData); /* Add a destroy callback for freeing history data structure */ XtAddCallback(textW, XmNdestroyCallback, histDestroyCB, histData); } static void histDestroyCB(Widget w, XtPointer clientData, XtPointer callData) { XtFree((char *)clientData); } static void histArrowKeyEH(Widget w, XtPointer callData, XEvent *event, Boolean *continueDispatch) { histInfo *histData = (histInfo *)callData; KeySym keysym = XLookupKeysym((XKeyEvent *)event, 0); /* only process up and down arrow keys */ if (keysym != XK_Up && keysym != XK_Down) return; /* increment or decrement the index depending on which arrow was pressed */ histData->index += (keysym == XK_Up) ? 1 : -1; /* if the index is out of range, beep, fix it up, and return */ if (histData->index < -1) { histData->index = -1; XBell(XtDisplay(w), 0); return; } if (histData->index >= *histData->nItems) { histData->index = *histData->nItems - 1; XBell(XtDisplay(w), 0); return; } /* Change the text field contents */ XmTextSetString(w, histData->index == -1 ? "" : (*histData->list)[histData->index]); } /* ** Copies a string on to the end of history list, which may be reallocated ** to make room. If historyList grows beyond its internally set boundary ** for size (HISTORY_LIST_MAX), it is trimmed back to a smaller size ** (HISTORY_LIST_TRIM_TO). Before adding to the list, checks if the item ** is a duplicate of the last item. If so, it is not added. */ void AddToHistoryList(char *newItem, char ***historyList, int *nItems) { char **newList; int i; if (*nItems != 0 && !strcmp(newItem, **historyList)) return; if (*nItems == HISTORY_LIST_MAX) { for (i=HISTORY_LIST_TRIM_TO; i timeout)) { XmUpdateDisplay(widget); last = current; } #else static time_t last = 0; time_t current; time(¤t); if (difftime(current, last) > 0) { XmUpdateDisplay(widget); last = current; } #endif } void EndWait(Widget topCursorWidget) { XUndefineCursor(XtDisplay(topCursorWidget), XtWindow(topCursorWidget)); } /* ** Create an X window geometry string from width, height, x, and y values. ** This is a complement to the X routine XParseGeometry, and uses the same ** bitmask values (XValue, YValue, WidthValue, HeightValue, XNegative, and ** YNegative) as defined in and documented under XParseGeometry. ** It expects a string of at least MAX_GEOMETRY_STRING_LEN in which to write ** result. Note that in a geometry string, it is not possible to supply a y ** position without an x position. Also note that the X/YNegative flags ** mean "add a '-' and negate the value" which is kind of odd. */ void CreateGeometryString(char *string, int x, int y, int width, int height, int bitmask) { char *ptr = string; int nChars; if (bitmask & WidthValue) { sprintf(ptr, "%d%n", width, &nChars); ptr += nChars; } if (bitmask & HeightValue) { sprintf(ptr, "x%d%n", height, &nChars); ptr += nChars; } if (bitmask & XValue) { if (bitmask & XNegative) sprintf(ptr, "-%d%n", -x, &nChars); else sprintf(ptr, "+%d%n", x, &nChars); ptr += nChars; } if (bitmask & YValue) { if (bitmask & YNegative) sprintf(ptr, "-%d%n", -y, &nChars); else sprintf(ptr, "+%d%n", y, &nChars); ptr += nChars; } *ptr = '\0'; } /* ** Remove the white space (blanks and tabs) from a string */ static void removeWhiteSpace(char *string) { char *outPtr = string; while (TRUE) { if (*string == 0) { *outPtr = 0; return; } else if (*string != ' ' && *string != '\t') *(outPtr++) = *(string++); else string++; } } /* ** Compares two strings and return TRUE if the two strings ** are the same, ignoring whitespace and case differences. */ static int stripCaseCmp(const char *str1, const char *str2) { const char *c1, *c2; for (c1=str1, c2=str2; *c1!='\0' && *c2!='\0'; c1++, c2++) { while (*c1 == ' ' || *c1 == '\t') c1++; while (*c2 == ' ' || *c2 == '\t') c2++; if (toupper((unsigned char)*c1) != toupper((unsigned char)*c2)) return FALSE; } return *c1 == '\0' && *c2 == '\0'; } static void warnHandlerCB(String message) { if (strstr(message, "XtRemoveGrab")) return; if (strstr(message, "Attempt to remove non-existant passive grab")) return; fputs(message, stderr); fputc('\n', stderr); } static XModifierKeymap *getKeyboardMapping(Display *display) { static XModifierKeymap *keyboardMap = NULL; if (keyboardMap == NULL) { keyboardMap = XGetModifierMapping(display); } return(keyboardMap); } /* ** get mask for a modifier ** */ static Modifiers findModifierMapping(Display *display, KeyCode keyCode) { int i, j; KeyCode *mapentry; XModifierKeymap *modMap = getKeyboardMapping(display); if (modMap == NULL || keyCode == 0) { return(0); } mapentry = modMap->modifiermap; for (i = 0; i < 8; ++i) { for (j = 0; j < (modMap->max_keypermod); ++j) { if (keyCode == *mapentry) { return(1 << ((mapentry - modMap->modifiermap) / modMap->max_keypermod)); } ++mapentry; } } return(0); } Modifiers GetNumLockModMask(Display *display) { static int numLockMask = -1; if (numLockMask == -1) { numLockMask = findModifierMapping(display, XKeysymToKeycode(display, XK_Num_Lock)); } return(numLockMask); } /* ** Grab a key regardless of caps-lock and other silly latching keys. ** */ static void reallyGrabAKey(Widget dialog, int keyCode, Modifiers mask) { Modifiers numLockMask = GetNumLockModMask(XtDisplay(dialog)); if (keyCode == 0) /* No anykey grabs, sorry */ return; XtGrabKey(dialog, keyCode, mask, True, GrabModeAsync, GrabModeAsync); XtGrabKey(dialog, keyCode, mask|LockMask, True, GrabModeAsync, GrabModeAsync); if (numLockMask && numLockMask != LockMask) { XtGrabKey(dialog, keyCode, mask|numLockMask, True, GrabModeAsync, GrabModeAsync); XtGrabKey(dialog, keyCode, mask|LockMask|numLockMask, True, GrabModeAsync, GrabModeAsync); } } /* ** Part of dialog mnemonic processing. Search the widget tree under w ** for widgets with mnemonics. When found, add a passive grab to the ** dialog widget for the mnemonic character, thus directing mnemonic ** events to the dialog widget. */ static void addMnemonicGrabs(Widget dialog, Widget w, int unmodifiedToo) { char mneString[2]; WidgetList children; Cardinal numChildren; int i, isMenu; KeySym mnemonic = '\0'; unsigned char rowColType; unsigned int keyCode; if (XtIsComposite(w)) { if (XtClass(w) == xmRowColumnWidgetClass) { XtVaGetValues(w, XmNrowColumnType, &rowColType, NULL); isMenu = rowColType != XmWORK_AREA; } else isMenu = False; if (!isMenu) { XtVaGetValues(w, XmNchildren, &children, XmNnumChildren, &numChildren, NULL); for (i=0; i<(int)numChildren; i++) addMnemonicGrabs(dialog, children[i], unmodifiedToo); } } else { XtVaGetValues(w, XmNmnemonic, &mnemonic, NULL); if (mnemonic != XK_VoidSymbol && mnemonic != '\0') { mneString[0] = mnemonic; mneString[1] = '\0'; keyCode = XKeysymToKeycode(XtDisplay(dialog), XStringToKeysym(mneString)); reallyGrabAKey(dialog, keyCode, Mod1Mask); if (unmodifiedToo) reallyGrabAKey(dialog, keyCode, 0); } } } /* ** Callback routine for dialog mnemonic processing. */ static void mnemonicCB(Widget w, XtPointer callData, XKeyEvent *event) { findAndActivateMnemonic(w, event->keycode); } /* ** Look for a widget in the widget tree w, with a mnemonic matching ** keycode. When one is found, simulate a button press on that widget ** and give it the keyboard focus. If the mnemonic is on a label, ** look in the userData field of the label to see if it points to ** another widget, and give that the focus. This routine is just ** sufficient for NEdit, no doubt it will need to be extended for ** mnemonics on widgets other than just buttons and text fields. */ static void findAndActivateMnemonic(Widget w, unsigned int keycode) { WidgetList children; Cardinal numChildren; int i, isMenu; KeySym mnemonic = '\0'; char mneString[2]; Widget userData; unsigned char rowColType; if (XtIsComposite(w)) { if (XtClass(w) == xmRowColumnWidgetClass) { XtVaGetValues(w, XmNrowColumnType, &rowColType, NULL); isMenu = rowColType != XmWORK_AREA; } else isMenu = False; if (!isMenu) { XtVaGetValues(w, XmNchildren, &children, XmNnumChildren, &numChildren, NULL); for (i=0; i<(int)numChildren; i++) findAndActivateMnemonic(children[i], keycode); } } else { XtVaGetValues(w, XmNmnemonic, &mnemonic, NULL); if (mnemonic != '\0') { mneString[0] = mnemonic; mneString[1] = '\0'; if (XKeysymToKeycode(XtDisplay(XtParent(w)), XStringToKeysym(mneString)) == keycode) { if (XtClass(w) == xmLabelWidgetClass || XtClass(w) == xmLabelGadgetClass) { XtVaGetValues(w, XmNuserData, &userData, NULL); if (userData!=NULL && XtIsWidget(userData) && XmIsTraversable(userData)) XmProcessTraversal(userData, XmTRAVERSE_CURRENT); } else if (XmIsTraversable(w)) { XmProcessTraversal(w, XmTRAVERSE_CURRENT); SimulateButtonPress(w); } } } } } /* ** Part of workaround for Motif Caps/Num Lock bug. Search the widget tree ** under w for widgets with accelerators. When found, add three passive ** grabs to topWidget, one for the accelerator keysym + modifiers + Caps ** Lock, one for Num Lock, and one for both, thus directing lock + ** accelerator events to topWidget. */ static void addAccelGrabs(Widget topWidget, Widget w) { WidgetList children; Widget menu; Cardinal numChildren; int i; if (XtIsComposite(w)) { XtVaGetValues(w, XmNchildren, &children, XmNnumChildren, &numChildren, NULL); for (i=0; i<(int)numChildren; i++) addAccelGrabs(topWidget, children[i]); } else if (XtClass(w) == xmCascadeButtonWidgetClass) { XtVaGetValues(w, XmNsubMenuId, &menu, NULL); if (menu != NULL) addAccelGrabs(topWidget, menu); } else addAccelGrab(topWidget, w); } /* ** Grabs the key + modifier defined in the widget's accelerator resource, ** in combination with the Caps Lock and Num Lock accelerators. */ static void addAccelGrab(Widget topWidget, Widget w) { char *accelString = NULL; KeySym keysym; unsigned int modifiers; KeyCode code; Modifiers numLockMask = GetNumLockModMask(XtDisplay(topWidget)); XtVaGetValues(w, XmNaccelerator, &accelString, NULL); if (accelString == NULL || *accelString == '\0') { XtFree(accelString); return; } if (!parseAccelString(XtDisplay(topWidget), accelString, &keysym, &modifiers)) { XtFree(accelString); return; } XtFree(accelString); /* Check to see if this server has this key mapped. Some cruddy PC X servers (Xoftware) have terrible default keymaps. If not, XKeysymToKeycode will return 0. However, it's bad news to pass that to XtGrabKey because 0 is really "AnyKey" which is definitely not what we want!! */ code = XKeysymToKeycode(XtDisplay(topWidget), keysym); if (code == 0) return; XtGrabKey(topWidget, code, modifiers | LockMask, True, GrabModeAsync, GrabModeAsync); if (numLockMask && numLockMask != LockMask) { XtGrabKey(topWidget, code, modifiers | numLockMask, True, GrabModeAsync, GrabModeAsync); XtGrabKey(topWidget, code, modifiers | LockMask | numLockMask, True, GrabModeAsync, GrabModeAsync); } } /* ** Read a Motif accelerator string and translate it into a keysym + modifiers. ** Returns TRUE if the parse was successful, FALSE, if not. */ static int parseAccelString(Display *display, const char *string, KeySym *keySym, unsigned int *modifiers) { #define N_MODIFIERS 12 /*... Is NumLock always Mod3? */ static char *modifierNames[N_MODIFIERS] = {"Ctrl", "Shift", "Alt", "Mod2", "Mod3", "Mod4", "Mod5", "Button1", "Button2", "Button3", "Button4", "Button5"}; static unsigned int modifierMasks[N_MODIFIERS] = {ControlMask, ShiftMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask, Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask}; Modifiers numLockMask = GetNumLockModMask(display); char modStr[MAX_ACCEL_LEN]; char evtStr[MAX_ACCEL_LEN]; char keyStr[MAX_ACCEL_LEN]; const char *c, *evtStart, *keyStart; int i; if (strlen(string) >= MAX_ACCEL_LEN) return FALSE; /* Get the modifier part */ for (c = string; *c != '<'; c++) if (*c == '\0') return FALSE; strncpy(modStr, string, c - string); modStr[c - string] = '\0'; /* Verify the or part */ evtStart = c; for ( ; *c != '>'; c++) if (*c == '\0') return FALSE; c++; strncpy(evtStr, evtStart, c - evtStart); evtStr[c - evtStart] = '\0'; if (!stripCaseCmp(evtStr, "") && !stripCaseCmp(evtStr, "")) return FALSE; /* Get the keysym part */ keyStart = c; for ( ; *c != '\0' && !(c != keyStart && *c == ':'); c++); strncpy(keyStr, keyStart, c - keyStart); keyStr[c - keyStart] = '\0'; *keySym = XStringToKeysym(keyStr); /* Parse the modifier part */ *modifiers = 0; c = modStr; while (*c != '\0') { while (*c == ' ' || *c == '\t') c++; if (*c == '\0') break; for (i = 0; i < N_MODIFIERS; i++) { if (!strncmp(c, modifierNames[i], strlen(modifierNames[i]))) { c += strlen(modifierNames[i]); if (modifierMasks[i] != numLockMask) { *modifiers |= modifierMasks[i]; } break; } } if (i == N_MODIFIERS) return FALSE; } return TRUE; } /* ** Event handler for patching around Motif's lock + accelerator problem. ** Looks for a menu item in the patched menu hierarchy and invokes its ** ArmAndActivate action. */ static void lockCB(Widget w, XtPointer callData, XEvent *event, Boolean *continueDispatch) { Modifiers numLockMask = GetNumLockModMask(XtDisplay(w)); Widget topMenuWidget = (Widget)callData; *continueDispatch = TRUE; if (!(((XKeyEvent *)event)->state & (LockMask | numLockMask))) return; if (findAndActivateAccel(topMenuWidget, ((XKeyEvent*) event)->keycode, ((XKeyEvent*) event)->state & ~(LockMask | numLockMask), event)) { *continueDispatch = FALSE; } } /* ** Search through menu hierarchy under w and look for a button with ** accelerator matching keyCode + modifiers, and do its action */ static int findAndActivateAccel(Widget w, unsigned int keyCode, unsigned int modifiers, XEvent *event) { WidgetList children; Widget menu; Cardinal numChildren; int i; char *accelString = NULL; KeySym keysym; unsigned int mods; if (XtIsComposite(w)) { XtVaGetValues(w, XmNchildren, &children, XmNnumChildren, &numChildren, NULL); for (i=0; i<(int)numChildren; i++) if (findAndActivateAccel(children[i], keyCode, modifiers, event)) return TRUE; } else if (XtClass(w) == xmCascadeButtonWidgetClass) { XtVaGetValues(w, XmNsubMenuId, &menu, NULL); if (menu != NULL) if (findAndActivateAccel(menu, keyCode, modifiers, event)) return TRUE; } else { XtVaGetValues(w, XmNaccelerator, &accelString, NULL); if (accelString != NULL && *accelString != '\0') { if (!parseAccelString(XtDisplay(w), accelString, &keysym, &mods)) return FALSE; if (keyCode == XKeysymToKeycode(XtDisplay(w), keysym) && modifiers == mods) { if (XtIsSensitive(w)) { XtCallActionProc(w, "ArmAndActivate", event, NULL, 0); return TRUE; } } } } return FALSE; } /* ** Global installation of mouse wheel actions for scrolled windows. */ void InstallMouseWheelActions(XtAppContext context) { static XtActionsRec Actions[] = { {"scrolled-window-scroll-up", scrollUpAP}, {"scrolled-window-page-up", pageUpAP}, {"scrolled-window-scroll-down", scrollDownAP}, {"scrolled-window-page-down", pageDownAP} }; XtAppAddActions(context, Actions, XtNumber(Actions)); } /* ** Add mouse wheel support to a specific widget, which must be the scrollable ** widget of a ScrolledWindow. */ void AddMouseWheelSupport(Widget w) { if (XmIsScrolledWindow(XtParent(w))) { static const char scrollTranslations[] = "Shift,: scrolled-window-scroll-up(1)\n" "Shift,: scrolled-window-scroll-down(1)\n" "Ctrl,: scrolled-window-page-up()\n" "Ctrl,: scrolled-window-page-down()\n" ",: scrolled-window-scroll-up(3)\n" ",: scrolled-window-scroll-down(3)\n"; static XtTranslations trans_table = NULL; if (trans_table == NULL) { trans_table = XtParseTranslationTable(scrollTranslations); } XtOverrideTranslations(w, trans_table); } } static void pageUpAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { Widget scrolledWindow, scrollBar; String al[1]; al[0] = "Up"; scrolledWindow = XtParent(w); scrollBar = XtNameToWidget (scrolledWindow, "VertScrollBar"); if (scrollBar) XtCallActionProc(scrollBar, "PageUpOrLeft", event, al, 1) ; return; } static void pageDownAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { Widget scrolledWindow, scrollBar; String al[1]; al[0] = "Down"; scrolledWindow = XtParent(w); scrollBar = XtNameToWidget (scrolledWindow, "VertScrollBar"); if (scrollBar) XtCallActionProc(scrollBar, "PageDownOrRight", event, al, 1) ; return; } static void scrollUpAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { Widget scrolledWindow, scrollBar; String al[1]; int i, nLines; if (*nArgs == 0 || sscanf(args[0], "%d", &nLines) != 1) return; al[0] = "Up"; scrolledWindow = XtParent(w); scrollBar = XtNameToWidget (scrolledWindow, "VertScrollBar"); if (scrollBar) for (i=0; i= 2.1.x and < 2.2.3. */ #ifndef LESSTIF_VERSION #if XmVersion == 2001 || (XmVersion == 2002 && XmUPDATE_LEVEL < 3) /* save the widget with current focus in case it moves */ Widget focusW, shellW = widget; while (shellW && !XtIsShell(shellW)) { shellW = XtParent(shellW); } focusW = XtGetKeyboardFocusWidget(shellW); if (state && XtIsRealized(widget)) { /* Simulate a mouse button click. The event attributes that matter are the event type and the coordinates. When the button is managed, the coordinates have to be inside the button. When the button is not managed, they have to be (0, 0) to make sure that the Select routine accepts the event. */ XEvent ev; if (XtIsManaged(widget)) { Position x, y; /* Calculate the coordinates in the same way as OM. */ XtTranslateCoords(XtParent(widget), widget->core.x, widget->core.y, &x, &y); ev.xbutton.x_root = x + widget->core.border_width; ev.xbutton.y_root = y + widget->core.border_width; } else { ev.xbutton.x_root = 0; ev.xbutton.y_root = 0; } /* Default button bindings: ~c: Arm() ~c: Select() Disarm() */ ev.xany.type = ButtonPress; XtCallActionProc(widget, "Arm", &ev, NULL, 0); ev.xany.type = ButtonRelease; XtCallActionProc(widget, "Select", &ev, NULL, 0); XtCallActionProc(widget, "Disarm", &ev, NULL, 0); } /* restore focus to the originator */ if (focusW) { XtSetKeyboardFocus(shellW, focusW); } #endif /* XmVersion == 2001 || ... */ #endif /* LESSTIF_VERSION */ /* This is sufficient on non-OM platforms */ XmToggleButtonSetState(widget, state, notify); } /* Workaround for bug in OpenMotif 2.1 and 2.2. If you have an active tear-off ** menu from a TopLevelShell that is a child of an ApplicationShell, and then ** close the parent window, Motif crashes. The problem doesn't ** happen if you close the tear-offs first, so, we programatically close them ** before destroying the shell widget. */ void CloseAllPopupsFor(Widget shell) { #ifndef LESSTIF_VERSION /* Doesn't happen in LessTif. The tear-off menus are popup-children of * of the TopLevelShell there, which just works. Motif wants to make * them popup-children of the ApplicationShell, where it seems to get * into trouble. */ Widget app = XtParent(shell); int i; for (i = 0; i < app->core.num_popups; i++) { Widget pop = app->core.popup_list[i]; Widget shellFor; XtVaGetValues(pop, XtNtransientFor, &shellFor, NULL); if (shell == shellFor) _XmDismissTearOff(pop, NULL, NULL); } #endif } static long queryDesktop(Display *display, Window window, Atom deskTopAtom) { long deskTopNumber = 0; Atom actualType; int actualFormat; unsigned long nItems, bytesAfter; unsigned char *prop; if (XGetWindowProperty(display, window, deskTopAtom, 0, 1, False, AnyPropertyType, &actualType, &actualFormat, &nItems, &bytesAfter, &prop) != Success) { return -1; /* Property not found */ } if (actualType == None) { return -1; /* Property does not exist */ } if (actualFormat != 32 || nItems != 1) { XFree((char*)prop); return -1; /* Wrong format */ } deskTopNumber = *(long*)prop; XFree((char*)prop); return deskTopNumber; } /* ** Returns the current desktop number, or -1 if no desktop information ** is available. */ long QueryCurrentDesktop(Display *display, Window rootWindow) { static Atom currentDesktopAtom = (Atom)-1; if (currentDesktopAtom == (Atom)-1) currentDesktopAtom = XInternAtom(display, "_NET_CURRENT_DESKTOP", True); if (currentDesktopAtom != None) return queryDesktop(display, rootWindow, currentDesktopAtom); return -1; /* No desktop information */ } /* ** Returns the number of the desktop the given shell window is currently on, ** or -1 if no desktop information is available. Note that windows shown ** on all desktops (sometimes called sticky windows) should return 0xFFFFFFFF. */ long QueryDesktop(Display *display, Widget shell) { static Atom wmDesktopAtom = (Atom)-1; if (wmDesktopAtom == (Atom)-1) wmDesktopAtom = XInternAtom(display, "_NET_WM_DESKTOP", True); if (wmDesktopAtom != None) return queryDesktop(display, XtWindow(shell), wmDesktopAtom); return -1; /* No desktop information */ } /* ** Clipboard wrapper functions that call the Motif clipboard functions ** a number of times before giving up. The interfaces are similar to the ** native Motif functions. */ #define SPINCOUNT 10 /* Try at most 10 times */ #define USLEEPTIME 1000 /* 1 ms between retries */ /* ** Warning reporting */ static void warning(const char* mesg) { fprintf(stderr, "NEdit warning:\n%s\n", mesg); } /* ** Sleep routine */ static void microsleep(long usecs) { static struct timeval timeoutVal; timeoutVal.tv_sec = usecs/1000000; timeoutVal.tv_usec = usecs - timeoutVal.tv_sec*1000000; select(0, NULL, NULL, NULL, &timeoutVal); } /* ** XmClipboardStartCopy spinlock wrapper. */ int SpinClipboardStartCopy(Display *display, Window window, XmString clip_label, Time timestamp, Widget widget, XmCutPasteProc callback, long *item_id) { int i, res; for (i=0; i #include #include #define TEXT_READ_OK 0 #define TEXT_IS_BLANK 1 #define TEXT_NOT_NUMBER 2 /* maximum length for a window geometry string */ #define MAX_GEOM_STRING_LEN 24 /* Maximum length for a menu accelerator string. Which e.g. can be parsed by misc.c:parseAccelString() (how many modifier keys can you hold down at once?) */ #define MAX_ACCEL_LEN 100 /* button margin width to avoid cramped buttons */ #define BUTTON_WIDTH_MARGIN 12 void AddMotifCloseCallback(Widget shell, XtCallbackProc closeCB, void *arg); void SuppressPassiveGrabWarnings(void); void PopDownBugPatch(Widget w); void RemapDeleteKey(Widget w); void SetDeleteRemap(int state); void RealizeWithoutForcingPosition(Widget shell); void RemovePPositionHint(Widget shell); void ManageDialogCenteredOnPointer(Widget dialogChild); void SetPointerCenteredDialogs(int state); void RaiseDialogWindow(Widget shell); void RaiseShellWindow(Widget shell, Boolean focus); void RaiseWindow(Display *display, Window w, Boolean focus); void AddDialogMnemonicHandler(Widget dialog, int unmodifiedToo); void RemoveDialogMnemonicHandler(Widget dialog); void AccelLockBugPatch(Widget topWidget, Widget topMenuContainer); void UpdateAccelLockPatch(Widget topWidget, Widget newButton); char *GetXmStringText(XmString fromString); XFontStruct *GetDefaultFontStruct(XmFontList font); XmString* StringTable(int count, ...); void FreeStringTable(XmString *table); void SimulateButtonPress(Widget widget); Widget AddMenuItem(Widget parent, char *name, char *label, char mnemonic, char *acc, char *accText, XtCallbackProc callback, void *cbArg); Widget AddMenuToggle(Widget parent, char *name, char *label, char mnemonic, char *acc, char *accText, XtCallbackProc callback, void *cbArg,int set); Widget AddSubMenu(Widget parent, char *name, char *label, char mnemonic); void SetIntText(Widget text, int value); int GetFloatText(Widget text, double *value); int GetIntText(Widget text, int *value); int GetFloatTextWarn(Widget text, double *value, const char *fieldName, int warnBlank); int GetIntTextWarn(Widget text, int *value, const char *fieldName, int warnBlank); int TextWidgetIsBlank(Widget textW); void MakeSingleLineTextW(Widget textW); void BeginWait(Widget topCursorWidget); void BusyWait(Widget anyWidget); void EndWait(Widget topCursorWidget); void PasswordText(Widget w, char *passTxt); void AddHistoryToTextWidget(Widget textW, char ***historyList, int *nItems); void AddToHistoryList(char *newItem, char ***historyList, int *nItems); void CreateGeometryString(char *string, int x, int y, int width, int height, int bitmask); Boolean FindBestVisual(Display *display, const char *appName, const char *appClass, Visual **visual, int *depth, Colormap *colormap); Widget CreateDialogShell(Widget parent, char *name, ArgList arglist, Cardinal argcount); Widget CreatePopupMenu(Widget parent, char *name, ArgList arglist, Cardinal argcount); Widget CreatePulldownMenu(Widget parent, char *name, ArgList arglist, Cardinal argcount); Widget CreatePromptDialog(Widget parent, char *name, ArgList arglist, Cardinal argcount); Widget CreateSelectionDialog(Widget parent, char *name, ArgList arglist, Cardinal argcount); Widget CreateFormDialog(Widget parent, char *name, ArgList arglist, Cardinal argcount); Widget CreateFileSelectionDialog(Widget parent, char *name, ArgList arglist, Cardinal argcount); Widget CreateQuestionDialog(Widget parent, char *name, ArgList arglist, Cardinal argcount); Widget CreateMessageDialog(Widget parent, char *name, ArgList arglist, Cardinal argcount); Widget CreateErrorDialog(Widget parent, char *name, ArgList arglist, Cardinal argcount); Widget CreateShellWithBestVis(String appName, String appClass, WidgetClass class, Display *display, ArgList args, Cardinal nArgs); Widget CreatePopupShellWithBestVis(String shellName, WidgetClass class, Widget parent, ArgList arglist, Cardinal argcount); Widget CreateWidget(Widget parent, const char *name, WidgetClass class, ArgList arglist, Cardinal argcount); Modifiers GetNumLockModMask(Display *display); void InstallMouseWheelActions(XtAppContext context); void AddMouseWheelSupport(Widget w); void RadioButtonChangeState(Widget widget, Boolean state, Boolean notify); void CloseAllPopupsFor(Widget shell); long QueryCurrentDesktop(Display *display, Window rootWindow); long QueryDesktop(Display *display, Widget shell); int SpinClipboardStartCopy(Display *display, Window window, XmString clip_label, Time timestamp, Widget widget, XmCutPasteProc callback, long *item_id); int SpinClipboardCopy(Display *display, Window window, long item_id, char *format_name, XtPointer buffer, unsigned long length, long private_id, long *data_id); int SpinClipboardEndCopy(Display *display, Window window, long item_id); int SpinClipboardInquireLength(Display *display, Window window, char *format_name, unsigned long *length); int SpinClipboardRetrieve(Display *display, Window window, char *format_name, XtPointer buffer, unsigned long length, unsigned long *num_bytes, long *private_id); int SpinClipboardLock(Display *display, Window window); int SpinClipboardUnlock(Display *display, Window window); #endif /* NEDIT_MISC_H_INCLUDED */ nedit-5.6.orig/util/motif.c0000644000175000017500000001453010654363157014366 0ustar paulpaul/******************************************************************************* * * * motif.c: Determine stability of Motif * * * * Copyright (C) 2003 Nathaniel Gray * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 28, 1992 * * * * Written by Nathaniel Gray * * * * Modifications by: * * Scott Tringali * * * *******************************************************************************/ /* * About the different #defines that Motif gives us: * All Motifs #define several values. These are the values in * Open Motif 2.1.30, for example: * #define XmVERSION 2 * #define XmREVISION 1 * #define XmUPDATE_LEVEL 30 * #define XmVersion (XmVERSION * 1000 + XmREVISION) * #define XmVERSION_STRING "@(#)Motif Version 2.1.30" * * In addition, LessTif #defines several values as shown here for * version 0.93.0: * #define LESSTIF_VERSION 0 * #define LESSTIF_REVISION 93 * #define LesstifVersion (LESSTIF_VERSION * 1000 + LESSTIF_REVISION) * #define LesstifVERSION_STRING \ * "@(#)GNU/LessTif Version 2.1 Release 0.93.0" * * Also, in LessTif the XmVERSION_STRING is identical to the * LesstifVERSION_STRING. Unfortunately, the only way to find out the * "update level" of a LessTif release is to parse the LesstifVERSION_STRING. */ #include "motif.h" #include #include #ifdef LESSTIF_VERSION static enum MotifStability GetLessTifStability(void); #else static enum MotifStability GetOpenMotifStability(void); #endif /* * These are versions of LessTif that are known to be stable with NEdit in * Motif 2.1 mode. */ static const char *const knownGoodLesstif[] = { "0.92.32", "0.93.0", "0.93.12", "0.93.18", #ifndef __x86_64 "0.93.94", /* 64-bit build .93.94 is broken */ #endif NULL }; /* * These are versions of LessTif that are known NOT to be stable with NEdit in * Motif 2.1 mode. */ const char *const knownBadLessTif[] = { "0.93.25", "0.93.29", "0.93.34" "0.93.36", "0.93.39", "0.93.40", "0.93.41", "0.93.44", #ifdef __x86_64 "0.93.94", /* 64-bit build .93.94 is broken */ #endif "0.93.95b", /* SF bug 1087192 */ "0.94.4", /* Alt-H, ESC => crash */ "0.95.0", /* same as above */ NULL }; #ifdef LESSTIF_VERSION static enum MotifStability GetLessTifStability(void) { int i; const char *rev = NULL; /* We assume that the lesstif version is the string after the last space. */ rev = strrchr(LesstifVERSION_STRING, ' '); if (rev == NULL) return MotifUnknown; rev += 1; /* Check for known good LessTif versions */ for (i = 0; knownGoodLesstif[i]; i++) if (!strcmp(rev, knownGoodLesstif[i])) return MotifKnownGood; /* Check for known bad LessTif versions */ for (i = 0; knownBadLessTif[i]; i++) if (!strcmp(rev, knownBadLessTif[i])) return MotifKnownBad; return MotifUnknown; } #else /* The stability depends on the patch level, so fold it into the usual XmVersion for easy comparison. */ static const int XmFullVersion = (XmVersion * 100 + XmUPDATE_LEVEL); static enum MotifStability GetOpenMotifStability(void) { enum MotifStability result = MotifUnknown; const Boolean really222 = (strcmp("@(#)Motif Version 2.2.2", XmVERSION_STRING) == 0); if (XmFullVersion <= 200200) /* 1.0 - 2.1 are fine */ { result = MotifKnownGood; } else if ((XmFullVersion < 200202) || really222) /* 2.2.0 - 2.2.2 are bad */ { result = MotifKnownBad; } else if (XmFullVersion >= 200203 && XmFullVersion <= 200300) /* 2.2.3 - 2.3 is good */ { result = MotifKnownGood; } else /* Anything else unknown */ { result = MotifUnknown; } return result; } #endif enum MotifStability GetMotifStability(void) { #ifdef LESSTIF_VERSION return GetLessTifStability(); #else return GetOpenMotifStability(); #endif } const char *GetMotifStableVersions(void) { int i; static char msg[sizeof knownGoodLesstif * 80]; for (i = 0; knownGoodLesstif[i] != NULL; i++) { strcat(msg, knownGoodLesstif[i]); strcat(msg, "\n"); } strcat(msg, "OpenMotif 2.1.30\n"); strcat(msg, "OpenMotif 2.2.3\n"); strcat(msg, "OpenMotif 2.3\n"); return msg; } nedit-5.6.orig/util/motif.h0000644000175000017500000000426510204270032014353 0ustar paulpaul/******************************************************************************* * * * motif.h: Determine stability of Motif * * * * Copyright (C) 2004 Scott Tringali * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Written by Scott Tringali * * * *******************************************************************************/ enum MotifStability { MotifKnownGood, MotifUnknown, MotifKnownBad }; /* Return the stability of the Motif compiled-in */ enum MotifStability GetMotifStability(void); /* Acquire a list of good version for showing to the user. */ const char *GetMotifStableVersions(void); nedit-5.6.orig/util/prefFile.c0000644000175000017500000003460411053030340014763 0ustar paulpaulstatic const char CVSID[] = "$Id: prefFile.c,v 1.27 2008/08/20 14:57:36 lebert Exp $"; /******************************************************************************* * * * prefFile.c -- Nirvana utilities for providing application preferences files * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * June 3, 1993 * * * * Written by Mark Edel * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "prefFile.h" #include "fileUtils.h" #include "utils.h" #include #include #include #ifdef VMS #include "VMSparam.h" #else #ifndef __MVS__ #include #endif #endif #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #define N_BOOLEAN_STRINGS 13 static const char *TrueStrings[N_BOOLEAN_STRINGS] = {"True", "true", "TRUE", "T", "t", "Yes", "yes", "YES", "y", "Y", "on", "On", "ON"}; static const char *FalseStrings[N_BOOLEAN_STRINGS] = {"False", "false", "FALSE", "F", "f", "No", "no", "NO", "n", "N", "off", "Off", "OFF"}; static void readPrefs(XrmDatabase prefDB, XrmDatabase appDB, const char *appName, const char *appClass, PrefDescripRec *rsrcDescrip, int nRsrc, int overlay); static int stringToPref(const char *string, PrefDescripRec *rsrcDescrip); static char *removeWhiteSpace(const char *string); /* ** Preferences File ** ** An application maintains a preferences file so that users can ** quickly save and restore program options from within a program, ** without being forced to learn the X resource mechanism. ** ** Preference files are the same format as X resource files, and ** are read using the X resource file reader. X-savvy users are allowed ** to move resources out of a preferences file to their X resource ** files. They would do so if they wanted to attach server-specific ** preferences (such as fonts and colors) to different X servers, or to ** combine additional preferences served only by X resources with those ** provided by the program's menus. */ /* ** Preference description table ** ** A preference description table contains the information necessary ** to read preference resources and store their values in a data ** structure. The table can, so far, describe four types ** of values (this will probably be expanded in the future to include ** more types): ints, booleans, enumerations, and strings. Each entry ** includes the name and class for saving and restoring the parameter ** in X database format, the data type, a default value in the form of ** a character string, and the address where the parameter value is ** be stored. Strings and enumerations take an additional argument. ** For strings, it is the maximum length string that can safely be ** stored or NULL to indicate that new space should be allocated and a ** pointer to it stored in the value address. For enums, it is an array ** of string pointers to the names of each of its possible values. The ** last value in a preference record is a flag for determining whether ** the value should be written to the save file by SavePreferences. */ /* ** CreatePreferencesDatabase ** ** Process a preferences file and the command line options pertaining to ** the X resources used to set those preferences. Create an X database ** of the results. The reason for this odd set of functionality is ** to process command line options before XtDisplayInitialize reads them ** into the application database that the toolkit attaches to the display. ** This allows command line arguments to properly override values specified ** in the preferences file. ** ** fileName Name only of the preferences file to be found ** in the user's home directory ** appName Application name to use in reading the preference ** resources ** opTable Xrm command line option table for the resources ** used in the preferences file ONLY. Command line ** options for other X resources should be processed ** by XtDisplayInitialize. ** nOptions Number of items in opTable ** argcInOut Address of argument count. This will be altered ** to remove the command line options that are ** recognized in the option table. ** argvInOut Argument vector. Will be altered as argcInOut. */ XrmDatabase CreatePreferencesDatabase(const char *fullName, const char *appName, XrmOptionDescList opTable, int nOptions, unsigned int *argcInOut, char **argvInOut) { XrmDatabase db; int argcCopy; char **argvCopy; char *fileString; static XrmOptionDescRec xrmOnlyTable[] = {{"-xrm", NULL, XrmoptionResArg, (caddr_t)NULL}}; /* read the preferences file into an X database. On failure prefDB will be NULL. */ if (NULL == fullName) { db = NULL; } else { fileString = ReadAnyTextFile(fullName, False); if (NULL == fileString) { db = NULL; } else { char* rsrcName; db = XrmGetStringDatabase(fileString); XtFree(fileString); /* Add a resource to the database which remembers that the file is read, so that NEdit will know it. */ rsrcName = (char*) XtMalloc(strlen(appName) + 14); sprintf(rsrcName, "%s.prefFileRead", appName); XrmPutStringResource(&db, rsrcName, "True"); XtFree(rsrcName); } } /* parse the command line, storing results in the preferences database */ XrmParseCommand(&db, opTable, nOptions, appName, (int *)argcInOut, argvInOut); /* process -xrm (resource setting by resource name) arguments so those pertaining to preference resources will be included in the database. Don't remove -xrm arguments from the argument vector, however, so XtDisplayInitialize can still read the non-preference resources */ argvCopy = (char**)XtMalloc(sizeof(char *) * *argcInOut); memcpy(argvCopy, argvInOut, sizeof(char *) * *argcInOut); argcCopy = *argcInOut; XrmParseCommand(&db, xrmOnlyTable, XtNumber(xrmOnlyTable), appName, &argcCopy, argvCopy); XtFree((char *)argvCopy); return db; } /* ** RestorePreferences ** ** Fill in preferences data from two X databases, values in prefDB taking ** precidence over those in appDB. */ void RestorePreferences(XrmDatabase prefDB, XrmDatabase appDB, const char *appName, const char *appClass, PrefDescripRec *rsrcDescrip, int nRsrc) { readPrefs(prefDB, appDB, appName, appClass, rsrcDescrip, nRsrc, False); } /* ** OverlayPreferences ** ** Incorporate preference specified in database "prefDB", preserving (not ** restoring to default) existing preferences, not mentioned in "prefDB" */ void OverlayPreferences(XrmDatabase prefDB, const char *appName, const char *appClass, PrefDescripRec *rsrcDescrip, int nRsrc) { readPrefs(NULL, prefDB, appName, appClass, rsrcDescrip, nRsrc, True); } static void readPrefs(XrmDatabase prefDB, XrmDatabase appDB, const char *appName, const char *appClass, PrefDescripRec *rsrcDescrip, int nRsrc, int overlay) { char rsrcName[256], rsrcClass[256], *valueString, *type; XrmValue rsrcValue; int i; /* read each resource, trying first the preferences file database, then the application database, then the default value if neither are found */ for (i=0; idataType) { case PREF_INT: cleanStr = removeWhiteSpace(string); *(int *)rsrcDescrip->valueAddr = strtol(cleanStr, &endPtr, 10); if (strlen(cleanStr) == 0) { /* String is empty */ *(int *)rsrcDescrip->valueAddr = 0; XtFree(cleanStr); return False; } else if (*endPtr != '\0') { /* Whole string not parsed */ *(int *)rsrcDescrip->valueAddr = 0; XtFree(cleanStr); return False; } XtFree(cleanStr); return True; case PREF_BOOLEAN: cleanStr = removeWhiteSpace(string); for (i=0; ivalueAddr = True; XtFree(cleanStr); return True; } if (!strcmp(FalseStrings[i], cleanStr)) { *(int *)rsrcDescrip->valueAddr = False; XtFree(cleanStr); return True; } } XtFree(cleanStr); *(int *)rsrcDescrip->valueAddr = False; return False; case PREF_ENUM: cleanStr = removeWhiteSpace(string); enumStrings = (char **)rsrcDescrip->arg; for (i=0; enumStrings[i]!=NULL; i++) { if (!strcmp(enumStrings[i], cleanStr)) { *(int *)rsrcDescrip->valueAddr = i; XtFree(cleanStr); return True; } } XtFree(cleanStr); *(int *)rsrcDescrip->valueAddr = 0; return False; case PREF_STRING: if ((int)strlen(string) >= (int)rsrcDescrip->arg) return False; strncpy(rsrcDescrip->valueAddr, string, (int)rsrcDescrip->arg); return True; case PREF_ALLOC_STRING: *(char **)rsrcDescrip->valueAddr = XtMalloc(strlen(string) + 1); strcpy(*(char **)rsrcDescrip->valueAddr, string); return True; } return False; } /* ** Remove the white space (blanks and tabs) from a string and return ** the result in a newly allocated string as the function value */ static char *removeWhiteSpace(const char *string) { char *outPtr, *outString; outPtr = outString = XtMalloc(strlen(string)+1); while (TRUE) { if (*string != ' ' && *string != '\t') *(outPtr++) = *(string++); else string++; if (*string == 0) { *outPtr = 0; return outString; } } } /******************* Implementation Note: Q: Why aren't you using the Xt type conversion services? A: 1) To create a save file, you also need to convert values back to text form, and there are no converters for that direction. 2) XtGetApplicationResources can only be used on the resource database created by the X toolkit at initialization time, and there is no way to intervene in the creation of that database or store new resources in it reliably after it is created. 3) The alternative, XtConvertAndStore is not adequately documented. The toolkit mauual does not explain why it overwrites its input value structure. 4) XtGetApplicationResources and XtConvertAndStore do not work well together because they use different storage strategies for certain data types. *******************/ nedit-5.6.orig/util/prefFile.h0000644000175000017500000000613610144236625015005 0ustar paulpaul/* $Id: prefFile.h,v 1.8 2004/11/09 21:58:45 yooden Exp $ */ /******************************************************************************* * * * prefFile.h -- Nirvana Editor Preference File Header File * * * * Copyright 2002 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_PREFFILE_H_INCLUDED #define NEDIT_PREFFILE_H_INCLUDED #include enum PrefDataTypes {PREF_INT, PREF_BOOLEAN, PREF_ENUM, PREF_STRING, PREF_ALLOC_STRING}; typedef struct _PrefDescripRec { char *name; char *class; int dataType; char *defaultString; void *valueAddr; void *arg; int save; } PrefDescripRec; XrmDatabase CreatePreferencesDatabase(const char *fileName, const char *appName, XrmOptionDescList opTable, int nOptions, unsigned int *argcInOut, char **argvInOut); void RestorePreferences(XrmDatabase prefDB, XrmDatabase appDB, const char *appName, const char *appClass, PrefDescripRec *rsrcDescrip, int nRsrc); void OverlayPreferences(XrmDatabase prefDB, const char *appName, const char *appClass, PrefDescripRec *rsrcDescrip, int nRsrc); void RestoreDefaultPreferences(PrefDescripRec *rsrcDescrip, int nRsrc); int SavePreferences(Display *display, const char *fileName, const char *fileHeader, PrefDescripRec *rsrcDescrip, int nRsrc); #endif /* NEDIT_PREFFILE_H_INCLUDED */ nedit-5.6.orig/util/printUtils.c0000644000175000017500000010415610103140224015402 0ustar paulpaulstatic const char CVSID[] = "$Id: printUtils.c,v 1.25 2004/08/01 10:06:12 yooden Exp $"; /******************************************************************************* * * * printUtils.c -- Nirvana library Printer Menu & Printing Routines * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * * * April 20, 1992 * * * * Written by Arnulfo Zepeda-Navratil * * Centro de Investigacion y Estudio Avanzados ( CINVESTAV ) * * Dept. Fisica - Mexico * * BITNET: ZEPEDA@CINVESMX * * * * Modified by Donna Reid and Joy Kyriakopulos 4/8/93 - VMS port * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "printUtils.h" #include "DialogF.h" #include "misc.h" #include "prefFile.h" #include #include #include #include #include #include #ifdef VMS #include "vmsparam.h" #include #include #include #include #include #include #else #ifdef USE_DIRENT #include #else #include #endif /* USE_DIRENT */ #ifndef __MVS__ #include #endif #endif /*VMS*/ #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif /* Separator between directory references in PATH environmental variable */ #ifdef __EMX__ /* For OS/2 */ #define SEPARATOR ';' #else #define SEPARATOR ':' #endif /* Number of extra pixels down to place a label even with a text widget */ #define LABEL_TEXT_DIFF 6 /* Maximum text string lengths */ #define MAX_OPT_STR 20 #define MAX_QUEUE_STR 60 #define MAX_INT_STR 13 #define MAX_HOST_STR 100 #define MAX_PCMD_STR 100 #define MAX_NAME_STR 100 #define MAX_CMD_STR 256 #define VMS_MAX_JOB_NAME_STR 39 #define N_PRINT_PREFS 7 /* must agree with number of preferences below */ struct printPrefDescrip { PrefDescripRec printCommand; PrefDescripRec copiesOption; PrefDescripRec queueOption; PrefDescripRec nameOption; PrefDescripRec hostOption; PrefDescripRec defaultQueue; PrefDescripRec defaultHost; }; /* Function Prototypes */ static Widget createForm(Widget parent); static void allowOnlyNumInput(Widget widget, caddr_t client_data, XmTextVerifyCallbackStruct *call_data); static void noSpaceOrPunct(Widget widget, caddr_t client_data, XmTextVerifyCallbackStruct *call_data); static void updatePrintCmd(Widget w, caddr_t client_data, caddr_t call_data); static void printCmdModified(Widget w, caddr_t client_data, caddr_t call_data); static void printButtonCB(Widget widget, caddr_t client_data, caddr_t call_data); static void cancelButtonCB(Widget widget, caddr_t client_data, caddr_t call_data); static void setQueueLabelText(void); static int fileInDir(const char *filename, const char *dirpath, unsigned short mode_flags); static int fileInPath(const char *filename, unsigned short mode_flags); static int flprPresent(void); #ifdef USE_LPR_PRINT_CMD static void getLprQueueDefault(char *defqueue); #endif #ifndef USE_LPR_PRINT_CMD static void getLpQueueDefault(char *defqueue); #endif static void setHostLabelText(void); #ifdef VMS static void getVmsQueueDefault(char *defqueue); #else static void getFlprHostDefault(char *defhost); static void getFlprQueueDefault(char *defqueue); #endif /* Module Global Variables */ static Boolean DoneWithDialog; static Boolean PreferencesLoaded = False; static Widget Form; static Widget Label2; static Widget Label3; static Widget Text1; static Widget Text2; static Widget Text3; static Widget Text4; static const char *PrintFileName; static const char *PrintJobName; static char PrintCommand[MAX_PCMD_STR]; /* print command string */ static char CopiesOption[MAX_OPT_STR]; /* # of copies argument string */ static char QueueOption[MAX_OPT_STR]; /* queue name argument string */ static char NameOption[MAX_OPT_STR]; /* print job name argument string */ static char HostOption[MAX_OPT_STR]; /* host name argument string */ static char DefaultQueue[MAX_QUEUE_STR];/* default print queue */ static char DefaultHost[MAX_HOST_STR]; /* default host name */ static char Copies[MAX_INT_STR] = ""; /* # of copies last entered by user */ static char Queue[MAX_QUEUE_STR] = ""; /* queue name last entered by user */ static char Host[MAX_HOST_STR] = ""; /* host name last entered by user */ static char CmdText[MAX_CMD_STR] = ""; /* print command last entered by user */ static int CmdFieldModified = False; /* user last changed the print command field, so don't trust the rest */ #ifdef VMS static int DeleteFile; /* append /DELETE to VMS print command*/ #endif /*VMS*/ static struct printPrefDescrip PrintPrefDescrip = { {"printCommand", "PrintCommand", PREF_STRING, NULL, PrintCommand, (void *)MAX_PCMD_STR, False}, {"printCopiesOption", "PrintCopiesOption", PREF_STRING, NULL, CopiesOption, (void *)MAX_OPT_STR, False}, {"printQueueOption", "PrintQueueOption", PREF_STRING, NULL, QueueOption, (void *)MAX_OPT_STR, False}, {"printNameOption", "PrintNameOption", PREF_STRING, NULL, NameOption, (void *)MAX_OPT_STR, False}, {"printHostOption", "PrintHostOption", PREF_STRING, NULL, HostOption, (void *)MAX_OPT_STR, False}, {"printDefaultQueue", "PrintDefaultQueue", PREF_STRING, NULL, DefaultQueue, (void *)MAX_QUEUE_STR, False}, {"printDefaultHost", "PrintDefaultHost", PREF_STRING, NULL, DefaultHost, (void *)MAX_HOST_STR, False}, }; /* ** PrintFile(Widget parent, char *printFile, char *jobName); ** ** function to put up an application-modal style Print Panel dialog ** box. ** ** parent Parent widget for displaying dialog ** printFile File to print (assumed to be a temporary file ** and not revealed to the user) ** jobName Title for the print banner page */ #ifdef VMS void PrintFile(Widget parent, const char *printFile, const char *jobName, int delete) #else void PrintFile(Widget parent, const char *printFile, const char *jobName) #endif /*VMS*/ { /* In case the program hasn't called LoadPrintPreferences, set up the default values for the print preferences */ if (!PreferencesLoaded) LoadPrintPreferences(NULL, "", "", True); /* Make the PrintFile information available to the callback routines */ PrintFileName = printFile; PrintJobName = jobName; #ifdef VMS DeleteFile = delete; #endif /*VMS*/ /* Create and display the print dialog */ DoneWithDialog = False; Form = createForm(parent); ManageDialogCenteredOnPointer(Form); /* Process events until the user is done with the print dialog */ while (!DoneWithDialog) XtAppProcessEvent(XtWidgetToApplicationContext(Form), XtIMAll); /* Destroy the dialog. Print dialogs are not preserved across calls to PrintFile so that it may be called with different parents and to generally simplify the call (this, of course, makes it slower) */ XtDestroyWidget(Form); } /* ** LoadPrintPreferences ** ** Read an X database to obtain print dialog preferences. ** ** prefDB X database potentially containing print preferences ** appName Application name which can be used to qualify ** resource names for database lookup. ** appClass Application class which can be used to qualify ** resource names for database lookup. ** lookForFlpr Check if the flpr print command is installed ** and use that for the default if it's found. ** (flpr is a Fermilab utility for printing on ** arbitrary systems that support the lpr protocol) */ void LoadPrintPreferences(XrmDatabase prefDB, const char *appName, const char *appClass, int lookForFlpr) { static char defaultQueue[MAX_QUEUE_STR], defaultHost[MAX_HOST_STR]; #ifdef VMS /* VMS built-in print command */ getVmsQueueDefault(defaultQueue); PrintPrefDescrip.printCommand.defaultString = "print"; PrintPrefDescrip.copiesOption.defaultString = "/copies="; PrintPrefDescrip.queueOption.defaultString = "/queue="; PrintPrefDescrip.nameOption.defaultString = "/name="; PrintPrefDescrip.hostOption.defaultString = ""; PrintPrefDescrip.defaultQueue.defaultString = defaultQueue; PrintPrefDescrip.defaultHost.defaultString = ""; #else /* check if flpr is installed, and otherwise choose appropriate printer per system type */ if (lookForFlpr && flprPresent()) { getFlprQueueDefault(defaultQueue); getFlprHostDefault(defaultHost); PrintPrefDescrip.printCommand.defaultString = "flpr"; PrintPrefDescrip.copiesOption.defaultString = ""; PrintPrefDescrip.queueOption.defaultString = "-q"; PrintPrefDescrip.nameOption.defaultString = "-j "; PrintPrefDescrip.hostOption.defaultString = "-h"; PrintPrefDescrip.defaultQueue.defaultString = defaultQueue; PrintPrefDescrip.defaultHost.defaultString = defaultHost; } else { #ifdef USE_LPR_PRINT_CMD getLprQueueDefault(defaultQueue); PrintPrefDescrip.printCommand.defaultString = "lpr"; PrintPrefDescrip.copiesOption.defaultString = "-# "; PrintPrefDescrip.queueOption.defaultString = "-P "; PrintPrefDescrip.nameOption.defaultString = "-J "; PrintPrefDescrip.hostOption.defaultString = ""; PrintPrefDescrip.defaultQueue.defaultString = defaultQueue; PrintPrefDescrip.defaultHost.defaultString = ""; #else getLpQueueDefault(defaultQueue); PrintPrefDescrip.printCommand.defaultString = "lp"; /* was lp -c */ PrintPrefDescrip.copiesOption.defaultString = "-n"; PrintPrefDescrip.queueOption.defaultString = "-d"; PrintPrefDescrip.nameOption.defaultString = "-t"; PrintPrefDescrip.hostOption.defaultString = ""; PrintPrefDescrip.defaultQueue.defaultString = defaultQueue; PrintPrefDescrip.defaultHost.defaultString = ""; #endif } #endif /* Read in the preferences from the X database using the mechanism from prefFile.c (this allows LoadPrintPreferences to work before any widgets are created, which is more convenient than XtGetApplication- Resources for applications which have no main window) */ RestorePreferences(NULL, prefDB, appName, appClass, (PrefDescripRec *)&PrintPrefDescrip, N_PRINT_PREFS); PreferencesLoaded = True; } static Widget createForm(Widget parent) { Widget form, printOk, printCancel, label1, separator; Widget topWidget = NULL; XmString st0; Arg args[65]; int argcnt; Widget bwidgetarray [30]; int bwidgetcnt = 0; /************************ FORM ***************************/ argcnt = 0; XtSetArg(args[argcnt], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); argcnt++; XtSetArg(args[argcnt], XmNdialogTitle, (st0=XmStringCreateLtoR( "Print", XmSTRING_DEFAULT_CHARSET))); argcnt++; XtSetArg(args[argcnt], XmNautoUnmanage, False); argcnt++; form = CreateFormDialog(parent, "printForm", args, argcnt); XtVaSetValues(form, XmNshadowThickness, 0, NULL); XmStringFree( st0 ); /*********************** LABEL 1 and TEXT BOX 1 *********************/ if (CopiesOption[0] != '\0') { argcnt = 0; XtSetArg(args[argcnt], XmNlabelString, (st0=XmStringCreateLtoR( "Number of copies (1)", XmSTRING_DEFAULT_CHARSET))); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'N'); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, LABEL_TEXT_DIFF+5); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 8); argcnt++; label1 = XmCreateLabelGadget(form, "label1", args, argcnt); XmStringFree( st0 ); bwidgetarray[bwidgetcnt] = label1; bwidgetcnt++; argcnt = 0; XtSetArg(args[argcnt], XmNshadowThickness, (short)2); argcnt++; XtSetArg(args[argcnt], XmNcolumns, 3); argcnt++; XtSetArg(args[argcnt], XmNrows, 1); argcnt++; XtSetArg(args[argcnt], XmNvalue , Copies); argcnt++; XtSetArg(args[argcnt], XmNmaxLength, 3); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 5); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNleftWidget, label1); argcnt++; Text1 = XmCreateText(form, "text1", args, argcnt); bwidgetarray[bwidgetcnt] = Text1; bwidgetcnt++; XtAddCallback(Text1, XmNmodifyVerifyCallback, (XtCallbackProc)allowOnlyNumInput, NULL); XtAddCallback(Text1, XmNvalueChangedCallback, (XtCallbackProc)updatePrintCmd, NULL); RemapDeleteKey(Text1); topWidget = Text1; XtVaSetValues(label1, XmNuserData, Text1, NULL); /* mnemonic procesing */ } /************************ LABEL 2 and TEXT 2 ************************/ if (QueueOption[0] != '\0') { argcnt = 0; XtSetArg(args[argcnt], XmNlabelString, (st0=XmStringCreateLtoR( " ", XmSTRING_DEFAULT_CHARSET))); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'Q'); argcnt++; XtSetArg(args[argcnt], XmNrecomputeSize, True); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, topWidget==NULL?XmATTACH_FORM:XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, topWidget); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, LABEL_TEXT_DIFF+4); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 8); argcnt++; Label2 = XmCreateLabelGadget(form, "label2", args, argcnt); XmStringFree(st0); bwidgetarray[bwidgetcnt] = Label2; bwidgetcnt++; setQueueLabelText(); argcnt = 0; XtSetArg(args[argcnt], XmNshadowThickness, (short)2); argcnt++; XtSetArg(args[argcnt], XmNcolumns, (short)17); argcnt++; XtSetArg(args[argcnt], XmNmaxLength, MAX_QUEUE_STR); argcnt++; XtSetArg(args[argcnt], XmNvalue, Queue); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNleftWidget, Label2 ); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, topWidget==NULL?XmATTACH_FORM:XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, topWidget ); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 8); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 4); argcnt++; Text2 = XmCreateText(form, "text2", args, argcnt); XtAddCallback(Text2, XmNmodifyVerifyCallback, (XtCallbackProc)noSpaceOrPunct, NULL); XtAddCallback(Text2, XmNvalueChangedCallback, (XtCallbackProc)updatePrintCmd, NULL); bwidgetarray[bwidgetcnt] = Text2; bwidgetcnt++; RemapDeleteKey(Text2); XtVaSetValues(Label2, XmNuserData, Text2, NULL); /* mnemonic procesing */ topWidget = Text2; } /****************** LABEL 3 and TEXT 3 *********************/ if (HostOption[0] != '\0') { argcnt = 0; XtSetArg(args[argcnt], XmNlabelString, (st0=XmStringCreateLtoR( " ", XmSTRING_DEFAULT_CHARSET))); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'H'); argcnt++; XtSetArg(args[argcnt], XmNrecomputeSize, True); argcnt++; XtSetArg(args[argcnt], XmNvalue , ""); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, topWidget==NULL?XmATTACH_FORM:XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, topWidget ); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 8); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, LABEL_TEXT_DIFF+4); argcnt++; Label3 = XmCreateLabelGadget(form, "label3", args, argcnt); XmStringFree(st0); bwidgetarray[bwidgetcnt] = Label3; bwidgetcnt++; setHostLabelText(); argcnt = 0; XtSetArg(args[argcnt], XmNcolumns, 17); argcnt++; XtSetArg(args[argcnt], XmNrows, 1); argcnt++; XtSetArg(args[argcnt], XmNvalue, Host); argcnt++; XtSetArg(args[argcnt], XmNmaxLength, MAX_HOST_STR); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNleftWidget, Label3 ); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, topWidget==NULL?XmATTACH_FORM:XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, topWidget ); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 8); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 4); argcnt++; Text3 = XmCreateText(form, "Text3", args, argcnt); XtAddCallback(Text3, XmNmodifyVerifyCallback, (XtCallbackProc)noSpaceOrPunct, NULL); XtAddCallback(Text3, XmNvalueChangedCallback, (XtCallbackProc)updatePrintCmd, NULL); bwidgetarray[bwidgetcnt] = Text3; bwidgetcnt++; RemapDeleteKey(Text3); XtVaSetValues(Label3, XmNuserData, Text3, NULL); /* mnemonic procesing */ topWidget = Text3; } /************************** TEXT 4 ***************************/ argcnt = 0; XtSetArg(args[argcnt], XmNvalue, CmdText); argcnt++; XtSetArg(args[argcnt], XmNcolumns, 50); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 8); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 8); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, topWidget ); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 8); argcnt++; Text4 = XmCreateText(form, "Text4", args, argcnt); XtAddCallback(Text4, XmNmodifyVerifyCallback, (XtCallbackProc)printCmdModified, NULL); bwidgetarray[bwidgetcnt] = Text4; bwidgetcnt++; RemapDeleteKey(Text4); topWidget = Text4; if (!CmdFieldModified) updatePrintCmd(NULL, NULL, NULL); /*********************** SEPARATOR **************************/ argcnt = 0; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 8); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, topWidget ); argcnt++; separator = XmCreateSeparatorGadget(form, "separator", args, argcnt); bwidgetarray[bwidgetcnt] = separator; bwidgetcnt++; topWidget = separator; /********************** CANCEL BUTTON *************************/ argcnt = 0; XtSetArg(args[argcnt], XmNlabelString, (st0=XmStringCreateLtoR( "Cancel", XmSTRING_DEFAULT_CHARSET))); argcnt++; XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNleftPosition, 60); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, topWidget ); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 7); argcnt++; printCancel = XmCreatePushButton(form, "printCancel", args, argcnt); XmStringFree( st0 ); bwidgetarray[bwidgetcnt] = printCancel; bwidgetcnt++; XtAddCallback (printCancel, XmNactivateCallback, (XtCallbackProc)cancelButtonCB, NULL); /*********************** PRINT BUTTON **************************/ argcnt = 0; XtSetArg(args[argcnt], XmNlabelString, (st0=XmStringCreateLtoR( "Print", XmSTRING_DEFAULT_CHARSET))); argcnt++; XtSetArg(args[argcnt], XmNshowAsDefault, True); argcnt++; XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_POSITION); argcnt++; XtSetArg(args[argcnt], XmNrightPosition, 40); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNtopWidget, topWidget ); argcnt++; XtSetArg(args[argcnt], XmNtopOffset, 7); argcnt++; printOk = XmCreatePushButton(form, "printOk", args, argcnt); XmStringFree( st0 ); bwidgetarray[bwidgetcnt] = printOk; bwidgetcnt++; XtAddCallback (printOk, XmNactivateCallback, (XtCallbackProc)printButtonCB, NULL); argcnt = 0; XtSetArg(args[argcnt], XmNcancelButton, printCancel); argcnt++; XtSetArg(args[argcnt], XmNdefaultButton, printOk); argcnt++; XtSetValues(form, args, argcnt); XtManageChildren(bwidgetarray, bwidgetcnt); AddDialogMnemonicHandler(form, FALSE); return form; } static void setQueueLabelText(void) { Arg args[15]; int argcnt; XmString st0; char tmp_buf[MAX_QUEUE_STR+8]; if (DefaultQueue[0] != '\0') sprintf(tmp_buf, "Queue (%s)", DefaultQueue); else sprintf(tmp_buf, "Queue"); argcnt = 0; XtSetArg(args[argcnt], XmNlabelString, (st0=XmStringCreateLtoR( tmp_buf, XmSTRING_DEFAULT_CHARSET))); argcnt++; XtSetValues (Label2, args, argcnt); XmStringFree( st0 ); } static void setHostLabelText(void) { Arg args[15]; int argcnt; XmString st0; char tmp_buf[MAX_HOST_STR+7]; if (strcmp(DefaultHost, "")) sprintf(tmp_buf, "Host (%s)", DefaultHost); else sprintf(tmp_buf, "Host"); argcnt = 0; XtSetArg(args[argcnt], XmNlabelString, (st0=XmStringCreateLtoR( tmp_buf, XmSTRING_DEFAULT_CHARSET))); argcnt++; XtSetValues (Label3, args, argcnt); XmStringFree( st0 ); } static void allowOnlyNumInput(Widget widget, caddr_t client_data, XmTextVerifyCallbackStruct *call_data) { int i, textInserted, nInserted; nInserted = call_data->text->length; textInserted = (nInserted > 0); if ((call_data->reason == XmCR_MODIFYING_TEXT_VALUE) && textInserted) { for (i=0; itext->ptr[i])) { call_data->doit = False; return; } } } call_data->doit = True; } /* ** Prohibit a relatively random sampling of characters that will cause ** problems on command lines */ static void noSpaceOrPunct(Widget widget, caddr_t client_data, XmTextVerifyCallbackStruct *call_data) { int i, j, textInserted, nInserted; #ifndef VMS static char prohibited[] = " \t,;|<>()[]{}!@?"; #else static char prohibited[] = " \t,;|@+"; #endif nInserted = call_data->text->length; textInserted = (nInserted > 0); if ((call_data->reason == XmCR_MODIFYING_TEXT_VALUE) && textInserted) { for (i=0; itext->ptr[i] == prohibited[j]) { call_data->doit = False; return; } } } } call_data->doit = True; } static void updatePrintCmd(Widget w, caddr_t client_data, caddr_t call_data) { char command[MAX_CMD_STR], copiesArg[MAX_OPT_STR+MAX_INT_STR]; char jobArg[MAX_NAME_STR], hostArg[MAX_OPT_STR+MAX_HOST_STR]; char queueArg[MAX_OPT_STR+MAX_QUEUE_STR]; char *str; int nCopies; #ifdef VMS char printJobName[VMS_MAX_JOB_NAME_STR+1]; #endif /*VMS*/ /* read each text field in the dialog and generate the corresponding command argument */ if (CopiesOption[0] == '\0') { copiesArg[0] = '\0'; } else { str = XmTextGetString(Text1); if (str[0] == '\0') { copiesArg[0] = '\0'; } else { if (sscanf(str, "%d", &nCopies) != 1) { copiesArg[0] = '\0'; } else { sprintf(copiesArg, " %s%s", CopiesOption, str); } } XtFree(str); } if (QueueOption[0] == '\0') { queueArg[0] = '\0'; } else { str = XmTextGetString(Text2); if (str[0] == '\0') queueArg[0] = '\0'; else sprintf(queueArg, " %s%s", QueueOption, str); XtFree(str); } if (HostOption[0] == '\0') { hostArg[0] = '\0'; } else { str = XmTextGetString(Text3); if (str[0] == '\0') hostArg[0] = '\0'; else sprintf(hostArg, " %s%s", HostOption, str); XtFree(str); } if (NameOption[0] == '\0') jobArg[0] = '\0'; else { #ifdef VMS /* truncate job name on VMS systems or it will cause problems */ strncpy(printJobName,PrintJobName,VMS_MAX_JOB_NAME_STR); printJobName[VMS_MAX_JOB_NAME_STR] = '\0'; sprintf(jobArg, " %s\"%s\"", NameOption, printJobName); #else sprintf(jobArg, " %s\"%s\"", NameOption, PrintJobName); #endif } /* Compose the command from the options determined above */ sprintf(command, "%s%s%s%s%s", PrintCommand, copiesArg, queueArg, hostArg, jobArg); /* display it in the command text area */ XmTextSetString(Text4, command); /* Indicate that the command field was synthesized from the other fields, so future dialog invocations can safely re-generate the command without overwriting commands specifically entered by the user */ CmdFieldModified = False; } static void printCmdModified(Widget w, caddr_t client_data, caddr_t call_data) { /* Indicate that the user has specifically modified the print command and that this field should be left as is in subsequent dialogs */ CmdFieldModified = True; } static void printButtonCB(Widget widget, caddr_t client_data, caddr_t call_data) { char *str, command[MAX_CMD_STR]; #ifdef VMS int spawn_sts; int spawnFlags=CLI$M_NOCLISYM; struct dsc$descriptor cmdDesc; /* get the print command from the command text area */ str = XmTextGetString(Text4); /* add the file name to the print command */ sprintf(command, "%s %s", str, PrintFileName); XtFree(str); /* append /DELETE to print command if requested */ if (DeleteFile) strcat(command, "/DELETE"); /* spawn the print command */ cmdDesc.dsc$w_length = strlen(command); cmdDesc.dsc$b_dtype = DSC$K_DTYPE_T; cmdDesc.dsc$b_class = DSC$K_CLASS_S; cmdDesc.dsc$a_pointer = command; spawn_sts = lib$spawn(&cmdDesc,0,0,&spawnFlags,0,0,0,0,0,0,0,0); if (spawn_sts != SS$_NORMAL) { DialogF(DF_WARN, widget, 1, "Print Error", "Unable to Print:\n%d - %s\n spawnFlags = %d\n", "OK", spawn_sts, strerror(EVMSERR, spawn_sts), spawnFlags); return; } #else int nRead; FILE *pipe; char errorString[MAX_PRINT_ERROR_LENGTH], discarded[1024]; /* get the print command from the command text area */ str = XmTextGetString(Text4); /* add the file name and output redirection to the print command */ sprintf(command, "cat %s | %s 2>&1", PrintFileName, str); XtFree(str); /* Issue the print command using a popen call and recover error messages from the output stream of the command. */ pipe = popen(command,"r"); if (pipe == NULL) { DialogF(DF_WARN, widget, 1, "Print Error", "Unable to Print:\n%s", "OK", strerror(errno)); return; } errorString[0] = 0; nRead = fread(errorString, sizeof(char), MAX_PRINT_ERROR_LENGTH-1, pipe); /* Make sure that the print command doesn't get stuck when trying to write a lot of output on stderr (pipe may fill up). We discard the additional output, though. */ while (fread(discarded, sizeof(char), 1024, pipe) > 0); if (!ferror(pipe)) { errorString[nRead] = '\0'; } if (pclose(pipe)) { DialogF(DF_WARN, widget, 1, "Print Error", "Unable to Print:\n%s", "OK", errorString); return; } #endif /*(VMS)*/ /* Print command succeeded, so retain the current print parameters */ if (CopiesOption[0] != '\0') { str = XmTextGetString(Text1); strcpy(Copies, str); XtFree(str); } if (QueueOption[0] != '\0') { str = XmTextGetString(Text2); strcpy(Queue, str); XtFree(str); } if (HostOption[0] != '\0') { str = XmTextGetString(Text3); strcpy(Host, str); XtFree(str); } str = XmTextGetString(Text4); strcpy(CmdText, str); XtFree(str); /* Pop down the dialog */ DoneWithDialog = True; } static void cancelButtonCB(Widget widget, caddr_t client_data, caddr_t call_data) { DoneWithDialog = True; CmdFieldModified = False; } #ifndef VMS /* ** Is the filename file in the directory dirpath ** and does it have at least some of the mode_flags enabled ? */ static int fileInDir(const char *filename, const char *dirpath, unsigned short mode_flags) { DIR *dfile; #ifdef USE_DIRENT struct dirent *DirEntryPtr; #else struct direct *DirEntryPtr; #endif struct stat statbuf; char fullname[MAXPATHLEN]; dfile = opendir(dirpath); if (dfile != NULL) { while ((DirEntryPtr=readdir(dfile)) != NULL) { if (!strcmp(DirEntryPtr->d_name, filename)) { strcpy(fullname,dirpath); strcat(fullname,"/"); strcat(fullname,filename); stat(fullname,&statbuf); closedir(dfile); return statbuf.st_mode & mode_flags; } } closedir(dfile); } return False; } /* ** Is the filename file in the environment path directories ** and does it have at least some of the mode_flags enabled ? */ static int fileInPath(const char *filename, unsigned short mode_flags) { char path[MAXPATHLEN]; char *pathstring,*lastchar; /* Get environmental value of PATH */ pathstring = getenv("PATH"); if (pathstring == NULL) return False; /* parse the pathstring and search on each directory found */ do { /* if final path in list is empty, don't search it */ if (!strcmp(pathstring, "")) return False; /* locate address of next : character */ lastchar = strchr(pathstring, SEPARATOR); if (lastchar != NULL) { /* if more directories remain in pathstring, copy up to : */ strncpy(path, pathstring, lastchar-pathstring); path[lastchar-pathstring] = '\0'; } else { /* if it's the last directory, just copy it */ strcpy(path, pathstring); } /* search for the file in this path */ if(fileInDir(filename, path, mode_flags)) return True; /* found it !! */ /* point pathstring to start of new dir string */ pathstring = lastchar + 1; } while( lastchar != NULL ); return False; } /* ** Is flpr present in the search path and is it executable ? */ static int flprPresent(void) { /* Is flpr present in the search path and is it executable ? */ return fileInPath("flpr",0111); } static int foundTag(const char *tagfilename, const char *tagname, char *result) { FILE *tfile; char tagformat[512],line[512]; strcpy(tagformat, tagname); strcat(tagformat, " %s"); tfile = fopen(tagfilename,"r"); if (tfile != NULL) { while (!feof(tfile)) { fgets(line,sizeof(line),tfile); if (sscanf(line,tagformat,result) != 0) { fclose(tfile); return True; } } fclose(tfile); } return False; } static int foundEnv(const char *EnvVarName, char *result) { char *dqstr; dqstr = getenv(EnvVarName); if (dqstr != NULL) { strcpy(result,dqstr); return True; } return False; } static void getFlprHostDefault(char *defhost) { if (!foundEnv("FLPHOST",defhost)) if(!foundTag("/usr/local/etc/flp.defaults", "host", defhost)) strcpy(defhost,""); } static void getFlprQueueDefault(char *defqueue) { if (!foundEnv("FLPQUE",defqueue)) if (!foundTag("/usr/local/etc/flp.defaults", "queue", defqueue)) strcpy(defqueue,""); } #ifdef USE_LPR_PRINT_CMD static void getLprQueueDefault(char *defqueue) { if (!foundEnv("PRINTER",defqueue)) strcpy(defqueue,""); } #endif #ifndef USE_LPR_PRINT_CMD static void getLpQueueDefault(char *defqueue) { if (!foundEnv("LPDEST",defqueue)) defqueue[0] = '\0'; } #endif #endif #ifdef VMS static void getVmsQueueDefault(char *defqueue) { int translate_sts; short ret_len; char logicl[12], tabl[15]; struct itemList { short bufL; short itemCode; char *queName; short *lngth; int end_entry; } translStruct; struct dsc$descriptor tabName; struct dsc$descriptor logName; sprintf(tabl, "LNM$FILE_DEV"); tabName.dsc$w_length = strlen(tabl); tabName.dsc$b_dtype = DSC$K_DTYPE_T; tabName.dsc$b_class = DSC$K_CLASS_S; tabName.dsc$a_pointer = tabl; sprintf(logicl, "SYS$PRINT"); logName.dsc$w_length = strlen(logicl); logName.dsc$b_dtype = DSC$K_DTYPE_T; logName.dsc$b_class = DSC$K_CLASS_S; logName.dsc$a_pointer = logicl; translStruct.itemCode = LNM$_STRING; translStruct.lngth = &ret_len; translStruct.bufL = 99; translStruct.end_entry = 0; translStruct.queName = defqueue; translate_sts = sys$trnlnm(0,&tabName,&logName,0,&translStruct); if (translate_sts != SS$_NORMAL && translate_sts != SS$_NOLOGNAM){ fprintf(stderr, "Error return from sys$trnlnm: %d\n", translate_sts); DialogF(DF_WARN, Label2, 1, "Error", "Error translating SYS$PRINT", "OK"); defqueue[0] = '\0'; } else { /* printf("return status from sys$trnlnm = %d\n", translate_sts); */ if (translate_sts == SS$_NOLOGNAM) { defqueue[0] = '\0'; } else { strncpy(defqueue, translStruct.queName, ret_len); defqueue[ret_len] = '\0'; /* printf("defqueue = %s, length = %d\n", defqueue, ret_len); */ } } } #endif /*(VMS)*/ nedit-5.6.orig/util/printUtils.h0000644000175000017500000000522410144236625015423 0ustar paulpaul/* $Id: printUtils.h,v 1.9 2004/11/09 21:58:45 yooden Exp $ */ /******************************************************************************* * * * printUtils.h -- Nirvana Editor Print Utilities Header File * * * * Copyright 2002 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_PRINTUTILS_H_INCLUDED #define NEDIT_PRINTUTILS_H_INCLUDED #include /* Maximum length of an error returned by IssuePrintCommand() */ #define MAX_PRINT_ERROR_LENGTH 1024 #define DESTINATION_REMOTE 1 #define DESTINATION_LOCAL 2 void LoadPrintPreferences(XrmDatabase prefDB, const char *appName, const char *appClass, int lookForFlpr); #ifdef VMS void PrintFile(Widget parent, const char *PrintFileName, const char *jobName, int delete); #else void PrintFile(Widget parent, const char *PrintFileName, const char *jobName); #endif /*VMS*/ #endif /* NEDIT_PRINTUTILS_H_INCLUDED */ nedit-5.6.orig/util/system.h0000644000175000017500000002062110466151303014564 0ustar paulpaul/* $Id: system.h,v 1.18 2006/08/08 18:06:59 tringali Exp $ */ /******************************************************************************* * * * system.h -- Compile Time Configuration Header File * * * * Copyright (C) 2001 Scott Tringali * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 23, 2001 * * * * Written by Scott Tringali, http://www.tringali.org * * * *******************************************************************************/ #ifndef NEDIT_SYSTEM_H_INCLUDED #define NEDIT_SYSTEM_H_INCLUDED /* Determine which machine we were compiled with. This isn't as accurate as calling uname(), which is preferred. However, this gets us very close for a majority of the machines out there, and doesn't require any games with make. A better, but trickier solution, is to run uname at compile time, capture the string, and place it in the executable. Please update this with the proper symbols for your compiler/CPU. It may take a little sleuthing to find out what the correct symbol is. Better compilers/OSs document the symbols they define, but not all do. Usually, the correct ones are prepended with an _ or __, as this is namespace is reserved by ANSI C for the compiler implementation. The order is important for the x86 macros. Some compilers will simultanenously define __i386 and __pentium, so we pick the highest one. Some of the info below derived from these excellent references: http://www.fortran-2000.com/ArnaudRecipes/Version.html http://predef.sourceforge.net/ */ #if defined(__alpha) || defined (_M_ALPHA) # define COMPILE_MACHINE "Alpha" #elif defined(__mips) # define COMPILE_MACHINE "MIPS" #elif defined(__sparc) # define COMPILE_MACHINE "Sparc" #elif defined(__sparcv9) # define COMPILE_MACHINE "Sparc64" #elif defined(__hppa) # define COMPILE_MACHINE "PA-RISC" #elif defined(__ALTIVEC__) # define COMPILE_MACHINE "PowerPC Altivec" #elif defined(__POWERPC__) || defined(__ppc__) || defined(__powerpc__) || defined(_POWER) # define COMPILE_MACHINE "PowerPC" #elif defined(__x86_64) || defined(_x86_64) # define COMPILE_MACHINE "x86-64" #elif defined(__IA64) || defined(__ia64) # define COMPILE_MACHINE "IA64" #elif defined(__k6) || defined(__k6__) # define COMPILE_MACHINE "K6" #elif defined(__athlon) || defined(__athlon__) # define COMPILE_MACHINE "Athlon" #elif defined(__pentium4) || defined(__pentium4__) # define COMPILE_MACHINE "Pentium IV" #elif defined(__pentium3) || defined(__pentium3__) # define COMPILE_MACHINE "Pentium III" #elif defined(__pentium2) || defined(__pentium2__) # define COMPILE_MACHINE "Pentium II" #elif defined(__pentiumpro) || defined(__pentiumpro__) # define COMPILE_MACHINE "Pentium Pro" #elif defined(__pentium) || defined(__pentium__) # define COMPILE_MACHINE "Pentium" #elif defined(__i486) || defined(__i486__) # define COMPILE_MACHINE "486" #elif defined(__i386) || defined(__i386__) # define COMPILE_MACHINE "386" #elif defined(_M_IX86) || defined(_X86_) || defined (__x86__) # define COMPILE_MACHINE "x86" #elif defined(__VAX) # define COMPILE_MACHINE "VAX" /* Untested, please verify */ #else # define COMPILE_MACHINE "Unknown" #endif #if defined(__osf__) # define COMPILE_OS "Tru64/Digital Unix" #elif defined(__sun) # define COMPILE_OS "Solaris" #elif defined(__hpux) # define COMPILE_OS "HP/UX" #elif defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) # define COMPILE_OS "Win32" #elif defined(__sgi) # define COMPILE_OS "IRIX" #elif defined(__Lynx__) # define COMPILE_OS "Lynx" #elif defined(__linux__) # define COMPILE_OS "Linux" #elif defined(_AIX) # define COMPILE_OS "AIX" #elif defined(__VMS) /* Untested, please verify */ # define COMPILE_OS "VMS" #elif defined(__FreeBSD__) # define COMPILE_OS "FreeBSD" #elif defined(__OpenBSD__) /* Untested, please verify */ # define COMPILE_OS "OpenBSD" #elif defined(__NetBSD__) /* Untested, please verify */ # define COMPILE_OS "NetBSD" #elif defined(__bsdi) /* Untested, please verify */ # define COMPILE_OS "BSDI" #elif defined(__ultrix) /* Untested, please verify */ # define COMPILE_OS "Ultrix" #elif defined(__EMX__) /* I think this should be __OS2__ */ # define COMPILE_OS "OS/2" #elif defined(__APPLE__) || defined(__MACOSX__) # define COMPILE_OS "MacOS X" #elif defined(__UNIXWARE__) # define COMPILE_OS "UnixWare" #elif defined(__unix__) /* Unknown Unix, next to last */ # define COMPILE_OS "Unix" #else # define COMPILE_OS "Unknown" #endif #if (defined(__GNUC__) && !defined (__INTEL_COMPILER)) /* Avoid Intel pretending to be gcc */ # define COMPILE_COMPILER "GNU C" #elif defined (__DECC) # define COMPILE_COMPILER "DEC C" #elif defined (__DECCXX) # define COMPILE_COMPILER "DEC C++" #elif defined (__APOGEE) # define COMPILE_COMPILER "Apogee" #elif defined (__SUNPRO_C) # define COMPILE_COMPILER "Sun Studio C" /* aka Sun WorkShop, Sun ONE studio, Forte, Sun Studio, ARGH! */ #elif defined (__SUNPRO_CC) # define COMPILE_COMPILER "Sun Studio C++" /* aka Sun WorkShop, Sun ONE studio, Forte, Sun Studio, ARGH! */ #elif defined (__LCC__) # define COMPILE_COMPILER "LCC" #elif defined (_MSC_VER) # define COMPILE_COMPILER "Microsoft C" #elif defined (__BORLANDC__) # define COMPILE_COMPILER "Borland C" #elif defined (__sgi) && defined (_COMPILER_VERSION) # define COMPILE_COMPILER "SGI MipsPro" #elif defined (__xlC__) /* Unix version of IBM C */ # define COMPILE_COMPILER "IBM xlC" #elif defined (__IBMC__) # define COMPILE_COMPILER "IBM C" /* PC (OS/2, Windows) versions */ #elif defined (__HP_cc) # define COMPILE_COMPILER "HP cc" #elif defined (__HP_aCC) # define COMPILE_COMPILER "HP aCC" #elif defined (__KCC) # define COMPILE_COMPILER "KAI C++" #elif defined (__MWERKS__) # define COMPILE_COMPILER "Metrowerks CodeWarrior" #elif defined (__WATCOMC__) # define COMPILE_COMPILER "Watcom C/C++" #elif defined (__INTEL_COMPILER) # define COMPILE_COMPILER "Intel C++" /* The next few entries are last-ditch efforts to guess the compiler, if no compiler macro exists. These need to be at the end of the list, after all the compilers we really recognize. */ #elif defined (__hpux) /* HP has no indentifier, so guessing here */ # define COMPILE_COMPILER "HP C [?]" #elif defined (__sgi) /* Same for old versions of SGI cc */ # define COMPILE_COMPILER "SGI MipsPro [?]" #else # define COMPILE_COMPILER "Unknown" /* Must be last */ #endif #endif /* NEDIT_SYSTEM_H_INCLUDED */ nedit-5.6.orig/util/utils.c0000644000175000017500000003450310737527371014414 0ustar paulpaulstatic const char CVSID[] = "$Id: utils.c,v 1.27 2008/01/04 22:11:05 yooden Exp $"; /******************************************************************************* * * * utils.c -- miscellaneous non-GUI routines * * * * Copyright (C) 2002 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details.* * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "utils.h" #include #include #include #include #ifdef VMS #include #include ssdef #include syidef #include "../util/VMSparam.h" #include "../util/VMSutils.h" #endif #include #include #include /* just to get 'Boolean' types defined: */ #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #define DEFAULT_NEDIT_HOME ".nedit" #ifdef VMS static char* hiddenFileNames[N_FILE_TYPES] = {".nedit", ".neditmacro", ".neditdb;1"}; static char* plainFileNames[N_FILE_TYPES] = {"nedit.rc", "autoload.nm", "nedit.history;1"}; #else static char* hiddenFileNames[N_FILE_TYPES] = {".nedit", ".neditmacro", ".neditdb"}; static char* plainFileNames[N_FILE_TYPES] = {"nedit.rc", "autoload.nm", "nedit.history"}; #endif static void buildFilePath(char* fullPath, const char* dir, const char* file); static Boolean isDir(const char* file); static Boolean isRegFile(const char* file); /* return non-NULL value for the current working directory. If system call fails, provide a fallback value */ const char* GetCurrentDir(void) { static char curdir[MAXPATHLEN]; if (!getcwd(curdir, (size_t) MAXPATHLEN)) { perror("nedit: getcwd() fails"); strcpy(curdir, "."); } return (curdir); } /* return a non-NULL value for the user's home directory, without trailing slash. We try the environment var and the system user database. */ const char* GetHomeDir(void) { const char *ptr; static char homedir[MAXPATHLEN]=""; struct passwd *passwdEntry; size_t len; if (*homedir) { return homedir; } ptr=getenv("HOME"); if (!ptr) { passwdEntry = getpwuid(getuid()); if (passwdEntry && *(passwdEntry->pw_dir)) { ptr= passwdEntry->pw_dir; } else { /* This is really serious, so just exit. */ perror("nedit: getpwuid() failed "); exit(EXIT_FAILURE); } } strncpy(homedir, ptr, sizeof(homedir)-1); homedir[sizeof(homedir)-1]='\0'; /* Fix trailing slash */ len=strlen(homedir); if (len>1 && homedir[len-1]=='/') { homedir[len-1]='\0'; } return homedir; } /* ** Return a pointer to the username of the current user in a statically ** allocated string. */ const char *GetUserName(void) { #ifdef VMS return cuserid(NULL); #else /* cuserid has apparently been dropped from the ansi C standard, and if strict ansi compliance is turned on (on Sun anyhow, maybe others), calls to cuserid fail to compile. Older versions of nedit try to use the getlogin call first, then if that fails, use getpwuid and getuid. This results in the user-name of the original terminal being used, which is not correct when the user uses the su command. Now, getpwuid only: */ const struct passwd *passwdEntry; static char *userName=NULL; if (userName) return userName; passwdEntry = getpwuid(getuid()); if (!passwdEntry) { /* This is really serious, but sometimes username service is misconfigured through no fault of the user. Be nice and let the user start nc anyway. */ perror("nedit: getpwuid() failed - reverting to $USER"); return getenv("USER"); } else { userName=malloc(strlen(passwdEntry->pw_name)+1); strcpy(userName, passwdEntry->pw_name); return userName; } #endif /* VMS */ } /* ** Writes the hostname of the current system in string "hostname". ** ** NOTE: This function used to be called "GetHostName" but that resulted in a ** linking conflict on VMS with the standard gethostname function, because ** VMS links case-insensitively. */ const char *GetNameOfHost(void) { static char hostname[MAXNODENAMELEN+1]; static int hostnameFound = False; if (!hostnameFound) { #ifdef VMS /* This should be simple, but uname is not supported in the DEC C RTL and gethostname on VMS depends either on Multinet or UCX. So use uname on Unix, and use LIB$GETSYI on VMS. Note the VMS hostname will be in DECNET format with trailing double colons, e.g. "FNALV1::". */ int syi_status; struct dsc$descriptor_s *hostnameDesc; unsigned long int syiItemCode = SYI$_NODENAME; /* get Nodename */ unsigned long int unused = 0; unsigned short int hostnameLen = MAXNODENAMELEN+1; hostnameDesc = NulStrWrtDesc(hostname, MAXNODENAMELEN+1); syi_status = lib$getsyi(&syiItemCode, &unused, hostnameDesc, &hostnameLen, 0, 0); if (syi_status != SS$_NORMAL) { fprintf(stderr, "nedit: Error return from lib$getsyi: %d", syi_status); strcpy(hostname, "VMS"); } else hostname[hostnameLen] = '\0'; FreeStrDesc(hostnameDesc); #else struct utsname nameStruct; int rc = uname(&nameStruct); if (rc<0) { /* Shouldn't ever happen, so we better exit() here */ perror("nedit: uname() failed "); exit(EXIT_FAILURE); } strcpy(hostname, nameStruct.nodename); #endif /* VMS */ hostnameFound = True; } return hostname; } /* ** Create a path: $HOME/filename ** Return "" if it doesn't fit into the buffer */ char *PrependHome(const char *filename, char *buf, size_t buflen) { const char *homedir; size_t home_len, file_len; homedir=GetHomeDir(); home_len=strlen(homedir); file_len=strlen(filename); if ( (home_len+1+file_len)>=buflen ) { buf[0]='\0'; } else { strcpy(buf, homedir); strcat(buf, "/"); strcat(buf, filename); } return buf; } int Min(int i1, int i2) { return i1 <= i2 ? i1 : i2; } /* ** Returns a pointer to the name of an rc file of the requested type. ** ** Preconditions: ** - MAXPATHLEN is set to the max. allowed path length ** - fullPath points to a buffer of at least MAXPATHLEN ** ** Returns: ** - NULL if an error occurs while creating a directory ** - Pointer to a static array containing the file name ** */ const char* GetRCFileName(int type) { static char rcFiles[N_FILE_TYPES][MAXPATHLEN + 1]; static int namesDetermined = False; if (!namesDetermined) { char* nedit_home; int i; if ((nedit_home = getenv("NEDIT_HOME")) == NULL) { /* No NEDIT_HOME */ #ifdef VMS /* This is a default VMS setup */ for (i = 0; i < N_FILE_TYPES; i++) { buildFilePath(rcFiles[i], "SYS$LOGIN", hiddenFileNames[i]); } #else /* #ifdef VMS */ /* Let's try if ~/.nedit is a regular file or not. */ char legacyFile[MAXPATHLEN + 1]; buildFilePath(legacyFile, GetHomeDir(), hiddenFileNames[NEDIT_RC]); if (isRegFile(legacyFile)) { /* This is a legacy setup with rc files in $HOME */ for (i = 0; i < N_FILE_TYPES; i++) { buildFilePath(rcFiles[i], GetHomeDir(), hiddenFileNames[i]); } } else { /* ${HOME}/.nedit does not exist as a regular file. */ /* FIXME: Devices, sockets and fifos are ignored for now. */ char defaultNEditHome[MAXPATHLEN + 1]; buildFilePath(defaultNEditHome, GetHomeDir(), DEFAULT_NEDIT_HOME); if (!isDir(defaultNEditHome)) { /* Create DEFAULT_NEDIT_HOME */ if (mkdir(defaultNEditHome, 0777) != 0) { perror("nedit: Error while creating rc file directory" " $HOME/" DEFAULT_NEDIT_HOME "\n" " (Make sure all parent directories exist.)"); return NULL; } } /* All set for DEFAULT_NEDIT_HOME, let's copy the names */ for (i = 0; i < N_FILE_TYPES; i++) { buildFilePath(rcFiles[i], defaultNEditHome, plainFileNames[i]); } } #endif /* #ifdef VMS */ } else { /* $NEDIT_HOME is set. */ #ifndef VMS /* FIXME: Is this required? Does VMS know stat(), mkdir()? */ if (!isDir(nedit_home)) { /* Create $NEDIT_HOME */ if (mkdir(nedit_home, 0777) != 0) { perror("nedit: Error while creating rc file directory $NEDIT_HOME\n" "nedit: (Make sure all parent directories exist.)"); return NULL; } } #endif /* #ifndef VMS */ /* All set for NEDIT_HOME, let's copy the names */ for (i = 0; i < N_FILE_TYPES; i++) { buildFilePath(rcFiles[i], nedit_home, plainFileNames[i]); } } namesDetermined = True; } return rcFiles[type]; } /* ** Builds a file path from 'dir' and 'file', watching for buffer overruns. ** ** Preconditions: ** - MAXPATHLEN is set to the max. allowed path length ** - 'fullPath' points to a buffer of at least MAXPATHLEN ** - 'dir' and 'file' are valid strings ** ** Postcondition: ** - 'fullpath' will contain 'dir/file' ** - Exits when the result would be greater than MAXPATHLEN */ static void buildFilePath(char* fullPath, const char* dir, const char* file) { if ((MAXPATHLEN) < strlen(dir) + strlen(file) + 2) { /* We have no way to build the path. */ fprintf(stderr, "nedit: rc file path too long for %s.\n", file); exit(EXIT_FAILURE); } /* The length is already checked */ strcpy(fullPath, dir); #ifdef VMS strcat(fullPath, ":"); #else /* #ifdef VMS */ strcat(fullPath, "/"); #endif /* #ifdef VMS */ strcat(fullPath, file); } /* ** Returns true if 'file' is a directory, false otherwise. ** Links are followed. ** ** Preconditions: ** - None ** ** Returns: ** - True for directories, false otherwise */ static Boolean isDir(const char* file) { struct stat attribute; return ((stat(file, &attribute) == 0) && S_ISDIR(attribute.st_mode)); } /* ** Returns true if 'file' is a regular file, false otherwise. ** Links are followed. ** ** Preconditions: ** - None ** ** Returns: ** - True for regular files, false otherwise */ static Boolean isRegFile(const char* file) { struct stat attribute; return ((stat(file, &attribute) == 0) && S_ISREG(attribute.st_mode)); } /* ** Part of the simple stack. Accepts a stack and the pointer you want to ** store. NULL is not allowed, as it is used in Pop() to signal an empty ** stack. */ void Push(Stack* stack, const void* value) { stackObject* pushee; /* Throw away invalid parameters. */ if (NULL == value) { fprintf(stderr, "nedit: Internal error: NULL was pushed.\n"); return; } if (NULL == stack) { fprintf(stderr, "nedit: Internal error: push() called with NULL stack.\n"); return; } /* Allocate memory for new value. */ pushee = (stackObject*) XtMalloc(sizeof(stackObject)); /* Put pushee on top of stack. */ pushee->value = (void*) value; pushee->next = stack->top; stack->top = pushee; (stack->size)++; return; } /* ** Part of the simple stack, returns the topmost item from the stack or ** NULL if the stack is empty. It also returns NULL if the stack itself ** is NULL. ** ** Precondition: The stack's top element is either NULL or a properly ** initialised stackObject. */ void* Pop(Stack* stack) { stackObject* popee; void* value; /* Throw away invalid parameter. */ if (NULL == stack) { fprintf(stderr, "nedit: Internal error: pop() called with NULL stack.\n"); return NULL; } /* Return NULL if Stack is empty. */ if (NULL == stack->top) { return NULL; } /* Remove top entry in the stack. */ popee = stack->top; stack->top = popee->next; (stack->size)--; value = popee->value; XtFree((char*) popee); return value; } /* ** We currently don't need this function: In the only situation where we use ** the stack, we empty it completely. This might come in handy if the stack ** is ever used anywhere else. ** ** Beware: Utterly untested. */ /* void FreeStack(Stack* stack) { void* dummy; while (NULL != (dummy = pop(progStack))) {} XtFree((char*) stack); } */ nedit-5.6.orig/util/utils.h0000644000175000017500000000741210737527371014420 0ustar paulpaul/* $Id: utils.h,v 1.17 2008/01/04 22:11:05 yooden Exp $ */ /******************************************************************************* * * * utils.h -- Nirvana Editor Utilities Header File * * * * Copyright 2002 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_UTILS_H_INCLUDED #define NEDIT_UTILS_H_INCLUDED #include #ifdef VMS #include "vmsparam.h" #else #include #endif /*VMS*/ const char *GetCurrentDir(void); const char *GetHomeDir(void); char *PrependHome(const char *filename, char *buf, size_t buflen); const char *GetUserName(void); const char *GetNameOfHost(void); int Min(int i1, int i2); const char* GetRCFileName(int type); /* ** Simple stack implementation which only keeps void pointers. ** The stack must already be allocated and initialised: ** ** Stack* stack = (Stack*) XtMalloc(sizeof(Stack)); ** stack->top = NULL; ** stack->size = 0; ** ** NULL is not allowed to pass in, as it is used to signal an empty stack. ** ** The user should only ever care about Stack, stackObject is an internal ** object. (So it should really go in utils.c. A forward reference was ** refused by my compiler for some reason though.) */ typedef struct _stackObject { void* value; struct _stackObject* next; } stackObject; typedef struct { unsigned size; stackObject* top; } Stack; void Push(Stack* stack, const void* value); void* Pop(Stack* stack); /* N_FILE_TYPES must be the last entry!! This saves us from counting. */ enum {NEDIT_RC, AUTOLOAD_NM, NEDIT_HISTORY, N_FILE_TYPES}; /* If anyone knows where to get this from system include files (in a machine independent way), please change this (L_cuserid is apparently not ANSI) */ #define MAXUSERNAMELEN 32 /* Ditto for the maximum length for a node name. SYS_NMLN is not available on most systems, and I don't know what the portable alternative is. */ #ifdef SYS_NMLN #define MAXNODENAMELEN SYS_NMLN #else #define MAXNODENAMELEN (MAXPATHLEN+2) #endif #endif /* NEDIT_UTILS_H_INCLUDED */ nedit-5.6.orig/util/vmsParam.h0000644000175000017500000000435610144236625015041 0ustar paulpaul/* $Id: vmsParam.h,v 1.6 2004/11/09 21:58:45 yooden Exp $ */ /******************************************************************************* * * * vmsParam.h -- Nirvana Editor VMS Parameter Header File * * * * Copyright 2002 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_VMSPARAM_H_INCLUDED #define NEDIT_VMSPARAM_H_INCLUDED #ifdef VMS #define MAXHOSTNAMELEN 255 #define MAXPATHLEN 255 #endif /*VMS*/ #endif /* NEDIT_VMSPARAM_H_INCLUDED */ nedit-5.6.orig/util/vmsUtils.c0000644000175000017500000003521010077452067015072 0ustar paulpaulstatic const char CVSID[] = "$Id: vmsUtils.c,v 1.6 2004/07/21 11:32:07 yooden Exp $"; /******************************************************************************* * * * vmsUtils.c - Utility routines for VMS systems. * * * * This file contains the following functions: * * * * StrDescToNul - Convert VMS String Descriptor to C-like null- * * terminated string. Returns the address of * * the malloc'd string. (Call FreeNulStr() when * * done with the string.) * * NulStrToDesc - Convert C-like null-terminated string to VMS * * String Descriptor. Returns the address of * * the malloc'd descriptor, which should be free'd * * when done by calling FreeStrDesc(). * * NulStrWrtDesc - Convert C-like null-terminated string to VMS * * String Descriptor for writing into. The C * * String should already be allocated and the * * length passed as the second parameter. Returns * * the address of the malloc'd descriptor, which * * should be free'd when done via FreeStrDesc(). * * FreeNulStr - Frees null-terminated strings created by * * StrDescToNul(). * * FreeStrDesc - Frees VMS String Descriptors created by * * NulStrToDesc() and NulStrWrtDesc(). * * ConvertVMSCommandLine - Convert an argument vector representing a * * VMS-style command line to something Unix-like. * * Limitations: no abbreviations, some syntax * * information is lost so some errors will yield * * strange results. * * * * rint - Returns the integer (represented as a double * * precision number) nearest its double argument. * * * * VMSFileScan - Calls LIB$FILE_SCAN for filenames on VMS systems * * * * VMSFileScanDone - Ends LIB$FILE_SCAN context & frees memory used * * * * ProcAlive - See if a process (identified by pID) is still * * alive on VMS. * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * February 22, 1993 * * * * Written by Joy Kyriakopulos * * * *******************************************************************************/ #ifdef VMS #include stdio #include string #include stdlib #include ctype #include errno #include math #include unixio #include fab #include nam #include rmsdef #include ssdef #include starlet #include lib$routines #include jpidef #include descrip #include "vmsUtils.h" /* Maximum number and length of arguments for ConvertVMSCommandLine */ #define MAX_ARGS 100 #define MAX_CMD_LENGTH 256 /* Maximum number of files handled by VMSFileScan */ #define MAX_NUM_FILES 100 static void successRtn(struct FAB *dirFab); /* VMSFileScan */ static void errRtn(struct FAB *dirFab); /* VMSFileScan */ static void addArgChar(int *argc, char *argv[], char c); char *StrDescToNul(struct dsc$descriptor_s *vmsString) { char *str; if (vmsString->dsc$b_dtype != DSC$K_DTYPE_T || vmsString->dsc$b_class != DSC$K_CLASS_S) fprintf(stderr,"Warning from StrDescToNul: descriptor class/type = %d/%d\n%s", vmsString->dsc$b_class, vmsString->dsc$b_dtype, " Expecting 1/14\n"); str = malloc(vmsString->dsc$w_length + 1); strncpy(str, vmsString->dsc$a_pointer, vmsString->dsc$w_length); str[vmsString->dsc$w_length + 1] = '\0'; return str; } struct dsc$descriptor_s *NulStrToDesc(char *nulTString) { struct dsc$descriptor_s *vmsString; int strLen; char *tmp; strLen = strlen(nulTString); if (strLen > 32767) fprintf(stderr,"Warning from NulStrToDesc: string > 32767 bytes\n"); vmsString = malloc(sizeof(struct dsc$descriptor_s) + strLen + 1); vmsString->dsc$a_pointer = ((char *)vmsString) + sizeof(struct dsc$descriptor_s); tmp = strcpy(vmsString->dsc$a_pointer, nulTString); vmsString->dsc$w_length = strLen; vmsString->dsc$b_dtype = DSC$K_DTYPE_T; vmsString->dsc$b_class = DSC$K_CLASS_S; return vmsString; } struct dsc$descriptor_s *NulStrWrtDesc(char *nulTString, int strLen) { struct dsc$descriptor_s *vmsString; if (strLen > 32767) fprintf(stderr,"Warning from NulStrToDesc: string > 32767 bytes\n"); memset(nulTString, 0, strLen); /*bzero(nulTString, strLen);*/ vmsString = malloc(sizeof(struct dsc$descriptor_s)); vmsString->dsc$a_pointer = nulTString; vmsString->dsc$w_length = strLen; vmsString->dsc$b_dtype = DSC$K_DTYPE_T; vmsString->dsc$b_class = DSC$K_CLASS_S; return vmsString; } void FreeNulStr(char *nulTString) { free(nulTString); } void FreeStrDesc(struct dsc$descriptor_s *vmsString) { if (vmsString->dsc$b_dtype != DSC$K_DTYPE_T || vmsString->dsc$b_class != DSC$K_CLASS_S) fprintf(stderr,"Warning from FreeStrDesc: descriptor class/type = %d/%d\n%s", vmsString->dsc$b_class, vmsString->dsc$b_dtype, " Expecting 1/14\n"); free(vmsString); } #if !(defined __ALPHA && (defined _XOPEN_SOURCE_EXTENDED || !defined _ANSI_C_SOURCE)) double rint(double dnum) { return floor(dnum + 0.5); } #endif /* ** Re-read the command line and convert it from VMS style to unix style. ** Replaces argv and argc with Unix-correct versions. This is ** a poor solution to parsing VMS command lines because some information ** is lost and some elements of the syntax are not checked. Users also ** can't abbreviate qualifiers as is customary under VMS. */ void ConvertVMSCommandLine(int *argc, char **argv[]) { int i; short cmdLineLen; char *c, cmdLine[MAX_CMD_LENGTH], *oldArg0; struct dsc$descriptor_s *cmdLineDesc; /* get the command line (don't use the old argv and argc because VMS has removed the quotes and altered the line somewhat */ cmdLineDesc = NulStrWrtDesc(cmdLine, MAX_CMD_LENGTH); lib$get_foreign(cmdLineDesc, 0, &cmdLineLen, 0); FreeStrDesc(cmdLineDesc); /* begin a new argv and argc, but preserve the original argv[0] which is not returned by lib$get_foreign */ oldArg0 = (*argv)[0]; *argv = (char **)malloc(sizeof(char *) * MAX_ARGS); (*argv)[0] = oldArg0; *argc = 1; /* scan all of the text on the command line, reconstructing the arg list */ for (i=0, c=cmdLine; i= 0, the number of files returned in namelist * = -1, an error was returned from LIB$FILE_SCAN * and the error is printed on stderr * * Parameters: * * dirname: input file specification (can include wildcards) * namelist: array of pointers to the expanded file specs * (free each string and the table of pointers when done) * select: user supplied function (or NULL) to call to select * which filenames are to be included in dirname array. * If NULL, all filenames will be included. * fnf: specify INCLUDE_FNF, EXCLUDE_FNF, or NOT_ERR_FNF * INCLUDE_FNF: the resultant file specification is * passed on to select() routine for returning * in namelist, even though the file doesn't exist * EXCLUDE_FNF: return -1 (error) if dirname doesn't exist * NOT_ERR_FNF: return 0 (no error) if no files found * * Call VMSFileScanDone() to free memory used by the FAB and RAB and clear * sticky filename defaults for another scanning sequence. */ static char **Namelist; static int NumFilesFound; static int Fnf; static int Context = 0; static int (*SelectRoutine)(); /* saves select fcn for successRtn */ static struct FAB *DirFAB = NULL; static struct NAM *DirNAM = NULL; int VMSFileScan(char *dirname, char *(*namelist[]), int (*select)(), int fnf) { char result_name[NAM$C_MAXRSS+1]; /* array for resulting file spec */ char expanded_name[NAM$C_MAXRSS+1]; /* array for expanded file spec */ int stat; if (DirFAB == NULL) { DirFAB = (struct FAB *) malloc(sizeof(struct FAB)); DirNAM = (struct NAM *) malloc(sizeof(struct NAM)); *DirFAB = cc$rms_fab; /* initialize FAB with default values */ *DirNAM = cc$rms_nam; /* " NAMe block " " " */ DirFAB->fab$l_nam = DirNAM; /* point FAB to NAM block */ DirFAB->fab$l_dna = "*."; /* default is no extension */ DirFAB->fab$b_dns = 2; DirNAM->nam$b_ess = sizeof(expanded_name) - 1; DirNAM->nam$b_rss = sizeof(result_name) - 1; } DirFAB->fab$l_fna = dirname; /* wildcard spec for LIB$FILE_SCAN */ DirFAB->fab$b_fns = strlen(dirname); DirNAM->nam$l_esa = &expanded_name[0]; /* expanded file specs ret'nd here */ DirNAM->nam$l_rsa = &result_name[0]; /* resultant file specs ret'nd here */ SelectRoutine = select; NumFilesFound = 0; Fnf = fnf; Namelist = malloc(sizeof(char *) * MAX_NUM_FILES); *namelist = 0; stat = lib$file_scan(DirFAB, successRtn, errRtn, &Context); if (stat != RMS$_NORMAL && stat != RMS$_FNF && stat != RMS$_NMF) { fprintf(stderr, "Error calling LIB$FILE_SCAN: %s\n", strerror(EVMSERR, stat)); return -1; } if (stat == RMS$_FNF && Fnf == EXCLUDE_FNF) return -1; *namelist = Namelist; return NumFilesFound; } static void successRtn(struct FAB *dirFab) { if (NumFilesFound >= MAX_NUM_FILES) return; /* terminate filename string with a null to pass to user's select routine */ dirFab->fab$l_nam->nam$l_rsa[dirFab->fab$l_nam->nam$b_rsl] = '\0'; /* if user's select routine returns value != 0, then put into name list */ if (SelectRoutine == NULL || (*SelectRoutine)(dirFab->fab$l_nam->nam$l_rsa)) { ++NumFilesFound; Namelist[NumFilesFound-1] = malloc(dirFab->fab$l_nam->nam$b_rsl+1); strcpy(Namelist[NumFilesFound-1], dirFab->fab$l_nam->nam$l_rsa); /* printf("File: %s included\n", dirFab->fab$l_nam->nam$l_rsa); */ } } static void errRtn(struct FAB *dirFab) { if (dirFab->fab$l_sts == RMS$_FNF && Fnf == INCLUDE_FNF) successRtn(dirFab); /* return filename even tho' doesn't exist */ else if (dirFab->fab$l_sts != RMS$_FNF || (dirFab->fab$l_sts == RMS$_FNF && Fnf != NOT_ERR_FNF)) fprintf(stderr, "Error - %s: %s\n", strerror(EVMSERR, dirFab->fab$l_sts), dirFab->fab$l_fna); } void VMSFileScanDone(void) { if (DirFAB != NULL) { int s; if ((s=lib$file_scan_end(DirFAB, &Context)) != RMS$_NORMAL && s != SS$_NORMAL) fprintf(stderr, "Error calling LIB$FILE_SCAN_END: %s\n", strerror(EVMSERR,s)); free(DirNAM); DirNAM = NULL; free(DirFAB); DirFAB = NULL; } } /* * ProcAlive: see if a process (identified by pID) is still alive on VMS. * * Returns: 1 - process exists * 0 - process does not exist * -1 - error getting process info */ int ProcAlive(const unsigned int pID) { int jpiStat; short retLen; char userName[13]; /* 12 plus 1 for ending null */ struct getJPIdescriptor { short bufLength; short itemCode; char *bufAddr; short *retLenAddr; int *endList; } getJPID; getJPID.bufLength = 12; /* (max) size of user name */ getJPID.itemCode = JPI$_USERNAME; getJPID.bufAddr = userName; getJPID.retLenAddr = &retLen; getJPID.endList = 0; jpiStat = sys$getjpiw(1,&pID,0,&getJPID,0,0,0); /* printf("in ProcAlive - jpiStat = %d, pid = %X\n", jpiStat, pID); */ if (jpiStat == SS$_NORMAL || jpiStat == SS$_NOPRIV || jpiStat == SS$_SUSPENDED) return 1; /* process exists */ if (jpiStat == SS$_NONEXPR) return 0; /* process does not exist */ fprintf(stderr, "Error calling GETJPI in ProcAlive. Status = %d\n", jpiStat); return -1; /* error */ } #endif /*VMS*/ nedit-5.6.orig/util/vmsUtils.h0000644000175000017500000000545310144236625015100 0ustar paulpaul/* $Id: vmsUtils.h,v 1.7 2004/11/09 21:58:45 yooden Exp $ */ /******************************************************************************* * * * vmsUtils.h -- Nirvana Editor VMS Utilities Header File * * * * Copyright 2004 The NEdit Developers * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute versions of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * July 31, 2001 * * * *******************************************************************************/ #ifndef NEDIT_VMSUTILS_H_INCLUDED #define NEDIT_VMSUTILS_H_INCLUDED #ifdef VMS #ifndef __DESCRIP_LOADED #include descrip #endif /*__DESCRIP_LOADED*/ #define INCLUDE_FNF 0 #define EXCLUDE_FNF 1 #define NOT_ERR_FNF 2 char *StrDescToNul(struct dsc$descriptor_s *vmsString); struct dsc$descriptor_s *NulStrToDesc(char *nulTString); struct dsc$descriptor_s *NulStrWrtDesc(char *nulTString, int strLen); void FreeNulStr(char *nulTString); void FreeStrDesc(struct dsc$descriptor_s *vmsString); double rint(double dnum); void ConvertVMSCommandLine(int *argc, char **argv[]); int VMSFileScan(char *dirname, char *(*namelist[]), int (*select)(), int fnf); void VMSFileScanDone(void); int ProcAlive(const unsigned int pID); #endif /*VMS*/ #endif /* NEDIT_VMSUTILS_H_INCLUDED */