123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639 |
- /* cooledit.bindings file parser
- Authors: 2005 Vitja Makarov
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307, USA.
- */
- /** \file
- * \brief Source: cooledit.bindings file parser
- * \author Vitja Makarov
- * \date 2005
- */
- #include <config.h>
- #include <ctype.h>
- #include <errno.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <unistd.h>
- #include "../src/global.h"
- #include "../src/tty/tty.h" /* keys */
- #include "../src/tty/key.h" /* KEY_M_* */
- #include "edit-impl.h"
- #include "edit-widget.h"
- #include "../src/cmddef.h" /* list of commands */
- #include "usermap.h"
- #include "../src/wtools.h"
- #include "../src/widget.h" /* buttonbar_redraw() */
- typedef struct NameMap {
- const char *name;
- int val;
- } name_map_t;
- typedef struct Config {
- time_t mtime; /* mtime at the moment we read config file */
- GArray *keymap;
- GArray *ext_keymap;
- gchar *labels[10];
- } config_t;
- typedef struct Command {
- const char *name;
- int (*handler) (config_t *cfg, int argc, char *argv[]);
- } command_t;
- static char error_msg[200] = "Nobody see this";
- static const name_map_t key_names[] = {
- {"backspace", KEY_BACKSPACE},
- {"end", KEY_END},
- {"up", KEY_UP},
- {"down", KEY_DOWN},
- {"left", KEY_LEFT},
- {"right", KEY_RIGHT},
- {"home", KEY_HOME},
- {"a1", KEY_A1},
- {"c1", KEY_C1},
- {"npage", KEY_NPAGE},
- {"ppage", KEY_PPAGE},
- {"ic", KEY_IC},
- {"enter", KEY_ENTER},
- {"dc", KEY_DC},
- {"scancel", KEY_SCANCEL},
- {"btab", KEY_BTAB},
- {"f11", KEY_F(11)},
- {"f12", KEY_F(12)},
- {"f13", KEY_F(13)},
- {"f14", KEY_F(14)},
- {"f15", KEY_F(15)},
- {"f16", KEY_F(16)},
- {"f17", KEY_F(17)},
- {"f18", KEY_F(18)},
- {"f19", KEY_F(19)},
- {"f20", KEY_F(20)},
- {"tab", '\t'},
- {"return", '\n'},
- {NULL, 0}
- };
- static const name_map_t command_names[] = {
- {"No-Command", CK_Ignore_Key},
- {"Ignore-Key", CK_Ignore_Key},
- {"BackSpace", CK_BackSpace},
- {"Delete", CK_Delete},
- {"Enter", CK_Enter},
- {"Page-Up", CK_Page_Up},
- {"Page-Down", CK_Page_Down},
- {"Left", CK_Left},
- {"Right", CK_Right},
- {"Word-Left", CK_Word_Left},
- {"Word-Right", CK_Word_Right},
- {"Up", CK_Up},
- {"Down", CK_Down},
- {"Home", CK_Home},
- {"End", CK_End},
- {"Tab", CK_Tab},
- {"Undo", CK_Undo},
- {"Beginning-Of-Text", CK_Beginning_Of_Text},
- {"End-Of-Text", CK_End_Of_Text},
- {"Scroll-Up", CK_Scroll_Up},
- {"Scroll-Down", CK_Scroll_Down},
- {"Return", CK_Return},
- {"Begin-Page", CK_Begin_Page},
- {"End-Page", CK_End_Page},
- {"Delete-Word-Left", CK_Delete_Word_Left},
- {"Delete-Word-Right", CK_Delete_Word_Right},
- {"Paragraph-Up", CK_Paragraph_Up},
- {"Paragraph-Down", CK_Paragraph_Down},
- {"Save", CK_Save},
- {"Load", CK_Load},
- {"New", CK_New},
- {"Save-as", CK_Save_As},
- {"Mark", CK_Mark},
- {"Copy", CK_Copy},
- {"Move", CK_Move},
- {"Remove", CK_Remove},
- {"Unmark", CK_Unmark},
- {"Save-Block", CK_Save_Block},
- {"Column-Mark", CK_Column_Mark},
- {"Find", CK_Find},
- {"Find-Again", CK_Find_Again},
- {"Replace", CK_Replace},
- {"Replace-Again", CK_Replace_Again},
- {"Complete-Word", CK_Complete_Word},
- {"Debug-Start", CK_Debug_Start},
- {"Debug-Stop", CK_Debug_Stop},
- {"Debug-Toggle-Break", CK_Debug_Toggle_Break},
- {"Debug-Clear", CK_Debug_Clear},
- {"Debug-Next", CK_Debug_Next},
- {"Debug-Step", CK_Debug_Step},
- {"Debug-Back-Trace", CK_Debug_Back_Trace},
- {"Debug-Continue", CK_Debug_Continue},
- {"Debug-Enter-Command", CK_Debug_Enter_Command},
- {"Debug-Until-Curser", CK_Debug_Until_Curser},
- {"Insert-File", CK_Insert_File},
- {"Exit", CK_Exit},
- {"Toggle-Insert", CK_Toggle_Insert},
- {"Help", CK_Help},
- {"Date", CK_Date},
- {"Refresh", CK_Refresh},
- {"Goto", CK_Goto},
- {"Delete-Line", CK_Delete_Line},
- {"Delete-To-Line-End", CK_Delete_To_Line_End},
- {"Delete-To-Line-Begin", CK_Delete_To_Line_Begin},
- {"Man-Page", CK_Man_Page},
- {"Sort", CK_Sort},
- {"Mail", CK_Mail},
- {"Cancel", CK_Cancel},
- {"Complete", CK_Complete},
- {"Paragraph-Format", CK_Paragraph_Format},
- {"Util", CK_Util},
- {"Type-Load-Python", CK_Type_Load_Python},
- {"Find-File", CK_Find_File},
- {"Ctags", CK_Ctags},
- {"Match-Bracket", CK_Match_Bracket},
- {"Terminal", CK_Terminal},
- {"Terminal-App", CK_Terminal_App},
- {"ExtCmd", CK_ExtCmd},
- {"User-Menu", CK_User_Menu},
- {"Save-Desktop", CK_Save_Desktop},
- {"New-Window", CK_New_Window},
- {"Cycle", CK_Cycle},
- {"Menu", CK_Menu},
- {"Save-And-Quit", CK_Save_And_Quit},
- {"Run-Another", CK_Run_Another},
- {"Check-Save-And-Quit", CK_Check_Save_And_Quit},
- {"Maximize", CK_Maximize},
- {"Begin-Record-Macro", CK_Begin_Record_Macro},
- {"End-Record-Macro", CK_End_Record_Macro},
- {"Delete-Macro", CK_Delete_Macro},
- {"Toggle-Bookmark", CK_Toggle_Bookmark},
- {"Flush-Bookmarks", CK_Flush_Bookmarks},
- {"Next-Bookmark", CK_Next_Bookmark},
- {"Prev-Bookmark", CK_Prev_Bookmark},
- {"Page-Up-Highlight", CK_Page_Up_Highlight},
- {"Page-Down-Highlight", CK_Page_Down_Highlight},
- {"Left-Highlight", CK_Left_Highlight},
- {"Right-Highlight", CK_Right_Highlight},
- {"Word-Left-Highlight", CK_Word_Left_Highlight},
- {"Word-Right-Highlight", CK_Word_Right_Highlight},
- {"Up-Highlight", CK_Up_Highlight},
- {"Down-Highlight", CK_Down_Highlight},
- {"Home-Highlight", CK_Home_Highlight},
- {"End-Highlight", CK_End_Highlight},
- {"Beginning-Of-Text-Highlight", CK_Beginning_Of_Text_Highlight},
- {"End-Of-Text_Highlight", CK_End_Of_Text_Highlight},
- {"Begin-Page-Highlight", CK_Begin_Page_Highlight},
- {"End-Page-Highlight", CK_End_Page_Highlight},
- {"Scroll-Up-Highlight", CK_Scroll_Up_Highlight},
- {"Scroll-Down-Highlight", CK_Scroll_Down_Highlight},
- {"Paragraph-Up-Highlight", CK_Paragraph_Up_Highlight},
- {"Paragraph-Down-Highlight", CK_Paragraph_Down_Highlight},
- {"XStore", CK_XStore},
- {"XCut", CK_XCut},
- {"XPaste", CK_XPaste},
- {"Selection-History", CK_Selection_History},
- {"Shell", CK_Shell},
- {"Select-Codepage", CK_Select_Codepage},
- {"Insert-Literal", CK_Insert_Literal},
- {"Execute-Macro", CK_Execute_Macro},
- {"Begin-or-End-Macro", CK_Begin_End_Macro},
- {"Ext-mode", CK_Ext_Mode},
- {"Toggle-Line-State", CK_Toggle_Line_State},
- #if 0
- {"Focus-Next", CK_Focus_Next},
- {"Focus-Prev", CK_Focus_Prev},
- {"Height-Inc", CK_Height_Inc},
- {"Height-Dec", CK_Height_Dec},
- {"Make", CK_Make},
- {"Error-Next", CK_Error_Next},
- {"Error-Prev", CK_Error_Prev},
- #endif
- {NULL, 0}
- };
- static void
- cfg_free_maps(config_t *cfg)
- {
- int i;
- if (cfg->keymap)
- g_array_free(cfg->keymap, TRUE);
- cfg->keymap = NULL;
- if (cfg->ext_keymap)
- g_array_free(cfg->ext_keymap, TRUE);
- cfg->ext_keymap = NULL;
- for (i = 0; i < 10; i++)
- g_free(cfg->labels[i]);
- }
- /* Returns an array containing the words in str. WARNING: As long as
- * the result is used, str[...] must be valid memory. This function
- * modifies str[...] and uses it, so the caller should not use it until
- * g_ptr_array_free() is called for the returned result.
- */
- static GPtrArray *
- split_line(char *str)
- {
- gboolean inside_quote = FALSE;
- int move = 0;
- GPtrArray *args;
- args = g_ptr_array_new();
- /* skip spaces */
- while (isspace((unsigned char) *str))
- str++;
-
- g_ptr_array_add(args, str);
- for (;; str++) {
- switch (*str) {
- case '#': /* cut off comments */
- if (inside_quote)
- break;
- /* FALLTHROUGH */
- case '\n': /* end of line */
- case '\r':
- case '\0':
- if (str == g_ptr_array_index(args, args->len - 1))
- g_ptr_array_remove_index(args, args->len - 1);
- else
- *(str - move) = '\0';
- return args;
- case '"': /* quote */
- case '\'':
- inside_quote = !inside_quote;
- move++;
- continue;
- case ' ': /* spaces */
- case '\t':
- if (inside_quote)
- break;
- *(str++ - move) = '\0';
- move = 0;
- /* skip spaces */
- while (isspace((unsigned char) *str))
- str++;
- g_ptr_array_add(args, str--);
- break;
- case '\\':
- switch (*(++str)) {
- case 'n':
- *str = '\n';
- break;
- case 'r':
- *str = '\r';
- break;
- case 't':
- *str = '\t';
- break;
- }
- move++;
- break;
- }
- if (move != 0)
- *(str - move) = *str;
- }
- /* never be here */
- }
- static void
- keymap_add(GArray *keymap, int key, int cmd)
- {
- global_key_map_t new_one, *map;
- guint i;
- map = &(g_array_index(keymap, global_key_map_t, 0));
- for (i = 0; i < keymap->len; i++) {
- if (map[i].key == key) {
- map[i].command = cmd;
- return;
- }
- }
- new_one.key = key;
- new_one.command = cmd;
- g_array_append_val(keymap, new_one);
- }
- /* bind <key> <command> */
- static gboolean
- cmd_bind(config_t *cfg, int argc, char *argv[])
- {
- char *keyname, *command;
- const name_map_t *key = key_names;
- const name_map_t *cmd = command_names;
- int mod = 0, k = -1, m = 0;
- if (argc != 3) {
- snprintf(error_msg, sizeof(error_msg),
- _("bind: Wrong argument number, bind <key> <command>"));
- return FALSE;
- }
- keyname = argv[1];
- command = argv[2];
- while (*keyname) {
- switch (*keyname++) {
- case 'C':
- m = KEY_M_CTRL;
- continue;
- case 'M':
- case 'A':
- m = KEY_M_ALT;
- continue;
- case 'S':
- m = KEY_M_SHIFT;
- continue;
- case '-':
- if (!m) { /* incorrect key */
- snprintf(error_msg, sizeof(error_msg),
- _("bind: Bad key value `%s'"), keyname);
- return FALSE;
- }
- mod |= m;
- m = 0;
- continue;
- }
- keyname--;
- break;
- }
- /* no key */
- if (keyname[0] == '\0') {
- snprintf(error_msg, sizeof(error_msg), _("bind: Ehh...no key?"));
- return FALSE;
- }
- /* ordinary key */
- if (keyname[1] == '\0') {
- k = keyname[0];
- } else {
- while (key->name && strcasecmp(key->name, keyname) != 0)
- key++;
- }
- if (k < 0 && !key->name) {
- snprintf(error_msg, sizeof(error_msg),
- _("bind: Unknown key: `%s'"), keyname);
- return FALSE;
- }
- while (cmd->name && strcasecmp(cmd->name, command) != 0)
- cmd++;
- if (!cmd->name) {
- snprintf(error_msg, sizeof(error_msg),
- _("bind: Unknown command: `%s'"), command);
- return FALSE;
- }
- if (mod & KEY_M_CTRL) {
- if (k < 256)
- k = XCTRL(k);
- else
- k |= KEY_M_CTRL;
- }
- if (mod & KEY_M_ALT)
- k |= KEY_M_ALT;
- if (mod & KEY_M_SHIFT)
- k |= KEY_M_SHIFT;
- if (!strcasecmp("bind-ext", argv[0]))
- keymap_add(cfg->ext_keymap, k, cmd->val);
- else
- keymap_add(cfg->keymap, k, cmd->val);
- return TRUE;
- }
- #if 0
- #define CMD_F(x) \
- static void cmd_F ## x (WEdit * edit) \
- { \
- send_message ((Widget *) edit, WIDGET_KEY, KEY_F (x)); \
- }
- CMD_F(1)
- CMD_F(2)
- CMD_F(3)
- CMD_F(4)
- CMD_F(5)
- CMD_F(6)
- CMD_F(7)
- CMD_F(8)
- CMD_F(9)
- CMD_F(10)
- void (*cmd_Fx[]) (WEdit *) = {
- cmd_F1, cmd_F2, cmd_F3, cmd_F4, cmd_F5,
- cmd_F6, cmd_F7, cmd_F8, cmd_F9, cmd_F10
- } ;
- /* move me! */
- static void edit_my_define (Dlg_head * h, int idx, const char *text,
- void (*fn) (WEdit *), WEdit * edit)
- {
- /* function-cast ok */
- buttonbar_set_label_data (h, idx, text, (buttonbarfn) fn, edit);
- }
- #endif
- /* label <number> <command> <label> */
- static gboolean
- cmd_label(config_t *cfg, int argc, char *argv[])
- {
- const name_map_t *cmd = command_names;
- const char *command, *label;
- int fn;
- if (argc != 4) {
- snprintf(error_msg, sizeof(error_msg),
- _("%s: Syntax: %s <n> <command> <label>"),
- argv[0], argv[0]);
- return FALSE;
- }
-
- fn = strtol(argv[1], NULL, 0);
- command = argv[2];
- label = argv[3];
- while (cmd->name && strcasecmp(cmd->name, command) != 0)
- cmd++;
- if (!cmd->name) {
- snprintf(error_msg, sizeof(error_msg),
- _("%s: Unknown command: `%s'"), argv[0], command);
- return FALSE;
- }
-
- if (fn < 1 || fn > 10) {
- snprintf(error_msg, sizeof(error_msg),
- _("%s: fn should be 1-10"), argv[0]);
- return FALSE;
- }
- keymap_add(cfg->keymap, KEY_F(fn), cmd->val);
- cfg->labels[fn - 1] = g_strdup(label);
- return TRUE;
- }
- static gboolean
- parse_file(config_t *cfg, const char *file, const command_t *cmd)
- {
- char buf[200];
- int line = 0;
- FILE *fp = fopen(file, "r");
- if (!fp) {
- snprintf(error_msg, sizeof(error_msg), _("%s: fopen(): %s"),
- file, strerror(errno));
- return FALSE;
- }
- while (fgets(buf, sizeof(buf), fp)) {
- const command_t *c = cmd;
- GPtrArray *args;
- char **argv;
- line++;
- args = split_line(buf);
- argv = (char **) args->pdata;
- if (args->len == 0) {
- g_ptr_array_free(args, TRUE);
- continue;
- }
- while (c->name != NULL && strcasecmp(c->name, argv[0]) != 0)
- c++;
- if (c->name == NULL) {
- snprintf(error_msg, sizeof(error_msg),
- _("%s:%d: unknown command `%s'"), file, line,
- argv[0]);
- g_ptr_array_free(args, TRUE);
- fclose(fp);
- return FALSE;
- }
- if (!(c->handler(cfg, args->len, argv))) {
- char *ss = g_strdup(error_msg);
- snprintf(error_msg, sizeof(error_msg),
- _("%s:%d: %s"), file, line, ss);
- g_free(ss);
- g_ptr_array_free(args, TRUE);
- fclose(fp);
- return FALSE;
- }
- g_ptr_array_free(args, TRUE);
- }
- fclose(fp);
- return TRUE;
- }
- static gboolean
- load_user_keymap(config_t *cfg, const char *file)
- {
- const command_t cmd[] = {
- {"bind", cmd_bind},
- {"bind-ext", cmd_bind},
- {"label", cmd_label},
- {0, 0}
- };
- cfg->keymap = g_array_new(TRUE, FALSE, sizeof(global_key_map_t));
- cfg->ext_keymap = g_array_new(TRUE, FALSE, sizeof(global_key_map_t));
- if (!parse_file(cfg, file, cmd)) {
- return FALSE;
- }
- return TRUE;
- }
- gboolean
- edit_load_user_map(WEdit *edit)
- {
- static config_t cfg;
- config_t new_cfg;
- char *file;
- struct stat s;
- if (edit_key_emulation != EDIT_KEY_EMULATION_USER)
- return TRUE;
- file = concat_dir_and_file(home_dir, MC_USERMAP);
- if (stat(file, &s) < 0) {
- char *msg = g_strdup_printf(_("%s not found!"), file);
- edit_error_dialog(_("Error"), msg);
- g_free(msg);
- g_free(file);
- return FALSE;
- }
- if (s.st_mtime != cfg.mtime) {
- memset(&new_cfg, 0, sizeof(new_cfg));
- new_cfg.mtime = s.st_mtime;
- if (!load_user_keymap(&new_cfg, file)) {
- edit_error_dialog(_("Error"), error_msg);
- cfg_free_maps(&new_cfg);
- g_free(file);
- return FALSE;
- } else {
- cfg_free_maps(&cfg);
- cfg = new_cfg;
- }
- }
- edit->user_map = (global_key_map_t *) cfg.keymap->data;
- edit->ext_map = (global_key_map_t *) cfg.ext_keymap->data;
- memcpy(edit->labels, cfg.labels, sizeof(edit->labels));
- g_free(file);
- return TRUE;
- }
|