/*
* JOE options
* Copyright
* (C) 1992 Joseph H. Allen
*
* This file is part of JOE (Joe's Own Editor)
*/
#include "types.h"
#define HEX_RESTORE_UTF8 2
#define HEX_RESTORE_CRLF 4
#define OPT_BUF_SIZE 300
const char *aborthint = "^C";
const char *helphint = "^K H";
OPTIONS *options_list = NULL; /* File name dependent list of options */
/* Default options for prompt windows */
OPTIONS pdefault = {
NULL, /* *next */
"prompt", /* ftype */
NULL, /* *match */
0, /* overtype */
0, /* lmargin */
76, /* rmargin */
0, /* autoindent */
0, /* wordwrap */
0, /* nobackup */
8, /* tab */
' ', /* indent char */
1, /* indent step */
NULL, /* *context */
NULL, /* *lmsg */
NULL, /* *rmsg */
NULL, /* *smsg */
NULL, /* *zmsg */
0, /* line numbers */
0, /* read only */
0, /* french spacing */
0, /* flowed text */
0, /* spaces */
#ifdef __MSDOS__
1, /* crlf */
#else
0, /* crlf */
#endif
0, /* Highlight */
NULL, /* Syntax name */
NULL, /* Syntax */
NULL, /* Name of character set */
NULL, /* Character set */
NULL, /* Language */
0, /* Smart home key */
0, /* Goto indent first */
0, /* Smart backspace key */
0, /* Purify indentation */
0, /* Picture mode */
0, /* highlighter_context */
0, /* single_quoted */
0, /* no_double_quoted */
0, /* c_comment */
0, /* cpp_comment */
0, /* pound_comment */
0, /* vhdl_comment */
0, /* semi_comment */
0, /* tex_comment */
0, /* hex */
0, /* hide ansi */
NULL, /* text_delimiters */
NULL, /* Characters which can indent paragraphs */
NULL, /* Characters which begin non-paragraph lines */
NULL, /* macro to execute for new files */
NULL, /* macro to execute for existing files */
NULL, /* macro to execute before saving new files */
NULL, /* macro to execute before saving existing files */
NULL /* macro to execute on first change */
};
/* Default options for file windows */
OPTIONS fdefault = {
NULL, /* *next */
"default", /* ftype */
NULL, /* *match */
0, /* overtype */
0, /* lmargin */
76, /* rmargin */
0, /* autoindent */
0, /* wordwrap */
0, /* nobackup */
8, /* tab */
' ', /* indent char */
1, /* indent step */
"main", /* *context */
"\\i%n %m %M", /* *lmsg */
" %S Ctrl-K H for help", /* *rmsg */
NULL, /* *smsg */
NULL, /* *zmsg */
0, /* line numbers */
0, /* read only */
0, /* french spacing */
0, /* flowed text */
0, /* spaces */
#ifdef __MSDOS__
1, /* crlf */
#else
0, /* crlf */
#endif
0, /* Highlight */
NULL, /* Syntax name */
NULL, /* Syntax */
NULL, /* Name of character set */
NULL, /* Character set */
NULL, /* Language */
0, /* Smart home key */
0, /* Goto indent first */
0, /* Smart backspace key */
0, /* Purity indentation */
0, /* Picture mode */
0, /* highlighter_context */
0, /* single_quoted */
0, /* no_double_quoted */
0, /* c_comment */
0, /* cpp_comment */
0, /* pound_comment */
0, /* vhdl_comment */
0, /* semi_comment */
0, /* tex_comment */
0, /* hex */
0, /* hide ansi */
NULL, /* text_delimiters */
">;!#%/", /* Characters which can indent paragraphs */
".", /* Characters which begin non-paragraph lines */
NULL, NULL, NULL, NULL, NULL /* macros (see above) */
};
/* Commands which just type in variable values */
int ucharset(W *w, int k)
{
const char *s;
BW *bw;
WIND_BW(bw, w);
w = w->main;
s = ((BW *)w->object)->o.charmap->name;
if (!s || !*s)
return -1;
while (*s)
if (utypebw(bw,*(const unsigned char *)s++))
return -1;
return 0;
}
int ulanguage(W *w, int k)
{
BW *bw;
const char *s;
WIND_BW(bw, w);
w = bw->parent->main;
s = ((BW *)w->object)->o.language;
if (!s || !*s)
return -1;
while (*s)
if (utypebw(bw,*(const unsigned char *)s++))
return -1;
return 0;
}
/* Update options
* This determines option values based on option names, for example it looks up the character map based on name */
void lazy_opts(B *b, OPTIONS *o)
{
struct charmap *orgmap = b->o.charmap; /* Remember guessed character map */
o->syntax = load_syntax(o->syntax_name);
b->o = *o;
if (!b->o.map_name || !(b->o.charmap = find_charmap(b->o.map_name))) {
/* Use the guessed one if it wasn't explicitly given */
b->o.charmap = orgmap;
if (orgmap)
b->o.map_name = orgmap->name;
}
if (!b->o.charmap)
b->o.charmap = locale_map;
if (!b->o.language)
b->o.language = locale_msgs;
if (b->o.hex) {
/* Hex not allowed with UTF-8 */
if (b->o.charmap->type) {
b->o.charmap = find_charmap("c");
b->o.hex |= HEX_RESTORE_UTF8;
}
/* Hex not allowed with CRLF */
if (b->o.crlf) {
b->o.crlf = 0;
b->o.hex |= HEX_RESTORE_CRLF;
}
}
}
/* Set local options depending on file name and contents */
void setopt(B *b, const char *parsed_name)
{
OPTIONS *o;
for (o = options_list; o; o = o->next) {
struct options_match *match;
for (match = o->match; match; match = match->next) {
if (rmatch(match->name_regex, parsed_name)) {
if(match->contents_regex) {
P *p = pdup(b->bof, "setopt");
if (!match->r_contents_regex)
match->r_contents_regex = joe_regcomp(ascii_map, match->contents_regex, zlen(match->contents_regex), 0, 1, 0);
if (match->r_contents_regex && !joe_regexec(match->r_contents_regex, p, 0, 0, 0)) {
prm(p);
lazy_opts(b, o);
goto done;
} else {
prm(p);
}
} else {
lazy_opts(b, o);
goto done;
}
}
}
}
lazy_opts(b, &fdefault);
done:;
}
/* Table of options and how to set them */
/* local means it's in an OPTION structure, global means it's in a global
* variable */
struct glopts {
const char *name; /* Option name */
int type; /* 0 for global option flag
1 for global option int
2 for global option string (in locale encoding)
4 for local option flag
5 for local option int
14 for local option off_t
6 for local option string (in utf8)
7 for local option off_t+1, with range checking
9 for syntax (options->syntax_name)
13 for byte encoding (options->map_name)
15 for file type (options->ftype)
*/
void *set; /* Address of global option */
const char *addr; /* Local options structure member address */
const char *yes; /* Message if option was turned on, or prompt string */
const char *no; /* Message if option was turned off */
const char *menu; /* Menu string */
ptrdiff_t ofst; /* Local options structure member offset */
int low; /* Low limit for numeric options */
int high; /* High limit for numeric options */
} glopts[] = {
{"overwrite",4, NULL, (char *) &fdefault.overtype, _("Overtype mode"), _("Insert mode"), _("T Overtype "), 0, 0, 0 },
{"hex",4, NULL, (char *) &fdefault.hex, _("Hex edit mode"), _("Text edit mode"), _(" Hex edit mode "), 0, 0, 0 },
{"ansi",4, NULL, (char *) &fdefault.ansi, _("Hide ANSI sequences"), _("Reveal ANSI sequences"), _(" Hide ANSI mode "), 0, 0, 0 },
{"autoindent", 4, NULL, (char *) &fdefault.autoindent, _("Autoindent enabled"), _("Autoindent disabled"), _("I Autoindent "), 0, 0, 0 },
{"wordwrap", 4, NULL, (char *) &fdefault.wordwrap, _("Wordwrap enabled"), _("Wordwrap disabled"), _("W Word wrap "), 0, 0, 0 },
{"tab", 14, NULL, (char *) &fdefault.tab, _("Tab width (%lld): "), 0, _("D Tab width "), 0, 1, 64 },
{"lmargin", 7, NULL, (char *) &fdefault.lmargin, _("Left margin (%d): "), 0, _("L Left margin "), 0, 0, 63 },
{"rmargin", 7, NULL, (char *) &fdefault.rmargin, _("Right margin (%d): "), 0, _("R Right margin "), 0, 7, 255 },
{"restore", 0, &restore_file_pos, NULL, _("Restore cursor position when files loaded"), _("Don't restore cursor when files loaded"), _(" Restore cursor "), 0, 0, 0 },
{"regex", 0, &std_regex, NULL, _("Standard regular expression format"), _("JOE regular expression format"), _(" Regex "), 0, 0, 0 },
{"square", 0, &square, NULL, _("Rectangle mode"), _("Text-stream mode"), _("X Rectangle mode "), 0, 0, 0 },
{"icase", 0, &opt_icase, NULL, _("Search ignores case by default"), _("Case sensitive search by default"), _(" Case insensitivity "), 0, 0, 0 },
{"wrap", 0, &wrap, NULL, _("Search wraps"), _("Search doesn't wrap"), _(" Search wraps "), 0, 0, 0 },
{"menu_explorer", 0, &menu_explorer, NULL, _("Menu explorer mode"), _("Simple completion mode"), _(" Menu explorer "), 0, 0, 0 },
{"menu_above", 0, &menu_above, NULL, _("Menu above prompt"), _("Menu below prompt"), _(" Menu position "), 0, 0, 0 },
{"notagsmenu", 0, ¬agsmenu, NULL, _("Tags menu disabled"), _("Tags menu enabled"), _(" Disable tags menu "), 0, 0, 0 },
{"search_prompting", 0, &pico, NULL, _("Search prompting on"), _("Search prompting off"), _(" Search prompting "), 0, 0, 0 },
{"menu_jump", 0, &menu_jump, NULL, _("Jump into menu is on"), _("Jump into menu is off"), _(" Jump into menu "), 0, 0, 0 },
{"autoswap", 0, &autoswap, NULL, _("Autoswap ^KB and ^KK"), _("Autoswap off "), _(" Autoswap mode "), 0, 0, 0 },
{"indentc", 5, NULL, (char *) &fdefault.indentc, _("Indent char %d (SPACE=32, TAB=9, %{abort} to abort): "), 0, _(" Indent char "), 0, 0, 255 },
{"istep", 14, NULL, (char *) &fdefault.istep, _("Indent step %lld (%{abort} to abort): "), 0, _(" Indent step "), 0, 1, 64 },
{"french", 4, NULL, (char *) &fdefault.french, _("One space after periods for paragraph reformat"), _("Two spaces after periods for paragraph reformat"), _(" French spacing "), 0, 0, 0 },
{"flowed", 4, NULL, (char *) &fdefault.flowed, _("One space after paragraph line"), _("No spaces after paragraph lines"), _(" Flowed text "), 0, 0, 0 },
{"highlight", 4, NULL, (char *) &fdefault.highlight, _("Highlighting enabled"), _("Highlighting disabled"), _("H Highlighting "), 0, 0, 0 },
{"spaces", 4, NULL, (char *) &fdefault.spaces, _("Inserting spaces when tab key is hit"), _("Inserting tabs when tab key is hit"), _(" No tabs "), 0, 0, 0 },
{"mid", 0, &opt_mid, NULL, _("Cursor will be recentered on scrolls"), _("Cursor will not be recentered on scroll"), _("C Center on scroll "), 0, 0, 0 },
{"left", 1, &opt_left, NULL, _("Columns to scroll left or -1 for 1/2 window (%d): "), 0, _(" Left scroll columns "), 0, -128, 127 },
{"right", 1, &opt_right, NULL, _("Columns to scroll right or -1 for 1/2 window (%d): "), 0, _(" Right scroll columns "), 0, -128, 127 },
{"guess_crlf",0, &guesscrlf, NULL, _("Automatically detect MS-DOS files"), _("Do not automatically detect MS-DOS files"), _(" Auto detect CR-LF "), 0, 0, 0 },
{"guess_indent",0, &guessindent, NULL, _("Automatically detect indentation"), _("Do not automatically detect indentation"), _(" Guess indent "), 0, 0, 0 },
{"guess_non_utf8",0, &guess_non_utf8, NULL, _("Automatically detect non-UTF-8 in UTF-8 locale"), _("Do not automatically detect non-UTF-8"), _(" Guess non-UTF-8 "), 0, 0, 0 },
{"guess_utf8",0, &guess_utf8, NULL, _("Automatically detect UTF-8 in non-UTF-8 locale"), _("Do not automatically detect UTF-8"), _(" Guess UTF-8 "), 0, 0, 0 },
{"guess_utf16",0, &guess_utf16, NULL, _("Automatically detect UTF-16"), _("Do not automatically detect UTF-16"), _(" Guess UTF-16 "), 0, 0, 0 },
{"transpose",0, &transpose, NULL, _("Menu is transposed"), _("Menus are not transposed"), _(" Transpose menus "), 0, 0, 0 },
{"crlf", 4, NULL, (char *) &fdefault.crlf, _("CR-LF is line terminator"), _("LF is line terminator"), _("Z CR-LF (MS-DOS) "), 0, 0, 0 },
{"linums", 4, NULL, (char *) &fdefault.linums, _("Line numbers enabled"), _("Line numbers disabled"), _("N Line numbers "), 0, 0, 0 },
{"marking", 0, &marking, NULL, _("Anchored block marking on"), _("Anchored block marking off"), _(" Marking "), 0, 0, 0 },
{"asis", 0, &dspasis, NULL, _("Characters above 127 shown as-is"), _("Characters above 127 shown in inverse"), _(" Meta chars as-is "), 0, 0, 0 },
{"force", 0, &force, NULL, _("Last line forced to have NL when file saved"), _("Last line not forced to have NL"), _(" Force last NL "), 0, 0, 0 },
{"joe_state",0, &joe_state, NULL, _("~/.joe_state file will be updated"), _("~/.joe_state file will not be updated"), _(" Joe_state file "), 0, 0, 0 },
{"nobackup", 4, NULL, (char *) &fdefault.nobackup, _("Nobackup enabled"), _("Nobackup disabled"), _(" No backup "), 0, 0, 0 },
{"nobackups", 0, &nobackups, NULL, _("Backup files will not be made"), _("Backup files will be made"), _(" Disable backups "), 0, 0, 0 },
{"nodeadjoe", 0, &nodeadjoe, NULL, _("DEADJOE files will not be made"), _("DEADJOE files will be made"), _(" Disable DEADJOE "), 0, 0, 0 },
{"nolocks", 0, &nolocks, NULL, _("Files will not be locked"), _("Files will be locked"), _(" Disable locks "), 0, 0, 0 },
{"nomodcheck", 0, &nomodcheck, NULL, _("No file modification time check"), _("File modification time checking enabled"), _(" Disable mtime check "), 0, 0, 0 },
{"nocurdir", 0, &nocurdir, NULL, _("No current dir"), _("Current dir enabled"), _(" Disable current dir "), 0, 0, 0 },
{"break_hardlinks", 0, &break_links, NULL, _("Hardlinks will be broken"), _("Hardlinks not broken"), _(" Break hard links "), 0, 0, 0 },
{"break_links", 0, &break_symlinks, NULL, _("Links will be broken"), _("Links not broken"), _(" Break links "), 0, 0, 0 },
{"lightoff", 0, &lightoff, NULL, _("Highlighting turned off after block operations"), _("Highlighting not turned off after block operations"), _(" Auto unmark "), 0, 0, 0 },
{"exask", 0, &exask, NULL, _("Prompt for filename in save & exit command"), _("Don't prompt for filename in save & exit command"), _(" Exit ask "), 0, 0, 0 },
{"beep", 0, &joe_beep, NULL, _("Warning bell enabled"), _("Warning bell disabled"), _("B Beeps "), 0, 0, 0 },
{"nosta", 0, &staen, NULL, _("Top-most status line disabled"), _("Top-most status line enabled"), _(" Disable status line "), 0, 0, 0 },
{"keepup", 0, &keepup, NULL, _("Status line updated constantly"), _("Status line updated once/sec"), _(" Fast status line "), 0, 0, 0 },
{"pg", 1, &pgamnt, NULL, _("Lines to keep for PgUp/PgDn or -1 for 1/2 window (%d): "), 0, _(" No. PgUp/PgDn lines "), 0, -1, 64 },
{"undo_keep", 1, &undo_keep, NULL, _("No. undo records to keep, or (0 for infinite): "), 0, _(" No. undo records "), 0, -1, 64 },
{"csmode", 0, &csmode, NULL, _("Start search after a search repeats previous search"), _("Start search always starts a new search"), _(" Continued search "), 0, 0, 0 },
{"rdonly", 4, NULL, (char *) &fdefault.readonly, _("Read only"), _("Full editing"), _("O Read only "), 0, 0, 0 },
{"smarthome", 4, NULL, (char *) &fdefault.smarthome, _("Smart home key enabled"), _("Smart home key disabled"), _(" Smart home key "), 0, 0, 0 },
{"indentfirst", 4, NULL, (char *) &fdefault.indentfirst, _("Smart home goes to indentation first"), _("Smart home goes home first"), _(" To indent first "), 0, 0, 0 },
{"smartbacks", 4, NULL, (char *) &fdefault.smartbacks, _("Smart backspace key enabled"), _("Smart backspace key disabled"), _(" Smart backspace "), 0, 0, 0 },
{"purify", 4, NULL, (char *) &fdefault.purify, _("Indentation clean up enabled"), _("Indentation clean up disabled"), _(" Clean up indents "), 0, 0, 0 },
{"picture", 4, NULL, (char *) &fdefault.picture, _("Picture drawing mode enabled"), _("Picture drawing mode disabled"), _("P Picture mode "), 0, 0, 0 },
{"backpath", 2, &backpath, NULL, _("Backup files stored in (%s): "), 0, _(" Path to backup files "), 0, 0, 0 },
{"syntax", 9, NULL, NULL, _("Select syntax (%{abort} to abort): "), 0, _("Y Syntax"), 0, 0, 0 },
{"encoding",13, NULL, NULL, _("Select file character set (%{abort} to abort): "), 0, _("E Encoding "), 0, 0, 0 },
{"type", 15, NULL, NULL, _("Select file type (%{abort} to abort): "), 0, _("F File type "), 0, 0, 0 },
{"highlighter_context", 4, NULL, (char *) &fdefault.highlighter_context, _("Highlighter context enabled"), _("Highlighter context disabled"), _(" ^G uses highlighter context "), 0, 0, 0 },
{"single_quoted", 4, NULL, (char *) &fdefault.single_quoted, _("Single quoting enabled"), _("Single quoting disabled"), _(" ^G ignores '... ' "), 0, 0, 0 },
{"no_double_quoted",4, NULL, (char *) &fdefault.no_double_quoted, _("Double quoting disabled"), _("Double quoting enabled"), _(" ^G ignores \"... \" "), 0, 0, 0 },
{"c_comment", 4, NULL, (char *) &fdefault.c_comment, _("/* comments enabled"), _("/* comments disabled"), _(" ^G ignores /*...*/ "), 0, 0, 0 },
{"cpp_comment", 4, NULL, (char *) &fdefault.cpp_comment, _("// comments enabled"), _("// comments disabled"), _(" ^G ignores //... "), 0, 0, 0 },
{"pound_comment", 4, NULL, (char *) &fdefault.pound_comment, _("# comments enabled"), _("# comments disabled"), _(" ^G ignores #... "), 0, 0, 0 },
{"vhdl_comment", 4, NULL, (char *) &fdefault.vhdl_comment, _("-- comments enabled"), _("-- comments disabled"), _(" ^G ignores --... "), 0, 0, 0 },
{"semi_comment", 4, NULL, (char *) &fdefault.semi_comment, _("; comments enabled"), _("; comments disabled"), _(" ^G ignores ;... "), 0, 0, 0 },
{"tex_comment", 4, NULL, (char *) &fdefault.tex_comment, _("% comments enabled"), _("% comments disabled"), _(" ^G ignores %... "), 0, 0, 0 },
{"text_delimiters", 6, NULL, (char *) &fdefault.text_delimiters, _("Text delimiters (%s): "), 0, _(" Text delimiters "), 0, 0, 0 },
{"language", 6, NULL, (char *) &fdefault.language, _("Language (%s): "), 0, _("V Language "), 0, 0, 0 },
{"cpara", 6, NULL, (char *) &fdefault.cpara, _("Characters which can indent paragraphs (%s): "), 0, _(" Paragraph indent chars "), 0, 0, 0 },
{"cnotpara", 6, NULL, (char *) &fdefault.cnotpara, _("Characters which begin non-paragraph lines (%s): "), 0, _(" Non-paragraph chars "), 0, 0, 0 },
{"floatmouse", 0, &floatmouse, 0, _("Clicking can move the cursor past end of line"), _("Clicking past end of line moves cursor to the end"), _(" Click past end "), 0, 0, 0 },
{"rtbutton", 0, &rtbutton, 0, _("Mouse action is done with the right button"), _("Mouse action is done with the left button"), _(" Right button "), 0, 0, 0 },
{"nonotice", 0, &nonotice, NULL, 0, 0, 0, 0, 0, 0 },
{"noexmsg", 0, &noexmsg, NULL, 0, 0, 0, 0, 0, 0 },
{"help_is_utf8", 0, &help_is_utf8, NULL, 0, 0, 0, 0, 0, 0 },
{"noxon", 0, &noxon, NULL, 0, 0, 0, 0, 0, 0 },
{"orphan", 0, &orphan, NULL, 0, 0, 0, 0, 0, 0 },
{"help", 0, &help, NULL, 0, 0, 0, 0, 0, 0 },
{"dopadding", 0, &dopadding, NULL, 0, 0, 0, 0, 0, 0 },
{"lines", 1, &env_lines, NULL, 0, 0, 0, 0, 2, 1024 },
{"baud", 1, &Baud, NULL, 0, 0, 0, 0, 50, 32767 },
{"columns", 1, &env_columns, NULL, 0, 0, 0, 0, 2, 1024 },
{"skiptop", 1, &skiptop, NULL, 0, 0, 0, 0, 0, 64 },
{"notite", 0, ¬ite, NULL, 0, 0, 0, 0, 0, 0 },
{"brpaste", 0, &brpaste, NULL, 0, 0, 0, 0, 0, 0 },
{"pastehack", 0, &pastehack, NULL, 0, 0, 0, 0, 0, 0 },
{"nolinefeeds", 0, &nolinefeeds, NULL, 0, 0, 0, 0, 0, 0 },
{"mouse", 0, &xmouse, NULL, 0, 0, 0, 0, 0, 0 },
{"usetabs", 0, &opt_usetabs, NULL, 0, 0, 0, 0, 0, 0 },
{"assume_color", 0, &assume_color, NULL, 0, 0, 0, 0, 0, 0 },
{"assume_256color", 0, &assume_256color, NULL, 0, 0, 0, 0, 0, 0 },
{"joexterm", 0, &joexterm, NULL, 0, 0, 0, 0, 0, 0 },
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 0, 0 }
};
/* Initialize .ofsts above. Is this really necessary? */
int isiz = 0;
HASH *opt_tab;
static void izopts(void)
{
int x;
opt_tab = htmk(128);
for (x = 0; glopts[x].name; ++x) {
htadd(opt_tab, glopts[x].name, glopts + x);
switch (glopts[x].type) {
case 4:
case 5:
case 6:
case 7:
case 8:
case 14:
glopts[x].ofst = glopts[x].addr - (char *) &fdefault;
}
}
isiz = 1;
}
/* Set file type option */
static char **getftypes(void)
{
OPTIONS *o;
char **s = vaensure(NULL, 20);
for (o = options_list; o; o = o->next)
s = vaadd(s, vsncpy(NULL, 0, sz(o->ftype)));
vasort(s, aLen(s));
return s;
}
char **ftypes = NULL; /* Array of file types */
static int ftypecmplt(BW *bw, int k)
{
if (!ftypes)
ftypes = getftypes();
return simple_cmplt(bw, ftypes);
}
static OPTIONS *find_ftype(const char *s)
{
OPTIONS *o;
for (o = options_list; o; o = o->next)
if (!zcmp(o->ftype, s))
break;
return o;
}
static int doftype(W *w, char *s, void *object, int *notify)
{
BW *bw;
OPTIONS *o = find_ftype(s);
WIND_BW(bw, w);
vsrm(s);
if (!o) {
msgnw(bw->parent, joe_gettext(_("No such file type")));
if (notify)
*notify = 1;
return -1;
} else {
lazy_opts(bw->b, o);
bw->o = bw->b->o;
return 0;
}
}
B *ftypehist = NULL;
/* Set a global or local option:
* 's' is option name
* 'arg' is a possible argument string (taken only if option has an arg)
* 'options' points to options structure to modify (can be NULL).
* 'set'==0: set only in 'options' if it's given.
* 'set'!=0: set global variable option.
* return value: no. of fields taken (1 or 2), or 0 if option not found.
*
* So this function is used both to set options, and to parse over options
* without setting them.
*
* These combinations are used:
*
* glopt(name,arg,NULL,1): set global variable option
* glopt(name,arg,NULL,0): parse over option
* glopt(name,arg,options,0): set file local option
* glopt(name,arg,&fdefault,1): set default file options
* glopt(name,arg,options,1): set file local option
*/
int glopt(char *s, char *arg, OPTIONS *options, int set)
{
int val;
int ret = 0;
int st = 1; /* 1 to set option, 0 to clear it */
struct glopts *opt;
/* Initialize offsets */
if (!isiz)
izopts();
/* Clear instead of set? */
if (s[0] == '-') {
st = 0;
++s;
}
opt = (struct glopts *)htfind(opt_tab, s);
if (opt) {
switch (opt->type) {
case 0: /* Global variable flag option */
if (set)
*(int *)opt->set = st;
ret = 1;
break;
case 1: /* Global variable integer option */
if (set && arg) {
val = ztoi(arg);
if (val >= opt->low && val <= opt->high)
*(int *)opt->set = val;
}
if (arg)
ret = 2;
else
ret = 1;
break;
case 2: /* Global variable string option */
if (set) {
if (arg)
*(char **) opt->set = zdup(arg);
else
*(char **) opt->set = 0;
}
if (arg)
ret = 2;
else
ret = 1;
break;
case 4: /* Local option flag */
if (options)
*(int *) ((char *) options + opt->ofst) = st;
ret = 1;
break;
case 5: /* Local option integer */
if (arg) {
if (options) {
val = ztoi(arg);
if (val >= opt->low && val <= opt->high)
*(int *) ((char *)
options + opt->ofst) = val;
}
}
if (arg)
ret = 2;
else
ret = 1;
break;
case 14: /* Local option off_t */
if (arg) {
if (options) {
off_t zz = ztoo(arg);
if (zz >= opt->low && zz <= opt->high)
*(off_t *) ((char *)
options + opt->ofst) = zz;
}
}
if (arg)
ret = 2;
else
ret = 1;
break;
case 15: /* Set file type */
if (arg && options) {
OPTIONS *o = find_ftype(arg);
if (o) {
*options = *o;
}
}
if (arg)
ret = 2;
else
ret = 1;
break;
case 6: /* Local string option */
if (options) {
if (arg) {
*(char **) ((char *)
options + opt->ofst) = zdup(arg);
} else {
*(char **) ((char *)
options + opt->ofst) = 0;
}
}
if (arg)
ret = 2;
else
ret = 1;
break;
case 7: /* Local option numeric + 1, with range checking */
if (arg) {
off_t zz = ztoo(arg);
if (zz >= opt->low && zz <= opt->high) {
--zz;
if (options)
*(off_t *) ((char *)
options + opt->ofst) = zz;
}
}
if (arg)
ret = 2;
else
ret = 1;
break;
case 9: /* Set syntax */
if (arg && options)
options->syntax_name = zdup(arg);
/* this was causing all syntax files to be loaded...
if (arg && options)
options->syntax = load_syntax(arg); */
if (arg)
ret = 2;
else
ret = 1;
break;
case 13: /* Set byte mode encoding */
if (arg && options)
options->map_name = zdup(arg);
if (arg)
ret = 2;
else
ret = 1;
break;
}
} else {
/* Why no case 6, string option? */
/* Keymap, mold, mnew, etc. are not strings */
/* These options do not show up in ^T */
if (!zcmp(s, "xmsg")) {
if (arg) {
xmsg = zdup(arg);
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "aborthint")) {
if (arg) {
aborthint = zdup(arg);
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "helphint")) {
if (arg) {
helphint = zdup(arg);
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "lmsg")) {
if (arg) {
if (options)
options->lmsg = zdup(arg);
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "rmsg")) {
if (arg) {
if (options)
options->rmsg = zdup(arg);
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "smsg")) {
if (arg) {
if (options)
options->smsg = zdup(arg);
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "zmsg")) {
if (arg) {
if (options)
options->zmsg = zdup(arg);
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "keymap")) {
if (arg) {
int y;
for (y = 0; !joe_isspace(locale_map,arg[y]); ++y) ;
if (!arg[y])
arg[y] = 0;
if (options && y)
options->context = zdup(arg);
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "mnew")) {
if (arg) {
ptrdiff_t sta;
if (options)
options->mnew = mparse(NULL, arg, &sta, 0);
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "mfirst")) {
if (arg) {
ptrdiff_t sta;
if (options)
options->mfirst = mparse(NULL, arg, &sta, 0);
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "mold")) {
if (arg) {
ptrdiff_t sta;
if (options)
options->mold = mparse(NULL, arg, &sta, 0);
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "msnew")) {
if (arg) {
ptrdiff_t sta;
if (options)
options->msnew = mparse(NULL, arg, &sta, 0);
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "msold")) {
if (arg) {
ptrdiff_t sta;
if (options)
options->msold = mparse(NULL, arg, &sta, 0);
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "text_color")) {
if (arg) {
bg_text = meta_color(arg);
bg_help = bg_text;
bg_prompt = bg_text;
bg_menu = bg_text;
bg_msg = bg_text;
bg_stalin = bg_text;
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "help_color")) {
if (arg) {
bg_help = meta_color(arg);
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "status_color")) {
if (arg) {
bg_stalin = meta_color(arg);
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "menu_color")) {
if (arg) {
bg_menu = meta_color(arg);
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "prompt_color")) {
if (arg) {
bg_prompt = meta_color(arg);
ret = 2;
} else
ret = 1;
} else if (!zcmp(s, "msg_color")) {
if (arg) {
bg_msg = meta_color(arg);
ret = 2;
} else
ret = 1;
}
}
return ret;
}
/* Option setting user interface (^T command) */
static int doabrt1(W *w, void *obj)
{
int *xx = (int *)obj;
joe_free(xx);
return -1;
}
static int doopt1(W *w, char *s, void *obj, int *notify)
{
BW *bw;
int ret = 0;
int *xx = (int *)obj;
int x = *xx;
int v;
off_t vv;
WIND_BW(bw, w);
joe_free(xx);
switch (glopts[x].type) {
case 1:
v = (int)calc(bw, s, 0);
if (merr) {
msgnw(bw->parent, merr);
ret = -1;
} else if (v >= glopts[x].low && v <= glopts[x].high)
*(int *)glopts[x].set = v;
else {
msgnw(bw->parent, joe_gettext(_("Value out of range")));
ret = -1;
}
break;
case 2:
if (s[0])
*(char **) glopts[x].set = zdup(s);
break;
case 6:
*(char **)((char *)&bw->o+glopts[x].ofst) = zdup(s);
break;
case 5:
v = (int)calc(bw, s, 0);
if (merr) {
msgnw(bw->parent, merr);
ret = -1;
} else if (v >= glopts[x].low && v <= glopts[x].high)
*(int *) ((char *) &bw->o + glopts[x].ofst) = v;
else {
msgnw(bw->parent, joe_gettext(_("Value out of range")));
ret = -1;
}
break;
case 14:
vv = (off_t)calc(bw, s, 0);
if (merr) {
msgnw(bw->parent, merr);
ret = -1;
} else if (vv >= glopts[x].low && vv <= glopts[x].high)
*(off_t *) ((char *) &bw->o + glopts[x].ofst) = vv;
else {
msgnw(bw->parent, joe_gettext(_("Value out of range")));
ret = -1;
}
break;
case 7:
vv = (off_t)(calc(bw, s, 0) - 1.0);
if (merr) {
msgnw(bw->parent, merr);
ret = -1;
} else if (vv >= glopts[x].low && vv <= glopts[x].high)
*(off_t *) ((char *) &bw->o + glopts[x].ofst) = vv;
else {
msgnw(bw->parent, joe_gettext(_("Value out of range")));
ret = -1;
}
break;
}
vsrm(s);
bw->b->o = bw->o;
wfit(bw->parent->t);
updall();
if (notify)
*notify = 1;
return ret;
}
static int dosyntax(W *w, char *s, void *obj, int *notify)
{
BW *bw;
int ret = 0;
struct high_syntax *syn;
WIND_BW(bw, w);
syn = load_syntax(s);
if (syn)
bw->o.syntax = syn;
else
msgnw(bw->parent, joe_gettext(_("Syntax definition file not found")));
vsrm(s);
bw->b->o = bw->o;
updall();
if (notify)
*notify = 1;
return ret;
}
char **syntaxes = NULL; /* Array of available syntaxes */
static int syntaxcmplt(BW *bw, int k)
{
if (!syntaxes) {
char *oldpwd = pwd();
char **t;
char **syntmp = NULL;
char *p;
int x, y;
/* Load first from global (NOTE: Order here does not matter.) */
if (!chpwd((JOEDATA "syntax")) && (t = rexpnd("*.jsf"))) {
for (x = 0; x != aLEN(t); ++x) {
char *r = vsncpy(NULL,0,t[x],zrchr((t[x]),'.')-t[x]);
syntmp = vaadd(syntmp,r);
}
varm(t);
}
/* Load from home directory. */
p = getenv("HOME");
if (p) {
char buf[1024];
joe_snprintf_1(buf,SIZEOF(buf),"%s/.joe/syntax",p);
if (!chpwd(buf) && (t = rexpnd("*.jsf"))) {
for (x = 0; x != aLEN(t); ++x)
*zrchr(t[x],'.') = 0;
for (x = 0; x != aLEN(t); ++x) {
for (y = 0; y != aLEN(syntmp); ++y)
if (!zcmp(t[x],syntmp[y]))
break;
if (y == aLEN(syntmp)) {
char *r = vsncpy(NULL,0,sv(t[x]));
syntmp = vaadd(syntmp,r);
}
}
varm(t);
}
}
/* Load from builtins. */
t = jgetbuiltins(".jsf");
for (x = 0; x != aLEN(t); ++x) {
*zrchr(t[x], '.') = 0;
for (y = 0; y != aLEN(syntmp); ++y)
if (!zcmp(t[x], syntmp[y]))
break;
if (y == aLEN(syntmp)) {
char *r = vsncpy(NULL, 0, sv(t[x]));
syntmp = vaadd(syntmp, r);
}
}
varm(t);
if (aLEN(syntmp)) {
vasort(av(syntmp));
syntaxes = syntmp;
}
chpwd(oldpwd);
}
return simple_cmplt(bw,syntaxes);
}
static int check_for_hex(BW *bw)
{
W *w;
if (bw->o.hex)
return 1;
for (w = bw->parent->link.next; w != bw->parent; w = w->link.next)
if ((w->watom == &watomtw || w->watom == &watompw) && ((BW *)w->object)->b == bw->b &&
((BW *)w->object)->o.hex)
return 1;
return 0;
}
static int doencoding(W *w, char *s, void *obj, int *notify)
{
BW *bw;
int ret = 0;
struct charmap *map;
WIND_BW(bw, w);
map = find_charmap(s);
if (map && map->type && check_for_hex(bw)) {
msgnw(bw->parent, joe_gettext(_("UTF-8 encoding not allowed with hexadecimal windows")));
if (notify)
*notify = 1;
return -1;
}
if (map) {
bw->o.charmap = map;
joe_snprintf_1(msgbuf, JOE_MSGBUFSIZE, joe_gettext(_("%s encoding assumed for this file")), map->name);
msgnw(bw->parent, msgbuf);
} else
msgnw(bw->parent, joe_gettext(_("Character set not found")));
vsrm(s);
bw->b->o = bw->o;
bw->cursor->valcol = 0;
bw->cursor->xcol = piscol(bw->cursor);
updall();
if (notify)
*notify = 1;
return ret;
}
char **encodings = NULL; /* Array of available encodinges */
static int encodingcmplt(BW *bw, int k)
{
if (!encodings) {
encodings = get_encodings();
vasort(av(encodings));
}
return simple_cmplt(bw,encodings);
}
static int find_option(char *s)
{
int y;
for (y = 0; glopts[y].name; ++y)
if (!zcmp(glopts[y].name, s))
return y;
return -1;
}
static int applyopt(BW *bw, void *optp, int y, int flg)
{
int oldval, newval;
oldval = *(int *)optp;
if (flg == 0) {
/* Return pressed: toggle */
newval = !oldval;
} else if (flg == 1) {
/* '1' pressed */
newval = oldval ? oldval : 1; /* Keep oldval if already 'on' */
} else {
/* '0' or backspace or something else */
newval = 0;
}
*(int *)optp = newval;
msgnw(bw->parent, newval ? joe_gettext(glopts[y].yes) : joe_gettext(glopts[y].no));
return oldval;
}
static int olddoopt(BW *bw, int y, int flg, int *notify)
{
int *xx, oldval;
char buf[OPT_BUF_SIZE];
if (y >= 0) {
switch (glopts[y].type) {
case 0:
applyopt(bw, glopts[y].set, y, flg);
break;
case 4:
oldval = applyopt(bw, (char *) &bw->o + glopts[y].ofst, y, flg);
/* Propagate readonly bit to B */
if (glopts[y].ofst == (char *) &fdefault.readonly - (char *) &fdefault)
bw->b->rdonly = bw->o.readonly;
/* Kill UTF-8 and CRLF modes if we switch to hex display */
if (glopts[y].ofst == (char *) &fdefault.hex - (char *) &fdefault) {
if (bw->o.hex && !oldval) {
bw->o.hex = 1;
if (bw->b->o.charmap->type) {
/* Switch out of UTF-8 mode */
doencoding(bw->parent, vsncpy(NULL, 0, sc("C")), NULL, NULL);
bw->o.hex |= HEX_RESTORE_UTF8;
}
if (bw->o.crlf) {
/* Switch out of CRLF mode */
bw->o.crlf = 0;
bw->o.hex |= HEX_RESTORE_CRLF;
}
} else if (!bw->o.hex && oldval) {
if ((oldval & HEX_RESTORE_UTF8) && !zcmp(bw->b->o.charmap->name, "ascii")) {
/* Switch back into UTF-8 */
doencoding(bw->parent, vsncpy(NULL, 0, sc("UTF-8")), NULL, NULL);
}
if (oldval & HEX_RESTORE_CRLF) {
/* Turn CRLF back on */
bw->o.crlf = 1;
}
}
}
break;
case 6:
xx = (int *) joe_malloc(SIZEOF(int));
*xx = y;
if(*(char **)((char *)&bw->o+glopts[y].ofst))
joe_snprintf_1(buf, OPT_BUF_SIZE, glopts[y].yes,*(char **)((char *)&bw->o+glopts[y].ofst));
else
joe_snprintf_1(buf, OPT_BUF_SIZE, glopts[y].yes,"");
if(wmkpw(bw->parent, buf, NULL, doopt1, NULL, doabrt1, utypebw, xx, notify, utf8_map, 0))
return 0;
else
return -1;
/* break; warns on some systems */
case 1:
joe_snprintf_1(buf, OPT_BUF_SIZE, joe_gettext(glopts[y].yes), *(int *)glopts[y].set);
xx = (int *) joe_malloc(SIZEOF(int));
*xx = y;
if (wmkpw(bw->parent, buf, NULL, doopt1, NULL, doabrt1, utypebw, xx, notify, utf8_map, 0))
return 0;
else
return -1;
case 2:
if (*(char **) glopts[y].set)
joe_snprintf_1(buf, OPT_BUF_SIZE, joe_gettext(glopts[y].yes), *(char **) glopts[y].set);
else
joe_snprintf_1(buf, OPT_BUF_SIZE, joe_gettext(glopts[y].yes), "");
xx = (int *) joe_malloc(SIZEOF(int));
*xx = y;
if (wmkpw(bw->parent, buf, NULL, doopt1, NULL, doabrt1, utypebw, xx, notify, locale_map, 0))
return 0;
else
return -1;
case 5:
joe_snprintf_1(buf, OPT_BUF_SIZE, joe_gettext(glopts[y].yes), *(int *) ((char *) &bw->o + glopts[y].ofst));
goto in;
case 14:
joe_snprintf_1(buf, OPT_BUF_SIZE, joe_gettext(glopts[y].yes), (long long)*(off_t *) ((char *) &bw->o + glopts[y].ofst));
goto in;
case 7:
joe_snprintf_1(buf, OPT_BUF_SIZE, joe_gettext(glopts[y].yes), *(int *) ((char *) &bw->o + glopts[y].ofst) + 1);
in:xx = (int *) joe_malloc(SIZEOF(int));
*xx = y;
if (wmkpw(bw->parent, buf, NULL, doopt1, NULL, doabrt1, utypebw, xx, notify, utf8_map, 0))
return 0;
else
return -1;
case 9:
joe_snprintf_1(buf, OPT_BUF_SIZE, joe_gettext(glopts[y].yes), "");
if (wmkpw(bw->parent, buf, NULL, dosyntax, NULL, NULL, syntaxcmplt, NULL, notify, utf8_map, 0))
return 0;
else
return -1;
case 13:
joe_snprintf_1(buf, OPT_BUF_SIZE, joe_gettext(glopts[y].yes), "");
if (wmkpw(bw->parent, buf, NULL, doencoding, NULL, NULL, encodingcmplt, NULL, notify, utf8_map, 0))
return 0;
else
return -1;
case 15:
joe_snprintf_1(buf, OPT_BUF_SIZE, joe_gettext(glopts[y].yes), "");
if (wmkpw(bw->parent, buf, &ftypehist, doftype, "ftype", NULL, ftypecmplt, NULL, notify, utf8_map, 0))
return 0;
else
return -1;
}
}
if (notify)
*notify = 1;
bw->b->o = bw->o;
wfit(bw->parent->t);
updall();
return 0;
}
/* Get option in printable format for %Zoption-name% */
const char *get_status(BW *bw, char *s)
{
static char buf[OPT_BUF_SIZE];
int y = find_option(s);
if (y == -1)
return "???";
else {
switch (glopts[y].type) {
case 0: {
return *(int *)glopts[y].set ? "ON" : "OFF";
} case 1: {
joe_snprintf_1(buf, OPT_BUF_SIZE, "%d", *(int *)glopts[y].set);
return buf;
} case 2: {
joe_snprintf_1(buf, OPT_BUF_SIZE, "%s", *(char **)glopts[y].set ? *(char **)glopts[y].set : "");
return buf;
} case 4: {
return *(int *) ((char *) &bw->o + glopts[y].ofst) ? "ON" : "OFF";
} case 5: {
joe_snprintf_1(buf, OPT_BUF_SIZE, "%d", *(int *) ((char *) &bw->o + glopts[y].ofst));
return buf;
} case 6: {
joe_snprintf_1(buf, OPT_BUF_SIZE, "%s", *(char **)((char *) &bw->o + glopts[y].ofst) ? *(char **)((char *) &bw->o + glopts[y].ofst) : "");
return buf;
} case 7: {
#ifdef HAVE_LONG_LONG
joe_snprintf_1(buf, OPT_BUF_SIZE, "%lld", (long long)*(off_t *) ((char *) &bw->o + glopts[y].ofst) + 1);
#else
joe_snprintf_1(buf, OPT_BUF_SIZE, "%ld", (long)*(off_t *) ((char *) &bw->o + glopts[y].ofst) + 1);
#endif
return buf;
} case 9: {
joe_snprintf_1(buf, OPT_BUF_SIZE, "%s", bw->o.syntax_name ? bw->o.syntax_name : "");
return buf;
} case 13: {
joe_snprintf_1(buf, OPT_BUF_SIZE, "%s", bw->o.map_name ? bw->o.map_name : "");
return buf;
} case 14: {
#ifdef HAVE_LONG_LONG
joe_snprintf_1(buf, OPT_BUF_SIZE, "%lld", (long long)*(off_t *) ((char *) &bw->o + glopts[y].ofst));
#else
joe_snprintf_1(buf, OPT_BUF_SIZE, "%ld", (long)*(off_t *) ((char *) &bw->o + glopts[y].ofst));
#endif
return buf;
} case 15: {
return bw->o.ftype;
} default: {
return "";
}
}
}
}
/* Simplified mode command */
static char **getoptions(void)
{
char **s = vaensure(NULL, 20);
int x;
for (x = 0; glopts[x].name; ++x)
s = vaadd(s, vsncpy(NULL, 0, sz(glopts[x].name)));
vasort(s, aLen(s));
return s;
}
/* Command line */
char **sopts = NULL; /* Array of command names */
static int optcmplt(BW *bw, int k)
{
if (!sopts)
sopts = getoptions();
return simple_cmplt(bw,sopts);
}
static int doopt(W *w, char *s, void *object, int *notify)
{
BW *bw;
int y = find_option(s);
WIND_BW(bw, w);
vsrm(s);
if (y == -1) {
msgnw(bw->parent, joe_gettext(_("No such option")));
if (notify)
*notify = 1;
return -1;
} else {
int flg = menu_flg;
menu_flg = 0;
return olddoopt(bw, y, flg, notify);
}
}
B *opthist = NULL;
int umode(W *w, int k)
{
if (wmkpw(w, joe_gettext(_("Option: ")), &opthist, doopt, "opt", NULL, optcmplt, NULL, NULL, locale_map, 0)) {
return 0;
} else {
return -1;
}
}