44-- z.lua - a cd command that learns, by skywind 2018, 2019
55-- Licensed under MIT license.
66--
7- -- Version 1.5.11 , Last Modified: 2019/03/02 11:37
7+ -- Version 1.6.0 , Last Modified: 2019/03/04 14:47
88--
99-- * 10x faster than fasd and autojump, 3x faster than z.sh
1010-- * available for posix shells: bash, zsh, sh, ash, dash, busybox
@@ -302,10 +302,107 @@ function os.log(text)
302302end
303303
304304
305+ ---- -------------------------------------------------------------------
306+ -- ffi optimize (luajit has builtin ffi module)
307+ ---- -------------------------------------------------------------------
308+ os .native = {}
309+ os .native .status , os .native .ffi = pcall (require , " ffi" )
310+ if os .native .status then
311+ local ffi = os .native .ffi
312+ if windows then
313+ ffi .cdef [[
314+ int GetFullPathNameA (const char * name , uint32_t size , char * out , char ** name );
315+ int ReplaceFileA (const char * dstname , const char * srcname , void * , uint32_t , void * , void * );
316+ uint32_t GetTickCount (void );
317+ uint32_t GetFileAttributesA (const char * name );
318+ uint32_t GetCurrentDirectoryA (uint32_t size , char * ptr );
319+ ]]
320+ local kernel32 = ffi .load (' kernel32.dll' )
321+ local buffer = ffi .new (' char[?]' , 300 )
322+ local INVALID_FILE_ATTRIBUTES = 0xffffffff
323+ local FILE_ATTRIBUTE_DIRECTORY = 0x10
324+ os .native .kernel32 = kernel32
325+ function os .native .GetFullPathName (name )
326+ local hr = kernel32 .GetFullPathNameA (name , 290 , buffer , nil )
327+ return (hr > 0 ) and ffi .string (buffer , hr ) or nil
328+ end
329+ function os .native .ReplaceFile (replaced , replacement )
330+ local hr = kernel32 .ReplaceFileA (replaced , replacement , nil , 2 , nil , nil )
331+ return (hr ~= 0 ) and true or false
332+ end
333+ function os .native .GetTickCount ()
334+ return kernel32 .GetTickCount ()
335+ end
336+ function os .native .GetFileAttributes (name )
337+ return kernel32 .GetFileAttributesA (name )
338+ end
339+ function os .native .exists (name )
340+ local attr = os .native .GetFileAttributes (name )
341+ return attr ~= INVALID_FILE_ATTRIBUTES
342+ end
343+ function os .native .isdir (name )
344+ local attr = os .native .GetFileAttributes (name )
345+ local isdir = FILE_ATTRIBUTE_DIRECTORY
346+ if attr == INVALID_FILE_ATTRIBUTES then
347+ return false
348+ end
349+ return (attr % (2 * isdir )) >= isdir
350+ end
351+ function os .native .getcwd ()
352+ local hr = kernel32 .GetCurrentDirectoryA (299 , buffer )
353+ if hr <= 0 then return nil end
354+ return ffi .string (buffer , hr )
355+ end
356+ else
357+ ffi .cdef [[
358+ typedef struct { long tv_sec ; long tv_usec ; } timeval;
359+ int gettimeofday (timeval * tv , void * tz );
360+ int access (const char * name , int mode );
361+ char *realpath (const char * path , char * resolve );
362+ char *getcwd (char * buf , size_t size );
363+ ]]
364+ local timeval = ffi .new (' timeval[?]' , 1 )
365+ local buffer = ffi .new (' char[?]' , 4100 )
366+ function os .native .gettimeofday ()
367+ local hr = ffi .C .gettimeofday (timeval , nil )
368+ local sec = tonumber (timeval [0 ].tv_sec )
369+ local usec = tonumber (timeval [0 ].tv_usec )
370+ return sec + (usec * 0.000001 )
371+ end
372+ function os .native .access (name , mode )
373+ return ffi .C .access (name , mode )
374+ end
375+ function os .native .realpath (name )
376+ local path = ffi .C .realpath (name , buffer )
377+ return (path ~= nil ) and ffi .string (buffer ) or nil
378+ end
379+ function os .native .getcwd ()
380+ local hr = ffi .C .getcwd (buffer , 4099 )
381+ return hr ~= nil and ffi .string (buffer ) or nil
382+ end
383+ end
384+ function os .native .tickcount ()
385+ if windows then
386+ return os .native .GetTickCount ()
387+ else
388+ return math.floor (os .native .gettimeofday () * 1000 )
389+ end
390+ end
391+ os .native .init = true
392+ end
393+
394+
305395---- -------------------------------------------------------------------
306396-- get current path
307397---- -------------------------------------------------------------------
308398function os .pwd ()
399+ if os .native and os .native .getcwd then
400+ local hr = os .native .getcwd ()
401+ if hr then return hr end
402+ end
403+ if os .getcwd then
404+ return os .getcwd ()
405+ end
309406 if windows then
310407 local fp = io.popen (' cd' )
311408 if fp == nil then
372469---- -------------------------------------------------------------------
373470function os .path .abspath (path )
374471 if path == ' ' then path = ' .' end
472+ if os .native and os .native .GetFullPathName then
473+ local test = os .native .GetFullPathName (path )
474+ if test then return test end
475+ end
375476 if windows then
376477 local script = ' FOR /f "delims=" %%i IN ("%s") DO @echo %%~fi'
377478 local script = string.format (script , path )
@@ -429,9 +530,15 @@ function os.path.isdir(pathname)
429530 return true
430531 end
431532 end
533+ if os .native and os .native .isdir then
534+ return os .native .isdir (pathname )
535+ end
536+ if clink and os .isdir then
537+ return os .isdir (pathname )
538+ end
432539 local name = pathname
433540 if (not name :endswith (' /' )) and (not name :endswith (' \\ ' )) then
434- name = name .. ' / '
541+ name = name .. os . path . sep
435542 end
436543 return os .path .exists (name )
437544end
@@ -871,6 +978,9 @@ function math.random_init()
871978 seed = seed .. rnd
872979 end
873980 seed = seed .. tostring (os.clock () * 10000000 )
981+ if os .native and os .native .tickcount then
982+ seed = seed .. tostring (os .native .tickcount ())
983+ end
874984 local number = 0
875985 for i = 1 , seed :len () do
876986 local k = string.byte (seed :sub (i , i ))
@@ -960,20 +1070,29 @@ function data_save(filename, M)
9601070 local tmpname = nil
9611071 local i
9621072 filename = os .path .expand (filename )
963- if windows then
964- fp = io.open (filename , ' w' )
965- else
966- math .random_init ()
967- while true do
968- tmpname = filename .. ' .' .. tostring (os.time ())
1073+ math .random_init ()
1074+ while true do
1075+ tmpname = filename .. ' .' .. tostring (os.time ())
1076+ if os .native and os .native .tickcount then
1077+ local key = os .native .tickcount () % 1000
1078+ tmpname = tmpname .. string.format (' %03d' , key )
1079+ tmpname = tmpname .. math .random_string (5 )
1080+ else
9691081 tmpname = tmpname .. math .random_string (8 )
970- local rnd = os.getenv (' _ZL_RANDOM' )
971- tmpname = tmpname .. ' ' .. (rnd and rnd or ' ' )
972- if not os .path .exists (tmpname ) then
973- -- print('tmpname: '..tmpname)
974- break
975- end
9761082 end
1083+ if not os .path .exists (tmpname ) then
1084+ -- print('tmpname: '..tmpname)
1085+ break
1086+ end
1087+ end
1088+ if windows then
1089+ if os .native and os .native .ReplaceFile then
1090+ fp = io.open (tmpname , ' w' )
1091+ else
1092+ fp = io.open (filename , ' w' )
1093+ tmpname = nil
1094+ end
1095+ else
9771096 fp = io.open (tmpname , ' w' )
9781097 end
9791098 if fp == nil then
@@ -986,7 +1105,11 @@ function data_save(filename, M)
9861105 end
9871106 fp :close ()
9881107 if tmpname ~= nil then
989- os.rename (tmpname , filename )
1108+ if windows then
1109+ os .native .ReplaceFile (filename , tmpname )
1110+ else
1111+ os.rename (tmpname , filename )
1112+ end
9901113 os.remove (tmpname )
9911114 end
9921115 return true
0 commit comments