*/ static void trim_lines(REBSER *ser, REBCNT index, REBCNT tail) /* ** Remove all newlines and extra space. ** ***********************************************************************/ { REBINT pad = 1; // used to allow a single space REBUNI uc; REBCNT out = index; for (; index < tail; index++) { uc = GET_ANY_CHAR(ser, index); if (IS_WHITE(uc)) { uc = ' '; if (!pad) { SET_ANY_CHAR(ser, out, uc); out++; pad = 2; } } else { SET_ANY_CHAR(ser, out, uc); out++; pad = 0; } } // Remove extra end pad if found: if (pad == 2) out--; SET_ANY_CHAR(ser, out, 0); SERIES_TAIL(ser) = out; }
*/ static void trim_auto(REBSER *ser, REBCNT index, REBCNT tail) /* ** Skip any blank lines and then determine indent of ** first line and make the rest align with it. ** ** BUG!!! If the indentation uses TABS, then it could ** fill past the source pointer! ** ***********************************************************************/ { REBCNT out = index; REBCNT line; REBCNT len; REBCNT indent; REBUNI uc = 0; // Skip whitespace, remember start of last line: for (line = index; index < tail; index++) { uc = GET_ANY_CHAR(ser, index); if (!IS_WHITE(uc)) break; if (uc == LF) line = index+1; } // Count the indentation used: for (indent = 0; line < index; line++) { if (GET_ANY_CHAR(ser, line) == ' ') indent++; else indent = (indent + TAB_SIZE) & ~3; } // For each line, pad with necessary indentation: while (index < tail) { // Skip to next content, track indentation: for (len = 0; index < tail; index++) { uc = GET_ANY_CHAR(ser, index); if (!IS_SPACE(uc) || len >= indent) break; if (uc == ' ') len++; else len = (len + TAB_SIZE) & ~3; } // Indent the line: for (; len > indent; len--) { SET_ANY_CHAR(ser, out, ' '); out++; } // Copy line contents: while (index < tail) { uc = GET_ANY_CHAR(ser, index); SET_ANY_CHAR(ser, out, uc); out++; index++; if (uc == LF) break; } } SET_ANY_CHAR(ser, out, 0); SERIES_TAIL(ser) = out; }
*/ static void replace_with(REBSER *ser, REBCNT index, REBCNT tail, REBVAL *with) /* ** Replace whitespace chars that match WITH string. ** ** Resulting string is always smaller than it was to start. ** ***********************************************************************/ { #define MAX_WITH 32 REBCNT wlen; REBUNI with_chars[MAX_WITH]; // chars to be trimmed REBUNI *up = with_chars; REBYTE *bp; REBCNT n; REBUNI uc; // Setup WITH array from arg or the default: n = 0; if (IS_NONE(with)) { bp = "\n \r\t"; wlen = n = 4; } else if (IS_CHAR(with)) { wlen = 1; *up++ = VAL_CHAR(with); } else if (IS_INTEGER(with)) { wlen = 1; *up++ = Int32s(with, 0); } else if (ANY_BINSTR(with)) { n = VAL_LEN(with); if (n >= MAX_WITH) n = MAX_WITH-1; wlen = n; if (VAL_BYTE_SIZE(with)) { bp = VAL_BIN_DATA(with); } else { memcpy(up, VAL_UNI_DATA(with), n * sizeof(REBUNI)); n = 0; } } for (; n > 0; n--) *up++ = (REBUNI)*bp++; // Remove all occurances of chars found in WITH string: for (n = index; index < tail; index++) { uc = GET_ANY_CHAR(ser, index); if (!find_in_uni(with_chars, wlen, uc)) { SET_ANY_CHAR(ser, n, uc); n++; } } SET_ANY_CHAR(ser, n, 0); SERIES_TAIL(ser) = n; }
static void swap_chars(REBVAL *val1, REBVAL *val2) { REBUNI c1; REBUNI c2; REBSER *s1 = VAL_SERIES(val1); REBSER *s2 = VAL_SERIES(val2); c1 = GET_ANY_CHAR(s1, VAL_INDEX(val1)); c2 = GET_ANY_CHAR(s2, VAL_INDEX(val2)); if (BYTE_SIZE(s1) && c2 > 0xff) Widen_String(s1); SET_ANY_CHAR(s1, VAL_INDEX(val1), c2); if (BYTE_SIZE(s2) && c1 > 0xff) Widen_String(s2); SET_ANY_CHAR(s2, VAL_INDEX(val2), c1); }
// // Shuffle_String: C // // Randomize a string. Return a new string series. // Handles both BYTE and UNICODE strings. // void Shuffle_String(REBVAL *value, REBOOL secure) { REBCNT n; REBCNT k; REBSER *series = VAL_SERIES(value); REBCNT idx = VAL_INDEX(value); REBUNI swap; for (n = VAL_LEN_AT(value); n > 1;) { k = idx + (REBCNT)Random_Int(secure) % n; n--; swap = GET_ANY_CHAR(series, k); SET_ANY_CHAR(series, k, GET_ANY_CHAR(series, n + idx)); SET_ANY_CHAR(series, n + idx, swap); } }
// // RL_Set_Char: C // // Set a character into a byte or unicode string. // // Returns: // The index passed as an argument. // Arguments: // series - string series pointer // index - where to store the character. If past the tail, // the string will be auto-expanded by one and the char // will be appended. // RL_API u32 RL_Set_Char(REBSER *series, u32 index, u32 chr) { if (index >= SER_LEN(series)) { index = SER_LEN(series); EXPAND_SERIES_TAIL(series, 1); } SET_ANY_CHAR(series, index, chr); return index; }
*/ REBINT PD_String(REBPVS *pvs) /* ***********************************************************************/ { REBVAL *data = pvs->value; REBVAL *val = pvs->setval; REBINT n = 0; REBCNT i; REBINT c; REBSER *ser = VAL_SERIES(data); if (IS_INTEGER(pvs->select)) { n = Int32(pvs->select) + VAL_INDEX(data) - 1; } else return PE_BAD_SELECT; if (val == 0) { if (n < 0 || (REBCNT)n >= SERIES_TAIL(ser)) return PE_NONE; if (IS_BINARY(data)) { SET_INTEGER(pvs->store, *BIN_SKIP(ser, n)); } else { SET_CHAR(pvs->store, GET_ANY_CHAR(ser, n)); } return PE_USE; } if (n < 0 || (REBCNT)n >= SERIES_TAIL(ser)) return PE_BAD_RANGE; if (IS_CHAR(val)) { c = VAL_CHAR(val); if (c > MAX_CHAR) return PE_BAD_SET; } else if (IS_INTEGER(val)) { c = Int32(val); if (c > MAX_CHAR || c < 0) return PE_BAD_SET; if (IS_BINARY(data)) { // special case for binary if (c > 0xff) Trap_Range(val); BIN_HEAD(ser)[n] = (REBYTE)c; return PE_OK; } } else if (ANY_BINSTR(val)) { i = VAL_INDEX(val); if (i >= VAL_TAIL(val)) return PE_BAD_SET; c = GET_ANY_CHAR(VAL_SERIES(val), i); } else return PE_BAD_SELECT; TRAP_PROTECT(ser); if (BYTE_SIZE(ser) && c > 0xff) Widen_String(ser); SET_ANY_CHAR(ser, n, c); return PE_OK; }
*/ void Insert_Char(REBSER *dst, REBCNT index, REBCNT chr) /* ** Insert a Char (byte or unicode) into a string. ** ***********************************************************************/ { if (index > dst->tail) index = dst->tail; if (chr > 0xFF && BYTE_SIZE(dst)) Widen_String(dst, TRUE); Expand_Series(dst, index, 1); SET_ANY_CHAR(dst, index, chr); }
*/ void Shuffle_String(REBVAL *value, REBFLG secure) /* ** Randomize a string. Return a new string series. ** Handles both BYTE and UNICODE strings. ** ***********************************************************************/ { REBCNT n; REBCNT k; REBSER *series = VAL_SERIES(value); REBCNT idx = VAL_INDEX(value); REBUNI swap; for (n = VAL_LEN(value); n > 1;) { k = idx + (REBCNT)Random_Int(secure) % n; n--; swap = GET_ANY_CHAR(series, k); SET_ANY_CHAR(series, k, GET_ANY_CHAR(series, n + idx)); SET_ANY_CHAR(series, n + idx, swap); } }
*/ static int Read_Dir(REBREQ *dir, REBSER *files) /* ** Provide option to get file info too. ** Provide option to prepend dir path. ** Provide option to use wildcards. ** ***********************************************************************/ { REBINT result; REBCNT len; REBSER *fname; REBSER *name; REBREQ file; RESET_TAIL(files); CLEARS(&file); // Temporary filename storage: fname = BUF_OS_STR; file.special.file.path = cast(REBCHR*, Reset_Buffer(fname, MAX_FILE_NAME)); SET_FLAG(dir->modes, RFM_DIR); dir->common.data = cast(REBYTE*, &file); while ((result = OS_DO_DEVICE(dir, RDC_READ)) == 0 && !GET_FLAG(dir->flags, RRF_DONE)) { len = OS_STRLEN(file.special.file.path); if (GET_FLAG(file.modes, RFM_DIR)) len++; name = Copy_OS_Str(file.special.file.path, len); if (GET_FLAG(file.modes, RFM_DIR)) SET_ANY_CHAR(name, name->tail-1, '/'); Val_Init_File(Alloc_Tail_Array(files), name); } if (result < 0 && dir->error != -RFE_OPEN_FAIL && ( OS_STRCHR(dir->special.file.path, '*') || OS_STRCHR(dir->special.file.path, '?') ) ) { result = 0; // no matches found, but not an error } return result; }
RL_API u32 RL_Set_Char(REBSER *series, u32 index, u32 chr) /* ** Set a character into a byte or unicode string. ** ** Returns: ** The index passed as an argument. ** Arguments: ** series - string series pointer ** index - where to store the character. If past the tail, ** the string will be auto-expanded by one and the char ** will be appended. */ { if (index >= series->tail) { index = series->tail; EXPAND_SERIES_TAIL(series, 1); } SET_ANY_CHAR(series, index, chr); return index; }
*/ static int Read_Dir(REBREQ *dir, REBSER *files) /* ** Provide option to get file info too. ** Provide option to prepend dir path. ** Provide option to use wildcards. ** ***********************************************************************/ { REBINT result; REBCNT len; REBSER *fname; REBSER *name; REBREQ file; RESET_TAIL(files); CLEARS(&file); // Temporary filename storage: fname = BUF_OS_STR; file.file.path = (REBCHR*)Reset_Buffer(fname, MAX_FILE_NAME); SET_FLAG(dir->modes, RFM_DIR); dir->data = (REBYTE*)(&file); while ((result = OS_DO_DEVICE(dir, RDC_READ)) == 0 && !GET_FLAG(dir->flags, RRF_DONE)) { len = LEN_STR(file.file.path); if (GET_FLAG(file.modes, RFM_DIR)) len++; name = Copy_OS_Str(file.file.path, len); if (GET_FLAG(file.modes, RFM_DIR)) SET_ANY_CHAR(name, name->tail-1, '/'); Set_Series(REB_FILE, Append_Value(files), name); } if (result < 0 && dir->error != -RFE_OPEN_FAIL && (FIND_CHR(dir->file.path, '*') || FIND_CHR(dir->file.path, '?'))) result = 0; // no matches found, but not an error return result; }
*/ static REB_R Console_Actor(struct Reb_Call *call_, REBSER *port, REBCNT action) /* ***********************************************************************/ { REBREQ *req; REBINT result; REBVAL *arg = D_ARG(2); REBSER *ser; Validate_Port(port, action); arg = D_ARG(2); *D_OUT = *D_ARG(1); req = cast(REBREQ*, Use_Port_State(port, RDI_STDIO, sizeof(REBREQ))); switch (action) { case A_READ: // If not open, open it: if (!IS_OPEN(req)) { if (OS_DO_DEVICE(req, RDC_OPEN)) Trap_Port_DEAD_END(RE_CANNOT_OPEN, port, req->error); } // If no buffer, create a buffer: arg = OFV(port, STD_PORT_DATA); if (!IS_STRING(arg) && !IS_BINARY(arg)) { Set_Binary(arg, MAKE_OS_BUFFER(OUT_BUF_SIZE)); } ser = VAL_SERIES(arg); RESET_SERIES(ser); req->common.data = BIN_HEAD(ser); req->length = SERIES_AVAIL(ser); #ifdef nono // Is the buffer large enough? req->length = SERIES_AVAIL(ser); // space available if (req->length < OUT_BUF_SIZE/2) Extend_Series(ser, OUT_BUF_SIZE); req->length = SERIES_AVAIL(ser); // Don't make buffer too large: Bug #174 ????? if (req->length > 1024) req->length = 1024; //??? req->common.data = STR_TAIL(ser); // write at tail //??? if (SERIES_TAIL(ser) == 0) req->actual = 0; //??? #endif result = OS_DO_DEVICE(req, RDC_READ); if (result < 0) Trap_Port_DEAD_END(RE_READ_ERROR, port, req->error); #ifdef nono // Does not belong here!! // Remove or replace CRs: result = 0; for (n = 0; n < req->actual; n++) { chr = GET_ANY_CHAR(ser, n); if (chr == CR) { chr = LF; // Skip LF if it follows: if ((n+1) < req->actual && LF == GET_ANY_CHAR(ser, n+1)) n++; } SET_ANY_CHAR(ser, result, chr); result++; } #endif // !!! Among many confusions in this file, it said "Another copy???" //Set_String(D_OUT, Copy_OS_Str(ser->data, result)); Set_Binary(D_OUT, Copy_Bytes(req->common.data, req->actual)); break; case A_OPEN: // ?? why??? //if (OS_DO_DEVICE(req, RDC_OPEN)) Trap_Port_DEAD_END(RE_CANNOT_OPEN, port); SET_OPEN(req); break; case A_CLOSE: SET_CLOSED(req); //OS_DO_DEVICE(req, RDC_CLOSE); break; case A_OPENQ: if (IS_OPEN(req)) return R_TRUE; return R_FALSE; default: Trap_Action_DEAD_END(REB_PORT, action); } return R_OUT; }
*/ static void trim_head_tail(REBSER *ser, REBCNT index, REBCNT tail, REBFLG h, REBFLG t) /* ** Trim from head and tail of each line, trim any leading or ** trailing lines as well, leaving one at the end if present ** ***********************************************************************/ { REBCNT start = index; REBCNT out = index; REBUNI uc; // Skip head lines if required: if (h || !t) { for (; index < tail; index++) { uc = GET_ANY_CHAR(ser, index); if (!IS_WHITE(uc)) break; } } // Trim the head and tail parts of a line: if (!h && !t) { REBINT hf = 1; // head space flag REBINT tf = 0; // tail space flag and index // Trim lines: for (; index < tail; index++) { uc = GET_ANY_CHAR(ser, index); if (IS_SPACE(uc)) { if (hf) continue; // trim from head tf = index; // tailing spaces? } else if (uc == LF) { hf = 1; if (tf) out = tf; tf = 0; } else hf = tf = 0; SET_ANY_CHAR(ser, out, uc); out++; } } else { for (; index < tail; index++) { uc = GET_ANY_CHAR(ser, index); SET_ANY_CHAR(ser, out, uc); out++; } } // Trim tail lines if required: if (t || !h) { REBOOL flag = FALSE; // found newline for (out--; out >= start; out--) { uc = GET_ANY_CHAR(ser, out); if (!IS_WHITE(uc)) break; if (uc == LF) flag = TRUE; } out++; if (!t && flag) { SET_ANY_CHAR(ser, out, LF); out++; } } SET_ANY_CHAR(ser, out, 0); SERIES_TAIL(ser) = out; }