changelog shortlog tags branches changeset files file revisions raw help

Mercurial > hg > plan9front / annotate sys/src/cmd/gs/src/ztype.c

changeset 7254: 03b53375c4f5
parent: eaccc3e8d226
author: cinap_lenrek@felloff.net
date: Fri, 24 May 2019 14:17:18 +0200
permissions: -rw-r--r--
description: gs: fix missing type check in ztype (thanks jsmoody)

to reproduce:

gs <<.
null [[][][][][][][][][][][][][][][]] .type
.
taruti@0 1
 /* Copyright (C) 1989, 2000 Aladdin Enterprises.  All rights reserved.
taruti@0 2
   
taruti@0 3
   This software is provided AS-IS with no warranty, either express or
taruti@0 4
   implied.
taruti@0 5
   
taruti@0 6
   This software is distributed under license and may not be copied,
taruti@0 7
   modified or distributed except as expressly authorized under the terms
taruti@0 8
   of the license contained in the file LICENSE in this distribution.
taruti@0 9
   
taruti@0 10
   For more information about licensing, please refer to
taruti@0 11
   http://www.ghostscript.com/licensing/. For information on
taruti@0 12
   commercial licensing, go to http://www.artifex.com/licensing/ or
taruti@0 13
   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
taruti@0 14
   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
taruti@0 15
 */
taruti@0 16
 
taruti@0 17
 /* $Id: ztype.c,v 1.8 2004/08/04 19:36:13 stefan Exp $ */
taruti@0 18
 /* Type, attribute, and conversion operators */
taruti@0 19
 #include "math_.h"
taruti@0 20
 #include "memory_.h"
taruti@0 21
 #include "string_.h"
taruti@0 22
 #include "gsexit.h"
taruti@0 23
 #include "ghost.h"
taruti@0 24
 #include "oper.h"
taruti@0 25
 #include "imemory.h"		/* for register_ref_root */
taruti@0 26
 #include "idict.h"
taruti@0 27
 #include "iname.h"
taruti@0 28
 #include "stream.h"		/* for iscan.h */
taruti@0 29
 #include "strimpl.h"		/* for sfilter.h for picky compilers */
taruti@0 30
 #include "sfilter.h"		/* ditto */
taruti@0 31
 #include "iscan.h"
taruti@0 32
 #include "iutil.h"
taruti@0 33
 #include "dstack.h"		/* for dict_set_top */
taruti@0 34
 #include "store.h"
taruti@0 35
 
taruti@0 36
 /*
taruti@0 37
  * Some of the procedures in this file are public only so they can be
taruti@0 38
  * called from the FunctionType 4 interpreter (zfunc4.c).
taruti@0 39
  */
taruti@0 40
 
taruti@0 41
 /* Forward references */
taruti@0 42
 private int access_check(i_ctx_t *, int, bool);
taruti@0 43
 private int convert_to_string(const gs_memory_t *mem, os_ptr, os_ptr);
taruti@0 44
 
taruti@0 45
 /*
taruti@0 46
  * Max and min integer values expressed as reals.
taruti@0 47
  * Note that these are biased by 1 to allow for truncation.
taruti@0 48
  * They should be #defines rather than static consts, but
taruti@0 49
  * several of the SCO Unix compilers apparently can't handle this.
taruti@0 50
  * On the other hand, the DEC compiler can't handle casts in
taruti@0 51
  * constant expressions, so we can't use min_long and max_long.
taruti@0 52
  * What a nuisance!
taruti@0 53
  */
taruti@0 54
 #define ALT_MIN_LONG (-1L << (arch_sizeof_long * 8 - 1))
taruti@0 55
 #define ALT_MAX_LONG (~(ALT_MIN_LONG))
taruti@0 56
 private const double min_int_real = (ALT_MIN_LONG * 1.0 - 1);
taruti@0 57
 private const double max_int_real = (ALT_MAX_LONG * 1.0 + 1);
