#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#include "nedit.h"
#include "file.h"
#include "preferences.h"
#include "editorconfig.h"
#include "regularExp.h"
#include "selection.h"
#include "tags.h"
#include "menu.h"
#include "macro.h"
#include "search.h"
#include "server.h"
#include "interpret.h"
#include "parse.h"
#include "help.h"
#include "text.h"
#include "../util/misc.h"
#include "../util/printUtils.h"
#include "../util/fileUtils.h"
#include "../util/filedialog.h"
#include "../util/getfiles.h"
#include "../util/motif.h"
#include "../util/nedit_malloc.h"
#include "../util/xdnd.h"
#include "filter.h"
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <langinfo.h>
#ifndef NO_XMIM
#include <X11/Xlocale.h>
#else
#include <locale.h>
#endif
#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/XmP.h>
#if XmVersion >=
1002
#include <Xm/RepType.h>
#endif
#ifndef __MVS__
#include <sys/param.h>
#endif
#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 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);
static void dndOpenFileCB(Widget w, XtPointer value, XtPointer data);
static XrmDatabase defaultResourceDB;
WindowInfo *WindowList =
NULL;
Display *TheDisplay =
NULL;
char *ArgV0 =
NULL;
Boolean IsServer = False;
Boolean BackgroundRun = False;
Widget TheAppShell;
#define NEDIT_DEFAULT_FONT "-*-helvetica-medium-r-normal-*-14-*-*-*-*-*-iso8859-1," \
"-*-helvetica-bold-r-normal-*-14-*-*-*-*-*-iso8859-1=BOLD," \
"-*-helvetica-medium-o-normal-*-14-*-*-*-*-*-iso8859-1=ITALIC"
#define NEDIT_FIXED_FONT "-*-courier-medium-r-normal-*-14-*-*-*-*-*-iso8859-1," \
"-*-courier-bold-r-normal-*-14-*-*-*-*-*-iso8859-1=BOLD," \
"-*-courier-medium-o-normal-*-14-*-*-*-*-*-iso8859-1=ITALIC"
#define NEDIT_DEFAULT_BG "#b3b3b3"
#define NEDIT_TEXT_TRANSLATIONS "#override\\n" \
"Ctrl~Alt~Meta<KeyPress>v: paste-clipboard()\\n" \
"Ctrl~Alt~Meta<KeyPress>c: copy-clipboard()\\n" \
"Ctrl~Alt~Meta<KeyPress>x: cut-clipboard()\\n" \
"Ctrl~Alt~Meta<KeyPress>u: delete-to-start-of-line()\\n"
#define NEDIT_XFT_DEFAULT_FONT "Sans"
#define NEDIT_XFT_FIXED_FONT "Monospace"
static char *fallbackResources[] = {
#if (XmVersion >=
2003 && XmUPDATE_LEVEL >=
3 &&
USE_XFT ==
1)
"*buttonRenderTable: defaultRT",
"*labelRenderTable: defaultRT",
"*textRenderTable: fixedRT",
"*defaultRT.fontType: FONT_IS_XFT",
"*defaultRT.fontName: " NEDIT_XFT_DEFAULT_FONT,
"*defaultRT.fontSize: 9",
"*fixedRT.fontType: FONT_IS_XFT",
"*fixedRT.fontName: Monospace",
"*fixedRT.fontSize: 9",
#elif 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
#ifdef XNE_TEXTFIELD
"*XmTextField.XftFont: Monospace:size=10",
#endif
"*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,
"*XmContainer.background: " NEDIT_DEFAULT_TEXT_BG,
"*XmIconGadget.background: " NEDIT_DEFAULT_TEXT_BG,
"*pbbutton.shadowThickness: 1",
"*pbbutton.highlightThickness: 1",
"*tabButton.shadowThickness: 1",
"*XmContainer.outlineIndentation: 30",
"*XmContainer.outlineColumnWidth: 6cm",
"*XmContainer.detailTabList: +3cm,+3cm,+3cm",
"*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",
"*XmFileSelectionBox.resizePolicy: XmRESIZE_NONE",
"*XmFileSelectionBox.textAccelerators:",
"*XmFileSelectionBox.pathMode: XmPATH_MODE_RELATIVE",
"*XmFileSelectionBox.width: 500",
"*XmFileSelectionBox.height: 400",
"*newFolder.labelString: New Folder",
"*newFolder.labelType: XmPIXMAP",
"*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: Ctrl<Key>n",
"*fileMenu.new.acceleratorText: Ctrl+N",
"*fileMenu.newOpposite.accelerator: Shift Ctrl<Key>n",
"*fileMenu.newOpposite.acceleratorText: Shift+Ctrl+N",
"*fileMenu.open.accelerator: Ctrl<Key>o",
"*fileMenu.open.acceleratorText: Ctrl+O",
"*fileMenu.openSelected.accelerator: Ctrl<Key>y",
"*fileMenu.openSelected.acceleratorText: Ctrl+Y",
"*fileMenu.close.accelerator: Ctrl<Key>w",
"*fileMenu.close.acceleratorText: Ctrl+W",
"*fileMenu.save.accelerator: Ctrl<Key>s",
"*fileMenu.save.acceleratorText: Ctrl+S",
"*fileMenu.includeFile.accelerator: Alt<Key>i",
"*fileMenu.includeFile.acceleratorText: Alt+I",
"*fileMenu.print.accelerator: Ctrl<Key>p",
"*fileMenu.print.acceleratorText: Ctrl+P",
"*fileMenu.exit.accelerator: Ctrl<Key>q",
"*fileMenu.exit.acceleratorText: Ctrl+Q",
"*editMenu.mnemonic: E",
"*editMenu.undo.accelerator: Ctrl<Key>z",
"*editMenu.undo.acceleratorText: Ctrl+Z",
"*editMenu.redo.accelerator: Shift Ctrl<Key>z",
"*editMenu.redo.acceleratorText: Shift+Ctrl+Z",
"*editMenu.cut.acceleratorText: Ctrl+X",
"*editMenu.copy.acceleratorText: Ctrl+C",
"*editMenu.paste.acceleratorText: Ctrl+V",
"*editMenu.pasteColumn.accelerator: Shift Ctrl<Key>v",
"*editMenu.pasteColumn.acceleratorText: Ctrl+Shift+V",
"*editMenu.delete.acceleratorText: Del",
"*editMenu.selectAll.accelerator: Ctrl<Key>a",
"*editMenu.selectAll.acceleratorText: Ctrl+A",
"*editMenu.shiftLeft.accelerator: Ctrl<Key>9",
"*editMenu.shiftLeft.acceleratorText: [Shift]Ctrl+9",
"*editMenu.shiftLeftShift.accelerator: Shift Ctrl<Key>9",
"*editMenu.shiftRight.accelerator: Ctrl<Key>0",
"*editMenu.shiftRight.acceleratorText: [Shift]Ctrl+0",
"*editMenu.shiftRightShift.accelerator: Shift Ctrl<Key>0",
"*editMenu.upperCase.accelerator: Ctrl<Key>6",
"*editMenu.upperCase.acceleratorText: Ctrl+6",
"*editMenu.lowerCase.accelerator: Shift Ctrl<Key>6",
"*editMenu.lowerCase.acceleratorText: Shift+Ctrl+6",
"*editMenu.fillParagraph.accelerator: Ctrl<Key>j",
"*editMenu.fillParagraph.acceleratorText: Ctrl+J",
"*editMenu.insertFormFeed.accelerator: Alt Ctrl<Key>l",
"*editMenu.insertFormFeed.acceleratorText: Alt+Ctrl+L",
"*editMenu.insertCtrlCode.accelerator: Alt Ctrl<Key>i",
"*editMenu.insertCtrlCode.acceleratorText: Alt+Ctrl+I",
"*editMenu.insertUnicode.accelerator: Alt Ctrl<Key>u",
"*editMenu.insertUnicode.acceleratorText: Alt+Ctrl+U",
"*searchMenu.mnemonic: S",
"*searchMenu.find.accelerator: Ctrl<Key>f",
"*searchMenu.find.acceleratorText: [Shift]Ctrl+F",
"*searchMenu.findShift.accelerator: Shift Ctrl<Key>f",
"*searchMenu.findAgain.accelerator: Ctrl<Key>g",
"*searchMenu.findAgain.acceleratorText: [Shift]Ctrl+G",
"*searchMenu.findAgainShift.accelerator: Shift Ctrl<Key>g",
"*searchMenu.findSelection.accelerator: Ctrl<Key>h",
"*searchMenu.findSelection.acceleratorText: [Shift]Ctrl+H",
"*searchMenu.findSelectionShift.accelerator: Shift Ctrl<Key>h",
"*searchMenu.findIncremental.accelerator: Ctrl<Key>i",
"*searchMenu.findIncrementalShift.accelerator: Shift Ctrl<Key>i",
"*searchMenu.findIncremental.acceleratorText: [Shift]Ctrl+I",
"*searchMenu.replace.accelerator: Ctrl<Key>r",
"*searchMenu.replace.acceleratorText: [Shift]Ctrl+R",
"*searchMenu.replaceShift.accelerator: Shift Ctrl<Key>r",
"*searchMenu.findReplace.accelerator: Ctrl<Key>r",
"*searchMenu.findReplace.acceleratorText: [Shift]Ctrl+R",
"*searchMenu.findReplaceShift.accelerator: Shift Ctrl<Key>r",
"*searchMenu.replaceFindAgain.accelerator: Ctrl<Key>t",
"*searchMenu.replaceFindAgain.acceleratorText: [Shift]Ctrl+T",
"*searchMenu.replaceFindAgainShift.accelerator: Shift Ctrl<Key>t",
"*searchMenu.replaceAgain.accelerator: Alt<Key>t",
"*searchMenu.replaceAgain.acceleratorText: [Shift]Alt+T",
"*searchMenu.replaceAgainShift.accelerator: Shift Alt<Key>t",
"*searchMenu.gotoLineNumber.accelerator: Ctrl<Key>l",
"*searchMenu.gotoLineNumber.acceleratorText: Ctrl+L",
"*searchMenu.gotoSelected.accelerator: Ctrl<Key>e",
"*searchMenu.gotoSelected.acceleratorText: Ctrl+E",
"*searchMenu.mark.accelerator: Alt<Key>m",
"*searchMenu.mark.acceleratorText: Alt+M a-z",
"*searchMenu.gotoMark.accelerator: Alt<Key>g",
"*searchMenu.gotoMark.acceleratorText: [Shift]Alt+G a-z",
"*searchMenu.gotoMarkShift.accelerator: Shift Alt<Key>g",
"*searchMenu.gotoMatching.accelerator: Ctrl<Key>m",
"*searchMenu.gotoMatching.acceleratorText: [Shift]Ctrl+M",
"*searchMenu.gotoMatchingShift.accelerator: Shift Ctrl<Key>m",
"*searchMenu.findDefinition.accelerator: Ctrl<Key>d",
"*searchMenu.findDefinition.acceleratorText: Ctrl+D",
"*searchMenu.showCalltip.accelerator: Ctrl<Key>apostrophe",
"*searchMenu.showCalltip.acceleratorText: Ctrl+''",
"*preferencesMenu.mnemonic: P",
"*preferencesMenu.statisticsLine.accelerator: Alt<Key>a",
"*preferencesMenu.statisticsLine.acceleratorText: Alt+A",
"*preferencesMenu.overtype.acceleratorText: Insert",
"*shellMenu.mnemonic: l",
"*shellMenu.filterSelection.accelerator: Alt<Key>r",
"*shellMenu.filterSelection.acceleratorText: Alt+R",
"*shellMenu.executeCommand.accelerator: Alt<Key>x",
"*shellMenu.executeCommand.acceleratorText: Alt+X",
"*shellMenu.executeCommandLine.accelerator: Ctrl<Key>KP_Enter",
"*shellMenu.executeCommandLine.acceleratorText: Ctrl+KP Enter",
"*shellMenu.cancelShellCommand.accelerator: Ctrl<Key>period",
"*shellMenu.cancelShellCommand.acceleratorText: Ctrl+.",
"*macroMenu.mnemonic: c",
"*macroMenu.learnKeystrokes.accelerator: Alt<Key>k",
"*macroMenu.learnKeystrokes.acceleratorText: Alt+K",
"*macroMenu.finishLearn.accelerator: Alt<Key>k",
"*macroMenu.finishLearn.acceleratorText: Alt+K",
"*macroMenu.cancelLearn.accelerator: Ctrl<Key>period",
"*macroMenu.cancelLearn.acceleratorText: Ctrl+.",
"*macroMenu.replayKeystrokes.accelerator: Ctrl<Key>k",
"*macroMenu.replayKeystrokes.acceleratorText: Ctrl+K",
"*macroMenu.repeat.accelerator: Ctrl<Key>comma",
"*macroMenu.repeat.acceleratorText: Ctrl+,",
"*windowsMenu.mnemonic: W",
"*windowsMenu.splitPane.accelerator: Ctrl<Key>2",
"*windowsMenu.splitPane.acceleratorText: Ctrl+2",
"*windowsMenu.closePane.accelerator: Ctrl<Key>1",
"*windowsMenu.closePane.acceleratorText: Ctrl+1",
"*helpMenu.mnemonic: H",
"?.help.helpForm.sw.helpText*baseTranslations: #override\
<Key>Tab:help-focus-buttons()\\n\
<Key>Return:help-button-action(\"close\")\\n\
Ctrl<Key>F:help-button-action(\"find\")\\n\
Ctrl<Key>G:help-button-action(\"findAgain\")\\n\
<KeyPress>osfCancel:help-button-action(\"close\")\\n\
~Meta~Ctrl~Shift<Btn1Down>:\
grab-focus() help-hyperlink()\\n\
~Meta~Ctrl~Shift<Btn1Up>:\
help-hyperlink(\"current\", \"process-cancel\", \"extend-end\")\\n\
~Meta~Ctrl~Shift<Btn2Down>:\
process-bdrag() help-hyperlink()\\n\
~Meta~Ctrl~Shift<Btn2Up>:\
help-hyperlink(\"new\", \"process-cancel\", \"copy-to\")",
NULL
};
static const char cmdLineHelp[] =
"Usage: xnedit [-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] [-bgrun] [-V|-version]\n\
[-h|-help] [--] [file...]\n";
static char *XNEditAppName =
"nedit";
char* GetAppName(
void)
{
return XNEditAppName;
}
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;
enum MotifStability stability = GetMotifStability();
char *appNameVar = getenv(
"XNEDIT_APPNAME");
if(appNameVar) {
XNEditAppName = appNameVar;
}
if (stability == MotifKnownBad) {
fputs(
"xnedit: WARNING: This version of XNEdit is built incorrectly, and will be unstable.\n",
stderr);
#ifndef BUILD_BROKEN_NEDIT
exit(
EXIT_FAILURE);
#endif
}
ArgV0 = argv[
0];
for (i=
1; i<argc; i++) {
if(opts && !strcmp(argv[
1],
"--")) {
opts = False;
continue;
}
else if (opts && !strcmp(argv[i],
"-bgrun")) {
BackgroundRun = True;
break;
}
}
opts = True;
int retpipe[
2];
pid_t pid = -
1;
if(BackgroundRun) {
if(pipe(retpipe)) {
perror(
"pipe");
fprintf(stderr,
"Abort.\n");
return 1;
}
pid = fork();
if(pid <
0) {
perror(
"fork");
fprintf(stderr,
"Abort.\n");
return 1;
}
else if(pid >
0) {
int ret =
0;
if(read(retpipe[
0], &ret,
sizeof(
int)) !=
sizeof(
int)) {
return 1;
}
return ret;
}
}
XtSetLanguageProc(
NULL, neditLanguageProc,
NULL);
XtToolkitInitialize();
context = XtCreateApplicationContext();
SuppressPassiveGrabWarnings();
XtAppSetWarningHandler(context, noWarningFilter);
XtAppSetFallbackResources(context, fallbackResources);
#if XmVersion >=
1002
XmRepTypeInstallTearOffModelConverter();
#endif
#ifdef __EMX__
_wildcard(&argc, &argv);
#endif
prefDB = CreateNEditPrefDB(&argc, argv);
maskArgvKeywords(argc, argv, protectedKeywords);
putenv(
"XLIB_SKIP_ARGB_VISUALS=1");
TheDisplay = XtOpenDisplay (context,
NULL,
APP_NAME,
APP_CLASS,
NULL,
0, &argc, argv);
unmaskArgvKeywords(argc, argv, protectedKeywords);
if (!TheDisplay) {
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 (
"XNEdit: Can''t open display\n", stderr);
exit(
EXIT_FAILURE);
}
defaultResourceDB = XtScreenDatabase(DefaultScreenOfDisplay(TheDisplay));
XdndInit(TheDisplay, context, dndOpenFileCB,
NULL);
fixupBrokenXKeysymDB();
patchResourcesForVisual();
patchResourcesForKDEbug();
InitMacroGlobals();
RegisterMacroSubroutines();
TextWidgetClassInit(TheDisplay,
NEDIT_XFT_FIXED_FONT ":size=11");
RestoreNEditPrefs(prefDB, XtDatabase(TheDisplay));
invalidBindings = sanitizeVirtualKeyBindings();
TheAppShell = CreateShellWithBestVis(
APP_NAME,
APP_CLASS,
applicationShellWidgetClass,
TheDisplay,
NULL,
0);
restoreInsaneVirtualKeyBindings(invalidBindings);
XtSetMappedWhenManaged(TheAppShell, False);
XtRealizeWidget(TheAppShell);
#ifndef NO_SESSION_RESTART
AttachSessionMgrHandler(TheAppShell);
#endif
LoadPrintPreferences(XtDatabase(TheDisplay),
APP_NAME,
APP_CLASS, True);
SetDeleteRemap(GetPrefMapDelete());
SetPointerCenteredDialogs(GetPrefRepositionDialogs());
InstallMenuActions(context);
InstallHelpLinkActions(context);
InstallMouseWheelActions(context);
SetREDefaultWordDelimiters(GetPrefDelimiters());
ReadNEditDB();
ReadSearchHistory();
for (i=
1; i<argc; i++) {
if(!strcmp(argv[i],
"--")) {
break;
}
else if (!strcmp(argv[i],
"-import")) {
nextArg(argc, argv, &i);
ImportPrefFile(argv[i], False);
}
else if (!strcmp(argv[i],
"-importold")) {
nextArg(argc, argv, &i);
ImportPrefFile(argv[i], True);
}
}
if (*GetPrefTagFile() !=
'\0') {
AddTagsFile(GetPrefTagFile(),
TAG);
}
if (strcmp(GetPrefServerName(),
"") !=
0) {
IsServer = True;
}
fileSpecified =
FALSE;
for (i=
1; i<argc; i++) {
if (opts && !strcmp(argv[i],
"--")) {
opts = False;
continue;
}
else if (opts && !strcmp(argv[i],
"-tags")) {
nextArg(argc, argv, &i);
if (!AddTagsFile(argv[i],
TAG))
fprintf(stderr,
"XNEdit: Unable to load tags file\n");
}
else if (opts && !strcmp(argv[i],
"-do")) {
nextArg(argc, argv, &i);
if (checkDoMacroArg(argv[i]))
toDoCommand = argv[i];
}
else if (opts && !strcmp(argv[i],
"-read")) {
editFlags |=
PREF_READ_ONLY;
}
else if (opts && !strcmp(argv[i],
"-create")) {
editFlags |=
SUPPRESS_CREATE_WARN;
}
else if (opts && !strcmp(argv[i],
"-tabbed")) {
tabbed =
1;
group =
0;
}
else if (opts && !strcmp(argv[i],
"-untabbed")) {
tabbed =
0;
group =
0;
}
else if (opts && !strcmp(argv[i],
"-group")) {
group =
2;
}
else if (opts && !strcmp(argv[i],
"-line")) {
nextArg(argc, argv, &i);
nRead = sscanf(argv[i],
"%d", &lineNum);
if (nRead !=
1)
fprintf(stderr,
"XNEdit: argument to line should be a number\n");
else
gotoLine = True;
}
else if (opts && (*argv[i] ==
'+')) {
nRead = sscanf((argv[i]+
1),
"%d", &lineNum);
if (nRead !=
1)
fprintf(stderr,
"XNEdit: argument to + should be a number\n");
else
gotoLine = True;
}
else if (opts && !strcmp(argv[i],
"-server")) {
IsServer = True;
}
else if (opts && !strcmp(argv[i],
"-bgrun")) {
}
else if (opts && !strcmp(argv[i],
"-xwarn")) {
XtAppSetWarningHandler(context, showWarningFilter);
}
else if (opts && (!strcmp(argv[i],
"-iconic") ||
!strcmp(argv[i],
"-icon"))) {
iconic = True;
}
else if (opts && !strcmp(argv[i],
"-noiconic")) {
iconic = False;
}
else if (opts && (!strcmp(argv[i],
"-geometry") ||
!strcmp(argv[i],
"-g"))) {
nextArg(argc, argv, &i);
geometry = argv[i];
}
else if (opts && !strcmp(argv[i],
"-lm")) {
nextArg(argc, argv, &i);
langMode = argv[i];
}
else if (opts && !strcmp(argv[i],
"-import")) {
nextArg(argc, argv, &i);
}
else if (opts && (!strcmp(argv[i],
"-V") ||
!strcmp(argv[i],
"-version"))) {
PrintVersion();
exit(
EXIT_SUCCESS);
}
else if (opts && (!strcmp(argv[i],
"-h") ||
!strcmp(argv[i],
"-help"))) {
fprintf(stderr,
"%s", cmdLineHelp);
exit(
EXIT_SUCCESS);
}
else if (opts && (*argv[i] ==
'-')) {
fprintf(stderr,
"xnedit: Unrecognized option %s\n%s", argv[i],
cmdLineHelp);
exit(
EXIT_FAILURE);
}
else {
if (ParseFilename(argv[i], filename, pathname) ==
0 ) {
if (group ==
2) {
isTabbed =
0;
group =
1;
}
else if (group ==
1) {
isTabbed =
1;
}
else {
isTabbed = tabbed==-
1? GetPrefOpenInTab() : tabbed;
}
size_t pathlen = strlen(pathname);
size_t namelen = strlen(filename);
char *fullpath = NEditMalloc(pathlen + namelen +
1);
memcpy(fullpath, pathname, pathlen);
memcpy(fullpath+pathlen, filename, namelen);
fullpath[pathlen+namelen] =
'\0';
IOFilter *filter = GetFilterForPath(fullpath);
const char *filter_name = filter ? filter->name :
NULL;
NEditFree(fullpath);
window = EditExistingFile(WindowList, filename, pathname,
NULL,
filter_name, editFlags, geometry, iconic, langMode, isTabbed,
True);
fileSpecified =
TRUE;
if (window) {
CleanUpTabBarExposeQueue(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;
if (lastFile && !IsValidWindow(lastFile))
lastFile =
NULL;
}
}
if (window)
lastFile = window;
}
else {
fprintf(stderr,
"xnedit: file name too long: %s\n", argv[i]);
}
gotoLine = False;
}
}
if (lastFile) {
CleanUpTabBarExposeQueue(lastFile);
RaiseDocument(lastFile);
}
CheckCloseDim();
if (!fileSpecified) {
EditNewFile(
NULL, geometry, iconic, langMode,
NULL);
ReadMacroInitFile(WindowList);
CheckCloseDim();
if (toDoCommand !=
NULL)
DoMacro(WindowList, toDoCommand,
"-do macro");
}
AddLastCommandActionHook(context);
if (IsServer)
InitServerCommunication();
if (BackgroundRun) {
if(pid !=
0) {
close(
0);
close(
1);
close(
2);
}
int ret =
0;
write(retpipe[
1], &ret,
sizeof(
int));
close(retpipe[
0]);
close(retpipe[
1]);
}
if (IsServer)
ServerMainLoop(context);
else
XtAppMainLoop(context);
return EXIT_SUCCESS;
}
static void nextArg(
int argc,
char **argv,
int *argIndex)
{
if (*argIndex +
1 >= argc) {
fprintf(stderr,
"XNEdit: %s requires an argument\n%s", argv[*argIndex],
cmdLineHelp);
exit(
EXIT_FAILURE);
}
(*argIndex)++;
}
static int checkDoMacroArg(
const char *macro)
{
Program *prog;
char *errMsg, *stoppedAt, *tMacro;
int macroLen;
macroLen = strlen(macro);
tMacro = (
char*)NEditMalloc(strlen(macro)+
2);
strncpy(tMacro, macro, macroLen);
tMacro[macroLen] =
'\n';
tMacro[macroLen+
1] =
'\0';
prog = ParseMacro(tMacro, &errMsg, &stoppedAt);
NEditFree(tMacro);
if (prog ==
NULL) {
ParseError(
NULL, tMacro, stoppedAt,
"argument to -do", errMsg);
return False;
}
FreeProgram(prog);
return True;
}
static void maskArgvKeywords(
int argc,
char **argv,
const char **maskArgs)
{
int i, k;
for (i=
1; i<argc; i++)
for (k=
0; maskArgs[k]!=
NULL; k++)
if (!strcmp(argv[i], maskArgs[k]))
argv[i][
0] =
' ';
}
static void unmaskArgvKeywords(
int argc,
char **argv,
const char **maskArgs)
{
int i, k;
for (i=
1; i<argc; i++)
for (k=
0; maskArgs[k]!=
NULL; k++)
if (argv[i][
0]==
' ' && !strcmp(&argv[i][
1], &maskArgs[k][
1]))
argv[i][
0] =
'-';
}
static void fixupBrokenXKeysymDB(
void)
{
const char *keysym = getenv(
"XKEYSYMDB");
if (keysym !=
NULL && access(keysym,
F_OK) !=
0)
putenv(
"XKEYSYMDB");
}
static void patchResourcesForVisual(
void)
{
Cardinal i;
Visual *visual;
int depth;
Colormap map;
Boolean usingDefaultVisual;
XrmDatabase db;
if (!TheDisplay)
return;
db = XtDatabase(TheDisplay);
usingDefaultVisual = FindBestVisual(TheDisplay,
APP_NAME,
APP_CLASS,
&visual,
&depth,
&map);
if (!usingDefaultVisual)
{
#ifndef LESSTIF_VERSION
XrmValue value;
value.addr = (XPointer)&visual;
value.size =
sizeof(visual);
XrmPutResource(&db,
"*visual",
"Visual", &value);
value.addr = (XPointer)↦
value.size =
sizeof(map);
XrmPutResource(&db,
"*colormap",
"Colormap", &value);
value.addr = (XPointer)&depth;
value.size =
sizeof(depth);
XrmPutResource(&db,
"*depth",
"Int", &value);
#endif
for (i =
1; i < XtNumber(fallbackResources); ++i)
{
Cardinal resIndex = i -
1;
if (strstr(fallbackResources[resIndex],
"*background:") ||
strstr(fallbackResources[resIndex],
"*foreground:"))
{
char buf[
1024];
snprintf(buf,
2,
"*%s",
APP_NAME);
strcat(buf, fallbackResources[resIndex]);
XrmPutLineResource(&db, buf);
}
}
}
}
static void patchResourcesForKDEbug(
void)
{
static const char* buggyResources[][
3] = {
{
"*fontList",
"FONTLIST",
NEDIT_DEFAULT_FONT },
{
"*XmText.background",
"BACKGROUND",
NEDIT_DEFAULT_TEXT_BG },
{
"*XmText.foreground",
"FOREGROUND",
NEDIT_DEFAULT_FG },
{
"*XmTextField.background",
"BACKGROUND",
NEDIT_DEFAULT_TEXT_BG },
{
"*XmTextField.foreground",
"FOREGROUND",
NEDIT_DEFAULT_FG },
{
"*XmList.background",
"BACKGROUND",
NEDIT_DEFAULT_TEXT_BG },
{
"*XmList.foreground",
"FOREGROUND",
NEDIT_DEFAULT_FG },
{
"*helpText.background",
"BACKGROUND",
NEDIT_DEFAULT_HELP_BG },
{
"*helpText.foreground",
"FOREGROUND",
NEDIT_DEFAULT_HELP_FG },
{
"*background",
"BACKGROUND",
NEDIT_DEFAULT_BG },
{
"*foreground",
"FOREGROUND",
NEDIT_DEFAULT_FG, },
{
"*selectColor",
"BACKGROUND",
NEDIT_DEFAULT_SEL_BG },
{
"*highlightColor",
"BACKGROUND",
NEDIT_DEFAULT_HI_BG },
{
"*text.background",
"WINDOW_BACKGROUND",
NEDIT_DEFAULT_TEXT_BG },
{
"*text.foreground",
"WINDOW_FOREGROUND",
NEDIT_DEFAULT_FG },
{
"*text.selectBackground",
"SELECT_BACKGROUND",
NEDIT_DEFAULT_SEL_BG },
{
"*text.selectForeground",
"SELECT_FOREGROUND",
NEDIT_DEFAULT_SEL_FG },
{
"*text.cursorForeground",
"WINDOW_FOREGROUND",
NEDIT_DEFAULT_CURSOR_FG},
{
"*statsLine.background",
"BACKGROUND",
NEDIT_DEFAULT_BG },
{
"*statsLine.foreground",
"FOREGROUND",
NEDIT_DEFAULT_FG },
{
NULL,
NULL,
NULL } };
XrmDatabase db;
int i;
if (!TheDisplay)
return;
db = XtDatabase(TheDisplay);
i =
0;
while (buggyResources[i][
0])
{
const char* resource = buggyResources[i][
0];
const char* buggyValue = buggyResources[i][
1];
const char* defaultValue = buggyResources[i][
2];
char name[
128];
char class[
128];
char* type;
XrmValue resValue;
snprintf(name,
128,
"%s%s",
APP_NAME, resource);
snprintf(class,
128,
"%s%s",
APP_CLASS, resource);
if (XrmGetResource(db, name, class, &type, &resValue) &&
!strcmp(type, XmRString))
{
if (!strcmp(resValue.addr, buggyValue))
{
XrmPutStringResource(&db, &name[
0], (
char*)defaultValue);
}
}
++i;
}
}
int XNEditDefaultCharsetIsUTF8(
void)
{
static int defaultCharsetIsUtf8 = -
1;
if(defaultCharsetIsUtf8 == -
1) {
char *l = nl_langinfo(
CODESET);
defaultCharsetIsUtf8 = !strcmp(l,
"UTF-8") ?
1 :
0;
}
return defaultCharsetIsUtf8;
}
static String neditLanguageProc(Display *dpy, String xnl, XtPointer closure)
{
if (! setlocale(
LC_ALL, xnl)) {
XtWarning(
"locale not supported by C library, locale unchanged");
}
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);
}
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);
}
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;
while ((pos = strstr(pos,
"\n")))
{
++pos;
++maxCount;
}
if (maxCount ==
1)
return False;
keys = (
char**)NEditMalloc(maxCount*
sizeof(
char*));
copy = NEditStrdup((
const char*)bindings);
i =
0;
pos2 = copy;
count =
0;
while (i<maxCount && pos2 && *pos2)
{
while (isspace((
int) *pos2) || *pos2 ==
'\n') ++pos2;
if (*pos2 ==
'!')
{
pos2 = strstr(pos2,
"\n");
continue;
}
if (*pos2)
{
keys[i++] = pos2;
++count;
pos3 = strstr(pos2,
":");
if (pos3)
{
*pos3++ =
0;
pos2 = pos3;
}
pos2 = strstr(pos2,
"\n");
}
}
if (count <=
1)
{
free(keys);
NEditFree(copy);
return False;
}
qsort((
void*)keys, count,
sizeof(
const char*), sortAlphabetical);
for (i=
1; i<count; ++i)
{
if (!strcmp(keys[i-
1], keys[i]))
{
free(keys);
NEditFree(copy);
return True;
}
}
free(keys);
NEditFree(copy);
return False;
}
static Atom virtKeyAtom;
static unsigned char* sanitizeVirtualKeyBindings(
void)
{
int overrideBindings = GetPrefOverrideVirtKeyBindings();
Window rootWindow;
const char *virtKeyPropName =
"_MOTIF_DEFAULT_BINDINGS";
Atom dummyAtom;
int getFmt;
unsigned long dummyULong, nItems;
unsigned char *insaneVirtKeyBindings =
NULL;
if (overrideBindings ==
VIRT_KEY_OVERRIDE_NEVER)
return NULL;
virtKeyAtom = XInternAtom(TheDisplay, virtKeyPropName, False);
rootWindow = RootWindow(TheDisplay, DefaultScreen(TheDisplay));
if (XGetWindowProperty(TheDisplay, rootWindow, virtKeyAtom,
0,
INT_MAX,
True,
XA_STRING, &dummyAtom, &getFmt, &nItems,
&dummyULong, &insaneVirtKeyBindings) != Success
|| nItems ==
0)
{
return NULL;
}
if (overrideBindings ==
VIRT_KEY_OVERRIDE_AUTO)
{
if (!virtKeyBindingsAreInvalid(insaneVirtKeyBindings))
{
XChangeProperty(TheDisplay, rootWindow, virtKeyAtom,
XA_STRING,
8,
PropModeReplace, insaneVirtKeyBindings,
strlen((
const char*)insaneVirtKeyBindings));
XFree((
char*)insaneVirtKeyBindings);
return NULL;
}
}
return insaneVirtKeyBindings;
}
static void restoreInsaneVirtualKeyBindings(
unsigned char *insaneVirtKeyBindings)
{
if (insaneVirtKeyBindings)
{
Window rootWindow = RootWindow(TheDisplay, DefaultScreen(TheDisplay));
XChangeProperty(TheDisplay, rootWindow, virtKeyAtom,
XA_STRING,
8,
PropModeReplace, insaneVirtKeyBindings,
strlen((
const char*)insaneVirtKeyBindings));
XFree((
char*)insaneVirtKeyBindings);
}
}
static void showWarningFilter(String message)
{
const char* bogusMessages[] = {
#ifdef LESSTIF_VERSION
"XmFontListCreate() is an obsolete function!",
"No type converter registered for ''String'' to ''PathMode'' conversion.",
"XtRemoveGrab asked to remove a widget not on the list",
#endif
NULL
};
const char **bogusMessage = &bogusMessages[
0];
while (*bogusMessage) {
size_t bogusLen = strlen(*bogusMessage);
if (strncmp(message, *bogusMessage, bogusLen) ==
0) {
#ifdef DEBUG_LESSTIF_WARNINGS
fprintf(stderr,
"[SUPPRESSED] %s\n", message);
#endif
return;
}
++bogusMessage;
}
fprintf(stderr,
"%s\n", message);
}
static void noWarningFilter(String message)
{
return;
}
static void dndOpenFileCB(Widget w, XtPointer value, XtPointer data) {
char *urilist = value;
size_t len = strlen(urilist);
size_t start =
0;
if(len >
7 && !memcmp(urilist,
"file://",
7)) {
start =
7;
}
int err =
0;
char *path = NEditMalloc(len +
1);
int k =
0;
for(
int i=start;i<len;i++) {
char c = urilist[i];
if(c ==
'%') {
if(i +
2 < len) {
char code[
3];
code[
0] = urilist[i+
1];
code[
1] = urilist[i+
2];
code[
2] =
'\0';
errno =
0;
char *end =
NULL;
int ascii = (
int)strtol(code, &end,
16);
if(errno ==
0 && end == &code[
2]) {
path[k] = ascii;
i +=
2;
}
else {
err =
1;
break;
}
}
else {
err =
1;
break;
}
}
else if(c ==
'\n' || c ==
'\r') {
break;
}
else {
path[k] = c;
}
k++;
}
path[k] =
'\0';
if(err ==
0) {
char *params[
2];
params[
0] = path;
params[
1] =
NULL;
XtCallActionProc(w,
"open",
NULL, params,
1);
}
else {
fprintf(stderr,
"dnd open file: url decode error\n");
}
NEditFree(path);
}
XrmDatabase GetDefaultResourceDB(
void)
{
return defaultResourceDB;
}