neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

runtime.c (96323B)


      1 /// @file runtime.c
      2 ///
      3 /// Management of runtime files (including packages)
      4 
      5 #include <assert.h>
      6 #include <errno.h>
      7 #include <fcntl.h>
      8 #include <inttypes.h>
      9 #include <stdbool.h>
     10 #include <stddef.h>
     11 #include <stdio.h>
     12 #include <string.h>
     13 #include <uv.h>
     14 
     15 #include "klib/kvec.h"
     16 #include "nvim/api/private/defs.h"
     17 #include "nvim/api/private/helpers.h"
     18 #include "nvim/ascii_defs.h"
     19 #include "nvim/autocmd.h"
     20 #include "nvim/autocmd_defs.h"
     21 #include "nvim/buffer_defs.h"
     22 #include "nvim/charset.h"
     23 #include "nvim/cmdexpand.h"
     24 #include "nvim/debugger.h"
     25 #include "nvim/errors.h"
     26 #include "nvim/eval.h"
     27 #include "nvim/eval/typval.h"
     28 #include "nvim/eval/userfunc.h"
     29 #include "nvim/eval/vars.h"
     30 #include "nvim/ex_cmds_defs.h"
     31 #include "nvim/ex_docmd.h"
     32 #include "nvim/ex_eval.h"
     33 #include "nvim/ex_eval_defs.h"
     34 #include "nvim/garray.h"
     35 #include "nvim/getchar.h"
     36 #include "nvim/gettext_defs.h"
     37 #include "nvim/globals.h"
     38 #include "nvim/hashtab.h"
     39 #include "nvim/hashtab_defs.h"
     40 #include "nvim/lua/executor.h"
     41 #include "nvim/macros_defs.h"
     42 #include "nvim/map_defs.h"
     43 #include "nvim/mbyte.h"
     44 #include "nvim/mbyte_defs.h"
     45 #include "nvim/memline.h"
     46 #include "nvim/memory.h"
     47 #include "nvim/memory_defs.h"
     48 #include "nvim/message.h"
     49 #include "nvim/option.h"
     50 #include "nvim/option_defs.h"
     51 #include "nvim/option_vars.h"
     52 #include "nvim/os/fs.h"
     53 #include "nvim/os/input.h"
     54 #include "nvim/os/os.h"
     55 #include "nvim/os/os_defs.h"
     56 #include "nvim/os/stdpaths_defs.h"
     57 #include "nvim/path.h"
     58 #include "nvim/pos_defs.h"
     59 #include "nvim/profile.h"
     60 #include "nvim/regexp.h"
     61 #include "nvim/regexp_defs.h"
     62 #include "nvim/runtime.h"
     63 #include "nvim/strings.h"
     64 #include "nvim/types_defs.h"
     65 #include "nvim/usercmd.h"
     66 #include "nvim/vim_defs.h"
     67 #ifdef USE_CRNL
     68 # include "nvim/highlight.h"
     69 #endif
     70 
     71 /// Structure used to store info for each sourced file.
     72 /// It is shared between do_source() and getsourceline().
     73 /// This is required, because it needs to be handed to do_cmdline() and
     74 /// sourcing can be done recursively.
     75 typedef struct {
     76  FILE *fp;                     ///< opened file for sourcing
     77  char *nextline;               ///< if not NULL: line that was read ahead
     78  linenr_T sourcing_lnum;       ///< line number of the source file
     79  bool finished;                ///< ":finish" used
     80  bool source_from_buf_or_str;  ///< true if sourcing from a buffer or string
     81  int buf_lnum;                 ///< line number in the buffer or string
     82  garray_T buflines;            ///< lines in the buffer or string
     83 #ifdef USE_CRNL
     84  int fileformat;               ///< EOL_UNKNOWN, EOL_UNIX or EOL_DOS
     85  bool error;                   ///< true if LF found after CR-LF
     86 #endif
     87  linenr_T breakpoint;          ///< next line with breakpoint or zero
     88  char *fname;                  ///< name of sourced file
     89  int dbg_tick;                 ///< debug_tick when breakpoint was set
     90  int level;                    ///< top nesting level of sourced file
     91  vimconv_T conv;               ///< type of conversion
     92 } source_cookie_T;
     93 
     94 typedef struct {
     95  char *path;
     96  bool after;
     97  bool pack_inserted;
     98  TriState has_lua;
     99  size_t pos_in_rtp;
    100 } SearchPathItem;
    101 
    102 typedef kvec_t(SearchPathItem) RuntimeSearchPath;
    103 typedef kvec_t(char *) CharVec;
    104 
    105 #include "runtime.c.generated.h"
    106 
    107 garray_T exestack = { 0, 0, sizeof(estack_T), 50, NULL };
    108 garray_T script_items = { 0, 0, sizeof(scriptitem_T *), 20, NULL };
    109 
    110 /// The names of packages that once were loaded are remembered.
    111 static garray_T ga_loaded = { 0, 0, sizeof(char *), 4, NULL };
    112 
    113 /// last used sequence number for sourcing scripts (current_sctx.sc_seq)
    114 static int last_current_SID_seq = 0;
    115 
    116 /// Initialize the execution stack.
    117 void estack_init(void)
    118 {
    119  ga_grow(&exestack, 10);
    120  estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len;
    121  entry->es_type = ETYPE_TOP;
    122  entry->es_name = NULL;
    123  entry->es_lnum = 0;
    124  entry->es_info.ufunc = NULL;
    125  exestack.ga_len++;
    126 }
    127 
    128 /// Add an item to the execution stack.
    129 /// @return  the new entry
    130 estack_T *estack_push(etype_T type, char *name, linenr_T lnum)
    131 {
    132  ga_grow(&exestack, 1);
    133  estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len;
    134  entry->es_type = type;
    135  entry->es_name = name;
    136  entry->es_lnum = lnum;
    137  entry->es_info.ufunc = NULL;
    138  exestack.ga_len++;
    139  return entry;
    140 }
    141 
    142 /// Add a user function to the execution stack.
    143 void estack_push_ufunc(ufunc_T *ufunc, linenr_T lnum)
    144 {
    145  estack_T *entry = estack_push(ETYPE_UFUNC,
    146                                ufunc->uf_name_exp != NULL ? ufunc->uf_name_exp : ufunc->uf_name,
    147                                lnum);
    148  if (entry != NULL) {
    149    entry->es_info.ufunc = ufunc;
    150  }
    151 }
    152 
    153 /// Take an item off of the execution stack.
    154 void estack_pop(void)
    155 {
    156  if (exestack.ga_len > 1) {
    157    exestack.ga_len--;
    158  }
    159 }
    160 
    161 /// Get the current value for <sfile> in allocated memory.
    162 /// @param which  ESTACK_SFILE for <sfile>, ESTACK_STACK for <stack> or
    163 ///               ESTACK_SCRIPT for <script>.
    164 char *estack_sfile(estack_arg_T which)
    165 {
    166  const estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1;
    167  if (which == ESTACK_SFILE && entry->es_type != ETYPE_UFUNC) {
    168    return entry->es_name != NULL ? xstrdup(entry->es_name) : NULL;
    169  }
    170 
    171  // If evaluated in a function or autocommand, return the path of the script
    172  // where it is defined, at script level the current script path is returned
    173  // instead.
    174  if (which == ESTACK_SCRIPT) {
    175    // Walk the stack backwards, starting from the current frame.
    176    for (int idx = exestack.ga_len - 1; idx >= 0; idx--, entry--) {
    177      if (entry->es_type == ETYPE_UFUNC || entry->es_type == ETYPE_AUCMD) {
    178        const sctx_T *const def_ctx = (entry->es_type == ETYPE_UFUNC
    179                                       ? &entry->es_info.ufunc->uf_script_ctx
    180                                       : &entry->es_info.aucmd->script_ctx);
    181        return def_ctx->sc_sid > 0
    182               ? xstrdup((SCRIPT_ITEM(def_ctx->sc_sid)->sn_name))
    183               : NULL;
    184      } else if (entry->es_type == ETYPE_SCRIPT) {
    185        return xstrdup(entry->es_name);
    186      }
    187    }
    188    return NULL;
    189  }
    190 
    191  // Give information about each stack entry up to the root.
    192  // For a function we compose the call stack, as it was done in the past:
    193  //   "function One[123]..Two[456]..Three"
    194  garray_T ga;
    195  ga_init(&ga, sizeof(char), 100);
    196  etype_T last_type = ETYPE_SCRIPT;
    197  for (int idx = 0; idx < exestack.ga_len; idx++) {
    198    entry = ((estack_T *)exestack.ga_data) + idx;
    199    if (entry->es_name != NULL) {
    200      String type_name = STATIC_CSTR_AS_STRING("");
    201      String es_name = cstr_as_string(entry->es_name);
    202      if (entry->es_type != last_type) {
    203        switch (entry->es_type) {
    204        case ETYPE_SCRIPT:
    205          type_name = STATIC_CSTR_AS_STRING("script "); break;
    206        case ETYPE_UFUNC:
    207          type_name = STATIC_CSTR_AS_STRING("function "); break;
    208        default:
    209          break;
    210        }
    211        last_type = entry->es_type;
    212      }
    213      linenr_T lnum = idx == exestack.ga_len - 1
    214                      ? which == ESTACK_STACK ? SOURCING_LNUM : 0
    215                      : entry->es_lnum;
    216 
    217      size_t len = es_name.size + type_name.size + 26;
    218      ga_grow(&ga, (int)len);
    219      ga_concat_len(&ga, type_name.data, type_name.size);
    220      ga_concat_len(&ga, es_name.data, es_name.size);
    221      // For the bottom entry of <sfile>: do not add the line number, it is used in
    222      // <slnum>.  Also leave it out when the number is not set.
    223      if (lnum != 0) {
    224        ga.ga_len += (int)vim_snprintf_safelen((char *)ga.ga_data + ga.ga_len,
    225                                               len - (size_t)ga.ga_len,
    226                                               "[%" PRIdLINENR "]", lnum);
    227      }
    228      if (idx != exestack.ga_len - 1) {
    229        GA_CONCAT_LITERAL(&ga, "..");
    230      }
    231    }
    232  }
    233 
    234  // Only NUL-terminate when not returning NULL.
    235  if (ga.ga_data != NULL) {
    236    ga_append(&ga, NUL);
    237  }
    238  return (char *)ga.ga_data;
    239 }
    240 
    241 static void stacktrace_push_item(list_T *const l, ufunc_T *const fp, const char *const event,
    242                                 const linenr_T lnum, char *const filepath)
    243 {
    244  dict_T *const d = tv_dict_alloc_lock(VAR_FIXED);
    245  typval_T tv = {
    246    .v_type = VAR_DICT,
    247    .v_lock = VAR_LOCKED,
    248    .vval.v_dict = d,
    249  };
    250 
    251  if (fp != NULL) {
    252    tv_dict_add_func(d, S_LEN("funcref"), fp);
    253  }
    254  if (event != NULL) {
    255    tv_dict_add_str(d, S_LEN("event"), event);
    256  }
    257  tv_dict_add_nr(d, S_LEN("lnum"), lnum);
    258  tv_dict_add_str(d, S_LEN("filepath"), filepath);
    259 
    260  tv_list_append_tv(l, &tv);
    261 }
    262 
    263 /// Create the stacktrace from exestack.
    264 list_T *stacktrace_create(void)
    265 {
    266  list_T *const l = tv_list_alloc(exestack.ga_len);
    267 
    268  for (int i = 0; i < exestack.ga_len; i++) {
    269    estack_T *const entry = &((estack_T *)exestack.ga_data)[i];
    270    linenr_T lnum = entry->es_lnum;
    271 
    272    if (entry->es_type == ETYPE_SCRIPT) {
    273      stacktrace_push_item(l, NULL, NULL, lnum, entry->es_name);
    274    } else if (entry->es_type == ETYPE_UFUNC) {
    275      ufunc_T *const fp = entry->es_info.ufunc;
    276      const sctx_T sctx = fp->uf_script_ctx;
    277      char *filepath = sctx.sc_sid > 0 ? get_scriptname(sctx, NULL) : "";
    278      lnum += sctx.sc_lnum;
    279      stacktrace_push_item(l, fp, NULL, lnum, filepath);
    280    } else if (entry->es_type == ETYPE_AUCMD) {
    281      const sctx_T sctx = entry->es_info.aucmd->script_ctx;
    282      char *filepath = sctx.sc_sid > 0 ? get_scriptname(sctx, NULL) : "";
    283      lnum += sctx.sc_lnum;
    284      stacktrace_push_item(l, NULL, entry->es_name, lnum, filepath);
    285    }
    286  }
    287  return l;
    288 }
    289 
    290 /// getstacktrace() function
    291 void f_getstacktrace(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
    292 {
    293  tv_list_set_ret(rettv, stacktrace_create());
    294 }
    295 
    296 static bool runtime_search_path_valid = false;
    297 static bool runtime_search_path_valid_thread = false;
    298 static int *runtime_search_path_ref = NULL;
    299 static RuntimeSearchPath runtime_search_path;
    300 static RuntimeSearchPath runtime_search_path_thread;
    301 static uv_mutex_t runtime_search_path_mutex;
    302 
    303 void runtime_init(void)
    304 {
    305  uv_mutex_init(&runtime_search_path_mutex);
    306 }
    307 
    308 /// Get DIP_ flags from the [where] argument of a :runtime command.
    309 /// "*argp" is advanced to after the [where] argument.
    310 static int get_runtime_cmd_flags(char **argp, size_t where_len)
    311 {
    312  char *arg = *argp;
    313 
    314  if (where_len == 0) {
    315    return 0;
    316  }
    317 
    318  if (strncmp(arg, "START", where_len) == 0) {
    319    *argp = skipwhite(arg + where_len);
    320    return DIP_START + DIP_NORTP;
    321  }
    322  if (strncmp(arg, "OPT", where_len) == 0) {
    323    *argp = skipwhite(arg + where_len);
    324    return DIP_OPT + DIP_NORTP;
    325  }
    326  if (strncmp(arg, "PACK", where_len) == 0) {
    327    *argp = skipwhite(arg + where_len);
    328    return DIP_START + DIP_OPT + DIP_NORTP;
    329  }
    330  if (strncmp(arg, "ALL", where_len) == 0) {
    331    *argp = skipwhite(arg + where_len);
    332    return DIP_START + DIP_OPT;
    333  }
    334 
    335  return 0;
    336 }
    337 
    338 /// ":runtime [where] {name}"
    339 void ex_runtime(exarg_T *eap)
    340 {
    341  char *arg = eap->arg;
    342  int flags = eap->forceit ? DIP_ALL : 0;
    343  char *p = skiptowhite(arg);
    344  flags += get_runtime_cmd_flags(&arg, (size_t)(p - arg));
    345  assert(arg != NULL);  // suppress clang false positive
    346  source_runtime(arg, flags);
    347 }
    348 
    349 static int runtime_expand_flags;
    350 
    351 /// Set the completion context for the :runtime command.
    352 void set_context_in_runtime_cmd(expand_T *xp, const char *arg)
    353 {
    354  char *p = skiptowhite(arg);
    355  runtime_expand_flags
    356    = *p != NUL ? get_runtime_cmd_flags((char **)&arg, (size_t)(p - arg)) : 0;
    357  // Skip to the last argument.
    358  while (*(p = skiptowhite_esc(arg)) != NUL) {
    359    if (runtime_expand_flags == 0) {
    360      // When there are multiple arguments and [where] is not specified,
    361      // use an unrelated non-zero flag to avoid expanding [where].
    362      runtime_expand_flags = DIP_ALL;
    363    }
    364    arg = skipwhite(p);
    365  }
    366  xp->xp_context = EXPAND_RUNTIME;
    367  xp->xp_pattern = (char *)arg;
    368 }
    369 
    370 /// Source all .vim and .lua files in "fnames" with .vim files being sourced first.
    371 static bool source_callback_vim_lua(int num_fnames, char **fnames, bool all, void *cookie)
    372 {
    373  bool did_one = false;
    374 
    375  for (int i = 0; i < num_fnames; i++) {
    376    if (path_with_extension(fnames[i], "vim")) {
    377      do_source(fnames[i], false, DOSO_NONE, cookie);
    378      did_one = true;
    379      if (!all) {
    380        return true;
    381      }
    382    }
    383  }
    384 
    385  for (int i = 0; i < num_fnames; i++) {
    386    if (path_with_extension(fnames[i], "lua")) {
    387      do_source(fnames[i], false, DOSO_NONE, cookie);
    388      did_one = true;
    389      if (!all) {
    390        return true;
    391      }
    392    }
    393  }
    394 
    395  return did_one;
    396 }
    397 
    398 /// Source all files in "fnames" with .vim files sourced first, .lua files
    399 /// sourced second, and any remaining files sourced last.
    400 static bool source_callback(int num_fnames, char **fnames, bool all, void *cookie)
    401 {
    402  bool did_one = source_callback_vim_lua(num_fnames, fnames, all, cookie);
    403 
    404  if (!all && did_one) {
    405    return true;
    406  }
    407 
    408  for (int i = 0; i < num_fnames; i++) {
    409    if (!path_with_extension(fnames[i], "vim")
    410        && !path_with_extension(fnames[i], "lua")) {
    411      do_source(fnames[i], false, DOSO_NONE, cookie);
    412      did_one = true;
    413      if (!all) {
    414        return true;
    415      }
    416    }
    417  }
    418 
    419  return did_one;
    420 }
    421 
    422 /// Find the patterns in "name" in all directories in "path" and invoke
    423 /// "callback(fname, cookie)".
    424 /// "prefix" is prepended to each pattern in "name".
    425 /// When "flags" has DIP_ALL: source all files, otherwise only the first one.
    426 /// When "flags" has DIP_DIR: find directories instead of files.
    427 /// When "flags" has DIP_ERR: give an error message if there is no match.
    428 ///
    429 /// Return FAIL when no file could be sourced, OK otherwise.
    430 int do_in_path(const char *path, const char *prefix, char *name, int flags,
    431               DoInRuntimepathCB callback, void *cookie)
    432  FUNC_ATTR_NONNULL_ARG(1, 2)
    433 {
    434  bool did_one = false;
    435 
    436  // Make a copy of 'runtimepath'.  Invoking the callback may change the
    437  // value.
    438  char *rtp_copy = xstrdup(path);
    439  char *buf = xmallocz(MAXPATHL);
    440  {
    441    char *tail;
    442    if (p_verbose > 10 && name != NULL) {
    443      verbose_enter();
    444      if (*prefix != NUL) {
    445        smsg(0, _("Searching for \"%s\" under \"%s\" in \"%s\""), name, prefix, path);
    446      } else {
    447        smsg(0, _("Searching for \"%s\" in \"%s\""), name, path);
    448      }
    449      verbose_leave();
    450    }
    451 
    452    bool do_all = (flags & DIP_ALL) != 0;
    453 
    454    // Loop over all entries in 'runtimepath'.
    455    char *rtp = rtp_copy;
    456    while (*rtp != NUL && (do_all || !did_one)) {
    457      // Copy the path from 'runtimepath' to buf[].
    458      copy_option_part(&rtp, buf, MAXPATHL, ",");
    459      size_t buflen = strlen(buf);
    460 
    461      // Skip after or non-after directories.
    462      if (flags & (DIP_NOAFTER | DIP_AFTER)) {
    463        bool is_after = path_is_after(buf, buflen);
    464 
    465        if ((is_after && (flags & DIP_NOAFTER))
    466            || (!is_after && (flags & DIP_AFTER))) {
    467          continue;
    468        }
    469      }
    470 
    471      if (name == NULL) {
    472        (*callback)(1, &buf, do_all, cookie);
    473        did_one = true;
    474      } else if (buflen + 2 + strlen(prefix) + strlen(name) < MAXPATHL) {
    475        add_pathsep(buf);
    476        strcat(buf, prefix);
    477        tail = buf + strlen(buf);
    478 
    479        // Loop over all patterns in "name"
    480        char *np = name;
    481        while (*np != NUL && (do_all || !did_one)) {
    482          // Append the pattern from "name" to buf[].
    483          assert(MAXPATHL >= (tail - buf));
    484          copy_option_part(&np, tail, (size_t)(MAXPATHL - (tail - buf)), "\t ");
    485 
    486          if (p_verbose > 10) {
    487            verbose_enter();
    488            smsg(0, _("Searching for \"%s\""), buf);
    489            verbose_leave();
    490          }
    491 
    492          int ew_flags = ((flags & DIP_DIR) ? EW_DIR : EW_FILE)
    493                         | ((flags & DIP_DIRFILE) ? (EW_DIR|EW_FILE) : 0);
    494 
    495          did_one |= gen_expand_wildcards_and_cb(1, &buf, ew_flags, do_all, callback,
    496                                                 cookie) == OK;
    497        }
    498      }
    499    }
    500  }
    501  xfree(buf);
    502  xfree(rtp_copy);
    503  if (!did_one && name != NULL) {
    504    char *basepath = path == p_rtp ? "runtimepath" : "packpath";
    505 
    506    if (flags & DIP_ERR) {
    507      semsg(_(e_dirnotf), basepath, name);
    508    } else if (p_verbose > 1) {
    509      verbose_enter();
    510      smsg(0, _("not found in '%s': \"%s\""), basepath, name);
    511      verbose_leave();
    512    }
    513  }
    514 
    515  return did_one ? OK : FAIL;
    516 }
    517 
    518 static RuntimeSearchPath runtime_search_path_get_cached(int *ref)
    519  FUNC_ATTR_NONNULL_ALL
    520 {
    521  runtime_search_path_validate();
    522 
    523  *ref = 0;
    524  if (runtime_search_path_ref == NULL) {
    525    // cached path was unreferenced. keep a ref to
    526    // prevent runtime_search_path() to freeing it too early
    527    (*ref)++;
    528    runtime_search_path_ref = ref;
    529  }
    530  return runtime_search_path;
    531 }
    532 
    533 static RuntimeSearchPath copy_runtime_search_path(const RuntimeSearchPath src)
    534 {
    535  RuntimeSearchPath dst = KV_INITIAL_VALUE;
    536  for (size_t j = 0; j < kv_size(src); j++) {
    537    SearchPathItem item = kv_A(src, j);
    538    kv_push(dst, ((SearchPathItem){ xstrdup(item.path), item.after, item.pack_inserted,
    539                                    item.has_lua, item.pos_in_rtp }));
    540  }
    541 
    542  return dst;
    543 }
    544 
    545 static void runtime_search_path_unref(RuntimeSearchPath path, const int *ref)
    546  FUNC_ATTR_NONNULL_ALL
    547 {
    548  if (*ref) {
    549    if (runtime_search_path_ref == ref) {
    550      runtime_search_path_ref = NULL;
    551    } else {
    552      runtime_search_path_free(path);
    553    }
    554  }
    555 }
    556 
    557 /// Find the file "name" in all directories in "path" and invoke
    558 /// "callback(fname, cookie)".
    559 /// "name" can contain wildcards.
    560 /// When "flags" has DIP_ALL: source all files, otherwise only the first one.
    561 /// When "flags" has DIP_DIR: find directories instead of files.
    562 /// When "flags" has DIP_ERR: give an error message if there is no match.
    563 ///
    564 /// return FAIL when no file could be sourced, OK otherwise.
    565 static int do_in_cached_path(char *name, int flags, DoInRuntimepathCB callback, void *cookie)
    566 {
    567  bool did_one = false;
    568 
    569  char buf[MAXPATHL];
    570 
    571  if (p_verbose > 10 && name != NULL) {
    572    verbose_enter();
    573    smsg(0, _("Searching for \"%s\" in runtime path"), name);
    574    verbose_leave();
    575  }
    576 
    577  int ref;
    578  RuntimeSearchPath path = runtime_search_path_get_cached(&ref);
    579 
    580  bool do_all = (flags & DIP_ALL) != 0;
    581 
    582  // Loop over all entries in cached path
    583  for (size_t j = 0; j < kv_size(path); j++) {
    584    SearchPathItem item = kv_A(path, j);
    585    size_t buflen = strlen(item.path);
    586 
    587    // Skip after or non-after directories.
    588    if (flags & (DIP_NOAFTER | DIP_AFTER)) {
    589      if ((item.after && (flags & DIP_NOAFTER))
    590          || (!item.after && (flags & DIP_AFTER))) {
    591        continue;
    592      }
    593    }
    594 
    595    if (name == NULL) {
    596      (*callback)(1, &item.path, do_all, cookie);
    597    } else if (buflen + strlen(name) + 2 < MAXPATHL) {
    598      STRCPY(buf, item.path);
    599      add_pathsep(buf);
    600      char *tail = buf + strlen(buf);
    601 
    602      // Loop over all patterns in "name"
    603      char *np = name;
    604 
    605      while (*np != NUL && (do_all || !did_one)) {
    606        // Append the pattern from "name" to buf[].
    607        assert(MAXPATHL >= (tail - buf));
    608        copy_option_part(&np, tail, (size_t)(MAXPATHL - (tail - buf)), "\t ");
    609 
    610        if (p_verbose > 10) {
    611          verbose_enter();
    612          smsg(0, _("Searching for \"%s\""), buf);
    613          verbose_leave();
    614        }
    615 
    616        int ew_flags = ((flags & DIP_DIR) ? EW_DIR : EW_FILE)
    617                       | ((flags & DIP_DIRFILE) ? (EW_DIR|EW_FILE) : 0)
    618                       | EW_NOBREAK;
    619 
    620        // Expand wildcards, invoke the callback for each match.
    621        char *(pat[]) = { buf };
    622        did_one |= gen_expand_wildcards_and_cb(1, pat, ew_flags, do_all, callback, cookie) == OK;
    623      }
    624    }
    625  }
    626 
    627  if (!did_one && name != NULL) {
    628    if (flags & DIP_ERR) {
    629      semsg(_(e_dirnotf), "runtime path", name);
    630    } else if (p_verbose > 1) {
    631      verbose_enter();
    632      smsg(0, _("not found in runtime path: \"%s\""), name);
    633      verbose_leave();
    634    }
    635  }
    636 
    637  runtime_search_path_unref(path, &ref);
    638 
    639  return did_one ? OK : FAIL;
    640 }
    641 
    642 Array runtime_inspect(Arena *arena)
    643 {
    644  RuntimeSearchPath path = runtime_search_path;
    645  Array rv = arena_array(arena, kv_size(path));
    646 
    647  for (size_t i = 0; i < kv_size(path); i++) {
    648    SearchPathItem *item = &kv_A(path, i);
    649    Dict entry = arena_dict(arena, 5);
    650    PUT_C(entry, "path", CSTR_AS_OBJ(item->path));
    651    if (item->after) {
    652      PUT_C(entry, "after", BOOLEAN_OBJ(true));
    653    }
    654    if (item->pack_inserted) {
    655      PUT_C(entry, "pack_inserted", BOOLEAN_OBJ(true));
    656    }
    657    if (item->has_lua != kNone) {
    658      PUT_C(entry, "has_lua",  BOOLEAN_OBJ(item->has_lua == kTrue));
    659    }
    660    PUT_C(entry, "pos_in_rtp", INTEGER_OBJ((Integer)item->pos_in_rtp));
    661 
    662    ADD_C(rv, DICT_OBJ(entry));
    663  }
    664  return rv;
    665 }
    666 
    667 ArrayOf(String) runtime_get_named(bool lua, Array pat, bool all, Arena *arena)
    668 {
    669  int ref;
    670  RuntimeSearchPath path = runtime_search_path_get_cached(&ref);
    671  static char buf[MAXPATHL];
    672 
    673  ArrayOf(String) rv = runtime_get_named_common(lua, pat, all, path, buf, sizeof buf, arena);
    674 
    675  runtime_search_path_unref(path, &ref);
    676  return rv;
    677 }
    678 
    679 ArrayOf(String) runtime_get_named_thread(bool lua, Array pat, bool all)
    680 {
    681  // TODO(bfredl): avoid contention between multiple worker threads?
    682  uv_mutex_lock(&runtime_search_path_mutex);
    683  static char buf[MAXPATHL];
    684  ArrayOf(String) rv = runtime_get_named_common(lua, pat, all, runtime_search_path_thread,
    685                                                buf, sizeof buf, NULL);
    686  uv_mutex_unlock(&runtime_search_path_mutex);
    687  return rv;
    688 }
    689 
    690 static ArrayOf(String) runtime_get_named_common(bool lua, Array pat, bool all,
    691                                                RuntimeSearchPath path, char *buf, size_t buf_len,
    692                                                Arena *arena)
    693 {
    694  ArrayOf(String) rv = arena_array(arena, kv_size(path) * pat.size);
    695  for (size_t i = 0; i < kv_size(path); i++) {
    696    SearchPathItem *item = &kv_A(path, i);
    697    if (lua) {
    698      if (item->has_lua == kNone) {
    699        size_t size = (size_t)snprintf(buf, buf_len, "%s/lua/", item->path);
    700        item->has_lua = (size < buf_len && os_isdir(buf));
    701      }
    702      if (item->has_lua == kFalse) {
    703        continue;
    704      }
    705    }
    706 
    707    for (size_t j = 0; j < pat.size; j++) {
    708      Object pat_item = pat.items[j];
    709      if (pat_item.type == kObjectTypeString) {
    710        size_t size = (size_t)snprintf(buf, buf_len, "%s/%s",
    711                                       item->path, pat_item.data.string.data);
    712        if (size < buf_len) {
    713          if (os_file_is_readable(buf)) {
    714            ADD_C(rv, CSTR_TO_ARENA_OBJ(arena, buf));
    715            if (!all) {
    716              goto done;
    717            }
    718          }
    719        }
    720      }
    721    }
    722  }
    723 done:
    724  return rv;
    725 }
    726 
    727 /// Find "name" in "path".  When found, invoke the callback function for
    728 /// it: callback(fname, "cookie")
    729 /// When "flags" has DIP_ALL repeat for all matches, otherwise only the first
    730 /// one is used.
    731 /// Returns OK when at least one match found, FAIL otherwise.
    732 /// If "name" is NULL calls callback for each entry in "path". Cookie is
    733 /// passed by reference in this case, setting it to NULL indicates that callback
    734 /// has done its job.
    735 int do_in_path_and_pp(char *path, char *name, int flags, DoInRuntimepathCB callback, void *cookie)
    736 {
    737  int done = FAIL;
    738 
    739  if ((flags & DIP_NORTP) == 0) {
    740    done |= do_in_path(path, "", (name && !*name) ? NULL : name, flags, callback,
    741                       cookie);
    742  }
    743 
    744  if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START)) {
    745    const char *prefix
    746      = (flags & DIP_AFTER) ? "pack/*/start/*/after/" : "pack/*/start/*/";  // NOLINT
    747    done |= do_in_path(p_pp, prefix, name, flags & ~DIP_AFTER, callback, cookie);
    748 
    749    if (done == FAIL || (flags & DIP_ALL)) {
    750      prefix = (flags & DIP_AFTER) ? "start/*/after/" : "start/*/";  // NOLINT
    751      done |= do_in_path(p_pp, prefix, name, flags & ~DIP_AFTER, callback, cookie);
    752    }
    753  }
    754 
    755  if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT)) {
    756    done |= do_in_path(p_pp, "pack/*/opt/*/", name, flags, callback, cookie);  // NOLINT
    757 
    758    if (done == FAIL || (flags & DIP_ALL)) {
    759      done |= do_in_path(p_pp, "opt/*/", name, flags, callback, cookie);  // NOLINT
    760    }
    761  }
    762 
    763  return done;
    764 }
    765 
    766 static bool push_path(RuntimeSearchPath *search_path, Set(String) *rtp_used, char *entry,
    767                      bool after, size_t pos_in_rtp)
    768 {
    769  String *key_alloc;
    770  if (set_put_ref(String, rtp_used, cstr_as_string(entry), &key_alloc)) {
    771    *key_alloc = cstr_to_string(entry);
    772    kv_push(*search_path, ((SearchPathItem){ key_alloc->data, after, false, kNone, pos_in_rtp }));
    773    return true;
    774  }
    775  return false;
    776 }
    777 
    778 static void expand_rtp_entry(RuntimeSearchPath *search_path, Set(String) *rtp_used, char *entry,
    779                             bool after, size_t pos_in_rtp)
    780 {
    781  if (set_has(String, rtp_used, cstr_as_string(entry))) {
    782    return;
    783  }
    784 
    785  if (!*entry) {
    786    push_path(search_path, rtp_used, entry, after, pos_in_rtp);
    787  }
    788 
    789  int num_files;
    790  char **files;
    791  char *(pat[]) = { entry };
    792  if (gen_expand_wildcards(1, pat, &num_files, &files, EW_DIR | EW_NOBREAK) == OK) {
    793    for (int i = 0; i < num_files; i++) {
    794      // reuses position but it is ok, we need to be monotonic but not strictly
    795      push_path(search_path, rtp_used, files[i], after, pos_in_rtp);
    796    }
    797    FreeWild(num_files, files);
    798  }
    799 }
    800 
    801 static void expand_pack_entry(RuntimeSearchPath *search_path, Set(String) *rtp_used,
    802                              CharVec *after_path, char *pack_entry, size_t pack_entry_len,
    803                              size_t pos_in_rtp)
    804 {
    805  static char buf[MAXPATHL];
    806  char *(start_pat[]) = { "/pack/*/start/*", "/start/*" };  // NOLINT
    807  for (int i = 0; i < 2; i++) {
    808    if (pack_entry_len + strlen(start_pat[i]) + 1 > sizeof buf) {
    809      continue;
    810    }
    811    xstrlcpy(buf, pack_entry, sizeof buf);
    812    xstrlcpy(buf + pack_entry_len, start_pat[i], sizeof buf - pack_entry_len);
    813    expand_rtp_entry(search_path, rtp_used, buf, false, pos_in_rtp);
    814    size_t after_size = strlen(buf) + 7;
    815    char *after = xmallocz(after_size);
    816    xstrlcpy(after, buf, after_size);
    817    xstrlcat(after, "/after", after_size);
    818    kv_push(*after_path, after);
    819  }
    820 }
    821 
    822 static bool path_is_after(char *buf, size_t buflen)
    823 {
    824  // NOTE: we only consider dirs exactly matching "after" to be an AFTER dir.
    825  // vim8 considers all dirs like "foo/bar_after", "Xafter" etc, as an
    826  // "after" dir in SOME codepaths not not in ALL codepaths.
    827  return buflen >= 5
    828         && (!(buflen >= 6) || vim_ispathsep(buf[buflen - 6]))
    829         && strcmp(buf + buflen - 5, "after") == 0;
    830 }
    831 
    832 static RuntimeSearchPath runtime_search_path_build(void)
    833 {
    834  kvec_t(String) pack_entries = KV_INITIAL_VALUE;
    835  Map(String, int) pack_used = MAP_INIT;
    836  Set(String) rtp_used = SET_INIT;
    837  RuntimeSearchPath search_path = KV_INITIAL_VALUE;
    838  CharVec after_path = KV_INITIAL_VALUE;
    839 
    840  static char buf[MAXPATHL];
    841  for (char *entry = p_pp; *entry != NUL;) {
    842    char *cur_entry = entry;
    843    copy_option_part(&entry, buf, MAXPATHL, ",");
    844 
    845    String the_entry = { .data = cur_entry, .size = strlen(buf) };
    846 
    847    kv_push(pack_entries, the_entry);
    848    map_put(String, int)(&pack_used, the_entry, 0);
    849  }
    850 
    851  char *rtp_entry;
    852  for (rtp_entry = p_rtp; *rtp_entry != NUL;) {
    853    char *cur_entry = rtp_entry;
    854    copy_option_part(&rtp_entry, buf, MAXPATHL, ",");
    855    size_t buflen = strlen(buf);
    856 
    857    if (path_is_after(buf, buflen)) {
    858      rtp_entry = cur_entry;
    859      break;
    860    }
    861 
    862    size_t pos_in_rtp = (size_t)(cur_entry - p_rtp);
    863 
    864    // fact: &rtp entries can contain wild chars
    865    expand_rtp_entry(&search_path, &rtp_used, buf, false, pos_in_rtp);
    866 
    867    handle_T *h = map_ref(String, int)(&pack_used, cstr_as_string(buf), NULL);
    868    if (h) {
    869      (*h)++;
    870      expand_pack_entry(&search_path, &rtp_used, &after_path, buf, buflen, pos_in_rtp);
    871    }
    872  }
    873 
    874  // The following entries were not explicit in rtp.
    875  // this is fine, but keep pos_in_rtp monotonic:
    876  // use the comma between two entries as a sentinel
    877  size_t sentinel_pos_in_rtp = (size_t)(rtp_entry - p_rtp);
    878  sentinel_pos_in_rtp -= (sentinel_pos_in_rtp > 0) ? 1 : 0;
    879 
    880  for (size_t i = 0; i < kv_size(pack_entries); i++) {
    881    String item = kv_A(pack_entries, i);
    882    handle_T h = map_get(String, int)(&pack_used, item);
    883    if (h == 0) {
    884      expand_pack_entry(&search_path, &rtp_used, &after_path, item.data, item.size,
    885                        sentinel_pos_in_rtp);
    886    }
    887  }
    888 
    889  // "after" packages
    890  for (size_t i = 0; i < kv_size(after_path); i++) {
    891    expand_rtp_entry(&search_path, &rtp_used, kv_A(after_path, i), true, sentinel_pos_in_rtp);
    892    xfree(kv_A(after_path, i));
    893  }
    894 
    895  // "after" dirs in rtp
    896  for (; *rtp_entry != NUL;) {
    897    char *cur_entry = rtp_entry;
    898    copy_option_part(&rtp_entry, buf, MAXPATHL, ",");
    899    size_t pos_in_rtp = (size_t)(cur_entry - p_rtp);
    900    expand_rtp_entry(&search_path, &rtp_used, buf, path_is_after(buf, strlen(buf)), pos_in_rtp);
    901  }
    902 
    903  // strings are not owned
    904  kv_destroy(pack_entries);
    905  kv_destroy(after_path);
    906  map_destroy(String, &pack_used);
    907  set_destroy(String, &rtp_used);
    908 
    909  return search_path;
    910 }
    911 
    912 const char *did_set_runtimepackpath(optset_T *args)
    913 {
    914  runtime_search_path_valid = false;
    915  return NULL;
    916 }
    917 
    918 static void runtime_search_path_free(RuntimeSearchPath path)
    919 {
    920  for (size_t j = 0; j < kv_size(path); j++) {
    921    SearchPathItem item = kv_A(path, j);
    922    xfree(item.path);
    923  }
    924  kv_destroy(path);
    925 }
    926 
    927 void runtime_search_path_validate(void)
    928 {
    929  if (!nlua_is_deferred_safe()) {
    930    // Cannot rebuild search path in an async context. As a plugin will invoke
    931    // itself asynchronously from sync code in the same plugin, the sought
    932    // after lua/autoload module will most likely already be in the cached path.
    933    // Thus prefer using the stale cache over erroring out in this situation.
    934    return;
    935  }
    936  if (!runtime_search_path_valid) {
    937    if (!runtime_search_path_ref) {
    938      runtime_search_path_free(runtime_search_path);
    939    }
    940    runtime_search_path = runtime_search_path_build();
    941    runtime_search_path_valid = true;
    942    runtime_search_path_ref = NULL;  // initially unowned
    943    update_runtime_search_path_thread(true);
    944  }
    945 }
    946 
    947 void update_runtime_search_path_thread(bool force)
    948 {
    949  if (!force && !(runtime_search_path_valid && !runtime_search_path_valid_thread)) {
    950    return;
    951  }
    952 
    953  uv_mutex_lock(&runtime_search_path_mutex);
    954  runtime_search_path_free(runtime_search_path_thread);
    955  runtime_search_path_thread = copy_runtime_search_path(runtime_search_path);
    956  uv_mutex_unlock(&runtime_search_path_mutex);
    957  runtime_search_path_valid_thread = true;
    958 }
    959 
    960 /// Just like do_in_path_and_pp(), using 'runtimepath' for "path".
    961 int do_in_runtimepath(char *name, int flags, DoInRuntimepathCB callback, void *cookie)
    962 {
    963  int success = FAIL;
    964  if (!(flags & DIP_NORTP)) {
    965    success |= do_in_cached_path((name && !*name) ? NULL : name, flags, callback, cookie);
    966    flags = (flags & ~DIP_START) | DIP_NORTP;
    967  }
    968  // TODO(bfredl): we could integrate disabled OPT dirs into the cached path
    969  // which would effectivize ":packadd myoptpack" as well
    970  if ((flags & (DIP_START|DIP_OPT)) && (success == FAIL || (flags & DIP_ALL))) {
    971    success |= do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
    972  }
    973  return success;
    974 }
    975 
    976 /// Source the file "name" from all directories in 'runtimepath'.
    977 /// "name" can contain wildcards.
    978 /// When "flags" has DIP_ALL: source all files, otherwise only the first one.
    979 ///
    980 /// return FAIL when no file could be sourced, OK otherwise.
    981 int source_runtime(char *name, int flags)
    982 {
    983  return do_in_runtimepath(name, flags, source_callback, NULL);
    984 }
    985 
    986 /// Just like source_runtime(), but only source vim and lua files
    987 int source_runtime_vim_lua(char *name, int flags)
    988 {
    989  return do_in_runtimepath(name, flags, source_callback_vim_lua, NULL);
    990 }
    991 
    992 /// Just like source_runtime(), but:
    993 /// - use "path" instead of 'runtimepath'.
    994 /// - only source .vim and .lua files
    995 int source_in_path_vim_lua(char *path, char *name, int flags)
    996 {
    997  return do_in_path_and_pp(path, name, flags, source_callback_vim_lua, NULL);
    998 }
    999 
   1000 /// Expand wildcards in "pats" and invoke callback matches.
   1001 ///
   1002 /// @param      num_pat  is number of input patterns.
   1003 /// @param      patx     is an array of pointers to input patterns.
   1004 /// @param      flags    is a combination of EW_* flags used in
   1005 ///                      expand_wildcards().
   1006 /// @param      all      invoke callback on all matches or just one
   1007 /// @param      callback called for each match.
   1008 /// @param      cookie   context for callback
   1009 ///
   1010 /// @returns             OK when some files were found, FAIL otherwise.
   1011 static int gen_expand_wildcards_and_cb(int num_pat, char **pats, int flags, bool all,
   1012                                       DoInRuntimepathCB callback, void *cookie)
   1013 {
   1014  int num_files;
   1015  char **files;
   1016 
   1017  if (gen_expand_wildcards(num_pat, pats, &num_files, &files, flags) != OK) {
   1018    return FAIL;
   1019  }
   1020 
   1021  (*callback)(num_files, files, all, cookie);
   1022 
   1023  FreeWild(num_files, files);
   1024 
   1025  return OK;
   1026 }
   1027 
   1028 /// Add the package directory to 'runtimepath'
   1029 ///
   1030 /// @param fname the package path
   1031 /// @param is_pack whether the added dir is a "pack/*/start/*/" style package
   1032 static int add_pack_dir_to_rtp(char *fname, bool is_pack)
   1033 {
   1034  char *afterdir = NULL;
   1035  int retval = FAIL;
   1036 
   1037  char *p1 = get_past_head(fname);
   1038  char *p2 = p1;
   1039  char *p3 = p1;
   1040  char *p4 = p1;
   1041  for (char *p = p1; *p; MB_PTR_ADV(p)) {
   1042    if (vim_ispathsep_nocolon(*p)) {
   1043      p4 = p3;
   1044      p3 = p2;
   1045      p2 = p1;
   1046      p1 = p;
   1047    }
   1048  }
   1049 
   1050  // now we have:
   1051  // rtp/pack/name/(start|opt)/name
   1052  //    p4   p3   p2           p1
   1053  //
   1054  // find the part up to "pack" in 'runtimepath'
   1055  p4++;  // append pathsep in order to expand symlink
   1056  char c = *p4;
   1057  *p4 = NUL;
   1058  char *const ffname = fix_fname(fname);
   1059  *p4 = c;
   1060 
   1061  if (ffname == NULL) {
   1062    return FAIL;
   1063  }
   1064 
   1065  // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences
   1066  // Also stop at the first "after" directory
   1067  size_t fname_len = strlen(ffname);
   1068  char buf[MAXPATHL];
   1069  const char *insp = NULL;
   1070  const char *after_insp = NULL;
   1071  const char *entry = p_rtp;
   1072  while (*entry != NUL) {
   1073    const char *cur_entry = entry;
   1074    copy_option_part((char **)&entry, buf, MAXPATHL, ",");
   1075 
   1076    char *p = strstr(buf, "after");
   1077    bool is_after = p != NULL
   1078                    && p > buf
   1079                    && vim_ispathsep(p[-1])
   1080                    && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ',');
   1081 
   1082    if (is_after) {
   1083      if (insp == NULL) {
   1084        // Did not find "ffname" before the first "after" directory,
   1085        // insert it before this entry.
   1086        insp = cur_entry;
   1087      }
   1088      after_insp = cur_entry;
   1089      break;
   1090    }
   1091 
   1092    if (insp == NULL) {
   1093      add_pathsep(buf);
   1094      char *const rtp_ffname = fix_fname(buf);
   1095      if (rtp_ffname == NULL) {
   1096        goto theend;
   1097      }
   1098      if (path_fnamencmp(rtp_ffname, ffname, fname_len) == 0) {
   1099        // Insert "ffname" after this entry (and comma).
   1100        insp = entry;
   1101      }
   1102      xfree(rtp_ffname);
   1103    }
   1104  }
   1105 
   1106  if (insp == NULL) {
   1107    // Both "fname" and "after" not found, append at the end.
   1108    insp = p_rtp + strlen(p_rtp);
   1109  }
   1110 
   1111  // check if rtp/pack/name/start/name/after exists
   1112  afterdir = concat_fnames(fname, "after", true);
   1113  size_t afterlen = 0;
   1114  if (is_pack ? pack_has_entries(afterdir) : os_isdir(afterdir)) {
   1115    afterlen = strlen(afterdir) + 1;  // add one for comma
   1116  }
   1117 
   1118  const size_t oldlen = strlen(p_rtp);
   1119  const size_t addlen = strlen(fname) + 1;  // add one for comma
   1120  const size_t new_rtp_capacity = oldlen + addlen + afterlen + 1;
   1121  // add one for NUL ------------------------------------------^
   1122  char *const new_rtp = try_malloc(new_rtp_capacity);
   1123  if (new_rtp == NULL) {
   1124    goto theend;
   1125  }
   1126 
   1127  // We now have 'rtp' parts: {keep}{keep_after}{rest}.
   1128  // Create new_rtp, first: {keep},{fname}
   1129  size_t keep = (size_t)(insp - p_rtp);
   1130  size_t first_pos = keep;
   1131  memmove(new_rtp, p_rtp, keep);
   1132  size_t new_rtp_len = keep;
   1133  if (*insp == NUL) {
   1134    new_rtp[new_rtp_len++] = ',';  // add comma before
   1135    first_pos++;
   1136  }
   1137  memmove(new_rtp + new_rtp_len, fname, addlen - 1);
   1138  new_rtp_len += addlen - 1;
   1139  if (*insp != NUL) {
   1140    new_rtp[new_rtp_len++] = ',';  // add comma after
   1141  }
   1142 
   1143  size_t after_pos = 0;
   1144 
   1145  if (afterlen > 0 && after_insp != NULL) {
   1146    size_t keep_after = (size_t)(after_insp - p_rtp);
   1147 
   1148    // Add to new_rtp: {keep},{fname}{keep_after},{afterdir}
   1149    memmove(new_rtp + new_rtp_len, p_rtp + keep, keep_after - keep);
   1150    new_rtp_len += keep_after - keep;
   1151    memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1);
   1152    new_rtp_len += afterlen - 1;
   1153    new_rtp[new_rtp_len++] = ',';
   1154    keep = keep_after;
   1155    after_pos = keep_after;
   1156  }
   1157 
   1158  if (p_rtp[keep] != NUL) {
   1159    // Append rest: {keep},{fname}{keep_after},{afterdir}{rest}
   1160    memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1);
   1161  } else {
   1162    new_rtp[new_rtp_len] = NUL;
   1163  }
   1164 
   1165  if (afterlen > 0 && after_insp == NULL) {
   1166    // Append afterdir when "after" was not found:
   1167    // {keep},{fname}{rest},{afterdir}
   1168    after_pos = xstrlcat(new_rtp, ",", new_rtp_capacity);
   1169    xstrlcat(new_rtp, afterdir, new_rtp_capacity);
   1170  }
   1171 
   1172  bool was_valid = runtime_search_path_valid;
   1173  set_option_value_give_err(kOptRuntimepath, CSTR_AS_OPTVAL(new_rtp), 0);
   1174 
   1175  assert(!runtime_search_path_valid);
   1176  // If this is the result of "packadd opt_pack", rebuilding runtime_search_pat
   1177  // from scratch is needlessly slow. splice in the package and its afterdir instead.
   1178  // But don't do this for "pack/*/start/*" (is_pack=true):
   1179  // we want properly expand wildcards in a "start" bundle.
   1180  if (was_valid && !is_pack) {
   1181    runtime_search_path_valid = true;
   1182    runtime_search_path_valid_thread = false;
   1183    kv_pushp(runtime_search_path);
   1184    ssize_t i = (ssize_t)(kv_size(runtime_search_path)) - 1;
   1185 
   1186    if (afterlen > 0) {
   1187      kv_pushp(runtime_search_path);
   1188      i += 1;
   1189      for (; i >= 1; i--) {
   1190        if (i > 1 && kv_A(runtime_search_path, i - 2).pos_in_rtp >= after_pos) {
   1191          kv_A(runtime_search_path, i) = kv_A(runtime_search_path, i - 2);
   1192          kv_A(runtime_search_path, i).pos_in_rtp += addlen + afterlen;
   1193        } else {
   1194          kv_A(runtime_search_path, i) = (SearchPathItem){ xstrdup(afterdir), true, true, kNone,
   1195                                                           after_pos + addlen };
   1196          i--;
   1197          break;
   1198        }
   1199      }
   1200    }
   1201 
   1202    for (; i >= 0; i--) {
   1203      if (i > 0 && kv_A(runtime_search_path, i - 1).pos_in_rtp >= first_pos) {
   1204        kv_A(runtime_search_path, i) = kv_A(runtime_search_path, i - 1);
   1205        kv_A(runtime_search_path, i).pos_in_rtp += addlen;
   1206      } else {
   1207        kv_A(runtime_search_path, i) = (SearchPathItem){ xstrdup(fname), false, true, kNone,
   1208                                                         first_pos };
   1209        break;
   1210      }
   1211    }
   1212  }
   1213  xfree(new_rtp);
   1214  retval = OK;
   1215 
   1216 theend:
   1217  xfree(ffname);
   1218  xfree(afterdir);
   1219  return retval;
   1220 }
   1221 
   1222 /// Load scripts in "plugin" directory of the package.
   1223 /// For opt packages, also load scripts in "ftdetect" (start packages already
   1224 /// load these from filetype.lua)
   1225 static int load_pack_plugin(bool opt, char *fname)
   1226 {
   1227  static const char plugpat[] = "%s/plugin/**/*";  // NOLINT
   1228  static const char ftpat[] = "%s/ftdetect/*";  // NOLINT
   1229 
   1230  char *const ffname = fix_fname(fname);
   1231  size_t len = strlen(ffname) + sizeof(plugpat);
   1232  char *pat = xmallocz(len);
   1233 
   1234  vim_snprintf(pat, len, plugpat, ffname);
   1235  gen_expand_wildcards_and_cb(1, &pat, EW_FILE, true, source_callback_vim_lua, NULL);
   1236 
   1237  char *cmd = xstrdup("g:did_load_filetypes");
   1238 
   1239  // If runtime/filetype.lua wasn't loaded yet, the scripts will be
   1240  // found when it loads.
   1241  if (opt && eval_to_number(cmd, false) > 0) {
   1242    do_cmdline_cmd("augroup filetypedetect");
   1243    vim_snprintf(pat, len, ftpat, ffname);
   1244    gen_expand_wildcards_and_cb(1, &pat, EW_FILE, true, source_callback_vim_lua, NULL);
   1245    do_cmdline_cmd("augroup END");
   1246  }
   1247  xfree(cmd);
   1248  xfree(pat);
   1249  xfree(ffname);
   1250 
   1251  return OK;
   1252 }
   1253 
   1254 // used for "cookie" of add_pack_plugin()
   1255 static int APP_ADD_DIR;
   1256 static int APP_LOAD;
   1257 static int APP_BOTH;
   1258 
   1259 static void add_pack_plugins(bool opt, int num_fnames, char **fnames, bool all, void *cookie)
   1260 {
   1261  bool did_one = false;
   1262 
   1263  if (cookie != &APP_LOAD) {
   1264    char buf[MAXPATHL];
   1265    for (int i = 0; i < num_fnames; i++) {
   1266      bool found = false;
   1267 
   1268      const char *p = p_rtp;
   1269      while (*p != NUL) {
   1270        copy_option_part((char **)&p, buf, MAXPATHL, ",");
   1271        if (path_fnamecmp(buf, fnames[i]) == 0) {
   1272          found = true;
   1273          break;
   1274        }
   1275      }
   1276      if (!found) {
   1277        // directory is not yet in 'runtimepath', add it
   1278        if (add_pack_dir_to_rtp(fnames[i], false) == FAIL) {
   1279          return;
   1280        }
   1281      }
   1282      did_one = true;
   1283      if (!all) {
   1284        break;
   1285      }
   1286    }
   1287  }
   1288 
   1289  if (!all && did_one) {
   1290    return;
   1291  }
   1292 
   1293  if (cookie != &APP_ADD_DIR) {
   1294    for (int i = 0; i < num_fnames; i++) {
   1295      load_pack_plugin(opt, fnames[i]);
   1296      if (!all) {
   1297        break;
   1298      }
   1299    }
   1300  }
   1301 }
   1302 
   1303 static bool add_start_pack_plugins(int num_fnames, char **fnames, bool all, void *cookie)
   1304 {
   1305  add_pack_plugins(false, num_fnames, fnames, all, cookie);
   1306  return num_fnames > 0;
   1307 }
   1308 
   1309 static bool add_opt_pack_plugins(int num_fnames, char **fnames, bool all, void *cookie)
   1310 {
   1311  add_pack_plugins(true, num_fnames, fnames, all, cookie);
   1312  return num_fnames > 0;
   1313 }
   1314 
   1315 /// Add all packages in the "start" directory to 'runtimepath'.
   1316 void add_pack_start_dirs(void)
   1317 {
   1318  do_in_path(p_pp, "", NULL, DIP_ALL + DIP_DIR, add_pack_start_dir, NULL);
   1319 }
   1320 
   1321 static bool pack_has_entries(char *buf)
   1322 {
   1323  int num_files;
   1324  char **files;
   1325  char *(pat[]) = { buf };
   1326  if (gen_expand_wildcards(1, pat, &num_files, &files, EW_DIR) == OK) {
   1327    FreeWild(num_files, files);
   1328  }
   1329  return num_files > 0;
   1330 }
   1331 
   1332 static bool add_pack_start_dir(int num_fnames, char **fnames, bool all, void *cookie)
   1333 {
   1334  static char buf[MAXPATHL];
   1335  for (int i = 0; i < num_fnames; i++) {
   1336    char *(start_pat[]) = { "/start/*", "/pack/*/start/*" };  // NOLINT
   1337    for (int j = 0; j < 2; j++) {
   1338      if (strlen(fnames[i]) + strlen(start_pat[j]) + 1 > MAXPATHL) {
   1339        continue;
   1340      }
   1341      xstrlcpy(buf, fnames[i], MAXPATHL);
   1342      xstrlcat(buf, start_pat[j], sizeof buf);
   1343      if (pack_has_entries(buf)) {
   1344        add_pack_dir_to_rtp(buf, true);
   1345      }
   1346    }
   1347 
   1348    if (!all) {
   1349      break;
   1350    }
   1351  }
   1352 
   1353  return num_fnames > 1;
   1354 }
   1355 
   1356 /// Load plugins from all packages in the "start" directory.
   1357 void load_start_packages(void)
   1358 {
   1359  did_source_packages = true;
   1360  do_in_path(p_pp, "", "pack/*/start/*", DIP_ALL + DIP_DIR,  // NOLINT
   1361             add_start_pack_plugins, &APP_LOAD);
   1362  do_in_path(p_pp, "", "start/*", DIP_ALL + DIP_DIR,  // NOLINT
   1363             add_start_pack_plugins, &APP_LOAD);
   1364 
   1365  update_runtime_search_path_thread(false);
   1366 }
   1367 
   1368 // ":packloadall"
   1369 // Find plugins in the package directories and source them.
   1370 void ex_packloadall(exarg_T *eap)
   1371 {
   1372  if (!did_source_packages || eap->forceit) {
   1373    // First do a round to add all directories to 'runtimepath', then load
   1374    // the plugins. This allows for plugins to use an autoload directory
   1375    // of another plugin.
   1376    add_pack_start_dirs();
   1377    load_start_packages();
   1378  }
   1379 }
   1380 
   1381 /// Read all the plugin files at startup
   1382 void load_plugins(void)
   1383 {
   1384  if (p_lpl) {
   1385    char *rtp_copy = p_rtp;
   1386    char *const plugin_pattern = "plugin/**/*";  // NOLINT
   1387 
   1388    if (!did_source_packages) {
   1389      rtp_copy = xstrdup(p_rtp);
   1390      add_pack_start_dirs();
   1391    }
   1392 
   1393    // Don't use source_runtime_vim_lua() yet so we can check for :packloadall below.
   1394    // NB: after calling this "rtp_copy" may have been freed if it wasn't copied.
   1395    source_in_path_vim_lua(rtp_copy, plugin_pattern, DIP_ALL | DIP_NOAFTER);
   1396    TIME_MSG("loading rtp plugins");
   1397 
   1398    // Only source "start" packages if not done already with a :packloadall
   1399    // command.
   1400    if (!did_source_packages) {
   1401      xfree(rtp_copy);
   1402      load_start_packages();
   1403    }
   1404    TIME_MSG("loading packages");
   1405 
   1406    source_runtime_vim_lua(plugin_pattern, DIP_ALL | DIP_AFTER);
   1407    TIME_MSG("loading after plugins");
   1408  }
   1409 }
   1410 
   1411 /// ":packadd[!] {name}"
   1412 void ex_packadd(exarg_T *eap)
   1413 {
   1414  static const char plugpat[] = "pack/*/%s/%s";  // NOLINT
   1415  int res = OK;
   1416 
   1417  const size_t len = sizeof(plugpat) + strlen(eap->arg) + 5;
   1418  char *pat = xmallocz(len);
   1419  void *cookie = eap->forceit ? &APP_ADD_DIR : &APP_BOTH;
   1420 
   1421  // Only look under "start" when loading packages wasn't done yet.
   1422  if (!did_source_packages) {
   1423    vim_snprintf(pat, len, plugpat, "start", eap->arg);
   1424    res = do_in_path(p_pp, "", pat, DIP_ALL + DIP_DIR,
   1425                     add_start_pack_plugins, cookie);
   1426  }
   1427 
   1428  // Give a "not found" error if nothing was found in 'start' or 'opt'.
   1429  vim_snprintf(pat, len, plugpat, "opt", eap->arg);
   1430  do_in_path(p_pp, "", pat, DIP_ALL + DIP_DIR + (res == FAIL ? DIP_ERR : 0),
   1431             add_opt_pack_plugins, cookie);
   1432 
   1433  update_runtime_search_path_thread(false);
   1434 
   1435  xfree(pat);
   1436 }
   1437 
   1438 static void ExpandRTDir_int(char *pat, size_t pat_len, int flags, bool keep_ext, garray_T *gap,
   1439                            char *dirnames[])
   1440 {
   1441  // TODO(bfredl): this is bullshit, expandpath should not reinvent path logic.
   1442  for (int i = 0; dirnames[i] != NULL; i++) {
   1443    const size_t buf_len = strlen(dirnames[i]) + pat_len + 64;
   1444    char *buf = xmalloc(buf_len);
   1445    int glob_flags = 0;
   1446    bool expand_dirs = false;
   1447    // Build base pattern
   1448    snprintf(buf, buf_len, "%s%s%s%s", *dirnames[i] ? dirnames[i] : "", *dirnames[i] ? "/" : "",
   1449             pat, "*.{vim,lua}");
   1450 
   1451 expand:
   1452    if ((flags & DIP_NORTP) == 0) {
   1453      globpath(p_rtp, buf, gap, glob_flags, expand_dirs);
   1454    }
   1455 
   1456    if (flags & DIP_START) {
   1457      // pack/*/start/*/ patterns
   1458      snprintf(buf, buf_len, "pack/*/start/*/%s%s%s%s", *dirnames[i] ? dirnames[i] : "",  // NOLINT
   1459               *dirnames[i] ? "/" : "", pat, expand_dirs ? "*" : "*.{vim,lua}");
   1460      globpath(p_pp, buf, gap, glob_flags, expand_dirs);
   1461 
   1462      // start/*/ patterns
   1463      snprintf(buf, buf_len, "start/*/%s%s%s%s", *dirnames[i] ? dirnames[i] : "",  // NOLINT
   1464               *dirnames[i] ? "/" : "", pat, expand_dirs ? "*" : "*.{vim,lua}");
   1465      globpath(p_pp, buf, gap, glob_flags, expand_dirs);
   1466    }
   1467 
   1468    if (flags & DIP_OPT) {
   1469      // pack/*/opt/*/ patterns
   1470      snprintf(buf, buf_len, "pack/*/opt/*/%s%s%s%s", *dirnames[i] ? dirnames[i] : "",  // NOLINT
   1471               *dirnames[i] ? "/" : "", pat, expand_dirs ? "*" : "*.{vim,lua}");
   1472      globpath(p_pp, buf, gap, glob_flags, expand_dirs);
   1473 
   1474      // opt/*/ patterns
   1475      snprintf(buf, buf_len, "opt/*/%s%s%s%s", *dirnames[i] ? dirnames[i] : "",  // NOLINT
   1476               *dirnames[i] ? "/" : "", pat, expand_dirs ? "*" : "*.{vim,lua}");
   1477      globpath(p_pp, buf, gap, glob_flags, expand_dirs);
   1478    }
   1479 
   1480    // Second round for directories
   1481    if (*dirnames[i] == NUL && !expand_dirs) {
   1482      snprintf(buf, buf_len, "%s*", pat);
   1483      glob_flags = WILD_ADD_SLASH;
   1484      expand_dirs = true;
   1485      goto expand;
   1486    }
   1487 
   1488    xfree(buf);
   1489  }
   1490 
   1491  int pat_pathsep_cnt = 0;
   1492  for (size_t i = 0; i < pat_len; i++) {
   1493    if (vim_ispathsep(pat[i])) {
   1494      pat_pathsep_cnt++;
   1495    }
   1496  }
   1497 
   1498  for (int i = 0; i < gap->ga_len; i++) {
   1499    char *match = ((char **)gap->ga_data)[i];
   1500    char *s = match;
   1501    char *e = s + strlen(s);
   1502    if (e - s > 4 && !keep_ext && (STRNICMP(e - 4, ".vim", 4) == 0
   1503                                   || STRNICMP(e - 4, ".lua", 4) == 0)) {
   1504      e -= 4;
   1505      *e = NUL;
   1506    }
   1507 
   1508    int match_pathsep_cnt = (e > s && e[-1] == '/') ? -1 : 0;
   1509    for (s = e; s > match; MB_PTR_BACK(match, s)) {
   1510      if (vim_ispathsep(*s) && ++match_pathsep_cnt > pat_pathsep_cnt) {
   1511        break;
   1512      }
   1513    }
   1514    s++;
   1515    if (s != match) {
   1516      assert((e - s) + 1 >= 0);
   1517      memmove(match, s, (size_t)(e - s) + 1);
   1518    }
   1519  }
   1520 
   1521  if (GA_EMPTY(gap)) {
   1522    return;
   1523  }
   1524 
   1525  // Sort and remove duplicates which can happen when specifying multiple
   1526  // directories in dirnames.
   1527  ga_remove_duplicate_strings(gap);
   1528 }
   1529 
   1530 /// Expand color scheme, compiler or filetype names.
   1531 /// Search from 'runtimepath':
   1532 ///   'runtimepath'/{dirnames}/{pat}.{vim,lua}
   1533 /// When "flags" has DIP_START: search also from "start" of 'packpath':
   1534 ///   'packpath'/pack/*/start/*/{dirnames}/{pat}.{vim,lua}
   1535 /// When "flags" has DIP_OPT: search also from "opt" of 'packpath':
   1536 ///   'packpath'/pack/*/opt/*/{dirnames}/{pat}.{vim,lua}
   1537 /// "dirnames" is an array with one or more directory names.
   1538 int ExpandRTDir(char *pat, int flags, int *num_file, char ***file, char *dirnames[])
   1539 {
   1540  *num_file = 0;
   1541  *file = NULL;
   1542 
   1543  garray_T ga;
   1544  ga_init(&ga, (int)sizeof(char *), 10);
   1545 
   1546  ExpandRTDir_int(pat, strlen(pat), flags, false, &ga, dirnames);
   1547 
   1548  if (GA_EMPTY(&ga)) {
   1549    return FAIL;
   1550  }
   1551 
   1552  *file = ga.ga_data;
   1553  *num_file = ga.ga_len;
   1554  return OK;
   1555 }
   1556 
   1557 /// Handle command line completion for :runtime command.
   1558 int expand_runtime_cmd(char *pat, int *numMatches, char ***matches)
   1559 {
   1560  *numMatches = 0;
   1561  *matches = NULL;
   1562 
   1563  garray_T ga;
   1564  ga_init(&ga, sizeof(char *), 10);
   1565 
   1566  const size_t pat_len = strlen(pat);
   1567  char *dirnames[] = { "", NULL };
   1568  ExpandRTDir_int(pat, pat_len, runtime_expand_flags, true, &ga, dirnames);
   1569 
   1570  // Try to complete values for [where] argument when none was found.
   1571  if (runtime_expand_flags == 0) {
   1572    char *where_values[] = { "START", "OPT", "PACK", "ALL" };
   1573    for (size_t i = 0; i < ARRAY_SIZE(where_values); i++) {
   1574      if (strncmp(pat, where_values[i], pat_len) == 0) {
   1575        GA_APPEND(char *, &ga, xstrdup(where_values[i]));
   1576      }
   1577    }
   1578  }
   1579 
   1580  if (GA_EMPTY(&ga)) {
   1581    return FAIL;
   1582  }
   1583 
   1584  *matches = ga.ga_data;
   1585  *numMatches = ga.ga_len;
   1586  return OK;
   1587 }
   1588 
   1589 /// Expand loadplugin names:
   1590 /// 'packpath'/pack/*/opt/{pat}
   1591 int ExpandPackAddDir(char *pat, int *num_file, char ***file)
   1592 {
   1593  garray_T ga;
   1594 
   1595  *num_file = 0;
   1596  *file = NULL;
   1597  size_t pat_len = strlen(pat);
   1598  ga_init(&ga, (int)sizeof(char *), 10);
   1599 
   1600  size_t buflen = pat_len + 26;
   1601  char *s = xmalloc(buflen);
   1602  snprintf(s, buflen, "pack/*/opt/%s*", pat);  // NOLINT
   1603  globpath(p_pp, s, &ga, 0, true);
   1604  snprintf(s, buflen, "opt/%s*", pat);  // NOLINT
   1605  globpath(p_pp, s, &ga, 0, true);
   1606  xfree(s);
   1607 
   1608  for (int i = 0; i < ga.ga_len; i++) {
   1609    char *match = ((char **)ga.ga_data)[i];
   1610    s = path_tail(match);
   1611    memmove(match, s, strlen(s) + 1);
   1612  }
   1613 
   1614  if (GA_EMPTY(&ga)) {
   1615    return FAIL;
   1616  }
   1617 
   1618  // Sort and remove duplicates which can happen when specifying multiple
   1619  // directories in dirnames.
   1620  ga_remove_duplicate_strings(&ga);
   1621 
   1622  *file = ga.ga_data;
   1623  *num_file = ga.ga_len;
   1624  return OK;
   1625 }
   1626 
   1627 /// Append string with escaped commas
   1628 static char *strcpy_comma_escaped(char *dest, const char *src, const size_t len)
   1629  FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
   1630 {
   1631  size_t shift = 0;
   1632  for (size_t i = 0; i < len; i++) {
   1633    if (src[i] == ',') {
   1634      dest[i + shift++] = '\\';
   1635    }
   1636    dest[i + shift] = src[i];
   1637  }
   1638  return &dest[len + shift];
   1639 }
   1640 
   1641 /// Compute length of a ENV_SEPCHAR-separated value, doubled and with some
   1642 /// suffixes
   1643 ///
   1644 /// @param[in]  val  ENV_SEPCHAR-separated array value.
   1645 /// @param[in]  common_suf_len  Length of the common suffix which is appended to
   1646 ///                             each item in the array, twice.
   1647 /// @param[in]  single_suf_len  Length of the suffix which is appended to each
   1648 ///                             item in the array once.
   1649 ///
   1650 /// @return Length of the ENV_SEPCHAR-separated string array that contains each
   1651 ///         item in the original array twice with suffixes with given length
   1652 ///         (common_suf is present after each new item, single_suf is present
   1653 ///         after half of the new items) and with commas after each item, commas
   1654 ///         inside the values are escaped.
   1655 static inline size_t compute_double_env_sep_len(const char *const val, const size_t common_suf_len,
   1656                                                const size_t single_suf_len)
   1657  FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
   1658 {
   1659  if (val == NULL || *val == NUL) {
   1660    return 0;
   1661  }
   1662  size_t ret = 0;
   1663  const void *iter = NULL;
   1664  do {
   1665    size_t dir_len;
   1666    const char *dir;
   1667    iter = vim_env_iter(ENV_SEPCHAR, val, iter, &dir, &dir_len);
   1668    if (dir != NULL && dir_len > 0) {
   1669      ret += ((dir_len + memcnt(dir, ',', dir_len) + common_suf_len
   1670               + !after_pathsep(dir, dir + dir_len)) * 2
   1671              + single_suf_len);
   1672    }
   1673  } while (iter != NULL);
   1674  return ret;
   1675 }
   1676 
   1677 /// Add directories to a ENV_SEPCHAR-separated array from a colon-separated one
   1678 ///
   1679 /// Commas are escaped in process. To each item PATHSEP "nvim" is appended in
   1680 /// addition to suf1 and suf2.
   1681 ///
   1682 /// @param[in,out]  dest  Destination comma-separated array.
   1683 /// @param[in]  val  Source ENV_SEPCHAR-separated array.
   1684 /// @param[in]  suf1  If not NULL, suffix appended to destination. Prior to it
   1685 ///                   directory separator is appended. Suffix must not contain
   1686 ///                   commas.
   1687 /// @param[in]  len1  Length of the suf1.
   1688 /// @param[in]  suf2  If not NULL, another suffix appended to destination. Again
   1689 ///                   with directory separator behind. Suffix must not contain
   1690 ///                   commas.
   1691 /// @param[in]  len2  Length of the suf2.
   1692 /// @param[in]  forward  If true, iterate over val in forward direction.
   1693 ///                      Otherwise in reverse.
   1694 ///
   1695 /// @return (dest + appended_characters_length)
   1696 static inline char *add_env_sep_dirs(char *dest, const char *const val, const char *const suf1,
   1697                                     const size_t len1, const char *const suf2, const size_t len2,
   1698                                     const bool forward)
   1699  FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1)
   1700 {
   1701  if (val == NULL || *val == NUL) {
   1702    return dest;
   1703  }
   1704  const void *iter = NULL;
   1705  const char *appname = get_appname(false);
   1706  const size_t appname_len = strlen(appname);
   1707  do {
   1708    size_t dir_len;
   1709    const char *dir;
   1710    iter = (forward ? vim_env_iter : vim_env_iter_rev)(ENV_SEPCHAR, val, iter,
   1711                                                       &dir, &dir_len);
   1712    if (dir != NULL && dir_len > 0) {
   1713      dest = strcpy_comma_escaped(dest, dir, dir_len);
   1714      if (!after_pathsep(dest - 1, dest)) {
   1715        *dest++ = PATHSEP;
   1716      }
   1717      memmove(dest, appname, appname_len);
   1718      dest += appname_len;
   1719      if (suf1 != NULL) {
   1720        *dest++ = PATHSEP;
   1721        memmove(dest, suf1, len1);
   1722        dest += len1;
   1723        if (suf2 != NULL) {
   1724          *dest++ = PATHSEP;
   1725          memmove(dest, suf2, len2);
   1726          dest += len2;
   1727        }
   1728      }
   1729      *dest++ = ',';
   1730    }
   1731  } while (iter != NULL);
   1732  return dest;
   1733 }
   1734 
   1735 /// Adds directory `dest` to a comma-separated list of directories.
   1736 ///
   1737 /// Commas in the added directory are escaped.
   1738 ///
   1739 /// Windows: Appends "nvim-data" instead of "nvim" if `type` is kXDGDataHome.
   1740 ///
   1741 /// @see get_xdg_home
   1742 ///
   1743 /// @param[in,out]  dest  Destination comma-separated array.
   1744 /// @param[in]  dir  Directory to append.
   1745 /// @param[in]  type  Decides whether to append "nvim" (Win: or "nvim-data").
   1746 /// @param[in]  suf1  If not NULL, suffix appended to destination. Prior to it
   1747 ///                   directory separator is appended. Suffix must not contain
   1748 ///                   commas.
   1749 /// @param[in]  len1  Length of the suf1.
   1750 /// @param[in]  suf2  If not NULL, another suffix appended to destination. Again
   1751 ///                   with directory separator behind. Suffix must not contain
   1752 ///                   commas.
   1753 /// @param[in]  len2  Length of the suf2.
   1754 /// @param[in]  forward  If true, iterate over val in forward direction.
   1755 ///                      Otherwise in reverse.
   1756 ///
   1757 /// @return (dest + appended_characters_length)
   1758 static inline char *add_dir(char *dest, const char *const dir, const size_t dir_len,
   1759                            const XDGVarType type, const char *const suf1, const size_t len1,
   1760                            const char *const suf2, const size_t len2)
   1761  FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT
   1762 {
   1763  if (dir == NULL || dir_len == 0) {
   1764    return dest;
   1765  }
   1766  dest = strcpy_comma_escaped(dest, dir, dir_len);
   1767  bool append_nvim = (type == kXDGDataHome || type == kXDGConfigHome);
   1768  if (append_nvim) {
   1769    if (!after_pathsep(dest - 1, dest)) {
   1770      *dest++ = PATHSEP;
   1771    }
   1772    const char *appname = get_appname(false);
   1773    size_t appname_len = strlen(appname);
   1774    assert(appname_len < (IOSIZE - sizeof("-data")));
   1775    xmemcpyz(IObuff, appname, appname_len);
   1776 #if defined(MSWIN)
   1777    if (type == kXDGDataHome || type == kXDGStateHome) {
   1778      xstrlcat(IObuff, "-data", IOSIZE);
   1779      appname_len += 5;
   1780    }
   1781 #endif
   1782    xmemcpyz(dest, IObuff, appname_len);
   1783    dest += appname_len;
   1784    if (suf1 != NULL) {
   1785      *dest++ = PATHSEP;
   1786      memmove(dest, suf1, len1);
   1787      dest += len1;
   1788      if (suf2 != NULL) {
   1789        *dest++ = PATHSEP;
   1790        memmove(dest, suf2, len2);
   1791        dest += len2;
   1792      }
   1793    }
   1794  }
   1795  *dest++ = ',';
   1796  return dest;
   1797 }
   1798 
   1799 char *get_lib_dir(void)
   1800 {
   1801  // TODO(bfredl): too fragile? Ideally default_lib_dir would be made empty
   1802  // in an appimage build
   1803  if (strlen(default_lib_dir) != 0
   1804      && os_isdir(default_lib_dir)) {
   1805    return xstrdup(default_lib_dir);
   1806  }
   1807 
   1808  // Find library path relative to the nvim binary: ../lib/nvim/
   1809  char exe_name[MAXPATHL];
   1810  vim_get_prefix_from_exepath(exe_name);
   1811  if (append_path(exe_name, "lib/nvim", MAXPATHL) == OK) {
   1812    return xstrdup(exe_name);
   1813  }
   1814  return NULL;
   1815 }
   1816 
   1817 /// Determine the startup value for &runtimepath
   1818 ///
   1819 /// Windows: Uses "…/nvim-data" for kXDGDataHome to avoid storing
   1820 /// configuration and data files in the same path. #4403
   1821 ///
   1822 /// @param clean_arg  Nvim was started with --clean.
   1823 /// @return allocated string with the value
   1824 char *runtimepath_default(bool clean_arg)
   1825 {
   1826  size_t rtp_size = 0;
   1827  char *const data_home = clean_arg
   1828                          ? NULL
   1829                          : stdpaths_get_xdg_var(kXDGDataHome);
   1830  char *const config_home = clean_arg
   1831                            ? NULL
   1832                            : stdpaths_get_xdg_var(kXDGConfigHome);
   1833  char *const vimruntime = vim_getenv("VIMRUNTIME");
   1834  char *const libdir = get_lib_dir();
   1835  char *const data_dirs = stdpaths_get_xdg_var(kXDGDataDirs);
   1836  char *const config_dirs = stdpaths_get_xdg_var(kXDGConfigDirs);
   1837 #define SITE_SIZE (sizeof("site") - 1)
   1838 #define AFTER_SIZE (sizeof("after") - 1)
   1839  size_t data_len = 0;
   1840  size_t config_len = 0;
   1841  size_t vimruntime_len = 0;
   1842  size_t libdir_len = 0;
   1843  size_t appname_len = strlen(get_appname(false));
   1844  if (data_home != NULL) {
   1845    data_len = strlen(data_home);
   1846    size_t nvim_data_size = appname_len;
   1847 #if defined(MSWIN)
   1848    nvim_data_size += sizeof("-data") - 1;  // -1: NULL byte should be ignored
   1849 #endif
   1850    if (data_len != 0) {
   1851      rtp_size += ((data_len + memcnt(data_home, ',', data_len)
   1852                    + nvim_data_size + 1 + SITE_SIZE + 1
   1853                    + !after_pathsep(data_home, data_home + data_len)) * 2
   1854                   + AFTER_SIZE + 1);
   1855    }
   1856  }
   1857  if (config_home != NULL) {
   1858    config_len = strlen(config_home);
   1859    if (config_len != 0) {
   1860      rtp_size += ((config_len + memcnt(config_home, ',', config_len)
   1861                    + appname_len + 1
   1862                    + !after_pathsep(config_home, config_home + config_len)) * 2
   1863                   + AFTER_SIZE + 1);
   1864    }
   1865  }
   1866  if (vimruntime != NULL) {
   1867    vimruntime_len = strlen(vimruntime);
   1868    if (vimruntime_len != 0) {
   1869      rtp_size += vimruntime_len + memcnt(vimruntime, ',', vimruntime_len) + 1;
   1870    }
   1871  }
   1872  if (libdir != NULL) {
   1873    libdir_len = strlen(libdir);
   1874    if (libdir_len != 0) {
   1875      rtp_size += libdir_len + memcnt(libdir, ',', libdir_len) + 1;
   1876    }
   1877  }
   1878  rtp_size += compute_double_env_sep_len(data_dirs,
   1879                                         appname_len + 1 + SITE_SIZE + 1,
   1880                                         AFTER_SIZE + 1);
   1881  rtp_size += compute_double_env_sep_len(config_dirs, appname_len + 1,
   1882                                         AFTER_SIZE + 1);
   1883  char *rtp = NULL;
   1884  if (rtp_size == 0) {
   1885    goto freeall;
   1886  }
   1887  rtp = xmalloc(rtp_size);
   1888  char *rtp_cur = rtp;
   1889  rtp_cur = add_dir(rtp_cur, config_home, config_len, kXDGConfigHome,
   1890                    NULL, 0, NULL, 0);
   1891  rtp_cur = add_env_sep_dirs(rtp_cur, config_dirs, NULL, 0, NULL, 0, true);
   1892  rtp_cur = add_dir(rtp_cur, data_home, data_len, kXDGDataHome,
   1893                    "site", SITE_SIZE, NULL, 0);
   1894  rtp_cur = add_env_sep_dirs(rtp_cur, data_dirs, "site", SITE_SIZE, NULL, 0,
   1895                             true);
   1896  rtp_cur = add_dir(rtp_cur, vimruntime, vimruntime_len, kXDGNone,
   1897                    NULL, 0, NULL, 0);
   1898  rtp_cur = add_dir(rtp_cur, libdir, libdir_len, kXDGNone, NULL, 0, NULL, 0);
   1899  rtp_cur = add_env_sep_dirs(rtp_cur, data_dirs, "site", SITE_SIZE,
   1900                             "after", AFTER_SIZE, false);
   1901  rtp_cur = add_dir(rtp_cur, data_home, data_len, kXDGDataHome,
   1902                    "site", SITE_SIZE, "after", AFTER_SIZE);
   1903  rtp_cur = add_env_sep_dirs(rtp_cur, config_dirs, "after", AFTER_SIZE, NULL, 0,
   1904                             false);
   1905  rtp_cur = add_dir(rtp_cur, config_home, config_len, kXDGConfigHome,
   1906                    "after", AFTER_SIZE, NULL, 0);
   1907  // Strip trailing comma.
   1908  rtp_cur[-1] = NUL;
   1909  assert((size_t)(rtp_cur - rtp) == rtp_size);
   1910 #undef SITE_SIZE
   1911 #undef AFTER_SIZE
   1912 freeall:
   1913  xfree(data_dirs);
   1914  xfree(config_dirs);
   1915  xfree(data_home);
   1916  xfree(config_home);
   1917  xfree(vimruntime);
   1918  xfree(libdir);
   1919 
   1920  return rtp;
   1921 }
   1922 
   1923 static void cmd_source(char *fname, exarg_T *eap)
   1924 {
   1925  if (*fname != NUL && eap != NULL && eap->addr_count > 0) {
   1926    // if a filename is specified to :source, then a range is not allowed
   1927    emsg(_(e_norange));
   1928    return;
   1929  }
   1930 
   1931  if (eap != NULL && *fname == NUL) {
   1932    if (eap->forceit) {
   1933      // a file name is needed to source normal mode commands
   1934      emsg(_(e_argreq));
   1935    } else {
   1936      // source ex commands from the current buffer
   1937      cmd_source_buffer(eap, false);
   1938    }
   1939  } else if (eap != NULL && eap->forceit) {
   1940    // ":source!": read Normal mode commands
   1941    // Need to execute the commands directly.  This is required at least
   1942    // for:
   1943    // - ":g" command busy
   1944    // - after ":argdo", ":windo" or ":bufdo"
   1945    // - another command follows
   1946    // - inside a loop
   1947    openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
   1948               || eap->cstack->cs_idx >= 0);
   1949 
   1950    // ":source" read ex commands
   1951  } else if (do_source(fname, false, DOSO_NONE, NULL) == FAIL) {
   1952    semsg(_(e_notopen), fname);
   1953  }
   1954 }
   1955 
   1956 /// ":source [{fname}]"
   1957 void ex_source(exarg_T *eap)
   1958 {
   1959  cmd_source(eap->arg, eap);
   1960 }
   1961 
   1962 /// ":options"
   1963 void ex_options(exarg_T *eap)
   1964 {
   1965  char buf[500];
   1966  bool multi_mods = 0;
   1967 
   1968  buf[0] = NUL;
   1969  add_win_cmd_modifiers(buf, &cmdmod, &multi_mods);
   1970 
   1971  os_setenv("OPTWIN_CMD", buf, 1);
   1972  cmd_source(SYS_OPTWIN_FILE, NULL);
   1973 }
   1974 
   1975 /// ":source" and associated commands.
   1976 ///
   1977 /// @return address holding the next breakpoint line for a source cookie
   1978 linenr_T *source_breakpoint(void *cookie)
   1979 {
   1980  return &((source_cookie_T *)cookie)->breakpoint;
   1981 }
   1982 
   1983 /// @return  the address holding the debug tick for a source cookie.
   1984 int *source_dbg_tick(void *cookie)
   1985 {
   1986  return &((source_cookie_T *)cookie)->dbg_tick;
   1987 }
   1988 
   1989 /// @return  the nesting level for a source cookie.
   1990 int source_level(void *cookie)
   1991  FUNC_ATTR_PURE
   1992 {
   1993  return ((source_cookie_T *)cookie)->level;
   1994 }
   1995 
   1996 /// Special function to open a file without handle inheritance.
   1997 /// If possible the handle is closed on exec().
   1998 static FILE *fopen_noinh_readbin(char *filename)
   1999 {
   2000 #ifdef MSWIN
   2001  int fd_tmp = os_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
   2002 #else
   2003  int fd_tmp = os_open(filename, O_RDONLY, 0);
   2004 #endif
   2005 
   2006  if (fd_tmp < 0) {
   2007    return NULL;
   2008  }
   2009 
   2010  os_set_cloexec(fd_tmp);
   2011 
   2012  return fdopen(fd_tmp, READBIN);
   2013 }
   2014 
   2015 /// Concatenate Vimscript line if it starts with a line continuation into a growarray
   2016 /// (excluding the continuation chars and leading whitespace)
   2017 ///
   2018 /// @note Growsize of the growarray may be changed to speed up concatenations!
   2019 ///
   2020 /// @param ga  the growarray to append to
   2021 /// @param init_growsize  the starting growsize value of the growarray
   2022 /// @param p  pointer to the beginning of the line to consider
   2023 /// @param len  the length of this line
   2024 ///
   2025 /// @return true if this line did begin with a continuation (the next line
   2026 ///         should also be considered, if it exists); false otherwise
   2027 static bool concat_continued_line(garray_T *const ga, const int init_growsize, const char *const p,
   2028                                  size_t len)
   2029  FUNC_ATTR_NONNULL_ALL
   2030 {
   2031  const char *const line = skipwhite_len(p, len);
   2032  len -= (size_t)(line - p);
   2033  // Skip lines starting with '\" ', concat lines starting with '\'
   2034  if (len >= 3 && strncmp(line, "\"\\ ", 3) == 0) {
   2035    return true;
   2036  } else if (len == 0 || line[0] != '\\') {
   2037    return false;
   2038  }
   2039  if (ga->ga_len > init_growsize) {
   2040    ga_set_growsize(ga, MIN(ga->ga_len, 8000));
   2041  }
   2042  ga_concat_len(ga, line + 1, len - 1);
   2043  return true;
   2044 }
   2045 
   2046 /// Create a new script item and allocate script-local vars. @see new_script_vars
   2047 ///
   2048 /// @param  name  File name of the script. NULL for anonymous :source.
   2049 /// @param[out]  sid_out  SID of the new item.
   2050 ///
   2051 /// @return  pointer to the created script item.
   2052 scriptitem_T *new_script_item(char *const name, scid_T *const sid_out)
   2053  FUNC_ATTR_NONNULL_RET
   2054 {
   2055  static scid_T last_current_SID = 0;
   2056  const scid_T sid = ++last_current_SID;
   2057  if (sid_out != NULL) {
   2058    *sid_out = sid;
   2059  }
   2060  ga_grow(&script_items, sid - script_items.ga_len);
   2061  while (script_items.ga_len < sid) {
   2062    scriptitem_T *si = xcalloc(1, sizeof(scriptitem_T));
   2063    script_items.ga_len++;
   2064    SCRIPT_ITEM(script_items.ga_len) = si;
   2065    si->sn_name = NULL;
   2066 
   2067    // Allocate the local script variables to use for this script.
   2068    new_script_vars(script_items.ga_len);
   2069 
   2070    si->sn_prof_on = false;
   2071  }
   2072  SCRIPT_ITEM(sid)->sn_name = name;
   2073  return SCRIPT_ITEM(sid);
   2074 }
   2075 
   2076 /// Initialization for sourcing lines from the current buffer. Reads all the
   2077 /// lines from the buffer and stores it in the cookie grow array.
   2078 /// Returns a pointer to the name ":source buffer=<n>" on success and NULL on failure.
   2079 static char *do_source_buffer_init(source_cookie_T *sp, const exarg_T *eap, bool ex_lua)
   2080  FUNC_ATTR_NONNULL_ALL
   2081 {
   2082  if (curbuf == NULL) {
   2083    return NULL;
   2084  }
   2085 
   2086  char *fname;
   2087  if (curbuf->b_ffname != NULL) {
   2088    fname = xstrdup(curbuf->b_ffname);
   2089  } else {
   2090    if (ex_lua) {
   2091      // Use ":{range}lua buffer=<num>" as the script name
   2092      snprintf(IObuff, IOSIZE, ":{range}lua buffer=%d", curbuf->b_fnum);
   2093    } else {
   2094      // Use ":source buffer=<num>" as the script name
   2095      snprintf(IObuff, IOSIZE, ":source buffer=%d", curbuf->b_fnum);
   2096    }
   2097    fname = xstrdup(IObuff);
   2098  }
   2099 
   2100  ga_init(&sp->buflines, sizeof(char *), 100);
   2101  // Copy the lines from the buffer into a grow array
   2102  for (linenr_T curr_lnum = eap->line1; curr_lnum <= eap->line2; curr_lnum++) {
   2103    GA_APPEND(char *, &sp->buflines, xstrdup(ml_get(curr_lnum)));
   2104  }
   2105  sp->buf_lnum = 0;
   2106  sp->source_from_buf_or_str = true;
   2107  // When sourcing a range of lines from a buffer, use buffer line number.
   2108  sp->sourcing_lnum = eap->line1 - 1;
   2109 
   2110  return fname;
   2111 }
   2112 
   2113 /// Initialization for sourcing lines from a string. Reads all the
   2114 /// lines from the string and stores it in the cookie grow array.
   2115 static void do_source_str_init(source_cookie_T *sp, const char *str)
   2116  FUNC_ATTR_NONNULL_ALL
   2117 {
   2118  ga_init(&sp->buflines, sizeof(char *), 100);
   2119  // Copy the lines from the string into a grow array
   2120  while (*str != NUL) {
   2121    const char *eol = skip_to_newline(str);
   2122    GA_APPEND(char *, &sp->buflines, xmemdupz(str, (size_t)(eol - str)));
   2123    str = eol + (*eol != NUL);
   2124  }
   2125  sp->buf_lnum = 0;
   2126  sp->source_from_buf_or_str = true;
   2127 }
   2128 
   2129 void cmd_source_buffer(const exarg_T *const eap, bool ex_lua)
   2130  FUNC_ATTR_NONNULL_ALL
   2131 {
   2132  do_source_ext(NULL, false, DOSO_NONE, NULL, eap, ex_lua, NULL);
   2133 }
   2134 
   2135 /// Executes lines in `str` as Ex commands.
   2136 ///
   2137 /// @see do_source_ext()
   2138 int do_source_str(const char *str, char *traceback_name)
   2139  FUNC_ATTR_NONNULL_ALL
   2140 {
   2141  char *const sourcing_name = SOURCING_NAME;
   2142  const linenr_T sourcing_lnum = SOURCING_LNUM;
   2143  char sname_buf[256];
   2144  if (sourcing_name != NULL) {
   2145    snprintf(sname_buf, sizeof(sname_buf), "%s called at %s:%" PRIdLINENR,
   2146             traceback_name, sourcing_name, sourcing_lnum);
   2147    traceback_name = sname_buf;
   2148  }
   2149  return do_source_ext(traceback_name, false, DOSO_NONE, NULL, NULL, false, str);
   2150 }
   2151 
   2152 /// When fname is a .lua file nlua_exec_file() is invoked to source it.
   2153 /// Otherwise reads the file `fname` and executes its lines as Ex commands.
   2154 ///
   2155 /// This function may be called recursively!
   2156 ///
   2157 /// @see do_source_str
   2158 ///
   2159 /// @param fname        if NULL, source from the current buffer
   2160 /// @param check_other  check for .vimrc and _vimrc
   2161 /// @param is_vimrc     DOSO_ value
   2162 /// @param ret_sid      if not NULL and we loaded the script before, don't load it again
   2163 /// @param eap          used when sourcing lines from a buffer instead of a file
   2164 /// @param str          if not NULL, source from the given string
   2165 ///
   2166 /// @return  FAIL if file could not be opened, OK otherwise
   2167 ///
   2168 /// If a scriptitem_T was found or created "*ret_sid" is set to the SID.
   2169 static int do_source_ext(char *const fname, const bool check_other, const int is_vimrc,
   2170                         int *const ret_sid, const exarg_T *const eap, const bool ex_lua,
   2171                         const char *const str)
   2172 {
   2173  source_cookie_T cookie;
   2174  uint8_t *firstline = NULL;
   2175  int retval = FAIL;
   2176  int save_debug_break_level = debug_break_level;
   2177  scriptitem_T *si = NULL;
   2178  proftime_T wait_start;
   2179  bool trigger_source_post = false;
   2180  ESTACK_CHECK_DECLARATION;
   2181 
   2182  CLEAR_FIELD(cookie);
   2183  char *fname_exp = NULL;
   2184  if (fname == NULL) {
   2185    assert(str == NULL);
   2186    // sourcing lines from a buffer
   2187    fname_exp = do_source_buffer_init(&cookie, eap, ex_lua);
   2188    if (fname_exp == NULL) {
   2189      return FAIL;
   2190    }
   2191  } else if (str != NULL) {
   2192    do_source_str_init(&cookie, str);
   2193    fname_exp = xstrdup(fname);
   2194  } else {
   2195    char *p = expand_env_save(fname);
   2196    if (p == NULL) {
   2197      return retval;
   2198    }
   2199    fname_exp = fix_fname(p);
   2200    xfree(p);
   2201    if (fname_exp == NULL) {
   2202      return retval;
   2203    }
   2204    if (os_isdir(fname_exp)) {
   2205      smsg(0, _("Cannot source a directory: \"%s\""), fname);
   2206      goto theend;
   2207    }
   2208  }
   2209 
   2210  // See if we loaded this script before.
   2211  int sid = str != NULL ? SID_STR : find_script_by_name(fname_exp);
   2212  if (sid > 0 && ret_sid != NULL) {
   2213    // Already loaded and no need to load again, return here.
   2214    *ret_sid = sid;
   2215    retval = OK;
   2216    goto theend;
   2217  }
   2218 
   2219  if (str == NULL) {
   2220    // Apply SourceCmd autocommands, they should get the file and source it.
   2221    if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
   2222        && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
   2223                          false, curbuf)) {
   2224      retval = aborting() ? FAIL : OK;
   2225      if (retval == OK) {
   2226        // Apply SourcePost autocommands.
   2227        apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, false, curbuf);
   2228      }
   2229      goto theend;
   2230    }
   2231 
   2232    // Apply SourcePre autocommands, they may get the file.
   2233    apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, false, curbuf);
   2234  }
   2235 
   2236  if (!cookie.source_from_buf_or_str) {
   2237    cookie.fp = fopen_noinh_readbin(fname_exp);
   2238  }
   2239  if (cookie.fp == NULL && check_other) {
   2240    // Try again, replacing file name ".nvimrc" by "_nvimrc" or vice versa,
   2241    // and ".exrc" by "_exrc" or vice versa.
   2242    char *p = path_tail(fname_exp);
   2243    if ((*p == '.' || *p == '_')
   2244        && (STRICMP(p + 1, "nvimrc") == 0 || STRICMP(p + 1, "exrc") == 0)) {
   2245      *p = (*p == '_') ? '.' : '_';
   2246      cookie.fp = fopen_noinh_readbin(fname_exp);
   2247    }
   2248  }
   2249 
   2250  if (cookie.fp == NULL && !cookie.source_from_buf_or_str) {
   2251    if (p_verbose > 1) {
   2252      verbose_enter();
   2253      if (SOURCING_NAME == NULL) {
   2254        smsg(0, _("could not source \"%s\""), fname);
   2255      } else {
   2256        smsg(0, _("line %" PRId64 ": could not source \"%s\""),
   2257             (int64_t)SOURCING_LNUM, fname);
   2258      }
   2259      verbose_leave();
   2260    }
   2261    goto theend;
   2262  }
   2263 
   2264  // The file exists.
   2265  // - In verbose mode, give a message.
   2266  // - For a vimrc file, may want to call vimrc_found().
   2267  if (p_verbose > 1) {
   2268    verbose_enter();
   2269    if (SOURCING_NAME == NULL) {
   2270      smsg(0, _("sourcing \"%s\""), fname);
   2271    } else {
   2272      smsg(0, _("line %" PRId64 ": sourcing \"%s\""), (int64_t)SOURCING_LNUM, fname);
   2273    }
   2274    verbose_leave();
   2275  }
   2276  if (is_vimrc == DOSO_VIMRC) {
   2277    vimrc_found(fname_exp, "MYVIMRC");
   2278  }
   2279 
   2280 #ifdef USE_CRNL
   2281  // If no automatic file format: Set default to CR-NL.
   2282  if (*p_ffs == NUL) {
   2283    cookie.fileformat = EOL_DOS;
   2284  } else {
   2285    cookie.fileformat = EOL_UNKNOWN;
   2286  }
   2287 #endif
   2288 
   2289  // Check if this script has a breakpoint.
   2290  cookie.breakpoint = dbg_find_breakpoint(true, fname_exp, 0);
   2291  cookie.fname = fname_exp;
   2292  cookie.dbg_tick = debug_tick;
   2293 
   2294  cookie.level = ex_nesting_level;
   2295 
   2296  // start measuring script load time if --startuptime was passed and
   2297  // time_fd was successfully opened afterwards.
   2298  proftime_T rel_time;
   2299  proftime_T start_time;
   2300  FILE * const l_time_fd = time_fd;
   2301  if (l_time_fd != NULL) {
   2302    time_push(&rel_time, &start_time);
   2303  }
   2304 
   2305  const int l_do_profiling = do_profiling;
   2306  if (l_do_profiling == PROF_YES) {
   2307    prof_child_enter(&wait_start);    // entering a child now
   2308  }
   2309 
   2310  // Don't use local function variables, if called from a function.
   2311  // Also starts profiling timer for nested script.
   2312  funccal_entry_T funccalp_entry;
   2313  save_funccal(&funccalp_entry);
   2314 
   2315  const sctx_T save_current_sctx = current_sctx;
   2316 
   2317  // Always use a new sequence number.
   2318  current_sctx.sc_seq = ++last_current_SID_seq;
   2319 
   2320  if (sid > 0) {
   2321    // loading the same script again
   2322    si = SCRIPT_ITEM(sid);
   2323  } else if (str == NULL) {
   2324    // It's new, generate a new SID.
   2325    si = new_script_item(fname_exp, &sid);
   2326    si->sn_lua = path_with_extension(fname_exp, "lua");
   2327    fname_exp = xstrdup(si->sn_name);  // used for autocmd
   2328    if (ret_sid != NULL) {
   2329      *ret_sid = sid;
   2330    }
   2331  }
   2332  // Sourcing a string doesn't allocate a script item immediately.
   2333  assert((si != NULL) == (str == NULL));
   2334 
   2335  // Don't change sc_sid to SID_STR when sourcing a string from a Lua script,
   2336  // as keeping the current sc_sid allows more useful :verbose messages.
   2337  if (str == NULL || !script_is_lua(current_sctx.sc_sid)) {
   2338    current_sctx.sc_sid = sid;
   2339    current_sctx.sc_lnum = 0;
   2340  }
   2341 
   2342  // Keep the sourcing name/lnum, for recursive calls.
   2343  estack_push(ETYPE_SCRIPT, si != NULL ? si->sn_name : fname_exp, 0);
   2344  ESTACK_CHECK_SETUP;
   2345 
   2346  if (l_do_profiling == PROF_YES && si != NULL) {
   2347    bool forceit = false;
   2348 
   2349    // Check if we do profiling for this script.
   2350    if (!si->sn_prof_on && has_profiling(true, si->sn_name, &forceit)) {
   2351      profile_init(si);
   2352      si->sn_pr_force = forceit;
   2353    }
   2354    if (si->sn_prof_on) {
   2355      si->sn_pr_count++;
   2356      si->sn_pr_start = profile_start();
   2357      si->sn_pr_children = profile_zero();
   2358    }
   2359  }
   2360 
   2361  cookie.conv.vc_type = CONV_NONE;              // no conversion
   2362 
   2363  // Check if treesitter detects this range as Lua (for injections like vimdoc codeblocks)
   2364  bool ts_lua = false;
   2365  if (fname == NULL && eap != NULL && !ex_lua
   2366      && !strequal(curbuf->b_p_ft, "lua")
   2367      && !(curbuf->b_fname && path_with_extension(curbuf->b_fname, "lua"))) {
   2368    MAXSIZE_TEMP_ARRAY(args, 3);
   2369    ADD_C(args, INTEGER_OBJ(curbuf->handle));
   2370    ADD_C(args, INTEGER_OBJ(eap->line1));
   2371    ADD_C(args, INTEGER_OBJ(eap->line2));
   2372    Error err = ERROR_INIT;
   2373    Object result = NLUA_EXEC_STATIC("return require('vim._core.util').source_is_lua(...)",
   2374                                     args, kRetNilBool, NULL, &err);
   2375    if (!ERROR_SET(&err) && LUARET_TRUTHY(result)) {
   2376      ts_lua = true;
   2377    }
   2378    api_clear_error(&err);
   2379  }
   2380 
   2381  if (fname == NULL
   2382      && (ex_lua || ts_lua || strequal(curbuf->b_p_ft, "lua")
   2383          || (curbuf->b_fname && path_with_extension(curbuf->b_fname, "lua")))) {
   2384    // Source lines from the current buffer as lua
   2385    nlua_exec_ga(&cookie.buflines, fname_exp);
   2386  } else if (si != NULL && si->sn_lua) {
   2387    // Source the file as lua
   2388    nlua_exec_file(fname_exp);
   2389  } else {
   2390    // Read the first line so we can check for a UTF-8 BOM.
   2391    firstline = (uint8_t *)getsourceline(0, (void *)&cookie, 0, true);
   2392    if (firstline != NULL && strlen((char *)firstline) >= 3 && firstline[0] == 0xef
   2393        && firstline[1] == 0xbb && firstline[2] == 0xbf) {
   2394      // Found BOM; setup conversion, skip over BOM and recode the line.
   2395      convert_setup(&cookie.conv, "utf-8", p_enc);
   2396      char *p = string_convert(&cookie.conv, (char *)firstline + 3, NULL);
   2397      if (p == NULL) {
   2398        p = xstrdup((char *)firstline + 3);
   2399      }
   2400      xfree(firstline);
   2401      firstline = (uint8_t *)p;
   2402    }
   2403    // Call do_cmdline, which will call getsourceline() to get the lines.
   2404    do_cmdline((char *)firstline, getsourceline, (void *)&cookie,
   2405               DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
   2406  }
   2407  retval = OK;
   2408 
   2409  if (l_do_profiling == PROF_YES && si != NULL) {
   2410    // Get "si" again, "script_items" may have been reallocated.
   2411    si = SCRIPT_ITEM(current_sctx.sc_sid);
   2412    if (si->sn_prof_on) {
   2413      si->sn_pr_start = profile_end(si->sn_pr_start);
   2414      si->sn_pr_start = profile_sub_wait(wait_start, si->sn_pr_start);
   2415      si->sn_pr_total = profile_add(si->sn_pr_total, si->sn_pr_start);
   2416      si->sn_pr_self = profile_self(si->sn_pr_self, si->sn_pr_start,
   2417                                    si->sn_pr_children);
   2418    }
   2419  }
   2420 
   2421  if (got_int) {
   2422    emsg(_(e_interr));
   2423  }
   2424  ESTACK_CHECK_NOW;
   2425  estack_pop();
   2426  if (p_verbose > 1) {
   2427    verbose_enter();
   2428    smsg(0, _("finished sourcing %s"), fname);
   2429    if (SOURCING_NAME != NULL) {
   2430      smsg(0, _("continuing in %s"), SOURCING_NAME);
   2431    }
   2432    verbose_leave();
   2433  }
   2434 
   2435  if (l_time_fd != NULL) {
   2436    vim_snprintf(IObuff, IOSIZE, "sourcing %s", fname);
   2437    time_msg(IObuff, &start_time);
   2438    time_pop(rel_time);
   2439  }
   2440 
   2441  if (!got_int) {
   2442    trigger_source_post = true;
   2443  }
   2444 
   2445  // After a "finish" in debug mode, need to break at first command of next
   2446  // sourced file.
   2447  if (save_debug_break_level > ex_nesting_level
   2448      && debug_break_level == ex_nesting_level) {
   2449    debug_break_level++;
   2450  }
   2451 
   2452  current_sctx = save_current_sctx;
   2453  restore_funccal();
   2454  if (l_do_profiling == PROF_YES) {
   2455    prof_child_exit(&wait_start);    // leaving a child now
   2456  }
   2457  if (cookie.fp != NULL) {
   2458    fclose(cookie.fp);
   2459  }
   2460  if (cookie.source_from_buf_or_str) {
   2461    ga_clear_strings(&cookie.buflines);
   2462  }
   2463  xfree(cookie.nextline);
   2464  xfree(firstline);
   2465  convert_setup(&cookie.conv, NULL, NULL);
   2466 
   2467  if (str == NULL && trigger_source_post) {
   2468    apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, false, curbuf);
   2469  }
   2470 
   2471 theend:
   2472  xfree(fname_exp);
   2473  return retval;
   2474 }
   2475 
   2476 /// @param check_other  check for .vimrc and _vimrc
   2477 /// @param is_vimrc     DOSO_ value
   2478 int do_source(char *fname, bool check_other, int is_vimrc, int *ret_sid)
   2479 {
   2480  return do_source_ext(fname, check_other, is_vimrc, ret_sid, NULL, false, NULL);
   2481 }
   2482 
   2483 /// Checks if the script with the given script ID is a Lua script.
   2484 bool script_is_lua(scid_T sid)
   2485 {
   2486  if (sid == SID_LUA) {
   2487    return true;
   2488  }
   2489  if (!SCRIPT_ID_VALID(sid)) {
   2490    return false;
   2491  }
   2492  return SCRIPT_ITEM(sid)->sn_lua;
   2493 }
   2494 
   2495 /// Find an already loaded script "name".
   2496 /// If found returns its script ID.  If not found returns -1.
   2497 int find_script_by_name(char *name)
   2498 {
   2499  assert(script_items.ga_len >= 0);
   2500  for (int sid = script_items.ga_len; sid > 0; sid--) {
   2501    // We used to check inode here, but that doesn't work:
   2502    // - If a script is edited and written, it may get a different
   2503    //   inode number, even though to the user it is the same script.
   2504    // - If a script is deleted and another script is written, with a
   2505    //   different name, the inode may be re-used.
   2506    scriptitem_T *si = SCRIPT_ITEM(sid);
   2507    if (si->sn_name != NULL && path_fnamecmp(si->sn_name, name) == 0) {
   2508      return sid;
   2509    }
   2510  }
   2511  return -1;
   2512 }
   2513 
   2514 /// ":scriptnames"
   2515 void ex_scriptnames(exarg_T *eap)
   2516 {
   2517  if (eap->addr_count > 0 || *eap->arg != NUL) {
   2518    // :script {scriptId}: edit the script
   2519    if (eap->addr_count > 0 && !SCRIPT_ID_VALID(eap->line2)) {
   2520      emsg(_(e_invarg));
   2521    } else {
   2522      if (eap->addr_count > 0) {
   2523        eap->arg = SCRIPT_ITEM(eap->line2)->sn_name;
   2524      } else {
   2525        expand_env(eap->arg, NameBuff, MAXPATHL);
   2526        eap->arg = NameBuff;
   2527      }
   2528      do_exedit(eap, NULL);
   2529    }
   2530    return;
   2531  }
   2532 
   2533  msg_ext_set_kind("list_cmd");
   2534  for (int i = 1; i <= script_items.ga_len && !got_int; i++) {
   2535    if (SCRIPT_ITEM(i)->sn_name != NULL) {
   2536      home_replace(NULL, SCRIPT_ITEM(i)->sn_name, NameBuff, MAXPATHL, true);
   2537      vim_snprintf(IObuff, IOSIZE, "%3d: %s", i, NameBuff);
   2538      if (!message_filtered(IObuff)) {
   2539        if (msg_col > 0) {
   2540          msg_putchar('\n');
   2541        }
   2542        msg_outtrans(IObuff, 0, false);
   2543        line_breakcheck();
   2544      }
   2545    }
   2546  }
   2547 }
   2548 
   2549 #if defined(BACKSLASH_IN_FILENAME)
   2550 /// Fix slashes in the list of script names for 'shellslash'.
   2551 void scriptnames_slash_adjust(void)
   2552 {
   2553  for (int i = 1; i <= script_items.ga_len; i++) {
   2554    if (SCRIPT_ITEM(i)->sn_name != NULL) {
   2555      slash_adjust(SCRIPT_ITEM(i)->sn_name);
   2556    }
   2557  }
   2558 }
   2559 
   2560 #endif
   2561 
   2562 /// Get a pointer to a script name.  Used for ":verbose set".
   2563 /// Message appended to "Last set from "
   2564 ///
   2565 /// @param should_free  if non-NULL and the script name is a file path, call
   2566 ///                     home_replace_save() on it and set *should_free to true.
   2567 char *get_scriptname(sctx_T script_ctx, bool *should_free)
   2568 {
   2569  if (should_free != NULL) {
   2570    *should_free = false;
   2571  }
   2572 
   2573  switch (script_ctx.sc_sid) {
   2574  case SID_MODELINE:
   2575    return _("modeline");
   2576  case SID_CMDARG:
   2577    return _("--cmd argument");
   2578  case SID_CARG:
   2579    return _("-c argument");
   2580  case SID_ENV:
   2581    return _("environment variable");
   2582  case SID_ERROR:
   2583    return _("error handler");
   2584  case SID_WINLAYOUT:
   2585    return _("changed window size");
   2586  case SID_LUA:
   2587    return _("Lua");
   2588  case SID_API_CLIENT:
   2589    snprintf(IObuff, IOSIZE, _("API client (channel id %" PRIu64 ")"), script_ctx.sc_chan);
   2590    return IObuff;
   2591  case SID_STR:
   2592    return _("anonymous :source");
   2593  default: {
   2594    char *const sname = SCRIPT_ITEM(script_ctx.sc_sid)->sn_name;
   2595    if (sname == NULL) {
   2596      snprintf(IObuff, IOSIZE, _("anonymous :source (script id %d)"),
   2597               script_ctx.sc_sid);
   2598      return IObuff;
   2599    }
   2600    if (should_free != NULL) {
   2601      *should_free = true;
   2602      return home_replace_save(NULL, sname);
   2603    } else {
   2604      return sname;
   2605    }
   2606  }
   2607  }
   2608 }
   2609 
   2610 #if defined(EXITFREE)
   2611 void free_scriptnames(void)
   2612 {
   2613  profile_reset();
   2614 
   2615 # define FREE_SCRIPTNAME(item) \
   2616  do { \
   2617    scriptitem_T *_si = *(item); \
   2618    /* the variables themselves are cleared in evalvars_clear() */ \
   2619    xfree(_si->sn_vars); \
   2620    xfree(_si->sn_name); \
   2621    ga_clear(&_si->sn_prl_ga); \
   2622    xfree(_si); \
   2623  } while (0) \
   2624 
   2625  GA_DEEP_CLEAR(&script_items, scriptitem_T *, FREE_SCRIPTNAME);
   2626 }
   2627 #endif
   2628 
   2629 void free_autoload_scriptnames(void)
   2630 {
   2631  ga_clear_strings(&ga_loaded);
   2632 }
   2633 
   2634 linenr_T get_sourced_lnum(LineGetter fgetline, void *cookie)
   2635  FUNC_ATTR_PURE
   2636 {
   2637  return fgetline == getsourceline
   2638         ? ((source_cookie_T *)cookie)->sourcing_lnum
   2639         : SOURCING_LNUM;
   2640 }
   2641 
   2642 /// Return a List of script-local functions defined in the script with id "sid".
   2643 static list_T *get_script_local_funcs(scid_T sid)
   2644 {
   2645  hashtab_T *const functbl = func_tbl_get();
   2646  list_T *l = tv_list_alloc((ptrdiff_t)functbl->ht_used);
   2647 
   2648  // Iterate through all the functions in the global function hash table
   2649  // looking for functions with script ID "sid".
   2650  HASHTAB_ITER(functbl, hi, {
   2651    const ufunc_T *const fp = HI2UF(hi);
   2652    // Add functions with script id == "sid"
   2653    if (fp->uf_script_ctx.sc_sid == sid) {
   2654      const char *const name = fp->uf_name_exp != NULL ? fp->uf_name_exp : fp->uf_name;
   2655      tv_list_append_string(l, name, -1);
   2656    }
   2657  });
   2658 
   2659  return l;
   2660 }
   2661 
   2662 /// "getscriptinfo()" function
   2663 void f_getscriptinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
   2664 {
   2665  tv_list_alloc_ret(rettv, script_items.ga_len);
   2666 
   2667  if (tv_check_for_opt_dict_arg(argvars, 0) == FAIL) {
   2668    return;
   2669  }
   2670 
   2671  list_T *l = rettv->vval.v_list;
   2672 
   2673  regmatch_T regmatch = {
   2674    .regprog = NULL,
   2675    .rm_ic = p_ic,
   2676  };
   2677  bool filterpat = false;
   2678  varnumber_T sid = -1;
   2679 
   2680  char *pat = NULL;
   2681  if (argvars[0].v_type == VAR_DICT) {
   2682    dictitem_T *sid_di = tv_dict_find(argvars[0].vval.v_dict, S_LEN("sid"));
   2683    if (sid_di != NULL) {
   2684      bool error = false;
   2685      sid = tv_get_number_chk(&sid_di->di_tv, &error);
   2686      if (error) {
   2687        return;
   2688      }
   2689      if (sid <= 0) {
   2690        semsg(_(e_invargNval), "sid", tv_get_string(&sid_di->di_tv));
   2691        return;
   2692      }
   2693    } else {
   2694      pat = tv_dict_get_string(argvars[0].vval.v_dict, "name", true);
   2695      if (pat != NULL) {
   2696        regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
   2697      }
   2698      if (regmatch.regprog != NULL) {
   2699        filterpat = true;
   2700      }
   2701    }
   2702  }
   2703 
   2704  for (varnumber_T i = sid > 0 ? sid : 1;
   2705       (i == sid || sid <= 0) && i <= script_items.ga_len; i++) {
   2706    scriptitem_T *si = SCRIPT_ITEM(i);
   2707 
   2708    if (si->sn_name == NULL) {
   2709      continue;
   2710    }
   2711 
   2712    if (filterpat && !vim_regexec(&regmatch, si->sn_name, 0)) {
   2713      continue;
   2714    }
   2715 
   2716    dict_T *d = tv_dict_alloc();
   2717    tv_list_append_dict(l, d);
   2718    tv_dict_add_str(d, S_LEN("name"), si->sn_name);
   2719    tv_dict_add_nr(d, S_LEN("sid"), i);
   2720    tv_dict_add_nr(d, S_LEN("version"), 1);
   2721    // Vim9 autoload script (:h vim9-autoload), not applicable to Nvim.
   2722    tv_dict_add_bool(d, S_LEN("autoload"), false);
   2723 
   2724    // When a script ID is specified, return information about only the
   2725    // specified script, and add the script-local variables and functions.
   2726    if (sid > 0) {
   2727      dict_T *var_dict = tv_dict_copy(NULL, &si->sn_vars->sv_dict, true, get_copyID());
   2728      tv_dict_add_dict(d, S_LEN("variables"), var_dict);
   2729      tv_dict_add_list(d, S_LEN("functions"), get_script_local_funcs((scid_T)sid));
   2730    }
   2731  }
   2732 
   2733  vim_regfree(regmatch.regprog);
   2734  xfree(pat);
   2735 }
   2736 
   2737 /// Get one full line from a sourced file.
   2738 /// Called by do_cmdline() when it's called from do_source().
   2739 ///
   2740 /// @return pointer to the line in allocated memory, or NULL for end-of-file or
   2741 ///         some error.
   2742 char *getsourceline(int c, void *cookie, int indent, bool do_concat)
   2743 {
   2744  source_cookie_T *sp = (source_cookie_T *)cookie;
   2745  char *line;
   2746 
   2747  // If breakpoints have been added/deleted need to check for it.
   2748  if ((sp->dbg_tick < debug_tick) && !sp->source_from_buf_or_str) {
   2749    sp->breakpoint = dbg_find_breakpoint(true, sp->fname, SOURCING_LNUM);
   2750    sp->dbg_tick = debug_tick;
   2751  }
   2752  if (do_profiling == PROF_YES) {
   2753    script_line_end();
   2754  }
   2755  // Set the current sourcing line number.
   2756  SOURCING_LNUM = sp->sourcing_lnum + 1;
   2757  // Get current line.  If there is a read-ahead line, use it, otherwise get
   2758  // one now.  "fp" is NULL if actually using a string.
   2759  if (sp->finished || (!sp->source_from_buf_or_str && sp->fp == NULL)) {
   2760    line = NULL;
   2761  } else if (sp->nextline == NULL) {
   2762    line = get_one_sourceline(sp);
   2763  } else {
   2764    line = sp->nextline;
   2765    sp->nextline = NULL;
   2766    sp->sourcing_lnum++;
   2767  }
   2768  if (line != NULL && do_profiling == PROF_YES) {
   2769    script_line_start();
   2770  }
   2771 
   2772  // Only concatenate lines starting with a \ when 'cpoptions' doesn't
   2773  // contain the 'C' flag.
   2774  if (line != NULL && do_concat && (vim_strchr(p_cpo, CPO_CONCAT) == NULL)) {
   2775    char *p;
   2776    // compensate for the one line read-ahead
   2777    sp->sourcing_lnum--;
   2778 
   2779    // Get the next line and concatenate it when it starts with a
   2780    // backslash. We always need to read the next line, keep it in
   2781    // sp->nextline.
   2782    // Also check for a comment in between continuation lines: "\ .
   2783    sp->nextline = get_one_sourceline(sp);
   2784    if (sp->nextline != NULL
   2785        && (*(p = skipwhite(sp->nextline)) == '\\'
   2786            || (p[0] == '"' && p[1] == '\\' && p[2] == ' '))) {
   2787      garray_T ga;
   2788 
   2789      ga_init(&ga, (int)sizeof(char), 400);
   2790      ga_concat(&ga, line);
   2791      while (sp->nextline != NULL
   2792             && concat_continued_line(&ga, 400, sp->nextline, strlen(sp->nextline))) {
   2793        xfree(sp->nextline);
   2794        sp->nextline = get_one_sourceline(sp);
   2795      }
   2796      ga_append(&ga, NUL);
   2797      xfree(line);
   2798      line = ga.ga_data;
   2799    }
   2800  }
   2801 
   2802  if (line != NULL && sp->conv.vc_type != CONV_NONE) {
   2803    // Convert the encoding of the script line.
   2804    char *s = string_convert(&sp->conv, line, NULL);
   2805    if (s != NULL) {
   2806      xfree(line);
   2807      line = s;
   2808    }
   2809  }
   2810 
   2811  // Did we encounter a breakpoint?
   2812  if (!sp->source_from_buf_or_str
   2813      && sp->breakpoint != 0 && sp->breakpoint <= SOURCING_LNUM) {
   2814    dbg_breakpoint(sp->fname, SOURCING_LNUM);
   2815    // Find next breakpoint.
   2816    sp->breakpoint = dbg_find_breakpoint(true, sp->fname, SOURCING_LNUM);
   2817    sp->dbg_tick = debug_tick;
   2818  }
   2819 
   2820  return line;
   2821 }
   2822 
   2823 static char *get_one_sourceline(source_cookie_T *sp)
   2824 {
   2825  garray_T ga;
   2826  int len;
   2827  int c;
   2828  char *buf;
   2829 #ifdef USE_CRNL
   2830  bool has_cr;                           // CR-LF found
   2831 #endif
   2832  bool have_read = false;
   2833 
   2834  // use a growarray to store the sourced line
   2835  ga_init(&ga, 1, 250);
   2836 
   2837  // Loop until there is a finished line (or end-of-file).
   2838  sp->sourcing_lnum++;
   2839  while (true) {
   2840    // make room to read at least 120 (more) characters
   2841    ga_grow(&ga, 120);
   2842    if (sp->source_from_buf_or_str) {
   2843      if (sp->buf_lnum >= sp->buflines.ga_len) {
   2844        break;              // all the lines are processed
   2845      }
   2846      ga_concat(&ga, ((char **)sp->buflines.ga_data)[sp->buf_lnum]);
   2847      sp->buf_lnum++;
   2848      ga_grow(&ga, 1);
   2849      buf = (char *)ga.ga_data;
   2850      buf[ga.ga_len++] = NUL;
   2851      len = ga.ga_len;
   2852    } else {
   2853      buf = ga.ga_data;
   2854 retry:
   2855      errno = 0;
   2856      if (fgets(buf + ga.ga_len, ga.ga_maxlen - ga.ga_len, sp->fp) == NULL) {
   2857        if (errno == EINTR) {
   2858          goto retry;
   2859        }
   2860        break;
   2861      }
   2862      len = ga.ga_len + (int)strlen(buf + ga.ga_len);
   2863    }
   2864 #ifdef USE_CRNL
   2865    // Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
   2866    // CTRL-Z by its own, or after a NL.
   2867    if ((len == 1 || (len >= 2 && buf[len - 2] == '\n'))
   2868        && sp->fileformat == EOL_DOS
   2869        && buf[len - 1] == Ctrl_Z) {
   2870      buf[len - 1] = NUL;
   2871      break;
   2872    }
   2873 #endif
   2874 
   2875    have_read = true;
   2876    ga.ga_len = len;
   2877 
   2878    // If the line was longer than the buffer, read more.
   2879    if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n') {
   2880      continue;
   2881    }
   2882 
   2883    if (len >= 1 && buf[len - 1] == '\n') {     // remove trailing NL
   2884 #ifdef USE_CRNL
   2885      has_cr = (len >= 2 && buf[len - 2] == '\r');
   2886      if (sp->fileformat == EOL_UNKNOWN) {
   2887        if (has_cr) {
   2888          sp->fileformat = EOL_DOS;
   2889        } else {
   2890          sp->fileformat = EOL_UNIX;
   2891        }
   2892      }
   2893 
   2894      if (sp->fileformat == EOL_DOS) {
   2895        if (has_cr) {               // replace trailing CR
   2896          buf[len - 2] = '\n';
   2897          len--;
   2898          ga.ga_len--;
   2899        } else {          // lines like ":map xx yy^M" will have failed
   2900          if (!sp->error) {
   2901            msg_source(HL_ATTR(HLF_W));
   2902            emsg(_("W15: Warning: Wrong line separator, ^M may be missing"));
   2903          }
   2904          sp->error = true;
   2905          sp->fileformat = EOL_UNIX;
   2906        }
   2907      }
   2908 #endif
   2909      // The '\n' is escaped if there is an odd number of ^V's just
   2910      // before it, first set "c" just before the 'V's and then check
   2911      // len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo
   2912      for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--) {}
   2913      if ((len & 1) != (c & 1)) {       // escaped NL, read more
   2914        sp->sourcing_lnum++;
   2915        continue;
   2916      }
   2917 
   2918      buf[len - 1] = NUL;               // remove the NL
   2919    }
   2920 
   2921    // Check for ^C here now and then, so recursive :so can be broken.
   2922    line_breakcheck();
   2923    break;
   2924  }
   2925 
   2926  if (have_read) {
   2927    return ga.ga_data;
   2928  }
   2929 
   2930  xfree(ga.ga_data);
   2931  return NULL;
   2932 }
   2933 
   2934 /// Returns true if sourcing a script either from a file or a buffer or a string.
   2935 /// Otherwise returns false.
   2936 int sourcing_a_script(exarg_T *eap)
   2937 {
   2938  return getline_equal(eap->ea_getline, eap->cookie, getsourceline);
   2939 }
   2940 
   2941 /// ":scriptencoding": Set encoding conversion for a sourced script.
   2942 /// Without the multi-byte feature it's simply ignored.
   2943 void ex_scriptencoding(exarg_T *eap)
   2944 {
   2945  if (!sourcing_a_script(eap)) {
   2946    emsg(_("E167: :scriptencoding used outside of a sourced file"));
   2947    return;
   2948  }
   2949 
   2950  char *name = (*eap->arg != NUL) ? enc_canonize(eap->arg) : eap->arg;
   2951 
   2952  // Setup for conversion from the specified encoding to 'encoding'.
   2953  source_cookie_T *sp = (source_cookie_T *)getline_cookie(eap->ea_getline, eap->cookie);
   2954  convert_setup(&sp->conv, name, p_enc);
   2955 
   2956  if (name != eap->arg) {
   2957    xfree(name);
   2958  }
   2959 }
   2960 
   2961 /// ":finish": Mark a sourced file as finished.
   2962 void ex_finish(exarg_T *eap)
   2963 {
   2964  if (sourcing_a_script(eap)) {
   2965    do_finish(eap, false);
   2966  } else {
   2967    emsg(_("E168: :finish used outside of a sourced file"));
   2968  }
   2969 }
   2970 
   2971 /// Mark a sourced file as finished.  Possibly makes the ":finish" pending.
   2972 /// Also called for a pending finish at the ":endtry" or after returning from
   2973 /// an extra do_cmdline().  "reanimate" is used in the latter case.
   2974 void do_finish(exarg_T *eap, bool reanimate)
   2975 {
   2976  if (reanimate) {
   2977    ((source_cookie_T *)getline_cookie(eap->ea_getline, eap->cookie))->finished = false;
   2978  }
   2979 
   2980  // Cleanup (and deactivate) conditionals, but stop when a try conditional
   2981  // not in its finally clause (which then is to be executed next) is found.
   2982  // In this case, make the ":finish" pending for execution at the ":endtry".
   2983  // Otherwise, finish normally.
   2984  int idx = cleanup_conditionals(eap->cstack, 0, true);
   2985  if (idx >= 0) {
   2986    eap->cstack->cs_pending[idx] = CSTP_FINISH;
   2987    report_make_pending(CSTP_FINISH, NULL);
   2988  } else {
   2989    ((source_cookie_T *)getline_cookie(eap->ea_getline, eap->cookie))->finished = true;
   2990  }
   2991 }
   2992 
   2993 /// @return  true when a sourced file had the ":finish" command: Don't give error
   2994 ///          message for missing ":endif".
   2995 ///          false when not sourcing a file.
   2996 bool source_finished(LineGetter fgetline, void *cookie)
   2997 {
   2998  return getline_equal(fgetline, cookie, getsourceline)
   2999         && ((source_cookie_T *)getline_cookie(fgetline, cookie))->finished;
   3000 }
   3001 
   3002 /// Return the autoload script name for a function or variable name
   3003 /// Caller must make sure that "name" contains AUTOLOAD_CHAR.
   3004 ///
   3005 /// @param[in]  name  Variable/function name.
   3006 /// @param[in]  name_len  Name length.
   3007 ///
   3008 /// @return [allocated] autoload script name.
   3009 char *autoload_name(const char *const name, const size_t name_len)
   3010  FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT
   3011 {
   3012  // Get the script file name: replace '#' with '/', append ".vim".
   3013  char *const scriptname = xmalloc(name_len + sizeof("autoload/.vim"));
   3014  memcpy(scriptname, "autoload/", sizeof("autoload/") - 1);
   3015  memcpy(scriptname + sizeof("autoload/") - 1, name, name_len);
   3016  size_t auchar_idx = 0;
   3017  for (size_t i = sizeof("autoload/") - 1;
   3018       i - sizeof("autoload/") + 1 < name_len;
   3019       i++) {
   3020    if (scriptname[i] == AUTOLOAD_CHAR) {
   3021      scriptname[i] = '/';
   3022      auchar_idx = i;
   3023    }
   3024  }
   3025  memcpy(scriptname + auchar_idx, ".vim", sizeof(".vim"));
   3026 
   3027  return scriptname;
   3028 }
   3029 
   3030 /// If name has a package name try autoloading the script for it
   3031 ///
   3032 /// @param[in]  name  Variable/function name.
   3033 /// @param[in]  name_len  Name length.
   3034 /// @param[in]  reload  If true, load script again when already loaded.
   3035 ///
   3036 /// @return true if a package was loaded.
   3037 bool script_autoload(const char *const name, const size_t name_len, const bool reload)
   3038 {
   3039  // If there is no '#' after name[0] there is no package name.
   3040  const char *p = memchr(name, AUTOLOAD_CHAR, name_len);
   3041  if (p == NULL || p == name) {
   3042    return false;
   3043  }
   3044 
   3045  bool ret = false;
   3046  char *tofree = autoload_name(name, name_len);
   3047  char *scriptname = tofree;
   3048 
   3049  // Find the name in the list of previously loaded package names.  Skip
   3050  // "autoload/", it's always the same.
   3051  int i = 0;
   3052  for (; i < ga_loaded.ga_len; i++) {
   3053    if (strcmp(((char **)ga_loaded.ga_data)[i] + 9, scriptname + 9) == 0) {
   3054      break;
   3055    }
   3056  }
   3057  if (!reload && i < ga_loaded.ga_len) {
   3058    ret = false;  // Was loaded already.
   3059  } else {
   3060    // Remember the name if it wasn't loaded already.
   3061    if (i == ga_loaded.ga_len) {
   3062      GA_APPEND(char *, &ga_loaded, scriptname);
   3063      tofree = NULL;
   3064    }
   3065 
   3066    // Try loading the package from $VIMRUNTIME/autoload/<name>.vim
   3067    // Use "ret_sid" to avoid loading the same script again.
   3068    int ret_sid;
   3069    if (do_in_runtimepath(scriptname, DIP_START, source_callback, &ret_sid) == OK) {
   3070      ret = true;
   3071    }
   3072  }
   3073 
   3074  xfree(tofree);
   3075  return ret;
   3076 }