/* ========================================================================= * * Nanite Systems Advanced Research Encapsulation System * * Copyright (c) 2023 Nanite Systems Corporation * * ========================================================================= * * FILE.H.LSL Header Component * * This program is covered under the terms of the ARES Software Copyright * License, Section 3 (ASCL-iii). It may be redistributed or used as the * basis of commercial, closed-source products so long as steps are taken * to ensure proper attribution as defined in the text of the license. * * To see the full text of the ASCL, type 'help license' on any standard * ARES distribution, or visit http://nanite-systems.com/ASCL for the * current version. * * DISCLAIMER * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS * IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY * DAMAGES HOWEVER CAUSED ON ANY THEORY OF LIABILITY ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * ========================================================================= * */ #ifndef _ARES_FILE_H_ #define _ARES_FILE_H_ #include #define FILE_R 0 #define FILE_INS 1 #define FILE_OUTS 2 #define FILE_USER 3 #define FILE_NAME 4 #define FILE_OFFSET 5 #define FILE_LENGTH 6 /* To use this script, call fopen() with the 'outs', 'ins', and 'user' from main() When file contents are available, the program will receive: SIGNAL_NOTIFY message: PROGRAM_NAME + " file" ins: matching the file_handle returned by fopen() You can then call fread(file_handle) to get contents. fread() has the following special return values: JSON_FALSE: file does not exist or file is empty JSON_TRUE: file was opened successfully and data will arrive soon If fread() returns any other value, it is file data. fread() reads files in buffer chunks of FILE_PAGE_LENGTH and always advances to the next chunk. FILE_PAGE_LENGTH is 1024 in ARES alpha 1. For notecards, which are not read in bytes, this is actually translated into 4 lines. fread() will close the file automatically when it is done reading, at which point getjs(tasks_queue, [file_handle]) will return JSON_INVALID. By default, this API will automatically try to resolve tasks for you when the file is closed. This is good for simple file readers but wrong if you intend to do more processing afterward. To suppress this behavior, set '_resolved = 0' before calling fopen(), and pass NULL_KEY for ins. */ // fopen(output_stream, input_stream, user_key, file_name): returns file_handle key fopen(key outs, key ins, key user, string filename) { key q = llGenerateKey(); // send request to io daemon to create pipe and fetch file length: file_open(q, filename); // track file information and prevent job from sleeping during load process string metadata = list2js(JSON_ARRAY, [ _resolved, // callback number for program that summoned us ins, // original input stream (often used as a callback handle) outs, // output stream user, // user that initiated the request filename, // filename being worked on NOWHERE, // file offset (haven't started reading yet) NOWHERE // file length (loaded first) ]); task_begin(q, metadata); // metadata is stored in the global JSON variable tasks_queue, and can be accessed later _resolved = 0; return q; } // fread(file_handle): returns JSON_TRUE if file opened successfully, JSON_FALSE if file empty/missing, otherwise file text string fread(key q) { // split apart file metadata into a list (smaller code) list file = js2list(getjs(tasks_queue, [q])); integer file_length = geti(file, FILE_LENGTH); string fn = gets(file, FILE_NAME); // copy contents of LSD pipe into local variable: string buffer; pipe_read(q, buffer); integer offset = geti(file, FILE_OFFSET); _resolved = 0; if(!~file_length) { // on the first successful call we load the file length file_length = (integer)buffer; tasks_queue = setjs(tasks_queue, [q, FILE_LENGTH], (string)file_length); // for notecards, file length is measured as 256 * (number of lines), // NOT the actual character count if(file_length > 0) { // a length greater than 0 indicates the file exists // start reading file file_read(q, fn, offset = 0); tasks_queue = setjs(tasks_queue, [q, FILE_OFFSET], (string)offset); buffer = JSON_TRUE; } else { // no file was found, or file was empty file_close(q); // job can now end: // resolve_io(geti(file, FILE_R), getk(file, FILE_OUTS), getk(file, FILE_INS)); resolve_i(geti(file, FILE_R), getk(file, FILE_INS)); task_end(q); buffer = JSON_FALSE; } } else { // got length earlier, so this must be file data // move forward to next page: offset += FILE_PAGE_LENGTH; // is there more file? if(offset < file_length) { // record new offset: tasks_queue = setjs(tasks_queue, [q, FILE_OFFSET], (string)offset); // get next section: file_read(q, fn, offset); } else { // reached end of file file_close(q); // job can now end: // resolve_io(geti(file, FILE_R), getk(file, FILE_OUTS), getk(file, FILE_INS)); resolve_i(geti(file, FILE_R), getk(file, FILE_INS)); // delete file handle: task_end(q); } } // send data to the program return buffer; } // preview what fread() will return without actually initiating the next file request string fpeek(key q) { // split apart file metadata into a list (smaller code) list file = js2list(getjs(tasks_queue, [q])); integer file_length = geti(file, FILE_LENGTH); // copy contents of LSD pipe into local variable: string buffer = llLinksetDataRead("p:" + (string)q); if(!~file_length) { // on the first successful call we load the file length file_length = (integer)buffer; // tasks_queue = setjs(tasks_queue, [q, FILE_LENGTH], (string)file_length); // for notecards, file length is measured as 256 * (number of lines), // NOT the actual character count if(file_length > 0) { // a length greater than 0 indicates the file exists buffer = JSON_TRUE; } else { // no file was found, or file was empty buffer = JSON_FALSE; } } // send data to the program return buffer; } // abort file reading (only needed when using fpeek()): fclose(key q) { // split apart file metadata into a list (smaller code) list file = js2list(getjs(tasks_queue, [q])); file_close(q); // job can now end: // resolve_io(geti(file, FILE_R), getk(file, FILE_OUTS), getk(file, FILE_INS)); resolve_i(geti(file, FILE_R), getk(file, FILE_INS)); // delete file handle: task_end(q); } #endif // _ARES_FILE_H_