Skip to content

Commit b781296

Browse files
committed
FEAT: mold/part to limit the length of the result
implements: Oldes/Rebol-issues#2422
1 parent 1317e13 commit b781296

File tree

11 files changed

+114
-39
lines changed

11 files changed

+114
-39
lines changed

src/core/a-lib.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,11 @@ extern int Do_Callback(REBSER *obj, u32 name, RXIARG *args, RXIARG *result);
446446
if (!IS_ERROR(top)) {
447447
types = Get_System(SYS_OPTIONS, OPTIONS_RESULT_TYPES);
448448
if (IS_TYPESET(types) && TYPE_CHECK(types, VAL_TYPE(top))) {
449-
if (marker) Out_Str(marker, 0);
449+
if (marker) {
450+
DS_SKIP; // protect `top` from modification
451+
Out_Str(marker, 0);
452+
DS_DROP;
453+
}
450454
Out_Value(top, 500, TRUE, 1); // limit, molded
451455
}
452456
// else {

src/core/f-enbase.c

+8-11
Original file line numberDiff line numberDiff line change
@@ -767,20 +767,19 @@
767767

768768
/***********************************************************************
769769
**
770-
*/ REBSER *Encode_Base2(REBVAL *value, REBSER *series, REBFLG brk)
770+
*/ REBSER *Encode_Base2(REBVAL *value, REBSER *series, REBCNT len, REBFLG brk)
771771
/*
772772
** Base2 encode a given series. Must be BYTES, not UNICODE.
773773
**
774774
***********************************************************************/
775775
{
776776
REBYTE *p; // ?? should it be REBYTE? Same with below functions?
777777
REBYTE *src;
778-
REBINT len;
779-
REBINT i;
780-
REBINT n;
778+
REBCNT i;
779+
REBCNT n;
781780
REBYTE b;
782781

783-
len = VAL_LEN(value);
782+
if(len > VAL_LEN(value)) len = VAL_LEN(value);
784783
src = VAL_BIN_DATA(value);
785784

786785
// Add slop-factor
@@ -809,18 +808,17 @@
809808

810809
/***********************************************************************
811810
**
812-
*/ REBSER *Encode_Base16(REBVAL *value, REBSER *series, REBFLG brk)
811+
*/ REBSER *Encode_Base16(REBVAL *value, REBSER *series, REBCNT len, REBFLG brk)
813812
/*
814813
** Base16 encode a given series. Must be BYTES, not UNICODE.
815814
**
816815
***********************************************************************/
817816
{
818817
REBCNT count;
819-
REBCNT len;
820818
REBYTE *bp;
821819
REBYTE *src;
822820

823-
len = VAL_LEN(value);
821+
if(len > VAL_LEN(value)) len = VAL_LEN(value);
824822
src = VAL_BIN_DATA(value);
825823

826824
// Account for hex, lines, and extra syntax:
@@ -844,18 +842,17 @@
844842

845843
/***********************************************************************
846844
**
847-
*/ REBSER *Encode_Base64(REBVAL *value, REBSER *series, REBFLG brk, REBOOL urlSafe)
845+
*/ REBSER *Encode_Base64(REBVAL *value, REBSER *series, REBCNT len, REBFLG brk, REBOOL urlSafe)
848846
/*
849847
** Base64 encode a given series. Must be BYTES, not UNICODE.
850848
**
851849
***********************************************************************/
852850
{
853851
REBYTE *p;
854852
REBYTE *src;
855-
REBCNT len;
856853
REBINT x, loop;
857854

858-
len = VAL_LEN(value);
855+
if(len > VAL_LEN(value)) len = VAL_LEN(value);
859856
src = VAL_BIN_DATA(value);
860857

861858
const REBYTE *table;

src/core/n-io.c

+14-2
Original file line numberDiff line numberDiff line change
@@ -124,22 +124,34 @@ static REBSER *Read_All_File(char *fname)
124124
** /only "For a block value, give only contents, no outer [ ]"
125125
** /all "Mold in serialized format"
126126
** /flat "No line indentation"
127+
** /part "Limit the length of the result"
128+
** limit [integer!]
127129
**
128130
***********************************************************************/
129131
{
130132
REBVAL *val = D_ARG(1);
131133
REB_MOLD mo = {0};
134+
REBINT len = -1; // no limit
132135

133136
if (D_REF(3)) SET_FLAG(mo.opts, MOPT_MOLD_ALL);
134137
if (D_REF(4)) SET_FLAG(mo.opts, MOPT_INDENT);
138+
if (D_REF(5)) {
139+
if (VAL_INT64(D_ARG(6)) > (i64)MAX_I32)
140+
len = MAX_I32;
141+
else if (VAL_INT64(D_ARG(6)) < 0)
142+
len = 0;
143+
else
144+
len = VAL_INT32(D_ARG(6));
145+
}
135146

136147
Reset_Mold(&mo);
148+
mo.limit = (REBINT)len;
137149

138150
if (D_REF(2) && IS_BLOCK(val)) SET_FLAG(mo.opts, MOPT_ONLY);
139151

140152
Mold_Value(&mo, val, TRUE);
141-
142-
Set_String(D_RET, Copy_String(mo.series, 0, -1));
153+
if (len > mo.series->tail) len = mo.series->tail;
154+
Set_String(D_RET, Copy_String(mo.series, 0, len));
143155

144156
return R_RET;
145157
}

src/core/n-strings.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -486,13 +486,13 @@ static struct digest {
486486

487487
switch (base) {
488488
case 64:
489-
ser = Encode_Base64(arg, 0, FALSE, D_REF(3));
489+
ser = Encode_Base64(arg, 0, NO_LIMIT, FALSE, D_REF(3));
490490
break;
491491
case 16:
492-
ser = Encode_Base16(arg, 0, FALSE);
492+
ser = Encode_Base16(arg, 0, NO_LIMIT, FALSE);
493493
break;
494494
case 2:
495-
ser = Encode_Base2(arg, 0, FALSE);
495+
ser = Encode_Base2(arg, 0, NO_LIMIT, FALSE);
496496
break;
497497
case 85:
498498
#ifdef INCLUDE_BASE85

src/core/s-mold.c

+22-10
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,8 @@ STOID Mold_String_Series(REBVAL *value, REB_MOLD *mold)
384384
return;
385385
}
386386

387+
CHECK_MOLD_LIMIT(mold, len);
388+
387389
Sniff_String(ser, idx, &sf);
388390
if (!GET_MOPT(mold, MOPT_ANSI_ONLY)) sf.paren = 0;
389391

@@ -415,7 +417,7 @@ STOID Mold_String_Series(REBVAL *value, REB_MOLD *mold)
415417

416418
*dp++ = '{';
417419

418-
for (n = idx; n < VAL_TAIL(value); n++) {
420+
for (n = idx; n < (len + idx); n++) {
419421

420422
c = uni ? up[n] : (REBUNI)(bp[n]);
421423
switch (c) {
@@ -554,18 +556,20 @@ STOID Mold_Handle(REBVAL *value, REB_MOLD *mold)
554556
REBSER *out;
555557
REBOOL indented = !GET_MOPT(mold, MOPT_INDENT);
556558

559+
CHECK_MOLD_LIMIT(mold, len);
560+
557561
switch (Get_System_Int(SYS_OPTIONS, OPTIONS_BINARY_BASE, 16)) {
558562
default:
559563
case 16:
560-
out = Encode_Base16(value, 0, indented && len > 32);
564+
out = Encode_Base16(value, 0, len, indented && len > 32);
561565
break;
562566
case 64:
563567
Append_Bytes(mold->series, "64");
564-
out = Encode_Base64(value, 0, indented && len > 64, FALSE);
568+
out = Encode_Base64(value, 0, len, indented && len > 64, FALSE);
565569
break;
566570
case 2:
567571
Append_Byte(mold->series, '2');
568-
out = Encode_Base2(value, 0, indented && len > 8);
572+
out = Encode_Base2(value, 0, len, indented && len > 8);
569573
break;
570574
}
571575

@@ -632,6 +636,8 @@ STOID Mold_Block_Series(REB_MOLD *mold, REBSER *series, REBCNT index, REBYTE *se
632636

633637
value = BLK_SKIP(series, index);
634638
while (NOT_END(value)) {
639+
// check if we can end sooner with molding..
640+
if (MOLD_HAS_LIMIT(mold) && MOLD_OVER_LIMIT(mold)) return;
635641
if (VAL_GET_LINE(value)) {
636642
if (indented && (sep[1] || line_flag)) New_Indented_Line(mold);
637643
had_lines = TRUE;
@@ -955,12 +961,16 @@ STOID Mold_Object(REBVAL *value, REB_MOLD *mold)
955961
Append_Bytes(mold->series, ": ");
956962
if (IS_WORD(vals+n) && !GET_MOPT(mold, MOPT_MOLD_ALL)) Append_Byte(mold->series, '\'');
957963
Mold_Value(mold, vals+n, TRUE);
964+
if (MOLD_HAS_LIMIT(mold) && MOLD_OVER_LIMIT(mold)) {
965+
// early escape
966+
Remove_Last(MOLD_LOOP);
967+
return;
968+
}
958969
}
959970
}
960971
mold->indent--;
961972
if (indented) New_Indented_Line(mold);
962973
Append_Byte(mold->series, ']');
963-
964974
End_Mold(mold);
965975
Remove_Last(MOLD_LOOP);
966976
}
@@ -1061,7 +1071,7 @@ STOID Mold_Error(REBVAL *value, REB_MOLD *mold, REBFLG molded)
10611071

10621072
// Forming a string:
10631073
if (!molded) {
1064-
Insert_String(ser, -1, VAL_SERIES(value), VAL_INDEX(value), VAL_LEN(value), 0);
1074+
Insert_String(ser, NO_LIMIT, VAL_SERIES(value), VAL_INDEX(value), VAL_LEN(value), 0);
10651075
return;
10661076
}
10671077

@@ -1138,7 +1148,7 @@ STOID Mold_Error(REBVAL *value, REB_MOLD *mold, REBFLG molded)
11381148
Mold_Binary(value, mold);
11391149
}
11401150
else {
1141-
Emit(mold, "E", Encode_Base16(value, 0, FALSE));
1151+
Emit(mold, "E", Encode_Base16(value, 0, NO_LIMIT, FALSE));
11421152
}
11431153
break;
11441154

@@ -1194,10 +1204,10 @@ STOID Mold_Error(REBVAL *value, REB_MOLD *mold, REBFLG molded)
11941204

11951205
case REB_BLOCK:
11961206
case REB_PAREN:
1197-
if (!molded)
1198-
Form_Block_Series(VAL_SERIES(value), VAL_INDEX(value), mold, 0);
1199-
else
1207+
if (molded)
12001208
Mold_Block(value, mold);
1209+
else
1210+
Form_Block_Series(VAL_SERIES(value), VAL_INDEX(value), mold, 0);
12011211
break;
12021212

12031213
case REB_PATH:
@@ -1445,6 +1455,7 @@ STOID Mold_Error(REBVAL *value, REB_MOLD *mold, REBFLG molded)
14451455
else if (len < 0) len = 0;
14461456
}
14471457
mold->digits = len;
1458+
mold->limit = NO_LIMIT;
14481459
}
14491460

14501461

@@ -1461,6 +1472,7 @@ STOID Mold_Error(REBVAL *value, REB_MOLD *mold, REBFLG molded)
14611472
REB_MOLD mo = {0};
14621473

14631474
Reset_Mold(&mo);
1475+
mo.limit = limit;
14641476

14651477
Mold_Value(&mo, value, mold);
14661478

src/core/t-image.c

+6
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,9 @@ INLINE REBCNT ARGB_To_BGR(REBCNT i)
479479
return;
480480
}
481481

482+
// reduce size if mold/part is used, so not all pixels are processed
483+
CHECK_MOLD_LIMIT(mold, size);
484+
482485
// use `flat` result for images with less than 10 pixels (looks better in console)
483486
if (size < 10) indented = FALSE;
484487

@@ -491,6 +494,9 @@ INLINE REBCNT ARGB_To_BGR(REBCNT i)
491494
up = Form_RGB_Uni(up, TO_RGBA_COLOR(pixel[C_R], pixel[C_G], pixel[C_B], pixel[C_A]));
492495
}
493496

497+
// don't waste time with alpha if we are over limit
498+
if (MOLD_HAS_LIMIT(mold) && MOLD_OVER_LIMIT(mold)) return;
499+
494500
// Output Alpha channel, if it has one:
495501
if (Image_Has_Alpha(value, FALSE)) {
496502
if (indented) Append_Byte(mold->series, '\n');

src/core/t-vector.c

+2
Original file line numberDiff line numberDiff line change
@@ -865,10 +865,12 @@ void Set_Vector_Row(REBSER *ser, REBVAL *blk)
865865
mold->indent++;
866866
New_Indented_Line(mold);
867867
}
868+
CHECK_MOLD_LIMIT(mold, len);
868869
}
869870

870871
c = 0;
871872
for (; n < vect->tail; n++) {
873+
if (MOLD_HAS_LIMIT(mold) && MOLD_OVER_LIMIT(mold)) return;
872874
v.i = get_vect(bits, data, n);
873875
if (bits < VTSF08) {
874876
l = Emit_Integer(buf, v.i);

src/include/sys-core.h

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ typedef struct rebol_mold {
101101
REBYTE period; // for decimal point
102102
REBYTE dash; // for date fields
103103
REBYTE digits; // decimal digits
104+
REBCNT limit; // optional length limit of the result (-1 = no limit)
104105
} REB_MOLD;
105106

106107
#include "reb-file.h"

src/include/sys-value.h

+10
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,16 @@ typedef struct Reb_Series_Ref
615615
//#define VAL_STR_LAST(v) STR_LAST(VAL_SERIES(v))
616616
//#define VAL_MEM_LEN(v) (VAL_TAIL(v) * VAL_SERIES_WIDTH(v))
617617

618+
// `mold` limit related defines
619+
#define NO_LIMIT (REBCNT)-1
620+
#define MOLD_HAS_LIMIT(mold) (mold->limit != NO_LIMIT)
621+
#define MOLD_OVER_LIMIT(mold) (mold->series->tail >= mold->limit)
622+
#define MOLD_REST(mold) (mold->limit - mold->series->tail)
623+
#define CHECK_MOLD_LIMIT(mold, len) \
624+
if (MOLD_HAS_LIMIT(mold)) { \
625+
if (MOLD_OVER_LIMIT(mold)) return; \
626+
if (MOLD_REST(mold) < len) len = MOLD_REST(mold); \
627+
}
618628

619629
/***********************************************************************
620630
**

src/mezz/mezz-help.r

+10-9
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,10 @@ import module [
6868

6969
clip-str: func [str] [
7070
; Keep string to one line.
71-
unless string? str [str: mold str]
72-
trim/lines str
73-
if (length? str) > max-desc-width [str: append copy/part str max-desc-width "..."]
71+
unless string? str [str: mold/part/flat str max-desc-width]
72+
replace/all str LF "^^/"
73+
replace/all str CR "^^M"
74+
if (length? str) > (max-desc-width - 1) [str: append copy/part str max-desc-width "..."]
7475
str
7576
]
7677

@@ -93,20 +94,20 @@ import module [
9394
a-an head clear back tail mold type? :value
9495
]
9596

96-
form-val: func [val] [
97+
form-val: func [val /local limit] [
9798
; Form a limited string from the value provided.
9899
val: case [
99-
string? :val [ mold val ]
100-
any-block? :val [ reform ["length:" length? val mold/flat val] ]
100+
string? :val [ mold/part/flat val max-desc-width]
101+
any-block? :val [ reform ["length:" length? val mold/part/flat val max-desc-width] ]
101102
object? :val [ words-of val ]
102103
module? :val [ words-of val ]
103104
any-function? :val [ any [title-of :val spec-of :val] ]
104105
datatype? :val [ get in spec-of val 'title ]
105106
typeset? :val [ to block! val]
106107
port? :val [ reduce [val/spec/title val/spec/ref] ]
107-
image? :val [ return reform ["size:" val/size] ]
108+
image? :val [ mold/part/all/flat val max-desc-width]
108109
gob? :val [ return reform ["offset:" val/offset "size:" val/size] ]
109-
vector? :val [ mold/all val ]
110+
vector? :val [ mold/part/all/flat val max-desc-width]
110111
;none? :val [ mold/all val]
111112
true [:val]
112113
]
@@ -184,7 +185,7 @@ import module [
184185
/local value spec args refs rets type ret desc arg def des ref
185186
][
186187
try [
187-
max-desc-width: (query/mode system/ports/input 'buffer-cols) - 36
188+
max-desc-width: (query/mode system/ports/input 'buffer-cols) - 35
188189
]
189190
buffer: any [string clear ""]
190191
catch [

0 commit comments

Comments
 (0)