= fname) {
350 | if (*p == '.') {
351 | lua_pushstring(L, p + 1);
352 | return 1;
353 | }
354 | p--;
355 | }
356 | return 0;
357 | }
358 |
359 |
360 | /* ------------------------------------------------------ */
361 | /* cwd and concat */
362 |
363 |
364 | static int
365 | lua_cwd(lua_State *L)
366 | {
367 | #ifdef _WIN32
368 |
369 | char drv[2];
370 | int l;
371 | SB sb;
372 | sbinit(&sb);
373 | drv[0] = '.'; drv[1] = 0;
374 | l = GetFullPathNameA(drv, sb.maxlen, sb.buffer, 0);
375 | if (l > sb.maxlen) {
376 | sbgrow(&sb, l+1);
377 | l = GetFullPathNameA(drv, sb.maxlen, sb.buffer, 0);
378 | }
379 | if (l <= 0)
380 | return sbsetpush(L, &sb, ".");
381 | sb.len += l;
382 | return sbpush(L, &sb);
383 |
384 | #elif HAVE_GETCWD
385 |
386 | const char *s;
387 | SB sb;
388 | sbinit(&sb);
389 | s = getcwd(sb.buffer, sb.maxlen);
390 | while (!s && errno==ERANGE)
391 | {
392 | sbgrow(&sb, sb.maxlen + SBINCREMENT);
393 | s = getcwd(sb.buffer, sb.maxlen);
394 | }
395 | if (! s)
396 | return sbsetpush(L, &sb, ".");
397 | sb.len += strlen(s);
398 | return sbpush(L, &sb);
399 |
400 | #else
401 |
402 | const char *s;
403 | SB sb;
404 | sbinit(&sb);
405 | sbgrow(&sb, PATH_MAX);
406 | s = getwd(sb.buffer);
407 | if (! s)
408 | return sbsetpush(L, &sb, ".");
409 | sb.len += strlen(s);
410 | return sbpush(L, &sb);
411 |
412 | #endif
413 | }
414 |
415 |
416 |
417 | static int
418 | concat_fname(lua_State *L, const char *fname)
419 | {
420 | const char *from = lua_tostring(L, -1);
421 |
422 | #ifdef _WIN32
423 |
424 | const char *s;
425 | SB sb;
426 | sbinit(&sb);
427 | sbaddn(&sb, from, strlen(from));
428 | if (fname==0)
429 | return sbpush(L, &sb);
430 | /* Handle absolute part of fname */
431 | if (fname[0]=='/' || fname[0]=='\\') {
432 | if (fname[1]=='/' || fname[1]=='\\') {
433 | sb.len = 0; /* Case //abcd */
434 | sbaddn(&sb, "//", 2);
435 | } else {
436 | char drive;
437 | if (sb.len >= 2 && sb.buffer[1]==':' /* Case "/abcd" */
438 | && isalpha((unsigned char)(sb.buffer[0])) )
439 | drive = sb.buffer[0];
440 | else
441 | drive = _getdrive() + 'A' - 1;
442 | sb.len = 0;
443 | sbadd1(&sb, drive);
444 | sbaddn(&sb, ":/", 2);
445 | }
446 | } else if (fname[0] && /* Case "x:abcd" */
447 | isalpha((unsigned char)(fname[0])) && fname[1]==':') {
448 | if (fname[2]!='/' && fname[2]!='\\') {
449 | if (sb.len < 2 || sb.buffer[1]!=':'
450 | || !isalpha((unsigned char)(sb.buffer[0]))
451 | || (toupper((unsigned char)sb.buffer[0]) !=
452 | toupper((unsigned char)fname[0]) ) )
453 | {
454 | int l;
455 | char drv[4];
456 | sb.len = 0;
457 | drv[0]=fname[0]; drv[1]=':'; drv[2]='.'; drv[3]=0;
458 | l = GetFullPathNameA(drv, sb.maxlen, sb.buffer, 0);
459 | if (l > sb.maxlen) {
460 | sbgrow(&sb, l+1);
461 | l = GetFullPathNameA(drv, sb.maxlen, sb.buffer, 0);
462 | }
463 | if (l <= 0)
464 | sbaddn(&sb, drv, 3);
465 | else
466 | sb.len += l;
467 | }
468 | fname += 2;
469 | } else {
470 | sb.len = 0; /* Case "x:/abcd" */
471 | sbadd1(&sb, toupper((unsigned char)fname[0]));
472 | sbaddn(&sb, ":/", 2);
473 | fname += 2;
474 | while (*fname == '/' || *fname == '\\')
475 | fname += 1;
476 | }
477 | }
478 | /* Process path components */
479 | for (;;)
480 | {
481 | while (*fname=='/' || *fname=='\\')
482 | fname ++;
483 | if (*fname == 0)
484 | return sbpush(L, &sb);
485 | if (fname[0]=='.') {
486 | if (fname[1]=='/' || fname[1]=='\\' || fname[1]==0) {
487 | fname += 1;
488 | continue;
489 | }
490 | if (fname[1]=='.')
491 | if (fname[2]=='/' || fname[2]=='\\' || fname[2]==0) {
492 | size_t l;
493 | fname += 2;
494 | lua_pushcfunction(L, lua_dirname);
495 | sbpush(L, &sb);
496 | lua_call(L, 1, 1);
497 | s = lua_tolstring(L, -1, &l);
498 | sbinit(&sb);
499 | sbaddn(&sb, s, l);
500 | lua_pop(L, 1);
501 | continue;
502 | }
503 | }
504 | if (sb.len==0 ||
505 | (sb.buffer[sb.len-1]!='/' && sb.buffer[sb.len-1]!='\\') )
506 | sbadd1(&sb, '/');
507 | while (*fname && *fname!='/' && *fname!='\\')
508 | sbadd1(&sb, *fname++);
509 | }
510 |
511 | #else
512 | SB sb;
513 | sbinit(&sb);
514 |
515 | if (fname && fname[0]=='/')
516 | sbadd1(&sb, '/');
517 | else
518 | sbaddn(&sb, from, strlen(from));
519 | for (;;) {
520 | while (fname && fname[0]=='/')
521 | fname++;
522 | if (!fname || !fname[0]) {
523 | sbadd1(&sb, '/');
524 | while (sb.len > 1 && sb.buffer[sb.len-1]=='/')
525 | sb.len --;
526 | return sbpush(L, &sb);
527 | }
528 | if (fname[0]=='.') {
529 | if (fname[1]=='/' || fname[1]==0) {
530 | fname +=1;
531 | continue;
532 | }
533 | if (fname[1]=='.')
534 | if (fname[2]=='/' || fname[2]==0) {
535 | fname +=2;
536 | while (sb.len > 0 && sb.buffer[sb.len-1]=='/')
537 | sb.len --;
538 | while (sb.len > 0 && sb.buffer[sb.len-1]!='/')
539 | sb.len --;
540 | continue;
541 | }
542 | }
543 | if (sb.len == 0 || sb.buffer[sb.len-1] != '/')
544 | sbadd1(&sb, '/');
545 | while (*fname!=0 && *fname!='/')
546 | sbadd1(&sb, *fname++);
547 | }
548 |
549 |
550 | #endif
551 |
552 | }
553 |
554 |
555 | static int
556 | lua_concatfname(lua_State *L)
557 | {
558 | int i;
559 | int narg = lua_gettop(L);
560 | lua_cwd(L);
561 | for (i=1; i<=narg; i++)
562 | {
563 | concat_fname(L, luaL_checkstring(L, i));
564 | lua_remove(L, -2);
565 | }
566 | return 1;
567 | }
568 |
569 |
570 |
571 | /* ------------------------------------------------------ */
572 | /* execdir */
573 |
574 |
575 | static int
576 | lua_execdir(lua_State *L)
577 | {
578 | const char *s = 0;
579 | #if HAVE_LUA_EXECUTABLE_DIR
580 | s = lua_executable_dir(0);
581 | #endif
582 | if (s && s[0])
583 | lua_pushstring(L, s);
584 | else
585 | lua_pushnil(L);
586 | return 1;
587 | }
588 |
589 |
590 |
591 | /* ------------------------------------------------------ */
592 | /* file lists */
593 |
594 |
595 | static int
596 | lua_dir(lua_State *L)
597 | {
598 | int k = 0;
599 | const char *s = luaL_checkstring(L, 1);
600 |
601 | #ifdef _WIN32
602 |
603 | SB sb;
604 | struct _finddata_t info;
605 | intptr_t hfind;
606 | /* special cases */
607 | lua_createtable(L, 0, 0);
608 | if ((s[0]=='/' || s[0]=='\\') &&
609 | (s[1]=='/' || s[1]=='\\') && !s[2])
610 | {
611 | int drive;
612 | hfind = GetLogicalDrives();
613 | for (drive='A'; drive<='Z'; drive++)
614 | if (hfind & ((intptr_t)1<<(drive-'A'))) {
615 | lua_pushfstring(L, "%c:/", drive);
616 | lua_rawseti(L, -2, ++k);
617 | }
618 | }
619 | else if (dirp(L, 1)) {
620 | lua_pushliteral(L, "..");
621 | lua_rawseti(L, -2, ++k);
622 | } else {
623 | lua_pushnil(L);
624 | return 1;
625 | }
626 | /* files */
627 | sbinit(&sb);
628 | sbaddn(&sb, s, strlen(s));
629 | if (sb.len>0 && sb.buffer[sb.len-1]!='/' && sb.buffer[sb.len-1]!='\\')
630 | sbadd1(&sb, '/');
631 | sbaddn(&sb, "*.*", 3);
632 | sbadd1(&sb, 0);
633 | hfind = _findfirst(sb.buffer, &info);
634 | if (hfind != -1) {
635 | do {
636 | if (strcmp(".",info.name) && strcmp("..",info.name)) {
637 | lua_pushstring(L, info.name);
638 | lua_rawseti(L, -2, ++k);
639 | }
640 | } while ( _findnext(hfind, &info) != -1 );
641 | _findclose(hfind);
642 | }
643 | sbfree(&sb);
644 |
645 | #else
646 |
647 | DIR *dirp;
648 | struct dirent *d;
649 | dirp = opendir(s);
650 | if (dirp) {
651 | lua_createtable(L, 0, 0);
652 | while ((d = readdir(dirp))) {
653 | int n = NAMLEN(d);
654 | lua_pushlstring(L, d->d_name, n);
655 | lua_rawseti(L, -2, ++k);
656 | }
657 | closedir(dirp);
658 | } else
659 | lua_pushnil(L);
660 |
661 | #endif
662 |
663 | return 1;
664 | }
665 |
666 |
667 | /* ------------------------------------------------------ */
668 | /* tmpname */
669 |
670 |
671 | static const char *tmpnames_key = "tmpname_sentinel";
672 |
673 | struct tmpname_s {
674 | struct tmpname_s *next;
675 | char tmp[4];
676 | };
677 |
678 | static int
679 | gc_tmpname(lua_State *L)
680 | {
681 | if (lua_isuserdata(L, -1))
682 | {
683 | struct tmpname_s **pp = (struct tmpname_s **)lua_touserdata(L, -1);
684 | while (pp && *pp)
685 | {
686 | struct tmpname_s *p = *pp;
687 | *pp = p->next;
688 | remove(p->tmp);
689 | free(p);
690 | }
691 | }
692 | return 0;
693 |
694 | }
695 |
696 | static void
697 | add_tmpname(lua_State *L, const char *tmp)
698 | {
699 | struct tmpname_s **pp = 0;
700 | lua_pushlightuserdata(L, (void*)tmpnames_key);
701 | lua_rawget(L, LUA_REGISTRYINDEX);
702 | if (lua_isuserdata(L, -1))
703 | {
704 | pp = (struct tmpname_s **)lua_touserdata(L, -1);
705 | lua_pop(L, 1);
706 | }
707 | else
708 | {
709 | lua_pop(L, 1);
710 | /* create sentinel */
711 | lua_pushlightuserdata(L, (void*)tmpnames_key);
712 | pp = (struct tmpname_s **)lua_newuserdata(L, sizeof(void*));
713 | pp[0] = 0;
714 | lua_createtable(L, 0, 1);
715 | lua_pushcfunction(L, gc_tmpname);
716 | lua_setfield(L,-2,"__gc");
717 | lua_setmetatable(L, -2);
718 | lua_rawset(L, LUA_REGISTRYINDEX);
719 | }
720 | while (pp && *pp)
721 | {
722 | struct tmpname_s *p = *pp;
723 | if (!strcmp(p->tmp, tmp)) return;
724 | pp = &(p->next);
725 | }
726 | if (pp)
727 | {
728 | int len = strlen(tmp);
729 | struct tmpname_s *t = (struct tmpname_s*)malloc(len + sizeof(struct tmpname_s));
730 | if (t)
731 | {
732 | t->next = 0;
733 | memcpy(t->tmp, tmp, len);
734 | t->tmp[len] = 0;
735 | *pp = t;
736 | }
737 | }
738 | }
739 |
740 |
741 | static int
742 | lua_tmpname(lua_State *L)
743 | {
744 | #ifdef _WIN32
745 | char *tmp = _tempnam("c:/temp", "luatmp");
746 | #else
747 | char *tmp = tempnam(NULL, "luatmp");
748 | #endif
749 | if (tmp)
750 | {
751 | lua_pushstring(L, tmp);
752 | add_tmpname(L, tmp);
753 | free(tmp);
754 | return 1;
755 | }
756 | else
757 | {
758 | lua_pushnil(L);
759 | return 1;
760 | }
761 | }
762 |
763 |
764 |
765 | /* ------------------------------------------------------ */
766 | /* mkdir, rmdir */
767 |
768 | static int
769 | pushresult (lua_State *L, int i, const char *filename) {
770 | int en = errno;
771 | if (i) {
772 | lua_pushboolean(L, 1);
773 | return 1;
774 | }
775 | else {
776 | lua_pushnil(L);
777 | lua_pushfstring(L, "%s: %s", filename, strerror(en));
778 | lua_pushinteger(L, en);
779 | return 3;
780 | }
781 | }
782 |
783 | static int
784 | lua_mkdir(lua_State *L)
785 | {
786 | int status = 0;
787 | const char *s = luaL_checkstring(L, 1);
788 | lua_pushcfunction(L, lua_mkdir);
789 | lua_pushcfunction(L, lua_dirname);
790 | lua_pushvalue(L, 1);
791 | lua_call(L, 1, 1);
792 | if (! dirp(L, -1))
793 | lua_call(L, 1, 3);
794 | #ifdef _WIN32
795 | status = _mkdir(s);
796 | #else
797 | status = mkdir(s, 0777);
798 | #endif
799 | return pushresult(L, status == 0, s);
800 | }
801 |
802 | static int
803 | lua_rmdir(lua_State *L)
804 | {
805 | const char *s = luaL_checkstring(L, 1);
806 | #ifdef _WIN32
807 | int status = _rmdir(s);
808 | #else
809 | int status = rmdir(s);
810 | #endif
811 | return pushresult(L, status == 0, s);
812 | }
813 |
814 |
815 | /* ------------------------------------------------------ */
816 | /* uname */
817 |
818 |
819 | static int
820 | lua_uname(lua_State *L)
821 | {
822 | #if defined(_WIN32)
823 | const char *name;
824 | SYSTEM_INFO info;
825 | lua_pushliteral(L, "Windows");
826 | name = getenv("COMPUTERNAME");
827 | lua_pushstring(L, name ? name : "");
828 | memset(&info, 0, sizeof(info));
829 | GetSystemInfo(&info);
830 | if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
831 | lua_pushliteral(L, "AMD64");
832 | else if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
833 | lua_pushliteral(L, "X86");
834 | else if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM)
835 | lua_pushliteral(L, "ARM");
836 | else if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
837 | lua_pushliteral(L, "IA64");
838 | else if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
839 | lua_pushstring(L, "");
840 | return 3;
841 | #else
842 | # if defined(HAVE_SYS_UTSNAME_H)
843 | struct utsname info;
844 | if (uname(&info) >= 0)
845 | {
846 | lua_pushstring(L, info.sysname);
847 | lua_pushstring(L, info.nodename);
848 | lua_pushstring(L, info.machine);
849 | return 3;
850 | }
851 | # endif
852 | lua_pushstring(L, "Unknown");
853 | return 1;
854 | #endif
855 | }
856 |
857 | static int
858 | lua_getregistryvalue(lua_State *L)
859 | {
860 | #ifdef _WIN32
861 | static char *keynames[] = {
862 | "HKEY_CLASSES_ROOT",
863 | "HKEY_CURRENT_CONFIG",
864 | "HKEY_CURRENT_USER",
865 | "HKEY_LOCAL_MACHINE",
866 | "HKEY_USERS",
867 | NULL };
868 | static HKEY keys[] = {
869 | HKEY_CLASSES_ROOT,
870 | HKEY_CURRENT_CONFIG,
871 | HKEY_CURRENT_USER,
872 | HKEY_LOCAL_MACHINE,
873 | HKEY_USERS
874 | };
875 |
876 | HKEY rkey = keys[ luaL_checkoption(L, 1, NULL, keynames) ];
877 | const char *subkey = luaL_checkstring(L, 2);
878 | const char *value = luaL_checkstring(L, 3);
879 | HKEY skey;
880 | DWORD type;
881 | DWORD len = 0;
882 | char *data = NULL;
883 | LONG res;
884 | res = RegOpenKeyExA(rkey, subkey, 0, KEY_READ, &skey);
885 | if (res != ERROR_SUCCESS)
886 | {
887 | lua_pushnil(L);
888 | lua_pushinteger(L, res);
889 | if (res == ERROR_FILE_NOT_FOUND)
890 | lua_pushstring(L, "subkey not found");
891 | if (res == ERROR_ACCESS_DENIED)
892 | lua_pushstring(L, "subkey access denied");
893 | else
894 | return 2;
895 | return 3;
896 | }
897 | res = RegQueryValueExA(skey, value, NULL, &type, (LPBYTE)data, &len);
898 | if (len > 0)
899 | {
900 | len += 8;
901 | data = (char*)malloc(len);
902 | if (! data)
903 | luaL_error(L, "out of memory");
904 | res = RegQueryValueExA(skey, value, NULL, &type, (LPBYTE)data, &len);
905 | }
906 | RegCloseKey(skey);
907 | if (res != ERROR_SUCCESS)
908 | {
909 | if (data)
910 | free(data);
911 | lua_pushnil(L);
912 | lua_pushinteger(L, res);
913 | if (res == ERROR_FILE_NOT_FOUND)
914 | lua_pushstring(L, "value not found");
915 | if (res == ERROR_ACCESS_DENIED)
916 | lua_pushstring(L, "value access denied");
917 | else
918 | return 2;
919 | return 3;
920 | }
921 | switch(type)
922 | {
923 | case REG_DWORD:
924 | lua_pushinteger(L, (lua_Integer)*(const DWORD*)data);
925 | if (data)
926 | free(data);
927 | return 1;
928 | case REG_EXPAND_SZ:
929 | if (data && len > 0)
930 | {
931 | if ((len = ExpandEnvironmentStrings(data, NULL, 0)) > 0)
932 | {
933 | char *buf = (char*)malloc(len + 8);
934 | if (!buf)
935 | luaL_error(L, "out of memory");
936 | len = ExpandEnvironmentStrings(data, buf, len+8);
937 | free(data);
938 | data = buf;
939 | }
940 | }
941 | /* fall thru */
942 | case REG_SZ:
943 | if (data && len > 0)
944 | if (((const char*)data)[len-1] == 0)
945 | len -= 1;
946 | /* fall thru */
947 | case REG_BINARY:
948 | if (data && len > 0)
949 | lua_pushlstring(L, (const char*)data, (int)len);
950 | else
951 | lua_pushliteral(L, "");
952 | if (data)
953 | free(data);
954 | return 1;
955 | /* unimplemented */
956 | case REG_QWORD:
957 | case REG_MULTI_SZ:
958 | default:
959 | lua_pushnil(L);
960 | lua_pushinteger(L, res);
961 | lua_pushfstring(L, "getting registry type %d not implemented", type);
962 | return 3;
963 | }
964 | #else
965 | luaL_error(L, "This function exists only on windows");
966 | return 0;
967 | #endif
968 | }
969 |
970 | /* ------------------------------------------------------ */
971 | /* require (with global flag) */
972 |
973 | #ifdef HAVE_DLOPEN
974 | # define NEED_PATH_REQUIRE 1
975 | # include