Ticket #4187: SlangScriptingForMC.patch

File SlangScriptingForMC.patch, 86.4 KB (added by psprint, 3 years ago)
  • lib/fileloc.h

    From 2cf267d8a0cfda61fdc94696bbc997c8369a43d1 Mon Sep 17 00:00:00 2001
    From: Sebastian Gniazdowski <sgniazdowski@gmail.com>
    Date: Mon, 25 Jan 2021 13:54:14 -0600
    Subject: Slang Scripting Support.
    
    ---
     lib/fileloc.h                           |   2 +
     lib/keybind.c                           | 140 +++-
     lib/keybind.h                           |  31 +-
     lib/mcconfig/paths.c                    |   3 +
     lib/widget/dialog.c                     |   4 +
     lib/widget/wtools.c                     |  64 ++
     lib/widget/wtools.h                     |  11 +
     misc/grow_shrink_integer.plugin.sl      | 102 +++
     misc/init.sl                            |  49 ++
     src/Makefile.am                         |   5 +-
     src/editor/edit.c                       |  26 +
     src/editor/editbuffer.c                 | 122 ++++
     src/editor/editbuffer.h                 |   4 +
     src/editor/editcmd.c                    |  58 +-
     src/editor/editwidget.c                 |   1 +
     src/main.c                              |  11 +
     src/setup.c                             |  18 +-
     src/slang_api_functions.c               | 423 ++++++++++++
     src/slang_api_functions.h               |  52 ++
     src/slang_api_functions_glue.c          | 871 ++++++++++++++++++++++++
     src/slang_engine.c                      | 275 ++++++++
     src/{vfs/fish/fish.h => slang_engine.h} |  19 +-
     22 files changed, 2212 insertions(+), 79 deletions(-)
     create mode 100644 misc/grow_shrink_integer.plugin.sl
     create mode 100644 misc/init.sl
     create mode 100644 src/slang_api_functions.c
     create mode 100644 src/slang_api_functions.h
     create mode 100644 src/slang_api_functions_glue.c
     create mode 100644 src/slang_engine.c
     copy src/{vfs/fish/fish.h => slang_engine.h} (72%)
    
    diff --git a/lib/fileloc.h b/lib/fileloc.h
    index c7d3bc625..44c3b5efd 100644
    a b  
    3030#define CHARSETS_LIST           "mc.charsets" 
    3131#define MC_LIB_EXT              "mc.ext" 
    3232#define MC_MACRO_FILE           "mc.macros" 
     33#define MC_SLANG_INIT_FILE      "init.sl" 
     34#define MC_PLUGIN_DIR           "plugin" 
    3335 
    3436#define FISH_PREFIX             "fish" 
    3537 
  • lib/keybind.c

    diff --git a/lib/keybind.c b/lib/keybind.c
    index abd44d3e2..4fd8aaed6 100644
    a b  
    3838 
    3939/*** global variables ****************************************************************************/ 
    4040 
     41int new_dynamic_command_id = 100000; 
     42 
    4143/*** file scope macro definitions ****************************************************************/ 
    4244 
    4345#define ADD_KEYMAP_NAME(name) \ 
     
    4749 
    4850/*** file scope variables ************************************************************************/ 
    4951 
    50 static name_keymap_t command_names[] = { 
     52static name_keymap_t command_names_start[] = { 
    5153    /* common */ 
    5254    ADD_KEYMAP_NAME (InsertChar), 
    5355    ADD_KEYMAP_NAME (Enter), 
    static name_keymap_t command_names[] = { 
    375377    {NULL, CK_IgnoreKey} 
    376378}; 
    377379 
    378 /* *INDENT-OFF* */ 
    379 static const size_t num_command_names = G_N_ELEMENTS (command_names) - 1; 
    380 /* *INDENT-ON* */ 
     380static name_keymap_t *command_names = NULL; 
     381 
     382static size_t num_command_names = 0; 
     383 
     384static gboolean has_been_sorted = FALSE; 
    381385 
    382386/*** file scope functions ************************************************************************/ 
    383387/* --------------------------------------------------------------------------------------------- */ 
    384388 
     389/* Initializes the dynamic command names array. */ 
     390static void 
     391init_command_names (void) 
     392{ 
     393    keybind_add_new_action (NULL, -1); 
     394} 
     395 
     396/* --------------------------------------------------------------------------------------------- */ 
     397 
    385398static int 
    386399name_keymap_comparator (const void *p1, const void *p2) 
    387400{ 
    name_keymap_comparator (const void *p1, const void *p2) 
    396409static inline void 
    397410sort_command_names (void) 
    398411{ 
    399     static gboolean has_been_sorted = FALSE; 
     412    if (!command_names) 
     413        init_command_names (); 
    400414 
    401415    if (!has_been_sorted) 
    402416    { 
    403417        qsort (command_names, num_command_names, 
    404418               sizeof (command_names[0]), &name_keymap_comparator); 
     419 
    405420        has_been_sorted = TRUE; 
    406421    } 
    407422} 
    sort_command_names (void) 
    409424/* --------------------------------------------------------------------------------------------- */ 
    410425 
    411426static void 
    412 keymap_add (GArray * keymap, long key, long cmd, const char *caption) 
     427keymap_add (GArray * keymap, long key, long cmd, const char *caption, key_origin_t origin) 
    413428{ 
    414429    if (key != 0 && cmd != CK_IgnoreKey) 
    415430    { 
    keymap_add (GArray * keymap, long key, long cmd, const char *caption) 
    417432 
    418433        new_bind.key = key; 
    419434        new_bind.command = cmd; 
     435        new_bind.origin = origin; 
    420436        g_snprintf (new_bind.caption, sizeof (new_bind.caption), "%s", caption); 
    421437        g_array_append_val (keymap, new_bind); 
    422438    } 
    keymap_add (GArray * keymap, long key, long cmd, const char *caption) 
    426442/*** public functions ****************************************************************************/ 
    427443/* --------------------------------------------------------------------------------------------- */ 
    428444 
     445/* Adds a dynamic command name. Can be used to initialize the dynamic 
     446   command names array by passing NULL as the first parameter. */ 
     447int 
     448keybind_add_new_action (const char *new_command_name, int new_ck_id) 
     449{ 
     450    name_keymap_t search_key = { 0 }; 
     451    name_keymap_t *old_command_names = command_names, *res = NULL, *src_commands; 
     452    int ret = 0,                /* Default return code → no command name added */ 
     453        size = 0; 
     454 
     455    /* Make a private copy of the command name. */ 
     456    search_key.name = new_command_name = g_strdup (new_command_name); 
     457 
     458    /* Count the size of the existing command names array. */ 
     459 
     460    src_commands = command_names ? command_names : command_names_start; 
     461    for (; src_commands[size].name; size++); 
     462 
     463    /* Initialize the size variable of the command names array. */ 
     464    num_command_names = size; 
     465 
     466    /* Check if the key already exists, i.e.: if the command is already registered. */ 
     467    if (search_key.name != NULL && strlen (search_key.name)) 
     468    { 
     469        res = bsearch (&search_key, src_commands, 
     470                       num_command_names, sizeof (command_names_start[0]), name_keymap_comparator); 
     471    } 
     472 
     473    /* 
     474     * a) Such command already exists or, b) no command given and the registry is already 
     475     * initialized (the first bootstrap invocation has been already run) ? If so, then exit doing 
     476     * no action. Note that the CK ID of the existing command is not updated and remains the same. 
     477     */ 
     478 
     479    if (res != NULL || (!new_command_name && old_command_names)) 
     480    { 
     481        return ret; 
     482    } 
     483 
     484    /* Allocate new space and copy the old keymap names. */ 
     485    command_names = (name_keymap_t *) calloc (size + (new_command_name ? 2 : 1), 
     486                                              sizeof (name_keymap_t)); 
     487 
     488    /* Extending an existing array? */ 
     489    if (old_command_names != NULL) 
     490    { 
     491        /* ...yes. Copy from `old_command_names` dynamic array. */ 
     492        memcpy (command_names, old_command_names, (size + 1) * sizeof (name_keymap_t)); 
     493 
     494        /* Release the previous command names after copying them. */ 
     495        free (old_command_names); 
     496    } 
     497    else 
     498    { 
     499        /* ...no. Copy the initial, compiled in command names into the dynamic array. */ 
     500        memcpy (command_names, command_names_start, sizeof (command_names_start)); 
     501    } 
     502 
     503    /* Add a new keymap if requested (i.e.: if given any non-NULL name). */ 
     504    if (new_command_name != NULL) 
     505    { 
     506        /* Insert the new command name at the end, then follow an empty sentinel element. */ 
     507        command_names[size].name = new_command_name; 
     508        command_names[size].val = new_ck_id; 
     509        command_names[size + 1].name = NULL; 
     510        command_names[size + 1].val = CK_IgnoreKey; 
     511 
     512        /* Increase the command name count. */ 
     513        num_command_names++; 
     514 
     515        /* Sort the new array. */ 
     516        has_been_sorted = FALSE; 
     517        sort_command_names (); 
     518 
     519        /* Return that a new command name has been registered. */ 
     520        ret = 1; 
     521    } 
     522    return ret; 
     523} 
     524 
     525/* --------------------------------------------------------------------------------------------- */ 
     526 
    429527void 
    430 keybind_cmd_bind (GArray * keymap, const char *keybind, long action) 
     528keybind_cmd_bind (GArray * keymap, const char *keybind, long action, key_origin_t origin) 
    431529{ 
    432530    char *caption = NULL; 
    433531    long key; 
    434532 
    435533    key = lookup_key (keybind, &caption); 
    436     keymap_add (keymap, key, action, caption); 
     534    keymap_add (keymap, key, action, caption, origin); 
    437535    g_free (caption); 
    438536} 
    439537 
    const char * 
    459557keybind_lookup_actionname (long action) 
    460558{ 
    461559    size_t i; 
     560    const char *name = NULL; 
    462561 
    463562    for (i = 0; command_names[i].name != NULL; i++) 
    464563        if (command_names[i].val == action) 
    465             return command_names[i].name; 
     564        { 
     565            name = command_names[i].name; 
     566            break; 
     567        } 
    466568 
    467     return NULL; 
     569 
     570    return name; 
     571} 
     572 
     573/* --------------------------------------------------------------------------------------------- */ 
     574 
     575/* Finds and returns the ·origin· field of the key bound to the given CK action. */ 
     576key_origin_t 
     577keybind_lookup_keymap_origin (const global_keymap_t * keymap, long action) 
     578{ 
     579    if (keymap != NULL) 
     580    { 
     581        size_t i; 
     582 
     583        for (i = 0; keymap[i].key != 0; i++) 
     584            if (keymap[i].command == action) 
     585                return keymap[i].origin; 
     586    } 
     587    return ORIGIN_UNKNOWN; 
    468588} 
    469589 
    470590/* --------------------------------------------------------------------------------------------- */ 
  • lib/keybind.h

    diff --git a/lib/keybind.h b/lib/keybind.h
    index af019df09..a3f1cd268 100644
    a b enum 
    346346    CK_MergeOther 
    347347}; 
    348348 
     349/* 
     350 * The values of the key binding «origin» indicator field in the global_keymap_t entry for the 
     351 * binding. It informs about from where the key binding comes from (the binary, a config file, 
     352 * a slang script / plugin). 
     353 */ 
     354 
     355typedef enum 
     356{ 
     357    /* 
     358     * A special, error value used when the keymap entry for the given action cannot be found, 
     359     * when looking up origin field by the CK action code. 
     360     */ 
     361    ORIGIN_UNKNOWN = -1, 
     362 
     363    /* 
     364     * Assign 0, so that omision of the field in the global_keymap_t initializer will lead to this. 
     365     * Meaning: the `mc` binary is the origin of the keybinding. 
     366     */ 
     367    ORIGIN_COMPILE_TIME = 0, 
     368 
     369    ORIGIN_FILE,                /* The binding comes from a file. */ 
     370    ORIGIN_SLANG_SCRIPT         /* The binding comes from S-Lang script execution (e.g.: a plugin) */ 
     371} key_origin_t; 
     372 
    349373/*** structures declarations (and typedefs of structures)*****************************************/ 
    350374 
    351375typedef struct name_keymap_t 
    typedef struct global_keymap_t 
    368392    long key; 
    369393    long command; 
    370394    char caption[KEYMAP_SHORTCUT_LENGTH]; 
     395    key_origin_t origin; 
    371396} global_keymap_t; 
    372397 
    373398/*** global variables defined in .c file *********************************************************/ 
    374399 
     400extern int new_dynamic_command_id; 
     401 
    375402/*** declarations of public functions ************************************************************/ 
    376403 
    377 void keybind_cmd_bind (GArray * keymap, const char *keybind, long action); 
     404int keybind_add_new_action (const char *new_command_name, int new_ck_id); 
     405void keybind_cmd_bind (GArray * keymap, const char *keybind, long action, key_origin_t origin); 
    378406long keybind_lookup_action (const char *name); 
    379407const char *keybind_lookup_actionname (long action); 
     408key_origin_t keybind_lookup_keymap_origin (const global_keymap_t * keymap, long action); 
    380409const char *keybind_lookup_keymap_shortcut (const global_keymap_t * keymap, long action); 
    381410long keybind_lookup_keymap_command (const global_keymap_t * keymap, long key); 
    382411 
  • lib/mcconfig/paths.c

    diff --git a/lib/mcconfig/paths.c b/lib/mcconfig/paths.c
    index e111dc7a2..33ca890b4 100644
    a b static const struct 
    7272    { "cedit" PATH_SEP_STR "menu",           &mc_config_str, EDIT_HOME_MENU }, 
    7373    { "panels.ini",                          &mc_config_str, MC_PANELS_FILE }, 
    7474 
     75    /* Plugins (S-Lang scripting). */ 
     76    { "plugin",                              &mc_config_str, MC_PLUGIN_DIR }, 
     77 
    7578    /* User should move this file with applying some changes in file */ 
    7679    { "",                                    &mc_config_str, MC_FILEBIND_FILE }, 
    7780 
  • lib/widget/dialog.c

    diff --git a/lib/widget/dialog.c b/lib/widget/dialog.c
    index b8a08f029..2aca8f8a0 100644
    a b frontend_dlg_run (WDialog * h) 
    313313 
    314314        widget_update_cursor (wh); 
    315315 
     316        /* Emit any postponed message boxes. */ 
     317        if (are_postponed_messages ()) 
     318            display_postponed_messages (); 
     319 
    316320        /* Clear interrupt flag */ 
    317321        tty_got_interrupt (); 
    318322        d_key = tty_get_event (&event, GROUP (h)->mouse_status == MOU_REPEAT, TRUE); 
  • lib/widget/wtools.c

    diff --git a/lib/widget/wtools.c b/lib/widget/wtools.c
    index 5c5dc4487..d1104d8bc 100644
    a b  
    5050 
    5151/*** file scope type declarations ****************************************************************/ 
    5252 
     53typedef struct postponed_msg_s 
     54{ 
     55    int flags; 
     56    char *title; 
     57    char *text; 
     58} postponed_msg_t; 
     59 
    5360/*** file scope variables ************************************************************************/ 
    5461 
     62static GSList *postponed_msgs = NULL; 
     63 
    5564static WDialog *last_query_dlg; 
    5665 
    5766static int sel_pos = 0; 
    wtools_parent_call_string (void *routine, int argc, ...) 
    268277/*** public functions ****************************************************************************/ 
    269278/* --------------------------------------------------------------------------------------------- */ 
    270279 
     280/* Return truth if there are some queued postponed messages. */ 
     281gboolean 
     282are_postponed_messages (void) 
     283{ 
     284    return postponed_msgs != NULL; 
     285} 
     286 
     287/* --------------------------------------------------------------------------------------------- */ 
     288 
     289void 
     290postponed_message (int flags_, const char *title, const char *text, ...) 
     291{ 
     292    va_list args; 
     293 
     294    /* Initialize a heap allocated, message container struct. */ 
     295    postponed_msg_t *msg_heap; 
     296    msg_heap = g_new (postponed_msg_t, 1); 
     297 
     298    va_start (args, text); 
     299 
     300    *msg_heap = (postponed_msg_t) 
     301    { 
     302    flags_, g_strdup (title), g_strdup_vprintf (text, args)}; 
     303 
     304    va_end (args); 
     305 
     306    /* Append the heap pointer to the GSList. */ 
     307    postponed_msgs = g_slist_append (postponed_msgs, msg_heap); 
     308} 
     309 
     310/* --------------------------------------------------------------------------------------------- */ 
     311 
     312void 
     313display_postponed_messages () 
     314{ 
     315    GSList *it; 
     316 
     317    for (it = postponed_msgs; it != NULL; it = it->next) 
     318    { 
     319        postponed_msg_t *msg = (postponed_msg_t *) it->data; 
     320 
     321        /* Show the dialog with the saved message body and flags. */ 
     322        message (msg->flags, msg->title, msg->text); 
     323 
     324        /* Release the fields of the struct. */ 
     325        g_free (msg->title); 
     326        g_free (msg->text); 
     327    } 
     328 
     329    /* Release whole list and also call g_free on each element. */ 
     330    g_slist_free_full (g_steal_pointer (&postponed_msgs), g_free); 
     331} 
     332 
     333/* --------------------------------------------------------------------------------------------- */ 
     334 
    271335/** Used to ask questions to the user */ 
    272336int 
    273337query_dialog (const char *header, const char *text, int flags, int count, ...) 
  • lib/widget/wtools.h

    diff --git a/lib/widget/wtools.h b/lib/widget/wtools.h
    index cd0bc3253..b1f7a9b47 100644
    a b struct simple_status_msg_t 
    6161 
    6262/*** declarations of public functions ************************************************************/ 
    6363 
     64/* 
     65 * A simple message queue that postpones the messages until MC enters the main loop. It allows to 
     66 * use dialog messages early during the initialization, e.g.: to signal problems during it. Message 
     67 * will appear when UI is fully initialized and drawn. 
     68 */ 
     69 
     70gboolean are_postponed_messages (void); 
     71void postponed_message (int flags, const char *title, const char *text, ...) 
     72    __attribute__ ((format (printf, 3, 4))); 
     73void display_postponed_messages (void); 
     74 
    6475/* The input dialogs */ 
    6576char *input_dialog (const char *header, const char *text, 
    6677                    const char *history_name, const char *def_text, 
  • new file misc/grow_shrink_integer.plugin.sl

    diff --git a/misc/grow_shrink_integer.plugin.sl b/misc/grow_shrink_integer.plugin.sl
    new file mode 100644
    index 000000000..ad91db04e
    - +  
     1% Copy this file to ~/.config/mc/plugin/, it'll be automatically loaded at startup. 
     2 
     3define grow_shrink_int__get_current_or_next_number() { 
     4    variable pos = -1, bol_offset, eol_offset, start_digit_offset,  
     5        t = "", found, start_digit_seen, c1,  c2; 
     6 
     7    bol_offset = mc->cure_get_bol (); 
     8    eol_offset = mc->cure_get_eol (); 
     9 
     10    % Find the start of the number (a word, actually) 
     11    for (pos = mc->cure_cursor_offset(); pos >= bol_offset; pos--) 
     12    { 
     13        c1 = mc->cure_get_byte (pos); 
     14        c2 = mc->cure_get_byte (pos - 1); 
     15 
     16        if (not isdigit(c1)) 
     17            break; 
     18        if (not isspace (c1) && isspace (c2)) 
     19            break; 
     20    } 
     21 
     22    % Find the end of the number (a word, actually) 
     23    found=0; 
     24    start_digit_offset=0; 
     25    start_digit_seen=0; 
     26    for (; pos <= eol_offset; pos++) 
     27    { 
     28        c1 = mc->cure_get_byte (pos); 
     29        c2 = mc->cure_get_byte (pos + 1); 
     30 
     31        % Append the byte to the string 
     32        if (isdigit (c1)) { 
     33            if (not start_digit_seen) { 
     34                start_digit_seen=1; 
     35                start_digit_offset=pos; 
     36            } 
     37            found = 1; t += char(c1); 
     38        } 
     39 
     40        if (isdigit (c1) && not isdigit (c2)) { 
     41            found += 1; 
     42            break; 
     43        } 
     44    } 
     45 
     46    % Any number found? 
     47    % If not, return an empty string and minus one position 
     48    if (found == 2) { 
     49        % Include any minus sign 
     50        c1 = mc->cure_get_byte (start_digit_offset-1); 
     51        if (c1 == '-') 
     52            t = char(c1) + t; 
     53    } 
     54    return t, pos; 
     55} 
     56 
     57% A backend function for the two next public functions 
     58define grow_shrink_int__increment(direction) { 
     59    variable pos, cpos, number = 0; 
     60    variable number_str, new_number_buf; 
     61    variable number_len = 0, new_number_len = 0, idx; 
     62 
     63    % Get the number 
     64    (number_str, pos) = grow_shrink_int__get_current_or_next_number(); 
     65    % Has been a number found? 
     66    if (strlen(number_str) > 0) { 
     67        number_len = strlen(number_str); 
     68        % Convert the string into integer to increment it 
     69        number = atoll(number_str); 
     70        number += (direction > 0) ? 1 : -1; 
     71        new_number_buf = string(number); 
     72        new_number_len = strlen(new_number_buf); 
     73 
     74        % Move the cursor to the found number 
     75        cpos = mc->cure_cursor_offset(); 
     76        mc->cure_cursor_move (pos-cpos); 
     77        % Delete the existing number 
     78        mc->cure_delete(); 
     79        for (idx = 0; idx < number_len-1; idx ++) 
     80            mc->cure_backspace(); 
     81        % Insert updated number 
     82        for (idx = 0; idx < new_number_len; idx ++) 
     83            mc->cure_insert_ahead(new_number_buf[new_number_len-idx-1]); 
     84    } 
     85 
     86    % Return the updated number. Just for fun :) Maybe it'll find some use one day 
     87    return number; 
     88} 
     89 
     90% The end user function for incrementing an integer 
     91define grow_shrink_int__grow_int() { 
     92    return grow_shrink_int__increment(1); 
     93} 
     94 
     95% The end user function for taking 1 from an integer 
     96define grow_shrink_int__shrink_int() { 
     97    return grow_shrink_int__increment(-1); 
     98} 
     99 
     100% Register the default key bindings – Alt-a for grow, Alt-x for shrink. 
     101mc->editor_map_key_to_func("GrowInteger", "alt-a", "grow_shrink_int__grow_int"); 
     102mc->editor_map_key_to_func("ShrinkInteger", "alt-x", "grow_shrink_int__shrink_int"); 
  • new file misc/init.sl

    diff --git a/misc/init.sl b/misc/init.sl
    new file mode 100644
    index 000000000..9f77dcfa5
    - +  
     1% MCEdit Startup Script in S-Lang Scripting Language 
     2% 
     3% See: 
     4% – https://www.jedsoft.org/slang/doc/html/slang.html, 
     5% for a reference on the language. 
     6 
     7% Increase to 2 to have confirmation messages after loading this script and other plugins. 
     8mc_loglevel=1; 
     9 
     10% A function showing a listbox: 
     11define listbox_display_function() { 
     12    variable items = ["This is a listbox", "It's displayed from…", 
     13        "…`init.sl` S-Lang startup script"]; 
     14 
     15    variable sel = mc->listbox(5, 35, "Welcome",items); 
     16 
     17    if (sel >= 0) 
     18        mc->message("You have selected:", "item #" + string(sel+1) + ": " + items[sel]); 
     19    else 
     20        mc->message("Info", "No selection have been made"); 
     21 
     22    return 1; 
     23} 
     24 
     25% A function causing runtime error: 
     26define divide_by_zero() { 
     27    variable string = "Divided by 0 on purpose"; 
     28    variable mc = 1 / 0; 
     29} 
     30 
     31% A function to present backtrace functionality: 
     32define b_function() { 
     33    variable tmp_variable = 5; 
     34    divide_by_zero(); 
     35    return 0; 
     36} 
     37 
     38% A function to present backtrace functionality: 
     39define a_function() { 
     40    b_function(); 
     41    return 0; 
     42} 
     43 
     44 
     45% Show an error message on Ctrl-t: 
     46mc->editor_map_key_to_func("DivBy0Action", "ctrl-t", "a_function"); 
     47 
     48% Show a listbox on Alt-y: 
     49mc->editor_map_key_to_func("ListboxAction", "alt-y", "listbox_display_function"); 
  • src/Makefile.am

    diff --git a/src/Makefile.am b/src/Makefile.am
    index e883ab4bd..3f8100352 100644
    a b libinternal_la_SOURCES = \ 
    8080        setup.c setup.h \ 
    8181        textconf.c textconf.h \ 
    8282        usermenu.c usermenu.h \ 
    83         util.c util.h 
     83        util.c util.h \ 
     84        slang_engine.c slang_engine.h \ 
     85        slang_api_functions.c \ 
     86        slang_api_functions_glue.c 
    8487 
    8588if CHARSET 
    8689    libinternal_la_SOURCES += selcodepage.c selcodepage.h 
  • src/editor/edit.c

    diff --git a/src/editor/edit.c b/src/editor/edit.c
    index edda1f832..53b9c059c 100644
    a b  
    4242#include <sys/stat.h> 
    4343#include <stdint.h>             /* UINTMAX_MAX */ 
    4444#include <stdlib.h> 
     45#include <slang.h> 
    4546 
    4647#include "lib/global.h" 
    4748 
     
    6566 
    6667#include "src/setup.h"          /* option_tab_spacing */ 
    6768#include "src/keybind-defaults.h" 
     69#include "src/slang_engine.h" 
    6870 
    6971#include "edit-impl.h" 
    7072#include "editwidget.h" 
    void 
    32483250edit_execute_cmd (WEdit * edit, long command, int char_for_insertion) 
    32493251{ 
    32503252    Widget *w = WIDGET (edit); 
     3253    GSList *slang_code = NULL; 
     3254    /* Check if the command is a S-Lang script registered command */ 
     3255    if ((slang_code = get_command_callback (command)) != NULL) 
     3256    { 
     3257        int ret_api, ret_api2 = -1, ret_fun = 0; 
     3258        ret_api = SLang_execute_function (slang_code->data); 
     3259        if (ret_api == 0) 
     3260            message (D_ERROR, "S-Lang plugin error", "Function doesn't exist."); 
    32513261 
     3262        else if (ret_api < 0 || -1 == (ret_api2 = SLang_pop_int (&ret_fun))) 
     3263        { 
     3264            /* 
     3265             * If the function returned 1, then edit_execute_cmd() will continue, otherwise it will 
     3266             * exit. This feature can be used to tap into build in commands and moderate/replace 
     3267             * their execution. 
     3268             */ 
     3269            if (SLang_get_error ()) 
     3270            { 
     3271                SLang_restart (1); 
     3272                SLang_set_error (0); 
     3273            } 
     3274        } 
     3275        if (ret_api <= 0 || ret_api2 <= 0 || !ret_fun) 
     3276            return; 
     3277    } 
    32523278    if (command == CK_WindowFullscreen) 
    32533279    { 
    32543280        edit_toggle_fullscreen (edit); 
  • src/editor/editbuffer.c

    diff --git a/src/editor/editbuffer.c b/src/editor/editbuffer.c
    index 101918bef..d3f78271f 100644
    a b  
    3333 
    3434#include <stdlib.h> 
    3535#include <string.h> 
     36#include <ctype.h> 
    3637#include <sys/types.h> 
    3738 
    3839#include "lib/global.h" 
    edit_buffer_get_eol (const edit_buffer_t * buf, off_t current) 
    384385    return current; 
    385386} 
    386387 
     388/* --------------------------------------------------------------------------------------------- */ 
     389/** 
     390 * Find first character of current word. If jump_spaces is TRUE, then any whitespace gap on the 
     391   left is being ignored (i.e.: jumped across for the preceding word). */ 
     392 
     393gboolean 
     394edit_buffer_find_word_start (const edit_buffer_t * buf, gboolean jump_spaces, off_t * word_start, 
     395                             gsize * word_len) 
     396{ 
     397    int c, spc_count = 0; 
     398    off_t i = 1; 
     399    gboolean have_ending_char = FALSE; 
     400 
     401    /* STARTUP: Initialize the output variables to a reasonable initial values. */ 
     402    *word_start = buf->curs1; 
     403    *word_len = (gsize) 0; 
     404 
     405    /* Return nothing if at begin of file. */ 
     406    if (buf->curs1 <= 0) 
     407        return FALSE; 
     408 
     409    /* A first peek at the first preceding char. */ 
     410    c = edit_buffer_get_previous_byte (buf); 
     411    /* Return if the word is empty (i.e.: the char is a space and we're not jumping over them). */ 
     412    if ((!jump_spaces && isspace (c)) || c == '\n') 
     413        return FALSE; 
     414 
     415    /* Skip any whitespace. */ 
     416    if (jump_spaces && isspace (c)) 
     417    { 
     418        spc_count++; 
     419        /* Jump over all whitespace on the left. Initial i++ means: a skip of the first space (move 
     420         * on to processing next char before it). */ 
     421        for (i++; buf->curs1 - i >= 0; i++) 
     422        { 
     423            c = edit_buffer_get_byte (buf, buf->curs1 - i); 
     424            if (!isspace (c)) 
     425            { 
     426                break; 
     427            } 
     428            else if (c == '\n') 
     429                /* Preliminary new line → return nothing. This function works in current line. */ 
     430                return FALSE; 
     431            spc_count++; 
     432        } 
     433    } 
     434 
     435    /* Whitespace till the beginning of the buffer? */ 
     436    if (isspace (c)) 
     437        return FALSE; 
     438 
     439    /* Accept this (either initial or one found after skipping spaces) char and move on, if 
     440     * there are any left chars in buffer. */ 
     441    i++; 
     442 
     443    /* 
     444     * Word boundary char right after optional spaces → accept only it. 
     445     * This means that a single word boundary char constitutes a word of length 1, either 
     446     * after spaces (skipped above ↑) or immediately before cursor. 
     447     */ 
     448 
     449    if (is_break_char (c)) 
     450        /* i variable points to the single char, skip iterating more. */ 
     451        have_ending_char = TRUE; 
     452 
     453    /* Search start of word to be completed. */ 
     454    for (; !have_ending_char && buf->curs1 - i >= 0; i++) 
     455    { 
     456        c = edit_buffer_get_byte (buf, buf->curs1 - i); 
     457 
     458        if (is_break_char (c)) 
     459            /* 
     460             * The isdigit() condition here was too specific for this general function (it was 
     461             * excluding any words starting with a digit). 
     462             */ 
     463            break; 
     464    } 
     465 
     466    /* Success – a word has been properly found and delimited. */ 
     467    *word_start = buf->curs1 - i + 1;   /* Save start found to result variable */ 
     468    *word_len = (gsize) i - 1 - spc_count;      /* …and word length */ 
     469 
     470    return TRUE; 
     471} 
     472 
     473/* --------------------------------------------------------------------------------------------- */ 
     474 
     475/* Gets the word on the left of the cursor. 
     476 * 
     477 * @param buf The edit buffer. 
     478 * @param jump_spaces Should any whitespace gap be jumped over? If not, it'll cause empty result. 
     479 * @param initial Initial contents of the result. 
     480 * @param release_on_empty Should the initial g_string be released when returning NULL. 
     481 * @return g_string with the word or NULL if the word is empty. 
     482 */ 
     483GString * 
     484edit_buffer_get_left_whole_word (const edit_buffer_t * buf, gboolean jump_spaces, GString * initial, 
     485                                 gboolean release_on_empty) 
     486{ 
     487    GString *ret = initial; 
     488    gsize i, word_len = 0; 
     489    off_t word_start = 0; 
     490 
     491    /* Search start of word left of cursor. */ 
     492    if (!edit_buffer_find_word_start (buf, jump_spaces, &word_start, &word_len)) 
     493    { 
     494        if (initial && release_on_empty) 
     495            g_string_free (initial, TRUE); 
     496        return NULL; 
     497    } 
     498 
     499    /* ret = g_strdup_printf ("\\b%.*s[a-zA-Z_0-9]+", word_len, bufpos); */ 
     500    if (!ret) 
     501        ret = g_string_sized_new (32); 
     502 
     503    for (i = 0; i < word_len; i++) 
     504        g_string_append_c (ret, edit_buffer_get_byte (buf, word_start + i)); 
     505 
     506    return ret; 
     507} 
     508 
    387509/* --------------------------------------------------------------------------------------------- */ 
    388510/** 
    389511 * Get word from specified offset. 
  • src/editor/editbuffer.h

    diff --git a/src/editor/editbuffer.h b/src/editor/editbuffer.h
    index 9d65e71eb..33dd8f548 100644
    a b int edit_buffer_get_prev_utf (const edit_buffer_t * buf, off_t byte_index, int * 
    4646long edit_buffer_count_lines (const edit_buffer_t * buf, off_t first, off_t last); 
    4747off_t edit_buffer_get_bol (const edit_buffer_t * buf, off_t current); 
    4848off_t edit_buffer_get_eol (const edit_buffer_t * buf, off_t current); 
     49gboolean edit_buffer_find_word_start (const edit_buffer_t * buf, gboolean jump_spaces, 
     50                                      off_t * word_start, gsize * word_len); 
     51GString *edit_buffer_get_left_whole_word (const edit_buffer_t * buf, gboolean jump_spaces, 
     52                                          GString * initial, gboolean release_on_empty); 
    4953GString *edit_buffer_get_word_from_pos (const edit_buffer_t * buf, off_t start_pos, off_t * start, 
    5054                                        gsize * cut); 
    5155 
  • src/editor/editcmd.c

    diff --git a/src/editor/editcmd.c b/src/editor/editcmd.c
    index 0d2caa923..6ec993e4d 100644
    a b pipe_mail (const edit_buffer_t * buf, char *to, char *subject, char *cc) 
    11271127    } 
    11281128} 
    11291129 
    1130 /* --------------------------------------------------------------------------------------------- */ 
    1131 /** find first character of current word */ 
    1132  
    1133 static gboolean 
    1134 edit_find_word_start (const edit_buffer_t * buf, off_t * word_start, gsize * word_len) 
    1135 { 
    1136     int c; 
    1137     off_t i; 
    1138  
    1139     /* return if at begin of file */ 
    1140     if (buf->curs1 <= 0) 
    1141         return FALSE; 
    1142  
    1143     c = edit_buffer_get_previous_byte (buf); 
    1144     /* return if not at end or in word */ 
    1145     if (is_break_char (c)) 
    1146         return FALSE; 
    1147  
    1148     /* search start of word to be completed */ 
    1149     for (i = 1;; i++) 
    1150     { 
    1151         int last; 
    1152  
    1153         last = c; 
    1154         c = edit_buffer_get_byte (buf, buf->curs1 - i - 1); 
    1155  
    1156         if (is_break_char (c)) 
    1157         { 
    1158             /* return if word starts with digit */ 
    1159             if (isdigit (last)) 
    1160                 return FALSE; 
    1161  
    1162             break; 
    1163         } 
    1164     } 
    1165  
    1166     /* success */ 
    1167     *word_start = buf->curs1 - i;       /* start found */ 
    1168     *word_len = (gsize) i; 
    1169  
    1170     return TRUE; 
    1171 } 
    1172  
    11731130/* --------------------------------------------------------------------------------------------- */ 
    11741131/** 
    11751132 * Get current word under cursor 
    edit_complete_word_cmd (WEdit * edit) 
    33403297    GString *compl[MAX_WORD_COMPLETIONS];       /* completions */ 
    33413298 
    33423299    /* search start of word to be completed */ 
    3343     if (!edit_find_word_start (&edit->buffer, &word_start, &word_len)) 
     3300    if (!edit_buffer_find_word_start (&edit->buffer, FALSE, &word_start, &word_len)) 
    33443301        return; 
    33453302 
    33463303    /* prepare match expression */ 
    edit_get_match_keyword_cmd (WEdit * edit) 
    35083465    gsize word_len = 0, max_len = 0; 
    35093466    int num_def = 0; 
    35103467    gsize i; 
    3511     off_t word_start = 0; 
    35123468    GString *match_expr; 
    35133469    char *path = NULL; 
    35143470    char *ptr = NULL; 
    edit_get_match_keyword_cmd (WEdit * edit) 
    35193475    for (i = 0; i < MAX_DEFINITIONS; i++) 
    35203476        def_hash[i].filename = NULL; 
    35213477 
    3522     /* search start of word to be completed */ 
    3523     if (!edit_find_word_start (&edit->buffer, &word_start, &word_len)) 
    3524         return; 
    3525  
    35263478    /* prepare match expression */ 
    3527     match_expr = g_string_sized_new (word_len); 
    3528     for (i = 0; i < word_len; i++) 
    3529         g_string_append_c (match_expr, edit_buffer_get_byte (&edit->buffer, word_start + i)); 
    3530  
     3479    match_expr = edit_buffer_get_left_whole_word (&edit->buffer, TRUE, NULL, FALSE); 
     3480    if (match_expr == NULL) 
     3481        return; 
    35313482    ptr = g_get_current_dir (); 
    35323483    path = g_strconcat (ptr, PATH_SEP_STR, (char *) NULL); 
    35333484    g_free (ptr); 
    edit_get_match_keyword_cmd (WEdit * edit) 
    35543505    g_free (path); 
    35553506 
    35563507    max_len = MAX_WIDTH_DEF_DIALOG; 
    3557     word_len = 0; 
    35583508    if (num_def > 0) 
    35593509        editcmd_dialog_select_definition_show (edit, match_expr->str, max_len, word_len, 
    35603510                                               (etags_hash_t *) & def_hash, num_def); 
  • src/editor/editwidget.c

    diff --git a/src/editor/editwidget.c b/src/editor/editwidget.c
    index 18ac00e66..5f553a8cb 100644
    a b  
    6161#include "src/filemanager/cmd.h"        /* save_setup_cmd()  */ 
    6262#include "src/learn.h"          /* learn_keys() */ 
    6363#include "src/args.h"           /* mcedit_arg_t */ 
     64#include "src/slang_engine.h" 
    6465 
    6566#include "edit-impl.h" 
    6667#include "editwidget.h" 
  • src/main.c

    diff --git a/src/main.c b/src/main.c
    index d691bcb2a..dd8b0b7ea 100644
    a b  
    6262#include "filemanager/ext.h"    /* flush_extension_file() */ 
    6363#include "filemanager/command.h"        /* cmdline */ 
    6464#include "filemanager/panel.h"  /* panalized_panel */ 
     65#include "editor/editwidget.h" 
    6566 
    6667#include "vfs/plugins_init.h" 
    6768 
     
    7778#include "selcodepage.h" 
    7879#endif /* HAVE_CHARSET */ 
    7980 
     81#include "slang_engine.h" 
    8082#include "consaver/cons.saver.h"        /* cons_saver_pid */ 
    8183 
    8284/*** global variables ****************************************************************************/ 
    main (int argc, char *argv[]) 
    456458        } 
    457459    } 
    458460 
     461    /* Initialize the S-Lang interpreter and load `init.sl` file. */ 
     462    slang_init_engine (); 
     463 
     464    /* 
     465     * Load the plugins before the setup so that the commands that are being 
     466     * created in them can be bound with a key. 
     467     */ 
     468    slang_plugins_init (); 
     469 
    459470    /* Program main loop */ 
    460471    if (mc_global.midnight_shutdown) 
    461472        exit_code = EXIT_SUCCESS; 
  • src/setup.c

    diff --git a/src/setup.c b/src/setup.c
    index 77c07649d..fce4f18a9 100644
    a b load_keymap_from_section (const char *section_name, GArray * keymap, mc_config_t 
    784784            long action; 
    785785 
    786786            action = keybind_lookup_action (*profile_keys); 
     787 
     788            /* 
     789             * Dynamically created commands – registered on demand. If the command doesn't exist, 
     790             * meaning that it isn't a compile-time, original command, then extend the internal 
     791             * data structures with a new command entry, assigning it an unique CK id. Such command 
     792             * can then be legally mapped to a key. 
     793             */ 
     794            if (action <= 0) 
     795            { 
     796                int added; 
     797                added = keybind_add_new_action (*profile_keys, new_dynamic_command_id); 
     798                action = added ? new_dynamic_command_id : 0;    /* check if CK ID was assigned */ 
     799                new_dynamic_command_id += added;        /* if yes, increment the root CK ID variable */ 
     800            } 
     801 
     802            /* Do the binding if the command has been found (i.e.: its CK ID is known). */ 
    787803            if (action > 0) 
    788804            { 
    789805                gchar **curr_values; 
    790806 
    791807                for (curr_values = values; *curr_values != NULL; curr_values++) 
    792                     keybind_cmd_bind (keymap, *curr_values, action); 
     808                    keybind_cmd_bind (keymap, *curr_values, action, ORIGIN_FILE); 
    793809            } 
    794810 
    795811            g_strfreev (values); 
  • new file src/slang_api_functions.c

    diff --git a/src/slang_api_functions.c b/src/slang_api_functions.c
    new file mode 100644
    index 000000000..be961d969
    - +  
     1/* 
     2   Implementation of functions supplied to S-Lang interpreter. 
     3 
     4   Copyright (C) 2021 
     5   Free Software Foundation, Inc. 
     6 
     7   Written by: 
     8   Sebastian Gniazdowski <sgniazdowski@gmail.com>, 2021 
     9 
     10   This file is part of the Midnight Commander. 
     11 
     12   The Midnight Commander is free software: you can redistribute it 
     13   and/or modify it under the terms of the GNU General Public License as 
     14   published by the Free Software Foundation, either version 3 of the License, 
     15   or (at your option) any later version. 
     16 
     17   The Midnight Commander is distributed in the hope that it will be useful, 
     18   but WITHOUT ANY WARRANTY; without even the implied warranty of 
     19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     20   GNU General Public License for more details. 
     21 
     22   You should have received a copy of the GNU General Public License 
     23   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
     24 */ 
     25 
     26/** \file slang_api_functions.c 
     27 *  \brief Implementation of functions exported/added to S-Lang interpreter. 
     28 *  \author Sebastian Gniazdowski 
     29 *  \date 2021 
     30 * 
     31 *  Here are functions implemented that are automatically exported to S-Lang interpreter by Slirp 
     32 *  utility. They connect the interpreter with mc process and allow to direct it to perform some 
     33 *  tasks like getting a word from current buffer, moving a cursor, etc. 
     34 */ 
     35 
     36 
     37#include <config.h> 
     38 
     39#include "lib/global.h" 
     40#include "lib/widget.h" 
     41#include "lib/util.h" 
     42 
     43#include "src/slang_engine.h" 
     44#include "src/slang_api_functions.h" 
     45#include "src/keybind-defaults.h" 
     46#include "src/editor/editwidget.h" 
     47 
     48/*** global variables ****************************************************************************/ 
     49 
     50/*** file scope macro definitions ****************************************************************/ 
     51 
     52/*** file scope type declarations ****************************************************************/ 
     53 
     54/*** file scope variables ************************************************************************/ 
     55 
     56/*** file scope functions ************************************************************************/ 
     57/* --------------------------------------------------------------------------------------------- */ 
     58 
     59/* Gets  current editor object. */ 
     60static WEdit * 
     61get_cure (void) 
     62{ 
     63    GList *dialog = top_dlg; 
     64 
     65    /* Search first fullscreen dialog */ 
     66    for (; dialog != NULL; dialog = g_list_next (dialog)) 
     67        if ((WIDGET (dialog->data)->pos_flags & WPOS_FULLSCREEN) != 0) 
     68            break; 
     69    if (dialog) 
     70        return (WEdit *) (GROUP (dialog->data)->current->data); 
     71    else 
     72        return NULL; 
     73} 
     74 
     75/* --------------------------------------------------------------------------------------------- */ 
     76 
     77/* 
     78 * Updates  possibly reallocated keymap pointer in all open editors. 
     79 */ 
     80 
     81static gboolean 
     82update_editor_keymaps (global_keymap_t * keymap) 
     83{ 
     84    WEdit *e; 
     85    WGroup *g; 
     86    gboolean ret = FALSE; 
     87 
     88    e = get_cure (); 
     89    if (e == NULL) 
     90        return ret; 
     91    g = GROUP (WIDGET (e)->owner); 
     92    if (g == NULL) 
     93        return ret; 
     94 
     95    editor_map = keymap; 
     96    for (GList * it = g->widgets; it != NULL; it = g_list_next (it)) 
     97    { 
     98        if (edit_widget_is_editor (WIDGET (it->data))) 
     99        { 
     100            WIDGET (it->data)->keymap = keymap; 
     101            ret = TRUE; 
     102        } 
     103    } 
     104 
     105    return ret; 
     106} 
     107 
     108/* --------------------------------------------------------------------------------------------- */ 
     109/*** public functions ****************************************************************************/ 
     110/* --------------------------------------------------------------------------------------------- */ 
     111 
     112/* 
     113 * S-LANG FUNCTION: _cure_cursor_move(offset) 
     114 */ 
     115 
     116void 
     117slang_api__cure_cursor_move (int offset) 
     118{ 
     119    edit_cursor_move (get_cure (), offset); 
     120} 
     121 
     122/* --------------------------------------------------------------------------------------------- */ 
     123 
     124/* 
     125 * S-LANG FUNCTION: cure_cursor_offset() 
     126 * RETURN VALUE: The offset in bytes of the current cursor position 
     127 */ 
     128 
     129int 
     130slang_api__cure_cursor_offset (void) 
     131{ 
     132    return get_cure ()->buffer.curs1; 
     133} 
     134 
     135/* --------------------------------------------------------------------------------------------- */ 
     136 
     137/* 
     138 * S-LANG FUNCTION: cure_get_eol(byte_idx) 
     139 * RETURN VALUE: the byte offset of the end of the current line 
     140 */ 
     141 
     142int 
     143slang_api__cure_get_eol (void) 
     144{ 
     145    return edit_buffer_get_current_eol (&get_cure ()->buffer); 
     146} 
     147 
     148/* --------------------------------------------------------------------------------------------- */ 
     149 
     150/* 
     151 * S-LANG FUNCTION: cure_get_bol(byte_idx) 
     152 * RETURN VALUE: the byte offset of the beginning of the current line 
     153 */ 
     154 
     155int 
     156slang_api__cure_get_bol (void) 
     157{ 
     158    return edit_buffer_get_current_bol (&get_cure ()->buffer); 
     159} 
     160 
     161/* --------------------------------------------------------------------------------------------- */ 
     162 
     163/* 
     164 * S-LANG FUNCTION: cure_get_byte(byte_idx) 
     165 * RETURN VALUE: the byte at the given index in the currently open file 
     166 */ 
     167 
     168int 
     169slang_api__cure_get_byte (int byte_idx) 
     170{ 
     171    return edit_buffer_get_byte (&get_cure ()->buffer, byte_idx); 
     172} 
     173 
     174/* --------------------------------------------------------------------------------------------- */ 
     175 
     176/* 
     177 * S-LANG FUNCTION: cure_get_left_whole_word(byte_idx) 
     178 * RETURN VALUE: word the byte at the given index in the currently open file 
     179 */ 
     180 
     181char * 
     182slang_api__cure_get_left_whole_word (int skip_space) 
     183{ 
     184    GString *res_gstr; 
     185    char *res; 
     186    res_gstr = edit_buffer_get_left_whole_word (&get_cure ()->buffer, skip_space, NULL, FALSE); 
     187 
     188    /* Ensure a non-null result. */ 
     189    if (!res_gstr) 
     190        res_gstr = g_string_new (""); 
     191 
     192    /* Return inner buffer of GString. */ 
     193    res = res_gstr->str; 
     194    g_string_free (res_gstr, FALSE); 
     195 
     196    return res; 
     197} 
     198 
     199/* --------------------------------------------------------------------------------------------- */ 
     200 
     201/* 
     202 * S-LANG FUNCTION: cure_delete() 
     203 * RETURN VALUE: The code of the deleted character 
     204 */ 
     205 
     206int 
     207slang_api__cure_delete (void) 
     208{ 
     209    return edit_buffer_delete (&get_cure ()->buffer); 
     210} 
     211 
     212/* --------------------------------------------------------------------------------------------- */ 
     213 
     214/* 
     215 * S-LANG FUNCTION: cure_backspace() 
     216 * RETURN VALUE: The code of the deleted character 
     217 */ 
     218 
     219int 
     220slang_api__cure_backspace (void) 
     221{ 
     222    return edit_buffer_backspace (&get_cure ()->buffer); 
     223} 
     224 
     225/* --------------------------------------------------------------------------------------------- */ 
     226 
     227/* 
     228 * S-LANG FUNCTION: cure_insert_ahead() 
     229 */ 
     230 
     231void 
     232slang_api__cure_insert_ahead (int c) 
     233{ 
     234    edit_buffer_insert_ahead (&get_cure ()->buffer, c); 
     235} 
     236 
     237/* --------------------------------------------------------------------------------------------- */ 
     238 
     239/* 
     240 * S-LANG FUNCTION: listbox( width, height, [ items…, NULL ], help_anchor ) 
     241 * RETURN VALUE: the index of the selected element or -1 if cancelled. 
     242 */ 
     243 
     244/* A S-Lang script function which allows to display a centered dialog with a listbox 
     245   in it and then get the index of the selected item, if any. */ 
     246int 
     247slang_api__listbox (int h, int w, char *title, char **items, unsigned long size) 
     248{ 
     249    Listbox *listb; 
     250    char **cur_item; 
     251    int selected; 
     252    unsigned long i = 0; 
     253 
     254    /* Use an utility function to create the dialog with the listbox in it. */ 
     255    listb = create_listbox_window (h, w, title, ""); 
     256 
     257    /* Add the requested elements to the listbox. */ 
     258    for (cur_item = items; i < size && *cur_item != NULL; i++, cur_item++) 
     259    { 
     260        listbox_add_item (listb->list, LISTBOX_APPEND_AT_END, 's', *cur_item, NULL, FALSE); 
     261    } 
     262 
     263    /* Run the dialog and get and then return the index of the selected item. */ 
     264    selected = run_listbox (listb); 
     265    return selected; 
     266} 
     267 
     268/* --------------------------------------------------------------------------------------------- */ 
     269 
     270/* 
     271 * S-LANG FUNCTION: listbox_with_data( width, height, [ items…, NULL ], [ data…, NULL ], help_anchor ) 
     272 * RETURN VALUE: the associated data of the selected element or NULL if cancelled. 
     273 */ 
     274 
     275/* A S-Lang script function which allows to display a centered dialog with a listbox 
     276   in it and then get the associated data of the selected item, if any (otherwise, 
     277   i.e.: if canceled, it returns "". The data has to be an array of char* strings 
     278   (ended with NULL). */ 
     279char * 
     280slang_api__listbox_with_data (int h, int w, char *title, char **items, unsigned long size, 
     281                              char **data, unsigned long size2) 
     282{ 
     283    Listbox *listb; 
     284    char **cur_item, **cur_data = data; 
     285    char *selected; 
     286    unsigned long p, q = 0; 
     287 
     288    /* Use an utility function to create the dialog with the listbox in it. */ 
     289    listb = create_listbox_window (h, w, title, ""); 
     290 
     291    /* Add the requested elements to the listbox, also passing the associated data. */ 
     292    for (p = 0, cur_item = items; p < size && *cur_item != NULL; p++, cur_item++) 
     293    { 
     294        listbox_add_item (listb->list, LISTBOX_APPEND_AT_END, 's', *cur_item, *cur_data, FALSE); 
     295 
     296        /* Advance the item data pointer, respecting its size. */ 
     297        if (q < size2) 
     298        { 
     299            q++; 
     300            cur_data++; 
     301        } 
     302    } 
     303 
     304    /* Run the dialog and get and then return the associated data of the selected 
     305       item, duplicating its allocation (for S-Lang scripting host memory 
     306       management). The data has to be a char* string. */ 
     307    selected = run_listbox_with_data (listb, NULL); 
     308    return selected ? g_strdup (selected) : NULL;       //g_strdup(""); 
     309} 
     310 
     311/* --------------------------------------------------------------------------------------------- */ 
     312 
     313/* 
     314 * S-LANG FUNCTION: listbox_auto(title, [items…, NULL]) 
     315 * RETURN VALUE: the index of the selected item or -1 if cancelled. 
     316 */ 
     317 
     318/* 
     319 * Shows a listbox with the height and width automatically adapted for the 
     320 * contents and the title. 
     321 */ 
     322int 
     323slang_api__listbox_auto (char *title, char **items, unsigned long size) 
     324{ 
     325    return slang_api__listbox (5, 5, title, items, size); 
     326} 
     327 
     328/* --------------------------------------------------------------------------------------------- */ 
     329 
     330/* 
     331 * S-LANG FUNCTION: message(title, body) 
     332 */ 
     333 
     334/* Shows a message popup with the given title and body. */ 
     335void 
     336slang_api__message (const char *title, const char *body) 
     337{ 
     338    message (D_NORMAL, title, "%s", body); 
     339} 
     340 
     341/* --------------------------------------------------------------------------------------------- */ 
     342 
     343/* 
     344 * S-LANG FUNCTION: set_action_hook(command, function_name, user_data) 
     345 * RETURN VALUE: The number of the registered callbacks after the addition 
     346 */ 
     347 
     348int 
     349slang_api__set_action_hook (const char *command, const char *function_name, const char *user_data) 
     350{ 
     351    int value, ins_ret; 
     352    GSList *new_element = NULL; 
     353 
     354    /* Get the integer value code for the command name `command`. */ 
     355    value = keybind_lookup_action (command); 
     356 
     357    new_element = g_slist_append (new_element, (char *) function_name); 
     358    new_element = g_slist_append (new_element, (char *) user_data); 
     359 
     360    /* Insert the `function_name` into the hash table. */ 
     361    ins_ret = g_hash_table_insert (action_hook_functions, GINT_TO_POINTER (value), new_element); 
     362 
     363    /* Increase the element count accordingly. */ 
     364    num_action_hook_functions += ins_ret; 
     365    return num_action_hook_functions; 
     366} 
     367 
     368/* --------------------------------------------------------------------------------------------- */ 
     369 
     370/* 
     371 * S-LANG FUNCTION: editor_map_key(key_combination, command_name) 
     372 * RETURN VALUE: 1 or 0 indicating if the binding was properly added 
     373 */ 
     374int 
     375slang_api__editor_map_key_to_action (const char *command_name, const char *key_combination) 
     376{ 
     377    int value; 
     378    value = keybind_lookup_action (command_name); 
     379    if (value == CK_IgnoreKey) 
     380        /* No such command found - return 0. */ 
     381        return FALSE; 
     382 
     383    /* Overriding the bindings coming from a keymap *file* is not allowed for S-Lang plugins. */ 
     384    if (keybind_lookup_keymap_origin (editor_map, value) != ORIGIN_FILE) 
     385    { 
     386        keybind_cmd_bind (editor_keymap, key_combination, value, ORIGIN_SLANG_SCRIPT); 
     387        /* Update editors' keymap pointers  to the GArray's data in case it is reallocated. */ 
     388        update_editor_keymaps ((global_keymap_t *) editor_keymap->data); 
     389    } 
     390    else 
     391    { 
     392        /* Returning -1 will mean that action exists, but its key mapping cannot be altered. */ 
     393        return -TRUE; 
     394    } 
     395    return TRUE; 
     396} 
     397 
     398/* --------------------------------------------------------------------------------------------- */ 
     399 
     400/* 
     401 * S-LANG FUNCTION: editor_map_key_to_func(new_command_name, key_combination, function_name) 
     402 * RETURN VALUE: 1 
     403 * 
     404 * This is a convenience function that equals to calling the following 3 function 
     405 *   mc->add_new_action("CustomCommand", <some-int-ID>); 
     406 *   mc->set_action_hook("CustomCommand", "a_slang_function_name"); 
     407 *   mc->editor_map_key("CustomCommand", "alt-y"); 
     408 * 
     409 * with the only difference that the ID of the command is chosen automatically. 
     410 */ 
     411int 
     412slang_api__editor_map_key_to_func (const char *new_command_name, 
     413                                   const char *key_combination, const char *function_name) 
     414{ 
     415    int ret; 
     416    keybind_add_new_action (new_command_name, new_dynamic_command_id++); 
     417    slang_api__set_action_hook (new_command_name, function_name, NULL); 
     418    ret = slang_api__editor_map_key_to_action (new_command_name, key_combination); 
     419 
     420    return ret; 
     421} 
     422 
     423/* --------------------------------------------------------------------------------------------- */ 
  • new file src/slang_api_functions.h

    diff --git a/src/slang_api_functions.h b/src/slang_api_functions.h
    new file mode 100644
    index 000000000..2c29a3448
    - +  
     1#ifndef MC__SLANG_API_FUNCTIONS_H 
     2#define MC__SLANG_API_FUNCTIONS_H 
     3 
     4/*** typedefs(not structures) and defined constants **********************************************/ 
     5 
     6/*** enums ***************************************************************************************/ 
     7 
     8/*** structures declarations (and typedefs of structures)*****************************************/ 
     9 
     10/*** global variables defined in .c file *********************************************************/ 
     11 
     12/*** declarations of public functions ************************************************************/ 
     13 
     14/* Movement functions */ 
     15void slang_api__cure_cursor_move (int offset); 
     16 
     17/* Getting offsets */ 
     18int slang_api__cure_cursor_offset (void); 
     19int slang_api__cure_get_eol (void); 
     20int slang_api__cure_get_bol (void); 
     21 
     22/* Getting data from  buffer */ 
     23char *slang_api__cure_get_left_whole_word (int skip_space); 
     24int slang_api__cure_get_byte (int byte_idx); 
     25 
     26/* Editing functions */ 
     27int slang_api__cure_delete (void); 
     28int slang_api__cure_backspace (void); 
     29void slang_api__cure_insert_ahead (int c); 
     30 
     31/* Dialog functions */ 
     32int slang_api__listbox (int h, int w, char *title, char **items, unsigned long size); 
     33char *slang_api__listbox_with_data (int h, int w, char *title, char **items, unsigned long size, 
     34                                    char **data, unsigned long size2); 
     35int slang_api__listbox_auto (char *title, char **items, unsigned long size); 
     36void slang_api__message (const char *title, const char *body); 
     37 
     38/* Action hooks */ 
     39int slang_api__set_action_hook (const char *command, const char *function_name, 
     40                                const char *user_data); 
     41#ifndef MC__KEYBIND_H 
     42int keybind_add_new_action (const char *new_command_name, int new_ck_id); 
     43#endif 
     44 
     45/* Key bindings */ 
     46int slang_api__editor_map_key_to_action (const char *key_combination, const char *command_name); 
     47int slang_api__editor_map_key_to_func (const char *new_command_name, 
     48                                       const char *key_combination, const char *function_name); 
     49 
     50/*** inline functions ****************************************************************************/ 
     51 
     52#endif 
  • new file src/slang_api_functions_glue.c

    diff --git a/src/slang_api_functions_glue.c b/src/slang_api_functions_glue.c
    new file mode 100644
    index 000000000..ca71c281d
    - +  
     1#define HAVE_LONG_LONG 1 
     2/* * This file was generated by SLIRP, the (Sl)ang (I)nte(r)face (P)ackage, 
     3 * a S-Lang module code generator for C, C++, and FORTRAN. 
     4 * 
     5 * Copyright (C) 2003-2009 Massachusetts Institute of Technology  
     6 * Copyright (C) 2002 Michael S. Noble <mnoble@space.mit.edu> 
     7 * 
     8 * SLIRP is free software, and may be used under the conditions stipulated 
     9 * in the COPYRIGHT agreement bundled within the SLIRP distribution. 
     10 */ 
     11#include <stdlib.h>             /* SLIRP common {{{ */ 
     12#include <unistd.h> 
     13#include <string.h> 
     14#include <stdarg.h> 
     15#include <ctype.h> 
     16#include <slang.h> 
     17 
     18#define SAFE_DEREF_OPAQUE(po)           (po == NULL ? NULL : po->instance) 
     19#define SAFE_DEREF_ARRAY(pa)            (pa == NULL ? NULL : pa->data) 
     20#define SLang_pop_array(x)              SLang_pop_array(x, 1) 
     21#define SLang_pop_string(x)             ( (SLang_peek_at_stack() == SLANG_NULL_TYPE && (SLdo_pop() || 1)) ? ((*x = NULL) || 1): SLang_pop_slstring(x)) 
     22#define SLang_push_size_t               SLang_push_ulong 
     23#define SLang_push_ptrdiff_t            SLang_push_long 
     24 
     25#define pop_defaultable(argno, kind, type, obj, value) \ 
     26   (SLang_Num_Function_Args >= argno ? SLang_pop_##kind ( (type*)&obj) : ((obj = value) || ( (void*)&obj > (void*)0) ) ) 
     27 
     28#ifdef __cplusplus 
     29#define LINKAGE "C" 
     30#else 
     31#define LINKAGE 
     32#endif 
     33 
     34#define USAGE(msg) \ 
     35    {SLang_verror(SL_USAGE_ERROR, (char*)"Usage: %s", msg); return;} 
     36 
     37static void Slirp_usage(int i, int j, int flags); 
     38 
     39static int slang_abi_mismatch(void) 
     40{ 
     41   long module_abi = SLANG_VERSION / 10000; 
     42   long app_abi    = SLang_Version / 10000; 
     43 
     44   if (module_abi != app_abi) { 
     45        SLang_verror(SL_APPLICATION_ERROR, (char*) 
     46                "S-Lang library abi mismatch\nmodule: %s, application: %s", 
     47                SLANG_VERSION_STRING, SLang_Version_String); 
     48        return 1; 
     49   } 
     50                                 
     51   return 0; 
     52} /* }}} */ 
     53 
     54static char *slns;  /* slang namespace active at time of module load */ 
     55#include "slang_api_functions.h" 
     56#define BEGIN_DECLS 
     57#define END_DECLS 
     58static unsigned char map_scalars_to_refs = 0; 
     59 
     60typedef struct _Slirp_Ref {                     /* Ref handling code {{{ */ 
     61#define REF_FLAG_FREE_DATA                      0x01 
     62#define REF_FLAG_IS_OPAQUE                      0x02 
     63#define REF_FLAG_COLUMN_MAJOR                   0x04 
     64#define REF_FLAG_ARRAY_EXPECTED                 0x08 
     65   unsigned int         flags;          /* Slirp_Ref encapsulates S-Lang    */ 
     66   SLtype               sltype;         /* array, ref, and MMT types, the   */ 
     67   size_t               sizeof_type;    /* latter two of which are seen as  */ 
     68   void                 **data;         /* pointing to a single object      */ 
     69   unsigned int         vstride;        /* how to find "next" vectored elem */ 
     70   SLang_Array_Type     *array; 
     71   SLang_Ref_Type       *ref; 
     72   SLang_MMT_Type       *mmt;           /* mmt supports passing around C    */ 
     73} Slirp_Ref;                            /* ptr arrays of indeterminate size */ 
     74 
     75static Slirp_Ref* ref_new(SLtype t,size_t typesize, void *d,unsigned int flags) 
     76{ 
     77   Slirp_Ref *ref; 
     78   if ((ref = (Slirp_Ref*)SLcalloc( sizeof(Slirp_Ref), 1)) != NULL) { 
     79        ref->sltype = t; 
     80        ref->sizeof_type = typesize; 
     81        ref->flags = flags; 
     82        ref->data = (void**)d; 
     83        *ref->data = NULL; 
     84   } 
     85   return ref; 
     86} 
     87 
     88static int ref_finalize(Slirp_Ref *r) /* {{{ */ 
     89{ 
     90   int status = 0; 
     91   if (r == NULL) return 0; 
     92 
     93   if (r->ref) { 
     94 
     95        void *ref_value = NULL; SLtype ref_type = 0; double dc[2]; 
     96 
     97        if (r->flags & REF_FLAG_IS_OPAQUE) {    /* wrap aggregates/opaques  */ 
     98#ifdef NUM_RESERVED_OPAQUES                     /* in mmt before ref assign */ 
     99           void *opaqval = *r->data;            /* the mmt w/be freed when  */ 
     100           if (opaqval == NULL) {               /* the S-Lang object goes   */ 
     101                ref_value = NULL;               /* out of scope             */ 
     102                ref_type = SLANG_NULL_TYPE; 
     103           } 
     104           else { 
     105                SLang_MMT_Type *mmt = create_opaque_mmt(r->sltype, opaqval, 0); 
     106                ref_value = &mmt; 
     107                ref_type = r->sltype; 
     108           } 
     109#endif 
     110        } 
     111        else { 
     112           ref_type = r->sltype; 
     113           if (ref_type == SLANG_COMPLEX_TYPE && r->sizeof_type < sizeof(dc)) { 
     114                float *fc = (float*) r->data; 
     115                dc[0] = fc[0]; 
     116                dc[1] = fc[1]; 
     117                ref_value = dc; 
     118           } 
     119           else 
     120                ref_value = r->data; 
     121        } 
     122 
     123        status = SLang_assign_to_ref (r->ref, ref_type, ref_value); 
     124        SLang_free_ref(r->ref); 
     125   } 
     126   else if (r->array) { 
     127#ifdef HAVE_FORTRAN_CODE 
     128        if ((r->flags & REF_FLAG_COLUMN_MAJOR) && TRANSPOSE(1,r->array) == -1) 
     129                return -1; 
     130#endif 
     131        SLang_free_array(r->array); 
     132   } 
     133   else if (r->mmt) 
     134        SLang_free_mmt(r->mmt); 
     135 
     136   if (r->flags & REF_FLAG_FREE_DATA) 
     137        SLfree( (char*) r->data ); 
     138 
     139   SLfree((char*)r); 
     140   return status; 
     141} /* }}} */ 
     142 
     143static void finalize_refs(unsigned int nargs, ...) /* {{{ */ 
     144{ 
     145   va_list ap; 
     146   va_start(ap, nargs); 
     147   while (nargs--) ref_finalize(va_arg(ap, Slirp_Ref *)); 
     148   va_end(ap); 
     149} /* }}} */ 
     150 
     151static unsigned int ref_get_size(Slirp_Ref *r, int which_dimension) /* {{{ */ 
     152{ 
     153   if (r->array) { 
     154        if (which_dimension == 0) 
     155           return (unsigned int)r->array->num_elements; 
     156        else if (which_dimension < 0) 
     157           return r->array->num_dims; 
     158        else { 
     159           which_dimension--; 
     160           if ((unsigned int)which_dimension < r->array->num_dims) 
     161                return (unsigned int)r->array->dims[which_dimension]; 
     162           else 
     163                return 0; 
     164        } 
     165   } 
     166 
     167   return 1; 
     168} /* }}} */ 
     169 
     170extern LINKAGE int _SLang_get_class_type (SLtype t);    /* quasi-public  */ 
     171 
     172#ifdef NUM_RESERVED_OPAQUES 
     173static SLtype sltype_to_opaque_ptr_type(SLtype sltype) /*{{{*/ 
     174{ 
     175   Reserved_Opaque_Type *pt; 
     176 
     177   if (sltype > Last_Reserved_Opaque_Type) return opaque_ptr_Type; 
     178   if (sltype == void_ptr_Type) return void_ptr_Type; 
     179 
     180   pt = Reserved_Opaque_Types;          /* sequential search, but s/b < O(n) */ 
     181   while (pt->name) {                   /* since list is ordered by expected */ 
     182        if (pt->masked_type == sltype)  /* frequency of use for each SLtype  */ 
     183           return *pt->type;             
     184        pt++; 
     185   } 
     186   return 0; 
     187} /*}}}*/ 
     188#endif 
     189 
     190static int try_pop_mmt(SLtype type, SLang_MMT_Type **mmt) /*{{{*/ 
     191{ 
     192   static SLang_Name_Type *cl_type_func;        /* SLang_pop_mmt doesn't */ 
     193   int classtype;                               /* validate that type is */ 
     194                                                /* an MMT, so we do here */ 
     195   *mmt = NULL;                                 /* FIXME: remove v2.0.7  */ 
     196 
     197   if (cl_type_func == NULL) 
     198        cl_type_func = SLang_get_function( (char*) "__class_type"); 
     199 
     200   if (cl_type_func == NULL) 
     201      return 0; 
     202 
     203   if (-1 == SLang_push_datatype(type) ||               /* do the hard way, */ 
     204        -1 == SLexecute_function(cl_type_func) ||       /* as C api lacks   */ 
     205        -1 == SLang_pop_int(&classtype))                /* get_class_type() */ 
     206        return -1; 
     207 
     208   if (classtype == SLANG_CLASS_TYPE_MMT) { 
     209        *mmt = SLang_pop_mmt(type); 
     210        return 1; 
     211   } 
     212   return 0; 
     213} /*}}}*/ 
     214 
     215#define POP_FLAG_NULLABLE       0x1 
     216#define POP_FLAG_VECTORIZE      0x2 
     217static int pop_array_or_ref(Slirp_Ref *r, int flags, int defaultable) /*{{{*/ 
     218{ 
     219   SLtype type; 
     220   unsigned int i, objtype; 
     221#ifdef NUM_RESERVED_OPAQUES 
     222   unsigned int is_opaque; 
     223#endif 
     224 
     225   if (r == NULL) { 
     226        SLang_verror(SL_INTRINSIC_ERROR, (char*)"Attempted NULL reference (out of memory?)"); 
     227        return -1; 
     228   } 
     229 
     230   if (defaultable && SLang_Num_Function_Args < defaultable) { 
     231        r->ref   = NULL;        /* observe that only NULL can be */ 
     232        *r->data = NULL;        /* assigned as the default value */ 
     233        return 0; 
     234   } 
     235    
     236   objtype = SLang_peek_at_stack(); 
     237 
     238   if ((flags & POP_FLAG_NULLABLE) && objtype == SLANG_NULL_TYPE) { 
     239        r->ref   = NULL;                /* nullable flag: a pointer arg for */ 
     240        *r->data = NULL;                /* which NULL is a legitimate value */ 
     241        return SLang_pop_null (); 
     242   } 
     243 
     244   type = r->sltype; 
     245 
     246#ifdef NUM_RESERVED_OPAQUES 
     247   is_opaque =(type >= First_Opaque_Type && sltype_to_slirp_type(type) != NULL); 
     248   if (is_opaque) r->flags |= REF_FLAG_IS_OPAQUE; 
     249#endif 
     250 
     251   switch(objtype) { 
     252 
     253        case SLANG_ARRAY_TYPE: 
     254 
     255           if (SLang_pop_array_of_type(&r->array, type) == -1) 
     256                return -1; 
     257 
     258#ifdef HAVE_FORTRAN_CODE 
     259           if (r->flags & REF_FLAG_COLUMN_MAJOR) { 
     260                if (flags & POP_FLAG_VECTORIZE)         /* vectorizable arrs*/ 
     261                   r->flags ^= REF_FLAG_COLUMN_MAJOR;   /* r not transposed */ 
     262                else if (TRANSPOSE(0,r->array) == -1) 
     263                   return -1; 
     264           } 
     265#endif 
     266 
     267           i = r->array->num_elements; 
     268#ifdef NUM_RESERVED_OPAQUES 
     269           if (is_opaque) { 
     270                Slirp_Opaque *ot; 
     271                SLang_MMT_Type** mmts = (SLang_MMT_Type**)r->array->data; 
     272                void **arr = (void**)SLmalloc(i * sizeof(void*) ); 
     273                if (arr == NULL) return -1; 
     274 
     275                while (i--) { 
     276                   ot = (Slirp_Opaque*) SLang_object_from_mmt (mmts[i]); 
     277                   if (ot == NULL) { 
     278                        SLfree((char*)arr); 
     279                        return -1; 
     280                   } 
     281                   arr[i] = ot->instance; 
     282                } 
     283 
     284                *r->data = (void*)arr; r->data = (void**)arr; 
     285                r->flags |= REF_FLAG_FREE_DATA; 
     286           } 
     287           else 
     288#endif 
     289           if (type == SLANG_COMPLEX_TYPE && 
     290                                r->sizeof_type < r->array->sizeof_type) { 
     291                double *dc = (double*) r->array->data; 
     292                float  *fc = (float *) SLmalloc(i * r->sizeof_type); 
     293                if (fc == NULL) return -1; 
     294                *r->data = fc; r->data = (void**)fc; 
     295                while (i--) { *fc++ = (float) *dc++; *fc++ = (float) *dc++; } 
     296                r->flags |= REF_FLAG_FREE_DATA; 
     297           } 
     298           else { 
     299                *r->data = r->array->data; 
     300                r->data = (void**)*r->data; 
     301           } 
     302 
     303           break; 
     304 
     305        case SLANG_REF_TYPE: 
     306 
     307           /* Refs can only send values one-way (C to S-Lang, not reverse) */ 
     308           if (SLang_pop_ref(&r->ref) == -1) 
     309                return -1; 
     310 
     311           /* Ref is assumed to point to a scalar instance of the  */ 
     312           /* refd type, so declare enough space to hold one such. */ 
     313           *r->data = (void*)SLmalloc(r->sizeof_type); 
     314           if (*r->data == NULL) return -1; 
     315           memset(*r->data, 0, r->sizeof_type); 
     316           r->flags |= REF_FLAG_FREE_DATA; 
     317           r->data = (void**)*r->data; 
     318           break; 
     319 
     320        /* Allow scalars to used as if they were 1-element arrays */ 
     321        case SLANG_CHAR_TYPE: case SLANG_UCHAR_TYPE: 
     322        case SLANG_SHORT_TYPE: case SLANG_USHORT_TYPE: 
     323        case SLANG_INT_TYPE: case SLANG_UINT_TYPE: 
     324        case SLANG_LONG_TYPE: case SLANG_ULONG_TYPE: 
     325        case SLANG_FLOAT_TYPE: case SLANG_DOUBLE_TYPE: 
     326        case SLANG_COMPLEX_TYPE: case SLANG_STRING_TYPE: 
     327 
     328           /* Accomodate FORTRAN-style pass by reference semantics */ 
     329           if (map_scalars_to_refs && 
     330                        SLang_pop_array_of_type(&r->array,type) == 0) { 
     331 
     332                *r->data = (void*)SLmalloc(r->sizeof_type); 
     333                if (*r->data == NULL) return -1; 
     334 
     335                if (r->sizeof_type == r->array->sizeof_type) 
     336                   memcpy(*r->data, r->array->data, r->sizeof_type); 
     337                else if (type == SLANG_COMPLEX_TYPE) { 
     338                   double *dc = (double*) r->array->data; 
     339                   float  *fc = (float*) *r->data; 
     340                   fc[0] = (float)dc[0]; 
     341                   fc[1] = (float)dc[1]; 
     342                } 
     343                else  { 
     344                   SLang_verror(SL_TYPE_MISMATCH, (char*) 
     345                        "mismatched type sizes, when popping scalar as ref"); 
     346                   SLang_free_array(r->array); 
     347                   return -1; 
     348                } 
     349 
     350                r->data = (void**)*r->data; 
     351                r->flags |= REF_FLAG_FREE_DATA; 
     352                /* Nullify to distinguish between vectored/non-vectored args */ 
     353                SLang_free_array(r->array); r->array = NULL; 
     354                break; 
     355           }                            /* intentional fallthrough */ 
     356 
     357        default: 
     358 
     359#ifdef NUM_RESERVED_OPAQUES 
     360           if (objtype >= First_Opaque_Type &&  
     361                                sltype_to_slirp_type(objtype) != NULL) { 
     362 
     363                if (!(flags & POP_FLAG_VECTORIZE)) 
     364                   type = sltype_to_opaque_ptr_type(type); 
     365 
     366                if (type) { 
     367 
     368                   Slirp_Opaque *otp; 
     369                   if (SLang_pop_opaque(type, NULL, &otp) == -1) 
     370                        return -1; 
     371                 
     372                   if (flags & POP_FLAG_VECTORIZE) { 
     373                        void **arr = (void**) SLmalloc(sizeof(void*)); 
     374                        if (arr == NULL) return -1; 
     375                        arr[0] = otp->instance; 
     376                        *r->data = arr; 
     377                        r->flags |= REF_FLAG_FREE_DATA; 
     378                   } 
     379                   else 
     380                        *r->data = otp->instance; 
     381 
     382                   r->data = (void**)*r->data; 
     383                   r->mmt = otp->mmt; 
     384                   return 0; 
     385                } 
     386           } 
     387           else 
     388#endif 
     389           if ( try_pop_mmt(objtype, &r->mmt) == 1 && 
     390                (*r->data = SLang_object_from_mmt (r->mmt)) != NULL) { 
     391                   r->data = (void**)*r->data;   /* not flagged for freeing */ 
     392                   return 0; 
     393           } 
     394 
     395           SLang_verror(SL_TYPE_MISMATCH, (char*) 
     396                        "context requires array, ref, or opaque pointer"); 
     397           return -1; 
     398   } 
     399   return 0; 
     400} /*}}}*/ 
     401/* }}} */ 
     402 
     403/* Wrapper functions */ /* {{{ */ 
     404static void sl_set_action_hook (void) 
     405{ 
     406   int retval; 
     407   char* arg1; 
     408   char* arg2; 
     409   char* arg3; 
     410   int issue_usage = 1; 
     411 
     412   if (SLang_Num_Function_Args != 3) goto usage_label; 
     413   if (-1 == SLang_pop_string((char**)&arg3)) goto usage_label; 
     414   if (-1 == SLang_pop_string((char**)&arg2)) goto free_and_return_3; 
     415   if (-1 == SLang_pop_string((char**)&arg1)) goto free_and_return_2; 
     416   issue_usage = 0; 
     417 
     418   retval = slang_api__set_action_hook(arg1, arg2, arg3); 
     419   (void)SLang_push_int(retval); 
     420   goto free_and_return; 
     421free_and_return: 
     422   /* drop */ 
     423   SLang_free_slstring(arg1); 
     424free_and_return_2: 
     425   SLang_free_slstring(arg2); 
     426free_and_return_3: 
     427   SLang_free_slstring(arg3); 
     428usage_label: 
     429   if (issue_usage) Slirp_usage (0, 0, 0); 
     430} 
     431 
     432static void sl_cure_backspace (void) 
     433{ 
     434   int retval; 
     435   int issue_usage = 1; 
     436 
     437   if (SLang_Num_Function_Args != 0) goto usage_label; 
     438   issue_usage = 0; 
     439 
     440   retval = slang_api__cure_backspace(); 
     441   (void)SLang_push_int(retval); 
     442   goto free_and_return; 
     443free_and_return: 
     444   /* drop */ 
     445usage_label: 
     446   if (issue_usage) Slirp_usage (1, 1, 0); 
     447} 
     448 
     449static void sl_add_new_action (void) 
     450{ 
     451   int retval; 
     452   char* arg1; 
     453   int arg2; 
     454   int issue_usage = 1; 
     455 
     456   if (SLang_Num_Function_Args != 2) goto usage_label; 
     457   if (-1 == SLang_pop_int((int*)&arg2)) goto usage_label; 
     458   if (-1 == SLang_pop_string((char**)&arg1)) goto usage_label; 
     459   issue_usage = 0; 
     460 
     461   retval = keybind_add_new_action(arg1,  arg2); 
     462   (void)SLang_push_int(retval); 
     463   goto free_and_return; 
     464free_and_return: 
     465   /* drop */ 
     466   SLang_free_slstring(arg1); 
     467usage_label: 
     468   if (issue_usage) Slirp_usage (2, 2, 0); 
     469} 
     470 
     471static void sl_editor_map_key_to_func (void) 
     472{ 
     473   int retval; 
     474   char* arg1; 
     475   char* arg2; 
     476   char* arg3; 
     477   int issue_usage = 1; 
     478 
     479   if (SLang_Num_Function_Args != 3) goto usage_label; 
     480   if (-1 == SLang_pop_string((char**)&arg3)) goto usage_label; 
     481   if (-1 == SLang_pop_string((char**)&arg2)) goto free_and_return_3; 
     482   if (-1 == SLang_pop_string((char**)&arg1)) goto free_and_return_2; 
     483   issue_usage = 0; 
     484 
     485   retval = slang_api__editor_map_key_to_func(arg1, arg2, arg3); 
     486   (void)SLang_push_int(retval); 
     487   goto free_and_return; 
     488free_and_return: 
     489   /* drop */ 
     490   SLang_free_slstring(arg1); 
     491free_and_return_2: 
     492   SLang_free_slstring(arg2); 
     493free_and_return_3: 
     494   SLang_free_slstring(arg3); 
     495usage_label: 
     496   if (issue_usage) Slirp_usage (3, 3, 0); 
     497} 
     498 
     499static void sl_editor_map_key_to_action (void) 
     500{ 
     501   int retval; 
     502   char* arg1; 
     503   char* arg2; 
     504   int issue_usage = 1; 
     505 
     506   if (SLang_Num_Function_Args != 2) goto usage_label; 
     507   if (-1 == SLang_pop_string((char**)&arg2)) goto usage_label; 
     508   if (-1 == SLang_pop_string((char**)&arg1)) goto free_and_return_2; 
     509   issue_usage = 0; 
     510 
     511   retval = slang_api__editor_map_key_to_action(arg1, arg2); 
     512   (void)SLang_push_int(retval); 
     513   goto free_and_return; 
     514free_and_return: 
     515   /* drop */ 
     516   SLang_free_slstring(arg1); 
     517free_and_return_2: 
     518   SLang_free_slstring(arg2); 
     519usage_label: 
     520   if (issue_usage) Slirp_usage (4, 4, 0); 
     521} 
     522 
     523static void sl_cure_get_eol (void) 
     524{ 
     525   int retval; 
     526   int issue_usage = 1; 
     527 
     528   if (SLang_Num_Function_Args != 0) goto usage_label; 
     529   issue_usage = 0; 
     530 
     531   retval = slang_api__cure_get_eol(); 
     532   (void)SLang_push_int(retval); 
     533   goto free_and_return; 
     534free_and_return: 
     535   /* drop */ 
     536usage_label: 
     537   if (issue_usage) Slirp_usage (5, 5, 0); 
     538} 
     539 
     540static void sl_cure_get_bol (void) 
     541{ 
     542   int retval; 
     543   int issue_usage = 1; 
     544 
     545   if (SLang_Num_Function_Args != 0) goto usage_label; 
     546   issue_usage = 0; 
     547 
     548   retval = slang_api__cure_get_bol(); 
     549   (void)SLang_push_int(retval); 
     550   goto free_and_return; 
     551free_and_return: 
     552   /* drop */ 
     553usage_label: 
     554   if (issue_usage) Slirp_usage (6, 6, 0); 
     555} 
     556 
     557static void sl_cure_delete (void) 
     558{ 
     559   int retval; 
     560   int issue_usage = 1; 
     561 
     562   if (SLang_Num_Function_Args != 0) goto usage_label; 
     563   issue_usage = 0; 
     564 
     565   retval = slang_api__cure_delete(); 
     566   (void)SLang_push_int(retval); 
     567   goto free_and_return; 
     568free_and_return: 
     569   /* drop */ 
     570usage_label: 
     571   if (issue_usage) Slirp_usage (7, 7, 0); 
     572} 
     573 
     574static void sl_cure_cursor_move (void) 
     575{ 
     576   int arg1; 
     577   int issue_usage = 1; 
     578 
     579   if (SLang_Num_Function_Args != 1) goto usage_label; 
     580   if (-1 == SLang_pop_int((int*)&arg1)) goto usage_label; 
     581   issue_usage = 0; 
     582 
     583   slang_api__cure_cursor_move( arg1); 
     584   goto free_and_return; 
     585free_and_return: 
     586   /* drop */ 
     587usage_label: 
     588   if (issue_usage) Slirp_usage (8, 8, 0); 
     589} 
     590 
     591static void sl_cure_cursor_offset (void) 
     592{ 
     593   int retval; 
     594   int issue_usage = 1; 
     595 
     596   if (SLang_Num_Function_Args != 0) goto usage_label; 
     597   issue_usage = 0; 
     598 
     599   retval = slang_api__cure_cursor_offset(); 
     600   (void)SLang_push_int(retval); 
     601   goto free_and_return; 
     602free_and_return: 
     603   /* drop */ 
     604usage_label: 
     605   if (issue_usage) Slirp_usage (9, 9, 0); 
     606} 
     607 
     608static void sl_listbox_with_data (void) 
     609{ 
     610   char* retval; 
     611   int arg1; 
     612   int arg2; 
     613   char* arg3; 
     614   char** arg4; 
     615   Slirp_Ref *arg4_r = ref_new(SLANG_STRING_TYPE,sizeof(char*),&arg4,0x0); 
     616   unsigned long arg5; 
     617   char** arg6; 
     618   Slirp_Ref *arg6_r = ref_new(SLANG_STRING_TYPE,sizeof(char*),&arg6,0x0); 
     619   unsigned long arg7; 
     620   int issue_usage = 1; 
     621 
     622   if (SLang_Num_Function_Args != 5) goto usage_label; 
     623   if (-1 == pop_array_or_ref( arg6_r, 0x0, 0)) goto usage_label; 
     624   if (-1 == pop_array_or_ref( arg4_r, 0x0, 0)) goto usage_label; 
     625   if (-1 == SLang_pop_string((char**)&arg3)) goto usage_label; 
     626   if (-1 == SLang_pop_int((int*)&arg2)) goto free_and_return_3; 
     627   if (-1 == SLang_pop_int((int*)&arg1)) goto free_and_return_3; 
     628   issue_usage = 0; 
     629 
     630   arg5 = (unsigned long) ref_get_size(arg4_r, 1); 
     631   arg7 = (unsigned long) ref_get_size(arg6_r, 1); 
     632   retval = slang_api__listbox_with_data( arg1,  arg2, arg3, arg4,  arg5, arg6,  arg7); 
     633   (void)SLang_push_malloced_string(retval); 
     634   goto free_and_return; 
     635free_and_return: 
     636   /* drop */ 
     637free_and_return_3: 
     638   SLang_free_slstring(arg3); 
     639usage_label: 
     640   if (issue_usage) Slirp_usage (10, 10, 0); 
     641   finalize_refs(2,arg4_r,arg6_r);  
     642} 
     643 
     644static void sl_cure_get_left_whole_word (void) 
     645{ 
     646   char* retval; 
     647   int arg1; 
     648   int issue_usage = 1; 
     649 
     650   if (SLang_Num_Function_Args != 1) goto usage_label; 
     651   if (-1 == SLang_pop_int((int*)&arg1)) goto usage_label; 
     652   issue_usage = 0; 
     653 
     654   retval = slang_api__cure_get_left_whole_word( arg1); 
     655   (void)SLang_push_malloced_string(retval); 
     656   goto free_and_return; 
     657free_and_return: 
     658   /* drop */ 
     659usage_label: 
     660   if (issue_usage) Slirp_usage (11, 11, 0); 
     661} 
     662 
     663static void sl_listbox (void) 
     664{ 
     665   int retval; 
     666   int arg1; 
     667   int arg2; 
     668   char* arg3; 
     669   char** arg4; 
     670   Slirp_Ref *arg4_r = ref_new(SLANG_STRING_TYPE,sizeof(char*),&arg4,0x0); 
     671   unsigned long arg5; 
     672   int issue_usage = 1; 
     673 
     674   if (SLang_Num_Function_Args != 4) goto usage_label; 
     675   if (-1 == pop_array_or_ref( arg4_r, 0x0, 0)) goto usage_label; 
     676   if (-1 == SLang_pop_string((char**)&arg3)) goto usage_label; 
     677   if (-1 == SLang_pop_int((int*)&arg2)) goto free_and_return_3; 
     678   if (-1 == SLang_pop_int((int*)&arg1)) goto free_and_return_3; 
     679   issue_usage = 0; 
     680 
     681   arg5 = (unsigned long) ref_get_size(arg4_r, 1); 
     682   retval = slang_api__listbox( arg1,  arg2, arg3, arg4,  arg5); 
     683   (void)SLang_push_int(retval); 
     684   goto free_and_return; 
     685free_and_return: 
     686   /* drop */ 
     687free_and_return_3: 
     688   SLang_free_slstring(arg3); 
     689usage_label: 
     690   if (issue_usage) Slirp_usage (12, 12, 0); 
     691   finalize_refs(1,arg4_r);  
     692} 
     693 
     694static void sl_message (void) 
     695{ 
     696   char* arg1; 
     697   char* arg2; 
     698   int issue_usage = 1; 
     699 
     700   if (SLang_Num_Function_Args != 2) goto usage_label; 
     701   if (-1 == SLang_pop_string((char**)&arg2)) goto usage_label; 
     702   if (-1 == SLang_pop_string((char**)&arg1)) goto free_and_return_2; 
     703   issue_usage = 0; 
     704 
     705   slang_api__message(arg1, arg2); 
     706   goto free_and_return; 
     707free_and_return: 
     708   /* drop */ 
     709   SLang_free_slstring(arg1); 
     710free_and_return_2: 
     711   SLang_free_slstring(arg2); 
     712usage_label: 
     713   if (issue_usage) Slirp_usage (13, 13, 0); 
     714} 
     715 
     716static void sl_listbox_auto (void) 
     717{ 
     718   int retval; 
     719   char* arg1; 
     720   char** arg2; 
     721   Slirp_Ref *arg2_r = ref_new(SLANG_STRING_TYPE,sizeof(char*),&arg2,0x0); 
     722   unsigned long arg3; 
     723   int issue_usage = 1; 
     724 
     725   if (SLang_Num_Function_Args != 2) goto usage_label; 
     726   if (-1 == pop_array_or_ref( arg2_r, 0x0, 0)) goto usage_label; 
     727   if (-1 == SLang_pop_string((char**)&arg1)) goto usage_label; 
     728   issue_usage = 0; 
     729 
     730   arg3 = (unsigned long) ref_get_size(arg2_r, 1); 
     731   retval = slang_api__listbox_auto(arg1, arg2,  arg3); 
     732   (void)SLang_push_int(retval); 
     733   goto free_and_return; 
     734free_and_return: 
     735   /* drop */ 
     736   SLang_free_slstring(arg1); 
     737usage_label: 
     738   if (issue_usage) Slirp_usage (14, 14, 0); 
     739   finalize_refs(1,arg2_r);  
     740} 
     741 
     742static void sl_cure_get_byte (void) 
     743{ 
     744   int retval; 
     745   int arg1; 
     746   int issue_usage = 1; 
     747 
     748   if (SLang_Num_Function_Args != 1) goto usage_label; 
     749   if (-1 == SLang_pop_int((int*)&arg1)) goto usage_label; 
     750   issue_usage = 0; 
     751 
     752   retval = slang_api__cure_get_byte( arg1); 
     753   (void)SLang_push_int(retval); 
     754   goto free_and_return; 
     755free_and_return: 
     756   /* drop */ 
     757usage_label: 
     758   if (issue_usage) Slirp_usage (15, 15, 0); 
     759} 
     760 
     761static void sl_cure_insert_ahead (void) 
     762{ 
     763   int arg1; 
     764   int issue_usage = 1; 
     765 
     766   if (SLang_Num_Function_Args != 1) goto usage_label; 
     767   if (-1 == SLang_pop_int((int*)&arg1)) goto usage_label; 
     768   issue_usage = 0; 
     769 
     770   slang_api__cure_insert_ahead( arg1); 
     771   goto free_and_return; 
     772free_and_return: 
     773   /* drop */ 
     774usage_label: 
     775   if (issue_usage) Slirp_usage (16, 16, 0); 
     776} 
     777 
     778 
     779static SLang_Intrin_Fun_Type slang_api_functions_Funcs [] = 
     780{ 
     781   MAKE_INTRINSIC_0((char*)"set_action_hook",sl_set_action_hook,SLANG_VOID_TYPE), 
     782   MAKE_INTRINSIC_0((char*)"cure_backspace",sl_cure_backspace,SLANG_VOID_TYPE), 
     783   MAKE_INTRINSIC_0((char*)"add_new_action",sl_add_new_action,SLANG_VOID_TYPE), 
     784   MAKE_INTRINSIC_0((char*)"editor_map_key_to_func",sl_editor_map_key_to_func,SLANG_VOID_TYPE), 
     785   MAKE_INTRINSIC_0((char*)"editor_map_key_to_action",sl_editor_map_key_to_action,SLANG_VOID_TYPE), 
     786   MAKE_INTRINSIC_0((char*)"cure_get_eol",sl_cure_get_eol,SLANG_VOID_TYPE), 
     787   MAKE_INTRINSIC_0((char*)"cure_get_bol",sl_cure_get_bol,SLANG_VOID_TYPE), 
     788   MAKE_INTRINSIC_0((char*)"cure_delete",sl_cure_delete,SLANG_VOID_TYPE), 
     789   MAKE_INTRINSIC_0((char*)"cure_cursor_move",sl_cure_cursor_move,SLANG_VOID_TYPE), 
     790   MAKE_INTRINSIC_0((char*)"cure_cursor_offset",sl_cure_cursor_offset,SLANG_VOID_TYPE), 
     791   MAKE_INTRINSIC_0((char*)"listbox_with_data",sl_listbox_with_data,SLANG_VOID_TYPE), 
     792   MAKE_INTRINSIC_0((char*)"cure_get_left_whole_word",sl_cure_get_left_whole_word,SLANG_VOID_TYPE), 
     793   MAKE_INTRINSIC_0((char*)"listbox",sl_listbox,SLANG_VOID_TYPE), 
     794   MAKE_INTRINSIC_0((char*)"message",sl_message,SLANG_VOID_TYPE), 
     795   MAKE_INTRINSIC_0((char*)"listbox_auto",sl_listbox_auto,SLANG_VOID_TYPE), 
     796   MAKE_INTRINSIC_0((char*)"cure_get_byte",sl_cure_get_byte,SLANG_VOID_TYPE), 
     797   MAKE_INTRINSIC_0((char*)"cure_insert_ahead",sl_cure_insert_ahead,SLANG_VOID_TYPE), 
     798   SLANG_END_INTRIN_FUN_TABLE 
     799};   /* }}} */ 
     800 
     801static const char* usage_strings[] = { /* {{{ */ 
     802   "int = set_action_hook(string,string,string)", 
     803   "int = cure_backspace()", 
     804   "int = add_new_action(string,int)", 
     805   "int = editor_map_key_to_func(string,string,string)", 
     806   "int = editor_map_key_to_action(string,string)", 
     807   "int = cure_get_eol()", 
     808   "int = cure_get_bol()", 
     809   "int = cure_delete()", 
     810   "cure_cursor_move(int)", 
     811   "int = cure_cursor_offset()", 
     812   "string = listbox_with_data(int,int,string,string[],string[])", 
     813   "string = cure_get_left_whole_word(int)", 
     814   "int = listbox(int,int,string,string[])", 
     815   "message(string,string)", 
     816   "int = listbox_auto(string,string[])", 
     817   "int = cure_get_byte(int)", 
     818   "cure_insert_ahead(int)", 
     819NULL 
     820}; /* }}} */ 
     821 
     822static void Slirp_usage(int i, int last, int flags) /* {{{ */ 
     823{ 
     824   char *indent; 
     825   int npop = SLstack_depth(); 
     826   if (npop > SLang_Num_Function_Args) npop = SLang_Num_Function_Args; 
     827   SLdo_pop_n(npop); 
     828   if (last == i) 
     829        indent = (char*)"Usage:  "; 
     830   else { 
     831        indent = (char*)"\t"; 
     832        SLang_verror(SL_USAGE_ERROR, (char*)"Usage: one of"); 
     833   } 
     834   do 
     835        SLang_verror(SL_USAGE_ERROR, (char*)"%s%s", indent, usage_strings[i++]); 
     836   while (i < last); 
     837   if (flags & 0x2) 
     838        SLang_verror(SL_USAGE_ERROR, 
     839                (char*)"\tThis function has been vectorized and parallelized."); 
     840   else if (flags & 0x1) 
     841        SLang_verror(SL_USAGE_ERROR, (char*)"\tThis function has been vectorized."); 
     842} /* }}} */ 
     843 
     844#define SLIRP_VERSION_STRING pre2.0.0-34 
     845#define SLIRP_VERSION_NUMBER 20000 
     846SLANG_MODULE(slang_api_functions); 
     847int init_slang_api_functions_module_ns(char *ns_name)   /* {{{ */ 
     848{ 
     849   SLang_NameSpace_Type *ns = NULL; 
     850 
     851   if (slang_abi_mismatch()) return -1; 
     852   if (ns_name != NULL) { 
     853        ns = SLns_create_namespace (ns_name); 
     854       if (ns == NULL || 
     855          (slns = SLmalloc(strlen(ns_name)+1)) == NULL) 
     856          return -1; 
     857       strcpy(slns, ns_name); 
     858   } 
     859 
     860 
     861#ifdef HAVE_OPAQUE_IVARS 
     862   if (-1 == set_opaque_ivar_types(slang_api_functions_Opaque_IVars) || 
     863       -1 == SLns_add_intrin_var_table(ns,slang_api_functions_Opaque_IVars,NULL)) 
     864        return -1; 
     865#endif 
     866 
     867   if ( -1 == SLns_add_intrin_fun_table (ns,slang_api_functions_Funcs,(char*)"__slang_api_functions__")) 
     868        return -1; 
     869 
     870   return 0; 
     871} /* }}} */ 
  • new file src/slang_engine.c

    diff --git a/src/slang_engine.c b/src/slang_engine.c
    new file mode 100644
    index 000000000..7bb01730a
    - +  
     1/* 
     2   Implements S-Lang scripting for MC. 
     3 
     4   Copyright (C) 2021 
     5   Free Software Foundation, Inc. 
     6 
     7   Written by: 
     8   Sebastian Gniazdowski, 2021 
     9 
     10   This file is part of the Midnight Commander. 
     11 
     12   The Midnight Commander is free software: you can redistribute it 
     13   and/or modify it under the terms of the GNU General Public License as 
     14   published by the Free Software Foundation, either version 3 of the License, 
     15   or (at your option) any later version. 
     16 
     17   The Midnight Commander is distributed in the hope that it will be useful, 
     18   but WITHOUT ANY WARRANTY; without even the implied warranty of 
     19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     20   GNU General Public License for more details. 
     21 
     22   You should have received a copy of the GNU General Public License 
     23   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
     24 */ 
     25 
     26/** \file slang_engine.c 
     27 *  \brief Internals of the S-Lang scripting for MC 
     28 *  \author Sebastian Gniazdowski 
     29 *  \date 2021 
     30 * 
     31 *  Functions that initialize S-Lang interpreter, load init.sl initialization script, load all 
     32 *  plugins from the plugin directory, catch errors and display them in dialogs, etc. 
     33 */ 
     34 
     35#include <config.h> 
     36 
     37#include <slang.h> 
     38#include <ctype.h> 
     39 
     40#include "lib/global.h" 
     41 
     42#include "lib/fileloc.h" 
     43#include "lib/widget.h" 
     44#include "lib/widget/wtools.h" 
     45#include "lib/util.h" 
     46 
     47#include "src/slang_engine.h" 
     48#include "src/filemanager/dir.h" 
     49 
     50/*** global variables ****************************************************************************/ 
     51 
     52int num_action_hook_functions = 0; 
     53GHashTable *action_hook_functions = NULL; 
     54 
     55/*** file scope macro definitions ****************************************************************/ 
     56 
     57/*** file scope type declarations ****************************************************************/ 
     58 
     59/*** file scope variables ************************************************************************/ 
     60 
     61static int mc_loglevel = 0; 
     62static GString *last_error = NULL; 
     63static char *last_fname = NULL; 
     64 
     65/*** file scope functions ************************************************************************/ 
     66/* --------------------------------------------------------------------------------------------- */ 
     67 
     68static void 
     69slang_error_handler (char *error_msg) 
     70{ 
     71    if (!last_error) 
     72        last_error = g_string_sized_new (255); 
     73 
     74    /* Truncate previous message. */ 
     75    g_string_truncate (last_error, 0); 
     76    /* Append  error message (copying it) and a two new lines. */ 
     77    g_string_append (last_error, "Error in script:"); 
     78 
     79    /* Does message contain a file path? If so, append a newline, else a space. */ 
     80    if (strchr (error_msg, '/')) 
     81        g_string_append_c (last_error, '\n'); 
     82    else 
     83        g_string_append_c (last_error, ' '); 
     84 
     85    /* Append message. */ 
     86    g_string_append (last_error, error_msg); 
     87    g_string_append (last_error, "\n\n"); 
     88 
     89    /* Append a traceback header. */ 
     90    g_string_append (last_error, "Traceback:\n"); 
     91} 
     92 
     93/* --------------------------------------------------------------------------------------------- */ 
     94 
     95static void 
     96slang_dump_handler (char *traceback) 
     97{ 
     98    char *last_fragment_search_str, **tb_bits; 
     99 
     100    if (!last_error) 
     101        last_error = g_string_sized_new (255); 
     102 
     103    /* Split to check for `/path:<number>:other` pattern. If detected, add preceding new line. */ 
     104    tb_bits = g_strsplit (traceback, ":", 3); 
     105    if (strchr (tb_bits[0], '/') != NULL && tb_bits[1] && isdigit (tb_bits[1][0]) && tb_bits[2]) 
     106        g_string_append (last_error, "\n"); 
     107    g_strfreev (tb_bits); 
     108 
     109    /* Append traceback into error message buffer. */ 
     110    if (traceback) 
     111        g_string_append (last_error, traceback); 
     112 
     113    /*  Search string to detect last part of traceback (i.e.: if it's top function traceback). */ 
     114    last_fragment_search_str = g_strdup_printf (":%s:", last_fname ? last_fname : ""); 
     115 
     116    /* If it's final message, then schedule a message display with complete error buffer. */ 
     117    if (g_strstr_len (traceback, -1, last_fragment_search_str) != NULL || 
     118        g_strstr_len (traceback, -1, ":<top-level>:") != NULL) 
     119        postponed_message (D_ERROR, " S-Lang script error ", "%s", last_error->str); 
     120 
     121    g_free (last_fragment_search_str); 
     122} 
     123 
     124/* --------------------------------------------------------------------------------------------- */ 
     125 
     126static void 
     127slang_exit_hook_handler (char *fname) 
     128{ 
     129    /* g_free is NULL safe, no need to check. */ 
     130    g_free (last_fname); 
     131    last_fname = g_strdup (fname); 
     132} 
     133 
     134/* --------------------------------------------------------------------------------------------- */ 
     135/*** public functions ****************************************************************************/ 
     136/* --------------------------------------------------------------------------------------------- */ 
     137 
     138/* Slirp doesn't provide a header so the declaration is placed here to mute warning. */ 
     139int init_slang_api_functions_module_ns (char *ns_name); 
     140 
     141int 
     142slang_init_engine (void) 
     143{ 
     144    const char *slang_init_path; 
     145 
     146    /* Handler for the (generated first) basic error message. */ 
     147    SLang_Error_Hook = slang_error_handler; 
     148    /* Handler for the (generated second) detailed traceback message. */ 
     149    SLang_Dump_Routine = slang_dump_handler; 
     150    /* Used to detect the last fragment of a traceback. */ 
     151    SLang_Exit_Function = slang_exit_hook_handler; 
     152 
     153    /* Set traceback level - do a full traceback via the dump handler. */ 
     154    SLang_Traceback = SL_TB_FULL; 
     155 
     156    /* Create the hash table for hooks. */ 
     157    action_hook_functions = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); 
     158 
     159    /* Init S-Lang subsystems. */ 
     160    if (-1 == SLang_init_all ()) 
     161        return FALSE; 
     162 
     163    /* Add `mc_loglevel` variable that controls execution information messages. */ 
     164    if (-1 == SLadd_intrinsic_variable ((char *) "mc_loglevel", 
     165                                        (VOID_STAR) & mc_loglevel, SLANG_INT_TYPE, 0)) 
     166    { 
     167        postponed_message (D_ERROR, "MC Plugin Subsystem Error", "%s\n%s", 
     168                           "Couldn't add mc_loglevel to S-Lang interpreter.", 
     169                           "Something is very wrong."); 
     170    } 
     171 
     172    /* Init the `mc` namespace. */ 
     173    init_slang_api_functions_module_ns ((char *) "mc"); 
     174 
     175    /* Establish path to the init.sl file. */ 
     176    slang_init_path = 
     177        mc_build_filename (mc_global.sysconfig_dir, MC_SLANG_INIT_FILE, (char *) NULL); 
     178 
     179    /* Source `init.sl` into the S-Lang interpreter. */ 
     180    if (-1 == SLang_load_file ((char *) slang_init_path)) 
     181    { 
     182        /* Clear the error and reset the interpreter */ 
     183        SLang_restart (1); 
     184        SLang_set_error (0); 
     185        if (mc_loglevel >= 2) 
     186            postponed_message (D_ERROR, "MC Plugin Subsystem Error", 
     187                               "Couldn't load init.sl startup script."); 
     188    } 
     189    else 
     190    { 
     191        if (mc_loglevel >= 2) 
     192            postponed_message (D_NORMAL, "MC Plugin Subsystem", 
     193                               "Correctly loaded init.sl startup script."); 
     194    } 
     195    return 1; 
     196} 
     197 
     198/* --------------------------------------------------------------------------------------------- */ 
     199 
     200int 
     201slang_plugins_init (void) 
     202{ 
     203    int ret = TRUE,             /* Default is OK return value */ 
     204        i; 
     205    const char *plugin_dir_path; 
     206    dir_list dir; 
     207    vfs_path_t *path; 
     208    file_entry_t *ptr; 
     209    dir_sort_options_t sort_options = { 0, 1, 0 };      /* A case-sensitive sort */ 
     210 
     211    dir.size = DIR_LIST_MIN_SIZE; 
     212    dir.list = g_new (file_entry_t, DIR_LIST_MIN_SIZE); 
     213    dir.len = 0; 
     214    dir.callback = NULL; 
     215 
     216    /* Get the VFS path for the plugins directory. */ 
     217    plugin_dir_path = mc_config_get_full_path (MC_PLUGIN_DIR); 
     218    path = vfs_path_from_str (plugin_dir_path); 
     219 
     220    if (!dir_list_load (&dir, path, (GCompareFunc) strcmp, &sort_options, "*.sl")) 
     221    { 
     222        postponed_message (D_ERROR, "MC Plugin Subsystem", "Couldn't read the plugin folder."); 
     223        return FALSE; 
     224    } 
     225 
     226    for (i = 0, ptr = dir.list; i < dir.len; i++, ptr++) 
     227    { 
     228        char *pl_path; 
     229 
     230        if (DIR_IS_DOT (ptr->fname) || DIR_IS_DOTDOT (ptr->fname)) 
     231            continue; 
     232        /* Construct full path to the found plugin (a text file with an .sl extension) script. */ 
     233        pl_path = mc_build_filename (plugin_dir_path, ptr->fname, (char *) NULL); 
     234 
     235        if (!pl_path) 
     236            continue; 
     237 
     238        /* Load the script with the interpreter. */ 
     239        if (-1 == SLang_load_file ((char *) pl_path) || SLang_get_error ()) 
     240        { 
     241            /* Error occurred: clear the error and reset the interpreter. */ 
     242            SLang_restart (1); 
     243            SLang_set_error (0); 
     244 
     245            if (mc_loglevel >= 2) 
     246                postponed_message (D_ERROR, "MC Plugin Subsystem", "Couldn't load the plugin: %s", 
     247                                   pl_path); 
     248 
     249            ret = FALSE; 
     250        } 
     251        else 
     252        { 
     253 
     254            /* Report if the loglevel is 2 or more. */ 
     255            if (mc_loglevel >= 2) 
     256                postponed_message (D_NORMAL, "MC Plugin Subsystem", "Plugin: %s loaded correctly", 
     257                                   pl_path); 
     258        } 
     259        g_free (pl_path); 
     260    } 
     261 
     262    return ret; 
     263} 
     264 
     265/* --------------------------------------------------------------------------------------------- */ 
     266 
     267/* A function that looks up the command associated S-Lang code callback. */ 
     268GSList * 
     269get_command_callback (int ck_id) 
     270{ 
     271    GSList *value = g_hash_table_lookup (action_hook_functions, GINT_TO_POINTER (ck_id)); 
     272    return value; 
     273} 
     274 
     275/* --------------------------------------------------------------------------------------------- */ 
  • .h

    diff --git a/src/vfs/fish/fish.h b/src/slang_engine.h
    similarity index 72%
    copy from src/vfs/fish/fish.h
    copy to src/slang_engine.h
    index 5d834cbd2..d8c5ac474 100644
    old new  
    1  
    2 /** 
    3  * \file 
    4  * \brief Header: Virtual File System: FISH implementation for transfering files over 
    5  * shell connections 
    6  */ 
    7  
    8  
    9 #ifndef MC__VFS_FISH_H 
    10 #define MC__VFS_FISH_H 
     1#ifndef MC__SLANG_ENGINE_H 
     2#define MC__SLANG_ENGINE_H 
    113 
    124/*** typedefs(not structures) and defined constants **********************************************/ 
    135 
     
    179 
    1810/*** global variables defined in .c file *********************************************************/ 
    1911 
    20 extern int fish_directory_timeout; 
     12extern int num_action_hook_functions; 
     13extern GHashTable *action_hook_functions; 
    2114 
    2215/*** declarations of public functions ************************************************************/ 
    2316 
    24 void vfs_init_fish (void); 
     17int slang_init_engine (void); 
     18int slang_plugins_init (void); 
     19GSList *get_command_callback (int ck_id); 
    2520 
    2621/*** inline functions ****************************************************************************/ 
    2722