/** * Compare the objects according to the comparison (returns 0 or 1) */ static t_snode *si_comparison(t_ast_element *p, int cmp) { t_snode *node1 = SI0(p); t_snode *node2 = SI1(p); // Check if the references are to the same object and we are doing a ==. If so, we are always true if (IS_OBJECT(node1) && IS_OBJECT(node2) && cmp == COMPARISON_EQ && node1->data.obj == node2->data.obj) return 0; t_object *obj1 = si_get_object(node1); t_object *obj2 = si_get_object(node2); if (obj1->type != obj2->type) { saffire_error("Types on comparison are not equal"); } t_object *obj = object_comparison(obj1, cmp, obj2); RETURN_SNODE_OBJECT(obj); }
*/ static void Ret_Query_Net(REBSER *port, REBREQ *sock, REBVAL *ret) /* ***********************************************************************/ { REBVAL *info = In_Object(port, STD_PORT_SCHEME, STD_SCHEME_INFO, 0); REBSER *obj; if (!info || !IS_OBJECT(info)) Trap_Port(RE_INVALID_SPEC, port, -10); obj = CLONE_OBJECT(VAL_OBJ_FRAME(info)); SET_OBJECT(ret, obj); Set_Tuple( OFV(obj, STD_NET_INFO_LOCAL_IP), cast(REBYTE*, &sock->special.net.local_ip), 4 ); Set_Tuple( OFV(obj, STD_NET_INFO_REMOTE_IP), cast(REBYTE*, &sock->special.net.remote_ip), 4 ); SET_INTEGER(OFV(obj, STD_NET_INFO_LOCAL_PORT), sock->special.net.local_port); SET_INTEGER(OFV(obj, STD_NET_INFO_REMOTE_PORT), sock->special.net.remote_port); }
/** * Returns object from a node. If the node points to a variable, return the object where this variable * points to. * * $a -> returns the object where $a points to * <obj> -> returns plain object */ static t_object *si_get_object(t_snode *node) { t_object *obj; if (IS_OBJECT(node)) { return node->data.obj; } if (HAS_IDENTIFIER_OBJ(node)) { // Fetch object where this var references to, and add it to the destination var return node->data.id.obj; } if (HAS_IDENTIFIER_ID(node)) { // Fetch object where this var references to, and add it to the destination var //t_hash_table_bucket *htb = si_find_in_context(node->data.id.id); char *key = node->data.id.id; obj = si_find_var_in_context(key, NULL); if (! obj) { saffire_error("This variable is not initialized!"); } return obj; } saffire_error("This identifier does not have any ID nor OBJ"); return NULL; }
*/ void Ret_Query_File(REBSER *port, REBREQ *file, REBVAL *ret) /* ** Query file and set RET value to resulting STD_FILE_INFO object. ** ***********************************************************************/ { REBVAL *info = In_Object(port, STD_PORT_SCHEME, STD_SCHEME_INFO, 0); REBSER *obj; REBSER *ser; if (!info || !IS_OBJECT(info)) Trap_Port(RE_INVALID_SPEC, port, -10); obj = CLONE_OBJECT(VAL_OBJ_FRAME(info)); SET_OBJECT(ret, obj); Init_Word_Unbound( OFV(obj, STD_FILE_INFO_TYPE), REB_WORD, GET_FLAG(file->modes, RFM_DIR) ? SYM_DIR : SYM_FILE ); SET_INTEGER(OFV(obj, STD_FILE_INFO_SIZE), file->special.file.size); Set_File_Date(file, OFV(obj, STD_FILE_INFO_DATE)); ser = To_REBOL_Path(file->special.file.path, 0, OS_WIDE, 0); Set_Series(REB_FILE, OFV(obj, STD_FILE_INFO_NAME), ser); }
// // Ret_Query_Net: C // static void Ret_Query_Net(REBSER *port, REBREQ *sock, REBVAL *ret) { REBVAL *info = In_Object(port, STD_PORT_SCHEME, STD_SCHEME_INFO, 0); REBSER *obj; if (!info || !IS_OBJECT(info)) fail (Error_On_Port(RE_INVALID_SPEC, port, -10)); obj = Copy_Array_Shallow(VAL_OBJ_FRAME(info)); MANAGE_SERIES(obj); Val_Init_Object(ret, obj); Set_Tuple( OFV(obj, STD_NET_INFO_LOCAL_IP), cast(REBYTE*, &sock->special.net.local_ip), 4 ); Set_Tuple( OFV(obj, STD_NET_INFO_REMOTE_IP), cast(REBYTE*, &sock->special.net.remote_ip), 4 ); SET_INTEGER(OFV(obj, STD_NET_INFO_LOCAL_PORT), sock->special.net.local_port); SET_INTEGER(OFV(obj, STD_NET_INFO_REMOTE_PORT), sock->special.net.remote_port); }
static int get_tok (char *js, jsmntok_t *tok, int ntok, char *s) { int i; int do_cmp = ~(0); /* only compare first value into token pair */ if (tok->type != JSMN_OBJECT) { return -1; } for (i = 1, tok++; i < ntok; ) { /* we don't expect nested Objects */ if (IS_OBJECT(*tok)) { return -1; } /* if token is an array, skip it */ if (IS_ARRAY(*tok)) { int skip = skip_array (tok + 1, tok->size); if (skip == -1) { return -1; } i += skip + 1; tok += skip + 1; do_cmp = ~(do_cmp); continue; } /* simple token: compare only if first value into pair and return index of second value if matched */ if ((do_cmp) && (TOK_CMP(js, *tok, s))) { return (i + 1); } do_cmp = ~(do_cmp); i += 1; tok += 1; } return -1; }
*/ REBVAL *Find_In_Contexts(REBCNT sym, REBVAL *where) /* ** Search a block of objects for a given word symbol and ** return the value for the word. NULL if not found. ** ***********************************************************************/ { REBVAL *val; for (; NOT_END(where); where++) { if (IS_WORD(where)) { val = Get_Var(where); } else if (IS_PATH(where)) { Do_Path(&where, 0); val = DS_TOP; // only safe for short time! } else val = where; if (IS_OBJECT(val)) { val = Find_Word_Value(VAL_OBJ_FRAME(val), sym); if (val) return val; } } return 0; }
/** * Interpret a leaf. Returns the last object encountered, or a NULL object. */ t_object *interpreter_leaf(t_ast_element *p) { t_snode *node = _interpreter(p); if (IS_OBJECT(node)) { RETURN_OBJECT(node->data.obj); } RETURN_NULL; }
CObject* lua_toobject ( lua_State* luaVM, int iArgument ) { CElement* pElement = lua_toelement ( luaVM, iArgument ); if ( pElement && IS_OBJECT ( pElement ) ) return static_cast < CObject* > ( pElement ); else return NULL; }
GtkWidget *mt_get_ancestor(GtkWidget *widget, char *name) { while (widget) { if (IS_OBJECT(widget, name)) return widget; widget = widget->parent; } return NULL; }
// // Get_System: C // // Return a second level object field of the system object. // REBVAL *Get_System(REBCNT i1, REBCNT i2) { REBVAL *obj; obj = CTX_VAR(VAL_CONTEXT(ROOT_SYSTEM), i1); if (i2 == 0) return obj; assert(IS_OBJECT(obj)); return Get_Field(VAL_CONTEXT(obj), i2); }
int skip_array (jsmntok_t *tok, int size) { int i; for (i = 0; i < size; i++, tok++) { if (IS_ARRAY(*tok)) { return (i + skip_array (tok + 1, tok->size)); } if (IS_OBJECT(*tok)) { return -1; } } return i; }
*/ REBVAL *Get_System(REBCNT i1, REBCNT i2) /* ** Return a second level object field of the system object. ** ***********************************************************************/ { REBVAL *obj; obj = VAL_OBJ_VALUES(ROOT_SYSTEM) + i1; if (!i2) return obj; ASSERT1(IS_OBJECT(obj), RP_BAD_OBJ_INDEX); return Get_Field(VAL_OBJ_FRAME(obj), i2); }
*/ void Trap_Port(REBCNT errnum, REBSER *port, REBINT err_code) /* ***********************************************************************/ { REBVAL *spec = OFV(port, STD_PORT_SPEC); REBVAL *val; if (!IS_OBJECT(spec)) Trap0(RE_INVALID_PORT); val = Get_Object(spec, STD_PORT_SPEC_HEAD_REF); // most informative if (IS_NONE(val)) val = Get_Object(spec, STD_PORT_SPEC_HEAD_TITLE); DS_PUSH_INTEGER(err_code); Trap2(errnum, val, DS_TOP); }
*/ void Validate_Port(REBSER *port, REBCNT action) /* ** Because port actors are exposed to the user level, we must ** prevent them from being called with invalid values. ** ***********************************************************************/ { if ( action >= A_MAX_ACTION || port->tail > 50 || SERIES_WIDE(port) != sizeof(REBVAL) || !IS_FRAME(BLK_HEAD(port)) || !IS_OBJECT(BLK_SKIP(port, STD_PORT_SPEC)) ) { raise Error_0(RE_INVALID_PORT); } }
object_t get_local(context_t context, int uplevel, int offset) { object_t cur = context->env; while (uplevel > 0) { if (cur->environment.parent == OBJECT_NULL) return NULL; else cur = cur->environment.parent; -- uplevel; } if (offset >= cur->environment.length) return NULL; object_t result = SLOT_GET(cur->environment.slot_entry[offset]); if (IS_OBJECT(result)) context_attach(context, result); return result; }
void CObjectSync::Packet_ObjectSync ( CObjectSyncPacket& Packet ) { // Grab the player CPlayer* pPlayer = Packet.GetSourcePlayer (); if ( pPlayer && pPlayer->IsJoined () ) { // Apply the data for each object in the packet vector < CObjectSyncPacket::SyncData* > ::const_iterator iter = Packet.IterBegin (); for ( ; iter != Packet.IterEnd (); iter++ ) { CObjectSyncPacket::SyncData* pData = *iter; // Grab the element CElement* pElement = CElementIDs::GetElement ( pData->ID ); if ( pElement && IS_OBJECT ( pElement ) ) { CObject* pObject = static_cast < CObject* > ( pElement ); // Is the player syncing this object? if ( ( pObject->GetSyncer () == pPlayer ) && pObject->CanUpdateSync ( pData->ucSyncTimeContext ) ) { // Apply the data to the object if ( pData->ucFlags & 0x1 ) { pObject->SetPosition ( pData->vecPosition ); g_pGame->GetColManager()->DoHitDetection ( pObject->GetLastPosition (), pObject->GetPosition (), 0.0f, pObject ); } if ( pData->ucFlags & 0x2 ) pObject->SetRotation ( pData->vecRotation ); if ( pData->ucFlags & 0x4 ) pObject->SetHealth ( pData->fHealth ); // Send this sync pData->bSend = true; } } } // Tell everyone m_pPlayerManager->BroadcastOnlyJoined ( Packet, pPlayer ); } }
*/ void Make_Command(REBVAL *value, REBVAL *def) /* ** Assumes prior function has already stored the spec and args ** series. This function validates the body. ** ***********************************************************************/ { REBVAL *args = BLK_HEAD(VAL_FUNC_ARGS(value)); REBCNT n; REBVAL *val = VAL_BLK_SKIP(def, 1); REBEXT *ext; if ( VAL_LEN(def) != 3 || !(IS_MODULE(val) || IS_OBJECT(val)) || !IS_HANDLE(VAL_OBJ_VALUE(val, 1)) || !IS_INTEGER(val+1) || VAL_INT64(val+1) > 0xffff ) Trap1(RE_BAD_FUNC_DEF, def); val = VAL_OBJ_VALUE(val, 1); if ( !(ext = &Ext_List[VAL_I32(val)]) || !(ext->call) ) Trap1(RE_BAD_EXTENSION, def); // make command! [[arg-spec] handle cmd-index] VAL_FUNC_BODY(value) = Copy_Block_Len(VAL_SERIES(def), 1, 2); // Check for valid command arg datatypes: args++; // skip self n = 1; for (; NOT_END(args); args++, n++) { // If the typeset contains args that are not valid: // (3 is the default when no args given, for not END and UNSET) if (3 != ~VAL_TYPESET(args) && (VAL_TYPESET(args) & ~RXT_ALLOWED_TYPES)) Trap1(RE_BAD_FUNC_ARG, args); } VAL_SET(value, REB_COMMAND); }
*/ REBVAL *In_Object(REBSER *base, ...) /* ** Get value from nested list of objects. List is null terminated. ** Returns object value, else returns 0 if not found. ** ***********************************************************************/ { REBVAL *obj = 0; REBCNT n; va_list args; va_start(args, base); while (NZ(n = va_arg(args, REBCNT))) { if (n >= SERIES_TAIL(base)) return 0; obj = OFV(base, n); if (!IS_OBJECT(obj)) return 0; base = VAL_OBJ_FRAME(obj); } va_end(args); return obj; }
static int traverse_undefined_functions(void *arg, symfunc_type fn) { int i; for (i = 0; i < number_of_symbols; i++) { /* Check if it is undefined and not an object. I have found that symbol * typing can be misleading: Imported functions are not marked as * BSF_FUNCTION; weakly defined objects are listed as undefined objects. * Conclusion: We will error if a object is truly undefined! */ if ((symbol_table[i]->value == 0) && (!IS_DEFINED(symbol_table[i])) && (!IS_OBJECT(symbol_table[i]))) { /* Is is imported as a "weak" symbol? If so, we will process the * symbol only if we were requested to do so from the command line. */ if ((!IS_WEAK(symbol_table[i])) || (weak_imports > 0)) { /* Yes, process the symbol */ if (fn(symbol_table[i], arg) != 0) { /* If the function returns a non-zero value, then we * terminate the traversal and return a non-zero value also. */ return 1; } } } } /* Return 0 meaning that all undefined symbols were examined successfully. */ return 0; }
*/ static REBFLG Set_GOB_Var(REBGOB *gob, REBVAL *word, REBVAL *val) /* ***********************************************************************/ { REBVAL *spec; REBVAL *hndl; switch (VAL_WORD_CANON(word)) { case SYM_OFFSET: return Set_Pair(&(gob->offset), val); case SYM_SIZE: return Set_Pair(&gob->size, val); case SYM_IMAGE: CLR_GOB_OPAQUE(gob); if (IS_IMAGE(val)) { SET_GOB_TYPE(gob, GOBT_IMAGE); GOB_W(gob) = (REBD32)VAL_IMAGE_WIDE(val); GOB_H(gob) = (REBD32)VAL_IMAGE_HIGH(val); GOB_CONTENT(gob) = VAL_SERIES(val); // if (!VAL_IMAGE_TRANSP(val)) SET_GOB_OPAQUE(gob); } else if (IS_NONE(val)) SET_GOB_TYPE(gob, GOBT_NONE); else return FALSE; break; #ifdef HAS_WIDGET_GOB case SYM_WIDGET: //printf("WIDGET GOB\n"); SET_GOB_TYPE(gob, GOBT_WIDGET); SET_GOB_OPAQUE(gob); GOB_CONTENT(gob) = Make_Block(4); // [handle type spec data] hndl = Append_Value(GOB_CONTENT(gob)); Append_Value(GOB_CONTENT(gob)); // used to cache type on host's side spec = Append_Value(GOB_CONTENT(gob)); Append_Value(GOB_CONTENT(gob)); // used to cache result data SET_HANDLE(hndl, 0, SYM_WIDGET, 0); if (IS_WORD(val) || IS_LIT_WORD(val)) { Set_Block(spec, Make_Block(1)); Append_Val(VAL_SERIES(spec), val); } else if (IS_BLOCK(val)) { Set_Block(spec, VAL_SERIES(val)); } else return FALSE; break; #endif // HAS_WIDGET_GOB case SYM_DRAW: CLR_GOB_OPAQUE(gob); if (IS_BLOCK(val)) { SET_GOB_TYPE(gob, GOBT_DRAW); GOB_CONTENT(gob) = VAL_SERIES(val); } else if (IS_NONE(val)) SET_GOB_TYPE(gob, GOBT_NONE); else return FALSE; break; case SYM_TEXT: CLR_GOB_OPAQUE(gob); if (IS_BLOCK(val)) { SET_GOB_TYPE(gob, GOBT_TEXT); GOB_CONTENT(gob) = VAL_SERIES(val); } else if (IS_STRING(val)) { SET_GOB_TYPE(gob, GOBT_STRING); GOB_CONTENT(gob) = VAL_SERIES(val); } else if (IS_NONE(val)) SET_GOB_TYPE(gob, GOBT_NONE); else return FALSE; break; case SYM_EFFECT: CLR_GOB_OPAQUE(gob); if (IS_BLOCK(val)) { SET_GOB_TYPE(gob, GOBT_EFFECT); GOB_CONTENT(gob) = VAL_SERIES(val); } else if (IS_NONE(val)) SET_GOB_TYPE(gob, GOBT_NONE); else return FALSE; break; case SYM_COLOR: CLR_GOB_OPAQUE(gob); if (IS_TUPLE(val)) { SET_GOB_TYPE(gob, GOBT_COLOR); Set_Pixel_Tuple((REBYTE*)&GOB_CONTENT(gob), val); if (VAL_TUPLE_LEN(val) < 4 || VAL_TUPLE(val)[3] == 255) SET_GOB_OPAQUE(gob); } else if (IS_NONE(val)) SET_GOB_TYPE(gob, GOBT_NONE); break; case SYM_PANE: if (GOB_PANE(gob)) Clear_Series(GOB_PANE(gob)); if (IS_BLOCK(val)) Insert_Gobs(gob, VAL_BLK_DATA(val), 0, VAL_BLK_LEN(val), 0); else if (IS_GOB(val)) Insert_Gobs(gob, val, 0, 1, 0); else if (IS_NONE(val)) gob->pane = 0; else return FALSE; break; case SYM_ALPHA: GOB_ALPHA(gob) = Clip_Int(Int32(val), 0, 255); break; case SYM_DATA: #ifdef HAS_WIDGET_GOB if (GOB_TYPE(gob) == GOBT_WIDGET) { OS_SET_WIDGET_DATA(gob, val); } else { #endif SET_GOB_DTYPE(gob, GOBD_NONE); if (IS_OBJECT(val)) { SET_GOB_DTYPE(gob, GOBD_OBJECT); SET_GOB_DATA(gob, VAL_OBJ_FRAME(val)); } else if (IS_BLOCK(val)) { SET_GOB_DTYPE(gob, GOBD_BLOCK); SET_GOB_DATA(gob, VAL_SERIES(val)); } else if (IS_STRING(val)) { SET_GOB_DTYPE(gob, GOBD_STRING); SET_GOB_DATA(gob, VAL_SERIES(val)); } else if (IS_BINARY(val)) { SET_GOB_DTYPE(gob, GOBD_BINARY); SET_GOB_DATA(gob, VAL_SERIES(val)); } else if (IS_INTEGER(val)) { SET_GOB_DTYPE(gob, GOBD_INTEGER); SET_GOB_DATA(gob, (void*)(REBIPT)VAL_INT64(val)); } else if (IS_NONE(val)) SET_GOB_TYPE(gob, GOBT_NONE); else return FALSE; #ifdef HAS_WIDGET_GOB } #endif break; case SYM_FLAGS: if (IS_WORD(val)) Set_Gob_Flag(gob, val); else if (IS_BLOCK(val)) { gob->flags = 0; for (val = VAL_BLK(val); NOT_END(val); val++) { if (IS_WORD(val)) Set_Gob_Flag(gob, val); } } break; case SYM_OWNER: if (IS_GOB(val)) GOB_TMP_OWNER(gob) = VAL_GOB(val); else return FALSE; break; default: return FALSE; } return TRUE; }
*/ static int Event_Actor(REBVAL *ds, REBSER *port, REBCNT action) /* ***********************************************************************/ { REBVAL *spec; REBVAL *state; REBCNT result; REBVAL *arg; REBVAL save_port; Validate_Port(port, action); arg = D_ARG(2); *D_RET = *D_ARG(1); // Validate and fetch relevant PORT fields: state = BLK_SKIP(port, STD_PORT_STATE); spec = BLK_SKIP(port, STD_PORT_SPEC); if (!IS_OBJECT(spec)) Trap1(RE_INVALID_SPEC, spec); // Get or setup internal state data: if (!IS_BLOCK(state)) Set_Block(state, Make_Block(127)); switch (action) { case A_UPDATE: return R_NONE; // Normal block actions done on events: case A_POKE: if (!IS_EVENT(D_ARG(3))) Trap_Arg(D_ARG(3)); goto act_blk; case A_INSERT: case A_APPEND: //case A_PATH: // not allowed: port/foo is port object field access //case A_PATH_SET: // not allowed: above if (!IS_EVENT(arg)) Trap_Arg(arg); case A_PICK: act_blk: save_port = *D_ARG(1); // save for return *D_ARG(1) = *state; result = T_Block(ds, action); SET_FLAG(Eval_Signals, SIG_EVENT_PORT); if (action == A_INSERT || action == A_APPEND || action == A_REMOVE) { *D_RET = save_port; break; } return result; // return condition case A_CLEAR: VAL_TAIL(state) = 0; VAL_BLK_TERM(state); CLR_FLAG(Eval_Signals, SIG_EVENT_PORT); break; case A_LENGTHQ: SET_INTEGER(D_RET, VAL_TAIL(state)); break; case A_OPEN: if (!req) { //!!! req = OS_MAKE_DEVREQ(RDI_EVENT); SET_OPEN(req); OS_DO_DEVICE(req, RDC_CONNECT); // stays queued } break; default: Trap_Action(REB_PORT, action); } return R_RET; }
*/ static REBFLG Set_GOB_Var(REBGOB *gob, REBVAL *word, REBVAL *val) /* ***********************************************************************/ { switch (VAL_WORD_CANON(word)) { case SYM_OFFSET: return Set_Pair(&(gob->offset), val); case SYM_SIZE: return Set_Pair(&gob->size, val); case SYM_IMAGE: CLR_GOB_OPAQUE(gob); if (IS_IMAGE(val)) { SET_GOB_TYPE(gob, GOBT_IMAGE); GOB_W(gob) = (REBD32)VAL_IMAGE_WIDE(val); GOB_H(gob) = (REBD32)VAL_IMAGE_HIGH(val); GOB_CONTENT(gob) = VAL_SERIES(val); // if (!VAL_IMAGE_TRANSP(val)) SET_GOB_OPAQUE(gob); } else if (IS_NONE(val)) SET_GOB_TYPE(gob, GOBT_NONE); else return FALSE; break; case SYM_DRAW: CLR_GOB_OPAQUE(gob); if (IS_BLOCK(val)) { SET_GOB_TYPE(gob, GOBT_DRAW); GOB_CONTENT(gob) = VAL_SERIES(val); } else if (IS_NONE(val)) SET_GOB_TYPE(gob, GOBT_NONE); else return FALSE; break; case SYM_TEXT: CLR_GOB_OPAQUE(gob); if (IS_BLOCK(val)) { SET_GOB_TYPE(gob, GOBT_TEXT); GOB_CONTENT(gob) = VAL_SERIES(val); } else if (IS_STRING(val)) { SET_GOB_TYPE(gob, GOBT_STRING); GOB_CONTENT(gob) = VAL_SERIES(val); } else if (IS_NONE(val)) SET_GOB_TYPE(gob, GOBT_NONE); else return FALSE; break; case SYM_EFFECT: CLR_GOB_OPAQUE(gob); if (IS_BLOCK(val)) { SET_GOB_TYPE(gob, GOBT_EFFECT); GOB_CONTENT(gob) = VAL_SERIES(val); } else if (IS_NONE(val)) SET_GOB_TYPE(gob, GOBT_NONE); else return FALSE; break; case SYM_COLOR: CLR_GOB_OPAQUE(gob); if (IS_TUPLE(val)) { SET_GOB_TYPE(gob, GOBT_COLOR); Set_Pixel_Tuple((REBYTE*)&GOB_CONTENT(gob), val); if (VAL_TUPLE_LEN(val) < 4 || VAL_TUPLE(val)[3] == 0) SET_GOB_OPAQUE(gob); } else if (IS_NONE(val)) SET_GOB_TYPE(gob, GOBT_NONE); break; case SYM_PANE: if (GOB_PANE(gob)) Clear_Series(GOB_PANE(gob)); if (IS_BLOCK(val)) Insert_Gobs(gob, VAL_BLK_DATA(val), 0, VAL_BLK_LEN(val), 0); else if (IS_GOB(val)) Insert_Gobs(gob, val, 0, 1, 0); else if (IS_NONE(val)) gob->pane = 0; else return FALSE; break; case SYM_ALPHA: GOB_ALPHA(gob) = Clip_Int(Int32(val), 0, 255); break; case SYM_DATA: SET_GOB_DTYPE(gob, GOBD_NONE); if (IS_OBJECT(val)) { SET_GOB_DTYPE(gob, GOBD_OBJECT); SET_GOB_DATA(gob, VAL_OBJ_FRAME(val)); } else if (IS_BLOCK(val)) { SET_GOB_DTYPE(gob, GOBD_BLOCK); SET_GOB_DATA(gob, VAL_SERIES(val)); } else if (IS_STRING(val)) { SET_GOB_DTYPE(gob, GOBD_STRING); SET_GOB_DATA(gob, VAL_SERIES(val)); } else if (IS_BINARY(val)) { SET_GOB_DTYPE(gob, GOBD_BINARY); SET_GOB_DATA(gob, VAL_SERIES(val)); } else if (IS_INTEGER(val)) { SET_GOB_DTYPE(gob, GOBD_INTEGER); SET_GOB_DATA(gob, (void*)(REBIPT)VAL_INT64(val)); } else if (IS_NONE(val)) SET_GOB_TYPE(gob, GOBT_NONE); else return FALSE; break; case SYM_FLAGS: if (IS_WORD(val)) Set_Gob_Flag(gob, val); else if (IS_BLOCK(val)) { gob->flags = 0; for (val = VAL_BLK(val); NOT_END(val); val++) { if (IS_WORD(val)) Set_Gob_Flag(gob, val); } } break; case SYM_OWNER: if (IS_GOB(val)) GOB_TMP_OWNER(gob) = VAL_GOB(val); else return FALSE; break; default: return FALSE; } return TRUE; }
*/ REBINT Text_Gob(void *richtext, REBSER *block) /* ** Handles all commands for the TEXT dialect as specified ** in the system/dialects/text object. ** ** This function calls the REBOL_Dialect interpreter to ** parse the dialect and build and return the command number ** (the index offset in the text object above) and a block ** of arguments. (For now, just a REBOL block, but this could ** be changed to isolate it from changes in REBOL's internals). ** ** Each arg will be of the specified datatype (given in the ** dialect) or NONE when no argument of that type was given ** and this code must determine the proper default value. ** ** If the cmd result is zero, then it is either the end of ** the block, or an error has occurred. If the error value ** is non-zero, then it was an error. ** ***********************************************************************/ { REBCNT index = 0; REBINT cmd; REBSER *args = 0; REBVAL *arg; REBCNT nargs; //font object conversion related values REBFNT* font; REBVAL* val; REBPAR offset; REBPAR space; //para object conversion related values REBPRA* para; REBPAR origin; REBPAR margin; REBPAR indent; REBPAR scroll; do { cmd = Reb_Dialect(DIALECTS_TEXT, block, &index, &args); if (cmd == 0) return 0; if (cmd < 0) { // Reb_Print("ERROR: %d, Index %d", -cmd, index); return -((REBINT)index+1); } // else // Reb_Print("TEXT: Cmd %d, Index %d, Args %m", cmd, index, args); arg = BLK_HEAD(args); nargs = SERIES_TAIL(args); // Reb_Print("Number of args: %d", nargs); switch (cmd) { case TW_TYPE_SPEC: if (IS_STRING(arg)) { rt_text(richtext, ARG_STRING(0), index); } else if (IS_TUPLE(arg)) { rt_color(richtext, ARG_TUPLE(0)); } break; case TW_ANTI_ALIAS: rt_anti_alias(richtext, ARG_OPT_LOGIC(0)); break; case TW_SCROLL: rt_scroll(richtext, ARG_PAIR(0)); break; case TW_BOLD: case TW_B: rt_bold(richtext, ARG_OPT_LOGIC(0)); break; case TW_ITALIC: case TW_I: rt_italic(richtext, ARG_OPT_LOGIC(0)); break; case TW_UNDERLINE: case TW_U: rt_underline(richtext, ARG_OPT_LOGIC(0)); break; case TW_CENTER: rt_center(richtext); break; case TW_LEFT: rt_left(richtext); break; case TW_RIGHT: rt_right(richtext); break; case TW_FONT: if (!IS_OBJECT(arg)) break; font = (REBFNT*)rt_get_font(richtext); val = BLK_HEAD(ARG_OBJECT(0))+1; if (IS_STRING(val)) { font->name = VAL_STRING(val); } // Reb_Print("font/name: %s", font->name); val++; if (IS_BLOCK(val)) { REBSER* styles = VAL_SERIES(val); REBVAL* slot = BLK_HEAD(styles); REBCNT len = SERIES_TAIL(styles) ,i; for (i = 0;i<len;i++){ if (IS_WORD(slot+i)){ set_font_styles(font, slot+i); } } } else if (IS_WORD(val)) { set_font_styles(font, val); } val++; if (IS_INTEGER(val)) { font->size = VAL_INT32(val); } // Reb_Print("font/size: %d", font->size); val++; if ((IS_TUPLE(val)) || (IS_NONE(val))) { COPY_MEM(font->color,VAL_TUPLE(val), 4); } // Reb_Print("font/color: %d.%d.%d.%d", font->color[0],font->color[1],font->color[2],font->color[3]); val++; if ((IS_PAIR(val)) || (IS_NONE(val))) { offset = VAL_PAIR(val); font->offset_x = offset.x; font->offset_y = offset.y; } // Reb_Print("font/offset: %dx%d", offset.x,offset.y); val++; if ((IS_PAIR(val)) || (IS_NONE(val))) { space = VAL_PAIR(val); font->space_x = space.x; font->space_y = space.y; } // Reb_Print("font/space: %dx%d", space.x, space.y); val++; font->shadow_x = 0; font->shadow_y = 0; if (IS_BLOCK(val)) { REBSER* ser = VAL_SERIES(val); REBVAL* slot = BLK_HEAD(ser); REBCNT len = SERIES_TAIL(ser) ,i; for (i = 0;i<len;i++){ if (IS_PAIR(slot)) { REBPAR shadow = VAL_PAIR(slot); font->shadow_x = shadow.x; font->shadow_y = shadow.y; } else if (IS_TUPLE(slot)) { COPY_MEM(font->shadow_color,VAL_TUPLE(slot), 4); } else if (IS_INTEGER(slot)) { font->shadow_blur = VAL_INT32(slot); } slot++; } } else if (IS_PAIR(val)) { REBPAR shadow = VAL_PAIR(val); font->shadow_x = shadow.x; font->shadow_y = shadow.y; } rt_font(richtext, font); break; case TW_PARA: if (!IS_OBJECT(arg)) break; para = (REBPRA*)rt_get_para(richtext); val = BLK_HEAD(ARG_OBJECT(0))+1; if (IS_PAIR(val)) { origin = VAL_PAIR(val); para->origin_x = origin.x; para->origin_y = origin.y; } // Reb_Print("para/origin: %dx%d", origin.x, origin.y); val++; if (IS_PAIR(val)) { margin = VAL_PAIR(val); para->margin_x = margin.x; para->margin_y = margin.y; } // Reb_Print("para/margin: %dx%d", margin.x, margin.y); val++; if (IS_PAIR(val)) { indent = VAL_PAIR(val); para->indent_x = indent.x; para->indent_y = indent.y; } // Reb_Print("para/indent: %dx%d", indent.x, indent.y); val++; if (IS_INTEGER(val)) { para->tabs = VAL_INT32(val); } // Reb_Print("para/tabs: %d", para->tabs); val++; if (IS_LOGIC(val)) { para->wrap = VAL_LOGIC(val); } // Reb_Print("para/wrap?: %d", para->wrap); val++; if (IS_PAIR(val)) { scroll = VAL_PAIR(val); para->scroll_x = scroll.x; para->scroll_y = scroll.y; } // Reb_Print("para/scroll: %dx%d", scroll.x, scroll.y); val++; if (IS_WORD(val)) { REBINT result = Reb_Find_Word(VAL_WORD_SYM(val), Symbol_Ids, 0); switch (result){ case SW_RIGHT: case SW_LEFT: case SW_CENTER: para->align = result; break; default: para->align = SW_LEFT; break; } } val++; if (IS_WORD(val)) { REBINT result = Reb_Find_Word(VAL_WORD_SYM(val), Symbol_Ids, 0); switch (result){ case SW_TOP: case SW_BOTTOM: case SW_MIDDLE: para->valign = result; break; default: para->valign = SW_TOP; break; } } rt_para(richtext, para); break; case TW_SIZE: rt_font_size(richtext, ARG_INTEGER(0)); break; case TW_SHADOW: rt_shadow(richtext, &ARG_PAIR(0), ARG_TUPLE(1), ARG_INTEGER(2)); break; case TW_DROP: rt_drop(richtext, ARG_OPT_INTEGER(0)); break; case TW_NEWLINE: case TW_NL: rt_newline(richtext, index); break; case TW_CARET: { REBPAR caret = {0,0}; REBPAR highlightStart = {0,0}; REBPAR highlightEnd = {0,0}; REBVAL *slot; if (!IS_OBJECT(arg)) break; val = BLK_HEAD(ARG_OBJECT(0))+1; if (IS_BLOCK(val)) { slot = BLK_HEAD(VAL_SERIES(val)); if (SERIES_TAIL(VAL_SERIES(val)) == 2 && IS_BLOCK(slot) && IS_STRING(slot+1)){ caret.x = 1 + slot->data.series.index; caret.y = 1 + (slot+1)->data.series.index;; //Reb_Print("caret %d, %d", caret.x, caret.y); } } val++; if (IS_BLOCK(val)) { slot = BLK_HEAD(VAL_SERIES(val)); if (SERIES_TAIL(VAL_SERIES(val)) == 2 && IS_BLOCK(slot) && IS_STRING(slot+1)){ highlightStart.x = 1 + slot->data.series.index; highlightStart.y = 1 + (slot+1)->data.series.index;; //Reb_Print("highlight-start %d, %d", highlightStart.x, highlightStart.y); } } val++; if (IS_BLOCK(val)) { slot = BLK_HEAD(VAL_SERIES(val)); if (SERIES_TAIL(VAL_SERIES(val)) == 2 && IS_BLOCK(slot) && IS_STRING(slot+1)){ highlightEnd.x = 1 + slot->data.series.index; highlightEnd.y = 1 + (slot+1)->data.series.index;; //Reb_Print("highlight-End %d, %d", highlightEnd.x, highlightEnd.y); } } rt_caret(richtext, &caret, &highlightStart,&highlightEnd); } break; } } while (TRUE); }
*/ int Do_Port_Action(struct Reb_Call *call_, REBSER *port, REBCNT action) /* ** Call a PORT actor (action) value. Search PORT actor ** first. If not found, search the PORT scheme actor. ** ** NOTE: stack must already be setup correctly for action, and ** the caller must cleanup the stack. ** ***********************************************************************/ { REBVAL *actor; REBCNT n = 0; assert(action < A_MAX_ACTION); // Verify valid port (all of these must be false): if ( // Must be = or larger than std port: (SERIES_TAIL(port) < STD_PORT_MAX) || // Must be an object series: !IS_FRAME(BLK_HEAD(port)) || // Must have a spec object: !IS_OBJECT(BLK_SKIP(port, STD_PORT_SPEC)) ) { raise Error_0(RE_INVALID_PORT); } // Get actor for port, if it has one: actor = BLK_SKIP(port, STD_PORT_ACTOR); if (IS_NONE(actor)) return R_NONE; // If actor is a native function: if (IS_NATIVE(actor)) return cast(REBPAF, VAL_FUNC_CODE(actor))(call_, port, action); // actor must be an object: if (!IS_OBJECT(actor)) raise Error_0(RE_INVALID_ACTOR); // Dispatch object function: n = Find_Action(actor, action); actor = Obj_Value(actor, n); if (!n || !actor || !ANY_FUNC(actor)) raise Error_1(RE_NO_PORT_ACTION, Get_Action_Word(action)); if (Redo_Func_Throws(actor)) { // No special handling needed, as we are just going to return // the output value in D_OUT anyway. } return R_OUT; // If not in PORT actor, use the SCHEME actor: #ifdef no_longer_used if (n == 0) { actor = Obj_Value(scheme, STD_SCHEME_actor); if (!actor) goto err; if (IS_NATIVE(actor)) goto fun; if (!IS_OBJECT(actor)) goto err; //vTrap_Expect(value, STD_PORT_actor, REB_OBJECT); n = Find_Action(actor, action); if (n == 0) goto err; } #endif }
*/ static int Dir_Actor(REBVAL *ds, REBSER *port, REBCNT action) /* ** Internal port handler for file directories. ** ***********************************************************************/ { REBVAL *spec; REBVAL *path; REBVAL *state; REBREQ dir; REBCNT args = 0; REBINT result; REBCNT len; //REBYTE *flags; Validate_Port(port, action); *D_RET = *D_ARG(1); CLEARS(&dir); // Validate and fetch relevant PORT fields: spec = BLK_SKIP(port, STD_PORT_SPEC); if (!IS_OBJECT(spec)) Trap1(RE_INVALID_SPEC, spec); path = Obj_Value(spec, STD_PORT_SPEC_HEAD_REF); if (!path) Trap1(RE_INVALID_SPEC, spec); if (IS_URL(path)) path = Obj_Value(spec, STD_PORT_SPEC_HEAD_PATH); else if (!IS_FILE(path)) Trap1(RE_INVALID_SPEC, path); state = BLK_SKIP(port, STD_PORT_STATE); // if block, then port is open. //flags = Security_Policy(SYM_FILE, path); // Get or setup internal state data: dir.port = port; dir.device = RDI_FILE; switch (action) { case A_READ: //Trap_Security(flags[POL_READ], POL_READ, path); args = Find_Refines(ds, ALL_READ_REFS); if (!IS_BLOCK(state)) { // !!! ignores /SKIP and /PART, for now Init_Dir_Path(&dir, path, 1, POL_READ); Set_Block(state, Make_Block(7)); // initial guess result = Read_Dir(&dir, VAL_SERIES(state)); ///OS_FREE(dir.file.path); if (result < 0) Trap_Port(RE_CANNOT_OPEN, port, dir.error); *D_RET = *state; SET_NONE(state); } else { len = VAL_BLK_LEN(state); // !!? Why does this need to copy the block?? Set_Block(D_RET, Copy_Block_Values(VAL_SERIES(state), 0, len, TS_STRING)); } break; case A_CREATE: //Trap_Security(flags[POL_WRITE], POL_WRITE, path); if (IS_BLOCK(state)) Trap1(RE_ALREADY_OPEN, path); // already open create: Init_Dir_Path(&dir, path, 0, POL_WRITE | REMOVE_TAIL_SLASH); // Sets RFM_DIR too result = OS_DO_DEVICE(&dir, RDC_CREATE); ///OS_FREE(dir.file.path); if (result < 0) Trap1(RE_NO_CREATE, path); if (action == A_CREATE) return R_ARG2; SET_NONE(state); break; case A_RENAME: if (IS_BLOCK(state)) Trap1(RE_ALREADY_OPEN, path); // already open else { REBSER *target; Init_Dir_Path(&dir, path, 0, POL_WRITE | REMOVE_TAIL_SLASH); // Sets RFM_DIR too // Convert file name to OS format: if (!(target = Value_To_OS_Path(D_ARG(2)))) Trap1(RE_BAD_FILE_PATH, D_ARG(2)); dir.data = BIN_DATA(target); OS_DO_DEVICE(&dir, RDC_RENAME); Free_Series(target); if (dir.error) Trap1(RE_NO_RENAME, path); } break; case A_DELETE: //Trap_Security(flags[POL_WRITE], POL_WRITE, path); SET_NONE(state); Init_Dir_Path(&dir, path, 0, POL_WRITE); // !!! add *.r deletion // !!! add recursive delete (?) result = OS_DO_DEVICE(&dir, RDC_DELETE); ///OS_FREE(dir.file.path); if (result < 0) Trap1(RE_NO_DELETE, path); return R_ARG2; case A_OPEN: // !! If open fails, what if user does a READ w/o checking for error? if (IS_BLOCK(state)) Trap1(RE_ALREADY_OPEN, path); // already open //Trap_Security(flags[POL_READ], POL_READ, path); args = Find_Refines(ds, ALL_OPEN_REFS); if (args & AM_OPEN_NEW) goto create; //if (args & ~AM_OPEN_READ) Trap1(RE_INVALID_SPEC, path); Set_Block(state, Make_Block(7)); Init_Dir_Path(&dir, path, 1, POL_READ); result = Read_Dir(&dir, VAL_SERIES(state)); ///OS_FREE(dir.file.path); if (result < 0) Trap_Port(RE_CANNOT_OPEN, port, dir.error); break; case A_OPENQ: if (IS_BLOCK(state)) return R_TRUE; return R_FALSE; case A_CLOSE: SET_NONE(state); break; case A_QUERY: //Trap_Security(flags[POL_READ], POL_READ, path); SET_NONE(state); Init_Dir_Path(&dir, path, -1, REMOVE_TAIL_SLASH | POL_READ); if (OS_DO_DEVICE(&dir, RDC_QUERY) < 0) return R_NONE; Ret_Query_File(port, &dir, D_RET); ///OS_FREE(dir.file.path); break; //-- Port Series Actions (only called if opened as a port) case A_LENGTHQ: len = IS_BLOCK(state) ? VAL_BLK_LEN(state) : 0; SET_INTEGER(D_RET, len); break; default: Trap_Action(REB_PORT, action); } return R_RET; }
*/ static REB_R Event_Actor(struct Reb_Call *call_, REBSER *port, REBCNT action) /* ** Internal port handler for events. ** ***********************************************************************/ { REBVAL *spec; REBVAL *state; REB_R result; REBVAL *arg; REBVAL save_port; Validate_Port(port, action); arg = D_ARG(2); *D_OUT = *D_ARG(1); // Validate and fetch relevant PORT fields: state = BLK_SKIP(port, STD_PORT_STATE); spec = BLK_SKIP(port, STD_PORT_SPEC); if (!IS_OBJECT(spec)) Trap1_DEAD_END(RE_INVALID_SPEC, spec); // Get or setup internal state data: if (!IS_BLOCK(state)) Set_Block(state, Make_Block(EVENTS_CHUNK - 1)); switch (action) { case A_UPDATE: return R_NONE; // Normal block actions done on events: case A_POKE: if (!IS_EVENT(D_ARG(3))) Trap_Arg_DEAD_END(D_ARG(3)); goto act_blk; case A_INSERT: case A_APPEND: //case A_PATH: // not allowed: port/foo is port object field access //case A_PATH_SET: // not allowed: above if (!IS_EVENT(arg)) Trap_Arg_DEAD_END(arg); case A_PICK: act_blk: save_port = *D_ARG(1); // save for return *D_ARG(1) = *state; result = T_Block(call_, action); SET_SIGNAL(SIG_EVENT_PORT); if (action == A_INSERT || action == A_APPEND || action == A_REMOVE) { *D_OUT = save_port; break; } return result; // return condition case A_CLEAR: VAL_TAIL(state) = 0; VAL_BLK_TERM(state); CLR_SIGNAL(SIG_EVENT_PORT); break; case A_LENGTHQ: SET_INTEGER(D_OUT, VAL_TAIL(state)); break; case A_OPEN: if (!req) { //!!! req = OS_MAKE_DEVREQ(RDI_EVENT); if (req) { SET_OPEN(req); OS_DO_DEVICE(req, RDC_CONNECT); // stays queued } } break; case A_CLOSE: OS_ABORT_DEVICE(req); OS_DO_DEVICE(req, RDC_CLOSE); // free req!!! SET_CLOSED(req); req = 0; break; case A_FIND: // add it default: Trap_Action_DEAD_END(REB_PORT, action); } return R_OUT; }
// // Transport_Actor: C // static REB_R Transport_Actor(struct Reb_Call *call_, REBSER *port, REBCNT action, enum Transport_Types proto) { REBREQ *sock; // IO request REBVAL *spec; // port spec REBVAL *arg; // action argument value REBVAL *val; // e.g. port number value REBINT result; // IO result REBCNT refs; // refinement argument flags REBCNT len; // generic length REBSER *ser; // simplifier Validate_Port(port, action); *D_OUT = *D_ARG(1); arg = DS_ARGC > 1 ? D_ARG(2) : NULL; sock = cast(REBREQ*, Use_Port_State(port, RDI_NET, sizeof(*sock))); if (proto == TRANSPORT_UDP) { SET_FLAG(sock->modes, RST_UDP); } //Debug_Fmt("Sock: %x", sock); spec = OFV(port, STD_PORT_SPEC); if (!IS_OBJECT(spec)) fail (Error(RE_INVALID_PORT)); // sock->timeout = 4000; // where does this go? !!! // HOW TO PREVENT OVERWRITE DURING BUSY OPERATION!!! // Should it just ignore it or cause an error? // Actions for an unopened socket: if (!IS_OPEN(sock)) { switch (action) { // Ordered by frequency case A_OPEN: arg = Obj_Value(spec, STD_PORT_SPEC_NET_HOST); val = Obj_Value(spec, STD_PORT_SPEC_NET_PORT_ID); if (OS_DO_DEVICE(sock, RDC_OPEN)) fail (Error_On_Port(RE_CANNOT_OPEN, port, -12)); SET_OPEN(sock); // Lookup host name (an extra TCP device step): if (IS_STRING(arg)) { sock->common.data = VAL_BIN(arg); sock->special.net.remote_port = IS_INTEGER(val) ? VAL_INT32(val) : 80; result = OS_DO_DEVICE(sock, RDC_LOOKUP); // sets remote_ip field if (result < 0) fail (Error_On_Port(RE_NO_CONNECT, port, sock->error)); return R_OUT; } // Host IP specified: else if (IS_TUPLE(arg)) { sock->special.net.remote_port = IS_INTEGER(val) ? VAL_INT32(val) : 80; memcpy(&sock->special.net.remote_ip, VAL_TUPLE(arg), 4); break; } // No host, must be a LISTEN socket: else if (IS_NONE(arg)) { SET_FLAG(sock->modes, RST_LISTEN); sock->common.data = 0; // where ACCEPT requests are queued sock->special.net.local_port = IS_INTEGER(val) ? VAL_INT32(val) : 8000; break; } else fail (Error_On_Port(RE_INVALID_SPEC, port, -10)); case A_CLOSE: return R_OUT; case A_OPENQ: return R_FALSE; case A_UPDATE: // allowed after a close break; default: fail (Error_On_Port(RE_NOT_OPEN, port, -12)); } } // Actions for an open socket: switch (action) { // Ordered by frequency case A_UPDATE: // Update the port object after a READ or WRITE operation. // This is normally called by the WAKE-UP function. arg = OFV(port, STD_PORT_DATA); if (sock->command == RDC_READ) { if (ANY_BINSTR(arg)) VAL_TAIL(arg) += sock->actual; } else if (sock->command == RDC_WRITE) { SET_NONE(arg); // Write is done. } return R_NONE; case A_READ: // Read data into a buffer, expanding the buffer if needed. // If no length is given, program must stop it at some point. refs = Find_Refines(call_, ALL_READ_REFS); if ( !GET_FLAG(sock->modes, RST_UDP) && !GET_FLAG(sock->state, RSM_CONNECT) ) { fail (Error_On_Port(RE_NOT_CONNECTED, port, -15)); } // Setup the read buffer (allocate a buffer if needed): arg = OFV(port, STD_PORT_DATA); if (!IS_STRING(arg) && !IS_BINARY(arg)) { Val_Init_Binary(arg, Make_Binary(NET_BUF_SIZE)); } ser = VAL_SERIES(arg); sock->length = SERIES_AVAIL(ser); // space available if (sock->length < NET_BUF_SIZE/2) Extend_Series(ser, NET_BUF_SIZE); sock->length = SERIES_AVAIL(ser); sock->common.data = STR_TAIL(ser); // write at tail //if (SERIES_TAIL(ser) == 0) sock->actual = 0; // Actual for THIS read, not for total. //Print("(max read length %d)", sock->length); result = OS_DO_DEVICE(sock, RDC_READ); // recv can happen immediately if (result < 0) fail (Error_On_Port(RE_READ_ERROR, port, sock->error)); break; case A_WRITE: // Write the entire argument string to the network. // The lower level write code continues until done. refs = Find_Refines(call_, ALL_WRITE_REFS); if (!GET_FLAG(sock->modes, RST_UDP) && !GET_FLAG(sock->state, RSM_CONNECT)) fail (Error_On_Port(RE_NOT_CONNECTED, port, -15)); // Determine length. Clip /PART to size of string if needed. spec = D_ARG(2); len = VAL_LEN(spec); if (refs & AM_WRITE_PART) { REBCNT n = Int32s(D_ARG(ARG_WRITE_LIMIT), 0); if (n <= len) len = n; } // Setup the write: *OFV(port, STD_PORT_DATA) = *spec; // keep it GC safe sock->length = len; sock->common.data = VAL_BIN_DATA(spec); sock->actual = 0; //Print("(write length %d)", len); result = OS_DO_DEVICE(sock, RDC_WRITE); // send can happen immediately if (result < 0) fail (Error_On_Port(RE_WRITE_ERROR, port, sock->error)); if (result == DR_DONE) SET_NONE(OFV(port, STD_PORT_DATA)); break; case A_PICK: // FIRST server-port returns new port connection. len = Get_Num_Arg(arg); // Position if (len == 1 && GET_FLAG(sock->modes, RST_LISTEN) && sock->common.data) Accept_New_Port(D_OUT, port, sock); // sets D_OUT else fail (Error_Out_Of_Range(arg)); break; case A_QUERY: // Get specific information - the scheme's info object. // Special notation allows just getting part of the info. Ret_Query_Net(port, sock, D_OUT); break; case A_OPENQ: // Connect for clients, bind for servers: if (sock->state & ((1<<RSM_CONNECT) | (1<<RSM_BIND))) return R_TRUE; return R_FALSE; case A_CLOSE: if (IS_OPEN(sock)) { OS_DO_DEVICE(sock, RDC_CLOSE); SET_CLOSED(sock); } break; case A_LENGTH: arg = OFV(port, STD_PORT_DATA); len = ANY_SERIES(arg) ? VAL_TAIL(arg) : 0; SET_INTEGER(D_OUT, len); break; case A_OPEN: result = OS_DO_DEVICE(sock, RDC_CONNECT); if (result < 0) fail (Error_On_Port(RE_NO_CONNECT, port, sock->error)); break; case A_DELETE: // Temporary to TEST error handler! { REBVAL *event = Append_Event(); // sets signal VAL_SET(event, REB_EVENT); // (has more space, if we need it) VAL_EVENT_TYPE(event) = EVT_ERROR; VAL_EVENT_DATA(event) = 101; VAL_EVENT_REQ(event) = sock; } break; default: fail (Error_Illegal_Action(REB_PORT, action)); } return R_OUT; }
*/ REBYTE *Security_Policy(REBCNT sym, REBVAL *name) /* ** Given a security symbol (like FILE) and a value (like the file ** path) returns the security policy (RWX) allowed for it. ** ** Args: ** ** sym: word that represents the type ['file 'net] ** name: file or path value ** ** Returns BTYE array of flags for the policy class: ** ** flags: [rrrr wwww xxxx ----] ** ** Where each byte is: ** 0: SEC_ALLOW ** 1: SEC_ASK ** 2: SEC_THROW ** 3: SEC_QUIT ** ** The secuity is defined by the system/state/policies object, that ** is of the form: ** ** [ ** file: [%file1 tuple-flags %file2 ... default tuple-flags] ** net: [...] ** call: tuple-flags ** stack: tuple-flags ** eval: integer (limit) ** ] ** ***********************************************************************/ { REBVAL *policy = Get_System(SYS_STATE, STATE_POLICIES); REBYTE *flags; REBCNT len; REBCNT errcode = RE_SECURITY_ERROR; if (!IS_OBJECT(policy)) goto error; // Find the security class in the block: (file net call...) policy = Find_Word_Value(VAL_OBJ_FRAME(policy), sym); if (!policy) goto error; // Obtain the policies for it: // Check for a master tuple: [file rrrr.wwww.xxxx] if (IS_TUPLE(policy)) return VAL_TUPLE(policy); // non-aligned // removed A90: if (IS_INTEGER(policy)) return (REBYTE*)VAL_INT64(policy); // probably not used // Only other form is detailed block: if (!IS_BLOCK(policy)) goto error; // Scan block of policies for the class: [file [allow read quit write]] len = 0; // file or url length flags = 0; // policy flags for (policy = VAL_BLK(policy); NOT_END(policy); policy += 2) { // Must be a policy tuple: if (!IS_TUPLE(policy+1)) goto error; // Is it a policy word: if (IS_WORD(policy)) { // any word works here // If no strings found, use the default: if (len == 0) flags = VAL_TUPLE(policy+1); // non-aligned } // Is it a string (file or URL): else if (ANY_BINSTR(policy) && name) { //Debug_Fmt("sec: %r %r", policy, name); if (Match_Sub_Path(VAL_SERIES(policy), VAL_SERIES(name))) { // Is the match adequate? if (VAL_TAIL(name) >= len) { len = VAL_TAIL(name); flags = VAL_TUPLE(policy+1); // non-aligned } } } else goto error; } if (!flags) { errcode = RE_SECURITY; policy = name ? name : 0; error: if (!policy) { Init_Word(DS_TOP, sym); policy = DS_TOP; } Trap1(errcode, policy); } return flags; }
*/ 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; }