taruti@0 58
 
taruti@0 59
 #define REAL_CAN_BE_INT(v)\
taruti@0 60
   ((v) > min_int_real && (v) < max_int_real)
taruti@0 61
 
taruti@0 62
 /* Get the pointer to the access flags for a ref. */
taruti@0 63
 #define ACCESS_REF(opp)\
taruti@0 64
   (r_has_type(opp, t_dictionary) ? dict_access_ref(opp) : opp)
taruti@0 65
 
taruti@0 66
 /* <obj> <typenames> .type <name> */
taruti@0 67
 private int
taruti@0 68
 ztype(i_ctx_t *i_ctx_p)
taruti@0 69
 {
taruti@0 70
     os_ptr op = osp;
taruti@0 71
     ref tnref;
taruti@0 72
     int code = array_get(imemory, op, (long)r_btype(op - 1), &tnref);
taruti@0 73
 
taruti@0 74
     if (code < 0)
taruti@0 75
 	return code;
taruti@0 76
     if (!r_has_type(&tnref, t_name)) {
taruti@0 77
 	/* Must be either a stack underflow or a t_[a]struct. */
taruti@0 78
 	check_op(2);
taruti@0 79
 	{			/* Get the type name from the structure. */
cinap_lenrek@7254 80
 	    if ((r_has_type(&op[-1], t_struct) || r_has_type(&op[-1], t_astruct))
cinap_lenrek@7254 81
 	    && op[-1].value.pstruct != 0x00) {
cinap_lenrek@7254 82
 		const char *sname =
cinap_lenrek@7254 83
 		    gs_struct_type_name_string(gs_object_type(imemory, op[-1].value.pstruct));
cinap_lenrek@7254 84
 		code = name_ref(imemory, (const byte *)sname, strlen(sname), (ref *) (op - 1), 0);
cinap_lenrek@7254 85
 		if (code < 0)
cinap_lenrek@7254 86
 		    return code;
cinap_lenrek@7254 87
 	    } else
cinap_lenrek@7254 88
 		return_error(e_stackunderflow);
taruti@0 89
 	}
taruti@0 90
 	r_set_attrs(op - 1, a_executable);
taruti@0 91
     } else {
taruti@0 92
 	ref_assign(op - 1, &tnref);
taruti@0 93
     }
taruti@0 94
     pop(1);
taruti@0 95
     return 0;
taruti@0 96
 }
taruti@0 97
 
taruti@0 98
 /* - .typenames <name1|null> ... <nameN|null> */
taruti@0 99
 private int
taruti@0 100
 ztypenames(i_ctx_t *i_ctx_p)
taruti@0 101
 {
taruti@0 102
     os_ptr op = osp;
taruti@0 103
     static const char *const tnames[] = { REF_TYPE_NAME_STRINGS };
taruti@0 104
     int i;
taruti@0 105
 
taruti@0 106
     check_ostack(t_next_index);
taruti@0 107
     for (i = 0; i < t_next_index; i++) {
taruti@0 108
 	ref *const rtnp = op + 1 + i;
taruti@0 109
 
taruti@0 110
 	if (i >= countof(tnames) || tnames[i] == 0)
taruti@0 111
 	    make_null(rtnp);
taruti@0 112
 	else {
taruti@0 113
 	    int code = name_enter_string(imemory, tnames[i], rtnp);
taruti@0 114
 
taruti@0 115
 	    if (code < 0)
taruti@0 116
 		return code;
taruti@0 117
 	    r_set_attrs(rtnp, a_executable);
taruti@0 118
 	}
taruti@0 119
     }
taruti@0 120
     osp += t_next_index;
taruti@0 121
     return 0;
taruti@0 122
 }
taruti@0 123
 
taruti@0 124
 /* <obj> cvlit <obj> */
taruti@0 125
 private int
taruti@0 126
 zcvlit(i_ctx_t *i_ctx_p)
