LEAFTYPE radix_get(struct ROOTSTRUCT * tree, LEAFTYPE leaf, EXTRA_ARG aux) { LEAFTYPE result; struct _internal_node * node; uint32_t dir; if (tree->leafcount == 0) return NO_LEAF; if (tree->leafcount == 1) { result = tree->root.leaf; if (COMPARE(result, leaf) == -1) return result; else return NO_LEAF; } /* root points to a node */ node = tree->root.node; while (1) { dir = DECIDE(leaf, node->critbit, aux); if (IS_LEAF(node, dir)) { result = node->child[dir].leaf; break; } else { node = node->child[dir].node; } } if (COMPARE(result, leaf) == -1) return result; else return NO_LEAF; }
LEAFTYPE radix_del(struct ROOTSTRUCT * tree, LEAFTYPE leaf, EXTRA_ARG aux) { LEAFTYPE result; struct _internal_node * node, * parent; uint32_t dir, dir2; if (tree->leafcount == 0) return NO_LEAF; if (tree->leafcount == 1) { result = tree->root.leaf; if (COMPARE(result, leaf) == -1) { tree->root.leaf = NO_LEAF; tree->leafcount --; return result; } else return NO_LEAF; } /* else */ node = tree->root.node; while (1) { dir = DECIDE(leaf, node->critbit, aux); if (IS_LEAF(node, dir)) { result = node->child[dir].leaf; break; } else { node = node->child[dir].node; } } if (COMPARE(result, leaf) == -1) { parent = tree->root.node; while (1) { dir2 = DECIDE(leaf, parent->critbit, aux); if (parent->child[dir2].node == node) break; else parent = parent->child[dir2].node; } if (IS_LEAF(node, 1 - dir)) { parent->child[dir2].leaf = node->child[1 - dir].leaf; SET_LEAF(parent, dir2); } else { parent->child[dir2].node = node->child[1 - dir].node; } tree->leafcount --; DEALLOC(node); return result; } else return NO_LEAF; }
*/ static REB_R File_Actor(struct Reb_Call *call_, REBSER *port, REBCNT action) /* ** Internal port handler for files. ** ***********************************************************************/ { REBVAL *spec; REBVAL *path; REBREQ *file = 0; REBCNT args = 0; REBCNT len; REBOOL opened = FALSE; // had to be opened (shortcut case) //Print("FILE ACTION: %r", Get_Action_Word(action)); Validate_Port(port, action); *D_OUT = *D_ARG(1); // Validate PORT fields: spec = BLK_SKIP(port, STD_PORT_SPEC); if (!IS_OBJECT(spec)) Trap1_DEAD_END(RE_INVALID_SPEC, spec); path = Obj_Value(spec, STD_PORT_SPEC_HEAD_REF); if (!path) Trap1_DEAD_END(RE_INVALID_SPEC, spec); if (IS_URL(path)) path = Obj_Value(spec, STD_PORT_SPEC_HEAD_PATH); else if (!IS_FILE(path)) Trap1_DEAD_END(RE_INVALID_SPEC, path); // Get or setup internal state data: file = (REBREQ*)Use_Port_State(port, RDI_FILE, sizeof(*file)); switch (action) { case A_READ: args = Find_Refines(call_, ALL_READ_REFS); // Handle the READ %file shortcut case: if (!IS_OPEN(file)) { REBCNT nargs = AM_OPEN_READ; if (args & AM_READ_SEEK) nargs |= AM_OPEN_SEEK; Setup_File(file, nargs, path); Open_File_Port(port, file, path); opened = TRUE; } if (args & AM_READ_SEEK) Set_Seek(file, D_ARG(ARG_READ_INDEX)); len = Set_Length( file, D_REF(ARG_READ_PART) ? VAL_INT64(D_ARG(ARG_READ_LENGTH)) : -1 ); Read_File_Port(D_OUT, port, file, path, args, len); if (opened) { OS_DO_DEVICE(file, RDC_CLOSE); Cleanup_File(file); } if (file->error) Trap_Port_DEAD_END(RE_READ_ERROR, port, file->error); break; case A_APPEND: if (!(IS_BINARY(D_ARG(2)) || IS_STRING(D_ARG(2)) || IS_BLOCK(D_ARG(2)))) Trap1_DEAD_END(RE_INVALID_ARG, D_ARG(2)); file->special.file.index = file->special.file.size; SET_FLAG(file->modes, RFM_RESEEK); case A_WRITE: args = Find_Refines(call_, ALL_WRITE_REFS); spec = D_ARG(2); // data (binary, string, or block) // Handle the READ %file shortcut case: if (!IS_OPEN(file)) { REBCNT nargs = AM_OPEN_WRITE; if (args & AM_WRITE_SEEK || args & AM_WRITE_APPEND) nargs |= AM_OPEN_SEEK; else nargs |= AM_OPEN_NEW; Setup_File(file, nargs, path); Open_File_Port(port, file, path); opened = TRUE; } else { if (!GET_FLAG(file->modes, RFM_WRITE)) Trap1_DEAD_END(RE_READ_ONLY, path); } // Setup for /append or /seek: if (args & AM_WRITE_APPEND) { file->special.file.index = -1; // append SET_FLAG(file->modes, RFM_RESEEK); } if (args & AM_WRITE_SEEK) Set_Seek(file, D_ARG(ARG_WRITE_INDEX)); // Determine length. Clip /PART to size of string if needed. len = VAL_LEN(spec); if (args & AM_WRITE_PART) { REBCNT n = Int32s(D_ARG(ARG_WRITE_LENGTH), 0); if (n <= len) len = n; } Write_File_Port(file, spec, len, args); if (opened) { OS_DO_DEVICE(file, RDC_CLOSE); Cleanup_File(file); } if (file->error) Trap1_DEAD_END(RE_WRITE_ERROR, path); break; case A_OPEN: args = Find_Refines(call_, ALL_OPEN_REFS); // Default file modes if not specified: if (!(args & (AM_OPEN_READ | AM_OPEN_WRITE))) args |= (AM_OPEN_READ | AM_OPEN_WRITE); Setup_File(file, args, path); Open_File_Port(port, file, path); // !!! needs to change file modes to R/O if necessary break; case A_COPY: if (!IS_OPEN(file)) Trap1_DEAD_END(RE_NOT_OPEN, path); //!!!! wrong msg len = Set_Length(file, D_REF(2) ? VAL_INT64(D_ARG(3)) : -1); Read_File_Port(D_OUT, port, file, path, args, len); break; case A_OPENQ: if (IS_OPEN(file)) return R_TRUE; return R_FALSE; case A_CLOSE: if (IS_OPEN(file)) { OS_DO_DEVICE(file, RDC_CLOSE); Cleanup_File(file); } break; case A_DELETE: if (IS_OPEN(file)) Trap1_DEAD_END(RE_NO_DELETE, path); Setup_File(file, 0, path); if (OS_DO_DEVICE(file, RDC_DELETE) < 0 ) Trap1_DEAD_END(RE_NO_DELETE, path); break; case A_RENAME: if (IS_OPEN(file)) Trap1_DEAD_END(RE_NO_RENAME, path); else { REBSER *target; Setup_File(file, 0, path); // Convert file name to OS format: if (!(target = Value_To_OS_Path(D_ARG(2), TRUE))) Trap1_DEAD_END(RE_BAD_FILE_PATH, D_ARG(2)); file->common.data = BIN_DATA(target); OS_DO_DEVICE(file, RDC_RENAME); Free_Series(target); if (file->error) Trap1_DEAD_END(RE_NO_RENAME, path); } break; case A_CREATE: // !!! should it leave file open??? if (!IS_OPEN(file)) { Setup_File(file, AM_OPEN_WRITE | AM_OPEN_NEW, path); if (OS_DO_DEVICE(file, RDC_CREATE) < 0) Trap_Port_DEAD_END(RE_CANNOT_OPEN, port, file->error); OS_DO_DEVICE(file, RDC_CLOSE); } break; case A_QUERY: if (!IS_OPEN(file)) { Setup_File(file, 0, path); if (OS_DO_DEVICE(file, RDC_QUERY) < 0) return R_NONE; } Ret_Query_File(port, file, D_OUT); // !!! free file path? break; case A_MODIFY: Set_Mode_Value(file, Get_Mode_Id(D_ARG(2)), D_ARG(3)); if (!IS_OPEN(file)) { Setup_File(file, 0, path); if (OS_DO_DEVICE(file, RDC_MODIFY) < 0) return R_NONE; } return R_TRUE; break; case A_INDEXQ: SET_INTEGER(D_OUT, file->special.file.index + 1); break; case A_LENGTHQ: SET_INTEGER(D_OUT, file->special.file.size - file->special.file.index); // !clip at zero break; case A_HEAD: file->special.file.index = 0; goto seeked; case A_TAIL: file->special.file.index = file->special.file.size; goto seeked; case A_NEXT: file->special.file.index++; goto seeked; case A_BACK: if (file->special.file.index > 0) file->special.file.index--; goto seeked; case A_SKIP: file->special.file.index += Get_Num_Arg(D_ARG(2)); goto seeked; case A_HEADQ: DECIDE(file->special.file.index == 0); case A_TAILQ: DECIDE(file->special.file.index >= file->special.file.size); case A_PASTQ: DECIDE(file->special.file.index > file->special.file.size); case A_CLEAR: // !! check for write enabled? SET_FLAG(file->modes, RFM_RESEEK); SET_FLAG(file->modes, RFM_TRUNCATE); file->length = 0; if (OS_DO_DEVICE(file, RDC_WRITE) < 0) Trap1_DEAD_END(RE_WRITE_ERROR, path); break; /* Not yet implemented: A_AT, // 38 A_PICK, // 41 A_PATH, // 42 A_PATH_SET, // 43 A_FIND, // 44 A_SELECT, // 45 A_TAKE, // 49 A_INSERT, // 50 A_REMOVE, // 52 A_CHANGE, // 53 A_POKE, // 54 A_QUERY, // 64 A_FLUSH, // 65 */ default: Trap_Action_DEAD_END(REB_PORT, action); } return R_OUT; seeked: SET_FLAG(file->modes, RFM_RESEEK); return R_ARG1; is_true: return R_TRUE; is_false: return R_FALSE; }
*/ REBINT Do_Series_Action(REBCNT action, REBVAL *value, REBVAL *arg) /* ** Common series functions. ** ***********************************************************************/ { REBINT index; REBINT tail; REBINT len = 0; // Common setup code for all actions: if (action != A_MAKE && action != A_TO) { index = (REBINT)VAL_INDEX(value); tail = (REBINT)VAL_TAIL(value); } else return -1; switch (action) { //-- Navigation: case A_HEAD: VAL_INDEX(value) = 0; break; case A_TAIL: VAL_INDEX(value) = (REBCNT)tail; break; case A_HEADQ: DECIDE(index == 0); case A_TAILQ: DECIDE(index >= tail); case A_PASTQ: DECIDE(index > tail); case A_NEXT: if (index < tail) VAL_INDEX(value)++; break; case A_BACK: if (index > 0) VAL_INDEX(value)--; break; case A_SKIP: case A_AT: len = Get_Num_Arg(arg); { REBI64 i = (REBI64)index + (REBI64)len; if (action == A_SKIP) { if (IS_LOGIC(arg)) i--; } else { // A_AT if (len > 0) i--; } if (i > (REBI64)tail) i = (REBI64)tail; else if (i < 0) i = 0; VAL_INDEX(value) = (REBCNT)i; } break; /* case A_ATZ: len = Get_Num_Arg(arg); { REBI64 idx = Add_Max(0, index, len, MAX_I32); if (idx < 0) idx = 0; VAL_INDEX(value) = (REBCNT)idx; } break; */ case A_INDEXQ: SET_INTEGER(DS_RETURN, ((REBI64)index) + 1); return R_RET; case A_LENGTHQ: SET_INTEGER(DS_RETURN, tail > index ? tail - index : 0); return R_RET; case A_REMOVE: // /PART length TRAP_PROTECT(VAL_SERIES(value)); len = DS_REF(2) ? Partial(value, 0, DS_ARG(3), 0) : 1; index = (REBINT)VAL_INDEX(value); if (index < tail && len != 0) Remove_Series(VAL_SERIES(value), VAL_INDEX(value), len); break; case A_ADD: // Join_Strings(value, arg); case A_SUBTRACT: // "test this" - 10 case A_MULTIPLY: // "t" * 4 = "tttt" case A_DIVIDE: case A_REMAINDER: case A_POWER: case A_ODDQ: case A_EVENQ: case A_ABSOLUTE: Trap_Action(VAL_TYPE(value), action); default: return -1; } DS_RET_VALUE(value); return R_RET; is_false: return R_FALSE; is_true: return R_TRUE; }
LEAFTYPE radix_add(struct ROOTSTRUCT * tree, LEAFTYPE leaf, EXTRA_ARG aux, int should_replace, int* error) { LEAFTYPE result; struct _internal_node * node, * parent, * child; uint32_t dir, dir2; int32_t critbit; *error = 0; if (tree->leafcount == 0) { tree->root.leaf = leaf; tree->leafcount ++; return NO_LEAF; } else if (tree->leafcount == 1) { result = tree->root.leaf; critbit = COMPARE(leaf, result); if (critbit == -1) { if (should_replace) { node->child[dir].leaf = leaf; return result; } else return leaf; } else { node = (struct _internal_node *) ALLOC(sizeof (struct _internal_node)); if (node == NULL) { *error = -1; return NO_LEAF; } else { node->critbit = critbit; dir = DECIDE(leaf, critbit, aux); node->child[dir].leaf = leaf; SET_LEAF(node, dir); } result = tree->root.leaf; node->child[1 - dir].leaf = tree->root.leaf; SET_LEAF(node, 1 - dir); tree->root.node = node; tree->leafcount ++; return NO_LEAF; } } /* else */ node = tree->root.node; while (1) { dir = DECIDE(leaf, node->critbit, aux); if (IS_LEAF(node, dir)) { result = node->child[dir].leaf; break; } else { node = node->child[dir].node; } } critbit = COMPARE(leaf, result); if (critbit == -1) { if (should_replace) { node->child[dir].leaf = leaf; return result; } else return leaf; } else { node = (struct _internal_node *) ALLOC(sizeof (struct _internal_node)); if (node == NULL) { *error = -1; return NO_LEAF; } else { node->critbit = critbit; dir = DECIDE(leaf, critbit, aux); node->child[dir].leaf = leaf; SET_LEAF(node, dir); } child = tree->root.node; if (node->critbit < child->critbit) { node->child[1 - dir].node = child; SET_NODE(node, 1 - dir); tree->root.node = node; } else while (1) { parent = child; dir2 = DECIDE(leaf, parent->critbit, aux); if (IS_LEAF(parent, dir2)) { result = parent->child[dir2].leaf; //node->child[1 - dir].leaf = tree->root.leaf; node->child[1 - dir].leaf = parent->child[dir2].leaf; SET_LEAF(node, 1 - dir); parent->child[dir2].node = node; SET_NODE(parent, dir2); break; } else { child = parent->child[dir2].node; if (node->critbit < child->critbit) { node->child[1 - dir].node = child; SET_NODE(node, 1 - dir); parent->child[dir2].node = node; SET_NODE(parent, dir2); break; } } } tree->leafcount ++; return NO_LEAF; } }