1: #include "../h/rt.h" 2: 3: /* 4: * doasgn - assign value of a2 to variable a1. 5: * Does the work for asgn, swap, rasgn, and rswap. 6: */ 7: 8: doasgn(a1, a2) 9: struct descrip *a1, *a2; 10: { 11: register int l1, l2; 12: register union block *bp; 13: register struct b_table *tp; 14: union block *hook; 15: long l3; 16: char sbuf1[MAXSTRING], sbuf2[MAXSTRING]; 17: extern struct descrip tended[]; /* uses tended[1] through tended[5] */ 18: extern struct b_lelem *alclstb(); 19: extern char *alcstr(); 20: 21: tended[1] = *a1; 22: tended[2] = *a2; 23: 24: assign: 25: #ifdef DEBUG 26: if (QUAL(tended[1]) || !VAR(tended[1])) 27: syserr("doasgn: variable expected"); 28: #endif DEBUG 29: 30: if (TVAR(tended[1])) { 31: switch (TYPE(tended[1])) { 32: case T_TVSUBS: 33: /* 34: * An assignment is being made to a substring trapped variable. 35: * Conceptually, there are three units involved: the value to 36: * be assigned to the substring, the string containing the 37: * substring and the substring itself. 38: * 39: * As an example, consider the action of x[2:4] := "xyz" where 40: * x == "abcd". The string containing the substring is "abcd", 41: * the substring is "bc", and the value to be assigned is "xyz". 42: * A string is allocated for the result, and the portion of the 43: * string containing the substring up to the substring ("a" in 44: * this case) is copied into the new string. Then, the value 45: * to be assigned, ("xyz"), is added to the new string. 46: * Finally, the portion of the substrung string to the right 47: * of the substring ("d") is copied into the new string to 48: * complete the result ("axyzd"). 49: * 50: * The tended descriptors are used as follows: 51: * tended[1] - the substring trapped variable 52: * tended[2] - the value to assign 53: * tended[3] - the string containing the substring 54: * tended[4] - the substring 55: * tended[5] - the result string 56: */ 57: /* 58: * Be sure that the value to assign is a string. The result 59: * is not used, so it seems like it would be much faster to 60: * see if the value is already a string and only call cvstr 61: * if necessary. 62: */ 63: if (cvstr(&tended[2], sbuf1) == NULL) 64: runerr(103, &tended[2]); 65: /* 66: * Be sure that the string containing the substring is a string. 67: */ 68: tended[3] = BLKLOC(tended[1])->tvsubs.ssvar; 69: if (cvstr(&tended[3], sbuf2) == NULL) 70: runerr(103, &tended[3]); 71: /* 72: * Ensure that there is enough string space by checking for 73: * the worst case size which is the length of the substrung 74: * string plus the length of the value to be assigned. 75: */ 76: sneed(STRLEN(tended[3]) + STRLEN(tended[2])); 77: /* 78: * Get a pointer to the tvsubs block and make l1 a C-style 79: * index to the character that begins the substring. 80: */ 81: bp = BLKLOC(tended[1]); 82: l1 = bp->tvsubs.sspos - 1; 83: /* 84: * Make tended[4] a descriptor for the substring. 85: */ 86: STRLEN(tended[4]) = bp->tvsubs.sslen; 87: STRLOC(tended[4]) = STRLOC(tended[3]) + l1; 88: /* 89: * Make l2 a C-style index to the character after the substring. 90: * If l2 is greater than the length of the substrung string, 91: * it's an error because the string being assigned won't fit. 92: */ 93: l2 = l1 + STRLEN(tended[4]); 94: if (l2 > STRLEN(tended[3])) 95: runerr(205,NULL); 96: /* 97: * Form the result string. First, copy the portion of the 98: * substring string to the left of the substring into the string 99: * space. 100: */ 101: STRLOC(tended[5]) = alcstr(STRLOC(tended[3]), l1); 102: /* 103: * Copy the string to be assigned into the string space, 104: * effectively concatenating it. 105: */ 106: alcstr(STRLOC(tended[2]), STRLEN(tended[2])); 107: /* 108: * Copy the portion of the substrung string to the right of 109: * the substring into the string space, completing the result. 110: */ 111: alcstr(STRLOC(tended[3])+l2, STRLEN(tended[3])-l2); 112: /* 113: * Calculate the length of the new string by: 114: * length of substring string minus 115: * length of substring (it was replaced) plus 116: * length of the assigned string. 117: */ 118: STRLEN(tended[5]) = STRLEN(tended[3]) - STRLEN(tended[4]) + 119: STRLEN(tended[2]); 120: /* 121: * For this next portion, the parchments left by the Old Ones read 122: * "tail recursion:" 123: * " doasgn(bp->tvsubs.ssvar,tended[5]);" 124: */ 125: bp->tvsubs.sslen = STRLEN(tended[2]); 126: tended[1] = bp->tvsubs.ssvar; 127: tended[2] = tended[5]; 128: goto assign; 129: 130: case T_TVTBL: 131: /* 132: * An assignment is being made to a table element trapped 133: * variable. 134: * 135: * Tended descriptors: 136: * tended[1] - the table element trapped variable 137: * tended[2] - the value to be assigned 138: * tended[3] - subscripting value 139: * 140: * Point bp at the trapped variable block; point tended[3] 141: * at the subscripting value; point tp at the table 142: * header block. 143: */ 144: bp = BLKLOC(tended[1]); 145: if (bp->tvtbl.type == T_TELEM) { 146: /* 147: * It is a converted tvtbl block already in the table 148: * just assign to it and return. 149: */ 150: bp->telem.tval = tended[2]; 151: clrtend(); 152: return; 153: } 154: tended[3] = bp->tvtbl.tvtref; 155: tp = (struct b_table *) BLKLOC(bp->tvtbl.tvtable); 156: /* 157: * Get a hash value for the subscripting value and locate the 158: * element chain on which the element being assigned to will 159: * be placed. 160: */ 161: l1 = bp->tvtbl.hashnum; 162: l2 = l1 % NBUCKETS; /* bucket number */ 163: bp = BLKLOC(tp->buckets[l2]); 164: /* 165: * Look down the bucket chain to see if the value is already 166: * in the table. If it's there, just assign to it and return. 167: */ 168: hook = bp; 169: while (bp != NULL) { 170: if ( bp->telem.hashnum > l1 ) /* past it - not there */ 171: break; 172: if ((bp->telem.hashnum == l1) && 173: (equiv(&bp->telem.tref, &tended[3]))) { 174: bp->telem.tval = tended[2]; 175: clrtend(); 176: return; 177: } 178: hook = bp; 179: bp = BLKLOC(bp->telem.blink); 180: } 181: /* 182: * The value being assigned is new. Increment the table size, 183: * and convert the tvtbl to a telem and link it into the chain 184: * in the table. 185: */ 186: tp->cursize++; 187: a1->type = D_VAR | D_TELEM; 188: if (hook == bp) { /* new element goes at front of chain */ 189: bp = BLKLOC(tended[1]); 190: bp->telem.blink = tp->buckets[l2]; 191: BLKLOC(tp->buckets[l2]) = bp; 192: tp->buckets[l2].type = D_TELEM; 193: } 194: else { /* new element follows hook */ 195: bp = BLKLOC(tended[1]); 196: bp->telem.blink = hook->telem.blink; 197: BLKLOC(hook->telem.blink) = bp; 198: hook->telem.blink.type = D_TELEM; 199: } 200: bp->tvtbl.type = T_TELEM; 201: bp->telem.tval = tended[2]; 202: clrtend(); 203: return; 204: 205: case T_TVPOS: 206: /* 207: * An assignment to &pos is being made. Be sure that the 208: * value being assigned is a (non-long) integer. 209: */ 210: switch (cvint(&tended[2], &l3)) { 211: case T_INTEGER: break; 212: #ifdef LONGS 213: case T_LONGINT: clrtend(); fail(); 214: #endif LONGS 215: default: runerr(101, &tended[2]); 216: } 217: /* 218: * Convert the value into a position and be sure that it's 219: * in range. Note that cvpos fails if the position is past 220: * the end of the string. 221: */ 222: l1 = cvpos(l3, STRLEN(k_subject)); 223: if (l1 <= 0) { 224: clrtend(); 225: fail(); 226: } 227: /* 228: * If all is well, make the assignment to &pos and return. 229: */ 230: k_pos = l1; 231: clrtend(); 232: return; 233: 234: case T_TVRAND: 235: /* 236: * An assignment to &random is being made. Be sure that the 237: * value being assigned is an integer. 238: */ 239: switch (cvint(&tended[2], &l3)) { 240: case T_INTEGER: 241: #ifdef LONGS 242: case T_LONGINT: 243: #endif LONGS 244: break; 245: default: runerr(101, &tended[2]); 246: } 247: k_random = l3; 248: clrtend(); 249: return; 250: 251: case T_TVTRACE: 252: /* 253: * An assignment to &trace is being made. Be sure that the 254: * value being assigned is an integer. Should it be a long 255: * integer, just set &trace to -1. 256: */ 257: switch (cvint(&tended[2], &l3)) { 258: case T_INTEGER: k_trace = (int)l3; break; 259: #ifdef LONGS 260: case T_LONGINT: k_trace = -1; break; 261: #endif LONGS 262: default: runerr(101, &tended[2]); 263: } 264: clrtend(); 265: return; 266: 267: default: 268: syserr("doasgn: illegal trapped variable"); 269: } 270: } 271: 272: if (VARLOC(tended[1]) == &k_subject) { 273: /* 274: * An assignment is being made to &subject. Be sure that the value 275: * being assigned is a string. If the value is converted to a string, 276: * allocate it. Note that &pos is set to 1. 277: */ 278: switch (cvstr(&tended[2], sbuf1)) { 279: case NULL: 280: runerr(103, &tended[2]); 281: case 1: 282: sneed(STRLEN(tended[2])); 283: STRLOC(tended[2]) = alcstr(STRLOC(tended[2]), STRLEN(tended[2])); 284: case 2: 285: k_subject = tended[2]; 286: k_pos = 1; 287: } 288: } 289: else 290: /* 291: * The easy case, just replace the variable descriptor with the value 292: * descriptor. 293: */ 294: *VARLOC(tended[1]) = tended[2]; 295: clrtend(); 296: return; 297: } 298: 299: /* 300: * clrtend - clear the tended descriptors. 301: */ 302: clrtend() 303: { 304: register struct descrip *p; 305: extern struct descrip tended[]; 306: 307: for (p = &tended[1]; p <= &tended[5]; p++) 308: *p = nulldesc; 309: }