diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/nvim/buffer.c | 4 | ||||
| -rw-r--r-- | src/nvim/eval.c | 7 | ||||
| -rw-r--r-- | src/nvim/os/fs.c | 130 | 
3 files changed, 136 insertions, 5 deletions
| diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 438a85dd5d..c934d44e70 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -4030,8 +4030,8 @@ void fname_expand(buf_T *buf, char_u **ffname, char_u **sfname)    if (!buf->b_p_bin) {      char_u  *rfname; -    /* If the file name is a shortcut file, use the file it links to. */ -    rfname = mch_resolve_shortcut(*ffname); +    // If the file name is a shortcut file, use the file it links to. +    rfname = os_resolve_shortcut(*ffname);      if (rfname != NULL) {        xfree(*ffname);        *ffname = rfname; diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 824b298592..7deb1c1bbb 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -13592,11 +13592,12 @@ static void f_resolve(typval_T *argvars, typval_T *rettv)    {      char_u  *v = NULL; -    v = mch_resolve_shortcut(p); -    if (v != NULL) +    v = os_resolve_shortcut(p); +    if (v != NULL) {        rettv->vval.v_string = v; -    else +    } else {        rettv->vval.v_string = vim_strsave(p); +    }    }  #else  # ifdef HAVE_READLINK diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 8c1c80bfad..2199b83108 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -929,3 +929,133 @@ bool os_fileid_equal_fileinfo(const FileID *file_id,           && file_id->device_id == file_info->stat.st_dev;  } +#ifdef WIN32 +# include <shlobj.h> +/// When "fname" is the name of a shortcut (*.lnk) resolve the file it points +/// to and return that name in allocated memory. +/// Otherwise NULL is returned. +char_u * os_resolve_shortcut(char_u *fname) +{ +  HRESULT hr; +  IShellLink *psl = NULL; +  IPersistFile *ppf = NULL; +  OLECHAR wsz[MAX_PATH]; +  WIN32_FIND_DATA ffd;     // we get those free of charge +  CHAR buf[MAX_PATH];      // could have simply reused 'wsz'... +  char_u *rfname = NULL; +  int len; +  IShellLinkW		*pslw = NULL; +  WIN32_FIND_DATAW	ffdw;  // we get those free of charge + +  // Check if the file name ends in ".lnk". Avoid calling CoCreateInstance(), +  // it's quite slow. +  if (fname == NULL) { +    return rfname; +  } +  len = (int)STRLEN(fname); +  if (len <= 4 || STRNICMP(fname + len - 4, ".lnk", 4) != 0) { +    return rfname; +  } + +  CoInitialize(NULL); + +# ifdef FEAT_MBYTE +  if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) { +    // create a link manager object and request its interface +    hr = CoCreateInstance( +        &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, +        &IID_IShellLinkW, (void**)&pslw); +    if (hr == S_OK) +    { +      WCHAR	*p = enc_to_utf16(fname, NULL); + +      if (p != NULL) { +        // Get a pointer to the IPersistFile interface. +        hr = pslw->lpVtbl->QueryInterface( +            pslw, &IID_IPersistFile, (void**)&ppf); +        if (hr != S_OK) +          goto shortcut_errorw; + +        // "load" the name and resolve the link +        hr = ppf->lpVtbl->Load(ppf, p, STGM_READ); +        if (hr != S_OK) { +          goto shortcut_errorw; +        } + +#  if 0  // This makes Vim wait a long time if the target does not exist. +        hr = pslw->lpVtbl->Resolve(pslw, NULL, SLR_NO_UI); +        if (hr != S_OK) { +          goto shortcut_errorw; +        } +#  endif + +        // Get the path to the link target. +        ZeroMemory(wsz, MAX_PATH * sizeof(WCHAR)); +        hr = pslw->lpVtbl->GetPath(pslw, wsz, MAX_PATH, &ffdw, 0); +        if (hr == S_OK && wsz[0] != NUL) { +          rfname = utf16_to_enc(wsz, NULL); +        } + +shortcut_errorw: +        xfree(p); +        goto shortcut_end; +      } +    } +    /* Retry with non-wide function (for Windows 98). */ +  } +# endif + +  // create a link manager object and request its interface +  hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, +                        &IID_IShellLink, (void**)&psl); +  if (hr != S_OK) { +    goto shortcut_end; +  } + +  // Get a pointer to the IPersistFile interface. +  hr = psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, (void**)&ppf); +  if (hr != S_OK) { +    goto shortcut_end; +  } + +  // full path string must be in Unicode. +  MultiByteToWideChar(CP_ACP, 0, (LPCSTR)fname, -1, wsz, MAX_PATH); + +  // "load" the name and resolve the link +  hr = ppf->lpVtbl->Load(ppf, wsz, STGM_READ); +  if (hr != S_OK) { +    goto shortcut_end; +  } + +# if 0  // This makes Vim wait a long time if the target doesn't exist. +  hr = psl->lpVtbl->Resolve(psl, NULL, SLR_NO_UI); +  if (hr != S_OK) { +    goto shortcut_end; +  } +# endif + +  // Get the path to the link target. +  ZeroMemory(buf, MAX_PATH); +  hr = psl->lpVtbl->GetPath(psl, buf, MAX_PATH, &ffd, 0); +  if (hr == S_OK && buf[0] != NUL) { +    rfname = vim_strsave((char_u *)buf); +  } + +shortcut_end: +  // Release all interface pointers (both belong to the same object) +  if (ppf != NULL) { +    ppf->lpVtbl->Release(ppf); +  } +  if (psl != NULL) { +    psl->lpVtbl->Release(psl); +  } +# ifdef FEAT_MBYTE +  if (pslw != NULL) { +    pslw->lpVtbl->Release(pslw); +  } +# endif + +  CoUninitialize(); +  return rfname; +} +#endif | 
