PLUGIN library lang: "C++" version: "1.1.1" date: "2024-08-06" author: "Julien BRUGUIER" maintainer: "Julien BRUGUIER " synopsis: "Libraries helper" description: %{ The virtual machine is able to load libraries written in machine language. .P This plugin enhances library loading and provides some tools around libraries. %} changelog: %{ svm-plugin-library (1.1.1) UNRELEASED; urgency=medium * Build for SVM API 2.9. -- Julien Bruguier Sun, 01 Mar 2026 22:58:15 +0100 svm-plugin-library (1.1.0) UNRELEASED; urgency=medium * Change :library.load instruction for error handling -- Julien Bruguier Sun, 11 Jan 2026 00:32:55 +0100 svm-plugin-library (1.0.0) UNRELEASED; urgency=medium * First release of this plugin -- Julien Bruguier Fri, 23 May 2025 10:30:23 +0200 %} example: "Basic handling" %{ Main code .nf #!/usr/bin/env svm LOG PLUGIN "===PLUGINLIB===" PLUGIN "svmcom.so" PLUGIN "svmstr.so" PROCESS "basic" CODE "main" INLINE :memory LIB/lib, PTR/entries, INT*3/p :library.load "library.lib.svm" -> &lib :library.entries @&lib -> &entries [ 12 , 5 , ] -> p :call $(@&lib/@&@&entries) p :com.message @(p/2) END END .fi Library code .nf :shutdown :symbol concat :str.join "" @&P "" -> &P :return :symbol add @&P -> (P/2) :shift @(P/1) (P/2) :return .fi %} includes: %{ #include %} test: initialisation %{ cat > correct.svm << EOM :shutdown :symbol test :str.join "" @&P "" -> (P/1) :return :symbol extra :return :label internal :return EOM cat > incorrect.svm << EOM :shutdown :symbol test :com.message "" @&P "" :return EOM %} test: finalisation %{ rm correct.svm incorrect.svm %} test: "Invalid_file" %{ PROCESS "test" CODE "main" INLINE :interruption DEVICE fail :memory LIB/l, STR/s :library.load "unknown.svm" -> &l :shutdown 1 :label fail END END %} test: "Invalid_library" %{ PROCESS "test" CODE "main" INLINE :interruption FAILURE fail :memory LIB/l, STR/s :library.load "incorrect.svm" -> &l :shutdown 1 :label fail END END %} test: "Simple" %{ PLUGIN "svmstr.so" PROCESS "test" CODE "main" INLINE :memory LIB/l, STR*2/s, BLN/b :library.load "correct.svm" -> &l "bla" -> &s :call $(@&l/"test") s :str.cmp @(s/1) = "bla" -> &b :shutdown 1 :unless @&b TRUE END END %} test: "Entries" %{ PLUGIN "svmstr.so" PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory LIB/l, PTR/p, BLN/b :library.load "correct.svm" -> &l :library.entries @&l -> &p :shutdown 1 :unless (&0+SIZE @&p) IN &2*1 :str.cmp @(@&p/0) = "extra" -> &b :shutdown 2 :unless @&b TRUE :str.cmp @(@&p/1) = "test" -> &b :shutdown 3 :unless @&b TRUE END END %} test: "Get_other" %{ PLUGIN "svmstr.so" PROCESS "test" CODE "main" INLINE :memory LIB/l, STR*2/s, BLN/b, SYM/sym, LIB/sl :library.load "correct.svm" -> &l $(@&l/"extra") -> &sym :library.get @&sym -> &sl "bla" -> &s :call $(@&sl/"test") s :str.cmp @(s/1) = "bla" -> &b :shutdown 1 :unless @&b TRUE END END %} test: "Get_current" %{ PLUGIN "svmstr.so" PROCESS "test" CODE "main" INLINE :symbol start :memory STR*2/s, BLN/b, LIB/sl :library.get $"start" -> &sl "bla" -> &s :call $(@&sl/"join") s :str.cmp @(s/1) = "bla" -> &b :shutdown 1 :unless @&b TRUE :shutdown :symbol join :str.join "" @&P "" -> (P/1) :return END END %} test: "Name" %{ PLUGIN "svmstr.so" PROCESS "test" CODE "main" INLINE :symbol start :memory STR/s, BLN/b, LIB/sl :library.get $"start" -> &sl :library.name @&sl -> &s :str.cmp @&s = "main" -> &b :shutdown 1 :unless @&b TRUE END END %} test: "Source" %{ PLUGIN "svmstr.so" PROCESS "test" CODE "main" INLINE :symbol start :memory STR/s, LIB/sl, PTR/p :library.get $"start" -> &sl :library.code @&sl -> &s :str.regex @&s CONST str.pattern ":library" -> &p :shutdown 1 :unless (&0+SIZE @&p) IN &3*1 END END %} test: "Current" %{ PLUGIN "svmstr.so" PROCESS "test" CODE "main" INLINE :memory LIB/l :library.current -> &l :goto $(@&l/"end") :shutdown 1 :symbol end END END %} DEFINE INSTRUCTION library.load STR:filename -> LIB %{ auto fn = ARGV_VALUE(0,string); std::fstream f; f.open(RAW_STRING(fn).c_str(),std::fstream::in); if(not f.is_open()) { std::ostringstream oss; oss << "Can not open " << RAW_STRING(fn) << " library"; ERROR_INTERNAL(DEVICE,oss.str().c_str()); } f.seekg (0, f.end); int length = f.tellg(); f.seekg (0, f.beg); char * buffer = new char [length]; f.read (buffer,length); if(not f) { delete [] buffer; std::ostringstream oss; oss << "Can not read " << RAW_STRING(fn) << " library"; ERROR_INTERNAL(DEVICE,oss.str().c_str()); } SVM_Variable code = ::svm_code_compile__string(svm,fn,::svm_string_new(svm,buffer,length)); delete [] buffer; if(not ::svm_variable_type_is_code(svm,code)) { SVM_String e = ::svm_value_string_get(svm,code); std::ostringstream oss; oss << "Can not compile " << RAW_STRING(fn) << " library: " << RAW_STRING(e); ERROR_INTERNAL(FAILURE,oss.str().c_str()); } return ::svm_value_library_new(svm,code); %} help: %{ This instruction opens the file specified in argument in read-only, reads the full content of the file and compile the code within the file and returns the library. .P The name of the library is the file name. .P The instruction raises a DEVICE interruption when the file is invalid, and a FAILURE interruption when the source code is invalid. .P Note: The error handling is the difference between this instruction and the built-in :library instruction. %} INSTRUCTION library.entries LIB -> PTR %{ SVM_Value_Library l = ::svm_parameter_value_get(svm,argv[0]); SVM_Code code = ::svm_value_library_get_code(svm,l); SVM_Value_String *s = ::svm_code_symbol_list(svm,code); SVM_Size ls = 0; for(SVM_Value_String* it=s ; *it ; ++it) { ::svm_value_state_is_movable(svm,*it); ++ls; } SVM_Memory_Zone z = ::svm_memory_zone_new(svm); ::svm_memory_zone_append_internal__raw(svm,z,STRING,ls); SVM_Value_Pointer p = ::svm_memory_allocate(svm,CURRENT(kernel),z); ::svm_memory_write_pointer(svm,CURRENT(kernel),p,s); return p; %} help: %{ This instruction returns the name of all symbols of the library, as an array of strings. %} SYSTEM INSTRUCTION library.get SYM -> LIB %{ SVM_Value_Symbol s = ::svm_parameter_value_get(svm,argv[0]); SVM_Code code = ::svm_value_symbol_get_code(svm,s); return ::svm_value_library_new(svm,code); %} help: %{ This instruction returns the library contained into a symbol. .P As this instruction can allow code to run unexpected code, it is limited to non-protected kernels. %} INSTRUCTION library.name LIB -> STR %{ SVM_Value_Library l = ::svm_parameter_value_get(svm,argv[0]); SVM_Code code = ::svm_value_library_get_code(svm,l); SVM_String n = ::svm_code_get_name(svm,code); return NEW_VALUE(string,n); %} help: %{ This instruction returns the name of the given library. %} SYSTEM INSTRUCTION library.code LIB -> STR %{ SVM_Value_Library l = ::svm_parameter_value_get(svm,argv[0]); SVM_Code code = ::svm_value_library_get_code(svm,l); SVM_String n = ::svm_code_get_source(svm,code); return NEW_VALUE(string,n); %} help: %{ This instruction returns the source code of the given library. .P As this instruction can allow code to run unexpected code, it is limited to non-protected kernels. %} SYSTEM INSTRUCTION library.current -> LIB %{ SVM_Code code = ::svm_processor_get_currentcode(svm,CURRENT(kernel)); return ::svm_value_library_new(svm,code); %} help: %{ This instruction returns the current code executed by the processor. .P As this instruction can allow code to run unexpected code, it is limited to non-protected kernels. %}