taruti@0 127
 {
taruti@0 128
     os_ptr op = osp;
taruti@0 129
     ref *aop;
taruti@0 130
 
taruti@0 131
     check_op(1);
taruti@0 132
     aop = ACCESS_REF(op);
taruti@0 133
     r_clear_attrs(aop, a_executable);
taruti@0 134
     return 0;
taruti@0 135
 }
taruti@0 136
 
taruti@0 137
 /* <obj> cvx <obj> */
taruti@0 138
 int
taruti@0 139
 zcvx(i_ctx_t *i_ctx_p)
taruti@0 140
 {
taruti@0 141
     os_ptr op = osp;
taruti@0 142
     ref *aop;
taruti@0 143
     uint opidx;
taruti@0 144
 
taruti@0 145
     check_op(1);
taruti@0 146
     /*
taruti@0 147
      * If the object is an internal operator, we can't allow it to
taruti@0 148
      * exist in executable form anywhere outside the e-stack.
taruti@0 149
      */
taruti@0 150
     if (r_has_type(op, t_operator) &&
taruti@0 151
 	((opidx = op_index(op)) == 0 ||
taruti@0 152
 	 op_def_is_internal(op_index_def(opidx)))
taruti@0 153
 	)
taruti@0 154
 	return_error(e_rangecheck);
taruti@0 155
     aop = ACCESS_REF(op);
taruti@0 156
     r_set_attrs(aop, a_executable);
taruti@0 157
     return 0;
taruti@0 158
 }
taruti@0 159
 
taruti@0 160
 /* <obj> xcheck <bool> */
taruti@0 161
 private int
taruti@0 162
 zxcheck(i_ctx_t *i_ctx_p)
taruti@0 163
 {
taruti@0 164
     os_ptr op = osp;
taruti@0 165
 
taruti@0 166
     check_op(1);
taruti@0 167
     make_bool(op, (r_has_attr(ACCESS_REF(op), a_executable) ? 1 : 0));
taruti@0 168
     return 0;
taruti@0 169
 }
taruti@0 170
 
taruti@0 171
 /* <obj:array|packedarray|file|string> executeonly <obj> */
taruti@0 172
 private int
taruti@0 173
 zexecuteonly(i_ctx_t *i_ctx_p)
taruti@0 174
 {
taruti@0 175
     os_ptr op = osp;
taruti@0 176
 
taruti@0 177
     check_op(1);
taruti@0 178
     if (r_has_type(op, t_dictionary))
taruti@0 179
 	return_error(e_typecheck);
taruti@0 180
     return access_check(i_ctx_p, a_execute, true);
taruti@0 181
 }
taruti@0 182
 
taruti@0 183
 /* <obj:array|packedarray|dict|file|string> noaccess <obj> */
taruti@0 184
 private int
taruti@0 185
 znoaccess(i_ctx_t *i_ctx_p)
taruti@0 186
 {
taruti@0 187
     os_ptr op = osp;
taruti@0 188
 
taruti@0 189
     check_op(1);
taruti@0 190
     if (r_has_type(op, t_dictionary)) {
taruti@0 191
 	/*
taruti@0 192
 	 * Setting noaccess on a read-only dictionary is an attempt to
taruti@0 193
 	 * change its value, which is forbidden (this is a subtle
taruti@0 194
 	 * point confirmed with Adobe).  Also, don't allow removing
taruti@0 195
 	 * read access to permanent dictionaries.
taruti@0 196
 	 */
taruti@0 197
 	if (dict_is_permanent_on_dstack(op) ||
taruti@0 198
 	    !r_has_attr(dict_access_ref(op), a_write)
taruti@0 199
 	    )
taruti@0 200
 	    return_error(e_invalidaccess);
taruti@0 201
     }
taruti@0 202
     return access_check(i_ctx_p, 0, true);
taruti@0 203
 }
taruti@0 204
 
taruti@0 205
 /* <obj:array|packedarray|dict|file|string> readonly <obj> */
