You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

paths.c 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161
  1. /* -*- C -*- */
  2. #include "paths.h"
  3. /* ------------------------------------------------------ */
  4. /* Utils to manipulate strings */
  5. #define SBINCREMENT 256
  6. typedef struct {
  7. char *buffer;
  8. int maxlen;
  9. int len;
  10. } SB;
  11. static void
  12. sbinit(SB *sb)
  13. {
  14. sb->buffer = (char*)malloc(SBINCREMENT);
  15. sb->maxlen = SBINCREMENT;
  16. sb->len = 0;
  17. }
  18. static char *
  19. sbfree(SB *sb)
  20. {
  21. if (sb->buffer)
  22. free(sb->buffer);
  23. sb->buffer = 0;
  24. return 0;
  25. }
  26. static void
  27. sbgrow(SB *sb, int n)
  28. {
  29. if (sb->buffer && sb->len + n > sb->maxlen)
  30. {
  31. int nlen = sb->maxlen;
  32. while (sb->len + n > nlen)
  33. nlen += SBINCREMENT;
  34. sb->buffer = (char*)realloc(sb->buffer, nlen);
  35. sb->maxlen = nlen;
  36. }
  37. }
  38. static void
  39. sbadd1(SB *sb, char c)
  40. {
  41. sbgrow(sb, 1);
  42. if (sb->buffer)
  43. sb->buffer[sb->len++] = c;
  44. }
  45. static void
  46. sbaddn(SB *sb, const char *s, int n)
  47. {
  48. sbgrow(sb, n);
  49. if (sb->buffer && s && n)
  50. memcpy(sb->buffer + sb->len, s, n);
  51. else if (sb->buffer && n)
  52. sbfree(sb);
  53. sb->len += n;
  54. }
  55. static void
  56. sbaddsf(SB *sb, char *s)
  57. {
  58. if (s)
  59. sbaddn(sb, s, strlen(s));
  60. else
  61. sbfree(sb);
  62. if (s)
  63. free((void*)s);
  64. }
  65. static void
  66. sbslash(SB *sb)
  67. {
  68. int i;
  69. if (sb->buffer && sb->len)
  70. for(i=0; i<sb->len; i++)
  71. if (sb->buffer[i]=='\\')
  72. sb->buffer[i]='/';
  73. }
  74. static int
  75. sbpush(lua_State *L, SB *sb)
  76. {
  77. sbslash(sb);
  78. lua_pushlstring(L, sb->buffer, sb->len);
  79. sbfree(sb);
  80. return 1;
  81. }
  82. static int
  83. sbsetpush(lua_State *L, SB *sb, const char *s)
  84. {
  85. sbfree(sb);
  86. lua_pushstring(L, s);
  87. return 1;
  88. }
  89. /* ------------------------------------------------------ */
  90. /* filep, dirp, basename, dirname */
  91. static int
  92. filep(lua_State *L, int i)
  93. {
  94. const char *s = luaL_checkstring(L, i);
  95. #ifdef _WIN32
  96. struct _stat buf;
  97. if (_stat(s,&buf) < 0)
  98. return 0;
  99. if (buf.st_mode & S_IFDIR)
  100. return 0;
  101. #else
  102. struct stat buf;
  103. if (stat(s,&buf) < 0)
  104. return 0;
  105. if (buf.st_mode & S_IFDIR)
  106. return 0;
  107. #endif
  108. return 1;
  109. }
  110. static int
  111. dirp(lua_State *L, int i)
  112. {
  113. const char *s = luaL_checkstring(L, i);
  114. #ifdef _WIN32
  115. char buffer[8];
  116. struct _stat buf;
  117. const char *last;
  118. if ((s[0]=='/' || s[0]=='\\') &&
  119. (s[1]=='/' || s[1]=='\\') && !s[2])
  120. return 1;
  121. if (s[0] && isalpha((unsigned char)(s[0])) && s[1] == ':' && s[2] == 0)
  122. { buffer[0]=s[0]; buffer[1]=':'; buffer[2]='.'; buffer[3]=0; s = buffer; }
  123. if (_stat(s, &buf) >= 0)
  124. if (buf.st_mode & S_IFDIR)
  125. return 1;
  126. #else
  127. struct stat buf;
  128. if (stat(s,&buf)==0)
  129. if (buf.st_mode & S_IFDIR)
  130. return 1;
  131. #endif
  132. return 0;
  133. }
  134. static int
  135. lua_filep(lua_State *L)
  136. {
  137. lua_pushboolean(L, filep(L, 1));
  138. return 1;
  139. }
  140. static int
  141. lua_dirp(lua_State *L)
  142. {
  143. lua_pushboolean(L, dirp(L, 1));
  144. return 1;
  145. }
  146. static int
  147. lua_basename(lua_State *L)
  148. {
  149. const char *fname = luaL_checkstring(L, 1);
  150. const char *suffix = luaL_optstring(L, 2, 0);
  151. #ifdef _WIN32
  152. int sl;
  153. const char *p, *s;
  154. SB sb;
  155. sbinit(&sb);
  156. /* Special cases */
  157. if (fname[0] && fname[1]==':') {
  158. sbaddn(&sb, fname, 2);
  159. fname += 2;
  160. if (fname[0]=='/' || fname[0]=='\\')
  161. sbadd1(&sb, '/');
  162. while (fname[0]=='/' || fname[0]=='\\')
  163. fname += 1;
  164. if (fname[0]==0)
  165. return sbpush(L, &sb);
  166. sb.len = 0;
  167. }
  168. /* Position p after last nontrivial slash */
  169. s = p = fname;
  170. while (*s) {
  171. if ((s[0]=='\\' || s[0]=='/') &&
  172. (s[1] && s[1]!='/' && s[1]!='\\' ) )
  173. p = s + 1;
  174. s++;
  175. }
  176. /* Copy into buffer */
  177. while (*p && *p!='/' && *p!='\\')
  178. sbadd1(&sb, *p++);
  179. /* Process suffix */
  180. if (suffix==0 || suffix[0]==0)
  181. return sbpush(L, &sb);
  182. if (suffix[0]=='.')
  183. suffix += 1;
  184. if (suffix[0]==0)
  185. return sbpush(L, &sb);
  186. sl = strlen(suffix);
  187. if (sb.len > sl) {
  188. s = sb.buffer + sb.len - (sl + 1);
  189. if (s[0]=='.' && _strnicmp(s+1,suffix, sl)==0)
  190. sb.len = s - sb.buffer;
  191. }
  192. return sbpush(L, &sb);
  193. #else
  194. int sl;
  195. const char *s, *p;
  196. SB sb;
  197. sbinit(&sb);
  198. /* Position p after last nontrivial slash */
  199. s = p = fname;
  200. while (*s) {
  201. if (s[0]=='/' && s[1] && s[1]!='/')
  202. p = s + 1;
  203. s++;
  204. }
  205. /* Copy into buffer */
  206. while (*p && *p!='/')
  207. sbadd1(&sb, *p++);
  208. /* Process suffix */
  209. if (suffix==0 || suffix[0]==0)
  210. return sbpush(L, &sb);
  211. if (suffix[0]=='.')
  212. suffix += 1;
  213. if (suffix[0]==0)
  214. return sbpush(L, &sb);
  215. sl = strlen(suffix);
  216. if (sb.len > sl) {
  217. s = sb.buffer + sb.len - (sl + 1);
  218. if (s[0]=='.' && strncmp(s+1,suffix, sl)==0)
  219. sb.len = s - sb.buffer;
  220. }
  221. return sbpush(L, &sb);
  222. #endif
  223. }
  224. static int
  225. lua_dirname(lua_State *L)
  226. {
  227. const char *fname = luaL_checkstring(L, 1);
  228. #ifdef _WIN32
  229. const char *s;
  230. const char *p;
  231. SB sb;
  232. sbinit(&sb);
  233. /* Handle leading drive specifier */
  234. if (isalpha((unsigned char)fname[0]) && fname[1]==':') {
  235. sbadd1(&sb, *fname++);
  236. sbadd1(&sb, *fname++);
  237. }
  238. /* Search last non terminal / or \ */
  239. p = 0;
  240. s = fname;
  241. while (*s) {
  242. if ((s[0]=='\\' || s[0]=='/') &&
  243. (s[1] && s[1]!='/' && s[1]!='\\') )
  244. p = s;
  245. s++;
  246. }
  247. /* Cannot find non terminal / or \ */
  248. if (p == 0) {
  249. if (sb.len > 0) {
  250. if (fname[0]==0 || fname[0]=='/' || fname[0]=='\\')
  251. sbadd1(&sb, '/');
  252. return sbpush(L, &sb);
  253. } else {
  254. if (fname[0]=='/' || fname[0]=='\\')
  255. return sbsetpush(L, &sb, "//");
  256. else
  257. return sbsetpush(L, &sb, ".");
  258. }
  259. }
  260. /* Single leading slash */
  261. if (p == fname) {
  262. sbadd1(&sb, '/');
  263. return sbpush(L, &sb);
  264. }
  265. /* Backtrack all slashes */
  266. while (p>fname && (p[-1]=='/' || p[-1]=='\\'))
  267. p--;
  268. /* Multiple leading slashes */
  269. if (p == fname)
  270. return sbsetpush(L, &sb, "//");
  271. /* Regular case */
  272. s = fname;
  273. do {
  274. sbadd1(&sb, *s++);
  275. } while (s<p);
  276. return sbpush(L, &sb);
  277. #else
  278. const char *s = fname;
  279. const char *p = 0;
  280. SB sb;
  281. sbinit(&sb);
  282. while (*s) {
  283. if (s[0]=='/' && s[1] && s[1]!='/')
  284. p = s;
  285. s++;
  286. }
  287. if (!p) {
  288. if (fname[0]=='/')
  289. return sbsetpush(L, &sb, fname);
  290. else
  291. return sbsetpush(L, &sb, ".");
  292. }
  293. s = fname;
  294. do {
  295. sbadd1(&sb, *s++);
  296. } while (s<p);
  297. return sbpush(L, &sb);
  298. #endif
  299. }
  300. static int
  301. lua_extname(lua_State *L)
  302. {
  303. const char *fname = luaL_checkstring(L, 1);
  304. const char *p;
  305. p = fname + strlen(fname) - 1;
  306. while (p >= fname) {
  307. if (*p == '.') {
  308. lua_pushstring(L, p + 1);
  309. return 1;
  310. }
  311. p--;
  312. }
  313. return 0;
  314. }
  315. /* ------------------------------------------------------ */
  316. /* cwd and concat */
  317. static int
  318. lua_cwd(lua_State *L)
  319. {
  320. #ifdef _WIN32
  321. char drv[2];
  322. int l;
  323. SB sb;
  324. sbinit(&sb);
  325. drv[0] = '.'; drv[1] = 0;
  326. l = GetFullPathNameA(drv, sb.maxlen, sb.buffer, 0);
  327. if (l > sb.maxlen) {
  328. sbgrow(&sb, l+1);
  329. l = GetFullPathNameA(drv, sb.maxlen, sb.buffer, 0);
  330. }
  331. if (l <= 0)
  332. return sbsetpush(L, &sb, ".");
  333. sb.len += l;
  334. return sbpush(L, &sb);
  335. #elif HAVE_GETCWD
  336. const char *s;
  337. SB sb;
  338. sbinit(&sb);
  339. s = getcwd(sb.buffer, sb.maxlen);
  340. while (!s && errno==ERANGE)
  341. {
  342. sbgrow(&sb, sb.maxlen + SBINCREMENT);
  343. s = getcwd(sb.buffer, sb.maxlen);
  344. }
  345. if (! s)
  346. return sbsetpush(L, &sb, ".");
  347. sb.len += strlen(s);
  348. return sbpush(L, &sb);
  349. #else
  350. const char *s;
  351. SB sb;
  352. sbinit(&sb);
  353. sbgrow(&sb, PATH_MAX);
  354. s = getwd(sb.buffer);
  355. if (! s)
  356. return sbsetpush(L, &sb, ".");
  357. sb.len += strlen(s);
  358. return sbpush(L, &sb);
  359. #endif
  360. }
  361. static int
  362. concat_fname(lua_State *L, const char *fname)
  363. {
  364. const char *from = lua_tostring(L, -1);
  365. #ifdef _WIN32
  366. const char *s;
  367. SB sb;
  368. sbinit(&sb);
  369. sbaddn(&sb, from, strlen(from));
  370. if (fname==0)
  371. return sbpush(L, &sb);
  372. /* Handle absolute part of fname */
  373. if (fname[0]=='/' || fname[0]=='\\') {
  374. if (fname[1]=='/' || fname[1]=='\\') {
  375. sb.len = 0; /* Case //abcd */
  376. sbaddn(&sb, "//", 2);
  377. } else {
  378. char drive;
  379. if (sb.len >= 2 && sb.buffer[1]==':' /* Case "/abcd" */
  380. && isalpha((unsigned char)(sb.buffer[0])) )
  381. drive = sb.buffer[0];
  382. else
  383. drive = _getdrive() + 'A' - 1;
  384. sb.len = 0;
  385. sbadd1(&sb, drive);
  386. sbaddn(&sb, ":/", 2);
  387. }
  388. } else if (fname[0] && /* Case "x:abcd" */
  389. isalpha((unsigned char)(fname[0])) && fname[1]==':') {
  390. if (fname[2]!='/' && fname[2]!='\\') {
  391. if (sb.len < 2 || sb.buffer[1]!=':'
  392. || !isalpha((unsigned char)(sb.buffer[0]))
  393. || (toupper((unsigned char)sb.buffer[0]) !=
  394. toupper((unsigned char)fname[0]) ) )
  395. {
  396. int l;
  397. char drv[4];
  398. sb.len = 0;
  399. drv[0]=fname[0]; drv[1]=':'; drv[2]='.'; drv[3]=0;
  400. l = GetFullPathNameA(drv, sb.maxlen, sb.buffer, 0);
  401. if (l > sb.maxlen) {
  402. sbgrow(&sb, l+1);
  403. l = GetFullPathNameA(drv, sb.maxlen, sb.buffer, 0);
  404. }
  405. if (l <= 0)
  406. sbaddn(&sb, drv, 3);
  407. else
  408. sb.len += l;
  409. }
  410. fname += 2;
  411. } else {
  412. sb.len = 0; /* Case "x:/abcd" */
  413. sbadd1(&sb, toupper((unsigned char)fname[0]));
  414. sbaddn(&sb, ":/", 2);
  415. fname += 2;
  416. while (*fname == '/' || *fname == '\\')
  417. fname += 1;
  418. }
  419. }
  420. /* Process path components */
  421. for (;;)
  422. {
  423. while (*fname=='/' || *fname=='\\')
  424. fname ++;
  425. if (*fname == 0)
  426. return sbpush(L, &sb);
  427. if (fname[0]=='.') {
  428. if (fname[1]=='/' || fname[1]=='\\' || fname[1]==0) {
  429. fname += 1;
  430. continue;
  431. }
  432. if (fname[1]=='.')
  433. if (fname[2]=='/' || fname[2]=='\\' || fname[2]==0) {
  434. size_t l;
  435. fname += 2;
  436. lua_pushcfunction(L, lua_dirname);
  437. sbpush(L, &sb);
  438. lua_call(L, 1, 1);
  439. s = lua_tolstring(L, -1, &l);
  440. sbinit(&sb);
  441. sbaddn(&sb, s, l);
  442. lua_pop(L, 1);
  443. continue;
  444. }
  445. }
  446. if (sb.len==0 ||
  447. (sb.buffer[sb.len-1]!='/' && sb.buffer[sb.len-1]!='\\') )
  448. sbadd1(&sb, '/');
  449. while (*fname && *fname!='/' && *fname!='\\')
  450. sbadd1(&sb, *fname++);
  451. }
  452. #else
  453. SB sb;
  454. sbinit(&sb);
  455. if (fname && fname[0]=='/')
  456. sbadd1(&sb, '/');
  457. else
  458. sbaddn(&sb, from, strlen(from));
  459. for (;;) {
  460. while (fname && fname[0]=='/')
  461. fname++;
  462. if (!fname || !fname[0]) {
  463. sbadd1(&sb, '/');
  464. while (sb.len > 1 && sb.buffer[sb.len-1]=='/')
  465. sb.len --;
  466. return sbpush(L, &sb);
  467. }
  468. if (fname[0]=='.') {
  469. if (fname[1]=='/' || fname[1]==0) {
  470. fname +=1;
  471. continue;
  472. }
  473. if (fname[1]=='.')
  474. if (fname[2]=='/' || fname[2]==0) {
  475. fname +=2;
  476. while (sb.len > 0 && sb.buffer[sb.len-1]=='/')
  477. sb.len --;
  478. while (sb.len > 0 && sb.buffer[sb.len-1]!='/')
  479. sb.len --;
  480. continue;
  481. }
  482. }
  483. if (sb.len == 0 || sb.buffer[sb.len-1] != '/')
  484. sbadd1(&sb, '/');
  485. while (*fname!=0 && *fname!='/')
  486. sbadd1(&sb, *fname++);
  487. }
  488. #endif
  489. }
  490. static int
  491. lua_concatfname(lua_State *L)
  492. {
  493. int i;
  494. int narg = lua_gettop(L);
  495. lua_cwd(L);
  496. for (i=1; i<=narg; i++)
  497. {
  498. concat_fname(L, luaL_checkstring(L, i));
  499. lua_remove(L, -2);
  500. }
  501. return 1;
  502. }
  503. /* ------------------------------------------------------ */
  504. /* execdir */
  505. static int
  506. lua_execdir(lua_State *L)
  507. {
  508. const char *s = 0;
  509. #if HAVE_LUA_EXECUTABLE_DIR
  510. s = lua_executable_dir(0);
  511. #endif
  512. if (s && s[0])
  513. lua_pushstring(L, s);
  514. else
  515. lua_pushnil(L);
  516. return 1;
  517. }
  518. /* ------------------------------------------------------ */
  519. /* file lists */
  520. static int
  521. lua_dir(lua_State *L)
  522. {
  523. int k = 0;
  524. const char *s = luaL_checkstring(L, 1);
  525. #ifdef _WIN32
  526. SB sb;
  527. struct _finddata_t info;
  528. intptr_t hfind;
  529. /* special cases */
  530. lua_createtable(L, 0, 0);
  531. if ((s[0]=='/' || s[0]=='\\') &&
  532. (s[1]=='/' || s[1]=='\\') && !s[2])
  533. {
  534. int drive;
  535. hfind = GetLogicalDrives();
  536. for (drive='A'; drive<='Z'; drive++)
  537. if (hfind & ((intptr_t)1<<(drive-'A'))) {
  538. lua_pushfstring(L, "%c:/", drive);
  539. lua_rawseti(L, -2, ++k);
  540. }
  541. }
  542. else if (dirp(L, 1)) {
  543. lua_pushliteral(L, "..");
  544. lua_rawseti(L, -2, ++k);
  545. } else {
  546. lua_pushnil(L);
  547. return 1;
  548. }
  549. /* files */
  550. sbinit(&sb);
  551. sbaddn(&sb, s, strlen(s));
  552. if (sb.len>0 && sb.buffer[sb.len-1]!='/' && sb.buffer[sb.len-1]!='\\')
  553. sbadd1(&sb, '/');
  554. sbaddn(&sb, "*.*", 3);
  555. sbadd1(&sb, 0);
  556. hfind = _findfirst(sb.buffer, &info);
  557. if (hfind != -1) {
  558. do {
  559. if (strcmp(".",info.name) && strcmp("..",info.name)) {
  560. lua_pushstring(L, info.name);
  561. lua_rawseti(L, -2, ++k);
  562. }
  563. } while ( _findnext(hfind, &info) != -1 );
  564. _findclose(hfind);
  565. }
  566. sbfree(&sb);
  567. #else
  568. DIR *dirp;
  569. struct dirent *d;
  570. dirp = opendir(s);
  571. if (dirp) {
  572. lua_createtable(L, 0, 0);
  573. while ((d = readdir(dirp))) {
  574. int n = NAMLEN(d);
  575. lua_pushlstring(L, d->d_name, n);
  576. lua_rawseti(L, -2, ++k);
  577. }
  578. closedir(dirp);
  579. } else
  580. lua_pushnil(L);
  581. #endif
  582. return 1;
  583. }
  584. /* ------------------------------------------------------ */
  585. /* tmpname */
  586. static const char *tmpnames_key = "tmpname_sentinel";
  587. struct tmpname_s {
  588. struct tmpname_s *next;
  589. char tmp[4];
  590. };
  591. static int
  592. gc_tmpname(lua_State *L)
  593. {
  594. if (lua_isuserdata(L, -1))
  595. {
  596. struct tmpname_s **pp = (struct tmpname_s **)lua_touserdata(L, -1);
  597. while (pp && *pp)
  598. {
  599. struct tmpname_s *p = *pp;
  600. *pp = p->next;
  601. remove(p->tmp);
  602. free(p);
  603. }
  604. }
  605. return 0;
  606. }
  607. static void
  608. add_tmpname(lua_State *L, const char *tmp)
  609. {
  610. struct tmpname_s **pp = 0;
  611. lua_pushlightuserdata(L, (void*)tmpnames_key);
  612. lua_rawget(L, LUA_REGISTRYINDEX);
  613. if (lua_isuserdata(L, -1))
  614. {
  615. pp = (struct tmpname_s **)lua_touserdata(L, -1);
  616. lua_pop(L, 1);
  617. }
  618. else
  619. {
  620. lua_pop(L, 1);
  621. /* create sentinel */
  622. lua_pushlightuserdata(L, (void*)tmpnames_key);
  623. pp = (struct tmpname_s **)lua_newuserdata(L, sizeof(void*));
  624. pp[0] = 0;
  625. lua_createtable(L, 0, 1);
  626. lua_pushcfunction(L, gc_tmpname);
  627. lua_setfield(L,-2,"__gc");
  628. lua_setmetatable(L, -2);
  629. lua_rawset(L, LUA_REGISTRYINDEX);
  630. }
  631. while (pp && *pp)
  632. {
  633. struct tmpname_s *p = *pp;
  634. if (!strcmp(p->tmp, tmp)) {
  635. return;
  636. }
  637. pp = &(p->next);
  638. }
  639. if (pp)
  640. {
  641. int len = strlen(tmp);
  642. struct tmpname_s *t = (struct tmpname_s*)malloc(len + sizeof(struct tmpname_s));
  643. if (t)
  644. {
  645. t->next = 0;
  646. memcpy(t->tmp, tmp, len);
  647. t->tmp[len] = 0;
  648. *pp = t;
  649. }
  650. }
  651. }
  652. static int
  653. lua_tmpname(lua_State *L)
  654. {
  655. char *tmp;
  656. int fd = -1;
  657. #ifdef _WIN32
  658. tmp = _tempnam("c:/temp", "luatmp");
  659. #else
  660. char *tempdir = getenv("TMPDIR");
  661. if (tempdir == NULL) {
  662. tempdir = "/tmp";
  663. }
  664. tmp = calloc(1, PATH_MAX);
  665. snprintf(tmp, PATH_MAX, "%s/%sXXXXXXXX", tempdir, "luatmp");
  666. fd = mkstemp(tmp);
  667. if (fd == -1) {
  668. free(tmp);
  669. tmp = NULL;
  670. }
  671. else {
  672. /* Stupid and unsafe thing but that's how this library wants to do it */
  673. close(fd);
  674. }
  675. #endif
  676. if (tmp)
  677. {
  678. lua_pushstring(L, tmp);
  679. add_tmpname(L, tmp);
  680. free(tmp);
  681. return 1;
  682. }
  683. else
  684. {
  685. lua_pushnil(L);
  686. return 1;
  687. }
  688. }
  689. /* ------------------------------------------------------ */
  690. /* mkdir, rmdir */
  691. static int
  692. pushresult (lua_State *L, int i, const char *filename) {
  693. int en = errno;
  694. if (i) {
  695. lua_pushboolean(L, 1);
  696. return 1;
  697. }
  698. else {
  699. lua_pushnil(L);
  700. lua_pushfstring(L, "%s: %s", filename, strerror(en));
  701. lua_pushinteger(L, en);
  702. return 3;
  703. }
  704. }
  705. static int
  706. lua_mkdir(lua_State *L)
  707. {
  708. int status = 0;
  709. const char *s = luaL_checkstring(L, 1);
  710. lua_pushcfunction(L, lua_mkdir);
  711. lua_pushcfunction(L, lua_dirname);
  712. lua_pushvalue(L, 1);
  713. lua_call(L, 1, 1);
  714. if (! dirp(L, -1))
  715. lua_call(L, 1, 3);
  716. #ifdef _WIN32
  717. status = _mkdir(s);
  718. #else
  719. status = mkdir(s, 0777);
  720. #endif
  721. return pushresult(L, status == 0, s);
  722. }
  723. static int
  724. lua_rmdir(lua_State *L)
  725. {
  726. const char *s = luaL_checkstring(L, 1);
  727. #ifdef _WIN32
  728. int status = _rmdir(s);
  729. #else
  730. int status = rmdir(s);
  731. #endif
  732. return pushresult(L, status == 0, s);
  733. }
  734. /* ------------------------------------------------------ */
  735. /* uname */
  736. static int
  737. lua_uname(lua_State *L)
  738. {
  739. #if defined(_WIN32)
  740. const char *name;
  741. SYSTEM_INFO info;
  742. lua_pushliteral(L, "Windows");
  743. name = getenv("COMPUTERNAME");
  744. lua_pushstring(L, name ? name : "");
  745. memset(&info, 0, sizeof(info));
  746. GetSystemInfo(&info);
  747. if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
  748. lua_pushliteral(L, "AMD64");
  749. else if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
  750. lua_pushliteral(L, "X86");
  751. else if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM)
  752. lua_pushliteral(L, "ARM");
  753. else if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
  754. lua_pushliteral(L, "IA64");
  755. else if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
  756. lua_pushstring(L, "");
  757. return 3;
  758. #else
  759. # if defined(HAVE_SYS_UTSNAME_H)
  760. struct utsname info;
  761. if (uname(&info) >= 0)
  762. {
  763. lua_pushstring(L, info.sysname);
  764. lua_pushstring(L, info.nodename);
  765. lua_pushstring(L, info.machine);
  766. return 3;
  767. }
  768. # endif
  769. lua_pushstring(L, "Unknown");
  770. return 1;
  771. #endif
  772. }
  773. static int
  774. lua_getregistryvalue(lua_State *L)
  775. {
  776. #ifdef _WIN32
  777. static char *keynames[] = {
  778. "HKEY_CLASSES_ROOT",
  779. "HKEY_CURRENT_CONFIG",
  780. "HKEY_CURRENT_USER",
  781. "HKEY_LOCAL_MACHINE",
  782. "HKEY_USERS",
  783. NULL };
  784. static HKEY keys[] = {
  785. HKEY_CLASSES_ROOT,
  786. HKEY_CURRENT_CONFIG,
  787. HKEY_CURRENT_USER,
  788. HKEY_LOCAL_MACHINE,
  789. HKEY_USERS
  790. };
  791. HKEY rkey = keys[ luaL_checkoption(L, 1, NULL, keynames) ];
  792. const char *subkey = luaL_checkstring(L, 2);
  793. const char *value = luaL_checkstring(L, 3);
  794. HKEY skey;
  795. DWORD type;
  796. DWORD len = 0;
  797. char *data = NULL;
  798. LONG res;
  799. res = RegOpenKeyExA(rkey, subkey, 0, KEY_READ, &skey);
  800. if (res != ERROR_SUCCESS)
  801. {
  802. lua_pushnil(L);
  803. lua_pushinteger(L, res);
  804. if (res == ERROR_FILE_NOT_FOUND)
  805. lua_pushstring(L, "subkey not found");
  806. if (res == ERROR_ACCESS_DENIED)
  807. lua_pushstring(L, "subkey access denied");
  808. else
  809. return 2;
  810. return 3;
  811. }
  812. res = RegQueryValueExA(skey, value, NULL, &type, (LPBYTE)data, &len);
  813. if (len > 0)
  814. {
  815. len += 8;
  816. data = (char*)malloc(len);
  817. if (! data)
  818. luaL_error(L, "out of memory");
  819. res = RegQueryValueExA(skey, value, NULL, &type, (LPBYTE)data, &len);
  820. }
  821. RegCloseKey(skey);
  822. if (res != ERROR_SUCCESS)
  823. {
  824. if (data)
  825. free(data);
  826. lua_pushnil(L);
  827. lua_pushinteger(L, res);
  828. if (res == ERROR_FILE_NOT_FOUND)
  829. lua_pushstring(L, "value not found");
  830. if (res == ERROR_ACCESS_DENIED)
  831. lua_pushstring(L, "value access denied");
  832. else
  833. return 2;
  834. return 3;
  835. }
  836. switch(type)
  837. {
  838. case REG_DWORD:
  839. lua_pushinteger(L, (lua_Integer)*(const DWORD*)data);
  840. if (data)
  841. free(data);
  842. return 1;
  843. case REG_EXPAND_SZ:
  844. if (data && len > 0)
  845. {
  846. if ((len = ExpandEnvironmentStrings(data, NULL, 0)) > 0)
  847. {
  848. char *buf = (char*)malloc(len + 8);
  849. if (!buf)
  850. luaL_error(L, "out of memory");
  851. len = ExpandEnvironmentStrings(data, buf, len+8);
  852. free(data);
  853. data = buf;
  854. }
  855. }
  856. /* fall thru */
  857. case REG_SZ:
  858. if (data && len > 0)
  859. if (((const char*)data)[len-1] == 0)
  860. len -= 1;
  861. /* fall thru */
  862. case REG_BINARY:
  863. if (data && len > 0)
  864. lua_pushlstring(L, (const char*)data, (int)len);
  865. else
  866. lua_pushliteral(L, "");
  867. if (data)
  868. free(data);
  869. return 1;
  870. /* unimplemented */
  871. case REG_QWORD:
  872. case REG_MULTI_SZ:
  873. default:
  874. lua_pushnil(L);
  875. lua_pushinteger(L, res);
  876. lua_pushfstring(L, "getting registry type %d not implemented", type);
  877. return 3;
  878. }
  879. #else
  880. luaL_error(L, "This function exists only on windows");
  881. return 0;
  882. #endif
  883. }
  884. /* ------------------------------------------------------ */
  885. /* require (with global flag) */
  886. #ifdef HAVE_DLOPEN
  887. # define NEED_PATH_REQUIRE 1
  888. # include <dlfcn.h>
  889. # ifndef RTLD_LAZY
  890. # define RTLD_LAZY 1
  891. # endif
  892. # ifndef RTLD_GLOBAL
  893. # define RTLD_GLOBAL 0
  894. # endif
  895. # define LL_LOAD(h,fname) h=dlopen(fname,RTLD_LAZY|RTLD_GLOBAL)
  896. # define LL_SYM(h,sym) dlsym(h, sym)
  897. #endif
  898. #ifdef _WIN32
  899. # define NEED_PATH_REQUIRE 1
  900. # include <windows.h>
  901. # define LL_LOAD(h,fname) h=(void*)LoadLibraryA(fname)
  902. # define LL_SYM(h,sym) GetProcAddress((HINSTANCE)h,sym)
  903. #endif
  904. #if NEED_PATH_REQUIRE
  905. /* {{{ functions copied or derived from loadlib.c */
  906. static int readable (const char *filename)
  907. {
  908. FILE *f = fopen(filename, "r"); /* try to open file */
  909. if (f == NULL) return 0; /* open failed */
  910. fclose(f);
  911. return 1;
  912. }
  913. #if LUA_VERSION_NUM >= 502 /* LUA52 compatibility defs */
  914. #define LUA_PATHSEP ";"
  915. #define PATHS_LUA_CLEANUP_DEFS 1
  916. #endif
  917. static const char *pushnexttemplate (lua_State *L, const char *path)
  918. {
  919. const char *l;
  920. while (*path == *LUA_PATHSEP) path++; /* skip separators */
  921. if (*path == '\0') return NULL; /* no more templates */
  922. l = strchr(path, *LUA_PATHSEP); /* find next separator */
  923. if (l == NULL) l = path + strlen(path);
  924. lua_pushlstring(L, path, l - path); /* template */
  925. return l;
  926. }
  927. #ifdef PATHS_LUA_CLEANUP_DEFS /* cleanup after yourself */
  928. #undef LUA_PATHSEP
  929. #endif
  930. static const char *pushfilename (lua_State *L, const char *name)
  931. {
  932. const char *path;
  933. const char *filename;
  934. lua_getglobal(L, "package");
  935. lua_getfield(L, -1, "cpath");
  936. lua_remove(L, -2);
  937. if (! (path = lua_tostring(L, -1)))
  938. luaL_error(L, LUA_QL("package.cpath") " must be a string");
  939. lua_pushliteral(L, "");
  940. while ((path = pushnexttemplate(L, path))) {
  941. filename = luaL_gsub(L, lua_tostring(L, -1), "?", name);
  942. lua_remove(L, -2);
  943. if (readable(filename))
  944. { /* stack: cpath errmsg filename */
  945. lua_remove(L, -3);
  946. lua_remove(L, -2);
  947. return lua_tostring(L, -1);
  948. }
  949. lua_pushfstring(L, "\n\tno file " LUA_QS, filename);
  950. lua_remove(L, -2); /* remove file name */
  951. lua_concat(L, 2); /* add entry to possible error message */
  952. }
  953. lua_pushfstring(L, "module " LUA_QS " not found", name);
  954. lua_replace(L, -3);
  955. lua_concat(L, 2);
  956. lua_error(L);
  957. return 0;
  958. }
  959. /* functions copied or derived from loadlib.c }}} */
  960. static int
  961. path_require(lua_State *L)
  962. {
  963. const char *filename;
  964. lua_CFunction func;
  965. void *handle;
  966. const char *name = luaL_checkstring(L, 1);
  967. lua_settop(L, 1);
  968. lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); /* index 2 */
  969. lua_getfield(L, 2, name);
  970. if (lua_toboolean(L, -1))
  971. return 1;
  972. filename = pushfilename(L, name); /* index 3 */
  973. LL_LOAD(handle, filename);
  974. if (! handle)
  975. luaL_error(L, "cannot load " LUA_QS, filename);
  976. lua_pushfstring(L, "luaopen_%s", name); /* index 4 */
  977. func = (lua_CFunction)LL_SYM(handle, lua_tostring(L, -1));
  978. if (! func)
  979. luaL_error(L, "no symbol " LUA_QS " in module " LUA_QS,
  980. lua_tostring(L, -1), filename);
  981. lua_pushboolean(L, 1);
  982. lua_setfield(L, 2, name);
  983. lua_pushcfunction(L, func);
  984. lua_pushstring(L, name);
  985. lua_call(L, 1, 1);
  986. if (! lua_isnil(L, -1))
  987. lua_setfield(L, 2, name);
  988. lua_getfield(L, 2, name);
  989. return 1;
  990. }
  991. #else
  992. /* fallback to calling require */
  993. static int
  994. path_require(lua_State *L)
  995. {
  996. int narg = lua_gettop(L);
  997. lua_getglobal(L, "require");
  998. lua_insert(L, 1);
  999. lua_call(L, narg, 1);
  1000. return 1;
  1001. }
  1002. #endif
  1003. /* ------------------------------------------------------ */
  1004. /* register */
  1005. static const struct luaL_Reg paths__ [] = {
  1006. {"filep", lua_filep},
  1007. {"dirp", lua_dirp},
  1008. {"basename", lua_basename},
  1009. {"dirname", lua_dirname},
  1010. {"extname", lua_extname},
  1011. {"cwd", lua_cwd},
  1012. {"concat", lua_concatfname},
  1013. {"execdir", lua_execdir},
  1014. {"dir", lua_dir},
  1015. {"tmpname", lua_tmpname},
  1016. {"mkdir", lua_mkdir},
  1017. {"rmdir", lua_rmdir},
  1018. {"uname", lua_uname},
  1019. {"getregistryvalue", lua_getregistryvalue},
  1020. {"require", path_require},
  1021. {NULL, NULL}
  1022. };
  1023. PATHS_API int
  1024. luaopen_libpaths(lua_State *L)
  1025. {
  1026. lua_newtable(L);
  1027. lua_pushvalue(L, -1);
  1028. lua_setglobal(L, "paths");
  1029. #if LUA_VERSION_NUM >= 502
  1030. luaL_setfuncs(L, paths__, 0);
  1031. #else
  1032. luaL_register(L, NULL, paths__);
  1033. #endif
  1034. return 1;
  1035. }