1if not modules then modules = { } end modules [ ' util-lib ' ] = {
2 version = 1 . 001 ,
3 comment = " companion to luat-lib.mkiv " ,
4 author = " Hans Hagen, PRAGMA-ADE, Hasselt NL " ,
5 copyright = " PRAGMA ADE / ConTeXt Development Team " ,
6 license = " see context related readme files " ,
7}
8
9
72
73local type = type
74local next = next
75local pcall = pcall
76local gsub = string . gsub
77local find = string . find
78local sort = table . sort
79local pathpart = file . pathpart
80local nameonly = file . nameonly
81local joinfile = file . join
82local removesuffix = file . removesuffix
83local addsuffix = file . addsuffix
84local findfile = resolvers . findfile
85local findfiles = resolvers . findfiles
86local expandpaths = resolvers . expandedpathlistfromvariable
87local qualifiedpath = file . is_qualified_path
88local isfile = lfs . isfile
89
90local done = false
91
92
93
94
95local function locate ( required , version , trace , report , action )
96 if type ( required ) ~ = " string " then
97 report ( " provide a proper library name " )
98 return
99 end
100 if trace then
101 report ( " requiring library %a with version %a " , required , version or " any " )
102 end
103 local found_library = nil
104 local required_full = gsub ( required , " %. " , " / " )
105 local required_path = pathpart ( required_full )
106 local required_base = nameonly ( required_full )
107 if qualifiedpath ( required ) then
108
109 if isfile ( addsuffix ( required , os . libsuffix ) ) then
110 if trace then
111 report ( " qualified name %a found " , required )
112 end
113 found_library = required
114 else
115 if trace then
116 report ( " qualified name %a not found " , required )
117 end
118 end
119 else
120
121 local required_name = required_base . . " . " . . os . libsuffix
122 local version = type ( version ) = = " string " and version ~ = " " and version or false
123
124 local engine = environment . ownmain or false
125
126 if trace and not done then
127 local list = expandpaths ( " lib " )
128 for i = 1 , # list do
129 report ( " tds path %i: %s " , i , list [ i ] )
130 end
131 end
132
133 local function found ( locate , asked_library , how , ... )
134 if trace then
135 report ( " checking %s: %a " , how , asked_library )
136 end
137 return locate ( asked_library , ... )
138 end
139 local function check ( locate , ... )
140 local found = nil
141 if version then
142 local asked_library = joinfile ( required_path , version , required_name )
143 if trace then
144 report ( " checking %s: %a " , " with version " , asked_library )
145 end
146 found = locate ( asked_library , ... )
147 end
148 if not found or found = = " " then
149 local asked_library = joinfile ( required_path , required_name )
150 if trace then
151 report ( " checking %s: %a " , " with version " , asked_library )
152 end
153 found = locate ( asked_library , ... )
154 end
155 return found and found ~ = " " and found or false
156 end
157
158
159
160 local function attempt ( checkpattern )
161
162 if trace then
163 report ( " checking tds lib paths strictly " )
164 end
165 local found = findfile and check ( findfile , " lib " )
166 if found and ( not checkpattern or find ( found , checkpattern ) ) then
167 return found
168 end
169
170 if trace then
171 report ( " checking tds lib paths with wildcard " )
172 end
173 local asked_library = joinfile ( required_path , " .* " , required_name )
174 if trace then
175 report ( " checking %s: %a " , " latest version " , asked_library )
176 end
177 local list = findfiles ( asked_library , " lib " , true )
178 if list and # list > 0 then
179 sort ( list )
180 local found = list [ # list ]
181 if found and ( not checkpattern or find ( found , checkpattern ) ) then
182 return found
183 end
184 end
185
186 if trace then
187 report ( " checking lib paths " )
188 end
189 package . extralibpath ( environment . ownpath )
190 local paths = package . libpaths ( )
191 local pattern = " /[^/]+%. " . . os . libsuffix . . " $ "
192 for i = 1 , # paths do
193 required_path = gsub ( paths [ i ] , pattern , " " )
194 local found = check ( lfs . isfound )
195 if type ( found ) = = " string " and ( not checkpattern or find ( found , checkpattern ) ) then
196 return found
197 end
198 end
199 return false
200 end
201 if engine then
202 if trace then
203 report ( " attemp 1, engine %a " , engine )
204 end
205 found_library = attempt ( " / " . . engine . . " / " )
206 if not found_library then
207 if trace then
208 report ( " attemp 2, no engine " , asked_library )
209 end
210 found_library = attempt ( )
211 end
212 else
213 found_library = attempt ( )
214 end
215 end
216
217 if not found_library then
218 if trace then
219 report ( " not found: %a " , required )
220 end
221 library = false
222 else
223 if trace then
224 report ( " found: %a " , found_library )
225 end
226 local result , message = action ( found_library , required_base )
227 if result then
228 library = result
229 else
230 library = false
231 report ( " load error: message %a, library %a " , tostring ( message or " unknown " ) , found_library or " no library " )
232 end
233 end
234 if trace then
235 if not library then
236 report ( " unknown library: %a " , required )
237 else
238 report ( " stored library: %a " , required )
239 end
240 end
241 return library or nil
242end
243
244resolvers . locatelib = locate
245
246do
247
248 local report_swiglib = logs . reporter ( " swiglib " )
249 local trace_swiglib = false
250 local savedrequire = require
251 local loadedlibs = { }
252 local loadlib = package . loadlib
253
254 local pushdir = dir . push
255 local popdir = dir . pop
256
257 trackers . register ( " resolvers.swiglib " , function ( v ) trace_swiglib = v end )
258
259 function requireswiglib ( required , version )
260 local library = loadedlibs [ library ]
261 if library = = nil then
262 local trace_swiglib = trace_swiglib or package . helpers . trace
263 library = locate ( required , version , trace_swiglib , report_swiglib , function ( name , base )
264 pushdir ( pathpart ( name ) )
265 local opener = " luaopen_ " . . base
266 if trace_swiglib then
267 report_swiglib ( " opening: %a with %a " , name , opener )
268 end
269 local library , message = loadlib ( name , opener )
270 local libtype = type ( library )
271 if libtype = = " function " then
272 library = library ( )
273 else
274 report_swiglib ( " load error: %a returns %a, message %a, library %a " , opener , libtype , ( string . gsub ( message or " no message " , " [%s]+$ " , " " ) ) , found_library or " no library " )
275 library = false
276 end
277 popdir ( )
278 return library
279 end )
280 loadedlibs [ required ] = library or false
281 end
282 return library
283 end
284
285
291
292 function require ( name , version )
293 if find ( name , " ^swiglib%. " ) then
294 return requireswiglib ( name , version )
295 else
296 return savedrequire ( name )
297 end
298 end
299
300
307
308 local swiglibs = { }
309 local initializer = " core "
310
311 function swiglib ( name , version )
312 local library = swiglibs [ name ]
313 if not library then
314 statistics . starttiming ( swiglibs )
315 if trace_swiglib then
316 report_swiglib ( " loading %a " , name )
317 end
318 if not find ( name , " %. " . . initializer . . " $ " ) then
319 fullname = " swiglib. " . . name . . " . " . . initializer
320 else
321 fullname = " swiglib. " . . name
322 end
323 library = requireswiglib ( fullname , version )
324 swiglibs [ name ] = library
325 statistics . stoptiming ( swiglibs )
326 end
327 return library
328 end
329
330 statistics . register ( " used swiglibs " , function ( )
331 if next ( swiglibs ) then
332 return string . format ( " %s, initial load time %s seconds " , table . concat ( table . sortedkeys ( swiglibs ) , " " ) , statistics . elapsedtime ( swiglibs ) )
333 end
334 end )
335
336end
337
338if FFISUPPORTED and ffi and ffi . load then
339
340
345
346 local report_ffilib = logs . reporter ( " ffilib " )
347 local trace_ffilib = false
348 local savedffiload = ffi . load
349
350
351
352
353
354
355 trackers . register ( " resolvers.ffilib " , function ( v ) trace_ffilib = v end )
356
357
358
359
360
361 local loaded = { }
362
363 local function locateindeed ( name )
364 name = removesuffix ( name )
365 local l = loaded [ name ]
366 if l = = nil then
367 local state , library = pcall ( savedffiload , name )
368 if type ( library ) = = " userdata " then
369 l = library
370 elseif type ( state ) = = " userdata " then
371 l = state
372 else
373 l = false
374 end
375 loaded [ name ] = l
376 elseif trace_ffilib then
377 report_ffilib ( " reusing already loaded %a " , name )
378 end
379 return l
380 end
381
382 local function getlist ( required )
383 local list = directives . value ( " system.librarynames " )
384 if type ( list ) = = " table " then
385 list = list [ required ]
386 if type ( list ) = = " table " then
387 if trace then
388 report ( " using lookup list for library %a: % | t " , required , list )
389 end
390 return list
391 end
392 end
393 return { required }
394 end
395
396 function ffilib ( name , version )
397 name = removesuffix ( name )
398 local l = loaded [ name ]
399 if l ~ = nil then
400 if trace_ffilib then
401 report_ffilib ( " reusing already loaded %a " , name )
402 end
403 return l
404 end
405 local list = getlist ( name )
406 if version = = " system " then
407 for i = 1 , # list do
408 local library = locateindeed ( list [ i ] )
409 if type ( library ) = = " userdata " then
410 return library
411 end
412 end
413 else
414 for i = 1 , # list do
415 local library = locate ( list [ i ] , version , trace_ffilib , report_ffilib , locateindeed )
416 if type ( library ) = = " userdata " then
417 return library
418 end
419 end
420 end
421 end
422
423 function ffi . load ( name )
424 local list = getlist ( name )
425 for i = 1 , # list do
426 local library = ffilib ( list [ i ] )
427 if type ( library ) = = " userdata " then
428 return library
429 end
430 end
431 if trace_ffilib then
432 report_ffilib ( " trying to load %a using normal loader " , name )
433 end
434
435 for i = 1 , # list do
436 local state , library = pcall ( savedffiload , list [ i ] )
437 if type ( library ) = = " userdata " then
438 return library
439 elseif type ( state ) = = " userdata " then
440 return library
441 end
442 end
443 end
444
445end
446
447
464
465do
466
467 local isfile = lfs . isfile
468 local report = logs . reporter ( " resolvers " , " lib " )
469 local trace = false
470
471 trackers . register ( " resolvers.lib " , function ( v ) trace = v end )
472
473 local function action ( filename )
474 return isfile ( filename ) and filename or false
475 end
476
477 function resolvers . findlib ( required )
478 local list = directives . value ( " system.librarynames " )
479 local only = nameonly ( required )
480 if type ( list ) = = " table " then
481 list = list [ only ]
482 if type ( list ) = = " table " then
483 if trace then
484 report ( " using lookup list for library %a: % | t " , only , list )
485 end
486 else
487 list = { only }
488 end
489 else
490 list = { only }
491 end
492 for i = 1 , # list do
493 local name = list [ i ]
494 local found = locate ( name , false , trace , report , action )
495 if found then
496 return found
497 end
498 end
499 local getpaths = resolvers . expandedpathlistfromvariable
500 if getpaths then
501 local list = getpaths ( " PATH " )
502 local base = addsuffix ( only , os . libsuffix )
503 for i = 1 , # list do
504 local full = joinfile ( list [ i ] , base )
505 local found = locate ( full , false , trace , report , action )
506 if found then
507 return found
508 end
509 end
510 end
511 end
512
513end
514 |