taruti@0 206
 int
taruti@0 207
 zreadonly(i_ctx_t *i_ctx_p)
taruti@0 208
 {
taruti@0 209
     return access_check(i_ctx_p, a_readonly, true);
taruti@0 210
 }
taruti@0 211
 
taruti@0 212
 /* <array|packedarray|dict|file|string> rcheck <bool> */
taruti@0 213
 private int
taruti@0 214
 zrcheck(i_ctx_t *i_ctx_p)
taruti@0 215
 {
taruti@0 216
     os_ptr op = osp;
taruti@0 217
     int code = access_check(i_ctx_p, a_read, false);
taruti@0 218
 
taruti@0 219
     if (code >= 0)
taruti@0 220
 	make_bool(op, code), code = 0;
taruti@0 221
     return code;
taruti@0 222
 }
taruti@0 223
 
taruti@0 224
 /* <array|packedarray|dict|file|string> wcheck <bool> */
taruti@0 225
 private int
taruti@0 226
 zwcheck(i_ctx_t *i_ctx_p)
taruti@0 227
 {
taruti@0 228
     os_ptr op = osp;
taruti@0 229
     int code = access_check(i_ctx_p, a_write, false);
taruti@0 230
 
taruti@0 231
     if (code >= 0)
taruti@0 232
 	make_bool(op, code), code = 0;
taruti@0 233
     return code;
taruti@0 234
 }
taruti@0 235
 
taruti@0 236
 /* <num> cvi <int> */
taruti@0 237
 /* <string> cvi <int> */
taruti@0 238
 int
taruti@0 239
 zcvi(i_ctx_t *i_ctx_p)
taruti@0 240
 {
taruti@0 241
     os_ptr op = osp;
taruti@0 242
     float fval;
taruti@0 243
 
taruti@0 244
     switch (r_type(op)) {
taruti@0 245
 	case t_integer:
taruti@0 246
 	    return 0;
taruti@0 247
 	case t_real:
taruti@0 248
 	    fval = op->value.realval;
taruti@0 249
 	    break;
taruti@0 250
 	default:
taruti@0 251
 	    return_op_typecheck(op);
taruti@0 252
 	case t_string:
taruti@0 253
 	    {
taruti@0 254
 		ref str, token;
taruti@0 255
 		int code;
taruti@0 256
 
taruti@0 257
 		ref_assign(&str, op);
taruti@0 258
 		code = scan_string_token(i_ctx_p, &str, &token);
taruti@0 259
 		if (code > 0)	/* anything other than a plain token */
taruti@0 260
 		    code = gs_note_error(e_syntaxerror);
taruti@0 261
 		if (code < 0)
taruti@0 262
 		    return code;
taruti@0 263
 		switch (r_type(&token)) {
taruti@0 264
 		    case t_integer:
taruti@0 265
 			*op = token;
taruti@0 266
 			return 0;
taruti@0 267
 		    case t_real:
taruti@0 268
 			fval = token.value.realval;
taruti@0 269
 			break;
taruti@0 270
 		    default:
taruti@0 271
 			return_error(e_typecheck);
taruti@0 272
 		}
taruti@0 273
 	    }
taruti@0 274
     }
taruti@0 275
     if (!REAL_CAN_BE_INT(fval))
taruti@0 276
 	return_error(e_rangecheck);
taruti@0 277
     make_int(op, (long)fval);	/* truncates towards 0 */
taruti@0 278
     return 0;
taruti@0 279
 }
taruti@0 280
 
taruti@0 281
 /* <string> cvn <name> */
taruti@0 282
 private int
taruti@0 283
 zcvn(i_ctx_t *i_ctx_p)
taruti@0 284
 {
taruti@0 285
     os_ptr op = osp;
taruti@0 286
 
taruti@0 287
     check_read_type(*op, t_string);
taruti@0 288
     return name_from_string(imemory, op, op);
taruti@0 289
 }
