io.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. #pragma once
  2. #include "ceval.h"
  3. #include "cffi.h"
  4. #if PK_ENABLE_FILEIO
  5. #include <fstream>
  6. #include <filesystem>
  7. namespace pkpy{
  8. inline Str _read_file_cwd(const Str& name, bool* ok){
  9. std::filesystem::path path(name.c_str());
  10. bool exists = std::filesystem::exists(path);
  11. if(!exists){
  12. *ok = false;
  13. return Str();
  14. }
  15. std::ifstream ifs(path);
  16. std::string buffer((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
  17. ifs.close();
  18. *ok = true;
  19. return Str(std::move(buffer));
  20. }
  21. struct FileIO {
  22. PY_CLASS(FileIO, io, FileIO)
  23. Str file;
  24. Str mode;
  25. std::fstream _fs;
  26. FileIO(VM* vm, Str file, Str mode): file(file), mode(mode) {
  27. if(mode == "rt" || mode == "r"){
  28. _fs.open(file, std::ios::in);
  29. }else if(mode == "wt" || mode == "w"){
  30. _fs.open(file, std::ios::out);
  31. }else if(mode == "at" || mode == "a"){
  32. _fs.open(file, std::ios::app);
  33. }
  34. if(!_fs.is_open()) vm->IOError(strerror(errno));
  35. }
  36. static void _register(VM* vm, PyObject* mod, PyObject* type){
  37. vm->bind_static_method<2>(type, "__new__", [](VM* vm, Args& args){
  38. return VAR_T(FileIO,
  39. vm, CAST(Str, args[0]), CAST(Str, args[1])
  40. );
  41. });
  42. vm->bind_method<0>(type, "read", [](VM* vm, Args& args){
  43. FileIO& io = CAST(FileIO&, args[0]);
  44. std::string buffer;
  45. io._fs >> buffer;
  46. return VAR(buffer);
  47. });
  48. vm->bind_method<1>(type, "write", [](VM* vm, Args& args){
  49. FileIO& io = CAST(FileIO&, args[0]);
  50. io._fs << CAST(Str&, args[1]);
  51. return vm->None;
  52. });
  53. vm->bind_method<0>(type, "close", [](VM* vm, Args& args){
  54. FileIO& io = CAST(FileIO&, args[0]);
  55. io._fs.close();
  56. return vm->None;
  57. });
  58. vm->bind_method<0>(type, "__exit__", [](VM* vm, Args& args){
  59. FileIO& io = CAST(FileIO&, args[0]);
  60. io._fs.close();
  61. return vm->None;
  62. });
  63. vm->bind_method<0>(type, "__enter__", CPP_LAMBDA(vm->None));
  64. }
  65. };
  66. inline void add_module_io(VM* vm){
  67. PyObject* mod = vm->new_module("io");
  68. PyObject* type = FileIO::register_class(vm, mod);
  69. vm->bind_builtin_func<2>("open", [type](VM* vm, const Args& args){
  70. return vm->call(type, args);
  71. });
  72. }
  73. inline void add_module_os(VM* vm){
  74. PyObject* mod = vm->new_module("os");
  75. // Working directory is shared by all VMs!!
  76. vm->bind_func<0>(mod, "getcwd", [](VM* vm, const Args& args){
  77. return VAR(std::filesystem::current_path().string());
  78. });
  79. vm->bind_func<1>(mod, "chdir", [](VM* vm, const Args& args){
  80. std::filesystem::path path(CAST(Str&, args[0]).c_str());
  81. std::filesystem::current_path(path);
  82. return vm->None;
  83. });
  84. vm->bind_func<1>(mod, "listdir", [](VM* vm, const Args& args){
  85. std::filesystem::path path(CAST(Str&, args[0]).c_str());
  86. std::filesystem::directory_iterator di;
  87. try{
  88. di = std::filesystem::directory_iterator(path);
  89. }catch(std::filesystem::filesystem_error& e){
  90. Str msg = e.what();
  91. auto pos = msg.find_last_of(":");
  92. if(pos != Str::npos) msg = msg.substr(pos + 1);
  93. vm->IOError(msg.lstrip());
  94. }
  95. List ret;
  96. for(auto& p: di) ret.push_back(VAR(p.path().filename().string()));
  97. return VAR(ret);
  98. });
  99. vm->bind_func<1>(mod, "remove", [](VM* vm, const Args& args){
  100. std::filesystem::path path(CAST(Str&, args[0]).c_str());
  101. bool ok = std::filesystem::remove(path);
  102. if(!ok) vm->IOError("operation failed");
  103. return vm->None;
  104. });
  105. vm->bind_func<1>(mod, "mkdir", [](VM* vm, const Args& args){
  106. std::filesystem::path path(CAST(Str&, args[0]).c_str());
  107. bool ok = std::filesystem::create_directory(path);
  108. if(!ok) vm->IOError("operation failed");
  109. return vm->None;
  110. });
  111. vm->bind_func<1>(mod, "rmdir", [](VM* vm, const Args& args){
  112. std::filesystem::path path(CAST(Str&, args[0]).c_str());
  113. bool ok = std::filesystem::remove(path);
  114. if(!ok) vm->IOError("operation failed");
  115. return vm->None;
  116. });
  117. vm->bind_func<-1>(mod, "path_join", [](VM* vm, const Args& args){
  118. std::filesystem::path path;
  119. for(int i=0; i<args.size(); i++){
  120. path /= CAST(Str&, args[i]).c_str();
  121. }
  122. return VAR(path.string());
  123. });
  124. vm->bind_func<1>(mod, "path_exists", [](VM* vm, const Args& args){
  125. std::filesystem::path path(CAST(Str&, args[0]).c_str());
  126. bool exists = std::filesystem::exists(path);
  127. return VAR(exists);
  128. });
  129. }
  130. } // namespace pkpy
  131. #else
  132. namespace pkpy{
  133. inline void add_module_io(VM* vm){}
  134. inline void add_module_os(VM* vm){}
  135. inline Str _read_file_cwd(const Str& name, bool* ok){
  136. *ok = false;
  137. return Str();
  138. }
  139. } // namespace pkpy
  140. #endif