4
4
-- z.lua - a cd command that learns, by skywind 2018, 2019
5
5
-- Licensed under MIT license.
6
6
--
7
- -- Version 1.5.11 , Last Modified: 2019/03/02 11:37
7
+ -- Version 1.6.0 , Last Modified: 2019/03/04 14:47
8
8
--
9
9
-- * 10x faster than fasd and autojump, 3x faster than z.sh
10
10
-- * available for posix shells: bash, zsh, sh, ash, dash, busybox
@@ -302,10 +302,107 @@ function os.log(text)
302
302
end
303
303
304
304
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
+
305
395
---- -------------------------------------------------------------------
306
396
-- get current path
307
397
---- -------------------------------------------------------------------
308
398
function 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
309
406
if windows then
310
407
local fp = io.popen (' cd' )
311
408
if fp == nil then
372
469
---- -------------------------------------------------------------------
373
470
function os .path .abspath (path )
374
471
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
375
476
if windows then
376
477
local script = ' FOR /f "delims=" %%i IN ("%s") DO @echo %%~fi'
377
478
local script = string.format (script , path )
@@ -429,9 +530,15 @@ function os.path.isdir(pathname)
429
530
return true
430
531
end
431
532
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
432
539
local name = pathname
433
540
if (not name :endswith (' /' )) and (not name :endswith (' \\ ' )) then
434
- name = name .. ' / '
541
+ name = name .. os . path . sep
435
542
end
436
543
return os .path .exists (name )
437
544
end
@@ -871,6 +978,9 @@ function math.random_init()
871
978
seed = seed .. rnd
872
979
end
873
980
seed = seed .. tostring (os.clock () * 10000000 )
981
+ if os .native and os .native .tickcount then
982
+ seed = seed .. tostring (os .native .tickcount ())
983
+ end
874
984
local number = 0
875
985
for i = 1 , seed :len () do
876
986
local k = string.byte (seed :sub (i , i ))
@@ -960,20 +1070,29 @@ function data_save(filename, M)
960
1070
local tmpname = nil
961
1071
local i
962
1072
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
969
1081
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
976
1082
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
977
1096
fp = io.open (tmpname , ' w' )
978
1097
end
979
1098
if fp == nil then
@@ -986,7 +1105,11 @@ function data_save(filename, M)
986
1105
end
987
1106
fp :close ()
988
1107
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
990
1113
os.remove (tmpname )
991
1114
end
992
1115
return true
0 commit comments