taruti@0 290
 
taruti@0 291
 /* <num> cvr <real> */
taruti@0 292
 /* <string> cvr <real> */
taruti@0 293
 int
taruti@0 294
 zcvr(i_ctx_t *i_ctx_p)
taruti@0 295
 {
taruti@0 296
     os_ptr op = osp;
taruti@0 297
 
taruti@0 298
     switch (r_type(op)) {
taruti@0 299
 	case t_integer:
taruti@0 300
 	    make_real(op, (float)op->value.intval);
taruti@0 301
 	case t_real:
taruti@0 302
 	    return 0;
taruti@0 303
 	default:
taruti@0 304
 	    return_op_typecheck(op);
taruti@0 305
 	case t_string:
taruti@0 306
 	    {
taruti@0 307
 		ref str, token;
taruti@0 308
 		int code;
taruti@0 309
 
taruti@0 310
 		ref_assign(&str, op);
taruti@0 311
 		code = scan_string_token(i_ctx_p, &str, &token);
taruti@0 312
 		if (code > 0)	/* anything other than a plain token */
taruti@0 313
 		    code = gs_note_error(e_syntaxerror);
taruti@0 314
 		if (code < 0)
taruti@0 315
 		    return code;
taruti@0 316
 		switch (r_type(&token)) {
taruti@0 317
 		    case t_integer:
taruti@0 318
 			make_real(op, (float)token.value.intval);
taruti@0 319
 			return 0;
taruti@0 320
 		    case t_real:
taruti@0 321
 			*op = token;
taruti@0 322
 			return 0;
taruti@0 323
 		    default:
taruti@0 324
 			return_error(e_typecheck);
taruti@0 325
 		}
taruti@0 326
 	    }
taruti@0 327
     }
taruti@0 328
 }
taruti@0 329
 
taruti@0 330
 /* <num> <radix_int> <string> cvrs <substring> */
taruti@0 331
 private int
taruti@0 332
 zcvrs(i_ctx_t *i_ctx_p)
taruti@0 333
 {
taruti@0 334
     os_ptr op = osp;
taruti@0 335
     int radix;
taruti@0 336
 
taruti@0 337
     check_type(op[-1], t_integer);
taruti@0 338
     if (op[-1].value.intval < 2 || op[-1].value.intval > 36)
taruti@0 339
 	return_error(e_rangecheck);
taruti@0 340
     radix = op[-1].value.intval;
taruti@0 341
     check_write_type(*op, t_string);
taruti@0 342
     if (radix == 10) {
taruti@0 343
 	switch (r_type(op - 2)) {
taruti@0 344
 	    case t_integer:
taruti@0 345
 	    case t_real:
taruti@0 346
 		{
taruti@0 347
 		    int code = convert_to_string(imemory, op - 2, op);
taruti@0 348
 
taruti@0 349
 		    if (code < 0)
taruti@0 350
 			return code;
taruti@0 351
 		    pop(2);
taruti@0 352
 		    return 0;
taruti@0 353
 		}
cinap_lenrek@7254 354
 	    case t__invalid:
cinap_lenrek@7254 355
 		return_error(e_stackunderflow);
taruti@0 356
 	    default:
taruti@0 357
 		return_op_typecheck(op - 2);
taruti@0 358
 	}
taruti@0 359
     } else {
taruti@0 360
 	ulong ival;
taruti@0 361
 	byte digits[sizeof(ulong) * 8];
taruti@0 362
 	byte *endp = &digits[countof(digits)];
taruti@0 363
 	byte *dp = endp;
taruti@0 364
 
taruti@0 365
 	switch (r_type(op - 2)) {
taruti@0 366
 	    case t_integer:
taruti@0 367
 		ival = (ulong) op[-2].value.intval;
taruti@0 368
 		break;
taruti@0 369
 	    case t_real:
taruti@0 370
 		{
taruti@0 371
 		    float fval = op[-2].value.realval;
taruti@0 372
 
taruti@0 373
 		    if (!REAL_CAN_BE_INT(fval))
taruti@0 374
 			return_error(e_rangecheck);
taruti@0 375
 		    ival = (ulong) (long)fval;
taruti@0 376
 		} break;
cinap_lenrek@7254 377
 	    case t__invalid:
cinap_lenrek@7254 378
 		return_error(e_stackunderflow);
taruti@0 379
 	    default:
taruti@0 380
 		return_op_typecheck(op - 2);
taruti@0 381
 	}
taruti@0 382
 	do {
taruti@0 383
 	    int dit = ival % radix;
taruti@0 384
 
taruti@0 385
 	    *--dp = dit + (dit < 10 ? '0' : ('A' - 10));
taruti@0 386
 	    ival /= radix;
taruti@0 387
 	}
taruti@0 388
 	while (ival);
taruti@0 389
 	if (endp - dp > r_size(op))
taruti@0 390
 	    return_error(e_rangecheck);
taruti@0 391
 	memcpy(op->value.bytes, dp, (uint) (endp - dp));
taruti@0 392
 	r_set_size(op, endp - dp);
taruti@0 393
     }
taruti@0 394
     op[-2] = *op;
taruti@0 395
     pop(2);
taruti@0 396
     return 0;
taruti@0 397
 }
