Exemple #1
0
*/	REBINT PD_Time(REBPVS *pvs)
/*
***********************************************************************/
{
	REBVAL *val;
	REBINT i;
	REBINT n;
	REBDEC f;
	REB_TIMEF tf;

	if (IS_WORD(pvs->select)) {
		switch (VAL_WORD_CANON(pvs->select)) {
		case SYM_HOUR:   i = 0; break;
		case SYM_MINUTE: i = 1; break;
		case SYM_SECOND: i = 2; break;
		default: return PE_BAD_SELECT;
		}
	}
	else if (IS_INTEGER(pvs->select))
		i = VAL_INT32(pvs->select) - 1;
	else
		return PE_BAD_SELECT;

	Split_Time(VAL_TIME(pvs->value), &tf); // loses sign

	if (!(val = pvs->setval)) {
		val = pvs->store;
		switch(i) {
		case 0: // hours
			SET_INTEGER(val, tf.h);
			break;
		case 1:
			SET_INTEGER(val, tf.m);
			break;
		case 2:
			if (tf.n == 0)
				SET_INTEGER(val, tf.s);
			else
				SET_DECIMAL(val, (REBDEC)tf.s + (tf.n * NANO));
			break;
		default:
			return PE_NONE;
		}
		return PE_USE;

	} else {
		if (IS_INTEGER(val) || IS_DECIMAL(val)) n = Int32s(val, 0);
		else if (IS_NONE(val)) n = 0;
		else return PE_BAD_SET;

		switch(i) {
		case 0:
			tf.h = n;
			break;
		case 1:
			tf.m = n;
			break;
		case 2:
			if (IS_DECIMAL(val)) {
				f = VAL_DECIMAL(val);
				if (f < 0.0) Trap_Range_DEAD_END(val);
				tf.s = (REBINT)f;
				tf.n = (REBINT)((f - tf.s) * SEC_SEC);
			}
			else {
				tf.s = n;
				tf.n = 0;
			}
			break;
		default:
			return PE_BAD_SELECT;
		}

		VAL_TIME(pvs->value) = Join_Time(&tf, FALSE);
		return PE_OK;
	}
}
Exemple #2
0
*/	REBFLG MT_Date(REBVAL *val, REBVAL *arg, REBCNT type)
/*
**		Given a block of values, construct a date datatype.
**
***********************************************************************/
{
	REBI64 secs = NO_TIME;
	REBINT tz = 0;
	REBDAT date;
	REBCNT year, month, day;

	if (IS_DATE(arg)) {
		*val = *arg;
		return TRUE;
	}

	if (!IS_INTEGER(arg)) return FALSE;
	day = Int32s(arg++, 1);
	if (!IS_INTEGER(arg)) return FALSE;
	month = Int32s(arg++, 1);
	if (!IS_INTEGER(arg)) return FALSE;
	if (day > 99) {
		year = day;
		day = Int32s(arg++, 1);
	} else
		year = Int32s(arg++, 0);

	if (month < 1 || month > 12) return FALSE;

	if (year > MAX_YEAR || day < 1 || day > Month_Max_Days[month-1])
		return FALSE;

	// Check February for leap year or century:
	if (month == 2 && day == 29) {
		if (((year % 4) != 0) ||		// not leap year
			((year % 100) == 0 && 		// century?
			(year % 400) != 0)) return FALSE; // not leap century
	}

	day--;
	month--;

	if (IS_TIME(arg)) {
		secs = VAL_TIME(arg);
		arg++;
	}

	if (IS_TIME(arg)) {
		tz = (REBINT)(VAL_TIME(arg) / (ZONE_MINS * MIN_SEC));
		if (tz < -MAX_ZONE || tz > MAX_ZONE) Trap_Range_DEAD_END(arg);
		arg++;
	}

	if (!IS_END(arg)) return FALSE;

	Normalize_Time(&secs, &day);
	date = Normalize_Date(day, month, year, tz);

	VAL_SET(val, REB_DATE);
	VAL_DATE(val) = date;
	VAL_TIME(val) = secs;
	Adjust_Date_Zone(val, TRUE);

	return TRUE;
}
Exemple #3
0
*/  REBI64 Make_Time(REBVAL *val)
/*
**		Returns NO_TIME if error.
**
***********************************************************************/
{
	REBI64 secs = 0;

	if (IS_TIME(val)) {
		secs = VAL_TIME(val);
	}
	else if (IS_STRING(val)) {
		REBYTE *bp;
		REBCNT len;
		bp = Qualify_String(val, 30, &len, FALSE); // can trap, ret diff str
		if (!Scan_Time(bp, len, val)) goto no_time;
		secs = VAL_TIME(val);
	}
	else if (IS_INTEGER(val)) {
		if (VAL_INT64(val) < -MAX_SECONDS || VAL_INT64(val) > MAX_SECONDS)
			Trap_Range_DEAD_END(val);
		secs = VAL_INT64(val) * SEC_SEC;
	}
	else if (IS_DECIMAL(val)) {
		if (VAL_DECIMAL(val) < (REBDEC)(-MAX_SECONDS) || VAL_DECIMAL(val) > (REBDEC)MAX_SECONDS)
			Trap_Range_DEAD_END(val);
		secs = DEC_TO_SECS(VAL_DECIMAL(val));
	}
	else if (ANY_BLOCK(val) && VAL_BLK_LEN(val) <= 3) {
		REBFLG neg = FALSE;
		REBI64 i;

		val = VAL_BLK_DATA(val);
		if (!IS_INTEGER(val)) goto no_time;
		i = Int32(val);
		if (i < 0) i = -i, neg = TRUE;
		secs = i * 3600;
		if (secs > MAX_SECONDS) goto no_time;

		if (NOT_END(++val)) {
			if (!IS_INTEGER(val)) goto no_time;
			if ((i = Int32(val)) < 0) goto no_time;
			secs += i * 60;
			if (secs > MAX_SECONDS) goto no_time;

			if (NOT_END(++val)) {
				if (IS_INTEGER(val)) {
					if ((i = Int32(val)) < 0) goto no_time;
					secs += i;
					if (secs > MAX_SECONDS) goto no_time;
				}
				else if (IS_DECIMAL(val)) {
					if (secs + (REBI64)VAL_DECIMAL(val) + 1 > MAX_SECONDS) goto no_time;
					// added in below
				}
				else goto no_time;
			}
		}
		secs *= SEC_SEC;
		if (IS_DECIMAL(val)) secs += DEC_TO_SECS(VAL_DECIMAL(val));
		if (neg) secs = -secs;
	}
	else
		no_time: return NO_TIME;

	return secs;
}
Exemple #4
0
*/	static int Transport_Actor(REBVAL *ds, 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 = D_ARG(2);
	refs = 0;

	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)) Trap_DEAD_END(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)) Trap_Port_DEAD_END(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) Trap_Port_DEAD_END(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 Trap_Port_DEAD_END(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:
			Trap_Port_DEAD_END(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(ds, ALL_READ_REFS);
		if (!GET_FLAG(sock->modes, RST_UDP)
			&& !GET_FLAG(sock->state, RSM_CONNECT))
			Trap_Port_DEAD_END(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)) {
			Set_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) Trap_Port_DEAD_END(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(ds, ALL_WRITE_REFS);
		if (!GET_FLAG(sock->modes, RST_UDP)
			&& !GET_FLAG(sock->state, RSM_CONNECT))
			Trap_Port_DEAD_END(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_LENGTH), 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) Trap_Port_DEAD_END(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(ds, port, sock); // sets D_OUT
		else
			Trap_Range_DEAD_END(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_LENGTHQ:
		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) Trap_Port_DEAD_END(RE_NO_CONNECT, port, sock->error);
		break;
		//Trap_Port_DEAD_END(RE_ALREADY_OPEN, port);

	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:
		Trap_Action_DEAD_END(REB_PORT, action);
	}

	return R_OUT;
}