*/ RL_API REBYTE *RL_Word_String(u32 word) /* ** Return a string related to a given global word identifier. ** ** Returns: ** A copy of the word string, null terminated. ** Arguments: ** word - a global word identifier ** Notes: ** The result is a null terminated copy of the name for your own use. ** The string is always UTF-8 encoded (chars > 127 are encoded.) ** In this API, word identifiers are always canonical. Therefore, ** the returned string may have different spelling/casing than expected. ** The string is allocated with OS_ALLOC and you can OS_FREE it any time. ** ***********************************************************************/ { REBYTE *s1, *s2; // !!This code should use a function from c-words.c (but nothing perfect yet.) if (word == 0 || word >= PG_Word_Table.series->tail) return 0; s1 = VAL_SYM_NAME(BLK_SKIP(PG_Word_Table.series, word)); s2 = OS_ALLOC_ARRAY(REBYTE, LEN_BYTES(s1) + 1); COPY_BYTES(s2, s1, LEN_BYTES(s1) + 1); return s2; }
// // RL_Word_String: C // // Return a string related to a given global word identifier. // // Returns: // A copy of the word string, null terminated. // Arguments: // word - a global word identifier // Notes: // The result is a null terminated copy of the name for your own use. // The string is always UTF-8 encoded (chars > 127 are encoded.) // In this API, word identifiers are always canonical. Therefore, // the returned string may have different spelling/casing than expected. // The string is allocated with OS_ALLOC and you can OS_FREE it any time. // RL_API REBYTE *RL_Word_String(u32 word) { REBYTE *s1, *s2; // !!This code should use a function from c-words.c (but nothing perfect yet.) if (word == 0 || word >= ARR_LEN(PG_Word_Table.array)) return 0; s1 = VAL_SYM_NAME(ARR_AT(PG_Word_Table.array, word)); s2 = OS_ALLOC_N(REBYTE, LEN_BYTES(s1) + 1); COPY_BYTES(s2, s1, LEN_BYTES(s1) + 1); return s2; }
static REBYTE *Get_Next_Line() { REBYTE *bp = inbuf; REBYTE *out; REBCNT len; // Scan for line terminator or end: for (bp = inbuf; *bp != CR && *bp != LF && *bp != 0; bp++); // If found, copy the line and remove it from buffer: if (*bp) { if (*bp == CR && bp[1] == LF) bp++; len = bp - inbuf; out = OS_ALLOC_ARRAY(REBYTE, len + 2); COPY_BYTES(out, inbuf, len+1); out[len+1] = 0; memmove(inbuf, bp + 1, 1 + LEN_BYTES(bp + 1)); return out; } return 0; // more input needed }
*/ static int Read_Directory(REBREQ *dir, REBREQ *file) /* ** This function will read a file directory, one file entry ** at a time, then close when no more files are found. ** ** Procedure: ** ** This function is passed directory and file arguments. ** The dir arg provides information about the directory to read. ** The file arg is used to return specific file information. ** ** To begin, this function is called with a dir->handle that ** is set to zero and a dir->file.path string for the directory. ** ** The directory is opened and a handle is stored in the dir ** structure for use on subsequent calls. If an error occurred, ** dir->error is set to the error code and -1 is returned. ** The dir->size field can be set to the number of files in the ** dir, if it is known. The dir->file.index field can be used by this ** function to store information between calls. ** ** If the open succeeded, then information about the first file ** is stored in the file argument and the function returns 0. ** On an error, the dir->error is set, the dir is closed, ** dir->handle is nulled, and -1 is returned. ** ** The caller loops until all files have been obtained. This ** action should be uninterrupted. (The caller should not perform ** additional OS or IO operations between calls.) ** ** When no more files are found, the dir is closed, dir->handle ** is nulled, and 1 is returned. No file info is returned. ** (That is, this function is called one extra time. This helps ** for OSes that may deallocate file strings on dir close.) ** ** Note that the dir->file.path can contain wildcards * and ?. The ** processing of these can be done in the OS (if supported) or ** by a separate filter operation during the read. ** ** Store file date info in file->file.index or other fields? ** Store permissions? Ownership? Groups? Or, require that ** to be part of a separate request? ** ***********************************************************************/ { struct stat info; struct dirent *d; char *cp; DIR *h; int n; // Remove * from tail, if present. (Allowed because the // path was copied into to-local-path first). n = strlen(cp = dir->file.path); if (n > 0 && cp[n-1] == '*') cp[n-1] = 0; // If no dir handle, open the dir: if (!(h = dir->handle)) { h = opendir(dir->file.path); if (!h) { dir->error = errno; return DR_ERROR; } dir->handle = h; CLR_FLAG(dir->flags, RRF_DONE); } // Get dir entry (skip over the . and .. dir cases): do { // Read next file entry or error: if (!(d = readdir(h))) { //dir->error = errno; closedir(h); dir->handle = 0; //if (dir->error) return DR_ERROR; SET_FLAG(dir->flags, RRF_DONE); // no more files return DR_DONE; } cp = d->d_name; } while (cp[0] == '.' && (cp[1] == 0 || cp[1] == '.')); file->modes = 0; COPY_BYTES(file->file.path, cp, MAX_FILE_NAME); // NOTE: not all posix filesystems support this (mainly // the Linux and BSD support it.) If this fails to build, a // different mechanism must be used. However, this is the // most efficient, because it does not require a separate // file system call for determining directories. if (d->d_type == DT_DIR) SET_FLAG(file->modes, RFM_DIR); // Line below DOES NOT WORK -- because we need full path. //Get_File_Info(file); // updates modes, size, time return DR_DONE; }
KS_E_ERROR ks_file_write(KS_FILE_PTR file_ptr, LongWord position, LongWord data_size, Pointer data_buffer) { /* ************************************************************** * * Local declarations: * * ************************************************************** */ KS_E_ERROR error; /* Holds error codes for subroutine*/ /* calls */ LongWord data_offset; /* Offset into the buffer to return*/ LongWord remaining_space; /* Space remaining in file buffer */ LongWord buffer_request; /* Size of each copy from the */ /* file buffer */ ROUTINE_ENTER(); /* ************************************************************** * * Verify the structure ID passed in is the correct one. * * ************************************************************** */ if (file_ptr->struct_id != KS_FILE_ID) { KS_ERROR(KS_E_INVALID_STRUCT_ID, KS_FILE_ID); }; /* ************************************************************** * * Zero the number of bytes transfered in the KS_FILE structure. * * ************************************************************** */ file_ptr->data_size = 0; /* ************************************************************** * * If there is a buffer, then lets put data into the file buffer.* * ************************************************************** */ if (file_ptr->buffer_size != NULL) { /* ********************************************************** * * Loop till we satisfy the request (or take an error) * * ********************************************************** */ data_offset = 0; while (data_size > 0) { /* ****************************************************** * * Calculate the remaining space in the buffer. If * * there is any space left in the buffer then lets copy * * as much as we need to into the file buffer. * * ****************************************************** */ remaining_space = (file_ptr->buffer_available) - (file_ptr->buffer_offset); if (remaining_space > 0) { buffer_request = MIN(data_size, remaining_space); COPY_BYTES(data_buffer, data_offset, file_ptr->buffer, file_ptr->buffer_offset, buffer_request); /* ************************************************** * * Now modify the parameters of the buffers by: * * * * 1) Adding the size of the request to the file * * buffer ofset and the data offset (IE: Indices to * * the file buffer and the read request buffer). * * * * 2) Subtracting the request size from the read * * request size and the remaining number of * * characters in the file buffer. * * ************************************************** */ file_ptr->buffer_offset = file_ptr->buffer_offset + buffer_request; data_offset = data_offset + buffer_request; file_ptr->data_size = data_offset; data_size = data_size - buffer_request; remaining_space = remaining_space - buffer_request; }; /* ****************************************************** * * If the file buffer is full, then we have to write it * * to disk. The problem is that the buffer size may * * have changed due to what our user wants (users are * * bound to be the end of all computing...). This means * * that we'll junp through a few hoops if we must change * * buffer sizes - so expect some weirdness here. * * ****************************************************** */ if (remaining_space == 0) { /* ************************************************** * * Issue a Read to the file into our buffer. * * ************************************************** */ KSf_pkts.IO.pCount = 4; KSf_pkts.IO.refNum = file_ptr->refNum; KSf_pkts.IO.dataBuffer = TO_POINTER(file_ptr->buffer); KSf_pkts.IO.requestCount = file_ptr->buffer_size; WriteGS(&KSf_pkts.IO); if ((error = GET_ERROR()) != KS_E_SUCCESS) { goto EXIT_NOW; }; file_ptr->buffer_available = file_ptr->buffer_size; file_ptr->buffer_offset = 0; /* ************************************************** * * This is the above mentioned weirdness - if the * * user specified a different size buffer we will * * no comply with their wishes. * * ************************************************** */ if (file_ptr->buffer_size != KSf_FileBufferSize) { KS_MEMORY_DEALLOCATE(file_ptr->buffer_handle, error); if (error != KS_E_SUCCESS) { goto EXIT_NOW; }; KS_MEMORY_ALLOCATE(attrFixed + attrLocked, KSf_FileBufferSize, BUFFER_USERID, file_ptr->buffer_handle, error); if (error != KS_E_SUCCESS) { goto EXIT_NOW; }; file_ptr->buffer = (Byte *) *(file_ptr->buffer_handle); file_ptr->buffer_size = KSf_FileBufferSize; file_ptr->buffer_available = KSf_FileBufferSize; }; }; /* End if there is no remaining buffer space */ }; /* End while there are characters to be read... */ KS_SUCCESS(); }; /* End if we are doing buffer I/O from the file */ /* ************************************************************** * * Ok, we've done enough buffering... lets do some real output...* * * * Position the 'mark' (where we will write to) in the file. * * Note: We'll move the mark only if our user asks us to. * * ************************************************************** */ if (position != KS_NEXT_FILE_POSITION) { KSf_pkts.position.pCount = 3; KSf_pkts.position.refNum = file_ptr->refNum; KSf_pkts.position.base = startPlus; KSf_pkts.position.displacement = position; SetMarkGS(&KSf_pkts.position); if ((error = GET_ERROR()) != KS_E_SUCCESS) { goto EXIT_NOW; }; }; /* End if we must change the file position */ /* ************************************************************** * * Setup the I/O packet and write what our user is asking for. * * ************************************************************** */ KSf_pkts.IO.pCount = 4; KSf_pkts.IO.refNum = file_ptr->refNum; KSf_pkts.IO.dataBuffer = data_buffer; KSf_pkts.IO.requestCount = data_size; WriteGS(&KSf_pkts.IO); if ((error = GET_ERROR()) != KS_E_SUCCESS) { goto EXIT_NOW; }; /* ************************************************************** * * Save the number of bytes transfered in the KS_FILE structure. * * ************************************************************** */ file_ptr->data_size = KSf_pkts.IO.transferCount; /* ************************************************************** * * Return the status back to our caller. * * ************************************************************** */ EXIT_NOW: if (error != KS_E_SUCCESS) { KS_ERROR(error, KS_FILE_ID); }; KS_SUCCESS(); } /* End of ks_file_write() */
*/ void Crash(REBINT id, ...) /* ** Print a failure message and abort. ** ** LATIN1 ONLY!! (For now) ** ** The error is identified by id number, which can reference an ** error message string in the boot strings block. ** ** Note that lower level error messages should not attempt to ** use the %r (mold value) format (uses higher level functions). ** ** See panics.h for list of crash errors. ** ***********************************************************************/ { va_list args; REBYTE buf[CRASH_BUF_SIZE]; REBYTE *msg; REBINT n = 0; va_start(args, id); DISABLE_GC; if (Reb_Opts->crash_dump) { Dump_Info(); Dump_Stack(0, 0); } // "REBOL PANIC #nnn:" COPY_BYTES(buf, Crash_Msgs[CM_ERROR], CRASH_BUF_SIZE); APPEND_BYTES(buf, " #", CRASH_BUF_SIZE); Form_Int(buf + LEN_BYTES(buf), id); APPEND_BYTES(buf, ": ", CRASH_BUF_SIZE); // "REBOL PANIC #nnn: put error message here" // The first few error types only print general error message. // Those errors > RP_STR_BASE have specific error messages (from boot.r). if (id < RP_BOOT_DATA) n = CM_DEBUG; else if (id < RP_INTERNAL) n = CM_BOOT; else if (id < RP_ASSERTS) n = CM_INTERNAL; else if (id < RP_DATATYPE) n = CM_ASSERT; else if (id < RP_STR_BASE) n = CM_DATATYPE; else if (id > RP_STR_BASE + RS_MAX - RS_ERROR) n = CM_DEBUG; // Use the above string or the boot string for the error (in boot.r): msg = (REBYTE*)(n >= 0 ? Crash_Msgs[n] : BOOT_STR(RS_ERROR, id - RP_STR_BASE - 1)); Form_Var_Args(buf + LEN_BYTES(buf), CRASH_BUF_SIZE - 1 - LEN_BYTES(buf), msg, args); n = LEN_BYTES(Crash_Msgs[CM_CONTACT]); if ((LEN_BYTES(buf) + n) < (CRASH_BUF_SIZE - 1)) APPEND_BYTES(buf, Crash_Msgs[CM_CONTACT], n); // Convert to OS-specific char-type: #ifdef disable_for_now //OS_WIDE_CHAR /// win98 does not support it { REBCHR s1[512]; REBCHR s2[2000]; n = TO_OS_STR(s1, Crash_Msgs[CM_ERROR], LEN_BYTES(Crash_Msgs[CM_ERROR])); if (n > 0) s1[n] = 0; // terminate else OS_EXIT(200); // bad conversion n = TO_OS_STR(s2, buf, LEN_BYTES(buf)); if (n > 0) s2[n] = 0; else OS_EXIT(200); OS_CRASH(s1, s2); } #else OS_CRASH(Crash_Msgs[CM_ERROR], buf); #endif }