taruti@0 398
 
taruti@0 399
 /* <any> <string> cvs <substring> */
taruti@0 400
 private int
taruti@0 401
 zcvs(i_ctx_t *i_ctx_p)
taruti@0 402
 {
taruti@0 403
     os_ptr op = osp;
taruti@0 404
     int code;
taruti@0 405
 
taruti@0 406
     check_op(2);
taruti@0 407
     check_write_type(*op, t_string);
taruti@0 408
     code = convert_to_string(imemory, op - 1, op);
taruti@0 409
     if (code >= 0)
taruti@0 410
 	pop(1);
taruti@0 411
     return code;
taruti@0 412
 }
taruti@0 413
 
taruti@0 414
 /* ------ Initialization procedure ------ */
taruti@0 415
 
taruti@0 416
 const op_def ztype_op_defs[] =
taruti@0 417
 {
taruti@0 418
     {"1cvi", zcvi},
taruti@0 419
     {"1cvlit", zcvlit},
taruti@0 420
     {"1cvn", zcvn},
taruti@0 421
     {"1cvr", zcvr},
taruti@0 422
     {"3cvrs", zcvrs},
taruti@0 423
     {"2cvs", zcvs},
taruti@0 424
     {"1cvx", zcvx},
taruti@0 425
     {"1executeonly", zexecuteonly},
taruti@0 426
     {"1noaccess", znoaccess},
taruti@0 427
     {"1rcheck", zrcheck},
taruti@0 428
     {"1readonly", zreadonly},
taruti@0 429
     {"2.type", ztype},
taruti@0 430
     {"0.typenames", ztypenames},
taruti@0 431
     {"1wcheck", zwcheck},
taruti@0 432
     {"1xcheck", zxcheck},
taruti@0 433
     op_def_end(0)
taruti@0 434
 };
taruti@0 435
 
taruti@0 436
 /* ------ Internal routines ------ */
taruti@0 437
 
taruti@0 438
 /* Test or modify the access of an object. */
taruti@0 439
 /* If modify = true, restrict to the selected access and return 0; */
taruti@0 440
 /* if modify = false, do not change the access, and return 1 */
taruti@0 441
 /* if the object had the access. */
taruti@0 442
 /* Return an error code if the object is not of appropriate type, */
taruti@0 443
 /* or if the object did not have the access already when modify=1. */
taruti@0 444
 private int
taruti@0 445
 access_check(i_ctx_t *i_ctx_p,
taruti@0 446
 	     int access,	/* mask for attrs */
taruti@0 447
 	     bool modify)	/* if true, reduce access */
