diff --git a/cgdate.c b/cgdate.c index 57bd09b..29ae7e0 100644 --- a/cgdate.c +++ b/cgdate.c @@ -106,7 +106,7 @@ void glk_current_time(glktimeval_t *time) return; } - gli_timestamp_to_time(tv.tv_sec, tv.tv_usec, time); + gli_timestamp_to_time(tv.tv_sec+pref_clock_skew, tv.tv_usec, time); } glsi32 glk_current_simple_time(glui32 factor) @@ -123,7 +123,7 @@ glsi32 glk_current_simple_time(glui32 factor) return 0; } - return gli_simplify_time(tv.tv_sec, factor); + return gli_simplify_time(tv.tv_sec+pref_clock_skew, factor); } void glk_time_to_date_utc(glktimeval_t *time, glkdate_t *date) diff --git a/glkterm.h b/glkterm.h index e2896b4..ae3c64a 100644 --- a/glkterm.h +++ b/glkterm.h @@ -117,6 +117,7 @@ struct glk_fileref_struct { char *filename; int filetype; int textmode; + int readonly; gidispatch_rock_t disprock; fileref_t *next, *prev; /* in the big linked list of filerefs */ @@ -145,6 +146,7 @@ extern window_t *gli_rootwin; extern window_t *gli_focuswin; extern grect_t content_box; extern void (*gli_interrupt_handler)(void); +extern int gli_exited; /* The following typedefs are copied from cheapglk.h. They support the tables declared in cgunigen.c. */ @@ -193,6 +195,35 @@ extern int pref_window_borders; extern int pref_precise_timing; extern int pref_historylen; extern int pref_prompt_defaults; +/* Extended pref */ +extern int pref_style_override; +extern int pref_border_graphics; +extern unsigned long pref_border_style; +extern int pref_use_colors; +extern int pref_clear_message; +extern int pref_auto_focus; +extern int pref_more_message; +extern int pref_typable_controls; +extern int pref_typable_specials; +#ifdef OPT_USE_MKSTEMP +extern char*pref_temporary_filename; +#endif +extern int pref_readonly; +extern int pref_auto_suffix; +extern int pref_prompt_raw_filename; +extern signed long pref_clock_skew; +extern int pref_restrict_files; +extern int pref_pause_warning; +extern int pref_more_exit; + +/* Filename mapping */ +typedef struct { + char*glkname; + char*native; + char writable; +} Filename_Mapping; +extern Filename_Mapping*filename_mapping; +extern int num_filename_mapping; /* Declarations of library internal functions. */ diff --git a/gtevent.c b/gtevent.c index 82b1827..78f423b 100644 --- a/gtevent.c +++ b/gtevent.c @@ -16,6 +16,7 @@ #include #include "glk.h" #include "glkterm.h" +#include "gtw_buf.h" /* A pointer to the place where the pending glk_select() will store its event. When not inside a glk_select() call, this will be NULL. */ @@ -46,14 +47,17 @@ void gli_initialize_events() void glk_select(event_t *event) { + window_textbuffer_t *dwin; + int ismore = FALSE; int needrefresh = TRUE; curevent = event; gli_event_clearevent(curevent); + if(pref_clear_message) gli_msgline(gli_exited?"-- Exit --":""); gli_windows_update(); gli_windows_set_paging(FALSE); - gli_input_guess_focus(); + if(pref_auto_focus || !gli_focuswin) gli_input_guess_focus(); while (curevent->type == evtype_None) { int key; @@ -61,6 +65,19 @@ void glk_select(event_t *event) /* It would be nice to display a "hit any key to continue" message in all windows which require it. */ if (needrefresh) { + if(pref_more_message && gli_focuswin && gli_focuswin->type==wintype_TextBuffer) { + dwin=gli_focuswin->data; + if(dwin->lastseenline < dwin->numlines - dwin->height) { + gli_msgline("-- More --"); + ismore=TRUE; + } else if(ismore) { + gli_msgline(gli_exited?"-- Exit --":""); + ismore=FALSE; + } + } else if(pref_more_message && ismore) { + gli_msgline(gli_exited?"-- Exit --":""); + ismore=FALSE; + } gli_windows_place_cursor(); refresh(); needrefresh = FALSE; diff --git a/gtfref.c b/gtfref.c index d595aa8..2eb7059 100644 --- a/gtfref.c +++ b/gtfref.c @@ -4,6 +4,10 @@ http://www.eblong.com/zarf/glk/index.html */ +#ifdef OPT_USE_MKSTEMP +#define _BSD_SOURCE +#endif + #include "gtoption.h" #include #include @@ -43,6 +47,7 @@ fileref_t *gli_new_fileref(char *filename, glui32 usage, glui32 rock) fref->textmode = ((usage & fileusage_TextMode) != 0); fref->filetype = (usage & fileusage_TypeMask); + fref->readonly = pref_readonly; fref->prev = NULL; fref->next = gli_filereflist; @@ -97,6 +102,8 @@ void glk_fileref_destroy(fileref_t *fref) static char *gli_suffix_for_usage(glui32 usage) { + if(!pref_auto_suffix) return ""; + switch (usage & fileusage_TypeMask) { case fileusage_Data: return ".glkdata"; @@ -112,17 +119,38 @@ static char *gli_suffix_for_usage(glui32 usage) frefid_t glk_fileref_create_temp(glui32 usage, glui32 rock) { - char filename[] = "/tmp/glktempfref-XXXXXX"; + char *filename; fileref_t *fref; + if(pref_readonly) return NULL; + /* This is a pretty good way to do this on Unix systems. It doesn't make sense on Windows, but anybody compiling this library on Windows has already set up some kind of Unix-like environment, I hope. */ - mkstemp(filename); - +#ifdef OPT_USE_MKSTEMP + if(pref_temporary_filename) { + int i=mkstemp(pref_temporary_filename); + if(i==-1) { + gli_strict_warning("fileref_create_temp: mkstemp() failed."); + return NULL; + } + close(i); + filename = pref_temporary_filename; + } else +#else + filename = tmpnam(NULL); +#endif + fref = gli_new_fileref(filename, usage, rock); +#ifdef OPT_USE_MKSTEMP + if(pref_temporary_filename) { + /* Reset template to end with "XXXXXX" */ + int i=strlen(pref_temporary_filename)-6; + memcpy(pref_temporary_filename+i,"XXXXXX",6); + } +#endif if (!fref) { gli_strict_warning("fileref_create_temp: unable to create fileref."); return NULL; @@ -159,6 +187,26 @@ frefid_t glk_fileref_create_by_name(glui32 usage, char *name, int len; char *cx; char *suffix; + int wr=0; + + /* Check for user filename mappings. */ + if(num_filename_mapping) { + int i; + for(i=0;i:|?*" (including quotes). Truncate at the first @@ -192,11 +240,13 @@ frefid_t glk_fileref_create_by_name(glui32 usage, char *name, suffix = gli_suffix_for_usage(usage); sprintf(buf2, "%s/%s%s", workingdir, buf, suffix); + filename_done: fref = gli_new_fileref(buf2, usage, rock); if (!fref) { gli_strict_warning("fileref_create_by_name: unable to create fileref."); return NULL; } + if(wr) fref->readonly = FALSE; return fref; } @@ -271,11 +321,14 @@ frefid_t glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, return NULL; } - if (cx[0] == '/') + if (cx[0] == '/' || pref_prompt_raw_filename) strcpy(newbuf, cx); else sprintf(newbuf, "%s/%s", workingdir, cx); + /* Acknowledge raw filename preference. */ + if(pref_prompt_raw_filename) goto raw_filename; + /* If there is no dot-suffix, add a standard one. */ val = strlen(newbuf); gotdot = FALSE; @@ -291,6 +344,7 @@ frefid_t glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, strcat(newbuf, suffix); } + raw_filename: if (fmode != filemode_Read) { if (!stat(newbuf, &sbuf) && S_ISREG(sbuf.st_mode)) { sprintf(prbuf, "Overwrite \"%s\"? [y/n] ", cx); @@ -313,6 +367,7 @@ frefid_t glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, gli_strict_warning("fileref_create_by_prompt: unable to create fileref."); return NULL; } + if(fmode != filemode_Read) fref->readonly = FALSE; return fref; } @@ -374,6 +429,11 @@ void glk_fileref_delete_file(fileref_t *fref) gli_strict_warning("fileref_delete_file: invalid ref"); return; } + + if (fref->readonly) { + gli_strict_warning("fileref_delete_file: can't delete read-only file"); + return; + } /* If you don't have the unlink() function, obviously, change it to whatever file-deletion function you do have. */ diff --git a/gtgestal.c b/gtgestal.c index 476c870..c1021a4 100644 --- a/gtgestal.c +++ b/gtgestal.c @@ -18,8 +18,10 @@ glui32 glk_gestalt(glui32 id, glui32 val) glui32 glk_gestalt_ext(glui32 id, glui32 val, glui32 *arr, glui32 arrlen) { + static int impl; int ix; + impl=TRUE; switch (id) { case gestalt_Version: @@ -49,7 +51,7 @@ glui32 glk_gestalt_ext(glui32 id, glui32 val, glui32 *arr, glui32 arrlen) || val == keycode_Up || val == keycode_Down || val == keycode_Return || val == keycode_Delete || val == keycode_Escape) - return TRUE; + return (val == keycode_Return || pref_typable_specials); else return FALSE; } @@ -118,10 +120,11 @@ glui32 glk_gestalt_ext(glui32 id, glui32 val, glui32 *arr, glui32 arrlen) return TRUE; case gestalt_LineTerminators: - return TRUE; + return pref_typable_specials; case gestalt_LineTerminatorKey: /* GlkTerm never uses the escape or function keys for anything, so we'll allow them to be line terminators. */ + if (!pref_typable_specials) return FALSE; if (val == keycode_Escape) return TRUE; if (val >= keycode_Func12 && val <= keycode_Func1) @@ -134,7 +137,16 @@ glui32 glk_gestalt_ext(glui32 id, glui32 val, glui32 *arr, glui32 arrlen) case gestalt_ResourceStream: return TRUE; + case 0x1400: /* gestalt_Gestalt */ + glk_gestalt_ext(val,0,NULL,0); + return impl; + + case 0x1407: /* gestalt_CharInputExt */ + if(val=='\031' || val=='\026') return char_typable_table[val]?0x22:0; + else return char_typable_table[val]?0x33:0; + default: + impl=FALSE; return 0; } diff --git a/gtinput.c b/gtinput.c index 64ee969..9990bdb 100644 --- a/gtinput.c +++ b/gtinput.c @@ -333,7 +333,7 @@ static command_t *commands_window(window_t *win, int key) case wintype_TextGrid: { window_textgrid_t *dwin = win->data; cmd = commands_textgrid(key); - if (!cmd) { + if (!cmd && !gli_exited) { if (win->line_request) cmd = commands_textgrid_line(dwin, key); else if (win->char_request) @@ -348,7 +348,7 @@ static command_t *commands_window(window_t *win, int key) if (dwin->lastseenline < dwin->numlines - dwin->height) { cmd = commands_textbuffer_paging(key); } - if (!cmd) { + if (!cmd && !gli_exited) { if (win->line_request) cmd = commands_textbuffer_line(dwin, key); else if (win->char_request) @@ -571,7 +571,7 @@ void gli_input_handle_key(int key) /* If not, see if there's some other window which has a binding for the key; if so, set the focus there. */ - if (!cmd && gli_rootwin) { + if (!cmd && gli_rootwin && pref_auto_focus) { window_t *altwin = gli_focuswin; command_t *altcmd = NULL; do { @@ -599,8 +599,10 @@ void gli_input_handle_key(int key) arg = cmd->arg; } (*cmd->func)(win, arg); - } - else { + } else if(gli_exited) { + /* Exit if a key is pushed */ + gli_event_store(evtype_CharInput, 0, 0, 1); + } else { char buf[256]; char *kbuf = key_to_name(key); sprintf(buf, "The key <%s> is not currently defined.", kbuf); diff --git a/gtmessag.c b/gtmessag.c index 86ca04f..88f3c36 100644 --- a/gtmessag.c +++ b/gtmessag.c @@ -26,8 +26,16 @@ void gli_msgline_warning(char *msg) if (!pref_messageline) return; - sprintf(buf, "Glk library error: %s", msg); + snprintf(buf, 256, "Glk library error: %s", msg); gli_msgline(buf); + + if(pref_pause_warning) { + move(content_box.bottom, 0); + refresh(); + while(getch()==ERR && !just_killed); + gli_msgline(""); + } + if(just_killed) gli_fast_exit(); } void gli_msgline(char *msg) diff --git a/gtmisc.c b/gtmisc.c index 5edfdaf..0f1465b 100644 --- a/gtmisc.c +++ b/gtmisc.c @@ -29,6 +29,8 @@ gidispatch_rock_t (*gli_register_arr)(void *array, glui32 len, char *typecode) = void (*gli_unregister_arr)(void *array, glui32 len, char *typecode, gidispatch_rock_t objrock) = NULL; +int gli_exited=FALSE; + static char *char_A0_FF_to_ascii[6*16] = { " ", "!", "c", "Lb", NULL, "Y", "|", NULL, NULL, "(C)", NULL, "<<", NULL, "-", "(R)", NULL, @@ -99,7 +101,7 @@ void gli_initialize_misc() || ix == '\033') /* parsed as keycode_Escape */ cantype = FALSE; else - cantype = TRUE; + cantype = pref_typable_controls; /* The newline is printable, but no other control characters. */ if (ix == '\012') canprint = TRUE; @@ -142,7 +144,18 @@ void gli_initialize_misc() void glk_exit() { - gli_msgin_getchar("Hit any key to exit.", TRUE); + if(pref_more_exit && gli_rootwin) { + event_t ev; + gli_exited=TRUE; + pref_auto_focus=TRUE; + pref_clear_message=TRUE; + for(;;) { + glk_select(&ev); + if(ev.type==evtype_CharInput) break; + } + } else { + gli_msgin_getchar("Hit any key to exit.", TRUE); + } gli_streams_close_all(); diff --git a/gtoption.h b/gtoption.h index e93ce9a..8ad8f93 100644 --- a/gtoption.h +++ b/gtoption.h @@ -17,7 +17,7 @@ /* Options: */ #define LIBRARY_VERSION "1.0.4" -#define LIBRARY_PORT "Generic" +#define LIBRARY_PORT "Enhanced" /* If you change this code substantially, you should change the LIBRARY_PORT definition to something which explains what the @@ -79,6 +79,13 @@ is also defined. */ + +#define OPT_USE_MKSTEMP + +/* OPT_USE_MKSTEMP should be defined if mkstemp() is available. See the + user setting documentation for details about the template. +*/ + /* #define NO_MEMMOVE */ /* NO_MEMMOVE should be defined if your standard library doesn't @@ -125,7 +132,6 @@ } */ -/* #define OPT_AO_FF_OUTPUT { \ 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, \ @@ -140,8 +146,8 @@ 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, \ } -*/ +/* #define OPT_AO_FF_OUTPUT { \ '\312', '\301', '\242', '\243', 0 , '\264', 0 , '\244', \ '\254', '\251', '\273', '\307', '\302', '\320', '\250', 0 , \ @@ -156,6 +162,7 @@ 0 , '\226', '\230', '\227', '\231', '\233', '\232', '\326', \ '\277', '\235', '\234', '\236', '\237', 0 , 0 , '\330', \ } +*/ /* OPT_AO_FF_OUTPUT should be defined as a translation table. This is ignored if OPT_NATIVE_LATIN_1 is defined. @@ -172,6 +179,7 @@ is for the standard Macintosh character set. */ +/* #define OPT_AO_FF_TYPABLE { \ 1, 1, 1, 1, 1, 1, 1, 1, \ 1, 1, 1, 1, 1, 1, 1, 1, \ @@ -186,8 +194,8 @@ 1, 1, 1, 1, 1, 1, 1, 1, \ 1, 1, 1, 1, 1, 1, 1, 1, \ } +*/ -/* #define OPT_AO_FF_TYPABLE { \ 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, \ @@ -202,7 +210,6 @@ 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, \ } -*/ /* OPT_AO_FF_TYPABLE should be defined as a table of which characters can actually be typed by the player. diff --git a/gtstream.c b/gtstream.c index 3b4a3be..92dfb98 100644 --- a/gtstream.c +++ b/gtstream.c @@ -232,6 +232,12 @@ strid_t glk_stream_open_file(fileref_t *fref, glui32 fmode, gli_strict_warning("stream_open_file: invalid fileref ref."); return 0; } + + /* User preference to force read-only */ + if(fref->readonly && fmode!=filemode_Read) { + gli_strict_warning("stream_openfile: trying to open read-only file for writing."); + return 0; + } /* The spec says that Write, ReadWrite, and WriteAppend create the file if necessary. However, fopen(filename, "r+") doesn't create @@ -347,7 +353,7 @@ strid_t glk_stream_open_file_uni(fileref_t *fref, glui32 fmode, { strid_t str = glk_stream_open_file(fref, fmode, rock); /* Unlovely, but it works in this library */ - str->unicode = TRUE; + if(str) str->unicode = TRUE; return str; } diff --git a/gtw_pair.c b/gtw_pair.c index c5da3fb..23166fc 100644 --- a/gtw_pair.c +++ b/gtw_pair.c @@ -7,11 +7,14 @@ #include "gtoption.h" #include #include +#include #include #include "glk.h" #include "glkterm.h" #include "gtw_pair.h" +char*border_buf; + window_pair_t *win_pair_create(window_t *win, glui32 method, window_t *key, glui32 size) { @@ -174,6 +177,52 @@ void win_pair_rearrange(window_t *win, grect_t *box) gli_window_rearrange(ch2, &box2); } +#define BORDER_BUF(y,x) border_buf[(y)*content_box.right+(x)] + +static chtype border_char[32]; + +void win_pair_calc_border(window_t*win) { + window_pair_t*dwin=win->data; + if(win==gli_rootwin) { + if(!pref_border_graphics || !border_buf) return; + if(win->type!=wintype_Pair) return; + memset(border_buf,0,content_box.right*content_box.bottom); + if(!*border_char) { + int ix; + for(ix=0;ix<32;ix++) border_char[ix]=ACS_PLUS; + border_char[1]=ACS_TTEE; + border_char[2]=ACS_BTEE; + border_char[4|16]=ACS_LTEE; + border_char[8|16]=ACS_RTEE; + border_char[0]=ACS_VLINE; + border_char[16]=ACS_HLINE; + } + } + if (dwin->vertical) { + if (dwin->splitwidth) { + if (win->bbox.top-1 >= 0) { + BORDER_BUF(win->bbox.top-1, dwin->splitpos) |= 1; + } + if (win->bbox.bottom < content_box.bottom) { + BORDER_BUF(win->bbox.bottom, dwin->splitpos) |= 2; + } + } + } + else { + if (dwin->splitwidth) { + move(dwin->splitpos, win->bbox.left); + if (win->bbox.left-1 >= 0) { + BORDER_BUF(dwin->splitpos, win->bbox.left-1) |= 4; + } + if (win->bbox.right < content_box.right) { + BORDER_BUF(dwin->splitpos, win->bbox.right) |= 8; + } + } + } + if(dwin->child1->type==wintype_Pair) win_pair_calc_border(dwin->child1); + if(dwin->child2->type==wintype_Pair) win_pair_calc_border(dwin->child2); +} + void win_pair_redraw(window_t *win) { int ix; @@ -187,13 +236,13 @@ void win_pair_redraw(window_t *win) if (dwin->vertical) { if (dwin->splitwidth) { for (ix=win->bbox.top; ixbbox.bottom; ix++) { - mvaddch(ix, dwin->splitpos, '|'); + mvaddch(ix, dwin->splitpos, (pref_border_graphics?border_char[BORDER_BUF(ix,dwin->splitpos)]:'|')|pref_border_style); } if (win->bbox.top-1 >= 0) { - mvaddch(win->bbox.top-1, dwin->splitpos, '+'); + mvaddch(win->bbox.top-1, dwin->splitpos, (pref_border_graphics?border_char[BORDER_BUF(win->bbox.top-1,dwin->splitpos)]:'+')|pref_border_style); } if (win->bbox.bottom < content_box.bottom) { - mvaddch(win->bbox.bottom, dwin->splitpos, '+'); + mvaddch(win->bbox.bottom, dwin->splitpos, (pref_border_graphics?border_char[BORDER_BUF(win->bbox.bottom,dwin->splitpos)]:'+')|pref_border_style); } } } @@ -201,13 +250,13 @@ void win_pair_redraw(window_t *win) if (dwin->splitwidth) { move(dwin->splitpos, win->bbox.left); for (ix=win->bbox.left; ixbbox.right; ix++) { - addch('-'); + addch((pref_border_graphics?border_char[BORDER_BUF(dwin->splitpos,ix)|16]:'-')|pref_border_style); } if (win->bbox.left-1 >= 0) { - mvaddch(dwin->splitpos, win->bbox.left-1, '+'); + mvaddch(dwin->splitpos, win->bbox.left-1, (pref_border_graphics?border_char[BORDER_BUF(dwin->splitpos,win->bbox.left-1)|16]:'+')|pref_border_style); } if (win->bbox.right < content_box.right) { - mvaddch(dwin->splitpos, win->bbox.right, '+'); + mvaddch(dwin->splitpos, win->bbox.right, (pref_border_graphics?border_char[BORDER_BUF(dwin->splitpos,win->bbox.right)|16]:'+')|pref_border_style); } } } diff --git a/gtw_pair.h b/gtw_pair.h index 19b29df..a391966 100644 --- a/gtw_pair.h +++ b/gtw_pair.h @@ -29,3 +29,6 @@ extern window_pair_t *win_pair_create(window_t *win, glui32 method, extern void win_pair_destroy(window_pair_t *dwin); extern void win_pair_rearrange(window_t *win, grect_t *box); extern void win_pair_redraw(window_t *win); +extern void win_pair_calc_border(window_t *win); + +extern char*border_buf; diff --git a/gtwindow.c b/gtwindow.c index 1a3c529..cb0fd48 100644 --- a/gtwindow.c +++ b/gtwindow.c @@ -7,6 +7,7 @@ #include "gtoption.h" #include #include +#include #ifdef OPT_USE_SIGNALS #include @@ -68,19 +69,23 @@ void gli_initialize_windows() spacebuffer[NUMSPACES] = '\0'; /* Create the curses.h attribute values for each style. */ - for (ix=0; ix 0) content_box.bottom--; /* allow a message line */ + + if(pref_border_graphics && width && height) { + border_buf=realloc(border_buf,width*height); + if(border_buf) memset(border_buf,0,width*height); + } } window_t *gli_new_window(glui32 type, glui32 rock) @@ -835,6 +857,7 @@ void gli_windows_unechostream(stream_t *str) void gli_window_rearrange(window_t *win, grect_t *box) { + win_pair_calc_border(gli_rootwin); switch (win->type) { case wintype_Blank: win_blank_rearrange(win, box); @@ -1307,6 +1330,7 @@ void gcmd_win_change_focus(window_t *win, glui32 arg) void gcmd_win_refresh(window_t *win, glui32 arg) { + if(pref_clear_message) gli_msgline(""); clear(); gli_windows_redraw(); gli_msgline_redraw(); diff --git a/main.c b/main.c index 38d2f0d..e28c52b 100644 --- a/main.c +++ b/main.c @@ -13,6 +13,11 @@ #include "glk.h" #include "glkterm.h" #include "glkstart.h" +#include "gtw_buf.h" +#include "gtw_grid.h" + +/* Make gcc shut up about "...pointer from integer without a cast" */ +char *strdup(const char *s); /* Declarations of preferences flags. */ int pref_printversion = FALSE; @@ -25,6 +30,29 @@ int pref_window_borders = FALSE; int pref_precise_timing = FALSE; int pref_historylen = 20; int pref_prompt_defaults = TRUE; +/* Extended pref */ +int pref_style_override = FALSE; +int pref_border_graphics = FALSE; +unsigned long pref_border_style = 0; +int pref_use_colors = FALSE; +int pref_clear_message = FALSE; +int pref_auto_focus = TRUE; +int pref_more_message = FALSE; +int pref_typable_controls = TRUE; +int pref_typable_specials = TRUE; +#ifdef OPT_USE_MKSTEMP +char*pref_temporary_filename = NULL; +#endif +int pref_readonly = FALSE; +int pref_auto_suffix = TRUE; +int pref_prompt_raw_filename = FALSE; +signed long pref_clock_skew = 0; +int pref_restrict_files = FALSE; +int pref_pause_warning = FALSE; +int pref_more_exit = FALSE; + +Filename_Mapping*filename_mapping=0; +int num_filename_mapping=0; /* Some constants for my wacky little command-line option parser. */ #define ex_Void (0) @@ -38,10 +66,158 @@ static int extract_value(int argc, char *argv[], char *optname, int type, int *argnum, int *result, int defval); static int string_to_bool(char *str); +static chtype parse_style(char*buf) { + chtype t=0; + while(*buf) { + switch(*buf++) { + case 's': t|=A_STANDOUT; break; + case 'u': t|=A_UNDERLINE; break; + case 'r': t|=A_REVERSE; break; + case 'k': t|=A_BLINK; break; + case 'd': t|=A_DIM; break; + case 'b': t|=A_BOLD; break; + case 'p': t|=A_PROTECT; break; + case 'i': t|=A_INVIS; break; + case 'a': t|=A_ALTCHARSET; break; + case ' ': case '\t': break; + case '0': t|=COLOR_PAIR(8); break; + case '1': t|=COLOR_PAIR(1); break; + case '2': t|=COLOR_PAIR(2); break; + case '3': t|=COLOR_PAIR(3); break; + case '4': t|=COLOR_PAIR(4); break; + case '5': t|=COLOR_PAIR(5); break; + case '6': t|=COLOR_PAIR(6); break; + case '7': t|=COLOR_PAIR(7); break; + default: + printf("Invalid style: %c\n",buf[-1]); + exit(1); + } + } + return t; +} + +#define USER_OPTION(a,b) if(!strncmp(a"=",buf,sizeof(a))) { buf+=sizeof(a); while(*buf==' ' || *buf=='\t') buf++; b; return; } +static void user_option(char*buf) { + int i,j; + chtype t; + USER_OPTION("screenwidth",pref_screenwidth=strtol(buf,0,10)); + USER_OPTION("screenheight",pref_screenheight=strtol(buf,0,10)); + USER_OPTION("messageline",pref_messageline=string_to_bool(buf)); + USER_OPTION("reverse_textgrids",pref_reverse_textgrids=string_to_bool(buf)); + USER_OPTION("window_borders",{ + pref_override_window_borders=TRUE; + pref_window_borders=string_to_bool(buf); + }); +#ifdef OPT_TIMED_INPUT + USER_OPTION("precise_timing",pref_precise_timing=string_to_bool(buf)); +#endif + USER_OPTION("historylen",pref_historylen=strtol(buf,0,10)); + USER_OPTION("prompt_defaults",pref_prompt_defaults=string_to_bool(buf)); + USER_OPTION("style_override",pref_style_override=string_to_bool(buf)); + USER_OPTION("border_graphics",pref_border_graphics=string_to_bool(buf)); + USER_OPTION("border_style",pref_border_style=parse_style(buf)); + USER_OPTION("use_colors",pref_use_colors=string_to_bool(buf)); + USER_OPTION("clear_message",pref_clear_message=string_to_bool(buf)); + USER_OPTION("auto_focus",pref_auto_focus=string_to_bool(buf)); + USER_OPTION("more_message",pref_more_message=string_to_bool(buf)); + USER_OPTION("typable_controls",pref_typable_controls=string_to_bool(buf)); + USER_OPTION("typable_specials",pref_typable_specials=string_to_bool(buf)); +#ifdef OPT_USE_MKSTEMP + USER_OPTION("temporary_filename",{ + pref_temporary_filename=strdup(buf); + if(!pref_temporary_filename) goto memerr; + if(strlen(pref_temporary_filename)<6 || strcmp(pref_temporary_filename+strlen(pref_temporary_filename)-6,"XXXXXX")) { + printf("Temporary filename must end with \"XXXXXX\"\n"); + exit(1); + } + }); +#endif + USER_OPTION("readonly",pref_readonly=string_to_bool(buf)); + USER_OPTION("auto_suffix",pref_auto_suffix=string_to_bool(buf)); + USER_OPTION("prompt_raw_filename",pref_prompt_raw_filename=string_to_bool(buf)); + USER_OPTION("clock_skew",pref_clock_skew=strtol(buf,0,10)); + USER_OPTION("restrict_files",pref_restrict_files=string_to_bool(buf)); + USER_OPTION("pause_warning",pref_pause_warning=string_to_bool(buf)); + USER_OPTION("more_exit",pref_more_exit=string_to_bool(buf)); + if(*buf=='S' || *buf=='B' || *buf=='G') { + j=*buf; + i=strtol(buf+1,&buf,10); + if(i>=0 && iwritable=(buf[1]=='/'?1:0); + fm->glkname=p=strdup(buf+fm->writable+1); + if(!p) goto memerr; + while(*p) { + if(*p=='=') break; + p++; + } + if(!*p) { + printf("Invalid filename mapping\n"); + exit(1); + } + *p++=0; + fm->native=p; + return; + } + printf("Invalid user option: %s\n",buf); + exit(1); + memerr: + printf("Memory allocation failed\n"); + exit(1); +} + +static void read_glktermrc(void) { + char*home; + char*filename=0; + FILE*fp; + char buf[1024]; + char*p; + int sk=0; + filename=getenv("GLKTERMRC"); + if(filename) { + fp=fopen(filename,"r"); + } else { + home=getenv("HOME"); + if(!home) home="."; + filename=malloc(strlen(home)+12); + if(!filename) return; + sprintf(filename,"%s/.glktermrc",home); + fp=fopen(filename,"r"); + free(filename); + } + if(!fp) return; + while(fgets(buf,1024,fp)) { + p=buf+strlen(buf); + while(p>buf && (p[-1]=='\r' || p[-1]=='\t' || p[-1]=='\n' || p[-1]==' ')) *--p=0; + p=buf; + while(*p==' ' || *p=='\t') p++; + if(*p=='[' && p[strlen(p)-1]==']') { + home=getenv("GLKTERMRC_SECTION"); + sk=home?strncmp(home,p+1,strlen(p)-2):1; + } + if(sk) continue; + if(*p && *p!='#') user_option(buf); + } + fclose(fp); +} + int main(int argc, char *argv[]) { int ix, jx, val; glkunix_startup_t startdata; + int endflags=0; /* Test for compile-time errors. If one of these spouts off, you must edit glk.h and recompile. */ @@ -54,6 +230,9 @@ int main(int argc, char *argv[]) return 1; } + /* Read .glktermrc if it exists. */ + read_glktermrc(); + /* Now some argument-parsing. This is probably going to hurt. */ startdata.argc = 0; startdata.argv = (char **)malloc(argc * sizeof(char *)); @@ -67,6 +246,14 @@ int main(int argc, char *argv[]) int inarglist = FALSE; char *cx; + if(endflags) { + startdata.argv[startdata.argc++]=argv[ix]; + continue; + } else if(argv[ix][0]=='-' && argv[ix][1]=='-' && !argv[ix][2]) { + endflags=1; + continue; + } + for (argform = glkunix_arguments; argform->argtype != glkunix_arg_End && !errflag; argform++) { @@ -177,6 +364,8 @@ int main(int argc, char *argv[]) else if (extract_value(argc, argv, "precise", ex_Bool, &ix, &val, pref_precise_timing)) pref_precise_timing = val; #endif /* !OPT_TIMED_INPUT */ + else if (!strcmp(argv[ix],"-glkext") && ix