|
|
1.1 root 1: /*
2: * File: oref.c
3: * Contents: bang, sect, subsc
4: */
5:
6: #include "../h/rt.h"
7:
8: /*
9: * !x - generate successive values from object x.
10: */
11:
12: OpDclV(bang,1,"!")
13: {
14: register word i, j, slen;
15: register union block *bp, *ep;
16: register struct descrip *dp;
17: int typ1;
18: char sbuf[MaxCvtLen];
19: FILE *fd;
20: extern char *alcstr();
21:
22: Arg2 = Arg1;
23:
24: DeRef(Arg1);
25: if ((typ1 = cvstr(&Arg1, sbuf)) != NULL) {
26: /*
27: * A string is being banged.
28: */
29: i = 1;
30: while (i <= StrLen(Arg1)) {
31: /*
32: * Loop through the string using i as an index.
33: */
34: if (typ1 == Cvt) {
35: /*
36: * x was converted to a string, thus, the resulting string
37: * can't be modified and a trapped variable isn't needed.
38: * Make a one-character string out of the next character
39: * in x and suspend it.
40: */
41: strreq((word)1);
42: StrLen(Arg0) = 1;
43: StrLoc(Arg0) = alcstr(StrLoc(Arg1)+i-1, (word)1);
44: Suspend;
45: }
46: else {
47: /*
48: * x a string and thus a trapped variable must be made
49: * for the one character string being suspended.
50: */
51: blkreq((word)sizeof(struct b_tvsubs));
52: mksubs(&Arg2, &Arg1, i, (word)1, &Arg0);
53: Suspend;
54: Arg1 = Arg2;
55: DeRef(Arg1);
56: if (!Qual(Arg1))
57: runerr(103, &Arg1);
58: }
59: i++;
60: }
61: }
62: else {
63: /*
64: * x isn't a string.
65: */
66: switch (Type(Arg1)) {
67: case T_List:
68: /*
69: * x is a list. Chain through each list element block and for
70: * each one, suspend with a variable pointing to each
71: * element contained in the block.
72: */
73: bp = BlkLoc(Arg1);
74: for (Arg1 = bp->list.listhead; Arg1.dword == D_Lelem;
75: Arg1 = BlkLoc(Arg1)->lelem.listnext) {
76: bp = BlkLoc(Arg1);
77: for (i = 0; i < bp->lelem.nused; i++) {
78: j = bp->lelem.first + i;
79: if (j >= bp->lelem.nelem)
80: j -= bp->lelem.nelem;
81: dp = &bp->lelem.lslots[j];
82: Arg0.dword = D_Var + ((word *)dp - (word *)bp);
83: VarLoc(Arg0) = dp;
84: Suspend;
85: bp = BlkLoc(Arg1); /* bp is untended, must reset */
86: }
87: }
88: break;
89:
90:
91: case T_File:
92: /*
93: * x is a file. Read the next line into the string space
94: * and suspend the newly allocated string.
95: */
96: fd = BlkLoc(Arg1)->file.fd;
97: if ((BlkLoc(Arg1)->file.status & Fs_Read) == 0)
98: runerr(212, &Arg1);
99: while ((slen = getstr(sbuf,MaxCvtLen,fd)) >= 0) {
100: strreq(slen);
101: StrLen(Arg0) = slen;
102: StrLoc(Arg0) = alcstr(sbuf,slen);
103: Suspend;
104: }
105: break;
106:
107: case T_Table:
108: /*
109: * x is a table. Chain down the element list in each bucket
110: * and suspend a variable pointing to each element in turn.
111: */
112: for (i = 0; i < TSlots; i++) {
113: bp = BlkLoc(Arg1);
114: for (Arg2 = bp->table.buckets[i]; Arg2.dword == D_Telem;
115: Arg2 = BlkLoc(Arg2)->telem.clink) {
116: ep = BlkLoc(Arg2);
117: dp = &ep->telem.tval;
118: Arg0.dword = D_Var + ((word *)dp - (word *)ep);
119: VarLoc(Arg0) = dp;
120: Suspend;
121: bp = BlkLoc(Arg1); /* bp is untended, must reset */
122: }
123: }
124: break;
125:
126: case T_Set:
127: /*
128: * This is similar to the method for tables except that a
129: * value is returned instead of a variable.
130: */
131: for(i = 0; i < SSlots; i++) {
132: bp = BlkLoc(Arg1);
133: for(Arg2 = bp->set.sbucks[i]; Arg2.dword == D_Selem;
134: Arg2 = BlkLoc(Arg2)->selem.clink) {
135: Arg0 = BlkLoc(Arg2)->selem.setmem;
136: Suspend;
137: bp = BlkLoc(Arg1); /* bp untended, must be reset */
138: }
139: }
140: break;
141:
142: case T_Record:
143: /*
144: * x is a record. Loop through the fields and suspend
145: * a variable pointing to each one.
146: */
147: bp = BlkLoc(Arg1);
148: j = BlkLoc(bp->record.recdesc)->proc.nfields;
149: for (i = 0; i < j; i++) {
150: dp = &bp->record.fields[i];
151: Arg0.dword = D_Var + ((word *)dp - (word *)bp);
152: VarLoc(Arg0) = dp;
153: Suspend;
154: bp = BlkLoc(Arg1); /* bp is untended, must reset */
155: }
156: break;
157:
158: default: /* This object can not be compromised. */
159: runerr(116, &Arg1);
160: }
161: }
162:
163: /*
164: * Eventually fail.
165: */
166: Fail;
167: }
168:
169:
170: /*
171: * x[i:j] - form a substring or list section of x.
172: */
173:
174: OpDclV(sect,3,":")
175: {
176: register word i, j, t;
177: int typ1;
178: char sbuf[MaxCvtLen];
179: long l1, l2;
180: extern char *alcstr();
181:
182: blkreq((word)sizeof(struct b_tvsubs)); /* request space */
183:
184: if (cvint(&Arg2, &l1) == NULL)
185: runerr(101, &Arg2);
186: if (cvint(&Arg3, &l2) == NULL)
187: runerr(101, &Arg3);
188:
189: Arg4 = Arg1;
190: DeRef(Arg1);
191:
192: if (!Qual(Arg1) && Arg1.dword == D_List) {
193: i = cvpos(l1, BlkLoc(Arg1)->list.size);
194: if (i == 0)
195: Fail;
196: j = cvpos(l2, BlkLoc(Arg1)->list.size);
197: if (j == 0)
198: Fail;
199: if (i > j) {
200: t = i;
201: i = j;
202: j = t;
203: }
204: cplist(&Arg1, &Arg0, i, j);
205: Return;
206: }
207:
208: if ((typ1 = cvstr(&Arg1, sbuf)) == NULL)
209: runerr(110, &Arg1);
210:
211: i = cvpos(l1, StrLen(Arg1));
212: if (i == 0)
213: Fail;
214: j = cvpos(l2, StrLen(Arg1));
215: if (j == 0)
216: Fail;
217: if (i > j) { /* convert section to substring */
218: t = i;
219: i = j;
220: j = t - j;
221: }
222: else
223: j = j - i;
224:
225: if (typ1 == Cvt) { /* if string was created, */
226: strreq(j); /* just return a string */
227: StrLen(Arg0) = j;
228: StrLoc(Arg0) = alcstr(StrLoc(Arg1)+i-1, j);
229: }
230: else /* else make a substring tv */
231: mksubs(&Arg4, &Arg1, i, j, &Arg0);
232: Return;
233: }
234:
235:
236: /*
237: * x[y] - access yth character or element of x.
238: */
239:
240: OpDclV(subsc,2,"[]")
241: {
242: register word i, j;
243: register union block *bp;
244: int typ1;
245: long l1;
246: struct descrip *dp;
247: char sbuf[MaxCvtLen];
248: extern char *alcstr();
249: extern struct b_tvtbl *alctvtbl();
250:
251: /*
252: * Make a copy of x.
253: */
254: Arg3 = Arg1;
255:
256: DeRef(Arg1);
257: if ((typ1 = cvstr(&Arg1, sbuf)) != NULL) {
258: /*
259: * x is a string, make sure that y is an integer.
260: */
261: if (cvint(&Arg2, &l1) == NULL)
262: runerr(101, &Arg2);
263: /*
264: * Convert y to a position in x and fail if the position is out
265: * of bounds.
266: */
267: i = cvpos(l1, StrLen(Arg1));
268: if (i == 0 || i > StrLen(Arg1))
269: Fail;
270: if (typ1 == Cvt) {
271: /*
272: * x was converted to a string, so it can't be assigned back into.
273: * Just return a string containing the selected character.
274: */
275: strreq((word)1);
276: StrLen(Arg0) = 1;
277: StrLoc(Arg0) = alcstr(StrLoc(Arg1)+i-1, (word)1);
278: }
279: else {
280: /*
281: * x is a string, make a substring trapped variable for the one
282: * character substring selected and return it.
283: */
284: blkreq((word)sizeof(struct b_tvsubs));
285: mksubs(&Arg3, &Arg1, i, (word)1, &Arg0);
286: }
287: Return;
288: }
289:
290: /*
291: * x isn't a string or convertible to one, see if it's an aggregate.
292: */
293: DeRef(Arg1);
294: /* >listref */
295: switch (Type(Arg1)) {
296: case T_List:
297: /*
298: * Make sure that Arg2 is an integer and that the
299: * subscript is in range.
300: */
301: if (cvint(&Arg2, &l1) == NULL)
302: runerr(101, &Arg2);
303: i = cvpos(l1, BlkLoc(Arg1)->list.size);
304: if (i == 0 || i > BlkLoc(Arg1)->list.size)
305: Fail;
306:
307: /*
308: * Locate the list block containing the desired element.
309: */
310: bp = BlkLoc(BlkLoc(Arg1)->list.listhead);
311: j = 1;
312: while (i >= j + bp->lelem.nused) {
313: j += bp->lelem.nused;
314: if ((bp->lelem.listnext).dword != D_Lelem)
315: syserr("list reference out of bounds in subsc");
316: bp = BlkLoc(bp->lelem.listnext);
317: }
318:
319: /*
320: * Locate the desired element in the block that contains it
321: * and return a pointer to it.
322: */
323: i += bp->lelem.first - j;
324: if (i >= bp->lelem.nelem)
325: i -= bp->lelem.nelem;
326: dp = &bp->lelem.lslots[i];
327: Arg0.dword = D_Var + ((int *)dp - (int *)bp);
328: VarLoc(Arg0) = dp;
329: Return;
330: /* <listref */
331:
332: case T_Table:
333: /*
334: * x is a table. Locate the appropriate bucket
335: * based on the hash value.
336: */
337: blkreq((word)sizeof(struct b_tvtbl));
338: i = hash(&Arg2); /* get hash number of subscript */
339: bp = BlkLoc(BlkLoc(Arg1)->table.buckets[SlotNum(i,TSlots)]);
340: /*
341: * Work down the chain of elements for the bucket and if an
342: * element with the desired subscript value is found, return
343: * a pointer to it.
344: * Elements are ordered in the chain by hash number value
345: * from smallest to largest.
346: */
347: while (bp != NULL) {
348: if (bp->telem.hashnum > i) /* past it - not there */
349: break;
350: if ((bp->telem.hashnum == i) && (equiv(&bp->telem.tref, &Arg2))) {
351: dp = &bp->telem.tval;
352: Arg0.dword = D_Var + ((word *)dp - (word *)bp);
353: VarLoc(Arg0) = dp;
354: Return;
355: }
356: /* We haven't reached the right hash number yet or
357: * the element is not the right one.
358: */
359: bp = BlkLoc(bp->telem.clink);
360: }
361: /*
362: * x[y] is not in the table, make a table element trapped variable
363: * and return it as the result.
364: */
365: Arg0.dword = D_Tvtbl;
366: BlkLoc(Arg0) = (union block *) alctvtbl(&Arg1, &Arg2, i);
367: Return;
368:
369: case T_Record:
370: /*
371: * x is a record. Convert y to an integer and be sure that it
372: * it is in range as a field number.
373: */
374: if (cvint(&Arg2, &l1) == NULL)
375: runerr(101, &Arg2);
376: bp = BlkLoc(Arg1);
377: i = cvpos(l1, (word)(BlkLoc(bp->record.recdesc)->proc.nfields));
378: if (i == 0 || i > BlkLoc(bp->record.recdesc)->proc.nfields)
379: Fail;
380: /*
381: * Locate the appropriate field and return a pointer to it.
382: */
383: dp = &bp->record.fields[i-1];
384: Arg0.dword = D_Var + ((word *)dp - (word *)bp);
385: VarLoc(Arg0) = dp;
386: Return;
387:
388: default:
389: /*
390: * x is of a type that can't be subscripted.
391: */
392: runerr(114, &Arg1);
393: }
394: Return;
395: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.