taruti@0 448
 {
taruti@0 449
     os_ptr op = osp;
taruti@0 450
     ref *aop;
taruti@0 451
 
taruti@0 452
     switch (r_type(op)) {
taruti@0 453
 	case t_dictionary:
taruti@0 454
 	    aop = dict_access_ref(op);
taruti@0 455
 	    if (modify) {
taruti@0 456
 		if (!r_has_attrs(aop, access))
taruti@0 457
 		    return_error(e_invalidaccess);
taruti@0 458
 		ref_save(op, aop, "access_check(modify)");
taruti@0 459
 		r_clear_attrs(aop, a_all);
taruti@0 460
 		r_set_attrs(aop, access);
taruti@0 461
 		dict_set_top();
taruti@0 462
 		return 0;
taruti@0 463
 	    }
taruti@0 464
 	    break;
taruti@0 465
 	case t_array:
taruti@0 466
 	case t_file:
taruti@0 467
 	case t_string:
taruti@0 468
 	case t_mixedarray:
taruti@0 469
 	case t_shortarray:
taruti@0 470
 	case t_astruct:
taruti@0 471
 	case t_device:;
taruti@0 472
 	    if (modify) {
taruti@0 473
 		if (!r_has_attrs(op, access))
taruti@0 474
 		    return_error(e_invalidaccess);
taruti@0 475
 		r_clear_attrs(op, a_all);
taruti@0 476
 		r_set_attrs(op, access);
taruti@0 477
 		return 0;
taruti@0 478
 	    }
taruti@0 479
 	    aop = op;
taruti@0 480
 	    break;
taruti@0 481
 	default:
taruti@0 482
 	    return_op_typecheck(op);
taruti@0 483
     }
taruti@0 484
     return (r_has_attrs(aop, access) ? 1 : 0);
taruti@0 485
 }
taruti@0 486
 
taruti@0 487
 /* Do all the work of cvs.  The destination has been checked, but not */
taruti@0 488
 /* the source.  This is a separate procedure so that */
taruti@0 489
 /* cvrs can use it when the radix is 10. */
taruti@0 490
 private int
taruti@0 491
 convert_to_string(const gs_memory_t *mem, os_ptr op1, os_ptr op)
taruti@0 492
 {
taruti@0 493
     uint len;
taruti@0 494
     const byte *pstr = 0;
taruti@0 495
     int code = obj_cvs(mem, op1, op->value.bytes, r_size(op), &len, &pstr);
taruti@0 496
 
taruti@0 497
     if (code < 0) {
taruti@0 498
 	/*
taruti@0 499
 	 * Some common downloaded error handlers assume that
taruti@0 500
 	 * operator names don't exceed a certain fixed size.
taruti@0 501
 	 * To work around this bit of bad design, we implement
taruti@0 502
 	 * a special hack here: if we got a rangecheck, and
taruti@0 503
 	 * the object is an operator whose name begins with
taruti@0 504
 	 * %, ., or @, we just truncate the name.
taruti@0 505
 	 */
taruti@0 506
 	if (code == e_rangecheck)
taruti@0 507
 	    switch (r_btype(op1)) {
taruti@0 508
 		case t_oparray:
taruti@0 509
 		case t_operator:
taruti@0 510
 		    if (pstr != 0)
taruti@0 511
 			switch (*pstr) {
taruti@0 512
 			    case '%':
taruti@0 513
 			    case '.':
taruti@0 514
 			    case '@':
taruti@0 515
 				len = r_size(op);
taruti@0 516
 				memcpy(op->value.bytes, pstr, len);
taruti@0 517
 				goto ok;
taruti@0 518
 			}
taruti@0 519
 	    }
taruti@0 520
 	return code;
taruti@0 521
     }
taruti@0 522
 ok:
taruti@0 523
     *op1 = *op;
taruti@0 524
     r_set_size(op1, len);
taruti@0 525
     return 0;
taruti@0 526
 }